--- /sys/man/8/nboot Sat Jan 29 21:24:18 2022 +++ /sys/man/8/nboot Sat Jan 29 00:00:00 2022 @@ -0,0 +1,188 @@ +.TH 9BOOT 8 +.SH NAME +9bootfat, 9bootiso, 9boothyb, 9bootpxe, bootia32.efi, bootx64.efi, efiboot.fat \- PC bootloader for FAT, ISO and PXE network booting +.SH SYNOPSIS +Started by PC BIOS/EFI or chainloaded by partition bootsector +.SH DESCRIPTION +9boot is the bootloader used on PCs to start the Plan 9 kernel. +Its task is to read and parse the +.IR plan9.ini (8) +configuration file, gather some basic system information like +the amount of usable system memory, do some basic system +initialization and load the kernel from the boot media into memory. + +After reading the configuration, the loader will automatically +attempt to boot the kernel that was specified by the +.B bootfile= +parameter. If there is no such parameter, a key +gets pressed on the keyboard or the kernel file was not +found then the loader enters the interactive +boot console. + +The syntax of the boot console is the same as in the +.IR plan9.ini (8) +file with +.IB key = value +pairs setting boot parameters. In addition a few command +words are recognized that are intended for interactive use: +.TP +.BI clear [prefix] +can be used to remove parameters from the configuration. +If a +.IR prefix +is specified, the first parameter that matches the prefix +is removed. If the +.IR prefix +argument is omitted, the whole configuration will be reset. +.TP +.B show +displays the current configuration in memory. +.TP +.B wait +will return to the console prompt after processing the +configuration file preventing automatic boot. +.TP +.B boot +will end the console and attempt booting the kernel. +.SS +There are many ways to boot a PC so +.IR 9boot +was split into a number of distinct programs, one for each boot +method. +.SH FAT BOOTING +When booting Plan 9 from a harddisk or USB pen drive, a +FAT16/32 partition +.IR (9fat) +is used to store the kernel and +.IR plan9.ini (8) +configuration. Due to size limitations, instead of loading +the kernel directly, the bootsector +.IR (pbs) +of the FAT partition loads +a 2nd stage bootloader +.IR (9bootfat) +from the root directory of the filesystem. +.SH CD-ROM BOOTING +Booting from CD-ROM requires only the +.IR 9bootiso +bootloader to be included in the ISO-9660 image under +.BR /386/9bootiso , +set as a non-emulation bootblock (see +.B -B +in +.IR mk9660 (8)). +Boot parameters are read from +.BR /cfg/plan9.ini . +.SH ISO HYBRID BOOTING +With the +.I 9boothyb +loader, an ISO image can be made into a bootable disk by +creating a MBR and appending a bootable DOS partition containing +.I 9boothyb +renamed to +.IR 9bootfat . +The loader will read the ISO filesystem as if it were stored +on a CD-ROM drive. +.SH NETWORK BOOTING +With a PXE capable BIOS and network card one can download +.IR 9bootpxe +and boot the kernel from a TFTP server (see +.IR dhcpd (8) +and +.IR ndb (6) +for details). Once started, +.IR 9bootpxe +will read the file +.B /cfg/pxe/$ether +or, if this file is not present, +.B /cfg/pxe/default +from the tftp server, where +.B $ether +is the MAC address of the client's network card +in lower case hex, and uses this as its +.IR plan9.ini (8) +file. +.SH EFI BOOTING +EFI firmware looks for the files +.I bootia32.efi +(for 386) +or +.I bootx64.efi +(for amd64) +in the boot media and executes them. +For local disk media, these files are located in the directory +.B /efi/boot +of the +.B FAT +formatted boot partition. +For +.B CD-ROM +media, the boot partition is provided +as a embedded +.B FAT +filesystem image +.I efiboot.fat +(see +.B -E +in +.IR mk9660 (8)). +In the network boot case, the +.I bootia32.efi +or +.I bootx64.efi +files are used as the +.B BSP +program instead of +.IR 9bootpxe . +Once started, the boot media +.RB ( PXE , +.BR ISO , +.BR FAT ) +is discovered and +.IR plan9.ini (8) +configuration is read from it in the same way as +with the BIOS-based +.I 9boot* +loaders. If the EFI loader was executed from a +.B FAT +partition, it will first search for +.IR plan9.ini (8) +in the same +.B FAT +filesystem that it was loaded from, and if not found, will search for +.IR plan9.ini (8) +in any other partition in an implementation-defined order. The kernel +is always loaded from the same partition that +.IR plan9.ini (8) +is read from. +.SH FILES +.B /386/pbs +.br +.B /386/9bootfat +.br +.B /386/9bootiso +.br +.B /386/9boothyb +.br +.B /386/9bootpxe +.br +.B /386/bootia32.efi +.br +.B /386/bootx64.efi +.br +.B /386/efiboot.fat +.SH SOURCE +.BR /sys/src/boot/pc +.br +.BR /sys/src/boot/efi +.br +.SH "SEE ALSO" +.IR plan9.ini (8), +.IR mk9660 (8), +.IR dhcpd (8), +.IR ndb (6) +.br +.I https://uefi.org +.SH HISTORY +9boot first appeared in 9front (April, 2011). +EFI support first appeared in 9front (Oct, 2014). diff -Nru /sys/src/nboot/bcm/mkfile /sys/src/nboot/bcm/mkfile --- /sys/src/nboot/bcm/mkfile Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/bcm/mkfile Sat Jan 29 00:00:00 2022 @@ -0,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 + } diff -Nru /sys/src/nboot/bitsy/donprint.c /sys/src/nboot/bitsy/donprint.c --- /sys/src/nboot/bitsy/donprint.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/bitsy/donprint.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,332 @@ +#include "u.h" +#include "lib.h" + +#define PTR sizeof(char*) +#define SHORT sizeof(int) +#define INT sizeof(int) +#define LONG sizeof(long) +#define IDIGIT 30 +#define MAXCON 30 + +#define FLONG (1<<0) +#define FSHORT (1<<1) +#define FUNSIGN (1<<2) + +typedef struct Op Op; +struct Op +{ + char *p; + char *ep; + void *argp; + int f1; + int f2; + int f3; +}; + +static int noconv(Op*); +static int cconv(Op*); +static int dconv(Op*); +static int hconv(Op*); +static int lconv(Op*); +static int oconv(Op*); +static int sconv(Op*); +static int uconv(Op*); +static int xconv(Op*); +static int Xconv(Op*); +static int percent(Op*); + +static +int (*fmtconv[MAXCON])(Op*) = +{ + noconv, + cconv, dconv, hconv, lconv, + oconv, sconv, uconv, xconv, + Xconv, percent, +}; +static +char fmtindex[128] = +{ + ['c'] 1, + ['d'] 2, + ['h'] 3, + ['l'] 4, + ['o'] 5, + ['s'] 6, + ['u'] 7, + ['x'] 8, + ['X'] 9, + ['%'] 10, +}; + +static int convcount = { 11 }; +static int ucase; + +static void +PUT(Op *o, int c) +{ + static int pos; + int opos; + + if(c == '\t'){ + opos = pos; + pos = (opos+8) & ~7; + while(opos++ < pos && o->p < o->ep) + *o->p++ = ' '; + return; + } + if(o->p < o->ep){ + *o->p++ = c; + pos++; + } + if(c == '\n') + pos = 0; +} + +int +fmtinstall(char c, int (*f)(Op*)) +{ + + c &= 0177; + if(fmtindex[c] == 0) { + if(convcount >= MAXCON) + return 1; + fmtindex[c] = convcount++; + } + fmtconv[fmtindex[c]] = f; + return 0; +} + +char* +donprint(char *p, char *ep, char *fmt, void *argp) +{ + int sf1, c; + Op o; + + o.p = p; + o.ep = ep; + o.argp = argp; + +loop: + c = *fmt++; + if(c != '%') { + if(c == 0) { + if(o.p < o.ep) + *o.p = 0; + return o.p; + } + PUT(&o, c); + goto loop; + } + o.f1 = 0; + o.f2 = -1; + o.f3 = 0; + c = *fmt++; + sf1 = 0; + if(c == '-') { + sf1 = 1; + c = *fmt++; + } + while(c >= '0' && c <= '9') { + o.f1 = o.f1*10 + c-'0'; + c = *fmt++; + } + if(sf1) + o.f1 = -o.f1; + if(c != '.') + goto l1; + c = *fmt++; + while(c >= '0' && c <= '9') { + if(o.f2 < 0) + o.f2 = 0; + o.f2 = o.f2*10 + c-'0'; + c = *fmt++; + } +l1: + if(c == 0) + fmt--; + c = (*fmtconv[fmtindex[c&0177]])(&o); + if(c < 0) { + o.f3 |= -c; + c = *fmt++; + goto l1; + } + o.argp = (char*)o.argp + c; + goto loop; +} + +void +strconv(char *o, Op *op, int f1, int f2) +{ + int n, c; + char *p; + + n = strlen(o); + if(f1 >= 0) + while(n < f1) { + PUT(op, ' '); + n++; + } + for(p=o; c = *p++;) + if(f2 != 0) { + PUT(op, c); + f2--; + } + if(f1 < 0) { + f1 = -f1; + while(n < f1) { + PUT(op, ' '); + n++; + } + } +} + +int +numbconv(Op *op, int base) +{ + char b[IDIGIT]; + int i, f, n, r; + long v; + short h; + + f = 0; + switch(op->f3 & (FLONG|FSHORT|FUNSIGN)) { + case FLONG: + v = *(long*)op->argp; + r = LONG; + break; + + case FUNSIGN|FLONG: + v = *(ulong*)op->argp; + r = LONG; + break; + + case FSHORT: + h = *(int*)op->argp; + v = h; + r = SHORT; + break; + + case FUNSIGN|FSHORT: + h = *(int*)op->argp; + v = (ushort)h; + r = SHORT; + break; + + default: + v = *(int*)op->argp; + r = INT; + break; + + case FUNSIGN: + v = *(unsigned*)op->argp; + r = INT; + break; + } + if(!(op->f3 & FUNSIGN) && v < 0) { + v = -v; + f = 1; + } + b[IDIGIT-1] = 0; + for(i = IDIGIT-2;; i--) { + n = (ulong)v % base; + n += '0'; + if(n > '9'){ + n += 'a' - ('9'+1); + if(ucase) + n += 'A'-'a'; + } + b[i] = n; + if(i < 2) + break; + v = (ulong)v / base; + if(op->f2 >= 0 && i >= IDIGIT-op->f2) + continue; + if(v <= 0) + break; + } + if(f) + b[--i] = '-'; + strconv(b+i, op, op->f1, -1); + return r; +} + +static int +noconv(Op *op) +{ + + strconv("***", op, 0, -1); + return 0; +} + +static int +cconv(Op *op) +{ + char b[2]; + + b[0] = *(int*)op->argp; + b[1] = 0; + strconv(b, op, op->f1, -1); + return INT; +} + +static int +dconv(Op *op) +{ + return numbconv(op, 10); +} + +static int +hconv(Op*) +{ + return -FSHORT; +} + +static int +lconv(Op*) +{ + return -FLONG; +} + +static int +oconv(Op *op) +{ + return numbconv(op, 8); +} + +static int +sconv(Op *op) +{ + strconv(*(char**)op->argp, op, op->f1, op->f2); + return PTR; +} + +static int +uconv(Op*) +{ + return -FUNSIGN; +} + +static int +xconv(Op *op) +{ + return numbconv(op, 16); +} + +static int +Xconv(Op *op) +{ + int r; + + ucase = 1; + r = numbconv(op, 16); + ucase = 0; + return r; +} + +static int +percent(Op *op) +{ + + PUT(op, '%'); + return 0; +} diff -Nru /sys/src/nboot/bitsy/fns.h /sys/src/nboot/bitsy/fns.h --- /sys/src/nboot/bitsy/fns.h Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/bitsy/fns.h Sat Jan 29 00:00:00 2022 @@ -0,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); diff -Nru /sys/src/nboot/bitsy/il.s /sys/src/nboot/bitsy/il.s --- /sys/src/nboot/bitsy/il.s Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/bitsy/il.s Sat Jan 29 00:00:00 2022 @@ -0,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 diff -Nru /sys/src/nboot/bitsy/imain.c /sys/src/nboot/bitsy/imain.c --- /sys/src/nboot/bitsy/imain.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/bitsy/imain.c Sat Jan 29 00:00:00 2022 @@ -0,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++) + ; + } +} diff -Nru /sys/src/nboot/bitsy/inflate.c /sys/src/nboot/bitsy/inflate.c --- /sys/src/nboot/bitsy/inflate.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/bitsy/inflate.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,208 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include + +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 *) +{ +} diff -Nru /sys/src/nboot/bitsy/io.h /sys/src/nboot/bitsy/io.h --- /sys/src/nboot/bitsy/io.h Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/bitsy/io.h Sat Jan 29 00:00:00 2022 @@ -0,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; diff -Nru /sys/src/nboot/bitsy/l.s /sys/src/nboot/bitsy/l.s --- /sys/src/nboot/bitsy/l.s Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/bitsy/l.s Sat Jan 29 00:00:00 2022 @@ -0,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 diff -Nru /sys/src/nboot/bitsy/lib.h /sys/src/nboot/bitsy/lib.h --- /sys/src/nboot/bitsy/lib.h Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/bitsy/lib.h Sat Jan 29 00:00:00 2022 @@ -0,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*); diff -Nru /sys/src/nboot/bitsy/map /sys/src/nboot/bitsy/map --- /sys/src/nboot/bitsy/map Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/bitsy/map Sat Jan 29 00:00:00 2022 @@ -0,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"); +} diff -Nru /sys/src/nboot/bitsy/mem.h /sys/src/nboot/bitsy/mem.h --- /sys/src/nboot/bitsy/mem.h Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/bitsy/mem.h Sat Jan 29 00:00:00 2022 @@ -0,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 */ diff -Nru /sys/src/nboot/bitsy/mkfile /sys/src/nboot/bitsy/mkfile --- /sys/src/nboot/bitsy/mkfile Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/bitsy/mkfile Sat Jan 29 00:00:00 2022 @@ -0,0 +1,45 @@ +objtype=arm + 0){ + /* wait for output ready */ + while((ur->status[1] & Tnotfull) == 0) + ; + ur->data = *str++; + } + while((ur->status[1] & Tbusy)) + ; +} diff -Nru /sys/src/nboot/efi/efi.c /sys/src/nboot/efi/efi.c --- /sys/src/nboot/efi/efi.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/efi/efi.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,308 @@ +#include +#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; iBootServices->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; + } +} diff -Nru /sys/src/nboot/efi/efi.h /sys/src/nboot/efi/efi.h --- /sys/src/nboot/efi/efi.h Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/efi/efi.h Sat Jan 29 00:00:00 2022 @@ -0,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; diff -Nru /sys/src/nboot/efi/fns.h /sys/src/nboot/efi/fns.h --- /sys/src/nboot/efi/fns.h Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/efi/fns.h Sat Jan 29 00:00:00 2022 @@ -0,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); diff -Nru /sys/src/nboot/efi/fs.c /sys/src/nboot/efi/fs.c --- /sys/src/nboot/efi/fs.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/efi/fs.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,166 @@ +#include +#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 && iOpen, 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; +} diff -Nru /sys/src/nboot/efi/iso.c /sys/src/nboot/efi/iso.c --- /sys/src/nboot/efi/iso.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/efi/iso.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,226 @@ +#include +#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(read(ex, &d.dirlen, 1) != 1) + break; + if(d.dirlen == 0) + continue; /* zero padding to next sector */ + if(read(ex, &d.dirlen + 1, Dirsz-1) != Dirsz-1) + break; + if(read(ex, name, d.namelen) != d.namelen) + break; + i = d.dirlen - (Dirsz + d.namelen); + while(i-- > 0){ + if(read(ex, &c, 1) != 1) + break; + } + for(i=0; i= '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; iBootServices->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; +} diff -Nru /sys/src/nboot/efi/mem.h /sys/src/nboot/efi/mem.h --- /sys/src/nboot/efi/mem.h Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/efi/mem.h Sat Jan 29 00:00:00 2022 @@ -0,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) */ diff -Nru /sys/src/nboot/efi/mkfile /sys/src/nboot/efi/mkfile --- /sys/src/nboot/efi/mkfile Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/efi/mkfile Sat Jan 29 00:00:00 2022 @@ -0,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.* diff -Nru /sys/src/nboot/efi/pe32.s /sys/src/nboot/efi/pe32.s --- /sys/src/nboot/efi/pe32.s Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/efi/pe32.s Sat Jan 29 00:00:00 2022 @@ -0,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 diff -Nru /sys/src/nboot/efi/pe64.s /sys/src/nboot/efi/pe64.s --- /sys/src/nboot/efi/pe64.s Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/efi/pe64.s Sat Jan 29 00:00:00 2022 @@ -0,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 diff -Nru /sys/src/nboot/efi/pxe.c /sys/src/nboot/efi/pxe.c --- /sys/src/nboot/efi/pxe.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/efi/pxe.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,487 @@ +#include +#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; iBootServices->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; +} diff -Nru /sys/src/nboot/efi/sub.c /sys/src/nboot/efi/sub.c --- /sys/src/nboot/efi/sub.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/efi/sub.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,373 @@ +#include +#include +#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"; +} diff -Nru /sys/src/nboot/mkfile /sys/src/nboot/mkfile --- /sys/src/nboot/mkfile Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/mkfile Sat Jan 29 00:00:00 2022 @@ -0,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 + } diff -Nru /sys/src/nboot/pc/a20.s /sys/src/nboot/pc/a20.s --- /sys/src/nboot/pc/a20.s Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/a20.s Sat Jan 29 00:00:00 2022 @@ -0,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 diff -Nru /sys/src/nboot/pc/apm.s /sys/src/nboot/pc/apm.s --- /sys/src/nboot/pc/apm.s Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/apm.s Sat Jan 29 00:00:00 2022 @@ -0,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 diff -Nru /sys/src/nboot/pc/e820.s /sys/src/nboot/pc/e820.s --- /sys/src/nboot/pc/e820.s Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/e820.s Sat Jan 29 00:00:00 2022 @@ -0,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 diff -Nru /sys/src/nboot/pc/fat.c /sys/src/nboot/pc/fat.c --- /sys/src/nboot/pc/fat.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/fat.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,405 @@ +#include +#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"); + } +} + diff -Nru /sys/src/nboot/pc/fns.h /sys/src/nboot/pc/fns.h --- /sys/src/nboot/pc/fns.h Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/fns.h Sat Jan 29 00:00:00 2022 @@ -0,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); diff -Nru /sys/src/nboot/pc/iso.c /sys/src/nboot/pc/iso.c --- /sys/src/nboot/pc/iso.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/iso.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,200 @@ +#include +#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; ilen > 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(read(ex, &d.dirlen, 1) != 1) + break; + if(d.dirlen == 0) + continue; /* zero padding to next sector */ + if(read(ex, &d.dirlen + 1, Dirsz-1) != Dirsz-1) + break; + if(read(ex, name, d.namelen) != d.namelen) + break; + i = d.dirlen - (Dirsz + d.namelen); + while(i-- > 0){ + if(read(ex, &c, 1) != 1) + break; + } + for(i=0; i= '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"); + } +} + diff -Nru /sys/src/nboot/pc/l.s /sys/src/nboot/pc/l.s --- /sys/src/nboot/pc/l.s Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/l.s Sat Jan 29 00:00:00 2022 @@ -0,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' diff -Nru /sys/src/nboot/pc/mbr.s /sys/src/nboot/pc/mbr.s --- /sys/src/nboot/pc/mbr.s Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/mbr.s Sat Jan 29 00:00:00 2022 @@ -0,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'; diff -Nru /sys/src/nboot/pc/mem.h /sys/src/nboot/pc/mem.h --- /sys/src/nboot/pc/mem.h Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/mem.h Sat Jan 29 00:00:00 2022 @@ -0,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) */ + diff -Nru /sys/src/nboot/pc/mkfile /sys/src/nboot/pc/mkfile --- /sys/src/nboot/pc/mkfile Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/mkfile Sat Jan 29 00:00:00 2022 @@ -0,0 +1,107 @@ +objtype=386 +>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 diff -Nru /sys/src/nboot/pc/pbs.s /sys/src/nboot/pc/pbs.s --- /sys/src/nboot/pc/pbs.s Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/pbs.s Sat Jan 29 00:00:00 2022 @@ -0,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 diff -Nru /sys/src/nboot/pc/pxe.c /sys/src/nboot/pc/pxe.c --- /sys/src/nboot/pc/pxe.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/pxe.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,362 @@ +#include +#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"); + } +} diff -Nru /sys/src/nboot/pc/sub.c /sys/src/nboot/pc/sub.c --- /sys/src/nboot/pc/sub.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/sub.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,554 @@ +#include +#include +#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<= '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"; +} diff -Nru /sys/src/nboot/pc/uart.s /sys/src/nboot/pc/uart.s --- /sys/src/nboot/pc/uart.s Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/uart.s Sat Jan 29 00:00:00 2022 @@ -0,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 diff -Nru /sys/src/nboot/pc/x16.h /sys/src/nboot/pc/x16.h --- /sys/src/nboot/pc/x16.h Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/pc/x16.h Sat Jan 29 00:00:00 2022 @@ -0,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< r */ \ + BYTE $i; +#define SHLBI(i, r) OPrr(0xC0, 0x04, r); /* r< 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 diff -Nru /sys/src/nboot/zynq/boothead.c /sys/src/nboot/zynq/boothead.c --- /sys/src/nboot/zynq/boothead.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/zynq/boothead.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,71 @@ +#include +#include + +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); +} diff -Nru /sys/src/nboot/zynq/dat.h /sys/src/nboot/zynq/dat.h --- /sys/src/nboot/zynq/dat.h Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/zynq/dat.h Sat Jan 29 00:00:00 2022 @@ -0,0 +1,11 @@ +enum { + DHCPTIMEOUT = 2000, + ARPTIMEOUT = 1000, + TFTPTIMEOUT = 10000, + + TZERO = 0x80000, + CONFSIZE = 65536, + CONF = TZERO - CONFSIZE, +}; + +#define nelem(x) (sizeof(x)/sizeof(*(x))) diff -Nru /sys/src/nboot/zynq/ddr.s /sys/src/nboot/zynq/ddr.s --- /sys/src/nboot/zynq/ddr.s Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/zynq/ddr.s Sat Jan 29 00:00:00 2022 @@ -0,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 diff -Nru /sys/src/nboot/zynq/fns.h /sys/src/nboot/zynq/fns.h --- /sys/src/nboot/zynq/fns.h Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/zynq/fns.h Sat Jan 29 00:00:00 2022 @@ -0,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); diff -Nru /sys/src/nboot/zynq/fsbl.s /sys/src/nboot/zynq/fsbl.s --- /sys/src/nboot/zynq/fsbl.s Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/zynq/fsbl.s Sat Jan 29 00:00:00 2022 @@ -0,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 diff -Nru /sys/src/nboot/zynq/jtagload.c /sys/src/nboot/zynq/jtagload.c --- /sys/src/nboot/zynq/jtagload.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/zynq/jtagload.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,647 @@ +#include +#include + +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< 0){ + b[0] = w >> s; + c |= BITS; + io(c, len, b); + if((c & TDO) != 0){ + w &= ~((uvlong)((1<> 8-len) << s; + } + s += len; + } + return w & (1ULL<= 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; idbgap, 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); +} diff -Nru /sys/src/nboot/zynq/main.c /sys/src/nboot/zynq/main.c --- /sys/src/nboot/zynq/main.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/zynq/main.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,203 @@ +#include +#include +#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"); +} diff -Nru /sys/src/nboot/zynq/mem.h /sys/src/nboot/zynq/mem.h --- /sys/src/nboot/zynq/mem.h Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/zynq/mem.h Sat Jan 29 00:00:00 2022 @@ -0,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 diff -Nru /sys/src/nboot/zynq/mkfile /sys/src/nboot/zynq/mkfile --- /sys/src/nboot/zynq/mkfile Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/zynq/mkfile Sat Jan 29 00:00:00 2022 @@ -0,0 +1,38 @@ +objtype=arm +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 diff -Nru /sys/src/nboot/zynq/mkfile.port /sys/src/nboot/zynq/mkfile.port --- /sys/src/nboot/zynq/mkfile.port Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/zynq/mkfile.port Sat Jan 29 00:00:00 2022 @@ -0,0 +1,14 @@ + +#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<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; +} diff -Nru /sys/src/nboot/zynq/net.c /sys/src/nboot/zynq/net.c --- /sys/src/nboot/zynq/net.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/zynq/net.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,577 @@ +#include +#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; +} diff -Nru /sys/src/nboot/zynq/qspi.c /sys/src/nboot/zynq/qspi.c --- /sys/src/nboot/zynq/qspi.c Thu Jan 1 00:00:00 1970 +++ /sys/src/nboot/zynq/qspi.c Sat Jan 29 00:00:00 2022 @@ -0,0 +1,45 @@ +#include +#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)); + +}