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
|
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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
43
boot/boot.c
43
boot/boot.c
@ -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];
|
||||||
|
|||||||
22
boot/dat.h
22
boot/dat.h
@ -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;
|
||||||
|
|||||||
27
boot/fn.h
27
boot/fn.h
@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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)
|
||||||
@ -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
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"
|
#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;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user