File: [local] / sys / arch / hppa64 / hppa64 / vm_machdep.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:05:59 2008 UTC (16 years, 3 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: vm_machdep.c,v 1.7 2007/06/20 17:29:35 miod Exp $ */
/*
* Copyright (c) 2005 Michael Shalayeff
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/user.h>
#include <sys/ptrace.h>
#include <sys/exec.h>
#include <sys/core.h>
#include <machine/psl.h>
#include <machine/pmap.h>
#include <machine/pcb.h>
#include <uvm/uvm.h>
/*
* Dump the machine specific header information at the start of a core dump.
*/
int
cpu_coredump(p, vp, cred, core)
struct proc *p;
struct vnode *vp;
struct ucred *cred;
struct core *core;
{
struct md_coredump md_core;
struct coreseg cseg;
off_t off;
int error;
CORE_SETMAGIC(*core, COREMAGIC, MID_HPPA20, 0);
core->c_hdrsize = ALIGN(sizeof(*core));
core->c_seghdrsize = ALIGN(sizeof(cseg));
core->c_cpusize = sizeof(md_core);
process_read_regs(p, &md_core.md_reg);
process_read_fpregs(p, &md_core.md_fpreg);
CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_HPPA20, CORE_CPU);
cseg.c_addr = 0;
cseg.c_size = core->c_cpusize;
#define write(vp, addr, n) \
vn_rdwr(UIO_WRITE, (vp), (caddr_t)(addr), (n), off, \
UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, NULL, p)
off = core->c_hdrsize;
if ((error = write(vp, &cseg, core->c_seghdrsize)))
return error;
off += core->c_seghdrsize;
if ((error = write(vp, &md_core, sizeof md_core)))
return error;
#undef write
core->c_nseg++;
return error;
}
void
cpu_fork(p1, p2, stack, stacksize, func, arg)
struct proc *p1, *p2;
void *stack;
size_t stacksize;
void (*func)(void *);
void *arg;
{
extern paddr_t fpu_curpcb; /* from locore.S */
extern register_t switch_tramp_p;
extern u_int fpu_enable;
struct pcb *pcbp;
struct trapframe *tf;
register_t sp, osp;
paddr_t pa;
#ifdef DIAGNOSTIC
if (round_page(sizeof(struct user) + sizeof(*tf)) > PAGE_SIZE)
panic("USPACE too small for user");
#endif
if (p1->p_md.md_regs->tf_cr30 == fpu_curpcb) {
mtctl(fpu_enable, CR_CCR);
fpu_save(fpu_curpcb);
mtctl(0, CR_CCR);
}
pcbp = &p2->p_addr->u_pcb;
bcopy(&p1->p_addr->u_pcb, pcbp, sizeof(*pcbp));
/* space is cached for the copy{in,out}'s pleasure */
pcbp->pcb_space = p2->p_vmspace->vm_map.pmap->pm_space;
pcbp->pcb_uva = (vaddr_t)p2->p_addr;
/* reset any of the pending FPU exceptions from parent */
pcbp->pcb_fpregs[0] = HPPA_FPU_FORK(pcbp->pcb_fpregs[0]);
pcbp->pcb_fpregs[1] = 0;
pcbp->pcb_fpregs[2] = 0;
pcbp->pcb_fpregs[3] = 0;
fdcache(HPPA_SID_KERNEL, (vaddr_t)&pcbp->pcb_fpregs[0], 8 * 4);
sp = (register_t)p2->p_addr + PAGE_SIZE;
p2->p_md.md_regs = tf = (struct trapframe *)sp;
sp += sizeof(struct trapframe);
bcopy(p1->p_md.md_regs, tf, sizeof(*tf));
/*
* Stash the physical for the pcb of U for later perusal
*/
if (!pmap_extract(pmap_kernel(), (vaddr_t)p2->p_addr, &pa))
panic("pmap_extract(%p) failed", p2->p_addr);
tf->tf_cr30 = pa;
tf->tf_sr0 = tf->tf_sr1 = tf->tf_sr2 = tf->tf_sr3 =
tf->tf_sr4 = tf->tf_sr5 = tf->tf_sr6 =
tf->tf_iisq[0] = tf->tf_iisq[1] =
p2->p_vmspace->vm_map.pmap->pm_space;
tf->tf_pidr1 = tf->tf_pidr2 = pmap_sid2pid(tf->tf_sr0);
/*
* theoretically these could be inherited from the father,
* but just in case.
*/
tf->tf_sr7 = HPPA_SID_KERNEL;
tf->tf_eiem = mfctl(CR_EIEM);
tf->tf_ipsw = PSL_C | PSL_Q | PSL_P | PSL_D | PSL_I /* | PSL_L */;
/*
* If specified, give the child a different stack.
*/
if (stack != NULL)
tf->tf_sp = (register_t)stack;
/*
* Build stack frames for the cpu_switch & co.
*/
osp = sp + HPPA_FRAME_SIZE;
*(register_t*)(osp - HPPA_FRAME_SIZE) = 0;
*(register_t*)(osp + HPPA_FRAME_RP) = switch_tramp_p;
*(register_t*)(osp) = (osp - HPPA_FRAME_SIZE);
sp = osp + HPPA_FRAME_SIZE + 20*8; /* frame + calee-save registers */
*(register_t*)(sp - HPPA_FRAME_SIZE + 0) = (register_t)arg;
*(register_t*)(sp - HPPA_FRAME_SIZE + 8) = KERNMODE(func);
*(register_t*)(sp - HPPA_FRAME_SIZE + 16) = 0; /* cpl */
pcbp->pcb_ksp = sp;
fdcache(HPPA_SID_KERNEL, (vaddr_t)p2->p_addr, sp - (vaddr_t)p2->p_addr);
}
void
cpu_exit(p)
struct proc *p;
{
extern paddr_t fpu_curpcb; /* from locore.S */
struct trapframe *tf = p->p_md.md_regs;
if (fpu_curpcb == tf->tf_cr30) {
fpu_exit();
fpu_curpcb = 0;
}
exit2(p);
cpu_switch(p);
}
void
cpu_wait(p)
struct proc *p;
{
}
/*
* Map an IO request into kernel virtual address space.
*/
void
vmapbuf(bp, len)
struct buf *bp;
vsize_t len;
{
struct pmap *pm = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map);
vaddr_t kva, uva;
vsize_t size, off;
#ifdef DIAGNOSTIC
if ((bp->b_flags & B_PHYS) == 0)
panic("vmapbuf");
#endif
bp->b_saveaddr = bp->b_data;
uva = trunc_page((vaddr_t)bp->b_data);
off = (vaddr_t)bp->b_data - uva;
size = round_page(off + len);
/*
* We do it on our own here to be able to specify an offset to uvm_map
* so that we can get all benefits of PMAP_PREFER.
* - art@
*/
kva = uvm_km_valloc_prefer_wait(phys_map, size, uva);
fdcache(pm->pm_space, uva, size);
bp->b_data = (caddr_t)(kva + off);
while (size > 0) {
paddr_t pa;
if (pmap_extract(pm, uva, &pa) == FALSE)
panic("vmapbuf: null page frame");
else
pmap_kenter_pa(kva, pa, UVM_PROT_RW);
uva += PAGE_SIZE;
kva += PAGE_SIZE;
size -= PAGE_SIZE;
}
pmap_update(pmap_kernel());
}
/*
* Unmap IO request from the kernel virtual address space.
*/
void
vunmapbuf(bp, len)
struct buf *bp;
vsize_t len;
{
vaddr_t addr, off;
#ifdef DIAGNOSTIC
if ((bp->b_flags & B_PHYS) == 0)
panic("vunmapbuf");
#endif
addr = trunc_page((vaddr_t)bp->b_data);
off = (vaddr_t)bp->b_data - addr;
len = round_page(off + len);
pmap_kremove(addr, len);
pmap_update(pmap_kernel());
uvm_km_free_wakeup(phys_map, addr, len);
bp->b_data = bp->b_saveaddr;
bp->b_saveaddr = NULL;
}