WIP - ATA devices

This commit is contained in:
Thomas Lovén 2017-03-15 08:57:00 +01:00
parent 4bb9021885
commit 8671007f19
5 changed files with 260 additions and 25 deletions

2
emul
View File

@ -58,7 +58,7 @@ function main() {
make all || exit 1
util/build_iso.sh || exit 1
echo > serial.log
emulator="qemu-system-x86_64 -cdrom mittos64.iso -serial file:serial.log -smp 4 ${EMULPARAM[@]}"
emulator="qemu-system-x86_64 -hda image.img -cdrom mittos64.iso -boot order=d -serial file:serial.log -smp 4 ${EMULPARAM[@]}"
debugger=$(which x86_64-elf-linux-gdb)
if [[ (-n ${EMULVNC}) ]]; then

View File

@ -8,29 +8,6 @@ int main(int argc, char **argv)
(void) argv;
int fd[2];
pipe(fd);
pid_t childpid = fork();
if(childpid)
{
printf("I am parent!\n");
close(fd[1]);
write(fd[0], "Hi, pipe!\n", 10);
close(fd[0]);
}
else
{
printf("I am child!\n");
close(fd[0]);
char buffer[255];
read(fd[1], buffer, 255);
printf("Received string: %s\n", buffer);
close(fd[1]);
}
for(;;);
return 0;
}

View File

@ -12,6 +12,7 @@
#include <syscall.h>
#include <cpuid.h>
#include <vfs.h>
#include <ata.h>
int kernel_execve(process_t *p, void *image, char *argv[], char *envp[]);
int kmain(uint64_t multiboot_magic, void *multiboot_data)
@ -30,10 +31,11 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data)
debug_info("Syscall enabled:%d\n", CPUID_FEATURE_SYSCALL);
fs_mount(0, "/");
fs_mount(&debug_file, "/dev/debug");
ata_init();
fs_write(&debug_file, "TESTING DEBUG FILE", 18, 0);
process_t *p1 = process_spawn(0);

155
kernel/drivers/ata.c Normal file
View File

@ -0,0 +1,155 @@
#include <ata.h>
#include <ports.h>
#include <debug.h>
ata_drive drives[4] = {
{.bus=ATA_PRIMARY, .ms=ATA_MASTER},
{.bus=ATA_PRIMARY, .ms=ATA_SLAVE},
{.bus=ATA_SECONDARY, .ms=ATA_MASTER},
{.bus=ATA_SECONDARY, .ms=ATA_SLAVE}
};
int ata_wait_status(int bus)
{
inb(ATA_STATUS(bus));
inb(ATA_STATUS(bus));
inb(ATA_STATUS(bus));
inb(ATA_STATUS(bus));
return inb(ATA_STATUS(bus));
}
int ata_send_command(ata_cmd_t *cmd, int wait)
{
(void)wait;
outb(ATA_DEVICE(cmd->bus), cmd->device | (cmd->lba_sep[3] & 0xF));
ata_wait_status(cmd->bus);
outb(ATA_COUNT(cmd->bus), cmd->count);
outb(ATA_LBAL(cmd->bus), cmd->lba_sep[0]);
outb(ATA_LBAM(cmd->bus), cmd->lba_sep[1]);
outb(ATA_LBAH(cmd->bus), cmd->lba_sep[2]);
while(inb(ATA_STATUS(cmd->bus)) & ATA_BSY);
outb(ATA_COMMAND(cmd->bus), cmd->command);
if(!inb(ATA_STATUS(cmd->bus)))
return 0;
cmd->status = ata_wait_status(cmd->bus);
while((cmd->status = inb(ATA_STATUS(cmd->bus))) & ATA_BSY);
if(cmd->wait_status) while(!(cmd->status = inb(ATA_STATUS(cmd->bus)) & (cmd->wait_status | ATA_ERR)));
cmd->error = inb(ATA_ERROR(cmd->bus));
cmd->count = inb(ATA_COUNT(cmd->bus));
cmd->device = inb(ATA_DEVICE(cmd->bus));
cmd->lba_sep[0] = inb(ATA_LBAL(cmd->bus));
cmd->lba_sep[1] = inb(ATA_LBAM(cmd->bus));
cmd->lba_sep[2] = inb(ATA_LBAH(cmd->bus));
cmd->lba_sep[3] = 0;
return cmd->status;
}
void init_drive(ata_drive *drive)
{
int bus = drive->bus;
// Check if the controller exists
// by writing a value to it and check
// that the same one is returned
int v1 = inb(ATA_LBAL(bus));
outb(ATA_LBAL(bus), (~v1)&0xFF);
int v2 = inb(ATA_LBAL(bus));
if(v2 != ((~v1)&0xFF))
return;
// Check if the drive exists
// by selecting the drive
outb(ATA_DEVICE(bus), 0xA0 | drive->ms);
if(!(ata_wait_status(bus) & ATA_RDY))
return;
outb(ATA_CONTROL(bus), ATA_SRST);
outb(ATA_CONTROL(bus), 0);
uint64_t lba = inb(ATA_LBAH(bus))<<16 | inb(ATA_LBAM(bus)) << 8 | inb(ATA_LBAL(bus));
ata_cmd_t command = {
.bus = bus,
.device=0xA0 | drive->ms,
.command = ATA_CMD_IDENTIFY,
.wait_status = ATA_DRQ,
};
if(lba == ATAPI_LBA_MAGIC)
{
drive->atapi = 1;
command.command = ATA_CMD_IDENTIFY_PACKET;
}
if(!ata_send_command(&command, 1))
return;
// Read IDENTIFY information
uint16_t *buf = (void *)&drive->id;
for(int i=0; i<256; i++)
{
buf[i] = inw(ATA_DATA(drive->bus));
}
drive->exists = 1;
}
int ata_read_block(ata_drive *drive, uint64_t lba, void *buffer)
{
int retries = 5;
while(retries)
{
ata_cmd_t command = {
.bus = drive->bus,
.count = 1,
.lba = lba & 0xFFFFFF,
.device = 0xE0 | drive->ms | ((lba >> 24) & 0xF),
.command = ATA_CMD_READ_SECTORS,
};
int status = ata_send_command(&command,0);
if(status & (ATA_DF | ATA_ERR) || !(status & ATA_DRQ))
{
retries--;
continue;
}
uint16_t *buf = buffer;
for(int i=0; i<256; i++)
{
buf[i] = inw(ATA_DATA(drive->bus));
}
return 0;
}
debug_error("Reading disk failed\n");
return -1;
}
int ata_write_block(ata_drive *drive, uint64_t lba, void *buffer)
{
ata_cmd_t command = {
.bus = drive->bus,
.count = 1,
.lba = lba & 0xFFFFFF,
.device = 0xE0 | drive->ms | ((lba >> 24) & 0xF),
.command = ATA_CMD_WRITE_SECTORS,
};
ata_send_command(&command, 0);
uint16_t *buf = buffer;
for(int i=0; i<256; i++)
{
outw(ATA_DATA(drive->bus), buf[i]);
}
return 0;
}
void ata_init()
{
init_drive(&drives[0]);
init_drive(&drives[1]);
init_drive(&drives[2]);
init_drive(&drives[3]);
}

101
kernel/include/ata.h Normal file
View File

@ -0,0 +1,101 @@
#pragma once
#include <stdint.h>
#define ATA_PRIMARY 0x1F0
#define ATA_SECONDARY 0x170
#define ATA_MASTER 0x00
#define ATA_SLAVE 0x10
// Input to controller
#define ATA_FEATURE(x) (x + 1)
#define ATA_COUNT(x) (x + 2)
#define ATA_LBAL(x) (x + 3)
#define ATA_LBAM(x) (x + 4)
#define ATA_LBAH(x) (x + 5)
#define ATA_DEVICE(x) (x + 6)
#define ATA_COMMAND(x) (x + 7)
#define ATA_CONTROL(x) (x + 0x206)
// Output from controller
#define ATA_DATA(x) (x + 0)
#define ATA_ERROR(x) (x + 1)
// COUNT
// LBAL
// LBAM
// LBAH
// DEVICE
#define ATA_STATUS(x) (x + 7)
#define ATA_ERR (1<<0)
#define ATA_DRQ (1<<3)
#define ATA_SRV (1<<4)
#define ATA_DF (1<<5)
#define ATA_RDY (1<<6)
#define ATA_BSY (1<<7)
#define ATA_nIEN (1<<1)
#define ATA_SRST (1<<2)
#define ATA_CMD_IDENTIFY 0xEC
#define ATA_CMD_IDENTIFY_PACKET 0xA1
#define ATA_CMD_READ_SECTORS 0x20
#define ATA_CMD_WRITE_SECTORS 0x30
#define ATA_CMD_PACKET 0xA0
#define ATAPI_LBA_MAGIC 0xEB1401
typedef struct ata_drive
{
int exists;
int bus;
int ms;
int atapi;
struct {
uint16_t config;
uint16_t unused1[9];
char serial[20];
uint16_t unused2[3];
char firmware[8];
char model[40];
uint8_t unused3;
uint8_t sectors_per_interrupt;
uint16_t unused4;
uint16_t capabilities[2];
uint16_t unused5[2];
uint16_t validity;
uint16_t unused6[3];
uint32_t capacity_sectors;
uint16_t sectors_per_command;
uint32_t capacity_lba28;
uint16_t unused7[38];
uint64_t capcity_lba48;
uint16_t unused8[152];
}__attribute__((packed)) id;
} ata_drive;
ata_drive drives[4];
typedef struct ata_cmd_st
{
uint16_t bus;
union {
uint8_t feature;
uint8_t error;
};
uint8_t count;
union {
uint64_t lba;
uint8_t lba_sep[4];
};
uint8_t device;
union {
uint8_t command;
uint8_t status;
};
uint8_t wait_status;
} ata_cmd_t;
int ata_read_block(struct ata_drive *drive, uint64_t lba, void *buffer);
int ata_write_block(struct ata_drive *drive, uint64_t lba, void *buffer);
void ata_init();