[Feature]add MT2731_MP2_MR2_SVN388 baseline version
Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/platform/pc/console.c b/src/bsp/lk/platform/pc/console.c
new file mode 100644
index 0000000..d4ccabd
--- /dev/null
+++ b/src/bsp/lk/platform/pc/console.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <arch/x86.h>
+#include <platform/pc.h>
+#include <platform/console.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+/* CGA values */
+#define CURSOR_START 0x0A
+#define CURSOR_END 0x0B
+#define VIDEO_ADDRESS_MSB 0x0C
+#define VIDEO_ADDRESS_LSB 0x0D
+#define CURSOR_POS_MSB 0x0E
+#define CURSOR_POS_LSB 0x0F
+
+/* curr settings */
+static unsigned char curr_x;
+static unsigned char curr_y;
+static unsigned char curr_start;
+static unsigned char curr_end;
+static unsigned char curr_attr;
+
+/* video page buffer */
+#define VPAGE_SIZE 2048
+#define PAGE_MAX 8
+
+static int active_page = 0;
+static int visual_page = 0;
+
+static int curs_x[PAGE_MAX];
+static int curs_y[PAGE_MAX];
+
+static struct {
+ int x1, y1, x2, y2;
+} view_window = {
+ 0, 0, 79, 24
+};
+
+void platform_init_console(void)
+{
+ curr_save();
+ window(0, 0, 79, 24);
+ clear();
+ place(0, 0);
+}
+
+void set_visual_page(int page)
+{
+ unsigned short page_offset = page*VPAGE_SIZE;
+ visual_page = page;
+
+ outp(CGA_INDEX_REG, VIDEO_ADDRESS_LSB);
+ outp(CGA_DATA_REG, page_offset & 0xFF);
+ outp(CGA_INDEX_REG, VIDEO_ADDRESS_MSB);
+ outp(CGA_DATA_REG, (page_offset >> 8) & 0xFF);
+}
+
+void set_active_page(int page)
+{
+ curs_x[active_page] = curr_x;
+ curs_y[active_page] = curr_y;
+ curr_x = curs_x[page];
+ curr_y = curs_y[page];
+ active_page = page;
+}
+
+int get_visual_page(void)
+{
+ return visual_page;
+}
+
+int get_active_page(void)
+{
+ return active_page;
+}
+
+void place(int x,int y)
+{
+ unsigned short cursor_word = x + y*80 + active_page*VPAGE_SIZE;
+
+ /*
+ * program CGA using index reg, then data reg
+ */
+ outp(CGA_INDEX_REG, CURSOR_POS_LSB);
+ outp(CGA_DATA_REG, cursor_word & 0xFF);
+ outp(CGA_INDEX_REG, CURSOR_POS_MSB);
+ outp(CGA_DATA_REG, (cursor_word >> 8) & 0xFF);
+
+ curr_x = x;
+ curr_y = y;
+}
+
+void cursor(int start,int end)
+{
+ outp(CGA_INDEX_REG, CURSOR_START);
+ outp(CGA_DATA_REG, start);
+ outp(CGA_INDEX_REG, CURSOR_END);
+ outp(CGA_DATA_REG, end);
+}
+
+void curr_save(void)
+{
+ /* grab some info from the bios data area (these should be defined in memmap.h */
+ curr_attr = *((unsigned char *)0xB8000 + 159);
+ curr_x = *((unsigned char *)0x00450);
+ curr_y = *((unsigned char *)0x00451);
+ curr_end = *((unsigned char *)0x00460);
+ curr_start = *((unsigned char *)0x00461);
+ active_page = visual_page = 0;
+}
+
+void curr_restore(void)
+{
+ *((unsigned char *)0x00450) = curr_x;
+ *((unsigned char *)0x00451) = curr_y;
+
+ place(curr_x, curr_y);
+ cursor(curr_start, curr_end);
+}
+
+void window(int x1, int y1, int x2, int y2)
+{
+ view_window.x1 = x1;
+ view_window.y1 = y1;
+ view_window.x2 = x2;
+ view_window.y2 = y2;
+
+ //place(x1, y1);
+}
+
+void _clear(char c,char attr,int x1,int y1,int x2,int y2)
+{
+ register int i,j;
+ unsigned short w = attr;
+
+ w <<= 8;
+ w |= c;
+ for (i = x1; i <= x2; i++) {
+ for (j = y1; j <= y2; j++) {
+ *((unsigned short *)(uintptr_t)(0xB8000 + 2*i+160*j + 2 * active_page * VPAGE_SIZE)) = w;
+ }
+ }
+
+ place(x1,y1);
+ curr_y = y1;
+ curr_x = x1;
+}
+
+void clear()
+{
+ _clear(' ', curr_attr, view_window.x1, view_window.y1, view_window.x2,
+ view_window.y2);
+}
+
+void _scroll(char attr, int x1, int y1, int x2, int y2)
+{
+ register int x,y;
+ unsigned short xattr = attr << 8,w;
+ unsigned char *v = (unsigned char *)(uintptr_t)(0xB8000 + active_page*(2*VPAGE_SIZE));
+
+ for (y = y1+1; y <= y2; y++) {
+ for (x = x1; x <= x2; x++) {
+ w = *((unsigned short *) (v + 2*(y*80+x)));
+ *((unsigned short *)(v + 2*((y-1)*80+x))) = w;
+ }
+ }
+
+ for (x = x1; x <= x2; x++) {
+ *((unsigned short *)(v + 2*((y-1)*80+x))) = xattr;
+ }
+}
+
+void scroll(void)
+{
+ _scroll(curr_attr, view_window.x1, view_window.y1, view_window.x2,
+ view_window.y2);
+}
+
+void cputc(char c)
+{
+ static unsigned short scan_x, x, y;
+ unsigned char *v = (unsigned char *)(uintptr_t)(0xB8000 + active_page*(2*VPAGE_SIZE));
+ x = curr_x;
+ y = curr_y;
+
+ switch (c) {
+ case '\t':
+ x += 8;
+ if (x >= view_window.x2+1) {
+ x = view_window.x1;
+ if (y == view_window.y2) {
+ scroll();
+ } else {
+ y++;
+ }
+ } else {
+ scan_x = 0;
+
+ while ((scan_x+8) < x) {
+ scan_x += 8;
+ }
+
+ x = scan_x;
+ }
+ break;
+
+ case '\r':
+ x = view_window.x1;
+ break;
+
+ case '\n':
+ if (y == view_window.y2) {
+ scroll();
+ } else {
+ y++;
+ }
+ break;
+
+ case '\b':
+ x--;
+ *(v + 2*(x + y*80)) = ' ';
+ break;
+
+ default:
+ *(v + 2*(x + y*80)) = c;
+ x++;
+
+ if (x >= view_window.x2+1) {
+ x = view_window.x1;
+ if (y == view_window.y2) {
+ scroll();
+ } else {
+ y++;
+ }
+ }
+ }
+
+ place(x, y);
+}
+
+void cputs(char *s)
+{
+ char c;
+ while (*s != '\0') {
+ c = *s++;
+ cputc(c);
+ }
+}
+
+void puts_xy(int x,int y,char attr,char *s)
+{
+ unsigned char *v = (unsigned char *)(uintptr_t)(0xB8000 + (80*y+x)*2 + active_page*(2*VPAGE_SIZE));
+ while (*s != 0) {
+ *v = *s;
+ s++;
+ v++;
+ *v = attr;
+ v++;
+ }
+}
+
+void putc_xy(int x, int y, char attr, char c)
+{
+ unsigned char *v = (unsigned char *)(uintptr_t)(0xB8000 + (80*y+x)*2 + active_page*(2*VPAGE_SIZE));
+ *v = c;
+ v++;
+ *v = attr;
+}
+
+int printf_xy(int x, int y, char attr, char *fmt, ...)
+{
+ char cbuf[200];
+ va_list parms;
+ int result;
+
+ va_start(parms, fmt);
+ result = vsprintf(cbuf, fmt, parms);
+ va_end(parms);
+
+ puts_xy(x, y, attr, cbuf);
+
+ return result;
+}
diff --git a/src/bsp/lk/platform/pc/debug.c b/src/bsp/lk/platform/pc/debug.c
new file mode 100644
index 0000000..e7d0e05
--- /dev/null
+++ b/src/bsp/lk/platform/pc/debug.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <stdarg.h>
+#include <reg.h>
+#include <stdio.h>
+#include <kernel/thread.h>
+#include <arch/x86.h>
+#include <lib/cbuf.h>
+#include <platform/interrupts.h>
+#include <platform/pc/memmap.h>
+#include <platform/console.h>
+#include <platform/keyboard.h>
+#include <platform/debug.h>
+
+static int uart_baud_rate = 115200;
+static int uart_io_port = 0x3f8;
+
+static cbuf_t uart_rx_buf;
+
+static enum handler_return uart_irq_handler(void *arg)
+{
+ unsigned char c;
+ bool resched = false;
+
+ while (inp(uart_io_port + 5) & (1<<0)) {
+ c = inp(uart_io_port + 0);
+ cbuf_write_char(&uart_rx_buf, c, false);
+ resched = true;
+ }
+
+ return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
+}
+
+void platform_init_uart(void)
+{
+ /* configure the uart */
+ int divisor = 115200 / uart_baud_rate;
+
+ /* get basic config done so that tx functions */
+ outp(uart_io_port + 3, 0x80); // set up to load divisor latch
+ outp(uart_io_port + 0, divisor & 0xff); // lsb
+ outp(uart_io_port + 1, divisor >> 8); // msb
+ outp(uart_io_port + 3, 3); // 8N1
+ outp(uart_io_port + 2, 0x07); // enable FIFO, clear, 14-byte threshold
+}
+
+void uart_init(void)
+{
+ /* finish uart init to get rx going */
+ cbuf_initialize(&uart_rx_buf, 16);
+
+ register_int_handler(0x24, uart_irq_handler, NULL);
+ unmask_interrupt(0x24);
+
+ outp(uart_io_port + 1, 0x1); // enable receive data available interrupt
+}
+
+void uart_putc(char c)
+{
+ while ((inp(uart_io_port + 5) & (1<<6)) == 0)
+ ;
+ outp(uart_io_port + 0, c);
+}
+
+int uart_getc(char *c, bool wait)
+{
+ return cbuf_read_char(&uart_rx_buf, c, wait);
+}
+
+void platform_dputc(char c)
+{
+ if (c == '\n')
+ platform_dputc('\r');
+#if WITH_CGA_CONSOLE
+ cputc(c);
+#else
+ uart_putc(c);
+#endif
+}
+
+int platform_dgetc(char *c, bool wait)
+{
+#if WITH_CGA_CONSOLE
+ int ret = platform_read_key(c);
+ //if (ret < 0)
+ // arch_idle();
+#else
+ int ret = uart_getc(c, wait);
+#endif
+
+ return ret;
+}
+
+void platform_halt(void)
+{
+ for (;;) {
+ x86_cli();
+ x86_hlt();
+ }
+}
+
diff --git a/src/bsp/lk/platform/pc/ide.c b/src/bsp/lk/platform/pc/ide.c
new file mode 100644
index 0000000..48ee309
--- /dev/null
+++ b/src/bsp/lk/platform/pc/ide.c
@@ -0,0 +1,908 @@
+/*
+ * Copyright (c) 2013 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <reg.h>
+#include <debug.h>
+#include <trace.h>
+#include <assert.h>
+#include <err.h>
+#include <malloc.h>
+#include <arch/x86.h>
+#include <sys/types.h>
+#include <platform/interrupts.h>
+#include <platform/ide.h>
+#include <platform/pc.h>
+#include <platform.h>
+#include <dev/pci.h>
+#include <dev/driver.h>
+#include <dev/class/block.h>
+#include <kernel/event.h>
+
+#define LOCAL_TRACE 1
+
+// status register bits
+#define IDE_CTRL_BSY 0x80
+#define IDE_DRV_RDY 0x40
+#define IDE_DRV_WRTFLT 0x20
+#define IDE_DRV_SKCOMP 0x10
+#define IDE_DRV_DRQ 0x08
+#define IDE_DRV_CORDAT 0x04
+#define IDE_DRV_IDX 0x02
+#define IDE_DRV_ERR 0x01
+
+// ATA commands
+#define ATA_NOP 0x00
+#define ATA_ATAPIRESET 0x08
+#define ATA_RECALIBRATE 0x10
+#define ATA_READMULT_RET 0x20
+#define ATA_READMULT 0x21
+#define ATA_READECC_RET 0x22
+#define ATA_READECC 0x23
+#define ATA_WRITEMULT_RET 0x30
+#define ATA_WRITEMULT 0x31
+#define ATA_WRITEECC_RET 0x32
+#define ATA_WRITEECC 0x33
+#define ATA_VERIFYMULT_RET 0x40
+#define ATA_VERIFYMULT 0x41
+#define ATA_FORMATTRACK 0x50
+#define ATA_SEEK 0x70
+#define ATA_DIAG 0x90
+#define ATA_INITPARAMS 0x91
+#define ATA_ATAPIPACKET 0xA0
+#define ATA_ATAPIIDENTIFY 0xA1
+#define ATA_ATAPISERVICE 0xA2
+#define ATA_READ_DMA 0xC8
+#define ATA_READ_DMA_EXT 0x25
+#define ATA_WRITE_DMA 0xCA
+#define ATA_WRITE_DMA_EXT 0x35
+#define ATA_GETDEVINFO 0xEC
+#define ATA_ATAPISETFEAT 0xEF
+
+// error codes
+#define IDE_NOERROR 0
+#define IDE_ADDRESSMARK 1
+#define IDE_CYLINDER0 2
+#define IDE_INVALIDCOMMAND 3
+#define IDE_MEDIAREQ 4
+#define IDE_SECTNOTFOUND 5
+#define IDE_MEDIACHANGED 6
+#define IDE_BADDATA 7
+#define IDE_BADSECTOR 8
+#define IDE_TIMEOUT 9
+#define IDE_DMAERROR 10
+
+enum {
+ IDE_REG_DATA = 0,
+ IDE_REG_ERROR = 1,
+ IDE_REG_PRECOMP = 1,
+ IDE_REG_SECTOR_COUNT = 2,
+ IDE_REG_SECTOR_NUM = 3,
+ IDE_REG_CYLINDER_LOW = 4,
+ IDE_REG_CYLINDER_HIGH = 5,
+ IDE_REG_DRIVE_HEAD = 6,
+ IDE_REG_STATUS = 7,
+ IDE_REG_COMMAND = 7,
+ IDE_REG_ALT_STATUS = 8,
+ IDE_REG_DEVICE_CONTROL = 8,
+
+ IDE_REG_NUM,
+};
+
+enum {
+ TYPE_NONE,
+ TYPE_UNKNOWN,
+ TYPE_FLOPPY,
+ TYPE_IDECDROM,
+ TYPE_SCSICDROM,
+ TYPE_IDEDISK,
+ TYPE_SCSIDISK
+};
+
+static const char *ide_type_str[] = {
+ "None",
+ "Unknown",
+ "Floppy",
+ "IDE CDROM",
+ "SCSI CDROM",
+ "IDE Disk",
+ "SCSI Disk",
+};
+
+static const char *ide_error_str[] = {
+ "Unknown error",
+ "Address mark not found",
+ "Cylinder 0 not found",
+ "Command aborted - invalid command",
+ "Media change requested",
+ "ID or target sector not found",
+ "Media changed",
+ "Uncorrectable data error",
+ "Bad sector detected",
+ "Command timed out",
+ "DMA error"
+};
+
+struct ide_driver_state {
+ int irq;
+ const uint16_t *regs;
+
+ event_t completion;
+
+ int type[2];
+ struct {
+ int sectors;
+ int sector_size;
+ } drive[2];
+};
+
+static const uint16_t ide_device_regs[][IDE_REG_NUM] = {
+ { 0x01F0, 0x01F1, 0x01F2, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, 0x03F6 },
+ { 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177, 0x0376 },
+};
+
+static const int ide_device_irqs[] = {
+ INT_IDE0,
+ INT_IDE1,
+};
+
+static status_t ide_init(struct device *dev);
+
+static enum handler_return ide_irq_handler(void *arg);
+
+static status_t ide_init(struct device *dev);
+static ssize_t ide_get_block_size(struct device *dev);
+static ssize_t ide_get_block_count(struct device *dev);
+static ssize_t ide_write(struct device *dev, off_t offset, const void *buf, size_t count);
+static ssize_t ide_read(struct device *dev, off_t offset, void *buf, size_t count);
+
+static struct block_ops the_ops = {
+ .std = {
+ .init = ide_init,
+ },
+ .get_block_size = ide_get_block_size,
+ .get_block_count = ide_get_block_count,
+ .write = ide_write,
+ .read = ide_read,
+};
+
+DRIVER_EXPORT(ide, &the_ops.std);
+
+static uint8_t ide_read_reg8(struct device *dev, int index);
+static uint16_t ide_read_reg16(struct device *dev, int index);
+static uint32_t ide_read_reg32(struct device *dev, int index);
+
+static void ide_write_reg8(struct device *dev, int index, uint8_t value);
+static void ide_write_reg16(struct device *dev, int index, uint16_t value);
+static void ide_write_reg32(struct device *dev, int index, uint32_t value);
+
+static void ide_read_reg8_array(struct device *dev, int index, void *buf, size_t count);
+static void ide_read_reg16_array(struct device *dev, int index, void *buf, size_t count);
+static void ide_read_reg32_array(struct device *dev, int index, void *buf, size_t count);
+
+static void ide_write_reg8_array(struct device *dev, int index, const void *buf, size_t count);
+static void ide_write_reg16_array(struct device *dev, int index, const void *buf, size_t count);
+static void ide_write_reg32_array(struct device *dev, int index, const void *buf, size_t count);
+
+static void ide_device_select(struct device *dev, int index);
+static void ide_device_reset(struct device *dev);
+static void ide_delay_400ns(struct device *dev);
+static int ide_poll_status(struct device *dev, uint8_t on_mask, uint8_t off_mask);
+static int ide_eval_error(struct device *dev);
+static void ide_detect_drives(struct device *dev);
+static int ide_wait_for_completion(struct device *dev);
+static int ide_detect_ata(struct device *dev, int index);
+static void ide_lba_setup(struct device *dev, uint32_t addr, int index);
+
+static status_t ide_init(struct device *dev)
+{
+ pci_location_t loc;
+ pci_config_t pci_config;
+ status_t res = NO_ERROR;
+ uint32_t i;
+ int err;
+
+ if (!dev)
+ return ERR_INVALID_ARGS;
+
+ if (!dev->config)
+ return ERR_NOT_CONFIGURED;
+
+ __UNUSED const struct platform_ide_config *config = dev->config;
+
+ err = pci_find_pci_class_code(&loc, 0x010180, 0);
+ if (err != _PCI_SUCCESSFUL) {
+ LTRACEF("Failed to find IDE device\n");
+ res = ERR_NOT_FOUND;
+ }
+
+ LTRACEF("Found IDE device at %02x:%02x\n", loc.bus, loc.dev_fn);
+
+ for (i=0; i < sizeof(pci_config) / sizeof(uint32_t); i++) {
+ uint32_t reg = sizeof(uint32_t) * i;
+
+ err = pci_read_config_word(&loc, reg, ((uint32_t *) &pci_config) + i);
+ if (err != _PCI_SUCCESSFUL) {
+ LTRACEF("Failed to read config reg %d: 0x%02x\n", reg, err);
+ res = ERR_NOT_CONFIGURED;
+ goto done;
+ }
+ }
+
+ for (i=0; i < 6; i++) {
+ LTRACEF("BAR[%d]: 0x%08x\n", i, pci_config.base_addresses[i]);
+ }
+
+ struct ide_driver_state *state = malloc(sizeof(struct ide_driver_state));
+ if (!state) {
+ res = ERR_NO_MEMORY;
+ goto done;
+ }
+ dev->state = state;
+
+ /* TODO: select io regs and irq based on device index */
+ state->irq = ide_device_irqs[0];
+ state->regs = ide_device_regs[0];
+ state->type[0] = state->type[1] = TYPE_NONE;
+
+ event_init(&state->completion, false, EVENT_FLAG_AUTOUNSIGNAL);
+
+ register_int_handler(state->irq, ide_irq_handler, dev);
+ unmask_interrupt(state->irq);
+
+ /* enable interrupts */
+ ide_write_reg8(dev, IDE_REG_DEVICE_CONTROL, 0);
+
+ /* detect drives */
+ ide_detect_drives(dev);
+
+done:
+ return res;
+}
+
+static enum handler_return ide_irq_handler(void *arg)
+{
+ struct device *dev = arg;
+ struct ide_driver_state *state = dev->state;
+ uint8_t val;
+
+ val = ide_read_reg8(dev, IDE_REG_STATUS);
+
+ if ((val & IDE_DRV_ERR) == 0) {
+ event_signal(&state->completion, false);
+
+ return INT_RESCHEDULE;
+ } else {
+ return INT_NO_RESCHEDULE;
+ }
+}
+
+static ssize_t ide_get_block_size(struct device *dev)
+{
+ DEBUG_ASSERT(dev);
+ DEBUG_ASSERT(dev->state);
+
+ struct ide_driver_state *state = dev->state;
+ return state->drive[0].sector_size;
+}
+
+static ssize_t ide_get_block_count(struct device *dev)
+{
+ DEBUG_ASSERT(dev);
+ DEBUG_ASSERT(dev->state);
+
+ struct ide_driver_state *state = dev->state;
+ return state->drive[0].sectors;
+}
+
+static ssize_t ide_write(struct device *dev, off_t offset, const void *buf, size_t count)
+{
+ DEBUG_ASSERT(dev);
+ DEBUG_ASSERT(dev->state);
+
+ __UNUSED struct ide_driver_state *state = dev->state;
+
+ size_t sectors, do_sectors, i;
+ const uint16_t *ubuf = buf;
+ int index = 0; // hard code drive for now
+ ssize_t ret = 0;
+ int err;
+
+ ide_device_select(dev, index);
+ ide_delay_400ns(dev);
+
+ err = ide_poll_status(dev, 0, IDE_CTRL_BSY | IDE_DRV_DRQ);
+ if (err) {
+ LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]);
+ ret = ERR_GENERIC;
+ goto done;
+ }
+
+ sectors = count;
+
+ while (sectors > 0) {
+ do_sectors = sectors;
+
+ if (do_sectors > 256)
+ do_sectors = 256;
+
+ err = ide_poll_status(dev, 0, IDE_CTRL_BSY);
+ if (err) {
+ LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]);
+ ret = ERR_GENERIC;
+ goto done;
+ }
+
+ ide_lba_setup(dev, offset, index);
+
+ if (do_sectors == 256)
+ ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0);
+ else
+ ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, do_sectors);
+
+ err = ide_poll_status(dev, IDE_DRV_RDY, 0);
+ if (err) {
+ LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]);
+ ret = ERR_GENERIC;
+ goto done;
+ }
+
+ ide_write_reg8(dev, IDE_REG_COMMAND, ATA_WRITEMULT_RET);
+ ide_delay_400ns(dev);
+
+ for (i=0; i < do_sectors; i++) {
+ err = ide_poll_status(dev, IDE_DRV_DRQ, 0);
+ if (err) {
+ LTRACEF("Error while waiting for drive: %s\n", ide_error_str[err]);
+ ret = ERR_GENERIC;
+ goto done;
+ }
+
+ ide_write_reg16_array(dev, IDE_REG_DATA, ubuf, 256);
+
+ ubuf += 256;
+ }
+
+ err = ide_wait_for_completion(dev);
+ if (err) {
+ LTRACEF("Error waiting for completion: %s\n", ide_error_str[err]);
+ ret = ERR_TIMED_OUT;
+ goto done;
+ }
+
+ sectors -= do_sectors;
+ offset += do_sectors;
+ }
+
+ ret = count;
+
+done:
+ return ret;
+}
+
+static ssize_t ide_read(struct device *dev, off_t offset, void *buf, size_t count)
+{
+ DEBUG_ASSERT(dev);
+ DEBUG_ASSERT(dev->state);
+
+ __UNUSED struct ide_driver_state *state = dev->state;
+
+ size_t sectors, do_sectors, i;
+ uint16_t *ubuf = buf;
+ int index = 0; // hard code drive for now
+ ssize_t ret = 0;
+ int err;
+
+ ide_device_select(dev, index);
+ ide_delay_400ns(dev);
+
+ err = ide_poll_status(dev, 0, IDE_CTRL_BSY | IDE_DRV_DRQ);
+ if (err) {
+ LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]);
+ ret = ERR_GENERIC;
+ goto done;
+ }
+
+ sectors = count;
+
+ while (sectors > 0) {
+ do_sectors = sectors;
+
+ if (do_sectors > 256)
+ do_sectors = 256;
+
+ err = ide_poll_status(dev, 0, IDE_CTRL_BSY);
+ if (err) {
+ LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]);
+ ret = ERR_GENERIC;
+ goto done;
+ }
+
+ ide_lba_setup(dev, offset, index);
+
+ if (do_sectors == 256)
+ ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0);
+ else
+ ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, do_sectors);
+
+ err = ide_poll_status(dev, IDE_DRV_RDY, 0);
+ if (err) {
+ LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]);
+ ret = ERR_GENERIC;
+ goto done;
+ }
+
+ ide_write_reg8(dev, IDE_REG_COMMAND, ATA_READMULT_RET);
+ ide_delay_400ns(dev);
+
+ for (i=0; i < do_sectors; i++) {
+ err = ide_poll_status(dev, IDE_DRV_DRQ, 0);
+ if (err) {
+ LTRACEF("Error while waiting for drive: %s\n", ide_error_str[err]);
+ ret = ERR_GENERIC;
+ goto done;
+ }
+
+ ide_read_reg16_array(dev, IDE_REG_DATA, ubuf, 256);
+
+ ubuf += 256;
+ }
+
+ err = ide_wait_for_completion(dev);
+ if (err) {
+ LTRACEF("Error waiting for completion: %s\n", ide_error_str[err]);
+ ret = ERR_TIMED_OUT;
+ goto done;
+ }
+
+ sectors -= do_sectors;
+ offset += do_sectors;
+ }
+
+ ret = count;
+
+done:
+ return ret;
+}
+
+static uint8_t ide_read_reg8(struct device *dev, int index)
+{
+ DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
+
+ struct ide_driver_state *state = dev->state;
+
+ return inp(state->regs[index]);
+}
+
+static uint16_t ide_read_reg16(struct device *dev, int index)
+{
+ DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
+
+ struct ide_driver_state *state = dev->state;
+
+ return inpw(state->regs[index]);
+}
+
+static uint32_t ide_read_reg32(struct device *dev, int index)
+{
+ DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
+
+ struct ide_driver_state *state = dev->state;
+
+ return inpd(state->regs[index]);
+}
+
+static void ide_read_reg8_array(struct device *dev, int index, void *buf, size_t count)
+{
+ DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
+
+ struct ide_driver_state *state = dev->state;
+
+ inprep(state->regs[index], (uint8_t *) buf, count);
+}
+
+static void ide_read_reg16_array(struct device *dev, int index, void *buf, size_t count)
+{
+ DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
+
+ struct ide_driver_state *state = dev->state;
+
+ inpwrep(state->regs[index], (uint16_t *) buf, count);
+}
+
+static void ide_read_reg32_array(struct device *dev, int index, void *buf, size_t count)
+{
+ DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
+
+ struct ide_driver_state *state = dev->state;
+
+ inpdrep(state->regs[index], (uint32_t *) buf, count);
+}
+
+static void ide_write_reg8_array(struct device *dev, int index, const void *buf, size_t count)
+{
+ DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
+
+ struct ide_driver_state *state = dev->state;
+
+ outprep(state->regs[index], (uint8_t *) buf, count);
+}
+
+static void ide_write_reg16_array(struct device *dev, int index, const void *buf, size_t count)
+{
+ DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
+
+ struct ide_driver_state *state = dev->state;
+
+ outpwrep(state->regs[index], (uint16_t *) buf, count);
+}
+
+static void ide_write_reg32_array(struct device *dev, int index, const void *buf, size_t count)
+{
+ DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
+
+ struct ide_driver_state *state = dev->state;
+
+ outpdrep(state->regs[index], (uint32_t *) buf, count);
+}
+
+static void ide_write_reg8(struct device *dev, int index, uint8_t value)
+{
+ DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
+
+ struct ide_driver_state *state = dev->state;
+
+ outp(state->regs[index], value);
+}
+
+static void ide_write_reg16(struct device *dev, int index, uint16_t value)
+{
+ DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
+
+ struct ide_driver_state *state = dev->state;
+
+ outpw(state->regs[index], value);
+}
+
+static void ide_write_reg32(struct device *dev, int index, uint32_t value)
+{
+ DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
+
+ struct ide_driver_state *state = dev->state;
+
+ outpd(state->regs[index], value);
+}
+
+static void ide_device_select(struct device *dev, int index)
+{
+ ide_write_reg8(dev, IDE_REG_DRIVE_HEAD, (index & 1) << 4);
+}
+
+static void ide_delay_400ns(struct device *dev)
+{
+ ide_read_reg8(dev, IDE_REG_ALT_STATUS);
+ ide_read_reg8(dev, IDE_REG_ALT_STATUS);
+ ide_read_reg8(dev, IDE_REG_ALT_STATUS);
+ ide_read_reg8(dev, IDE_REG_ALT_STATUS);
+}
+
+static void ide_device_reset(struct device *dev)
+{
+ struct ide_driver_state *state = dev->state;
+
+ lk_time_t start;
+ uint8_t sect_cnt, sect_num;
+ int err;
+
+ ide_device_select(dev, 0);
+ ide_delay_400ns(dev);
+
+ // set bit 2 for at least 4.8us
+ ide_write_reg8(dev, IDE_REG_DEVICE_CONTROL, 1<<2);
+
+ // delay 5us
+ spin(5);
+
+ ide_write_reg8(dev, IDE_REG_DEVICE_CONTROL, 0x00);
+
+ err = ide_poll_status(dev, 0, IDE_CTRL_BSY);
+ if (err) {
+ LTRACEF("Failed while waiting for controller to be ready: %s\n", ide_error_str[err]);
+ return;
+ }
+
+ // make sure the slave is ready if present
+ if (state->type[1] != TYPE_NONE) {
+ ide_device_select(dev, 1);
+ ide_delay_400ns(dev);
+
+ start = current_time();
+
+ do {
+ sect_cnt = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT);
+ sect_num = ide_read_reg8(dev, IDE_REG_SECTOR_NUM);
+
+ if (sect_cnt == 1 && sect_num == 1) {
+ err = ide_poll_status(dev, 0, IDE_CTRL_BSY);
+ if (err) {
+ LTRACEF("Failed while waiting for slave ready: %s\n", ide_error_str[err]);
+ return;
+ }
+
+ break;
+ }
+ } while (TIME_LTE(current_time(), start + 20000));
+
+ err = ide_read_reg8(dev, IDE_REG_ALT_STATUS);
+ if (err & IDE_DRV_ERR) {
+ err = ide_eval_error(dev);
+ LTRACEF("Failed while resetting controller: %s\n", ide_error_str[err]);
+ return;
+ }
+ }
+}
+
+static int ide_eval_error(struct device *dev)
+{
+ int err = 0;
+ uint8_t data = 0;
+
+ data = ide_read_reg8(dev, IDE_REG_ERROR);
+
+ if (data & 0x01) {
+ err = IDE_ADDRESSMARK;
+ } else if (data & 0x02) {
+ err = IDE_CYLINDER0;
+ } else if (data & 0x04) {
+ err = IDE_INVALIDCOMMAND;
+ } else if (data & 0x08) {
+ err = IDE_MEDIAREQ;
+ } else if (data & 0x10) {
+ err = IDE_SECTNOTFOUND;
+ } else if (data & 0x20) {
+ err = IDE_MEDIACHANGED;
+ } else if (data & 0x40) {
+ err = IDE_BADDATA;
+ } else if (data & 0x80) {
+ err = IDE_BADSECTOR;
+ } else {
+ err = IDE_NOERROR;
+ }
+
+ return err;
+}
+
+static int ide_poll_status(struct device *dev, uint8_t on_mask, uint8_t off_mask)
+{
+ int err;
+ uint8_t value;
+ lk_time_t start = current_time();
+
+ do {
+ value = ide_read_reg8(dev, IDE_REG_ALT_STATUS);
+
+ if (value & IDE_DRV_ERR) {
+ err = ide_eval_error(dev);
+ LTRACEF("Error while polling status: %s\n", ide_error_str[err]);
+ return err;
+ }
+
+ if ((value & on_mask) == on_mask && (value & off_mask) == 0)
+ return IDE_NOERROR;
+ } while (TIME_LTE(current_time(), start + 20000));
+
+ return IDE_TIMEOUT;
+}
+
+static void ide_detect_drives(struct device *dev)
+{
+ struct ide_driver_state *state = dev->state;
+ uint8_t sc = 0, sn = 0, st = 0, cl = 0, ch = 0;
+
+ ide_device_select(dev, 0);
+ ide_delay_400ns(dev);
+ ide_delay_400ns(dev);
+
+ ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0x55);
+ ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0xaa);
+ ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0xaa);
+ ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0x55);
+ ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0x55);
+ ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0xaa);
+
+ sc = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT);
+ sn = ide_read_reg8(dev, IDE_REG_SECTOR_NUM);
+
+ if (sc == 0x55 && sn == 0xaa) {
+ state->type[0] = TYPE_UNKNOWN;
+ }
+
+ // check for device 1
+ ide_device_select(dev, 1);
+ ide_delay_400ns(dev);
+
+ ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0x55);
+ ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0xaa);
+ ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0xaa);
+ ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0x55);
+ ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0x55);
+ ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0xaa);
+
+ sc = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT);
+ sn = ide_read_reg8(dev, IDE_REG_SECTOR_NUM);
+
+ if (sc == 0x55 && sn == 0xaa) {
+ state->type[1] = TYPE_UNKNOWN;
+ }
+
+ // now the drives present should be known
+ // soft reset now
+ ide_device_select(dev, 0);
+ ide_delay_400ns(dev);
+ ide_device_reset(dev);
+
+ ide_device_select(dev, 0);
+ ide_delay_400ns(dev);
+
+ sc = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT);
+ sn = ide_read_reg8(dev, IDE_REG_SECTOR_NUM);
+ if (sc == 0x01 && sn == 0x01) {
+ state->type[0] = TYPE_UNKNOWN;
+
+ st = ide_read_reg8(dev, IDE_REG_STATUS);
+ cl = ide_read_reg8(dev, IDE_REG_CYLINDER_LOW);
+ ch = ide_read_reg8(dev, IDE_REG_CYLINDER_HIGH);
+
+ // PATAPI or SATAPI respectively
+ if ((cl == 0x14 && ch == 0xeb) || (cl == 0x69 && ch == 0x96)) {
+ state->type[0] = TYPE_IDECDROM;
+ } else if (st != 0 && ((cl == 0x00 && ch == 0x00) || (cl == 0x3c && ch == 0xc3))) {
+ state->type[0] = TYPE_IDEDISK;
+ }
+ }
+
+ ide_device_select(dev, 1);
+ ide_delay_400ns(dev);
+
+ sc = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT);
+ sn = ide_read_reg8(dev, IDE_REG_SECTOR_NUM);
+ if (sc == 0x01 && sn == 0x01) {
+ state->type[1] = TYPE_UNKNOWN;
+
+ st = ide_read_reg8(dev, IDE_REG_STATUS);
+ cl = ide_read_reg8(dev, IDE_REG_CYLINDER_LOW);
+ ch = ide_read_reg8(dev, IDE_REG_CYLINDER_HIGH);
+
+ // PATAPI or SATAPI respectively
+ if ((cl == 0x14 && ch == 0xeb) || (cl == 0x69 && ch == 0x96)) {
+ state->type[1] = TYPE_IDECDROM;
+ } else if (st != 0 && ((cl == 0x00 && ch == 0x00) || (cl == 0x3c && ch == 0xc3))) {
+ state->type[1] = TYPE_IDEDISK;
+ }
+ }
+
+ LTRACEF("Detected drive 0: %s\n", ide_type_str[state->type[0]]);
+ LTRACEF("Detected drive 1: %s\n", ide_type_str[state->type[1]]);
+
+ switch (state->type[0]) {
+ case TYPE_IDEDISK:
+ ide_detect_ata(dev, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ switch (state->type[1]) {
+ case TYPE_IDEDISK:
+ ide_detect_ata(dev, 1);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int ide_wait_for_completion(struct device *dev)
+{
+ struct ide_driver_state *state = dev->state;
+ status_t err;
+
+ err = event_wait_timeout(&state->completion, 20000);
+ if (err)
+ return IDE_TIMEOUT;
+
+ return IDE_NOERROR;
+}
+
+static status_t ide_detect_ata(struct device *dev, int index)
+{
+ struct ide_driver_state *state = dev->state;
+ status_t res = NO_ERROR;
+ uint8_t *info = NULL;
+ int err;
+
+ ide_device_select(dev, index);
+ ide_delay_400ns(dev);
+
+ err = ide_poll_status(dev, 0, IDE_CTRL_BSY | IDE_DRV_DRQ);
+ if (err) {
+ LTRACEF("Error while detecting drive %d: %s\n", index, ide_error_str[err]);
+ res = ERR_TIMED_OUT;
+ goto error;
+ }
+
+ ide_device_select(dev, index);
+ ide_delay_400ns(dev);
+
+ err = ide_poll_status(dev, 0, IDE_CTRL_BSY | IDE_DRV_DRQ);
+ if (err) {
+ LTRACEF("Error while detecting drive %d: %s\n", index, ide_error_str[err]);
+ res = ERR_TIMED_OUT;
+ goto error;
+ }
+
+ // try to wait for the selected drive to be ready, but don't quit if not
+ // since CD-ROMs don't seem to respond to this when they're masters
+ ide_poll_status(dev, IDE_DRV_RDY, 0);
+
+ // send the "identify device" command
+ ide_write_reg8(dev, IDE_REG_COMMAND, ATA_GETDEVINFO);
+ ide_delay_400ns(dev);
+
+ err = ide_wait_for_completion(dev);
+ if (err) {
+ LTRACEF("Error while waiting for command: %s\n", ide_error_str[err]);
+ res = ERR_TIMED_OUT;
+ goto error;
+ }
+
+ info = malloc(512);
+ if (!info) {
+ res = ERR_NO_MEMORY;
+ goto error;
+ }
+
+ LTRACEF("Found ATA hard disk on channel %d!\n", index);
+
+ ide_read_reg16_array(dev, IDE_REG_DATA, info, 256);
+
+ state->drive[index].sectors = *((uint32_t *) (info + 120));
+ state->drive[index].sector_size = 512;
+
+ LTRACEF("Disk supports %u sectors for a total of %u bytes\n", state->drive[index].sectors,
+ state->drive[index].sectors * 512);
+
+error:
+ free(info);
+ return res;
+}
+
+static void ide_lba_setup(struct device *dev, uint32_t addr, int drive)
+{
+ ide_write_reg8(dev, IDE_REG_DRIVE_HEAD, 0xe0 | ((drive & 0x00000001) << 4) | ((addr >> 24) & 0xf));
+ ide_write_reg8(dev, IDE_REG_CYLINDER_LOW, (addr >> 8) & 0xff);
+ ide_write_reg8(dev, IDE_REG_CYLINDER_HIGH, (addr >> 16) & 0xff);
+ ide_write_reg8(dev, IDE_REG_SECTOR_NUM, addr & 0xff);
+ ide_write_reg8(dev, IDE_REG_PRECOMP, 0xff);
+}
+
diff --git a/src/bsp/lk/platform/pc/include/pcnet.h b/src/bsp/lk/platform/pc/include/pcnet.h
new file mode 100644
index 0000000..40f08e3
--- /dev/null
+++ b/src/bsp/lk/platform/pc/include/pcnet.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2013 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PLATFORM_PC_PCNET_H
+#define __PLATFORM_PC_PCNET_H
+
+#include <compiler.h>
+#include <stdint.h>
+
+#define REG_APROM 0x00
+#define REG_RDP 0x10
+#define REG_RAP 0x14
+#define REG_RESET 0x18
+#define REG_BDP 0x1c
+
+#define CSR0_INIT 0x0001
+#define CSR0_STRT 0x0002
+#define CSR0_STOP 0x0004
+#define CSR0_TDMD 0x0008
+#define CSR0_TXON 0x0010
+#define CSR0_RXON 0x0020
+#define CSR0_IENA 0x0040
+#define CSR0_INTR 0x0080
+#define CSR0_IDON 0x0100
+#define CSR0_TINT 0x0200
+#define CSR0_RINT 0x0400
+#define CSR0_MERR 0x0800
+#define CSR0_MISS 0x1000
+#define CSR0_CERR 0x2000
+#define CSR0_BABL 0x4000
+#define CSR0_ERR 0x8000
+
+#define CSR4_DMAPLUS 0x4000
+
+#define DESC_SIZE (4*sizeof(uint32_t))
+
+struct init_block_32 {
+ uint16_t mode;
+
+ uint16_t reserved_0 : 4;
+ uint16_t rlen : 4;
+ uint16_t reserved_1 : 4;
+ uint16_t tlen : 4;
+
+ uint8_t padr[6];
+
+ uint16_t reserved_2;
+
+ uint64_t ladr;
+ uint32_t rdra;
+ uint32_t tdra;
+} __PACKED;
+
+struct td_style3 {
+ uint32_t trc : 4;
+ uint32_t reserved_1 : 8;
+ uint32_t tdr : 14;
+ uint32_t rtry : 1;
+ uint32_t lcar : 1;
+ uint32_t lcol : 1;
+ uint32_t exdef : 1;
+ uint32_t uflo : 1;
+ uint32_t buff : 1;
+
+ uint32_t bcnt : 12;
+ uint32_t ones : 4;
+ uint32_t reserved_0 : 7;
+ uint32_t bpe : 1;
+ uint32_t enp : 1;
+ uint32_t stp : 1;
+ uint32_t def : 1;
+ uint32_t one : 1;
+ uint32_t more_ltinit : 1;
+ uint32_t add_no_fcs : 1;
+ uint32_t err : 1;
+ uint32_t own : 1;
+
+ uint32_t tbadr;
+
+ uint32_t reserved_2;
+} __PACKED;
+
+struct rd_style3 {
+ uint16_t mcnt : 12;
+ uint16_t zeros : 4;
+
+ uint8_t rpc;
+ uint8_t rcc;
+
+ uint32_t bcnt : 12;
+ uint32_t ones : 4;
+ uint32_t reserved_0 : 4;
+ uint32_t bam : 1;
+ uint32_t lafm : 1;
+ uint32_t pam : 1;
+ uint32_t bpe : 1;
+ uint32_t enp : 1;
+ uint32_t stp : 1;
+ uint32_t buff : 1;
+ uint32_t crc : 1;
+ uint32_t oflo : 1;
+ uint32_t fram : 1;
+ uint32_t err : 1;
+ uint32_t own : 1;
+
+ uint32_t rbadr;
+
+ uint32_t reserved_1;
+} __PACKED;
+
+#endif
+
diff --git a/src/bsp/lk/platform/pc/include/platform/console.h b/src/bsp/lk/platform/pc/include/platform/console.h
new file mode 100644
index 0000000..c7870a5
--- /dev/null
+++ b/src/bsp/lk/platform/pc/include/platform/console.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PLATFORM_CONSOLE_H
+#define __PLATFORM_CONSOLE_H
+
+#include <compiler.h>
+
+__BEGIN_CDECLS
+
+void platform_init_console(void);
+
+void set_visual_page(int page);
+void set_active_page(int page);
+
+int get_visual_page(void);
+int get_active_page(void);
+
+void place(int x,int y);
+void cursor(int start, int end);
+
+void _clear(char c, char attr, int x1, int y1, int x2, int y2);
+void clear(void);
+
+void _scroll(char attr, int x1, int y1, int x2, int y2);
+void scroll(void);
+
+void curr_save(void);
+void curr_restore(void);
+
+void cputc(char c);
+void cputs(char *s);
+
+void window(int x1, int y1, int x2, int y2);
+
+void putc_xy(int x, int y, char attr, char c);
+void puts_xy(int x, int y, char attr, char *s);
+
+int printf_xy(int x, int y, char attr, char *fmt, ...) __PRINTFLIKE(4, 5);
+
+#define CURSOR_BLOCK() cursor(0, 15);
+#define CURSOR_OFF() cursor(16, 16);
+#define CURSOR_STD() cursor(14, 15);
+
+/* text colors */
+#define BLACK 0
+#define BLUE 1
+#define GREEN 2
+#define CYAN 3
+#define RED 4
+#define MAGENTA 5
+#define BROWN 6
+#define LIGHTGRAY 7
+#define DARKGRAY 8
+#define LIGHTBLUE 9
+#define LIGHTGREEN 10
+#define LIGHTCYAN 11
+#define LIGHTRED 12
+#define LIGHTMAGENTA 13
+#define YELLOW 14
+#define WHITE 15
+
+__END_CDECLS
+
+#endif
+
diff --git a/src/bsp/lk/platform/pc/include/platform/ide.h b/src/bsp/lk/platform/pc/include/platform/ide.h
new file mode 100644
index 0000000..4dd8e25
--- /dev/null
+++ b/src/bsp/lk/platform/pc/include/platform/ide.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2013 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __PLATFORM_IDE_H
+#define __PLATFORM_IDE_H
+
+struct platform_ide_config {
+};
+
+#endif
+
+
diff --git a/src/bsp/lk/platform/pc/include/platform/keyboard.h b/src/bsp/lk/platform/pc/include/platform/keyboard.h
new file mode 100644
index 0000000..5464995
--- /dev/null
+++ b/src/bsp/lk/platform/pc/include/platform/keyboard.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PLATFORM_KEYBOARD_H
+#define __PLATFORM_KEYBOARD_H
+
+void platform_init_keyboard(void);
+
+int platform_read_key(char *c);
+
+#endif
diff --git a/src/bsp/lk/platform/pc/include/platform/multiboot.h b/src/bsp/lk/platform/pc/include/platform/multiboot.h
new file mode 100644
index 0000000..8b61faa
--- /dev/null
+++ b/src/bsp/lk/platform/pc/include/platform/multiboot.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PLATFORM_MULTIBOOT_H
+#define __PLATFORM_MULTIBOOT_H
+
+#include <sys/types.h>
+
+/* magic number for multiboot header */
+#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
+
+/* flags for multiboot header */
+#ifdef __ELF__
+#define MULTIBOOT_HEADER_FLAGS 0x00000003
+#else
+#define MULTIBOOT_HEADER_FLAGS 0x00010003
+#endif
+
+/* magic number passed by multiboot-compliant boot loaders */
+#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
+
+#ifndef ASSEMBLY
+
+/* multiboot header */
+typedef struct multiboot_header {
+ uint32_t magic;
+ uint32_t flags;
+ uint32_t checksum;
+ uint32_t header_addr;
+ uint32_t load_addr;
+ uint32_t load_end_addr;
+ uint32_t bss_end_addr;
+ uint32_t entry_addr;
+} multiboot_header_t;
+
+/* symbol table for a.out */
+typedef struct aout_symbol_table {
+ uint32_t tabsize;
+ uint32_t strsize;
+ uint32_t addr;
+ uint32_t reserved;
+} aout_symbol_table_t;
+
+/* section header table for ELF */
+typedef struct elf_section_header_table {
+ uint32_t num;
+ uint32_t size;
+ uint32_t addr;
+ uint32_t shndx;
+} elf_section_header_table_t;
+
+/* multiboot info */
+typedef struct multiboot_info {
+ uint32_t flags;
+ uint32_t mem_lower;
+ uint32_t mem_upper;
+ uint32_t boot_device;
+ uint32_t cmdline;
+ uint32_t mods_count;
+ uint32_t mods_addr;
+ union {
+ aout_symbol_table_t aout_sym;
+ elf_section_header_table_t elf_sec;
+ } u;
+ uint32_t mmap_length;
+ uint32_t mmap_addr;
+} multiboot_info_t;
+
+enum {
+ MB_INFO_MEM_SIZE = 0x001,
+ MB_INFO_BOOT_DEV = 0x002,
+ MB_INFO_CMD_LINE = 0x004,
+ MB_INFO_MODS = 0x008,
+ MB_INFO_SYMS = 0x010,
+ MB_INFO_MMAP = 0x020,
+ MB_INFO_DRIVES = 0x040,
+ MB_INFO_CONFIG = 0x080,
+ MB_INFO_BOOT_LOADER = 0x100,
+ MB_INFO_APM_TABLE = 0x200,
+ MB_INFO_VBE = 0x400,
+};
+
+/* module structure */
+typedef struct module {
+ uint32_t mod_start;
+ uint32_t mod_end;
+ uint32_t string;
+ uint32_t reserved;
+} module_t;
+
+/* memory map - be careful that the offset 0 is base_addr_low without size */
+typedef struct memory_map {
+ uint32_t size;
+ uint32_t base_addr_low;
+ uint32_t base_addr_high;
+ uint32_t length_low;
+ uint32_t length_high;
+ uint32_t type;
+} memory_map_t;
+
+/* memory map entry types */
+enum {
+ MB_MMAP_TYPE_AVAILABLE = 0x01,
+ MB_MMAP_TYPE_RESERVED = 0x02,
+ MB_MMAP_TYPE_ACPI_RECLAIM = 0x03,
+ MB_MMAP_TYPE_ACPI_NVS = 0x04,
+};
+
+#endif
+
+#endif
diff --git a/src/bsp/lk/platform/pc/include/platform/pc.h b/src/bsp/lk/platform/pc/include/platform/pc.h
new file mode 100644
index 0000000..9f8b812
--- /dev/null
+++ b/src/bsp/lk/platform/pc/include/platform/pc.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ * Copyright (c) 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PLATFORM_PC_H
+#define __PLATFORM_PC_H
+
+#include <platform/pc/memmap.h>
+#include <platform/pc/iomap.h>
+
+/* NOTE: keep arch/x86/crt0.S in sync with these definitions */
+
+/* interrupts */
+#define INT_VECTORS 0x31
+
+/* defined interrupts */
+#define INT_BASE 0x20
+#define INT_PIT 0x20
+#define INT_KEYBOARD 0x21
+#define INT_PIC2 0x22
+
+#define INT_BASE2 0x28
+#define INT_CMOSRTC 0x28
+#define INT_PS2MOUSE 0x2c
+#define INT_IDE0 0x2e
+#define INT_IDE1 0x2f
+
+/* exceptions */
+#define INT_DIVIDE_0 0x00
+#define INT_DEBUG_EX 0x01
+#define INT_INVALID_OP 0x06
+#define INT_DEV_NA_EX 0x07
+#define INT_MF 0x10
+#define INT_XM 0x13
+
+/* faults */
+#define INT_STACK_FAULT 0x0c
+#define INT_GP_FAULT 0x0d
+#define INT_PAGE_FAULT 0x0e
+
+/* APIC vectors */
+#define INT_APIC_TIMER 0x22
+
+#define INT_SYSCALL 0x30
+
+/* PIC remap bases */
+#define PIC1_BASE 0x20
+#define PIC2_BASE 0x28
+
+#endif
+
diff --git a/src/bsp/lk/platform/pc/include/platform/pc/iomap.h b/src/bsp/lk/platform/pc/include/platform/pc/iomap.h
new file mode 100644
index 0000000..26c808b
--- /dev/null
+++ b/src/bsp/lk/platform/pc/include/platform/pc/iomap.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __IOMAP_H
+#define __IOMAP_H
+
+/* i8253/i8254 programmable interval timer registers */
+#define I8253_CONTROL_REG 0x43
+#define I8253_DATA_REG 0x40
+
+/* i8042 keyboard controller registers */
+#define I8042_COMMAND_REG 0x64
+#define I8042_STATUS_REG 0x64
+#define I8042_DATA_REG 0x60
+
+/* CGA registers */
+#define CGA_INDEX_REG 0x3D4
+#define CGA_DATA_REG 0x3D5
+
+#endif
diff --git a/src/bsp/lk/platform/pc/include/platform/pc/memmap.h b/src/bsp/lk/platform/pc/include/platform/pc/memmap.h
new file mode 100644
index 0000000..e782116
--- /dev/null
+++ b/src/bsp/lk/platform/pc/include/platform/pc/memmap.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __MEMMAP_H
+#define __MEMMAP_H
+
+/* some helpful macros */
+#define REG(x) ((volatile unsigned int *)(x))
+#define REG_H(x) ((volatile unsigned short *)(x))
+#define REG_B(x) ((volatile unsigned char *)(x))
+
+/* TODO: put fixed memory address definitions here */
+
+#endif
diff --git a/src/bsp/lk/platform/pc/include/platform/pcnet.h b/src/bsp/lk/platform/pc/include/platform/pcnet.h
new file mode 100644
index 0000000..cb04234
--- /dev/null
+++ b/src/bsp/lk/platform/pc/include/platform/pcnet.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __PLATFORM_PCNET_H
+#define __PLATFORM_PCNET_H
+
+#include <stdint.h>
+
+struct platform_pcnet_config {
+ uint16_t vendor_id;
+ uint16_t device_id;
+ int index;
+};
+
+#endif
+
+
+
diff --git a/src/bsp/lk/platform/pc/include/platform/uart.h b/src/bsp/lk/platform/pc/include/platform/uart.h
new file mode 100644
index 0000000..60fd661
--- /dev/null
+++ b/src/bsp/lk/platform/pc/include/platform/uart.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __PLATFORM_UART_H
+#define __PLATFORM_UART_H
+
+struct platform_uart_config {
+ int baud_rate;
+ int io_port;
+ int irq;
+ int rx_buf_len;
+ int tx_buf_len;
+};
+
+#endif
+
diff --git a/src/bsp/lk/platform/pc/interrupts.c b/src/bsp/lk/platform/pc/interrupts.c
new file mode 100755
index 0000000..dc2869b
--- /dev/null
+++ b/src/bsp/lk/platform/pc/interrupts.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ * Copyright (c) 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <sys/types.h>
+#include <debug.h>
+#include <err.h>
+#include <reg.h>
+#include <kernel/thread.h>
+#include <platform/interrupts.h>
+#include <arch/ops.h>
+#include <arch/x86.h>
+#include <arch/fpu.h>
+#include <kernel/spinlock.h>
+#include "platform_p.h"
+#include <platform/pc.h>
+
+static spin_lock_t lock;
+
+void x86_gpf_handler(struct x86_iframe *frame);
+void x86_invop_handler(struct x86_iframe *frame);
+void x86_unhandled_exception(struct x86_iframe *frame);
+#ifdef ARCH_X86_64
+void x86_pfe_handler(struct x86_iframe *frame);
+#endif
+
+#define PIC1 0x20
+#define PIC2 0xA0
+
+#define ICW1 0x11
+#define ICW4 0x01
+
+struct int_handler_struct {
+ int_handler handler;
+ void *arg;
+};
+
+static struct int_handler_struct int_handler_table[INT_VECTORS];
+
+/*
+ * Cached IRQ mask (enabled/disabled)
+ */
+static uint8_t irqMask[2];
+
+/*
+ * init the PICs and remap them
+ */
+static void map(uint32_t pic1, uint32_t pic2)
+{
+ /* send ICW1 */
+ outp(PIC1, ICW1);
+ outp(PIC2, ICW1);
+
+ /* send ICW2 */
+ outp(PIC1 + 1, pic1); /* remap */
+ outp(PIC2 + 1, pic2); /* pics */
+
+ /* send ICW3 */
+ outp(PIC1 + 1, 4); /* IRQ2 -> connection to slave */
+ outp(PIC2 + 1, 2);
+
+ /* send ICW4 */
+ outp(PIC1 + 1, 5);
+ outp(PIC2 + 1, 1);
+
+ /* disable all IRQs */
+ outp(PIC1 + 1, 0xff);
+ outp(PIC2 + 1, 0xff);
+
+ irqMask[0] = 0xff;
+ irqMask[1] = 0xff;
+}
+
+static void enable(unsigned int vector, bool enable)
+{
+ if (vector >= PIC1_BASE && vector < PIC1_BASE + 8) {
+ vector -= PIC1_BASE;
+
+ uint8_t bit = 1 << vector;
+
+ if (enable && (irqMask[0] & bit)) {
+ irqMask[0] = inp(PIC1 + 1);
+ irqMask[0] &= ~bit;
+ outp(PIC1 + 1, irqMask[0]);
+ irqMask[0] = inp(PIC1 + 1);
+ } else if (!enable && !(irqMask[0] & bit)) {
+ irqMask[0] = inp(PIC1 + 1);
+ irqMask[0] |= bit;
+ outp(PIC1 + 1, irqMask[0]);
+ irqMask[0] = inp(PIC1 + 1);
+ }
+ } else if (vector >= PIC2_BASE && vector < PIC2_BASE + 8) {
+ vector -= PIC2_BASE;
+
+ uint8_t bit = 1 << vector;
+
+ if (enable && (irqMask[1] & bit)) {
+ irqMask[1] = inp(PIC2 + 1);
+ irqMask[1] &= ~bit;
+ outp(PIC2 + 1, irqMask[1]);
+ irqMask[1] = inp(PIC2 + 1);
+ } else if (!enable && !(irqMask[1] & bit)) {
+ irqMask[1] = inp(PIC2 + 1);
+ irqMask[1] |= bit;
+ outp(PIC2 + 1, irqMask[1]);
+ irqMask[1] = inp(PIC2 + 1);
+ }
+
+ bit = 1 << (INT_PIC2 - PIC1_BASE);
+
+ if (irqMask[1] != 0xff && (irqMask[0] & bit)) {
+ irqMask[0] = inp(PIC1 + 1);
+ irqMask[0] &= ~bit;
+ outp(PIC1 + 1, irqMask[0]);
+ irqMask[0] = inp(PIC1 + 1);
+ } else if (irqMask[1] == 0 && !(irqMask[0] & bit)) {
+ irqMask[0] = inp(PIC1 + 1);
+ irqMask[0] |= bit;
+ outp(PIC1 + 1, irqMask[0]);
+ irqMask[0] = inp(PIC1 + 1);
+ }
+ } else {
+ //dprintf(DEBUG, "Invalid PIC interrupt: %02x\n", vector);
+ }
+}
+
+void issueEOI(unsigned int vector)
+{
+ if (vector >= PIC1_BASE && vector <= PIC1_BASE + 7) {
+ outp(PIC1, 0x20);
+ } else if (vector >= PIC2_BASE && vector <= PIC2_BASE + 7) {
+ outp(PIC2, 0x20);
+ outp(PIC1, 0x20); // must issue both for the second PIC
+ }
+}
+
+void platform_init_interrupts(void)
+{
+ // rebase the PIC out of the way of processor exceptions
+ map(PIC1_BASE, PIC2_BASE);
+}
+
+status_t mask_interrupt(unsigned int vector)
+{
+ if (vector >= INT_VECTORS)
+ return ERR_INVALID_ARGS;
+
+// dprintf(DEBUG, "%s: vector %d\n", __PRETTY_FUNCTION__, vector);
+
+ spin_lock_saved_state_t state;
+ spin_lock_irqsave(&lock, state);
+
+ enable(vector, false);
+
+ spin_unlock_irqrestore(&lock, state);
+
+ return NO_ERROR;
+}
+
+
+void platform_mask_irqs(void)
+{
+ irqMask[0] = inp(PIC1 + 1);
+ irqMask[1] = inp(PIC2 + 1);
+
+ outp(PIC1 + 1, 0xff);
+ outp(PIC2 + 1, 0xff);
+
+ irqMask[0] = inp(PIC1 + 1);
+ irqMask[1] = inp(PIC2 + 1);
+}
+
+status_t unmask_interrupt(unsigned int vector)
+{
+ if (vector >= INT_VECTORS)
+ return ERR_INVALID_ARGS;
+
+// dprintf("%s: vector %d\n", __PRETTY_FUNCTION__, vector);
+
+ spin_lock_saved_state_t state;
+ spin_lock_irqsave(&lock, state);
+
+ enable(vector, true);
+
+ spin_unlock_irqrestore(&lock, state);
+
+ return NO_ERROR;
+}
+
+enum handler_return platform_irq(struct x86_iframe *frame)
+{
+ // get the current vector
+ unsigned int vector = frame->vector;
+
+ THREAD_STATS_INC(interrupts);
+
+ // deliver the interrupt
+ enum handler_return ret = INT_NO_RESCHEDULE;
+
+ switch (vector) {
+ case INT_GP_FAULT:
+ x86_gpf_handler(frame);
+ break;
+
+ case INT_INVALID_OP:
+ x86_invop_handler(frame);
+ break;
+ case INT_PAGE_FAULT:
+#ifdef ARCH_X86_64
+ x86_pfe_handler(frame);
+#endif
+ break;
+
+ case INT_DEV_NA_EX:
+#if X86_WITH_FPU
+ fpu_dev_na_handler();
+ break;
+#endif
+
+ case INT_MF:
+ case INT_XM:
+ case INT_DIVIDE_0:
+ case INT_DEBUG_EX:
+ case INT_STACK_FAULT:
+ case 3:
+ x86_unhandled_exception(frame);
+ break;
+
+ default:
+ if (int_handler_table[vector].handler)
+ ret = int_handler_table[vector].handler(int_handler_table[vector].arg);
+ }
+
+ // ack the interrupt
+ issueEOI(vector);
+
+ return ret;
+}
+
+void register_int_handler(unsigned int vector, int_handler handler, void *arg)
+{
+ if (vector >= INT_VECTORS)
+ panic("register_int_handler: vector out of range %d\n", vector);
+
+ spin_lock_saved_state_t state;
+ spin_lock_irqsave(&lock, state);
+
+ int_handler_table[vector].arg = arg;
+ int_handler_table[vector].handler = handler;
+
+ spin_unlock_irqrestore(&lock, state);
+}
+
+/* vim: set noexpandtab: */
+
diff --git a/src/bsp/lk/platform/pc/keyboard.c b/src/bsp/lk/platform/pc/keyboard.c
new file mode 100644
index 0000000..3478cf2
--- /dev/null
+++ b/src/bsp/lk/platform/pc/keyboard.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <sys/types.h>
+#include <err.h>
+#include <reg.h>
+#include <debug.h>
+#include <kernel/thread.h>
+#include <platform.h>
+#include <platform/interrupts.h>
+#include <platform/console.h>
+#include <platform/timer.h>
+#include <platform/pc.h>
+#include "platform_p.h"
+#include <arch/x86.h>
+#include <lib/cbuf.h>
+
+static inline int i8042_read_data(void)
+{
+ return inp(I8042_DATA_REG);
+}
+
+static inline int i8042_read_status(void)
+{
+ return inp(I8042_STATUS_REG);
+}
+
+static inline void i8042_write_data(int val)
+{
+ outp(I8042_DATA_REG, val);
+}
+
+static inline void i8042_write_command(int val)
+{
+ outp(I8042_COMMAND_REG, val);
+}
+
+/*
+ * timeout in milliseconds
+ */
+#define I8042_CTL_TIMEOUT 500
+
+/*
+ * status register bits
+ */
+#define I8042_STR_PARITY 0x80
+#define I8042_STR_TIMEOUT 0x40
+#define I8042_STR_AUXDATA 0x20
+#define I8042_STR_KEYLOCK 0x10
+#define I8042_STR_CMDDAT 0x08
+#define I8042_STR_MUXERR 0x04
+#define I8042_STR_IBF 0x02
+#define I8042_STR_OBF 0x01
+
+/*
+ * control register bits
+ */
+#define I8042_CTR_KBDINT 0x01
+#define I8042_CTR_AUXINT 0x02
+#define I8042_CTR_IGNKEYLK 0x08
+#define I8042_CTR_KBDDIS 0x10
+#define I8042_CTR_AUXDIS 0x20
+#define I8042_CTR_XLATE 0x40
+
+/*
+ * commands
+ */
+#define I8042_CMD_CTL_RCTR 0x0120
+#define I8042_CMD_CTL_WCTR 0x1060
+#define I8042_CMD_CTL_TEST 0x01aa
+
+#define I8042_CMD_KBD_DIS 0x00ad
+#define I8042_CMD_KBD_EN 0x00ae
+#define I8042_CMD_KBD_TEST 0x01ab
+#define I8042_CMD_KBD_MODE 0x01f0
+
+/*
+ * used for flushing buffers. the i8042 internal buffer shoudn't exceed this.
+ */
+#define I8042_BUFFER_LENGTH 32
+
+static inline void delay(lk_time_t delay)
+{
+ lk_time_t start = current_time();
+
+ while (start + delay > current_time());
+}
+
+/* scancodes we want to do something with that don't translate via table */
+#define SCANCODE_LSHIFT 0x2a
+#define SCANCODE_RSHIFT 0x36
+
+/* scancode translation tables */
+static const int KeyCodeSingleLower[] = {
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ -1, -1, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=','\b','\t', // 0
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']','\n', -1, 'a', 's', // 1
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`', -1,'\\', 'z', 'x', 'c', 'v', // 2
+ 'b', 'n', 'm', ',', '.', '/', -1, '*', -1, ' ', -1, -1, -1, -1, -1, -1, // 3
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7
+};
+
+static const int KeyCodeMultiLower[] = {
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 3
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7
+};
+
+static const int KeyCodeSingleUpper[] = {
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ -1, -1, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+','\b','\t', // 0
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}','\n', -1, 'A', 'S', // 1
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', -1, '|', 'Z', 'X', 'C', 'V', // 2
+ 'B', 'N', 'M', '<', '>', '?', -1, '*', -1, ' ', -1, -1, -1, -1, -1, -1, // 3
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7
+};
+
+static const int KeyCodeMultiUpper[] = {
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 3
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7
+};
+
+/*
+ * state key flags
+ */
+static bool key_lshift;
+static bool key_rshift;
+
+static cbuf_t key_buf;
+
+static void i8042_process_scode(uint8_t scode, unsigned int flags)
+{
+ static int lastCode = 0;
+ int keyCode;
+ uint8_t keyUpBit;
+
+ bool multi = lastCode == 0xe0;
+
+ // save the key up event bit
+ keyUpBit = scode & 0x80;
+ scode &= 0x7f;
+
+ if (scode == SCANCODE_LSHIFT) {
+ key_lshift = !keyUpBit;
+ }
+
+ if (scode == SCANCODE_RSHIFT) {
+ key_rshift = !keyUpBit;
+ }
+
+ if (key_lshift || key_rshift) {
+ keyCode = multi ? KeyCodeMultiUpper[scode] : KeyCodeSingleUpper[scode];
+ } else {
+ keyCode = multi ? KeyCodeMultiLower[scode] : KeyCodeSingleLower[scode];
+ }
+
+ /*printf_xy(71, 3, BLUE, "%02x%02x %c %c%c", multi ? lastCode : 0, scode,
+ keyCode != -1 ? (char) keyCode : ' ', key_lshift ? 'L' : ' ',
+ key_rshift ? 'R' : ' ');*/
+
+ if (keyCode != -1 && !keyUpBit) {
+ char c = (char) keyCode;
+ cbuf_write_char(&key_buf, c, false);
+ }
+
+ // update the last received code
+ lastCode = scode;
+}
+
+static int i8042_wait_read(void)
+{
+ int i = 0;
+ while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
+ delay(1);
+ i++;
+ }
+ return -(i == I8042_CTL_TIMEOUT);
+}
+
+static int i8042_wait_write(void)
+{
+ int i = 0;
+ while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
+ delay(1);
+ i++;
+ }
+ return -(i == I8042_CTL_TIMEOUT);
+}
+
+static int i8042_flush(void)
+{
+ unsigned char data __UNUSED;
+ int i = 0;
+
+ //enter_critical_section();
+
+ while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_LENGTH)) {
+ delay(1);
+ data = i8042_read_data();
+ }
+
+ //exit_critical_section();
+
+ return i;
+}
+
+static int i8042_command(uint8_t *param, int command)
+{
+ int retval = 0, i = 0;
+
+ //enter_critical_section();
+
+ retval = i8042_wait_write();
+ if (!retval) {
+ i8042_write_command(command & 0xff);
+ }
+
+ if (!retval) {
+ for (i = 0; i < ((command >> 12) & 0xf); i++) {
+ if ((retval = i8042_wait_write())) {
+ break;
+ }
+
+ i8042_write_data(param[i]);
+ }
+ }
+
+ if (!retval) {
+ for (i = 0; i < ((command & 0xf0) >> 8); i++) {
+ if ((retval = i8042_wait_read())) {
+ break;
+ }
+
+ if (i8042_read_status() & I8042_STR_AUXDATA) {
+ param[i] = ~i8042_read_data();
+ } else {
+ param[i] = i8042_read_data();
+ }
+ }
+ }
+
+ //exit_critical_section();
+
+ return retval;
+}
+
+static enum handler_return i8042_interrupt(void *arg)
+{
+ uint8_t str, data = 0;
+
+ //enter_critical_section();
+ str = i8042_read_status();
+ if (str & I8042_STR_OBF) {
+ data = i8042_read_data();
+ }
+ //exit_critical_section();
+
+ if (str & I8042_STR_OBF) {
+ i8042_process_scode(data,
+ ((str & I8042_STR_PARITY) ? I8042_STR_PARITY : 0) |
+ ((str & I8042_STR_TIMEOUT) ? I8042_STR_TIMEOUT : 0));
+ }
+
+ return INT_NO_RESCHEDULE;
+}
+
+int platform_read_key(char *c)
+{
+ ssize_t len;
+
+ len = cbuf_read_char(&key_buf, c, true);
+ return len;
+}
+
+void platform_init_keyboard(void)
+{
+ uint8_t ctr;
+
+ cbuf_initialize(&key_buf, 32);
+
+ i8042_flush();
+
+ if (i8042_command(&ctr, I8042_CMD_CTL_RCTR)) {
+ dprintf(SPEW, "Failed to read CTR while initializing i8042\n");
+ return;
+ }
+
+ // turn on translation
+ ctr |= I8042_CTR_XLATE;
+
+ // enable keyboard and keyboard irq
+ ctr &= ~I8042_CTR_KBDDIS;
+ ctr |= I8042_CTR_KBDINT;
+
+ if (i8042_command(&ctr, I8042_CMD_CTL_WCTR)) {
+ dprintf(SPEW, "Failed to write CTR while initializing i8042\n");
+ return;
+ }
+
+ register_int_handler(INT_KEYBOARD, &i8042_interrupt, NULL);
+ unmask_interrupt(INT_KEYBOARD);
+
+ i8042_interrupt(NULL);
+}
diff --git a/src/bsp/lk/platform/pc/pci.c b/src/bsp/lk/platform/pc/pci.c
new file mode 100644
index 0000000..87aac3b
--- /dev/null
+++ b/src/bsp/lk/platform/pc/pci.c
@@ -0,0 +1,590 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <kernel/thread.h>
+#include <kernel/spinlock.h>
+#include <arch/x86/descriptor.h>
+#include <dev/pci.h>
+
+static int last_bus = 0;
+static spin_lock_t lock;
+
+typedef struct {
+ uint16_t size;
+ void *offset;
+ uint16_t selector;
+} __PACKED irq_routing_options_t;
+
+static int pci_type1_detect(void);
+static int pci_bios_detect(void);
+
+int pci_get_last_bus(void)
+{
+ return last_bus;
+}
+
+/*
+ * pointers to installed PCI routines
+ */
+int (*g_pci_find_pci_device)(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index);
+int (*g_pci_find_pci_class_code)(pci_location_t *state, uint32_t class_code, uint16_t index);
+
+int (*g_pci_read_config_byte)(const pci_location_t *state, uint32_t reg, uint8_t *value);
+int (*g_pci_read_config_half)(const pci_location_t *state, uint32_t reg, uint16_t *value);
+int (*g_pci_read_config_word)(const pci_location_t *state, uint32_t reg, uint32_t *value);
+
+int (*g_pci_write_config_byte)(const pci_location_t *state, uint32_t reg, uint8_t value);
+int (*g_pci_write_config_half)(const pci_location_t *state, uint32_t reg, uint16_t value);
+int (*g_pci_write_config_word)(const pci_location_t *state, uint32_t reg, uint32_t value);
+
+int (*g_pci_get_irq_routing_options)(irq_routing_options_t *options, uint16_t *pci_irqs);
+int (*g_pci_set_irq_hw_int)(const pci_location_t *state, uint8_t int_pin, uint8_t irq);
+
+
+int pci_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index)
+{
+ spin_lock_saved_state_t irqstate;
+ spin_lock_irqsave(&lock, irqstate);
+
+ int res = g_pci_find_pci_device(state, device_id, vendor_id, index);
+
+ spin_unlock_irqrestore(&lock, irqstate);
+
+ return res;
+}
+
+int pci_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index)
+{
+ spin_lock_saved_state_t irqstate;
+ spin_lock_irqsave(&lock, irqstate);
+
+ int res = g_pci_find_pci_class_code(state, class_code, index);
+
+ spin_unlock_irqrestore(&lock, irqstate);
+
+ return res;
+}
+
+int pci_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value)
+{
+ spin_lock_saved_state_t irqstate;
+ spin_lock_irqsave(&lock, irqstate);
+
+ int res = g_pci_read_config_byte(state, reg, value);
+
+ spin_unlock_irqrestore(&lock, irqstate);
+
+ return res;
+}
+int pci_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value)
+{
+ spin_lock_saved_state_t irqstate;
+ spin_lock_irqsave(&lock, irqstate);
+
+ int res = g_pci_read_config_half(state, reg, value);
+
+ spin_unlock_irqrestore(&lock, irqstate);
+
+ return res;
+}
+
+int pci_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value)
+{
+ spin_lock_saved_state_t irqstate;
+ spin_lock_irqsave(&lock, irqstate);
+
+ int res = g_pci_read_config_word(state, reg, value);
+
+ spin_unlock_irqrestore(&lock, irqstate);
+
+ return res;
+}
+
+int pci_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value)
+{
+ spin_lock_saved_state_t irqstate;
+ spin_lock_irqsave(&lock, irqstate);
+
+ int res = g_pci_write_config_byte(state, reg, value);
+
+ spin_unlock_irqrestore(&lock, irqstate);
+
+ return res;
+}
+
+int pci_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value)
+{
+ spin_lock_saved_state_t irqstate;
+ spin_lock_irqsave(&lock, irqstate);
+
+ int res = g_pci_write_config_half(state, reg, value);
+
+ spin_unlock_irqrestore(&lock, irqstate);
+
+ return res;
+}
+
+int pci_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value)
+{
+ spin_lock_saved_state_t irqstate;
+ spin_lock_irqsave(&lock, irqstate);
+
+ int res = g_pci_write_config_word(state, reg, value);
+
+ spin_unlock_irqrestore(&lock, irqstate);
+
+ return res;
+}
+
+
+int pci_get_irq_routing_options(irq_routing_entry *entries, uint16_t *count, uint16_t *pci_irqs)
+{
+ irq_routing_options_t options;
+ options.size = sizeof(irq_routing_entry) **count;
+ options.selector = DATA_SELECTOR;
+ options.offset = entries;
+
+ spin_lock_saved_state_t irqstate;
+ spin_lock_irqsave(&lock, irqstate);
+
+ int res = g_pci_get_irq_routing_options(&options, pci_irqs);
+
+ spin_unlock_irqrestore(&lock, irqstate);
+
+ *count = options.size / sizeof(irq_routing_entry);
+
+ return res;
+}
+
+int pci_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq)
+{
+ spin_lock_saved_state_t irqstate;
+ spin_lock_irqsave(&lock, irqstate);
+
+ int res = g_pci_set_irq_hw_int(state, int_pin, irq);
+
+ spin_unlock_irqrestore(&lock, irqstate);
+
+ return res;
+}
+
+void pci_init(void)
+{
+ if (!pci_bios_detect()) {
+ dprintf(INFO, "pci bios functions installed\n");
+ dprintf(INFO, "last pci bus is %d\n", last_bus);
+ }
+}
+
+#define PCIBIOS_PRESENT 0xB101
+#define PCIBIOS_FIND_PCI_DEVICE 0xB102
+#define PCIBIOS_FIND_PCI_CLASS_CODE 0xB103
+#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xB106
+#define PCIBIOS_READ_CONFIG_BYTE 0xB108
+#define PCIBIOS_READ_CONFIG_WORD 0xB109
+#define PCIBIOS_READ_CONFIG_DWORD 0xB10A
+#define PCIBIOS_WRITE_CONFIG_BYTE 0xB10B
+#define PCIBIOS_WRITE_CONFIG_WORD 0xB10C
+#define PCIBIOS_WRITE_CONFIG_DWORD 0xB10D
+#define PCIBIOS_GET_IRQ_ROUTING_OPTIONS 0xB10E
+#define PCIBIOS_PCI_SET_IRQ_HW_INT 0xB10F
+
+#define PCIBIOS_SUCCESSFUL 0x00
+#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81
+#define PCIBIOS_BAD_VENDOR_ID 0x83
+#define PCIBIOS_DEVICE_NOT_FOUND 0x86
+#define PCIBIOS_BAD_REGISTER_NUMBER 0x87
+#define PCIBIOS_SET_FAILED 0x88
+#define PCIBIOS_BUFFER_TOO_SMALL 0x89
+
+/*
+ * far call structure used by BIOS32 routines
+ */
+static struct {
+ uint32_t offset;
+ uint16_t selector;
+} __PACKED bios32_entry;
+
+/*
+ * BIOS32 entry header
+ */
+typedef struct {
+ uint8_t magic[4]; // "_32_"
+ void * entry; // entry point
+ uint8_t revision;
+ uint8_t length;
+ uint8_t checksum;
+ uint8_t reserved[5];
+} __PACKED pci_bios_info;
+
+/*
+ * scan for pci bios
+ */
+static const char * pci_bios_magic = "_32_";
+static pci_bios_info *find_pci_bios_info(void)
+{
+ uint32_t *head = (uint32_t *) 0x000e0000;
+ int8_t sum, *b;
+ uint i;
+
+ while (head < (uint32_t *) 0x000ffff0) {
+ if (*head == *(uint32_t *) pci_bios_magic) {
+ // perform the checksum
+ sum = 0;
+ b = (int8_t *) head;
+ for (i=0; i < sizeof(pci_bios_info); i++) {
+ sum += b[i];
+ }
+
+ if (sum == 0) {
+ return (pci_bios_info *) head;
+ }
+ }
+
+ head += 4;
+ }
+
+ return NULL;
+}
+
+/*
+ * local BIOS32 PCI routines
+ */
+static int bios_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index)
+{
+ uint32_t bx, ret;
+
+ __asm__(
+ "lcall *(%%edi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=b"(bx),
+ "=a"(ret)
+ : "1"(PCIBIOS_FIND_PCI_DEVICE),
+ "c"(device_id),
+ "d"(vendor_id),
+ "S"(index),
+ "D"(&bios32_entry));
+
+ state->bus = bx >> 8;
+ state->dev_fn = bx & 0xFF;
+
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index)
+{
+ uint32_t bx, ret;
+
+ __asm__(
+ "lcall *(%%edi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=b"(bx),
+ "=a"(ret)
+ : "1"(PCIBIOS_FIND_PCI_CLASS_CODE),
+ "c"(class_code),
+ "S"(index),
+ "D"(&bios32_entry));
+
+ state->bus = bx >> 8;
+ state->dev_fn = bx & 0xFF;
+
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+
+static int bios_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value)
+{
+ uint32_t bx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=c"(*value),
+ "=a"(ret)
+ : "1"(PCIBIOS_READ_CONFIG_BYTE),
+ "b"(bx),
+ "D"(reg),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value)
+{
+ uint32_t bx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=c"(*value),
+ "=a"(ret)
+ : "1"(PCIBIOS_READ_CONFIG_WORD),
+ "b"(bx),
+ "D"(reg),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value)
+{
+ uint32_t bx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=c"(*value),
+ "=a"(ret)
+ : "1"(PCIBIOS_READ_CONFIG_DWORD),
+ "b"(bx),
+ "D"(reg),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value)
+{
+ uint32_t bx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=a"(ret)
+ : "0"(PCIBIOS_WRITE_CONFIG_BYTE),
+ "c"(value),
+ "b"(bx),
+ "D"(reg),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value)
+{
+ uint32_t bx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=a"(ret)
+ : "0"(PCIBIOS_WRITE_CONFIG_WORD),
+ "c"(value),
+ "b"(bx),
+ "D"(reg),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value)
+{
+ uint32_t bx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=a"(ret)
+ : "0"(PCIBIOS_WRITE_CONFIG_DWORD),
+ "c"(value),
+ "b"(bx),
+ "D"(reg),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_get_irq_routing_options(irq_routing_options_t *route_buffer, uint16_t *pciIrqs)
+{
+ uint32_t ret;
+
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=b"(*pciIrqs),
+ "=a"(ret)
+ : "1"(PCIBIOS_GET_IRQ_ROUTING_OPTIONS),
+ "b"(0),
+ "D"(route_buffer),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xff;
+}
+
+static int bios_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq)
+{
+ uint32_t bx, cx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ cx = irq;
+ cx <<= 8;
+ cx |= int_pin;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=a"(ret)
+ : "0"(PCIBIOS_PCI_SET_IRQ_HW_INT),
+ "b"(bx),
+ "c"(cx),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static const char *pci_signature = "PCI ";
+static int pci_bios_detect(void)
+{
+ pci_bios_info * pci = find_pci_bios_info();
+
+ if (pci != NULL) {
+ /*printf("Found PCI structure at %08x\n", (uint32_t) pci);
+
+ printf("\nPCI header info:\n");
+ printf("%c%c%c%c\n", pci->magic[0], pci->magic[1], pci->magic[2],
+ pci->magic[3]);
+ printf("%08x\n", (uint32_t) pci->entry);
+ printf("%d\n", pci->length * 16);
+ printf("%d\n", pci->checksum);*/
+
+ uint32_t adr, temp, len;
+ uint8_t err;
+
+ bios32_entry.offset = (uint32_t) pci->entry;
+ bios32_entry.selector = CODE_SELECTOR;
+
+ __asm__(
+ "lcall *(%%edi)"
+ : "=a"(err), /* AL out=status */
+ "=b"(adr), /* EBX out=code segment base adr */
+ "=c"(len), /* ECX out=code segment size */
+ "=d"(temp) /* EDX out=entry pt offset in code */
+ : "0"(0x49435024),/* EAX in=service="$PCI" */
+ "1"(0), /* EBX in=0=get service entry pt */
+ "D"(&bios32_entry)
+ );
+
+ if (err == 0x80) {
+ dprintf(INFO, "BIOS32 found, but no PCI BIOS\n");
+ return -1;
+ }
+
+ if (err != 0) {
+ dprintf(INFO, "BIOS32 call to locate PCI BIOS returned %x\n", err);
+ return -1;
+ }
+
+ bios32_entry.offset = adr + temp;
+
+ // now call PCI_BIOS_PRESENT to get version, hw mechanism, and last bus
+ uint16_t present, version, busses;
+ uint32_t signature;
+ __asm__(
+ "lcall *(%%edi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=a"(present),
+ "=b"(version),
+ "=c"(busses),
+ "=d"(signature)
+ : "0"(PCIBIOS_PRESENT),
+ "D"(&bios32_entry)
+ );
+
+ if (present & 0xff00) {
+ dprintf(INFO, "PCI_BIOS_PRESENT call returned ah=%02x\n", present >> 8);
+ return -1;
+ }
+
+ if (signature != *(uint32_t *)pci_signature) {
+ dprintf(INFO, "PCI_BIOS_PRESENT call returned edx=%08x\n", signature);
+ return -1;
+ }
+
+ //dprintf(DEBUG, "busses=%04x\n", busses);
+ last_bus = busses & 0xff;
+
+ g_pci_find_pci_device = bios_find_pci_device;
+ g_pci_find_pci_class_code = bios_find_pci_class_code;
+
+ g_pci_read_config_word = bios_read_config_word;
+ g_pci_read_config_half = bios_read_config_half;
+ g_pci_read_config_byte = bios_read_config_byte;
+
+ g_pci_write_config_word = bios_write_config_word;
+ g_pci_write_config_half = bios_write_config_half;
+ g_pci_write_config_byte = bios_write_config_byte;
+
+ g_pci_get_irq_routing_options = bios_get_irq_routing_options;
+ g_pci_set_irq_hw_int = bios_set_irq_hw_int;
+
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/src/bsp/lk/platform/pc/platform.c b/src/bsp/lk/platform/pc/platform.c
new file mode 100644
index 0000000..d97190c
--- /dev/null
+++ b/src/bsp/lk/platform/pc/platform.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ * Copyright (c) 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <err.h>
+#include <trace.h>
+#include <arch/x86/mmu.h>
+#include <platform.h>
+#include "platform_p.h"
+#include <platform/pc.h>
+#include <platform/multiboot.h>
+#include <platform/console.h>
+#include <platform/keyboard.h>
+#include <dev/pci.h>
+#include <dev/uart.h>
+#include <arch/x86.h>
+#include <arch/mmu.h>
+#include <malloc.h>
+#include <string.h>
+#include <assert.h>
+#include <kernel/vm.h>
+
+extern multiboot_info_t *_multiboot_info;
+
+#define DEFAULT_MEMEND (16*1024*1024)
+
+#ifdef WITH_KERNEL_VM
+extern int _end;
+static uintptr_t _heap_end = (uintptr_t)DEFAULT_MEMEND;
+#else
+extern uintptr_t _heap_end;
+#endif
+extern uint64_t __code_start;
+extern uint64_t __code_end;
+extern uint64_t __rodata_start;
+extern uint64_t __rodata_end;
+extern uint64_t __data_start;
+extern uint64_t __data_end;
+extern uint64_t __bss_start;
+extern uint64_t __bss_end;
+extern void pci_init(void);
+extern void arch_mmu_init(void);
+
+/* Address width including virtual/physical address*/
+uint8_t g_vaddr_width = 0;
+uint8_t g_paddr_width = 0;
+
+/* Kernel global CR3 */
+map_addr_t g_CR3 = 0;
+
+void platform_init_mmu_mappings(void)
+{
+ struct map_range range;
+ arch_flags_t access;
+ map_addr_t *init_table, phy_init_table;
+ uint32_t addr_width;
+
+ /* getting the address width from CPUID instr */
+ /* Bits 07-00: Physical Address width info */
+ /* Bits 15-08: Linear Address width info */
+ addr_width = x86_get_address_width();
+ g_paddr_width = (uint8_t)(addr_width & 0xFF);
+ g_vaddr_width = (uint8_t)((addr_width >> 8) & 0xFF);
+
+ /* Creating the First page in the page table hirerachy */
+ /* Can be pml4, pdpt or pdt based on x86_64, x86 PAE mode & x86 non-PAE mode respectively */
+ init_table = memalign(PAGE_SIZE, PAGE_SIZE);
+ ASSERT(init_table);
+ memset(init_table, 0, PAGE_SIZE);
+
+ phy_init_table = (map_addr_t)X86_VIRT_TO_PHYS(init_table);
+
+ /* kernel code section mapping */
+ access = ARCH_MMU_FLAG_PERM_RO;
+ range.start_vaddr = range.start_paddr = (map_addr_t) &__code_start;
+ range.size = ((map_addr_t)&__code_end) - ((map_addr_t)&__code_start);
+ x86_mmu_map_range(phy_init_table, &range, access);
+
+ /* kernel data section mapping */
+ access = 0;
+#if defined(ARCH_X86_64) || defined(PAE_MODE_ENABLED)
+ access |= ARCH_MMU_FLAG_PERM_NO_EXECUTE;
+#endif
+ range.start_vaddr = range.start_paddr = (map_addr_t) &__data_start;
+ range.size = ((map_addr_t)&__data_end) - ((map_addr_t)&__data_start);
+ x86_mmu_map_range(phy_init_table, &range, access);
+
+ /* kernel rodata section mapping */
+ access = ARCH_MMU_FLAG_PERM_RO;
+#if defined(ARCH_X86_64) || defined(PAE_MODE_ENABLED)
+ access |= ARCH_MMU_FLAG_PERM_NO_EXECUTE;
+#endif
+ range.start_vaddr = range.start_paddr = (map_addr_t) &__rodata_start;
+ range.size = ((map_addr_t)&__rodata_end) - ((map_addr_t)&__rodata_start);
+ x86_mmu_map_range(phy_init_table, &range, access);
+
+ /* kernel bss section and kernel heap mappings */
+ access = 0;
+#ifdef ARCH_X86_64
+ access |= ARCH_MMU_FLAG_PERM_NO_EXECUTE;
+#endif
+ range.start_vaddr = range.start_paddr = (map_addr_t) &__bss_start;
+ range.size = ((map_addr_t)_heap_end) - ((map_addr_t)&__bss_start);
+ x86_mmu_map_range(phy_init_table, &range, access);
+
+ /* Mapping for BIOS, devices */
+ access = 0;
+ range.start_vaddr = range.start_paddr = (map_addr_t) 0;
+ range.size = ((map_addr_t)&__code_start);
+ x86_mmu_map_range(phy_init_table, &range, access);
+
+ /* Moving to the new CR3 */
+ g_CR3 = (map_addr_t)phy_init_table;
+ x86_set_cr3((map_addr_t)phy_init_table);
+}
+
+#if WITH_KERNEL_VM
+struct mmu_initial_mapping mmu_initial_mappings[] = {
+ /* all of detected memory */
+ {
+ .phys = MEMBASE,
+ .virt = MEMBASE,
+ .size = DEFAULT_MEMEND - MEMBASE,
+ .flags = 0,
+ .name = "memory"
+ },
+
+ /* null entry to terminate the list */
+ { 0 }
+};
+
+/* set up the size of the identity map of physical ram to virtual at the base
+ * of the kernel to match what we detected in platform_init_multiboot_info()
+ */
+void initial_mapping_init(void)
+{
+ /* tweak the amount of physical memory map we have mapped
+ * in the mmu_initial_mappings table, which is used by the vm
+ * for reverse lookups of memory in the kernel area */
+ mmu_initial_mappings[0].size = _heap_end - mmu_initial_mappings[0].virt;
+}
+
+static pmm_arena_t mem_arena = {
+ .name = "memory",
+ .base = MEMBASE, /* start 2MB into memory */
+ .size = DEFAULT_MEMEND, /* default amount of memory in case we don't have multiboot */
+ .priority = 1,
+ .flags = PMM_ARENA_FLAG_KMAP
+};
+
+/* set up the size of the physical memory map based on the end of memory we detected in
+ * platform_init_multiboot_info()
+ */
+void mem_arena_init(void)
+{
+ uintptr_t mem_base = ((uintptr_t)MEMBASE);
+ uintptr_t mem_size = (uintptr_t)_heap_end - (uintptr_t)mem_base;
+
+ mem_arena.base = PAGE_ALIGN(mem_base);
+ mem_arena.size = PAGE_ALIGN(mem_size);
+}
+#endif
+
+void platform_init_multiboot_info(void)
+{
+ if (_multiboot_info) {
+ if (_multiboot_info->flags & MB_INFO_MEM_SIZE) {
+ _heap_end = _multiboot_info->mem_upper * 1024;
+ }
+
+ if (_multiboot_info->flags & MB_INFO_MMAP) {
+ memory_map_t *mmap = (memory_map_t *)(uintptr_t)(_multiboot_info->mmap_addr - 4);
+
+ for (uint i = 0; i < _multiboot_info->mmap_length / sizeof(memory_map_t); i++) {
+
+ if (mmap[i].type == MB_MMAP_TYPE_AVAILABLE && mmap[i].base_addr_low >= _heap_end) {
+ _heap_end = mmap[i].base_addr_low + mmap[i].length_low;
+ } else if (mmap[i].type != MB_MMAP_TYPE_AVAILABLE && mmap[i].base_addr_low >= _heap_end) {
+ /*
+ * break on first memory hole above default heap end for now.
+ * later we can add facilities for adding free chunks to the
+ * heap for each segregated memory region.
+ */
+ break;
+ }
+ }
+ }
+ }
+}
+
+void platform_early_init(void)
+{
+
+ platform_init_uart();
+
+ /* get the text console working */
+ platform_init_console();
+
+ /* initialize the interrupt controller */
+ platform_init_interrupts();
+
+ /* initialize the timer */
+ platform_init_timer();
+
+ /* look at multiboot to determine our memory size */
+ platform_init_multiboot_info();
+
+#ifdef WITH_KERNEL_VM
+ initial_mapping_init();
+ mem_arena_init();
+ pmm_add_arena(&mem_arena);
+#endif
+}
+
+void platform_init(void)
+{
+ uart_init();
+
+ platform_init_keyboard();
+#if defined(ARCH_X86)
+ pci_init();
+#endif
+
+ /* MMU init for x86 Archs done after the heap is setup */
+ // XXX move this into arch/
+ arch_mmu_init();
+ platform_init_mmu_mappings();
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/bsp/lk/platform/pc/platform_p.h b/src/bsp/lk/platform/pc/platform_p.h
new file mode 100644
index 0000000..07bbbb6
--- /dev/null
+++ b/src/bsp/lk/platform/pc/platform_p.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PLATFORM_P_H
+#define __PLATFORM_P_H
+
+void platform_init_interrupts(void);
+void platform_init_timer(void);
+void platform_init_uart(void);
+
+#endif
+
diff --git a/src/bsp/lk/platform/pc/rules.mk b/src/bsp/lk/platform/pc/rules.mk
new file mode 100644
index 0000000..24f9e5d
--- /dev/null
+++ b/src/bsp/lk/platform/pc/rules.mk
@@ -0,0 +1,40 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+CPU := generic
+
+MODULE_DEPS += \
+ lib/cbuf \
+
+ifeq ($(ARCH), x86)
+MODULE_SRCS += \
+ $(LOCAL_DIR)/interrupts.c \
+ $(LOCAL_DIR)/platform.c \
+ $(LOCAL_DIR)/timer.c \
+ $(LOCAL_DIR)/debug.c \
+ $(LOCAL_DIR)/console.c \
+ $(LOCAL_DIR)/keyboard.c \
+ $(LOCAL_DIR)/pci.c \
+ $(LOCAL_DIR)/ide.c \
+ $(LOCAL_DIR)/uart.c \
+
+else
+MODULE_SRCS += \
+ $(LOCAL_DIR)/interrupts.c \
+ $(LOCAL_DIR)/platform.c \
+ $(LOCAL_DIR)/timer.c \
+ $(LOCAL_DIR)/debug.c \
+ $(LOCAL_DIR)/console.c \
+ $(LOCAL_DIR)/keyboard.c \
+ $(LOCAL_DIR)/uart.c \
+
+endif
+
+LK_HEAP_IMPLEMENTATION ?= dlmalloc
+
+LINKER_SCRIPT += \
+ $(BUILDDIR)/kernel.ld
+
+include make/module.mk
+
diff --git a/src/bsp/lk/platform/pc/timer.c b/src/bsp/lk/platform/pc/timer.c
new file mode 100644
index 0000000..06f329b
--- /dev/null
+++ b/src/bsp/lk/platform/pc/timer.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <sys/types.h>
+#include <err.h>
+#include <reg.h>
+#include <debug.h>
+#include <kernel/thread.h>
+#include <kernel/spinlock.h>
+#include <platform.h>
+#include <platform/interrupts.h>
+#include <platform/console.h>
+#include <platform/timer.h>
+#include <platform/pc.h>
+#include "platform_p.h"
+#include <arch/x86.h>
+
+static platform_timer_callback t_callback;
+static void *callback_arg;
+static spin_lock_t lock;
+
+static uint64_t next_trigger_time;
+static uint64_t next_trigger_delta;
+static uint64_t ticks_per_ms;
+
+static uint64_t timer_delta_time;
+static volatile uint64_t timer_current_time;
+
+static uint16_t divisor;
+
+#define INTERNAL_FREQ 1193182ULL
+#define INTERNAL_FREQ_3X 3579546ULL
+
+/* Maximum amount of time that can be program on the timer to schedule the next
+ * interrupt, in miliseconds */
+#define MAX_TIMER_INTERVAL 55
+
+
+
+status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval)
+{
+ t_callback = callback;
+ callback_arg = arg;
+
+ next_trigger_delta = (uint64_t) interval << 32;
+ next_trigger_time = timer_current_time + next_trigger_delta;
+
+ return NO_ERROR;
+}
+
+lk_time_t current_time(void)
+{
+ lk_time_t time;
+
+ // XXX slight race
+ time = (lk_time_t) (timer_current_time >> 32);
+
+ return time;
+}
+
+lk_bigtime_t current_time_hires(void)
+{
+ lk_bigtime_t time;
+
+ // XXX slight race
+ time = (lk_bigtime_t) ((timer_current_time >> 22) * 1000) >> 10;
+
+ return time;
+}
+static enum handler_return os_timer_tick(void *arg)
+{
+ uint64_t delta;
+
+ timer_current_time += timer_delta_time;
+
+ lk_time_t time = current_time();
+ //lk_bigtime_t btime = current_time_hires();
+ //printf_xy(71, 0, WHITE, "%08u", (uint32_t) time);
+ //printf_xy(63, 1, WHITE, "%016llu", (uint64_t) btime);
+
+ if (t_callback && timer_current_time >= next_trigger_time) {
+ delta = timer_current_time - next_trigger_time;
+ next_trigger_time = timer_current_time + next_trigger_delta - delta;
+
+ return t_callback(callback_arg, time);
+ } else {
+ return INT_NO_RESCHEDULE;
+ }
+}
+
+static void set_pit_frequency(uint32_t frequency)
+{
+ uint32_t count, remainder;
+
+ /* figure out the correct divisor for the desired frequency */
+ if (frequency <= 18) {
+ count = 0xffff;
+ } else if (frequency >= INTERNAL_FREQ) {
+ count = 1;
+ } else {
+ count = INTERNAL_FREQ_3X / frequency;
+ remainder = INTERNAL_FREQ_3X % frequency;
+
+ if (remainder >= INTERNAL_FREQ_3X / 2) {
+ count += 1;
+ }
+
+ count /= 3;
+ remainder = count % 3;
+
+ if (remainder >= 1) {
+ count += 1;
+ }
+ }
+
+ divisor = count & 0xffff;
+
+ /*
+ * funky math that i don't feel like explaining. essentially 32.32 fixed
+ * point representation of the configured timer delta.
+ */
+ timer_delta_time = (3685982306ULL * count) >> 10;
+
+ //dprintf(DEBUG, "set_pit_frequency: dt=%016llx\n", timer_delta_time);
+ //dprintf(DEBUG, "set_pit_frequency: divisor=%04x\n", divisor);
+
+ /*
+ * setup the Programmable Interval Timer
+ * timer 0, mode 2, binary counter, LSB followed by MSB
+ */
+ outp(I8253_CONTROL_REG, 0x34);
+ outp(I8253_DATA_REG, divisor & 0xff); // LSB
+ outp(I8253_DATA_REG, divisor >> 8); // MSB
+}
+
+void platform_init_timer(void)
+{
+
+ timer_current_time = 0;
+ ticks_per_ms = INTERNAL_FREQ/1000;
+ set_pit_frequency(1000); // ~1ms granularity
+ register_int_handler(INT_PIT, &os_timer_tick, NULL);
+ unmask_interrupt(INT_PIT);
+}
+
+void platform_halt_timers(void)
+{
+ mask_interrupt(INT_PIT);
+}
+
+
+
+status_t platform_set_oneshot_timer(platform_timer_callback callback,
+ void *arg, lk_time_t interval)
+{
+
+ uint32_t count;
+
+ spin_lock_saved_state_t state;
+ spin_lock_irqsave(&lock, state);
+
+ t_callback = callback;
+ callback_arg = arg;
+
+
+ if (interval > MAX_TIMER_INTERVAL)
+ interval = MAX_TIMER_INTERVAL;
+ if (interval < 1) interval = 1;
+
+ count = ticks_per_ms * interval;
+
+ divisor = count & 0xffff;
+ timer_delta_time = (3685982306ULL * count) >> 10;
+ /* Program PIT in teh software strobe configuration, to send one pulse
+ * after the count reach 0 */
+ outp(I8253_CONTROL_REG, 0x38);
+ outp(I8253_DATA_REG, divisor & 0xff); // LSB
+ outp(I8253_DATA_REG, divisor >> 8); // MSB
+
+
+ unmask_interrupt(INT_PIT);
+ spin_unlock_irqrestore(&lock, state);
+
+ return NO_ERROR;
+}
+
+void platform_stop_timer(void)
+{
+ /* Enable interrupt mode that will stop the decreasing counter of the PIT */
+ outp(I8253_CONTROL_REG, 0x30);
+ return;
+}
+
+/* vim: set noexpandtab */
diff --git a/src/bsp/lk/platform/pc/uart.c b/src/bsp/lk/platform/pc/uart.c
new file mode 100644
index 0000000..be94bf6
--- /dev/null
+++ b/src/bsp/lk/platform/pc/uart.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2012 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dev/driver.h>
+#include <dev/class/uart.h>
+#include <debug.h>
+#include <assert.h>
+#include <malloc.h>
+#include <err.h>
+#include <lib/cbuf.h>
+#include <platform/uart.h>
+#include <arch/x86.h>
+#include <kernel/thread.h>
+#include <platform/interrupts.h>
+
+struct device_class uart_device_class = {
+ .name = "uart",
+};
+
+struct uart_driver_state {
+ struct cbuf rx_buf;
+ struct cbuf tx_buf;
+};
+
+static status_t uart_init(struct device *dev);
+
+static enum handler_return uart_irq_handler(void *arg);
+static int uart_write_thread(void *arg);
+
+static ssize_t uart_read(struct device *dev, void *buf, size_t len);
+static ssize_t uart_write(struct device *dev, const void *buf, size_t len);
+
+static struct uart_ops the_ops = {
+ .std = {
+ .device_class = &uart_device_class,
+ .init = uart_init,
+ },
+ .read = uart_read,
+ .write = uart_write,
+};
+
+DRIVER_EXPORT(uart, &the_ops.std);
+
+static status_t uart_init(struct device *dev)
+{
+ status_t res = NO_ERROR;
+
+ if (!dev)
+ return ERR_INVALID_ARGS;
+
+ if (!dev->config)
+ return ERR_NOT_CONFIGURED;
+
+ const struct platform_uart_config *config = dev->config;
+
+ struct uart_driver_state *state = malloc(sizeof(struct uart_driver_state));
+ if (!state) {
+ res = ERR_NO_MEMORY;
+ goto done;
+ }
+
+ dev->state = state;
+
+ /* set up the driver state */
+ cbuf_initialize(&state->rx_buf, config->rx_buf_len);
+ cbuf_initialize(&state->tx_buf, config->tx_buf_len);
+
+ /* configure the uart */
+ int divisor = 115200 / config->baud_rate;
+
+ outp(config->io_port + 3, 0x80); // set up to load divisor latch
+ outp(config->io_port + 0, divisor & 0xff); // lsb
+ outp(config->io_port + 1, divisor >> 8); // msb
+ outp(config->io_port + 3, 3); // 8N1
+ outp(config->io_port + 2, 0x07); // enable FIFO, clear, 14-byte threshold
+
+ register_int_handler(config->irq, uart_irq_handler, dev);
+ unmask_interrupt(config->irq);
+
+ //outp(config->io_port + 1, 0x3); // enable rx data available and tx holding empty interrupts
+ outp(config->io_port + 1, 0x1); // enable rx data available interrupts
+
+ thread_resume(thread_create("[uart writer]", uart_write_thread, dev, DEFAULT_PRIORITY,
+ DEFAULT_STACK_SIZE));
+
+done:
+ return res;
+}
+
+static enum handler_return uart_irq_handler(void *arg)
+{
+ bool resched = false;
+ struct device *dev = arg;
+
+ DEBUG_ASSERT(dev);
+ DEBUG_ASSERT(dev->config);
+ DEBUG_ASSERT(dev->state);
+
+ const struct platform_uart_config *config = dev->config;
+ struct uart_driver_state *state = dev->state;
+
+ while (inp(config->io_port + 5) & (1<<0)) {
+ char c = inp(config->io_port + 0);
+ cbuf_write(&state->rx_buf, &c, 1, false);
+ resched = true;
+ }
+
+ return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
+}
+
+static int uart_write_thread(void *arg)
+{
+ struct device *dev = arg;
+
+ DEBUG_ASSERT(dev);
+ DEBUG_ASSERT(dev->config);
+ DEBUG_ASSERT(dev->state);
+
+ const struct platform_uart_config *config = dev->config;
+ struct uart_driver_state *state = dev->state;
+
+ return 0;
+
+ while (true) {
+ char c = cbuf_read(&state->tx_buf, &c, 1, true);
+
+ while ((inp(config->io_port + 5) & (1<<6)) == 0)
+ ;
+
+ outp(config->io_port + 0, c);
+ }
+
+ return 0;
+}
+
+static ssize_t uart_read(struct device *dev, void *buf, size_t len)
+{
+ if (!dev || !buf)
+ return ERR_INVALID_ARGS;
+
+ DEBUG_ASSERT(dev->state);
+ struct uart_driver_state *state = dev->state;
+
+ return cbuf_read(&state->rx_buf, buf, len, true);
+}
+
+static ssize_t uart_write(struct device *dev, const void *buf, size_t len)
+{
+ if (!dev || !buf)
+ return ERR_INVALID_ARGS;
+
+ DEBUG_ASSERT(dev->state);
+ struct uart_driver_state *state = dev->state;
+
+ return cbuf_write(&state->tx_buf, buf, len, true);
+}
+