Upload files to "drivers"
This commit is contained in:
34
drivers/gdt.c
Normal file
34
drivers/gdt.c
Normal file
@ -0,0 +1,34 @@
|
||||
#include <gdt.h>
|
||||
|
||||
|
||||
#define GDT_ENTRIES 3
|
||||
|
||||
struct gdt_entry gdt[GDT_ENTRIES];
|
||||
struct gdt_ptr gp;
|
||||
|
||||
extern void gdt_flush(uint32_t);
|
||||
|
||||
void gdt_install()
|
||||
{
|
||||
gp.limit = (sizeof(struct gdt_entry) * GDT_ENTRIES) - 1;
|
||||
gp.base = (uint32_t)&gdt;
|
||||
|
||||
gdt_set_entry(0, 0, 0, 0, 0); /* Null segment */
|
||||
gdt_set_entry(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* Code segment */
|
||||
gdt_set_entry(2, 0, 0xFFFFFFFF, 0x92, 0xCF); /* Data segment */
|
||||
|
||||
gdt_flush((uint32_t)&gp);
|
||||
}
|
||||
|
||||
void gdt_set_entry(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
|
||||
{
|
||||
gdt[num].base_low = (base & 0xFFFF);
|
||||
gdt[num].base_middle = (base >> 16) & 0xFF;
|
||||
gdt[num].base_high = (base >> 24) & 0xFF;
|
||||
|
||||
gdt[num].limit_low = (limit & 0xFFFF);
|
||||
gdt[num].granularity = (limit >> 16) & 0x0F;
|
||||
|
||||
gdt[num].granularity |= (gran & 0xF0);
|
||||
gdt[num].access = access;
|
||||
}
|
173
drivers/ide.c
Normal file
173
drivers/ide.c
Normal file
@ -0,0 +1,173 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <port_io.h>
|
||||
|
||||
#include <drivers/ide.h>
|
||||
|
||||
|
||||
static void io_delay() {
|
||||
for (int32_t i = 0; i < 1000; i++) {
|
||||
outb(0x80, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int32_t ide_wait(uint16_t io, int32_t check_drq) {
|
||||
for (int32_t i = 0; i < 5000; i++) { // 5000 ms = 5s
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (!(status & ATA_SR_BSY)) {
|
||||
if (!check_drq || (status & ATA_SR_DRQ))
|
||||
return 0;
|
||||
}
|
||||
io_delay(1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int32_t ide_wait_ready(uint16_t io) {
|
||||
for (int32_t i = 0; i < 100000; i++) {
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (!(status & ATA_SR_BSY)) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32_t ide_identify(uint8_t drive, uint16_t* buffer) {
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
uint8_t slave_bit = (drive & 1) << 4;
|
||||
|
||||
ide_wait(io, 0);
|
||||
outb(io + ATA_REG_HDDEVSEL, 0xA0 | slave_bit);
|
||||
outb(io + ATA_REG_SECCOUNT0, 0);
|
||||
outb(io + ATA_REG_LBA0, 0);
|
||||
outb(io + ATA_REG_LBA1, 0);
|
||||
outb(io + ATA_REG_LBA2, 0);
|
||||
outb(io + ATA_REG_COMMAND, 0xEC); // IDENTIFY DEVICE
|
||||
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (status == 0) return -1; // No device
|
||||
|
||||
if (ide_wait(io, 1)) return -2;
|
||||
|
||||
insw(io + ATA_REG_DATA, buffer, 256); // Read 512 bytes
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ide_initialize(void) {
|
||||
outb(ATA_PRIMARY_CTRL, 0x02); // Disable IRQs
|
||||
|
||||
uint16_t identify_buf[256];
|
||||
if (ide_identify(0, identify_buf) == 0) {
|
||||
char model[41];
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
model[i * 2 + 0] = identify_buf[27 + i] >> 8;
|
||||
model[i * 2 + 1] = identify_buf[27 + i] & 0xFF;
|
||||
}
|
||||
model[40] = 0;
|
||||
printf("Disk model: %s\n", model);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer) {
|
||||
if (sector_count == 0) return -1;
|
||||
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
uint8_t slave_bit = (drive & 1) << 4;
|
||||
|
||||
ide_wait(io, 0); // Wait for BSY to clear
|
||||
|
||||
outb(io + ATA_REG_HDDEVSEL, 0xE0 | slave_bit); // Select drive
|
||||
|
||||
// High bytes (use 0xC2 - 0xC6 offsets if you define them separately)
|
||||
outb(io + 6, (sector_count >> 8) & 0xFF); // Sector Count High
|
||||
outb(io + 7, (lba >> 40) & 0xFF); // LBA[47:40]
|
||||
outb(io + 8, (lba >> 32) & 0xFF); // LBA[39:32]
|
||||
outb(io + 9, (lba >> 24) & 0xFF); // LBA[31:24]
|
||||
|
||||
// Low bytes
|
||||
outb(io + 2, sector_count & 0xFF); // Sector Count Low
|
||||
outb(io + 3, (lba >> 0) & 0xFF); // LBA[7:0]
|
||||
outb(io + 4, (lba >> 8) & 0xFF); // LBA[15:8]
|
||||
outb(io + 5, (lba >> 16) & 0xFF); // LBA[23:16]
|
||||
|
||||
|
||||
outb(io + ATA_REG_COMMAND, ATA_CMD_READ_SECTORS_EXT);
|
||||
|
||||
uint16_t* ptr = (uint16_t*)buffer;
|
||||
for (int i = 0; i < sector_count; i++) {
|
||||
if (ide_wait(io, 1)) {
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
printf("IDE DRQ wait failed (read), status = 0x%02X\n", status);
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (status & ATA_SR_ERR) return -3;
|
||||
|
||||
insw(io + ATA_REG_DATA, ptr, 256);
|
||||
ptr += 256;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer) {
|
||||
if (sector_count == 0) return -1;
|
||||
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
uint8_t slave_bit = (drive & 1) << 4;
|
||||
|
||||
ide_wait(io, 0); // Wait for BSY to clear
|
||||
|
||||
outb(io + ATA_REG_HDDEVSEL, 0xE0 | slave_bit); // Select drive
|
||||
|
||||
// Send high bytes of sector count and LBA first
|
||||
outb(io + ATA_REG_SECCOUNT0, 0); // Sector count high byte
|
||||
outb(io + ATA_REG_LBA0, (lba >> 40) & 0xFF); // LBA[47:40]
|
||||
outb(io + ATA_REG_LBA1, (lba >> 32) & 0xFF); // LBA[39:32]
|
||||
outb(io + ATA_REG_LBA2, (lba >> 24) & 0xFF); // LBA[31:24]
|
||||
|
||||
// Send low bytes
|
||||
outb(io + ATA_REG_SECCOUNT0, sector_count); // Sector count low byte
|
||||
outb(io + ATA_REG_LBA0, (lba >> 0) & 0xFF); // LBA[7:0]
|
||||
outb(io + ATA_REG_LBA1, (lba >> 8) & 0xFF); // LBA[15:8]
|
||||
outb(io + ATA_REG_LBA2, (lba >> 16) & 0xFF); // LBA[23:16]
|
||||
|
||||
// Send write command
|
||||
outb(io + ATA_REG_COMMAND, ATA_CMD_WRITE_SECTORS_EXT); // 0x34
|
||||
|
||||
const uint16_t* ptr = (const uint16_t*)buffer;
|
||||
for (int i = 0; i < sector_count; i++) {
|
||||
if (ide_wait(io, 1)) {
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
printf("IDE DRQ wait failed (write), status = 0x%02X\n", status);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Check for drive error
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (status & ATA_SR_ERR) return -3;
|
||||
|
||||
outsw(io + ATA_REG_DATA, ptr, 256); // 256 words = 512 bytes
|
||||
inb(io + ATA_REG_STATUS); /* Dummy read */
|
||||
ptr += 256;
|
||||
}
|
||||
|
||||
// Wait for BSY=0 before issuing FLUSH CACHE
|
||||
if (ide_wait_ready(io)) return -5;
|
||||
outb(io + ATA_REG_COMMAND, 0xE7); // FLUSH CACHE
|
||||
if (ide_wait(io, 0)) {
|
||||
printf("FLUSH CACHE timeout, status=0x%02X\n", inb(io + ATA_REG_STATUS));
|
||||
return -4;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
110
drivers/idt.c
Normal file
110
drivers/idt.c
Normal file
@ -0,0 +1,110 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <idt.h>
|
||||
|
||||
#define IDT_ENTRIES 256
|
||||
|
||||
struct idt_entry idt[IDT_ENTRIES];
|
||||
struct idt_ptr idtp;
|
||||
|
||||
extern void idt_load(uint32_t);
|
||||
|
||||
void idt_install(void)
|
||||
{
|
||||
idtp.limit = sizeof(struct idt_entry) * IDT_ENTRIES - 1;
|
||||
idtp.base = (uint32_t)&idt;
|
||||
|
||||
memset(&idt, 0, sizeof(struct idt_entry) * IDT_ENTRIES);
|
||||
|
||||
/* Set entries for IRQs/ISRs here using `idt_set_entry(...)` */
|
||||
/* Example: idt_set_entry(0, (uint32_t)isr0, 0x08, 0x8E); */
|
||||
|
||||
idt_load((uint32_t)&idtp);
|
||||
}
|
||||
|
||||
void idt_set_entry(int num, uint32_t base, uint16_t sel, uint8_t flags)
|
||||
{
|
||||
idt[num].base_low = base & 0xFFFF;
|
||||
idt[num].base_high = (base >> 16) & 0xFFFF;
|
||||
|
||||
idt[num].sel = sel;
|
||||
idt[num].always0 = 0;
|
||||
idt[num].flags = flags;
|
||||
}
|
||||
|
||||
extern void isr0();
|
||||
extern void isr1();
|
||||
extern void isr2();
|
||||
extern void isr3();
|
||||
extern void isr4();
|
||||
extern void isr5();
|
||||
extern void isr6();
|
||||
extern void isr7();
|
||||
extern void isr8();
|
||||
extern void isr9();
|
||||
extern void isr10();
|
||||
extern void isr11();
|
||||
extern void isr12();
|
||||
extern void isr13();
|
||||
extern void isr14();
|
||||
extern void isr15();
|
||||
extern void isr16();
|
||||
extern void isr17();
|
||||
extern void isr18();
|
||||
extern void isr19();
|
||||
extern void isr20();
|
||||
extern void isr21();
|
||||
extern void isr22();
|
||||
extern void isr23();
|
||||
extern void isr24();
|
||||
extern void isr25();
|
||||
extern void isr26();
|
||||
extern void isr27();
|
||||
extern void isr28();
|
||||
extern void isr29();
|
||||
extern void isr30();
|
||||
extern void isr31();
|
||||
|
||||
extern void isr128();
|
||||
|
||||
|
||||
void idt_install_isrs(void)
|
||||
{
|
||||
idt_set_entry(0, (uint32_t)isr0, 0x08, 0x8E);
|
||||
idt_set_entry(1, (uint32_t)isr1, 0x08, 0x8E);
|
||||
idt_set_entry(2, (uint32_t)isr2, 0x08, 0x8E);
|
||||
idt_set_entry(3, (uint32_t)isr3, 0x08, 0x8E);
|
||||
idt_set_entry(4, (uint32_t)isr4, 0x08, 0x8E);
|
||||
idt_set_entry(5, (uint32_t)isr5, 0x08, 0x8E);
|
||||
idt_set_entry(6, (uint32_t)isr6, 0x08, 0x8E);
|
||||
idt_set_entry(7, (uint32_t)isr7, 0x08, 0x8E);
|
||||
idt_set_entry(8, (uint32_t)isr8, 0x08, 0x8E);
|
||||
idt_set_entry(9, (uint32_t)isr9, 0x08, 0x8E);
|
||||
idt_set_entry(10, (uint32_t)isr10, 0x08, 0x8E);
|
||||
idt_set_entry(11, (uint32_t)isr11, 0x08, 0x8E);
|
||||
idt_set_entry(12, (uint32_t)isr12, 0x08, 0x8E);
|
||||
idt_set_entry(13, (uint32_t)isr13, 0x08, 0x8E);
|
||||
idt_set_entry(14, (uint32_t)isr14, 0x08, 0x8E);
|
||||
idt_set_entry(15, (uint32_t)isr15, 0x08, 0x8E);
|
||||
idt_set_entry(16, (uint32_t)isr16, 0x08, 0x8E);
|
||||
idt_set_entry(17, (uint32_t)isr17, 0x08, 0x8E);
|
||||
idt_set_entry(18, (uint32_t)isr18, 0x08, 0x8E);
|
||||
idt_set_entry(19, (uint32_t)isr19, 0x08, 0x8E);
|
||||
idt_set_entry(20, (uint32_t)isr20, 0x08, 0x8E);
|
||||
idt_set_entry(21, (uint32_t)isr21, 0x08, 0x8E);
|
||||
idt_set_entry(22, (uint32_t)isr22, 0x08, 0x8E);
|
||||
idt_set_entry(23, (uint32_t)isr23, 0x08, 0x8E);
|
||||
idt_set_entry(24, (uint32_t)isr24, 0x08, 0x8E);
|
||||
idt_set_entry(25, (uint32_t)isr25, 0x08, 0x8E);
|
||||
idt_set_entry(26, (uint32_t)isr26, 0x08, 0x8E);
|
||||
idt_set_entry(27, (uint32_t)isr27, 0x08, 0x8E);
|
||||
idt_set_entry(28, (uint32_t)isr28, 0x08, 0x8E);
|
||||
idt_set_entry(29, (uint32_t)isr29, 0x08, 0x8E);
|
||||
idt_set_entry(30, (uint32_t)isr30, 0x08, 0x8E);
|
||||
idt_set_entry(31, (uint32_t)isr31, 0x08, 0x8E);
|
||||
}
|
||||
|
||||
void idt_install_syscall(void)
|
||||
{
|
||||
idt_set_entry(128, (uint32_t)isr128, 0x08, 0xEE);
|
||||
}
|
29
drivers/isr.c
Normal file
29
drivers/isr.c
Normal file
@ -0,0 +1,29 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <isr.h>
|
||||
|
||||
|
||||
void isr_handler(regs_t *r)
|
||||
{
|
||||
// Handle faults
|
||||
if (r->int_no < 32)
|
||||
{
|
||||
printf("Received interrupt: %d\n", r->int_no);
|
||||
// halt or kill task...
|
||||
}
|
||||
if (r->int_no == 128)
|
||||
{
|
||||
syscall_handler(r);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void syscall_handler(regs_t *r)
|
||||
{
|
||||
switch (r->eax) {
|
||||
case 0: printf("Syscall: Hello world\n"); break;
|
||||
case 1: printf("Syscall: value = %d\n", r->ebx); break;
|
||||
default: printf("Unknown syscall %d\n", r->eax);
|
||||
}
|
||||
}
|
||||
|
59
drivers/pci.c
Normal file
59
drivers/pci.c
Normal file
@ -0,0 +1,59 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <drivers/pci.h>
|
||||
#include <port_io.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define PCI_CONFIG_ADDRESS 0xCF8
|
||||
#define PCI_CONFIG_DATA 0xCFC
|
||||
|
||||
uint32_t pci_config_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset)
|
||||
{
|
||||
uint32_t address = 0;
|
||||
address |= (bus << 16); // Bus number (bits 23-16)
|
||||
address |= (device << 11); // Device number (bits 15-11)
|
||||
address |= (function << 8); // Function number (bits 10-8)
|
||||
address |= (offset & 0xFC); // Register offset (bits 7-0)
|
||||
address |= (1 << 31); // Enable configuration access
|
||||
|
||||
outl(PCI_CONFIG_ADDRESS, address); // Write address to PCI config space
|
||||
return inl(PCI_CONFIG_DATA); // Read data from PCI config space
|
||||
}
|
||||
|
||||
void pci_config_write(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value)
|
||||
{
|
||||
uint32_t address = 0x80000000 | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC);
|
||||
outl(PCI_CONFIG_ADDRESS, address); // Send the address to PCI config space
|
||||
outl(PCI_CONFIG_DATA, value); // Write data to PCI config space
|
||||
}
|
||||
|
||||
void pci_enumerate()
|
||||
{
|
||||
for (uint16_t bus = 0; bus < 256; bus++) // Maximum 256 buses
|
||||
{
|
||||
for (uint8_t device = 0; device < 32; device++) // Maximum 32 devices per bus
|
||||
{
|
||||
for (uint8_t function = 0; function < 8; function++) // Maximum 8 functions per device
|
||||
{
|
||||
uint32_t vendor_id = pci_config_read(bus, device, function, 0x00);
|
||||
if (vendor_id == 0xFFFFFFFF) continue; // No device present
|
||||
|
||||
uint32_t device_id = pci_config_read(bus, device, function, 0x02);
|
||||
uint32_t class_code = pci_config_read(bus, device, function, 0x08);
|
||||
printf("Found PCI device: Vendor ID: 0x%X Device ID: 0x%X Class: 0x%X\n", vendor_id, device_id, class_code);
|
||||
|
||||
printf("0x%X", class_code);
|
||||
printf(" --- ");
|
||||
printf("0x%X\n", (class_code >> 8));
|
||||
|
||||
|
||||
if ((class_code >> 8) == 0x0C) {
|
||||
printf("Found USB controller (Class: 0x%02X)\n", class_code);
|
||||
// Now, you can initialize and configure the USB controller.
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user