// 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
#include "elf.h"
#include "x86.h"
#include "memlayout.h"
-
-#define SECTSIZE 512
+#include "ide.h"
void readseg(uchar*, uint, uint);
waitdisk(void)
{
// Wait for disk ready.
- while((inb(0x1F7) & 0xC0) != 0x40)
+ while((inb(IDE_DATA_PRIMARY+IDE_REG_STATUS) & 0xC0) != 0x40)
;
}
{
// 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'.
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);
}
#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.
{
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;
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.
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);
}
}
// 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);
}
//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
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);
--- /dev/null
+// 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)