Compare commits

..
13 Commits
58 changed files with 768 additions and 2938 deletions
-1
View File
@@ -1 +0,0 @@
![It works!](./WATCHME.png)
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 949 KiB

+14 -26
View File
@@ -3,34 +3,22 @@ set -euo pipefail
export CC=clang export CC=clang
LOG_LEVEL=1 meson setup build --reconfigure
for arg in "${@}"; do
case "${arg}" in
-v) LOG_LEVEL=2 ;;
-vv) LOG_LEVEL=3 ;;
-vvv) LOG_LEVEL=4 ;;
esac
done
meson setup build --reconfigure -Dc_args="-DLOG_LEVEL=${LOG_LEVEL}"
meson compile -v -C build meson compile -v -C build
sector_size=512 sector_size=512
partition_offset=2048 partition_offset=2048
dd if=/dev/zero of=build/os.raw bs="${sector_size}" count="$((partition_offset + 20480))" dd if=/dev/zero of=build/os.img bs="${sector_size}" count="$((partition_offset + 20480))"
dd if=build/mbr.bin of=build/os.raw bs="${sector_size}" count=1 conv=notrunc dd if=build/mbr.bin of=build/os.img bs="${sector_size}" count=1 conv=notrunc
dd if=build/bootloader.bin of=build/os.raw bs="${sector_size}" seek=1 count="$((partition_offset - 1))" conv=notrunc dd if=build/bootloader.bin of=build/os.img bs="${sector_size}" seek=1 count="$((partition_offset - 1))" conv=notrunc
mkfs.fat -F 16 --offset "${partition_offset}" build/os.raw mkfs.fat -F 16 --offset "${partition_offset}" build/os.img
mcopy -i build/os.raw@@"$((partition_offset * sector_size))" -s src ::src mcopy -i build/os.img@@"$((partition_offset * sector_size))" -s src ::src
mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/kernel.bin ::kernel.bin mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/kernel.bin ::kernel.bin
mmd -i build/os.raw@@"$((partition_offset * sector_size))" ::bin mmd -i build/os.img@@"$((partition_offset * sector_size))" ::bin
mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/terminal ::bin/terminal mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/terminal ::bin/terminal
mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/shell ::bin/shell mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/shell ::bin/shell
mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/echo ::bin/echo mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/echo ::bin/echo
mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/ls ::bin/ls mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/ls ::bin/ls
mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/cat ::bin/cat mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/cat ::bin/cat
mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/cp ::bin/cp mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/cp ::bin/cp
mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/mkdir ::bin/mkdir
mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/rm ::bin/rm
mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/wc ::bin/wc
-19
View File
@@ -1,19 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
device=${1:-}
if [[ ! -b ${device} ]]; then
echo "ERROR: \"${device}\" is not a block device" >&2
fi
if [[ ! -f build/os.raw ]]; then
echo "ERROR: \"build/os.raw\" does not appear to be built, run \"build.sh\"" >&2
fi
echo 'Copying the image...' >&2
mnt=$(mktemp --directory)
mount "${device}2" "${mnt}"
cp --update "build/os.raw" "${mnt}"
umount "${mnt}"
rm -rf "${mnt}"
echo 'Done.' >&2
+236 -59
View File
@@ -71,46 +71,35 @@ kernel_sources = files([
'src/kernel/fat16.c', 'src/kernel/fat16.c',
'src/kernel/fs.c', 'src/kernel/fs.c',
'src/kernel/gdt.c', 'src/kernel/gdt.c',
'src/kernel/hid-keyboard.c',
'src/kernel/idt.c', 'src/kernel/idt.c',
'src/kernel/kernel.c', 'src/kernel/kernel.c',
'src/kernel/log.c', 'src/kernel/keyboard.c',
'src/kernel/memory.c', 'src/kernel/memory.c',
'src/kernel/nvme.c',
'src/kernel/panic.c', 'src/kernel/panic.c',
'src/kernel/path.c', 'src/kernel/path.c',
'src/kernel/pci.c',
'src/kernel/pic.c', 'src/kernel/pic.c',
'src/kernel/pipe.c', 'src/kernel/pipe.c',
'src/kernel/process.c', 'src/kernel/process.c',
'src/kernel/ps2-keyboard.c',
'src/kernel/syscall.c', 'src/kernel/syscall.c',
'src/kernel/timer.c', 'src/kernel/timer.c',
'src/kernel/tss.c', 'src/kernel/tss.c',
'src/kernel/usb.c',
'src/kernel/vga.c', 'src/kernel/vga.c',
'src/kernel/xhci.c',
]) ])
c_args = [
'-ffreestanding',
'-nostdlib',
'-nostartfiles',
'-mno-red-zone',
'-mgeneral-regs-only',
'-fno-stack-protector',
'-DVERSION="' + meson.project_version() + '"',
]
kernel_elf = executable( kernel_elf = executable(
'kernel.elf', 'kernel.elf',
sources: [kernel_entry_o, timer_o, process_o, syscall_o, lib_sources, kernel_sources], sources: [kernel_entry_o, timer_o, process_o, syscall_o, lib_sources, kernel_sources],
c_args: [ c_args: [
c_args, '-ffreestanding',
'-nostdlib',
'-nostartfiles',
'-mno-red-zone',
'-mgeneral-regs-only',
'-mcmodel=kernel', '-mcmodel=kernel',
'-Wno-unused-command-line-argument', '-Wno-unused-command-line-argument',
'-Wconversion', '-Wconversion',
'-DKERNEL="yes"', '-DKERNEL="yes"',
'-DVERSION="' + meson.project_version() + '"',
], ],
link_args: [ link_args: [
'-T', meson.project_source_root() / 'src/kernel/linker.ld', '-T', meson.project_source_root() / 'src/kernel/linker.ld',
@@ -127,48 +116,236 @@ custom_target(
build_by_default: true, build_by_default: true,
) )
foreach app : ['terminal', 'shell', 'echo', 'ls', 'cat', 'cp', 'mkdir', 'rm', 'wc'] terminal_start = custom_target(
start = custom_target( 'terminal_start',
f'@app@_start', input: 'src/user/start.asm',
input: 'src/user/start.asm', output: 'terminal_start.o',
output: f'@app@_start.o', command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'], )
)
syscall = custom_target( terminal_syscall = custom_target(
f'@app@_syscall', 'terminal_syscall',
input: 'src/user/syscall.asm', input: 'src/user/syscall.asm',
output: f'@app@_syscall.o', output: 'terminal_syscall.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'], command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
) )
elf = executable( terminal_elf = executable(
f'@app@.elf', 'terminal.elf',
sources: [start, syscall, lib_sources, f'src/user/app/@app@/@app@.c'], sources: [terminal_start, terminal_syscall, lib_sources, 'src/user/app/terminal/terminal.c'],
c_args: [ c_args: [
c_args, '-ffreestanding',
'-mcmodel=large', '-nostdlib',
], '-fno-stack-protector',
link_args: [ '-mcmodel=large',
'-T', meson.project_source_root() / 'src/user/linker.ld', '-DVERSION="' + meson.project_version() + '"',
'-nostdlib', ],
], link_args: [
link_depends: 'src/user/linker.ld', '-T', meson.project_source_root() / 'src/user/linker.ld',
) '-nostdlib',
],
link_depends: 'src/user/linker.ld',
)
elf_data = custom_target( custom_target(
f'@app@_data.elf', 'terminal',
input: elf, input: terminal_elf,
output: f'@app@_data.elf', output: 'terminal',
command: ['objcopy', '--set-section-flags', '.data=alloc,load,contents', '@INPUT@', '@OUTPUT@'], command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
build_by_default: true, build_by_default: true,
) )
custom_target( shell_start = custom_target(
app, 'shell_start',
input: elf_data, input: 'src/user/start.asm',
output: app, output: 'shell_start.o',
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'], command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
build_by_default: true, )
)
endforeach shell_syscall = custom_target(
'shell_syscall',
input: 'src/user/syscall.asm',
output: 'shell_syscall.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
shell_elf = executable(
'shell.elf',
sources: [shell_start, shell_syscall, lib_sources, 'src/user/app/shell/shell.c'],
c_args: [
'-ffreestanding',
'-nostdlib',
'-fno-stack-protector',
'-mcmodel=large',
'-DVERSION="' + meson.project_version() + '"',
],
link_args: [
'-T', meson.project_source_root() / 'src/user/linker.ld',
'-nostdlib',
],
link_depends: 'src/user/linker.ld',
)
custom_target(
'shell',
input: shell_elf,
output: 'shell',
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
build_by_default: true,
)
echo_start = custom_target(
'echo_start',
input: 'src/user/start.asm',
output: 'echo_start.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
echo_syscall = custom_target(
'echo_syscall',
input: 'src/user/syscall.asm',
output: 'echo_syscall.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
echo_elf = executable(
'echo.elf',
sources: [echo_start, echo_syscall, lib_sources, 'src/user/app/echo/echo.c'],
c_args: [
'-ffreestanding',
'-nostdlib',
'-fno-stack-protector',
'-mcmodel=large',
'-DVERSION="' + meson.project_version() + '"',
],
link_args: [
'-T', meson.project_source_root() / 'src/user/linker.ld',
'-nostdlib',
],
link_depends: 'src/user/linker.ld',
)
custom_target(
'echo',
input: echo_elf,
output: 'echo',
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
build_by_default: true,
)
ls_start = custom_target(
'ls_start',
input: 'src/user/start.asm',
output: 'ls_start.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
ls_syscall = custom_target(
'ls_syscall',
input: 'src/user/syscall.asm',
output: 'ls_syscall.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
ls_elf = executable(
'ls.elf',
sources: [ls_start, ls_syscall, lib_sources, 'src/user/app/ls/ls.c'],
c_args: [
'-ffreestanding',
'-nostdlib',
'-fno-stack-protector',
'-mcmodel=large',
'-DVERSION="' + meson.project_version() + '"',
],
link_args: [
'-T', meson.project_source_root() / 'src/user/linker.ld',
'-nostdlib',
],
link_depends: 'src/user/linker.ld',
)
custom_target(
'ls',
input: ls_elf,
output: 'ls',
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
build_by_default: true,
)
cat_start = custom_target(
'cat_start',
input: 'src/user/start.asm',
output: 'cat_start.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
cat_syscall = custom_target(
'cat_syscall',
input: 'src/user/syscall.asm',
output: 'cat_syscall.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
cat_elf = executable(
'cat.elf',
sources: [cat_start, cat_syscall, lib_sources, 'src/user/app/cat/cat.c'],
c_args: [
'-ffreestanding',
'-nostdlib',
'-fno-stack-protector',
'-mcmodel=large',
'-DVERSION="' + meson.project_version() + '"',
],
link_args: [
'-T', meson.project_source_root() / 'src/user/linker.ld',
'-nostdlib',
],
link_depends: 'src/user/linker.ld',
)
custom_target(
'cat',
input: cat_elf,
output: 'cat',
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
build_by_default: true,
)
cp_start = custom_target(
'cp_start',
input: 'src/user/start.asm',
output: 'cp_start.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
cp_syscall = custom_target(
'cp_syscall',
input: 'src/user/syscall.asm',
output: 'cp_syscall.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
cp_elf = executable(
'cp.elf',
sources: [cp_start, cp_syscall, lib_sources, 'src/user/app/cp/cp.c'],
c_args: [
'-ffreestanding',
'-nostdlib',
'-fno-stack-protector',
'-mcmodel=large',
'-DVERSION="' + meson.project_version() + '"',
],
link_args: [
'-T', meson.project_source_root() / 'src/user/linker.ld',
'-nostdlib',
],
link_depends: 'src/user/linker.ld',
)
custom_target(
'cp',
input: cp_elf,
output: 'cp',
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
build_by_default: true,
)
+6 -8
View File
@@ -10,6 +10,7 @@ mov sp, 0x7000
FIRST_PARTITION_SECTOR equ 2048 ; TODO Read MBR. FIRST_PARTITION_SECTOR equ 2048 ; TODO Read MBR.
STAGE_BUFFER_SEGMENT equ 0x0900 STAGE_BUFFER_SEGMENT equ 0x0900
STAGE_BUFFER_OFFSET equ 0x0000 STAGE_BUFFER_OFFSET equ 0x0000
KERNEL_BUFFER_SEGMENT equ 0x2000
jmp prepare_kernel jmp prepare_kernel
@@ -38,10 +39,9 @@ root_start: dw 0
root_size: dw 0 root_size: dw 0
data_start: dw 0 data_start: dw 0
kernel_filename: db 'KERNEL BIN' kernel_filename: db 'KERNEL BIN'
kernel_cluster: dw 0 kernel_cluster: dw 0
kernel_buffer_segment: dw 0x2000 kernel_buffer_offset: dw 0
kernel_buffer_offset: dw 0
read_sectors: read_sectors:
xor bx, bx xor bx, bx
@@ -192,7 +192,7 @@ load_kernel_cluster:
add ax, [data_start] add ax, [data_start]
xor cx, cx xor cx, cx
mov cl, [bpb.sectors_per_cluster] mov cl, [bpb.sectors_per_cluster]
mov bx, [kernel_buffer_segment] mov bx, KERNEL_BUFFER_SEGMENT
mov es, bx mov es, bx
mov di, [kernel_buffer_offset] mov di, [kernel_buffer_offset]
call read_sectors call read_sectors
@@ -201,8 +201,6 @@ load_kernel_cluster:
shl ax, 9 ; * 512 shl ax, 9 ; * 512
add ax, [kernel_buffer_offset] add ax, [kernel_buffer_offset]
mov [kernel_buffer_offset], ax mov [kernel_buffer_offset], ax
jnc find_next_kernel_cluster
add word [kernel_buffer_segment], 0x1000
find_next_kernel_cluster: find_next_kernel_cluster:
xor bx, bx xor bx, bx
@@ -247,7 +245,7 @@ gdt_data:
.base_low: dw 0x0000 .base_low: dw 0x0000
.base_middle: db 0x00 .base_middle: db 0x00
.access: db 10010010b ; present, ring 0, data, writable .access: db 10010010b ; present, ring 0, data, writable
.flags: db 10000000b .flags: db 00000000b
.base_high: db 0x00 .base_high: db 0x00
gdt_data_end: gdt_data_end:
gdt_end: gdt_end:
+193 -348
View File
@@ -1,11 +1,10 @@
#include "src/kernel/fat16.h" #include "src/kernel/fat16.h"
#include "src/kernel/ata.h"
#include "src/kernel/fs.h" #include "src/kernel/fs.h"
#include "src/kernel/nvme.h"
#include "src/kernel/panic.h" #include "src/kernel/panic.h"
#include "src/kernel/stream.h" #include "src/kernel/stream.h"
#include "src/lib/memory.h" #include "src/lib/memory.h"
#include "src/lib/string.h" #include "src/lib/string.h"
#include "src/lib/syscall.h"
#include "src/lib/util.h" #include "src/lib/util.h"
#define SECTOR_SIZE 512 #define SECTOR_SIZE 512
@@ -34,68 +33,96 @@ typedef struct __attribute__((packed)) {
uint32_t size; uint32_t size;
} fat16_dir_entry_t; } fat16_dir_entry_t;
// Assuming one persistently mounted partition. #define MAX_INODES 256
static fat16_bpb_t *bpb = NUL;
static uint32_t data_start;
static uint16_t *fat = NUL;
typedef struct { typedef struct {
fs_node_t base; uint32_t refs;
uint16_t first_cluster;
uint32_t size;
uint16_t dir_cluster; uint16_t dir_cluster;
uint16_t dir_index; uint16_t dir_index;
uint16_t first_cluster; uint8_t valid;
} fat16_node_t; } fat16_inode_t;
#define MAX_NODES 256 static fat16_inode_t inodes[MAX_INODES];
static fat16_node_t nodes[MAX_NODES]; static fat16_inode_t *inode_create(uint16_t first_cluster, uint32_t size, uint16_t dir_cluster, uint16_t dir_index) {
for (uint64_t i = 0; i < MAX_INODES; i++) {
static fs_node_t *node_create(uint16_t dir_cluster, uint16_t dir_index, const char *name, uint8_t is_dir, uint16_t first_cluster, if (!inodes[i].valid) {
uint32_t size) { inodes[i] = (fat16_inode_t){
for (uint64_t i = 0; i < MAX_NODES; i++) { .refs = 1,
if (!nodes[i].base.refs) { .first_cluster = first_cluster,
nodes[i].base.type = FAT16; .size = size,
nodes[i].base.refs = 1; .dir_cluster = dir_cluster,
memory_copy(name, FILENAME_SIZE_LIMIT + 1, nodes[i].base.name); .dir_index = dir_index,
nodes[i].base.size = size; .valid = 1,
nodes[i].base.is_dir = is_dir; };
nodes[i].base.removed = 0; return &inodes[i];
nodes[i].dir_cluster = dir_cluster;
nodes[i].dir_index = dir_index;
nodes[i].first_cluster = first_cluster;
return (fs_node_t *)&nodes[i];
} }
} }
return NUL; return NUL;
} }
static fs_node_t *node_get(uint32_t dir_cluster, uint16_t dir_index) { static fat16_inode_t *inode_get(uint32_t dir_cluster, uint16_t dir_index) {
for (uint64_t i = 0; i < MAX_NODES; i++) { for (uint64_t i = 0; i < MAX_INODES; i++) {
if (nodes[i].base.refs && nodes[i].dir_cluster == dir_cluster && nodes[i].dir_index == dir_index) { if (inodes[i].valid && inodes[i].dir_cluster == dir_cluster && inodes[i].dir_index == dir_index) {
return (fs_node_t *)&nodes[i]; return &inodes[i];
} }
} }
return NUL; return NUL;
} }
static fs_node_t *node_use(uint16_t dir_cluster, uint16_t dir_index, const char *name, uint8_t is_dir, uint16_t first_cluster, static fat16_inode_t *inode_use(uint16_t first_cluster, uint32_t size, uint16_t dir_cluster, uint16_t dir_index) {
uint32_t size) { fat16_inode_t *result = inode_get(dir_cluster, dir_index);
fs_node_t *result = node_get(dir_cluster, dir_index);
if (!result) { if (!result) {
result = node_create(dir_cluster, dir_index, name, is_dir, first_cluster, size); result = inode_create(first_cluster, size, dir_cluster, dir_index);
} else { } else {
ASSERT(result->refs < UINT32_MAX, "node_use: too many references");
result->refs++; result->refs++;
} }
return result; return result;
} }
static void node_free(fs_node_t *node) { static void inode_free(fat16_inode_t *inode) {
if (node->refs) { inode->refs--;
node->refs--; if (!inode->refs) {
for (uint64_t i = 0; i < MAX_INODES; i++) {
if (&inodes[i] == inode) {
inodes[i].valid = 0;
break;
}
}
} }
} }
typedef struct {
fs_node_t base;
fat16_inode_t *inode;
} fat16_node_t;
static fat16_bpb_t bpb; // Assuming one partition.
static uint32_t data_start;
static fs_node_t *fs = NUL;
static uint16_t *fat = NUL;
fs_node_t *fat16_mount() { // Assuming one partition.
uint8_t sector[512];
ata_read_sectors(FIRST_PARTITION_SECTOR, 1, &sector);
memory_copy(sector + 11, sizeof(fat16_bpb_t), &bpb);
data_start = FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.sectors_per_fat * bpb.fats_count +
(bpb.root_entry_count * sizeof(fat16_dir_entry_t) + SECTOR_SIZE - 1) / SECTOR_SIZE;
fat16_node_t *node = memory_allocate(sizeof(fat16_node_t));
node->base.type = FAT16;
node->base.name[0] = '/';
node->base.size = sizeof(fat16_dir_entry_t) * bpb.root_entry_count;
node->base.is_dir = 1;
node->inode = inode_use(0, node->base.size, 0, UINT16_MAX);
if (!node->inode) {
memory_free(node);
return NUL;
}
return fs = (fs_node_t *)node;
}
static void to_8_3(const char *name, char *output) { static void to_8_3(const char *name, char *output) {
memory_set(' ', 11, output); memory_set(' ', 11, output);
output[11] = '\0'; output[11] = '\0';
@@ -129,35 +156,17 @@ static void from_8_3(const char *name, const char *extension, char *output) {
} }
} }
static void ensure_bpb() {
if (bpb) {
return;
}
uint8_t sector[512];
nvme_read_sectors(FIRST_PARTITION_SECTOR, 1, &sector);
bpb = memory_allocate(sizeof(fat16_bpb_t));
memory_copy(sector + 11, sizeof(fat16_bpb_t), bpb);
data_start = FIRST_PARTITION_SECTOR + bpb->reserved_sectors + bpb->sectors_per_fat * bpb->fats_count +
(bpb->root_entry_count * sizeof(fat16_dir_entry_t) + SECTOR_SIZE - 1) / SECTOR_SIZE;
}
static void ensure_fat() { static void ensure_fat() {
if (fat) { ASSERT(bpb.sectors_per_fat < 256, "ensure_fat: big FAT not implemented")
return; if (!fat) {
fat = memory_allocate(bpb.sectors_per_fat * SECTOR_SIZE);
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors, (uint8_t)bpb.sectors_per_fat, fat);
} }
ensure_bpb();
ASSERT(bpb->sectors_per_fat < 256, "ensure_fat: big FAT not implemented");
fat = memory_allocate(bpb->sectors_per_fat * SECTOR_SIZE);
nvme_read_sectors(FIRST_PARTITION_SECTOR + bpb->reserved_sectors, (uint8_t)bpb->sectors_per_fat, fat);
} }
static uint16_t allocate_cluster() { static uint16_t allocate_cluster() {
ensure_fat(); ensure_fat();
for (uint16_t i = 2; i < bpb->sectors_per_fat * SECTOR_SIZE / 2; i++) { for (uint16_t i = 2; i < bpb.sectors_per_fat * SECTOR_SIZE / 2; i++) {
if (fat[i] == 0x0000) { if (fat[i] == 0x0000) {
fat[i] = 0xFFFF; fat[i] = 0xFFFF;
return i; return i;
@@ -167,40 +176,38 @@ static uint16_t allocate_cluster() {
} }
static void flush_fat() { static void flush_fat() {
ensure_fat(); ata_write_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors, (uint8_t)bpb.sectors_per_fat, fat);
nvme_write_sectors(FIRST_PARTITION_SECTOR + bpb->reserved_sectors, (uint8_t)bpb->sectors_per_fat, fat);
} }
static uint16_t read_directory(uint16_t dir_cluster, fat16_dir_entry_t **entries) { static fat16_dir_entry_t *read_directory(uint16_t dir_cluster) {
ensure_bpb(); fat16_dir_entry_t *entries;
if (!dir_cluster) { if (!dir_cluster) {
uint8_t sectors = (uint8_t)((sizeof(fat16_dir_entry_t) * bpb->root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE); uint8_t sectors = (uint8_t)((sizeof(fat16_dir_entry_t) * bpb.root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE);
*entries = memory_allocate(sectors * SECTOR_SIZE); entries = memory_allocate(sectors * SECTOR_SIZE + sizeof(fat16_dir_entry_t)); // One extra as null terminator.
nvme_read_sectors(FIRST_PARTITION_SECTOR + bpb->reserved_sectors + bpb->fats_count * bpb->sectors_per_fat, sectors, *entries); ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.fats_count * bpb.sectors_per_fat, sectors, entries);
return bpb->root_entry_count;
} else { } else {
ensure_fat(); ensure_fat();
uint16_t next_cluster = dir_cluster; uint16_t next_cluster = dir_cluster;
uint16_t cluster_count = 0; uint32_t cluster_count = 0;
while (next_cluster < 0xFFF8) { while (next_cluster < 0xFFF8) {
cluster_count++; cluster_count++;
next_cluster = fat[next_cluster]; next_cluster = fat[next_cluster];
} }
*entries = memory_allocate(cluster_count * bpb->sectors_per_cluster * SECTOR_SIZE); entries =
memory_allocate(cluster_count * bpb.sectors_per_cluster * SECTOR_SIZE + sizeof(fat16_dir_entry_t)); // One extra as null terminator.
uint8_t *chunk = (uint8_t *)*entries; uint8_t *chunk = (uint8_t *)entries;
next_cluster = dir_cluster; next_cluster = dir_cluster;
while (next_cluster < 0xFFF8) { while (next_cluster < 0xFFF8) {
nvme_read_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, chunk); ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, chunk);
chunk += bpb->sectors_per_cluster * SECTOR_SIZE; chunk += bpb.sectors_per_cluster * SECTOR_SIZE;
next_cluster = fat[next_cluster]; next_cluster = fat[next_cluster];
} }
return cluster_count * bpb->sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t);
} }
return (uint16_t)-1; return entries;
} }
static fs_node_t *open_entry(uint16_t dir_cluster, const fat16_dir_entry_t *entries, uint16_t index) { static fs_node_t *open_entry(uint16_t dir_cluster, const fat16_dir_entry_t *entries, uint16_t index) {
@@ -210,61 +217,53 @@ static fs_node_t *open_entry(uint16_t dir_cluster, const fat16_dir_entry_t *entr
return NUL; return NUL;
} }
char name[FILENAME_SIZE_LIMIT + 1]; fat16_node_t *result = memory_allocate(sizeof(fat16_node_t));
from_8_3(entry->name, entry->ext, name); result->base.type = FAT16;
from_8_3(entry->name, entry->ext, result->base.name);
return node_use(dir_cluster, index, name, entry->attributes & ATTRIBUTE_SUBDIRECTORY, entry->first_cluster, entry->size); result->base.size = entry->size;
} result->base.is_dir = entry->attributes & ATTRIBUTE_SUBDIRECTORY;
result->inode = inode_use(entry->first_cluster, entry->size, dir_cluster, index);
static void write_directory(uint16_t dir_cluster, const fat16_dir_entry_t *entries, uint16_t count) { if (!result->inode) {
ensure_bpb(); memory_free(result);
ASSERT((count * sizeof(fat16_dir_entry_t)) % (bpb->sectors_per_cluster * SECTOR_SIZE) == 0,
"write_directory: entries must be aligned to clusters");
if (!dir_cluster) {
nvme_write_sectors(FIRST_PARTITION_SECTOR + bpb->reserved_sectors + bpb->fats_count * bpb->sectors_per_fat,
(uint8_t)((sizeof(fat16_dir_entry_t) * bpb->root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE), entries);
} else {
ensure_fat();
uint8_t *chunk = (uint8_t *)entries;
uint16_t next_cluster = dir_cluster;
while (count) {
nvme_write_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, chunk);
chunk += bpb->sectors_per_cluster * SECTOR_SIZE;
count -= bpb->sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t);
if (count && fat[next_cluster] >= 0xFFF8) {
fat[next_cluster] = allocate_cluster();
}
next_cluster = fat[next_cluster];
}
flush_fat();
}
}
fs_node_t *fat16_open_root() {
ensure_bpb();
return node_use(0, UINT16_MAX, "", 1, 0, sizeof(fat16_dir_entry_t) * bpb->root_entry_count);
}
fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name, uint64_t flags) {
if (!directory || directory->type != FAT16 || !directory->is_dir || directory->removed) {
return NUL; return NUL;
} }
uint16_t dir_cluster = ((fat16_node_t *)directory)->first_cluster; return (fs_node_t *)result;
}
static void write_directory(uint16_t dir_cluster, const fat16_dir_entry_t *entries) {
if (!dir_cluster) {
ata_write_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.fats_count * bpb.sectors_per_fat,
(uint8_t)((sizeof(fat16_dir_entry_t) * bpb.root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE), entries);
} else {
ensure_fat();
// Assuming no entries were added or removed.
uint8_t *chunk = (uint8_t *)entries;
uint16_t next_cluster = dir_cluster;
while (next_cluster < 0xFFF8) {
ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, chunk);
chunk += bpb.sectors_per_cluster * SECTOR_SIZE;
next_cluster = fat[next_cluster];
}
}
}
fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name) {
if (directory->type != FAT16 || !directory->is_dir) {
return NUL;
}
char name_8_3[12]; char name_8_3[12];
to_8_3(name, name_8_3); to_8_3(name, name_8_3);
fat16_dir_entry_t *entries; fat16_dir_entry_t *entries = read_directory(((fat16_node_t *)directory)->inode->first_cluster);
uint16_t entries_count = read_directory(dir_cluster, &entries);
fat16_dir_entry_t *entry = entries; fat16_dir_entry_t *entry = entries;
uint16_t index = 0; uint16_t index = 0;
while (index < entries_count && entry->name[0]) { while (entry->name[0]) {
if ((uint8_t)entry->name[0] != 0xE5 && (uint8_t)entry->attributes != 0x0F && bytes_equal(name_8_3, (char *)entry, 11)) { if ((uint8_t)entry->name[0] != 0xE5 && (uint8_t)entry->attributes != 0x0F && bytes_equal(name_8_3, (char *)entry, 11)) {
break; break;
} }
@@ -272,82 +271,20 @@ fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name, uint64_t
index++; index++;
} }
fs_node_t *result = open_entry(dir_cluster, entries, index); fs_node_t *result = open_entry(((fat16_node_t *)directory)->inode->first_cluster, entries, index);
if (result && (flags & OPEN_EXCLUSIVE)) {
memory_free(entries);
return NUL;
}
if (!result && (flags & OPEN_CREATE)) {
index = 0;
while (index < entries_count && entries[index].name[0]) {
index++;
}
if (index >= entries_count) {
if (!dir_cluster) {
memory_free(entries);
return NUL;
} else {
uint16_t new_entries_count = entries_count + bpb->sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t);
fat16_dir_entry_t *new_entries = memory_allocate(new_entries_count * sizeof(fat16_dir_entry_t));
memory_copy(entries, entries_count * sizeof(fat16_dir_entry_t), new_entries);
memory_free(entries);
entries_count = new_entries_count;
entries = new_entries;
}
}
memory_copy(name_8_3, 11, &entries[index]);
if (flags & OPEN_DIRECTORY && !(flags & OPEN_FILE)) {
entries[index].attributes = ATTRIBUTE_SUBDIRECTORY;
entries[index].first_cluster = allocate_cluster();
fat16_dir_entry_t *inner_entries = memory_allocate(bpb->sectors_per_cluster * SECTOR_SIZE);
memory_copy(". ", 11, inner_entries[0].name);
inner_entries[0].attributes = ATTRIBUTE_SUBDIRECTORY;
inner_entries[0].first_cluster = entries[index].first_cluster;
memory_copy(".. ", 11, inner_entries[1].name);
inner_entries[1].attributes = ATTRIBUTE_SUBDIRECTORY;
inner_entries[1].first_cluster = dir_cluster;
write_directory(entries[index].first_cluster, inner_entries, bpb->sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t));
memory_free(inner_entries);
}
write_directory(dir_cluster, entries, entries_count);
result = open_entry(dir_cluster, entries, index);
}
memory_free(entries); memory_free(entries);
if (!result) {
return NUL;
}
if (result->is_dir && !(flags & OPEN_DIRECTORY)) {
return NUL;
}
if (!result->is_dir && !(flags & OPEN_FILE)) {
return NUL;
}
return result; return result;
} }
fs_node_t *fat16_open_at(const fs_node_t *directory, uint16_t index, uint64_t flags) { fs_node_t *fat16_open_at(const fs_node_t *directory, uint64_t index) {
if (!directory || directory->type != FAT16 || !directory->is_dir || directory->removed) { if (directory->type != FAT16 || !directory->is_dir) {
return NUL; return NUL;
} }
uint16_t dir_cluster = ((fat16_node_t *)directory)->first_cluster; fat16_dir_entry_t *entries = read_directory(((fat16_node_t *)directory)->inode->first_cluster);
fat16_dir_entry_t *entries;
uint16_t entries_count = read_directory(dir_cluster, &entries);
uint16_t ei = 0, vi = 0; uint16_t ei = 0, vi = 0;
while (ei < entries_count && entries[ei].name[0]) { while (entries[ei].name[0]) {
if ((uint8_t)entries[ei].name[0] != 0xE5 && (uint8_t)entries[ei].attributes != 0x0F) { if ((uint8_t)entries[ei].name[0] != 0xE5 && (uint8_t)entries[ei].attributes != 0x0F) {
if (vi == index) { if (vi == index) {
break; break;
@@ -357,56 +294,37 @@ fs_node_t *fat16_open_at(const fs_node_t *directory, uint16_t index, uint64_t fl
ei++; ei++;
} }
fs_node_t *result = ei < entries_count ? open_entry(dir_cluster, entries, ei) : NUL; fs_node_t *result = open_entry(((fat16_node_t *)directory)->inode->first_cluster, entries, ei);
memory_free(entries); memory_free(entries);
if (result && (flags & OPEN_EXCLUSIVE)) {
return NUL;
}
if (!result) {
return NUL;
}
if (result->is_dir && !(flags & OPEN_DIRECTORY)) {
return NUL;
}
if (!result->is_dir && !(flags & OPEN_FILE)) {
return NUL;
}
return result; return result;
} }
fs_node_t *fat16_open_again(fs_node_t *source) { fs_node_t *fat16_open_again(const fs_node_t *source) {
ASSERT(source->refs < UINT32_MAX, "fat16_open_again: too many references"); fs_node_t *result = memory_allocate(sizeof(fat16_node_t));
source->refs++; memory_copy(source, sizeof(fat16_node_t), result);
return source; ((fat16_node_t *)result)->inode->refs++;
return result;
} }
uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void *to) { uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void *to) {
if (!file || file->type != FAT16 || file->is_dir) { fat16_node_t *fat_file = (fat16_node_t *)file;
if (fat_file->base.type != FAT16 || fat_file->base.is_dir) {
return (uint64_t)-1; return (uint64_t)-1;
} }
if (file->removed) { if (offset >= fat_file->inode->size) {
return 0; return 0;
} }
if (offset >= file->size) { if (offset + bytes >= fat_file->inode->size) {
return 0; bytes = fat_file->inode->size - offset;
}
if (offset + bytes >= file->size) {
bytes = file->size - offset;
} }
ensure_fat(); ensure_fat();
uint32_t cluster_size = bpb->sectors_per_cluster * SECTOR_SIZE; uint32_t cluster_size = bpb.sectors_per_cluster * SECTOR_SIZE;
uint32_t next_cluster = ((fat16_node_t *)file)->first_cluster; uint32_t next_cluster = fat_file->inode->first_cluster;
while (offset >= cluster_size) { while (offset >= cluster_size) {
next_cluster = fat[next_cluster]; next_cluster = fat[next_cluster];
@@ -418,7 +336,7 @@ uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void
uint8_t *cursor = to; uint8_t *cursor = to;
uint8_t *tmp = memory_allocate(cluster_size); uint8_t *tmp = memory_allocate(cluster_size);
nvme_read_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, tmp); ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp);
uint32_t prefix_size = bytes <= cluster_size - offset ? bytes : cluster_size - offset; uint32_t prefix_size = bytes <= cluster_size - offset ? bytes : cluster_size - offset;
memory_copy(tmp + offset, prefix_size, cursor); memory_copy(tmp + offset, prefix_size, cursor);
bytes -= prefix_size; bytes -= prefix_size;
@@ -427,7 +345,7 @@ uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void
next_cluster = fat[next_cluster]; next_cluster = fat[next_cluster];
while (bytes >= cluster_size) { while (bytes >= cluster_size) {
nvme_read_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, cursor); ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, cursor);
bytes -= cluster_size; bytes -= cluster_size;
readden += cluster_size; readden += cluster_size;
cursor += cluster_size; cursor += cluster_size;
@@ -435,7 +353,7 @@ uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void
} }
if (bytes) { if (bytes) {
nvme_read_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, tmp); ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp);
memory_copy(tmp, bytes, cursor); memory_copy(tmp, bytes, cursor);
readden += bytes; readden += bytes;
} }
@@ -446,24 +364,20 @@ uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void
} }
uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_t bytes) { uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_t bytes) {
if (!file || file->type != FAT16 || file->is_dir) { fat16_node_t *fat_file = (fat16_node_t *)file;
return (uint64_t)-1;
}
if (file->removed) { if (fat_file->base.type != FAT16 || fat_file->base.is_dir) {
return 0; return (uint64_t)-1;
} }
ensure_fat(); ensure_fat();
fat16_node_t *fat_file = (fat16_node_t *)file; if (!fat_file->inode->first_cluster) {
fat_file->inode->first_cluster = allocate_cluster();
if (!fat_file->first_cluster) {
fat_file->first_cluster = allocate_cluster();
} }
uint32_t cluster_size = bpb->sectors_per_cluster * SECTOR_SIZE; uint32_t cluster_size = bpb.sectors_per_cluster * SECTOR_SIZE;
uint32_t next_cluster = fat_file->first_cluster; uint32_t next_cluster = fat_file->inode->first_cluster;
uint32_t allocated = cluster_size; uint32_t allocated = cluster_size;
while (allocated < offset + bytes) { while (allocated < offset + bytes) {
@@ -476,8 +390,8 @@ uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_
flush_fat(); flush_fat();
cluster_size = bpb->sectors_per_cluster * SECTOR_SIZE; cluster_size = bpb.sectors_per_cluster * SECTOR_SIZE;
next_cluster = fat_file->first_cluster; next_cluster = fat_file->inode->first_cluster;
while (offset >= cluster_size) { while (offset >= cluster_size) {
next_cluster = fat[next_cluster]; next_cluster = fat[next_cluster];
@@ -489,17 +403,17 @@ uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_
const uint8_t *cursor = from; const uint8_t *cursor = from;
uint8_t *tmp = memory_allocate(cluster_size); uint8_t *tmp = memory_allocate(cluster_size);
nvme_read_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, tmp); ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp);
uint32_t prefix_size = bytes <= cluster_size - offset ? bytes : cluster_size - offset; uint32_t prefix_size = bytes <= cluster_size - offset ? bytes : cluster_size - offset;
memory_copy(cursor, prefix_size, tmp + offset); memory_copy(cursor, prefix_size, tmp + offset);
nvme_write_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, tmp); ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp);
bytes -= prefix_size; bytes -= prefix_size;
written += prefix_size; written += prefix_size;
cursor += prefix_size; cursor += prefix_size;
next_cluster = fat[next_cluster]; next_cluster = fat[next_cluster];
while (bytes >= cluster_size) { while (bytes >= cluster_size) {
nvme_write_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, cursor); ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, cursor);
bytes -= cluster_size; bytes -= cluster_size;
written += cluster_size; written += cluster_size;
cursor += cluster_size; cursor += cluster_size;
@@ -507,22 +421,21 @@ uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_
} }
if (bytes) { if (bytes) {
nvme_read_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, tmp); ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp);
memory_copy(cursor, bytes, tmp); memory_copy(cursor, bytes, tmp);
nvme_write_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, tmp); ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp);
written += bytes; written += bytes;
} }
memory_free(tmp); memory_free(tmp);
if (offset + written > file->size) { if (offset + written > fat_file->inode->size) {
file->size = offset + written; fat_file->inode->size = offset + written;
fat16_dir_entry_t *entries; fat16_dir_entry_t *entries = read_directory(fat_file->inode->dir_cluster);
uint16_t entries_count = read_directory(fat_file->dir_cluster, &entries); entries[fat_file->inode->dir_index].first_cluster = fat_file->inode->first_cluster;
entries[fat_file->dir_index].first_cluster = fat_file->first_cluster; entries[fat_file->inode->dir_index].size = fat_file->inode->size;
entries[fat_file->dir_index].size = file->size; write_directory(fat_file->inode->dir_cluster, entries);
write_directory(fat_file->dir_cluster, entries, entries_count);
memory_free(entries); memory_free(entries);
} }
@@ -530,12 +443,10 @@ uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_
} }
uint64_t fat16_truncate(fs_node_t *file, uint32_t size) { uint64_t fat16_truncate(fs_node_t *file, uint32_t size) {
if (!file || file->type != FAT16 || file->is_dir) { fat16_node_t *fat_file = (fat16_node_t *)file;
return (uint64_t)-1;
}
if (file->removed) { if (fat_file->base.type != FAT16 || fat_file->base.is_dir) {
return 0; return (uint64_t)-1;
} }
if (file->size == size) { if (file->size == size) {
@@ -547,11 +458,9 @@ uint64_t fat16_truncate(fs_node_t *file, uint32_t size) {
memory_free(tmp); memory_free(tmp);
return written == (uint64_t)-1 ? (uint64_t)-1 : file->size + written; return written == (uint64_t)-1 ? (uint64_t)-1 : file->size + written;
} else if (file->size > size) { } else if (file->size > size) {
fat16_node_t *fat_file = (fat16_node_t *)file; uint32_t cluster_size = bpb.sectors_per_cluster * SECTOR_SIZE;
uint32_t cluster_size = bpb->sectors_per_cluster * SECTOR_SIZE;
uint32_t prev_cluster = 0; uint32_t prev_cluster = 0;
uint32_t next_cluster = fat_file->first_cluster; uint32_t next_cluster = fat_file->inode->first_cluster;
ensure_fat(); ensure_fat();
uint32_t allocated = 0; uint32_t allocated = 0;
@@ -563,7 +472,7 @@ uint64_t fat16_truncate(fs_node_t *file, uint32_t size) {
if (prev_cluster) { if (prev_cluster) {
fat[prev_cluster] = 0xFFFF; fat[prev_cluster] = 0xFFFF;
} else { } else {
fat_file->first_cluster = 0; fat_file->inode->first_cluster = 0;
} }
do { do {
uint32_t swap = fat[next_cluster]; uint32_t swap = fat[next_cluster];
@@ -572,12 +481,11 @@ uint64_t fat16_truncate(fs_node_t *file, uint32_t size) {
} while (next_cluster < 0xFFF8); } while (next_cluster < 0xFFF8);
flush_fat(); flush_fat();
file->size = size; fat_file->inode->size = size;
fat16_dir_entry_t *entries; fat16_dir_entry_t *entries = read_directory(fat_file->inode->dir_cluster);
uint16_t entries_count = read_directory(fat_file->dir_cluster, &entries); entries[fat_file->inode->dir_index].first_cluster = fat_file->inode->first_cluster;
entries[fat_file->dir_index].first_cluster = fat_file->first_cluster; entries[fat_file->inode->dir_index].size = fat_file->inode->size;
entries[fat_file->dir_index].size = file->size; write_directory(fat_file->inode->dir_cluster, entries);
write_directory(fat_file->dir_cluster, entries, entries_count);
memory_free(entries); memory_free(entries);
return size; return size;
@@ -585,57 +493,6 @@ uint64_t fat16_truncate(fs_node_t *file, uint32_t size) {
return (uint64_t)-1; return (uint64_t)-1;
} }
uint64_t fat16_remove(fs_node_t *file) {
if (!file || file->type != FAT16) {
return (uint64_t)-1;
}
if (file->removed) {
return 0;
}
fat16_node_t *fat_file = (fat16_node_t *)file;
if (file->is_dir) {
fat16_dir_entry_t *subentries;
uint16_t subentries_count = read_directory(fat_file->first_cluster, &subentries);
uint16_t ei = 0, vi = 0;
while (ei < subentries_count && subentries[ei].name[0]) {
if ((uint8_t)subentries[ei].name[0] != 0xE5 && (uint8_t)subentries[ei].attributes != 0x0F) {
vi++;
}
ei++;
}
memory_free(subentries);
if (vi > 2) {
return (uint64_t)-1;
}
}
file->removed = 1;
if (fat_file->first_cluster) {
ensure_fat();
uint64_t next_cluster = fat_file->first_cluster;
do {
uint32_t swap = fat[next_cluster];
fat[next_cluster] = 0;
next_cluster = swap;
} while (next_cluster < 0xFFF8);
flush_fat();
}
fat16_dir_entry_t *entries;
uint16_t entries_count = read_directory(fat_file->dir_cluster, &entries);
entries[fat_file->dir_index].name[0] = 0xE5;
entries[fat_file->dir_index].first_cluster = 0;
entries[fat_file->dir_index].size = 0;
write_directory(fat_file->dir_cluster, entries, entries_count);
memory_free(entries);
return 1;
}
typedef struct { typedef struct {
stream_t stream; stream_t stream;
fs_node_t *node; fs_node_t *node;
@@ -643,10 +500,6 @@ typedef struct {
} fat16_file_stream_t; } fat16_file_stream_t;
static uint64_t file_stream_write(stream_t *self, const char *from, uint64_t bytes) { static uint64_t file_stream_write(stream_t *self, const char *from, uint64_t bytes) {
if (!self) {
return (uint64_t)-1;
}
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self; fat16_file_stream_t *ffs = (fat16_file_stream_t *)self;
uint64_t written = fat16_write(ffs->node, ffs->offset, from, bytes > UINT32_MAX ? UINT32_MAX : (uint32_t)bytes); uint64_t written = fat16_write(ffs->node, ffs->offset, from, bytes > UINT32_MAX ? UINT32_MAX : (uint32_t)bytes);
if (written != (uint64_t)-1) { if (written != (uint64_t)-1) {
@@ -656,10 +509,6 @@ static uint64_t file_stream_write(stream_t *self, const char *from, uint64_t byt
} }
static uint64_t file_stream_read(stream_t *self, uint64_t max, char *to) { static uint64_t file_stream_read(stream_t *self, uint64_t max, char *to) {
if (!self) {
return (uint64_t)-1;
}
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self; fat16_file_stream_t *ffs = (fat16_file_stream_t *)self;
uint64_t readden = fat16_read(ffs->node, ffs->offset, max > UINT32_MAX ? UINT32_MAX : (uint32_t)max, to); uint64_t readden = fat16_read(ffs->node, ffs->offset, max > UINT32_MAX ? UINT32_MAX : (uint32_t)max, to);
if (readden != (uint64_t)-1) { if (readden != (uint64_t)-1) {
@@ -669,10 +518,6 @@ static uint64_t file_stream_read(stream_t *self, uint64_t max, char *to) {
} }
static uint64_t file_stream_truncate(stream_t *self, uint64_t size) { static uint64_t file_stream_truncate(stream_t *self, uint64_t size) {
if (!self) {
return (uint64_t)-1;
}
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self; fat16_file_stream_t *ffs = (fat16_file_stream_t *)self;
uint64_t resized = fat16_truncate(ffs->node, size > UINT32_MAX ? UINT32_MAX : (uint32_t)size); uint64_t resized = fat16_truncate(ffs->node, size > UINT32_MAX ? UINT32_MAX : (uint32_t)size);
if (resized != (uint64_t)-1 && resized < ffs->offset) { if (resized != (uint64_t)-1 && resized < ffs->offset) {
@@ -682,10 +527,6 @@ static uint64_t file_stream_truncate(stream_t *self, uint64_t size) {
} }
static void file_stream_close(stream_t *self) { static void file_stream_close(stream_t *self) {
if (!self) {
return;
}
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self; fat16_file_stream_t *ffs = (fat16_file_stream_t *)self;
fat16_close(ffs->node); fat16_close(ffs->node);
memory_free(self); memory_free(self);
@@ -694,7 +535,7 @@ static void file_stream_close(stream_t *self) {
typedef struct { typedef struct {
stream_t stream; stream_t stream;
fs_node_t *node; fs_node_t *node;
uint16_t index; uint32_t index;
} fat16_directory_stream_t; } fat16_directory_stream_t;
static uint64_t directory_stream_write(__attribute__((unused)) stream_t *self, __attribute__((unused)) const char *from, static uint64_t directory_stream_write(__attribute__((unused)) stream_t *self, __attribute__((unused)) const char *from,
@@ -703,18 +544,15 @@ static uint64_t directory_stream_write(__attribute__((unused)) stream_t *self, _
} }
static uint64_t directory_stream_read(stream_t *self, uint64_t max, char *to) { static uint64_t directory_stream_read(stream_t *self, uint64_t max, char *to) {
if (!self) {
return (uint64_t)-1;
}
fat16_directory_stream_t *fds = (fat16_directory_stream_t *)self; fat16_directory_stream_t *fds = (fat16_directory_stream_t *)self;
fs_node_t *node = fat16_open_at(fds->node, fds->index++, OPEN_FILE | OPEN_DIRECTORY); fs_node_t *node = fat16_open_at(fds->node, fds->index++);
if (!node) { if (!node) {
return 0; return 0;
} }
uint64_t length = string_length(node->name); uint64_t length = string_length(node->name);
uint64_t to_read = length > max ? max : length; uint64_t to_read = length + 1 > max ? max : length + 1;
memory_copy(node->name, to_read, to); memory_copy(node->name, to_read, to);
to[to_read - 1] = '\0';
return to_read; return to_read;
} }
@@ -723,20 +561,12 @@ static uint64_t directory_stream_truncate(__attribute__((unused)) stream_t *self
} }
static void directory_stream_close(stream_t *self) { static void directory_stream_close(stream_t *self) {
if (!self) {
return;
}
fat16_directory_stream_t *fds = (fat16_directory_stream_t *)self; fat16_directory_stream_t *fds = (fat16_directory_stream_t *)self;
fat16_close(fds->node); fat16_close(fds->node);
memory_free(self); memory_free(self);
} }
stream_t *fat16_open_stream(fs_node_t *source) { stream_t *fat16_open_stream(const fs_node_t *source) {
if (!source) {
return NUL;
}
if (!source->is_dir) { if (!source->is_dir) {
fat16_file_stream_t *result = memory_allocate(sizeof(fat16_file_stream_t)); fat16_file_stream_t *result = memory_allocate(sizeof(fat16_file_stream_t));
result->stream.read = file_stream_read; result->stream.read = file_stream_read;
@@ -759,9 +589,24 @@ stream_t *fat16_open_stream(fs_node_t *source) {
} }
void fat16_close(fs_node_t *node) { void fat16_close(fs_node_t *node) {
if (!node || node->type != FAT16) { if (node->type != FAT16 || node == fs) {
return; return;
} }
inode_free(((fat16_node_t *)node)->inode);
memory_free(node);
}
node_free(node); void fat16_unmount(fs_node_t *node) {
if (node->type != FAT16 || node != fs) {
return;
}
inode_free(((fat16_node_t *)node)->inode);
memory_free(node);
if (fat) {
memory_free(fat);
fat = NUL;
}
fs = NUL;
} }
+7 -7
View File
@@ -5,15 +5,15 @@
#define FAT16 1 #define FAT16 1
fs_node_t *fat16_open_root(); fs_node_t *fat16_mount();
fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name, uint64_t flags); fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name);
fs_node_t *fat16_open_at(const fs_node_t *directory, uint16_t index, uint64_t flags); fs_node_t *fat16_open_at(const fs_node_t *directory, uint64_t index);
fs_node_t *fat16_open_again(fs_node_t *source); fs_node_t *fat16_open_again(const fs_node_t *source);
stream_t *fat16_open_stream(fs_node_t *source); stream_t *fat16_open_stream(const fs_node_t *source);
uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void *to); uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void *to);
@@ -21,6 +21,6 @@ uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_
uint64_t fat16_truncate(fs_node_t *file, uint32_t size); uint64_t fat16_truncate(fs_node_t *file, uint32_t size);
uint64_t fat16_remove(fs_node_t *file);
void fat16_close(fs_node_t *node); void fat16_close(fs_node_t *node);
void fat16_unmount(fs_node_t *fs);
+12 -12
View File
@@ -1,23 +1,23 @@
#include "src/kernel/fs.h" #include "src/kernel/fs.h"
#include "src/kernel/fat16.h" #include "src/kernel/fat16.h"
fs_node_t *fs_open_root() { fs_node_t *fs_mount() {
return fat16_open_root(); return fat16_mount();
} }
fs_node_t *fs_open_by(const fs_node_t *directory, const char *name, uint64_t flags) { fs_node_t *fs_open_by(const fs_node_t *directory, const char *name) {
return fat16_open_by(directory, name, flags); return fat16_open_by(directory, name);
} }
fs_node_t *fs_open_at(const fs_node_t *directory, uint16_t index, uint64_t flags) { fs_node_t *fs_open_at(const fs_node_t *directory, uint64_t index) {
return fat16_open_at(directory, index, flags); return fat16_open_at(directory, index);
} }
fs_node_t *fs_open_again(fs_node_t *source) { fs_node_t *fs_open_again(const fs_node_t *source) {
return fat16_open_again(source); return fat16_open_again(source);
} }
stream_t *fs_open_stream(fs_node_t *source) { stream_t *fs_open_stream(const fs_node_t *source) {
return fat16_open_stream(source); return fat16_open_stream(source);
} }
@@ -33,10 +33,10 @@ void fs_truncate(fs_node_t *file, uint32_t size) {
fat16_truncate(file, size); fat16_truncate(file, size);
} }
void fs_remove(fs_node_t *file) {
fat16_remove(file);
}
void fs_close(fs_node_t *node) { void fs_close(fs_node_t *node) {
fat16_close(node); fat16_close(node);
} }
void fs_unmount(fs_node_t *fs) {
fat16_unmount(fs);
}
+9 -10
View File
@@ -1,27 +1,26 @@
#pragma once #pragma once
#include "src/kernel/stream.h" #include "src/kernel/stream.h"
#include <stdint.h>
#define FILENAME_SIZE_LIMIT 255 #define FILENAME_SIZE_LIMIT 255
typedef struct fs_node { typedef struct fs_node {
uint8_t type;
uint32_t refs;
char name[FILENAME_SIZE_LIMIT + 1]; char name[FILENAME_SIZE_LIMIT + 1];
uint32_t size; uint32_t size;
uint8_t is_dir; uint8_t is_dir;
uint8_t removed; uint8_t type;
} fs_node_t; } fs_node_t;
fs_node_t *fs_open_root(); fs_node_t *fs_mount();
fs_node_t *fs_open_by(const fs_node_t *directory, const char *name, uint64_t flags); fs_node_t *fs_open_by(const fs_node_t *directory, const char *name);
fs_node_t *fs_open_at(const fs_node_t *directory, uint16_t index, uint64_t flags); fs_node_t *fs_open_at(const fs_node_t *directory, uint64_t index);
fs_node_t *fs_open_again(fs_node_t *source); fs_node_t *fs_open_again(const fs_node_t *source);
stream_t *fs_open_stream(fs_node_t *source); stream_t *fs_open_stream(const fs_node_t *source);
void fs_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void *to); void fs_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void *to);
@@ -29,6 +28,6 @@ void fs_write(fs_node_t *file, uint32_t offset, const void *from, uint32_t bytes
void fs_truncate(fs_node_t *file, uint32_t size); void fs_truncate(fs_node_t *file, uint32_t size);
void fs_remove(fs_node_t *file);
void fs_close(fs_node_t *node); void fs_close(fs_node_t *node);
void fs_unmount(fs_node_t *fs);
-201
View File
@@ -1,201 +0,0 @@
#include "src/kernel/log.h"
#include "src/kernel/panic.h"
#include "src/kernel/process.h"
#include "src/kernel/stream.h"
#include "src/kernel/usb.h"
#include "src/kernel/xhci.h"
#include "src/lib/memory.h"
#define USB_INTERFACE_HID_KEYBOARD_CLASS 0x3
#define USB_INTERFACE_HID_KEYBOARD_SUBCLASS 0x1
#define USB_INTERFACE_HID_KEYBOARD_PROTOCOL 0x1
#define USB_HID_BOOT_PACKET_SIZE 8
#define HID_MOD_LCTRL 0b00000001
#define HID_MOD_LSHIFT 0b00000010
#define HID_MOD_LALT 0b00000100
#define HID_MOD_RCTRL 0b00010000
#define HID_MOD_RSHIFT 0b00100000
#define HID_MOD_RALT 0b01000000
#define HID_KEY_ENTER 0x28
#define HID_KEY_BACKSPACE 0x2A
#define HID_KEY_TAB 0x2B
#define HID_KEY_HOME 0x4A
#define HID_KEY_END 0x4D
#define HID_KEY_DELETE 0x4C
#define HID_KEY_RIGHT 0x4F
#define HID_KEY_LEFT 0x50
#define HID_KEY_DOWN 0x51
#define HID_KEY_UP 0x52
// HID keycode to ASCII, index 0 = keycode 4 ('a')
static const char hid_normal[128] = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'\n', 0, '\b', '\t', ' ', '-', '=', '[', ']', '\\', 0, ';', '\'', '`', ',', '.', '/',
};
static const char hid_shifted[128] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
'\n', 0, '\b', '\t', ' ', '_', '+', '{', '}', '|', 0, ':', '"', '~', '<', '>', '?',
};
static xhci_port_t keyboard_port;
static xhci_slot_t keyboard_slot;
static xhci_endpoint_t keyboard_endpoint;
typedef uint64_t hid_report;
static hid_report prev;
#define BUFFER_SIZE 256
static char buffer[BUFFER_SIZE];
static uint16_t buffer_offset = 0;
static uint16_t buffer_length = 0;
static void append(char c) {
buffer[(buffer_offset + buffer_length) % BUFFER_SIZE] = c;
if (buffer_length < BUFFER_SIZE) {
buffer_length++;
}
}
static void append_sequence(const char *s) {
while (*s) {
append(*s);
s++;
}
}
static void on_key_pressed(uint8_t code, uint8_t modifiers) {
code -= 4;
if (code >= 128) {
return;
}
switch (code + 4) {
case HID_KEY_ENTER:
append('\n');
return;
case HID_KEY_BACKSPACE:
append('\b');
return;
case HID_KEY_TAB:
append('\t');
return;
case HID_KEY_HOME:
append_sequence(STREAM_SEQ_HOME);
return;
case HID_KEY_END:
append_sequence(STREAM_SEQ_END);
return;
case HID_KEY_DELETE:
append_sequence(STREAM_SEQ_DELETE);
return;
case HID_KEY_RIGHT:
append_sequence(STREAM_SEQ_RIGHT);
return;
case HID_KEY_LEFT:
append_sequence(STREAM_SEQ_LEFT);
return;
case HID_KEY_DOWN:
append_sequence(STREAM_SEQ_DOWN);
return;
case HID_KEY_UP:
append_sequence(STREAM_SEQ_UP);
return;
}
if (modifiers & (HID_MOD_LCTRL | HID_MOD_RCTRL)) {
if ((hid_normal[code] >= '0' && hid_normal[code] <= '9') || (hid_normal[code] >= 'a' && hid_normal[code] <= 'z')) {
append(hid_normal[code] - 'a' + 1);
}
} else if (modifiers & (HID_MOD_LALT | HID_MOD_RALT)) {
// TODO Alt combinations.
} else {
append(((modifiers & (HID_MOD_LSHIFT | HID_MOD_RSHIFT)) ? hid_shifted : hid_normal)[code]);
}
}
static uint64_t stream_write(__attribute__((unused)) stream_t *self, __attribute__((unused)) const char *from,
__attribute__((unused)) uint64_t bytes) {
return 0;
}
static uint64_t stream_read(__attribute__((unused)) stream_t *self, uint64_t max, char *to) {
while (!buffer_length) {
hid_report next;
while (xhci_read_endpoint(keyboard_slot, keyboard_endpoint, sizeof(next), &next)) {
uint8_t *prev_bytes = (uint8_t *)&prev;
uint8_t *next_bytes = (uint8_t *)&next;
if (next == prev) { // Assuming new report without changes means automatic repetition.
for (uint8_t i = 2; i < 8; i++) {
if (next_bytes[i]) {
on_key_pressed(next_bytes[i], next_bytes[0]);
}
}
} else {
for (uint8_t i = 2; i < 8; i++) {
uint8_t found = 0;
for (uint8_t j = 2; j < 8; j++) {
if (prev_bytes[j] == next_bytes[i]) {
found = 1;
break;
}
}
if (next_bytes[i] && !found) {
on_key_pressed(next_bytes[i], next_bytes[0]);
}
}
}
prev = next;
}
__asm__ volatile("sti");
process_next();
__asm__ volatile("cli");
}
uint64_t size = buffer_length > max ? max : buffer_length;
if (buffer_offset + size <= BUFFER_SIZE) {
memory_copy(buffer + buffer_offset, size, to);
} else {
uint64_t chunk_0 = BUFFER_SIZE - buffer_offset;
memory_copy(buffer + buffer_offset, chunk_0, to);
memory_copy(buffer, size - chunk_0, to + chunk_0);
}
buffer_length -= size;
buffer_offset = (buffer_offset + size) % BUFFER_SIZE;
return size;
}
static uint64_t stream_truncate(__attribute__((unused)) stream_t *self, __attribute__((unused)) uint64_t size) {
return size;
}
static void stream_close(__attribute__((unused)) stream_t *self) {
}
static stream_t stream = {stream_write, stream_read, stream_truncate, stream_close};
stream_t *hid_keyboard_init() {
LOG_LN_INFO("Searching for suitable device...");
keyboard_port =
usb_find_by_interface(USB_INTERFACE_HID_KEYBOARD_CLASS, USB_INTERFACE_HID_KEYBOARD_SUBCLASS, USB_INTERFACE_HID_KEYBOARD_PROTOCOL);
ASSERT(keyboard_port != (xhci_port_t)-1, "hid_keyboard_init: No suitable device found.");
keyboard_slot = usb_attach((uint8_t)keyboard_port);
ASSERT(keyboard_slot != (xhci_slot_t)-1, "hid_keyboard_init: Could not attach the device.");
keyboard_endpoint = usb_open_endpoint(keyboard_slot, 7, USB_HID_BOOT_PACKET_SIZE);
ASSERT(keyboard_endpoint != (xhci_endpoint_t)-1, "hid_keyboard_init: Could not open endpoint.");
LOG_LN_INFO("Done.");
return &stream;
}
-7
View File
@@ -1,7 +0,0 @@
#pragma once
#include "src/kernel/stream.h"
#include <stdint.h>
stream_t *hid_keyboard_init(); // Assuming one and only one HID device.
-4
View File
@@ -38,7 +38,3 @@ void idt_set_entry(int vector, void (*handler)(struct interrupt_frame *), uint8_
idt[vector].offset_high = (addr >> 32) & 0xFFFFFFFF; idt[vector].offset_high = (addr >> 32) & 0xFFFFFFFF;
idt[vector].zero = 0; idt[vector].zero = 0;
} }
void idt_set_entry_ec(int vector, void (*handler)(struct interrupt_frame *, uint64_t error), uint8_t flags) {
idt_set_entry(vector, (void *)handler, flags);
}
-2
View File
@@ -13,5 +13,3 @@ struct interrupt_frame {
void idt_init(); void idt_init();
void idt_set_entry(int vector, void (*handler)(struct interrupt_frame *), uint8_t flags); void idt_set_entry(int vector, void (*handler)(struct interrupt_frame *), uint8_t flags);
void idt_set_entry_ec(int vector, void (*handler)(struct interrupt_frame *, uint64_t error), uint8_t flags);
+11 -41
View File
@@ -1,26 +1,19 @@
#include "src/kernel/fs.h" #include "src/kernel/fs.h"
#include "src/kernel/gdt.h" #include "src/kernel/gdt.h"
#include "src/kernel/hid-keyboard.h"
#include "src/kernel/idt.h" #include "src/kernel/idt.h"
#include "src/kernel/log.h" #include "src/kernel/keyboard.h"
#include "src/kernel/nvme.h"
#include "src/kernel/panic.h" #include "src/kernel/panic.h"
#include "src/kernel/path.h" #include "src/kernel/path.h"
#include "src/kernel/pci.h"
#include "src/kernel/pic.h" #include "src/kernel/pic.h"
#include "src/kernel/pipe.h" #include "src/kernel/pipe.h"
#include "src/kernel/process.h" #include "src/kernel/process.h"
#include "src/kernel/stream.h"
#include "src/kernel/syscall.h" #include "src/kernel/syscall.h"
#include "src/kernel/timer.h" #include "src/kernel/timer.h"
#include "src/kernel/tss.h" #include "src/kernel/tss.h"
#include "src/kernel/usb.h"
#include "src/kernel/util.h" #include "src/kernel/util.h"
#include "src/kernel/vga.h" #include "src/kernel/vga.h"
#include "src/kernel/xhci.h"
#include "src/lib/layout.h" #include "src/lib/layout.h"
#include "src/lib/memory.h" #include "src/lib/memory.h"
#include "src/lib/syscall.h"
__attribute__((interrupt)) void isr_divide_by_zero(__attribute__((unused)) struct interrupt_frame *frame) { __attribute__((interrupt)) void isr_divide_by_zero(__attribute__((unused)) struct interrupt_frame *frame) {
vga_set_string(VGA_HEIGHT - 1, 0, "EXCEPTION: divide by zero", 0x4F); vga_set_string(VGA_HEIGHT - 1, 0, "EXCEPTION: divide by zero", 0x4F);
@@ -28,23 +21,8 @@ __attribute__((interrupt)) void isr_divide_by_zero(__attribute__((unused)) struc
; ;
} }
__attribute__((interrupt)) void isr_invalid_opcode(struct interrupt_frame *frame) { __attribute__((interrupt)) void isr_page_fault(__attribute__((unused)) struct interrupt_frame *frame) {
char msg[80]; vga_set_string(VGA_HEIGHT - 1, 0, "EXCEPTION: page fault", 0x4F);
string_format("INVALID OPCODE: ip=%x cs=%x flags=%x sp=%x", 80, msg, frame->ip, frame->cs, frame->flags, frame->sp);
vga_set_string(VGA_HEIGHT - 1, 0, msg, 0x4F);
while (1)
;
}
__attribute__((interrupt)) void isr_page_fault(__attribute__((unused)) struct interrupt_frame *frame, uint64_t error_code) {
uint64_t cr2;
__asm__ volatile("mov %%cr2, %0" : "=r"(cr2));
char msg[80];
string_format("EXCEPTION: page fault; addr=%lx err=%lx", 80, msg, cr2, error_code);
vga_set_string(VGA_HEIGHT - 1, 0, msg, 0x4F);
while (1) while (1)
; ;
} }
@@ -61,24 +39,16 @@ __attribute__((interrupt)) void isr_ata_primary(__attribute__((unused)) struct i
} }
void kernel_main() { void kernel_main() {
stream_t *vga = vga_init();
log_init(vga);
pic_init(); pic_init();
idt_init(); idt_init();
outb(0x21, inb(0x21) | 0x01); // mask out timer interrupt outb(0x21, inb(0x21) | 0x01); // mask out timer interrupt
idt_set_entry(0, isr_divide_by_zero, 0x8E); idt_set_entry(0, isr_divide_by_zero, 0x8E);
idt_set_entry(0x06, isr_invalid_opcode, 0x8E); idt_set_entry(0x0E, isr_page_fault, 0x8E);
idt_set_entry_ec(0x0E, isr_page_fault, 0x8E);
idt_set_entry(0x0D, isr_general_violation, 0x8E); idt_set_entry(0x0D, isr_general_violation, 0x8E);
idt_set_entry(46, isr_ata_primary, 0x8E); idt_set_entry(46, isr_ata_primary, 0x8E);
gdt_init(); gdt_init();
syscall_init(); syscall_init();
pci_init();
nvme_init();
xhci_init();
usb_init();
process_t *kernel = memory_allocate(sizeof(process_t)); process_t *kernel = memory_allocate(sizeof(process_t));
kernel->pml4 = (uint64_t *)KERNEL_VIRTUAL_PML4; kernel->pml4 = (uint64_t *)KERNEL_VIRTUAL_PML4;
@@ -87,16 +57,16 @@ void kernel_main() {
kernel->kernel_stack = kernel->kernel_rsp = (uint8_t *)memory_allocate(PAGE_SIZE) + PAGE_SIZE; kernel->kernel_stack = kernel->kernel_rsp = (uint8_t *)memory_allocate(PAGE_SIZE) + PAGE_SIZE;
kernel->user_stack = kernel->user_rsp = (uint8_t *)memory_allocate(PAGE_SIZE) + PAGE_SIZE; kernel->user_stack = kernel->user_rsp = (uint8_t *)memory_allocate(PAGE_SIZE) + PAGE_SIZE;
kernel->cwd = memory_allocate(sizeof(path_t)); kernel->cwd = memory_allocate(sizeof(path_t));
kernel->fds[STDIN] = hid_keyboard_init(); kernel->root = fs_mount();
kernel->fds[STDOUT] = kernel->fds[STDERR] = vga; kernel->fds[kernel->free_fd++] = keyboard_init();
kernel->free_fd = STDERR + 1; kernel->fds[kernel->free_fd++] = vga_init();
kernel->code = EXIT_CODE_OK; kernel->code = EXIT_CODE_OK;
current_process = kernel; current_process = kernel;
tss.rsp0 = (uint64_t)kernel->kernel_stack; tss.rsp0 = (uint64_t)kernel->kernel_stack;
fs_node_t *terminal_node = path_open_node(kernel->cwd, "bin/terminal", OPEN_FILE); fs_node_t *terminal_node = path_open_file(kernel->root, kernel->cwd, "bin/terminal");
fs_node_t *shell_node = path_open_node(kernel->cwd, "bin/shell", OPEN_FILE); fs_node_t *shell_node = path_open_file(kernel->root, kernel->cwd, "bin/shell");
ASSERT(terminal_node, "kernel: terminal not found"); ASSERT(terminal_node, "kernel: terminal not found");
ASSERT(shell_node, "kernel: shell not found"); ASSERT(shell_node, "kernel: shell not found");
@@ -109,10 +79,10 @@ void kernel_main() {
fs_read(shell_node, 0, shell_node->size, shell_code); fs_read(shell_node, 0, shell_node->size, shell_code);
fs_close(shell_node); fs_close(shell_node);
process_t *terminal = process_create(kernel, terminal_code, terminal_node->size, STDIN, STDOUT); process_t *terminal = process_create(kernel, terminal_code, terminal_node->size);
memory_free(terminal_code); memory_free(terminal_code);
process_t *shell = process_create(kernel, shell_code, shell_node->size, STDIN, STDOUT); process_t *shell = process_create(kernel, shell_code, shell_node->size);
memory_free(shell_code); memory_free(shell_code);
uint64_t *terminal_stack = (uint64_t *)terminal->user_stack; uint64_t *terminal_stack = (uint64_t *)terminal->user_stack;
@@ -1,4 +1,4 @@
#include "src/kernel/ps2-keyboard.h" #include "src/kernel/keyboard.h"
#include "src/kernel/idt.h" #include "src/kernel/idt.h"
#include "src/kernel/process.h" #include "src/kernel/process.h"
#include "src/kernel/stream.h" #include "src/kernel/stream.h"
@@ -158,15 +158,15 @@ static void on_key(uint8_t scancode) {
} }
} }
__attribute__((interrupt)) static void isr_ps2_keyboard(__attribute__((unused)) struct interrupt_frame *frame) { __attribute__((interrupt)) static void isr_keyboard(__attribute__((unused)) struct interrupt_frame *frame) {
uint8_t scancode = inb(0x60); uint8_t scancode = inb(0x60);
outb(0x20, 0x20); outb(0x20, 0x20);
on_key(scancode); on_key(scancode);
} }
stream_t *ps2_keyboard_init() { stream_t *keyboard_init() {
outb(0x21, inb(0x21) & ~0x02); outb(0x21, inb(0x21) & ~0x02);
idt_set_entry(33, isr_ps2_keyboard, 0x8E); idt_set_entry(33, isr_keyboard, 0x8E);
return &stream; return &stream;
} }
@@ -3,4 +3,4 @@
#include "src/kernel/stream.h" #include "src/kernel/stream.h"
#include <stdint.h> #include <stdint.h>
stream_t *ps2_keyboard_init(); stream_t *keyboard_init();
-8
View File
@@ -1,8 +0,0 @@
#include "src/kernel/log.h"
#include "src/kernel/stream.h"
stream_t *kernel_log;
void log_init(stream_t *log) {
kernel_log = log;
}
-60
View File
@@ -1,60 +0,0 @@
#pragma once
#include "src/kernel/stream.h"
#include "src/lib/string.h"
extern stream_t *kernel_log;
#ifndef LOG_LEVEL
#define LOG_LEVEL 1
#endif
#define LOG_LEVEL_INFO 1
#define LOG_LEVEL_STEP 2
#define LOG_LEVEL_DATA 3
#define LOG_LEVEL_TRACE 4
static uint64_t print_size;
static char print_buffer[512];
#define PRINT(stream, fmt, ...) \
print_size = string_format(fmt, sizeof(print_buffer) - 1, print_buffer, ##__VA_ARGS__); \
stream->write(stream, print_buffer, print_size);
#define PRINT_LN(stream, fmt, ...) \
print_size = string_format(fmt, sizeof(print_buffer) - 1, print_buffer, ##__VA_ARGS__); \
stream->write(stream, __func__, string_length(__func__)); \
stream->write(stream, ": ", 2); \
stream->write(stream, print_buffer, print_size); \
stream->write(stream, "\n", 1);
#define PRINT_VAL(stream, v, f) PRINT_LN(#v = f, v)
#define LOG(level, fmt, ...) \
if (LOG_LEVEL >= level) { \
PRINT(kernel_log, fmt, ##__VA_ARGS__) \
}
#define LOG_LN(level, fmt, ...) \
if (LOG_LEVEL >= level) { \
PRINT_LN(kernel_log, fmt, ##__VA_ARGS__) \
}
#define LOG_VAL(level, v, f) LOG_LN(level, #v "=" f, v)
#define LOG_INFO(fmt, ...) LOG(LOG_LEVEL_INFO, fmt, ##__VA_ARGS__)
#define LOG_STEP(fmt, ...) LOG(LOG_LEVEL_STEP, fmt, ##__VA_ARGS__)
#define LOG_DATA(fmt, ...) LOG(LOG_LEVEL_DATA, fmt, ##__VA_ARGS__)
#define LOG_TRACE(fmt, ...) LOG(LOG_LEVEL_TRACE, fmt, ##__VA_ARGS__)
#define LOG_LN_INFO(fmt, ...) LOG_LN(LOG_LEVEL_INFO, fmt, ##__VA_ARGS__)
#define LOG_LN_STEP(fmt, ...) LOG_LN(LOG_LEVEL_STEP, fmt, ##__VA_ARGS__)
#define LOG_LN_DATA(fmt, ...) LOG_LN(LOG_LEVEL_DATA, fmt, ##__VA_ARGS__)
#define LOG_LN_TRACE(fmt, ...) LOG_LN(LOG_LEVEL_TRACE, fmt, ##__VA_ARGS__)
#define LOG_VAL_INFO(v, f) LOG_VAL(LOG_LEVEL_INFO, v, f)
#define LOG_VAL_STEP(v, f) LOG_VAL(LOG_LEVEL_STEP, v, f)
#define LOG_VAL_DATA(v, f) LOG_VAL(LOG_LEVEL_DATA, v, f)
#define LOG_VAL_TRACE(v, f) LOG_VAL(LOG_LEVEL_TRACE, v, f)
void log_init(stream_t *log);
+1 -14
View File
@@ -1,5 +1,4 @@
#include "src/kernel/memory.h" #include "src/kernel/memory.h"
#include "src/kernel/log.h"
#include "src/kernel/panic.h" #include "src/kernel/panic.h"
#include "src/lib/layout.h" #include "src/lib/layout.h"
#include "src/lib/memory.h" #include "src/lib/memory.h"
@@ -67,10 +66,7 @@ void memory_page_map(uint64_t *pml4, void *virt, void *phys, uint64_t flags) {
const uint64_t pd_index = (ivirt >> 21) & 0x1FF; const uint64_t pd_index = (ivirt >> 21) & 0x1FF;
const uint64_t pt_index = (ivirt >> 12) & 0x1FF; const uint64_t pt_index = (ivirt >> 12) & 0x1FF;
LOG_LN_TRACE("Mapping physical %lx to virtual %lx / [%u, %u, %u, %u]...", phys, virt, pml4_index, pdpt_index, pd_index, pt_index);
if (!(pml4[pml4_index] & PAGE_PRESENT)) { if (!(pml4[pml4_index] & PAGE_PRESENT)) {
LOG_LN_TRACE("PML4 entry %u does not exist, creating...", pml4_index);
uint64_t *pdpt = memory_page_allocate(); uint64_t *pdpt = memory_page_allocate();
memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pdpt)); memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pdpt));
pml4[pml4_index] = (uint64_t)pdpt | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER; pml4[pml4_index] = (uint64_t)pdpt | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
@@ -78,30 +74,21 @@ void memory_page_map(uint64_t *pml4, void *virt, void *phys, uint64_t flags) {
uint64_t *pdpt = PHYS_TO_VIRT(pml4[pml4_index] & ~(uint64_t)0xFFF); uint64_t *pdpt = PHYS_TO_VIRT(pml4[pml4_index] & ~(uint64_t)0xFFF);
if (!(pdpt[pdpt_index] & PAGE_PRESENT)) { if (!(pdpt[pdpt_index] & PAGE_PRESENT)) {
LOG_LN_TRACE("PDPT entry %u does not exist, creating...", pdpt_index);
uint64_t *pd = memory_page_allocate(); uint64_t *pd = memory_page_allocate();
memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pd)); memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pd));
pdpt[pdpt_index] = (uint64_t)pd | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER; pdpt[pdpt_index] = (uint64_t)pd | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
} }
uint64_t *pd = PHYS_TO_VIRT(pdpt[pdpt_index] & ~(uint64_t)0xFFF); uint64_t *pd = PHYS_TO_VIRT(pdpt[pdpt_index] & ~(uint64_t)0xFFF);
ASSERT(!(pd[pd_index] & 0x80), "memory_page_map: Huge page in PD."); ASSERT(!(pd[pd_index] & 0x80), "memory_page_map: huge page in PD");
if (!(pd[pd_index] & PAGE_PRESENT)) { if (!(pd[pd_index] & PAGE_PRESENT)) {
LOG_LN_TRACE("PD entry %u does not exist, creating...", pd_index);
uint64_t *pt = memory_page_allocate(); uint64_t *pt = memory_page_allocate();
memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pt)); memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pt));
pd[pd_index] = (uint64_t)pt | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER; pd[pd_index] = (uint64_t)pt | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
} }
uint64_t *pt = PHYS_TO_VIRT(pd[pd_index] & ~(uint64_t)0xFFF); uint64_t *pt = PHYS_TO_VIRT(pd[pd_index] & ~(uint64_t)0xFFF);
ASSERT(!(pt[pt_index] & PAGE_PRESENT), "memory_page_map: Page already mapped.")
LOG_LN_TRACE("PT entry %u does not exist, creating...", pt_index);
pt[pt_index] = (uint64_t)phys | flags | PAGE_PRESENT; pt[pt_index] = (uint64_t)phys | flags | PAGE_PRESENT;
LOG_VAL_TRACE(pt[pt_index], "%lx");
LOG_LN_TRACE("Done.");
} }
void memory_page_unmap(uint64_t *pml4, void *virt) { void memory_page_unmap(uint64_t *pml4, void *virt) {
-278
View File
@@ -1,278 +0,0 @@
#include "src/kernel/nvme.h"
#include "src/kernel/log.h"
#include "src/kernel/panic.h"
#include "src/kernel/pci.h"
#include "src/lib/layout.h"
#include "src/lib/memory.h"
#include "src/lib/util.h"
#define SECTOR_SIZE 512
#define NVME_PCI_CLASS 0x01
#define NVME_PCI_SUBCLASS 0x08
typedef volatile struct __attribute__((packed)) {
uint64_t cap;
uint32_t vs;
uint32_t intms;
uint32_t intmc;
uint32_t cc;
uint32_t rsvd;
uint32_t csts;
uint32_t nssr;
uint32_t aqa;
uint64_t asq;
uint64_t acq;
} nvme_regs_t;
#define NVME_REGS_NVME_CS_SUPPORTED(r) BITS_R(r->cap, 37, 37)
#define NVME_REGS_MQES(r) BITS_R(r->cap, 15, 0)
#define NVME_REGS_IOCQES_R(r) BITS_R(r->cc, 23, 20)
#define NVME_REGS_IOCQES_W(r, v) BITS_W(r->cc, 23, 20, v)
#define NVME_REGS_IOSQES_R(r) BITS_R(r->cc, 19, 16)
#define NVME_REGS_IOSQES_W(r, v) BITS_W(r->cc, 19, 16, v)
#define NVME_REGS_CSS_R(r) BITS_R(r->cc, 6, 4)
#define NVME_REGS_CSS_W(r, v) BITS_W(r->cc, 6, 4, v)
#define NVME_REGS_EN_R(r) BITS_R(r->cc, 0, 0)
#define NVME_REGS_EN_W(r, v) BITS_W(r->cc, 0, 0, v)
#define NVME_REGS_RDY(r) BITS_R(r->csts, 0, 0)
#define NVME_REGS_ACQS_R(r) BITS_R(r->aqa, 27, 16)
#define NVME_REGS_ACQS_W(r, v) BITS_W(r->aqa, 27, 16, v)
#define NVME_REGS_ASQS_R(r) BITS_R(r->aqa, 11, 0)
#define NVME_REGS_ASQS_W(r, v) BITS_W(r->aqa, 11, 0, v)
static nvme_regs_t *regs = (nvme_regs_t *)KERNEL_VIRTUAL_NVME;
static volatile uint32_t *db_regs = (uint32_t *)(KERNEL_VIRTUAL_NVME + 0x1000); // TODO Get stride from caps.
#define QUEUE_DEPTH 2
typedef volatile struct __attribute__((packed)) {
uint8_t opc;
uint8_t flags;
uint16_t cid;
uint32_t nsid;
uint64_t reserved;
uint64_t mptr;
uint64_t prp1;
uint64_t prp2;
uint32_t cdw10;
uint32_t cdw11;
uint32_t cdw12;
uint32_t cdw13;
uint32_t cdw14;
uint32_t cdw15;
} nvme_sqe_t;
typedef volatile struct __attribute__((packed)) {
uint32_t dw0;
uint32_t reserved;
uint16_t sqhd;
uint16_t sqid;
uint16_t cid;
uint16_t status;
} nvme_cqe_t;
#define NVME_CQE_STATUS(e) BITS_R(e->status, 15, 1)
#define NVME_CQE_P(e) BITS_R(e->status, 0, 0)
static uint8_t admin_cq_phase = 1;
static nvme_sqe_t admin_sq[QUEUE_DEPTH] __attribute__((aligned(PAGE_SIZE)));
static uint16_t admin_sq_tail = 0;
static nvme_cqe_t admin_cq[QUEUE_DEPTH] __attribute__((aligned(PAGE_SIZE)));
static uint16_t admin_cq_head = 0;
static uint8_t io_cq_phase = 1;
static nvme_sqe_t io_sq[QUEUE_DEPTH] __attribute__((aligned(PAGE_SIZE)));
static uint16_t io_sq_tail = 0;
static nvme_cqe_t io_cq[QUEUE_DEPTH] __attribute__((aligned(PAGE_SIZE)));
static uint16_t io_cq_head = 0;
static void admin_exec_sync(nvme_sqe_t *cmd) {
cmd->cid = admin_sq_tail;
LOG_LN_STEP("Queueing submission...");
LOG_VAL_TRACE(cmd->opc, "%hhx");
LOG_VAL_TRACE(cmd->nsid, "%x");
LOG_VAL_TRACE(cmd->cdw10, "%x");
LOG_VAL_TRACE(cmd->cdw11, "%x");
LOG_VAL_TRACE(cmd->cdw12, "%x");
LOG_VAL_TRACE(cmd->prp1, "%lx");
LOG_VAL_TRACE(cmd->prp2, "%lx");
memory_copy(cmd, sizeof(nvme_sqe_t), &admin_sq[admin_sq_tail]);
LOG_LN_STEP("Advancing submission doorbell...");
db_regs[0] = admin_sq_tail = (admin_sq_tail + 1) % QUEUE_DEPTH;
LOG_VAL_TRACE(admin_sq_tail, "%u");
LOG_LN_STEP("Waiting for completion...");
nvme_cqe_t *cmp = &admin_cq[admin_cq_head];
while (NVME_CQE_P(cmp) != admin_cq_phase)
;
LOG_LN_STEP("Received completion...");
LOG_VAL_TRACE(cmp->dw0, "%x");
LOG_VAL_TRACE(cmp->reserved, "%x");
LOG_VAL_TRACE(cmp->sqhd, "%hx");
LOG_VAL_TRACE(cmp->sqid, "%hx");
LOG_VAL_TRACE(cmp->cid, "%hx");
LOG_VAL_TRACE(cmp->status, "%hx");
ASSERT(NVME_CQE_STATUS(cmp) == 0, "admin_exec_sync: NVMe command failed.");
LOG_LN_STEP("Advancing completion doorbell...");
db_regs[1] = admin_cq_head = (admin_cq_head + 1) % QUEUE_DEPTH;
admin_cq_phase ^= (admin_cq_head == 0);
LOG_LN_STEP("Done.");
}
static void io_exec_sync(nvme_sqe_t *cmd) {
cmd->cid = io_sq_tail;
LOG_LN_STEP("Queueing submission...");
LOG_VAL_TRACE(cmd->opc, "%hhx");
LOG_VAL_TRACE(cmd->nsid, "%x");
LOG_VAL_TRACE(cmd->cdw10, "%x");
LOG_VAL_TRACE(cmd->cdw11, "%x");
LOG_VAL_TRACE(cmd->cdw12, "%x");
LOG_VAL_TRACE(cmd->prp1, "%x");
LOG_VAL_TRACE(cmd->prp2, "%x");
memory_copy(cmd, sizeof(nvme_sqe_t), &io_sq[io_sq_tail]);
LOG_LN_STEP("Advancing submission doorbell...");
db_regs[2] = io_sq_tail = (io_sq_tail + 1) % QUEUE_DEPTH;
LOG_LN_STEP("Waiting for completion...");
nvme_cqe_t *cmp = &io_cq[io_cq_head];
while (NVME_CQE_P(cmp) != io_cq_phase)
;
LOG_LN_STEP("Received completion...");
LOG_VAL_TRACE(cmp->dw0, "%x");
LOG_VAL_TRACE(cmp->reserved, "%x");
LOG_VAL_TRACE(cmp->sqhd, "%hx");
LOG_VAL_TRACE(cmp->sqid, "%hx");
LOG_VAL_TRACE(cmp->cid, "%hx");
LOG_VAL_TRACE(cmp->status, "%hx");
ASSERT(NVME_CQE_STATUS(cmp) == 0, "io_exec_sync: NVMe command failed.");
LOG_LN_STEP("Advancing completion doorbell...");
db_regs[3] = io_cq_head = (io_cq_head + 1) % QUEUE_DEPTH;
io_cq_phase ^= (io_cq_head == 0);
LOG_LN_STEP("Done.");
}
void nvme_init() {
LOG_LN_INFO("Searching for suitable device...");
pci_bdf_t bdf = pci_find_by_class(NVME_PCI_CLASS, NVME_PCI_SUBCLASS, NUL);
ASSERT(bdf != (pci_bdf_t)-1, "nvme_init: No suitable devices found.");
LOG_LN_INFO("Mapping device to virtual memory...");
pci_map(bdf, regs, 4);
ASSERT(NVME_REGS_NVME_CS_SUPPORTED(regs), "nvme_init: NVM command set not supported.");
ASSERT(QUEUE_DEPTH <= NVME_REGS_MQES(regs), "nvme_init: Command queues are too big.")
LOG_LN_INFO("Disabling device...");
regs->cc = 0;
LOG_VAL_DATA(regs->cc, "%lx");
while (NVME_REGS_RDY(regs))
;
LOG_VAL_DATA(regs->cc, "%lx");
LOG_LN_INFO("Configuring device...");
NVME_REGS_ASQS_W(regs, QUEUE_DEPTH - 1);
regs->asq = (uint64_t)(VIRT_TO_PHYS(admin_sq));
NVME_REGS_ACQS_W(regs, QUEUE_DEPTH - 1);
regs->acq = (uint64_t)(VIRT_TO_PHYS(admin_cq));
LOG_VAL_DATA(regs->asq, "%lx");
LOG_VAL_DATA(regs->acq, "%lx");
LOG_VAL_DATA(regs->aqa, "%lx");
LOG_LN_INFO("Enabling device...");
NVME_REGS_IOCQES_W(regs, 4);
NVME_REGS_IOSQES_W(regs, 6);
NVME_REGS_CSS_W(regs, 0);
NVME_REGS_EN_W(regs, 1);
LOG_VAL_DATA(regs->cc, "%lx");
while (!NVME_REGS_RDY(regs))
;
LOG_VAL_DATA(regs->cc, "%lx");
LOG_LN_INFO("Creating I/O completion queue...");
nvme_sqe_t create_io_cq = {
.opc = 0x05,
.prp1 = (uint64_t)VIRT_TO_PHYS(io_cq),
.cdw10 = ((QUEUE_DEPTH - 1) << 16) | 1,
.cdw11 = 1,
};
admin_exec_sync(&create_io_cq);
LOG_LN_INFO("Creating I/O submission queue...");
nvme_sqe_t create_io_sq = {
.opc = 0x01,
.prp1 = (uint64_t)VIRT_TO_PHYS(io_sq),
.cdw10 = ((QUEUE_DEPTH - 1) << 16) | 1,
.cdw11 = (1 << 16) | 1,
};
admin_exec_sync(&create_io_sq);
LOG_LN_INFO("Done.");
}
void nvme_read_sectors(uint32_t index, uint8_t count, void *to) {
LOG_LN_STEP("Reading %u sectors at %u...", count, index);
while (count) {
uint64_t remainder = PAGE_SIZE - (uint64_t)to % PAGE_SIZE;
uint8_t i_count = (uint8_t)((remainder + PAGE_SIZE) / SECTOR_SIZE);
i_count = i_count > count ? count : i_count;
nvme_sqe_t read_sq = {
.opc = 0x02,
.nsid = 1,
.cdw10 = index,
.cdw11 = 0,
.cdw12 = i_count - 1,
.prp1 = (uint64_t)VIRT_TO_PHYS(to),
.prp2 = i_count * SECTOR_SIZE > remainder ? (uint64_t)VIRT_TO_PHYS(to + remainder) : 0,
};
io_exec_sync(&read_sq);
index += i_count;
count -= i_count;
to = (void *)((uint8_t *)to + i_count * SECTOR_SIZE);
}
LOG_LN_STEP("Done.");
}
void nvme_write_sectors(uint32_t index, uint8_t count, const void *from) {
LOG_LN_STEP("Writing %u sectors at %u...", count, index);
while (count) {
uint64_t remainder = PAGE_SIZE - (uint64_t)from % PAGE_SIZE;
uint8_t i_count = (uint8_t)((remainder + PAGE_SIZE) / SECTOR_SIZE);
i_count = i_count > count ? count : i_count;
nvme_sqe_t write_sq = {
.opc = 0x01,
.nsid = 1,
.cdw10 = index,
.cdw11 = 0,
.cdw12 = i_count - 1,
.prp1 = (uint64_t)VIRT_TO_PHYS(from),
.prp2 = i_count * SECTOR_SIZE > remainder ? (uint64_t)VIRT_TO_PHYS(from + remainder) : 0,
};
io_exec_sync(&write_sq);
index += i_count;
count -= i_count;
from = (void *)((uint8_t *)from + i_count * SECTOR_SIZE);
}
LOG_LN_STEP("Done.");
}
-9
View File
@@ -1,9 +0,0 @@
#pragma once
#include <stdint.h>
void nvme_init(); // Assuming one and only one NVMe device.
void nvme_read_sectors(uint32_t index, uint8_t count, void *to);
void nvme_write_sectors(uint32_t index, uint8_t count, const void *from);
+1 -1
View File
@@ -2,7 +2,7 @@
#include "src/kernel/vga.h" #include "src/kernel/vga.h"
void kernel_panic(const char *msg, __attribute__((unused)) const char *file, __attribute__((unused)) int line) { void kernel_panic(const char *msg, __attribute__((unused)) const char *file, __attribute__((unused)) int line) {
vga_set_string(VGA_HEIGHT - 1, 0, msg, 0x28); vga_set_string(0, VGA_HEIGHT - 1, msg, 0x28);
while (1) while (1)
; ;
} }
+39 -32
View File
@@ -3,14 +3,9 @@
#include "src/kernel/stream.h" #include "src/kernel/stream.h"
#include "src/lib/memory.h" #include "src/lib/memory.h"
#include "src/lib/string.h" #include "src/lib/string.h"
#include "src/lib/syscall.h"
#include "src/lib/util.h" #include "src/lib/util.h"
path_t *path_open(const path_t *base, const char *path, uint64_t flags) { path_t *path_open(const fs_node_t *root, const path_t *source, const char *path) {
if (!base || !path) {
return NUL;
}
uint64_t length = string_length(path); uint64_t length = string_length(path);
char *path_own = memory_allocate(length + 1); char *path_own = memory_allocate(length + 1);
memory_copy(path, length + 1, path_own); memory_copy(path, length + 1, path_own);
@@ -20,28 +15,21 @@ path_t *path_open(const path_t *base, const char *path, uint64_t flags) {
char *path_components[PATH_DEPTH]; char *path_components[PATH_DEPTH];
uint8_t path_length = (uint8_t)string_split(path_own, '/', PATH_DEPTH, path_components); uint8_t path_length = (uint8_t)string_split(path_own, '/', PATH_DEPTH, path_components);
if (!string_empty(path_components[0])) { if (!string_empty(path_components[0])) {
for (uint8_t i = 0; i < base->depth; i++) { for (uint8_t i = 0; i < source->depth; i++) {
result->stack[result->depth++] = fs_open_again(base->stack[i]); result->stack[result->depth++] = fs_open_again(source->stack[i]);
} }
} }
for (uint8_t i = 0; i < path_length; i++) { for (uint8_t i = 0; i < path_length; i++) {
if (!result->depth) {
result->stack[result->depth++] = fs_open_root();
}
if (string_empty(path_components[i]) || string_equal(path_components[i], ".")) { if (string_empty(path_components[i]) || string_equal(path_components[i], ".")) {
if (i == path_length - 1 && result->depth) {
// TODO Apply flags to current top of stack.
}
continue; continue;
} else if (string_equal(path_components[i], "..")) { } else if (string_equal(path_components[i], "..")) {
if (result->depth > 1) { if (result->depth) {
fs_close(result->stack[--result->depth]); fs_close(result->stack[--result->depth]);
} }
} else { } else {
fs_node_t *next = fs_open_by(result->stack[result->depth - 1], path_components[i], const fs_node_t *prev = result->depth ? result->stack[result->depth - 1] : root;
i < path_length - 1 ? (flags & ~(uint64_t)OPEN_EXCLUSIVE) | OPEN_DIRECTORY : flags); fs_node_t *next = prev->is_dir ? fs_open_by(prev, path_components[i]) : NUL;
if (!next || result->depth >= PATH_DEPTH) { if (!next || result->depth >= PATH_DEPTH) {
path_close(result); path_close(result);
memory_free(path_own); memory_free(path_own);
@@ -57,35 +45,54 @@ path_t *path_open(const path_t *base, const char *path, uint64_t flags) {
return result; return result;
} }
path_t *path_open_again(const path_t *path) { fs_node_t *path_open_node(const fs_node_t *root, const path_t *source, const char *path) {
if (!path) { path_t *p = path_open(root, source, path);
if (!p) {
return NUL; return NUL;
} }
fs_node_t *n = fs_open_again(p->depth ? p->stack[p->depth - 1] : root);
path_t *p = memory_allocate(sizeof(path_t)); path_close(p);
p->depth = path->depth; return n;
for (uint8_t i = 0; i < path->depth; i++) {
p->stack[i] = fs_open_again(path->stack[i]);
}
return p;
} }
fs_node_t *path_open_node(const path_t *base, const char *path, uint64_t flags) { fs_node_t *path_open_file(const fs_node_t *root, const path_t *source, const char *path) {
path_t *p = path_open(base, path, flags); path_t *p = path_open(root, source, path);
if (!p) { if (!p) {
return NUL; return NUL;
} }
if (!p->depth || p->stack[p->depth - 1]->is_dir) {
path_close(p);
return NUL;
}
fs_node_t *n = fs_open_again(p->stack[p->depth - 1]); fs_node_t *n = fs_open_again(p->stack[p->depth - 1]);
path_close(p); path_close(p);
return n; return n;
} }
stream_t *path_open_stream(const path_t *base, const char *path, uint64_t flags) { fs_node_t *path_open_directory(const fs_node_t *root, const path_t *source, const char *path) {
path_t *p = path_open(base, path, flags); path_t *p = path_open(root, source, path);
if (!p) { if (!p) {
return NUL; return NUL;
} }
stream_t *s = fs_open_stream(p->stack[p->depth - 1]); if (!p->depth) {
path_close(p);
return fs_open_again(root);
}
if (!p->stack[p->depth - 1]->is_dir) {
path_close(p);
return NUL;
}
fs_node_t *n = fs_open_again(p->stack[p->depth - 1]);
path_close(p);
return n;
}
stream_t *path_open_stream(const fs_node_t *root, const path_t *source, const char *path) {
path_t *p = path_open(root, source, path);
if (!p) {
return NUL;
}
stream_t *s = fs_open_stream(p->depth ? p->stack[p->depth - 1] : root);
path_close(p); path_close(p);
return s; return s;
} }
+6 -4
View File
@@ -10,12 +10,14 @@ typedef struct {
uint8_t depth; uint8_t depth;
} path_t; } path_t;
path_t *path_open(const path_t *base, const char *path, uint64_t flags); path_t *path_open(const fs_node_t *root, const path_t *source, const char *path);
path_t *path_open_again(const path_t *path); fs_node_t *path_open_node(const fs_node_t *root, const path_t *source, const char *path);
fs_node_t *path_open_node(const path_t *base, const char *path, uint64_t flags); fs_node_t *path_open_file(const fs_node_t *root, const path_t *source, const char *path);
stream_t *path_open_stream(const path_t *base, const char *path, uint64_t flags); fs_node_t *path_open_directory(const fs_node_t *root, const path_t *source, const char *path);
stream_t *path_open_stream(const fs_node_t *root, const path_t *source, const char *path);
void path_close(path_t *path); void path_close(path_t *path);
-116
View File
@@ -1,116 +0,0 @@
#include "src/kernel/pci.h"
#include "src/kernel/log.h"
#include "src/kernel/memory.h"
#include "src/kernel/panic.h"
#include "src/kernel/util.h"
#include "src/lib/layout.h"
#include "src/lib/util.h"
#define PCI_MAX_BUSES 256
#define PCI_MAX_DEVICES 32
#define PCI_MAX_FUNCTIONS 8
#define PCI_PORT_ADDRESS 0xCF8
#define PCI_PORT_DATA 0xCFC
#define PCI_BDF(b, d, f) (pci_bdf_t)(((b) << 8) | ((d) << 3) | (f))
#define PCI_B(bdf) (((bdf) >> 8) & 0xFF)
#define PCI_D(bdf) (((bdf) >> 3) & 0x1F)
#define PCI_F(bdf) ((bdf) & 0x07)
#define PCI_OFFSET_DEVICE_VENDOR 0x00
#define PCI_OFFSET_STATUS_COMMAND 0x04
#define PCI_OFFSET_CLASS_REVISION 0x08
#define PCI_OFFSET_BAR_0 0x10
#define PCI_OFFSET_BAR_1 0x14
#define PCI_VENDOR(i) BITS_R(i, 15, 0)
#define PCI_DEVICE(i) BITS_R(i, 31, 16)
#define PCI_DEVICE_EMPTY 0xFFFF
#define PCI_CLASS(c) BITS_R(c, 31, 24)
#define PCI_SUBCLASS(c) BITS_R(c, 23, 16)
#define PCI_INTERFACE(c) BITS_R(c, 15, 8)
#define PCI_COMMAND_MEMORY_SPACE 0x02
#define PCI_COMMAND_BUS_MASTER 0x04
static uint32_t pci_read(pci_bdf_t bdf, uint8_t offset) {
outl(PCI_PORT_ADDRESS, ((uint32_t)1 << 31) | ((uint32_t)bdf << 8) | (offset & 0xFC));
return inl(PCI_PORT_DATA);
}
static void pci_write(pci_bdf_t bdf, uint8_t offset, uint32_t value) {
outl(PCI_PORT_ADDRESS, ((uint32_t)1 << 31) | ((uint32_t)bdf << 8) | (offset & 0xFC));
outl(PCI_PORT_DATA, value);
}
void pci_init() {
PRINT_LN(kernel_log, "Scanning devices...");
pci_enumerate(kernel_log);
PRINT_LN(kernel_log, "Done.");
}
void pci_enumerate(stream_t *out) {
for (uint16_t b = 0; b < PCI_MAX_BUSES; b++) {
for (uint8_t d = 0; d < PCI_MAX_DEVICES; d++) {
for (uint8_t f = 0; f < PCI_MAX_FUNCTIONS; f++) {
uint32_t id = pci_read(PCI_BDF(b, d, f), PCI_OFFSET_DEVICE_VENDOR);
if (PCI_DEVICE(id) == PCI_DEVICE_EMPTY) {
continue;
}
uint32_t class = pci_read(PCI_BDF(b, d, f), PCI_OFFSET_CLASS_REVISION);
PRINT_LN(out, "%hx:%hx class=%hhx subclass=%hhx iface=%hhx.", PCI_VENDOR(id), PCI_DEVICE(id), PCI_CLASS(class), PCI_SUBCLASS(class),
PCI_INTERFACE(class));
}
}
}
}
pci_bdf_t pci_find_by_class(uint8_t class, uint8_t subclass, uint8_t iface) {
for (uint16_t b = 0; b < PCI_MAX_BUSES; b++) {
for (uint8_t d = 0; d < PCI_MAX_DEVICES; d++) {
for (uint8_t f = 0; f < PCI_MAX_FUNCTIONS; f++) {
uint32_t id = pci_read(PCI_BDF(b, d, f), PCI_OFFSET_DEVICE_VENDOR);
if (PCI_DEVICE(id) == PCI_DEVICE_EMPTY) {
continue;
}
uint32_t csi = pci_read(PCI_BDF(b, d, f), PCI_OFFSET_CLASS_REVISION);
if ((class != NUL && PCI_CLASS(csi) != class) || (subclass != NUL && PCI_SUBCLASS(csi) != subclass) ||
(iface != NUL && PCI_INTERFACE(csi) != iface)) {
continue;
}
return PCI_BDF(b, d, f);
}
}
}
return (pci_bdf_t)-1;
}
void pci_map(pci_bdf_t bdf, volatile void *virt, uint8_t pages) {
ASSERT(bdf != (pci_bdf_t)-1, "pci_map: Invalid BDF.");
pci_write(bdf, PCI_OFFSET_STATUS_COMMAND, pci_read(bdf, PCI_OFFSET_STATUS_COMMAND) | PCI_COMMAND_MEMORY_SPACE | PCI_COMMAND_BUS_MASTER);
uint64_t bar = ((uint64_t)pci_read(bdf, PCI_OFFSET_BAR_1) << 32) | (pci_read(bdf, PCI_OFFSET_BAR_0) & 0xFFFFFFF0);
LOG_LN_STEP("Mapping BAR to memory, phys %lx <-> virt %lx...", bar, virt);
for (uint8_t i = 0; i < pages; i++) {
memory_page_map((void *)KERNEL_VIRTUAL_PML4, (void *)((uint8_t *)virt + i * PAGE_SIZE), (void *)((uint8_t *)bar + i * PAGE_SIZE),
PAGE_WRITABLE | PAGE_PCD | PAGE_USER);
}
}
void pci_unmap(pci_bdf_t bdf, volatile void *virt, uint8_t pages) {
ASSERT(bdf != (pci_bdf_t)-1, "pci_unmap: Invalid BDF.");
LOG_LN_STEP("Unmapping BAR from memory, virt %lx...", virt);
for (uint8_t i = 0; i < pages; i++) {
memory_page_unmap((void *)KERNEL_VIRTUAL_PML4, (void *)((uint8_t *)virt + i * PAGE_SIZE));
}
pci_write(bdf, PCI_OFFSET_STATUS_COMMAND,
pci_read(bdf, PCI_OFFSET_STATUS_COMMAND) & ~(uint32_t)(PCI_COMMAND_MEMORY_SPACE | PCI_COMMAND_BUS_MASTER));
}
-15
View File
@@ -1,15 +0,0 @@
#pragma once
#include "src/kernel/stream.h"
typedef uint16_t pci_bdf_t;
void pci_init();
void pci_enumerate(stream_t *out);
pci_bdf_t pci_find_by_class(uint8_t class, uint8_t subclass, uint8_t iface);
void pci_map(pci_bdf_t bdf, volatile void *virt, uint8_t pages);
void pci_unmap(pci_bdf_t bdf, volatile void *virt, uint8_t pages);
+13 -11
View File
@@ -14,7 +14,7 @@ static uint64_t free_pid = 1;
process_t *current_process; process_t *current_process;
process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t size, uint64_t stdin, uint64_t stdout) { process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t size) {
if (size >= USER_VIRTUAL_HEAP - USER_VIRTUAL_CODE) { if (size >= USER_VIRTUAL_HEAP - USER_VIRTUAL_CODE) {
return NUL; return NUL;
} }
@@ -29,10 +29,6 @@ process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t
return NUL; return NUL;
} }
if (stdin >= MAX_FDS || !parent->fds[stdin] || stdout > MAX_FDS || !parent->fds[stdout]) {
return NUL;
}
process_t *proc = processes[free_pi] = memory_allocate(sizeof(process_t)); process_t *proc = processes[free_pi] = memory_allocate(sizeof(process_t));
proc->parent = parent; proc->parent = parent;
@@ -72,13 +68,19 @@ process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t
PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER); PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
} }
path_t *cwd = memory_allocate(sizeof(path_t));
cwd->depth = parent->cwd->depth;
for (uint8_t i = 0; i < parent->cwd->depth; i++) {
cwd->stack[i] = fs_open_again(parent->cwd->stack[i]);
}
proc->pid = free_pid++; proc->pid = free_pid++;
proc->state = PROCESS_RUNNING; proc->state = PROCESS_RUNNING;
proc->cwd = path_open_again(parent->cwd); proc->cwd = cwd;
proc->fds[STDIN] = parent->fds[stdin]; proc->root = parent->root;
proc->fds[STDOUT] = parent->fds[stdout]; proc->fds[0] = parent->fds[0];
proc->fds[STDERR] = parent->fds[STDERR]; proc->fds[1] = parent->fds[1];
proc->free_fd = STDERR + 1; proc->free_fd = 2;
proc->code = EXIT_CODE_OK; proc->code = EXIT_CODE_OK;
return proc; return proc;
@@ -130,7 +132,7 @@ void process_next() {
} }
void process_destroy(process_t *proc) { void process_destroy(process_t *proc) {
for (uint64_t i = STDERR + 1; i < MAX_FDS; i++) { for (uint64_t i = 2; i < MAX_FDS; i++) {
if (proc->fds[i]) { if (proc->fds[i]) {
proc->fds[i]->close(proc->fds[i]); proc->fds[i]->close(proc->fds[i]);
proc->fds[i] = NUL; proc->fds[i] = NUL;
+3 -1
View File
@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "src/kernel/fs.h"
#include "src/kernel/path.h" #include "src/kernel/path.h"
#include "src/kernel/stream.h" #include "src/kernel/stream.h"
#include "src/lib/util.h" #include "src/lib/util.h"
@@ -24,6 +25,7 @@ typedef struct process {
uint64_t pid; uint64_t pid;
process_state_t state; process_state_t state;
uint64_t waiting_for; uint64_t waiting_for;
const fs_node_t *root;
const path_t *cwd; const path_t *cwd;
stream_t *fds[MAX_FDS]; stream_t *fds[MAX_FDS];
uint64_t free_fd; uint64_t free_fd;
@@ -36,7 +38,7 @@ extern process_t *current_process;
extern void process_trampoline(); extern void process_trampoline();
process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t size, uint64_t stdin, uint64_t stdout); process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t size);
process_t *process_get(uint64_t pid); process_t *process_get(uint64_t pid);
-1
View File
@@ -28,7 +28,6 @@ syscall_entry:
push r14 push r14
push r15 push r15
mov r9, r8 ; arg5
mov r8, r10 ; arg4 mov r8, r10 ; arg4
mov rcx, rdx ; arg3 mov rcx, rdx ; arg3
mov rdx, rsi ; arg2 mov rdx, rsi ; arg2
+14 -32
View File
@@ -2,13 +2,11 @@
#include "src/kernel/fs.h" #include "src/kernel/fs.h"
#include "src/kernel/gdt.h" #include "src/kernel/gdt.h"
#include "src/kernel/path.h" #include "src/kernel/path.h"
#include "src/kernel/pipe.h"
#include "src/kernel/process.h" #include "src/kernel/process.h"
#include "src/kernel/stream.h" #include "src/kernel/stream.h"
#include "src/lib/layout.h" #include "src/lib/layout.h"
#include "src/lib/memory.h" #include "src/lib/memory.h"
#include "src/lib/string.h" #include "src/lib/string.h"
#include "src/lib/syscall.h"
#include "src/lib/util.h" #include "src/lib/util.h"
#define MSR_EFER 0xC0000080 #define MSR_EFER 0xC0000080
@@ -81,17 +79,22 @@ static uint64_t getcwd(uint64_t max, char *to) {
} }
static uint64_t chdir(const char *path) { static uint64_t chdir(const char *path) {
path_t *cwd = path_open(current_process->cwd, path, OPEN_DIRECTORY); path_t *cwd = path_open(current_process->root, current_process->cwd, path);
if (!cwd) { if (!cwd) {
return (uint64_t)-1; return (uint64_t)-1;
} }
if (!cwd->depth || !cwd->stack[cwd->depth - 1]->is_dir) {
path_close(cwd);
return (uint64_t)-1;
}
path_close((path_t *)current_process->cwd); path_close((path_t *)current_process->cwd);
current_process->cwd = cwd; current_process->cwd = cwd;
return current_process->cwd->depth; return current_process->cwd->depth;
} }
static uint64_t spawn(const char *path, uint64_t argc, const char **argv, uint64_t stdin, uint64_t stdout) { static uint64_t spawn(const char *path, uint64_t argc, const char **argv) {
fs_node_t *node = path_open_node(current_process->cwd, path, OPEN_FILE); fs_node_t *node = path_open_file(current_process->root, current_process->cwd, path);
if (!node) { if (!node) {
return EXIT_CODE_NOT_FOUND; return EXIT_CODE_NOT_FOUND;
} }
@@ -110,7 +113,7 @@ static uint64_t spawn(const char *path, uint64_t argc, const char **argv, uint64
memory_copy(argv[i], sizes[i], blob + offsets[i]); memory_copy(argv[i], sizes[i], blob + offsets[i]);
} }
process_t *child = process_create(current_process, bin, node->size, stdin, stdout); process_t *child = process_create(current_process, bin, node->size);
memory_free(bin); memory_free(bin);
fs_close(node); fs_close(node);
@@ -158,11 +161,11 @@ static exit_code_t wait(uint64_t pid) {
return code; return code;
} }
static uint64_t open(const char *path, uint64_t flags) { static uint64_t open(const char *path) {
if (current_process->free_fd >= MAX_FDS) { if (current_process->free_fd >= MAX_FDS) {
return (uint64_t)-1; return (uint64_t)-1;
} }
stream_t *stream = path_open_stream(current_process->cwd, path, flags); stream_t *stream = path_open_stream(current_process->root, current_process->cwd, path);
if (!stream) { if (!stream) {
return (uint64_t)-1; return (uint64_t)-1;
} }
@@ -186,23 +189,6 @@ static uint64_t truncate(uint64_t fd, uint64_t size) {
return current_process->fds[fd]->truncate(current_process->fds[fd], size); return current_process->fds[fd]->truncate(current_process->fds[fd], size);
} }
static uint64_t remove(const char *path) {
fs_node_t *node = path_open_node(current_process->cwd, path, OPEN_FILE | OPEN_DIRECTORY);
fs_remove(node);
fs_close(node);
return 0;
}
static uint64_t pipe(uint64_t *write_fd, uint64_t *read_fd) {
if (current_process->free_fd + 2 >= MAX_FDS) {
return (uint64_t)-1;
}
*write_fd = current_process->free_fd++;
*read_fd = current_process->free_fd++;
pipe_init(&current_process->fds[*write_fd], &current_process->fds[*read_fd]);
return 0;
}
static void exit(exit_code_t code) { static void exit(exit_code_t code) {
current_process->state = PROCESS_ZOMBIE; current_process->state = PROCESS_ZOMBIE;
current_process->code = code; current_process->code = code;
@@ -217,7 +203,7 @@ static void exit(exit_code_t code) {
process_next(); process_next();
} }
uint64_t syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) { uint64_t syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t arg3, __attribute__((unused)) uint64_t arg4) {
switch (func) { switch (func) {
case SYSCALL_READ: case SYSCALL_READ:
return read(arg1, arg2, (char *)arg3); return read(arg1, arg2, (char *)arg3);
@@ -228,19 +214,15 @@ uint64_t syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t
case SYSCALL_CHDIR: case SYSCALL_CHDIR:
return chdir((const char *)arg1); return chdir((const char *)arg1);
case SYSCALL_SPAWN: case SYSCALL_SPAWN:
return spawn((const char *)arg1, arg2, (const char **)arg3, arg4, arg5); return spawn((const char *)arg1, arg2, (const char **)arg3);
case SYSCALL_WAIT: case SYSCALL_WAIT:
return wait(arg1); return wait(arg1);
case SYSCALL_OPEN: case SYSCALL_OPEN:
return open((const char *)arg1, arg2); return open((const char *)arg1);
case SYSCALL_CLOSE: case SYSCALL_CLOSE:
return close(arg1); return close(arg1);
case SYSCALL_TRUNCATE: case SYSCALL_TRUNCATE:
return truncate(arg1, arg2); return truncate(arg1, arg2);
case SYSCALL_REMOVE:
return remove((char *)arg1);
case SYSCALL_PIPE:
return pipe((uint64_t *)arg1, (uint64_t *)arg2);
case SYSCALL_EXIT: case SYSCALL_EXIT:
exit(arg1); exit(arg1);
return 0; return 0;
+12 -1
View File
@@ -2,6 +2,17 @@
#include <stdint.h> #include <stdint.h>
#define SYSCALL_READ 0
#define SYSCALL_WRITE 1
#define SYSCALL_GETCWD 2
#define SYSCALL_CHDIR 3
#define SYSCALL_SPAWN 4
#define SYSCALL_WAIT 5
#define SYSCALL_OPEN 6
#define SYSCALL_CLOSE 7
#define SYSCALL_TRUNCATE 8
#define SYSCALL_EXIT 60
void syscall_init(); void syscall_init();
uint64_t syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5); uint64_t syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4);
-274
View File
@@ -1,274 +0,0 @@
#include "src/kernel/usb.h"
#include "src/kernel/log.h"
#include "src/kernel/panic.h"
#include "src/kernel/stream.h"
#include "src/kernel/xhci.h"
#include "src/lib/layout.h"
#include "src/lib/memory.h"
#include "src/lib/util.h"
typedef struct __attribute__((packed)) {
uint8_t bm_request_type;
uint8_t b_request;
uint16_t w_value;
uint16_t w_index;
uint16_t w_length;
} usb_setup_t;
#define USB_SETUP_DIRECTION_R(s) BITS_R((s)->bm_request_type, 7, 7)
#define USB_SETUP_DIRECTION_W(s, v) BITS_W((s)->bm_request_type, 7, 7, v)
#define USB_SETUP_TYPE_R(s) BITS_R((s)->bm_request_type, 6, 5)
#define USB_SETUP_TYPE_W(s, v) BITS_W((s)->bm_request_type, 6, 5, v)
#define USB_SETUP_RECIPIENT_R(s) BITS_R((s)->bm_request_type, 4, 0)
#define USB_SETUP_RECIPIENT_W(s, v) BITS_W((s)->bm_request_type, 4, 0, v)
#define USB_SETUP_DIRECTION_H2D 0
#define USB_SETUP_DIRECTION_D2H 1
#define USB_SETUP_TYPE_STANDARD 0
#define USB_SETUP_TYPE_CLASS 1
#define USB_SETUP_TYPE_VENDOR 2
#define USB_SETUP_RECIPIENT_DEVICE 0
#define USB_SETUP_RECIPIENT_INTERFACE 1
#define USB_SETUP_RECIPIENT_ENDPOINT 2
#define USB_SETUP_RECIPIENT_OTHER 3
#define USB_SETUP_GET_DESCRIPTOR 0x06
#define USB_SETUP_SET_CONFIGURATION 0x09
#define USB_SETUP_SET_IDLE 0x0A
#define USB_SETUP_SET_PROTOCOL 0x0B
#define USB_SETUP_DESCRIPTOR_TYPE_R(s) BITS_R((s)->w_value, 15, 8)
#define USB_SETUP_DESCRIPTOR_TYPE_W(s, v) BITS_W((s)->w_value, 15, 8, v)
#define USB_SETUP_DESCRIPTOR_INDEX_R(s) BITS_R((s)->w_value, 7, 0)
#define USB_SETUP_DESCRIPTOR_INDEX_W(s, v) BITS_W((s)->w_value, 7, 0, v)
typedef struct __attribute__((packed)) {
uint8_t length;
uint8_t descriptor_type;
} usb_descriptor_base_t;
#define USB_DESCRIPTOR_TYPE_DEVICE 0x01
#define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02
#define USB_DESCRIPTOR_TYPE_INTERFACE 0x04
#define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05
typedef struct __attribute__((packed)) {
usb_descriptor_base_t base;
uint16_t usb_version;
uint8_t device_class;
uint8_t device_subclass;
uint8_t device_protocol;
uint8_t max_packet_size;
uint16_t vendor_id;
uint16_t product_id;
uint16_t device_version;
uint8_t manufacturer_str;
uint8_t product_str;
uint8_t serial_str;
uint8_t num_configurations;
} usb_device_descriptor_t;
typedef struct __attribute__((packed)) {
usb_descriptor_base_t base;
uint16_t total_length;
uint8_t num_interfaces;
uint8_t configuration_value;
uint8_t configuration_str;
uint8_t attributes;
uint8_t max_power;
} usb_configuration_descriptor_t;
typedef struct __attribute__((packed)) {
usb_descriptor_base_t base;
uint8_t interface_number;
uint8_t alternate_setting;
uint8_t num_endpoints;
uint8_t interface_class;
uint8_t interface_subclass;
uint8_t interface_protocol;
uint8_t interface_str;
} usb_interface_descriptor_t;
typedef struct __attribute__((packed)) {
usb_descriptor_base_t base;
uint8_t endpoint_address;
uint8_t attributes;
uint16_t max_packet_size;
uint8_t interval;
} usb_endpoint_descriptor_t;
typedef struct __attribute__((packed)) {
usb_descriptor_base_t base;
uint16_t hid_version;
uint8_t country_code;
uint8_t num_descriptors;
uint8_t report_descriptor_type;
uint16_t report_descriptor_length;
} usb_hid_descriptor_t;
static uint8_t descriptor_buffer[PAGE_SIZE] __attribute__((aligned(64)));
static void scan_device(xhci_slot_t slot, usb_device_descriptor_t *device, usb_configuration_descriptor_t *configuration,
usb_interface_descriptor_t *interface, usb_endpoint_descriptor_t *endpoint) {
memory_set(0, sizeof(usb_device_descriptor_t), device);
memory_set(0, sizeof(usb_configuration_descriptor_t), configuration);
memory_set(0, sizeof(usb_interface_descriptor_t), interface);
memory_set(0, sizeof(usb_endpoint_descriptor_t), endpoint);
usb_setup_t setup;
memory_set(0, sizeof(setup), &setup);
USB_SETUP_DIRECTION_W(&setup, USB_SETUP_DIRECTION_D2H);
setup.b_request = USB_SETUP_GET_DESCRIPTOR;
USB_SETUP_DESCRIPTOR_TYPE_W(&setup, USB_DESCRIPTOR_TYPE_DEVICE);
setup.w_length = sizeof(usb_device_descriptor_t);
memory_set(0, sizeof(descriptor_buffer), descriptor_buffer);
xhci_control_transfer(slot, *(uint64_t *)&setup, &descriptor_buffer, setup.w_length);
memory_copy(descriptor_buffer, sizeof(usb_device_descriptor_t), device);
memory_set(0, sizeof(setup), &setup);
USB_SETUP_DIRECTION_W(&setup, USB_SETUP_DIRECTION_D2H);
setup.b_request = USB_SETUP_GET_DESCRIPTOR;
USB_SETUP_DESCRIPTOR_TYPE_W(&setup, USB_DESCRIPTOR_TYPE_CONFIGURATION);
setup.w_length = sizeof(usb_configuration_descriptor_t);
memory_set(0, sizeof(descriptor_buffer), descriptor_buffer);
xhci_control_transfer(slot, *(uint64_t *)&setup, &descriptor_buffer, setup.w_length);
memory_set(0, sizeof(setup), &setup);
USB_SETUP_DIRECTION_W(&setup, USB_SETUP_DIRECTION_D2H);
setup.b_request = USB_SETUP_GET_DESCRIPTOR;
USB_SETUP_DESCRIPTOR_TYPE_W(&setup, USB_DESCRIPTOR_TYPE_CONFIGURATION);
setup.w_length = ((usb_configuration_descriptor_t *)&descriptor_buffer)->total_length;
memory_set(0, sizeof(descriptor_buffer), descriptor_buffer);
xhci_control_transfer(slot, *(uint64_t *)&setup, &descriptor_buffer, setup.w_length);
usb_descriptor_base_t *descriptor = (usb_descriptor_base_t *)&descriptor_buffer;
while (descriptor->descriptor_type) { // Assuming `descriptor_buffer` longer than any potential descriptor set.
if (descriptor->descriptor_type == USB_DESCRIPTOR_TYPE_CONFIGURATION && !configuration->base.descriptor_type) {
memory_copy(descriptor, sizeof(usb_configuration_descriptor_t), configuration);
}
if (descriptor->descriptor_type == USB_DESCRIPTOR_TYPE_INTERFACE && !interface->base.descriptor_type) {
memory_copy(descriptor, sizeof(usb_interface_descriptor_t), interface);
}
if (descriptor->descriptor_type == USB_DESCRIPTOR_TYPE_ENDPOINT && !endpoint->base.descriptor_type) {
memory_copy(descriptor, sizeof(usb_endpoint_descriptor_t), endpoint);
}
descriptor = (usb_descriptor_base_t *)((uint8_t *)descriptor + descriptor->length);
}
}
void usb_init() {
PRINT_LN(kernel_log, "Enumerating devices...");
usb_enumerate(kernel_log);
PRINT_LN(kernel_log, "Done.");
}
void usb_enumerate(stream_t *out) {
for (xhci_port_t port = 0; port < xhci_port_count(); port++) {
if (!xhci_port_connected(port)) {
continue;
}
xhci_slot_t slot = xhci_attach(port);
if (slot == (xhci_slot_t)-1) {
continue;
}
usb_device_descriptor_t device;
usb_configuration_descriptor_t configuration;
usb_interface_descriptor_t interface;
usb_endpoint_descriptor_t endpoint;
scan_device(slot, &device, &configuration, &interface, &endpoint);
xhci_detach(slot);
PRINT_LN(
out,
"%hx:%hx usb_version=%hx device_class=%hhx device_subclass=%hhx device_protocol=%hhx interface_class=%hhx interface_subclass=%hhx "
"interface_protocol=%hhx endpoint_address=%hhx max_packet_size=%hx interval=%hhx",
device.vendor_id, device.product_id, device.usb_version, device.device_class, device.device_subclass, device.device_protocol,
interface.interface_class, interface.interface_subclass, interface.interface_protocol, endpoint.endpoint_address,
endpoint.max_packet_size, endpoint.interval);
}
}
xhci_port_t usb_find_by_interface(uint8_t class, uint8_t subclass, uint8_t protocol) {
for (xhci_port_t port = 0; port < xhci_port_count(); port++) {
if (!xhci_port_connected(port)) {
continue;
}
xhci_slot_t slot = xhci_attach(port);
if (slot == (xhci_slot_t)-1) {
continue;
}
usb_device_descriptor_t device;
usb_configuration_descriptor_t configuration;
usb_interface_descriptor_t interface;
usb_endpoint_descriptor_t endpoint;
scan_device(slot, &device, &configuration, &interface, &endpoint);
xhci_detach(slot);
if ((class == NUL || interface.interface_class == class) && (subclass == NUL || interface.interface_subclass == subclass) &&
(protocol == NUL || interface.interface_protocol == protocol)) {
return port;
}
}
return (xhci_port_t)-1;
}
xhci_slot_t usb_attach(xhci_port_t port) {
return xhci_attach(port);
}
xhci_endpoint_t usb_open_endpoint(xhci_slot_t slot, uint8_t type, uint16_t max_packet_size) {
usb_device_descriptor_t device;
usb_configuration_descriptor_t configuration;
usb_interface_descriptor_t interface;
usb_endpoint_descriptor_t endpoint;
scan_device(slot, &device, &configuration, &interface, &endpoint);
usb_setup_t setup;
memory_set(0, sizeof(setup), &setup);
USB_SETUP_DIRECTION_W(&setup, USB_SETUP_DIRECTION_H2D);
USB_SETUP_TYPE_W(&setup, USB_SETUP_TYPE_STANDARD);
USB_SETUP_RECIPIENT_W(&setup, USB_SETUP_RECIPIENT_DEVICE);
setup.b_request = USB_SETUP_SET_CONFIGURATION;
setup.w_value = configuration.configuration_value;
xhci_control_transfer(slot, *(uint64_t *)&setup, NUL, 0);
memory_set(0, sizeof(setup), &setup);
USB_SETUP_DIRECTION_W(&setup, USB_SETUP_DIRECTION_H2D);
USB_SETUP_TYPE_W(&setup, USB_SETUP_TYPE_CLASS);
USB_SETUP_RECIPIENT_W(&setup, USB_SETUP_RECIPIENT_INTERFACE);
setup.b_request = USB_SETUP_SET_PROTOCOL;
xhci_control_transfer(slot, *(uint64_t *)&setup, NUL, 0);
memory_set(0, sizeof(setup), &setup);
USB_SETUP_DIRECTION_W(&setup, USB_SETUP_DIRECTION_H2D);
USB_SETUP_TYPE_W(&setup, USB_SETUP_TYPE_CLASS);
USB_SETUP_RECIPIENT_W(&setup, USB_SETUP_RECIPIENT_INTERFACE);
setup.b_request = USB_SETUP_SET_IDLE;
xhci_control_transfer(slot, *(uint64_t *)&setup, NUL, 0);
ASSERT(endpoint.max_packet_size == max_packet_size, "usb_open_endpoint: Unexpected max packet size.");
return xhci_open_endpoint(slot, endpoint.endpoint_address, type, endpoint.max_packet_size, 7);
}
uint16_t usb_read_endpoint(xhci_slot_t slot, xhci_endpoint_t endpoint, uint16_t max, void *to) {
return xhci_read_endpoint(slot, endpoint, max, to);
}
void usb_close_endpoint(xhci_slot_t slot, xhci_endpoint_t endpoint) {
return xhci_close_endpoint(slot, endpoint);
}
void usb_detach(xhci_slot_t slot) {
return xhci_detach(slot);
}
-21
View File
@@ -1,21 +0,0 @@
#pragma once
#include "src/kernel/stream.h"
#include "src/kernel/xhci.h"
#include <stdint.h>
void usb_init();
void usb_enumerate(stream_t *out);
xhci_port_t usb_find_by_interface(uint8_t class, uint8_t subclass, uint8_t protocol);
xhci_slot_t usb_attach(xhci_port_t port);
xhci_endpoint_t usb_open_endpoint(xhci_slot_t slot, uint8_t type, uint16_t max_packet_size);
uint16_t usb_read_endpoint(xhci_slot_t slot, xhci_endpoint_t endpoint, uint16_t max, void *to);
void usb_close_endpoint(xhci_slot_t slot, xhci_endpoint_t endpoint);
void usb_detach(xhci_slot_t slot);
-10
View File
@@ -22,16 +22,6 @@ static inline void outw(uint16_t port, uint16_t value) {
__asm__ volatile("outw %0, %1" : : "a"(value), "Nd"(port)); __asm__ volatile("outw %0, %1" : : "a"(value), "Nd"(port));
} }
static inline uint32_t inl(uint16_t port) {
uint32_t value;
__asm__ volatile("inl %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
static inline void outl(uint16_t port, uint32_t value) {
__asm__ volatile("outl %0, %1" : : "a"(value), "Nd"(port));
}
static inline void insw(uint16_t port, void *to, uint32_t count) { static inline void insw(uint16_t port, void *to, uint32_t count) {
__asm__ volatile("rep insw" : "=D"(to), "=c"(count) : "d"(port), "D"(to), "c"(count) : "memory"); __asm__ volatile("rep insw" : "=D"(to), "=c"(count) : "d"(port), "D"(to), "c"(count) : "memory");
} }
-2
View File
@@ -172,10 +172,8 @@ stream_t *vga_init() {
void vga_set_string(uint8_t row, uint8_t col, const char *str, uint8_t c) { void vga_set_string(uint8_t row, uint8_t col, const char *str, uint8_t c) {
ASSERT(row < VGA_HEIGHT && col < VGA_WIDTH, "vga_set_string: invalid coordinates") ASSERT(row < VGA_HEIGHT && col < VGA_WIDTH, "vga_set_string: invalid coordinates")
color = (uint16_t)((uint16_t)c << 8); color = (uint16_t)((uint16_t)c << 8);
uint16_t prev_offset = offset;
offset = row * VGA_WIDTH + col; offset = row * VGA_WIDTH + col;
while (*str) { while (*str) {
on_char_received(*str++); on_char_received(*str++);
} }
offset = prev_offset;
} }
-693
View File
@@ -1,693 +0,0 @@
#include "src/kernel/xhci.h"
#include "src/kernel/log.h"
#include "src/kernel/memory.h"
#include "src/kernel/panic.h"
#include "src/kernel/pci.h"
#include "src/kernel/stream.h"
#include "src/lib/layout.h"
#include "src/lib/memory.h"
#include "src/lib/util.h"
#define XHCI_PCI_CLASS 0x0C
#define XHCI_PCI_SUBCLASS 0x03
#define XHCI_PCI_INTERFACE 0x30
typedef volatile struct __attribute__((packed)) {
uint8_t caplength;
uint8_t reserved;
uint16_t hciversion;
uint32_t hcsparams1;
uint32_t hcsparams2;
uint32_t hcsparams3;
uint32_t hccparams1;
uint32_t dboff;
uint32_t rtsoff;
uint32_t hccparams2;
} xhci_cap_regs_t;
#define XHCI_CAP_REGS_MAX_SLOTS(c) BITS_R((c)->hcsparams1, 7, 0)
#define XHCI_CAP_REGS_MAX_INTRS(c) BITS_R((c)->hcsparams1, 18, 8)
#define XHCI_CAP_REGS_MAX_PORTS(c) BITS_R((c)->hcsparams1, 31, 24)
#define XHCI_CAP_REGS_MAX_ERSTS(c) BITS_R((c)->hcsparams2, 7, 4)
#define XHCI_CAP_REGS_MAX_SCRATCHPAD_BUFFERS(c) (BITS_R((c)->hcsparams2, 31, 27) << 5 | BITS_R((c)->hcsparams2, 4, 0))
typedef volatile struct __attribute__((packed)) {
uint32_t usbcmd;
uint32_t usbsts;
uint32_t pagesize;
uint32_t reserved[2];
uint32_t dnctrl;
uint64_t crcr;
uint32_t reserved2[4];
uint64_t dcbaap;
uint32_t config;
} xhci_op_regs_t;
#define XHCI_OP_REGS_RS_R(o) BITS_R((o)->usbcmd, 0, 0)
#define XHCI_OP_REGS_RS_W(o, v) BITS_W((o)->usbcmd, 0, 0, v)
#define XHCI_OP_REGS_HCRST_R(o) BITS_R((o)->usbcmd, 1, 1)
#define XHCI_OP_REGS_HCRST_W(o, v) BITS_W((o)->usbcmd, 1, 1, v)
#define XHCI_OP_REGS_HCH(o) BITS_R((o)->usbsts, 0, 0)
#define XHCI_OP_REGS_HSE(o) BITS_R((o)->usbsts, 2, 2)
#define XHCI_OP_REGS_EINT_R(o) BITS_R((o)->usbsts, 3, 3)
#define XHCI_OP_REGS_EINT_W(o, v) BITS_W((o)->usbsts, 3, 3, v)
#define XHCI_OP_REGS_CNR(o) BITS_R((o)->usbsts, 11, 11)
#define XHCI_OP_REGS_HCE(o) BITS_R((o)->usbsts, 12, 12)
#define XHCI_OP_REGS_RCS(o) BITS_R((o)->crcr, 0, 0)
#define XHCI_OP_REGS_CRR(o) BITS_R((o)->crcr, 3, 3)
#define XHCI_OP_REGS_CRP(o) BITS_R((o)->crcr, 63, 6)
#define XHCI_OP_REGS_MAX_SLOTS_EN_R(o) BITS_R((o)->config, 7, 0)
#define XHCI_OP_REGS_MAX_SLOTS_EN_W(o, v) BITS_W((o)->config, 7, 0, v)
typedef volatile struct __attribute__((packed)) {
uint32_t portsc;
uint32_t portpmsc;
uint32_t portli;
uint32_t porthlpmc;
} xhci_port_regs_t;
#define XHCI_PORT_REGS_CCS(p) BITS_R((p)->portsc, 0, 0)
#define XHCI_PORT_REGS_PED(p) BITS_R((p)->portsc, 1, 1)
#define XHCI_PORT_REGS_PR_R(p) BITS_R((p)->portsc, 4, 4)
#define XHCI_PORT_REGS_PR_W(p, v) BITS_W((p)->portsc, 4, 4, v)
#define XHCI_PORT_REGS_PLL(p) BITS_R((p)->portsc, 8, 5)
#define XHCI_PORT_REGS_PP(p) BITS_R((p)->portsc, 9, 9)
#define XHCI_PORT_REGS_PS(p) BITS_R((p)->portsc, 13, 10)
typedef volatile struct __attribute__((packed)) {
uint32_t iman;
uint32_t imod;
uint32_t erstsz;
uint32_t reserved;
uint64_t erstba;
uint64_t erdp;
} xhci_intr_regs_t;
static xhci_cap_regs_t *cap_regs = (xhci_cap_regs_t *)KERNEL_VIRTUAL_XHCI;
static xhci_op_regs_t *op_regs;
static xhci_port_regs_t *port_regs;
static xhci_intr_regs_t *intr_regs;
typedef volatile uint32_t xhci_db_regs;
#define XHCI_DB_REGS_TASK_ID(d) BITS_R((d), 31, 16)
#define XHCI_DB_REGS_TARGET(d) BITS_R((d), 7, 0)
static xhci_db_regs *db_regs;
#define MAX_SLOTS 32
static void *scratchpads[32];
static void *dcbaa[MAX_SLOTS + 1] __attribute__((aligned(PAGE_SIZE)));
typedef struct __attribute__((packed)) {
uint64_t base;
uint32_t size;
uint32_t reserved;
} xchi_erst_entry_t;
typedef struct __attribute__((packed)) {
uint64_t parameter;
uint32_t status;
uint32_t control;
} xhci_trb_t;
#define XHCI_TRB_CYCLE_R(t) BITS_R((t)->control, 0, 0)
#define XHCI_TRB_CYCLE_W(t, v) BITS_W((t)->control, 0, 0, v)
#define XHCI_TRB_TOGGLE_CYCLE_R(t) BITS_R((t)->control, 1, 1)
#define XHCI_TRB_TOGGLE_CYCLE_W(t, v) BITS_W((t)->control, 1, 1, v)
#define XHCI_TRB_IOC_R(t) BITS_R((t)->control, 5, 5)
#define XHCI_TRB_IOC_W(t, v) BITS_W((t)->control, 5, 5, v)
#define XHCI_TRB_TRB_TYPE_R(t) BITS_R((t)->control, 15, 10)
#define XHCI_TRB_TRB_TYPE_W(t, v) BITS_W((t)->control, 15, 10, v)
#define XHCI_TRB_SLOT_TYPE_R(t) BITS_R((t)->control, 20, 16)
#define XHCI_TRB_SLOT_TYPE_W(t, v) BITS_W((t)->control, 20, 16, v)
#define XHCI_TRB_ENDPOINT_ID_R(t) BITS_R((t)->control, 20, 16)
#define XHCI_TRB_ENDPOINT_ID_W(t, v) BITS_W((t)->control, 20, 16, v)
#define XHCI_TRB_COMPLETION_CODE(t) BITS_R((t)->status, 31, 24)
#define XHCI_TRB_SLOT_ID_R(t) BITS_R((t)->control, 31, 24)
#define XHCI_TRB_SLOT_ID_W(t, v) BITS_W((t)->control, 31, 24, v)
#define XHCI_TRB_TYPE_TRANSFER_NORMAL 1
#define XHCI_TRB_TYPE_TRANSFER_SETUP_STAGE 2
#define XHCI_TRB_TYPE_TRANSFER_DATA_STAGE 3
#define XHCI_TRB_TYPE_TRANSFER_STATUS_STAGE 4
#define XHCI_TRB_TYPE_LINK 6
#define XHCI_TRB_TYPE_COMMAND_ENABLE_SLOT 9
#define XHCI_TRB_TYPE_COMMAND_DISABLE_SLOT 10
#define XHCI_TRB_TYPE_COMMAND_ADDRESS_DEVICE 11
#define XHCI_TRB_TYPE_COMMAND_CONFIGURE_ENDPOINT 12
#define XHCI_TRB_TYPE_COMMAND_STOP_ENDPOINT 15
#define XHCI_TRB_TYPE_COMMAND_NOOP 23
#define XHCI_TRB_TYPE_EVENT_TRANSFER_COMPLETION 32
#define XHCI_TRB_TYPE_EVENT_COMMAND_COMPLETION 33
#define XHCI_TRB_TYPE_EVENT_PORT_STATUS_CHANGE 34
static xchi_erst_entry_t erst[1] __attribute__((aligned(PAGE_SIZE)));
#define RING_LENGTH 32
#define RING(name) \
static uint8_t name##_r_cycle = 1; \
static uint8_t name##_r_i = 0; \
static xhci_trb_t name##_r[RING_LENGTH + 1] __attribute__((aligned(PAGE_SIZE)));
#define RING_WRAP(name) \
xhci_trb_t *name##_wrapper = &name##_r[RING_LENGTH]; \
name##_wrapper->parameter = (uint64_t)VIRT_TO_PHYS(name##_r); \
name##_wrapper->status = 0; \
XHCI_TRB_TRB_TYPE_W(name##_wrapper, XHCI_TRB_TYPE_LINK); \
XHCI_TRB_TOGGLE_CYCLE_W(name##_wrapper, 1);
#define RING_ADVANCE(name) \
name##_r_i = (name##_r_i + 1) % RING_LENGTH; \
XHCI_TRB_CYCLE_W(&name##_r[RING_LENGTH], name##_r_cycle); \
name##_r_cycle ^= (name##_r_i == 0);
RING(cmd);
RING(evt);
typedef struct __attribute__((packed)) {
uint32_t drop_flags;
uint32_t add_flags;
uint32_t reserved[6];
} xhci_input_control_ctx_t;
typedef struct __attribute__((packed)) {
uint32_t dw0;
uint32_t dw1;
uint32_t dw2;
uint32_t dw3;
uint32_t reserved[4];
} xhci_slot_ctx_t;
#define XHCI_SLOT_CTX_SPEED_R(s) BITS_R((s)->dw0, 23, 20)
#define XHCI_SLOT_CTX_SPEED_W(s, v) BITS_W((s)->dw0, 23, 20, v)
#define XHCI_SLOT_CTX_CTX_ENTRIES_R(s) BITS_R((s)->dw0, 31, 27)
#define XHCI_SLOT_CTX_CTX_ENTRIES_W(s, v) BITS_W((s)->dw0, 31, 27, v)
#define XHCI_SLOT_CTX_ROOT_HUB_PORT_R(s) BITS_R((s)->dw1, 23, 16)
#define XHCI_SLOT_CTX_ROOT_HUB_PORT_W(s, v) BITS_W((s)->dw1, 23, 16, v)
typedef struct __attribute__((packed)) {
uint32_t dw0;
uint32_t dw1;
uint64_t dequeue;
uint32_t dw4;
uint32_t reserved[3];
} xhci_ep_ctx_t;
#define XHCI_EP_CTX_INTERVAL_R(e) BITS_R((e)->dw0, 23, 16)
#define XHCI_EP_CTX_INTERVAL_W(e, v) BITS_W((e)->dw0, 23, 16, v)
#define XHCI_EP_CTX_EP_TYPE_R(e) BITS_R((e)->dw1, 5, 3)
#define XHCI_EP_CTX_EP_TYPE_W(e, v) BITS_W((e)->dw1, 5, 3, v)
#define XHCI_EP_CTX_MAX_PACKET_SIZE_R(e) BITS_R((e)->dw1, 31, 16)
#define XHCI_EP_CTX_MAX_PACKET_SIZE_W(e, v) BITS_W((e)->dw1, 31, 16, v)
#define XHCI_EP_CTX_MAX_PACKET_SIZE 64
typedef struct __attribute__((packed)) {
xhci_input_control_ctx_t control;
xhci_slot_ctx_t slot;
xhci_ep_ctx_t ep[31];
} xhci_input_ctx_t;
static xhci_input_ctx_t input_ctx __attribute__((aligned(64)));
typedef struct __attribute__((packed)) {
xhci_slot_ctx_t slot;
xhci_ep_ctx_t endpoints[31];
} xchi_device_ctx_t;
static xchi_device_ctx_t device_ctx __attribute__((aligned(64)));
static uint8_t tsf_r_attached_slot = 0;
RING(tsf);
static uint8_t ep_r_attached_endpoint = 0;
RING(ep);
static uint16_t ep_transfer_size = 0;
static uint8_t ep_buffer[RING_LENGTH][XHCI_EP_CTX_MAX_PACKET_SIZE] __attribute__((aligned(64)));
static uint8_t ep_processed_events = RING_LENGTH;
static const xhci_trb_t *command_exec_sync(const xhci_trb_t *cmd) {
LOG_LN_STEP("Queueing command TRB...");
LOG_VAL_TRACE(cmd->parameter, "%lx");
LOG_VAL_TRACE(cmd->status, "%x");
LOG_VAL_TRACE(cmd->control, "%x");
xhci_trb_t *cre = &cmd_r[cmd_r_i];
memory_copy(cmd, sizeof(xhci_trb_t), cre);
XHCI_TRB_CYCLE_W(cre, cmd_r_cycle);
RING_ADVANCE(cmd);
LOG_LN_STEP("Ringing command doorbell...");
LOG_VAL_TRACE(op_regs->usbsts, "%x");
db_regs[0] = 0;
LOG_VAL_TRACE(op_regs->usbsts, "%x");
LOG_LN_STEP("Waiting for completion...");
while (1) {
xhci_trb_t *cmp = &evt_r[evt_r_i];
while (XHCI_TRB_CYCLE_R(cmp) != evt_r_cycle)
;
RING_ADVANCE(evt);
if (XHCI_TRB_TRB_TYPE_R(cmp) != XHCI_TRB_TYPE_EVENT_COMMAND_COMPLETION || (void *)cmp->parameter != VIRT_TO_PHYS(cre)) {
LOG_LN_STEP("Received irrelevant event, skipping...");
LOG_VAL_TRACE(cmp->parameter, "%lx");
LOG_VAL_TRACE(cmp->status, "%x");
LOG_VAL_TRACE(cmp->control, "%x");
} else {
LOG_LN_STEP("Received command completion event...");
LOG_VAL_TRACE(cmp->parameter, "%lx");
LOG_VAL_TRACE(cmp->status, "%x");
LOG_VAL_TRACE(cmp->control, "%x");
ASSERT(XHCI_TRB_COMPLETION_CODE(cmp) == 1, "command_exec_sync: Command failed.");
LOG_LN_STEP("Done.");
return cmp;
}
}
}
static const xhci_trb_t *control_transfer_exec_sync(uint64_t setup, void *data, uint16_t length) {
ASSERT(tsf_r_attached_slot, "control_transfer_exec_sync: Slot not attached.");
LOG_LN_STEP("Queueing transfer TRBs...");
xhci_trb_t *tre = &tsf_r[tsf_r_i];
tre->parameter = setup;
tre->status = sizeof(setup);
XHCI_TRB_TRB_TYPE_W(tre, XHCI_TRB_TYPE_TRANSFER_SETUP_STAGE);
BITS_W(tre->control, 17, 16, 3);
BITS_W(tre->control, 6, 6, 1);
XHCI_TRB_CYCLE_W(tre, tsf_r_cycle);
LOG_VAL_TRACE(tre->parameter, "%lx");
LOG_VAL_TRACE(tre->status, "%x");
LOG_VAL_TRACE(tre->control, "%x");
RING_ADVANCE(tsf);
if (data != NUL) {
tre = &tsf_r[tsf_r_i];
tre->parameter = (uint64_t)VIRT_TO_PHYS(data);
tre->status = length;
XHCI_TRB_TRB_TYPE_W(tre, XHCI_TRB_TYPE_TRANSFER_DATA_STAGE);
BITS_W(tre->control, 16, 16, 1);
XHCI_TRB_CYCLE_W(tre, tsf_r_cycle);
LOG_VAL_TRACE(tre->parameter, "%lx");
LOG_VAL_TRACE(tre->status, "%x");
LOG_VAL_TRACE(tre->control, "%x");
RING_ADVANCE(tsf);
}
tre = &tsf_r[tsf_r_i];
XHCI_TRB_TRB_TYPE_W(tre, XHCI_TRB_TYPE_TRANSFER_STATUS_STAGE);
BITS_W(tre->control, 16, 16, 0);
XHCI_TRB_IOC_W(tre, 1);
XHCI_TRB_CYCLE_W(tre, tsf_r_cycle);
RING_ADVANCE(tsf);
LOG_LN_STEP("Ringing slot doorbell...");
db_regs[tsf_r_attached_slot] = 1;
LOG_LN_STEP("Waiting for completion...");
while (1) {
xhci_trb_t *cmp = &evt_r[evt_r_i];
while (XHCI_TRB_CYCLE_R(cmp) != evt_r_cycle)
;
RING_ADVANCE(evt);
if (XHCI_TRB_TRB_TYPE_R(cmp) != XHCI_TRB_TYPE_EVENT_TRANSFER_COMPLETION || (void *)cmp->parameter != VIRT_TO_PHYS(tre)) {
LOG_LN_STEP("Received irrelevant event, skipping...");
LOG_VAL_TRACE(cmp->parameter, "%lx");
LOG_VAL_TRACE(cmp->status, "%x");
LOG_VAL_TRACE(cmp->control, "%x");
} else {
LOG_LN_STEP("Received transfer completion event...");
LOG_VAL_TRACE(cmp->parameter, "%lx");
LOG_VAL_TRACE(cmp->status, "%x");
LOG_VAL_TRACE(cmp->control, "%x");
ASSERT(XHCI_TRB_COMPLETION_CODE(cmp) == 1, "control_transfer_exec_sync: Transfer failed.");
LOG_LN_STEP("Done.");
return cmp;
}
}
}
void xhci_init() {
LOG_LN_INFO("Searching for suitable controller...");
pci_bdf_t bdf = pci_find_by_class(XHCI_PCI_CLASS, XHCI_PCI_SUBCLASS, XHCI_PCI_INTERFACE);
ASSERT(bdf != (pci_bdf_t)-1, "xhci_init: No suitable controllers found.");
LOG_LN_INFO("Mapping controller to virtual memory...");
pci_map(bdf, cap_regs, 4);
op_regs = (xhci_op_regs_t *)((uint8_t *)cap_regs + cap_regs->caplength);
port_regs = (xhci_port_regs_t *)((uint8_t *)cap_regs + cap_regs->caplength + 0x400);
intr_regs = (xhci_intr_regs_t *)((uint8_t *)cap_regs + cap_regs->rtsoff + 0x20);
db_regs = (uint32_t *)((uint8_t *)cap_regs + cap_regs->dboff);
LOG_VAL_DATA(cap_regs->caplength, "%hhx");
LOG_VAL_DATA(cap_regs->hciversion, "%hx");
LOG_VAL_DATA(cap_regs->hcsparams1, "%x");
LOG_VAL_DATA(cap_regs->hcsparams2, "%x");
LOG_VAL_DATA(cap_regs->hcsparams3, "%x");
LOG_VAL_DATA(cap_regs->hccparams1, "%x");
LOG_VAL_DATA(cap_regs->dboff, "%x");
LOG_VAL_DATA(cap_regs->rtsoff, "%x");
LOG_VAL_DATA(cap_regs->hccparams2, "%x");
LOG_VAL_DATA(op_regs->usbcmd, "%x");
LOG_VAL_DATA(op_regs->usbsts, "%x");
LOG_VAL_DATA(op_regs->pagesize, "%x");
LOG_VAL_DATA(op_regs->dnctrl, "%x");
LOG_VAL_DATA(op_regs->crcr, "%lx");
LOG_VAL_DATA(op_regs->dcbaap, "%lx");
LOG_VAL_DATA(op_regs->config, "%x");
LOG_LN_INFO("Stopping controller...");
XHCI_OP_REGS_RS_W(op_regs, 0);
LOG_VAL_DATA(op_regs->usbcmd, "%x");
LOG_VAL_DATA(op_regs->usbsts, "%x");
while (!XHCI_OP_REGS_HCH(op_regs))
;
LOG_VAL_DATA(op_regs->usbcmd, "%x");
LOG_VAL_DATA(op_regs->usbsts, "%x");
LOG_LN_INFO("Resetting controller...");
XHCI_OP_REGS_EINT_W(op_regs, 0);
XHCI_OP_REGS_HCRST_W(op_regs, 1);
LOG_VAL_DATA(op_regs->usbcmd, "%x");
LOG_VAL_DATA(op_regs->usbsts, "%x");
while (XHCI_OP_REGS_HCRST_R(op_regs))
;
LOG_VAL_DATA(op_regs->usbcmd, "%x");
LOG_VAL_DATA(op_regs->usbsts, "%x");
while (XHCI_OP_REGS_CNR(op_regs))
;
LOG_VAL_DATA(op_regs->usbcmd, "%x");
LOG_VAL_DATA(op_regs->usbsts, "%x");
LOG_LN_INFO("Setting up command ring...");
RING_WRAP(cmd);
XHCI_TRB_CYCLE_W(&cmd_r[RING_LENGTH], cmd_r_cycle);
LOG_LN_INFO("Setting up scratchpad buffers...");
ASSERT(XHCI_CAP_REGS_MAX_SCRATCHPAD_BUFFERS(cap_regs) <= sizeof(scratchpads), "Too many scratchpad buffers expected.");
for (uint32_t i = 0; i < XHCI_CAP_REGS_MAX_SCRATCHPAD_BUFFERS(cap_regs); i++) {
scratchpads[i] = memory_page_allocate();
}
dcbaa[0] = VIRT_TO_PHYS(scratchpads);
LOG_LN_INFO("Configuring controller...");
XHCI_OP_REGS_MAX_SLOTS_EN_W(op_regs, MAX_SLOTS);
op_regs->dcbaap = (uint64_t)VIRT_TO_PHYS(dcbaa);
op_regs->crcr = (uint64_t)VIRT_TO_PHYS(cmd_r) | cmd_r_cycle;
erst[0].size = RING_LENGTH;
erst[0].base = (uint64_t)VIRT_TO_PHYS(evt_r);
intr_regs->erstsz = sizeof(erst) / sizeof(xchi_erst_entry_t);
intr_regs->erstba = (uint64_t)VIRT_TO_PHYS(erst);
intr_regs->erdp = erst[0].base;
LOG_VAL_DATA(op_regs->config, "%x");
LOG_VAL_DATA(op_regs->dcbaap, "%lx");
LOG_VAL_DATA(op_regs->crcr, "%lx");
LOG_VAL_DATA(intr_regs->erstba, "%lx");
LOG_VAL_DATA(intr_regs->erstsz, "%x");
LOG_VAL_DATA(intr_regs->erdp, "%lx");
LOG_VAL_DATA(erst[0].size, "%hx");
LOG_VAL_DATA(erst[0].base, "%lx");
LOG_LN_INFO("Starting controller...");
LOG_VAL_DATA(op_regs->usbcmd, "%x");
LOG_VAL_DATA(op_regs->usbsts, "%x");
XHCI_OP_REGS_RS_W(op_regs, 1);
LOG_VAL_DATA(op_regs->usbcmd, "%x");
LOG_VAL_DATA(op_regs->usbsts, "%x");
while (XHCI_OP_REGS_HCH(op_regs))
;
LOG_VAL_DATA(op_regs->usbcmd, "%x");
LOG_VAL_DATA(op_regs->usbsts, "%x");
sleep(1000); // Wait for ports to settle
PRINT_LN(kernel_log, "Enumerating ports...");
xhci_enumerate(kernel_log);
PRINT_LN(kernel_log, "Done.");
}
void xhci_enumerate(stream_t *out) {
for (uint16_t i = 0; i < XHCI_CAP_REGS_MAX_PORTS(cap_regs); i++) {
PRINT_LN(out, "port=%d CCS=%d PED=%d PP=%d PS=%d portsc=%x", i, XHCI_PORT_REGS_CCS(&port_regs[i]), XHCI_PORT_REGS_PED(&port_regs[i]),
XHCI_PORT_REGS_PP(&port_regs[i]), XHCI_PORT_REGS_PS(&port_regs[i]), port_regs[i].portsc);
}
}
uint8_t xhci_port_count() {
return XHCI_CAP_REGS_MAX_PORTS(cap_regs);
}
uint8_t xhci_port_connected(xhci_port_t port) {
ASSERT(port < XHCI_CAP_REGS_MAX_PORTS(cap_regs), "xhci_port_connected: Port doesn't exist.");
return XHCI_PORT_REGS_CCS(&port_regs[port]);
}
xhci_slot_t xhci_attach(xhci_port_t port) {
LOG_LN_STEP("Attaching port %d ...", port);
ASSERT(port < XHCI_CAP_REGS_MAX_PORTS(cap_regs), "xhci_attach: Port doesn't exist.");
ASSERT(!tsf_r_attached_slot, "xhci_attach: Can only attach one port at a time.");
ASSERT(XHCI_PORT_REGS_CCS(&port_regs[port]), "xhci_attach: Port is not connected.");
LOG_LN_STEP("Setting up transfer ring...");
memory_set(0, sizeof(tsf_r), tsf_r);
tsf_r_i = 0;
tsf_r_cycle = 1;
RING_WRAP(tsf);
LOG_LN_STEP("Resetting device...");
LOG_VAL_TRACE(port_regs[port].portsc, "%x");
port_regs[port].portsc = (port_regs[port].portsc & ~(uint32_t)0x00FE0000) | 0x00FE0000;
LOG_VAL_TRACE(port_regs[port].portsc, "%x");
port_regs[port].portsc = (port_regs[port].portsc & ~(uint32_t)0x00FE0000) | (1 << 4);
LOG_VAL_TRACE(port_regs[port].portsc, "%x");
while (XHCI_PORT_REGS_PR_R(&port_regs[port]))
;
LOG_VAL_TRACE(port_regs[port].portsc, "%x");
while (!XHCI_PORT_REGS_PED(&port_regs[port]) && XHCI_PORT_REGS_PLL(&port_regs[port]) != 0)
;
LOG_VAL_TRACE(port_regs[port].portsc, "%x");
LOG_LN_STEP("Enabling a slot...");
xhci_trb_t cmd_es;
memory_set(0, sizeof(xhci_trb_t), &cmd_es);
XHCI_TRB_TRB_TYPE_W(&cmd_es, XHCI_TRB_TYPE_COMMAND_ENABLE_SLOT);
xhci_slot_t slot = XHCI_TRB_SLOT_ID_R(command_exec_sync(&cmd_es));
LOG_LN_STEP("Addressing device...");
memory_set(0, sizeof(input_ctx), &input_ctx);
input_ctx.control.add_flags = 0b11;
XHCI_SLOT_CTX_CTX_ENTRIES_W(&input_ctx.slot, 1);
XHCI_SLOT_CTX_ROOT_HUB_PORT_W(&input_ctx.slot, port + 1);
XHCI_SLOT_CTX_SPEED_W(&input_ctx.slot, XHCI_PORT_REGS_PS((&port_regs[port])));
XHCI_EP_CTX_EP_TYPE_W(&input_ctx.ep[0], 4);
XHCI_EP_CTX_MAX_PACKET_SIZE_W(&input_ctx.ep[0], 64);
input_ctx.ep[0].dequeue = (uint64_t)VIRT_TO_PHYS(tsf_r) | tsf_r_cycle;
dcbaa[slot] = VIRT_TO_PHYS(&device_ctx);
xhci_trb_t cmd_ad;
memory_set(0, sizeof(xhci_trb_t), &cmd_ad);
cmd_ad.parameter = (uint64_t)VIRT_TO_PHYS(&input_ctx);
XHCI_TRB_TRB_TYPE_W(&cmd_ad, XHCI_TRB_TYPE_COMMAND_ADDRESS_DEVICE);
XHCI_TRB_SLOT_ID_W(&cmd_ad, slot);
command_exec_sync(&cmd_ad);
tsf_r_attached_slot = slot;
LOG_LN_STEP("Done.");
return slot;
}
uint64_t xhci_control_transfer(xhci_slot_t slot, uint64_t setup, void *data, uint16_t length) {
ASSERT(slot < MAX_SLOTS, "xhci_control_transfer: Slot does not exist.");
ASSERT(tsf_r_attached_slot == slot, "xhci_control_transfer: Slot is not attached.");
ASSERT(!ep_r_attached_endpoint, "xhci_control_transfer: Can not control transfer while in polling mode.");
return length - (control_transfer_exec_sync(setup, data, length)->status & 0xFFFFFF);
}
xhci_endpoint_t xhci_open_endpoint(xhci_slot_t slot, uint8_t address, uint8_t type, uint16_t max_packet_size, uint8_t interval) {
LOG_LN_STEP("Opening endpoint slot %d address %hhx...", slot, address);
ASSERT(slot < MAX_SLOTS, "xhci_control_transfer: Slot does not exist.");
ASSERT(tsf_r_attached_slot == slot, "xhci_open_endpoint: Slot is not attached.");
ASSERT(!ep_r_attached_endpoint, "xhci_open_endpoint: Can only open one endpoint at a time.");
ASSERT(max_packet_size <= XHCI_EP_CTX_MAX_PACKET_SIZE, "xhci_open_endpoint: Packet size too big.")
uint8_t ep_num = address & 0x0F;
uint8_t ep_dir = (address >> 7) & 1;
uint8_t dci = ep_num * 2 + ep_dir;
LOG_LN_STEP("Setting up endpoint ring...");
RING_WRAP(ep);
XHCI_TRB_CYCLE_W(&ep_r[RING_LENGTH], ep_r_cycle);
LOG_LN_STEP("Configuring endpoint...");
memory_set(0, sizeof(xhci_input_ctx_t), &input_ctx);
input_ctx.slot = device_ctx.slot;
input_ctx.control.add_flags = (1 << 0) | (1 << dci);
XHCI_SLOT_CTX_CTX_ENTRIES_W(&input_ctx.slot, dci);
XHCI_EP_CTX_EP_TYPE_W(&input_ctx.ep[dci - 1], type);
XHCI_EP_CTX_MAX_PACKET_SIZE_W(&input_ctx.ep[dci - 1], max_packet_size);
XHCI_EP_CTX_INTERVAL_W(&input_ctx.ep[dci - 1], interval);
input_ctx.ep[dci - 1].dequeue = (uint64_t)VIRT_TO_PHYS(ep_r) | ep_r_cycle;
xhci_trb_t cmd_ce;
memory_set(0, sizeof(xhci_trb_t), &cmd_ce);
XHCI_TRB_TRB_TYPE_W(&cmd_ce, XHCI_TRB_TYPE_COMMAND_CONFIGURE_ENDPOINT);
cmd_ce.parameter = (uint64_t)VIRT_TO_PHYS(&input_ctx);
XHCI_TRB_SLOT_ID_W(&cmd_ce, slot);
command_exec_sync(&cmd_ce);
ep_r_attached_endpoint = dci;
ep_transfer_size = max_packet_size;
return dci;
}
uint16_t xhci_read_endpoint(xhci_slot_t slot, xhci_endpoint_t endpoint, uint16_t max, void *to) {
LOG_LN_STEP("Reading from endpoint %hhx...", endpoint);
ASSERT(slot < MAX_SLOTS, "xhci_control_transfer: Slot does not exist.");
ASSERT(tsf_r_attached_slot == slot, "xhci_read_endpoint: Slot is not attached.");
ASSERT(ep_r_attached_endpoint == endpoint, "xhci_read_endpoint: Endpoint not open.");
if (ep_processed_events == RING_LENGTH) {
LOG_LN_STEP("Event batch finished, posting new transfer requests...");
ep_processed_events = 0;
ASSERT(ep_r_i == 0, "xhci_read_endpoint: Endpoint ring cycle broken.");
for (uint64_t i = 0; i < RING_LENGTH; i++) {
xhci_trb_t *ere = &ep_r[i];
ere->parameter = (uint64_t)VIRT_TO_PHYS(&ep_buffer[i]);
ere->status = ep_transfer_size;
XHCI_TRB_TRB_TYPE_W(ere, XHCI_TRB_TYPE_TRANSFER_NORMAL);
XHCI_TRB_IOC_W(ere, 1);
XHCI_TRB_CYCLE_W(ere, ep_r_cycle);
}
ep_r_cycle ^= 1;
db_regs[tsf_r_attached_slot] = ep_r_attached_endpoint;
return 0;
}
uint16_t transferred = 0;
while (XHCI_TRB_CYCLE_R(&evt_r[evt_r_i]) == evt_r_cycle && !transferred) {
if (ep_processed_events == 0) {
// A bit of a hack: flip link TRB cycle only after the first event is processed. There is some delay between controller
// posting the last success event of the batch, and consuming the link TRB. Flipping the link cycle together with the batch
// might happen before the controller got a chance to check the link cycle, and stall the consumption. If we received the
// first event of the next batch, we're certain the link TRB has just been processed, and there's plenty of time before the next loop.
XHCI_TRB_CYCLE_W(&ep_r[RING_LENGTH], !ep_r_cycle);
}
xhci_trb_t *cmp = &evt_r[evt_r_i];
if (XHCI_TRB_TRB_TYPE_R(cmp) != XHCI_TRB_TYPE_EVENT_TRANSFER_COMPLETION) {
LOG_LN_STEP("Received irrelevant event, skipping...");
LOG_VAL_TRACE(cmp->parameter, "%lx");
LOG_VAL_TRACE(cmp->status, "%x");
LOG_VAL_TRACE(cmp->control, "%x");
} else if (XHCI_TRB_COMPLETION_CODE(cmp) != 1) {
LOG_LN_STEP("Received unsuccessful transfer event, skipping...");
ep_processed_events++;
LOG_VAL_TRACE(cmp->parameter, "%lx");
LOG_VAL_TRACE(cmp->status, "%x");
LOG_VAL_TRACE(cmp->control, "%x");
} else {
LOG_LN_STEP("Received transfer event, returning...");
ep_processed_events++;
LOG_VAL_TRACE(cmp->parameter, "%lx");
LOG_VAL_TRACE(cmp->status, "%x");
LOG_VAL_TRACE(cmp->control, "%x");
xhci_trb_t *cmd = PHYS_TO_VIRT(cmp->parameter);
uint16_t size = max < cmd->status ? max : (uint16_t)cmd->status;
memory_copy(PHYS_TO_VIRT(cmd->parameter), size, to);
LOG_VAL_TRACE(size, "%d");
LOG_VAL_TRACE(*(uint64_t *)to, "%lx");
transferred = size;
}
RING_ADVANCE(evt);
intr_regs->erdp = (uint64_t)VIRT_TO_PHYS(&evt_r[evt_r_i]);
}
return transferred;
}
void xhci_close_endpoint(xhci_slot_t slot, xhci_endpoint_t endpoint) {
LOG_LN_STEP("Closing endpoind %hhx...", endpoint);
ASSERT(slot < MAX_SLOTS, "xhci_control_transfer: Slot does not exist.");
ASSERT(tsf_r_attached_slot == slot, "xhci_close_endpoint: Slot is not attached.");
ASSERT(ep_r_attached_endpoint == endpoint, "xhci_close_endpoint: Endpoint not open.");
ep_r_attached_endpoint = NUL;
xhci_trb_t cmd_se;
memory_set(0, sizeof(xhci_trb_t), &cmd_se);
XHCI_TRB_TRB_TYPE_W(&cmd_se, XHCI_TRB_TYPE_COMMAND_STOP_ENDPOINT);
XHCI_TRB_SLOT_ID_W(&cmd_se, slot);
XHCI_TRB_ENDPOINT_ID_W(&cmd_se, endpoint);
command_exec_sync(&cmd_se);
}
void xhci_detach(xhci_slot_t slot) {
LOG_LN_STEP("Detaching slot %d...", slot);
ASSERT(slot < MAX_SLOTS, "xhci_control_transfer: Slot does not exist.");
ASSERT(tsf_r_attached_slot == slot, "xhci_detach: Slot not attached.");
ASSERT(!ep_r_attached_endpoint, "xhci_detach: Can not detach slot while in polling mode.");
xhci_trb_t cmd_ds;
memory_set(0, sizeof(xhci_trb_t), &cmd_ds);
XHCI_TRB_TRB_TYPE_W(&cmd_ds, XHCI_TRB_TYPE_COMMAND_DISABLE_SLOT);
XHCI_TRB_SLOT_ID_W(&cmd_ds, slot);
command_exec_sync(&cmd_ds);
dcbaa[slot] = 0;
tsf_r_attached_slot = 0;
LOG_LN_STEP("Done.");
}
-28
View File
@@ -1,28 +0,0 @@
#pragma once
#include "src/kernel/stream.h"
#include <stdint.h>
typedef uint8_t xhci_port_t;
typedef uint8_t xhci_slot_t;
typedef uint8_t xhci_endpoint_t;
void xhci_init(); // Assuming one and only one xHCI controller.
void xhci_enumerate(stream_t *out);
uint8_t xhci_port_count();
uint8_t xhci_port_connected(xhci_port_t port);
xhci_slot_t xhci_attach(xhci_port_t port);
uint64_t xhci_control_transfer(xhci_slot_t slot, uint64_t setup, void *data, uint16_t length);
xhci_endpoint_t xhci_open_endpoint(xhci_slot_t slot, uint8_t address, uint8_t type, uint16_t max_packet_size, uint8_t interval);
uint16_t xhci_read_endpoint(xhci_slot_t slot, xhci_endpoint_t endpoint, uint16_t max, void *to);
void xhci_close_endpoint(xhci_slot_t slot, xhci_endpoint_t endpoint);
void xhci_detach(xhci_slot_t slot);
-5
View File
@@ -11,17 +11,12 @@
#define PHYS_TO_VIRT(phys) ((void *)((uint64_t)(phys) + KERNEL_VIRTUAL_BASE)) #define PHYS_TO_VIRT(phys) ((void *)((uint64_t)(phys) + KERNEL_VIRTUAL_BASE))
#define VIRT_TO_PHYS(virt) ((void *)((uint64_t)(virt) - KERNEL_VIRTUAL_BASE)) #define VIRT_TO_PHYS(virt) ((void *)((uint64_t)(virt) - KERNEL_VIRTUAL_BASE))
#define NVME_PAGE_COUNT 4
#define USB_PAGE_COUNT 4
#define KERNEL_VIRTUAL_PML4 (KERNEL_VIRTUAL_BASE + 0x10000) #define KERNEL_VIRTUAL_PML4 (KERNEL_VIRTUAL_BASE + 0x10000)
#define KERNEL_VIRTUAL_CODE (KERNEL_VIRTUAL_PML4 + 0x10000) #define KERNEL_VIRTUAL_CODE (KERNEL_VIRTUAL_PML4 + 0x10000)
#define KERNEL_VIRTUAL_HEAP (KERNEL_VIRTUAL_CODE + 0x100000) #define KERNEL_VIRTUAL_HEAP (KERNEL_VIRTUAL_CODE + 0x100000)
#define KERNEL_VIRTUAL_UNUSED (KERNEL_VIRTUAL_HEAP + HEAP_SIZE) #define KERNEL_VIRTUAL_UNUSED (KERNEL_VIRTUAL_HEAP + HEAP_SIZE)
#define KERNEL_VIRTUAL_STACK (KERNEL_VIRTUAL_BASE + 0xF00000 - PAGE_SIZE) #define KERNEL_VIRTUAL_STACK (KERNEL_VIRTUAL_BASE + 0xF00000 - PAGE_SIZE)
#define KERNEL_VIRTUAL_STACK_TOP (KERNEL_VIRTUAL_STACK + PAGE_SIZE) #define KERNEL_VIRTUAL_STACK_TOP (KERNEL_VIRTUAL_STACK + PAGE_SIZE)
#define KERNEL_VIRTUAL_NVME (KERNEL_VIRTUAL_BASE + MEMORY_SIZE)
#define KERNEL_VIRTUAL_XHCI (KERNEL_VIRTUAL_NVME + NVME_PAGE_COUNT * PAGE_SIZE)
#define USER_VIRTUAL_BASE 0x0000000000000000ULL #define USER_VIRTUAL_BASE 0x0000000000000000ULL
#define USER_VIRTUAL_CODE (USER_VIRTUAL_BASE + 0x400000) #define USER_VIRTUAL_CODE (USER_VIRTUAL_BASE + 0x400000)
+3 -3
View File
@@ -6,11 +6,11 @@ void *memory_allocate(uint64_t size);
void memory_free(void *pointer); void memory_free(void *pointer);
static inline void memory_set(uint8_t value, uint64_t bytes, volatile void *to) { static inline void memory_set(uint8_t value, uint64_t bytes, void *to) {
__asm__ volatile("rep stosb" : "=D"(to), "=c"(bytes) : "D"(to), "a"(value), "c"(bytes) : "memory"); __asm__ volatile("rep stosb" : "=D"(to), "=c"(bytes) : "D"(to), "a"(value), "c"(bytes) : "memory");
} }
static inline void memory_move(volatile void *from, uint64_t bytes, volatile void *to) { static inline void memory_move(void *from, uint64_t bytes, void *to) {
if (to == from) { if (to == from) {
return; return;
} else if (to < from) { } else if (to < from) {
@@ -20,7 +20,7 @@ static inline void memory_move(volatile void *from, uint64_t bytes, volatile voi
} }
} }
static inline void memory_copy(volatile const void *from, uint64_t bytes, volatile void *to) { static inline void memory_copy(const void *from, uint64_t bytes, void *to) {
// TODO ASSERT((uint64_t)to + bytes <= (uint64_t)from || (uint64_t)to >= (uint64_t)from + bytes, "memory_copy: overlapping backward // TODO ASSERT((uint64_t)to + bytes <= (uint64_t)from || (uint64_t)to >= (uint64_t)from + bytes, "memory_copy: overlapping backward
// copy"); // copy");
+56 -217
View File
@@ -33,30 +33,6 @@ uint8_t string_equal(const char *l, const char *r) {
return *l == *r; return *l == *r;
} }
uint64_t string_trim(char *string, char character, char **result) {
while (*string == character) {
string++;
}
*result = string;
if (*string == '\0') {
return 0;
}
char *end = string;
while (*end != '\0') {
end++;
}
end--;
while (string < end && *end == character) {
*end = '\0';
end--;
}
return (uint64_t)(end - string + 1);
}
uint64_t string_split(char *string, char separator, uint64_t max, char **result) { uint64_t string_split(char *string, char separator, uint64_t max, char **result) {
uint64_t count = 1; uint64_t count = 1;
*result = string; *result = string;
@@ -73,7 +49,7 @@ uint64_t string_split(char *string, char separator, uint64_t max, char **result)
return count; return count;
} }
uint64_t string_uint8_to_hex(uint8_t value, uint64_t max, char *result) { uint64_t string_byte_to_hex(uint8_t value, uint64_t max, char *result) {
if (max == 0) { if (max == 0) {
return 0; return 0;
} }
@@ -94,7 +70,7 @@ uint64_t string_uint8_to_hex(uint8_t value, uint64_t max, char *result) {
uint8_t i = 0; uint8_t i = 0;
while (value) { while (value) {
uint8_t nibble = value & 0xF; uint8_t nibble = value & 0xF;
tmp[i++] = nibble < 10 ? '0' + nibble : 'A' + nibble - 10; tmp[i++] = nibble < 10 ? '0' + nibble : 'a' + nibble - 10;
value >>= 4; value >>= 4;
} }
@@ -110,117 +86,6 @@ uint64_t string_uint8_to_hex(uint8_t value, uint64_t max, char *result) {
return i; return i;
} }
uint64_t string_uint16_to_hex(uint16_t value, uint64_t max, char *result) {
if (max == 0) {
return 0;
}
if (max == 1) {
result[0] = '\0';
return 0;
}
if (max == 2) {
result[0] = '0';
result[1] = '\0';
return 1;
}
char tmp[5] = "0000";
uint8_t i = 0;
while (value) {
uint8_t nibble = value & 0xF;
tmp[i++] = nibble < 10 ? '0' + nibble : 'A' + nibble - 10;
value >>= 4;
}
result[0] = '0';
result[1] = 'x';
i = 2;
while (i < 6 && i < max - 1) {
result[i] = tmp[5 - i];
i++;
}
result[i] = '\0';
return i;
}
uint64_t string_uint32_to_hex(uint32_t value, uint64_t max, char *result) {
if (max == 0) {
return 0;
}
if (max == 1) {
result[0] = '\0';
return 0;
}
if (max == 2) {
result[0] = '0';
result[1] = '\0';
return 1;
}
char tmp[9] = "00000000";
uint8_t i = 0;
while (value) {
uint8_t nibble = value & 0xF;
tmp[i++] = nibble < 10 ? '0' + nibble : 'A' + nibble - 10;
value >>= 4;
}
result[0] = '0';
result[1] = 'x';
i = 2;
while (i < 10 && i < max - 1) {
result[i] = tmp[9 - i];
i++;
}
result[i] = '\0';
return i;
}
uint64_t string_uint64_to_hex(uint64_t value, uint64_t max, char *result) {
if (max == 0) {
return 0;
}
if (max == 1) {
result[0] = '\0';
return 0;
}
if (max == 2) {
result[0] = '0';
result[1] = '\0';
return 1;
}
char tmp[17] = "0000000000000000";
uint8_t i = 0;
while (value) {
uint8_t nibble = value & 0xF;
tmp[i++] = nibble < 10 ? '0' + nibble : 'A' + nibble - 10;
value >>= 4;
}
result[0] = '0';
result[1] = 'x';
i = 2;
while (i < 18 && i < max - 1) {
result[i] = tmp[17 - i];
i++;
}
result[i] = '\0';
return i;
}
uint64_t string_uint_to_decimal(uint64_t value, uint64_t max, char *result) { uint64_t string_uint_to_decimal(uint64_t value, uint64_t max, char *result) {
if (max == 0) { if (max == 0) {
return 0; return 0;
@@ -260,6 +125,43 @@ uint64_t string_int_to_decimal(int64_t value, uint64_t max, char *result) {
return 1 + string_uint_to_decimal((uint64_t)(-value), max - 1, result + 1); return 1 + string_uint_to_decimal((uint64_t)(-value), max - 1, result + 1);
} }
uint64_t string_uint_to_hex(uint64_t value, uint64_t max, char *result) {
if (max == 0) {
return 0;
}
if (max == 1) {
result[0] = '\0';
return 0;
}
if (max == 2) {
result[0] = '0';
result[1] = '\0';
return 1;
}
char tmp[17] = "0000000000000000";
uint8_t i = 0;
while (value) {
uint8_t nibble = value & 0xF;
tmp[i++] = nibble < 10 ? '0' + nibble : 'A' + nibble - 10;
value >>= 4;
}
result[0] = '0';
result[1] = 'x';
i = 2;
while (i < 18 && i < max - 1) {
result[i] = tmp[17 - i];
i++;
}
result[i] = '\0';
return i;
}
uint64_t string_format(const char *format, uint64_t max, char *output, ...) { uint64_t string_format(const char *format, uint64_t max, char *output, ...) {
va_list args; va_list args;
va_start(args, output); va_start(args, output);
@@ -272,19 +174,31 @@ uint64_t string_format(const char *format, uint64_t max, char *output, ...) {
output[ri++] = format[fi++]; output[ri++] = format[fi++];
} else { } else {
switch (format[fi + 1]) { switch (format[fi + 1]) {
case 'c': { case 'c':
output[ri++] = (char)va_arg(args, int); output[ri++] = (char)va_arg(args, int);
fi += 2; fi += 2;
break; break;
} case 'd':
case 'd': {
string_int_to_decimal(va_arg(args, int64_t), limit - ri, output + ri); string_int_to_decimal(va_arg(args, int64_t), limit - ri, output + ri);
while (output[ri]) { while (output[ri]) {
ri++; ri++;
} }
fi += 2; fi += 2;
break; break;
} case 'u':
string_uint_to_decimal(va_arg(args, uint64_t), limit - ri, output + ri);
while (output[ri]) {
ri++;
}
fi += 2;
break;
case 'x':
string_uint_to_hex(va_arg(args, uint64_t), limit - ri, output + ri);
while (output[ri]) {
ri++;
}
fi += 2;
break;
case 's': { case 's': {
char *s = va_arg(args, char *); char *s = va_arg(args, char *);
while (*s && ri < limit) { while (*s && ri < limit) {
@@ -294,91 +208,16 @@ uint64_t string_format(const char *format, uint64_t max, char *output, ...) {
fi += 2; fi += 2;
break; break;
} }
case 'u': {
string_uint_to_decimal(va_arg(args, uint64_t), limit - ri, output + ri);
while (output[ri]) {
ri++;
}
fi += 2;
break;
}
case 'x': {
string_uint32_to_hex(va_arg(args, uint32_t), limit - ri, output + ri);
while (output[ri]) {
ri++;
}
fi += 2;
break;
}
case '%': { case '%': {
output[ri++] = '%'; output[ri++] = '%';
fi += 2; fi += 2;
break; break;
} }
case 'h': { default:
switch (format[fi + 2]) {
case 'x': {
string_uint16_to_hex(va_arg(args, uint64_t), limit - ri, output + ri);
while (output[ri]) {
ri++;
}
fi += 3;
break;
}
case 'h': {
switch (format[fi + 3]) {
case 'x': {
string_uint8_to_hex(va_arg(args, uint64_t), limit - ri, output + ri);
while (output[ri]) {
ri++;
}
fi += 4;
break;
}
default: {
output[ri++] = format[fi++];
output[ri++] = format[fi++];
output[ri++] = format[fi++];
output[ri++] = format[fi++];
break;
}
}
break;
}
default: {
output[ri++] = format[fi++];
output[ri++] = format[fi++];
output[ri++] = format[fi++];
break;
}
}
break;
}
case 'l': {
switch (format[fi + 2]) {
case 'x': {
string_uint64_to_hex(va_arg(args, uint64_t), limit - ri, output + ri);
while (output[ri]) {
ri++;
}
fi += 3;
break;
}
default: {
output[ri++] = format[fi++];
output[ri++] = format[fi++];
output[ri++] = format[fi++];
break;
}
}
break;
}
default: {
output[ri++] = format[fi++]; output[ri++] = format[fi++];
output[ri++] = format[fi++]; output[ri++] = format[fi++];
break; break;
} }
}
} }
} }
output[ri] = '\0'; output[ri] = '\0';
+3 -9
View File
@@ -10,20 +10,14 @@ uint64_t string_length(const char *s);
uint8_t string_equal(const char *l, const char *r); uint8_t string_equal(const char *l, const char *r);
uint64_t string_trim(char *string, char character, char **result);
uint64_t string_split(char *string, char separator, uint64_t max, char **result); uint64_t string_split(char *string, char separator, uint64_t max, char **result);
uint64_t string_uint8_to_hex(uint8_t value, uint64_t max, char *result); uint64_t string_byte_to_hex(uint8_t value, uint64_t max, char *result);
uint64_t string_uint16_to_hex(uint16_t value, uint64_t max, char *result);
uint64_t string_uint32_to_hex(uint32_t value, uint64_t max, char *result);
uint64_t string_uint64_to_hex(uint64_t value, uint64_t max, char *result);
uint64_t string_uint_to_decimal(uint64_t value, uint64_t max, char *result); uint64_t string_uint_to_decimal(uint64_t value, uint64_t max, char *result);
uint64_t string_int_to_decimal(int64_t value, uint64_t max, char *result); uint64_t string_int_to_decimal(int64_t value, uint64_t max, char *result);
uint64_t string_uint_to_hex(uint64_t value, uint64_t max, char *result);
uint64_t string_format(const char *format, uint64_t max, char *output, ...); uint64_t string_format(const char *format, uint64_t max, char *output, ...);
-17
View File
@@ -1,17 +0,0 @@
#define SYSCALL_READ 0
#define SYSCALL_WRITE 1
#define SYSCALL_GETCWD 2
#define SYSCALL_CHDIR 3
#define SYSCALL_SPAWN 4
#define SYSCALL_WAIT 5
#define SYSCALL_OPEN 6
#define SYSCALL_CLOSE 7
#define SYSCALL_TRUNCATE 8
#define SYSCALL_REMOVE 9
#define SYSCALL_PIPE 10
#define SYSCALL_EXIT 60
#define OPEN_CREATE 0b0001
#define OPEN_EXCLUSIVE 0b0010
#define OPEN_FILE 0b0100
#define OPEN_DIRECTORY 0b1000
-13
View File
@@ -4,21 +4,8 @@
#define NUL 0 // TODO Fix VSCode thinking `NULL` conflicts with some other definition. #define NUL 0 // TODO Fix VSCode thinking `NULL` conflicts with some other definition.
#define ONES(h, l) ((1ULL << ((h) - (l) + 1)) - 1)
#define BITS_R(s, h, l) (((s) >> (l)) & ONES(h, l))
#define BITS_W(s, h, l, v) ((s) = (__typeof__(s))(((s) & ~(ONES(h, l) << (l))) | (((v) & ONES(h, l)) << (l))))
#define STDIN 0
#define STDOUT 1
#define STDERR 2
typedef uint64_t exit_code_t; typedef uint64_t exit_code_t;
#define EXIT_CODE_OK 0 #define EXIT_CODE_OK 0
#define EXIT_CODE_NOT_FOUND ((uint64_t)-2) #define EXIT_CODE_NOT_FOUND ((uint64_t)-2)
#define EXIT_CODE_GENERAL_FAILURE ((uint64_t)-1) #define EXIT_CODE_GENERAL_FAILURE ((uint64_t)-1)
static inline void sleep(uint64_t ms) {
for (volatile uint64_t i = 1000000 * ms; i; i--) // Very approximately
;
}
+13
View File
@@ -19,6 +19,19 @@ load_bootloader:
jmp 0x8000 jmp 0x8000
times 446 - ($ - $$) db 0
partition_table:
partition_1:
.bootable: db 0x80
.chs_start: db 0x20, 0x21, 0x00
.type: db 0x06
.chs_end: db 0xFF, 0xFF, 0xFF
.lba_start: dd 0x00000800
.lba_size dd 0x00005000
partition_1_end:
partition_table_end:
times 510 - ($ - $$) db 0 times 510 - ($ - $$) db 0
boot_signature: boot_signature:
+16 -19
View File
@@ -1,41 +1,38 @@
#include "src/lib/syscall.h"
#include "src/lib/util.h" #include "src/lib/util.h"
#include "src/user/syscall.h" #include "src/user/syscall.h"
#define BLOCK_SIZE 65536 #define BLOCK_SIZE 65536
exit_code_t pass(uint64_t fd) { #define PRINT_S(s) write(1, s, sizeof(s) - 1);
#define PRINT_D(s) write(1, s, string_length(s));
exit_code_t cat(const char *path) {
uint64_t fd = open(path);
if (fd == (uint64_t)-1) {
PRINT_S("cat: path does not exist\n");
return EXIT_CODE_GENERAL_FAILURE;
}
static char buffer[BLOCK_SIZE]; static char buffer[BLOCK_SIZE];
uint64_t bytes; uint64_t bytes;
while ((bytes = read(fd, BLOCK_SIZE, buffer))) { while ((bytes = read(fd, BLOCK_SIZE, buffer))) {
if (bytes == (uint64_t)-1) { if (bytes == (uint64_t)-1) {
ERR_S("cat: could not read file\n"); PRINT_S("cat: could not read file\n");
close(fd);
return EXIT_CODE_GENERAL_FAILURE; return EXIT_CODE_GENERAL_FAILURE;
} }
write(STDOUT, buffer, bytes); write(1, buffer, bytes);
} }
return EXIT_CODE_OK;
}
exit_code_t cat(const char *path) {
uint64_t fd = open(path, OPEN_FILE);
if (fd == (uint64_t)-1) {
ERR_S("cat: path does not exist\n");
return EXIT_CODE_GENERAL_FAILURE;
}
exit_code_t code = pass(fd);
close(fd); close(fd);
return code; return 0;
} }
exit_code_t main(uint64_t argc, const char **argv) { exit_code_t main(uint64_t argc, const char **argv) {
if (argc == 1) { if (argc == 1) {
return pass(0); return cat(".");
} }
uint64_t code = EXIT_CODE_OK; uint64_t code = EXIT_CODE_OK;
+10 -9
View File
@@ -1,30 +1,31 @@
#include "src/lib/syscall.h"
#include "src/lib/util.h" #include "src/lib/util.h"
#include "src/user/syscall.h" #include "src/user/syscall.h"
#define BLOCK_SIZE 65536 #define BLOCK_SIZE 65536
#define PRINT_S(s) write(1, s, sizeof(s) - 1);
#define PRINT_D(s) write(1, s, string_length(s));
exit_code_t main(uint64_t argc, const char **argv) { exit_code_t main(uint64_t argc, const char **argv) {
if (argc != 3) { if (argc != 3) {
ERR_S("cp: requires source and target\n"); PRINT_S("cp: requires source and target");
return EXIT_CODE_GENERAL_FAILURE; return EXIT_CODE_GENERAL_FAILURE;
} }
uint64_t source = open(argv[1], OPEN_FILE); uint64_t source = open(argv[1]);
if (source == (uint64_t)-1) { if (source == (uint64_t)-1) {
ERR_S("cp: source does not exist\n"); PRINT_S("cp: source does not exist\n");
return EXIT_CODE_GENERAL_FAILURE; return EXIT_CODE_GENERAL_FAILURE;
} }
uint64_t target = open(argv[2], OPEN_FILE | OPEN_CREATE); uint64_t target = open(argv[2]);
if (target == (uint64_t)-1) { if (target == (uint64_t)-1) {
ERR_S("cp: target path does not exist\n"); PRINT_S("cp: target does not exist\n");
close(source); close(source);
return EXIT_CODE_GENERAL_FAILURE; return EXIT_CODE_GENERAL_FAILURE;
} }
if (truncate(target, 0) == (uint64_t)-1) { if (truncate(target, 0) == (uint64_t)-1) {
ERR_S("cp: could not write file\n");
close(source); close(source);
close(target); close(target);
return EXIT_CODE_GENERAL_FAILURE; return EXIT_CODE_GENERAL_FAILURE;
@@ -34,13 +35,13 @@ exit_code_t main(uint64_t argc, const char **argv) {
uint64_t bytes; uint64_t bytes;
while ((bytes = read(source, BLOCK_SIZE, buffer))) { while ((bytes = read(source, BLOCK_SIZE, buffer))) {
if (bytes == (uint64_t)-1) { if (bytes == (uint64_t)-1) {
ERR_S("cp: could not read file\n"); PRINT_S("cp: could not read file\n");
close(source); close(source);
close(target); close(target);
return EXIT_CODE_GENERAL_FAILURE; return EXIT_CODE_GENERAL_FAILURE;
} }
if (write(target, buffer, bytes) == (uint64_t)-1) { if (write(target, buffer, bytes) == (uint64_t)-1) {
ERR_S("cp: could not write file\n"); PRINT_S("cp: could not write file\n");
close(source); close(source);
close(target); close(target);
return EXIT_CODE_GENERAL_FAILURE; return EXIT_CODE_GENERAL_FAILURE;
+4 -4
View File
@@ -1,14 +1,14 @@
#include "src/lib/string.h"
#include "src/lib/util.h" #include "src/lib/util.h"
#include "src/user/syscall.h" #include "src/user/syscall.h"
exit_code_t main(uint64_t argc, const char **argv) { exit_code_t main(uint64_t argc, const char **argv) {
for (uint64_t i = 1; i < argc; i++) { for (uint64_t i = 1; i < argc; i++) {
if (i > 1) { if (i > 1) {
OUT_S(" "); write(1, " ", 1);
} }
OUT_D(argv[i]); write(1, argv[i], string_length(argv[i]));
} }
OUT_S("\n"); write(1, "\n", 1);
return EXIT_CODE_OK; return EXIT_CODE_OK;
} }
+13 -12
View File
@@ -1,27 +1,28 @@
#include "src/lib/syscall.h" #include "src/lib/string.h"
#include "src/lib/util.h" #include "src/lib/util.h"
#include "src/user/syscall.h" #include "src/user/syscall.h"
#define BLOCK_SIZE 256 #define PRINT_S(s) write(1, s, sizeof(s) - 1);
#define PRINT_D(s) write(1, s, string_length(s));
exit_code_t ls(const char *path) { exit_code_t ls(const char *path) {
uint64_t fd = open(path, OPEN_DIRECTORY); uint64_t fd = open(path);
if (fd == (uint64_t)-1) { if (fd == (uint64_t)-1) {
ERR_S("ls: path does not exist\n"); PRINT_S("ls: path does not exist\n");
return EXIT_CODE_GENERAL_FAILURE; return EXIT_CODE_GENERAL_FAILURE;
} }
char buffer[BLOCK_SIZE]; char buffer[100];
uint64_t bytes; uint64_t bytes;
while ((bytes = read(fd, BLOCK_SIZE, buffer))) { while ((bytes = read(fd, 100, buffer))) {
if (bytes == (uint64_t)-1) { if (bytes == (uint64_t)-1) {
ERR_S("ls: could not read directory\n"); PRINT_S("ls: could not read directory\n");
close(fd); close(fd);
return EXIT_CODE_GENERAL_FAILURE; return EXIT_CODE_GENERAL_FAILURE;
} }
write(STDOUT, buffer, bytes); write(1, buffer, bytes - 1);
OUT_S("\n"); PRINT_S("\n");
} }
close(fd); close(fd);
@@ -37,9 +38,9 @@ exit_code_t main(uint64_t argc, const char **argv) {
exit_code_t code = EXIT_CODE_OK; exit_code_t code = EXIT_CODE_OK;
for (uint64_t i = 1; i < argc; i++) { for (uint64_t i = 1; i < argc; i++) {
if (argc > 2) { if (argc > 2) {
OUT_S("\n"); PRINT_S("\n");
OUT_D(argv[i]); PRINT_D(argv[i]);
OUT_S(":\n"); PRINT_S(":\n");
} }
exit_code_t c = ls(argv[i]); exit_code_t c = ls(argv[i]);
if (c != EXIT_CODE_OK) { if (c != EXIT_CODE_OK) {
-23
View File
@@ -1,23 +0,0 @@
#include "src/lib/syscall.h"
#include "src/lib/util.h"
#include "src/user/syscall.h"
exit_code_t main(uint64_t argc, const char **argv) {
if (argc < 2) {
ERR_S("mkdir: requires target(s)\n");
return EXIT_CODE_GENERAL_FAILURE;
}
exit_code_t code = EXIT_CODE_OK;
for (uint64_t i = 1; i < argc; i++) {
uint64_t fd = open(argv[i], OPEN_DIRECTORY | OPEN_CREATE | OPEN_EXCLUSIVE);
if (fd == (uint64_t)-1) {
ERR_S("mkdir: could not create directory\n");
code = EXIT_CODE_GENERAL_FAILURE;
} else {
close(fd);
}
}
return code;
}
-20
View File
@@ -1,20 +0,0 @@
#include "src/lib/syscall.h"
#include "src/lib/util.h"
#include "src/user/syscall.h"
exit_code_t main(uint64_t argc, const char **argv) {
if (argc < 2) {
ERR_S("rm: requires one or more arguments\n");
return EXIT_CODE_GENERAL_FAILURE;
}
uint64_t code = EXIT_CODE_OK;
for (uint64_t i = 1; i < argc; i++) {
if (remove(argv[i]) == (uint64_t)-1) {
ERR_S("rm: could not remove file\n");
code = EXIT_CODE_GENERAL_FAILURE;
}
}
return code;
}
+42 -110
View File
@@ -3,15 +3,15 @@
#include "src/lib/util.h" #include "src/lib/util.h"
#include "src/user/syscall.h" #include "src/user/syscall.h"
static exit_code_t help(uint8_t argc, char **argv, uint64_t stdin, uint64_t stdout); static void help(uint8_t argc, char **argv);
static exit_code_t cd(uint8_t argc, char **argv, uint64_t stdin, uint64_t stdout); static void cd(uint8_t argc, char **argv);
#define PATH "/bin/" #define PATH "/bin/"
#define WRITE_S(o, s) write(o, s, sizeof(s) - 1); #define PRINT_S(s) write(1, s, sizeof(s) - 1);
#define WRITE_D(o, s) write(o, s, string_length(s)); #define PRINT_D(s) write(1, s, string_length(s));
typedef exit_code_t (*app_t)(uint8_t argc, char **argv, uint64_t stdin, uint64_t stdout); typedef void (*app_t)(uint8_t argc, char **argv);
typedef struct { typedef struct {
const char *name; const char *name;
@@ -23,33 +23,28 @@ static app_entry_t builtins[] = {
{"cd", cd}, {"cd", cd},
}; };
static exit_code_t help(uint8_t argc, __attribute__((unused)) char **argv, __attribute__((unused)) uint64_t stdin, uint64_t stdout) { static void help(uint8_t argc, __attribute__((unused)) char **argv) {
if (argc > 1) { if (argc > 1) {
ERR_S("help: expects no arguments\n"); PRINT_S("help: expects no arguments");
return EXIT_CODE_GENERAL_FAILURE; return;
} }
WRITE_S(stdout, "Available commands:\n"); PRINT_S("Available commands:\n");
for (uint64_t i = 0; i < sizeof(builtins) / sizeof(app_entry_t); i++) { for (uint64_t i = 0; i < sizeof(builtins) / sizeof(app_entry_t); i++) {
WRITE_D(stdout, builtins[i].name); PRINT_D(builtins[i].name);
WRITE_S(stdout, "\n"); PRINT_S("\n");
} }
return EXIT_CODE_OK;
} }
static exit_code_t cd(uint8_t argc, char **argv, __attribute__((unused)) uint64_t stdin, __attribute__((unused)) uint64_t stdout) { static void cd(uint8_t argc, char **argv) {
if (argc != 2) { if (argc != 2) {
ERR_S("cd: requires a single path\n"); PRINT_S("cd: requires a single path\n");
return EXIT_CODE_GENERAL_FAILURE; return;
} }
if (chdir(argv[1]) == (uint64_t)-1) { if (chdir(argv[1]) == (uint64_t)-1) {
ERR_S("cd: path does not exist\n"); PRINT_S("cd: path does not exist\n");
return EXIT_CODE_GENERAL_FAILURE;
} }
return EXIT_CODE_OK;
} }
static void print_prompt() { static void print_prompt() {
@@ -58,23 +53,16 @@ static void print_prompt() {
char *components[16]; char *components[16];
uint8_t cl = string_split(path, '/', 16, components); uint8_t cl = string_split(path, '/', 16, components);
OUT_S("[") PRINT_S("[")
OUT_D(pl == 1 ? "/" : components[cl - 1]); PRINT_D(pl == 1 ? "/" : components[cl - 1]);
OUT_S("]$ "); PRINT_S("]$ ");
}
static void free_fds(uint64_t *fds, uint8_t fds_count) {
for (uint8_t i = 0; i < fds_count; i++) {
close(fds[i]);
}
}
static void kill_pids(__attribute__((unused)) uint64_t *pids, __attribute__((unused)) uint8_t pid_count) {
// TODO.
} }
static void execute(char *command) { static void execute(char *command) {
OUT_S("\n"); char *argv[16];
uint8_t argc = (uint8_t)string_split(command, ' ', 16, argv);
PRINT_S("\n");
if (string_equal(command, "^C")) { if (string_equal(command, "^C")) {
print_prompt(); print_prompt();
@@ -83,95 +71,39 @@ static void execute(char *command) {
if (string_equal(command, "^D")) { if (string_equal(command, "^D")) {
exit(EXIT_CODE_OK); exit(EXIT_CODE_OK);
return;
} }
char *subcommands[16]; uint8_t i;
uint8_t subcommands_count = (uint8_t)string_split(command, '|', 16, subcommands); for (i = 0; i < sizeof(builtins) / sizeof(app_entry_t); i++) {
if (string_equal(argv[0], builtins[i].name)) {
uint64_t fds[32]; builtins[i].app(argc, argv);
uint8_t fds_count = 0;
uint64_t pids[16];
uint8_t pids_count = 0;
for (uint8_t i = 0; i < subcommands_count; i++) {
if (!string_trim(subcommands[i], ' ', &subcommands[i])) {
if (subcommands_count > 1) {
ERR_S("Syntax error.\n");
}
break; break;
} }
}
if (i == sizeof(builtins) / sizeof(app_entry_t)) {
uint64_t size = sizeof(PATH) + string_length(argv[0]) + 1;
char *path = memory_allocate(size);
memory_copy(PATH, sizeof(PATH), path);
memory_copy(argv[0], size - sizeof(PATH), path + sizeof(PATH) - 1);
uint64_t pid = spawn(path, argc, (const char **)argv);
memory_free(path);
char *argv[16]; if (pid == EXIT_CODE_NOT_FOUND) {
uint8_t argc = (uint8_t)string_split(subcommands[i], ' ', 16, argv); PRINT_S("shell: program not found\n");
} else {
uint64_t stdin = 0; waitpid(pid);
uint64_t stdout = 1;
if (i > 0) {
stdin = fds[fds_count - 1];
}
if (i < subcommands_count - 1) {
if (pipe(&fds[fds_count], &fds[fds_count + 1]) == (uint64_t)-1) {
kill_pids(pids, pids_count);
free_fds(fds, fds_count);
print_prompt();
return;
}
fds_count += 2;
stdout = fds[fds_count - 2];
}
uint8_t j;
for (j = 0; j < sizeof(builtins) / sizeof(app_entry_t); j++) {
if (string_equal(argv[0], builtins[j].name)) {
builtins[j].app(argc, argv, stdin, stdout);
pids[pids_count++] = 0;
break;
}
}
if (j == sizeof(builtins) / sizeof(app_entry_t)) {
uint64_t size = sizeof(PATH) + string_length(argv[0]) + 1;
char *path = memory_allocate(size);
memory_copy(PATH, sizeof(PATH), path);
memory_copy(argv[0], size - sizeof(PATH), path + sizeof(PATH) - 1);
uint64_t pid = spawn(path, argc, (const char **)argv, stdin, stdout);
memory_free(path);
if (pid == (uint64_t)-1) {
kill_pids(pids, pids_count);
free_fds(fds, fds_count);
print_prompt();
return;
} else {
pids[pids_count++] = pid;
}
} }
} }
for (uint8_t i = 0; i < pids_count; i++) {
if (pids[i]) {
waitpid(pids[i]);
}
if (i > 0) {
close(fds[(i - 1) * 2 + 1]);
}
if (i < pids_count - 1) {
close(fds[i * 2]);
}
}
print_prompt(); print_prompt();
} }
exit_code_t main() { uint64_t main() {
ERR_S("Welcome to FreywarOS v" VERSION "!\n\n"); PRINT_D("Welcome to FreywarOS v" VERSION "!\n\n");
print_prompt(); print_prompt();
char line[256]; char line[256];
uint64_t offset = 0; uint64_t offset;
char chunk[64]; char chunk[64];
uint64_t received; uint64_t received;
@@ -188,5 +120,5 @@ exit_code_t main() {
} }
} }
return EXIT_CODE_OK; return 0;
} }
+18 -15
View File
@@ -2,6 +2,9 @@
#include "src/lib/util.h" #include "src/lib/util.h"
#include "src/user/syscall.h" #include "src/user/syscall.h"
#define PRINT_S(s) write(1, s, sizeof(s) - 1);
#define PRINT_D(s) write(1, s, string_length(s));
#define PROMPT_LENGTH 255 #define PROMPT_LENGTH 255
static const char bs[PROMPT_LENGTH + 1]; static const char bs[PROMPT_LENGTH + 1];
@@ -16,7 +19,7 @@ static void on_home_pressed() {
return; return;
} }
write(STDOUT, bs, prompt_offset); write(1, bs, prompt_offset);
prompt_offset = 0; prompt_offset = 0;
} }
@@ -25,7 +28,7 @@ static void on_left_pressed() {
return; return;
} }
write(STDOUT, bs, 1); write(1, bs, 1);
prompt_offset--; prompt_offset--;
} }
@@ -34,7 +37,7 @@ static void on_right_pressed() {
return; return;
} }
write(STDOUT, prompt + prompt_offset, 1); write(1, prompt + prompt_offset, 1);
prompt_offset++; prompt_offset++;
} }
@@ -43,27 +46,27 @@ static void on_end_pressed() {
return; return;
} }
write(STDOUT, prompt + prompt_offset, prompt_length - prompt_offset); write(1, prompt + prompt_offset, prompt_length - prompt_offset);
prompt_offset = prompt_length; prompt_offset = prompt_length;
} }
static void on_enter_pressed() { static void on_enter_pressed() {
prompt[prompt_length] = '\n'; prompt[prompt_length] = '\n';
write(3, prompt, prompt_length + 1); write(2, prompt, prompt_length + 1);
prompt_length = prompt_offset = 0; prompt_length = prompt_offset = 0;
} }
static void on_cancel_pressed() { static void on_cancel_pressed() {
OUT_S("^C\n"); PRINT_S("^C\n");
write(3, "^C\n", 3); write(2, "^C\n", 3);
prompt_length = prompt_offset = 0; prompt_length = prompt_offset = 0;
} }
static void on_disconnect_pressed() { static void on_disconnect_pressed() {
OUT_S("^D\n"); PRINT_S("^D\n");
write(3, "^D\n", 3); write(2, "^D\n", 3);
exit(EXIT_CODE_OK); exit(EXIT_CODE_OK);
} }
@@ -77,9 +80,9 @@ static void on_ctrl_character_pressed(char c) {
static void redraw_from_cursor() { static void redraw_from_cursor() {
uint64_t tail = prompt_length - prompt_offset; uint64_t tail = prompt_length - prompt_offset;
write(STDOUT, prompt + prompt_offset, tail); write(1, prompt + prompt_offset, tail);
write(STDOUT, ws, 1); // erase the character past the end write(1, ws, 1); // erase the character past the end
write(STDOUT, bs, tail + 1); // move back to cursor position write(1, bs, tail + 1); // move back to cursor position
} }
static void on_character_pressed(char c) { static void on_character_pressed(char c) {
@@ -93,7 +96,7 @@ static void on_character_pressed(char c) {
prompt_length++; prompt_length++;
prompt_offset++; prompt_offset++;
write(STDOUT, &c, 1); // emit the character itself write(1, &c, 1); // emit the character itself
redraw_from_cursor(); redraw_from_cursor();
} }
@@ -107,7 +110,7 @@ static void on_backspace_pressed() {
prompt_offset--; prompt_offset--;
prompt_length--; prompt_length--;
write(STDOUT, bs, 1); write(1, bs, 1);
redraw_from_cursor(); redraw_from_cursor();
} }
@@ -194,7 +197,7 @@ uint64_t main() {
memory_set(' ', PROMPT_LENGTH, (char *)ws); memory_set(' ', PROMPT_LENGTH, (char *)ws);
char c; char c;
while (read(STDIN, 1, &c)) { while (read(0, 1, &c)) {
on_char_received(c); on_char_received(c);
} }
-56
View File
@@ -1,56 +0,0 @@
#include "src/lib/string.h"
#include "src/lib/syscall.h"
#include "src/lib/util.h"
#include "src/user/syscall.h"
#define BLOCK_SIZE 65536
exit_code_t pass(uint64_t fd) {
static char buffer[BLOCK_SIZE];
uint64_t bytes;
uint64_t total = 0;
while ((bytes = read(fd, BLOCK_SIZE, buffer))) {
if (bytes == (uint64_t)-1) {
ERR_S("wc: could not read file\n");
return EXIT_CODE_GENERAL_FAILURE;
} else {
total += bytes;
}
}
uint64_t l = string_format("%d\n", BLOCK_SIZE, buffer, total);
write(STDOUT, buffer, l);
return EXIT_CODE_OK;
}
exit_code_t wc(const char *path) {
uint64_t fd = open(path, OPEN_FILE);
if (fd == (uint64_t)-1) {
OUT_S("wc: path does not exist\n");
return EXIT_CODE_GENERAL_FAILURE;
}
exit_code_t code = pass(fd);
close(fd);
return code;
}
exit_code_t main(uint64_t argc, const char **argv) {
if (argc == 1) {
return pass(0);
}
uint64_t code = EXIT_CODE_OK;
for (uint64_t i = 1; i < argc; i++) {
exit_code_t c = wc(argv[i]);
if (c != EXIT_CODE_OK) {
code = c;
}
}
return code;
}
+4 -3
View File
@@ -3,7 +3,8 @@ ENTRY(_start)
SECTIONS { SECTIONS {
. = 0x0000000000400000; . = 0x0000000000400000;
.text : { *(.text*) } .text : { *(.text) }
.rodata : { *(.rodata*) *(.lrodata*) } .rodata : { *(.rodata) }
.data : { *(.data*) *(.ldata*) *(.bss*) *(.lbss*) } .data : { *(.data) }
.bss : { *(.bss) }
} }
-24
View File
@@ -3,83 +3,59 @@ bits 64
global read global read
read: read:
mov rax, 0 mov rax, 0
mov r10, rcx
syscall syscall
ret ret
global write global write
write: write:
mov rax, 1 mov rax, 1
mov r10, rcx
syscall syscall
ret ret
global getcwd global getcwd
getcwd: getcwd:
mov rax, 2 mov rax, 2
mov r10, rcx
syscall syscall
ret ret
global chdir global chdir
chdir: chdir:
mov rax, 3 mov rax, 3
mov r10, rcx
syscall syscall
ret ret
global spawn global spawn
spawn: spawn:
mov rax, 4 mov rax, 4
mov r10, rcx
syscall syscall
ret ret
global waitpid global waitpid
waitpid: waitpid:
mov rax, 5 mov rax, 5
mov r10, rcx
syscall syscall
ret ret
global open global open
open: open:
mov rax, 6 mov rax, 6
mov r10, rcx
syscall syscall
ret ret
global close global close
close: close:
mov rax, 7 mov rax, 7
mov r10, rcx
syscall syscall
ret ret
global truncate global truncate
truncate: truncate:
mov rax, 8 mov rax, 8
mov r10, rcx
syscall
ret
global remove
remove:
mov rax, 9
mov r10, rcx
syscall
ret
global pipe
pipe:
mov rax, 10
mov r10, rcx
syscall syscall
ret ret
global exit global exit
exit: exit:
mov rax, 60 mov rax, 60
mov r10, rcx
syscall syscall
; never returns ; never returns
+3 -13
View File
@@ -1,13 +1,7 @@
#pragma once #pragma once
#include "src/lib/util.h" #include "src/lib/util.h"
#include "src/lib/string.h" #include <stdint.h>
#define OUT_S(s) write(STDOUT, s, sizeof(s) - 1);
#define OUT_D(s) write(STDOUT, s, string_length(s));
#define ERR_S(s) write(STDERR, s, sizeof(s) - 1);
#define ERR_D(s) write(STDERR, s, string_length(s));
uint64_t read(int64_t fd, uint64_t max, void *to); uint64_t read(int64_t fd, uint64_t max, void *to);
@@ -17,18 +11,14 @@ uint64_t getcwd(uint64_t max, void *to);
uint64_t chdir(const char *path); uint64_t chdir(const char *path);
uint64_t spawn(const char *path, uint64_t argc, const char **argv, uint64_t stdin, uint64_t stdout); uint64_t spawn(const char *path, uint64_t argc, const char **argv);
exit_code_t waitpid(uint64_t pid); exit_code_t waitpid(uint64_t pid);
uint64_t open(const char *path, uint64_t flags); uint64_t open(const char *path);
uint64_t close(uint64_t fd); uint64_t close(uint64_t fd);
uint64_t truncate(uint64_t fd, uint64_t size); uint64_t truncate(uint64_t fd, uint64_t size);
uint64_t remove(const char *path);
uint64_t pipe(uint64_t *write_fd, uint64_t *read_fd);
void exit(exit_code_t code); void exit(exit_code_t code);
+1 -5
View File
@@ -9,10 +9,6 @@ fi
qemu-system-x86_64 \ qemu-system-x86_64 \
"${debug_flags[@]}" \ "${debug_flags[@]}" \
-monitor stdio \ -monitor stdio \
-drive file=build/os.raw,format=raw,if=none,id=nvme0 \ -drive file="build/os.img",format=raw,if=ide \
-device nvme,drive=nvme0,serial=foo \
-device qemu-xhci,id=xhci,msi=off,msix=off \
-device usb-kbd,bus=xhci.0 \
-no-reboot \ -no-reboot \
-trace "*xhci*" \
-d int -d int