HelenOS sources

root/boot/arch/arm64/src/asm.S

/* [<][>][^][v][top][bottom][index][help] */
/*
 * 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)

/* [<][>][^][v][top][bottom][index][help] */
HelenOS homepage, sources at GitHub