aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2005-10-05 18:12:00 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-10-05 18:12:00 -0400
commit9ad98c5b4461e7dfa3754963200993a68825eab4 (patch)
treeb7456cf49eaf034740fa7cb8b75e5b6ee01c9666 /arch
parent782c3fd470abddf2525e34cf3131215a8f95e834 (diff)
[SPARC64]: Fix initrd when net booting.
By allocating early memory for the firmware page tables, we can write over the beginning of the initrd image. So what we do now is: 1) Read in firmware translations table while still on the firmware's trap table. 2) Switch to Linux trap table. 3) Init bootmem. 4) Build firmware page tables using __alloc_bootmem(). And this keeps the initrd from being clobbered. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch')
-rw-r--r--arch/sparc64/mm/init.c156
1 files changed, 56 insertions, 100 deletions
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 4e2f71e0abc8..0d2e967c7200 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -368,6 +368,7 @@ struct linux_prom_translation {
368 unsigned long data; 368 unsigned long data;
369}; 369};
370static struct linux_prom_translation prom_trans[512] __initdata; 370static struct linux_prom_translation prom_trans[512] __initdata;
371static unsigned int prom_trans_ents __initdata;
371 372
372extern unsigned long prom_boot_page; 373extern unsigned long prom_boot_page;
373extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle); 374extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle);
@@ -381,57 +382,7 @@ unsigned long kern_locked_tte_data;
381unsigned long prom_pmd_phys __read_mostly; 382unsigned long prom_pmd_phys __read_mostly;
382unsigned int swapper_pgd_zero __read_mostly; 383unsigned int swapper_pgd_zero __read_mostly;
383 384
384/* Allocate power-of-2 aligned chunks from the end of the 385static pmd_t *prompmd __read_mostly;
385 * kernel image. Return physical address.
386 */
387static inline unsigned long early_alloc_phys(unsigned long size)
388{
389 unsigned long base;
390
391 BUILD_BUG_ON(size & (size - 1));
392
393 kern_size = (kern_size + (size - 1)) & ~(size - 1);
394 base = kern_base + kern_size;
395 kern_size += size;
396
397 return base;
398}
399
400static inline unsigned long load_phys32(unsigned long pa)
401{
402 unsigned long val;
403
404 __asm__ __volatile__("lduwa [%1] %2, %0"
405 : "=&r" (val)
406 : "r" (pa), "i" (ASI_PHYS_USE_EC));
407
408 return val;
409}
410
411static inline unsigned long load_phys64(unsigned long pa)
412{
413 unsigned long val;
414
415 __asm__ __volatile__("ldxa [%1] %2, %0"
416 : "=&r" (val)
417 : "r" (pa), "i" (ASI_PHYS_USE_EC));
418
419 return val;
420}
421
422static inline void store_phys32(unsigned long pa, unsigned long val)
423{
424 __asm__ __volatile__("stwa %0, [%1] %2"
425 : /* no outputs */
426 : "r" (val), "r" (pa), "i" (ASI_PHYS_USE_EC));
427}
428
429static inline void store_phys64(unsigned long pa, unsigned long val)
430{
431 __asm__ __volatile__("stxa %0, [%1] %2"
432 : /* no outputs */
433 : "r" (val), "r" (pa), "i" (ASI_PHYS_USE_EC));
434}
435 386
436#define BASE_PAGE_SIZE 8192 387#define BASE_PAGE_SIZE 8192
437 388
@@ -441,34 +392,28 @@ static inline void store_phys64(unsigned long pa, unsigned long val)
441 */ 392 */
442unsigned long prom_virt_to_phys(unsigned long promva, int *error) 393unsigned long prom_virt_to_phys(unsigned long promva, int *error)
443{ 394{
444 unsigned long pmd_phys = (prom_pmd_phys + 395 pmd_t *pmdp = prompmd + ((promva >> 23) & 0x7ff);
445 ((promva >> 23) & 0x7ff) * sizeof(pmd_t)); 396 pte_t *ptep;
446 unsigned long pte_phys;
447 pmd_t pmd_ent;
448 pte_t pte_ent;
449 unsigned long base; 397 unsigned long base;
450 398
451 pmd_val(pmd_ent) = load_phys32(pmd_phys); 399 if (pmd_none(*pmdp)) {
452 if (pmd_none(pmd_ent)) {
453 if (error) 400 if (error)
454 *error = 1; 401 *error = 1;
455 return 0; 402 return 0;
456 } 403 }
457 404 ptep = (pte_t *)__pmd_page(*pmdp) + ((promva >> 13) & 0x3ff);
458 pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL; 405 if (!pte_present(*ptep)) {
459 pte_phys += ((promva >> 13) & 0x3ff) * sizeof(pte_t);
460 pte_val(pte_ent) = load_phys64(pte_phys);
461 if (!pte_present(pte_ent)) {
462 if (error) 406 if (error)
463 *error = 1; 407 *error = 1;
464 return 0; 408 return 0;
465 } 409 }
466 if (error) { 410 if (error) {
467 *error = 0; 411 *error = 0;
468 return pte_val(pte_ent); 412 return pte_val(*ptep);
469 } 413 }
470 base = pte_val(pte_ent) & _PAGE_PADDR; 414 base = pte_val(*ptep) & _PAGE_PADDR;
471 return (base + (promva & (BASE_PAGE_SIZE - 1))); 415
416 return base + (promva & (BASE_PAGE_SIZE - 1));
472} 417}
473 418
474/* The obp translations are saved based on 8k pagesize, since obp can 419/* The obp translations are saved based on 8k pagesize, since obp can
@@ -481,25 +426,20 @@ static void __init build_obp_range(unsigned long start, unsigned long end, unsig
481 unsigned long vaddr; 426 unsigned long vaddr;
482 427
483 for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) { 428 for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) {
484 unsigned long val, pte_phys, pmd_phys; 429 unsigned long val;
485 pmd_t pmd_ent; 430 pmd_t *pmd;
486 int i; 431 pte_t *pte;
487
488 pmd_phys = (prom_pmd_phys +
489 (((vaddr >> 23) & 0x7ff) * sizeof(pmd_t)));
490 pmd_val(pmd_ent) = load_phys32(pmd_phys);
491 if (pmd_none(pmd_ent)) {
492 pte_phys = early_alloc_phys(BASE_PAGE_SIZE);
493
494 for (i = 0; i < BASE_PAGE_SIZE / sizeof(pte_t); i++)
495 store_phys64(pte_phys+i*sizeof(pte_t),0);
496 432
497 pmd_val(pmd_ent) = pte_phys >> 11UL; 433 pmd = prompmd + ((vaddr >> 23) & 0x7ff);
498 store_phys32(pmd_phys, pmd_val(pmd_ent)); 434 if (pmd_none(*pmd)) {
435 pte = __alloc_bootmem(BASE_PAGE_SIZE, BASE_PAGE_SIZE,
436 PAGE_SIZE);
437 if (!pte)
438 prom_halt();
439 memset(pte, 0, BASE_PAGE_SIZE);
440 pmd_set(pmd, pte);
499 } 441 }
500 442 pte = (pte_t *) __pmd_page(*pmd) + ((vaddr >> 13) & 0x3ff);
501 pte_phys = (unsigned long)pmd_val(pmd_ent) << 11UL;
502 pte_phys += (((vaddr >> 13) & 0x3ff) * sizeof(pte_t));
503 443
504 val = data; 444 val = data;
505 445
@@ -507,7 +447,8 @@ static void __init build_obp_range(unsigned long start, unsigned long end, unsig
507 if (tlb_type == spitfire) 447 if (tlb_type == spitfire)
508 val &= ~0x0003fe0000000000UL; 448 val &= ~0x0003fe0000000000UL;
509 449
510 store_phys64(pte_phys, val | _PAGE_MODIFIED); 450 set_pte_at(&init_mm, vaddr, pte,
451 __pte(val | _PAGE_MODIFIED));
511 452
512 data += BASE_PAGE_SIZE; 453 data += BASE_PAGE_SIZE;
513 } 454 }
@@ -520,13 +461,17 @@ static inline int in_obp_range(unsigned long vaddr)
520} 461}
521 462
522#define OBP_PMD_SIZE 2048 463#define OBP_PMD_SIZE 2048
523static void __init build_obp_pgtable(int prom_trans_ents) 464static void __init build_obp_pgtable(void)
524{ 465{
525 unsigned long i; 466 unsigned long i;
526 467
527 prom_pmd_phys = early_alloc_phys(OBP_PMD_SIZE); 468 prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, PAGE_SIZE);
528 for (i = 0; i < OBP_PMD_SIZE; i += 4) 469 if (!prompmd)
529 store_phys32(prom_pmd_phys + i, 0); 470 prom_halt();
471
472 memset(prompmd, 0, OBP_PMD_SIZE);
473
474 prom_pmd_phys = __pa(prompmd);
530 475
531 for (i = 0; i < prom_trans_ents; i++) { 476 for (i = 0; i < prom_trans_ents; i++) {
532 unsigned long start, end; 477 unsigned long start, end;
@@ -546,7 +491,7 @@ static void __init build_obp_pgtable(int prom_trans_ents)
546/* Read OBP translations property into 'prom_trans[]'. 491/* Read OBP translations property into 'prom_trans[]'.
547 * Return the number of entries. 492 * Return the number of entries.
548 */ 493 */
549static int __init read_obp_translations(void) 494static void __init read_obp_translations(void)
550{ 495{
551 int n, node; 496 int n, node;
552 497
@@ -567,8 +512,10 @@ static int __init read_obp_translations(void)
567 prom_printf("prom_mappings: Couldn't get property.\n"); 512 prom_printf("prom_mappings: Couldn't get property.\n");
568 prom_halt(); 513 prom_halt();
569 } 514 }
515
570 n = n / sizeof(struct linux_prom_translation); 516 n = n / sizeof(struct linux_prom_translation);
571 return n; 517
518 prom_trans_ents = n;
572} 519}
573 520
574static void __init remap_kernel(void) 521static void __init remap_kernel(void)
@@ -605,19 +552,21 @@ static void __init remap_kernel(void)
605 } 552 }
606} 553}
607 554
608static void __init inherit_prom_mappings(void)
609{
610 int n;
611 555
612 n = read_obp_translations(); 556static void __init inherit_prom_mappings_pre(void)
613 build_obp_pgtable(n); 557{
558 read_obp_translations();
614 559
615 /* Now fixup OBP's idea about where we really are mapped. */ 560 /* Now fixup OBP's idea about where we really are mapped. */
616 prom_printf("Remapping the kernel... "); 561 prom_printf("Remapping the kernel... ");
617 remap_kernel(); 562 remap_kernel();
618 563
619 prom_printf("done.\n"); 564 prom_printf("done.\n");
565}
620 566
567static void __init inherit_prom_mappings_post(void)
568{
569 build_obp_pgtable();
621 register_prom_callbacks(); 570 register_prom_callbacks();
622} 571}
623 572
@@ -1570,8 +1519,7 @@ void __init paging_init(void)
1570 1519
1571 swapper_pgd_zero = pgd_val(swapper_pg_dir[0]); 1520 swapper_pgd_zero = pgd_val(swapper_pg_dir[0]);
1572 1521
1573 /* Inherit non-locked OBP mappings. */ 1522 inherit_prom_mappings_pre();
1574 inherit_prom_mappings();
1575 1523
1576 /* Ok, we can use our TLB miss and window trap handlers safely. 1524 /* Ok, we can use our TLB miss and window trap handlers safely.
1577 * We need to do a quick peek here to see if we are on StarFire 1525 * We need to do a quick peek here to see if we are on StarFire
@@ -1582,15 +1530,23 @@ void __init paging_init(void)
1582 extern void setup_tba(int); 1530 extern void setup_tba(int);
1583 setup_tba(this_is_starfire); 1531 setup_tba(this_is_starfire);
1584 } 1532 }
1585
1586 inherit_locked_prom_mappings(1);
1587
1588 __flush_tlb_all(); 1533 __flush_tlb_all();
1589 1534
1535 /* Everything from this point forward, until we are done with
1536 * inherit_prom_mappings_post(), must complete successfully
1537 * without calling into the firmware. The firwmare page tables
1538 * have not been built, but we are running on the Linux kernel's
1539 * trap table.
1540 */
1541
1590 /* Setup bootmem... */ 1542 /* Setup bootmem... */
1591 pages_avail = 0; 1543 pages_avail = 0;
1592 last_valid_pfn = end_pfn = bootmem_init(&pages_avail); 1544 last_valid_pfn = end_pfn = bootmem_init(&pages_avail);
1593 1545
1546 inherit_prom_mappings_post();
1547
1548 inherit_locked_prom_mappings(1);
1549
1594#ifdef CONFIG_DEBUG_PAGEALLOC 1550#ifdef CONFIG_DEBUG_PAGEALLOC
1595 kernel_physical_mapping_init(); 1551 kernel_physical_mapping_init();
1596#endif 1552#endif