.section .text.user_first,"ax" .balign 4 .global __user_blob_start __user_blob_start: // Copied to private EL0 RO+X page at 0x80000000. These instructions // touch separate RW+XN data and stack pages before SVC #0x42. .if {elf_stack} // New ELF image: consume argc/argv through EL0 stack translations, // preserve a witness in reserved stack bytes, and restore SP after a // real push/pop before continuing to the R|X write-fault instruction. movz x0, #0x5a5a ldr x3, [sp] ldr x4, [sp, #8] ldr x5, [x4] ldrb w6, [x5] str x3, [sp, #208] str x6, [sp, #216] str x0, [sp, #-16]! ldr x0, [sp], #16 movz x1, #0x1000 movk x1, #0x8000, lsl #16 ldr x2, [x1] str x0, [x1] ldr x2, [x1] movz x1, #0x0000 movk x1, #0x8000, lsl #16 str x0, [x1] svc #0x42 b . .else .if {elf_load} // Executed only after ELF PT_LOAD bytes were installed in owned pages. // Read the ELF data canary, write the RW page, then deliberately attempt // to write the ELF R|X page. The final STR must raise EL0 permission fault. movz x0, #0x5a5a movz x1, #0x1000 movk x1, #0x8000, lsl #16 ldr x2, [x1] str x0, [x1] ldr x2, [x1] movz x1, #0x0000 movk x1, #0x8000, lsl #16 str x0, [x1] svc #0x42 b . .else .if {dual_space} // A/B token is supplied in x0 at ERET, so identical user VAs execute // independent physical code while preserving distinct data witnesses. nop .else movz x0, #0x5a5a .endif .if {stack_overflow} // Cross the one-page stack boundary with the live EL0 stack pointer. sub sp, sp, #0x1000 sub sp, sp, #16 str x0, [sp] .else .if {write_fault} movz x1, #0x0000 .else movz x1, #0x1000 .endif movk x1, #0x8000, lsl #16 .if {unaligned} // Exclusive accesses require alignment even when ordinary Normal-memory // loads are permitted to use an unaligned address. add x1, x1, #1 .else .if {data_exec} br x1 .else str x0, [x1] .endif .endif .endif .if {unaligned} ldxr x0, [x1] .else ldr x0, [x1] .endif str x0, [sp, #-16]! ldr x0, [sp], #16 svc #0x42 b . .endif .endif .global __user_blob_end __user_blob_end: .if {dual_fault} .balign 4 .global __user_kernel_read_blob_start __user_kernel_read_blob_start: // x1 is the EL1-only kernel TTBR0 root supplied at ERET. A must fault // before touching its private data or stack; B uses the normal blob. nop nop nop ldr x0, [x1] ldr x0, [x1] str x0, [sp, #-16]! ldr x0, [sp], #16 svc #0x42 b . .global __user_kernel_read_blob_end __user_kernel_read_blob_end: .endif .if {dual_stack_fault} .balign 4 .global __user_stack_fault_blob_start __user_stack_fault_blob_start: // A uses its live EL0 SP to enter the unmapped guard page. B retains the // ordinary 36-byte blob in a disjoint private root and must still run. nop sub sp, sp, #0x1000 sub sp, sp, #16 str x0, [sp] nop nop nop nop nop .global __user_stack_fault_blob_end __user_stack_fault_blob_end: .endif .balign 128 .global __user_first_sync_entry __user_first_sync_entry: // EL0 SVC arrives on SP_EL1. Preserve the user x0 token before using // argument registers for the hardware exception record. mov x5, x0 mrs x0, ESR_EL1 mrs x1, ELR_EL1 mrs x2, SP_EL0 mrs x3, SPSR_EL1 mrs x4, TTBR0_EL1 mrs x6, FAR_EL1 .if {dual_space} b kernel_user_dual_exception .else b kernel_user_first_exception .endif