698 lines · 12.5 KB · C
RawDownload
#include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "sd.h"#include "fs.h" enum {	Datamagic = 0xcafebabe,}; /* * "cache" must be in this list so that 9load will pass the definition of * the cache partition into the kernel so that the disk named by the `cfs' * variable in plan9.ini can be seen in all circumstances before termrc * sets up all the disk partitions.  In particular, if it's on an odd-ball * disk like sd10 rather than sdC0, this is needed. * "nvram" is for the benefit of AoE clients. */static char *diskparts[] = {	"dos", "plan9", "9fat", "fs", "data", "cdboot", "cache", "nvram", 0};static char *etherparts[] = { "*", 0 }; static char *diskinis[] = {	"plan9/plan9.ini",	"plan9.ini",	0};static char *etherinis[] = {	"/cfg/pxe/%E",	0}; /* ordering: devbios must be called before devsd calls sdbios */Type types[] = {	{	Tfloppy,		Fini|Ffs,		floppyinit, floppyinitdev,		floppygetfspart, 0, floppyboot,		floppyprintdevs,		diskparts,		diskinis,	},	{	Tether,		Fini|Fbootp,		etherinit, etherinitdev,		pxegetfspart, 0, bootpboot,		etherprintdevs,		etherparts,		etherinis,	},	{	Tbios,		Fini|Ffs,		biosinit, biosinitdev,		biosgetfspart, nil, biosboot,		biosprintdevs,		diskparts,		diskinis,	},	{	Tcd,		Fini|Ffs,		cdinit, sdinitdev,		sdgetfspart, sdaddconf, sdboot,		sdprintdevs,		diskparts,		diskinis,	},	{	Tsd,		Fini|Ffs,		sdinit, sdinitdev,		sdgetfspart, sdaddconf, sdboot,		sdprintdevs,		diskparts,		diskinis,	},	{	Tnil,		0,		nil, nil, nil, nil, nil, nil,		nil,		nil,		0,		nil,	},}; static char *typenm[] = {	[Tnil]		"nil",	[Tfloppy]	"floppy",	[Tsd]		"sd",	[Tether]	"ether",	[Tcd]		"cd",	[Tbios]		"bios",}; extern SDifc sdataifc;extern SDifc sdiahciifc;extern SDifc sdaoeifc;extern SDifc sdbiosifc; extern SDifc sdmylexifc;extern SDifc sd53c8xxifc; SDifc* sdifc[] = {	&sdataifc,	&sdiahciifc,	&sdmylexifc,	&sd53c8xxifc,	&sdbiosifc,	&sdaoeifc,	nil,}; typedef struct Mode Mode; enum {	Maxdev		= 7,	Dany		= -1,	Nmedia		= 16,	Nini		= 10,}; enum {					/* mode */	Mauto		= 0x00,	Mlocal		= 0x01,	Manual		= 0x02,	NMode		= 0x03,}; typedef struct Medium Medium;struct Medium {	Type*	type;	int	flag;	int	dev;	char name[NAMELEN]; 	Fs *inifs;	char *part;	char *ini; 	Medium*	next;}; typedef struct Mode {	char*	name;	int	mode;} Mode; static Medium media[Nmedia];static Medium *curmedium = media; static Mode modes[NMode+1] = {	[Mauto]		{ "auto",   Mauto,  },	[Mlocal]	{ "local",  Mlocal, },	[Manual]	{ "manual", Manual, },}; char **ini; int scsi0port;char *defaultpartition; /* * Is it safe to probe the bios? * * Empirically, we can't touch any disks natively (not through the * bios) if we want to read them through the bios.  So we have to * choose bios (usb) loading or everything-else loading. */int biosload;int askbiosload; int iniread;int debugload;int vga;char *persist; static char *typename(int type){	if (type < 0 || type >= nelem(typenm) || typenm[type] == nil)		return "**gok**";	return typenm[type];} static Medium*parse(char *line, char **file){	char *p;	Type *tp;	Medium *mp; 	if(p = strchr(line, '!')) {		*p++ = 0;		*file = p;	} else		*file = ""; 	for(tp = types; tp->type != Tnil; tp++)		for(mp = tp->media; mp; mp = mp->next)			if(strcmp(mp->name, line) == 0)				return mp;	if(p)		*--p = '!';	return nil;} static intboot(Medium *mp, char *file){	Type *tp;	Medium *xmp;	static int didaddconf;	Boot b; 	memset(&b, 0, sizeof b);	b.state = INITKERNEL; 	if(didaddconf == 0) {		didaddconf = 1;		for(tp = types; tp->type != Tnil; tp++)			if(tp->addconf)				for(xmp = tp->media; xmp; xmp = xmp->next)					(*tp->addconf)(xmp->dev);	} 	sprint(BOOTLINE, "%s!%s", mp->name, file);//	print("booting %s!%s\n", mp->name, file);	return (*mp->type->boot)(mp->dev, file, &b);} 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 i;	Medium *mp;	File f;	Fs *fs;	char **partp; 	for(tp = types; tp->type != Tnil; 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 (debugload)			print("probing %s...", typename(tp->type));		if((tp->flag & Fprobe) == 0){			tp->flag |= Fprobe;			tp->mask = (*tp->init)();		} 		for(i = 0; tp->mask; i++){			if((tp->mask & (1<<i)) == 0)				continue;			tp->mask &= ~(1<<i); 			if((mp = allocm(tp)) == 0)				continue; 			mp->dev = i;			mp->flag = tp->flag;			mp->type = tp;			(*tp->initdev)(i, mp->name); 			if(mp->flag & Fini){				mp->flag &= ~Fini;				for(partp = tp->parts; *partp; partp++){					if((fs = (*tp->getfspart)(i, *partp, 0)) == nil)						continue; 					for(ini = tp->inis; *ini; ini++){						if(fswalk(fs, *ini, &f) > 0){							mp->inifs = fs;							mp->part = *partp;							mp->ini = f.path;							mp->flag |= Fini;							goto Break2;						}					}				}			}		Break2:			if((flag & mp->flag) && (dev == Dany || dev == i))				return mp;		}	} 	return 0;} voidmain(void){	Medium *mp;	int flag, i, mode, tried;	char def[2*NAMELEN], line[80], *p, *file;	Type *tp;	static ulong vfy = Datamagic; 	i8042a20();	memset(m, 0, sizeof(Mach));	trapinit();	clockinit();	alarminit();	meminit(0);	spllo(); 	/*	 * the soekris machines have no video but each has a serial port.	 * they must see serial output, if any, before cga output because	 * otherwise the soekris bios will translate cga output to serial	 * output, which will garble serial console output.	 */	pcimatch(nil, 0, 0);		/* force scan of pci table */	if (!vga) {		consinit("0", "9600");	/* e.g., for soekris debugging */		print("no vga; serial console only\n");	}	kbdinit();	if((ulong)&end > (KZERO|(640*1024)))		panic("i'm too big"); 	if (vfy != Datamagic)		panic("data segment incorrectly aligned or loaded");	if (!pxe)		/* TODO turning off debug and debugload makes loading fail */		debug = 1; 	/* this is too early for the non-soekris serial console, alas */	if (askbiosload) {		line[0] = '\0';		getstr("use bios drivers (e.g., for usb)", line, sizeof line,			"no", 60);		biosload = strncmp(line, "yes", 3) == 0;	} 	/*	 * find and read plan9.ini, setting configuration variables.	 */	if (debug)		print("plan9.ini probe...");	for(tp = types; tp->type != Tnil; tp++){		/*		 * we don't know which ether interface to use nor		 * whether bios loading is disabled until we have read		 * plan9.ini.  make an exception for 9pxeload: probe		 * ethers anyway.		 */		if(!pxe && tp->type == Tether /*|| !vga && tp->type == Tbios */)			continue;		if (debug)			print("probing %s...", typename(tp->type));		if((mp = probe(tp->type, Fini, Dany)) && (mp->flag & Fini)){			if (debug)				print("using %s!%s!%s\n",					mp->name, mp->part, mp->ini);			iniread = !dotini(mp->inifs);			break;		}	}	if (debug)		print("\n"); 	/*	 * we should now have read plan9.ini, if any.	 */	if (!iniread)		print("no plan9.ini\n"); 	persist = getconf("*bootppersist");	if (!pxe)		debug = 0;		/* stop the flood of output */	debugload = getconf("*debugload") != nil;	/*	 * !vga is a hack for soekris-like machines.	 * 9pxeload can't use bios int 13 calls; they wedge the machine.	 */	if(!vga || pxe || getconf("*nobiosload") != nil)		biosload = 0;	if((p = getconf("console")) != nil)		consinit(p, getconf("baud")); 	prcpuid();	readlsconf();	apminit();	print("bios (usb) loading %s\n", biosload? "enabled": "disabled"); 	devpccardlink();	devi82365link(); 	/* 	 * Even after we find the ini file, we keep probing disks,	 * because we have to collect the partition tables and	 * have boot devices for parse.	 */	probe(Tany, Fnone, Dany);	if (debugload)		print("end disk probe\n");	tried = 0;	mode = Mauto; 	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((mp = parse(p, &file)) == nil) {			print("Unknown boot device: %s\n", p);			goto done;		}		tried = boot(mp, 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, "");		if (debugload)			print("end auto-boot probe\n");	} 	def[0] = 0;	probe(Tany, Fnone, Dany);	if (debugload)		print("end final probe\n"); 	if(p = getconf("bootdef"))		strncpy(def, p, sizeof def); 	/* print possible boot methods */	flag = 0;	for(tp = types; tp->type != Tnil; tp++){		for(mp = tp->media; mp; mp = mp->next){			if(flag == 0){				flag = 1;				print("Boot devices:");			}			(*tp->printdevs)(mp->dev);		}	}	if(flag)		print("\n"); 	/*	 * e.g., *bootppersist=ether0	 *	 * previously, we looped in bootpopen if we were pxeload or if	 * *bootppersist was set.  that doesn't work well for pxeload	 * in configurations where bootp will never succeed on the first	 * interface but only on another interface.	 */	if (mode == Mauto && persist != nil &&	    (mp = parse(persist, &file)) != nil) {		boot(mp, file);		print("pausing before retry...");		delay(30*1000);		print("\n");	} 	for(;;){		if(getstr("boot from", line, sizeof(line), def, (mode != Manual)*15) >= 0)			if(mp = parse(line, &file))				boot(mp, file);		def[0] = 0;	}} intgetfields(char *lp, char **fields, int n, char sep){	int i;

Lines 1–500 of 698.