caddr_t mips_init(int argc, void *argv, caddr_t boot_esym) { char *cp; int i; caddr_t sd; u_int cputype; vaddr_t tlb_handler, xtlb_handler; extern char start[], edata[], end[]; extern char exception[], e_exception[]; extern char *hw_vendor, *hw_prod; extern void tlb_miss; extern void tlb_miss_err_r5k; extern void xtlb_miss; extern void xtlb_miss_err_r5k; /* * 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); #ifdef notyet /* * Make sure KSEG0 cacheability match what we intend to use. * * XXX This does not work as expected on IP30. Does ARCBios * XXX depend on this? */ cp0_setcfg((cp0_getcfg() & ~0x07) | CCA_CACHED); #endif /* * 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(); /* * Determine system type and set up configuration record data. */ hw_vendor = "SGI"; switch (sys_config.system_type) { #if defined(TGT_O2) case SGI_O2: bios_printf("Found SGI-IP32, setting up.\n"); hw_prod = "O2"; strlcpy(cpu_model, "IP32", sizeof(cpu_model)); ip32_setup(); sys_config.cpu[0].clock = 180000000; /* Reasonable default */ cp = Bios_GetEnvironmentVariable("cpufreq"); if (cp && atoi(cp, 10, NULL) > 100) sys_config.cpu[0].clock = atoi(cp, 10, NULL) * 1000000; break; #endif #if defined(TGT_ORIGIN200) || defined(TGT_ORIGIN2000) case SGI_O200: bios_printf("Found SGI-IP27, setting up.\n"); hw_prod = "Origin 200"; strlcpy(cpu_model, "IP27", sizeof(cpu_model)); ip27_setup(); break; case SGI_O300: bios_printf("Found SGI-IP35, setting up.\n"); hw_prod = "Origin 300"; /* IP27 is intentional, we use the same kernel */ strlcpy(cpu_model, "IP27", sizeof(cpu_model)); ip27_setup(); break; #endif #if defined(TGT_OCTANE) case SGI_OCTANE: bios_printf("Found SGI-IP30, setting up.\n"); hw_prod = "Octane"; strlcpy(cpu_model, "IP30", sizeof(cpu_model)); ip30_setup(); sys_config.cpu[0].clock = 175000000; /* Reasonable default */ cp = Bios_GetEnvironmentVariable("cpufreq"); if (cp && atoi(cp, 10, NULL) > 100) sys_config.cpu[0].clock = atoi(cp, 10, NULL) * 1000000; break; #endif default: bios_printf("Kernel doesn't support this system type!\n"); bios_printf("Halting system.\n"); Bios_Halt(); while(1); } /* * Read and store console type. */ cp = Bios_GetEnvironmentVariable("ConsoleOut"); if (cp != NULL && *cp != '\0') strlcpy(bios_console, cp, sizeof bios_console); /* Disable serial console if ARCS is telling us to use video. */ if (strncmp(bios_console, "video", 5) == 0) comconsaddr = 0; /* * 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) { #if defined(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_first_page != 0; i++) { u_int32_t fp, lp; u_int32_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 = KSEG0_TO_PHYS((vaddr_t)start); if (IS_XKPHYS((vaddr_t)ekern)) lastkernpa = XKPHYS_TO_PHYS((vaddr_t)ekern); else lastkernpa = KSEG0_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! */ u_int32_t xp = firstkernpage; uvm_page_physload(fp, xp, fp, xp, freelist); fp = lastkernpage; } if (lp > fp) uvm_page_physload(fp, lp, fp, lp, freelist); } switch (sys_config.system_type) { #if defined(TGT_O2) || defined(TGT_OCTANE) case SGI_O2: case SGI_OCTANE: sys_config.cpu[0].type = (cp0_get_prid() >> 8) & 0xff; sys_config.cpu[0].vers_maj = (cp0_get_prid() >> 4) & 0x0f; sys_config.cpu[0].vers_min = cp0_get_prid() & 0x0f; sys_config.cpu[0].fptype = (cp1_get_prid() >> 8) & 0xff; sys_config.cpu[0].fpvers_maj = (cp1_get_prid() >> 4) & 0x0f; sys_config.cpu[0].fpvers_min = cp1_get_prid() & 0x0f; /* * Configure TLB. */ switch(sys_config.cpu[0].type) { case MIPS_RM7000: /* Rev A (version >= 2) CPU's have 64 TLB entries. */ if (sys_config.cpu[0].vers_maj < 2) { sys_config.cpu[0].tlbsize = 48; } else { sys_config.cpu[0].tlbsize = 64; } break; case MIPS_R10000: case MIPS_R12000: case MIPS_R14000: sys_config.cpu[0].tlbsize = 64; break; default: sys_config.cpu[0].tlbsize = 48; break; } break; #endif default: break; } /* * Configure cache. */ switch(sys_config.cpu[0].type) { case MIPS_R10000: case MIPS_R12000: case MIPS_R14000: cputype = MIPS_R10000; break; case MIPS_R5000: case MIPS_RM7000: case MIPS_RM52X0: case MIPS_RM9000: cputype = MIPS_R5000; break; 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_O200: case SGI_O300: cputype = MIPS_R10000; break; } break; } switch (cputype) { case MIPS_R10000: Mips10k_ConfigCache(); sys_config._SyncCache = Mips10k_SyncCache; sys_config._InvalidateICache = Mips10k_InvalidateICache; sys_config._InvalidateICachePage = Mips10k_InvalidateICachePage; sys_config._SyncDCachePage = Mips10k_SyncDCachePage; sys_config._HitSyncDCache = Mips10k_HitSyncDCache; sys_config._IOSyncDCache = Mips10k_IOSyncDCache; sys_config._HitInvalidateDCache = Mips10k_HitInvalidateDCache; break; default: case MIPS_R5000: Mips5k_ConfigCache(); sys_config._SyncCache = Mips5k_SyncCache; sys_config._InvalidateICache = Mips5k_InvalidateICache; sys_config._InvalidateICachePage = Mips5k_InvalidateICachePage; sys_config._SyncDCachePage = Mips5k_SyncDCachePage; sys_config._HitSyncDCache = Mips5k_HitSyncDCache; sys_config._IOSyncDCache = Mips5k_IOSyncDCache; sys_config._HitInvalidateDCache = Mips5k_HitInvalidateDCache; break; } /* * 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... */ sys_config.cpu[0].tlbwired = UPAGES / 2; tlb_set_wired(0); tlb_flush(sys_config.cpu[0].tlbsize); tlb_set_wired(sys_config.cpu[0].tlbwired); /* * 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 = 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); /* * Allocate system data structures. */ i = (vsize_t)allocsys(NULL); sd = (caddr_t)pmap_steal_memory(i, NULL, NULL); allocsys(sd); /* * 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) { 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; we test on the `rounded' * cputype value instead of sys_config.cpu[0].type; this * causes RM7k and RM9k to be included, just to be on the * safe side. */ tlb_handler = (vaddr_t)&tlb_miss_err_r5k; xtlb_handler = (vaddr_t)&xtlb_miss_err_r5k; break; default: tlb_handler = (vaddr_t)&tlb_miss; xtlb_handler = (vaddr_t)&xtlb_miss; break; } build_trampoline(TLB_MISS_EXC_VEC, tlb_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(); #ifdef DDB db_machine_init(); if (boothowto & RB_KDB) Debugger(); #endif /* * Return new stack pointer. */ return ((caddr_t)proc0paddr + USPACE - 64); }
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); }