diff --git a/.vscode/browse.vc.db b/.vscode/browse.vc.db index 6ddf39b..93b7121 100644 Binary files a/.vscode/browse.vc.db and b/.vscode/browse.vc.db differ diff --git a/.vscode/browse.vc.db-shm b/.vscode/browse.vc.db-shm index c21ceaf..2009ede 100644 Binary files a/.vscode/browse.vc.db-shm and b/.vscode/browse.vc.db-shm differ diff --git a/src/boot/boot2.asm b/src/boot/boot2.asm index cf5c437..25d4288 100644 --- a/src/boot/boot2.asm +++ b/src/boot/boot2.asm @@ -40,16 +40,58 @@ start: call printstr ; Load the kernel into memory - ; ... + %include "kernel_loader.asm" - ; Set up GDT, IDT, IVT - ; ... + ; Set up IVT (GTD and IDT not used in 16 bit real mode) + ; Define interrupt handlers (replace with your actual handler code) + div_by_zero_handler: + cli + hlt + + timer_handler: + ; Your timer interrupt handler code + hlt + ret + + ; IVT entries (offset 0 for all handlers since segment 0) + times 0x100 dw 0x0000 ; Initialize unused entries + dw offset div_by_zero_handler ; Interrupt 0 (Division by Zero) + times 0x7 dw 0x0000 ; Skip unused entries + dw offset timer_handler ; Interrupt 0x8 (Timer) ; Switch to protected mode - ; ... + ; Enable Protected Mode + switch_to_protected_mode: + cli ; Disable interrupts + mov eax, cr0 ; Get current CR0 value + or eax, 0x01 ; Set PE bit (Protected Mode Enable) + mov cr0, eax ; Write modified CR0 value back ; Set up stack and start executing kernel's code - ; ... + ; Define GDT structure (replace with your actual GDT definition) + gdt_start: ; Beginning of GDT + times 5 dd 0 ; Null descriptor entries (optional) + gdt_code: ; Code segment descriptor + dw 0xffff ; Segment size (limit) + dw 0x0000 ; Segment base address (low) + db 0x0 ; Segment base address (high) + db 10011010b ; Access rights (present, readable, conforming, executable) + db 11001111b ; Access rights (long mode, 4-granularity, size) + gdt_end: ; End of GDT + gdt_descriptor: + equ gdt_end - gdt_start ; Size of GDT + dw gdt_descriptor ; Offset of GDT + dd gdt_start ; Base address of GDT + + ; Load the GDT + lgdt [gdt_descriptor] ; Load GDT descriptor into GDTR + + ; Set up Stack (replace with your actual stack segment and address) + mov ss, data_segment ; Set stack segment selector + mov esp, 0x100000 ; Set stack pointer (top of stack) + + ; Start Kernel Execution + jmp farptr kernel_entry ; Jump to kernel entry point (replace with actual address) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; printstr routine, prints the string pointed by si using int 0x10 ; diff --git a/src/boot/kernel_loader.asm b/src/boot/kernel_loader.asm new file mode 100644 index 0000000..17949f7 --- /dev/null +++ b/src/boot/kernel_loader.asm @@ -0,0 +1,28 @@ +; Define constants (adjust as needed) +boot_drive equ 0x00 ; Drive to load kernel from (usually 0 for primary) +kernel_sector equ 1 ; Sector containing the kernel (adjust for your kernel's location) +kernel_segments equ 4 ; Number of sectors to load (adjust for your kernel size) +kernel_load_address equ 0x1000 ; Memory address to load the kernel + +; ... (Function prototypes and int_13h implementation copied from previous response) +; Function prototypes for readability +; (These functions are not strictly necessary in NASM, but improve code organization) +; Prototype for BIOS disk read interrupt (INT 13h) +void int_13h(unsigned int ah, unsigned int al, unsigned int dx, unsigned int ch, unsigned int cl, unsigned int bx); + +; Function prototype for error handling or printing a message +void error_handler(const char *message); +; Main kernel loading code +mov bx, kernel_load_address ; Set load address + +; Loop to load kernel sectors +mov cx, 0 ; Initialize counter +loop_load: + int_13h(0x02, kernel_segments, boot_drive * 256 + kernel_sector, ch, cl, bx) ; Read sectors + add bx, 512 * kernel_segments ; Update load address + inc cx ; Increment counter + cmp cx, kernel_segments ; Check if all sectors loaded + jne loop_load ; Jump back if not finished + +; Success - kernel is now loaded into memory +ret ; Return to the main bootloader code \ No newline at end of file diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c index 073237e..3c70502 100644 --- a/src/drivers/bus/pci.c +++ b/src/drivers/bus/pci.c @@ -1,68 +1,169 @@ -#include "pci.h" - -#include -#include -#include - -// PCI bus controller base address -#define PCI_BASE_ADDRESS 0x0000 - -// PCI bus controller data port -#define PCI_DATA_PORT 0x00 - -// PCI bus controller command port -#define PCI_COMMAND_PORT 0x01 - -// Initialize the PCI bus -void pci_init() -{ - // Enable PCI bus master - pci_write(PCI_COMMAND_PORT, 0x04); -} - -// Detect and configure PCI devices -void pci_detect_devices() -{ - // Scan all PCI buses and devices - for (int bus = 0; bus < 256; bus++) { - for (int device = 0; device < 32; device++) { - for (int function = 0; function < 8; function++) { - uint16_t vendor_id = pci_read(bus, device, function, 0x00); - if (vendor_id != 0xFFFF) { - uint16_t device_id = pci_read(bus, device, function, 0x02); - uint8_t class_code = pci_read(bus, device, function, 0x0B); - uint8_t subclass_code = pci_read(bus, device, function, 0x0A); - uint8_t prog_if = pci_read(bus, device, function, 0x09); - uint8_t header_type = pci_read(bus, device, function, 0x0E); - uint8_t irq_line = pci_read(bus, device, function, 0x3C); - uint32_t bar0 = pci_read(bus, device, function, 0x10); - uint32_t bar1 = pci_read(bus, device, function, 0x14); - uint32_t bar2 = pci_read(bus, device, function, 0x18); - uint32_t bar3 = pci_read(bus, device, function, 0x1C); - uint32_t bar4 = pci_read(bus, device, function, 0x20); - uint32_t bar5 = pci_read(bus, device, function, 0x24); - // Add any necessary device detection and configuration code here - } - } - } - } -} - -// Read from a PCI device -uint8_t pci_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset) -{ - uint16_t port = PCI_BASE_ADDRESS | ((uint16_t)bus << 8) | ((uint16_t)device << 3) | ((uint16_t)function << 0x0B) | ((uint16_t)offset & 0xFC); - uint8_t value; - - // Read from the specified port - __asm__ volatile("inb %1, %0" : "=a"(value) : "dN"(port)); - - return value; -} - -// Write to a PCI device -void pci_write(uint16_t port, uint8_t value) -{ - // Write the specified value to the specified port - __asm__ volatile("outb %0, %1" : : "a"(value), "dN"(port)); -} +#include "pci.h" + +#include +#include +#include + +// PCI bus controller base address +#define PCI_BASE_ADDRESS 0x0000 + +// PCI bus controller data port +#define PCI_DATA_PORT 0x00 + +// PCI bus controller command port +#define PCI_COMMAND_PORT 0x01 + +// Initialize the PCI bus +void pci_init() +{ + // Enable PCI bus master + pci_write(PCI_COMMAND_PORT, 0x04); +} + +// Read from a PCI device +uint8_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset) +{ + uint16_t port = PCI_BASE_ADDRESS | ((uint16_t)bus << 8) | ((uint16_t)device << 3) | ((uint16_t)function << 0x0B) | ((uint16_t)offset & 0xFC); + uint8_t value; + + // Read from the specified port + __asm__ volatile("inb %1, %0" : "=a"(value) : "dN"(port)); + + return value; +} +// Function to write a value to a PCI configuration register +void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint8_t value) +{ + // ... (your existing implementation for setting up the port address) + + // Write the specified value to the specified offset + __asm__ volatile("outb %0, %1" : : "a"(value), "dN"(port)); +} + +// Set the PCI Latency Timer for a device +void pci_set_latency(uint8_t bus, uint8_t device, uint8_t function, uint8_t value) +{ + pci_write_config(bus, device, function, 0x0D, value); +} + +uint16_t pci_read_config_word(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset) +{ + uint16_t value = 0; + value |= pci_read_config(bus, device, function, offset); + value |= (uint16_t)pci_read_config(bus, device, function, offset + 1) << 8; + return value; +} + +// Function to read a 32-bit value from PCI configuration space +uint32_t pci_read_config_dword(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset) +{ + uint32_t value = 0; + value |= pci_read_config(bus, device, function, offset); + value |= (uint32_t)pci_read_config(bus, device, function, offset + 1) << 8; + value |= (uint32_t)pci_read_config(bus, device, function, offset + 2) << 16; + value |= (uint32_t)pci_read_config(bus, device, function, offset + 3) << 24; + return value; +} + +// Structure to hold information about a BAR +typedef struct +{ + uint8_t type; // Memory (0) or I/O (1) + uint32_t base; // Base address + uint32_t size; // Size of the region (in bytes) +} bar_t; + +// Function to decode a BAR register +bar_t pci_decode_bar(uint32_t bar_value) +{ + bar_t bar; + bar.type = (bar_value & 1) ? 1 : 0; // Check bit 0 for type + + // Extract address and size information (logic might need adjustment) + bar.base = bar_value & ~((1 << 0) | (1 << 1)); // Mask out type and prefetchable bits + + // Size calculation needs further processing based on Memory Space Enable bit (bit 3) + uint32_t size_bits = bar_value & ~(bar.base | (1 << 0) | (1 << 1) | (1 << 3)); + if (size_bits == 0) + { // Handle case where size is 0 + bar.size = 0; + } + else + { + // Calculate size based on the number of leading 1s in size_bits + int num_leading_ones = 0; + while (size_bits && (size_bits & 0x80000000)) + { + num_leading_ones++; + size_bits <<= 1; + } + bar.size = 1 << num_leading_ones; + } + + return bar; +} +// Detect and configure PCI devices +void pci_detect_devices() +{ + // Scan all PCI buses and devices + for (int bus = 0; bus < 256; bus++) + { + for (int device = 0; device < 32; device++) + { + for (int function = 0; function < 8; function++) + { + uint16_t vendor_id = pci_read(bus, device, function, 0x00); + if (vendor_id != 0xFFFF) + { + uint16_t device_id = pci_read(bus, device, function, 0x02); + + // Lookup vendor and device ID in a database (e.g., PCI.ids) + const char *device_name = lookup_device_name(vendor_id, device_id); + + if (device_name != NULL) + { + // Device identified! + printk("Found PCI device: %s (vendor: %04x, device: %04x)\n", + device_name, vendor_id, device_id); + + // ... (Optional) Further configuration based on device type + } + else + { + // Device not found in database, handle unknown device + printk("Found unknown PCI device (vendor: %04x, device: %04x)\n", + vendor_id, device_id); + } + + // Continue reading other registers, handling BARs, etc. + uint8_t class_code = pci_read(bus, device, function, 0x0B); + uint8_t subclass_code = pci_read(bus, device, function, 0x0A); + uint8_t prog_if = pci_read(bus, device, function, 0x09); + uint8_t header_type = pci_read(bus, device, function, 0x0E); + uint8_t irq_line = pci_read(bus, device, function, 0x3C); + + // ... (rest of your code for handling BARs, etc.) + } + } + } + } +} + +// Read from a PCI device +uint8_t pci_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset) +{ + uint16_t port = PCI_BASE_ADDRESS | ((uint16_t)bus << 8) | ((uint16_t)device << 3) | ((uint16_t)function << 0x0B) | ((uint16_t)offset & 0xFC); + uint8_t value; + + // Read from the specified port + __asm__ volatile("inb %1, %0" : "=a"(value) : "dN"(port)); + + return value; +} + +// Write to a PCI device +void pci_write(uint16_t port, uint8_t value) +{ + // Write the specified value to the specified port + __asm__ volatile("outb %0, %1" : : "a"(value), "dN"(port)); +} diff --git a/src/drivers/display/vga.c b/src/drivers/display/vga.c index eafebb9..4c158d6 100644 --- a/src/drivers/display/vga.c +++ b/src/drivers/display/vga.c @@ -7,30 +7,31 @@ #include uint8_t *map_memory(uint32_t base_address, uint32_t size); - -#define VGA_MEMORY_ADDRESS 0xA0000 -#define VGA_MEMORY_SIZE 0x60000 -#define VGA_MEMORY_BASE_ADDRESS 0xA0000 - -#define COLOR_GREEN 0x00FF00 - uint8_t *vga_memory = (uint8_t *)VGA_MEMORY_ADDRESS; static uint16_t vga_width = VGA_WIDTH; static uint16_t vga_height = VGA_HEIGHT; static uint8_t vga_depth = VGA_DEPTH; uint8_t *framebuffer = (uint8_t *)vga_memory; +uint8_t *map_memory(uint32_t base_address, uint32_t size); +uint8_t read_vga_register(uint16_t register_address); +int inb(uint16_t port); +void outb(uint16_t port, uint8_t data); +uint16_t width; +uint32_t get_vga_memory_address(); // Set a specific pixel color (assuming RGB format) int x = 10; int y = 20; int color = 0x00FF00; // Green -framebuffer[y * width + x * 3] = (color & 0x00FF) >> 8; // Green value -framebuffer[y * width + x * 3 + 1] = color & 0x00FF; // Blue value -framebuffer[y * width + x * 3 + 2] = color >> 8; // Red value +void some_function() +{ + // ... other code ... + uint8_t misc_output_value = read_vga_register(0x3C2); // Initialize here + // ... use misc_output_value ... +} uint8_t misc_output_value = read_vga_register(0x3C2); - // Check bit 1 to determine text mode (0) or graphics mode (1) if (misc_output_value & 0x02) { @@ -53,7 +54,7 @@ uint32_t get_vga_memory_address() void vga_init(void) { // Initialize VGA driver here - vga_memory = (uint8_t *)map_memory(VGA_MEMORY_BASE_ADDRESS, VGA_MEMORY_SIZE); + vga_memory = (uint8_t *)map_memory(VGA_MEMORY_ADDRESS, VGA_MEMORY_SIZE); if (vga_memory == NULL) { @@ -61,38 +62,43 @@ void vga_init(void) fprintf(stderr, "Failed to map VGA Memory\n"); } - framebuffer = vga_memory; + framebuffer = (uint8_t *)vga_memory; } // Replace with actual functions to read VGA registers based on your system uint8_t read_vga_register(uint16_t register_address) { - uint8_t value = inb(register_address); // Read from the specified port - return value; + uint8_t value = inb(register_address); // Read from the specified port + return value; } -int inb(uint16_t port) { - // Implement port access logic (replace with system-specific function) +int inb(uint16_t port) +{ + uint8_t value; + __asm volatile("inb %1, %0" : "=a"(value) : "d"(port)); + return value; } -void outb(uint16_t port, uint8_t data) { - +void outb(uint16_t port, uint8_t data) +{ + __asm volatile("outb %0, %1" : : "a"(data), "d"(port)); } void vga_set_resolution(uint16_t width, uint16_t height, uint8_t depth) { - // Set VGA resolution here - // Example (replace with actual register values and writes based on your system): // Sequencer unlock outb(0x3C4, 0x01); outb(0x3C5, 0x01); // Set specific CRTC registers for desired resolution and refresh rate - // ... (write to specific VGA registers using outb) + outb(0x3D4, 0x01); // Horizontal total + outb(0x3D5, 0x5F); // ... + // ... (set other CRTC registers) // Graphics controller registers for memory access - // ... (write to specific VGA registers using outb) + outb(0x3CE, 0x05); // Graphics mode + outb(0x3CF, 0x03); } void vga_draw_pixel(uint16_t x, uint16_t y, uint8_t color) @@ -100,6 +106,9 @@ void vga_draw_pixel(uint16_t x, uint16_t y, uint8_t color) // Draw a pixel on the screen at (x, y) with the given color uint32_t offset = y * vga_width + x; vga_memory[offset] = color; + framebuffer[y * width + x * 3] = (color & 0x00FF) >> 8; // Green value + framebuffer[y * width + x * 3 + 1] = color & 0x00FF; // Blue value + framebuffer[y * width + x * 3 + 2] = color >> 8; // Red value } void vga_clear_screen(uint8_t color) diff --git a/src/drivers/display/vga.h b/src/drivers/display/vga.h index c2edeb1..b02f228 100644 --- a/src/drivers/display/vga.h +++ b/src/drivers/display/vga.h @@ -3,14 +3,22 @@ #include -typedef struct { - uint16_t width; - uint16_t height; - uint8_t depth; - // Add other relevant settings like color palette, etc. +#define VGA_WIDTH 320 // Replace with the desired width +#define VGA_HEIGHT 200 // Replace with the desired height +#define VGA_DEPTH 8 // Replace with the desired color depth (e.g., 8 for 256 colors) +#define VGA_MEMORY_ADDRESS 0xA0000 // Move to header file +#define VGA_MEMORY_SIZE 0x60000 // Move to header file +#define COLOR_GREEN 0x00FF00 +#define VGA_MAP_MEM_ERROR -1 + +typedef struct +{ + uint16_t width; + uint16_t height; + uint8_t depth; + // Add other relevant settings like color palette, etc. } vga_display_settings_t; -void vga_init(); void vga_set_resolution(uint16_t width, uint16_t height, uint8_t depth); void vga_draw_pixel(uint16_t x, uint16_t y, uint8_t color); void vga_clear_screen(uint8_t color); diff --git a/src/kernel/acpi.c b/src/kernel/acpi.c index e69de29..9512aea 100644 --- a/src/kernel/acpi.c +++ b/src/kernel/acpi.c @@ -0,0 +1,33 @@ +#include "acpi.h" +#include +#include + +// Function prototypes (implementations below) +acpi_fadt_t *acpi_find_fadt(); +int acpi_validate_rsdt(acpi_fadt_t *fadt); + +// ... (Add other ACPI functions for table parsing, resource access, etc.) + +// Function to locate the FADT table +acpi_fadt_t *acpi_find_fadt() { + // Read the RSDP (Root System Description Pointer) signature and checksum + // at the ACPI base address. + acpi_fadt_t *rsdp = (acpi_fadt_t *)ACPI_BASE; + if (rsdp->signature != *(uint32_t *)"RSDT" && rsdp->signature != *(uint32_t *)"XSDT") { + return NULL; // Not a valid ACPI signature + } + if (rsdp->checksum != 0) { + return NULL; // Invalid checksum + } + + // Check ACPI revision and use appropriate table address (RSDT or XSDT) + return (acpi_fadt_t *)(rsdp->revision >= 2 ? rsdp->xsdt_addr : rsdp->rsdp_addr); +} + +// Function to validate the RSDT (or XSDT) table +int acpi_validate_rsdt(acpi_fadt_t *fadt) { + // Check table length and perform basic integrity checks + // ... + + return 0; // Assuming success, replace with actual validation logic +} diff --git a/src/kernel/acpi.h b/src/kernel/acpi.h index e69de29..38d4ac7 100644 --- a/src/kernel/acpi.h +++ b/src/kernel/acpi.h @@ -0,0 +1,25 @@ +#ifndef ACPI_H +#define ACPI_H + +#include + +// ACPI base address (replace with actual value) +#define ACPI_BASE 0xE0000000 + +// ACPI Fixed ACPI Description Table (FADT) structure +typedef struct +{ + uint32_t signature; // Signature ("RSDT" or "XSDT") + uint32_t length; // Length of the table + uint8_t revision; // ACPI revision + uint8_t checksum; // Checksum (should be zero) + uint32_t oem_id[6]; // OEM ID string + uint8_t oem_revision[8]; // OEM revision string + uint32_t rsdp_addr; // Physical address of RSDT (for ACPI 1.0) + uint32_t xsdt_addr; // Physical address of XSDT (for ACPI 2.0+) + // ... other FADT fields (refer to ACPI specification) +} __attribute__((packed)) acpi_fadt_t; + +// ... (Add other ACPI table structure definitions as needed) + +#endif /* ACPI_H */ diff --git a/src/kernel/ahci.c b/src/kernel/ahci.c new file mode 100644 index 0000000..204c9cc --- /dev/null +++ b/src/kernel/ahci.c @@ -0,0 +1,36 @@ +#include "ahci.h" +#include + +// Function prototypes (implementations below) +uint32_t ahci_read_reg(uint32_t offset); +void ahci_write_reg(uint32_t offset, uint32_t value); + +// Function to send an AHCI command +int ahci_send_command(uint32_t cmd_slot, ahci_cmd_t *cmd); + +// ... (Add other AHCI functions for initialization, status checks, etc.) + +// Helper function to read a 32-bit register +uint32_t ahci_read_reg(uint32_t offset) +{ + return *(volatile uint32_t *)(HBA_PORT_BASE + offset); +} + +// Helper function to write a 32-bit register +void ahci_write_reg(uint32_t offset, uint32_t value) +{ + *(volatile uint32_t *)(HBA_PORT_BASE + offset) = value; +} + +// Function to send an AHCI command +int ahci_send_command(uint32_t cmd_slot, ahci_cmd_t *cmd) +{ + // Implement logic to write the command list entry to appropriate registers + // ... + + // Wait for command completion (check relevant AHCI registers) + // ... + + // Return status based on completion and error checking + // ... +} diff --git a/src/kernel/ahci.h b/src/kernel/ahci.h new file mode 100644 index 0000000..037ba85 --- /dev/null +++ b/src/kernel/ahci.h @@ -0,0 +1,28 @@ +#ifndef AHCI_H +#define AHCI_H + +#include + +// Base address of AHCI registers (replace with actual value) +#define HBA_PORT_BASE 0x10000000 + +// AHCI register offsets +#define HBA_CAP 0x00 // Host Capabilities +#define HBA_PI 0x0C // Port Interrupt +#define HBA_ISR 0x20 // Interrupt Status +#define HBA_IMR 0x30 // Interrupt Mask +#define HBA_CMD 0x34 // Command List Head +#define HBA_CMD_SLOT_0 0 // First command slot + +// AHCI command list structure +typedef struct +{ + uint32_t cmd_sts; // FIS (Frame in flight) + uint32_t prdt_addr; // Physical address of PRDT (SATA FIS) + uint32_t prdt_length; // Length of PRDT in bytes + uint32_t reserved[4]; // Reserved (set to 0) +} __attribute__((packed)) ahci_cmd_t; + +// ... (Add other AHCI register definitions and structures as needed) + +#endif /* AHCI_H */ diff --git a/src/kernel/arch/x86/idt.asm b/src/kernel/arch/x86/idt.asm index e2e796e..09bfeab 100644 --- a/src/kernel/arch/x86/idt.asm +++ b/src/kernel/arch/x86/idt.asm @@ -1,7 +1,12 @@ -global LoadIDT +global LoadIDT ; Declare function as global + +_offset idt db 0 + +section .text ; Code section + +%include "idt.h" -section .text LoadIDT: -mov eax, [offset idt] ; Get the IDT address - LIDT [eax + 8*0x33] ; Load only the timer interrupt entry (offset 8*0x33) - RET \ No newline at end of file + mov eax, [esp + 4] ; Get IDT address (ensure offset idt is defined) + LIDT [eax] ; Load timer interrupt entry (check for correct brackets) + RET ; Return from function \ No newline at end of file diff --git a/src/kernel/arch/x86/include/types.c b/src/kernel/arch/x86/include/types.c index 56fa289..b4c4336 100644 --- a/src/kernel/arch/x86/include/types.c +++ b/src/kernel/arch/x86/include/types.c @@ -1,18 +1,19 @@ -#include "./types.h" - -void gdt_set_entry(gdt_entry_t *entry, uint32_t base, uint32_t limit, - uint16_t flags) -{ - entry->base = base; - entry->limit = limit; - entry->flags = flags; -} - -void idt_set_entry(idt_entry_t *entry, uint32_t base, uint16_t selector, - uint16_t flags) -{ - entry->base_low = base & 0xFFFF; - entry->base_high = (base >> 16) & 0xFFFF; - entry->selector = selector; - entry->flags = flags; -} \ No newline at end of file +#include "./types.h" +#include + +void gdt_set_entry(gdt_entry_t *entry, uint32_t base, uint32_t limit, + uint16_t flags) +{ + entry->base = base; + entry->limit = limit; + entry->flags = flags; +} + +void idt_set_entry(idt_entry_t *entry, uint32_t base, uint16_t selector, + uint16_t flags) +{ + entry->base_low = base & 0xFFFF; + entry->base_high = (base >> 16) & 0xFFFF; + entry->selector = selector; + entry->flags = flags; +} diff --git a/src/kernel/arch/x86/isr/isr.asm b/src/kernel/arch/x86/isr/isr.asm index 142d6ef..4d7d42b 100644 --- a/src/kernel/arch/x86/isr/isr.asm +++ b/src/kernel/arch/x86/isr/isr.asm @@ -1,7 +1,13 @@ -section .text -global isr_handler -global _isr_stub +%include "isr.h" +section .data + ISR_HAS_ERROR_CODE equ 1 + ISR_IS_HARDWARE_INTERRUPT equ 1 + +section .text +global isr_stub + +global _isr_stub _isr_stub: ; Save context PUSHAD ; Preserve all general-purpose registers @@ -10,41 +16,36 @@ _isr_stub: CLI ; Align stack to 16-byte boundary for performance (if needed) - ; AND ESP, 0xFFFFFFF0 + AND ESP, 0xFFFFFFF0 ; Check if an error code is present (typically in EAX) ; This is just a placeholder, actual implementation depends on your IDT setup CMP BYTE [ISR_HAS_ERROR_CODE], 1 JNE no_error_code PUSH DWORD [ESP + 32] ; Push error code - JMP done_pushing_error_code + no_error_code: - PUSH DWORD 0 ; Push a dummy error code -done_pushing_error_code: - - ; Push interrupt number onto the stack - MOV EAX, [ESP + 36] ; Move interrupt number to EAX (accounting for the dummy/error code) - PUSH EAX ; Interrupt number - - ; Call isr_handler + PUSH DWORD 0 + MOV EAX, [ESP + 36] + PUSH EAX + ; Call the C ISR handler CALL isr_handler - ; Send EOI to PIC only if it's a hardware interrupt - ; This is just a placeholder, actual implementation depends on your IDT setup - CMP BYTE [ISR_IS_HARDWARE_INTERRUPT], 1 - JNE skip_eoi - MOV AL, 0x20 - OUT 0x20, AL + MOV AL, BYTE [ISR_IS_HARDWARE_INTERRUPT] + CMP AL, 1 + + JNE skip_eoi + MOV AL, 0x20 + OUT 0x20, AL + skip_eoi: + POPAD ; Enable interrupts STI ; Clean up the stack - ADD ESP, 8 ; Remove error code and interrupt number - - ; Restore context - POPAD ; Restore all general-purpose registers + ADD ESP, 16 ; Remove error code and interrupt number ; Return from interrupt IRETD \ No newline at end of file diff --git a/src/kernel/arch/x86/isr/isr.c b/src/kernel/arch/x86/isr/isr.c index 5f8d426..7473e04 100644 --- a/src/kernel/arch/x86/isr/isr.c +++ b/src/kernel/arch/x86/isr/isr.c @@ -1,4 +1,5 @@ #include "isr.h" +#include void isr_handler(struct isr_regs regs) { switch(regs.int_no) { diff --git a/src/kernel/arch/x86/isr/isr.h b/src/kernel/arch/x86/isr/isr.h index 3ca0c56..99fb512 100644 --- a/src/kernel/arch/x86/isr/isr.h +++ b/src/kernel/arch/x86/isr/isr.h @@ -2,6 +2,7 @@ #define ISR_H #include "../include/types.h" +#include enum ISR_Vector { @@ -33,6 +34,7 @@ struct isr_regs esp_at_signal; // Pushed by the processor automatically }; +void isr_handler(struct isr_regs regs); // Structure for storing register values during an ISR struct idt_regs { diff --git a/src/kernel/malloc/kmalloc.c b/src/kernel/malloc/kmalloc.c index 096d394..6fb1775 100644 --- a/src/kernel/malloc/kmalloc.c +++ b/src/kernel/malloc/kmalloc.c @@ -1,43 +1,108 @@ #include "kmalloc.h" static void *kernel_heap_start; // Start of the kernel heap -static void *kernel_heap_end; // End of the kernel heap +static void *kernel_heap_end; // End of the kernel heap +static struct memory_block *free_blocks = NULL; -void init_kernel_heap(void *start, void *end) { - kernel_heap_start = start; - kernel_heap_end = end; - // Initialize the kernel heap here +struct memory_block +{ + size_t size; + struct memory_block *next; +}; + +void mark_as_used_kernel(void *ptr, size_t size) +{ + // Since we're using a linked list, there's no specific action needed + // to mark the block itself as used (it's already removed from the list). + // However, you might want to perform additional bookkeeping for debugging + // or memory analysis purposes. + + // Example: Update some metadata associated with the allocated block + // ((struct memory_block *)ptr)->used = true; // Assuming a 'used' flag + + // This function can be potentially empty if you don't require specific + // actions for marking a block as used in the kernel. } -void *kmalloc(size_t size) { - if (kernel_heap_start == NULL || kernel_heap_end == NULL) { - // Kernel heap not initialized, cannot allocate - return NULL; - } +void mark_as_free_kernel(void *ptr) +{ + // Cast the pointer to a memory_block structure + struct memory_block *block = (struct memory_block *)ptr; - // Align the size to the word size for efficiency - size += sizeof(size_t) - 1; - size &= ~(sizeof(size_t) - 1); - - // Search for a free block of sufficient size - // This is a placeholder for the actual algorithm - void *block = find_free_kernel_block(size); - if (block != NULL) { - // Mark the block as used - mark_as_used_kernel(block, size); - return block; - } - - // No suitable block found, out of memory - return NULL; + // Add the block to the beginning of the free block list + block->next = free_blocks; + free_blocks = block; } -void kfree(void *ptr) { - if (ptr == NULL) { - return; - } +void init_kernel_heap(void *start, void *end) +{ + kernel_heap_start = start; + kernel_heap_end = end; - // Mark the block as free - // This is a placeholder for the actual algorithm - mark_as_free_kernel(ptr); + free_blocks = (struct memory_block *)start; + free_blocks->size = (size_t)(end - start); + free_blocks->next = NULL; + + // You'll need to replace this placeholder with logic to split the + // initial block into smaller ones based on your requirements. +} + +void *find_free_kernel_block(size_t size) +{ + // First-fit algorithm (can be optimized with different strategies) + struct memory_block *current = free_blocks; + while (current != NULL) + { + if (current->size >= size) + { + // Found a suitable block + return current; + } + current = current->next; + } + // No suitable block found + return NULL; +} + +void *kmalloc(size_t size) +{ + if (kernel_heap_start == NULL || kernel_heap_end == NULL) + { + // Kernel heap not initialized, cannot allocate + return NULL; + } + + // Align the size to the word size for efficiency + size += sizeof(size_t) - 1; + size &= ~(sizeof(size_t) - 1); + + // Search for a free block of sufficient size + void *block = find_free_kernel_block(size); + if (block != NULL) + { + // Mark the block as used + mark_as_used_kernel(block, size); + + // This is a placeholder for splitting the block if necessary + // You'll need to implement logic to potentially split the block + // into a used part of size 'size' and a remaining free block + // if the block size is significantly larger than 'size'. + + return block; + } + + // No suitable block found, out of memory + return NULL; +} + +void kfree(void *ptr) +{ + if (ptr == NULL) + { + return; + } + + // Mark the block as free + // This is a placeholder for the actual algorithm + mark_as_free_kernel(ptr); } diff --git a/src/kernel/malloc/kmalloc.h b/src/kernel/malloc/kmalloc.h index 8843c4f..bd88c5c 100644 --- a/src/kernel/malloc/kmalloc.h +++ b/src/kernel/malloc/kmalloc.h @@ -1,9 +1,12 @@ -#ifndef KMALLOC_H -#define KMALLOC_H +#ifndef KMALLOC_H_ // Corrected guard macro +#define KMALLOC_H_ #include // For size_t void *kmalloc(size_t size); void kfree(void *ptr); -#endif // KMALLOC_H +void mark_as_used_kernel(void *ptr, size_t size); +void mark_as_free_kernel(void *ptr); + +#endif /* KMALLOC_H_ */ diff --git a/src/kernel/malloc/malloc.c b/src/kernel/malloc/malloc.c index 484c8d6..b69d49b 100644 --- a/src/kernel/malloc/malloc.c +++ b/src/kernel/malloc/malloc.c @@ -10,6 +10,20 @@ void init_heap(void *start, void *end) // Initialize the heap here } +void *find_free_block(size_t size) { + // Implementation is similar to find_free_kernel_block + struct memory_block *current = free_blocks; + while (current != NULL) { + if (current->size >= size) { + return current; + } + current = current->next; + } + + // No suitable block found + return NULL; +} + void *malloc(size_t size) { if (heap_start == NULL || heap_end == NULL) diff --git a/src/kernel/malloc/malloc.h b/src/kernel/malloc/malloc.h index 7ae3800..728d4be 100644 --- a/src/kernel/malloc/malloc.h +++ b/src/kernel/malloc/malloc.h @@ -6,4 +6,6 @@ void *malloc(size_t size); void free(void *ptr); +void *find_free_block(size_t size); + #endif // MALLOC_H diff --git a/src/kernel/timer.c b/src/kernel/timer.c index 246aae4..5abd326 100644 --- a/src/kernel/timer.c +++ b/src/kernel/timer.c @@ -1,3 +1,26 @@ -/* -timer functions go here -*/ \ No newline at end of file +#include +#include "timer.h" + +// Function to send a byte to an I/O port +void outb(uint16_t port, uint8_t data) { + __asm__ volatile ("outb %b, %w" : : "a" (data), "d" (port)); +} + +// Function to initialize the timer with a desired frequency +void init_timer(uint32_t frequency) { + // Calculate the divisor based on the desired frequency + uint16_t divisor = 1193180 / frequency; + + // Send the mode and divisor byte to the timer control port + outb(IOPORT_TIMER_CONTROL, TIMER_CTRL_SELECT_0 | TIMER_MODE_3 | TIMER_CTRL_BINARY); + outb(IOPORT_TIMER_0, (uint8_t) (divisor & 0xFF)); + outb(IOPORT_TIMER_0, (uint8_t) ((divisor >> 8) & 0xFF)); +} + +// Function to wait for a specified number of microseconds +void wait_us(uint32_t microseconds) { + uint32_t count = microseconds * 10; // Adjust for desired resolution (1 count = 100ns) + while (count--) { + // Implement a short delay loop here (e.g., empty loop or reading the PIT) + } +} diff --git a/src/kernel/timer.h b/src/kernel/timer.h index 246aae4..0146f01 100644 --- a/src/kernel/timer.h +++ b/src/kernel/timer.h @@ -1,3 +1,37 @@ -/* -timer functions go here -*/ \ No newline at end of file +Here's a breakdown of how to create timer.c and timer.h compatible with the 8253 for x86 32-bit protected mode on 386/486 processors: + +1. timer.h: + +This header file will contain function prototypes, constants, and any data structures you might need for interacting with the 8253 timer. Here's an example: +C + +#ifndef TIMER_H +#define TIMER_H + +#include + +// I/O port addresses for the 8253 +#define IOPORT_TIMER_CONTROL 0x43 +#define IOPORT_TIMER_0 0x40 + +// Timer modes (refer to 8253 documentation for details) +#define TIMER_MODE_0 0x00 +#define TIMER_MODE_1 0x40 +#define TIMER_MODE_2 0x80 +#define TIMER_MODE_3 0xC0 + +// Timer control bits (refer to 8253 documentation for details) +#define TIMER_CTRL_SELECT_0 0x01 +#define TIMER_CTRL_SELECT_1 0x02 +#define TIMER_CTRL_SELECT_2 0x04 +#define TIMER_CTRL_MODE 0x30 +#define TIMER_CTRL_BINARY 0x00 +#define TIMER_CTRL_BCD 0x40 +#define TIMER_CTRL_ONE_SHOT 0x80 +#define TIMER_CTRL_CONTINOUS 0x00 + +// Function prototypes +void init_timer(uint32_t frequency); +void wait_us(uint32_t microseconds); + +#endif /* TIMER_H */