summaryrefslogtreecommitdiff
path: root/os/boot/mpc
diff options
context:
space:
mode:
Diffstat (limited to 'os/boot/mpc')
-rw-r--r--os/boot/mpc/NOTICE3
-rw-r--r--os/boot/mpc/alarm.c123
-rw-r--r--os/boot/mpc/all.h6
-rw-r--r--os/boot/mpc/archfads.c355
-rw-r--r--os/boot/mpc/archfads.h42
-rw-r--r--os/boot/mpc/archpaq.c240
-rw-r--r--os/boot/mpc/archpaq.h29
-rw-r--r--os/boot/mpc/boot.h8
-rw-r--r--os/boot/mpc/bootp.c507
-rw-r--r--os/boot/mpc/clock.c71
-rw-r--r--os/boot/mpc/conf.c173
-rw-r--r--os/boot/mpc/console.c173
-rw-r--r--os/boot/mpc/cpm.c162
-rw-r--r--os/boot/mpc/crc32.c42
-rw-r--r--os/boot/mpc/dat.h217
-rw-r--r--os/boot/mpc/defont0.c216
-rw-r--r--os/boot/mpc/devether.c157
-rw-r--r--os/boot/mpc/devuart.c230
-rw-r--r--os/boot/mpc/dload.c103
-rw-r--r--os/boot/mpc/donprint.c332
-rw-r--r--os/boot/mpc/dosboot.c614
-rw-r--r--os/boot/mpc/dosfs.h110
-rw-r--r--os/boot/mpc/etherif.h59
-rw-r--r--os/boot/mpc/etherscc.c411
-rw-r--r--os/boot/mpc/fblt.c531
-rw-r--r--os/boot/mpc/flash.c212
-rw-r--r--os/boot/mpc/fns.h117
-rw-r--r--os/boot/mpc/gbitbltclip.c52
-rw-r--r--os/boot/mpc/gnot.h71
-rw-r--r--os/boot/mpc/i2c.c351
-rw-r--r--os/boot/mpc/initfads.c187
-rw-r--r--os/boot/mpc/initpaq.c101
-rw-r--r--os/boot/mpc/initrpcg.c91
-rw-r--r--os/boot/mpc/io.h463
-rw-r--r--os/boot/mpc/ip.h98
-rw-r--r--os/boot/mpc/l.s370
-rw-r--r--os/boot/mpc/lib.h106
-rw-r--r--os/boot/mpc/main.c524
-rw-r--r--os/boot/mpc/mem.c0
-rw-r--r--os/boot/mpc/mem.h95
-rw-r--r--os/boot/mpc/mkfile116
-rw-r--r--os/boot/mpc/ms2.c179
-rw-r--r--os/boot/mpc/plan9boot.c96
-rw-r--r--os/boot/mpc/qio.c128
-rw-r--r--os/boot/mpc/rmap.c104
-rw-r--r--os/boot/mpc/screen.c242
-rw-r--r--os/boot/mpc/sload.c71
-rw-r--r--os/boot/mpc/squeeze.h34
-rw-r--r--os/boot/mpc/trap.c233
-rw-r--r--os/boot/mpc/uartboot.c189
-rw-r--r--os/boot/mpc/ureg.h43
-rw-r--r--os/boot/mpc/zqs.c234
52 files changed, 9421 insertions, 0 deletions
diff --git a/os/boot/mpc/NOTICE b/os/boot/mpc/NOTICE
new file mode 100644
index 00000000..b0086fa7
--- /dev/null
+++ b/os/boot/mpc/NOTICE
@@ -0,0 +1,3 @@
+Inferno® Copyright © 1996-1999 Lucent Technologies Inc. All rights reserved.
+PowerPC support Copyright © 1995-1997 C H Forsyth (forsyth@caldo.demon.co.uk). All rights reserved.
+MPC8xx Inferno PowerPC port Copyright © 1998-2003 Vita Nuova Holdings Limited. All rights reserved.
diff --git a/os/boot/mpc/alarm.c b/os/boot/mpc/alarm.c
new file mode 100644
index 00000000..2aa4431a
--- /dev/null
+++ b/os/boot/mpc/alarm.c
@@ -0,0 +1,123 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#define MAXALARM 10
+
+Alarm alarmtab[MAXALARM];
+
+/*
+ * Insert new into list after where
+ */
+void
+insert(List **head, List *where, List *new)
+{
+ if(where == 0){
+ new->next = *head;
+ *head = new;
+ }else{
+ new->next = where->next;
+ where->next = new;
+ }
+
+}
+
+/*
+ * Delete old from list. where->next is known to be old.
+ */
+void
+delete(List **head, List *where, List *old)
+{
+ if(where == 0){
+ *head = old->next;
+ return;
+ }
+ where->next = old->next;
+}
+
+Alarm*
+newalarm(void)
+{
+ int i;
+ Alarm *a;
+
+ for(i=0,a=alarmtab; i < nelem(alarmtab); i++,a++)
+ if(a->busy==0 && a->f==0){
+ a->f = 0;
+ a->arg = 0;
+ a->busy = 1;
+ return a;
+ }
+ panic("newalarm");
+ return 0; /* not reached */
+}
+
+Alarm*
+alarm(int ms, void (*f)(Alarm*), void *arg)
+{
+ Alarm *a, *w, *pw;
+ ulong s;
+
+ if(ms < 0)
+ ms = 0;
+ s = splhi();
+ a = newalarm();
+ a->dt = MS2TK(ms);
+ a->f = f;
+ a->arg = arg;
+ pw = 0;
+ for(w=m->alarm; w; pw=w, w=w->next){
+ if(w->dt <= a->dt){
+ a->dt -= w->dt;
+ continue;
+ }
+ w->dt -= a->dt;
+ break;
+ }
+ insert(&m->alarm, pw, a);
+ splx(s);
+ return a;
+}
+
+void
+cancel(Alarm *a)
+{
+ a->f = 0;
+}
+
+void
+alarminit(void)
+{
+}
+
+#define NA 10 /* alarms per clock tick */
+void
+checkalarms(void)
+{
+ int i, n, s;
+ Alarm *a;
+ void (*f)(Alarm*);
+ Alarm *alist[NA];
+
+ s = splhi();
+ a = m->alarm;
+ if(a){
+ for(n=0; a && a->dt<=0 && n<NA; n++){
+ alist[n] = a;
+ delete(&m->alarm, 0, a);
+ a = m->alarm;
+ }
+ if(a)
+ a->dt--;
+
+ for(i = 0; i < n; i++){
+ f = alist[i]->f; /* avoid race with cancel */
+ if(f)
+ (*f)(alist[i]);
+ alist[i]->busy = 0;
+ }
+ }
+ splx(s);
+}
diff --git a/os/boot/mpc/all.h b/os/boot/mpc/all.h
new file mode 100644
index 00000000..0612bf04
--- /dev/null
+++ b/os/boot/mpc/all.h
@@ -0,0 +1,6 @@
+#include "u.h"
+#include "lib.h"
+#include "dat.h"
+#include "fns.h"
+#include "mem.h"
+#include "io.h"
diff --git a/os/boot/mpc/archfads.c b/os/boot/mpc/archfads.c
new file mode 100644
index 00000000..39f86e03
--- /dev/null
+++ b/os/boot/mpc/archfads.c
@@ -0,0 +1,355 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "archfads.h"
+
+/*
+ * board-specific support for the 8xxFADS (including 860/21 development system)
+ */
+
+enum {
+ USESDRAM = 0, /* set to 1 if kernel is to use SDRAM as well as DRAM */
+
+ /* sccr */
+ RTSEL = IBIT(8), /* =0, select main oscillator (OSCM); =1, select external crystal (EXTCLK) */
+ RTDIV = IBIT(7), /* =0, divide by 4; =1, divide by 512 */
+ CRQEN = IBIT(9), /* =1, switch to high frequency when CPM active */
+ PRQEN = IBIT(10), /* =1, switch to high frequency when interrupt pending */
+
+ /* plprcr */
+ CSRC = IBIT(21), /* =0, clock is DFNH; =1, clock is DFNL */
+};
+
+/*
+ * called early in main.c, after machinit:
+ * using board and architecture specific registers, initialise
+ * 8xx registers that need it and complete initialisation of the Mach structure.
+ */
+void
+archinit(void)
+{
+ IMM *io;
+ int mf, isfads, sysmhz, t;
+ ulong v;
+
+ v = getimmr() & 0xFFFF;
+ isfads = 0; /* assume it's the 860/821 board */
+ sysmhz = 40;
+ switch(v>>8){
+ case 0x00: t = 0x86000; break;
+ case 0x20: t = 0x82300; isfads = 1; break;
+ case 0x21: t = 0x823a0; isfads = 1; break;
+ default: t = 0; break;
+ }
+ m->cputype = t;
+ m->bcsr = KADDR(BCSRMEM);
+ m->bcsr[1] |= DisableRS232a | DisableIR | DisableEther | DisablePCMCIA | DisableRS232b;
+ m->bcsr[1] &= ~(DisableDRAM|DisableFlash);
+ if(isfads){
+ sysmhz = 50;
+ m->bcsr[1] &= ~EnableSDRAM;
+ m->bcsr[4] &= ~(EnableVideoClock|EnableVideoPort);
+ m->bcsr[4] |= DisableVideoLamp;
+ }
+ io = m->iomem;
+ if(1 || io->sccr & IBIT(7)){ /* RTDIV=1 */
+ /* oscillator frequency can't be determined independently: check a switch */
+ if((m->bcsr[2]>>19)&(1<<2))
+ m->clockgen = 5*MHz;
+ else
+ m->clockgen = 4*MHz;
+ } else
+ m->clockgen = 32768;
+ mf = (sysmhz*MHz)/m->clockgen;
+ m->cpuhz = m->clockgen*mf;
+ io->plprcrk = KEEP_ALIVE_KEY;
+ io->plprcr &= ~IBIT(21); /* general system clock is DFNH */
+ io->plprcr = (io->plprcr & ((1<<20)-1)) | ((mf-1)<<20);
+ io->mptpr = 0x0400; /* memory prescaler = 16 for refresh */
+ io->plprcrk = ~KEEP_ALIVE_KEY;
+ if(isfads){
+ m->bcsr[1] |= EnableSDRAM;
+ sdraminit(SDRAMMEM);
+ if(!USESDRAM)
+ m->bcsr[1] &= ~EnableSDRAM; /* tells kernel not to map it */
+ }
+}
+
+static void
+archidprint(void)
+{
+ int f, i;
+ ulong v;
+
+ /* 8xx and FADS specific */
+ print("IMMR: ");
+ v = getimmr() & 0xFFFF;
+ switch(v>>8){
+ case 0x00: print("MPC860/821"); break;
+ case 0x20: print("MPC823"); break;
+ case 0x21: print("MPC823A"); break;
+ default: print("Type #%lux", v>>8); break;
+ }
+ print(", mask #%lux\n", v&0xFF);
+ v = m->bcsr[3]>>16;
+ print("MPC8xxFADS rev %lud, DB: ", ((v>>4)&8)|((v>>1)&4)|(v&3));
+ f = (v>>8)&0x3F;
+ switch(f){
+ default: print("ID#%x", f); break;
+ case 0x00: print("MPC860/821"); break;
+ case 0x01: print("MPC813"); break;
+ case 0x02: print("MPC821"); break;
+ case 0x03: print("MPC823"); break;
+ case 0x20: print("MPC801"); break;
+ case 0x21: print("MPC850"); break;
+ case 0x22: print("MPC860"); break;
+ case 0x23: print("MPC860SAR"); break;
+ case 0x24: print("MPC860T"); break;
+ }
+ print("ADS, rev #%lux\n", (m->bcsr[2]>>16)&7);
+ for(i=0; i<=4; i++)
+ print("BCSR%d: %8.8lux\n", i, m->bcsr[i]);
+ v = m->bcsr[2];
+ f = (v>>28)&0xF;
+ switch(f){
+ default: print("Unknown"); break;
+ case 4: print("SM732A2000/SM73228 - 8M SIMM"); break;
+ case 5: print("SM732A1000A/SM73218 - 4M SIMM"); break;
+ case 6: print("MCM29080 - 8M SIMM"); break;
+ case 7: print("MCM29040 - 4M SIMM"); break;
+ case 8: print("MCM29020 - 2M SIMM"); break;
+ }
+ switch((m->bcsr[3]>>20)&7){
+ default: i = 0; break;
+ case 1: i = 150; break;
+ case 2: i = 120; break;
+ case 3: i = 90; break;
+ }
+ print(" flash, %dns\n", i);
+ f = (v>>23)&0xF;
+ switch(f&3){
+ case 0: i = 4; break;
+ case 1: i = 32; break;
+ case 2: i = 16; break;
+ case 3: i = 8; break;
+ }
+ print("%dM SIMM, ", i);
+ switch(f>>2){
+ default: i = 0; break;
+ case 2: i = 70; break;
+ case 3: i = 60; break;
+ }
+ print("%dns\n", i);
+ print("options: #%lux\n", (m->bcsr[2]>>19)&0xF);
+ print("plprcr=%8.8lux sccr=%8.8lux\n", m->iomem->plprcr, m->iomem->sccr);
+}
+
+void
+cpuidprint(void)
+{
+ int t;
+
+ print("PVR: ");
+ t = getpvr()>>16;
+ switch(t){
+ case 0x01: print("MPC601"); break;
+ case 0x03: print("MPC603"); break;
+ case 0x04: print("MPC604"); break;
+ case 0x06: print("MPC603e"); break;
+ case 0x07: print("MPC603e-v7"); break;
+ case 0x50: print("MPC8xx"); break;
+ default: print("PowerPC version #%x", t); break;
+ }
+ print(", revision #%lux\n", getpvr()&0xffff);
+ archidprint();
+ print("%lud MHz system\n", m->cpuhz/MHz);
+ print("\n");
+}
+
+static char* defplan9ini[2] = {
+ /* 860/821 */
+ "ether0=type=SCC port=1 ea=00108bf12900\r\n"
+ "vgasize=640x480x8\r\n"
+ "kernelpercent=40\r\n"
+ "console=0 lcd\r\nbaud=9600\r\n",
+
+ /* 823 */
+ "ether0=type=SCC port=2 ea=00108bf12900\r\n"
+ "vgasize=640x480x8\r\n"
+ "kernelpercent=40\r\n"
+ "console=0 lcd\r\nbaud=9600\r\n",
+};
+
+char *
+archconfig(void)
+{
+ print("Using default configuration\n");
+ return defplan9ini[MPCMODEL(m->cputype) == 0x823];
+}
+
+/*
+ * provide value for #r/switch (devrtc.c)
+ */
+int
+archoptionsw(void)
+{
+ return (m->bcsr[2]>>19)&0xF; /* value of switch DS1 */
+}
+
+/*
+ * invoked by clock.c:/^clockintr
+ */
+static void
+twinkle(void)
+{
+ if(m->ticks%MS2TK(1000) == 0)
+ m->bcsr[4] ^= DisableLamp;
+}
+
+void (*archclocktick)(void) = twinkle;
+
+/*
+ * for flash.c:/^flashreset
+ * retrieve flash type, virtual base and length and return 0;
+ * return -1 on error (no flash)
+ */
+int
+archflashreset(char *type, void **addr, long *length)
+{
+ char *t;
+ int mbyte;
+
+ if((m->iomem->memc[0].base & 1) == 0)
+ return -1; /* shouldn't happen */
+ switch((m->bcsr[2]>>28)&0xF){
+ default: return -1; /* unknown or not there */
+ case 4: mbyte=8; t = "SM732x8"; break;
+ case 5: mbyte=4; t = "SM732x8"; break;
+ case 6: mbyte=8; t = "AMD29F0x0"; break;
+ case 7: mbyte=4; t = "AMD29F0x0"; break;
+ case 8: mbyte=2; t = "AMD29F0x0"; break;
+ }
+ strcpy(type, t);
+ *addr = KADDR(FLASHMEM);
+ *length = mbyte*1024*1024;
+ return 0;
+}
+
+/*
+ * enable the clocks for the given SCC ether and reveal them to the caller.
+ * do anything else required to prepare the transceiver (eg, set full-duplex, reset loopback).
+ */
+int
+archetherenable(int cpmid, int *rcs, int *tcs)
+{
+ IMM *io;
+
+ switch(cpmid){
+ default:
+ /* no other SCCs are wired on the FADS board */
+ return -1;
+
+ case SCC2ID: /* assume 8xxFADS board with 823DABS */
+ io = ioplock();
+ m->bcsr[1] |= DisableIR|DisableRS232b;
+ m->bcsr[1] &= ~DisableEther;
+ io->papar |= SIBIT(6)|SIBIT(5); /* enable CLK2 and CLK3 */
+ io->padir &= ~(SIBIT(6)|SIBIT(5));
+
+ /* ETHLOOP etc set in BCSR elsewhere */
+ *rcs = CLK2;
+ *tcs = CLK3;
+ iopunlock();
+ break;
+
+ case SCC1ID: /* assume 860/21 development board */
+ io = ioplock();
+ m->bcsr[1] |= DisableIR|DisableRS232b; /* TO DO: might not be shared with RS232b */
+ m->bcsr[1] &= ~DisableEther;
+ io->papar |= SIBIT(6)|SIBIT(7); /* enable CLK2 and CLK1 */
+ io->padir &= ~(SIBIT(6)|SIBIT(7));
+
+ /* settings peculiar to 860/821 development board */
+ io->pcpar &= ~(SIBIT(4)|SIBIT(5)|SIBIT(6)); /* ETHLOOP, TPFULDL~, TPSQEL~ */
+ io->pcdir |= SIBIT(4)|SIBIT(5)|SIBIT(6);
+ io->pcdat &= ~SIBIT(4);
+ io->pcdat |= SIBIT(5)|SIBIT(6);
+ *rcs = CLK2;
+ *tcs = CLK1;
+ iopunlock();
+ break;
+ }
+ return 0;
+}
+
+void
+archetherdisable(int id)
+{
+ USED(id);
+ m->bcsr[1] |= DisableEther|DisableIR|DisableRS232b;
+}
+
+/*
+ * do anything extra required to enable the UART on the given CPM port
+ */
+void
+archenableuart(int id, int irda)
+{
+ switch(id){
+ case SMC1ID:
+ m->bcsr[1] &= ~DisableRS232a;
+ break;
+ case SCC2ID:
+ m->bcsr[1] |= DisableEther|DisableIR|DisableRS232b;
+ if(irda)
+ m->bcsr[1] &= ~DisableIR;
+ else
+ m->bcsr[1] &= ~DisableRS232b;
+ break;
+ default:
+ /* nothing special */
+ break;
+ }
+}
+
+/*
+ * do anything extra required to disable the UART on the given CPM port
+ */
+void
+archdisableuart(int id)
+{
+ switch(id){
+ case SMC1ID:
+ m->bcsr[1] |= DisableRS232a;
+ break;
+ case SCC2ID:
+ m->bcsr[1] |= DisableIR|DisableRS232b;
+ break;
+ default:
+ /* nothing special */
+ break;
+ }
+}
+
+/*
+ * enable/disable the LCD panel's backlight via
+ * York touch panel interface (does no harm without it)
+ */
+void
+archbacklight(int on)
+{
+ IMM *io;
+
+ delay(2);
+ io = ioplock();
+ io->papar &= ~SIBIT(4);
+ io->padir |= SIBIT(4);
+ if(on)
+ io->padat |= SIBIT(4);
+ else
+ io->padat &= ~SIBIT(4);
+ iopunlock();
+}
diff --git a/os/boot/mpc/archfads.h b/os/boot/mpc/archfads.h
new file mode 100644
index 00000000..fbe30361
--- /dev/null
+++ b/os/boot/mpc/archfads.h
@@ -0,0 +1,42 @@
+
+enum {
+ /* BCSR1 bits */
+ DisableFlash= IBIT(0),
+ DisableDRAM= IBIT(1),
+ DisableEther= IBIT(2),
+ DisableIR= IBIT(3),
+ DisableRS232a= IBIT(7),
+ DisablePCMCIA= IBIT(8),
+ PCCVCCMask= IBIT(9)|IBIT(15),
+ PCCVPPMask= IBIT(10)|IBIT(11),
+ DisableRS232b= IBIT(13),
+ EnableSDRAM= IBIT(14),
+
+ PCCVCC0V= IBIT(15)|IBIT(9),
+ PCCVCC5V= IBIT(9), /* active low */
+ PCCVCC3V= IBIT(15), /* active low */
+ PCCVPP0V= IBIT(10)|IBIT(11), /* active low */
+ PCCVPP5V= IBIT(10), /* active low */
+ PCCVPP12V= IBIT(11), /* active low */
+ PCCVPPHiZ= IBIT(10)|IBIT(11),
+
+ /* BCSR4 bits */
+ DisableTPDuplex= IBIT(1),
+ DisableLamp= IBIT(3),
+ DisableUSB= IBIT(4),
+ USBFullSpeed= IBIT(5),
+ DisableUSBVcc= IBIT(6),
+ DisableVideoLamp= IBIT(8),
+ EnableVideoClock= IBIT(9),
+ EnableVideoPort= IBIT(10),
+ DisableModem= IBIT(11),
+};
+
+enum {
+ /* memory controller CS assignment on FADS boards */
+ BOOTCS = 0,
+ BCSRCS = 1,
+ DRAM1 = 2,
+ DRAM2 = 3,
+ SDRAM = 4,
+};
diff --git a/os/boot/mpc/archpaq.c b/os/boot/mpc/archpaq.c
new file mode 100644
index 00000000..abffe266
--- /dev/null
+++ b/os/boot/mpc/archpaq.c
@@ -0,0 +1,240 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "archpaq.h"
+
+/*
+ * board-specific support for the 82x PowerPAQ
+ */
+
+enum {
+ SYSMHZ = 50, /* desired system clock in MHz */
+
+ /* sccr */
+ RTSEL = IBIT(8), /* =0, select main oscillator (OSCM); =1, select external crystal (EXTCLK) */
+ RTDIV = IBIT(7), /* =0, divide by 4; =1, divide by 512 */
+ CRQEN = IBIT(9), /* =1, switch to high frequency when CPM active */
+ PRQEN = IBIT(10), /* =1, switch to high frequency when interrupt pending */
+
+ /* plprcr */
+ CSRC = IBIT(21), /* =0, clock is DFNH; =1, clock is DFNL */
+};
+
+/*
+ * called early in main.c, after machinit:
+ * using board and architecture specific registers, initialise
+ * 8xx registers that need it and complete initialisation of the Mach structure.
+ */
+void
+archinit(void)
+{
+ IMM *io;
+ int mf, t;
+
+ switch((getimmr()>>8)&0xFF){
+ case 0x00: t = 0x86000; break; /* also 821 */
+ case 0x20: t = 0x82300; break;
+ case 0x21: t = 0x823a0; break;
+ default: t = 0; break;
+ }
+ m->cputype = t;
+ m->bcsr = nil; /* there isn't one */
+ m->clockgen = 32*1024; /* crystal frequency */
+ io = m->iomem;
+ io->sccrk = KEEP_ALIVE_KEY;
+ io->sccr &= ~RTDIV; /* divide 32k by 4 */
+ io->sccr |= RTSEL;
+ io->sccrk = ~KEEP_ALIVE_KEY;
+ mf = (SYSMHZ*MHz)/m->clockgen;
+ m->cpuhz = m->clockgen*mf;
+ io->plprcrk = KEEP_ALIVE_KEY;
+ io->plprcr &= ~IBIT(21); /* general system clock is DFNH */
+ io->plprcr = (io->plprcr & ((1<<20)-1)) | ((mf-1)<<20);
+ io->mptpr = 0x0400; /* memory prescaler = 16 for refresh */
+ io->plprcrk = ~KEEP_ALIVE_KEY;
+}
+
+void
+cpuidprint(void)
+{
+ int t, v;
+
+ print("PVR: ");
+ t = getpvr()>>16;
+ switch(t){
+ case 0x01: print("MPC601"); break;
+ case 0x03: print("MPC603"); break;
+ case 0x04: print("MPC604"); break;
+ case 0x06: print("MPC603e"); break;
+ case 0x07: print("MPC603e-v7"); break;
+ case 0x50: print("MPC8xx"); break;
+ default: print("PowerPC version #%x", t); break;
+ }
+ print(", revision #%lux\n", getpvr()&0xffff);
+ print("IMMR: ");
+ v = getimmr() & 0xFFFF;
+ switch(v>>8){
+ case 0x00: print("MPC860/821"); break;
+ case 0x20: print("MPC823"); break;
+ case 0x21: print("MPC823A"); break;
+ default: print("Type #%lux", v>>8); break;
+ }
+ print(", mask #%lux\n", v&0xFF);
+ print("plprcr=%8.8lux sccr=%8.8lux\n", m->iomem->plprcr, m->iomem->sccr);
+ print("%lud MHz system\n", m->cpuhz/MHz);
+ print("\n");
+}
+
+static char* defplan9ini[2] = {
+ /* 860/821 */
+ "ether0=type=SCC port=1 ea=00108bf12900\r\n"
+ "vgasize=640x480x8\r\n"
+ "kernelpercent=40\r\n"
+ "console=0 lcd\r\nbaud=19200\r\n",
+
+ /* 823 */
+ "ether0=type=SCC port=2 ea=00108bf12900\r\n"
+ "vgasize=640x480x8\r\n"
+ "kernelpercent=40\r\n"
+ "console=0 lcd\r\nbaud=19200\r\n",
+};
+
+char *
+archconfig(void)
+{
+ print("Using default configuration\n");
+ return defplan9ini[MPCMODEL(m->cputype) == 0x823];
+}
+
+/*
+ * provide value for #r/switch (devrtc.c)
+ */
+int
+archoptionsw(void)
+{
+ return 0;
+}
+
+/*
+ * invoked by clock.c:/^clockintr
+ */
+static void
+twinkle(void)
+{
+ /* no easy-to-use LED on PAQ (they use i2c) */
+}
+
+void (*archclocktick)(void) = twinkle;
+
+/*
+ * for flash.c:/^flashinit
+ * retrieve flash type, virtual base and length and return 0;
+ * return -1 on error (no flash)
+ */
+int
+archflashreset(char *type, void **addr, long *length)
+{
+ strcpy(type, "AMD29F0x0");
+ *addr = KADDR(FLASHMEM);
+ *length = 8*1024*1024; /* 8mbytes on some models */
+ return 0;
+}
+
+/*
+ * enable the clocks for the given SCC ether and reveal them to the caller.
+ * do anything else required to prepare the transceiver (eg, set full-duplex, reset loopback).
+ */
+int
+archetherenable(int cpmid, int *rcs, int *tcs)
+{
+ USED(cpmid, rcs, tcs);
+ return -1; /* there isn't an ether on the PAQs */
+}
+
+void
+archetherdisable(int id)
+{
+ USED(id);
+}
+
+/*
+ * do anything extra required to enable the UART on the given CPM port
+ */
+void
+archenableuart(int id, int irda)
+{
+ IMM *io;
+
+ USED(irda);
+ switch(id){
+ case SMC1ID:
+ io = ioplock();
+ io->pbodr &= ~0xc0;
+ io->pbdat |= 0xc0;
+ io->pcdat |= 0x400;
+ io->pcpar &= ~0x400;
+ io->pcdir |= 0x400;
+ io->pcdat &= ~0x400; /* enable SMC RS232 buffer */
+ iopunlock();
+ break;
+ case SCC2ID:
+ /* TO DO */
+ break;
+ default:
+ /* nothing special */
+ break;
+ }
+}
+
+/*
+ * do anything extra required to disable the UART on the given CPM port
+ */
+void
+archdisableuart(int id)
+{
+ switch(id){
+ case SMC1ID:
+ /* TO DO */
+ break;
+ case SCC2ID:
+ /* TO DO */
+ break;
+ default:
+ /* nothing special */
+ break;
+ }
+}
+
+/*
+ * enable/disable the LCD panel's backlight via i2c
+ */
+void
+archbacklight(int on)
+{
+ uchar msg;
+ IMM *io;
+
+ i2csetup();
+ msg = ~7;
+ i2csend(LEDRegI2C, &msg, 1);
+ io = ioplock();
+ io->pbpar &= ~EnableLCD;
+ io->pbodr &= ~EnableLCD;
+ io->pbdir |= EnableLCD;
+ if(on)
+ io->pbdat |= EnableLCD;
+ else
+ io->pbdat &= ~EnableLCD;
+ iopunlock();
+ if(on){
+ msg = ~(DisablePanelVCC5|DisableTFT);
+ i2csend(PanelI2C, &msg, 1);
+ }else{
+ msg = ~0;
+ i2csend(PanelI2C, &msg, 1);
+ }
+}
diff --git a/os/boot/mpc/archpaq.h b/os/boot/mpc/archpaq.h
new file mode 100644
index 00000000..095abfaa
--- /dev/null
+++ b/os/boot/mpc/archpaq.h
@@ -0,0 +1,29 @@
+enum {
+ /* memory controller CS assignment on PowerPAQ */
+ BOOTCS = 0,
+ DRAM1 = 1, /* UPMB */
+ DRAM2 = 2, /* UPMB */
+ /* CS3 also connected to DRAM */
+ /* CS4 128mbyte 8-bit gpcm, trlx, 15 wait; it's DAC */
+ /* CS5 is external*/
+};
+
+enum {
+ /* I2C addresses */
+ PanelI2C = 0x21<<1,
+ /* the control bits are active low enables, or high disables */
+ DisableVGA = ~0xFD, /* disable VGA signals */
+ DisableTFT = ~0xFB, /* disable TFT panel signals */
+ DisableSPIBus = ~0xF7, /* disable SPI/I2C to panel */
+ DisablePanelVCC5 = ~0xEF, /* disable +5V to panel(s) */
+ DisablePanelVCC3 = ~0xDF, /* disable +3.3V to panel(s) */
+ DisableMonoPanel = ~0xBF, /* disable mono panel signals */
+ DisableSPISelect = ~0x7F, /* disable SPI chip select to LVDS panel */
+ ContrastI2C = 0x2E<<1,
+ LEDRegI2C = 0x20<<1,
+ DisableGreenLED = ~0xFE,
+ DisableYellowLED = ~0xFD,
+ DisableRedLED = ~0xFB,
+
+ EnableLCD = IBIT(23), /* LCD enable bit in i/o port B */
+};
diff --git a/os/boot/mpc/boot.h b/os/boot/mpc/boot.h
new file mode 100644
index 00000000..1b2a09fb
--- /dev/null
+++ b/os/boot/mpc/boot.h
@@ -0,0 +1,8 @@
+#include <u.h>
+#include "lib.h"
+
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
diff --git a/os/boot/mpc/bootp.c b/os/boot/mpc/bootp.c
new file mode 100644
index 00000000..94b188f4
--- /dev/null
+++ b/os/boot/mpc/bootp.c
@@ -0,0 +1,507 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "ip.h"
+
+enum {
+ CHECKSUM = 1, /* set zero if trouble booting from Linux */
+};
+
+uchar broadcast[Eaddrlen] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+};
+
+static ushort tftpport = 5000;
+static int Id = 1;
+static Netaddr myaddr;
+static Netaddr server;
+
+typedef struct {
+ uchar header[4];
+ uchar data[Segsize];
+} Tftp;
+static Tftp tftpb;
+
+static void
+hnputs(uchar *ptr, ushort val)
+{
+ ptr[0] = val>>8;
+ ptr[1] = val;
+}
+
+static void
+hnputl(uchar *ptr, ulong val)
+{
+ ptr[0] = val>>24;
+ ptr[1] = val>>16;
+ ptr[2] = val>>8;
+ ptr[3] = val;
+}
+
+static ulong
+nhgetl(uchar *ptr)
+{
+ return ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]);
+}
+
+static ushort
+nhgets(uchar *ptr)
+{
+ return ((ptr[0]<<8) | ptr[1]);
+}
+
+static short endian = 1;
+static char* aendian = (char*)&endian;
+#define LITTLE *aendian
+
+static ushort
+ptcl_csum(void *a, int len)
+{
+ uchar *addr;
+ ulong t1, t2;
+ ulong losum, hisum, mdsum, x;
+
+ addr = a;
+ losum = 0;
+ hisum = 0;
+ mdsum = 0;
+
+ x = 0;
+ if((ulong)addr & 1) {
+ if(len) {
+ hisum += addr[0];
+ len--;
+ addr++;
+ }
+ x = 1;
+ }
+ while(len >= 16) {
+ t1 = *(ushort*)(addr+0);
+ t2 = *(ushort*)(addr+2); mdsum += t1;
+ t1 = *(ushort*)(addr+4); mdsum += t2;
+ t2 = *(ushort*)(addr+6); mdsum += t1;
+ t1 = *(ushort*)(addr+8); mdsum += t2;
+ t2 = *(ushort*)(addr+10); mdsum += t1;
+ t1 = *(ushort*)(addr+12); mdsum += t2;
+ t2 = *(ushort*)(addr+14); mdsum += t1;
+ mdsum += t2;
+ len -= 16;
+ addr += 16;
+ }
+ while(len >= 2) {
+ mdsum += *(ushort*)addr;
+ len -= 2;
+ addr += 2;
+ }
+ if(x) {
+ if(len)
+ losum += addr[0];
+ if(LITTLE)
+ losum += mdsum;
+ else
+ hisum += mdsum;
+ } else {
+ if(len)
+ hisum += addr[0];
+ if(LITTLE)
+ hisum += mdsum;
+ else
+ losum += mdsum;
+ }
+
+ losum += hisum >> 8;
+ losum += (hisum & 0xff) << 8;
+ while(hisum = losum>>16)
+ losum = hisum + (losum & 0xffff);
+
+ return ~losum;
+}
+
+static ushort
+ip_csum(uchar *addr)
+{
+ int len;
+ ulong sum = 0;
+
+ len = (addr[0]&0xf)<<2;
+
+ while(len > 0) {
+ sum += addr[0]<<8 | addr[1] ;
+ len -= 2;
+ addr += 2;
+ }
+
+ sum = (sum & 0xffff) + (sum >> 16);
+ sum = (sum & 0xffff) + (sum >> 16);
+ return (sum^0xffff);
+}
+
+static void
+udpsend(int ctlrno, Netaddr *a, void *data, int dlen)
+{
+ Udphdr *uh;
+ Etherhdr *ip;
+ static Etherpkt pkt;
+ int len, ptcllen;
+
+
+ uh = (Udphdr*)&pkt;
+
+ memset(uh, 0, sizeof(Etherpkt));
+ memmove(uh->udpcksum+sizeof(uh->udpcksum), data, dlen);
+
+ /*
+ * UDP portion
+ */
+ ptcllen = dlen + (UDP_HDRSIZE-UDP_PHDRSIZE);
+ uh->ttl = 0;
+ uh->udpproto = IP_UDPPROTO;
+ uh->frag[0] = 0;
+ uh->frag[1] = 0;
+ hnputs(uh->udpplen, ptcllen);
+ hnputl(uh->udpsrc, myaddr.ip);
+ hnputs(uh->udpsport, myaddr.port);
+ hnputl(uh->udpdst, a->ip);
+ hnputs(uh->udpdport, a->port);
+ hnputs(uh->udplen, ptcllen);
+ uh->udpcksum[0] = 0;
+ uh->udpcksum[1] = 0;
+ /*dlen = (dlen+1)&~1; */
+ hnputs(uh->udpcksum, ptcl_csum(&uh->ttl, dlen+UDP_HDRSIZE));
+
+ /*
+ * IP portion
+ */
+ ip = (Etherhdr*)&pkt;
+ len = sizeof(Udphdr)+dlen;
+ ip->vihl = IP_VER|IP_HLEN;
+ ip->tos = 0;
+ ip->ttl = 255;
+ hnputs(ip->length, len-ETHER_HDR);
+ hnputs(ip->id, Id++);
+ ip->frag[0] = 0;
+ ip->frag[1] = 0;
+ ip->cksum[0] = 0;
+ ip->cksum[1] = 0;
+ hnputs(ip->cksum, ip_csum(&ip->vihl));
+
+ /*
+ * Ethernet MAC portion
+ */
+ hnputs(ip->type, ET_IP);
+ memmove(ip->d, a->ea, sizeof(ip->d));
+
+ ethertxpkt(ctlrno, &pkt, len, Timeout);
+}
+
+static void
+nak(int ctlrno, Netaddr *a, int code, char *msg, int report)
+{
+ int n;
+ char buf[128];
+
+ buf[0] = 0;
+ buf[1] = Tftp_ERROR;
+ buf[2] = 0;
+ buf[3] = code;
+ strcpy(buf+4, msg);
+ n = strlen(msg) + 4 + 1;
+ udpsend(ctlrno, a, buf, n);
+ if(report)
+ print("\ntftp: error(%d): %s\n", code, msg);
+}
+
+static int
+udprecv(int ctlrno, Netaddr *a, void *data, int dlen)
+{
+ int n, len;
+ ushort csm;
+ Udphdr *h;
+ ulong addr, timo;
+ static Etherpkt pkt;
+ static int rxactive;
+
+ if(rxactive == 0)
+ timo = 1000;
+ else
+ timo = Timeout;
+ timo += TK2MS(m->ticks);
+ while(timo > TK2MS(m->ticks)){
+ n = etherrxpkt(ctlrno, &pkt, timo-TK2MS(m->ticks));
+ if(n <= 0)
+ continue;
+
+ h = (Udphdr*)&pkt;
+ if(nhgets(h->type) != ET_IP)
+ continue;
+
+ if(ip_csum(&h->vihl)) {
+ print("ip chksum error\n");
+ continue;
+ }
+ if(h->vihl != (IP_VER|IP_HLEN)) {
+ print("ip bad vers/hlen\n");
+ continue;
+ }
+
+ if(h->udpproto != IP_UDPPROTO)
+ continue;
+
+ h->ttl = 0;
+ len = nhgets(h->udplen);
+ hnputs(h->udpplen, len);
+
+ if(CHECKSUM && nhgets(h->udpcksum)) {
+ csm = ptcl_csum(&h->ttl, len+UDP_PHDRSIZE);
+ if(csm != 0) {
+ print("udp chksum error csum #%4lux len %d\n", csm, n);
+ break;
+ }
+ }
+
+ if(a->port != 0 && nhgets(h->udpsport) != a->port)
+ continue;
+
+ addr = nhgetl(h->udpsrc);
+ if(a->ip != Bcastip && addr != a->ip)
+ continue;
+
+ len -= UDP_HDRSIZE-UDP_PHDRSIZE;
+ if(len > dlen) {
+ print("udp: packet too big\n");
+ continue;
+ }
+
+ memmove(data, h->udpcksum+sizeof(h->udpcksum), len);
+ a->ip = addr;
+ a->port = nhgets(h->udpsport);
+ memmove(a->ea, pkt.s, sizeof(a->ea));
+
+ rxactive = 1;
+ return len;
+ }
+
+ return 0;
+}
+
+static int tftpblockno;
+
+static int
+tftpopen(int ctlrno, Netaddr *a, char *name, Tftp *tftp)
+{
+ int i, len, rlen, oport;
+ char buf[Segsize+2];
+
+ buf[0] = 0;
+ buf[1] = Tftp_READ;
+ len = sprint(buf+2, "%s", name) + 2;
+ len += sprint(buf+len+1, "octet") + 2;
+
+ oport = a->port;
+ for(i = 0; i < 5; i++){
+ a->port = oport;
+ udpsend(ctlrno, a, buf, len);
+ a->port = 0;
+ if((rlen = udprecv(ctlrno, a, tftp, sizeof(Tftp))) < sizeof(tftp->header))
+ continue;
+
+ switch((tftp->header[0]<<8)|tftp->header[1]){
+
+ case Tftp_ERROR:
+ print("tftpopen: error (%d): %s\n",
+ (tftp->header[2]<<8)|tftp->header[3], tftp->data);
+ return -1;
+
+ case Tftp_DATA:
+ tftpblockno = 1;
+ len = (tftp->header[2]<<8)|tftp->header[3];
+ if(len != tftpblockno){
+ print("tftpopen: block error: %d\n", len);
+ nak(ctlrno, a, 1, "block error", 0);
+ return -1;
+ }
+ return rlen-sizeof(tftp->header);
+ }
+ }
+
+ print("tftpopen: failed to connect to server\n");
+ return -1;
+}
+
+static int
+tftpread(int ctlrno, Netaddr *a, Tftp *tftp, int dlen)
+{
+ int blockno, len, retry;
+ uchar buf[4];
+
+ buf[0] = 0;
+ buf[1] = Tftp_ACK;
+ buf[2] = tftpblockno>>8;
+ buf[3] = tftpblockno;
+ tftpblockno++;
+
+ dlen += sizeof(tftp->header);
+
+ retry = 0;
+buggery:
+ udpsend(ctlrno, a, buf, sizeof(buf));
+
+ if((len = udprecv(ctlrno, a, tftp, dlen)) < dlen){
+ print("tftpread: %d != %d\n", len, dlen);
+ nak(ctlrno, a, 2, "short read", 0);
+ if(retry++ < 5)
+ goto buggery;
+ return -1;
+ }
+
+ blockno = (tftp->header[2]<<8)|tftp->header[3];
+ if(blockno != tftpblockno){
+ print("?");
+
+ if(blockno == tftpblockno-1 && retry++ < 8)
+ goto buggery;
+ print("tftpread: block error: %d, expected %d\n", blockno, tftpblockno);
+ nak(ctlrno, a, 1, "block error", 0);
+
+ return -1;
+ }
+
+ return len-sizeof(tftp->header);
+}
+
+int
+bootp(int ctlrno, char *file)
+{
+ Bootp req, rep;
+ int i, dlen, segsize, text, data, bss, total;
+ uchar *ea, *addr, *p;
+ ulong entry;
+ Exec *exec;
+ char name[128], *filename, *sysname;
+
+ if((ea = etheraddr(ctlrno)) == 0){
+ print("invalid ctlrno %d\n", ctlrno);
+ return -1;
+ }
+
+ filename = 0;
+ sysname = 0;
+ if(file && *file){
+ strcpy(name, file);
+ if(filename = strchr(name, ':')){
+ if(filename != name && *(filename-1) != '\\'){
+ sysname = name;
+ *filename++ = 0;
+ }
+ }
+ else
+ filename = name;
+ }
+
+
+ memset(&req, 0, sizeof(req));
+ req.op = Bootrequest;
+ req.htype = 1; /* ethernet */
+ req.hlen = Eaddrlen; /* ethernet */
+ memmove(req.chaddr, ea, Eaddrlen);
+
+ myaddr.ip = 0;
+ myaddr.port = BPportsrc;
+ memmove(myaddr.ea, ea, Eaddrlen);
+
+ for(i = 0; i < 10; i++) {
+ server.ip = Bcastip;
+ server.port = BPportdst;
+ memmove(server.ea, broadcast, sizeof(server.ea));
+ udpsend(ctlrno, &server, &req, sizeof(req));
+ if(udprecv(ctlrno, &server, &rep, sizeof(rep)) <= 0)
+ continue;
+ if(memcmp(req.chaddr, rep.chaddr, Eaddrlen))
+ continue;
+ if(rep.htype != 1 || rep.hlen != Eaddrlen)
+ continue;
+ if(sysname == 0 || strcmp(sysname, rep.sname) == 0)
+ break;
+ }
+ if(i >= 10) {
+ print("bootp timed out\n");
+ return -1;
+ }
+
+ if(filename == 0 || *filename == 0)
+ filename = rep.file;
+
+ if(rep.sname[0] != '\0')
+ print("%s ", rep.sname);
+ print("(%d.%d.%d.%d!%d): %s\n",
+ rep.siaddr[0],
+ rep.siaddr[1],
+ rep.siaddr[2],
+ rep.siaddr[3],
+ server.port,
+ filename);uartwait();
+
+ myaddr.ip = nhgetl(rep.yiaddr);
+ myaddr.port = tftpport++;
+ server.ip = nhgetl(rep.siaddr);
+ server.port = TFTPport;
+
+ if((dlen = tftpopen(ctlrno, &server, filename, &tftpb)) < 0)
+ return -1;
+ exec = (Exec*)(tftpb.data);
+ if(dlen < sizeof(Exec) || GLLONG(exec->magic) != Q_MAGIC){
+ nak(ctlrno, &server, 0, "bad magic number", 1);
+ return -1;
+ }
+ text = GLLONG(exec->text);
+ data = GLLONG(exec->data);
+ bss = GLLONG(exec->bss);
+ total = text+data+bss;
+ entry = GLLONG(exec->entry);
+print("load@%8.8lux: ", PADDR(entry));uartwait();
+ print("%d", text);
+
+ addr = (uchar*)PADDR(entry);
+ p = tftpb.data+sizeof(Exec);
+ dlen -= sizeof(Exec);
+ segsize = text;
+ for(;;){
+ if(dlen == 0){
+ if((dlen = tftpread(ctlrno, &server, &tftpb, sizeof(tftpb.data))) < 0)
+ return -1;
+ p = tftpb.data;
+ }
+ if(segsize <= dlen)
+ i = segsize;
+ else
+ i = dlen;
+ memmove(addr, p, i);
+
+ addr += i;
+ p += i;
+ segsize -= i;
+ dlen -= i;
+
+ if(segsize <= 0){
+ if(data == 0)
+ break;
+ print("+%d", data);
+ segsize = data;
+ data = 0;
+ addr = (uchar*)PGROUND((ulong)addr);
+ }
+ }
+ nak(ctlrno, &server, 3, "ok", 0); /* tftpclose */
+ print("+%d=%d\n", bss, total);
+ print("entry: 0x%lux\n", entry);
+ uartwait();
+ scc2stop();
+ splhi();
+ (*(void(*)(void))(PADDR(entry)))();
+
+ return 0;
+}
diff --git a/os/boot/mpc/clock.c b/os/boot/mpc/clock.c
new file mode 100644
index 00000000..4d2d6bfd
--- /dev/null
+++ b/os/boot/mpc/clock.c
@@ -0,0 +1,71 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+
+enum {
+ Timebase = 4, /* system clock cycles per time base cycle */
+};
+
+void (*archclocktick)(void); /* set by arch*.c when desired */
+
+static ulong clkreload;
+
+void
+delay(int l)
+{
+ ulong i, j;
+
+ j = m->delayloop;
+ while(l-- > 0)
+ for(i=0; i < j; i++)
+ ;
+}
+
+void
+microdelay(int l)
+{
+ ulong i;
+
+ l *= m->delayloop;
+ l /= 1000;
+ if(l <= 0)
+ l = 1;
+ for(i = 0; i < l; i++)
+ ;
+}
+
+void
+clockintr(Ureg*, void*)
+{
+ putdec(clkreload);
+ m->ticks++;
+ checkalarms();
+ if(archclocktick != nil)
+ archclocktick();
+}
+
+void
+clockinit(void)
+{
+ long x;
+
+ m->delayloop = m->cpuhz/1000; /* initial estimate */
+ do {
+ x = gettbl();
+ delay(10);
+ x = gettbl() - x;
+ } while(x < 0);
+
+ /*
+ * fix count
+ */
+ m->delayloop = ((vlong)m->delayloop*(10*m->clockgen/1000))/(x*Timebase);
+ if(m->delayloop == 0)
+ m->delayloop = 1;
+ clkreload = (m->clockgen/Timebase)/HZ-1;
+ putdec(clkreload);
+}
diff --git a/os/boot/mpc/conf.c b/os/boot/mpc/conf.c
new file mode 100644
index 00000000..4ecb4b3e
--- /dev/null
+++ b/os/boot/mpc/conf.c
@@ -0,0 +1,173 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "dosfs.h"
+
+static char *confname[MAXCONF];
+static char *confval[MAXCONF];
+static int nconf;
+
+extern char **ini;
+
+char*
+getconf(char *name)
+{
+ int i;
+
+ for(i = 0; i < nconf; i++)
+ if(strcmp(confname[i], name) == 0)
+ return confval[i];
+ return 0;
+}
+
+/*
+ * read configuration file
+ */
+int
+plan9ini(Dos *dos, char *val)
+{
+ Dosfile rc;
+ int i, n;
+ char *cp, *p, *q, *line[MAXCONF];
+
+ cp = BOOTARGS;
+ if(dos) {
+ if(dosstat(dos, *ini, &rc) <= 0)
+ return -1;
+
+ *cp = 0;
+ n = dosread(&rc, cp, BOOTARGSLEN-1);
+ if(n <= 0)
+ return -1;
+ cp[n] = 0;
+ } else if(val != nil){
+ if(memchr(val, 0, BOOTARGSLEN-1) == nil)
+ return -1;
+ print("Using flash configuration\n");
+ strcpy(cp, val);
+ n = strlen(cp);
+ }else{
+ strcpy(cp, archconfig());
+ n = strlen(cp);
+ }
+
+ /*
+ * Make a working copy.
+ * We could change this to pass the parsed strings
+ * to the booted programme instead of the raw
+ * string, then it only gets done once.
+ */
+ memmove(cp+BOOTARGSLEN, cp, n+1);
+ cp += BOOTARGSLEN;
+
+ /*
+ * Strip out '\r', change '\t' -> ' '.
+ */
+ p = cp;
+ for(q = cp; *q; q++){
+ if(*q == '\r')
+ continue;
+ if(*q == '\t')
+ *q = ' ';
+ *p++ = *q;
+ }
+ *p = 0;
+ n = getcfields(cp, line, MAXCONF, "\n");
+ for(i = 0; i < n; i++){
+ cp = strchr(line[i], '=');
+ if(cp == 0)
+ continue;
+ *cp++ = 0;
+ if(cp - line[i] >= NAMELEN+1)
+ *(line[i]+NAMELEN-1) = 0;
+ confname[nconf] = line[i];
+ confval[nconf] = cp;
+ nconf++;
+ }
+ return 0;
+}
+
+int
+parseether(uchar *to, char *from)
+{
+ char nip[4];
+ char *p;
+ int i;
+
+ p = from;
+ while(*p == ' ')
+ ++p;
+ for(i = 0; i < 6; i++){
+ if(*p == 0)
+ return -1;
+ nip[0] = *p++;
+ if(*p == 0)
+ return -1;
+ nip[1] = *p++;
+ nip[2] = 0;
+ to[i] = strtoul(nip, 0, 16);
+ if(*p == ':')
+ p++;
+ }
+ return 0;
+}
+
+int
+isaconfig(char *class, int ctlrno, ISAConf *isa)
+{
+ char cc[NAMELEN], *p, *q, *r;
+ int n;
+
+ sprint(cc, "%s%d", class, ctlrno);
+ for(n = 0; n < nconf; n++){
+ if(strncmp(confname[n], cc, NAMELEN))
+ continue;
+ isa->nopt = 0;
+ p = confval[n];
+ while(*p){
+ while(*p == ' ' || *p == '\t')
+ p++;
+ if(*p == '\0')
+ break;
+ if(strncmp(p, "type=", 5) == 0){
+ p += 5;
+ for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){
+ if(*p == '\0' || *p == ' ' || *p == '\t')
+ break;
+ *q = *p++;
+ }
+ *q = '\0';
+ }
+ else if(strncmp(p, "port=", 5) == 0)
+ isa->port = strtoul(p+5, &p, 0);
+ else if(strncmp(p, "irq=", 4) == 0)
+ isa->irq = strtoul(p+4, &p, 0);
+ else if(strncmp(p, "mem=", 4) == 0)
+ isa->mem = strtoul(p+4, &p, 0);
+ else if(strncmp(p, "size=", 5) == 0)
+ isa->size = strtoul(p+5, &p, 0);
+ else if(strncmp(p, "ea=", 3) == 0){
+ if(parseether(isa->ea, p+3) == -1)
+ memset(isa->ea, 0, 6);
+ }
+ else if(isa->nopt < NISAOPT){
+ r = isa->opt[isa->nopt];
+ while(*p && *p != ' ' && *p != '\t'){
+ *r++ = *p++;
+ if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1)
+ break;
+ }
+ *r = '\0';
+ isa->nopt++;
+ }
+ while(*p && *p != ' ' && *p != '\t')
+ p++;
+ }
+ return 1;
+ }
+ return 0;
+}
diff --git a/os/boot/mpc/console.c b/os/boot/mpc/console.c
new file mode 100644
index 00000000..9a05c122
--- /dev/null
+++ b/os/boot/mpc/console.c
@@ -0,0 +1,173 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+static Queue* consiq;
+static Queue* consoq;
+
+void
+bothputs(char *s, int n)
+{
+ uartputs(s, n);
+ screenputs(s, n);
+}
+
+static void (*consputs)(char*, int) = bothputs; /* or screenputs */
+
+void
+consinit(void)
+{
+ char *p;
+ int baud, port;
+ static int cgadone;
+
+ p = getconf("console");
+ if(0)
+ if(p == 0 || strcmp(p, "lcd") == 0 || strcmp(p, "screen") == 0){
+ consiq = qopen(4*1024, 0, 0, 0);
+ consoq = qopen(8*1024, 0, 0, 0);
+ consputs = screenputs;
+ return;
+ }
+ if(p!=0 && strstr(p, "lcd") == 0)
+ consputs = bothputs;
+ else
+ consputs = uartputs;
+//consputs = screenputs;
+ port = 0;
+ if(p)
+ port = strtoul(p, 0, 0);
+ baud = 0;
+ if(p = getconf("baud"))
+ baud = strtoul(p, 0, 0);
+ if(baud == 0)
+ baud = 9600;
+ uartspecial(port, baud, &consiq, &consoq, kbdchar);
+}
+
+void
+kbdchar(Queue *q, int c)
+{
+ c &= 0x7F;
+ if(c == 0x10)
+ panic("^p");
+ qbputc(q, c);
+}
+
+static int
+getline(char *buf, int size, int dotimeout)
+{
+ int c, i=0;
+ ulong start;
+ char echo;
+
+ for (;;) {
+ start = m->ticks;
+ do{
+ if(dotimeout && ((m->ticks - start) > 5*HZ))
+ return -2;
+ c = qbgetc(consiq);
+ }while(c == -1);
+ if(c == '\r')
+ c = '\n'; /* turn carriage return into newline */
+ if(c == '\177')
+ c = '\010'; /* turn delete into backspace */
+ if(c == '\025')
+ echo = '\n'; /* echo ^U as a newline */
+ else
+ echo = c;
+ (*consputs)(&echo, 1);
+
+ if(c == '\010'){
+ if(i > 0)
+ i--; /* bs deletes last character */
+ continue;
+ }
+ /* a newline ends a line */
+ if (c == '\n')
+ break;
+ /* ^U wipes out the line */
+ if (c =='\025')
+ return -1;
+ if(i == size)
+ return size;
+ buf[i++] = c;
+ }
+ buf[i] = 0;
+ return i;
+}
+
+int
+getstr(char *prompt, char *buf, int size, char *def)
+{
+ int len, isdefault;
+
+ buf[0] = 0;
+ isdefault = (def && *def);
+ for (;;) {
+ if(isdefault)
+ print("%s[default==%s]: ", prompt, def);
+ else
+ print("%s: ", prompt);
+ len = getline(buf, size, isdefault);
+ switch(len){
+ case -1:
+ /* ^U typed */
+ continue;
+ case -2:
+ /* timeout, use default */
+ (*consputs)("\n", 1);
+ len = 0;
+ break;
+ default:
+ break;
+ }
+ if(len >= size){
+ print("line too long\n");
+ continue;
+ }
+ break;
+ }
+ if(len == 0 && isdefault)
+ strcpy(buf, def);
+ return 0;
+}
+
+int
+sprint(char *s, char *fmt, ...)
+{
+ return donprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s;
+}
+
+int
+print(char *fmt, ...)
+{
+ char buf[PRINTSIZE];
+ int n;
+
+ if(consputs == 0)
+ return 0;
+ n = donprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
+ (*consputs)(buf, n);
+ return n;
+}
+
+void
+panic(char *fmt, ...)
+{
+ char buf[PRINTSIZE];
+ int n;
+
+ if(consputs){
+ (*consputs)("panic: ", 7);
+ n = donprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
+ (*consputs)(buf, n);
+ (*consputs)("\n", 1);
+ }
+ spllo();
+ for(;;)
+ idle();
+}
diff --git a/os/boot/mpc/cpm.c b/os/boot/mpc/cpm.c
new file mode 100644
index 00000000..a9a45d60
--- /dev/null
+++ b/os/boot/mpc/cpm.c
@@ -0,0 +1,162 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+enum {
+ BDSIZE= 1024, /* TO DO: check this */
+};
+
+static Map bdmapv[BDSIZE/sizeof(BD)];
+static RMap bdmap = {"buffer descriptors"};
+
+void
+cpminit(void)
+{
+ IMM *io;
+
+ io = m->iomem;
+ io->sdcr = 1;
+ io->lccr &= ~1; /* disable LCD */
+ io->pcint = 0; /* disable all port C interrupts */
+ io->pcso = 0;
+ io->pcdir =0;
+ io->pcpar = 0;
+ io->pcdat = 0;
+ io->papar = 0;
+ io->padir = 0;
+ io->paodr = 0;
+ io->padat = 0;
+ io->pbpar = 0;
+ io->pbdir = 0;
+ io->pbodr = 0;
+ io->pbdat = 0;
+ eieio();
+
+ for(io->cpcr = 0x8001; io->cpcr & 1;) /* reset all CPM channels */
+ eieio();
+
+ mapinit(&bdmap, bdmapv, sizeof(bdmapv));
+ mapfree(&bdmap, DPBASE, BDSIZE);
+}
+
+void
+cpmop(int op, int cno, int param)
+{
+ IMM *io;
+ int s;
+
+ s = splhi();
+ io = m->iomem;
+ eieio();
+ while(io->cpcr & 1)
+ eieio();
+ io->cpcr = (op<<8)|(cno<<4)|(param<<1)|1;
+ eieio();
+ while(io->cpcr & 1)
+ eieio();
+ splx(s);
+}
+
+/*
+ * connect SCCx clocks in NSMI mode (x=1 for USB)
+ */
+void
+sccnmsi(int x, int rcs, int tcs)
+{
+ IMM *io;
+ ulong v;
+ int sh;
+
+ sh = (x-1)*8; /* each SCCx field in sicr is 8 bits */
+ v = (((rcs&7)<<3) | (tcs&7)) << sh;
+ io = ioplock();
+ io->sicr = (io->sicr & ~(0xFF<<sh)) | v;
+ iopunlock();
+}
+
+void
+scc2stop(void)
+{
+ SCC *scc;
+
+ scc = IOREGS(0xA20, SCC);
+ if(scc->gsmrl & (3<<4)){
+ cpmop(GracefulStopTx, SCC2ID, 0);
+ cpmop(CloseRxBD, SCC2ID, 0);
+ delay(1);
+ scc->gsmrl &= ~(3<<4); /* disable current use */
+ archetherdisable(SCC2ID);
+ }
+}
+
+BD *
+bdalloc(int n)
+{
+ ulong a;
+
+ a = mapalloc(&bdmap, 0, n*sizeof(BD), 0);
+ if(a == 0)
+ panic("bdalloc");
+ return KADDR(a);
+}
+
+void
+bdfree(BD *b, int n)
+{
+ if(b){
+ eieio();
+ mapfree(&bdmap, PADDR(b), n*sizeof(BD));
+ }
+}
+
+/*
+ * initialise receive and transmit buffer rings.
+ */
+int
+ioringinit(Ring* r, int nrdre, int ntdre, int bufsize)
+{
+ int i, x;
+
+ /* the ring entries must be aligned on sizeof(BD) boundaries */
+ r->nrdre = nrdre;
+ if(r->rdr == nil)
+ r->rdr = bdalloc(nrdre);
+ /* the buffer size must align with cache lines since the cache doesn't snoop */
+ bufsize = (bufsize+CACHELINESZ-1)&~(CACHELINESZ-1);
+ if(r->rrb == nil)
+ r->rrb = malloc(nrdre*bufsize);
+ if(r->rdr == nil || r->rrb == nil)
+ return -1;
+ dcflush(r->rrb, nrdre*bufsize);
+ x = PADDR(r->rrb);
+ for(i = 0; i < nrdre; i++){
+ r->rdr[i].length = 0;
+ r->rdr[i].addr = x;
+ r->rdr[i].status = BDEmpty|BDInt;
+ x += bufsize;
+ }
+ r->rdr[i-1].status |= BDWrap;
+ r->rdrx = 0;
+
+ r->ntdre = ntdre;
+ if(r->tdr == nil)
+ r->tdr = bdalloc(ntdre);
+ if(r->txb == nil)
+ r->txb = malloc(ntdre*sizeof(Block*));
+ if(r->tdr == nil || r->txb == nil)
+ return -1;
+ for(i = 0; i < ntdre; i++){
+ r->txb[i] = nil;
+ r->tdr[i].addr = 0;
+ r->tdr[i].length = 0;
+ r->tdr[i].status = 0;
+ }
+ r->tdr[i-1].status |= BDWrap;
+ r->tdrh = 0;
+ r->tdri = 0;
+ r->ntq = 0;
+ return 0;
+}
diff --git a/os/boot/mpc/crc32.c b/os/boot/mpc/crc32.c
new file mode 100644
index 00000000..78bdacba
--- /dev/null
+++ b/os/boot/mpc/crc32.c
@@ -0,0 +1,42 @@
+#include "boot.h"
+
+/*
+ * from Rob Warnock
+ */
+static ulong crc32tab[256]; /* initialised on first call to crc32 */
+
+enum {
+ CRC32POLY = 0x04c11db7 /* AUTODIN II, Ethernet, & FDDI */
+};
+
+/*
+ * Build auxiliary table for parallel byte-at-a-time CRC-32.
+ */
+static void
+initcrc32(void)
+{
+ int i, j;
+ ulong c;
+
+ for(i = 0; i < 256; i++) {
+ for(c = i << 24, j = 8; j > 0; j--)
+ if(c & (1<<31))
+ c = (c<<1) ^ CRC32POLY;
+ else
+ c <<= 1;
+ crc32tab[i] = c;
+ }
+}
+
+ulong
+crc32(void *buf, int n, ulong crc)
+{
+ uchar *p;
+
+ if(crc32tab[1] == 0)
+ initcrc32();
+ crc = ~crc;
+ for(p = buf; --n >= 0;)
+ crc = (crc << 8) ^ crc32tab[(crc >> 24) ^ *p++];
+ return ~crc;
+}
diff --git a/os/boot/mpc/dat.h b/os/boot/mpc/dat.h
new file mode 100644
index 00000000..edadc030
--- /dev/null
+++ b/os/boot/mpc/dat.h
@@ -0,0 +1,217 @@
+typedef struct Alarm Alarm;
+typedef struct Block Block;
+typedef struct IMM IMM;
+typedef struct Queue Queue;
+
+typedef struct List {
+ void *next;
+} List;
+
+typedef struct {
+ int fake;
+ int pri;
+} Lock;
+#define lock(x)
+#define unlock(x)
+
+struct Alarm {
+ List;
+ int busy;
+ long dt;
+ void (*f)(Alarm*);
+ void *arg;
+};
+
+enum {
+ Eaddrlen = 6,
+ ETHERMINTU = 60, /* minimum transmit size */
+ ETHERMAXTU = 1514, /* maximum transmit size */
+ ETHERHDRSIZE = 14, /* size of an ethernet header */
+
+ MaxEther = 4,
+};
+
+typedef struct {
+ uchar d[Eaddrlen];
+ uchar s[Eaddrlen];
+ uchar type[2];
+ uchar data[1500];
+ uchar crc[4];
+} Etherpkt;
+
+extern uchar broadcast[Eaddrlen];
+
+enum {
+ Npart = 20+2, /* 8 sub partitions, disk, and partition */
+ Maxxfer = 16*1024, /* maximum transfer size/cmd */
+};
+
+typedef struct {
+ ulong start;
+ ulong end;
+ char name[NAMELEN+1];
+} Partition;
+
+typedef struct {
+ int online;
+ int npart; /* number of real partitions */
+ Partition p[Npart];
+ ulong offset;
+ Partition *current; /* current partition */
+
+ ulong cap; /* total bytes */
+ int bytes; /* bytes/sector */
+ int sectors; /* sectors/track */
+ int heads; /* heads/cyl */
+ long cyl; /* cylinders/drive */
+
+ char lba; /* true if drive has logical block addressing */
+ char multi; /* non-zero if drive does multiple block xfers */
+} Disc;
+
+enum {
+ ScsiTestunit = 0x00,
+ ScsiExtsens = 0x03,
+ ScsiInquiry = 0x12,
+ ScsiModesense = 0x1a,
+ ScsiStartunit = 0x1B,
+ ScsiStopunit = 0x1B,
+ ScsiGetcap = 0x25,
+ ScsiRead = 0x08,
+ ScsiWrite = 0x0a,
+ ScsiExtread = 0x28,
+ ScsiExtwrite = 0x2a,
+
+ /* data direction */
+ ScsiIn = 1,
+ ScsiOut = 0,
+};
+
+typedef struct Scsibuf Scsibuf;
+typedef struct Scsibuf {
+ void* virt;
+ void* phys;
+ Scsibuf* next;
+};
+
+typedef struct Scsidata {
+ uchar* base;
+ uchar* lim;
+ uchar* ptr;
+} Scsidata;
+
+typedef struct Ureg Ureg;
+
+typedef struct Scsi {
+ ulong pid;
+ ushort target;
+ ushort lun;
+ ushort rflag;
+ ushort status;
+ Scsidata cmd;
+ Scsidata data;
+ Scsibuf* b;
+ uchar* save;
+ uchar cmdblk[16];
+} Scsi;
+
+typedef struct Segdesc {
+ ulong d0;
+ ulong d1;
+} Segdesc;
+
+typedef struct Mach {
+ ulong ticks; /* of the clock since boot time */
+ ulong delayloop;
+ long cpuhz; /* general system clock (cycles) */
+ long clockgen; /* clock generator frequency (cycles) */
+ ulong cpupvr; /* cpu type in processor version register */
+ ulong cputype; /* cpu variant in BCD (eg, 0x823xx) */
+ void* alarm; /* alarms bound to this clock */
+ ulong* bcsr;
+ IMM* iomem;
+} Mach;
+
+/* Mach.cputype */
+#define MPCREV(x) ((x) & 0xFF)
+#define MPCMODEL(x) (((x)>>8) & 0xFFF)
+#define MPCFAMILY(x) (((x)>>24) & 0x0F)
+
+
+extern Mach *m;
+
+#define Q_MAGIC ((((4*21)+0)*21)+7)
+
+typedef struct Exec Exec;
+struct Exec
+{
+ uchar magic[4]; /* magic number */
+ uchar text[4]; /* size of text segment */
+ uchar data[4]; /* size of initialized data */
+ uchar bss[4]; /* size of uninitialized data */
+ uchar syms[4]; /* size of symbol table */
+ uchar entry[4]; /* entry point */
+ uchar spsz[4]; /* size of sp/pc offset table */
+ uchar pcsz[4]; /* size of pc/line number table */
+};
+
+/*
+ * bootline passed by boot program
+ */
+#define BOOTLINE ((char *)0x200000-150)
+
+/*
+ * Where we leave configuration info.
+ */
+#define BOOTARGS ((char*)(0x200000))
+#define BOOTARGSLEN 1024
+#define MAXCONF 32
+
+/*
+ * a parsed plan9.ini line
+ */
+#define ISAOPTLEN 16
+#define NISAOPT 8
+
+typedef struct ISAConf {
+ char type[NAMELEN];
+ ulong port;
+ ulong irq;
+ ulong mem;
+ ulong size;
+ uchar ea[6];
+
+ int nopt;
+ char opt[NISAOPT][ISAOPTLEN];
+} ISAConf;
+
+typedef struct {
+ int size;
+ ulong addr;
+} Map;
+
+typedef struct {
+ char* name;
+ Map* map;
+ Map* mapend;
+
+ Lock;
+} RMap;
+
+typedef struct PCIcfg PCIcfg;
+
+extern uchar* vgamem;
+
+struct Block {
+ uchar *rp;
+ uchar *wp;
+ uchar *lim;
+ uchar *data;
+ Block* next;
+ ulong magic;
+};
+#define BLEN(b) ((b)->wp-(b)->rp)
+
+typedef struct QLock {
+ int dummy;
+} QLock;
diff --git a/os/boot/mpc/defont0.c b/os/boot/mpc/defont0.c
new file mode 100644
index 00000000..9a25e1bd
--- /dev/null
+++ b/os/boot/mpc/defont0.c
@@ -0,0 +1,216 @@
+#include <u.h>
+#include <libc.h>
+#include <libg.h>
+#include <gnot.h>
+
+
+
+static ulong bits0[] = {
+ 0x907070f0, 0xf0f07000, 0xf0888888, 0xf8707070, 0xe0e0e0e0, 0xe09070f0, 0x70f870f0, 0xf870f088,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000e0,
+ 0xd0808080, 0x80808800, 0x8888c888, 0x80888888, 0x90909090, 0x90d08080, 0x80808080, 0x80888888,
+ 0x00000000, 0x08000000, 0x0c300000, 0x00000006, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000003c, 0xc03c0000,
+ 0x00006000, 0x06001e00, 0x60181860, 0x78000000, 0x00000000, 0x00000000, 0x0000001c, 0x18380090,
+ 0xb06060e0, 0xe0e0f800, 0xf088a888, 0x80808080, 0x90909090, 0x90b060e0, 0x808060e0, 0x80808888,
+ 0x00182428, 0x3e707018, 0x18180000, 0x00000006, 0x3c183c3c, 0x1c3e3c7e, 0x3c3c0000, 0x0200403c,
+ 0x3c187c1e, 0x787e7e1e, 0x663c7c66, 0x6066623c, 0x7c3c7c3c, 0x7e6266c2, 0x66667e30, 0xc00c1000,
+ 0x08006000, 0x06003000, 0x60181860, 0x18000000, 0x00000000, 0x10000000, 0x00000030, 0x180c0090,
+ 0x90101080, 0x80808818, 0x88f8a888, 0xe0807070, 0xe0e0e0e0, 0xe0901080, 0x70e01080, 0xe098f088,
+ 0x00182428, 0x6adad818, 0x18181000, 0x0000000c, 0x66386666, 0x2c3e667e, 0x66660000, 0x06006066,
+ 0x42186632, 0x6c606032, 0x66181864, 0x60667224, 0x66246666, 0x186262da, 0x62620630, 0x600c3800,
+ 0x10006000, 0x06003000, 0x60000060, 0x18000000, 0x00000000, 0x30000000, 0x00000030, 0x180c00e0,
+ 0x00e0e0f0, 0xf0f00018, 0x88889850, 0x80880808, 0x201c1c1c, 0x1c00e0f0, 0x0080e0f0, 0x80888888,
+ 0x00182428, 0x68dad808, 0x300c5418, 0x0000000c, 0x66580606, 0x2c206002, 0x66661818, 0x0cfe3006,
+ 0x9e2c6660, 0x66606060, 0x6618186c, 0x60667266, 0x66666660, 0x186262da, 0x36660c30, 0x600c2800,
+ 0x103c6c3c, 0x3e3c7e3e, 0x6c787866, 0x18d46c3c, 0x6c3e763c, 0x7e6666c2, 0x66667e18, 0x18180000,
+ 0x44180000, 0x18241c24, 0xf0888820, 0x8070f0f0, 0x20202020, 0x201c243e, 0x1cf8241c, 0x80708870,
+ 0x0018247c, 0x78745008, 0x300c3818, 0x00000018, 0x66180606, 0x4c206006, 0x76661818, 0x18fe180c,
+ 0xb62c6660, 0x66606060, 0x66181868, 0x607e5a66, 0x66666470, 0x186266da, 0x34340c30, 0x300c6c00,
+ 0x18667666, 0x66663066, 0x76181864, 0x18fe7666, 0x76663666, 0x306662da, 0x62620608, 0x1810323c,
+ 0x44247c7c, 0x24342042, 0x00000000, 0x00000000, 0x20202020, 0x20222408, 0x22002420, 0x00000000,
+ 0x00180028, 0x3c287610, 0x300cee7e, 0x00fe0018, 0x66180c18, 0x4c3c7c0c, 0x3c3e0000, 0x30000c18,
+ 0xb62c7c60, 0x667c7c6e, 0x7e181878, 0x605a5a66, 0x6466783c, 0x186234da, 0x18341830, 0x300c4400,
+ 0x18066660, 0x66663066, 0x66181868, 0x18d66666, 0x66663860, 0x306662da, 0x34620c30, 0x180c5a20,
+ 0x44241010, 0x242c2042, 0x0e3e103e, 0x3e3c1c3e, 0x3c1c1c1c, 0x1c3e1c08, 0x3e222418, 0x0e0e0e0e,
+ 0x0008007c, 0x1e5cdc00, 0x300c387e, 0x00fe0030, 0x66181806, 0x7e066618, 0x6e060000, 0x18001818,
+ 0xb67e6660, 0x66606066, 0x6618186c, 0x605a4e66, 0x78666c0e, 0x1862346c, 0x2c183030, 0x180c4400,
+ 0x003e6660, 0x667e3066, 0x66181878, 0x18d66666, 0x6666303c, 0x306634da, 0x18341808, 0x18104c38,
+ 0x3c181010, 0x18241c42, 0x11081008, 0x20222208, 0x00000000, 0x00220408, 0x22361804, 0x11111111,
+ 0x00000028, 0x16b6cc00, 0x300c5418, 0x00000030, 0x66183006, 0x7e066618, 0x66060000, 0x0cfe3000,
+ 0x9a466660, 0x66606066, 0x6618186c, 0x605a4e66, 0x60666606, 0x1862346c, 0x6c183030, 0x180c0000,
+ 0x00666660, 0x66603066, 0x6618186c, 0x18d66666, 0x66663006, 0x3066346c, 0x2c343018, 0x18180020,
+ 0x00091010, 0x000e0942, 0x10081008, 0x20222208, 0x0f06060f, 0x0a09041e, 0x002a0e38, 0x10101010,
+ 0x00180028, 0x56b6cc00, 0x300c1018, 0x18001860, 0x66187e66, 0x0c666630, 0x66661818, 0x06fe6018,
+ 0x40466632, 0x6c606036, 0x66181866, 0x605a4624, 0x60246666, 0x1834186c, 0x46186030, 0x0c0c0000,
+ 0x006e6666, 0x6e66306e, 0x66181866, 0x18d66666, 0x666e3066, 0x306e186c, 0x46186030, 0x180c003c,
+ 0x08090909, 0x1f110aff, 0x0e081008, 0x382c2208, 0x08020901, 0x0a0a0911, 0x09220907, 0x0e0e0e0e,
+ 0x00180028, 0x7c1c7600, 0x18180000, 0x18001860, 0x3c7e7e3c, 0x0c3c3c30, 0x3c3c1818, 0x02004018,
+ 0x3e467c1e, 0x787e601e, 0x663c1866, 0x7e42463c, 0x603c663c, 0x1818186c, 0x66187e30, 0x0c0c0000,
+ 0x00367c3c, 0x363c7c36, 0x667e1866, 0x7ed6663c, 0x7c367c3c, 0x1e36186c, 0x66187e30, 0x180c0008,
+ 0x080f0606, 0x04110c18, 0x01081008, 0x20222208, 0x0e020203, 0x0a0c0d1e, 0x0d220e08, 0x01010101,
+ 0x00000000, 0x10000000, 0x18180000, 0x080000c0, 0x00000000, 0x00000000, 0x00000008, 0x00000000,
+ 0x00000000, 0x00000000, 0x00001800, 0x00000000, 0x000c0000, 0x00000000, 0x00000030, 0x060c00fe,
+ 0x00000000, 0x00000006, 0x00001800, 0x00000000, 0x60060000, 0x00000000, 0x0010001c, 0x18380008,
+ 0x08090606, 0x040e0a18, 0x11081f08, 0x20221c3e, 0x08020401, 0x0f0a0b11, 0x0b220908, 0x11111111,
+ 0x00000000, 0x00000000, 0x0c300000, 0x080000c0, 0x00000000, 0x00000000, 0x00000008, 0x00000000,
+ 0x00000000, 0x00000000, 0x00007000, 0x00000000, 0x00060000, 0x00000000, 0x0000003c, 0x063c0000,
+ 0x00000000, 0x00000066, 0x00001800, 0x00000000, 0x60060000, 0x00000000, 0x00300000, 0x00000008,
+ 0x0f090909, 0x04030900, 0x0e000000, 0x00000000, 0x0f0f0f0f, 0x0209091e, 0x09000f07, 0x0e0e0e0e,
+ 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x00000000, 0x00000000, 0x00000010, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x0000003c, 0x00007000, 0x00000000, 0x60060000, 0x00000000, 0x00600000, 0x0000000f,
+
+};
+
+static GBitmap strike0 = {
+ bits0,
+ 0,
+ 32,
+ 0,
+ {0, 0, 1024, 14},
+ {0, 0, 1024, 14},
+};
+
+static Fontchar info0[] = {
+ { 0, 0, 14, 0, 8 },
+ { 8, 0, 14, 0, 8 },
+ { 16, 0, 14, 0, 8 },
+ { 24, 0, 14, 0, 8 },
+ { 32, 0, 14, 0, 8 },
+ { 40, 0, 14, 0, 8 },
+ { 48, 0, 14, 0, 8 },
+ { 56, 0, 14, 0, 8 },
+ { 64, 0, 14, 0, 8 },
+ { 72, 0, 14, 0, 8 },
+ { 80, 0, 14, 0, 8 },
+ { 88, 0, 14, 0, 8 },
+ { 96, 0, 14, 0, 8 },
+ { 104, 0, 14, 0, 8 },
+ { 112, 0, 14, 0, 8 },
+ { 120, 0, 14, 0, 8 },
+ { 128, 0, 14, 0, 8 },
+ { 136, 0, 14, 0, 8 },
+ { 144, 0, 14, 0, 8 },
+ { 152, 0, 14, 0, 8 },
+ { 160, 0, 14, 0, 8 },
+ { 168, 0, 14, 0, 8 },
+ { 176, 0, 14, 0, 8 },
+ { 184, 0, 14, 0, 8 },
+ { 192, 0, 14, 0, 8 },
+ { 200, 0, 14, 0, 8 },
+ { 208, 0, 14, 0, 8 },
+ { 216, 0, 14, 0, 8 },
+ { 224, 0, 14, 0, 8 },
+ { 232, 0, 14, 0, 8 },
+ { 240, 0, 14, 0, 8 },
+ { 248, 0, 14, 0, 8 },
+ { 256, 0, 0, 0, 8 },
+ { 264, 2, 11, 0, 8 },
+ { 272, 2, 6, 0, 8 },
+ { 280, 2, 11, 0, 8 },
+ { 288, 1, 12, 0, 8 },
+ { 296, 2, 11, 0, 8 },
+ { 304, 2, 11, 0, 8 },
+ { 312, 2, 7, 0, 8 },
+ { 320, 1, 13, 0, 8 },
+ { 328, 1, 13, 0, 8 },
+ { 336, 3, 10, 0, 8 },
+ { 344, 4, 10, 0, 8 },
+ { 352, 9, 14, 0, 8 },
+ { 360, 6, 8, 0, 8 },
+ { 368, 9, 11, 0, 8 },
+ { 376, 1, 13, 0, 8 },
+ { 384, 2, 11, 0, 8 },
+ { 392, 2, 11, 0, 8 },
+ { 400, 2, 11, 0, 8 },
+ { 408, 2, 11, 0, 8 },
+ { 416, 2, 11, 0, 8 },
+ { 424, 2, 11, 0, 8 },
+ { 432, 2, 11, 0, 8 },
+ { 440, 2, 11, 0, 8 },
+ { 448, 2, 11, 0, 8 },
+ { 456, 2, 11, 0, 8 },
+ { 464, 4, 11, 0, 8 },
+ { 472, 4, 14, 0, 8 },
+ { 480, 2, 11, 0, 8 },
+ { 488, 4, 10, 0, 8 },
+ { 496, 2, 11, 0, 8 },
+ { 504, 2, 11, 0, 8 },
+ { 512, 2, 11, 0, 8 },
+ { 520, 2, 11, 0, 8 },
+ { 528, 2, 11, 0, 8 },
+ { 536, 2, 11, 0, 8 },
+ { 544, 2, 11, 0, 8 },
+ { 552, 2, 11, 0, 8 },
+ { 560, 2, 11, 0, 8 },
+ { 568, 2, 11, 0, 8 },
+ { 576, 2, 11, 0, 8 },
+ { 584, 2, 11, 0, 8 },
+ { 592, 2, 13, 0, 8 },
+ { 600, 2, 11, 0, 8 },
+ { 608, 2, 11, 0, 8 },
+ { 616, 2, 11, 0, 8 },
+ { 624, 2, 11, 0, 8 },
+ { 632, 2, 11, 0, 8 },
+ { 640, 2, 11, 0, 8 },
+ { 648, 2, 13, 0, 8 },
+ { 656, 2, 11, 0, 8 },
+ { 664, 2, 11, 0, 8 },
+ { 672, 2, 11, 0, 8 },
+ { 680, 2, 11, 0, 8 },
+ { 688, 2, 11, 0, 8 },
+ { 696, 2, 11, 0, 8 },
+ { 704, 2, 11, 0, 8 },
+ { 712, 2, 11, 0, 8 },
+ { 720, 2, 11, 0, 8 },
+ { 728, 1, 13, 0, 8 },
+ { 736, 1, 13, 0, 8 },
+ { 744, 1, 13, 0, 8 },
+ { 752, 2, 8, 0, 8 },
+ { 760, 11, 12, 0, 8 },
+ { 768, 2, 7, 0, 8 },
+ { 776, 4, 11, 0, 8 },
+ { 784, 1, 11, 0, 8 },
+ { 792, 4, 11, 0, 8 },
+ { 800, 1, 11, 0, 8 },
+ { 808, 4, 11, 0, 8 },
+ { 816, 1, 11, 0, 8 },
+ { 824, 4, 14, 0, 8 },
+ { 832, 1, 11, 0, 8 },
+ { 840, 1, 11, 0, 8 },
+ { 848, 1, 14, 0, 8 },
+ { 856, 1, 11, 0, 8 },
+ { 864, 1, 11, 0, 8 },
+ { 872, 4, 11, 0, 8 },
+ { 880, 4, 11, 0, 8 },
+ { 888, 4, 11, 0, 8 },
+ { 896, 4, 14, 0, 8 },
+ { 904, 4, 14, 0, 8 },
+ { 912, 4, 11, 0, 8 },
+ { 920, 4, 11, 0, 8 },
+ { 928, 2, 11, 0, 8 },
+ { 936, 4, 11, 0, 8 },
+ { 944, 4, 11, 0, 8 },
+ { 952, 4, 11, 0, 8 },
+ { 960, 4, 11, 0, 8 },
+ { 968, 4, 14, 0, 8 },
+ { 976, 4, 11, 0, 8 },
+ { 984, 1, 12, 0, 8 },
+ { 992, 1, 12, 0, 8 },
+ { 1000, 1, 12, 0, 8 },
+ { 1008, 5, 8, 0, 8 },
+ { 1016, 0, 14, 0, 8 },
+ { 1024, 0, 14, 0, 8 },
+ { 0, 0, 0, 0, 0 }
+};
+
+GSubfont defont0 = {
+ 129,
+ 14,
+ 2,
+ info0,
+ &strike0,
+};
diff --git a/os/boot/mpc/devether.c b/os/boot/mpc/devether.c
new file mode 100644
index 00000000..5c5ac792
--- /dev/null
+++ b/os/boot/mpc/devether.c
@@ -0,0 +1,157 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "etherif.h"
+
+static Ctlr ether[MaxEther];
+
+static struct {
+ char *type;
+ int (*reset)(Ctlr*);
+} cards[] = {
+ { "SCC", sccethreset, },
+ { "SCC2", sccethreset, },
+ { 0, }
+};
+
+int
+etherinit(void)
+{
+ Ctlr *ctlr;
+ int ctlrno, i, mask, n;
+
+ mask = 0;
+ for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
+ ctlr = &ether[ctlrno];
+ memset(ctlr, 0, sizeof(Ctlr));
+ if(isaconfig("ether", ctlrno, &ctlr->card) == 0)
+ continue;
+ for(n = 0; cards[n].type; n++){
+ if(strcmp(cards[n].type, ctlr->card.type))
+ continue;
+ ctlr->ctlrno = ctlrno;
+ if((*cards[n].reset)(ctlr))
+ break;
+
+ ctlr->iq = qopen(16*1024, 1, 0, 0);
+ ctlr->oq = qopen(16*1024, 1, 0, 0);
+
+ ctlr->present = 1;
+ mask |= 1<<ctlrno;
+
+ print("ether%d: %s: port 0x%luX irq %d",
+ ctlr->ctlrno, ctlr->card.type, ctlr->card.port, ctlr->card.irq);
+ if(ctlr->card.mem)
+ print(" addr 0x%luX", PADDR(ctlr->card.mem));
+ if(ctlr->card.size)
+ print(" size 0x%luX", ctlr->card.size);
+ print(":");
+ for(i = 0; i < sizeof(ctlr->card.ea); i++)
+ print(" %2.2uX", ctlr->card.ea[i]);
+ print("\n"); uartwait();
+ setvec(VectorPIC + ctlr->card.irq, ctlr->card.intr, ctlr);
+ break;
+ }
+ }
+
+ return mask;
+}
+
+static Ctlr*
+attach(int ctlrno)
+{
+ Ctlr *ctlr;
+
+ if(ctlrno >= MaxEther || ether[ctlrno].present == 0)
+ return 0;
+
+ ctlr = &ether[ctlrno];
+ if(ctlr->present == 1){
+ ctlr->present = 2;
+ (*ctlr->card.attach)(ctlr);
+ }
+
+ return ctlr;
+}
+
+uchar*
+etheraddr(int ctlrno)
+{
+ Ctlr *ctlr;
+
+ if((ctlr = attach(ctlrno)) == 0)
+ return 0;
+
+ return ctlr->card.ea;
+}
+
+int
+etherrxpkt(int ctlrno, Etherpkt *pkt, int timo)
+{
+ int n;
+ Ctlr *ctlr;
+ Block *b;
+ ulong start;
+
+ if((ctlr = attach(ctlrno)) == 0)
+ return 0;
+
+ start = m->ticks;
+ while((b = qget(ctlr->iq)) == 0){
+ if(TK2MS(m->ticks - start) >= timo){
+ /*
+ print("ether%d: rx timeout\n", ctlrno);
+ */
+ return 0;
+ }
+ }
+
+ n = BLEN(b);
+ memmove(pkt, b->rp, n);
+ freeb(b);
+
+ return n;
+}
+
+int
+etheriq(Ctlr *ctlr, Block *b, int freebp)
+{
+ if(memcmp(((Etherpkt*)b->rp)->d, ctlr->card.ea, Eaddrlen) != 0 &&
+ memcmp(((Etherpkt*)b->rp)->d, broadcast, Eaddrlen) != 0){
+ if(freebp)
+ freeb(b);
+ return 0;
+ }
+ qbwrite(ctlr->iq, b);
+ return 1;
+}
+
+int
+ethertxpkt(int ctlrno, Etherpkt *pkt, int len, int)
+{
+ Ctlr *ctlr;
+ Block *b;
+ int s;
+
+ if((ctlr = attach(ctlrno)) == 0)
+ return 0;
+
+ if(qlen(ctlr->oq) > 16*1024){
+ print("ether%d: tx queue full\n", ctlrno);
+ return 0;
+ }
+ b = iallocb(sizeof(Etherpkt));
+ memmove(b->wp, pkt, len);
+ memmove(((Etherpkt*)b->wp)->s, ctlr->card.ea, Eaddrlen);
+ b->wp += len;
+ qbwrite(ctlr->oq, b);
+ s = splhi();
+ (*ctlr->card.transmit)(ctlr);
+ splx(s);
+
+ return 1;
+}
diff --git a/os/boot/mpc/devuart.c b/os/boot/mpc/devuart.c
new file mode 100644
index 00000000..14e38592
--- /dev/null
+++ b/os/boot/mpc/devuart.c
@@ -0,0 +1,230 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+/*
+ * SMC1 in UART mode
+ */
+
+typedef struct Uartsmc Uartsmc;
+struct Uartsmc {
+ IOCparam;
+ ushort maxidl;
+ ushort idlc;
+ ushort brkln;
+ ushort brkec;
+ ushort brkcr;
+ ushort rmask;
+};
+
+typedef struct Uart Uart;
+struct Uart
+{
+ int port;
+ int setup;
+ uchar txbusy;
+
+ Queue* iq;
+ Queue* oq;
+ void (*rx)(Queue*, int);
+ void (*boot)(uchar*, int);
+
+ ulong frame;
+ ulong overrun;
+ uchar rxbuf[128];
+ char txbuf[16];
+ BD* rxb;
+ BD* txb;
+};
+
+Uart uart[1];
+int predawn = 1;
+
+static void uartintr(Ureg*, void*);
+static void uartkick(void*);
+
+static int
+baudgen(int baud)
+{
+ int d;
+
+ d = ((m->cpuhz/baud)+8)>>4;
+ if(d >= (1<<12))
+ return ((d+15)>>3)|1;
+ return d<<1;
+}
+
+static void
+smcsetup(Uart *up, int baud)
+{
+ IMM *io;
+ Uartsmc *p;
+ BD *bd;
+ SMC *smc;
+
+ archenableuart(SMC1ID, 0);
+ io = m->iomem;
+ io->pbpar |= IBIT(24)|IBIT(25); /* enable SMC1 TX/RX */
+ io->pbdir &= ~(IBIT(24)|IBIT(25));
+ io->brgc1 = baudgen(baud) | BaudEnable;
+ io->simode &= ~0xF000; /* SMC1 to NMSI mode, Tx/Rx clocks are BRG1 */
+
+ bd = bdalloc(1);
+ p = (Uartsmc*)KADDR(SMC1P);
+ p->rbase = (ushort)bd;
+ up->rxb = bd;
+ bd->status = BDEmpty|BDWrap|BDInt;
+ bd->length = 0;
+ bd->addr = PADDR(up->rxbuf);
+ bd = bdalloc(1);
+ p->tbase = (ushort)bd;
+ up->txb = bd;
+ bd->status = BDWrap|BDInt;
+ bd->length = 0;
+ bd->addr = PADDR(up->txbuf);
+
+ cpmop(InitRxTx, SMC1ID, 0);
+
+ /* protocol parameters */
+ p->rfcr = 0x18;
+ p->tfcr = 0x18;
+ p->mrblr = 1;
+ p->maxidl = 1;
+ p->brkln = 0;
+ p->brkec = 0;
+ p->brkcr = 1;
+ smc = IOREGS(0xA80, SMC);
+ smc->smce = 0xff; /* clear events */
+ smc->smcm = 0x17; /* enable all possible interrupts */
+ setvec(VectorCPIC+4, uartintr, up);
+ smc->smcmr = 0x4820; /* 8-bit mode, no parity, 1 stop bit, UART mode, ... */
+ smc->smcmr |= 3; /* enable rx/tx */
+}
+
+static void
+uartintr(Ureg*, void *arg)
+{
+ Uart *up;
+ int ch, i;
+ BD *bd;
+ SMC *smc;
+ Block *b;
+
+ up = arg;
+ smc = IOREGS(0xA80, SMC);
+ smc->smce = 0xff; /* clear all events */
+ if((bd = up->rxb) != nil && (bd->status & BDEmpty) == 0){
+ if(up->iq != nil && bd->length > 0){
+ if(up->boot != nil){
+ up->boot(up->rxbuf, bd->length);
+ }else if(up->rx != nil){
+ for(i=0; i<bd->length; i++){
+ ch = up->rxbuf[i];
+ up->rx(up->iq, ch);
+ }
+ }else{
+ b = iallocb(bd->length);
+ memmove(b->wp, up->rxbuf, bd->length);
+ b->wp += bd->length;
+ qbwrite(up->iq, b);
+ }
+ }
+ bd->status |= BDEmpty|BDInt;
+ } else if((bd = up->txb) != nil && (bd->status & BDReady) == 0){
+ ch = -1;
+ if(up->oq)
+ ch = qbgetc(up->oq);
+ if(ch != -1){
+ up->txbuf[0] = ch;
+ bd->length = 1;
+ bd->status |= BDReady;
+ }else
+ up->txbusy = 0;
+ }
+ /* TO DO: modem status, errors, etc */
+}
+
+static void
+uartkick(void *arg)
+{
+ Uart *up = arg;
+ int s, c, i;
+
+ s = splhi();
+ while(up->txbusy == 0 && (c = qbgetc(up->oq)) != -1){
+ if(predawn){
+ while(up->txb->status & BDReady)
+ ;
+ } else {
+ for(i = 0; i < 100; i++){
+ if((up->txb->status & BDReady) == 0)
+ break;
+ delay(1);
+ }
+ }
+ up->txbuf[0] = c;
+ up->txb->length = 1;
+ up->txb->status |= BDReady;
+ up->txbusy = !predawn;
+ }
+ splx(s);
+}
+
+void
+uartspecial(int port, int baud, Queue **iq, Queue **oq, void (*rx)(Queue*,int))
+{
+ Uart *up = &uart[0];
+
+ if(up->setup)
+ return;
+ up->setup = 1;
+
+ *iq = up->iq = qopen(4*1024, 0, 0, 0);
+ *oq = up->oq = qopen(16*1024, 0, uartkick, up);
+ up->rx = rx;
+ USED(port);
+ up->port = SMC1ID;
+ if(baud == 0)
+ baud = 9600;
+ smcsetup(up, baud);
+ /* if using SCCn's UART, would also set DTR and RTS, but SMC doesn't use them */
+}
+
+void
+uartsetboot(void (*f)(uchar*, int))
+{
+ uart[0].boot = f;
+}
+
+void
+uartputs(char *s, int n)
+{
+ Uart *up = &uart[0];
+ Block *b;
+ int nl;
+ char *p;
+
+ nl = 0;
+ for(p = s; p < s+n; p++)
+ if(*p == '\n')
+ nl++;
+ b = iallocb(n+nl);
+ while(n--){
+ if(*s == '\n')
+ *b->wp++ = '\r';
+ *b->wp++ = *s++;
+ }
+ qbwrite(up->oq, b);
+}
+
+void
+uartwait(void)
+{
+ Uart *up = &uart[0];
+
+ while(up->txbusy)
+ ;
+}
diff --git a/os/boot/mpc/dload.c b/os/boot/mpc/dload.c
new file mode 100644
index 00000000..c05423a2
--- /dev/null
+++ b/os/boot/mpc/dload.c
@@ -0,0 +1,103 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+static char *kernelfile = "/power/ipaq";
+ulong crc32(void *buf, int n, ulong crc);
+
+void
+main(int argc, char **argv)
+{
+ int ifd, n;
+ char buf[64], reply[1];
+ int i, execsize;
+ Fhdr f;
+ ulong csum;
+
+ ARGBEGIN{
+ }ARGEND
+ ifd = open(kernelfile, OREAD);
+ if(ifd < 0){
+ fprint(2, "dload: can't open %s: %r\n", kernelfile);
+ exits("open");
+ }
+ i = 0;
+ if(crackhdr(ifd, &f) == 0){
+ fprint(2, "dload: not an executable file: %r\n");
+ exits("format");
+ }
+ if(f.magic != Q_MAGIC){
+ fprint(2, "dload: not a powerpc executable\n");
+ exits("format");
+ }
+ execsize = f.txtsz + f.datsz + f.txtoff;
+ seek(ifd, 0, 0);
+ csum = ~0;
+ while(execsize > 0 && (n = read(ifd, buf, sizeof(buf))) > 0){
+ if(n > execsize)
+ n = execsize;
+ for(;;){
+ if(write(1, buf, sizeof(buf)) != sizeof(buf)){ /* always writes full buffer */
+ fprint(2, "dload: write error: %r\n");
+ exits("write");
+ }
+ if(read(0, reply, 1) != 1){
+ fprint(2, "dload: bad reply\n");
+ exits("read");
+ }
+ if(reply[0] != 'n')
+ break;
+ fprint(2, "!");
+ }
+ if(reply[0] != 'y'){
+ fprint(2, "dload: bad ack: %c\n", reply[0]);
+ exits("reply");
+ }
+ if(++i%10 == 0)
+ fprint(2, ".");
+ execsize -= n;
+ }
+ exits(0);
+}
+
+/*
+ * from Rob Warnock
+ */
+static ulong crc32tab[256]; /* initialised on first call to crc32 */
+
+enum {
+ CRC32POLY = 0x04c11db7 /* AUTODIN II, Ethernet, & FDDI */
+};
+
+/*
+ * Build auxiliary table for parallel byte-at-a-time CRC-32.
+ */
+static void
+initcrc32(void)
+{
+ int i, j;
+ ulong c;
+
+ for(i = 0; i < 256; i++) {
+ for(c = i << 24, j = 8; j > 0; j--)
+ if(c & (1<<31))
+ c = (c<<1) ^ CRC32POLY;
+ else
+ c <<= 1;
+ crc32tab[i] = c;
+ }
+}
+
+ulong
+crc32(void *buf, int n, ulong crc)
+{
+ uchar *p;
+
+ if(crc32tab[1] == 0)
+ initcrc32();
+ crc = ~crc;
+ for(p = buf; --n >= 0;)
+ crc = (crc << 8) ^ crc32tab[(crc >> 24) ^ *p++];
+ return ~crc;
+}
diff --git a/os/boot/mpc/donprint.c b/os/boot/mpc/donprint.c
new file mode 100644
index 00000000..4125e690
--- /dev/null
+++ b/os/boot/mpc/donprint.c
@@ -0,0 +1,332 @@
+#include "u.h"
+#include "lib.h"
+
+#define PTR sizeof(char*)
+#define SHORT sizeof(int)
+#define INT sizeof(int)
+#define LONG sizeof(long)
+#define IDIGIT 30
+#define MAXCON 30
+
+#define FLONG (1<<0)
+#define FSHORT (1<<1)
+#define FUNSIGN (1<<2)
+
+typedef struct Op Op;
+struct Op
+{
+ char *p;
+ char *ep;
+ void *argp;
+ int f1;
+ int f2;
+ int f3;
+};
+
+static int noconv(Op*);
+static int cconv(Op*);
+static int dconv(Op*);
+static int hconv(Op*);
+static int lconv(Op*);
+static int oconv(Op*);
+static int sconv(Op*);
+static int uconv(Op*);
+static int xconv(Op*);
+static int Xconv(Op*);
+static int percent(Op*);
+
+static
+int (*fmtconv[MAXCON])(Op*) =
+{
+ noconv,
+ cconv, dconv, hconv, lconv,
+ oconv, sconv, uconv, xconv,
+ Xconv, percent,
+};
+static
+char fmtindex[128] =
+{
+ ['c'] 1,
+ ['d'] 2,
+ ['h'] 3,
+ ['l'] 4,
+ ['o'] 5,
+ ['s'] 6,
+ ['u'] 7,
+ ['x'] 8,
+ ['X'] 9,
+ ['%'] 10,
+};
+
+static int convcount = { 11 };
+static int ucase;
+
+static void
+PUT(Op *o, int c)
+{
+ static int pos;
+ int opos;
+
+ if(c == '\t'){
+ opos = pos;
+ pos = (opos+8) & ~7;
+ while(opos++ < pos && o->p < o->ep)
+ *o->p++ = ' ';
+ return;
+ }
+ if(o->p < o->ep){
+ *o->p++ = c;
+ pos++;
+ }
+ if(c == '\n')
+ pos = 0;
+}
+
+int
+fmtinstall(char c, int (*f)(Op*))
+{
+
+ c &= 0177;
+ if(fmtindex[c] == 0) {
+ if(convcount >= MAXCON)
+ return 1;
+ fmtindex[c] = convcount++;
+ }
+ fmtconv[fmtindex[c]] = f;
+ return 0;
+}
+
+char*
+donprint(char *p, char *ep, char *fmt, void *argp)
+{
+ int sf1, c;
+ Op o;
+
+ o.p = p;
+ o.ep = ep;
+ o.argp = argp;
+
+loop:
+ c = *fmt++;
+ if(c != '%') {
+ if(c == 0) {
+ if(o.p < o.ep)
+ *o.p = 0;
+ return o.p;
+ }
+ PUT(&o, c);
+ goto loop;
+ }
+ o.f1 = 0;
+ o.f2 = -1;
+ o.f3 = 0;
+ c = *fmt++;
+ sf1 = 0;
+ if(c == '-') {
+ sf1 = 1;
+ c = *fmt++;
+ }
+ while(c >= '0' && c <= '9') {
+ o.f1 = o.f1*10 + c-'0';
+ c = *fmt++;
+ }
+ if(sf1)
+ o.f1 = -o.f1;
+ if(c != '.')
+ goto l1;
+ c = *fmt++;
+ while(c >= '0' && c <= '9') {
+ if(o.f2 < 0)
+ o.f2 = 0;
+ o.f2 = o.f2*10 + c-'0';
+ c = *fmt++;
+ }
+l1:
+ if(c == 0)
+ fmt--;
+ c = (*fmtconv[fmtindex[c&0177]])(&o);
+ if(c < 0) {
+ o.f3 |= -c;
+ c = *fmt++;
+ goto l1;
+ }
+ o.argp = (char*)o.argp + c;
+ goto loop;
+}
+
+void
+strconv(char *o, Op *op, int f1, int f2)
+{
+ int n, c;
+ char *p;
+
+ n = strlen(o);
+ if(f1 >= 0)
+ while(n < f1) {
+ PUT(op, ' ');
+ n++;
+ }
+ for(p=o; c = *p++;)
+ if(f2 != 0) {
+ PUT(op, c);
+ f2--;
+ }
+ if(f1 < 0) {
+ f1 = -f1;
+ while(n < f1) {
+ PUT(op, ' ');
+ n++;
+ }
+ }
+}
+
+int
+numbconv(Op *op, int base)
+{
+ char b[IDIGIT];
+ int i, f, n, r;
+ long v;
+ short h;
+
+ f = 0;
+ switch(op->f3 & (FLONG|FSHORT|FUNSIGN)) {
+ case FLONG:
+ v = *(long*)op->argp;
+ r = LONG;
+ break;
+
+ case FUNSIGN|FLONG:
+ v = *(ulong*)op->argp;
+ r = LONG;
+ break;
+
+ case FSHORT:
+ h = *(int*)op->argp;
+ v = h;
+ r = SHORT;
+ break;
+
+ case FUNSIGN|FSHORT:
+ h = *(int*)op->argp;
+ v = (ushort)h;
+ r = SHORT;
+ break;
+
+ default:
+ v = *(int*)op->argp;
+ r = INT;
+ break;
+
+ case FUNSIGN:
+ v = *(unsigned*)op->argp;
+ r = INT;
+ break;
+ }
+ if(!(op->f3 & FUNSIGN) && v < 0) {
+ v = -v;
+ f = 1;
+ }
+ b[IDIGIT-1] = 0;
+ for(i = IDIGIT-2;; i--) {
+ n = (ulong)v % base;
+ n += '0';
+ if(n > '9'){
+ n += 'a' - ('9'+1);
+ if(ucase)
+ n += 'A'-'a';
+ }
+ b[i] = n;
+ if(i < 2)
+ break;
+ v = (ulong)v / base;
+ if(op->f2 >= 0 && i >= IDIGIT-op->f2)
+ continue;
+ if(v <= 0)
+ break;
+ }
+ if(f)
+ b[--i] = '-';
+ strconv(b+i, op, op->f1, -1);
+ return r;
+}
+
+static int
+noconv(Op *op)
+{
+
+ strconv("***", op, 0, -1);
+ return 0;
+}
+
+static int
+cconv(Op *op)
+{
+ char b[2];
+
+ b[0] = *(int*)op->argp;
+ b[1] = 0;
+ strconv(b, op, op->f1, -1);
+ return INT;
+}
+
+static int
+dconv(Op *op)
+{
+ return numbconv(op, 10);
+}
+
+static int
+hconv(Op*)
+{
+ return -FSHORT;
+}
+
+static int
+lconv(Op*)
+{
+ return -FLONG;
+}
+
+static int
+oconv(Op *op)
+{
+ return numbconv(op, 8);
+}
+
+static int
+sconv(Op *op)
+{
+ strconv(*(char**)op->argp, op, op->f1, op->f2);
+ return PTR;
+}
+
+static int
+uconv(Op*)
+{
+ return -FUNSIGN;
+}
+
+static int
+xconv(Op *op)
+{
+ return numbconv(op, 16);
+}
+
+static int
+Xconv(Op *op)
+{
+ int r;
+
+ ucase = 1;
+ r = numbconv(op, 16);
+ ucase = 0;
+ return r;
+}
+
+static int
+percent(Op *op)
+{
+
+ PUT(op, '%');
+ return 0;
+}
diff --git a/os/boot/mpc/dosboot.c b/os/boot/mpc/dosboot.c
new file mode 100644
index 00000000..cd8d1276
--- /dev/null
+++ b/os/boot/mpc/dosboot.c
@@ -0,0 +1,614 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "dosfs.h"
+
+extern char *premature;
+
+/*
+ * predeclared
+ */
+static void bootdump(Dosboot*);
+static void setname(Dosfile*, char*);
+long dosreadseg(Dosfile*, long, long);
+
+/*
+ * debugging
+ */
+#define chatty 1
+#define chat if(chatty)print
+
+/*
+ * block io buffers
+ */
+enum
+{
+ Nbio= 16,
+};
+typedef struct Clustbuf Clustbuf;
+struct Clustbuf
+{
+ int age;
+ long sector;
+ uchar *iobuf;
+ Dos *dos;
+ int size;
+};
+Clustbuf bio[Nbio];
+
+/*
+ * get an io block from an io buffer
+ */
+Clustbuf*
+getclust(Dos *dos, long sector)
+{
+ Clustbuf *p, *oldest;
+ int size;
+
+ chat("getclust @ %d\n", sector);
+
+ /*
+ * if we have it, just return it
+ */
+ for(p = bio; p < &bio[Nbio]; p++){
+ if(sector == p->sector && dos == p->dos){
+ p->age = m->ticks;
+ chat("getclust %d in cache\n", sector);
+ return p;
+ }
+ }
+
+ /*
+ * otherwise, reuse the oldest entry
+ */
+ oldest = bio;
+ for(p = &bio[1]; p < &bio[Nbio]; p++){
+ if(p->age <= oldest->age)
+ oldest = p;
+ }
+ p = oldest;
+
+ /*
+ * make sure the buffer is big enough
+ */
+ size = dos->clustsize*dos->sectsize;
+ if(p->iobuf==0 || p->size < size)
+ p->iobuf = ialloc(size, 0);
+ p->size = size;
+
+ /*
+ * read in the cluster
+ */
+ chat("getclust addr %d\n", (sector+dos->start)*dos->sectsize);
+ if((*dos->seek)(dos->dev, (sector+dos->start)*dos->sectsize) < 0){
+ chat("can't seek block\n");
+ return 0;
+ }
+ if((*dos->read)(dos->dev, p->iobuf, size) != size){
+ chat("can't read block\n");
+ return 0;
+ }
+
+ p->age = m->ticks;
+ p->dos = dos;
+ p->sector = sector;
+ chat("getclust %d read\n", sector);
+ return p;
+}
+
+/*
+ * walk the fat one level ( n is a current cluster number ).
+ * return the new cluster number or -1 if no more.
+ */
+static long
+fatwalk(Dos *dos, int n)
+{
+ ulong k, sect;
+ Clustbuf *p;
+ int o;
+
+ chat("fatwalk %d\n", n);
+
+ if(n < 2 || n >= dos->fatclusters)
+ return -1;
+
+ switch(dos->fatbits){
+ case 12:
+ k = (3*n)/2; break;
+ case 16:
+ k = 2*n; break;
+ default:
+ return -1;
+ }
+ if(k >= dos->fatsize*dos->sectsize)
+ panic("getfat");
+
+ sect = (k/(dos->sectsize*dos->clustsize))*dos->clustsize + dos->fataddr;
+ o = k%(dos->sectsize*dos->clustsize);
+ p = getclust(dos, sect);
+ k = p->iobuf[o++];
+ if(o >= dos->sectsize*dos->clustsize){
+ p = getclust(dos, sect+dos->clustsize);
+ o = 0;
+ }
+ k |= p->iobuf[o]<<8;
+ if(dos->fatbits == 12){
+ if(n&1)
+ k >>= 4;
+ else
+ k &= 0xfff;
+ if(k >= 0xff8)
+ k |= 0xf000;
+ }
+ k = k < 0xfff8 ? k : -1;
+ chat("fatwalk %d -> %d\n", n, k);
+ return k;
+}
+
+/*
+ * map a file's logical cluster address to a physical sector address
+ */
+static long
+fileaddr(Dosfile *fp, long ltarget)
+{
+ Dos *dos = fp->dos;
+ long l;
+ long p;
+
+ chat("fileaddr %8.8s %d\n", fp->name, ltarget);
+ /*
+ * root directory is contiguous and easy
+ */
+ if(fp->pstart == 0){
+ if(ltarget*dos->sectsize*dos->clustsize >= dos->rootsize*sizeof(Dosdir))
+ return -1;
+ l = dos->rootaddr + ltarget*dos->clustsize;
+ chat("fileaddr %d -> %d\n", ltarget, l);
+ return l;
+ }
+
+ /*
+ * anything else requires a walk through the fat
+ */
+ if(ltarget >= fp->lcurrent && fp->pcurrent){
+ /* start at the currrent point */
+ l = fp->lcurrent;
+ p = fp->pcurrent;
+ } else {
+ /* go back to the beginning */
+ l = 0;
+ p = fp->pstart;
+ }
+ while(l != ltarget){
+ /* walk the fat */
+ p = fatwalk(dos, p);
+ if(p < 0)
+ return -1;
+ l++;
+ }
+ fp->lcurrent = l;
+ fp->pcurrent = p;
+
+ /*
+ * clusters start at 2 instead of 0 (why? - presotto)
+ */
+ l = dos->dataaddr + (p-2)*dos->clustsize;
+ chat("fileaddr %d -> %d\n", ltarget, l);
+ return l;
+}
+
+/*
+ * read from a dos file
+ */
+long
+dosread(Dosfile *fp, void *a, long n)
+{
+ long addr;
+ long rv;
+ int i;
+ int off;
+ Clustbuf *p;
+ uchar *from, *to;
+
+ if((fp->attr & DDIR) == 0){
+ if(fp->offset >= fp->length)
+ return 0;
+ if(fp->offset+n > fp->length)
+ n = fp->length - fp->offset;
+ }
+
+ to = a;
+ for(rv = 0; rv < n; rv+=i){
+ /*
+ * read the cluster
+ */
+ addr = fileaddr(fp, fp->offset/fp->dos->clustbytes);
+ if(addr < 0)
+ return -1;
+ p = getclust(fp->dos, addr);
+ if(p == 0)
+ return -1;
+
+ /*
+ * copy the bytes we need
+ */
+ off = fp->offset % fp->dos->clustbytes;
+ from = &p->iobuf[off];
+ i = n - rv;
+ if(i > fp->dos->clustbytes - off)
+ i = fp->dos->clustbytes - off;
+ memmove(to, from, i);
+ to += i;
+ fp->offset += i;
+ }
+
+ return rv;
+}
+
+/*
+ * walk a directory returns
+ * -1 if something went wrong
+ * 0 if not found
+ * 1 if found
+ */
+int
+doswalk(Dosfile *file, char *name)
+{
+ Dosdir d;
+ long n;
+
+ if((file->attr & DDIR) == 0){
+ chat("walking non-directory!\n");
+ return -1;
+ }
+
+ setname(file, name);
+
+ file->offset = 0; /* start at the beginning */
+ while((n = dosread(file, &d, sizeof(d))) == sizeof(d)){
+ chat("comparing to %8.8s.%3.3s\n", d.name, d.ext);
+ if(memcmp(file->name, d.name, sizeof(d.name)) != 0)
+ continue;
+ if(memcmp(file->ext, d.ext, sizeof(d.ext)) != 0)
+ continue;
+ if(d.attr & DVLABEL){
+ chat("%8.8s.%3.3s is a LABEL\n", d.name, d.ext);
+ continue;
+ }
+ file->attr = d.attr;
+ file->pstart = GSHORT(d.start);
+ file->length = GLONG(d.length);
+ file->pcurrent = 0;
+ file->lcurrent = 0;
+ file->offset = 0;
+ return 1;
+ }
+ return n >= 0 ? 0 : -1;
+}
+
+
+/*
+ * instructions that boot blocks can start with
+ */
+#define JMPSHORT 0xeb
+#define JMPNEAR 0xe9
+
+/*
+ * read dos file system properties
+ */
+int
+dosinit(Dos *dos, int start, int ishard)
+{
+ Dosboot *b;
+ int i;
+ Clustbuf *p;
+ Dospart *dp;
+ ulong mbroffset, offset;
+
+ /* defaults till we know better */
+ dos->start = start;
+ dos->sectsize = 512;
+ dos->clustsize = 1;
+ mbroffset = 0;
+
+dmddo:
+ /* get first sector */
+ p = getclust(dos, mbroffset);
+ if(p == 0){
+ chat("can't read boot block\n");
+ return -1;
+ }
+
+ /*
+ * If it's a hard disc then look for an MBR and pick either an
+ * active partition or the FAT with the lowest starting LBA.
+ * Things are tricky because we could be pointing to, amongst others:
+ * 1) a floppy BPB;
+ * 2) a hard disc MBR;
+ * 3) a hard disc extended partition table;
+ * 4) a logical drive on a hard disc;
+ * 5) a disc-manager boot block.
+ * They all have the same magic at the end of the block.
+ */
+ if(p->iobuf[0x1FE] != 0x55 || p->iobuf[0x1FF] != 0xAA) {
+ chat("not DOS\n");
+ return -1;
+ }
+ p->dos = 0;
+ b = (Dosboot *)p->iobuf;
+ if(ishard && b->mediadesc != 0xF8){
+ dp = (Dospart*)&p->iobuf[0x1BE];
+ offset = 0xFFFFFFFF;
+ for(i = 0; i < 4; i++, dp++){
+ if(dp->type == DMDDO){
+ mbroffset = 63;
+ goto dmddo;
+ }
+ if(dp->type != FAT12 && dp->type != FAT16 && dp->type != FATHUGE)
+ continue;
+ if(dp->flag & 0x80){
+ offset = GLONG(dp->start);
+ break;
+ }
+ if(GLONG(dp->start) < offset)
+ offset = GLONG(dp->start);
+ }
+ if(i != 4 || offset != 0xFFFFFFFF){
+ dos->start = mbroffset+offset;
+ p = getclust(dos, 0);
+ if(p == 0 || p->iobuf[0x1FE] != 0x55 || p->iobuf[0x1FF] != 0xAA)
+ return -1;
+ }
+ p->dos = 0;
+ }
+
+ b = (Dosboot *)p->iobuf;
+ if(b->magic[0] != JMPNEAR && (b->magic[0] != JMPSHORT || b->magic[2] != 0x90)){
+ chat("no dos file system\n");
+ return -1;
+ }
+
+ if(chatty)
+ bootdump(b);
+
+ /*
+ * determine the systems' wondersous properties
+ */
+ dos->sectsize = GSHORT(b->sectsize);
+ dos->clustsize = b->clustsize;
+ dos->clustbytes = dos->sectsize*dos->clustsize;
+ dos->nresrv = GSHORT(b->nresrv);
+ dos->nfats = b->nfats;
+ dos->rootsize = GSHORT(b->rootsize);
+ dos->volsize = GSHORT(b->volsize);
+ if(dos->volsize == 0)
+ dos->volsize = GLONG(b->bigvolsize);
+ dos->mediadesc = b->mediadesc;
+ dos->fatsize = GSHORT(b->fatsize);
+ dos->fataddr = dos->nresrv;
+ dos->rootaddr = dos->fataddr + dos->nfats*dos->fatsize;
+ i = dos->rootsize*sizeof(Dosdir) + dos->sectsize - 1;
+ i = i/dos->sectsize;
+ dos->dataaddr = dos->rootaddr + i;
+ dos->fatclusters = 2+(dos->volsize - dos->dataaddr)/dos->clustsize;
+ if(dos->fatclusters < 4087)
+ dos->fatbits = 12;
+ else
+ dos->fatbits = 16;
+ dos->freeptr = 2;
+
+ /*
+ * set up the root
+ */
+ dos->root.dos = dos;
+ dos->root.pstart = 0;
+ dos->root.pcurrent = dos->root.lcurrent = 0;
+ dos->root.offset = 0;
+ dos->root.attr = DDIR;
+ dos->root.length = dos->rootsize*sizeof(Dosdir);
+
+ return 0;
+}
+
+static void
+bootdump(Dosboot *b)
+{
+ if(chatty == 0)
+ return;
+ print("magic: 0x%2.2x 0x%2.2x 0x%2.2x\n",
+ b->magic[0], b->magic[1], b->magic[2]);
+ print("version: \"%8.8s\"\n", b->version);
+ print("sectsize: %d\n", GSHORT(b->sectsize));
+ print("allocsize: %d\n", b->clustsize);
+ print("nresrv: %d\n", GSHORT(b->nresrv));
+ print("nfats: %d\n", b->nfats);
+ print("rootsize: %d\n", GSHORT(b->rootsize));
+ print("volsize: %d\n", GSHORT(b->volsize));
+ print("mediadesc: 0x%2.2x\n", b->mediadesc);
+ print("fatsize: %d\n", GSHORT(b->fatsize));
+ print("trksize: %d\n", GSHORT(b->trksize));
+ print("nheads: %d\n", GSHORT(b->nheads));
+ print("nhidden: %d\n", GLONG(b->nhidden));
+ print("bigvolsize: %d\n", GLONG(b->bigvolsize));
+ print("driveno: %d\n", b->driveno);
+ print("reserved0: 0x%2.2x\n", b->reserved0);
+ print("bootsig: 0x%2.2x\n", b->bootsig);
+ print("volid: 0x%8.8x\n", GLONG(b->volid));
+ print("label: \"%11.11s\"\n", b->label);
+}
+
+/*
+ * grab next element from a path, return the pointer to unprocessed portion of
+ * path.
+ */
+static char *
+nextelem(char *path, char *elem)
+{
+ int i;
+
+ while(*path == '/')
+ path++;
+ if(*path==0 || *path==' ')
+ return 0;
+ for(i=0; *path!='\0' && *path!='/' && *path!=' '; i++){
+ if(i==28){
+ print("name component too long\n");
+ return 0;
+ }
+ *elem++ = *path++;
+ }
+ *elem = '\0';
+ return path;
+}
+
+int
+dosstat(Dos *dos, char *path, Dosfile *f)
+{
+ char element[NAMELEN];
+
+ *f = dos->root;
+ while(path = nextelem(path, element)){
+ switch(doswalk(f, element)){
+ case -1:
+ return -1;
+ case 0:
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * boot
+ */
+int
+dosboot(Dos *dos, char *path)
+{
+ Dosfile file;
+ long n;
+ long addr;
+ Exec *ep;
+ void (*b)(void);
+
+ switch(dosstat(dos, path, &file)){
+
+ case -1:
+ print("error walking to %s\n", path);
+ return -1;
+ case 0:
+ print("%s not found\n", path);
+ return -1;
+ case 1:
+ print("found %8.8s.%3.3s attr 0x%ux start 0x%lux len %d\n", file.name,
+ file.ext, file.attr, file.pstart, file.length);
+ break;
+ }
+
+ /*
+ * read header
+ */
+ ep = (Exec*)ialloc(sizeof(Exec), 0);
+ n = sizeof(Exec);
+ if(dosreadseg(&file, n, (ulong) ep) != n){
+ print(premature);
+ return -1;
+ }
+ if(GLLONG(ep->magic) != Q_MAGIC){
+ print("bad magic 0x%lux not a plan 9 executable!\n", GLLONG(ep->magic));
+ return -1;
+ }
+
+ /*
+ * read text
+ */
+ addr = PADDR(GLLONG(ep->entry));
+ n = GLLONG(ep->text);
+ print("+%d", n);
+ if(dosreadseg(&file, n, addr) != n){
+ print(premature);
+ return -1;
+ }
+
+ /*
+ * read data (starts at first page after kernel)
+ */
+ addr = PGROUND(addr+n);
+ n = GLLONG(ep->data);
+ print("+%d", n);
+ if(dosreadseg(&file, n, addr) != n){
+ print(premature);
+ return -1;
+ }
+
+ /*
+ * bss and entry point
+ */
+ print("+%d\nstart at 0x%lux\n", GLLONG(ep->bss), GLLONG(ep->entry));
+
+ /*
+ * Go to new code. It's up to the program to get its PC relocated to
+ * the right place.
+ */
+ b = (void (*)(void))(PADDR(GLLONG(ep->entry)));
+ (*b)();
+ return 0;
+}
+
+/*
+ * read in a segment
+ */
+long
+dosreadseg(Dosfile *fp, long len, long addr)
+{
+ char *a;
+ long n, sofar;
+
+ a = (char *)addr;
+ for(sofar = 0; sofar < len; sofar += n){
+ n = 8*1024;
+ if(len - sofar < n)
+ n = len - sofar;
+ n = dosread(fp, a + sofar, n);
+ if(n <= 0)
+ break;
+ print(".");
+ }
+ return sofar;
+}
+
+/*
+ * set up a dos file name
+ */
+static void
+setname(Dosfile *fp, char *from)
+{
+ char *to;
+
+ to = fp->name;
+ for(; *from && to-fp->name < 8; from++, to++){
+ if(*from == '.'){
+ from++;
+ break;
+ }
+ if(*from >= 'a' && *from <= 'z')
+ *to = *from + 'A' - 'a';
+ else
+ *to = *from;
+ }
+ while(to - fp->name < 8)
+ *to++ = ' ';
+
+ to = fp->ext;
+ for(; *from && to-fp->ext < 3; from++, to++){
+ if(*from >= 'a' && *from <= 'z')
+ *to = *from + 'A' - 'a';
+ else
+ *to = *from;
+ }
+ while(to-fp->ext < 3)
+ *to++ = ' ';
+
+ chat("name is %8.8s %3.3s\n", fp->name, fp->ext);
+}
diff --git a/os/boot/mpc/dosfs.h b/os/boot/mpc/dosfs.h
new file mode 100644
index 00000000..a45065a6
--- /dev/null
+++ b/os/boot/mpc/dosfs.h
@@ -0,0 +1,110 @@
+typedef struct Dosboot Dosboot;
+typedef struct Dos Dos;
+typedef struct Dosdir Dosdir;
+typedef struct Dosfile Dosfile;
+typedef struct Dospart Dospart;
+
+struct Dospart
+{
+ uchar flag; /* active flag */
+ uchar shead; /* starting head */
+ uchar scs[2]; /* starting cylinder/sector */
+ uchar type; /* partition type */
+ uchar ehead; /* ending head */
+ uchar ecs[2]; /* ending cylinder/sector */
+ uchar start[4]; /* starting sector */
+ uchar len[4]; /* length in sectors */
+};
+
+#define FAT12 0x01
+#define FAT16 0x04
+#define FATHUGE 0x06
+#define DMDDO 0x54
+
+struct Dosboot{
+ uchar magic[3];
+ uchar version[8];
+ uchar sectsize[2];
+ uchar clustsize;
+ uchar nresrv[2];
+ uchar nfats;
+ uchar rootsize[2];
+ uchar volsize[2];
+ uchar mediadesc;
+ uchar fatsize[2];
+ uchar trksize[2];
+ uchar nheads[2];
+ uchar nhidden[4];
+ uchar bigvolsize[4];
+ uchar driveno;
+ uchar reserved0;
+ uchar bootsig;
+ uchar volid[4];
+ uchar label[11];
+ uchar reserved1[8];
+};
+
+struct Dosfile{
+ Dos *dos; /* owning dos file system */
+ char name[8];
+ char ext[3];
+ uchar attr;
+ long length;
+ long pstart; /* physical start cluster address */
+ long pcurrent; /* physical current cluster address */
+ long lcurrent; /* logical current cluster address */
+ long offset;
+};
+
+struct Dos{
+ int dev; /* device id */
+ long (*read)(int, void*, long); /* read routine */
+ long (*seek)(int, long); /* seek routine */
+
+ int start; /* start of file system */
+ int sectsize; /* in bytes */
+ int clustsize; /* in sectors */
+ int clustbytes; /* in bytes */
+ int nresrv; /* sectors */
+ int nfats; /* usually 2 */
+ int rootsize; /* number of entries */
+ int volsize; /* in sectors */
+ int mediadesc;
+ int fatsize; /* in sectors */
+ int fatclusters;
+ int fatbits; /* 12 or 16 */
+ long fataddr; /* sector number */
+ long rootaddr;
+ long dataaddr;
+ long freeptr;
+
+ Dosfile root;
+};
+
+struct Dosdir{
+ uchar name[8];
+ uchar ext[3];
+ uchar attr;
+ uchar reserved[10];
+ uchar time[2];
+ uchar date[2];
+ uchar start[2];
+ uchar length[4];
+};
+
+#define DRONLY 0x01
+#define DHIDDEN 0x02
+#define DSYSTEM 0x04
+#define DVLABEL 0x08
+#define DDIR 0x10
+#define DARCH 0x20
+
+extern int chatty;
+
+extern int dosboot(Dos*, char*);
+extern int dosinit(Dos*, int, int);
+extern long dosread(Dosfile*, void*, long);
+extern int dosstat(Dos*, char*, Dosfile*);
+extern int doswalk(Dosfile*, char*);
+
+extern int plan9ini(Dos*, char*);
diff --git a/os/boot/mpc/etherif.h b/os/boot/mpc/etherif.h
new file mode 100644
index 00000000..a4e790a6
--- /dev/null
+++ b/os/boot/mpc/etherif.h
@@ -0,0 +1,59 @@
+/*
+ * All the goo for PC ethernet cards.
+ */
+typedef struct Card Card;
+typedef struct Type Type;
+typedef struct Ctlr Ctlr;
+
+/*
+ * Hardware interface.
+ */
+struct Card {
+ ISAConf;
+
+ int (*reset)(Ctlr*);
+ void (*attach)(Ctlr*);
+
+ void *(*read)(Ctlr*, void*, ulong, ulong);
+ void *(*write)(Ctlr*, ulong, void*, ulong);
+
+ void (*receive)(Ctlr*);
+ void (*transmit)(Ctlr*);
+ void (*intr)(Ureg*, void*);
+ void (*overflow)(Ctlr*);
+
+ uchar bit16; /* true if a 16 bit interface */
+ uchar ram; /* true if card has shared memory */
+
+ ulong dp8390; /* I/O address of 8390 (if any) */
+ ulong data; /* I/O data port if no shared memory */
+ uchar nxtpkt; /* software bndry */
+ uchar tstart; /* 8390 ring addresses */
+ uchar pstart;
+ uchar pstop;
+
+ uchar dummyrr; /* do dummy remote read */
+};
+
+/*
+ * Software controller.
+ */
+struct Ctlr {
+ Card card; /* hardware info */
+ int ctlrno;
+ int present;
+
+ Queue* iq;
+ Queue* oq;
+
+ int inpackets;
+ int outpackets;
+ int crcs; /* input crc errors */
+ int oerrs; /* output errors */
+ int frames; /* framing errors */
+ int overflows; /* packet overflows */
+ int buffs; /* buffering errors */
+};
+
+extern int sccethreset(Ctlr*);
+extern int etheriq(Ctlr*, Block*, int);
diff --git a/os/boot/mpc/etherscc.c b/os/boot/mpc/etherscc.c
new file mode 100644
index 00000000..1e47d473
--- /dev/null
+++ b/os/boot/mpc/etherscc.c
@@ -0,0 +1,411 @@
+/*
+ * SCCn ethernet
+ */
+
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "etherif.h"
+
+enum {
+ Nrdre = 32, /* receive descriptor ring entries */
+ Ntdre = 4, /* transmit descriptor ring entries */
+
+ Rbsize = ETHERMAXTU+4, /* ring buffer size (+4 for CRC) */
+ Bufsize = (Rbsize+7)&~7, /* aligned */
+};
+
+enum {
+ /* ether-specific Rx BD bits */
+ RxMiss= 1<<8,
+ RxeLG= 1<<5,
+ RxeNO= 1<<4,
+ RxeSH= 1<<3,
+ RxeCR= 1<<2,
+ RxeOV= 1<<1,
+ RxeCL= 1<<0,
+ RxError= (RxeLG|RxeNO|RxeSH|RxeCR|RxeOV|RxeCL), /* various error flags */
+
+ /* ether-specific Tx BD bits */
+ TxPad= 1<<14, /* pad short frames */
+ TxTC= 1<<10, /* transmit CRC */
+ TxeDEF= 1<<9,
+ TxeHB= 1<<8,
+ TxeLC= 1<<7,
+ TxeRL= 1<<6,
+ TxeUN= 1<<1,
+ TxeCSL= 1<<0,
+
+ /* scce */
+ RXB= 1<<0,
+ TXB= 1<<1,
+ BSY= 1<<2,
+ RXF= 1<<3,
+ TXE= 1<<4,
+
+ /* gsmrl */
+ ENR= 1<<5,
+ ENT= 1<<4,
+
+ /* port A */
+ RXD1= SIBIT(15),
+ TXD1= SIBIT(14),
+
+ /* port B */
+ RTS1= IBIT(19),
+
+ /* port C */
+ CTS1= SIBIT(11),
+ CD1= SIBIT(10),
+};
+
+typedef struct Etherparam Etherparam;
+struct Etherparam {
+ SCCparam;
+ ulong c_pres; /* preset CRC */
+ ulong c_mask; /* constant mask for CRC */
+ ulong crcec; /* CRC error counter */
+ ulong alec; /* alighnment error counter */
+ ulong disfc; /* discard frame counter */
+ ushort pads; /* short frame PAD characters */
+ ushort ret_lim; /* retry limit threshold */
+ ushort ret_cnt; /* retry limit counter */
+ ushort mflr; /* maximum frame length reg */
+ ushort minflr; /* minimum frame length reg */
+ ushort maxd1; /* maximum DMA1 length reg */
+ ushort maxd2; /* maximum DMA2 length reg */
+ ushort maxd; /* rx max DMA */
+ ushort dma_cnt; /* rx dma counter */
+ ushort max_b; /* max bd byte count */
+ ushort gaddr[4]; /* group address filter */
+ ulong tbuf0_data0; /* save area 0 - current frm */
+ ulong tbuf0_data1; /* save area 1 - current frm */
+ ulong tbuf0_rba0;
+ ulong tbuf0_crc;
+ ushort tbuf0_bcnt;
+ ushort paddr[3]; /* physical address LSB to MSB increasing */
+ ushort p_per; /* persistence */
+ ushort rfbd_ptr; /* rx first bd pointer */
+ ushort tfbd_ptr; /* tx first bd pointer */
+ ushort tlbd_ptr; /* tx last bd pointer */
+ ulong tbuf1_data0; /* save area 0 - next frame */
+ ulong tbuf1_data1; /* save area 1 - next frame */
+ ulong tbuf1_rba0;
+ ulong tbuf1_crc;
+ ushort tbuf1_bcnt;
+ ushort tx_len; /* tx frame length counter */
+ ushort iaddr[4]; /* individual address filter*/
+ ushort boff_cnt; /* back-off counter */
+ ushort taddr[3]; /* temp address */
+};
+
+typedef struct {
+ SCC* scc;
+ int port;
+ int cpm;
+
+ BD* rdr; /* receive descriptor ring */
+ void* rrb; /* receive ring buffers */
+ int rdrx; /* index into rdr */
+
+ BD* tdr; /* transmit descriptor ring */
+ void* trb; /* transmit ring buffers */
+ int tdrx; /* index into tdr */
+} Mot;
+static Mot mot[MaxEther];
+
+static int sccid[] = {-1, SCC1ID, SCC2ID, SCC3ID, SCC4ID};
+static int sccparam[] = {-1, SCC1P, SCC2P, SCC3P, SCC4P};
+static int sccreg[] = {-1, 0xA00, 0xA20, 0xA40, 0xA60};
+static int sccirq[] = {-1, 0x1E, 0x1D, 0x1C, 0x1B};
+
+static void
+attach(Ctlr *ctlr)
+{
+ mot[ctlr->ctlrno].scc->gsmrl |= ENR|ENT;
+ eieio();
+}
+
+static void
+transmit(Ctlr *ctlr)
+{
+ int len;
+ Mot *motp;
+ Block *b;
+ BD *tdre;
+
+ motp = &mot[ctlr->ctlrno];
+ while(((tdre = &motp->tdr[motp->tdrx])->status & BDReady) == 0){
+ b = qget(ctlr->oq);
+ if(b == 0)
+ break;
+
+ /*
+ * Copy the packet to the transmit buffer.
+ */
+ len = BLEN(b);
+ memmove(KADDR(tdre->addr), b->rp, len);
+
+ /*
+ * Give ownership of the descriptor to the chip, increment the
+ * software ring descriptor pointer and tell the chip to poll.
+ */
+ tdre->length = len;
+ eieio();
+ tdre->status = (tdre->status & BDWrap) | BDReady|TxPad|BDInt|BDLast|TxTC;
+ eieio();
+ motp->scc->todr = 1<<15; /* transmit now */
+ eieio();
+ motp->tdrx = NEXT(motp->tdrx, Ntdre);
+
+ freeb(b);
+
+ }
+}
+
+static void
+interrupt(Ureg*, void *ap)
+{
+ int len, events, status;
+ Mot *motp;
+ BD *rdre;
+ Block *b;
+ Ctlr *ctlr;
+
+ ctlr = ap;
+ motp = &mot[ctlr->ctlrno];
+
+ /*
+ * Acknowledge all interrupts and whine about those that shouldn't
+ * happen.
+ */
+ events = motp->scc->scce;
+ eieio();
+ motp->scc->scce = events;
+ eieio();
+ if(events & (TXE|BSY|RXB))
+ print("ETHER.SCC#%d: scce = 0x%uX\n", ctlr->ctlrno, events);
+ //print(" %ux|", events);
+ /*
+ * Receiver interrupt: run round the descriptor ring logging
+ * errors and passing valid receive data up to the higher levels
+ * until we encounter a descriptor still owned by the chip.
+ */
+ if(events & (RXF|RXB) || 1){
+ rdre = &motp->rdr[motp->rdrx];
+ while(((status = rdre->status) & BDEmpty) == 0){
+ if(status & RxError || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){
+ //if(status & RxBuff)
+ // ctlr->buffs++;
+ if(status & (1<<2))
+ ctlr->crcs++;
+ if(status & (1<<1))
+ ctlr->overflows++;
+ //print("eth rx: %ux\n", status);
+ if(status & RxError)
+ print("~");
+ else if((status & BDLast) == 0)
+ print("@");
+ }
+ else{
+ /*
+ * We have a packet. Read it into the next
+ * free ring buffer, if any.
+ */
+ len = rdre->length-4;
+ if((b = iallocb(len)) != 0){
+ memmove(b->wp, KADDR(rdre->addr), len);
+ b->wp += len;
+ etheriq(ctlr, b, 1);
+ }
+ }
+
+ /*
+ * Finished with this descriptor, reinitialise it,
+ * give it back to the chip, then on to the next...
+ */
+ rdre->length = 0;
+ rdre->status = (rdre->status & BDWrap) | BDEmpty | BDInt;
+ eieio();
+
+ motp->rdrx = NEXT(motp->rdrx, Nrdre);
+ rdre = &motp->rdr[motp->rdrx];
+ }
+ }
+
+ /*
+ * Transmitter interrupt: handle anything queued for a free descriptor.
+ */
+ if(events & TXB)
+ transmit(ctlr);
+ if(events & TXE)
+ cpmop(RestartTx, motp->cpm, 0);
+}
+
+static void
+ringinit(Mot* motp)
+{
+ int i, x;
+
+ /*
+ * Initialise the receive and transmit buffer rings. The ring
+ * entries must be aligned on 16-byte boundaries.
+ */
+ if(motp->rdr == 0)
+ motp->rdr = bdalloc(Nrdre);
+ if(motp->rrb == 0)
+ motp->rrb = ialloc(Nrdre*Bufsize, 0);
+ x = PADDR(motp->rrb);
+ for(i = 0; i < Nrdre; i++){
+ motp->rdr[i].length = 0;
+ motp->rdr[i].addr = x;
+ motp->rdr[i].status = BDEmpty|BDInt;
+ x += Bufsize;
+ }
+ motp->rdr[i-1].status |= BDWrap;
+ motp->rdrx = 0;
+
+ if(motp->tdr == 0)
+ motp->tdr = bdalloc(Ntdre);
+ if(motp->trb == 0)
+ motp->trb = ialloc(Ntdre*Bufsize, 0);
+ x = PADDR(motp->trb);
+ for(i = 0; i < Ntdre; i++){
+ motp->tdr[i].addr = x;
+ motp->tdr[i].length = 0;
+ motp->tdr[i].status = TxPad|BDInt|BDLast|TxTC;
+ x += Bufsize;
+ }
+ motp->tdr[i-1].status |= BDWrap;
+ motp->tdrx = 0;
+}
+
+/*
+ * This follows the MPC823 user guide: section16.9.23.7's initialisation sequence,
+ * except that it sets the right bits for the MPC823ADS board when SCC2 is used,
+ * and those for the 860/821 development board for SCC1.
+ */
+static void
+sccsetup(Mot *ctlr, SCC *scc, uchar *ea)
+{
+ int i, rcs, tcs, w;
+ Etherparam *p;
+ IMM *io;
+
+
+ i = 2*(ctlr->port-1);
+ io = ioplock();
+ w = (TXD1|RXD1)<<i; /* TXDn and RXDn in port A */
+ io->papar |= w; /* enable TXDn and RXDn pins */
+ io->padir &= ~w;
+ io->paodr &= ~w; /* not open drain */
+
+ w = (CD1|CTS1)<<i; /* CLSN and RENA: CDn and CTSn in port C */
+ io->pcpar &= ~w; /* enable CLSN (CTSn) and RENA (CDn) */
+ io->pcdir &= ~w;
+ io->pcso |= w;
+ iopunlock();
+
+ /* clocks and transceiver control: details depend on the board's wiring */
+ archetherenable(ctlr->cpm, &rcs, &tcs);
+
+ sccnmsi(ctlr->port, rcs, tcs); /* connect the clocks */
+
+ p = (Etherparam*)KADDR(sccparam[ctlr->port]);
+ memset(p, 0, sizeof(*p));
+ p->rfcr = 0x18;
+ p->tfcr = 0x18;
+ p->mrblr = Bufsize;
+ p->rbase = PADDR(ctlr->rdr);
+ p->tbase = PADDR(ctlr->tdr);
+
+ cpmop(InitRxTx, ctlr->cpm, 0);
+
+ p->c_pres = ~0;
+ p->c_mask = 0xDEBB20E3;
+ p->crcec = 0;
+ p->alec = 0;
+ p->disfc = 0;
+ p->pads = 0x8888;
+ p->ret_lim = 0xF;
+ p->mflr = Rbsize;
+ p->minflr = ETHERMINTU+4;
+ p->maxd1 = Bufsize;
+ p->maxd2 = Bufsize;
+ p->p_per = 0; /* only moderate aggression */
+
+ for(i=0; i<Eaddrlen; i+=2)
+ p->paddr[2-i/2] = (ea[i+1]<<8)|ea[i]; /* it's not the obvious byte order */
+
+ scc->psmr = (2<<10)|(5<<1); /* 32-bit CRC, ignore 22 bits before SFD */
+ scc->dsr = 0xd555;
+ scc->gsmrh = 0; /* normal operation */
+ scc->gsmrl = (1<<28)|(4<<21)|(1<<19)|0xC; /* transmit clock invert, 48 bit preamble, repetitive 10 preamble, ethernet */
+ eieio();
+ scc->scce = ~0; /* clear all events */
+ eieio();
+ scc->sccm = TXE | RXF | TXB; /* enable interrupts */
+ eieio();
+
+ io = ioplock();
+ w = RTS1<<(ctlr->port-1); /* enable TENA pin (RTSn) */
+ io->pbpar |= w;
+ io->pbdir |= w;
+ iopunlock();
+
+ /* gsmrl enable is deferred until attach */
+}
+
+/*
+ * Prepare the SCCx ethernet for booting.
+ */
+int
+sccethreset(Ctlr* ctlr)
+{
+ uchar ea[Eaddrlen];
+ Mot *motp;
+ SCC *scc;
+ char line[50], def[50];
+
+ /*
+ * Since there's no EPROM, insist that the configuration entry
+ * (see conf.c and flash.c) holds the Ethernet address.
+ */
+ memset(ea, 0, Eaddrlen);
+ if(memcmp(ea, ctlr->card.ea, Eaddrlen) == 0){
+ print("no preset Ether address\n");
+ for(;;){
+ strcpy(def, "00108bf12900"); /* valid MAC address to be used only for initial configuration */
+ if(getstr("ether MAC address", line, sizeof(line), def) < 0)
+ return -1;
+ if(parseether(ctlr->card.ea, line) >= 0 || ctlr->card.ea[0] == 0xFF)
+ break;
+ print("invalid MAC address\n");
+ }
+ }
+
+ scc = IOREGS(sccreg[ctlr->card.port], SCC);
+ ctlr->card.irq = VectorCPIC+sccirq[ctlr->card.port];
+
+ motp = &mot[ctlr->ctlrno];
+ motp->scc = scc;
+ motp->port = ctlr->card.port;
+ motp->cpm = sccid[ctlr->card.port];
+
+ ringinit(motp);
+
+ sccsetup(motp, scc, ctlr->card.ea);
+
+ /* enable is deferred until attach */
+
+ ctlr->card.reset = sccethreset;
+ ctlr->card.attach = attach;
+ ctlr->card.transmit = transmit;
+ ctlr->card.intr = interrupt;
+
+ return 0;
+}
diff --git a/os/boot/mpc/fblt.c b/os/boot/mpc/fblt.c
new file mode 100644
index 00000000..5014e35c
--- /dev/null
+++ b/os/boot/mpc/fblt.c
@@ -0,0 +1,531 @@
+#include <u.h>
+#include <libc.h>
+#include <libg.h>
+#include <gnot.h>
+
+/*
+ * bitblt operates a 'word' at a time.
+ * WBITS is the number of bits in a word
+ * LWBITS=log2(WBITS),
+ * W2L is the number of words in a long
+ * WMASK has bits set for the low order word of a long
+ * WType is a pointer to a word
+ */
+#ifndef WBITS
+#define WBITS 32
+#define LWBITS 5
+#define W2L 1
+#define WMASK ~0UL
+typedef ulong *WType;
+#endif
+
+#define DEBUG
+
+#ifdef TEST
+/*
+ * globals used for testing
+ */
+int FORCEFORW;
+int FORCEBAKW;
+GBitmap *curdm, *cursm;
+Point curpt;
+Rectangle curr;
+Fcode curf;
+void *mem;
+#endif
+
+static void
+gbitexplode(ulong sw, ulong *buf, int sdep, int x)
+{
+ int j, o, q, n, nw, inc, qinc;
+ ulong s, dw, pix;
+
+ inc = 1 << sdep;
+ pix = (1 << inc) - 1;
+ nw = 1 << x;
+ n = 32 >> x;
+ qinc = (nw << sdep) - inc;
+ for(o = 32 - n; o >= 0; o -= n){
+ dw = 0;
+ s = sw >> o;
+ q = 0;
+ for(j = 0; j < n; j += inc){
+ dw |= (s & (pix << j)) << q;
+ q += qinc;
+ }
+ for(j = 0; j < x; j++)
+ dw |= dw << (inc << j);
+ *buf++ = dw;
+ }
+}
+
+/*
+void
+main(void)
+{
+ ulong buf[128];
+
+ gbitexplode(0x7777, buf, 0, 3);
+ exits(0);
+}
+*/
+
+void
+gbitblt(GBitmap *dm, Point pt, GBitmap *sm, Rectangle r, Fcode fcode)
+{
+ int width; /* width in bits of dst */
+ int wwidth; /* floor width in words */
+ int height; /* height in pixels minus 1 */
+ int sdep; /* src ldepth */
+ int ddep; /* dst ldepth */
+ int deltadep; /* diff between ldepths */
+ int sspan; /* words between scanlines in src */
+ int dspan; /* words between scanlines in dst */
+ int soff; /* bit offset of src start point */
+ int sdest; /* bit offset of src start point that matches doff when expanded */
+ int doff; /* bit offset of dst start point */
+ int delta; /* amount to shift src by */
+ int sign; /* of delta */
+ ulong *saddr;
+ ulong *daddr;
+ ulong *s;
+ ulong *d;
+ ulong mask;
+ ulong tmp; /* temp storage source word */
+ ulong sw; /* source word constructed */
+ ulong dw; /* dest word fetched */
+ ulong lmask; /* affected pixels in leftmost dst word */
+ ulong rmask; /* affected pixels in rightmost dst word */
+ int i;
+ int j;
+ ulong buf[32]; /* for expanding a source */
+ ulong *p; /* pointer into buf */
+ int spare; /* number of words already converted */
+
+
+#ifdef TEST
+ curdm = dm;
+ cursm = sm;
+ curpt = pt;
+ curr = r;
+ curf = fcode;
+#endif
+
+ gbitbltclip(&dm);
+
+ width = r.max.x - r.min.x;
+ if(width <= 0)
+ return;
+ height = r.max.y - r.min.y - 1;
+ if(height < 0)
+ return;
+
+ ddep = dm->ldepth;
+ pt.x <<= ddep;
+ width <<= ddep;
+
+ sdep = sm->ldepth;
+ r.min.x <<= sdep;
+ r.max.x <<= sdep;
+
+ dspan = dm->width * W2L;
+ sspan = sm->width * W2L;
+
+ daddr = (ulong*)((WType)dm->base
+ + dm->zero*W2L + pt.y*dspan
+ + (pt.x >> LWBITS));
+ saddr = (ulong*)((WType)sm->base
+ + sm->zero*W2L + r.min.y*sspan
+ + (r.min.x >> LWBITS));
+
+ doff = pt.x & (WBITS - 1);
+ lmask = WMASK >> doff;
+ rmask = (WMASK << (WBITS - ((doff+width) & (WBITS-1))))&WMASK;
+ if(!rmask)
+ rmask = WMASK;
+ soff = r.min.x & (WBITS-1);
+ wwidth = ((pt.x+width-1)>>LWBITS) - (pt.x>>LWBITS);
+
+ if(sm == dm){
+#ifdef TEST
+ if(!FORCEBAKW &&
+ (FORCEFORW || sm != dm || saddr > daddr ||
+ (saddr == daddr && soff > doff)))
+ ;
+ else{
+ daddr += height * dspan;
+ saddr += height * sspan;
+ sspan -= 2 * W2L * sm->width;
+ dspan -= 2 * W2L * dm->width;
+ }
+#else
+ if(r.min.y < pt.y){ /* bottom to top */
+ daddr += height * dspan;
+ saddr += height * sspan;
+ sspan -= 2 * W2L * sm->width;
+ dspan -= 2 * W2L * dm->width;
+ }else if(r.min.y == pt.y && r.min.x < pt.x)
+ abort()/*goto right*/;
+#endif
+ }
+ if(wwidth == 0) /* collapse masks for narrow cases */
+ lmask &= rmask;
+ fcode &= F;
+
+ deltadep = ddep - sdep;
+ sdest = doff >> deltadep;
+ delta = soff - sdest;
+ sign = 0;
+ if(delta < 0){
+ sign = 1;
+ delta = -delta;
+ }
+
+ p = 0;
+ for(j = 0; j <= height; j++){
+ d = daddr;
+ s = saddr;
+ mask = lmask;
+ tmp = 0;
+ if(!sign)
+ tmp = *s++;
+ spare = 0;
+ for(i = wwidth; i >= 0; i--){
+ if(spare)
+ sw = *p++;
+ else{
+ if(sign){
+ sw = tmp << (WBITS-delta);
+ tmp = *s++;
+ sw |= tmp >> delta;
+ }else{
+ sw = tmp << delta;
+ tmp = *s++;
+ if(delta)
+ sw |= tmp >> (WBITS-delta);
+ }
+ spare = 1 << deltadep;
+ if(deltadep >= 1){
+ gbitexplode(sw, buf, sdep, deltadep);
+ p = buf;
+ sw = *p++;
+ }
+ }
+
+ dw = *d;
+ switch(fcode){ /* ltor bit aligned */
+ case Zero: *d = dw & ~mask; break;
+ case DnorS: *d = dw ^ ((~sw | dw) & mask); break;
+ case DandnotS: *d = dw ^ ((sw & dw) & mask); break;
+ case notS: *d = dw ^ ((~sw ^ dw) & mask); break;
+ case notDandS: *d = dw ^ ((sw | dw) & mask); break;
+ case notD: *d = dw ^ mask; break;
+ case DxorS: *d = dw ^ (sw & mask); break;
+ case DnandS: *d = dw ^ ((sw | ~dw) & mask); break;
+ case DandS: *d = dw ^ ((~sw & dw) & mask); break;
+ case DxnorS: *d = dw ^ (~sw & mask); break;
+ case D: break;
+ case DornotS: *d = dw | (~sw & mask); break;
+ case S: *d = dw ^ ((sw ^ dw) & mask); break;
+ case notDorS: *d = dw ^ (~(sw & dw) & mask); break;
+ case DorS: *d = dw | (sw & mask); break;
+ case F: *d = dw | mask; break;
+ }
+ d++;
+
+ mask = WMASK;
+ if(i == 1)
+ mask = rmask;
+ spare--;
+ }
+ saddr += sspan;
+ daddr += dspan;
+ }
+}
+
+#ifdef TEST
+void prprog(void);
+GBitmap *bb1, *bb2;
+ulong *src, *dst, *xdst, *xans;
+int swds, dwds;
+long ticks;
+int timeit;
+
+long
+func(int f, long s, int sld, long d, int dld)
+{
+ long a;
+ int sh, i, db, sb;
+
+ db = 1 << dld;
+ sb = 1 << sld;
+ sh = db - sb;
+ if(sh > 0) {
+ a = s;
+ for(i = sb; i<db; i += sb){
+ a <<= sb;
+ s |= a;
+ }
+ } else if(sh < 0)
+ s >>= -sh;
+
+ switch(f){
+ case Zero: d = 0; break;
+ case DnorS: d = ~(d|s); break;
+ case DandnotS: d = d & ~s; break;
+ case notS: d = ~s; break;
+ case notDandS: d = ~d & s; break;
+ case notD: d = ~d; break;
+ case DxorS: d = d ^ s; break;
+ case DnandS: d = ~(d&s); break;
+ case DandS: d = d & s; break;
+ case DxnorS: d = ~(d^s); break;
+ case S: d = s; break;
+ case DornotS: d = d | ~s; break;
+ case D: d = d; break;
+ case notDorS: d = ~d | s; break;
+ case DorS: d = d | s; break;
+ case F: d = ~0; break;
+ }
+
+ d &= ((1<<db)-1);
+ return d;
+}
+
+void
+run(int fr, int to, int w, int op)
+{
+ int i, j, f, t, fy, ty;
+ extern long *_clock;
+
+ fr += bb2->r.min.x;
+ to += bb1->r.min.x;
+ fy = bb2->r.min.y + 1;
+ ty = bb1->r.min.y + 1;
+ if(timeit) {
+ memcpy(dst, xdst, dwds * sizeof(long));
+ ticks -= *_clock;
+ gbitblt(bb1, Pt(to,ty), bb2, Rect(fr,fy,fr+w,fy+2), op);
+ ticks += *_clock;
+ return;
+ }
+ f = fr;
+ t = to;
+ memcpy(dst, xdst, dwds * sizeof(long));
+ for(i=0; i<w; i++) {
+ gbitblt(bb1, Pt(t,ty), bb2, Rect(f,fy,f+1,fy+1), op);
+ gbitblt(bb1, Pt(t,ty+1), bb2, Rect(f,fy+1,f+1,fy+2), op);
+ f++;
+ t++;
+ }
+ memcpy(xans, dst, dwds * sizeof(long));
+
+ memcpy(dst, xdst, dwds * sizeof(long));
+ gbitblt(bb1, Pt(to,ty), bb2, Rect(fr,fy,fr+w,fy+2), op);
+
+ if(memcmp(xans, dst, dwds * sizeof(long))) {
+ /*
+ * print src and dst row offset, width in bits, and forw/back
+ * then print for each of the four rows: the source (s),
+ * the dest (d), the good value of the answer (g),
+ * and the actual bad value of the answer (b)
+ */
+ print("fr=%d to=%d w=%d fb=%d%d\n",
+ fr, to, w, FORCEFORW, FORCEBAKW);
+ print("dst bitmap b %#lux, z %d, w %d, ld %d, r [%d,%d][%d,%d]\n",
+ bb1->base, bb1->zero, bb1->width, bb1->ldepth,
+ bb1->r.min.x, bb1->r.min.y, bb1->r.max.x, bb1->r.max.y);
+ print("src bitmap b %#lux, z %d, w %d, ld %d, r [%d,%d][%d,%d]\n",
+ bb2->base, bb2->zero, bb2->width, bb2->ldepth,
+ bb2->r.min.x, bb2->r.min.y, bb2->r.max.x, bb2->r.max.y);
+ for(j=0; 7*j < dwds; j++) {
+ print("\ns");
+ for(i=0; i<7 && 7*j+i < dwds; i++)
+ print(" %.8lux", src[7*j + i]);
+ print("\nd");
+ for(i=0; i<7 && 7*j+i < dwds; i++)
+ print(" %.8lux", xdst[7*j + i]);
+ print("\ng");
+ for(i=0; i<7 && 7*j+i < dwds; i++)
+ print(" %.8lux", xans[7*j + i]);
+ print("\nb");
+ for(i=0; i<7 && 7*j+i < dwds; i++)
+ print(" %.8lux", dst[7*j + i]);
+ print("\n");
+ }
+ prprog();
+ }
+}
+
+void
+prprog(void)
+{
+ exits(0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int f, t, w, i, sld, dld, op, iters, simple;
+ ulong s, d, spix, dpix, apix, fpix, m, *ps, *pd;
+ Point sorg, dorg;
+ GBitmap *bs, *bd;
+ long seed;
+ char *ct;
+
+ sld = 0;
+ dld = 0;
+ timeit = 0;
+ iters = 200;
+ simple = 0;
+ ARGBEGIN {
+ case 'i':
+ iters = atoi(ARGF());
+ break;
+ case 's':
+ simple = 1;
+ break;
+ case 't':
+ timeit = 1;
+ ct = ARGF();
+ if(ct)
+ iters = atoi(ct);
+ break;
+ } ARGEND
+ if(argc > 0)
+ sld = atoi(argv[0]);
+ if(argc > 1)
+ dld = atoi(argv[1]);
+ if(!timeit && !simple) {
+ seed = time(0);
+ print("seed %lux\n", seed); srand(seed); /**/
+ }
+
+ print("sld %d dld %d\n", sld, dld);
+ op = 1;
+
+ /* bitmaps for 1-bit tests */
+ bd = gballoc(Rect(0,0,32,1), dld);
+ bs = gballoc(Rect(0,0,32,1), sld);
+ for(i=0; i<bs->width; i++)
+ bs->base[i] = lrand();
+
+ /* bitmaps for rect tests */
+ if(simple) {
+ dorg = Pt(0,0);
+ sorg = Pt(0,0);
+ } else {
+ dorg = Pt(nrand(63)-31,nrand(63)-31);
+ sorg = Pt(nrand(63)-31,nrand(63)-31);
+ }
+ bb1 = gballoc(Rpt(dorg,add(dorg,Pt(200,4))), dld);
+ bb2 = gballoc(Rpt(sorg,add(sorg,Pt(200,4))), sld);
+ dwds = bb1->width * Dy(bb1->r);
+ swds = bb2->width * Dy(bb2->r);
+ dst = bb1->base;
+ src = bb2->base;
+ xdst = malloc(dwds * sizeof(long));
+ xans = malloc(dwds * sizeof(long));
+ for(i=0; i<swds; i++)
+ src[i] = lrand();
+ for(i=0; i<dwds; i++)
+ xdst[i] = lrand();
+
+loop:
+ print("Op %d\n", op);
+ if(!timeit) {
+ print("one pixel\n");
+ ps = bs->base;
+ pd = bd->base;
+ FORCEFORW = 1;
+ FORCEBAKW = 0;
+ for(i=0; i<1000; i++, FORCEFORW = !FORCEFORW, FORCEBAKW = !FORCEBAKW) {
+ f = nrand(32 >> sld);
+ t = nrand(32 >> dld);
+ s = lrand();
+ d = lrand();
+ ps[0] = s;
+ pd[0] = d;
+#ifdef T386
+ spix = (byterev(s) >> (32 - ((f+1)<<sld))) & ((1 << (1<<sld)) - 1);
+ dpix = (byterev(d) >> (32 - ((t+1)<<dld))) & ((1 << (1<<dld)) - 1);
+#else
+ spix = (s >> (32 - ((f+1)<<sld))) & ((1 << (1<<sld)) - 1);
+ dpix = (d >> (32 - ((t+1)<<dld))) & ((1 << (1<<dld)) - 1);
+#endif
+#ifdef T386
+ apix = byterev(func(op, spix, sld, dpix, dld) << (32 - ((t+1)<<dld)));
+#else
+ apix = func(op, spix, sld, dpix, dld) << (32 - ((t+1)<<dld));
+#endif
+ gbitblt(bd, Pt(t,0), bs, Rect(f,0,f+1,1), op);
+ if(ps[0] != s) {
+ print("bb src %.8lux %.8lux %d %d\n", ps[0], s, f, t);
+ exits("error");
+ }
+ m = ((1 << (1<<dld)) - 1) << (32 - ((t+1)<<dld));
+#ifdef T386
+ m = byterev(m);
+#endif
+ if((pd[0] & ~m) != (d & ~m)) {
+ print("bb dst1 %.8lux %.8lux\n",
+ s, d);
+ print("bb %.8lux %.8lux %d %d\n",
+ ps[0], pd[0], f, t);
+ prprog();
+ exits("error");
+ }
+ if((pd[0] & m) != apix) {
+ spix <<= 32 - ((f+1)<<sld);
+ dpix <<= 32 - ((t+1)<<dld);
+#ifdef T386
+ spix = byterev(spix);
+ dpix = byterev(dpix);
+#endif
+ print("bb dst2 %.8lux %.8lux\n",
+ s, d);
+ print("bb %.8lux %.8lux %d %d\n",
+ ps[0], pd[0], f, t);
+ print("bb %.8lux %.8lux %.8lux %.8lux\n",
+ spix, dpix, apix, pd[0] & m);
+ prprog();
+ exits("error");
+ }
+ }
+ }
+
+ print("for\n");
+ FORCEFORW = 1;
+ FORCEBAKW = 0;
+
+ for(i=0; i<iters; i++) {
+ f = nrand(64);
+ t = nrand(64);
+ w = nrand(130);
+ run(f, t, w, op);
+ }
+
+ if(sld == dld) {
+ print("bak\n");
+ FORCEFORW = 0;
+ FORCEBAKW = 1;
+
+ for(i=0; i<iters; i++) {
+ f = nrand(64);
+ t = nrand(64);
+ w = nrand(130);
+ run(f, t, w, op);
+ }
+ }
+
+ if(op < F) {
+ op++;
+ goto loop;
+ }
+ if(timeit)
+ print("time: %d ticks\n", ticks);
+ exits(0);
+}
+
+
+#endif
diff --git a/os/boot/mpc/flash.c b/os/boot/mpc/flash.c
new file mode 100644
index 00000000..d05f638f
--- /dev/null
+++ b/os/boot/mpc/flash.c
@@ -0,0 +1,212 @@
+#include "boot.h"
+
+typedef struct Flashdev Flashdev;
+struct Flashdev {
+ uchar* base;
+ int size;
+ uchar* exec;
+ char* config;
+ int conflen;
+};
+
+enum {
+ FLASHSEG = 256*1024,
+ CONFIGLIM = FLASHSEG,
+ BOOTOFF = FLASHSEG,
+ BOOTLEN = 3*FLASHSEG, /* third segment might be filsys */
+ /* rest of flash is free */
+};
+
+static Flashdev flash;
+
+/*
+ * configuration data is written between the bootstrap and
+ * the end of region 0. the region ends with allocation descriptors
+ * of the following form:
+ *
+ * byte order is big endian
+ *
+ * the last valid region found that starts with the string "#plan9.ini\n" is plan9.ini
+ */
+typedef struct Flalloc Flalloc;
+struct Flalloc {
+ ulong check; /* checksum of data, or ~0 */
+ ulong base; /* base of region; ~0 if unallocated, 0 if deleted */
+ uchar len[3];
+ uchar tag; /* see below */
+ uchar sig[4];
+};
+
+enum {
+ /* tags */
+ Tdead= 0,
+ Tboot= 0x01, /* space reserved for boot */
+ Tconf= 0x02, /* configuration data */
+ Tnone= 0xFF,
+
+ Noval= ~0,
+};
+
+static char flashsig[] = {0xF1, 0xA5, 0x5A, 0x1F};
+static char conftag[] = "#plan9.ini\n";
+
+static ulong
+checksum(uchar* p, int n)
+{
+ ulong s;
+
+ for(s=0; --n >= 0;)
+ s += *p++;
+ return s;
+}
+
+static int
+validptr(Flalloc *ap, uchar *p)
+{
+ return p > (uchar*)&end && p < (uchar*)ap;
+}
+
+static int
+flashcheck(Flalloc *ap, char **val, int *len)
+{
+ uchar *base;
+ int n;
+
+ if(ap->base == Noval || ap->base >= FLASHSEG || ap->tag == Tnone)
+ return 0;
+ base = flash.base+ap->base;
+ if(!validptr(ap, base))
+ return 0;
+ n = (((ap->len[0]<<8)|ap->len[1])<<8)|ap->len[2];
+ if(n == 0xFFFFFF)
+ n = 0;
+ if(n < 0)
+ return 0;
+ if(n > 0 && !validptr(ap, base+n-1))
+ return 0;
+ if(ap->check != Noval && checksum(base, n) != ap->check){
+ print("flash: bad checksum\n");
+ return 0;
+ }
+ *val = (char*)base;
+ *len = n;
+ return 1;
+}
+
+int
+flashinit(void)
+{
+ int len;
+ char *val;
+ Flalloc *ap;
+ void *addr;
+ long mbytes;
+ char type[20];
+
+ flash.base = 0;
+ flash.exec = 0;
+ flash.size = 0;
+ if(archflashreset(type, &addr, &mbytes) < 0){
+ print("flash: flash not present or not enabled\n"); /* shouldn't happen */
+ return 0;
+ }
+ flash.size = mbytes;
+ flash.base = addr;
+ flash.exec = flash.base + BOOTOFF;
+ flash.config = nil;
+ flash.conflen = 0;
+
+ for(ap = (Flalloc*)(flash.base+CONFIGLIM)-1; memcmp(ap->sig, flashsig, 4) == 0; ap--){
+ if(0)
+ print("conf #%8.8lux: #%x #%6.6lux\n", ap, ap->tag, ap->base);
+ if(ap->tag == Tconf &&
+ flashcheck(ap, &val, &len) &&
+ len >= sizeof(conftag)-1 &&
+ memcmp(val, conftag, sizeof(conftag)-1) == 0){
+ flash.config = val;
+ flash.conflen = len;
+ if(0)
+ print("flash: found config %8.8lux(%d):\n%s\n", val, len, val);
+ }
+ }
+ if(flash.config == nil)
+ print("flash: no config\n");
+ else
+ print("flash config %8.8lux(%d):\n%s\n", flash.config, flash.conflen, flash.config);
+ if(issqueezed(flash.exec) == Q_MAGIC){
+ print("flash: squeezed powerpc kernel installed\n");
+ return 1<<0;
+ }
+ if(GLLONG(flash.exec) == Q_MAGIC){
+ print("flash: unsqueezed powerpc kernel installed\n");
+ return 1<<0;
+ }
+ flash.exec = 0;
+ print("flash: no powerpc kernel in Flash\n");
+ return 0;
+}
+
+char*
+flashconfig(int)
+{
+ return flash.config;
+}
+
+int
+flashbootable(int)
+{
+ return flash.exec != nil && (issqueezed(flash.exec) || GLLONG(flash.exec) == Q_MAGIC);
+}
+
+int
+flashboot(int)
+{
+ ulong entry, addr;
+ void (*b)(void);
+ Exec *ep;
+ Block in;
+ long n;
+ uchar *p;
+
+ if(flash.exec == 0)
+ return -1;
+ p = flash.exec;
+ if(GLLONG(p) == Q_MAGIC){
+ /* unsqueezed: copy data and perhaps text, then jump to it */
+ ep = (Exec*)p;
+ entry = PADDR(GLLONG(ep->entry));
+ p += sizeof(Exec);
+ addr = entry;
+ n = GLLONG(ep->text);
+ if(addr != (ulong)p){
+ memmove((void*)addr, p, n);
+ print("text: %8.8lux <- %8.8lux [%ld]\n", addr, p, n);
+ }
+ p += n;
+ if(entry >= FLASHMEM)
+ addr = 3*BY2PG; /* kernel text is in Flash, data in RAM */
+ else
+ addr = PGROUND(addr+n);
+ n = GLLONG(ep->data);
+ memmove((void*)addr, p, n);
+ print("data: %8.8lux <- %8.8lux [%ld]\n", addr, p, n);
+ }else{
+ in.data = p;
+ in.rp = in.data;
+ in.lim = p+BOOTLEN;
+ in.wp = in.lim;
+ n = unsqueezef(&in, &entry);
+ if(n < 0)
+ return -1;
+ }
+ print("entry=0x%lux\n", entry);
+ uartwait();
+ scc2stop();
+ /*
+ * Go to new code. It's up to the program to get its PC relocated to
+ * the right place.
+ */
+ b = (void (*)(void))KADDR(PADDR(entry));
+ (*b)();
+ return -1;
+}
diff --git a/os/boot/mpc/fns.h b/os/boot/mpc/fns.h
new file mode 100644
index 00000000..5bf5d90e
--- /dev/null
+++ b/os/boot/mpc/fns.h
@@ -0,0 +1,117 @@
+Alarm* alarm(int, void (*)(Alarm*), void*);
+void alarminit(void);
+void archbacklight(int);
+char* archconfig(void);
+void archdisableuart(int);
+void archenableuart(int, int);
+void archenableusb(int);
+void archetherdisable(int);
+int archetherenable(int, int*, int*);
+int archflashreset(char*, void**, long*);
+void archinit(void);
+int archoptionsw(void);
+int bootp(int, char*);
+void cancel(Alarm*);
+void checkalarms(void);
+void clockinit(void);
+void clockintr(Ureg*, void*);
+void consinit(void);
+void cpminit(void);
+void cpuidprint(void);
+#define dcflush(a,b)
+void delay(int);
+void eieio(void);
+uchar* etheraddr(int);
+int etherinit(void);
+int etherrxpkt(int, Etherpkt*, int);
+int ethertxpkt(int, Etherpkt*, int, int);
+void exception(void);
+int flashboot(int);
+int flashbootable(int);
+char* flashconfig(int);
+int flashinit(void);
+void free(void*);
+void freeb(Block*);
+int getcfields(char*, char**, int, char*);
+char* getconf(char*);
+ulong getdec(void);
+ulong gethid0(void);
+ulong getimmr(void);
+ulong getmsr(void);
+ulong getpvr(void);
+int getstr(char*, char*, int, char*);
+ulong gettbl(void);
+ulong gettbu(void);
+int hardinit(void);
+long hardread(int, void*, long);
+long hardseek(int, long);
+long hardwrite(int, void*, long);
+long i2csend(int, void*, long);
+void i2csetup(void);
+void* ialloc(ulong, int);
+Block* iallocb(int);
+void idle(void);
+int isaconfig(char*, int, ISAConf*);
+int issqueezed(uchar*);
+void kbdchar(Queue*, int);
+void kbdinit(void);
+void kbdreset(void);
+void machinit(void);
+void* malloc(ulong);
+ulong mapalloc(RMap*, ulong, int, int);
+void mapfree(RMap*, ulong, int);
+void mapinit(RMap*, Map*, int);
+void meminit(void);
+void microdelay(int);
+void mmuinit(void);
+int optionsw(void);
+void panic(char*, ...);
+int parseether(uchar*, char*);
+int plan9boot(int, long (*)(int, long), long (*)(int, void*, long));
+void putdec(ulong);
+void puthid0(ulong);
+void putmsr(ulong);
+int qbgetc(Queue*);
+void qbputc(Queue*, int);
+void qbwrite(Queue*, Block*);
+Block* qget(Queue*);
+long qlen(Queue*);
+Queue* qopen(int, int, void (*)(void*), void*);
+#define qpass qbwrite
+void scc2stop(void);
+void sccnmsi(int, int, int);
+void sched(void);
+void screeninit(void);
+void screenputs(char*, int);
+void sdraminit(ulong);
+Partition* sethardpart(int, char*);
+Partition* setscsipart(int, char*);
+void setvec(int, void (*)(Ureg*, void*), void*);
+int splhi(void);
+int spllo(void);
+void splx(int);
+void trapinit(void);
+void uartputs(char*, int);
+void uartsetboot(void (*f)(uchar*, int));
+void uartspecial(int, int, Queue**, Queue**, void(*)(Queue*,int));
+void uartwait(void);
+long unsqueezef(Block*, ulong*);
+
+#define GSHORT(p) (((p)[1]<<8)|(p)[0])
+#define GLONG(p) ((GSHORT(p+2)<<16)|GSHORT(p))
+#define GLSHORT(p) (((p)[0]<<8)|(p)[1])
+#define GLLONG(p) ((GLSHORT(p)<<16)|GLSHORT(p+2))
+
+#define KADDR(a) ((void*)((ulong)(a)|KZERO))
+#define PADDR(a) ((ulong)(a)&~KSEGM)
+
+/* IBM bit field order */
+#define IBIT(b) ((ulong)1<<(31-(b)))
+#define SIBIT(n) ((ushort)1<<(15-(n)))
+
+#define IOREGS(x, T) ((T*)((char*)m->iomem+(x)))
+
+int uartinit(void);
+Partition* setuartpart(int, char*);
+long uartread(int, void*, long);
+long uartseek(int, long);
diff --git a/os/boot/mpc/gbitbltclip.c b/os/boot/mpc/gbitbltclip.c
new file mode 100644
index 00000000..cbf877f5
--- /dev/null
+++ b/os/boot/mpc/gbitbltclip.c
@@ -0,0 +1,52 @@
+#include <u.h>
+#include <libc.h>
+#include <libg.h>
+#include <gnot.h>
+
+void
+gbitbltclip(void *vp)
+{
+ int dx, dy;
+ int i;
+ struct{
+ GBitmap *dm;
+ Point p;
+ GBitmap *sm;
+ Rectangle r;
+ Fcode f;
+ }*bp;
+
+ bp = vp;
+ dx = Dx(bp->r);
+ dy = Dy(bp->r);
+ if(bp->p.x < bp->dm->clipr.min.x){
+ i = bp->dm->clipr.min.x-bp->p.x;
+ bp->r.min.x += i;
+ bp->p.x += i;
+ dx -= i;
+ }
+ if(bp->p.y < bp->dm->clipr.min.y){
+ i = bp->dm->clipr.min.y-bp->p.y;
+ bp->r.min.y += i;
+ bp->p.y += i;
+ dy -= i;
+ }
+ if(bp->p.x+dx > bp->dm->clipr.max.x)
+ bp->r.max.x -= bp->p.x+dx-bp->dm->clipr.max.x;
+ if(bp->p.y+dy > bp->dm->clipr.max.y)
+ bp->r.max.y -= bp->p.y+dy-bp->dm->clipr.max.y;
+ if(bp->r.min.x < bp->sm->clipr.min.x){
+ i = bp->sm->clipr.min.x-bp->r.min.x;
+ bp->p.x += i;
+ bp->r.min.x += i;
+ }
+ if(bp->r.min.y < bp->sm->clipr.min.y){
+ i = bp->sm->clipr.min.y-bp->r.min.y;
+ bp->p.y += i;
+ bp->r.min.y += i;
+ }
+ if(bp->r.max.x > bp->sm->clipr.max.x)
+ bp->r.max.x = bp->sm->clipr.max.x;
+ if(bp->r.max.y > bp->sm->clipr.max.y)
+ bp->r.max.y = bp->sm->clipr.max.y;
+}
diff --git a/os/boot/mpc/gnot.h b/os/boot/mpc/gnot.h
new file mode 100644
index 00000000..7b99e6bb
--- /dev/null
+++ b/os/boot/mpc/gnot.h
@@ -0,0 +1,71 @@
+
+extern void *bbmalloc(int);
+extern void bbfree(void *, int);
+extern int bbonstack(void);
+extern void bbexec(void(*)(void), int, int);
+
+/*
+ * Graphics types
+ */
+
+typedef struct GBitmap GBitmap;
+typedef struct GFont GFont;
+typedef struct GSubfont GSubfont;
+typedef struct GCacheinfo GCacheinfo;
+
+struct GBitmap
+{
+ ulong *base; /* pointer to start of data */
+ long zero; /* base+zero=&word containing (0,0) */
+ ulong width; /* width in 32 bit words of total data area */
+ int ldepth; /* log base 2 of number of bits per pixel */
+ Rectangle r; /* rectangle in data area, local coords */
+ Rectangle clipr; /* clipping region */
+ GBitmap *cache; /* zero; distinguishes bitmap from layer */
+};
+
+
+/*
+ * GFont etc. are not used in the library, only in devbit.c.
+ * GSubfont is only barely used.
+ */
+struct GSubfont
+{
+ short n; /* number of chars in font */
+ char height; /* height of bitmap */
+ char ascent; /* top of bitmap to baseline */
+ Fontchar *info; /* n+1 character descriptors */
+ GBitmap *bits; /* where the characters are */
+};
+struct GCacheinfo
+{
+ ulong xright; /* right edge of bits */
+ Fontchar;
+};
+
+struct GFont
+{
+ uchar height; /* max height of bitmap, interline spacing */
+ char ascent; /* top of bitmap to baseline */
+ char width; /* widest so far; used in caching only */
+ char ldepth; /* of images */
+ short id; /* of font */
+ int ncache; /* number of entries in cache */
+ GCacheinfo *cache; /* cached characters */
+ GBitmap *b; /* cached images */
+};
+
+extern ulong *gaddr(GBitmap*, Point);
+extern uchar *gbaddr(GBitmap*, Point);
+extern void gbitblt(GBitmap*, Point, GBitmap*, Rectangle, Fcode);
+extern void gbitbltclip(void*);
+extern void gtexture(GBitmap*, Rectangle, GBitmap*, Fcode);
+extern Point gsubfstrsize(GSubfont*, char*);
+extern int gsubfstrwidth(GSubfont*, char*);
+extern Point gsubfstring(GBitmap*, Point, GSubfont*, char*, Fcode);
+extern Point gbitbltstring(GBitmap*, Point, GSubfont*, char*, Fcode);
+extern void gsegment(GBitmap*, Point, Point, int, Fcode);
+extern void gpoint(GBitmap*, Point, int, Fcode);
+extern void gflushcpucache(void);
+extern GBitmap* gballoc(Rectangle, int);
+extern void gbfree(GBitmap*);
diff --git a/os/boot/mpc/i2c.c b/os/boot/mpc/i2c.c
new file mode 100644
index 00000000..1cf9243c
--- /dev/null
+++ b/os/boot/mpc/i2c.c
@@ -0,0 +1,351 @@
+#include "boot.h"
+
+/*
+ * basic read/write interface to mpc8xx I2C bus (master mode)
+ */
+
+typedef struct I2C I2C;
+
+struct I2C {
+ uchar i2mod;
+ uchar rsv12a[3];
+ uchar i2add;
+ uchar rsv12b[3];
+ uchar i2brg;
+ uchar rsv12c[3];
+ uchar i2com;
+ uchar rsv12d[3];
+ uchar i2cer;
+ uchar rsv12e[3];
+ uchar i2cmr;
+};
+
+enum {
+ /* i2c-specific BD flags */
+ RxeOV= 1<<1, /* overrun */
+ TxS= 1<<10, /* transmit start condition */
+ TxeNAK= 1<<2, /* last transmitted byte not acknowledged */
+ TxeUN= 1<<1, /* underflow */
+ TxeCL= 1<<0, /* collision */
+ TxERR= (TxeNAK|TxeUN|TxeCL),
+
+ /* i2cmod */
+ REVD= 1<<5, /* =1, LSB first */
+ GCD= 1<<4, /* =1, general call address disabled */
+ FLT= 1<<3, /* =0, not filtered; =1, filtered */
+ PDIV= 3<<1, /* predivisor field */
+ EN= 1<<0, /* enable */
+
+ /* i2com */
+ STR= 1<<7, /* start transmit */
+ I2CM= 1<<0, /* master */
+ I2CS= 0<<0, /* slave */
+
+ /* i2cer */
+ TXE = 1<<4,
+ BSY = 1<<2,
+ TXB = 1<<1,
+ RXB = 1<<0,
+
+ /* port B bits */
+ I2CSDA = IBIT(27),
+ I2CSCL = IBIT(26),
+
+ Rbit = 1<<0, /* bit in address byte denoting read */
+
+ /* maximum I2C I/O (can change) */
+ Bufsize = 64,
+ Tbuflen= Bufsize+4, /* extra address bytes and alignment */
+ Freq = 100000,
+ I2CTimeout = 250, /* msec */
+};
+
+/* data cache needn't be flushed if buffers allocated in uncached INTMEM */
+#define DCFLUSH(a,n)
+
+/*
+ * I2C software structures
+ */
+
+struct Ctlr {
+ Lock;
+ QLock io;
+ int init;
+ I2C* i2c;
+ IOCparam* sp;
+
+ BD* rd;
+ BD* td;
+ int phase;
+ char* addr;
+ char* txbuf;
+ char* rxbuf;
+};
+typedef struct Ctlr Ctlr;
+
+static Ctlr i2ctlr[1];
+extern int predawn;
+
+static void interrupt(Ureg*, void*);
+
+static void
+enable(void)
+{
+ I2C *i2c;
+
+ i2c = i2ctlr->i2c;
+ i2c->i2cer = ~0; /* clear events */
+ eieio();
+ i2c->i2mod |= EN;
+ eieio();
+ i2c->i2cmr = TXE|BSY|TXB|RXB; /* enable all interrupts */
+ eieio();
+}
+
+static void
+disable(void)
+{
+ I2C *i2c;
+
+ i2c = i2ctlr->i2c;
+ i2c->i2cmr = 0; /* mask all interrupts */
+ i2c->i2mod &= ~EN;
+}
+
+/*
+ * called by the reset routine of any driver using the I2C
+ */
+void
+i2csetup(void)
+{
+ IMM *io;
+ I2C *i2c;
+ IOCparam *sp;
+ Ctlr *ctlr;
+ long f, e, emin;
+ int p, d, dmax;
+
+ ctlr = i2ctlr;
+ if(ctlr->init)
+ return;
+ print("i2c setup...\n");
+ ctlr->init = 1;
+ i2c = KADDR(INTMEM+0x860);
+ ctlr->i2c = i2c;
+ sp = KADDR(INTMEM+0x3c80);
+ ctlr->sp = sp;
+ disable();
+
+ if(ctlr->txbuf == nil){
+ ctlr->txbuf = ialloc(Tbuflen, 2);
+ ctlr->addr = ctlr->txbuf+Bufsize;
+ }
+ if(ctlr->rxbuf == nil)
+ ctlr->rxbuf = ialloc(Bufsize, 2);
+ if(ctlr->rd == nil){
+ ctlr->rd = bdalloc(1);
+ ctlr->rd->addr = PADDR(ctlr->rxbuf);
+ ctlr->rd->length = 0;
+ ctlr->rd->status = BDWrap;
+ }
+ if(ctlr->td == nil){
+ ctlr->td = bdalloc(2);
+ ctlr->td->addr = PADDR(ctlr->txbuf);
+ ctlr->td->length = 0;
+ ctlr->td->status = BDWrap|BDLast;
+ }
+
+ /* select port pins */
+ io = ioplock();
+ io->pbdir |= I2CSDA | I2CSCL;
+ io->pbodr |= I2CSDA | I2CSCL;
+ io->pbpar |= I2CSDA | I2CSCL;
+ iopunlock();
+
+ /* explicitly initialise parameters, because InitRxTx can't be used (see i2c/spi relocation errata) */
+ sp = ctlr->sp;
+ sp->rbase = PADDR(ctlr->rd);
+ sp->tbase = PADDR(ctlr->td);
+ sp->rfcr = 0x18;
+ sp->tfcr = 0x18;
+ sp->mrblr = Bufsize;
+ sp->rstate = 0;
+ sp->rptr = 0;
+ sp->rbptr = sp->rbase;
+ sp->rcnt = 0;
+ sp->tstate = 0;
+ sp->tbptr = sp->tbase;
+ sp->tptr = 0;
+ sp->tcnt = 0;
+ eieio();
+
+ i2c->i2com = I2CM;
+ i2c->i2mod = 0; /* normal mode */
+ i2c->i2add = 0;
+
+ emin = Freq;
+ dmax = (m->cpuhz/Freq)/2-3;
+ for(d=0; d < dmax; d++){
+ for(p=3; p>=0; p--){
+ f = (m->cpuhz>>(p+2))/(2*(d+3));
+ e = Freq - f;
+ if(e < 0)
+ e = -e;
+ if(e < emin){
+ emin = e;
+ i2c->i2brg = d;
+ i2c->i2mod = (i2c->i2mod&~PDIV)|((3-p)<<1); /* set PDIV */
+ }
+ }
+ }
+ //print("i2brg=%d i2mod=#%2.2ux\n", i2c->i2brg, i2c->i2mod);
+ setvec(VectorCPIC+0x10, interrupt, i2ctlr);
+}
+
+enum {
+ Idling,
+ Done,
+ Busy,
+ Sending,
+ Recving,
+};
+
+static void
+interrupt(Ureg*, void *arg)
+{
+ int events;
+ Ctlr *ctlr;
+ I2C *i2c;
+
+ ctlr = arg;
+ i2c = ctlr->i2c;
+ events = i2c->i2cer;
+ eieio();
+ i2c->i2cer = events;
+ if(events & (BSY|TXE)){
+ //print("I2C#%x\n", events);
+ if(ctlr->phase != Idling){
+ ctlr->phase = Idling;
+ }
+ }else{
+ if(events & TXB){
+ //print("i2c: xmt %d %4.4ux %4.4ux\n", ctlr->phase, ctlr->td->status, ctlr->td[1].status);
+ if(ctlr->phase == Sending){
+ ctlr->phase = Done;
+ }
+ }
+ if(events & RXB){
+ //print("i2c: rcv %d %4.4ux %d\n", ctlr->phase, ctlr->rd->status, ctlr->rd->length);
+ if(ctlr->phase == Recving){
+ ctlr->phase = Done;
+ }
+ }
+ }
+}
+
+static int
+done(void *a)
+{
+ return ((Ctlr*)a)->phase < Busy;
+}
+
+static void
+i2cwait(Ctlr *ctlr)
+{
+ /* TO DO: timeout */
+ while(!done(ctlr)){
+ if(predawn)
+ interrupt(nil, ctlr);
+ }
+}
+
+long
+i2csend(int addr, void *buf, long n)
+{
+ Ctlr *ctlr;
+ int i, p, s;
+
+ ctlr = i2ctlr;
+ if(n > Bufsize)
+ return -1;
+ i = 1;
+ ctlr->txbuf[0] = addr & ~1;
+ if(addr & 1){
+ ctlr->txbuf[1] = addr>>8;
+ i++;
+ }
+ memmove(ctlr->txbuf+i, buf, n);
+ DCFLUSH(ctlr->txbuf, Tbuflen);
+ ctlr->phase = Sending;
+ ctlr->rd->status = BDEmpty|BDWrap|BDInt;
+ ctlr->td->addr = PADDR(ctlr->txbuf);
+ ctlr->td->length = n+i;
+ ctlr->td->status = BDReady|BDWrap|BDLast|BDInt;
+ enable();
+ ctlr->i2c->i2com = STR|I2CM;
+ eieio();
+ i2cwait(ctlr);
+ disable();
+ p = ctlr->phase;
+ s = ctlr->td->status;
+ if(s & BDReady || s & TxERR || p != Done)
+ return -1;
+ return n;
+}
+
+long
+i2crecv(int addr, void *buf, long n)
+{
+ Ctlr *ctlr;
+ int p, s, flag;
+ BD *td;
+ long nr;
+
+ ctlr = i2ctlr;
+ if(n > Bufsize)
+ return -1;
+ ctlr->txbuf[0] = addr|Rbit;
+ if(addr & 1){ /* special select sequence */
+ ctlr->addr[0] = addr &~ 1;
+ ctlr->addr[1] = addr>>8;
+ }
+ DCFLUSH(ctlr->txbuf, Tbuflen);
+ DCFLUSH(ctlr->rxbuf, Bufsize);
+ ctlr->phase = Recving;
+ ctlr->rd->addr = PADDR(ctlr->rxbuf);
+ ctlr->rd->status = BDEmpty|BDWrap|BDInt;
+ flag = 0;
+ td = ctlr->td;
+ td[1].status = 0;
+ if(addr & 1){
+ /* special select sequence */
+ td->addr = PADDR(ctlr->addr);
+ td->length = 2;
+ /* td->status made BDReady below */
+ td++;
+ flag = TxS;
+ }
+ td->addr = PADDR(ctlr->txbuf);
+ td->length = n+1;
+ td->status = BDReady|BDWrap|BDLast | flag; /* not BDInt: leave that to receive */
+ if(flag)
+ ctlr->td->status = BDReady;
+ enable();
+ ctlr->i2c->i2com = STR|I2CM;
+ eieio();
+ i2cwait(ctlr);
+ disable();
+ p = ctlr->phase;
+ s = ctlr->td->status;
+ if(flag)
+ s |= ctlr->td[1].status;
+ nr = ctlr->rd->length;
+ if(nr > n)
+ nr = n; /* shouldn't happen */
+ if(s & TxERR || s & BDReady || ctlr->rd->status & BDEmpty)
+ return -1;
+ if(p != Done)
+ return -1;
+ memmove(buf, ctlr->rxbuf, nr);
+ return nr;
+}
diff --git a/os/boot/mpc/initfads.c b/os/boot/mpc/initfads.c
new file mode 100644
index 00000000..eed7c319
--- /dev/null
+++ b/os/boot/mpc/initfads.c
@@ -0,0 +1,187 @@
+/*
+ * Called from l.s in EPROM to set up a minimal working environment.
+ * Since there is no DRAM yet, and therefore no stack, no function
+ * calls may be made from sysinit0, and values can't be stored,
+ * except to INTMEM. Global values are accessed by offset from SB,
+ * which has been set by l.s to point into EPROM.
+ *
+ * This is FADS-specific in CS assignment and access of the FADS BCSR
+ * to discover memory size and speed.
+ */
+
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "archfads.h"
+
+#define MB (1024*1024)
+
+enum {
+ UPMSIZE = 64, /* memory controller instruction RAM */
+ SPEED = 50, /* maximum memory clock in MHz */
+ SDRAMSIZE = 4*MB,
+
+ /* mcr */
+ WriteRAM = 0<<30,
+ ReadRAM = 1<<30,
+ ExecRAM = 2<<30,
+
+ SelUPMA = 0<<23,
+ SelUPMB = 1<<23,
+
+ Once = 1<<8,
+};
+
+/*
+ * mpc8bug uses the following for 60ns EDO DRAMs 32-50MHz
+ */
+static ulong upma50[UPMSIZE] = {
+ 0x8FFFEC24, 0xFFFEC04, 0xCFFEC04, 0xFFEC04,
+ 0xFFEC00, 0x37FFEC47, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x8FFFEC24, 0xFFFEC04, 0x8FFEC04, 0xFFEC0C,
+ 0x3FFEC00, 0xFFEC44, 0xFFCC08, 0xCFFCC44,
+ 0xFFEC0C, 0x3FFEC00, 0xFFEC44, 0xFFCC00,
+ 0x3FFFC847, 0x3FFFEC47, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x8FAFCC24, 0xFAFCC04, 0xCAFCC00, 0x11BFCC47,
+ 0xC0FFCC84, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x8FAFCC24, 0xFAFCC04, 0xCAFCC00, 0x3AFCC4C,
+ 0xCAFCC00, 0x3AFCC4C, 0xCAFCC00, 0x3AFCC4C,
+ 0xCAFCC00, 0x33BFCC4F, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xC0FFCC84, 0xFFCC04, 0x7FFCC04, 0x3FFFCC06,
+ 0xFFFFCC85, 0xFFFFCC05, 0xFFFFCC05, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x33FFCC07, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+};
+
+/*
+ * the FADS manual table 3-7 suggests the following for 60ns EDO DRAMs at 20MHz
+ */
+static ulong upma20[UPMSIZE] = {
+ 0x8FFFCC04, 0x08FFCC00, 0x33FFCC47, ~0, ~0, ~0, ~0, ~0,
+ [0x08] 0x8FFFCC04, 0x08FFCC08, 0x08FFCC08, 0x08FFCC08, 0x08FFCC00, 0x3FFFCC47, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
+ [0x18] 0x8FEFCC00, 0x39BFCC47, ~0, ~0, ~0, ~0, ~0, ~0,
+ [0x20] 0x8FEFCC00, 0x09AFCC48, 0x09AFCC48, 0x08AFCC48, 0x39BFCC47, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
+ [0x30] 0x80FFCC84, 0x17FFCC04, 0xFFFFCC86, 0xFFFFCC05, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
+ [0x3C] 0x33FFCC07, ~0, ~0, ~0,
+};
+
+void
+sysinit0(int inrom)
+{
+ ulong *upm, *bcsr;
+ IMM *io;
+ int i, mb;
+
+ io = (IMM*)INTMEM; /* running before maps, no KADDR */
+
+ /* system interface unit initialisation, FADS manual table 3-2, except as noted */
+ io->siumcr = 0x01012440;
+ io->sypcr = 0xFFFFFF88;
+ io->tbscrk = KEEP_ALIVE_KEY;
+ io->tbscr = 0xC3; /* time base enabled */
+ io->rtcsck = KEEP_ALIVE_KEY;
+ io->rtcsc = 0xC1; /* don't FRZ, real-time clock enabled */
+ io->rtcsck = ~KEEP_ALIVE_KEY;
+ io->piscrk = KEEP_ALIVE_KEY;
+ io->piscr = 0x82;
+
+ io->memc[BCSRCS].option = 0xFFFF8110; /* 32k block, all types access, CS early negate, 1 ws */
+ io->memc[BCSRCS].base = BCSRMEM | 1; /* base, 32-bit port, no parity, GPCM */
+
+ io->memc[BOOTCS].base = FLASHMEM | 1;
+ io->memc[BOOTCS].option = 0xFF800D54;
+
+ if(!inrom)
+ return; /* can't initialise DRAM controller from DRAM */
+
+ bcsr = (ulong*)BCSRMEM;
+// bcsr[1] &= ~DisableDRAM;
+ /* could check DRAM speed here; assume 60ns */
+ switch((bcsr[2]>>23)&3){
+ default: return; /* can't happen; for the compiler */
+ case 0: mb = 4; break;
+ case 1: mb = 32; break;
+ case 2: mb = 16; break;
+ case 3: mb = 8; break;
+ }
+
+ upm = upma50;
+ for(i=0; i<UPMSIZE; i++){
+ io->mdr = upm[i];
+ io->mcr = WriteRAM | SelUPMA | i;
+ }
+ io->mptpr = 0x0400;
+ if(SPEED >= 32)
+ io->mamr = (0x9C<<24) | 0xA21114; /* 50MHz BRGCLK; FADS manual says 0xC0, mpc8bug sets 0x9C */
+ else if(SPEED >= 20)
+ io->mamr = (0x60<<24) | 0xA21114; /* 25MHz BRGCLK */
+ else
+ io->mamr = (0x40<<24) | 0xA21114; /* 16.67MHz BRGCLK */
+ io->memc[DRAM1].option = ~((mb<<20)-1)|0x0800; /* address mask, SAM=1 */
+ io->memc[DRAM1].base = 0 | 0x81; /* base at 0, 32-bit port size, no parity, UPMA */
+}
+
+/*
+ * the FADS manual table 3-9's suggestion for MB811171622A-100 32+MHz-50MHz
+ */
+static ulong upmb50[UPMSIZE] = {
+ [0x00] 0x1F07FC04, 0xEEAEFC04, 0x11ADFC04, 0xEFBBBC00, 0x1FF77C47,
+ [0x05] 0x1FF77C34, 0xEFEABC34, 0x1FB57C35,
+ [0x08] 0x1F07FC04, 0xEEAEFC04, 0x10ADFC04, 0xF0AFFC00, 0xF0AFFC00, 0xF1AFFC00, 0xEFBBBC00, 0x1FF77C47, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
+ [0x18] 0x1F27FC04, 0xEEAEBC00, 0x01B93C04, 0x1FF77C47, ~0, ~0, ~0, ~0,
+ [0x20] 0x1F07FC04, 0xEEAEBC00, 0x10AD7C00, 0xF0AFFC00, 0xF0AFFC00, 0xE1BBBC04, 0x1FF77C47, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
+ [0x30] 0x1FF5FC84, 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC84, 0xFFFFFC07, ~0, ~0, ~0, ~0, ~0, ~0,
+ [0x3C] 0x7FFFFC07, ~0, ~0, ~0,
+};
+
+/*
+ * the FADS manual table 3-8's suggestion for MB811171622A-100 up to 32MHz
+ */
+static ulong upmb32[UPMSIZE] = {
+ [0x00] 0x126CC04, 0xFB98C00, 0x1FF74C45, ~0, ~0,
+ [0x05] 0x1FE77C34, 0xEFAABC34, 0x1FA57C35,
+ [0x08] 0x0026FC04, 0x10ADFC00, 0xF0AFFC00, 0xF1AFFC00, 0xEFBBBC00, 0x1FF77C45, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
+ [0x18] 0x0E26BC04, 0x01B93C00, 0x1FF77C45, ~0, ~0, ~0, ~0, ~0,
+ [0x20] 0x0E26BC00, 0x10AD7C00, 0xF0AFFC00, 0xF0AFFC00, 0xE1BBBC04, 0x1FF77C45, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
+ [0x30] 0x1FF5FC84, 0xFFFFFC04, 0xFFFFFC84, 0xFFFFFC05, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
+ [0x3C] 0x7FFFFC07, ~0, ~0, ~0,
+};
+
+/*
+ * optionally called by archfads.c:/^archinit to initialise access to SDRAM
+ */
+void
+sdraminit(ulong base)
+{
+ ulong *upm;
+ IMM *io;
+ int i;
+
+ io = (IMM*)INTMEM; /* running before maps, no KADDR */
+ if(SPEED > 32)
+ upm = upmb50;
+ else
+ upm = upmb32;
+ for(i=0; i<UPMSIZE; i++){
+ io->mdr = upm[i];
+ io->mcr = WriteRAM | SelUPMB | i;
+ }
+ io->memc[SDRAM].option = ~(SDRAMSIZE-1)|0x0A00; /* address mask, SAM=1, G5LS=1 */
+ io->memc[SDRAM].base = base | 0xC1;
+ if(SPEED > 32){
+ io->mbmr = 0xD0802114; /* 50MHz BRGCLK */
+ io->mar = 0x88;
+ }else{
+ io->mbmr = 0x80802114; /* 32MHz BRGCLK */
+ io->mar = 0x48;
+ }
+ io->mcr = ExecRAM | SelUPMB | (SDRAM<<13) | Once | 5; /* run MRS command in locations 5-8 of UPMB */
+ io->mbmr = (io->mbmr & ~0xF) | 8;
+ io->mcr = ExecRAM | SelUPMB | (SDRAM<<13) | Once | 0x30; /* run refresh sequence */
+ io->mbmr = (io->mbmr & ~0xF) | 4; /* 4-beat refresh bursts */
+}
diff --git a/os/boot/mpc/initpaq.c b/os/boot/mpc/initpaq.c
new file mode 100644
index 00000000..d10d92ce
--- /dev/null
+++ b/os/boot/mpc/initpaq.c
@@ -0,0 +1,101 @@
+/*
+ * Called from l.s in EPROM to set up a minimal working environment.
+ * Since there is no DRAM yet, and therefore no stack, no function
+ * calls may be made from sysinit0, and values can't be stored,
+ * except to INTMEM. Global values are accessed by offset from SB,
+ * which has been set by l.s to point into EPROM.
+ *
+ * This is PowerPAQ-specific:
+ * - assumes 8mbytes
+ * - powerpaq CS assignment
+ */
+
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "archpaq.h"
+
+#define MB (1024*1024)
+
+enum {
+ DRAMSIZE = 8*MB,
+ FLASHSIZE = 8*MB,
+
+ UPMSIZE = 64, /* memory controller instruction RAM */
+ SPEED = 50, /* maximum memory clock in MHz */
+
+ /* mcr */
+ WriteRAM = 0<<30,
+ ReadRAM = 1<<30,
+ ExecRAM = 2<<30,
+
+ SelUPMA = 0<<23,
+ SelUPMB = 1<<23,
+
+ Once = 1<<8,
+};
+
+/*
+ * mpc8bug uses the following for 60ns EDO DRAMs 32-50MHz
+ */
+static ulong upmb50[UPMSIZE] = {
+ 0x8FFFEC24, 0xFFFEC04, 0xCFFEC04, 0xFFEC04,
+ 0xFFEC00, 0x37FFEC47, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x8FFFEC24, 0xFFFEC04, 0x8FFEC04, 0xFFEC0C,
+ 0x3FFEC00, 0xFFEC44, 0xFFCC08, 0xCFFCC44,
+ 0xFFEC0C, 0x3FFEC00, 0xFFEC44, 0xFFCC00,
+ 0x3FFFC847, 0x3FFFEC47, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x8FAFCC24, 0xFAFCC04, 0xCAFCC00, 0x11BFCC47,
+ 0xC0FFCC84, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x8FAFCC24, 0xFAFCC04, 0xCAFCC00, 0x3AFCC4C,
+ 0xCAFCC00, 0x3AFCC4C, 0xCAFCC00, 0x3AFCC4C,
+ 0xCAFCC00, 0x33BFCC4F, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xC0FFCC84, 0xFFCC04, 0x7FFCC04, 0x3FFFCC06,
+ 0xFFFFCC85, 0xFFFFCC05, 0xFFFFCC05, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x33FFCC07, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+};
+
+void
+sysinit0(int inrom)
+{
+ ulong *upm;
+ IMM *io;
+ int i;
+
+ io = (IMM*)INTMEM; /* running before maps, no KADDR */
+
+ /* system interface unit initialisation, FADS manual table 3-2, except as noted */
+ io->siumcr = 0x01012440;
+ io->sypcr = 0xFFFFFF88;
+ io->tbscrk = KEEP_ALIVE_KEY;
+ io->tbscr = 0xC3; /* time base enabled */
+ io->rtcsck = KEEP_ALIVE_KEY;
+ io->rtcsc = 0xC1; /* don't FRZ, real-time clock enabled */
+ io->rtcsck = ~KEEP_ALIVE_KEY;
+ io->piscrk = KEEP_ALIVE_KEY;
+ io->piscr = 0x82;
+
+ io->memc[BOOTCS].base = FLASHMEM | 1;
+ io->memc[BOOTCS].option = ~(FLASHSIZE-1)|(1<<8)|(2<<4); /* mask, BIH, 2 wait states */
+
+ if(!inrom)
+ return; /* can't initialise DRAM controller from DRAM */
+
+ /* could check DRAM speed here; assume 60ns */
+ /* could probe DRAM for size here; assume DRAMSIZE */
+ io->mptpr = 0x400; /* powerpaq flash has 0x1000 */
+ io->mbmr = (0xC0<<24) | 0xA21114; /* 50MHz BRGCLK */
+ upm = upmb50;
+ for(i=0; i<UPMSIZE; i++){
+ io->mdr = upm[i];
+ io->mcr = WriteRAM | SelUPMB | i;
+ }
+ io->memc[DRAM1].option = ~(DRAMSIZE-1)|0x0800; /* address mask, SAM=1 */
+ io->memc[DRAM1].base = 0 | 0xC1; /* base at 0, 32-bit port size, no parity, UPMB */
+}
diff --git a/os/boot/mpc/initrpcg.c b/os/boot/mpc/initrpcg.c
new file mode 100644
index 00000000..55219548
--- /dev/null
+++ b/os/boot/mpc/initrpcg.c
@@ -0,0 +1,91 @@
+
+/*
+ * Called from l.s in EPROM to set up a minimal working environment.
+ * Since there is no DRAM yet, and therefore no stack, no function
+ * calls may be made from sysinit, and values can't be stored,
+ * except to INTMEM. Global values are accessed by offset from SB,
+ * which has been set by l.s to point into EPROM.
+ */
+
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "archrpcg.h"
+
+#define MB (1024*1024)
+
+enum {
+ UPMSIZE = 64, /* memory controller instruction RAM */
+ DRAMSIZE = 16*MB,
+ FLASHSIZE = 4*MB,
+
+ WriteRAM = 0<<30,
+ ReadRAM = 1<<30,
+ ExecRAM = 2<<30,
+
+ SelUPMA = 0<<23,
+ SelUPMB = 1<<23,
+};
+/* RPCG values for RPXLite AW */
+static ulong upma50[UPMSIZE] = {
+ 0xCFFFCC24, 0x0FFFCC04, 0x0CAFCC04, 0x03AFCC08,
+ 0x3FBFCC27, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25,
+ 0xCFFFCC24, 0x0FFFCC04, 0x0CAFCC84, 0x03AFCC88,
+ 0x3FBFCC27, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25,
+ 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25,
+ 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25,
+ 0xCFFFCC24, 0x0FFFCC04, 0x0CFFCC04, 0x03FFCC00,
+ 0x3FFFCC27, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25,
+ 0xCFFFCC24, 0x0FFFCC04, 0x0CFFCC84, 0x03FFCC84,
+ 0x0CFFCC00, 0x33FFCC27, 0xFFFFCC25, 0xFFFFCC25,
+ 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25,
+ 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25,
+ 0xC0FFCC24, 0x03FFCC24, 0x0FFFCC24, 0x0FFFCC24,
+ 0x3FFFCC27, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25,
+ 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25,
+ 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25, 0xFFFFCC25,
+};
+
+void
+sysinit0(int inrom)
+{
+ ulong *upm;
+ IMM *io;
+ int i;
+
+ io = (IMM*)INTMEM; /* running before maps, no KADDR */
+ io->siumcr = 0x01012440;
+ io->sypcr = 0xFFFFFF88;
+ io->tbscrk = KEEP_ALIVE_KEY;
+ io->tbscr = 0xC3;
+ io->rtcsck = KEEP_ALIVE_KEY;
+ io->rtcsc = 0xC1;
+ io->rtcsck = ~KEEP_ALIVE_KEY;
+ io->piscrk = KEEP_ALIVE_KEY;
+ io->piscr = 0x82;
+return;
+ io->memc[BCSRCS].option = 0xFFFF8910; /* 32k block, all types access, CSNT, CS early negate, burst inhibit, 1 ws */
+ io->memc[BCSRCS].base = BCSRMEM | 1; /* base, 32-bit port, no parity, GPCM */
+
+ io->memc[BOOTCS].base = FLASHMEM | 0x801; /* base, 16 bit port */
+ io->memc[BOOTCS].option = ~(FLASHSIZE-1)|(1<<8)|(4<<4); /* mask, BIH, 4 wait states */
+
+ if(1||!inrom)
+ return; /* can't initialise DRAM controller from DRAM */
+
+ /* TO DO: could check DRAM size and speed now */
+
+ upm = upma50;
+ for(i=0; i<nelem(upma50); i++){
+ io->mdr = upm[i];
+ io->mcr = WriteRAM | SelUPMA | i;
+ }
+ io->mptpr = 0x0800; /* divide by 8 */
+ io->mamr = (0x58<<24) | 0xA01430; /* 40MHz BRGCLK */
+ io->memc[DRAM1].option = ~(DRAMSIZE-1)|0x0E00; /* address mask, SAM=1, G5LA/S=3 */
+ io->memc[DRAM1].base = 0 | 0x81; /* base at 0, 32-bit port size, no parity, UPMA */
+}
diff --git a/os/boot/mpc/io.h b/os/boot/mpc/io.h
new file mode 100644
index 00000000..8ae1d5b3
--- /dev/null
+++ b/os/boot/mpc/io.h
@@ -0,0 +1,463 @@
+enum
+{
+ /* software interrupt vectors (SIU and CPM) */
+ VectorPIC= 0, /* level 0 to level 7, assigned by software */
+ CPIClevel= 4,
+ VectorIRQ= VectorPIC+8, /* IRQ0 to IRQ7 */
+ VectorCPIC= VectorIRQ+8, /* 32 CPM interrupts: 0 (error) to 0x1F (PC15) */
+};
+
+enum
+{
+ BUSUNKNOWN = 0,
+};
+
+/*
+ * Buffer Descriptors and IO Rings
+ */
+
+typedef struct BD BD;
+struct BD {
+ ushort status;
+ ushort length;
+ ulong addr;
+};
+
+BD* bdalloc(int);
+void bdfree(BD*, int);
+
+enum {
+ /* Rx BDs, bits common to all protocols */
+ BDEmpty= 1<<15,
+ BDWrap= 1<<13,
+ BDInt= 1<<12,
+ BDLast= 1<<11,
+ BDFirst= 1<<10,
+
+ /* Tx BDs */
+ BDReady= 1<<15,
+ /* BDWrap, BDInt, BDLast */
+};
+
+typedef struct Ring Ring;
+struct Ring {
+ BD* rdr; /* receive descriptor ring */
+ void* rrb; /* receive ring buffers */
+ int rdrx; /* index into rdr */
+ int nrdre; /* length of rdr */
+
+ BD* tdr; /* transmit descriptor ring */
+ Block** txb; /* corresponding transmit ring buffers */
+ int tdrh; /* host index into tdr */
+ int tdri; /* interface index into tdr */
+ int ntdre; /* length of tdr */
+ int ntq; /* pending transmit requests */
+};
+
+#define NEXT(x, l) (((x)+1)%(l))
+#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
+#define HOWMANY(x, y) (((x)+((y)-1))/(y))
+#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
+
+int ioringinit(Ring*, int, int, int);
+
+/*
+ * CPM
+ */
+enum {
+ /* commands */
+ InitRxTx = 0,
+ InitRx = 1,
+ InitTx = 2,
+ EnterHunt= 3,
+ StopTx= 4,
+ GracefulStopTx = 5,
+ InitIDMA = 5,
+ RestartTx = 6,
+ CloseRxBD = 7,
+ SetGroupAddr = 8,
+ SetTimer = 8,
+ GCITimeout = 9,
+ GCIAbort = 10,
+ StopIDMA = 11,
+ StartDSP = 12,
+ ArmIDMA = 13,
+ InitDSP = 13,
+ USBCmd = 15,
+
+ /* channel IDs */
+ SCC1ID= 0,
+ USBID= 0,
+ I2CID= 1,
+ IDMA1ID= 1,
+ SCC2ID= 4,
+ SPIID= 5,
+ IDMA2ID= 5,
+ TIMERID= 5,
+ SCC3ID= 8,
+ SMC1ID= 9,
+ DSP1ID=9,
+ SCC4ID= 12,
+ SMC2ID= 13,
+ DSP2ID= 13,
+
+ BaudEnable = 1<<16,
+
+ /* sicr */
+ CLK1 = 4, /* SCC1,2 */
+ CLK2 = 5,
+ CLK3 = 6,
+ CLK4 = 7,
+ CLK5 = CLK1, /* SCC3,4 */
+ CLK6 = CLK2,
+ CLK7 = CLK3,
+ CLK8 = CLK4,
+};
+
+void cpmop(int, int, int);
+#define ioplock() (m->iomem)
+#define iopunlock()
+
+/*
+ * the structures below follow hardware/firmware layouts in the 8xx manuals:
+ * mind the data types, offsets and alignment
+ */
+
+/*
+ * basic IO controller parameters (SMC and SCC)
+ */
+typedef struct IOCparam IOCparam;
+struct IOCparam {
+ ushort rbase;
+ ushort tbase;
+ uchar rfcr;
+ uchar tfcr;
+ ushort mrblr;
+ ulong rstate;
+ ulong rptr;
+ ushort rbptr;
+ ushort rcnt;
+ ulong rtmp;
+ ulong tstate;
+ ulong tptr;
+ ushort tbptr;
+ ushort tcnt;
+ ulong ttmp;
+};
+
+typedef struct SCCparam SCCparam;
+struct SCCparam {
+ IOCparam;
+ ulong rcrc;
+ ulong tcrc;
+};
+
+typedef struct SCC SCC;
+struct SCC {
+ ulong gsmrl;
+ ulong gsmrh;
+ ushort psmr;
+ uchar rsvscc0[2];
+ ushort todr;
+ ushort dsr;
+ ushort scce;
+ uchar rsvscc1[2];
+ ushort sccm;
+ uchar rsvscc3;
+ uchar sccs;
+ ushort irmode;
+ ushort irsip;
+};
+
+typedef struct SMC SMC;
+struct SMC {
+ uchar pad1[2];
+ ushort smcmr;
+ uchar pad2[2];
+ uchar smce;
+ uchar pad3[3];
+ uchar smcm;
+ uchar pad4[5];
+};
+
+typedef struct SPI SPI;
+struct SPI {
+ ushort spmode;
+ uchar res1[4];
+ uchar spie;
+ uchar res2[3];
+ uchar spim;
+ uchar res3[2];
+ uchar spcom;
+ uchar res4[10];
+};
+
+typedef struct USB USB;
+struct USB { /* 823 only */
+ uchar usmod;
+ uchar usadr;
+ uchar uscom;
+ uchar rsvu1;
+ ushort usep[4];
+ uchar rsvu2[4];
+ ushort usber;
+ uchar rsvu3[2];
+ ushort usbmr;
+ uchar rsvu4;
+ uchar usbs;
+ uchar rsvu5[8];
+};
+
+typedef struct IMM IMM;
+struct IMM {
+ struct { /* general SIU */
+ ulong siumcr;
+ ulong sypcr;
+ uchar rsv0[0xE-0x8];
+ ushort swsr;
+ ulong sipend;
+ ulong simask;
+ ulong siel;
+ uchar sivec;
+ uchar padv[3];
+ ulong tesr;
+ uchar rsv1[0x30-0x24];
+ ulong sdcr;
+ uchar rsv2[0x80-0x34];
+ };
+ struct { /* PCMCIA */
+ struct {
+ ulong base;
+ ulong option;
+ } pcmr[8];
+ uchar rsv3[0xe0-0xc0];
+ ulong pgcra;
+ ulong pgcrb;
+ ulong pscr;
+ uchar rsv4[0xf0-0xec];
+ ulong pipr;
+ uchar rsv5[4];
+ ulong per;
+ uchar rsv6[4];
+ };
+ struct { /* MEMC */
+ struct {
+ ulong base;
+ ulong option;
+ } memc[8];
+ uchar rsv7a[0x24];
+ ulong mar;
+ ulong mcr;
+ uchar rsv7b[4];
+ ulong mamr;
+ ulong mbmr;
+ ushort mstat;
+ ushort mptpr;
+ ulong mdr;
+ uchar rsv7c[0x80];
+ };
+ struct { /* system integration timers */
+ ushort tbscr;
+ uchar rsv8a[2];
+ ulong tbrefu;
+ ulong tbrefl;
+ uchar rsv8b[0x14];
+ ushort rtcsc;
+ uchar rsv8c[2];
+ ulong rtc;
+ ulong rtsec;
+ ulong rtcal;
+ uchar rsv8d[0x10];
+ ushort piscr;
+ ushort rsv8e;
+ ulong pitc;
+ ulong pitr;
+ uchar rsv8f[0x34];
+ };
+ struct { /* 280: clocks and resets */
+ ulong sccr;
+ ulong plprcr;
+ ulong rsr;
+ uchar rsv9[0x300-0x28c];
+ };
+ struct { /* 300: system integration timers keys */
+ ulong tbscrk;
+ ulong tbrefuk;
+ ulong tbreflk;
+ ulong tbk;
+ uchar rsv10a[0x10];
+ ulong rtcsck;
+ ulong rtck;
+ ulong rtseck;
+ ulong rtcalk;
+ uchar rsv10b[0x10];
+ ulong piscrk;
+ ulong pitck;
+ uchar rsv10c[0x38];
+ };
+ struct { /* 380: clocks and resets keys */
+ ulong sccrk;
+ ulong plprcrk;
+ ulong rsrk;
+ uchar rsv11[0x800-0x38C];
+ };
+ struct { /* 800: video controller */
+ ushort vccr;
+ ushort pad11a;
+ uchar vsr;
+ uchar pad11b;
+ uchar vcmr;
+ uchar pad11c;
+ ulong vbcb;
+ ulong pad11d;
+ ulong vfcr0;
+ ulong vfaa0;
+ ulong vfba0;
+ ulong vfcr1;
+ ulong vfaa1;
+ ulong vfba1;
+ uchar rsv11a[0x840-0x828];
+ };
+ struct { /* 840: LCD */
+ ulong lccr;
+ ulong lchcr;
+ ulong lcvcr;
+ ulong rsv11b;
+ ulong lcfaa;
+ ulong lcfba;
+ uchar lcsr;
+ uchar rsv11c[0x860-0x859];
+ };
+ struct { /* 860: I2C */
+ uchar i2mod;
+ uchar rsv12a[3];
+ uchar i2add;
+ uchar rsv12b[3];
+ uchar i2brg;
+ uchar rsv12c[3];
+ uchar i2com;
+ uchar rsv12d[3];
+ uchar i2cer;
+ uchar rsv12e[3];
+ uchar i2cmr;
+ uchar rsv12[0x900-0x875];
+ };
+ struct { /* 900: DMA */
+ uchar rsv13[4];
+ ulong sdar;
+ uchar sdsr;
+ uchar pad1[3];
+ uchar sdmr;
+ uchar pad2[3];
+ uchar idsr1;
+ uchar pad3[3];
+ uchar idmr1;
+ uchar pad4[3];
+ uchar idsr2;
+ uchar pad5[3];
+ uchar idmr2;
+ uchar pad6[0x930-0x91D];
+ };
+ struct { /* CPM interrupt control */
+ ushort civr;
+ uchar pad7[0x940-0x932];
+ ulong cicr;
+ ulong cipr;
+ ulong cimr;
+ ulong cisr;
+ };
+ struct { /* input/output port */
+ ushort padir;
+ ushort papar;
+ ushort paodr;
+ ushort padat;
+ uchar pad8[8];
+ ushort pcdir;
+ ushort pcpar;
+ ushort pcso;
+ ushort pcdat;
+ ushort pcint;
+ uchar pad9[6];
+ ushort pddir;
+ ushort pdpar;
+ ushort rsv14a;
+ ushort pddat;
+ uchar rsv14[0x980-0x978];
+ };
+ struct { /* CPM timers */
+ ushort tgcr;
+ uchar rsv15a[0x990-0x982];
+ ushort tmr1;
+ ushort tmr2;
+ ushort trr1;
+ ushort trr2;
+ ushort tcr1;
+ ushort tcr2;
+ ushort tcn1;
+ ushort tcn2;
+ ushort tmr3;
+ ushort tmr4;
+ ushort trr3;
+ ushort trr4;
+ ushort tcr3;
+ ushort tcr4;
+ ushort tcn3;
+ ushort tcn4;
+ ushort ter1;
+ ushort ter2;
+ ushort ter3;
+ ushort ter4;
+ uchar rsv15[0x9C0-0x9B8];
+ };
+ struct { /* CPM */
+ ushort cpcr;
+ uchar res0[2];
+ ushort rccr;
+ uchar res1;
+ uchar rmds;
+ uchar res2a[4];
+ ushort rctr1;
+ ushort rctr2;
+ ushort rctr3;
+ ushort rctr4;
+ uchar res2[2];
+ ushort rter;
+ uchar res3[2];
+ ushort rtmr;
+ uchar rsv16[0x9F0-0x9DC];
+ };
+ union { /* BRG */
+ struct {
+ ulong brgc1;
+ ulong brgc2;
+ ulong brgc3;
+ ulong brgc4;
+ };
+ ulong brgc[4];
+ };
+ uchar skip0[0xAB2-0xA00]; /* USB, SCC, SMC, SPI: address using cpmdev(CP...)->regs */
+ struct { /* PIP */
+ ushort pipc; /* not 823 */
+ ushort ptpr; /* not 823 */
+ ulong pbdir;
+ ulong pbpar;
+ uchar pad10[2];
+ ushort pbodr;
+ ulong pbdat;
+ uchar pad11[0xAE0-0xAC8];
+ };
+ struct { /* SI */
+ ulong simode;
+ uchar sigmr;
+ uchar pad12;
+ uchar sistr;
+ uchar sicmr;
+ uchar pad13[4];
+ ulong sicr;
+ ulong sirp;
+ uchar pad14[0xB00-0xAF4];
+ };
+ ulong vcram[64];
+ ushort siram[256];
+ ushort lcdmap[256];
+};
diff --git a/os/boot/mpc/ip.h b/os/boot/mpc/ip.h
new file mode 100644
index 00000000..a39b5b4b
--- /dev/null
+++ b/os/boot/mpc/ip.h
@@ -0,0 +1,98 @@
+typedef struct Udphdr Udphdr;
+struct Udphdr
+{
+ uchar d[6]; /* Ethernet destination */
+ uchar s[6]; /* Ethernet source */
+ uchar type[2]; /* Ethernet packet type */
+
+ uchar vihl; /* Version and header length */
+ uchar tos; /* Type of service */
+ uchar length[2]; /* packet length */
+ uchar id[2]; /* Identification */
+ uchar frag[2]; /* Fragment information */
+
+ /* Udp pseudo ip really starts here */
+ uchar ttl;
+ uchar udpproto; /* Protocol */
+ uchar udpplen[2]; /* Header plus data length */
+ uchar udpsrc[4]; /* Ip source */
+ uchar udpdst[4]; /* Ip destination */
+ uchar udpsport[2]; /* Source port */
+ uchar udpdport[2]; /* Destination port */
+ uchar udplen[2]; /* data length */
+ uchar udpcksum[2]; /* Checksum */
+};
+
+typedef struct Etherhdr Etherhdr;
+struct Etherhdr
+{
+ uchar d[6];
+ uchar s[6];
+ uchar type[2];
+
+ /* Now we have the ip fields */
+ uchar vihl; /* Version and header length */
+ uchar tos; /* Type of service */
+ uchar length[2]; /* packet length */
+ uchar id[2]; /* Identification */
+ uchar frag[2]; /* Fragment information */
+ uchar ttl; /* Time to live */
+ uchar proto; /* Protocol */
+ uchar cksum[2]; /* Header checksum */
+ uchar src[4]; /* Ip source */
+ uchar dst[4]; /* Ip destination */
+};
+
+enum
+{
+ IP_VER = 0x40,
+ IP_HLEN = 0x05,
+ UDP_EHSIZE = 22,
+ UDP_PHDRSIZE = 12,
+ UDP_HDRSIZE = 20,
+ ETHER_HDR = 14,
+ IP_UDPPROTO = 17,
+ ET_IP = 0x800,
+ Bcastip = 0xffffffff,
+ BPportsrc = 68,
+ BPportdst = 67,
+ TFTPport = 69,
+ Timeout = 5000, /* milliseconds */
+ Bootrequest = 1,
+ Bootreply = 2,
+ Tftp_READ = 1,
+ Tftp_WRITE = 2,
+ Tftp_DATA = 3,
+ Tftp_ACK = 4,
+ Tftp_ERROR = 5,
+ Segsize = 512,
+ TFTPSZ = Segsize+10,
+};
+
+typedef struct Bootp Bootp;
+struct Bootp
+{
+ uchar op; /* opcode */
+ uchar htype; /* hardware type */
+ uchar hlen; /* hardware address len */
+ uchar hops; /* hops */
+ uchar xid[4]; /* a random number */
+ uchar secs[2]; /* elapsed snce client started booting */
+ uchar pad[2];
+ uchar ciaddr[4]; /* client IP address (client tells server) */
+ uchar yiaddr[4]; /* client IP address (server tells client) */
+ uchar siaddr[4]; /* server IP address */
+ uchar giaddr[4]; /* gateway IP address */
+ uchar chaddr[16]; /* client hardware address */
+ char sname[64]; /* server host name (optional) */
+ char file[128]; /* boot file name */
+ char vend[128]; /* vendor-specific goo */
+};
+
+typedef struct Netaddr Netaddr;
+struct Netaddr
+{
+ ulong ip;
+ ushort port;
+ char ea[Eaddrlen];
+};
diff --git a/os/boot/mpc/l.s b/os/boot/mpc/l.s
new file mode 100644
index 00000000..225a2d59
--- /dev/null
+++ b/os/boot/mpc/l.s
@@ -0,0 +1,370 @@
+#include "mem.h"
+
+/* special instruction definitions */
+#define BDNE BC 0,2,
+#define BDNZ BC 16,0,
+#define NOOP OR R0,R0,R0
+
+/*
+ * common ppc special purpose registers
+ */
+#define DSISR 18
+#define DAR 19 /* Data Address Register */
+#define DEC 22 /* Decrementer */
+#define SRR0 26 /* Saved Registers (exception) */
+#define SRR1 27
+#define SPRG0 272 /* Supervisor Private Registers */
+#define SPRG1 273
+#define SPRG2 274
+#define SPRG3 275
+#define TBRU 269 /* Time base Upper/Lower (Reading) */
+#define TBRL 268
+#define TBWU 285 /* Time base Upper/Lower (Writing) */
+#define TBWL 284
+#define PVR 287 /* Processor Version */
+
+/*
+ * mpc82x-specific special purpose registers of interest here
+ */
+#define EIE 80
+#define EID 81
+#define NRI 82
+#define IMMR 638
+#define IC_CST 560
+#define IC_ADR 561
+#define IC_DAT 562
+#define DC_CST 568
+#define DC_ADR 569
+#define DC_DAT 570
+#define MI_CTR 784
+#define MI_AP 786
+#define MI_EPN 787
+#define MI_TWC 789
+#define MI_RPN 790
+#define MI_DBCAM 816
+#define MI_DBRAM0 817
+#define MI_DBRAM1 818
+#define MD_CTR 792
+#define M_CASID 793
+#define MD_AP 794
+#define MD_EPN 795
+#define M_TWB 796
+#define MD_TWC 797
+#define MD_RPN 798
+#define M_TW 799
+#define MD_DBCAM 824
+#define MD_DBRAM0 825
+#define MD_DBRAM1 826
+
+/* as on 603e, apparently mtmsr needs help in some chip revisions */
+#define WAITMSR SYNC; ISYNC
+
+/* use of SPRG registers in save/restore */
+#define SAVER0 SPRG0
+#define SAVER1 SPRG1
+#define SAVELR SPRG2
+#define SAVECR SPRG3
+
+#define UREGSIZE ((8+32)*4)
+#define UREGSPACE (UREGSIZE+8) /* allow for arg to trap, and align */
+
+/*
+ * This code is loaded by the ROM loader at location 0x3000,
+ * or lives in flash memory at 0x2800100.
+ * Move it to high memory so that it can load the kernel at 0x0000.
+ */
+
+#define LOADCODEBASE 0x3000 /* when downloaded in S records */
+#define FLASHCODEBASE (FLASHMEM+0x100) /* when in flash */
+
+ TEXT start(SB), $-4
+ MOVW MSR, R3
+ MOVW $(EE|IP|RI), R4
+ ANDN R4, R3
+ OR $ME, R3
+ SYNC
+ MOVW R3, MSR /* turn off interrupts but enable traps */
+ WAITMSR
+
+/*
+ * reset the caches and disable them for now
+ */
+ MOVW SPR(IC_CST), R4 /* read and clear */
+ MOVW $(5<<25), R4
+ MOVW R4, SPR(IC_CST) /* unlock all */
+ ISYNC
+ MOVW $(6<<25), R4
+ MOVW R4, SPR(IC_CST) /* invalidate all */
+ ISYNC
+ MOVW $(2<<25), R4
+ MOVW R4, SPR(IC_CST) /* disable i-cache */
+ ISYNC
+
+ SYNC
+ MOVW SPR(DC_CST), R4 /* read and clear */
+ MOVW $(10<<24), R4
+ MOVW R4, SPR(DC_CST) /* unlock all */
+ ISYNC
+ MOVW $(12<<24), R4
+ MOVW R4, SPR(DC_CST) /* invalidate all */
+ ISYNC
+ MOVW $(4<<24), R4
+ MOVW R4, SPR(DC_CST) /* disable i-cache */
+ ISYNC
+
+ MOVW $7, R4
+ANDN R4, R4, R4
+ MOVW R4, SPR(158) /* cancel `show cycle' for normal instruction execution */
+
+/*
+ * set other system configuration values
+ */
+ MOVW SPR(IMMR), R5 /* save initial space pointer */
+ MOVW $INTMEM, R4
+ MOVW R4, SPR(IMMR) /* set internal memory base */
+ MOVW $0xFFFFFF88, R3
+ MOVW R3, 4(R4) /* disable watchdog in sypcr */
+ MOVW $0x01012440, R3
+ MOVW R3, 0(R4) /* siumcr */
+
+/*
+ * system initialisation (init and map DRAM)
+ */
+ MOVW $0, R0
+ MOVW $setSB(SB), R2
+ MOVW $(0xF000<<16), R3
+/*MOVW R0, R3*/
+ ANDCC R5, R3 /* initial space is high? */
+ BEQ notrom
+ MOVW $FLASHCODEBASE, R5 /* where $start(SB) actually is now */
+ MOVW $start(SB), R4 /* logical start address */
+ SUB R4, R5, R6 /* text relocation value */
+ MOVW $etext(SB), R7
+ SUB R4, R7
+ ADD R5, R7 /* data address in ROM */
+ MOVW $bdata(SB), R8
+ SUB R8, R2
+ ADD R7, R2 /* relocate SB: SB' = romdata+(SB-bdata) */
+ MOVW $sysinit0(SB), R4
+ ADD R6, R4 /* relocate sysinit0's address */
+ MOVW R4, CTR
+ MOVW $inmem(SB), R4
+ ADD R6, R4
+ MOVW R4, LR /* and the return address */
+ BR (CTR) /* call sysinit0 */
+ TEXT inmem(SB), $-4
+ MOVW $FLASHCODEBASE, R3
+ BR cpu0
+notrom:
+ MOVW $start(SB), R6
+ SUB R6, R2
+ ADD $LOADCODEBASE, R2
+ BL sysinit0(SB)
+ MOVW $LOADCODEBASE, R3
+
+/*
+ * cpu 0
+ * relocate bootstrap to our link addresses for text and data
+ * set new PC
+ */
+cpu0:
+ MOVW $setSB(SB), R2 /* set correct static base register */
+ MOVW $start(SB), R4
+ MOVW $etext(SB), R5
+ SUB R4, R5
+ CMP R4, R3 /* already there? */
+ BNE copytext
+ ADD R5, R3 /* start of data image */
+ BR copydata
+
+copytext:
+ ADD $3, R5
+ SRAW $2, R5
+ MOVW R5, CTR
+ SUB $4, R4
+ SUB $4, R3
+copyt: /* copy text */
+ MOVWU 4(R3), R5
+ MOVWU R5, 4(R4)
+ BDNZ copyt
+ ADD $4, R3
+
+copydata:
+ /* copy data */
+ MOVW $bdata(SB), R4
+ CMP R4, R3 /* already there? */
+ BEQ loadkpc
+ MOVW $edata(SB), R5
+ SUB R4, R5
+ ADD $3, R5
+ SRAW $2, R5
+ MOVW R5, CTR
+ SUB $4, R4
+ SUB $4, R3
+copyd:
+ MOVWU 4(R3), R5
+ MOVWU R5, 4(R4)
+ BDNZ copyd
+
+ /* load correct PC */
+loadkpc:
+ MOVW $start1(SB), R3
+ MOVW R3, LR
+ BR (LR)
+TEXT start1(SB), $-4
+ MOVW $edata(SB), R3
+ MOVW $end(SB), R4
+ SUBCC R3, R4
+ BLE skipz
+ SRAW $2, R4
+ MOVW R4, CTR
+ SUB $4, R3
+ MOVW $0, R0
+zero:
+ MOVWU R0, 4(R3)
+ BDNZ zero
+skipz:
+ MOVW $mach0(SB), R1
+ MOVW R1, m(SB)
+ ADD $(MACHSIZE-8), R1
+ MOVW $0, R0
+ BL main(SB)
+ BR 0(PC)
+
+TEXT getmsr(SB), $0
+ MOVW MSR, R3
+ RETURN
+
+TEXT putmsr(SB), $0
+ SYNC
+ MOVW R3, MSR
+ WAITMSR
+ RETURN
+
+TEXT eieio(SB), $0
+ EIEIO
+ RETURN
+
+TEXT idle(SB), $0
+ RETURN
+
+TEXT spllo(SB), $0
+ MOVW MSR, R3
+ OR $EE, R3, R4
+ SYNC
+ MOVW R4, MSR
+ WAITMSR
+ RETURN
+
+TEXT splhi(SB), $0
+ MOVW MSR, R3
+ RLWNM $0, R3, $~EE, R4
+ SYNC
+ MOVW R4, MSR
+ WAITMSR
+ RETURN
+
+TEXT splx(SB), $0
+ MOVW MSR, R4
+ RLWMI $0, R3, $EE, R4
+ SYNC
+ MOVW R4, MSR
+ WAITMSR
+ RETURN
+
+TEXT gettbl(SB), $0
+/* MOVW SPR(TBRL), R3 */
+ WORD $0x7c6c42e6 /* mftbl on 8xx series */
+ RETURN
+
+TEXT getpvr(SB), $0
+ MOVW SPR(PVR), R3
+ RETURN
+
+TEXT getimmr(SB), $0
+ MOVW SPR(IMMR), R3
+ RETURN
+
+TEXT getdec(SB), $0
+ MOVW SPR(DEC), R3
+ RETURN
+
+TEXT putdec(SB), $0
+ MOVW R3, SPR(DEC)
+ RETURN
+
+/*
+ * save state in Ureg on kernel stack.
+ * enter with R0 giving the PC from the call to `exception' from the vector.
+ * on return, SB (R2) has been set, and R3 has the Ureg*
+ */
+TEXT saveureg(SB), $-4
+ SUB $UREGSPACE, R1
+ MOVMW R2, 48(R1) /* r2:r31 */
+ MOVW $setSB(SB), R2
+ MOVW SPR(SAVER1), R4
+ MOVW R4, 44(R1)
+ MOVW SPR(SAVER0), R5
+ MOVW R5, 40(R1)
+ MOVW CTR, R6
+ MOVW R6, 36(R1)
+ MOVW XER, R4
+ MOVW R4, 32(R1)
+ MOVW SPR(SAVECR), R5 /* CR */
+ MOVW R5, 28(R1)
+ MOVW SPR(SAVELR), R6 /* LR */
+ MOVW R6, 24(R1)
+ /* pad at 20(R1) */
+ MOVW SPR(SRR0), R4
+ MOVW R4, 16(R1) /* old PC */
+ MOVW SPR(SRR1), R5
+ MOVW R5, 12(R1)
+ MOVW R0, 8(R1) /* cause/vector, encoded in LR from vector */
+ ADD $8, R1, R3 /* Ureg* */
+ STWCCC R3, (R1) /* break any pending reservations */
+ MOVW $0, R0 /* R0ISZERO */
+ BR (LR)
+
+/*
+ * restore state from Ureg
+ * SB (R2) is unusable on return
+ */
+TEXT restoreureg(SB), $-4
+ MOVMW 48(R1), R2 /* r2:r31 */
+ /* defer R1 */
+ MOVW 40(R1), R0
+ MOVW R0, SPR(SAVER0)
+ MOVW 36(R1), R0
+ MOVW R0, CTR
+ MOVW 32(R1), R0
+ MOVW R0, XER
+ MOVW 28(R1), R0
+ MOVW R0, CR /* CR */
+ MOVW 24(R1), R0
+ MOVW R0, SPR(SAVELR) /* LR */
+ /* pad, skip */
+ MOVW 16(R1), R0
+ MOVW R0, SPR(SRR0) /* old PC */
+ MOVW 12(R1), R0
+ MOVW R0, SPR(SRR1) /* old MSR */
+ /* cause, skip */
+ MOVW 44(R1), R1 /* old SP */
+ BR (LR)
+
+TEXT exception(SB), $-4
+ MOVW R1, SPR(SAVER1)
+ MOVW CR, R0
+ MOVW R0, SPR(SAVECR)
+ MOVW LR, R0
+ BL saveureg(SB)
+ MOVW $0, R0
+ BL trap(SB)
+ BL restoreureg(SB)
+ MOVW SPR(SAVELR), R0
+ MOVW R0, LR
+ MOVW SPR(SAVER0), R0
+ ISYNC
+ RFI
+
+GLOBL mach0+0(SB), $MACHSIZE
+GLOBL m(SB), $4
diff --git a/os/boot/mpc/lib.h b/os/boot/mpc/lib.h
new file mode 100644
index 00000000..1eb0532d
--- /dev/null
+++ b/os/boot/mpc/lib.h
@@ -0,0 +1,106 @@
+/*
+ * functions (possibly) linked in, complete, from libc.
+ */
+
+/*
+ * mem routines
+ */
+extern void* memccpy(void*, void*, int, long);
+extern void* memset(void*, int, long);
+extern int memcmp(void*, void*, long);
+extern void* memmove(void*, void*, long);
+extern void* memchr(void*, int, long);
+
+/*
+ * string routines
+ */
+extern char* strcat(char*, char*);
+extern char* strchr(char*, char);
+extern int strcmp(char*, char*);
+extern char* strcpy(char*, char*);
+extern char* strncat(char*, char*, long);
+extern char* strncpy(char*, char*, long);
+extern int strncmp(char*, char*, long);
+extern long strlen(char*);
+extern char* strrchr(char*, char);
+extern char* strstr(char*, char*);
+
+/*
+ * print routines
+ * Fconv isn't used but is defined to satisfy prototypes in libg.h
+ * that are never called.
+ */
+typedef struct Fconv Fconv;
+
+extern char* donprint(char*, char*, char*, void*);
+extern int sprint(char*, char*, ...);
+extern int print(char*, ...);
+
+#define PRINTSIZE 256
+
+/*
+ * one-of-a-kind
+ */
+extern int atoi(char*);
+extern long strtol(char*, char**, int);
+extern ulong strtoul(char*, char**, int);
+extern long end;
+
+/*
+ * Syscall data structures
+ */
+
+#define MORDER 0x0003 /* mask for bits defining order of mounting */
+#define MREPL 0x0000 /* mount replaces object */
+#define MBEFORE 0x0001 /* mount goes before others in union directory */
+#define MAFTER 0x0002 /* mount goes after others in union directory */
+#define MCREATE 0x0004 /* permit creation in mounted directory */
+#define MMASK 0x0007 /* all bits on */
+
+#define OREAD 0 /* open for read */
+#define OWRITE 1 /* write */
+#define ORDWR 2 /* read and write */
+#define OEXEC 3 /* execute, == read but check execute permission */
+#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
+#define OCEXEC 32 /* or'ed in, close on exec */
+#define ORCLOSE 64 /* or'ed in, remove on close */
+
+#define NCONT 0 /* continue after note */
+#define NDFLT 1 /* terminate after note */
+
+typedef struct Qid Qid;
+typedef struct Dir Dir;
+typedef struct Waitmsg Waitmsg;
+
+#define ERRLEN 64
+#define DIRLEN 116
+#define NAMELEN 28
+
+struct Qid
+{
+ ulong path;
+ ulong vers;
+};
+
+struct Dir
+{
+ char name[NAMELEN];
+ char uid[NAMELEN];
+ char gid[NAMELEN];
+ Qid qid;
+ ulong mode;
+ long atime;
+ long mtime;
+ vlong length;
+ short type;
+ short dev;
+};
+
+struct Waitmsg
+{
+ int pid; /* of loved one */
+ int status; /* unused; a placeholder */
+ ulong time[3]; /* of loved one */
+ char msg[ERRLEN];
+};
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
diff --git a/os/boot/mpc/main.c b/os/boot/mpc/main.c
new file mode 100644
index 00000000..a6250471
--- /dev/null
+++ b/os/boot/mpc/main.c
@@ -0,0 +1,524 @@
+#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 {
+ Dany = -1,
+ Nmedia = 16,
+
+ /* DS1 switch options */
+ Sflashfs = 1<<0, /* take local fs from flash */
+ Snotflash = 1<<1, /* don't boot from flash */
+};
+
+enum { /* type */
+ Tflash,
+ Tuart,
+ Tether,
+ Thard,
+
+ Tany = -1,
+};
+
+enum { /* flag and name */
+ Fnone = 0x00,
+
+ Fdos = 0x01,
+ Ndos = 0x00,
+ Fboot = 0x02,
+ Nboot = 0x01,
+ Fbootp = 0x04,
+ Nbootp = 0x02,
+ Fflash = 0x08,
+ Fuart = 0x10,
+ NName = 0x03,
+
+ Fany = Fbootp|Fboot|Fdos|Fflash|Fuart,
+
+ Fini = 0x10,
+ Fprobe = 0x80,
+};
+
+enum { /* mode */
+ Mauto = 0x00,
+ Mlocal = 0x01,
+ Manual = 0x02,
+ NMode = 0x03,
+};
+
+typedef struct Type {
+ int type;
+ char *cname;
+ 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[] = {
+ { Tflash, "flash",
+ Fflash,
+ flashinit, 0, 0, 0,
+ { 0, "F", 0, }
+ },
+/*
+ { Tuart, "uart",
+ Fuart|Fboot,
+ uartinit, uartread, uartseek, setuartpart,
+ { 0, "u", 0, }
+ },
+*/
+ { Tether, "ether",
+ Fbootp,
+ etherinit, 0, 0, 0,
+ { 0, 0, "e", },
+ },
+ { Thard, "ata",
+ Fini|Fboot|Fdos,
+ 0, 0, 0, 0, /* not used now, will be later with PCMCIA */
+ { "hd", "h", 0, },
+ },
+ {-1},
+};
+
+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[] = {
+ "inferno/inferno.ini",
+ "inferno.ini",
+ "plan9/plan9.ini",
+ "plan9.ini",
+ 0,
+};
+char **ini;
+int predawn;
+
+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(getcfields(buf, v, 4, "!")){
+
+ case 3:
+ break;
+
+ case 2:
+ v[2] = "";
+ break;
+
+ default:
+ return 0;
+ }
+
+ *flag = 0;
+ for(tp = types; tp->cname; 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;
+ int r;
+
+ uartsetboot(0);
+ if(flag & Fbootp){
+ sprint(BOOTLINE, "%s!%d", mp->type->name[Nbootp], mp->dev);
+ return bootp(mp->dev, file);
+ }
+
+ if(flag & Fflash){
+ if(mp->flag & Fflash && flashbootable(0))
+ flashboot(mp->dev);
+ }
+
+ if(flag & Fboot){
+
+ if(mp->flag & Fini){
+ (*mp->type->setpart)(mp->dev, "disk");
+ plan9ini(mp, nil);
+ }
+ 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);
+ r = plan9boot(mp->dev, mp->seek, mp->read);
+ uartsetboot(0);
+ return r;
+ }
+
+ if(flag & Fdos){
+ if(mp->type->setpart)
+ (*mp->type->setpart)(mp->dev, "disk");
+ if(mp->flag & Fini)
+ plan9ini(mp, nil);
+ if(file == 0 || *file == 0){
+ strcpy(ixdos, *ini);
+ if(p = strrchr(ixdos, '/'))
+ p++;
+ else
+ p = ixdos;
+ strcpy(p, "impc");
+ 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 dombr, i, start;
+ Medium *mp;
+ Dosfile df;
+ Partition *pp;
+
+ for(tp = types; tp->cname; tp++){
+ if(type != Tany && type != tp->type || tp->init == 0)
+ 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->mask & (1<<i)) == 0)
+ continue;
+ tp->mask &= ~(1<<i);
+
+ if((mp = allocm(tp)) == 0)
+ continue;
+
+ mp->dev = i;
+ mp->flag = tp->flag;
+ mp->seek = tp->seek;
+ mp->read = tp->read;
+ mp->type = tp;
+
+ if(mp->flag & Fboot){
+ if((mp->partition = (*tp->setpart)(i, "boot")) == 0)
+ mp->flag &= ~Fboot;
+ if((mp->flag & (Fflash|Fuart)) == 0)
+ (*tp->setpart)(i, "disk");
+ }
+
+ if(mp->flag & Fdos){
+ start = 0;
+ dombr = 1;
+ if(mp->type->setpart){
+ if(pp = (*mp->type->setpart)(i, "dos")){
+ if(start = pp->start)
+ dombr = 0;
+ }
+ (*tp->setpart)(i, "disk");
+ }
+ if(dosinit(mp, start, dombr) < 0)
+ mp->flag &= ~(Fini|Fdos);
+ else
+ print("dos init failed\n");
+ }
+
+ 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 == i))
+ return mp;
+ }
+ }
+
+ return 0;
+}
+
+void
+main(void)
+{
+ Medium *mp;
+ int dev, flag, i, mode, tried, type, options;
+ char def[2*NAMELEN], file[2*NAMELEN], line[80], *p;
+ Type *tp;
+
+ machinit();
+ archinit();
+ meminit();
+ cpminit();
+ trapinit();
+ consinit(); /* screen and keyboard initially */
+ screeninit();
+ cpuidprint();
+ alarminit();
+ clockinit();
+ predawn = 0;
+ spllo();
+ options = archoptionsw();
+
+ mp = 0;
+ for(tp = types; tp->cname; tp++){
+ if(tp->type == Tether)
+ continue;
+ if((mp = probe(tp->type, Fini, Dany)) && (mp->flag & Fini)){
+ plan9ini(mp, nil);
+ break;
+ }
+ }
+
+ if(mp == 0 || (mp->flag & Fini) == 0)
+ plan9ini(nil, flashconfig(0));
+
+ //consinit(); /* establish new console location */
+
+ if((options & Snotflash) == 0 && flashbootable(0)){
+ print("Flash boot\n");
+ flashboot(0);
+ }
+
+ tried = 0;
+ mode = Mauto;
+ p = getconf("bootfile");
+ flag = 0;
+
+ 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(options & Snotflash)
+ flag &= ~Fflash;
+ if((mp = probe(Tany, flag, Dany)) != 0)
+ boot(mp, flag & mp->flag, 0);
+ }
+
+ def[0] = 0;
+ probe(Tany, Fnone, Dany);
+
+ flag = 0;
+ for(tp = types; tp->cname; 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 & (Fflash|Fuart) || 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) >= 0){
+ if(parse(line, &type, &flag, &dev, file)){
+ if(mp = probe(type, flag, dev))
+ boot(mp, flag, file);
+ }
+ }
+ def[0] = 0;
+ }
+}
+
+void
+machinit(void)
+{
+ memset(m, 0, sizeof(*m));
+ m->delayloop = 20000;
+ m->cpupvr = getpvr();
+ m->iomem = KADDR(INTMEM);
+}
+
+int
+getcfields(char* lp, char** fields, int n, char* sep)
+{
+ int i;
+
+ for(i = 0; lp && *lp && i < n; i++){
+ while(*lp && strchr(sep, *lp) != 0)
+ *lp++ = 0;
+ if(*lp == 0)
+ break;
+ fields[i] = lp;
+ while(*lp && strchr(sep, *lp) == 0){
+ if(*lp == '\\' && *(lp+1) == '\n')
+ *lp++ = ' ';
+ lp++;
+ }
+ }
+
+ return i;
+}
+
+static Map memv[512];
+static RMap rammap = {"physical memory"};
+
+void
+meminit(void)
+{
+ ulong e;
+
+ mapinit(&rammap, memv, sizeof(memv));
+ e = PADDR(&end);
+ mapfree(&rammap, e, 4*1024*1024-e); /* fixed 4Mbytes is plenty for bootstrap */
+}
+
+void*
+ialloc(ulong n, int align)
+{
+ ulong a;
+ int s;
+
+ if(align <= 0)
+ align = 4;
+ s = splhi();
+ a = mapalloc(&rammap, 0, n, align);
+ splx(s);
+ if(a == 0)
+ panic("ialloc");
+ return memset(KADDR(a), 0, n);
+}
+
+void*
+malloc(ulong n)
+{
+ ulong *p;
+
+ n = ((n+sizeof(int)-1)&~(sizeof(int)-1))+2*sizeof(int);
+ p = ialloc(n, sizeof(int));
+ *p++ = 0xcafebeef;
+ *p++ = n;
+ return p;
+}
+
+void
+free(void *ap)
+{
+ int s;
+ ulong *p;
+
+ p = ap;
+ if(p){
+ if(*(p -= 2) != 0xcafebeef)
+ panic("free");
+ s = splhi();
+ mapfree(&rammap, (ulong)p, p[1]);
+ splx(s);
+ }
+}
+
+void
+sched(void)
+{
+}
diff --git a/os/boot/mpc/mem.c b/os/boot/mpc/mem.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/os/boot/mpc/mem.c
diff --git a/os/boot/mpc/mem.h b/os/boot/mpc/mem.h
new file mode 100644
index 00000000..f76867a8
--- /dev/null
+++ b/os/boot/mpc/mem.h
@@ -0,0 +1,95 @@
+/*
+ * Memory and machine-specific definitions. Used in C and assembler.
+ */
+
+/*
+ * Sizes
+ */
+#define BI2BY 8 /* bits per byte */
+#define BI2WD 32 /* bits per word */
+#define BY2WD 4 /* bytes per word */
+#define BY2PG 4096 /* bytes per page */
+#define WD2PG (BY2PG/BY2WD) /* words per page */
+#define PGSHIFT 12 /* log(BY2PG) */
+#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1))
+
+#define MAXMACH 1 /* max # cpus system can run */
+#define CACHELINELOG 4
+#define CACHELINESZ (1<<CACHELINELOG)
+
+/*
+ * Time
+ */
+#define HZ (50) /* clock frequency */
+#define MS2HZ (1000/HZ) /* millisec per clock tick */
+#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
+#define TK2MS(t) ((((ulong)(t))*1000)/HZ) /* ticks to milliseconds */
+#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */
+#define MHz 1000000
+
+/*
+ * Fundamental values
+ */
+
+#define KZERO 0 /* bootstrap runs in real mode */
+#define MACHSIZE 4096
+
+/*
+ * physical MMU
+ */
+#define KSEG0 0x20000000
+#define KSEGM 0xE0000000 /* mask to check which seg */
+
+/*
+ * MSR bits
+ */
+
+#define POW 0x40000 /* enable power mgmt */
+#define TGPR 0x20000 /* GPR0-3 remapped; 603/603e specific */
+#define ILE 0x10000 /* interrupts little endian */
+#define EE 0x08000 /* enable external/decrementer interrupts */
+#define PR 0x04000 /* =1, user mode */
+#define FPE 0x02000 /* enable floating point */
+#define ME 0x01000 /* enable machine check exceptions */
+#define FE0 0x00800
+#define SE 0x00400 /* single-step trace */
+#define BE 0x00200 /* branch trace */
+#define FE1 0x00100
+#define IP 0x00040 /* =0, vector to nnnnn; =1, vector to FFFnnnnn */
+#define IR 0x00020 /* enable instruction address translation */
+#define DR 0x00010 /* enable data address translation */
+#define RI 0x00002 /* exception is recoverable */
+#define LE 0x00001 /* little endian mode */
+
+#define KMSR (ME|FE0|FE1|FPE)
+#define UMSR (KMSR|PR|EE|IR|DR)
+
+/*
+ * MPC82x addresses; mpc8bug is happy with these
+ */
+#define BCSRMEM 0x02100000
+#define INTMEM 0x02200000
+#define FLASHMEM 0x02800000
+#define SDRAMMEM 0x03000000
+
+#define DPRAM (INTMEM+0x2000)
+#define DPLEN1 0x400
+#define DPLEN2 0x200
+#define DPLEN3 0x100
+#define DPBASE (DPRAM+DPLEN1)
+
+#define SCC1P (INTMEM+0x3C00)
+#define I2CP (INTMEM+0x3C80)
+#define MISCP (INTMEM+0x3CB0)
+#define IDMA1P (INTMEM+0x3CC0)
+#define SCC2P (INTMEM+0x3D00)
+#define SCC3P (INTMEM+0x3E00)
+#define SCC4P (INTMEM+0x3F00)
+#define SPIP (INTMEM+0x3D80)
+#define TIMERP (INTMEM+0x3DB0)
+#define SMC1P (INTMEM+0x3E80)
+#define DSP1P (INTMEM+0x3EC0)
+#define SMC2P (INTMEM+0x3F80)
+#define DSP2P (INTMEM+0x3FC0)
+
+#define KEEP_ALIVE_KEY 0x55ccaa33 /* clock and rtc register key */
diff --git a/os/boot/mpc/mkfile b/os/boot/mpc/mkfile
new file mode 100644
index 00000000..9a279264
--- /dev/null
+++ b/os/boot/mpc/mkfile
@@ -0,0 +1,116 @@
+objtype=power
+OBJTYPE=power # always
+<../../../mkconfig
+SYSTARG=$OSTARG # always
+<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE
+INSTALLDIR=$ROOT/Inferno/$OBJTYPE/bin #path of directory where kernel is installed
+ARCH=fads # selects board dependent code
+TARG=qb$ARCH
+OFILES=\
+ l.$O\
+ arch$ARCH.$O\
+ devuart.$O\
+ uartboot.$O\
+ alarm.$O\
+ bootp.$O\
+ clock.$O\
+ conf.$O\
+ console.$O\
+ cpm.$O\
+ defont0.$O\
+ donprint.$O\
+ dosboot.$O\
+ devether.$O\
+ etherscc.$O\
+ fblt.$O\
+ gbitbltclip.$O\
+ flash.$O\
+ main.$O\
+ plan9boot.$O\
+ qio.$O\
+ rmap.$O\
+ screen.$O\
+ init$ARCH.$O\
+ trap.$O\
+ zqs.$O\
+
+HFILES=\
+ boot.h\
+ dat.h\
+ fns.h\
+ io.h\
+ lib.h\
+ mem.h\
+ squeeze.h\
+ gnot.h\
+ arch$ARCH.h\
+
+LIBS=\
+ kern\
+
+LIBDIRS=$LIBS
+LIBNAMES=${LIBS:%=lib%.a}
+LIBFILES=${LIBS:%=$ROOT/$TARGMODEL/$OBJTYPE/lib/lib%.a}
+
+#all:NV: $TARG k.mx f.mx
+all:NV: $TARG
+install:V: $INSTALLDIR/$TARG
+installall:V: $INSTALLDIR/$TARG
+
+$INSTALLDIR/%: %
+ rm -f $INSTALLDIR/$stem && cp $stem $INSTALLDIR/$stem
+
+$TARG: $OFILES $LIBNAMES
+ $LD -o $target -l -T0x140000 -R4 $OFILES $LIBFILES
+ ls -l $target
+
+qbrom$ARCH: $OFILES $LIBNAMES
+ $LD -o $target -l -T0x02800100 -R0 -D0x140000 $OFILES $LIBFILES
+
+k.mx: $TARG
+ ms2 -S 0x100 -a 0x100 -p 4 $TARG >k.mx
+
+f.mx: qbrom$ARCH
+ ms2 -S 0x100 -a 0x2800100 -p 4 $prereq >f.mx
+
+%.$O: %.s
+ $AS $stem.s
+
+%.$O: %.c
+ $CC $CFLAGS $stem.c
+
+%.$O: $HFILES
+
+lib%.a:V: $SHELLTYPE-lib%.a
+
+rc-lib%.a nt-lib%.a:VQ:
+ echo '@{builtin cd ' $ROOT/lib$stem ';mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE install}'
+ @{builtin cd $ROOT/lib$stem ;mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE install}
+
+sh-lib%.a:VQ:
+ echo "(cd $ROOT/lib$stem ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE install)"
+ (cd $ROOT/lib$stem ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE install)
+
+clock.$O floppy.$O trap.$O: ureg.h
+conf.$O dosboot.$O main.$O: dosfs.h
+ether.$O etherscc.$O: etherif.h
+bootp.$O: ip.h
+
+clean:V:
+ rm -f *.[$OS] [$OS].out y.tab.? y.debug y.output $TARG qboot k.mx f.mx romboot
+
+nuke-sh:QV:
+ for i in $LIBDIRS
+ do
+ echo "(cd $ROOT/lib$i ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE nuke)"
+ (cd $ROOT/lib$i; mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE nuke)
+ done
+
+nuke-rc nuke-nt:QV:
+ for (i in $LIBDIRS)
+ {
+ echo '@{cd $ROOT/lib$i ; mk SHELLTYPE=$SHELLTYPE SYSTARG=$SYSTARG OBJTYPE=$OBJTYPE nuke}'
+ @{cd $ROOT/lib$i; mk 'SHELLTYPE='$SHELLTYPE 'SYSTARG='$SYSTARG 'OBJTYPE='$OBJTYPE nuke}
+ }
+
+nuke:V: clean nuke-$SHELLTYPE
diff --git a/os/boot/mpc/ms2.c b/os/boot/mpc/ms2.c
new file mode 100644
index 00000000..ce96df78
--- /dev/null
+++ b/os/boot/mpc/ms2.c
@@ -0,0 +1,179 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+void record(uchar*, int);
+void usage(void);
+void dosegment(long, int);
+void trailer(ulong);
+
+enum
+{
+ Recordsize = 32,
+};
+
+int dsegonly;
+int supressend;
+int binary;
+int addr4;
+ulong addr;
+ulong psize = 4096;
+ulong startaddr = 0x030000;
+Biobuf stdout;
+Biobuf bio;
+
+void
+main(int argc, char **argv)
+{
+ Dir dir;
+ Fhdr f;
+ int fd;
+
+ ARGBEGIN{
+ case 'd':
+ dsegonly++;
+ break;
+ case 's':
+ supressend++;
+ break;
+ case 'a':
+ addr = strtoul(ARGF(), 0, 0);
+ break;
+ case 'p':
+ psize = strtoul(ARGF(), 0, 0);
+ break;
+ case 'b':
+ binary++;
+ break;
+ case 'S':
+ startaddr = strtoul(ARGF(), 0, 0);
+ break;
+ case '4':
+ addr4++;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc != 1)
+ usage();
+
+ Binit(&stdout, 1, OWRITE);
+
+ fd = open(argv[0], OREAD);
+ if(fd < 0) {
+ fprint(2, "ms2: open %s: %r\n", argv[0]);
+ exits("open");
+ }
+
+ if(binary) {
+ if(dirfstat(fd, &dir) < 0) {
+ fprint(2, "ms2: stat failed %r");
+ exits("dirfstat");
+ }
+ Binit(&bio, fd, OREAD);
+ dosegment(0, dir.length);
+ if(supressend == 0)
+ trailer(startaddr);
+ Bterm(&stdout);
+ Bterm(&bio);
+ exits(0);
+ }
+
+ if(crackhdr(fd, &f) == 0){
+ fprint(2, "ms2: bad magic: %r\n");
+ exits("magic");
+ }
+ seek(fd, 0, 0);
+
+ Binit(&bio, fd, OREAD);
+
+ if(dsegonly)
+ dosegment(f.datoff, f.datsz);
+ else {
+ dosegment(f.txtoff, f.txtsz);
+ addr = (addr+(psize-1))&~(psize-1);
+ dosegment(f.datoff, f.datsz);
+ }
+
+ if(supressend == 0)
+ trailer(startaddr);
+
+ Bterm(&stdout);
+ Bterm(&bio);
+ exits(0);
+}
+
+void
+dosegment(long foff, int len)
+{
+ int l, n;
+ uchar buf[2*Recordsize];
+
+ Bseek(&bio, foff, 0);
+ for(;;) {
+ l = len;
+ if(l > Recordsize)
+ l = Recordsize;
+ n = Bread(&bio, buf, l);
+ if(n == 0)
+ break;
+ if(n < 0) {
+ fprint(2, "ms2: read error: %r\n");
+ exits("read");
+ }
+ record(buf, l);
+ len -= l;
+ }
+}
+
+void
+record(uchar *s, int l)
+{
+ int i;
+ ulong cksum;
+
+ if(addr4 || addr & (0xFF<<24)){
+ Bprint(&stdout, "S3%.2X%.8luX", l+5, addr);
+ cksum = l+5;
+ cksum += (addr>>24)&0xff;
+ }else{
+ Bprint(&stdout, "S2%.2X%.6X", l+4, addr);
+ cksum = l+4;
+ }
+ cksum += addr&0xff;
+ cksum += (addr>>8)&0xff;
+ cksum += (addr>>16)&0xff;
+
+ for(i = 0; i < l; i++) {
+ cksum += *s;
+ Bprint(&stdout, "%.2X", *s++);
+ }
+ Bprint(&stdout, "%.2X\n", (~cksum)&0xff);
+ addr += l;
+}
+
+void
+trailer(ulong a)
+{
+ ulong cksum;
+
+ cksum = 0;
+ if(addr4 || a & (0xFF<<24)){
+ Bprint(&stdout, "S7%.8luX", a);
+ cksum += (a>>24)&0xff;
+ }else
+ Bprint(&stdout, "S9%.6X", a);
+ cksum += a&0xff;
+ cksum += (a>>8)&0xff;
+ cksum += (a>>16)&0xff;
+ Bprint(&stdout, "%.2X\n", (~cksum)&0xff);
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: ms2 [-ds] [-a address] [-p pagesize] ?.out\n");
+ exits("usage");
+}
diff --git a/os/boot/mpc/plan9boot.c b/os/boot/mpc/plan9boot.c
new file mode 100644
index 00000000..047474e3
--- /dev/null
+++ b/os/boot/mpc/plan9boot.c
@@ -0,0 +1,96 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+char *premature = "premature EOF\n";
+
+/*
+ * read in a segment
+ */
+static long
+readseg(int dev, long (*read)(int, void*, long), long len, long addr)
+{
+ char *a;
+ long n, sofar;
+
+ a = (char *)addr;
+ for(sofar = 0; sofar < len; sofar += n){
+ n = 8*1024;
+ if(len - sofar < n)
+ n = len - sofar;
+ n = (*read)(dev, a + sofar, n);
+ if(n <= 0)
+ break;
+ print(".");
+ }
+ return sofar;
+}
+
+/*
+ * boot
+ */
+int
+plan9boot(int dev, long (*seek)(int, long), long (*read)(int, void*, long))
+{
+ long n;
+ long addr;
+ void (*b)(void);
+ Exec *ep;
+
+ if((*seek)(dev, 0) < 0)
+ return -1;
+
+ /*
+ * read header
+ */
+ ep = (Exec *) ialloc(sizeof(Exec), 0);
+ n = sizeof(Exec);
+ if(readseg(dev, read, n, (long) ep) != n){
+ print(premature);
+ return -1;
+ }
+ if(GLLONG(ep->magic) != Q_MAGIC){
+ print("bad magic 0x%lux not a plan 9 executable!\n", GLLONG(ep->magic));
+ return -1;
+ }
+
+ /*
+ * read text
+ */
+ addr = PADDR(GLLONG(ep->entry));
+ n = GLLONG(ep->text);
+ print("%d", n);
+ if(readseg(dev, read, n, addr) != n){
+ print(premature);
+ return -1;
+ }
+
+ /*
+ * read data (starts at first page after kernel)
+ */
+ addr = PGROUND(addr+n);
+ n = GLLONG(ep->data);
+ print("+%d@%8.8lux", n, addr);
+ if(readseg(dev, read, n, addr) != n){
+ print(premature);
+ return -1;
+ }
+
+ /*
+ * bss and entry point
+ */
+ print("+%d\nstart at 0x%lux\n", GLLONG(ep->bss), GLLONG(ep->entry));
+ uartwait();
+ scc2stop();
+ splhi();
+
+ /*
+ * Go to new code. It's up to the program to get its PC relocated to
+ * the right place.
+ */
+ b = (void (*)(void))(PADDR(GLLONG(ep->entry)));
+ (*b)();
+ return 0;
+}
diff --git a/os/boot/mpc/qio.c b/os/boot/mpc/qio.c
new file mode 100644
index 00000000..e014433e
--- /dev/null
+++ b/os/boot/mpc/qio.c
@@ -0,0 +1,128 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+struct Queue {
+ Block* first;
+ Block* last;
+ void (*kick)(void*);
+ void* arg;
+ long len;
+};
+
+Block *
+iallocb(int n)
+{
+ Block *b;
+
+ b = (Block*)malloc(sizeof(Block)+n);
+ b->data = (uchar*)b + sizeof(Block);
+ b->rp = b->wp = b->data;
+ b->lim = b->data + n;
+ b->next = 0;
+ b->magic = 0xcafebee0;
+ return b;
+}
+
+void
+freeb(Block *b)
+{
+ if(b){
+ if(b->magic != 0xcafebee0)
+ panic("freeb");
+ b->magic = 0;
+ b->next = (Block*)0xdeadbabe;
+ free(b);
+ }
+}
+
+Queue *
+qopen(int limit, int msg, void (*kick)(void*), void *arg)
+{
+ Queue *q;
+
+ USED(limit, msg);
+ q = (Queue*)malloc(sizeof(Queue));
+ q->first = q->last = 0;
+ q->kick = kick;
+ q->arg = arg;
+ q->len = 0;
+ return q;
+}
+
+Block *
+qget(Queue *q)
+{
+ int s;
+ Block *b;
+
+ s = splhi();
+ if((b = q->first) != 0){
+ q->first = b->next;
+ b->next = 0;
+ q->len -= BLEN(b);
+ if(q->len < 0)
+ panic("qget");
+ }
+ splx(s);
+ return b;
+}
+
+void
+qbwrite(Queue *q, Block *b)
+{
+ int s;
+
+ s = splhi();
+ b->next = 0;
+ if(q->first == 0)
+ q->first = b;
+ else
+ q->last->next = b;
+ q->last = b;
+ q->len += BLEN(b);
+ splx(s);
+ if(q->kick)
+ q->kick(q->arg);
+}
+
+long
+qlen(Queue *q)
+{
+ return q->len;
+}
+
+int
+qbgetc(Queue *q)
+{
+ Block *b;
+ int s, c;
+
+ c = -1;
+ s = splhi();
+ while(c < 0 && (b = q->first) != nil){
+ if(b->rp < b->wp){
+ c = *b->rp++;
+ q->len--;
+ }
+ if(b->rp >= b->wp){
+ q->first = b->next;
+ b->next = nil;
+ }
+ }
+ splx(s);
+ return c;
+}
+
+void
+qbputc(Queue *q, int c)
+{
+ Block *b;
+
+ b = iallocb(1);
+ *b->wp++ = c;
+ qbwrite(q, b);
+}
diff --git a/os/boot/mpc/rmap.c b/os/boot/mpc/rmap.c
new file mode 100644
index 00000000..8b8a0bef
--- /dev/null
+++ b/os/boot/mpc/rmap.c
@@ -0,0 +1,104 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+void
+mapinit(RMap *rmap, Map *map, int size)
+{
+ lock(rmap);
+ rmap->map = map;
+ rmap->mapend = map+(size/sizeof(Map));
+ unlock(rmap);
+}
+
+void
+mapfree(RMap* rmap, ulong addr, int size)
+{
+ Map *mp;
+ ulong t;
+
+ if(size <= 0)
+ return;
+
+ lock(rmap);
+ for(mp = rmap->map; mp->addr <= addr && mp->size; mp++)
+ ;
+
+ if(mp > rmap->map && (mp-1)->addr+(mp-1)->size == addr){
+ (mp-1)->size += size;
+ if(addr+size == mp->addr){
+ (mp-1)->size += mp->size;
+ while(mp->size){
+ mp++;
+ (mp-1)->addr = mp->addr;
+ (mp-1)->size = mp->size;
+ }
+ }
+ }
+ else{
+ if(addr+size == mp->addr && mp->size){
+ mp->addr -= size;
+ mp->size += size;
+ }
+ else do{
+ if(mp >= rmap->mapend){
+ print("mapfree: %s: losing 0x%uX, %d\n",
+ rmap->name, addr, size);
+ break;
+ }
+ t = mp->addr;
+ mp->addr = addr;
+ addr = t;
+ t = mp->size;
+ mp->size = size;
+ mp++;
+ }while(size = t);
+ }
+ unlock(rmap);
+}
+
+ulong
+mapalloc(RMap* rmap, ulong addr, int size, int align)
+{
+ Map *mp;
+ ulong maddr, oaddr;
+
+ lock(rmap);
+ for(mp = rmap->map; mp->size; mp++){
+ maddr = mp->addr;
+
+ if(addr){
+ if(maddr > addr)
+ continue;
+ if(addr+size > maddr+mp->size)
+ break;
+ maddr = addr;
+ }
+
+ if(align > 0)
+ maddr = ((maddr+align-1)/align)*align;
+ if(mp->addr+mp->size-maddr < size)
+ continue;
+
+ oaddr = mp->addr;
+ mp->addr = maddr+size;
+ mp->size -= maddr-oaddr+size;
+ if(mp->size == 0){
+ do{
+ mp++;
+ (mp-1)->addr = mp->addr;
+ }while((mp-1)->size = mp->size);
+ }
+
+ unlock(rmap);
+ if(oaddr != maddr)
+ mapfree(rmap, oaddr, maddr-oaddr);
+
+ return maddr;
+ }
+ unlock(rmap);
+
+ return 0;
+}
diff --git a/os/boot/mpc/screen.c b/os/boot/mpc/screen.c
new file mode 100644
index 00000000..ec420ee9
--- /dev/null
+++ b/os/boot/mpc/screen.c
@@ -0,0 +1,242 @@
+#include "all.h"
+#include <libg.h>
+#include <gnot.h>
+
+enum {
+ Colldepth = 3,
+ Colmaxx = 640,
+ Colmaxxvis = 640,
+ Colmaxy = 480,
+};
+
+#define MINX 8
+
+extern GSubfont defont0;
+
+struct{
+ Point pos;
+ int bwid;
+}out;
+
+typedef struct Mode Mode;
+struct Mode {
+ int x;
+ int y;
+ int d;
+ char* aperture;
+ int apsize;
+};
+
+GBitmap gscreen;
+Point gchar(GBitmap*, Point, GFont*, int, Fcode);
+int setcolor(ulong, ulong, ulong, ulong);
+static void lcdinit(Mode*);
+
+void
+screeninit(void)
+{
+ Mode m;
+
+ m.x = Colmaxx;
+ m.y = Colmaxy;
+ m.d = Colldepth;
+ m.aperture = 0;
+ lcdinit(&m);
+ if(m.aperture == 0)
+ return;
+ gscreen.ldepth = 3;
+ gscreen.base = (ulong*)m.aperture;
+ gscreen.width = Colmaxx/BY2WD;
+ gscreen.r = Rect(0, 0, Colmaxxvis, Colmaxy);
+ gscreen.clipr = gscreen.r;
+ /*
+ * For now, just use a fixed colormap:
+ * 0 == white and 255 == black
+ */
+ setcolor(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
+ setcolor(255, 0x00000000, 0x00000000, 0x00000000);
+
+ gbitblt(&gscreen, Pt(0, 0), &gscreen, gscreen.r, Zero);
+ out.pos.x = MINX;
+ out.pos.y = 0;
+ out.bwid = defont0.info[' '].width;
+}
+
+void
+screenputc(int c)
+{
+ Fontchar *i;
+ Point p;
+
+ if(gscreen.base == nil)
+ return;
+ switch(c){
+ case '\n':
+ out.pos.x = MINX;
+ out.pos.y += defont0.height;
+ if(out.pos.y > gscreen.r.max.y-defont0.height)
+ out.pos.y = gscreen.r.min.y;
+ gbitblt(&gscreen, Pt(0, out.pos.y), &gscreen,
+ Rect(0, out.pos.y, gscreen.r.max.x, out.pos.y+2*defont0.height),
+ Zero);
+ break;
+ case '\t':
+ out.pos.x += (8-((out.pos.x-MINX)/out.bwid&7))*out.bwid;
+ if(out.pos.x >= gscreen.r.max.x)
+ screenputc('\n');
+ break;
+ case '\b':
+ if(out.pos.x >= out.bwid+MINX){
+ out.pos.x -= out.bwid;
+ screenputc(' ');
+ out.pos.x -= out.bwid;
+ }
+ break;
+ default:
+ if(out.pos.x >= gscreen.r.max.x-out.bwid)
+ screenputc('\n');
+ c &= 0x7f;
+ if(c <= 0 || c >= defont0.n)
+ break;
+ i = defont0.info + c;
+ p = out.pos;
+ gbitblt(&gscreen, Pt(p.x+i->left, p.y), defont0.bits,
+ Rect(i[0].x, 0, i[1].x, defont0.height),
+ S);
+ out.pos.x = p.x + i->width;
+ break;
+ }
+}
+
+void
+screenputs(char *s, int n)
+{
+ while(n-- > 0)
+ screenputc(*s++);
+}
+
+/*
+ * See section 5.2.1 (page 5-6) of the MPC823 manual
+ */
+static uchar lcdclock[17] = { /* (a<<2)|b => divisor of (1<<a)*((b<<1)+1) */
+ 0, 0, (1<<2), 1,
+ (2<<2), 2, (1<<2)|1, 3,
+ (3<<2), (1<<2)|2, (1<<2)|2, (2<<2)|1,
+ (2<<2)|1, (1<<2)|3, (1<<2)|3, (4<<2),
+ (4<<2)
+};
+
+/*
+ * support for the Sharp LQ64D341 TFT colour display
+ */
+
+enum {
+ COLS = 640,
+ ROWS = 480,
+ LDEPTH = 3, /* screen depth */
+ LCDFREQ = 25000000,
+
+ /* lccr */
+ ClockLow = 1<<11,
+ OELow = 1<<10,
+ HsyncLow = 1<<9,
+ VsyncLow = 1<<8,
+ DataLow = 1<<7,
+ Passive8 = 1<<4,
+ DualScan = 1<<3,
+ IsColour = 1<<2,
+ IsTFT = 1<<1,
+ Enable = 1<<0,
+
+ /* lchcr */
+ BigEndian = 1<<24,
+ AT7 = 7<<21, /* access type */
+
+ /* sdcr */
+ LAM = 1<<6, /* ``LCD aggressive mode'' */
+};
+
+/*
+ * TO DO: most of the data could come from a table
+ */
+static void
+lcdinit(Mode *mode)
+{
+ IMM *io;
+ int i, d;
+ long hz;
+
+ io = m->iomem;
+ mode->y = ROWS;
+ mode->x = COLS;
+ mode->d = LDEPTH;
+ mode->aperture = ialloc(mode->x*mode->y, 16);
+ mode->apsize = mode->x*mode->y;
+
+ io->sdcr &= ~LAM; /* MPC823 errata: turn off LAM before disabling controller */
+ io->lcfaa = PADDR(mode->aperture);
+ io->lccr = (((mode->x*mode->y*(1<<LDEPTH)+127)/128) << 17) | (LDEPTH << 5) | IsColour | IsTFT | OELow | VsyncLow | ClockLow;
+
+ switch(LDEPTH){
+ default:
+ case 0:
+ /* monochrome/greyscale identity map */
+ for(i=0; i<16; i++)
+ io->lcdmap[i] = i;
+ break;
+ case 2:
+ /* 4-bit grey scale map */
+ for(i=0; i<16; i++)
+ io->lcdmap[0] = (i<<8)|(i<<4)|i;
+ break;
+ case 3:
+ /* 8-bit linear map */
+ for(i=0; i<256; i++)
+ io->lcdmap[i] = (i<<8)|(i<<4)|i;
+ break;
+ }
+
+ io->lcvcr = (mode->y << 11) | (1<<28) | 33; /* 2 line vsync pulse, 34 line wait between frames */
+ io->lchcr = (mode->x<<10) | BigEndian | 228; /* clock cycles between lines */
+
+ hz = m->cpuhz;
+ d = hz/LCDFREQ;
+ if(hz/d > LCDFREQ)
+ d++;
+ if(d >= 16)
+ d = 16;
+
+ /*
+ * enable LCD outputs
+ */
+ io->pddat = 0;
+ io->pdpar = 0x1fff;
+io->pdpar &= ~SIBIT(6); /* 823 bug fix? */
+ io->pddir = 0x1fff;
+ io->pbpar |= IBIT(31) | IBIT(19) | IBIT(17);
+ io->pbdir |= IBIT(31) | IBIT(19) | IBIT(17);
+ io->pbodr &= ~(IBIT(31) | IBIT(19) | IBIT(17));
+
+ eieio();
+ io->sccrk = KEEP_ALIVE_KEY;
+ eieio();
+ io->sccr = (io->sccr & ~0x1F) | lcdclock[d];
+ eieio();
+ io->sccrk = ~KEEP_ALIVE_KEY;
+ eieio();
+ gscreen.width = gscreen.width; /* access external memory before enabling (mpc823 errata) */
+ io->lcsr = 7; /* clear status */
+ eieio();
+ io->lccr |= Enable;
+ archbacklight(1);
+}
+
+int
+setcolor(ulong p, ulong r, ulong g, ulong b)
+{
+ r >>= 28;
+ g >>= 28;
+ b >>= 28;
+ m->iomem->lcdmap[~p&0xFF] = (r<<8) | (g<<4) | b; /* TO DO: it's a function of the ldepth */
+ return 1;
+}
diff --git a/os/boot/mpc/sload.c b/os/boot/mpc/sload.c
new file mode 100644
index 00000000..0eb02805
--- /dev/null
+++ b/os/boot/mpc/sload.c
@@ -0,0 +1,71 @@
+/*
+ * send S records to rpcg
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+static int dbg;
+static char buf[2048];
+static int run=1;
+static void stuffbym(char*, int, int);
+static void getdot(void);
+
+void
+main(int argc, char **argv)
+{
+ int n;
+ char *l;
+ Biobuf *f;
+ static int p;
+
+ ARGBEGIN{
+ case 'd': dbg++; break;
+ case 'n': run=0; break;
+ }ARGEND
+
+ f = Bopen(*argv? *argv: "k.mx", OREAD);
+ if(f == 0) {
+ fprint(2, "sload: cannot open k.mx: %r\n");
+ exits("sload");
+ }
+ getdot();
+ while((l = Brdline(f, '\n')) != 0) {
+ l[Blinelen(f)-1] = '\r';
+ stuffbym(l, Blinelen(f), 16);
+ getdot();
+ if(++p % 25 == 0)
+ write(2, ".", 1);
+ }
+ exits(0);
+}
+
+static void
+stuffbym(char *l, int n, int m)
+{
+ int nr, ns;
+
+ while(n > 0) {
+ ns = n;
+ if(ns > m)
+ ns = m;
+ write(1, l, ns);
+ l += ns;
+ n -= ns;
+ }
+}
+
+static void
+getdot(void)
+{
+ char c;
+
+ for(;;){
+ if(read(0, &c, 1) != 1)
+ exits("bang");
+ write(2, &c, 1);
+ if(c == '.')
+ break;
+ }
+}
diff --git a/os/boot/mpc/squeeze.h b/os/boot/mpc/squeeze.h
new file mode 100644
index 00000000..b06c1b79
--- /dev/null
+++ b/os/boot/mpc/squeeze.h
@@ -0,0 +1,34 @@
+
+/*
+ * squeezed file format:
+ * Sqhdr
+ * original Exec header
+ * two Squeeze tables
+ * squeezed segment
+ * unsqueezed segment, if any
+ */
+#define SQMAGIC (ulong)0xFEEF0F1E
+
+typedef struct Sqhdr Sqhdr;
+struct Sqhdr {
+ uchar magic[4]; /* SQMAGIC */
+ uchar text[4]; /* squeezed length of text (excluding tables) */
+ uchar data[4]; /* squeezed length of data (excluding tables) */
+ uchar asis[4]; /* length of unsqueezed segment */
+ uchar toptxt[4]; /* value for 0 encoding in text */
+ uchar topdat[4]; /* value for 0 encoding in data */
+ uchar sum[4]; /* simple checksum of unsqueezed data */
+ uchar flags[4];
+};
+#define SQHDRLEN (8*4)
+
+/*
+ * certain power instruction types are rearranged by sqz
+ * so as to move the variable part of the instruction word to the
+ * low order bits. note that the mapping is its own inverse.
+ */
+#define QREMAP(X)\
+ switch((X)>>26){\
+ case 19: case 31: case 59: case 63:\
+ (X) = (((X) & 0xFC00F801) | (((X)>>15)&0x7FE) | (((X)&0x7FE)<<15));\
+ }
diff --git a/os/boot/mpc/trap.c b/os/boot/mpc/trap.c
new file mode 100644
index 00000000..3440ee1f
--- /dev/null
+++ b/os/boot/mpc/trap.c
@@ -0,0 +1,233 @@
+#include "boot.h"
+
+enum
+{
+ Maxhandler= 32+16, /* max number of interrupt handlers */
+};
+
+typedef struct Handler Handler;
+struct Handler
+{
+ void (*r)(Ureg*, void*);
+ void *arg;
+ Handler *next;
+ int edge;
+};
+
+struct
+{
+ Handler *ivec[128];
+ Handler h[Maxhandler];
+ int free;
+} halloc;
+
+char *excname[] = {
+ "reserved 0",
+ "system reset",
+ "machine check",
+ "data access",
+ "instruction access",
+ "external interrupt",
+ "alignment",
+ "program exception",
+ "floating-point unavailable",
+ "decrementer",
+ "reserved A",
+ "reserved B",
+ "system call",
+ "trace trap",
+ "floating point assist",
+ "reserved F",
+ "software emulation",
+ "ITLB miss",
+ "DTLB miss",
+ "ITLB error",
+ "DTLB error",
+};
+
+char *regname[]={
+ "CAUSE", "SRR1",
+ "PC", "GOK",
+ "LR", "CR",
+ "XER", "CTR",
+ "R0", "R1",
+ "R2", "R3",
+ "R4", "R5",
+ "R6", "R7",
+ "R8", "R9",
+ "R10", "R11",
+ "R12", "R13",
+ "R14", "R15",
+ "R16", "R17",
+ "R18", "R19",
+ "R20", "R21",
+ "R22", "R23",
+ "R24", "R25",
+ "R26", "R27",
+ "R28", "R29",
+ "R30", "R31",
+};
+
+static void intr(Ureg*);
+
+void
+sethvec(int v, void (*r)(void))
+{
+ ulong *vp, pa, o;
+
+ if((ulong)r & 3)
+ panic("sethvec");
+ vp = (ulong*)KADDR(v);
+ vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */
+ vp[1] = 0x7c0802a6; /* MOVW LR, R0 */
+ vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */
+ pa = PADDR(r);
+ o = pa >> 25;
+ if(o != 0 && o != 0x7F){
+ /* a branch too far: running from ROM */
+ vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */
+ vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */
+ vp[5] = 0x7c0803a6; /* MOVW R0, LR */
+ vp[6] = 0x4e800021; /* BL (LR) */
+ }else
+ vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */
+}
+
+#define LEV(n) (((n)<<1)|1)
+#define IRQ(n) (((n)<<1)|0)
+
+void
+setvec(int v, void (*r)(Ureg*, void*), void *arg)
+{
+ Handler *h;
+ IMM *io;
+
+ if(halloc.free >= Maxhandler)
+ panic("out of interrupt handlers");
+ v -= VectorPIC;
+ h = &halloc.h[halloc.free++];
+ h->next = halloc.ivec[v];
+ h->r = r;
+ h->arg = arg;
+ halloc.ivec[v] = h;
+
+ /*
+ * enable corresponding interrupt in SIU/CPM
+ */
+
+ io = m->iomem;
+ if(v >= VectorCPIC){
+ v -= VectorCPIC;
+ io->cimr |= 1<<(v&0x1F);
+ }
+ else if(v >= VectorIRQ)
+ io->simask |= 1<<(31-IRQ(v&7));
+ else
+ io->simask |= 1<<(31-LEV(v));
+}
+
+void
+trapinit(void)
+{
+ int i;
+ IMM *io;
+
+ io = m->iomem;
+ io->sypcr &= ~(3<<2); /* disable watchdog (821/823) */
+ io->simask = 0; /* mask all */
+ io->siel = ~0; /* edge sensitive, wake on all */
+ io->cicr = 0; /* disable CPM interrupts */
+ io->cipr = ~0; /* clear all interrupts */
+ io->cimr = 0; /* mask all events */
+ io->cicr = (0xE1<<16)|(CPIClevel<<13)|(0x1F<<8);
+ io->cicr |= 1 << 7; /* enable */
+ io->tbscrk = KEEP_ALIVE_KEY;
+ io->tbscr = 1; /* TBE */
+ io->simask |= 1<<(31-LEV(CPIClevel)); /* CPM's level */
+ io->tbk = KEEP_ALIVE_KEY;
+ eieio();
+ putdec(~0);
+
+ /*
+ * set all exceptions to trap
+ */
+ for(i = 0x0; i < 0x3000; i += 0x100)
+ sethvec(i, exception);
+}
+
+void
+dumpregs(Ureg *ur)
+{
+ int i;
+ ulong *l;
+ l = &ur->cause;
+ for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
+ print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
+}
+
+void
+trap(Ureg *ur)
+{
+ int c;
+
+ c = ur->cause >> 8;
+ switch(c){
+ default:
+ {extern int predawn; predawn = 1;}
+ if(c < 0 || c >= nelem(excname))
+ print("exception/interrupt #%x\n", c);
+ else
+ print("exception %s\n", excname[c]);
+ dumpregs(ur);
+ /* spllo(); */
+ print("^P to reset\n");
+ for(;;)
+ ;
+
+ case 0x09: /* decrementer */
+ clockintr(ur, 0);
+ return;
+
+ case 0x05: /* external interrupt */
+ intr(ur);
+ break;
+ }
+}
+
+static void
+intr(Ureg *ur)
+{
+ int b, v;
+ Handler *h;
+ IMM *io;
+
+ io = m->iomem;
+ b = io->sivec>>2;
+ v = b>>1;
+ if(b & 1) {
+ if(v == CPIClevel){
+ io->civr = 1;
+ eieio();
+ v = VectorCPIC+(io->civr>>11);
+ }
+ }else
+ v += VectorIRQ;
+ h = halloc.ivec[v];
+ if(h == nil){
+ for(;;)
+ ;
+ //print("unknown interrupt %d pc=0x%lux\n", v, ur->pc);
+ return;
+ }
+ if(h->edge)
+ io->sipend |= 1<<(31-b);
+ /*
+ * call the interrupt handlers
+ */
+ do {
+ (*h->r)(ur, h->arg);
+ h = h->next;
+ } while(h != nil);
+ if(v >= VectorCPIC)
+ io->cisr |= 1<<(v-VectorCPIC);
+}
diff --git a/os/boot/mpc/uartboot.c b/os/boot/mpc/uartboot.c
new file mode 100644
index 00000000..0b11b5d5
--- /dev/null
+++ b/os/boot/mpc/uartboot.c
@@ -0,0 +1,189 @@
+#include "boot.h"
+
+/*
+ * this doesn't yet use the crc
+ */
+
+typedef struct Uboot Uboot;
+struct Uboot {
+ Queue* iq;
+ Block* partial;
+ ulong csum;
+ long bno;
+ uchar buf[64];
+ int nleft;
+ int ntimeout;
+};
+
+static Uboot uboot;
+ulong crc32(void *buf, int n, ulong crc);
+
+static void
+uartbrecv(uchar *p, int n)
+{
+ Uboot *ub;
+ Block *b;
+
+ ub = &uboot;
+ if(n > 0 && ub->iq != nil){
+ b = iallocb(n);
+ memmove(b->wp, p, n);
+ b->wp += n;
+ qbwrite(ub->iq, b);
+ }
+}
+
+int
+uartinit(void)
+{
+ return 1<<0;
+}
+
+Partition*
+setuartpart(int, char *s)
+{
+ static Partition pp[1];
+
+ if(strcmp(s, "boot") != 0 && strcmp(s, "disk") != 0)
+ return 0;
+ pp[0].start = 0;
+ pp[0].end = 2*1024*1024;
+ strcpy(pp[0].name, "boot");
+ return pp;
+}
+
+long
+uartseek(int, long)
+{
+ /* start the boot */
+ if(uboot.iq == nil)
+ uboot.iq = qopen(64*1024, 0, 0, 0);
+ if(uboot.partial){
+ freeb(uboot.partial);
+ uboot.partial = 0;
+ }
+ print("uart: start transmission\n");
+ uartsetboot(uartbrecv);
+ uboot.csum = ~0;
+ uboot.bno = 0;
+ uboot.nleft = 0;
+ uboot.ntimeout = 0;
+ return 0;
+}
+
+static long
+uartreadn(void *buf, int nb)
+{
+ ulong start;
+ Uboot *ub;
+ int l;
+ Block *b;
+ uchar *p;
+
+ p = buf;
+ ub = &uboot;
+ start = m->ticks;
+ while(nb > 0){
+ b = ub->partial;
+ ub->partial = nil;
+ if(b == nil){
+ ub->ntimeout = 0;
+ while((b = qget(ub->iq)) == 0){
+ if(TK2MS(m->ticks - start) >= 15*1000){
+ if(++ub->ntimeout >= 3){
+ print("uart: timeout\n");
+ return 0;
+ }
+ uartputs("n", 1);
+ }
+ }
+ }
+ l = BLEN(b);
+ if(l > nb)
+ l = nb;
+ memmove(p, b->rp, l);
+ b->rp += l;
+ if(b->rp >= b->wp)
+ freeb(b);
+ else
+ ub->partial = b;
+ nb -= l;
+ p += l;
+ }
+ return p-(uchar*)buf;
+}
+
+long
+uartread(int, void *buf, long n)
+{
+ uchar *p;
+ int l;
+ static uchar lbuf[64];
+
+ p = buf;
+ if((l = uboot.nleft) > 0){
+ if(l > n)
+ l = n;
+ uboot.nleft -= l;
+ memmove(p, uboot.buf, l);
+ p += l;
+ n -= l;
+ }
+ while(n > 0){
+ l = uartreadn(lbuf, sizeof(lbuf));
+ if(l < sizeof(lbuf))
+ return 0;
+ if(l > n){
+ uboot.nleft = l-n;
+ memmove(uboot.buf, lbuf+n, uboot.nleft);
+ l = n;
+ }
+ memmove(p, lbuf, l);
+ n -= l;
+ p += l;
+ uboot.bno++;
+ uartputs("y", 1);
+ }
+ return p-(uchar*)buf;
+}
+
+/*
+ * from Rob Warnock
+ */
+static ulong crc32tab[256]; /* initialised on first call to crc32 */
+
+enum {
+ CRC32POLY = 0x04c11db7 /* AUTODIN II, Ethernet, & FDDI */
+};
+
+/*
+ * Build auxiliary table for parallel byte-at-a-time CRC-32.
+ */
+static void
+initcrc32(void)
+{
+ int i, j;
+ ulong c;
+
+ for(i = 0; i < 256; i++) {
+ for(c = i << 24, j = 8; j > 0; j--)
+ if(c & (1<<31))
+ c = (c<<1) ^ CRC32POLY;
+ else
+ c <<= 1;
+ crc32tab[i] = c;
+ }
+}
+
+ulong
+crc32(void *buf, int n, ulong crc)
+{
+ uchar *p;
+
+ if(crc32tab[1] == 0)
+ initcrc32();
+ crc = ~crc;
+ for(p = buf; --n >= 0;)
+ crc = (crc << 8) ^ crc32tab[(crc >> 24) ^ *p++];
+ return ~crc;
+}
diff --git a/os/boot/mpc/ureg.h b/os/boot/mpc/ureg.h
new file mode 100644
index 00000000..7ccdb492
--- /dev/null
+++ b/os/boot/mpc/ureg.h
@@ -0,0 +1,43 @@
+struct Ureg
+{
+ ulong cause;
+ union { ulong srr1; ulong status;};
+ ulong pc; /* SRR0 */
+ ulong pad;
+ ulong lr;
+ ulong cr;
+ ulong xer;
+ ulong ctr;
+ ulong r0;
+ union{ ulong r1; ulong sp; ulong usp; };
+ ulong r2;
+ ulong r3;
+ ulong r4;
+ ulong r5;
+ ulong r6;
+ ulong r7;
+ ulong r8;
+ ulong r9;
+ ulong r10;
+ ulong r11;
+ ulong r12;
+ ulong r13;
+ ulong r14;
+ ulong r15;
+ ulong r16;
+ ulong r17;
+ ulong r18;
+ ulong r19;
+ ulong r20;
+ ulong r21;
+ ulong r22;
+ ulong r23;
+ ulong r24;
+ ulong r25;
+ ulong r26;
+ ulong r27;
+ ulong r28;
+ ulong r29;
+ ulong r30;
+ ulong r31;
+};
diff --git a/os/boot/mpc/zqs.c b/os/boot/mpc/zqs.c
new file mode 100644
index 00000000..b6296786
--- /dev/null
+++ b/os/boot/mpc/zqs.c
@@ -0,0 +1,234 @@
+#include "boot.h"
+#include "squeeze.h"
+
+/*
+ * for details of `unsqueeze' see:
+ *
+ * %A Mark Taunton
+ * %T Compressed Executables: An Exercise in Thinking Small
+ * %P 385-404
+ * %I USENIX
+ * %B USENIX Conference Proceedings
+ * %D Summer 1991
+ * %C Nashville, TN
+ *
+ * several of the unimplemented improvements described in the paper
+ * have been implemented here
+ *
+ * there is a further transformation on the powerpc (QFLAG!=0) to shuffle bits
+ * in certain instructions so as to push the fixed bits to the top of the word.
+ */
+
+#define EXECHDRLEN (8*4)
+
+typedef struct Squeeze Squeeze;
+struct Squeeze {
+ int n;
+ ulong tab[7*256];
+};
+
+#define GET4(p) (((((((p)[0]<<8)|(p)[1])<<8)|(p)[2])<<8)|(p)[3])
+
+/*
+ * for speed of unsqueezing from Flash, certain checks are
+ * not done inside the loop (as they would be in the unsqueeze program zqs),
+ * but instead the checksum is expected to catch corrupted files.
+ * in fact the Squeeze array bounds can't be exceeded in practice
+ * because the tables are always full for a squeezed kernel.
+ */
+enum {
+ QFLAG = 1, /* invert powerpc-specific code transformation */
+ CHECK = 0, /* check precise bounds in Squeeze array (otherwise checksum detects error) */
+};
+
+static ulong chksum;
+static int rdtab(Block*, Squeeze*, int);
+static ulong* unsqueeze(ulong*, uchar*, uchar*, Squeeze*, Squeeze*, ulong);
+static uchar* unsqzseg(uchar*, Block*, long, long, char*);
+static Alarm* unsqzal;
+
+int
+issqueezed(uchar *b)
+{
+ return GET4(b) == SQMAGIC? GET4(b+SQHDRLEN): 0;
+}
+
+static void
+unsqzdot(Alarm*)
+{
+ unsqzal = alarm(500, unsqzdot, nil);
+ print(".");
+}
+
+long
+unsqueezef(Block *b, ulong *entryp)
+{
+ uchar *loada, *wp;
+ ulong toptxt, topdat, oldsum;
+ long asis, nst, nsd;
+ Sqhdr *sqh;
+ Exec *ex;
+
+ if(BLEN(b) < SQHDRLEN+EXECHDRLEN)
+ return -1;
+ sqh = (Sqhdr*)b->rp;
+ if(GET4(sqh->magic) != SQMAGIC)
+ return -1;
+ chksum = 0;
+ toptxt = GET4(sqh->toptxt);
+ topdat = GET4(sqh->topdat);
+ oldsum = GET4(sqh->sum);
+ asis = GET4(sqh->asis);
+ nst = GET4(sqh->text);
+ nsd = GET4(sqh->data);
+ b->rp += SQHDRLEN;
+ ex = (Exec*)b->rp;
+ if(GET4(ex->magic) != Q_MAGIC){
+ print("zqs: not powerPC executable\n");
+ return -1;
+ }
+ *entryp = GET4(ex->entry);
+ b->rp += EXECHDRLEN;
+ loada = KADDR(PADDR(*entryp));
+ wp = unsqzseg(loada, b, nst, toptxt, "text");
+ if(wp == nil){
+ print("zqs: format error\n");
+ return -1;
+ }
+ if(nsd){
+ wp = (uchar*)PGROUND((ulong)wp);
+ wp = unsqzseg(wp, b, nsd, topdat, "data");
+ if(wp == nil){
+ print("zqs: format error\n");
+ return -1;
+ }
+ }
+ if(asis){
+ memmove(wp, b->rp, asis);
+ wp += asis;
+ b->rp += asis;
+ }
+ if(chksum != oldsum){
+ print("\nsqueezed kernel: checksum error: %8.8lux need %8.8lux\n", chksum, oldsum);
+ return -1;
+ }
+ return wp-loada;
+}
+
+static uchar *
+unsqzseg(uchar *wp, Block *b, long ns, long top, char *what)
+{
+ static Squeeze sq3, sq4;
+
+ print("unpack %s %8.8lux %lud:", what, wp, ns);
+ if(ns == 0)
+ return wp;
+ if(rdtab(b, &sq3, 0) < 0)
+ return nil;
+ if(rdtab(b, &sq4, 8) < 0)
+ return nil;
+ if(BLEN(b) < ns){
+ print(" **size error\n");
+ return nil;
+ }
+ unsqzal = alarm(500, unsqzdot, nil);
+ wp = (uchar*)unsqueeze((ulong*)wp, b->rp, b->rp+ns, &sq3, &sq4, top);
+ cancel(unsqzal);
+ unsqzal = nil;
+ print("\n");
+ if(wp == nil){
+ print("zqs: corrupt squeezed data stream\n");
+ return nil;
+ }
+ b->rp += ns;
+ return wp;
+}
+
+static ulong*
+unsqueeze(ulong *wp, uchar *rp, uchar *ep, Squeeze *sq3, Squeeze *sq4, ulong top)
+{
+ ulong nx, csum;
+ int code, n;
+
+ if(QFLAG){
+ QREMAP(top); /* adjust top just once, outside the loop */
+ }
+ csum = chksum;
+ while(rp < ep){
+ /* no function calls within this loop for speed */
+ code = *rp;
+ rp++;
+ n = 0;
+ nx = code>>4;
+ do{
+ if(nx == 0){
+ nx = top;
+ }else{
+ if(nx==1){
+ nx = (((((rp[3]<<8)|rp[2])<<8)|rp[1])<<8)|rp[0];
+ rp += 4;
+ }else if(nx <= 8){ /* 2 to 8 */
+ nx = ((nx-2)<<8) | rp[0];
+ if(CHECK && nx >= sq4->n)
+ return nil; /* corrupted file */
+ nx = sq4->tab[nx] | rp[1];
+ rp += 2;
+ }else{ /* 9 to 15 */
+ nx = ((nx-9)<<8) | rp[0];
+ if(CHECK && nx >= sq3->n)
+ return nil; /* corrupted file */
+ nx = sq3->tab[nx];
+ rp++;
+ }
+ if(rp > ep)
+ return nil; /* corrupted file */
+ if(QFLAG){
+ QREMAP(nx);
+ }
+ }
+ *wp = nx;
+ wp++;
+ csum += nx;
+ nx = code & 0xF;
+ }while(++n == 1);
+ }
+ chksum = csum;
+ return wp;
+}
+
+static int
+rdtab(Block *b, Squeeze *sq, int shift)
+{
+ uchar *p, *ep;
+ ulong v, w;
+ int i;
+
+ if(BLEN(b) < 2)
+ return -1;
+ i = (b->rp[0]<<8) | b->rp[1];
+ if(1)
+ print(" T%d", i);
+ b->rp += 2;
+ if((i -= 2) > 0){
+ if(BLEN(b) < i)
+ return -1;
+ }
+ sq->n = 0;
+ p = b->rp;
+ ep = b->rp+i;
+ b->rp += i;
+ v = 0;
+ while(p < ep){
+ w = 0;
+ do{
+ if(p >= ep)
+ return -1;
+ w = (w<<7) | (*p & 0x7F);
+ }while(*p++ & 0x80);
+ v += w;
+ if(0)
+ print("%d %8.8lux %8.8lux\n", sq->n, v, w);
+ sq->tab[sq->n++] = v<<shift;
+ }
+ return 0;
+}