From: Jan Kiszka Date: Thu, 17 Jul 2014 15:18:21 +0000 (+0200) Subject: inmates: Add memory services to inmates framework X-Git-Url: https://rtime.felk.cvut.cz/gitweb/jailhouse.git/commitdiff_plain/994d207f669f6159cb18b0f3e98b2e886f86b1b0 inmates: Add memory services to inmates framework This adds a primitive memory allocator (without release) and a page mapper (without unmap) to the inmates library. MMIO accessors are also included. Those used for intercepted resources are encoded in assembly to ensure that only supported instructions are used. With these services, inmates can now access memory-mapped devices. The allocator uses the lower memory starting from the first page. Document this as well as the remaining memory layout. Signed-off-by: Jan Kiszka --- diff --git a/inmates/lib/x86/inmate.h b/inmates/lib/x86/inmate.h index 38c5151..ff707f5 100644 --- a/inmates/lib/x86/inmate.h +++ b/inmates/lib/x86/inmate.h @@ -10,6 +10,7 @@ * the COPYING file in the top-level directory. */ +#define HEAP_BASE 0x000000 #define FSEGMENT_BASE 0x0f0000 #define COMM_REGION_BASE 0x100000 @@ -20,6 +21,15 @@ #define NS_PER_MSEC 1000000UL #define NS_PER_SEC 1000000000UL +#define PAGE_SIZE (4 * 1024ULL) +#ifdef __x86_64__ +#define HUGE_PAGE_SIZE (2 * 1024 * 1024ULL) +#else +#define HUGE_PAGE_SIZE (4 * 1024 * 1024ULL) +#endif +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define HUGE_PAGE_MASK (~(HUGE_PAGE_SIZE - 1)) + #define X2APIC_ID 0x802 #ifndef __ASSEMBLY__ @@ -73,6 +83,51 @@ static inline u32 inl(u16 port) return v; } +static inline u8 mmio_read8(void *address) +{ + return *(volatile u8 *)address; +} + +static inline u16 mmio_read16(void *address) +{ + return *(volatile u16 *)address; +} + +static inline u32 mmio_read32(void *address) +{ + u32 value; + + /* assembly-encoded to match the hypervisor MMIO parser support */ + asm volatile("movl (%1),%0" : "=r" (value) : "r" (address)); + return value; +} + +static inline u64 mmio_read64(void *address) +{ + return *(volatile u64 *)address; +} + +static inline void mmio_write8(void *address, u8 value) +{ + *(volatile u8 *)address = value; +} + +static inline void mmio_write16(void *address, u16 value) +{ + *(volatile u16 *)address = value; +} + +static inline void mmio_write32(void *address, u32 value) +{ + /* assembly-encoded to match the hypervisor MMIO parser support */ + asm volatile("movl %0,(%1)" : : "r" (value), "r" (address)); +} + +static inline void mmio_write64(void *address, u64 value) +{ + *(volatile u64 *)address = value; +} + static inline u64 read_msr(unsigned int msr) { u32 low, high; @@ -113,4 +168,9 @@ void inmate_main(void); unsigned long pm_timer_read(void); unsigned long apic_timer_init(unsigned int vector); void apic_timer_set(unsigned long timeout_ns); + +enum map_type { MAP_CACHED, MAP_UNCACHED }; + +void *alloc(unsigned long size, unsigned long align); +void map_range(void *start, unsigned long size, enum map_type map_type); #endif diff --git a/inmates/lib/x86/inmate.lds b/inmates/lib/x86/inmate.lds index 84d782d..afd9375 100644 --- a/inmates/lib/x86/inmate.lds +++ b/inmates/lib/x86/inmate.lds @@ -10,6 +10,15 @@ * the COPYING file in the top-level directory. */ +/* + * Layout: + * 0x000000.. : heap (not configured here) + * ..0x0e0000: stack + * 0x0e0000..0x0effff: bss + * 0x0f0000..0x0fffef: startup code, text, rodata, data + * 0x0ffff0..0x0fffff: startup code (boot address) + * 0x100000..0x100fff: communication region (not configured here) + */ SECTIONS { /* 16-bit sections */ diff --git a/inmates/lib/x86/mem.c b/inmates/lib/x86/mem.c new file mode 100644 index 0000000..79d49cc --- /dev/null +++ b/inmates/lib/x86/mem.c @@ -0,0 +1,70 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include + +#define PG_PRESENT 0x01 +#define PG_RW 0x02 +#define PG_PS 0x80 +#define PG_PCD 0x10 + +static unsigned long heap_pos = HEAP_BASE; + +void *alloc(unsigned long size, unsigned long align) +{ + unsigned long base = (heap_pos + align - 1) & ~(align - 1); + + heap_pos = base + size; + return (void *)base; +} + +void map_range(void *start, unsigned long size, enum map_type map_type) +{ + unsigned long pt_addr, *pt_entry, *pt; + unsigned long vaddr = (unsigned long)start; + + asm volatile("mov %%cr3,%0" : "=r" (pt_addr)); + + size += HUGE_PAGE_SIZE - 1; + size &= HUGE_PAGE_MASK; + while (size > 0) { +#ifdef __x86_64__ + pt_addr &= PAGE_MASK; + pt = (unsigned long *)pt_addr; + + pt_entry = &pt[(vaddr >> 39) & 0x1ff]; + if (*pt_entry & PG_PRESENT) { + pt = (unsigned long *)(*pt_entry & PAGE_MASK); + } else { + pt = alloc(PAGE_SIZE, PAGE_SIZE); + *pt_entry = (unsigned long)pt | PG_RW | PG_PRESENT; + } + + pt_entry = &pt[(vaddr >> 30) & 0x1ff]; + if (*pt_entry & PG_PRESENT) { + pt = (unsigned long *)(*pt_entry & PAGE_MASK); + } else { + pt = alloc(PAGE_SIZE, PAGE_SIZE); + *pt_entry = (unsigned long)pt | PG_RW | PG_PRESENT; + } + + pt_entry = &pt[(vaddr >> 21) & 0x1ff]; + *pt_entry = (vaddr & HUGE_PAGE_MASK) | + (map_type == MAP_UNCACHED ? PG_PCD : 0) | + PG_PS | PG_RW | PG_PRESENT; +#else +#error not yet implemented +#endif + size -= HUGE_PAGE_SIZE; + vaddr += HUGE_PAGE_SIZE; + } +}