[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.