xref: /netbsd/sys/arch/cobalt/cobalt/machdep.c (revision c4a72b64)
1 /*	$NetBSD: machdep.c,v 1.40 2002/09/25 22:21:07 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 2000 Soren S. Jorvang.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions, and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include "opt_ddb.h"
29 #include "opt_kgdb.h"
30 #include "opt_execfmt.h"
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/proc.h>
36 #include <sys/buf.h>
37 #include <sys/reboot.h>
38 #include <sys/conf.h>
39 #include <sys/file.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/msgbuf.h>
43 #include <sys/device.h>
44 #include <sys/user.h>
45 #include <sys/exec.h>
46 #include <uvm/uvm_extern.h>
47 #include <sys/sysctl.h>
48 #include <sys/mount.h>
49 #include <sys/syscallargs.h>
50 #include <sys/kcore.h>
51 #include <sys/boot_flag.h>
52 
53 #include <machine/cpu.h>
54 #include <machine/reg.h>
55 #include <machine/psl.h>
56 #include <machine/pte.h>
57 #include <machine/autoconf.h>
58 #include <machine/intr.h>
59 #include <machine/intr_machdep.h>
60 #include <mips/locore.h>
61 
62 #include <machine/nvram.h>
63 #include <machine/leds.h>
64 
65 #include <dev/cons.h>
66 
67 #ifdef KGDB
68 #include <sys/kgdb.h>
69 #endif
70 
71 #ifdef DDB
72 #include <machine/db_machdep.h>
73 #include <ddb/db_extern.h>
74 #define ELFSIZE		DB_ELFSIZE
75 #include <sys/exec_elf.h>
76 #endif
77 
78 /* For sysctl. */
79 extern char cpu_model[];
80 
81 /* Our exported CPU info; we can have only one. */
82 struct cpu_info cpu_info_store;
83 
84 /* Maps for VM objects. */
85 struct vm_map *exec_map = NULL;
86 struct vm_map *mb_map = NULL;
87 struct vm_map *phys_map = NULL;
88 
89 int	physmem;		/* Total physical memory */
90 
91 char	bootstring[512];	/* Boot command */
92 int	netboot;		/* Are we netbooting? */
93 
94 char *	nfsroot_bstr = NULL;
95 char *	root_bstr = NULL;
96 int	bootunit = -1;
97 int	bootpart = -1;
98 
99 
100 phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX];
101 int mem_cluster_cnt;
102 
103 void	configure(void);
104 void	mach_init(unsigned int);
105 void	decode_bootstring(void);
106 static char *	strtok_light(char *, const char);
107 
108 /*
109  * safepri is a safe priority for sleep to set for a spin-wait during
110  * autoconfiguration or after a panic.  Used as an argument to splx().
111  */
112 int	safepri = MIPS1_PSL_LOWIPL;
113 
114 extern caddr_t esym;
115 extern struct user *proc0paddr;
116 
117 
118 
119 /*
120  * Do all the stuff that locore normally does before calling main().
121  */
122 void
123 mach_init(memsize)
124 	unsigned int memsize;
125 {
126 	caddr_t kernend, v;
127         u_long first, last;
128 	vsize_t size;
129 	extern char edata[], end[];
130 
131 	/*
132 	 * Clear the BSS segment.
133 	 */
134 #ifdef DDB
135 	if (memcmp(((Elf_Ehdr *)end)->e_ident, ELFMAG, SELFMAG) == 0 &&
136 	    ((Elf_Ehdr *)end)->e_ident[EI_CLASS] == ELFCLASS) {
137 		esym = end;
138 		esym += ((Elf_Ehdr *)end)->e_entry;
139 		kernend = (caddr_t)mips_round_page(esym);
140 		memset(edata, 0, end - edata);
141 	} else
142 #endif
143 	{
144 		kernend = (caddr_t)mips_round_page(end);
145 		memset(edata, 0, kernend - edata);
146 	}
147 
148 	physmem = btoc(memsize - MIPS_KSEG0_START);
149 
150 	consinit();
151 
152 	uvm_setpagesize();
153 
154 	/*
155 	 * Copy exception-dispatch code down to exception vector.
156 	 * Initialize locore-function vector.
157 	 * Clear out the I and D caches.
158 	 */
159 	mips_vector_init();
160 
161 	/*
162 	 * The boot command is passed in the top 512 bytes,
163 	 * so don't clobber that.
164 	 */
165 	mem_clusters[0].start = 0;
166 	mem_clusters[0].size = ctob(physmem) - 512;
167 	mem_cluster_cnt = 1;
168 
169 	memcpy(bootstring, (char *)(memsize - 512), 512);
170 	memset((char *)(memsize - 512), 0, 512);
171 	bootstring[511] = '\0';
172 
173 	decode_bootstring();
174 
175 #ifdef DDB
176 	ddb_init(0, NULL, NULL);
177 	if (boothowto & RB_KDB)
178 		Debugger();
179 #endif
180 #ifdef KGDB
181         if (boothowto & RB_KDB)
182                 kgdb_connect(0);
183 #endif
184 
185 	strcpy(cpu_model, "Cobalt Microserver");
186 
187 	/*
188 	 * Load the rest of the available pages into the VM system.
189 	 */
190 	first = round_page(MIPS_KSEG0_TO_PHYS(kernend));
191 	last = mem_clusters[0].start + mem_clusters[0].size;
192 	uvm_page_physload(atop(first), atop(last), atop(first), atop(last),
193 		VM_FREELIST_DEFAULT);
194 
195 	/*
196 	 * Initialize error message buffer (at end of core).
197 	 */
198 	mips_init_msgbuf();
199 
200 	/*
201 	 * Compute the size of system data structures.  pmap_bootstrap()
202 	 * needs some of this information.
203 	 */
204 	size = (vsize_t)allocsys(NULL, NULL);
205 
206 	pmap_bootstrap();
207 
208 	/*
209 	 * Allocate space for proc0's USPACE.
210 	 */
211 	v = (caddr_t)uvm_pageboot_alloc(USPACE);
212 	proc0.p_addr = proc0paddr = (struct user *)v;
213 	proc0.p_md.md_regs = (struct frame *)(v + USPACE) - 1;
214 	curpcb = &proc0.p_addr->u_pcb;
215 	curpcb->pcb_context[11] = MIPS_INT_MASK | MIPS_SR_INT_IE; /* SR */
216 
217 	/*
218 	 * Allocate space for system data structures.  These data structures
219 	 * are allocated here instead of cpu_startup() because physical
220 	 * memory is directly addressable.  We don't have to map these into
221 	 * virtual address space.
222 	 */
223 	v = (caddr_t)uvm_pageboot_alloc(size);
224 	if ((allocsys(v, NULL) - v) != size)
225 		panic("mach_init: table size inconsistency");
226 }
227 
228 /*
229  * Allocate memory for variable-sized tables,
230  */
231 void
232 cpu_startup()
233 {
234 	int i, base, residual;
235 	vaddr_t minaddr, maxaddr;
236 	vsize_t size;
237 	char pbuf[9];
238 
239 	/*
240 	 * Good {morning,afternoon,evening,night}.
241 	 */
242 	printf(version);
243 	format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
244 	printf("%s memory", pbuf);
245 
246 	/*
247 	 * Allocate virtual address space for file I/O buffers.
248 	 * Note they are different than the array of headers, 'buf',
249 	 * and usually occupy more virtual memory than physical.
250 	 */
251 	size = MAXBSIZE * nbuf;
252 	if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(size),
253 		    NULL, UVM_UNKNOWN_OFFSET, 0,
254 		    UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE,
255 		    UVM_ADV_NORMAL, 0)) != 0)
256 		panic("startup: cannot allocate VM for buffers");
257 	minaddr = (vaddr_t)buffers;
258 	base = bufpages / nbuf;
259 	residual = bufpages % nbuf;
260 	for (i = 0; i < nbuf; i++) {
261 		vsize_t curbufsize;
262 		vaddr_t curbuf;
263 		struct vm_page *pg;
264 
265 		/*
266 		 * Each buffer has MAXBSIZE bytes of VM space allocated.  Of
267 		 * that MAXBSIZE space, we allocate and map (base+1) pages
268 		 * for the first "residual" buffers, and then we allocate
269 		 * "base" pages for the rest.
270 		 */
271 		curbuf = (vaddr_t) buffers + (i * MAXBSIZE);
272 		curbufsize = NBPG * ((i < residual) ? (base + 1) : base);
273 
274 		while (curbufsize) {
275 			pg = uvm_pagealloc(NULL, 0, NULL, 0);
276 			if (pg == NULL)
277 				panic("cpu_startup: not enough memory for "
278 					"buffer cache");
279 			pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg),
280 				       VM_PROT_READ|VM_PROT_WRITE);
281 			curbuf += PAGE_SIZE;
282 			curbufsize -= PAGE_SIZE;
283 		}
284 	}
285 	pmap_update(pmap_kernel());
286 
287 	/*
288 	 * Allocate a submap for exec arguments.  This map effectively
289 	 * limits the number of processes exec'ing at any time.
290 	 */
291 	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
292 				    16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
293 	/*
294 	 * Allocate a submap for physio.
295 	 */
296 	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
297 				    VM_PHYS_SIZE, 0, FALSE, NULL);
298 
299 	/*
300 	 * (No need to allocate an mbuf cluster submap.  Mbuf clusters
301 	 * are allocated via the pool allocator, and we use KSEG to
302 	 * map those pages.)
303 	 */
304 
305 	format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free));
306 	printf(", %s free", pbuf);
307 	format_bytes(pbuf, sizeof(pbuf), bufpages * NBPG);
308 	printf(", %s in %u buffers\n", pbuf, nbuf);
309 
310 	/*
311 	 * Set up buffers, so they can be used to read disk labels.
312 	 */
313 	bufinit();
314 }
315 
316 int	waittime = -1;
317 
318 void
319 cpu_reboot(howto, bootstr)
320 	int howto;
321 	char *bootstr;
322 {
323 	/* Take a snapshot before clobbering any registers. */
324 	if (curproc)
325 		savectx((struct user *)curpcb);
326 
327 	if (cold) {
328 		howto |= RB_HALT;
329 		goto haltsys;
330 	}
331 
332 	/* If "always halt" was specified as a boot flag, obey. */
333 	if (boothowto & RB_HALT)
334 		howto |= RB_HALT;
335 
336 	boothowto = howto;
337 	if ((howto & RB_NOSYNC) == 0 && (waittime < 0)) {
338 		waittime = 0;
339 		vfs_shutdown();
340 
341 		/*
342 		 * If we've been adjusting the clock, the todr
343 		 * will be out of synch; adjust it now.
344 		 */
345 		resettodr();
346 	}
347 
348 	splhigh();
349 
350 	if (howto & RB_DUMP)
351 		dumpsys();
352 
353 haltsys:
354 	doshutdownhooks();
355 
356 	if (howto & RB_HALT) {
357 		printf("\n");
358 		printf("The operating system has halted.\n");
359 		printf("Please press any key to reboot.\n\n");
360 		cnpollc(1);	/* For proper keyboard command handling */
361 		cngetc();
362 		cnpollc(0);
363 	}
364 
365 	printf("rebooting...\n\n");
366 	delay(500000);
367 
368 	*(volatile char *)MIPS_PHYS_TO_KSEG1(LED_ADDR) = LED_RESET;
369 	printf("WARNING: reboot failed!\n");
370 
371 	for (;;);
372 }
373 
374 void
375 microtime(tvp)
376 	struct timeval *tvp;
377 {
378 	int s = splclock();
379 	static struct timeval lasttime;
380 	u_int32_t counter0;
381 
382 	*tvp = time;
383 
384 	counter0 = *(volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000850);
385 
386 	/*
387 	 * XXX
388 	 */
389 
390 	counter0 /= 50;
391 	counter0 %= 10000;
392 
393 	if (counter0 > 9999) {
394 		counter0 = 9999;
395 	}
396 
397 	tvp->tv_usec -= tvp->tv_usec % 10000;
398 	tvp->tv_usec += 10000 - counter0;
399 
400 	lasttime = *tvp;
401 	splx(s);
402 }
403 
404 unsigned long cpuspeed;
405 
406 __inline void
407 delay(n)
408 	unsigned long n;
409 {
410 	volatile register long N = cpuspeed * n;
411 
412 	while (--N > 0);
413 }
414 
415 #define NINTR	6
416 
417 static struct cobalt_intr intrtab[NINTR];
418 
419 void *
420 cpu_intr_establish(level, ipl, func, arg)
421 	int level;
422 	int ipl;
423 	int (*func)(void *);
424 	void *arg;
425 {
426 	if (level < 0 || level >= NINTR)
427 		panic("invalid interrupt level");
428 
429 	if (intrtab[level].func != NULL)
430 		panic("cannot share CPU interrupts");
431 
432 	intrtab[level].cookie_type = COBALT_COOKIE_TYPE_CPU;
433 	intrtab[level].func = func;
434 	intrtab[level].arg = arg;
435 
436 	return &intrtab[level];
437 }
438 
439 void
440 cpu_intr_disestablish(cookie)
441 	void *cookie;
442 {
443 	struct cobalt_intr *p = cookie;
444 
445         if (p->cookie_type == COBALT_COOKIE_TYPE_CPU) {
446 		p->func = NULL;
447 		p->arg = NULL;
448 	}
449 }
450 
451 void
452 cpu_intr(status, cause, pc, ipending)
453 	u_int32_t status;
454 	u_int32_t cause;
455 	u_int32_t pc;
456 	u_int32_t ipending;
457 {
458 	struct clockframe cf;
459 	static u_int32_t cycles;
460 	int i;
461 
462 	uvmexp.intrs++;
463 
464 	if (ipending & MIPS_INT_MASK_0) {
465 		volatile u_int32_t *irq_src =
466 				(u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000c18);
467 
468 		if (*irq_src & 0x00000100) {
469 			*irq_src = 0;
470 
471 			cf.pc = pc;
472 			cf.sr = status;
473 
474 			hardclock(&cf);
475 		}
476 		cause &= ~MIPS_INT_MASK_0;
477 	}
478 
479 	for (i = 0; i < 5; i++) {
480 		if (ipending & (MIPS_INT_MASK_0 << i))
481 			if (intrtab[i].func != NULL)
482 				if ((*intrtab[i].func)(intrtab[i].arg))
483 					cause &= ~(MIPS_INT_MASK_0 << i);
484 	}
485 
486 	if (ipending & MIPS_INT_MASK_5) {
487 		cycles = mips3_cp0_count_read();
488 		mips3_cp0_compare_write(cycles + 1250000);	/* XXX */
489 
490 #if 0
491 		cf.pc = pc;
492 		cf.sr = status;
493 
494 		statclock(&cf);
495 #endif
496 		cause &= ~MIPS_INT_MASK_5;
497 	}
498 
499 	_splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
500 
501 	/* 'softnet' interrupt */
502 	if (ipending & MIPS_SOFT_INT_MASK_1) {
503 		clearsoftnet();
504 		uvmexp.softs++;
505 		netintr();
506 	}
507 
508 	/* 'softclock' interrupt */
509 	if (ipending & MIPS_SOFT_INT_MASK_0) {
510 		clearsoftclock();
511 		uvmexp.softs++;
512 		intrcnt[SOFTCLOCK_INTR]++;
513 		softclock(NULL);
514 	}
515 }
516 
517 
518 void
519 decode_bootstring(void)
520 {
521 	char * work;
522 	char * equ;
523 	int i;
524 
525 	/* break apart bootstring on ' ' boundries  and itterate*/
526 	work = strtok_light(bootstring, ' ');
527 	while (work != '\0') {
528 		/* if starts with '-', we got options, walk its decode */
529 		if (work[0] == '-') {
530 			i = 1;
531 			while (work[i] != ' ' && work[i] != '\0') {
532 				BOOT_FLAG(work[i], boothowto);
533 				i++;
534 			}
535 		} else
536 
537 		/* if it has a '=' its an assignment, switch and set */
538 		if ((equ = strchr(work,'=')) != '\0') {
539 			if(0 == memcmp("nfsroot=", work, 8)) {
540 				nfsroot_bstr = (equ +1);
541 			} else
542 			if(0 == memcmp("root=", work, 5)) {
543 				root_bstr = (equ +1);
544 			}
545 		} else
546 
547 		/* else it a single value, switch and process */
548 		if (memcmp("single", work, 5) == 0) {
549 			boothowto |= RB_SINGLE;
550 		} else
551 		if (memcmp("ro", work, 2) == 0) {
552 			/* this is also inserted by the firmware */
553 		}
554 
555 		/* grab next token */
556 		work = strtok_light(NULL, ' ');
557 	}
558 
559 	if (root_bstr != NULL) {
560 		/* this should be of the form "/dev/hda1" */
561 		/* [abcd][1234]    drive partition  linux probe order */
562 		if ((memcmp("/dev/hd",root_bstr,7) == 0) &&
563 		    (strlen(root_bstr) == 9) ){
564 			bootunit = root_bstr[7] - 'a';
565 			bootpart = root_bstr[8] - '1';
566 		}
567 	}
568 }
569 
570 
571 static char *
572 strtok_light(str, sep)
573 	char * str;
574 	const char sep;
575 {
576 	static char * proc;
577 	char * head;
578 	char * work;
579 
580 	if (str != NULL)
581 		proc = str;
582 	if (proc == NULL)  /* end of string return NULL */
583 		return proc;
584 
585 	head = proc;
586 
587 	work = strchr (proc, sep);
588 	if (work == NULL) {  /* we hit the end */
589 		proc = work;
590 	} else {
591 		proc = (work +1 );
592 		*work = '\0';
593 	}
594 
595 	return head;
596 }
597 
598