1 1. Example use of I/O instructions: boot loader 2 3 Below is a part of WeensyOS boot loader (for WeensyOS Schedos, which is part of 4 lab 4). 5 6 The main point for today’s class is that this code demonstrates I/O, 7 specifically with the disk: the bootloader reads in the kernel from the disk. 8 9 See the functions waitdisk() and readsect(). Compare to Figures 36.5 10 and 36.6 in OSTEP 11 12 13 14 #define SECTORSIZE 512 15 16 void waitdisk(void) 17 { 18 // wait for disk reaady 19 while ((inb(0x1F7) & 0xC0) != 0x40) 20 /* do nothing */; 21 } 22 23 void readsect(void *dst, uint32_t sect) 24 { 25 // wait for disk to be ready 26 waitdisk(); 27 28 outb(0x1F2, 1); // count = 1 29 outb(0x1F3, sect); 30 outb(0x1F4, sect >> 8); 31 outb(0x1F5, sect >> 16); 32 outb(0x1F6, (sect >> 24) | 0xE0); 33 outb(0x1F7, 0x20); // cmd 0x20 − read sectors 34 35 // wait for disk to be ready 36 waitdisk(); 37 38 // read a sector 39 insl(0x1F0, dst, SECTORSIZE/4); 40 } 41 42 43 2. Another example: reading keyboard input 44 45 The code below is an excerpt from WeensyOS’s x86.c. 46 47 This reads a character typed at the keyboard (which shows up on the 48 "keyboard data port" (KBDATAP)), and converts it to a digit. This 49 code is not called in lab4; it was called in lab1. (Use grep to 50 convince yourself of this!) 51 52 /* Excerpt from WeensyOS x86.c. Comments from kbd.h in xv6 */ 53 54 #define KBSTATP 0x64 // keyboard controller status port (I) 55 #define KBS_DIB 0x01 // keyboard data in buffer 56 #define KBDATAP 0x60 // keyboard data port (I) 57 58 int console_read_digit(void) 59 { 60 uint8_t data; 61 62 if ((inb(KBSTATP) & KBS_DIB) == 0) 63 return −1; 64 65 data = inb(KBDATAP); 66 67 if (data >= 0x02 && data <= 0x0A) 68 return data − 0x02 + 1; 69 else if (data == 0x0B) 70 return 0; 71 else if (data >= 0x47 && data <= 0x49) 72 return data − 0x47 + 7; 73 else if (data >= 0x4B && data <= 0x4D) 74 return data − 0x4B + 4; 75 else if (data >= 0x4F && data <= 0x51) 76 return data − 0x4F + 1; 77 else if (data == 0x53) 78 return 0; 79 else 80 return −1; 81 } 82 83 3. Memory−mapped I/O 84 85 An example is the console printing code from WeensyOS. Here are 86 excerpts from lib.h and lib.c: 87 88 /* Compare the addresses below to the map above. */ 89 #define CONSOLE_BEGIN ((uint16_t *) 0x000B8000) 90 #define CONSOLE_END (CONSOLE_BEGIN + 80 * 25) 91 92 /* 93 * prints a character to the console at the specified 94 * cursor position in the specified color. 95 */ 96 97 static uint16_t * 98 console_putc(uint16_t *cursor, unsigned char c, int color) 99 { 100 if (cursor >= CONSOLE_END) 101 cursor = CONSOLE_BEGIN; 102 103 if (c == ’\n’) { 104 int pos = (cursor − CONSOLE_BEGIN) % 80; 105 106 /* what does this do? */ 107 for (; pos != 80; pos++) 108 *cursor++ = ’ ’ | color; 109 } else 110 *cursor++ = c | color; 111 112 return cursor; 113 }