diff --git a/.vscode/browse.vc.db b/.vscode/browse.vc.db index 93b7121..d1f5cb5 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 2009ede..abe0035 100644 Binary files a/.vscode/browse.vc.db-shm and b/.vscode/browse.vc.db-shm differ diff --git a/src/boot/boot2.bin b/src/boot/boot2.bin deleted file mode 100644 index 4b83fe4..0000000 Binary files a/src/boot/boot2.bin and /dev/null differ diff --git a/src/boot/kernel_loader.asm b/src/boot/kernel_loader.asm index 17949f7..330eeee 100644 --- a/src/boot/kernel_loader.asm +++ b/src/boot/kernel_loader.asm @@ -4,14 +4,9 @@ kernel_sector equ 1 ; Sector containing the kernel (adjust for your kernel's l 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); +void error_handler(const char *message) ; Main kernel loading code mov bx, kernel_load_address ; Set load address diff --git a/src/cpu/cpuid.asm b/src/cpu/cpuid.asm new file mode 100644 index 0000000..1ec408c --- /dev/null +++ b/src/cpu/cpuid.asm @@ -0,0 +1,18 @@ +[bits 32] + +global cpuid + +cpuid: + ; Input parameter in EAX register + mov eax, %edi + + ; Call CPUID instruction (clobbers EAX, EBX, ECX, EDX) + cpuid + + ; Return values in output registers + mov %esi, [esp + 4] ; eax (output) + mov %edx, [esp + 8] ; ebx (output) + mov %ecx, [esp + 12] ; ecx (output) + mov %edi, [esp + 16] ; edx (output) + + ret diff --git a/src/cpu/cpuid.c b/src/cpu/cpuid.c new file mode 100644 index 0000000..cdf6b86 --- /dev/null +++ b/src/cpu/cpuid.c @@ -0,0 +1,36 @@ +#include "cpuid.h" +#include + +void cpuid(uint32_t code, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { + asm volatile ("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) : "a" (code)); +} + +void identify_cpu() { + uint32_t max_leaf; + uint32_t vendor_id[4]; + uint32_t eax, ebx, ecx, edx; + + // Get the maximum supported leaf value (CPUID function) + cpuid(0, &eax, &ebx, &ecx, &edx); + max_leaf = eax; + + // Get the vendor ID string + cpuid(0x80000000, &eax, &ebx, &ecx, &edx); + vendor_id[0] = eax; + vendor_id[1] = ebx; + vendor_id[2] = ecx; + vendor_id[3] = edx; + + // Print the vendor ID string (assuming ASCII characters) + printf("Vendor ID: %.4s%.4s\n", (char *)&vendor_id[0], (char *)&vendor_id[1]); + + // Identify basic features based on CPUID information (optional, needs further logic) + // ... (code to check specific CPU features using max_leaf and additional CPUID calls) ... + + printf("Maximum leaf value: %u\n", max_leaf); +} + +int main() { + identify_cpu(); + return 0; +} diff --git a/src/cpu/cpuid.h b/src/cpu/cpuid.h new file mode 100644 index 0000000..162ba74 --- /dev/null +++ b/src/cpu/cpuid.h @@ -0,0 +1,7 @@ +#ifndef CPUID_H +#define CPUID_H + +// Function prototypes for CPUID instruction +void cpuid(uint32_t code, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); + +#endif diff --git a/src/drivers/io/io.bin b/src/drivers/io/io.bin new file mode 100644 index 0000000..cee7ee4 Binary files /dev/null and b/src/drivers/io/io.bin differ diff --git a/src/drivers/io/io.c b/src/drivers/io/io.c index fc278da..8bfc8fc 100644 --- a/src/drivers/io/io.c +++ b/src/drivers/io/io.c @@ -15,8 +15,15 @@ LPT3: 0x3BC */ +typedef enum { + IO_SUCCESS = 0, + IO_ERROR_PORT_NOT_READY, + IO_ERROR_PORT_UNAVAILABLE, + // Add more error codes as needed +} IOErrorCode; + // Function to initialize the ports before reading or writing -void io_init() +void io_init(uint16_t port) { // Initialize COM1 port (0x3F8) - You can add more port initializations here if needed diff --git a/src/drivers/io/io.h b/src/drivers/io/io.h index 3f72309..8290eee 100644 --- a/src/drivers/io/io.h +++ b/src/drivers/io/io.h @@ -4,7 +4,7 @@ #include // Function to initialize the COM and LPT ports -void io_init(); +void io_init(uint16_t port); // Function to read from the COM port char io_read_com(); diff --git a/src/drivers/keyboard/keyboard.c b/src/drivers/keyboard/keyboard.c index 87e0b98..f45071f 100644 --- a/src/drivers/keyboard/keyboard.c +++ b/src/drivers/keyboard/keyboard.c @@ -22,14 +22,20 @@ static size_t keyboard_buffer_tail = 0; void set_interrupt_vector(uint8_t vector, void (*handler)()); void enable_interrupt(uint8_t vector); +bool keyboard_buffer_full() +{ + return (keyboard_buffer_head + 1) % KEYBOARD_BUFFER_SIZE == keyboard_buffer_tail; +} void KeyboardInterruptHandler() { - uint8_t scancode = inb(KEYBOARD_DATA_PORT); + if (!keyboard_buffer_full()) + {uint8_t scancode = inb(KEYBOARD_DATA_PORT); uint8_t keycode = translate_scancode_to_keycode(scancode); // Add scancode to buffer keyboard_buffer[keyboard_buffer_head] = scancode; keyboard_buffer_head = (keyboard_buffer_head + 1) % KEYBOARD_BUFFER_SIZE; + } } // Function to translate the combined extended scancode (first byte + second byte) @@ -134,7 +140,30 @@ uint8_t translate_scancode_to_keycode(uint8_t scancode) [0x51] = KEYCODE_PAGE_DOWN, [0x52] = KEYCODE_INSERT, [0x53] = KEYCODE_DELETE, - + [0x54] = KEYCODE_HOME, + [0x55] = KEYCODE_UP, + [0x56] = KEYCODE_PAGE_UP, + [0x57] = KEYCODE_LEFT_CTRL_BREAK, // Handle Break key (adjust if needed) + [0x58] = KEYCODE_RIGHT_SHIFT, + [0x59] = KEYCODE_NUM_LOCK, + [0x5A] = KEYCODE_SCROLL_LOCK, + [0x5B] = KEYCODE_F7, + [0x5C] = KEYCODE_F8, + [0x5D] = KEYCODE_F9, + [0x5E] = KEYCODE_F10, + [0x5F] = KEYCODE_PAUSE, // Handle Pause key (adjust if needed) + [0x60] = KEYCODE_INSERT, + [0x61] = KEYCODE_DELETE, + [0x62] = KEYCODE_RIGHT, + [0x63] = KEYCODE_END, + [0x64] = KEYCODE_DOWN, + [0x65] = KEYCODE_PAGE_DOWN, + [0x66] = KEYCODE_F11, + [0x67] = KEYCODE_F12, + [0x68] = KEYCODE_UNKNOWN, // (unused) + [0x69] = KEYCODE_LED_NUM_LOCK, // Num Lock LED status + [0x6A] = KEYCODE_LED_CAPS_LOCK, // Caps Lock LED status + [0x6B] = KEYCODE_LED_SCROLL_LOCK // ... (complete the rest based on the scancode table) [0xE0] = 0, // Handle extended scancodes (e.g., Print Screen) separately }; diff --git a/src/drivers/keyboard/keyboard.h b/src/drivers/keyboard/keyboard.h index 7579c08..9ee8c2b 100644 --- a/src/drivers/keyboard/keyboard.h +++ b/src/drivers/keyboard/keyboard.h @@ -8,6 +8,7 @@ void KeyboardInterruptHandler(); void keyboard_init(); bool keyboard_buffer_empty(); +bool keyboard_buffer_full(); uint8_t keyboard_read_scancode(); void set_interrupt_vector(uint8_t vector, void (*handler)()); void enable_interrupt(uint8_t vector); diff --git a/src/drivers/network/ne2000.c b/src/drivers/network/ne2000.c index 30877ad..2fd1393 100644 --- a/src/drivers/network/ne2000.c +++ b/src/drivers/network/ne2000.c @@ -1,3 +1,4 @@ +#include "ne2000.h" #include // NE2000 registers @@ -12,15 +13,15 @@ // ... more commands ... // Write a value to a NE2000 register -void ne2000_write_reg(uint16_t base_addr, uint8_t reg, uint8_t value) { - volatile uint8_t *ne2000_reg = (volatile uint8_t *)(base_addr + reg); - *ne2000_reg = value; +void ne2000_write_reg(uint16_t base_addr, uint8_t reg, uint8_t value) +{ + outb(base_addr + reg, value); } // Read a value from a NE2000 register -uint8_t ne2000_read_reg(uint16_t base_addr, uint8_t reg) { - volatile uint8_t *ne2000_reg = (volatile uint8_t *)(base_addr + reg); - return *ne2000_reg; +uint8_t ne2000_read_reg(uint16_t base_addr, uint8_t reg) +{ + return inb(base_addr + reg); } // Initialize the NE2000 card diff --git a/src/drivers/network/ne2000.h b/src/drivers/network/ne2000.h index 43f05bb..f760f1a 100644 --- a/src/drivers/network/ne2000.h +++ b/src/drivers/network/ne2000.h @@ -1,23 +1,26 @@ -#ifndef NE2000_H -#define NE2000_H - -#include - -// NE2000 registers -#define NE2000_COMMAND 0x00 -#define NE2000_PSTART 0x01 -#define NE2000_PSTOP 0x02 -// ... more registers ... - -// NE2000 commands -#define NE2000_CMD_START 0x02 -#define NE2000_CMD_STOP 0x01 -// ... more commands ... - -// Function prototypes -void ne2000_write_reg(uint16_t base_addr, uint8_t reg, uint8_t value); -uint8_t ne2000_read_reg(uint16_t base_addr, uint8_t reg); -void ne2000_init(uint16_t base_addr); -// ... more function prototypes ... - -#endif // NE2000_H \ No newline at end of file +#ifndef NE2000_H +#define NE2000_H + +#include + +uint8_t inb(uint16_t port); +void outb(uint16_t port, uint8_t value); + +// NE2000 registers +#define NE2000_COMMAND 0x00 +#define NE2000_PSTART 0x01 +#define NE2000_PSTOP 0x02 +// ... more registers ... + +// NE2000 commands +#define NE2000_CMD_START 0x02 +#define NE2000_CMD_STOP 0x01 +// ... more commands ... + +// Function prototypes +void ne2000_write_reg(uint16_t base_addr, uint8_t reg, uint8_t value); +uint8_t ne2000_read_reg(uint16_t base_addr, uint8_t reg); +void ne2000_init(uint16_t base_addr); +// ... more function prototypes ... + +#endif // NE2000_H diff --git a/src/filesystem/fat16/fat16.c b/src/filesystem/fat16/fat16.c index 18750d7..6cde96b 100644 --- a/src/filesystem/fat16/fat16.c +++ b/src/filesystem/fat16/fat16.c @@ -1,3 +1,32 @@ -/* -fat16 goes here -*/ \ No newline at end of file +#include "fat16.h" +#include +#include "fat16_io.h" + +// Implementation of read_sector and write_sector functions (replace with actual disk I/O) +int read_sector(uint32_t sector_number, void *buffer) +{ + // ... (Code to read a sector from disk) ... +} + +int write_sector(uint32_t sector_number, void *buffer) +{ + return read_sector_from_disk(sector_number, buffer); +} + +// Function to parse the boot sector (replace with actual parsing logic) +int parse_boot_sector(const char *device_name) +{ + // ... (Read and parse boot sector information) ... + return 0; // Or error code +} + +// Function to mount the FAT16 volume (replace with actual mounting logic) +int mount_fat16(const char *device_name) +{ + if (parse_boot_sector(device_name) != 0) + { + return -1; // Error parsing boot sector + } + // ... (Additional mounting logic) ... + return 0; +} diff --git a/src/filesystem/fat16/fat16.h b/src/filesystem/fat16/fat16.h index 18750d7..3ebd6c6 100644 --- a/src/filesystem/fat16/fat16.h +++ b/src/filesystem/fat16/fat16.h @@ -1,3 +1,26 @@ -/* -fat16 goes here -*/ \ No newline at end of file +#ifndef FAT16_H +#define FAT16_H + +#include +// Define constants for sector size, cluster size, etc. (replace with actual values) +#define SECTOR_SIZE 512 +#define BYTES_PER_CLUSTER 4096 // Example: 8 sectors per cluster + +// Define structures for FAT entry, directory entry, etc. +typedef struct +{ + // ... (FAT entry fields) ... +} fat_entry_t; + +typedef struct +{ + // ... (Directory entry fields) ... +} directory_entry_t; + +// Function prototypes for FAT operations +int read_sector(uint32_t sector_number, void *buffer); +int write_sector(uint32_t sector_number, void *buffer); +int mount_fat16(const char *device_name); // Mount the FAT16 volume +// ... (other function prototypes) ... + +#endif diff --git a/src/filesystem/fat16/fat16_io.c b/src/filesystem/fat16/fat16_io.c new file mode 100644 index 0000000..b8608cd --- /dev/null +++ b/src/filesystem/fat16/fat16_io.c @@ -0,0 +1,50 @@ +#include "fat16_io.h" +#include +// I/O port addresses for IDE controller (replace with actual values if needed) +#define PRIMARY_DATA_REGISTER 0x1F0 +#define PRIMARY_ERROR_REGISTER 0x1F1 +#define PRIMARY_COMMAND_REGISTER 0x1F2 +#define PRIMARY_SELECT_REGISTER 0x1F6 + +// Define bit masks for IDE commands +#define ATA_CMD_READ_SECTORS_WITHOUT_RETRIES 0x20 +#define ATA_CMD_READ_SECTORS_WITH_RETRIES 0xC4 + +// Function to read a sector from disk +int read_sector(uint32_t sector_number, void *buffer) +{ + // 1. Prepare for disk access + outb(PRIMARY_SELECT_REGISTER, 0x00); // Select primary IDE channel + + // 2. Wait for controller to become ready + while ((inb(PRIMARY_STATUS_REGISTER) & 0x02) == 0) + { + } // Wait for BUSY bit to clear + + // 3. Send read command with parameters + outb(PRIMARY_COMMAND_REGISTER, ATA_CMD_READ_SECTORS_WITHOUT_RETRIES); // Replace with retries if needed + outb(PRIMARY_ERROR_REGISTER, 0); // Features (usually set to 0) + outb(PRIMARY_SELECT_REGISTER, (sector_number & 0x0FF) | 0x80); // LBA low byte with LBA bit set + outb(PRIMARY_COMMAND_REGISTER, ((sector_number >> 8) & 0xFF)); // LBA mid byte + outb(PRIMARY_COMMAND_REGISTER, ((sector_number >> 16) & 0x0F) | 0xE0); // LBA high byte with select bit + outb(PRIMARY_COMMAND_REGISTER, 1); // Number of sectors to read (1 in this case) + + // 4. Wait for data transfer to complete (replace with timeout if needed) + while ((inb(PRIMARY_STATUS_REGISTER) & 0x08) == 0) + { + } // Wait for DRQ bit to set + + // 5. Read data from the data register + for (int i = 0; i < 512; ++i) + { + ((uint8_t *)buffer)[i] = inb(PRIMARY_DATA_REGISTER); + } + + // 6. Check for errors (optional, implement error handling) + if (inb(PRIMARY_STATUS_REGISTER) & 0x01) + { + return -1; // Error occurred + } + + return 0; // Success +} diff --git a/src/filesystem/fat16/fat16_io.h b/src/filesystem/fat16/fat16_io.h new file mode 100644 index 0000000..7a6bf6b --- /dev/null +++ b/src/filesystem/fat16/fat16_io.h @@ -0,0 +1,19 @@ +#ifndef FAT16_IO_H +#define FAT16_IO_H + +#include + +// I/O port addresses for IDE controller (replace with actual values if needed) +#define PRIMARY_DATA_REGISTER 0x1F0 +#define PRIMARY_ERROR_REGISTER 0x1F1 +#define PRIMARY_COMMAND_REGISTER 0x1F2 +#define PRIMARY_SELECT_REGISTER 0x1F6 + +// Define bit masks for IDE commands +#define ATA_CMD_READ_SECTORS_WITHOUT_RETRIES 0x20 +#define ATA_CMD_READ_SECTORS_WITH_RETRIES 0xC4 + +// Function prototype for reading a sector from disk +int read_sector(uint32_t sector_number, void *buffer); + +#endif // FAT16_IO_H diff --git a/src/kernel/arch/x86/gdt.bin b/src/kernel/arch/x86/gdt.bin new file mode 100644 index 0000000..79b6bde Binary files /dev/null and b/src/kernel/arch/x86/gdt.bin differ diff --git a/src/kernel/arch/x86/idt.h b/src/kernel/arch/x86/idt.h index feb83c4..b114a87 100644 --- a/src/kernel/arch/x86/idt.h +++ b/src/kernel/arch/x86/idt.h @@ -1,21 +1,32 @@ -#ifndef IDT_H -#define IDT_H - -#include "include/types.h" - -// IDT entry structure -struct idt_entry -{ - uint16_t base_lo; // Lower 16 bits of handler function address - uint16_t sel; // Kernel segment selector - uint8_t always0; // Always 0 - uint8_t flags; // Flags - uint16_t base_hi; // Upper 16 bits of handler function address -} __attribute__((packed)); - -extern struct idt_entry idt[256]; - -// Initialize the IDT -void InitializeIDT(); - -#endif /* IDT_H */ \ No newline at end of file +#ifndef IDT_H +#define IDT_H + +#include "include/types.h" + +#define IDT_ENTRY_SIZE 16 + +#if IDT_ENTRY_SIZE != 16 +#error "idt_entry structure size mismatch!" +#endif + +// IDT entry structure +struct idt_entry +{ + uint16_t base_lo; // Lower 16 bits of handler function address + uint16_t sel; // Kernel segment selector + uint8_t always0; // Always 0 + uint8_t flags; // Flags + uint16_t base_hi; // Upper 16 bits of handler function address +} __attribute__((packed)); + +extern struct idt_entry idt[256]; + +// Initialize the IDT +void InitializeIDT(); + +extern void KeyboardInterruptHandler(); +extern void TimerInterruptHandler(); + +extern void LoadIDT(struct idt_entry *entry); + +#endif /* IDT_H */ diff --git a/src/kernel/arch/x86/isr/exceptions.c b/src/kernel/arch/x86/isr/exceptions.c index f0a197a..6bd8e84 100644 --- a/src/kernel/arch/x86/isr/exceptions.c +++ b/src/kernel/arch/x86/isr/exceptions.c @@ -4,37 +4,117 @@ #include #include #include +#include + +#define PAGE_SIZE 4096 +typedef struct memory_region_t +{ + void *start_address; + size_t size; +} memory_region_t; + +// Array of allocated memory regions (example) +memory_region_t *allocated_regions; +size_t num_allocated_regions; + +jmp_buf page_fault_buffer; void DivideByZero() { // Add logic to handle Divide By Zero Exception - printf("Divide By Zero Exception\n"); + printf("Divide By Zero Exception\n"); - // Additional Exception Handling Logic: - // Example: Perform specific actions for Divide By Zero scenario - // - Log the exception to a file - FILE *logFile = fopen("error.log", "a"); - if (logFile != NULL) { - fprintf(logFile, "Divide By Zero Exception occurred\n"); - fclose(logFile); - } + // Additional Exception Handling Logic: + // Example: Perform specific actions for Divide By Zero scenario + // - Log the exception to a file + FILE *logFile = fopen("error.log", "a"); + if (logFile != NULL) + { + fprintf(logFile, "Divide By Zero Exception occurred\n"); + fclose(logFile); + } - // - Gracefully terminate the kernel - printf("Exiting kernel due to Divide By Zero Exception\n"); + // - Gracefully terminate the kernel + printf("Exiting kernel due to Divide By Zero Exception\n"); exit(EXIT_FAILURE); } void DoubleFault() { - // printf("Double Fault Exception"); + printf("Double Fault Exception\n"); + // Handle double fault exception (typically unrecoverable) + exit(EXIT_FAILURE); } -void PageFault() +// Function to check if address is within allocated memory (example) +int IsAddressInRange(uint16_t address) { - // printf("Page Fault Exception"); + for (size_t i = 0; i < num_allocated_regions; ++i) + { + if ((address >= allocated_regions[i].start_address) && + (address < (allocated_regions[i].start_address + allocated_regions[i].size))) + { + return 1; + } + } + return 0; +} + +// Placeholder for loading page from disk (replace with actual implementation) +void LoadPageFromDisk(uint16_t fault_address, void *page_buffer) +{ + // Implement logic to read page data from disk based on fault_address + // and store it in the provided page_buffer + printf("** Placeholder: Load page from disk (implementation needed) **\n"); +} + +// Placeholder for modifying paging tables (replace with actual implementation) +void NotifyCPUAboutPage(uint16_t fault_address) +{ + // Implement logic to modify paging tables based on fault_address + // to point to the loaded page data + printf("** Placeholder: Modify paging tables (implementation needed) **\n"); +} + +void PageFault(uint16_t fault_address) +{ + // 1. Identify the cause of the page fault + if (IsAddressInRange(fault_address)) + { + // Address is within allocated memory, potentially a missing page + printf("Page fault for address 0x%x (potentially missing page)\n", fault_address); + + // 2. Allocate memory for the page data (assuming OS doesn't handle this) + void *page_buffer = malloc(PAGE_SIZE); // Replace with actual page size + if (page_buffer == NULL) + { + printf("Failed to allocate memory for page data\n"); + exit(EXIT_FAILURE); + } + + // 3. Load the missing page from disk + LoadPageFromDisk(fault_address, page_buffer); + + // 4. Inform the CPU that the page is now available + NotifyCPUAboutPage(fault_address); + + // 5. Free the temporary page buffer (if applicable) + free(page_buffer); + + // 6. Resume execution with longjmp + longjmp(page_fault_buffer, 1); + } + else + { + // Handle invalid memory access + printf("Invalid memory access at 0x%x\n", fault_address); + exit(EXIT_FAILURE); // Or perform alternative error handling + } } void GeneralProtectionFault() { - // printf("General Protection Fault Exception"); + printf("General Protection Fault Exception\n"); + // Handle general protection fault exception (access violation) + exit(EXIT_FAILURE); } diff --git a/src/kernel/malloc/malloc.c b/src/kernel/malloc/malloc.c index b69d49b..92d7ac3 100644 --- a/src/kernel/malloc/malloc.c +++ b/src/kernel/malloc/malloc.c @@ -33,7 +33,6 @@ void *malloc(size_t size) } // 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