ref: 8411fca67137ba5d0e22d8184633a83fd25fe0a5
parent: 5c30140aa4d842dbb700cd6c8b9d7296fd91da84
author: joe9 <joe9mail@gmail.com>
date: Fri Jul 16 19:34:58 EDT 2021
copied 9front boot infrastructure over
--- /dev/null
+++ b/os/boot/bcm/mkfile
@@ -1,0 +1,16 @@
+URL=https://github.com/raspberrypi/firmware/raw/master/boot
+FILES=bootcode.bin fixup_cd.dat start_cd.elf fixup4cd.dat start4cd.elf \
+ bcm2711-rpi-4-b.dtb \
+ bcm2711-rpi-400.dtb \
+ bcm2711-rpi-cm4.dtb \
+ LICENCE.broadcom
+
+all:V: $FILES
+
+clean:V:
+ rm -f $FILES
+
+$FILES:
+ for(i in $target){
+ hget -o $i $URL/$i
+ }
--- /dev/null
+++ b/os/boot/bitsy/donprint.c
@@ -1,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;
+}
--- /dev/null
+++ b/os/boot/bitsy/fns.h
@@ -1,0 +1,7 @@
+/*
+ * functions defined locally
+ */
+extern int gunzip(uchar *out, int outn, uchar *in, int inn);
+extern void delay(int ms);
+extern void serialputs(char *str, int n);
+extern void draincache(void);
--- /dev/null
+++ b/os/boot/bitsy/il.s
@@ -1,0 +1,99 @@
+#include "mem.h"
+/*
+ * Entered here from Compaq's bootldr. First relocate to
+ * the location we're linked for and then copy back the
+ * decompressed kernel.
+ *
+ * All
+ */
+TEXT _start(SB), $-4
+ MOVW $setR12(SB), R12 /* load the SB */
+ MOVW $1, R0 /* dance to make 5l think that the magic */
+ MOVW $1, R1 /* numbers in WORDs below are being used */
+ CMP.S R0, R1 /* and to align them to where bootldr wants */
+ BEQ _start2
+ WORD $0x016f2818 /* magic number to say we are a kernel */
+ WORD $0xc0008000 /* entry point address */
+ WORD $0 /* size?, or end of data? */
+
+_start2:
+
+ /* SVC mode, interrupts disabled */
+ MOVW $(PsrDirq|PsrDfiq|PsrMsvc), R1
+ MOVW R1, CPSR
+
+ /* disable the MMU */
+ MOVW $0x130, R1
+ MCR CpMMU, 0, R1, C(CpControl), C(0x0)
+
+ /* enable caches */
+ MRC CpMMU, 0, R0, C(CpControl), C(0x0)
+ ORR $(CpCdcache|CpCicache|CpCwb), R0
+ MCR CpMMU, 0, R0, C(CpControl), C(0x0)
+
+ /* flush caches */
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0
+ /* drain prefetch */
+ MOVW R0,R0
+ MOVW R0,R0
+ MOVW R0,R0
+ MOVW R0,R0
+
+ /* drain write buffer */
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
+
+ /* relocate to where we expect to be */
+ MOVW $(512*1024),R3
+ MOVW $0xC0008000,R1
+ MOVW $0xC0200000,R2
+ ADD R1,R3
+_relloop:
+ MOVW (R1),R0
+ MOVW R0,(R2)
+ ADD $4,R1
+ ADD $4,R2
+ CMP.S R1,R3
+ BNE _relloop
+
+ MOVW $(MACHADDR+BY2PG), R13 /* stack */
+ SUB $4, R13 /* link */
+
+ /* jump to where we've been relocated */
+ MOVW $_relocated(SB),R15
+
+TEXT _relocated(SB),$-4
+ BL main(SB)
+ BL exit(SB)
+ /* we shouldn't get here */
+_mainloop:
+ B _mainloop
+ BL _div(SB) /* hack to get _div etc loaded */
+
+TEXT mypc(SB),$-4
+ MOVW R14,R0
+ RET
+
+TEXT draincache(SB),$-4
+ /* write back any dirty data */
+ MOVW $0xe0000000,R0
+ ADD $(8*1024),R0,R1
+_cfloop:
+ MOVW.P 32(R0),R2
+ CMP.S R0,R1
+ BNE _cfloop
+
+ /* drain write buffer and invalidate i&d cache contents */
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0
+
+ /* drain prefetch */
+ MOVW R0,R0
+ MOVW R0,R0
+ MOVW R0,R0
+ MOVW R0,R0
+
+ /* disable caches */
+ MRC CpMMU, 0, R0, C(CpControl), C(0x0)
+ BIC $(CpCdcache|CpCicache|CpCwb), R0
+ MCR CpMMU, 0, R0, C(CpControl), C(0x0)
+ RET
--- /dev/null
+++ b/os/boot/bitsy/imain.c
@@ -1,0 +1,48 @@
+#include "u.h"
+#include "lib.h"
+#include "fns.h"
+#include "dat.h"
+#include "mem.h"
+
+void
+main(void)
+{
+ void (*f)(void);
+ ulong *kernel;
+
+ print("inflating kernel\n");
+
+ kernel = (ulong*)(0xc0200000+20*1024);
+ if(gunzip((uchar*)0xc0008000, 2*1024*1024, (uchar*)kernel, 512*1024) > 0){
+ f = (void (*)(void))0xc0008010;
+ draincache();
+ } else {
+ print("inflation failed\n");
+ f = nil;
+ }
+ (*f)();
+}
+
+void
+exit(void)
+{
+
+ void (*f)(void);
+
+ delay(1000);
+
+ print("it's a wonderful day to die\n");
+ f = nil;
+ (*f)();
+}
+
+void
+delay(int ms)
+{
+ int i;
+
+ while(ms-- > 0){
+ for(i = 0; i < 1000; i++)
+ ;
+ }
+}
--- /dev/null
+++ b/os/boot/bitsy/inflate.c
@@ -1,0 +1,208 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include <flate.h>
+
+typedef struct Biobuf Biobuf;
+
+struct Biobuf
+{
+ uchar *bp;
+ uchar *p;
+ uchar *ep;
+};
+
+static int header(Biobuf*);
+static int trailer(Biobuf*, Biobuf*);
+static int getc(void*);
+static ulong offset(Biobuf*);
+static int crcwrite(void *out, void *buf, int n);
+static ulong get4(Biobuf *b);
+static ulong Boffset(Biobuf *bp);
+
+/* GZIP flags */
+enum {
+ Ftext= (1<<0),
+ Fhcrc= (1<<1),
+ Fextra= (1<<2),
+ Fname= (1<<3),
+ Fcomment= (1<<4),
+
+ GZCRCPOLY = 0xedb88320UL,
+};
+
+static ulong *crctab;
+static ulong crc;
+
+int
+gunzip(uchar *out, int outn, uchar *in, int inn)
+{
+ Biobuf bin, bout;
+ int err;
+
+ crc = 0;
+ crctab = mkcrctab(GZCRCPOLY);
+ err = inflateinit();
+ if(err != FlateOk)
+ print("inflateinit failed: %s\n", flateerr(err));
+
+ bin.bp = bin.p = in;
+ bin.ep = in+inn;
+ bout.bp = bout.p = out;
+ bout.ep = out+outn;
+
+ err = header(&bin);
+ if(err != FlateOk)
+ return err;
+
+ err = inflate(&bout, crcwrite, &bin, getc);
+ if(err != FlateOk)
+ print("inflate failed: %s\n", flateerr(err));
+
+ err = trailer(&bout, &bin);
+ if(err != FlateOk)
+ return err;
+
+ return Boffset(&bout);
+}
+
+static int
+header(Biobuf *bin)
+{
+ int i, flag;
+
+ if(getc(bin) != 0x1f || getc(bin) != 0x8b){
+ print("bad magic\n");
+ return FlateCorrupted;
+ }
+ if(getc(bin) != 8){
+ print("unknown compression type\n");
+ return FlateCorrupted;
+ }
+
+ flag = getc(bin);
+
+ /* mod time */
+ get4(bin);
+
+ /* extra flags */
+ getc(bin);
+
+ /* OS type */
+ getc(bin);
+
+ if(flag & Fextra)
+ for(i=getc(bin); i>0; i--)
+ getc(bin);
+
+ /* name */
+ if(flag&Fname)
+ while(getc(bin) != 0)
+ ;
+
+ /* comment */
+ if(flag&Fcomment)
+ while(getc(bin) != 0)
+ ;
+
+ /* crc16 */
+ if(flag&Fhcrc) {
+ getc(bin);
+ getc(bin);
+ }
+
+ return FlateOk;
+}
+
+static int
+trailer(Biobuf *bout, Biobuf *bin)
+{
+ /* crc32 */
+ ulong x;
+
+ x = get4(bin);
+ if(crc != x){
+ print("crc mismatch %lux %lux\n", crc, x);
+ return FlateCorrupted;
+ }
+
+ /* length */
+ if(get4(bin) != Boffset(bout)){
+ print("bad output len\n");
+ return FlateCorrupted;
+ }
+ return FlateOk;
+}
+
+static ulong
+get4(Biobuf *b)
+{
+ ulong v;
+ int i, c;
+
+ v = 0;
+ for(i = 0; i < 4; i++){
+ c = getc(b);
+ v |= c << (i * 8);
+ }
+ return v;
+}
+
+static int
+getc(void *in)
+{
+ Biobuf *bp = in;
+
+ if((bp->p - bp->bp) % 10000 == 0)
+ print(".");
+ if(bp->p >= bp->ep)
+ return -1;
+ return *bp->p++;
+}
+
+static ulong
+Boffset(Biobuf *bp)
+{
+ return bp->p - bp->bp;
+}
+
+static int
+crcwrite(void *out, void *buf, int n)
+{
+ Biobuf *bp;
+
+ crc = blockcrc(crctab, crc, buf, n);
+ bp = out;
+ if(n > bp->ep-bp->p)
+ n = bp->ep-bp->p;
+ memmove(bp->p, buf, n);
+ bp->p += n;
+ return n;
+}
+
+#undef malloc
+#undef free
+
+static ulong ibrkp = ~0;
+
+void *
+malloc(ulong n)
+{
+ ulong rv;
+
+ if(ibrkp == ~0)
+ ibrkp = ((ulong)end)+1024*1024;
+ n = (n+3)>>2;
+ n <<= 2;
+ rv = ibrkp;
+ ibrkp += n;
+ return (void*)rv;
+}
+
+void
+free(void *)
+{
+}
--- /dev/null
+++ b/os/boot/bitsy/io.h
@@ -1,0 +1,261 @@
+/*
+ * Definitions for IO devices. Used only in C.
+ */
+
+enum
+{
+ /* hardware counter frequency */
+ ClockFreq= 3686400,
+};
+
+/*
+ * IRQ's defined by SA1100
+ */
+enum
+{
+ IRQgpio0= 0,
+ IRQgpio1= 1,
+ IRQgpio2= 2,
+ IRQgpio3= 3,
+ IRQgpio4= 4,
+ IRQgpio5= 5,
+ IRQgpio6= 6,
+ IRQgpio7= 7,
+ IRQgpio8= 8,
+ IRQgpio9= 9,
+ IRQgpio10= 10,
+ IRQgpiohi= 11,
+ IRQlcd= 12,
+ IRQudc= 13,
+ IRQuart1b= 15,
+ IRQuart2= 16,
+ IRQuart3= 17,
+ IRQmcp= 18,
+ IRQssp= 19,
+ IRQdma0= 20,
+ IRQdma1= 21,
+ IRQdma2= 22,
+ IRQdma3= 23,
+ IRQdma4= 24,
+ IRQdma5= 25,
+ IRQtimer0= 26,
+ IRQtimer1= 27,
+ IRQtimer2= 28,
+ IRQtimer3= 29,
+ IRQsecond= 30,
+ IRQrtc= 31,
+};
+
+/*
+ * GPIO lines (signal names from compaq document). _i indicates input
+ * and _o output.
+ */
+enum
+{
+ GPIO_PWR_ON_i= 1<<0, /* power button */
+ GPIO_UP_IRQ_i= 1<<1, /* microcontroller interrupts */
+ GPIO_LDD8_o= 1<<2, /* LCD data 8-15 */
+ GPIO_LDD9_o= 1<<3,
+ GPIO_LDD10_o= 1<<4,
+ GPIO_LDD11_o= 1<<5,
+ GPIO_LDD12_o= 1<<6,
+ GPIO_LDD13_o= 1<<7,
+ GPIO_LDD14_o= 1<<8,
+ GPIO_LDD15_o= 1<<9,
+ GPIO_CARD_IND1_i= 1<<10, /* card inserted in PCMCIA socket 1 */
+ GPIO_CARD_IRQ1_i= 1<<11, /* PCMCIA socket 1 interrupt */
+ GPIO_CLK_SET0_o= 1<<12, /* clock selects for audio codec */
+ GPIO_CLK_SET1_o= 1<<13,
+ GPIO_L3_SDA_io= 1<<14, /* UDA1341 interface */
+ GPIO_L3_MODE_o= 1<<15,
+ GPIO_L3_SCLK_o= 1<<16,
+ GPIO_CARD_IND0_i= 1<<17, /* card inserted in PCMCIA socket 0 */
+ GPIO_KEY_ACT_i= 1<<18, /* hot key from cradle */
+ GPIO_SYS_CLK_i= 1<<19, /* clock from codec */
+ GPIO_BAT_FAULT_i= 1<<20, /* battery fault */
+ GPIO_CARD_IRQ0_i= 1<<21, /* PCMCIA socket 0 interrupt */
+ GPIO_LOCK_i= 1<<22, /* expansion pack lock/unlock */
+ GPIO_COM_DCD_i= 1<<23, /* DCD from UART3 */
+ GPIO_OPT_IRQ_i= 1<<24, /* expansion pack IRQ */
+ GPIO_COM_CTS_i= 1<<25, /* CTS from UART3 */
+ GPIO_COM_RTS_o= 1<<26, /* RTS to UART3 */
+ GPIO_OPT_IND_i= 1<<27, /* expansion pack inserted */
+
+/* Peripheral Unit GPIO pin assignments: alternate functions */
+ GPIO_SSP_TXD_o= 1<<10, /* SSP Transmit Data */
+ GPIO_SSP_RXD_i= 1<<11, /* SSP Receive Data */
+ GPIO_SSP_SCLK_o= 1<<12, /* SSP Sample CLocK */
+ GPIO_SSP_SFRM_o= 1<<13, /* SSP Sample FRaMe */
+ /* ser. port 1: */
+ GPIO_UART_TXD_o= 1<<14, /* UART Transmit Data */
+ GPIO_UART_RXD_i= 1<<15, /* UART Receive Data */
+ GPIO_SDLC_SCLK_io= 1<<16, /* SDLC Sample CLocK (I/O) */
+ GPIO_SDLC_AAF_o= 1<<17, /* SDLC Abort After Frame */
+ GPIO_UART_SCLK1_i= 1<<18, /* UART Sample CLocK 1 */
+ /* ser. port 4: */
+ GPIO_SSP_CLK_i= 1<<19, /* SSP external CLocK */
+ /* ser. port 3: */
+ GPIO_UART_SCLK3_i= 1<<20, /* UART Sample CLocK 3 */
+ /* ser. port 4: */
+ GPIO_MCP_CLK_i= 1<<21, /* MCP CLocK */
+ /* test controller: */
+ GPIO_TIC_ACK_o= 1<<21, /* TIC ACKnowledge */
+ GPIO_MBGNT_o= 1<<21, /* Memory Bus GraNT */
+ GPIO_TREQA_i= 1<<22, /* TIC REQuest A */
+ GPIO_MBREQ_i= 1<<22, /* Memory Bus REQuest */
+ GPIO_TREQB_i= 1<<23, /* TIC REQuest B */
+ GPIO_1Hz_o= 1<<25, /* 1 Hz clock */
+ GPIO_RCLK_o= 1<<26, /* internal (R) CLocK (O, fcpu/2) */
+ GPIO_32_768kHz_o= 1<<27, /* 32.768 kHz clock (O, RTC) */
+};
+
+/*
+ * types of interrupts
+ */
+enum
+{
+ GPIOrising,
+ GPIOfalling,
+ GPIOboth,
+ IRQ,
+};
+
+/* hardware registers */
+typedef struct Uartregs Uartregs;
+struct Uartregs
+{
+ ulong ctl[4];
+ ulong dummya;
+ ulong data;
+ ulong dummyb;
+ ulong status[2];
+};
+Uartregs *uart3regs;
+
+/* general purpose I/O lines control registers */
+typedef struct GPIOregs GPIOregs;
+struct GPIOregs
+{
+ ulong level; /* 1 == high */
+ ulong direction; /* 1 == output */
+ ulong set; /* a 1 sets the bit, 0 leaves it alone */
+ ulong clear; /* a 1 clears the bit, 0 leaves it alone */
+ ulong rising; /* rising edge detect enable */
+ ulong falling; /* falling edge detect enable */
+ ulong edgestatus; /* writing a 1 bit clears */
+ ulong altfunc; /* turn on alternate function for any set bits */
+};
+
+extern GPIOregs *gpioregs;
+
+/* extra general purpose I/O bits, output only */
+enum
+{
+ EGPIO_prog_flash= 1<<0,
+ EGPIO_pcmcia_reset= 1<<1,
+ EGPIO_exppack_reset= 1<<2,
+ EGPIO_codec_reset= 1<<3,
+ EGPIO_exp_nvram_power= 1<<4,
+ EGPIO_exp_full_power= 1<<5,
+ EGPIO_lcd_3v= 1<<6,
+ EGPIO_rs232_power= 1<<7,
+ EGPIO_lcd_ic_power= 1<<8,
+ EGPIO_ir_power= 1<<9,
+ EGPIO_audio_power= 1<<10,
+ EGPIO_audio_ic_power= 1<<11,
+ EGPIO_audio_mute= 1<<12,
+ EGPIO_fir= 1<<13, /* not set is sir */
+ EGPIO_lcd_5v= 1<<14,
+ EGPIO_lcd_9v= 1<<15,
+};
+extern ulong *egpioreg;
+
+/* Peripheral pin controller registers */
+typedef struct PPCregs PPCregs;
+struct PPCregs {
+ ulong direction;
+ ulong state;
+ ulong assignment;
+ ulong sleepdir;
+ ulong flags;
+};
+extern PPCregs *ppcregs;
+
+/* Synchronous Serial Port controller registers */
+typedef struct SSPregs SSPregs;
+struct SSPregs {
+ ulong control0;
+ ulong control1;
+ ulong dummy0;
+ ulong data;
+ ulong dummy1;
+ ulong status;
+};
+extern SSPregs *sspregs;
+
+/* Multimedia Communications Port controller registers */
+typedef struct MCPregs MCPregs;
+struct MCPregs {
+ ulong control0;
+ ulong reserved0;
+ ulong data0;
+ ulong data1;
+ ulong data2;
+ ulong reserved1;
+ ulong status;
+ ulong reserved[11];
+ ulong control1;
+};
+extern MCPregs *mcpregs;
+
+/*
+ * memory configuration
+ */
+enum
+{
+ /* bit shifts for pcmcia access time counters */
+ MECR_io0= 0,
+ MECR_attr0= 5,
+ MECR_mem0= 10,
+ MECR_fast0= 11,
+ MECR_io1= MECR_io0+16,
+ MECR_attr1= MECR_attr0+16,
+ MECR_mem1= MECR_mem0+16,
+ MECR_fast1= MECR_fast0+16,
+};
+
+typedef struct MemConfRegs MemConfRegs;
+struct MemConfRegs
+{
+ ulong mdcnfg; /* dram */
+ ulong mdcas00; /* dram banks 0/1 */
+ ulong mdcas01;
+ ulong mdcas02;
+ ulong msc0; /* static */
+ ulong msc1;
+ ulong mecr; /* pcmcia */
+ ulong mdrefr; /* dram refresh */
+ ulong mdcas20; /* dram banks 2/3 */
+ ulong mdcas21;
+ ulong mdcas22;
+ ulong msc2; /* static */
+ ulong smcnfg; /* SMROM config */
+};
+extern MemConfRegs *memconfregs;
+
+/*
+ * power management
+ */
+typedef struct PowerRegs PowerRegs;
+struct PowerRegs
+{
+ ulong pmcr; /* Power manager control register */
+ ulong pssr; /* Power manager sleep status register */
+ ulong pspr; /* Power manager scratch pad register */
+ ulong pwer; /* Power manager wakeup enable register */
+ ulong pcfr; /* Power manager general configuration register */
+ ulong ppcr; /* Power manager PPL configuration register */
+ ulong pgsr; /* Power manager GPIO sleep state register */
+ ulong posr; /* Power manager oscillator status register */
+};
+extern PowerRegs *powerregs;
--- /dev/null
+++ b/os/boot/bitsy/l.s
@@ -1,0 +1,454 @@
+#include "mem.h"
+
+/*
+ * Entered here from Compaq's bootldr with MMU disabled.
+ */
+TEXT _start(SB), $-4
+ MOVW $setR12(SB), R12 /* load the SB */
+_main:
+ /* SVC mode, interrupts disabled */
+ MOVW $(PsrDirq|PsrDfiq|PsrMsvc), R1
+ MOVW R1, CPSR
+
+ /* disable the MMU */
+ MOVW $0x130, R1
+ MCR CpMMU, 0, R1, C(CpControl), C(0x0)
+
+ /* flush caches */
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0
+ /* drain prefetch */
+ MOVW R0,R0
+ MOVW R0,R0
+ MOVW R0,R0
+ MOVW R0,R0
+
+ /* drain write buffer */
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
+
+ MOVW $(MACHADDR+BY2PG), R13 /* stack */
+ SUB $4, R13 /* link */
+ BL main(SB)
+ BL exit(SB)
+ /* we shouldn't get here */
+_mainloop:
+ B _mainloop
+ BL _div(SB) /* hack to get _div etc loaded */
+
+/* flush tlb's */
+TEXT mmuinvalidate(SB), $-4
+ MCR CpMMU, 0, R0, C(CpTLBFlush), C(0x7)
+ RET
+
+/* flush tlb's */
+TEXT mmuinvalidateaddr(SB), $-4
+ MCR CpMMU, 0, R0, C(CpTLBFlush), C(0x6), 1
+ RET
+
+/* write back and invalidate i and d caches */
+TEXT cacheflush(SB), $-4
+ /* write back any dirty data */
+ MOVW $0xe0000000,R0
+ ADD $(8*1024),R0,R1
+_cfloop:
+ MOVW.P 32(R0),R2
+ CMP.S R0,R1
+ BNE _cfloop
+
+ /* drain write buffer and invalidate i&d cache contents */
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x7), 0
+
+ /* drain prefetch */
+ MOVW R0,R0
+ MOVW R0,R0
+ MOVW R0,R0
+ MOVW R0,R0
+ RET
+
+/* write back d cache */
+TEXT cachewb(SB), $-4
+ /* write back any dirty data */
+_cachewb:
+ MOVW $0xe0000000,R0
+ ADD $(8*1024),R0,R1
+_cwbloop:
+ MOVW.P 32(R0),R2
+ CMP.S R0,R1
+ BNE _cwbloop
+
+ /* drain write buffer */
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
+ RET
+
+/* write back a single cache line */
+TEXT cachewbaddr(SB), $-4
+ BIC $31,R0
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 1
+ B _wbflush
+
+/* write back a region of cache lines */
+TEXT cachewbregion(SB), $-4
+ MOVW 4(FP),R1
+ CMP.S $(4*1024),R1
+ BGT _cachewb
+ ADD R0,R1
+ BIC $31,R0
+_cwbrloop:
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 1
+ ADD $32,R0
+ CMP.S R0,R1
+ BGT _cwbrloop
+ B _wbflush
+
+/* invalidate the dcache */
+TEXT dcacheinvalidate(SB), $-4
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x6)
+ RET
+
+/* invalidate the icache */
+TEXT icacheinvalidate(SB), $-4
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0x9)
+ RET
+
+/* drain write buffer */
+TEXT wbflush(SB), $-4
+_wbflush:
+ MCR CpMMU, 0, R0, C(CpCacheFlush), C(0xa), 4
+ RET
+
+/* return cpu id */
+TEXT getcpuid(SB), $-4
+ MRC CpMMU, 0, R0, C(CpCPUID), C(0x0)
+ RET
+
+/* return fault status */
+TEXT getfsr(SB), $-4
+ MRC CpMMU, 0, R0, C(CpFSR), C(0x0)
+ RET
+
+/* return fault address */
+TEXT getfar(SB), $-4
+ MRC CpMMU, 0, R0, C(CpFAR), C(0x0)
+ RET
+
+/* return fault address */
+TEXT putfar(SB), $-4
+ MRC CpMMU, 0, R0, C(CpFAR), C(0x0)
+ RET
+
+/* set the translation table base */
+TEXT putttb(SB), $-4
+ MCR CpMMU, 0, R0, C(CpTTB), C(0x0)
+ RET
+
+/*
+ * enable mmu, i and d caches
+ */
+TEXT mmuenable(SB), $-4
+ MRC CpMMU, 0, R0, C(CpControl), C(0x0)
+ ORR $(CpCmmuena|CpCdcache|CpCicache|CpCwb), R0
+ MCR CpMMU, 0, R0, C(CpControl), C(0x0)
+ RET
+
+TEXT mmudisable(SB), $-4
+ MRC CpMMU, 0, R0, C(CpControl), C(0x0)
+ BIC $(CpCmmuena|CpCdcache|CpCicache|CpCwb|CpCvivec), R0
+ MCR CpMMU, 0, R0, C(CpControl), C(0x0)
+ RET
+
+/*
+ * use exception vectors at 0xffff0000
+ */
+TEXT mappedIvecEnable(SB), $-4
+ MRC CpMMU, 0, R0, C(CpControl), C(0x0)
+ ORR $(CpCvivec), R0
+ MCR CpMMU, 0, R0, C(CpControl), C(0x0)
+ RET
+TEXT mappedIvecDisable(SB), $-4
+ MRC CpMMU, 0, R0, C(CpControl), C(0x0)
+ BIC $(CpCvivec), R0
+ MCR CpMMU, 0, R0, C(CpControl), C(0x0)
+ RET
+
+/* set the translation table base */
+TEXT putdac(SB), $-4
+ MCR CpMMU, 0, R0, C(CpDAC), C(0x0)
+ RET
+
+/* set address translation pid */
+TEXT putpid(SB), $-4
+ MCR CpMMU, 0, R0, C(CpPID), C(0x0)
+ RET
+
+/*
+ * set the stack value for the mode passed in R0
+ */
+TEXT setr13(SB), $-4
+ MOVW 4(FP), R1
+
+ MOVW CPSR, R2
+ BIC $PsrMask, R2, R3
+ ORR R0, R3
+ MOVW R3, CPSR
+
+ MOVW R13, R0
+ MOVW R1, R13
+
+ MOVW R2, CPSR
+ RET
+
+/*
+ * exception vectors, copied by trapinit() to somewhere useful
+ */
+
+TEXT vectors(SB), $-4
+ MOVW 0x18(R15), R15 /* reset */
+ MOVW 0x18(R15), R15 /* undefined */
+ MOVW 0x18(R15), R15 /* SWI */
+ MOVW 0x18(R15), R15 /* prefetch abort */
+ MOVW 0x18(R15), R15 /* data abort */
+ MOVW 0x18(R15), R15 /* reserved */
+ MOVW 0x18(R15), R15 /* IRQ */
+ MOVW 0x18(R15), R15 /* FIQ */
+
+TEXT vtable(SB), $-4
+ WORD $_vsvc(SB) /* reset, in svc mode already */
+ WORD $_vund(SB) /* undefined, switch to svc mode */
+ WORD $_vsvc(SB) /* swi, in svc mode already */
+ WORD $_vpabt(SB) /* prefetch abort, switch to svc mode */
+ WORD $_vdabt(SB) /* data abort, switch to svc mode */
+ WORD $_vsvc(SB) /* reserved */
+ WORD $_virq(SB) /* IRQ, switch to svc mode */
+ WORD $_vfiq(SB) /* FIQ, switch to svc mode */
+
+TEXT _vrst(SB), $-4
+ BL resettrap(SB)
+
+TEXT _vsvc(SB), $-4 /* SWI */
+ MOVW.W R14, -4(R13) /* ureg->pc = interupted PC */
+ MOVW SPSR, R14 /* ureg->psr = SPSR */
+ MOVW.W R14, -4(R13) /* ... */
+ MOVW $PsrMsvc, R14 /* ureg->type = PsrMsvc */
+ MOVW.W R14, -4(R13) /* ... */
+ MOVM.DB.W.S [R0-R14], (R13) /* save user level registers, at end r13 points to ureg */
+ MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */
+ MOVW R13, R0 /* first arg is pointer to ureg */
+ SUB $8, R13 /* space for argument+link */
+
+ BL syscall(SB)
+
+ ADD $(8+4*15), R13 /* make r13 point to ureg->type */
+ MOVW 8(R13), R14 /* restore link */
+ MOVW 4(R13), R0 /* restore SPSR */
+ MOVW R0, SPSR /* ... */
+ MOVM.DB.S (R13), [R0-R14] /* restore registers */
+ ADD $8, R13 /* pop past ureg->{type+psr} */
+ RFE /* MOVM.IA.S.W (R13), [R15] */
+
+TEXT _vund(SB), $-4 /* undefined */
+ MOVM.IA [R0-R4], (R13) /* free some working space */
+ MOVW $PsrMund, R0
+ B _vswitch
+
+TEXT _vpabt(SB), $-4 /* prefetch abort */
+ MOVM.IA [R0-R4], (R13) /* free some working space */
+ MOVW $PsrMabt, R0 /* r0 = type */
+ B _vswitch
+
+TEXT _vdabt(SB), $-4 /* prefetch abort */
+ MOVM.IA [R0-R4], (R13) /* free some working space */
+ MOVW $(PsrMabt+1), R0 /* r0 = type */
+ B _vswitch
+
+TEXT _virq(SB), $-4 /* IRQ */
+ MOVM.IA [R0-R4], (R13) /* free some working space */
+ MOVW $PsrMirq, R0 /* r0 = type */
+ B _vswitch
+
+ /*
+ * come here with type in R0 and R13 pointing above saved [r0-r4]
+ * and type in r0. we'll switch to SVC mode and then call trap.
+ */
+_vswitch:
+ MOVW SPSR, R1 /* save SPSR for ureg */
+ MOVW R14, R2 /* save interrupted pc for ureg */
+ MOVW R13, R3 /* save pointer to where the original [R0-R3] are */
+
+ /* switch to svc mode */
+ MOVW CPSR, R14
+ BIC $PsrMask, R14
+ ORR $(PsrDirq|PsrDfiq|PsrMsvc), R14
+ MOVW R14, CPSR
+
+ /* interupted code kernel or user? */
+ AND.S $0xf, R1, R4
+ BEQ _userexcep
+
+ /* here for trap from SVC mode */
+ MOVM.DB.W [R0-R2], (R13) /* set ureg->{type, psr, pc}; r13 points to ureg->type */
+ MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */
+ MOVM.DB.W [R0-R14], (R13) /* save kernel level registers, at end r13 points to ureg */
+ MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */
+ MOVW R13, R0 /* first arg is pointer to ureg */
+ SUB $8, R13 /* space for argument+link (for debugger) */
+ MOVW $0xdeaddead,R11 /* marker */
+
+ BL trap(SB)
+
+ ADD $(8+4*15), R13 /* make r13 point to ureg->type */
+ MOVW 8(R13), R14 /* restore link */
+ MOVW 4(R13), R0 /* restore SPSR */
+ MOVW R0, SPSR /* ... */
+ MOVM.DB (R13), [R0-R14] /* restore registers */
+ ADD $8, R13 /* pop past ureg->{type+psr} */
+ RFE /* MOVM.IA.S.W (R13), [R15] */
+
+ /* here for trap from USER mode */
+_userexcep:
+ MOVM.DB.W [R0-R2], (R13) /* set ureg->{type, psr, pc}; r13 points to ureg->type */
+ MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */
+ MOVM.DB.W.S [R0-R14], (R13) /* save kernel level registers, at end r13 points to ureg */
+ MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */
+ MOVW R13, R0 /* first arg is pointer to ureg */
+ SUB $8, R13 /* space for argument+link (for debugger) */
+
+ BL trap(SB)
+
+ ADD $(8+4*15), R13 /* make r13 point to ureg->type */
+ MOVW 8(R13), R14 /* restore link */
+ MOVW 4(R13), R0 /* restore SPSR */
+ MOVW R0, SPSR /* ... */
+ MOVM.DB.S (R13), [R0-R14] /* restore registers */
+ ADD $8, R13 /* pop past ureg->{type+psr} */
+ RFE /* MOVM.IA.S.W (R13), [R15] */
+
+TEXT _vfiq(SB), $-4 /* FIQ */
+ RFE /* FIQ is special, ignore it for now */
+
+/*
+ * This is the first jump from kernel to user mode.
+ * Fake a return from interrupt.
+ *
+ * Enter with R0 containing the user stack pointer.
+ * UTZERO + 0x20 is always the entry point.
+ *
+ */
+TEXT touser(SB),$-4
+ /* store the user stack pointer into the USR_r13 */
+ MOVM.DB.W [R0], (R13)
+ MOVM.S.IA.W (R13),[R13]
+
+ /* set up a PSR for user level */
+ MOVW $(PsrMusr), R0
+ MOVW R0,SPSR
+
+ /* save the PC on the stack */
+ MOVW $(UTZERO+0x20), R0
+ MOVM.DB.W [R0],(R13)
+
+ /* return from interrupt */
+ RFE /* MOVM.IA.S.W (R13), [R15] */
+
+/*
+ * here to jump to a newly forked process
+ */
+TEXT forkret(SB),$-4
+ ADD $(4*15), R13 /* make r13 point to ureg->type */
+ MOVW 8(R13), R14 /* restore link */
+ MOVW 4(R13), R0 /* restore SPSR */
+ MOVW R0, SPSR /* ... */
+ MOVM.DB.S (R13), [R0-R14] /* restore registers */
+ ADD $8, R13 /* pop past ureg->{type+psr} */
+ RFE /* MOVM.IA.S.W (R13), [R15] */
+
+TEXT splhi(SB), $-4
+ /* save caller pc in Mach */
+ MOVW $(MACHADDR+0x04),R2
+ MOVW R14,0(R2)
+ /* turn off interrupts */
+ MOVW CPSR, R0
+ ORR $(PsrDfiq|PsrDirq), R0, R1
+ MOVW R1, CPSR
+ RET
+
+TEXT spllo(SB), $-4
+ MOVW CPSR, R0
+ BIC $(PsrDfiq|PsrDirq), R0, R1
+ MOVW R1, CPSR
+ RET
+
+TEXT splx(SB), $-4
+ /* save caller pc in Mach */
+ MOVW $(MACHADDR+0x04),R2
+ MOVW R14,0(R2)
+ /* reset interrupt level */
+ MOVW R0, R1
+ MOVW CPSR, R0
+ MOVW R1, CPSR
+ RET
+
+TEXT splxpc(SB), $-4 /* for iunlock */
+ MOVW R0, R1
+ MOVW CPSR, R0
+ MOVW R1, CPSR
+ RET
+
+TEXT spldone(SB), $0
+ RET
+
+TEXT islo(SB), $-4
+ MOVW CPSR, R0
+ AND $(PsrDfiq|PsrDirq), R0
+ EOR $(PsrDfiq|PsrDirq), R0
+ RET
+
+TEXT cpsrr(SB), $-4
+ MOVW CPSR, R0
+ RET
+
+TEXT spsrr(SB), $-4
+ MOVW SPSR, R0
+ RET
+
+TEXT getcallerpc(SB), $-4
+ MOVW 0(R13), R0
+ RET
+
+TEXT tas(SB), $-4
+ MOVW R0, R1
+ MOVW $0xDEADDEAD, R2
+ SWPW R2, (R1), R0
+ RET
+
+TEXT setlabel(SB), $-4
+ MOVW R13, 0(R0) /* sp */
+ MOVW R14, 4(R0) /* pc */
+ MOVW $0, R0
+ RET
+
+TEXT gotolabel(SB), $-4
+ MOVW 0(R0), R13 /* sp */
+ MOVW 4(R0), R14 /* pc */
+ MOVW $1, R0
+ RET
+
+
+/* The first MCR instruction of this function needs to be on a cache-line
+ * boundary; to make this happen, it will be copied (in trap.c).
+ *
+ * Doze puts the machine into idle mode. Any interrupt will get it out
+ * at the next instruction (the RET, to be precise).
+ */
+TEXT _doze(SB), $-4
+ MOVW $UCDRAMZERO, R1
+ MOVW R0,R0
+ MOVW R0,R0
+ MOVW R0,R0
+ MOVW R0,R0
+ MOVW R0,R0
+ MOVW R0,R0
+ MOVW R0,R0
+ MCR CpPWR, 0, R0, C(CpTest), C(0x2), 2
+ MOVW (R1), R0
+ MCR CpPWR, 0, R0, C(CpTest), C(0x8), 2
+ RET
--- /dev/null
+++ b/os/boot/bitsy/lib.h
@@ -1,0 +1,143 @@
+/*
+ * 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 char *strrchr(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* strstr(char*, char*);
+extern int atoi(char*);
+
+enum
+{
+ UTFmax = 3, /* maximum bytes per rune */
+ Runesync = 0x80, /* cannot represent part of a UTF sequence */
+ Runeself = 0x80, /* rune and UTF sequences are the same (<) */
+ Runeerror = 0x80, /* decoding error in UTF */
+};
+
+/*
+ * rune routines
+ */
+extern int runetochar(char*, Rune*);
+extern int chartorune(Rune*, char*);
+extern char* utfrune(char*, long);
+extern int utflen(char*);
+extern int runelen(long);
+
+extern int abs(int);
+
+/*
+ * print routines
+ */
+typedef struct Cconv Fconv;
+extern char* donprint(char*, char*, char*, void*);
+extern int sprint(char*, char*, ...);
+extern char* seprint(char*, char*, char*, ...);
+extern int snprint(char*, int, char*, ...);
+extern int print(char*, ...);
+
+/*
+ * one-of-a-kind
+ */
+extern char* cleanname(char*);
+extern uintptr getcallerpc(void*);
+extern long strtol(char*, char**, int);
+extern ulong strtoul(char*, char**, int);
+extern vlong strtoll(char*, char**, int);
+extern uvlong strtoull(char*, char**, int);
+extern char etext[];
+extern char edata[];
+extern char end[];
+extern int getfields(char*, char**, int, int, char*);
+
+/*
+ * 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 MCACHE 0x0010 /* cache some data */
+#define MMASK 0x001F /* 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 */
+#define NSAVE 2 /* clear note but hold state */
+#define NRSTR 3 /* restore saved state */
+
+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
+{
+ char pid[12]; /* of loved one */
+ char time[3*12]; /* of loved one and descendants */
+ char msg[ERRLEN];
+};
+
+/*
+ * locks
+ */
+typedef
+struct Lock {
+ int val;
+} Lock;
+
+extern int _tas(int*);
+
+extern void lock(Lock*);
+extern void unlock(Lock*);
+extern int canlock(Lock*);
--- /dev/null
+++ b/os/boot/bitsy/map
@@ -1,0 +1,10 @@
+defn acidmap()
+{
+ local dfoffset;
+
+ dfoffset = map()[1][3];
+ map({"text", _start, etext, 0x20});
+ map({"data", etext+1, edata, dfoffset});
+ print("Set map for plan 9 kernel image\n");
+ print("btext ", _start, " etext ", etext, "\n");
+}
--- /dev/null
+++ b/os/boot/bitsy/mem.h
@@ -1,0 +1,213 @@
+/*
+ * 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 BY2V 8 /* bytes per double word */
+#define BY2PG 4096 /* bytes per page */
+#define WD2PG (BY2PG/BY2WD) /* words per page */
+#define PGSHIFT 12 /* log(BY2PG) */
+#define ROUND(s, sz) (((s)+(sz-1))&~(sz-1))
+#define PGROUND(s) ROUND(s, BY2PG)
+#define BLOCKALIGN 8
+
+#define MAXMACH 1 /* max # cpus system can run */
+
+/*
+ * Time
+ */
+#define HZ (20) /* 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 */
+
+/*
+ * Virtual addresses:
+ *
+ * We direct map all discovered DRAM and the area twixt 0xe0000000 and
+ * 0xe8000000 used to provide zeros for cache flushing.
+ *
+ * Flash is mapped to 0xb0000000 and special registers are mapped
+ * on demand to areas starting at 0xa0000000.
+ *
+ * The direct mapping is convenient but not necessary. It means
+ * that we don't have to turn on the MMU till well into the
+ * kernel. This can be changed by providing a mapping in l.s
+ * before calling main.
+ */
+#define UZERO 0 /* base of user address space */
+#define UTZERO (UZERO+BY2PG) /* first address in user text */
+#define KZERO 0xC0000000 /* base of kernel address space */
+#define KTZERO 0xC0008000 /* first address in kernel text */
+#define EMEMZERO 0x90000000 /* 256 meg for add on memory */
+#define EMEMTOP 0xA0000000 /* ... */
+#define REGZERO 0xA0000000 /* 128 meg for mapspecial regs */
+#define REGTOP 0xA8000000 /* ... */
+#define FLASHZERO 0xB0000000 /* 128 meg for flash */
+#define FLASHTOP 0xB8000000 /* ... */
+#define DRAMZERO 0xC0000000 /* 128 meg for dram */
+#define DRAMTOP 0xC8000000 /* ... */
+#define UCDRAMZERO 0xC8000000 /* 128 meg for dram (uncached/unbuffered) */
+#define UCDRAMTOP 0xD0000000 /* ... */
+#define NULLZERO 0xE0000000 /* 128 meg for cache flush zeroes */
+#define NULLTOP 0xE8000000 /* ... */
+#define USTKTOP 0x2000000 /* byte just beyond user stack */
+#define USTKSIZE (8*1024*1024) /* size of user stack */
+#define TSTKTOP (USTKTOP-USTKSIZE) /* end of new stack in sysexec */
+#define TSTKSIZ 100
+#define MACHADDR (KZERO+0x00001000)
+#define EVECTORS 0xFFFF0000 /* virt base of exception vectors */
+
+#define KSTACK (16*1024) /* Size of kernel stack */
+
+/*
+ * Offsets into flash
+ */
+#define Flash_bootldr (FLASHZERO+0x0) /* boot loader */
+#define Flash_kernel (FLASHZERO+0x10000) /* boot kernel */
+#define Flash_tar (FLASHZERO+0x100000) /* tar file containing fs.sac */
+
+/*
+ * virtual MMU
+ */
+#define PTEMAPMEM (1024*1024)
+#define PTEPERTAB (PTEMAPMEM/BY2PG)
+#define SEGMAPSIZE 1984
+#define SSEGMAPSIZE 16
+#define PPN(x) ((x)&~(BY2PG-1))
+
+/*
+ * SA1110 definitions
+ */
+
+/*
+ * memory physical addresses
+ */
+#define PHYSFLASH0 0x00000000
+#define PHYSDRAM0 0xC0000000
+#define PHYSNULL0 0xE0000000
+
+/*
+ * peripheral control module physical addresses
+ */
+#define USBREGS 0x80000000 /* serial port 0 - USB */
+#define UART1REGS 0x80010000 /* serial port 1 - UART */
+#define GPCLKREGS 0x80020060 /* serial port 1 - general purpose clock */
+#define UART2REGS 0x80030000 /* serial port 2 - low speed IR */
+#define HSSPREGS 0x80040060 /* serial port 2 - high speed IR */
+#define UART3REGS 0x80050000 /* serial port 3 - RS232 UART */
+#define MCPREGS 0x80060000 /* serial port 4 - multimedia comm port */
+#define SSPREGS 0x80070060 /* serial port 4 - synchronous serial port */
+#define OSTIMERREGS 0x90000000 /* operating system timer registers */
+#define POWERREGS 0x90020000 /* power management */
+#define GPIOREGS 0x90040000 /* 28 general purpose IO pins */
+#define INTRREGS 0x90050000 /* interrupt registers */
+#define PPCREGS 0x90060000 /* peripheral pin controller */
+#define MEMCONFREGS 0xA0000000 /* memory configuration */
+#define LCDREGS 0xB0100000 /* display */
+
+/*
+ * PCMCIA addresses
+ */
+#define PHYSPCM0REGS 0x20000000
+#define PYHSPCM0ATTR 0x28000000
+#define PYHSPCM0MEM 0x2C000000
+#define PHYSPCM1REGS 0x30000000
+#define PYHSPCM1ATTR 0x38000000
+#define PYHSPCM1MEM 0x3C000000
+
+/*
+ * Program Status Registers
+ */
+#define PsrMusr 0x00000010 /* mode */
+#define PsrMfiq 0x00000011
+#define PsrMirq 0x00000012
+#define PsrMsvc 0x00000013
+#define PsrMabt 0x00000017
+#define PsrMund 0x0000001B
+#define PsrMask 0x0000001F
+
+#define PsrDfiq 0x00000040 /* disable FIQ interrupts */
+#define PsrDirq 0x00000080 /* disable IRQ interrupts */
+
+#define PsrV 0x10000000 /* overflow */
+#define PsrC 0x20000000 /* carry/borrow/extend */
+#define PsrZ 0x40000000 /* zero */
+#define PsrN 0x80000000 /* negative/less than */
+
+/*
+ * Coprocessors
+ */
+#define CpMMU 15
+#define CpPWR 15
+
+/*
+ * Internal MMU coprocessor registers
+ */
+#define CpCPUID 0 /* R: */
+#define CpControl 1 /* R: */
+#define CpTTB 2 /* RW: translation table base */
+#define CpDAC 3 /* RW: domain access control */
+#define CpFSR 5 /* RW: fault status */
+#define CpFAR 6 /* RW: fault address */
+#define CpCacheFlush 7 /* W: cache flushing, wb draining*/
+#define CpTLBFlush 8 /* W: TLB flushing */
+#define CpRBFlush 9 /* W: Read Buffer ops */
+#define CpPID 13 /* RW: PID for virtual mapping */
+#define CpBpt 14 /* W: Breakpoint register */
+#define CpTest 15 /* W: Test, Clock and Idle Control */
+
+/*
+ * CpControl
+ */
+#define CpCmmuena 0x00000001 /* M: MMU enable */
+#define CpCalign 0x00000002 /* A: alignment fault enable */
+#define CpCdcache 0x00000004 /* C: data cache on */
+#define CpCwb 0x00000008 /* W: write buffer turned on */
+#define CpCi32 0x00000010 /* P: 32-bit program space */
+#define CpCd32 0x00000020 /* D: 32-bit data space */
+#define CpCbe 0x00000080 /* B: big-endian operation */
+#define CpCsystem 0x00000100 /* S: system permission */
+#define CpCrom 0x00000200 /* R: ROM permission */
+#define CpCicache 0x00001000 /* I: instruction cache on */
+#define CpCvivec 0x00002000 /* X: virtual interrupt vector adjust */
+
+/*
+ * fault codes
+ */
+#define FCterm 0x2 /* terminal */
+#define FCvec 0x0 /* vector */
+#define FCalignf 0x1 /* unaligned full word data access */
+#define FCalignh 0x3 /* unaligned half word data access */
+#define FCl1abort 0xc /* level 1 external abort on translation */
+#define FCl2abort 0xe /* level 2 external abort on translation */
+#define FCtransSec 0x5 /* section translation */
+#define FCtransPage 0x7 /* page translation */
+#define FCdomainSec 0x9 /* section domain */
+#define FCdomainPage 0x11 /* page domain */
+#define FCpermSec 0x9 /* section permissions */
+#define FCpermPage 0x11 /* page permissions */
+#define FCabortLFSec 0x4 /* external abort on linefetch for section */
+#define FCabortLFPage 0x6 /* external abort on linefetch for page */
+#define FCabortNLFSec 0x8 /* external abort on non-linefetch for section */
+#define FCabortNLFPage 0xa /* external abort on non-linefetch for page */
+
+/*
+ * PTE bits used by fault.h. mmu.c translates them to real values.
+ */
+#define PTEVALID (1<<0)
+#define PTERONLY 0 /* this is implied by the absence of PTEWRITE */
+#define PTEWRITE (1<<1)
+#define PTEUNCACHED (1<<2)
+#define PTEKERNEL (1<<3) /* no user access */
+
+/*
+ * H3650 specific definitions
+ */
+#define EGPIOREGS 0x49000000 /* Additional GPIO register */
--- /dev/null
+++ b/os/boot/bitsy/mkfile
@@ -1,0 +1,45 @@
+objtype=arm
+</$objtype/mkfile
+BIN=/arm
+
+TARG=\
+ inflate\
+
+INFLATE=\
+ il.$O\
+ imain.$O\
+
+CORE=\
+ uart.$O\
+ inflate.$O\
+ donprint.$O\
+ print.$O\
+
+HFILES=\
+ mem.h\
+
+CFLAGS=-w -I.
+
+all:V: $TARG
+
+install:V: $BIN/$TARG
+
+$BIN/%: %
+ cp $stem $BIN/$stem
+
+inflate: $INFLATE $CORE
+ $LD -o s$target -R4 -T0xC0200010 $prereq -lflate -lc
+ $LD -o _^$target -H5 -R4 -T0xC0200010 $prereq -lflate -lc
+ dd -conv sync -ibs 20k -if _^$target -of $target
+
+%.$O: %.s
+ $AS $stem.s
+
+%.$O: %.c
+ $CC $CFLAGS $stem.c
+
+%.$O: $HFILES
+
+clean:
+ rm -f *.[$OS] [$OS].out y.tab.? y.debug y.output $TARG _$TARG
+
--- /dev/null
+++ b/os/boot/bitsy/print.c
@@ -1,0 +1,56 @@
+#include "u.h"
+#include "lib.h"
+#include "fns.h"
+#include "dat.h"
+
+
+#define SIZE 1024
+
+int
+print(char *fmt, ...)
+{
+ char buf[SIZE], *out;
+ va_list arg;
+
+ va_start(arg, fmt);
+ out = donprint(buf, buf+SIZE, fmt, arg);
+ va_end(arg);
+ serialputs(buf, out-buf);
+ return out-buf;
+}
+
+int
+sprint(char *buf, char *fmt, ...)
+{
+ char *out;
+ va_list arg;
+
+ va_start(arg, fmt);
+ out = donprint(buf, buf+SIZE, fmt, arg);
+ va_end(arg);
+ return out-buf;
+}
+
+int
+snprint(char *buf, int len, char *fmt, ...)
+{
+ char *out;
+ va_list arg;
+
+ va_start(arg, fmt);
+ out = donprint(buf, buf+len, fmt, arg);
+ va_end(arg);
+ return out-buf;
+}
+
+char*
+seprint(char *buf, char *e, char *fmt, ...)
+{
+ char *out;
+ va_list arg;
+
+ va_start(arg, fmt);
+ out = donprint(buf, e, fmt, arg);
+ va_end(arg);
+ return out;
+}
binary files /dev/null b/os/boot/bitsy/sinflate differ
--- /dev/null
+++ b/os/boot/bitsy/uart.c
@@ -1,0 +1,69 @@
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+enum
+{
+ /* ctl[0] bits */
+ Parity= 1<<0,
+ Even= 1<<1,
+ Stop2= 1<<2,
+ Bits8= 1<<3,
+ SCE= 1<<4, /* synchronous clock enable */
+ RCE= 1<<5, /* rx on falling edge of clock */
+ TCE= 1<<6, /* tx on falling edge of clock */
+
+ /* ctl[3] bits */
+ Rena= 1<<0, /* receiver enable */
+ Tena= 1<<1, /* transmitter enable */
+ Break= 1<<2, /* force TXD3 low */
+ Rintena= 1<<3, /* enable receive interrupt */
+ Tintena= 1<<4, /* enable transmitter interrupt */
+ Loopback= 1<<5, /* loop back data */
+
+ /* data bits */
+ DEparity= 1<<8, /* parity error */
+ DEframe= 1<<9, /* framing error */
+ DEoverrun= 1<<10, /* overrun error */
+
+ /* status[0] bits */
+ Tint= 1<<0, /* transmit fifo half full interrupt */
+ Rint0= 1<<1, /* receiver fifo 1/3-2/3 full */
+ Rint1= 1<<2, /* receiver fifo not empty and receiver idle */
+ Breakstart= 1<<3,
+ Breakend= 1<<4,
+ Fifoerror= 1<<5, /* fifo error */
+
+ /* status[1] bits */
+ Tbusy= 1<<0, /* transmitting */
+ Rnotempty= 1<<1, /* receive fifo not empty */
+ Tnotfull= 1<<2, /* transmit fifo not full */
+ ParityError= 1<<3,
+ FrameError= 1<<4,
+ Overrun= 1<<5,
+};
+
+Uartregs *uart3regs = (Uartregs*)UART3REGS;
+
+
+/*
+ * for iprint, just write it
+ */
+void
+serialputs(char *str, int n)
+{
+ Uartregs *ur;
+
+ ur = uart3regs;
+ while(n-- > 0){
+ /* wait for output ready */
+ while((ur->status[1] & Tnotfull) == 0)
+ ;
+ ur->data = *str++;
+ }
+ while((ur->status[1] & Tbusy))
+ ;
+}
--- /dev/null
+++ b/os/boot/efi/efi.c
@@ -1,0 +1,308 @@
+#include <u.h>
+#include "fns.h"
+#include "efi.h"
+
+UINTN MK;
+EFI_HANDLE IH;
+EFI_SYSTEM_TABLE *ST;
+
+void* (*open)(char *name);
+int (*read)(void *f, void *data, int len);
+void (*close)(void *f);
+
+void
+putc(int c)
+{
+ CHAR16 w[2];
+
+ w[0] = c;
+ w[1] = 0;
+ eficall(ST->ConOut->OutputString, ST->ConOut, w);
+}
+
+int
+getc(void)
+{
+ EFI_INPUT_KEY k;
+
+ if(eficall(ST->ConIn->ReadKeyStroke, ST->ConIn, &k))
+ return 0;
+ return k.UnicodeChar;
+}
+
+void
+usleep(int us)
+{
+ eficall(ST->BootServices->Stall, (UINTN)us);
+}
+
+void
+unload(void)
+{
+ eficall(ST->BootServices->ExitBootServices, IH, MK);
+}
+
+static void
+memconf(char **cfg)
+{
+ static uchar memtype[EfiMaxMemoryType] = {
+ [EfiReservedMemoryType] 2,
+ [EfiLoaderCode] 1,
+ [EfiLoaderData] 1,
+ [EfiBootServicesCode] 2,
+ [EfiBootServicesData] 2,
+ [EfiRuntimeServicesCode] 2,
+ [EfiRuntimeServicesData] 2,
+ [EfiConventionalMemory] 1,
+ [EfiUnusableMemory] 2,
+ [EfiACPIReclaimMemory] 3,
+ [EfiACPIMemoryNVS] 4,
+ [EfiMemoryMappedIO] 2,
+ [EfiMemoryMappedIOPortSpace] 2,
+ [EfiPalCode] 2,
+ };
+ UINTN mapsize, entsize;
+ EFI_MEMORY_DESCRIPTOR *t;
+ uchar mapbuf[96*1024], *p, m;
+ UINT32 entvers;
+ char *s;
+
+ mapsize = sizeof(mapbuf);
+ entsize = sizeof(EFI_MEMORY_DESCRIPTOR);
+ entvers = 1;
+ if(eficall(ST->BootServices->GetMemoryMap, &mapsize, mapbuf, &MK, &entsize, &entvers))
+ return;
+
+ s = *cfg;
+ for(p = mapbuf; mapsize >= entsize; p += entsize, mapsize -= entsize){
+ t = (EFI_MEMORY_DESCRIPTOR*)p;
+
+ m = 0;
+ if(t->Type < EfiMaxMemoryType)
+ m = memtype[t->Type];
+
+ if(m == 0)
+ continue;
+
+ if(s == *cfg)
+ memmove(s, "*e820=", 6), s += 6;
+ s = hexfmt(s, 1, m), *s++ = ' ';
+ s = hexfmt(s, 16, t->PhysicalStart), *s++ = ' ';
+ s = hexfmt(s, 16, t->PhysicalStart + t->NumberOfPages * 4096ULL), *s++ = ' ';
+ }
+ *s = '\0';
+ if(s > *cfg){
+ s[-1] = '\n';
+ print(*cfg);
+ *cfg = s;
+ }
+}
+
+static void
+acpiconf(char **cfg)
+{
+ static EFI_GUID ACPI_20_TABLE_GUID = {
+ 0x8868e871, 0xe4f1, 0x11d3,
+ 0xbc, 0x22, 0x00, 0x80,
+ 0xc7, 0x3c, 0x88, 0x81,
+ };
+ static EFI_GUID ACPI_10_TABLE_GUID = {
+ 0xeb9d2d30, 0x2d88, 0x11d3,
+ 0x9a, 0x16, 0x00, 0x90,
+ 0x27, 0x3f, 0xc1, 0x4d,
+ };
+ EFI_CONFIGURATION_TABLE *t;
+ uintptr pa;
+ char *s;
+ int n;
+
+ pa = 0;
+ t = ST->ConfigurationTable;
+ n = ST->NumberOfTableEntries;
+ while(--n >= 0){
+ if(memcmp(&t->VendorGuid, &ACPI_10_TABLE_GUID, sizeof(EFI_GUID)) == 0){
+ if(pa == 0)
+ pa = (uintptr)t->VendorTable;
+ } else if(memcmp(&t->VendorGuid, &ACPI_20_TABLE_GUID, sizeof(EFI_GUID)) == 0)
+ pa = (uintptr)t->VendorTable;
+ t++;
+ }
+
+ if(pa){
+ s = *cfg;
+ memmove(s, "*acpi=0x", 8), s += 8;
+ s = hexfmt(s, 0, pa), *s++ = '\n';
+ *s = '\0';
+ print(*cfg);
+ *cfg = s;
+ }
+}
+
+
+static int
+topbit(ulong mask)
+{
+ int bit = 0;
+
+ while(mask != 0){
+ mask >>= 1;
+ bit++;
+ }
+ return bit;
+}
+
+static int
+lowbit(ulong mask)
+{
+ int bit = 0;
+
+ while((mask & 1) == 0){
+ mask >>= 1;
+ bit++;
+ }
+ return bit;
+}
+
+static void
+screenconf(char **cfg)
+{
+ static EFI_GUID EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID = {
+ 0x9042a9de, 0x23dc, 0x4a38,
+ 0x96, 0xfb, 0x7a, 0xde,
+ 0xd0, 0x80, 0x51, 0x6a,
+ };
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
+ EFI_HANDLE *Handles;
+ UINTN Count;
+
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
+ ulong mr, mg, mb, mx, mc;
+ int i, bits, depth;
+ char *s;
+
+ Count = 0;
+ Handles = nil;
+ if(eficall(ST->BootServices->LocateHandleBuffer,
+ ByProtocol, &EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, nil, &Count, &Handles))
+ return;
+
+ for(i=0; i<Count; i++){
+ gop = nil;
+ if(eficall(ST->BootServices->HandleProtocol,
+ Handles[i], &EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, &gop))
+ continue;
+
+ if(gop == nil)
+ continue;
+ if((info = gop->Mode->Info) == nil)
+ continue;
+
+ switch(info->PixelFormat){
+ default:
+ continue; /* unsupported */
+
+ case PixelRedGreenBlueReserved8BitPerColor:
+ mr = 0x000000ff;
+ mg = 0x0000ff00;
+ mb = 0x00ff0000;
+ mx = 0xff000000;
+ break;
+
+ case PixelBlueGreenRedReserved8BitPerColor:
+ mb = 0x000000ff;
+ mg = 0x0000ff00;
+ mr = 0x00ff0000;
+ mx = 0xff000000;
+ break;
+
+ case PixelBitMask:
+ mr = info->PixelInformation.RedMask;
+ mg = info->PixelInformation.GreenMask;
+ mb = info->PixelInformation.BlueMask;
+ mx = info->PixelInformation.ReservedMask;
+ break;
+ }
+
+ if((depth = topbit(mr | mg | mb | mx)) == 0)
+ continue;
+
+ /* make sure we have linear framebuffer */
+ if(gop->Mode->FrameBufferBase == 0)
+ continue;
+ if(gop->Mode->FrameBufferSize == 0)
+ continue;
+
+ goto Found;
+ }
+ return;
+
+Found:
+ s = *cfg;
+ memmove(s, "*bootscreen=", 12), s += 12;
+ s = decfmt(s, 0, info->PixelsPerScanLine), *s++ = 'x';
+ s = decfmt(s, 0, info->VerticalResolution), *s++ = 'x';
+ s = decfmt(s, 0, depth), *s++ = ' ';
+
+ while(depth > 0){
+ if(depth == topbit(mr)){
+ mc = mr;
+ *s++ = 'r';
+ } else if(depth == topbit(mg)){
+ mc = mg;
+ *s++ = 'g';
+ } else if(depth == topbit(mb)){
+ mc = mb;
+ *s++ = 'b';
+ } else if(depth == topbit(mx)){
+ mc = mx;
+ *s++ = 'x';
+ } else {
+ break;
+ }
+ bits = depth - lowbit(mc);
+ s = decfmt(s, 0, bits);
+ depth -= bits;
+ }
+ *s++ = ' ';
+
+ *s++ = '0', *s++ = 'x';
+ s = hexfmt(s, 0, gop->Mode->FrameBufferBase), *s++ = '\n';
+ *s = '\0';
+
+ print(*cfg);
+ *cfg = s;
+}
+
+void
+eficonfig(char **cfg)
+{
+ memconf(cfg);
+ acpiconf(cfg);
+ screenconf(cfg);
+}
+
+EFI_STATUS
+efimain(EFI_HANDLE ih, EFI_SYSTEM_TABLE *st)
+{
+ char path[MAXPATH], *kern;
+ void *f;
+
+ IH = ih;
+ ST = st;
+
+ f = nil;
+ if(pxeinit(&f) && isoinit(&f) && fsinit(&f))
+ print("no boot devices\n");
+
+ for(;;){
+ kern = configure(f, path);
+ f = open(kern);
+ if(f == nil){
+ print("not found\n");
+ continue;
+ }
+ print(bootkern(f));
+ print("\n");
+ f = nil;
+ }
+}
--- /dev/null
+++ b/os/boot/efi/efi.h
@@ -1,0 +1,256 @@
+typedef ushort CHAR16;
+
+typedef uchar UINT8;
+typedef ushort UINT16;
+typedef ulong UINT32;
+typedef uvlong UINT64;
+typedef UINT8 BOOLEAN;
+
+typedef uintptr UINTN;
+
+typedef void* EFI_HANDLE;
+typedef UINT32 EFI_STATUS;
+
+enum {
+ AllHandles,
+ ByRegisterNotify,
+ ByProtocol,
+};
+
+typedef struct {
+ UINT32 Data1;
+ UINT16 Data2;
+ UINT16 Data3;
+ UINT8 Data4[8];
+} EFI_GUID;
+
+typedef struct {
+ UINT16 ScanCode;
+ CHAR16 UnicodeChar;
+} EFI_INPUT_KEY;
+
+typedef struct {
+ void *Reset;
+ void *ReadKeyStroke;
+ void *WaitForKey;
+} EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
+
+typedef struct {
+ void *Reset;
+ void *OutputString;
+ void *TestString;
+ void *QueryMode;
+ void *SetMode;
+ void *SetAttribute;
+ void *ClearScreen;
+ void *SetCursorPosition;
+ void *EnableCursor;
+ void *Mode;
+} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
+
+typedef struct {
+ UINT32 Revision;
+ EFI_HANDLE ParentHandle;
+ void *SystemTable;
+ EFI_HANDLE DeviceHandle;
+ void *FilePath;
+ void *Reserved;
+ UINT32 LoadOptionsSize;
+ void *LoadOptions;
+ void *ImageBase;
+ UINT64 ImageSize;
+ UINT32 ImageCodeType;
+ UINT32 ImageDataType;
+ void *Unload;
+} EFI_LOADED_IMAGE_PROTOCOL;
+
+typedef struct {
+ UINT32 RedMask;
+ UINT32 GreenMask;
+ UINT32 BlueMask;
+ UINT32 ReservedMask;
+} EFI_PIXEL_BITMASK;
+
+enum {
+ PixelRedGreenBlueReserved8BitPerColor,
+ PixelBlueGreenRedReserved8BitPerColor,
+ PixelBitMask,
+ PixelBltOnly,
+ PixelFormatMax,
+};
+
+typedef struct {
+ UINT32 Version;
+ UINT32 HorizontalResolution;
+ UINT32 VerticalResolution;
+ UINT32 PixelFormat;
+ EFI_PIXEL_BITMASK PixelInformation;
+ UINT32 PixelsPerScanLine;
+} EFI_GRAPHICS_OUTPUT_MODE_INFORMATION;
+
+typedef struct {
+ UINT32 MaxMode;
+ UINT32 Mode;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ UINTN SizeOfInfo;
+ UINT64 FrameBufferBase;
+ UINTN FrameBufferSize;
+} EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE;
+
+typedef struct {
+ void *QueryMode;
+ void *SetMode;
+ void *Blt;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode;
+} EFI_GRAPHICS_OUTPUT_PROTOCOL;
+
+enum {
+ EfiReservedMemoryType,
+ EfiLoaderCode,
+ EfiLoaderData,
+ EfiBootServicesCode,
+ EfiBootServicesData,
+ EfiRuntimeServicesCode,
+ EfiRuntimeServicesData,
+ EfiConventionalMemory,
+ EfiUnusableMemory,
+ EfiACPIReclaimMemory,
+ EfiACPIMemoryNVS,
+ EfiMemoryMappedIO,
+ EfiMemoryMappedIOPortSpace,
+ EfiPalCode,
+ EfiMaxMemoryType,
+};
+
+typedef struct {
+ UINT32 Type;
+ UINT32 Reserved;
+ UINT64 PhysicalStart;
+ UINT64 VirtualStart;
+ UINT64 NumberOfPages;
+ UINT64 Attribute;
+} EFI_MEMORY_DESCRIPTOR;
+
+
+typedef struct {
+ UINT64 Signature;
+ UINT32 Revision;
+ UINT32 HeaderSize;
+ UINT32 CRC32;
+ UINT32 Reserved;
+} EFI_TABLE_HEADER;
+
+typedef struct {
+ EFI_TABLE_HEADER;
+
+ void *RaiseTPL;
+ void *RestoreTPL;
+ void *AllocatePages;
+ void *FreePages;
+ void *GetMemoryMap;
+ void *AllocatePool;
+ void *FreePool;
+
+ void *CreateEvent;
+ void *SetTimer;
+ void *WaitForEvent;
+ void *SignalEvent;
+ void *CloseEvent;
+ void *CheckEvent;
+
+ void **InstallProtocolInterface;
+ void **ReinstallProtocolInterface;
+ void **UninstallProtocolInterface;
+
+ void *HandleProtocol;
+ void *Reserved;
+ void *RegisterProtocolNotify;
+
+ void *LocateHandle;
+ void *LocateDevicePath;
+ void *InstallConfigurationTable;
+
+ void *LoadImage;
+ void *StartImage;
+ void *Exit;
+ void *UnloadImage;
+ void *ExitBootServices;
+
+ void *GetNextMonotonicCount;
+ void *Stall;
+ void *SetWatchdogTimer;
+
+ void *ConnectController;
+ void *DisconnectController;
+
+ void *OpenProtocol;
+ void *CloseProtocol;
+
+ void *OpenProtocolInformation;
+ void *ProtocolsPerHandle;
+ void *LocateHandleBuffer;
+ void *LocateProtocol;
+
+ void *InstallMultipleProtocolInterfaces;
+ void *UninstallMultipleProtocolInterfaces;
+
+ void *CalculateCrc32;
+
+ void *CopyMem;
+ void *SetMem;
+ void *CreateEventEx;
+} EFI_BOOT_SERVICES;
+
+typedef struct {
+ EFI_TABLE_HEADER;
+
+ void *GetTime;
+ void *SetTime;
+ void *GetWakeupTime;
+ void *SetWakeupTime;
+
+ void *SetVirtualAddressMap;
+ void *ConvertPointer;
+
+ void *GetVariable;
+ void *GetNextVariableName;
+ void *SetVariable;
+
+ void *GetNextHighMonotonicCount;
+ void *ResetSystem;
+
+ void *UpdateCapsule;
+ void *QueryCapsuleCapabilities;
+
+ void *QueryVariableInfo;
+} EFI_RUNTIME_SERVICES;
+
+typedef struct {
+ EFI_GUID VendorGuid;
+ void *VendorTable;
+} EFI_CONFIGURATION_TABLE;
+
+typedef struct {
+ EFI_TABLE_HEADER;
+
+ CHAR16 *FirmwareVendor;
+ UINT32 FirmwareRevision;
+
+ EFI_HANDLE ConsoleInHandle;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
+
+ EFI_HANDLE ConsoleOutHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+
+ EFI_HANDLE StandardErrorHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr;
+
+ EFI_RUNTIME_SERVICES *RuntimeServices;
+ EFI_BOOT_SERVICES *BootServices;
+
+ UINTN NumberOfTableEntries;
+ EFI_CONFIGURATION_TABLE *ConfigurationTable;
+} EFI_SYSTEM_TABLE;
+
+extern EFI_SYSTEM_TABLE *ST;
+extern EFI_HANDLE IH;
--- /dev/null
+++ b/os/boot/efi/fns.h
@@ -1,0 +1,39 @@
+enum {
+ MAXPATH = 128,
+};
+
+extern char hex[];
+
+void usleep(int t);
+void jump(void *pc);
+
+int pxeinit(void **pf);
+int isoinit(void **pf);
+int fsinit(void **pf);
+
+void* (*open)(char *name);
+int (*read)(void *f, void *data, int len);
+void (*close)(void *f);
+
+int readn(void *f, void *data, int len);
+void unload(void);
+
+int getc(void);
+void putc(int c);
+
+void memset(void *p, int v, int n);
+void memmove(void *dst, void *src, int n);
+int memcmp(void *src, void *dst, int n);
+int strlen(char *s);
+char *strchr(char *s, int c);
+char *strrchr(char *s, int c);
+void print(char *s);
+
+char *configure(void *f, char *path);
+char *bootkern(void *f);
+
+char *hexfmt(char *s, int i, uvlong a);
+char *decfmt(char *s, int i, ulong a);
+
+uintptr eficall(void *proc, ...);
+void eficonfig(char **cfg);
--- /dev/null
+++ b/os/boot/efi/fs.c
@@ -1,0 +1,166 @@
+#include <u.h>
+#include "fns.h"
+#include "efi.h"
+
+typedef struct {
+ UINT64 Revision;
+ void *Open;
+ void *Close;
+ void *Delete;
+ void *Read;
+ void *Write;
+ void *GetPosition;
+ void *SetPosition;
+ void *GetInfo;
+ void *SetInfo;
+ void *Flush;
+ void *OpenEx;
+ void *ReadEx;
+ void *WriteEx;
+ void *FlushEx;
+} EFI_FILE_PROTOCOL;
+
+typedef struct {
+ UINT64 Revision;
+ void *OpenVolume;
+} EFI_SIMPLE_FILE_SYSTEM_PROTOCOL;
+
+static
+EFI_GUID EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID = {
+ 0x0964e5b22, 0x6459, 0x11d2,
+ 0x8e, 0x39, 0x00, 0xa0,
+ 0xc9, 0x69, 0x72, 0x3b,
+};
+
+static EFI_GUID EFI_LOADED_IMAGE_PROTOCOL_GUID = {
+ 0x5b1b31a1, 0x9562, 0x11d2,
+ 0x8e, 0x3f, 0x00, 0xa0,
+ 0xc9, 0x69, 0x72, 0x3b,
+};
+
+static
+EFI_FILE_PROTOCOL *fsroot;
+
+static void
+towpath(CHAR16 *w, int nw, char *s)
+{
+ int i;
+
+ for(i=0; *s && i<nw-1; i++){
+ *w = *s++;
+ if(*w == '/')
+ *w = '\\';
+ w++;
+ }
+ *w = 0;
+}
+
+static void*
+fsopen(char *name)
+{
+ CHAR16 wname[MAXPATH];
+ EFI_FILE_PROTOCOL *fp;
+
+ if(fsroot == nil)
+ return nil;
+
+ towpath(wname, MAXPATH, name);
+
+ fp = nil;
+ if(eficall(fsroot->Open, fsroot, &fp, wname, (UINT64)1, (UINT64)1))
+ return nil;
+ return fp;
+}
+
+static int
+fsread(void *f, void *data, int len)
+{
+ UINTN size;
+
+ size = len > 4096 ? 4096 : len;
+ if(eficall(((EFI_FILE_PROTOCOL*)f)->Read, f, &size, data))
+ return 0;
+ return (int)size;
+}
+
+static void
+fsclose(void *f)
+{
+ eficall(((EFI_FILE_PROTOCOL*)f)->Close, f);
+}
+
+int
+fsinit(void **pf)
+{
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
+ EFI_LOADED_IMAGE_PROTOCOL *image;
+ EFI_FILE_PROTOCOL *root;
+ EFI_HANDLE *Handles;
+ void *f;
+ UINTN Count;
+ int i;
+
+ image = nil;
+
+ /* locate kernel and plan9.ini by deriving a fs protocol
+ * from the device the loader was read from.
+ * if that fails, fall back to old method.
+ */
+ if(eficall(ST->BootServices->HandleProtocol, IH,
+ &EFI_LOADED_IMAGE_PROTOCOL_GUID, &image) == 0 &&
+ eficall(ST->BootServices->HandleProtocol, image->DeviceHandle,
+ &EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, &fs) == 0 &&
+ eficall(fs->OpenVolume, fs, &root) == 0){
+
+ fsroot = root;
+ f = fsopen("/plan9.ini");
+ if(f != nil){
+ if(pf != nil)
+ *pf = f;
+ else
+ fsclose(f);
+
+ goto gotit;
+ }
+ }
+
+ Count = 0;
+ Handles = nil;
+ if(eficall(ST->BootServices->LocateHandleBuffer,
+ ByProtocol, &EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, nil, &Count, &Handles))
+ return -1;
+
+ /*
+ * assuming the ESP is the first entry in the handle buffer, so go backwards
+ * to scan for plan9.ini in other (9fat) filesystems first. if nothing is found
+ * we'll be defaulting to the ESP.
+ */
+ fsroot = nil;
+ for(i=Count-1; i>=0; i--){
+ root = nil;
+ fs = nil;
+ if(eficall(ST->BootServices->HandleProtocol,
+ Handles[i], &EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, &fs))
+ continue;
+ if(eficall(fs->OpenVolume, fs, &root))
+ continue;
+ fsroot = root;
+ f = fsopen("/plan9.ini");
+ if(f != nil){
+ if(pf != nil)
+ *pf = f;
+ else
+ fsclose(f);
+ break;
+ }
+ }
+ if(fsroot == nil)
+ return -1;
+
+gotit:
+ read = fsread;
+ close = fsclose;
+ open = fsopen;
+
+ return 0;
+}
--- /dev/null
+++ b/os/boot/efi/iso.c
@@ -1,0 +1,222 @@
+#include <u.h>
+#include "fns.h"
+#include "efi.h"
+
+enum {
+ Sectsz = 0x800,
+ Dirsz = 33,
+};
+
+typedef struct Extend Extend;
+typedef struct Dir Dir;
+
+struct Extend
+{
+ ulong lba;
+ ulong len;
+ uchar *rp;
+ uchar *ep;
+ uchar buf[Sectsz];
+};
+
+struct Dir
+{
+ uchar dirlen;
+ uchar extlen;
+
+ uchar lba[8];
+ uchar len[8];
+
+ uchar date[7];
+
+ uchar flags[3];
+
+ uchar seq[4];
+
+ uchar namelen;
+};
+
+typedef struct {
+ UINT32 MediaId;
+
+ BOOLEAN RemovableMedia;
+ BOOLEAN MediaPresent;
+ BOOLEAN LogicalPartition;
+ BOOLEAN ReadOnly;
+
+ BOOLEAN WriteCaching;
+ BOOLEAN Pad[3];
+
+ UINT32 BlockSize;
+ UINT32 IoAlign;
+ UINT64 LastBlock;
+} EFI_BLOCK_IO_MEDIA;
+
+typedef struct {
+ UINT64 Revision;
+ EFI_BLOCK_IO_MEDIA *Media;
+ void *Reset;
+ void *ReadBlocks;
+ void *WriteBlocks;
+ void *FlushBlocks;
+} EFI_BLOCK_IO_PROTOCOL;
+
+static EFI_GUID
+EFI_BLOCK_IO_PROTOCOL_GUID = {
+ 0x964e5b21, 0x6459, 0x11d2,
+ 0x8e, 0x39, 0x00, 0xa0,
+ 0xc9, 0x69, 0x72, 0x3b,
+};
+
+static EFI_BLOCK_IO_PROTOCOL *bio;
+
+static int
+readsect(ulong lba, void *buf)
+{
+ lba *= Sectsz/bio->Media->BlockSize;
+ return eficall(bio->ReadBlocks, bio, (UINTN)bio->Media->MediaId, (UINT64)lba, (UINTN)Sectsz, buf);
+}
+
+static int
+isoread(void *f, void *data, int len)
+{
+ Extend *ex = f;
+
+ if(ex->len > 0 && ex->rp >= ex->ep)
+ if(readsect(ex->lba++, ex->rp = ex->buf))
+ return -1;
+ if(ex->len < len)
+ len = ex->len;
+ if(len > (ex->ep - ex->rp))
+ len = ex->ep - ex->rp;
+ memmove(data, ex->rp, len);
+ ex->rp += len;
+ ex->len -= len;
+ return len;
+}
+
+void
+isoclose(void *f)
+{
+ Extend *ex = f;
+
+ ex->lba = 0;
+ ex->len = 0;
+ ex->rp = ex->ep = ex->buf + Sectsz;
+}
+
+static int
+isowalk(Extend *ex, char *path)
+{
+ char name[MAXPATH], c, *end;
+ int i;
+ Dir d;
+
+ isoclose(ex);
+
+ /* find pvd */
+ for(i=0x10; i<0x1000; i++){
+ if(readsect(i, ex->buf))
+ return -1;
+ if(memcmp(ex->buf, "\001CD001\001", 7) == 0)
+ goto Foundpvd;
+ }
+ return -1;
+Foundpvd:
+ ex->lba = *((ulong*)(ex->buf + 156 + 2));
+ ex->len = *((ulong*)(ex->buf + 156 + 10));
+ if(*path == 0)
+ return 0;
+
+ for(;;){
+ if(readn(ex, &d, Dirsz) != Dirsz)
+ break;
+ if(d.dirlen == 0)
+ break;
+ if(readn(ex, name, d.namelen) != d.namelen)
+ break;
+ i = d.dirlen - (Dirsz + d.namelen);
+ while(i-- > 0)
+ read(ex, &c, 1);
+ for(i=0; i<d.namelen; i++){
+ c = name[i];
+ if(c >= 'A' && c <= 'Z'){
+ c -= 'A';
+ c += 'a';
+ }
+ name[i] = c;
+ }
+ name[i] = 0;
+ while(*path == '/')
+ path++;
+ if((end = strchr(path, '/')) == 0)
+ end = path + strlen(path);
+ i = end - path;
+ if(d.namelen == i && memcmp(name, path, i) == 0){
+ ex->rp = ex->ep;
+ ex->lba = *((ulong*)d.lba);
+ ex->len = *((ulong*)d.len);
+ if(*end == 0)
+ return 0;
+ else if(d.flags[0] & 2){
+ path = end;
+ continue;
+ }
+ break;
+ }
+ }
+ return -1;
+}
+
+static void*
+isoopen(char *path)
+{
+ static uchar buf[sizeof(Extend)+8];
+ Extend *ex = (Extend*)((uintptr)(buf+7)&~7);
+
+ if(isowalk(ex, path))
+ return nil;
+ return ex;
+}
+
+int
+isoinit(void **fp)
+{
+ EFI_BLOCK_IO_MEDIA *media;
+ EFI_HANDLE *Handles;
+ UINTN Count;
+ int i;
+
+ bio = nil;
+ Count = 0;
+ Handles = nil;
+ if(eficall(ST->BootServices->LocateHandleBuffer,
+ ByProtocol, &EFI_BLOCK_IO_PROTOCOL_GUID, nil, &Count, &Handles))
+ return -1;
+
+ for(i=0; i<Count; i++){
+ bio = nil;
+ if(eficall(ST->BootServices->HandleProtocol,
+ Handles[i], &EFI_BLOCK_IO_PROTOCOL_GUID, &bio))
+ continue;
+
+ media = bio->Media;
+ if(media != nil
+ && media->MediaPresent
+ && media->LogicalPartition == 0
+ && media->BlockSize != 0
+ && isoopen("") != nil)
+ goto Found;
+ }
+ return -1;
+
+Found:
+ open = isoopen;
+ read = isoread;
+ close = isoclose;
+
+ if(fp != nil)
+ *fp = isoopen("/cfg/plan9.ini");
+
+ return 0;
+}
--- /dev/null
+++ b/os/boot/efi/mem.h
@@ -1,0 +1,47 @@
+/*
+ * 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))
+
+/*
+ * Fundamental addresses
+ */
+#define CONFADDR 0x1200 /* info passed from boot loader */
+#define BIOSXCHG 0x6000 /* To exchange data with the BIOS */
+
+#define SELGDT (0<<3) /* selector is in gdt */
+#define SELLDT (1<<3) /* selector is in ldt */
+
+#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p))
+
+/*
+ * fields in segment descriptors
+ */
+#define SEGDATA (0x10<<8) /* data/stack segment */
+#define SEGEXEC (0x18<<8) /* executable segment */
+#define SEGTSS (0x9<<8) /* TSS segment */
+#define SEGCG (0x0C<<8) /* call gate */
+#define SEGIG (0x0E<<8) /* interrupt gate */
+#define SEGTG (0x0F<<8) /* trap gate */
+#define SEGLDT (0x02<<8) /* local descriptor table */
+#define SEGTYPE (0x1F<<8)
+
+#define SEGP (1<<15) /* segment present */
+#define SEGPL(x) ((x)<<13) /* priority level */
+#define SEGB (1<<22) /* granularity 1==4k (for expand-down) */
+#define SEGD (1<<22) /* default 1==32bit (for code) */
+#define SEGE (1<<10) /* expand down */
+#define SEGW (1<<9) /* writable (for data/stack) */
+#define SEGR (1<<9) /* readable (for code) */
+#define SEGL (1<<21) /* 64 bit */
+#define SEGG (1<<23) /* granularity 1==4k (for other) */
--- /dev/null
+++ b/os/boot/efi/mkfile
@@ -1,0 +1,105 @@
+TARG=bootia32.efi bootx64.efi efiboot.fat
+HFILES=fns.h mem.h
+IMAGEBASE=0x8000
+CFLAGS=-FTVw
+PEFLAGS=$CFLAGS '-DIMAGEBASE='$IMAGEBASE
+
+all:V: $TARG
+
+install:V: $TARG
+ cp $prereq /386
+
+bootia32.efi: pe32.8 efi.8 fs.8 pxe.8 iso.8 sub.8
+ 8l -l -H3 -T$IMAGEBASE -o $target $prereq
+
+pe32.8: pe32.s
+ 8a $PEFLAGS pe32.s
+
+efi.8: efi.c efi.h
+ 8c $CFLAGS efi.c
+
+fs.8: fs.c efi.h
+ 8c $CFLAGS fs.c
+
+pxe.8: pxe.c efi.h
+ 8c $CFLAGS pxe.c
+
+iso.8: iso.c efi.h
+ 8c $CFLAGS iso.c
+
+sub.8: sub.c
+ 8c $CFLAGS sub.c
+
+%.8: $HFILES
+
+
+bootx64.efi: pe64.6 efi.6 fs.6 pxe.6 iso.6 sub.6
+ 6l -l -s -R1 -T$IMAGEBASE -o bootx64.out $prereq
+ dd -if bootx64.out -bs 1 -iseek 40 >$target
+
+pe64.6: pe64.s
+ 6a $PEFLAGS pe64.s
+
+efi.6: efi.c efi.h
+ 6c $CFLAGS efi.c
+
+fs.6: fs.c efi.h
+ 6c $CFLAGS fs.c
+
+pxe.6: pxe.c efi.h
+ 6c $CFLAGS pxe.c
+
+iso.6: iso.c efi.h
+ 6c $CFLAGS iso.c
+
+sub.6: sub.c
+ 6c $CFLAGS sub.c
+
+%.6: $HFILES
+
+efiboot.fat:D: bootia32.efi bootx64.efi
+ s = $target.$pid
+ rm -f $target
+ dd -if /dev/zero -of $target -bs 1024 -count 1024
+ disk/format -xd -t hard $target
+ dossrv -f $target $s
+ mount -c /srv/$s /n/esp
+ mkdir /n/esp/efi
+ mkdir /n/esp/efi/boot
+ cp bootia32.efi /n/esp/efi/boot
+ cp bootx64.efi /n/esp/efi/boot
+ unmount /n/esp
+ rm /srv/$s
+
+
+test.iso:D: efiboot.fat
+ rm -fr tmp
+ mkdir tmp
+ mkdir tmp/cfg
+ mkdir tmp/386
+ cp efiboot.fat tmp/386
+ cp /386/9bootiso tmp/386
+ cp /386/9pc tmp/386
+ echo 'bootfile=/386/9pc' >tmp/cfg/plan9.ini
+ disk/mk9660 -B 386/9bootiso -E 386/efiboot.fat -p <{echo +} -s tmp $target
+ rm -r tmp
+
+test.fat:D: bootia32.efi bootx64.efi
+ s = $target.$pid
+ rm -f $target
+ dd -if /dev/zero -of $target -bs 65536 -count 128
+ disk/format -xd -t hard $target
+ dossrv -f $target $s
+ mount -c /srv/$s /n/esp
+ mkdir /n/esp/efi
+ mkdir /n/esp/efi/boot
+ cp bootia32.efi /n/esp/efi/boot
+ cp bootx64.efi /n/esp/efi/boot
+ cp /386/9pc /n/esp
+ echo 'bootfile=9pc' >/n/esp/plan9.ini
+ unmount /n/esp
+ rm /srv/$s
+
+
+clean:V:
+ rm -f *.[68] *.out $TARG test.*
--- /dev/null
+++ b/os/boot/efi/pe32.s
@@ -1,0 +1,159 @@
+TEXT mzhdr(SB), 1, $0
+ BYTE $'M'; BYTE $'Z'
+
+ WORD $0 /* e_cblp UNUSED */
+ WORD $0 /* e_cp UNUSED */
+ WORD $0 /* e_crlc UNUSED */
+ WORD $0 /* e_cparhdr UNUSED */
+ WORD $0 /* e_minalloc UNUSED */
+ WORD $0 /* e_maxalloc UNUSED */
+ WORD $0 /* e_ss UNUSED */
+ WORD $0 /* e_sp UNUSED */
+ WORD $0 /* e_csum UNUSED */
+ WORD $0 /* e_ip UNUSED */
+ WORD $0 /* e_cs UNUSED */
+ WORD $0 /* e_lsarlc UNUSED */
+ WORD $0 /* e_ovno UNUSED */
+
+ WORD $0 /* e_res UNUSED */
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+
+ WORD $0 /* e_oemid UNUSED */
+
+ WORD $0 /* e_res2 UNUSED */
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+
+ LONG $pehdr-IMAGEBASE(SB) /* offset to pe header */
+
+TEXT pehdr(SB), 1, $0
+ BYTE $'P'; BYTE $'E'; BYTE $0; BYTE $0
+
+ WORD $0x014C /* Machine (Intel 386) */
+ WORD $1 /* NumberOfSections */
+ LONG $0 /* TimeDateStamp UNUSED */
+ LONG $0 /* PointerToSymbolTable UNUSED */
+ LONG $0 /* NumberOfSymbols UNUSED */
+ WORD $0xE0 /* SizeOfOptionalHeader */
+ WORD $2103 /* Characteristics (no relocations, executable, 32 bit) */
+
+ WORD $0x10B /* Magic (PE32) */
+ BYTE $9 /* MajorLinkerVersion UNUSED */
+ BYTE $0 /* MinorLinkerVersion UNUSED */
+ LONG $0 /* SizeOfCode UNUSED */
+ LONG $0 /* SizeOfInitializedData UNUSED */
+ LONG $0 /* SizeOfUninitializedData UNUSED */
+ LONG $start-IMAGEBASE(SB)/* AddressOfEntryPoint */
+ LONG $0 /* BaseOfCode UNUSED */
+ LONG $0 /* BaseOfData UNUSED */
+ LONG $IMAGEBASE /* ImageBase */
+ LONG $0x200 /* SectionAlignment */
+ LONG $0x200 /* FileAlignment */
+ WORD $4 /* MajorOperatingSystemVersion UNUSED */
+ WORD $0 /* MinorOperatingSystemVersion UNUSED */
+ WORD $0 /* MajorImageVersion UNUSED */
+ WORD $0 /* MinorImageVersion UNUSED */
+ WORD $4 /* MajorSubsystemVersion */
+ WORD $0 /* MinorSubsystemVersion UNUSED */
+ LONG $0 /* Win32VersionValue UNUSED */
+ LONG $end-IMAGEBASE(SB) /* SizeOfImage */
+ LONG $start-IMAGEBASE(SB)/* SizeOfHeaders */
+ LONG $0 /* CheckSum UNUSED */
+ WORD $10 /* Subsystem (10 = efi application) */
+ WORD $0 /* DllCharacteristics UNUSED */
+ LONG $0 /* SizeOfStackReserve UNUSED */
+ LONG $0 /* SizeOfStackCommit UNUSED */
+ LONG $0 /* SizeOfHeapReserve UNUSED */
+ LONG $0 /* SizeOfHeapCommit UNUSED */
+ LONG $0 /* LoaderFlags UNUSED */
+ LONG $16 /* NumberOfRvaAndSizes UNUSED */
+
+ LONG $0; LONG $0
+ LONG $0; LONG $0
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+
+ BYTE $'.'; BYTE $'t'; BYTE $'e'; BYTE $'x'
+ BYTE $'t'; BYTE $0; BYTE $0; BYTE $0
+ LONG $edata-(IMAGEBASE+0x200)(SB) /* VirtualSize */
+ LONG $start-IMAGEBASE(SB) /* VirtualAddress */
+ LONG $edata-(IMAGEBASE+0x200)(SB) /* SizeOfData */
+ LONG $start-IMAGEBASE(SB) /* PointerToRawData */
+ LONG $0 /* PointerToRelocations UNUSED */
+ LONG $0 /* PointerToLinenumbers UNUSED */
+ WORD $0 /* NumberOfRelocations UNUSED */
+ WORD $0 /* NumberOfLinenumbers UNUSED */
+ LONG $0x86000020 /* Characteristics (code, execute, read, write) */
+
+ /* padding to get start(SB) at IMAGEBASE+0x200 */
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+
+TEXT start(SB), 1, $0
+ CALL reloc(SP)
+
+TEXT reloc(SB), 1, $0
+ MOVL 0(SP), SI
+ SUBL $reloc-IMAGEBASE(SB), SI
+ MOVL $IMAGEBASE, DI
+ MOVL $edata-IMAGEBASE(SB), CX
+ CLD
+ REP; MOVSB
+ MOVL $efimain(SB), DI
+ MOVL DI, (SP)
+ RET
+
+TEXT jump(SB), $0
+ CLI
+ MOVL 4(SP), AX
+ JMP *AX
+
+TEXT eficall(SB), 1, $0
+ MOVL SP, SI
+ MOVL SP, DI
+ MOVL $(4*16), CX
+ SUBL CX, DI
+ ANDL $~15ULL, DI
+ SUBL $8, DI
+
+ MOVL 4(SI), AX
+ LEAL 8(DI), SP
+
+ CLD
+ REP; MOVSB
+ SUBL $(4*16), SI
+
+ CALL AX
+
+ MOVL SI, SP
+ RET
--- /dev/null
+++ b/os/boot/efi/pe64.s
@@ -1,0 +1,237 @@
+TEXT mzhdr(SB), 1, $0
+ BYTE $'M'; BYTE $'Z'
+
+ WORD $0 /* e_cblp UNUSED */
+ WORD $0 /* e_cp UNUSED */
+ WORD $0 /* e_crlc UNUSED */
+ WORD $0 /* e_cparhdr UNUSED */
+ WORD $0 /* e_minalloc UNUSED */
+ WORD $0 /* e_maxalloc UNUSED */
+ WORD $0 /* e_ss UNUSED */
+ WORD $0 /* e_sp UNUSED */
+ WORD $0 /* e_csum UNUSED */
+ WORD $0 /* e_ip UNUSED */
+ WORD $0 /* e_cs UNUSED */
+ WORD $0 /* e_lsarlc UNUSED */
+ WORD $0 /* e_ovno UNUSED */
+
+ WORD $0 /* e_res UNUSED */
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+
+ WORD $0 /* e_oemid UNUSED */
+
+ WORD $0 /* e_res2 UNUSED */
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+ WORD $0
+
+ LONG $pehdr-IMAGEBASE(SB) /* offset to pe header */
+
+TEXT pehdr(SB), 1, $0
+ BYTE $'P'; BYTE $'E'; BYTE $0; BYTE $0
+
+ WORD $0x8664 /* Machine (AMD64) */
+ WORD $1 /* NumberOfSections */
+ LONG $0 /* TimeDateStamp UNUSED */
+ LONG $0 /* PointerToSymbolTable UNUSED */
+ LONG $0 /* NumberOfSymbols UNUSED */
+ WORD $0xF0 /* SizeOfOptionalHeader */
+ WORD $2223 /* Characteristics */
+
+ WORD $0x20B /* Magic (PE32+) */
+ BYTE $9 /* MajorLinkerVersion UNUSED */
+ BYTE $0 /* MinorLinkerVersion UNUSED */
+ LONG $0 /* SizeOfCode UNUSED */
+ LONG $0 /* SizeOfInitializedData UNUSED */
+ LONG $0 /* SizeOfUninitializedData UNUSED */
+ LONG $start-IMAGEBASE(SB)/* AddressOfEntryPoint */
+ LONG $0 /* BaseOfCode UNUSED */
+
+ QUAD $IMAGEBASE /* ImageBase */
+ LONG $0x200 /* SectionAlignment */
+ LONG $0x200 /* FileAlignment */
+ WORD $4 /* MajorOperatingSystemVersion UNUSED */
+ WORD $0 /* MinorOperatingSystemVersion UNUSED */
+ WORD $0 /* MajorImageVersion UNUSED */
+ WORD $0 /* MinorImageVersion UNUSED */
+ WORD $4 /* MajorSubsystemVersion */
+ WORD $0 /* MinorSubsystemVersion UNUSED */
+ LONG $0 /* Win32VersionValue UNUSED */
+ LONG $end-IMAGEBASE(SB) /* SizeOfImage */
+ LONG $start-IMAGEBASE(SB)/* SizeOfHeaders */
+ LONG $0 /* CheckSum UNUSED */
+ WORD $10 /* Subsystem (10 = efi application) */
+ WORD $0 /* DllCharacteristics UNUSED */
+ QUAD $0 /* SizeOfStackReserve UNUSED */
+ QUAD $0 /* SizeOfStackCommit UNUSED */
+ QUAD $0 /* SizeOfHeapReserve UNUSED */
+ QUAD $0 /* SizeOfHeapCommit UNUSED */
+ LONG $0 /* LoaderFlags UNUSED */
+ LONG $16 /* NumberOfRvaAndSizes UNUSED */
+
+ LONG $0; LONG $0
+ LONG $0; LONG $0
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+ LONG $0; LONG $0 /* RVA */
+
+ BYTE $'.'; BYTE $'t'; BYTE $'e'; BYTE $'x'
+ BYTE $'t'; BYTE $0; BYTE $0; BYTE $0
+ LONG $edata-(IMAGEBASE+0x200)(SB) /* VirtualSize */
+ LONG $start-IMAGEBASE(SB) /* VirtualAddress */
+ LONG $edata-(IMAGEBASE+0x200)(SB) /* SizeOfData */
+ LONG $start-IMAGEBASE(SB) /* PointerToRawData */
+ LONG $0 /* PointerToRelocations UNUSED */
+ LONG $0 /* PointerToLinenumbers UNUSED */
+ WORD $0 /* NumberOfRelocations UNUSED */
+ WORD $0 /* NumberOfLinenumbers UNUSED */
+ LONG $0x86000020 /* Characteristics (code, execute, read, write) */
+
+ /* padding to get start(SB) at IMAGEBASE+0x200 */
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0;
+ LONG $0; LONG $0; LONG $0; LONG $0
+
+MODE $64
+
+TEXT start(SB), 1, $-4
+ /* spill arguments */
+ MOVQ CX, 8(SP)
+ MOVQ DX, 16(SP)
+
+ CALL reloc(SP)
+
+TEXT reloc(SB), 1, $-4
+ MOVQ 0(SP), SI
+ SUBQ $reloc-IMAGEBASE(SB), SI
+ MOVQ $IMAGEBASE, DI
+ MOVQ $edata-IMAGEBASE(SB), CX
+ CLD
+ REP; MOVSB
+
+ MOVQ 16(SP), BP
+ MOVQ $efimain(SB), DI
+ MOVQ DI, (SP)
+ RET
+
+TEXT eficall(SB), 1, $-4
+ MOVQ SP, SI
+ MOVQ SP, DI
+ MOVL $(8*16), CX
+ SUBQ CX, DI
+ ANDQ $~15ULL, DI
+ LEAQ 16(DI), SP
+ CLD
+ REP; MOVSB
+ SUBQ $(8*16), SI
+
+ MOVQ 0(SP), CX
+ MOVQ 8(SP), DX
+ MOVQ 16(SP), R8
+ MOVQ 24(SP), R9
+ CALL BP
+
+ MOVQ SI, SP
+ RET
+
+#include "mem.h"
+
+TEXT jump(SB), 1, $-4
+ CLI
+
+ /* load zero length idt */
+ MOVL $_idtptr64p<>(SB), AX
+ MOVL (AX), IDTR
+
+ /* load temporary gdt */
+ MOVL $_gdtptr64p<>(SB), AX
+ MOVL (AX), GDTR
+
+ /* load CS with 32bit code segment */
+ PUSHQ $SELECTOR(3, SELGDT, 0)
+ PUSHQ $_warp32<>(SB)
+ RETFQ
+
+MODE $32
+
+TEXT _warp32<>(SB), 1, $-4
+
+ /* load 32bit data segments */
+ MOVL $SELECTOR(2, SELGDT, 0), AX
+ MOVW AX, DS
+ MOVW AX, ES
+ MOVW AX, FS
+ MOVW AX, GS
+ MOVW AX, SS
+
+ /* turn off paging */
+ MOVL CR0, AX
+ ANDL $0x7fffffff, AX /* ~(PG) */
+ MOVL AX, CR0
+
+ MOVL $0, AX
+ MOVL AX, CR3
+
+ /* disable long mode */
+ MOVL $0xc0000080, CX /* Extended Feature Enable */
+ RDMSR
+ ANDL $0xfffffeff, AX /* Long Mode Disable */
+ WRMSR
+
+ /* diable pae */
+ MOVL CR4, AX
+ ANDL $0xffffff5f, AX /* ~(PAE|PGE) */
+ MOVL AX, CR4
+
+ JMP *BP
+
+TEXT _gdt<>(SB), 1, $-4
+ /* null descriptor */
+ LONG $0
+ LONG $0
+
+ /* (KESEG) 64 bit long mode exec segment */
+ LONG $(0xFFFF)
+ LONG $(SEGL|SEGG|SEGP|(0xF<<16)|SEGPL(0)|SEGEXEC|SEGR)
+
+ /* 32 bit data segment descriptor for 4 gigabytes (PL 0) */
+ LONG $(0xFFFF)
+ LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
+
+ /* 32 bit exec segment descriptor for 4 gigabytes (PL 0) */
+ LONG $(0xFFFF)
+ LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
+
+TEXT _gdtptr64p<>(SB), 1, $-4
+ WORD $(4*8-1)
+ QUAD $_gdt<>(SB)
+
+TEXT _idtptr64p<>(SB), 1, $-4
+ WORD $0
+ QUAD $0
--- /dev/null
+++ b/os/boot/efi/pxe.c
@@ -1,0 +1,487 @@
+#include <u.h>
+#include "fns.h"
+#include "efi.h"
+
+typedef UINT16 EFI_PXE_BASE_CODE_UDP_PORT;
+
+typedef struct {
+ UINT8 Addr[4];
+} EFI_IPv4_ADDRESS;
+
+typedef struct {
+ UINT8 Addr[16];
+} EFI_IPv6_ADDRESS;
+
+typedef union {
+ UINT32 Addr[4];
+ EFI_IPv4_ADDRESS v4;
+ EFI_IPv6_ADDRESS v6;
+} EFI_IP_ADDRESS;
+
+typedef struct {
+ UINT8 Addr[32];
+} EFI_MAC_ADDRESS;
+
+typedef struct {
+ UINT8 BootpOpcode;
+ UINT8 BootpHwType;
+ UINT8 BootpHwAddrLen;
+ UINT8 BootpGateHops;
+ UINT32 BootpIdent;
+ UINT16 BootpSeconds;
+ UINT16 BootpFlags;
+ UINT8 BootpCiAddr[4];
+ UINT8 BootpYiAddr[4];
+ UINT8 BootpSiAddr[4];
+ UINT8 BootpGiAddr[4];
+ UINT8 BootpHwAddr[16];
+ UINT8 BootpSrvName[64];
+ UINT8 BootpBootFile[128];
+ UINT32 DhcpMagik;
+ UINT8 DhcpOptions[56];
+} EFI_PXE_BASE_CODE_DHCPV4_PACKET;
+
+typedef struct {
+ BOOLEAN Started;
+ BOOLEAN Ipv6Available;
+ BOOLEAN Ipv6Supported;
+ BOOLEAN UsingIpv6;
+ BOOLEAN BisSupported;
+ BOOLEAN BisDetected;
+ BOOLEAN AutoArp;
+ BOOLEAN SendGUID;
+ BOOLEAN DhcpDiscoverValid;
+ BOOLEAN DhcpAckReceived;
+ BOOLEAN ProxyOfferReceived;
+ BOOLEAN PxeDiscoverValid;
+ BOOLEAN PxeReplyReceived;
+ BOOLEAN PxeBisReplyReceived;
+ BOOLEAN IcmpErrorReceived;
+ BOOLEAN TftpErrorReceived;
+ BOOLEAN MakeCallbacks;
+
+ UINT8 TTL;
+ UINT8 ToS;
+
+ UINT8 Reserved;
+
+ UINT8 StationIp[16];
+ UINT8 SubnetMask[16];
+
+ UINT8 DhcpDiscover[1472];
+ UINT8 DhcpAck[1472];
+ UINT8 ProxyOffer[1472];
+ UINT8 PxeDiscover[1472];
+ UINT8 PxeReply[1472];
+ UINT8 PxeBisReply[1472];
+
+} EFI_PXE_BASE_CODE_MODE;
+
+typedef struct {
+ UINT64 Revision;
+ void *Start;
+ void *Stop;
+ void *Dhcp;
+ void *Discover;
+ void *Mtftp;
+ void *UdpWrite;
+ void *UdpRead;
+ void *SetIpFilter;
+ void *Arp;
+ void *SetParameters;
+ void *SetStationIp;
+ void *SetPackets;
+ EFI_PXE_BASE_CODE_MODE *Mode;
+} EFI_PXE_BASE_CODE_PROTOCOL;
+
+
+enum {
+ Tftp_READ = 1,
+ Tftp_WRITE = 2,
+ Tftp_DATA = 3,
+ Tftp_ACK = 4,
+ Tftp_ERROR = 5,
+ Tftp_OACK = 6,
+
+ TftpPort = 69,
+
+ Segsize = 512,
+};
+
+static
+EFI_GUID EFI_PXE_BASE_CODE_PROTOCOL_GUID = {
+ 0x03C4E603, 0xAC28, 0x11D3,
+ 0x9A, 0x2D, 0x00, 0x90,
+ 0x27, 0x3F, 0xC1, 0x4D,
+};
+
+static
+EFI_PXE_BASE_CODE_PROTOCOL *pxe;
+
+static uchar mymac[6];
+static uchar myip[16];
+static uchar serverip[16];
+
+typedef struct Tftp Tftp;
+struct Tftp
+{
+ EFI_IP_ADDRESS sip;
+ EFI_IP_ADDRESS dip;
+
+ EFI_PXE_BASE_CODE_UDP_PORT sport;
+ EFI_PXE_BASE_CODE_UDP_PORT dport;
+
+ char *rp;
+ char *ep;
+
+ int seq;
+ int eof;
+
+ char pkt[2+2+Segsize];
+ char nul;
+};
+
+static void
+puts(void *x, ushort v)
+{
+ uchar *p = x;
+
+ p[1] = (v>>8) & 0xFF;
+ p[0] = v & 0xFF;
+}
+
+static ushort
+gets(void *x)
+{
+ uchar *p = x;
+
+ return p[1]<<8 | p[0];
+}
+
+static void
+hnputs(void *x, ushort v)
+{
+ uchar *p = x;
+
+ p[0] = (v>>8) & 0xFF;
+ p[1] = v & 0xFF;
+}
+
+static ushort
+nhgets(void *x)
+{
+ uchar *p = x;
+
+ return p[0]<<8 | p[1];
+}
+
+enum {
+ ANY_SRC_IP = 0x0001,
+ ANY_SRC_PORT = 0x0002,
+ ANY_DEST_IP = 0x0004,
+ ANY_DEST_PORT = 0x0008,
+ USE_FILTER = 0x0010,
+ MAY_FRAGMENT = 0x0020,
+};
+
+static int
+udpread(EFI_IP_ADDRESS *sip, EFI_IP_ADDRESS *dip,
+ EFI_PXE_BASE_CODE_UDP_PORT *sport,
+ EFI_PXE_BASE_CODE_UDP_PORT dport,
+ int *len, void *data)
+{
+ UINTN size;
+
+ size = *len;
+ if(eficall(pxe->UdpRead, pxe, (UINTN)ANY_SRC_PORT, dip, &dport, sip, sport, nil, nil, &size, data))
+ return -1;
+
+ *len = size;
+ return 0;
+}
+
+static int
+udpwrite(EFI_IP_ADDRESS *dip,
+ EFI_PXE_BASE_CODE_UDP_PORT sport,
+ EFI_PXE_BASE_CODE_UDP_PORT dport,
+ int len, void *data)
+{
+ UINTN size;
+
+ size = len;
+ if(eficall(pxe->UdpWrite, pxe, (UINTN)MAY_FRAGMENT, dip, &dport, nil, nil, &sport, nil, nil, &size, data))
+ return -1;
+
+ return 0;
+}
+
+static int
+pxeread(void *f, void *data, int len)
+{
+ Tftp *t = f;
+ int seq, n;
+
+ while(!t->eof && t->rp >= t->ep){
+ for(;;){
+ n = sizeof(t->pkt);
+ if(udpread(&t->dip, &t->sip, &t->dport, t->sport, &n, t->pkt))
+ continue;
+ if(n >= 4)
+ break;
+ }
+ switch(nhgets(t->pkt)){
+ case Tftp_DATA:
+ seq = nhgets(t->pkt+2);
+ if(seq > t->seq){
+ putc('?');
+ continue;
+ }
+ hnputs(t->pkt, Tftp_ACK);
+ while(udpwrite(&t->dip, t->sport, t->dport, 4, t->pkt))
+ putc('!');
+ if(seq < t->seq){
+ putc('@');
+ continue;
+ }
+ t->seq = seq+1;
+ n -= 4;
+ t->rp = t->pkt + 4;
+ t->ep = t->rp + n;
+ t->eof = n < Segsize;
+ break;
+ case Tftp_ERROR:
+ print(t->pkt+4);
+ print("\n");
+ default:
+ t->eof = 1;
+ return -1;
+ }
+ break;
+ }
+ n = t->ep - t->rp;
+ if(len > n)
+ len = n;
+ memmove(data, t->rp, len);
+ t->rp += len;
+ return len;
+}
+
+static void
+pxeclose(void *f)
+{
+ Tftp *t = f;
+ t->eof = 1;
+}
+
+
+static int
+tftpopen(Tftp *t, char *path)
+{
+ static EFI_PXE_BASE_CODE_UDP_PORT xport = 6666;
+ int r, n;
+ char *p;
+
+ t->sport = xport++;
+ t->dport = 0;
+ t->rp = t->ep = 0;
+ t->seq = 1;
+ t->eof = 0;
+ t->nul = 0;
+ p = t->pkt;
+ hnputs(p, Tftp_READ); p += 2;
+ n = strlen(path)+1;
+ memmove(p, path, n); p += n;
+ memmove(p, "octet", 6); p += 6;
+ n = p - t->pkt;
+ for(;;){
+ if(r = udpwrite(&t->dip, t->sport, TftpPort, n, t->pkt))
+ break;
+ if(r = pxeread(t, 0, 0))
+ break;
+ return 0;
+ }
+ pxeclose(t);
+ return r;
+}
+
+static void*
+pxeopen(char *name)
+{
+ static uchar buf[sizeof(Tftp)+8];
+ Tftp *t = (Tftp*)((uintptr)(buf+7)&~7);
+
+ memset(t, 0, sizeof(Tftp));
+ memmove(&t->sip, myip, sizeof(myip));
+ memmove(&t->dip, serverip, sizeof(serverip));
+ if(tftpopen(t, name))
+ return nil;
+ return t;
+}
+
+static int
+parseipv6(uchar to[16], char *from)
+{
+ int i, dig, elipsis;
+ char *p;
+
+ elipsis = 0;
+ memset(to, 0, 16);
+ for(i = 0; i < 16; i += 2){
+ dig = 0;
+ for(p = from;; p++){
+ if(*p >= '0' && *p <= '9')
+ dig = (dig << 4) | (*p - '0');
+ else if(*p >= 'a' && *p <= 'f')
+ dig = (dig << 4) | (*p - 'a'+10);
+ else if(*p >= 'A' && *p <= 'F')
+ dig = (dig << 4) | (*p - 'A'+10);
+ else
+ break;
+ if(dig > 0xFFFF)
+ return -1;
+ }
+ to[i] = dig>>8;
+ to[i+1] = dig;
+ if(*p == ':'){
+ if(*++p == ':'){ /* :: is elided zero short(s) */
+ if (elipsis)
+ return -1; /* second :: */
+ elipsis = i+2;
+ p++;
+ }
+ } else if (p == from)
+ break;
+ from = p;
+ }
+ if(i < 16){
+ memmove(&to[elipsis+16-i], &to[elipsis], i-elipsis);
+ memset(&to[elipsis], 0, 16-i);
+ }
+ return 0;
+}
+
+static void
+parsedhcp(EFI_PXE_BASE_CODE_DHCPV4_PACKET *dhcp)
+{
+ uchar *p, *e;
+ char *x;
+ int opt;
+ int len;
+ uint type;
+
+ memset(mymac, 0, sizeof(mymac));
+ memset(serverip, 0, sizeof(serverip));
+
+ /* DHCPv4 */
+ if(pxe->Mode->UsingIpv6 == 0){
+ memmove(mymac, dhcp->BootpHwAddr, 6);
+ memmove(serverip, dhcp->BootpSiAddr, 4);
+ return;
+ }
+
+ /* DHCPv6 */
+
+ /*
+ * some UEFI implementations use random UUID based DUID instead of
+ * ethernet address, but use ethernet derived link-local addresses.
+ * so extract the MAC from our IPv6 address as a fallback.
+ */
+ p = pxe->Mode->StationIp;
+ mymac[0] = p[8] ^ 2;
+ mymac[1] = p[9];
+ mymac[2] = p[10];
+ mymac[3] = p[13];
+ mymac[4] = p[14];
+ mymac[5] = p[15];
+
+ e = (uchar*)dhcp + sizeof(*dhcp);
+ p = (uchar*)dhcp + 4;
+ while(p+4 <= e){
+ opt = p[0]<<8 | p[1];
+ len = p[2]<<8 | p[3];
+ p += 4;
+ if(p + len > e)
+ break;
+ switch(opt){
+ case 1: /* Client DUID */
+ if(len < 4+6)
+ break;
+ type = p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3];
+ switch(type){
+ case 0x00010001:
+ case 0x00030001:
+ memmove(mymac, p+len-6, 6);
+ break;
+ }
+ break;
+ case 59: /* Boot File URL */
+ for(x = (char*)p; x < (char*)p+len; x++){
+ if(*x == '['){
+ parseipv6(serverip, x+1);
+ break;
+ }
+ }
+ break;
+ }
+ p += len;
+ }
+}
+
+int
+pxeinit(void **pf)
+{
+ EFI_PXE_BASE_CODE_DHCPV4_PACKET *dhcp;
+ EFI_PXE_BASE_CODE_MODE *mode;
+ EFI_HANDLE *Handles;
+ UINTN Count;
+ int i;
+
+ pxe = nil;
+ Count = 0;
+ Handles = nil;
+ if(eficall(ST->BootServices->LocateHandleBuffer,
+ ByProtocol, &EFI_PXE_BASE_CODE_PROTOCOL_GUID, nil, &Count, &Handles))
+ return -1;
+
+ for(i=0; i<Count; i++){
+ pxe = nil;
+ if(eficall(ST->BootServices->HandleProtocol,
+ Handles[i], &EFI_PXE_BASE_CODE_PROTOCOL_GUID, &pxe))
+ continue;
+ mode = pxe->Mode;
+ if(mode == nil || mode->Started == 0)
+ continue;
+ if(mode->DhcpAckReceived){
+ dhcp = (EFI_PXE_BASE_CODE_DHCPV4_PACKET*)mode->DhcpAck;
+ goto Found;
+ }
+ if(mode->PxeReplyReceived){
+ dhcp = (EFI_PXE_BASE_CODE_DHCPV4_PACKET*)mode->PxeReply;
+ goto Found;
+ }
+ }
+ return -1;
+
+Found:
+ parsedhcp(dhcp);
+ memmove(myip, mode->StationIp, 16);
+
+ open = pxeopen;
+ read = pxeread;
+ close = pxeclose;
+
+ if(pf != nil){
+ char ini[24];
+
+ memmove(ini, "/cfg/pxe/", 9);
+ for(i=0; i<6; i++){
+ ini[9+i*2+0] = hex[mymac[i] >> 4];
+ ini[9+i*2+1] = hex[mymac[i] & 0xF];
+ }
+ ini[9+12] = '\0';
+ if((*pf = pxeopen(ini)) == nil)
+ *pf = pxeopen("/cfg/pxe/default");
+ }
+
+ return 0;
+}
--- /dev/null
+++ b/os/boot/efi/sub.c
@@ -1,0 +1,373 @@
+#include <u.h>
+#include <a.out.h>
+#include "fns.h"
+#include "mem.h"
+
+char hex[] = "0123456789abcdef";
+
+void
+print(char *s)
+{
+ while(*s != 0){
+ if(*s == '\n')
+ putc('\r');
+ putc(*s++);
+ }
+}
+
+int
+readn(void *f, void *data, int len)
+{
+ uchar *p, *e;
+
+ p = data;
+ e = p + len;
+ while(p < e){
+ if((len = read(f, p, e - p)) <= 0)
+ break;
+ p += len;
+ }
+
+ return p - (uchar*)data;
+}
+
+void
+memmove(void *dst, void *src, int n)
+{
+ uchar *d = dst;
+ uchar *s = src;
+
+ if(d < s){
+ while(n-- > 0)
+ *d++ = *s++;
+ } else if(d > s){
+ s += n;
+ d += n;
+ while(n-- > 0)
+ *--d = *--s;
+ }
+}
+
+int
+memcmp(void *src, void *dst, int n)
+{
+ uchar *d = dst;
+ uchar *s = src;
+ int r = 0;
+
+ while(n-- > 0){
+ r = *d++ - *s++;
+ if(r != 0)
+ break;
+ }
+
+ return r;
+}
+
+int
+strlen(char *s)
+{
+ char *p = s;
+
+ while(*p != '\0')
+ p++;
+
+ return p - s;
+}
+
+char*
+strchr(char *s, int c)
+{
+ for(; *s != 0; s++)
+ if(*s == c)
+ return s;
+
+ return nil;
+}
+
+void
+memset(void *dst, int v, int n)
+{
+ uchar *d = dst;
+
+ while(n > 0){
+ *d++ = v;
+ n--;
+ }
+}
+
+static int
+readline(void *f, char *buf)
+{
+ static char white[] = "\t ";
+ char *p;
+
+ p = buf;
+ do{
+ if(f == nil)
+ putc('>');
+ for(;;){
+ if(f == nil){
+ while((*p = getc()) == 0)
+ ;
+ if(p == buf && (*p == '\b' || strchr(white, *p) != nil))
+ continue;
+ putc(*p);
+ if(*p == '\r')
+ putc('\n');
+ else if(*p == '\b'){
+ p--;
+ putc(' ');
+ putc('\b');
+ continue;
+ }
+ }else if(read(f, p, 1) <= 0)
+ return 0;
+ if(strchr("\r\n", *p) != nil)
+ break;
+ if(p == buf && strchr(white, *p) != nil)
+ continue; /* whitespace on start of line */
+ p++;
+ }
+ while(p > buf && strchr(white, p[-1]))
+ p--;
+ }while(p == buf);
+ *p = 0;
+
+ return p - buf;
+}
+
+static int
+timeout(int ms)
+{
+ while(ms > 0){
+ if(getc() != 0)
+ return 1;
+ usleep(100000);
+ ms -= 100;
+ }
+ return 0;
+}
+
+#define BOOTLINE ((char*)CONFADDR)
+#define BOOTLINELEN 64
+#define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN))
+#define BOOTARGSLEN (4096-0x200-BOOTLINELEN)
+
+char *confend;
+
+static char*
+getconf(char *s, char *buf)
+{
+ char *p, *e;
+ int n;
+
+ n = strlen(s);
+ for(p = BOOTARGS; p < confend; p = e+1){
+ for(e = p+1; e < confend; e++)
+ if(*e == '\n')
+ break;
+ if(memcmp(p, s, n) == 0){
+ p += n;
+ n = e - p;
+ buf[n] = 0;
+ memmove(buf, p, n);
+ return buf;
+ }
+ }
+ return nil;
+}
+
+static int
+delconf(char *s)
+{
+ char *p, *e;
+
+ for(p = BOOTARGS; p < confend; p = e){
+ for(e = p+1; e < confend; e++){
+ if(*e == '\n'){
+ e++;
+ break;
+ }
+ }
+ if(memcmp(p, s, strlen(s)) == 0){
+ memmove(p, e, confend - e);
+ confend -= e - p;
+ *confend = 0;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+char*
+configure(void *f, char *path)
+{
+ char *line, *kern, *s, *p;
+ int inblock, nowait, n;
+ static int once = 1;
+
+ if(once){
+ once = 0;
+Clear:
+ memset(BOOTLINE, 0, BOOTLINELEN);
+
+ confend = BOOTARGS;
+ memset(confend, 0, BOOTARGSLEN);
+ eficonfig(&confend);
+ }
+ nowait = 1;
+ inblock = 0;
+Loop:
+ while(readline(f, line = confend+1) > 0){
+ if(*line == 0 || strchr("#;=", *line) != nil)
+ continue;
+ if(*line == '['){
+ inblock = memcmp("[common]", line, 8) != 0;
+ continue;
+ }
+ if(memcmp("boot", line, 5) == 0){
+ nowait=1;
+ break;
+ }
+ if(memcmp("wait", line, 5) == 0){
+ nowait=0;
+ continue;
+ }
+ if(memcmp("show", line, 5) == 0){
+ print(BOOTARGS);
+ continue;
+ }
+ if(memcmp("clear", line, 5) == 0){
+ if(line[5] == '\0'){
+ print("ok\n");
+ goto Clear;
+ } else if(line[5] == ' ' && delconf(line+6))
+ print("ok\n");
+ continue;
+ }
+ if(inblock != 0 || (p = strchr(line, '=')) == nil)
+ continue;
+ *p++ = 0;
+ delconf(line);
+ s = confend;
+ memmove(confend, line, n = strlen(line)); confend += n;
+ *confend++ = '=';
+ memmove(confend, p, n = strlen(p)); confend += n;
+ *confend++ = '\n';
+ *confend = 0;
+ print(s);
+ }
+ kern = getconf("bootfile=", path);
+
+ if(f != nil){
+ close(f);
+ f = nil;
+
+ if(kern != nil && (nowait==0 || timeout(1000)))
+ goto Loop;
+ }
+
+ if(kern == nil){
+ print("no bootfile\n");
+ goto Loop;
+ }
+ while((p = strchr(kern, '!')) != nil)
+ kern = p+1;
+
+ return kern;
+}
+
+static char*
+numfmt(char *s, ulong b, ulong i, ulong a)
+{
+ char *r;
+
+ if(i == 0){
+ ulong v = a;
+ while(v != 0){
+ v /= b;
+ i++;
+ }
+ if(i == 0)
+ i = 1;
+ }
+
+ s += i;
+ r = s;
+ while(i > 0){
+ *--s = hex[a % b];
+ a /= b;
+ i--;
+ }
+ return r;
+}
+
+char*
+hexfmt(char *s, int i, uvlong a)
+{
+ if(i > 8 || i == 0 && (a>>32) != 0){
+ s = numfmt(s, 16, i ? i-8 : 0, a>>32);
+ i = 8;
+ }
+ return numfmt(s, 16, i, a);
+}
+
+char*
+decfmt(char *s, int i, ulong a)
+{
+ return numfmt(s, 10, i, a);
+}
+
+static ulong
+beswal(ulong l)
+{
+ uchar *p = (uchar*)&l;
+ return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+}
+
+char*
+bootkern(void *f)
+{
+ uchar *e, *d, *t;
+ ulong n;
+ Exec ex;
+
+ if(readn(f, &ex, sizeof(ex)) != sizeof(ex))
+ return "bad header";
+
+ e = (uchar*)(beswal(ex.entry) & ~0xF0000000UL);
+ switch(beswal(ex.magic)){
+ case S_MAGIC:
+ if(readn(f, e, 8) != 8)
+ goto Error;
+ case I_MAGIC:
+ break;
+ default:
+ return "bad magic";
+ }
+
+ t = e;
+ n = beswal(ex.text);
+ if(readn(f, t, n) != n)
+ goto Error;
+ t += n;
+ d = (uchar*)PGROUND((uintptr)t);
+ memset(t, 0, d - t);
+ n = beswal(ex.data);
+ if(readn(f, d, n) != n)
+ goto Error;
+ d += n;
+ t = (uchar*)PGROUND((uintptr)d);
+ t += PGROUND(beswal(ex.bss));
+ memset(d, 0, t - d);
+
+ close(f);
+ print("boot\n");
+ unload();
+
+ jump(e);
+
+Error:
+ return "i/o error";
+}
--- /dev/null
+++ b/os/boot/mkfile
@@ -1,0 +1,23 @@
+ARCH=\
+ bitsy\
+ efi\
+ pc\
+ zynq\
+
+all:V:
+ for(i in $ARCH)@{
+ cd $i
+ mk
+ }
+
+installall install:V:
+ for(i in $ARCH) @{
+ cd $i
+ mk install
+ }
+
+clean:V:
+ for(i in $ARCH) @{
+ cd $i
+ mk clean
+ }
--- /dev/null
+++ b/os/boot/pc/a20.s
@@ -1,0 +1,84 @@
+#include "x16.h"
+
+#undef ORB
+
+TEXT a20test(SB), $0
+ LONG $1234567
+
+TEXT a20check(SB), $0
+ MOVL $10000, CX
+_loop:
+ LEAL a20test(SB), AX
+ MOVL (AX), BX
+ ADDL $12345, BX
+ MOVL BX, (AX)
+ ORL $(1<<20), AX
+ MOVL (AX), AX
+ CMPL AX, BX
+ JNZ _done
+ LOOP _loop
+ RET
+_done:
+ /* return directly to caller of a20() */
+ ADDL $4, SP
+ XORL AX, AX
+ RET
+
+TEXT a20(SB), $0
+ CALL a20check(SB)
+
+ /* try bios */
+ CALL rmode16(SB)
+ STI
+ LWI(0x2401, rAX)
+ BIOSCALL(0x15)
+ CALL16(pmode32(SB))
+
+ CALL a20check(SB)
+
+ /* try fast a20 */
+ MOVL $0x92, DX
+ INB
+ TESTB $2, AL
+ JNZ _no92
+ ORB $2, AL
+ ANDB $0xfe, AL
+ OUTB
+_no92:
+ CALL a20check(SB)
+
+ /* try keyboard */
+ CALL kbdempty(SB)
+ MOVL $0x64, DX
+ MOVB $0xd1, AL /* command write */
+ OUTB
+ CALL kbdempty(SB)
+ MOVL $0x60, DX
+ MOVB $0xdf, AL /* a20 on */
+ OUTB
+ CALL kbdempty(SB)
+ MOVL $0x64, DX
+ MOVB $0xff, AL /* magic */
+ OUTB
+ CALL kbdempty(SB)
+
+ CALL a20check(SB)
+
+ /* fail */
+ XORL AX, AX
+ DECL AX
+ RET
+
+TEXT kbdempty(SB), $0
+_kbdwait:
+ MOVL $0x64, DX
+ INB
+ TESTB $1, AL
+ JZ _kbdempty
+ MOVL $0x60, DX
+ INB
+ JMP _kbdwait
+_kbdempty:
+ TESTB $2, AL
+ JNZ _kbdwait
+ RET
--- /dev/null
+++ b/os/boot/pc/apm.s
@@ -1,0 +1,51 @@
+#include "x16.h"
+#include "mem.h"
+
+TEXT apm(SB), $0
+ MOVL id+4(SP), BX
+ CALL rmode16(SB)
+
+ PUSHR(rBX)
+ LWI(0x5300, rAX)
+ BIOSCALL(0x15)
+ POPR(rBX)
+ JC noapm
+
+ PUSHR(rBX)
+ LWI(0x5304, rAX)
+ BIOSCALL(0x15)
+ POPR(rBX)
+ CLC
+
+ /* connect */
+ LWI(0x5303, rAX)
+ BIOSCALL(0x15)
+ JC noapm
+
+ OPSIZE; PUSHR(rSI)
+ OPSIZE; PUSHR(rBX)
+ PUSHR(rDI)
+ PUSHR(rDX)
+ PUSHR(rCX)
+ PUSHR(rAX)
+
+ LWI(CONFADDR, rDI)
+
+ /*
+ * write APM data. first four bytes are APM\0.
+ */
+ LWI(0x5041, rAX)
+ STOSW
+
+ LWI(0x004d, rAX)
+ STOSW
+
+ LWI(8, rCX)
+apmmove:
+ POPR(rAX)
+ STOSW
+ LOOP apmmove
+
+noapm:
+ CALL16(pmode32(SB))
+ RET
--- /dev/null
+++ b/os/boot/pc/e820.s
@@ -1,0 +1,32 @@
+#include "x16.h"
+#include "mem.h"
+
+TEXT e820(SB), $0
+ MOVL bx+4(SP), BX
+ MOVL p+8(SP), DI
+ MOVL $0xE820, AX
+ MOVL $0x534D4150, DX
+ CALL rmode16(SB)
+ LWI(24, rCX)
+ BIOSCALL(0x15)
+ JC _bad
+ CALL16(pmode32(SB))
+ CMPB CL, $24
+ JZ _ret
+ MOVL $1, AX
+ MOVL p+8(SP), DI
+ MOVL AX, 20(DI)
+_ret:
+ MOVL BX, AX
+ RET
+_bad:
+ CALL16(pmode32(SB))
+ XORL AX, AX
+ MOVL p+8(SP), DI
+ MOVL AX, 0(DI)
+ MOVL AX, 4(DI)
+ MOVL AX, 8(DI)
+ MOVL AX, 12(DI)
+ MOVL AX, 16(DI)
+ MOVL AX, 20(DI)
+ RET
--- /dev/null
+++ b/os/boot/pc/fat.c
@@ -1,0 +1,405 @@
+#include <u.h>
+#include "fns.h"
+
+#define GETSHORT(p) (*(ushort *)(p))
+#define GETLONG(p) (*(uint *)(p))
+
+enum {
+ Sectsz = 0x200,
+ Dirsz = 0x20,
+ Maxpath = 64,
+ Fat12 = 1,
+ Fat16 = 2,
+ Fat32 = 4,
+};
+
+typedef struct File File;
+typedef struct Dir Dir;
+typedef struct Pbs Pbs;
+typedef struct Pbs32 Pbs32;
+typedef struct Fat Fat;
+
+struct Fat
+{
+ ulong ver;
+ int drive;
+ ulong clustsize;
+ ulong eofmark;
+ ulong partlba;
+ ulong fatlba;
+ ulong dirstart; /* LBA for FAT16, cluster for FAT32 */
+ ulong dirents;
+ ulong datalba;
+};
+
+struct File
+{
+ Fat *fat;
+ ulong lba;
+ ulong clust;
+ ulong lbaoff;
+ ulong len;
+ uchar *rp;
+ uchar *ep;
+ uchar buf[Sectsz];
+};
+
+struct Dir
+{
+ char name[11];
+ uchar attr;
+ uchar reserved;
+ uchar ctime;
+ uchar ctime[2];
+ uchar cdate[2];
+ uchar adate[2];
+ uchar starthi[2];
+ uchar mtime[2];
+ uchar mdate[2];
+ uchar startlo[2];
+ uchar len[4];
+};
+
+struct Pbs
+{
+ uchar magic[3];
+ uchar version[8];
+ uchar sectsize[2];
+ uchar clustsize;
+ uchar nreserv[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 type[8];
+};
+
+struct Pbs32
+{
+ uchar common[36];
+ uchar fatsize[4];
+ uchar flags[2];
+ uchar ver[2];
+ uchar rootclust[4];
+ uchar fsinfo[2];
+ uchar bootbak[2];
+ uchar reserved0[12];
+ uchar driveno;
+ uchar reserved1;
+ uchar bootsig;
+ uchar volid[4];
+ uchar label[11];
+ uchar type[8];
+};
+
+int readsect(ulong drive, ulong lba, void *buf);
+
+void
+unload(void)
+{
+}
+
+static ulong
+readnext(File *fp, ulong clust)
+{
+ Fat *fat = fp->fat;
+ uchar tmp[2], *p;
+ ulong idx, lba;
+
+ if(fat->ver == Fat12)
+ idx = (3*clust)/2;
+ else
+ idx = clust*fat->ver;
+ lba = fat->fatlba + (idx / Sectsz);
+ if(readsect(fat->drive, lba, fp->buf))
+ memset(fp->buf, 0xff, Sectsz);
+ p = &fp->buf[idx % Sectsz];
+ if(p == &fp->buf[Sectsz-1]){
+ tmp[0] = *p;
+ if(readsect(fat->drive, ++lba, fp->buf))
+ memset(fp->buf, 0xff, Sectsz);
+ tmp[1] = fp->buf[0];
+ p = tmp;
+ }
+ if(fat->ver == Fat32)
+ return GETLONG(p) & 0xfffffff;
+ idx = GETSHORT(p);
+ if(fat->ver == Fat12){
+ if(clust & 1)
+ idx >>= 4;
+ idx &= 0xfff;
+ }
+ return idx;
+}
+
+int
+read(void *f, void *data, int len)
+{
+ File *fp = f;
+ Fat *fat = fp->fat;
+
+ if(fp->len > 0 && fp->rp >= fp->ep){
+ if(fp->clust != ~0U){
+ if(fp->lbaoff % fat->clustsize == 0){
+ if(fp->clust < 2 || fp->clust >= fat->eofmark)
+ return -1;
+ fp->lbaoff = (fp->clust - 2) * fat->clustsize;
+ fp->clust = readnext(fp, fp->clust);
+ fp->lba = fp->lbaoff + fat->datalba;
+ }
+ fp->lbaoff++;
+ }
+ if(readsect(fat->drive, fp->lba++, fp->rp = fp->buf))
+ return -1;
+ }
+ if(fp->len < len)
+ len = fp->len;
+ if(len > (fp->ep - fp->rp))
+ len = fp->ep - fp->rp;
+ memmove(data, fp->rp, len);
+ fp->rp += len;
+ fp->len -= len;
+ return len;
+}
+
+void
+close(void *)
+{
+}
+
+static int
+dirname(Dir *d, char buf[Maxpath])
+{
+ char c, *x;
+
+ if(d->attr == 0x0F || *d->name <= 0)
+ return -1;
+ memmove(buf, d->name, 8);
+ x = buf+8;
+ while(x > buf && x[-1] == ' ')
+ x--;
+ if(d->name[8] != ' '){
+ *x++ = '.';
+ memmove(x, d->name+8, 3);
+ x += 3;
+ }
+ while(x > buf && x[-1] == ' ')
+ x--;
+ *x = 0;
+ x = buf;
+ while(c = *x){
+ if(c >= 'A' && c <= 'Z'){
+ c -= 'A';
+ c += 'a';
+ }
+ *x++ = c;
+ }
+ return x - buf;
+}
+
+static ulong
+dirclust(Dir *d)
+{
+ return *((ushort*)d->starthi)<<16 | *((ushort*)d->startlo);
+}
+
+static void
+fileinit(File *fp, Fat *fat, ulong lba)
+{
+ fp->fat = fat;
+ fp->lba = lba;
+ fp->len = 0;
+ fp->lbaoff = 0;
+ fp->clust = ~0U;
+ fp->rp = fp->ep = fp->buf + Sectsz;
+}
+
+static int
+fatwalk(File *fp, Fat *fat, char *path)
+{
+ char name[Maxpath], *end;
+ int i, j;
+ Dir d;
+
+ if(fat->ver == Fat32){
+ fileinit(fp, fat, 0);
+ fp->clust = fat->dirstart;
+ fp->len = ~0U;
+ }else{
+ fileinit(fp, fat, fat->dirstart);
+ fp->len = fat->dirents * Dirsz;
+ }
+ for(;;){
+ if(readn(fp, &d, Dirsz) != Dirsz)
+ break;
+ if((i = dirname(&d, name)) <= 0)
+ continue;
+ while(*path == '/')
+ path++;
+ if((end = strchr(path, '/')) == 0)
+ end = path + strlen(path);
+ j = end - path;
+ if(i == j && memcmp(name, path, j) == 0){
+ fileinit(fp, fat, 0);
+ fp->clust = dirclust(&d);
+ fp->len = GETLONG(d.len);
+ if(*end == 0)
+ return 0;
+ else if(d.attr & 0x10){
+ fp->len = fat->clustsize * Sectsz;
+ path = end;
+ continue;
+ }
+ break;
+ }
+ }
+ return -1;
+}
+
+static int
+conffat(Fat *fat, void *buf)
+{
+ Pbs *p = buf;
+ uint fatsize, volsize, datasize, reserved;
+ uint ver, dirsize, dirents, clusters;
+
+ if(GETSHORT(p->sectsize) != Sectsz)
+ return -1;
+ if(memcmp(p->type, "FAT", 3) && memcmp(((Pbs32*)buf)->type, "FAT", 3))
+ return -1;
+
+ /* load values from fat */
+ ver = 0;
+ fatsize = GETSHORT(p->fatsize);
+ if(fatsize == 0){
+ fatsize = GETLONG(((Pbs32*)buf)->fatsize);
+ ver = Fat32;
+ }
+ volsize = GETSHORT(p->volsize);
+ if(volsize == 0)
+ volsize = GETLONG(p->bigvolsize);
+ reserved = GETSHORT(p->nreserv);
+ dirents = GETSHORT(p->rootsize);
+ dirsize = (dirents * Dirsz + Sectsz - 1) / Sectsz;
+ datasize = volsize - (reserved + fatsize * p->nfats + dirsize);
+ clusters = datasize / p->clustsize;
+ if(ver != Fat32)
+ if(clusters < 0xff7)
+ ver = Fat12;
+ else
+ ver = Fat16;
+
+ /* fill FAT descriptor */
+ fat->ver = ver;
+ fat->dirents = dirents;
+ fat->clustsize = p->clustsize;
+ fat->fatlba = fat->partlba + reserved;
+ fat->dirstart = fat->fatlba + fatsize * p->nfats;
+ if(ver == Fat32){
+ fat->datalba = fat->dirstart;
+ fat->dirstart = GETLONG(((Pbs32*)buf)->rootclust);
+ fat->eofmark = 0xffffff7;
+ }else{
+ fat->datalba = fat->dirstart + dirsize;
+ if(ver == Fat16)
+ fat->eofmark = 0xfff7;
+ else
+ fat->eofmark = 0xff7;
+ }
+ return 0;
+}
+
+static int
+findfat(Fat *fat, int drive, ulong xbase, ulong lba)
+{
+ struct {
+ uchar status;
+ uchar bchs[3];
+ uchar typ;
+ uchar echs[3];
+ uchar lba[4];
+ uchar len[4];
+ } p[4];
+ uchar buf[Sectsz];
+ int i;
+
+ if(xbase == 0)
+ xbase = lba;
+ if(readsect(drive, lba, buf))
+ return -1;
+ if(buf[0x1fe] != 0x55 || buf[0x1ff] != 0xAA)
+ return -1;
+ if(lba == 0 && (drive & 0x80) == 0){ /* floppy */
+ fat->drive = drive;
+ fat->partlba = 0;
+ if(!conffat(fat, buf))
+ return 0;
+ }
+ memmove(p, &buf[0x1be], sizeof(p));
+ for(i=0; i<4; i++){
+ switch(p[i].typ){
+ case 0x05:
+ case 0x0f:
+ case 0x85:
+ /* extended partitions */
+ if(!findfat(fat, drive, xbase, xbase + GETLONG(p[i].lba)))
+ return 0;
+ /* no break */
+ case 0x00:
+ continue;
+ default:
+ if(p[i].status != 0x80)
+ continue;
+ case 0x39: /* always try plan9 partition */
+ fat->drive = drive;
+ fat->partlba = lba + GETLONG(p[i].lba);
+ if(readsect(drive, fat->partlba, buf))
+ continue;
+ if(!conffat(fat, buf))
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void
+start(void *sp)
+{
+ char path[Maxpath], *kern;
+ int drive;
+ File fi;
+ Fat fat;
+ void *f;
+
+ /* drive passed in DL */
+ drive = ((ushort*)sp)[5] & 0xFF;
+
+ if(findfat(&fat, drive, 0, 0)){
+ print("no fat\n");
+ halt();
+ }
+ if(fatwalk(f = &fi, &fat, "plan9.ini")){
+ print("no config\n");
+ f = 0;
+ }
+ for(;;){
+ kern = configure(f, path); f = 0;
+ if(fatwalk(&fi, &fat, kern)){
+ print("not found\n");
+ continue;
+ }
+ print(bootkern(&fi));
+ print("\n");
+ }
+}
+
--- /dev/null
+++ b/os/boot/pc/fns.h
@@ -1,0 +1,46 @@
+/* handy strings in l.s */
+extern char origin[];
+extern char uart;
+extern char hex[];
+extern char bootname[];
+
+/* l.s */
+void start(void *sp);
+void cgaputc(int c);
+int kbdgetc(void);
+void usleep(int t);
+void halt(void);
+void jump(void *pc);
+
+int read(void *f, void *data, int len);
+int readn(void *f, void *data, int len);
+void close(void *f);
+void unload(void);
+
+int getc(void);
+void putc(int c);
+
+void memset(void *p, int v, int n);
+void memmove(void *dst, void *src, int n);
+int memcmp(void *src, void *dst, int n);
+int strlen(char *s);
+char *strchr(char *s, int c);
+char *strrchr(char *s, int c);
+void print(char *s);
+
+char *configure(void *f, char *path);
+char *bootkern(void *f);
+
+/* a20.s */
+int a20(void);
+
+/* e820.s */
+ulong e820(ulong bx, void *p);
+
+/* apm.s */
+void apm(int id);
+
+/* uart.s */
+void uartinit(int p, int c);
+void uartputc(int p, int c);
+int uartgetc(int p);
--- /dev/null
+++ b/os/boot/pc/iso.c
@@ -1,0 +1,196 @@
+#include <u.h>
+#include "fns.h"
+
+enum {
+ Sectsz = 0x800,
+ Maxpath = 256,
+ Dirsz = 33,
+};
+
+typedef struct Extend Extend;
+typedef struct Dir Dir;
+
+struct Extend
+{
+ int drive;
+ ulong lba;
+ ulong len;
+ uchar *rp;
+ uchar *ep;
+ uchar buf[Sectsz];
+};
+
+struct Dir
+{
+ uchar dirlen;
+ uchar extlen;
+
+ uchar lba[8];
+ uchar len[8];
+
+ uchar date[7];
+
+ uchar flags[3];
+
+ uchar seq[4];
+
+ uchar namelen;
+};
+
+int readsect(ulong drive, ulong lba, void *buf);
+
+#ifdef FAT
+int
+readsect4(ulong drive, ulong lba, void *buf)
+{
+ int i;
+
+ lba *= Sectsz/512;
+ for(i = 0; i<Sectsz/512; i++){
+ if(readsect(drive, lba++, buf))
+ return -1;
+ buf = (uchar*)buf + 512;
+ }
+ return 0;
+}
+#define readsect readsect4
+#endif
+
+void
+unload(void)
+{
+}
+
+int
+read(void *f, void *data, int len)
+{
+ Extend *ex = f;
+
+ if(ex->len > 0 && ex->rp >= ex->ep)
+ if(readsect(ex->drive, ex->lba++, ex->rp = ex->buf))
+ return -1;
+ if(ex->len < len)
+ len = ex->len;
+ if(len > (ex->ep - ex->rp))
+ len = ex->ep - ex->rp;
+ memmove(data, ex->rp, len);
+ ex->rp += len;
+ ex->len -= len;
+ return len;
+}
+
+void
+close(void *f)
+{
+ Extend *ex = f;
+
+ ex->drive = 0;
+ ex->lba = 0;
+ ex->len = 0;
+ ex->rp = ex->ep = ex->buf + Sectsz;
+}
+
+static int
+isowalk(Extend *ex, int drive, char *path)
+{
+ char name[Maxpath], c, *end;
+ int i;
+ Dir d;
+
+ close(ex);
+ ex->drive = drive;
+
+ /* find pvd */
+ for(i=0x10; i<0x1000; i++){
+ if(readsect(drive, i, ex->buf))
+ return -1;
+ if(*ex->buf == 1)
+ break;
+ }
+ ex->lba = *((ulong*)(ex->buf + 156 + 2));
+ ex->len = *((ulong*)(ex->buf + 156 + 10));
+
+ for(;;){
+ if(readn(ex, &d, Dirsz) != Dirsz)
+ break;
+ if(d.dirlen == 0)
+ break;
+ if(readn(ex, name, d.namelen) != d.namelen)
+ break;
+ i = d.dirlen - (Dirsz + d.namelen);
+ while(i-- > 0)
+ read(ex, &c, 1);
+ for(i=0; i<d.namelen; i++){
+ c = name[i];
+ if(c >= 'A' && c <= 'Z'){
+ c -= 'A';
+ c += 'a';
+ }
+ name[i] = c;
+ }
+ name[i] = 0;
+ while(*path == '/')
+ path++;
+ if((end = strchr(path, '/')) == 0)
+ end = path + strlen(path);
+ i = end - path;
+ if(d.namelen == i && memcmp(name, path, i) == 0){
+ ex->rp = ex->ep;
+ ex->lba = *((ulong*)d.lba);
+ ex->len = *((ulong*)d.len);
+ if(*end == 0)
+ return 0;
+ else if(d.flags[0] & 2){
+ path = end;
+ continue;
+ }
+ break;
+ }
+ }
+ close(ex);
+ return -1;
+}
+
+void
+start(void *sp)
+{
+ char path[Maxpath], *kern;
+ int drive;
+ Extend ex;
+ void *f;
+
+ /* drive passed in DL */
+ drive = ((ushort*)sp)[5] & 0xFF;
+
+#ifndef FAT
+ /*
+ * load full bootblock as only the frist 2K get
+ * loaded from bios. the code is specially arranged
+ * to have all the important routines in the first
+ * 2K of the 9bootiso image. (strings have been
+ * placed in l.s to make sure they will be < 2K)
+ */
+ if(isowalk(&ex, drive, bootname)){
+ print(bootname);
+ putc('?');
+ halt();
+ }
+ readn(&ex, origin, ex.len);
+ close(&ex);
+#endif
+
+ if(isowalk(f = &ex, drive, "/cfg/plan9.ini")){
+ print("no config\n");
+ f = 0;
+ }
+ for(;;){
+ kern = configure(f, path); f = 0;
+ if(isowalk(&ex, drive, kern)){
+ print("not found\n");
+ continue;
+ }
+ print(bootkern(&ex));
+ print("\n");
+ }
+}
+
--- /dev/null
+++ b/os/boot/pc/l.s
@@ -1,0 +1,299 @@
+#include "x16.h"
+#include "mem.h"
+
+#undef ORB
+
+#define DATA32SEL SELECTOR(1, SELGDT, 0)
+#define EXEC32SEL SELECTOR(2, SELGDT, 0)
+#define DATA16SEL SELECTOR(3, SELGDT, 0)
+#define EXEC16SEL SELECTOR(4, SELGDT, 0)
+
+#define SEGSS BYTE $0x36
+#define SEGES BYTE $0x26
+#define FARRET BYTE $0xCB
+
+TEXT origin(SB), $0
+ CLI
+ CLR(rCX)
+ MTSR(rCX, rSS)
+ OPSIZE; MOVL $origin(SB), SP
+ PUSHA
+ OPSIZE; ADSIZE; PUSHL SP
+ OPSIZE; ADSIZE; PUSHL CX
+ PUSHI(start(SB))
+
+TEXT pmode32(SB), $0
+ CLI
+
+ /* get return pc */
+ POPR(rDI)
+
+ /* make sure stack is at 0000: */
+ CLR(rCX)
+ MTSR(rCX, rSS)
+ OPSIZE; ANDL $0xFFFF, SP
+
+ /* convert 16-bit return pc to far pointer */
+ PUSHI(EXEC32SEL)
+ PUSHR(rDI)
+
+ /* load gdt */
+ SEGSS; LGDT(tgdtptr(SB))
+
+ /* enable protected mode */
+ MFCR(rCR0, rCX)
+ ORB $1, CL
+ MTCR(rCX, rCR0)
+
+ /* flush */
+ FARJUMP16(EXEC16SEL, pmode32flush(SB));
+TEXT pmode32flush(SB), $0
+
+ /* load 32-bit protected mode data selector */
+ LWI(DATA32SEL, rCX)
+
+_segret:
+ /* load all data segments */
+ MTSR(rCX, rDS)
+ MTSR(rCX, rES)
+ MTSR(rCX, rFS)
+ MTSR(rCX, rGS)
+ MTSR(rCX, rSS)
+ FARRET
+
+TEXT rmode16(SB), $0
+ /* setup farret to rmode16x */
+ PUSHL $EXEC16SEL
+ PUSHL $rmode16x(SB)
+
+ /* load 16-bit protected mode data selector */
+ MOVL $DATA16SEL, CX
+ JMP _segret
+
+TEXT rmode16x(SB), $0
+ /* disable protected mode */
+ MFCR(rCR0, rCX)
+ ANDB $0xfe, CL
+ MTCR(rCX, rCR0)
+
+ /* flush */
+ FARJUMP16(0, rmode16flush(SB));
+TEXT rmode16flush(SB), $0
+
+ /*
+ * load 16-bit realmode data segment 0000: and
+ * return to 32 bit return pc interpreted
+ * as 16 bit far pointer.
+ */
+ CLR(rCX)
+ JMP _segret
+
+TEXT tgdt(SB), $0
+ /* null descriptor */
+ LONG $0
+ LONG $0
+
+ /* data segment descriptor for 4 gigabytes (PL 0) */
+ LONG $(0xFFFF)
+ LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
+
+ /* exec segment descriptor for 4 gigabytes (PL 0) */
+ LONG $(0xFFFF)
+ LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
+
+ /* data segment descriptor for (PL 0) 16-bit */
+ LONG $(0xFFFF)
+ LONG $((0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
+
+ /* exec segment descriptor for (PL 0) 16-bit */
+ LONG $(0xFFFF)
+ LONG $((0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
+
+TEXT tgdtptr(SB), $0
+ WORD $(5*8)
+ LONG $tgdt(SB)
+
+TEXT jump(SB), $0
+ MOVL 4(SP), AX
+ JMP *AX
+
+TEXT halt(SB), $0
+_halt:
+ JMP _halt
+
+TEXT kbdgetc(SB), $0
+ CALL rmode16(SB)
+ STI
+ MOVB $0x01, AH
+ BIOSCALL(0x16)
+ JNZ _gotkey
+ CLR(rAX)
+ JMP _pret32
+_gotkey:
+ CLR(rAX)
+ BIOSCALL(0x16)
+ JMP _pret32
+
+TEXT cgaputc(SB), $0
+ MOVL 4(SP),AX
+ CALL rmode16(SB)
+ STI
+ MOVB $0x0E, AH
+ BIOSCALL(0x10)
+_pret32:
+ CALL16(pmode32(SB))
+ ANDL $0xFFFF, AX
+ RET
+
+TEXT usleep(SB), $0
+ MOVL t+4(SP), AX
+ PUSHL AX
+ CALL rmode16(SB)
+ STI
+ POPR(rDX)
+ POPR(rCX)
+ MOVB $0x86, AH
+ BIOSCALL(0x15)
+ JMP _pret32
+
+#ifdef PXE
+
+TEXT pxeinit(SB), $0
+ CALL rmode16(SB)
+
+ /* get pxe env structure in ES:BX */
+ LWI(0x5650, rAX)
+ BIOSCALL(0x1A)
+ JC _pret32
+
+ /* !PXE or PXEENV+ signature */
+ SEGES; LXW(0, xBX, rAX)
+ CMPI((('!'<<0)|('P'<<8)), rAX)
+ JEQ _getentry
+ CMPI((('P'<<0)|('X'<<8)), rAX)
+ JNE _pret32
+
+ SEGES; LXW(0x2A, xBX, rAX)
+ SEGES; LXW(0x28, xBX, rBX)
+ MTSR(rAX, rES)
+
+_getentry:
+ SEGES; LXW(0x12, xBX, rAX)
+ SW(rAX, pxepseg(SB))
+ SEGES; LXW(0x10, xBX, rAX)
+ SW(rAX, pxepoff(SB))
+ CLR(rAX)
+ JMP _pret32
+
+TEXT pxecallret(SB), $0
+ ADDI(6, rSP)
+ JMP _pret32
+
+TEXT pxecall(SB), $0
+ MOVL op+4(SP),AX
+ MOVL buf+8(SP),SI
+ CALL rmode16(SB)
+
+ CLR(rCX)
+ PUSHR(rCX)
+ PUSHR(rSI)
+
+ /* opcode */
+ PUSHR(rAX)
+
+ /* farcall */
+ PUSHR(rCX)
+ PUSHI(pxecallret(SB))
+
+ LW(pxepseg(SB), rAX)
+ PUSHR(rAX)
+ LW(pxepoff(SB), rAX)
+ PUSHR(rAX)
+
+ STI
+
+ CLR(rAX)
+ CLR(rBX)
+ CLR(rCX)
+ CLR(rDX)
+ CLR(rDI)
+ CLR(rSI)
+ FARRET
+
+TEXT pxepseg(SB), $0
+ WORD $0
+TEXT pxepoff(SB), $0
+ WORD $0
+
+#else /* PXE */
+
+/*
+ * in:
+ * DL drive
+ * AX:BX lba32,
+ * 0000:SI buffer
+ */
+TEXT readsect16(SB), $0
+ PUSHA
+ CLR(rCX)
+
+ PUSHR(rCX) /* qword lba */
+ PUSHR(rCX)
+ PUSHR(rBX)
+ PUSHR(rAX)
+
+ PUSHR(rCX) /* dword buffer */
+ PUSHR(rSI)
+
+ INC(rCX)
+ PUSHR(rCX) /* word # of sectors */
+
+ PUSHI(0x0010) /* byte reserved, byte packet size */
+
+ MW(rSP, rSI)
+ LWI(0x4200, rAX)
+ BIOSCALL(0x13)
+ JCC _readok
+ ADDI(0x10, rSP)
+ POPA
+ CLR(rAX)
+ DEC(rAX)
+ RET
+_readok:
+ ADDI(0x10, rSP)
+ POPA
+ CLR(rAX)
+ RET
+
+TEXT readsect(SB), $0
+ MOVL 4(SP), DX
+ MOVW 8(SP), AX
+ MOVW 10(SP), BX
+ MOVL 12(SP), SI
+ CALL rmode16(SB)
+ STI
+ CALL16(readsect16(SB))
+ CALL16(pmode32(SB))
+ ANDL $0xFFFF, AX
+ RET
+
+#endif
+
+#ifdef ISO
+
+TEXT bootname(SB), $0
+ BYTE $'3'; BYTE $'8'; BYTE $'6'; BYTE $'/';
+ BYTE $'9'; BYTE $'b'; BYTE $'o'; BYTE $'o';
+ BYTE $'t'; BYTE $'i'; BYTE $'s'; BYTE $'o';
+ BYTE $0
+
+#endif
+
+TEXT uart(SB), $0
+ BYTE $0xff
+
+TEXT hex(SB), $0
+ BYTE $'0'; BYTE $'1'; BYTE $'2'; BYTE $'3';
+ BYTE $'4'; BYTE $'5'; BYTE $'6'; BYTE $'7';
+ BYTE $'8'; BYTE $'9'; BYTE $'a'; BYTE $'b';
+ BYTE $'c'; BYTE $'d'; BYTE $'e'; BYTE $'f'
--- /dev/null
+++ b/os/boot/pc/mbr.s
@@ -1,0 +1,259 @@
+/*
+ * Hard disc boot block. Loaded at 0x7C00, relocates to 0x0600:
+ * 8a mbr.s; 8l -o mbr -l -H3 -T0x0600 mbr.8
+ */
+#include "x16.h"
+#include "mem.h"
+
+/*#define FLOPPY 1 /* test on a floppy */
+#define TRACE(C) PUSHA;\
+ CLR(rBX);\
+ MOVB $C, AL;\
+ LBI(0x0E, rAH);\
+ BIOSCALL(0x10);\
+ POPA
+
+/*
+ * We keep data on the stack, indexed by BP.
+ */
+#define Xdap 0x00 /* disc address packet */
+#define Xtable 0x10 /* partition table entry */
+#define Xdrive 0x12 /* starting disc */
+#define Xtotal 0x14 /* sum of allocated data above */
+
+/*
+ * Start: loaded at 0000:7C00, relocate to 0000:0600.
+ * Boot drive is in rDL.
+ */
+TEXT _start(SB), $0
+ CLI
+ CLR(rAX)
+ MTSR(rAX, rSS) /* 0000 -> rSS */
+ LWI((0x7C00-Xtotal), rSP) /* 7Bxx -> rSP */
+ MW(rSP, rBP) /* set the indexed-data pointer */
+
+ MTSR(rAX, rDS) /* 0000 -> rDS, source segment */
+ LWI(0x7C00, rSI) /* 7C00 -> rSI, source offset */
+ MTSR(rAX, rES) /* 0000 -> rES, destination segment */
+ LWI(0x600, rDI) /* 0600 -> rDI, destination offset */
+ LWI(0x100, rCX) /* 0100 -> rCX, loop count (words) */
+
+ CLD
+ REP; MOVSL /* MOV DS:[(E)SI] -> ES:[(E)DI] */
+
+ FARJUMP16(0x0000, _start0600(SB))
+
+TEXT _start0600(SB), $0
+#ifdef FLOPPY
+ LBI(0x80, rDL)
+#else
+ CLRB(rAL) /* some systems pass 0 */
+ CMPBR(rAL, rDL)
+ JNE _save
+ LBI(0x80, rDL)
+#endif /* FLOPPY */
+_save:
+ SXB(rDL, Xdrive, xBP) /* save disc */
+
+ LWI(confidence(SB), rSI) /* for that warm, fuzzy feeling */
+ CALL16(BIOSputs(SB))
+
+ LWI(_start+0x01BE(SB), rSI) /* address of partition table */
+ LWI(0x04, rCX) /* 4 entries in table */
+ LBI(0x80, rAH) /* active entry value */
+ CLRB(rAL) /* inactive entry value */
+
+_activeloop0:
+ LXB(0x00, xSI, rBL) /* get active entry from table */
+ CMPBR(rBL, rAH) /* is this an active entry? */
+ JEQ _active
+
+ CMPBR(rBL, rAL) /* if not active it should be 0 */
+ JNE _invalidMBR
+
+ ADDI(0x10, rSI) /* next table entry */
+ DEC(rCX)
+ JNE _activeloop0
+
+ LWI(noentry(SB), rSI)
+ CALL16(buggery(SB))
+
+_active:
+ MW(rSI, rDI) /* save table address */
+
+_activeloop1:
+ ADDI(0x10, rSI) /* next table entry */
+ DEC(rCX)
+ JEQ _readsector
+
+ LXB(0x00, xSI, rBL) /* get active entry from table */
+ CMPBR(rBL, rAH) /* is this an active entry? */
+ JNE _activeloop1 /* should only be one active */
+
+_invalidMBR:
+ LWI(invalidMBR(SB), rSI)
+ CALL16(buggery(SB))
+
+_readsector:
+ LBI(0x41, rAH) /* check extensions present */
+ LWI(0x55AA, rBX)
+ LXB(Xdrive, xBP, rDL) /* drive */
+ BIOSCALL(0x13) /* CF set on failure */
+ JCS _readsector2
+ CMPI(0xAA55, rBX)
+ JNE _readsector2
+ ANDI(0x0001, rCX)
+ JEQ _readsector2
+
+_readsector42:
+ SBPBI(0x10, Xdap+0) /* packet size */
+ SBPBI(0x00, Xdap+1) /* reserved */
+ SBPBI(0x01, Xdap+2) /* number of blocks to transfer */
+ SBPBI(0x00, Xdap+3) /* reserved */
+ SBPWI(0x7C00, Xdap+4) /* transfer buffer :offset */
+ SBPWI(0x0000, Xdap+6) /* transfer buffer seg: */
+ LXW(0x08, xDI, rAX) /* LBA (64-bits) */
+ SBPW(rAX, Xdap+8)
+ LXW(0x0A, xDI, rAX)
+ SBPW(rAX, Xdap+10)
+ SBPWI(0x0000, Xdap+12)
+ SBPWI(0x0000, Xdap+14)
+
+ MW(rBP, rSI) /* disk address packet */
+ LBI(0x42, rAH) /* extended read */
+ BIOSCALL(0x13) /* CF set on failure */
+ JCC _readsectorok
+
+ LWI(ioerror(SB), rSI)
+ CALL16(buggery(SB))
+
+/*
+ * Read a sector from a disc using the traditional BIOS call.
+ * For BIOSCALL(0x13/AH=0x02):
+ * rAH 0x02
+ * rAL number of sectors to read (1)
+ * rCH low 8 bits of cylinder
+ * rCL high 2 bits of cylinder (7-6), sector (5-0)
+ * rDH head
+ * rDL drive
+ * rES:rBX buffer address
+ */
+_readsector2:
+ LXB(0x01, xDI, rDH) /* head */
+ LXW(0x02, xDI, rCX) /* save active cylinder/sector */
+
+ LWI(0x0201, rAX) /* read one sector */
+ LXB(Xdrive, xBP, rDL) /* drive */
+ LWI(0x7C00, rBX) /* buffer address (rES already OK) */
+ BIOSCALL(0x13) /* CF set on failure */
+ JCC _readsectorok
+
+ LWI(ioerror(SB), rSI)
+ CALL16(buggery(SB))
+
+_readsectorok:
+ LWI(0x7C00, rBX) /* buffer address (rES already OK) */
+ LXW(0x1FE, xBX, rAX)
+ CMPI(0xAA55, rAX)
+ JNE _bbnotok
+
+ /*
+ * Jump to the loaded PBS.
+ * rDL and rSI should still contain the drive
+ * and partition table pointer respectively.
+ */
+ MW(rDI, rSI)
+ FARJUMP16(0x0000, 0x7C00)
+
+_bbnotok:
+ LWI(invalidPBS(SB), rSI)
+
+TEXT buggery(SB), $0
+ CALL16(BIOSputs(SB))
+ LWI(reboot(SB), rSI)
+ CALL16(BIOSputs(SB))
+
+_wait:
+ CLR(rAX) /* wait for any key */
+ BIOSCALL(0x16)
+
+_reset:
+ CLR(rBX) /* set ES segment for BIOS area */
+ MTSR(rBX, rES)
+
+ LWI(0x0472, rBX) /* warm-start code address */
+ LWI(0x1234, rAX) /* warm-start code */
+ POKEW /* MOVW AX, ES:[BX] */
+
+ FARJUMP16(0xFFFF, 0x0000) /* reset */
+
+/*
+ * Output a string to the display.
+ * String argument is in rSI.
+ */
+TEXT BIOSputs(SB), $0
+ PUSHA
+ CLR(rBX)
+_BIOSputs:
+ LODSB
+ ORB(rAL, rAL)
+ JEQ _BIOSputsret
+
+ LBI(0x0E, rAH)
+ BIOSCALL(0x10)
+ JMP _BIOSputs
+
+_BIOSputsret:
+ POPA
+ RET
+
+/* "No active entry in MBR" */
+TEXT noentry(SB), $0
+ BYTE $'N'; BYTE $'o'; BYTE $' '; BYTE $'a';
+ BYTE $'c'; BYTE $'t'; BYTE $'i'; BYTE $'v';
+ BYTE $'e'; BYTE $' '; BYTE $'e'; BYTE $'n';
+ BYTE $'t'; BYTE $'r'; BYTE $'y'; BYTE $' ';
+ BYTE $'i'; BYTE $'n'; BYTE $' '; BYTE $'M';
+ BYTE $'B'; BYTE $'R';
+ BYTE $'\z';
+
+/* "Invalid MBR" */
+TEXT invalidMBR(SB), $0
+ BYTE $'I'; BYTE $'n'; BYTE $'v'; BYTE $'a';
+ BYTE $'l'; BYTE $'i'; BYTE $'d'; BYTE $' ';
+ BYTE $'M'; BYTE $'B'; BYTE $'R';
+ BYTE $'\z';
+
+/* "I/O error" */
+TEXT ioerror(SB), $0
+ BYTE $'I'; BYTE $'/'; BYTE $'O'; BYTE $' ';
+ BYTE $'e'; BYTE $'r'; BYTE $'r'; BYTE $'o';
+ BYTE $'r';
+ BYTE $'\z';
+
+/* "Invalid PBS" */
+TEXT invalidPBS(SB), $0
+ BYTE $'I'; BYTE $'n'; BYTE $'v'; BYTE $'a';
+ BYTE $'l'; BYTE $'i'; BYTE $'d'; BYTE $' ';
+ BYTE $'P'; BYTE $'B'; BYTE $'S';
+ BYTE $'\z';
+
+/* "\r\nPress almost any key to reboot..." */
+TEXT reboot(SB), $0
+ BYTE $'\r';BYTE $'\n';
+ BYTE $'P'; BYTE $'r'; BYTE $'e'; BYTE $'s';
+ BYTE $'s'; BYTE $' '; BYTE $'a'; BYTE $'l';
+ BYTE $'m'; BYTE $'o'; BYTE $'s'; BYTE $'t';
+ BYTE $' '; BYTE $'a'; BYTE $'n'; BYTE $'y';
+ BYTE $' '; BYTE $'k'; BYTE $'e'; BYTE $'y';
+ BYTE $' '; BYTE $'t'; BYTE $'o'; BYTE $' ';
+ BYTE $'r'; BYTE $'e'; BYTE $'b'; BYTE $'o';
+ BYTE $'o'; BYTE $'t'; BYTE $'.'; BYTE $'.';
+ BYTE $'.';
+ BYTE $'\z';
+
+/* "MBR..." */
+TEXT confidence(SB), $0
+ BYTE $'M'; BYTE $'B'; BYTE $'R'; BYTE $'.';
+ BYTE $'.'; BYTE $'.';
+ BYTE $'\z';
--- /dev/null
+++ b/os/boot/pc/mem.h
@@ -1,0 +1,46 @@
+/*
+ * 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))
+
+/*
+ * Fundamental addresses
+ */
+#define CONFADDR 0x1200 /* info passed from boot loader */
+#define BIOSXCHG 0x6000 /* To exchange data with the BIOS */
+
+#define SELGDT (0<<3) /* selector is in gdt */
+#define SELLDT (1<<3) /* selector is in ldt */
+
+#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p))
+
+/*
+ * fields in segment descriptors
+ */
+#define SEGDATA (0x10<<8) /* data/stack segment */
+#define SEGEXEC (0x18<<8) /* executable segment */
+#define SEGTSS (0x9<<8) /* TSS segment */
+#define SEGCG (0x0C<<8) /* call gate */
+#define SEGIG (0x0E<<8) /* interrupt gate */
+#define SEGTG (0x0F<<8) /* task gate */
+#define SEGTYPE (0x1F<<8)
+
+#define SEGP (1<<15) /* segment present */
+#define SEGPL(x) ((x)<<13) /* priority level */
+#define SEGB (1<<22) /* granularity 1==4k (for expand-down) */
+#define SEGG (1<<23) /* granularity 1==4k (for other) */
+#define SEGE (1<<10) /* expand down */
+#define SEGW (1<<9) /* writable (for data/stack) */
+#define SEGR (1<<9) /* readable (for code) */
+#define SEGD (1<<22) /* default 1==32bit (for code) */
+
--- /dev/null
+++ b/os/boot/pc/mkfile
@@ -1,0 +1,107 @@
+objtype=386
+</$objtype/mkfile
+BIN=/386
+
+TARG=9bootiso 9bootpxe 9bootfat 9boothyb mbr pbs
+
+HFILES=mem.h fns.h x16.h
+
+all: 9bootiso 9bootpxe 9bootfat 9boothyb mbr pbs
+
+clean:V:
+ rm -rf $TARG *.$O test.* tmp
+
+liso.$O: l.s
+ $AS -DISO -o $target l.s
+
+lpxe.$O: l.s
+ $AS -DPXE -o $target l.s
+
+lfat.$O: l.s
+ $AS -DFAT -o $target l.s
+
+lhyb.$O: l.s
+ $AS -DFAT -o $target l.s
+
+hyb.$O: iso.c
+ $CC $CFLAGS -DFAT -o $target iso.c
+
+%.$O: %.s
+ $AS $stem.s
+
+%.$O: %.c
+ $CC $CFLAGS $stem.c
+
+%.$O: $HFILES
+
+mbr: mbr.$O
+ $LD -o $target -H3 -T0x0600 -l $prereq
+ ls -l $target
+
+pbs: pbs.$O
+ $LD -o $target -H3 -T0x0800 -l $prereq
+ ls -l $target
+
+9boot&: l%.$O %.$O sub.$O apm.$O e820.$O a20.$O uart.$O
+ $LD -o $target -H3 -T0x7c00 -l $prereq
+ ls -l $target
+
+install:V:
+ for (i in $TARG)
+ mk $MKFLAGS $i.install
+
+%.install:V: $BIN/%
+
+
+$BIN/%: %
+ cp $stem $BIN/$stem
+
+test.iso: 9bootiso 9boothyb 9bootfat mbr pbs
+ rm -fr tmp $target
+ mkdir tmp
+ mkdir tmp/386
+ mkdir tmp/cfg
+ cp 9bootiso tmp/386
+ cp /386/9pc tmp/386
+ cp /sys/lib/dist/cfg/plan9.ini tmp/cfg/plan9.ini
+ echo wait >>tmp/cfg/plan9.ini
+ disk/mk9660 -B 386/9bootiso -p <{echo +} -s tmp $target
+ @{rfork n
+ bind 9boothyb 9bootfat
+ dd -if /dev/zero -bs 512 -count 4096 >> $target
+ disk/partfs -m /n/partfs $target
+ disk=/n/partfs/sdXX
+ disk/mbr -m mbr $disk/data
+ @{echo a p1 '$-1' '$'
+ echo t p1 FAT16
+ echo A p1
+ echo w
+ echo q} | disk/fdisk -b $disk/data
+ disk/format -b pbs -d -r 1 $disk/dos 9bootfat
+ }
+ rm -fr tmp
+
+test.dsk: 9bootfat mbr pbs test.iso
+ rm -fr tmp $target
+ mkdir tmp
+ cp test.iso 9bootfat tmp
+ mkdir tmp/386
+ cp /386/9pc tmp/386
+ echo 'bootfile=/386/9pc' >tmp/plan9.ini
+ dd -if /dev/zero -of $target -bs 512 -count 32768
+ disk/partfs -m /n/$target $target
+ disk=/n/$target/sdXX
+ disk/mbr -m mbr $disk/data
+ disk/fdisk -baw $disk/data
+ disk/prep -bw -a 9fat $disk/plan9
+ disk/format -b pbs -d -r 2 $disk/9fat
+ s=$target.dos
+ m=/n/$target.9fat
+ rm -f /srv/$s
+ dossrv -f $disk/9fat $s
+ mount -c /srv/$s $m
+ @{cd tmp; tar c .} | @{cd $m; tar xv}
+ unmount $m
+ rm -f /srv/$s
+ unmount /n/$target
+ rm -fr tmp
--- /dev/null
+++ b/os/boot/pc/pbs.s
@@ -1,0 +1,292 @@
+#include "x16.h"
+#include "mem.h"
+
+#define RELOC 0x7c00
+
+TEXT _magic(SB), $0
+ BYTE $0xEB; BYTE $0x58; /* jmp .+ 0x58 (_start0x5A) */
+ BYTE $0x90 /* nop */
+TEXT _version(SB), $0
+ BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
+ BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
+TEXT _sectsize(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _clustsize(SB), $0
+ BYTE $0x00
+TEXT _nresrv(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _nfats(SB), $0
+ BYTE $0x00
+TEXT _rootsize(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _volsize(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _mediadesc(SB), $0
+ BYTE $0x00
+TEXT _fatsize(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _trksize(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _nheads(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _nhiddenlo(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _nhiddenhi(SB), $0
+ BYTE $0x00; BYTE $0x00;
+TEXT _bigvolsize(SB), $0
+ BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
+/* FAT32 structure, starting @0x24 */
+TEXT _fatsz32lo(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _fatsz32hi(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _extflags(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _fsver(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _rootclust(SB), $0
+ BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
+TEXT _fsinfo(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _bkboot(SB), $0
+ BYTE $0x00; BYTE $0x00
+TEXT _reserved0(SB), $0
+ BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
+ BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
+ BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
+TEXT _driveno(SB), $0
+ BYTE $0x00
+TEXT _reserved1(SB), $0
+ BYTE $0x00
+TEXT _bootsig(SB), $0
+ BYTE $0x00
+TEXT _volid(SB), $0
+ BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
+TEXT _label(SB), $0
+ BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
+ BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
+ BYTE $0x00; BYTE $0x00; BYTE $0x00
+TEXT _type(SB), $0
+ BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
+ BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
+
+_start0x5A:
+ CLI
+ CLR(rAX)
+ MTSR(rAX, rSS) /* 0000 -> rSS */
+ MTSR(rAX, rDS) /* 0000 -> rDS, source segment */
+ MTSR(rAX, rES)
+
+ LWI(0x100, rCX)
+ LWI(RELOC, rSI)
+ MW(rSI, rSP)
+ LWI(_magic(SB), rDI)
+ CLD
+ REP; MOVSL /* MOV DS:[(E)SI] -> ES:[(E)DI] */
+
+ MW(rSP, rBP)
+
+ PUSHR(rCX)
+ PUSHI(start16(SB))
+ BYTE $0xCB /* FAR RET */
+
+TEXT start16(SB), $0
+ STI
+
+ LWI(hello(SB), rSI)
+ CALL16(print16(SB))
+
+ STB(rDL, _driveno(SB))
+
+ CLR(rDX)
+ LW(_fatsize(SB), rAX)
+ CLR(rCX)
+ LB(_nfats(SB), rCL)
+ MUL(rCX)
+ OR(rAX, rAX)
+ JNE _fatszok /* zero? it's FAT32 */
+
+ LW(_fatsz32hi(SB), rBX)
+ IMUL(rCX, rBX)
+ LW(_fatsz32lo(SB), rAX)
+ MUL(rCX)
+ ADD(rBX, rDX)
+
+_fatszok:
+ LW(_nhiddenlo(SB), rCX)
+ ADD(rCX, rAX)
+ LW(_nhiddenhi(SB), rCX)
+ ADC(rCX, rDX)
+
+ CLR(rBX)
+ LW(_nresrv(SB), rCX)
+ ADD(rCX, rAX)
+ ADC(rDX, rBX)
+
+ SW(rAX, _volid(SB)) /* save for later use */
+ SW(rBX, _volid+2(SB))
+
+ PUSHR(rBP)
+ LW(_sectsize(SB), rCX)
+ SUB(rCX, rSP)
+ MW(rSP, rBP)
+ MW(rSP, rSI)
+
+_nextsect:
+ CALL16(readsect16(SB))
+ LW(_sectsize(SB), rCX)
+ SHRI(5, rCX)
+
+_nextdir:
+ PUSHR(rCX)
+ PUSHR(rSI) /* save for later if it matches */
+ LWI(bootname(SB), rDI)
+ LW(bootnamelen(SB), rCX)
+ CLD
+ REP
+ CMPSB
+ POPR(rSI)
+ POPR(rCX)
+ JEQ _found
+ ADDI(0x20, rSI)
+ LOOP _nextdir
+ ADDI(1, rAX)
+ ADC(rCX, rBX)
+ JMP _nextsect
+
+_found:
+ CLR(rBX)
+ LW(_rootsize(SB), rAX) /* calculate and save Xrootsz */
+ LWI(0x20, rCX)
+ MUL(rCX)
+ LW(_sectsize(SB), rCX)
+ DEC(rCX)
+ ADD(rCX, rAX)
+ ADC(rBX, rDX)
+ INC(rCX)
+ DIV(rCX)
+ PUSHR(rAX) /* Xrootsz */
+
+ CLR(rCX)
+ LXW(0x1a, xSI, rAX) /* start cluster low */
+ LXW(0x14, xSI, rBX) /* start cluster high */
+ SUBI(2, rAX) /* cluster -= 2 */
+ SBB(rCX, rBX)
+
+ LB(_clustsize(SB), rCL) /* convert to sectors (AX:DX) */
+ IMUL(rCX, rBX)
+ MUL(rCX)
+ ADD(rBX, rDX)
+
+ LW(_volid(SB), rCX) /* Xrootlo */
+ ADD(rCX, rAX)
+ LW(_volid+2(SB), rCX) /* Xroothi */
+ ADC(rCX, rDX)
+
+ CLR(rBX)
+ POPR(rCX) /* Xrootsz */
+ ADD(rCX, rAX)
+ ADC(rBX, rDX)
+
+ PUSHR(rAX) /* calculate how many sectors to read (CX) */
+ PUSHR(rDX)
+ LXW(0x1c, xSI, rAX)
+ LXW(0x1e, xSI, rDX)
+ LW(_sectsize(SB), rCX)
+ DEC(rCX)
+ ADD(rCX, rAX)
+ ADC(rBX, rDX)
+ INC(rCX)
+ DIV(rCX)
+ MW(rAX, rCX)
+ POPR(rBX)
+ POPR(rAX)
+
+ LWI(RELOC, rSI)
+ PUSHR(rSI) /* entry */
+
+_loadnext:
+ CALL16(readsect16(SB))
+
+ LW(_sectsize(SB), rDX)
+ ADD(rDX, rSI)
+
+ CLR(rDX)
+ ADDI(1, rAX)
+ ADC(rDX, rBX)
+
+ LOOP _loadnext
+
+ LWI(ok(SB), rSI)
+ CALL16(print16(SB))
+
+ LB(_driveno(SB), rDL)
+ CLI
+ RET
+
+TEXT print16(SB), $0
+ PUSHA
+ CLR(rBX)
+_printnext:
+ LODSB
+ ORB(rAL, rAL)
+ JEQ _printret
+ LBI(0x0E, rAH)
+ BIOSCALL(0x10)
+ JMP _printnext
+_printret:
+ POPA
+ RET
+
+/*
+ * in:
+ * AX:BX lba32,
+ * 0000:SI buffer
+ */
+TEXT readsect16(SB), $0
+_retry:
+ PUSHA
+ CLR(rDX)
+
+ PUSHR(rDX) /* qword lba */
+ PUSHR(rDX)
+ PUSHR(rBX)
+ PUSHR(rAX)
+
+ PUSHR(rDX) /* dword buffer */
+ PUSHR(rSI)
+
+ INC(rDX)
+ PUSHR(rDX) /* word # of sectors */
+
+ PUSHI(0x0010) /* byte reserved, byte packet size */
+
+ MW(rSP, rSI)
+ LB(_driveno(SB), rDL)
+ LWI(0x4200, rAX)
+ BIOSCALL(0x13)
+ JCC _readok
+ LWI((0x0E00|'!'), rAX)
+ BIOSCALL(0x10)
+ ADDI(0x10, rSP)
+ POPA
+ JMP _retry
+_readok:
+ LWI((0x0E00|'.'), rAX)
+ BIOSCALL(0x10)
+ ADDI(0x10, rSP)
+ POPA
+ RET
+
+TEXT bootnamelen(SB), $0
+ WORD $8
+TEXT bootname(SB), $0
+ BYTE $'9'; BYTE $'B'; BYTE $'O'; BYTE $'O';
+ BYTE $'T'; BYTE $'F'; BYTE $'A'; BYTE $'T';
+ BYTE $0
+
+TEXT hello(SB), $0
+ BYTE $'p'; BYTE $'b'; BYTE $'s'; BYTE $0
+TEXT ok(SB), $0
+ BYTE $'o'; BYTE $'k'; BYTE $'\r'; BYTE $'\n';
+ BYTE $0
--- /dev/null
+++ b/os/boot/pc/pxe.c
@@ -1,0 +1,362 @@
+#include <u.h>
+#include "fns.h"
+
+enum {
+ Tftp_READ = 1,
+ Tftp_WRITE = 2,
+ Tftp_DATA = 3,
+ Tftp_ACK = 4,
+ Tftp_ERROR = 5,
+ Tftp_OACK = 6,
+
+ TftpPort = 69,
+
+ Segsize = 512,
+ Maxpath = 64,
+};
+
+typedef uchar IP4[4];
+
+typedef struct Tftp Tftp;
+typedef struct Dhcp Dhcp;
+
+struct Tftp
+{
+ IP4 sip;
+ IP4 dip;
+ IP4 gip;
+
+ int sport;
+ int dport;
+
+ char *rp;
+ char *ep;
+
+ int seq;
+ int eof;
+
+ char pkt[2+2+Segsize];
+ char nul;
+};
+
+struct Dhcp
+{
+ uchar opcode;
+ uchar hardware;
+ uchar hardlen;
+ uchar gatehops;
+ uchar ident[4];
+ uchar seconds[2];
+ uchar flags[2];
+ uchar cip[4];
+ uchar yip[4];
+ uchar sip[4];
+ uchar gip[4];
+ uchar mac[16];
+ char sname[64];
+ char bootfile[128];
+};
+
+int pxeinit(void);
+int pxecall(int op, void *buf);
+
+static void*
+unfar(ulong seg, ulong off)
+{
+ return (void*)((off & 0xFFFF) + (seg & 0xFFFF)*16);
+}
+
+static void
+puts(void *x, ushort v)
+{
+ uchar *p = x;
+
+ p[1] = (v>>8) & 0xFF;
+ p[0] = v & 0xFF;
+}
+
+static ushort
+gets(void *x)
+{
+ uchar *p = x;
+
+ return p[1]<<8 | p[0];
+}
+
+static void
+hnputs(void *x, ushort v)
+{
+ uchar *p = x;
+
+ p[0] = (v>>8) & 0xFF;
+ p[1] = v & 0xFF;
+}
+
+static ushort
+nhgets(void *x)
+{
+ uchar *p = x;
+
+ return p[0]<<8 | p[1];
+}
+
+static void
+moveip(IP4 d, IP4 s)
+{
+ memmove(d, s, sizeof(d));
+}
+
+void
+unload(void)
+{
+ struct {
+ uchar status[2];
+ uchar junk[10];
+ } buf;
+ static uchar shutdown[] = { 0x05, 0x070, 0x02, 0 };
+ uchar *o;
+
+ for(o = shutdown; *o; o++){
+ memset(&buf, 0, sizeof(buf));
+ if(pxecall(*o, &buf))
+ break;
+ }
+}
+
+static int
+getip(IP4 yip, IP4 sip, IP4 gip, char mac[16])
+{
+ struct {
+ uchar status[2];
+ uchar pkttype[2];
+ uchar bufsize[2];
+ uchar off[2];
+ uchar seg[2];
+ uchar lim[2];
+ } buf;
+ int i, r;
+ Dhcp *p;
+
+ memset(&buf, 0, sizeof(buf));
+ puts(buf.pkttype, 3);
+
+ if(r = pxecall(0x71, &buf))
+ return -r;
+ if((p = unfar(gets(buf.seg), gets(buf.off))) == 0)
+ return -1;
+ moveip(yip, p->yip);
+ moveip(sip, p->sip);
+ moveip(gip, p->gip);
+ mac[12] = 0;
+ for(i=0; i<6; i++){
+ mac[i*2] = hex[p->mac[i]>>4];
+ mac[i*2+1] = hex[p->mac[i]&15];
+ }
+ return 0;
+}
+
+static int
+udpopen(IP4 sip)
+{
+ struct {
+ uchar status[2];
+ uchar sip[4];
+ } buf;
+
+ puts(buf.status, 0);
+ moveip(buf.sip, sip);
+ return pxecall(0x30, &buf);
+}
+
+static int
+udpclose(void)
+{
+ uchar status[2];
+ puts(status, 0);
+ return pxecall(0x31, status);
+}
+
+static int
+udpread(IP4 sip, IP4 dip, int *sport, int dport, int *len, void *data)
+{
+ struct {
+ uchar status[2];
+ uchar sip[4];
+ uchar dip[4];
+ uchar sport[2];
+ uchar dport[2];
+ uchar len[2];
+ uchar off[2];
+ uchar seg[2];
+ } buf;
+ int r;
+
+ puts(buf.status, 0);
+ moveip(buf.sip, sip);
+ moveip(buf.dip, dip);
+ hnputs(buf.sport, *sport);
+ hnputs(buf.dport, dport);
+ puts(buf.len, *len);
+ puts(buf.off, (long)data);
+ puts(buf.seg, 0);
+ if(r = pxecall(0x32, &buf))
+ return r;
+ moveip(sip, buf.sip);
+ *sport = nhgets(buf.sport);
+ *len = gets(buf.len);
+ return 0;
+}
+
+static int
+udpwrite(IP4 ip, IP4 gw, int sport, int dport, int len, void *data)
+{
+ struct {
+ uchar status[2];
+ uchar ip[4];
+ uchar gw[4];
+ uchar sport[2];
+ uchar dport[2];
+ uchar len[2];
+ uchar off[2];
+ uchar seg[2];
+ } buf;
+
+ puts(buf.status, 0);
+ moveip(buf.ip, ip);
+ moveip(buf.gw, gw);
+ hnputs(buf.sport, sport);
+ hnputs(buf.dport, dport);
+ puts(buf.len, len);
+ puts(buf.off, (long)data);
+ puts(buf.seg, 0);
+ return pxecall(0x33, &buf);
+}
+
+int
+read(void *f, void *data, int len)
+{
+ Tftp *t = f;
+ int seq, n;
+
+ while(!t->eof && t->rp >= t->ep){
+ for(;;){
+ n = sizeof(t->pkt);
+ if(udpread(t->dip, t->sip, &t->dport, t->sport, &n, t->pkt))
+ continue;
+ if(n >= 4)
+ break;
+ }
+ switch(nhgets(t->pkt)){
+ case Tftp_DATA:
+ seq = nhgets(t->pkt+2);
+ if(seq > t->seq){
+ putc('?');
+ continue;
+ }
+ hnputs(t->pkt, Tftp_ACK);
+ while(udpwrite(t->dip, t->gip, t->sport, t->dport, 4, t->pkt))
+ putc('!');
+ if(seq < t->seq){
+ putc('@');
+ continue;
+ }
+ t->seq = seq+1;
+ n -= 4;
+ t->rp = t->pkt + 4;
+ t->ep = t->rp + n;
+ t->eof = n < Segsize;
+ break;
+ case Tftp_ERROR:
+ print(t->pkt+4);
+ print("\n");
+ default:
+ t->eof = 1;
+ return -1;
+ }
+ break;
+ }
+ n = t->ep - t->rp;
+ if(len > n)
+ len = n;
+ memmove(data, t->rp, len);
+ t->rp += len;
+ return len;
+}
+
+void
+close(void *f)
+{
+ Tftp *t = f;
+ t->eof = 1;
+ udpclose();
+}
+
+
+static int
+tftpopen(Tftp *t, char *path, IP4 sip, IP4 dip, IP4 gip)
+{
+ static ushort xport = 6666;
+ int r, n;
+ char *p;
+
+ moveip(t->sip, sip);
+ moveip(t->gip, gip);
+ memset(t->dip, 0, sizeof(t->dip));
+ t->sport = xport++;
+ t->dport = 0;
+ t->rp = t->ep = 0;
+ t->seq = 1;
+ t->eof = 0;
+ t->nul = 0;
+ if(r = udpopen(t->sip))
+ return r;
+ p = t->pkt;
+ hnputs(p, Tftp_READ); p += 2;
+ n = strlen(path)+1;
+ memmove(p, path, n); p += n;
+ memmove(p, "octet", 6); p += 6;
+ n = p - t->pkt;
+ for(;;){
+ if(r = udpwrite(dip, t->gip, t->sport, TftpPort, n, t->pkt))
+ break;
+ if(r = read(t, 0, 0))
+ break;
+ return 0;
+ }
+ close(t);
+ return r;
+}
+
+void
+start(void *)
+{
+ char mac[16], path[Maxpath], *kern;
+ IP4 yip, sip, gip;
+ void *f;
+ Tftp t;
+
+ if(pxeinit()){
+ print("pxe init\n");
+ halt();
+ }
+ if(getip(yip, sip, gip, mac)){
+ print("bad dhcp\n");
+ halt();
+ }
+ memmove(path, "/cfg/pxe/", 9);
+ memmove(path+9, mac, 13);
+ if(tftpopen(f = &t, path, yip, sip, gip))
+ if(tftpopen(f, "/cfg/pxe/default", yip, sip, gip)){
+ print("no config\n");
+ f = 0;
+ }
+ for(;;){
+ kern = configure(f, path); f = 0;
+ if(tftpopen(&t, kern, yip, sip, gip)){
+ print("not found\n");
+ continue;
+ }
+ print(bootkern(&t));
+ print("\n");
+ }
+}
--- /dev/null
+++ b/os/boot/pc/sub.c
@@ -1,0 +1,554 @@
+#include <u.h>
+#include <a.out.h>
+#include "fns.h"
+#include "mem.h"
+
+void
+putc(int c)
+{
+ cgaputc(c);
+ if(uart != -1)
+ uartputc(uart, c);
+}
+
+void
+print(char *s)
+{
+ while(*s != 0){
+ if(*s == '\n')
+ putc('\r');
+ putc(*s++);
+ }
+}
+
+int
+readn(void *f, void *data, int len)
+{
+ uchar *p, *e;
+
+ putc(' ');
+ p = data;
+ e = p + len;
+ while(p < e){
+ if(((ulong)p & 0xF000) == 0){
+ putc('\b');
+ putc(hex[((ulong)p>>16)&0xF]);
+ }
+ if((len = read(f, p, e - p)) <= 0)
+ break;
+ p += len;
+ }
+ putc('\b');
+
+ return p - (uchar*)data;
+}
+
+void
+memmove(void *dst, void *src, int n)
+{
+ uchar *d = dst;
+ uchar *s = src;
+
+ if(d < s){
+ while(n-- > 0)
+ *d++ = *s++;
+ } else if(d > s){
+ s += n;
+ d += n;
+ while(n-- > 0)
+ *--d = *--s;
+ }
+}
+
+int
+memcmp(void *src, void *dst, int n)
+{
+ uchar *d = dst;
+ uchar *s = src;
+ int r = 0;
+
+ while(n-- > 0){
+ r = *d++ - *s++;
+ if(r != 0)
+ break;
+ }
+
+ return r;
+}
+
+int
+strlen(char *s)
+{
+ char *p = s;
+
+ while(*p != '\0')
+ p++;
+
+ return p - s;
+}
+
+char*
+strchr(char *s, int c)
+{
+ for(; *s != 0; s++)
+ if(*s == c)
+ return s;
+
+ return nil;
+}
+
+void
+memset(void *dst, int v, int n)
+{
+ uchar *d = dst;
+
+ while(n > 0){
+ *d++ = v;
+ n--;
+ }
+}
+
+int
+getc(void)
+{
+ int c;
+
+ c = kbdgetc();
+ if(c == 0 && uart != -1)
+ c = uartgetc(uart);
+ return c;
+}
+
+static int
+readline(void *f, char *buf)
+{
+ static char white[] = "\t ";
+ char *p;
+
+ p = buf;
+ do{
+ if(f == nil)
+ putc('>');
+ for(;;){
+ if(f == nil){
+ while((*p = getc()) == 0)
+ ;
+ if(p == buf && (*p == '\b' || strchr(white, *p) != nil))
+ continue;
+ putc(*p);
+ if(*p == '\r')
+ putc('\n');
+ else if(*p == '\b'){
+ p--;
+ putc(' ');
+ putc('\b');
+ continue;
+ }
+ }else if(read(f, p, 1) <= 0)
+ return 0;
+ if(strchr("\r\n", *p) != nil)
+ break;
+ if(p == buf && strchr(white, *p) != nil)
+ continue; /* whitespace on start of line */
+ p++;
+ }
+ while(p > buf && strchr(white, p[-1]))
+ p--;
+ }while(p == buf);
+ *p = 0;
+
+ return p - buf;
+}
+
+static int
+timeout(int ms)
+{
+ while(ms > 0){
+ if(getc() != 0)
+ return 1;
+ usleep(100000);
+ ms -= 100;
+ }
+ return 0;
+}
+
+#define BOOTLINE ((char*)CONFADDR)
+#define BOOTLINELEN 64
+#define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN))
+#define BOOTARGSLEN (4096-0x200-BOOTLINELEN)
+
+char *confend;
+
+static void apmconf(int);
+static void e820conf(void);
+static void ramdiskconf(int);
+static void uartconf(char*);
+
+static char*
+getconf(char *s, char *buf)
+{
+ char *p, *e;
+ int n;
+
+ n = strlen(s);
+ for(p = BOOTARGS; p < confend; p = e+1){
+ for(e = p+1; e < confend; e++)
+ if(*e == '\n')
+ break;
+ if(memcmp(p, s, n) == 0){
+ p += n;
+ n = e - p;
+ buf[n] = 0;
+ memmove(buf, p, n);
+ return buf;
+ }
+ }
+ return nil;
+}
+
+static int
+delconf(char *s)
+{
+ char *p, *e;
+
+ for(p = BOOTARGS; p < confend; p = e){
+ for(e = p+1; e < confend; e++){
+ if(*e == '\n'){
+ e++;
+ break;
+ }
+ }
+ if(memcmp(p, s, strlen(s)) == 0){
+ memmove(p, e, confend - e);
+ confend -= e - p;
+ *confend = 0;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+char*
+configure(void *f, char *path)
+{
+ char *line, *kern, *s, *p;
+ int inblock, nowait, n;
+ static int once = 1;
+
+ if(once){
+ once = 0;
+Clear:
+ memset(BOOTLINE, 0, BOOTLINELEN);
+
+ confend = BOOTARGS;
+ memset(confend, 0, BOOTARGSLEN);
+
+ e820conf();
+ ramdiskconf(0);
+ }
+ nowait = 1;
+ inblock = 0;
+Loop:
+ while(readline(f, line = confend+1) > 0){
+ if(*line == 0 || strchr("#;=", *line) != nil)
+ continue;
+ if(*line == '['){
+ inblock = memcmp("[common]", line, 8) != 0;
+ continue;
+ }
+ if(memcmp("boot", line, 5) == 0){
+ nowait=1;
+ break;
+ }
+ if(memcmp("wait", line, 5) == 0){
+ nowait=0;
+ continue;
+ }
+ if(memcmp("show", line, 5) == 0){
+ print(BOOTARGS);
+ continue;
+ }
+ if(memcmp("clear", line, 5) == 0){
+ if(line[5] == '\0'){
+ print("ok\n");
+ goto Clear;
+ } else if(line[5] == ' ' && delconf(line+6))
+ print("ok\n");
+ continue;
+ }
+ if(inblock != 0 || (p = strchr(line, '=')) == nil)
+ continue;
+ *p++ = 0;
+ delconf(line);
+ if(memcmp("apm", line, 3) == 0){
+ apmconf(line[3] - '0');
+ continue;
+ }
+ if(memcmp("console", line, 8) == 0)
+ uartconf(p);
+
+ s = confend;
+ memmove(confend, line, n = strlen(line)); confend += n;
+ *confend++ = '=';
+ memmove(confend, p, n = strlen(p)); confend += n;
+ *confend++ = '\n';
+ *confend = 0;
+ print(s);
+ }
+ kern = getconf("bootfile=", path);
+
+ if(f != nil){
+ close(f);
+ f = nil;
+
+ if(kern != nil && (nowait==0 || timeout(1000)))
+ goto Loop;
+ }
+
+ if(kern == nil){
+ print("no bootfile\n");
+ goto Loop;
+ }
+ while((p = strchr(kern, '!')) != nil)
+ kern = p+1;
+
+ return kern;
+}
+
+
+static void
+hexfmt(char *s, int i, ulong a)
+{
+ s += i;
+ while(i > 0){
+ *--s = hex[a&15];
+ a >>= 4;
+ i--;
+ }
+}
+
+static void
+addconfx(char *s, int w, ulong v)
+{
+ int n;
+
+ n = strlen(s);
+ memmove(confend, s, n);
+ hexfmt(confend+n, w, v);
+ confend += n+w;
+ *confend = 0;
+}
+
+static void
+apmconf(int id)
+{
+ uchar *a;
+ char *s;
+
+ a = (uchar*)CONFADDR;
+ memset(a, 0, 20);
+
+ apm(id);
+ if(memcmp(a, "APM", 4) != 0)
+ return;
+
+ s = confend;
+
+ addconfx("apm", 1, id);
+ addconfx("=ax=", 4, *((ushort*)(a+4)));
+ addconfx(" ebx=", 8, *((ulong*)(a+12)));
+ addconfx(" cx=", 4, *((ushort*)(a+6)));
+ addconfx(" dx=", 4, *((ushort*)(a+8)));
+ addconfx(" di=", 4, *((ushort*)(a+10)));
+ addconfx(" esi=", 8, *((ulong*)(a+16)));
+
+ *confend++ = '\n';
+ *confend = 0;
+
+ print(s);
+}
+
+static void
+e820conf(void)
+{
+ struct {
+ uvlong base;
+ uvlong len;
+ ulong typ;
+ ulong ext;
+ } e;
+ uvlong v;
+ ulong bx;
+ char *s;
+
+ bx=0;
+ s = confend;
+
+ do{
+ bx = e820(bx, &e);
+ if(e.len != 0 && (e.ext & 3) == 1){
+ if(confend == s){
+ /* single entry <= 1MB is useless */
+ if(bx == 0 && e.typ == 1 && e.len <= 0x100000)
+ break;
+ memmove(confend, "*e820=", 6);
+ confend += 6;
+ }
+ addconfx("", 1, e.typ);
+ v = e.base;
+ addconfx(" 0x", 8, v>>32);
+ addconfx("", 8, v&0xffffffff);
+ v += e.len;
+ addconfx(" 0x", 8, v>>32);
+ addconfx("", 8, v&0xffffffff);
+ *confend++ = ' ';
+ }
+ } while(bx);
+
+ if(confend == s)
+ return;
+
+ *confend++ = '\n';
+ *confend = 0;
+
+ print(s);
+}
+
+static int
+checksum(void *v, int n)
+{
+ uchar *p, s;
+
+ s = 0;
+ p = v;
+ while(n-- > 0)
+ s += *p++;
+ return s;
+}
+
+static void
+ramdiskconf(int id)
+{
+ struct {
+ /* ACPI header */
+ char sig[4];
+ u32int len;
+ uchar revision;
+ uchar csum;
+ char oem_id[6];
+ char oem_table_id[8];
+ u32int oem_revision;
+ char asl_compiler_id[4];
+ u32int asl_compiler_revision;
+
+ u32int safe_hook;
+
+ /* MDI structure */
+ u16int bytes;
+ uchar version_minor;
+ uchar version_major;
+ u32int diskbuf;
+ u32int disksize;
+ u32int cmdline;
+ u32int oldint13;
+ u32int oldint15;
+ u16int olddosmem;
+ uchar bootloaderid;
+ uchar sector_shift;
+ u16int dpt_ptr;
+ } *mbft;
+ int shift;
+ char *s;
+
+#define BDA ((uchar*)0x400)
+ mbft = (void*)((((BDA[0x14]<<8) | BDA[0x13])<<10) - 1024);
+ for(; (ulong)&mbft->sector_shift < 0xA0000; mbft = (void*)((ulong)mbft + 16)){
+ if(memcmp("mBFT", mbft, 4) == 0
+ && mbft->len < 1024 && (uchar*)mbft + mbft->len > &mbft->sector_shift
+ && checksum(mbft, mbft->len) == 0)
+ goto Found;
+ }
+ return;
+Found:
+ shift = mbft->sector_shift;
+ if(shift == 0)
+ shift = 9;
+
+ s = confend;
+ addconfx("ramdisk", 1, id);
+ addconfx("=0x", 8, mbft->diskbuf);
+ addconfx(" 0x", 8, mbft->disksize<<shift);
+ addconfx(" 0x", 8, 1UL<<shift);
+
+ *confend++ = '\n';
+ *confend = 0;
+
+ print(s);
+}
+
+static void
+uartconf(char *s)
+{
+ if(*s >= '0' && *s <= '3'){
+ uart = *s - '0';
+ uartinit(uart, (7<<5) | 3); /* b9660 l8 s1 */
+ } else
+ uart = -1;
+}
+
+static ulong
+beswal(ulong l)
+{
+ uchar *p = (uchar*)&l;
+ return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+}
+
+char*
+bootkern(void *f)
+{
+ uchar *e, *d, *t;
+ ulong n;
+ Exec ex;
+
+ while(a20() < 0)
+ print("a20 enable failed\n");
+
+ if(readn(f, &ex, sizeof(ex)) != sizeof(ex))
+ return "bad header";
+
+ e = (uchar*)(beswal(ex.entry) & ~0xF0000000UL);
+ switch(beswal(ex.magic)){
+ case S_MAGIC:
+ if(readn(f, e, 8) != 8)
+ goto Error;
+ case I_MAGIC:
+ break;
+ default:
+ return "bad magic";
+ }
+
+ t = e;
+ n = beswal(ex.text);
+ if(readn(f, t, n) != n)
+ goto Error;
+ t += n;
+ d = (uchar*)PGROUND((ulong)t);
+ memset(t, 0, d - t);
+ n = beswal(ex.data);
+ if(readn(f, d, n) != n)
+ goto Error;
+ d += n;
+ t = (uchar*)PGROUND((ulong)d);
+ t += PGROUND(beswal(ex.bss));
+ memset(d, 0, t - d);
+
+ close(f);
+ unload();
+
+ print("boot\n");
+
+ jump(e);
+
+Error:
+ return "i/o error";
+}
--- /dev/null
+++ b/os/boot/pc/uart.s
@@ -1,0 +1,35 @@
+#include "x16.h"
+
+TEXT uartinit(SB), $0
+ MOVL c+8(SP), AX
+ MOVB $0x00, AH
+ JMP _uartbios
+
+TEXT uartputc(SB), $0
+ MOVL c+8(SP), AX
+ MOVB $0x01, AH
+ JMP _uartbios
+
+TEXT uartgetc(SB), $0
+ MOVL p+4(SP), DX
+ CALL rmode16(SB)
+ STI
+ MOVB $0x03, AH
+ BIOSCALL(0x14)
+ CALL16(pmode32(SB))
+ ANDL $0x8100, AX
+ MOVL $0x0100, BX
+ CMPL BX, AX
+ JE _uartread
+ XORL AX, AX
+ RET
+_uartread:
+ MOVB $0x02, AH
+_uartbios:
+ MOVL p+4(SP), DX
+ CALL rmode16(SB)
+ STI
+ BIOSCALL(0x14)
+ CALL16(pmode32(SB))
+ ANDL $0xFF, AX
+ RET
--- /dev/null
+++ b/os/boot/pc/x16.h
@@ -1,0 +1,163 @@
+/*
+ * Can't write 16-bit code for 8a without getting into
+ * lots of bother, so define some simple commands and
+ * output the code directly.
+ *
+ * N.B. CALL16(x) kills DI, so don't expect it to be
+ * saved across calls.
+ */
+#define rAX 0 /* rX */
+#define rCX 1
+#define rDX 2
+#define rBX 3
+#define rSP 4 /* SP */
+#define rBP 5 /* BP */
+#define rSI 6 /* SI */
+#define rDI 7 /* DI */
+
+#define rAL 0 /* rL */
+#define rCL 1
+#define rDL 2
+#define rBL 3
+#define rAH 4 /* rH */
+#define rCH 5
+#define rDH 6
+#define rBH 7
+
+#define rES 0 /* rS */
+#define rCS 1
+#define rSS 2
+#define rDS 3
+#define rFS 4
+#define rGS 5
+
+#define xSI 4 /* rI (index) */
+#define xDI 5
+#define xBP 6
+#define xBX 7
+
+#define rCR0 0 /* rC */
+#define rCR2 2
+#define rCR3 3
+#define rCR4 4
+
+#define OP(o, m, ro, rm) BYTE $o; /* op + modr/m byte */ \
+ BYTE $(((m)<<6)|((ro)<<3)|(rm))
+#define OPrm(o, r, m) OP(o, 0x00, r, 0x06); /* general r <-> m */ \
+ WORD $m;
+#define OPrr(o, r0, r1) OP(o, 0x03, r0, r1); /* general r -> r */
+
+#define LW(m, rX) OPrm(0x8B, rX, m) /* m -> rX */
+#define LXW(x, rI, r) OP(0x8B, 0x02, r, rI); /* x(rI) -> r */ \
+ WORD $x
+#define LBPW(x, r) OP(0x8B, 0x02, r, xBP); /* x(rBP) -> r */ \
+ WORD $x
+#define LB(m, rB) OPrm(0x8A, rB, m) /* m -> r[HL] */
+#define LXB(x, rI, r) OP(0x8A, 0x01, r, rI); /* x(rI) -> r */ \
+ BYTE $x
+#define LBPB(x, r) OP(0x8A, 0x01, r, xBP); /* x(rBP) -> r */ \
+ BYTE $x
+#define SW(rX, m) OPrm(0x89, rX, m) /* rX -> m */
+#define SXW(r, x, rI) OP(0x89, 0x02, r, rI); /* r -> x(rI) */ \
+ WORD $x
+#define SBPW(r, x) OP(0x89, 0x02, r, xBP); /* r -> x(rBP) */ \
+ WORD $(x)
+#define SBPWI(i, x) OP(0xC7, 0x01, 0, xBP); /* i -> x(rBP) */ \
+ BYTE $(x); WORD $(i)
+#define STB(rB, m) OPrm(0x88, rB, m) /* rB -> m */
+#define SXB(r, x, rI) OP(0x88, 0x01, r, rI); /* rB -> x(rI) */ \
+ BYTE $x
+#define SBPB(r, x) OP(0x88, 0x01, r, xBP); /* r -> x(rBP) */ \
+ BYTE $x
+#define SBPBI(i, x) OP(0xC6, 0x01, 0, xBP); /* i -> x(rBP) */ \
+ BYTE $(x); BYTE $(i)
+#define LWI(i, rX) BYTE $(0xB8+rX); /* i -> rX */ \
+ WORD $i;
+#define LBI(i, rB) BYTE $(0xB0+rB); /* i -> r[HL] */ \
+ BYTE $i
+
+#define MW(r0, r1) OPrr(0x89, r0, r1) /* r0 -> r1 */
+#define MFSR(rS, rX) OPrr(0x8C, rS, rX) /* rS -> rX */
+#define MTSR(rX, rS) OPrr(0x8E, rS, rX) /* rX -> rS */
+#define MFCR(rC, rX) BYTE $0x0F; /* rC -> rX */ \
+ OP(0x20, 0x03, rC, rX)
+#define MTCR(rX, rC) BYTE $0x0F; /* rX -> rC */ \
+ OP(0x22, 0x03, rC, rX)
+
+#define ADC(r0, r1) OPrr(0x11, r0, r1) /* r0 + r1 -> r1 */
+#define ADD(r0, r1) OPrr(0x01, r0, r1) /* r0 + r1 -> r1 */
+#define ADDI(i, r) OP(0x81, 0x03, 0x00, r);/* i+r -> r */ \
+ WORD $i;
+#define AND(r0, r1) OPrr(0x21, r0, r1) /* r0&r1 -> r1 */
+#define ANDI(i, r) OP(0x81, 0x03, 0x04, r);/* i&r -> r */ \
+ WORD $i;
+#define CLR(r) OPrr(0x31, r, r) /* r^r -> r */
+#define CLRB(r) OPrr(0x30, r, r) /* r^r -> r */
+#define CMP(r0, r1) OPrr(0x39, r0, r1) /* r1-r0 -> flags */
+#define CMPI(i, r) OP(0x81, 0x03, 0x07, r);/* r-i -> flags */ \
+ WORD $i;
+#define CMPBR(r0, r1) OPrr(0x38, r0, r1) /* r1-r0 -> flags */
+#define DEC(r) BYTE $(0x48|r) /* r-1 -> r */
+#define DIV(r) OPrr(0xF7, 0x06, r) /* rDX:rAX/r -> rAX, rDX:rAX%r -> rDX */
+#define INC(r) BYTE $(0x40|r) /* r+1 -> r */
+#define MUL(r) OPrr(0xF7, 0x04, r) /* r*rAX -> rDX:rAX */
+#define IMUL(r0, r1) BYTE $0x0F; /* r0*r1 -> r1 */ \
+ OPrr(0xAF, r1, r0) /* (signed) */
+#define OR(r0, r1) OPrr(0x09, r0, r1) /* r0|r1 -> r1 */
+#define ORB(r0, r1) OPrr(0x08, r0, r1) /* r0|r1 -> r1 */
+#define ORI(i, r) OP(0x81, 0x03, 0x01, r);/* i|r -> r */ \
+ WORD $i;
+#define ROLI(i, r) OPrr(0xC1, 0x00, r); /* r<<>>i -> r */ \
+ BYTE $i;
+#define SHLI(i, r) OPrr(0xC1, 0x04, r); /* r<<i -> r */ \
+ BYTE $i;
+#define SHLBI(i, r) OPrr(0xC0, 0x04, r); /* r<<i -> r */ \
+ BYTE $i;
+#define SHRI(i, r) OPrr(0xC1, 0x05, r); /* r>>i -> r */ \
+ BYTE $i;
+#define SHRBI(i, r) OPrr(0xC0, 0x05, r); /* r>>i -> r */ \
+ BYTE $i;
+#define SBB(r0, r1) OPrr(0x19, r0, r1) /* r1-r0 -> r1 */
+#define SUB(r0, r1) OPrr(0x29, r0, r1) /* r1-r0 -> r1 */
+#define SUBI(i, r) OP(0x81, 0x03, 0x05, r);/* r-i -> r */ \
+ WORD $i;
+
+#define STOSW STOSL
+
+#define CALL16(f) LWI(f, rDI); /* &f -> rDI */ \
+ BYTE $0xFF; /* (*rDI) */ \
+ BYTE $0xD7;
+#define FARJUMP16(s, o) BYTE $0xEA; /* jump to ptr16:16 */ \
+ WORD $o; WORD $s
+#define FARJUMP32(s, o) BYTE $0x66; /* jump to ptr32:16 */ \
+ BYTE $0xEA; LONG $o; WORD $s
+#define DELAY BYTE $0xEB; /* jmp .+2 */ \
+ BYTE $0x00
+#define BIOSCALL(b) INT $b /* INT $b */
+
+#define PEEKW BYTE $0x26; /* MOVW rES:[rBX], rAX */ \
+ BYTE $0x8B; BYTE $0x07
+#define POKEW BYTE $0x26; /* MOVW rAX, rES:[rBX] */ \
+ BYTE $0x89; BYTE $0x07
+#define OUTPORTB(p, d) LBI(d, rAL); /* d -> I/O port p */ \
+ BYTE $0xE6; \
+ BYTE $p; DELAY
+#define PUSHA BYTE $0x60
+#define PUSHR(r) BYTE $(0x50|r) /* r -> (--rSP) */
+#define PUSHS(rS) BYTE $(0x06|((rS)<<3)) /* rS -> (--rSP) */
+#define PUSHI(i) BYTE $0x68; WORD $i; /* i -> --(rSP) */
+#define POPA BYTE $0x61
+#define POPR(r) BYTE $(0x58|r) /* (rSP++) -> r */
+#define POPS(rS) BYTE $(0x07|((rS)<<3)) /* (rSP++) -> r */
+#define NOP BYTE $0x90 /* nop */
+
+#define LGDT(gdtptr) BYTE $0x0F; /* LGDT */ \
+ BYTE $0x01; BYTE $0x16; \
+ WORD $gdtptr
+#define LIDT(idtptr) BYTE $0x0F; /* LIDT */ \
+ BYTE $0x01; BYTE $0x1e; \
+ WORD $idtptr
+
+/* operand size switch. */
+#define OPSIZE BYTE $0x66
+#define ADSIZE BYTE $0x67
--- /dev/null
+++ b/os/boot/zynq/boothead.c
@@ -1,0 +1,71 @@
+#include <u.h>
+#include <libc.h>
+
+char *data;
+uchar head[0x8c0];
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s file\n", argv0);
+ exits("usage");
+}
+
+void
+u32(int n, u32int p)
+{
+ head[n] = p;
+ head[n+1] = p >> 8;
+ head[n+2] = p >> 16;
+ head[n+3] = p >> 24;
+}
+
+u32int
+gu32(int n)
+{
+ return head[n] | head[n+1] << 8 | head[n+2] << 16 | head[n+3] << 24;
+}
+
+void
+main(int argc, char **argv)
+{
+ int fd, sz, i;
+ u32int ck;
+
+ ARGBEGIN {
+ default:
+ usage();
+ } ARGEND;
+
+ if(argc != 1)
+ usage();
+ fd = open(argv[0], OREAD);
+ if(fd < 0)
+ sysfatal("open: %r");
+ sz = seek(fd, 0, 2);
+ if(sz < 0)
+ sysfatal("seek: %r");
+ data = malloc(sz);
+ if(data == nil)
+ sysfatal("malloc: %r");
+ seek(fd, 0, 0);
+ if(readn(fd, data, sz) < sz)
+ sysfatal("read: %r");
+ close(fd);
+ memset(head, 0, sizeof(head));
+
+ u32(0x20, 0xaa995566);
+ u32(0x24, 0x584C4E58);
+ u32(0x30, sizeof(head));
+ u32(0x34, sz);
+ u32(0x40, sz);
+ ck = 0;
+ for(i = 0x20; i < 0x48; i += 4)
+ ck += gu32(i);
+ u32(0x48, ~ck);
+ u32(0xa0, -1);
+
+ write(1, head, sizeof(head));
+ write(1, data, sz);
+ exits(nil);
+}
--- /dev/null
+++ b/os/boot/zynq/dat.h
@@ -1,0 +1,11 @@
+enum {
+ DHCPTIMEOUT = 2000,
+ ARPTIMEOUT = 1000,
+ TFTPTIMEOUT = 10000,
+
+ TZERO = 0x80000,
+ CONFSIZE = 65536,
+ CONF = TZERO - CONFSIZE,
+};
+
+#define nelem(x) (sizeof(x)/sizeof(*(x)))
--- /dev/null
+++ b/os/boot/zynq/ddr.s
@@ -1,0 +1,258 @@
+#define OUTPUT_EN (3<<9)
+#define DCI_EN (7<<4)
+#define INP_VREF (1<<1)
+#define INP_DIFF (2<<1)
+
+TEXT ddriob(SB), $-4
+ WORD $(OUTPUT_EN) // DDRIOB_ADDR0
+ WORD $(OUTPUT_EN) // DDRIOB_ADDR1
+ WORD $(OUTPUT_EN | DCI_EN | INP_VREF) // DDRIOB_DATA0
+ WORD $(OUTPUT_EN | DCI_EN | INP_VREF) // DDRIOB_DATA1
+ WORD $(OUTPUT_EN | DCI_EN | INP_DIFF) // DDRIOB_DIFF0
+ WORD $(OUTPUT_EN | DCI_EN | INP_DIFF) // DDRIOB_DIFF1
+ WORD $(OUTPUT_EN) // DDRIOB_CLOCK
+ WORD $0x0018C61C // DDRIOB_DRIVE_SLEW_ADDR
+ WORD $0x00F9861C // DDRIOB_DRIVE_SLEW_DATA
+ WORD $0x00F9861C // DDRIOB_DRIVE_SLEW_DIFF
+ WORD $0x00F9861C // DDRIOB_DRIVE_SLEW_CLOCK
+ WORD $0xE60 // DDRIOB_DDR_CTRL
+
+TEXT ddrdata(SB), $-4
+ WORD $0XF8006000
+ WORD $0x0001FFFF
+ WORD $0x00000080
+ WORD $0XF8006004
+ WORD $0x1FFFFFFF
+ WORD $0x00081081
+ WORD $0XF8006008
+ WORD $0x03FFFFFF
+ WORD $0x03C0780F
+ WORD $0XF800600C
+ WORD $0x03FFFFFF
+ WORD $0x02001001
+ WORD $0XF8006010
+ WORD $0x03FFFFFF
+ WORD $0x00014001
+ WORD $0XF8006014
+ WORD $0x001FFFFF
+ WORD $0x0004281A
+ WORD $0XF8006018
+ WORD $0xF7FFFFFF
+ WORD $0x44E458D2
+ WORD $0XF800601C
+ WORD $0xFFFFFFFF
+ WORD $0x82023965
+ WORD $0XF8006020
+ WORD $0xFFFFFFFC
+ WORD $0x2B288290
+ WORD $0XF8006024
+ WORD $0x0FFFFFFF
+ WORD $0x0000003C
+ WORD $0XF8006028
+ WORD $0x00003FFF
+ WORD $0x00002007
+ WORD $0XF800602C
+ WORD $0xFFFFFFFF
+ WORD $0x00000008
+ WORD $0XF8006030
+ WORD $0xFFFFFFFF
+ WORD $0x00040970
+ WORD $0XF8006034
+ WORD $0x13FF3FFF
+ WORD $0x00011054
+ WORD $0XF8006038
+ WORD $0x00001FC3
+ WORD $0x00000000
+ WORD $0XF800603C
+ WORD $0x000FFFFF
+ WORD $0x00000777
+ WORD $0XF8006040
+ WORD $0xFFFFFFFF
+ WORD $0xFFF00000
+ WORD $0XF8006044
+ WORD $0x0FFFFFFF
+ WORD $0x0F666666
+ WORD $0XF8006048
+ WORD $0x3FFFFFFF
+ WORD $0x0003C248
+ WORD $0XF8006050
+ WORD $0xFF0F8FFF
+ WORD $0x77010800
+ WORD $0XF8006058
+ WORD $0x0001FFFF
+ WORD $0x00000101
+ WORD $0XF800605C
+ WORD $0x0000FFFF
+ WORD $0x00005003
+ WORD $0XF8006060
+ WORD $0x000017FF
+ WORD $0x0000003E
+ WORD $0XF8006064
+ WORD $0x00021FE0
+ WORD $0x00020000
+ WORD $0XF8006068
+ WORD $0x03FFFFFF
+ WORD $0x00284545
+ WORD $0XF800606C
+ WORD $0x0000FFFF
+ WORD $0x00001610
+ WORD $0XF80060A0
+ WORD $0x00FFFFFF
+ WORD $0x00008000
+ WORD $0XF80060A4
+ WORD $0xFFFFFFFF
+ WORD $0x10200802
+ WORD $0XF80060A8
+ WORD $0x0FFFFFFF
+ WORD $0x0690CB73
+ WORD $0XF80060AC
+ WORD $0x000001FF
+ WORD $0x000001FE
+ WORD $0XF80060B0
+ WORD $0x1FFFFFFF
+ WORD $0x04FFFFFF
+ WORD $0XF80060B4
+ WORD $0x000007FF
+ WORD $0x00000200
+ WORD $0XF80060B8
+ WORD $0x01FFFFFF
+ WORD $0x0020006A
+ WORD $0XF80060C4
+ WORD $0x00000003
+ WORD $0x00000003
+ WORD $0XF80060C4
+ WORD $0x00000003
+ WORD $0x00000000
+ WORD $0XF80060C8
+ WORD $0x000000FF
+ WORD $0x00000000
+ WORD $0XF80060DC
+ WORD $0x00000001
+ WORD $0x00000000
+ WORD $0XF80060F0
+ WORD $0x0000FFFF
+ WORD $0x00000000
+ WORD $0XF80060F4
+ WORD $0x0000000F
+ WORD $0x00000008
+ WORD $0XF8006114
+ WORD $0x000000FF
+ WORD $0x00000000
+ WORD $0XF8006118
+ WORD $0x7FFFFFFF
+ WORD $0x40000001
+ WORD $0XF800611C
+ WORD $0x7FFFFFFF
+ WORD $0x40000001
+ WORD $0XF8006120
+ WORD $0x7FFFFFFF
+ WORD $0x40000001
+ WORD $0XF8006124
+ WORD $0x7FFFFFFF
+ WORD $0x40000001
+ WORD $0XF800612C
+ WORD $0x000FFFFF
+ WORD $0x00000000
+ WORD $0XF8006130
+ WORD $0x000FFFFF
+ WORD $0x00000000
+ WORD $0XF8006134
+ WORD $0x000FFFFF
+ WORD $0x00000000
+ WORD $0XF8006138
+ WORD $0x000FFFFF
+ WORD $0x00000000
+ WORD $0XF8006140
+ WORD $0x000FFFFF
+ WORD $0x00000035
+ WORD $0XF8006144
+ WORD $0x000FFFFF
+ WORD $0x00000035
+ WORD $0XF8006148
+ WORD $0x000FFFFF
+ WORD $0x00000035
+ WORD $0XF800614C
+ WORD $0x000FFFFF
+ WORD $0x00000035
+ WORD $0XF8006154
+ WORD $0x000FFFFF
+ WORD $0x00000080
+ WORD $0XF8006158
+ WORD $0x000FFFFF
+ WORD $0x00000080
+ WORD $0XF800615C
+ WORD $0x000FFFFF
+ WORD $0x00000080
+ WORD $0XF8006160
+ WORD $0x000FFFFF
+ WORD $0x00000075
+ WORD $0XF8006168
+ WORD $0x001FFFFF
+ WORD $0x000000EE
+ WORD $0XF800616C
+ WORD $0x001FFFFF
+ WORD $0x000000E4
+ WORD $0XF8006170
+ WORD $0x001FFFFF
+ WORD $0x000000FC
+ WORD $0XF8006174
+ WORD $0x001FFFFF
+ WORD $0x000000F4
+ WORD $0XF800617C
+ WORD $0x000FFFFF
+ WORD $0x000000C0
+ WORD $0XF8006180
+ WORD $0x000FFFFF
+ WORD $0x000000C0
+ WORD $0XF8006184
+ WORD $0x000FFFFF
+ WORD $0x000000C0
+ WORD $0XF8006188
+ WORD $0x000FFFFF
+ WORD $0x000000B5
+ WORD $0XF8006190
+ WORD $0xFFFFFFFF
+ WORD $0x10040080
+ WORD $0XF8006194
+ WORD $0x000FFFFF
+ WORD $0x00007D02
+ WORD $0XF8006204
+ WORD $0xFFFFFFFF
+ WORD $0x00000000
+ WORD $0XF8006208
+ WORD $0x000F03FF
+ WORD $0x000803FF
+ WORD $0XF800620C
+ WORD $0x000F03FF
+ WORD $0x000803FF
+ WORD $0XF8006210
+ WORD $0x000F03FF
+ WORD $0x000803FF
+ WORD $0XF8006214
+ WORD $0x000F03FF
+ WORD $0x000803FF
+ WORD $0XF8006218
+ WORD $0x000F03FF
+ WORD $0x000003FF
+ WORD $0XF800621C
+ WORD $0x000F03FF
+ WORD $0x000003FF
+ WORD $0XF8006220
+ WORD $0x000F03FF
+ WORD $0x000003FF
+ WORD $0XF8006224
+ WORD $0x000F03FF
+ WORD $0x000003FF
+ WORD $0XF80062A8
+ WORD $0x00000FF7
+ WORD $0x00000000
+ WORD $0XF80062AC
+ WORD $0xFFFFFFFF
+ WORD $0x00000000
+ WORD $0XF80062B0
+ WORD $0x003FFFFF
+ WORD $0x00005125
+ WORD $0xF80062B4
+ WORD $0x003FFFFF
+ WORD $0x000012A8
+ WORD $0
--- /dev/null
+++ b/os/boot/zynq/fns.h
@@ -1,0 +1,15 @@
+void putc(int);
+void puts(char *);
+int netboot(void);
+int mmcboot(void);
+void puthex(u32int);
+void memset(void *, char, int);
+void memcpy(void *, void *, int);
+void print(char *, ...);
+u32int u32get(void *);
+uchar* u32put(uchar *, u32int);
+void jump(void *);
+void sleep(int);
+void timeren(int);
+int timertrig(void);
+void flash(void);
--- /dev/null
+++ b/os/boot/zynq/fsbl.s
@@ -1,0 +1,310 @@
+#include "mem.h"
+
+#define Rb R10
+#define SET(R, V) MOVW $(V), R0 ; MOVW R0, (R)(Rb)
+#define RMW(r, m, v) MOVW (r)(Rb), R0; BIC $(m), R0; ORR $(v), R0; MOVW R0, (r)(Rb)
+
+TEXT _start(SB), $-4
+ WORD $0xea000006
+ MOVW $abort(SB), R15
+ MOVW $abort(SB), R15
+ MOVW $abort(SB), R15
+ MOVW $abort(SB), R15
+ MOVW $abort(SB), R15
+ MOVW $abort(SB), R15
+ MOVW $abort(SB), R15
+
+TEXT reloc(SB), $-4
+ MOVW $(1<<7|1<<6|0x13), R0
+ MOVW R0, CPSR
+ MOVW $STACKTOP, R13
+ MOVW $_start(SB), R0
+ MCR CpMMU, 0, R0, C(12), C(0)
+ MOVW $SLCR_BASE, Rb
+ SET(SLCR_UNLOCK, UNLOCK_KEY)
+ MOVW $0, R0
+ MCR 15, 0, R0, C(8), C(7), 0
+ MCR 15, 0, R0, C(7), C(5), 0
+ MCR 15, 0, R0, C(7), C(5), 6
+ MOVW $0xc5047a, R1
+ MCR 15, 0, R1, C(1), C(0), 0
+ DSB
+ ISB
+ CMP.S $0, R15
+ BL.LT reset(SB)
+
+ MOVW $0xf, R1
+ MOVW $0xffff0000, R3
+ MOVW $0xe58a1910, R0
+ MOVW R0, (R3)
+ MOVW $0xf57ff04f, R0
+ MOVW R0, 4(R3)
+ MOVW $0xf57ff06f, R0
+ MOVW R0, 8(R3)
+ MOVW $0xe28ef000, R0
+ MOVW R0, 12(R3)
+ MOVW $reset(SB), R14
+ DSB
+ ISB
+ MOVW R3, R15
+
+TEXT reset(SB), $-4
+ BL pllsetup(SB)
+ BL miosetup(SB)
+ BL ddrsetup(SB)
+ BL uartsetup(SB)
+ MOVW $SLCR_BASE, Rb
+ SET(SLCR_LOCK, LOCK_KEY)
+// BL memtest(SB)
+ MOVW $setR12(SB), R12
+ BL main(SB)
+ B abort(SB)
+
+TEXT pllsetup(SB), $0
+ MOVW $SLCR_BASE, Rb
+
+ SET(ARM_PLL_CFG, ARM_PLL_CFG_VAL)
+ SET(DDR_PLL_CFG, DDR_PLL_CFG_VAL)
+ SET(IO_PLL_CFG, IO_PLL_CFG_VAL)
+
+ MOVW $(ARM_FDIV | PLL_BYPASS_FORCE), R0
+ MOVW R0, ARM_PLL_CTRL(Rb)
+ ORR $(PLL_RESET), R4
+ MOVW R4, ARM_PLL_CTRL(Rb)
+ MOVW R0, ARM_PLL_CTRL(Rb)
+
+ MOVW $(DDR_FDIV | PLL_BYPASS_FORCE), R0
+ MOVW R0, DDR_PLL_CTRL(Rb)
+ ORR $(PLL_RESET), R4
+ MOVW R4, DDR_PLL_CTRL(Rb)
+ MOVW R0, DDR_PLL_CTRL(Rb)
+
+ MOVW $(IO_FDIV | PLL_BYPASS_FORCE), R0
+ MOVW R0, IO_PLL_CTRL(Rb)
+ ORR $(PLL_RESET), R4
+ MOVW R4, IO_PLL_CTRL(Rb)
+ MOVW R0, IO_PLL_CTRL(Rb)
+
+_pllsetupl:
+ MOVW PLL_STATUS(Rb), R0
+ AND $7, R0
+ CMP.S $7, R0
+ BNE _pllsetupl
+
+ SET(ARM_PLL_CTRL, ARM_FDIV)
+ SET(DDR_PLL_CTRL, DDR_FDIV)
+ SET(IO_PLL_CTRL, IO_FDIV)
+
+ SET(ARM_CLK_CTRL, 0x1f << 24 | CPU_DIV << 8)
+ SET(UART_CLK_CTRL, UART_DIV << 8 | 3)
+ SET(DDR_CLK_CTRL, DDR_DIV3 << 20 | DDR_DIV2 << 26 | 3)
+ SET(DCI_CLK_CTRL, DCI_DIV0 << 8 | DCI_DIV1 << 20 | 1)
+ SET(GEM0_RCLK_CTRL, 1)
+ SET(GEM1_RCLK_CTRL, 0)
+ SET(GEM0_CLK_CTRL, ETH_DIV0 << 8 | ETH_DIV1 << 20 | 1)
+ SET(GEM1_CLK_CTRL, 0)
+ SET(GPIOB_CTRL, VREF_SW_EN)
+ SET(APER_CLK_CTRL, LQSPI_CLK_EN | GPIO_CLK_EN | UART0_CLK_EN | UART1_CLK_EN | I2C0_CLK_EN | SDIO1_CLK_EN | GEM0_CLK_EN | USB0_CLK_EN | USB1_CLK_EN | DMA_CLK_EN)
+ SET(SMC_CLK_CTRL, 0x3C20)
+ SET(LQSPI_CLK_CTRL, QSPI_DIV << 8 | 1)
+ SET(SDIO_CLK_CTRL, SDIO_DIV << 8 | 2)
+ SET(SPI_CLK_CTRL, 0x3F00)
+ SET(CAN_CLK_CTRL, 0x501900)
+ SET(PCAP_CLK_CTRL, PCAP_DIV << 8 | 1)
+ RET
+
+TEXT miosetup(SB), $0
+ MOVW $SLCR_BASE, Rb
+ SET(UART_RST_CTRL, 0xf)
+ SET(UART_RST_CTRL, 0)
+
+ MOVW $miodata(SB), R1
+ ADD $MIO_PIN_0, Rb, R2
+ MOVW $54, R3
+ BL copy(SB)
+
+ MOVW $0, R0
+ MOVW R0, MIO_MST_TRI0(Rb)
+ MOVW R0, MIO_MST_TRI1(Rb)
+ RET
+
+TEXT copy(SB), $0
+_copyl:
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ SUB.S $1, R3
+ BNE _copyl
+ RET
+
+TEXT ddrsetup(SB), $0
+ MOVW $SLCR_BASE, Rb
+ RMW(DDRIOB_DCI_CTRL, DCI_RESET, DCI_RESET)
+ RMW(DDRIOB_DCI_CTRL, DCI_RESET, 0)
+ RMW(DDRIOB_DCI_CTRL, DDRIOB_DCI_CTRL_MASK, DCI_NREF | DCI_ENABLE | DCI_RESET)
+
+ MOVW $ddriob(SB), R1
+ ADD $DDRIOB_ADDR0, Rb, R2
+ MOVW $12, R3
+ BL copy(SB)
+
+ MOVW $ddrdata(SB), R1
+_ddrl1:
+ MOVW.P 4(R1), R2
+ ORR.S $0, R2
+ BEQ _ddrl2
+ MOVW.P 4(R1), R3
+ MOVW.P 4(R1), R4
+ AND R3, R4
+ MOVW (R2), R0
+ BIC R3, R0
+ ORR R4, R0
+ MOVW R0, (R2)
+ B _ddrl1
+_ddrl2:
+ MOVW DDRIOB_DCI_STATUS(Rb), R0
+ AND.S $(1<<13), R0
+ BEQ _ddrl2
+ MOVW $DDR_BASE, Rb
+ RMW(DDRC_CTRL, 0x1ffff, 0x81)
+_ddrl4:
+ MOVW DDR_MODE_STS(Rb), R0
+ AND.S $7, R0
+ BEQ _ddrl4
+
+ MOVW $MP_BASE, Rb
+ SET(FILTER_START, 0)
+ RET
+
+TEXT memtest(SB), $0
+ MOVW $0, R0
+ ADD $(1024 * 1024 * 10), R0, R1
+_testl:
+ MOVW R0, (R0)
+ ADD $4, R0
+ CMP.S R0, R1
+ BNE _testl
+ MOVW $0, R0
+_testl2:
+ MOVW (R0), R2
+ CMP.S R0, R2
+ BNE _no
+ ADD $4, R0
+ CMP.S R0, R1
+ BNE _testl2
+ MOVW $'.', R0
+ BL putc(SB)
+ RET
+_no:
+ MOVW $'!', R0
+ BL putc(SB)
+ RET
+
+TEXT uartsetup(SB), $0
+ MOVW $UART1_BASE, Rb
+ SET(UART_CTRL, 0x17)
+ SET(UART_MODE, 0x20)
+ SET(UART_SAMP, 15)
+ SET(UART_BAUD, 14)
+ RET
+
+TEXT putc(SB), $0
+ MOVW $UART1_BASE, Rb
+ CMP.S $10, R0
+ BNE _putcl
+ MOVW R0, R2
+ MOVW $13, R0
+ BL putc(SB)
+ MOVW R2, R0
+_putcl:
+ MOVW UART_STAT(Rb), R1
+ AND.S $0x10, R1
+ BNE _putcl
+ AND $0xFF, R0
+ MOVW R0, UART_DATA(Rb)
+ RET
+
+TEXT jump(SB), $-4
+ MOVW R0, R15
+
+TEXT abort(SB), $0
+ MOVW $'?', R0
+ BL putc(SB)
+_loop:
+ WFE
+ B _loop
+
+#define TRI 1
+#define LVCMOS18 (1<<9)
+#define LVCMOS25 (2<<9)
+#define LVCMOS33 (3<<9)
+#define HSTL (4<<9)
+#define PULLUP (1<<12)
+#define NORECV (1<<13)
+#define FAST (1<<8)
+#define MUX(a, b, c, d) ((a)<<1 | (b)<<2 | (c)<<3 | (d)<<5)
+
+#define NO (TRI | LVCMOS33)
+#define SPI (MUX(1, 0, 0, 0) | LVCMOS33)
+#define UART (MUX(0, 0, 0, 7) | LVCMOS33)
+#define SD (MUX(0, 0, 0, 4) | LVCMOS33)
+#define ETX (MUX(1, 0, 0, 0) | HSTL | NORECV | PULLUP)
+#define ERX (MUX(1, 0, 0, 0) | HSTL | TRI | PULLUP)
+#define USB (MUX(0, 1, 0, 0) | LVCMOS18)
+#define MDCLK (MUX(0, 0, 0, 4) | HSTL)
+#define MDDATA (MUX(0, 0, 0, 4) | HSTL)
+
+TEXT miodata(SB), $-4
+ WORD $NO // 0
+ WORD $SPI // 1
+ WORD $SPI // 2
+ WORD $SPI // 3
+ WORD $SPI // 4
+ WORD $SPI // 5
+ WORD $SPI // 6
+ WORD $NO // 7
+ WORD $UART // 8
+ WORD $(UART|TRI) // 9
+ WORD $SD // 10
+ WORD $SD // 11
+ WORD $SD // 12
+ WORD $SD // 13
+ WORD $SD // 14
+ WORD $SD // 15
+ WORD $ETX // 16
+ WORD $ETX // 17
+ WORD $ETX // 18
+ WORD $ETX // 19
+ WORD $ETX // 20
+ WORD $ETX // 21
+ WORD $ERX // 22
+ WORD $ERX // 23
+ WORD $ERX // 24
+ WORD $ERX // 25
+ WORD $ERX // 26
+ WORD $ERX // 27
+ WORD $USB // 28
+ WORD $USB // 29
+ WORD $USB // 30
+ WORD $USB // 31
+ WORD $USB // 32
+ WORD $USB // 33
+ WORD $USB // 34
+ WORD $USB // 35
+ WORD $USB // 36
+ WORD $USB // 37
+ WORD $USB // 38
+ WORD $USB // 39
+ WORD $USB // 40
+ WORD $USB // 41
+ WORD $USB // 42
+ WORD $USB // 43
+ WORD $USB // 44
+ WORD $USB // 45
+ WORD $USB // 46
+ WORD $USB // 47
+ WORD $USB // 48
+ WORD $USB // 49
+ WORD $USB // 50
+ WORD $USB // 51
+ WORD $MDCLK // 52
+ WORD $MDDATA // 53
--- /dev/null
+++ b/os/boot/zynq/jtagload.c
@@ -1,0 +1,647 @@
+#include <u.h>
+#include <libc.h>
+
+typedef struct Tap Tap;
+typedef struct Dap Dap;
+
+struct Tap
+{
+ int off;
+ int len;
+ int delay;
+
+ u32int id;
+ u32int dapsel;
+};
+
+struct Dap
+{
+ Tap *tap;
+
+ uint port;
+ u32int id;
+};
+
+int dfd = -1;
+int lastbit = -1;
+
+int irlen;
+
+int ntaps;
+Tap* taps;
+
+int ndaps;
+Dap* daps;
+
+Dap* ahbap;
+Dap* apbap;
+
+/* MPSSE command bits */
+enum {
+ FEW = 1<<0, /* -ve CLK on write */
+ BITS = 1<<1, /* bits or bytes */
+ FER = 1<<2, /* -ve CLK on read */
+ LSB = 1<<3, /* LSB first = 1 else MSB first */
+ TDI = 1<<4, /* do write TDI */
+ TDO = 1<<5, /* do read TDO */
+ TMS = 1<<6, /* do write TMS */
+};
+
+void
+ioinit(char *dev)
+{
+ uchar b[3];
+
+ dfd = open(dev, ORDWR);
+ if(dfd < 0)
+ sysfatal("open: %r");
+
+ b[0] = 0x80;
+ b[1] = 0x08;
+ b[2] = 0x0B;
+ write(dfd, b, 3);
+}
+
+void
+io(int cmd, int len, uchar *dat)
+{
+ uchar buf[64];
+ uchar *p = buf;
+
+ *p++ = cmd;
+ *p++ = len-1;
+ if((cmd & BITS) != 0)
+ len = 1;
+ else
+ *p++ = (len-1)>>8;
+ if((cmd & (TDI|TMS)) != 0){
+ memmove(p, dat, len);
+ p += len;
+ }
+ if(write(dfd, buf, p - buf) != (p - buf))
+ sysfatal("io write: %r");
+ if((cmd & TDO) != 0)
+ if(readn(dfd, dat, len) != len)
+ sysfatal("io read: %r");
+}
+
+void
+dstate(u32int s, int len)
+{
+ uchar b[1];
+
+ assert(len < 8);
+ b[0] = s;
+ if(lastbit != -1){
+ b[0] |= lastbit << 7;
+ lastbit = -1;
+ }
+ io(TMS|LSB|BITS|FEW, len, b);
+}
+uvlong
+dshift(uvlong w, int len)
+{
+ uchar b[8];
+ int c, s, n;
+
+ c = TDI|LSB|FEW;
+ if(len < 0){
+ len = -len;
+ c |= TDO;
+ }
+ s = 0;
+ n = len/8;
+ if(n > 0) {
+ switch(n){
+ case 8: b[7] = w >> 56;
+ case 7: b[6] = w >> 48;
+ case 6: b[5] = w >> 40;
+ case 5: b[4] = w >> 32;
+ case 4: b[3] = w >> 24;
+ case 3: b[2] = w >> 16;
+ case 2: b[1] = w >> 8;
+ case 1: b[0] = w >> 0;
+ }
+ io(c, n, b);
+ s = n*8;
+ if((c & TDO) != 0){
+ w &= ~((1ULL<<s)-1);
+ switch(n){
+ case 8: w |= (uvlong)b[7] << 56;
+ case 7: w |= (uvlong)b[6] << 48;
+ case 6: w |= (uvlong)b[5] << 40;
+ case 5: w |= (uvlong)b[4] << 32;
+ case 4: w |= (uvlong)b[3] << 24;
+ case 3: w |= (uvlong)b[2] << 16;
+ case 2: w |= (uvlong)b[1] << 8;
+ case 1: w |= (uvlong)b[0] << 0;
+ }
+ }
+ len -= s;
+ }
+ if(len > 0){
+ b[0] = w >> s;
+ c |= BITS;
+ io(c, len, b);
+ if((c & TDO) != 0){
+ w &= ~((uvlong)((1<<len)-1) << s);
+ w |= (uvlong)(b[0] >> 8-len) << s;
+ }
+ s += len;
+ }
+ return w & (1ULL<<s)-1;
+}
+void
+dshiftones(int len)
+{
+ while(len >= 64){
+ dshift(~0ULL, 64);
+ len -= 64;
+ }
+ dshift(~0ULL, len);
+}
+int
+dshiftdelay(void)
+{
+ int i;
+
+ /* send ones */
+ dshiftones(512);
+ for(i=0; i<512; i++){
+ if(dshift(i != 0, -1) == 0)
+ return i;
+ }
+ return 0;
+}
+
+void
+irw(Tap *tap, uvlong w)
+{
+ /* 0011 -> Shift-IR */
+ dstate(0x3, 4);
+
+ dshiftones(tap->off);
+ if((tap->off + tap->len) == irlen){
+ dshift(w, tap->len-1);
+ lastbit = w >> (tap->len-1);
+ } else {
+ dshift(w, tap->len);
+ dshiftones(irlen - (tap->off + tap->len-1));
+ lastbit = 1;
+ }
+
+ /* 011 -> Idle */
+ dstate(0x3, 3);
+}
+uvlong
+drr(Tap *tap, int len)
+{
+ uvlong w, d;
+
+ /* 001 -> Shift-DR */
+ dstate(0x1, 3);
+
+ d = dshift(0, -tap->delay);
+ w = dshift(0, -len);
+ dshift(d, tap->delay);
+ dshift(w, len-1);
+ lastbit = (w >> len-1) & 1;
+
+ /* 011 -> Idle */
+ dstate(0x3, 3);
+
+ return w;
+}
+void
+drw(Tap *tap, uvlong w, int len)
+{
+ /* 001 -> Shift-DR */
+ dstate(0x1, 3);
+
+ dshift(0, tap->delay);
+ dshift(w, len-1);
+ lastbit = (w >> len-1) & 1;
+
+ /* 011 -> Idle */
+ dstate(0x3, 3);
+}
+
+enum {
+ ABORT = 0x8,
+ DPACC = 0xA,
+ APACC = 0xB,
+ CTRLSTAT = 0x4,
+ SELECT = 0x8,
+ RDBUF = 0xC,
+};
+
+u32int
+dapr(Dap *dap, uchar r, uchar a)
+{
+ uvlong w;
+
+ irw(dap->tap, r);
+ w = 1 | (a >> 1) & 0x6;
+ drw(dap->tap, w, 35);
+ do {
+ w = drr(dap->tap, 35);
+ } while((w & 7) == 1);
+ return w >> 3;
+}
+void
+dapw(Dap *dap, uchar r, uchar a, u32int v)
+{
+ uvlong w;
+
+ irw(dap->tap, r);
+ w = (a >> 1) & 0x6;
+ w |= (uvlong)v << 3;
+ drw(dap->tap, w, 35);
+}
+
+void
+app(Dap *dap)
+{
+ enum {
+ CSYSPWRUPACK = 1<<31,
+ CSYSPWRUPREQ = 1<<30,
+ CDBGPWRUPACK = 1<<29,
+ CDBGPWRUPREQ = 1<<28,
+ CDBGRSTACK = 1<<27,
+ CDBGRSTREQ = 1<<26,
+ };
+ u32int s;
+
+ for(;;){
+ s = dapr(dap, DPACC, CTRLSTAT);
+ if((s & (CDBGPWRUPACK|CSYSPWRUPACK)) == (CDBGPWRUPACK|CSYSPWRUPACK))
+ break;
+ s |= CSYSPWRUPREQ|CDBGPWRUPREQ;
+ dapw(dap, DPACC, CTRLSTAT, s);
+ }
+}
+void
+apa(Dap *dap, uchar a)
+{
+ u32int s;
+
+ s = dap->port<<24 | a&0xf0;
+ if(s != dap->tap->dapsel){
+ dap->tap->dapsel = s;
+ dapw(dap, DPACC, SELECT, s);
+ app(dap);
+ }
+}
+u32int
+apr(Dap *dap, uchar a)
+{
+ apa(dap, a);
+ return dapr(dap, APACC, a&0xC);
+}
+void
+apw(Dap *dap, uchar a, u32int v)
+{
+ apa(dap, a);
+ dapw(dap, APACC, a&0xC, v);
+}
+u32int
+mmr(Dap *ap, u32int addr)
+{
+ apw(ap, 0x4, addr);
+ return apr(ap, 0xC);
+}
+void
+mmw(Dap *ap, u32int addr, u32int val)
+{
+ apw(ap, 0x4, addr);
+ apw(ap, 0xC, val);
+}
+
+void
+tapreset(void)
+{
+ int i, j, o;
+
+ dstate(0x1F, 6); /* 011111 -> Reset->Idle */
+ dstate(0x3, 4); /* 0011 -> Shift-IR */
+
+ irlen = dshiftdelay();
+ lastbit = 1;
+
+ dstate(0x7, 5); /* 00111 -> Shift-IR->Shift-DR */
+
+ ntaps = dshiftdelay();
+
+ dstate(0x1F, 6); /* 011111 -> Reset->Idle */
+ dstate(0x1, 3); /* 001 -> Shift-DR */
+
+ taps = realloc(taps, sizeof(taps[0]) * ntaps);
+
+ o = 0;
+ for(i=ntaps-1; i>=0; i--){
+ taps[i].delay = ntaps - i - 1;
+ taps[i].off = o;
+ taps[i].id = dshift(0, -32);
+ switch(taps[i].id){
+ default:
+ sysfatal("unknown tapid %.8ux\n", taps[i].id);
+ case 0x03727093:
+ case 0x0373b093:
+ case 0x23727093:
+ taps[i].len = 6;
+ break;
+ case 0x4ba00477:
+ taps[i].len = 4;
+ break;
+ }
+ o += taps[i].len;
+ }
+
+ dstate(0x1F, 6); /* 011111 -> Reset->Idle */
+
+ if(o != irlen)
+ sysfatal("wrong tapchain irlen %d %d\n", o, irlen);
+
+ ndaps = 0;
+ for(i=0; i<ntaps; i++){
+ fprint(2, "tap%d: id=%.8ux off=%d len=%d delay=%d\n",
+ i, taps[i].id, taps[i].off, taps[i].len, taps[i].delay);
+
+ switch(taps[i].id){
+ case 0x4ba00477:
+ o = 3;
+ daps = realloc(daps, sizeof(daps[0]) * (ndaps+o));
+ for(j=0; j<o; j++){
+ daps[ndaps].tap = taps+i;
+ daps[ndaps].port = j;
+ daps[ndaps].id = apr(daps+ndaps, 0xFC);
+ fprint(2, "\tdap%d: id=%.8ux\n", j, daps[ndaps].id);
+
+ ndaps++;
+ }
+ break;
+ }
+ }
+
+ for(i=0; i<ndaps; i++){
+ switch(daps[i].id){
+ case 0x44770001:
+ ahbap = daps+i;
+ break;
+ case 0x24770002:
+ apbap = daps+i;
+ break;
+ }
+ }
+}
+
+enum {
+ DBGDIDR = 0x000,
+ DBGDEVID = 0xFC8,
+ DBGDSCR = 0x088,
+ RXfull = 1<<30,
+ TXfull = 1<<29,
+ RXfull_1 = 1<<27,
+ TXfull_1 = 1<<26,
+ PipeAdv = 1<<25,
+ InstrCompl_1 = 1<<24,
+ ExtDCCmodeShift = 20,
+ ExtDCCmodeMask = 3<<ExtDCCmodeShift,
+ ADAdiscard = 1<<19,
+ NS = 1<<18,
+ SPNIDdis = 1<<17,
+ SPIDdis = 1<<16,
+ MDBGen = 1<<15,
+ HDBGen = 1<<14,
+ ITRen = 1<<13,
+ UDCCdis = 1<<12,
+ INTdis = 1<<11,
+ DBGack = 1<<10,
+ UND_1 = 1<<8,
+ ADABORT_1 = 1<<7,
+ SDABORT_1 = 1<<6,
+ MOEShift = 2,
+ MOEMask = 15<<MOEShift,
+ RESTARTED = 1<<1,
+ HALTED = 1<<0,
+
+ DBGDRCR = 0x90,
+ RestartReq = 1<<1,
+ HaltReq = 1<<0,
+
+ DBGPRCR = 0x310,
+
+ DBGITR = 0x084, /* Instruction Transfer Register */
+ DBGDTRRX = 0x080, /* Host to Target Data Transfer Register */
+ DBGDTRTX = 0x08C, /* Target to Host Data Transfer Register */
+};
+
+typedef struct Arm Arm;
+struct Arm
+{
+ u32int dbgbase;
+
+ Dap *dbgap;
+ Dap *memap;
+
+ char *id;
+};
+Arm arm[2];
+u32int
+dbgr(Arm *arm, u32int reg)
+{
+ return mmr(arm->dbgap, arm->dbgbase+reg);
+}
+void
+dbgw(Arm *arm, u32int reg, u32int val)
+{
+ mmw(arm->dbgap, arm->dbgbase+reg, val);
+}
+u32int
+dbgrpoll(Arm *arm, u32int reg, u32int mask, u32int val)
+{
+ u32int w;
+
+ for(;;){
+ w = dbgr(arm, reg);
+ if((w & mask) == val)
+ break;
+ }
+ return w;
+}
+
+void
+startstop(Arm *arm, int stop)
+{
+ u32int s;
+
+ s = dbgr(arm, DBGDSCR);
+ if((s & HALTED) != stop){
+ if(!stop){
+ s &= ~ITRen;
+ dbgw(arm, DBGDSCR, s);
+ }
+ dbgw(arm, DBGDRCR, stop ? HaltReq : RestartReq);
+ s = dbgrpoll(arm, DBGDSCR, HALTED, stop);
+ if(stop){
+ s |= ITRen;
+ dbgw(arm, DBGDSCR, s);
+ }
+ fprint(2, "%s: startstop: %.8ux\n", arm->id, s);
+ }
+}
+
+void
+armxec(Arm *arm, u32int instr)
+{
+ dbgw(arm, DBGITR, instr);
+ dbgrpoll(arm, DBGDSCR, InstrCompl_1, InstrCompl_1);
+}
+
+#define ARMV4_5_MRC(CP, op1, Rd, CRn, CRm, op2) \
+ (0xee100010 | (CRm) | ((op2) << 5) | ((CP) << 8) \
+ | ((Rd) << 12) | ((CRn) << 16) | ((op1) << 21))
+#define ARMV4_5_MCR(CP, op1, Rd, CRn, CRm, op2) \
+ (0xee000010 | (CRm) | ((op2) << 5) | ((CP) << 8) \
+ | ((Rd) << 12) | ((CRn) << 16) | ((op1) << 21))
+
+void
+trrxw(Arm *arm, u32int val)
+{
+ dbgrpoll(arm, DBGDSCR, RXfull_1, 0);
+ dbgw(arm, DBGDTRRX, val);
+}
+u32int
+trtxr(Arm *arm)
+{
+ dbgrpoll(arm, DBGDSCR, TXfull_1, TXfull_1);
+ return dbgr(arm, DBGDTRTX);
+}
+
+void
+armrw(Arm *arm, int reg, u32int val);
+
+u32int
+armrr(Arm *arm, int rn)
+{
+ if(rn == 15){
+ u32int r0;
+
+ r0 = armrr(arm, 0);
+ armxec(arm, 0xE1A0000F);
+ armxec(arm, ARMV4_5_MCR(14, 0, 0, 0, 5, 0));
+ armrw(arm, 0, r0);
+ } else {
+ armxec(arm, ARMV4_5_MCR(14, 0, rn, 0, 5, 0));
+ }
+ return trtxr(arm);
+}
+void
+armrw(Arm *arm, int rn, u32int val)
+{
+ if(rn == 15){
+ u32int r0;
+
+ r0 = armrr(arm, 0);
+ armrw(arm, 0, val);
+ armxec(arm, 0xE1A0F000);
+ armrw(arm, 0, r0);
+ } else {
+ trrxw(arm, val);
+ armxec(arm, ARMV4_5_MRC(14, 0, rn, 0, 5, 0));
+ }
+}
+
+/*
+ * mww phys 0xf8000008 0xdf0d
+ * mww phys 0xf8000910 0xf
+ * load_image "/sys/src/boot/zynq/fsbl" 0xfffc0000 bin
+ * reg pc 0xfffc0000
+ */
+void
+boot(char *file, u32int entry)
+{
+ u32int *buf, *src;
+ int fd, size;
+ u32int dst;
+
+ fprint(2, "load %s", file);
+ if((fd = open(file, OREAD)) < 0)
+ sysfatal("open: %r");
+
+ size = seek(fd, 0, 2);
+ fprint(2, " [%ud]", size);
+ seek(fd, 0, 0);
+ buf = malloc((size+3) & ~3);
+ if(readn(fd, buf, size) != size)
+ sysfatal("read: %r");
+ close(fd);
+
+ /* map ocm */
+ mmw(arm->memap, 0xf8000008, 0xdf0d);
+ mmw(arm->memap, 0xf8000910, 0xf);
+
+ src = buf;
+ for(dst = entry; size > 0; dst += 4, size -= 4){
+ if((dst & 0xF) == 0)
+ fprint(2, ".");
+ mmw(arm->memap, dst, *src++);
+ }
+ free(buf);
+ fprint(2, ".\nentry %.8ux\n", entry);
+
+ armrw(arm, 15, entry);
+}
+
+void
+usage(void)
+{
+ fprint(2, "%s [ -j jtagdev ] entry image\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ char *jtag = "/dev/jtagddd94.0";
+ char *image;
+ u32int entry;
+
+ fmtinstall('H', encodefmt);
+
+ ARGBEGIN {
+ case 'j':
+ jtag = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if(argc != 2)
+ usage();
+ entry = strtoul(argv[0], nil, 0);
+ image = argv[1];
+
+ ioinit(jtag);
+ tapreset();
+
+ arm[0].dbgbase = 0x80090000;
+ arm[0].dbgap = apbap;
+ arm[0].memap = ahbap;
+ arm[0].id = "arm0";
+
+ arm[1].dbgbase = 0x80092000;
+ arm[1].dbgap = apbap;
+ arm[1].memap = ahbap;
+ arm[1].id = "arm1";
+
+ startstop(arm+0, 1);
+ startstop(arm+1, 1);
+
+ boot(image, entry);
+
+ startstop(arm+0, 0);
+ startstop(arm+1, 0);
+
+ exits(nil);
+}
--- /dev/null
+++ b/os/boot/zynq/main.c
@@ -1,0 +1,203 @@
+#include <u.h>
+#include <a.out.h>
+#include "dat.h"
+#include "fns.h"
+
+void
+puts(char *s)
+{
+ while(*s)
+ putc(*s++);
+}
+
+void
+puthex(u32int u)
+{
+ static char *dig = "0123456789abcdef";
+ int i;
+
+ for(i = 0; i < 8; i++){
+ putc(dig[u >> 28]);
+ u <<= 4;
+ }
+}
+
+void
+putdec(int n)
+{
+ if(n / 10 != 0)
+ putdec(n / 10);
+ putc(n % 10 + '0');
+}
+
+void
+print(char *s, ...)
+{
+ va_list va;
+ int n;
+ u32int u;
+
+ va_start(va, s);
+ while(*s)
+ if(*s == '%'){
+ switch(*++s){
+ case 's':
+ puts(va_arg(va, char *));
+ break;
+ case 'x':
+ puthex(va_arg(va, u32int));
+ break;
+ case 'd':
+ n = va_arg(va, int);
+ if(n < 0){
+ putc('-');
+ putdec(-n);
+ }else
+ putdec(n);
+ break;
+ case 'I':
+ u = va_arg(va, u32int);
+ putdec(u >> 24);
+ putc('.');
+ putdec((uchar)(u >> 16));
+ putc('.');
+ putdec((uchar)(u >> 8));
+ putc('.');
+ putdec((uchar)u);
+ break;
+ case 0:
+ va_end(va);
+ return;
+ }
+ s++;
+ }else
+ putc(*s++);
+ va_end(va);
+}
+
+void
+memset(void *v, char c, int n)
+{
+ char *vc;
+
+ vc = v;
+ while(n--)
+ *vc++ = c;
+}
+
+void
+memcpy(void *d, void *s, int n)
+{
+ char *cd, *cs;
+
+ cd = d;
+ cs = s;
+ while(n--)
+ *cd++ = *cs++;
+}
+
+u32int
+u32get(void *pp)
+{
+ uchar *p;
+
+ p = pp;
+ return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
+}
+
+uchar *
+u32put(uchar *p, u32int v)
+{
+ p[0] = v >> 24;
+ p[1] = v >> 16;
+ p[2] = v >> 8;
+ p[3] = v;
+ return p + 4;
+}
+
+void
+run(void)
+{
+ ulong t, tr;
+ char *p, *d;
+ int n;
+ ulong *h;
+
+ h = (ulong *) TZERO;
+ if(u32get(&h[0]) != E_MAGIC){
+ print("invalid magic: %x != %x\n", u32get(&h[0]), E_MAGIC);
+ return;
+ }
+ t = u32get(&h[1]) + 0x20;
+ tr = t + 0xfff & ~0xfff;
+ if(t != tr){
+ n = u32get(&h[2]);
+ p = (char *) (TZERO + t + n);
+ d = (char *) (TZERO + tr + n);
+ while(n--)
+ *--d = *--p;
+ }
+ p = (char *) (TZERO + tr + u32get(&h[2]));
+ memset(p, 0, u32get(&h[3]));
+ jump((void *) (u32get(&h[5]) & 0xfffffff));
+}
+
+enum {
+ TIMERVALL,
+ TIMERVALH,
+ TIMERCTL,
+ TIMERSTAT,
+ TIMERCOMPL,
+ TIMERCOMPH,
+};
+
+void
+timeren(int n)
+{
+ ulong *r;
+
+ r = (ulong *) 0xf8f00200;
+ if(n < 0){
+ r[TIMERSTAT] |= 1;
+ r[TIMERCTL] = 0;
+ return;
+ }
+ r[TIMERCTL] = 0;
+ r[TIMERVALL] = 0;
+ r[TIMERVALH] = 0;
+ r[TIMERCOMPL] = 1000 * n;
+ r[TIMERCOMPH] = 0;
+ r[TIMERSTAT] |= 1;
+ r[TIMERCTL] = 100 << 8 | 3;
+}
+
+int
+timertrig(void)
+{
+ ulong *r;
+
+ r = (ulong *) 0xf8f00200;
+ if((r[TIMERSTAT] & 1) != 0){
+ r[TIMERCTL] = 0;
+ r[TIMERSTAT] |= 1;
+ return 1;
+ }
+ return 0;
+}
+
+void
+sleep(int n)
+{
+ timeren(n);
+ while(!timertrig())
+ ;
+}
+
+void
+main(void)
+{
+ puts("Booting ...\n");
+ if(mmcboot() > 0 || netboot() > 0)
+ run();
+ print("hjboot: ending\n");
+}
--- /dev/null
+++ b/os/boot/zynq/mem.h
@@ -1,0 +1,107 @@
+#define STACKTOP 0xFFFFFE00
+
+#define ARM_FDIV (40 << PLL_FDIV_SH)
+#define DDR_FDIV (32 << PLL_FDIV_SH)
+#define IO_FDIV (30 << PLL_FDIV_SH)
+#define PLL_CFG_VAL(CP, RES, CNT) ((CP)<<8 | (RES)<<4 | (CNT)<<12)
+#define ARM_PLL_CFG_VAL PLL_CFG_VAL(2, 2, 250)
+#define DDR_PLL_CFG_VAL PLL_CFG_VAL(2, 2, 300)
+#define IO_PLL_CFG_VAL PLL_CFG_VAL(2, 12, 325)
+#define PLL_FDIV_SH 12
+#define PLL_BYPASS_FORCE 0x10
+#define PLL_RESET 0x01
+
+#define CPU_DIV 2
+#define DDR_DIV3 2
+#define DDR_DIV2 3
+#define UART_DIV 40
+#define DCI_DIV0 20
+#define DCI_DIV1 5
+#define ETH_DIV0 8
+#define ETH_DIV1 1
+#define QSPI_DIV 5
+#define SDIO_DIV 10
+#define PCAP_DIV 5
+#define MDC_DIV 6 /* this value depends on CPU_1xCLK, see TRM GEM.net_cfg description */
+
+#define SLCR_BASE 0xF8000000
+#define SLCR_LOCK 0x004
+#define LOCK_KEY 0x767B
+#define SLCR_UNLOCK 0x008
+#define UNLOCK_KEY 0xDF0D
+
+#define ARM_PLL_CTRL 0x100
+#define DDR_PLL_CTRL 0x104
+#define IO_PLL_CTRL 0x108
+#define PLL_STATUS 0x10C
+#define ARM_PLL_CFG 0x110
+#define DDR_PLL_CFG 0x114
+#define IO_PLL_CFG 0x118
+#define ARM_CLK_CTRL 0x120
+#define DDR_CLK_CTRL 0x124
+#define DCI_CLK_CTRL 0x128
+#define APER_CLK_CTRL 0x12C
+#define GEM0_RCLK_CTRL 0x138
+#define GEM1_RCLK_CTRL 0x13C
+#define GEM0_CLK_CTRL 0x140
+#define GEM1_CLK_CTRL 0x144
+#define SMC_CLK_CTRL 0x148
+#define LQSPI_CLK_CTRL 0x14C
+#define SDIO_CLK_CTRL 0x150
+#define UART_CLK_CTRL 0x154
+#define SPI_CLK_CTRL 0x158
+#define CAN_CLK_CTRL 0x15C
+#define PCAP_CLK_CTRL 0x168
+#define UART_RST_CTRL 0x228
+#define A9_CPU_RST_CTRL 0x244
+
+#define LQSPI_CLK_EN (1<<23)
+#define GPIO_CLK_EN (1<<22)
+#define UART0_CLK_EN (1<<20)
+#define UART1_CLK_EN (1<<21)
+#define I2C0_CLK_EN (1<<18)
+#define SDIO1_CLK_EN (1<<11)
+#define GEM0_CLK_EN (1<<6)
+#define USB1_CLK_EN (1<<3)
+#define USB0_CLK_EN (1<<2)
+#define DMA_CLK_EN (1<<0)
+
+#define MIO_PIN_0 0x00000700
+#define MIO_MST_TRI0 0x80C
+#define MIO_MST_TRI1 0x810
+#define OCM_CFG 0x910
+#define GPIOB_CTRL 0xB00
+#define VREF_SW_EN (1<<11)
+#define DDRIOB_ADDR0 0xB40
+#define DDRIOB_DCI_CTRL 0xB70
+#define DDRIOB_DCI_CTRL_MASK 0x1ffc3
+#define DDRIOB_DCI_STATUS 0xB74
+#define DCI_RESET 1
+#define DCI_NREF (1<<11)
+#define DCI_ENABLE 2
+
+#define DDR_BASE 0xF8006000
+#define DDRC_CTRL 0x0
+#define DDR_MODE_STS 0x54
+
+#define UART1_BASE 0xE0001000
+#define UART_CTRL 0x0
+#define UART_MODE 0x4
+#define UART_BAUD 0x18
+#define UART_STAT 0x2C
+#define UART_DATA 0x30
+#define UART_SAMP 0x34
+
+#define QSPI_BASE 0xE000D000
+#define QSPI_CFG 0x0
+#define SPI_EN 0x4
+#define QSPI_TX 0x1c
+
+#define MP_BASE 0xF8F00000
+#define FILTER_START 0x40
+
+#define CpMMU 15
+
+#define DSB WORD $0xf57ff04f
+#define ISB WORD $0xf57ff06f
+#define WFE WORD $0xe320f002
--- /dev/null
+++ b/os/boot/zynq/mkfile
@@ -1,0 +1,38 @@
+objtype=arm
+</$objtype/mkfile
+BIN=/arm
+TARG=fsbl fsbl.img
+FSBLFILES=fsbl.$O ddr.$O main.$O mmc.$O net.$O div.$O qspi.$O
+TEXTBASE=0xfffc0000
+
+all:V: $TARG
+
+clean:V:
+ rm -rf $TARG *.$O
+ @{objtype=$cputype mk -f mkfile.port clean}
+
+fsbl: $FSBLFILES
+ $LD -o $target -T$TEXTBASE -H6 -R4096 -l -s $prereq
+
+9fsbl: $FSBLFILES
+ $LD -o $target -T$TEXTBASE -l $prereq
+
+fsbl.img:D: fsbl boothead.$cputype
+ ./boothead.$cputype fsbl >fsbl.img
+
+%.$cputype:V: mkfile.port
+ @{objtype=$cputype mk -f $prereq $target}
+
+jtagload:V: fsbl jtagload.$cputype
+ ./jtagload.$cputype -j /dev/jtag*.0 $TEXTBASE fsbl
+
+div.$O: /sys/src/libc/arm/div.s
+ $AS /sys/src/libc/arm/div.s
+
+%.$O: dat.h fns.h mem.h
+
+%.$O: %.s
+ $AS $stem.s
+
+%.$O: %.c
+ $CC $CFLAGS $stem.c
--- /dev/null
+++ b/os/boot/zynq/mkfile.port
@@ -1,0 +1,14 @@
+</$objtype/mkfile
+
+TARG=boothead.$objtype jtagload.$objtype
+
+all:V: $TARG
+
+clean:V:
+ rm -f $TARG *.$O
+
+%.$objtype: %.$O
+ $LD $LDFLAGS -o $target $prereq
+
+%.$O: %.c
+ $CC $CFLAGS $stem.c
--- /dev/null
+++ b/os/boot/zynq/mmc.c
@@ -1,0 +1,832 @@
+#include <u.h>
+#include "dat.h"
+#include "fns.h"
+#include "mem.h"
+
+enum {
+ Sectsz = 0x200,
+ Dirsz = 0x20,
+ Maxpath = 64,
+ Fat12 = 1,
+ Fat16 = 2,
+ Fat32 = 4,
+};
+
+typedef struct File File;
+typedef struct Dir Dir;
+typedef struct Pbs Pbs;
+typedef struct Pbs32 Pbs32;
+typedef struct Fat Fat;
+
+struct Fat
+{
+ ulong ver;
+ ulong clustsize;
+ ulong eofmark;
+ ulong partlba;
+ ulong fatlba;
+ ulong dirstart; /* LBA for FAT16, cluster for FAT32 */
+ ulong dirents;
+ ulong datalba;
+};
+
+struct File
+{
+ Fat *fat;
+ ulong lba;
+ ulong clust;
+ ulong lbaoff;
+ ulong len;
+ uchar *rp;
+ uchar *ep;
+ uchar buf[Sectsz];
+};
+
+struct Dir
+{
+ char name[11];
+ uchar attr;
+ uchar reserved;
+ uchar ctime;
+ uchar ctime[2];
+ uchar cdate[2];
+ uchar adate[2];
+ uchar starthi[2];
+ uchar mtime[2];
+ uchar mdate[2];
+ uchar startlo[2];
+ uchar len[4];
+};
+
+struct Pbs
+{
+ uchar magic[3];
+ uchar version[8];
+ uchar sectsize[2];
+ uchar clustsize;
+ uchar nreserv[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 type[8];
+};
+
+struct Pbs32
+{
+ uchar common[36];
+ uchar fatsize[4];
+ uchar flags[2];
+ uchar ver[2];
+ uchar rootclust[4];
+ uchar fsinfo[2];
+ uchar bootbak[2];
+ uchar reserved0[12];
+ uchar driveno;
+ uchar reserved1;
+ uchar bootsig;
+ uchar volid[4];
+ uchar label[11];
+ uchar type[8];
+};
+
+enum {
+ Initfreq = 400000, /* initialisation frequency for MMC */
+ SDfreq = 25000000, /* standard SD frequency */
+ DTO = 14, /* data timeout exponent (guesswork) */
+};
+
+enum {
+ /* Controller registers */
+ Sysaddr = 0x00>>2,
+ Blksizecnt = 0x04>>2,
+ Arg1 = 0x08>>2,
+ Cmdtm = 0x0c>>2,
+ Resp0 = 0x10>>2,
+ Resp1 = 0x14>>2,
+ Resp2 = 0x18>>2,
+ Resp3 = 0x1c>>2,
+ Data = 0x20>>2,
+ Status = 0x24>>2,
+ Control0 = 0x28>>2,
+ Control1 = 0x2c>>2,
+ Interrupt = 0x30>>2,
+ Irptmask = 0x34>>2,
+ Irpten = 0x38>>2,
+ Capabilites = 0x40>>2,
+ Forceirpt = 0x50>>2,
+ Boottimeout = 0x60>>2,
+ Dbgsel = 0x64>>2,
+ Spiintspt = 0xf0>>2,
+ Slotisrver = 0xfc>>2,
+
+ /* Control0 */
+ Dwidth4 = 1<<1,
+ Dwidth1 = 0<<1,
+
+ /* Control1 */
+ Srstdata = 1<<26, /* reset data circuit */
+ Srstcmd = 1<<25, /* reset command circuit */
+ Srsthc = 1<<24, /* reset complete host controller */
+ Datatoshift = 16, /* data timeout unit exponent */
+ Datatomask = 0xF0000,
+ Clkfreq8shift = 8, /* SD clock base divider LSBs */
+ Clkfreq8mask = 0xFF00,
+ Clkfreqms2shift = 6, /* SD clock base divider MSBs */
+ Clkfreqms2mask = 0xC0,
+ Clkgendiv = 0<<5, /* SD clock divided */
+ Clkgenprog = 1<<5, /* SD clock programmable */
+ Clken = 1<<2, /* SD clock enable */
+ Clkstable = 1<<1,
+ Clkintlen = 1<<0, /* enable internal EMMC clocks */
+
+ /* Cmdtm */
+ Indexshift = 24,
+ Suspend = 1<<22,
+ Resume = 2<<22,
+ Abort = 3<<22,
+ Isdata = 1<<21,
+ Ixchken = 1<<20,
+ Crcchken = 1<<19,
+ Respmask = 3<<16,
+ Respnone = 0<<16,
+ Resp136 = 1<<16,
+ Resp48 = 2<<16,
+ Resp48busy = 3<<16,
+ Multiblock = 1<<5,
+ Host2card = 0<<4,
+ Card2host = 1<<4,
+ Autocmd12 = 1<<2,
+ Autocmd23 = 2<<2,
+ Blkcnten = 1<<1,
+ Dmaen = 1<<0,
+
+ /* Interrupt */
+ Acmderr = 1<<24,
+ Denderr = 1<<22,
+ Dcrcerr = 1<<21,
+ Dtoerr = 1<<20,
+ Cbaderr = 1<<19,
+ Cenderr = 1<<18,
+ Ccrcerr = 1<<17,
+ Ctoerr = 1<<16,
+ Err = 1<<15,
+ Cardintr = 1<<8,
+ Cardinsert = 1<<6,
+ Readrdy = 1<<5,
+ Writerdy = 1<<4,
+ Dmaintr = 1<<3,
+ Datadone = 1<<1,
+ Cmddone = 1<<0,
+
+ /* Status */
+ Present = 1<<18,
+ Bufread = 1<<11,
+ Bufwrite = 1<<10,
+ Readtrans = 1<<9,
+ Writetrans = 1<<8,
+ Datactive = 1<<2,
+ Datinhibit = 1<<1,
+ Cmdinhibit = 1<<0,
+
+ Inittimeout = 15,
+// Multiblock = 1,
+
+ /* Commands */
+ GO_IDLE_STATE = 0,
+ ALL_SEND_CID = 2,
+ SEND_RELATIVE_ADDR= 3,
+ SELECT_CARD = 7,
+ SD_SEND_IF_COND = 8,
+ SEND_CSD = 9,
+ STOP_TRANSMISSION= 12,
+ SEND_STATUS = 13,
+ SET_BLOCKLEN = 16,
+ READ_SINGLE_BLOCK= 17,
+ READ_MULTIPLE_BLOCK= 18,
+ WRITE_BLOCK = 24,
+ WRITE_MULTIPLE_BLOCK= 25,
+ APP_CMD = 55, /* prefix for following app-specific commands */
+ SET_BUS_WIDTH = 6,
+ SD_SEND_OP_COND = 41,
+
+ /* Command arguments */
+ /* SD_SEND_IF_COND */
+ Voltage = 1<<8,
+ Checkpattern = 0x42,
+
+ /* SELECT_CARD */
+ Rcashift = 16,
+
+ /* SD_SEND_OP_COND */
+ Hcs = 1<<30, /* host supports SDHC & SDXC */
+ Ccs = 1<<30, /* card is SDHC or SDXC */
+ V3_3 = 3<<20, /* 3.2-3.4 volts */
+
+ /* SET_BUS_WIDTH */
+ Width1 = 0<<0,
+ Width4 = 2<<0,
+
+ /* OCR (operating conditions register) */
+ Powerup = 1<<31,
+};
+
+static int cmdinfo[64] = {
+[0] Ixchken,
+[2] Resp136,
+[3] Resp48 | Ixchken | Crcchken,
+[6] Resp48 | Ixchken | Crcchken,
+[7] Resp48busy | Ixchken | Crcchken,
+[8] Resp48 | Ixchken | Crcchken,
+[9] Resp136,
+[12] Resp48busy | Ixchken | Crcchken,
+[13] Resp48 | Ixchken | Crcchken,
+[16] Resp48,
+[17] Resp48 | Isdata | Card2host | Ixchken | Crcchken | Dmaen,
+[18] Resp48 | Isdata | Card2host | Multiblock | Blkcnten | Ixchken | Crcchken | Dmaen,
+[24] Resp48 | Isdata | Host2card | Ixchken | Crcchken | Dmaen,
+[25] Resp48 | Isdata | Host2card | Multiblock | Blkcnten | Ixchken | Crcchken | Dmaen,
+[41] Resp48,
+[55] Resp48 | Ixchken | Crcchken,
+};
+
+typedef struct Ctlr Ctlr;
+struct Ctlr {
+ u32int *regs;
+ ulong extclk;
+
+ /* SD card registers */
+ u16int rca;
+ u32int ocr;
+ u32int cid[4];
+ u32int csd[4];
+};
+static Ctlr ctlr = {
+ .regs = (u32int*)0xE0101000,
+ .extclk = 100000000,
+};
+
+
+static ushort
+GETSHORT(void *v)
+{
+ uchar *p = v;
+ return p[0] | p[1]<<8;
+}
+static ulong
+GETLONG(void *v)
+{
+ uchar *p = v;
+ return p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24;
+}
+
+static int
+memcmp(void *src, void *dst, int n)
+{
+ uchar *d = dst;
+ uchar *s = src;
+ int r = 0;
+
+ while(n-- > 0){
+ r = *d++ - *s++;
+ if(r != 0)
+ break;
+ }
+
+ return r;
+}
+
+static uint
+clkdiv(uint d)
+{
+ uint v;
+
+ v = (d << Clkfreq8shift) & Clkfreq8mask;
+ v |= ((d >> 8) << Clkfreqms2shift) & Clkfreqms2mask;
+ return v;
+}
+
+static int
+mmcwait(int mask)
+{
+ int i, t;
+
+ t = 0;
+ while(((i=ctlr.regs[Interrupt])&mask) == 0)
+ if(t++ > 10000000)
+ break;
+
+ return i;
+}
+
+static int
+mmccmd(u32int cmd, u32int arg, u32int *resp)
+{
+ u32int *r;
+ u32int c;
+ int i;
+
+ c = (cmd << Indexshift) | cmdinfo[cmd];
+
+ r = ctlr.regs;
+ if(r[Status] & Cmdinhibit){
+ print("mmc: need to reset Cmdinhibit intr %x stat %x\n",
+ r[Interrupt], r[Status]);
+ r[Control1] |= Srstcmd;
+ while(r[Control1] & Srstcmd)
+ ;
+ while(r[Status] & Cmdinhibit)
+ ;
+ }
+ if((c & Isdata || (c & Respmask) == Resp48busy) && r[Status] & Datinhibit){
+ print("mmc: need to reset Datinhibit intr %x stat %x\n",
+ r[Interrupt], r[Status]);
+ r[Control1] |= Srstdata;
+ while(r[Control1] & Srstdata)
+ ;
+ while(r[Status] & Datinhibit)
+ ;
+ }
+ r[Arg1] = arg;
+ if((i = r[Interrupt]) != 0){
+ if(i != Cardinsert)
+ print("mmc: before command, intr was %x\n", i);
+ r[Interrupt] = i;
+ }
+ r[Cmdtm] = c;
+
+ i = mmcwait(Cmddone|Err);
+ if((i&(Cmddone|Err)) != Cmddone){
+ if((i&~Err) != Ctoerr)
+ print("mmc: CMD%d error intr %x stat %x\n", cmd, i, r[Status]);
+ r[Interrupt] = i;
+ if(r[Status]&Cmdinhibit){
+ r[Control1] |= Srstcmd;
+ while(r[Control1]&Srstcmd)
+ ;
+ }
+ return -1;
+ }
+ r[Interrupt] = i & ~(Datadone|Readrdy|Writerdy);
+ switch(c & Respmask){
+ case Resp136:
+ resp[0] = r[Resp0]<<8;
+ resp[1] = r[Resp0]>>24 | r[Resp1]<<8;
+ resp[2] = r[Resp1]>>24 | r[Resp2]<<8;
+ resp[3] = r[Resp2]>>24 | r[Resp3]<<8;
+ break;
+ case Resp48:
+ case Resp48busy:
+ resp[0] = r[Resp0];
+ break;
+ case Respnone:
+ resp[0] = 0;
+ break;
+ }
+ if((c & Respmask) == Resp48busy){
+ r[Irpten] = Datadone|Err;
+ i = mmcwait(Cmddone|Err);
+ if(i)
+ r[Interrupt] = i;
+ r[Irpten] = 0;
+ if((i & Datadone) == 0)
+ print("mmc: no Datadone after CMD%d\n", cmd);
+ if(i & Err)
+ print("mmc: CMD%d error interrupt %x\n", cmd, i);
+ }
+
+ /*
+ * Once card is selected, use faster clock
+ */
+ if(cmd == SELECT_CARD){
+ sleep(10);
+ r[Control1] = clkdiv(ctlr.extclk / SDfreq - 1) |
+ DTO << Datatoshift | Clkgendiv | Clken | Clkintlen;
+ for(i = 0; i < 1000; i++){
+ sleep(1);
+ if(r[Control1] & Clkstable)
+ break;
+ }
+ sleep(10);
+ }
+
+ /*
+ * If card bus width changes, change host bus width
+ */
+ if(cmd == SET_BUS_WIDTH)
+ switch(arg){
+ case 0:
+ r[Control0] &= ~Dwidth4;
+ break;
+ case 2:
+ r[Control0] |= Dwidth4;
+ break;
+ }
+ return 0;
+}
+
+static int
+mmconline(void)
+{
+ u32int r[4];
+ int hcs, i;
+
+ mmccmd(GO_IDLE_STATE, 0, r);
+
+ hcs = 0;
+ if(mmccmd(SD_SEND_IF_COND, Voltage|Checkpattern, r) == 0){
+ if(r[0] == (Voltage|Checkpattern)) /* SD 2.0 or above */
+ hcs = Hcs;
+ }
+ for(i = 0; i < Inittimeout; i++){
+ sleep(100);
+ mmccmd(APP_CMD, 0, r);
+ mmccmd(SD_SEND_OP_COND, hcs|V3_3, r);
+ if(r[0] & Powerup)
+ break;
+ }
+ if(i == Inittimeout){
+ print("mmc: card won't power up\n");
+ return -1;
+ }
+ ctlr.ocr = r[0];
+ mmccmd(ALL_SEND_CID, 0, r);
+ memcpy(ctlr.cid, r, sizeof ctlr.cid);
+ mmccmd(SEND_RELATIVE_ADDR, 0, r);
+ ctlr.rca = r[0]>>16;
+ mmccmd(SEND_CSD, ctlr.rca<<Rcashift, r);
+ memcpy(ctlr.csd, r, sizeof ctlr.csd);
+ mmccmd(SELECT_CARD, ctlr.rca<<Rcashift, r);
+ mmccmd(SET_BLOCKLEN, Sectsz, r);
+ mmccmd(APP_CMD, ctlr.rca<<Rcashift, r);
+ mmccmd(SET_BUS_WIDTH, Width4, r);
+ return 0;
+}
+
+static int
+mmcinit(void)
+{
+ u32int *r;
+ int i;
+
+ r = ctlr.regs;
+ r[Control1] = Srsthc;
+ for(i = 0; i < 100; i++){
+ sleep(10);
+ if((r[Control1] & Srsthc) == 0)
+ break;
+ }
+ if(i == 100){
+ print("mmc: reset timeout!\n");
+ return -1;
+ }
+ r[Control1] = clkdiv(ctlr.extclk / Initfreq - 1) | DTO << Datatoshift |
+ Clkgendiv | Clken | Clkintlen;
+ for(i = 0; i < 1000; i++){
+ sleep(1);
+ if(r[Control1] & Clkstable)
+ break;
+ }
+ if(i == 1000){
+ print("mmc: SD clock won't initialise!\n");
+ return -1;
+ }
+ r[Irptmask] = ~(Dtoerr|Cardintr|Dmaintr);
+ return mmconline();
+}
+
+static int
+mmcread(ulong bno, uchar buf[Sectsz])
+{
+ u32int *r, rr[4];
+ int i, t;
+
+ r = ctlr.regs;
+ for(t=0; t<3; t++){
+ r[Sysaddr] = (u32int)buf;
+ r[Blksizecnt] = 7<<12 | 1<<16 | Sectsz;
+ r[Irpten] = Datadone|Err;
+ mmccmd(READ_SINGLE_BLOCK, ctlr.ocr & Ccs? bno : bno*Sectsz, rr);
+ i = mmcwait(Datadone|Err);
+ if(i)
+ r[Interrupt] = i;
+ r[Irpten] = 0;
+ if((i & Err) != 0)
+ print("mmcread: error intr %x stat %x\n", i, r[Status]);
+ else if((i & Datadone) == 0)
+ print("mmcread: timeout intr %x stat %x\n", i, r[Status]);
+ else
+ return 0;
+ }
+ return -1;
+}
+
+static int
+dirname(Dir *d, char buf[Maxpath])
+{
+ char c, *x;
+
+ if(d->attr == 0x0F || *d->name <= 0)
+ return -1;
+ memcpy(buf, d->name, 8);
+ x = buf+8;
+ while(x > buf && x[-1] == ' ')
+ x--;
+ if(d->name[8] != ' '){
+ *x++ = '.';
+ memcpy(x, d->name+8, 3);
+ x += 3;
+ }
+ while(x > buf && x[-1] == ' ')
+ x--;
+ *x = 0;
+ x = buf;
+ while(c = *x){
+ if(c >= 'A' && c <= 'Z'){
+ c -= 'A';
+ c += 'a';
+ }
+ *x++ = c;
+ }
+ return x - buf;
+}
+
+static ulong
+dirclust(Dir *d)
+{
+ return GETSHORT(d->starthi)<<16 | GETSHORT(d->startlo);
+}
+
+static void
+fileinit(File *fp, Fat *fat, ulong lba)
+{
+ fp->fat = fat;
+ fp->lba = lba;
+ fp->len = 0;
+ fp->lbaoff = 0;
+ fp->clust = ~0U;
+ fp->rp = fp->ep = fp->buf + Sectsz;
+}
+
+static ulong
+readnext(File *fp, ulong clust)
+{
+ Fat *fat = fp->fat;
+ uchar tmp[2], *p;
+ ulong idx, lba;
+
+ if(fat->ver == Fat12)
+ idx = (3*clust)/2;
+ else
+ idx = clust*fat->ver;
+ lba = fat->fatlba + (idx / Sectsz);
+ if(mmcread(lba, fp->buf))
+ memset(fp->buf, 0xff, Sectsz);
+ p = &fp->buf[idx % Sectsz];
+ if(p == &fp->buf[Sectsz-1]){
+ tmp[0] = *p;
+ if(mmcread(++lba, fp->buf))
+ memset(fp->buf, 0xff, Sectsz);
+ tmp[1] = fp->buf[0];
+ p = tmp;
+ }
+ if(fat->ver == Fat32)
+ return GETLONG(p) & 0xfffffff;
+ idx = GETSHORT(p);
+ if(fat->ver == Fat12){
+ if(clust & 1)
+ idx >>= 4;
+ idx &= 0xfff;
+ }
+ return idx;
+}
+
+static int
+fileread(File *fp, void *data, int len)
+{
+ Fat *fat = fp->fat;
+
+ if(fp->len > 0 && fp->rp >= fp->ep){
+ if(fp->clust != ~0U){
+ if(fp->lbaoff % fat->clustsize == 0){
+ if(fp->clust < 2 || fp->clust >= fat->eofmark)
+ return -1;
+ fp->lbaoff = (fp->clust - 2) * fat->clustsize;
+ fp->clust = readnext(fp, fp->clust);
+ fp->lba = fp->lbaoff + fat->datalba;
+ }
+ fp->lbaoff++;
+ }
+ if(mmcread(fp->lba++, fp->rp = fp->buf))
+ return -1;
+ }
+ if(fp->len < len)
+ len = fp->len;
+ if(len > (fp->ep - fp->rp))
+ len = fp->ep - fp->rp;
+ memcpy(data, fp->rp, len);
+ fp->rp += len;
+ fp->len -= len;
+ return len;
+}
+
+static int
+fatwalk(File *fp, Fat *fat, char *path)
+{
+ char name[Maxpath], *end;
+ int i, j;
+ Dir d;
+
+ if(fat->ver == Fat32){
+ fileinit(fp, fat, 0);
+ fp->clust = fat->dirstart;
+ fp->len = ~0U;
+ }else{
+ fileinit(fp, fat, fat->dirstart);
+ fp->len = fat->dirents * Dirsz;
+ }
+ for(;;){
+ if(fileread(fp, &d, Dirsz) != Dirsz)
+ break;
+ if((i = dirname(&d, name)) <= 0)
+ continue;
+ while(*path == '/')
+ path++;
+ for(end = path; *end != '\0'; end++)
+ if(*end == '/')
+ break;
+ j = end - path;
+ if(i == j && memcmp(name, path, j) == 0){
+ fileinit(fp, fat, 0);
+ fp->clust = dirclust(&d);
+ fp->len = GETLONG(d.len);
+ if(*end == 0)
+ return 0;
+ else if(d.attr & 0x10){
+ fp->len = fat->clustsize * Sectsz;
+ path = end;
+ continue;
+ }
+ break;
+ }
+ }
+ return -1;
+}
+
+static int
+conffat(Fat *fat, void *buf)
+{
+ Pbs *p = buf;
+ uint fatsize, volsize, datasize, reserved;
+ uint ver, dirsize, dirents, clusters;
+
+ if(GETSHORT(p->sectsize) != Sectsz)
+ return -1;
+ if(memcmp(p->type, "FAT", 3) && memcmp(((Pbs32*)buf)->type, "FAT", 3))
+ return -1;
+
+ /* load values from fat */
+ ver = 0;
+ fatsize = GETSHORT(p->fatsize);
+ if(fatsize == 0){
+ fatsize = GETLONG(((Pbs32*)buf)->fatsize);
+ ver = Fat32;
+ }
+ volsize = GETSHORT(p->volsize);
+ if(volsize == 0)
+ volsize = GETLONG(p->bigvolsize);
+ reserved = GETSHORT(p->nreserv);
+ dirents = GETSHORT(p->rootsize);
+ dirsize = (dirents * Dirsz + Sectsz - 1) / Sectsz;
+ datasize = volsize - (reserved + fatsize * p->nfats + dirsize);
+ clusters = datasize / p->clustsize;
+ if(ver != Fat32)
+ if(clusters < 0xff7)
+ ver = Fat12;
+ else
+ ver = Fat16;
+
+ /* fill FAT descriptor */
+ fat->ver = ver;
+ fat->dirents = dirents;
+ fat->clustsize = p->clustsize;
+ fat->fatlba = fat->partlba + reserved;
+ fat->dirstart = fat->fatlba + fatsize * p->nfats;
+ if(ver == Fat32){
+ fat->datalba = fat->dirstart;
+ fat->dirstart = GETLONG(((Pbs32*)buf)->rootclust);
+ fat->eofmark = 0xffffff7;
+ }else{
+ fat->datalba = fat->dirstart + dirsize;
+ if(ver == Fat16)
+ fat->eofmark = 0xfff7;
+ else
+ fat->eofmark = 0xff7;
+ }
+ return 0;
+}
+
+static int
+findfat(Fat *fat, ulong xbase, ulong lba)
+{
+ struct {
+ uchar status;
+ uchar bchs[3];
+ uchar typ;
+ uchar echs[3];
+ uchar lba[4];
+ uchar len[4];
+ } p[4];
+ uchar buf[Sectsz];
+ int i;
+
+ if(xbase == 0)
+ xbase = lba;
+ if(mmcread(lba, buf))
+ return -1;
+ if(buf[0x1fe] != 0x55 || buf[0x1ff] != 0xAA)
+ return -1;
+ memcpy(p, &buf[0x1be], sizeof(p));
+ for(i=0; i<4; i++){
+ switch(p[i].typ){
+ case 0x05:
+ case 0x0f:
+ case 0x85:
+ /* extended partitions */
+ if(!findfat(fat, xbase, xbase + GETLONG(p[i].lba)))
+ return 0;
+ /* no break */
+ case 0x00:
+ continue;
+ default:
+ fat->partlba = lba + GETLONG(p[i].lba);
+ if(mmcread(fat->partlba, buf))
+ continue;
+ if(!conffat(fat, buf))
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+load(Fat *fat, char *path, void *data)
+{
+ uchar *p;
+ File fi;
+ int n;
+
+ print("%s", path);
+ if(fatwalk(&fi, fat, path)){
+ print(": not found\n", path);
+ return -1;
+ }
+ print("...");
+ p = data;
+ while((n = fileread(&fi, p, Sectsz)) > 0)
+ p += n;
+ print("\n");
+ return p - (uchar*)data;
+}
+
+int
+mmcboot(void)
+{
+ char file[Maxpath], *p;
+ Fat fat;
+
+ if(mmcinit() < 0)
+ return 0;
+ if(findfat(&fat, 0, 0)){
+ print("no fat\n");
+ return 0;
+ }
+ memcpy(file, "9zynq", 6);
+ memset(p = (char*)CONF, 0, CONFSIZE);
+ p += load(&fat, "plan9.ini", p);
+ p -= 9; /* "bootfile=" */
+ while(--p >= (char*)CONF){
+ while(p > (char*)CONF && p[-1] != '\n')
+ p--;
+ if(memcmp("bootfile=", p, 9) == 0){
+ p += 9;
+ memcpy(file, p, sizeof(file)-1);
+ for(p=file; p < &file[sizeof(file)-1]; p++)
+ if(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
+ break;
+ *p = '\0';
+ break;
+ }
+ }
+ return load(&fat, file, (void*)TZERO) > 0;
+}
--- /dev/null
+++ b/os/boot/zynq/net.c
@@ -1,0 +1,577 @@
+#include <u.h>
+#include "dat.h"
+#include "fns.h"
+#include "mem.h"
+
+enum {
+ ETHLEN = 1600,
+ UDPLEN = 576,
+ NRX = 64,
+ RXBASE = 128 * 1024 * 1024,
+
+ ETHHEAD = 14,
+ IPHEAD = 20,
+ UDPHEAD = 8,
+
+ BOOTREQ = 1,
+ DHCPDISCOVER = 1,
+ DHCPOFFER,
+ DHCPREQUEST,
+ DHCPDECLINE,
+};
+
+enum {
+ NET_CTRL,
+ NET_CFG,
+ NET_STATUS,
+ DMA_CFG = 4,
+ TX_STATUS,
+ RX_QBAR,
+ TX_QBAR,
+ RX_STATUS,
+ INTR_STATUS,
+ INTR_EN,
+ INTR_DIS,
+ INTR_MASK,
+ PHY_MAINT,
+ RX_PAUSEQ,
+ TX_PAUSEQ,
+ HASH_BOT = 32,
+ HASH_TOP,
+ SPEC_ADDR1_BOT,
+ SPEC_ADDR1_TOP,
+};
+
+enum {
+ MDCTRL,
+ MDSTATUS,
+ MDID1,
+ MDID2,
+ MDAUTOADV,
+ MDAUTOPART,
+ MDAUTOEX,
+ MDAUTONEXT,
+ MDAUTOLINK,
+ MDGCTRL,
+ MDGSTATUS,
+ MDPHYCTRL = 0x1f,
+};
+
+enum {
+ /* NET_CTRL */
+ RXEN = 1<<2,
+ TXEN = 1<<3,
+ MDEN = 1<<4,
+ STARTTX = 1<<9,
+ /* NET_CFG */
+ SPEED = 1<<0,
+ FDEN = 1<<1,
+ RX1536EN = 1<<8,
+ GIGE_EN = 1<<10,
+ RXCHKSUMEN = 1<<24,
+ /* NET_STATUS */
+ PHY_IDLE = 1<<2,
+ /* DMA_CFG */
+ TXCHKSUMEN = 1<<11,
+ /* TX_STATUS */
+ TXCOMPL = 1<<5,
+ /* MDCTRL */
+ MDRESET = 1<<15,
+ AUTONEG = 1<<12,
+ FULLDUP = 1<<8,
+ /* MDSTATUS */
+ LINK = 1<<2,
+ /* MDGSTATUS */
+ RECVOK = 3<<12,
+};
+
+typedef struct {
+ uchar edest[6];
+ uchar esrc[6];
+ ulong idest;
+ ulong isrc;
+ ushort dport, sport;
+ ushort len;
+ uchar data[UDPLEN];
+} udp;
+
+static ulong *eth0 = (ulong *) 0xe000b000;
+static int phyaddr = 7;
+
+static u32int myip, dhcpip, tftpip, xid;
+static uchar mac[6] = {0x0E, 0xA7, 0xDE, 0xAD, 0xBE, 0xEF};
+static uchar tmac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+static char file[128];
+
+static udp ubuf, urbuf;
+static uchar txbuf[ETHLEN];
+static ulong txdesc[4], *txact, *rxact;
+static ulong rxdesc[NRX*2];
+
+void
+mdwrite(ulong *r, int reg, u16int val)
+{
+ while((r[NET_STATUS] & PHY_IDLE) == 0)
+ ;
+ r[PHY_MAINT] = 1<<30 | 1<<28 | 1<<17 | phyaddr << 23 | reg << 18 | val;
+ while((r[NET_STATUS] & PHY_IDLE) == 0)
+ ;
+}
+
+u16int
+mdread(ulong *r, int reg)
+{
+ while((r[NET_STATUS] & PHY_IDLE) == 0)
+ ;
+ r[PHY_MAINT] = 1<<30 | 1<<29 | 1<<17 | phyaddr << 23 | reg << 18;
+ while((r[NET_STATUS] & PHY_IDLE) == 0)
+ ;
+ return r[PHY_MAINT];
+}
+
+void
+ethinit(ulong *r)
+{
+ int v;
+ ulong *p;
+ ulong d;
+
+ r[NET_CTRL] = 0;
+ r[RX_STATUS] = 0xf;
+ r[TX_STATUS] = 0xff;
+ r[INTR_DIS] = 0x7FFFEFF;
+ r[RX_QBAR] = r[TX_QBAR] = 0;
+ r[NET_CFG] = MDC_DIV << 18 | FDEN | SPEED | RX1536EN | GIGE_EN | RXCHKSUMEN;
+ r[SPEC_ADDR1_BOT] = mac[0] | mac[1] << 8 | mac[2] << 16 | mac[3] << 24;
+ r[SPEC_ADDR1_TOP] = mac[4] | mac[5] << 8;
+ r[DMA_CFG] = TXCHKSUMEN | 0x18 << 16 | 1 << 10 | 3 << 8 | 0x10;
+
+ txdesc[0] = 0;
+ txdesc[1] = 1<<31;
+ txdesc[2] = 0;
+ txdesc[3] = 1<<31 | 1<<30;
+ txact = txdesc;
+ r[TX_QBAR] = (ulong) txdesc;
+ for(p = rxdesc, d = RXBASE; p < rxdesc + nelem(rxdesc); d += ETHLEN){
+ *p++ = d;
+ *p++ = 0;
+ }
+ p[-2] |= 2;
+ rxact = rxdesc;
+ r[RX_QBAR] = (ulong) rxdesc;
+
+ r[NET_CTRL] = MDEN;
+// mdwrite(r, MDCTRL, MDRESET);
+ mdwrite(r, MDCTRL, AUTONEG);
+ if((mdread(r, MDSTATUS) & LINK) == 0){
+ puts("Waiting for Link ...\n");
+ while((mdread(r, MDSTATUS) & LINK) == 0)
+ ;
+ }
+ *(u32int*)(SLCR_BASE + SLCR_UNLOCK) = UNLOCK_KEY;
+ v = mdread(r, MDPHYCTRL);
+ if((v & 0x40) != 0){
+ puts("1000BASE-T");
+ while((mdread(r, MDGSTATUS) & RECVOK) != RECVOK)
+ ;
+ r[NET_CFG] |= GIGE_EN;
+ *(u32int*)(SLCR_BASE + GEM0_CLK_CTRL) = 1 << 20 | 8 << 8 | 1;
+ }else if((v & 0x20) != 0){
+ puts("100BASE-TX");
+ r[NET_CFG] = r[NET_CFG] & ~GIGE_EN | SPEED;
+ *(u32int*)(SLCR_BASE + GEM0_CLK_CTRL) = 5 << 20 | 8 << 8 | 1;
+ }else if((v & 0x10) != 0){
+ puts("10BASE-T");
+ r[NET_CFG] = r[NET_CFG] & ~(GIGE_EN | SPEED);
+ *(u32int*)(SLCR_BASE + GEM0_CLK_CTRL) = 20 << 20 | 20 << 8 | 1;
+ }else
+ puts("???");
+ *(u32int*)(SLCR_BASE + SLCR_UNLOCK) = LOCK_KEY;
+ if((v & 0x08) != 0)
+ puts(" Full Duplex\n");
+ else{
+ puts(" Half Duplex\n");
+ r[NET_CFG] &= ~FDEN;
+ }
+ r[NET_CTRL] |= TXEN | RXEN;
+}
+
+void
+ethtx(ulong *r, uchar *buf, int len)
+{
+ txact[0] = (ulong) buf;
+ txact[1] = 1<<15 | len;
+ if(txact == txdesc + nelem(txdesc) - 2){
+ txact[1] |= 1<<30;
+ txact = txdesc;
+ }else
+ txact += 2;
+ r[TX_STATUS] = -1;
+ r[NET_CTRL] |= STARTTX;
+ while((r[TX_STATUS] & TXCOMPL) == 0)
+ ;
+}
+
+void
+udptx(ulong *r, udp *u)
+{
+ uchar *p, *q;
+ int n;
+
+ p = q = txbuf;
+ memcpy(p, u->edest, 6);
+ memcpy(p + 6, u->esrc, 6);
+ q += 12;
+ *q++ = 8;
+ *q++ = 0;
+
+ *q++ = 5 | 4 << 4;
+ *q++ = 0;
+ n = IPHEAD + UDPHEAD + u->len;
+ *q++ = n >> 8;
+ *q++ = n;
+
+ *q++ = 0x13;
+ *q++ = 0x37;
+ *q++ = 1<<6;
+ *q++ = 0;
+
+ *q++ = 1;
+ *q++ = 0x11;
+ *q++ = 0;
+ *q++ = 0;
+ q = u32put(q, u->isrc);
+ q = u32put(q, u->idest);
+
+ *q++ = u->sport >> 8;
+ *q++ = u->sport;
+ *q++ = u->dport >> 8;
+ *q++ = u->dport;
+ n = UDPHEAD + u->len;
+ *q++ = n >> 8;
+ *q++ = n;
+ *q++ = 0;
+ *q++ = 0;
+
+ memcpy(q, u->data, u->len);
+ ethtx(r, p, ETHHEAD + IPHEAD + UDPHEAD + u->len);
+}
+
+void
+dhcppkg(ulong *r, int t)
+{
+ uchar *p;
+ udp *u;
+
+ u = &ubuf;
+ p = u->data;
+ *p++ = BOOTREQ;
+ *p++ = 1;
+ *p++ = 6;
+ *p++ = 0;
+ p = u32put(p, xid);
+ p = u32put(p, 0x8000);
+ memset(p, 0, 16);
+ u32put(p + 8, dhcpip);
+ p += 16;
+ memcpy(p, mac, 6);
+ p += 6;
+ memset(p, 0, 202);
+ p += 202;
+ *p++ = 99;
+ *p++ = 130;
+ *p++ = 83;
+ *p++ = 99;
+
+ *p++ = 53;
+ *p++ = 1;
+ *p++ = t;
+ if(t == DHCPREQUEST){
+ *p++ = 50;
+ *p++ = 4;
+ p = u32put(p, myip);
+ *p++ = 54;
+ *p++ = 4;
+ p = u32put(p, dhcpip);
+ }
+
+ *p++ = 0xff;
+
+ memset(u->edest, 0xff, 6);
+ memcpy(u->esrc, mac, 6);
+ u->sport = 68;
+ u->dport = 67;
+ u->idest = -1;
+ u->isrc = 0;
+ u->len = p - u->data;
+ udptx(r, u);
+}
+
+uchar *
+ethrx(void)
+{
+ while((*rxact & 1) == 0)
+ if(timertrig())
+ return nil;
+ return (uchar *) (*rxact & ~3);
+}
+
+void
+ethnext(void)
+{
+ *rxact &= ~1;
+ if((*rxact & 2) != 0)
+ rxact = rxdesc;
+ else
+ rxact += 2;
+}
+
+void
+arp(int op, uchar *edest, ulong idest)
+{
+ uchar *p;
+ static uchar broad[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ p = txbuf;
+ if(edest == nil)
+ edest = broad;
+ memcpy(p, edest, 6);
+ memcpy(p + 6, mac, 6);
+ p[12] = 8;
+ p[13] = 6;
+ p += 14;
+ p = u32put(p, 0x00010800);
+ p = u32put(p, 0x06040000 | op);
+ memcpy(p, mac, 6);
+ p = u32put(p + 6, myip);
+ memcpy(p, edest, 6);
+ p = u32put(p + 6, idest);
+ ethtx(eth0, txbuf, p - txbuf);
+}
+
+void
+arpc(uchar *p)
+{
+ p += 14;
+ if(u32get(p) != 0x00010800 || p[4] != 6 || p[5] != 4 || p[6] != 0)
+ return;
+ switch(p[7]){
+ case 1:
+ if(myip != 0 && u32get(p + 24) == myip)
+ arp(2, p + 8, u32get(p + 14));
+ break;
+ case 2:
+ if(tftpip != 0 && u32get(p + 14) == tftpip)
+ memcpy(tmac, p + 8, 6);
+ break;
+ }
+}
+
+udp *
+udprx(void)
+{
+ uchar *p;
+ ulong v;
+ udp *u;
+
+ u = &urbuf;
+ for(;; ethnext()){
+ p = ethrx();
+ if(p == nil)
+ return nil;
+ if(p[12] != 8)
+ continue;
+ if(p[13] == 6){
+ arpc(p);
+ continue;
+ }
+ if(p[13] != 0)
+ continue;
+ p += ETHHEAD;
+ if((p[0] >> 4) != 4 || p[9] != 0x11)
+ continue;
+ v = u32get(p + 16);
+ if(v != (ulong) -1 && v != myip)
+ continue;
+ u->idest = v;
+ u->isrc = u32get(p + 12);
+ p += (p[0] & 0xf) << 2;
+ u->sport = p[0] << 8 | p[1];
+ u->dport = p[2] << 8 | p[3];
+ u->len = p[4] << 8 | p[5];
+ if(u->len < 8)
+ continue;
+ u->len -= 8;
+ if(u->len >= sizeof(u->data))
+ u->len = sizeof(u->data);
+ memcpy(u->data, p + 8, u->len);
+ ethnext();
+ return u;
+ }
+}
+
+void
+arpreq(void)
+{
+ uchar *p;
+
+ arp(1, nil, tftpip);
+ timeren(ARPTIMEOUT);
+ for(;; ethnext()){
+ p = ethrx();
+ if(p == nil){
+ print("ARP timeout\n");
+ timeren(ARPTIMEOUT);
+ arp(1, nil, tftpip);
+ }
+ if(p[12] != 8 || p[13] != 6)
+ continue;
+ arpc(p);
+ if(tmac[0] != 0xff)
+ break;
+ }
+ timeren(-1);
+}
+
+void
+dhcp(ulong *r)
+{
+ udp *u;
+ uchar *p;
+ uchar type;
+
+ xid = 0xdeadbeef;
+ tftpip = 0;
+ dhcppkg(r, DHCPDISCOVER);
+ timeren(DHCPTIMEOUT);
+ for(;;){
+ u = udprx();
+ if(u == nil){
+ timeren(DHCPTIMEOUT);
+ dhcppkg(r, DHCPDISCOVER);
+ print("DHCP timeout\n");
+ }
+ p = u->data;
+ if(u->dport != 68 || p[0] != 2 || u32get(p + 4) != xid || u32get(p + 236) != 0x63825363)
+ continue;
+ p += 240;
+ type = 0;
+ dhcpip = 0;
+ for(; p < u->data + u->len && *p != 0xff; p += 2 + p[1])
+ switch(*p){
+ case 53:
+ type = p[2];
+ break;
+ case 54:
+ dhcpip = u32get(p + 2);
+ break;
+ }
+ if(type != DHCPOFFER)
+ continue;
+ p = u->data;
+ if(p[108] == 0){
+ print("Offer from %I for %I with no boot file\n", dhcpip, u32get(p + 16));
+ continue;
+ }
+ myip = u32get(p + 16);
+ tftpip = u32get(p + 20);
+ memcpy(file, p + 108, 128);
+ print("Offer from %I for %I with boot file '%s' at %I\n", dhcpip, myip, file, tftpip);
+ break;
+ }
+ timeren(-1);
+ dhcppkg(r, DHCPREQUEST);
+}
+
+udp *
+tftppkg(void)
+{
+ udp *u;
+
+ u = &ubuf;
+ memcpy(u->edest, tmac, 6);
+ memcpy(u->esrc, mac, 6);
+ u->idest = tftpip;
+ u->isrc = myip;
+ u->sport = 69;
+ u->dport = 69;
+ return u;
+}
+
+void
+tftp(ulong *r, char *q, uintptr base)
+{
+ udp *u, *v;
+ uchar *p;
+ int bn, len;
+
+restart:
+ u = tftppkg();
+ p = u->data;
+ *p++ = 0;
+ *p++ = 1;
+ do
+ *p++ = *q;
+ while(*q++ != 0);
+ memcpy(p, "octet", 6);
+ p += 6;
+ u->len = p - u->data;
+ udptx(r, u);
+ timeren(TFTPTIMEOUT);
+
+ for(;;){
+ v = udprx();
+ if(v == nil){
+ print("TFTP timeout");
+ goto restart;
+ }
+ if(v->dport != 69 || v->isrc != tftpip || v->idest != myip)
+ continue;
+ if(v->data[0] != 0)
+ continue;
+ switch(v->data[1]){
+ case 3:
+ bn = v->data[2] << 8 | v->data[3];
+ len = v->len - 4;
+ if(len < 0)
+ continue;
+ if(len > 512)
+ len = 512;
+ memcpy((char*)base + ((bn - 1) << 9), v->data + 4, len);
+ if((bn & 127) == 0)
+ putc('.');
+ p = u->data;
+ *p++ = 0;
+ *p++ = 4;
+ *p++ = bn >> 8;
+ *p = bn;
+ u->len = 4;
+ udptx(r, u);
+ if(len < 512){
+ putc(10);
+ timeren(-1);
+ return;
+ }
+ timeren(TFTPTIMEOUT);
+ break;
+ case 5:
+ v->data[v->len - 1] = 0;
+ print("TFTP error: %s\n", v->data + 4);
+ timeren(-1);
+ return;
+ }
+ }
+}
+
+int
+netboot(void)
+{
+ ethinit(eth0);
+ myip = 0;
+ dhcp(eth0);
+ arpreq();
+ tftp(eth0, file, TZERO);
+ memset((void *) CONF, 0, CONFSIZE);
+ tftp(eth0, "/cfg/pxe/0ea7deadbeef", CONF);
+ return 1;
+}
--- /dev/null
+++ b/os/boot/zynq/qspi.c
@@ -1,0 +1,45 @@
+#include <u.h>
+#include "dat.h"
+#include "fns.h"
+
+enum {
+ QSPI_CFG,
+ QSPI_STATUS,
+ QSPI_EN = 5,
+ QSPI_TXD4 = 7,
+ QSPI_RXD,
+ QSPI_TXD1 = 32,
+ QSPI_TXD2,
+ QSPI_TXD3
+};
+
+#define QSPI0 ((void *) 0xE000D000)
+
+static u32int
+cmd(ulong *r, int sz, u32int c)
+{
+ if(sz == 4)
+ r[QSPI_TXD4] = c;
+ else
+ r[QSPI_TXD1 + sz - 1] = c;
+ r[QSPI_CFG] |= 1<<16;
+ while((r[QSPI_STATUS] & (1<<2|1<<4)) != (1<<2|1<<4))
+ ;
+ return r[QSPI_RXD];
+}
+
+void
+flash(void)
+{
+ ulong *r;
+
+ r = QSPI0;
+ r[QSPI_CFG] = 1<<31 | 1<<19 | 3<<6 | 1<<15 | 1<<14 | 1<<10 | 1<<3 | 1;
+ r[QSPI_CFG] &= ~(1<<10);
+ r[QSPI_EN] = 1;
+ cmd(r, 1, 0x06);
+// cmd(r, 3, 0xD8);
+ for(;;)
+ print("%x\n", cmd(r, 2, 0x05));
+
+}