Compare commits
10
Commits
e4b9a79a5f
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae7af6e6cf | ||
|
|
532d8e757b | ||
|
|
b5215d5327 | ||
|
|
dccb93fb82 | ||
|
|
b78ef69da8 | ||
|
|
d72169473f | ||
|
|
c58605b56d | ||
|
|
63c1720e60 | ||
|
|
bbb9988bcf | ||
|
|
0cb2169c29 |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 949 KiB |
@@ -18,19 +18,19 @@ meson compile -v -C build
|
||||
sector_size=512
|
||||
partition_offset=2048
|
||||
|
||||
dd if=/dev/zero of=build/os.img 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/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.img
|
||||
mcopy -i build/os.img@@"$((partition_offset * sector_size))" -s src ::src
|
||||
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/kernel.bin ::kernel.bin
|
||||
mmd -i build/os.img@@"$((partition_offset * sector_size))" ::bin
|
||||
mcopy -i build/os.img@@"$((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.img@@"$((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.img@@"$((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.img@@"$((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.img@@"$((partition_offset * sector_size))" build/wc ::bin/wc
|
||||
dd if=/dev/zero of=build/os.raw 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/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.raw
|
||||
mcopy -i build/os.raw@@"$((partition_offset * sector_size))" -s src ::src
|
||||
mcopy -i build/os.raw@@"$((partition_offset * sector_size))" build/kernel.bin ::kernel.bin
|
||||
mmd -i build/os.raw@@"$((partition_offset * sector_size))" ::bin
|
||||
mcopy -i build/os.raw@@"$((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.raw@@"$((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.raw@@"$((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.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
|
||||
|
||||
@@ -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
|
||||
+54
-353
@@ -71,9 +71,9 @@ kernel_sources = files([
|
||||
'src/kernel/fat16.c',
|
||||
'src/kernel/fs.c',
|
||||
'src/kernel/gdt.c',
|
||||
'src/kernel/hid-keyboard.c',
|
||||
'src/kernel/idt.c',
|
||||
'src/kernel/kernel.c',
|
||||
'src/kernel/keyboard.c',
|
||||
'src/kernel/log.c',
|
||||
'src/kernel/memory.c',
|
||||
'src/kernel/nvme.c',
|
||||
@@ -83,6 +83,7 @@ kernel_sources = files([
|
||||
'src/kernel/pic.c',
|
||||
'src/kernel/pipe.c',
|
||||
'src/kernel/process.c',
|
||||
'src/kernel/ps2-keyboard.c',
|
||||
'src/kernel/syscall.c',
|
||||
'src/kernel/timer.c',
|
||||
'src/kernel/tss.c',
|
||||
@@ -91,20 +92,25 @@ kernel_sources = files([
|
||||
'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',
|
||||
sources: [kernel_entry_o, timer_o, process_o, syscall_o, lib_sources, kernel_sources],
|
||||
c_args: [
|
||||
'-ffreestanding',
|
||||
'-nostdlib',
|
||||
'-nostartfiles',
|
||||
'-mno-red-zone',
|
||||
'-mgeneral-regs-only',
|
||||
c_args,
|
||||
'-mcmodel=kernel',
|
||||
'-Wno-unused-command-line-argument',
|
||||
'-Wconversion',
|
||||
'-DKERNEL="yes"',
|
||||
'-DVERSION="' + meson.project_version() + '"',
|
||||
],
|
||||
link_args: [
|
||||
'-T', meson.project_source_root() / 'src/kernel/linker.ld',
|
||||
@@ -121,353 +127,48 @@ custom_target(
|
||||
build_by_default: true,
|
||||
)
|
||||
|
||||
terminal_start = custom_target(
|
||||
'terminal_start',
|
||||
input: 'src/user/start.asm',
|
||||
output: 'terminal_start.o',
|
||||
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
|
||||
)
|
||||
foreach app : ['terminal', 'shell', 'echo', 'ls', 'cat', 'cp', 'mkdir', 'rm', 'wc']
|
||||
start = custom_target(
|
||||
f'@app@_start',
|
||||
input: 'src/user/start.asm',
|
||||
output: f'@app@_start.o',
|
||||
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
|
||||
)
|
||||
|
||||
terminal_syscall = custom_target(
|
||||
'terminal_syscall',
|
||||
input: 'src/user/syscall.asm',
|
||||
output: 'terminal_syscall.o',
|
||||
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
|
||||
)
|
||||
syscall = custom_target(
|
||||
f'@app@_syscall',
|
||||
input: 'src/user/syscall.asm',
|
||||
output: f'@app@_syscall.o',
|
||||
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
|
||||
)
|
||||
|
||||
terminal_elf = executable(
|
||||
'terminal.elf',
|
||||
sources: [terminal_start, terminal_syscall, lib_sources, 'src/user/app/terminal/terminal.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',
|
||||
)
|
||||
elf = executable(
|
||||
f'@app@.elf',
|
||||
sources: [start, syscall, lib_sources, f'src/user/app/@app@/@app@.c'],
|
||||
c_args: [
|
||||
c_args,
|
||||
'-mcmodel=large',
|
||||
],
|
||||
link_args: [
|
||||
'-T', meson.project_source_root() / 'src/user/linker.ld',
|
||||
'-nostdlib',
|
||||
],
|
||||
link_depends: 'src/user/linker.ld',
|
||||
)
|
||||
|
||||
custom_target(
|
||||
'terminal',
|
||||
input: terminal_elf,
|
||||
output: 'terminal',
|
||||
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
|
||||
build_by_default: true,
|
||||
)
|
||||
elf_data = custom_target(
|
||||
f'@app@_data.elf',
|
||||
input: elf,
|
||||
output: f'@app@_data.elf',
|
||||
command: ['objcopy', '--set-section-flags', '.data=alloc,load,contents', '@INPUT@', '@OUTPUT@'],
|
||||
build_by_default: true,
|
||||
)
|
||||
|
||||
shell_start = custom_target(
|
||||
'shell_start',
|
||||
input: 'src/user/start.asm',
|
||||
output: 'shell_start.o',
|
||||
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
|
||||
)
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
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,
|
||||
)
|
||||
custom_target(
|
||||
app,
|
||||
input: elf_data,
|
||||
output: app,
|
||||
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
|
||||
build_by_default: true,
|
||||
)
|
||||
endforeach
|
||||
|
||||
+7
-5
@@ -10,7 +10,6 @@ mov sp, 0x7000
|
||||
FIRST_PARTITION_SECTOR equ 2048 ; TODO Read MBR.
|
||||
STAGE_BUFFER_SEGMENT equ 0x0900
|
||||
STAGE_BUFFER_OFFSET equ 0x0000
|
||||
KERNEL_BUFFER_SEGMENT equ 0x2000
|
||||
|
||||
jmp prepare_kernel
|
||||
|
||||
@@ -39,9 +38,10 @@ root_start: dw 0
|
||||
root_size: dw 0
|
||||
data_start: dw 0
|
||||
|
||||
kernel_filename: db 'KERNEL BIN'
|
||||
kernel_cluster: dw 0
|
||||
kernel_buffer_offset: dw 0
|
||||
kernel_filename: db 'KERNEL BIN'
|
||||
kernel_cluster: dw 0
|
||||
kernel_buffer_segment: dw 0x2000
|
||||
kernel_buffer_offset: dw 0
|
||||
|
||||
read_sectors:
|
||||
xor bx, bx
|
||||
@@ -192,7 +192,7 @@ load_kernel_cluster:
|
||||
add ax, [data_start]
|
||||
xor cx, cx
|
||||
mov cl, [bpb.sectors_per_cluster]
|
||||
mov bx, KERNEL_BUFFER_SEGMENT
|
||||
mov bx, [kernel_buffer_segment]
|
||||
mov es, bx
|
||||
mov di, [kernel_buffer_offset]
|
||||
call read_sectors
|
||||
@@ -201,6 +201,8 @@ load_kernel_cluster:
|
||||
shl ax, 9 ; * 512
|
||||
add ax, [kernel_buffer_offset]
|
||||
mov [kernel_buffer_offset], ax
|
||||
jnc find_next_kernel_cluster
|
||||
add word [kernel_buffer_segment], 0x1000
|
||||
|
||||
find_next_kernel_cluster:
|
||||
xor bx, bx
|
||||
|
||||
+1
-1
@@ -357,7 +357,7 @@ fs_node_t *fat16_open_at(const fs_node_t *directory, uint16_t index, uint64_t fl
|
||||
ei++;
|
||||
}
|
||||
|
||||
fs_node_t *result = open_entry(dir_cluster, entries, ei);
|
||||
fs_node_t *result = ei < entries_count ? open_entry(dir_cluster, entries, ei) : NUL;
|
||||
|
||||
memory_free(entries);
|
||||
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "src/kernel/stream.h"
|
||||
#include <stdint.h>
|
||||
|
||||
stream_t *hid_keyboard_init(); // Assuming one and only one HID device.
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
#include "src/kernel/fs.h"
|
||||
#include "src/kernel/gdt.h"
|
||||
#include "src/kernel/hid-keyboard.h"
|
||||
#include "src/kernel/idt.h"
|
||||
#include "src/kernel/keyboard.h"
|
||||
#include "src/kernel/log.h"
|
||||
#include "src/kernel/nvme.h"
|
||||
#include "src/kernel/panic.h"
|
||||
@@ -87,7 +87,7 @@ void kernel_main() {
|
||||
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->cwd = memory_allocate(sizeof(path_t));
|
||||
kernel->fds[STDIN] = keyboard_init();
|
||||
kernel->fds[STDIN] = hid_keyboard_init();
|
||||
kernel->fds[STDOUT] = kernel->fds[STDERR] = vga;
|
||||
kernel->free_fd = STDERR + 1;
|
||||
kernel->code = EXIT_CODE_OK;
|
||||
|
||||
+34
-46
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "src/kernel/stream.h"
|
||||
#include "src/lib/memory.h"
|
||||
#include "src/lib/string.h"
|
||||
|
||||
extern stream_t *kernel_log;
|
||||
@@ -15,58 +14,47 @@ extern stream_t *kernel_log;
|
||||
#define LOG_LEVEL_DATA 3
|
||||
#define LOG_LEVEL_TRACE 4
|
||||
|
||||
static uint64_t print_size;
|
||||
static char print_buffer[512];
|
||||
|
||||
#define PRINT(stream, fmt, ...) \
|
||||
do { \
|
||||
uint64_t _size = string_length(fmt) * 10; \
|
||||
char *_string = memory_allocate(_size); \
|
||||
_size = string_format(fmt, _size, _string, ##__VA_ARGS__); \
|
||||
stream->write(stream, _string, _size); \
|
||||
memory_free(_string); \
|
||||
} while (0);
|
||||
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, ...) \
|
||||
do { \
|
||||
uint64_t _size = string_length(fmt) * 10; \
|
||||
char *_string = memory_allocate(_size); \
|
||||
_size = string_format(fmt, _size, _string, ##__VA_ARGS__); \
|
||||
stream->write(stream, __func__, string_length(__func__)); \
|
||||
stream->write(stream, ": ", 2); \
|
||||
stream->write(stream, _string, _size); \
|
||||
stream->write(stream, "\n", 1); \
|
||||
memory_free(_string); \
|
||||
} while (0);
|
||||
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_INFO(fmt, ...) \
|
||||
if (LOG_LEVEL >= LOG_LEVEL_INFO) \
|
||||
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(level, fmt, ...) \
|
||||
if (LOG_LEVEL >= level) { \
|
||||
PRINT(kernel_log, fmt, ##__VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define LOG_LN_INFO(fmt, ...) \
|
||||
if (LOG_LEVEL >= LOG_LEVEL_INFO) \
|
||||
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_LN(level, fmt, ...) \
|
||||
if (LOG_LEVEL >= level) { \
|
||||
PRINT_LN(kernel_log, fmt, ##__VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define LOG_VAL_INFO(v, f) LOG_LN_INFO(#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_VAL_TRACE(v, f) LOG_LN_TRACE(#v "=" f, v)
|
||||
#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
-1
@@ -167,7 +167,7 @@ static void io_exec_sync(nvme_sqe_t *cmd) {
|
||||
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, "nvme_init: No suitable devices found.");
|
||||
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);
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
#include "src/kernel/vga.h"
|
||||
|
||||
void kernel_panic(const char *msg, __attribute__((unused)) const char *file, __attribute__((unused)) int line) {
|
||||
vga_set_string(0, VGA_HEIGHT - 1, msg, 0x28);
|
||||
vga_set_string(VGA_HEIGHT - 1, 0, msg, 0x28);
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
+7
-2
@@ -1,6 +1,7 @@
|
||||
#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"
|
||||
@@ -70,7 +71,7 @@ void pci_enumerate(stream_t *out) {
|
||||
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; PCI_MAX_FUNCTIONS; f++) {
|
||||
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;
|
||||
@@ -85,10 +86,12 @@ pci_bdf_t pci_find_by_class(uint8_t class, uint8_t subclass, uint8_t iface) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return NUL;
|
||||
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);
|
||||
@@ -101,6 +104,8 @@ 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) {
|
||||
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));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "src/kernel/keyboard.h"
|
||||
#include "src/kernel/ps2-keyboard.h"
|
||||
#include "src/kernel/idt.h"
|
||||
#include "src/kernel/process.h"
|
||||
#include "src/kernel/stream.h"
|
||||
@@ -158,15 +158,15 @@ static void on_key(uint8_t scancode) {
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) static void isr_keyboard(__attribute__((unused)) struct interrupt_frame *frame) {
|
||||
__attribute__((interrupt)) static void isr_ps2_keyboard(__attribute__((unused)) struct interrupt_frame *frame) {
|
||||
uint8_t scancode = inb(0x60);
|
||||
outb(0x20, 0x20);
|
||||
on_key(scancode);
|
||||
}
|
||||
|
||||
stream_t *keyboard_init() {
|
||||
stream_t *ps2_keyboard_init() {
|
||||
outb(0x21, inb(0x21) & ~0x02);
|
||||
idt_set_entry(33, isr_keyboard, 0x8E);
|
||||
idt_set_entry(33, isr_ps2_keyboard, 0x8E);
|
||||
|
||||
return &stream;
|
||||
}
|
||||
@@ -3,4 +3,4 @@
|
||||
#include "src/kernel/stream.h"
|
||||
#include <stdint.h>
|
||||
|
||||
stream_t *keyboard_init();
|
||||
stream_t *ps2_keyboard_init();
|
||||
+240
-10
@@ -1,16 +1,67 @@
|
||||
#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; // 0x01 for device descriptor
|
||||
uint16_t usb_version; // BCD, e.g. 0x0200 for USB 2.0
|
||||
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; // for ep0
|
||||
uint8_t max_packet_size;
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
uint16_t device_version;
|
||||
@@ -20,7 +71,94 @@ typedef struct __attribute__((packed)) {
|
||||
uint8_t num_configurations;
|
||||
} usb_device_descriptor_t;
|
||||
|
||||
static usb_device_descriptor_t device_descriptor __attribute__((aligned(64)));
|
||||
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...");
|
||||
@@ -29,16 +167,108 @@ void usb_init() {
|
||||
}
|
||||
|
||||
void usb_enumerate(stream_t *out) {
|
||||
for (uint8_t i = 0; i < xhci_port_count(); i++) {
|
||||
if (!xhci_port_connected(i)) {
|
||||
for (xhci_port_t port = 0; port < xhci_port_count(); port++) {
|
||||
if (!xhci_port_connected(port)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
xhci_slot_t slot = xhci_attach(i);
|
||||
xhci_slot_t slot = xhci_attach(port);
|
||||
if (slot == (xhci_slot_t)-1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
xhci_control_transfer(slot, 0x0012000001000680ULL, &device_descriptor, sizeof(usb_device_descriptor_t));
|
||||
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);
|
||||
|
||||
PRINT_LN(out, "%hx:%hx class=%hx subclass=%hx protocol=%hx", device_descriptor.vendor_id, device_descriptor.product_id,
|
||||
device_descriptor.device_class, device_descriptor.device_subclass, device_descriptor.device_protocol);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
#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);
|
||||
|
||||
+294
-102
@@ -1,5 +1,6 @@
|
||||
#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"
|
||||
@@ -28,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_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;
|
||||
@@ -68,6 +70,7 @@ typedef volatile struct __attribute__((packed)) {
|
||||
#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)
|
||||
|
||||
@@ -94,6 +97,8 @@ 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)) {
|
||||
@@ -112,14 +117,19 @@ typedef struct __attribute__((packed)) {
|
||||
#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
|
||||
@@ -127,6 +137,8 @@ typedef struct __attribute__((packed)) {
|
||||
#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
|
||||
@@ -136,13 +148,25 @@ static xchi_erst_entry_t erst[1] __attribute__((aligned(PAGE_SIZE)));
|
||||
|
||||
#define RING_LENGTH 32
|
||||
|
||||
static uint8_t cr_cycle = 1;
|
||||
static uint8_t cr_i = 0;
|
||||
static xhci_trb_t cr[RING_LENGTH + 1] __attribute__((aligned(PAGE_SIZE)));
|
||||
#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)));
|
||||
|
||||
static uint8_t er_cycle = 1;
|
||||
static uint8_t er_i = 0;
|
||||
static xhci_trb_t er[RING_LENGTH] __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;
|
||||
@@ -173,10 +197,14 @@ typedef struct __attribute__((packed)) {
|
||||
uint32_t reserved[3];
|
||||
} xhci_ep_ctx_t;
|
||||
|
||||
#define USB_EP_CTX_EP_TYPE_R(e) BITS_R((e)->dw1, 5, 3)
|
||||
#define USB_EP_CTX_EP_TYPE_W(e, v) BITS_W((e)->dw1, 5, 3, v)
|
||||
#define USB_EP_CTX_MAX_PACKET_SIZE_R(e) BITS_R((e)->dw1, 31, 16)
|
||||
#define USB_EP_CTX_MAX_PACKET_SIZE_W(e, v) BITS_W((e)->dw1, 31, 16, v)
|
||||
#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;
|
||||
@@ -193,10 +221,15 @@ typedef struct __attribute__((packed)) {
|
||||
|
||||
static xchi_device_ctx_t device_ctx __attribute__((aligned(64)));
|
||||
|
||||
static uint8_t tr_attached_slot = 0;
|
||||
static uint8_t tr_cycle = 1;
|
||||
static uint8_t tr_i = 0;
|
||||
static xhci_trb_t tr[RING_LENGTH + 1] __attribute__((aligned(PAGE_SIZE)));
|
||||
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...");
|
||||
@@ -204,14 +237,10 @@ static const xhci_trb_t *command_exec_sync(const xhci_trb_t *cmd) {
|
||||
LOG_VAL_TRACE(cmd->status, "%x");
|
||||
LOG_VAL_TRACE(cmd->control, "%x");
|
||||
|
||||
xhci_trb_t *cre = &cr[cr_i];
|
||||
|
||||
xhci_trb_t *cre = &cmd_r[cmd_r_i];
|
||||
memory_copy(cmd, sizeof(xhci_trb_t), cre);
|
||||
XHCI_TRB_CYCLE_W(cre, cr_cycle);
|
||||
|
||||
cr_i = (cr_i + 1) % RING_LENGTH;
|
||||
XHCI_TRB_CYCLE_W((&cr[RING_LENGTH]), cr_cycle);
|
||||
cr_cycle ^= (cr_i == 0);
|
||||
XHCI_TRB_CYCLE_W(cre, cmd_r_cycle);
|
||||
RING_ADVANCE(cmd);
|
||||
|
||||
LOG_LN_STEP("Ringing command doorbell...");
|
||||
LOG_VAL_TRACE(op_regs->usbsts, "%x");
|
||||
@@ -220,16 +249,17 @@ static const xhci_trb_t *command_exec_sync(const xhci_trb_t *cmd) {
|
||||
|
||||
LOG_LN_STEP("Waiting for completion...");
|
||||
while (1) {
|
||||
xhci_trb_t *cmp = &er[er_i];
|
||||
while (XHCI_TRB_CYCLE_R(cmp) != er_cycle)
|
||||
xhci_trb_t *cmp = &evt_r[evt_r_i];
|
||||
while (XHCI_TRB_CYCLE_R(cmp) != evt_r_cycle)
|
||||
;
|
||||
|
||||
er_i = (er_i + 1) % RING_LENGTH;
|
||||
intr_regs->erdp = (uint64_t)(VIRT_TO_PHYS(&er[er_i]));
|
||||
er_cycle ^= (er_i == 0);
|
||||
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...");
|
||||
|
||||
@@ -246,10 +276,88 @@ static const xhci_trb_t *command_exec_sync(const xhci_trb_t *cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
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, "xhci_init: No suitable controllers found.");
|
||||
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);
|
||||
@@ -300,19 +408,22 @@ void xhci_init() {
|
||||
LOG_VAL_DATA(op_regs->usbsts, "%x");
|
||||
|
||||
LOG_LN_INFO("Setting up command ring...");
|
||||
xhci_trb_t *wrapper = &cr[RING_LENGTH];
|
||||
wrapper->parameter = (uint64_t)VIRT_TO_PHYS(cr);
|
||||
wrapper->status = 0;
|
||||
XHCI_TRB_TRB_TYPE_W(wrapper, XHCI_TRB_TYPE_LINK);
|
||||
XHCI_TRB_TOGGLE_CYCLE_W(wrapper, 1);
|
||||
XHCI_TRB_CYCLE_W(wrapper, cr_cycle);
|
||||
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(cr) | cr_cycle;
|
||||
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(er);
|
||||
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;
|
||||
@@ -336,6 +447,7 @@ void xhci_init() {
|
||||
;
|
||||
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);
|
||||
@@ -343,9 +455,9 @@ void xhci_init() {
|
||||
}
|
||||
|
||||
void xhci_enumerate(stream_t *out) {
|
||||
for (uint8_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", 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]));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,27 +465,37 @@ uint8_t xhci_port_count() {
|
||||
return XHCI_CAP_REGS_MAX_PORTS(cap_regs);
|
||||
}
|
||||
|
||||
uint8_t xhci_port_connected(uint8_t port) {
|
||||
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(uint8_t port) {
|
||||
xhci_slot_t xhci_attach(xhci_port_t port) {
|
||||
LOG_LN_STEP("Attaching port %d ...", port);
|
||||
|
||||
ASSERT(!tr_attached_slot, "xhci_attach: Can only attach one port at a time.")
|
||||
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.");
|
||||
|
||||
memory_set(0, sizeof(tr), tr);
|
||||
tr_i = 0;
|
||||
tr_cycle = 1;
|
||||
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...");
|
||||
port_regs[port].portsc = 1 << 4;
|
||||
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]))
|
||||
;
|
||||
while (!XHCI_PORT_REGS_PED(&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(XHCI_PORT_REGS_PED(&port_regs[port]), "%hhx");
|
||||
LOG_VAL_TRACE(port_regs[port].portsc, "%x");
|
||||
|
||||
LOG_LN_STEP("Enabling a slot...");
|
||||
xhci_trb_t cmd_es;
|
||||
@@ -387,9 +509,9 @@ xhci_slot_t xhci_attach(uint8_t port) {
|
||||
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])));
|
||||
USB_EP_CTX_EP_TYPE_W(&input_ctx.ep[0], 4);
|
||||
USB_EP_CTX_MAX_PACKET_SIZE_W(&input_ctx.ep[0], 64);
|
||||
input_ctx.ep[0].dequeue = (uint64_t)VIRT_TO_PHYS(tr) | tr_cycle;
|
||||
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);
|
||||
|
||||
@@ -400,7 +522,7 @@ xhci_slot_t xhci_attach(uint8_t port) {
|
||||
XHCI_TRB_SLOT_ID_W(&cmd_ad, slot);
|
||||
command_exec_sync(&cmd_ad);
|
||||
|
||||
tr_attached_slot = slot;
|
||||
tsf_r_attached_slot = slot;
|
||||
|
||||
LOG_LN_STEP("Done.");
|
||||
|
||||
@@ -408,85 +530,155 @@ xhci_slot_t xhci_attach(uint8_t port) {
|
||||
}
|
||||
|
||||
uint64_t xhci_control_transfer(xhci_slot_t slot, uint64_t setup, void *data, uint16_t length) {
|
||||
ASSERT(tr_attached_slot == slot, "xhci_control_transfer: Can only attach one port at a time.");
|
||||
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.");
|
||||
|
||||
LOG_LN_STEP("Queueing transfer TRBs...");
|
||||
return length - (control_transfer_exec_sync(setup, data, length)->status & 0xFFFFFF);
|
||||
}
|
||||
|
||||
tr[tr_i].parameter = setup;
|
||||
tr[tr_i].status = sizeof(setup);
|
||||
XHCI_TRB_TRB_TYPE_W(&tr[tr_i], XHCI_TRB_TYPE_TRANSFER_SETUP_STAGE);
|
||||
BITS_W(tr[tr_i].control, 17, 16, 3);
|
||||
BITS_W(tr[tr_i].control, 6, 6, 1);
|
||||
XHCI_TRB_CYCLE_W(&tr[tr_i], tr_cycle);
|
||||
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);
|
||||
|
||||
LOG_VAL_TRACE(tr[tr_i].parameter, "%lx");
|
||||
LOG_VAL_TRACE(tr[tr_i].status, "%x");
|
||||
LOG_VAL_TRACE(tr[tr_i].control, "%x");
|
||||
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.")
|
||||
|
||||
tr_i = (tr_i + 1) % RING_LENGTH;
|
||||
XHCI_TRB_CYCLE_W(&tr[RING_LENGTH], tr_cycle);
|
||||
tr_cycle ^= (tr_i == 0);
|
||||
uint8_t ep_num = address & 0x0F;
|
||||
uint8_t ep_dir = (address >> 7) & 1;
|
||||
uint8_t dci = ep_num * 2 + ep_dir;
|
||||
|
||||
tr[tr_i].parameter = (uint64_t)VIRT_TO_PHYS(data);
|
||||
tr[tr_i].status = length;
|
||||
XHCI_TRB_TRB_TYPE_W(&tr[tr_i], XHCI_TRB_TYPE_TRANSFER_DATA_STAGE);
|
||||
BITS_W(tr[tr_i].control, 16, 16, 1);
|
||||
XHCI_TRB_CYCLE_W(&tr[tr_i], tr_cycle);
|
||||
LOG_LN_STEP("Setting up endpoint ring...");
|
||||
RING_WRAP(ep);
|
||||
XHCI_TRB_CYCLE_W(&ep_r[RING_LENGTH], ep_r_cycle);
|
||||
|
||||
LOG_VAL_TRACE(tr[tr_i].parameter, "%lx");
|
||||
LOG_VAL_TRACE(tr[tr_i].status, "%x");
|
||||
LOG_VAL_TRACE(tr[tr_i].control, "%x");
|
||||
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);
|
||||
|
||||
tr_i = (tr_i + 1) % RING_LENGTH;
|
||||
XHCI_TRB_CYCLE_W(&tr[RING_LENGTH], tr_cycle);
|
||||
tr_cycle ^= (tr_i == 0);
|
||||
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 *tre = &tr[tr_i];
|
||||
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);
|
||||
|
||||
XHCI_TRB_TRB_TYPE_W(&tr[tr_i], XHCI_TRB_TYPE_TRANSFER_STATUS_STAGE);
|
||||
BITS_W(tr[tr_i].control, 16, 16, 0);
|
||||
BITS_W(tr[tr_i].control, 5, 5, 1);
|
||||
XHCI_TRB_CYCLE_W(&tr[tr_i], tr_cycle);
|
||||
ep_r_attached_endpoint = dci;
|
||||
ep_transfer_size = max_packet_size;
|
||||
|
||||
tr_i = (tr_i + 1) % RING_LENGTH;
|
||||
XHCI_TRB_CYCLE_W(&tr[RING_LENGTH], tr_cycle);
|
||||
tr_cycle ^= (tr_i == 0);
|
||||
return dci;
|
||||
}
|
||||
|
||||
LOG_LN_STEP("Ringing slot doorbell...");
|
||||
db_regs[tr_attached_slot] = 1;
|
||||
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);
|
||||
|
||||
LOG_LN_STEP("Waiting for completion...");
|
||||
while (1) {
|
||||
xhci_trb_t *cmp = &er[er_i];
|
||||
while (XHCI_TRB_CYCLE_R(cmp) != er_cycle)
|
||||
;
|
||||
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.");
|
||||
|
||||
er_i = (er_i + 1) % RING_LENGTH;
|
||||
intr_regs->erdp = (uint64_t)(VIRT_TO_PHYS(&er[er_i]));
|
||||
er_cycle ^= (er_i == 0);
|
||||
if (ep_processed_events == RING_LENGTH) {
|
||||
LOG_LN_STEP("Event batch finished, posting new transfer requests...");
|
||||
ep_processed_events = 0;
|
||||
|
||||
if (XHCI_TRB_TRB_TYPE_R(cmp) != XHCI_TRB_TYPE_EVENT_TRANSFER_COMPLETION || (void *)cmp->parameter != VIRT_TO_PHYS(tre)) {
|
||||
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 completion event...");
|
||||
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");
|
||||
|
||||
ASSERT(XHCI_TRB_COMPLETION_CODE(cmp) == 1, "xhci_control_transfer: Transfer failed.");
|
||||
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_LN_STEP("Done.");
|
||||
LOG_VAL_TRACE(size, "%d");
|
||||
LOG_VAL_TRACE(*(uint64_t *)to, "%lx");
|
||||
|
||||
return length - (cmp->status & 0xFFFFFF);
|
||||
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(tr_attached_slot == slot, "xhci_detach: Slot not attached.");
|
||||
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);
|
||||
@@ -495,7 +687,7 @@ void xhci_detach(xhci_slot_t slot) {
|
||||
command_exec_sync(&cmd_ds);
|
||||
|
||||
dcbaa[slot] = 0;
|
||||
tr_attached_slot = 0;
|
||||
tsf_r_attached_slot = 0;
|
||||
|
||||
LOG_LN_STEP("Done.");
|
||||
}
|
||||
|
||||
+10
-2
@@ -3,7 +3,9 @@
|
||||
#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.
|
||||
|
||||
@@ -11,10 +13,16 @@ void xhci_enumerate(stream_t *out);
|
||||
|
||||
uint8_t xhci_port_count();
|
||||
|
||||
uint8_t xhci_port_connected(uint8_t port);
|
||||
uint8_t xhci_port_connected(xhci_port_t port);
|
||||
|
||||
xhci_slot_t xhci_attach(uint8_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);
|
||||
|
||||
@@ -17,3 +17,8 @@ typedef uint64_t exit_code_t;
|
||||
#define EXIT_CODE_OK 0
|
||||
#define EXIT_CODE_NOT_FOUND ((uint64_t)-2)
|
||||
#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
|
||||
;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ exit_code_t main(uint64_t argc, const char **argv) {
|
||||
|
||||
uint64_t code = EXIT_CODE_OK;
|
||||
for (uint64_t i = 1; i < argc; i++) {
|
||||
uint64_t removed = remove(argv[i]);
|
||||
if (removed == (uint64_t)-1) {
|
||||
if (remove(argv[i]) == (uint64_t)-1) {
|
||||
ERR_S("rm: could not remove file\n");
|
||||
code = EXIT_CODE_GENERAL_FAILURE;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,12 @@ static void execute(char *command) {
|
||||
uint8_t pids_count = 0;
|
||||
|
||||
for (uint8_t i = 0; i < subcommands_count; i++) {
|
||||
string_trim(subcommands[i], ' ', &subcommands[i]);
|
||||
if (!string_trim(subcommands[i], ' ', &subcommands[i])) {
|
||||
if (subcommands_count > 1) {
|
||||
ERR_S("Syntax error.\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
char *argv[16];
|
||||
uint8_t argc = (uint8_t)string_split(subcommands[i], ' ', 16, argv);
|
||||
@@ -166,7 +171,7 @@ exit_code_t main() {
|
||||
print_prompt();
|
||||
|
||||
char line[256];
|
||||
uint64_t offset;
|
||||
uint64_t offset = 0;
|
||||
|
||||
char chunk[64];
|
||||
uint64_t received;
|
||||
|
||||
+3
-4
@@ -3,8 +3,7 @@ ENTRY(_start)
|
||||
SECTIONS {
|
||||
. = 0x0000000000400000;
|
||||
|
||||
.text : { *(.text) }
|
||||
.rodata : { *(.rodata) }
|
||||
.data : { *(.data) }
|
||||
.bss : { *(.bss) }
|
||||
.text : { *(.text*) }
|
||||
.rodata : { *(.rodata*) *(.lrodata*) }
|
||||
.data : { *(.data*) *(.ldata*) *(.bss*) *(.lbss*) }
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ fi
|
||||
qemu-system-x86_64 \
|
||||
"${debug_flags[@]}" \
|
||||
-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 qemu-xhci,id=xhci,msi=off,msix=off \
|
||||
-device usb-kbd,bus=xhci.0 \
|
||||
|
||||
Reference in New Issue
Block a user