mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
mini-os: arm: boot code
Based on an initial patch by Karim Raslan. Signed-off-by: Karim Allah Ahmed <karim.allah.ahmed@gmail.com> Signed-off-by: Thomas Leonard <talex5@gmail.com> Acked-by: Ian Campbell <ian.campbell@citrix.com>
This commit is contained in:
1 parent
abc465b15c
commit
dce56dfac0
4 files changed
+477
No files matched your search
@@ -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
|
||||
@@ -0,0 +1,64 @@
|
||||
/******************************************************************************
|
||||
* hypercall.S
|
||||
*
|
||||
* Xen hypercall wrappers
|
||||
*
|
||||
* Stefano Stabellini <stefano.stabellini@eu.citrix.com>, 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);
|
||||
Executable
+83
@@ -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) }
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||