Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 123986
b: refs/heads/master
c: 58a2456
h: refs/heads/master
v: v3
  • Loading branch information
Matias Zabaljauregui authored and Rusty Russell committed Dec 29, 2008
1 parent cb1c63d commit 65e7b0e
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 82 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: be3c5832d51174ef7f21cefd6ad612dabdcb62fd
refs/heads/master: 58a24566449892dda409b9ad92c2e56c76c5670c
60 changes: 6 additions & 54 deletions trunk/Documentation/lguest/lguest.c
Original file line number Diff line number Diff line change
Expand Up @@ -481,51 +481,6 @@ static unsigned long load_initrd(const char *name, unsigned long mem)
/* We return the initrd size. */
return len;
}

/* Once we know how much memory we have we can construct simple linear page
* tables which set virtual == physical which will get the Guest far enough
* into the boot to create its own.
*
* We lay them out of the way, just below the initrd (which is why we need to
* know its size here). */
static unsigned long setup_pagetables(unsigned long mem,
unsigned long initrd_size)
{
unsigned long *pgdir, *linear;
unsigned int mapped_pages, i, linear_pages;
unsigned int ptes_per_page = getpagesize()/sizeof(void *);

mapped_pages = mem/getpagesize();

/* Each PTE page can map ptes_per_page pages: how many do we need? */
linear_pages = (mapped_pages + ptes_per_page-1)/ptes_per_page;

/* We put the toplevel page directory page at the top of memory. */
pgdir = from_guest_phys(mem) - initrd_size - getpagesize();

/* Now we use the next linear_pages pages as pte pages */
linear = (void *)pgdir - linear_pages*getpagesize();

/* Linear mapping is easy: put every page's address into the mapping in
* order. PAGE_PRESENT contains the flags Present, Writable and
* Executable. */
for (i = 0; i < mapped_pages; i++)
linear[i] = ((i * getpagesize()) | PAGE_PRESENT);

/* The top level points to the linear page table pages above. */
for (i = 0; i < mapped_pages; i += ptes_per_page) {
pgdir[i/ptes_per_page]
= ((to_guest_phys(linear) + i*sizeof(void *))
| PAGE_PRESENT);
}

verbose("Linear mapping of %u pages in %u pte pages at %#lx\n",
mapped_pages, linear_pages, to_guest_phys(linear));

/* We return the top level (guest-physical) address: the kernel needs
* to know where it is. */
return to_guest_phys(pgdir);
}
/*:*/

/* Simple routine to roll all the commandline arguments together with spaces
Expand All @@ -548,13 +503,13 @@ static void concat(char *dst, char *args[])

/*L:185 This is where we actually tell the kernel to initialize the Guest. We
* saw the arguments it expects when we looked at initialize() in lguest_user.c:
* the base of Guest "physical" memory, the top physical page to allow, the
* top level pagetable and the entry point for the Guest. */
static int tell_kernel(unsigned long pgdir, unsigned long start)
* the base of Guest "physical" memory, the top physical page to allow and the
* entry point for the Guest. */
static int tell_kernel(unsigned long start)
{
unsigned long args[] = { LHREQ_INITIALIZE,
(unsigned long)guest_base,
guest_limit / getpagesize(), pgdir, start };
guest_limit / getpagesize(), start };
int fd;

verbose("Guest: %p - %p (%#lx)\n",
Expand Down Expand Up @@ -1941,7 +1896,7 @@ int main(int argc, char *argv[])
{
/* Memory, top-level pagetable, code startpoint and size of the
* (optional) initrd. */
unsigned long mem = 0, pgdir, start, initrd_size = 0;
unsigned long mem = 0, start, initrd_size = 0;
/* Two temporaries and the /dev/lguest file descriptor. */
int i, c, lguest_fd;
/* The boot information for the Guest. */
Expand Down Expand Up @@ -2040,9 +1995,6 @@ int main(int argc, char *argv[])
boot->hdr.type_of_loader = 0xFF;
}

/* Set up the initial linear pagetables, starting below the initrd. */
pgdir = setup_pagetables(mem, initrd_size);

/* The Linux boot header contains an "E820" memory map: ours is a
* simple, single region. */
boot->e820_entries = 1;
Expand All @@ -2064,7 +2016,7 @@ int main(int argc, char *argv[])

/* We tell the kernel to initialize the Guest: this returns the open
* /dev/lguest file descriptor. */
lguest_fd = tell_kernel(pgdir, start);
lguest_fd = tell_kernel(start);

/* We clone off a thread, which wakes the Launcher whenever one of the
* input file descriptors needs attention. We call this the Waker, and
Expand Down
15 changes: 0 additions & 15 deletions trunk/arch/x86/lguest/i386_head.S
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,6 @@ ENTRY(lguest_entry)
movl $lguest_data - __PAGE_OFFSET, %edx
int $LGUEST_TRAP_ENTRY

/* The Host put the toplevel pagetable in lguest_data.pgdir. The movsl
* instruction uses %esi implicitly as the source for the copy we're
* about to do. */
movl lguest_data - __PAGE_OFFSET + LGUEST_DATA_pgdir, %esi

/* Copy first 32 entries of page directory to __PAGE_OFFSET entries.
* This means the first 128M of kernel memory will be mapped at
* PAGE_OFFSET where the kernel expects to run. This will get it far
* enough through boot to switch to its own pagetables. */
movl $32, %ecx
movl %esi, %edi
addl $((__PAGE_OFFSET >> 22) * 4), %edi
rep
movsl

/* Set up the initial stack so we can run C code. */
movl $(init_thread_union+THREAD_SIZE),%esp

Expand Down
2 changes: 1 addition & 1 deletion trunk/drivers/lguest/lg.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt);
void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt);

/* page_tables.c: */
int init_guest_pagetable(struct lguest *lg, unsigned long pgtable);
int init_guest_pagetable(struct lguest *lg);
void free_guest_pagetable(struct lguest *lg);
void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable);
void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i);
Expand Down
13 changes: 5 additions & 8 deletions trunk/drivers/lguest/lguest_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
return 0;
}

/*L:020 The initialization write supplies 4 pointer sized (32 or 64 bit)
/*L:020 The initialization write supplies 3 pointer sized (32 or 64 bit)
* values (in addition to the LHREQ_INITIALIZE value). These are:
*
* base: The start of the Guest-physical memory inside the Launcher memory.
Expand All @@ -155,9 +155,6 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
* allowed to access. The Guest memory lives inside the Launcher, so it sets
* this to ensure the Guest can only reach its own memory.
*
* pgdir: The (Guest-physical) address of the top of the initial Guest
* pagetables (which are set up by the Launcher).
*
* start: The first instruction to execute ("eip" in x86-speak).
*/
static int initialize(struct file *file, const unsigned long __user *input)
Expand All @@ -166,7 +163,7 @@ static int initialize(struct file *file, const unsigned long __user *input)
* Guest. */
struct lguest *lg;
int err;
unsigned long args[4];
unsigned long args[3];

/* We grab the Big Lguest lock, which protects against multiple
* simultaneous initializations. */
Expand All @@ -192,14 +189,14 @@ static int initialize(struct file *file, const unsigned long __user *input)
lg->mem_base = (void __user *)args[0];
lg->pfn_limit = args[1];

/* This is the first cpu (cpu 0) and it will start booting at args[3] */
err = lg_cpu_start(&lg->cpus[0], 0, args[3]);
/* This is the first cpu (cpu 0) and it will start booting at args[2] */
err = lg_cpu_start(&lg->cpus[0], 0, args[2]);
if (err)
goto release_guest;

/* Initialize the Guest's shadow page tables, using the toplevel
* address the Launcher gave us. This allocates memory, so can fail. */
err = init_guest_pagetable(lg, args[2]);
err = init_guest_pagetable(lg);
if (err)
goto free_regs;

Expand Down
72 changes: 70 additions & 2 deletions trunk/drivers/lguest/page_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/percpu.h>
#include <asm/tlbflush.h>
#include <asm/uaccess.h>
#include <asm/bootparam.h>
#include "lg.h"

/*M:008 We hold reference to pages, which prevents them from being swapped.
Expand Down Expand Up @@ -581,15 +582,82 @@ void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 idx)
release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx);
}

/* Once we know how much memory we have we can construct simple identity
* (which set virtual == physical) and linear mappings
* which will get the Guest far enough into the boot to create its own.
*
* We lay them out of the way, just below the initrd (which is why we need to
* know its size here). */
static unsigned long setup_pagetables(struct lguest *lg,
unsigned long mem,
unsigned long initrd_size)
{
pgd_t __user *pgdir;
pte_t __user *linear;
unsigned int mapped_pages, i, linear_pages, phys_linear;
unsigned long mem_base = (unsigned long)lg->mem_base;

/* We have mapped_pages frames to map, so we need
* linear_pages page tables to map them. */
mapped_pages = mem / PAGE_SIZE;
linear_pages = (mapped_pages + PTRS_PER_PTE - 1) / PTRS_PER_PTE;

/* We put the toplevel page directory page at the top of memory. */
pgdir = (pgd_t *)(mem + mem_base - initrd_size - PAGE_SIZE);

/* Now we use the next linear_pages pages as pte pages */
linear = (void *)pgdir - linear_pages * PAGE_SIZE;

/* Linear mapping is easy: put every page's address into the
* mapping in order. */
for (i = 0; i < mapped_pages; i++) {
pte_t pte;
pte = pfn_pte(i, __pgprot(_PAGE_PRESENT|_PAGE_RW|_PAGE_USER));
if (copy_to_user(&linear[i], &pte, sizeof(pte)) != 0)
return -EFAULT;
}

/* The top level points to the linear page table pages above.
* We setup the identity and linear mappings here. */
phys_linear = (unsigned long)linear - mem_base;
for (i = 0; i < mapped_pages; i += PTRS_PER_PTE) {
pgd_t pgd;
pgd = __pgd((phys_linear + i * sizeof(pte_t)) |
(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER));

if (copy_to_user(&pgdir[i / PTRS_PER_PTE], &pgd, sizeof(pgd))
|| copy_to_user(&pgdir[pgd_index(PAGE_OFFSET)
+ i / PTRS_PER_PTE],
&pgd, sizeof(pgd)))
return -EFAULT;
}

/* We return the top level (guest-physical) address: remember where
* this is. */
return (unsigned long)pgdir - mem_base;
}

/*H:500 (vii) Setting up the page tables initially.
*
* When a Guest is first created, the Launcher tells us where the toplevel of
* its first page table is. We set some things up here: */
int init_guest_pagetable(struct lguest *lg, unsigned long pgtable)
int init_guest_pagetable(struct lguest *lg)
{
u64 mem;
u32 initrd_size;
struct boot_params __user *boot = (struct boot_params *)lg->mem_base;

/* Get the Guest memory size and the ramdisk size from the boot header
* located at lg->mem_base (Guest address 0). */
if (copy_from_user(&mem, &boot->e820_map[0].size, sizeof(mem))
|| get_user(initrd_size, &boot->hdr.ramdisk_size))
return -EFAULT;

/* We start on the first shadow page table, and give it a blank PGD
* page. */
lg->pgdirs[0].gpgdir = pgtable;
lg->pgdirs[0].gpgdir = setup_pagetables(lg, mem, initrd_size);
if (IS_ERR_VALUE(lg->pgdirs[0].gpgdir))
return lg->pgdirs[0].gpgdir;
lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL);
if (!lg->pgdirs[0].pgdir)
return -ENOMEM;
Expand Down
2 changes: 1 addition & 1 deletion trunk/include/linux/lguest_launcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ struct lguest_vqconfig {
/* Write command first word is a request. */
enum lguest_req
{
LHREQ_INITIALIZE, /* + base, pfnlimit, pgdir, start */
LHREQ_INITIALIZE, /* + base, pfnlimit, start */
LHREQ_GETDMA, /* No longer used */
LHREQ_IRQ, /* + irq */
LHREQ_BREAK, /* + on/off flag (on blocks until someone does off) */
Expand Down

0 comments on commit 65e7b0e

Please sign in to comment.