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

#include "u.h"
#include "lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

#include "dosfs.h"

typedef struct Type Type;
typedef struct Medium Medium;
typedef struct Mode Mode;

enum {
	Maxdev		= 7,
	Dany		= -1,
	Nmedia		= 16,
};

enum {					/* type */
	Tfloppy		= 0x00,
	Thard		= 0x01,
	Tscsi		= 0x02,
	Tether		= 0x03,
	NType		= 0x04,

	Tany		= -1,
};

enum {					/* flag and name */
	Fnone		= 0x00,

	Fdos		= 0x01,
	Ndos		= 0x00,
	Fboot		= 0x02,
	Nboot		= 0x01,
	Fbootp		= 0x04,
	Nbootp		= 0x02,
	NName		= 0x03,

	Fany		= Fbootp|Fboot|Fdos,

	Fini		= 0x10,
	Freverse	= 0x20,
	Fprobe		= 0x80,
};

enum {					/* mode */
	Mauto		= 0x00,
	Mlocal		= 0x01,
	Manual		= 0x02,
	NMode		= 0x03,
};

typedef struct Type {
	int	type;
	int	flag;
	int	(*init)(void);
	long	(*read)(int, void*, long);
	long	(*seek)(int, long);
	Partition* (*setpart)(int, char*);
	char*	name[NName];

	int	mask;
	Medium*	media;
} Type;

typedef struct Medium {
	Type*	type;
	int	flag;
	Partition* partition;
	Dos;

	Medium*	next;
} Medium;

typedef struct Mode {
	char*	name;
	int	mode;
} Mode;

static Type types[NType] = {
	{	Tfloppy,
		Fini|Fdos,
		floppyinit, floppyread, floppyseek, 0,
		{ "fd", }
	},
	{	Tether,
		Fbootp,
		etherinit, 0, 0, 0,
		{ 0, 0, "e", },
	},
	{	Thard,
		Fini|Fboot|Fdos,
		hardinit, hardread, hardseek, sethardpart,
		{ "hd", "h", },
	},
	{	Tscsi,
		Fini|Fboot|Fdos,
		scsiinit, scsiread, scsiseek, setscsipart,
		{ "sd", "s", },
	},
};

static Medium media[Nmedia];
static Medium *curmedium = media;

static Mode modes[NMode+1] = {
	[Mauto]		{ "auto",   Mauto,  },
	[Mlocal]	{ "local",  Mlocal, },
	[Manual]	{ "manual", Manual, },
};

static char *inis[] = {
	"plan9/plan9.ini",
	"plan9.ini",
	0,
};
char **ini;

static int
parse(char *line, int *type, int *flag, int *dev, char *file)
{
	Type *tp;
	char buf[2*NAMELEN], *v[4], *p;
	int i;

	strcpy(buf, line);
	switch(getfields(buf, v, 4, '!')){

	case 3:
		break;

	case 2:
		v[2] = "";
		break;

	default:
		return 0;
	}

	*flag = 0;
	for(tp = types; tp < &types[NType]; tp++){
		for(i = 0; i < NName; i++){

			if(tp->name[i] == 0 || strcmp(v[0], tp->name[i]))
				continue;
			*type = tp->type;
			*flag |= 1<<i;

			if((*dev = strtoul(v[1], &p, 0)) == 0 && p == v[1])
				return 0;
		
			strcpy(file, v[2]);
		
			return 1;
		}
	}

	return 0;

}

static int
boot(Medium *mp, int flag, char *file)
{
	Dosfile df;
	char ixdos[128], *p;

	if(flag & Fbootp){
		sprint(BOOTLINE, "%s!%d", mp->type->name[Nbootp], mp->dev);
		return bootp(mp->dev, file);
	}

	if(flag & Fboot){
		if(mp->flag & Fini){
			(*mp->type->setpart)(mp->dev, "disk");
			plan9ini(mp);
		}
		if(file == 0 || *file == 0)
			file = mp->partition->name;
		(*mp->type->setpart)(mp->dev, file);
		sprint(BOOTLINE, "%s!%d!%s", mp->type->name[Nboot], mp->dev, file);
		return plan9boot(mp->dev, mp->seek, mp->read);
	}

	if(flag & Fdos){
		if(mp->type->setpart)
			(*mp->type->setpart)(mp->dev, "disk");
		if(mp->flag & Fini)
			plan9ini(mp);
		if(file == 0 || *file == 0){
			strcpy(ixdos, *ini);
			if(p = strrchr(ixdos, '/'))
				p++;
			else
				p = ixdos;
			strcpy(p, "9dos");
			if(dosstat(mp, ixdos, &df) <= 0)
				return -1;
		}
		else
			strcpy(ixdos, file);
		sprint(BOOTLINE, "%s!%d!%s", mp->type->name[Ndos], mp->dev, ixdos);
		return dosboot(mp, ixdos);
	}

	return -1;
}

static Medium*
allocm(Type *tp)
{
	Medium **l;

	if(curmedium >= &media[Nmedia])
		return 0;

	for(l = &tp->media; *l; l = &(*l)->next)
		;
	*l = curmedium++;
	return *l;
}

Medium*
probe(int type, int flag, int dev)
{
	Type *tp;
	int d, i, m;
	Medium *mp;
	Dosfile df;

	for(tp = types; tp < &types[NType]; tp++){
		if(type != Tany && type != tp->type)
			continue;

		if(flag != Fnone){
			for(mp = tp->media; mp; mp = mp->next){
				if((flag & mp->flag) && (dev == Dany || dev == mp->dev))
					return mp;
			}
		}

		if((tp->flag & Fprobe) == 0){
			tp->flag |= Fprobe;
			tp->mask = (*tp->init)();
		}

		for(i = 0; tp->mask; i++){
			if(tp->flag & Freverse){
				m = 1<<(Maxdev-i);
				d = (Maxdev-i);
			}
			else{
				m = 1<<i;
				d = i;
			}
			if((tp->mask & m) == 0)
				continue;
			tp->mask &= ~m;

			if((mp = allocm(tp)) == 0)
				continue;

			mp->dev = d;
			mp->flag = tp->flag;
			mp->seek = tp->seek;
			mp->read = tp->read;
			mp->type = tp;

			if(mp->flag & Fboot){
				if((mp->partition = (*tp->setpart)(d, "boot")) == 0)
					mp->flag &= ~Fboot;
				(*tp->setpart)(d, "disk");
			}

			if((mp->flag & Fdos) && (dosinit(mp) < 0))
				mp->flag &= ~(Fini|Fdos);

			if(mp->flag & Fini){
				mp->flag &= ~Fini;
				for(ini = inis; *ini; ini++){
					if(dosstat(mp, *ini, &df) <= 0)
						continue;
					mp->flag |= Fini;
					break;
				}
			}

			if((flag & mp->flag) && (dev == Dany || dev == d))
				return mp;
		}
	}

	return 0;
}

void
main(void)
{
	Medium *mp;
	int dev, flag, i, mode, tried, type;
	char def[2*NAMELEN], file[2*NAMELEN], line[80], *p;
	Type *tp;

	i8042a20();
	memset(m, 0, sizeof(Mach));
	trapinit();
	clockinit();
	alarminit();
	spllo();

	if((ulong)&end > (KZERO|(640*1024)))
		panic("b.com too big\n");

	for(tp = types; tp < &types[NType]; tp++){
		if(tp->type == Tether)
			continue;
		if((mp = probe(tp->type, Fini, Dany)) && (mp->flag & Fini)){
			plan9ini(mp);
			break;
		}
	}

	consinit();

	/*
	 * If there were any arguments, MS-DOS leaves a character
	 * count followed by the arguments in the runtime header.
	 * Step over the leading space.
	 */
	p = (char*)0x80080080;
	if(p[0]){
		p[p[0]+1] = 0;
		p += 2;
	}
	else
		p = 0;

	tried = 0;
	mode = Mauto;
	if(p == 0)
		p = getconf("bootfile");

	if(p != 0) {
		mode = Manual;
		for(i = 0; i < NMode; i++){
			if(strcmp(p, modes[i].name) == 0){
				mode = modes[i].mode;
				goto done;
			}
		}
		if(parse(p, &type, &flag, &dev, file) == 0) {
			print("Bad bootfile syntax: %s\n", p);
			goto done;
		}
		mp = probe(type, flag, dev);
		if(mp == 0) {
			print("Cannot access device: %s\n", p);
			goto done;
		}
		tried = boot(mp, flag, file);
	}
done:
	if(tried == 0 && mode != Manual){
		flag = Fany;
		if(mode == Mlocal)
			flag &= ~Fbootp;
		if((mp = probe(Tany, flag, Dany)) && mp->type->type != Tfloppy)
			boot(mp, flag & mp->flag, 0);
	}

	def[0] = 0;
	probe(Tany, Fnone, Dany);
	if(mode != Manual && (mp = probe(Tfloppy, Fdos, Dany)))
		sprint(def, "%s!%d!9dos", mp->type->name[Ndos], mp->dev);

	flag = 0;
	for(tp = types; tp < &types[NType]; tp++){
		for(mp = tp->media; mp; mp = mp->next){
			if(flag == 0){
				flag = 1;
				print("Boot devices:");
			}
	
			if(mp->flag & Fbootp)
				print(" %s!%d", mp->type->name[Nbootp], mp->dev);
			if(mp->flag & Fdos)
				print(" %s!%d", mp->type->name[Ndos], mp->dev);
			if(mp->flag & Fboot)
				print(" %s!%d", mp->type->name[Nboot], mp->dev);
		}
	}
	if(flag)
		print("\n");

	for(;;){
		if(getstr("boot from", line, sizeof(line), def, def[0]!=0) >= 0){
			if(parse(line, &type, &flag, &dev, file)){
				if(mp = probe(type, flag, dev))
					boot(mp, flag, file);
			}
		}
		def[0] = 0;
	}
}

int
getfields(char *lp, char **fields, int n, char sep)
{
	int i;

	for(i=0; lp && *lp && i<n; i++){
		while(*lp == sep)
			*lp++=0;
		if(*lp == 0)
			break;
		fields[i]=lp;
		while(*lp && *lp != sep)
			lp++;
	}
	return i;
}

void*
ialloc(ulong n, int align)
{

	static struct {
		ulong	addr;
	} palloc;
	ulong p;

	if(palloc.addr == 0)
		palloc.addr = ((ulong)&end)&~KZERO;
	if(align)
		palloc.addr = PGROUND(palloc.addr);
	if((palloc.addr <= 640*1024) && (palloc.addr + n > 640*1024))
		palloc.addr = 2*1024*1024;

	memset((void*)(palloc.addr|KZERO), 0, n);
	p = palloc.addr;
	palloc.addr += n;
	if(align)
		palloc.addr = PGROUND(palloc.addr);

	return (void*)(p|KZERO);
}

enum {
	Paddr=		0x70,	/* address port */
	Pdata=		0x71,	/* data port */
};

uchar
nvramread(int offset)
{
	outb(Paddr, offset);
	return inb(Pdata);
}

unix.superglobalmegacorp.com

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