From: Jack Lange Date: Wed, 23 Apr 2008 20:56:50 +0000 (+0000) Subject: added pic device X-Git-Tag: working-cdboot-physical-but-not-qemu~11 X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=159356d2478ab200cda0a0aa726d8f1bfa4ffeeb added pic device --- diff --git a/palacios/build/Makefile b/palacios/build/Makefile index 416b0c7..4a28af3 100644 --- a/palacios/build/Makefile +++ b/palacios/build/Makefile @@ -1,6 +1,6 @@ # Makefile for GeekOS kernel, userspace, and tools # Copyright (c) 2004,2005 David H. Hovemeyer -# $Revision: 1.27 $ +# $Revision: 1.28 $ # This is free software. You are permitted to use, # redistribute, and modify it as specified in the file "COPYING". @@ -134,7 +134,7 @@ VMM_C_OBJS := $(VMM_C_SRCS:%.c=palacios/%.o) VMM_OBJS := $(VMM_C_OBJS) $(VMM_ASM_OBJS) -DEVICE_C_SRCS := nvram.c timer.c simple_pic.c +DEVICE_C_SRCS := nvram.c timer.c simple_pic.c 8259a.c DEVICE_C_OBJS := $(DEVICE_C_SRCS:%.c=devices/%.o) diff --git a/palacios/include/devices/8259a.h b/palacios/include/devices/8259a.h index 64fa889..23567d3 100644 --- a/palacios/include/devices/8259a.h +++ b/palacios/include/devices/8259a.h @@ -1,9 +1,10 @@ #ifndef __8259A_H #define __8259A_H +#include - +struct vm_device * create_pic(); #endif diff --git a/palacios/include/devices/simple_pic.h b/palacios/include/devices/simple_pic.h index 58a9080..bc651da 100644 --- a/palacios/include/devices/simple_pic.h +++ b/palacios/include/devices/simple_pic.h @@ -2,6 +2,6 @@ #define __SIMPLE_PIC_H #include -struct vm_device * create_pic(); +struct vm_device * create_simple_pic(); #endif diff --git a/palacios/src/devices/8259a.c b/palacios/src/devices/8259a.c index 60d6180..2e305e9 100644 --- a/palacios/src/devices/8259a.c +++ b/palacios/src/devices/8259a.c @@ -1,9 +1,464 @@ -#include +#include +#include +#include #include +typedef enum {RESET, ICW1, ICW2, ICW3, ICW4, READY} pic_state_t; + +static const uint_t MASTER_PORT1 = 0x20; +static const uint_t MASTER_PORT2 = 0x21; +static const uint_t SLAVE_PORT1 = 0xA0; +static const uint_t SLAVE_PORT2 = 0xA1; + +#define IS_OCW2(x) (((x & 0x18) >> 3) == 0x0) +#define IS_OCW3(x) (((x & 0x18) >> 3) == 0x1) + +struct icw1 { + uint_t ic4 : 1; // ICW4 has to be read + uint_t sngl : 1; // single (only one PIC) + uint_t adi : 1; // call address interval + uint_t ltim : 1; // level interrupt mode + uint_t one : 1; + uint_t rsvd : 3; +}; + + +struct icw2 { + uint_t rsvd : 3; + uint_t vector : 5; +}; + + +// Each bit that is set indicates that the IR input has a slave +struct icw3_master { + uint_t S0 : 1; + uint_t S1 : 1; + uint_t S2 : 1; + uint_t S3 : 1; + uint_t S4 : 1; + uint_t S5 : 1; + uint_t S6 : 1; + uint_t S7 : 1; +}; + +// The ID is the Slave device ID +struct icw3_slave { + uint_t id : 3; + uint_t zeroes : 5; +}; + +struct icw4 { + uint_t uPM : 1; // 1=x86 + uint_t AEOI : 1; // Automatic End of Interrupt + uint_t M_S : 1; // only if buffered 1=master,0=slave + uint_t BUF : 1; // buffered mode + uint_t SFNM : 1; // special fully nexted mode + uint_t zeroes : 3; +}; + + +struct ocw1 { + uint_t m0 : 1; + uint_t m1 : 1; + uint_t m2 : 1; + uint_t m3 : 1; + uint_t m4 : 1; + uint_t m5 : 1; + uint_t m6 : 1; + uint_t m7 : 1; +}; + +struct ocw2 { + uint_t level : 3; + uint_t cw_code : 2; // should be 00 + uint_t EOI : 1; + uint_t SL : 1; + uint_t R : 1; +}; + +struct ocw3 { + uint_t RIS : 1; + uint_t RR : 1; + uint_t P : 1; + uint_t cw_code : 2; // should be 01 + uint_t smm : 1; + uint_t esmm : 1; + uint_t zero2 : 1; +}; + + +struct pic_internal { + + + char master_irr; + char slave_irr; + + char master_isr; + char slave_isr; + + char master_icw1; + char master_icw2; + char master_icw3; + char master_icw4; + + + char slave_icw1; + char slave_icw2; + char slave_icw3; + char slave_icw4; + + + char master_imr; + char slave_imr; + char master_ocw2; + char master_ocw3; + char slave_ocw2; + char slave_ocw3; + + pic_state_t master_state; + pic_state_t slave_state; +}; + + + +static int pic_raise_intr(void * private_data, int irq, int error_code) { + struct pic_internal * state = (struct pic_internal*)private_data; + + if (irq == 2) { + irq = 9; + } + + if (irq <= 7) { + state->master_irr |= 0x1 << irq; + } else if ((irq > 7) && (irq < 16)) { + state->slave_irr |= 0x1 << (irq - 7); + } else { + return -1; + } + + return 0; +} + +static int pic_intr_pending(void * private_data) { + struct pic_internal * state = (struct pic_internal*)private_data; + + if ((state->master_irr & ~(state->master_imr)) || + (state->slave_irr & ~(state->slave_imr))) { + return 1; + } + + return 0; +} + +static int pic_get_intr_number(void * private_data) { + struct pic_internal * state = (struct pic_internal*)private_data; + int i; + + for (i = 0; i < 16; i++) { + if (i <= 7) { + if (((state->master_irr & ~(state->master_imr)) >> i) == 0x1) { + return i; + } + } else { + if (((state->slave_irr & ~(state->slave_imr)) >> i) == 0x1) { + return i; + } + } + } + + return 0; +} + + +static struct intr_ctrl_ops intr_ops = { + .intr_pending = pic_intr_pending, + .get_intr_number = pic_get_intr_number, + .raise_intr = pic_raise_intr +}; + + + + + + + +int read_master_port1(ushort_t port, void * dst, uint_t length, struct vm_device * dev) { + struct pic_internal * state = (struct pic_internal*)dev->private_data; + if (length != 1) { + //error + } + + if ((state->master_ocw3 & 0x3) == 0x2) { + *(char *)dst = state->master_irr; + } else if ((state->master_ocw3 & 0x3) == 0x3) { + *(char *)dst = state->master_isr; + } else { + *(char *)dst = 0; + } + + return 1; +} + +int read_master_port2(ushort_t port, void * dst, uint_t length, struct vm_device * dev) { + struct pic_internal * state = (struct pic_internal*)dev->private_data; + if (length != 1) { + // error + } + + *(char *)dst = state->master_imr; + + return 1; + +} + +int read_slave_port1(ushort_t port, void * dst, uint_t length, struct vm_device * dev) { + struct pic_internal * state = (struct pic_internal*)dev->private_data; + if (length != 1) { + // error + } + + if ((state->slave_ocw3 & 0x3) == 0x2) { + *(char*)dst = state->slave_irr; + } else if ((state->slave_ocw3 & 0x3) == 0x3) { + *(char *)dst = state->slave_isr; + } else { + *(char *)dst = 0; + } + + return 1; +} + +int read_slave_port2(ushort_t port, void * dst, uint_t length, struct vm_device * dev) { + struct pic_internal * state = (struct pic_internal*)dev->private_data; + if (length != 1) { + // error + } + + *(char *)dst = state->slave_imr; + + return 1; +} + + +int write_master_port1(ushort_t port, void * src, uint_t length, struct vm_device * dev) { + struct pic_internal * state = (struct pic_internal*)dev->private_data; + char cw = *(char *)src; + + if (length != 1) { + // error + } + + if (state->master_state == ICW1) { + state->master_icw1 = cw; + state->master_state = ICW2; + } else if (state->master_state == READY) { + if (IS_OCW2(cw)) { + state->master_ocw2 = cw; + } else if (IS_OCW3(cw)) { + state->master_ocw3 = cw; + } else { + // error + } + } else { + // error + } + + return 1; +} + +int write_master_port2(ushort_t port, void * src, uint_t length, struct vm_device * dev) { + struct pic_internal * state = (struct pic_internal*)dev->private_data; + char cw = *(char *)src; + + if (length != 1) { + //error + } + + if (state->master_state == ICW2) { + struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1); + + state->master_icw2 = cw; + + if (cw1->sngl == 0) { + state->master_state = ICW3; + } else if (cw1->ic4 == 1) { + state->master_state = ICW4; + } else { + state->master_state = READY; + } + + } else if (state->master_state == ICW3) { + struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1); + + state->master_icw3 = cw; + + if (cw1->ic4 == 1) { + state->master_state = ICW4; + } else { + state->master_state = READY; + } + + } else if (state->master_state == ICW4) { + state->master_icw4 = cw; + state->master_state = READY; + } else if (state->master_state == READY) { + state->master_imr = cw; + } else { + // error + } + + return 1; +} + +int write_slave_port1(ushort_t port, void * src, uint_t length, struct vm_device * dev) { + struct pic_internal * state = (struct pic_internal*)dev->private_data; + char cw = *(char *)src; + + if (length != 1) { + // error + } + + if (state->slave_state == ICW1) { + state->slave_icw1 = cw; + state->slave_state = ICW2; + } else if (state->slave_state == READY) { + if (IS_OCW2(cw)) { + state->slave_ocw2 = cw; + } else if (IS_OCW3(cw)) { + state->slave_ocw3 = cw; + } else { + // error + } + } else { + // error + } + + return 1; +} + +int write_slave_port2(ushort_t port, void * src, uint_t length, struct vm_device * dev) { + struct pic_internal * state = (struct pic_internal*)dev->private_data; + char cw = *(char *)src; + + if (length != 1) { + //error + } + + if (state->slave_state == ICW2) { + struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1); + + state->slave_icw2 = cw; + + if (cw1->sngl == 0) { + state->slave_state = ICW3; + } else if (cw1->ic4 == 1) { + state->slave_state = ICW4; + } else { + state->slave_state = READY; + } + + } else if (state->slave_state == ICW3) { + struct icw1 * cw1 = (struct icw1 *)&(state->master_icw1); + + state->slave_icw3 = cw; + + if (cw1->ic4 == 1) { + state->slave_state = ICW4; + } else { + state->slave_state = READY; + } + + } else if (state->slave_state == ICW4) { + state->slave_icw4 = cw; + state->slave_state = READY; + } else if (state->slave_state == READY) { + state->slave_imr = cw; + } else { + // error + } + + return 1; +} + + + + + + + + +int pic_init(struct vm_device * dev) { + struct pic_internal * state = (struct pic_internal*)dev->private_data; + + set_intr_controller(dev->vm, &intr_ops, state); + + state->master_irr = 0; + state->master_isr = 0; + state->master_icw1 = 0; + state->master_icw2 = 0; + state->master_icw3 = 0; + state->master_icw4 = 0; + state->master_imr = 0; + state->master_ocw2 = 0; + state->master_ocw3 = 0x2; + state->master_state = ICW1; + + + state->slave_irr = 0; + state->slave_isr = 0; + state->slave_icw1 = 0; + state->slave_icw2 = 0; + state->slave_icw3 = 0; + state->slave_icw4 = 0; + state->slave_imr = 0; + state->slave_ocw2 = 0; + state->slave_ocw3 = 0x2; + state->slave_state = ICW1; + + + dev_hook_io(dev, MASTER_PORT1, &read_master_port1, &write_master_port1); + dev_hook_io(dev, MASTER_PORT2, &read_master_port2, &write_master_port2); + dev_hook_io(dev, SLAVE_PORT1, &read_slave_port1, &write_slave_port1); + dev_hook_io(dev, SLAVE_PORT2, &read_slave_port2, &write_slave_port2); + + return 0; +} + + +int pic_deinit(struct vm_device * dev) { + dev_unhook_io(dev, MASTER_PORT1); + dev_unhook_io(dev, MASTER_PORT2); + dev_unhook_io(dev, SLAVE_PORT1); + dev_unhook_io(dev, SLAVE_PORT2); + + return 0; +} + + + + + + + +static struct vm_device_ops dev_ops = { + .init = pic_init, + .deinit = pic_deinit, + .reset = NULL, + .start = NULL, + .stop = NULL, +}; + + +struct vm_device * create_pic() { + struct pic_internal * state = NULL; + VMMMalloc(struct pic_internal *, state, sizeof(struct pic_internal)); + + struct vm_device *device = create_device("8259A", &dev_ops, state); + + return device; +} + + + -static const uint_t PIC1_PORT_1 0x20; -static const uint_t PIC1_PORT_2 0x21; -static const uint_t PIC2_PORT_1 0xA0; -static const uint_t PIC2_PORT_2 0xA1; diff --git a/palacios/src/devices/simple_pic.c b/palacios/src/devices/simple_pic.c index a4e25f5..c3539b7 100644 --- a/palacios/src/devices/simple_pic.c +++ b/palacios/src/devices/simple_pic.c @@ -9,13 +9,13 @@ struct pic_internal { }; -int pic_intr_pending(void * private_data) { +static int pic_intr_pending(void * private_data) { struct pic_internal * data = (struct pic_internal *)private_data; return (data->pending_irq > 0); } -int pic_raise_intr(void * private_data, int irq, int error_code) { +static int pic_raise_intr(void * private_data, int irq, int error_code) { struct pic_internal * data = (struct pic_internal *)private_data; data->pending_irq = irq; @@ -25,7 +25,7 @@ int pic_raise_intr(void * private_data, int irq, int error_code) { } -int pic_get_intr_number(void * private_data) { +static int pic_get_intr_number(void * private_data) { struct pic_internal * data = (struct pic_internal *)private_data; return data->pending_irq; @@ -67,7 +67,7 @@ static struct vm_device_ops dev_ops = { }; -struct vm_device * create_pic() { +struct vm_device * create_simple_pic() { struct pic_internal * state = NULL; VMMMalloc(struct pic_internal *, state, sizeof(struct pic_internal)); diff --git a/palacios/src/geekos/vm.c b/palacios/src/geekos/vm.c index 4375e43..2697333 100644 --- a/palacios/src/geekos/vm.c +++ b/palacios/src/geekos/vm.c @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -281,11 +282,12 @@ int RunVMM(struct Boot_Info * bootInfo) { hook_io_port(&(vm_info.io_map), 0x61, &IO_Read, &IO_Write, NULL); hook_io_port(&(vm_info.io_map), 0x05, &IO_Read, &IO_Write_to_Serial, NULL); - hook_io_port(&(vm_info.io_map), 0x20, &IO_Read, &IO_Write_to_Serial, NULL); - hook_io_port(&(vm_info.io_map), 0x21, &IO_Read, &IO_Write_to_Serial, NULL); - hook_io_port(&(vm_info.io_map), 0xa0, &IO_Read, &IO_Write_to_Serial, NULL); - hook_io_port(&(vm_info.io_map), 0xa1, &IO_Read, &IO_Write_to_Serial, NULL); - + /* + hook_io_port(&(vm_info.io_map), 0x20, &IO_Read, &IO_Write_to_Serial, NULL); + hook_io_port(&(vm_info.io_map), 0x21, &IO_Read, &IO_Write_to_Serial, NULL); + hook_io_port(&(vm_info.io_map), 0xa0, &IO_Read, &IO_Write_to_Serial, NULL); + hook_io_port(&(vm_info.io_map), 0xa1, &IO_Read, &IO_Write_to_Serial, NULL); + */ hook_io_port(&(vm_info.io_map), 0x400, &IO_Read, &IO_Write_to_Serial, NULL); hook_io_port(&(vm_info.io_map), 0x401, &IO_Read, &IO_Write_to_Serial, NULL); hook_io_port(&(vm_info.io_map), 0x402, &IO_Read, &IO_BOCHS_debug, NULL);