[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v4 09/14] xen/arm32: head: Remove restriction where to load Xen
Hi Julien, On 13/01/2023 11:11, Julien Grall wrote: > > > From: Julien Grall <jgrall@xxxxxxxxxx> > > At the moment, bootloaders can load Xen anywhere in memory but the > region 2MB - 4MB. While I am not aware of any issue, we have no way > to tell the bootloader to avoid that region. > > In addition to that, in the future, Xen may grow over 2MB if we > enable feature like UBSAN or GCOV. To avoid widening the restriction > on the load address, it would be better to get rid of it. > > When the identity mapping is clashing with the Xen runtime mapping, > we need an extra indirection to be able to replace the identity > mapping with the Xen runtime mapping. > > Reserve a new memory region that will be used to temporarily map Xen. > For convenience, the new area is re-using the same first slot as the > domheap which is used for per-cpu temporary mapping after a CPU has > booted. > > Furthermore, directly map boot_second (which cover Xen and more) > to the temporary area. This will avoid to allocate an extra page-table > for the second-level and will helpful for follow-up patches (we will > want to use the fixmap whilst in the temporary mapping). > > Lastly, some part of the code now needs to know whether the temporary > mapping was created. So reserve r12 to store this information. > > Signed-off-by: Julien Grall <jgrall@xxxxxxxxxx> > ---- > Changes in v4: > - Remove spurious newline > > Changes in v3: > - Remove the ASSERT() in init_domheap_mappings() because it was > bogus (secondary CPU root tables are initialized to the CPU0 > root table so the entry will be valid). Also, it is not > related to this patch as the CPU0 root table are rebuilt > during boot. The ASSERT() will be re-introduced later. > > Changes in v2: > - Patch added > --- > xen/arch/arm/arm32/head.S | 139 ++++++++++++++++++++++++++---- > xen/arch/arm/include/asm/config.h | 14 +++ > xen/arch/arm/mm.c | 14 +++ > 3 files changed, 152 insertions(+), 15 deletions(-) > > diff --git a/xen/arch/arm/arm32/head.S b/xen/arch/arm/arm32/head.S > index 67b910808b74..3800efb44169 100644 > --- a/xen/arch/arm/arm32/head.S > +++ b/xen/arch/arm/arm32/head.S > @@ -35,6 +35,9 @@ > #define XEN_FIRST_SLOT first_table_offset(XEN_VIRT_START) > #define XEN_SECOND_SLOT second_table_offset(XEN_VIRT_START) > > +/* Offset between the early boot xen mapping and the runtime xen mapping */ > +#define XEN_TEMPORARY_OFFSET (TEMPORARY_XEN_VIRT_START - XEN_VIRT_START) > + > #if defined(CONFIG_EARLY_PRINTK) && defined(CONFIG_EARLY_PRINTK_INC) > #include CONFIG_EARLY_PRINTK_INC > #endif > @@ -94,7 +97,7 @@ > * r9 - paddr(start) > * r10 - phys offset > * r11 - UART address > - * r12 - > + * r12 - Temporary mapping created > * r13 - SP > * r14 - LR > * r15 - PC > @@ -445,6 +448,9 @@ ENDPROC(cpu_init) > * r9 : paddr(start) > * r10: phys offset > * > + * Output: > + * r12: Was a temporary mapping created? > + * > * Clobbers r0 - r4, r6 > * > * Register usage within this function: > @@ -484,7 +490,11 @@ create_page_tables: > /* > * Setup the 1:1 mapping so we can turn the MMU on. Note that > * only the first page of Xen will be part of the 1:1 mapping. > + * > + * In all the cases, we will link boot_third_id. So create the > + * mapping in advance. > */ > + create_mapping_entry boot_third_id, r9, r9 > > /* > * Find the first slot used. If the slot is not XEN_FIRST_SLOT, > @@ -501,8 +511,7 @@ create_page_tables: > /* > * Find the second slot used. If the slot is XEN_SECOND_SLOT, then > the > * 1:1 mapping will use its own set of page-tables from the > - * third level. For slot XEN_SECOND_SLOT, Xen is not yet able to > handle > - * it. > + * third level. > */ > get_table_slot r1, r9, 2 /* r1 := second slot */ > cmp r1, #XEN_SECOND_SLOT > @@ -513,13 +522,33 @@ create_page_tables: > link_from_second_id: > create_table_entry boot_second_id, boot_third_id, r9, 2 > link_from_third_id: > - create_mapping_entry boot_third_id, r9, r9 > + /* Good news, we are not clashing with Xen virtual mapping */ > + mov r12, #0 /* r12 := temporary mapping not created > */ > mov pc, lr > > virtphys_clash: > - /* Identity map clashes with boot_third, which we cannot handle yet > */ > - PRINT("- Unable to build boot page tables - virt and phys addresses > clash. -\r\n") > - b fail > + /* > + * The identity map clashes with boot_third. Link boot_first_id and > + * map Xen to a temporary mapping. See switch_to_runtime_mapping > + * for more details. > + */ > + PRINT("- Virt and Phys addresses clash -\r\n") > + PRINT("- Create temporary mapping -\r\n") > + > + /* > + * This will override the link to boot_second in XEN_FIRST_SLOT. > + * The page-tables are not live yet. So no need to use > + * break-before-make. > + */ > + create_table_entry boot_pgtable, boot_second_id, r9, 1 > + create_table_entry boot_second_id, boot_third_id, r9, 2 > + > + /* Map boot_second (cover Xen mappings) to the temporary 1st slot */ > + mov_w r0, TEMPORARY_XEN_VIRT_START > + create_table_entry boot_pgtable, boot_second, r0, 1 > + > + mov r12, #1 /* r12 := temporary mapping created */ > + mov pc, lr > ENDPROC(create_page_tables) > > /* > @@ -528,9 +557,10 @@ ENDPROC(create_page_tables) > * > * Inputs: > * r9 : paddr(start) > + * r12 : Was the temporary mapping created? > * lr : Virtual address to return to > * > - * Clobbers r0 - r3 > + * Clobbers r0 - r5 > */ > enable_mmu: > PRINT("- Turning on paging -\r\n") > @@ -558,21 +588,79 @@ enable_mmu: > * The MMU is turned on and we are in the 1:1 mapping. Switch > * to the runtime mapping. > */ > - mov_w r0, 1f > - mov pc, r0 > + mov r5, lr /* Save LR before overwritting it */ > + mov_w lr, 1f /* Virtual address in the runtime > mapping */ > + b switch_to_runtime_mapping > 1: > + mov lr, r5 /* Restore LR */ > /* > - * The 1:1 map may clash with other parts of the Xen virtual memory > - * layout. As it is not used anymore, remove it completely to > - * avoid having to worry about replacing existing mapping > - * afterwards. > + * At this point, either the 1:1 map or the temporary mapping > + * will be present. The former may clash with other parts of the > + * Xen virtual memory layout. As both of them are not used > + * anymore, remove them completely to avoid having to worry > + * about replacing existing mapping afterwards. > * > * On return this will jump to the virtual address requested by > * the caller. > */ > - b remove_identity_mapping > + teq r12, #0 > + beq remove_identity_mapping > + b remove_temporary_mapping > ENDPROC(enable_mmu) > > +/* > + * Switch to the runtime mapping. The logic depends on whether the > + * runtime virtual region is clashing with the physical address > + * > + * - If it is not clashing, we can directly jump to the address in > + * the runtime mapping. > + * - If it is clashing, create_page_tables() would have mapped Xen to > + * a temporary virtual address. We need to switch to the temporary > + * mapping so we can remove the identity mapping and map Xen at the > + * correct position. > + * > + * Inputs > + * r9: paddr(start) > + * r12: Was a temporary mapping created? > + * lr: Address in the runtime mapping to jump to > + * > + * Clobbers r0 - r4 > + */ > +switch_to_runtime_mapping: > + /* > + * Jump to the runtime mapping if the virt and phys are not > + * clashing > + */ > + teq r12, #0 > + beq ready_to_switch > + > + /* We are still in the 1:1 mapping. Jump to the temporary Virtual > address. */ > + mov_w r0, 1f > + add r0, r0, #XEN_TEMPORARY_OFFSET /* r0 := address in temporary > mapping */ > + mov pc, r0 > + > +1: > + /* Remove boot_second_id */ > + mov r2, #0 > + mov r3, #0 > + adr_l r0, boot_pgtable > + get_table_slot r1, r9, 1 /* r1 := first slot */ > + lsl r1, r1, #3 /* r1 := first slot offset */ > + strd r2, r3, [r0, r1] > + > + flush_xen_tlb_local r0 > + > + /* Map boot_second into boot_pgtable */ > + mov_w r0, XEN_VIRT_START > + create_table_entry boot_pgtable, boot_second, r0, 1 > + > + /* Ensure any page table updates are visible before continuing */ > + dsb nsh > + > +ready_to_switch: > + mov pc, lr > +ENDPROC(switch_to_runtime_mapping) > + > /* > * Remove the 1:1 map from the page-tables. It is not easy to keep track > * where the 1:1 map was mapped, so we will look for the top-level entry > @@ -618,6 +706,27 @@ identity_mapping_removed: > mov pc, lr > ENDPROC(remove_identity_mapping) > > +/* > + * Remove the temporary mapping of Xen starting at TEMPORARY_XEN_VIRT_START. > + * > + * Clobbers r0 - r1 > + */ > +remove_temporary_mapping: > + /* r2:r3 := invalid page-table entry */ > + mov r2, #0 > + mov r3, #0 > + > + adr_l r0, boot_pgtable > + mov_w r1, TEMPORARY_XEN_VIRT_START > + get_table_slot r1, r1, 1 /* r1 := first slot */ Can't we just use TEMPORARY_AREA_FIRST_SLOT? > + lsl r1, r1, #3 /* r1 := first slot offset */ > + strd r2, r3, [r0, r1] > + > + flush_xen_tlb_local r0 > + > + mov pc, lr > +ENDPROC(remove_temporary_mapping) > + > /* > * Map the UART in the fixmap (when earlyprintk is used) and hook the > * fixmap table in the page tables. > diff --git a/xen/arch/arm/include/asm/config.h > b/xen/arch/arm/include/asm/config.h > index 87851e677701..6c1b762e976d 100644 > --- a/xen/arch/arm/include/asm/config.h > +++ b/xen/arch/arm/include/asm/config.h > @@ -148,6 +148,20 @@ > /* Number of domheap pagetable pages required at the second level (2MB > mappings) */ > #define DOMHEAP_SECOND_PAGES (DOMHEAP_VIRT_SIZE >> FIRST_SHIFT) > > +/* > + * The temporary area is overlapping with the domheap area. This may > + * be used to create an alias of the first slot containing Xen mappings > + * when turning on/off the MMU. > + */ > +#define TEMPORARY_AREA_FIRST_SLOT (first_table_offset(DOMHEAP_VIRT_START)) > + > +/* Calculate the address in the temporary area */ > +#define TEMPORARY_AREA_ADDR(addr) \ > + (((addr) & ~XEN_PT_LEVEL_MASK(1)) | \ > + (TEMPORARY_AREA_FIRST_SLOT << XEN_PT_LEVEL_SHIFT(1))) XEN_PT_LEVEL_{MASK/SHIFT} should be used when we do not know the level upfront. Otherwise, no need for opencoding and you should use FIRST_MASK and FIRST_SHIFT. ~Michal
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |