add serial console 8250 UART

This commit is contained in:
Hojun-Cho 2024-12-05 22:08:53 +09:00
parent dbb2d58280
commit 11097add40
9 changed files with 295 additions and 25 deletions

View File

@ -5,7 +5,7 @@ PROG = boot
SRCS = srt0.S gdt.S boot.c SRCS = srt0.S gdt.S boot.c
OBJS = srt0.o gdt.o boot.o 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) OBJS += $(ESRCS:.c=.o)
include $(SDIR)/Makefile.inc include $(SDIR)/Makefile.inc

View File

@ -1,4 +1,5 @@
#include <u.h> #include <u.h>
#include "dat.h"
#include "fn.h" #include "fn.h"
#define I8042_DPORT 0x60 #define I8042_DPORT 0x60

View File

@ -2,8 +2,11 @@
#include "dat.h" #include "dat.h"
#include "fn.h" #include "fn.h"
static void coninit(void);
static void machdep(void);
void (*probe1[])(void) = { void (*probe1[])(void) = {
a20up, a20up, coninit,
}; };
void (*probe2[])(void) = { void (*probe2[])(void) = {
}; };
@ -13,13 +16,41 @@ BootProbe probes[] = {
{"disk", probe2, elem(probe2) }, {"disk", probe2, elem(probe2) },
}; };
ConDev condev = { ConDev contab[CON_END] = {
.getc = pcgetc, {
.putc = pcputc, .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 // https://wiki.osdev.org/BIOS
void static void
machdep(void) machdep(void)
{ {
for(int i = 0; i < elem(probes); ++i){ for(int i = 0; i < elem(probes); ++i){
@ -61,8 +92,8 @@ done:
void void
boot(int bootdev) boot(int bootdev)
{ {
machdep();
print("\n\n===> Hello world <===\n\tBooted on disk 0x%x\n", bootdev); print("\n\n===> Hello world <===\n\tBooted on disk 0x%x\n", bootdev);
machdep();
for(;;){ for(;;){
char buf[8192]; char buf[8192];

View File

@ -3,6 +3,12 @@
// 0x64 Read Status Register // 0x64 Read Status Register
// 0x64 Write Command Register // 0x64 Write Command Register
enum{
CON_PC,
CON_SRI,
CON_END,
};
struct BIOSreg{ struct BIOSreg{
u32 ax; u32 ax;
u32 cx; u32 cx;
@ -15,18 +21,21 @@ struct BIOSreg{
u32 es; u32 es;
}__attribute__((packed)); }__attribute__((packed));
typedef struct{ typedef struct{
char *name; char *name;
void (**probes)(void); void (**probes)(void);
int cnt; uint cnt;
}BootProbe; }BootProbe;
typedef struct{ typedef struct ConDev ConDev;
struct ConDev{
int (*probe)(ConDev*);
void (*init)(ConDev *);
int (*getc)(int); int (*getc)(int);
void (*putc)(int, int); void (*putc)(int, int);
int dev; uint dev;
}ConDev; uchar pri; // the higher the better
};
// gdt.S // gdt.S
extern volatile struct BIOSreg BIOSreg; extern volatile struct BIOSreg BIOSreg;
@ -35,4 +44,5 @@ extern volatile struct BIOSreg BIOSreg;
extern void (*probe1[])(void); extern void (*probe1[])(void);
extern void (*probe2[])(void); extern void (*probe2[])(void);
extern BootProbe probes[]; extern BootProbe probes[];
extern ConDev condev; extern ConDev contab[CON_END];
extern ConDev *con;

View File

@ -1,7 +1,12 @@
// console.c // console.c
void cominit(ConDev *d);
void pcinit(ConDev *d);
int pcprobe(ConDev *d);
int pcgetc(int dev); int pcgetc(int dev);
void pcputc(int dev, int c); void pcputc(int dev, int c);
int comprobe(ConDev *d);
int comgetc(int dev);
void computc(int dev, int c);
// print.c // print.c
void putchar(int c); void putchar(int c);
@ -14,6 +19,26 @@ void a20up(void);
// long.c // long.c
long getsecs(void); 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 static __inline void
outb(int port, u8 data) outb(int port, u8 data)
{ {

View File

@ -1,7 +1,23 @@
// PC console
#include <u.h> #include <u.h>
#include "dat.h"
#include "fn.h" #include "fn.h"
// https://stanislavs.org/helppc/int_16.html // 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 void
pcputc(int dev, int c) pcputc(int dev, int c)
@ -23,4 +39,4 @@ pcgetc(int dev)
__asm volatile("int $0x36" : "=a" (rv) : __asm volatile("int $0x36" : "=a" (rv) :
"0" (0x000) : "%ecx", "%edx", "cc" ); "0" (0x000) : "%ecx", "%edx", "cc" );
return rv&0xff; return rv&0xff;
} }

View File

@ -15,7 +15,7 @@ print(const char *fmt, ...)
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
doprint(putchar, fmt, args); doprint(putchar, fmt, args);
va_end(args); va_end(args);
} }
@ -31,7 +31,7 @@ doprint(void (*put)(int), const char *s, va_list ap)
++s; ++s;
switch(*s){ switch(*s){
case 'd': case 'd':
putint(put, va_arg(ap,int), "0123456789", 10); putint(put, va_arg(ap,int), "0123456789", 10);
break; break;
case 'x': case 'x':
putint(put, va_arg(ap,int), "0123456789abcdef", 16); putint(put, va_arg(ap,int), "0123456789abcdef", 16);
@ -45,7 +45,7 @@ doprint(void (*put)(int), const char *s, va_list ap)
break; break;
default: default:
return; return;
} }
++s; ++s;
} }
} }
@ -98,16 +98,16 @@ static void
conputc(int c) conputc(int c)
{ {
if(c){ if(c){
condev.putc(condev.dev, c); con->putc(con->dev, c);
if(c == '\n') if(c == '\n')
condev.putc(condev.dev, '\r'); con->putc(con->dev, '\r');
} }
} }
static int static int
congetc(void) congetc(void)
{ {
return condev.getc(condev.dev); return con->getc(con->dev);
} }
static void static void

185
boot/sricon.c Normal file
View File

@ -0,0 +1,185 @@
// Serial console
#include <u.h>
#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);
}

View File

@ -3,8 +3,10 @@
#include "fn.h" #include "fn.h"
// https://stanislavs.org/helppc/int_1a.html // https://stanislavs.org/helppc/int_1a.html
#define INT_TIME 2<<8 enum{
#define INT_DATE 4<<8 GET_TIME = 2<<8,
GET_DATE = 4<<8,
};
static int static int
bcd2int(u8 c) bcd2int(u8 c)
@ -59,8 +61,8 @@ getsecs(void)
u8 t[4], d[4]; u8 t[4], d[4];
long s; long s;
int1a(INT_TIME, t); int1a(GET_TIME, t);
int1a(INT_DATE, d); int1a(GET_DATE, d);
s = (date2day(d[0]*100+d[1], d[2], d[3]) * 24 + t[0]) * 60 s = (date2day(d[0]*100+d[1], d[2], d[3]) * 24 + t[0]) * 60
+ (t[1] * 60) + t[2]; + (t[1] * 60) + t[2];
return s; return s;