A update
This commit is contained in:
1
drivers/ahci.c
Normal file
1
drivers/ahci.c
Normal file
@ -0,0 +1 @@
|
||||
#include <drivers/ahci.h>
|
29
drivers/ehci.c
Normal file
29
drivers/ehci.c
Normal file
@ -0,0 +1,29 @@
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#define EHCI_BASE_ADDR 0xF0000000 // Example, your base address will be different
|
||||
|
||||
// EHCI Register Offsets (from EHCI spec)
|
||||
#define EHCI_CAPLENGTH_OFFSET 0x00
|
||||
#define EHCI_HCIVERSION_OFFSET 0x02
|
||||
#define EHCI_CONTROL_OFFSET 0x04
|
||||
#define EHCI_STATUS_OFFSET 0x08
|
||||
#define EHCI_COMMAND_OFFSET 0x10
|
||||
|
||||
// Registers access
|
||||
uint32_t read_ehci_register(uint32_t* base, uint32_t offset) {
|
||||
return *(volatile uint32_t*)(base + offset);
|
||||
}
|
||||
|
||||
void write_ehci_register(uint32_t* base, uint32_t offset, uint32_t value) {
|
||||
*(volatile uint32_t*)(base + offset) = value;
|
||||
}
|
||||
|
||||
// Initialize EHCI controller
|
||||
void initialize_ehci(uint32_t* base) {
|
||||
uint32_t control = read_ehci_register(base, EHCI_CONTROL_OFFSET);
|
||||
control |= (1 << 1); // Enable controller
|
||||
write_ehci_register(base, EHCI_CONTROL_OFFSET, control);
|
||||
|
||||
// Set up frame list pointer and other initialization steps as per EHCI specs
|
||||
}
|
220
drivers/fs/duckfs.c
Normal file
220
drivers/fs/duckfs.c
Normal file
@ -0,0 +1,220 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <drivers/ide.h>
|
||||
|
||||
#include <fs/duckfs.h>
|
||||
|
||||
|
||||
static uint16_t duckfs_initialized = 0;
|
||||
|
||||
static duckfs_file_header_t duckfs_root;
|
||||
|
||||
const char* duckfs_versions[18] = { DFS_VERSION_0, DFS_VERSION_1, DFS_VERSION_2, DFS_VERSION_3, DFS_VERSION_4 };
|
||||
|
||||
int32_t duckfs_init(int16_t drive)
|
||||
{
|
||||
char duckfs_header_block[512];
|
||||
if (ide_read48(drive, 0xA, 1, duckfs_header_block) != 0)
|
||||
{
|
||||
printf("[ DEBUG ] Disk read error on drive #%i\n", drive);
|
||||
return -1;
|
||||
}
|
||||
|
||||
duckfs_superblock_t* superblock = (duckfs_superblock_t*)duckfs_header_block;
|
||||
/*
|
||||
if (superblock->duckfs_magic != (int32_t) DFS_MAGIC)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
bool compliant = false;
|
||||
for (int16_t i = 0; i < 5; ++i)
|
||||
{
|
||||
if (strcmp(superblock->duckfs_version_string, duckfs_versions[i]) == 0)
|
||||
{
|
||||
compliant = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (compliant == false)
|
||||
{
|
||||
return -3;
|
||||
}*/
|
||||
|
||||
memset(&duckfs_root, 0, sizeof(duckfs_root));
|
||||
|
||||
strncpy(duckfs_root.filename, "/", DFS_MAX_FILENAME_LEN);
|
||||
strncpy(duckfs_root.permissions, "RW", sizeof(duckfs_root.permissions));
|
||||
|
||||
duckfs_root.num_sectors = -1;
|
||||
duckfs_root.type = DFS_FILE_DIRECTORY;
|
||||
duckfs_root.next = NULL;
|
||||
duckfs_root.prev = NULL;
|
||||
duckfs_root.contents = NULL;
|
||||
duckfs_root.lba_start = 0;
|
||||
duckfs_root.lba_end = 0;
|
||||
|
||||
duckfs_root.contents = malloc(sizeof(duckfs_file_header_t) * DFS_MAX_FILES);
|
||||
if (!duckfs_root.contents) {
|
||||
printf("Memory allocation failed for duckfs_root.contents\n");
|
||||
return -4;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < DFS_MAX_FILES; i++) {
|
||||
duckfs_root.contents[i].type = DFS_FILE_UNUSED;
|
||||
}
|
||||
|
||||
|
||||
duckfs_initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void duckfs_format(int16_t drive)
|
||||
{
|
||||
/* Nothing to do, DuckFS does not require formatting. */
|
||||
}
|
||||
|
||||
int32_t duckfs_makedir(const char* filename, const char* perms)
|
||||
{
|
||||
duckfs_file_header_t* dir = malloc(sizeof(duckfs_file_header_t));
|
||||
if (!dir)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlen(perms) < 3)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
char p[3] = { "." };
|
||||
p[0] = perms[0];
|
||||
p[1] = perms[1];
|
||||
p[2] = perms[2];
|
||||
|
||||
char filen[DFS_MAX_FILENAME_LEN + 1];
|
||||
char perma[3];
|
||||
|
||||
strcpy(filen, filename);
|
||||
|
||||
|
||||
strcpy(perma, perms);
|
||||
|
||||
strncpy(dir->filename, filen, sizeof(dir->filename) - 1);
|
||||
dir->filename[sizeof(dir->filename) - 1] = '\0';
|
||||
|
||||
strncpy(dir->permissions, p, sizeof(dir->permissions));
|
||||
|
||||
dir->type = DFS_FILE_DIRECTORY;
|
||||
dir->contents = malloc(sizeof(duckfs_file_header_t) * DFS_MAX_FILES);
|
||||
|
||||
if (!dir->contents) {
|
||||
free(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < DFS_MAX_FILES; i++) {
|
||||
dir->contents[i].type = DFS_FILE_UNUSED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void duckfs_free_directory(duckfs_file_header_t* dir)
|
||||
{
|
||||
if (!dir || dir->type != DFS_FILE_DIRECTORY || !dir->contents)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < DFS_MAX_FILES; i++) {
|
||||
duckfs_file_header_t* entry = &dir->contents[i];
|
||||
|
||||
if (entry->type == DFS_FILE_UNUSED)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry->type == DFS_FILE_DIRECTORY) {
|
||||
duckfs_free_directory(entry);
|
||||
}
|
||||
}
|
||||
|
||||
free(dir->contents);
|
||||
dir->contents = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool duckfs_add_entry(duckfs_file_header_t* dir, duckfs_file_header_t* entry)
|
||||
{
|
||||
if (dir->type != DFS_FILE_DIRECTORY || !dir->contents)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < DFS_MAX_FILES; i++) {
|
||||
if (dir->contents[i].type == DFS_FILE_UNUSED) {
|
||||
dir->contents[i] = *entry;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; /* Directory full */
|
||||
}
|
||||
|
||||
duckfs_file_header_t duckfs_create_entry(const char* name, const char* perms, const char* type)
|
||||
{
|
||||
duckfs_file_header_t entry = {0};
|
||||
|
||||
strncpy(entry.filename, name, DFS_MAX_FILENAME_LEN);
|
||||
strncpy(entry.permissions, perms, sizeof(entry.permissions) - 1);
|
||||
|
||||
int16_t itype = DFS_FILE_UNUSED;
|
||||
|
||||
if (strcmp(type, "text") == 0)
|
||||
{
|
||||
itype = DFS_FILE_TEXT;
|
||||
}
|
||||
else if (strcmp(type, "bin") == 0)
|
||||
{
|
||||
itype = DFS_FILE_BINARY;
|
||||
}
|
||||
else if (strcmp(type, "dir") == 0)
|
||||
{
|
||||
itype = DFS_FILE_BINARY;
|
||||
}
|
||||
else
|
||||
{
|
||||
duckfs_file_header_t vvvv = { .type = DFS_FILE_ERROR };
|
||||
return vvvv;
|
||||
}
|
||||
|
||||
entry.num_sectors = 0;
|
||||
entry.type = itype;
|
||||
entry.next = NULL;
|
||||
entry.prev = NULL;
|
||||
entry.contents = NULL;
|
||||
entry.lba_start = 0;
|
||||
entry.lba_end = 0;
|
||||
|
||||
if (itype == DFS_FILE_DIRECTORY)
|
||||
{
|
||||
entry.contents = malloc(sizeof(duckfs_file_header_t) * DFS_MAX_FILES);
|
||||
if (entry.contents)
|
||||
{
|
||||
for (int i = 0; i < DFS_MAX_FILES; i++)
|
||||
{
|
||||
entry.contents[i].type = DFS_FILE_UNUSED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
duckfs_file_header_t duckfs_makefile(const char* filename, const char* perms, duckfs_file_header_t parent)
|
||||
{
|
||||
|
||||
}
|
428
drivers/fs/fat32.c
Normal file
428
drivers/fs/fat32.c
Normal file
@ -0,0 +1,428 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <drivers/ide.h>
|
||||
|
||||
#include <fs/fat32.h>
|
||||
|
||||
struct __attribute__((packed)) fat32_bpb {
|
||||
uint8_t jmp[3];
|
||||
uint8_t oem[8];
|
||||
uint16_t bytes_per_sector;
|
||||
uint8_t sectors_per_cluster;
|
||||
uint16_t reserved_sector_count;
|
||||
uint8_t num_fats;
|
||||
uint16_t root_entry_count;
|
||||
uint16_t total_sectors_16;
|
||||
uint8_t media;
|
||||
uint16_t fat_size_16;
|
||||
uint16_t sectors_per_track;
|
||||
uint16_t num_heads;
|
||||
uint32_t hidden_sectors;
|
||||
uint32_t total_sectors_32;
|
||||
uint32_t fat_size_32;
|
||||
uint16_t ext_flags;
|
||||
uint16_t fs_version;
|
||||
uint32_t root_cluster;
|
||||
};
|
||||
|
||||
static int32_t fat32_drive = 0;
|
||||
static struct fat32_bpb bpb;
|
||||
static uint32_t fat_start_lba;
|
||||
static uint32_t cluster_heap_lba;
|
||||
static uint32_t current_directory_cluster;
|
||||
|
||||
static uint8_t sector[512];
|
||||
|
||||
int32_t fat32_init(int32_t drive)
|
||||
{
|
||||
fat32_drive = drive;
|
||||
int err = ide_read48(drive, 0, 1, sector);
|
||||
if (err != 0) {
|
||||
printf("ide_read48 failed on sector 0 (err = %d)\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&bpb, sector, sizeof(bpb));
|
||||
|
||||
|
||||
fat_start_lba = bpb.reserved_sector_count;
|
||||
cluster_heap_lba = fat_start_lba + bpb.num_fats * bpb.fat_size_32;
|
||||
current_directory_cluster = bpb.root_cluster;
|
||||
printf("Bytes per sector: %u\n", bpb.bytes_per_sector);
|
||||
printf("Sectors per cluster: %u\n", bpb.sectors_per_cluster);
|
||||
printf("Reserved sectors: %u\n", bpb.reserved_sector_count);
|
||||
printf("Number of FATs: %u\n", bpb.num_fats);
|
||||
printf("FAT size (32): %u\n", bpb.fat_size_32);
|
||||
printf("Root cluster: %u\n", bpb.root_cluster);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t cluster_to_lba(uint32_t cluster)
|
||||
{
|
||||
return cluster_heap_lba + (cluster - 2) * bpb.sectors_per_cluster;
|
||||
}
|
||||
|
||||
static void format_83_name(const char *input, char out[11]) {
|
||||
memset(out, ' ', 11);
|
||||
int i = 0, j = 0;
|
||||
|
||||
// Copy name part (up to 8 chars)
|
||||
while (input[i] && input[i] != '.' && j < 8) {
|
||||
out[j++] = toupper((unsigned char)input[i++]);
|
||||
}
|
||||
|
||||
// Skip dot
|
||||
if (input[i] == '.') i++;
|
||||
|
||||
// Copy extension (up to 3 chars)
|
||||
int k = 8;
|
||||
while (input[i] && j < 11) {
|
||||
out[k++] = toupper((unsigned char)input[i++]);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t find_free_cluster() {
|
||||
// Read FAT sectors one by one
|
||||
for (uint32_t cluster = 2; cluster < bpb.total_sectors_32; cluster++) {
|
||||
uint32_t fat_sector = fat_start_lba + (cluster * 4) / 512;
|
||||
uint32_t fat_offset = (cluster * 4) % 512;
|
||||
|
||||
if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0)
|
||||
return 0;
|
||||
|
||||
uint32_t entry = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||
if (entry == 0x00000000) {
|
||||
return cluster;
|
||||
}
|
||||
}
|
||||
return 0; // No free cluster found
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32_t fat32_list_root(void)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(current_directory_cluster);
|
||||
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 512; i += 32)
|
||||
{
|
||||
char *entry = (char *)§or[i];
|
||||
if ((uint8_t)entry[0] == 0x00)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ((uint8_t)entry[0] == 0xE5)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char name[12];
|
||||
memcpy(name, entry, 11);
|
||||
name[11] = 0;
|
||||
for (int j = 0; j < 11; j++)
|
||||
{
|
||||
if (name[j] == ' ')
|
||||
{
|
||||
name[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t attr = entry[11];
|
||||
if (attr & FAT32_ATTR_DIRECTORY)
|
||||
{
|
||||
printf("<DIR> %s\n", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" %s\n", name);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t fat32_read_file(const char *name, uint8_t *buffer, uint32_t max_len)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(current_directory_cluster);
|
||||
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < 512; i += 32)
|
||||
{
|
||||
char *entry = (char *)§or[i];
|
||||
if ((uint8_t)entry[0] == 0x00)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ((uint8_t)entry[0] == 0xE5)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char entry_name[12];
|
||||
memcpy(entry_name, entry, 11);
|
||||
entry_name[11] = 0;
|
||||
for (int32_t j = 0; j < 11; j++)
|
||||
{
|
||||
if (entry_name[j] == ' ')
|
||||
{
|
||||
entry_name[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(entry_name, name, 11) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||
uint32_t size = *(uint32_t *)(entry + 28);
|
||||
uint32_t bytes_read = 0;
|
||||
|
||||
while (cluster < 0x0FFFFFF8 && bytes_read < max_len && bytes_read < size)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(cluster);
|
||||
if (ide_read48(fat32_drive, lba, bpb.sectors_per_cluster, buffer + bytes_read) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
bytes_read += bpb.sectors_per_cluster * 512;
|
||||
|
||||
uint32_t fat_sector = cluster * 4 / 512;
|
||||
uint32_t fat_offset = cluster * 4 % 512;
|
||||
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(current_directory_cluster);
|
||||
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < 512; i += 32)
|
||||
{
|
||||
char *entry = (char *)§or[i];
|
||||
if ((uint8_t)entry[0] == 0x00) break;
|
||||
if ((uint8_t)entry[0] == 0xE5) continue;
|
||||
|
||||
char entry_name[12];
|
||||
memcpy(entry_name, entry, 11);
|
||||
entry_name[11] = 0;
|
||||
for (int j = 0; j < 11; j++)
|
||||
{
|
||||
if (entry_name[j] == ' ')
|
||||
{
|
||||
entry_name[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(entry_name, name, 11) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||
uint32_t bytes_written = 0;
|
||||
|
||||
while (cluster < 0x0FFFFFF8 && bytes_written < len)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(cluster);
|
||||
if (ide_write48(fat32_drive, lba, bpb.sectors_per_cluster, buffer + bytes_written) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
bytes_written += bpb.sectors_per_cluster * 512;
|
||||
|
||||
if (bytes_written < len)
|
||||
{
|
||||
uint32_t fat_sector = cluster * 4 / 512;
|
||||
uint32_t fat_offset = cluster * 4 % 512;
|
||||
|
||||
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t next_cluster = find_free_cluster();
|
||||
if (next_cluster == 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
*(uint32_t *)(sector + fat_offset) = next_cluster & 0x0FFFFFFF;
|
||||
|
||||
if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
cluster = next_cluster;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t fat_sector = cluster * 4 / 512;
|
||||
uint32_t fat_offset = cluster * 4 % 512;
|
||||
|
||||
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*(uint32_t *)(sector + fat_offset) = 0x0FFFFFFF;
|
||||
|
||||
if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*(uint32_t *)(entry + 28) = len;
|
||||
if (ide_write48(fat32_drive, lba, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return bytes_written;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
int32_t fat32_create_file(const char *name) {
|
||||
uint32_t root_lba = cluster_to_lba(bpb.root_cluster);
|
||||
|
||||
// Read root directory cluster sector (assuming 1 sector here for simplicity)
|
||||
if (ide_read48(fat32_drive, root_lba, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
char formatted_name[11];
|
||||
format_83_name(name, formatted_name);
|
||||
|
||||
for (int32_t i = 0; i < 512; i += 32) {
|
||||
uint8_t *entry = §or[i];
|
||||
if (entry[0] == 0x00 || entry[0] == 0xE5) {
|
||||
// Found free directory entry, clear it
|
||||
memset(entry, 0, 32);
|
||||
|
||||
// Copy formatted filename
|
||||
memcpy(entry, formatted_name, 11);
|
||||
|
||||
// Set attributes to Archive (normal file)
|
||||
entry[11] = 0x20;
|
||||
|
||||
// Allocate first cluster for the file
|
||||
uint32_t free_cluster = find_free_cluster();
|
||||
if (free_cluster == 0) {
|
||||
return -2; // No free cluster
|
||||
}
|
||||
|
||||
// Mark cluster as end-of-chain in FAT
|
||||
uint32_t fat_sector = fat_start_lba + (free_cluster * 4) / 512;
|
||||
uint32_t fat_offset = (free_cluster * 4) % 512;
|
||||
if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
*(uint32_t *)(sector + fat_offset) = 0x0FFFFFFF; // end of cluster chain
|
||||
if (ide_write48(fat32_drive, fat_sector, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
// Set first cluster in directory entry (split high and low 16 bits)
|
||||
entry[20] = (free_cluster >> 16) & 0xFF;
|
||||
entry[21] = (free_cluster >> 24) & 0xFF;
|
||||
entry[26] = free_cluster & 0xFF;
|
||||
entry[27] = (free_cluster >> 8) & 0xFF;
|
||||
|
||||
// Set file size = 0
|
||||
entry[28] = 0;
|
||||
entry[29] = 0;
|
||||
entry[30] = 0;
|
||||
entry[31] = 0;
|
||||
|
||||
// Write back directory sector
|
||||
if (ide_write48(fat32_drive, root_lba, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
return 0; // Success
|
||||
}
|
||||
}
|
||||
|
||||
return -3; // No free directory entry found
|
||||
}
|
||||
|
||||
int32_t fat32_create_directory(const char *name) {
|
||||
uint32_t lba = cluster_to_lba(current_directory_cluster);
|
||||
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
for (int32_t i = 0; i < 512; i += 32) {
|
||||
char *entry = (char *)§or[i];
|
||||
if ((uint8_t)entry[0] == 0x00 || (uint8_t)entry[0] == 0xE5) {
|
||||
memset(entry, 0, 32);
|
||||
memcpy(entry, name, strlen(name) > 11 ? 11 : strlen(name));
|
||||
entry[11] = FAT32_ATTR_DIRECTORY;
|
||||
|
||||
uint32_t cluster = 6;
|
||||
*(uint16_t *)(entry + 26) = cluster & 0xFFFF;
|
||||
*(uint16_t *)(entry + 20) = (cluster >> 16) & 0xFFFF;
|
||||
*(uint32_t *)(entry + 28) = 0;
|
||||
|
||||
if (ide_write48(fat32_drive, lba, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
int32_t fat32_change_directory(const char *name) {
|
||||
uint32_t lba = cluster_to_lba(current_directory_cluster);
|
||||
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
|
||||
return -1;
|
||||
|
||||
for (int32_t i = 0; i < 512; i += 32) {
|
||||
char *entry = (char *)§or[i];
|
||||
if ((uint8_t)entry[0] == 0x00) break;
|
||||
if ((uint8_t)entry[0] == 0xE5) continue;
|
||||
|
||||
char entry_name[12];
|
||||
memcpy(entry_name, entry, 11);
|
||||
entry_name[11] = 0;
|
||||
for (int32_t j = 0; j < 11; j++)
|
||||
if (entry_name[j] == ' ') entry_name[j] = 0;
|
||||
|
||||
if (strncmp(entry_name, name, 11) != 0) continue;
|
||||
|
||||
if (!(entry[11] & FAT32_ATTR_DIRECTORY))
|
||||
return -2;
|
||||
|
||||
current_directory_cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||
return 0;
|
||||
}
|
||||
return -3;
|
||||
}
|
||||
|
34
drivers/gdt.c
Normal file
34
drivers/gdt.c
Normal file
@ -0,0 +1,34 @@
|
||||
#include <gdt.h>
|
||||
|
||||
|
||||
#define GDT_ENTRIES 3
|
||||
|
||||
struct gdt_entry gdt[GDT_ENTRIES];
|
||||
struct gdt_ptr gp;
|
||||
|
||||
extern void gdt_flush(uint32_t);
|
||||
|
||||
void gdt_install()
|
||||
{
|
||||
gp.limit = (sizeof(struct gdt_entry) * GDT_ENTRIES) - 1;
|
||||
gp.base = (uint32_t)&gdt;
|
||||
|
||||
gdt_set_entry(0, 0, 0, 0, 0); /* Null segment */
|
||||
gdt_set_entry(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* Code segment */
|
||||
gdt_set_entry(2, 0, 0xFFFFFFFF, 0x92, 0xCF); /* Data segment */
|
||||
|
||||
gdt_flush((uint32_t)&gp);
|
||||
}
|
||||
|
||||
void gdt_set_entry(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
|
||||
{
|
||||
gdt[num].base_low = (base & 0xFFFF);
|
||||
gdt[num].base_middle = (base >> 16) & 0xFF;
|
||||
gdt[num].base_high = (base >> 24) & 0xFF;
|
||||
|
||||
gdt[num].limit_low = (limit & 0xFFFF);
|
||||
gdt[num].granularity = (limit >> 16) & 0x0F;
|
||||
|
||||
gdt[num].granularity |= (gran & 0xF0);
|
||||
gdt[num].access = access;
|
||||
}
|
173
drivers/ide.c
Normal file
173
drivers/ide.c
Normal file
@ -0,0 +1,173 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <port_io.h>
|
||||
|
||||
#include <drivers/ide.h>
|
||||
|
||||
|
||||
static void io_delay() {
|
||||
for (int32_t i = 0; i < 1000; i++) {
|
||||
outb(0x80, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int32_t ide_wait(uint16_t io, int32_t check_drq) {
|
||||
for (int32_t i = 0; i < 5000; i++) {
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (!(status & ATA_SR_BSY)) {
|
||||
if (!check_drq || (status & ATA_SR_DRQ))
|
||||
return 0;
|
||||
}
|
||||
io_delay(1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int32_t ide_wait_ready(uint16_t io) {
|
||||
for (int32_t i = 0; i < 100000; i++) {
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (!(status & ATA_SR_BSY)) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32_t ide_identify(uint8_t drive, uint16_t* buffer) {
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
uint8_t slave_bit = (drive & 1) << 4;
|
||||
|
||||
ide_wait(io, 0);
|
||||
outb(io + ATA_REG_HDDEVSEL, 0xA0 | slave_bit);
|
||||
outb(io + ATA_REG_SECCOUNT0, 0);
|
||||
outb(io + ATA_REG_LBA0, 0);
|
||||
outb(io + ATA_REG_LBA1, 0);
|
||||
outb(io + ATA_REG_LBA2, 0);
|
||||
outb(io + ATA_REG_COMMAND, 0xEC); // IDENTIFY DEVICE
|
||||
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (status == 0) return -1; // No device
|
||||
|
||||
if (ide_wait(io, 1)) return -2;
|
||||
|
||||
insw(io + ATA_REG_DATA, buffer, 256); // Read 512 bytes
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ide_initialize(void) {
|
||||
outb(ATA_PRIMARY_CTRL, 0x02); // Disable IRQs
|
||||
|
||||
uint16_t identify_buf[256];
|
||||
if (ide_identify(0, identify_buf) == 0) {
|
||||
char model[41];
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
model[i * 2 + 0] = identify_buf[27 + i] >> 8;
|
||||
model[i * 2 + 1] = identify_buf[27 + i] & 0xFF;
|
||||
}
|
||||
model[40] = 0;
|
||||
printf("Disk model: %s\n", model);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer) {
|
||||
if (sector_count == 0) return -1;
|
||||
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
uint8_t slave_bit = (drive & 1) << 4;
|
||||
|
||||
ide_wait(io, 0); // Wait for BSY to clear
|
||||
|
||||
outb(io + ATA_REG_HDDEVSEL, 0xE0 | slave_bit); // Select drive
|
||||
|
||||
// High bytes (use 0xC2 - 0xC6 offsets if you define them separately)
|
||||
outb(io + 6, (sector_count >> 8) & 0xFF); // Sector Count High
|
||||
outb(io + 7, (lba >> 40) & 0xFF); // LBA[47:40]
|
||||
outb(io + 8, (lba >> 32) & 0xFF); // LBA[39:32]
|
||||
outb(io + 9, (lba >> 24) & 0xFF); // LBA[31:24]
|
||||
|
||||
// Low bytes
|
||||
outb(io + 2, sector_count & 0xFF); // Sector Count Low
|
||||
outb(io + 3, (lba >> 0) & 0xFF); // LBA[7:0]
|
||||
outb(io + 4, (lba >> 8) & 0xFF); // LBA[15:8]
|
||||
outb(io + 5, (lba >> 16) & 0xFF); // LBA[23:16]
|
||||
|
||||
|
||||
outb(io + ATA_REG_COMMAND, ATA_CMD_READ_SECTORS_EXT);
|
||||
|
||||
uint16_t* ptr = (uint16_t*)buffer;
|
||||
for (int i = 0; i < sector_count; i++) {
|
||||
if (ide_wait(io, 1)) {
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
printf("IDE DRQ wait failed (read), status = 0x%02X\n", status);
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (status & ATA_SR_ERR) return -3;
|
||||
|
||||
insw(io + ATA_REG_DATA, ptr, 256);
|
||||
ptr += 256;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer) {
|
||||
if (sector_count == 0) return -1;
|
||||
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
uint8_t slave_bit = (drive & 1) << 4;
|
||||
|
||||
ide_wait(io, 0); // Wait for BSY to clear
|
||||
|
||||
outb(io + ATA_REG_HDDEVSEL, 0xE0 | slave_bit); // Select drive
|
||||
|
||||
// Send high bytes of sector count and LBA first
|
||||
outb(io + ATA_REG_SECCOUNT0, 0); // Sector count high byte
|
||||
outb(io + ATA_REG_LBA0, (lba >> 40) & 0xFF); // LBA[47:40]
|
||||
outb(io + ATA_REG_LBA1, (lba >> 32) & 0xFF); // LBA[39:32]
|
||||
outb(io + ATA_REG_LBA2, (lba >> 24) & 0xFF); // LBA[31:24]
|
||||
|
||||
// Send low bytes
|
||||
outb(io + ATA_REG_SECCOUNT0, sector_count); // Sector count low byte
|
||||
outb(io + ATA_REG_LBA0, (lba >> 0) & 0xFF); // LBA[7:0]
|
||||
outb(io + ATA_REG_LBA1, (lba >> 8) & 0xFF); // LBA[15:8]
|
||||
outb(io + ATA_REG_LBA2, (lba >> 16) & 0xFF); // LBA[23:16]
|
||||
|
||||
// Send write command
|
||||
outb(io + ATA_REG_COMMAND, ATA_CMD_WRITE_SECTORS_EXT); // 0x34
|
||||
|
||||
const uint16_t* ptr = (const uint16_t*)buffer;
|
||||
for (int i = 0; i < sector_count; i++) {
|
||||
if (ide_wait(io, 1)) {
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
printf("IDE DRQ wait failed (write), status = 0x%02X\n", status);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Check for drive error
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (status & ATA_SR_ERR) return -3;
|
||||
|
||||
outsw(io + ATA_REG_DATA, ptr, 256); // 256 words = 512 bytes
|
||||
inb(io + ATA_REG_STATUS); /* Dummy read */
|
||||
ptr += 256;
|
||||
}
|
||||
|
||||
// Wait for BSY=0 before issuing FLUSH CACHE
|
||||
if (ide_wait_ready(io)) return -5;
|
||||
outb(io + ATA_REG_COMMAND, 0xE7); // FLUSH CACHE
|
||||
if (ide_wait(io, 0)) {
|
||||
printf("FLUSH CACHE timeout, status=0x%02X\n", inb(io + ATA_REG_STATUS));
|
||||
return -4;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
131
drivers/idt.c
Normal file
131
drivers/idt.c
Normal file
@ -0,0 +1,131 @@
|
||||
#include <string.h>
|
||||
#include <port_io.h>
|
||||
|
||||
#include <idt.h>
|
||||
|
||||
#define IDT_ENTRIES 256
|
||||
|
||||
struct idt_entry idt[IDT_ENTRIES];
|
||||
struct idt_ptr idtp;
|
||||
|
||||
extern void idt_load(uint32_t);
|
||||
|
||||
void idt_install(void)
|
||||
{
|
||||
idtp.limit = sizeof(struct idt_entry) * IDT_ENTRIES - 1;
|
||||
idtp.base = (uint32_t)&idt;
|
||||
|
||||
memset(&idt, 0, sizeof(struct idt_entry) * IDT_ENTRIES);
|
||||
|
||||
/* Set entries for IRQs/ISRs here using `idt_set_entry(...)` */
|
||||
/* Example: idt_set_entry(0, (uint32_t)isr0, 0x08, 0x8E); */
|
||||
|
||||
idt_load((uint32_t)&idtp);
|
||||
}
|
||||
|
||||
void pic_remap(void)
|
||||
{
|
||||
outb(0x20, 0x11); /* Start init for master PIC */
|
||||
outb(0xA0, 0x11); /* Start init for slave PIC */
|
||||
outb(0x21, 0x20); /* Master PIC vector offset */
|
||||
outb(0xA1, 0x28); /* Slave PIC vector offset */
|
||||
outb(0x21, 0x04); /* Tell Master PIC about Slave PIC at IRQ2 */
|
||||
outb(0xA1, 0x02); /* Tell Slave PIC its cascade identity */
|
||||
outb(0x21, 0x01); /* 8086/88 mode */
|
||||
outb(0xA1, 0x01);
|
||||
outb(0x21, 0x0); /* Unmask master */
|
||||
outb(0xA1, 0x0); /* Unmask slave */
|
||||
}
|
||||
|
||||
void idt_set_entry(int num, uint32_t base, uint16_t sel, uint8_t flags)
|
||||
{
|
||||
idt[num].base_low = base & 0xFFFF;
|
||||
idt[num].base_high = (base >> 16) & 0xFFFF;
|
||||
|
||||
idt[num].sel = sel;
|
||||
idt[num].always0 = 0;
|
||||
idt[num].flags = flags;
|
||||
}
|
||||
|
||||
extern void IRQ0_handler(void);
|
||||
extern void isr0(void);
|
||||
extern void isr1(void);
|
||||
extern void isr2(void);
|
||||
extern void isr3(void);
|
||||
extern void isr4(void);
|
||||
extern void isr5(void);
|
||||
extern void isr6(void);
|
||||
extern void isr7(void);
|
||||
extern void isr8(void);
|
||||
extern void isr9(void);
|
||||
extern void isr10(void);
|
||||
extern void isr11(void);
|
||||
extern void isr12(void);
|
||||
extern void isr13(void);
|
||||
extern void isr14(void);
|
||||
extern void isr15(void);
|
||||
extern void isr16(void);
|
||||
extern void isr17(void);
|
||||
extern void isr18(void);
|
||||
extern void isr19(void);
|
||||
extern void isr20(void);
|
||||
extern void isr21(void);
|
||||
extern void isr22(void);
|
||||
extern void isr23(void);
|
||||
extern void isr24(void);
|
||||
extern void isr25(void);
|
||||
extern void isr26(void);
|
||||
extern void isr27(void);
|
||||
extern void isr28(void);
|
||||
extern void isr29(void);
|
||||
extern void isr30(void);
|
||||
extern void isr31(void);
|
||||
|
||||
extern void isr33(void);
|
||||
|
||||
extern void isr128(void);
|
||||
|
||||
|
||||
void idt_install_isrs(void)
|
||||
{
|
||||
idt_set_entry(0, (uint32_t)isr0, 0x08, 0x8E);
|
||||
idt_set_entry(1, (uint32_t)isr1, 0x08, 0x8E);
|
||||
idt_set_entry(2, (uint32_t)isr2, 0x08, 0x8E);
|
||||
idt_set_entry(3, (uint32_t)isr3, 0x08, 0x8E);
|
||||
idt_set_entry(4, (uint32_t)isr4, 0x08, 0x8E);
|
||||
idt_set_entry(5, (uint32_t)isr5, 0x08, 0x8E);
|
||||
idt_set_entry(6, (uint32_t)isr6, 0x08, 0x8E);
|
||||
idt_set_entry(7, (uint32_t)isr7, 0x08, 0x8E);
|
||||
idt_set_entry(8, (uint32_t)isr8, 0x08, 0x8E);
|
||||
idt_set_entry(9, (uint32_t)isr9, 0x08, 0x8E);
|
||||
idt_set_entry(10, (uint32_t)isr10, 0x08, 0x8E);
|
||||
idt_set_entry(11, (uint32_t)isr11, 0x08, 0x8E);
|
||||
idt_set_entry(12, (uint32_t)isr12, 0x08, 0x8E);
|
||||
idt_set_entry(13, (uint32_t)isr13, 0x08, 0x8E);
|
||||
idt_set_entry(14, (uint32_t)isr14, 0x08, 0x8E);
|
||||
idt_set_entry(15, (uint32_t)isr15, 0x08, 0x8E);
|
||||
idt_set_entry(16, (uint32_t)isr16, 0x08, 0x8E);
|
||||
idt_set_entry(17, (uint32_t)isr17, 0x08, 0x8E);
|
||||
idt_set_entry(18, (uint32_t)isr18, 0x08, 0x8E);
|
||||
idt_set_entry(19, (uint32_t)isr19, 0x08, 0x8E);
|
||||
idt_set_entry(20, (uint32_t)isr20, 0x08, 0x8E);
|
||||
idt_set_entry(21, (uint32_t)isr21, 0x08, 0x8E);
|
||||
idt_set_entry(22, (uint32_t)isr22, 0x08, 0x8E);
|
||||
idt_set_entry(23, (uint32_t)isr23, 0x08, 0x8E);
|
||||
idt_set_entry(24, (uint32_t)isr24, 0x08, 0x8E);
|
||||
idt_set_entry(25, (uint32_t)isr25, 0x08, 0x8E);
|
||||
idt_set_entry(26, (uint32_t)isr26, 0x08, 0x8E);
|
||||
idt_set_entry(27, (uint32_t)isr27, 0x08, 0x8E);
|
||||
idt_set_entry(28, (uint32_t)isr28, 0x08, 0x8E);
|
||||
idt_set_entry(29, (uint32_t)isr29, 0x08, 0x8E);
|
||||
idt_set_entry(30, (uint32_t)isr30, 0x08, 0x8E);
|
||||
idt_set_entry(31, (uint32_t)isr31, 0x08, 0x8E);
|
||||
|
||||
idt_set_entry(33, (uint32_t)isr33, 0x08, 0x8E);
|
||||
|
||||
}
|
||||
|
||||
void idt_install_syscall(void)
|
||||
{
|
||||
idt_set_entry(128, (uint32_t)isr128, 0x08, 0xEE);
|
||||
}
|
42
drivers/isr.c
Normal file
42
drivers/isr.c
Normal file
@ -0,0 +1,42 @@
|
||||
#include <port_io.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <isr.h>
|
||||
|
||||
|
||||
void (*irq_handlers[256])(isr_stack_t *r) = { 0 };
|
||||
|
||||
void register_interrupt_handler(uint8_t n, void (*handler)(isr_stack_t *))
|
||||
{
|
||||
irq_handlers[n] = handler;
|
||||
}
|
||||
|
||||
void isr_handler(isr_stack_t *r)
|
||||
{
|
||||
if (irq_handlers[r->int_no]) {
|
||||
irq_handlers[r->int_no](r);
|
||||
} else {
|
||||
printf("Unhandled interrupt: %d\n", r->int_no);
|
||||
}
|
||||
|
||||
|
||||
/* Send EOI to PIC */
|
||||
if (r->int_no >= 40)
|
||||
{
|
||||
outb(0xA0, 0x20);
|
||||
}
|
||||
if (r->int_no >= 32)
|
||||
{
|
||||
outb(0x20, 0x20);
|
||||
}
|
||||
}
|
||||
|
||||
void syscall_handler(regs_t *r)
|
||||
{
|
||||
switch (r->eax) {
|
||||
case 0: printf("Syscall: Hello world\n"); break;
|
||||
case 1: printf("Syscall: value = %d\n", r->ebx); break;
|
||||
default: printf("Unknown syscall %d\n", r->eax);
|
||||
}
|
||||
}
|
||||
|
59
drivers/pci.c
Normal file
59
drivers/pci.c
Normal file
@ -0,0 +1,59 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <drivers/pci.h>
|
||||
#include <port_io.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define PCI_CONFIG_ADDRESS 0xCF8
|
||||
#define PCI_CONFIG_DATA 0xCFC
|
||||
|
||||
uint32_t pci_config_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset)
|
||||
{
|
||||
uint32_t address = 0;
|
||||
address |= (bus << 16); // Bus number (bits 23-16)
|
||||
address |= (device << 11); // Device number (bits 15-11)
|
||||
address |= (function << 8); // Function number (bits 10-8)
|
||||
address |= (offset & 0xFC); // Register offset (bits 7-0)
|
||||
address |= (1 << 31); // Enable configuration access
|
||||
|
||||
outl(PCI_CONFIG_ADDRESS, address); // Write address to PCI config space
|
||||
return inl(PCI_CONFIG_DATA); // Read data from PCI config space
|
||||
}
|
||||
|
||||
void pci_config_write(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value)
|
||||
{
|
||||
uint32_t address = 0x80000000 | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC);
|
||||
outl(PCI_CONFIG_ADDRESS, address); // Send the address to PCI config space
|
||||
outl(PCI_CONFIG_DATA, value); // Write data to PCI config space
|
||||
}
|
||||
|
||||
void pci_enumerate()
|
||||
{
|
||||
for (uint16_t bus = 0; bus < 256; bus++) // Maximum 256 buses
|
||||
{
|
||||
for (uint8_t device = 0; device < 32; device++) // Maximum 32 devices per bus
|
||||
{
|
||||
for (uint8_t function = 0; function < 8; function++) // Maximum 8 functions per device
|
||||
{
|
||||
uint32_t vendor_id = pci_config_read(bus, device, function, 0x00);
|
||||
if (vendor_id == 0xFFFFFFFF) continue; // No device present
|
||||
|
||||
uint32_t device_id = pci_config_read(bus, device, function, 0x02);
|
||||
uint32_t class_code = pci_config_read(bus, device, function, 0x08);
|
||||
printf("Found PCI device: Vendor ID: 0x%X Device ID: 0x%X Class: 0x%X\n", vendor_id, device_id, class_code);
|
||||
|
||||
printf("0x%X", class_code);
|
||||
printf(" --- ");
|
||||
printf("0x%X\n", (class_code >> 8));
|
||||
|
||||
|
||||
if ((class_code >> 8) == 0x0C) {
|
||||
printf("Found USB controller (Class: 0x%02X)\n", class_code);
|
||||
// Now, you can initialize and configure the USB controller.
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
0
drivers/pit.c
Normal file
0
drivers/pit.c
Normal file
98
drivers/ps2_keyboard.c
Normal file
98
drivers/ps2_keyboard.c
Normal file
@ -0,0 +1,98 @@
|
||||
#include <stdio.h>
|
||||
#include <port_io.h>
|
||||
|
||||
#include <drivers/ps2_keyboard.h>
|
||||
|
||||
|
||||
/*
|
||||
PS/2 Controller IO Ports
|
||||
|
||||
The PS/2 Controller itself uses 2 IO ports (IO ports 0x60 and 0x64). Like many IO ports, reads and writes may access different internal registers.
|
||||
|
||||
Historical note: The PC-XT PPI had used port 0x61 to reset the keyboard interrupt request signal (among other unrelated functions). Port 0x61 has no keyboard related functions on AT and PS/2 compatibles.
|
||||
IO Port Access Type Purpose
|
||||
0x60 Read/Write Data Port
|
||||
0x64 Read Status Register
|
||||
0x64 Write Command Register
|
||||
*/
|
||||
|
||||
#define PS2_DATA_PORT 0x60
|
||||
#define PS2_STATUS_PORT 0x64
|
||||
|
||||
#define KEYBOARD_IRQ 33
|
||||
|
||||
/*extern void register_interrupt_handler(int irq, void (*handler)(void));*/
|
||||
|
||||
static const char scancode_map[128] = {
|
||||
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */
|
||||
'\t', /* Tab */
|
||||
'q','w','e','r','t','y','u','i','o','p','[',']','\n', /* Enter */
|
||||
0, /* Control */
|
||||
'a','s','d','f','g','h','j','k','l',';','\'','`',
|
||||
0, /* Left shift */
|
||||
'\\','z','x','c','v','b','n','m',',','.','/',
|
||||
0, /* Right shift */
|
||||
'*',
|
||||
0, /* Alt */
|
||||
' ', /* Spacebar */
|
||||
0, /* Caps lock */
|
||||
/* The rest are function and control keys */
|
||||
};
|
||||
|
||||
static bool shift_pressed = false;
|
||||
|
||||
void keyboard_handler(isr_stack_t* regs)
|
||||
{
|
||||
(void)regs; /* Only here to dismiss the "Unused parameter" warnings */
|
||||
printd("PS/2 Keyboard handler fired!\n");
|
||||
|
||||
uint8_t scancode = inb(PS2_DATA_PORT);
|
||||
|
||||
/* Handle shift press/release */
|
||||
if (scancode == 0x2A || scancode == 0x36)
|
||||
{
|
||||
shift_pressed = true;
|
||||
return;
|
||||
}
|
||||
else if (scancode == 0xAA || scancode == 0xB6)
|
||||
{
|
||||
shift_pressed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (scancode & 0x80)
|
||||
{
|
||||
/* Key release event, ignore for now */
|
||||
}
|
||||
else
|
||||
{
|
||||
char c = scancode_map[scancode];
|
||||
if (shift_pressed && c >= 'a' && c <= 'z')
|
||||
{
|
||||
c -= 32; /* Convert to uppercase */
|
||||
}
|
||||
|
||||
if (c)
|
||||
{
|
||||
/* Do something with the keypress (e.g., print or buffer) */
|
||||
printf("Char: %c", c);
|
||||
}
|
||||
}
|
||||
|
||||
outb(0x20, 0x20); /* Acknowledge PIC */
|
||||
}
|
||||
|
||||
void test_handler(isr_stack_t* r) {
|
||||
printf("IRQ1 fired!\n");
|
||||
}
|
||||
|
||||
|
||||
void keyboard_init(void)
|
||||
{
|
||||
outb(0x21, inb(0x21) & ~0x02);
|
||||
|
||||
register_interrupt_handler(KEYBOARD_IRQ, test_handler);
|
||||
|
||||
/* Enable keyboard (controller-specific, often optional if already working) */
|
||||
//outb(0x64, 0xAE);
|
||||
}
|
177
drivers/tty.c
Normal file
177
drivers/tty.c
Normal file
@ -0,0 +1,177 @@
|
||||
#include <types.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <port_io.h>
|
||||
#include <vga/vga.h>
|
||||
#include <tty.h>
|
||||
|
||||
static size_t terminal_row;
|
||||
static size_t terminal_column;
|
||||
static uint8_t terminal_color;
|
||||
static uint16_t* terminal_buffer;
|
||||
|
||||
void terminal_initialize(void)
|
||||
{
|
||||
terminal_initializec(0x00);
|
||||
}
|
||||
|
||||
void terminal_initializec(uint8_t color)
|
||||
{
|
||||
terminal_row = 0;
|
||||
terminal_column = 0;
|
||||
|
||||
if (color == 0x00)
|
||||
{
|
||||
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
|
||||
}
|
||||
else {
|
||||
terminal_color = color;
|
||||
}
|
||||
|
||||
terminal_buffer = VGA_MEMORY;
|
||||
for (size_t y = 0; y < VGA_HEIGHT; y++)
|
||||
{
|
||||
for (size_t x = 0; x < VGA_WIDTH; x++)
|
||||
{
|
||||
const size_t index = y * VGA_WIDTH + x;
|
||||
terminal_buffer[index] = vga_entry(' ', terminal_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void terminal_setcolor(uint8_t color)
|
||||
{
|
||||
terminal_color = color;
|
||||
}
|
||||
|
||||
uint8_t terminal_getcolor(void)
|
||||
{
|
||||
return terminal_color;
|
||||
}
|
||||
|
||||
void terminal_putentryat(unsigned char c, uint8_t color, size_t x, size_t y)
|
||||
{
|
||||
const size_t index = y * VGA_WIDTH + x;
|
||||
terminal_buffer[index] = vga_entry(c, color);
|
||||
}
|
||||
|
||||
void terminal_putchar(const char c)
|
||||
{
|
||||
unsigned char uc = c;
|
||||
|
||||
if (uc == '\n')
|
||||
{
|
||||
terminal_column = 0;
|
||||
if (++terminal_row == VGA_HEIGHT)
|
||||
{
|
||||
terminal_scroll();
|
||||
terminal_row = VGA_HEIGHT - 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (uc == '\t')
|
||||
{
|
||||
terminal_column += 4;
|
||||
|
||||
if (terminal_column >= VGA_WIDTH)
|
||||
{
|
||||
terminal_putchar('\n');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
terminal_putentryat(uc, terminal_color, terminal_column, terminal_row);
|
||||
|
||||
|
||||
if (++terminal_column == VGA_WIDTH)
|
||||
{
|
||||
terminal_column = 0;
|
||||
if (++terminal_row == VGA_HEIGHT)
|
||||
{
|
||||
terminal_scroll();
|
||||
terminal_row = VGA_HEIGHT - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void terminal_write(const char* data, size_t size)
|
||||
{
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
terminal_putchar(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void terminal_writestring(const char* data)
|
||||
{
|
||||
terminal_write(data, strlen(data));
|
||||
}
|
||||
|
||||
void terminal_debug_writestring(const char* data)
|
||||
{
|
||||
terminal_writestring("[ DEBUG ] ");
|
||||
terminal_writestring(data);
|
||||
}
|
||||
|
||||
void terminal_writeline(const char* data)
|
||||
{
|
||||
terminal_column = 0;
|
||||
terminal_writestring(data);
|
||||
}
|
||||
|
||||
void terminal_writechar_r(const char ch)
|
||||
{
|
||||
unsigned char uch = ch;
|
||||
|
||||
for (size_t i = 0; i < VGA_WIDTH; i++)
|
||||
{
|
||||
terminal_putchar(uch);
|
||||
}
|
||||
}
|
||||
|
||||
void terminal_clear(void)
|
||||
{
|
||||
terminal_clearl(-1);
|
||||
}
|
||||
|
||||
void terminal_clearl(size_t num_lines)
|
||||
{
|
||||
if (num_lines == (size_t)-1)
|
||||
{
|
||||
terminal_initializec(terminal_getcolor());
|
||||
}
|
||||
else
|
||||
{
|
||||
/* XXX note to self: VGA_HEIGHT is 25, and VGA_WIDTH is 80 XXX */
|
||||
/* static size_t terminal_row; static size_t terminal_column; */
|
||||
|
||||
terminal_row = VGA_HEIGHT;
|
||||
terminal_column = 0;
|
||||
|
||||
while (terminal_row < num_lines)
|
||||
{
|
||||
terminal_writechar_r(' ');
|
||||
terminal_row -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void terminal_scroll(void)
|
||||
{
|
||||
for (size_t y = 1; y < VGA_HEIGHT; y++)
|
||||
{
|
||||
for (size_t x = 0; x < VGA_WIDTH; x++)
|
||||
{
|
||||
const size_t src_index = y * VGA_WIDTH + x;
|
||||
const size_t dst_index = (y - 1) * VGA_WIDTH + x;
|
||||
terminal_buffer[dst_index] = terminal_buffer[src_index];
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t x = 0; x < VGA_WIDTH; x++)
|
||||
{
|
||||
const size_t index = (VGA_HEIGHT - 1) * VGA_WIDTH + x;
|
||||
terminal_buffer[index] = (terminal_color << 8) | ' ';
|
||||
}
|
||||
}
|
10
drivers/vga/vga.c
Normal file
10
drivers/vga/vga.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include <stddef.h>
|
||||
#include <vga/vga.h>
|
||||
|
||||
uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) {
|
||||
return fg | bg << 4;
|
||||
}
|
||||
|
||||
uint16_t vga_entry(unsigned char uc, uint8_t color) {
|
||||
return (uint16_t) uc | (uint16_t) color << 8;
|
||||
}
|
Reference in New Issue
Block a user