diff options
author | Len Brown <len.brown@intel.com> | 2009-01-09 03:39:43 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-01-09 03:39:43 -0500 |
commit | b2576e1d4408e134e2188c967b1f28af39cd79d4 (patch) | |
tree | 004f3c82faab760f304ce031d6d2f572e7746a50 /drivers/lguest | |
parent | 3cc8a5f4ba91f67bbdb81a43a99281a26aab8d77 (diff) | |
parent | 2150edc6c5cf00f7adb54538b9ea2a3e9cedca3f (diff) |
Merge branch 'linus' into release
Diffstat (limited to 'drivers/lguest')
-rw-r--r-- | drivers/lguest/interrupts_and_traps.c | 13 | ||||
-rw-r--r-- | drivers/lguest/lg.h | 2 | ||||
-rw-r--r-- | drivers/lguest/lguest_device.c | 18 | ||||
-rw-r--r-- | drivers/lguest/lguest_user.c | 13 | ||||
-rw-r--r-- | drivers/lguest/page_tables.c | 72 |
5 files changed, 93 insertions, 25 deletions
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index a1039068f95c..415fab0125ac 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c | |||
@@ -222,11 +222,16 @@ bool check_syscall_vector(struct lguest *lg) | |||
222 | int init_interrupts(void) | 222 | int init_interrupts(void) |
223 | { | 223 | { |
224 | /* If they want some strange system call vector, reserve it now */ | 224 | /* If they want some strange system call vector, reserve it now */ |
225 | if (syscall_vector != SYSCALL_VECTOR | 225 | if (syscall_vector != SYSCALL_VECTOR) { |
226 | && test_and_set_bit(syscall_vector, used_vectors)) { | 226 | if (test_bit(syscall_vector, used_vectors) || |
227 | printk("lg: couldn't reserve syscall %u\n", syscall_vector); | 227 | vector_used_by_percpu_irq(syscall_vector)) { |
228 | return -EBUSY; | 228 | printk(KERN_ERR "lg: couldn't reserve syscall %u\n", |
229 | syscall_vector); | ||
230 | return -EBUSY; | ||
231 | } | ||
232 | set_bit(syscall_vector, used_vectors); | ||
229 | } | 233 | } |
234 | |||
230 | return 0; | 235 | return 0; |
231 | } | 236 | } |
232 | 237 | ||
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index 5faefeaf6790..f2c641e0bdde 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h | |||
@@ -164,7 +164,7 @@ void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt); | |||
164 | void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt); | 164 | void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt); |
165 | 165 | ||
166 | /* page_tables.c: */ | 166 | /* page_tables.c: */ |
167 | int init_guest_pagetable(struct lguest *lg, unsigned long pgtable); | 167 | int init_guest_pagetable(struct lguest *lg); |
168 | void free_guest_pagetable(struct lguest *lg); | 168 | void free_guest_pagetable(struct lguest *lg); |
169 | void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable); | 169 | void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable); |
170 | void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i); | 170 | void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i); |
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index a661bbdae3d6..b4d44e571d76 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c | |||
@@ -250,7 +250,7 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev, | |||
250 | /* Figure out how many pages the ring will take, and map that memory */ | 250 | /* Figure out how many pages the ring will take, and map that memory */ |
251 | lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT, | 251 | lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT, |
252 | DIV_ROUND_UP(vring_size(lvq->config.num, | 252 | DIV_ROUND_UP(vring_size(lvq->config.num, |
253 | PAGE_SIZE), | 253 | LGUEST_VRING_ALIGN), |
254 | PAGE_SIZE)); | 254 | PAGE_SIZE)); |
255 | if (!lvq->pages) { | 255 | if (!lvq->pages) { |
256 | err = -ENOMEM; | 256 | err = -ENOMEM; |
@@ -259,8 +259,8 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev, | |||
259 | 259 | ||
260 | /* OK, tell virtio_ring.c to set up a virtqueue now we know its size | 260 | /* OK, tell virtio_ring.c to set up a virtqueue now we know its size |
261 | * and we've got a pointer to its pages. */ | 261 | * and we've got a pointer to its pages. */ |
262 | vq = vring_new_virtqueue(lvq->config.num, vdev, lvq->pages, | 262 | vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN, |
263 | lg_notify, callback); | 263 | vdev, lvq->pages, lg_notify, callback); |
264 | if (!vq) { | 264 | if (!vq) { |
265 | err = -ENOMEM; | 265 | err = -ENOMEM; |
266 | goto unmap; | 266 | goto unmap; |
@@ -272,7 +272,7 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev, | |||
272 | * the interrupt as a source of randomness: it'd be nice to have that | 272 | * the interrupt as a source of randomness: it'd be nice to have that |
273 | * back.. */ | 273 | * back.. */ |
274 | err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED, | 274 | err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED, |
275 | vdev->dev.bus_id, vq); | 275 | dev_name(&vdev->dev), vq); |
276 | if (err) | 276 | if (err) |
277 | goto destroy_vring; | 277 | goto destroy_vring; |
278 | 278 | ||
@@ -321,10 +321,7 @@ static struct virtio_config_ops lguest_config_ops = { | |||
321 | 321 | ||
322 | /* The root device for the lguest virtio devices. This makes them appear as | 322 | /* The root device for the lguest virtio devices. This makes them appear as |
323 | * /sys/devices/lguest/0,1,2 not /sys/devices/0,1,2. */ | 323 | * /sys/devices/lguest/0,1,2 not /sys/devices/0,1,2. */ |
324 | static struct device lguest_root = { | 324 | static struct device *lguest_root; |
325 | .parent = NULL, | ||
326 | .bus_id = "lguest", | ||
327 | }; | ||
328 | 325 | ||
329 | /*D:120 This is the core of the lguest bus: actually adding a new device. | 326 | /*D:120 This is the core of the lguest bus: actually adding a new device. |
330 | * It's a separate function because it's neater that way, and because an | 327 | * It's a separate function because it's neater that way, and because an |
@@ -351,7 +348,7 @@ static void add_lguest_device(struct lguest_device_desc *d, | |||
351 | } | 348 | } |
352 | 349 | ||
353 | /* This devices' parent is the lguest/ dir. */ | 350 | /* This devices' parent is the lguest/ dir. */ |
354 | ldev->vdev.dev.parent = &lguest_root; | 351 | ldev->vdev.dev.parent = lguest_root; |
355 | /* We have a unique device index thanks to the dev_index counter. */ | 352 | /* We have a unique device index thanks to the dev_index counter. */ |
356 | ldev->vdev.id.device = d->type; | 353 | ldev->vdev.id.device = d->type; |
357 | /* We have a simple set of routines for querying the device's | 354 | /* We have a simple set of routines for querying the device's |
@@ -407,7 +404,8 @@ static int __init lguest_devices_init(void) | |||
407 | if (strcmp(pv_info.name, "lguest") != 0) | 404 | if (strcmp(pv_info.name, "lguest") != 0) |
408 | return 0; | 405 | return 0; |
409 | 406 | ||
410 | if (device_register(&lguest_root) != 0) | 407 | lguest_root = root_device_register("lguest"); |
408 | if (IS_ERR(lguest_root)) | ||
411 | panic("Could not register lguest root"); | 409 | panic("Could not register lguest root"); |
412 | 410 | ||
413 | /* Devices are in a single page above top of "normal" mem */ | 411 | /* Devices are in a single page above top of "normal" mem */ |
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index e73a000473cc..34bc017b8b3c 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c | |||
@@ -146,7 +146,7 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip) | |||
146 | return 0; | 146 | return 0; |
147 | } | 147 | } |
148 | 148 | ||
149 | /*L:020 The initialization write supplies 4 pointer sized (32 or 64 bit) | 149 | /*L:020 The initialization write supplies 3 pointer sized (32 or 64 bit) |
150 | * values (in addition to the LHREQ_INITIALIZE value). These are: | 150 | * values (in addition to the LHREQ_INITIALIZE value). These are: |
151 | * | 151 | * |
152 | * base: The start of the Guest-physical memory inside the Launcher memory. | 152 | * base: The start of the Guest-physical memory inside the Launcher memory. |
@@ -155,9 +155,6 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip) | |||
155 | * allowed to access. The Guest memory lives inside the Launcher, so it sets | 155 | * allowed to access. The Guest memory lives inside the Launcher, so it sets |
156 | * this to ensure the Guest can only reach its own memory. | 156 | * this to ensure the Guest can only reach its own memory. |
157 | * | 157 | * |
158 | * pgdir: The (Guest-physical) address of the top of the initial Guest | ||
159 | * pagetables (which are set up by the Launcher). | ||
160 | * | ||
161 | * start: The first instruction to execute ("eip" in x86-speak). | 158 | * start: The first instruction to execute ("eip" in x86-speak). |
162 | */ | 159 | */ |
163 | static int initialize(struct file *file, const unsigned long __user *input) | 160 | static int initialize(struct file *file, const unsigned long __user *input) |
@@ -166,7 +163,7 @@ static int initialize(struct file *file, const unsigned long __user *input) | |||
166 | * Guest. */ | 163 | * Guest. */ |
167 | struct lguest *lg; | 164 | struct lguest *lg; |
168 | int err; | 165 | int err; |
169 | unsigned long args[4]; | 166 | unsigned long args[3]; |
170 | 167 | ||
171 | /* We grab the Big Lguest lock, which protects against multiple | 168 | /* We grab the Big Lguest lock, which protects against multiple |
172 | * simultaneous initializations. */ | 169 | * simultaneous initializations. */ |
@@ -192,14 +189,14 @@ static int initialize(struct file *file, const unsigned long __user *input) | |||
192 | lg->mem_base = (void __user *)args[0]; | 189 | lg->mem_base = (void __user *)args[0]; |
193 | lg->pfn_limit = args[1]; | 190 | lg->pfn_limit = args[1]; |
194 | 191 | ||
195 | /* This is the first cpu (cpu 0) and it will start booting at args[3] */ | 192 | /* This is the first cpu (cpu 0) and it will start booting at args[2] */ |
196 | err = lg_cpu_start(&lg->cpus[0], 0, args[3]); | 193 | err = lg_cpu_start(&lg->cpus[0], 0, args[2]); |
197 | if (err) | 194 | if (err) |
198 | goto release_guest; | 195 | goto release_guest; |
199 | 196 | ||
200 | /* Initialize the Guest's shadow page tables, using the toplevel | 197 | /* Initialize the Guest's shadow page tables, using the toplevel |
201 | * address the Launcher gave us. This allocates memory, so can fail. */ | 198 | * address the Launcher gave us. This allocates memory, so can fail. */ |
202 | err = init_guest_pagetable(lg, args[2]); | 199 | err = init_guest_pagetable(lg); |
203 | if (err) | 200 | if (err) |
204 | goto free_regs; | 201 | goto free_regs; |
205 | 202 | ||
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index 81d0c6053447..576a8318221c 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/percpu.h> | 14 | #include <linux/percpu.h> |
15 | #include <asm/tlbflush.h> | 15 | #include <asm/tlbflush.h> |
16 | #include <asm/uaccess.h> | 16 | #include <asm/uaccess.h> |
17 | #include <asm/bootparam.h> | ||
17 | #include "lg.h" | 18 | #include "lg.h" |
18 | 19 | ||
19 | /*M:008 We hold reference to pages, which prevents them from being swapped. | 20 | /*M:008 We hold reference to pages, which prevents them from being swapped. |
@@ -581,15 +582,82 @@ void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 idx) | |||
581 | release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx); | 582 | release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx); |
582 | } | 583 | } |
583 | 584 | ||
585 | /* Once we know how much memory we have we can construct simple identity | ||
586 | * (which set virtual == physical) and linear mappings | ||
587 | * which will get the Guest far enough into the boot to create its own. | ||
588 | * | ||
589 | * We lay them out of the way, just below the initrd (which is why we need to | ||
590 | * know its size here). */ | ||
591 | static unsigned long setup_pagetables(struct lguest *lg, | ||
592 | unsigned long mem, | ||
593 | unsigned long initrd_size) | ||
594 | { | ||
595 | pgd_t __user *pgdir; | ||
596 | pte_t __user *linear; | ||
597 | unsigned int mapped_pages, i, linear_pages, phys_linear; | ||
598 | unsigned long mem_base = (unsigned long)lg->mem_base; | ||
599 | |||
600 | /* We have mapped_pages frames to map, so we need | ||
601 | * linear_pages page tables to map them. */ | ||
602 | mapped_pages = mem / PAGE_SIZE; | ||
603 | linear_pages = (mapped_pages + PTRS_PER_PTE - 1) / PTRS_PER_PTE; | ||
604 | |||
605 | /* We put the toplevel page directory page at the top of memory. */ | ||
606 | pgdir = (pgd_t *)(mem + mem_base - initrd_size - PAGE_SIZE); | ||
607 | |||
608 | /* Now we use the next linear_pages pages as pte pages */ | ||
609 | linear = (void *)pgdir - linear_pages * PAGE_SIZE; | ||
610 | |||
611 | /* Linear mapping is easy: put every page's address into the | ||
612 | * mapping in order. */ | ||
613 | for (i = 0; i < mapped_pages; i++) { | ||
614 | pte_t pte; | ||
615 | pte = pfn_pte(i, __pgprot(_PAGE_PRESENT|_PAGE_RW|_PAGE_USER)); | ||
616 | if (copy_to_user(&linear[i], &pte, sizeof(pte)) != 0) | ||
617 | return -EFAULT; | ||
618 | } | ||
619 | |||
620 | /* The top level points to the linear page table pages above. | ||
621 | * We setup the identity and linear mappings here. */ | ||
622 | phys_linear = (unsigned long)linear - mem_base; | ||
623 | for (i = 0; i < mapped_pages; i += PTRS_PER_PTE) { | ||
624 | pgd_t pgd; | ||
625 | pgd = __pgd((phys_linear + i * sizeof(pte_t)) | | ||
626 | (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER)); | ||
627 | |||
628 | if (copy_to_user(&pgdir[i / PTRS_PER_PTE], &pgd, sizeof(pgd)) | ||
629 | || copy_to_user(&pgdir[pgd_index(PAGE_OFFSET) | ||
630 | + i / PTRS_PER_PTE], | ||
631 | &pgd, sizeof(pgd))) | ||
632 | return -EFAULT; | ||
633 | } | ||
634 | |||
635 | /* We return the top level (guest-physical) address: remember where | ||
636 | * this is. */ | ||
637 | return (unsigned long)pgdir - mem_base; | ||
638 | } | ||
639 | |||
584 | /*H:500 (vii) Setting up the page tables initially. | 640 | /*H:500 (vii) Setting up the page tables initially. |
585 | * | 641 | * |
586 | * When a Guest is first created, the Launcher tells us where the toplevel of | 642 | * When a Guest is first created, the Launcher tells us where the toplevel of |
587 | * its first page table is. We set some things up here: */ | 643 | * its first page table is. We set some things up here: */ |
588 | int init_guest_pagetable(struct lguest *lg, unsigned long pgtable) | 644 | int init_guest_pagetable(struct lguest *lg) |
589 | { | 645 | { |
646 | u64 mem; | ||
647 | u32 initrd_size; | ||
648 | struct boot_params __user *boot = (struct boot_params *)lg->mem_base; | ||
649 | |||
650 | /* Get the Guest memory size and the ramdisk size from the boot header | ||
651 | * located at lg->mem_base (Guest address 0). */ | ||
652 | if (copy_from_user(&mem, &boot->e820_map[0].size, sizeof(mem)) | ||
653 | || get_user(initrd_size, &boot->hdr.ramdisk_size)) | ||
654 | return -EFAULT; | ||
655 | |||
590 | /* We start on the first shadow page table, and give it a blank PGD | 656 | /* We start on the first shadow page table, and give it a blank PGD |
591 | * page. */ | 657 | * page. */ |
592 | lg->pgdirs[0].gpgdir = pgtable; | 658 | lg->pgdirs[0].gpgdir = setup_pagetables(lg, mem, initrd_size); |
659 | if (IS_ERR_VALUE(lg->pgdirs[0].gpgdir)) | ||
660 | return lg->pgdirs[0].gpgdir; | ||
593 | lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL); | 661 | lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL); |
594 | if (!lg->pgdirs[0].pgdir) | 662 | if (!lg->pgdirs[0].pgdir) |
595 | return -ENOMEM; | 663 | return -ENOMEM; |