This file was repocopied to src/sys/powerpc/aim, where it will

live on -- an afterlife.
This commit is contained in:
marcel 2007-12-14 23:03:48 +00:00
parent c8b672d408
commit e1d637468a
15 changed files with 0 additions and 7483 deletions

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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, &params);
} 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;
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}