/*
* Copyright (c) 2015 Petr Pavlu
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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.
*/
#include <abi/asmtool.h>
#include <arch/arch.h>
#include <arch/regutils.h>
.section BOOTSTRAP
#define DIRECTORY_ENTRIES 16
/* MS-DOS stub */
msdos_stub:
.ascii "MZ" /* MS-DOS signature */
.space 0x3a /* Ignore fields up to byte at 0x3c */
.long pe_header - msdos_stub /* Offset to the PE header */
/* Portable Executable header */
pe_header:
/* PE signature */
.ascii "PE\x0\x0"
/* COFF File Header */
.short 0xaa64 /* Machine = IMAGE_FILE_MACHINE_ARM64 */
.short 1 /* Number of sections */
.long 0 /* Time date stamp */
.long 0 /* Pointer to symbol table */
.long 0 /* Number of symbols */
.short sec_table - opt_header /* Size of optional header */
/*
* Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE |
* IMAGE_FILE_LARGE_ADDRESS_AWARE
*/
.short 0x22
/* Optional header standard fields */
opt_header:
.short 0x20b /* Magic = PE32+ */
.byte 0 /* Major linker version */
.byte 0 /* Minor linker version */
.long payload_end - msdos_stub /* Size of code */
.long 0 /* Size of initialized data */
.long 0 /* Size of uninitialized data */
.long start - msdos_stub /* Address of entry point */
.long start - msdos_stub /* Base of code */
/* Optional header Windows-specific fields */
.quad 0 /* Image base */
.long 4 /* Section alignment */
.long 4 /* File alignment */
.short 0 /* Major operating system version */
.short 0 /* Minor operating system version */
.short 0 /* Major image version */
.short 0 /* Minor image version */
.short 0 /* Major subsystem version */
.short 0 /* Minor subsystem version */
.long 0 /* Win32 version value */
.long payload_end - msdos_stub /* Size of image */
.long start - msdos_stub /* Size of headers */
.long 0 /* Checksum */
.short 10 /* Subsystem = EFI application */
.short 0 /* DLL characteristics */
.quad 0 /* Size of stack reserve */
.quad 0 /* Size of stack commit */
.quad 0 /* Size of heap reserve */
.quad 0 /* Size of heap commit */
.long 0 /* Loader flags */
.long DIRECTORY_ENTRIES /* Number of RVA and sizes */
.space DIRECTORY_ENTRIES * 8 /* Directory entries */
sec_table:
.ascii ".text\x0\x0\x0" /* Name */
.long payload_end - start /* Virtual size */
.long start - msdos_stub /* Virtual address */
.long payload_end - start /* Size of raw data */
.long start - msdos_stub /* Pointer to raw data */
.long 0 /* Pointer to relocations */
.long 0 /* Pointer to line numbers */
.short 0 /* Number of relocations */
.short 0 /* Number of line numbers */
/*
* Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE |
* IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
*/
.long 0xe0000020
/** Boot loader entry point
*
* @param x0 UEFI image handle.
* @param x1 Pointer to the UEFI system table.
*
*/
SYMBOL(start)
.hidden start
/*
* Stay on the UEFI stack. Its size is at least 128 KiB, plenty for this
* boot loader.
*/
stp x29, x30, [sp, #-32]!
mov x29, sp
stp x0, x1, [sp, #16]
/*
* Self-relocate the image. Pass a load address of the image (x0) and a
* pointer to the dynamic array (x1).
*/
adr x0, msdos_stub
adrp x1, _DYNAMIC
add x1, x1, #:lo12:_DYNAMIC
bl self_relocate
cbnz x0, __uefi_exit
/*
* Flush the instruction cache of the relocated boot loader image.
*/
adr x0, msdos_stub
adrp x1, payload_end
sub x1, x1, x0
bl smc_coherence
/*
* Pass the image handle (x0), a pointer to the UEFI system table (x1),
* and the image load address (x2) to the boostrap function.
*/
ldp x0, x1, [sp, #16]
adr x2, msdos_stub
bl bootstrap
__uefi_exit:
ldp x29, x30, [sp], #32
ret
FUNCTION_BEGIN(halt)
.hidden halt
b halt
FUNCTION_END(halt)
/** Flush instruction caches
*
* @param x0 Starting address of the flushing.
* @param x1 Number of bytes to flush.
*
*/
FUNCTION_BEGIN(smc_coherence)
.hidden smc_coherence
/* Initialize loop */
mov x9, x0
mov x10, xzr
__dc_loop:
/* Data or Unified Cache Line Clean */
dc cvau, x9
add x9, x9, #4
add x10, x10, #4
cmp x10, x1
blo __dc_loop
dsb ish
/* Initialize loop */
mov x9, x0
mov x10, xzr
__ic_loop:
/* Instruction Cache Line Invalidate */
ic ivau, x9
add x9, x9, #4
add x10, x10, #4
cmp x10, x1
blo __ic_loop
dsb ish
isb
ret
FUNCTION_END(smc_coherence)
/** Flush data caches
*
* @param x0 Starting address of the flushing.
* @param x1 Number of bytes to flush.
*
*/
FUNCTION_BEGIN(dcache_flush)
.hidden dcache_flush
mov x9, x0
mov x10, xzr
__dc_flush_loop:
/* Data or Unified Cache Line Clean */
dc cvau, x9
add x9, x9, #4
add x10, x10, #4
cmp x10, x1
blo __dc_flush_loop
dsb ish
isb
ret
FUNCTION_END(dcache_flush)
/** Kernel entry
*
* @param x0 Kernel entry point.
* @param x1 Pointer to the bootinfo structure.
*
*/
FUNCTION_BEGIN(jump_to_kernel)
.hidden jump_to_kernel
mrs x9, CurrentEL
lsr x9, x9, 2
cmp x9, #3
b.eq __el3
cmp x9, #2
b.eq __el2
cmp x9, #1
b.eq __el1
b halt
__el3:
msr sctlr_el2, xzr
msr hcr_el2, xzr
isb
/* EL2 is AArch64, EL1 is Non-secure World */
mov x9, #(1 << 10)
orr x9, x9, #(1 << 0)
msr scr_el3, x9
isb
/* EL2h */
mov x9, #0x9
msr spsr_el3, x9
isb
adr x9, __el2
msr elr_el3, x9
isb
/* Switch to EL2 */
eret
__el2:
msr sctlr_el1, xzr
isb
/* EL1 is AArch64 */
mov x9, #(1 << 31)
msr hcr_el2, x9
isb
/* EL1h */
mov x9, #0x5
msr spsr_el2, x9
isb
adr x9, __el1
msr elr_el2, x9
isb
/* Switch to EL1 */
eret
__el1:
/* Do not trap on FPU instructions */
mrs x9, cpacr_el1
orr x9, x9, #(3 << 20)
msr cpacr_el1, x9
dmb ish
/* Disable MMU (removes the identity mapping provided by UEFI) */
mrs x9, sctlr_el1
bic x9, x9, #SCTLR_M_FLAG
msr sctlr_el1, x9
isb
br x0
FUNCTION_END(jump_to_kernel)