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