static int mmu_mapin(vm_offset_t va, vm_size_t len) { vm_offset_t pa, mva; u_long data; if (va + len > curkva) curkva = va + len; pa = (vm_offset_t)-1; len += va & PAGE_MASK_4M; va &= ~PAGE_MASK_4M; while (len) { if (dtlb_va_to_pa(va) == (vm_offset_t)-1 || itlb_va_to_pa(va) == (vm_offset_t)-1) { /* Allocate a physical page, claim the virtual area */ if (pa == (vm_offset_t)-1) { pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M, PAGE_SIZE_4M); if (pa == (vm_offset_t)-1) panic("out of memory"); mva = (vm_offset_t)OF_claim_virt(va, PAGE_SIZE_4M, 0); if (mva != va) { panic("can't claim virtual page " "(wanted %#lx, got %#lx)", va, mva); } /* The mappings may have changed, be paranoid. */ continue; } /* * Actually, we can only allocate two pages less at * most (depending on the kernel TSB size). */ if (dtlb_slot >= dtlb_slot_max) panic("mmu_mapin: out of dtlb_slots"); if (itlb_slot >= itlb_slot_max) panic("mmu_mapin: out of itlb_slots"); data = TD_V | TD_4M | TD_PA(pa) | TD_L | TD_CP | TD_CV | TD_P | TD_W; dtlb_store[dtlb_slot].te_pa = pa; dtlb_store[dtlb_slot].te_va = va; itlb_store[itlb_slot].te_pa = pa; itlb_store[itlb_slot].te_va = va; dtlb_slot++; itlb_slot++; dtlb_enter(va, data); itlb_enter(va, data); pa = (vm_offset_t)-1; } len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; va += PAGE_SIZE_4M; } if (pa != (vm_offset_t)-1) OF_release_phys(pa, PAGE_SIZE_4M); return 0; }
void * OF_claim(void *virt, u_int size, u_int align) { #define SUNVMOF #ifndef SUNVMOF struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t virt; cell_t size; cell_t align; cell_t baseaddr; } args; args.name = ADR2CELL("claim"); args.nargs = 3; args.nreturns = 1; args.virt = virt; args.size = size; args.align = align; if (openfirmware(&args) == -1) return (void *)-1; return (void *)args.baseaddr; #else /* * Sun Ultra machines run the firmware with VM enabled, * so you need to handle allocating and mapping both * virtual and physical memory. Ugh. */ paddr_t paddr; void * newvirt = NULL; if (virt == NULL) { virt = (void *)OF_alloc_virt(size, align); if (virt == (void *)-1LL) { printf("OF_alloc_virt(%d,%d) failed w/%x\n", size, align, virt); return virt; } } else { newvirt = (void *)OF_claim_virt((vaddr_t)virt, size); if (newvirt == (void *)-1LL) { printf("OF_claim_virt(%x,%d) failed w/%x\n", virt, size, newvirt); return newvirt; } virt = newvirt; } if ((paddr = OF_alloc_phys(size, align)) == (paddr_t)-1LL) { printf("OF_alloc_phys(%d,%d) failed\n", size, align); OF_free_virt((vaddr_t)virt, size); return (void *)-1LL; } if (OF_map_phys(paddr, size, (vaddr_t)virt, -1) == -1) { printf("OF_map_phys(%x,%d,%x,%d) failed\n", paddr, size, virt, -1); OF_free_phys((paddr_t)paddr, size); OF_free_virt((vaddr_t)virt, size); return (void *)-1LL; } return virt; #endif }