add serial console 8250 UART
This commit is contained in:
parent
dbb2d58280
commit
11097add40
@ -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
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#include <u.h>
|
||||
#include "dat.h"
|
||||
#include "fn.h"
|
||||
|
||||
#define I8042_DPORT 0x60
|
||||
|
||||
43
boot/boot.c
43
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];
|
||||
|
||||
22
boot/dat.h
22
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;
|
||||
extern ConDev contab[CON_END];
|
||||
extern ConDev *con;
|
||||
|
||||
27
boot/fn.h
27
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)
|
||||
{
|
||||
|
||||
@ -1,7 +1,23 @@
|
||||
// PC console
|
||||
#include <u.h>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
12
boot/print.c
12
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
|
||||
|
||||
185
boot/sricon.c
Normal file
185
boot/sricon.c
Normal 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);
|
||||
}
|
||||
10
boot/time.c
10
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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user