+
+ fdt_load(&fdt, dtb);
+ fdt_memscan_begin(&mscan, &fdt);
+
+ struct boot_mmapent* mmap_ent;
+
+ while(fdt_memscan_nextnode(&mscan, &fdt))
+ {
+ while (fdt_memscan_nextrange(&mscan, &mnode))
+ {
+ mmap_ent = &mmap[mmap_len++];
+ *mmap_ent = (struct boot_mmapent) {
+ .size = mnode.size,
+ .start = mnode.base
+ };
+
+ if (mnode.type == FDT_MEM_FREE) {
+ mmap_ent->type = BOOT_MMAP_FREE;
+ pmem_size += mnode.size;
+ }
+ else {
+ mmap_ent->type = BOOT_MMAP_RSVD;
+ }
+
+
+ if (mmap_len < mmap_max_len) {
+ continue;
+ }
+
+ mmap_max_len += MMAP_ENTS_CHUNK_SIZE;
+
+ // another allocation is just expanding the previous allocation.
+ bootmem_alloc(sizeof(*mmap) * MMAP_ENTS_CHUNK_SIZE);
+ }
+ }
+
+ handoff->mem.mmap = mmap;
+ handoff->mem.mmap_len = mmap_len;
+ handoff->mem.size = pmem_size;
+}
+
+static inline void
+setup_gic_sysreg()
+{
+ int el;
+ bool has_el2;
+ u64_t pfr;
+
+ pfr = read_sysreg(ID_AA64PFR0_EL1);
+ el = read_sysreg(CurrentEL) >> 2;
+
+ // Arm A-Profile: D19.2.69, check for GIC sysreg avaliability
+
+ if (!BITS_GET(pfr, BITFIELD(27, 24))) {
+ return;
+ }
+
+ has_el2 = !!BITS_GET(pfr, BITFIELD(11, 8));
+
+ // GIC spec (v3,v4): 12.1.7, table 12-2
+ // GIC spec (v3,v4): ICC_SRE_ELx accessing
+ // Arm A-Profile: R_PCDTX, PSTATE.EL reset value
+
+ if (el == 3) {
+ sysreg_flagging(ICC_SRE_EL3, ICC_SRE_SRE, 0);
+ }
+
+ if (has_el2) {
+ // el must be >= 2
+ sysreg_flagging(ICC_SRE_EL2, ICC_SRE_SRE, 0);
+ }
+
+ sysreg_flagging(ICC_SRE_EL1, ICC_SRE_SRE, 0);
+}
+
+void boot_text
+aarch64_pre_el1_init()
+{
+ setup_gic_sysreg();
+}
+
+bool boot_text
+aarch64_prepare_el1_transfer()
+{
+ ptr_t spsr;
+ int el;
+
+ el = read_sysreg(CurrentEL) >> 2;
+
+ if (el == 1) {
+ // no transfer required
+ return false;
+ }
+
+ spsr = SPSR_EL1_preset;
+ spsr |= SPSR_AllInt | SPSR_I | SPSR_F | SPSR_A;
+
+ if (el == 2) {
+ set_sysreg(SPSR_EL2, spsr);
+ }
+ else {
+ set_sysreg(SPSR_EL3, spsr);
+ }
+
+ return true;