[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH ARM v7 05/13] mini-os: arm: boot code
Based on an initial patch by Karim Raslan. Signed-off-by: Karim Allah Ahmed <karim.allah.ahmed@xxxxxxxxx> Signed-off-by: Thomas Leonard <talex5@xxxxxxxxx> --- Changes since v6: - Fixed printk format types. Addressed Ian Campbell's comments: - ARMv7 A8.8.247 says udf should not be used conditionally, so use a branch instead. - Enable caching earlier (required setting the cacheability for the translation table walks). - Added some extra dsb instructions to protect against reordering. Addressed Julien Grall's comments: - Note that TTBCR is zero (using short-descriptors, TTBR0 only). - Note about relying on 0x8000 load offset. --- extras/mini-os/arch/arm/arm32.S | 211 +++++++++++++++++++++++++++++++ extras/mini-os/arch/arm/hypercalls32.S | 64 ++++++++++ extras/mini-os/arch/arm/minios-arm32.lds | 83 ++++++++++++ extras/mini-os/arch/arm/setup.c | 119 +++++++++++++++++ 4 files changed, 477 insertions(+) create mode 100644 extras/mini-os/arch/arm/arm32.S create mode 100644 extras/mini-os/arch/arm/hypercalls32.S create mode 100755 extras/mini-os/arch/arm/minios-arm32.lds create mode 100644 extras/mini-os/arch/arm/setup.c diff --git a/extras/mini-os/arch/arm/arm32.S b/extras/mini-os/arch/arm/arm32.S new file mode 100644 index 0000000..d2e6932 --- /dev/null +++ b/extras/mini-os/arch/arm/arm32.S @@ -0,0 +1,211 @@ +@ Offset of the kernel within the RAM. This is a Linux/zImage convention which we +@ rely on for now. +#define ZIMAGE_KERNEL_OFFSET 0x8000 + +.section .text + +.globl _start +_start: + @ zImage header +.rept 8 + mov r0, r0 +.endr + b reset + .word 0x016f2818 @ Magic numbers to help the loader + .word 0 @ zImage start address (0 = relocatable) + .word _edata - _start @ zImage end address (excludes bss section) + @ end of zImage header + +@ Called at boot time. Sets up MMU, exception vectors and stack, and then calls C arch_init() function. +@ => r2 -> DTB +@ <= never returns +@ Note: this boot code needs to be within the first (1MB - ZIMAGE_KERNEL_OFFSET) of _start. +reset: + @ Problem: the C code wants to be at a known address (_start), but Xen might + @ load us anywhere. We initialise the MMU (mapping virtual to physical @ addresses) + @ so everything ends up where the code expects it to be. + @ + @ We calculate the offet between where the linker thought _start would be and where + @ it actually is and initialise the page tables to have that offset for every page. + @ + @ When we turn on the MMU, we're still executing at the old address. We don't want + @ the code to disappear from under us. So we have to do the mapping in stages: + @ + @ 1. set up a mapping to our current page from both its current and desired addresses + @ 2. enable the MMU + @ 3. jump to the new address + @ 4. remap all the other pages with the calculated offset + + adr r1, _start @ r1 = physical address of _start + ldr r3, =_start @ r3 = (desired) virtual address of _start + sub r9, r1, r3 @ r9 = (physical - virtual) offset + + ldr r7, =_page_dir @ r7 = (desired) virtual addr of translation table + add r1, r7, r9 @ r1 = physical addr of translation table + + @ Tell the system where our page table is located. + @ This is the 16 KB top-level translation table, in which + @ each word maps one 1MB virtual section to a physical section. + @ Note: We leave TTBCR as 0, meaning that only TTBR0 is used and + @ we use the short-descriptor format (32-bit physical addresses). + orr r0, r1, #0b0001011 @ Sharable, Inner/Outer Write-Back Write-Allocate Cacheable + mcr p15, 0, r0, c2, c0, 0 @ set TTBR0 + + @ Set access permission for domains. + @ Domains are deprecated, but we have to configure them anyway. + @ We mark every page as being domain 0 and set domain 0 to "client mode" + @ (client mode = use access flags in page table). + mov r0, #1 @ 1 = client + mcr p15, 0, r0, c3, c0, 0 @ DACR + + @ Template (flags) for a 1 MB page-table entry. + @ TEX[2:0] C B = 001 1 1 (outer and inner write-back, write-allocate) + ldr r8, =(0x2 + /* Section entry */ \ + 0xc + /* C B */ \ + (3 << 10) + /* Read/write */ \ + (1 << 12) + /* TEX */ \ + (1 << 16) + /* Sharable */ \ + (1<<19)) /* Non-secure */ + @ r8 = template page table entry + + @ Add an entry for the current physical section, at the old and new + @ addresses. It's OK if they're the same. + mov r0, pc, lsr#20 + mov r0, r0, lsl#20 @ r0 = physical address of this code's section start + orr r3, r0, r8 @ r3 = table entry for this section + ldr r4, =_start @ r4 = desired virtual address of this section + str r3, [r1, r4, lsr#18] @ map desired virtual section to this code + str r3, [r1, r0, lsr#18] @ map current section to this code too + + @ Invalidate TLB + dsb @ Caching is off, but must still prevent reordering + mcr p15, 0, r1, c8, c7, 0 @ TLBIALL + + @ Enable MMU / SCTLR + mrc p15, 0, r1, c1, c0, 0 @ SCTLR + orr r1, r1, #3 << 11 @ enable icache, branch prediction + orr r1, r1, #4 + 1 @ enable dcache, MMU + mcr p15, 0, r1, c1, c0, 0 @ SCTLR + isb + + ldr r1, =stage2 @ Virtual address of stage2 + bx r1 + +@ Called once the MMU is enabled. The boot code and the page table are mapped, +@ but nothing else is yet. +@ +@ => r2 -> dtb (physical) +@ r7 = virtual address of page table +@ r8 = section entry template (flags) +@ r9 = desired physical - virtual offset +@ pc -> somewhere in newly-mapped virtual code section +stage2: + @ Invalidate TLB + mcr p15, 0, r1, c8, c7, 0 @ TLBIALL + isb + + @ The new mapping has now taken effect: + @ r7 -> page_dir + + @ Fill in the whole top-level translation table (at page_dir). + @ Populate the whole pagedir with 1MB section descriptors. + + mov r1, r7 @ r1 -> first section entry + add r3, r1, #4*4*1024 @ limit (4 GB address space, 4 byte entries) + orr r0, r8, r9 @ r0 = entry mapping section zero to start of physical RAM +1: + str r0, [r1],#4 @ write the section entry + add r0, r0, #1 << 20 @ next physical page (wraps) + cmp r1, r3 + bne 1b + + @ Invalidate TLB + dsb + mcr p15, 0, r1, c8, c7, 0 @ TLBIALL + isb + + @ Set VBAR -> exception_vector_table + @ SCTLR.V = 0 + adr r0, exception_vector_table + mcr p15, 0, r0, c12, c0, 0 + + @ Enable hardware floating point: + @ 1. Access to CP10 and CP11 must be enabled in the Coprocessor Access + @ Control Register (CP15.CACR): + mrc p15, 0, r1, c1, c0, 2 @ CACR + orr r1, r1, #(3 << 20) + (3 << 22) @ full access for CP10 & CP11 + mcr p15, 0, r1, c1, c0, 2 + @ 2. The EN bit in the FPEXC register must be set: + vmrs r0, FPEXC + orr r0, r0, #1<<30 @ EN (enable) + vmsr FPEXC, r0 + + @ Initialise 16 KB stack + ldr sp, =_boot_stack_end + + sub r0, r2, r9 @ r0 -> device tree (virtual address) + mov r1, r9 @ r1 = physical_address_offset + + b arch_init + +.pushsection .bss +@ Note: calling arch_init zeroes out this region. +.align 12 +.globl shared_info_page +shared_info_page: + .fill (1024), 4, 0x0 + +.align 3 +.globl irqstack +.globl irqstack_end +irqstack: + .fill (1024), 4, 0x0 +irqstack_end: + +.popsection + +@ exception base address +.align 5 +.globl exception_vector_table +@ Note: remember to call CLREX if returning from an exception: +@ "The architecture enables the local monitor to treat any exclusive store as +@ matching a previous LDREX address. For this reason, use of the CLREX +@ instruction to clear an existing tag is required on context switches." +@ -- ARM Cortex-A Series Programmerâs Guide (Version: 4.0) +exception_vector_table: + b . @ reset + b . @ undefined instruction + b . @ supervisor call + b . @ prefetch call + b . @ prefetch abort + b . @ data abort + b irq_handler @ irq + .word 0xe7f000f0 @ abort on FIQ + +@ Call fault_undefined_instruction in "Undefined mode" +bug: + .word 0xe7f000f0 @ und/udf - a "Permanently Undefined" instruction + +irq_handler: + ldr sp, =irqstack_end + push {r0 - r12, r14} + + ldr r0, IRQ_handler + cmp r0, #0 + beq bug + blx r0 @ call handler + + @ Return from IRQ + pop {r0 - r12, r14} + clrex + subs pc, lr, #4 + +.globl IRQ_handler +IRQ_handler: + .long 0x0 + +@ This is called if you try to divide by zero. For now, we make a supervisor call, +@ which will make us halt. +.globl raise +raise: + svc 0 diff --git a/extras/mini-os/arch/arm/hypercalls32.S b/extras/mini-os/arch/arm/hypercalls32.S new file mode 100644 index 0000000..af8e175 --- /dev/null +++ b/extras/mini-os/arch/arm/hypercalls32.S @@ -0,0 +1,64 @@ +/****************************************************************************** + * hypercall.S + * + * Xen hypercall wrappers + * + * Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>, Citrix, 2012 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <xen/xen.h> + +#define __HVC(imm16) .long ((0xE1400070 | (((imm16) & 0xFFF0) << 4) | ((imm16) & 0x000F)) & 0xFFFFFFFF) + +#define XEN_IMM 0xEA1 + +#define HYPERCALL_SIMPLE(hypercall) \ +.globl HYPERVISOR_##hypercall; \ +.align 4,0x90; \ +HYPERVISOR_##hypercall: \ + mov r12, #__HYPERVISOR_##hypercall; \ + __HVC(XEN_IMM); \ + mov pc, lr; + +#define _hypercall0 HYPERCALL_SIMPLE +#define _hypercall1 HYPERCALL_SIMPLE +#define _hypercall2 HYPERCALL_SIMPLE +#define _hypercall3 HYPERCALL_SIMPLE +#define _hypercall4 HYPERCALL_SIMPLE + +_hypercall2(sched_op); +_hypercall2(memory_op); +_hypercall2(event_channel_op); +_hypercall2(xen_version); +_hypercall3(console_io); +_hypercall1(physdev_op); +_hypercall3(grant_table_op); +_hypercall3(vcpu_op); +_hypercall1(sysctl); +_hypercall1(domctl); +_hypercall2(hvm_op); +_hypercall1(xsm_op); diff --git a/extras/mini-os/arch/arm/minios-arm32.lds b/extras/mini-os/arch/arm/minios-arm32.lds new file mode 100755 index 0000000..9627162 --- /dev/null +++ b/extras/mini-os/arch/arm/minios-arm32.lds @@ -0,0 +1,83 @@ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + /* Note: we currently assume that Xen will load the kernel image + * at start-of-RAM + 0x8000. We use this initial 32 KB for the stack + * and translation tables. + */ + _boot_stack = 0x400000; /* 16 KB boot stack */ + _boot_stack_end = 0x404000; + _page_dir = 0x404000; /* 16 KB translation table */ + . = 0x408000; + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.gnu.warning) + } = 0x9090 + + _etext = .; /* End of text section */ + + .rodata : { *(.rodata) *(.rodata.*) } + . = ALIGN(4096); + _erodata = .; + + /* newlib initialization functions */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + + .ctors : { + __CTOR_LIST__ = .; + *(.ctors) + CONSTRUCTORS + LONG(0) + __CTOR_END__ = .; + } + + .dtors : { + __DTOR_LIST__ = .; + *(.dtors) + LONG(0) + __DTOR_END__ = .; + } + + .data : { /* Data */ + *(.data) + } + + /* Note: linker will insert any extra sections here, just before .bss */ + + .bss : { + _edata = .; /* End of data included in image */ + /* Nothing after here is included in the zImage's size */ + + __bss_start = .; + *(.bss) + *(.app.bss) + } + _end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.text.exit) + *(.data.exit) + *(.exitcall.exit) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff --git a/extras/mini-os/arch/arm/setup.c b/extras/mini-os/arch/arm/setup.c new file mode 100644 index 0000000..06afe46 --- /dev/null +++ b/extras/mini-os/arch/arm/setup.c @@ -0,0 +1,119 @@ +#include <mini-os/os.h> +#include <mini-os/kernel.h> +#include <mini-os/gic.h> +#include <mini-os/console.h> +#include <xen/xen.h> +#include <xen/memory.h> +#include <xen/hvm/params.h> +#include <arch_mm.h> +#include <libfdt.h> + +/* + * This structure contains start-of-day info, such as pagetable base pointer, + * address of the shared_info structure, and things like that. + * On x86, the hypervisor passes it to us. On ARM, we fill it in ourselves. + */ +union start_info_union start_info_union; + +/* + * Shared page for communicating with the hypervisor. + * Events flags go here, for example. + */ +shared_info_t *HYPERVISOR_shared_info; + +extern char shared_info_page[PAGE_SIZE]; + +void *device_tree; + +static int hvm_get_parameter(int idx, uint64_t *value) +{ + struct xen_hvm_param xhv; + int ret; + + xhv.domid = DOMID_SELF; + xhv.index = idx; + ret = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv); + if (ret < 0) { + BUG(); + } + *value = xhv.value; + return ret; +} + +static void get_console(void) +{ + uint64_t v = -1; + + hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); + start_info.console.domU.evtchn = v; + + hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); + start_info.console.domU.mfn = v; + + printk("Console is on port %d\n", start_info.console.domU.evtchn); + printk("Console ring is at mfn %lx\n", (unsigned long) start_info.console.domU.mfn); +} + +void get_xenbus(void) +{ + uint64_t value; + + if (hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &value)) + BUG(); + + start_info.store_evtchn = (int)value; + + if(hvm_get_parameter(HVM_PARAM_STORE_PFN, &value)) + BUG(); + start_info.store_mfn = (unsigned long)value; +} + +/* + * INITIAL C ENTRY POINT. + */ +void arch_init(void *dtb_pointer, uint32_t physical_offset) +{ + struct xen_add_to_physmap xatp; + int r; + + memset(&__bss_start, 0, &_end - &__bss_start); + + physical_address_offset = physical_offset; + + xprintk("Virtual -> physical offset = %x\n", physical_address_offset); + + xprintk("Checking DTB at %p...\n", dtb_pointer); + + if ((r = fdt_check_header(dtb_pointer))) { + xprintk("Invalid DTB from Xen: %s\n", fdt_strerror(r)); + BUG(); + } + device_tree = dtb_pointer; + + /* Map shared_info page */ + xatp.domid = DOMID_SELF; + xatp.idx = 0; + xatp.space = XENMAPSPACE_shared_info; + xatp.gpfn = virt_to_pfn(shared_info_page); + if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp) != 0) + BUG(); + HYPERVISOR_shared_info = (struct shared_info *)shared_info_page; + + /* Fill in start_info */ + get_console(); + get_xenbus(); + + gic_init(); + + start_kernel(); +} + +void +arch_fini(void) +{ +} + +void +arch_do_exit(void) +{ +} -- 2.0.3 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |