/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986,1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:debugmain.c 12.0$ */
/* $ACIS:debugmain.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/standca/RCS/debugmain.c,v $ */

#ifndef lint
static char *rcsid = "$Header:debugmain.c 12.0$";
#endif

#include <stdio.h>

#include "debug.h"
#define nlist nlist_out
#include <a.out.h>
#undef nlist
#include <nlist.h>
#include "../h/types.h"
#include "../h/stat.h"
#include "../h/ioctl.h"
#include <setjmp.h>
#include <signal.h>
#include "init.h"
#include "err.h"

struct hatipt_entry *MMU_HATIPT;
int MMU_HASHMASK;
int mem;
int screen_lines = 24;
int trflag;
int iar_mask;

#define SEG_MASK	0xf0000000

#define RDB_START	0
#define RDB_SYMTAB	1
#define DUMPREGS	2
#define MMUREGS		3
#define HAT_IPT		4
#define HASHMASK	5
#define SYSREGS		6

#define MAXMMU 0x19	/* max mmu register saved */

struct nlist nl[] = {
{ "_rdb_start" },
{ "_rdb_symtab" },
{ "_dumpregs" },
{ "_dumpmmregs" },
{ "_MMU_HATIPT" },
{ "_MMU_HASHMASK" },
{ "_dumpsysregs" },
{ 0 } 
};

int regs[16];
int sysregs[16];
int mmuregs[MAXMMU];
int nflg;		/* no pausing */
int dflg;
int wflg;
int bflg = 1;		/* buffer by default */
#define BUFFSIZE 512	/* basic buffer size */
int buffsize = BUFFSIZE;
char buffer[BUFFSIZE];
int mem_offset;		/* if it is actually an a.out file */
int curpage = -1;
unsigned int endtext = 0xffffffff;
int data_adjust;
#define FIX_ADDR(addr) if ((unsigned) (addr) >= endtext) 	\
	addr -= data_adjust		/* adjust it to proper place */

char *bread();
jmp_buf label;
int intsig();

main(argc,argv)
char **argv;
{
	register char *argp;
	char *mem_file;
	char *namelist;
	register int l;
	struct exec hdr;
	char tbuf[2048];
	char tarea[512];
	char *tareaptr = tarea;
	char *getenv();
	char *name = getenv("TERM");

	if (name && tgetent(tbuf, name) == 1)
		{
		extern char *CL, *HO, *CE;
		int LI;
		char *tgetstr();
		CL = tgetstr("cl", &tareaptr);
		HO = tgetstr("ho", &tareaptr);
		if ((CE = tgetstr("ce", &tareaptr)) == 0)
			CE = "";		/* ignore it */
		LI = tgetnum("li");
		if (LI > 0)
			screen_lines = LI;
		}
	getwinsize();
	signal(SIGWINCH, getwinsize);
	iar_mask = 0x0fffffff; /* ignore segment number */
	while (argc > 1 && * (argp = argv[1]) == '-')
		{
		--argc;
		++argv;
		switch(argp[1])
			{
		case 'b':		/* buffer the disk */
			if (l = atoi(argp+2))
				buffsize = l;
			if (l < 0)
				bflg = 0;
			else
				++bflg;
			if (buffsize > BUFFSIZE)
				buffsize = BUFFSIZE;
			break;
		case 'd':		/* debug */
			++dflg;
			break;
		case 'w':		/* write file */
			++wflg;
			break;
		case 't':		/* turn on trflag (trace debugging) */
			++trflag;
			break;
		case 'n':
			++nflg;		/* no pausing */
			break;
			}
		}
	mem_file = argc > 1 ? argv[1] : "/dev/mem";
	namelist = argc > 2 ? argv[2] : "/vmunix";
	if ((mem = open(mem_file, wflg ? 2 : 0)) < 0)
		err("can't open %s%s",mem_file,wflg ? " for update" : "");
	if (read(mem, &hdr, sizeof hdr) != sizeof hdr)
		err("reading %s",mem_file);
	if (!N_BADMAG(hdr))
		{
		mem_offset = N_TXTOFF(hdr);	/* good enough to look at code */
		if (hdr.a_magic != 0407)
			{
			int pagesize = getpagesize();
			endtext = hdr.a_text;
			data_adjust = pagesize - (endtext & (pagesize - 1));
			}
		}
	if (dflg)
		printf("nlist %s\n",namelist);
	nlist(namelist,nl);
	if (dflg>1)
		prnlist();
	if (argc > 3)
		readsymtab(argv[3]);
	else
		{
		if (nl[RDB_START].n_type == 0)
			{
			char symfile[256];
			char cmd[512];
			struct stat statb;
			sprintf(symfile,"%s.sym",namelist);
			if (stat(symfile,&statb) < 0)
				{
				sprintf(cmd,"/sys/conf/buildsym %s %s",namelist,symfile);
				printf("could not find symtab in %s - building symbol table\n",namelist);
				printf("%s\n",cmd);
				system(cmd);
				}
			else
				printf("using symbol table in %s\n",symfile);
			readsymtab(symfile);
			}
		else
			{
			int size = nl[RDB_START].n_value - nl[RDB_SYMTAB].n_value;
			long off =  ((nl[RDB_SYMTAB].n_value)&~SEG_MASK) + mem_offset;
			if (dflg)
				printf("read symbol table (%d bytes) from offset %x of %s\n",size,off,mem_file);
			lseek(mem, off, 0);
			if ((symtab = (struct symtab *) calloc(size + sizeof (struct symtab),1)) == 0)
				err("can't allocate %d bytes for symbol table",size);
			bzero((char *) symtab, size + sizeof (struct symtab));
			if ((l = read(mem, (char *) symtab, size)) != size)
				err("can't read all of symbol table (got %d)",l);
			}
		}

	readinfo((char *) regs, nl[DUMPREGS].n_value, sizeof regs,"regs");
	readinfo((char *) sysregs, nl[SYSREGS].n_value, sizeof sysregs,"sysregs");
	readinfo((char *) mmuregs, nl[MMUREGS].n_value, sizeof mmuregs,"mmuregs");
	regsave = regs;		/* point to saved registers */
	fix_internal();
	init_hatipt();
	signal(SIGINT, intsig);
	setjmp(label);
	debug_state = 0;
	_debugger(PM_VEC);
}

readsymtab(symfile)
char *symfile;
{
	int size;
	int sym;
	struct exec hdr;
	if (dflg)
		printf("reading debugger symbol table from %s\n",symfile);
	if ((sym = open(symfile,0)) < 0)
		err("can't open %s",symfile);
	if (read(sym,&hdr, sizeof hdr) != sizeof hdr)
		err("can't read header of %s",symfile);
	size = hdr.a_text;
	if (N_BADMAG(hdr))
		err("%s bad magic number",symfile);
	if ((symtab = (struct symtab *) calloc(size,1)) == 0)
		err("can't allocate %d bytes for symbol table",size);
	lseek(sym, N_TXTOFF(hdr), 0);
	if (read(sym,(char *) symtab, size) != size)
		err("can't read all of symbol table");
	close(sym);
}

ior(reg)
register int reg;
{
	if (reg < MMUBASE || reg >= MMUBASE+MAXMMU)
		{
		printf("can't ior %x\n",reg);
		err_flag++;
		return(0);
		}
	else
		return(mmuregs[reg-MMUBASE]);
}

iow(reg,value)
register int reg;
register int value;
{
	if (reg < MMUBASE || reg >= MMUBASE+MAXMMU)
		{
		printf("can't iow(%x,%x)\n",reg,value);
		err_flag++;
		return(0);
		}
	else
		mmuregs[reg-MMUBASE] = value;
	return(0);
}

lps()
{
	if (dflg)
		printf("can't lps");
}

wfetch(addr)
{
	unsigned int value;
	register unsigned int *ptr;

/*	if (addr == CSR)
		return(0);	/* fake the csr value */
	if (addr == PM_VEC)
		return(sysregs[SCR_IAR] ? sysregs[SCR_IAR] : regs[15]);	/* we'll pretend it's r15 if no iar found */
	FIX_ADDR(addr);
	if (bflg)
		{
		if (ptr = (unsigned int *) bread(addr))
			return(*ptr);
		else
			return(-1);
		}
	lseek(mem, (long) addr + mem_offset, 0);
	if (read(mem, &value, sizeof value) != sizeof value)
		return(-1);
	return(value);
}

hfetch(addr)
{
	unsigned short value;
	register unsigned short *ptr;

	if (addr == PM_VEC+4)
		return(sysregs[SCR_ICS]&0xffff);
	if (addr == PM_VEC+6)
		return(sysregs[SCR_CS]&0xffff);
	FIX_ADDR(addr);
	if (bflg)
		{
		if (ptr = (unsigned short *) bread(addr))
			return(*ptr);
		else
			return(-1);
		}
	lseek(mem, (long) addr + mem_offset, 0);
	if (read(mem, &value, sizeof value) != sizeof value)
		return(-1);
	return(value);
}


bfetch(addr)
{
	unsigned char value;
	register unsigned char *ptr;

	FIX_ADDR(addr);
	if (bflg)
		{
		if (ptr = (unsigned char *) bread(addr))
			return(*ptr);
		else
			return(-1);
		}
	lseek(mem, (long) addr + mem_offset, 0);
	if (read(mem, &value, sizeof value) != sizeof value)
		return(-1);
	return(value);
}


wstore(addr,value)
	unsigned int value;
{
	if (addr == PM_VEC)
		{
		sysregs[SCR_IAR] = value;
		return(value);
		}
	FIX_ADDR(addr);
	lseek(mem, (long) addr + mem_offset, 0);
	if (write(mem, &value, sizeof value) != sizeof value)
		{
		printf("cannot write location %x\n",addr);
		return(-1);
		}
	curpage = -1;
	return(value);
}

hstore(addr,hvalue)
{
	unsigned short value = hvalue;
	if (addr == PM_VEC+4)
		{
		sysregs[SCR_ICS] = value;
		return(value);
		}
	if (addr == PM_VEC+6)
		{
		sysregs[SCR_CS] = value;
		return(value);
		}
	FIX_ADDR(addr);
	lseek(mem, (long) addr + mem_offset, 0);
	if (write(mem, &value, sizeof value) != sizeof value)
		{
		printf("cannot write location %x\n",addr);
		return(-1);
		}
	curpage = -1;
	return(value);
}


bstore(addr,bvalue)
{
	unsigned char value = bvalue;

	FIX_ADDR(addr);
	lseek(mem, (long) addr + mem_offset, 0);
	if (write(mem, &value, sizeof value) != sizeof value)
		{
		printf("cannot write location %x\n",addr);
		return(-1);
		}
	curpage = -1;
	return(value);
}

#ifdef __STDC__
void err/* KILL CTAGS */(char *fmt, ...)
#else
void err/* KILL CTAGS */(fmt,d1,d2,d3)
char *fmt;
#endif __STDC__
{
	printf(fmt,((int *) &fmt)[1],((int *) &fmt)[2],((int *) &fmt)[3]);
	printf("\n");
	exit(1);
}


mfsr(reg)
register int reg;
{
	if (dflg>1)
		printf("mfsr s%d\n",reg);
	if (reg >= 0 && reg < 16)
		return(sysregs[reg]);
	else
		err("mfsr s%d\n",reg);
	return(0);
}

mtsr(reg,value)
register int reg;
register int value;
{
	if (dflg>1)
		printf("mtsr s%d %d\n",reg,value);
	if (reg >= 0 && reg < 16)
		sysregs[reg] = value;
	else
		err("mtsr s%d %d\n",reg,value);
	return(0);
}

#include <sgtty.h>
#undef getchar
_getchar()
{
	register int c;
	struct sgttyb sgtty;

	if (nflg)
		return(' ');
	gtty(0, &sgtty);
	sgtty.sg_flags &= ~ECHO;
	stty(0, &sgtty);
	c = getc(stdin);
	sgtty.sg_flags |= ECHO;
	stty(0, &sgtty);
	return(c);
}

callabs()
{
	printf("callabs\n");
}

_init_vectors(n)
register int n;
{
	debug_state = n;	/* what a kludge! */
}

init_kbd()
{
	printf("init_kbd\n");
}

put_status(pos,str)
register char *str;
{
	if (!nflg)
		printf("%s\r",str);
}

readinfo(info, addr, size, name)
register char *info;
register int addr;
register int size;
register char *name;
{
	if (dflg)
		printf("read %s from %x (%d bytes)\n",name, addr, size);
	if (addr == 0)
		printf("warning: unable to locate %s (not in namelist)\n",name);
	else
		{
		lseek(mem, addr & ~SEG_MASK, 0);
		if (read(mem, info, size) != size)
			err("reading %s - %d bytes from %x",name,size,addr);
		}
}

struct symtab internal[];

fix_internal()
{
	register struct symtab *sym;
	register adjust = ((int) regsave) - REGSAVE;

	internal[0].value = (int) &sysregs[SCR_IAR];
	for (sym = internal; sym->symbol[0]; ++sym)
		if (sym->value >= REGSAVE && sym->value < REGSAVE+64)
			sym->value += adjust;
}

/*
 * read in hat/ipt so that we can do virtual to real translations
 */
init_hatipt()
{

	register int ptr = wfetch(nl[HAT_IPT].n_value & ~SEG_MASK);
	register int hash = wfetch(nl[HASHMASK].n_value & ~SEG_MASK);
	register int size = (hash+1) * sizeof (struct hatipt_entry);

	MMU_HASHMASK = hash;
	MMU_HATIPT = (struct hatipt_entry *) calloc(size, 1);
	readinfo((char *) MMU_HATIPT, ptr & ~SEG_MASK, size, "hatipt");
}


#define btop(addr) (((unsigned) (addr)) >> 11)
#define ctob(addr) (((unsigned) (addr)) << 11)
#define PGOFSET 0x7ff		/* NBPG - 1 */

/*
 * do virtual to real translation using the hat/ipt and the 
 * contents of the segment registers
 */
vtop(where)
	register unsigned int where;
{
	register struct hatipt_entry *ipte;
	register unsigned int addrtag, vpage, sid;
	register int probes;
	unsigned int page_off;
#define MAX_PROBES 100
	sid = get_segreg(where >> 28) & 0xFFF;
	vpage = btop(where & 0x0FFFFFFF);
	page_off = where & PGOFSET;
	ipte = &MMU_HATIPT[MMU_HASH(sid, vpage)];
if (dflg>1) printf("vtop:  where=%x,sid=%x,vpage=%x,ipte=%x\n",where,sid,vpage,ipte);/* DEBUG */
	/* make sure there is an ipt chain */
	if (MMU_ENDCHAIN(ipte->hat_ptr)) { /* hat pointer empty...not found */
if (dflg>1) printf("hat chain empty\n");/* DEBUG */
		printf("bad virtual address\n");
		++err_flag;
		return (-1);
	}
	/* chase down the hat ptr */
	if (dflg>1) printf("get_hatptr(ipte=%x)=%x\n",ipte,get_hatptr(ipte));/* DEBUG */
	ipte = &MMU_HATIPT[get_hatptr(ipte) & MMU_HASHMASK];
	if (dflg>1) printf("ipte now at %x\n",ipte);/* DEBUG */
	addrtag = (sid << MMU_VPAGE_BITS) | vpage;
	if (dflg>1) printf("addrtag=%x\n",addrtag);/* DEBUG */
	/* check addrtag of first element of ipt chain */
	if ((ipte->key_addrtag & 0x1fffffff) == addrtag) {
					  /* same, return vpage + page offset from where 
					  */
if (dflg>1) printf("first on chain,=%x\n",ctob(ipte-MMU_HATIPT)+page_off);/* DEBUG */
		return (ctob(ipte - MMU_HATIPT) + page_off);
	}
	/* for second element ff. */
	probes = 0;
	while (!MMU_ENDCHAIN(get_iptptr(ipte))) { /* while there is a next element */
		/* point to the next element */
		ipte = &MMU_HATIPT[get_iptptr(ipte) & MMU_HASHMASK];
if (dflg>1) printf("checking ipte at %x\n",ipte);/* DEBUG */
		/* check addrtag for this element against desired one */
		if ((ipte->key_addrtag & 0x1fffffff) == addrtag) {
					  /* same, return vpage + page offset from where 
					  */
if (dflg>1) printf("found it, = %x\n",ctob(ipte-MMU_HATIPT)+page_off);/* DEBUG */
			return (ctob(ipte - MMU_HATIPT) + page_off);
		}
		if (probes++ >= MAX_PROBES) {
if (dflg>1) printf("VTOP:  loop chasing down an ipt chain!!!\n");/* DEBUG */
			return (-1);
		}
	}
if (dflg>1) printf("end of chain...not found\n");/* DEBUG */
	printf("bad virtual address\n");
	++err_flag;
	return (-1);
}

prnlist()
{
	register struct nlist *nlist;

	for (nlist=nl; nlist < nl + sizeof nl / sizeof nl[0]; ++nlist)
		printf("%-20s %08x %08x\n",nlist->n_name,nlist->n_value,nlist->n_type);
}



/*
 * read "addr" into a buffer and return a pointer to it.
 * used so that sequential accesses to memory are fairly
 * efficient.
 */
char *bread(base_addr)
register int base_addr;
{
	register int addr = base_addr + mem_offset;
	register int off = addr & (buffsize-1);
	register int page = addr & ~(buffsize-1);

	if (curpage != page)
		{
		lseek(mem, (long) page, 0);
		if (read(mem, buffer, sizeof buffer) != sizeof buffer)
			return((char *) 0);		/* could not read it */
		curpage = page;
		}
	return(buffer+off);
}

intsig()
{
	printf("interrupted\n");
	longjmp(label);
}

/*
 * NOTE: we put the type on the same line to defeat ctags which otherwise
 * would pick these definitions instead of the real ones.
 */

void save_screen()
{
}

void screen_restore()
{
}

/*
 * following are only for ATR
 */
int pcif_io_b;
int pcif_io_hw;
int pcif_512_fw;

int get_512_window/* KILL CTAGS */(addr)
{
	return(addr);
}

int set_512_window/* KILL CTAGS */(addr)
{
	return(addr);
}

int get_128_window/* KILL CTAGS */(addr)
{
	return(addr);
}

int set_128_window/* KILL CTAGS */(addr)
{
	return(addr);
}

int ps2_enter_debugger/* KILL CTAGS */()
{
	return(0);
}

void ps2_exit_debugger/* KILL CTAGS */()
{
}

int pcif_print/* KILL CTAGS */()
{
}

getwinsize()
{
	struct winsize window;

	if (ioctl(1, TIOCGWINSZ, (char *) &window) >= 0)
		if (window.ws_row > 0) {
			screen_lines = window.ws_row;
			if (dflg)
				printf("%d lines\n",screen_lines);
		}
}
