📄 init.c
字号:
case cheetah: phys_page = cheetah_get_litlb_data(sparc64_highest_locked_tlbent()); break; }; phys_page &= _PAGE_PADDR; phys_page += ((unsigned long)&prom_boot_page - (unsigned long)KERNBASE); if (tlb_type == spitfire) { /* Lock this into i/d tlb entry 59 */ __asm__ __volatile__( "stxa %%g0, [%2] %3\n\t" "stxa %0, [%1] %4\n\t" "membar #Sync\n\t" "flush %%g6\n\t" "stxa %%g0, [%2] %5\n\t" "stxa %0, [%1] %6\n\t" "membar #Sync\n\t" "flush %%g6" : : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), "r" (59 << 3), "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS) : "memory"); } else if (tlb_type == cheetah) { /* Lock this into i/d tlb-0 entry 11 */ __asm__ __volatile__( "stxa %%g0, [%2] %3\n\t" "stxa %0, [%1] %4\n\t" "membar #Sync\n\t" "flush %%g6\n\t" "stxa %%g0, [%2] %5\n\t" "stxa %0, [%1] %6\n\t" "membar #Sync\n\t" "flush %%g6" : : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), "r" ((0 << 16) | (11 << 3)), "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS) : "memory"); } else { /* Implement me :-) */ BUG(); } tte_vaddr = (unsigned long) KERNBASE; /* Spitfire Errata #32 workaround */ __asm__ __volatile__("stxa %0, [%1] %2\n\t" "flush %%g6" : /* No outputs */ : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); if (tlb_type == spitfire) tte_data = spitfire_get_dtlb_data(sparc64_highest_locked_tlbent()); else tte_data = cheetah_get_ldtlb_data(sparc64_highest_locked_tlbent()); kern_locked_tte_data = tte_data; remap_func = (void *) ((unsigned long) &prom_remap - (unsigned long) &prom_boot_page); /* Spitfire Errata #32 workaround */ __asm__ __volatile__("stxa %0, [%1] %2\n\t" "flush %%g6" : /* No outputs */ : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); remap_func((tlb_type == spitfire ? (spitfire_get_dtlb_data(sparc64_highest_locked_tlbent()) & _PAGE_PADDR) : (cheetah_get_litlb_data(sparc64_highest_locked_tlbent()) & _PAGE_PADDR)), (unsigned long) KERNBASE, prom_get_mmu_ihandle()); if (bigkernel) remap_func(((tte_data + 0x400000) & _PAGE_PADDR), (unsigned long) KERNBASE + 0x400000, prom_get_mmu_ihandle()); /* Flush out that temporary mapping. */ spitfire_flush_dtlb_nucleus_page(0x0); spitfire_flush_itlb_nucleus_page(0x0); /* Now lock us back into the TLBs via OBP. */ prom_dtlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr); prom_itlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr); if (bigkernel) { prom_dtlb_load(sparc64_highest_locked_tlbent()-1, tte_data + 0x400000, tte_vaddr + 0x400000); prom_itlb_load(sparc64_highest_locked_tlbent()-1, tte_data + 0x400000, tte_vaddr + 0x400000); } /* Re-read translations property. */ if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) { prom_printf("Couldn't get translation property\n"); prom_halt(); } n = n / sizeof(*trans); for (i = 0; i < n; i++) { unsigned long vaddr = trans[i].virt; unsigned long size = trans[i].size; if (vaddr < 0xf0000000UL) { unsigned long avoid_start = (unsigned long) KERNBASE; unsigned long avoid_end = avoid_start + (4 * 1024 * 1024); if (bigkernel) avoid_end += (4 * 1024 * 1024); if (vaddr < avoid_start) { unsigned long top = vaddr + size; if (top > avoid_start) top = avoid_start; prom_unmap(top - vaddr, vaddr); } if ((vaddr + size) > avoid_end) { unsigned long bottom = vaddr; if (bottom < avoid_end) bottom = avoid_end; prom_unmap((vaddr + size) - bottom, bottom); } } } prom_printf("done.\n"); register_prom_callbacks();}/* The OBP specifications for sun4u mark 0xfffffffc00000000 and * upwards as reserved for use by the firmware (I wonder if this * will be the same on Cheetah...). We use this virtual address * range for the VPTE table mappings of the nucleus so we need * to zap them when we enter the PROM. -DaveM */static void __flush_nucleus_vptes(void){ unsigned long prom_reserved_base = 0xfffffffc00000000UL; int i; /* Only DTLB must be checked for VPTE entries. */ if (tlb_type == spitfire) { for (i = 0; i < 63; i++) { unsigned long tag; /* Spitfire Errata #32 workaround */ __asm__ __volatile__("stxa %0, [%1] %2\n\t" "flush %%g6" : /* No outputs */ : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); tag = spitfire_get_dtlb_tag(i); if (((tag & ~(PAGE_MASK)) == 0) && ((tag & (PAGE_MASK)) >= prom_reserved_base)) { __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" "membar #Sync" : /* no outputs */ : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); spitfire_put_dtlb_data(i, 0x0UL); } } } else if (tlb_type == cheetah) { for (i = 0; i < 512; i++) { unsigned long tag = cheetah_get_dtlb_tag(i); if ((tag & ~PAGE_MASK) == 0 && (tag & PAGE_MASK) >= prom_reserved_base) { __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" "membar #Sync" : /* no outputs */ : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); cheetah_put_dtlb_data(i, 0x0UL); } } } else { /* Implement me :-) */ BUG(); }}static int prom_ditlb_set = 0;struct prom_tlb_entry { int tlb_ent; unsigned long tlb_tag; unsigned long tlb_data;};struct prom_tlb_entry prom_itlb[16], prom_dtlb[16];void prom_world(int enter){ unsigned long pstate; int i; if (!enter) set_fs(current->thread.current_ds); if (!prom_ditlb_set) return; /* Make sure the following runs atomically. */ __asm__ __volatile__("flushw\n\t" "rdpr %%pstate, %0\n\t" "wrpr %0, %1, %%pstate" : "=r" (pstate) : "i" (PSTATE_IE)); if (enter) { /* Kick out nucleus VPTEs. */ __flush_nucleus_vptes(); /* Install PROM world. */ for (i = 0; i < 16; i++) { if (prom_dtlb[i].tlb_ent != -1) { __asm__ __volatile__("stxa %0, [%1] %2\n\t" "membar #Sync" : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); if (tlb_type == spitfire) spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, prom_dtlb[i].tlb_data); else if (tlb_type == cheetah) cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, prom_dtlb[i].tlb_data); } if (prom_itlb[i].tlb_ent != -1) { __asm__ __volatile__("stxa %0, [%1] %2\n\t" "membar #Sync" : : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); if (tlb_type == spitfire) spitfire_put_itlb_data(prom_itlb[i].tlb_ent, prom_itlb[i].tlb_data); else if (tlb_type == cheetah) cheetah_put_litlb_data(prom_itlb[i].tlb_ent, prom_itlb[i].tlb_data); } } } else { for (i = 0; i < 16; i++) { if (prom_dtlb[i].tlb_ent != -1) { __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" "membar #Sync" : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); if (tlb_type == spitfire) spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL); else cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, 0x0UL); } if (prom_itlb[i].tlb_ent != -1) { __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" "membar #Sync" : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); if (tlb_type == spitfire) spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL); else cheetah_put_litlb_data(prom_itlb[i].tlb_ent, 0x0UL); } } } __asm__ __volatile__("wrpr %0, 0, %%pstate" : : "r" (pstate));}void inherit_locked_prom_mappings(int save_p){ int i; int dtlb_seen = 0; int itlb_seen = 0; /* Fucking losing PROM has more mappings in the TLB, but * it (conveniently) fails to mention any of these in the * translations property. The only ones that matter are * the locked PROM tlb entries, so we impose the following * irrecovable rule on the PROM, it is allowed 8 locked * entries in the ITLB and 8 in the DTLB. * * Supposedly the upper 16GB of the address space is * reserved for OBP, BUT I WISH THIS WAS DOCUMENTED * SOMEWHERE!!!!!!!!!!!!!!!!! Furthermore the entire interface * used between the client program and the firmware on sun5 * systems to coordinate mmu mappings is also COMPLETELY * UNDOCUMENTED!!!!!! Thanks S(t)un! */ if (save_p) { for (i = 0; i < 16; i++) { prom_itlb[i].tlb_ent = -1; prom_dtlb[i].tlb_ent = -1; } } if (tlb_type == spitfire) { int high = SPITFIRE_HIGHEST_LOCKED_TLBENT - bigkernel; for (i = 0; i < high; i++) { unsigned long data; /* Spitfire Errata #32 workaround */ __asm__ __volatile__("stxa %0, [%1] %2\n\t" "flush %%g6" : /* No outputs */ : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); data = spitfire_get_dtlb_data(i); if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { unsigned long tag; /* Spitfire Errata #32 workaround */ __asm__ __volatile__("stxa %0, [%1] %2\n\t" "flush %%g6" : /* No outputs */ : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); tag = spitfire_get_dtlb_tag(i); if (save_p) { prom_dtlb[dtlb_seen].tlb_ent = i; prom_dtlb[dtlb_seen].tlb_tag = tag; prom_dtlb[dtlb_seen].tlb_data = data; } __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" "membar #Sync" : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); spitfire_put_dtlb_data(i, 0x0UL); dtlb_seen++; if (dtlb_seen > 15) break; } } for (i = 0; i < high; i++) { unsigned long data; /* Spitfire Errata #32 workaround */ __asm__ __volatile__("stxa %0, [%1] %2\n\t" "flush %%g6" : /* No outputs */ : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); data = spitfire_get_itlb_data(i); if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { unsigned long tag; /* Spitfire Errata #32 workaround */ __asm__ __volatile__("stxa %0, [%1] %2\n\t" "flush %%g6" : /* No outputs */ : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); tag = spitfire_get_itlb_tag(i); if (save_p) { prom_itlb[itlb_seen].tlb_ent = i; prom_itlb[itlb_seen].tlb_tag = tag; prom_itlb[itlb_seen].tlb_data = data; } __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" "membar #Sync" : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); spitfire_put_itlb_data(i, 0x0UL); itlb_seen++; if (itlb_seen > 15) break; } } } else if (tlb_type == cheetah) { int high = CHEETAH_HIGHEST_LOCKED_TLBENT - bigkernel; for (i = 0; i < high; i++) { unsigned long data; data = cheetah_get_ldtlb_data(i); if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { unsigned long tag; tag = cheetah_get_ldtlb_tag(i); if (save_p) { prom_dtlb[dtlb_seen].tlb_ent = i; prom_dtlb[dtlb_seen].tlb_tag = tag; prom_dtlb[dtlb_seen].tlb_data = data; } __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" "membar #Sync" : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); cheetah_put_ldtlb_data(i, 0x0UL); dtlb_seen++; if (dtlb_seen > 15) break; } } for (i = 0; i < high; i++) { unsigned long data; data = cheetah_get_litlb_data(i); if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { unsigned long tag; tag = cheetah_get_litlb_tag(i); if (save_p) { prom_itlb[itlb_seen].tlb_ent = i; prom_itlb[itlb_seen].tlb_tag = tag; prom_itlb[itlb_seen].tlb_data = data; } __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" "membar #Sync" : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); cheetah_put_litlb_data(i, 0x0UL); itlb_seen++; if (itlb_seen > 15) break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -