This patch modifies the aarch64 port to move the kernel from
the 2nd to 63rd GB or virtual memory. It also adjusts the early preboot and boot
assembly to dynamically adjust the early phys/virt mapping tables to make
it work regardless where in physical memory the kernel and DTB is loaded.
This allows us to use the same kernel binary on QEMU and Firecracker without
having to adjust relevant variables in the makefile and rebuild it to accomodate
the fact that each hypervisor would load loader.img in different area
of physical memory. Prior to this patch the kernel would be mapped 1:1
in the first 4 GB of phys/virt memory.

In essence, this patch enhances the preboot.S to dynamically identify
location of start_elf to jump to. Then it modifies boot.S to dynamically
calculate the offset between where kernel is located in virtual memory and where
it is loaded in physical memory and then adjust the 63rd GB of early boot
mapping tables accordingly. Finally it also adjust the virt/phys and phys/virt
translation functions in core/mmu.cc and other aspects in elf.cc and makefile.

After the patch the virtual memory layout would look like this in QEMU:

           vaddr            paddr     size perm memattr name
         8000000          8000000    10000 rwxp     dev gic_dist
         8010000          8010000    10000 rwxp     dev gic_cpu
         9000000          9000000     1000 rwxp     dev pl011
         9010000          9010000     1000 rwxp     dev pl031
        10000000         10000000 2eff0000 rwxp     dev pci_mem
        3eff0000         3eff0000    10000 rwxp     dev pci_io
       fc0000000         40000000   84e000 rwxp  normal kernel
      4010000000       4010000000 10000000 rwxp     dev pci_cfg
ffff80000a000000          a000000      200 rwxp  normal virtio_mmio_cfg
ffff80000a000200          a000200      200 rwxp  normal virtio_mmio_cfg
ffff80000a000400          a000400      200 rwxp  normal virtio_mmio_cfg
ffff80000a000600          a000600      200 rwxp  normal virtio_mmio_cfg
ffff80000a000800          a000800      200 rwxp  normal virtio_mmio_cfg
ffff80000a000a00          a000a00      200 rwxp  normal virtio_mmio_cfg
ffff80000a000c00          a000c00      200 rwxp  normal virtio_mmio_cfg
ffff80000a000e00          a000e00      200 rwxp  normal virtio_mmio_cfg
ffff80004084e000         4084e000 7f7b2000 rwxp  normal main
ffff90004084e000         4084e000 7f7b2000 rwxp  normal page
ffffa0004084e000         4084e000 7f7b2000 rwxp  normal mempool

Fixes #1087

Changes since V1: removed some code from loader.cc that got
acidentally added as part of the initial version of the patch.

Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>
---
 Makefile                   |  27 +++++---
 arch/aarch64/arch-dtb.cc   |  10 +--
 arch/aarch64/arch-mmu.hh   |   1 +
 arch/aarch64/arch-setup.cc |  10 ++-
 arch/aarch64/arch.hh       |   2 +-
 arch/aarch64/boot.S        | 138 ++++++++++++++++++++++++++++++++++---
 arch/aarch64/loader.ld     |   5 +-
 arch/aarch64/preboot.S     |  20 ++++--
 core/elf.cc                |   4 ++
 core/mmu.cc                |  18 +++++
 loader.cc                  |  11 ++-
 11 files changed, 213 insertions(+), 33 deletions(-)

diff --git a/Makefile b/Makefile
index 82885016..c6dff37f 100644
--- a/Makefile
+++ b/Makefile
@@ -318,8 +318,12 @@ kernel-defines = -D_KERNEL $(source-dialects) 
$(cc-hide-flags) $(gc-flags)
 # To add something that will *not* be part of the main kernel, you can do:
 #
 #   mydir/*.o EXTRA_FLAGS = <MY_STUFF>
+ifeq ($(arch),x64)
 EXTRA_FLAGS = -D__OSV_CORE__ -DOSV_KERNEL_BASE=$(kernel_base) 
-DOSV_KERNEL_VM_BASE=$(kernel_vm_base) \
        -DOSV_KERNEL_VM_SHIFT=$(kernel_vm_shift) 
-DOSV_LZKERNEL_BASE=$(lzkernel_base)
+else
+EXTRA_FLAGS = -D__OSV_CORE__ -DOSV_KERNEL_VM_BASE=$(kernel_vm_base)
+endif
 EXTRA_LIBS =
 COMMON = $(autodepend) -g -Wall -Wno-pointer-arith $(CFLAGS_WERROR) -Wformat=0 
-Wno-format-security \
        -D __BSD_VISIBLE=1 -U _FORTIFY_SOURCE -fno-stack-protector $(INCLUDES) \
@@ -497,12 +501,13 @@ acpi = $(patsubst %.c, %.o, $(acpi-source))
 
 $(acpi:%=$(out)/%): CFLAGS += -fno-strict-aliasing -Wno-stringop-truncation
 
+kernel_vm_shift := $(shell printf "0x%X" $(shell expr $$(( $(kernel_vm_base) - 
$(kernel_base) )) ))
+
 endif # x64
 
 ifeq ($(arch),aarch64)
 
-kernel_base := 0x40080000
-kernel_vm_base := $(kernel_base)
+kernel_vm_base := 0xfc0080000 #63GB
 app_local_exec_tls_size := 0x40
 
 include $(libfdt_base)/Makefile.libfdt
@@ -516,7 +521,7 @@ $(out)/preboot.bin: $(out)/preboot.elf
        $(call quiet, $(OBJCOPY) -O binary $^ $@, OBJCOPY $@)
 
 edata = $(shell readelf --syms $(out)/loader.elf | grep "\.edata" | awk 
'{print "0x" $$2}')
-image_size = $$(( $(edata) - $(kernel_base) ))
+image_size = $$(( $(edata) - $(kernel_vm_base) ))
 
 $(out)/loader.img: $(out)/preboot.bin $(out)/loader-stripped.elf
        $(call quiet, dd if=$(out)/preboot.bin of=$@ > /dev/null 2>&1, DD $@ 
preboot.bin)
@@ -526,8 +531,6 @@ $(out)/loader.img: $(out)/preboot.bin 
$(out)/loader-stripped.elf
 
 endif # aarch64
 
-kernel_vm_shift := $(shell printf "0x%X" $(shell expr $$(( $(kernel_vm_base) - 
$(kernel_base) )) ))
-
 $(out)/bsd/sys/crypto/rijndael/rijndael-api-fst.o: COMMON+=-fno-strict-aliasing
 $(out)/bsd/sys/crypto/sha2/sha2.o: COMMON+=-fno-strict-aliasing
 $(out)/bsd/sys/net/route.o: COMMON+=-fno-strict-aliasing
@@ -2071,9 +2074,16 @@ endif
 $(out)/default_version_script: exported_symbols/*.symbols 
exported_symbols/$(arch)/*.symbols
        $(call quiet, scripts/generate_version_script.sh 
$(out)/default_version_script, GEN default_version_script)
 
+ifeq ($(arch),aarch64)
+def_symbols = --defsym=OSV_KERNEL_VM_BASE=$(kernel_vm_base)
+else
+def_symbols = --defsym=OSV_KERNEL_BASE=$(kernel_base) \
+              --defsym=OSV_KERNEL_VM_BASE=$(kernel_vm_base) \
+              --defsym=OSV_KERNEL_VM_SHIFT=$(kernel_vm_shift)
+endif
+
 $(out)/loader.elf: $(stage1_targets) arch/$(arch)/loader.ld $(out)/bootfs.o 
$(loader_options_dep) $(version_script_file)
-       $(call quiet, $(LD) -o $@ --defsym=OSV_KERNEL_BASE=$(kernel_base) \
-           --defsym=OSV_KERNEL_VM_BASE=$(kernel_vm_base) 
--defsym=OSV_KERNEL_VM_SHIFT=$(kernel_vm_shift) \
+       $(call quiet, $(LD) -o $@ $(def_symbols) \
                -Bdynamic --export-dynamic --eh-frame-hdr --enable-new-dtags 
-L$(out)/arch/$(arch) \
             $(patsubst 
%version_script,--version-script=%version_script,$(patsubst %.ld,-T %.ld,$^)) \
            $(linker_archives_options) $(conf_linker_extra_options), \
@@ -2085,8 +2095,7 @@ $(out)/loader.elf: $(stage1_targets) 
arch/$(arch)/loader.ld $(out)/bootfs.o $(lo
        $(call quiet, $(CC) $(out)/osv.o -nostdlib -shared -o $(out)/libosv.so 
-T $(out)/libosv.ld, LIBOSV.SO)
 
 $(out)/kernel.elf: $(stage1_targets) arch/$(arch)/loader.ld 
$(out)/empty_bootfs.o $(loader_options_dep) $(version_script_file)
-       $(call quiet, $(LD) -o $@ --defsym=OSV_KERNEL_BASE=$(kernel_base) \
-           --defsym=OSV_KERNEL_VM_BASE=$(kernel_vm_base) 
--defsym=OSV_KERNEL_VM_SHIFT=$(kernel_vm_shift) \
+       $(call quiet, $(LD) -o $@ $(def_symbols) \
                -Bdynamic --export-dynamic --eh-frame-hdr --enable-new-dtags 
-L$(out)/arch/$(arch) \
             $(patsubst 
%version_script,--version-script=%version_script,$(patsubst %.ld,-T %.ld,$^)) \
            $(linker_archives_options) $(conf_linker_extra_options), \
diff --git a/arch/aarch64/arch-dtb.cc b/arch/aarch64/arch-dtb.cc
index 7a7ef51f..d7241963 100644
--- a/arch/aarch64/arch-dtb.cc
+++ b/arch/aarch64/arch-dtb.cc
@@ -778,7 +778,7 @@ void  __attribute__((constructor(init_prio::dtb))) 
dtb_setup()
     }
 
     olddtb = dtb;
-    dtb = (void *)OSV_KERNEL_BASE;
+    dtb = (void *)OSV_KERNEL_VM_BASE;
 
     if (fdt_open_into(olddtb, dtb, 0x10000) != 0) {
         abort("dtb_setup: failed to move dtb (dtb too large?)\n");
@@ -808,15 +808,17 @@ void  __attribute__((constructor(init_prio::dtb))) 
dtb_setup()
     register u64 edata;
     asm volatile ("adrp %0, .edata" : "=r"(edata));
 
-    /* import from loader.cc */
+    /* import from loader.cc and core/mmu.cc */
     extern elf::Elf64_Ehdr *elf_header;
     extern size_t elf_size;
     extern void *elf_start;
+    extern u64 kernel_vm_shift;
 
-    elf_start = reinterpret_cast<void *>(elf_header);
+    mmu::elf_phys_start = reinterpret_cast<void *>(elf_header);
+    elf_start = mmu::elf_phys_start + kernel_vm_shift;
     elf_size = (u64)edata - (u64)elf_start;
 
     /* remove amount of memory used for ELF from avail memory */
-    mmu::phys addr = (mmu::phys)elf_start + elf_size;
+    mmu::phys addr = (mmu::phys)mmu::elf_phys_start + elf_size;
     memory::phys_mem_size -= addr - mmu::mem_addr;
 }
diff --git a/arch/aarch64/arch-mmu.hh b/arch/aarch64/arch-mmu.hh
index bd9efeb1..14149fe5 100644
--- a/arch/aarch64/arch-mmu.hh
+++ b/arch/aarch64/arch-mmu.hh
@@ -19,6 +19,7 @@
 namespace mmu {
 constexpr int max_phys_addr_size = 48;
 extern u64 mem_addr; /* set by the dtb_setup constructor */
+extern void *elf_phys_start;
 
 enum class mattr {
     normal,
diff --git a/arch/aarch64/arch-setup.cc b/arch/aarch64/arch-setup.cc
index 622fb75f..24e007c4 100644
--- a/arch/aarch64/arch-setup.cc
+++ b/arch/aarch64/arch-setup.cc
@@ -86,9 +86,9 @@ void arch_setup_free_memory()
 
     /* import from loader.cc */
     extern size_t elf_size;
-    extern void *elf_start;
+    extern elf::Elf64_Ehdr* elf_header;
 
-    mmu::phys addr = (mmu::phys)elf_start + elf_size;
+    mmu::phys addr = (mmu::phys)elf_header + elf_size;
     mmu::free_initial_memory_range(addr, memory::phys_mem_size);
 
     /* linear_map [TTBR1] */
@@ -100,7 +100,11 @@ void arch_setup_free_memory()
     }
 
     /* linear_map [TTBR0 - boot, DTB and ELF] */
-    mmu::linear_map((void *)mmu::mem_addr, (mmu::phys)mmu::mem_addr,
+    /* physical memory layout - relative to the 2MB-aligned address PA stored 
in mmu::mem_addr
+       PA +     0x0 - PA + 0x80000: boot
+       PA + 0x80000 - PA + 0x90000: DTB copy
+       PA + 0x90000 -       [addr]: kernel ELF */
+    mmu::linear_map((void *)(OSV_KERNEL_VM_BASE - 0x80000), 
(mmu::phys)mmu::mem_addr,
                     addr - mmu::mem_addr, "kernel");
 
     if (console::PL011_Console::active) {
diff --git a/arch/aarch64/arch.hh b/arch/aarch64/arch.hh
index 855f1987..c07e9999 100644
--- a/arch/aarch64/arch.hh
+++ b/arch/aarch64/arch.hh
@@ -18,7 +18,7 @@ namespace arch {
 
 #define CACHELINE_ALIGNED __attribute__((aligned(64)))
 #define INSTR_SIZE_MIN 4
-#define ELF_IMAGE_START (OSV_KERNEL_BASE + 0x10000)
+#define ELF_IMAGE_START (OSV_KERNEL_VM_BASE + 0x10000)
 
 inline void irq_disable()
 {
diff --git a/arch/aarch64/boot.S b/arch/aarch64/boot.S
index 5fce7853..9ca18f9c 100644
--- a/arch/aarch64/boot.S
+++ b/arch/aarch64/boot.S
@@ -14,17 +14,26 @@
 start_elf:
         /* elf program start address */
         /* input: x3=elf header x4=cmdline x5=dtb */
+        bl      calculate_virt_offset
+        /* x6 contains virt-phys offset */
         adrp    x0, exception_vectors
+        add     x0, x0, x6    // apply virt-phys offset to make it virtual 
address
         msr     vbar_el1, x0
         isb
 
-        bl      validate_el // check that we are at EL1 or die
+        bl      validate_el   // check that we are at EL1 or die
         bl      init_stack
-        bl      zero_bss    // initialize bss contents to 0
+        bl      zero_bss      // initialize bss contents to 0
         bl      init_cpu
-        bl      init_boot_pt
+        bl      fixup_boot_pt // apply virt-phys offset to the boot mapping 
tables
+        bl      init_boot_pt  // set mapping table registers
+        /* at this point the virtual memory is not yet enabled but we are 
ready to enable it */
         bl      init_mmu
 
+        /* after we returned from init_mmu we are operating in the virtual 
memory space */
+        adrp    x0, kernel_vm_shift
+        str     x6, [x0]      // save the kernel VM shift under kernel_vm_shift
+
         adrp    x1, elf_header              // store elf header address
         str     x3, [x1, #:lo12:elf_header]
         adrp    x1, cmdline                 // store cmdline (arch-setup.cc)
@@ -36,7 +45,6 @@ start_elf:
         mov     x29, xzr
         bl      init_xen
 #endif
-
         mov     x29, xzr
         bl      premain
 
@@ -48,12 +56,19 @@ start_elf:
 
         bl      halt
 
+calculate_virt_offset:
+        adr     x0, text_start // fetch physical address of text_start
+        ldr     x6, =(OSV_KERNEL_VM_BASE + 0x20000) // calculate virtual 
address of text_start per loader.ld
+        sub     x6, x6, x0
+        ret
+
 init_stack:
         mov     x0, #1     // select SP_ELx
         msr     spsel, x0
         isb
 
         adrp    x0, init_stack_top
+        add     x0, x0, x6 // make it virtual address
         mov     sp, x0
         ret
 
@@ -119,12 +134,80 @@ init_cpu:
         isb
         ret
 
+fixup_boot_pt:
+        // x6 contains kernel phys/virt offset
+        mov     x29, x30 // save link register so wa can call fixup_pt_entry
+
+        /* we need to fix the addresses of the ident subtables to make them 
physical */
+        /* as the virt-phys mapping structures use physical addresses during 
walk-up */
+
+        // subtract p/v offset from the address of the subtable 
ident_pt_l3_ttbr0
+        adrp    x0, ident_pt_l4_ttbr0
+        bl      fixup_pt_entry
+
+        // subtract p/v offset from the address of the subtable 
ident_pt_l2_0_ttbr0
+        adrp    x0, ident_pt_l3_ttbr0
+        bl      fixup_pt_entry
+        // subtract p/v offset from the address of the subtable 
ident_pt_l2_1_ttbr0
+        add     x0, x0, #8
+        bl      fixup_pt_entry
+        // subtract p/v offset from the address of the subtable 
ident_pt_l2_2_ttbr0
+        add     x0, x0, #8
+        bl      fixup_pt_entry
+        // subtract p/v offset from the address of the subtable 
ident_pt_l2_3_ttbr0
+        add     x0, x0, #8
+        bl      fixup_pt_entry
+        // subtract p/v offset from the address of the subtable 
kernel_pt_l2_63_ttbr0
+        add     x0, x0, #480  //=60*8
+        bl      fixup_pt_entry
+
+        // fix 63-64 GB mapping which maps the kernel code
+
+        // From https://www.kernel.org/doc/Documentation/arm64/booting.txt:
+        //"The Image must be placed text_offset bytes from a 2MB aligned base
+        // address anywhere in usable system RAM and called there."
+
+        // Given the kernel can be loaded in any place of the allowed range of 
physical memory
+        // we have to dynamically figure out the physical address so that we 
can correctly
+        // initialize the pt entries of the 63th GB of the virtual memory 
which is where
+        // the kernel is expected to be per loader.ld.
+
+        // We use the physical address of the symbol text_start located in the 
1st 2MB
+        // of the kernel text to identify which 2MB of RAM the kernel ELF is 
loaded.
+        // Then we use this information to map the 63-rd GB of virtual memory 
into
+        // whatever 2 MB-aligned area of physical memory the kernel is loaded.
+
+        // round-up to whole 2MB and store in x2
+        adrp    x0, text_start
+        lsr     x2, x0, #21
+        lsl     x2, x2, #21
+
+        // start with pt entry stored at kernel_pt_l2_63_ttbr0 (x0)
+        adrp    x0, kernel_pt_l2_63_ttbr0
+        mov     x7, #512
+kernel_pt_loop:
+        ldr     x1, [x0]   // load initial value of pt entry at address stored 
in x0
+        add     x1, x1, x2 // add the physical address offset
+        str     x1, [x0]   // store the fixed pt value
+
+        add     x0, x0, #8 // fix another 2MB
+        sub     x7, x7, #1
+        cbnz    x7, kernel_pt_loop
+
+        mov     x30, x29   // restore link register (x30) so we can properly 
return ret
+
+fixup_pt_entry:
+        ldr     x1, [x0]   // x0 contains address of the entry, x6 contains 
offset
+        sub     x1, x1, x6 // apply kernel offset
+        str     x1, [x0]   // store the fixed pt entry back into memory
+        ret
+
 init_boot_pt:
         adrp    x0, ident_pt_l4_ttbr0
         adrp    x1, ident_pt_l4_ttbr1
         ret
 
-init_secondary_pt:
+init_runtime_pt:
         adrp    x1, smpboot_ttbr0
         ldr     x0, [x1], #8
         ldr     x1, [x1]
@@ -150,6 +233,21 @@ init_mmu:
         msr     sctlr_el1, x0
         isb
 
+        // Apply offset to switch to the kernel VM address so that we jump
+        // into virtual memory space of where kernel is mapped (63-rd GB)
+        add     x30, x30, x6
+        ret
+
+switch_to_runtime_pt:
+        msr     ttbr0_el1, x0
+        msr     ttbr1_el1, x1
+        isb
+
+        dsb sy  //Flush TLB
+        tlbi vmalle1
+        dsb sy
+        isb
+
         ret
 
 .align 16
@@ -157,15 +255,20 @@ init_mmu:
 .hidden start_secondary_cpu
 .type  start_secondary_cpu , "function"
 start_secondary_cpu:
+        bl      calculate_virt_offset
+        /* x6 contains virt-phys offset */
         adrp    x0, exception_vectors
+        add     x0, x0, x6    // apply virt-phys offset to make it virtual 
address
         msr     vbar_el1, x0
         isb
 
         bl      init_cpu
-        bl      init_boot_pt
-        bl      init_mmu
-        bl      init_secondary_pt
+        bl      init_boot_pt  // use the boot mapping tables fixed by 
start_elf on primary CPU
         bl      init_mmu
+        /* after we returned from init_mmu we are operating in the virtual 
memory space */
+        /* but on secondary CPU we can subsequently switch to the runtime 
mapping tables */
+        bl      init_runtime_pt
+        bl      switch_to_runtime_pt
 
         ldr     x0, =smp_stack_free    /* ptr */
         ldr     x1, [x0]               /* old value */
@@ -199,7 +302,11 @@ ident_pt_l3_ttbr0:
         .quad ident_pt_l2_1_ttbr0 + 0x3 // Map 1GB-2GB one-to-one
         .quad ident_pt_l2_2_ttbr0 + 0x3 // Map 2GB-3GB one-to-one
         .quad ident_pt_l2_3_ttbr0 + 0x3 // Map 3GB-4GB one-to-one
-        .rept 508
+        .rept 59
+        .quad 0
+        .endr
+        .quad kernel_pt_l2_63_ttbr0 + 0x3 // Map 63GB-64GB -> 1GB-2GB
+        .rept 448
         .quad 0
         .endr
 ident_pt_l2_0_ttbr0:
@@ -230,6 +337,13 @@ ident_pt_l2_3_ttbr0:
         .quad offset + (index << 21) + 0x411
         index = index + 1
         .endr
+kernel_pt_l2_63_ttbr0:
+        index = 0
+        offset = 0
+        .rept 512
+        .quad offset + (index << 21) + 0x411
+        index = index + 1
+        .endr
 .align 12
 ident_pt_l4_ttbr1:
         .rept 512
@@ -258,6 +372,12 @@ smp_stack_free: .quad 0
 smpboot_ttbr0:  .quad 0
 smpboot_ttbr1:  .quad 0
 
+.hidden kernel_vm_shift
+.globl kernel_vm_shift
+.type kernel_vm_shift, "object"
+.align 16
+kernel_vm_shift: .quad 0
+
 /* hmm should we provide an interrupt stack?
 . = . + 4096*10
 .global interrupt_stack_top
diff --git a/arch/aarch64/loader.ld b/arch/aarch64/loader.ld
index 2e2d55b6..f08cce2f 100644
--- a/arch/aarch64/loader.ld
+++ b/arch/aarch64/loader.ld
@@ -18,8 +18,11 @@ SECTIONS
         *
         * We can't export the ELF header base as a symbol, because ld
         * insists on moving stuff around if we do.
+        *
+        * We add 0x10000 (64 KB) below to create space for our copy of DTB tree
+        * (see dtb_setup() in arch-dtb.cc)
         */
-    . = OSV_KERNEL_BASE + 0x10000 + 0x1000;
+    . = OSV_KERNEL_VM_BASE + 0x10000 + 0x1000;
 
     .dynamic : ALIGN(16) { *(.dynamic) } : dynamic : text
 
diff --git a/arch/aarch64/preboot.S b/arch/aarch64/preboot.S
index 006858c2..f066859f 100644
--- a/arch/aarch64/preboot.S
+++ b/arch/aarch64/preboot.S
@@ -5,8 +5,9 @@
  * BSD license as described in the LICENSE file in the top-level directory.
  */
 
+image_start = .
 cmdline_addr = . + 0x200 // 512 bytes after start of image
-target = . + 0x10000
+target = . + 0x10000     // start of the ELF in physical memory
 
 .text
 .align 16
@@ -37,14 +38,23 @@ _head:
 
 .globl prestart
 .hidden prestart
-prestart: // x4 = 0x40080000 set by qemu bootloader
-        mov     x5, x0     /* save device tree blob addr */
+prestart:
+        mov     x5, x0     /* save device tree blob physical addr */
         adr     x4, cmdline_addr
         adr     x3, target /* elf header start */
 
-        // load entry point from ELF header + 24
+        // load virtual address of the entry point from ELF header + 24 into x0
         ldr     w0, [x3, #24]
         ldr     w1, [x3, #28]
-
         orr     x0, x0, x1, LSL #32
+
+        // calculate offset of elf entry point in physical memory relative to 
image_start
+        and     x0, x0, #0x1fffff // offset in 2MB segment
+        sub     x0, x0, #0x80000  // subtract the image load offset (see 
"image load offset" in the _head section above)
+
+        // add the offset calculated above to the physical address of 
image_start
+        adr     x1, image_start   // fetch physical address of the image_start
+        add     x0, x0, x1        // add entry point offset to the image_start 
address
+
+        // jump to elf entry point address in physical memory
         br      x0
diff --git a/core/elf.cc b/core/elf.cc
index f80d2446..5170bf53 100644
--- a/core/elf.cc
+++ b/core/elf.cc
@@ -1294,7 +1294,11 @@ void create_main_program()
 program::program(void* addr)
     : _next_alloc(addr)
 {
+#ifdef __x86_64__
     void *program_base = (void*)(ELF_IMAGE_START + OSV_KERNEL_VM_SHIFT);
+#else
+    void *program_base = (void*)(ELF_IMAGE_START);
+#endif
     _core = std::make_shared<memory_image>(*this, program_base);
     _core->set_base(program_base);
     assert(_core->module_index() == core_module_index);
diff --git a/core/mmu.cc b/core/mmu.cc
index 80ce6b63..62aebc35 100644
--- a/core/mmu.cc
+++ b/core/mmu.cc
@@ -125,12 +125,25 @@ phys pte_level_mask(unsigned level)
     return ~((phys(1) << shift) - 1);
 }
 
+#ifdef __x86_64__
 static void *elf_phys_start = (void*)OSV_KERNEL_BASE;
+#endif
+
+#ifdef __aarch64__
+void *elf_phys_start;
+extern "C" u64 kernel_vm_shift;
+#endif
+
 void* phys_to_virt(phys pa)
 {
     void* phys_addr = reinterpret_cast<void*>(pa);
     if ((phys_addr >= elf_phys_start) && (phys_addr < elf_phys_start + 
elf_size)) {
+#ifdef __x86_64__
         return (void*)(phys_addr + OSV_KERNEL_VM_SHIFT);
+#endif
+#ifdef __aarch64__
+        return (void*)(phys_addr + kernel_vm_shift);
+#endif
     }
 
     return phys_mem + pa;
@@ -141,7 +154,12 @@ phys virt_to_phys_pt(void* virt);
 phys virt_to_phys(void *virt)
 {
     if ((virt >= elf_start) && (virt < elf_start + elf_size)) {
+#ifdef __x86_64__
         return reinterpret_cast<phys>((void*)(virt - OSV_KERNEL_VM_SHIFT));
+#endif
+#ifdef __aarch64__
+        return reinterpret_cast<phys>((void*)(virt - kernel_vm_shift));
+#endif
     }
 
 #if CONF_debug_memory
diff --git a/loader.cc b/loader.cc
index 48716587..b98f9681 100644
--- a/loader.cc
+++ b/loader.cc
@@ -111,8 +111,17 @@ void premain()
 
     arch_init_premain();
 
+#ifdef __x86_64__
+    auto elf_header_virt_address = (void*)elf_header + OSV_KERNEL_VM_SHIFT;
+#endif
+
+#ifdef __aarch64__
+    extern u64 kernel_vm_shift;
+    auto elf_header_virt_address = (void*)elf_header + kernel_vm_shift;
+#endif
+
     auto inittab = elf::get_init(reinterpret_cast<elf::Elf64_Ehdr*>(
-        (void*)elf_header + OSV_KERNEL_VM_SHIFT));
+        elf_header_virt_address));
 
     if (inittab.tls.start == nullptr) {
         debug_early("premain: failed to get TLS data from ELF\n");
-- 
2.31.1

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/20220429040738.13267-1-jwkozaczuk%40gmail.com.

Reply via email to