diff --git a/boot/Makefile b/boot/Makefile index ef89990..77041f0 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -5,7 +5,7 @@ PROG = boot SRCS = srt0.S gdt.S boot.c OBJS = srt0.o gdt.o boot.o -ESRCS = console.c print.c a20.c time.c +ESRCS = pccon.c sricon.c print.c a20.c time.c OBJS += $(ESRCS:.c=.o) include $(SDIR)/Makefile.inc diff --git a/boot/a20.c b/boot/a20.c index 3fa537c..72ebb18 100644 --- a/boot/a20.c +++ b/boot/a20.c @@ -1,4 +1,5 @@ #include +#include "dat.h" #include "fn.h" #define I8042_DPORT 0x60 diff --git a/boot/boot.c b/boot/boot.c index 4a29add..1ea7e52 100644 --- a/boot/boot.c +++ b/boot/boot.c @@ -2,8 +2,11 @@ #include "dat.h" #include "fn.h" +static void coninit(void); +static void machdep(void); + void (*probe1[])(void) = { - a20up, + a20up, coninit, }; void (*probe2[])(void) = { }; @@ -13,13 +16,41 @@ BootProbe probes[] = { {"disk", probe2, elem(probe2) }, }; -ConDev condev = { - .getc = pcgetc, - .putc = pcputc, +ConDev contab[CON_END] = { + { + .probe = pcprobe, + .init = pcinit, + .getc = pcgetc, + .putc = pcputc + }, + { + // serial console + .probe = comprobe, + .getc = comgetc, + .putc = computc, + .init = cominit, + }, }; +ConDev *con = &contab[0]; + +static void +coninit(void) +{ + ConDev *p = con; + + for(int i = 0; i < elem(contab); ++i){ + ConDev *t = &contab[i]; + if(t->probe(t) != 0 && t->pri > p->pri) + p = t; + } + if(p){ + p->init(p); + con = p; + } +} // https://wiki.osdev.org/BIOS -void +static void machdep(void) { for(int i = 0; i < elem(probes); ++i){ @@ -61,8 +92,8 @@ done: void boot(int bootdev) { - machdep(); print("\n\n===> Hello world <===\n\tBooted on disk 0x%x\n", bootdev); + machdep(); for(;;){ char buf[8192]; diff --git a/boot/dat.h b/boot/dat.h index 085d5ac..1166b5a 100644 --- a/boot/dat.h +++ b/boot/dat.h @@ -3,6 +3,12 @@ // 0x64 Read Status Register // 0x64 Write Command Register +enum{ + CON_PC, + CON_SRI, + CON_END, +}; + struct BIOSreg{ u32 ax; u32 cx; @@ -15,18 +21,21 @@ struct BIOSreg{ u32 es; }__attribute__((packed)); - typedef struct{ char *name; void (**probes)(void); - int cnt; + uint cnt; }BootProbe; -typedef struct{ +typedef struct ConDev ConDev; +struct ConDev{ + int (*probe)(ConDev*); + void (*init)(ConDev *); int (*getc)(int); void (*putc)(int, int); - int dev; -}ConDev; + uint dev; + uchar pri; // the higher the better +}; // gdt.S extern volatile struct BIOSreg BIOSreg; @@ -35,4 +44,5 @@ extern volatile struct BIOSreg BIOSreg; extern void (*probe1[])(void); extern void (*probe2[])(void); extern BootProbe probes[]; -extern ConDev condev; \ No newline at end of file +extern ConDev contab[CON_END]; +extern ConDev *con; diff --git a/boot/fn.h b/boot/fn.h index e997708..4d1bb47 100644 --- a/boot/fn.h +++ b/boot/fn.h @@ -1,7 +1,12 @@ - // console.c +void cominit(ConDev *d); +void pcinit(ConDev *d); +int pcprobe(ConDev *d); int pcgetc(int dev); void pcputc(int dev, int c); +int comprobe(ConDev *d); +int comgetc(int dev); +void computc(int dev, int c); // print.c void putchar(int c); @@ -14,6 +19,26 @@ void a20up(void); // long.c long getsecs(void); +static __inline int +major(int x) +{ + return (x >> 8) & 0xff; +} + +static __inline int +minor(int x) +{ + return (x & 0xff) | ((x & 0xffff0000) >> 8); +} + +static __inline int +makedev(int x, int y) +{ + return (((x & 0xff) << 8) | + (y & 0xff) | + ((y & 0xffff00)<<8)); +} + static __inline void outb(int port, u8 data) { diff --git a/boot/console.c b/boot/pccon.c similarity index 72% rename from boot/console.c rename to boot/pccon.c index 0f46609..5d41e48 100644 --- a/boot/console.c +++ b/boot/pccon.c @@ -1,7 +1,23 @@ +// PC console #include +#include "dat.h" #include "fn.h" // https://stanislavs.org/helppc/int_16.html +int +pcprobe(ConDev *d) +{ + d->pri = 2; + d->dev = makedev(12, 0); + print("PC:%d\n", minor(d->dev)); + return 1; +} + +void +pcinit(ConDev *d) +{ + USED(d); +} void pcputc(int dev, int c) @@ -23,4 +39,4 @@ pcgetc(int dev) __asm volatile("int $0x36" : "=a" (rv) : "0" (0x000) : "%ecx", "%edx", "cc" ); return rv&0xff; -} \ No newline at end of file +} diff --git a/boot/print.c b/boot/print.c index 857ff56..647e82d 100644 --- a/boot/print.c +++ b/boot/print.c @@ -15,7 +15,7 @@ print(const char *fmt, ...) { va_list args; - va_start(args, fmt); + va_start(args, fmt); doprint(putchar, fmt, args); va_end(args); } @@ -31,7 +31,7 @@ doprint(void (*put)(int), const char *s, va_list ap) ++s; switch(*s){ case 'd': - putint(put, va_arg(ap,int), "0123456789", 10); + putint(put, va_arg(ap,int), "0123456789", 10); break; case 'x': putint(put, va_arg(ap,int), "0123456789abcdef", 16); @@ -45,7 +45,7 @@ doprint(void (*put)(int), const char *s, va_list ap) break; default: return; - } + } ++s; } } @@ -98,16 +98,16 @@ static void conputc(int c) { if(c){ - condev.putc(condev.dev, c); + con->putc(con->dev, c); if(c == '\n') - condev.putc(condev.dev, '\r'); + con->putc(con->dev, '\r'); } } static int congetc(void) { - return condev.getc(condev.dev); + return con->getc(con->dev); } static void diff --git a/boot/sricon.c b/boot/sricon.c new file mode 100644 index 0000000..fe37ce8 --- /dev/null +++ b/boot/sricon.c @@ -0,0 +1,185 @@ +// Serial console +#include +#include "dat.h" +#include "fn.h" + +/* + * 8250 UART and compatibles. + */ +enum { + Uart0 = 0x3F8, /* COM1 */ + Uart0IRQ = 4, + Uart1 = 0x2F8, /* COM2 */ + Uart1IRQ = 3, + UartFREQ = 1843200, /* 1.8432 MHz */ +}; + +/* I/O ports */ +enum { + Rbr = 0, /* Receiver Buffer (RO) */ + Thr = 0, /* Transmitter Holding (WO) */ + Ier = 1, /* Interrupt Enable */ + Iir = 2, /* Interrupt Identification (RO) */ + Fcr = 2, /* FIFO Control (WO) */ + Lcr = 3, /* Line Control */ + Mcr = 4, /* Modem Control */ + Lsr = 5, /* Line Status */ + Msr = 6, /* Modem Status */ + Scr = 7, /* Scratch Pad */ + Dll = 0, /* Divisor Latch Low */ + Dlh = 1, /* Divisor Latch High */ +}; + +/* Interrupt Enable Registe */ +enum { /* Ier */ + Erda = 0x01, /* Enable Received Data Available */ + Ethre = 0x02, /* Enable Thr Empty */ + Erls = 0x04, /* Enable Receiver Line Status */ + Ems = 0x08, /* Enable Modem Status */ +}; + +/* Interrupt Identification Register */ +enum { /* Iir */ + Ims = 0x00, /* Ms interrupt */ + Ip = 0x01, /* Interrupt Pending (not) */ + Ithre = 0x02, /* Thr Empty */ + Irda = 0x04, /* Received Data Available */ + Irls = 0x06, /* Receiver Line Status */ + Ictoi = 0x0C, /* Character Time-out Indication */ + IirMASK = 0x3F, + Ifena = 0xC0, /* FIFOs enabled */ +}; + +/* FIFO Control Registe */ +enum { /* Fcr */ + FIFOena = 0x01, /* FIFO enable */ + FIFOrclr= 0x02, /* clear Rx FIFO */ + FIFOtclr= 0x04, /* clear Tx FIFO */ + FIFO1 = 0x00, /* Rx FIFO trigger level 1 byte */ + FIFO4 = 0x40, /* 4 bytes */ + FIFO8 = 0x80, /* 8 bytes */ + FIFO14 = 0xC0, /* 14 bytes */ +}; + +/* Line Control Registe */ +enum { /* Lcr */ + Wls5 = 0x00, /* Word Length Select 5 bits/byte */ + Wls6 = 0x01, /* 6 bits/byte */ + Wls7 = 0x02, /* 7 bits/byte */ + Wls8 = 0x03, /* 8 bits/byte */ + WlsMASK = 0x03, + Stb = 0x04, /* 2 stop bits */ + Pen = 0x08, /* Parity Enable */ + Eps = 0x10, /* Even Parity Select */ + Stp = 0x20, /* Stick Parity */ + Brk = 0x40, /* Break */ + Dlab = 0x80, /* Divisor Latch Access Bit */ +}; + +/* Modem Control Register */ +enum { /* Mcr */ + Dtr = 0x01, /* Data Terminal Ready */ + Rts = 0x02, /* Ready To Send */ + Out1 = 0x04, /* no longer in use */ + Ie = 0x08, /* IRQ Enable */ + Dm = 0x10, /* Diagnostic Mode loopback */ +}; + +/* Line Status Register */ +enum { /* Lsr */ + Dr = 0x01, /* Data Ready */ + Oe = 0x02, /* Overrun Error */ + Pe = 0x04, /* Parity Error */ + Fe = 0x08, /* Framing Error */ + Bi = 0x10, /* Break Interrupt */ + Thre = 0x20, /* Thr Empty */ + Temt = 0x40, /* Tramsmitter Empty */ + FIFOerr = 0x80, /* error in receiver FIFO */ +}; + +/* Modem Status Register */ +enum { /* Msr */ + Dcts = 0x01, /* Delta Cts */ + Ddsr = 0x02, /* Delta Dsr */ + Teri = 0x04, /* Trailing Edge of Ri */ + Ddcd = 0x08, /* Delta Dcd */ + Cts = 0x10, /* Clear To Send */ + Dsr = 0x20, /* Data Set Ready */ + Ri = 0x40, /* Ring Indicator */ + Dcd = 0x80, /* Data Set Ready */ +}; + +static int setbaud(int dev, int baud); + +// probe serial console +// https://stanislavs.org/helppc/int_11.html +// https://wiki.osdev.org/Serial_Ports +int +comprobe(ConDev *d) +{ + register int n; + + __asm volatile("int $0x31" : "=a" (n):: "%ecx", "%edx", "cc"); + n >>= 9; + n &= 0b111; + if(n == 0) + return 0; + for(int i = 0; i < n; ++i) + print("Found com %d\n", i); + d->pri = 0; + d->dev = makedev(8, 0); + return n; +} + +// init serial consone +void +cominit(ConDev *d) +{ + long t = getsecs() + 1; + + outb(Uart0+Ier, 0); + setbaud(d->dev, 9600); + outb(Uart0+Mcr, Dtr|Rts); + outb(Uart0+Fcr, FIFOena|FIFOrclr|FIFOtclr|FIFO1); + inb(Uart0+Iir); // check fifo + + // wait + for(ulong i = 1; ((i % 1000)!=0) && getsecs() < t; ++i) + ; + // drain input buffer + while(inb(Uart0+Lsr) & Dr) + inb(Uart0+Rbr); +} + +static int +setbaud(int dev, int baud) +{ + int port = Uart0; + ulong div; + + if(baud <= 0) + return -1; + /* Divisor = 115200/baud */ + div = (UartFREQ+8*baud-1)/(16*baud); + outb(port+Lcr, Dlab); + outb(port+Dlh, div>>8); + outb(port+Dll, div); + outb(port+Lcr, Wls8); + return 0; +} + +int +comgetc(int dev) +{ + while((inb(Uart0+Lsr) & Dr) == 0) + ; + return inb(Uart0+Rbr) & 0xff; +} + +void +computc(int dev, int c) +{ + while((inb(Uart0+Lsr) & Thre) == 0) + ; + outb(Uart0+Thr, c); +} \ No newline at end of file diff --git a/boot/time.c b/boot/time.c index 377f8fb..8e3af65 100644 --- a/boot/time.c +++ b/boot/time.c @@ -3,8 +3,10 @@ #include "fn.h" // https://stanislavs.org/helppc/int_1a.html -#define INT_TIME 2<<8 -#define INT_DATE 4<<8 +enum{ + GET_TIME = 2<<8, + GET_DATE = 4<<8, +}; static int bcd2int(u8 c) @@ -59,8 +61,8 @@ getsecs(void) u8 t[4], d[4]; long s; - int1a(INT_TIME, t); - int1a(INT_DATE, d); + int1a(GET_TIME, t); + int1a(GET_DATE, d); s = (date2day(d[0]*100+d[1], d[2], d[3]) * 24 + t[0]) * 60 + (t[1] * 60) + t[2]; return s;