diff --git a/kernel/console.c b/kernel/console.c index a97ef30..9a18cd9 100644 --- a/kernel/console.c +++ b/kernel/console.c @@ -42,9 +42,9 @@ consputc(int c) if(c == BACKSPACE){ // if the user typed backspace, overwrite with a space. - uartputc('\b', 0); uartputc(' ', 0); uartputc('\b', 0); + uartputc_sync('\b'); uartputc_sync(' '); uartputc_sync('\b'); } else { - uartputc(c, 0); + uartputc_sync(c); } } @@ -72,7 +72,7 @@ consolewrite(int user_src, uint64 src, int n) char c; if(either_copyin(&c, user_src, src+i, 1) == -1) break; - uartputc(c, 1); + uartputc(c); } release(&cons.lock); diff --git a/kernel/defs.h b/kernel/defs.h index 1b164a4..4eedd89 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -149,7 +149,8 @@ void usertrapret(void); // uart.c void uartinit(void); void uartintr(void); -void uartputc(int, int); +void uartputc(int); +void uartputc_sync(int); int uartgetc(void); // vm.c diff --git a/kernel/uart.c b/kernel/uart.c index 4d70b42..32cb575 100644 --- a/kernel/uart.c +++ b/kernel/uart.c @@ -69,33 +69,19 @@ uartinit(void) // add a character to the output buffer and tell the // UART to start sending if it isn't already. -// -// usually called from the top-half -- by a process -// calling write(). can also be called from a uart -// interrupt to echo a received character, or by printf -// or panic from anywhere in the kernel. -// -// the block argument controls what happens if the -// buffer is full. for write(), block is 1, and the -// process waits. for kernel printf's and echoed -// characters, block is 0, and the character is -// discarded; this is necessary since sleep() is -// not possible in interrupts. +// blocks if the output buffer is full. +// because it may block, it can't be called +// from interrupts; it's only suitable for use +// by write(). void -uartputc(int c, int block) +uartputc(int c) { acquire(&uart_tx_lock); while(1){ if(((uart_tx_w + 1) % UART_TX_BUF_SIZE) == uart_tx_r){ // buffer is full. - if(block){ - // wait for uartstart() to open up space in the buffer. - sleep(&uart_tx_r, &uart_tx_lock); - } else { - // caller does not want us to wait. - release(&uart_tx_lock); - return; - } + // wait for uartstart() to open up space in the buffer. + sleep(&uart_tx_r, &uart_tx_lock); } else { uart_tx_buf[uart_tx_w] = c; uart_tx_w = (uart_tx_w + 1) % UART_TX_BUF_SIZE; @@ -106,6 +92,23 @@ uartputc(int c, int block) } } +// alternate version of uartputc() that doesn't +// use interrupts, for use by kernel printf() and +// to echo characters. it spins waiting for the uart's +// output register to be empty. +void +uartputc_sync(int c) +{ + push_off(); + + // wait for Transmit Holding Empty to be set in LSR. + while((ReadReg(LSR) & (1 << 5)) == 0) + ; + WriteReg(THR, c); + + pop_off(); +} + // if the UART is idle, and a character is waiting // in the transmit buffer, send it. // caller must hold uart_tx_lock.