diff options
Diffstat (limited to 'os/boot/mpc')
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 = ðer[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 = ðer[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; +} |
