reading files from cd!!

This commit is contained in:
Benji Dial 2025-12-27 18:39:05 -05:00
parent fc79e09922
commit 645cc90b4d
13 changed files with 711 additions and 164 deletions

View file

@ -2,7 +2,6 @@ timeout: 0
quiet: yes
/Calcite
protocol: limine
path: boot():/calcite/kernel.elf
module_path: boot():/calcite/initfs.tar
module_cmdline: initfs
protocol: limine
path: boot():/calcite/kernel.elf
cmdline: root-drive=pata2,root-fs=iso9660

View file

@ -69,7 +69,8 @@ for dir in src/user-libs/*; do
build_all $dir user_cc user_lib_ld lib$lib_name.o
done
apps=""
cp_apps=""
app_deps=""
for dir in src/user-apps/*; do
@ -81,21 +82,18 @@ for dir in src/user-apps/*; do
app_name=$(echo $dir | sed -e 's/^src\/user-apps\///')
build_all $dir user_cc user_app_ld $app_name.elf $lib_paths
build_dir=$(echo $dir | sed -e 's/^src/build/')
apps="$apps $build_dir/$app_name.elf"
build_elf=$(echo $dir | sed -e 's/^src/build/')/$app_name.elf
disk_dir=build/disk/calcite/apps/$app_name
disk_elf=$disk_dir/$app_name.elf
cp_apps=$(echo "$cp_apps" \
"mkdir -p $disk_dir &&" \
"cp $build_elf $disk_elf &&")
app_deps="$app_deps $build_elf"
done
echo "rule initfs" >> build.ninja
echo " command =" \
"rm -rf build/initfs &&" \
"mkdir -p build/initfs/apps &&" \
"cp build/user-apps/hello/hello.elf build/initfs/apps/ &&" \
"cd build/initfs &&" \
"tar cf ../initfs.tar *" >> build.ninja
echo "build build/initfs.tar: initfs $apps" >> build.ninja
echo "rule disk" >> build.ninja
echo " command =" \
"rm -rf build/disk &&" \
@ -107,10 +105,10 @@ echo " command =" \
"cp dependencies/limine/BOOTX64.EFI build/disk/EFI/BOOT/ &&" \
"mkdir build/disk/calcite &&" \
"cp build/kernel/kernel.elf build/disk/calcite/ &&" \
"cp build/initfs.tar build/disk/calcite/ &&" \
$cp_apps \
"xorriso -as mkisofs -R -r -J -b limine/limine-bios-cd.bin -no-emul-boot -boot-load-size 4 -boot-info-table -hfsplus -apm-block-size 2048 --efi-boot limine/limine-uefi-cd.bin -efi-boot-part --efi-boot-image --protective-msdos-label build/disk -o build/disk.iso &&" \
"dependencies/limine/limine bios-install build/disk.iso" >> build.ninja
echo "build build/disk.iso: disk | build/kernel/kernel.elf build/initfs.tar" >> build.ninja
echo "build build/disk.iso: disk | build/kernel/kernel.elf $app_deps" >> build.ninja
echo "default build/disk.iso" >> build.ninja

View file

@ -46,3 +46,10 @@ struct drive_info *add_drive() {
return to_return;
}
const struct drive_info *look_up_drive(const char *name) {
for (int i = 0; i < drive_list_count; ++i)
if (strequ(drive_list[i].name, name))
return &drive_list[i];
return 0;
}

View file

@ -20,7 +20,8 @@
#include <stdint.h>
enum drive_access_result {
DAR_SUCCESS
DAR_SUCCESS,
DAR_HARDWARE_ERROR
};
struct drive_info {
@ -32,7 +33,7 @@ struct drive_info {
//start and count are both in blocks
enum drive_access_result (*read_blocks)(
const void *driver_info, void *buffer, uint64_t start, uint64_t count);
const struct drive_info *info, void *buffer, uint64_t start, uint64_t count);
};
@ -40,4 +41,6 @@ struct drive_info {
//the returned pointer might be invalidated by future calls.
struct drive_info *add_drive();
//returned pointer might be invalidated by future calls to add_drive.
//returns 0 if there is no drive with that name.
const struct drive_info *look_up_drive(const char *name);

View file

@ -22,12 +22,13 @@
#include "syscalls.h"
#include "process.h"
#include "utility.h"
#include "initfs.h"
#include "drives.h"
#include "paging.h"
#include "panic.h"
#include "heap.h"
#include "pata.h"
#include "ps2.h"
#include "fs.h"
#include <limine.h>
@ -57,8 +58,8 @@ static volatile struct limine_memmap_request memmap_request = {
.response = 0
};
static volatile struct limine_module_request module_request = {
.id = LIMINE_MODULE_REQUEST,
static volatile struct limine_executable_cmdline_request cmdline_request = {
.id = LIMINE_EXECUTABLE_CMDLINE_REQUEST,
.revision = 0,
.response = 0
};
@ -84,8 +85,8 @@ static void map_kernel_region(
physical_start + i, (uint8_t *)virtual_start + i, writable, executable);
}
static uint8_t *initfs_start;
static uint64_t initfs_length;
#define MAX_CMDLINE_LENGTH 1000
static char cmdline_copy[MAX_CMDLINE_LENGTH + 1];
[[noreturn]] static void with_kernel_page_tables();
@ -95,9 +96,7 @@ static uint64_t initfs_length;
if (fb_request.response == 0 || hhdm_request.response == 0 ||
ka_request.response == 0 || memmap_request.response == 0 ||
module_request.response == 0 ||
fb_request.response->framebuffer_count == 0 ||
module_request.response->module_count == 0)
fb_request.response->framebuffer_count == 0)
die();
struct limine_framebuffer *fb = fb_request.response->framebuffers[0];
@ -107,19 +106,6 @@ static uint64_t initfs_length;
fb->blue_mask_shift != 0 || fb->blue_mask_size != 8)
die();
//find the initfs, and die if we don't have one.
struct limine_file *initfs = 0;
struct limine_module_response *response = module_request.response;
for (uint64_t i = 0; i < response->module_count; ++i)
if (strequ(response->modules[i]->cmdline, "initfs")) {
initfs = response->modules[i];
break;
}
if (!initfs)
die();
//set up page tables. we will mark the regions with bootloader structures as
//usable, so we need to be careful not to allocate any physical pages until
//after we are done using bootloader structures. we map the kernel into our
@ -162,17 +148,17 @@ static uint64_t initfs_length;
fb_height = fb->height;
fb_pitch = fb->pitch;
//remap initfs module and store information.
//make a copy of the kernel cmdline
uint64_t initfs_physical_start =
(uint64_t)initfs->address - hhdm_request.response->offset;
const char *original_cmdline = cmdline_request.response->cmdline;
int cmdline_length = 0;
while (original_cmdline[cmdline_length] != 0)
++cmdline_length;
initfs_length = initfs->size;
uint64_t initfs_length_rounded = ((initfs_length - 1) / 4096 + 1) * 4096;
if (cmdline_length > MAX_CMDLINE_LENGTH)
die();
initfs_start = find_free_kernel_region(initfs_length_rounded);
map_kernel_region(
initfs_physical_start, initfs_start, initfs_length_rounded, 0, 0);
memcpy(cmdline_copy, original_cmdline, cmdline_length + 1);
//switch to kernel page tables!
@ -180,11 +166,78 @@ static uint64_t initfs_length;
}
struct cmdline_pair {
const char *key;
const char *value;
};
static const struct cmdline_pair *cmdline_pairs;
static int cmdline_pair_count;
//returns the corresponding value if the key exists, otherwise returns 0.
static const char *cmdline_look_up(const char *key) {
for (int i = 0; i < cmdline_pair_count; ++i)
if (strequ(cmdline_pairs[i].key, key))
return cmdline_pairs[i].value;
return 0;
}
[[noreturn]] static void with_kernel_page_tables() {
//set initfs
//store cmdline as key-value pairs
set_initfs(initfs_start, initfs_length);
if (cmdline_copy[0] == 0)
cmdline_pair_count = 0;
else {
int comma_count = 0;
for (int i = 0; cmdline_copy[i] != 0; ++i)
if (cmdline_copy[i] == ',')
++comma_count;
cmdline_pair_count = comma_count + 1;
struct cmdline_pair *pairs = heap_alloc(cmdline_pair_count * sizeof(struct cmdline_pair));
int key_start = 0;
for (int i = 0; i < cmdline_pair_count; ++i) {
int key_end = key_start;
while (1) {
if (cmdline_copy[key_end] == '=')
break;
if (cmdline_copy[key_end] == ',' || cmdline_copy[key_end] == 0)
die();
++key_end;
}
int value_start = key_end + 1;
int value_end = value_start;
while (1) {
if (cmdline_copy[value_end] == ',' || cmdline_copy[value_end] == 0)
break;
if (cmdline_copy[value_end] == '=')
die();
++value_end;
}
char *key = heap_alloc(key_end - key_start + 1);
memcpy(key, &cmdline_copy[key_start], key_end - key_start);
key[key_end - key_start] = 0;
pairs[i].key = key;
char *value = heap_alloc(value_end - value_start + 1);
memcpy(value, &cmdline_copy[value_start], value_end - value_start);
value[value_end - value_start] = 0;
pairs[i].value = value;
key_start = value_end + 1;
}
cmdline_pairs = pairs;
}
//set up interrupts
@ -203,18 +256,40 @@ static uint64_t initfs_length;
probe_pata_drives();
//load root file system
const char *root_drive_name = cmdline_look_up("root-drive");
if (!root_drive_name)
panic("root drive mising from cmdline")
const struct drive_info *root_drive = look_up_drive(root_drive_name);
if (!root_drive)
panic("could not find root drive")
const char *root_fs_type = cmdline_look_up("root-fs");
if (!root_fs_type)
panic("root fs missing from cmdline")
struct fs_info root_fs;
if (create_fs_info(root_drive, &root_fs, root_fs_type) != FAR_SUCCESS)
panic("could not create root file system info")
//load hello and start it
init_scheduler();
const uint8_t *hello_start;
uint64_t hello_length;
look_up_initfs_file("apps/hello.elf", &hello_start, &hello_length);
void *hello_node;
if ((*root_fs.look_up_file)(
&root_fs, &hello_node,
"calcite/apps/hello/hello.elf") != FAR_SUCCESS)
panic("could not look up hello.elf")
struct process *hello = heap_alloc(sizeof(struct process));
uint64_t hello_entry;
create_process(hello);
load_elf(hello, &hello_entry, hello_start, hello_length);
if (load_elf(hello, &hello_entry, &root_fs, hello_node) != 1)
panic("could not load hello.elf")
if ((*root_fs.free_node)(&root_fs, hello_node) != FAR_SUCCESS)
panic("could not free hello.elf node")
struct thread *hello_thread = heap_alloc(sizeof(struct thread));
create_thread(hello, hello_thread);

30
src/kernel/fs.c Normal file
View file

@ -0,0 +1,30 @@
/* Calcite, src/kernel/fs.c
* Copyright 2025 Benji Dial
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "iso9660.h"
#include "utility.h"
#include "fs.h"
enum fs_access_result create_fs_info(
const struct drive_info *drive, struct fs_info *fs_out, const char *fs_type) {
if (strequ(fs_type, "iso9660"))
return create_iso9660_info(drive, fs_out);
return FAR_UNKNOWN_FS_TYPE;
}

58
src/kernel/fs.h Normal file
View file

@ -0,0 +1,58 @@
/* Calcite, src/kernel/fs.h
* Copyright 2025 Benji Dial
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "drives.h"
#include <stdint.h>
enum fs_access_result {
FAR_SUCCESS,
FAR_HARDWARE_ERROR,
FAR_FORMAT_ERROR,
FAR_UNKNOWN_FS_TYPE,
FAR_NOT_FOUND
};
struct fs_stat {
uint64_t bytes;
};
struct fs_info {
const struct drive_info *drive;
const void *driver_info;
enum fs_access_result (*free_node)(
const struct fs_info *info, void *node);
enum fs_access_result (*look_up_file)(
const struct fs_info *info, void **node_out, const char *path);
enum fs_access_result (*stat_file)(
const struct fs_info *info, void *node, struct fs_stat *stat_out);
//start is in bytes
enum fs_access_result (*read_file)(
const struct fs_info *info, void *node,
void *buffer, uint64_t start, uint64_t bytes);
};
enum fs_access_result create_fs_info(
const struct drive_info *drive, struct fs_info *fs_out, const char *fs_type);

View file

@ -1,74 +0,0 @@
/* Calcite, src/kernel/initfs.c
* Copyright 2025 Benji Dial
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "initfs.h"
static const uint8_t *initfs_start;
static uint64_t initfs_length;
void set_initfs(const uint8_t *start, uint64_t length) {
initfs_start = start;
initfs_length = length;
}
static uint64_t decode_octal(const char *from) {
uint64_t value = 0;
while (*from != '\0') {
value = value * 8 + *from - '0';
++from;
}
return value;
}
void look_up_initfs_file(
const char *path, const uint8_t **start_out, uint64_t *length_out) {
int path_len = 0;
while (path[path_len] != '\0')
++path_len;
uint64_t offset = 0;
while (1) {
if (offset + 512 > initfs_length) {
*start_out = 0;
return;
}
uint64_t length =
decode_octal((const char *)(initfs_start + offset + 0x7c));
int found_it = 1;
for (int i = 0; i < path_len; ++i)
if (initfs_start[offset + i] != path[i]) {
found_it = 0;
break;
}
if (found_it) {
*start_out = initfs_start + offset + 512;
*length_out = length;
return;
}
offset += 512 + ((length - 1) / 512 + 1) * 512;
}
}

375
src/kernel/iso9660.c Normal file
View file

@ -0,0 +1,375 @@
/* Calcite, src/kernel/iso9660.c
* Copyright 2025 Benji Dial
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "iso9660.h"
#include "utility.h"
#include "drives.h"
#include "panic.h"
#include "heap.h"
#include "fs.h"
//relevant sources:
// https://www.ecma-international.org/wp-content/uploads/ECMA-119_2nd_edition_december_1987.pdf
//case-insensitive equality
static bool ciequ(char c1, char c2) {
if (c1 >= 'a' && c1 <= 'z')
c1 &= 0xdf;
if (c2 >= 'a' && c2 <= 'z')
c2 &= 0xdf;
return c1 == c2;
}
struct iso9660_driver_info {
const void *path_table;
//in bytes
int path_table_length;
};
static const struct iso9660_driver_info *get_driver_info(const struct fs_info *info) {
return (const struct iso9660_driver_info *)info->driver_info;
}
struct iso9660_node {
uint32_t first_block;
//in bytes
uint32_t length;
};
static enum fs_access_result free_node_iso9660(const struct fs_info *info, void *node) {
(void)info;
heap_dealloc(node, sizeof(struct iso9660_node));
return FAR_SUCCESS;
}
static uint8_t directory_buffer[2048];
static enum fs_access_result look_up_in_directory(
const struct fs_info *info, void **node_out,
const char *path, int path_length,
uint32_t first_directory_block) {
if (first_directory_block >= info->drive->block_count)
return FAR_FORMAT_ERROR;
switch ((*info->drive->read_blocks)(info->drive, directory_buffer, first_directory_block, 1)) {
case DAR_SUCCESS:
break;
case DAR_HARDWARE_ERROR:
return FAR_HARDWARE_ERROR;
default:
assert(0);
}
int length = *(uint32_t *)&directory_buffer[10];
if (length % 2048 != 0)
return FAR_FORMAT_ERROR;
uint32_t loaded_block = first_directory_block;
int offset_in_block = 0;
int total_offset = 0;
while (1) {
if (total_offset == length)
return FAR_NOT_FOUND;
if (offset_in_block == 2048 || directory_buffer[offset_in_block] == 0) {
++loaded_block;
if (loaded_block >= info->drive->block_count)
return FAR_FORMAT_ERROR;
switch ((*info->drive->read_blocks)(info->drive, directory_buffer, loaded_block, 1)) {
case DAR_SUCCESS:
break;
case DAR_HARDWARE_ERROR:
return FAR_HARDWARE_ERROR;
default:
assert(0);
}
total_offset = total_offset - offset_in_block + 2048;
offset_in_block = 0;
if (total_offset == length)
return FAR_NOT_FOUND;
}
int dr_length = directory_buffer[offset_in_block];
if (offset_in_block + dr_length > 2048)
return FAR_FORMAT_ERROR;
int id_length = directory_buffer[offset_in_block + 32];
if (33 + id_length > dr_length)
return FAR_FORMAT_ERROR;
for (int i = 0; i < id_length; ++i)
if (directory_buffer[offset_in_block + 33 + i] == ';') {
id_length = i;
break;
}
if (id_length != path_length)
goto next_entry;
for (int i = 0; i < id_length; ++i)
if (!ciequ(directory_buffer[offset_in_block + 33 + i], path[i]))
goto next_entry;
struct iso9660_node *node = heap_alloc(sizeof(struct iso9660_node));
node->first_block = *(uint32_t *)&directory_buffer[offset_in_block + 2];
node->length = *(uint32_t *)&directory_buffer[offset_in_block + 10];
*node_out = node;
return FAR_SUCCESS;
next_entry:
offset_in_block += dr_length;
total_offset += dr_length;
}
}
static enum fs_access_result look_up_recursive(
const struct fs_info *info, void **node_out,
const char *path, int parent_path_table_offset,
int parent_directory_number) {
//FIXME: this function is pretty unoptimized
recurse:
int slash_location = 0;
int path_length;
while (1) {
if (path[slash_location] == '/')
break;
if (path[slash_location] == 0) {
path_length = slash_location;
slash_location = -1;
break;
}
++slash_location;
}
const struct iso9660_driver_info *driver_info = get_driver_info(info);
int on_offset = parent_path_table_offset;
int on_number = parent_directory_number;
if (slash_location == -1) {
if (on_offset + 6 > driver_info->path_table_length)
return FAR_NOT_FOUND;
uint32_t first_directory_block = *(uint32_t *)(driver_info->path_table + on_offset + 2);
return look_up_in_directory(info, node_out, path, path_length, first_directory_block);
}
while (1) {
if (on_offset >= driver_info->path_table_length)
return FAR_NOT_FOUND;
int old_id_length = *(uint8_t *)(driver_info->path_table + on_offset);
on_offset += 8 + old_id_length + (old_id_length & 0x01);
++on_number;
if (on_offset + 8 > driver_info->path_table_length)
return FAR_NOT_FOUND;
int this_entry_parent = *(uint16_t *)(driver_info->path_table + on_offset + 6);
if (this_entry_parent != parent_directory_number)
continue;
int this_entry_id_length = *(uint8_t *)(driver_info->path_table + on_offset);
if (this_entry_id_length != slash_location)
continue;
if (on_offset + 8 + this_entry_id_length > driver_info->path_table_length)
return FAR_NOT_FOUND;
char *this_entry_id = (char *)(driver_info->path_table + on_offset + 8);
for (int i = 0; i < slash_location; ++i)
if (!ciequ(this_entry_id[i], path[i]))
goto next_entry;
path = path + slash_location + 1;
parent_path_table_offset = on_offset;
parent_directory_number = on_number;
goto recurse;
next_entry:
;
}
}
static enum fs_access_result look_up_file_iso9660(
const struct fs_info *info, void **node_out, const char *path) {
return look_up_recursive(info, node_out, path, 0, 1);
}
static enum fs_access_result stat_file_iso9660(
const struct fs_info *info, void *node, struct fs_stat *stat_out) {
(void)info;
struct iso9660_node *iso9660_node = (struct iso9660_node *)node;
stat_out->bytes = iso9660_node->length;
return FAR_SUCCESS;
}
static uint8_t read_buffer[2048];
static enum fs_access_result read_file_iso9660(
const struct fs_info *info, void *node, void *buffer, uint64_t start, uint64_t bytes) {
struct iso9660_node *iso9660_node = (struct iso9660_node *)node;
if (iso9660_node->first_block + (start + bytes - 1) / 2048 + 1 > info->drive->block_count)
return FAR_FORMAT_ERROR;
if (start % 2048 != 0) {
switch ((*info->drive->read_blocks)(
info->drive, read_buffer, iso9660_node->first_block + start / 2048, 1)) {
case DAR_SUCCESS:
break;
case DAR_HARDWARE_ERROR:
return FAR_HARDWARE_ERROR;
default:
assert(0);
}
if (start + bytes <= ((start - 1) / 2048 + 1) * 2048) {
memcpy(buffer, read_buffer + (start % 2048), bytes);
return FAR_SUCCESS;
}
int to_copy = 2048 - (start % 2048);
memcpy(buffer, read_buffer + (start % 2048), to_copy);
buffer += to_copy;
start += to_copy;
bytes -= to_copy;
}
switch ((*info->drive->read_blocks)(
info->drive, buffer,
iso9660_node->first_block + start / 2048,
bytes / 2048)) {
case DAR_SUCCESS:
break;
case DAR_HARDWARE_ERROR:
return FAR_HARDWARE_ERROR;
default:
assert(0);
}
buffer += (bytes / 2048) * 2048;
start += (bytes / 2048) * 2048;
bytes %= 2048;
if (bytes > 0) {
switch ((*info->drive->read_blocks)(
info->drive, read_buffer, iso9660_node->first_block + start / 2048, 1)) {
case DAR_SUCCESS:
break;
case DAR_HARDWARE_ERROR:
return FAR_HARDWARE_ERROR;
default:
assert(0);
}
memcpy(buffer, read_buffer + (start % 2048), bytes);
}
return FAR_SUCCESS;
}
static uint8_t vd_buffer[2048];
enum fs_access_result create_iso9660_info(const struct drive_info *drive, struct fs_info *fs_out) {
if (drive->block_size != 2048)
panic("TODO")
int descriptor_number = 0;
while (1) {
if ((uint64_t)(16 + descriptor_number) >= drive->block_count)
return FAR_FORMAT_ERROR;
switch ((*drive->read_blocks)(drive, vd_buffer, 16 + descriptor_number, 1)) {
case DAR_SUCCESS:
break;
case DAR_HARDWARE_ERROR:
return FAR_HARDWARE_ERROR;
default:
assert(0)
}
if (vd_buffer[0] == 0xff)
return FAR_FORMAT_ERROR;
if (vd_buffer[0] == 0x01)
break;
++descriptor_number;
}
uint32_t path_table_length = *(uint32_t *)&vd_buffer[132];
uint32_t path_table_start = *(uint32_t *)&vd_buffer[140];
uint64_t path_table_length_rounded_up = ((path_table_length - 1) / 2048 + 1) * 2048;
void *path_table = heap_alloc(path_table_length_rounded_up);
if (path_table_start >= drive->block_count)
return FAR_FORMAT_ERROR;
switch ((*drive->read_blocks)(
drive, path_table, path_table_start,
path_table_length_rounded_up / 2048)) {
case DAR_SUCCESS:
break;
case DAR_HARDWARE_ERROR:
heap_dealloc(path_table, path_table_length_rounded_up);
return FAR_HARDWARE_ERROR;
default:
assert(0);
}
heap_dealloc(
path_table + path_table_length,
path_table_length_rounded_up - path_table_length);
struct iso9660_driver_info *driver_info = heap_alloc(sizeof(struct iso9660_driver_info));
driver_info->path_table = path_table;
driver_info->path_table_length = path_table_length;
fs_out->drive = drive;
fs_out->driver_info = driver_info;
fs_out->free_node = &free_node_iso9660;
fs_out->look_up_file = &look_up_file_iso9660;
fs_out->stat_file = &stat_file_iso9660;
fs_out->read_file = &read_file_iso9660;
return FAR_SUCCESS;
}

View file

@ -1,4 +1,4 @@
/* Calcite, src/kernel/initfs.h
/* Calcite, src/kernel/iso9660.h
* Copyright 2025 Benji Dial
*
* This program is free software: you can redistribute it and/or modify
@ -17,10 +17,6 @@
#pragma once
#include <stdint.h>
#include "fs.h"
void set_initfs(const uint8_t *start, uint64_t length);
//if the file does not exist, *start_out is set to a null pointer.
void look_up_initfs_file(
const char *path, const uint8_t **start_out, uint64_t *length_out);
enum fs_access_result create_iso9660_info(const struct drive_info *drive, struct fs_info *fs_out);

View file

@ -21,6 +21,11 @@
#include "heap.h"
#include "pata.h"
//some relevant sources:
// ANSI: AT Attachment 8 - ATA/ATAPI Command Set
// Seagate: SCSI Commands Reference Manual
// OSDev Wiki: ATAPI, PCI IDE Controller
//in any function that takes a "controller", 0 means the primary controller
//and 1 means the secondary controller. in any function that takes a "drive",
//bit 1 is the controller, and bit 0 is bit 4 of the device register.
@ -116,6 +121,51 @@ static enum pata_result patapi_read_capacity(
}
static enum pata_result patapi_read(
uint8_t drive, uint16_t block_size, uint32_t start_block, uint32_t block_count, void *buffer) {
uint8_t controller = drive >> 1;
pata_set_device(controller, (drive & 0x01) << 4);
pata_set_features(controller, 0);
pata_set_lba(controller, (uint32_t)block_size << 8);
pata_set_command(controller, 0xa0);
enum pata_result result = wait_pio(controller);
if (result != PR_SUCCESS)
return result;
uint8_t cmd[12] = {
0xa8, 0,
start_block >> 24,
(start_block >> 16) & 0xff,
(start_block >> 8) & 0xff,
start_block & 0xff,
block_count >> 24,
(block_count >> 16) & 0xff,
(block_count >> 8) & 0xff,
block_count & 0xff,
0, 0 };
pata_write_data(controller, (uint16_t *)cmd, 8);
for (uint32_t i = 0; i < block_count; ++i) {
result = wait_pio(controller);
if (result != PR_SUCCESS)
return result;
uint32_t actual_response_size = pata_read_lba(controller) >> 8;
if (actual_response_size != block_size)
panic("TODO")
pata_read_data(controller, (uint16_t *)(buffer + i * block_size), block_size / 2);
}
return PR_SUCCESS;
}
static uint16_t ipd_buffer[256];
struct pata_driver_info {
@ -123,10 +173,19 @@ struct pata_driver_info {
};
static enum drive_access_result read_blocks_patapi(
const struct pata_driver_info *driver_info,
const struct drive_info *drive_info,
void *buffer, uint64_t start, uint64_t count) {
panic("TODO");
if (count >= (1ULL << 32) || start >= (1ULL << 32))
panic("TODO")
uint8_t drive = ((const struct pata_driver_info *)drive_info->driver_info)->drive;
return
patapi_read(
drive, drive_info->block_size,
start, count, buffer) == PR_SUCCESS
? DAR_SUCCESS : DAR_HARDWARE_ERROR;
}
@ -155,7 +214,7 @@ static void probe_pata_drive(uint8_t drive) {
driver_info->drive = drive;
di->driver_info = driver_info;
di->read_blocks = (void *)&read_blocks_patapi;
di->read_blocks = &read_blocks_patapi;
}

View file

@ -16,6 +16,7 @@
*/
#include "framebuffer.h"
#include "fs.h"
#include "scheduler.h"
#include "process.h"
#include "utility.h"
@ -191,26 +192,38 @@ no_mem:
}
void load_elf(
int load_elf(
struct process *process, uint64_t *entry_out,
const void *elf_start, uint64_t elf_length) {
const struct fs_info *fs_info, void *fs_node) {
if (elf_length < 58)
panic("malformed elf")
struct fs_stat stat;
if ((*fs_info->stat_file)(fs_info, fs_node, &stat) != FAR_SUCCESS)
return 0;
*entry_out = *(uint64_t *)(elf_start + 24);
if (stat.bytes < 58)
return 0;
uint64_t phead_start = *(uint64_t *)(elf_start + 32);
uint16_t phead_entry_size = *(uint16_t *)(elf_start + 54);
uint16_t phead_entry_count = *(uint16_t *)(elf_start + 56);
uint8_t head_part[34];
if ((*fs_info->read_file)(fs_info, fs_node, head_part, 24, 34) != FAR_SUCCESS)
return 0;
if (elf_length < phead_start + phead_entry_count * phead_entry_size)
*entry_out = *(uint64_t *)head_part;
uint64_t phead_start = *(uint64_t *)(head_part + 8);
uint16_t phead_entry_size = *(uint16_t *)(head_part + 30);
uint16_t phead_entry_count = *(uint16_t *)(head_part + 32);
if (stat.bytes < phead_start + phead_entry_count * phead_entry_size)
panic("malformed elf")
for (uint16_t i = 0; i < phead_entry_count; ++i) {
uint64_t *entry =
(uint64_t *)(elf_start + phead_start + i * phead_entry_size);
uint64_t entry[6];
if ((*fs_info->read_file)(
fs_info, fs_node, entry,
phead_start + i * phead_entry_size,
6 * sizeof(uint64_t)) != FAR_SUCCESS)
return 0;
if ((entry[0] & 0xffffffff) != 1)
continue;
@ -223,13 +236,13 @@ void load_elf(
uint64_t file_length = entry[4];
uint64_t virtual_length = ((entry[5] - 1) / 4096 + 1) * 4096;
if (elf_length < file_start + file_length)
panic("malformed elf")
if (stat.bytes < file_start + file_length)
return 0;
if (file_length > virtual_length)
panic("malformed elf")
return 0;
if ((uint64_t)virtual_start % 4096 != 0 || virtual_length % 4096 != 0)
panic("unaligned elf")
return 0;
for (uint64_t i = 0; i < virtual_length; i += 4096) {
@ -240,12 +253,20 @@ void load_elf(
void *kvma = find_free_kernel_region(4096);
map_in_kernel_page_table(pma, kvma, 1, 0);
if (i + 4096 <= file_length)
memcpy(kvma, elf_start + file_start + i, 4096);
if (i + 4096 <= file_length) {
if ((*fs_info->read_file)(
fs_info, fs_node, kvma,
file_start + i, 4096) != FAR_SUCCESS)
return 0;
}
else if (i >= file_length)
memzero(kvma, 4096);
else {
memcpy(kvma, elf_start + file_start + i, file_length & 0xfff);
if ((*fs_info->read_file)(
fs_info, fs_node, kvma,
file_start + i,
file_length & 0xfff) != FAR_SUCCESS)
return 0;
memzero(kvma + (file_length & 0xfff), 4096 - (file_length & 0xfff));
}
@ -255,6 +276,8 @@ void load_elf(
}
return 1;
}
void destroy_process(struct process *process) {

View file

@ -17,7 +17,7 @@
#pragma once
#include <stdint.h>
#include "fs.h"
struct process {
@ -64,12 +64,10 @@ void unmap_page_for_process(
void *find_free_process_region(
struct process *process, uint64_t page_count);
//loaded sections are copied to new pages. once storage drivers are written,
//this should probably just take a file handle so it can load and parse the
//header and then load sections directly into user pages.
void load_elf(
//returns 0 on failure, 1 on success.
int load_elf(
struct process *process, uint64_t *entry_out,
const void *elf_start, uint64_t elf_length);
const struct fs_info *fs_info, void *fs_node);
void destroy_process(struct process *process);