Mailing List Archive

[PATCH 07/14] arm: implement the functions which are required to create the dom0.
arm: implement the functions which are required to create the dom0.

xen/arch/arm/xen/Makefile | 1 +
xen/arch/arm/xen/arch_domain.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
xen/arch/arm/xen/armv7.S | 19 ++++++++
xen/arch/arm/xen/domain_build.c | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
xen/arch/arm/xen/mm.c | 2 -
xen/include/asm-arm/current.h | 23 ++++++++++
xen/include/asm-arm/domain.h | 39 +----------------
7 files changed, 356 insertions(+), 61 deletions(-)

Signed-off-by: Jaemin Ryu <jm77.ryu@samsung.com>

diff -r 08f39a9da04f xen/arch/arm/xen/Makefile
--- a/xen/arch/arm/xen/Makefile Mon Feb 06 11:17:01 2012 +0900
+++ b/xen/arch/arm/xen/Makefile Sun Feb 12 11:46:32 2012 +0900
@@ -21,3 +21,4 @@ obj-y += crash.o
obj-y += p2m.o
obj-y += perfmon.o
obj-y += pci.o
+obj-y += armv7.o
diff -r 08f39a9da04f xen/arch/arm/xen/arch_domain.c
--- a/xen/arch/arm/xen/arch_domain.c Mon Feb 06 11:17:01 2012 +0900
+++ b/xen/arch/arm/xen/arch_domain.c Sun Feb 12 11:46:32 2012 +0900
@@ -31,6 +31,12 @@
#include <xen/irq.h>
#include <xen/irq_cpustat.h>
#include <xen/softirq.h>
+#include <asm/current.h>
+#include <asm/cpu-ops.h>
+#include <asm/memory.h>
+#include <asm/mmu.h>
+
+struct vcpu *switch_to( struct vcpu *, struct vcpu_guest_context *, struct vcpu_guest_context *);

void arch_dump_domain_info(struct domain *d)
{
@@ -52,33 +58,84 @@ unsigned long hypercall_create_continuat

int arch_domain_create(struct domain *d, unsigned int domcr_flags)
{
- NOT_YET();
+ int rc;

- return -EINVAL;
+ rc = 0;
+ if (is_idle_domain(d))
+ return rc;
+
+ d->arch.ioport_caps = rangeset_new(d, "I/O Ports", RANGESETF_prettyprint_hex);
+ rc = -ENOMEM;
+ if (d->arch.ioport_caps == NULL) {
+ goto failed;
+ }
+
+ if ((d->shared_info = alloc_xenheap_pages(0, MEMF_bits(32))) == NULL) {
+ goto failed;
+ }
+
+ clear_page(d->shared_info);
+ share_xen_page_with_guest(virt_to_page(d->shared_info), d, XENSHARE_writable);
+
+ d->arch.pirq_irq = xmalloc_array(int, d->nr_pirqs);
+ if (!d->arch.pirq_irq) {
+ goto failed;
+ }
+
+ memset(d->arch.pirq_irq, 0, d->nr_pirqs * sizeof(*d->arch.pirq_irq));
+
+ d->arch.irq_pirq = xmalloc_array(int, nr_irqs);
+ if ( !d->arch.irq_pirq ) {
+ goto failed;
+ }
+
+ memset(d->arch.irq_pirq, 0, nr_irqs * sizeof(*d->arch.irq_pirq));
+
+ return 0;
+
+failed:
+ d->is_dying = DOMDYING_dead;
+ xfree(d->arch.pirq_irq);
+ xfree(d->arch.irq_pirq);
+
+ free_xenheap_page(d->shared_info);
+
+ return rc;
}

void arch_domain_destroy(struct domain *d)
{
- NOT_YET();
+ free_xenheap_page(d->shared_info);
+
+ xfree(d->arch.pirq_irq);
+ xfree(d->arch.irq_pirq);
}

struct vcpu_guest_context *alloc_vcpu_guest_context(void)
{
- NOT_YET();
+ struct vcpu_guest_context *vgc;

- return NULL;
+ vgc = xmalloc(struct vcpu_guest_context);
+
+ return vgc;
}

void free_vcpu_guest_context(struct vcpu_guest_context *context)
{
- NOT_YET();
+ xfree(context);
}


struct vcpu *alloc_vcpu_struct(void)
{
- NOT_YET();
- return NULL;
+ struct vcpu *v;
+
+ v = xmalloc(struct vcpu);
+ if ( v != NULL )
+ memset(v, 0, sizeof(struct vcpu));
+
+
+ return v;
}

void arch_vcpu_reset(struct vcpu *v)
@@ -88,7 +145,6 @@ void arch_vcpu_reset(struct vcpu *v)

int vcpu_initialise(struct vcpu *v)
{
- NOT_YET();
return 0;
}

@@ -99,27 +155,32 @@ void vcpu_destroy(struct vcpu *v)

void free_vcpu_struct(struct vcpu *v)
{
- NOT_YET();
+ xfree(v);
}

struct domain *alloc_domain_struct(void)
{
- NOT_YET();
+ struct domain *d;

- return NULL;
+ d = xmalloc(struct domain);
+ if ( d != NULL )
+ memset(d, 0, sizeof(struct domain));
+
+ return d;
}


void free_domain_struct(struct domain *d)
{
- NOT_YET();
+ xfree(d);
}

+/* This is called by arch_final_setup_guest and do_boot_vcpu */
int arch_set_info_guest(struct vcpu *v, vcpu_guest_context_t *ctx)
{
NOT_YET();

- return 0;
+ return -EINVAL;

}

@@ -135,12 +196,17 @@ void dump_pageframe_info(struct domain *

void context_switch(struct vcpu *prev, struct vcpu *next)
{
- NOT_YET();
+ ASSERT(prev != next);
+ ASSERT(vcpu_runnable(next));
+
+ prev = switch_to(prev, &prev->arch.ctx, &next->arch.ctx);
}

void continue_running(struct vcpu *same)
{
NOT_YET();
+
+ return ;
}

void sync_lazy_execstate_cpu(unsigned int cpu)
@@ -168,6 +234,24 @@ void relinquish_memory(struct domain *d,
NOT_YET();
}

+void trace_domheap_pages(const char *caption, struct domain *d, struct list_head *list)
+{
+ struct list_head *ent;
+ struct page_info *page;
+
+ /* Use a recursive lock, as we may enter 'free_domheap_page'. */
+ spin_lock_recursive(&d->page_alloc_lock);
+
+ ent = list->next;
+ while ( ent != list )
+ {
+ page = list_entry(ent, struct page_info, list);
+ ent = ent->next;
+ }
+
+ spin_unlock_recursive(&d->page_alloc_lock);
+}
+
int domain_relinquish_resources(struct domain *d)
{
NOT_YET();
@@ -177,7 +261,16 @@ int domain_relinquish_resources(struct d

void startup_cpu_idle_loop(void)
{
- NOT_YET();
+ while(1) {
+ if (cpu_is_haltable(smp_processor_id())) {
+ local_irq_disable();
+ cpu_idle();
+ local_irq_enable();
+ }
+
+ do_tasklet();
+ do_softirq();
+ }
}

long arch_do_vcpu_op(int cmd, struct vcpu *v, XEN_GUEST_HANDLE(void) arg)
@@ -189,22 +282,33 @@ long arch_do_vcpu_op(int cmd, struct vcp

void vcpu_kick(struct vcpu *v)
{
- NOT_YET();
+ bool_t running = v->is_running;
+
+ vcpu_unblock(v);
+
+ if (running && (in_irq() || (v != current))) {
+ cpu_raise_softirq(v->processor, VCPU_KICK_SOFTIRQ);
+ }
}

void vcpu_mark_events_pending(struct vcpu *v)
{
- NOT_YET();
+ int already = test_and_set_bit(0, (unsigned long *)&vcpu_info(v, evtchn_upcall_pending));
+
+ if (already) {
+ return;
+ }
+
+ vcpu_kick(v);
}

static void vcpu_kick_softirq(void)
{
- NOT_YET();
}

static int __init vcpu_kick_softirq_init(void)
{
- NOT_YET();
+ open_softirq(VCPU_KICK_SOFTIRQ, vcpu_kick_softirq);

return 0;
}
diff -r 08f39a9da04f xen/arch/arm/xen/armv7.S
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/arm/xen/armv7.S Sun Feb 12 11:46:32 2012 +0900
@@ -0,0 +1,19 @@
+#include <asm/page.h>
+#include <asm/cpu-ops.h>
+#include <asm/system.h>
+#include <asm/asm-macros.h>
+#include <asm/asm-offsets.h>
+#include <public/arch-arm.h>
+
+ .text
+ENTRY(cpu_idle)
+ dsb
+ wfi
+ mov pc, lr
+
+ENTRY(cpu_halt)
+ mov pc, lr
+
+ENTRY(cpu_reset)
+ mov pc, lr
+
diff -r 08f39a9da04f xen/arch/arm/xen/domain_build.c
--- a/xen/arch/arm/xen/domain_build.c Mon Feb 06 11:17:01 2012 +0900
+++ b/xen/arch/arm/xen/domain_build.c Sun Feb 12 11:46:32 2012 +0900
@@ -33,6 +33,67 @@
#include <public/xen.h>
#include <public/version.h>

+extern void return_to_guest();
+
+void vcpu_context_init(struct vcpu *v, unsigned long stk, unsigned long pc, struct start_info *si)
+{
+ void *stack;
+ struct cpu_info *ci;
+ struct cpu_ctx *cpu_ctx;
+
+ stack = alloc_xenheap_pages(STACK_ORDER, 0);
+ if(stack == NULL) {
+ return;
+ }
+
+ ci = (struct cpu_info *)stack;
+ ci->vcpu = v;
+ ci->vsp = 0;
+ ci->vspsr = PSR_MODE_SVC;
+ ci->vdacr = DACR_STAT_SVC;
+
+ stack += (STACK_SIZE - sizeof(struct cpu_ctx));
+
+ cpu_ctx = (struct cpu_ctx *)stack;
+ cpu_ctx->r0 = 0;
+ cpu_ctx->r12 = (unsigned long)si;
+ cpu_ctx->usp = stk;
+ cpu_ctx->ulr = 0;
+ cpu_ctx->ssp = (unsigned long)(stack + sizeof(struct cpu_ctx));
+ cpu_ctx->pc = pc;
+ cpu_ctx->spsr = 0x10;
+
+ VCPU_REG(v, r13) = (unsigned long)stack;
+ VCPU_REG(v, r14) = (unsigned long)return_to_guest;
+
+ VCPU_REG(v, dacr) = DACR_STAT_SVC;
+ VCPU_REG(v, fcseidr) = 0;
+ VCPU_REG(v, contextidr) = 0;
+ VCPU_REG(v, cpar) = (0x40) | (1 << 13);
+}
+
+#define DOM_PFN_ALIGN (SECTION_SIZE >> PAGE_SHIFT)
+
+static unsigned long alloc_domain_pages(struct domain *d, unsigned int size)
+{
+ unsigned phys;
+ unsigned long pages = size >> PAGE_SHIFT;
+
+ d->max_pages = ~(0x0UL);
+
+ phys = alloc_boot_pages(pages, DOM_PFN_ALIGN);
+
+ if (!phys) {
+ d->tot_pages = 0;
+ return 0;
+ }
+
+ d->tot_pages = pages;
+
+ /* Set Page Owner */
+ return phys <<= PAGE_SHIFT;
+}
+
/*
* domain_construct() should be always invoked in idle domain
*/
@@ -40,8 +101,132 @@ int domain_construct(struct domain *d,
unsigned long img_start, unsigned long img_len,
unsigned long dom_size, unsigned int vcpus)
{
- NOT_YET();
+ int i, rc;
+ struct vcpu *v;
+ struct elf_binary elf;
+ struct elf_dom_parms parms;
+ struct start_info *si;
+ unsigned long vstart, vend, ventry;
+ unsigned long pstart, pend, pmap, len;

- return -EINVAL;
+ l1e_t *gpt;
+
+ BUG_ON(d == NULL);
+ BUG_ON(dom_size & ~SECTION_MASK);
+
+ pstart = alloc_domain_pages(d, dom_size);
+ if (!pstart) {
+ return -ENOMEM;
+ }
+
+ memcpy((pstart + dom_size - img_len), img_start, img_len);
+ img_start = pstart + dom_size - img_len;
+
+ if ((rc = elf_init(&elf, img_start, img_len)) != 0) {
+ return rc;
+ }
+
+ elf_parse_binary(&elf);
+
+ if ((rc = elf_xen_parse(&elf, &parms)) != 0) {
+ return rc;
+ }
+
+ d->vcpu = xmalloc_array(struct vcpu *, MAX_VIRT_CPUS);
+ if (!d->vcpu) {
+ return -ENOMEM;
+ }
+
+ memset(d->vcpu, 0, MAX_VIRT_CPUS * sizeof(*d->vcpu));
+ d->max_vcpus = MAX_VIRT_CPUS;
+
+ for (i = 0; i < MAX_VIRT_CPUS; i++) {
+ d->shared_info->vcpu_info[i].evtchn_upcall_mask = 1;
+ d->shared_info->vcpu_info[i].arch.cpsr = (VPSR_I_BIT | VPSR_F_BIT | VPSR_MODE_SVC);
+ }
+
+ for (i = 0; i < vcpus; i++) {
+ if (alloc_vcpu(d, i, i) == NULL) {
+ return -ENOMEM;
+ }
+ }
+
+ vstart = parms.virt_kstart & SECTION_MASK;
+ vend = round_up(parms.virt_kend, L1_TABLE_SIZE);
+ ventry = parms.virt_entry;
+
+ len = vend - vstart;
+
+ /* Guest page table is located in the end of vend */
+ gpt = (l1e_t *)(pstart + len);
+
+ /* Duplicate L1 page table */
+ memcpy(gpt, xen_translation_table, L1_TABLE_SIZE);
+
+ pmap = pstart;
+ pend = pmap + dom_size;
+
+
+ gpt = l1_linear_offset(gpt, vstart);
+
+ /* Create 1:1 mapping */
+ do {
+ *gpt = MK_L1E(pmap, L1E_TYPE_GUEST);
+ pmap += SECTION_SIZE;
+ } while(gpt++, pmap < pend);
+
+ /* Activate guest address space to relocate guest image */
+ mmu_switch_ttb(gpt & ~(0x4000 - 1));
+
+ elf.dest = (void *)ventry;
+ elf_load_binary(&elf);
+
+ si = (struct start_info *)(vend + L1_TABLE_SIZE);
+ memset(si, 0, PAGE_SIZE);
+
+
+ si->nr_pages = d->tot_pages;
+ si->shared_info = virt_to_maddr(d->shared_info);
+ si->pt_base = vend;
+ si->nr_pt_frames = 4;
+ si->mfn_list = 0;
+ si->first_p2m_pfn = pstart >> PAGE_SHIFT;
+ si->flags = 0;
+ si->min_mfn = pstart >> PAGE_SHIFT;
+
+ if (d->domain_id == 0) {
+ si->flags = SIF_PRIVILEGED | SIF_INITDOMAIN;
+ }
+
+ v = d->vcpu[0];
+
+ VCPU_REG(v, ttbr0) = (unsigned long)gpt;
+
+ mmu_switch_ttb(VCPU_REG(idle_vcpu[0], ttbr0));
+
+ vcpu_context_init(v, 0, ventry, si);
+
+ v->is_initialised = 1;
+ clear_bit(_VPF_down, &v->pause_flags);
+
+ rc = 0;
+
+ /* DOM0 is permitted full I/O capabilities. */
+ rc |= ioports_permit_access(dom0, 0, 0xFFFF);
+ rc |= iomem_permit_access(dom0, 0UL, ~0UL);
+ rc |= irqs_permit_access(dom0, 0, d->nr_pirqs - 1);
+
+ return rc;
}

+int elf_sanity_check(const Elf_Ehdr *ehdr)
+{
+ if ( !IS_ELF(*ehdr) ||
+ (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) ||
+ (ehdr->e_type != ET_EXEC) ) {
+ printk("DOM0 image is not a Xen-compatible Elf image.\n");
+ return 0;
+ }
+
+ return 1;
+}
diff -r 08f39a9da04f xen/arch/arm/xen/mm.c
--- a/xen/arch/arm/xen/mm.c Mon Feb 06 11:17:01 2012 +0900
+++ b/xen/arch/arm/xen/mm.c Sun Feb 12 11:46:32 2012 +0900
@@ -217,8 +217,6 @@ unsigned long alloc_page_tables(l1e_t *l
return 0;
}

-// cache_clean_range(page, page + PAGE_SIZE, 0);
-
wire_page_tables(l1e, page);

return page;
diff -r 08f39a9da04f xen/include/asm-arm/current.h
--- a/xen/include/asm-arm/current.h Mon Feb 06 11:17:01 2012 +0900
+++ b/xen/include/asm-arm/current.h Sun Feb 12 11:46:32 2012 +0900
@@ -27,6 +27,29 @@
#ifndef __ASSEMBLY__
struct vcpu;

+struct cpu_ctx {
+ unsigned long r0;
+ unsigned long r1;
+ unsigned long r2;
+ unsigned long r3;
+ unsigned long r4;
+ unsigned long r5;
+ unsigned long r6;
+ unsigned long r7;
+ unsigned long r8;
+ unsigned long r9;
+ unsigned long r10;
+ unsigned long r11;
+ unsigned long r12;
+ unsigned long usp;
+ unsigned long ulr;
+ unsigned long ssp;
+ unsigned long slr;
+ unsigned long pc;
+ unsigned long spsr;
+};
+
+
struct cpu_info {
struct vcpu *vcpu;
unsigned long vspsr;
diff -r 08f39a9da04f xen/include/asm-arm/domain.h
--- a/xen/include/asm-arm/domain.h Mon Feb 06 11:17:01 2012 +0900
+++ b/xen/include/asm-arm/domain.h Sun Feb 12 11:46:32 2012 +0900
@@ -8,42 +8,8 @@
#include <asm/iommu.h>
#include <public/arch-arm.h>

-#if 0
-#define MAPHASH_ENTRIES 8
-#define MAPHASH_HASHFN(pfn) ((pfn) & (MAPHASH_ENTRIES-1))
-#define MAPHASHENT_NOTINUSE ((u16)~0U)
-
-struct vcpu_maphash {
- struct vcpu_maphash_entry {
- unsigned long pfn;
- uint16_t idx;
- uint16_t refcnt;
- } hash[MAPHASH_ENTRIES];
-}__cacheline_aligned;
-
-
-#define MAPCACHE_ORDER 8
-#define MAPCACHE_ENTRIES (1 << MAPCACHE_ORDER)
-
-struct mapcache {
- /* The PTEs that provide the mappings, and a cursor into the array. */
- l2e_t *table;
- unsigned int cursor;
-
- /* Protects map_domain_page(). */
- spinlock_t lock;
-
- /* Which mappings are in use, and which are garbage to reap next epoch? */
- unsigned long inuse[BITS_TO_LONGS(MAPCACHE_ENTRIES)];
- unsigned long garbage[BITS_TO_LONGS(MAPCACHE_ENTRIES)];
-
- /* Lock-free per-VCPU hash of recently-used mappings. */
- struct vcpu_maphash vcpu_maphash[MAX_VIRT_CPUS];
-}__cacheline_aligned;
-#endif
struct arch_domain
{
-#if 0
/* I/O-port admin-specified access capabilities. */
struct rangeset *ioport_caps;

@@ -51,8 +17,7 @@ struct arch_domain
int *pirq_irq;

unsigned long *pirq_eoi_map;
- unsigned long pirq_eoi_map_mfn;
-#endif
+
struct page_list_head relmem_list;
};

@@ -61,7 +26,7 @@ struct arch_vcpu
struct vcpu_guest_context ctx;
} __cacheline_aligned;

-//#define VCPU_REG(v, reg) v->arch.ctx.reg
+#define VCPU_REG(v, reg) v->arch.ctx.reg

#define return_reg(v) ((v)->arch.ctx.r0)