add lab answers

This commit is contained in:
chyyuu
2014-08-20 15:42:20 +08:00
parent d9ec12887b
commit f9773095fe
731 changed files with 92876 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
#include <x86.h>
#include <trap.h>
#include <stdio.h>
#include <picirq.h>
/* *
* Support for time-related hardware gadgets - the 8253 timer,
* which generates interruptes on IRQ-0.
* */
#define IO_TIMER1 0x040 // 8253 Timer #1
/* *
* Frequency of all three count-down timers; (TIMER_FREQ/freq)
* is the appropriate count to generate a frequency of freq Hz.
* */
#define TIMER_FREQ 1193182
#define TIMER_DIV(x) ((TIMER_FREQ + (x) / 2) / (x))
#define TIMER_MODE (IO_TIMER1 + 3) // timer mode port
#define TIMER_SEL0 0x00 // select counter 0
#define TIMER_RATEGEN 0x04 // mode 2, rate generator
#define TIMER_16BIT 0x30 // r/w counter 16 bits, LSB first
volatile size_t ticks;
/* *
* clock_init - initialize 8253 clock to interrupt 100 times per second,
* and then enable IRQ_TIMER.
* */
void
clock_init(void) {
// set 8253 timer-chip
outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(IO_TIMER1, TIMER_DIV(100) % 256);
outb(IO_TIMER1, TIMER_DIV(100) / 256);
// initialize time counter 'ticks' to zero
ticks = 0;
cprintf("++ setup timer interrupts\n");
pic_enable(IRQ_TIMER);
}

View File

@@ -0,0 +1,11 @@
#ifndef __KERN_DRIVER_CLOCK_H__
#define __KERN_DRIVER_CLOCK_H__
#include <defs.h>
extern volatile size_t ticks;
void clock_init(void);
#endif /* !__KERN_DRIVER_CLOCK_H__ */

View File

@@ -0,0 +1,465 @@
#include <defs.h>
#include <x86.h>
#include <stdio.h>
#include <string.h>
#include <kbdreg.h>
#include <picirq.h>
#include <trap.h>
#include <memlayout.h>
#include <sync.h>
/* stupid I/O delay routine necessitated by historical PC design flaws */
static void
delay(void) {
inb(0x84);
inb(0x84);
inb(0x84);
inb(0x84);
}
/***** Serial I/O code *****/
#define COM1 0x3F8
#define COM_RX 0 // In: Receive buffer (DLAB=0)
#define COM_TX 0 // Out: Transmit buffer (DLAB=0)
#define COM_DLL 0 // Out: Divisor Latch Low (DLAB=1)
#define COM_DLM 1 // Out: Divisor Latch High (DLAB=1)
#define COM_IER 1 // Out: Interrupt Enable Register
#define COM_IER_RDI 0x01 // Enable receiver data interrupt
#define COM_IIR 2 // In: Interrupt ID Register
#define COM_FCR 2 // Out: FIFO Control Register
#define COM_LCR 3 // Out: Line Control Register
#define COM_LCR_DLAB 0x80 // Divisor latch access bit
#define COM_LCR_WLEN8 0x03 // Wordlength: 8 bits
#define COM_MCR 4 // Out: Modem Control Register
#define COM_MCR_RTS 0x02 // RTS complement
#define COM_MCR_DTR 0x01 // DTR complement
#define COM_MCR_OUT2 0x08 // Out2 complement
#define COM_LSR 5 // In: Line Status Register
#define COM_LSR_DATA 0x01 // Data available
#define COM_LSR_TXRDY 0x20 // Transmit buffer avail
#define COM_LSR_TSRE 0x40 // Transmitter off
#define MONO_BASE 0x3B4
#define MONO_BUF 0xB0000
#define CGA_BASE 0x3D4
#define CGA_BUF 0xB8000
#define CRT_ROWS 25
#define CRT_COLS 80
#define CRT_SIZE (CRT_ROWS * CRT_COLS)
#define LPTPORT 0x378
static uint16_t *crt_buf;
static uint16_t crt_pos;
static uint16_t addr_6845;
/* TEXT-mode CGA/VGA display output */
static void
cga_init(void) {
volatile uint16_t *cp = (uint16_t *)(CGA_BUF + KERNBASE);
uint16_t was = *cp;
*cp = (uint16_t) 0xA55A;
if (*cp != 0xA55A) {
cp = (uint16_t*)(MONO_BUF + KERNBASE);
addr_6845 = MONO_BASE;
} else {
*cp = was;
addr_6845 = CGA_BASE;
}
// Extract cursor location
uint32_t pos;
outb(addr_6845, 14);
pos = inb(addr_6845 + 1) << 8;
outb(addr_6845, 15);
pos |= inb(addr_6845 + 1);
crt_buf = (uint16_t*) cp;
crt_pos = pos;
}
static bool serial_exists = 0;
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);
if (serial_exists) {
pic_enable(IRQ_COM1);
}
}
static void
lpt_putc_sub(int c) {
int i;
for (i = 0; !(inb(LPTPORT + 1) & 0x80) && i < 12800; i ++) {
delay();
}
outb(LPTPORT + 0, c);
outb(LPTPORT + 2, 0x08 | 0x04 | 0x01);
outb(LPTPORT + 2, 0x08);
}
/* lpt_putc - copy console output to parallel port */
static void
lpt_putc(int c) {
if (c != '\b') {
lpt_putc_sub(c);
}
else {
lpt_putc_sub('\b');
lpt_putc_sub(' ');
lpt_putc_sub('\b');
}
}
/* cga_putc - print character to console */
static void
cga_putc(int c) {
// set black on white
if (!(c & ~0xFF)) {
c |= 0x0700;
}
switch (c & 0xff) {
case '\b':
if (crt_pos > 0) {
crt_pos --;
crt_buf[crt_pos] = (c & ~0xff) | ' ';
}
break;
case '\n':
crt_pos += CRT_COLS;
case '\r':
crt_pos -= (crt_pos % CRT_COLS);
break;
default:
crt_buf[crt_pos ++] = c; // write the character
break;
}
// 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;
}
// move that little blinky thing
outb(addr_6845, 14);
outb(addr_6845 + 1, crt_pos >> 8);
outb(addr_6845, 15);
outb(addr_6845 + 1, crt_pos);
}
static void
serial_putc_sub(int c) {
int i;
for (i = 0; !(inb(COM1 + COM_LSR) & COM_LSR_TXRDY) && i < 12800; i ++) {
delay();
}
outb(COM1 + COM_TX, c);
}
/* serial_putc - print character to serial port */
static void
serial_putc(int c) {
if (c != '\b') {
serial_putc_sub(c);
}
else {
serial_putc_sub('\b');
serial_putc_sub(' ');
serial_putc_sub('\b');
}
}
/* *
* Here we manage the console input buffer, where we stash characters
* received from the keyboard or serial port whenever the corresponding
* interrupt occurs.
* */
#define CONSBUFSIZE 512
static struct {
uint8_t buf[CONSBUFSIZE];
uint32_t rpos;
uint32_t wpos;
} cons;
/* *
* cons_intr - called by device interrupt routines to feed input
* characters into the circular console input buffer.
* */
static void
cons_intr(int (*proc)(void)) {
int c;
while ((c = (*proc)()) != -1) {
if (c != 0) {
cons.buf[cons.wpos ++] = c;
if (cons.wpos == CONSBUFSIZE) {
cons.wpos = 0;
}
}
}
}
/* serial_proc_data - get data from serial port */
static int
serial_proc_data(void) {
if (!(inb(COM1 + COM_LSR) & COM_LSR_DATA)) {
return -1;
}
int c = inb(COM1 + COM_RX);
if (c == 127) {
c = '\b';
}
return c;
}
/* serial_intr - try to feed input characters from serial port */
void
serial_intr(void) {
if (serial_exists) {
cons_intr(serial_proc_data);
}
}
/***** Keyboard input code *****/
#define NO 0
#define SHIFT (1<<0)
#define CTL (1<<1)
#define ALT (1<<2)
#define CAPSLOCK (1<<3)
#define NUMLOCK (1<<4)
#define SCROLLLOCK (1<<5)
#define E0ESC (1<<6)
static uint8_t shiftcode[256] = {
[0x1D] CTL,
[0x2A] SHIFT,
[0x36] SHIFT,
[0x38] ALT,
[0x9D] CTL,
[0xB8] ALT
};
static uint8_t togglecode[256] = {
[0x3A] CAPSLOCK,
[0x45] NUMLOCK,
[0x46] SCROLLLOCK
};
static uint8_t normalmap[256] = {
NO, 0x1B, '1', '2', '3', '4', '5', '6', // 0x00
'7', '8', '9', '0', '-', '=', '\b', '\t',
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', // 0x10
'o', 'p', '[', ']', '\n', NO, 'a', 's',
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', // 0x20
'\'', '`', NO, '\\', 'z', 'x', 'c', 'v',
'b', 'n', 'm', ',', '.', '/', NO, '*', // 0x30
NO, ' ', NO, NO, NO, NO, NO, NO,
NO, NO, NO, NO, NO, NO, NO, '7', // 0x40
'8', '9', '-', '4', '5', '6', '+', '1',
'2', '3', '0', '.', NO, NO, NO, NO, // 0x50
[0xC7] KEY_HOME, [0x9C] '\n' /*KP_Enter*/,
[0xB5] '/' /*KP_Div*/, [0xC8] KEY_UP,
[0xC9] KEY_PGUP, [0xCB] KEY_LF,
[0xCD] KEY_RT, [0xCF] KEY_END,
[0xD0] KEY_DN, [0xD1] KEY_PGDN,
[0xD2] KEY_INS, [0xD3] KEY_DEL
};
static uint8_t shiftmap[256] = {
NO, 033, '!', '@', '#', '$', '%', '^', // 0x00
'&', '*', '(', ')', '_', '+', '\b', '\t',
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', // 0x10
'O', 'P', '{', '}', '\n', NO, 'A', 'S',
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', // 0x20
'"', '~', NO, '|', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', '<', '>', '?', NO, '*', // 0x30
NO, ' ', NO, NO, NO, NO, NO, NO,
NO, NO, NO, NO, NO, NO, NO, '7', // 0x40
'8', '9', '-', '4', '5', '6', '+', '1',
'2', '3', '0', '.', NO, NO, NO, NO, // 0x50
[0xC7] KEY_HOME, [0x9C] '\n' /*KP_Enter*/,
[0xB5] '/' /*KP_Div*/, [0xC8] KEY_UP,
[0xC9] KEY_PGUP, [0xCB] KEY_LF,
[0xCD] KEY_RT, [0xCF] KEY_END,
[0xD0] KEY_DN, [0xD1] KEY_PGDN,
[0xD2] KEY_INS, [0xD3] KEY_DEL
};
#define C(x) (x - '@')
static uint8_t ctlmap[256] = {
NO, NO, NO, NO, NO, NO, NO, NO,
NO, NO, NO, NO, NO, NO, NO, NO,
C('Q'), C('W'), C('E'), C('R'), C('T'), C('Y'), C('U'), C('I'),
C('O'), C('P'), NO, NO, '\r', NO, C('A'), C('S'),
C('D'), C('F'), C('G'), C('H'), C('J'), C('K'), C('L'), NO,
NO, NO, NO, C('\\'), C('Z'), C('X'), C('C'), C('V'),
C('B'), C('N'), C('M'), NO, NO, C('/'), NO, NO,
[0x97] KEY_HOME,
[0xB5] C('/'), [0xC8] KEY_UP,
[0xC9] KEY_PGUP, [0xCB] KEY_LF,
[0xCD] KEY_RT, [0xCF] KEY_END,
[0xD0] KEY_DN, [0xD1] KEY_PGDN,
[0xD2] KEY_INS, [0xD3] KEY_DEL
};
static uint8_t *charcode[4] = {
normalmap,
shiftmap,
ctlmap,
ctlmap
};
/* *
* kbd_proc_data - get data from keyboard
*
* The kbd_proc_data() function gets data from the keyboard.
* If we finish a character, return it, else 0. And return -1 if no data.
* */
static int
kbd_proc_data(void) {
int c;
uint8_t data;
static uint32_t shift;
if ((inb(KBSTATP) & KBS_DIB) == 0) {
return -1;
}
data = inb(KBDATAP);
if (data == 0xE0) {
// E0 escape character
shift |= E0ESC;
return 0;
} else if (data & 0x80) {
// Key released
data = (shift & E0ESC ? data : data & 0x7F);
shift &= ~(shiftcode[data] | E0ESC);
return 0;
} else if (shift & E0ESC) {
// Last character was an E0 escape; or with 0x80
data |= 0x80;
shift &= ~E0ESC;
}
shift |= shiftcode[data];
shift ^= togglecode[data];
c = charcode[shift & (CTL | SHIFT)][data];
if (shift & CAPSLOCK) {
if ('a' <= c && c <= 'z')
c += 'A' - 'a';
else if ('A' <= c && c <= 'Z')
c += 'a' - 'A';
}
// Process special keys
// Ctrl-Alt-Del: reboot
if (!(~shift & (CTL | ALT)) && c == KEY_DEL) {
cprintf("Rebooting!\n");
outb(0x92, 0x3); // courtesy of Chris Frost
}
return c;
}
/* kbd_intr - try to feed input characters from keyboard */
static void
kbd_intr(void) {
cons_intr(kbd_proc_data);
}
static void
kbd_init(void) {
// drain the kbd buffer
kbd_intr();
pic_enable(IRQ_KBD);
}
/* cons_init - initializes the console devices */
void
cons_init(void) {
cga_init();
serial_init();
kbd_init();
if (!serial_exists) {
cprintf("serial port does not exist!!\n");
}
}
/* cons_putc - print a single character @c to console devices */
void
cons_putc(int c) {
bool intr_flag;
local_intr_save(intr_flag);
{
lpt_putc(c);
cga_putc(c);
serial_putc(c);
}
local_intr_restore(intr_flag);
}
/* *
* cons_getc - return the next input character from console,
* or 0 if none waiting.
* */
int
cons_getc(void) {
int c = 0;
bool intr_flag;
local_intr_save(intr_flag);
{
// poll for any pending input characters,
// so that this function works even when interrupts are disabled
// (e.g., when called from the kernel monitor).
serial_intr();
kbd_intr();
// grab the next character from the input buffer.
if (cons.rpos != cons.wpos) {
c = cons.buf[cons.rpos ++];
if (cons.rpos == CONSBUFSIZE) {
cons.rpos = 0;
}
}
}
local_intr_restore(intr_flag);
return c;
}

View File

@@ -0,0 +1,11 @@
#ifndef __KERN_DRIVER_CONSOLE_H__
#define __KERN_DRIVER_CONSOLE_H__
void cons_init(void);
void cons_putc(int c);
int cons_getc(void);
void serial_intr(void);
void kbd_intr(void);
#endif /* !__KERN_DRIVER_CONSOLE_H__ */

View File

@@ -0,0 +1,214 @@
#include <defs.h>
#include <stdio.h>
#include <trap.h>
#include <picirq.h>
#include <fs.h>
#include <ide.h>
#include <x86.h>
#include <assert.h>
#define ISA_DATA 0x00
#define ISA_ERROR 0x01
#define ISA_PRECOMP 0x01
#define ISA_CTRL 0x02
#define ISA_SECCNT 0x02
#define ISA_SECTOR 0x03
#define ISA_CYL_LO 0x04
#define ISA_CYL_HI 0x05
#define ISA_SDH 0x06
#define ISA_COMMAND 0x07
#define ISA_STATUS 0x07
#define IDE_BSY 0x80
#define IDE_DRDY 0x40
#define IDE_DF 0x20
#define IDE_DRQ 0x08
#define IDE_ERR 0x01
#define IDE_CMD_READ 0x20
#define IDE_CMD_WRITE 0x30
#define IDE_CMD_IDENTIFY 0xEC
#define IDE_IDENT_SECTORS 20
#define IDE_IDENT_MODEL 54
#define IDE_IDENT_CAPABILITIES 98
#define IDE_IDENT_CMDSETS 164
#define IDE_IDENT_MAX_LBA 120
#define IDE_IDENT_MAX_LBA_EXT 200
#define IO_BASE0 0x1F0
#define IO_BASE1 0x170
#define IO_CTRL0 0x3F4
#define IO_CTRL1 0x374
#define MAX_IDE 4
#define MAX_NSECS 128
#define MAX_DISK_NSECS 0x10000000U
#define VALID_IDE(ideno) (((ideno) >= 0) && ((ideno) < MAX_IDE) && (ide_devices[ideno].valid))
static const struct {
unsigned short base; // I/O Base
unsigned short ctrl; // Control Base
} channels[2] = {
{IO_BASE0, IO_CTRL0},
{IO_BASE1, IO_CTRL1},
};
#define IO_BASE(ideno) (channels[(ideno) >> 1].base)
#define IO_CTRL(ideno) (channels[(ideno) >> 1].ctrl)
static struct ide_device {
unsigned char valid; // 0 or 1 (If Device Really Exists)
unsigned int sets; // Commend Sets Supported
unsigned int size; // Size in Sectors
unsigned char model[41]; // Model in String
} ide_devices[MAX_IDE];
static int
ide_wait_ready(unsigned short iobase, bool check_error) {
int r;
while ((r = inb(iobase + ISA_STATUS)) & IDE_BSY)
/* nothing */;
if (check_error && (r & (IDE_DF | IDE_ERR)) != 0) {
return -1;
}
return 0;
}
void
ide_init(void) {
static_assert((SECTSIZE % 4) == 0);
unsigned short ideno, iobase;
for (ideno = 0; ideno < MAX_IDE; ideno ++) {
/* assume that no device here */
ide_devices[ideno].valid = 0;
iobase = IO_BASE(ideno);
/* wait device ready */
ide_wait_ready(iobase, 0);
/* step1: select drive */
outb(iobase + ISA_SDH, 0xE0 | ((ideno & 1) << 4));
ide_wait_ready(iobase, 0);
/* step2: send ATA identify command */
outb(iobase + ISA_COMMAND, IDE_CMD_IDENTIFY);
ide_wait_ready(iobase, 0);
/* step3: polling */
if (inb(iobase + ISA_STATUS) == 0 || ide_wait_ready(iobase, 1) != 0) {
continue ;
}
/* device is ok */
ide_devices[ideno].valid = 1;
/* read identification space of the device */
unsigned int buffer[128];
insl(iobase + ISA_DATA, buffer, sizeof(buffer) / sizeof(unsigned int));
unsigned char *ident = (unsigned char *)buffer;
unsigned int sectors;
unsigned int cmdsets = *(unsigned int *)(ident + IDE_IDENT_CMDSETS);
/* device use 48-bits or 28-bits addressing */
if (cmdsets & (1 << 26)) {
sectors = *(unsigned int *)(ident + IDE_IDENT_MAX_LBA_EXT);
}
else {
sectors = *(unsigned int *)(ident + IDE_IDENT_MAX_LBA);
}
ide_devices[ideno].sets = cmdsets;
ide_devices[ideno].size = sectors;
/* check if supports LBA */
assert((*(unsigned short *)(ident + IDE_IDENT_CAPABILITIES) & 0x200) != 0);
unsigned char *model = ide_devices[ideno].model, *data = ident + IDE_IDENT_MODEL;
unsigned int i, length = 40;
for (i = 0; i < length; i += 2) {
model[i] = data[i + 1], model[i + 1] = data[i];
}
do {
model[i] = '\0';
} while (i -- > 0 && model[i] == ' ');
cprintf("ide %d: %10u(sectors), '%s'.\n", ideno, ide_devices[ideno].size, ide_devices[ideno].model);
}
// enable ide interrupt
pic_enable(IRQ_IDE1);
pic_enable(IRQ_IDE2);
}
bool
ide_device_valid(unsigned short ideno) {
return VALID_IDE(ideno);
}
size_t
ide_device_size(unsigned short ideno) {
if (ide_device_valid(ideno)) {
return ide_devices[ideno].size;
}
return 0;
}
int
ide_read_secs(unsigned short ideno, uint32_t secno, void *dst, size_t nsecs) {
assert(nsecs <= MAX_NSECS && VALID_IDE(ideno));
assert(secno < MAX_DISK_NSECS && secno + nsecs <= MAX_DISK_NSECS);
unsigned short iobase = IO_BASE(ideno), ioctrl = IO_CTRL(ideno);
ide_wait_ready(iobase, 0);
// generate interrupt
outb(ioctrl + ISA_CTRL, 0);
outb(iobase + ISA_SECCNT, nsecs);
outb(iobase + ISA_SECTOR, secno & 0xFF);
outb(iobase + ISA_CYL_LO, (secno >> 8) & 0xFF);
outb(iobase + ISA_CYL_HI, (secno >> 16) & 0xFF);
outb(iobase + ISA_SDH, 0xE0 | ((ideno & 1) << 4) | ((secno >> 24) & 0xF));
outb(iobase + ISA_COMMAND, IDE_CMD_READ);
int ret = 0;
for (; nsecs > 0; nsecs --, dst += SECTSIZE) {
if ((ret = ide_wait_ready(iobase, 1)) != 0) {
goto out;
}
insl(iobase, dst, SECTSIZE / sizeof(uint32_t));
}
out:
return ret;
}
int
ide_write_secs(unsigned short ideno, uint32_t secno, const void *src, size_t nsecs) {
assert(nsecs <= MAX_NSECS && VALID_IDE(ideno));
assert(secno < MAX_DISK_NSECS && secno + nsecs <= MAX_DISK_NSECS);
unsigned short iobase = IO_BASE(ideno), ioctrl = IO_CTRL(ideno);
ide_wait_ready(iobase, 0);
// generate interrupt
outb(ioctrl + ISA_CTRL, 0);
outb(iobase + ISA_SECCNT, nsecs);
outb(iobase + ISA_SECTOR, secno & 0xFF);
outb(iobase + ISA_CYL_LO, (secno >> 8) & 0xFF);
outb(iobase + ISA_CYL_HI, (secno >> 16) & 0xFF);
outb(iobase + ISA_SDH, 0xE0 | ((ideno & 1) << 4) | ((secno >> 24) & 0xF));
outb(iobase + ISA_COMMAND, IDE_CMD_WRITE);
int ret = 0;
for (; nsecs > 0; nsecs --, src += SECTSIZE) {
if ((ret = ide_wait_ready(iobase, 1)) != 0) {
goto out;
}
outsl(iobase, src, SECTSIZE / sizeof(uint32_t));
}
out:
return ret;
}

View File

@@ -0,0 +1,14 @@
#ifndef __KERN_DRIVER_IDE_H__
#define __KERN_DRIVER_IDE_H__
#include <defs.h>
void ide_init(void);
bool ide_device_valid(unsigned short ideno);
size_t ide_device_size(unsigned short ideno);
int ide_read_secs(unsigned short ideno, uint32_t secno, void *dst, size_t nsecs);
int ide_write_secs(unsigned short ideno, uint32_t secno, const void *src, size_t nsecs);
#endif /* !__KERN_DRIVER_IDE_H__ */

View File

@@ -0,0 +1,15 @@
#include <x86.h>
#include <intr.h>
/* intr_enable - enable irq interrupt */
void
intr_enable(void) {
sti();
}
/* intr_disable - disable irq interrupt */
void
intr_disable(void) {
cli();
}

View File

@@ -0,0 +1,8 @@
#ifndef __KERN_DRIVER_INTR_H__
#define __KERN_DRIVER_INTR_H__
void intr_enable(void);
void intr_disable(void);
#endif /* !__KERN_DRIVER_INTR_H__ */

View File

@@ -0,0 +1,84 @@
#ifndef __KERN_DRIVER_KBDREG_H__
#define __KERN_DRIVER_KBDREG_H__
// Special keycodes
#define KEY_HOME 0xE0
#define KEY_END 0xE1
#define KEY_UP 0xE2
#define KEY_DN 0xE3
#define KEY_LF 0xE4
#define KEY_RT 0xE5
#define KEY_PGUP 0xE6
#define KEY_PGDN 0xE7
#define KEY_INS 0xE8
#define KEY_DEL 0xE9
/* This is i8042reg.h + kbdreg.h from NetBSD. */
#define KBSTATP 0x64 // kbd controller status port(I)
#define KBS_DIB 0x01 // kbd data in buffer
#define KBS_IBF 0x02 // kbd input buffer low
#define KBS_WARM 0x04 // kbd input buffer low
#define BS_OCMD 0x08 // kbd output buffer has command
#define KBS_NOSEC 0x10 // kbd security lock not engaged
#define KBS_TERR 0x20 // kbd transmission error
#define KBS_RERR 0x40 // kbd receive error
#define KBS_PERR 0x80 // kbd parity error
#define KBCMDP 0x64 // kbd controller port(O)
#define KBC_RAMREAD 0x20 // read from RAM
#define KBC_RAMWRITE 0x60 // write to RAM
#define KBC_AUXDISABLE 0xa7 // disable auxiliary port
#define KBC_AUXENABLE 0xa8 // enable auxiliary port
#define KBC_AUXTEST 0xa9 // test auxiliary port
#define KBC_KBDECHO 0xd2 // echo to keyboard port
#define KBC_AUXECHO 0xd3 // echo to auxiliary port
#define KBC_AUXWRITE 0xd4 // write to auxiliary port
#define KBC_SELFTEST 0xaa // start self-test
#define KBC_KBDTEST 0xab // test keyboard port
#define KBC_KBDDISABLE 0xad // disable keyboard port
#define KBC_KBDENABLE 0xae // enable keyboard port
#define KBC_PULSE0 0xfe // pulse output bit 0
#define KBC_PULSE1 0xfd // pulse output bit 1
#define KBC_PULSE2 0xfb // pulse output bit 2
#define KBC_PULSE3 0xf7 // pulse output bit 3
#define KBDATAP 0x60 // kbd data port(I)
#define KBOUTP 0x60 // kbd data port(O)
#define K_RDCMDBYTE 0x20
#define K_LDCMDBYTE 0x60
#define KC8_TRANS 0x40 // convert to old scan codes
#define KC8_MDISABLE 0x20 // disable mouse
#define KC8_KDISABLE 0x10 // disable keyboard
#define KC8_IGNSEC 0x08 // ignore security lock
#define KC8_CPU 0x04 // exit from protected mode reset
#define KC8_MENABLE 0x02 // enable mouse interrupt
#define KC8_KENABLE 0x01 // enable keyboard interrupt
#define CMDBYTE (KC8_TRANS|KC8_CPU|KC8_MENABLE|KC8_KENABLE)
/* keyboard commands */
#define KBC_RESET 0xFF // reset the keyboard
#define KBC_RESEND 0xFE // request the keyboard resend the last byte
#define KBC_SETDEFAULT 0xF6 // resets keyboard to its power-on defaults
#define KBC_DISABLE 0xF5 // as per KBC_SETDEFAULT, but also disable key scanning
#define KBC_ENABLE 0xF4 // enable key scanning
#define KBC_TYPEMATIC 0xF3 // set typematic rate and delay
#define KBC_SETTABLE 0xF0 // set scancode translation table
#define KBC_MODEIND 0xED // set mode indicators(i.e. LEDs)
#define KBC_ECHO 0xEE // request an echo from the keyboard
/* keyboard responses */
#define KBR_EXTENDED 0xE0 // extended key sequence
#define KBR_RESEND 0xFE // needs resend of command
#define KBR_ACK 0xFA // received a valid command
#define KBR_OVERRUN 0x00 // flooded
#define KBR_FAILURE 0xFD // diagnosic failure
#define KBR_BREAK 0xF0 // break code prefix - sent on key release
#define KBR_RSTDONE 0xAA // reset complete
#define KBR_ECHO 0xEE // echo response
#endif /* !__KERN_DRIVER_KBDREG_H__ */

View File

@@ -0,0 +1,86 @@
#include <defs.h>
#include <x86.h>
#include <picirq.h>
// I/O Addresses of the two programmable interrupt controllers
#define IO_PIC1 0x20 // Master (IRQs 0-7)
#define IO_PIC2 0xA0 // Slave (IRQs 8-15)
#define IRQ_SLAVE 2 // IRQ at which slave connects to master
// Current IRQ mask.
// Initial IRQ mask has interrupt 2 enabled (for slave 8259A).
static uint16_t irq_mask = 0xFFFF & ~(1 << IRQ_SLAVE);
static bool did_init = 0;
static void
pic_setmask(uint16_t mask) {
irq_mask = mask;
if (did_init) {
outb(IO_PIC1 + 1, mask);
outb(IO_PIC2 + 1, mask >> 8);
}
}
void
pic_enable(unsigned int irq) {
pic_setmask(irq_mask & ~(1 << irq));
}
/* pic_init - initialize the 8259A interrupt controllers */
void
pic_init(void) {
did_init = 1;
// mask all interrupts
outb(IO_PIC1 + 1, 0xFF);
outb(IO_PIC2 + 1, 0xFF);
// Set up master (8259A-1)
// ICW1: 0001g0hi
// g: 0 = edge triggering, 1 = level triggering
// h: 0 = cascaded PICs, 1 = master only
// i: 0 = no ICW4, 1 = ICW4 required
outb(IO_PIC1, 0x11);
// ICW2: Vector offset
outb(IO_PIC1 + 1, IRQ_OFFSET);
// ICW3: (master PIC) bit mask of IR lines connected to slaves
// (slave PIC) 3-bit # of slave's connection to master
outb(IO_PIC1 + 1, 1 << IRQ_SLAVE);
// ICW4: 000nbmap
// n: 1 = special fully nested mode
// b: 1 = buffered mode
// m: 0 = slave PIC, 1 = master PIC
// (ignored when b is 0, as the master/slave role
// can be hardwired).
// a: 1 = Automatic EOI mode
// p: 0 = MCS-80/85 mode, 1 = intel x86 mode
outb(IO_PIC1 + 1, 0x3);
// Set up slave (8259A-2)
outb(IO_PIC2, 0x11); // ICW1
outb(IO_PIC2 + 1, IRQ_OFFSET + 8); // ICW2
outb(IO_PIC2 + 1, IRQ_SLAVE); // ICW3
// NB Automatic EOI mode doesn't tend to work on the slave.
// Linux source code says it's "to be investigated".
outb(IO_PIC2 + 1, 0x3); // ICW4
// OCW3: 0ef01prs
// ef: 0x = NOP, 10 = clear specific mask, 11 = set specific mask
// p: 0 = no polling, 1 = polling mode
// rs: 0x = NOP, 10 = read IRR, 11 = read ISR
outb(IO_PIC1, 0x68); // clear specific mask
outb(IO_PIC1, 0x0a); // read IRR by default
outb(IO_PIC2, 0x68); // OCW3
outb(IO_PIC2, 0x0a); // OCW3
if (irq_mask != 0xFFFF) {
pic_setmask(irq_mask);
}
}

View File

@@ -0,0 +1,10 @@
#ifndef __KERN_DRIVER_PICIRQ_H__
#define __KERN_DRIVER_PICIRQ_H__
void pic_init(void);
void pic_enable(unsigned int irq);
#define IRQ_OFFSET 32
#endif /* !__KERN_DRIVER_PICIRQ_H__ */