From d2a1b0e4eabb197439fcb56ad290b30af271207a Mon Sep 17 00:00:00 2001 From: "Peter H. Froehlich" Date: Sun, 27 Sep 2015 15:40:21 -0400 Subject: [PATCH] New IDE header, adjusted IDE driver code, nits. --- bootmain.c | 27 +++++++++++++------------- ide.c | 56 +++++++++++++++++++++++------------------------------- ide.h | 45 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 46 deletions(-) create mode 100644 ide.h diff --git a/bootmain.c b/bootmain.c index 97d5258..2010d6f 100644 --- a/bootmain.c +++ b/bootmain.c @@ -1,5 +1,5 @@ // Boot loader. -// +// // Part of the boot block, along with bootasm.S, which calls bootmain(). // bootasm.S has put the processor into protected 32-bit mode. // bootmain() loads an ELF kernel image from the disk starting at @@ -9,8 +9,7 @@ #include "elf.h" #include "x86.h" #include "memlayout.h" - -#define SECTSIZE 512 +#include "ide.h" void readseg(uchar*, uint, uint); @@ -51,7 +50,7 @@ void waitdisk(void) { // Wait for disk ready. - while((inb(0x1F7) & 0xC0) != 0x40) + while((inb(IDE_DATA_PRIMARY+IDE_REG_STATUS) & 0xC0) != 0x40) ; } @@ -61,16 +60,16 @@ readsect(void *dst, uint offset) { // Issue command. waitdisk(); - outb(0x1F2, 1); // count = 1 - outb(0x1F3, offset); - outb(0x1F4, offset >> 8); - outb(0x1F5, offset >> 16); - outb(0x1F6, (offset >> 24) | 0xE0); - outb(0x1F7, 0x20); // cmd 0x20 - read sectors + outb(IDE_DATA_PRIMARY+IDE_REG_SECTORS, 1); // count = 1 + outb(IDE_DATA_PRIMARY+IDE_REG_LBA0, offset); + outb(IDE_DATA_PRIMARY+IDE_REG_LBA1, offset >> 8); + outb(IDE_DATA_PRIMARY+IDE_REG_LBA2, offset >> 16); + outb(IDE_DATA_PRIMARY+IDE_REG_DISK, (offset >> 24) | 0xE0); + outb(IDE_DATA_PRIMARY+IDE_REG_COMMAND, IDE_CMD_READ); // cmd 0x20 - read sectors // Read data. waitdisk(); - insl(0x1F0, dst, SECTSIZE/4); + insl(IDE_DATA_PRIMARY+IDE_REG_DATA, dst, SECTOR_SIZE/4); } // Read 'count' bytes at 'offset' from kernel into physical address 'pa'. @@ -83,14 +82,14 @@ readseg(uchar* pa, uint count, uint offset) epa = pa + count; // Round down to sector boundary. - pa -= offset % SECTSIZE; + pa -= offset % SECTOR_SIZE; // Translate from bytes to sectors; kernel starts at sector 1. - offset = (offset / SECTSIZE) + 1; + offset = (offset / SECTOR_SIZE) + 1; // If this is too slow, we could read lots of sectors at a time. // We'd write more to memory than asked, but it doesn't matter -- // we load in increasing order. - for(; pa < epa; pa += SECTSIZE, offset++) + for(; pa < epa; pa += SECTOR_SIZE, offset++) readsect(pa, offset); } diff --git a/ide.c b/ide.c index ed5a572..1b0e63e 100644 --- a/ide.c +++ b/ide.c @@ -11,15 +11,7 @@ #include "spinlock.h" #include "fs.h" #include "buf.h" - -#define SECTOR_SIZE 512 -#define IDE_BSY 0x80 -#define IDE_DRDY 0x40 -#define IDE_DF 0x20 -#define IDE_ERR 0x01 - -#define IDE_CMD_READ 0x20 -#define IDE_CMD_WRITE 0x30 +#include "ide.h" // idequeue points to the buf now being read/written to the disk. // idequeue->qnext points to the next buf to be processed. @@ -37,7 +29,7 @@ idewait(int checkerr) { int r; - while(((r = inb(0x1f7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY) + while(((r = inb(IDE_DATA_PRIMARY+IDE_REG_STATUS)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY) ; if(checkerr && (r & (IDE_DF|IDE_ERR)) != 0) return -1; @@ -48,23 +40,23 @@ void ideinit(void) { int i; - + initlock(&idelock, "ide"); picenable(IRQ_IDE); ioapicenable(IRQ_IDE, ncpu - 1); idewait(0); - + // Check if disk 1 is present - outb(0x1f6, 0xe0 | (1<<4)); + outb(IDE_DATA_PRIMARY+IDE_REG_DISK, 0xe0 | (1<<4)); for(i=0; i<1000; i++){ - if(inb(0x1f7) != 0){ + if(inb(IDE_DATA_PRIMARY+IDE_REG_STATUS) != 0){ havedisk1 = 1; break; } } - + // Switch back to disk 0. - outb(0x1f6, 0xe0 | (0<<4)); + outb(IDE_DATA_PRIMARY+IDE_REG_DISK, 0xe0 | (0<<4)); } // Start the request for b. Caller must hold idelock. @@ -79,19 +71,19 @@ idestart(struct buf *b) int sector = b->blockno * sector_per_block; if (sector_per_block > 7) panic("idestart"); - + idewait(0); - outb(0x3f6, 0); // generate interrupt - outb(0x1f2, sector_per_block); // number of sectors - outb(0x1f3, sector & 0xff); - outb(0x1f4, (sector >> 8) & 0xff); - outb(0x1f5, (sector >> 16) & 0xff); - outb(0x1f6, 0xe0 | ((b->dev&1)<<4) | ((sector>>24)&0x0f)); + outb(IDE_CTRL_PRIMARY+IDE_REG_CTRL, 0); // generate interrupt + outb(IDE_DATA_PRIMARY+IDE_REG_SECTORS, sector_per_block); // number of sectors + outb(IDE_DATA_PRIMARY+IDE_REG_LBA0, sector & 0xff); + outb(IDE_DATA_PRIMARY+IDE_REG_LBA1, (sector >> 8) & 0xff); + outb(IDE_DATA_PRIMARY+IDE_REG_LBA2, (sector >> 16) & 0xff); + outb(IDE_DATA_PRIMARY+IDE_REG_DISK, 0xe0 | ((b->dev&1)<<4) | ((sector>>24)&0x0f)); if(b->flags & B_DIRTY){ - outb(0x1f7, IDE_CMD_WRITE); - outsl(0x1f0, b->data, BSIZE/4); + outb(IDE_DATA_PRIMARY+IDE_REG_COMMAND, IDE_CMD_WRITE); + outsl(IDE_DATA_PRIMARY+IDE_REG_DATA, b->data, BSIZE/4); } else { - outb(0x1f7, IDE_CMD_READ); + outb(IDE_DATA_PRIMARY+IDE_REG_COMMAND, IDE_CMD_READ); } } @@ -112,13 +104,13 @@ ideintr(void) // Read data if needed. if(!(b->flags & B_DIRTY) && idewait(1) >= 0) - insl(0x1f0, b->data, BSIZE/4); - + insl(IDE_DATA_PRIMARY+IDE_REG_DATA, b->data, BSIZE/4); + // Wake process waiting for this buf. b->flags |= B_VALID; b->flags &= ~B_DIRTY; wakeup(b); - + // Start disk on next buf in queue. if(idequeue != 0) idestart(idequeue); @@ -127,7 +119,7 @@ ideintr(void) } //PAGEBREAK! -// Sync buf with disk. +// Sync buf with disk. // If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID. // Else if B_VALID is not set, read buf from disk, set B_VALID. void @@ -149,11 +141,11 @@ iderw(struct buf *b) for(pp=&idequeue; *pp; pp=&(*pp)->qnext) //DOC:insert-queue ; *pp = b; - + // Start disk if necessary. if(idequeue == b) idestart(b); - + // Wait for request to finish. while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){ sleep(b, &idelock); diff --git a/ide.h b/ide.h new file mode 100644 index 0000000..c2bce5f --- /dev/null +++ b/ide.h @@ -0,0 +1,45 @@ +// This file contains definitions for IDE/ATA disk controllers. + +// IDE sectors are 512 bytes long. +#define SECTOR_SIZE 512 + +// Base addresses in I/O space for the first two IDE channels, +// each of which supports up to two drives. +#define IDE_DATA_PRIMARY 0x1f0 +#define IDE_CTRL_PRIMARY 0x3f4 +#define IDE_DATA_SECONDARY 0x170 +#define IDE_CTRL_SECONDARY 0x374 + +// DATA registers for each IDE channel; add offsets to relevant +// DATA base address. +#define IDE_REG_DATA 0x00 // read/write data from/to disk +#define IDE_REG_ERROR 0x01 +#define IDE_REG_SECTORS 0x02 +#define IDE_REG_LBA0 0x03 +#define IDE_REG_LBA1 0x04 +#define IDE_REG_LBA2 0x05 +#define IDE_REG_DISK 0x06 +#define IDE_REG_COMMAND 0x07 // write commands +#define IDE_REG_STATUS 0x07 // read status + +// Masks for IDE_REG_DISK. +#define IDE_DISK_CHS 0xA0 // bits 7 and 5 always set, bit 6 LBA clear +#define IDE_DISK_LBA 0xE0 // bits 7 and 5 always set, bit 6 LBA set + +// Flags read from IDE_REG_STATUS. +#define IDE_BSY 0x80 // drive busy (with a command?) +#define IDE_DRDY 0x40 // drive ready (for comment? spun up?) +#define IDE_DF 0x20 // drive (write?) failure +#define IDE_DRQ 0x08 // PIO data ready +#define IDE_ERR 0x01 // error, details in IDE_REG_ERROR + +// Commands written to IDE_REG_COMMAND. These are +// the PIO read/write commands for LBA-28. +#define IDE_CMD_READ 0x20 +#define IDE_CMD_WRITE 0x30 +#define IDE_CMD_IDENT 0xEC + +// CTRL registers for each IDE channel; add offsets +// to relevant CTRL base address. +#define IDE_REG_CTRL 0x02 // write device control +#define IDE_REG_ALTSTATUS 0x02 // read status (without IRQ stuff) -- 2.50.1