aboutsummaryrefslogtreecommitdiff
path: root/sys/arm64/arm64/locore.S
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arm64/arm64/locore.S')
-rw-r--r--sys/arm64/arm64/locore.S318
1 files changed, 223 insertions, 95 deletions
diff --git a/sys/arm64/arm64/locore.S b/sys/arm64/arm64/locore.S
index ba85bb4e46b2..fd77938edae9 100644
--- a/sys/arm64/arm64/locore.S
+++ b/sys/arm64/arm64/locore.S
@@ -22,8 +22,6 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * $FreeBSD$
*/
#include "assym.inc"
@@ -39,6 +37,19 @@
#define VIRT_BITS 48
+#if PAGE_SIZE == PAGE_SIZE_16K
+/*
+ * The number of level 3 tables to create. 32 will allow for 1G of address
+ * space, the same as a single level 2 page with 4k pages.
+ */
+#define L3_PAGE_COUNT 32
+#endif
+
+/*
+ * The size of our bootstrap stack.
+ */
+#define BOOT_STACK_SIZE (KSTACK_PAGES * PAGE_SIZE)
+
.globl kernbase
.set kernbase, KERNBASE
@@ -51,8 +62,8 @@
*/
ENTRY(_start)
- /* Drop to EL1 */
- bl drop_to_el1
+ /* Enter the kernel exception level */
+ bl enter_kernel_el
/*
* Disable the MMU. We may have entered the kernel with it on and
@@ -71,11 +82,10 @@ ENTRY(_start)
msr contextidr_el1, xzr
/* Get the virt -> phys offset */
- bl get_virt_delta
+ bl get_load_phys_addr
/*
* At this point:
- * x29 = PA - VA
* x28 = Our physical load address
*/
@@ -101,11 +111,12 @@ ENTRY(_start)
br x15
virtdone:
+ BTI_J
+
/* Set up the stack */
adrp x25, initstack_end
add x25, x25, :lo12:initstack_end
- mov sp, x25
- sub sp, sp, #PCB_SIZE
+ sub sp, x25, #PCB_SIZE
/* Zero the BSS */
ldr x15, .Lbss
@@ -125,25 +136,29 @@ virtdone:
/* Backup the module pointer */
mov x1, x0
- /* Make the page table base a virtual address */
- sub x26, x26, x29
- sub x24, x24, x29
-
sub sp, sp, #BOOTPARAMS_SIZE
mov x0, sp
- /* Degate the delda so it is VA -> PA */
- neg x29, x29
-
str x1, [x0, #BP_MODULEP]
- str x26, [x0, #BP_KERN_L1PT]
- str x29, [x0, #BP_KERN_DELTA]
adrp x25, initstack
add x25, x25, :lo12:initstack
str x25, [x0, #BP_KERN_STACK]
- str x24, [x0, #BP_KERN_L0PT]
str x27, [x0, #BP_KERN_TTBR0]
str x23, [x0, #BP_BOOT_EL]
+ str x4, [x0, #BP_HCR_EL2]
+
+#ifdef KASAN
+ /* Save bootparams */
+ mov x19, x0
+
+ /* Bootstrap an early shadow map for the boot stack. */
+ ldr x0, [x0, #BP_KERN_STACK]
+ ldr x1, =BOOT_STACK_SIZE
+ bl kasan_init_early
+
+ /* Restore bootparams */
+ mov x0, x19
+#endif
/* trace back starts here */
mov fp, #0
@@ -186,8 +201,8 @@ ENTRY(mpentry)
/* Disable interrupts */
msr daifset, #DAIF_INTR
- /* Drop to EL1 */
- bl drop_to_el1
+ /* Enter the kernel exception level */
+ bl enter_kernel_el
/* Set the context id */
msr contextidr_el1, xzr
@@ -196,8 +211,8 @@ ENTRY(mpentry)
adrp x24, pagetable_l0_ttbr1
add x24, x24, :lo12:pagetable_l0_ttbr1
/* Load the identity page table */
- adrp x27, pagetable_l0_ttbr0_boostrap
- add x27, x27, :lo12:pagetable_l0_ttbr0_boostrap
+ adrp x27, pagetable_l0_ttbr0_bootstrap
+ add x27, x27, :lo12:pagetable_l0_ttbr0_bootstrap
/* Enable the mmu */
bl start_mmu
@@ -211,9 +226,11 @@ ENTRY(mpentry)
br x15
mp_virtdone:
+ BTI_J
+
/* Start using the AP boot stack */
- ldr x4, =bootstack
- ldr x4, [x4]
+ adrp x4, bootstack
+ ldr x4, [x4, :lo12:bootstack]
mov sp, x4
#if defined(PERTHREAD_SSP)
@@ -232,6 +249,14 @@ mp_virtdone:
dsb sy
isb
+ /*
+ * Initialize the per-CPU pointer before calling into C code, for the
+ * benefit of kernel sanitizers.
+ */
+ adrp x18, bootpcpu
+ ldr x18, [x18, :lo12:bootpcpu]
+ msr tpidr_el1, x18
+
b init_secondary
END(mpentry)
#endif
@@ -240,10 +265,10 @@ END(mpentry)
* If we are started in EL2, configure the required hypervisor
* registers and drop to EL1.
*/
-LENTRY(drop_to_el1)
+LENTRY(enter_kernel_el)
mrs x23, CurrentEL
- lsr x23, x23, #2
- cmp x23, #0x2
+ and x23, x23, #(CURRENTEL_EL_MASK)
+ cmp x23, #(CURRENTEL_EL_EL2)
b.eq 1f
ret
1:
@@ -261,6 +286,10 @@ LENTRY(drop_to_el1)
ldr x2, =(HCR_RW | HCR_APK | HCR_API)
msr hcr_el2, x2
+ /* Stash value of HCR_EL2 for later */
+ isb
+ mrs x4, hcr_el2
+
/* Load the Virtualization Process ID Register */
mrs x2, midr_el1
msr vpidr_el2, x2
@@ -273,8 +302,15 @@ LENTRY(drop_to_el1)
ldr x2, .Lsctlr_res1
msr sctlr_el1, x2
- /* Don't trap to EL2 for exceptions */
- mov x2, #CPTR_RES1
+ /*
+ * On some hardware, e.g., Apple M1, we can't clear E2H, so make sure we
+ * don't trap to EL2 for SIMD register usage to have at least a
+ * minimally usable system.
+ */
+ tst x4, #HCR_E2H
+ mov x3, #CPTR_RES1 /* HCR_E2H == 0 */
+ mov x5, #CPTR_FPEN /* HCR_E2H == 1 */
+ csel x2, x3, x5, eq
msr cptr_el2, x2
/* Don't trap to EL2 for CP15 traps */
@@ -289,11 +325,14 @@ LENTRY(drop_to_el1)
msr cntvoff_el2, xzr
/* Hypervisor trap functions */
- adrp x2, hyp_vectors
- add x2, x2, :lo12:hyp_vectors
+ adrp x2, hyp_stub_vectors
+ add x2, x2, :lo12:hyp_stub_vectors
msr vbar_el2, x2
- mov x2, #(PSR_F | PSR_I | PSR_A | PSR_D | PSR_M_EL1h)
+ /* Zero vttbr_el2 so a hypervisor can tell the host and guest apart */
+ msr vttbr_el2, xzr
+
+ mov x2, #(PSR_DAIF | PSR_M_EL1h)
msr spsr_el2, x2
/* Configure GICv3 CPU interface */
@@ -319,56 +358,20 @@ LENTRY(drop_to_el1)
.align 3
.Lsctlr_res1:
.quad SCTLR_RES1
-LEND(drop_to_el1)
-
-#define VECT_EMPTY \
- .align 7; \
- 1: b 1b
-
- .align 11
-hyp_vectors:
- VECT_EMPTY /* Synchronous EL2t */
- VECT_EMPTY /* IRQ EL2t */
- VECT_EMPTY /* FIQ EL2t */
- VECT_EMPTY /* Error EL2t */
-
- VECT_EMPTY /* Synchronous EL2h */
- VECT_EMPTY /* IRQ EL2h */
- VECT_EMPTY /* FIQ EL2h */
- VECT_EMPTY /* Error EL2h */
-
- VECT_EMPTY /* Synchronous 64-bit EL1 */
- VECT_EMPTY /* IRQ 64-bit EL1 */
- VECT_EMPTY /* FIQ 64-bit EL1 */
- VECT_EMPTY /* Error 64-bit EL1 */
-
- VECT_EMPTY /* Synchronous 32-bit EL1 */
- VECT_EMPTY /* IRQ 32-bit EL1 */
- VECT_EMPTY /* FIQ 32-bit EL1 */
- VECT_EMPTY /* Error 32-bit EL1 */
+LEND(enter_kernel_el)
/*
- * Get the delta between the physical address we were loaded to and the
- * virtual address we expect to run from. This is used when building the
- * initial page table.
+ * Get the physical address the kernel was loaded at.
*/
-LENTRY(get_virt_delta)
- /* Load the physical address of virt_map */
- adrp x29, virt_map
- add x29, x29, :lo12:virt_map
- /* Load the virtual address of virt_map stored in virt_map */
- ldr x28, [x29]
- /* Find PA - VA as PA' = VA' - VA + PA = VA' + (PA - VA) = VA' + x29 */
- sub x29, x29, x28
- /* Find the load address for the kernel */
- mov x28, #(KERNBASE)
- add x28, x28, x29
+LENTRY(get_load_phys_addr)
+ /* Load the offset of get_load_phys_addr from KERNBASE */
+ ldr x28, =(get_load_phys_addr - KERNBASE)
+ /* Load the physical address of get_load_phys_addr */
+ adr x29, get_load_phys_addr
+ /* Find the physical address of KERNBASE, i.e. our load address */
+ sub x28, x29, x28
ret
-
- .align 3
-virt_map:
- .quad virt_map
-LEND(get_virt_delta)
+LEND(get_load_phys_addr)
/*
* This builds the page tables containing the identity map, and the kernel
@@ -431,8 +434,13 @@ LENTRY(create_pagetables)
/* Booted with modules pointer */
/* Find modulep - begin */
sub x8, x0, x6
- /* Add two 2MiB pages for the module data and round up */
- ldr x7, =(3 * L2_SIZE - 1)
+ /*
+ * Add space for the module data. When PAGE_SIZE is 4k this will
+ * add at least 2 level 2 blocks (2 * 2MiB). When PAGE_SIZE is
+ * larger it will be at least as large as we use smaller level 3
+ * pages.
+ */
+ ldr x7, =((6 * 1024 * 1024) - 1)
add x8, x8, x7
b common
@@ -457,6 +465,34 @@ booti_no_fdt:
#endif
common:
+#if PAGE_SIZE != PAGE_SIZE_4K
+ /*
+ * Create L3 pages. The kernel will be loaded at a 2M aligned
+ * address, however L2 blocks are too large when the page size is
+ * not 4k to map the kernel with such an aligned address. However,
+ * when the page size is larger than 4k, L2 blocks are too large to
+ * map the kernel with such an alignment.
+ */
+
+ /* Get the number of l3 pages to allocate, rounded down */
+ lsr x10, x8, #(L3_SHIFT)
+
+ /* Create the kernel space L2 table */
+ mov x6, x26
+ mov x7, #(ATTR_S1_IDX(VM_MEMATTR_WRITE_BACK))
+ mov x8, #(KERNBASE)
+ mov x9, x28
+ bl build_l3_page_pagetable
+
+ /* Move to the l2 table */
+ ldr x9, =(PAGE_SIZE * L3_PAGE_COUNT)
+ add x26, x26, x9
+
+ /* Link the l2 -> l3 table */
+ mov x9, x6
+ mov x6, x26
+ bl link_l2_pagetable
+#else
/* Get the number of l2 pages to allocate, rounded down */
lsr x10, x8, #(L2_SHIFT)
@@ -466,6 +502,7 @@ common:
mov x8, #(KERNBASE)
mov x9, x28
bl build_l2_block_pagetable
+#endif
/* Move to the l1 table */
add x26, x26, #PAGE_SIZE
@@ -504,7 +541,8 @@ common:
#if defined(SOCDEV_PA)
/* Create a table for the UART */
mov x7, #(ATTR_S1_nG | ATTR_S1_IDX(VM_MEMATTR_DEVICE))
- add x16, x16, #(L2_SIZE) /* VA start */
+ ldr x9, =(L2_SIZE)
+ add x16, x16, x9 /* VA start */
mov x8, x16
/* Store the socdev virtual address */
@@ -523,7 +561,8 @@ common:
/* Create the mapping for FDT data (2 MiB max) */
mov x7, #(ATTR_S1_nG | ATTR_S1_IDX(VM_MEMATTR_WRITE_BACK))
- add x16, x16, #(L2_SIZE) /* VA start */
+ ldr x9, =(L2_SIZE)
+ add x16, x16, x9 /* VA start */
mov x8, x16
mov x9, x0 /* PA start */
/* Update the module pointer to point at the allocated memory */
@@ -644,6 +683,9 @@ LENTRY(build_l2_block_pagetable)
orr x12, x7, #L2_BLOCK
orr x12, x12, #(ATTR_DEFAULT)
orr x12, x12, #(ATTR_S1_UXN)
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+ orr x12, x12, #(ATTR_S1_GP)
+#endif
/* Only use the output address bits */
lsr x9, x9, #L2_SHIFT
@@ -662,6 +704,79 @@ LENTRY(build_l2_block_pagetable)
ret
LEND(build_l2_block_pagetable)
+#if PAGE_SIZE != PAGE_SIZE_4K
+/*
+ * Builds an L2 -> L3 table descriptor
+ *
+ * x6 = L2 table
+ * x8 = Virtual Address
+ * x9 = L3 PA (trashed)
+ * x11, x12 and x13 are trashed
+ */
+LENTRY(link_l2_pagetable)
+ /*
+ * Link an L2 -> L3 table entry.
+ */
+ /* Find the table index */
+ lsr x11, x8, #L2_SHIFT
+ and x11, x11, #Ln_ADDR_MASK
+
+ /* Build the L1 block entry */
+ mov x12, #L2_TABLE
+
+ /* Only use the output address bits */
+ lsr x9, x9, #PAGE_SHIFT
+ orr x13, x12, x9, lsl #PAGE_SHIFT
+
+ /* Store the entry */
+ str x13, [x6, x11, lsl #3]
+
+ ret
+LEND(link_l2_pagetable)
+
+/*
+ * Builds count level 3 page table entries
+ * x6 = L3 table
+ * x7 = Block attributes
+ * x8 = VA start
+ * x9 = PA start (trashed)
+ * x10 = Entry count (trashed)
+ * x11, x12 and x13 are trashed
+ */
+LENTRY(build_l3_page_pagetable)
+ /*
+ * Build the L3 table entry.
+ */
+ /* Find the table index */
+ lsr x11, x8, #L3_SHIFT
+ and x11, x11, #Ln_ADDR_MASK
+
+ /* Build the L3 page entry */
+ orr x12, x7, #L3_PAGE
+ orr x12, x12, #(ATTR_DEFAULT)
+ orr x12, x12, #(ATTR_S1_UXN)
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+ orr x12, x12, #(ATTR_S1_GP)
+#endif
+
+ /* Only use the output address bits */
+ lsr x9, x9, #L3_SHIFT
+
+ /* Set the physical address for this virtual address */
+1: orr x13, x12, x9, lsl #L3_SHIFT
+
+ /* Store the entry */
+ str x13, [x6, x11, lsl #3]
+
+ sub x10, x10, #1
+ add x11, x11, #1
+ add x9, x9, #1
+ cbnz x10, 1b
+
+ ret
+LEND(build_l3_page_pagetable)
+#endif
+
LENTRY(start_mmu)
dsb sy
@@ -743,14 +858,22 @@ mair:
MAIR_ATTR(MAIR_NORMAL_WT, VM_MEMATTR_WRITE_THROUGH) | \
MAIR_ATTR(MAIR_DEVICE_nGnRE, VM_MEMATTR_DEVICE_nGnRE)
tcr:
- .quad (TCR_TxSZ(64 - VIRT_BITS) | TCR_TG1_4K | TCR_TG0_4K | \
+#if PAGE_SIZE == PAGE_SIZE_4K
+#define TCR_TG (TCR_TG1_4K | TCR_TG0_4K)
+#elif PAGE_SIZE == PAGE_SIZE_16K
+#define TCR_TG (TCR_TG1_16K | TCR_TG0_16K)
+#else
+#error Unsupported page size
+#endif
+
+ .quad (TCR_TxSZ(64 - VIRT_BITS) | TCR_TG | \
TCR_CACHE_ATTRS | TCR_SMP_ATTRS)
sctlr_set:
/* Bits to set */
.quad (SCTLR_LSMAOE | SCTLR_nTLSMD | SCTLR_UCI | SCTLR_SPAN | \
SCTLR_nTWE | SCTLR_nTWI | SCTLR_UCT | SCTLR_DZE | \
SCTLR_I | SCTLR_SED | SCTLR_SA0 | SCTLR_SA | SCTLR_C | \
- SCTLR_M | SCTLR_CP15BEN)
+ SCTLR_M | SCTLR_CP15BEN | SCTLR_BT1 | SCTLR_BT0)
sctlr_clear:
/* Bits to clear */
.quad (SCTLR_EE | SCTLR_E0E | SCTLR_IESB | SCTLR_WXN | SCTLR_UMA | \
@@ -761,6 +884,12 @@ ENTRY(abort)
b abort
END(abort)
+.bss
+ .align PAGE_SHIFT
+initstack:
+ .space BOOT_STACK_SIZE
+initstack_end:
+
.section .init_pagetable, "aw", %nobits
.align PAGE_SHIFT
/*
@@ -774,6 +903,10 @@ END(abort)
*/
.globl pagetable_l0_ttbr1
pagetable:
+#if PAGE_SIZE != PAGE_SIZE_4K
+ .space (PAGE_SIZE * L3_PAGE_COUNT)
+pagetable_l2_ttbr1:
+#endif
.space PAGE_SIZE
pagetable_l1_ttbr1:
.space PAGE_SIZE
@@ -783,24 +916,19 @@ pagetable_l2_ttbr0_bootstrap:
.space PAGE_SIZE
pagetable_l1_ttbr0_bootstrap:
.space PAGE_SIZE
-pagetable_l0_ttbr0_boostrap:
+pagetable_l0_ttbr0_bootstrap:
.space PAGE_SIZE
pagetable_l0_ttbr0:
.space PAGE_SIZE
-
pagetable_end:
el2_pagetable:
.space PAGE_SIZE
- .align 4
-initstack:
- .space (PAGE_SIZE * KSTACK_PAGES)
-initstack_end:
-
-
-.text
-EENTRY(aarch32_sigcode)
+ .section .rodata, "a", %progbits
+ .globl aarch32_sigcode
+ .align 2
+aarch32_sigcode:
.word 0xe1a0000d // mov r0, sp
.word 0xe2800040 // add r0, r0, #SIGF_UC
.word 0xe59f700c // ldr r7, [pc, #12]
@@ -808,10 +936,10 @@ EENTRY(aarch32_sigcode)
.word 0xe59f7008 // ldr r7, [pc, #8]
.word 0xef000000 // swi #0
.word 0xeafffffa // b . - 16
-EEND(aarch32_sigcode)
.word SYS_sigreturn
.word SYS_exit
.align 3
+ .size aarch32_sigcode, . - aarch32_sigcode
aarch32_esigcode:
.data
.global sz_aarch32_sigcode