From a82a7aa1a4559d3e4b838f7f129266c20cc50ebd Mon Sep 17 00:00:00 2001 From: slinky55 Date: Sun, 21 Jun 2026 16:57:16 -0500 Subject: [PATCH] still working on ata :( --- compile_commands.json | 17 ++++ kernel/common_stubs.S | 32 ++++++- kernel/drivers/atapi/ata.c | 92 +++++++++++++++++++- kernel/drivers/atapi/ata.h | 143 ++++++++++++++++++++++++++++--- kernel/drivers/atapi/ata_stubs.S | 97 ++++++++++++++++++--- 5 files changed, 353 insertions(+), 28 deletions(-) diff --git a/compile_commands.json b/compile_commands.json index e19f5ec..8e89d91 100644 --- a/compile_commands.json +++ b/compile_commands.json @@ -15,5 +15,22 @@ "directory": "/home/slinky/source/RockOS", "file": "/home/slinky/source/RockOS/kernel/drivers/atapi/ata.c", "output": "/home/slinky/source/RockOS/obj/kernel/drivers/atapi/ata.o" + }, + { + "arguments": [ + "/home/slinky/opt/cross/bin/i686-elf-gcc", + "-c", + "-ffreestanding", + "-O2", + "-Wall", + "-Wextra", + "-Ikernel", + "-o", + "obj/kernel/drivers/atapi/ata_stubs.o", + "kernel/drivers/atapi/ata_stubs.S" + ], + "directory": "/home/slinky/source/RockOS", + "file": "/home/slinky/source/RockOS/kernel/drivers/atapi/ata_stubs.S", + "output": "/home/slinky/source/RockOS/obj/kernel/drivers/atapi/ata_stubs.o" } ] diff --git a/kernel/common_stubs.S b/kernel/common_stubs.S index a6c2f5e..77c5da2 100644 --- a/kernel/common_stubs.S +++ b/kernel/common_stubs.S @@ -1,5 +1,6 @@ .code32 -.section .text +.section .text + .global disable_interrupts disable_interrupts: cli @@ -37,4 +38,31 @@ liftoff: xor %eax, %eax xor %edx, %edx - iret \ No newline at end of file + iret + +.global outb +outb: + push %ebp + mov %esp, %ebp + + # 8(%ebp) port + # 12(%ebp) data + mov 8(%ebp), %edx + mov 12(%ebp), %eax + outb %al, %dx + + leave + ret + +.global inb +inb: + push %ebp + mov %esp, %ebp + + # 8(%ebp) port + mov 8(%ebp), %edx + xor %eax, %eax + inb %dx, %al + + leave + ret \ No newline at end of file diff --git a/kernel/drivers/atapi/ata.c b/kernel/drivers/atapi/ata.c index c72f802..422c932 100644 --- a/kernel/drivers/atapi/ata.c +++ b/kernel/drivers/atapi/ata.c @@ -31,12 +31,96 @@ void scan_drives() { ide_devices[0].device = IDE_DRIVE_MASTER; ide_devices->type = type; - atapi_identify_data_t* ident_result = (atapi_identify_data_t*)secondary_master_info_buffer; + atapi_identify_t* ident_result = (atapi_identify_t*)secondary_master_info_buffer; ide_devices->ident_info_struct = (void*)ident_result; - kprintf("Detected ATAPI master device on secondary bus\n"); + kprintf("Assigned ATAPI master device on secondary bus to drive %d\n", 0); + uint8_t buf[2048]; + int rtn = read_atapi(IDE_SECONDARY_IO_BASE, IDE_DRIVE_MASTER, 0x10, 1, (uint16_t*)buf); + if (rtn < 0) { + if (rtn == -1) { + kprintf("Read error, failed to send command\n"); + } + + if (rtn == -2) { + kprintf("Read error, failed to read sector\n"); + } - fix_ata_string(ident_result->model_num, 40); - kprintf("Model Number: %s\n", ident_result->model_num); + kprintf("Read error\n"); + return; + } + + kprintf("Read first sector of drive\n"); + + if (buf[0] != 0x01) { + kprintf("First byte not valid for ISO drive\n"); + return; + } + + if (buf[1] != 'C' || buf[2] != 'D') { + kprintf("Magic bytes are invalid for ISO drive\n"); + return; + } + + kprintf("ISO filesystem detected on drive\n"); } +} + +extern void outb(uint8_t port, uint8_t data); +extern uint8_t inb(uint8_t port); +extern void atapi_wait(uint16_t port); + +int read_atapi(uint16_t bus, uint8_t drive, uint32_t lba, uint32_t sectors, uint16_t* buf) { + volatile uint8_t read_cmd[12] = {0xA8, 0, + (lba >> 0x18) & 0xFF, (lba >> 0x10) & 0xFF, (lba >> 0x08) & 0xFF, + (lba >> 0x00) & 0xFF, + (sectors >> 0x18) & 0xFF, (sectors >> 0x10) & 0xFF, (sectors >> 0x08) & 0xFF, + (sectors >> 0x00) & 0xFF, + 0, 0}; + + outb(bus + IO_DRIVE_SELECT_REG, drive); // select drive + atapi_wait(bus); + outb(bus + IO_FEATURE_REG, 0x00); + outb(bus + IO_LBA_MID_REG, 2048 & 0xFF); + outb(bus + IO_LBA_HI_REG, 2048 >> 8); + outb(bus + IO_CMD_REG, 0xA0); + + atapi_wait(bus); + atapi_wait(bus); + + while (1) { + kprintf("waiting bsy\n"); + uint8_t status = inb(bus + IO_STATUS_REG); + if (status & STATUS_REG_BSY) { + atapi_wait(bus); + continue; + } + + if (status & STATUS_REG_ERR) + return -1; + + if (status & STATUS_REG_DRQ) + break; + + atapi_wait(bus); + } + + send_scsi_packet(bus, (void*)read_cmd, 6); + + for (uint32_t i = 0; i < sectors; i++) { + while (1) { + uint8_t status = inb(bus + IO_STATUS_REG); + if (status & STATUS_REG_ERR) + return -2; + if (!(status & STATUS_REG_BSY) && (status & STATUS_REG_DRQ)) + break; + atapi_wait(bus); + } + int bytes = inb(bus + IO_LBA_HI_REG) << 8 | inb(bus + IO_LBA_MID_REG); + int words = bytes / 2; + + read_data_words(bus, ((uint8_t*)buf + i * 0x800), words); + } + + return 0; } \ No newline at end of file diff --git a/kernel/drivers/atapi/ata.h b/kernel/drivers/atapi/ata.h index 0170f10..11b04b3 100644 --- a/kernel/drivers/atapi/ata.h +++ b/kernel/drivers/atapi/ata.h @@ -3,6 +3,7 @@ #ifndef __ASSEMBLER__ #include +#include #endif #define IDE_PRIMARY_IO_BASE 0x01F0 @@ -67,6 +68,9 @@ #ifndef __ASSEMBLER__ uint8_t ident_device(uint16_t bus, uint8_t drive_select, uint8_t* buffer); +int read_atapi(uint16_t bus, uint8_t drive, uint32_t lba, uint32_t sectors, uint16_t* buf); +void send_scsi_packet(uint16_t bus, void* cmd, size_t sz); +void read_data_words(uint16_t bus, void* buf, size_t sz); typedef struct __attribute__((packed)) { uint16_t bus; @@ -75,18 +79,133 @@ typedef struct __attribute__((packed)) { void* ident_info_struct; } ide_device_t; -typedef struct __attribute__((packed)) { - uint16_t gen_config; - uint16_t reserved_1[9]; - char serial_number[20]; - uint16_t vendor_1[3]; - char firmware_v[8]; - char model_num[40]; - uint16_t vendor_2[2]; - uint16_t capabilities; - uint16_t reserved_2; - uint16_t pio_dma_timing; -} atapi_identify_data_t; +typedef struct { + // Word 0: General configuration bit-map + struct { + uint16_t packet_size : 2; // 00=12 bytes, 01=16 bytes + uint16_t reserved1 : 3; + uint16_t drq_response : 2; // DRQ response microsecond timing + uint16_t device_type : 5; // Device type (e.g., 0x05 for CD/DVD-ROM) + uint16_t reserved2 : 1; + uint16_t removable_media : 1; // 1 = Removable media + uint16_t command_packet_type : 2; // 10 = ATAPI device + } general_config; + + uint16_t logical_cylinders; + uint16_t specific_configuration; // Word 2: Specific configuration + uint16_t logical_heads; // Word 3: Obsolete / Reserved + uint16_t retired1[2]; // Words 4-5: Retired + + uint16_t logical_sectors_per_track; // Word 6: Obsolete / Reserved + uint16_t reserved_vendor[3]; // Words 7-9: Vendor specific + + char serial_number[20]; // Words 10-19: Serial number (ASCII, byte-swapped) + uint16_t retired2[2]; // Words 20-21: Retired + uint16_t obsolete1; // Word 22: Obsolete + + char firmware_revision[8]; // Words 23-26: Firmware revision (ASCII, byte-swapped) + char model_number[40]; // Words 27-46: Model number (ASCII, byte-swapped) + + uint16_t sectors_per_interrupt; // Word 47: Bits 7:0 = Max sectors per interrupt + uint16_t reserved3; // Word 48: Reserved + + // Word 49: Capabilities + struct { + uint16_t reserved1 : 8; + uint16_t dma_supported : 1; // 1 = DMA supported + uint16_t lba_supported : 1; // 1 = LBA supported + uint16_t iordy_disable : 1; // 1 = IORDY can be disabled + uint16_t iordy_supported : 1; // 1 = IORDY supported + uint16_t reserved2 : 1; + uint16_t overlap_supported : 1; // 1 = Overlap operation supported + uint16_t reserved3 : 2; + } capabilities1; + + uint16_t capabilities2; // Word 50: Capabilities bit 0 = Min MDMA cycle time info + uint16_t pio_data_transfer_timing;// Word 51: Obsolete + uint16_t dma_data_transfer_timing;// Word 52: Obsolete + + // Word 53: Field validity + struct { + uint16_t fields_54_58_valid : 1; // 1 = Words 54-58 are valid + uint16_t fields_64_70_valid : 1; // 1 = Words 64-70 are valid + uint16_t field_88_valid : 1; // 1 = Word 88 is valid (Ultra DMA) + uint16_t reserved : 13; + } field_validity; + + uint16_t obsolete2[5]; // Words 54-58: Obsolete + uint16_t multi_sector_setting; // Word 59: Multi-sector setting + uint32_t total_addressable_sectors; // Words 60-61: Total number of user addressable sectors (LBA28) + uint16_t single_word_dma_modes; + uint16_t multi_word_dma_modes; + + struct { + uint16_t pio_mode_3 : 1; + uint16_t pio_mode_4 : 1; + uint16_t reserved : 14; + } advanced_pio_modes; + + uint16_t min_mwdma_cycle_time; + uint16_t rec_mwdma_cycle_time; + uint16_t min_pio_cycle_time_no_flow; + uint16_t min_pio_cycle_time_iordy; + uint16_t reserved4[2]; + + uint16_t packet_release_time; + uint16_t service_clear_time; + uint16_t major_revision_number; + uint16_t minor_revision_number; + + uint16_t queue_depth; + uint16_t reserved5[4]; + + uint16_t major_version; + uint16_t minor_version; + + uint16_t command_sets_supported1; + uint16_t command_sets_supported2; + uint16_t command_sets_supported3; + + uint16_t command_sets_enabled1; + uint16_t command_sets_enabled2; + uint16_t command_sets_enabled3; + + uint16_t ultra_dma_modes; + uint16_t reserved_erase_time[2]; + uint16_t current_apm_level; + uint16_t master_password_revision; + uint16_t hardware_reset_result; + uint16_t obsolete3; + uint16_t stream_minimum_request; + uint16_t streaming_transfer_delay; + uint16_t streaming_access_latency; + uint32_t streaming_perf_granularity; + + uint64_t total_user_sectors_lba48; + uint16_t streaming_transfer_delay_block; + uint16_t reserved6; + + struct { + uint16_t logical_sectors_per_physical : 4; + uint16_t reserved1 : 8; + uint16_t logical_sector_longer_than_256: 1; + uint16_t physical_sector_longer_than_logical: 1; + uint16_t validation_bits : 2; + } physical_sector_size; + + uint16_t inter_seek_delay; + uint16_t world_wide_name[4]; + uint16_t reserved7[8]; + uint16_t command_submission_delay; + uint16_t reserved8[7]; + uint16_t security_status; + uint16_t vendor_specific[31]; + uint16_t cfa_power_mode; + uint16_t reserved9[15]; + char media_serial_number[60]; + uint16_t sct_command_transport; + uint16_t reserved10[49]; +} __attribute__((packed)) atapi_identify_t; #endif diff --git a/kernel/drivers/atapi/ata_stubs.S b/kernel/drivers/atapi/ata_stubs.S index 56de6d2..a1da4c2 100644 --- a/kernel/drivers/atapi/ata_stubs.S +++ b/kernel/drivers/atapi/ata_stubs.S @@ -2,18 +2,15 @@ .code32 -.extern selected_drive_primary -.extern selected_drive_secondary - .global ident_device ident_device: push %ebp mov %esp, %ebp push %ebx - push %ecx - push %edx - push $0 + push %esi + push %edi + push $0 mov 8(%ebp), %ebx # ebx = bus base address mov 12(%ebp), %ecx # ecx = drive select mask @@ -24,6 +21,12 @@ ident_device: mov %cl, %al outb %al, (%dx) + mov %ebx, %edx + add $IO_STATUS_REG, %edx + .rept 15 + inb (%dx), %al + .endr + xor %eax, %eax # clear sector count and LBA mov %ebx, %edx @@ -65,6 +68,7 @@ poll_status: test $STATUS_REG_BSY, %al jnz poll_status +# first check if this is an ATA device check_ata: mov %ebx, %edx add $IO_LBA_MID_REG, %edx @@ -77,7 +81,7 @@ check_ata: inb (%dx), %al test %al, %al jnz check_atapi - +is_ata: mov $0x01, (%esp) jmp poll_drq @@ -118,6 +122,9 @@ poll_drq: add $IO_STATUS_REG, %edx inb (%dx), %al + test $STATUS_REG_BSY, %al + jnz poll_drq + test $STATUS_REG_ERR, %al jnz error @@ -130,12 +137,12 @@ drq_set: mov 16(%ebp), %edi mov $256, %ecx + cld read_data: inw (%dx), %ax mov %ax, (%edi) add $2, %edi loop read_data - jmp done not_found: @@ -143,8 +150,78 @@ error: mov $0x0, (%esp) done: pop %eax - pop %edx - pop %ecx + pop %edi + pop %esi pop %ebx leave + ret + +.global atapi_wait +atapi_wait: + push %ebp + mov %esp, %ebp + + # 8(%ebp) bus + mov 8(%ebp), %edx + + add $IO_STATUS_REG, %edx + inb (%dx), %al + inb (%dx), %al + inb (%dx), %al + inb (%dx), %al + + pop %edx + leave + ret + +.global send_scsi_packet +send_scsi_packet: + push %ebp + mov %esp, %ebp + + push %esi + push %ecx + push %edx + + # 8(%ebp) bus + # 12(%ebp) cmd + # 16(%ebp) sz + mov 8(%ebp), %edx + add $IO_DATA_REG, %edx + mov 12(%ebp), %esi + mov 16(%ebp), %ecx + + cld + rep outsw + + pop %edx + pop %ecx + pop %esi + leave + ret + +.global read_data_words +read_data_words: + push %ebp + mov %esp, %ebp + + push %edi + push %ecx + push %edx + + # 8(%ebp) bus + # 12(%ebp) buf + # 16(%ebp) sz + mov 8(%ebp), %edx + add $IO_DATA_REG, %edx + mov 12(%ebp), %edi + mov 16(%ebp), %ecx + + cld + rep insw + + pop %edx + pop %ecx + pop %edi + leave ret \ No newline at end of file