Disk infrastructure and working read support

This commit is contained in:
Ali Mashtizadeh 2014-07-24 16:38:35 -07:00
parent bb9f0133fc
commit 82af1f6801
4 changed files with 261 additions and 27 deletions

View File

@ -34,6 +34,7 @@ src_amd64 = [
src_common = [
"kern/debug.c",
"kern/disk.c",
"kern/libc.c",
"kern/palloc.c",
"kern/printf.c",

View File

@ -4,7 +4,8 @@
#include <string.h>
#include <sys/kassert.h>
#include <sys/sga.h>
#include <sys/kmem.h>
#include <sys/disk.h>
#include "ioport.h"
#include "../ata.h"
@ -32,15 +33,12 @@
#define IDE_COMMAND 7 /* Write */
#define IDE_STATUS 7 /* Read */
// Drives
#define IDE_DRIVE_MASTER 0xA0
#define IDE_DRIVE_SLAVE 0xB0
// IDE Commands
#define IDE_CMD_READ
#define IDE_CMD_READ 0x20
#define IDE_CMD_READ_EXT 0x24
#define IDE_CMD_WRITE
#define IDE_CMD_WRITE_EXT 0x34
#define IDE_CMD_FLUSH 0xE7
#define IDE_CMD_IDENTIFY 0xEC
// Status
@ -72,6 +70,10 @@ typedef struct IDEDrive
bool IDE_HasController(IDE *ide);
void IDE_Reset(IDE *ide);
void IDE_Identify(IDE *ide, int drive);
int IDE_Read(Disk *disk, void *buf, SGArray *sga, DiskCB, void *arg);
int IDE_Write(Disk *disk, void *buf, SGArray *sga, DiskCB, void *arg);
int IDE_Flush(Disk *disk, void *buf, SGArray *sga, DiskCB, void *arg);
int IDE_ReadOne(IDEDrive *drive, void *buf, uint64_t off, uint64_t len);
void
IDE_Init()
@ -89,6 +91,7 @@ IDE_Init()
}
IDE_Reset(&ide);
IDE_Identify(&ide, 0);
IDE_Identify(&ide, 1);
}
bool
@ -170,7 +173,7 @@ IDE_Identify(IDE *ide, int drive)
status = inb(ide->base + IDE_STATUS);
if (status == 0) {
kprintf("IDE: No drive %d\n", drive);
kprintf("IDE: Drive %d not present\n", drive);
return;
}
@ -203,45 +206,141 @@ IDE_Identify(IDE *ide, int drive)
kprintf("IDE: Drive %d Model: %s Serial: %s\n", drive, model, serial);
kprintf("IDE: Drive %d %llu Sectors (%llu MBs)\n",
drive, ident.lbaSectors, ident.lbaSectors / 2048ULL);
// Register Disk
Disk *disk = PAlloc_AllocPage();
if (!disk) {
Panic("IDE: No memory!\n");
}
disk->handle = 0;
disk->ctrlNo = 0;
disk->diskNo = drive;
disk->sectorSize = IDE_SECTOR_SIZE;
disk->sectorCount = ident.lbaSectors;
disk->diskSize = IDE_SECTOR_SIZE * ident.lbaSectors;
disk->read = IDE_Read;
disk->write = IDE_Write;
disk->flush = IDE_Flush;
Disk_AddDisk(disk);
}
void
IDE_Read(IDEDrive *drive, void *buf, uint64_t off, uint64_t len)
int
IDEWaitForBusy(IDE *ide)
{
uint8_t status;
while (1) {
status = inb(ide->base + IDE_STATUS);
if ((status & IDE_STATUS_BSY) == 0)
return status;
}
return 0xFF;
}
int
IDE_Read(Disk *disk, void *buf, SGArray *sga, DiskCB cb, void *arg)
{
int i;
int status;
IDE ide;
IDEDrive idedrive;
ide.base = IDE_PRIMARY_BASE;
ide.devctl = IDE_PRIMARY_DEVCTL;
idedrive.ide = &ide;
idedrive.drive = disk->diskNo;
idedrive.lba48 = true;
idedrive.size = disk->sectorCount;
for (i = 0; i < sga->len; i++) {
status = IDE_ReadOne(&idedrive,
buf,
sga->entries[i].offset,
sga->entries[i].length / disk->sectorSize);
buf += sga->entries[i].offset;
if (status < 0)
return status;
}
return 0;
}
int
IDE_Write(Disk *disk, void *buf, SGArray *sga, DiskCB cb, void *arg)
{
return -1;
}
int
IDE_Flush(Disk *disk, void *buf, SGArray *sga, DiskCB cb, void *arg)
{
uint8_t driveCode;
uint8_t status;
IDE *ide = drive->ide;
IDE ide;
IDEDrive idedrive;
ASSERT(drive->drive == 0 || drive->drive == 1);
ide.base = IDE_PRIMARY_BASE;
ide.devctl = IDE_PRIMARY_DEVCTL;
idedrive.ide = &ide;
idedrive.drive = disk->diskNo;
idedrive.lba48 = true;
idedrive.size = disk->sectorCount;
if (drive->drive == 0)
if (idedrive.drive == 0)
driveCode = IDE_DRIVE_MASTER;
else
driveCode = IDE_DRIVE_SLAVE;
outb(ide.base + IDE_DRIVE, driveCode);
outb(ide.base + IDE_COMMAND, IDE_CMD_FLUSH);
IDEWaitForBusy(&ide);
return 0;
}
int
IDE_ReadOne(IDEDrive *drive, void *buf, uint64_t off, uint64_t len)
{
bool lba48 = false;
uint8_t driveCode;
uint8_t status;
IDE *ide = drive->ide;
kprintf("%llx %llx\n", off, len);
ASSERT(drive->drive == 0 || drive->drive == 1);
if (drive->drive == 0)
driveCode = lba48 ? 0x40 : 0xE0;
else
driveCode = lba48 ? 0x50 : 0xF0;
ASSERT(len < 0x10000);
outb(ide->base + IDE_DRIVE, driveCode);
outb(ide->base + IDE_SECTORCOUNT, len >> 8);
outb(ide->base + IDE_LBALOW, off >> 24);
outb(ide->base + IDE_LBAMID, off >> 32);
outb(ide->base + IDE_LBAHIGH, off >> 40);
if (lba48) {
outb(ide->base + IDE_SECTORCOUNT, len >> 8);
outb(ide->base + IDE_LBALOW, off >> 24);
outb(ide->base + IDE_LBAMID, off >> 32);
outb(ide->base + IDE_LBAHIGH, off >> 40);
}
outb(ide->base + IDE_SECTORCOUNT, len);
outb(ide->base + IDE_LBALOW, off);
outb(ide->base + IDE_LBAMID, off >> 8);
outb(ide->base + IDE_LBAHIGH, off >> 16);
outb(ide->base + IDE_COMMAND, IDE_CMD_READ_EXT);
// XXX: Need timeout
while (1) {
status = inb(ide->base + IDE_STATUS);
if ((status & IDE_STATUS_BSY) == 0)
break;
}
if (lba48)
outb(ide->base + IDE_COMMAND, IDE_CMD_READ_EXT);
else
outb(ide->base + IDE_COMMAND, IDE_CMD_READ);
status = IDEWaitForBusy(ide);
if ((status & IDE_STATUS_ERR) != 0) {
kprintf("IDE: Error trying read from drive %d\n", drive);
return;
kprintf("IDE: Error trying read from drive %d\n", drive->drive);
return -1;
}
int sectors;
@ -250,10 +349,12 @@ IDE_Read(IDEDrive *drive, void *buf, uint64_t off, uint64_t len)
uint8_t *b = buf + sectors * IDE_SECTOR_SIZE;
insw(ide->base, b, 256);
}
return 0;
}
void
IDE_Write(IDEDrive *drive, void *buf, uint64_t off, uint64_t len)
IDE_WriteOne(IDEDrive *drive, void *buf, uint64_t off, uint64_t len)
{
uint8_t driveCode;
uint8_t status;

32
sys/include/disk.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef __SYS_DISK_H__
#define __SYS_DISK_H__
#include <sys/queue.h>
#include <sys/sga.h>
typedef void (*DiskCB)(int, void *);
typedef struct Disk Disk;
typedef struct Disk {
void *handle; // Driver handle
uint64_t ctrlNo; // Controller number
uint64_t diskNo; // Disk number
uint64_t sectorSize; // Sector Size
uint64_t sectorCount; // Sector Count
uint64_t diskSize; // Disk Size in Bytes
int (*read)(Disk *, void *, SGArray *, DiskCB, void *); // Read
int (*write)(Disk *, void *, SGArray *, DiskCB, void *); // Write
int (*flush)(Disk *, void *, SGArray *, DiskCB, void *); // Flush
LIST_ENTRY(Disk) entries;
} Disk;
void Disk_AddDisk(Disk *disk);
void Disk_RemoveDisk(Disk *disk);
Disk *Disk_GetByID(uint64_t ctrlNo, uint64_t diskNo);
int Disk_Read(Disk *disk, void * buf, SGArray *sga, DiskCB cb, void *arg);
int Disk_Write(Disk *disk, void * buf, SGArray *sga, DiskCB cb, void *arg);
int Disk_Flush(Disk *disk, void * buf, SGArray *sga, DiskCB cb, void *arg);
#endif /* __SYS_DISK_H__ */

100
sys/kern/disk.c Normal file
View File

@ -0,0 +1,100 @@
#include <stdbool.h>
#include <stdint.h>
#include <sys/kassert.h>
#include <sys/kdebug.h>
#include <sys/queue.h>
#include <sys/sga.h>
#include <sys/disk.h>
#include <sys/spinlock.h>
LIST_HEAD(DiskList, Disk) diskList;
void
Disk_AddDisk(Disk *disk)
{
LIST_INSERT_HEAD(&diskList, disk, entries);
}
void
Disk_RemoveDisk(Disk *disk)
{
LIST_REMOVE(disk, entries);
}
Disk *
Disk_GetByID(uint64_t ctrlNo, uint64_t diskNo)
{
Disk *d;
LIST_FOREACH(d, &diskList, entries) {
if (d->ctrlNo == ctrlNo && d->diskNo == diskNo)
return d;
}
return NULL;
}
int
Disk_Read(Disk *disk, void *buf, SGArray *sga, DiskCB cb, void *arg)
{
return disk->read(disk, buf, sga, cb, arg);
}
int
Disk_Write(Disk *disk, void *buf, SGArray *sga, DiskCB cb, void *arg)
{
return disk->write(disk, buf, sga, cb, arg);
}
int
Disk_Flush(Disk *disk, void *buf, SGArray *sga, DiskCB cb, void *arg)
{
return disk->flush(disk, buf, sga, cb, arg);
}
void
Debug_Disks(int argc, const char *argv[])
{
Disk *d;
LIST_FOREACH(d, &diskList, entries) {
kprintf("disk%lld.%lld: %lld Sectors\n",
d->ctrlNo, d->diskNo, d->sectorCount);
}
}
REGISTER_DBGCMD(disks, "List disks", Debug_Disks);
void
Debug_DumpDisk(int argc, const char *argv[])
{
uint64_t ctrlNo, diskNo;
uint64_t sector;
char buf[512];
SGArray sga;
if (argc != 4) {
kprintf("dumpdisk requires 4 arguments!\n");
return;
}
ctrlNo = Debug_StrToInt(argv[1]);
diskNo = Debug_StrToInt(argv[2]);
sector = Debug_StrToInt(argv[3]);
Disk *d = Disk_GetByID(ctrlNo, diskNo);
sga.len = 1;
sga.entries[0].offset = sector;
sga.entries[0].length = 512;
kprintf("Reading Sector %lld from disk%lld.%lld\n", sector, ctrlNo, diskNo);
Disk_Read(d, &buf, &sga, NULL, NULL);
Debug_PrintHex((const char *)&buf, 512, 0, 512);
}
REGISTER_DBGCMD(dumpdisk, "Dump disk sector", Debug_DumpDisk);