iBoot Flags

From The Apple Wiki

Notes

Initial

Initially, boot flags are set to 0x2C0000, or:

bit0: No

bit 1: No

bit 2: No

bit 3: No

bit 4: No

bit 5: No

bit 6: No

bit 7: No

bit 8: No

bit 9: No

bit 10: No

bit 11: No

bit 12: No

bit 13: No

bit 14: No

bit 15: No

bit 16: No

bit 17: No

bit 18: Yes

bit 19: Yes

bit 20: No

bit 21: Yes

bit 22: No

bit 23: No

bit 24: No

bit 25: No

bit 26: No

bit 27: No

bit 28: No

bit 29: No

bit 30: No

bit 31: No

Commands

||***Command***||***Bits***|| ||powernvram||Check if bit 8 is set to even allow the command to be used without a Permission Denied error, and check if bit is set 17 to allow usage of the 'set' subcommand|| ||diags||Check if bit 4 is set to allow usage of ***diags [address]*** to execute code.|| ||charge||Check if bits 8 ***and*** 17 are set to allow usage of this command.|| ||bdev||Check if bit 8 is set to allow usage of this command.|| ||pki||Check if bit 8 is set to allow usage of this command.|| ||image||Check if bit 8 is set to allow usage of this command.|| ||iic||Check of bit 17 is set to allow usage of this command.|| ||chunk||Check if bit 8 is set to allow usage of this command.||

Undocumented Routine

This stuff is from an interesting (and long) routine that I am not quite sure what it does, it has something to do with the 'bootx' command though, I think.

||***Thing***||***Bits***|| ||System-Trusted||Check if bit 29 is set.|| ||Secure-Boot||Check if bit 28 is set.|| ||uid-aes-key||Check if bit 19 is set.|| ||gid-aes-key||Check if bit 18 is set.|| ||production-cert||Check if bit 21 is set.|| ||development-cert||Check if bit 20 is set.|| ||debug-enabled||Check if bit 5 is set.||

Range Check

If bit 16 is set, range check is bypassed.

Reversing

Reversings of various routines that relate to the iBoot flags in an effort to find out what does what.

Setup Range

ROM:0FF0BD38                 ; =============== S U B R O U T I N E =======================================
ROM:0FF0BD38
ROM:0FF0BD38                 ; logic:
ROM:0FF0BD38                 ; if running on a special engineering / debug device, return.
ROM:0FF0BD38                 ; if 'option' is not set to 0, then set mimimum address to -1 and maximum address to 0. then return. wtf?
ROM:0FF0BD38                 ; if new_min is higher or equal to the current minimum address, don't set it.
ROM:0FF0BD38                 ; if new_max is lower or equal to the current maximum address, don't set it.
ROM:0FF0BD38
ROM:0FF0BD38                 ; void __cdecl Set_Up_Allowed_Range(__int32 new_min, __int32 new_max, int option)
ROM:0FF0BD38                 Set_Up_Allowed_Range                    ; CODE XREF: sub_FF07682+B9E�p
ROM:0FF0BD38                                                         ; sub_FF0BD7C+6E�p
ROM:0FF0BD38                 new_min = R0                            ; new minimum allowed address to be set
ROM:0FF0BD38                 new_max = R1                            ; this one is weird. it should be new maximum address minus the new minimum
ROM:0FF0BD38 000 10 B5                       PUSH    {R4,LR}         ; Push registers
ROM:0FF0BD3A 008 0D 4B                       LDR     R3, =iBoot_flags ; Load from Memory
ROM:0FF0BD3C 008 41 18                       ADDS    new_max, new_min, new_max ; new_max + new_min = real new maximum (wtf?)
ROM:0FF0BD3E 008 1B 68                       LDR     R3, [R3]        ; Load from Memory
ROM:0FF0BD40 008 DC 03                       LSLS    R4, R3, #0xF    ; Logical Shift Left
ROM:0FF0BD42 008 13 D4                       BMI     return          ; if bit 16 is set, return.
ROM:0FF0BD42                                                         ;
ROM:0FF0BD42                                                         ; by the looks of it, bit 16 is set when the device is a special
ROM:0FF0BD42                                                         ; engineering / debug device
ROM:0FF0BD44 008 00 2A                       CMP     R2, #0          ; Set cond. codes on Op1 - Op2
ROM:0FF0BD46 008 07 D0                       BEQ     set_minimum     ; if the "option" arg is 0, jump here.
ROM:0FF0BD48
ROM:0FF0BD48                 bad                                     ; Load from Memory
ROM:0FF0BD48 008 0A 4A                       LDR     R2, =Minimum_Allowed_Addr
ROM:0FF0BD4A 008 01 23                       MOVS    R3, #1          ; Rd = Op2
ROM:0FF0BD4C 008 5B 42                       NEGS    R3, R3          ; Negate
ROM:0FF0BD4E 008 13 60                       STR     R3, [R2]        ; set minimum address to -1
ROM:0FF0BD50 008 09 4B                       LDR     R3, =Maximum_Allowed_Addr ; Load from Memory
ROM:0FF0BD52 008 00 22                       MOVS    R2, #0          ; Rd = Op2
ROM:0FF0BD54 008 1A 60                       STR     R2, [R3]        ; set maximum address to 0
ROM:0FF0BD56 008 09 E0                       B       return          ; Branch
ROM:0FF0BD58                 ; ---------------------------------------------------------------------------
ROM:0FF0BD58
ROM:0FF0BD58                 set_minimum                             ; CODE XREF: Set_Up_Allowed_Range+E�j
ROM:0FF0BD58 008 06 4A                       LDR     R2, =Minimum_Allowed_Addr ; Load from Memory
ROM:0FF0BD5A 008 13 68                       LDR     R3, [R2]        ; Load from Memory
ROM:0FF0BD5C 008 98 42                       CMP     new_min, R3     ; Set cond. codes on Op1 - Op2
ROM:0FF0BD5E 008 00 D2                       BCS     set_maximum     ; if new_min is higher or the same as the current
ROM:0FF0BD5E                                                         ; minimum address, don't change anything.
ROM:0FF0BD60 008 10 60                       STR     new_min, [R2]   ; set the minimum address to new_min
ROM:0FF0BD62
ROM:0FF0BD62                 set_maximum                             ; CODE XREF: Set_Up_Allowed_Range+26�j
ROM:0FF0BD62 008 05 4A                       LDR     R2, =Maximum_Allowed_Addr ; Load from Memory
ROM:0FF0BD64 008 13 68                       LDR     R3, [R2]        ; Load from Memory
ROM:0FF0BD66 008 99 42                       CMP     new_max, R3     ; Set cond. codes on Op1 - Op2
ROM:0FF0BD68 008 00 D9                       BLS     return          ; if new_max is less than or the same as the current
ROM:0FF0BD68                                                         ; maximum address, don't change anything.
ROM:0FF0BD6A 008 11 60                       STR     new_max, [R2]   ; set maximum address to new_max
ROM:0FF0BD6C
ROM:0FF0BD6C                 return                                  ; CODE XREF: Set_Up_Allowed_Range+A�j
ROM:0FF0BD6C                                                         ; Set_Up_Allowed_Range+1E�j
ROM:0FF0BD6C                                                         ; Set_Up_Allowed_Range+30�j
ROM:0FF0BD6C 008 10 BD                       POP     {R4,PC}         ; Pop registers
ROM:0FF0BD6C                 ; End of function Set_Up_Allowed_Range
ROM:0FF0BD6C
ROM:0FF0BD6C                 ; ---------------------------------------------------------------------------
ROM:0FF0BD6E 00 00                           DCW 0
ROM:0FF0BD70 C0 86 F1 0F     off_FF0BD70     DCD iBoot_flags         ; DATA XREF: Set_Up_Allowed_Range+2�r
ROM:0FF0BD74 C4 86 F1 0F     off_FF0BD74     DCD Minimum_Allowed_Addr
ROM:0FF0BD74                                                         ; DATA XREF: Set_Up_Allowed_Range:bad�r
ROM:0FF0BD74                                                         ; Set_Up_Allowed_Range:set_minimum�r
ROM:0FF0BD78 C8 86 F1 0F     off_FF0BD78     DCD Maximum_Allowed_Addr
ROM:0FF0BD78                                                         ; DATA XREF: Set_Up_Allowed_Range+18�r
ROM:0FF0BD78                                                         ; Set_Up_Allowed_Range:set_maximum�r

Range Check

ROM:0FF0BD04                 ; =============== S U B R O U T I N E =======================================
ROM:0FF0BD04
ROM:0FF0BD04                 ; iboot range check
ROM:0FF0BD04                 ;
ROM:0FF0BD04                 ; logic:
ROM:0FF0BD04                 ; if running on a special dev board, we are good to go. bypasses the range check.
ROM:0FF0BD04                 ; if unkown addr is negative for some reason, then fail.
ROM:0FF0BD04                 ; if addr to check is less than the minimum addr defined at 0x0ff186c4, then fail.
ROM:0FF0BD04                 ; if addr to check is greater than the maximum addr defined in 0xff186c8, then fail.
ROM:0FF0BD04                 ;
ROM:0FF0BD04                 ; psuedocode:
ROM:0FF0BD04                 ; int permissions_check(long addr_to_check, long unk_addr) {
ROM:0FF0BD04                 ;     if(flags at 0x0ff186c0 << 0xF < 0) { // is bit 16 set?
ROM:0FF0BD04                 ;         return(1);    // aka, success.
ROM:0FF0BD04                 ;     }
ROM:0FF0BD04                 ;     if(addr to check >= unk addr + addr to check) {
ROM:0FF0BD04                 ;         return(0);    // aka, fail.
ROM:0FF0BD04                 ;     }
ROM:0FF0BD04                 ;     if(addr to check < min allowed addr) {
ROM:0FF0BD04                 ;         return(0);    // aka, fail.
ROM:0FF0BD04                 ;     }
ROM:0FF0BD04                 ;     if(addr to check > max allowed addr) {
ROM:0FF0BD04                 ;         return(0);    // aka, fail.
ROM:0FF0BD04                 ;     }
ROM:0FF0BD04                 ;
ROM:0FF0BD04                 ;     return(1);    // aka, success, since the other checks above passed
ROM:0FF0BD04                 ; }
ROM:0FF0BD04
ROM:0FF0BD04                 ; int __cdecl range_check(__int32 addr_to_check, __int32 unk_addr)
ROM:0FF0BD04                 range_check                             ; CODE XREF: cmd_bootx+30�p
ROM:0FF0BD04                                                         ; cmd_diags+1C�p
ROM:0FF0BD04                                                         ; sub_FF00BE8+64�p
ROM:0FF0BD04                                                         ; sub_FF00CA8+56�p ...
ROM:0FF0BD04 000 09 4B                       LDR     R3, =0xFF186C0  ; iboot flags
ROM:0FF0BD06 000 42 18                       ADDS    R2, R0, R1      ; r2 = addr to check + unknown addr
ROM:0FF0BD08 000 1B 68                       LDR     R3, [R3]        ; flags located at 0x0ff186c0
ROM:0FF0BD0A 000 D9 03                       LSLS    R1, R3, #0xF    ; Logical Shift Left
ROM:0FF0BD0C 000 09 D4                       BMI     return_success  ; return(1);    // good
ROM:0FF0BD0E 000 90 42                       CMP     R0, R2          ; Set cond. codes on Op1 - Op2
ROM:0FF0BD10 000 09 D2                       BCS     return_fail     ; return(0);    // bad
ROM:0FF0BD12 000 07 4B                       LDR     R3, =0xFF186C4  ; min addr
ROM:0FF0BD14 000 1B 68                       LDR     R3, [R3]        ; Load from Memory
ROM:0FF0BD16 000 98 42                       CMP     R0, R3          ; Set cond. codes on Op1 - Op2
ROM:0FF0BD18 000 05 D3                       BCC     return_fail     ; return(0);    // bad
ROM:0FF0BD1A 000 06 4B                       LDR     R3, =0xFF186C8  ; max addr
ROM:0FF0BD1C 000 1B 68                       LDR     R3, [R3]        ; Load from Memory
ROM:0FF0BD1E 000 9A 42                       CMP     R2, R3          ; Set cond. codes on Op1 - Op2
ROM:0FF0BD20 000 01 D8                       BHI     return_fail     ; return(0);    // bad
ROM:0FF0BD22
ROM:0FF0BD22                 return_success                          ; CODE XREF: range_check+8�j
ROM:0FF0BD22 000 01 20                       MOVS    R0, #1          ; return(1);    // good
ROM:0FF0BD24 000 00 E0                       B       return          ; Branch
ROM:0FF0BD26                 ; ---------------------------------------------------------------------------
ROM:0FF0BD26
ROM:0FF0BD26                 return_fail                             ; CODE XREF: range_check+C�j
ROM:0FF0BD26                                                         ; range_check+14�j
ROM:0FF0BD26                                                         ; range_check+1C�j
ROM:0FF0BD26 000 00 20                       MOVS    R0, #0          ; return(0);    // bad
ROM:0FF0BD28
ROM:0FF0BD28                 return                                  ; CODE XREF: range_check+20�j
ROM:0FF0BD28 000 70 47                       BX      LR              ; Branch to/from Thumb mode
ROM:0FF0BD28                 ; End of function range_check
ROM:0FF0BD28
ROM:0FF0BD28                 ; ---------------------------------------------------------------------------
ROM:0FF0BD2A 00 00                           DCW 0
ROM:0FF0BD2C C0 86 F1 0F     dword_FF0BD2C   DCD 0xFF186C0           ; DATA XREF: range_check�r
ROM:0FF0BD30 C4 86 F1 0F     dword_FF0BD30   DCD 0xFF186C4           ; DATA XREF: range_check+E�r
ROM:0FF0BD34 C8 86 F1 0F     dword_FF0BD34   DCD 0xFF186C8           ; DATA XREF: range_check+16�r

Permissions / Generic Flag Check

ROM:0FF0BCAC                 ; will check the given flag in the iboot flags
ROM:0FF0BCAC                 ;
ROM:0FF0BCAC                 ; logic:
ROM:0FF0BCAC                 ; if the iboot_flags do not contain the flag supplied to the routine, return 0                                      // bad
ROM:0FF0BCAC                 ; if the flags supplied to this routine does has bit 4 set, then set bit 5 in the iboot flags as well. return 1.    // good
ROM:0FF0BCAC
ROM:0FF0BCAC                 ; int __cdecl flag_check(int flag)
ROM:0FF0BCAC                 flag_check                              ; CODE XREF: cmd_diags+26�p
ROM:0FF0BCAC                                                         ; cmd_powernvram+E�p
ROM:0FF0BCAC                                                         ; cmd_powernvram+7E�p
ROM:0FF0BCAC                                                         ; cmd_charge+C�p ...
ROM:0FF0BCAC 000 10 B5                       PUSH    {R4,LR}         ; Push registers
ROM:0FF0BCAE 008 08 49                       LDR     R1, =iBoot_flags ; Load from Memory
ROM:0FF0BCB0 008 00 24                       MOVS    R4, #0          ; Rd = Op2
ROM:0FF0BCB2 008 0A 68                       LDR     R2, [R1]        ; Load from Memory
ROM:0FF0BCB4 008 13 1C                       ADDS    R3, R2, #0      ; Rd = Op1 + Op2
ROM:0FF0BCB6 008 03 40                       ANDS    R3, R0          ; Rd = Op1 & Op2
ROM:0FF0BCB8 008 98 42                       CMP     R0, R3          ; check iboot flags against the supplied flags
ROM:0FF0BCBA 008 07 D1                       BNE     return          ; return(0);
ROM:0FF0BCBC 008 01 24                       MOVS    R4, #1          ; Rd = Op2
ROM:0FF0BCBE 008 C3 06                       LSLS    R3, R0, #0x1B   ; check if the supplied flags has bit 4 set
ROM:0FF0BCC0 008 04 D5                       BPL     return          ; return(1);
ROM:0FF0BCC2 008 04 4B                       LDR     R3, =0xDFF3FFFF ; Load from Memory
ROM:0FF0BCC4 008 13 40                       ANDS    R3, R2          ; Rd = Op1 & Op2
ROM:0FF0BCC6 008 20 22                       MOVS    R2, #0x20       ; Rd = Op2
ROM:0FF0BCC8 008 13 43                       ORRS    R3, R2          ; Rd = Op1 | Op2
ROM:0FF0BCCA 008 0B 60                       STR     R3, [R1]        ; set bit 5 of the iboot flags
ROM:0FF0BCCC
ROM:0FF0BCCC                 return                                  ; CODE XREF: flag_check+E�j
ROM:0FF0BCCC                                                         ; flag_check+14�j
ROM:0FF0BCCC 008 20 1C                       ADDS    R0, R4, #0      ; Rd = Op1 + Op2
ROM:0FF0BCCE 008 10 BD                       POP     {R4,PC}         ; Pop registers
ROM:0FF0BCCE                 ; End of function flag_check

Thanks

MUCH thanks to CPICH for teaching me about all of this bitwise stuff that was really confusing to me at first

References

chronicdev Google Code