diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2013-04-22 00:40:39 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2013-04-22 02:14:47 -0400 |
commit | 17427e08faae3e63271a9c2d0edb6a22e5fbb54b (patch) | |
tree | f2a7b84741ce7c21b818a2da9873d7eef0b92307 | |
parent | e1d12606f756bdb8328a66a2873dca6c46bcb4e5 (diff) |
lguest: extract shadow PTE walking / allocating.
We want a separate find_pte() function so we can call it for populating the
switcher PTE entries.
We can also use it in page_writable().
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r-- | drivers/lguest/page_tables.c | 170 |
1 files changed, 101 insertions, 69 deletions
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index f074f34acb86..009c717fda99 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c | |||
@@ -291,6 +291,88 @@ static bool check_gpmd(struct lg_cpu *cpu, pmd_t gpmd) | |||
291 | } | 291 | } |
292 | #endif | 292 | #endif |
293 | 293 | ||
294 | /*H:331 | ||
295 | * This is the core routine to walk the shadow page tables and find the page | ||
296 | * table entry for a specific address. | ||
297 | * | ||
298 | * If allocate is set, then we allocate any missing levels, setting the flags | ||
299 | * on the new page directory and mid-level directories using the arguments | ||
300 | * (which are copied from the Guest's page table entries). | ||
301 | */ | ||
302 | static pte_t *find_spte(struct lg_cpu *cpu, unsigned long vaddr, bool allocate, | ||
303 | int pgd_flags, int pmd_flags) | ||
304 | { | ||
305 | pgd_t *spgd; | ||
306 | /* Mid level for PAE. */ | ||
307 | #ifdef CONFIG_X86_PAE | ||
308 | pmd_t *spmd; | ||
309 | #endif | ||
310 | |||
311 | /* Get top level entry. */ | ||
312 | spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr); | ||
313 | if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) { | ||
314 | /* No shadow entry: allocate a new shadow PTE page. */ | ||
315 | unsigned long ptepage; | ||
316 | |||
317 | /* If they didn't want us to allocate anything, stop. */ | ||
318 | if (!allocate) | ||
319 | return NULL; | ||
320 | |||
321 | ptepage = get_zeroed_page(GFP_KERNEL); | ||
322 | /* | ||
323 | * This is not really the Guest's fault, but killing it is | ||
324 | * simple for this corner case. | ||
325 | */ | ||
326 | if (!ptepage) { | ||
327 | kill_guest(cpu, "out of memory allocating pte page"); | ||
328 | return NULL; | ||
329 | } | ||
330 | /* | ||
331 | * And we copy the flags to the shadow PGD entry. The page | ||
332 | * number in the shadow PGD is the page we just allocated. | ||
333 | */ | ||
334 | set_pgd(spgd, __pgd(__pa(ptepage) | pgd_flags)); | ||
335 | } | ||
336 | |||
337 | /* | ||
338 | * Intel's Physical Address Extension actually uses three levels of | ||
339 | * page tables, so we need to look in the mid-level. | ||
340 | */ | ||
341 | #ifdef CONFIG_X86_PAE | ||
342 | /* Now look at the mid-level shadow entry. */ | ||
343 | spmd = spmd_addr(cpu, *spgd, vaddr); | ||
344 | |||
345 | if (!(pmd_flags(*spmd) & _PAGE_PRESENT)) { | ||
346 | /* No shadow entry: allocate a new shadow PTE page. */ | ||
347 | unsigned long ptepage; | ||
348 | |||
349 | /* If they didn't want us to allocate anything, stop. */ | ||
350 | if (!allocate) | ||
351 | return NULL; | ||
352 | |||
353 | ptepage = get_zeroed_page(GFP_KERNEL); | ||
354 | |||
355 | /* | ||
356 | * This is not really the Guest's fault, but killing it is | ||
357 | * simple for this corner case. | ||
358 | */ | ||
359 | if (!ptepage) { | ||
360 | kill_guest(cpu, "out of memory allocating pmd page"); | ||
361 | return NULL; | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * And we copy the flags to the shadow PMD entry. The page | ||
366 | * number in the shadow PMD is the page we just allocated. | ||
367 | */ | ||
368 | set_pmd(spmd, __pmd(__pa(ptepage) | pmd_flags)); | ||
369 | } | ||
370 | #endif | ||
371 | |||
372 | /* Get the pointer to the shadow PTE entry we're going to set. */ | ||
373 | return spte_addr(cpu, *spgd, vaddr); | ||
374 | } | ||
375 | |||
294 | /*H:330 | 376 | /*H:330 |
295 | * (i) Looking up a page table entry when the Guest faults. | 377 | * (i) Looking up a page table entry when the Guest faults. |
296 | * | 378 | * |
@@ -304,17 +386,11 @@ static bool check_gpmd(struct lg_cpu *cpu, pmd_t gpmd) | |||
304 | */ | 386 | */ |
305 | bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode) | 387 | bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode) |
306 | { | 388 | { |
307 | pgd_t gpgd; | ||
308 | pgd_t *spgd; | ||
309 | unsigned long gpte_ptr; | 389 | unsigned long gpte_ptr; |
310 | pte_t gpte; | 390 | pte_t gpte; |
311 | pte_t *spte; | 391 | pte_t *spte; |
312 | |||
313 | /* Mid level for PAE. */ | ||
314 | #ifdef CONFIG_X86_PAE | ||
315 | pmd_t *spmd; | ||
316 | pmd_t gpmd; | 392 | pmd_t gpmd; |
317 | #endif | 393 | pgd_t gpgd; |
318 | 394 | ||
319 | /* We never demand page the Switcher, so trying is a mistake. */ | 395 | /* We never demand page the Switcher, so trying is a mistake. */ |
320 | if (vaddr >= switcher_addr) | 396 | if (vaddr >= switcher_addr) |
@@ -329,67 +405,31 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode) | |||
329 | /* Toplevel not present? We can't map it in. */ | 405 | /* Toplevel not present? We can't map it in. */ |
330 | if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) | 406 | if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) |
331 | return false; | 407 | return false; |
332 | } | ||
333 | 408 | ||
334 | /* Now look at the matching shadow entry. */ | 409 | /* |
335 | spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr); | 410 | * This kills the Guest if it has weird flags or tries to |
336 | if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) { | 411 | * refer to a "physical" address outside the bounds. |
337 | /* No shadow entry: allocate a new shadow PTE page. */ | ||
338 | unsigned long ptepage = get_zeroed_page(GFP_KERNEL); | ||
339 | /* | ||
340 | * This is not really the Guest's fault, but killing it is | ||
341 | * simple for this corner case. | ||
342 | */ | 412 | */ |
343 | if (!ptepage) { | ||
344 | kill_guest(cpu, "out of memory allocating pte page"); | ||
345 | return false; | ||
346 | } | ||
347 | /* We check that the Guest pgd is OK. */ | ||
348 | if (!check_gpgd(cpu, gpgd)) | 413 | if (!check_gpgd(cpu, gpgd)) |
349 | return false; | 414 | return false; |
350 | /* | ||
351 | * And we copy the flags to the shadow PGD entry. The page | ||
352 | * number in the shadow PGD is the page we just allocated. | ||
353 | */ | ||
354 | set_pgd(spgd, __pgd(__pa(ptepage) | pgd_flags(gpgd))); | ||
355 | } | 415 | } |
356 | 416 | ||
417 | /* This "mid-level" entry is only used for non-linear, PAE mode. */ | ||
418 | gpmd = __pmd(_PAGE_TABLE); | ||
419 | |||
357 | #ifdef CONFIG_X86_PAE | 420 | #ifdef CONFIG_X86_PAE |
358 | if (unlikely(cpu->linear_pages)) { | 421 | if (likely(!cpu->linear_pages)) { |
359 | /* Faking up a linear mapping. */ | ||
360 | gpmd = __pmd(_PAGE_TABLE); | ||
361 | } else { | ||
362 | gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t); | 422 | gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t); |
363 | /* Middle level not present? We can't map it in. */ | 423 | /* Middle level not present? We can't map it in. */ |
364 | if (!(pmd_flags(gpmd) & _PAGE_PRESENT)) | 424 | if (!(pmd_flags(gpmd) & _PAGE_PRESENT)) |
365 | return false; | 425 | return false; |
366 | } | ||
367 | |||
368 | /* Now look at the matching shadow entry. */ | ||
369 | spmd = spmd_addr(cpu, *spgd, vaddr); | ||
370 | |||
371 | if (!(pmd_flags(*spmd) & _PAGE_PRESENT)) { | ||
372 | /* No shadow entry: allocate a new shadow PTE page. */ | ||
373 | unsigned long ptepage = get_zeroed_page(GFP_KERNEL); | ||
374 | 426 | ||
375 | /* | 427 | /* |
376 | * This is not really the Guest's fault, but killing it is | 428 | * This kills the Guest if it has weird flags or tries to |
377 | * simple for this corner case. | 429 | * refer to a "physical" address outside the bounds. |
378 | */ | 430 | */ |
379 | if (!ptepage) { | ||
380 | kill_guest(cpu, "out of memory allocating pte page"); | ||
381 | return false; | ||
382 | } | ||
383 | |||
384 | /* We check that the Guest pmd is OK. */ | ||
385 | if (!check_gpmd(cpu, gpmd)) | 431 | if (!check_gpmd(cpu, gpmd)) |
386 | return false; | 432 | return false; |
387 | |||
388 | /* | ||
389 | * And we copy the flags to the shadow PMD entry. The page | ||
390 | * number in the shadow PMD is the page we just allocated. | ||
391 | */ | ||
392 | set_pmd(spmd, __pmd(__pa(ptepage) | pmd_flags(gpmd))); | ||
393 | } | 433 | } |
394 | 434 | ||
395 | /* | 435 | /* |
@@ -441,7 +481,9 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode) | |||
441 | gpte = pte_mkdirty(gpte); | 481 | gpte = pte_mkdirty(gpte); |
442 | 482 | ||
443 | /* Get the pointer to the shadow PTE entry we're going to set. */ | 483 | /* Get the pointer to the shadow PTE entry we're going to set. */ |
444 | spte = spte_addr(cpu, *spgd, vaddr); | 484 | spte = find_spte(cpu, vaddr, true, pgd_flags(gpgd), pmd_flags(gpmd)); |
485 | if (!spte) | ||
486 | return false; | ||
445 | 487 | ||
446 | /* | 488 | /* |
447 | * If there was a valid shadow PTE entry here before, we release it. | 489 | * If there was a valid shadow PTE entry here before, we release it. |
@@ -493,33 +535,23 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode) | |||
493 | */ | 535 | */ |
494 | static bool page_writable(struct lg_cpu *cpu, unsigned long vaddr) | 536 | static bool page_writable(struct lg_cpu *cpu, unsigned long vaddr) |
495 | { | 537 | { |
496 | pgd_t *spgd; | 538 | pte_t *spte; |
497 | unsigned long flags; | 539 | unsigned long flags; |
498 | #ifdef CONFIG_X86_PAE | ||
499 | pmd_t *spmd; | ||
500 | #endif | ||
501 | 540 | ||
502 | /* You can't put your stack in the Switcher! */ | 541 | /* You can't put your stack in the Switcher! */ |
503 | if (vaddr >= switcher_addr) | 542 | if (vaddr >= switcher_addr) |
504 | return false; | 543 | return false; |
505 | 544 | ||
506 | /* Look at the current top level entry: is it present? */ | 545 | /* If there's no shadow PTE, it's not writable. */ |
507 | spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr); | 546 | spte = find_spte(cpu, vaddr, false, 0, 0); |
508 | if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) | 547 | if (!spte) |
509 | return false; | 548 | return false; |
510 | 549 | ||
511 | #ifdef CONFIG_X86_PAE | ||
512 | spmd = spmd_addr(cpu, *spgd, vaddr); | ||
513 | if (!(pmd_flags(*spmd) & _PAGE_PRESENT)) | ||
514 | return false; | ||
515 | #endif | ||
516 | |||
517 | /* | 550 | /* |
518 | * Check the flags on the pte entry itself: it must be present and | 551 | * Check the flags on the pte entry itself: it must be present and |
519 | * writable. | 552 | * writable. |
520 | */ | 553 | */ |
521 | flags = pte_flags(*(spte_addr(cpu, *spgd, vaddr))); | 554 | flags = pte_flags(*spte); |
522 | |||
523 | return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW); | 555 | return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW); |
524 | } | 556 | } |
525 | 557 | ||