From: Peter H. Froehlich Date: Tue, 20 Oct 2015 15:23:33 +0000 (-0400) Subject: A second serial port for debugging output. X-Git-Url: https://hydra-www.ietfng.org/gitweb/?a=commitdiff_plain;h=378d9a5d5724d7d2effc3d270b27cbdc36f0aaba;p=xv6-public A second serial port for debugging output. --- diff --git a/Makefile b/Makefile index 0a1e31a..38f6692 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ OBJS = \ bio.o\ console.o\ + debug.o\ exec.o\ file.o\ fs.o\ @@ -213,7 +214,7 @@ endif QEMUOPTS = -drive file=fs.img,index=1,media=disk,format=raw -drive file=xv6.img,index=0,media=disk,format=raw -smp $(CPUS) -m 512 $(QEMUEXTRA) qemu: fs.img xv6.img - $(QEMU) -serial mon:stdio $(QEMUOPTS) + $(QEMU) -serial mon:stdio -serial file:DEBUGLOG $(QEMUOPTS) qemu-memfs: xv6memfs.img $(QEMU) -drive file=xv6memfs.img,index=0,media=disk,format=raw -smp $(CPUS) -m 256 diff --git a/debug.c b/debug.c new file mode 100644 index 0000000..d62c5f1 --- /dev/null +++ b/debug.c @@ -0,0 +1,151 @@ +// A second Intel 8250 serial port (UART) for early-boot debug output. +// Requires that QEMU was started with a second serial port, otherwise +// debug output is suppressed. +// +// We want to allow debug output as early as possible and from anywhere, +// including the spinlock code. This requires a custom lock to make sure +// output is complete and consistent. Our custom lock cannot possibly be +// acquired from an interrupt context so it doesn't disable interrupts. + +#include "types.h" +#include "defs.h" +#include "x86.h" +#include "uart.h" + +static int uart; // do we have a second uart? +static volatile uint locked; // custom lock + +static void +lock(void) +{ + while(xchg(&locked, 1) != 0) + ; +} + +static void +unlock(void) +{ + xchg(&locked, 0); +} + +static int +cantransmit(void) +{ + return inb(COM2+UART_LINE_STATUS) & UART_TRANSMIT_READY; +} + +static void +debugputc(int c) +{ + int i; + + if(!uart) + return; + for(i = 0; i < 128 && !cantransmit(); i++) + microdelay(10); + outb(COM2+UART_TRANSMIT_BUFFER, c); +} + +void +debuginit(void) +{ + // Turn off the FIFO + outb(COM2+UART_FIFO_CONTROL, 0); + + // 9600 baud, 8 data bits, 1 stop bit, parity off. + outb(COM2+UART_LINE_CONTROL, UART_DIVISOR_LATCH); + outb(COM2+UART_DIVISOR_LOW, 115200/9600); + outb(COM2+UART_DIVISOR_HIGH, 0); + outb(COM2+UART_LINE_CONTROL, 0x03); // 8 data bits. + outb(COM2+UART_MODEM_CONTROL, 0); // No RTS/DTR handshake. + outb(COM2+UART_INTERRUPT_ENABLE, 0); // Disable interrupts. + + // If status is 0xFF, no serial port. + if(inb(COM2+UART_LINE_STATUS) == 0xFF) + return; + uart = 1; + + // Acknowledge pre-existing interrupt conditions, if any. + // We don't use any of the interrupt stuff ourselves. + inb(COM2+UART_INTERRUPT_ID); + inb(COM2+UART_RECEIVE_BUFFER); +} + +// It's certainly sad that we have to replicate the printf code *again* for +// this module. Alas there doesn't seem to be a nice way to modularize. + +static void +printint(int xx, int base, int sign) +{ + static char digits[] = "0123456789abcdef"; + char buf[16]; + int i; + uint x; + + if(sign && (sign = (xx < 0))) + x = -xx; + else + x = xx; + + i = 0; + do{ + buf[i++] = digits[x % base]; + }while((x /= base) != 0); + + if(sign) + buf[i++] = '-'; + + while(--i >= 0) + debugputc(buf[i]); +} + +void +debugf(char *fmt, ...) +{ + int i, c; + uint *argp; + char *s; + + if(fmt == 0){ + debugf("debugf: null fmt\n"); // no panic(), no console.c dependency + return; + } + + lock(); + + argp = (uint*)(void*)(&fmt + 1); + for(i = 0; (c = fmt[i] & 0xff) != 0; i++){ + if(c != '%'){ + debugputc(c); + continue; + } + c = fmt[++i] & 0xff; + if(c == 0) + break; + switch(c){ + case 'd': + printint(*argp++, 10, 1); + break; + case 'x': + case 'p': + printint(*argp++, 16, 0); + break; + case 's': + if((s = (char*)*argp++) == 0) + s = "(null)"; + for(; *s; s++) + debugputc(*s); + break; + case '%': + debugputc('%'); + break; + default: + // Print unknown % sequence to draw attention. + debugputc('%'); + debugputc(c); + break; + } + } + + unlock(); +} diff --git a/defs.h b/defs.h index 3758232..8c3568c 100644 --- a/defs.h +++ b/defs.h @@ -22,6 +22,10 @@ void cprintf(char*, ...); void consoleintr(int(*)(void)); void panic(char*) __attribute__((noreturn)); +// debug.c +void debuginit(void); +void debugf(char*, ...); + // exec.c int exec(char*, char**); diff --git a/main.c b/main.c index 88a3867..d25e719 100644 --- a/main.c +++ b/main.c @@ -16,6 +16,7 @@ extern char end[]; // first address after kernel loaded from ELF file int main(void) { + debuginit(); // enable debug output first kinit1(end, P2V(4*1024*1024)); // phys page allocator kvmalloc(); // kernel page table mpinit(); // collect info about this machine