#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/exec.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/syscallargs.h>
#include <sys/user.h>
#include <sys/sched.h>
#include <sys/msg.h>
#include <sys/conf.h>
#include <sys/kcore.h>
#include <sys/reboot.h>
#include <uvm/uvm_extern.h>
#include <dev/cons.h>
#include <sh/cache.h>
#include <sh/clock.h>
#include <sh/fpu.h>
#include <sh/locore.h>
#include <sh/mmu.h>
#include <sh/trap.h>
#include <sh/intr.h>
#include <sh/kcore.h>
int cpu_arch;
int cpu_product;
char cpu_model[120];
struct vm_map *exec_map;
struct vm_map *phys_map;
int physmem;
struct user *proc0paddr;
struct pcb *curpcb;
struct md_upte *curupte;
#define VBR (u_int8_t *)SH3_PHYS_TO_P1SEG(IOM_RAM_BEGIN)
vaddr_t ram_start = SH3_PHYS_TO_P1SEG(IOM_RAM_BEGIN);
extern char sh_vector_generic[], sh_vector_generic_end[];
extern char sh_vector_interrupt[], sh_vector_interrupt_end[];
#ifdef SH3
extern char sh3_vector_tlbmiss[], sh3_vector_tlbmiss_end[];
#endif
#ifdef SH4
extern char sh4_vector_tlbmiss[], sh4_vector_tlbmiss_end[];
#endif
u_long dumpmag = 0x8fca0101;
u_int dumpsize;
long dumplo;
cpu_kcore_hdr_t cpu_kcore_hdr;
void
sh_cpu_init(int arch, int product)
{
cpu_arch = arch;
cpu_product = product;
#if defined(SH3) && defined(SH4)
sh_devreg_init();
#endif
sh_cache_init();
sh_mmu_init();
machine_clock_init();
intc_init();
memcpy(VBR + 0x100, sh_vector_generic,
sh_vector_generic_end - sh_vector_generic);
#ifdef SH3
if (CPU_IS_SH3)
memcpy(VBR + 0x400, sh3_vector_tlbmiss,
sh3_vector_tlbmiss_end - sh3_vector_tlbmiss);
#endif
#ifdef SH4
if (CPU_IS_SH4)
memcpy(VBR + 0x400, sh4_vector_tlbmiss,
sh4_vector_tlbmiss_end - sh4_vector_tlbmiss);
#endif
memcpy(VBR + 0x600, sh_vector_interrupt,
sh_vector_interrupt_end - sh_vector_interrupt);
if (!SH_HAS_UNIFIED_CACHE)
sh_icache_sync_all();
__asm volatile("ldc %0, vbr" :: "r"(VBR));
__sh_switch_resume = CPU_IS_SH3 ? sh3_switch_resume : sh4_switch_resume;
uvm_setpagesize();
}
void
sh_proc0_init(void)
{
struct switchframe *sf;
vaddr_t u;
u = uvm_pageboot_alloc(USPACE);
memset((void *)u, 0, USPACE);
proc0paddr = (struct user *)u;
proc0.p_addr = proc0paddr;
curpcb = proc0.p_md.md_pcb = &proc0.p_addr->u_pcb;
curupte = proc0.p_md.md_upte;
sf = &curpcb->pcb_sf;
sf->sf_r6_bank = u + PAGE_SIZE;
sf->sf_r7_bank = sf->sf_r15 = u + USPACE;
__asm volatile("ldc %0, r6_bank" :: "r"(sf->sf_r6_bank));
__asm volatile("ldc %0, r7_bank" :: "r"(sf->sf_r7_bank));
proc0.p_md.md_regs = (struct trapframe *)sf->sf_r6_bank - 1;
#ifdef KSTACK_DEBUG
memset((char *)(u + sizeof(struct user)), 0x5a,
PAGE_SIZE - sizeof(struct user));
memset((char *)(u + PAGE_SIZE), 0xa5, USPACE - PAGE_SIZE);
#endif
}
void
sh_startup(void)
{
vaddr_t minaddr, maxaddr;
printf("%s", version);
#ifdef DEBUG
printf("general exception handler:\t%d byte\n",
sh_vector_generic_end - sh_vector_generic);
printf("TLB miss exception handler:\t%d byte\n",
#if defined(SH3) && defined(SH4)
CPU_IS_SH3 ? sh3_vector_tlbmiss_end - sh3_vector_tlbmiss :
sh4_vector_tlbmiss_end - sh4_vector_tlbmiss
#elif defined(SH3)
sh3_vector_tlbmiss_end - sh3_vector_tlbmiss
#elif defined(SH4)
sh4_vector_tlbmiss_end - sh4_vector_tlbmiss
#endif
);
printf("interrupt exception handler:\t%d byte\n",
sh_vector_interrupt_end - sh_vector_interrupt);
#endif
printf("real mem = %lu (%luMB)\n", ptoa(physmem),
ptoa(physmem) / 1024 / 1024);
minaddr = vm_map_min(kernel_map);
exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
VM_PHYS_SIZE, 0, FALSE, NULL);
bufinit();
printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free),
ptoa(uvmexp.free) / 1024 / 1024);
if (boothowto & RB_CONFIG) {
#ifdef BOOT_CONFIG
user_config();
#else
printf("kernel does not support -c; continuing..\n");
#endif
}
}
void
dumpconf(void)
{
cpu_kcore_hdr_t *h = &cpu_kcore_hdr;
u_int dumpextra, totaldumpsize;
u_int seg, nblks;
if (dumpdev == NODEV ||
(nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0)
return;
if (nblks <= ctod(1))
return;
dumpsize = 0;
for (seg = 0; seg < h->kcore_nsegs; seg++)
dumpsize += atop(h->kcore_segs[seg].size);
dumpextra = cpu_dumpsize();
if (dumplo < btodb(1))
dumplo = btodb(1);
totaldumpsize = ctod(dumpsize) + dumpextra;
if (totaldumpsize > nblks - dumplo) {
totaldumpsize = dbtob(nblks - dumplo);
dumpsize = dtoc(totaldumpsize - dumpextra);
}
if (dumplo < nblks - totaldumpsize)
dumplo = nblks - totaldumpsize;
}
void
dumpsys(void)
{
cpu_kcore_hdr_t *h = &cpu_kcore_hdr;
daddr_t blkno;
int (*dump)(dev_t, daddr_t, caddr_t, size_t);
u_int page = 0;
paddr_t dumppa;
u_int seg;
int rc;
extern int msgbufmapped;
msgbufmapped = 0;
if (dumpdev == NODEV)
return;
if (dumpsize == 0) {
dumpconf();
if (dumpsize == 0)
return;
}
if (dumplo <= 0) {
printf("\ndump to dev 0x%x not possible, not enough space\n",
dumpdev);
return;
}
dump = bdevsw[major(dumpdev)].d_dump;
blkno = dumplo;
printf("\ndumping to dev 0x%x offset %ld\n", dumpdev, dumplo);
printf("dump ");
rc = cpu_dump(dump, &blkno);
if (rc != 0)
goto bad;
for (seg = 0; seg < h->kcore_nsegs; seg++) {
u_int pagesleft;
pagesleft = atop(h->kcore_segs[seg].size);
dumppa = (paddr_t)h->kcore_segs[seg].start;
while (pagesleft != 0) {
u_int npages;
#define NPGMB atop(1024 * 1024)
if (page != 0 && (page % NPGMB) == 0)
printf("%u ", page / NPGMB);
npages = min(pagesleft, NPGMB);
#undef NPGMB
npages = min(npages, dumpsize);
rc = (*dump)(dumpdev, blkno,
(caddr_t)SH3_PHYS_TO_P2SEG(dumppa), ptoa(npages));
if (rc != 0)
goto bad;
pagesleft -= npages;
dumppa += ptoa(npages);
page += npages;
dumpsize -= npages;
if (dumpsize == 0)
goto bad;
blkno += ctod(npages);
}
}
bad:
switch (rc) {
case 0:
printf("succeeded\n");
break;
case ENXIO:
printf("device bad\n");
break;
case EFAULT:
printf("device not ready\n");
break;
case EINVAL:
printf("area improper\n");
break;
case EIO:
printf("I/O error\n");
break;
case EINTR:
printf("aborted\n");
break;
default:
printf("error %d\n", rc);
break;
}
delay(1 * 1000 * 1000);
}
struct sigframe {
#if 0
int sf_signum;
siginfo_t *sf_sip;
struct sigcontext *sf_ucp;
#endif
struct sigcontext sf_uc;
siginfo_t sf_si;
};
int
sendsig(sig_t catcher, int sig, sigset_t mask, const siginfo_t *ksip,
int info, int onstack)
{
struct proc *p = curproc;
struct sigframe *fp, frame;
struct trapframe *tf = p->p_md.md_regs;
siginfo_t *sip;
if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 &&
!sigonstack(p->p_md.md_regs->tf_r15) &&
onstack)
fp = (struct sigframe *)
trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size);
else
fp = (void *)p->p_md.md_regs->tf_r15;
--fp;
bzero(&frame, sizeof(frame));
if (info) {
frame.sf_si = *ksip;
sip = &fp->sf_si;
} else
sip = NULL;
memcpy(frame.sf_uc.sc_reg, &tf->tf_spc, sizeof(frame.sf_uc.sc_reg));
#ifdef SH4
if (CPU_IS_SH4)
fpu_save((struct fpreg *)&frame.sf_uc.sc_fpreg);
#endif
frame.sf_uc.sc_expevt = tf->tf_expevt;
frame.sf_uc.sc_mask = mask;
frame.sf_uc.sc_cookie = (long)&fp->sf_uc ^ p->p_p->ps_sigcookie;
if (copyout(&frame, fp, sizeof(frame)) != 0)
return 1;
tf->tf_r4 = sig;
tf->tf_r5 = (int)sip;
tf->tf_r6 = (int)&fp->sf_uc;
tf->tf_spc = (int)catcher;
tf->tf_r15 = (int)fp;
tf->tf_pr = (int)p->p_p->ps_sigcode;
return 0;
}
int
sys_sigreturn(struct proc *p, void *v, register_t *retval)
{
struct sys_sigreturn_args
*uap = v;
struct sigcontext ksc, *scp = SCARG(uap, sigcntxp);
struct trapframe *tf;
int error;
if (PROC_PC(p) != p->p_p->ps_sigcoderet) {
sigexit(p, SIGILL);
return (EPERM);
}
if ((error = copyin(scp, &ksc, sizeof(*scp))) != 0)
return (error);
if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) {
sigexit(p, SIGILL);
return (EFAULT);
}
ksc.sc_cookie = 0;
(void)copyout(&ksc.sc_cookie, (caddr_t)scp +
offsetof(struct sigcontext, sc_cookie), sizeof(ksc.sc_cookie));
tf = p->p_md.md_regs;
if (((ksc.sc_reg[1] ^ tf->tf_ssr) & PSL_USERSTATIC) != 0)
return (EINVAL);
memcpy(&tf->tf_spc, ksc.sc_reg, sizeof(ksc.sc_reg));
#ifdef SH4
if (CPU_IS_SH4)
fpu_restore((struct fpreg *)&ksc.sc_fpreg);
#endif
p->p_sigmask = ksc.sc_mask & ~sigcantmask;
return (EJUSTRETURN);
}
void
setregs(struct proc *p, struct exec_package *pack, u_long stack,
struct ps_strings *arginfo)
{
struct trapframe *tf;
struct pcb *pcb = p->p_md.md_pcb;
p->p_md.md_flags &= ~MDP_USEDFPU;
tf = p->p_md.md_regs;
tf->tf_gbr = 0;
tf->tf_macl = 0;
tf->tf_mach = 0;
tf->tf_r0 = 0;
tf->tf_r1 = 0;
tf->tf_r2 = 0;
tf->tf_r3 = 0;
tf->tf_r4 = arginfo->ps_nargvstr;
tf->tf_r5 = (register_t)arginfo->ps_argvstr;
tf->tf_r6 = (register_t)arginfo->ps_envstr;
tf->tf_r7 = 0;
tf->tf_r8 = 0;
tf->tf_r9 = (int)p->p_p->ps_strings;
tf->tf_r10 = 0;
tf->tf_r11 = 0;
tf->tf_r12 = 0;
tf->tf_r13 = 0;
tf->tf_r14 = 0;
tf->tf_spc = pack->ep_entry;
tf->tf_ssr = PSL_USERSET;
tf->tf_r15 = stack;
#ifdef SH4
if (CPU_IS_SH4) {
bzero(&pcb->pcb_fp, sizeof(pcb->pcb_fp));
pcb->pcb_fp.fpr_fpscr = FPSCR_PR;
fpu_restore(&pcb->pcb_fp);
}
#endif
}
void
cpu_reset(void)
{
_cpu_exception_suspend();
_reg_write_4(SH_(EXPEVT), EXPEVT_RESET_MANUAL);
#ifndef __lint__
goto *(void *)0xa0000000;
#endif
}