|
37 | 37 | #include <asm/unistd.h>
|
38 | 38 | #include <asm/fixmap.h>
|
39 | 39 | #include <asm/traps.h>
|
| 40 | +#include <asm/paravirt.h> |
40 | 41 |
|
41 | 42 | #define CREATE_TRACE_POINTS
|
42 | 43 | #include "vsyscall_trace.h"
|
@@ -329,16 +330,47 @@ int in_gate_area_no_mm(unsigned long addr)
|
329 | 330 | return vsyscall_mode != NONE && (addr & PAGE_MASK) == VSYSCALL_ADDR;
|
330 | 331 | }
|
331 | 332 |
|
| 333 | +/* |
| 334 | + * The VSYSCALL page is the only user-accessible page in the kernel address |
| 335 | + * range. Normally, the kernel page tables can have _PAGE_USER clear, but |
| 336 | + * the tables covering VSYSCALL_ADDR need _PAGE_USER set if vsyscalls |
| 337 | + * are enabled. |
| 338 | + * |
| 339 | + * Some day we may create a "minimal" vsyscall mode in which we emulate |
| 340 | + * vsyscalls but leave the page not present. If so, we skip calling |
| 341 | + * this. |
| 342 | + */ |
| 343 | +static void __init set_vsyscall_pgtable_user_bits(void) |
| 344 | +{ |
| 345 | + pgd_t *pgd; |
| 346 | + p4d_t *p4d; |
| 347 | + pud_t *pud; |
| 348 | + pmd_t *pmd; |
| 349 | + |
| 350 | + pgd = pgd_offset_k(VSYSCALL_ADDR); |
| 351 | + set_pgd(pgd, __pgd(pgd_val(*pgd) | _PAGE_USER)); |
| 352 | + p4d = p4d_offset(pgd, VSYSCALL_ADDR); |
| 353 | +#if CONFIG_PGTABLE_LEVELS >= 5 |
| 354 | + p4d->p4d |= _PAGE_USER; |
| 355 | +#endif |
| 356 | + pud = pud_offset(p4d, VSYSCALL_ADDR); |
| 357 | + set_pud(pud, __pud(pud_val(*pud) | _PAGE_USER)); |
| 358 | + pmd = pmd_offset(pud, VSYSCALL_ADDR); |
| 359 | + set_pmd(pmd, __pmd(pmd_val(*pmd) | _PAGE_USER)); |
| 360 | +} |
| 361 | + |
332 | 362 | void __init map_vsyscall(void)
|
333 | 363 | {
|
334 | 364 | extern char __vsyscall_page;
|
335 | 365 | unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page);
|
336 | 366 |
|
337 |
| - if (vsyscall_mode != NONE) |
| 367 | + if (vsyscall_mode != NONE) { |
338 | 368 | __set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall,
|
339 | 369 | vsyscall_mode == NATIVE
|
340 | 370 | ? PAGE_KERNEL_VSYSCALL
|
341 | 371 | : PAGE_KERNEL_VVAR);
|
| 372 | + set_vsyscall_pgtable_user_bits(); |
| 373 | + } |
342 | 374 |
|
343 | 375 | BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_PAGE) !=
|
344 | 376 | (unsigned long)VSYSCALL_ADDR);
|
|
0 commit comments