@@ -15,4 +15,6 @@ void setup_initial_pagetables(void);
void enable_mmu(void);
void cont_after_mmu_is_enabled(void);
+unsigned long calc_phys_offset(void);
+
#endif /* _ASM_RISCV_MM_H */
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
+#include <xen/cache.h>
#include <xen/compiler.h>
#include <xen/init.h>
#include <xen/kernel.h>
@@ -19,9 +20,10 @@ struct mmu_desc {
pte_t *pgtbl_base;
};
-#define PHYS_OFFSET ((unsigned long)_start - XEN_VIRT_START)
-#define LOAD_TO_LINK(addr) ((addr) - PHYS_OFFSET)
-#define LINK_TO_LOAD(addr) ((addr) + PHYS_OFFSET)
+static unsigned long __ro_after_init phys_offset;
+
+#define LOAD_TO_LINK(addr) ((unsigned long)(addr) - phys_offset)
+#define LINK_TO_LOAD(addr) ((unsigned long)(addr) + phys_offset)
/*
* It is expected that Xen won't be more then 2 MB.
@@ -273,3 +275,16 @@ void __init noreturn noinline enable_mmu()
switch_stack_and_jump((unsigned long)cpu0_boot_stack + STACK_SIZE,
cont_after_mmu_is_enabled);
}
+
+/*
+ * calc_phys_offset() should be used before MMU is enabled because access to
+ * start() is PC-relative and in case when load_addr != linker_addr phys_offset
+ * will have an incorrect value
+ */
+unsigned long __init calc_phys_offset(void)
+{
+ volatile unsigned long load_start = (unsigned long)_start;
+
+ phys_offset = load_start - XEN_VIRT_START;
+ return phys_offset;
+}
@@ -29,6 +29,20 @@ ENTRY(start)
jal reset_stack
+ /*
+ * save hart_id ( bootcpu_id ) and dtb_base as a0 and a1 register can
+ * be used by C code
+ */
+ mv s0, a0
+ mv s1, a1
+
+ jal calc_phys_offset
+ mv s2, a0
+
+ /* restore hart_id ( bootcpu_id ) and dtb address */
+ mv a0, s0
+ mv a1, s1
+
tail start_xen
.section .text, "ax", %progbits
The function was introduced to calculate and save physical offset before MMU is enabled because access to start() is PC-relative and in case of linker_addr != load_addr it will result in incorrect value in phys_offset. Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V6: - After 9380f06fe8("xen: Drop the (almost) unused extern start[]") an update of calc_phys_offset() was needed: - change start to _start. - add local volatile variable load_start to get properly Xens' load address. Otherwise compile thinks that (start - XEN_VIRT_START) is equal to 0. --- Changes in V5: - update prototype of calc_phys_offset(). now it returns phys_offset. - declare phys_offset as static. - save returned value of calc_phys_offset to register s2. --- Changes in V4: - update the comment messages in head.S related to save/restore of a0/a1 regs. --- Changes in V3: - save/restore of a0/a1 registers before C first function call. --- Changes in V2: - add __ro_after_init for phys_offset variable. - remove double blank lines. - add __init for calc_phys_offset(). - update the commit message. - declaring variable phys_off as non static as it will be used in head.S. --- xen/arch/riscv/include/asm/mm.h | 2 ++ xen/arch/riscv/mm.c | 21 ++++++++++++++++++--- xen/arch/riscv/riscv64/head.S | 14 ++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-)