Line 1:
Line 1:
β
Just like it's Wii counterpart, boot1 is the second-stage bootloader which is loaded by [[boot0]].
+
{{lowercase title}}
β
boot1 is stored inside the first SLC NAND blocks in the form of an [[Ancast_Image|ancast image]]. There are always two copies of boot1 inside the SLC NAND and, together, these images form the only blocks that are left as plain data (not encrypted with the OTP SLC key).
β
boot1 runs from on-die SRAM starting at address 0x0D400000 and it's size must not exceed the total of 0xF800 bytes (it's size is checked by boot0).
β
During the boot process, boot0 loads boot1 from NAND and decrypts it using an AES key stored in the console's [[Hardware/OTP|OTP]]. Immediately after, boot0 permanently disables access to this key by clearing the appropriate value in the [[Hardware/Latte_Registers#LT_OTPPROT|LT_OTPPROT]] register.
+
Just like it's Wii counterpart, '''boot1''' is the second-stage bootloader which is loaded by [[boot0]]. boot1 is stored inside the first SLC NAND blocks in the form of an [[Ancast_Image|ancast image]]. Unlike the Wii boot1, this boot1 is the final bootloader of the Wii U, much like the Wii [https://wiibrew.org/wiki/boot2 boot2]. There are always two copies of boot1 inside the SLC NAND and, together, these images form the only blocks that are left as plain data (not encrypted with the OTP SLC key).
+
+
boot1 runs from on-die SRAM starting at address 0x0D400000 and its size must not exceed the total of 0xF800 bytes (it's size is checked by boot0).
+
+
During the boot process, boot0 loads boot1 from NAND and decrypts it using an AES key stored in the console's [[Hardware/OTP|OTP]]. Immediately after, boot0 permanently disables access to this key by clearing the appropriate value in the [[Hardware/Latte_Registers#LT_EFUSEPROT|LT_EFUSEPROT]] register.
+
+
boot1 then loads [[IOSU]] from the filesystem as an ancast image, and decrypts and verifies it, similar to what boot0 does with boot1.
What follows are general descriptions and pseudo-code that illustrates the several sub-stages of the Wii U's boot1.
What follows are general descriptions and pseudo-code that illustrates the several sub-stages of the Wii U's boot1.
Line 47:
Line 51:
// Assert RSTB_IOPI and RSTB_IOMEM
// Assert RSTB_IOPI and RSTB_IOMEM
β
u32 resets_val = *(u32 *)HW_RSTB;
+
u32 resets_val = *(u32 *)HW_RSTCTRL;
resets_val &= 0xFFF7FFFF;
resets_val &= 0xFFF7FFFF;
resets_val |= 0x80000;
resets_val |= 0x80000;
resets_val &= 0xFFFBFFFF;
resets_val &= 0xFFFBFFFF;
resets_val |= 0x40000;
resets_val |= 0x40000;
β
*(u32 *)HW_RSTB= resets_val;
+
*(u32 *)HW_RSTCTRL = resets_val;
// Enable EXI
// Enable EXI
β
u32 aip_prot_val = *(u32 *)HW_AIP_PROT;
+
u32 aip_prot_val = *(u32 *)HW_AIPPROT;
aip_prot_val &= ~(0x01);
aip_prot_val &= ~(0x01);
aip_prot_val |= 0x01;
aip_prot_val |= 0x01;
β
*(u32 *)HW_AIP_PROT = aip_prot_val;
+
*(u32 *)HW_AIPPROT = aip_prot_val;
β
=== check_hw ===
+
=== TestHardware ===
boot1 setups the fan's speed and power, initializes I2C for SMC and validates the hardware version.
boot1 setups the fan's speed and power, initializes I2C for SMC and validates the hardware version.
Line 159:
Line 163:
}
}
β
=== get_rtc_events ===
+
=== GetRtcEvents ===
boot1 setups EXI for the RTC and collects events from RTC_CONTROL0 and RTC_CONTROL1.
boot1 setups EXI for the RTC and collects events from RTC_CONTROL0 and RTC_CONTROL1.
Line 193:
Line 197:
}
}
β
u32 debug_val = *(u32 *)LT_DEBUG;
+
u32 syscfg1_val = *(u32 *)LT_SYSCFG1;
β
u32 state_flag = 0;
+
u32 pflags_val = 0;
// Check if the CMPT_RETSTAT0 flag is raised
// Check if the CMPT_RETSTAT0 flag is raised
β
if (debug_val & 0x04)
+
if (syscfg1_val & 0x04)
β
state_flag = 0x100000;
+
pflags_val = 0x100000; // Set CMPT_RETSTAT0 power flag
// Check if the CMPT_RETSTAT1 flag is raised
// Check if the CMPT_RETSTAT1 flag is raised
β
if (debug_val & 0x08)
+
if (syscfg1_val & 0x08)
β
state_flag |= 0x80000;
+
pflags_val |= 0x80000; // Set CMPT_RETSTAT1 power flag
u32 rtc_ctrl0 = *(u32 *)rtc_control0_buf;
u32 rtc_ctrl0 = *(u32 *)rtc_control0_buf;
Line 208:
Line 212:
// Check if the POFFLG_FPOFF flag is raised
// Check if the POFFLG_FPOFF flag is raised
if (rtc_ctrl0 & 0x04000000)
if (rtc_ctrl0 & 0x04000000)
β
state_flag |= 0x01000000;
+
pflags_val |= 0x01000000; // Set POFF_FORCED power flag
// Check if the POFFLG_4S flag is raised
// Check if the POFFLG_4S flag is raised
if (rtc_ctrl0 & 0x02000000)
if (rtc_ctrl0 & 0x02000000)
β
state_flag |= 0x00800000;
+
pflags_val |= 0x00800000; // Set POFF_4S power flag
// Check if the POFFLG_TMR flag is raised
// Check if the POFFLG_TMR flag is raised
if (rtc_ctrl0 & 0x01000000)
if (rtc_ctrl0 & 0x01000000)
β
state_flag |= 0x00400000;
+
pflags_val |= 0x00400000; // Set POFF_TMR power flag
// Check if the PONLG_TMR flag is raised
// Check if the PONLG_TMR flag is raised
if (rtc_ctrl0 & 0x00010000)
if (rtc_ctrl0 & 0x00010000)
β
state_flag |= 0x02000000;
+
pflags_val |= 0x02000000; // Set PON_TMR power flag
// Check if PONFLG_SYS is raised
// Check if PONFLG_SYS is raised
if (rtc_ctrl0 & 0x00020000)
if (rtc_ctrl0 & 0x00020000)
{
{
β
state_flag |= 0x04000000;
+
pflags_val |= 0x04000000; // Set PON_SMC power flag
// Read the SystemEventFlag from SMC
// Read the SystemEventFlag from SMC
Line 234:
Line 238:
// POWER button was pressed
// POWER button was pressed
if (sys_event & 0x00000040)
if (sys_event & 0x00000040)
β
state_flag |= 0x80000000;
+
pflags_val |= 0x80000000; // Set PON_POWER_BTN power flag
// EJECT button was pressed
// EJECT button was pressed
if (sys_event & 0x00000020)
if (sys_event & 0x00000020)
β
state_flag |= 0x40000000;
+
pflags_val |= 0x40000000; // Set PON_EJECT_BTN power flag
// Wake 1 signal is active
// Wake 1 signal is active
if (sys_event & 0x00000001)
if (sys_event & 0x00000001)
β
state_flag |= 0x08000000;
+
pflags_val |= 0x08000000; // Set PON_WAKEREQ1_EVENT power flag
// Wake 0 signal is active
// Wake 0 signal is active
if (sys_event & 0x00000002)
if (sys_event & 0x00000002)
β
state_flag |= 0x10000000;
+
pflags_val |= 0x10000000; // Set PON_WAKEREQ0_EVENT power flag
// BT interrupt request is active
// BT interrupt request is active
if (sys_event & 0x00000004)
if (sys_event & 0x00000004)
β
state_flag |= 0x20000000;
+
pflags_val |= 0x20000000; // Set PON_WAKEBT_EVENT power flag
// Timer signal is active
// Timer signal is active
if (sys_event & 0x00000008)
if (sys_event & 0x00000008)
β
state_flag |= 0x00020000;
+
pflags_val |= 0x00020000; // Set PON_SMC_TIMER power flag
}
}
Line 264:
Line 268:
// Check if SLEEP_EN is raised
// Check if SLEEP_EN is raised
if (rtc_ctrl1 & 0x00000100)
if (rtc_ctrl1 & 0x00000100)
β
state_flag |= 0x00200000;
+
pflags_val |= 0x00200000; // Set DDR_SREFRESH power flag
u32 mem_mode = 0;
u32 mem_mode = 0;
β
// SLEEP_EN is raised
+
// DDR_SREFRESH power flag is set
β
if (state_flag & 0x00200000)
+
if (pflags_val & 0x00200000)
mem_mode = 0x08;
mem_mode = 0x08;
β
// sys_event has 0x00000008 flag (timer signal) set
+
// PON_SMC_TIMER power flag is set
β
if (state_flag & 0x00020000)
+
if (pflags_val & 0x00020000)
{
{
// Pulse the CCIndicator
// Pulse the CCIndicator
Line 289:
Line 293:
}
}
β
=== init_mem ===
+
=== InitializeMemory ===
boot1 initializes the memory controller.
boot1 initializes the memory controller.
Line 308:
Line 312:
}
}
β
=== mem2_test ===
+
=== WriteMem2 ===
boot1 tests MEM2 by writing a pattern over it's first 0x400 bytes.
boot1 tests MEM2 by writing a pattern over it's first 0x400 bytes.
Line 317:
Line 321:
if (error_count)
if (error_count)
{
{
β
// SLEEP_EN is raised
+
// DDR_SREFRESH power flag is set
β
if (state_flag & 0x00200000)
+
if (pflags_val & 0x00200000)
{
{
// Check memory
// Check memory
Line 353:
Line 357:
}
}
β
=== mem2_check ===
+
=== TestMem2 ===
boot1 checks if MEM2 refreshing is working.
boot1 checks if MEM2 refreshing is working.
Line 409:
Line 413:
}
}
β
=== mem0_clear ===
+
=== ClearMem0 ===
boot1 clears all MEM0 and adjusts IOP clock multiplier if necessary.
boot1 clears all MEM0 and adjusts IOP clock multiplier if necessary.
Line 415:
Line 419:
memset(0x08000000, 0, 0x002E0000);
memset(0x08000000, 0, 0x002E0000);
β
// sys_event doesn't have 0x00000008 flag (timer signal) set
+
// PON_SMC_TIMER power flag is not set
β
if (!(state_flag & 0x00020000))
+
if (!(pflags_val & 0x00020000))
{
{
// Change NDEV_LED state
// Change NDEV_LED state
Line 441:
Line 445:
}
}
β
=== get_boot_info ===
+
=== GetBootInfo ===
boot1 decrypts the PRSH/PRST from MEM2 and parses the "boot_info" structure.
boot1 decrypts the PRSH/PRST from MEM2 and parses the "boot_info" structure.
Line 481:
Line 485:
sub_D40AF10(0);
sub_D40AF10(0);
β
// SLEEP_EN is raised
+
// DDR_SREFRESH power flag is set
β
if ((state_flag & 0x01E00001) == 0x00200000)
+
if ((pflags_val & 0x01E00001) == 0x00200000)
{
{
*(u32 *)boot_info_08_addr = 0;
*(u32 *)boot_info_08_addr = 0;
Line 493:
Line 497:
{
{
u32 boot_info_08 = *(u32 *)boot_info_08_addr;
u32 boot_info_08 = *(u32 *)boot_info_08_addr;
β
state_flag |= (boot_info_08 & 0x101E);
+
pflags_val |= (boot_info_08 & 0x101E);
}
}
}
}
else
else
{
{
β
// Mask boot_info_04 with 0xBFFFFFFF
+
// Clear bit 6 (IsWarmboot) in boot_info_04
sub_D40AE4C();
sub_D40AE4C();
β
// Mask boot_info_04 with 0xF7FFFFFF and set some other fields
+
// Clear bit 3 (HasRamFwImg) in boot_info_04 and reset the RamFwImg fields
sub_D40AC7C();
sub_D40AC7C();
}
}
// Set boot_info_08
// Set boot_info_08
β
sub_D40AC30(state_flag);
+
sub_D40AC30(pflags_val);
β
=== load_fw_img ===
+
=== LoadFwImg ===
boot1 loads, validates and decrypts the IOSU fw.img file.
boot1 loads, validates and decrypts the IOSU fw.img file.
Line 893:
Line 897:
// Get timer value
// Get timer value
β
u32 time_after_fw_decrypt = *(u32 *)LT_TIMER;
+
u32 time_after_fw_decrypt = *(u32 *)HW_TIMER;
// Calculate time spent decrypting fw.img
// Calculate time spent decrypting fw.img
Line 915:
Line 919:
// Lock out two additional blocks in the OTP
// Lock out two additional blocks in the OTP
β
u32 otpprot_val = *(u32 *)LT_OTPPROT;
+
u32 efuseprot_val = *(u32 *)LT_EFUSEPROT;
β
otpprot_val &= 0xEF7FFFFF;
+
efuseprot_val &= 0xEF7FFFFF;
β
*(u32 *)LT_OTPPROT = otpprot_val;
+
*(u32 *)LT_EFUSEPROT = efuseprot_val;
u32 onoff_val = 0;
u32 onoff_val = 0;
β
// Setup ODD based on boot data
+
// PON_SMC_TIMER and an unknown power flag are set
β
if (state_flag & 0x00020010)
+
if (pflags_val & 0x00020010)
{
{
// Set DcdcPowerControl2 GPIO's state
// Set DcdcPowerControl2 GPIO's state
Line 985:
Line 989:
sub_D40AD2C(0x07, time_boot1_decrypt);
sub_D40AD2C(0x07, time_boot1_decrypt);
β
// Set flag 0x04000000 in boot_info_04
+
// Set bit 2 (HasBootTimeStats) in boot_info_04
sub_D40ABCC();
sub_D40ABCC();
Line 1,001:
Line 1,005:
// Deadlock
// Deadlock
loc_D400A3A();
loc_D400A3A();
+
+
== BootInfo ==
+
This is the "boot_info" structure used for sharing information between boot1 and IOS-MCP.
+
+
{| class="wikitable" border="1"
+
|-
+
! Offset || Size || Description
+
|-
+
| 0x0 || 0x4 || Version
+
|-
+
| 0x4 || 0x4 || [[#BootFlags|BootFlags]]
+
|-
+
| 0x8 || 0x4 || [[#PowerFlags|PowerFlags]]
+
|-
+
| 0xC || 0x4 || BootCount
+
|-
+
| 0x10 || 0x4 || [[#SystemMode|CurrentSystemMode]]
+
|-
+
| 0x14 || 0x4 || [[#SystemMode|NextSystemMode]]
+
|-
+
| 0x18 || 0x4 ||
+
|-
+
| 0x1C || 0x4 ||
+
|-
+
| 0x20 || 0x4 ||
+
|-
+
| 0x24 || 0x4 ||
+
|-
+
| 0x28 || 0x4 || RamFwImgOsIdHigh
+
|-
+
| 0x2C || 0x4 || RamFwImgOsIdLow
+
|-
+
| 0x30 || 0x4 || RamFwImgAddress
+
|-
+
| 0x34 || 0x4 || RamFwImgSize
+
|-
+
| 0x38 || 0x4 || Boot1MainTime
+
|-
+
| 0x3C || 0x4 || Boot1ReadTime
+
|-
+
| 0x40 || 0x4 || Boot1VerifyTime
+
|-
+
| 0x44 || 0x4 || Boot1DecryptTime
+
|-
+
| 0x48 || 0x4 || Boot0MainTime
+
|-
+
| 0x4C || 0x4 || Boot0ReadTime
+
|-
+
| 0x50 || 0x4 || Boot0VerifyTime
+
|-
+
| 0x54 || 0x4 || Boot0DecryptTime
+
|}
+
+
=== BootFlags ===
+
{| class="wikitable" border="1"
+
|-
+
! Bits
+
! Description
+
|-
+
| 0
+
| IsPowerTransitionsEnabled
+
|-
+
| 1
+
| IsProd
+
|-
+
| 2
+
| HasBootTimeStats
+
|-
+
| 3
+
| HasRamFwImg
+
|-
+
| 4
+
|
+
|-
+
| 5
+
| IsBootModeNand
+
|-
+
| 6
+
| IsWarmboot
+
|-
+
| 7
+
| HasBootInfo
+
|-
+
| 8
+
|
+
|-
+
| 9
+
|
+
|-
+
| 10
+
|
+
|-
+
| 11
+
|
+
|-
+
| 12
+
|
+
|-
+
| 13
+
|
+
|-
+
| 14
+
|
+
|-
+
| 15
+
| IsPonEjectBtn
+
|-
+
| 16-31
+
|
+
|}
+
+
=== PowerFlags ===
+
{| class="wikitable" border="1"
+
|-
+
! Bits
+
! Description
+
|-
+
| 0
+
| PFLAGS_INVALID
+
|-
+
| 1
+
| PON_WAKEREQ1_EVENT_SW
+
|-
+
| 2
+
| PON_WAKEBT_EVENT_SW
+
|-
+
| 3
+
| PON_POWER_BTN_SW
+
|-
+
| 4
+
| ENTER_BG_NORMAL_MODE
+
|-
+
| 5
+
|
+
|-
+
| 6
+
|
+
|-
+
| 7
+
|
+
|-
+
| 8
+
|
+
|-
+
| 9
+
| PON_SMC_DISC
+
|-
+
| 10
+
| PON_SYNC_BTN
+
|-
+
| 11
+
|
+
|-
+
| 12
+
|
+
|-
+
| 13
+
| PON_RESTART
+
|-
+
| 14
+
|
+
|-
+
| 15
+
|
+
|-
+
| 16
+
| PON_COLDBOOT
+
|-
+
| 17
+
| PON_SMC_TIMER
+
|-
+
| 18
+
|
+
|-
+
| 19
+
| CMPT_RETSTAT1
+
|-
+
| 20
+
| CMPT_RETSTAT0
+
|-
+
| 21
+
| DDR_SREFRESH
+
|-
+
| 22
+
| POFF_TMR
+
|-
+
| 23
+
| POFF_4S
+
|-
+
| 24
+
| POFF_FORCED
+
|-
+
| 25
+
| PON_TMR
+
|-
+
| 26
+
| PON_SMC
+
|-
+
| 27
+
| PON_WAKEREQ1_EVENT
+
|-
+
| 28
+
| PON_WAKEREQ0_EVENT
+
|-
+
| 29
+
| PON_WAKEBT_EVENT
+
|-
+
| 30
+
| PON_EJECT_BTN
+
|-
+
| 31
+
| PON_POWER_BTN
+
|}
+
+
=== SystemMode ===
+
{| class="wikitable" border="1"
+
|-
+
! Bits
+
! Description
+
|-
+
| 0
+
| Off
+
|-
+
| 1
+
| Compat
+
|-
+
| 2
+
| Standby
+
|-
+
| 3
+
| Restart
+
|-
+
| 4-14
+
|
+
|-
+
| 15
+
| WiiReturn
+
|-
+
| 16-17
+
|
+
|-
+
| 18
+
| Recovery
+
|-
+
| 19
+
| Eco
+
|-
+
| 20
+
| Normal
+
|-
+
| 21-31
+
|
+
|}
== Error codes ==
== Error codes ==
Line 1,007:
Line 1,264:
{| class="wikitable"
{| class="wikitable"
|-
|-
β
! Error code
+
! Value
β
! Notes
+
! Description
|-
|-
| 0xF1
| 0xF1
Line 1,015:
Line 1,272:
| 0xF2
| 0xF2
| Failed to initialize memory
| Failed to initialize memory
+
|-
+
| 0xF3
+
| Failed to initialize [[Hardware/Toucan|Toucan]]
+
|-
+
| 0xF4
+
| Failed to read packages from [[Hardware/Toucan|Toucan]]
+
|-
+
| 0xF5
+
| Failed to read firmware image from [[Hardware/Toucan|Toucan]]
|-
|-
| 0xF6
| 0xF6