# iBoot RE (64 bits)

We focus on 64 bit iBoot cause we should:)

## In the beginning

### The Loading Address

Bootloaders in general and iBoot in particular expect to run at a specific, predefined, addresses.
Such an address called the __loading address__ (reset vector) of a bootloader.
When loading the bootloader into IDA you need to supply the loading address, so IDA will be able to
resolve data and code references properly.

Most Apple bootloaders start with a relocation code which compares the loading address with the current
address and moves the bootloader if needed.

Looking at this relocation code we can extract the loading address of the particular bootloader.

So, we start by using 0 as the loading address until we know better.

Here is an iBoot 64 bit example loaded at 0:

~~~ data
ROM:000 loc_0
ROM:000
ROM:000          ADRP     X0, #loc_0@PAGE
ROM:004          ADD      X0, X0, #loc_0@PAGEOFF <=== X0 has the current page address
ROM:008          LDR      X1, =0x83D37B000       <=== this is the loading address
ROM:00C          BL       sub_17634
ROM:010          CMP      X1, X0                 <=== are we running at loading address
ROM:014          B.EQ     loc_44                 <=== if yes: continue booting normally
ROM:018          MOV      X30, X1                <=== else: set LR to loading address
ROM:01C          LDR      X2, =0x83D413440
ROM:020          LDR      X3, =0x83D37B000
ROM:024          SUB      X2, X2, X3            <=== calculate len
ROM:028
ROM:028 loc_28                                  <=== copy loop
ROM:028          LDP      X3, X4, [X0]
ROM:02C          STP      X3, X4, [X1]
ROM:030          ADD      X0, X0, #0x10
ROM:034          ADD      X1, X1, #0x10
ROM:038          SUBS     X2, X2, #0x10
ROM:03C          B.NE     loc_28
ROM:040          RET                            <=== done copying -> return to loading address (LR)
ROM:044 ; -------------------------------------------------------------
ROM:044
ROM:044 loc_44                                  <=== rest of the iboot
ROM:044          MSR      #6, #0xF ; MSR DAIFSET, #0XF
ROM:048          ADRP     X30, #loc_AC8@PAGE
ROM:04C          ADD      X30, X30, #loc_AC8@PAGEOFF
ROM:050          ADRP     X10, #loc_1F000@PAGE
ROM:054          ADD      X10, X10, #loc_1F000@PAGEOFF
ROM:058          MSR      #6, c12, c0, #0, X10 ; MSR VBAR_EL3, X10
~~~

So, the __loading address__ in this example is: __0x83D37B000__.
With this knowledge we can load the iboot to IDA with a proper loading address.

For 32 bits iboot the relocation code works the same, but it's not the first code.
The iboot starts with an exception vector.The first vector (reset) branches to the relocation code and
it's the same from there.

Other bootloader: LLB, iBEC, IBSS have the same relocation code and hence the loading address available
for grabbing.

### Beyond the loading address

After relocation of the iBoot to the proper running place, the boot continues.
Setting SP pointers, exception tables, etc.
Below is the rest of the first function that runs on boot.
Between the comments and the labels you should have no troubles following the code flow.

~~~ data
.........   [        relocation code as shown above        ]
ROM:83D07B044
ROM:83D07B044   ; mask exceptions
ROM:83D07B044                 MSR             #6, #0xF ; MSR DAIFSET, #0XF
ROM:83D07B048   ; set the next function to be executed on return
ROM:83D07B048                 ADRP            X30, #_start@PAGE
ROM:83D07B04C                 ADD             X30, X30, #_start@PAGEOFF
ROM:83D07B050   ; setup exceptions table base address
ROM:83D07B050                 ADRP            X10, #exception_table@PAGE
ROM:83D07B054                 ADD             X10, X10, #exception_table@PAGEOFF
ROM:83D07B058                 MSR             #6, c12, c0, #0, X10 ; MSR VBAR_EL3, X10
ROM:83D07B05C   ; clear 512K of memory
ROM:83D07B05C                 LDR             X10, =base_addr_for_stack_and_stuff
ROM:83D07B060                 LDR             X11, =0x80000 ; 512K
ROM:83D07B064                 ADD             X11, X11, X10
ROM:83D07B068                 MOV             X12, #0
ROM:83D07B06C loop__clear_512K
ROM:83D07B06C                 STP             X12, X12, [X10]
ROM:83D07B070                 ADD             X10, X10, #0x10
ROM:83D07B074                 CMP             X10, X11
ROM:83D07B078                 B.NE            loop__clear_512K
ROM:83D07B07C   ; set base address for stack and stuff
ROM:83D07B07C                 LDR             X10, =base_addr_for_stack_and_stuff
ROM:83D07B080                 ADD             X10, X10, #1,LSL#12 ; (base + 4K)
ROM:83D07B084   ; set EL3 SP to (base + 4K)
ROM:83D07B084                 MOV             SP, X10
ROM:83D07B088                 MSR             #5, #0  ; MSR SPSEL, #0
ROM:83D07B08C                 ADD             X10, X10, #2,LSL#12 ; ((base + 4K) + 8K)
ROM:83D07B090   ; set EL0 SP to (base + 12K)
ROM:83D07B090                 MOV             SP, X10
ROM:83D07B094                 ADD             X20, X10, #2,LSL#12 ; (((base + 4K) + 8K) + 8K)
ROM:83D07B098   ; zero additional space
ROM:83D07B098                 LDR             X10, =_iboot_end ; from this addr
ROM:83D07B09C                 LDR             X11, =fb_mbe ; to this addr
ROM:83D07B0A0                 MOV             X12, #0xF
ROM:83D07B0A4                 BIC             X12, X11, X12 ; end addr aligned to 16
ROM:83D07B0A8                 MOV             X13, #0
ROM:83D07B0AC   ; clear more space, aligned 16
ROM:83D07B0AC loop__clear_more__aligned
ROM:83D07B0AC                 STP             X13, X13, [X10],#0x10
ROM:83D07B0B0                 CMP             X10, X12
ROM:83D07B0B4                 B.NE            loop__clear_more__aligned
ROM:83D07B0B8                 CMP             X11, X12
ROM:83D07B0BC                 B.EQ            loc_83D07B0CC
ROM:83D07B0C0  ; clear more space, the rest (unaligned)
ROM:83D07B0C0 loop__clear_more__unaligned
ROM:83D07B0C0                 STR             W13, [X10],#4
ROM:83D07B0C4                 CMP             X10, X11
ROM:83D07B0C8                 B.NE            loop__clear_more__unaligned
ROM:83D07B0CC
ROM:83D07B0CC loc_83D07B0CC
ROM:83D07B0CC  ; set Exception handlers SP to (base + 20K)
ROM:83D07B0CC                 ADRP            X11, #sp_for_exception_handlers@PAGE
ROM:83D07B0D0                 ADD             X11, X11, #sp_for_exception_handlers@PAGEOFF
ROM:83D07B0D4                 STR             X20, [X11]
ROM:83D07B0D8                 RET
~~~

Notes:

- MSR DAIFSET, #0XF (mask all exceptions)
  This is very early stage and we don't want to be interrupted before we can handle exceptions properly.
- _start
  We are running a kind of a 'reset vector' code now and this is the next
  function we execute by setting its address in the LR register and running with the RET instruction.
- exception_table
  The address that goes into the VBAR_EL3 register is the beginning of the EL3 exception table.
  ARMv8 is very different from ARMv7 in how the exception table looks and works.
  Some of the differences are:
  - Instead of vector of dwords it has 0x80 bytes of code for each exception
  - There are multiple entries for the same exception depending on the circumstances of where the exception is taken from
