~kris/9p

9hist

076532721ebfd039d0341a2ade6afe0c70079d10 — David du Colombier 24 years ago 3179b98
Plan 9 from Bell Labs 2002-04-12
M bitsy/power.c => bitsy/power.c +2 -2
@@ 286,12 286,12 @@ idlehands(void)
	char *msga = "doze returns with splhi\n";

	if(!islo()){
		serialputs(msga, strlen(msga));
		uartputs(msga, strlen(msga));
		spllo();
	}
	doze();
	if(!islo()){
		serialputs(msgb, strlen(msgb));
		uartputs(msgb, strlen(msgb));
		spllo();
	}
}

M bitsy/uartsa1110.c => bitsy/uartsa1110.c +28 -24
@@ 80,7 80,6 @@ Uart sa1110uart[2] = {
	.special	= 0,
	.next		= nil, },
};
static Uart* consuart;
static Uart* µcuart;

#define R(p) ((Uartregs*)((p)->regs))


@@ 381,6 380,31 @@ sa1110_pnp(void)
	return sa1110uart;
}

static int
sa1110_getc(Uart *uart)
{
	Uartregs *ur;

	ur = uart->regs;
	while((ur->status[1] & Rnotempty) == 0)
		;
	return ur->data;
}

static void
sa1110_putc(Uart *uart, int c)
{
	Uartregs *ur;

	ur = uart->regs;
	/* wait for output ready */
	while((ur->status[1] & Tnotfull) == 0)
		;
	ur->data = c;
	while((ur->status[1] & Tbusy))
		;
}

PhysUart sa1110physuart = {
	.name=		"sa1110",
	.pnp= 		sa1110_pnp,


@@ 397,32 421,13 @@ PhysUart sa1110physuart = {
	.dtr=			sa1110_uartdtr,
	.status=		sa1110_uartstatus,
	.power=		sa1110_uartpower,
	.getc=		sa1110_getc,
	.putc=		sa1110_putc,
};

/*
 *  for iprint, just write it
 */
static void
sa1110puts(char *str, int n)
{
	Uartregs *ur;

	if(consuart == nil)
		return;
	ur = consuart->regs;
	while(n-- > 0){
		/* wait for output ready */
		while((ur->status[1] & Tnotfull) == 0)
			;
		ur->data = *str++;
	}
	while((ur->status[1] & Tbusy))
		;
}

/*
 *  for iprint, just write it
 */
void
serialµcputs(uchar *str, int n)
{


@@ 465,10 470,9 @@ sa1110_uartsetup(int console)
	/* set eia0 up as a console */
	if(console){
		uartctl(p, "b115200 l8 pn s1");
		consuart = p;
		(*p->phys->enable)(p, 0);
		serialputs = sa1110puts;
		p->console = 1;
		consuart = p;
	}
	intrenable(IRQ, IRQuart3, sa1110_uartintr, p, p->name);


M boot/boot.h => boot/boot.h +3 -0
@@ 64,6 64,9 @@ extern int	connectlocal(void);
extern void	configsac(Method*);
extern int	connectsac(void);

extern void	configpaq(Method*);
extern int	connectpaq(void);

extern void	configrc(Method*);
extern int	connectrc(void);


A boot/paq.c => boot/paq.c +67 -0
@@ 0,0 1,67 @@
#include <u.h>
#include <libc.h>
#include <../boot/boot.h>

char *fparts[] =
{
	"add bootldr	0x0000000 0x0040000",
	"add params	0x0040000 0x0080000",
	"add kernel	0x0080000 0x0140000",
	"add user	0x0140000 0x0200000",
	"add ramdisk	0x0200000 0x0800000",
};

void
configpaq(Method*)
{
	int fd;
	int i;

	if(bind("#F", "/dev", MAFTER) < 0)
		fatal("bind #c");
	if(bind("#p", "/proc", MREPL) < 0)
		fatal("bind #p");
	fd = open("/dev/flash/flashctl", OWRITE);
	if(fd < 0)
		fatal("opening flashctl");
	for(i = 0; i < nelem(fparts); i++)
		if(fprint(fd, fparts[i]) < 0)
			fatal(fparts[i]);
	close(fd);
}

int
connectpaq(void)
{
	int  p[2];
	char **arg, **argp;

	print("paq...");
	if(pipe(p)<0)
		fatal("pipe");
	switch(fork()){
	case -1:
		fatal("fork");
	case 0:
		arg = malloc(10*sizeof(char*));
		argp = arg;
		*argp++ = "paqfs";
		*argp++ = "-v";
		*argp++ = "-i";
		*argp++ = "/dev/flash/ramdisk";
		*argp = 0;

		dup(p[0], 0);
		dup(p[1], 1);
		close(p[0]);
		close(p[1]);
		exec("/paqfs", arg);
		fatal("can't exec paqfs");
	default:
		break;
	}
	waitpid();

	close(p[1]);
	return p[0];
}

M mtx/uarti8250.c => mtx/uarti8250.c +30 -42
@@ 146,8 146,6 @@ static Uart i8250uart[2] = {
	.next	= nil, },
};

static Uart* consuart;

#define csr8r(c, r)	inb((c)->io+(r))
#define csr8w(c, r, v)	outb((c)->io+(r), (c)->sticky[(r)]|(v))



@@ 560,6 558,31 @@ i8250pnp(void)
	return i8250uart;
}

static int
i8250getc(Uart *uart)
{
	Ctlr *ctlr;

	ctlr = uart->regs;
	while(!(csr8r(ctlr, Lsr)&Dr))
		delay(1);
	return csr8r(ctlr, Rbr);
}

static void
i8250putc(Uart *uart, int c)
{
	int i;
	Ctlr *ctlr;

	ctlr = uart->regs;
	for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
		delay(1);
	outb(ctlr->io+Thr, c);
	for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
		delay(1);
}

PhysUart i8250physuart = {
	.name		= "i8250",
	.pnp		= i8250pnp,


@@ 576,44 599,10 @@ PhysUart i8250physuart = {
	.dtr		= i8250dtr,
	.status		= i8250status,
	.fifo		= i8250fifo,
	.getc		= i8250getc,
	.putc		= i8250putc,
};

int
serialgetc(void)
{
	return -1;
}

static void
i8250putc(Ctlr* ctlr, int c)
{
	int i;

	for(i = 0; i < 128; i++){
		if(csr8r(ctlr, Lsr) & Thre)
			break;
		delay(1);
	}
	outb(ctlr->io+Thr, c);
}

static void
i8250puts(char* s, int n)
{
	Ctlr *ctlr;
	Uart *uart;

	if((uart = consuart) == nil)
		return;

	ctlr = uart->regs;
	while(n--){
		if(*s == '\n')
			i8250putc(ctlr, '\r');
		i8250putc(ctlr, *s++);
	}
}

void
i8250console(void)
{


@@ 637,12 626,11 @@ i8250console(void)
		break;	
	}

	if(*cmd == 0)
		cmd = "b9600 l8 pn s1";
	uartctl(uart, cmd);
	uartctl(uart, "b9600 l8 pn s1");
	if(*cmd != '\0')
		uartctl(uart, cmd);
	(*uart->phys->enable)(uart, 0);

	consuart = uart;
	serialputs = i8250puts;
	uart->console = 1;
} 

M pc/dat.h => pc/dat.h +3 -2
@@ 147,12 147,12 @@ struct Segdesc

struct Mach
{
	int	machno;			/* physical id of processor */
	int	machno;			/* physical id of processor (KNOWN TO ASSEMBLY) */
	ulong	splpc;			/* pc of last caller to splhi */

	ulong*	pdb;			/* page directory base for this processor (va) */
	Tss*	tss;			/* tss for this processor */
	Segdesc	gdt[NGDT];			/* gdt for this processor */
	Segdesc	*gdt;			/* gdt for this processor */

	Proc*	proc;			/* current process on this processor */
	Proc*	externup;		/* extern register Proc *up */


@@ 191,6 191,7 @@ struct Mach
	char	cpuidid[16];
	char*	cpuidtype;
	int	havetsc;
	int	havepge;

	vlong	mtrrcap;
	vlong	mtrrdef;

M pc/devarch.c => pc/devarch.c +59 -8
@@ 623,26 623,26 @@ cpuidentify(void)
{
	char *p;
	int family, model, nomce;
	X86type *t;
	X86type *t, *tab;
	ulong cr4;
	vlong mca, mct;

	cpuid(m->cpuidid, &m->cpuidax, &m->cpuiddx);
	if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0)
		t = x86amd;
		tab = x86amd;
	else if(strncmp(m->cpuidid, "CentaurHauls", 12) == 0)
		t = x86winchip;
		tab = x86winchip;
	else
		t = x86intel;
		tab = x86intel;
	
	family = X86FAMILY(m->cpuidax);
	model = X86MODEL(m->cpuidax);
	while(t->name){
	for(t=tab; t->name; t++)
		if((t->family == family && t->model == model)
		|| (t->family == family && t->model == -1)
		|| (t->family == -1))
			break;
		t++;
	}

	m->cpuidtype = t->name;

	/*


@@ 682,10 682,31 @@ cpuidentify(void)
			rdmsr(0x01, &mct);
	}

	if(t->family >= 6){
	/*
	 * Detect whether the chip supports the global bit
	 * in page directory and page table entries.  When set
	 * in a particular entry, it means ``don't bother removing
	 * this from the TLB when CR3 changes.''  
	 * 
	 * We flag all kernel pages with this bit.  Doing so lessens the
	 * overhead of switching processes on bare hardware,
	 * even more so on VMware.  See mmu.c:/^memglobal.
	 *
	 * This feature exists on Intel Pentium Pro and later
	 * processors.  Presumably the AMD processors have
	 * a similar notion, but I can't find it in the meager
	 * documentation I've tried.
	 *
	 * For future reference, should we ever need to do a
	 * full TLB flush, it can be accomplished by clearing
	 * the PGE bit in CR4, writing to CR3, and then
	 * restoring the PGE bit.
	 */
	if(tab==x86intel && t->family >= 6){
		cr4 = getcr4();
		cr4 |= 0x80;		/* page global enable bit */
		putcr4(cr4);
		m->havepge = 1;
	}

	cputype = t;


@@ 704,6 725,35 @@ cputyperead(Chan*, void *a, long n, vlong offset)
	return readstr(offset, a, n, str);
}

static long
pgewrite(Chan*, void *a, long n, vlong)
{
	if(!m->havepge)
		error("processor does not support pge");

	if(n==3 && memcmp(a, "off", 3)==0){
		putcr4(getcr4() & ~0x80);
		return n;
	}
	if(n==2 && memcmp(a, "on", 2)==0){
		putcr4(getcr4() | 0x80);
		return n;
	}
	error("invalid control message");
	return -1;
}

static long
pgeread(Chan*, void *a, long n, vlong offset)
{
	if(n < 16)
		error("need more room");
	if(offset)
		return 0;
	n = snprint(a, n, "%s pge; %s", m->havepge ? "have" : "no", getcr4()&0x80 ? "on" : "off");
	return n;
}

void
archinit(void)
{


@@ 742,6 792,7 @@ archinit(void)
		conf.copymode = 1;

	addarchfile("cputype", 0444, cputyperead, nil);
	addarchfile("pge", 0664, pgeread, pgewrite);
}

/*

M pc/main.c => pc/main.c +4 -1
@@ 117,6 117,7 @@ mach0init(void)
	conf.nmach = 1;
	MACHP(0) = (Mach*)CPU0MACH;
	m->pdb = (ulong*)CPU0PDB;
	m->gdt = (Segdesc*)CPU0GDT;

	machinit();



@@ 129,12 130,15 @@ machinit(void)
{
	int machno;
	ulong *pdb;
	Segdesc *gdt;

	machno = m->machno;
	pdb = m->pdb;
	gdt = m->gdt;
	memset(m, 0, sizeof(Mach));
	m->machno = machno;
	m->pdb = pdb;
	m->gdt = gdt;

	/*
	 * For polled uart output at boot, need


@@ 561,7 565,6 @@ procsave(Proc *p)
	}

	/*
	 * Switch to the prototype page tables for this processor.
	 * While this processor is in the scheduler, the process could run
	 * on another processor and exit, returning the page tables to
	 * the free list where they could be reallocated and overwritten.

M pc/mem.h => pc/mem.h +53 -47
@@ 6,18 6,18 @@
 * Sizes
 */
#define	BI2BY		8			/* bits per byte */
#define BI2WD		32			/* bits per word */
#define	BI2WD		32			/* bits per word */
#define	BY2WD		4			/* bytes per word */
#define	BY2V		8			/* bytes per double word */
#define	BY2PG		4096			/* bytes per page */
#define	WD2PG		(BY2PG/BY2WD)		/* words per page */
#define	PGSHIFT		12			/* log(BY2PG) */
#define ROUND(s, sz)	(((s)+((sz)-1))&~((sz)-1))
#define PGROUND(s)	ROUND(s, BY2PG)
#define BLOCKALIGN	8
#define	ROUND(s, sz)	(((s)+((sz)-1))&~((sz)-1))
#define	PGROUND(s)	ROUND(s, BY2PG)
#define	BLOCKALIGN	8

#define	MAXMACH		8			/* max # cpus system can run */
#define KSTACK		4096			/* Size of kernel stack */
#define	KSTACK		4096			/* Size of kernel stack */

/*
 * Time


@@ 29,15 29,21 @@
/*
 * Fundamental addresses
 */
#define IDTADDR		0x80000800		/* idt */
#define	IDTADDR		0x80000800		/* idt */
#define	REBOOTADDR	0x00001000		/* reboot code - physical address */
#define APBOOTSTRAP	0x80001000		/* AP bootstrap code */
#define CONFADDR	0x80001200		/* info passed from boot loader */
#define CPU0PDB		0x80002000		/* bootstrap processor PDB */
#define CPU0PTE		0x80003000		/* bootstrap processor PTE's for 0-4MB */
#define MACHADDR	0x80004000		/* as seen by current processor */
#define CPU0MACH	0x80005000		/* Mach for bootstrap processor */
#define	APBOOTSTRAP	0x80001000		/* AP bootstrap code */
#define	CONFADDR	0x80001200		/* info passed from boot loader */
#define	CPU0PDB		0x80002000		/* bootstrap processor PDB */
#define	CPU0PTE		0x80003000		/* bootstrap processor PTE's for 0-4MB */
#define	CPU0GDT		0x80004000		/* bootstrap processor GDT */
#define	MACHADDR	0x80005000		/* as seen by current processor */
#define	CPU0MACH	0x80006000		/* Mach for bootstrap processor */
#define	MACHSIZE	BY2PG
/*
 * N.B.  ramscan knows that CPU0MACH+BY2PG is the end of reserved data
 * N.B.  _start0x00100020 knows that CPU0PDB is the first reserved page
 * and that there are 5 of them.
 */

/*
 *  Address spaces


@@ 52,7 58,7 @@
#define	USTKTOP		(KZERO-BY2PG)		/* byte just beyond user stack */
#define	USTKSIZE	(16*1024*1024)		/* size of user stack */
#define	TSTKTOP		(USTKTOP-USTKSIZE)	/* end of new stack in sysexec */
#define TSTKSIZ 	100
#define	TSTKSIZ 	100

/*
 *  known x86 segments (in GDT) and their selectors


@@ 62,57 68,57 @@
#define	KESEG	2	/* kernel executable */	
#define	UDSEG	3	/* user data/stack */
#define	UESEG	4	/* user executable */
#define TSSSEG	5	/* task segment */
#define	TSSSEG	5	/* task segment */
#define	APMCSEG		6	/* APM code segment */
#define	APMCSEG16	7	/* APM 16-bit code segment */
#define	APMDSEG		8	/* APM data segment */
#define NGDT		10	/* number of GDT entries required */
#define	NGDT		10	/* number of GDT entries required */
/* #define	APM40SEG	8	/* APM segment 0x40 */

#define SELGDT	(0<<2)	/* selector is in gdt */
#define	SELGDT	(0<<2)	/* selector is in gdt */
#define	SELLDT	(1<<2)	/* selector is in ldt */

#define SELECTOR(i, t, p)	(((i)<<3) | (t) | (p))
#define	SELECTOR(i, t, p)	(((i)<<3) | (t) | (p))

#define NULLSEL	SELECTOR(NULLSEG, SELGDT, 0)
#define KDSEL	SELECTOR(KDSEG, SELGDT, 0)
#define KESEL	SELECTOR(KESEG, SELGDT, 0)
#define UESEL	SELECTOR(UESEG, SELGDT, 3)
#define UDSEL	SELECTOR(UDSEG, SELGDT, 3)
#define TSSSEL	SELECTOR(TSSSEG, SELGDT, 0)
#define APMCSEL 	SELECTOR(APMCSEG, SELGDT, 0)
#define APMCSEL16	SELECTOR(APMCSEG16, SELGDT, 0)
#define APMDSEL		SELECTOR(APMDSEG, SELGDT, 0)
/* #define APM40SEL	SELECTOR(APM40SEG, SELGDT, 0) */
#define	NULLSEL	SELECTOR(NULLSEG, SELGDT, 0)
#define	KDSEL	SELECTOR(KDSEG, SELGDT, 0)
#define	KESEL	SELECTOR(KESEG, SELGDT, 0)
#define	UESEL	SELECTOR(UESEG, SELGDT, 3)
#define	UDSEL	SELECTOR(UDSEG, SELGDT, 3)
#define	TSSSEL	SELECTOR(TSSSEG, SELGDT, 0)
#define	APMCSEL 	SELECTOR(APMCSEG, SELGDT, 0)
#define	APMCSEL16	SELECTOR(APMCSEG16, SELGDT, 0)
#define	APMDSEL		SELECTOR(APMDSEG, SELGDT, 0)
/* #define	APM40SEL	SELECTOR(APM40SEG, SELGDT, 0) */

/*
 *  fields in segment descriptors
 */
#define SEGDATA	(0x10<<8)	/* data/stack segment */
#define SEGEXEC	(0x18<<8)	/* executable segment */
#define	SEGDATA	(0x10<<8)	/* data/stack segment */
#define	SEGEXEC	(0x18<<8)	/* executable segment */
#define	SEGTSS	(0x9<<8)	/* TSS segment */
#define SEGCG	(0x0C<<8)	/* call gate */
#define	SEGCG	(0x0C<<8)	/* call gate */
#define	SEGIG	(0x0E<<8)	/* interrupt gate */
#define SEGTG	(0x0F<<8)	/* trap gate */
#define SEGTYPE	(0x1F<<8)
#define	SEGTG	(0x0F<<8)	/* trap gate */
#define	SEGTYPE	(0x1F<<8)

#define SEGP	(1<<15)		/* segment present */
#define SEGPL(x) ((x)<<13)	/* priority level */
#define SEGB	(1<<22)		/* granularity 1==4k (for expand-down) */
#define SEGG	(1<<23)		/* granularity 1==4k (for other) */
#define SEGE	(1<<10)		/* expand down */
#define SEGW	(1<<9)		/* writable (for data/stack) */
#define	SEGP	(1<<15)		/* segment present */
#define	SEGPL(x) ((x)<<13)	/* priority level */
#define	SEGB	(1<<22)		/* granularity 1==4k (for expand-down) */
#define	SEGG	(1<<23)		/* granularity 1==4k (for other) */
#define	SEGE	(1<<10)		/* expand down */
#define	SEGW	(1<<9)		/* writable (for data/stack) */
#define	SEGR	(1<<9)		/* readable (for code) */
#define SEGD	(1<<22)		/* default 1==32bit (for code) */
#define	SEGD	(1<<22)		/* default 1==32bit (for code) */

/*
 *  virtual MMU
 */
#define PTEMAPMEM	(1024*1024)	
#define	PTEMAPMEM	(1024*1024)	
#define	PTEPERTAB	(PTEMAPMEM/BY2PG)
#define SEGMAPSIZE	1984
#define SSEGMAPSIZE	16
#define PPN(x)		((x)&~(BY2PG-1))
#define	SEGMAPSIZE	1984
#define	SSEGMAPSIZE	16
#define	PPN(x)		((x)&~(BY2PG-1))

/*
 *  physical MMU


@@ 120,7 126,7 @@
#define	PTEVALID	(1<<0)
#define	PTEWT		(1<<3)
#define	PTEUNCACHED	(1<<4)
#define 	PTEWRITE	(1<<1)
#define	PTEWRITE	(1<<1)
#define	PTERONLY	(0<<1)
#define	PTEKERNEL	(0<<2)
#define	PTEUSER		(1<<2)


@@ 131,7 137,7 @@
 * Macros for calculating offsets within the page directory base
 * and page tables. 
 */
#define PDX(va)		((((ulong)(va))>>22) & 0x03FF)
#define PTX(va)		((((ulong)(va))>>12) & 0x03FF)
#define	PDX(va)		((((ulong)(va))>>22) & 0x03FF)
#define	PTX(va)		((((ulong)(va))>>12) & 0x03FF)

#define getpgcolor(a)	0
#define	getpgcolor(a)	0

M pc/memory.c => pc/memory.c +8 -0
@@ 425,6 425,14 @@ ramscan(ulong maxmem)
		mmuflushtlb(PADDR(m->pdb));
		x += 0x3141526;
	}

	/*
	 * If we didn't reach the end of the 4MB chunk, that part won't
	 * be mapped.  Commit the already initialised space for the page table.
	 */
	if(pa % (4*MB))
		map = 0;

	if(map)
		mapfree(&rmapram, map, BY2PG);
	if(pa < maxmem)

M pc/mmu.c => pc/mmu.c +62 -14
@@ 36,19 36,45 @@ taskswitch(ulong pdb, ulong stack)
	putcr3(pdb);
}

void
gdtinit(void)
/* 
 * On processors that support it, we set the PTEGLOBAL bit in
 * page table and page directory entries that map kernel memory.
 * Doing this tells the processor not to bother flushing them
 * from the TLB when doing the TLB flush associated with a 
 * context switch (write to CR3).  Since kernel memory mappings
 * are never removed, this is safe.  (If we ever remove kernel memory
 * mappings, we can do a full flush by turning off the PGE bit in CR4,
 * writing to CR3, and then turning the PGE bit back on.) 
 *
 * See also mmukmap below.
 * 
 * Processor support for the PTEGLOBAL bit is enabled in devarch.c.
 */
static void
memglobal(void)
{
	ulong x;
	ushort ptr[3];

	memmove(m->gdt, gdt, sizeof(m->gdt));

	ptr[0] = sizeof(m->gdt)-1;
	x = (ulong)m->gdt;
	ptr[1] = x & 0xFFFF;
	ptr[2] = (x>>16) & 0xFFFF;
	lgdt(ptr);
	int i, j;
	ulong *pde, *pte;

	/* only need to do this once, on bootstrap processor */
	if(m->machno != 0)
		return;

	if(!m->havepge)
		return;

	pde = m->pdb;
	for(i=512; i<1024; i++){	/* 512: start at entry for virtual 0x80000000 */
		if(pde[i] & PTEVALID){
			pde[i] |= PTEGLOBAL;
			if(!(pde[i] & PTESIZE)){
				pte = KADDR(pde[i]&~(BY2PG-1));
				for(j=0; j<1024; j++)
					if(pte[j] & PTEVALID)
						pte[j] |= PTEGLOBAL;
			}
		}
	}			
}

void


@@ 57,15 83,27 @@ mmuinit(void)
	ulong x, *p;
	ushort ptr[3];

	memglobal();

	m->tss = malloc(sizeof(Tss));
	memset(m->tss, 0, sizeof(Tss));

	memmove(m->gdt, gdt, sizeof(m->gdt));
	/*
	 * We used to keep the GDT in the Mach structure, but it
	 * turns out that that slows down access to the rest of the
	 * page.  Since the Mach structure is accessed quite often,
	 * it pays off anywhere from a factor of 1.25 to 2 on real
	 * hardware to separate them (the AMDs are more sensitive
	 * than Intels in this regard).  Under VMware it pays off
	 * a factor of about 10 to 100.
	 */

	memmove(m->gdt, gdt, sizeof gdt);
	x = (ulong)m->tss;
	m->gdt[TSSSEG].d0 = (x<<16)|sizeof(Tss);
	m->gdt[TSSSEG].d1 = (x&0xFF000000)|((x>>16)&0xFF)|SEGTSS|SEGPL(0)|SEGP;

	ptr[0] = sizeof(m->gdt)-1;
	ptr[0] = sizeof(gdt)-1;
	x = (ulong)m->gdt;
	ptr[1] = x & 0xFFFF;
	ptr[2] = (x>>16) & 0xFFFF;


@@ 395,14 433,24 @@ mmukmap(ulong pa, ulong va, int size)
		 * starts on a 4MB boundary, size >= 4MB and processor can do it.
		 * If not a big page, walk the walk, talk the talk.
		 * Sync is set.
		 *
		 * If we're creating a kernel mapping, we know that it will never
		 * expire and thus we can set the PTEGLOBAL bit to make the entry
	 	 * persist in the TLB across flushes.  If we do add support later for
		 * unmapping kernel addresses, see devarch.c for instructions on
		 * how to do a full TLB flush.
		 */
		if(pse && (pa % (4*MB)) == 0 && (pae >= pa+4*MB)){
			*table = pa|PTESIZE|PTEWRITE|PTEUNCACHED|PTEVALID;
			if((va&KZERO) && m->havepge)
				*table |= PTEGLOBAL;
			pgsz = 4*MB;
		}
		else{
			pte = mmuwalk(mach0->pdb, va, 2, 1);
			*pte = pa|PTEWRITE|PTEUNCACHED|PTEVALID;
			if((va&KZERO) && m->havepge)
				*pte |= PTEGLOBAL;
			pgsz = BY2PG;
		}
		pa += pgsz;

M pc/mp.c => pc/mp.c +7 -1
@@ 390,7 390,7 @@ mpstartap(Apic* apic)
	 * the PTE for the Mach structure.
	 * Xspanalloc will panic if an allocation can't be made.
	 */
	p = xspanalloc(3*BY2PG, BY2PG, 0);
	p = xspanalloc(4*BY2PG, BY2PG, 0);
	pdb = (ulong*)p;
	memmove(pdb, mach0->pdb, BY2PG);
	p += BY2PG;


@@ 399,17 399,23 @@ mpstartap(Apic* apic)
		return;
	memmove(p, KADDR(PPN(*pte)), BY2PG);
	*pte = PADDR(p)|PTEWRITE|PTEVALID;
	if(mach0->havepge)
		*pte |= PTEGLOBAL;
	p += BY2PG;

	mach = (Mach*)p;
	if((pte = mmuwalk(pdb, MACHADDR, 2, 0)) == nil)
		return;
	*pte = PADDR(mach)|PTEWRITE|PTEVALID;
	if(mach0->havepge)
		*pte |= PTEGLOBAL;
	p += BY2PG;

	machno = apic->machno;
	MACHP(machno) = mach;
	mach->machno = machno;
	mach->pdb = pdb;
	mach->gdt = (Segdesc*)p;	/* filled by mmuinit */

	/*
	 * Tell the AP where its kernel vector and pdb are.

M pc/trap.c => pc/trap.c +7 -2
@@ 439,10 439,15 @@ _dumpstack(Ureg *ureg)

	print("ktrace /kernel/path %.8lux %.8lux\n", ureg->pc, ureg->sp);
	i = 0;
	if(up)
	if(up
	&& (ulong)&l >= (ulong)up->kstack
	&& (ulong)&l <= (ulong)up->kstack+KSTACK)
		estack = (ulong)up->kstack+KSTACK;
	else
	else if((ulong)&l >= (ulong)m->stack
	&& (ulong)&l <= (ulong)m+BY2PG)
		estack = (ulong)m+MACHSIZE;
	else
		return;

	for(l=(ulong)&l; l<estack; l+=4){
		v = *(ulong*)l;

M pc/uarti8250.c => pc/uarti8250.c +27 -39
@@ 146,8 146,6 @@ static Uart i8250uart[2] = {
	.next	= nil, },
};

static Uart* consuart;

#define csr8r(c, r)	inb((c)->io+(r))
#define csr8w(c, r, v)	outb((c)->io+(r), (c)->sticky[(r)]|(v))



@@ 597,6 595,31 @@ i8250pnp(void)
	return i8250uart;
}

static int
i8250getc(Uart *uart)
{
	Ctlr *ctlr;

	ctlr = uart->regs;
	while(!(csr8r(ctlr, Lsr)&Dr))
		delay(1);
	return csr8r(ctlr, Rbr);
}

static void
i8250putc(Uart *uart, int c)
{
	int i;
	Ctlr *ctlr;

	ctlr = uart->regs;
	for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
		delay(1);
	outb(ctlr->io+Thr, c);
	for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
		delay(1);
}

PhysUart i8250physuart = {
	.name		= "i8250",
	.pnp		= i8250pnp,


@@ 613,44 636,10 @@ PhysUart i8250physuart = {
	.dtr		= i8250dtr,
	.status		= i8250status,
	.fifo		= i8250fifo,
	.getc		= i8250getc,
	.putc		= i8250putc,
};

int
serialgetc(void)
{
	return -1;
}

static void
i8250putc(Ctlr* ctlr, int c)
{
	int i;

	for(i = 0; i < 128; i++){
		if(csr8r(ctlr, Lsr) & Thre)
			break;
		delay(1);
	}
	outb(ctlr->io+Thr, c);
}

static void
i8250puts(char* s, int n)
{
	Ctlr *ctlr;
	Uart *uart;

	if((uart = consuart) == nil)
		return;

	ctlr = uart->regs;
	while(n--){
		if(*s == '\n')
			i8250putc(ctlr, '\r');
		i8250putc(ctlr, *s++);
	}
}

void
i8250console(void)
{


@@ 680,6 669,5 @@ i8250console(void)
	(*uart->phys->enable)(uart, 0);

	consuart = uart;
	serialputs = i8250puts;
	uart->console = 1;
} 

M port/devaudio.c => port/devaudio.c +18 -0
@@ 745,6 745,17 @@ audioinit(void)
		print("#A: bad port 0x%lux\n", sbconf.port);
		return;
	}

	if(ioalloc(sbconf.port, 0x10, 0, "audio") < 0){
		print("#A: cannot ioalloc range %x+0x10\n", sbconf.port);
		return;
	}
	if(ioalloc(sbconf.port+0x100, 1, 0, "audio.mpu401") < 0){
		iofree(sbconf.port);
		print("#A: cannot ioalloc range %x+0x01\n", sbconf.port+0x100);
		return;
	}

	switch(sbconf.irq){
	case 2:
	case 5:


@@ 754,6 765,8 @@ audioinit(void)
		break;
	default:
		print("#A: bad irq %lud\n", sbconf.irq);
		iofree(sbconf.port);
		iofree(sbconf.port+0x100);
		return;
	}



@@ 783,6 796,8 @@ audioinit(void)
	i = sbread();
	if(i != 0xaa) {
		print("#A: no response #%.2x\n", i);
		iofree(sbconf.port);
		iofree(sbconf.port+0x100);
		return;
	}



@@ 794,6 809,8 @@ audioinit(void)
		if(audio.major != 3 || audio.minor != 1 || ess1688(&sbconf)){
			print("#A: model 0x%.2x 0x%.2x; not SB 16 compatible\n",
				audio.major, audio.minor);
			iofree(sbconf.port);
			iofree(sbconf.port+0x100);
			return;
		}
		audio.major = 4;


@@ 821,6 838,7 @@ audioinit(void)
		(sbconf.irq==9)? 1:
		(sbconf.irq==10)? 8:
		0);

	mxcmd(0x81, 1<<blaster.dma);	/* dma */

	x = mxread(0x81);

M port/devcons.c => port/devcons.c +4 -8
@@ 9,7 9,6 @@

void	(*consdebug)(void) = nil;
void	(*screenputs)(char*, int) = nil;
void	(*serialputs)(char*, int) = nil;

Queue*	kbdq;			/* unprocessed console input */
Queue*	lineq;			/* processed console input */


@@ 121,8 120,7 @@ putstrn0(char *str, int n, int usewrite)
		screenputs(str, n);

	if(serialoq == nil){
		if(serialputs != nil)
			serialputs(str, n);
		uartputs(str, n);
		return;
	}



@@ 188,8 186,7 @@ iprint(char *fmt, ...)
	va_end(arg);
	if(screenputs != nil && iprintscreenputs)
		screenputs(buf, n);
	if(serialputs != nil)
		serialputs(buf, n);
	uartputs(buf, n);
	splx(s);

	return n;


@@ 215,10 212,9 @@ panic(char *fmt, ...)
	n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
	va_end(arg);
	buf[n] = '\n';
	if(serialputs != nil)
		serialputs(buf, n+1);
	uartputs(buf, n+1);
	if(consdebug)
		consdebug();
		(*consdebug)();
	spllo();
	prflush();
	putstrn(buf, n+1);

M port/devuart.c => port/devuart.c +38 -0
@@ 650,3 650,41 @@ uartclock(void)
		}
	}
}

/*
 * polling console input, output
 */

Uart* consuart;

int
uartgetc(void)
{
	if(consuart == nil || consuart->phys->getc == nil)
		return -1;
	return consuart->phys->getc(consuart);
}

void
uartputc(int c)
{
	if(consuart == nil || consuart->phys->putc == nil)
		return;
	consuart->phys->putc(consuart, c);
}

void
uartputs(char *s, int n)
{
	char *e;

	if(consuart == nil || consuart->phys->putc == nil)
		return;

	e = s+n;
	for(; s<e; s++){
		if(*s == '\n')
			consuart->phys->putc(consuart, '\r');
		consuart->phys->putc(consuart, *s);
	}
}

M port/portclock.c => port/portclock.c +1 -1
@@ 127,7 127,7 @@ hzclock(Ureg *ur)
	if(up == 0 || up->state != Running)
		return;

	// i.e. don't schedule an EDF process here!
	/* i.e. don't deschedule an EDF process here! */
	if(anyready() && !isedf(up)){
		sched();
		splhi();

M port/portdat.h => port/portdat.h +4 -0
@@ 766,6 766,8 @@ struct PhysUart
	long	(*status)(Uart*, void*, long, long);
	void	(*fifo)(Uart*, int);
	void	(*power)(Uart*, int);
	int	(*getc)(Uart*);	/* polling versions, for iprint, rdb */
	void	(*putc)(Uart*, int);
};

enum {


@@ 828,6 830,8 @@ struct Uart
	Rendez	r;
};

extern	Uart*	consuart;

/*
 * fasttick timer interrupts (Dummy for now)
 */

M port/portfns.h => port/portfns.h +3 -2
@@ 307,8 307,6 @@ long		seconds(void);
ulong		segattach(Proc*, ulong, char *, ulong, ulong);
void		segclock(ulong);
void		segpage(Segment*, Page*);
int		serialgetc(void);
void		(*serialputs)(char*, int);
int		setcolor(ulong, ulong, ulong, ulong);
void		setkernur(Ureg*, Proc*);
int		setlabel(Label*);


@@ 340,7 338,10 @@ void		todset(vlong, vlong, int);
Block*		trimblock(Block*, int, int);
void		tsleep(Rendez*, int (*)(void*), void*, int);
int		uartctl(Uart*, char*);
int		uartgetc(void);
void		uartkick(void*);
void		uartputc(int);
void		uartputs(char*, int);
void		uartrecv(Uart*, char);
Uart*		uartsetup(Uart*);
int		uartstageoutput(Uart*);

M port/rdb.c => port/rdb.c +1 -1
@@ 30,7 30,7 @@ getline(void)
	int i, c;

	for(;;){
		for(i=0; i<nelem(buf) && (c=serialgetc()) != '\n'; i++){
		for(i=0; i<nelem(buf) && (c=uartgetc()) != '\n'; i++){
			DBG("%c...", c);
			buf[i] = c;
		}

M port/sysproc.c => port/sysproc.c +14 -0
@@ 9,9 9,22 @@

int	shargs(char*, int, char**);

Ref sysr1ref;

long
sysr1(ulong *arg)
{
	int x;
	long a;

	a = *arg;
	if(a > 0)
		return incref(&sysr1ref);
	if(a < 0)
		return decref(&sysr1ref);
	return sysr1ref.ref;

/*
	extern int chandebug;
	extern void dumpmount(void);



@@ 21,6 34,7 @@ sysr1(ulong *arg)
		dumpmount();

	return 0;
*/
}

long