lots of progress, including readonly PATA driver and part of FAT16 driver
This commit is contained in:
parent
63167f223e
commit
2ddbeb9f72
27 changed files with 287 additions and 276 deletions
2
makefile
2
makefile
|
@ -21,7 +21,7 @@ skel:
|
|||
mkdir -p out/fs
|
||||
cp -r fs-skel/* out/fs/
|
||||
|
||||
kgccargs = -Wall -m32 -Og -ffreestanding -fno-asynchronous-unwind-tables
|
||||
kgccargs = -Wall -Wsuggest-attribute=pure -Wsuggest-attribute=const -Wsuggest-attribute=malloc -m32 -Og -ffreestanding -fno-asynchronous-unwind-tables
|
||||
ugccargs = ${kgccargs} -Isrc/libc/inc
|
||||
nasmargs = -f elf32
|
||||
|
||||
|
|
|
@ -38,23 +38,16 @@ enum {
|
|||
};
|
||||
|
||||
enum {
|
||||
ATA_REG_DATA = 0x0,
|
||||
ATA_REG_ERROR = 0x1,
|
||||
ATA_REG_FEAT = 0x1,
|
||||
ATA_REG_COUNT_LOW = 0x2,
|
||||
ATA_REG_LBA0 = 0x3,
|
||||
ATA_REG_LBA1 = 0x4,
|
||||
ATA_REG_LBA2 = 0x5,
|
||||
ATA_REG_SELECT = 0x6,
|
||||
ATA_REG_CMD = 0x7,
|
||||
ATA_REG_STATUS = 0x7,
|
||||
ATA_REG_COUNT_HIGH = 0x8,
|
||||
ATA_REG_LBA3 = 0x9,
|
||||
ATA_REG_LBA4 = 0xa,
|
||||
ATA_REG_LBA5 = 0xb,
|
||||
ATA_REG_CONTROL = 0xc,
|
||||
ATA_REG_ALT_STATUS = 0xc,
|
||||
ATA_REG_ADDR = 0xd
|
||||
ATA_REG_DATA = 0x0,
|
||||
ATA_REG_ERROR = 0x1,
|
||||
ATA_REG_FEAT = 0x1,
|
||||
ATA_REG_COUNT = 0x2,
|
||||
ATA_REG_LBA0 = 0x3,
|
||||
ATA_REG_LBA1 = 0x4,
|
||||
ATA_REG_LBA2 = 0x5,
|
||||
ATA_REG_SELECT = 0x6,
|
||||
ATA_REG_CMD = 0x7,
|
||||
ATA_REG_STATUS = 0x7,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -71,5 +64,12 @@ enum {
|
|||
};
|
||||
|
||||
enum {
|
||||
ATA_CONTROL_NO_IRQS = 0x02
|
||||
ATA_CONTROL_NO_IRQS = 0x02,
|
||||
};
|
||||
|
||||
enum {
|
||||
PATA_TYPE_ID = 0x0000,
|
||||
SATA_TYPE_ID = 0xc33c,
|
||||
PATAPI_TYPE_ID = 0xeb14,
|
||||
SATAPI_TYPE_ID = 0x9669
|
||||
};
|
|
@ -1,24 +1,24 @@
|
|||
#include "drive.h"
|
||||
#include "fat.h"
|
||||
#include "panic.h"
|
||||
#include "fat.h"
|
||||
|
||||
uint8_t n_drives = 0;
|
||||
struct drive drives[256];
|
||||
|
||||
drive_file_id_t unknown_get_file(struct drive *d, char *path) {
|
||||
__attribute__ ((const)) drive_file_id_t unknown_get_file(const struct drive *d, const char *path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void unknown_free_file(struct drive *d, drive_file_id_t fid) {
|
||||
void unknown_free_file(const struct drive *d, drive_file_id_t fid) {
|
||||
panic("Free file called on unknown file system");
|
||||
}
|
||||
|
||||
void unknown_load_sector(struct drive *d, drive_file_id_t fid, uint32_t sector, void *at) {
|
||||
void unknown_load_sector(const struct drive *d, drive_file_id_t fid, uint32_t sector, void *at) {
|
||||
panic("Load sector called on unknown file system");
|
||||
}
|
||||
|
||||
uint32_t unknown_get_free_sectors(struct drive *d) {
|
||||
return d->n_sectors;
|
||||
__attribute__ ((const)) uint32_t unknown_get_free_sectors(const struct drive *d) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void determine_fs(struct drive *d) {
|
||||
|
|
|
@ -14,15 +14,15 @@ struct drive {
|
|||
char *drive_type;
|
||||
char *fs_type;
|
||||
|
||||
uint8_t (*read_sectors)(struct drive *d, uint32_t start, uint32_t count, void *buffer);
|
||||
uint8_t (*write_sectors)(struct drive *d, uint32_t start, uint32_t count, void *buffer);
|
||||
uint8_t (*read_sectors)(const struct drive *d, uint32_t start, uint32_t count, void *buffer);
|
||||
uint8_t (*write_sectors)(const struct drive *d, uint32_t start, uint32_t count, const void *buffer);
|
||||
uint32_t n_sectors;
|
||||
drive_id_t drive_id;
|
||||
|
||||
drive_file_id_t (*get_file)(struct drive *d, char *path);
|
||||
void (*free_file)(struct drive *d, drive_file_id_t fid);
|
||||
void (*load_sector)(struct drive *d, drive_file_id_t fid, uint32_t sector, void *at);
|
||||
uint32_t (*get_free_sectors)(struct drive *d);
|
||||
drive_file_id_t (*get_file)(const struct drive *d, const char *path);
|
||||
void (*free_file)(const struct drive *d, drive_file_id_t fid);
|
||||
void (*load_sector)(const struct drive *d, drive_file_id_t fid, uint32_t sector, void *at);
|
||||
uint32_t (*get_free_sectors)(const struct drive *d);
|
||||
fs_id_t fs_id;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#include "fat.h"
|
||||
#include "ata.h"
|
||||
#include "panic.h"
|
||||
#include "drive.h"
|
||||
#include "mem.h"
|
||||
#include "panic.h"
|
||||
#include "util.h"
|
||||
#include "ata.h"
|
||||
#include "fat.h"
|
||||
#include "mem.h"
|
||||
|
||||
#define MAX_FAT_DRIVES 16
|
||||
#define MAX_OPEN_FILES_PER_DRIVE 32
|
||||
|
@ -57,20 +57,19 @@ struct fat_info {
|
|||
uint8_t fs_type[8];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define CTOS(c, fi) ((fi)->reserved_sectors + (fi)->sectors_per_fat * (fi)->fats + ((fi)->root_entries >> 4) + (c) - 2)
|
||||
#define CTOS(c, fdi) ((fdi)->data_start + (c) - 2)
|
||||
|
||||
struct fat_drive_info {
|
||||
struct fat_info *fi;
|
||||
const struct fat_info *fi;
|
||||
uint16_t *fat;
|
||||
uint16_t root_start;
|
||||
uint16_t data_start;
|
||||
struct directory_entry open_files[MAX_OPEN_FILES_PER_DRIVE];
|
||||
};
|
||||
|
||||
struct fat_drive_info infos[MAX_FAT_DRIVES];
|
||||
uint8_t next_id = 0;
|
||||
|
||||
#define FI(n) ((struct fat_info *)(infos[n].fi + 3))
|
||||
#define FN(n, f) (infos[n].open_files[f - 1])
|
||||
|
||||
uint8_t fat_driver_buffer[512];
|
||||
struct fat_info *next_fi;
|
||||
|
||||
|
@ -80,8 +79,9 @@ void alloc_next_fi() {
|
|||
panic("Out of memory in FAT driver.");
|
||||
}
|
||||
|
||||
struct drive *cur_drive;
|
||||
const struct drive *cur_drive;
|
||||
fs_id_t cur_id;
|
||||
const struct fat_drive_info *cur_fdi;
|
||||
struct directory_entry *cur_dir;
|
||||
|
||||
//loads cluster `c`
|
||||
|
@ -91,7 +91,7 @@ void load_cluster(uint16_t c, void *to) {
|
|||
return;
|
||||
}
|
||||
|
||||
uint32_t s = CTOS(c, FI(cur_id));
|
||||
uint32_t s = CTOS(c, cur_fdi);
|
||||
cur_drive->read_sectors(cur_drive, s, 1, to);
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ uint16_t next_cluster(uint16_t c) {
|
|||
panic("TODO: compute next sector (or 0 for none)");
|
||||
}
|
||||
|
||||
static inline bool check_fat_names(uint8_t *a, uint8_t *b) {
|
||||
static inline bool check_fat_names(const uint8_t *a, const uint8_t *b) {
|
||||
return (((uint32_t *)a)[0] == ((uint32_t *)b)[0]) &&
|
||||
(((uint32_t *)a)[1] == ((uint32_t *)b)[1]) &&
|
||||
(((uint16_t *)a)[8] == ((uint16_t *)b)[8]) &&
|
||||
|
@ -107,8 +107,8 @@ static inline bool check_fat_names(uint8_t *a, uint8_t *b) {
|
|||
}
|
||||
|
||||
//after: cur_dir -> specified entry in root
|
||||
bool try_locate_root_entry(uint8_t *fat_name) {
|
||||
uint32_t cur_dir_sect = FI(cur_id)->reserved_sectors + FI(cur_id)->sectors_per_fat * FI(cur_id)->fats - 1;
|
||||
bool try_locate_root_entry(const uint8_t *fat_name) {
|
||||
uint32_t cur_dir_sect = cur_fdi->root_start - 1;
|
||||
cur_dir = (struct directory_entry *)(fat_driver_buffer + 512);
|
||||
while (true) {
|
||||
if (cur_dir == (struct directory_entry *)(fat_driver_buffer + 512)) {
|
||||
|
@ -127,7 +127,7 @@ bool try_locate_root_entry(uint8_t *fat_name) {
|
|||
|
||||
//before: cur_dir -> entry of dir to search
|
||||
//after: cur_dir -> specified entry in dir
|
||||
bool try_locate_entry(uint8_t *fat_name) {
|
||||
bool try_locate_entry(const uint8_t *fat_name) {
|
||||
uint16_t cur_dir_cluster = cur_dir->first_cluster;
|
||||
load_cluster(cur_dir_cluster, fat_driver_buffer);
|
||||
cur_dir = (struct directory_entry *)fat_driver_buffer;
|
||||
|
@ -146,32 +146,41 @@ bool try_locate_entry(uint8_t *fat_name) {
|
|||
}
|
||||
}
|
||||
|
||||
drive_file_id_t fat_get_file(struct drive *d, char *path) {
|
||||
drive_file_id_t fat_get_file(const struct drive *d, const char *path) {
|
||||
cur_drive = d;
|
||||
cur_id = d->drive_id;
|
||||
cur_fdi = &infos[cur_id];
|
||||
const struct directory_entry *open_files = cur_fdi->open_files - 1;
|
||||
for (drive_file_id_t n = 1; n != MAX_OPEN_FILES_PER_DRIVE + 1; ++n)
|
||||
if (!*(uint8_t *)(&FN(d->drive_id, n))) {
|
||||
panic("TODO: open path at FN(id, n)");
|
||||
if (!*(uint8_t *)(&open_files[n])) {
|
||||
panic("TODO: open path into open_files[n]");
|
||||
return n;
|
||||
}
|
||||
panic("Maximum number of files open reached for FAT drive.");
|
||||
}
|
||||
|
||||
void fat_free_file(struct drive *d, drive_file_id_t fid) {
|
||||
*(uint8_t *)(&FN(d->drive_id, fid)) = 0;
|
||||
void fat_free_file(const struct drive *d, drive_file_id_t fid) {
|
||||
*(uint8_t *)(&infos[d->drive_id].open_files[fid - 1]) = 0;
|
||||
}
|
||||
|
||||
void fat_load_sector(struct drive *d, drive_file_id_t fid, uint32_t sector, void *at) {
|
||||
void fat_load_sector(const struct drive *d, drive_file_id_t fid, uint32_t sector, void *at) {
|
||||
cur_drive = d;
|
||||
cur_id = d->drive_id;
|
||||
uint16_t c = FN(d->drive_id, fid).first_cluster;
|
||||
cur_fdi = &infos[cur_id];
|
||||
uint16_t c = cur_fdi->open_files[fid - 1].first_cluster;
|
||||
for (uint32_t i = 0; i < sector; ++i)
|
||||
c = next_cluster(c);
|
||||
load_cluster(c, at);
|
||||
}
|
||||
|
||||
uint32_t fat_get_free_sectors(struct drive *d) {
|
||||
panic("TODO: get free sectors of drive");
|
||||
__attribute__ ((pure)) uint32_t fat_get_free_sectors(const struct drive *d) {
|
||||
uint16_t *start = infos[d->fs_id].fat + 2;
|
||||
uint16_t *end = start + d->n_sectors - infos[d->fs_id].data_start;
|
||||
uint32_t count = 0;
|
||||
for (uint16_t *i = start; i < end; ++i)
|
||||
if (!*i)
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
|
||||
void init_fat() {
|
||||
|
@ -186,8 +195,8 @@ bool try_fat_init_drive(struct drive *d) {
|
|||
return false;
|
||||
memcpy(next_fi, fat_driver_buffer + 3, sizeof(struct fat_info));
|
||||
uint32_t *fs_type_32 = (uint32_t *)next_fi->fs_type;
|
||||
if ((fs_type_32[0] != ('F' + 'A' * 256 + 'T' + 65536 + '1' * 16777216)) ||
|
||||
(fs_type_32[1] != ('6' + ' ' * 256 + ' ' + 65536 + ' ' * 16777216)))
|
||||
if ((fs_type_32[0] != ('F' + 'A' * 256 + 'T' * 65536 + '1' * 16777216)) ||
|
||||
(fs_type_32[1] != ('6' + ' ' * 256 + ' ' * 65536 + ' ' * 16777216)))
|
||||
return false;
|
||||
|
||||
d->fs_type = "FAT16";
|
||||
|
@ -199,10 +208,15 @@ bool try_fat_init_drive(struct drive *d) {
|
|||
d->fs_id = next_id;
|
||||
infos[next_id].fi = next_fi;
|
||||
infos[next_id].fat = allocate_pages(((next_fi->sectors_per_fat - 1) >> 3) + 1);
|
||||
for (drive_file_id_t i = 0; i < MAX_OPEN_FILES_PER_DRIVE; ++i)
|
||||
*(uint8_t *)&FN(next_id, i) = 0;
|
||||
infos[next_id].root_start = next_fi->reserved_sectors +
|
||||
next_fi->sectors_per_fat * next_fi->fats;
|
||||
infos[next_id].data_start = infos[next_id].root_start +
|
||||
((next_fi->root_entries - 1) >> 4) + 1;
|
||||
|
||||
d->read_sectors(d, next_fi->reserved_sectors, next_fi->sectors_per_fat, infos[next_id].fat);
|
||||
struct directory_entry *open_files = infos[next_id].open_files - 1;
|
||||
for (drive_file_id_t i = 0; i < MAX_OPEN_FILES_PER_DRIVE; ++i)
|
||||
*(uint8_t *)&open_files[i] = 0;
|
||||
|
||||
alloc_next_fi();
|
||||
++next_id;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef FAT_H
|
||||
#define FAT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "drive.h"
|
||||
|
||||
void init_fat();
|
||||
|
|
228
src/kernel/ide.c
228
src/kernel/ide.c
|
@ -1,171 +1,192 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "drive.h"
|
||||
#include "panic.h"
|
||||
#include "util.h"
|
||||
#include "drive.h"
|
||||
#include "pci.h"
|
||||
#include "ata.h"
|
||||
#include "pci.h"
|
||||
|
||||
#define MAX_IDE_DRIVES 8
|
||||
|
||||
struct ide_drive_info {
|
||||
uint16_t base_port;
|
||||
uint16_t control_port;
|
||||
uint16_t alt_port;
|
||||
bool slave;
|
||||
};
|
||||
|
||||
struct ide_drive_info ide_drives[MAX_IDE_DRIVES];
|
||||
drive_id_t n_ide_drives = 0;
|
||||
|
||||
void spin_delay() {
|
||||
for (uint32_t i = -1; i; --i)
|
||||
;
|
||||
typedef uint16_t spinner_t;
|
||||
|
||||
//returns the status after waiting
|
||||
uint8_t wait_after_cmd(uint16_t base_port) {
|
||||
for (spinner_t n = -1; n; --n) {
|
||||
uint8_t s = inb(base_port | ATA_REG_STATUS);
|
||||
if (s & ATA_STATUS_ERROR)
|
||||
panic("Error status in IDE driver.");
|
||||
if (!(s & ATA_STATUS_BUSY))
|
||||
return s;
|
||||
}
|
||||
panic("Spun out in IDE driver.");
|
||||
}
|
||||
|
||||
//return true on error condition
|
||||
bool poll(struct ide_drive_info *info) {
|
||||
spin_delay();
|
||||
|
||||
uint8_t status;
|
||||
|
||||
while ((status = inb(info->base_port | ATA_REG_STATUS)) & ATA_STATUS_BUSY)
|
||||
;
|
||||
|
||||
return (status & (ATA_STATUS_ERROR | ATA_STATUS_DRIVE_FAULT)) || !(status & ATA_STATUS_DRIVE_READY);
|
||||
//returns the status after waiting
|
||||
uint8_t wait_for_ready(uint16_t base_port) {
|
||||
for (spinner_t n = -1; n; --n) {
|
||||
uint8_t s = inb(base_port | ATA_REG_STATUS);
|
||||
if (s & ATA_STATUS_ERROR)
|
||||
panic("Error status in IDE driver.");
|
||||
if (s & ATA_STATUS_DRIVE_READY)
|
||||
return s;
|
||||
}
|
||||
panic("Spun out in IDE driver.");
|
||||
}
|
||||
|
||||
uint8_t ide_ata_rs(struct drive *d, uint32_t start, uint32_t count, void *buffer) {
|
||||
if (start & 0xf0000000)
|
||||
panic("IDE ATA driver only supports LBA28 addressing currently.");
|
||||
//returns the status after waiting
|
||||
uint8_t wait_for_error_or_ready(uint16_t base_port) {
|
||||
for (spinner_t n = -1; n; --n) {
|
||||
uint8_t s = inb(base_port | ATA_REG_STATUS);
|
||||
if (s & (ATA_STATUS_DRIVE_READY | ATA_STATUS_ERROR))
|
||||
return s;
|
||||
}
|
||||
panic("Spun out in IDE driver.");
|
||||
}
|
||||
|
||||
struct ide_drive_info *info = ide_drives + d->drive_id;
|
||||
//returns the status after waiting
|
||||
uint8_t wait_for_data_ready_not_busy(uint16_t base_port) {
|
||||
for (spinner_t n = -1; n; --n) {
|
||||
uint8_t s = inb(base_port | ATA_REG_STATUS);
|
||||
if (!(s & ATA_STATUS_BUSY) && (s & ATA_STATUS_DATA_READY))
|
||||
return s;
|
||||
if (s & ATA_STATUS_ERROR)
|
||||
panic("Error status in IDE driver.");
|
||||
}
|
||||
panic("Spun out in IDE driver.");
|
||||
}
|
||||
|
||||
uint8_t ide_ata_rs(const struct drive *d, uint32_t start, uint32_t count, void *buffer) {
|
||||
if (start >= d->n_sectors)
|
||||
return 0;
|
||||
if (start + count > d->n_sectors)
|
||||
count = d->n_sectors - start;
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (start & 0xf0000000)
|
||||
panic("IDE ATA driver does not support reads starting past 256MiB currently.");
|
||||
if (count & 0xffffff00)
|
||||
panic("IDE ATA driver only supports reading up to 128k at a time currently.");
|
||||
panic("IDE ATA driver does not support reads over 128kiB in length currently.");
|
||||
|
||||
uint32_t lba = start & 0x00ffffff;
|
||||
|
||||
uint32_t spin = -1;
|
||||
while (inb(info->base_port | ATA_REG_STATUS) & ATA_STATUS_BUSY)
|
||||
if (!spin--)
|
||||
panic("Spun out in IDE ATA reading");
|
||||
struct ide_drive_info *info = ide_drives + d->drive_id;
|
||||
|
||||
outb(info->base_port | ATA_REG_SELECT, (info->slave ? 0xf0 : 0xe0) | (start >> 24));
|
||||
outb(info->base_port | ATA_REG_COUNT_LOW, count);
|
||||
//spin?
|
||||
|
||||
outb(info->base_port | ATA_REG_COUNT, count);
|
||||
outb(info->base_port | ATA_REG_LBA0, lba);
|
||||
outb(info->base_port | ATA_REG_LBA1, lba >> 8);
|
||||
outb(info->base_port | ATA_REG_LBA2, lba >> 16);
|
||||
|
||||
uint16_t *buffer_16 = buffer;
|
||||
outb(info->base_port | ATA_REG_CMD, ATA_CMD_READ);
|
||||
|
||||
uint16_t *buf16 = (uint16_t *)buffer;
|
||||
|
||||
for (uint16_t i = 0; i < count; ++i) {
|
||||
if (poll(info))
|
||||
return i;
|
||||
wait_for_data_ready_not_busy(info->base_port);
|
||||
for (uint16_t j = 0; j < 256; ++j)
|
||||
*buffer_16++ = inw(info->base_port + ATA_REG_DATA);
|
||||
*buf16++ = inw(info->base_port | ATA_REG_DATA);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t ide_ata_ws(struct drive *d, uint32_t start, uint32_t count, void *buffer) {
|
||||
uint8_t ide_ata_ws(const struct drive *d, uint32_t start, uint32_t count, const void *buffer) {
|
||||
panic("IDE ATA writing not implemented yet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t ide_atapi_rs(struct drive *d, uint32_t start, uint32_t count, void *buffer) {
|
||||
uint8_t ide_atapi_rs(const struct drive *d, uint32_t start, uint32_t count, void *buffer) {
|
||||
//panic("IDE ATAPI reading not implemented yet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t ide_atapi_ws(struct drive *d, uint32_t start, uint32_t count, void *buffer) {
|
||||
uint8_t ide_atapi_ws(const struct drive *d, uint32_t start, uint32_t count, const void *buffer) {
|
||||
panic("IDE ATAPI writing not implemented yet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct id_space {
|
||||
uint16_t device_type;//0
|
||||
uint8_t skip1[98 - 2];
|
||||
uint16_t capabilities;//98
|
||||
uint8_t skip2[120 - (98 + 2)];
|
||||
uint8_t skip1[120];
|
||||
uint32_t max_lba;//120
|
||||
uint8_t skip3[164 - (120 + 4)];
|
||||
uint32_t command_sets;//164
|
||||
uint8_t skip4[200 - (164 + 4)];
|
||||
uint32_t max_lba_ext;//200
|
||||
uint8_t skip5[512 - (200 + 4)];
|
||||
} __attribute__ ((__packed__));
|
||||
uint8_t skip2[512 - (120 + 4)];
|
||||
} __attribute__ ((__packed__ ));
|
||||
|
||||
void read_id_space(uint16_t base_port, struct id_space *to) {
|
||||
uint32_t *to_32 = (uint32_t *)to;
|
||||
for (uint8_t i = 0; i < 128; ++i)
|
||||
*(to_32++) = ind(base_port | ATA_REG_DATA);
|
||||
}
|
||||
void vga_printsz(char *s);
|
||||
|
||||
void test_drive(uint16_t base_port, uint16_t control_port, bool slave) {
|
||||
outb(base_port | ATA_REG_SELECT, slave ? ATA_SLAVE_SELECT : ATA_MASTER_SELECT);
|
||||
spin_delay();
|
||||
void test_drive(uint16_t base_port, uint16_t alt_port, bool slave) {
|
||||
if (n_ide_drives == MAX_IDE_DRIVES)
|
||||
panic("Maximum number of IDE drives reached.");
|
||||
|
||||
struct ide_drive_info *next = ide_drives + n_ide_drives;
|
||||
struct drive next_d;
|
||||
next_d.drive_id = n_ide_drives;
|
||||
|
||||
next->base_port = base_port;
|
||||
next->alt_port = alt_port;
|
||||
next->slave = slave;
|
||||
|
||||
outb(base_port | ATA_REG_SELECT, slave ? 0xb0 : 0xa0);
|
||||
outb(base_port | ATA_REG_COUNT, 0);
|
||||
outb(base_port | ATA_REG_LBA0, 0);
|
||||
outb(base_port | ATA_REG_LBA1, 0);
|
||||
outb(base_port | ATA_REG_LBA2, 0);
|
||||
|
||||
outb(base_port | ATA_REG_CMD, ATA_CMD_ID);
|
||||
spin_delay();
|
||||
|
||||
if (!inb(base_port | ATA_REG_STATUS))
|
||||
return;
|
||||
|
||||
if (n_ide_drives == MAX_IDE_DRIVES)
|
||||
panic("Maximum IDE drives reached");
|
||||
struct id_space ids;
|
||||
|
||||
outb(base_port | ATA_REG_CONTROL, ATA_CONTROL_NO_IRQS);
|
||||
if (!(wait_for_error_or_ready(base_port) & ATA_STATUS_ERROR)) {
|
||||
wait_for_ready(base_port);
|
||||
for (uint16_t *ids_16 = (uint16_t *)&ids; ids_16 < (uint16_t *)&ids + 256; ++ids_16)
|
||||
*ids_16 = inw(base_port | ATA_REG_DATA);
|
||||
|
||||
struct ide_drive_info *this_drive = ide_drives + n_ide_drives;
|
||||
this_drive->base_port = base_port;
|
||||
this_drive->control_port = control_port;
|
||||
this_drive->slave = slave;
|
||||
|
||||
struct drive data;
|
||||
data.drive_id = n_ide_drives;
|
||||
|
||||
uint32_t spin_out = -1;
|
||||
while (1) {//wait for identify to complete
|
||||
uint8_t status = inb(base_port | ATA_REG_STATUS);
|
||||
if (status & ATA_STATUS_ERROR) {
|
||||
uint16_t type = inb(base_port | ATA_REG_LBA1) +
|
||||
(inb(base_port | ATA_REG_LBA2) << 8);
|
||||
|
||||
//These two are listed on OSDev Wiki
|
||||
// as being ATAPI device types.
|
||||
if ((type != 0xeb14) && (type != 0x9669))
|
||||
return;
|
||||
|
||||
outb(base_port | ATA_REG_CMD, ATAPI_CMD_ID);
|
||||
|
||||
data.read_sectors = &ide_atapi_rs;
|
||||
data.write_sectors = &ide_atapi_ws;
|
||||
data.drive_type = "IDE ATAPI";
|
||||
break;
|
||||
next_d.drive_type = "IDE PATA";
|
||||
next_d.read_sectors = &ide_ata_rs;
|
||||
next_d.write_sectors = &ide_ata_ws;
|
||||
}
|
||||
else {
|
||||
uint16_t code = inb(base_port | 0x4) + (inb(base_port | 0x5) << 8);
|
||||
if (!code) {
|
||||
panic("PATA identification aborted.");
|
||||
}
|
||||
if (!(status & ATA_STATUS_BUSY) && (status & ATA_STATUS_DATA_READY)) {
|
||||
data.read_sectors = &ide_ata_rs;
|
||||
data.write_sectors = &ide_ata_ws;
|
||||
data.drive_type = "IDE ATA";
|
||||
break;
|
||||
if (code == 0xeb14) {
|
||||
next_d.drive_type = "IDE PATAPI";
|
||||
next_d.read_sectors = &ide_atapi_rs;
|
||||
next_d.write_sectors = &ide_atapi_ws;
|
||||
|
||||
//TODO: issue proper identify command
|
||||
ids.max_lba = -1;
|
||||
}
|
||||
else if (code == 0xc33c) {
|
||||
next_d.drive_type = "IDE SATA";
|
||||
|
||||
//TODO: set up drive hooks, issue proper identify command
|
||||
return;
|
||||
}
|
||||
if (!spin_out--)
|
||||
panic("IDE ATA identify won't complete");
|
||||
}
|
||||
|
||||
struct id_space id;
|
||||
read_id_space(base_port, &id);
|
||||
//in the future, maybe add support for 48-bit LBA, and/or CHS addressing
|
||||
if (!ids.max_lba)
|
||||
panic("Encountered ATA drive that doesn't support 28-bit LBA");
|
||||
next_d.n_sectors = ids.max_lba;
|
||||
|
||||
if (!(id.capabilities & ATA_CAP_LBA))
|
||||
//TODO: CHS compability driver?
|
||||
return;
|
||||
data.n_sectors = (id.command_sets & ATA_SET_EXT) ? id.max_lba_ext : id.max_lba;
|
||||
|
||||
commit_drive(data);
|
||||
commit_drive(next_d);
|
||||
++n_ide_drives;
|
||||
}
|
||||
|
||||
|
@ -176,14 +197,9 @@ void init_ide() {
|
|||
while ((device = find_pci_device_from_class_and_subclass(PCI_MASS_STORAGE, PCI_IDE, check_from, &check_from))) {
|
||||
++check_from;
|
||||
|
||||
uint16_t primary_base_port = device->bar0 <= 1 ? 0x01f0 : device->bar0;
|
||||
uint16_t primary_control_port = device->bar1 <= 1 ? 0x03f6 : device->bar1;
|
||||
uint16_t secondary_base_port = device->bar2 <= 1 ? 0x0170 : device->bar2;
|
||||
uint16_t secondary_control_port = device->bar3 <= 1 ? 0x0376 : device->bar3;
|
||||
|
||||
test_drive(primary_base_port, primary_control_port, false);
|
||||
test_drive(primary_base_port, primary_control_port, true);
|
||||
test_drive(secondary_base_port, secondary_control_port, false);
|
||||
test_drive(secondary_base_port, secondary_control_port, true);
|
||||
test_drive(0x01f0, 0x03f6, false);
|
||||
test_drive(0x01f0, 0x03f6, true);
|
||||
test_drive(0x0170, 0x0376, false);
|
||||
test_drive(0x0170, 0x0376, true);
|
||||
}
|
||||
}
|
|
@ -1,12 +1,6 @@
|
|||
#ifndef IDE_H
|
||||
#define IDE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "drive.h"
|
||||
|
||||
void init_ide();
|
||||
|
||||
uint8_t ide_read_sectors(drive_id_t id, uint32_t start, uint32_t count, void *buffer);
|
||||
uint8_t ide_write_sectors(drive_id_t id, uint32_t start, uint32_t count, void *buffer);
|
||||
|
||||
#endif
|
|
@ -1,30 +1,20 @@
|
|||
#include <stdint.h>
|
||||
#include "vga.h"
|
||||
#include "serial.h"
|
||||
#include "panic.h"
|
||||
#include "boot.h"
|
||||
#include "util.h"
|
||||
#include "vesa.h"
|
||||
#include "fat.h"
|
||||
#include "ide.h"
|
||||
#include "panic.h"
|
||||
#include "serial.h"
|
||||
#include "util.h"
|
||||
#include "mem.h"
|
||||
#include "pci.h"
|
||||
#include "boot.h"
|
||||
#include "vesa.h"
|
||||
|
||||
char nbuf[11];
|
||||
|
||||
#define SOTL(field) field = (void *)((*((uint16_t *)(&field) + 1) << 16) + *(uint16_t *)(&field));
|
||||
#include "vga.h"
|
||||
|
||||
__attribute__ ((noreturn)) void main() {
|
||||
SOTL(VESA_INFO->oem)
|
||||
SOTL(VESA_INFO->modes)
|
||||
SOTL(VESA_INFO->vendor)
|
||||
SOTL(VESA_INFO->pname)
|
||||
SOTL(VESA_INFO->prev)
|
||||
char nbuf[11];
|
||||
|
||||
init_mmap();
|
||||
|
||||
init_vesa();
|
||||
|
||||
init_serial();
|
||||
|
||||
vga_blank();
|
||||
|
@ -64,8 +54,10 @@ __attribute__ ((noreturn)) void main() {
|
|||
vga_printch('\n');
|
||||
|
||||
init_fat();
|
||||
//other fs drivers
|
||||
|
||||
init_ide();
|
||||
//other drive drivers
|
||||
|
||||
u8_dec(n_drives, nbuf);
|
||||
vga_printsz(nbuf);
|
||||
|
@ -79,24 +71,27 @@ __attribute__ ((noreturn)) void main() {
|
|||
vga_printsz(nbuf);
|
||||
vga_printsz(" (");
|
||||
vga_printsz(d->drive_type);
|
||||
vga_printsz("): ");
|
||||
|
||||
vga_printsz(d->fs_type);
|
||||
vga_printsz(", ");
|
||||
|
||||
u32_dec(d->n_sectors / 2, nbuf);
|
||||
vga_printsz(nbuf);
|
||||
if (d->n_sectors % 2)
|
||||
vga_printsz(".5");
|
||||
vga_printsz("k, ");
|
||||
vga_printsz("k): ");
|
||||
|
||||
vga_printsz(d->fs_type);
|
||||
|
||||
uint32_t free_sectors = d->get_free_sectors(d);
|
||||
if (free_sectors != -1) {
|
||||
u32_dec(free_sectors / 2, nbuf);
|
||||
vga_printsz(", ");
|
||||
vga_printsz(nbuf);
|
||||
if (free_sectors % 2)
|
||||
vga_printsz(".5");
|
||||
vga_printsz("k free");
|
||||
}
|
||||
|
||||
u32_dec(free_sectors / 2, nbuf);
|
||||
vga_printsz(nbuf);
|
||||
if (d->n_sectors % 2)
|
||||
vga_printsz(".5");
|
||||
vga_printsz("k free.\n");
|
||||
vga_printsz(".\n");
|
||||
}
|
||||
|
||||
vga_printch('\n');
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "panic.h"
|
||||
#include "mem.h"
|
||||
|
||||
#define DYNAMIC_START (0x10000000)
|
||||
#define DYNAMIC_END (DYNAMIC_START + 65536 * 4096)
|
||||
|
@ -55,7 +55,7 @@ void *allocate_pages(uint16_t n) {
|
|||
}
|
||||
|
||||
//in the future, change this to go by bytes or dwords instead of bits.
|
||||
void free_pages(void *ptr, uint16_t n) {
|
||||
void free_pages(const void *ptr, uint16_t n) {
|
||||
uint16_t page = ADDR_TO_PAGE(ptr);
|
||||
for (uint32_t i = page; i < page + n; ++i)
|
||||
CLEAR_PAGE(i);
|
||||
|
|
|
@ -7,7 +7,7 @@ extern uint16_t pages_left;
|
|||
|
||||
void init_mmap();
|
||||
|
||||
void *allocate_pages(uint16_t n);
|
||||
void free_pages(void *ptr, uint16_t n);
|
||||
void *allocate_pages(uint16_t n) __attribute__ ((malloc));
|
||||
void free_pages(const void *ptr, uint16_t n);
|
||||
|
||||
#endif
|
|
@ -1,10 +1,7 @@
|
|||
#include <stdint.h>
|
||||
#include "vga.h"
|
||||
#include "serial.h"
|
||||
#include "util.h"
|
||||
#include "panic.h"
|
||||
#include "vga.h"
|
||||
|
||||
void panic(char *message) {
|
||||
void panic(const char *message) {
|
||||
vga_set_color(0x4f);
|
||||
vga_blank();
|
||||
vga_printsz("Kernel panic: ");
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef PANIC_H
|
||||
#define PANIC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void panic(char *message) __attribute__ ((noreturn));
|
||||
void panic(const char *message) __attribute__ ((noreturn));
|
||||
|
||||
#endif
|
|
@ -1,8 +1,8 @@
|
|||
#include "boot.h"
|
||||
#include "mem.h"
|
||||
#include "util.h"
|
||||
#include "pci.h"
|
||||
#include "panic.h"
|
||||
#include "boot.h"
|
||||
#include "util.h"
|
||||
#include "mem.h"
|
||||
#include "pci.h"
|
||||
|
||||
enum {
|
||||
PCP_SELECT = 0x0cf8,
|
||||
|
@ -59,11 +59,6 @@ void pci_device_check(uint16_t number) {
|
|||
next_device->class = class >> 24;
|
||||
next_device->subclass = class >> 16;
|
||||
next_device->iface = class >> 8;
|
||||
|
||||
next_device->bar0 = pci_read_config(number, 4);
|
||||
next_device->bar1 = pci_read_config(number, 5);
|
||||
next_device->bar2 = pci_read_config(number, 6);
|
||||
next_device->bar3 = pci_read_config(number, 7);
|
||||
}
|
||||
|
||||
void pci_init() {
|
||||
|
|
|
@ -20,16 +20,10 @@ struct pci_device {
|
|||
uint8_t class;
|
||||
uint8_t subclass;
|
||||
uint8_t iface;
|
||||
|
||||
uint32_t bar0;
|
||||
uint32_t bar1;
|
||||
uint32_t bar2;
|
||||
uint32_t bar3;
|
||||
//etc
|
||||
};
|
||||
|
||||
extern uint16_t n_pci_devices;
|
||||
struct pci_device *nth_pci_device(uint16_t n);
|
||||
struct pci_device *nth_pci_device(uint16_t n) __attribute__ ((pure));
|
||||
|
||||
struct pci_device *find_pci_device_from_class_and_subclass(uint8_t class, uint8_t subclass, uint16_t start, uint16_t *index);
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "plef.h"
|
||||
#include "drive.h"
|
||||
#include "util.h"
|
||||
#include "plef.h"
|
||||
#include "task.h"
|
||||
#include "util.h"
|
||||
|
||||
#define PLEF_MAGIC 0xb9ba4c50
|
||||
|
||||
task_handle plef_run(struct drive *d, char *path) {
|
||||
task_handle plef_run(const struct drive *d, const char *path) {
|
||||
drive_file_id_t h = d->get_file(d, path);
|
||||
if (!h)
|
||||
return 0;
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define PLEF_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "drive.h"
|
||||
|
||||
typedef uint8_t task_handle;
|
||||
|
@ -17,6 +16,6 @@ struct plef_header {
|
|||
uint32_t entry_point;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
task_handle plef_run(struct drive *d, char *path);
|
||||
task_handle plef_run(const struct drive *d, const char *path);
|
||||
|
||||
#endif
|
|
@ -1,5 +1,6 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "serial.h"
|
||||
#include "util.h"
|
||||
|
||||
enum {
|
||||
|
@ -76,12 +77,12 @@ void sout(char b) {
|
|||
outb(CP_1 | CP_DATA, (uint8_t)b);
|
||||
}
|
||||
|
||||
void soutsz(char *s) {
|
||||
void soutsz(const char *s) {
|
||||
while (*s)
|
||||
sout(*(s++));
|
||||
}
|
||||
|
||||
void soutsn(char *s, uint8_t n) {
|
||||
void soutsn(const char *s, uint8_t n) {
|
||||
while (n--)
|
||||
sout(*(s++));
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#ifndef SERIAL_H
|
||||
#define SERIAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
bool serr();
|
||||
bool serr() __attribute__ ((pure));
|
||||
void init_serial();
|
||||
void sout(char b);
|
||||
void soutsz(char *s);
|
||||
void soutsn(char *s, uint8_t n);
|
||||
void soutsz(const char *s);
|
||||
void soutsn(const char *s, uint8_t n);
|
||||
char sin();
|
||||
void sinsn(char *s, uint8_t n);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "task.h"
|
||||
#include "panic.h"
|
||||
#include "task.h"
|
||||
|
||||
segment_id new_segment(bool is_code, uint32_t length, uint32_t *location_out) {
|
||||
panic("TODO: make new segment");
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef TASK_H
|
||||
#define TASK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t segment_id;
|
||||
typedef uint8_t task_handle;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include <stdint.h>
|
||||
#include "panic.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "drive.h"
|
||||
|
||||
void memcpy(void *to, void *from, uint32_t n) {
|
||||
uint32_t *tp = to, *fp = from;
|
||||
void memcpy(void *to, const void *from, uint32_t n) {
|
||||
uint32_t *tp = to;
|
||||
const uint32_t *fp = from;
|
||||
while (n >= 4) {
|
||||
*(tp++) = *(fp++);
|
||||
n -= 4;
|
||||
|
@ -14,7 +14,7 @@ void memcpy(void *to, void *from, uint32_t n) {
|
|||
*(tpp++) = *(fpp++);
|
||||
}
|
||||
|
||||
void fmcpy(void *to, struct drive *d, drive_file_id_t f, uint32_t from, uint32_t n) {
|
||||
void fmcpy(void *to, const struct drive *d, drive_file_id_t f, uint32_t from, uint32_t n) {
|
||||
uint8_t buf[512];
|
||||
d->load_sector(d, f, from >> 9, buf);
|
||||
uint16_t from_low = from & 511;
|
||||
|
|
|
@ -10,8 +10,8 @@ static inline void outb(uint16_t port, uint8_t value) {
|
|||
: : "a"(value), "Nd"(port));
|
||||
}
|
||||
static inline uint8_t inb(uint16_t port) {
|
||||
uint8_t value;
|
||||
asm volatile (
|
||||
volatile uint8_t value;
|
||||
asm (
|
||||
"inb %1, %0"
|
||||
: "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
|
@ -22,8 +22,8 @@ static inline void outw(uint16_t port, uint16_t value) {
|
|||
: : "a"(value), "Nd"(port));
|
||||
}
|
||||
static inline uint16_t inw(uint16_t port) {
|
||||
uint16_t value;
|
||||
asm volatile (
|
||||
volatile uint16_t value;
|
||||
asm (
|
||||
"inw %1, %0"
|
||||
: "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
|
@ -34,15 +34,15 @@ static inline void outd(uint16_t port, uint32_t value) {
|
|||
: : "a"(value), "Nd"(port));
|
||||
}
|
||||
static inline uint32_t ind(uint16_t port) {
|
||||
uint32_t value;
|
||||
asm volatile (
|
||||
volatile uint32_t value;
|
||||
asm (
|
||||
"inl %1, %0"
|
||||
: "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
void memcpy(void *to, void *from, uint32_t n);
|
||||
void fmcpy(void *to, struct drive *d, drive_file_id_t f, uint32_t from, uint32_t n);
|
||||
void memcpy(void *to, const void *from, uint32_t n);
|
||||
void fmcpy(void *to, const struct drive *d, drive_file_id_t f, uint32_t from, uint32_t n);
|
||||
|
||||
void u32_dec(uint32_t n, char *b);
|
||||
void u16_dec(uint16_t n, char *b);
|
||||
|
|
|
@ -1,5 +1,21 @@
|
|||
#include "vesa.h"
|
||||
|
||||
uint16_t screen_width;
|
||||
uint16_t screen_height;
|
||||
uint8_t bpp;
|
||||
|
||||
void *frame_buffer;
|
||||
|
||||
void put_pixel(uint16_t x, uint16_t y, color c) {
|
||||
|
||||
}
|
||||
|
||||
void screen_fill(color c) {
|
||||
|
||||
}
|
||||
|
||||
void init_vesa() {
|
||||
|
||||
// for (void *v = 0; v < 0x65536; ++v) {
|
||||
// if (*(uint32_t *)v == 'P' + 'M' * 256 + 'I' * 65536 + 'D' * 16777216)
|
||||
// }
|
||||
}
|
|
@ -1,23 +1,16 @@
|
|||
#ifndef VESA_H
|
||||
#define VESA_H
|
||||
|
||||
struct video_mode {
|
||||
//TODO
|
||||
};
|
||||
#include <stdint.h>
|
||||
|
||||
#define VESA_INFO \
|
||||
((struct { \
|
||||
uint32_t sig; \
|
||||
uint16_t vbe_ver; \
|
||||
char *oem; \
|
||||
uint32_t capabilities; \
|
||||
struct video_mode *modes; \
|
||||
uint16_t vram_size_high; \
|
||||
uint16_t soft_ver; \
|
||||
char *vendor; \
|
||||
char *pname; \
|
||||
char *prev; \
|
||||
} *)0x4200)
|
||||
extern uint16_t screen_width;
|
||||
extern uint16_t screen_height;
|
||||
extern uint8_t bpp;
|
||||
|
||||
typedef uint32_t color;
|
||||
|
||||
void put_pixel(uint16_t x, uint16_t y, color c);
|
||||
void screen_fill(color c);
|
||||
|
||||
void init_vesa();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define VGA_COM_MIRROR
|
||||
|
||||
|
@ -50,12 +50,12 @@ void vga_printch(char ch) {
|
|||
vga_scroll();
|
||||
}
|
||||
|
||||
void vga_printsz(char *sz) {
|
||||
void vga_printsz(const char *sz) {
|
||||
while (*sz)
|
||||
vga_printch(*(sz++));
|
||||
}
|
||||
|
||||
void vga_printsn(char *sn, uint8_t n) {
|
||||
void vga_printsn(const char *sn, uint8_t n) {
|
||||
while (n--)
|
||||
vga_printch(*(sn++));
|
||||
}
|
|
@ -7,7 +7,7 @@ void vga_set_color(uint8_t color);
|
|||
void vga_blank();
|
||||
void vga_scroll();
|
||||
void vga_printch(char ch);
|
||||
void vga_printsz(char *sz);
|
||||
void vga_printsn(char *sn, uint8_t n);
|
||||
void vga_printsz(const char *sz);
|
||||
void vga_printsn(const char *sn, uint8_t n);
|
||||
|
||||
#endif
|
Reference in a new issue