summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorRobert Morris <[email protected]>2020-07-22 10:31:46 -0400
committerFrans Kaashoek <[email protected]>2020-08-10 11:19:10 -0400
commit0f50e9527c68168c8114a38b211a8744e3bd2473 (patch)
treedea9a9d3ce5d8496e455137bca2c9d5ef988f948 /kernel
parent27057bc9b467db64a3de600f27d6fa3239a04c88 (diff)
downloadxv6-labs-0f50e9527c68168c8114a38b211a8744e3bd2473.tar.gz
xv6-labs-0f50e9527c68168c8114a38b211a8744e3bd2473.tar.bz2
xv6-labs-0f50e9527c68168c8114a38b211a8744e3bd2473.zip
fix printf() in interrupts
Diffstat (limited to 'kernel')
-rw-r--r--kernel/console.c6
-rw-r--r--kernel/defs.h3
-rw-r--r--kernel/uart.c45
3 files changed, 29 insertions, 25 deletions
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.