File:  [Plan 9 NeXT] / lucent / sys / src / 9 / pc / main.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:01:02 2018 UTC (8 years, 1 month ago) by root
Branches: lucent, MAIN
CVS tags: plan9, HEAD
Plan 9 NeXT

#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"ureg.h"
#include	"init.h"
#include	<ctype.h>


uchar *sp;	/* stack pointer for /boot */

extern PCArch nsx20, generic, ncr3170;

PCArch *arch;
PCArch *knownarch[] =
{
	&nsx20,
	&ncr3170,
	&generic,
};

/* where b.com leaves configuration info */
#define BOOTARGS	((char*)(KZERO|1024))
#define	BOOTARGSLEN	1024
#define	MAXCONF		32

char bootdisk[NAMELEN];
char *confname[MAXCONF];
char *confval[MAXCONF];
int nconf;

/* memory map */
#define MAXMEG 64
char mmap[MAXMEG+2];

void
main(void)
{
	ident();
	i8042a20();		/* enable address lines 20 and up */
	machinit();
	active.exiting = 0;
	active.machs = 1;
	confinit();
	xinit();
	dmainit();
	screeninit();
	printinit();
	mmuinit();
	pageinit();
	trapinit();
	mathinit();
	clockinit();
	printcpufreq();
	faultinit();
	kbdinit();
	procinit0();
	initseg();
	streaminit();
	chandevreset();
	swapinit();
	userinit();
	schedinit();
}

/*
 *  This tries to capture architecture dependencies since things
 *  like power management/reseting/mouse are outside the hardware
 *  model.
 */
void
ident(void)
{
	char *id = (char*)(ROMBIOS + 0xFF40);
	PCArch **p;

	for(p = knownarch; *p != &generic; p++)
		if(strncmp((*p)->id, id, strlen((*p)->id)) == 0)
			break;
	arch = *p;
}

void
machinit(void)
{
	int n;

	n = m->machno;
	memset(m, 0, sizeof(Mach));
	m->machno = n;
	m->mmask = 1<<m->machno;
}

ulong garbage;

void
init0(void)
{
	int i;
	char tstr[32];

	u->nerrlab = 0;
	m->proc = u->p;
	u->p->state = Running;
	u->p->mach = m;

	spllo();

	/*
	 * These are o.k. because rootinit is null.
	 * Then early kproc's will have a root and dot.
	 */
	u->slash = (*devtab[0].attach)(0);
	u->dot = clone(u->slash, 0);

	kproc("alarm", alarmkproc, 0);
	chandevinit();

	if(!waserror()){
		strcpy(tstr, arch->id);
		strcat(tstr, " %s");
		ksetterm(tstr);
		ksetenv("cputype", "386");
		for(i = 0; i < nconf; i++)
			if(confname[i])
				ksetenv(confname[i], confval[i]);
		poperror();
	}
	touser(sp);
}

void
userinit(void)
{
	Proc *p;
	Segment *s;
	User *up;
	KMap *k;
	Page *pg;

	p = newproc();
	p->pgrp = newpgrp();
	p->egrp = smalloc(sizeof(Egrp));
	p->egrp->ref = 1;
	p->fgrp = smalloc(sizeof(Fgrp));
	p->fgrp->ref = 1;
	p->procmode = 0640;

	strcpy(p->text, "*init*");
	strcpy(p->user, eve);
	p->fpstate = FPinit;
	fpoff();

	/*
	 * Kernel Stack
	 *
	 * N.B. The -12 for the stack pointer is important.
	 *	4 bytes for gotolabel's return PC
	 */
	p->sched.pc = (ulong)init0;
	p->sched.sp = USERADDR + BY2PG - 4;
	p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF));

	/*
	 * User
	 */
	k = kmap(p->upage);
	up = (User*)VA(k);
	up->p = p;
	kunmap(k);

	/*
	 * User Stack
	 */
	s = newseg(SG_STACK, USTKTOP-BY2PG, 1);
	p->seg[SSEG] = s;
	pg = newpage(1, 0, USTKTOP-BY2PG);
	segpage(s, pg);
	k = kmap(pg);
	bootargs(VA(k));
	kunmap(k);

	/*
	 * Text
	 */
	s = newseg(SG_TEXT, UTZERO, 1);
	p->seg[TSEG] = s;
	segpage(s, newpage(1, 0, UTZERO));
	k = kmap(s->map[0]->pages[0]);
	memmove((ulong*)VA(k), initcode, sizeof initcode);
	kunmap(k);

	ready(p);
}

uchar *
pusharg(char *p)
{
	int n;

	n = strlen(p)+1;
	sp -= n;
	memmove(sp, p, n);
	return sp;
}

void
bootargs(ulong base)
{
 	int i, ac;
	uchar *av[32];
	uchar **lsp;
	char *cp = BOOTLINE;
	char buf[64];

	sp = (uchar*)base + BY2PG - MAXSYSARG*BY2WD;

	ac = 0;
	av[ac++] = pusharg("/386/9pc");
	cp[64] = 0;
	buf[0] = 0;

	/*
	 *  decode the b.com bootline and convert to
	 *  a disk device name to pass to the boot
	 */
	if(strncmp(cp, "fd!", 3) == 0){
		sprint(buf, "local!#f/fd%ddisk", atoi(cp+3));
		av[ac++] = pusharg(buf);
	} else if(strncmp(cp, "h!", 2) == 0){
		sprint(buf, "local!#H/hd%dfs", atoi(cp+2));
		av[ac++] = pusharg(buf);
	} else if(strncmp(cp, "hd!", 3) == 0){
		sprint(buf, "local!#H/hd%ddisk", atoi(cp+3));
		av[ac++] = pusharg(buf);
	} else if(strncmp(cp, "s!", 2) == 0){
		sprint(buf, "local!#w%d/sd%dfs", atoi(cp+2), atoi(cp+2));
		av[ac++] = pusharg(buf);
	} else if(strncmp(cp, "sd!", 3) == 0){
		sprint(buf, "local!#w%d/sd%ddisk", atoi(cp+3), atoi(cp+3));
		av[ac++] = pusharg(buf);
	} else if(getconf("bootdisk") == 0){
		if(conf.nhard){
			sprint(buf, "local!#H/hd0disk");
			av[ac++] = pusharg(buf);
		} else{
			sprint(buf, "local!#w/sd0disk");
			av[ac++] = pusharg(buf);
		}
	}
	if(buf[0]){
		cp = strchr(buf, '!');
		if(cp){
			strcpy(bootdisk, cp+1);
			addconf("bootdisk", bootdisk);
		}
	}

	/* 4 byte word align stack */
	sp = (uchar*)((ulong)sp & ~3);

	/* build argc, argv on stack */
	sp -= (ac+1)*sizeof(sp);
	lsp = (uchar**)sp;
	for(i = 0; i < ac; i++)
		*lsp++ = av[i] + ((USTKTOP - BY2PG) - base);
	*lsp = 0;
	sp += (USTKTOP - BY2PG) - base - sizeof(ulong);
}

Conf	conf;

void
addconf(char *name, char *val)
{
	if(nconf >= MAXCONF)
		return;
	confname[nconf] = name;
	confval[nconf] = val;
	nconf++;
}

char*
getconf(char *name)
{
	int i;

	for(i = 0; i < nconf; i++)
		if(strcmp(confname[i], name) == 0)
			return confval[i];
	return 0;
}

/*
 *  look for unused address space in 0xC8000 to 1 meg
 */
void
romscan(void)
{
	uchar *p;

	p = (uchar*)(KZERO+0xC8000);
	while(p < (uchar*)(KZERO+0xE0000)){
		p[0] = 0x55;
		p[1] = 0xAA;
		p[2] = 4;
		if(p[0] != 0x55 || p[1] != 0xAA){
			putisa(PADDR(p), 2048);
			p += 2048;
			continue;
		}
		p += p[2]*512;
	}

	p = (uchar*)(KZERO+0xE0000);
	if(p[0] != 0x55 || p[1] != 0xAA)
		putisa(PADDR(p), 64*1024);
}


void
confinit(void)
{
	long x, i, j, n;
	int pcnt;
	ulong ktop;
	char *cp;
	char *line[MAXCONF];

	pcnt = 0;

	/*
	 *  parse configuration args from dos file p9rc
	 */
	cp = BOOTARGS;	/* where b.com leaves plan9.ini */
	cp[BOOTARGSLEN-1] = 0;
	n = getfields(cp, line, MAXCONF, "\n");
	for(j = 0; j < n; j++){
		cp = strchr(line[j], '\r');
		if(cp)
			*cp = 0;
		cp = strchr(line[j], '=');
		if(cp == 0)
			continue;
		*cp++ = 0;
		if(cp - line[j] >= NAMELEN+1)
			*(line[j]+NAMELEN-1) = 0;
		confname[nconf] = line[j];
		confval[nconf] = cp;
		if(strcmp(confname[nconf], "kernelpercent") == 0)
			pcnt = 100 - atoi(confval[nconf]);
		nconf++;
	}
	/*
	 *  size memory above 1 meg. Kernel sits at 1 meg.  We
	 *  only recognize MB size chunks.
	 */
	memset(mmap, ' ', sizeof(mmap));
	x = 0x12345678;
	for(i = 1; i <= MAXMEG; i++){
		/*
		 *  write the first & last word in a megabyte of memory
		 */
		*mapaddr(KZERO|(i*MB)) = x;
		*mapaddr(KZERO|((i+1)*MB-BY2WD)) = x;

		/*
		 *  write the first and last word in all previous megs to
		 *  handle address wrap around
		 */
		for(j = 1; j < i; j++){
			*mapaddr(KZERO|(j*MB)) = ~x;
			*mapaddr(KZERO|((j+1)*MB-BY2WD)) = ~x;
		}

		/*
		 *  check for correct value
		 */
		if(*mapaddr(KZERO|(i*MB)) == x && *mapaddr(KZERO|((i+1)*MB-BY2WD)) == x){
			mmap[i] = 'x';
			/*
			 *  zero memory to set ECC but skip over the kernel
			 */
			if(i != 1)
				for(j = 0; j < MB/BY2PG; j += BY2PG)
					memset(mapaddr(KZERO|(i*MB+j)), 0, BY2PG);
		}
		x += 0x3141526;
	}
	/*
	 *  bank0 usually goes from the end of kernel bss to the end of memory
	 */
	ktop = PGROUND((ulong)end);
	ktop = PADDR(ktop);
	conf.base0 = ktop;
	for(i = 1; mmap[i] == 'x'; i++)
		;
	conf.npage0 = (i*MB - ktop)/BY2PG;
	conf.topofmem = i*MB;

	/*
	 *  bank1 usually goes from the end of BOOTARGS to 640k
	 */
	conf.base1 = (ulong)(BOOTARGS+BOOTARGSLEN);
	conf.base1 = PGROUND(conf.base1);
	conf.base1 = PADDR(conf.base1);
	conf.npage1 = (640*1024-conf.base1)/BY2PG;

	/*
	 *  if there is a hole in memory (due to a shadow BIOS) make the
	 *  memory after the hole be bank 1. The memory from 0 to 640k
	 *  is lost.
	 */
	for(; i <= MAXMEG; i++)
		if(mmap[i] == 'x'){
			conf.base1 = i*MB;
			for(j = i+1; mmap[j] == 'x'; j++)
				;
			conf.npage1 = (j - i)*MB/BY2PG;
			conf.topofmem = j*MB;
			break;
		}

	/*
 	 *  add address space holes holes under 16 meg to available
	 *  isa space.
	 */
	romscan();
	if(conf.topofmem < 16*MB)
		putisa(conf.topofmem, 16*MB - conf.topofmem);

	conf.npage = conf.npage0 + conf.npage1;
	conf.ldepth = 0;
	if(pcnt < 10)
		pcnt = 70;
	conf.upages = (conf.npage*pcnt)/100;

	conf.nproc = 30 + ((conf.npage*BY2PG)/MB)*8;
	conf.monitor = 1;
	conf.nswap = conf.nproc*80;
	conf.nimage = 50;
	switch(x86()){
	case 3:
		conf.copymode = 1;	/* copy on reference */
		break;
	default:
		conf.copymode = 0;	/* copy on write */
		break;
	}
	conf.nfloppy = 2;
	conf.nhard = 2;
	conf.nmach = 1;
}

char *mathmsg[] =
{
	"invalid",
	"denormalized",
	"div-by-zero",
	"overflow",
	"underflow",
	"precision",
	"stack",
	"error",
};

/*
 *  math coprocessor error
 */
void
matherror(Ureg *ur, void *a)
{
	ulong status;
	int i;
	char *msg;
	char note[ERRLEN];

	USED(a);

	/*
	 *  a write cycle to port 0xF0 clears the interrupt latch attached
	 *  to the error# line from the 387
	 */
	outb(0xF0, 0xFF);

	/*
	 *  save floating point state to check out error
	 */
	fpenv(&u->fpsave);
	status = u->fpsave.status;

	msg = 0;
	for(i = 0; i < 8; i++)
		if((1<<i) & status){
			msg = mathmsg[i];
			sprint(note, "sys: fp: %s fppc=0x%lux", msg, u->fpsave.pc);
			postnote(u->p, 1, note, NDebug);
			break;
		}
	if(msg == 0){
		sprint(note, "sys: fp: unknown fppc=0x%lux", u->fpsave.pc);
		postnote(u->p, 1, note, NDebug);
	}
	if(ur->pc & KZERO)
		panic("fp: status %lux fppc=0x%lux pc=0x%lux", status,
			u->fpsave.pc, ur->pc);
}

/*
 *  math coprocessor emulation fault
 */
void
mathemu(Ureg *ur, void *a)
{
	USED(ur, a);

	switch(u->p->fpstate){
	case FPinit:
		fpinit();
		u->p->fpstate = FPactive;
		break;
	case FPinactive:
		fprestore(&u->fpsave);
		u->p->fpstate = FPactive;
		break;
	case FPactive:
		panic("math emu", 0);
		break;
	}
}

/*
 *  math coprocessor segment overrun
 */
void
mathover(Ureg *ur, void *a)
{
	USED(ur, a);

print("sys: fp: math overrun pc 0x%lux pid %d\n", ur->pc, u->p->pid);
	pexit("math overrun", 0);
}

void
mathinit(void)
{
	setvec(Matherr1vec, matherror, 0);
	setvec(Matherr2vec, matherror, 0);
	setvec(Mathemuvec, mathemu, 0);
	setvec(Mathovervec, mathover, 0);
}

/*
 *  set up floating point for a new process
 */
void
procsetup(Proc *p)
{
	p->fpstate = FPinit;
	fpoff();
}

/*
 *  Save the mach dependent part of the process state.
 */
void
procsave(Proc *p)
{
	if(p->fpstate == FPactive){
		if(p->state == Moribund)
			fpoff();
		else
			fpsave(&u->fpsave);
		p->fpstate = FPinactive;
	}
}

/*
 *  Restore what procsave() saves
 */
void
procrestore(Proc *p)
{
	USED(p);
}


/*
 *  the following functions all are slightly different from
 *  PC to PC.
 */

/*
 *  reset the i387 chip
 */
void
exit(int ispanic)
{
	u = 0;
	wipekeys();
	print("exiting\n");
	if(ispanic){
		if(cpuserver)
			delay(10000);
		else
			for(;;);
	}

	(*arch->reset)();
}

/*
 *  set cpu speed
 *	0 == low speed
 *	1 == high speed
 */
int
cpuspeed(int speed)
{
	if(arch->cpuspeed)
		return (*arch->cpuspeed)(speed);
	else
		return 0;
}

/*
 *  f == frequency (Hz)
 *  d == duration (ms)
 */
void
buzz(int f, int d)
{
	if(arch->buzz)
		(*arch->buzz)(f, d);
}

/*
 *  each bit in val stands for a light
 */
void
lights(int val)
{
	if(arch->lights)
		(*arch->lights)(val);
}

/*
 *  power to serial port
 *	onoff == 1 means on
 *	onoff == 0 means off
 */
int
serial(int onoff)
{
	if(arch->serialpower)
		return (*arch->serialpower)(onoff);
	else
		return 0;
}

/*
 *  power to modem
 *	onoff == 1 means on
 *	onoff == 0 means off
 */
int
modem(int onoff)
{
	if(arch->modempower)
		return (*arch->modempower)(onoff);
	else
		return 0;
}

int
parseether(uchar *to, char *from)
{
	char nip[4];
	char *p;
	int i;

	p = from;
	while(*p == ' ')
		++p;
	for(i = 0; i < 6; i++){
		if(*p == 0)
			return -1;
		nip[0] = *p++;
		if(*p == 0)
			return -1;
		nip[1] = *p++;
		nip[2] = 0;
		to[i] = strtoul(nip, 0, 16);
		if(*p == ':')
			p++;
	}
	return 0;
}

int
isaconfig(char *class, int ctlrno, ISAConf *isa)
{
	char cc[NAMELEN], *p, *q;
	int n;

	sprint(cc, "%s%d", class, ctlrno);
	for(n = 0; n < nconf; n++){
		if(strncmp(confname[n], cc, NAMELEN))
			continue;
		p = confval[n];
		while(*p){
			while(*p == ' ' || *p == '\t')
				p++;
			if(*p == '\0')
				break;
			if(strncmp(p, "type=", 5) == 0){
				p += 5;
				for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){
					if(*p == '\0' || *p == ' ' || *p == '\t')
						break;
					*q = *p++;
				}
				*q = '\0';
			}
			else if(strncmp(p, "port=", 5) == 0)
				isa->port = strtoul(p+5, &p, 0);
			else if(strncmp(p, "irq=", 4) == 0)
				isa->irq = strtoul(p+4, &p, 0);
			else if(strncmp(p, "mem=", 4) == 0)
				isa->mem = strtoul(p+4, &p, 0);
			else if(strncmp(p, "size=", 5) == 0)
				isa->size = strtoul(p+5, &p, 0);
			else if(strncmp(p, "dma=", 4) == 0)
				isa->dma = strtoul(p+4, &p, 0);
			else if(strncmp(p, "ea=", 3) == 0){
				if(parseether(isa->ea, p+3) == -1)
					memset(isa->ea, 0, 6);
			}
			while(*p && *p != ' ' && *p != '\t')
				p++;
		}
		return 1;
	}
	return 0;
}

static void
pcfloppyintr(Ureg *ur, void *a)
{
	USED(a);

	floppyintr(ur);
}

void
floppysetup0(FController *fl)
{
	USED(fl);
}

void
floppysetup1(FController *fl)
{
	uchar equip;

	/*
	 *  read nvram for types of floppies 0 & 1
	 */
	equip = nvramread(0x10);
	if(conf.nfloppy > 0){
		fl->d[0].dt = (equip >> 4) & 0xf;
		floppysetdef(&fl->d[0]);
	}
	if(conf.nfloppy > 1){
		fl->d[1].dt = equip & 0xf;
		floppysetdef(&fl->d[1]);
	}

	setvec(Floppyvec, pcfloppyintr, 0);
}

/*
 *  eject disk ( unknown on safari )
 */
void
floppyeject(FDrive *dp)
{
	floppyon(dp);
	dp->vers++;
	floppyoff(dp);
}

int 
floppyexec(char *a, long b, int c)
{
	USED(a, b, c);
	return b;
}

int
cistrcmp(char *a, char *b)
{
	int ac, bc;

	for(;;){
		ac = *a++;
		bc = *b++;
	
		if(ac >= 'A' && ac <= 'Z')
			ac = 'a' + (ac - 'A');
		if(bc >= 'A' && bc <= 'Z')
			bc = 'a' + (bc - 'A');
		ac -= bc;
		if(ac)
			return ac;
		if(bc == 0)
			break;
	}
	return 0;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.