/*
 * system-mode mapping
 * vax version
 */

#include "defs.h"
#include "space.h"
#include <sys/param.h>
#include <sys/pte.h>
#include <sys/pcb.h>
#include "machine.h"

static struct pte *sbr;
static WORD svpcbb;
static struct pcb pcb;
#define	HWPAGE	512

printkm()
{

	if (sbr)
		printf("%R$k\n", (WORD)sbr);
	if (svpcbb)
		printf("%R$p\np0 %R %R; p1 %R %R\n", svpcbb,
			(WORD)pcb.pcb_p0br, (WORD)pcb.pcb_p0lr,
			(WORD)pcb.pcb_p1br, (WORD)pcb.pcb_p1lr);
}

kmsys()
{

	if (adrflg)
		sbr = (struct pte *)adrval;
	else
		printkm();
}

kmproc()
{
	struct pte pte;

	if (adrflg == 0) {
		printkm();
		return;
	}
	if (adrval == -1) {
		svpcbb = 0;
		return;
	}
	if (sbr == 0)
		error("map the kernel first");
	if (INKERNEL(adrval)) {
		*(long *)&pte = lget((ADDR)adrval, CORF|DATASP);
		if (pte.pg_v == 0)
			error("pcb address not found");
		adrval = pte.pg_pfnum * HWPAGE;
	}
	if (fget((ADDR)adrval, CORF|DATASP|RAWADDR, (char *)&pcb, sizeof(pcb)) == 0) {
		svpcbb = 0;
		chkerr();
	}
	svpcbb = adrval;
}

/*
 * map a kernel address to a physical address
 * arg is a pointer to be filled in
 * returns nonzero if address is valid
 */

int
kmap(paddr, sp)
ADDR *paddr;
{
	long a;
	long pte;
#define	Ppte	(*(struct pte *)&pte)
	register int off, pfn;

	if (sbr == 0)
		return (1);
	sp &=~ RAWADDR;
	a = (long)*paddr & ~0xc0000000;
	off = a % HWPAGE;
	pfn = (a / HWPAGE);
	switch ((int)*paddr & 0xc0000000) {
	case 0xc0000000:		/* really illegal, but who cares? */
	case 0x80000000:		/* system space */
		pte = (long)lget((ADDR)(sbr + pfn), sp | RAWADDR);
		break;

	case 0x40000000:		/* p1 */
		if (svpcbb == 0)
			return (1);
		if (pfn <= pcb.pcb_p1lr)
			return (0);
		pte = lget((ADDR)(pcb.pcb_p1br + pfn), sp);
		if (errflg)
			return (0);
		break;

	case 0x00000000:		/* p0 */
		if (svpcbb == 0)
			return (1);
		if (pfn > pcb.pcb_p0lr)
			return (0);
		pte = lget((ADDR)(pcb.pcb_p0br + pfn), sp);
		if (errflg)
			return (0);
		break;
	}
	if (Ppte.pg_v == 0)
		return (0);
	*paddr = (ADDR)(Ppte.pg_pfnum * HWPAGE + off);
	return (1);
}
