Detection/init of primary ATA drive
authorRhett Aultman <roadriverrail@gmail.com>
Thu, 12 Jul 2012 08:38:19 +0000 (01:38 -0700)
committerRhett Aultman <roadriverrail@gmail.com>
Thu, 12 Jul 2012 08:38:19 +0000 (01:38 -0700)
kern/Makefrag
kern/devices/atapio.c [new file with mode: 0644]
kern/devices/atapio.h [new file with mode: 0644]
kern/init.c

index 226507b17d2c1d1e948d123fd06d6b332be74d4e..a9ad9d84c6216b811783444092b6062acd226cb3 100644 (file)
@@ -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 (file)
index 0000000..721d0f1
--- /dev/null
@@ -0,0 +1,90 @@
+#include <kern/devices/atapio.h>
+#include <inc/x86.h>
+#include <inc/stringformat.h>
+
+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 (file)
index 0000000..bcb0aaa
--- /dev/null
@@ -0,0 +1,59 @@
+#include <inc/types.h>
+
+/**
+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
index fb14f92559e0ad2150e3507cbad331d7afa1f391..aac14a765dc3a80745e5293d1555e7663e7a741e 100644 (file)
@@ -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");