diff options
author | Jeremy Fitzhardinge <jeremy@goop.org> | 2008-07-08 18:06:53 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-16 05:00:49 -0400 |
commit | 39dbc5bd345ebf93e066dde7f8e29467eb61b42e (patch) | |
tree | e86122d1ce65d152b6d2c523e052e16f06ae72fb /arch/x86/xen | |
parent | d114e1981cc1a51131230993a082c27c79ab370a (diff) |
xen32: create initial mappings like 64-bit
Rearrange the pagetable initialization to share code with the 64-bit
kernel. Rather than deferring anything to pagetable_setup_start, just
set up an initial pagetable in swapper_pg_dir early at startup, and
create an additional 8MB of physical memory mappings. This matches
the native head_32.S mappings to a large degree, and allows the rest
of the pagetable setup to continue without much Xen vs. native
difference.
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Cc: Stephen Tweedie <sct@redhat.com>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Cc: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/xen')
-rw-r--r-- | arch/x86/xen/enlighten.c | 130 |
1 files changed, 52 insertions, 78 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index e9e3bafe48cf..19c12a6c7311 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -854,50 +854,6 @@ static __init void xen_set_pte_init(pte_t *ptep, pte_t pte) | |||
854 | 854 | ||
855 | static __init void xen_pagetable_setup_start(pgd_t *base) | 855 | static __init void xen_pagetable_setup_start(pgd_t *base) |
856 | { | 856 | { |
857 | #ifdef CONFIG_X86_32 | ||
858 | pgd_t *xen_pgd = (pgd_t *)xen_start_info->pt_base; | ||
859 | int i; | ||
860 | |||
861 | init_mm.pgd = base; | ||
862 | /* | ||
863 | * copy top-level of Xen-supplied pagetable into place. This | ||
864 | * is a stand-in while we copy the pmd pages. | ||
865 | */ | ||
866 | memcpy(base, xen_pgd, PTRS_PER_PGD * sizeof(pgd_t)); | ||
867 | |||
868 | /* | ||
869 | * For PAE, need to allocate new pmds, rather than | ||
870 | * share Xen's, since Xen doesn't like pmd's being | ||
871 | * shared between address spaces. | ||
872 | */ | ||
873 | for (i = 0; i < PTRS_PER_PGD; i++) { | ||
874 | if (pgd_val_ma(xen_pgd[i]) & _PAGE_PRESENT) { | ||
875 | pmd_t *pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE); | ||
876 | |||
877 | memcpy(pmd, (void *)pgd_page_vaddr(xen_pgd[i]), | ||
878 | PAGE_SIZE); | ||
879 | |||
880 | make_lowmem_page_readonly(pmd); | ||
881 | |||
882 | set_pgd(&base[i], __pgd(1 + __pa(pmd))); | ||
883 | } else | ||
884 | pgd_clear(&base[i]); | ||
885 | } | ||
886 | |||
887 | /* make sure zero_page is mapped RO so we can use it in pagetables */ | ||
888 | make_lowmem_page_readonly(empty_zero_page); | ||
889 | make_lowmem_page_readonly(base); | ||
890 | /* | ||
891 | * Switch to new pagetable. This is done before | ||
892 | * pagetable_init has done anything so that the new pages | ||
893 | * added to the table can be prepared properly for Xen. | ||
894 | */ | ||
895 | xen_write_cr3(__pa(base)); | ||
896 | |||
897 | /* Unpin initial Xen pagetable */ | ||
898 | pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, | ||
899 | PFN_DOWN(__pa(xen_start_info->pt_base))); | ||
900 | #endif /* CONFIG_X86_32 */ | ||
901 | } | 857 | } |
902 | 858 | ||
903 | void xen_setup_shared_info(void) | 859 | void xen_setup_shared_info(void) |
@@ -936,12 +892,6 @@ static __init void xen_pagetable_setup_done(pgd_t *base) | |||
936 | pv_mmu_ops.set_pte = xen_set_pte; | 892 | pv_mmu_ops.set_pte = xen_set_pte; |
937 | 893 | ||
938 | xen_setup_shared_info(); | 894 | xen_setup_shared_info(); |
939 | |||
940 | #ifdef CONFIG_X86_32 | ||
941 | /* Actually pin the pagetable down, but we can't set PG_pinned | ||
942 | yet because the page structures don't exist yet. */ | ||
943 | pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(base))); | ||
944 | #endif | ||
945 | } | 895 | } |
946 | 896 | ||
947 | static __init void xen_post_allocator_init(void) | 897 | static __init void xen_post_allocator_init(void) |
@@ -1299,14 +1249,17 @@ static void __init xen_reserve_top(void) | |||
1299 | #endif /* CONFIG_X86_32 */ | 1249 | #endif /* CONFIG_X86_32 */ |
1300 | } | 1250 | } |
1301 | 1251 | ||
1302 | #ifdef CONFIG_X86_64 | ||
1303 | /* | 1252 | /* |
1304 | * Like __va(), but returns address in the kernel mapping (which is | 1253 | * Like __va(), but returns address in the kernel mapping (which is |
1305 | * all we have until the physical memory mapping has been set up. | 1254 | * all we have until the physical memory mapping has been set up. |
1306 | */ | 1255 | */ |
1307 | static void *__ka(phys_addr_t paddr) | 1256 | static void *__ka(phys_addr_t paddr) |
1308 | { | 1257 | { |
1258 | #ifdef CONFIG_X86_64 | ||
1309 | return (void *)(paddr + __START_KERNEL_map); | 1259 | return (void *)(paddr + __START_KERNEL_map); |
1260 | #else | ||
1261 | return __va(paddr); | ||
1262 | #endif | ||
1310 | } | 1263 | } |
1311 | 1264 | ||
1312 | /* Convert a machine address to physical address */ | 1265 | /* Convert a machine address to physical address */ |
@@ -1326,6 +1279,7 @@ static void *m2v(phys_addr_t maddr) | |||
1326 | return __ka(m2p(maddr)); | 1279 | return __ka(m2p(maddr)); |
1327 | } | 1280 | } |
1328 | 1281 | ||
1282 | #ifdef CONFIG_X86_64 | ||
1329 | static void walk(pgd_t *pgd, unsigned long addr) | 1283 | static void walk(pgd_t *pgd, unsigned long addr) |
1330 | { | 1284 | { |
1331 | unsigned l4idx = pgd_index(addr); | 1285 | unsigned l4idx = pgd_index(addr); |
@@ -1356,13 +1310,14 @@ static void walk(pgd_t *pgd, unsigned long addr) | |||
1356 | xen_raw_printk(" l1: %016lx\n", l1.pte); | 1310 | xen_raw_printk(" l1: %016lx\n", l1.pte); |
1357 | xen_raw_printk(" %016lx\n", pte_val(l1)); | 1311 | xen_raw_printk(" %016lx\n", pte_val(l1)); |
1358 | } | 1312 | } |
1313 | #endif | ||
1359 | 1314 | ||
1360 | static void set_page_prot(void *addr, pgprot_t prot) | 1315 | static void set_page_prot(void *addr, pgprot_t prot) |
1361 | { | 1316 | { |
1362 | unsigned long pfn = __pa(addr) >> PAGE_SHIFT; | 1317 | unsigned long pfn = __pa(addr) >> PAGE_SHIFT; |
1363 | pte_t pte = pfn_pte(pfn, prot); | 1318 | pte_t pte = pfn_pte(pfn, prot); |
1364 | 1319 | ||
1365 | xen_raw_printk("addr=%p pfn=%lx mfn=%lx prot=%016x pte=%016x\n", | 1320 | xen_raw_printk("addr=%p pfn=%lx mfn=%lx prot=%016llx pte=%016llx\n", |
1366 | addr, pfn, get_phys_to_machine(pfn), | 1321 | addr, pfn, get_phys_to_machine(pfn), |
1367 | pgprot_val(prot), pte.pte); | 1322 | pgprot_val(prot), pte.pte); |
1368 | 1323 | ||
@@ -1370,17 +1325,6 @@ static void set_page_prot(void *addr, pgprot_t prot) | |||
1370 | BUG(); | 1325 | BUG(); |
1371 | } | 1326 | } |
1372 | 1327 | ||
1373 | static void convert_pfn_mfn(void *v) | ||
1374 | { | ||
1375 | pte_t *pte = v; | ||
1376 | int i; | ||
1377 | |||
1378 | /* All levels are converted the same way, so just treat them | ||
1379 | as ptes. */ | ||
1380 | for(i = 0; i < PTRS_PER_PTE; i++) | ||
1381 | pte[i] = xen_make_pte(pte[i].pte); | ||
1382 | } | ||
1383 | |||
1384 | /* | 1328 | /* |
1385 | * Identity map, in addition to plain kernel map. This needs to be | 1329 | * Identity map, in addition to plain kernel map. This needs to be |
1386 | * large enough to allocate page table pages to allocate the rest. | 1330 | * large enough to allocate page table pages to allocate the rest. |
@@ -1388,7 +1332,7 @@ static void convert_pfn_mfn(void *v) | |||
1388 | */ | 1332 | */ |
1389 | static pte_t level1_ident_pgt[PTRS_PER_PTE * 4] __page_aligned_bss; | 1333 | static pte_t level1_ident_pgt[PTRS_PER_PTE * 4] __page_aligned_bss; |
1390 | 1334 | ||
1391 | static __init void xen_map_identity_early(unsigned long max_pfn) | 1335 | static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) |
1392 | { | 1336 | { |
1393 | unsigned pmdidx, pteidx; | 1337 | unsigned pmdidx, pteidx; |
1394 | unsigned ident_pte; | 1338 | unsigned ident_pte; |
@@ -1399,11 +1343,9 @@ static __init void xen_map_identity_early(unsigned long max_pfn) | |||
1399 | for(pmdidx = 0; pmdidx < PTRS_PER_PMD && pfn < max_pfn; pmdidx++) { | 1343 | for(pmdidx = 0; pmdidx < PTRS_PER_PMD && pfn < max_pfn; pmdidx++) { |
1400 | pte_t *pte_page; | 1344 | pte_t *pte_page; |
1401 | 1345 | ||
1402 | BUG_ON(level2_ident_pgt[pmdidx].pmd != level2_kernel_pgt[pmdidx].pmd); | ||
1403 | |||
1404 | /* Reuse or allocate a page of ptes */ | 1346 | /* Reuse or allocate a page of ptes */ |
1405 | if (pmd_present(level2_ident_pgt[pmdidx])) | 1347 | if (pmd_present(pmd[pmdidx])) |
1406 | pte_page = m2v(level2_ident_pgt[pmdidx].pmd); | 1348 | pte_page = m2v(pmd[pmdidx].pmd); |
1407 | else { | 1349 | else { |
1408 | /* Check for free pte pages */ | 1350 | /* Check for free pte pages */ |
1409 | if (ident_pte == ARRAY_SIZE(level1_ident_pgt)) | 1351 | if (ident_pte == ARRAY_SIZE(level1_ident_pgt)) |
@@ -1412,9 +1354,7 @@ static __init void xen_map_identity_early(unsigned long max_pfn) | |||
1412 | pte_page = &level1_ident_pgt[ident_pte]; | 1354 | pte_page = &level1_ident_pgt[ident_pte]; |
1413 | ident_pte += PTRS_PER_PTE; | 1355 | ident_pte += PTRS_PER_PTE; |
1414 | 1356 | ||
1415 | /* Install new l1 in l2(s) */ | 1357 | pmd[pmdidx] = __pmd(__pa(pte_page) | _PAGE_TABLE); |
1416 | level2_ident_pgt[pmdidx] = __pmd(__pa(pte_page) | _PAGE_TABLE); | ||
1417 | level2_kernel_pgt[pmdidx] = level2_ident_pgt[pmdidx]; | ||
1418 | } | 1358 | } |
1419 | 1359 | ||
1420 | /* Install mappings */ | 1360 | /* Install mappings */ |
@@ -1434,6 +1374,20 @@ static __init void xen_map_identity_early(unsigned long max_pfn) | |||
1434 | 1374 | ||
1435 | for(pteidx = 0; pteidx < ident_pte; pteidx += PTRS_PER_PTE) | 1375 | for(pteidx = 0; pteidx < ident_pte; pteidx += PTRS_PER_PTE) |
1436 | set_page_prot(&level1_ident_pgt[pteidx], PAGE_KERNEL_RO); | 1376 | set_page_prot(&level1_ident_pgt[pteidx], PAGE_KERNEL_RO); |
1377 | |||
1378 | set_page_prot(pmd, PAGE_KERNEL_RO); | ||
1379 | } | ||
1380 | |||
1381 | #ifdef CONFIG_X86_64 | ||
1382 | static void convert_pfn_mfn(void *v) | ||
1383 | { | ||
1384 | pte_t *pte = v; | ||
1385 | int i; | ||
1386 | |||
1387 | /* All levels are converted the same way, so just treat them | ||
1388 | as ptes. */ | ||
1389 | for(i = 0; i < PTRS_PER_PTE; i++) | ||
1390 | pte[i] = xen_make_pte(pte[i].pte); | ||
1437 | } | 1391 | } |
1438 | 1392 | ||
1439 | /* | 1393 | /* |
@@ -1471,18 +1425,18 @@ static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pf | |||
1471 | memcpy(level2_fixmap_pgt, l2, sizeof(pmd_t) * PTRS_PER_PMD); | 1425 | memcpy(level2_fixmap_pgt, l2, sizeof(pmd_t) * PTRS_PER_PMD); |
1472 | 1426 | ||
1473 | /* Set up identity map */ | 1427 | /* Set up identity map */ |
1474 | xen_map_identity_early(max_pfn); | 1428 | xen_map_identity_early(level2_ident_pgt, max_pfn); |
1475 | 1429 | ||
1476 | /* Make pagetable pieces RO */ | 1430 | /* Make pagetable pieces RO */ |
1477 | set_page_prot(init_level4_pgt, PAGE_KERNEL_RO); | 1431 | set_page_prot(init_level4_pgt, PAGE_KERNEL_RO); |
1478 | set_page_prot(level3_ident_pgt, PAGE_KERNEL_RO); | 1432 | set_page_prot(level3_ident_pgt, PAGE_KERNEL_RO); |
1479 | set_page_prot(level3_kernel_pgt, PAGE_KERNEL_RO); | 1433 | set_page_prot(level3_kernel_pgt, PAGE_KERNEL_RO); |
1480 | set_page_prot(level2_ident_pgt, PAGE_KERNEL_RO); | ||
1481 | set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO); | 1434 | set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO); |
1482 | set_page_prot(level2_fixmap_pgt, PAGE_KERNEL_RO); | 1435 | set_page_prot(level2_fixmap_pgt, PAGE_KERNEL_RO); |
1483 | 1436 | ||
1484 | /* Pin down new L4 */ | 1437 | /* Pin down new L4 */ |
1485 | pin_pagetable_pfn(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa_symbol(init_level4_pgt))); | 1438 | pin_pagetable_pfn(MMUEXT_PIN_L4_TABLE, |
1439 | PFN_DOWN(__pa_symbol(init_level4_pgt))); | ||
1486 | 1440 | ||
1487 | /* Unpin Xen-provided one */ | 1441 | /* Unpin Xen-provided one */ |
1488 | pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd))); | 1442 | pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd))); |
@@ -1498,17 +1452,37 @@ static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pf | |||
1498 | 1452 | ||
1499 | return pgd; | 1453 | return pgd; |
1500 | } | 1454 | } |
1501 | #else | 1455 | #else /* !CONFIG_X86_64 */ |
1456 | static pmd_t level2_kernel_pgt[PTRS_PER_PMD] __page_aligned_bss; | ||
1457 | |||
1502 | static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) | 1458 | static __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) |
1503 | { | 1459 | { |
1460 | pmd_t *kernel_pmd; | ||
1461 | |||
1504 | init_pg_tables_start = __pa(pgd); | 1462 | init_pg_tables_start = __pa(pgd); |
1505 | init_pg_tables_end = __pa(pgd) + xen_start_info->nr_pt_frames*PAGE_SIZE; | 1463 | init_pg_tables_end = __pa(pgd) + xen_start_info->nr_pt_frames*PAGE_SIZE; |
1506 | max_pfn_mapped = PFN_DOWN(init_pg_tables_end + 512*1024); | 1464 | max_pfn_mapped = PFN_DOWN(init_pg_tables_end + 512*1024); |
1507 | 1465 | ||
1508 | x86_write_percpu(xen_cr3, __pa(pgd)); | 1466 | kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd); |
1509 | x86_write_percpu(xen_current_cr3, __pa(pgd)); | 1467 | memcpy(level2_kernel_pgt, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD); |
1510 | 1468 | ||
1511 | return pgd; | 1469 | xen_map_identity_early(level2_kernel_pgt, max_pfn); |
1470 | |||
1471 | memcpy(swapper_pg_dir, pgd, sizeof(pgd_t) * PTRS_PER_PGD); | ||
1472 | set_pgd(&swapper_pg_dir[KERNEL_PGD_BOUNDARY], | ||
1473 | __pgd(__pa(level2_kernel_pgt) | _PAGE_PRESENT)); | ||
1474 | |||
1475 | set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO); | ||
1476 | set_page_prot(swapper_pg_dir, PAGE_KERNEL_RO); | ||
1477 | set_page_prot(empty_zero_page, PAGE_KERNEL_RO); | ||
1478 | |||
1479 | pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd))); | ||
1480 | |||
1481 | xen_write_cr3(__pa(swapper_pg_dir)); | ||
1482 | |||
1483 | pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(swapper_pg_dir))); | ||
1484 | |||
1485 | return swapper_pg_dir; | ||
1512 | } | 1486 | } |
1513 | #endif /* CONFIG_X86_64 */ | 1487 | #endif /* CONFIG_X86_64 */ |
1514 | 1488 | ||