From 401191f624f5b2d4c5e934873d89410c45cfdcc2 Mon Sep 17 00:00:00 2001 From: Rhett Aultman Date: Thu, 12 Jul 2012 01:38:19 -0700 Subject: [PATCH] Detection/init of primary ATA drive --- kern/Makefrag | 3 +- kern/devices/atapio.c | 90 +++++++++++++++++++++++++++++++++++++++++++ kern/devices/atapio.h | 59 ++++++++++++++++++++++++++++ kern/init.c | 6 ++- 4 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 kern/devices/atapio.c create mode 100644 kern/devices/atapio.h diff --git a/kern/Makefrag b/kern/Makefrag index 226507b..a9ad9d8 100644 --- a/kern/Makefrag +++ b/kern/Makefrag @@ -15,7 +15,8 @@ KERN_SRCFILES := kern/entry.S \ kern/interrupts/interrupts.S \ kern/interrupts/interrupt_handlers.c \ kern/interrupts/idt.c \ - kern/interrupts/pic.c + kern/interrupts/pic.c \ + kern/devices/atapio.c # Only build files if they exist. KERN_SRCFILES := $(wildcard $(KERN_SRCFILES)) diff --git a/kern/devices/atapio.c b/kern/devices/atapio.c new file mode 100644 index 0000000..721d0f1 --- /dev/null +++ b/kern/devices/atapio.c @@ -0,0 +1,90 @@ +#include +#include +#include + +static uint8_t drive_attached = 0; +static uint8_t current_drive = 0; + +void atapio_init() +{ + base_port = ATA_BUS1_BASE; + + // Confirm if a disk drive even exists! + uint8_t result = inb(ATA_COMMAND_STATUS_PORT); + if (result == 0xFF) { + drive_attached = 0; + return; + } + + // Reset the bus + _kern_print("Resetting ATA bus\n"); + outb(ATA_DEVCONTROL, 0x04); + // Stall for 2ms + int i; + for (i=0; i<20; i++) + { + inb(ATA_COMMAND_STATUS_PORT); + } + outb(ATA_COMMAND_STATUS_PORT, 0x00); + + // Really, we should issue an IDENTIFY command here + // but we'll just presume for now. Select the master + // disc and let it go + + outb(ATA_DEVCONTROL, SELECT_MASTER_DRIVE); + + // Drives may need up to 500ns for drive select to + // complete, and an IO read is about 100ns, so burn + // 400ns. + + inb(ATA_COMMAND_STATUS_PORT); + inb(ATA_COMMAND_STATUS_PORT); + inb(ATA_COMMAND_STATUS_PORT); + inb(ATA_COMMAND_STATUS_PORT); + + uint8_t cl=inb(ATA_LBAMID_PORT); /* get the "signature bytes" */ + uint8_t ch=inb(ATA_LBAHI_PORT); + + _kern_print("Read signature bytes %x and %x\n", cl, ch); + /* differentiate ATA, ATAPI, SATA and SATAPI */ + if (cl==0x14 && ch==0xEB) + { + _kern_print("Detected PATAPI device on default bus and drive\n"); + } + else if (cl==0x69 && ch==0x96) + { + _kern_print("Detected SATAPI device on default bus and drive\n"); + } + else if (cl==0 && ch == 0) + { + _kern_print("Detected PATA device on default bus and drive\n"); + } + else if (cl==0x3c && ch==0xc3) + { + _kern_print("Detected SATA device on default bus and drive\n"); + } + else + { + _kern_print("UNKNOWN device on default bus and drive\n"); + } + +} + +void atapio_read(uint32_t sector, uint32_t sector_count, char *buffer) +{ +/* +An example of a 28 bit LBA PIO mode read on the Primary bus: +Send 0xE0 for the "master" or 0xF0 for the "slave", ORed with the highest 4 bits of the LBA to port 0x1F6: outb(0x1F6, 0xE0 | (slavebit << 4) | ((LBA >> 24) & 0x0F)) +Send a NULL byte to port 0x1F1, if you like (it is ignored and wastes lots of CPU time): outb(0x1F1, 0x00) +Send the sectorcount to port 0x1F2: outb(0x1F2, (unsigned char) count) +Send the low 8 bits of the LBA to port 0x1F3: outb(0x1F3, (unsigned char) LBA)) +Send the next 8 bits of the LBA to port 0x1F4: outb(0x1F4, (unsigned char)(LBA >> 8)) +Send the next 8 bits of the LBA to port 0x1F5: outb(0x1F5, (unsigned char)(LBA >> 16)) +Send the "READ SECTORS" command (0x20) to port 0x1F7: outb(0x1F7, 0x20) +Wait for an IRQ or poll. +Transfer 256 words, a word at a time, into your buffer from I/O port 0x1F0. (In assembler, REP INSW works well for this.) +Then loop back to waiting for the next IRQ (or poll again -- see next note) for each successive sector. +*/ + + +} \ No newline at end of file diff --git a/kern/devices/atapio.h b/kern/devices/atapio.h new file mode 100644 index 0000000..bcb0aaa --- /dev/null +++ b/kern/devices/atapio.h @@ -0,0 +1,59 @@ +#include + +/** +Port Offset Function Description +0 Data Port Read/Write PIO data bytes on this port. +1 Features / Error Information Usually used for ATAPI devices. +2 Sector Count Number of sectors to read/write (0 is a special value). +3 Sector Number / LBAlo This is CHS / LBA28 / LBA48 specific. +4 Cylinder Low / LBAmid Partial Disk Sector address. +5 Cylinder High / LBAhi Partial Disk Sector address. +6 Drive / Head Port Used to select a drive and/or head. May supports extra address/flag bits. +7 Command port / Regular Status port Used to send commands or read the current status. +*/ + + +#define ATA_BUS1_BASE 0x1F0 +#define ATA_BUS2_BASE 0x170 + +uint16_t base_port; + + + +#define ATA_DATA_PORT (base_port + 0) +#define ATA_FEATURES_ERR_INFO_PORT (base_port + 1) +#define ATA_SECTOR_COUNT_PORT (base_port + 2) +#define ATA_LBALOW_PORT (base_port + 3) +#define ATA_LBAMID_PORT (base_port + 4) +#define ATA_LBAHI_PORT (base_port + 5) +#define ATA_DRIVE_HEAD_PORT (base_port + 6) +#define ATA_COMMAND_STATUS_PORT (base_port + 7) + +#define ATA_DEVCONTROL ((base_port == ATA_BUS1_BASE) ? 0x3F6 : 0x376) +#define ATA_ALT_STATUS_PORT ATA_DEVCONTROL + +/* + * Bit Abbreviation Function +0 ERR Indicates an error occurred. Send a new command to clear it (or nuke it with a Software Reset). +3 DRQ Set when the drive has PIO data to transfer, or is ready to accept PIO data. +4 SRV Overlapped Mode Service Request. +5 DF Drive Fault Error (does not set ERR). +6 RDY Bit is clear when drive is spun down, or after an error. Set otherwise. +7 BSY Indicates the drive is preparing to send/receive data (wait for it to clear). In case of 'hang' (it never clears), do a software reset. +*/ + +#define STATUS_ERR (1 << 0) +#define STATUS_DRQ (1 << 3) +#define STATUS_SRV (1 << 4) +#define STATUS_DF (1 << 5) +#define STATUS_RDY (1 << 6) +#define STATUS_BSY (1 << 7) + +#define SELECT_MASTER_DRIVE 0xA0 +#define SELECT_SLAVE_DRIVE 0xB0 + +#define RW_MASTER_DRIVE 0xE0 +#define RW_SLAVE_DRIVE 0xF0 + +#define COMMAND_READ_SECTORS 0x20 +#define COMMAND_IDENTIFY 0xEC \ No newline at end of file diff --git a/kern/init.c b/kern/init.c index fb14f92..aac14a7 100644 --- a/kern/init.c +++ b/kern/init.c @@ -13,6 +13,7 @@ #define CHECK_FLAG(flags,bit) ((flags) & (1 << (bit))) extern void keyboard_isr(); +extern void atapio_init(); void i386_init(multiboot_info_t* mbi); void kernel_main( void* mbd, unsigned int magic ) @@ -139,8 +140,9 @@ i386_init(multiboot_info_t* mbi) //keyboard ISR to perhaps...process any lingering key presses? asm("int $33"); memmgr_init(); - - char* yaay = memmgr_allocate(1024); + + _kern_print("Initializing ATAPIO driver\n"); + atapio_init(); //stop here for now _kern_print("Entering kernel idle loop.\n"); asm("hlt"); -- 2.34.1