fix printf() in interrupts

This commit is contained in:
Robert Morris 2020-07-22 10:31:46 -04:00
parent 823864099d
commit db0f092ae4
3 changed files with 29 additions and 25 deletions

View file

@ -42,9 +42,9 @@ consputc(int c)
if(c == BACKSPACE){ if(c == BACKSPACE){
// if the user typed backspace, overwrite with a space. // 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 { } else {
uartputc(c, 0); uartputc_sync(c);
} }
} }
@ -72,7 +72,7 @@ consolewrite(int user_src, uint64 src, int n)
char c; char c;
if(either_copyin(&c, user_src, src+i, 1) == -1) if(either_copyin(&c, user_src, src+i, 1) == -1)
break; break;
uartputc(c, 1); uartputc(c);
} }
release(&cons.lock); release(&cons.lock);

View file

@ -149,7 +149,8 @@ void usertrapret(void);
// uart.c // uart.c
void uartinit(void); void uartinit(void);
void uartintr(void); void uartintr(void);
void uartputc(int, int); void uartputc(int);
void uartputc_sync(int);
int uartgetc(void); int uartgetc(void);
// vm.c // vm.c

View file

@ -69,33 +69,19 @@ uartinit(void)
// add a character to the output buffer and tell the // add a character to the output buffer and tell the
// UART to start sending if it isn't already. // UART to start sending if it isn't already.
// // blocks if the output buffer is full.
// usually called from the top-half -- by a process // because it may block, it can't be called
// calling write(). can also be called from a uart // from interrupts; it's only suitable for use
// interrupt to echo a received character, or by printf // by write().
// 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.
void void
uartputc(int c, int block) uartputc(int c)
{ {
acquire(&uart_tx_lock); acquire(&uart_tx_lock);
while(1){ while(1){
if(((uart_tx_w + 1) % UART_TX_BUF_SIZE) == uart_tx_r){ if(((uart_tx_w + 1) % UART_TX_BUF_SIZE) == uart_tx_r){
// buffer is full. // buffer is full.
if(block){ // wait for uartstart() to open up space in the buffer.
// wait for uartstart() to open up space in the buffer. sleep(&uart_tx_r, &uart_tx_lock);
sleep(&uart_tx_r, &uart_tx_lock);
} else {
// caller does not want us to wait.
release(&uart_tx_lock);
return;
}
} else { } else {
uart_tx_buf[uart_tx_w] = c; uart_tx_buf[uart_tx_w] = c;
uart_tx_w = (uart_tx_w + 1) % UART_TX_BUF_SIZE; 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 // if the UART is idle, and a character is waiting
// in the transmit buffer, send it. // in the transmit buffer, send it.
// caller must hold uart_tx_lock. // caller must hold uart_tx_lock.