Booting petitboot from VFLASH: Difference between revisions

From PS3 Developer wiki
Jump to navigation Jump to search
(Replaced content with "Moderators wanted - troy [dot] gerrie [at] gmail [dot] com")
Line 1: Line 1:
[[Category:PS3]]
Moderators wanted - troy [dot] gerrie [at] gmail [dot] com
''' Source: graf_chokolo @ http://ps3wiki.lan.st/index.php/Booting_petitboot_from_VFLASH '''
----
= How it was done in 3.15 Firmware =
 
* Linux bootloader '''otheros.bld''' is a compressed version of '''petitboot''' or '''kboot'''
* '''otheros.self''' stores the Linux bootloader on the '''5th region of VFLASH'''
* The 5th region of VFLASH is of size '''0x2000''' sectors, each sector is of size '''0x200''', which makes '''0x400000''' bytes
* The 5th region of VFLASH starts at absolute sector offset '''0x77E00''' on VFLASH storage device
* So Linux bootloader cannot be larger than 0x400000 bytes
* In LPAR 1 the 5th region of VFLASH is accessible through device file '''/dev/rflash_lx'''
* '''Linux System Manager''' (HV process 9) loads the Linux bootloader stored on '''/dev/rflash_lx''' into LPAR 2 memory and when LPAR 2 boots, the Linux bootloader gets control of the system and loads the Linux kernel from HDD
 
= How things are in 3.41 Firmware =
 
* '''The good news is that the 5th region of VFLASH is still there in 3.41 and even in 3.55 PS3 firmware. Even better, it's accessible in LPAR 1 through /dev/rflash_lx !!!'''
* '''And PS3 Slim has it also !!!'''
* '''Why didn't SONY remove it you will ask. I'm very sure that SONY's HV developer team still uses Linux internally !!! I will bet on it :-)'''
* But SONY removed '''Linux System Manager''' from 3.41 firmware, so we cannot boot Linux bootloader from VFLASH without adding new code to HV. HV cannot boot the Linux bootloader anymore on its own.
* The second problem is that the Linux bootloader uncompressed is very large and it won't fit into the default 5th region of VFLASH that is of size 0x400000 bytes.
* We have to store the Linux bootloader uncompressed on VFLASH
* Before we can do it, we have to resize the 5th VFLASH region. And nothing is simpler if you know HV like the back of your hand :-)
* SONY could remove '''/dev/rflash_lx''' in future HVs but i know now HV so good that it will be no problem to me to add this device again :-)
 
= Creating and Resizing of VFLASH region =
 
* So we have to resize the 5th VFLASH region in order to be able to store an uncompressed petitiboot which is quite large
* On my PS3 3.41 i set the size of the 5th VFLASH region to 0x800000 bytes, it's enough to store there petitboot with nice GUI and many features. But we could use larger size without any problems, because VFLASH is large enough.
* GameOS is able to create/delete storage device regions (see HV calls '''lv1_undocumented_function_250''' and '''lv1_undocumented_function_251''')
* GameOS is able to set ACLs for a storage device region (see HV calls '''lv1_undocumented_function_252''' and '''lv1_undocumented_function_253''')
* The 5th VFLASH storage device region can be resized with '''2 different methods''': the first one is dirty and requires HV access rights, the second one is simpler and requires only GameOS rights
* I tested both methods, both worked very well
* The first method is only for advanced HV hackers :-) I reversed the storage device class and know now where which data is stored, e.g. region start sector and region sector count. I patched the sector count of the 5th VFLASH region in memory, then i forced HV to update the partition table of VFLASH and HV stored the new region size on VFLASH. Then i rebooted HV and i got a new larger VFLASH region :-) Another possibility is to write partition table on your own.
* '''Don't try the first method if you are not familiar with HV :-) Consider you warned guys :-)'''
* The second method is safer. It requires only GameOS rights. First i deleted the 5th VFLASH region, it's safe because GameOS doesn't use this region at all. Then i created it again with larger size. That simple :-)
 
= Installing petitboot on VFLASH region =
 
* petitboot binary image can be stored on the 5th VFLASH region with GameOS rights
* petitboot should be stored on VFLASH with encryption disabled !!!
 
= Patching GameOS System Manager =
 
* '''GameOS System Manager''' is in HV process 9
* '''GameOS System Manager''' allocates an initial LPAR 2 memory for GameOS, then it sends a SS request (see my HV page) to load '''lv2_kernel.self''' to '''Secure LPAR Loader''' which is located in HV process 3
* We have to patch the initial LPAR 2 memory size because GameOS uses a smaller value but Linux kernel requires more memory
 
= Patching Secure LPAR Loader (SLL) =
 
* Secure LPAR Loader (SLL) is in HV process 3
* SLL loads '''lv2_kernel.self''' from FLASH, passes it to '''lv2ldr''' which decrypts it
* I replaced the '''lv2_kernel.self''' loader with my OtherOS bootloader loader
 
== otheros_booloader_loader.S ==
 
Here is my OtherOS bootloader loader from VFLASH.
 
* All function addresses are valid for 3.41 firmware only !!!
* The loader maps LPAR memory region
* Reads OtherOS bootloader from VFLASH into mapped LPAR memory region
 
<pre>
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
 
.set STACK_SIZE, 0x100
.set STACK_LR, (STACK_SIZE + 0x10)
.set STACK_R25, (STACK_SIZE - 1 * 0x8)
.set STACK_R26, (STACK_SIZE - 2 * 0x8)
.set STACK_R27, (STACK_SIZE - 3 * 0x8)
.set STACK_R28, (STACK_SIZE - 4 * 0x8)
.set STACK_R29, (STACK_SIZE - 5 * 0x8)
.set STACK_R30, (STACK_SIZE - 6 * 0x8)
.set STACK_R31, (STACK_SIZE - 7 * 0x8)
.set STACK_LPAR_MEM,         (STACK_SIZE - 8 * 0x8)
 
.set SUB_SLL_LOAD_LV2,         0x80000E44 /* sll_load_lv2 */
.set SUB_MMAP_LPAR_MEM,         0x800026B4
.set SUB_OPEN, 0x80013D40 /* syscall 0x7 */
.set SUB_CLOSE, 0x80013D7C /* syscall 0x8 */
.set SUB_READ, 0x80013DB8 /* syscall 0x9 */
.set SUB_MUNMAP, 0x80013EB8 /* syscall 0x19 */
.set SUB_BSET, 0x80000278
.set SUB_BCOPY, 0x80000254
 
#define BL(sub_addr)         \
li %r30, 0; \
oris %r30, %r30, (sub_addr >> 16);                 \
ori %r30, %r30, (sub_addr & 0xFFFF);                         \
mtctr %r30; \
bctrl
 
.set CACHE_LINE_SIZE,         0x80
 
.set FD_ERROR, 0x10
.set HEADER_ERROR, 0x14
 
#define LWZ_DATA(reg, data_addr)                 lwz reg, data_addr(%r31)
#define LD_DATA(reg, data_addr)                 ld reg, data_addr(%r31)
#define LD_DATA_PTR(reg, data_addr)                 addi reg, %r31, data_addr - sll_load_lv2
 
/*
* %r3 - path
* %r4 - laid
* %r5 - lpar id
*
* %r25 - volatile
* %r26 - OtherOS bootloader load address
* %r27 - return value
* %r28 - size of /dev/rflash_lx
* %r29 - file descriptor of /dev/rflash_lx
* %r30 - reserved for function calls
* %r31 - reserved for data accesses
*/
.globl sll_load_lv2
sll_load_lv2:
 
stdu %r1, -STACK_SIZE(%r1)
mflr %r0
std %r0, STACK_LR(%r1)
std %r25, STACK_R25(%r1)
std %r26, STACK_R26(%r1)
std %r27, STACK_R27(%r1)
std %r28, STACK_R28(%r1)
std %r29, STACK_R29(%r1)
std %r30, STACK_R30(%r1)
std %r31, STACK_R31(%r1)
 
bl 1f
 
1:
 
mflr %r31
addi %r31, %r31, (sll_load_lv2 - 1b)
 
/* map lpar memory */
 
mr %r3, %r5
li %r4, 0
LD_DATA(%r26, bootloader_load_addr)
LD_DATA(%r28, dev_rflash_lx_size)
add %r5, %r26, %r28
addi %r6, %r1, STACK_LPAR_MEM
BL(SUB_MMAP_LPAR_MEM)
cmpwi %cr7, %r3, 0
mr %r27, %r3
bne %cr7, done
 
/* zero out lpar memory */
 
ld %r3, STACK_LPAR_MEM(%r1)
li %r4, 0
mr %r5, %r28
BL(SUB_BSET)
 
/* open /dev/rflash_lx where OtherOS bootloader is stored */
 
LD_DATA_PTR(%r3, dev_rflash_lx)
li %r4, 0
li %r27, FD_ERROR
BL(SUB_OPEN)
cmpwi %cr7, %r3, 0
mr %r29, %r3
blt %cr7, bad1
 
/* read header */
 
extsw %r3, %r29
ld %r4, STACK_LPAR_MEM(%r1)
LD_DATA(%r25, header_size)
mr %r5, %r25
li %r27, FD_ERROR
BL(SUB_READ)
cmpd %cr7, %r3, %r25
bne %cr7, bad2
 
/* check header magic */
 
li %r27, HEADER_ERROR
 
LD_DATA(%r3, header_magic)
ld %r5, STACK_LPAR_MEM(%r1)
ld %r4, 0(%r5)
cmpd %cr7, %r3, %r4
bne %cr7, bad2
 
/* read OtherOS bootloader size from header */
 
ld %r25, 8(%r5)
cmpd %cr7, %r25, %r28
bgt %cr7, bad2
 
/* read OtherOS bootloader to lpar memory */
 
extsw %r3, %r29
ld %r4, STACK_LPAR_MEM(%r1)
mr %r5, %r25
li %r27, FD_ERROR
BL(SUB_READ)
cmpd %cr7, %r3, %r25
bne %cr7, bad2
 
/* flush data cache */
 
li %r9, 0
b 2f
 
1:
 
ld %r0, STACK_LPAR_MEM(%r1)
add %r0, %r9, %r0
dcbst %r0, %r0
addi %r9, %r9, CACHE_LINE_SIZE
 
2:
 
cmpd %cr7, %r9, %r28
blt %cr7, 1b
 
sync
 
/* flush code cache */
 
li %r9, 0
b 2f
 
1:
 
ld %r0, STACK_LPAR_MEM(%r1)
add %r0, %r9, %r0
icbi %r0, %r0
addi %r9, %r9, CACHE_LINE_SIZE
 
2:
 
cmpd %cr7, %r9, %r28
blt %cr7, 1b
 
isync
 
success:
 
li %r27, 0
 
bad2:
 
/* close /dev/rflash_lx */
 
extsw %r3, %r29
BL(SUB_CLOSE)
 
bad1:
 
/* unmap lpar memory */
 
ld %r3, STACK_LPAR_MEM(%r1)
add %r4, %r26, %r28
BL(SUB_MUNMAP)
 
done:
 
rldicl %r3, %r27, 0, 32
 
ld %r0, STACK_LR(%r1)
ld %r25, STACK_R25(%r1)
ld %r26, STACK_R26(%r1)
ld %r27, STACK_R27(%r1)
ld %r28, STACK_R28(%r1)
ld %r29, STACK_R29(%r1)
ld %r30, STACK_R30(%r1)
ld %r31, STACK_R31(%r1)
addi %r1, %r1, STACK_SIZE
mtlr %r0
blr
 
/* read-only data */
 
data_start:
 
bootloader_load_addr:
.quad 0x0000000000000000
 
header_size:
.quad (2 * 0x200) /* 2 sectors of size 0x200 */
 
header_magic:
.quad 0x0FACE0FFDEADBABE
 
dev_rflash_lx_size:
.quad (0x4000 * 0x200) /* 0x4000 sectors of size 0x200 */
 
dev_rflash_lx:
.asciz "/dev/rflash_lx"
 
data_end:
</pre>

Revision as of 01:02, 12 March 2011

Moderators wanted - troy [dot] gerrie [at] gmail [dot] com