JOS1-1
调用顺序:
1.
init.c / void i386_init(void)
2.
console.c / void cons_init()
3.
cga_init();
kbd_init();
serial_init();
4.
/* * 获取显存第一个位置的指针 * 获取当前光标位置 */ static void cga_init(void) { volatile uint16_t *cp; uint16_t was; unsigned pos; cp = (uint16_t*) (KERNBASE + CGA_BUF); was = *cp; /*保存显存前2个字节*/ *cp = (uint16_t) 0xA55A; /*重新写显存的第一个位置 背景为高亮绿色 前景为洋红 */ if (*cp != 0xA55A) { cp = (uint16_t*) (KERNBASE + MONO_BUF); addr_6845 = MONO_BASE; } else { *cp = was; /*显存第一个位置恢复原样*/ addr_6845 = CGA_BASE; } /* Extract cursor location */ /*获取光标位置*/ outb(addr_6845, 14); /*0x3d4 - 0eh*/ pos = inb(addr_6845 + 1) << 8; /*高八位*/ outb(addr_6845, 15); /*0x3d4 - 0fh*/ pos |= inb(addr_6845 + 1); /*低八位*/ crt_buf = (uint16_t*) cp; crt_pos = pos; } /*串口I/O初始化*/ static void serial_init(void) { // Turn off the FIFO outb(COM1+COM_FCR, 0); // Set speed; requires DLAB latch outb(COM1+COM_LCR, COM_LCR_DLAB); outb(COM1+COM_DLL, (uint8_t) (115200 / 9600)); outb(COM1+COM_DLM, 0); // 8 data bits, 1 stop bit, parity off; turn off DLAB latch outb(COM1+COM_LCR, COM_LCR_WLEN8 & ~COM_LCR_DLAB); // No modem controls outb(COM1+COM_MCR, 0); // Enable rcv interrupts outb(COM1+COM_IER, COM_IER_RDI); // Clear any preexisting overrun indications and interrupts // Serial port doesn't exist if COM_LSR returns 0xFF serial_exists = (inb(COM1+COM_LSR) != 0xFF); (void) inb(COM1+COM_IIR); (void) inb(COM1+COM_RX); }
5.
cprintf() --> vcprintf() --> vprintfmt()
-->putch()/printfmt()-->cputchar()-->cons_putc()
-->
serial_putc(c) 将数据输出到外设
lpt_putc(c) 数据输出到并行接口
cga_putc(c) (函数内会处理转义字符)数据输出到cga
// What is the purpose of this? if (crt_pos >= CRT_SIZE) { int i; memmove(crt_buf, crt_buf + CRT_COLS, (CRT_SIZE - CRT_COLS) * sizeof(uint16_t)); for (i = CRT_SIZE - CRT_COLS; i < CRT_SIZE; i++) crt_buf[i] = 0x0700 | ' '; crt_pos -= CRT_COLS; }
作用:如果输出的数据超过一个屏幕 80×25 大小 那么就会向上卷屏。
memmove作用是向上卷一行,那么下面自然是原来的最后一行,这样倒数第一行与倒数第二行重复,所以倒数第一行用空格填充并且把pos设置好。
outb(addr_6845, 14); outb(addr_6845 + 1, crt_pos >> 8); outb(addr_6845, 15); outb(addr_6845 + 1, crt_pos);
根据当前位置移动光标。
vprintfmt()中处理八进制的代码:
// (unsigned) octal case 'o': // Replace this with your code. putch('X', putdat); putch('X', putdat); putch('X', putdat); break;
我们来看看十六进制是如何实现的:
// (unsigned) hexadecimal case 'x': num = getuint(&ap, lflag); base = 16; number: printnum(putch, putdat, num, base, width, padc); break;
Exercise 8. We have omitted a small fragment of code - the code necessary to print octal numbers using patterns of the form "%o". Find and fill in this code fragment.
// (unsigned) octal case 'o': // Replace this with your code. //putch('X', putdat); //putch('X', putdat); //putch('X', putdat); num = getuint(&ap, lflag); base = 8; goto number; break;

6.
i386_init() --> test_backtrace() -->
void test_backtrace(int x) { cprintf("entering test_backtrace %d\n", x); if (x > 0) test_backtrace(x-1); else mon_backtrace(0, 0, 0); cprintf("leaving test_backtrace %d\n", x); }
-->
int mon_backtrace(int argc, char **argv, struct Trapframe *tf) { // Your code here. return 0; }

浙公网安备 33010602011771号