#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: promlib.c,v 1.20 2024/01/13 18:51:38 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/reboot.h>
#include <sys/boot_flag.h>
#include <uvm/uvm_extern.h>
#define _SUN2_PROMLIB_PRIVATE
#include <machine/promlib.h>
#include <machine/vectors.h>
#include <sun2/sun2/machdep.h>
#include <sun2/sun2/control.h>
#include <machine/pte.h>
struct kernel_state {
int saved_spl;
int saved_ctx;
u_int saved_ptes[4];
};
static void **sunmon_vbr;
static struct kernel_state sunmon_kernel_state;
static struct bootparam sunmon_bootparam;
static u_int sunmon_ptes[4];
static void tracedump(int);
static inline void _prom_swap_ptes(u_int *, u_int *);
static inline void
_prom_swap_ptes(u_int *swapout, u_int *swapin)
{
int pte_number;
vaddr_t va;
for (pte_number = 0, va = 0; pte_number < 4;
pte_number++, va += PAGE_SIZE) {
swapout[pte_number] = get_pte(va);
set_pte(va, swapin[pte_number]);
}
}
static inline void _mode_monitor(struct kernel_state *, int);
static inline void
_mode_monitor(struct kernel_state *state, int full)
{
state->saved_ctx = get_context();
set_context(0);
_prom_swap_ptes(state->saved_ptes, sunmon_ptes);
if (full) {
state->saved_spl = splhigh();
set_clk_mode(0, 0);
setvbr(sunmon_vbr);
set_clk_mode(1, 1);
}
}
static inline void _mode_kernel(struct kernel_state *, int);
static inline void
_mode_kernel(struct kernel_state *state, int full)
{
if (full) {
set_clk_mode(1, 0);
setvbr(vectab);
set_clk_mode(0, 1);
splx(state->saved_spl);
}
_prom_swap_ptes(sunmon_ptes, state->saved_ptes);
set_context(state->saved_ctx);
}
#define PROMLIB_FUNC(type, new, proto, old, args, ret) \
type new proto \
{ \
struct kernel_state state; \
int rc; \
_mode_monitor(&state, 0); \
rc = (*(romVectorPtr->old)) args; \
__USE(rc); \
_mode_kernel(&state, 0); \
ret ; \
}
PROMLIB_FUNC(int, prom_memsize, (void), memorySize, + 0, return(rc))
PROMLIB_FUNC(int, prom_stdin, (void), inSource, + 0, return(rc))
PROMLIB_FUNC(int, prom_stdout, (void), outSink, + 0, return(rc))
PROMLIB_FUNC(int, prom_kbdid, (void), keyBid, + 0, return(rc))
PROMLIB_FUNC(int, prom_getchar, (void), getChar, (), return(rc))
PROMLIB_FUNC(int, prom_peekchar, (void), mayGet, (), return(rc))
PROMLIB_FUNC(void, prom_putchar, (int c), putChar, (c), return)
void
prom_putstr(char *buf, int len)
{
struct kernel_state state;
_mode_monitor(&state, 0);
for(; len > 0; buf++, len--) {
(*(romVectorPtr->putChar))((int) (*buf));
}
_mode_kernel(&state, 0);
}
void
prom_printf(const char *fmt, ...)
{
struct kernel_state state;
int rc;
va_list ap;
const char *p1;
char c1;
struct printf_args {
int arg[15];
} varargs;
int i;
va_start(ap, fmt);
i = 0;
for(p1 = fmt; (c1 = *(p1++)) != '\0'; ) {
if (c1 == '%') {
if (i == (sizeof(varargs.arg) /
sizeof(varargs.arg[0]))) {
prom_printf("too many args to prom_printf, "
"format %s", fmt);
prom_abort();
}
varargs.arg[i++] = va_arg(ap, int);
}
}
va_end(ap);
_mode_monitor(&state, 0);
rc = (*
( (int (*)(const char *, struct printf_args))
(romVectorPtr->printf))
)(fmt, varargs);
__USE(rc);
_mode_kernel(&state, 0);
}
char *
prom_getbootpath(void)
{
return (sunmon_bootparam.argPtr[0]);
}
char *
prom_getbootargs(void)
{
return (sunmon_bootparam.argPtr[1]);
}
char *
prom_getbootfile(void)
{
return (sunmon_bootparam.fileName);
}
int
prom_sd_target(int unit)
{
switch(unit) {
case 2: return (4);
}
return (unit);
}
void
prom_abort(void)
{
uint16_t old_g0_g4_vectors[4], *vec, *store;
_mode_monitor(&sunmon_kernel_state, 1);
#define BRAW 0x6000
vec = (uint16_t *) sunmon_vbr;
store = old_g0_g4_vectors;
*(store++) = *vec;
*(vec++) = BRAW;
*(store++) = *vec;
*vec = ((u_long) g0_entry) - ((u_long) vec);
vec++;
*(store++) = *vec;
*(vec++) = BRAW;
*(store++) = *vec;
*vec = ((u_long) g4_entry) - ((u_long) vec);
vec++;
#undef BRAW
delay(100000);
__asm(" trap #14 ; _sunmon_continued: nop");
vec = (uint16_t *) sunmon_vbr;
store = old_g0_g4_vectors;
*(vec++) = *(store++);
*(vec++) = *(store++);
*(vec++) = *(store++);
*(vec++) = *(store++);
_mode_kernel(&sunmon_kernel_state, 1);
}
void
prom_halt(void)
{
_mode_monitor(&sunmon_kernel_state, 1);
(*romVectorPtr->exitToMon)();
for(;;);
}
void
prom_boot(const char *bs)
{
_mode_monitor(&sunmon_kernel_state, 1);
(*romVectorPtr->reBoot)(bs);
(*romVectorPtr->exitToMon)();
for(;;);
}
struct funcall_frame {
struct funcall_frame *fr_savfp;
int fr_savpc;
int fr_arg[1];
};
static void __noinline
tracedump(int x1)
{
struct funcall_frame *fp = (struct funcall_frame *)(&x1 - 2);
u_int stackpage = ((u_int)fp) & ~PGOFSET;
prom_printf("Begin traceback...fp = 0x%x\n", fp);
do {
if (fp == fp->fr_savfp) {
prom_printf("FP loop at 0x%x", fp);
break;
}
prom_printf("Called from 0x%x, fp=0x%x, args=0x%x 0x%x 0x%x 0x%x\n",
fp->fr_savpc, fp->fr_savfp,
fp->fr_arg[0], fp->fr_arg[1], fp->fr_arg[2], fp->fr_arg[3]);
fp = fp->fr_savfp;
} while ( (((u_int)fp) & ~PGOFSET) == stackpage);
prom_printf("End traceback...\n");
}
void g0_handler(void);
void
g0_handler(void)
{
_mode_kernel(&sunmon_kernel_state, 1);
panic("zero");
}
void g4_handler(int);
void
g4_handler(int addr)
{
_mode_kernel(&sunmon_kernel_state, 1);
tracedump(addr);
}
void
prom_init(void)
{
struct bootparam *old_bp;
struct bootparam *new_bp;
int bp_shift;
int i;
char *p;
int fl;
old_bp = *romVectorPtr->bootParam;
new_bp = &sunmon_bootparam;
*new_bp = *old_bp;
bp_shift = ((char *) new_bp) - ((char *) old_bp);
for(i = 0; i < 8 && new_bp->argPtr[i] != NULL; i++) {
new_bp->argPtr[i] += bp_shift;
}
new_bp->fileName += bp_shift;
_prom_swap_ptes(sunmon_ptes, sunmon_ptes);
sunmon_vbr = getvbr();
sunmon_vbr[32+14] = romVectorPtr->abortEntry;
p = prom_getbootargs();
if (p != NULL) {
for(; *p != '-'; )
if (*(p++) == '\0') {
p = NULL;
break;
}
}
if (p != NULL) {
#ifdef DEBUG
prom_printf("boot options: %s\n", p);
#endif
for(; *(++p); ) {
fl = 0;
BOOT_FLAG(*p, fl);
if (fl)
boothowto |= fl;
else
prom_printf("unknown option `%c'\n", *p);
}
}
}