From d6d1bdfefafff50b7b6d15d218c0a188570be541 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 10 Jun 2017 21:26:24 +0200 Subject: some big renames into subdirs of aspects updated README removed size_t in sys/types.h and sys/types.h itself, size_t is in stddef.h --- src/hardware/interrupts.asm | 90 +++++++++++++++++++ src/hardware/interrupts.c | 215 ++++++++++++++++++++++++++++++++++++++++++++ src/hardware/interrupts.h | 103 +++++++++++++++++++++ src/hardware/pci.c | 187 ++++++++++++++++++++++++++++++++++++++ src/hardware/pci.h | 49 ++++++++++ src/hardware/port.asm | 49 ++++++++++ src/hardware/port.c | 17 ++++ src/hardware/port.h | 23 +++++ 8 files changed, 733 insertions(+) create mode 100644 src/hardware/interrupts.asm create mode 100644 src/hardware/interrupts.c create mode 100644 src/hardware/interrupts.h create mode 100644 src/hardware/pci.c create mode 100644 src/hardware/pci.h create mode 100644 src/hardware/port.asm create mode 100644 src/hardware/port.c create mode 100644 src/hardware/port.h (limited to 'src/hardware') diff --git a/src/hardware/interrupts.asm b/src/hardware/interrupts.asm new file mode 100644 index 0000000..155b2af --- /dev/null +++ b/src/hardware/interrupts.asm @@ -0,0 +1,90 @@ +[bits 32] + +global interrupts_enable +global interrupts_disable +global interrupts_load_idt +extern interrupts_handle_static_interrupt + +; void interrupts_enable( void ) +interrupts_enable: + push ebp + mov ebp, esp + sti + leave + ret + +; void interrupts_disable( void ) +interrupts_disable: + push ebp + mov ebp, esp + cli + leave + ret + +; void interrupts_load_idt( interrupt_descriptor_table_pointer_t *idt_pointer ) +interrupts_load_idt: + push ebp + mov ebp, esp + mov ecx, [ebp+8] + lidt [ecx] + leave + ret + +; the handler to ignore interrupts +global interrupts_ignore_request +interrupts_ignore_request: + iret + +; void interrupts_handle_request_0x00( ); +%macro exception_stub 1 +global interrupts_handle_exception_%1 +interrupts_handle_exception_%1: + mov [interrupt_no], byte %1 + jmp int_entry +%endmacro + +exception_stub 0x00 + +; IRQs and exceptions would normally collidate, that's why the +; hardware interrupts must be transposed by an offset +IRQ_BASE equ 0x20 + +%macro irq_stub 1 +global interrupts_handle_irq_%1 +interrupts_handle_irq_%1: + mov [interrupt_no], byte IRQ_BASE + %1 + jmp int_entry +%endmacro + +irq_stub 0x00 +irq_stub 0x01 +irq_stub 0x0C + +int_entry: + ; safe state of interrupted code + pusha + push ds + push es + push fs + push gs + + ; call the static C handler with the correct interrupt number + ; uint32_t interrupts_handle_interrupt( uint8_t interrupt_no, uint32_t esp ); + push esp + mov eax, [interrupt_no] + push eax + call interrupts_handle_static_interrupt + ;add esp, 8 + mov esp, eax + + ; restore state + pop gs + pop fs + pop es + pop ds + popa + + iret + +interrupt_no: + db 0 diff --git a/src/hardware/interrupts.c b/src/hardware/interrupts.c new file mode 100644 index 0000000..614dbf0 --- /dev/null +++ b/src/hardware/interrupts.c @@ -0,0 +1,215 @@ +#include "interrupts.h" + +#include "string.h" +#include "stdio.h" + +#include "kernel.h" + +#include "keyboard.h" + +// TODO: for now the code segment is the first entry in the boot GDT +#define GDT_CODE_SEGMENT_SELECTOR 8 + +// the Present bit in a IDT entry +#define IDT_PRESENT_BIT 0x80 + +// DPL rings +#define KERNEL_RING 0 + +// types of IDT entries +#define IDT_TYPE_INTERRUPT_GATE 0xE + +// PIC constants + +#define ICW1_ICW4 0x01 // support a 4th initialization word (ICW4) +#define ICW1_INIT 0x10 // bit indicating initialization of chip + +// offset for hardware interrupts (for PIC ICW2) +#define ICW2_IRQ_BASE_MASTER IRQ_BASE +#define ICW2_IRQ_BASE_SLAVE ICW2_IRQ_BASE_MASTER + 8 + +// IRQ selection (master and slave, ICW3) +#define ICW3_MASTER_IR0 0x01 +#define ICW3_MASTER_IR1 0x02 +#define ICW3_MASTER_IR2 0x04 +#define ICW3_MASTER_IR3 0x08 +#define ICW3_MASTER_IR4 0x10 +#define ICW3_MASTER_IR5 0x20 +#define ICW3_MASTER_IR6 0x40 +#define ICW3_MASTER_IR7 0x80 +#define ICW3_SLAVE_IR0 0x00 +#define ICW3_SLAVE_IR1 0x01 +#define ICW3_SLAVE_IR2 0x02 +#define ICW3_SLAVE_IR3 0x03 +#define ICW3_SLAVE_IR4 0x04 +#define ICW3_SLAVE_IR5 0x05 +#define ICW3_SLAVE_IR6 0x06 +#define ICW3_SLAVE_IR7 0x07 + +// special mode PIC ICW4 +#define ICW4_8086 0x01 +#define ICW4_AUTO_ACK_EOI 0x02 +#define ICW4_BUF_MASTER 0x04 +#define ICW4_BUFFER 0x08 +#define ICW4_FULLY_NESTED 0x10 + +// OCW2 +#define OCW2_EOI 0x20 // non-specific End Of Interrupt + +void interrupt_handler_init_void( interrupt_handler_t *handler ) +{ + memset( handler, 0, sizeof( interrupt_handler_t ) ); +} + +void interrupt_handler_init( interrupt_handler_t *handler, uint8_t interrupt_no, struct interrupt_t *interrupt, interrupt_handler_func_t handle, void *driver ) +{ + memset( handler, 0, sizeof( interrupt_handler_t ) ); + + handler->interrupt_no = interrupt_no; + handler->interrupt = interrupt; + handler->handle = handle; + handler->driver = driver; +} + +// must be global: when called via assembly code we loose the context +// of the interrupt handler structure +static interrupt_t *active_interrupt; + +void interrupts_init( interrupt_t *interrupt ) +{ + memset( interrupt, 0, sizeof( interrupt_t ) ); + + interrupt_handler_t empty_interrupt_handler; + interrupt_handler_init_void( &empty_interrupt_handler ); + + for( int i = 0; i < NOF_INTERRUPTS; i++ ) { + interrupts_register_interrupt_gate( interrupt, i, GDT_CODE_SEGMENT_SELECTOR, + &interrupts_ignore_request, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); + interrupts_register_interrupt_handler( empty_interrupt_handler ); + } + + // divide-by-zero exception 0x00 + interrupt_handler_t divide_by_zero_interrupt_handler; + interrupt_handler_init( ÷_by_zero_interrupt_handler, 0x00, interrupt, interrupts_exception_division_by_zero, NULL ); + + interrupts_register_interrupt_gate( interrupt, 0x00, GDT_CODE_SEGMENT_SELECTOR, + &interrupts_handle_exception_0x00, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); + interrupts_register_interrupt_handler( divide_by_zero_interrupt_handler ); + + // IRQ 0 - PIT - programmable interrupt timer + interrupt_handler_t pit_interrupt_handler; + interrupt_handler_init( &pit_interrupt_handler, IRQ_BASE + 0x00, interrupt, interrupts_interrupt_PIT, NULL ); + + interrupts_register_interrupt_gate( interrupt, IRQ_BASE + 0x00, GDT_CODE_SEGMENT_SELECTOR, + &interrupts_handle_irq_0x00, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); + interrupts_register_interrupt_handler( pit_interrupt_handler ); + + // IRQ 1 - PS/2 keyboard + interrupts_register_interrupt_gate( interrupt, IRQ_BASE + 0x01, GDT_CODE_SEGMENT_SELECTOR, + &interrupts_handle_irq_0x01, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); + + // IRQ 12 - PS/2 mouse + interrupts_register_interrupt_gate( interrupt, IRQ_BASE + 0x0C, GDT_CODE_SEGMENT_SELECTOR, + &interrupts_handle_irq_0x0C, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); + + port8_init( &interrupt->PIC_master_control, 0x20 ); + port8_init( &interrupt->PIC_master_data, 0x21 ); + port8_init( &interrupt->PIC_slave_control, 0xA0 ); + port8_init( &interrupt->PIC_slave_data, 0xA1 ); + + // initialize hardware management PICs (ICW1) + port8_write( &interrupt->PIC_master_control, ICW1_ICW4 | ICW1_INIT ); + port8_write( &interrupt->PIC_slave_control, ICW1_ICW4 | ICW1_INIT ); + + // set IRQ base of both PICS (ICW2), remap them so they + // don't collide with CPU exceptions (this is true after 0x20) + port8_write( &interrupt->PIC_master_data, ICW2_IRQ_BASE_MASTER ); + port8_write( &interrupt->PIC_slave_data, ICW2_IRQ_BASE_SLAVE ); + + // use IRQ2 for master slave communication (ICW3) + port8_write( &interrupt->PIC_master_data, ICW3_MASTER_IR2 ); + port8_write( &interrupt->PIC_slave_data, ICW3_SLAVE_IR2 ); + + // unbuffered, manual acknoledgment and 8086 mode (ICW4) + // TODO: use buffered mode later? + port8_write( &interrupt->PIC_master_data, ICW4_8086 ); + port8_write( &interrupt->PIC_slave_data, ICW4_8086 ); + + // done, enable all IRQs by setting the interrupt mask register + // 0 for all bits. We are not interested in the old state of + // the mask as we are initializing in protected mode + // TODO: later we will mask uninmported interrupts maybe? + port8_write( &interrupt->PIC_master_data, 0 ); + port8_write( &interrupt->PIC_slave_data, 0 ); + + // tell CPU where the IDT is + interrupt->idt_pointer.size = NOF_INTERRUPTS * sizeof( interrupt_gate_descriptor_t ) - 1; + interrupt->idt_pointer.base = (uint32_t)interrupt->descriptor_table; + + interrupts_load_idt( &interrupt->idt_pointer ); + + active_interrupt = interrupt; +} + +void interrupts_register_interrupt_gate( interrupt_t *interrupts, + uint8_t interrupt_no, uint16_t gdt_code_segment_selector, + void (*helper_handler)( ), uint8_t privilege_level, uint8_t descriptor_type ) +{ + interrupt_gate_descriptor_t *descr = &interrupts->descriptor_table[interrupt_no]; + + descr->handler_address_low_bits = ( (uint32_t )helper_handler ) & 0xFFFF; + descr->handler_address_high_bits = ( ( (uint32_t )helper_handler ) >> 16 ) & 0xFFFF; + descr->gdt_code_segment_selector = gdt_code_segment_selector; + descr->access = IDT_PRESENT_BIT | (( privilege_level & 0x3 ) << 5 ) | descriptor_type; + descr->reserved = 0; +} + +void interrupts_register_interrupt_handler( interrupt_handler_t handler ) +{ + handler.interrupt->interrupt_handler[handler.interrupt_no] = handler; +} + +uint32_t interrupts_exception_division_by_zero( interrupt_handler_t *handler, uint32_t esp ) +{ + // TODO: caused by kernel code or user land code? or a task we can kill? + // For now, the kernel has no task management, so we panic + kernel_panic( "Division by zero with ESP 0x%X\n", esp ); + + return esp; +} + +uint32_t interrupts_interrupt_PIT( interrupt_handler_t *handler, uint32_t esp ) +{ + // for now do noting with the timer tick + return esp; +} + +uint32_t interrupts_handle_static_interrupt( uint8_t interrupt_no, uint32_t esp ) +{ + if( active_interrupt == NULL ) { + kernel_panic( "No active interrupt handler!" ); + } + + return interrupts_handle_interrupt( active_interrupt, interrupt_no, esp ); +} + +uint32_t interrupts_handle_interrupt( interrupt_t *interrupt, uint8_t interrupt_no, uint32_t esp ) +{ + interrupt_handler_t *handler = &interrupt->interrupt_handler[interrupt_no]; + + if( handler->handle == NULL ) { + kernel_panic( "Unhandled interrupt 0x%X with ESP 0x%X\n", interrupt_no, esp ); + } + + uint32_t new_esp = handler->handle( handler, esp ); + + // send ACK to PIC for hardware interrups + if( interrupt_no >= IRQ_BASE && interrupt_no <= IRQ_BASE + 16 ) { + port8_write( &interrupt->PIC_master_control, OCW2_EOI ); + if( interrupt_no >= IRQ_BASE + 8 ) { + port8_write( &interrupt->PIC_slave_control, OCW2_EOI ); + } + } + + return new_esp; +} diff --git a/src/hardware/interrupts.h b/src/hardware/interrupts.h new file mode 100644 index 0000000..8ab485e --- /dev/null +++ b/src/hardware/interrupts.h @@ -0,0 +1,103 @@ +#ifndef INTERRUPTS_H +#define INTERRUPTS_H + +#include + +#include "port.h" + +// total number of supported interrupts +#define NOF_INTERRUPTS 256 + +// offset for hardware interrupts +#define IRQ_BASE 0x20 + +// TCC 0.9.26 bug?, __attribute__( ( packed ) ) on structs not working, +// also not working on members.. resorting to pragmas +#if defined( __TINYC__ ) +#pragma pack(1) +#endif + +// packed IDT structure, note TCC needs every member to have a packed +// attribute, GCC/Clang are happy with the packed attribute at the +// structure level +typedef struct interrupt_gate_descriptor_t { + uint16_t handler_address_low_bits; + uint16_t gdt_code_segment_selector; + uint8_t reserved; + uint8_t access; + uint16_t handler_address_high_bits; +} __attribute__( ( packed ) ) interrupt_gate_descriptor_t; + +#if defined( __TINYC__ ) +#pragma pack() +#endif + +#if defined( __TINYC__ ) +#pragma pack(1) +#endif + +typedef struct { + uint16_t size; + uint32_t base; +} __attribute__( ( packed ) ) interrupt_descriptor_table_pointer_t; + +#if defined( __TINYC__ ) +#pragma pack() +#endif + +struct interrupt_t; +struct interrupt_handler_t; + +typedef uint32_t (*interrupt_handler_func_t)( struct interrupt_handler_t *handler, uint32_t esp ); + +typedef struct interrupt_handler_t { + uint8_t interrupt_no; + struct interrupt_t *interrupt; + interrupt_handler_func_t handle; + void *driver; +} interrupt_handler_t; + +void interrupt_handler_init_void( interrupt_handler_t *handler ); +void interrupt_handler_init( interrupt_handler_t *handler, uint8_t interrupt_no, struct interrupt_t *interrupt, interrupt_handler_func_t handle, void *driver ); + +typedef struct interrupt_t { + interrupt_descriptor_table_pointer_t idt_pointer; + interrupt_gate_descriptor_t descriptor_table[NOF_INTERRUPTS]; + interrupt_handler_t interrupt_handler[NOF_INTERRUPTS]; + // PIC master control register: command and status register + port8_t PIC_master_control; + // PIC master data register: interrupt mask and data register + port8_t PIC_master_data; + // since PC/AT we always have a slave PIC, we don't support the PC/XT architecture + // with just one PIC + port8_t PIC_slave_control; + port8_t PIC_slave_data; +} interrupt_t; + +void interrupts_enable( void ); +void interrupts_disable( void ); +void interrupts_init( interrupt_t *interrupt ); +void interrupts_register_interrupt_gate( interrupt_t *interrupt, + uint8_t interrupt_no, uint16_t gdt_code_segment_selector, + void (*helper_handler)( ), uint8_t privilege_level, uint8_t descriptor_type ); +void interrupts_register_interrupt_handler( interrupt_handler_t handler ); + +void interrupts_load_idt( interrupt_descriptor_table_pointer_t *idt_pointer ); + +uint32_t interrupts_handle_interrupt( interrupt_t *interrupt, uint8_t interrupt_no, uint32_t esp ); + +uint32_t interrupts_handle_static_interrupt( uint8_t interrupt_no, uint32_t esp ); + +uint32_t interrupts_exception_division_by_zero( interrupt_handler_t *handler, uint32_t esp ); + +uint32_t interrupts_interrupt_PIT( interrupt_handler_t *handler, uint32_t esp ); + +void interrupts_ignore_request( ); +void interrupts_handle_exception_0x00( ); +void interrupts_handle_irq_0x00( ); +void interrupts_handle_irq_0x01( ); +void interrupts_handle_irq_0x0C( ); + +// later: tasks and stacks, queues + +#endif // INTERRUPTS_H diff --git a/src/hardware/pci.c b/src/hardware/pci.c new file mode 100644 index 0000000..6b124b2 --- /dev/null +++ b/src/hardware/pci.c @@ -0,0 +1,187 @@ +#include "pci.h" + +#include "string.h" +#include "stdio.h" + +#define NOF_BUSES 8 +#define NOF_DEVICES_PER_BUS 32 +#define NOF_FUNCTIONS_PER_DEVICE 8 +#define NOF_BARS 6 + +#define PCI_VENDOR_ID 0x00 +#define PCI_DEVICE_ID 0x02 +#define PCI_REVISION 0x08 +#define PCI_INTERFACE 0x09 +#define PCI_SUBCLASS 0x0A +#define PCI_CLASS 0x0B +#define PCI_HEADER_TYPE 0x0E +#define PCI_BAR_BASE 0x10 + +void pci_controller_init( pci_controller_t *controller ) +{ + memset( controller, 0, sizeof( pci_controller_t ) ); + + port32_init( &controller->command_port, 0xCF8 ); + port32_init( &controller->data_port, 0xCFC ); +} + +static uint32_t compute_id( uint16_t bus, uint16_t device, uint16_t function, uint32_t offset ) +{ + uint32_t id; + + id = ( 0x01 << 31 ) + | ( ( bus & 0xFF ) << 16 ) + | ( ( device & 0x1F ) << 11 ) + | ( ( function & 0x07 ) << 8 ) + | ( offset & 0xFC ); + + return id; +} + +uint16_t pci_controller_read( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset ) +{ + uint32_t id = compute_id( bus, device, function, offset ); + + port32_write( &controller->command_port, id ); + + uint32_t data = port32_read( &controller->data_port ); + + // we get 256 byte data blocks aligned to 32-bit addresses + // for each offset + data = data >> ( ( 8 * ( offset % 4 ) ) & 0xFFFF ); + + return data; +} + +void pci_controller_write( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset, uint32_t data ) +{ + uint32_t id = compute_id( bus, device, function, offset ); + + port32_write( &controller->command_port, id ); + port32_write( &controller->data_port, data ); +} + +void pci_controller_scan_and_register( pci_controller_t *controller, driver_manager_t *driver_manager, interrupt_t *interrupt ) +{ + for( int bus = 0; bus < NOF_BUSES; bus++ ) { + for( int device = 0; device < NOF_DEVICES_PER_BUS; device++ ) { + // TODO: detect single/multi function device from header + for( int function = 0; function < NOF_FUNCTIONS_PER_DEVICE; function++ ) { + pci_device_descriptor_t device_descriptor; + pci_device_descriptor_init( &device_descriptor, controller, bus, device, function ); + + // no device + if( device_descriptor.device_id == 0x0 || + device_descriptor.device_id == 0xFFFF ) { + continue; + } + + printf( "%X:%X.%d: %X:%X (interface: %X, class %X:%X, rev: %d)\n", + bus, device, function, + device_descriptor.vendor_id, + device_descriptor.device_id, + device_descriptor.interface_id, + device_descriptor.class_id, + device_descriptor.subclass_id, + device_descriptor.revision_id ); + + uint8_t header_type = pci_controller_read( controller, bus, device, function, PCI_HEADER_TYPE ) & 0x7F; + int max_nof_bars = NOF_BARS; + if( header_type & 0x01 ) { + max_nof_bars = 2; + } + + for( int bar_number = 0; bar_number < max_nof_bars; bar_number++ ) { + pci_base_address_register_t bar; + pci_base_address_register_init( &bar, controller, bus, device, function, bar_number ); + if( bar.type == BASE_ADDRESS_REGISTER_TYPE_IO && bar.addr ) { + device_descriptor.port_base = (uint32_t)bar.addr; + } + + driver_t *driver = pci_device_get_driver( &device_descriptor, interrupt ); + if( driver ) { + driver_manager_add_driver( driver_manager, driver ); + } + } + } + } + } +} + +void pci_device_descriptor_init( pci_device_descriptor_t *descriptor, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function ) +{ + memset( descriptor, 0, sizeof( pci_device_descriptor_t ) ); + + descriptor->vendor_id = pci_controller_read( controller, bus, device, function, PCI_VENDOR_ID ); + descriptor->device_id = pci_controller_read( controller, bus, device, function, PCI_DEVICE_ID ); + descriptor->class_id = pci_controller_read( controller, bus, device, function, PCI_CLASS ); + descriptor->subclass_id = pci_controller_read( controller, bus, device, function, PCI_SUBCLASS ); + descriptor->interface_id = pci_controller_read( controller, bus, device, function, PCI_INTERFACE ); + descriptor->revision_id = pci_controller_read( controller, bus, device, function, PCI_REVISION ); +} + +void pci_base_address_register_init( pci_base_address_register_t *base_address_register, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint16_t bar ) +{ + memset( base_address_register, 0, sizeof( pci_base_address_register_t ) ); + + uint32_t val = pci_controller_read( controller, bus, device, function, PCI_BAR_BASE + sizeof( uint32_t ) * bar ); + + // bit 0 indicates whether we are I/O or memory mapped + base_address_register->type = ( val & 0x01 ) ? BASE_ADDRESS_REGISTER_TYPE_IO : BASE_ADDRESS_REGISTER_TYPE_MEMORY_MAPPED; + + switch( base_address_register->type ) { + case BASE_ADDRESS_REGISTER_TYPE_IO: + base_address_register->addr = (uint8_t *)( val & 0xFFFC ); + base_address_register->prefetchable = false; + break; + + case BASE_ADDRESS_REGISTER_TYPE_MEMORY_MAPPED: + switch( val << 1 & 0x03 ) { + case 0x00: + // 32-bit mode + break; + + case 0x01: + // 20-bit mode + break; + + case 0x02: + // 64-bit mode + break; + } + break; + } +} + +driver_t *pci_device_get_driver( pci_device_descriptor_t *descriptor, interrupt_t *interrupt ) +{ + // find a specific device + switch( descriptor->vendor_id ) { + case 0x10ec: // Realtek Semiconductor + switch( descriptor->device_id ) { + case 0x8029: // RTL-8029 + break; + } + break; + + case 0x8086: // Intel + break; + + default: + break; + } + + // find a generic driver + switch( descriptor->class_id ) { + case 0x03: // graphics + switch( descriptor->subclass_id ) { + case 0x00: // VGA + break; + } + break; + + default: // no driver found + break; + } + return NULL; +} diff --git a/src/hardware/pci.h b/src/hardware/pci.h new file mode 100644 index 0000000..ddbc990 --- /dev/null +++ b/src/hardware/pci.h @@ -0,0 +1,49 @@ +#ifndef PCI_H +#define PCI_H + +#include + +#include "port.h" +#include "interrupts.h" +#include "driver.h" + +typedef struct { + uint16_t vendor_id; + uint16_t device_id; + uint8_t class_id; + uint8_t subclass_id; + uint8_t interface_id; + uint8_t revision_id; + uint32_t port_base; +} pci_device_descriptor_t; + +typedef struct { + port32_t command_port; + port32_t data_port; +} pci_controller_t; + +typedef enum { + BASE_ADDRESS_REGISTER_TYPE_IO, + BASE_ADDRESS_REGISTER_TYPE_MEMORY_MAPPED +} pci_base_address_register_type_t; + +typedef struct { + pci_base_address_register_type_t type; + bool prefetchable; + uint8_t *addr; + uint32_t *size; +} pci_base_address_register_t; + +void pci_controller_init( pci_controller_t *controller ); + +uint16_t pci_controller_read( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset ); +void pci_controller_write( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset, uint32_t data ); +void pci_controller_scan_and_register( pci_controller_t *controller, driver_manager_t *driver_manager, interrupt_t *interrupt ); + +void pci_device_descriptor_init( pci_device_descriptor_t *descriptor, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function ); + +void pci_base_address_register_init( pci_base_address_register_t *base_address_register, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint16_t bar ); + +driver_t *pci_device_get_driver( pci_device_descriptor_t *descriptor, interrupt_t *interrupt ); + +#endif // PCI_H diff --git a/src/hardware/port.asm b/src/hardware/port.asm new file mode 100644 index 0000000..555a4e8 --- /dev/null +++ b/src/hardware/port.asm @@ -0,0 +1,49 @@ +[bits 32] + +global port8_write +global port8_read + +; void port8_write( port8_t *port, uint8_t data ); +port8_write: + push ebp + mov ebp, esp + mov ecx, [ebp+8] + mov edx, DWORD [ecx] + movzx ax, BYTE [ebp+12] + out dx, al + leave + ret + +; uint8_t port8_read( port8_t *port ) +port8_read: + push ebp + mov ebp, esp + mov ecx, DWORD [ebp+8] + mov edx, [ecx] + in al, dx + leave + ret + +global port32_write +global port32_read + +; void port32_write( port32_t *port, uint32_t data ); +port32_write: + push ebp + mov ebp, esp + mov ecx, [ebp+8] + mov edx, DWORD [ecx] + mov eax, DWORD [ebp+12] + out dx, eax + leave + ret + +; uint32_t port32_read( port32_t *port ) +port32_read: + push ebp + mov ebp, esp + mov ecx, DWORD [ebp+8] + mov edx, [ecx] + in eax, dx + leave + ret diff --git a/src/hardware/port.c b/src/hardware/port.c new file mode 100644 index 0000000..46e7f37 --- /dev/null +++ b/src/hardware/port.c @@ -0,0 +1,17 @@ +#include "port.h" + +#include "string.h" + +void port8_init( port8_t *port, uint16_t number ) +{ + memset( port, 0, sizeof( port8_t ) ); + + port->number = number; +} + +void port32_init( port32_t *port, uint16_t number ) +{ + memset( port, 0, sizeof( port32_t ) ); + + port->number = number; +} diff --git a/src/hardware/port.h b/src/hardware/port.h new file mode 100644 index 0000000..ec96d09 --- /dev/null +++ b/src/hardware/port.h @@ -0,0 +1,23 @@ +#ifndef PORT_H +#define PORT_H + +#include + +typedef struct { + uint16_t number; // port number, e.g. 0x3d4 VGA index register +} port8_t; + +void port8_init( port8_t *port, uint16_t number ); +void port8_write( port8_t *port, uint8_t data ); +uint8_t port8_read( port8_t *port ); + +typedef struct { + uint16_t number; // port number, e.g. 0x3d4 VGA index register +} port32_t; + +void port32_init( port32_t *port, uint16_t number ); +void port32_write( port32_t *port, uint32_t data ); +uint32_t port32_read( port32_t *port ); + +#endif // PORT_H + -- cgit v1.2.3-54-g00ecf