first version of ide controller

This commit is contained in:
2021-02-04 23:15:02 +01:00
parent dc8a0444f9
commit b156509da1
7 changed files with 572 additions and 68 deletions

View File

@@ -37,6 +37,13 @@ static void timer_callback(registers_t regs) {
tick++;
}
void sleep(u32 milliseconds) {
u32 done = tick + milliseconds;
while (done != milliseconds) {
k_wait_for_interrupt();
}
}
void print_current_tick() {
char msg[32];
memset(msg, 0, 32);

View File

@@ -9,5 +9,6 @@
int init_timer(u32 freq);
void print_current_tick();
void sleep(u32 milliseconds);
#endif //MY_KERNEL_TIMER_H

View File

@@ -1,17 +1,279 @@
//
// Created by rick on 03-02-21.
//
// https://wiki.osdev.org/PCI_IDE_Controller
#include "ide.h"
#include "ports.h"
#include <types.h>
#include <kprint.h>
#include <drivers/pci.h>
#include <libc/stdbool.h>
#include <libk.h>
#include <libc/libc.h>
#include <cpu/timer.h>
const char* ide_pci_driver_name = "pci-ide";
#define ATA_SR_BSY 0x80 // Busy
#define ATA_SR_DRDY 0x40 // Drive ready
#define ATA_SR_DF 0x20 // Drive write fault
#define ATA_SR_DSC 0x10 // Drive seek complete
#define ATA_SR_DRQ 0x08 // Data request ready
#define ATA_SR_CORR 0x04 // Corrected data
#define ATA_SR_IDX 0x02 // Index
#define ATA_SR_ERR 0x01 // Error
#define ATA_ER_BBK 0x80 // Bad block
#define ATA_ER_UNC 0x40 // Uncorrectable data
#define ATA_ER_MC 0x20 // Media changed
#define ATA_ER_IDNF 0x10 // ID mark not found
#define ATA_ER_MCR 0x08 // Media change request
#define ATA_ER_ABRT 0x04 // Command aborted
#define ATA_ER_TK0NF 0x02 // Track 0 not found
#define ATA_ER_AMNF 0x01 // No address mark
#define ATA_CMD_READ_PIO 0x20
#define ATA_CMD_READ_PIO_EXT 0x24
#define ATA_CMD_READ_DMA 0xC8
#define ATA_CMD_READ_DMA_EXT 0x25
#define ATA_CMD_WRITE_PIO 0x30
#define ATA_CMD_WRITE_PIO_EXT 0x34
#define ATA_CMD_WRITE_DMA 0xCA
#define ATA_CMD_WRITE_DMA_EXT 0x35
#define ATA_CMD_CACHE_FLUSH 0xE7
#define ATA_CMD_CACHE_FLUSH_EXT 0xEA
#define ATA_CMD_PACKET 0xA0
#define ATA_CMD_IDENTIFY_PACKET 0xA1
#define ATA_CMD_IDENTIFY 0xEC
#define ATAPI_CMD_READ 0xA8
#define ATAPI_CMD_EJECT 0x1B
#define ATA_IDENT_DEVICETYPE 0
#define ATA_IDENT_CYLINDERS 2
#define ATA_IDENT_HEADS 6
#define ATA_IDENT_SECTORS 12
#define ATA_IDENT_SERIAL 20
#define ATA_IDENT_MODEL 54
#define ATA_IDENT_CAPABILITIES 98
#define ATA_IDENT_FIELDVALID 106
#define ATA_IDENT_MAX_LBA 120
#define ATA_IDENT_COMMANDSETS 164
#define ATA_IDENT_MAX_LBA_EXT 200
#define IDE_ATA 0x00
#define IDE_ATAPI 0x01
#define ATA_MASTER 0x00
#define ATA_SLAVE 0x01
#define ATA_REG_DATA 0x00
#define ATA_REG_ERROR 0x01
#define ATA_REG_FEATURES 0x01
#define ATA_REG_SECCOUNT0 0x02
#define ATA_REG_LBA0 0x03
#define ATA_REG_LBA1 0x04
#define ATA_REG_LBA2 0x05
#define ATA_REG_HDDEVSEL 0x06
#define ATA_REG_COMMAND 0x07
#define ATA_REG_STATUS 0x07
#define ATA_REG_SECCOUNT1 0x08
#define ATA_REG_LBA3 0x09
#define ATA_REG_LBA4 0x0A
#define ATA_REG_LBA5 0x0B
#define ATA_REG_CONTROL 0x0C
#define ATA_REG_ALTSTATUS 0x0C
#define ATA_REG_DEVADDRESS 0x0D
// Channels:
#define ATA_PRIMARY 0x00
#define ATA_SECONDARY 0x01
// Directions:
#define ATA_READ 0x00
#define ATA_WRITE 0x01
struct ide_channel_registers {
unsigned short base; // I/O Base.
unsigned short ctrl; // Control Base
unsigned short bmide; // Bus Master IDE
unsigned char nIEN; // nIEN (No Interrupt);
} channels[2];
unsigned char ide_buf[2048] = {0};
unsigned static char ide_irq_invoked = 0;
unsigned static char atapi_packet[12] = {0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
struct ide_device {
unsigned char reserved; // 0 (Empty) or 1 (This Drive really exists).
unsigned char channel; // 0 (Primary Channel) or 1 (Secondary Channel).
unsigned char drive; // 0 (Master Drive) or 1 (Slave Drive).
unsigned short type; // 0: ATA, 1:ATAPI.
unsigned short signature; // Drive Signature
unsigned short capabilities;// Features.
unsigned int commandSets; // Command Sets Supported.
unsigned int size; // Size in Sectors.
unsigned char model[41]; // Model in string.
} ide_devices[4];
u8 ide_read(u8 channel, u8 reg);
void ide_write(u8 channel, u8 reg, u8 data);
u8 ide_read(u8 channel, u8 reg) {
u8 result;
if (reg > 0x07 && reg < 0x0C)
ide_write(channel, ATA_REG_CONTROL, 0x80 | channels[channel].nIEN);
if (reg < 0x08)
result = port_byte_in(channels[channel].base + reg - 0x00);
else if (reg < 0x0C)
result = port_byte_in(channels[channel].base + reg - 0x06);
else if (reg < 0x0E)
result = port_byte_in(channels[channel].ctrl + reg - 0x0A);
else if (reg < 0x16)
result = port_byte_in(channels[channel].bmide + reg - 0x0E);
if (reg > 0x07 && reg < 0x0C)
ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN);
return result;
}
void ide_write(u8 channel, u8 reg, u8 data) {
if (reg > 0x07 && reg < 0x0C)
ide_write(channel, ATA_REG_CONTROL, 0x80 | channels[channel].nIEN);
if (reg < 0x08)
port_byte_out(channels[channel].base + reg - 0x00, data);
else if (reg < 0x0C)
port_byte_out(channels[channel].base + reg - 0x06, data);
else if (reg < 0x0E)
port_byte_out(channels[channel].ctrl + reg - 0x0A, data);
else if (reg < 0x16)
port_byte_out(channels[channel].bmide + reg - 0x0E, data);
if (reg > 0x07 && reg < 0x0C)
ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN);
}
void ide_read_buffer(unsigned char channel, unsigned char reg, unsigned int* buffer, unsigned int quads) {
/* WARNING: This code contains a serious bug. The inline assembly trashes ES and
* ESP for all of the code the compiler generates between the inline
* assembly blocks.
*/
if (reg > 0x07 && reg < 0x0C) {
ide_write(channel, ATA_REG_CONTROL, 0x80 | channels[channel].nIEN);
}
// asm("pushw %es; movw %ds, %ax; movw %ax, %es" : : : "es", "esp");
if (reg < 0x08) {
port_double_word_in_repeat(channels[channel].base + reg - 0x00, buffer, quads);
} else if (reg < 0x0C) {
port_double_word_in_repeat(channels[channel].base + reg - 0x06, buffer, quads);
} else if (reg < 0x0E) {
port_double_word_in_repeat(channels[channel].ctrl + reg - 0x0A, buffer, quads);
} else if (reg < 0x16) {
port_double_word_in_repeat(channels[channel].bmide + reg - 0x0E, buffer, quads);
}
// asm("popw %es;");
if (reg > 0x07 && reg < 0x0C) {
ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN);
}
}
unsigned char ide_polling(unsigned char channel, unsigned int advanced_check) {
// (I) Delay 400 nanosecond for BSY to be set:
// -------------------------------------------------
for (int i = 0; i < 4; i++)
ide_read(channel, ATA_REG_ALTSTATUS); // Reading the Alternate Status port wastes 100ns; loop four times.
// (II) Wait for BSY to be cleared:
// -------------------------------------------------
while (ide_read(channel, ATA_REG_STATUS) & ATA_SR_BSY); // Wait for BSY to be zero.
if (advanced_check) {
unsigned char state = ide_read(channel, ATA_REG_STATUS); // Read Status Register.
// (III) Check For Errors:
// -------------------------------------------------
if (state & ATA_SR_ERR)
return 2; // Error.
// (IV) Check If Device fault:
// -------------------------------------------------
if (state & ATA_SR_DF)
return 1; // Device Fault.
// (V) Check DRQ:
// -------------------------------------------------
// BSY = 0; DF = 0; ERR = 0 so we should check for DRQ now.
if ((state & ATA_SR_DRQ) == 0)
return 3; // DRQ should be set
}
return 0; // No Error.
}
unsigned char ide_print_error(unsigned int drive, unsigned char err) {
if (err == 0)
return err;
kprint("IDE:");
if (err == 1) {
kprint("- Device Fault\n ");
err = 19;
} else if (err == 2) {
unsigned char st = ide_read(ide_devices[drive].channel, ATA_REG_ERROR);
if (st & ATA_ER_AMNF) {
kprint("- No Address Mark Found\n ");
err = 7;
}
if (st & ATA_ER_TK0NF) {
kprint("- No Media or Media Error\n ");
err = 3;
}
if (st & ATA_ER_ABRT) {
kprint("- Command Aborted\n ");
err = 20;
}
if (st & ATA_ER_MCR) {
kprint("- No Media or Media Error\n ");
err = 3;
}
if (st & ATA_ER_IDNF) {
kprint("- ID mark not Found\n ");
err = 21;
}
if (st & ATA_ER_MC) {
kprint("- No Media or Media Error\n ");
err = 3;
}
if (st & ATA_ER_UNC) {
kprint("- Uncorrectable Data Error\n ");
err = 22;
}
if (st & ATA_ER_BBK) {
kprint("- Bad Sectors\n ");
err = 13;
}
} else if (err == 3) {
kprint("- Reads Nothing\n ");
err = 23;
} else if (err == 4) {
kprint("- Write Protected\n ");
err = 8;
}
kprint(" - [");
kprint((const char *[]) {"Primary", "Secondary"}[ide_devices[drive].channel]);
kprint(" ");
kprint((const char *[]) {"Master", "Slave"}[ide_devices[drive].drive]);
kprint("] ");
kprint(&ide_devices[drive].model);
kprint("\n");
return err;
}
u8 ide_pci_validate(const pci_device *device);
u8 ide_pci_initialize(const pci_device *device);
u8 ide_pci_initialize(pci_device *device);
const pci_driver ide_pci_driver = {
.name = "pci-ide",
@@ -27,16 +289,139 @@ const pci_driver ide_pci_driver = {
u8 ide_pci_validate(const pci_device *device) {
if (device->class != PCI_CLASS_MASS_STORAGE
|| device->subclass != PCI_SUB_CLASS_IDE) {
|| device->subclass != PCI_SUB_CLASS_IDE
|| (device->programInterface != 0x8A && device->programInterface != 0x80)) {
return PCI_VALIDATE_FAIL;
}
// todo other validations
return PCI_VALIDATE_OK;
}
u8 ide_pci_initialize(const pci_device *device) {
kprint("IDE registered");
return PCI_VALIDATE_OK;
u8 ide_pci_initialize(pci_device *device) {
pci_config_write_byte(device->bus, device->slot, device->func, PCI_CONFIG_INTERRUPT_LINE, 0xFE);
if (pci_config_read_byte(device->bus, device->slot, device->func, PCI_CONFIG_INTERRUPT_LINE) == 0xFE) {
// todo
// k_panics("Interrupt line");
// return PCI_INIT_FAIL;
}
pci_init_bar(device, 0);
pci_init_bar(device, 1);
pci_init_bar(device, 2);
pci_init_bar(device, 3);
pci_init_bar(device, 4);
if (!device->bar0.present
|| !device->bar1.present
|| !device->bar2.present
|| !device->bar3.present
|| !device->bar4.present) {
k_panics("IDE Missing bars");
return PCI_INIT_FAIL;
}
channels[ATA_PRIMARY].base = device->bar0.address + 0x1F0;
channels[ATA_PRIMARY].ctrl = device->bar1.address + 0x3F6;
channels[ATA_SECONDARY].base = device->bar2.address + 0x170;
channels[ATA_SECONDARY].ctrl = device->bar3.address + 0x376;
channels[ATA_PRIMARY].bmide = device->bar4.address + 0; // Bus Master IDE
channels[ATA_SECONDARY].bmide = device->bar4.address + 8; // Bus Master IDE
// disable IRQ
ide_write(ATA_PRIMARY, ATA_REG_CONTROL, 2);
ide_write(ATA_SECONDARY, ATA_REG_CONTROL, 2);
int count = 0;
// 3- Detect ATA-ATAPI Devices:
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++) {
unsigned char err = 0, type = IDE_ATA, status;
ide_devices[count].reserved = 0; // Assuming that no drive here.
// (I) Select Drive:
ide_write(i, ATA_REG_HDDEVSEL, 0xA0 | (j << 4)); // Select Drive.
sleep(1); // Wait 1ms for drive select to work.
// (II) Send ATA Identify Command:
ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
sleep(1); // This function should be implemented in your OS. which waits for 1 ms.
// it is based on System Timer Device Driver.
// (III) Polling:
if (ide_read(i, ATA_REG_STATUS) == 0) continue; // If Status = 0, No Device.
while (1) {
status = ide_read(i, ATA_REG_STATUS);
if ((status & ATA_SR_ERR)) {
err = 1;
break;
} // If Err, Device is not ATA.
if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) break; // Everything is right.
}
// (IV) Probe for ATAPI Devices:
if (err != 0) {
unsigned char cl = ide_read(i, ATA_REG_LBA1);
unsigned char ch = ide_read(i, ATA_REG_LBA2);
if (cl == 0x14 && ch == 0xEB)
type = IDE_ATAPI;
else if (cl == 0x69 && ch == 0x96)
type = IDE_ATAPI;
else
continue; // Unknown Type (may not be a device).
ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET);
sleep(1);
}
// (V) Read Identification Space of the Device:
ide_read_buffer(i, ATA_REG_DATA, (unsigned int*) ide_buf, 128);
// (VI) Read Device Parameters:
ide_devices[count].reserved = 1;
ide_devices[count].type = type;
ide_devices[count].channel = i;
ide_devices[count].drive = j;
ide_devices[count].signature = *((unsigned short *) (ide_buf + ATA_IDENT_DEVICETYPE));
ide_devices[count].capabilities = *((unsigned short *) (ide_buf + ATA_IDENT_CAPABILITIES));
ide_devices[count].commandSets = *((unsigned int *) (ide_buf + ATA_IDENT_COMMANDSETS));
// (VII) Get Size:
if (ide_devices[count].commandSets & (1 << 26))
// Device uses 48-Bit Addressing:
ide_devices[count].size = *((unsigned int *) (ide_buf + ATA_IDENT_MAX_LBA_EXT));
else
// Device uses CHS or 28-bit Addressing:
ide_devices[count].size = *((unsigned int *) (ide_buf + ATA_IDENT_MAX_LBA));
// (VIII) String indicates model of device (like Western Digital HDD and SONY DVD-RW...):
for (int k = 0; k < 40; k += 2) {
ide_devices[count].model[k] = ide_buf[ATA_IDENT_MODEL + k + 1];
ide_devices[count].model[k + 1] = ide_buf[ATA_IDENT_MODEL + k];
}
ide_devices[count].model[40] = 0; // Terminate String.
count++;
}
// 4- Print Summary:
for (int i = 0; i < 4; i++) {
if (ide_devices[i].reserved == 1) {
char tmp[64];
itoa(ide_devices[i].size / 1024 / 1024 / 2, tmp, 10);
kprint("Found ");
kprint((const char *[]) {"ATA", "ATAPI"}[ide_devices[i].type]);
kprint(" Drive ");
kprint(tmp);
kprint(" - ");
kprint(ide_devices[i].model);
kprint("\n");
}
}
return PCI_INIT_OK;
}
void ide_register() {

View File

@@ -1,6 +1,7 @@
//
// Created by rick on 02-02-21.
//
// https://wiki.osdev.org/PCI
#include "pci.h"
@@ -17,42 +18,17 @@
#define PCI_CONFIG_SHIFT_FUNC_NUMBER 8
#define PCI_CONFIG_LINE_0 0x00
#define PCI_CONFIG_VENDOR_ID 0x00
#define PCI_CONFIG_DEVICE_ID 0x02
#define PCI_CONFIG_LINE_1 0x01
#define PCI_CONFIG_COMMAND 0x04
#define PCI_CONFIG_STATUS 0x06
#define PCI_CONFIG_LINE_2 0x08
#define PCI_CONFIG_REVISION_ID 0x08
#define PCI_CONFIG_PROG_IF 0x09
#define PCI_CONFIG_SUBCLASS 0x0A
#define PCI_CONFIG_CLASS_CODE 0x0B
#define PCI_CONFIG_LINE_3 0x0C
#define PCI_CONFIG_CACHE_LINE_SIZE 0x0C
#define PCI_CONFIG_LATENCY_TIMER 0x0D
#define PCI_CONFIG_HEADER_TYPE 0x0E
#define PCI_CONFIG_BIST 0x0F
#define PCI_CONFIG_BAR0 0x10
#define PCI_CONFIG_BAR1 0x14
#define PCI_CONFIG_BAR2 0x18
#define PCI_CONFIG_BAR3 0x1C
#define PCI_CONFIG_BAR4 0x20
#define PCI_CONFIG_BAR5 0x24
#define PCI_CONFIG_CARDBUS_CIS_P 0x28
#define PCI_CONFIG_SUBSYSTEM_VENDOR_ID 0x2C
#define PCI_CONFIG_SUBSYSTEM_ID 0x2E
#define PCI_CONFIG_EXPANSION_ROM_ADDR 0x30
#define PCI_CONFIG_CAP_POINTER 0x34
#define PCI_CONFIG_INTERRUPT_LINE 0x3C
#define PCI_CONFIG_INTERRUPT_PIN 0x3D
#define PCI_CONFIG_MAX_GRANT 0x3E
#define PCI_CONFIG_MAX_LATENCY 0x3F
#define PCI_HEADER_TYPE_MULTI_FUNC 0x80
#define MAX_PCI_DRIVERS 64
#define MAX_PCI_DEVICES 64
#define MASK_BAR_IOSPACE 0xFFFFFFFC
#define MASK_BAR_MEMSPACE 0xFFFFFFF0
const pci_driver *pci_drivers[MAX_PCI_DRIVERS];
int last_pci_device_index = 0;
pci_device pci_devices[MAX_PCI_DEVICES];
@@ -68,61 +44,58 @@ u32 pci_register_driver(const pci_driver *pci_driver) {
return PCI_REGISTER_ERR_FULL;
}
u32 pci_config_address(u8 bus, u8 slot, u8 func, u8 offset) {
return PCI_CONFIG_ENABLE
| ((u32) bus << PCI_CONFIG_SHIFT_BUS_NUMBER)
| ((u32) slot << PCI_CONFIG_SHIFT_DEV_NUMBER)
| ((u32) func << PCI_CONFIG_SHIFT_FUNC_NUMBER)
| (offset & 0xFC);
}
u32 pci_config_read_double_word(u8 bus, u8 slot, u8 func, u8 offset) {
u32 address = PCI_CONFIG_ENABLE
| ((u32) bus << PCI_CONFIG_SHIFT_BUS_NUMBER)
| ((u32) slot << PCI_CONFIG_SHIFT_DEV_NUMBER)
| ((u32) func << PCI_CONFIG_SHIFT_FUNC_NUMBER)
| (offset & 0xFC);
u32 address = pci_config_address(bus, slot, func, offset);
port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address);
return port_double_word_in(PORT_PCI_CONFIG_DATA);
}
u16 pci_config_read_word(u8 bus, u8 slot, u8 func, u8 offset) {
u32 address = PCI_CONFIG_ENABLE
| ((u32) bus << PCI_CONFIG_SHIFT_BUS_NUMBER)
| ((u32) slot << PCI_CONFIG_SHIFT_DEV_NUMBER)
| ((u32) func << PCI_CONFIG_SHIFT_FUNC_NUMBER)
| (offset & 0xFC);
u32 address = pci_config_address(bus, slot, func, offset);
port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address);
return port_double_word_in(PORT_PCI_CONFIG_DATA) >> ((offset & 2) * 8) & 0xFFFF;
}
u8 pci_config_read_byte(u8 bus, u8 slot, u8 func, u8 offset) {
u32 address = PCI_CONFIG_ENABLE
| ((u32) bus << PCI_CONFIG_SHIFT_BUS_NUMBER)
| ((u32) slot << PCI_CONFIG_SHIFT_DEV_NUMBER)
| ((u32) func << PCI_CONFIG_SHIFT_FUNC_NUMBER)
| (offset & 0xFC);
u32 address = pci_config_address(bus, slot, func, offset);
port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address);
return port_double_word_in(PORT_PCI_CONFIG_DATA) >> ((offset & 0b11) * 8) & 0xFF;
}
void pci_config_write_double_word(u8 bus, u8 slot, u8 func, u8 offset, u32 value) {
u32 address = pci_config_address(bus, slot, func, offset);
port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address);
port_double_word_out(PORT_PCI_CONFIG_DATA, value);
}
void pci_config_write_word(u8 bus, u8 slot, u8 func, u8 offset, u16 value) {
u32 address = pci_config_address(bus, slot, func, offset);
port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address);
port_word_out(PORT_PCI_CONFIG_DATA, value);
}
void pci_config_write_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 value) {
u32 address = pci_config_address(bus, slot, func, offset);
port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address);
port_byte_out(PORT_PCI_CONFIG_DATA, value);
}
u16 pci_get_vendor_id(u8 bus, u8 slot, u8 func) {
return pci_config_read_word(bus, slot, func, PCI_CONFIG_VENDOR_ID);
}
u16 pci_get_device_id(u8 bus, u8 slot, u8 func) {
return pci_config_read_word(bus, slot, func, PCI_CONFIG_DEVICE_ID);
}
u8 pci_get_prog_if(u8 bus, u8 slot, u8 func) {
return pci_config_read_byte(bus, slot, func, PCI_CONFIG_PROG_IF);
}
u8 pci_get_header_type(u8 bus, u8 slot, u8 func) {
return pci_config_read_byte(bus, slot, func, PCI_CONFIG_HEADER_TYPE);
}
u8 pci_get_class_code(u8 bus, u8 slot, u8 func) {
return pci_config_read_byte(bus, slot, func, PCI_CONFIG_CLASS_CODE);
}
u8 pci_get_subclass_code(u8 bus, u8 slot, u8 func) {
return pci_config_read_byte(bus, slot, func, PCI_CONFIG_SUBCLASS);
}
void print_u8(u8 val) {
char buf[3];
itoa(val, buf, 16);
@@ -187,6 +160,7 @@ void pci_check_bus(u8 bus) {
pci_check_device(bus, device);
}
}
void pci_sort_drivers() {
// todo
}
@@ -253,6 +227,64 @@ void pci_print_info() {
}
}
// todo https://wiki.osdev.org/PCI
// todo https://wiki.osdev.org/PCI_IDE_Controller
void pci_init_bar(pci_device *device, u8 bar_index) {
if (device->headerType != 0x00) {
k_panics("Only header 0x00 supported for now");
return;
}
u8 offset = 0;
bar_info *bar;
switch (bar_index) {
case 0:
offset = PCI_CONFIG_BAR0;
bar = &device->bar0;
break;
case 1:
offset = PCI_CONFIG_BAR1;
bar = &device->bar1;
break;
case 2:
offset = PCI_CONFIG_BAR2;
bar = &device->bar2;
break;
case 3:
offset = PCI_CONFIG_BAR3;
bar = &device->bar3;
break;
case 4:
offset = PCI_CONFIG_BAR4;
bar = &device->bar4;
break;
case 5:
offset = PCI_CONFIG_BAR5;
bar = &device->bar5;
break;
default:
k_panics("Bar index too high");
return;
}
u32 original_address = pci_config_read_double_word(device->bus, device->slot, device->func, offset);
pci_config_write_double_word(device->bus, device->slot, device->func, offset, 0xFFFFFFFF);
u32 masked_size = pci_config_read_double_word(device->bus, device->slot, device->func, offset);
if (original_address & 0x1) {
// IO Space
bar->size = ~(masked_size & MASK_BAR_IOSPACE) + 1;
bar->address = original_address & MASK_BAR_IOSPACE;
bar->is_io_space = 1;
} else {
// Memory space
bar->size = ~(masked_size & MASK_BAR_MEMSPACE) + 1;
bar->address = original_address & 0xFFFFFFF0;
bar->is_io_space = 0;
bar->type = (original_address & 0b110) >> 1;
bar->prefetchable = (original_address & 0b111000) >> 3;
}
// todo identify conflicts, move to different address
pci_config_write_double_word(device->bus, device->slot, device->func, offset, original_address);
bar->present = 1;
}
// todo https://wiki.osdev.org/Universal_Serial_Bus if i dare

View File

@@ -21,11 +21,45 @@
#define PCI_INIT_OK 0
#define PCI_INIT_FAIL 1
#define PCI_HEADER_TYPE_MULTI_FUNC 0x80
#define PCI_HEADER_TYPE_ENDPOINT 0x00
#define PCI_HEADER_TYPE_PCI_PCI_BRIDGE 0x01
#define PCI_HEADER_TYPE_PCI_CARDBUS_BRIDGE 0x02
#define PCI_CONFIG_VENDOR_ID 0x00
#define PCI_CONFIG_DEVICE_ID 0x02
#define PCI_CONFIG_COMMAND 0x04
#define PCI_CONFIG_STATUS 0x06
#define PCI_CONFIG_REVISION_ID 0x08
#define PCI_CONFIG_PROG_IF 0x09
#define PCI_CONFIG_SUBCLASS 0x0A
#define PCI_CONFIG_CLASS_CODE 0x0B
#define PCI_CONFIG_CACHE_LINE_SIZE 0x0C
#define PCI_CONFIG_LATENCY_TIMER 0x0D
#define PCI_CONFIG_HEADER_TYPE 0x0E
#define PCI_CONFIG_BIST 0x0F
#define PCI_CONFIG_BAR0 0x10
#define PCI_CONFIG_BAR1 0x14
#define PCI_CONFIG_BAR2 0x18
#define PCI_CONFIG_BAR3 0x1C
#define PCI_CONFIG_BAR4 0x20
#define PCI_CONFIG_BAR5 0x24
#define PCI_CONFIG_CARDBUS_CIS_P 0x28
#define PCI_CONFIG_SUBSYSTEM_VENDOR_ID 0x2C
#define PCI_CONFIG_SUBSYSTEM_ID 0x2E
#define PCI_CONFIG_EXPANSION_ROM_ADDR 0x30
#define PCI_CONFIG_CAP_POINTER 0x34
#define PCI_CONFIG_INTERRUPT_LINE 0x3C
#define PCI_CONFIG_INTERRUPT_PIN 0x3D
#define PCI_CONFIG_MAX_GRANT 0x3E
#define PCI_CONFIG_MAX_LATENCY 0x3F
typedef struct pci_driver pci_driver;
typedef struct pci_device pci_device;
typedef u8 (*pci_driver_validate)(const pci_device *);
typedef u8 (*pci_driver_initialize)(const pci_device *);
typedef u8 (*pci_driver_initialize)(pci_device *);
typedef struct pci_driver {
const char *name;
@@ -40,6 +74,15 @@ typedef struct pci_driver {
pci_driver_initialize initialize;
} pci_driver;
typedef struct {
u32 address;
u32 size;
u8 present: 1;
u8 is_io_space: 1;
u8 type: 2;
u8 prefetchable: 3;
} bar_info;
typedef struct pci_device {
u8 bus;
u8 slot;
@@ -69,6 +112,12 @@ typedef struct pci_device {
};
u32 config_line_3;
};
bar_info bar0;
bar_info bar1;
bar_info bar2;
bar_info bar3;
bar_info bar4;
bar_info bar5;
const pci_driver *pci_driver;
struct {
u8 present: 1;
@@ -88,4 +137,17 @@ void pci_init_drivers();
void pci_scan();
u32 pci_config_read_double_word(u8 bus, u8 slot, u8 func, u8 offset);
u16 pci_config_read_word(u8 bus, u8 slot, u8 func, u8 offset);
u8 pci_config_read_byte(u8 bus, u8 slot, u8 func, u8 offset);
void pci_config_write_double_word(u8 bus, u8 slot, u8 func, u8 offset, u32 value);
void pci_config_write_word(u8 bus, u8 slot, u8 func, u8 offset, u16 value);
void pci_config_write_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 value);
void pci_init_bar(pci_device *device, u8 bar_index);
#endif //NEW_KERNEL_PCI_H

View File

@@ -40,3 +40,17 @@ unsigned int port_double_word_in(unsigned int port) {
void port_double_word_out(unsigned short port, unsigned int data) {
__asm__("out %%eax, %%dx" : : "a" (data), "d" (port));
}
void port_word_in_repeat(unsigned short port, unsigned short *data, int buffer_size) {
asm("rep insw"
: "+D"(data), "+c"(buffer_size)
: "d"(port)
: "memory");
}
void port_double_word_in_repeat(unsigned short port, unsigned int *data, int buffer_size) {
asm("rep insl"
: "+D"(data), "+c"(buffer_size)
: "d"(port)
: "memory");
}

View File

@@ -56,4 +56,7 @@ unsigned int port_double_word_in(unsigned int port);
void port_double_word_out(unsigned short port, unsigned int data);
void port_word_in_repeat(unsigned short port, unsigned short *data, int buffer_size);
void port_double_word_in_repeat(unsigned short port, unsigned int *data, int buffer_size);
#endif