This file was repocopied to src/sys/powerpc/aim, where it will
live on -- an afterlife.
This commit is contained in:
parent
c8b672d408
commit
e1d637468a
@ -1,318 +0,0 @@
|
||||
/*-
|
||||
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
|
||||
* Copyright (C) 1995, 1996 TooLs GmbH.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by TooLs GmbH.
|
||||
* 4. The name of TooLs GmbH may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $NetBSD: clock.c,v 1.9 2000/01/19 02:52:19 msaitoh Exp $
|
||||
*/
|
||||
/*
|
||||
* Copyright (C) 2001 Benno Rice.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/clock.h>
|
||||
#include <sys/timetc.h>
|
||||
#include <sys/interrupt.h>
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
|
||||
#include <machine/clock.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/intr.h>
|
||||
#include <machine/md_var.h>
|
||||
|
||||
/*
|
||||
* Initially we assume a processor with a bus frequency of 12.5 MHz.
|
||||
*/
|
||||
u_int tickspending;
|
||||
u_long ns_per_tick = 80;
|
||||
static u_long ticks_per_sec = 12500000;
|
||||
static long ticks_per_intr;
|
||||
static volatile u_long lasttb;
|
||||
|
||||
#define DIFF19041970 2082844800
|
||||
|
||||
static int clockinitted = 0;
|
||||
|
||||
static timecounter_get_t decr_get_timecount;
|
||||
|
||||
static struct timecounter decr_timecounter = {
|
||||
decr_get_timecount, /* get_timecount */
|
||||
0, /* no poll_pps */
|
||||
~0u, /* counter_mask */
|
||||
0, /* frequency */
|
||||
"decrementer" /* name */
|
||||
};
|
||||
|
||||
void
|
||||
inittodr(time_t base)
|
||||
{
|
||||
time_t deltat;
|
||||
u_int rtc_time;
|
||||
struct timespec ts;
|
||||
phandle_t phandle;
|
||||
ihandle_t ihandle;
|
||||
char rtcpath[128];
|
||||
u_int rtcsecs;
|
||||
|
||||
/*
|
||||
* If we can't read from RTC, use the fs time.
|
||||
*/
|
||||
phandle = OF_finddevice("rtc");
|
||||
if (phandle != -1) {
|
||||
OF_package_to_path(phandle, rtcpath, sizeof(rtcpath));
|
||||
ihandle = OF_open(rtcpath);
|
||||
if (ihandle != -1) {
|
||||
if (OF_call_method("read-rtc", ihandle,
|
||||
0, 1, &rtcsecs))
|
||||
printf("RTC call method error\n");
|
||||
else {
|
||||
ts.tv_sec = rtcsecs - DIFF19041970;
|
||||
ts.tv_nsec = 0;
|
||||
tc_setclock(&ts);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ts.tv_sec = base;
|
||||
ts.tv_nsec = 0;
|
||||
tc_setclock(&ts);
|
||||
return;
|
||||
}
|
||||
clockinitted = 1;
|
||||
ts.tv_sec = rtc_time - DIFF19041970;
|
||||
|
||||
deltat = ts.tv_sec - base;
|
||||
if (deltat < 0) {
|
||||
deltat = -deltat;
|
||||
}
|
||||
if (deltat < 2 * SECDAY) {
|
||||
tc_setclock(&ts);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("WARNING: clock %s %d days",
|
||||
ts.tv_sec < base ? "lost" : "gained", (int)(deltat / SECDAY));
|
||||
|
||||
printf(" -- CHECK AND RESET THE DATE!\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Similar to the above
|
||||
*/
|
||||
void
|
||||
resettodr()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
decr_intr(struct trapframe *frame)
|
||||
{
|
||||
u_long tb;
|
||||
long tick;
|
||||
int nticks;
|
||||
|
||||
/*
|
||||
* Check whether we are initialized.
|
||||
*/
|
||||
if (!ticks_per_intr)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Based on the actual time delay since the last decrementer reload,
|
||||
* we arrange for earlier interrupt next time.
|
||||
*/
|
||||
__asm ("mftb %0; mfdec %1" : "=r"(tb), "=r"(tick));
|
||||
for (nticks = 0; tick < 0; nticks++)
|
||||
tick += ticks_per_intr;
|
||||
mtdec(tick);
|
||||
/*
|
||||
* lasttb is used during microtime. Set it to the virtual
|
||||
* start of this tick interval.
|
||||
*/
|
||||
lasttb = tb + tick - ticks_per_intr;
|
||||
|
||||
nticks += tickspending;
|
||||
tickspending = 0;
|
||||
|
||||
/*
|
||||
* Reenable interrupts
|
||||
*/
|
||||
#if 0
|
||||
msr = mfmsr();
|
||||
mtmsr(msr | PSL_EE | PSL_RI);
|
||||
#endif
|
||||
/*
|
||||
* Do standard timer interrupt stuff.
|
||||
* Do softclock stuff only on the last iteration.
|
||||
*/
|
||||
#if 0
|
||||
while (--nticks > 0) {
|
||||
hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
|
||||
}
|
||||
#endif
|
||||
hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
|
||||
}
|
||||
|
||||
void
|
||||
decr_init(void)
|
||||
{
|
||||
int qhandle, phandle;
|
||||
char name[32];
|
||||
unsigned int msr;
|
||||
|
||||
phandle = 0;
|
||||
|
||||
/*
|
||||
* Get this info during autoconf? XXX
|
||||
*/
|
||||
for (qhandle = OF_peer(0); qhandle; qhandle = phandle) {
|
||||
if (OF_getprop(qhandle, "device_type", name, sizeof name) >= 0
|
||||
&& !strcmp(name, "cpu")
|
||||
&& OF_getprop(qhandle, "timebase-frequency",
|
||||
&ticks_per_sec, sizeof ticks_per_sec) >= 0) {
|
||||
/*
|
||||
* Should check for correct CPU here? XXX
|
||||
*/
|
||||
msr = mfmsr();
|
||||
mtmsr(msr & ~(PSL_EE|PSL_RI));
|
||||
|
||||
ns_per_tick = 1000000000 / ticks_per_sec;
|
||||
ticks_per_intr = ticks_per_sec / hz;
|
||||
__asm __volatile ("mftb %0" : "=r"(lasttb));
|
||||
mtdec(ticks_per_intr);
|
||||
|
||||
mtmsr(msr);
|
||||
|
||||
break;
|
||||
}
|
||||
if ((phandle = OF_child(qhandle)))
|
||||
continue;
|
||||
while (qhandle) {
|
||||
if ((phandle = OF_peer(qhandle)))
|
||||
break;
|
||||
qhandle = OF_parent(qhandle);
|
||||
}
|
||||
}
|
||||
if (!phandle)
|
||||
panic("no cpu node");
|
||||
}
|
||||
|
||||
void
|
||||
decr_tc_init(void)
|
||||
{
|
||||
decr_timecounter.tc_frequency = ticks_per_sec;
|
||||
tc_init(&decr_timecounter);
|
||||
}
|
||||
|
||||
static __inline u_quad_t
|
||||
mftb(void)
|
||||
{
|
||||
u_long scratch;
|
||||
u_quad_t tb;
|
||||
|
||||
__asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw 0,%0,%1; bne 1b"
|
||||
: "=r"(tb), "=r"(scratch));
|
||||
return tb;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
decr_get_timecount(struct timecounter *tc)
|
||||
{
|
||||
return mftb();
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for about n microseconds (at least!).
|
||||
*/
|
||||
void
|
||||
DELAY(int n)
|
||||
{
|
||||
u_quad_t tb, ttb;
|
||||
|
||||
tb = mftb();
|
||||
ttb = tb + (n * 1000 + ns_per_tick - 1) / ns_per_tick;
|
||||
while (tb < ttb)
|
||||
tb = mftb();
|
||||
}
|
||||
|
||||
/*
|
||||
* Nothing to do.
|
||||
*/
|
||||
void
|
||||
cpu_startprofclock(void)
|
||||
{
|
||||
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
void
|
||||
cpu_stopprofclock(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX Needed by syscons
|
||||
*/
|
||||
int
|
||||
sysbeep(int pitch, int period)
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
@ -1,356 +0,0 @@
|
||||
/*-
|
||||
* Copyright (C) 2002 Benno Rice
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*-
|
||||
* Copyright (C) 1993 Wolfgang Solfrank.
|
||||
* Copyright (C) 1993 TooLs GmbH.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by TooLs GmbH.
|
||||
* 4. The name of TooLs GmbH may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <vm/vm_map.h>
|
||||
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/sr.h>
|
||||
|
||||
int setfault(faultbuf); /* defined in locore.S */
|
||||
|
||||
/*
|
||||
* Makes sure that the right segment of userspace is mapped in.
|
||||
*/
|
||||
static __inline void
|
||||
set_user_sr(register_t vsid)
|
||||
{
|
||||
|
||||
isync();
|
||||
__asm __volatile ("mtsr %0,%1" :: "n"(USER_SR), "r"(vsid));
|
||||
isync();
|
||||
}
|
||||
|
||||
int
|
||||
copyout(const void *kaddr, void *udaddr, size_t len)
|
||||
{
|
||||
struct thread *td;
|
||||
pmap_t pm;
|
||||
faultbuf env;
|
||||
const char *kp;
|
||||
char *up, *p;
|
||||
size_t l;
|
||||
|
||||
td = PCPU_GET(curthread);
|
||||
pm = &td->td_proc->p_vmspace->vm_pmap;
|
||||
|
||||
if (setfault(env)) {
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (EFAULT);
|
||||
}
|
||||
|
||||
kp = kaddr;
|
||||
up = udaddr;
|
||||
|
||||
while (len > 0) {
|
||||
p = (char *)USER_ADDR + ((u_int)up & ~SEGMENT_MASK);
|
||||
|
||||
l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p;
|
||||
if (l > len)
|
||||
l = len;
|
||||
|
||||
set_user_sr(pm->pm_sr[(u_int)up >> ADDR_SR_SHFT]);
|
||||
|
||||
bcopy(kp, p, l);
|
||||
|
||||
up += l;
|
||||
kp += l;
|
||||
len -= l;
|
||||
}
|
||||
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
copyin(const void *udaddr, void *kaddr, size_t len)
|
||||
{
|
||||
struct thread *td;
|
||||
pmap_t pm;
|
||||
faultbuf env;
|
||||
const char *up;
|
||||
char *kp, *p;
|
||||
size_t l;
|
||||
|
||||
td = PCPU_GET(curthread);
|
||||
pm = &td->td_proc->p_vmspace->vm_pmap;
|
||||
|
||||
if (setfault(env)) {
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (EFAULT);
|
||||
}
|
||||
|
||||
kp = kaddr;
|
||||
up = udaddr;
|
||||
|
||||
while (len > 0) {
|
||||
p = (char *)USER_ADDR + ((u_int)up & ~SEGMENT_MASK);
|
||||
|
||||
l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p;
|
||||
if (l > len)
|
||||
l = len;
|
||||
|
||||
set_user_sr(pm->pm_sr[(u_int)up >> ADDR_SR_SHFT]);
|
||||
|
||||
bcopy(p, kp, l);
|
||||
|
||||
up += l;
|
||||
kp += l;
|
||||
len -= l;
|
||||
}
|
||||
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
|
||||
{
|
||||
struct thread *td;
|
||||
pmap_t pm;
|
||||
faultbuf env;
|
||||
const char *up;
|
||||
char *kp;
|
||||
size_t l;
|
||||
int rv, c;
|
||||
|
||||
td = PCPU_GET(curthread);
|
||||
pm = &td->td_proc->p_vmspace->vm_pmap;
|
||||
|
||||
if (setfault(env)) {
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (EFAULT);
|
||||
}
|
||||
|
||||
kp = kaddr;
|
||||
up = udaddr;
|
||||
|
||||
rv = ENAMETOOLONG;
|
||||
|
||||
for (l = 0; len-- > 0; l++) {
|
||||
if ((c = fubyte(up++)) < 0) {
|
||||
rv = EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(*kp++ = c)) {
|
||||
l++;
|
||||
rv = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (done != NULL) {
|
||||
*done = l;
|
||||
}
|
||||
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (rv);
|
||||
}
|
||||
|
||||
int
|
||||
subyte(void *addr, int byte)
|
||||
{
|
||||
struct thread *td;
|
||||
pmap_t pm;
|
||||
faultbuf env;
|
||||
char *p;
|
||||
|
||||
td = PCPU_GET(curthread);
|
||||
pm = &td->td_proc->p_vmspace->vm_pmap;
|
||||
p = (char *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
|
||||
|
||||
if (setfault(env)) {
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
|
||||
|
||||
*p = (char)byte;
|
||||
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
suword(void *addr, long word)
|
||||
{
|
||||
struct thread *td;
|
||||
pmap_t pm;
|
||||
faultbuf env;
|
||||
long *p;
|
||||
|
||||
td = PCPU_GET(curthread);
|
||||
pm = &td->td_proc->p_vmspace->vm_pmap;
|
||||
p = (long *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
|
||||
|
||||
if (setfault(env)) {
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
|
||||
|
||||
*p = word;
|
||||
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
suword32(void *addr, int32_t word)
|
||||
{
|
||||
return (suword(addr, (long)word));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
fubyte(const void *addr)
|
||||
{
|
||||
struct thread *td;
|
||||
pmap_t pm;
|
||||
faultbuf env;
|
||||
u_char *p;
|
||||
int val;
|
||||
|
||||
td = PCPU_GET(curthread);
|
||||
pm = &td->td_proc->p_vmspace->vm_pmap;
|
||||
p = (u_char *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
|
||||
|
||||
if (setfault(env)) {
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
|
||||
|
||||
val = *p;
|
||||
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (val);
|
||||
}
|
||||
|
||||
long
|
||||
fuword(const void *addr)
|
||||
{
|
||||
struct thread *td;
|
||||
pmap_t pm;
|
||||
faultbuf env;
|
||||
long *p, val;
|
||||
|
||||
td = PCPU_GET(curthread);
|
||||
pm = &td->td_proc->p_vmspace->vm_pmap;
|
||||
p = (long *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
|
||||
|
||||
if (setfault(env)) {
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
|
||||
|
||||
val = *p;
|
||||
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (val);
|
||||
}
|
||||
|
||||
int32_t
|
||||
fuword32(const void *addr)
|
||||
{
|
||||
return ((int32_t)fuword(addr));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
casuword32(volatile uint32_t *base, uint32_t oldval, uint32_t newval)
|
||||
{
|
||||
return (casuword((volatile u_long *)base, oldval, newval));
|
||||
}
|
||||
|
||||
u_long
|
||||
casuword(volatile u_long *addr, u_long old, u_long new)
|
||||
{
|
||||
struct thread *td;
|
||||
pmap_t pm;
|
||||
faultbuf env;
|
||||
u_long *p, val;
|
||||
|
||||
td = PCPU_GET(curthread);
|
||||
pm = &td->td_proc->p_vmspace->vm_pmap;
|
||||
p = (u_long *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
|
||||
|
||||
set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
|
||||
|
||||
if (setfault(env)) {
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
val = *p;
|
||||
(void) atomic_cmpset_32((volatile uint32_t *)p, old, new);
|
||||
|
||||
td->td_pcb->pcb_onfault = NULL;
|
||||
|
||||
return (val);
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
/*-
|
||||
* Copyright 2002 by Peter Grehan. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Interrupts are dispatched to here from locore asm
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/interrupt.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/kthread.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/smp.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/vmmeter.h>
|
||||
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/clock.h>
|
||||
#include <machine/db_machdep.h>
|
||||
#include <machine/fpu.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/intr_machdep.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/psl.h>
|
||||
#include <machine/trap.h>
|
||||
#include <machine/spr.h>
|
||||
#include <machine/sr.h>
|
||||
|
||||
#include "pic_if.h"
|
||||
|
||||
/*
|
||||
* A very short dispatch, to try and maximise assembler code use
|
||||
* between all exception types. Maybe 'true' interrupts should go
|
||||
* here, and the trap code can come in separately
|
||||
*/
|
||||
void
|
||||
powerpc_interrupt(struct trapframe *framep)
|
||||
{
|
||||
struct thread *td;
|
||||
register_t ee;
|
||||
|
||||
td = curthread;
|
||||
|
||||
switch (framep->exc) {
|
||||
case EXC_EXI:
|
||||
atomic_add_int(&td->td_intr_nesting_level, 1);
|
||||
PIC_DISPATCH(pic, framep);
|
||||
atomic_subtract_int(&td->td_intr_nesting_level, 1);
|
||||
break;
|
||||
|
||||
case EXC_DECR:
|
||||
atomic_add_int(&td->td_intr_nesting_level, 1);
|
||||
decr_intr(framep);
|
||||
atomic_subtract_int(&td->td_intr_nesting_level, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Re-enable interrupts if applicable. */
|
||||
ee = framep->srr1 & PSL_EE;
|
||||
if (ee != 0) {
|
||||
mtmsr(mfmsr() | ee);
|
||||
isync();
|
||||
}
|
||||
trap(framep);
|
||||
}
|
||||
}
|
@ -1,208 +0,0 @@
|
||||
/* $FreeBSD$ */
|
||||
/* $NetBSD: locore.S,v 1.24 2000/05/31 05:09:17 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 2001 Benno Rice
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*-
|
||||
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
|
||||
* Copyright (C) 1995, 1996 TooLs GmbH.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by TooLs GmbH.
|
||||
* 4. The name of TooLs GmbH may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "assym.s"
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <machine/trap.h>
|
||||
#include <machine/param.h>
|
||||
#include <machine/sr.h>
|
||||
#include <machine/spr.h>
|
||||
#include <machine/psl.h>
|
||||
#include <machine/asm.h>
|
||||
|
||||
/* Locate the per-CPU data structure */
|
||||
#define GET_CPUINFO(r) \
|
||||
mfsprg0 r
|
||||
|
||||
/*
|
||||
* Globals
|
||||
*/
|
||||
.data
|
||||
GLOBAL(tmpstk)
|
||||
.space 8208
|
||||
GLOBAL(esym)
|
||||
.long 0 /* end of symbol table */
|
||||
|
||||
GLOBAL(ofmsr)
|
||||
.long 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */
|
||||
|
||||
GLOBAL(powersave)
|
||||
.long 0
|
||||
|
||||
#define INTSTK 16384 /* 16K interrupt stack */
|
||||
#define INTRCNT_COUNT 256 /* max(HROWPIC_IRQMAX,OPENPIC_IRQMAX) */
|
||||
GLOBAL(intrnames)
|
||||
.space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
|
||||
GLOBAL(eintrnames)
|
||||
.align 4
|
||||
GLOBAL(intrcnt)
|
||||
.space INTRCNT_COUNT * 4 * 2
|
||||
GLOBAL(eintrcnt)
|
||||
|
||||
/*
|
||||
* File-scope for locore.S
|
||||
*/
|
||||
idle_u:
|
||||
.long 0 /* fake uarea during idle after exit */
|
||||
openfirmware_entry:
|
||||
.long 0 /* Open Firmware entry point */
|
||||
srsave:
|
||||
.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
|
||||
/*
|
||||
* This symbol is here for the benefit of kvm_mkdb, and is supposed to
|
||||
* mark the start of kernel text.
|
||||
*/
|
||||
.text
|
||||
.globl kernel_text
|
||||
kernel_text:
|
||||
|
||||
/*
|
||||
* Startup entry. Note, this must be the first thing in the text
|
||||
* segment!
|
||||
*/
|
||||
.text
|
||||
.globl __start
|
||||
__start:
|
||||
#ifdef FIRMWORKSBUGS
|
||||
mfmsr 0
|
||||
andi. 0,0,PSL_IR|PSL_DR
|
||||
beq 1f
|
||||
|
||||
bl ofwr_init
|
||||
1:
|
||||
#endif
|
||||
li 8,0
|
||||
li 9,0x100
|
||||
mtctr 9
|
||||
1:
|
||||
dcbf 0,8
|
||||
icbi 0,8
|
||||
addi 8,8,0x20
|
||||
bdnz 1b
|
||||
sync
|
||||
isync
|
||||
|
||||
/* Save the argument pointer and length */
|
||||
mr 20,6
|
||||
mr 21,7
|
||||
|
||||
lis 8,openfirmware_entry@ha
|
||||
stw 5,openfirmware_entry@l(8) /* save client interface handler */
|
||||
mr 3,5
|
||||
|
||||
lis 1,tmpstk@ha
|
||||
addi 1,1,tmpstk@l
|
||||
addi 1,1,8192
|
||||
|
||||
mfmsr 0
|
||||
lis 9,ofmsr@ha
|
||||
stwu 0,ofmsr@l(9)
|
||||
|
||||
mfsprg0 0 /* save SPRG0-3 */
|
||||
stw 0,4(9) /* ofmsr[1] = sprg0 */
|
||||
mfsprg1 0
|
||||
stw 0,8(9) /* ofmsr[2] = sprg1 */
|
||||
mfsprg2 0
|
||||
stw 0,12(9) /* ofmsr[3] = sprg2 */
|
||||
mfsprg3 0
|
||||
stw 0,16(9) /* ofmsr[4] = sprg3 */
|
||||
|
||||
bl OF_init
|
||||
|
||||
lis 4,end@ha
|
||||
addi 4,4,end@l
|
||||
mr 5,4
|
||||
|
||||
lis 3,kernel_text@ha
|
||||
addi 3,3,kernel_text@l
|
||||
|
||||
/* Restore the argument pointer and length */
|
||||
mr 6,20
|
||||
mr 7,21
|
||||
|
||||
bl powerpc_init
|
||||
bl mi_startup
|
||||
b OF_exit
|
||||
|
||||
/*
|
||||
* int setfault()
|
||||
*
|
||||
* Similar to setjmp to setup for handling faults on accesses to user memory.
|
||||
* Any routine using this may only call bcopy, either the form below,
|
||||
* or the (currently used) C code optimized, so it doesn't use any non-volatile
|
||||
* registers.
|
||||
*/
|
||||
.globl setfault
|
||||
setfault:
|
||||
mflr 0
|
||||
mfcr 12
|
||||
mfsprg 4,0
|
||||
lwz 4,PC_CURTHREAD(4)
|
||||
lwz 4,TD_PCB(4)
|
||||
stw 3,PCB_ONFAULT(4)
|
||||
stw 0,0(3)
|
||||
stw 1,4(3)
|
||||
stw 2,8(3)
|
||||
stmw 12,12(3)
|
||||
xor 3,3,3
|
||||
blr
|
||||
|
||||
#include <powerpc/powerpc/trap_subr.S>
|
@ -1,995 +0,0 @@
|
||||
/*-
|
||||
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
|
||||
* Copyright (C) 1995, 1996 TooLs GmbH.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by TooLs GmbH.
|
||||
* 4. The name of TooLs GmbH may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*-
|
||||
* Copyright (C) 2001 Benno Rice
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* $NetBSD: machdep.c,v 1.74.2.1 2000/11/01 16:13:48 tv Exp $
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_compat.h"
|
||||
#include "opt_ddb.h"
|
||||
#include "opt_kstack_pages.h"
|
||||
#include "opt_msgbuf.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bio.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/cons.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <sys/exec.h>
|
||||
#include <sys/imgact.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/msgbuf.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/sysent.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/vmmeter.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <net/netisr.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_extern.h>
|
||||
#include <vm/vm_kern.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_map.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/vm_pager.h>
|
||||
|
||||
#include <machine/bat.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/elf.h>
|
||||
#include <machine/fpu.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/metadata.h>
|
||||
#include <machine/mmuvar.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/powerpc.h>
|
||||
#include <machine/reg.h>
|
||||
#include <machine/sigframe.h>
|
||||
#include <machine/trap.h>
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
|
||||
#ifdef DDB
|
||||
extern vm_offset_t ksym_start, ksym_end;
|
||||
#endif
|
||||
|
||||
int cold = 1;
|
||||
|
||||
struct pcpu __pcpu[MAXCPU];
|
||||
struct trapframe frame0;
|
||||
|
||||
vm_offset_t kstack0;
|
||||
vm_offset_t kstack0_phys;
|
||||
|
||||
char machine[] = "powerpc";
|
||||
SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
|
||||
|
||||
static int cacheline_size = CACHELINESIZE;
|
||||
SYSCTL_INT(_machdep, CPU_CACHELINE, cacheline_size,
|
||||
CTLFLAG_RD, &cacheline_size, 0, "");
|
||||
|
||||
static void cpu_startup(void *);
|
||||
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL)
|
||||
|
||||
void powerpc_init(u_int, u_int, u_int, void *);
|
||||
|
||||
int save_ofw_mapping(void);
|
||||
int restore_ofw_mapping(void);
|
||||
|
||||
void install_extint(void (*)(void));
|
||||
|
||||
int setfault(faultbuf); /* defined in locore.S */
|
||||
|
||||
static int grab_mcontext(struct thread *, mcontext_t *, int);
|
||||
|
||||
void asm_panic(char *);
|
||||
|
||||
long Maxmem = 0;
|
||||
long realmem = 0;
|
||||
|
||||
struct pmap ofw_pmap;
|
||||
extern int ofmsr;
|
||||
|
||||
struct bat battable[16];
|
||||
|
||||
struct kva_md_info kmi;
|
||||
|
||||
void setPQL2(int *const size, int *const ways);
|
||||
|
||||
void
|
||||
setPQL2(int *const size, int *const ways)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
powerpc_ofw_shutdown(void *junk, int howto)
|
||||
{
|
||||
if (howto & RB_HALT) {
|
||||
OF_halt();
|
||||
}
|
||||
OF_reboot();
|
||||
}
|
||||
|
||||
static void
|
||||
cpu_startup(void *dummy)
|
||||
{
|
||||
|
||||
/*
|
||||
* Initialise the decrementer-based clock.
|
||||
*/
|
||||
decr_init();
|
||||
|
||||
/*
|
||||
* Good {morning,afternoon,evening,night}.
|
||||
*/
|
||||
cpu_setup(PCPU_GET(cpuid));
|
||||
|
||||
/* startrtclock(); */
|
||||
#ifdef PERFMON
|
||||
perfmon_init();
|
||||
#endif
|
||||
printf("real memory = %ld (%ld MB)\n", ptoa(physmem),
|
||||
ptoa(physmem) / 1048576);
|
||||
realmem = physmem;
|
||||
|
||||
/*
|
||||
* Display any holes after the first chunk of extended memory.
|
||||
*/
|
||||
if (bootverbose) {
|
||||
int indx;
|
||||
|
||||
printf("Physical memory chunk(s):\n");
|
||||
for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) {
|
||||
int size1 = phys_avail[indx + 1] - phys_avail[indx];
|
||||
|
||||
printf("0x%08x - 0x%08x, %d bytes (%d pages)\n",
|
||||
phys_avail[indx], phys_avail[indx + 1] - 1, size1,
|
||||
size1 / PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
vm_ksubmap_init(&kmi);
|
||||
|
||||
printf("avail memory = %ld (%ld MB)\n", ptoa(cnt.v_free_count),
|
||||
ptoa(cnt.v_free_count) / 1048576);
|
||||
|
||||
/*
|
||||
* Set up buffers, so they can be used to read disk labels.
|
||||
*/
|
||||
bufinit();
|
||||
vm_pager_bufferinit();
|
||||
|
||||
EVENTHANDLER_REGISTER(shutdown_final, powerpc_ofw_shutdown, 0,
|
||||
SHUTDOWN_PRI_LAST);
|
||||
|
||||
#ifdef SMP
|
||||
/*
|
||||
* OK, enough kmem_alloc/malloc state should be up, lets get on with it!
|
||||
*/
|
||||
mp_start(); /* fire up the secondaries */
|
||||
mp_announce();
|
||||
#endif /* SMP */
|
||||
}
|
||||
|
||||
extern char kernel_text[], _end[];
|
||||
|
||||
extern void *trapcode, *trapsize;
|
||||
extern void *alitrap, *alisize;
|
||||
extern void *dsitrap, *dsisize;
|
||||
extern void *decrint, *decrsize;
|
||||
extern void *extint, *extsize;
|
||||
extern void *dblow, *dbsize;
|
||||
extern void *vectrap, *vectrapsize;
|
||||
|
||||
void
|
||||
powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp)
|
||||
{
|
||||
struct pcpu *pc;
|
||||
vm_offset_t end, off;
|
||||
void *kmdp;
|
||||
char *env;
|
||||
|
||||
end = 0;
|
||||
kmdp = NULL;
|
||||
|
||||
/*
|
||||
* Parse metadata if present and fetch parameters. Must be done
|
||||
* before console is inited so cninit gets the right value of
|
||||
* boothowto.
|
||||
*/
|
||||
if (mdp != NULL) {
|
||||
preload_metadata = mdp;
|
||||
kmdp = preload_search_by_type("elf kernel");
|
||||
if (kmdp != NULL) {
|
||||
boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
|
||||
kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
|
||||
end = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t);
|
||||
#ifdef DDB
|
||||
ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
|
||||
ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Init params/tunables that can be overridden by the loader
|
||||
*/
|
||||
init_param1();
|
||||
|
||||
/*
|
||||
* Start initializing proc0 and thread0.
|
||||
*/
|
||||
proc_linkup0(&proc0, &thread0);
|
||||
thread0.td_frame = &frame0;
|
||||
|
||||
/*
|
||||
* Set up per-cpu data.
|
||||
*/
|
||||
pc = &__pcpu[0];
|
||||
pcpu_init(pc, 0, sizeof(struct pcpu));
|
||||
pc->pc_curthread = &thread0;
|
||||
pc->pc_curpcb = thread0.td_pcb;
|
||||
pc->pc_cpuid = 0;
|
||||
|
||||
__asm __volatile("mtsprg 0, %0" :: "r"(pc));
|
||||
|
||||
mutex_init();
|
||||
|
||||
/*
|
||||
* Initialize the console before printing anything.
|
||||
*/
|
||||
cninit();
|
||||
|
||||
/*
|
||||
* Complain if there is no metadata.
|
||||
*/
|
||||
if (mdp == NULL || kmdp == NULL) {
|
||||
printf("powerpc_init: no loader metadata.\n");
|
||||
}
|
||||
|
||||
kdb_init();
|
||||
|
||||
kobj_machdep_init();
|
||||
|
||||
/*
|
||||
* XXX: Initialize the interrupt tables.
|
||||
* Disable translation in case the vector area
|
||||
* hasn't been mapped (G5)
|
||||
*/
|
||||
mtmsr(mfmsr() & ~(PSL_IR | PSL_DR));
|
||||
isync();
|
||||
bcopy(&trapcode, (void *)EXC_RST, (size_t)&trapsize);
|
||||
bcopy(&trapcode, (void *)EXC_MCHK, (size_t)&trapsize);
|
||||
bcopy(&dsitrap, (void *)EXC_DSI, (size_t)&dsisize);
|
||||
bcopy(&trapcode, (void *)EXC_ISI, (size_t)&trapsize);
|
||||
bcopy(&trapcode, (void *)EXC_EXI, (size_t)&trapsize);
|
||||
bcopy(&alitrap, (void *)EXC_ALI, (size_t)&alisize);
|
||||
bcopy(&trapcode, (void *)EXC_PGM, (size_t)&trapsize);
|
||||
bcopy(&trapcode, (void *)EXC_FPU, (size_t)&trapsize);
|
||||
bcopy(&trapcode, (void *)EXC_DECR, (size_t)&trapsize);
|
||||
bcopy(&trapcode, (void *)EXC_SC, (size_t)&trapsize);
|
||||
bcopy(&trapcode, (void *)EXC_TRC, (size_t)&trapsize);
|
||||
bcopy(&trapcode, (void *)EXC_FPA, (size_t)&trapsize);
|
||||
bcopy(&vectrap, (void *)EXC_VEC, (size_t)&vectrapsize);
|
||||
bcopy(&trapcode, (void *)EXC_VECAST, (size_t)&trapsize);
|
||||
bcopy(&trapcode, (void *)EXC_THRM, (size_t)&trapsize);
|
||||
bcopy(&trapcode, (void *)EXC_BPT, (size_t)&trapsize);
|
||||
#ifdef KDB
|
||||
bcopy(&dblow, (void *)EXC_RST, (size_t)&dbsize);
|
||||
bcopy(&dblow, (void *)EXC_MCHK, (size_t)&dbsize);
|
||||
bcopy(&dblow, (void *)EXC_PGM, (size_t)&dbsize);
|
||||
bcopy(&dblow, (void *)EXC_TRC, (size_t)&dbsize);
|
||||
bcopy(&dblow, (void *)EXC_BPT, (size_t)&dbsize);
|
||||
#endif
|
||||
__syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD);
|
||||
|
||||
/*
|
||||
* Make sure translation has been enabled
|
||||
*/
|
||||
mtmsr(mfmsr() | PSL_IR|PSL_DR|PSL_ME|PSL_RI);
|
||||
isync();
|
||||
|
||||
/*
|
||||
* Initialise virtual memory.
|
||||
*/
|
||||
pmap_mmu_install(MMU_TYPE_OEA, 0); /* XXX temporary */
|
||||
pmap_bootstrap(startkernel, endkernel);
|
||||
|
||||
/*
|
||||
* Initialize params/tunables that are derived from memsize
|
||||
*/
|
||||
init_param2(physmem);
|
||||
|
||||
/*
|
||||
* Grab booted kernel's name
|
||||
*/
|
||||
env = getenv("kernelname");
|
||||
if (env != NULL) {
|
||||
strlcpy(kernelname, env, sizeof(kernelname));
|
||||
freeenv(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finish setting up thread0.
|
||||
*/
|
||||
thread0.td_kstack = kstack0;
|
||||
thread0.td_pcb = (struct pcb *)
|
||||
(thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1;
|
||||
|
||||
/*
|
||||
* Map and initialise the message buffer.
|
||||
*/
|
||||
for (off = 0; off < round_page(MSGBUF_SIZE); off += PAGE_SIZE)
|
||||
pmap_kenter((vm_offset_t)msgbufp + off, msgbuf_phys + off);
|
||||
msgbufinit(msgbufp, MSGBUF_SIZE);
|
||||
|
||||
#ifdef KDB
|
||||
if (boothowto & RB_KDB)
|
||||
kdb_enter("Boot flags requested debugger");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
bzero(void *buf, size_t len)
|
||||
{
|
||||
caddr_t p;
|
||||
|
||||
p = buf;
|
||||
|
||||
while (((vm_offset_t) p & (sizeof(u_long) - 1)) && len) {
|
||||
*p++ = 0;
|
||||
len--;
|
||||
}
|
||||
|
||||
while (len >= sizeof(u_long) * 8) {
|
||||
*(u_long*) p = 0;
|
||||
*((u_long*) p + 1) = 0;
|
||||
*((u_long*) p + 2) = 0;
|
||||
*((u_long*) p + 3) = 0;
|
||||
len -= sizeof(u_long) * 8;
|
||||
*((u_long*) p + 4) = 0;
|
||||
*((u_long*) p + 5) = 0;
|
||||
*((u_long*) p + 6) = 0;
|
||||
*((u_long*) p + 7) = 0;
|
||||
p += sizeof(u_long) * 8;
|
||||
}
|
||||
|
||||
while (len >= sizeof(u_long)) {
|
||||
*(u_long*) p = 0;
|
||||
len -= sizeof(u_long);
|
||||
p += sizeof(u_long);
|
||||
}
|
||||
|
||||
while (len) {
|
||||
*p++ = 0;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
{
|
||||
struct trapframe *tf;
|
||||
struct sigframe *sfp;
|
||||
struct sigacts *psp;
|
||||
struct sigframe sf;
|
||||
struct thread *td;
|
||||
struct proc *p;
|
||||
int oonstack, rndfsize;
|
||||
int sig;
|
||||
int code;
|
||||
|
||||
td = curthread;
|
||||
p = td->td_proc;
|
||||
PROC_LOCK_ASSERT(p, MA_OWNED);
|
||||
sig = ksi->ksi_signo;
|
||||
code = ksi->ksi_code;
|
||||
psp = p->p_sigacts;
|
||||
mtx_assert(&psp->ps_mtx, MA_OWNED);
|
||||
tf = td->td_frame;
|
||||
oonstack = sigonstack(tf->fixreg[1]);
|
||||
|
||||
rndfsize = ((sizeof(sf) + 15) / 16) * 16;
|
||||
|
||||
CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
|
||||
catcher, sig);
|
||||
|
||||
/*
|
||||
* Save user context
|
||||
*/
|
||||
memset(&sf, 0, sizeof(sf));
|
||||
grab_mcontext(td, &sf.sf_uc.uc_mcontext, 0);
|
||||
sf.sf_uc.uc_sigmask = *mask;
|
||||
sf.sf_uc.uc_stack = td->td_sigstk;
|
||||
sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
|
||||
? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
|
||||
|
||||
sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* Allocate and validate space for the signal handler context.
|
||||
*/
|
||||
if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
|
||||
SIGISMEMBER(psp->ps_sigonstack, sig)) {
|
||||
sfp = (struct sigframe *)(td->td_sigstk.ss_sp +
|
||||
td->td_sigstk.ss_size - rndfsize);
|
||||
} else {
|
||||
sfp = (struct sigframe *)(tf->fixreg[1] - rndfsize);
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate the signal if appropriate (Linux emu ?)
|
||||
*/
|
||||
if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize)
|
||||
sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
|
||||
|
||||
/*
|
||||
* Save the floating-point state, if necessary, then copy it.
|
||||
*/
|
||||
/* XXX */
|
||||
|
||||
/*
|
||||
* Set up the registers to return to sigcode.
|
||||
*
|
||||
* r1/sp - sigframe ptr
|
||||
* lr - sig function, dispatched to by blrl in trampoline
|
||||
* r3 - sig number
|
||||
* r4 - SIGINFO ? &siginfo : exception code
|
||||
* r5 - user context
|
||||
* srr0 - trampoline function addr
|
||||
*/
|
||||
tf->lr = (register_t)catcher;
|
||||
tf->fixreg[1] = (register_t)sfp;
|
||||
tf->fixreg[FIRSTARG] = sig;
|
||||
tf->fixreg[FIRSTARG+2] = (register_t)&sfp->sf_uc;
|
||||
if (SIGISMEMBER(psp->ps_siginfo, sig)) {
|
||||
/*
|
||||
* Signal handler installed with SA_SIGINFO.
|
||||
*/
|
||||
tf->fixreg[FIRSTARG+1] = (register_t)&sfp->sf_si;
|
||||
|
||||
/*
|
||||
* Fill siginfo structure.
|
||||
*/
|
||||
sf.sf_si = ksi->ksi_info;
|
||||
sf.sf_si.si_signo = sig;
|
||||
sf.sf_si.si_addr = (void *) ((tf->exc == EXC_DSI) ?
|
||||
tf->dar : tf->srr0);
|
||||
} else {
|
||||
/* Old FreeBSD-style arguments. */
|
||||
tf->fixreg[FIRSTARG+1] = code;
|
||||
tf->fixreg[FIRSTARG+3] = (tf->exc == EXC_DSI) ?
|
||||
tf->dar : tf->srr0;
|
||||
}
|
||||
mtx_unlock(&psp->ps_mtx);
|
||||
PROC_UNLOCK(p);
|
||||
|
||||
tf->srr0 = (register_t)(PS_STRINGS - *(p->p_sysent->sv_szsigcode));
|
||||
|
||||
/*
|
||||
* copy the frame out to userland.
|
||||
*/
|
||||
if (copyout(&sf, sfp, sizeof(*sfp)) != 0) {
|
||||
/*
|
||||
* Process has trashed its stack. Kill it.
|
||||
*/
|
||||
CTR2(KTR_SIG, "sendsig: sigexit td=%p sfp=%p", td, sfp);
|
||||
PROC_LOCK(p);
|
||||
sigexit(td, SIGILL);
|
||||
}
|
||||
|
||||
CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td,
|
||||
tf->srr0, tf->fixreg[1]);
|
||||
|
||||
PROC_LOCK(p);
|
||||
mtx_lock(&psp->ps_mtx);
|
||||
}
|
||||
|
||||
int
|
||||
sigreturn(struct thread *td, struct sigreturn_args *uap)
|
||||
{
|
||||
struct proc *p;
|
||||
ucontext_t uc;
|
||||
int error;
|
||||
|
||||
CTR2(KTR_SIG, "sigreturn: td=%p ucp=%p", td, uap->sigcntxp);
|
||||
|
||||
if (copyin(uap->sigcntxp, &uc, sizeof(uc)) != 0) {
|
||||
CTR1(KTR_SIG, "sigreturn: efault td=%p", td);
|
||||
return (EFAULT);
|
||||
}
|
||||
|
||||
error = set_mcontext(td, &uc.uc_mcontext);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
p = td->td_proc;
|
||||
PROC_LOCK(p);
|
||||
td->td_sigmask = uc.uc_sigmask;
|
||||
SIG_CANTMASK(td->td_sigmask);
|
||||
signotify(td);
|
||||
PROC_UNLOCK(p);
|
||||
|
||||
CTR3(KTR_SIG, "sigreturn: return td=%p pc=%#x sp=%#x",
|
||||
td, uc.uc_mcontext.mc_srr0, uc.uc_mcontext.mc_gpr[1]);
|
||||
|
||||
return (EJUSTRETURN);
|
||||
}
|
||||
|
||||
#ifdef COMPAT_FREEBSD4
|
||||
int
|
||||
freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
|
||||
{
|
||||
|
||||
return sigreturn(td, (struct sigreturn_args *)uap);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Construct a PCB from a trapframe. This is called from kdb_trap() where
|
||||
* we want to start a backtrace from the function that caused us to enter
|
||||
* the debugger. We have the context in the trapframe, but base the trace
|
||||
* on the PCB. The PCB doesn't have to be perfect, as long as it contains
|
||||
* enough for a backtrace.
|
||||
*/
|
||||
void
|
||||
makectx(struct trapframe *tf, struct pcb *pcb)
|
||||
{
|
||||
|
||||
pcb->pcb_lr = tf->srr0;
|
||||
pcb->pcb_sp = tf->fixreg[1];
|
||||
}
|
||||
|
||||
/*
|
||||
* get_mcontext/sendsig helper routine that doesn't touch the
|
||||
* proc lock
|
||||
*/
|
||||
static int
|
||||
grab_mcontext(struct thread *td, mcontext_t *mcp, int flags)
|
||||
{
|
||||
struct pcb *pcb;
|
||||
|
||||
pcb = td->td_pcb;
|
||||
|
||||
memset(mcp, 0, sizeof(mcontext_t));
|
||||
|
||||
mcp->mc_vers = _MC_VERSION;
|
||||
mcp->mc_flags = 0;
|
||||
memcpy(&mcp->mc_frame, td->td_frame, sizeof(struct trapframe));
|
||||
if (flags & GET_MC_CLEAR_RET) {
|
||||
mcp->mc_gpr[3] = 0;
|
||||
mcp->mc_gpr[4] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This assumes that floating-point context is *not* lazy,
|
||||
* so if the thread has used FP there would have been a
|
||||
* FP-unavailable exception that would have set things up
|
||||
* correctly.
|
||||
*/
|
||||
if (pcb->pcb_flags & PCB_FPU) {
|
||||
KASSERT(td == curthread,
|
||||
("get_mcontext: fp save not curthread"));
|
||||
critical_enter();
|
||||
save_fpu(td);
|
||||
critical_exit();
|
||||
mcp->mc_flags |= _MC_FP_VALID;
|
||||
memcpy(&mcp->mc_fpscr, &pcb->pcb_fpu.fpscr, sizeof(double));
|
||||
memcpy(mcp->mc_fpreg, pcb->pcb_fpu.fpr, 32*sizeof(double));
|
||||
}
|
||||
|
||||
/* XXX Altivec context ? */
|
||||
|
||||
mcp->mc_len = sizeof(*mcp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
get_mcontext(struct thread *td, mcontext_t *mcp, int flags)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = grab_mcontext(td, mcp, flags);
|
||||
if (error == 0) {
|
||||
PROC_LOCK(curthread->td_proc);
|
||||
mcp->mc_onstack = sigonstack(td->td_frame->fixreg[1]);
|
||||
PROC_UNLOCK(curthread->td_proc);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
set_mcontext(struct thread *td, const mcontext_t *mcp)
|
||||
{
|
||||
struct pcb *pcb;
|
||||
struct trapframe *tf;
|
||||
|
||||
pcb = td->td_pcb;
|
||||
tf = td->td_frame;
|
||||
|
||||
if (mcp->mc_vers != _MC_VERSION ||
|
||||
mcp->mc_len != sizeof(*mcp))
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* Don't let the user set privileged MSR bits
|
||||
*/
|
||||
if ((mcp->mc_srr1 & PSL_USERSTATIC) != (tf->srr1 & PSL_USERSTATIC)) {
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
memcpy(tf, mcp->mc_frame, sizeof(mcp->mc_frame));
|
||||
|
||||
if (mcp->mc_flags & _MC_FP_VALID) {
|
||||
if ((pcb->pcb_flags & PCB_FPU) != PCB_FPU) {
|
||||
critical_enter();
|
||||
enable_fpu(td);
|
||||
critical_exit();
|
||||
}
|
||||
memcpy(&pcb->pcb_fpu.fpscr, &mcp->mc_fpscr, sizeof(double));
|
||||
memcpy(pcb->pcb_fpu.fpr, mcp->mc_fpreg, 32*sizeof(double));
|
||||
}
|
||||
|
||||
/* XXX Altivec context? */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
cpu_boot(int howto)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
cpu_initclocks(void)
|
||||
{
|
||||
|
||||
decr_tc_init();
|
||||
}
|
||||
|
||||
/* Get current clock frequency for the given cpu id. */
|
||||
int
|
||||
cpu_est_clockrate(int cpu_id, uint64_t *rate)
|
||||
{
|
||||
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shutdown the CPU as much as possible.
|
||||
*/
|
||||
void
|
||||
cpu_halt(void)
|
||||
{
|
||||
|
||||
OF_exit();
|
||||
}
|
||||
|
||||
void
|
||||
cpu_idle(void)
|
||||
{
|
||||
/* TODO: Insert code to halt (until next interrupt) */
|
||||
|
||||
#ifdef INVARIANTS
|
||||
if ((mfmsr() & PSL_EE) != PSL_EE) {
|
||||
struct thread *td = curthread;
|
||||
printf("td msr %x\n", td->td_md.md_saved_msr);
|
||||
panic("ints disabled in idleproc!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Set set up registers on exec.
|
||||
*/
|
||||
void
|
||||
exec_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings)
|
||||
{
|
||||
struct trapframe *tf;
|
||||
struct ps_strings arginfo;
|
||||
|
||||
tf = trapframe(td);
|
||||
bzero(tf, sizeof *tf);
|
||||
tf->fixreg[1] = -roundup(-stack + 8, 16);
|
||||
|
||||
/*
|
||||
* XXX Machine-independent code has already copied arguments and
|
||||
* XXX environment to userland. Get them back here.
|
||||
*/
|
||||
(void)copyin((char *)PS_STRINGS, &arginfo, sizeof(arginfo));
|
||||
|
||||
/*
|
||||
* Set up arguments for _start():
|
||||
* _start(argc, argv, envp, obj, cleanup, ps_strings);
|
||||
*
|
||||
* Notes:
|
||||
* - obj and cleanup are the auxilliary and termination
|
||||
* vectors. They are fixed up by ld.elf_so.
|
||||
* - ps_strings is a NetBSD extention, and will be
|
||||
* ignored by executables which are strictly
|
||||
* compliant with the SVR4 ABI.
|
||||
*
|
||||
* XXX We have to set both regs and retval here due to different
|
||||
* XXX calling convention in trap.c and init_main.c.
|
||||
*/
|
||||
/*
|
||||
* XXX PG: these get overwritten in the syscall return code.
|
||||
* execve() should return EJUSTRETURN, like it does on NetBSD.
|
||||
* Emulate by setting the syscall return value cells. The
|
||||
* registers still have to be set for init's fork trampoline.
|
||||
*/
|
||||
td->td_retval[0] = arginfo.ps_nargvstr;
|
||||
td->td_retval[1] = (register_t)arginfo.ps_argvstr;
|
||||
tf->fixreg[3] = arginfo.ps_nargvstr;
|
||||
tf->fixreg[4] = (register_t)arginfo.ps_argvstr;
|
||||
tf->fixreg[5] = (register_t)arginfo.ps_envstr;
|
||||
tf->fixreg[6] = 0; /* auxillary vector */
|
||||
tf->fixreg[7] = 0; /* termination vector */
|
||||
tf->fixreg[8] = (register_t)PS_STRINGS; /* NetBSD extension */
|
||||
|
||||
tf->srr0 = entry;
|
||||
tf->srr1 = PSL_MBO | PSL_USERSET | PSL_FE_DFLT;
|
||||
td->td_pcb->pcb_flags = 0;
|
||||
}
|
||||
|
||||
int
|
||||
fill_regs(struct thread *td, struct reg *regs)
|
||||
{
|
||||
struct trapframe *tf;
|
||||
|
||||
tf = td->td_frame;
|
||||
memcpy(regs, tf, sizeof(struct reg));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
fill_dbregs(struct thread *td, struct dbreg *dbregs)
|
||||
{
|
||||
/* No debug registers on PowerPC */
|
||||
return (ENOSYS);
|
||||
}
|
||||
|
||||
int
|
||||
fill_fpregs(struct thread *td, struct fpreg *fpregs)
|
||||
{
|
||||
struct pcb *pcb;
|
||||
|
||||
pcb = td->td_pcb;
|
||||
|
||||
if ((pcb->pcb_flags & PCB_FPU) == 0)
|
||||
memset(fpregs, 0, sizeof(struct fpreg));
|
||||
else
|
||||
memcpy(fpregs, &pcb->pcb_fpu, sizeof(struct fpreg));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
set_regs(struct thread *td, struct reg *regs)
|
||||
{
|
||||
struct trapframe *tf;
|
||||
|
||||
tf = td->td_frame;
|
||||
memcpy(tf, regs, sizeof(struct reg));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
set_dbregs(struct thread *td, struct dbreg *dbregs)
|
||||
{
|
||||
/* No debug registers on PowerPC */
|
||||
return (ENOSYS);
|
||||
}
|
||||
|
||||
int
|
||||
set_fpregs(struct thread *td, struct fpreg *fpregs)
|
||||
{
|
||||
struct pcb *pcb;
|
||||
|
||||
pcb = td->td_pcb;
|
||||
if ((pcb->pcb_flags & PCB_FPU) == 0)
|
||||
enable_fpu(td);
|
||||
memcpy(&pcb->pcb_fpu, fpregs, sizeof(struct fpreg));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ptrace_set_pc(struct thread *td, unsigned long addr)
|
||||
{
|
||||
struct trapframe *tf;
|
||||
|
||||
tf = td->td_frame;
|
||||
tf->srr0 = (register_t)addr;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ptrace_single_step(struct thread *td)
|
||||
{
|
||||
struct trapframe *tf;
|
||||
|
||||
tf = td->td_frame;
|
||||
tf->srr1 |= PSL_SE;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ptrace_clear_single_step(struct thread *td)
|
||||
{
|
||||
struct trapframe *tf;
|
||||
|
||||
tf = td->td_frame;
|
||||
tf->srr1 &= ~PSL_SE;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise a struct pcpu.
|
||||
*/
|
||||
void
|
||||
cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t sz)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
spinlock_enter(void)
|
||||
{
|
||||
struct thread *td;
|
||||
|
||||
td = curthread;
|
||||
if (td->td_md.md_spinlock_count == 0)
|
||||
td->td_md.md_saved_msr = intr_disable();
|
||||
td->td_md.md_spinlock_count++;
|
||||
critical_enter();
|
||||
}
|
||||
|
||||
void
|
||||
spinlock_exit(void)
|
||||
{
|
||||
struct thread *td;
|
||||
|
||||
td = curthread;
|
||||
critical_exit();
|
||||
td->td_md.md_spinlock_count--;
|
||||
if (td->td_md.md_spinlock_count == 0)
|
||||
intr_restore(td->td_md.md_saved_msr);
|
||||
}
|
||||
|
||||
/*
|
||||
* kcopy(const void *src, void *dst, size_t len);
|
||||
*
|
||||
* Copy len bytes from src to dst, aborting if we encounter a fatal
|
||||
* page fault.
|
||||
*
|
||||
* kcopy() _must_ save and restore the old fault handler since it is
|
||||
* called by uiomove(), which may be in the path of servicing a non-fatal
|
||||
* page fault.
|
||||
*/
|
||||
int
|
||||
kcopy(const void *src, void *dst, size_t len)
|
||||
{
|
||||
struct thread *td;
|
||||
faultbuf env, *oldfault;
|
||||
int rv;
|
||||
|
||||
td = PCPU_GET(curthread);
|
||||
oldfault = td->td_pcb->pcb_onfault;
|
||||
if ((rv = setfault(env)) != 0) {
|
||||
td->td_pcb->pcb_onfault = oldfault;
|
||||
return rv;
|
||||
}
|
||||
|
||||
memcpy(dst, src, len);
|
||||
|
||||
td->td_pcb->pcb_onfault = oldfault;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
asm_panic(char *pstr)
|
||||
{
|
||||
panic(pstr);
|
||||
}
|
||||
|
||||
int db_trap_glue(struct trapframe *); /* Called from trap_subr.S */
|
||||
|
||||
int
|
||||
db_trap_glue(struct trapframe *frame)
|
||||
{
|
||||
if (!(frame->srr1 & PSL_PR)
|
||||
&& (frame->exc == EXC_TRC || frame->exc == EXC_RUNMODETRC
|
||||
|| (frame->exc == EXC_PGM
|
||||
&& (frame->srr1 & 0x20000))
|
||||
|| frame->exc == EXC_BPT
|
||||
|| frame->exc == EXC_DSI)) {
|
||||
int type = frame->exc;
|
||||
if (type == EXC_PGM && (frame->srr1 & 0x20000)) {
|
||||
type = T_BREAKPOINT;
|
||||
}
|
||||
return (kdb_trap(type, 0, frame));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,487 +0,0 @@
|
||||
/*-
|
||||
* Copyright 1998 Massachusetts Institute of Technology
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that both the above copyright notice and this
|
||||
* permission notice appear in all copies, that both the above
|
||||
* copyright notice and this permission notice appear in all
|
||||
* supporting documentation, and that the name of M.I.T. not be used
|
||||
* in advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission. M.I.T. makes
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied
|
||||
* warranty.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
|
||||
* ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
|
||||
* SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/*-
|
||||
* Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include "opt_psim.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/cons.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/intr_machdep.h>
|
||||
#include <machine/nexusvar.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include "ofw_bus_if.h"
|
||||
#include "pic_if.h"
|
||||
|
||||
/*
|
||||
* The nexus (which is a pseudo-bus actually) iterates over the nodes that
|
||||
* exist in Open Firmware and adds them as devices to this bus so that drivers
|
||||
* can be attached to them.
|
||||
*
|
||||
* Maybe this code should get into dev/ofw to some extent, as some of it should
|
||||
* work for all Open Firmware based machines...
|
||||
*/
|
||||
|
||||
static MALLOC_DEFINE(M_NEXUS, "nexus", "nexus device information");
|
||||
|
||||
struct nexus_devinfo {
|
||||
phandle_t ndi_node;
|
||||
/* Some common properties. */
|
||||
const char *ndi_name;
|
||||
const char *ndi_device_type;
|
||||
const char *ndi_compatible;
|
||||
};
|
||||
|
||||
struct nexus_softc {
|
||||
struct rman sc_rman;
|
||||
};
|
||||
|
||||
/*
|
||||
* Device interface
|
||||
*/
|
||||
static int nexus_probe(device_t);
|
||||
static void nexus_probe_nomatch(device_t, device_t);
|
||||
|
||||
/*
|
||||
* Bus interface
|
||||
*/
|
||||
static device_t nexus_add_child(device_t, int, const char *, int);
|
||||
static int nexus_read_ivar(device_t, device_t, int, uintptr_t *);
|
||||
static int nexus_write_ivar(device_t, device_t, int, uintptr_t);
|
||||
static int nexus_setup_intr(device_t, device_t, struct resource *, int,
|
||||
driver_filter_t *, driver_intr_t *, void *, void **);
|
||||
static int nexus_teardown_intr(device_t, device_t, struct resource *,
|
||||
void *);
|
||||
static struct resource *nexus_alloc_resource(device_t, device_t, int, int *,
|
||||
u_long, u_long, u_long, u_int);
|
||||
static int nexus_activate_resource(device_t, device_t, int, int,
|
||||
struct resource *);
|
||||
static int nexus_deactivate_resource(device_t, device_t, int, int,
|
||||
struct resource *);
|
||||
static int nexus_release_resource(device_t, device_t, int, int,
|
||||
struct resource *);
|
||||
|
||||
static phandle_t nexus_ofw_get_node(device_t, device_t);
|
||||
static const char *nexus_ofw_get_name(device_t, device_t);
|
||||
static const char *nexus_ofw_get_type(device_t, device_t);
|
||||
static const char *nexus_ofw_get_compat(device_t, device_t);
|
||||
|
||||
/*
|
||||
* Local routines
|
||||
*/
|
||||
static device_t nexus_device_from_node(device_t, phandle_t);
|
||||
|
||||
static device_method_t nexus_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, nexus_probe),
|
||||
DEVMETHOD(device_attach, bus_generic_attach),
|
||||
DEVMETHOD(device_detach, bus_generic_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* Bus interface. Resource management is business of the children... */
|
||||
DEVMETHOD(bus_add_child, nexus_add_child),
|
||||
DEVMETHOD(bus_print_child, bus_generic_print_child),
|
||||
DEVMETHOD(bus_probe_nomatch, nexus_probe_nomatch),
|
||||
DEVMETHOD(bus_read_ivar, nexus_read_ivar),
|
||||
DEVMETHOD(bus_write_ivar, nexus_write_ivar),
|
||||
DEVMETHOD(bus_setup_intr, nexus_setup_intr),
|
||||
DEVMETHOD(bus_teardown_intr, nexus_teardown_intr),
|
||||
DEVMETHOD(bus_alloc_resource, nexus_alloc_resource),
|
||||
DEVMETHOD(bus_activate_resource, nexus_activate_resource),
|
||||
DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource),
|
||||
DEVMETHOD(bus_release_resource, nexus_release_resource),
|
||||
|
||||
/* OFW bus interface */
|
||||
DEVMETHOD(ofw_bus_get_node, nexus_ofw_get_node),
|
||||
DEVMETHOD(ofw_bus_get_name, nexus_ofw_get_name),
|
||||
DEVMETHOD(ofw_bus_get_type, nexus_ofw_get_type),
|
||||
DEVMETHOD(ofw_bus_get_compat, nexus_ofw_get_compat),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t nexus_driver = {
|
||||
"nexus",
|
||||
nexus_methods,
|
||||
sizeof(struct nexus_softc),
|
||||
};
|
||||
|
||||
static devclass_t nexus_devclass;
|
||||
|
||||
DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0);
|
||||
|
||||
static int
|
||||
nexus_probe(device_t dev)
|
||||
{
|
||||
phandle_t root;
|
||||
phandle_t child;
|
||||
struct nexus_softc *sc;
|
||||
u_long start, end;
|
||||
|
||||
if ((root = OF_peer(0)) == -1)
|
||||
panic("nexus_probe: OF_peer failed.");
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
start = 0;
|
||||
end = INTR_VECTORS - 1;
|
||||
|
||||
sc->sc_rman.rm_start = start;
|
||||
sc->sc_rman.rm_end = end;
|
||||
sc->sc_rman.rm_type = RMAN_ARRAY;
|
||||
sc->sc_rman.rm_descr = "Interrupt request lines";
|
||||
if (rman_init(&sc->sc_rman) ||
|
||||
rman_manage_region(&sc->sc_rman, start, end))
|
||||
panic("nexus_probe IRQ rman");
|
||||
|
||||
/*
|
||||
* Allow devices to identify
|
||||
*/
|
||||
bus_generic_probe(dev);
|
||||
|
||||
/*
|
||||
* Now walk the OFW tree to locate top-level devices
|
||||
*/
|
||||
for (child = OF_child(root); child != 0; child = OF_peer(child)) {
|
||||
if (child == -1)
|
||||
panic("nexus_probe(): OF_child failed.");
|
||||
(void)nexus_device_from_node(dev, child);
|
||||
|
||||
}
|
||||
device_set_desc(dev, "Open Firmware Nexus device");
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
nexus_probe_nomatch(device_t dev, device_t child)
|
||||
{
|
||||
char *name, *type;
|
||||
|
||||
if (BUS_READ_IVAR(dev, child, NEXUS_IVAR_NAME,
|
||||
(uintptr_t *)&name) != 0 ||
|
||||
BUS_READ_IVAR(dev, child, NEXUS_IVAR_DEVICE_TYPE,
|
||||
(uintptr_t *)&type) != 0)
|
||||
return;
|
||||
|
||||
if (type == NULL)
|
||||
type = "(unknown)";
|
||||
|
||||
if (bootverbose)
|
||||
device_printf(dev, "<%s>, type %s (no driver attached)\n",
|
||||
name, type);
|
||||
}
|
||||
|
||||
static device_t
|
||||
nexus_add_child(device_t dev, int order, const char *name, int unit)
|
||||
{
|
||||
device_t child;
|
||||
struct nexus_devinfo *dinfo;
|
||||
|
||||
child = device_add_child_ordered(dev, order, name, unit);
|
||||
if (child == NULL)
|
||||
return (NULL);
|
||||
|
||||
dinfo = malloc(sizeof(struct nexus_devinfo), M_NEXUS, M_NOWAIT|M_ZERO);
|
||||
if (dinfo == NULL)
|
||||
return (NULL);
|
||||
|
||||
dinfo->ndi_node = -1;
|
||||
dinfo->ndi_name = name;
|
||||
device_set_ivars(child, dinfo);
|
||||
|
||||
return (child);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
nexus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
|
||||
{
|
||||
struct nexus_devinfo *dinfo;
|
||||
|
||||
if ((dinfo = device_get_ivars(child)) == 0)
|
||||
return (ENOENT);
|
||||
switch (which) {
|
||||
case NEXUS_IVAR_NODE:
|
||||
*result = dinfo->ndi_node;
|
||||
break;
|
||||
case NEXUS_IVAR_NAME:
|
||||
*result = (uintptr_t)dinfo->ndi_name;
|
||||
break;
|
||||
case NEXUS_IVAR_DEVICE_TYPE:
|
||||
*result = (uintptr_t)dinfo->ndi_device_type;
|
||||
break;
|
||||
case NEXUS_IVAR_COMPATIBLE:
|
||||
*result = (uintptr_t)dinfo->ndi_compatible;
|
||||
break;
|
||||
default:
|
||||
return (ENOENT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nexus_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
|
||||
{
|
||||
struct nexus_devinfo *dinfo;
|
||||
|
||||
if ((dinfo = device_get_ivars(child)) == 0)
|
||||
return (ENOENT);
|
||||
|
||||
switch (which) {
|
||||
case NEXUS_IVAR_NAME:
|
||||
return (EINVAL);
|
||||
|
||||
/* Identified devices may want to set these */
|
||||
case NEXUS_IVAR_NODE:
|
||||
dinfo->ndi_node = (phandle_t)value;
|
||||
break;
|
||||
|
||||
case NEXUS_IVAR_DEVICE_TYPE:
|
||||
dinfo->ndi_device_type = (char *)value;
|
||||
break;
|
||||
|
||||
default:
|
||||
return (ENOENT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
|
||||
driver_filter_t *filter, driver_intr_t *ihand, void *arg, void **cookiep)
|
||||
{
|
||||
driver_t *driver;
|
||||
int error;
|
||||
|
||||
/* somebody tried to setup an irq that failed to allocate! */
|
||||
if (res == NULL)
|
||||
panic("nexus_setup_intr: NULL irq resource!");
|
||||
|
||||
*cookiep = 0;
|
||||
if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
|
||||
flags |= INTR_EXCL;
|
||||
|
||||
driver = device_get_driver(child);
|
||||
|
||||
/*
|
||||
* We depend here on rman_activate_resource() being idempotent.
|
||||
*/
|
||||
error = rman_activate_resource(res);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
error = powerpc_setup_intr(device_get_nameunit(child),
|
||||
rman_get_start(res), filter, ihand, arg, flags, cookiep);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
nexus_teardown_intr(device_t dev, device_t child, struct resource *res,
|
||||
void *cookie)
|
||||
{
|
||||
|
||||
return (powerpc_teardown_intr(cookie));
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate resources at the behest of a child. This only handles interrupts,
|
||||
* since I/O resources are handled by child busses.
|
||||
*/
|
||||
static struct resource *
|
||||
nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
||||
u_long start, u_long end, u_long count, u_int flags)
|
||||
{
|
||||
struct nexus_softc *sc;
|
||||
struct resource *rv;
|
||||
|
||||
if (type != SYS_RES_IRQ) {
|
||||
device_printf(bus, "unknown resource request from %s\n",
|
||||
device_get_nameunit(child));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (count == 0 || start + count - 1 != end) {
|
||||
device_printf(bus, "invalid IRQ allocation from %s\n",
|
||||
device_get_nameunit(child));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
sc = device_get_softc(bus);
|
||||
|
||||
rv = rman_reserve_resource(&sc->sc_rman, start, end, count,
|
||||
flags, child);
|
||||
if (rv == NULL) {
|
||||
device_printf(bus, "IRQ allocation failed for %s\n",
|
||||
device_get_nameunit(child));
|
||||
} else
|
||||
rman_set_rid(rv, *rid);
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
static int
|
||||
nexus_activate_resource(device_t bus, device_t child, int type, int rid,
|
||||
struct resource *res)
|
||||
{
|
||||
|
||||
/* Not much to be done yet... */
|
||||
return (rman_activate_resource(res));
|
||||
}
|
||||
|
||||
static int
|
||||
nexus_deactivate_resource(device_t bus, device_t child, int type, int rid,
|
||||
struct resource *res)
|
||||
{
|
||||
|
||||
/* Not much to be done yet... */
|
||||
return (rman_deactivate_resource(res));
|
||||
}
|
||||
|
||||
static int
|
||||
nexus_release_resource(device_t bus, device_t child, int type, int rid,
|
||||
struct resource *res)
|
||||
{
|
||||
|
||||
if (type != SYS_RES_IRQ) {
|
||||
device_printf(bus, "unknown resource request from %s\n",
|
||||
device_get_nameunit(child));
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (rman_release_resource(res));
|
||||
}
|
||||
|
||||
static device_t
|
||||
nexus_device_from_node(device_t parent, phandle_t node)
|
||||
{
|
||||
device_t cdev;
|
||||
struct nexus_devinfo *dinfo;
|
||||
char *name, *type, *compatible;
|
||||
|
||||
OF_getprop_alloc(node, "name", 1, (void **)&name);
|
||||
OF_getprop_alloc(node, "device_type", 1, (void **)&type);
|
||||
OF_getprop_alloc(node, "compatible", 1, (void **)&compatible);
|
||||
cdev = device_add_child(parent, NULL, -1);
|
||||
if (cdev != NULL) {
|
||||
dinfo = malloc(sizeof(*dinfo), M_NEXUS, M_WAITOK);
|
||||
dinfo->ndi_node = node;
|
||||
dinfo->ndi_name = name;
|
||||
dinfo->ndi_device_type = type;
|
||||
dinfo->ndi_compatible = compatible;
|
||||
device_set_ivars(cdev, dinfo);
|
||||
} else
|
||||
free(name, M_OFWPROP);
|
||||
|
||||
return (cdev);
|
||||
}
|
||||
|
||||
static const char *
|
||||
nexus_ofw_get_name(device_t bus, device_t dev)
|
||||
{
|
||||
struct nexus_devinfo *dinfo;
|
||||
|
||||
if ((dinfo = device_get_ivars(dev)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
return (dinfo->ndi_name);
|
||||
}
|
||||
|
||||
static phandle_t
|
||||
nexus_ofw_get_node(device_t bus, device_t dev)
|
||||
{
|
||||
struct nexus_devinfo *dinfo;
|
||||
|
||||
if ((dinfo = device_get_ivars(dev)) == NULL)
|
||||
return (0);
|
||||
|
||||
return (dinfo->ndi_node);
|
||||
}
|
||||
|
||||
static const char *
|
||||
nexus_ofw_get_type(device_t bus, device_t dev)
|
||||
{
|
||||
struct nexus_devinfo *dinfo;
|
||||
|
||||
if ((dinfo = device_get_ivars(dev)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
return (dinfo->ndi_device_type);
|
||||
}
|
||||
|
||||
static const char *
|
||||
nexus_ofw_get_compat(device_t bus, device_t dev)
|
||||
{
|
||||
struct nexus_devinfo *dinfo;
|
||||
|
||||
if ((dinfo = device_get_ivars(dev)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
return (dinfo->ndi_compatible);
|
||||
}
|
@ -1,436 +0,0 @@
|
||||
/*-
|
||||
* Copyright (C) 1996 Wolfgang Solfrank.
|
||||
* Copyright (C) 1996 TooLs GmbH.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by TooLs GmbH.
|
||||
* 4. The name of TooLs GmbH may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/disk.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include <dev/ofw/ofw_pci.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/vm_page.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/powerpc.h>
|
||||
#include <machine/ofw_machdep.h>
|
||||
#include <powerpc/ofw/ofw_pci.h>
|
||||
|
||||
#define OFMEM_REGIONS 32
|
||||
static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
|
||||
static struct mem_region OFfree[OFMEM_REGIONS + 3];
|
||||
|
||||
extern register_t ofmsr[5];
|
||||
extern struct pcpu __pcpu[MAXCPU];
|
||||
extern struct pmap ofw_pmap;
|
||||
static int (*ofwcall)(void *);
|
||||
|
||||
/*
|
||||
* Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
|
||||
*/
|
||||
register_t ofw_sprg0_save;
|
||||
|
||||
static __inline void
|
||||
ofw_sprg_prepare(void)
|
||||
{
|
||||
/*
|
||||
* Assume that interrupt are disabled at this point, or
|
||||
* SPRG1-3 could be trashed
|
||||
*/
|
||||
__asm __volatile("mfsprg0 %0\n\t"
|
||||
"mtsprg0 %1\n\t"
|
||||
"mtsprg1 %2\n\t"
|
||||
"mtsprg2 %3\n\t"
|
||||
"mtsprg3 %4\n\t"
|
||||
: "=&r"(ofw_sprg0_save)
|
||||
: "r"(ofmsr[1]),
|
||||
"r"(ofmsr[2]),
|
||||
"r"(ofmsr[3]),
|
||||
"r"(ofmsr[4]));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ofw_sprg_restore(void)
|
||||
{
|
||||
/*
|
||||
* Note that SPRG1-3 contents are irrelevant. They are scratch
|
||||
* registers used in the early portion of trap handling when
|
||||
* interrupts are disabled.
|
||||
*
|
||||
* PCPU data cannot be used until this routine is called !
|
||||
*/
|
||||
__asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
|
||||
}
|
||||
|
||||
/*
|
||||
* Memory region utilities: determine if two regions overlap,
|
||||
* and merge two overlapping regions into one
|
||||
*/
|
||||
static int
|
||||
memr_overlap(struct mem_region *r1, struct mem_region *r2)
|
||||
{
|
||||
if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
|
||||
(r2->mr_start + r2->mr_size) < r1->mr_start)
|
||||
return (FALSE);
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
memr_merge(struct mem_region *from, struct mem_region *to)
|
||||
{
|
||||
int end;
|
||||
end = imax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
|
||||
to->mr_start = imin(from->mr_start, to->mr_start);
|
||||
to->mr_size = end - to->mr_start;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called during powerpc_init, before the system is really initialized.
|
||||
* It shall provide the total and the available regions of RAM.
|
||||
* Both lists must have a zero-size entry as terminator.
|
||||
* The available regions need not take the kernel into account, but needs
|
||||
* to provide space for two additional entry beyond the terminating one.
|
||||
*/
|
||||
void
|
||||
mem_regions(struct mem_region **memp, int *memsz,
|
||||
struct mem_region **availp, int *availsz)
|
||||
{
|
||||
int phandle;
|
||||
int asz, msz, fsz;
|
||||
int i, j;
|
||||
int still_merging;
|
||||
|
||||
/*
|
||||
* Get memory.
|
||||
*/
|
||||
if ((phandle = OF_finddevice("/memory")) == -1
|
||||
|| (msz = OF_getprop(phandle, "reg",
|
||||
OFmem, sizeof OFmem[0] * OFMEM_REGIONS))
|
||||
<= 0
|
||||
|| (asz = OF_getprop(phandle, "available",
|
||||
OFavail, sizeof OFavail[0] * OFMEM_REGIONS))
|
||||
<= 0)
|
||||
panic("no memory?");
|
||||
*memp = OFmem;
|
||||
*memsz = msz / sizeof(struct mem_region);
|
||||
|
||||
/*
|
||||
* OFavail may have overlapping regions - collapse these
|
||||
* and copy out remaining regions to OFfree
|
||||
*/
|
||||
asz /= sizeof(struct mem_region);
|
||||
do {
|
||||
still_merging = FALSE;
|
||||
for (i = 0; i < asz; i++) {
|
||||
if (OFavail[i].mr_size == 0)
|
||||
continue;
|
||||
for (j = i+1; j < asz; j++) {
|
||||
if (OFavail[j].mr_size == 0)
|
||||
continue;
|
||||
if (memr_overlap(&OFavail[j], &OFavail[i])) {
|
||||
memr_merge(&OFavail[j], &OFavail[i]);
|
||||
/* mark inactive */
|
||||
OFavail[j].mr_size = 0;
|
||||
still_merging = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (still_merging == TRUE);
|
||||
|
||||
/* evict inactive ranges */
|
||||
for (i = 0, fsz = 0; i < asz; i++) {
|
||||
if (OFavail[i].mr_size != 0) {
|
||||
OFfree[fsz] = OFavail[i];
|
||||
fsz++;
|
||||
}
|
||||
}
|
||||
|
||||
*availp = OFfree;
|
||||
*availsz = fsz;
|
||||
}
|
||||
|
||||
void
|
||||
set_openfirm_callback(int (*openfirm)(void *))
|
||||
{
|
||||
|
||||
ofwcall = openfirm;
|
||||
}
|
||||
|
||||
int
|
||||
openfirmware(void *args)
|
||||
{
|
||||
long oldmsr;
|
||||
int result;
|
||||
u_int srsave[16];
|
||||
u_int i;
|
||||
|
||||
__asm __volatile( "\t"
|
||||
"sync\n\t"
|
||||
"mfmsr %0\n\t"
|
||||
"mtmsr %1\n\t"
|
||||
"isync\n"
|
||||
: "=r" (oldmsr)
|
||||
: "r" (ofmsr[0])
|
||||
);
|
||||
|
||||
ofw_sprg_prepare();
|
||||
|
||||
if (pmap_bootstrapped) {
|
||||
/*
|
||||
* Swap the kernel's address space with Open Firmware's
|
||||
*/
|
||||
for (i = 0; i < 16; i++) {
|
||||
srsave[i] = mfsrin(i << ADDR_SR_SHFT);
|
||||
mtsrin(i << ADDR_SR_SHFT, ofw_pmap.pm_sr[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear battable[] translations
|
||||
*/
|
||||
__asm __volatile("mtdbatu 2, %0\n"
|
||||
"mtdbatu 3, %0" : : "r" (0));
|
||||
isync();
|
||||
}
|
||||
|
||||
result = ofwcall(args);
|
||||
|
||||
if (pmap_bootstrapped) {
|
||||
/*
|
||||
* Restore the kernel's addr space. The isync() doesn;t
|
||||
* work outside the loop unless mtsrin() is open-coded
|
||||
* in an asm statement :(
|
||||
*/
|
||||
for (i = 0; i < 16; i++) {
|
||||
mtsrin(i << ADDR_SR_SHFT, srsave[i]);
|
||||
isync();
|
||||
}
|
||||
}
|
||||
|
||||
ofw_sprg_restore();
|
||||
|
||||
__asm( "\t"
|
||||
"mtmsr %0\n\t"
|
||||
"isync\n"
|
||||
: : "r" (oldmsr)
|
||||
);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
OF_halt()
|
||||
{
|
||||
int retval; /* dummy, this may not be needed */
|
||||
|
||||
OF_interpret("shut-down", 1, &retval);
|
||||
for (;;); /* just in case */
|
||||
}
|
||||
|
||||
void
|
||||
OF_reboot()
|
||||
{
|
||||
int retval; /* dummy, this may not be needed */
|
||||
|
||||
OF_interpret("reset-all", 1, &retval);
|
||||
for (;;); /* just in case */
|
||||
}
|
||||
|
||||
void
|
||||
OF_getetheraddr(device_t dev, u_char *addr)
|
||||
{
|
||||
phandle_t node;
|
||||
|
||||
node = ofw_pci_find_node(dev);
|
||||
OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a bus handle and bus tag that corresponds to the register
|
||||
* numbered regno for the device referenced by the package handle
|
||||
* dev. This function is intended to be used by console drivers in
|
||||
* early boot only. It works by mapping the address of the device's
|
||||
* register in the address space of its parent and recursively walk
|
||||
* the device tree upward this way.
|
||||
*/
|
||||
static void
|
||||
OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
|
||||
{
|
||||
char name[16];
|
||||
uint32_t addr, size;
|
||||
int pci, res;
|
||||
|
||||
res = OF_getprop(node, "#address-cells", &addr, sizeof(addr));
|
||||
if (res == -1)
|
||||
addr = 2;
|
||||
res = OF_getprop(node, "#size-cells", &size, sizeof(size));
|
||||
if (res == -1)
|
||||
size = 1;
|
||||
pci = 0;
|
||||
if (addr == 3 && size == 2) {
|
||||
res = OF_getprop(node, "name", name, sizeof(name));
|
||||
if (res != -1) {
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
pci = (strcmp(name, "pci") == 0) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
if (addrp != NULL)
|
||||
*addrp = addr;
|
||||
if (sizep != NULL)
|
||||
*sizep = size;
|
||||
if (pcip != NULL)
|
||||
*pcip = pci;
|
||||
}
|
||||
|
||||
int
|
||||
OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
|
||||
bus_space_handle_t *handle)
|
||||
{
|
||||
uint32_t cell[32];
|
||||
bus_addr_t addr, raddr, baddr;
|
||||
bus_size_t size, rsize;
|
||||
uint32_t c, nbridge, naddr, nsize;
|
||||
phandle_t bridge, parent;
|
||||
u_int spc, rspc;
|
||||
int pci, pcib, res;
|
||||
|
||||
/* Sanity checking. */
|
||||
if (dev == 0)
|
||||
return (EINVAL);
|
||||
bridge = OF_parent(dev);
|
||||
if (bridge == 0)
|
||||
return (EINVAL);
|
||||
if (regno < 0)
|
||||
return (EINVAL);
|
||||
if (tag == NULL || handle == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
/* Get the requested register. */
|
||||
OF_get_addr_props(bridge, &naddr, &nsize, &pci);
|
||||
res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
|
||||
cell, sizeof(cell));
|
||||
if (res == -1)
|
||||
return (ENXIO);
|
||||
if (res % sizeof(cell[0]))
|
||||
return (ENXIO);
|
||||
res /= sizeof(cell[0]);
|
||||
regno *= naddr + nsize;
|
||||
if (regno + naddr + nsize > res)
|
||||
return (EINVAL);
|
||||
spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0;
|
||||
addr = 0;
|
||||
for (c = 0; c < naddr; c++)
|
||||
addr = ((uint64_t)addr << 32) | cell[regno++];
|
||||
size = 0;
|
||||
for (c = 0; c < nsize; c++)
|
||||
size = ((uint64_t)size << 32) | cell[regno++];
|
||||
|
||||
/*
|
||||
* Map the address range in the bridge's decoding window as given
|
||||
* by the "ranges" property. If a node doesn't have such property
|
||||
* then no mapping is done.
|
||||
*/
|
||||
parent = OF_parent(bridge);
|
||||
while (parent != 0) {
|
||||
OF_get_addr_props(parent, &nbridge, NULL, &pcib);
|
||||
res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
|
||||
if (res == -1)
|
||||
goto next;
|
||||
if (res % sizeof(cell[0]))
|
||||
return (ENXIO);
|
||||
res /= sizeof(cell[0]);
|
||||
regno = 0;
|
||||
while (regno < res) {
|
||||
rspc = (pci)
|
||||
? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
|
||||
: ~0;
|
||||
if (rspc != spc) {
|
||||
regno += naddr + nbridge + nsize;
|
||||
continue;
|
||||
}
|
||||
raddr = 0;
|
||||
for (c = 0; c < naddr; c++)
|
||||
raddr = ((uint64_t)raddr << 32) | cell[regno++];
|
||||
rspc = (pcib)
|
||||
? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
|
||||
: ~0;
|
||||
baddr = 0;
|
||||
for (c = 0; c < nbridge; c++)
|
||||
baddr = ((uint64_t)baddr << 32) | cell[regno++];
|
||||
rsize = 0;
|
||||
for (c = 0; c < nsize; c++)
|
||||
rsize = ((uint64_t)rsize << 32) | cell[regno++];
|
||||
if (addr < raddr || addr >= raddr + rsize)
|
||||
continue;
|
||||
addr = addr - raddr + baddr;
|
||||
if (rspc != ~0)
|
||||
spc = rspc;
|
||||
}
|
||||
|
||||
next:
|
||||
bridge = parent;
|
||||
parent = OF_parent(bridge);
|
||||
OF_get_addr_props(bridge, &naddr, &nsize, &pci);
|
||||
}
|
||||
|
||||
/* Default to memory mapped I/O. */
|
||||
*tag = PPC_BUS_SPACE_MEM;
|
||||
if (spc == OFW_PCI_PHYS_HI_SPACE_IO)
|
||||
*tag = PPC_BUS_SPACE_IO;
|
||||
return (bus_space_map(*tag, addr, size, 0, handle));
|
||||
}
|
||||
|
||||
int
|
||||
mem_valid(vm_offset_t addr, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < OFMEM_REGIONS; i++)
|
||||
if ((addr >= OFmem[i].mr_start)
|
||||
&& (addr + len < OFmem[i].mr_start + OFmem[i].mr_size))
|
||||
return (0);
|
||||
|
||||
return (EFAULT);
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
/* $FreeBSD$ */
|
||||
/* $NetBSD: ofwmagic.S,v 1.2 1997/10/09 08:38:18 jtc Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Jason R. Thorpe.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Magic note section used by Open Firmware.
|
||||
*/
|
||||
|
||||
.section ".note"
|
||||
|
||||
/*# note header */
|
||||
|
||||
/*# length of name */
|
||||
.long 8
|
||||
|
||||
/*# note descriptor size */
|
||||
.long 20
|
||||
|
||||
/*# note type (IEEE 1275) */
|
||||
.long 0x1275
|
||||
|
||||
/*# name of owner */
|
||||
.asciz "PowerPC"
|
||||
.balign 4
|
||||
|
||||
|
||||
/*# note descriptor */
|
||||
|
||||
/*# real mode (-1) or virtual mode (0) */
|
||||
.long 0
|
||||
|
||||
/*# real-base */
|
||||
.long -1
|
||||
/*# real-size */
|
||||
.long -1
|
||||
|
||||
/*# virt-base */
|
||||
.long -1
|
||||
/*# virt-size */
|
||||
.long -1
|
@ -1,158 +0,0 @@
|
||||
/* $FreeBSD$ */
|
||||
/* $NetBSD: locore.S,v 1.24 2000/05/31 05:09:17 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 2001 Benno Rice
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*-
|
||||
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
|
||||
* Copyright (C) 1995, 1996 TooLs GmbH.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by TooLs GmbH.
|
||||
* 4. The name of TooLs GmbH may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "assym.s"
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <machine/trap.h>
|
||||
#include <machine/param.h>
|
||||
#include <machine/sr.h>
|
||||
#include <machine/psl.h>
|
||||
#include <machine/asm.h>
|
||||
|
||||
/*
|
||||
* void cpu_switch(struct thread *old,
|
||||
* struct thread *new,
|
||||
* struct mutex *mtx);
|
||||
*
|
||||
* Switch to a new thread saving the current state in the old thread.
|
||||
*/
|
||||
ENTRY(cpu_switch)
|
||||
stw %r5,TD_LOCK(%r3) /* ULE: update old thread's lock */
|
||||
/* XXX needs to change for MP */
|
||||
|
||||
lwz %r5,TD_PCB(%r3) /* Get the old thread's PCB ptr */
|
||||
mr %r12,%r2
|
||||
stmw %r12,PCB_CONTEXT(%r5) /* Save the non-volatile GP regs.
|
||||
These can now be used for scratch */
|
||||
|
||||
mfcr %r16 /* Save the condition register */
|
||||
stw %r16,PCB_CR(%r5)
|
||||
mflr %r16 /* Save the link register */
|
||||
stw %r16,PCB_LR(%r5)
|
||||
mfsr %r16,USER_SR /* Save USER_SR for copyin/out */
|
||||
isync
|
||||
stw %r16,PCB_USR(%r5)
|
||||
stw %r1,PCB_SP(%r5) /* Save the stack pointer */
|
||||
|
||||
mr %r14,%r3 /* Copy the old thread ptr... */
|
||||
mr %r15,%r4 /* and the new thread ptr in scratch */
|
||||
|
||||
lwz %r6,PCB_FLAGS(%r5) /* Save FPU context if needed */
|
||||
andi. %r6, %r6, PCB_FPU
|
||||
beq .L1
|
||||
bl save_fpu
|
||||
mr %r3,%r14 /* restore old thread ptr */
|
||||
.L1:
|
||||
bl pmap_deactivate /* Deactivate the current pmap */
|
||||
|
||||
mr %r3,%r15 /* Get new thread ptr */
|
||||
bl pmap_activate /* Activate the new address space */
|
||||
|
||||
mfsprg %r7,0 /* Get the pcpu pointer */
|
||||
stw %r15,PC_CURTHREAD(%r7) /* Store new current thread */
|
||||
lwz %r17,TD_PCB(%r15) /* Store new current PCB */
|
||||
stw %r17,PC_CURPCB(%r7)
|
||||
|
||||
lwz %r6, PCB_FLAGS(%r17) /* Restore FPU context if needed */
|
||||
andi. %r6, %r6, PCB_FPU
|
||||
beq .L2
|
||||
mr %r3,%r15 /* Pass curthread to enable_fpu */
|
||||
bl enable_fpu
|
||||
|
||||
/* thread to restore is in r3 */
|
||||
.L2:
|
||||
mr %r3,%r17 /* Recover PCB ptr */
|
||||
lmw %r12,PCB_CONTEXT(%r3) /* Load the non-volatile GP regs */
|
||||
mr %r2,%r12
|
||||
lwz %r5,PCB_CR(%r3) /* Load the condition register */
|
||||
mtcr %r5
|
||||
lwz %r5,PCB_LR(%r3) /* Load the link register */
|
||||
mtlr %r5
|
||||
lwz %r5,PCB_USR(%r3) /* Load the USER_SR segment reg */
|
||||
mtsr USER_SR,%r5
|
||||
isync
|
||||
lwz %r1,PCB_SP(%r3) /* Load the stack pointer */
|
||||
blr
|
||||
|
||||
/*
|
||||
* savectx(pcb)
|
||||
* Update pcb, saving current processor state
|
||||
*/
|
||||
ENTRY(savectx)
|
||||
mr %r12,%r2
|
||||
stmw %r12,PCB_CONTEXT(%r3) /* Save the non-volatile GP regs */
|
||||
mfcr %r4 /* Save the condition register */
|
||||
stw %r4,PCB_CONTEXT(%r3)
|
||||
blr
|
||||
|
||||
/*
|
||||
* fork_trampoline()
|
||||
* Set up the return from cpu_fork()
|
||||
*/
|
||||
ENTRY(fork_trampoline)
|
||||
lwz %r3,CF_FUNC(%r1)
|
||||
lwz %r4,CF_ARG0(%r1)
|
||||
lwz %r5,CF_ARG1(%r1)
|
||||
bl fork_exit
|
||||
addi %r1,%r1,CF_SIZE-FSP /* Allow 8 bytes in front of
|
||||
trapframe to simulate FRAME_SETUP
|
||||
does when allocating space for
|
||||
a frame pointer/saved LR */
|
||||
b trapexit
|
@ -1,681 +0,0 @@
|
||||
/*-
|
||||
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
|
||||
* Copyright (C) 1995, 1996 TooLs GmbH.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by TooLs GmbH.
|
||||
* 4. The name of TooLs GmbH may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $NetBSD: trap.c,v 1.58 2002/03/04 04:07:35 dbj Exp $
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_ktrace.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/pioctl.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/sysent.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/signalvar.h>
|
||||
#ifdef KTRACE
|
||||
#include <sys/ktrace.h>
|
||||
#endif
|
||||
#include <sys/vmmeter.h>
|
||||
|
||||
#include <security/audit/audit.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <vm/vm_extern.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/vm_kern.h>
|
||||
#include <vm/vm_map.h>
|
||||
#include <vm/vm_page.h>
|
||||
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/db_machdep.h>
|
||||
#include <machine/fpu.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/pmap.h>
|
||||
#include <machine/psl.h>
|
||||
#include <machine/trap.h>
|
||||
#include <machine/spr.h>
|
||||
#include <machine/sr.h>
|
||||
|
||||
static void trap_fatal(struct trapframe *frame);
|
||||
static void printtrap(u_int vector, struct trapframe *frame, int isfatal,
|
||||
int user);
|
||||
static int trap_pfault(struct trapframe *frame, int user);
|
||||
static int fix_unaligned(struct thread *td, struct trapframe *frame);
|
||||
static int handle_onfault(struct trapframe *frame);
|
||||
static void syscall(struct trapframe *frame);
|
||||
|
||||
static __inline void setusr(u_int);
|
||||
|
||||
int setfault(faultbuf); /* defined in locore.S */
|
||||
|
||||
/* Why are these not defined in a header? */
|
||||
int badaddr(void *, size_t);
|
||||
int badaddr_read(void *, size_t, int *);
|
||||
|
||||
extern char *syscallnames[];
|
||||
|
||||
struct powerpc_exception {
|
||||
u_int vector;
|
||||
char *name;
|
||||
};
|
||||
|
||||
static struct powerpc_exception powerpc_exceptions[] = {
|
||||
{ 0x0100, "system reset" },
|
||||
{ 0x0200, "machine check" },
|
||||
{ 0x0300, "data storage interrupt" },
|
||||
{ 0x0400, "instruction storage interrupt" },
|
||||
{ 0x0500, "external interrupt" },
|
||||
{ 0x0600, "alignment" },
|
||||
{ 0x0700, "program" },
|
||||
{ 0x0800, "floating-point unavailable" },
|
||||
{ 0x0900, "decrementer" },
|
||||
{ 0x0c00, "system call" },
|
||||
{ 0x0d00, "trace" },
|
||||
{ 0x0e00, "floating-point assist" },
|
||||
{ 0x0f00, "performance monitoring" },
|
||||
{ 0x0f20, "altivec unavailable" },
|
||||
{ 0x1000, "instruction tlb miss" },
|
||||
{ 0x1100, "data load tlb miss" },
|
||||
{ 0x1200, "data store tlb miss" },
|
||||
{ 0x1300, "instruction breakpoint" },
|
||||
{ 0x1400, "system management" },
|
||||
{ 0x1600, "altivec assist" },
|
||||
{ 0x1700, "thermal management" },
|
||||
{ 0x2000, "run mode/trace" },
|
||||
{ 0x3000, NULL }
|
||||
};
|
||||
|
||||
static const char *
|
||||
trapname(u_int vector)
|
||||
{
|
||||
struct powerpc_exception *pe;
|
||||
|
||||
for (pe = powerpc_exceptions; pe->vector != 0x3000; pe++) {
|
||||
if (pe->vector == vector)
|
||||
return (pe->name);
|
||||
}
|
||||
|
||||
return ("unknown");
|
||||
}
|
||||
|
||||
void
|
||||
trap(struct trapframe *frame)
|
||||
{
|
||||
struct thread *td;
|
||||
struct proc *p;
|
||||
int sig, type, user;
|
||||
u_int ucode;
|
||||
ksiginfo_t ksi;
|
||||
|
||||
PCPU_INC(cnt.v_trap);
|
||||
|
||||
td = PCPU_GET(curthread);
|
||||
p = td->td_proc;
|
||||
|
||||
type = ucode = frame->exc;
|
||||
sig = 0;
|
||||
user = frame->srr1 & PSL_PR;
|
||||
|
||||
CTR3(KTR_TRAP, "trap: %s type=%s (%s)", td->td_name,
|
||||
trapname(type), user ? "user" : "kernel");
|
||||
|
||||
if (user) {
|
||||
td->td_pticks = 0;
|
||||
td->td_frame = frame;
|
||||
if (td->td_ucred != p->p_ucred)
|
||||
cred_update_thread(td);
|
||||
|
||||
/* User Mode Traps */
|
||||
switch (type) {
|
||||
case EXC_RUNMODETRC:
|
||||
case EXC_TRC:
|
||||
frame->srr1 &= ~PSL_SE;
|
||||
sig = SIGTRAP;
|
||||
break;
|
||||
|
||||
case EXC_DSI:
|
||||
case EXC_ISI:
|
||||
sig = trap_pfault(frame, 1);
|
||||
break;
|
||||
|
||||
case EXC_SC:
|
||||
syscall(frame);
|
||||
break;
|
||||
|
||||
case EXC_FPU:
|
||||
KASSERT((td->td_pcb->pcb_flags & PCB_FPU) != PCB_FPU,
|
||||
("FPU already enabled for thread"));
|
||||
enable_fpu(td);
|
||||
break;
|
||||
|
||||
#ifdef ALTIVEC
|
||||
case EXC_VEC:
|
||||
if ((vecthread = PCPU_GET(vecthread)) != NULL) {
|
||||
KASSERT(vecthread != td,
|
||||
("altivec already enabled"));
|
||||
save_vec(vecthread);
|
||||
}
|
||||
PCPU_SET(vecthread, td);
|
||||
td->td_pcb->pcb_veccpu = PCPU_GET(cpuid);
|
||||
enable_vec(td);
|
||||
frame->srr1 |= PSL_VEC;
|
||||
break;
|
||||
#else
|
||||
case EXC_VEC:
|
||||
case EXC_VECAST:
|
||||
sig = SIGILL;
|
||||
break;
|
||||
#endif /* ALTIVEC */
|
||||
|
||||
case EXC_ALI:
|
||||
if (fix_unaligned(td, frame) != 0)
|
||||
sig = SIGBUS;
|
||||
else
|
||||
frame->srr0 += 4;
|
||||
break;
|
||||
|
||||
case EXC_PGM:
|
||||
/* XXX temporarily */
|
||||
/* XXX: Magic Number? */
|
||||
if (frame->srr1 & 0x0002000)
|
||||
sig = SIGTRAP;
|
||||
else
|
||||
sig = SIGILL;
|
||||
break;
|
||||
|
||||
default:
|
||||
trap_fatal(frame);
|
||||
}
|
||||
} else {
|
||||
/* Kernel Mode Traps */
|
||||
|
||||
KASSERT(cold || td->td_ucred != NULL,
|
||||
("kernel trap doesn't have ucred"));
|
||||
switch (type) {
|
||||
case EXC_DSI:
|
||||
if (trap_pfault(frame, 0) == 0)
|
||||
return;
|
||||
break;
|
||||
case EXC_MCHK:
|
||||
if (handle_onfault(frame))
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
trap_fatal(frame);
|
||||
}
|
||||
|
||||
#ifdef ALTIVEC
|
||||
if (td != PCPU_GET(vecthread) ||
|
||||
td->td_pcb->pcb_veccpu != PCPU_GET(cpuid))
|
||||
frame->srr1 &= ~PSL_VEC;
|
||||
#endif /* ALTIVEC */
|
||||
|
||||
if (sig != 0) {
|
||||
if (p->p_sysent->sv_transtrap != NULL)
|
||||
sig = (p->p_sysent->sv_transtrap)(sig, type);
|
||||
ksiginfo_init_trap(&ksi);
|
||||
ksi.ksi_signo = sig;
|
||||
ksi.ksi_code = (int) ucode; /* XXX, not POSIX */
|
||||
/* ksi.ksi_addr = ? */
|
||||
ksi.ksi_trapno = type;
|
||||
trapsignal(td, &ksi);
|
||||
}
|
||||
|
||||
userret(td, frame);
|
||||
mtx_assert(&Giant, MA_NOTOWNED);
|
||||
}
|
||||
|
||||
static void
|
||||
trap_fatal(struct trapframe *frame)
|
||||
{
|
||||
|
||||
printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR));
|
||||
#ifdef KDB
|
||||
if ((debugger_on_panic || kdb_active) &&
|
||||
kdb_trap(frame->exc, 0, frame))
|
||||
return;
|
||||
#endif
|
||||
panic("%s trap", trapname(frame->exc));
|
||||
}
|
||||
|
||||
static void
|
||||
printtrap(u_int vector, struct trapframe *frame, int isfatal, int user)
|
||||
{
|
||||
|
||||
printf("\n");
|
||||
printf("%s %s trap:\n", isfatal ? "fatal" : "handled",
|
||||
user ? "user" : "kernel");
|
||||
printf("\n");
|
||||
printf(" exception = 0x%x (%s)\n", vector >> 8,
|
||||
trapname(vector));
|
||||
switch (vector) {
|
||||
case EXC_DSI:
|
||||
printf(" virtual address = 0x%x\n", frame->dar);
|
||||
break;
|
||||
case EXC_ISI:
|
||||
printf(" virtual address = 0x%x\n", frame->srr0);
|
||||
break;
|
||||
}
|
||||
printf(" srr0 = 0x%x\n", frame->srr0);
|
||||
printf(" srr1 = 0x%x\n", frame->srr1);
|
||||
printf(" curthread = %p\n", curthread);
|
||||
if (curthread != NULL)
|
||||
printf(" pid = %d, comm = %s\n",
|
||||
curthread->td_proc->p_pid, curthread->td_name);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Handles a fatal fault when we have onfault state to recover. Returns
|
||||
* non-zero if there was onfault recovery state available.
|
||||
*/
|
||||
static int
|
||||
handle_onfault(struct trapframe *frame)
|
||||
{
|
||||
struct thread *td;
|
||||
faultbuf *fb;
|
||||
|
||||
td = curthread;
|
||||
fb = td->td_pcb->pcb_onfault;
|
||||
if (fb != NULL) {
|
||||
frame->srr0 = (*fb)[0];
|
||||
frame->fixreg[1] = (*fb)[1];
|
||||
frame->fixreg[2] = (*fb)[2];
|
||||
frame->fixreg[3] = 1;
|
||||
frame->cr = (*fb)[3];
|
||||
bcopy(&(*fb)[4], &frame->fixreg[13],
|
||||
19 * sizeof(register_t));
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
syscall(struct trapframe *frame)
|
||||
{
|
||||
caddr_t params;
|
||||
struct sysent *callp;
|
||||
struct thread *td;
|
||||
struct proc *p;
|
||||
int error, n;
|
||||
size_t narg;
|
||||
register_t args[10];
|
||||
u_int code;
|
||||
|
||||
td = PCPU_GET(curthread);
|
||||
p = td->td_proc;
|
||||
|
||||
PCPU_INC(cnt.v_syscall);
|
||||
|
||||
#ifdef KSE
|
||||
if (p->p_flag & P_SA)
|
||||
thread_user_enter(td);
|
||||
#endif
|
||||
|
||||
code = frame->fixreg[0];
|
||||
params = (caddr_t)(frame->fixreg + FIRSTARG);
|
||||
n = NARGREG;
|
||||
|
||||
if (p->p_sysent->sv_prepsyscall) {
|
||||
/*
|
||||
* The prep code is MP aware.
|
||||
*/
|
||||
(*p->p_sysent->sv_prepsyscall)(frame, args, &code, ¶ms);
|
||||
} else if (code == SYS_syscall) {
|
||||
/*
|
||||
* code is first argument,
|
||||
* followed by actual args.
|
||||
*/
|
||||
code = *(u_int *) params;
|
||||
params += sizeof(register_t);
|
||||
n -= 1;
|
||||
} else if (code == SYS___syscall) {
|
||||
/*
|
||||
* Like syscall, but code is a quad,
|
||||
* so as to maintain quad alignment
|
||||
* for the rest of the args.
|
||||
*/
|
||||
params += sizeof(register_t);
|
||||
code = *(u_int *) params;
|
||||
params += sizeof(register_t);
|
||||
n -= 2;
|
||||
}
|
||||
|
||||
if (p->p_sysent->sv_mask)
|
||||
code &= p->p_sysent->sv_mask;
|
||||
|
||||
if (code >= p->p_sysent->sv_size)
|
||||
callp = &p->p_sysent->sv_table[0];
|
||||
else
|
||||
callp = &p->p_sysent->sv_table[code];
|
||||
|
||||
narg = callp->sy_narg;
|
||||
|
||||
if (narg > n) {
|
||||
bcopy(params, args, n * sizeof(register_t));
|
||||
error = copyin(MOREARGS(frame->fixreg[1]), args + n,
|
||||
(narg - n) * sizeof(register_t));
|
||||
params = (caddr_t)args;
|
||||
} else
|
||||
error = 0;
|
||||
|
||||
CTR5(KTR_SYSC, "syscall: p=%s %s(%x %x %x)", td->td_name,
|
||||
syscallnames[code],
|
||||
frame->fixreg[FIRSTARG],
|
||||
frame->fixreg[FIRSTARG+1],
|
||||
frame->fixreg[FIRSTARG+2]);
|
||||
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(td, KTR_SYSCALL))
|
||||
ktrsyscall(code, narg, (register_t *)params);
|
||||
#endif
|
||||
|
||||
td->td_syscalls++;
|
||||
|
||||
if (error == 0) {
|
||||
td->td_retval[0] = 0;
|
||||
td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
|
||||
|
||||
STOPEVENT(p, S_SCE, narg);
|
||||
|
||||
PTRACESTOP_SC(p, td, S_PT_SCE);
|
||||
|
||||
AUDIT_SYSCALL_ENTER(code, td);
|
||||
error = (*callp->sy_call)(td, params);
|
||||
AUDIT_SYSCALL_EXIT(error, td);
|
||||
|
||||
CTR3(KTR_SYSC, "syscall: p=%s %s ret=%x", td->td_name,
|
||||
syscallnames[code], td->td_retval[0]);
|
||||
}
|
||||
switch (error) {
|
||||
case 0:
|
||||
if (frame->fixreg[0] == SYS___syscall &&
|
||||
code != SYS_freebsd6_lseek && code != SYS_lseek) {
|
||||
/*
|
||||
* 64-bit return, 32-bit syscall. Fixup byte order
|
||||
*/
|
||||
frame->fixreg[FIRSTARG] = 0;
|
||||
frame->fixreg[FIRSTARG + 1] = td->td_retval[0];
|
||||
} else {
|
||||
frame->fixreg[FIRSTARG] = td->td_retval[0];
|
||||
frame->fixreg[FIRSTARG + 1] = td->td_retval[1];
|
||||
}
|
||||
/* XXX: Magic number */
|
||||
frame->cr &= ~0x10000000;
|
||||
break;
|
||||
case ERESTART:
|
||||
/*
|
||||
* Set user's pc back to redo the system call.
|
||||
*/
|
||||
frame->srr0 -= 4;
|
||||
break;
|
||||
case EJUSTRETURN:
|
||||
/* nothing to do */
|
||||
break;
|
||||
default:
|
||||
if (p->p_sysent->sv_errsize) {
|
||||
if (error >= p->p_sysent->sv_errsize)
|
||||
error = -1; /* XXX */
|
||||
else
|
||||
error = p->p_sysent->sv_errtbl[error];
|
||||
}
|
||||
frame->fixreg[FIRSTARG] = error;
|
||||
/* XXX: Magic number: Carry Flag Equivalent? */
|
||||
frame->cr |= 0x10000000;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for misbehavior.
|
||||
*/
|
||||
WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
|
||||
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
|
||||
KASSERT(td->td_critnest == 0,
|
||||
("System call %s returning in a critical section",
|
||||
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???"));
|
||||
KASSERT(td->td_locks == 0,
|
||||
("System call %s returning with %d locks held",
|
||||
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???",
|
||||
td->td_locks));
|
||||
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(td, KTR_SYSRET))
|
||||
ktrsysret(code, error, td->td_retval[0]);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Does the comment in the i386 code about errno apply here?
|
||||
*/
|
||||
STOPEVENT(p, S_SCX, code);
|
||||
|
||||
PTRACESTOP_SC(p, td, S_PT_SCX);
|
||||
}
|
||||
|
||||
static int
|
||||
trap_pfault(struct trapframe *frame, int user)
|
||||
{
|
||||
vm_offset_t eva, va;
|
||||
struct thread *td;
|
||||
struct proc *p;
|
||||
vm_map_t map;
|
||||
vm_prot_t ftype;
|
||||
int rv;
|
||||
u_int user_sr;
|
||||
|
||||
td = curthread;
|
||||
p = td->td_proc;
|
||||
if (frame->exc == EXC_ISI) {
|
||||
eva = frame->srr0;
|
||||
ftype = VM_PROT_READ | VM_PROT_EXECUTE;
|
||||
} else {
|
||||
eva = frame->dar;
|
||||
if (frame->dsisr & DSISR_STORE)
|
||||
ftype = VM_PROT_WRITE;
|
||||
else
|
||||
ftype = VM_PROT_READ;
|
||||
}
|
||||
|
||||
if (user) {
|
||||
map = &p->p_vmspace->vm_map;
|
||||
} else {
|
||||
if ((eva >> ADDR_SR_SHFT) == USER_SR) {
|
||||
if (p->p_vmspace == NULL)
|
||||
return (SIGSEGV);
|
||||
|
||||
__asm ("mfsr %0, %1"
|
||||
: "=r"(user_sr)
|
||||
: "K"(USER_SR));
|
||||
eva &= ADDR_PIDX | ADDR_POFF;
|
||||
eva |= user_sr << ADDR_SR_SHFT;
|
||||
map = &p->p_vmspace->vm_map;
|
||||
} else {
|
||||
map = kernel_map;
|
||||
}
|
||||
}
|
||||
va = trunc_page(eva);
|
||||
|
||||
if (map != kernel_map) {
|
||||
/*
|
||||
* Keep swapout from messing with us during this
|
||||
* critical time.
|
||||
*/
|
||||
PROC_LOCK(p);
|
||||
++p->p_lock;
|
||||
PROC_UNLOCK(p);
|
||||
|
||||
/* Fault in the user page: */
|
||||
rv = vm_fault(map, va, ftype,
|
||||
(ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY
|
||||
: VM_FAULT_NORMAL);
|
||||
|
||||
PROC_LOCK(p);
|
||||
--p->p_lock;
|
||||
PROC_UNLOCK(p);
|
||||
} else {
|
||||
/*
|
||||
* Don't have to worry about process locking or stacks in the
|
||||
* kernel.
|
||||
*/
|
||||
rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
|
||||
}
|
||||
|
||||
if (rv == KERN_SUCCESS)
|
||||
return (0);
|
||||
|
||||
if (!user && handle_onfault(frame))
|
||||
return (0);
|
||||
|
||||
return (SIGSEGV);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
setusr(u_int content)
|
||||
{
|
||||
__asm __volatile ("isync; mtsr %0,%1; isync"
|
||||
:: "n"(USER_SR), "r"(content));
|
||||
}
|
||||
|
||||
int
|
||||
badaddr(void *addr, size_t size)
|
||||
{
|
||||
return (badaddr_read(addr, size, NULL));
|
||||
}
|
||||
|
||||
int
|
||||
badaddr_read(void *addr, size_t size, int *rptr)
|
||||
{
|
||||
struct thread *td;
|
||||
faultbuf env;
|
||||
int x;
|
||||
|
||||
/* Get rid of any stale machine checks that have been waiting. */
|
||||
__asm __volatile ("sync; isync");
|
||||
|
||||
td = PCPU_GET(curthread);
|
||||
|
||||
if (setfault(env)) {
|
||||
td->td_pcb->pcb_onfault = 0;
|
||||
__asm __volatile ("sync");
|
||||
return 1;
|
||||
}
|
||||
|
||||
__asm __volatile ("sync");
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
x = *(volatile int8_t *)addr;
|
||||
break;
|
||||
case 2:
|
||||
x = *(volatile int16_t *)addr;
|
||||
break;
|
||||
case 4:
|
||||
x = *(volatile int32_t *)addr;
|
||||
break;
|
||||
default:
|
||||
panic("badaddr: invalid size (%d)", size);
|
||||
}
|
||||
|
||||
/* Make sure we took the machine check, if we caused one. */
|
||||
__asm __volatile ("sync; isync");
|
||||
|
||||
td->td_pcb->pcb_onfault = 0;
|
||||
__asm __volatile ("sync"); /* To be sure. */
|
||||
|
||||
/* Use the value to avoid reorder. */
|
||||
if (rptr)
|
||||
*rptr = x;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, this only deals with the particular unaligned access case
|
||||
* that gcc tends to generate. Eventually it should handle all of the
|
||||
* possibilities that can happen on a 32-bit PowerPC in big-endian mode.
|
||||
*/
|
||||
|
||||
static int
|
||||
fix_unaligned(struct thread *td, struct trapframe *frame)
|
||||
{
|
||||
struct thread *fputhread;
|
||||
int indicator, reg;
|
||||
double *fpr;
|
||||
|
||||
indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr);
|
||||
|
||||
switch (indicator) {
|
||||
case EXC_ALI_LFD:
|
||||
case EXC_ALI_STFD:
|
||||
reg = EXC_ALI_RST(frame->dsisr);
|
||||
fpr = &td->td_pcb->pcb_fpu.fpr[reg];
|
||||
fputhread = PCPU_GET(fputhread);
|
||||
|
||||
/* Juggle the FPU to ensure that we've initialized
|
||||
* the FPRs, and that their current state is in
|
||||
* the PCB.
|
||||
*/
|
||||
if (fputhread != td) {
|
||||
if (fputhread)
|
||||
save_fpu(fputhread);
|
||||
enable_fpu(td);
|
||||
}
|
||||
save_fpu(td);
|
||||
|
||||
if (indicator == EXC_ALI_LFD) {
|
||||
if (copyin((void *)frame->dar, fpr,
|
||||
sizeof(double)) != 0)
|
||||
return -1;
|
||||
enable_fpu(td);
|
||||
} else {
|
||||
if (copyout(fpr, (void *)frame->dar,
|
||||
sizeof(double)) != 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
@ -1,540 +0,0 @@
|
||||
/* $FreeBSD$ */
|
||||
/* $NetBSD: trap_subr.S,v 1.20 2002/04/22 23:20:08 kleink Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
|
||||
* Copyright (C) 1995, 1996 TooLs GmbH.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by TooLs GmbH.
|
||||
* 4. The name of TooLs GmbH may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTICE: This is not a standalone file. to use it, #include it in
|
||||
* your port's locore.S, like so:
|
||||
*
|
||||
* #include <powerpc/powerpc/trap_subr.S>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Save/restore segment registers
|
||||
*/
|
||||
#define RESTORE_SRS(pmap,sr) mtsr 0,sr; \
|
||||
lwz sr,1*4(pmap); mtsr 1,sr; \
|
||||
lwz sr,2*4(pmap); mtsr 2,sr; \
|
||||
lwz sr,3*4(pmap); mtsr 3,sr; \
|
||||
lwz sr,4*4(pmap); mtsr 4,sr; \
|
||||
lwz sr,5*4(pmap); mtsr 5,sr; \
|
||||
lwz sr,6*4(pmap); mtsr 6,sr; \
|
||||
lwz sr,7*4(pmap); mtsr 7,sr; \
|
||||
lwz sr,8*4(pmap); mtsr 8,sr; \
|
||||
lwz sr,9*4(pmap); mtsr 9,sr; \
|
||||
lwz sr,10*4(pmap); mtsr 10,sr; \
|
||||
lwz sr,11*4(pmap); mtsr 11,sr; \
|
||||
lwz sr,12*4(pmap); mtsr 12,sr; \
|
||||
lwz sr,13*4(pmap); mtsr 13,sr; \
|
||||
lwz sr,14*4(pmap); mtsr 14,sr; \
|
||||
lwz sr,15*4(pmap); mtsr 15,sr; isync;
|
||||
|
||||
/*
|
||||
* User SRs are loaded through a pointer to the current pmap.
|
||||
*/
|
||||
#define RESTORE_USER_SRS(pmap,sr) \
|
||||
GET_CPUINFO(pmap); \
|
||||
lwz pmap,PC_CURPMAP(pmap); \
|
||||
lwzu sr,PM_SR(pmap); \
|
||||
RESTORE_SRS(pmap,sr)
|
||||
|
||||
/*
|
||||
* Kernel SRs are loaded directly from kernel_pmap_
|
||||
*/
|
||||
#define RESTORE_KERN_SRS(pmap,sr) \
|
||||
lis pmap,CNAME(kernel_pmap_store)@ha; \
|
||||
lwzu sr,CNAME(kernel_pmap_store)+PM_SR@l(pmap); \
|
||||
RESTORE_SRS(pmap,sr)
|
||||
|
||||
/*
|
||||
* FRAME_SETUP assumes:
|
||||
* SPRG1 SP (1)
|
||||
* savearea r28-r31,DAR,DSISR (DAR & DSISR only for DSI traps)
|
||||
* r28 LR
|
||||
* r29 CR
|
||||
* r30 scratch
|
||||
* r31 scratch
|
||||
* r1 kernel stack
|
||||
* LR trap type (from calling address, mask with 0xff00)
|
||||
* SRR0/1 as at start of trap
|
||||
*/
|
||||
#define FRAME_SETUP(savearea) \
|
||||
/* Have to enable translation to allow access of kernel stack: */ \
|
||||
GET_CPUINFO(%r31); \
|
||||
mfsrr0 %r30; \
|
||||
stw %r30,(savearea+CPUSAVE_SRR0)(%r31); /* save SRR0 */ \
|
||||
mfsrr1 %r30; \
|
||||
stw %r30,(savearea+CPUSAVE_SRR1)(%r31); /* save SRR1 */ \
|
||||
mfmsr %r30; \
|
||||
ori %r30,%r30,(PSL_DR|PSL_IR|PSL_RI)@l; /* relocation on */ \
|
||||
mtmsr %r30; /* stack can now be accessed */ \
|
||||
isync; \
|
||||
mfsprg1 %r31; /* get saved SP */ \
|
||||
stwu %r31,-FRAMELEN(%r1); /* save it in the callframe */ \
|
||||
stw %r0, FRAME_0+8(%r1); /* save r0 in the trapframe */ \
|
||||
stw %r31,FRAME_1+8(%r1); /* save SP " " */ \
|
||||
stw %r2, FRAME_2+8(%r1); /* save r2 " " */ \
|
||||
stw %r28,FRAME_LR+8(%r1); /* save LR " " */ \
|
||||
stw %r29,FRAME_CR+8(%r1); /* save CR " " */ \
|
||||
GET_CPUINFO(%r2); \
|
||||
lwz %r28,(savearea+CPUSAVE_R28)(%r2); /* get saved r28 */ \
|
||||
lwz %r29,(savearea+CPUSAVE_R29)(%r2); /* get saved r29 */ \
|
||||
lwz %r30,(savearea+CPUSAVE_R30)(%r2); /* get saved r30 */ \
|
||||
lwz %r31,(savearea+CPUSAVE_R31)(%r2); /* get saved r31 */ \
|
||||
stw %r3, FRAME_3+8(%r1); /* save r3-r31 */ \
|
||||
stw %r4, FRAME_4+8(%r1); \
|
||||
stw %r5, FRAME_5+8(%r1); \
|
||||
stw %r6, FRAME_6+8(%r1); \
|
||||
stw %r7, FRAME_7+8(%r1); \
|
||||
stw %r8, FRAME_8+8(%r1); \
|
||||
stw %r9, FRAME_9+8(%r1); \
|
||||
stw %r10, FRAME_10+8(%r1); \
|
||||
stw %r11, FRAME_11+8(%r1); \
|
||||
stw %r12, FRAME_12+8(%r1); \
|
||||
stw %r13, FRAME_13+8(%r1); \
|
||||
stw %r14, FRAME_14+8(%r1); \
|
||||
stw %r15, FRAME_15+8(%r1); \
|
||||
stw %r16, FRAME_16+8(%r1); \
|
||||
stw %r17, FRAME_17+8(%r1); \
|
||||
stw %r18, FRAME_18+8(%r1); \
|
||||
stw %r19, FRAME_19+8(%r1); \
|
||||
stw %r20, FRAME_20+8(%r1); \
|
||||
stw %r21, FRAME_21+8(%r1); \
|
||||
stw %r22, FRAME_22+8(%r1); \
|
||||
stw %r23, FRAME_23+8(%r1); \
|
||||
stw %r24, FRAME_24+8(%r1); \
|
||||
stw %r25, FRAME_25+8(%r1); \
|
||||
stw %r26, FRAME_26+8(%r1); \
|
||||
stw %r27, FRAME_27+8(%r1); \
|
||||
stw %r28, FRAME_28+8(%r1); \
|
||||
stw %r29, FRAME_29+8(%r1); \
|
||||
stw %r30, FRAME_30+8(%r1); \
|
||||
stw %r31, FRAME_31+8(%r1); \
|
||||
lwz %r28,(savearea+CPUSAVE_DAR)(%r2); /* saved DAR */ \
|
||||
lwz %r29,(savearea+CPUSAVE_DSISR)(%r2);/* saved DSISR */ \
|
||||
lwz %r30,(savearea+CPUSAVE_SRR0)(%r2); /* saved SRR0 */ \
|
||||
lwz %r31,(savearea+CPUSAVE_SRR1)(%r2); /* saved SRR1 */ \
|
||||
mfxer %r3; \
|
||||
mfctr %r4; \
|
||||
mflr %r5; \
|
||||
andi. %r5,%r5,0xff00; /* convert LR to exc # */ \
|
||||
stw %r3, FRAME_XER+8(1); /* save xer/ctr/exc */ \
|
||||
stw %r4, FRAME_CTR+8(1); \
|
||||
stw %r5, FRAME_EXC+8(1); \
|
||||
stw %r28,FRAME_DAR+8(1); \
|
||||
stw %r29,FRAME_DSISR+8(1); /* save dsisr/srr0/srr1 */ \
|
||||
stw %r30,FRAME_SRR0+8(1); \
|
||||
stw %r31,FRAME_SRR1+8(1)
|
||||
|
||||
#define FRAME_LEAVE(savearea) \
|
||||
/* Now restore regs: */ \
|
||||
lwz %r2,FRAME_SRR0+8(%r1); \
|
||||
lwz %r3,FRAME_SRR1+8(%r1); \
|
||||
lwz %r4,FRAME_CTR+8(%r1); \
|
||||
lwz %r5,FRAME_XER+8(%r1); \
|
||||
lwz %r6,FRAME_LR+8(%r1); \
|
||||
GET_CPUINFO(%r7); \
|
||||
stw %r2,(savearea+CPUSAVE_SRR0)(%r7); /* save SRR0 */ \
|
||||
stw %r3,(savearea+CPUSAVE_SRR1)(%r7); /* save SRR1 */ \
|
||||
lwz %r7,FRAME_CR+8(%r1); \
|
||||
mtctr %r4; \
|
||||
mtxer %r5; \
|
||||
mtlr %r6; \
|
||||
mtsprg1 %r7; /* save cr */ \
|
||||
lwz %r31,FRAME_31+8(%r1); /* restore r0-31 */ \
|
||||
lwz %r30,FRAME_30+8(%r1); \
|
||||
lwz %r29,FRAME_29+8(%r1); \
|
||||
lwz %r28,FRAME_28+8(%r1); \
|
||||
lwz %r27,FRAME_27+8(%r1); \
|
||||
lwz %r26,FRAME_26+8(%r1); \
|
||||
lwz %r25,FRAME_25+8(%r1); \
|
||||
lwz %r24,FRAME_24+8(%r1); \
|
||||
lwz %r23,FRAME_23+8(%r1); \
|
||||
lwz %r22,FRAME_22+8(%r1); \
|
||||
lwz %r21,FRAME_21+8(%r1); \
|
||||
lwz %r20,FRAME_20+8(%r1); \
|
||||
lwz %r19,FRAME_19+8(%r1); \
|
||||
lwz %r18,FRAME_18+8(%r1); \
|
||||
lwz %r17,FRAME_17+8(%r1); \
|
||||
lwz %r16,FRAME_16+8(%r1); \
|
||||
lwz %r15,FRAME_15+8(%r1); \
|
||||
lwz %r14,FRAME_14+8(%r1); \
|
||||
lwz %r13,FRAME_13+8(%r1); \
|
||||
lwz %r12,FRAME_12+8(%r1); \
|
||||
lwz %r11,FRAME_11+8(%r1); \
|
||||
lwz %r10,FRAME_10+8(%r1); \
|
||||
lwz %r9, FRAME_9+8(%r1); \
|
||||
lwz %r8, FRAME_8+8(%r1); \
|
||||
lwz %r7, FRAME_7+8(%r1); \
|
||||
lwz %r6, FRAME_6+8(%r1); \
|
||||
lwz %r5, FRAME_5+8(%r1); \
|
||||
lwz %r4, FRAME_4+8(%r1); \
|
||||
lwz %r3, FRAME_3+8(%r1); \
|
||||
lwz %r2, FRAME_2+8(%r1); \
|
||||
lwz %r0, FRAME_0+8(%r1); \
|
||||
lwz %r1, FRAME_1+8(%r1); \
|
||||
/* Can't touch %r1 from here on */ \
|
||||
mtsprg2 %r2; /* save r2 & r3 */ \
|
||||
mtsprg3 %r3; \
|
||||
/* Disable translation, machine check and recoverability: */ \
|
||||
mfmsr %r2; \
|
||||
andi. %r2,%r2,~(PSL_DR|PSL_IR|PSL_EE|PSL_ME|PSL_RI)@l; \
|
||||
mtmsr %r2; \
|
||||
isync; \
|
||||
/* Decide whether we return to user mode: */ \
|
||||
GET_CPUINFO(%r2); \
|
||||
lwz %r3,(savearea+CPUSAVE_SRR1)(%r2); \
|
||||
mtcr %r3; \
|
||||
bf 17,1f; /* branch if PSL_PR is false */ \
|
||||
/* Restore user SRs */ \
|
||||
RESTORE_USER_SRS(%r2,%r3); \
|
||||
1: mfsprg1 %r2; /* restore cr */ \
|
||||
mtcr %r2; \
|
||||
GET_CPUINFO(%r2); \
|
||||
lwz %r3,(savearea+CPUSAVE_SRR0)(%r2); /* restore srr0 */ \
|
||||
mtsrr0 %r3; \
|
||||
lwz %r3,(savearea+CPUSAVE_SRR1)(%r2); /* restore srr1 */ \
|
||||
mtsrr1 %r3; \
|
||||
mfsprg2 %r2; /* restore r2 & r3 */ \
|
||||
mfsprg3 %r3
|
||||
|
||||
#ifdef KDB
|
||||
/*
|
||||
* Define the kdb debugger stack
|
||||
*/
|
||||
.data
|
||||
GLOBAL(dbstk)
|
||||
.space INTSTK+8 /* kdb stack */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This code gets copied to all the trap vectors
|
||||
* (except ISI/DSI, ALI, and the interrupts)
|
||||
*/
|
||||
.text
|
||||
.globl CNAME(trapcode),CNAME(trapsize)
|
||||
CNAME(trapcode):
|
||||
mtsprg1 %r1 /* save SP */
|
||||
GET_CPUINFO(%r1)
|
||||
stw %r28,(PC_TEMPSAVE+CPUSAVE_R28)(%r1) /* free r28-r31 */
|
||||
stw %r29,(PC_TEMPSAVE+CPUSAVE_R29)(%r1)
|
||||
stw %r30,(PC_TEMPSAVE+CPUSAVE_R30)(%r1)
|
||||
stw %r31,(PC_TEMPSAVE+CPUSAVE_R31)(%r1)
|
||||
mfsprg1 %r1 /* restore SP, in case of branch */
|
||||
mflr %r28 /* save LR */
|
||||
mfcr %r29 /* save CR */
|
||||
/* Test whether we already had PR set */
|
||||
mfsrr1 %r31
|
||||
mtcr %r31
|
||||
bla s_trap /* LR & 0xff00 is exception # */
|
||||
CNAME(trapsize) = .-CNAME(trapcode)
|
||||
|
||||
/*
|
||||
* For ALI: has to save DSISR and DAR
|
||||
*/
|
||||
.globl CNAME(alitrap),CNAME(alisize)
|
||||
CNAME(alitrap):
|
||||
mtsprg1 %r1 /* save SP */
|
||||
GET_CPUINFO(%r1)
|
||||
stw %r28,(PC_TEMPSAVE+CPUSAVE_R28)(%r1) /* free r28-r31 */
|
||||
stw %r29,(PC_TEMPSAVE+CPUSAVE_R29)(%r1)
|
||||
stw %r30,(PC_TEMPSAVE+CPUSAVE_R30)(%r1)
|
||||
stw %r31,(PC_TEMPSAVE+CPUSAVE_R31)(%r1)
|
||||
mfdar %r30
|
||||
mfdsisr %r31
|
||||
stw %r30,(PC_TEMPSAVE+CPUSAVE_DAR)(%r1)
|
||||
stw %r31,(PC_TEMPSAVE+CPUSAVE_DSISR)(%r1)
|
||||
mfsprg1 %r1 /* restore SP, in case of branch */
|
||||
mflr %r28 /* save LR */
|
||||
mfcr %r29 /* save CR */
|
||||
/* Test whether we already had PR set */
|
||||
mfsrr1 %r31
|
||||
mtcr %r31
|
||||
bla s_trap /* LR & 0xff00 is exception # */
|
||||
CNAME(alisize) = .-CNAME(alitrap)
|
||||
|
||||
/*
|
||||
* Similar to the above for DSI
|
||||
* Has to handle BAT spills
|
||||
* and standard pagetable spills
|
||||
*/
|
||||
.globl CNAME(dsitrap),CNAME(dsisize)
|
||||
CNAME(dsitrap):
|
||||
mtsprg1 %r1 /* save SP */
|
||||
GET_CPUINFO(%r1)
|
||||
stw %r28,(PC_DISISAVE+CPUSAVE_R28)(%r1) /* free r28-r31 */
|
||||
stw %r29,(PC_DISISAVE+CPUSAVE_R29)(%r1)
|
||||
stw %r30,(PC_DISISAVE+CPUSAVE_R30)(%r1)
|
||||
stw %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1)
|
||||
mfsprg1 %r1 /* restore SP */
|
||||
mfcr %r29 /* save CR */
|
||||
mfxer %r30 /* save XER */
|
||||
mtsprg2 %r30 /* in SPRG2 */
|
||||
mfsrr1 %r31 /* test kernel mode */
|
||||
mtcr %r31
|
||||
bt 17,1f /* branch if PSL_PR is set */
|
||||
mfdar %r31 /* get fault address */
|
||||
rlwinm %r31,%r31,7,25,28 /* get segment * 8 */
|
||||
|
||||
/* get batu */
|
||||
addis %r31,%r31,CNAME(battable)@ha
|
||||
lwz %r30,CNAME(battable)@l(31)
|
||||
mtcr %r30
|
||||
bf 30,1f /* branch if supervisor valid is
|
||||
false */
|
||||
/* get batl */
|
||||
lwz %r31,CNAME(battable)+4@l(31)
|
||||
/* We randomly use the highest two bat registers here */
|
||||
mftb %r28
|
||||
andi. %r28,%r28,1
|
||||
bne 2f
|
||||
mtdbatu 2,%r30
|
||||
mtdbatl 2,%r31
|
||||
b 3f
|
||||
2:
|
||||
mtdbatu 3,%r30
|
||||
mtdbatl 3,%r31
|
||||
3:
|
||||
mfsprg2 %r30 /* restore XER */
|
||||
mtxer %r30
|
||||
mtcr %r29 /* restore CR */
|
||||
mtsprg1 %r1
|
||||
GET_CPUINFO(%r1)
|
||||
lwz %r28,(PC_DISISAVE+CPUSAVE_R28)(%r1) /* restore r28-r31 */
|
||||
lwz %r29,(PC_DISISAVE+CPUSAVE_R29)(%r1)
|
||||
lwz %r30,(PC_DISISAVE+CPUSAVE_R30)(%r1)
|
||||
lwz %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1)
|
||||
mfsprg1 %r1
|
||||
rfi /* return to trapped code */
|
||||
1:
|
||||
mflr %r28 /* save LR (SP already saved) */
|
||||
bla disitrap
|
||||
CNAME(dsisize) = .-CNAME(dsitrap)
|
||||
|
||||
/*
|
||||
* Preamble code for DSI/ISI traps
|
||||
*/
|
||||
disitrap:
|
||||
GET_CPUINFO(%r1)
|
||||
lwz %r30,(PC_DISISAVE+CPUSAVE_R28)(%r1)
|
||||
stw %r30,(PC_TEMPSAVE+CPUSAVE_R28)(%r1)
|
||||
lwz %r31,(PC_DISISAVE+CPUSAVE_R29)(%r1)
|
||||
stw %r31,(PC_TEMPSAVE+CPUSAVE_R29)(%r1)
|
||||
lwz %r30,(PC_DISISAVE+CPUSAVE_R30)(%r1)
|
||||
stw %r30,(PC_TEMPSAVE+CPUSAVE_R30)(%r1)
|
||||
lwz %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1)
|
||||
stw %r31,(PC_TEMPSAVE+CPUSAVE_R31)(%r1)
|
||||
mfdar %r30
|
||||
mfdsisr %r31
|
||||
stw %r30,(PC_TEMPSAVE+CPUSAVE_DAR)(%r1)
|
||||
stw %r31,(PC_TEMPSAVE+CPUSAVE_DSISR)(%r1)
|
||||
|
||||
#ifdef KDB
|
||||
/* Try and detect a kernel stack overflow */
|
||||
mfsrr1 %r31
|
||||
mtcr %r31
|
||||
bt 17,realtrap /* branch is user mode */
|
||||
mfsprg1 %r31 /* get old SP */
|
||||
sub. %r30,%r31,%r30 /* SP - DAR */
|
||||
bge 1f
|
||||
neg %r30,%r30 /* modulo value */
|
||||
1: cmplwi %cr0,%r30,4096 /* is DAR within a page of SP? */
|
||||
bge %cr0,realtrap /* no, too far away. */
|
||||
|
||||
/* Now convert this DSI into a DDB trap. */
|
||||
GET_CPUINFO(%r1)
|
||||
lwz %r30,(PC_TEMPSAVE+CPUSAVE_DAR)(%r1) /* get DAR */
|
||||
stw %r30,(PC_DBSAVE +CPUSAVE_DAR)(%r1) /* save DAR */
|
||||
lwz %r30,(PC_TEMPSAVE+CPUSAVE_DSISR)(%r1) /* get DSISR */
|
||||
lwz %r30,(PC_DBSAVE +CPUSAVE_DSISR)(%r1) /* save DSISR */
|
||||
lwz %r30,(PC_DISISAVE+CPUSAVE_R28)(%r1) /* get r28 */
|
||||
stw %r30,(PC_DBSAVE +CPUSAVE_R28)(%r1) /* save r28 */
|
||||
lwz %r31,(PC_DISISAVE+CPUSAVE_R29)(%r1) /* get r29 */
|
||||
stw %r31,(PC_DBSAVE +CPUSAVE_R29)(%r1) /* save r29 */
|
||||
lwz %r30,(PC_DISISAVE+CPUSAVE_R30)(%r1) /* get r30 */
|
||||
stw %r30,(PC_DBSAVE +CPUSAVE_R30)(%r1) /* save r30 */
|
||||
lwz %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1) /* get r31 */
|
||||
stw %r31,(PC_DBSAVE +CPUSAVE_R31)(%r1) /* save r31 */
|
||||
lis %r1,dbstk+INTSTK@ha /* get new SP */
|
||||
addi %r1,%r1,dbstk+INTSTK@l
|
||||
b dbtrap
|
||||
#endif
|
||||
|
||||
/* XXX need stack probe here */
|
||||
realtrap:
|
||||
/* Test whether we already had PR set */
|
||||
mfsrr1 %r1
|
||||
mtcr %r1
|
||||
mfsprg1 %r1 /* restore SP (might have been
|
||||
overwritten) */
|
||||
s_trap:
|
||||
bf 17,k_trap /* branch if PSL_PR is false */
|
||||
GET_CPUINFO(%r1)
|
||||
u_trap:
|
||||
lwz %r1,PC_CURPCB(%r1)
|
||||
RESTORE_KERN_SRS(%r30,%r31) /* enable kernel mapping */
|
||||
|
||||
/*
|
||||
* Now the common trap catching code.
|
||||
*/
|
||||
k_trap:
|
||||
FRAME_SETUP(PC_TEMPSAVE)
|
||||
/* Call C interrupt dispatcher: */
|
||||
trapagain:
|
||||
addi %r3,%r1,8
|
||||
bl CNAME(powerpc_interrupt)
|
||||
.globl CNAME(trapexit) /* backtrace code sentinel */
|
||||
CNAME(trapexit):
|
||||
|
||||
/* Disable interrupts: */
|
||||
mfmsr %r3
|
||||
andi. %r3,%r3,~PSL_EE@l
|
||||
mtmsr %r3
|
||||
/* Test AST pending: */
|
||||
lwz %r5,FRAME_SRR1+8(%r1)
|
||||
mtcr %r5
|
||||
bf 17,1f /* branch if PSL_PR is false */
|
||||
|
||||
GET_CPUINFO(%r3) /* get per-CPU pointer */
|
||||
lwz %r4, PC_CURTHREAD(%r3) /* deref to get curthread */
|
||||
lwz %r4, TD_FLAGS(%r4) /* get thread flags value */
|
||||
lis %r5, (TDF_ASTPENDING|TDF_NEEDRESCHED)@h
|
||||
ori %r5,%r5, (TDF_ASTPENDING|TDF_NEEDRESCHED)@l
|
||||
and. %r4,%r4,%r5
|
||||
beq 1f
|
||||
mfmsr %r3 /* re-enable interrupts */
|
||||
ori %r3,%r3,PSL_EE@l
|
||||
mtmsr %r3
|
||||
isync
|
||||
addi %r3,%r1,8
|
||||
bl CNAME(ast)
|
||||
.globl CNAME(asttrapexit) /* backtrace code sentinel #2 */
|
||||
CNAME(asttrapexit):
|
||||
b trapexit /* test ast ret value ? */
|
||||
1:
|
||||
FRAME_LEAVE(PC_TEMPSAVE)
|
||||
rfi
|
||||
|
||||
/*
|
||||
* Temporary: vector-unavailable traps are directed to vector-assist traps
|
||||
*/
|
||||
.globl CNAME(vectrap),CNAME(vectrapsize)
|
||||
CNAME(vectrap):
|
||||
ba EXC_VECAST
|
||||
CNAME(vectrapsize) = .-CNAME(vectrap)
|
||||
|
||||
#if defined(KDB)
|
||||
/*
|
||||
* Deliberate entry to dbtrap
|
||||
*/
|
||||
.globl CNAME(ppc_db_trap)
|
||||
CNAME(ppc_db_trap):
|
||||
mtsprg1 %r1
|
||||
mfmsr %r3
|
||||
mtsrr1 %r3
|
||||
andi. %r3,%r3,~(PSL_EE|PSL_ME)@l
|
||||
mtmsr %r3 /* disable interrupts */
|
||||
isync
|
||||
GET_CPUINFO(%r3)
|
||||
stw %r28,(PC_DBSAVE+CPUSAVE_R28)(%r3)
|
||||
stw %r29,(PC_DBSAVE+CPUSAVE_R29)(%r3)
|
||||
stw %r30,(PC_DBSAVE+CPUSAVE_R30)(%r3)
|
||||
stw %r31,(PC_DBSAVE+CPUSAVE_R31)(%r3)
|
||||
mflr %r28
|
||||
li %r29,EXC_BPT
|
||||
mtlr %r29
|
||||
mfcr %r29
|
||||
mtsrr0 %r28
|
||||
|
||||
/*
|
||||
* Now the kdb trap catching code.
|
||||
*/
|
||||
dbtrap:
|
||||
FRAME_SETUP(PC_DBSAVE)
|
||||
/* Call C trap code: */
|
||||
addi %r3,%r1,8
|
||||
bl CNAME(db_trap_glue)
|
||||
or. %r3,%r3,%r3
|
||||
bne dbleave
|
||||
/* This wasn't for KDB, so switch to real trap: */
|
||||
lwz %r3,FRAME_EXC+8(%r1) /* save exception */
|
||||
GET_CPUINFO(%r4)
|
||||
stw %r3,(PC_DBSAVE+CPUSAVE_R31)(%r4)
|
||||
FRAME_LEAVE(PC_DBSAVE)
|
||||
mtsprg1 %r1 /* prepare for entrance to realtrap */
|
||||
GET_CPUINFO(%r1)
|
||||
stw %r28,(PC_TEMPSAVE+CPUSAVE_R28)(%r1)
|
||||
stw %r29,(PC_TEMPSAVE+CPUSAVE_R29)(%r1)
|
||||
stw %r30,(PC_TEMPSAVE+CPUSAVE_R30)(%r1)
|
||||
stw %r31,(PC_TEMPSAVE+CPUSAVE_R31)(%r1)
|
||||
mflr %r28
|
||||
mfcr %r29
|
||||
lwz %r31,(PC_DBSAVE+CPUSAVE_R31)(%r1)
|
||||
mtlr %r31
|
||||
mfsprg1 %r1
|
||||
b realtrap
|
||||
dbleave:
|
||||
FRAME_LEAVE(PC_DBSAVE)
|
||||
rfi
|
||||
|
||||
/*
|
||||
* In case of KDB we want a separate trap catcher for it
|
||||
*/
|
||||
.globl CNAME(dblow),CNAME(dbsize)
|
||||
CNAME(dblow):
|
||||
mtsprg1 %r1 /* save SP */
|
||||
mtsprg2 %r29 /* save r29 */
|
||||
mfcr %r29 /* save CR in r29 */
|
||||
mfsrr1 %r1
|
||||
mtcr %r1
|
||||
GET_CPUINFO(%r1)
|
||||
bf 17,1f /* branch if privileged */
|
||||
stw %r28,(PC_TEMPSAVE+CPUSAVE_R28)(%r1) /* free r28 */
|
||||
mfsprg2 %r28 /* r29 holds cr ... */
|
||||
stw %r28,(PC_TEMPSAVE+CPUSAVE_R29)(%r1) /* free r29 */
|
||||
stw %r30,(PC_TEMPSAVE+CPUSAVE_R30)(%r1) /* free r30 */
|
||||
stw %r31,(PC_TEMPSAVE+CPUSAVE_R31)(%r1) /* free r31 */
|
||||
mflr %r28 /* save LR */
|
||||
bla u_trap
|
||||
1:
|
||||
stw %r28,(PC_DBSAVE+CPUSAVE_R28)(%r1) /* free r28 */
|
||||
mfsprg2 %r28 /* r29 holds cr... */
|
||||
stw %r28,(PC_DBSAVE+CPUSAVE_R29)(%r1) /* free r29 */
|
||||
stw %r30,(PC_DBSAVE+CPUSAVE_R30)(%r1) /* free r30 */
|
||||
stw %r31,(PC_DBSAVE+CPUSAVE_R31)(%r1) /* free r31 */
|
||||
mflr %r28 /* save LR */
|
||||
lis %r1,dbstk+INTSTK@ha /* get new SP */
|
||||
addi %r1,%r1,dbstk+INTSTK@l
|
||||
bla dbtrap
|
||||
CNAME(dbsize) = .-CNAME(dblow)
|
||||
#endif /* KDB */
|
@ -1,124 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2004 Alan L. Cox <alc@cs.rice.edu>
|
||||
* Copyright (c) 1982, 1986, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)kern_subr.c 8.3 (Berkeley) 1/21/94
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_page.h>
|
||||
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
/*
|
||||
* Implement uiomove(9) from physical memory using the direct map to
|
||||
* avoid the creation and destruction of ephemeral mappings.
|
||||
*/
|
||||
int
|
||||
uiomove_fromphys(vm_page_t ma[], vm_offset_t offset, int n, struct uio *uio)
|
||||
{
|
||||
struct thread *td = curthread;
|
||||
struct iovec *iov;
|
||||
void *cp;
|
||||
vm_offset_t page_offset;
|
||||
size_t cnt;
|
||||
int error = 0;
|
||||
int save = 0;
|
||||
|
||||
KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
|
||||
("uiomove_fromphys: mode"));
|
||||
KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread,
|
||||
("uiomove_fromphys proc"));
|
||||
save = td->td_pflags & TDP_DEADLKTREAT;
|
||||
td->td_pflags |= TDP_DEADLKTREAT;
|
||||
while (n > 0 && uio->uio_resid) {
|
||||
iov = uio->uio_iov;
|
||||
cnt = iov->iov_len;
|
||||
if (cnt == 0) {
|
||||
uio->uio_iov++;
|
||||
uio->uio_iovcnt--;
|
||||
continue;
|
||||
}
|
||||
if (cnt > n)
|
||||
cnt = n;
|
||||
page_offset = offset & PAGE_MASK;
|
||||
cnt = min(cnt, PAGE_SIZE - page_offset);
|
||||
cp = (char *)VM_PAGE_TO_PHYS(ma[offset >> PAGE_SHIFT]) +
|
||||
page_offset;
|
||||
switch (uio->uio_segflg) {
|
||||
case UIO_USERSPACE:
|
||||
if (ticks - PCPU_GET(switchticks) >= hogticks)
|
||||
uio_yield();
|
||||
if (uio->uio_rw == UIO_READ)
|
||||
error = copyout(cp, iov->iov_base, cnt);
|
||||
else
|
||||
error = copyin(iov->iov_base, cp, cnt);
|
||||
if (error)
|
||||
goto out;
|
||||
if (uio->uio_rw == UIO_WRITE &&
|
||||
pmap_page_executable(ma[offset >> PAGE_SHIFT]))
|
||||
__syncicache(cp, cnt);
|
||||
break;
|
||||
case UIO_SYSSPACE:
|
||||
if (uio->uio_rw == UIO_READ)
|
||||
bcopy(cp, iov->iov_base, cnt);
|
||||
else
|
||||
bcopy(iov->iov_base, cp, cnt);
|
||||
break;
|
||||
case UIO_NOCOPY:
|
||||
break;
|
||||
}
|
||||
iov->iov_base = (char *)iov->iov_base + cnt;
|
||||
iov->iov_len -= cnt;
|
||||
uio->uio_resid -= cnt;
|
||||
uio->uio_offset += cnt;
|
||||
offset += cnt;
|
||||
n -= cnt;
|
||||
}
|
||||
out:
|
||||
if (save == 0)
|
||||
td->td_pflags &= ~TDP_DEADLKTREAT;
|
||||
return (error);
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2003 The FreeBSD Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_pageout.h>
|
||||
#include <vm/uma.h>
|
||||
#include <vm/uma_int.h>
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
static int hw_uma_mdpages;
|
||||
SYSCTL_INT(_hw, OID_AUTO, uma_mdpages, CTLFLAG_RD, &hw_uma_mdpages, 0,
|
||||
"UMA MD pages in use");
|
||||
|
||||
void *
|
||||
uma_small_alloc(uma_zone_t zone, int bytes, u_int8_t *flags, int wait)
|
||||
{
|
||||
static vm_pindex_t color;
|
||||
void *va;
|
||||
vm_page_t m;
|
||||
int pflags;
|
||||
|
||||
*flags = UMA_SLAB_PRIV;
|
||||
if ((wait & (M_NOWAIT|M_USE_RESERVE)) == M_NOWAIT)
|
||||
pflags = VM_ALLOC_INTERRUPT | VM_ALLOC_WIRED;
|
||||
else
|
||||
pflags = VM_ALLOC_SYSTEM | VM_ALLOC_WIRED;
|
||||
if (wait & M_ZERO)
|
||||
pflags |= VM_ALLOC_ZERO;
|
||||
|
||||
for (;;) {
|
||||
m = vm_page_alloc(NULL, color++, pflags | VM_ALLOC_NOOBJ);
|
||||
if (m == NULL) {
|
||||
if (wait & M_NOWAIT)
|
||||
return (NULL);
|
||||
VM_WAIT;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
va = (void *) VM_PAGE_TO_PHYS(m);
|
||||
if ((wait & M_ZERO) && (m->flags & PG_ZERO) == 0)
|
||||
bzero(va, PAGE_SIZE);
|
||||
atomic_add_int(&hw_uma_mdpages, 1);
|
||||
|
||||
return (va);
|
||||
}
|
||||
|
||||
void
|
||||
uma_small_free(void *mem, int size, u_int8_t flags)
|
||||
{
|
||||
vm_page_t m;
|
||||
|
||||
m = PHYS_TO_VM_PAGE((u_int32_t)mem);
|
||||
m->wire_count--;
|
||||
vm_page_free(m);
|
||||
atomic_subtract_int(&cnt.v_wire_count, 1);
|
||||
atomic_subtract_int(&hw_uma_mdpages, 1);
|
||||
}
|
@ -1,369 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986 The Regents of the University of California.
|
||||
* Copyright (c) 1989, 1990 William Jolitz
|
||||
* Copyright (c) 1994 John Dyson
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* the Systems Programming Group of the University of Utah Computer
|
||||
* Science Department, and William Jolitz.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91
|
||||
* Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
|
||||
* $FreeBSD$
|
||||
*/
|
||||
/*-
|
||||
* Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Chris G. Demetriou
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation is hereby granted, provided that both the copyright
|
||||
* notice and this permission notice appear in all copies of the
|
||||
* software, derivative works or modified versions, and any portions
|
||||
* thereof, and that both notices appear in supporting documentation.
|
||||
*
|
||||
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
|
||||
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
|
||||
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
*
|
||||
* Carnegie Mellon requests users of this software to return to
|
||||
*
|
||||
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
|
||||
* School of Computer Science
|
||||
* Carnegie Mellon University
|
||||
* Pittsburgh PA 15213-3890
|
||||
*
|
||||
* any improvements or extensions that they make and grant Carnegie the
|
||||
* rights to redistribute these changes.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/bio.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/vmmeter.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/sf_buf.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/unistd.h>
|
||||
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/fpu.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/powerpc.h>
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/vm_kern.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_map.h>
|
||||
#include <vm/vm_extern.h>
|
||||
|
||||
/*
|
||||
* Finish a fork operation, with process p2 nearly set up.
|
||||
* Copy and update the pcb, set up the stack so that the child
|
||||
* ready to run and return to user mode.
|
||||
*/
|
||||
void
|
||||
cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
|
||||
{
|
||||
struct proc *p1;
|
||||
struct trapframe *tf;
|
||||
struct callframe *cf;
|
||||
struct pcb *pcb;
|
||||
|
||||
KASSERT(td1 == curthread || td1 == &thread0,
|
||||
("cpu_fork: p1 not curproc and not proc0"));
|
||||
CTR3(KTR_PROC, "cpu_fork: called td1=%08x p2=%08x flags=%x", (u_int)td1, (u_int)p2, flags);
|
||||
|
||||
if ((flags & RFPROC) == 0)
|
||||
return;
|
||||
|
||||
p1 = td1->td_proc;
|
||||
|
||||
pcb = (struct pcb *)((td2->td_kstack +
|
||||
td2->td_kstack_pages * PAGE_SIZE - sizeof(struct pcb)) & ~0x2fU);
|
||||
td2->td_pcb = pcb;
|
||||
|
||||
/* Copy the pcb */
|
||||
bcopy(td1->td_pcb, pcb, sizeof(struct pcb));
|
||||
|
||||
/*
|
||||
* Create a fresh stack for the new process.
|
||||
* Copy the trap frame for the return to user mode as if from a
|
||||
* syscall. This copies most of the user mode register values.
|
||||
*/
|
||||
tf = (struct trapframe *)pcb - 1;
|
||||
bcopy(td1->td_frame, tf, sizeof(*tf));
|
||||
|
||||
/* Set up trap frame. */
|
||||
tf->fixreg[FIRSTARG] = 0;
|
||||
tf->fixreg[FIRSTARG + 1] = 0;
|
||||
tf->cr &= ~0x10000000;
|
||||
|
||||
td2->td_frame = tf;
|
||||
|
||||
cf = (struct callframe *)tf - 1;
|
||||
memset(cf, 0, sizeof(struct callframe));
|
||||
cf->cf_func = (register_t)fork_return;
|
||||
cf->cf_arg0 = (register_t)td2;
|
||||
cf->cf_arg1 = (register_t)tf;
|
||||
|
||||
pcb->pcb_sp = (register_t)cf;
|
||||
pcb->pcb_lr = (register_t)fork_trampoline;
|
||||
pcb->pcb_usr = kernel_pmap->pm_sr[USER_SR];
|
||||
|
||||
/* Setup to release spin count in fork_exit(). */
|
||||
td2->td_md.md_spinlock_count = 1;
|
||||
td2->td_md.md_saved_msr = PSL_KERNSET;
|
||||
|
||||
/*
|
||||
* Now cpu_switch() can schedule the new process.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Intercept the return address from a freshly forked process that has NOT
|
||||
* been scheduled yet.
|
||||
*
|
||||
* This is needed to make kernel threads stay in kernel mode.
|
||||
*/
|
||||
void
|
||||
cpu_set_fork_handler(td, func, arg)
|
||||
struct thread *td;
|
||||
void (*func)(void *);
|
||||
void *arg;
|
||||
{
|
||||
struct callframe *cf;
|
||||
|
||||
CTR3(KTR_PROC, "cpu_set_fork_handler: called with td=%08x func=%08x arg=%08x",
|
||||
(u_int)td, (u_int)func, (u_int)arg);
|
||||
|
||||
cf = (struct callframe *)td->td_pcb->pcb_sp;
|
||||
|
||||
cf->cf_func = (register_t)func;
|
||||
cf->cf_arg0 = (register_t)arg;
|
||||
}
|
||||
|
||||
void
|
||||
cpu_exit(td)
|
||||
register struct thread *td;
|
||||
{
|
||||
}
|
||||
|
||||
/* Temporary helper */
|
||||
void
|
||||
cpu_throw(struct thread *old, struct thread *new)
|
||||
{
|
||||
|
||||
cpu_switch(old, new, old->td_lock);
|
||||
panic("cpu_throw() didn't");
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset back to firmware.
|
||||
*/
|
||||
void
|
||||
cpu_reset()
|
||||
{
|
||||
OF_reboot();
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate an sf_buf for the given vm_page. On this machine, however, there
|
||||
* is no sf_buf object. Instead, an opaque pointer to the given vm_page is
|
||||
* returned.
|
||||
*/
|
||||
struct sf_buf *
|
||||
sf_buf_alloc(struct vm_page *m, int pri)
|
||||
{
|
||||
|
||||
return ((struct sf_buf *)m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the sf_buf. In fact, do nothing because there are no resources
|
||||
* associated with the sf_buf.
|
||||
*/
|
||||
void
|
||||
sf_buf_free(struct sf_buf *sf)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Software interrupt handler for queued VM system processing.
|
||||
*/
|
||||
void
|
||||
swi_vm(void *dummy)
|
||||
{
|
||||
#if 0 /* XXX: Don't have busdma stuff yet */
|
||||
if (busdma_swi_pending != 0)
|
||||
busdma_swi();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell whether this address is in some physical memory region.
|
||||
* Currently used by the kernel coredump code in order to avoid
|
||||
* dumping the ``ISA memory hole'' which could cause indefinite hangs,
|
||||
* or other unpredictable behaviour.
|
||||
*/
|
||||
|
||||
|
||||
int
|
||||
is_physical_memory(addr)
|
||||
vm_offset_t addr;
|
||||
{
|
||||
/*
|
||||
* stuff other tests for known memory-mapped devices (PCI?)
|
||||
* here
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* KSE functions
|
||||
*/
|
||||
void
|
||||
cpu_thread_exit(struct thread *td)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
cpu_thread_clean(struct thread *td)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
cpu_thread_alloc(struct thread *td)
|
||||
{
|
||||
struct pcb *pcb;
|
||||
|
||||
pcb = (struct pcb *)((td->td_kstack + td->td_kstack_pages * PAGE_SIZE -
|
||||
sizeof(struct pcb)) & ~0x2fU);
|
||||
td->td_pcb = pcb;
|
||||
td->td_frame = (struct trapframe *)pcb - 1;
|
||||
}
|
||||
|
||||
void
|
||||
cpu_thread_free(struct thread *td)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
cpu_thread_swapin(struct thread *td)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
cpu_thread_swapout(struct thread *td)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
cpu_set_upcall(struct thread *td, struct thread *td0)
|
||||
{
|
||||
struct pcb *pcb2;
|
||||
struct trapframe *tf;
|
||||
struct callframe *cf;
|
||||
|
||||
pcb2 = td->td_pcb;
|
||||
|
||||
/* Copy the upcall pcb */
|
||||
bcopy(td0->td_pcb, pcb2, sizeof(*pcb2));
|
||||
|
||||
/* Create a stack for the new thread */
|
||||
tf = td->td_frame;
|
||||
bcopy(td0->td_frame, tf, sizeof(struct trapframe));
|
||||
tf->fixreg[FIRSTARG] = 0;
|
||||
tf->fixreg[FIRSTARG + 1] = 0;
|
||||
tf->cr &= ~0x10000000;
|
||||
|
||||
/* Set registers for trampoline to user mode. */
|
||||
cf = (struct callframe *)tf - 1;
|
||||
memset(cf, 0, sizeof(struct callframe));
|
||||
cf->cf_func = (register_t)fork_return;
|
||||
cf->cf_arg0 = (register_t)td;
|
||||
cf->cf_arg1 = (register_t)tf;
|
||||
|
||||
pcb2->pcb_sp = (register_t)cf;
|
||||
pcb2->pcb_lr = (register_t)fork_trampoline;
|
||||
pcb2->pcb_usr = kernel_pmap->pm_sr[USER_SR];
|
||||
|
||||
/* Setup to release spin count in fork_exit(). */
|
||||
td->td_md.md_spinlock_count = 1;
|
||||
td->td_md.md_saved_msr = PSL_KERNSET;
|
||||
}
|
||||
|
||||
void
|
||||
cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
|
||||
stack_t *stack)
|
||||
{
|
||||
struct trapframe *tf;
|
||||
uint32_t sp;
|
||||
|
||||
tf = td->td_frame;
|
||||
/* align stack and alloc space for frame ptr and saved LR */
|
||||
sp = ((uint32_t)stack->ss_sp + stack->ss_size
|
||||
- 2*sizeof(u_int32_t)) & ~0x1f;
|
||||
bzero(tf, sizeof(struct trapframe));
|
||||
|
||||
tf->fixreg[1] = (register_t)sp;
|
||||
tf->fixreg[3] = (register_t)arg;
|
||||
tf->srr0 = (register_t)entry;
|
||||
tf->srr1 = PSL_MBO | PSL_USERSET | PSL_FE_DFLT;
|
||||
td->td_pcb->pcb_flags = 0;
|
||||
|
||||
td->td_retval[0] = (register_t)entry;
|
||||
td->td_retval[1] = 0;
|
||||
}
|
||||
|
||||
int
|
||||
cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
{
|
||||
|
||||
td->td_frame->fixreg[2] = (register_t)tls_base + 0x7008;
|
||||
return (0);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user