1 /* $NetBSD: arm32_machdep.c,v 1.70 2009/11/27 03:23:05 rmind Exp $ */
4 * Copyright (c) 1994-1998 Mark Brinicombe.
5 * Copyright (c) 1994 Brini.
8 * This code is derived from software written for Brini by Mark Brinicombe
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Mark Brinicombe
21 * for the NetBSD Project.
22 * 4. The name of the company nor the name of the author may be used to
23 * endorse or promote products derived from this software without specific
24 * prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * Machine dependant functions for kernel setup
41 * Updated : 18/04/01 updated for new wscons
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: arm32_machdep.c,v 1.70 2009/11/27 03:23:05 rmind Exp $");
48 #include "opt_pmap_debug.h"
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/reboot.h>
54 #include <sys/kernel.h>
56 #include <sys/mount.h>
58 #include <sys/msgbuf.h>
59 #include <sys/device.h>
60 #include <uvm/uvm_extern.h>
61 #include <sys/sysctl.h>
66 #include <arm/arm32/katelib.h>
67 #include <arm/arm32/machdep.h>
68 #include <machine/bootconfig.h>
72 struct vm_map
*mb_map
= NULL
;
73 struct vm_map
*phys_map
= NULL
;
75 #if NMD > 0 && defined(MEMORY_DISK_HOOKS) && !defined(MEMORY_DISK_ROOT_SIZE)
76 extern size_t md_root_size
; /* Memory disc size */
77 #endif /* NMD && MEMORY_DISK_HOOKS && !MEMORY_DISK_ROOT_SIZE */
79 pv_addr_t kernelstack
;
82 extern paddr_t msgbufphys
;
86 /* exported variable to be filled in by the bootloaders */
92 void data_abort_handler(trapframe_t
*frame
);
93 void prefetch_abort_handler(trapframe_t
*frame
);
94 extern void configure(void);
99 * Initialize the vector page, and select whether or not to
100 * relocate the vectors.
102 * NOTE: We expect the vector page to be mapped at its expected
106 arm32_vector_init(vaddr_t va
, int which
)
108 extern unsigned int page0
[], page0_data
[];
109 unsigned int *vectors
= (int *) va
;
110 unsigned int *vectors_data
= vectors
+ (page0_data
- page0
);
114 * Loop through the vectors we're taking over, and copy the
115 * vector's insn and data word.
117 for (vec
= 0; vec
< ARM_NVEC
; vec
++) {
118 if ((which
& (1 << vec
)) == 0) {
119 /* Don't want to take over this vector. */
122 vectors
[vec
] = page0
[vec
];
123 vectors_data
[vec
] = page0_data
[vec
];
126 /* Now sync the vectors. */
127 cpu_icache_sync_range(va
, (ARM_NVEC
* 2) * sizeof(u_int
));
131 if (va
== ARM_VECTORS_HIGH
) {
133 * Assume the MD caller knows what it's doing here, and
134 * really does want the vector page relocated.
136 * Note: This has to be done here (and not just in
137 * cpu_setup()) because the vector page needs to be
138 * accessible *before* cpu_startup() is called.
141 * NOTE: If the CPU control register is not readable,
142 * this will totally fail! We'll just assume that
143 * any system that has high vector support has a
144 * readable CPU control register, for now. If we
145 * ever encounter one that does not, we'll have to
148 cpu_control(CPU_CONTROL_VECRELOC
, CPU_CONTROL_VECRELOC
);
153 * Debug function just to park the CPU
164 /* Sync the discs and unmount the filesystems */
169 static bool bootsyncdone
= false;
171 if (bootsyncdone
) return;
175 /* Make sure we can still manage to do things */
176 if (GetCPSR() & I32_bit
) {
178 * If we get here then boot has been called without RB_NOSYNC
179 * and interrupts were disabled. This means the boot() call
180 * did not come from a user process e.g. shutdown, but must
181 * have come from somewhere in the kernel.
184 printf("Warning IRQ's disabled during boot()\n");
191 * void cpu_startup(void)
193 * Machine dependant startup code.
204 /* Set the CPU control register */
205 cpu_setup(boot_args
);
207 /* Lock down zero page */
208 vector_page_setprot(VM_PROT_READ
);
211 * Give pmap a chance to set up a few more things now the vm
217 * Initialize error message buffer (at end of core).
220 /* msgbufphys was setup during the secondary boot strap */
221 for (loop
= 0; loop
< btoc(MSGBUFSIZE
); ++loop
)
222 pmap_kenter_pa((vaddr_t
)msgbufaddr
+ loop
* PAGE_SIZE
,
223 msgbufphys
+ loop
* PAGE_SIZE
,
224 VM_PROT_READ
|VM_PROT_WRITE
, 0);
225 pmap_update(pmap_kernel());
226 initmsgbuf(msgbufaddr
, round_page(MSGBUFSIZE
));
229 * Identify ourselves for the msgbuf (everything printed earlier will
232 printf("%s%s", copyright
, version
);
234 format_bytes(pbuf
, sizeof(pbuf
), arm_ptob(physmem
));
235 printf("total memory = %s\n", pbuf
);
240 * Allocate a submap for physio
242 phys_map
= uvm_km_suballoc(kernel_map
, &minaddr
, &maxaddr
,
243 VM_PHYS_SIZE
, 0, false, NULL
);
246 * Finally, allocate mbuf cluster submap.
248 mb_map
= uvm_km_suballoc(kernel_map
, &minaddr
, &maxaddr
,
249 nmbclusters
* mclbytes
, VM_MAP_INTRSAFE
,
252 format_bytes(pbuf
, sizeof(pbuf
), ptoa(uvmexp
.free
));
253 printf("avail memory = %s\n", pbuf
);
255 curpcb
= lwp_getpcb(&lwp0
);
256 curpcb
->pcb_flags
= 0;
257 curpcb
->pcb_un
.un_32
.pcb32_sp
=
258 uvm_lwp_getuarea(&lwp0
) + USPACE_SVC_STACK_TOP
;
259 curpcb
->pcb_tf
= (struct trapframe
*)curpcb
->pcb_un
.un_32
.pcb32_sp
- 1;
263 * machine dependent system variables.
266 sysctl_machdep_booted_device(SYSCTLFN_ARGS
)
268 struct sysctlnode node
;
270 if (booted_device
== NULL
)
274 node
.sysctl_data
= booted_device
->dv_xname
;
275 node
.sysctl_size
= strlen(booted_device
->dv_xname
) + 1;
276 return (sysctl_lookup(SYSCTLFN_CALL(&node
)));
280 sysctl_machdep_booted_kernel(SYSCTLFN_ARGS
)
282 struct sysctlnode node
;
284 if (booted_kernel
== NULL
|| booted_kernel
[0] == '\0')
288 node
.sysctl_data
= booted_kernel
;
289 node
.sysctl_size
= strlen(booted_kernel
) + 1;
290 return (sysctl_lookup(SYSCTLFN_CALL(&node
)));
294 sysctl_machdep_powersave(SYSCTLFN_ARGS
)
296 struct sysctlnode node
= *rnode
;
299 newval
= cpu_do_powersave
;
300 node
.sysctl_data
= &newval
;
301 if (cpufuncs
.cf_sleep
== (void *) cpufunc_nullop
)
302 node
.sysctl_flags
&= ~CTLFLAG_READWRITE
;
303 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
304 if (error
|| newp
== NULL
|| newval
== cpu_do_powersave
)
307 if (newval
< 0 || newval
> 1)
309 cpu_do_powersave
= newval
;
314 SYSCTL_SETUP(sysctl_machdep_setup
, "sysctl machdep subtree setup")
317 sysctl_createv(clog
, 0, NULL
, NULL
,
319 CTLTYPE_NODE
, "machdep", NULL
,
321 CTL_MACHDEP
, CTL_EOL
);
323 sysctl_createv(clog
, 0, NULL
, NULL
,
324 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
,
325 CTLTYPE_INT
, "debug", NULL
,
326 NULL
, 0, &kernel_debug
, 0,
327 CTL_MACHDEP
, CPU_DEBUG
, CTL_EOL
);
328 sysctl_createv(clog
, 0, NULL
, NULL
,
330 CTLTYPE_STRING
, "booted_device", NULL
,
331 sysctl_machdep_booted_device
, 0, NULL
, 0,
332 CTL_MACHDEP
, CPU_BOOTED_DEVICE
, CTL_EOL
);
333 sysctl_createv(clog
, 0, NULL
, NULL
,
335 CTLTYPE_STRING
, "booted_kernel", NULL
,
336 sysctl_machdep_booted_kernel
, 0, NULL
, 0,
337 CTL_MACHDEP
, CPU_BOOTED_KERNEL
, CTL_EOL
);
338 sysctl_createv(clog
, 0, NULL
, NULL
,
340 CTLTYPE_STRUCT
, "console_device", NULL
,
341 sysctl_consdev
, 0, NULL
, sizeof(dev_t
),
342 CTL_MACHDEP
, CPU_CONSDEV
, CTL_EOL
);
343 sysctl_createv(clog
, 0, NULL
, NULL
,
344 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
,
345 CTLTYPE_INT
, "powersave", NULL
,
346 sysctl_machdep_powersave
, 0, &cpu_do_powersave
, 0,
347 CTL_MACHDEP
, CPU_POWERSAVE
, CTL_EOL
);
351 parse_mi_bootargs(char *args
)
355 if (get_bootconf_option(args
, "single", BOOTOPT_TYPE_BOOLEAN
, &integer
)
356 || get_bootconf_option(args
, "-s", BOOTOPT_TYPE_BOOLEAN
, &integer
))
358 boothowto
|= RB_SINGLE
;
359 if (get_bootconf_option(args
, "kdb", BOOTOPT_TYPE_BOOLEAN
, &integer
)
360 || get_bootconf_option(args
, "-k", BOOTOPT_TYPE_BOOLEAN
, &integer
))
363 if (get_bootconf_option(args
, "ask", BOOTOPT_TYPE_BOOLEAN
, &integer
)
364 || get_bootconf_option(args
, "-a", BOOTOPT_TYPE_BOOLEAN
, &integer
))
366 boothowto
|= RB_ASKNAME
;
369 if (get_bootconf_option(args
, "pmapdebug", BOOTOPT_TYPE_INT
, &integer
)) {
370 pmap_debug_level
= integer
;
371 pmap_debug(pmap_debug_level
);
373 #endif /* PMAP_DEBUG */
375 /* if (get_bootconf_option(args, "nbuf", BOOTOPT_TYPE_INT, &integer))
376 bufpages = integer;*/
378 #if NMD > 0 && defined(MEMORY_DISK_HOOKS) && !defined(MEMORY_DISK_ROOT_SIZE)
379 if (get_bootconf_option(args
, "memorydisc", BOOTOPT_TYPE_INT
, &integer
)
380 || get_bootconf_option(args
, "memorydisk", BOOTOPT_TYPE_INT
, &integer
)) {
381 md_root_size
= integer
;
382 md_root_size
*= 1024;
383 if (md_root_size
< 32*1024)
384 md_root_size
= 32*1024;
385 if (md_root_size
> 2048*1024)
386 md_root_size
= 2048*1024;
388 #endif /* NMD && MEMORY_DISK_HOOKS && !MEMORY_DISK_ROOT_SIZE */
390 if (get_bootconf_option(args
, "quiet", BOOTOPT_TYPE_BOOLEAN
, &integer
)
391 || get_bootconf_option(args
, "-q", BOOTOPT_TYPE_BOOLEAN
, &integer
))
393 boothowto
|= AB_QUIET
;
394 if (get_bootconf_option(args
, "verbose", BOOTOPT_TYPE_BOOLEAN
, &integer
)
395 || get_bootconf_option(args
, "-v", BOOTOPT_TYPE_BOOLEAN
, &integer
))
397 boothowto
|= AB_VERBOSE
;
400 #ifdef __HAVE_FAST_SOFTINTS
401 #if IPL_SOFTSERIAL != IPL_SOFTNET + 1
402 #error IPLs are screwed up
403 #elif IPL_SOFTNET != IPL_SOFTBIO + 1
404 #error IPLs are screwed up
405 #elif IPL_SOFTBIO != IPL_SOFTCLOCK + 1
406 #error IPLs are screwed up
407 #elif !(IPL_SOFTCLOCK > IPL_NONE)
408 #error IPLs are screwed up
409 #elif (IPL_NONE != 0)
410 #error IPLs are screwed up
413 #define SOFTINT2IPLMAP \
414 (((IPL_SOFTSERIAL - IPL_SOFTCLOCK) << (SOFTINT_SERIAL * 4)) | \
415 ((IPL_SOFTNET - IPL_SOFTCLOCK) << (SOFTINT_NET * 4)) | \
416 ((IPL_SOFTBIO - IPL_SOFTCLOCK) << (SOFTINT_BIO * 4)) | \
417 ((IPL_SOFTCLOCK - IPL_SOFTCLOCK) << (SOFTINT_CLOCK * 4)))
418 #define SOFTINT2IPL(l) ((SOFTINT2IPLMAP >> ((l) * 4)) & 0x0f)
421 * This returns a mask of softint IPLs that be dispatch at <ipl>
422 * SOFTIPLMASK(IPL_NONE) = 0x0000000f
423 * SOFTIPLMASK(IPL_SOFTCLOCK) = 0x0000000e
424 * SOFTIPLMASK(IPL_SOFTBIO) = 0x0000000c
425 * SOFTIPLMASK(IPL_SOFTNET) = 0x00000008
426 * SOFTIPLMASK(IPL_SOFTSERIAL) = 0x00000000
428 #define SOFTIPLMASK(ipl) (0x0f << (ipl))
430 void softint_switch(lwp_t
*, int);
433 softint_trigger(uintptr_t mask
)
435 curcpu()->ci_softints
|= mask
;
439 softint_init_md(lwp_t
*l
, u_int level
, uintptr_t *machdep
)
441 lwp_t
** lp
= &curcpu()->ci_softlwps
[level
];
442 KASSERT(*lp
== NULL
|| *lp
== l
);
444 *machdep
= 1 << SOFTINT2IPL(level
);
445 KASSERT(level
!= SOFTINT_CLOCK
|| *machdep
== (1 << (IPL_SOFTCLOCK
- IPL_SOFTCLOCK
)));
446 KASSERT(level
!= SOFTINT_BIO
|| *machdep
== (1 << (IPL_SOFTBIO
- IPL_SOFTCLOCK
)));
447 KASSERT(level
!= SOFTINT_NET
|| *machdep
== (1 << (IPL_SOFTNET
- IPL_SOFTCLOCK
)));
448 KASSERT(level
!= SOFTINT_SERIAL
|| *machdep
== (1 << (IPL_SOFTSERIAL
- IPL_SOFTCLOCK
)));
454 struct cpu_info
* const ci
= curcpu();
455 const int opl
= ci
->ci_cpl
;
456 const uint32_t softiplmask
= SOFTIPLMASK(opl
);
459 u_int softints
= ci
->ci_softints
& softiplmask
;
460 KASSERT((softints
!= 0) == ((ci
->ci_softints
>> opl
) != 0));
463 ci
->ci_cpl
= IPL_HIGH
;
464 #define DOSOFTINT(n) \
465 if (softints & (1 << (IPL_SOFT ## n - IPL_SOFTCLOCK))) { \
467 ~(1 << (IPL_SOFT ## n - IPL_SOFTCLOCK)); \
468 softint_switch(ci->ci_softlwps[SOFTINT_ ## n], \
477 panic("dosoftints wtf (softints=%u?, ipl=%d)", softints
, opl
);
480 #endif /* __HAVE_FAST_SOFTINTS */