[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [PATCH v3 06/43] arm64: add the boot code
On Mon, Apr 16, 2018 at 06:13:31PM +0100, Julien Grall wrote: > Hi, > > On 16/04/18 07:31, Huang Shijie wrote: > >This patch adds the boot code for arm64: > > 0.) add the header which contains all the macros to setup the page table > > 1.) init the MAIR/TCR for 48 bit virtual address. > > 2.) setup the page table for the code section. > > 3.) enable the MMU > > > >This patch refers to Chen Baozi's patch: > > "Initial codes for arm64" > > > >Signed-off-by: Huang Shijie <shijie.huang@xxxxxxx> > >--- > > arch/arm/arm64/arm64.S | 286 > > ++++++++++++++++++++++++++++++++++++++++++ > > arch/arm/arm64/asm.h | 18 +++ > > include/arm/arm64/pagetable.h | 108 ++++++++++++++++ > > 3 files changed, 412 insertions(+) > > create mode 100644 arch/arm/arm64/arm64.S > > create mode 100644 arch/arm/arm64/asm.h > > create mode 100644 include/arm/arm64/pagetable.h > > > >diff --git a/arch/arm/arm64/arm64.S b/arch/arm/arm64/arm64.S > >new file mode 100644 > >index 0000000..b454cc6 > >--- /dev/null > >+++ b/arch/arm/arm64/arm64.S > >@@ -0,0 +1,286 @@ > >+#include "asm.h" > >+#include <arch_limits.h> > >+#include <arm64/pagetable.h> > >+#include <xen/xen.h> > >+ > >+/* This macro will use the x0/x1/x2/x16 */ > >+#define PRINT(_s) \ > >+ adr x2, 97f; \ > >+ adr x1, 98f; \ > >+ sub x1, x1, x2; \ > >+ mov x0, #CONSOLEIO_write; \ > >+ mov x16, #__HYPERVISOR_console_io; \ > >+ hvc #XEN_HYPERCALL_TAG; \ > >+ b 99f; \ > > I see you use the PRINT(...) before enabling the MMU. Per > include/xen/arch-arm.h: > > "All memory which is shared with other entities in the system > (including the hypervisor and other guests) must reside in memory > which is mapped as Normal Inner Write-Back Outer Write-Back Inner-Shareable. > This applies to: > - hypercall arguments passed via a pointer to guest memory. > - memory shared via the grant table mechanism (including PV I/O > rings etc). > - memory shared with the hypervisor (struct shared_info, struct > vcpu_info, the grant table, etc)." > > This means that your PRINT may not always appear and provoking other funny > problem as the cache may have an inconsistent state. So I think you want to > avoid using those print before MMU is enabled. okay, I will remove the PRINT. It is really not necessary. > > >+97: .asciz _s; \ > > Don't you want to put the string into the text section? Ditto. > > >+98: ; \ > >+ .align 2; \ > >+99: \ > >+ > >+ .data > >+ .globl _boot_stack > >+ .globl boot_l0_pgtable > >+ .globl boot_l1_pgtable > >+ .globl boot_l2_pgtable > >+ .globl idmap_l0_pgtable > >+ .globl idmap_l1_pgtable > > Please put the .globl label before each declaration. But I am not sure why > you need to export most of them. The code setup the page table may need them, so I should export them. > > >+ > >+ .align 12 > >+boot_l0_pgtable: > >+ .fill PAGE_SIZE,1,0 > >+boot_l1_pgtable: > >+ .fill PAGE_SIZE,1,0 > >+boot_l2_pgtable: > >+ .fill PAGE_SIZE,1,0 > >+idmap_l0_pgtable: > >+ .fill PAGE_SIZE,1,0 > >+idmap_l1_pgtable: > >+ .fill PAGE_SIZE,1,0 > >+ > >+ .align 12 > >+_boot_stack: > >+ .fill __STACK_SIZE,1,0 > > Can we please use STACK_SIZE and not __STACK_SIZE. I will try... But I remember I met something wrong in compiling when I used STACK_SIZE. > > >+stack_end: > >+ > >+/* > >+ * Kernel startup entry point. > >+ * > >+ * Please refer to linux kernel file Documentation/arm64/booting.txt > >+ * for the header format. > >+ */ > >+ .text > >+ > >+ b _start /* branch to kernel start, magic */ > >+ .long 0 /* reserved */ > >+ .quad 0x0 /* Image load offset from start of RAM > >*/ > >+ .quad _end - _start /* Effective Image size */ > >+ .quad 2 /* kernel flags: LE, 4K page size */ > > Again, do we really care to have the kernel placed as close as possible to > the base address of the DRAM? Do you have a better place to place the kernel? > > For reminder, the documentation of that flag is: > > Bit 3: Kernel physical placement > 0 - 2MB aligned base should be as close as possible > to the base of DRAM, since memory below it is not accessible via the linear > mapping > 1 - 2MB aligned base may be anywhere in physical > memory > > How does mini-OS on Arm64 deal with memory below the loaded address of the > kernel? We do not use the memory below the loaded address of kernel. We put kernel at 0xffff000000000000 (48bit). And we setup the page table for address >= 0xffff000000000000, the address below 0xffff000000000000 is not accessed. > > >+ .quad 0 /* reserved */ > >+ .quad 0 /* reserved */ > >+ .quad 0 /* reserved */ > >+ .byte 0x41 /* Magic number, "ARM\x64" */ > >+ .byte 0x52 > >+ .byte 0x4d > >+ .byte 0x64 > >+ .long 0 /* reserved */ > >+ > >+/* > >+ * Primary CPU general-purpose register settings > > This is fairly unclear to me what you mean by primary. Did you mean, > "Initial state of the GPR when _start is called?" yes, We can remove the Primary here, there is only one cpu for mini-os... > > >+ * x0 = physical address of device tree blob (dtb) in system RAM. > >+ * x1 = 0 (reserved for future use) > >+ * x2 = 0 (reserved for future use) > >+ * x3 = 0 (reserved for future use) > >+ * > >+ * The registers used by _start: > >+ * x20 - FDT pointer > >+ * x22 - offset between PA and VA > >+ */ > >+ENTRY(_start) > >+ /* Save the FDT pointer */ > >+ mov x20, x0 > >+ > >+ /* Calculate where we are */ > >+ bl _calc_offset > >+ > >+ PRINT("- Mini-OS booting -\n") > >+ > >+ PRINT("- Setup CPU -\n") > >+ /* Setup CPU for turning on the MMU. */ > >+ bl _setup_cpu > >+ > >+ PRINT("- Setup booting pagetable -\n") > > I am pretty sure you need to clean the cache for the page-table region here > to avoid potential dirty lines being evicted and ... I am not clear about this. is it possible that there is cache for the paget able region? Sorry, I will read more document and reply your following comments... Thanks Huang Shijie > > >+ /* Setup the initial page table. */ > >+ bl _setup_initial_pgtable > >+ mov x19, x0 > >+ > >+ /* Setup the identity mapping */ > >+ bl _setup_idmap_pgtable > > Also here because you populated the page-tables with non-cacheable accesses > (MMU disabled), so you want to remove speculatively loaded cache lines. > > >+ > >+ /* Load TTBRx */ > >+ msr ttbr1_el1, x19 > >+ msr ttbr0_el1, x0 > >+ isb > >+ > >+ /* Turning on MMU */ > >+ tlbi vmalle1 > > Can you please document why the TLB here. In that case it remove stall TLB > entries. > > >+ dsb nsh > >+ isb > > The isb here is not necessary. You can rely on the one after the MMU is > enabled below. > > >+ ldr x1, =(SCTLR_M | SCTLR_C | SCTLR_I) > > If you fully overwrite SCTLR_EL1 value, then you need to make sure all RES1 > are set to 1 in ARMv8.0. Otherwise, you are going to have some surprise when > those bits are defined differently (such as moving to ARMv8.2). > > >+ msr sctlr_el1, x1 > >+ isb > >+ > >+ PRINT("- MMU on -\n") > >+ ldr x0, =mmu_on > >+ br x0 > >+ > >+mmu_on: > >+ /* Do not use the TTBR0_EL1 any more */ > >+ mrs x19, tcr_el1 > >+ add x19, x19, TCR_EPD0 > >+ msr tcr_el1, x19 > > You probably want to flush the TLB here. So you don't end up to use stall > data. > > >+ > >+ /* Setup stack */ > >+ PRINT("- Setup stack -\n") > >+ ldr x1, =stack_end > >+ mov sp, x1 > >+ > >+ PRINT("- Jumping to C entry -\n") > >+ mov x0, x20 /* x0 <- device tree (physical > >address) */ > >+ mov x1, x22 /* x1 <- phys_offset */ > >+ > >+ b arch_init > >+ENDPROC(_start) > >+ > >+/* > >+ * Get the phys-offset, and save it in x22 > >+ */ > >+_calc_offset: > >+ ldr x22, =_start /* x0 := vaddr(_start) */ > >+ adr x21, _start /* x21 := paddr(_start) */ > >+ sub x22, x21, x22 /* x22 := phys-offset (paddr - vaddr) > >*/ > >+ ret > >+ > >+/* > >+ * Setup the memory region attribute; > >+ * Setup the TCR. > >+ */ > >+_setup_cpu: > >+ /* > >+ * Setup memory attribute type tables > >+ * > >+ * Memory region attributes for LPAE: > >+ * > >+ * n = AttrIndx[2:0] > >+ * n MAIR > >+ * DEVICE_nGnRnE 000 00000000 (0x00) > >+ * DEVICE_nGnRE 001 00000100 (0x04) > >+ * DEVICE_GRE 010 00001100 (0x0c) > >+ * NORMAL_NC 011 01000100 (0x44) > >+ * NORMAL 100 11111111 (0xff) > >+ */ > >+ ldr x0, =(SET_MAIR(0x00, MEM_DEVICE_nGnRnE) | \ > >+ SET_MAIR(0x04, MEM_DEVICE_nGnRE) | \ > >+ SET_MAIR(0x0c, MEM_DEVICE_GRE) | \ > >+ SET_MAIR(0x44, MEM_NORMAL_NC) | \ > >+ SET_MAIR(0xff, MEM_NORMAL)) > >+ msr mair_el1, x0 > >+ > >+ /* > >+ * Setup translation control register (TCR) > >+ */ > >+ ldr x0, =(TCR_TxSZ(VA_BITS) | TCR_ASID16 | TCR_TG1_4K | \ > >+ TCR_IRGN_WBWA | TCR_ORGN_WBWA | TCR_SHARED | > >TCR_IPS_48BIT) > >+ msr tcr_el1, x0 > >+ > >+ ret > >+ > >+/* > >+ * Setup the page table mapping for @addr at @level with @prot. > >+ * > >+ * Note: x22 stores the offset between virtual address and physical address. > >+ */ > >+.macro set_page_table, addr, level, prot > >+ /* Find the table index in @level, save it in x3 */ > >+.if \level == 0 > >+ lsr x3, \addr, #L0_SHIFT > >+ adr x8, boot_l1_pgtable > >+ adr x11, boot_l0_pgtable > >+.endif > >+ > >+.if \level == 1 > >+ lsr x3, \addr, #L1_SHIFT > >+ adr x8, boot_l2_pgtable > >+ adr x11, boot_l1_pgtable > >+.endif > >+ > >+.if \level == 2 > >+ lsr x3, \addr, #L2_SHIFT > >+ adr x11, boot_l2_pgtable > >+ /* Get the physical address, the @addr should be 2M aligned. */ > >+ add x8, \addr, x22 > >+.endif > >+ > >+ and x3, x3, #Ln_ADDR_MASK > >+ > >+ /* Build the page table entry */ > >+ ldr x7, = \prot > >+ lsr x9, x8, #PAGE_SHIFT > >+ orr x7, x7, x9, lsl #PAGE_SHIFT > >+ > >+ /* Store entry */ > >+ str x7, [x11, x3, lsl #3] > >+.endm > >+ > >+/* > >+ * Setup the mapping for code section > >+ * > >+ * => null > >+ * <= x0 -> for TTBR1_EL1 > >+ */ > >+_setup_initial_pgtable: > >+ /* Start to map the code */ > >+ ldr x0, =_text /* x0 := vaddr(_text) */ > >+ ldr x1, =_end /* x1 := vaddr(_end) */ > >+ > >+ set_page_table x0, 0, PT_PT > >+ set_page_table x0, 1, PT_PT > >+1: > >+ set_page_table x0, 2, PT_MEM > >+ > >+ add x0, x0, L2_SIZE > >+ cmp x1, x0 > >+ b.gt 1b > >+ > >+ adr x0, boot_l0_pgtable > >+ dsb sy > >+ ret > >+ > >+/* > >+ * Setup the page table mapping for @addr at @level with @prot. > >+ * > >+ * Only used for identity mapping. > >+ */ > >+.macro set_ident_page_table, addr, level, prot > >+ /* Find the table index in @level, save it in x3 */ > >+.if \level == 0 > >+ lsr x3, \addr, #L0_SHIFT > >+ adr x8, idmap_l1_pgtable > >+ adr x11, idmap_l0_pgtable > >+.endif > >+ > >+.if \level == 1 > >+ lsr x3, \addr, #L1_SHIFT > >+ mov x8, \addr > >+ adr x11, idmap_l1_pgtable > >+.endif > >+ > >+ and x3, x3, #Ln_ADDR_MASK > >+ > >+ /* Build the page table entry */ > >+ ldr x7, = \prot > >+ lsr x9, x8, #PAGE_SHIFT > >+ orr x7, x7, x9, lsl #PAGE_SHIFT > >+ > >+ /* Store entry */ > >+ str x7, [x11, x3, lsl #3] > >+.endm > >+ > >+/* > >+ * Setup the page table for TTBR0_EL1: > >+ * Mapping the page table for the code section. > >+ * We use 48bit address, and just use level 0/1 > >+ * for the mapping (we do not use level 2 and level 3). > >+ * > >+ * => none > >+ * <= x0 : save the page table pointer for TTBR0_EL1. > >+ */ > >+_setup_idmap_pgtable: > >+ /* Create the VA = PA map */ > >+ adr x0, _text > >+ > >+ set_ident_page_table x0, 0, PT_PT > >+ set_ident_page_table x0, 1, PT_MEM > >+ > >+ adr x0, idmap_l0_pgtable > >+ dsb sy > >+ ret > >diff --git a/arch/arm/arm64/asm.h b/arch/arm/arm64/asm.h > >new file mode 100644 > >index 0000000..3a498c4 > >--- /dev/null > >+++ b/arch/arm/arm64/asm.h > > Again, nothing in this header look arm64 specific. > > >@@ -0,0 +1,18 @@ > >+#ifndef __ASM_H__ > >+#define __ASM_H__ > >+ > >+#define ALIGN .align 4 > >+ > >+#define ENTRY(name) \ > >+ .globl name; \ > >+ ALIGN; \ > >+ name: > >+ > >+#define END(name) \ > >+ .size name, .-name > >+ > >+#define ENDPROC(name) \ > >+ .type name, @function; \ > >+ END(name) > >+ > >+#endif /* __ASM_H__ */ > >diff --git a/include/arm/arm64/pagetable.h b/include/arm/arm64/pagetable.h > >new file mode 100644 > >index 0000000..8e2384f > >--- /dev/null > >+++ b/include/arm/arm64/pagetable.h > >@@ -0,0 +1,108 @@ > >+#ifndef __ARM64_PAGE_TABLE__ > >+ > >+#define __ARM64_PAGE_TABLE__ > >+ > >+/* TCR flags */ > >+#define TCR_TxSZ(x) ((((64) - (x)) << 16) | (((64) - (x)) << 0)) > >+#define TCR_IRGN_WBWA (((1) << 8) | ((1) << 24)) > >+#define TCR_ORGN_WBWA (((1) << 10) | ((1) << 26)) > >+#define TCR_SHARED (((3) << 12) | ((3) << 28)) > >+#define TCR_ASID16 ((1) << 36) > >+#define TCR_IPS_48BIT ((5) << 32) > >+#define TCR_TG1_4K ((2) << 30) > > Those flags are only going to work well in assembly. In C, you will have > truncation problem as the shift is based on integer (aka 32-bit). > > Also can you remove parenthese around all plain values. I.e s/(2)/2/. This > will make the code more readable. > > >+#define TCR_EPD0 (1 << 7) > >+ > >+/* Max virtual address */ > >+#define VM_MAX_ADDRESS (0xffffffffffffffff) > >+ > >+/* Number of virtual address bits */ > >+#define VA_BITS 48 > >+ > >+/* > >+ * Memory types available. > >+ */ > >+#define MEM_DEVICE_nGnRnE 0 > >+#define MEM_DEVICE_nGnRE 1 > >+#define MEM_DEVICE_GRE 2 > >+#define MEM_NORMAL_NC 3 > >+#define MEM_NORMAL 4 > >+ > >+#define SET_MAIR(attr, mt) ((attr) << ((mt) * 8)) > >+ > >+/* SCTLR_EL1 - System Control Register */ > >+#define SCTLR_M (1 << 0) > >+#define SCTLR_C (1 << 2) > >+#define SCTLR_I (1 << 12) > >+ > >+/* Level 0 table, 512GiB per entry */ > >+#define L0_SHIFT 39 > >+#define L0_SIZE (1UL << L0_SHIFT) > >+#define L0_INVAL 0x0 /* An invalid address */ > >+#define L0_TABLE 0x3 /* A next-level table */ > >+ > >+/* Level 1 table, 1GiB per entry */ > >+#define L1_SHIFT 30 > >+#define L1_SIZE (1 << L1_SHIFT) > > Please try to be consistent to use 1UL everywhere for *_SIZE. > > >+#define L1_OFFSET (L1_SIZE - 1) > >+#define L1_INVAL L0_INVAL > >+#define L1_BLOCK 0x1 > >+#define L1_TABLE L0_TABLE > >+#define L1_MASK (~(L1_SIZE-1)) > >+ > >+/* Level 2 table, 2MiB per entry */ > >+#define L2_SHIFT 21 > >+#define L2_SIZE (1 << L2_SHIFT) > >+#define L2_OFFSET (L2_SIZE - 1) > >+#define L2_INVAL L0_INVAL > >+#define L2_BLOCK L1_BLOCK > >+#define L2_TABLE L0_TABLE > >+#define L2_MASK (~(L2_SIZE-1)) > >+ > >+/* Level 3 table, 4KiB per entry */ > >+#define L3_SHIFT 12 > >+#define L3_SIZE (1 << L3_SHIFT) > >+#define L3_OFFSET (L3_SIZE - 1) > >+#define L3_INVAL 0x0 > >+#define L3_PAGE 0x3 > >+#define L3_MASK (~(L3_SIZE-1)) > >+ > >+#define Ln_ENTRIES (1 << 9) > >+#define Ln_ADDR_MASK (Ln_ENTRIES - 1) > >+ > >+#define ATTR_MASK_L 0xfff > >+ > >+#define l0_pgt_idx(va) (((va) >> L0_SHIFT) & Ln_ADDR_MASK) > >+#define l1_pgt_idx(va) (((va) >> L1_SHIFT) & Ln_ADDR_MASK) > >+#define l2_pgt_idx(va) (((va) >> L2_SHIFT) & Ln_ADDR_MASK) > >+#define l3_pgt_idx(va) (((va) >> L3_SHIFT) & Ln_ADDR_MASK) > >+ > >+/* > >+ * Lower attributes fields in Stage 1 VMSAv8-A Block and Page descriptor > >+ */ > >+#define ATTR_nG (1 << 11) > >+#define ATTR_AF (1 << 10) > >+#define ATTR_SH(x) ((x) << 8) > >+#define ATTR_SH_MASK ATTR_SH(3) > >+#define ATTR_SH_NS 0 /* Non-shareable */ > >+#define ATTR_SH_OS 2 /* Outer-shareable */ > >+#define ATTR_SH_IS 3 /* Inner-shareable */ > >+#define ATTR_AP_RW_BIT (1 << 7) > >+#define ATTR_AP(x) ((x) << 6) > >+#define ATTR_AP_MASK ATTR_AP(3) > >+#define ATTR_AP_RW (0 << 1) > >+#define ATTR_AP_RO (1 << 1) > >+#define ATTR_AP_USER (1 << 0) > >+#define ATTR_NS (1 << 5) > >+#define ATTR_IDX(x) ((x) << 2) > >+#define ATTR_IDX_MASK (7 << 2) > >+ > >+#define MEM_DEF_ATTR > >(ATTR_AF|ATTR_SH(ATTR_SH_IS)|ATTR_IDX(MEM_NORMAL)) > >+#define MEM_NC_ATTR > >(ATTR_AF|ATTR_SH(ATTR_SH_IS)|ATTR_IDX(MEM_NORMAL_NC)) > >+#define MEM_DEV_ATTR > >(ATTR_AF|ATTR_SH(ATTR_SH_IS)|ATTR_IDX(MEM_DEVICE_nGnRnE)) > >+ > >+#define MEM_RO_ATTR (MEM_DEF_ATTR|ATTR_AP(ATTR_AP_RO)) > >+ > >+#define PT_PT (L0_TABLE) > >+#define PT_MEM (MEM_DEF_ATTR | L1_BLOCK) > > The naming for those 2 macros don't make sense based on the value. For > instance, PT_PT gives the impression to be attribute for table and does not > necessarily need to be level-0. > > But I just notice that you define L1_TABLE as L0_TABLE. This is so > confusing, you probably want to do some renaming some where. Same for > L1_BLOCK. > > Cheers, > > -- > Julien Grall _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |