576 lines · 10.9 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * parse plan.ini or /cfg/pxe/%E file into low memory */#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h"#include	"ureg.h"#include	"pool.h"#include	"../port/netif.h"#include	"../ip/ip.h"#include	"pxe.h" typedef struct {	char*	name;	int	start;	int	end;} Mblock; typedef struct {	char*	tag;	Mblock*	mb;} Mitem; Chan *conschan; static Mblock mblock[MAXCONF];static int nmblock;static Mitem mitem[MAXCONF];static int nmitem;static char* mdefault;static char mdefaultbuf[10];static int mtimeout; static char*comma(char* line, char** residue){	char *q, *r; 	if((q = strchr(line, ',')) != nil){		*q++ = 0;		if(*q == ' ')			q++;	}	*residue = q; 	if((r = strchr(line, ' ')) != nil)		*r = 0; 	if(*line == ' ')		line++;	return line;} static Mblock*findblock(char* name, char** residue){	int i;	char *p; 	p = comma(name, residue);	for(i = 0; i < nmblock; i++){		if(strcmp(p, mblock[i].name) == 0)			return &mblock[i];	}	return nil;} static Mitem*finditem(char* name, char** residue){	int i;	char *p; 	p = comma(name, residue);	for(i = 0; i < nmitem; i++){		if(strcmp(p, mitem[i].mb->name) == 0)			return &mitem[i];	}	return nil;} /* timeout is in seconds */intgetstr(char *prompt, char *buf, int size, char *def, int timeout){	int len, isdefault;	static char pbuf[PRINTSIZE]; 	if(conschan == nil)		panic("getstr: #c/cons not open");	buf[0] = 0;	isdefault = (def && *def);	if(isdefault == 0){		timeout = 0;		snprint(pbuf, sizeof pbuf, "%s: ", prompt);	}	else if(timeout)		snprint(pbuf, sizeof pbuf, "%s[default==%s (%ds timeout)]: ",			prompt, def, timeout);	else		snprint(pbuf, sizeof pbuf, "%s[default==%s]: ", prompt, def);	for (;;) {		print("%s", pbuf);		if (timeout > 0) {			for(timeout *= 1000; timeout > 0; timeout -= 100) {				if (qlen(kbdq) > 0)	/* if input queued */					break; 				tsleep(&up->sleep, return0, 0, 100);			}			if (timeout <= 0) {		/* use default */				print("\n");				len = 0;				break;			}		}		buf[0] = '\0';		len = devtab[conschan->type]->read(conschan, buf, size - 1,			conschan->offset);		if(len >= 0)			buf[len] = '\0';		switch(len){		case 0:				/* eof */		case 1:				/* newline */			len = 0;			buf[len] = '\0';			if(!isdefault)				continue;			break;		}		if(len < size - 1)			break;		print("line too long\n");	}	if(len == 0 && isdefault)		strncpy(buf, def, size);	return 0;} voidaskbootfile(char *buf, int len, char **bootfp, int secs, char *def){	getstr("\nBoot from", buf, len, def, secs);	trimnl(buf);	if (bootfp)		kstrdup(bootfp, buf);} intisconf(char *name){	int i; 	for(i = 0; i < nconf; i++)		if(cistrcmp(confname[i], name) == 0)			return 1;	return 0;} /* result is not malloced, unlike user-mode getenv() */char*getconf(char *name){	int i, n, nmatch;	char buf[120]; 	nmatch = 0;	for(i = 0; i < nconf; i++)		if(cistrcmp(confname[i], name) == 0)			nmatch++; 	switch(nmatch) {	default:		print("\n");		nmatch = 0;		for(i = 0; i < nconf; i++)			if(cistrcmp(confname[i], name) == 0)				print("%d. %s\n", ++nmatch, confval[i]);		print("%d. none of the above\n", ++nmatch);		do {			getstr(name, buf, sizeof(buf), nil, 0);			n = atoi(buf);		} while(n < 1 || n > nmatch); 		for(i = 0; i < nconf; i++)			if(cistrcmp(confname[i], name) == 0)				if(--n == 0)					return confval[i];		break; 	case 1:		for(i = 0; i < nconf; i++)			if(cistrcmp(confname[i], name) == 0)				return confval[i];		break; 	case 0:		break;	}	return nil;} static voidparsemenu(char* str, char* scratch, int len){	Mitem *mi;	Mblock *mb, *menu;	char buf[20], *p, *q, *line[MAXCONF];	int i, inblock, n, show; 	inblock = 0;	menu = nil;	memmove(scratch, str, len);	n = getfields(scratch, line, MAXCONF, 0, "\n");	if(n >= MAXCONF)		print("warning: possibly too many lines in plan9.ini\n");	for(i = 0; i < n; i++){		p = line[i];		if(inblock && *p == '['){			mblock[nmblock].end = i;			if(strcmp(mblock[nmblock].name, "menu") == 0)				menu = &mblock[nmblock];			nmblock++;			inblock = 0;		}		if(*p == '['){			if(nmblock == 0 && i != 0){				mblock[nmblock].name = "common";				mblock[nmblock].start = 0;				mblock[nmblock].end = i;				nmblock++;			}			q = strchr(p+1, ']');			if(q == nil || *(q+1) != 0){				print("malformed menu block header - %s\n", p);				return;			}			*q = 0;			mblock[nmblock].name = p+1;			mblock[nmblock].start = i+1;			inblock = 1;		}	} 	if(inblock){		mblock[nmblock].end = i;		nmblock++;	}	if(menu == nil)		return;	if(nmblock < 2){		print("incomplete menu specification\n");		return;	} 	for(i = menu->start; i < menu->end; i++){		p = line[i];		if(cistrncmp(p, "menuitem=", 9) == 0){			p += 9;			if((mb = findblock(p, &q)) == nil){				print("no block for menuitem %s\n", p);				return;			}			if(q != nil)				mitem[nmitem].tag = q;			else				mitem[nmitem].tag = mb->name;			mitem[nmitem].mb = mb;			nmitem++;		}		else if(cistrncmp(p, "menudefault=", 12) == 0){			p += 12;			if((mi = finditem(p, &q)) == nil){				print("no item for menudefault %s\n", p);				return;			}			if(q != nil)				mtimeout = strtol(q, 0, 0);			snprint(mdefaultbuf, sizeof mdefaultbuf, "%ld",				mi-mitem+1);			mdefault = mdefaultbuf;		}		else if(cistrncmp(p, "menuconsole=", 12) == 0){			p += 12;			p = comma(p, &q);			i8250config(p);		}		else{			print("invalid line in [menu] block - %s\n", p);			return;		}	} again:	print("\nPlan 9 Startup Menu:\n====================\n");	for(i = 0; i < nmitem; i++)		print("    %d. %s\n", i+1, mitem[i].tag);	for(;;){		getstr("Selection", buf, sizeof(buf), mdefault, mtimeout);		mtimeout = 0;		i = strtol(buf, &p, 0)-1;		if(i < 0 || i >= nmitem)			goto again;		switch(*p){		case 'p':		case 'P':			show = 1;			print("\n");			break;		case 0:		case '\n':			show = 0;			break;		default:			continue;					}		mi = &mitem[i];			p = str;		p += snprint(p, len, "menuitem=%s\n", mi->mb->name);		for(i = 0; i < nmblock; i++){			mb = &mblock[i];			if(mi->mb != mb && cistrcmp(mb->name, "common") != 0)				continue;			for(n = mb->start; n < mb->end; n++)				p += snprint(p, &str[len] - p, "%s\n", line[n]);		} 		if(show){			for(q = str; q < p; q += i){				if((i = print(q)) <= 0)					break;			}			goto again;		}		break;	}	print("\n");} /* dig out tables created by l16r.s in real mode */voidreadlsconf(void){	int i, n;	uchar *p;	MMap *map;	u64int addr, len; 	/*	 * we could be running above 1MB, so put bios tables in low memory,	 * not after end.	 */	p = (uchar*)KADDR(BIOSTABLES);	for(n = 0; n < nelem(mmap); n++){		if(*p == 0)			break;		if(memcmp(p, "APM\0", 4) == 0){			p += 20;			continue;		}		else if(memcmp(p, "MAP\0", 4) == 0){			map = (MMap*)p; 			switch(map->type){			default:				if(v_flag)					print("type %ud", map->type);				break;			case 1:				if(v_flag)					print("Memory");				break;			case 2:				if(v_flag)					print("reserved");				break;			case 3:				if(v_flag)					print("ACPI Reclaim Memory");				break;			case 4:				if(v_flag)					print("ACPI NVS Memory");				break;			}			addr = (((u64int)map->base[1])<<32)|map->base[0];			len = (((u64int)map->length[1])<<32)|map->length[0];			if(v_flag)				print("\t%#16.16lluX %#16.16lluX (%llud)\n",					addr, addr+len, len); 			if(nmmap < nelem(mmap)){				memmove(&mmap[nmmap], map, sizeof(MMap));				mmap[nmmap].size = 20;				nmmap++;			}			p += 24;			continue;		}		else{			 /* ideally we shouldn't print here */			print("\nweird low-memory map at %#p:\n", p);			for(i = 0; i < 24; i++)				print(" %2.2uX", *(p+i));			print("\n");			delay(5000);		}		break;	}} voidaddconf(char *fmt, ...){	va_list arg; 	va_start(arg, fmt);	vseprint(BOOTARGS+strlen(BOOTARGS), BOOTARGS+BOOTARGSLEN, fmt, arg);	va_end(arg);} voiddumpbootargs(void){	char *p, *nl; 	/* in the boot, we can only print PRINTSIZE (256) bytes at a time. */	print("boot args: ");	for (p = (char *)BOOTARGS; *p != '\0'; p = nl) {		nl = strchr(p, '\n');		if (nl != nil) {			++nl;			print("%.*s", (int)(nl - p), p);		}	}} voidchangeconf(char *fmt, ...){	va_list arg;	char *p, *q, pref[20], buf[128]; 	va_start(arg, fmt);	vseprint(buf, buf+sizeof buf, fmt, arg);	va_end(arg); 	pref[0] = '\n';	strncpy(pref+1, buf, 19);	pref[19] = '\0';	if(p = strchr(pref, '='))		*(p+1) = '\0';	else		print("warning: did not change %s in plan9.ini\n", buf); 	/* find old line by looking for \nwhat= */	if(strncmp(BOOTARGS, pref+1, strlen(pref+1)) == 0)		p = BOOTARGS;	else if(p = strstr(BOOTARGS, pref))		p++;	else		p = nil; 	/* move rest of args up, deleting what= line. */	if(p != nil && (q = strchr(p, '\n')) != nil)		memmove(p, q+1, strlen(q+1)+1); 	/* add replacement to end */	addconf("%s", buf);} /* *  read configuration file */static char id[8] = "ZORT 0\r\n"; intdotini(char *inibuf){	int blankline, i, incomment, inspace, n;	char *cp, *p, *q, *line[MAXCONF]; 	cp = inibuf; 	/*	 * Strip out '\r', change '\t' -> ' '.	 * Change runs of spaces into single spaces.

Lines 1–500 of 576.