Disk infrastructure and working read support
This commit is contained in:
parent
bb9f0133fc
commit
82af1f6801
@ -34,6 +34,7 @@ src_amd64 = [
|
||||
|
||||
src_common = [
|
||||
"kern/debug.c",
|
||||
"kern/disk.c",
|
||||
"kern/libc.c",
|
||||
"kern/palloc.c",
|
||||
"kern/printf.c",
|
||||
|
@ -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
32
sys/include/disk.h
Normal 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
100
sys/kern/disk.c
Normal 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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user