Compare commits

...
3 Commits
Author SHA1 Message Date
freywar 7d274da197 Finalize xHCI and USB modules
Scratchpad buffers allocation added to xHCI. Missing initialization steps
for keyboards - set configuration and set idle - added to USB. (Even
though they are specific to HID protocol, they go through USB command
endpoint, and with current module contents it's cleaner to have them
in USB module.)
2026-08-25 21:20:53 +03:00
freywar a3240d9316 Fix LOG_X usage crashing the system
Each `LOG_X` call declared a rather huge variable on the stack,
and using it to dump a whole structure often led to a page fault.
Now the temporary variables are `static`, which is a bit wasteful
on the kernel binary size, but easier to maintain.

Additionally bootloader updated to load kernels bigger than 64K.
2026-08-25 17:20:34 +03:00
freywar c92ccd41ce Improve installation process
`meson.build` rewritten with DRY principle. `deploy.sh` added,
which deploys the image on a installation USB stick borrowed from
another project. Image name aligned with the installer's expectations.
2026-08-25 17:14:50 +03:00
10 changed files with 175 additions and 435 deletions
+16 -16
View File
@@ -18,19 +18,19 @@ meson compile -v -C build
sector_size=512 sector_size=512
partition_offset=2048 partition_offset=2048
dd if=/dev/zero of=build/os.img bs="${sector_size}" count="$((partition_offset + 20480))" dd if=/dev/zero of=build/os.raw bs="${sector_size}" count="$((partition_offset + 20480))"
dd if=build/mbr.bin of=build/os.img bs="${sector_size}" count=1 conv=notrunc dd if=build/mbr.bin of=build/os.raw bs="${sector_size}" count=1 conv=notrunc
dd if=build/bootloader.bin of=build/os.img bs="${sector_size}" seek=1 count="$((partition_offset - 1))" conv=notrunc dd if=build/bootloader.bin of=build/os.raw bs="${sector_size}" seek=1 count="$((partition_offset - 1))" conv=notrunc
mkfs.fat -F 16 --offset "${partition_offset}" build/os.img mkfs.fat -F 16 --offset "${partition_offset}" build/os.raw
mcopy -i build/os.img@@"$((partition_offset * sector_size))" -s src ::src mcopy -i build/os.raw@@"$((partition_offset * sector_size))" -s src ::src
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/kernel.bin ::kernel.bin mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/kernel.bin ::kernel.bin
mmd -i build/os.img@@"$((partition_offset * sector_size))" ::bin mmd -i build/os.raw@@"$((partition_offset * sector_size))" ::bin
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/terminal ::bin/terminal mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/terminal ::bin/terminal
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/shell ::bin/shell mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/shell ::bin/shell
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/echo ::bin/echo mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/echo ::bin/echo
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/ls ::bin/ls mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/ls ::bin/ls
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/cat ::bin/cat mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/cat ::bin/cat
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/cp ::bin/cp mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/cp ::bin/cp
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/mkdir ::bin/mkdir mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/mkdir ::bin/mkdir
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/rm ::bin/rm mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/rm ::bin/rm
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/wc ::bin/wc mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/wc ::bin/wc
Executable
+19
View File
@@ -0,0 +1,19 @@
#!/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
+52 -352
View File
@@ -92,20 +92,25 @@ kernel_sources = files([
'src/kernel/xhci.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: [
'-ffreestanding', c_args,
'-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',
@@ -122,353 +127,48 @@ custom_target(
build_by_default: true, build_by_default: true,
) )
terminal_start = custom_target( foreach app : ['terminal', 'shell', 'echo', 'ls', 'cat', 'cp', 'mkdir', 'rm', 'wc']
'terminal_start', start = custom_target(
input: 'src/user/start.asm', f'@app@_start',
output: 'terminal_start.o', input: 'src/user/start.asm',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'], output: f'@app@_start.o',
) command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
terminal_syscall = custom_target( syscall = custom_target(
'terminal_syscall', f'@app@_syscall',
input: 'src/user/syscall.asm', input: 'src/user/syscall.asm',
output: 'terminal_syscall.o', output: f'@app@_syscall.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'], command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
) )
terminal_elf = executable( elf = executable(
'terminal.elf', f'@app@.elf',
sources: [terminal_start, terminal_syscall, lib_sources, 'src/user/app/terminal/terminal.c'], sources: [start, syscall, lib_sources, f'src/user/app/@app@/@app@.c'],
c_args: [ c_args: [
'-ffreestanding', c_args,
'-nostdlib', '-mcmodel=large',
'-fno-stack-protector', ],
'-mcmodel=large', link_args: [
'-DVERSION="' + meson.project_version() + '"', '-T', meson.project_source_root() / 'src/user/linker.ld',
], '-nostdlib',
link_args: [ ],
'-T', meson.project_source_root() / 'src/user/linker.ld', link_depends: 'src/user/linker.ld',
'-nostdlib', )
],
link_depends: 'src/user/linker.ld',
)
custom_target( elf_data = custom_target(
'terminal', f'@app@_data.elf',
input: terminal_elf, input: elf,
output: 'terminal', output: f'@app@_data.elf',
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'], command: ['objcopy', '--set-section-flags', '.data=alloc,load,contents', '@INPUT@', '@OUTPUT@'],
build_by_default: true, build_by_default: true,
) )
shell_start = custom_target( custom_target(
'shell_start', app,
input: 'src/user/start.asm', input: elf_data,
output: 'shell_start.o', output: app,
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'], command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
) build_by_default: true,
)
shell_syscall = custom_target( endforeach
'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,
)
mkdir_start = custom_target(
'mkdir_start',
input: 'src/user/start.asm',
output: 'mkdir_start.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
mkdir_syscall = custom_target(
'mkdir_syscall',
input: 'src/user/syscall.asm',
output: 'mkdir_syscall.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
mkdir_elf = executable(
'mkdir.elf',
sources: [mkdir_start, mkdir_syscall, lib_sources, 'src/user/app/mkdir/mkdir.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(
'mkdir',
input: mkdir_elf,
output: 'mkdir',
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
build_by_default: true,
)
rm_start = custom_target(
'rm_start',
input: 'src/user/start.asm',
output: 'rm_start.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
rm_syscall = custom_target(
'rm_syscall',
input: 'src/user/syscall.asm',
output: 'rm_syscall.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
rm_elf = executable(
'rm.elf',
sources: [rm_start, rm_syscall, lib_sources, 'src/user/app/rm/rm.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(
'rm',
input: rm_elf,
output: 'rm',
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
build_by_default: true,
)
wc_start = custom_target(
'wc_start',
input: 'src/user/start.asm',
output: 'wc_start.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
wc_syscall = custom_target(
'wc_syscall',
input: 'src/user/syscall.asm',
output: 'wc_syscall.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
wc_elf = executable(
'wc.elf',
sources: [wc_start, wc_syscall, lib_sources, 'src/user/app/wc/wc.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(
'wc',
input: wc_elf,
output: 'wc',
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
build_by_default: true,
)
+7 -5
View File
@@ -10,7 +10,6 @@ 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
@@ -39,9 +38,10 @@ 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_offset: dw 0 kernel_buffer_segment: dw 0x2000
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,6 +201,8 @@ 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
+1
View File
@@ -170,6 +170,7 @@ static uint64_t stream_read(__attribute__((unused)) stream_t *self, uint64_t max
} }
buffer_length -= size; buffer_length -= size;
buffer_offset = (buffer_offset + size) % BUFFER_SIZE; buffer_offset = (buffer_offset + size) % BUFFER_SIZE;
return size; return size;
} }
+34 -46
View File
@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "src/kernel/stream.h" #include "src/kernel/stream.h"
#include "src/lib/memory.h"
#include "src/lib/string.h" #include "src/lib/string.h"
extern stream_t *kernel_log; extern stream_t *kernel_log;
@@ -15,58 +14,47 @@ extern stream_t *kernel_log;
#define LOG_LEVEL_DATA 3 #define LOG_LEVEL_DATA 3
#define LOG_LEVEL_TRACE 4 #define LOG_LEVEL_TRACE 4
static uint64_t print_size;
static char print_buffer[512];
#define PRINT(stream, fmt, ...) \ #define PRINT(stream, fmt, ...) \
do { \ print_size = string_format(fmt, sizeof(print_buffer) - 1, print_buffer, ##__VA_ARGS__); \
uint64_t _size = string_length(fmt) * 10; \ stream->write(stream, print_buffer, print_size);
char *_string = memory_allocate(_size); \
_size = string_format(fmt, _size, _string, ##__VA_ARGS__); \
stream->write(stream, _string, _size); \
memory_free(_string); \
} while (0);
#define PRINT_LN(stream, fmt, ...) \ #define PRINT_LN(stream, fmt, ...) \
do { \ print_size = string_format(fmt, sizeof(print_buffer) - 1, print_buffer, ##__VA_ARGS__); \
uint64_t _size = string_length(fmt) * 10; \ stream->write(stream, __func__, string_length(__func__)); \
char *_string = memory_allocate(_size); \ stream->write(stream, ": ", 2); \
_size = string_format(fmt, _size, _string, ##__VA_ARGS__); \ stream->write(stream, print_buffer, print_size); \
stream->write(stream, __func__, string_length(__func__)); \ stream->write(stream, "\n", 1);
stream->write(stream, ": ", 2); \
stream->write(stream, _string, _size); \
stream->write(stream, "\n", 1); \
memory_free(_string); \
} while (0);
#define PRINT_VAL(stream, v, f) PRINT_LN(#v = f, v) #define PRINT_VAL(stream, v, f) PRINT_LN(#v = f, v)
#define LOG_INFO(fmt, ...) \ #define LOG(level, fmt, ...) \
if (LOG_LEVEL >= LOG_LEVEL_INFO) \ if (LOG_LEVEL >= level) { \
PRINT(kernel_log, fmt, ##__VA_ARGS__) PRINT(kernel_log, fmt, ##__VA_ARGS__) \
#define LOG_STEP(fmt, ...) \ }
if (LOG_LEVEL >= LOG_LEVEL_STEP) \
PRINT(kernel_log, fmt, ##__VA_ARGS__)
#define LOG_DATA(fmt, ...) \
if (LOG_LEVEL >= LOG_LEVEL_DATA) \
PRINT(kernel_log, fmt, ##__VA_ARGS__)
#define LOG_TRACE(fmt, ...) \
if (LOG_LEVEL >= LOG_LEVEL_TRACE) \
PRINT(kernel_log, fmt, ##__VA_ARGS__)
#define LOG_LN_INFO(fmt, ...) \ #define LOG_LN(level, fmt, ...) \
if (LOG_LEVEL >= LOG_LEVEL_INFO) \ if (LOG_LEVEL >= level) { \
PRINT_LN(kernel_log, fmt, ##__VA_ARGS__) PRINT_LN(kernel_log, fmt, ##__VA_ARGS__) \
#define LOG_LN_STEP(fmt, ...) \ }
if (LOG_LEVEL >= LOG_LEVEL_STEP) \
PRINT_LN(kernel_log, fmt, ##__VA_ARGS__)
#define LOG_LN_DATA(fmt, ...) \
if (LOG_LEVEL >= LOG_LEVEL_DATA) \
PRINT_LN(kernel_log, fmt, ##__VA_ARGS__)
#define LOG_LN_TRACE(fmt, ...) \
if (LOG_LEVEL >= LOG_LEVEL_TRACE) \
PRINT_LN(kernel_log, fmt, ##__VA_ARGS__)
#define LOG_VAL_INFO(v, f) LOG_LN_INFO(#v "=" f, v) #define LOG_VAL(level, v, f) LOG_LN(level, #v "=" f, v)
#define LOG_VAL_STEP(v, f) LOG_LN_STEP(#v "=" f, v)
#define LOG_VAL_DATA(v, f) LOG_LN_DATA(#v "=" f, v) #define LOG_INFO(fmt, ...) LOG(LOG_LEVEL_INFO, fmt, ##__VA_ARGS__)
#define LOG_VAL_TRACE(v, f) LOG_LN_TRACE(#v "=" f, v) #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); void log_init(stream_t *log);
+18 -8
View File
@@ -35,6 +35,8 @@ typedef struct __attribute__((packed)) {
#define USB_SETUP_RECIPIENT_OTHER 3 #define USB_SETUP_RECIPIENT_OTHER 3
#define USB_SETUP_GET_DESCRIPTOR 0x06 #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_SET_PROTOCOL 0x0B
#define USB_SETUP_DESCRIPTOR_TYPE_R(s) BITS_R((s)->w_value, 15, 8) #define USB_SETUP_DESCRIPTOR_TYPE_R(s) BITS_R((s)->w_value, 15, 8)
@@ -52,11 +54,6 @@ typedef struct __attribute__((packed)) {
#define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02 #define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02
#define USB_DESCRIPTOR_TYPE_INTERFACE 0x04 #define USB_DESCRIPTOR_TYPE_INTERFACE 0x04
#define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05 #define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05
#define USB_DESCRIPTOR_TYPE_HID 0x21
#define USB_INTERFACE_HID_KEYBOARD_CLASS 0x3
#define USB_INTERFACE_HID_KEYBOARD_SUBCLASS 0x1
#define USB_INTERFACE_HID_KEYBOARD_PROTOCOL 0x1
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
usb_descriptor_base_t base; usb_descriptor_base_t base;
@@ -176,7 +173,6 @@ void usb_enumerate(stream_t *out) {
} }
xhci_slot_t slot = xhci_attach(port); xhci_slot_t slot = xhci_attach(port);
if (slot == (xhci_slot_t)-1) { if (slot == (xhci_slot_t)-1) {
continue; continue;
} }
@@ -206,7 +202,6 @@ xhci_port_t usb_find_by_interface(uint8_t class, uint8_t subclass, uint8_t proto
} }
xhci_slot_t slot = xhci_attach(port); xhci_slot_t slot = xhci_attach(port);
if (slot == (xhci_slot_t)-1) { if (slot == (xhci_slot_t)-1) {
continue; continue;
} }
@@ -239,6 +234,14 @@ xhci_endpoint_t usb_open_endpoint(xhci_slot_t slot, uint8_t type, uint16_t max_p
scan_device(slot, &device, &configuration, &interface, &endpoint); scan_device(slot, &device, &configuration, &interface, &endpoint);
usb_setup_t setup; 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); memory_set(0, sizeof(setup), &setup);
USB_SETUP_DIRECTION_W(&setup, USB_SETUP_DIRECTION_H2D); USB_SETUP_DIRECTION_W(&setup, USB_SETUP_DIRECTION_H2D);
USB_SETUP_TYPE_W(&setup, USB_SETUP_TYPE_CLASS); USB_SETUP_TYPE_W(&setup, USB_SETUP_TYPE_CLASS);
@@ -246,9 +249,16 @@ xhci_endpoint_t usb_open_endpoint(xhci_slot_t slot, uint8_t type, uint16_t max_p
setup.b_request = USB_SETUP_SET_PROTOCOL; setup.b_request = USB_SETUP_SET_PROTOCOL;
xhci_control_transfer(slot, *(uint64_t *)&setup, NUL, 0); 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."); 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, endpoint.interval); 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) { uint16_t usb_read_endpoint(xhci_slot_t slot, xhci_endpoint_t endpoint, uint16_t max, void *to) {
+24 -3
View File
@@ -1,12 +1,12 @@
#include "src/kernel/xhci.h" #include "src/kernel/xhci.h"
#include "src/kernel/log.h" #include "src/kernel/log.h"
#include "src/kernel/memory.h"
#include "src/kernel/panic.h" #include "src/kernel/panic.h"
#include "src/kernel/pci.h" #include "src/kernel/pci.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/util.h" #include "src/lib/util.h"
#include <stdint.h>
#define XHCI_PCI_CLASS 0x0C #define XHCI_PCI_CLASS 0x0C
#define XHCI_PCI_SUBCLASS 0x03 #define XHCI_PCI_SUBCLASS 0x03
@@ -29,6 +29,7 @@ typedef volatile struct __attribute__((packed)) {
#define XHCI_CAP_REGS_MAX_INTRS(c) BITS_R((c)->hcsparams1, 18, 8) #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_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_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)) { typedef volatile struct __attribute__((packed)) {
uint32_t usbcmd; uint32_t usbcmd;
@@ -96,6 +97,8 @@ static xhci_db_regs *db_regs;
#define MAX_SLOTS 32 #define MAX_SLOTS 32
static void *scratchpads[32];
static void *dcbaa[MAX_SLOTS + 1] __attribute__((aligned(PAGE_SIZE))); static void *dcbaa[MAX_SLOTS + 1] __attribute__((aligned(PAGE_SIZE)));
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
@@ -408,6 +411,13 @@ void xhci_init() {
RING_WRAP(cmd); RING_WRAP(cmd);
XHCI_TRB_CYCLE_W(&cmd_r[RING_LENGTH], cmd_r_cycle); 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..."); LOG_LN_INFO("Configuring controller...");
XHCI_OP_REGS_MAX_SLOTS_EN_W(op_regs, MAX_SLOTS); XHCI_OP_REGS_MAX_SLOTS_EN_W(op_regs, MAX_SLOTS);
op_regs->dcbaap = (uint64_t)VIRT_TO_PHYS(dcbaa); op_regs->dcbaap = (uint64_t)VIRT_TO_PHYS(dcbaa);
@@ -475,13 +485,17 @@ xhci_slot_t xhci_attach(xhci_port_t port) {
RING_WRAP(tsf); RING_WRAP(tsf);
LOG_LN_STEP("Resetting device..."); 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); 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])) while (XHCI_PORT_REGS_PR_R(&port_regs[port]))
; ;
LOG_VAL_TRACE(&port_regs[port].portsc, "%x"); LOG_VAL_TRACE(port_regs[port].portsc, "%x");
while (!XHCI_PORT_REGS_PED(&port_regs[port]) && XHCI_PORT_REGS_PLL(&port_regs[port]) != 0) 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_VAL_TRACE(port_regs[port].portsc, "%x");
LOG_LN_STEP("Enabling a slot..."); LOG_LN_STEP("Enabling a slot...");
xhci_trb_t cmd_es; xhci_trb_t cmd_es;
@@ -612,10 +626,17 @@ uint16_t xhci_read_endpoint(xhci_slot_t slot, xhci_endpoint_t endpoint, uint16_t
LOG_LN_STEP("Received transfer event, returning..."); LOG_LN_STEP("Received transfer event, returning...");
ep_processed_events++; 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); xhci_trb_t *cmd = PHYS_TO_VIRT(cmp->parameter);
uint16_t size = max < cmd->status ? max : (uint16_t)cmd->status; uint16_t size = max < cmd->status ? max : (uint16_t)cmd->status;
memory_copy(PHYS_TO_VIRT(cmd->parameter), size, to); memory_copy(PHYS_TO_VIRT(cmd->parameter), size, to);
LOG_VAL_TRACE(size, "%d");
LOG_VAL_TRACE(*(uint64_t *)to, "%lx");
transferred = size; transferred = size;
} }
+3 -4
View File
@@ -3,8 +3,7 @@ ENTRY(_start)
SECTIONS { SECTIONS {
. = 0x0000000000400000; . = 0x0000000000400000;
.text : { *(.text) } .text : { *(.text*) }
.rodata : { *(.rodata) } .rodata : { *(.rodata*) *(.lrodata*) }
.data : { *(.data) } .data : { *(.data*) *(.ldata*) *(.bss*) *(.lbss*) }
.bss : { *(.bss) }
} }
+1 -1
View File
@@ -9,7 +9,7 @@ fi
qemu-system-x86_64 \ qemu-system-x86_64 \
"${debug_flags[@]}" \ "${debug_flags[@]}" \
-monitor stdio \ -monitor stdio \
-drive file=build/os.img,format=raw,if=none,id=nvme0 \ -drive file=build/os.raw,format=raw,if=none,id=nvme0 \
-device nvme,drive=nvme0,serial=foo \ -device nvme,drive=nvme0,serial=foo \
-device qemu-xhci,id=xhci,msi=off,msix=off \ -device qemu-xhci,id=xhci,msi=off,msix=off \
-device usb-kbd,bus=xhci.0 \ -device usb-kbd,bus=xhci.0 \