reading files from cd!!
This commit is contained in:
parent
fc79e09922
commit
645cc90b4d
13 changed files with 711 additions and 164 deletions
|
|
@ -2,7 +2,6 @@ timeout: 0
|
||||||
quiet: yes
|
quiet: yes
|
||||||
|
|
||||||
/Calcite
|
/Calcite
|
||||||
protocol: limine
|
protocol: limine
|
||||||
path: boot():/calcite/kernel.elf
|
path: boot():/calcite/kernel.elf
|
||||||
module_path: boot():/calcite/initfs.tar
|
cmdline: root-drive=pata2,root-fs=iso9660
|
||||||
module_cmdline: initfs
|
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,8 @@ for dir in src/user-libs/*; do
|
||||||
build_all $dir user_cc user_lib_ld lib$lib_name.o
|
build_all $dir user_cc user_lib_ld lib$lib_name.o
|
||||||
done
|
done
|
||||||
|
|
||||||
apps=""
|
cp_apps=""
|
||||||
|
app_deps=""
|
||||||
|
|
||||||
for dir in src/user-apps/*; do
|
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\///')
|
app_name=$(echo $dir | sed -e 's/^src\/user-apps\///')
|
||||||
build_all $dir user_cc user_app_ld $app_name.elf $lib_paths
|
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
|
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 "rule disk" >> build.ninja
|
||||||
echo " command =" \
|
echo " command =" \
|
||||||
"rm -rf build/disk &&" \
|
"rm -rf build/disk &&" \
|
||||||
|
|
@ -107,10 +105,10 @@ echo " command =" \
|
||||||
"cp dependencies/limine/BOOTX64.EFI build/disk/EFI/BOOT/ &&" \
|
"cp dependencies/limine/BOOTX64.EFI build/disk/EFI/BOOT/ &&" \
|
||||||
"mkdir build/disk/calcite &&" \
|
"mkdir build/disk/calcite &&" \
|
||||||
"cp build/kernel/kernel.elf 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 &&" \
|
"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
|
"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
|
echo "default build/disk.iso" >> build.ninja
|
||||||
|
|
|
||||||
|
|
@ -46,3 +46,10 @@ struct drive_info *add_drive() {
|
||||||
return to_return;
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
enum drive_access_result {
|
enum drive_access_result {
|
||||||
DAR_SUCCESS
|
DAR_SUCCESS,
|
||||||
|
DAR_HARDWARE_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
struct drive_info {
|
struct drive_info {
|
||||||
|
|
@ -32,7 +33,7 @@ struct drive_info {
|
||||||
|
|
||||||
//start and count are both in blocks
|
//start and count are both in blocks
|
||||||
enum drive_access_result (*read_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.
|
//the returned pointer might be invalidated by future calls.
|
||||||
struct drive_info *add_drive();
|
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);
|
const struct drive_info *look_up_drive(const char *name);
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,13 @@
|
||||||
#include "syscalls.h"
|
#include "syscalls.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "initfs.h"
|
#include "drives.h"
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "pata.h"
|
#include "pata.h"
|
||||||
#include "ps2.h"
|
#include "ps2.h"
|
||||||
|
#include "fs.h"
|
||||||
|
|
||||||
#include <limine.h>
|
#include <limine.h>
|
||||||
|
|
||||||
|
|
@ -57,8 +58,8 @@ static volatile struct limine_memmap_request memmap_request = {
|
||||||
.response = 0
|
.response = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
static volatile struct limine_module_request module_request = {
|
static volatile struct limine_executable_cmdline_request cmdline_request = {
|
||||||
.id = LIMINE_MODULE_REQUEST,
|
.id = LIMINE_EXECUTABLE_CMDLINE_REQUEST,
|
||||||
.revision = 0,
|
.revision = 0,
|
||||||
.response = 0
|
.response = 0
|
||||||
};
|
};
|
||||||
|
|
@ -84,8 +85,8 @@ static void map_kernel_region(
|
||||||
physical_start + i, (uint8_t *)virtual_start + i, writable, executable);
|
physical_start + i, (uint8_t *)virtual_start + i, writable, executable);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t *initfs_start;
|
#define MAX_CMDLINE_LENGTH 1000
|
||||||
static uint64_t initfs_length;
|
static char cmdline_copy[MAX_CMDLINE_LENGTH + 1];
|
||||||
|
|
||||||
[[noreturn]] static void with_kernel_page_tables();
|
[[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 ||
|
if (fb_request.response == 0 || hhdm_request.response == 0 ||
|
||||||
ka_request.response == 0 || memmap_request.response == 0 ||
|
ka_request.response == 0 || memmap_request.response == 0 ||
|
||||||
module_request.response == 0 ||
|
fb_request.response->framebuffer_count == 0)
|
||||||
fb_request.response->framebuffer_count == 0 ||
|
|
||||||
module_request.response->module_count == 0)
|
|
||||||
die();
|
die();
|
||||||
|
|
||||||
struct limine_framebuffer *fb = fb_request.response->framebuffers[0];
|
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)
|
fb->blue_mask_shift != 0 || fb->blue_mask_size != 8)
|
||||||
die();
|
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
|
//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
|
//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
|
//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_height = fb->height;
|
||||||
fb_pitch = fb->pitch;
|
fb_pitch = fb->pitch;
|
||||||
|
|
||||||
//remap initfs module and store information.
|
//make a copy of the kernel cmdline
|
||||||
|
|
||||||
uint64_t initfs_physical_start =
|
const char *original_cmdline = cmdline_request.response->cmdline;
|
||||||
(uint64_t)initfs->address - hhdm_request.response->offset;
|
int cmdline_length = 0;
|
||||||
|
while (original_cmdline[cmdline_length] != 0)
|
||||||
|
++cmdline_length;
|
||||||
|
|
||||||
initfs_length = initfs->size;
|
if (cmdline_length > MAX_CMDLINE_LENGTH)
|
||||||
uint64_t initfs_length_rounded = ((initfs_length - 1) / 4096 + 1) * 4096;
|
die();
|
||||||
|
|
||||||
initfs_start = find_free_kernel_region(initfs_length_rounded);
|
memcpy(cmdline_copy, original_cmdline, cmdline_length + 1);
|
||||||
map_kernel_region(
|
|
||||||
initfs_physical_start, initfs_start, initfs_length_rounded, 0, 0);
|
|
||||||
|
|
||||||
//switch to kernel page tables!
|
//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() {
|
[[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
|
//set up interrupts
|
||||||
|
|
||||||
|
|
@ -203,18 +256,40 @@ static uint64_t initfs_length;
|
||||||
|
|
||||||
probe_pata_drives();
|
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
|
//load hello and start it
|
||||||
|
|
||||||
init_scheduler();
|
init_scheduler();
|
||||||
|
|
||||||
const uint8_t *hello_start;
|
void *hello_node;
|
||||||
uint64_t hello_length;
|
if ((*root_fs.look_up_file)(
|
||||||
look_up_initfs_file("apps/hello.elf", &hello_start, &hello_length);
|
&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));
|
struct process *hello = heap_alloc(sizeof(struct process));
|
||||||
uint64_t hello_entry;
|
uint64_t hello_entry;
|
||||||
create_process(hello);
|
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));
|
struct thread *hello_thread = heap_alloc(sizeof(struct thread));
|
||||||
create_thread(hello, hello_thread);
|
create_thread(hello, hello_thread);
|
||||||
|
|
|
||||||
30
src/kernel/fs.c
Normal file
30
src/kernel/fs.c
Normal 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
58
src/kernel/fs.h
Normal 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);
|
||||||
|
|
@ -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
375
src/kernel/iso9660.c
Normal 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/* Calcite, src/kernel/initfs.h
|
/* Calcite, src/kernel/iso9660.h
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -17,10 +17,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include "fs.h"
|
||||||
|
|
||||||
void set_initfs(const uint8_t *start, uint64_t length);
|
enum fs_access_result create_iso9660_info(const struct drive_info *drive, struct fs_info *fs_out);
|
||||||
|
|
||||||
//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);
|
|
||||||
|
|
@ -21,6 +21,11 @@
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "pata.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
|
//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",
|
//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.
|
//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];
|
static uint16_t ipd_buffer[256];
|
||||||
|
|
||||||
struct pata_driver_info {
|
struct pata_driver_info {
|
||||||
|
|
@ -123,10 +173,19 @@ struct pata_driver_info {
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum drive_access_result read_blocks_patapi(
|
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) {
|
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;
|
driver_info->drive = drive;
|
||||||
di->driver_info = driver_info;
|
di->driver_info = driver_info;
|
||||||
|
|
||||||
di->read_blocks = (void *)&read_blocks_patapi;
|
di->read_blocks = &read_blocks_patapi;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "framebuffer.h"
|
#include "framebuffer.h"
|
||||||
|
#include "fs.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
|
@ -191,26 +192,38 @@ no_mem:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_elf(
|
int load_elf(
|
||||||
struct process *process, uint64_t *entry_out,
|
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)
|
struct fs_stat stat;
|
||||||
panic("malformed elf")
|
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);
|
uint8_t head_part[34];
|
||||||
uint16_t phead_entry_size = *(uint16_t *)(elf_start + 54);
|
if ((*fs_info->read_file)(fs_info, fs_node, head_part, 24, 34) != FAR_SUCCESS)
|
||||||
uint16_t phead_entry_count = *(uint16_t *)(elf_start + 56);
|
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")
|
panic("malformed elf")
|
||||||
|
|
||||||
for (uint16_t i = 0; i < phead_entry_count; ++i) {
|
for (uint16_t i = 0; i < phead_entry_count; ++i) {
|
||||||
|
|
||||||
uint64_t *entry =
|
uint64_t entry[6];
|
||||||
(uint64_t *)(elf_start + phead_start + i * phead_entry_size);
|
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)
|
if ((entry[0] & 0xffffffff) != 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -223,13 +236,13 @@ void load_elf(
|
||||||
uint64_t file_length = entry[4];
|
uint64_t file_length = entry[4];
|
||||||
uint64_t virtual_length = ((entry[5] - 1) / 4096 + 1) * 4096;
|
uint64_t virtual_length = ((entry[5] - 1) / 4096 + 1) * 4096;
|
||||||
|
|
||||||
if (elf_length < file_start + file_length)
|
if (stat.bytes < file_start + file_length)
|
||||||
panic("malformed elf")
|
return 0;
|
||||||
if (file_length > virtual_length)
|
if (file_length > virtual_length)
|
||||||
panic("malformed elf")
|
return 0;
|
||||||
|
|
||||||
if ((uint64_t)virtual_start % 4096 != 0 || virtual_length % 4096 != 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) {
|
for (uint64_t i = 0; i < virtual_length; i += 4096) {
|
||||||
|
|
||||||
|
|
@ -240,12 +253,20 @@ void load_elf(
|
||||||
void *kvma = find_free_kernel_region(4096);
|
void *kvma = find_free_kernel_region(4096);
|
||||||
map_in_kernel_page_table(pma, kvma, 1, 0);
|
map_in_kernel_page_table(pma, kvma, 1, 0);
|
||||||
|
|
||||||
if (i + 4096 <= file_length)
|
if (i + 4096 <= file_length) {
|
||||||
memcpy(kvma, elf_start + file_start + i, 4096);
|
if ((*fs_info->read_file)(
|
||||||
|
fs_info, fs_node, kvma,
|
||||||
|
file_start + i, 4096) != FAR_SUCCESS)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
else if (i >= file_length)
|
else if (i >= file_length)
|
||||||
memzero(kvma, 4096);
|
memzero(kvma, 4096);
|
||||||
else {
|
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));
|
memzero(kvma + (file_length & 0xfff), 4096 - (file_length & 0xfff));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -255,6 +276,8 @@ void load_elf(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_process(struct process *process) {
|
void destroy_process(struct process *process) {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include "fs.h"
|
||||||
|
|
||||||
struct process {
|
struct process {
|
||||||
|
|
||||||
|
|
@ -64,12 +64,10 @@ void unmap_page_for_process(
|
||||||
void *find_free_process_region(
|
void *find_free_process_region(
|
||||||
struct process *process, uint64_t page_count);
|
struct process *process, uint64_t page_count);
|
||||||
|
|
||||||
//loaded sections are copied to new pages. once storage drivers are written,
|
//returns 0 on failure, 1 on success.
|
||||||
//this should probably just take a file handle so it can load and parse the
|
int load_elf(
|
||||||
//header and then load sections directly into user pages.
|
|
||||||
void load_elf(
|
|
||||||
struct process *process, uint64_t *entry_out,
|
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);
|
void destroy_process(struct process *process);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue