/* * Translate a kernel virtual address to a physical address. */ int _kvm_kvatop(kvm_t *kd, u_long va, paddr_t *pa) { struct vmstate *vm; pt_entry_t pte; u_long idx, addr; int offset; if (ISALIVE(kd)) { _kvm_err(kd, 0, "vatop called in live kernel!"); return((off_t)0); } vm = kd->vmst; offset = (int)va & vm->pagemask; /* * If we are initializing (kernel segment table pointer not yet set) * then return pa == va to avoid infinite recursion. */ if (vm->Sysmap == 0) { *pa = va; return vm->pagesize - offset; } /* * Check for direct-mapped segments */ if (IS_XKPHYS(va)) { *pa = XKPHYS_TO_PHYS(va); return vm->pagesize - offset; } if (va >= (vaddr_t)CKSEG0_BASE && va < (vaddr_t)CKSSEG_BASE) { *pa = CKSEG0_TO_PHYS(va); return vm->pagesize - offset; } if (va < vm->Sysmapbase) goto invalid; idx = (va - vm->Sysmapbase) >> vm->pageshift; if (idx >= vm->Sysmapsize) goto invalid; addr = (u_long)vm->Sysmap + idx; /* * Can't use KREAD to read kernel segment table entries. * Fortunately it is 1-to-1 mapped so we don't have to. */ if (_kvm_pread(kd, kd->pmfd, (char *)&pte, sizeof(pte), (off_t)addr) < 0) goto invalid; if (!(pte & PG_V)) goto invalid; *pa = (pte & PG_FRAME) | (paddr_t)offset; return vm->pagesize - offset; invalid: _kvm_err(kd, 0, "invalid address (%lx)", va); return (0); }
paddr_t if_cnmac_kvtophys(vaddr_t kva) { if (IS_XKPHYS(kva)) return XKPHYS_TO_PHYS(kva); else if (kva >= CKSEG0_BASE && kva < CKSEG0_BASE + CKSEG_SIZE) return CKSEG0_TO_PHYS(kva); else if (kva >= CKSEG1_BASE && kva < CKSEG1_BASE + CKSEG_SIZE) return CKSEG1_TO_PHYS(kva); panic("%s: non-direct mapped address %p", __func__, (void *)kva); }
paddr_t if_cnmac_kvtophys(vaddr_t kva) { if (IS_XKPHYS(kva)) return XKPHYS_TO_PHYS(kva); else if (kva >= CKSEG0_BASE && kva < CKSEG0_BASE + CKSEG_SIZE) return CKSEG0_TO_PHYS(kva); else if (kva >= CKSEG1_BASE && kva < CKSEG1_BASE + CKSEG_SIZE) return CKSEG1_TO_PHYS(kva); printf("kva %lx is not able to convert physical address\n", kva); panic("if_cnmac_kvtophys"); }
/*ARGSUSED*/ int mmrw(dev_t dev, struct uio *uio, int flags) { struct iovec *iov; boolean_t allowed; int error = 0; size_t c; vaddr_t v; while (uio->uio_resid > 0 && error == 0) { iov = uio->uio_iov; if (iov->iov_len == 0) { uio->uio_iov++; uio->uio_iovcnt--; if (uio->uio_iovcnt < 0) panic("mmrw"); continue; } switch (minor(dev)) { /* minor device 0 is physical memory */ case 0: v = uio->uio_offset; c = iov->iov_len; if (v + c < v || v + c > ptoa((psize_t)physmem)) return (EFAULT); v = (vaddr_t)PHYS_TO_XKPHYS(v, CCA_NONCOHERENT); error = uiomove((caddr_t)v, c, uio); continue; /* minor device 1 is kernel memory */ case 1: v = uio->uio_offset; c = ulmin(iov->iov_len, MAXPHYS); /* Allow access to RAM through XKPHYS... */ if (IS_XKPHYS(v)) allowed = is_memory_range(XKPHYS_TO_PHYS(v), (psize_t)c, 0); /* ...or through CKSEG0... */ else if (v >= CKSEG0_BASE && v < CKSEG0_BASE + CKSEG_SIZE) allowed = is_memory_range(CKSEG0_TO_PHYS(v), (psize_t)c, CKSEG_SIZE); /* ...or through CKSEG1... */ else if (v >= CKSEG1_BASE && v < CKSEG1_BASE + CKSEG_SIZE) allowed = is_memory_range(CKSEG1_TO_PHYS(v), (psize_t)c, CKSEG_SIZE); /* ...otherwise, check it's within kernel kvm limits. */ else allowed = uvm_kernacc((caddr_t)v, c, uio->uio_rw == UIO_READ ? B_READ : B_WRITE); if (allowed) { error = uiomove((caddr_t)v, c, uio); continue; } else { return (EFAULT); } /* minor device 2 is EOF/RATHOLE */ case 2: if (uio->uio_rw == UIO_WRITE) uio->uio_resid = 0; return (0); /* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */ case 12: if (uio->uio_rw == UIO_WRITE) { c = iov->iov_len; break; } if (zeropage == NULL) zeropage = malloc(PAGE_SIZE, M_TEMP, M_WAITOK | M_ZERO); c = ulmin(iov->iov_len, PAGE_SIZE); error = uiomove(zeropage, c, uio); continue; default: return (ENODEV); } if (error) break; iov->iov_base += c; iov->iov_len -= c; uio->uio_offset += c; uio->uio_resid -= c; } return error; }
caddr_t mips_init(int argc, void *argv, caddr_t boot_esym) { char *cp; int i; u_int cputype; vaddr_t xtlb_handler; extern char start[], edata[], end[]; extern char exception[], e_exception[]; extern char *hw_vendor; #ifdef MULTIPROCESSOR /* * Set curcpu address on primary processor. */ setcurcpu(&cpu_info_primary); #endif /* * Make sure we can access the extended address space. * Note that r10k and later do not allow XUSEG accesses * from kernel mode unless SR_UX is set. */ setsr(getsr() | SR_KX | SR_UX); /* * Clear the compiled BSS segment in OpenBSD code. */ bzero(edata, end - edata); /* * Reserve space for the symbol table, if it exists. */ ssym = (char *)*(u_int64_t *)end; /* Attempt to locate ELF header and symbol table after kernel. */ if (end[0] == ELFMAG0 && end[1] == ELFMAG1 && end[2] == ELFMAG2 && end[3] == ELFMAG3 ) { /* ELF header exists directly after kernel. */ ssym = end; esym = boot_esym; ekern = esym; } else if (((long)ssym - (long)end) >= 0 && ((long)ssym - (long)end) <= 0x1000 && ssym[0] == ELFMAG0 && ssym[1] == ELFMAG1 && ssym[2] == ELFMAG2 && ssym[3] == ELFMAG3 ) { /* Pointers exist directly after kernel. */ esym = (char *)*((u_int64_t *)end + 1); ekern = esym; } else { /* Pointers aren't setup either... */ ssym = NULL; esym = NULL; ekern = end; } /* * Initialize the system type and set up memory layout. * Note that some systems have a more complex memory setup. */ bios_ident(); /* * Read and store ARCBios variables for future reference. */ cp = Bios_GetEnvironmentVariable("ConsoleOut"); if (cp != NULL && *cp != '\0') strlcpy(bios_console, cp, sizeof(bios_console)); cp = Bios_GetEnvironmentVariable("gfx"); if (cp != NULL && *cp != '\0') strlcpy(bios_graphics, cp, sizeof(bios_graphics)); cp = Bios_GetEnvironmentVariable("keybd"); if (cp != NULL && *cp != '\0') strlcpy(bios_keyboard, cp, sizeof(bios_keyboard)); /* * Determine system type and set up configuration record data. */ hw_vendor = "SGI"; switch (sys_config.system_type) { #ifdef TGT_O2 case SGI_O2: bios_printf("Found SGI-IP32, setting up.\n"); strlcpy(cpu_model, "IP32", sizeof(cpu_model)); ip32_setup(); break; #endif #ifdef TGT_ORIGIN case SGI_IP27: bios_printf("Found SGI-IP27, setting up.\n"); strlcpy(cpu_model, "IP27", sizeof(cpu_model)); ip27_setup(); break; case SGI_IP35: bios_printf("Found SGI-IP35, setting up.\n"); /* IP27 is intentional, we use the same kernel */ strlcpy(cpu_model, "IP27", sizeof(cpu_model)); ip27_setup(); break; #endif #ifdef TGT_OCTANE case SGI_OCTANE: bios_printf("Found SGI-IP30, setting up.\n"); strlcpy(cpu_model, "IP30", sizeof(cpu_model)); ip30_setup(); break; #endif default: bios_printf("Kernel doesn't support this system type!\n"); bios_printf("Halting system.\n"); Bios_Halt(); while(1); } /* * Look at arguments passed to us and compute boothowto. */ boothowto = RB_AUTOBOOT; dobootopts(argc, argv); /* * Figure out where we supposedly booted from. */ cp = Bios_GetEnvironmentVariable("OSLoadPartition"); if (cp == NULL) cp = "unknown"; if (strlcpy(osloadpartition, cp, sizeof osloadpartition) >= sizeof osloadpartition) bios_printf("Value of `OSLoadPartition' is too large.\n" "The kernel might not be able to find out its root device.\n"); /* * Read platform-specific environment variables. */ switch (sys_config.system_type) { #ifdef TGT_O2 case SGI_O2: /* Get Ethernet address from ARCBIOS. */ cp = Bios_GetEnvironmentVariable("eaddr"); if (cp != NULL && strlen(cp) > 0) strlcpy(bios_enaddr, cp, sizeof bios_enaddr); break; #endif default: break; } /* * Set pagesize to enable use of page macros and functions. * Commit available memory to UVM system. */ uvmexp.pagesize = PAGE_SIZE; uvm_setpagesize(); for (i = 0; i < MAXMEMSEGS && mem_layout[i].mem_last_page != 0; i++) { uint64_t fp, lp; uint64_t firstkernpage, lastkernpage; unsigned int freelist; paddr_t firstkernpa, lastkernpa; if (IS_XKPHYS((vaddr_t)start)) firstkernpa = XKPHYS_TO_PHYS((vaddr_t)start); else firstkernpa = CKSEG0_TO_PHYS((vaddr_t)start); if (IS_XKPHYS((vaddr_t)ekern)) lastkernpa = XKPHYS_TO_PHYS((vaddr_t)ekern); else lastkernpa = CKSEG0_TO_PHYS((vaddr_t)ekern); firstkernpage = atop(trunc_page(firstkernpa)); lastkernpage = atop(round_page(lastkernpa)); fp = mem_layout[i].mem_first_page; lp = mem_layout[i].mem_last_page; freelist = mem_layout[i].mem_freelist; /* Account for kernel and kernel symbol table. */ if (fp >= firstkernpage && lp < lastkernpage) continue; /* In kernel. */ if (lp < firstkernpage || fp > lastkernpage) { uvm_page_physload(fp, lp, fp, lp, freelist); continue; /* Outside kernel. */ } if (fp >= firstkernpage) fp = lastkernpage; else if (lp < lastkernpage) lp = firstkernpage; else { /* Need to split! */ uint64_t xp = firstkernpage; uvm_page_physload(fp, xp, fp, xp, freelist); fp = lastkernpage; } if (lp > fp) { uvm_page_physload(fp, lp, fp, lp, freelist); } } /* * Configure cache. */ switch (bootcpu_hwinfo.type) { #ifdef CPU_R10000 case MIPS_R10000: case MIPS_R12000: case MIPS_R14000: cputype = MIPS_R10000; break; #endif #ifdef CPU_R5000 case MIPS_R5000: case MIPS_RM52X0: cputype = MIPS_R5000; break; #endif #ifdef CPU_RM7000 case MIPS_RM7000: case MIPS_RM9000: cputype = MIPS_R5000; break; #endif default: /* * If we can't identify the cpu type, it must be * r10k-compatible on Octane and Origin families, and * it is likely to be r5k-compatible on O2. */ switch (sys_config.system_type) { case SGI_O2: cputype = MIPS_R5000; break; default: case SGI_OCTANE: case SGI_IP27: case SGI_IP35: cputype = MIPS_R10000; break; } break; } switch (cputype) { default: #if defined(CPU_R5000) || defined(CPU_RM7000) case MIPS_R5000: Mips5k_ConfigCache(curcpu()); sys_config._SyncCache = Mips5k_SyncCache; sys_config._InvalidateICache = Mips5k_InvalidateICache; sys_config._SyncDCachePage = Mips5k_SyncDCachePage; sys_config._HitSyncDCache = Mips5k_HitSyncDCache; sys_config._IOSyncDCache = Mips5k_IOSyncDCache; sys_config._HitInvalidateDCache = Mips5k_HitInvalidateDCache; break; #endif #ifdef CPU_R10000 case MIPS_R10000: Mips10k_ConfigCache(curcpu()); sys_config._SyncCache = Mips10k_SyncCache; sys_config._InvalidateICache = Mips10k_InvalidateICache; sys_config._SyncDCachePage = Mips10k_SyncDCachePage; sys_config._HitSyncDCache = Mips10k_HitSyncDCache; sys_config._IOSyncDCache = Mips10k_IOSyncDCache; sys_config._HitInvalidateDCache = Mips10k_HitInvalidateDCache; break; #endif } /* * Last chance to call the BIOS. Wiping the TLB means the BIOS' data * areas are demapped on most systems. */ delay(20*1000); /* Let any UART FIFO drain... */ tlb_set_page_mask(TLB_PAGE_MASK); tlb_set_wired(0); tlb_flush(bootcpu_hwinfo.tlbsize); tlb_set_wired(UPAGES / 2); /* * Get a console, very early but after initial mapping setup. */ consinit(); printf("Initial setup done, switching console.\n"); /* * Init message buffer. */ msgbufbase = (caddr_t)pmap_steal_memory(MSGBUFSIZE, NULL, NULL); initmsgbuf(msgbufbase, MSGBUFSIZE); /* * Allocate U page(s) for proc[0], pm_tlbpid 1. */ proc0.p_addr = proc0paddr = curcpu()->ci_curprocpaddr = (struct user *)pmap_steal_memory(USPACE, NULL, NULL); proc0.p_md.md_regs = (struct trap_frame *)&proc0paddr->u_pcb.pcb_regs; tlb_set_pid(1); /* * Bootstrap VM system. */ pmap_bootstrap(); /* * Copy down exception vector code. */ bcopy(exception, (char *)CACHE_ERR_EXC_VEC, e_exception - exception); bcopy(exception, (char *)GEN_EXC_VEC, e_exception - exception); /* * Build proper TLB refill handler trampolines. */ switch (cputype) { #if defined(CPU_R5000) || defined(CPU_RM7000) case MIPS_R5000: { /* * R5000 processors need a specific chip bug workaround * in their tlb handlers. Theoretically only revision 1 * of the processor need it, but there is evidence * later versions also need it. * * This is also necessary on RM52x0 and most RM7k/RM9k, * and is a documented errata for these chips. */ extern void xtlb_miss_err_r5k; xtlb_handler = (vaddr_t)&xtlb_miss_err_r5k; } break; #endif default: { extern void xtlb_miss; xtlb_handler = (vaddr_t)&xtlb_miss; } break; } build_trampoline(TLB_MISS_EXC_VEC, xtlb_handler); build_trampoline(XTLB_MISS_EXC_VEC, xtlb_handler); /* * Turn off bootstrap exception vectors. */ setsr(getsr() & ~SR_BOOT_EXC_VEC); proc0.p_md.md_regs->sr = getsr(); /* * Clear out the I and D caches. */ Mips_SyncCache(curcpu()); #ifdef DDB db_machine_init(); if (boothowto & RB_KDB) Debugger(); #endif /* * Return new stack pointer. */ return ((caddr_t)proc0paddr + USPACE - 64); }