machdep.c revision 181236
1 /* $OpenBSD: machdep.c,v 1.33 1998/09/15 10:58:54 pefo Exp $ */ 2/* tracked to 1.38 */ 3/* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the Systems Programming Group of the University of Utah Computer 10 * Science Department, The Mach Operating System project at 11 * Carnegie-Mellon University and Ralph Campbell. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * from: @(#)machdep.c 8.3 (Berkeley) 1/12/94 38 * Id: machdep.c,v 1.33 1998/09/15 10:58:54 pefo Exp 39 * JNPR: machdep.c,v 1.11.2.3 2007/08/29 12:24:49 girish 40 */ 41 42#include <sys/cdefs.h> 43__FBSDID("$FreeBSD: head/sys/mips/mips/machdep.c 181236 2008-08-03 14:11:06Z trhodes $"); 44 45#include "opt_md.h" 46#include "opt_ddb.h" 47 48#include <sys/param.h> 49#include <sys/proc.h> 50#include <sys/systm.h> 51#include <sys/buf.h> 52#include <sys/bus.h> 53#include <sys/conf.h> 54#include <sys/cpu.h> 55#include <sys/kernel.h> 56#include <sys/linker.h> 57#include <sys/malloc.h> 58#include <sys/mbuf.h> 59#include <sys/msgbuf.h> 60#include <sys/reboot.h> 61#include <sys/sched.h> 62#include <sys/sysctl.h> 63#include <sys/sysproto.h> 64#include <sys/vmmeter.h> 65 66#include <vm/vm.h> 67#include <vm/vm_kern.h> 68#include <vm/vm_object.h> 69#include <vm/vm_page.h> 70#include <vm/pmap.h> 71#include <vm/vm_map.h> 72#include <vm/vm_pager.h> 73#include <vm/vm_extern.h> 74#include <sys/socket.h> 75 76#include <sys/user.h> 77#include <sys/cons.h> 78#include <sys/syslog.h> 79#include <machine/cache.h> 80#include <machine/cpu.h> 81#include <machine/pltfm.h> 82#include <net/netisr.h> 83#include <machine/md_var.h> 84#if 0 85#include <machine/defs.h> 86#endif 87#include <machine/clock.h> 88#include <machine/asm.h> 89#include <machine/bootinfo.h> 90#ifdef DDB 91#include <sys/kdb.h> 92#include <ddb/ddb.h> 93#endif 94 95#include <sys/random.h> 96#include <net/if.h> 97 98#define BOOTINFO_DEBUG 0 99 100char machine[] = "mips"; 101SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "Machine class"); 102 103static char cpu_model[30]; 104SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, "Machine model"); 105 106#if 0 /* see comment below */ 107static void getmemsize(void); 108#endif 109 110int cold = 1; 111int Maxmem; 112long realmem = 0; 113int cpu_clock = MIPS_DEFAULT_HZ; 114SYSCTL_INT(_hw, OID_AUTO, clockrate, CTLFLAG_RD, 115 &cpu_clock, 0, "CPU instruction clock rate"); 116int clocks_running = 0; 117 118vm_offset_t kstack0; 119 120#ifdef SMP 121struct pcpu __pcpu[32]; 122char pcpu_boot_stack[KSTACK_PAGES * PAGE_SIZE * (MAXCPU-1)]; 123#else 124struct pcpu pcpu; 125struct pcpu *pcpup = &pcpu; 126#endif 127 128vm_offset_t phys_avail[10]; 129#ifdef UNIMPLEMENTED 130struct platform platform; 131#endif 132 133vm_paddr_t mips_wired_tlb_physmem_start; 134vm_paddr_t mips_wired_tlb_physmem_end; 135u_int need_wired_tlb_page_pool; 136 137static void cpu_startup(void *); 138SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); 139 140struct kva_md_info kmi; 141 142int cpucfg; /* Value of processor config register */ 143int num_tlbentries = 64; /* Size of the CPU tlb */ 144int cputype; 145 146extern char MipsException[], MipsExceptionEnd[]; 147 148/* TLB miss handler address and end */ 149extern char MipsTLBMiss[], MipsTLBMissEnd[]; 150 151/* Cache error handler */ 152extern char MipsCache[], MipsCacheEnd[]; 153 154extern char edata[], end[]; 155 156u_int32_t bootdev; 157struct bootinfo bootinfo; 158 159 160static void 161cpu_startup(void *dummy) 162{ 163 164 if (boothowto & RB_VERBOSE) 165 bootverbose++; 166 167 /* 168 * Good {morning,afternoon,evening,night}. 169 */ 170 printf("%s", version); 171 172 printf("real memory = %lu (%luK bytes)\n", ptoa(Maxmem), 173 ptoa(Maxmem) / 1024); 174 realmem = Maxmem; 175 /* 176 * Display any holes after the first chunk of extended memory. 177 */ 178 if (bootverbose) { 179 int indx; 180 181 printf("Physical memory chunk(s):\n"); 182 for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) { 183 int size1 = phys_avail[indx + 1] - phys_avail[indx]; 184 185 printf("0x%08x - 0x%08x, %u bytes (%u pages)\n", 186 phys_avail[indx], phys_avail[indx + 1] - 1, size1, 187 size1 / PAGE_SIZE); 188 } 189 } 190 191 vm_ksubmap_init(&kmi); 192 193 printf("avail memory = %lu (%luMB)\n", ptoa(cnt.v_free_count), 194 ptoa(cnt.v_free_count) / 1048576); 195 196 /* 197 * Set up buffers, so they can be used to read disk labels. 198 */ 199 bufinit(); 200 vm_pager_bufferinit(); 201} 202 203/* 204 * Shutdown the CPU as much as possible 205 */ 206void 207cpu_reset(void) 208{ 209 for (;;) 210 ; 211} 212 213/* Get current clock frequency for the given cpu id. */ 214int 215cpu_est_clockrate(int cpu_id, uint64_t *rate) 216{ 217 218 return (ENXIO); 219} 220 221/* 222 * Shutdown the CPU as much as possible 223 */ 224void 225cpu_halt(void) 226{ 227 for (;;) 228 ; 229} 230 231#ifdef PORT_TO_JMIPS 232 233static int 234sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS) 235{ 236} 237 238SYSCTL_PROC(_machdep, CPU_ADJKERNTZ, adjkerntz, CTLTYPE_INT | CTLFLAG_RW, 239 &adjkerntz, 0, sysctl_machdep_adjkerntz, "I", 240 "Local offset from GMT in seconds"); 241#endif /* PORT_TO_JMIPS */ 242 243#ifdef PORT_TO_JMIPS 244/* art */ 245SYSCTL_INT(_machdep, CPU_DISRTCSET, disable_rtc_set, CTLFLAG_RW, 246 &disable_rtc_set, 0, "Disable setting the real time clock to system time"); 247#endif /* PORT_TO_JMIPS */ 248 249SYSCTL_STRUCT(_machdep, CPU_BOOTINFO, bootinfo, CTLFLAG_RD, &bootinfo, 250 bootinfo, "Bootinfo struct: kernel filename, BIOS harddisk geometry, etc"); 251 252#ifdef PORT_TO_JMIPS 253/* dchu */ 254SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock, CTLFLAG_RW, 255 &wall_cmos_clock, 0, "Wall CMOS clock assumed"); 256#endif /* PORT_TO_JMIPS */ 257 258/* 259 * Initialize mips and configure to run kernel 260 */ 261 262void 263mips_proc0_init(void) 264{ 265 proc_linkup(&proc0, &thread0); 266 thread0.td_kstack = kstack0; 267 thread0.td_kstack_pages = KSTACK_PAGES - 1; 268 if (thread0.td_kstack & (1 << PAGE_SHIFT)) 269 thread0.td_md.md_realstack = thread0.td_kstack + PAGE_SIZE; 270 else 271 thread0.td_md.md_realstack = thread0.td_kstack; 272 /* Initialize pcpu info of cpu-zero */ 273#ifdef SMP 274 pcpu_init(&__pcpu[0], 0, sizeof(struct pcpu)); 275#else 276 pcpu_init(pcpup, 0, sizeof(struct pcpu)); 277#endif 278 /* 279 * Do not use cpu_thread_alloc to initialize these fields 280 * thread0 is the only thread that has kstack located in KSEG0 281 * while cpu_thread_alloc handles kstack allocated in KSEG2. 282 */ 283 thread0.td_pcb = (struct pcb *)(thread0.td_md.md_realstack + 284 (thread0.td_kstack_pages - 1) * PAGE_SIZE) - 1; 285 thread0.td_frame = &thread0.td_pcb->pcb_regs; 286 /* 287 * There is no need to initialize md_upte array for thread0 as it's 288 * located in .bss section and should be explicitly zeroed during 289 * kernel initialization. 290 */ 291 292 PCPU_SET(curthread, &thread0); 293 PCPU_SET(curpcb, thread0.td_pcb); 294} 295 296struct msgbuf *msgbufp=0; 297 298#if 0 299/* 300 * This code has been moved to the platform_init code. The only 301 * thing that's beign done here that hasn't been moved is the wired tlb 302 * pool stuff. I'm still trying to understand that feature..., since 303 * it maps from the end the kernel to 0x08000000 somehow. But the stuff 304 * was stripped out, so it is hard to say what's going on.... 305 */ 306u_int32_t freemem_start; 307 308static void 309getmemsize() 310{ 311 vm_offset_t kern_start, kern_end; 312 vm_offset_t AllowMem, memsize; 313 const char *cp; 314 size_t sz; 315 int phys_avail_cnt; 316 317 /* Determine memory layout */ 318 phys_avail_cnt = 0; 319 kern_start = mips_trunc_page(MIPS_CACHED_TO_PHYS(btext)); 320 if (kern_start < freemem_start) 321panic("kernel load address too low, overlapping with memory reserved for FPC IPC\n"); 322 323 if (kern_start > freemem_start) { 324 phys_avail[phys_avail_cnt++] = freemem_start; 325 /* 326 * Since the stack is setup just before kern_start, 327 * leave some space for stack to grow 328 */ 329 phys_avail[phys_avail_cnt++] = kern_start - PAGE_SIZE * 3; 330 MIPS_DEBUG_PRINT("phys_avail : %p - %p", \ 331 phys_avail[phys_avail_cnt-2], phys_avail[phys_avail_cnt-1]); 332 } 333 334 kern_end = (vm_offset_t) end; 335 kern_end = (vm_offset_t) mips_round_page(kern_end); 336 MIPS_DEBUG_PRINT("kern_start : 0x%x, kern_end : 0x%x", btext, kern_end); 337 phys_avail[phys_avail_cnt++] = MIPS_CACHED_TO_PHYS(kern_end); 338 339 if (need_wired_tlb_page_pool) { 340 mips_wired_tlb_physmem_start = MIPS_CACHED_TO_PHYS(kern_end); 341 mips_wired_tlb_physmem_end = 0x08000000; 342 MIPS_DEBUG_PRINT("%s: unmapped page start [0x%x] end[0x%x]\n",\ 343 __FUNCTION__, mips_wired_tlb_physmem_start, \ 344 mips_wired_tlb_physmem_end); 345 if (mips_wired_tlb_physmem_start > mips_wired_tlb_physmem_end) 346 panic("Error in Page table page physical address assignment\n"); 347 } 348 349 if (bootinfo.bi_memsizes_valid) 350 memsize = bootinfo.bi_basemem * 1024; 351 else { 352 memsize = SDRAM_MEM_SIZE; 353 } 354 355 /* 356 * hw.physmem is a size in bytes; we also allow k, m, and g suffixes 357 * for the appropriate modifiers. 358 */ 359 if ((cp = getenv("hw.physmem")) != NULL) { 360 vm_offset_t sanity; 361 char *ep; 362 363 sanity = AllowMem = strtouq(cp, &ep, 0); 364 if ((ep != cp) && (*ep != 0)) { 365 switch(*ep) { 366 case 'g': 367 case 'G': 368 AllowMem <<= 10; 369 case 'm': 370 case 'M': 371 AllowMem <<= 10; 372 case 'k': 373 case 'K': 374 AllowMem <<= 10; 375 break; 376 default: 377 AllowMem = sanity = 0; 378 } 379 if (AllowMem < sanity) 380 AllowMem = 0; 381 } 382 if (!AllowMem || (AllowMem < (kern_end - KERNBASE))) 383 printf("Ignoring invalid hw.physmem size of '%s'\n", cp); 384 } else 385 AllowMem = 0; 386 387 if (AllowMem) 388 memsize = (memsize > AllowMem) ? AllowMem : memsize; 389 390 phys_avail[phys_avail_cnt++] = SDRAM_ADDR_START + memsize; 391 MIPS_DEBUG_PRINT("phys_avail : 0x%x - 0x%x", \ 392 phys_avail[phys_avail_cnt-2], phys_avail[phys_avail_cnt-1]); 393 phys_avail[phys_avail_cnt] = 0; 394 395 physmem = btoc(memsize); 396 Maxmem = physmem; 397 398 /* 399 * Initialize error message buffer (at high end of memory). 400 */ 401 sz = round_page(MSGBUF_SIZE); 402 msgbufp = (struct msgbuf *) pmap_steal_memory(sz); 403 msgbufinit(msgbufp, sz); 404 printf("%s: msgbufp[size=%d] = 0x%p\n", __FUNCTION__, sz, msgbufp); 405} 406#endif 407 408/* 409 * Initialize the hardware exception vectors, and the jump table used to 410 * call locore cache and TLB management functions, based on the kind 411 * of CPU the kernel is running on. 412 */ 413void 414mips_vector_init(void) 415{ 416 /* 417 * Copy down exception vector code. 418 */ 419 if (MipsTLBMissEnd - MipsTLBMiss > 0x80) 420 panic("startup: UTLB code too large"); 421 422 if (MipsCacheEnd - MipsCache > 0x80) 423 panic("startup: Cache error code too large"); 424 425 bcopy(MipsTLBMiss, (void *)TLB_MISS_EXC_VEC, 426 MipsTLBMissEnd - MipsTLBMiss); 427 428#ifdef TARGET_OCTEON 429/* Fake, but sufficient, for the 32-bit with 64-bit hardware addresses */ 430 bcopy(MipsTLBMiss, (void *)XTLB_MISS_EXC_VEC, 431 MipsTLBMissEnd - MipsTLBMiss); 432#endif 433 434 bcopy(MipsException, (void *)GEN_EXC_VEC, 435 MipsExceptionEnd - MipsException); 436 437 bcopy(MipsCache, (void *)CACHE_ERR_EXC_VEC, 438 MipsCacheEnd - MipsCache); 439 440 /* 441 * Clear out the I and D caches. 442 */ 443 mips_icache_sync_all(); 444 mips_dcache_wbinv_all(); 445 446 /* 447 * Mask all interrupts. Each interrupt will be enabled 448 * when handler is installed for it 449 */ 450 set_intr_mask (ALL_INT_MASK); 451 /* Clear BEV in SR so we start handling our own exceptions */ 452 mips_cp0_status_write(mips_cp0_status_read() & ~SR_BOOT_EXC_VEC); 453 454} 455 456/* 457 * Initialise a struct pcpu. 458 */ 459void 460cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size) 461{ 462#ifdef SMP 463 if (cpuid != 0) 464 pcpu->pc_boot_stack = (void *)(pcpu_boot_stack + cpuid * 465 (KSTACK_PAGES * PAGE_SIZE)); 466#endif 467 pcpu->pc_next_asid = 1; 468 pcpu->pc_asid_generation = 1; 469} 470 471int 472sysarch(struct thread *td, register struct sysarch_args *uap) 473{ 474 return (ENOSYS); 475} 476 477int 478fill_dbregs(struct thread *td, struct dbreg *dbregs) 479{ 480 481 /* No debug registers on mips */ 482 return (ENOSYS); 483} 484 485int 486set_dbregs(struct thread *td, struct dbreg *dbregs) 487{ 488 489 /* No debug registers on mips */ 490 return (ENOSYS); 491} 492 493int spinco; 494void 495spinlock_enter(void) 496{ 497 struct thread *td; 498 499 td = curthread; 500 if (td->td_md.md_spinlock_count == 0) 501 td->td_md.md_saved_intr = disableintr(); 502 td->td_md.md_spinlock_count++; 503 critical_enter(); 504} 505 506void 507spinlock_exit(void) 508{ 509 struct thread *td; 510 511 td = curthread; 512 critical_exit(); 513 td->td_md.md_spinlock_count--; 514 if (td->td_md.md_spinlock_count == 0) 515 restoreintr(td->td_md.md_saved_intr); 516} 517 518u_int32_t 519get_cyclecount(void) 520{ 521 u_int32_t count; 522 523 mfc0_macro(count, 9); 524 return (count); 525} 526 527/* 528 * call platform specific code to halt (until next interrupt) for the idle loop 529 */ 530void 531cpu_idle(int busy) 532{ 533 if (mips_cp0_status_read() & SR_INT_ENAB) 534 __asm __volatile ("wait"); 535 else 536 panic("ints disabled in idleproc!"); 537} 538 539int 540cpu_idle_wakeup(int cpu) 541{ 542 543 return (0); 544} 545 546void 547dumpsys(struct dumperinfo *di __unused) 548{ 549 550 printf("Kernel dumps not implemented on this architecture\n"); 551} 552