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