Compare commits
104 Commits
v0.7.0
...
feature/dy
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17261622c6 | ||
|
|
dff9e53658 | ||
|
|
0bf709a339 | ||
|
|
c245949ea4 | ||
|
|
c27f8baa31 | ||
|
|
f51f519c31 | ||
|
|
55a485ee67 | ||
|
|
ba6e8e1349 | ||
|
|
75d30fb56d | ||
|
|
4abcf238a0 | ||
|
|
c05b4211fa | ||
|
|
337b8bb36b | ||
|
|
97433fc7d1 | ||
|
|
fc16ed54b3 | ||
|
|
8cbde13139 | ||
|
|
646a534dfd | ||
|
|
eda816ad90 | ||
|
|
c4bb60299e | ||
|
|
3cfd0cf86b | ||
|
|
8b3fa3ed01 | ||
|
|
a0f91ed0fd | ||
|
|
77590b31a6 | ||
|
|
ce27749705 | ||
|
|
b239bb6df2 | ||
|
|
28379dc0f6 | ||
|
|
c86c0f2ae6 | ||
|
|
bbe27c6b53 | ||
|
|
21916ab869 | ||
|
|
778e766f6b | ||
|
|
5d1fdd0e81 | ||
|
|
f5208d1641 | ||
|
|
a7beb0df18 | ||
|
|
1ec46ee641 | ||
|
|
3ba0600694 | ||
|
|
a449a88395 | ||
|
|
4bf03266a9 | ||
|
|
4bceac3d56 | ||
|
|
350396d70f | ||
|
|
ad3afae315 | ||
|
|
0dc86f2a0d | ||
|
|
2b3c276f33 | ||
|
|
8bf2425c4a | ||
|
|
72530ccb15 | ||
|
|
da14fd123e | ||
|
|
f215b98f74 | ||
|
|
b5662bfd25 | ||
|
|
3b3857548c | ||
|
|
1e2e154747 | ||
|
|
2d8d4fd200 | ||
|
|
459b40ad57 | ||
|
|
90cf1e2220 | ||
|
|
692e0d8656 | ||
|
|
3ab1a6b170 | ||
|
|
069bc63d1f | ||
|
|
373121c455 | ||
|
|
936b12a977 | ||
|
|
2a4c286f2b | ||
|
|
bfab4f085e | ||
|
|
201e7191ef | ||
|
|
9fa588566f | ||
|
|
ed95574c24 | ||
|
|
0c777bc62f | ||
|
|
1d7d5e8015 | ||
|
|
95627ba43c | ||
|
|
841ac41e36 | ||
|
|
a46d8bce37 | ||
|
|
4052911ac4 | ||
|
|
3a7a18011c | ||
|
|
15e2f8abf3 | ||
|
|
6b43ddc8d7 | ||
|
|
508058c3d7 | ||
|
|
4c9ff44b1c | ||
|
|
c092e07832 | ||
|
|
abe7fe37d0 | ||
|
|
cca8e8b3ad | ||
|
|
7c194950bb | ||
|
|
723f7d0330 | ||
|
|
274891854f | ||
|
|
94b2a79f79 | ||
|
|
d2a6113fb7 | ||
|
|
55c88dd943 | ||
|
|
42db1e8899 | ||
|
|
38ca7004a6 | ||
|
|
8817766469 | ||
|
|
e250aaef30 | ||
|
|
7b29ba7d23 | ||
|
|
dc30437ce7 | ||
|
|
2c2398b549 | ||
|
|
bce01591f3 | ||
|
|
847ef1ccfe | ||
|
|
6fa9b33ac0 | ||
|
|
df6d5b3b16 | ||
|
|
4884a624d9 | ||
|
|
ea587076ed | ||
|
|
0eddb002f0 | ||
|
|
8f968f4954 | ||
|
|
094b54d728 | ||
|
|
4125175870 | ||
|
|
1cb8f1258d | ||
|
|
f05a1d3310 | ||
|
|
71069cb38b | ||
|
|
393db1e792 | ||
|
|
0a097ec7d3 | ||
|
|
ada660deeb |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -3,7 +3,7 @@
|
|||||||
/build*
|
/build*
|
||||||
*.bak
|
*.bak
|
||||||
tags
|
tags
|
||||||
jsix.log
|
*.log
|
||||||
*.out
|
*.out
|
||||||
*.o
|
*.o
|
||||||
*.a
|
*.a
|
||||||
@@ -13,3 +13,6 @@ sysroot
|
|||||||
__pycache__
|
__pycache__
|
||||||
/venv
|
/venv
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
buddy_allocs.txt
|
||||||
|
frame_allocs.txt
|
||||||
|
heap_allocs.txt
|
||||||
|
|||||||
19
.vscode/c_cpp_properties.json
vendored
Normal file
19
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Linux",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/src/libraries/**",
|
||||||
|
"${workspaceFolder}/build/**",
|
||||||
|
"${workspaceFolder}/sysroot/include"
|
||||||
|
],
|
||||||
|
"defines": [],
|
||||||
|
"compilerPath": "/usr/bin/clang",
|
||||||
|
"cStandard": "c17",
|
||||||
|
"cppStandard": "c++17",
|
||||||
|
"intelliSenseMode": "linux-clang-x64",
|
||||||
|
"compileCommands": "${workspaceFolder}/compile_commands.json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
32
.vscode/launch.json
vendored
Normal file
32
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "QEMU Debug Server",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/build/jsix.elf",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"logging": {
|
||||||
|
//"engineLogging": true,
|
||||||
|
"programOutput": true
|
||||||
|
},
|
||||||
|
"stopAtConnect": true,
|
||||||
|
"stopAtEntry": false,
|
||||||
|
|
||||||
|
"setupCommands": [
|
||||||
|
{"text": "dashboard -enabled off", "ignoreFailures": true}
|
||||||
|
],
|
||||||
|
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerServerAddress": "localhost:1234",
|
||||||
|
"debugServerPath": "${workspaceFolder}/qemu.sh",
|
||||||
|
"debugServerArgs": "--debug --no-build",
|
||||||
|
"serverLaunchTimeout": 5000,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
45
.vscode/tasks.json
vendored
45
.vscode/tasks.json
vendored
@@ -1,28 +1,41 @@
|
|||||||
{
|
{
|
||||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
// for the documentation about the tasks.json format
|
// for the documentation about the tasks.json format
|
||||||
"version": "0.1.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"taskName": "make",
|
"label": "Ninja",
|
||||||
"command": "make.bat",
|
"type": "shell",
|
||||||
"isBuildCommand": true
|
"command": "source ${workspaceFolder}/venv/bin/activate.fish; ninja",
|
||||||
|
"detail": "Build the project",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}/build"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskName": "clean",
|
"label": "Run QEMU",
|
||||||
"command": "make.bat",
|
"command": "./qemu.sh",
|
||||||
"args": [ "clean" ],
|
"args": [ "--no-build", "--kvm" ],
|
||||||
"isShellCommand": true
|
"dependsOn": ["Ninja"],
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"taskName": "qemu (windowed)",
|
"label": "clean",
|
||||||
"command": "qemu-win.bat",
|
"command": "${workspaceFolder}/venv/bin/ninja",
|
||||||
"showOutput": "never",
|
"options": {
|
||||||
"isTestCommand": true
|
"cwd": "${workspaceFolder}/build"
|
||||||
},
|
},
|
||||||
{
|
"args": [
|
||||||
"taskName": "qemu",
|
"-t",
|
||||||
"command": "qemu.bat"
|
"clean"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
---
|
|
||||||
variables:
|
|
||||||
cc: "${source_root}/sysroot/bin/clang"
|
|
||||||
cxx: "${source_root}/sysroot/bin/clang++"
|
|
||||||
ld: "${source_root}/sysroot/bin/ld.lld"
|
|
||||||
ar: ar
|
|
||||||
nasm: nasm
|
|
||||||
objcopy: objcopy
|
|
||||||
|
|
||||||
ccflags: [
|
|
||||||
"-I${source_root}/src/include",
|
|
||||||
"-I${source_root}/src/include/x86_64",
|
|
||||||
"-fcolor-diagnostics",
|
|
||||||
"-U__STDCPP_THREADS__",
|
|
||||||
"-D_LIBCPP_HAS_NO_THREADS",
|
|
||||||
"-DVERSION_MAJOR=${version_major}",
|
|
||||||
"-DVERSION_MINOR=${version_minor}",
|
|
||||||
"-DVERSION_PATCH=${version_patch}",
|
|
||||||
"-DVERSION_GITSHA=0x${version_sha}",
|
|
||||||
'-DGIT_VERSION=\"${version_major}.${version_minor}.${version_patch}+${version_sha}\"',
|
|
||||||
'-DGIT_VERSION_WIDE=L\"${version_major}.${version_minor}.${version_patch}+${version_sha}\"',
|
|
||||||
|
|
||||||
"-Wformat=2", "-Winit-self", "-Wfloat-equal", "-Winline", "-Wmissing-format-attribute",
|
|
||||||
"-Wmissing-include-dirs", "-Wswitch", "-Wundef", "-Wdisabled-optimization",
|
|
||||||
"-Wpointer-arith", "-Wno-attributes", "-Wno-sign-compare", "-Wno-multichar",
|
|
||||||
"-Wno-div-by-zero", "-Wno-endif-labels", "-Wno-pragmas", "-Wno-format-extra-args",
|
|
||||||
"-Wno-unused-result", "-Wno-deprecated-declarations", "-Wno-unused-function",
|
|
||||||
"-Wno-address-of-packed-member", "-Wno-invalid-offsetof", "-Wno-format-nonliteral",
|
|
||||||
"-Werror" ]
|
|
||||||
|
|
||||||
asflags: [
|
|
||||||
"-DVERSION_MAJOR=${version_major}",
|
|
||||||
"-DVERSION_MINOR=${version_minor}",
|
|
||||||
"-DVERSION_PATCH=${version_patch}",
|
|
||||||
"-DVERSION_GITSHA=0x${version_sha}",
|
|
||||||
"-I${source_root}/src/include" ]
|
|
||||||
|
|
||||||
cflags: [ "-std=c11" ]
|
|
||||||
cxxflags: [ "-std=c++17" ]
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
---
|
|
||||||
extends: base
|
|
||||||
|
|
||||||
variables:
|
|
||||||
ld: clang++
|
|
||||||
|
|
||||||
ccflags: [
|
|
||||||
"-nostdlib",
|
|
||||||
"-nodefaultlibs",
|
|
||||||
"-fno-builtin",
|
|
||||||
|
|
||||||
"-I${source_root}/external",
|
|
||||||
"--target=x86_64-unknown-windows",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-mno-red-zone",
|
|
||||||
"-fshort-wchar",
|
|
||||||
"-fno-omit-frame-pointer",
|
|
||||||
"-ggdb",
|
|
||||||
"-g3" ]
|
|
||||||
|
|
||||||
cxxflags: [ "-fno-exceptions", "-fno-rtti" ]
|
|
||||||
|
|
||||||
ldflags: [
|
|
||||||
"--target=x86_64-unknown-windows",
|
|
||||||
"-nostdlib",
|
|
||||||
"-Wl,-entry:efi_main",
|
|
||||||
"-Wl,-subsystem:efi_application",
|
|
||||||
"-fuse-ld=lld-link",
|
|
||||||
"-g" ]
|
|
||||||
|
|
||||||
9
assets/build/config.debug.yaml
Normal file
9
assets/build/config.debug.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
ccflags: [
|
||||||
|
"-g3",
|
||||||
|
"-ggdb",
|
||||||
|
]
|
||||||
|
|
||||||
|
ldflags: [
|
||||||
|
"-g",
|
||||||
|
]
|
||||||
39
assets/build/global.yaml
Normal file
39
assets/build/global.yaml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
cc: "${source_root}/sysroot/bin/clang"
|
||||||
|
cxx: "${source_root}/sysroot/bin/clang++"
|
||||||
|
ld: "${source_root}/sysroot/bin/ld.lld"
|
||||||
|
ar: ar
|
||||||
|
nasm: nasm
|
||||||
|
objcopy: objcopy
|
||||||
|
|
||||||
|
ccflags: [
|
||||||
|
"-I${source_root}/src/include",
|
||||||
|
"-fcolor-diagnostics",
|
||||||
|
"-U__STDCPP_THREADS__",
|
||||||
|
"-D_LIBCPP_HAS_NO_THREADS",
|
||||||
|
"-D__jsix_config=${build_config}",
|
||||||
|
"-D__jsix_config_${build_config}",
|
||||||
|
"-DVERSION_MAJOR=${version_major}",
|
||||||
|
"-DVERSION_MINOR=${version_minor}",
|
||||||
|
"-DVERSION_PATCH=${version_patch}",
|
||||||
|
"-DVERSION_GITSHA=0x${version_sha}",
|
||||||
|
'-DGIT_VERSION=\"${version_major}.${version_minor}.${version_patch}+${version_sha}\"',
|
||||||
|
'-DGIT_VERSION_WIDE=L\"${version_major}.${version_minor}.${version_patch}+${version_sha}\"',
|
||||||
|
|
||||||
|
"-Wformat=2", "-Winit-self", "-Winline", "-Wmissing-format-attribute",
|
||||||
|
"-Wmissing-include-dirs", "-Wswitch", "-Wundef", "-Wdisabled-optimization",
|
||||||
|
"-Wpointer-arith", "-Wno-attributes", "-Wno-sign-compare", "-Wno-multichar",
|
||||||
|
"-Wno-div-by-zero", "-Wno-endif-labels", "-Wno-pragmas", "-Wno-format-extra-args",
|
||||||
|
"-Wno-unused-result", "-Wno-deprecated-declarations", "-Wno-unused-function",
|
||||||
|
"-Wno-address-of-packed-member", "-Wno-invalid-offsetof", "-Wno-format-nonliteral",
|
||||||
|
"-Werror" ]
|
||||||
|
|
||||||
|
asflags: [
|
||||||
|
"-DVERSION_MAJOR=${version_major}",
|
||||||
|
"-DVERSION_MINOR=${version_minor}",
|
||||||
|
"-DVERSION_PATCH=${version_patch}",
|
||||||
|
"-DVERSION_GITSHA=0x${version_sha}",
|
||||||
|
"-I${source_root}/src/include" ]
|
||||||
|
|
||||||
|
cflags: [ "-std=c11" ]
|
||||||
|
cxxflags: [ "-std=c++17" ]
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
---
|
|
||||||
extends: base
|
|
||||||
|
|
||||||
variables:
|
|
||||||
asflags: [ "-I${source_root}/src/kernel/" ]
|
|
||||||
|
|
||||||
ccflags: [
|
|
||||||
"--target=x86_64-jsix-elf",
|
|
||||||
"-fno-stack-protector",
|
|
||||||
|
|
||||||
"-I${source_root}/external",
|
|
||||||
|
|
||||||
"-nostdinc",
|
|
||||||
"-nostdlib",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-nodefaultlibs",
|
|
||||||
"-fno-builtin",
|
|
||||||
"-fno-plt",
|
|
||||||
|
|
||||||
"-mno-sse",
|
|
||||||
"-fno-omit-frame-pointer",
|
|
||||||
"-mno-red-zone",
|
|
||||||
"-mcmodel=kernel",
|
|
||||||
"-fvisibility=hidden",
|
|
||||||
"-fvisibility-inlines-hidden",
|
|
||||||
|
|
||||||
"-g3",
|
|
||||||
"-ggdb",
|
|
||||||
|
|
||||||
"-D__ELF__",
|
|
||||||
"-D__jsix__",
|
|
||||||
"-D__j6kernel",
|
|
||||||
"-U__linux",
|
|
||||||
"-U__linux__",
|
|
||||||
"-DPRINTF_ALIAS_STANDARD_FUNCTION_NAMES=1",
|
|
||||||
"-DPRINTF_INCLUDE_CONFIG_H=1",
|
|
||||||
|
|
||||||
"-isystem${build_root}/include/libc",
|
|
||||||
"-isystem${source_root}/sysroot/include",
|
|
||||||
"--sysroot='${source_root}/sysroot'" ]
|
|
||||||
|
|
||||||
|
|
||||||
cflags: [ '-nostdinc' ]
|
|
||||||
|
|
||||||
cxxflags: [
|
|
||||||
"-fno-exceptions",
|
|
||||||
"-fno-rtti",
|
|
||||||
"-nostdinc",
|
|
||||||
"-isystem${source_root}/sysroot/include/c++/v1" ]
|
|
||||||
|
|
||||||
ldflags: [
|
|
||||||
"-g",
|
|
||||||
"-m", "elf_x86_64",
|
|
||||||
"-nostdlib",
|
|
||||||
"-Bstatic",
|
|
||||||
"--no-eh-frame-hdr",
|
|
||||||
"-z", "norelro",
|
|
||||||
"-z", "separate-code" ]
|
|
||||||
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
# This file is automatically generated by bonnibel
|
|
||||||
|
|
||||||
rule compile.c
|
rule compile.c
|
||||||
command = $cc -MMD -MF $out.d $cflags $ccflags -o $out -c $in
|
command = $cc -MMD -MF $out.d $cflags $ccflags -o $out -c $in
|
||||||
description = Compiling $name
|
description = Compiling [$target]:$name
|
||||||
depfile = $out.d
|
depfile = $out.d
|
||||||
deps = gcc
|
deps = gcc
|
||||||
|
|
||||||
@@ -17,7 +15,7 @@ rule dump_c_run
|
|||||||
|
|
||||||
rule compile.cpp
|
rule compile.cpp
|
||||||
command = $cxx -MMD -MF $out.d $cxxflags $ccflags -o $out -c $in
|
command = $cxx -MMD -MF $out.d $cxxflags $ccflags -o $out -c $in
|
||||||
description = Compiling $name
|
description = Compiling [$target]:$name
|
||||||
depfile = $out.d
|
depfile = $out.d
|
||||||
deps = gcc
|
deps = gcc
|
||||||
|
|
||||||
@@ -32,25 +30,33 @@ rule dump_cpp_run
|
|||||||
|
|
||||||
rule compile.s
|
rule compile.s
|
||||||
command = $nasm -o $out -felf64 -MD $out.d $asflags $in
|
command = $nasm -o $out -felf64 -MD $out.d $asflags $in
|
||||||
description = Assembling $name
|
description = Assembling [$target]:$name
|
||||||
depfile = $out.d
|
depfile = $out.d
|
||||||
deps = gcc
|
deps = gcc
|
||||||
|
|
||||||
rule parse.cog
|
rule parse.cog
|
||||||
command = cog -o $out -d -D target=$target $cogflags $in
|
command = cog -o $out -d -D target=$target $cogflags $in
|
||||||
description = Parsing $name
|
description = Parsing [$target]:$name
|
||||||
|
|
||||||
rule exe
|
rule exe
|
||||||
command = $ld $ldflags -o $out $in $libs
|
command = $ld $ldflags -o $out $in $libs
|
||||||
description = Linking $name
|
description = Linking exe [$target]:$name
|
||||||
|
|
||||||
|
rule driver
|
||||||
|
command = $ld $ldflags -o $out $in $libs
|
||||||
|
description = Linking driver [$target]:$name
|
||||||
|
|
||||||
rule lib
|
rule lib
|
||||||
|
command = $ld -shared -soname $soname $ldflags -o $out $in $libs
|
||||||
|
description = Linking [$target]:$name
|
||||||
|
|
||||||
|
rule lib_static
|
||||||
command = $ar qcs $out $in
|
command = $ar qcs $out $in
|
||||||
description = Archiving $name
|
description = Archiving [$target]:$name
|
||||||
|
|
||||||
rule cp
|
rule cp
|
||||||
command = cp $in $out
|
command = cp $in $out
|
||||||
description = Copying $name
|
description = Copying [$target]:$name
|
||||||
|
|
||||||
rule dump
|
rule dump
|
||||||
command = objdump -DSC -M intel $in > $out
|
command = objdump -DSC -M intel $in > $out
|
||||||
|
|||||||
26
assets/build/target.boot.yaml
Normal file
26
assets/build/target.boot.yaml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
ld: clang++
|
||||||
|
|
||||||
|
ccflags: [
|
||||||
|
"-nostdlib",
|
||||||
|
"-nodefaultlibs",
|
||||||
|
"-fno-builtin",
|
||||||
|
|
||||||
|
"-I${source_root}/external",
|
||||||
|
"--target=x86_64-unknown-windows",
|
||||||
|
"-ffreestanding",
|
||||||
|
"-mno-red-zone",
|
||||||
|
"-fshort-wchar",
|
||||||
|
"-fno-omit-frame-pointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
cxxflags: [ "-fno-exceptions", "-fno-rtti" ]
|
||||||
|
|
||||||
|
ldflags: [
|
||||||
|
"--target=x86_64-unknown-windows",
|
||||||
|
"-nostdlib",
|
||||||
|
"-Wl,-entry:efi_main",
|
||||||
|
"-Wl,-subsystem:efi_application",
|
||||||
|
"-fuse-ld=lld-link",
|
||||||
|
]
|
||||||
|
|
||||||
39
assets/build/target.init.yaml
Normal file
39
assets/build/target.init.yaml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
ccflags: [
|
||||||
|
"--target=x86_64-jsix-elf",
|
||||||
|
"-fno-omit-frame-pointer",
|
||||||
|
"-fno-stack-protector",
|
||||||
|
|
||||||
|
"-fvisibility=hidden",
|
||||||
|
"-fvisibility-inlines-hidden",
|
||||||
|
|
||||||
|
"-D__ELF__",
|
||||||
|
"-D__jsix__",
|
||||||
|
"-U__linux",
|
||||||
|
"-U__linux__",
|
||||||
|
|
||||||
|
"-DMSPACES",
|
||||||
|
|
||||||
|
"--sysroot='${source_root}/sysroot'"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
cxxflags: [
|
||||||
|
"-fno-exceptions",
|
||||||
|
"-fno-rtti",
|
||||||
|
]
|
||||||
|
|
||||||
|
ldflags: [
|
||||||
|
"-Bstatic",
|
||||||
|
"-m", "elf_x86_64",
|
||||||
|
"--sysroot='${source_root}/sysroot'",
|
||||||
|
"--no-eh-frame-hdr",
|
||||||
|
"-L", "${source_root}/sysroot/lib",
|
||||||
|
"-z", "separate-code",
|
||||||
|
"-lc++", "-lc++abi", "-lunwind",
|
||||||
|
"--no-dependent-libraries",
|
||||||
|
]
|
||||||
|
|
||||||
|
libs: [
|
||||||
|
"${target_dir}/crt0.o",
|
||||||
|
]
|
||||||
52
assets/build/target.kernel.yaml
Normal file
52
assets/build/target.kernel.yaml
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
asflags: [ "-I${source_root}/src/kernel/" ]
|
||||||
|
|
||||||
|
ccflags: [
|
||||||
|
"--target=x86_64-jsix-elf",
|
||||||
|
"-fno-stack-protector",
|
||||||
|
|
||||||
|
"-I${source_root}/external",
|
||||||
|
|
||||||
|
"-nostdinc",
|
||||||
|
"-nostdlib",
|
||||||
|
"-ffreestanding",
|
||||||
|
"-nodefaultlibs",
|
||||||
|
"-fno-builtin",
|
||||||
|
"-fno-plt",
|
||||||
|
|
||||||
|
"-mno-sse",
|
||||||
|
"-fno-omit-frame-pointer",
|
||||||
|
"-mno-red-zone",
|
||||||
|
"-mcmodel=kernel",
|
||||||
|
"-fvisibility=hidden",
|
||||||
|
"-fvisibility-inlines-hidden",
|
||||||
|
|
||||||
|
"-D__ELF__",
|
||||||
|
"-D__jsix__",
|
||||||
|
"-D__j6kernel",
|
||||||
|
"-U__linux",
|
||||||
|
"-U__linux__",
|
||||||
|
"-DPRINTF_ALIAS_STANDARD_FUNCTION_NAMES=1",
|
||||||
|
"-DPRINTF_INCLUDE_CONFIG_H=1",
|
||||||
|
|
||||||
|
"--sysroot='${source_root}/sysroot'"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
cflags: [ '-nostdinc' ]
|
||||||
|
|
||||||
|
cxxflags: [
|
||||||
|
"-fno-exceptions",
|
||||||
|
"-fno-rtti",
|
||||||
|
"-nostdinc",
|
||||||
|
]
|
||||||
|
|
||||||
|
ldflags: [
|
||||||
|
"-m", "elf_x86_64",
|
||||||
|
"-nostdlib",
|
||||||
|
"-Bstatic",
|
||||||
|
"--no-eh-frame-hdr",
|
||||||
|
"-z", "norelro",
|
||||||
|
"-z", "separate-code"
|
||||||
|
]
|
||||||
|
|
||||||
15
assets/build/target.user.exe.yaml
Normal file
15
assets/build/target.user.exe.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
ccflags: [
|
||||||
|
"-fpie"
|
||||||
|
]
|
||||||
|
|
||||||
|
ldflags: [
|
||||||
|
"-pie",
|
||||||
|
"--dynamic-linker", "/jsix/lib/ld.so",
|
||||||
|
"--push-state", "--as-needed", "-Bstatic", "-lc++", "-lc++abi", "-lunwind", "--pop-state",
|
||||||
|
]
|
||||||
|
|
||||||
|
libs: [
|
||||||
|
"${target_dir}/crt0.o",
|
||||||
|
]
|
||||||
7
assets/build/target.user.shared.yaml
Normal file
7
assets/build/target.user.shared.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
ccflags: [
|
||||||
|
]
|
||||||
|
|
||||||
|
ldflags: [
|
||||||
|
"-shared",
|
||||||
|
]
|
||||||
33
assets/build/target.user.yaml
Normal file
33
assets/build/target.user.yaml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
asflags: []
|
||||||
|
|
||||||
|
ccflags: [
|
||||||
|
"--target=x86_64-jsix-elf",
|
||||||
|
"-fno-omit-frame-pointer",
|
||||||
|
"-fno-stack-protector",
|
||||||
|
|
||||||
|
"-fvisibility=hidden",
|
||||||
|
"-fvisibility-inlines-hidden",
|
||||||
|
|
||||||
|
"-D__ELF__",
|
||||||
|
"-D__jsix__",
|
||||||
|
"-U__linux",
|
||||||
|
"-U__linux__",
|
||||||
|
|
||||||
|
"--sysroot='${source_root}/sysroot'",
|
||||||
|
"-fpic",
|
||||||
|
]
|
||||||
|
|
||||||
|
cxxflags: [
|
||||||
|
"-fno-exceptions",
|
||||||
|
"-fno-rtti",
|
||||||
|
]
|
||||||
|
|
||||||
|
ldflags: [
|
||||||
|
"-m", "elf_x86_64",
|
||||||
|
"--sysroot='${source_root}/sysroot'",
|
||||||
|
"--no-eh-frame-hdr",
|
||||||
|
"-L", "${source_root}/sysroot/lib",
|
||||||
|
"-z", "separate-code",
|
||||||
|
"--no-dependent-libraries",
|
||||||
|
]
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
---
|
|
||||||
extends: base
|
|
||||||
|
|
||||||
variables:
|
|
||||||
asflags: [ "-I${source_root}/src/kernel/" ]
|
|
||||||
|
|
||||||
ccflags: [
|
|
||||||
"--target=x86_64-jsix-elf",
|
|
||||||
"-fno-omit-frame-pointer",
|
|
||||||
"-fno-stack-protector",
|
|
||||||
|
|
||||||
"-g",
|
|
||||||
|
|
||||||
"-D__ELF__",
|
|
||||||
"-D__jsix__",
|
|
||||||
"-U__linux",
|
|
||||||
"-U__linux__",
|
|
||||||
|
|
||||||
"-isystem${source_root}/sysroot/include",
|
|
||||||
"-isystem${build_root}/include/libc",
|
|
||||||
"--sysroot='${source_root}/sysroot'" ]
|
|
||||||
|
|
||||||
|
|
||||||
cxxflags: [
|
|
||||||
"-fno-exceptions",
|
|
||||||
"-fno-rtti",
|
|
||||||
"-isystem${source_root}/sysroot/include/c++/v1" ]
|
|
||||||
|
|
||||||
ldflags: [
|
|
||||||
"-g",
|
|
||||||
"-Bstatic",
|
|
||||||
"--sysroot='${source_root}/sysroot'",
|
|
||||||
"-L", "${source_root}/sysroot/lib",
|
|
||||||
"-z", "separate-code",
|
|
||||||
"-lc++", "-lc++abi", "-lunwind",
|
|
||||||
"--no-dependent-libraries",
|
|
||||||
]
|
|
||||||
|
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
import gdb
|
import gdb
|
||||||
import gdb.printing
|
import gdb.printing
|
||||||
|
|
||||||
|
import sys
|
||||||
|
sys.path.append('./scripts')
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
Capability = namedtuple("Capability", ["id", "parent", "refcount", "caps", "type", "koid"])
|
Capability = namedtuple("Capability", ["id", "parent", "refcount", "caps", "type", "koid"])
|
||||||
|
LogEntry = namedtuple("LogHeader", ["id", "bytes", "severity", "area", "message"])
|
||||||
|
|
||||||
class PrintStackCommand(gdb.Command):
|
class PrintStackCommand(gdb.Command):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -168,12 +174,12 @@ class GetThreadsCommand(gdb.Command):
|
|||||||
rsp = int(gdb.parse_and_eval(f"{tcb}->rsp"))
|
rsp = int(gdb.parse_and_eval(f"{tcb}->rsp"))
|
||||||
pri = int(gdb.parse_and_eval(f"{tcb}->priority"))
|
pri = int(gdb.parse_and_eval(f"{tcb}->priority"))
|
||||||
flags = int(gdb.parse_and_eval(f"{thread}->m_state"))
|
flags = int(gdb.parse_and_eval(f"{thread}->m_state"))
|
||||||
koid = int(gdb.parse_and_eval(f"{thread}->m_koid"))
|
koid = int(gdb.parse_and_eval(f"{thread}->m_obj_id"))
|
||||||
proc = int(gdb.parse_and_eval(f"{thread}->m_parent.m_koid"))
|
proc = int(gdb.parse_and_eval(f"{thread}->m_parent.m_obj_id"))
|
||||||
|
|
||||||
creator = int(gdb.parse_and_eval(f"{thread}->m_creator"))
|
creator = int(gdb.parse_and_eval(f"{thread}->m_creator"))
|
||||||
if creator != 0:
|
if creator != 0:
|
||||||
creator_koid = int(gdb.parse_and_eval(f"{thread}->m_creator->m_koid"))
|
creator_koid = int(gdb.parse_and_eval(f"{thread}->m_creator->m_obj_id"))
|
||||||
creator = f"{creator_koid:x}"
|
creator = f"{creator_koid:x}"
|
||||||
else:
|
else:
|
||||||
creator = "<no thread>"
|
creator = "<no thread>"
|
||||||
@@ -233,11 +239,7 @@ class GetThreadsCommand(gdb.Command):
|
|||||||
self.print_cpudata(cpu)
|
self.print_cpudata(cpu)
|
||||||
|
|
||||||
previous = int(gdb.parse_and_eval(f"{runlist}.prev"))
|
previous = int(gdb.parse_and_eval(f"{runlist}.prev"))
|
||||||
if previous != 0:
|
print(f" prev: {previous:x}")
|
||||||
tcb = f"((TCB*){previous:#x})"
|
|
||||||
thread = f"({tcb}->thread)"
|
|
||||||
koid = int(gdb.parse_and_eval(f"{thread}->m_koid"))
|
|
||||||
print(f" prev: {koid:x}")
|
|
||||||
print()
|
print()
|
||||||
|
|
||||||
for pri in range(8):
|
for pri in range(8):
|
||||||
@@ -283,6 +285,79 @@ class PrintProfilesCommand(gdb.Command):
|
|||||||
print(f"{name:>{max_len}}: {avg:15.3f}")
|
print(f"{name:>{max_len}}: {avg:15.3f}")
|
||||||
|
|
||||||
|
|
||||||
|
class DumpLogCommand(gdb.Command):
|
||||||
|
level_names = ["", "fatal", "error", "warn", "info", "verbose", "spam"]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("j6log", gdb.COMMAND_DATA)
|
||||||
|
|
||||||
|
from memory import Layout
|
||||||
|
layout = Layout("definitions/memory_layout.yaml")
|
||||||
|
for region in layout.regions:
|
||||||
|
if region.name == "logs":
|
||||||
|
self.base_addr = region.start
|
||||||
|
break
|
||||||
|
|
||||||
|
self.areas = []
|
||||||
|
area_re = re.compile(r"LOG\(\s*(\w+).*")
|
||||||
|
with open("src/libraries/j6/include/j6/tables/log_areas.inc", 'r') as areas_inc:
|
||||||
|
for line in areas_inc:
|
||||||
|
m = area_re.match(line)
|
||||||
|
if m:
|
||||||
|
self.areas.append(m.group(1))
|
||||||
|
|
||||||
|
def get_entry(self, addr):
|
||||||
|
addr = int(addr)
|
||||||
|
size = int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->bytes"))
|
||||||
|
mlen = size - 8
|
||||||
|
|
||||||
|
return LogEntry(
|
||||||
|
int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->id")),
|
||||||
|
size,
|
||||||
|
int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->severity")),
|
||||||
|
int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->area")),
|
||||||
|
gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->message").string(length=mlen))
|
||||||
|
|
||||||
|
def invoke(self, arg, from_tty):
|
||||||
|
start = gdb.parse_and_eval("g_logger.m_start & (g_logger.m_buffer.count - 1)")
|
||||||
|
end = gdb.parse_and_eval("g_logger.m_end & (g_logger.m_buffer.count - 1)")
|
||||||
|
if end < start:
|
||||||
|
end += gdb.parse_and_eval("g_logger.m_buffer.count")
|
||||||
|
|
||||||
|
print(f"Logs are {start} -> {end}")
|
||||||
|
|
||||||
|
addr = self.base_addr + start
|
||||||
|
end += self.base_addr
|
||||||
|
while addr < end:
|
||||||
|
entry = self.get_entry(addr)
|
||||||
|
if entry.bytes < 8:
|
||||||
|
print(f"Bad log header size: {entry.bytes}")
|
||||||
|
break
|
||||||
|
addr += entry.bytes
|
||||||
|
area = "??"
|
||||||
|
if entry.area < len(self.areas):
|
||||||
|
area = self.areas[entry.area]
|
||||||
|
level = self.level_names[entry.severity]
|
||||||
|
print(f"{area:>7}:{level:7} {entry.message}")
|
||||||
|
|
||||||
|
|
||||||
|
class ShowCurrentProcessCommand(gdb.Command):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("j6current", gdb.COMMAND_DATA)
|
||||||
|
|
||||||
|
def invoke(self, arg, from_tty):
|
||||||
|
def get_obj_and_id(name):
|
||||||
|
obj = int(gdb.parse_and_eval(f"((cpu_data*)$gs_base)->{name}"))
|
||||||
|
oid = -1
|
||||||
|
if obj != 0:
|
||||||
|
oid = int(gdb.parse_and_eval(f"((obj::kobject*){obj:#x})->m_obj_id"))
|
||||||
|
return obj, oid
|
||||||
|
|
||||||
|
process, pid = get_obj_and_id("process")
|
||||||
|
thread, tid = get_obj_and_id("thread")
|
||||||
|
print(f"{pid:02x}/{tid:02x} [ {process:x} / {thread:x} ]")
|
||||||
|
|
||||||
|
|
||||||
class CapTablePrinter:
|
class CapTablePrinter:
|
||||||
def __init__(self, val):
|
def __init__(self, val):
|
||||||
node_map = val["m_caps"]
|
node_map = val["m_caps"]
|
||||||
@@ -307,7 +382,7 @@ class CapTablePrinter:
|
|||||||
refcount = int(node["holders"]),
|
refcount = int(node["holders"]),
|
||||||
caps = int(node["caps"]),
|
caps = int(node["caps"]),
|
||||||
type = str(node["type"])[14:],
|
type = str(node["type"])[14:],
|
||||||
koid = node['object']['m_koid']))
|
koid = node['object']['m_obj_id']))
|
||||||
|
|
||||||
self.nodes.sort(key=lambda n: n.id, reverse=True)
|
self.nodes.sort(key=lambda n: n.id, reverse=True)
|
||||||
|
|
||||||
@@ -399,11 +474,39 @@ class HandleSetPrinter:
|
|||||||
return self._iterator(self.node_map['m_nodes'], self.capacity)
|
return self._iterator(self.node_map['m_nodes'], self.capacity)
|
||||||
|
|
||||||
|
|
||||||
|
class LinkedListPrinter:
|
||||||
|
def __init__(self, llist):
|
||||||
|
self.name = llist.type.tag
|
||||||
|
self.head = llist['m_head']
|
||||||
|
self.tail = llist['m_tail']
|
||||||
|
|
||||||
|
self.items = []
|
||||||
|
current = self.head
|
||||||
|
while current:
|
||||||
|
item = current.dereference()
|
||||||
|
self.items.append((str(len(self.items)), item))
|
||||||
|
current = item['m_next']
|
||||||
|
|
||||||
|
class _iterator:
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return f"{self.name}[{len(self.items)}]"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.items
|
||||||
|
|
||||||
|
|
||||||
def build_pretty_printers():
|
def build_pretty_printers():
|
||||||
pp = gdb.printing.RegexpCollectionPrettyPrinter("jsix")
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("jsix")
|
||||||
pp.add_printer("cap table", '^cap_table$', CapTablePrinter)
|
pp.add_printer("cap table", '^cap_table$', CapTablePrinter)
|
||||||
pp.add_printer("handle set", '^util::node_set<unsigned long, 0, heap_allocated>$', HandleSetPrinter)
|
pp.add_printer("handle set", '^util::node_set<unsigned long, 0, heap_allocated>$', HandleSetPrinter)
|
||||||
pp.add_printer("vector", '^util::vector<.*>$', VectorPrinter)
|
pp.add_printer("vector", '^util::vector<.*>$', VectorPrinter)
|
||||||
|
pp.add_printer("linked list", '^util::linked_list<.*>$', LinkedListPrinter)
|
||||||
return pp
|
return pp
|
||||||
|
|
||||||
gdb.printing.register_pretty_printer(
|
gdb.printing.register_pretty_printer(
|
||||||
@@ -415,8 +518,11 @@ PrintBacktraceCommand()
|
|||||||
TableWalkCommand()
|
TableWalkCommand()
|
||||||
GetThreadsCommand()
|
GetThreadsCommand()
|
||||||
PrintProfilesCommand()
|
PrintProfilesCommand()
|
||||||
|
DumpLogCommand()
|
||||||
|
ShowCurrentProcessCommand()
|
||||||
|
|
||||||
gdb.execute("display/i $rip")
|
gdb.execute("display/i $rip")
|
||||||
|
gdb.execute("define hook-quit\nkill\nend")
|
||||||
if not gdb.selected_inferior().was_attached:
|
if not gdb.selected_inferior().was_attached:
|
||||||
gdb.execute("add-symbol-file build/panic.serial.elf")
|
gdb.execute("add-symbol-file build/panic.serial.elf")
|
||||||
gdb.execute("target remote :1234")
|
gdb.execute("target remote :1234")
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ name: IDENTIFIER
|
|||||||
options: "[" ( OPTION | IDENTIFIER )+ "]"
|
options: "[" ( OPTION | IDENTIFIER )+ "]"
|
||||||
description: COMMENT+
|
description: COMMENT+
|
||||||
|
|
||||||
PRIMITIVE: INT_TYPE | "size" | "string" | "buffer" | "address"
|
PRIMITIVE: INT_TYPE "*"? | "size" | "string" | "buffer" | "address"
|
||||||
INT_TYPE: /u?int(8|16|32|64)?/
|
INT_TYPE: /u?int(8|16|32|64)?/
|
||||||
NUMBER: /(0x)?[0-9a-fA-F]+/
|
NUMBER: /(0x)?[0-9a-fA-F]+/
|
||||||
UID: /[0-9a-fA-F]{16}/
|
UID: /[0-9a-fA-F]{16}/
|
||||||
|
|||||||
@@ -8,5 +8,9 @@ panic:
|
|||||||
- panic.serial
|
- panic.serial
|
||||||
services:
|
services:
|
||||||
- srv.logger
|
- srv.logger
|
||||||
|
- testapp
|
||||||
drivers:
|
drivers:
|
||||||
- drv.uart
|
- drv.uart
|
||||||
|
- drv.uefi_fb
|
||||||
|
libs:
|
||||||
|
- ld.so
|
||||||
@@ -9,5 +9,3 @@ panic:
|
|||||||
- panic.serial
|
- panic.serial
|
||||||
services:
|
services:
|
||||||
- test_runner
|
- test_runner
|
||||||
drivers:
|
|
||||||
- drv.uart
|
|
||||||
|
|||||||
1
configure
vendored
1
configure
vendored
@@ -35,6 +35,7 @@ def generate(output, config, manifest):
|
|||||||
"source_root": root,
|
"source_root": root,
|
||||||
"build_root": output,
|
"build_root": output,
|
||||||
"module_root": path,
|
"module_root": path,
|
||||||
|
"config": config,
|
||||||
}
|
}
|
||||||
code = compile(open(modfile, 'r').read(), modfile, "exec")
|
code = compile(open(modfile, 'r').read(), modfile, "exec")
|
||||||
|
|
||||||
|
|||||||
@@ -24,3 +24,6 @@
|
|||||||
|
|
||||||
- name: buffers
|
- name: buffers
|
||||||
size: 64G
|
size: 64G
|
||||||
|
|
||||||
|
- name: logs
|
||||||
|
size: 2G
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
object channel : object {
|
|
||||||
uid 3ea38b96aa0e54c8
|
|
||||||
|
|
||||||
capabilities [
|
|
||||||
send
|
|
||||||
receive
|
|
||||||
close
|
|
||||||
]
|
|
||||||
|
|
||||||
method create [constructor]
|
|
||||||
method close [destructor cap:close]
|
|
||||||
|
|
||||||
method send [cap:send] {
|
|
||||||
param data buffer [inout]
|
|
||||||
}
|
|
||||||
|
|
||||||
method receive [cap:receive] {
|
|
||||||
param data buffer [out]
|
|
||||||
param flags uint64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
# Mailboxes are objects that enable synchronous IPC via short message-passing
|
# Mailboxes are objects that enable synchronous IPC via arbitrary
|
||||||
# of tagged handles.
|
# message-passing of tagged data and/or handles. Not as efficient
|
||||||
|
# as shared memory channels, but more flexible.
|
||||||
|
|
||||||
object mailbox : object {
|
object mailbox : object {
|
||||||
uid 99934ad04ece1e07
|
uid 99934ad04ece1e07
|
||||||
@@ -13,13 +14,14 @@ object mailbox : object {
|
|||||||
method create [constructor]
|
method create [constructor]
|
||||||
method close [destructor cap:close]
|
method close [destructor cap:close]
|
||||||
|
|
||||||
# Send a message to the reciever, and block until a
|
# Send a message to the reciever, and block until a response is
|
||||||
# response is sent. Note that getting this response
|
# sent. Note that getting this response does not require the
|
||||||
# does not require the receive capability.
|
# receive capability.
|
||||||
method call [cap:send] {
|
method call [cap:send] {
|
||||||
param tag uint64 [inout]
|
param tag uint64 [inout]
|
||||||
param subtag uint64 [inout]
|
param data buffer [optional inout]
|
||||||
param give_handle ref object [optional inout handle]
|
param data_in_len size # number of bytes in data used for input
|
||||||
|
param handles ref object [optional inout handle list]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Respond to a message sent using call, and wait for another
|
# Respond to a message sent using call, and wait for another
|
||||||
@@ -28,8 +30,9 @@ object mailbox : object {
|
|||||||
# to waiting for a new message.
|
# to waiting for a new message.
|
||||||
method respond [cap:receive] {
|
method respond [cap:receive] {
|
||||||
param tag uint64 [inout]
|
param tag uint64 [inout]
|
||||||
param subtag uint64 [inout]
|
param data buffer [optional inout]
|
||||||
param give_handle ref object [optional inout handle]
|
param data_in_len size # number of bytes in data used for input
|
||||||
|
param handles ref object [optional inout handle list]
|
||||||
param reply_tag uint64 [inout]
|
param reply_tag uint64 [inout]
|
||||||
param flags uint64
|
param flags uint64
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,10 @@ object system : object {
|
|||||||
change_iopl
|
change_iopl
|
||||||
]
|
]
|
||||||
|
|
||||||
# Get a log line from the kernel log
|
# Get the next log line from the kernel log
|
||||||
method get_log [cap:get_log] {
|
method get_log [cap:get_log] {
|
||||||
param buffer buffer [out zero_ok] # Buffer for the log message data structure
|
param seen uint64 # Last seen log id
|
||||||
|
param buffer buffer [out zero_ok] # Buffer for the log message data structure
|
||||||
}
|
}
|
||||||
|
|
||||||
# Ask the kernel to send this process messages whenever
|
# Ask the kernel to send this process messages whenever
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ object thread : object {
|
|||||||
]
|
]
|
||||||
|
|
||||||
method create [constructor] {
|
method create [constructor] {
|
||||||
param process ref process [cap:create_thread]
|
param process ref process [optional cap:create_thread]
|
||||||
param stack_top address
|
param stack_top address
|
||||||
param entrypoint address
|
param entrypoint address
|
||||||
|
param arg0 uint64
|
||||||
|
param arg1 uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
method kill [destructor cap:kill]
|
method kill [destructor cap:kill]
|
||||||
|
|||||||
@@ -17,20 +17,21 @@ object vma : object {
|
|||||||
|
|
||||||
method create_map [constructor cap:map] {
|
method create_map [constructor cap:map] {
|
||||||
param size size
|
param size size
|
||||||
param address address
|
param address address [inout]
|
||||||
param flags uint32
|
param flags uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
method map [cap:map] {
|
method map [cap:map] {
|
||||||
param process ref process
|
param process ref process [optional]
|
||||||
param address address
|
param address address [inout]
|
||||||
|
param flags uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
method unmap [cap:unmap] {
|
method unmap [cap:unmap] {
|
||||||
param process ref process
|
param process ref process [optional]
|
||||||
}
|
}
|
||||||
|
|
||||||
method resize [cap:resize] {
|
method resize [cap:resize] {
|
||||||
param size size [inout]
|
param size size [inout] # New size for the VMA, or 0 to query the current size without changing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import "objects/object.def"
|
import "objects/object.def"
|
||||||
|
|
||||||
import "objects/channel.def"
|
|
||||||
import "objects/event.def"
|
import "objects/event.def"
|
||||||
import "objects/mailbox.def"
|
import "objects/mailbox.def"
|
||||||
import "objects/process.def"
|
import "objects/process.def"
|
||||||
@@ -12,12 +11,12 @@ interface syscalls [syscall] {
|
|||||||
uid 01d9b6a948961097
|
uid 01d9b6a948961097
|
||||||
|
|
||||||
expose ref object
|
expose ref object
|
||||||
expose ref system
|
|
||||||
expose ref event
|
expose ref event
|
||||||
expose ref process
|
|
||||||
expose ref thread
|
|
||||||
expose ref mailbox
|
expose ref mailbox
|
||||||
expose ref channel
|
expose ref process
|
||||||
|
expose ref system
|
||||||
|
expose ref thread
|
||||||
expose ref vma
|
expose ref vma
|
||||||
|
|
||||||
# Simple no-op syscall for testing
|
# Simple no-op syscall for testing
|
||||||
@@ -43,6 +42,19 @@ interface syscalls [syscall] {
|
|||||||
param mask uint32 # The capability bitmask
|
param mask uint32 # The capability bitmask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Block waiting on a futex
|
||||||
|
function futex_wait [static] {
|
||||||
|
param address uint32* # Address of the futex value
|
||||||
|
param current uint32 # Current value of the futex
|
||||||
|
param timeout uint64 # Wait timeout in nanoseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wake threads waiting on a futex
|
||||||
|
function futex_wake [static] {
|
||||||
|
param address uint32* # Address of the futex value
|
||||||
|
param count uint64 # Number of threads to wake, or 0 for all
|
||||||
|
}
|
||||||
|
|
||||||
# Testing mode only: Have the kernel finish and exit QEMU with the given exit code
|
# Testing mode only: Have the kernel finish and exit QEMU with the given exit code
|
||||||
function test_finish [test] {
|
function test_finish [test] {
|
||||||
param exit_code uint32
|
param exit_code uint32
|
||||||
|
|||||||
4
external/zstd.module
vendored
4
external/zstd.module
vendored
@@ -3,8 +3,8 @@
|
|||||||
zstd = module("zstd",
|
zstd = module("zstd",
|
||||||
root = "${source_root}/external/zstd",
|
root = "${source_root}/external/zstd",
|
||||||
kind = "lib",
|
kind = "lib",
|
||||||
deps = [ ],
|
copy_headers = True,
|
||||||
output = "libzstd.a",
|
deps = [ "libc" ],
|
||||||
sources = [
|
sources = [
|
||||||
"decompress/zstd_decompress.c",
|
"decompress/zstd_decompress.c",
|
||||||
"decompress/zstd_ddict.c",
|
"decompress/zstd_ddict.c",
|
||||||
|
|||||||
77
qemu.sh
77
qemu.sh
@@ -1,7 +1,10 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
build="$(dirname $0)/build"
|
root=$(dirname $0)
|
||||||
assets="$(dirname $0)/assets"
|
build="${root}/build"
|
||||||
|
assets="${root}/assets"
|
||||||
|
|
||||||
|
no_build=""
|
||||||
debug=""
|
debug=""
|
||||||
isaexit='-device isa-debug-exit,iobase=0xf4,iosize=0x04'
|
isaexit='-device isa-debug-exit,iobase=0xf4,iosize=0x04'
|
||||||
debugtarget="${build}/jsix.elf"
|
debugtarget="${build}/jsix.elf"
|
||||||
@@ -9,7 +12,9 @@ gfx="-nographic"
|
|||||||
vga="-vga none"
|
vga="-vga none"
|
||||||
log=""
|
log=""
|
||||||
kvm=""
|
kvm=""
|
||||||
cpu="Broadwell,+pdpe1gb"
|
debugcon_cmd=""
|
||||||
|
cpu_features=",+pdpe1gb,+invtsc,+hypervisor,+x2apic,+xsavec,+xsaves,+xsaveopt"
|
||||||
|
cpu="Broadwell"
|
||||||
smp=4
|
smp=4
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
@@ -35,14 +40,14 @@ while true; do
|
|||||||
;;
|
;;
|
||||||
-r | --remote)
|
-r | --remote)
|
||||||
shift
|
shift
|
||||||
vnchost="${1:-${VNCHOST:-localhost}}"
|
vnchost="${1:-${VNCHOST:-"localhost:5500"}}"
|
||||||
gfx="-vnc ${vnchost}:7000,reverse"
|
gfx="-vnc ${vnchost},reverse"
|
||||||
vga=""
|
vga=""
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
-k | --kvm)
|
-k | --kvm)
|
||||||
kvm="-enable-kvm"
|
kvm="-enable-kvm"
|
||||||
cpu="host"
|
cpu="max"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
-c | --cpus)
|
-c | --cpus)
|
||||||
@@ -50,7 +55,15 @@ while true; do
|
|||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
-l | --log)
|
-l | --log)
|
||||||
log="-d mmu,int,guest_errors -D jsix.log"
|
log="-d mmu,int,guest_errors -D ${root}/jsix.log"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-x | --debugcon)
|
||||||
|
debugcon_cmd="less --follow-name -R +F debugcon.log"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--no-build)
|
||||||
|
no_build="yes"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -67,17 +80,44 @@ if [[ ! -c /dev/kvm ]]; then
|
|||||||
kvm=""
|
kvm=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! ninja -C "${build}"; then
|
[[ -z "${no_build}" ]] && if ! ninja -C "${build}"; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $TMUX ]]; then
|
if [[ -n $TMUX ]]; then
|
||||||
|
cols=$(tput cols)
|
||||||
|
log_width=100
|
||||||
|
|
||||||
if [[ -n $debug ]]; then
|
if [[ -n $debug ]]; then
|
||||||
tmux split-window -h "gdb ${debugtarget}" &
|
log_cols=1
|
||||||
|
if [[ $debugcon_cmd ]]; then
|
||||||
|
log_cols=2
|
||||||
|
fi
|
||||||
|
|
||||||
|
gdb_width=$(($cols - $log_cols * $log_width))
|
||||||
|
|
||||||
|
if (($gdb_width < 150)); then
|
||||||
|
stack=1
|
||||||
|
gdb_width=$(($cols - $log_width))
|
||||||
|
tmux split-window -h -l $gdb_width "gdb ${debugtarget}"
|
||||||
|
if [[ $debugcon_cmd ]]; then
|
||||||
|
tmux select-pane -t .left
|
||||||
|
tmux split-window -v "$debugcon_cmd"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ $debugcon_cmd ]]; then
|
||||||
|
tmux split-window -h -l $(($log_width + $gdb_width)) "$debugcon_cmd"
|
||||||
|
fi
|
||||||
|
tmux split-window -h -l $gdb_width "gdb ${debugtarget}"
|
||||||
|
tmux select-pane -t .left
|
||||||
|
tmux select-pane -t .right
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
tmux split-window -h -l 100 "sleep 1; telnet localhost 45455" &
|
if [[ $debugcon_cmd ]]; then
|
||||||
tmux last-pane
|
tmux split-window -h -l $log_width "$debugcon_cmd"
|
||||||
tmux split-window -l 10 "sleep 1; telnet localhost 45454" &
|
tmux last-pane
|
||||||
|
fi
|
||||||
|
tmux split-window -l 10 "sleep 1; telnet localhost 45454"
|
||||||
fi
|
fi
|
||||||
elif [[ $DESKTOP_SESSION = "i3" ]]; then
|
elif [[ $DESKTOP_SESSION = "i3" ]]; then
|
||||||
if [[ -n $debug ]]; then
|
if [[ -n $debug ]]; then
|
||||||
@@ -87,19 +127,24 @@ elif [[ $DESKTOP_SESSION = "i3" ]]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -n "${debug}" ]]; then
|
||||||
|
(sleep 1; echo "Debugging ready.") &
|
||||||
|
fi
|
||||||
|
|
||||||
qemu-system-x86_64 \
|
qemu-system-x86_64 \
|
||||||
-drive "if=pflash,format=raw,readonly,file=${assets}/ovmf/x64/ovmf_code.fd" \
|
-drive "if=pflash,format=raw,readonly=on,file=${assets}/ovmf/x64/ovmf_code.fd" \
|
||||||
-drive "if=pflash,format=raw,file=${build}/ovmf_vars.fd" \
|
-drive "if=pflash,format=raw,file=${build}/ovmf_vars.fd" \
|
||||||
-drive "format=raw,file=${build}/jsix.img" \
|
-drive "format=raw,file=${build}/jsix.img" \
|
||||||
-chardev socket,host=localhost,port=45455,server,nowait,telnet=on,id=jsix_debug -device isa-debugcon,iobase=0x6600,chardev=jsix_debug \
|
-chardev "file,path=${root}/debugcon.log,id=jsix_debug" \
|
||||||
|
-device "isa-debugcon,iobase=0x6600,chardev=jsix_debug" \
|
||||||
-monitor telnet:localhost:45454,server,nowait \
|
-monitor telnet:localhost:45454,server,nowait \
|
||||||
-serial stdio \
|
-serial stdio \
|
||||||
-smp "${smp}" \
|
-smp "${smp}" \
|
||||||
-m 4096 \
|
-m 4096 \
|
||||||
-cpu "${cpu}" \
|
-cpu "${cpu}${cpu_features}" \
|
||||||
-M q35 \
|
-M q35 \
|
||||||
-no-reboot \
|
-no-reboot \
|
||||||
-name "jsix" \
|
-name jsix \
|
||||||
$isaexit $log $gfx $vga $kvm $debug
|
$isaexit $log $gfx $vga $kvm $debug
|
||||||
|
|
||||||
((result = ($? >> 1) - 1))
|
((result = ($? >> 1) - 1))
|
||||||
|
|||||||
@@ -5,3 +5,5 @@ pyyaml >= 5.4
|
|||||||
lark == 0.12.0
|
lark == 0.12.0
|
||||||
pure-cdb == 4
|
pure-cdb == 4
|
||||||
pyzstd == 0.15
|
pyzstd == 0.15
|
||||||
|
pyelftools
|
||||||
|
iced-x86
|
||||||
|
|||||||
68
scripts/bonnibel/config.py
Normal file
68
scripts/bonnibel/config.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
_config_cache = {}
|
||||||
|
|
||||||
|
def _load(filename, depfiles):
|
||||||
|
from . import load_config
|
||||||
|
if not filename in _config_cache:
|
||||||
|
if filename.exists():
|
||||||
|
depfiles.add(filename)
|
||||||
|
data = load_config(filename)
|
||||||
|
_config_cache[filename] = data
|
||||||
|
return _config_cache.get(filename, dict())
|
||||||
|
|
||||||
|
|
||||||
|
def _build_config(chain, depfiles):
|
||||||
|
config = {}
|
||||||
|
for d in [_load(c, depfiles) for c in chain]:
|
||||||
|
for k, v in d.items():
|
||||||
|
if isinstance(v, (list, tuple)):
|
||||||
|
config[k] = config.get(k, list()) + list(v)
|
||||||
|
elif isinstance(v, dict):
|
||||||
|
config[k] = config.get(k, dict())
|
||||||
|
config[k].update(v)
|
||||||
|
else:
|
||||||
|
config[k] = v
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def _make_ninja_config(outfile, config, files):
|
||||||
|
from os import makedirs
|
||||||
|
from ninja.ninja_syntax import Writer
|
||||||
|
|
||||||
|
makedirs(outfile.parent, exist_ok=True)
|
||||||
|
|
||||||
|
with open(outfile, "w") as buildfile:
|
||||||
|
build = Writer(buildfile)
|
||||||
|
build.comment("This file is automatically generated by bonnibel")
|
||||||
|
build.comment("Source config files:")
|
||||||
|
for f in files:
|
||||||
|
build.comment(f" - {f}")
|
||||||
|
|
||||||
|
build.newline()
|
||||||
|
for k, v in config.items():
|
||||||
|
build.variable(k, v)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_configs(root, output, config, targets, kinds):
|
||||||
|
|
||||||
|
assets = root / "assets" / "build"
|
||||||
|
base = ["global.yaml", f"config.{config}.yaml"]
|
||||||
|
|
||||||
|
depfiles = set()
|
||||||
|
|
||||||
|
for target in targets:
|
||||||
|
chain = base + [f"target.{target}.yaml"]
|
||||||
|
|
||||||
|
files = [assets / f for f in chain]
|
||||||
|
config = _build_config(files, depfiles)
|
||||||
|
outfile = output / target / f"config.ninja"
|
||||||
|
_make_ninja_config(outfile, config, files)
|
||||||
|
|
||||||
|
for kind in kinds:
|
||||||
|
custom = [f"kind.{kind}.yaml", f"target.{target}.{kind}.yaml"]
|
||||||
|
files = [assets / f for f in chain + custom]
|
||||||
|
config = _build_config(files, depfiles)
|
||||||
|
outfile = output / target / f"config.{kind}.ninja"
|
||||||
|
_make_ninja_config(outfile, config, files)
|
||||||
|
|
||||||
|
return depfiles
|
||||||
@@ -26,7 +26,7 @@ class Manifest:
|
|||||||
name="kernel", target="kernel")
|
name="kernel", target="kernel")
|
||||||
|
|
||||||
self.init = self.__build_entry(modules,
|
self.init = self.__build_entry(modules,
|
||||||
config.get("init", None))
|
config.get("init", None), target="init")
|
||||||
|
|
||||||
self.panics = [self.__build_entry(modules, i, target="kernel")
|
self.panics = [self.__build_entry(modules, i, target="kernel")
|
||||||
for i in config.get("panic", tuple())]
|
for i in config.get("panic", tuple())]
|
||||||
@@ -37,6 +37,13 @@ class Manifest:
|
|||||||
self.drivers = [self.__build_entry(modules, i)
|
self.drivers = [self.__build_entry(modules, i)
|
||||||
for i in config.get("drivers", tuple())]
|
for i in config.get("drivers", tuple())]
|
||||||
|
|
||||||
|
libs = set(config.get("libs", tuple()))
|
||||||
|
libs.update(self.__libdeps([modules[e.module] for e in self.services]))
|
||||||
|
libs.update(self.__libdeps([modules[e.module] for e in self.drivers]))
|
||||||
|
|
||||||
|
self.libs = [self.__build_entry(modules, i)
|
||||||
|
for i in libs]
|
||||||
|
|
||||||
self.flags = config.get("flags", tuple())
|
self.flags = config.get("flags", tuple())
|
||||||
|
|
||||||
self.symbols = ""
|
self.symbols = ""
|
||||||
@@ -71,7 +78,14 @@ class Manifest:
|
|||||||
if not f in Manifest.flags:
|
if not f in Manifest.flags:
|
||||||
raise BonnibelError(f"Manifest specifies unknown flag '{f}'")
|
raise BonnibelError(f"Manifest specifies unknown flag '{f}'")
|
||||||
|
|
||||||
return Manifest.Entry(name, target, mod.output, flags)
|
return Manifest.Entry(name, target, mod.get_output(), flags)
|
||||||
|
|
||||||
|
def __libdeps(self, modules):
|
||||||
|
deps = set([m.name for m in modules if m.kind == "lib"])
|
||||||
|
for m in modules:
|
||||||
|
if m.static: continue
|
||||||
|
deps.update(self.__libdeps(m.depmods))
|
||||||
|
return deps
|
||||||
|
|
||||||
def add_data(self, output, desc, flags=tuple()):
|
def add_data(self, output, desc, flags=tuple()):
|
||||||
e = Manifest.Entry(None, None, output, flags)
|
e = Manifest.Entry(None, None, output, flags)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from . import include_rel, mod_rel, target_rel
|
from . import include_rel, mod_rel, target_rel
|
||||||
|
from . import BonnibelError
|
||||||
|
|
||||||
def resolve(path):
|
def resolve(path):
|
||||||
if path.startswith('/') or path.startswith('$'):
|
if path.startswith('/') or path.startswith('$'):
|
||||||
@@ -7,29 +8,43 @@ def resolve(path):
|
|||||||
return str(Path(path).resolve())
|
return str(Path(path).resolve())
|
||||||
|
|
||||||
class BuildOptions:
|
class BuildOptions:
|
||||||
def __init__(self, includes=tuple(), libs=tuple(), order_only=tuple(), ld_script=None):
|
def __init__(self, includes=tuple(), local=tuple(), late=tuple(), libs=tuple(), order_only=tuple(), ld_script=None):
|
||||||
self.includes = list(includes)
|
self.includes = list(includes)
|
||||||
|
self.local = list(local)
|
||||||
|
self.late = list(late)
|
||||||
self.libs = list(libs)
|
self.libs = list(libs)
|
||||||
self.order_only = list(order_only)
|
self.order_only = list(order_only)
|
||||||
self.ld_script = ld_script and str(ld_script)
|
self.ld_script = ld_script and str(ld_script)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def implicit(self):
|
def implicit(self):
|
||||||
|
libfiles = list(map(lambda x: x[0], self.libs))
|
||||||
if self.ld_script is not None:
|
if self.ld_script is not None:
|
||||||
return self.libs + [self.ld_script]
|
return libfiles + [self.ld_script]
|
||||||
else:
|
else:
|
||||||
return self.libs
|
return libfiles
|
||||||
|
|
||||||
|
@property
|
||||||
|
def linker_args(self):
|
||||||
|
from pathlib import Path
|
||||||
|
def arg(path, static):
|
||||||
|
if static: return path
|
||||||
|
return "-l:" + Path(path).name
|
||||||
|
return [arg(*l) for l in self.libs]
|
||||||
|
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
__fields = {
|
__fields = {
|
||||||
# name: (type, default)
|
# name: (type, default)
|
||||||
"kind": (str, "exe"),
|
"kind": (str, "exe"),
|
||||||
"output": (str, None),
|
"outfile": (str, None),
|
||||||
|
"basename": (str, None),
|
||||||
"targets": (set, ()),
|
"targets": (set, ()),
|
||||||
"deps": (set, ()),
|
"deps": (set, ()),
|
||||||
"public_headers": (set, ()),
|
"public_headers": (set, ()),
|
||||||
|
"copy_headers": (bool, False),
|
||||||
"includes": (tuple, ()),
|
"includes": (tuple, ()),
|
||||||
|
"include_phase": (str, "normal"),
|
||||||
"sources": (tuple, ()),
|
"sources": (tuple, ()),
|
||||||
"drivers": (tuple, ()),
|
"drivers": (tuple, ()),
|
||||||
"variables": (dict, ()),
|
"variables": (dict, ()),
|
||||||
@@ -37,13 +52,15 @@ class Module:
|
|||||||
"description": (str, None),
|
"description": (str, None),
|
||||||
"no_libc": (bool, False),
|
"no_libc": (bool, False),
|
||||||
"ld_script": (str, None),
|
"ld_script": (str, None),
|
||||||
|
"static": (bool, False),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, name, modfile, root, **kwargs):
|
def __init__(self, name, modfile, root, **kwargs):
|
||||||
from .source import make_source
|
from pathlib import Path
|
||||||
|
from .source import make_source, make_copy_source
|
||||||
|
|
||||||
# Required fields
|
# Required fields
|
||||||
self.root = root
|
self.root = Path(root)
|
||||||
self.name = name
|
self.name = name
|
||||||
self.modfile = modfile
|
self.modfile = modfile
|
||||||
|
|
||||||
@@ -57,31 +74,46 @@ class Module:
|
|||||||
|
|
||||||
for name in kwargs:
|
for name in kwargs:
|
||||||
if not name in self.__fields:
|
if not name in self.__fields:
|
||||||
raise AttributeError(f"No attribute named {name} on Module")
|
raise AttributeError(f"No attribute named {name} on Module ({modfile})")
|
||||||
|
|
||||||
|
if not self.no_libc:
|
||||||
|
self.deps.add("libc_free")
|
||||||
|
|
||||||
# Turn strings into real Source objects
|
# Turn strings into real Source objects
|
||||||
self.sources = [make_source(root, f) for f in self.sources]
|
self.sources = [make_source(root, f) for f in self.sources]
|
||||||
self.public_headers = [make_source(root, f) for f in self.public_headers]
|
|
||||||
|
header_source = lambda f: make_source(root, Path("include") / f)
|
||||||
|
if self.copy_headers:
|
||||||
|
header_source = lambda f: make_copy_source(root, f, "include")
|
||||||
|
self.public_headers = [header_source(f) for f in self.public_headers]
|
||||||
|
|
||||||
# Filled by Module.update
|
# Filled by Module.update
|
||||||
self.depmods = set()
|
self.depmods = set()
|
||||||
|
|
||||||
def __str__(self):
|
def __repr__(self):
|
||||||
return "Module {} {}\n\t{}".format(self.kind, self.name, "\n\t".join(map(str, self.sources)))
|
return f"<Module {self.kind} {self.name}>"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def output(self):
|
def basename(self):
|
||||||
if self.__output is not None:
|
if self.__basename is not None:
|
||||||
return self.__output
|
return self.__basename
|
||||||
|
|
||||||
if self.kind == "lib":
|
if self.kind == "lib":
|
||||||
return f"lib{self.name}.a"
|
return f"lib{self.name}"
|
||||||
else:
|
else:
|
||||||
return f"{self.name}.elf"
|
return self.name
|
||||||
|
|
||||||
@output.setter
|
@basename.setter
|
||||||
def output(self, value):
|
def basename(self, value):
|
||||||
self.__output = value
|
self.__basename = value
|
||||||
|
|
||||||
|
def get_output(self, static=False):
|
||||||
|
if self.outfile is not None:
|
||||||
|
return self.outfile
|
||||||
|
elif self.kind == "headers":
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
ext = dict(exe=".elf", driver=".drv", lib=(static and ".a" or ".so"))
|
||||||
|
return self.basename + ext.get(self.kind, "")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def update(cls, mods):
|
def update(cls, mods):
|
||||||
@@ -114,66 +146,28 @@ class Module:
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from ninja.ninja_syntax import Writer
|
from ninja.ninja_syntax import Writer
|
||||||
|
|
||||||
def walk_deps(deps):
|
def walk_deps(deps, static, results):
|
||||||
open_set = set(deps)
|
for mod in deps:
|
||||||
closed_set = set()
|
if static or mod.name not in results:
|
||||||
while open_set:
|
results[mod.name] = (mod, static)
|
||||||
dep = open_set.pop()
|
walk_deps(mod.depmods, static or mod.static, results)
|
||||||
closed_set.add(dep)
|
|
||||||
open_set |= {m for m in dep.depmods if not m in closed_set}
|
|
||||||
return closed_set
|
|
||||||
|
|
||||||
all_deps = walk_deps(self.depmods)
|
all_deps = {}
|
||||||
|
walk_deps(self.depmods, self.static, all_deps)
|
||||||
|
all_deps = all_deps.values()
|
||||||
|
|
||||||
def gather_phony(build, deps, child_rel, add_headers=False):
|
def gather_phony(build, deps, child_rel):
|
||||||
phony = ".headers.phony"
|
phony = ".headers.phony"
|
||||||
child_phony = [child_rel(phony, module=c.name)
|
child_phony = [child_rel(phony, module=c.name)
|
||||||
for c in all_deps]
|
for c, _ in all_deps]
|
||||||
|
|
||||||
header_targets = []
|
|
||||||
if add_headers:
|
|
||||||
if not self.no_libc:
|
|
||||||
header_targets.append(f"${{build_root}}/include/libc/{phony}")
|
|
||||||
if self.public_headers:
|
|
||||||
header_targets.append(f"${{build_root}}/include/{self.name}/{phony}")
|
|
||||||
|
|
||||||
build.build(
|
build.build(
|
||||||
rule = "touch",
|
rule = "touch",
|
||||||
outputs = [mod_rel(phony)],
|
outputs = [mod_rel(phony)],
|
||||||
implicit = child_phony + header_targets,
|
implicit = child_phony,
|
||||||
order_only = list(map(mod_rel, deps)),
|
order_only = list(map(mod_rel, deps)),
|
||||||
)
|
)
|
||||||
|
|
||||||
filename = str(output / f"headers.{self.name}.ninja")
|
|
||||||
with open(filename, "w") as buildfile:
|
|
||||||
build = Writer(buildfile)
|
|
||||||
|
|
||||||
build.comment("This file is automatically generated by bonnibel")
|
|
||||||
build.newline()
|
|
||||||
|
|
||||||
build.variable("module_dir", f"${{build_root}}/include/{self.name}")
|
|
||||||
|
|
||||||
header_deps = []
|
|
||||||
|
|
||||||
inputs = []
|
|
||||||
headers = set(self.public_headers)
|
|
||||||
while headers:
|
|
||||||
source = headers.pop()
|
|
||||||
headers.update(source.next)
|
|
||||||
|
|
||||||
if source.action:
|
|
||||||
build.newline()
|
|
||||||
build.build(rule=source.action, **source.args)
|
|
||||||
|
|
||||||
if source.gather:
|
|
||||||
header_deps += list(source.outputs)
|
|
||||||
|
|
||||||
if source.input:
|
|
||||||
inputs.extend(map(mod_rel, source.outputs))
|
|
||||||
|
|
||||||
build.newline()
|
|
||||||
gather_phony(build, header_deps, include_rel)
|
|
||||||
|
|
||||||
filename = str(output / f"module.{self.name}.ninja")
|
filename = str(output / f"module.{self.name}.ninja")
|
||||||
with open(filename, "w") as buildfile:
|
with open(filename, "w") as buildfile:
|
||||||
build = Writer(buildfile)
|
build = Writer(buildfile)
|
||||||
@@ -182,13 +176,21 @@ class Module:
|
|||||||
build.newline()
|
build.newline()
|
||||||
|
|
||||||
build.variable("module_dir", target_rel(self.name + ".dir"))
|
build.variable("module_dir", target_rel(self.name + ".dir"))
|
||||||
|
build.variable("module_kind", self.kind)
|
||||||
|
build.newline()
|
||||||
|
|
||||||
|
build.include(f"${{target_dir}}/config.{self.kind}.ninja")
|
||||||
|
build.newline()
|
||||||
|
|
||||||
modopts = BuildOptions(
|
modopts = BuildOptions(
|
||||||
includes = [self.root, "${module_dir}"],
|
local = [self.root, "${module_dir}"],
|
||||||
ld_script = self.ld_script and self.root / self.ld_script,
|
ld_script = self.ld_script and self.root / self.ld_script,
|
||||||
)
|
)
|
||||||
if self.public_headers:
|
if self.public_headers:
|
||||||
modopts.includes += [f"${{build_root}}/include/{self.name}"]
|
modopts.includes += [
|
||||||
|
self.root / "include",
|
||||||
|
f"${{target_dir}}/{self.name}.dir/include",
|
||||||
|
]
|
||||||
|
|
||||||
for key, value in self.variables.items():
|
for key, value in self.variables.items():
|
||||||
build.variable(key, value)
|
build.variable(key, value)
|
||||||
@@ -207,27 +209,64 @@ class Module:
|
|||||||
modopts.includes.append(str(incpath))
|
modopts.includes.append(str(incpath))
|
||||||
modopts.includes.append(destpath)
|
modopts.includes.append(destpath)
|
||||||
|
|
||||||
all_deps = walk_deps(self.depmods)
|
for dep, static in all_deps:
|
||||||
for dep in all_deps:
|
|
||||||
if dep.public_headers:
|
if dep.public_headers:
|
||||||
modopts.includes += [f"${{build_root}}/include/{dep.name}"]
|
if dep.include_phase == "normal":
|
||||||
|
modopts.includes += [dep.root / "include", f"${{target_dir}}/{dep.name}.dir/include"]
|
||||||
|
elif dep.include_phase == "late":
|
||||||
|
modopts.late += [dep.root / "include", f"${{target_dir}}/{dep.name}.dir/include"]
|
||||||
|
else:
|
||||||
|
from . import BonnibelError
|
||||||
|
raise BonnibelError(f"Module {dep.name} has invalid include_phase={dep.include_phase}")
|
||||||
|
|
||||||
if dep.kind == "lib":
|
if dep.kind == "headers":
|
||||||
modopts.libs.append(target_rel(dep.output))
|
continue
|
||||||
|
elif dep.kind == "lib":
|
||||||
|
modopts.libs.append((target_rel(dep.get_output(static)), static))
|
||||||
else:
|
else:
|
||||||
modopts.order_only.append(target_rel(dep.output))
|
modopts.order_only.append(target_rel(dep.get_output(static)))
|
||||||
|
|
||||||
|
cc_includes = []
|
||||||
|
if modopts.local:
|
||||||
|
cc_includes += [f"-iquote{i}" for i in modopts.local]
|
||||||
|
|
||||||
if modopts.includes:
|
if modopts.includes:
|
||||||
build.variable("ccflags", ["${ccflags}"] + [f"-I{i}" for i in modopts.includes])
|
cc_includes += [f"-I{i}" for i in modopts.includes]
|
||||||
build.variable("asflags", ["${asflags}"] + [f"-I{i}" for i in modopts.includes])
|
|
||||||
|
if modopts.late:
|
||||||
|
cc_includes += [f"-idirafter{i}" for i in modopts.late]
|
||||||
|
|
||||||
|
if cc_includes:
|
||||||
|
build.variable("ccflags", ["${ccflags}"] + cc_includes)
|
||||||
|
|
||||||
|
as_includes = [f"-I{d}" for d in modopts.local + modopts.includes + modopts.late]
|
||||||
|
if as_includes:
|
||||||
|
build.variable("asflags", ["${asflags}"] + as_includes)
|
||||||
|
|
||||||
if modopts.libs:
|
if modopts.libs:
|
||||||
build.variable("libs", ["${libs}"] + modopts.libs)
|
build.variable("libs", ["-L${target_dir}", "${libs}"] + modopts.linker_args)
|
||||||
|
|
||||||
if modopts.ld_script:
|
if modopts.ld_script:
|
||||||
build.variable("ldflags", ["${ldflags}"] + ["-T", modopts.ld_script])
|
build.variable("ldflags", ["${ldflags}"] + ["-T", modopts.ld_script])
|
||||||
|
|
||||||
header_deps = []
|
header_deps = []
|
||||||
|
inputs = []
|
||||||
|
headers = set(self.public_headers)
|
||||||
|
while headers:
|
||||||
|
source = headers.pop()
|
||||||
|
headers.update(source.next)
|
||||||
|
|
||||||
|
if source.action:
|
||||||
|
build.newline()
|
||||||
|
build.build(rule=source.action, **source.args)
|
||||||
|
|
||||||
|
if source.gather:
|
||||||
|
header_deps += list(source.outputs)
|
||||||
|
|
||||||
|
if source.input:
|
||||||
|
inputs.extend(map(mod_rel, source.outputs))
|
||||||
|
|
||||||
|
build.newline()
|
||||||
|
|
||||||
inputs = []
|
inputs = []
|
||||||
sources = set(self.sources)
|
sources = set(self.sources)
|
||||||
@@ -245,11 +284,13 @@ class Module:
|
|||||||
if source.input:
|
if source.input:
|
||||||
inputs.extend(map(mod_rel, source.outputs))
|
inputs.extend(map(mod_rel, source.outputs))
|
||||||
|
|
||||||
build.newline()
|
gather_phony(build, header_deps, target_rel)
|
||||||
|
|
||||||
gather_phony(build, header_deps, target_rel, add_headers=True)
|
if self.kind == "headers":
|
||||||
|
# Header-only, don't output a build rule
|
||||||
|
return
|
||||||
|
|
||||||
output = target_rel(self.output)
|
output = target_rel(self.get_output())
|
||||||
build.newline()
|
build.newline()
|
||||||
build.build(
|
build.build(
|
||||||
rule = self.kind,
|
rule = self.kind,
|
||||||
@@ -257,6 +298,8 @@ class Module:
|
|||||||
inputs = inputs,
|
inputs = inputs,
|
||||||
implicit = modopts.implicit,
|
implicit = modopts.implicit,
|
||||||
order_only = modopts.order_only,
|
order_only = modopts.order_only,
|
||||||
|
variables = {"name": self.name,
|
||||||
|
"soname": self.get_output()},
|
||||||
)
|
)
|
||||||
|
|
||||||
dump = output + ".dump"
|
dump = output + ".dump"
|
||||||
@@ -268,14 +311,34 @@ class Module:
|
|||||||
variables = {"name": self.name},
|
variables = {"name": self.name},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
s_output = target_rel(self.get_output(static=True))
|
||||||
|
if s_output != output:
|
||||||
|
build.newline()
|
||||||
|
build.build(
|
||||||
|
rule = self.kind + "_static",
|
||||||
|
outputs = s_output,
|
||||||
|
inputs = inputs,
|
||||||
|
order_only = modopts.order_only,
|
||||||
|
variables = {"name": self.name},
|
||||||
|
)
|
||||||
|
|
||||||
|
dump = s_output + ".dump"
|
||||||
|
build.newline()
|
||||||
|
build.build(
|
||||||
|
rule = "dump",
|
||||||
|
outputs = dump,
|
||||||
|
inputs = s_output,
|
||||||
|
variables = {"name": self.name},
|
||||||
|
)
|
||||||
|
|
||||||
if self.default:
|
if self.default:
|
||||||
build.newline()
|
build.newline()
|
||||||
build.default(output)
|
build.default(output)
|
||||||
build.default(dump)
|
build.default(dump)
|
||||||
|
|
||||||
def add_input(self, path, **kwargs):
|
def add_input(self, path, **kwargs):
|
||||||
from .source import Source
|
from .source import make_source
|
||||||
s = Source(self.root, path, **kwargs)
|
s = make_source(self.root, path, **kwargs)
|
||||||
self.sources.append(s)
|
self.sources.append(s)
|
||||||
return s.outputs
|
return s.outputs
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,17 @@ class Project:
|
|||||||
|
|
||||||
def generate(self, root, output, modules, config, manifest_file):
|
def generate(self, root, output, modules, config, manifest_file):
|
||||||
import sys
|
import sys
|
||||||
import bonnibel
|
|
||||||
from os.path import join
|
from os.path import join
|
||||||
from ninja.ninja_syntax import Writer
|
from ninja.ninja_syntax import Writer
|
||||||
from .target import Target
|
|
||||||
|
|
||||||
targets = set()
|
targets = set()
|
||||||
|
kinds = set()
|
||||||
for mod in modules.values():
|
for mod in modules.values():
|
||||||
targets.update({Target.load(root, t, config) for t in mod.targets})
|
targets.update(mod.targets)
|
||||||
|
kinds.add(mod.kind)
|
||||||
|
|
||||||
|
from .config import generate_configs
|
||||||
|
config_deps = generate_configs(root, output, config, targets, kinds)
|
||||||
|
|
||||||
with open(output / "build.ninja", "w") as buildfile:
|
with open(output / "build.ninja", "w") as buildfile:
|
||||||
build = Writer(buildfile)
|
build = Writer(buildfile)
|
||||||
@@ -28,6 +31,7 @@ class Project:
|
|||||||
build.variable("ninja_required_version", "1.3")
|
build.variable("ninja_required_version", "1.3")
|
||||||
build.variable("build_root", output)
|
build.variable("build_root", output)
|
||||||
build.variable("source_root", root)
|
build.variable("source_root", root)
|
||||||
|
build.variable("build_config", config)
|
||||||
build.newline()
|
build.newline()
|
||||||
|
|
||||||
build.include(root / "assets/build/rules.ninja")
|
build.include(root / "assets/build/rules.ninja")
|
||||||
@@ -46,11 +50,7 @@ class Project:
|
|||||||
build.newline()
|
build.newline()
|
||||||
|
|
||||||
for target in targets:
|
for target in targets:
|
||||||
build.subninja(output / target.name / "target.ninja")
|
build.subninja(output / target / "target.ninja")
|
||||||
build.newline()
|
|
||||||
|
|
||||||
for mod in modules.values():
|
|
||||||
build.subninja(output / f"headers.{mod.name}.ninja")
|
|
||||||
build.newline()
|
build.newline()
|
||||||
|
|
||||||
build.build(
|
build.build(
|
||||||
@@ -154,6 +154,9 @@ class Project:
|
|||||||
for program in manifest.drivers:
|
for program in manifest.drivers:
|
||||||
add_initrd_stripped("jsix/drivers", program)
|
add_initrd_stripped("jsix/drivers", program)
|
||||||
|
|
||||||
|
for program in manifest.libs:
|
||||||
|
add_initrd_stripped("jsix/lib", program)
|
||||||
|
|
||||||
syms = manifest.add_data("symbol_table.dat",
|
syms = manifest.add_data("symbol_table.dat",
|
||||||
"Symbol table", ("symbols",))
|
"Symbol table", ("symbols",))
|
||||||
|
|
||||||
@@ -163,7 +166,7 @@ class Project:
|
|||||||
build.build(
|
build.build(
|
||||||
rule = "makest",
|
rule = "makest",
|
||||||
outputs = [syms_out],
|
outputs = [syms_out],
|
||||||
inputs = [f"${{build_root}}/kernel/{modules['kernel'].output}"],
|
inputs = [f"${{build_root}}/kernel/{modules['kernel'].get_output(static=True)}"],
|
||||||
)
|
)
|
||||||
fatroot_content.append(syms_out)
|
fatroot_content.append(syms_out)
|
||||||
manifest.symbols = syms_file
|
manifest.symbols = syms_file
|
||||||
@@ -232,8 +235,7 @@ class Project:
|
|||||||
[f"{self.root}/configure", str(manifest_file)] + \
|
[f"{self.root}/configure", str(manifest_file)] + \
|
||||||
[str(mod.modfile) for mod in modules.values()]
|
[str(mod.modfile) for mod in modules.values()]
|
||||||
|
|
||||||
for target in targets:
|
regen_implicits += list(map(str, config_deps))
|
||||||
regen_implicits += target.depfiles
|
|
||||||
|
|
||||||
build.build(
|
build.build(
|
||||||
rule = "compdb",
|
rule = "compdb",
|
||||||
@@ -249,7 +251,7 @@ class Project:
|
|||||||
implicit = regen_implicits,
|
implicit = regen_implicits,
|
||||||
implicit_outputs =
|
implicit_outputs =
|
||||||
[f"module.{mod.name}.ninja" for mod in modules.values()] +
|
[f"module.{mod.name}.ninja" for mod in modules.values()] +
|
||||||
[f"{target.name}/target.ninja" for target in targets] +
|
[f"{target}/target.ninja" for target in targets] +
|
||||||
[boot_config],
|
[boot_config],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -257,9 +259,9 @@ class Project:
|
|||||||
build.default(["${build_root}/jsix.img"])
|
build.default(["${build_root}/jsix.img"])
|
||||||
|
|
||||||
for target in targets:
|
for target in targets:
|
||||||
mods = [m.name for m in modules.values() if target.name in m.targets]
|
mods = [m.name for m in modules.values() if target in m.targets]
|
||||||
|
|
||||||
targetdir = output / target.name
|
targetdir = output / target
|
||||||
targetdir.mkdir(exist_ok=True)
|
targetdir.mkdir(exist_ok=True)
|
||||||
|
|
||||||
buildfilename = str(targetdir / "target.ninja")
|
buildfilename = str(targetdir / "target.ninja")
|
||||||
@@ -268,17 +270,16 @@ class Project:
|
|||||||
build.comment("This file is automatically generated by bonnibel")
|
build.comment("This file is automatically generated by bonnibel")
|
||||||
build.newline()
|
build.newline()
|
||||||
|
|
||||||
build.variable("target", target.name)
|
build.variable("target", target)
|
||||||
build.variable("target_dir", output / target.name)
|
build.variable("target_dir", output / target)
|
||||||
build.newline()
|
build.newline()
|
||||||
|
|
||||||
for name, value in target.items():
|
build.include(f"{target}/config.ninja")
|
||||||
build.variable(name, value)
|
|
||||||
|
|
||||||
build.newline()
|
build.newline()
|
||||||
for kind in ('defs', 'run'):
|
for kind in ('defs', 'run'):
|
||||||
for lang in ('c', 'cpp'):
|
for lang in ('c', 'cpp'):
|
||||||
deffile = str(output / target.name / f"{lang}.{kind}")
|
deffile = str(output / target / f"{lang}.{kind}")
|
||||||
|
|
||||||
build.build(
|
build.build(
|
||||||
rule = f"dump_{lang}_{kind}",
|
rule = f"dump_{lang}_{kind}",
|
||||||
|
|||||||
@@ -72,22 +72,21 @@ class ParseSource(Source):
|
|||||||
variables = dict(name=self.path),
|
variables = dict(name=self.path),
|
||||||
)
|
)
|
||||||
|
|
||||||
class HeaderSource(Source):
|
class CopySource(ParseSource):
|
||||||
action = "cp"
|
action = "cp"
|
||||||
gather = True
|
|
||||||
|
def __init__(self, path, root = "${module_dir}", deps=tuple(), prefix = ""):
|
||||||
|
self.path = path
|
||||||
|
self.root = root
|
||||||
|
self.deps = deps
|
||||||
|
self.prefix = prefix
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def outputs(self):
|
def output(self):
|
||||||
return (self.path,)
|
from pathlib import Path
|
||||||
|
return Path(self.prefix) / self.path
|
||||||
|
|
||||||
@property
|
class HeaderSource(Source): pass
|
||||||
def args(self):
|
|
||||||
return dict(
|
|
||||||
outputs = [mod_rel(self.path)],
|
|
||||||
inputs = [join(self.root, self.path)],
|
|
||||||
implicit = list(map(_resolve, self.deps)),
|
|
||||||
variables = dict(name=self.path),
|
|
||||||
)
|
|
||||||
|
|
||||||
class CompileSource(Source):
|
class CompileSource(Source):
|
||||||
action = property(_dynamic_action("compile"))
|
action = property(_dynamic_action("compile"))
|
||||||
@@ -117,3 +116,6 @@ def make_source(root, path):
|
|||||||
return HeaderSource(path, root)
|
return HeaderSource(path, root)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(f"{path} has no Source type")
|
raise RuntimeError(f"{path} has no Source type")
|
||||||
|
|
||||||
|
def make_copy_source(root, path, prefix = ""):
|
||||||
|
return CopySource(path, root, prefix=prefix)
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
class Target(dict):
|
|
||||||
__targets = {}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def load(cls, root, name, config=None):
|
|
||||||
from . import load_config
|
|
||||||
|
|
||||||
if (name, config) in cls.__targets:
|
|
||||||
return cls.__targets[(name, config)]
|
|
||||||
|
|
||||||
configs = root / "assets/build"
|
|
||||||
|
|
||||||
dicts = []
|
|
||||||
depfiles = []
|
|
||||||
basename = name
|
|
||||||
if config:
|
|
||||||
basename += f"-{config}"
|
|
||||||
|
|
||||||
while basename is not None:
|
|
||||||
filename = str(configs / (basename + ".yaml"))
|
|
||||||
depfiles.append(filename)
|
|
||||||
desc = load_config(filename)
|
|
||||||
basename = desc.get("extends")
|
|
||||||
dicts.append(desc.get("variables", dict()))
|
|
||||||
|
|
||||||
t = Target(name, config, depfiles)
|
|
||||||
for d in reversed(dicts):
|
|
||||||
for k, v in d.items():
|
|
||||||
if isinstance(v, (list, tuple)):
|
|
||||||
t[k] = t.get(k, list()) + list(v)
|
|
||||||
elif isinstance(v, dict):
|
|
||||||
t[k] = t.get(k, dict())
|
|
||||||
t[k].update(v)
|
|
||||||
else:
|
|
||||||
t[k] = v
|
|
||||||
|
|
||||||
cls.__targets[(name, config)] = t
|
|
||||||
return t
|
|
||||||
|
|
||||||
def __init__(self, name, config, depfiles):
|
|
||||||
self.__name = name
|
|
||||||
self.__config = config
|
|
||||||
self.__depfiles = tuple(depfiles)
|
|
||||||
|
|
||||||
def __hash__(self):
|
|
||||||
return hash((self.__name, self.__config))
|
|
||||||
|
|
||||||
name = property(lambda self: self.__name)
|
|
||||||
config = property(lambda self: self.__config)
|
|
||||||
depfiles = property(lambda self: self.__depfiles)
|
|
||||||
62
scripts/debug_buddy_alloc.gdb
Normal file
62
scripts/debug_buddy_alloc.gdb
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
das -enabled off
|
||||||
|
|
||||||
|
break heap_allocator.cpp:200
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "n %016lx %d\n", m_end, current
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator.cpp:206
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "N %016lx %d\n", m_end, order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator::register_free_block
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "F %016lx %d\n", block, order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator.cpp:118
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "f %016lx %d\n", block, info->order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator.cpp:241
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "S %016lx %d\n", block, order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator.cpp:158
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "P %016lx %d\n", block, order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator.cpp:180
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "p %016lx %d\n", block, order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
break heap_allocator.cpp:182
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "M %016lx %016lx %d\n", block, buddy, order
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
set logging file buddy_allocs.txt
|
||||||
|
set logging overwrite on
|
||||||
|
set logging enabled on
|
||||||
|
continue
|
||||||
18
scripts/debug_frame_alloc.gdb
Normal file
18
scripts/debug_frame_alloc.gdb
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
das -enabled off
|
||||||
|
break frame_allocator.cpp:62
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "+ %016lx %3d\n", *address, n
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
break frame_allocator.cpp:95
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "- %016lx %3d\n", address, count
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
set logging file frame_allocs.txt
|
||||||
|
set logging overwrite on
|
||||||
|
set logging enabled on
|
||||||
|
continue
|
||||||
29
scripts/debug_heap_alloc.gdb
Normal file
29
scripts/debug_heap_alloc.gdb
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
das -enabled off
|
||||||
|
break heap_allocator.cpp:81
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "+ %016lx %4d\n", block, length
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
break heap_allocator.cpp:86
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "+ %016lx %4d\n", block, length
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
break heap_allocator.cpp:120
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "- %016lx\n", p
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
break heap_allocator.cpp:140
|
||||||
|
commands
|
||||||
|
silent
|
||||||
|
printf "> %016lx %4d %4d\n", p, old_length, new_length
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
set logging file heap_allocs.txt
|
||||||
|
set logging overwrite on
|
||||||
|
set logging enabled on
|
||||||
|
continue
|
||||||
File diff suppressed because one or more lines are too long
@@ -42,31 +42,37 @@ class PrimitiveRef(Primitive):
|
|||||||
def cxx_names(self, options):
|
def cxx_names(self, options):
|
||||||
return self.c_names(options)
|
return self.c_names(options)
|
||||||
|
|
||||||
|
_inttypes = {
|
||||||
|
"int": "int",
|
||||||
|
"uint": "unsigned",
|
||||||
|
"size": "size_t",
|
||||||
|
"address": "uintptr_t",
|
||||||
|
|
||||||
|
"int8": "int8_t",
|
||||||
|
"uint8": "uint8_t",
|
||||||
|
"int16": "int16_t",
|
||||||
|
"uint16": "uint16_t",
|
||||||
|
"int32": "int32_t",
|
||||||
|
"uint32": "uint32_t",
|
||||||
|
"int64": "int64_t",
|
||||||
|
"uint64": "uint64_t",
|
||||||
|
}
|
||||||
|
|
||||||
_primitives = {
|
_primitives = {
|
||||||
"string": PrimitiveRef("string", "char"),
|
"string": PrimitiveRef("string", "char"),
|
||||||
"buffer": PrimitiveRef("buffer", "void", counted=True),
|
"buffer": PrimitiveRef("buffer", "void", counted=True),
|
||||||
|
|
||||||
"int": Primitive("int", "int"),
|
|
||||||
"uint": Primitive("uint", "unsigned"),
|
|
||||||
"size": Primitive("size", "size_t"),
|
|
||||||
"address": Primitive("address", "uintptr_t"),
|
|
||||||
|
|
||||||
"int8": Primitive("int8", "int8_t"),
|
|
||||||
"uint8": Primitive("uint8", "uint8_t"),
|
|
||||||
|
|
||||||
"int16": Primitive("int16", "int16_t"),
|
|
||||||
"uint16": Primitive("uint16", "uint16_t"),
|
|
||||||
|
|
||||||
"int32": Primitive("int32", "int32_t"),
|
|
||||||
"uint32": Primitive("uint32", "uint32_t"),
|
|
||||||
|
|
||||||
"int64": Primitive("int64", "int64_t"),
|
|
||||||
"uint64": Primitive("uint64", "uint64_t"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_primitive(name):
|
def get_primitive(name):
|
||||||
p = _primitives.get(name)
|
p = _primitives.get(name)
|
||||||
if not p:
|
if p: return p
|
||||||
from ..errors import InvalidType
|
|
||||||
raise InvalidType(name)
|
it = _inttypes.get(name.replace('*', ''))
|
||||||
return p
|
if it:
|
||||||
|
if '*' in name:
|
||||||
|
return PrimitiveRef(name, it)
|
||||||
|
else:
|
||||||
|
return Primitive(name, it)
|
||||||
|
|
||||||
|
from ..errors import InvalidType
|
||||||
|
raise InvalidType(name)
|
||||||
|
|||||||
93
scripts/parse_buddy_allocs.py
Executable file
93
scripts/parse_buddy_allocs.py
Executable file
@@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
class block:
|
||||||
|
def __init__(self, start, order, free=False):
|
||||||
|
self.start = start
|
||||||
|
self.order = order
|
||||||
|
self.free = free
|
||||||
|
|
||||||
|
@property
|
||||||
|
def end(self):
|
||||||
|
return self.start + (1<<self.order)
|
||||||
|
|
||||||
|
def overlaps(self, other):
|
||||||
|
return other.start < self.end and other.end > self.start
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"[{self.start:016x} {self.order:2} {self.free and 'free' or 'used'}]"
|
||||||
|
|
||||||
|
def get_block(blocks, addr, order, reason):
|
||||||
|
b = blocks.get(addr)
|
||||||
|
if b is None:
|
||||||
|
print(f"ERROR: {reason} unknown block [{addr:016x}, {order}]")
|
||||||
|
elif b.order != order:
|
||||||
|
print(f"ERROR: {reason} block {b} for order {order}")
|
||||||
|
else:
|
||||||
|
return b
|
||||||
|
return None
|
||||||
|
|
||||||
|
def new_block(blocks, addr, order):
|
||||||
|
b = block(addr, order)
|
||||||
|
for existing in blocks.values():
|
||||||
|
if b.overlaps(existing):
|
||||||
|
print(f"ERROR: new block {b} overlaps existing {existing}")
|
||||||
|
blocks[addr] = b
|
||||||
|
|
||||||
|
def free_block(blocks, addr, order, free):
|
||||||
|
s = free and "freeing" or "popping"
|
||||||
|
b = get_block(blocks, addr, order, s)
|
||||||
|
if b and b.free == free:
|
||||||
|
print(f"ERROR: {s} block {b}")
|
||||||
|
elif b:
|
||||||
|
b.free = free
|
||||||
|
|
||||||
|
def split_block(blocks, addr, order):
|
||||||
|
b = get_block(blocks, addr, order+1, "splitting")
|
||||||
|
if b:
|
||||||
|
b.order = order
|
||||||
|
buddy = b.start ^ (1<<order)
|
||||||
|
blocks[buddy] = block(buddy, order)
|
||||||
|
|
||||||
|
def merge_blocks(blocks, addr1, addr2, order):
|
||||||
|
b1 = get_block(blocks, addr1, order, "merging")
|
||||||
|
b2 = get_block(blocks, addr2, order, "merging")
|
||||||
|
if b1.start > b2.start:
|
||||||
|
b1, b2 = b2, b1
|
||||||
|
del blocks[b2.start]
|
||||||
|
b1.order = order + 1
|
||||||
|
|
||||||
|
def parse_line(blocks, line):
|
||||||
|
args = line.strip().split()
|
||||||
|
match args:
|
||||||
|
case ['N', addr, order]:
|
||||||
|
new_block(blocks, int(addr, base=16), int(order))
|
||||||
|
case ['n', addr, order]:
|
||||||
|
new_block(blocks, int(addr, base=16), int(order))
|
||||||
|
case ['P', addr, order]:
|
||||||
|
free_block(blocks, int(addr, base=16), int(order), False)
|
||||||
|
case ['p', addr, order]:
|
||||||
|
free_block(blocks, int(addr, base=16), int(order), False)
|
||||||
|
case ['F', addr, order]:
|
||||||
|
free_block(blocks, int(addr, base=16), int(order), True)
|
||||||
|
case ['S', addr, order]:
|
||||||
|
split_block(blocks, int(addr, base=16), int(order))
|
||||||
|
case ['M', addr1, addr2, order]:
|
||||||
|
merge_blocks(blocks, int(addr1, base=16), int(addr2, base=16), int(order))
|
||||||
|
case _:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def parse_file(f):
|
||||||
|
blocks = {}
|
||||||
|
for line in f.readlines():
|
||||||
|
parse_line(blocks, line)
|
||||||
|
|
||||||
|
#for addr in sorted(blocks.keys()):
|
||||||
|
# print(f"{addr:09x}: {blocks[addr]}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
with open(sys.argv[1]) as f:
|
||||||
|
parse_file(f)
|
||||||
|
else:
|
||||||
|
parse_file(sys.stdin)
|
||||||
40
scripts/parse_frame_allocs.py
Executable file
40
scripts/parse_frame_allocs.py
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
def add_maps(allocs, addr, count):
|
||||||
|
for i in range(count):
|
||||||
|
if addr+i in allocs:
|
||||||
|
print(f"ERROR: frame {addr+i:012x} map collision.")
|
||||||
|
else:
|
||||||
|
#print(f" frame {addr+i:012x} mapped")
|
||||||
|
allocs.add(addr+i)
|
||||||
|
|
||||||
|
def remove_maps(allocs, addr, count):
|
||||||
|
for i in range(count):
|
||||||
|
if addr+i not in allocs:
|
||||||
|
print(f" WARN: removing unmapped frame {addr+i:012x}")
|
||||||
|
else:
|
||||||
|
#print(f" frame {addr+i:012x} unmapped")
|
||||||
|
allocs.remove(addr+i)
|
||||||
|
|
||||||
|
def parse_line(allocs, line):
|
||||||
|
args = line.strip().split()
|
||||||
|
match args:
|
||||||
|
case ['+', addr, count]:
|
||||||
|
add_maps(allocs, int(addr, base=16), int(count))
|
||||||
|
case ['-', addr, count]:
|
||||||
|
remove_maps(allocs, int(addr, base=16), int(count))
|
||||||
|
case _:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def parse_file(f):
|
||||||
|
allocs = set()
|
||||||
|
for line in f.readlines():
|
||||||
|
parse_line(allocs, line)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
with open(sys.argv[1]) as f:
|
||||||
|
parse_file(f)
|
||||||
|
else:
|
||||||
|
parse_file(sys.stdin)
|
||||||
62
scripts/parse_heap_allocs.py
Executable file
62
scripts/parse_heap_allocs.py
Executable file
@@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from bisect import bisect_left, insort
|
||||||
|
from operator import attrgetter
|
||||||
|
|
||||||
|
by_start = attrgetter('start')
|
||||||
|
|
||||||
|
class alloc:
|
||||||
|
def __init__(self, start, size):
|
||||||
|
self.start = start
|
||||||
|
self.size = size
|
||||||
|
|
||||||
|
@property
|
||||||
|
def end(self):
|
||||||
|
return self.start + self.size
|
||||||
|
|
||||||
|
def overlaps(self, other):
|
||||||
|
return other.start < self.end and other.end > self.start
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"[{self.start:012x} - {self.end:012x}]"
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
return self.start > other.start
|
||||||
|
|
||||||
|
def add_alloc(allocs, addr, length):
|
||||||
|
a = alloc(addr, length)
|
||||||
|
for existing in allocs:
|
||||||
|
if a.overlaps(existing):
|
||||||
|
print(f"ERROR: allocation {a} overlaps existing {existing}")
|
||||||
|
insort(allocs, a)
|
||||||
|
|
||||||
|
def remove_alloc(allocs, addr):
|
||||||
|
a = alloc(addr, 0)
|
||||||
|
i = bisect_left(allocs, a)
|
||||||
|
if len(allocs) > i and allocs[i].start == addr:
|
||||||
|
del allocs[i]
|
||||||
|
else:
|
||||||
|
print(f"ERROR: freeing unallocated {a}")
|
||||||
|
|
||||||
|
def parse_line(allocs, line):
|
||||||
|
args = line.strip().split()
|
||||||
|
match args:
|
||||||
|
case ['+', addr, length]:
|
||||||
|
add_alloc(allocs, int(addr, base=16), int(length))
|
||||||
|
case ['-', addr]:
|
||||||
|
remove_alloc(allocs, int(addr, base=16))
|
||||||
|
case _:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def parse_file(f):
|
||||||
|
allocs = []
|
||||||
|
for line in f.readlines():
|
||||||
|
parse_line(allocs, line)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
with open(sys.argv[1]) as f:
|
||||||
|
parse_file(f)
|
||||||
|
else:
|
||||||
|
parse_file(sys.stdin)
|
||||||
124
scripts/print_got.py
Executable file
124
scripts/print_got.py
Executable file
@@ -0,0 +1,124 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
|
||||||
|
def section_header(name):
|
||||||
|
print()
|
||||||
|
print(name)
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
|
||||||
|
def print_dyn(elf):
|
||||||
|
section = elf.get_section_by_name(".dynamic")
|
||||||
|
if section is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
section_header(".dynamic")
|
||||||
|
for tag in section.iter_tags():
|
||||||
|
print(tag)
|
||||||
|
|
||||||
|
|
||||||
|
def print_got(elf, name):
|
||||||
|
import struct
|
||||||
|
|
||||||
|
section = elf.get_section_by_name(name)
|
||||||
|
if section is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
section_header(name)
|
||||||
|
base_ip = section['sh_addr']
|
||||||
|
|
||||||
|
data = section.data()
|
||||||
|
n = section.data_size // 8
|
||||||
|
for i in range(n):
|
||||||
|
addr = struct.unpack_from("Q", data, i*8)[0]
|
||||||
|
print(f"[{i:2x}]: {base_ip+i*8:6x} {addr:16x}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_plt(elf):
|
||||||
|
from iced_x86 import Decoder, Formatter, FormatterSyntax
|
||||||
|
|
||||||
|
section_header(".plt")
|
||||||
|
|
||||||
|
section = elf.get_section_by_name(".plt")
|
||||||
|
n = section.data_size // 16
|
||||||
|
data = section.data()
|
||||||
|
|
||||||
|
frm = Formatter(FormatterSyntax.NASM)
|
||||||
|
frm.digit_separator = "'"
|
||||||
|
frm.first_operand_char_index = 8
|
||||||
|
frm.hex_prefix = "0x"
|
||||||
|
frm.hex_suffix = ""
|
||||||
|
frm.leading_zeros = False
|
||||||
|
frm.rip_relative_addresses = False
|
||||||
|
frm.small_hex_numbers_in_decimal = False
|
||||||
|
frm.uppercase_hex = False
|
||||||
|
|
||||||
|
base_ip = section['sh_addr']
|
||||||
|
|
||||||
|
for i in range(n):
|
||||||
|
entry = data[ i*16 : (i+1)*16 ]
|
||||||
|
d = Decoder(64, entry, ip=base_ip + i*16)
|
||||||
|
|
||||||
|
indent = f"[{i:2x}]:"
|
||||||
|
for instr in d:
|
||||||
|
disasm = frm.format(instr)
|
||||||
|
print(f"{indent:6} {instr.ip:6x} {disasm}")
|
||||||
|
indent = ""
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def print_gnu_hash(elf):
|
||||||
|
hash_section = elf.get_section_by_name(".gnu.hash")
|
||||||
|
data = hash_section.data()
|
||||||
|
|
||||||
|
import struct
|
||||||
|
(nbuckets, symoff, bloom_sz, bloom_sh) = struct.unpack_from("IIII", data, 0)
|
||||||
|
blooms = struct.unpack_from(f"{bloom_sz}Q", data, 16)
|
||||||
|
buckets = struct.unpack_from(f"{nbuckets}I", data, 16+(bloom_sz*8))
|
||||||
|
|
||||||
|
p = 16 + (bloom_sz*8) + (nbuckets*4)
|
||||||
|
n = (len(data) - p) // 4
|
||||||
|
chains = struct.unpack_from(f"{n}I", data, p)
|
||||||
|
|
||||||
|
section_header(".gnu.hash")
|
||||||
|
print(f" Bucket Count: {nbuckets}")
|
||||||
|
print(f"Symbol Offset: {symoff}")
|
||||||
|
print(f" Buckets: {buckets}")
|
||||||
|
|
||||||
|
print("\n Bloom words:")
|
||||||
|
for i in range(len(blooms)):
|
||||||
|
print(f" [{i:2}]: {blooms[i]:016x}")
|
||||||
|
|
||||||
|
print("\n Hashes:")
|
||||||
|
for i in range(len(chains)):
|
||||||
|
h = chains[i]
|
||||||
|
end = ""
|
||||||
|
if (h & 1) == 1:
|
||||||
|
end = "END"
|
||||||
|
bloom_idx = (h>>6) % bloom_sz
|
||||||
|
bloom_msk = ((1<<(h%64)) | (1<<((h>>bloom_sh)%64)))
|
||||||
|
print(f" [{i+symoff:2}]: {h:08x} {end:5} {bloom_idx:2}/{bloom_msk:016x}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_tables(filename):
|
||||||
|
from elftools.elf.elffile import ELFFile
|
||||||
|
|
||||||
|
print(filename)
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
with open(filename, 'rb') as f:
|
||||||
|
elf = ELFFile(f)
|
||||||
|
print_got(elf, ".got")
|
||||||
|
print_got(elf, ".got.plt")
|
||||||
|
print_plt(elf)
|
||||||
|
print_dyn(elf)
|
||||||
|
print_gnu_hash(elf)
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
for filename in sys.argv[1:]:
|
||||||
|
print_tables(filename)
|
||||||
1
scripts/wsl_set_vnchost.fish
Normal file
1
scripts/wsl_set_vnchost.fish
Normal file
@@ -0,0 +1 @@
|
|||||||
|
set -gx VNCHOST (ip -j route list default | jq -r '.[0].gateway'):5500
|
||||||
@@ -71,10 +71,10 @@ allocator::add_modules()
|
|||||||
allocate_pages(1, alloc_type::init_args, true));
|
allocate_pages(1, alloc_type::init_args, true));
|
||||||
|
|
||||||
if (m_modules)
|
if (m_modules)
|
||||||
m_modules->next = reinterpret_cast<uintptr_t>(mods);
|
m_modules->next = mods;
|
||||||
|
|
||||||
m_modules = mods;
|
m_modules = mods;
|
||||||
m_next_mod = mods->modules;
|
m_next_mod = reinterpret_cast<module*>(mods+1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,9 +109,9 @@ allocator::allocate_pages(size_t count, alloc_type type, bool zero)
|
|||||||
}
|
}
|
||||||
|
|
||||||
module *
|
module *
|
||||||
allocator::allocate_module()
|
allocator::allocate_module(size_t extra)
|
||||||
{
|
{
|
||||||
static constexpr size_t size = sizeof(module);
|
size_t size = sizeof(module) + extra;
|
||||||
|
|
||||||
size_t remaining =
|
size_t remaining =
|
||||||
reinterpret_cast<uintptr_t>(m_modules) + page_size
|
reinterpret_cast<uintptr_t>(m_modules) + page_size
|
||||||
@@ -120,8 +120,8 @@ allocator::allocate_module()
|
|||||||
if (size > remaining)
|
if (size > remaining)
|
||||||
add_modules();
|
add_modules();
|
||||||
|
|
||||||
++m_modules->count;
|
|
||||||
module *m = m_next_mod;
|
module *m = m_next_mod;
|
||||||
|
m->bytes = size;
|
||||||
m_next_mod = util::offset_pointer(m_next_mod, size);
|
m_next_mod = util::offset_pointer(m_next_mod, size);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public:
|
|||||||
|
|
||||||
void * allocate_pages(size_t count, alloc_type type, bool zero = false);
|
void * allocate_pages(size_t count, alloc_type type, bool zero = false);
|
||||||
|
|
||||||
module * allocate_module();
|
module * allocate_module(size_t extra = 0);
|
||||||
|
|
||||||
void memset(void *start, size_t size, uint8_t value);
|
void memset(void *start, size_t size, uint8_t value);
|
||||||
void copy(void *to, const void *from, size_t size);
|
void copy(void *to, const void *from, size_t size);
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
boot = module("boot",
|
boot = module("boot",
|
||||||
kind = "exe",
|
kind = "exe",
|
||||||
output = "boot.efi",
|
outfile = "boot.efi",
|
||||||
targets = [ "boot" ],
|
targets = [ "boot" ],
|
||||||
deps = [ "cpu", "elf", "util", "bootproto" ],
|
deps = [ "cpu", "elf", "util", "bootproto" ],
|
||||||
|
static = True,
|
||||||
sources = [
|
sources = [
|
||||||
"allocator.cpp",
|
"allocator.cpp",
|
||||||
"bootconfig.cpp",
|
"bootconfig.cpp",
|
||||||
|
|||||||
@@ -79,10 +79,11 @@ check_cpu_supported()
|
|||||||
status_line status {L"Checking CPU features"};
|
status_line status {L"Checking CPU features"};
|
||||||
|
|
||||||
cpu::cpu_id cpu;
|
cpu::cpu_id cpu;
|
||||||
cpu::cpu_id::features features = cpu.validate();
|
cpu::features features = cpu.features();
|
||||||
bool supported = true;
|
bool supported = true;
|
||||||
|
|
||||||
#define CPU_FEATURE_OPT(...)
|
#define CPU_FEATURE_OPT(...)
|
||||||
|
#define CPU_FEATURE_WRN(...)
|
||||||
#define CPU_FEATURE_REQ(name, ...) \
|
#define CPU_FEATURE_REQ(name, ...) \
|
||||||
if (!features[cpu::feature::name]) { \
|
if (!features[cpu::feature::name]) { \
|
||||||
status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \
|
status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \
|
||||||
|
|||||||
@@ -167,15 +167,15 @@ load_module(
|
|||||||
fs::file &disk,
|
fs::file &disk,
|
||||||
const wchar_t *name,
|
const wchar_t *name,
|
||||||
const wchar_t *path,
|
const wchar_t *path,
|
||||||
bootproto::module_type type,
|
bootproto::module_type type)
|
||||||
uint16_t subtype)
|
|
||||||
{
|
{
|
||||||
status_line status(L"Loading module", name);
|
status_line status(L"Loading module", name);
|
||||||
|
|
||||||
bootproto::module *mod = g_alloc.allocate_module();
|
bootproto::module *mod = g_alloc.allocate_module(sizeof(util::buffer));
|
||||||
mod->type = type;
|
mod->type = type;
|
||||||
mod->subtype = subtype;
|
|
||||||
mod->data = load_file(disk, path);
|
util::buffer *data = mod->data<util::buffer>();
|
||||||
|
*data = load_file(disk, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace loader
|
} // namespace loader
|
||||||
|
|||||||
@@ -60,14 +60,12 @@ load_program(
|
|||||||
/// \arg name The human-readable name of the module
|
/// \arg name The human-readable name of the module
|
||||||
/// \arg path The path of the file to load the module from
|
/// \arg path The path of the file to load the module from
|
||||||
/// \arg type The major type to set on the module
|
/// \arg type The major type to set on the module
|
||||||
/// \arg subtype The subtype to set on the module
|
|
||||||
void
|
void
|
||||||
load_module(
|
load_module(
|
||||||
fs::file &disk,
|
fs::file &disk,
|
||||||
const wchar_t *name,
|
const wchar_t *name,
|
||||||
const wchar_t *path,
|
const wchar_t *path,
|
||||||
bootproto::module_type type,
|
bootproto::module_type type);
|
||||||
uint16_t subtype);
|
|
||||||
|
|
||||||
} // namespace loader
|
} // namespace loader
|
||||||
} // namespace boot
|
} // namespace boot
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <bootproto/acpi.h>
|
||||||
#include <bootproto/bootconfig.h>
|
#include <bootproto/bootconfig.h>
|
||||||
#include <bootproto/kernel.h>
|
#include <bootproto/kernel.h>
|
||||||
#include <bootproto/memory.h>
|
#include <bootproto/memory.h>
|
||||||
@@ -125,7 +126,7 @@ load_resources(
|
|||||||
loader::parse_program(L"init server", init, args->init);
|
loader::parse_program(L"init server", init, args->init);
|
||||||
|
|
||||||
loader::load_module(disk, L"initrd", bc.initrd(),
|
loader::load_module(disk, L"initrd", bc.initrd(),
|
||||||
bootproto::module_type::initrd, 0);
|
bootproto::module_type::initrd);
|
||||||
|
|
||||||
return reinterpret_cast<bootproto::entrypoint>(kentry);
|
return reinterpret_cast<bootproto::entrypoint>(kentry);
|
||||||
}
|
}
|
||||||
@@ -176,9 +177,23 @@ efi_main(uefi::handle image, uefi::system_table *st)
|
|||||||
bootproto::entrypoint kentry =
|
bootproto::entrypoint kentry =
|
||||||
load_resources(args, screen, image, pager, bs);
|
load_resources(args, screen, image, pager, bs);
|
||||||
|
|
||||||
|
bootproto::module *acpi_mod =
|
||||||
|
g_alloc.allocate_module(sizeof(bootproto::acpi));
|
||||||
|
acpi_mod->type = bootproto::module_type::acpi;
|
||||||
|
bootproto::acpi *acpi = acpi_mod->data<bootproto::acpi>();
|
||||||
|
acpi->root = args->acpi_table;
|
||||||
|
|
||||||
pager.update_kernel_args(args);
|
pager.update_kernel_args(args);
|
||||||
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < args->mem_map.count; ++i) {
|
||||||
|
bootproto::mem_entry &e = args->mem_map.pointer[i];
|
||||||
|
if (e.type == bootproto::mem_type::acpi) {
|
||||||
|
acpi->region = util::buffer::from(e.start, e.pages * memory::page_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
args->allocations = allocs;
|
args->allocations = allocs;
|
||||||
args->init_modules = reinterpret_cast<uintptr_t>(modules);
|
args->init_modules = reinterpret_cast<uintptr_t>(modules);
|
||||||
|
|
||||||
@@ -194,6 +209,7 @@ efi_main(uefi::handle image, uefi::system_table *st)
|
|||||||
|
|
||||||
change_pointer(args);
|
change_pointer(args);
|
||||||
change_pointer(args->pml4);
|
change_pointer(args->pml4);
|
||||||
|
change_pointer(args->symbol_table.pointer);
|
||||||
change_pointer(args->init.sections.pointer);
|
change_pointer(args->init.sections.pointer);
|
||||||
|
|
||||||
//status.next();
|
//status.next();
|
||||||
|
|||||||
@@ -249,13 +249,13 @@ build_frame_blocks(const util::counted<bootproto::mem_entry> &kmap)
|
|||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
|
|
||||||
uint64_t b1 = (page_count + 4095) / 4096;
|
uint64_t b1 = (page_count + 4095) / 4096;
|
||||||
blk->map1 = (1 << b1) - 1;
|
blk->map1 = (1ull << b1) - 1;
|
||||||
|
|
||||||
uint64_t b2 = (page_count + 63) / 64;
|
uint64_t b2 = (page_count + 63) / 64;
|
||||||
uint64_t b2q = b2 / 64;
|
uint64_t b2q = b2 / 64;
|
||||||
uint64_t b2r = b2 % 64;
|
uint64_t b2r = b2 % 64;
|
||||||
g_alloc.memset(blk->map2, b2q, 0xff);
|
g_alloc.memset(blk->map2, b2q, 0xff);
|
||||||
blk->map2[b2q] = (1 << b2r) - 1;
|
blk->map2[b2q] = (1ull << b2r) - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,7 +269,7 @@ build_frame_blocks(const util::counted<bootproto::mem_entry> &kmap)
|
|||||||
size_t b = blk.count / 64;
|
size_t b = blk.count / 64;
|
||||||
size_t r = blk.count % 64;
|
size_t r = blk.count % 64;
|
||||||
g_alloc.memset(blk.bitmap, b*8, 0xff);
|
g_alloc.memset(blk.bitmap, b*8, 0xff);
|
||||||
blk.bitmap[b] = (1 << r) - 1;
|
blk.bitmap[b] = (1ull << r) - 1;
|
||||||
|
|
||||||
bitmap += bitmap_size(blk.count);
|
bitmap += bitmap_size(blk.count);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ pick_mode(uefi::boot_services *bs)
|
|||||||
uint32_t res = info->horizontal_resolution * info->vertical_resolution;
|
uint32_t res = info->horizontal_resolution * info->vertical_resolution;
|
||||||
int pixmode = static_cast<int>(info->pixel_format);
|
int pixmode = static_cast<int>(info->pixel_format);
|
||||||
|
|
||||||
|
/*
|
||||||
const uint32_t modes = gop->mode->max_mode;
|
const uint32_t modes = gop->mode->max_mode;
|
||||||
for (uint32_t i = 0; i < modes; ++i) {
|
for (uint32_t i = 0; i < modes; ++i) {
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
@@ -63,6 +64,7 @@ pick_mode(uefi::boot_services *bs)
|
|||||||
pixmode = new_pixmode;
|
pixmode = new_pixmode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
screen *s = new screen;
|
screen *s = new screen;
|
||||||
s->mode = {
|
s->mode = {
|
||||||
@@ -109,20 +111,15 @@ make_module(screen *s)
|
|||||||
{
|
{
|
||||||
using bootproto::module;
|
using bootproto::module;
|
||||||
using bootproto::module_type;
|
using bootproto::module_type;
|
||||||
using bootproto::device_type;
|
namespace devices = bootproto::devices;
|
||||||
using bootproto::devices::uefi_fb;
|
|
||||||
|
|
||||||
uefi_fb *fb = new uefi_fb;
|
module *mod = g_alloc.allocate_module(sizeof(devices::uefi_fb));
|
||||||
|
mod->type = module_type::device;
|
||||||
|
mod->type_id = devices::type_id_uefi_fb;
|
||||||
|
|
||||||
|
devices::uefi_fb *fb = mod->data<devices::uefi_fb>();
|
||||||
fb->framebuffer = s->framebuffer;
|
fb->framebuffer = s->framebuffer;
|
||||||
fb->mode = s->mode;
|
fb->mode = s->mode;
|
||||||
|
|
||||||
module *mod = g_alloc.allocate_module();
|
|
||||||
mod->type = module_type::device;
|
|
||||||
mod->subtype = static_cast<uint16_t>(device_type::uefi_fb);
|
|
||||||
mod->data = {
|
|
||||||
.pointer = fb,
|
|
||||||
.count = sizeof(uefi_fb),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace video
|
} // namespace video
|
||||||
|
|||||||
@@ -6,7 +6,9 @@
|
|||||||
#include <util/enum_bitfields.h>
|
#include <util/enum_bitfields.h>
|
||||||
#include <util/misc.h> // for byteswap32
|
#include <util/misc.h> // for byteswap32
|
||||||
|
|
||||||
struct acpi_table_header
|
namespace acpi {
|
||||||
|
|
||||||
|
struct table_header
|
||||||
{
|
{
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
@@ -18,24 +20,26 @@ struct acpi_table_header
|
|||||||
uint32_t creator_id;
|
uint32_t creator_id;
|
||||||
uint32_t creator_revision;
|
uint32_t creator_revision;
|
||||||
|
|
||||||
bool validate(uint32_t expected_type = 0) const;
|
bool validate() const { return util::checksum(this, length) == 0; }
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
#define TABLE_HEADER(signature) \
|
#define TABLE_HEADER(signature) \
|
||||||
static constexpr uint32_t type_id = util::byteswap32(signature); \
|
static constexpr uint32_t type_id = util::byteswap32(signature); \
|
||||||
acpi_table_header header;
|
table_header header;
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool acpi_validate(const T *t) { return t->header.validate(T::type_id); }
|
bool validate(const T *t) {
|
||||||
|
return t->header.validate(T::type_id);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
size_t acpi_table_entries(const T *t, size_t size)
|
size_t table_entries(const T *t, size_t size) {
|
||||||
{
|
|
||||||
return (t->header.length - sizeof(T)) / size;
|
return (t->header.length - sizeof(T)) / size;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class acpi_gas_type : uint8_t
|
|
||||||
|
enum class gas_type : uint8_t
|
||||||
{
|
{
|
||||||
system_memory,
|
system_memory,
|
||||||
system_io,
|
system_io,
|
||||||
@@ -46,9 +50,9 @@ enum class acpi_gas_type : uint8_t
|
|||||||
functional_fixed = 0x7f
|
functional_fixed = 0x7f
|
||||||
};
|
};
|
||||||
|
|
||||||
struct acpi_gas
|
struct gas
|
||||||
{
|
{
|
||||||
acpi_gas_type type;
|
gas_type type;
|
||||||
|
|
||||||
uint8_t reg_bits;
|
uint8_t reg_bits;
|
||||||
uint8_t reg_offset;
|
uint8_t reg_offset;
|
||||||
@@ -58,7 +62,7 @@ struct acpi_gas
|
|||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
enum class acpi_fadt_flags : uint32_t
|
enum class fadt_flags : uint32_t
|
||||||
{
|
{
|
||||||
wbinvd = 0x00000001,
|
wbinvd = 0x00000001,
|
||||||
wbinvd_flush = 0x00000002,
|
wbinvd_flush = 0x00000002,
|
||||||
@@ -83,9 +87,9 @@ enum class acpi_fadt_flags : uint32_t
|
|||||||
hw_reduced_acpi = 0x00100000,
|
hw_reduced_acpi = 0x00100000,
|
||||||
low_pwr_s0_idle = 0x00200000
|
low_pwr_s0_idle = 0x00200000
|
||||||
};
|
};
|
||||||
is_bitfield(acpi_fadt_flags);
|
is_bitfield(fadt_flags);
|
||||||
|
|
||||||
struct acpi_fadt
|
struct fadt
|
||||||
{
|
{
|
||||||
TABLE_HEADER('FACP');
|
TABLE_HEADER('FACP');
|
||||||
|
|
||||||
@@ -130,9 +134,9 @@ struct acpi_fadt
|
|||||||
|
|
||||||
uint16_t iapc_boot_arch;
|
uint16_t iapc_boot_arch;
|
||||||
uint8_t reserved1;
|
uint8_t reserved1;
|
||||||
acpi_fadt_flags flags;
|
fadt_flags flags;
|
||||||
|
|
||||||
acpi_gas reset_reg;
|
gas reset_reg;
|
||||||
uint8_t reset_value;
|
uint8_t reset_value;
|
||||||
|
|
||||||
uint16_t arm_boot_arch;
|
uint16_t arm_boot_arch;
|
||||||
@@ -142,28 +146,28 @@ struct acpi_fadt
|
|||||||
uint64_t x_facs;
|
uint64_t x_facs;
|
||||||
uint64_t x_dsdt;
|
uint64_t x_dsdt;
|
||||||
|
|
||||||
acpi_gas x_pm1a_event_block;
|
gas x_pm1a_event_block;
|
||||||
acpi_gas x_pm1b_event_block;
|
gas x_pm1b_event_block;
|
||||||
acpi_gas x_pm1a_control_block;
|
gas x_pm1a_control_block;
|
||||||
acpi_gas x_pm1b_control_block;
|
gas x_pm1b_control_block;
|
||||||
acpi_gas x_pm2_control_block;
|
gas x_pm2_control_block;
|
||||||
acpi_gas x_pm_timer_block;
|
gas x_pm_timer_block;
|
||||||
acpi_gas x_gpe0_block;
|
gas x_gpe0_block;
|
||||||
acpi_gas x_gpe1_block;
|
gas x_gpe1_block;
|
||||||
|
|
||||||
acpi_gas sleep_control_reg;
|
gas sleep_control_reg;
|
||||||
acpi_gas sleep_status_reg;
|
gas sleep_status_reg;
|
||||||
|
|
||||||
uint64_t hypervisor_vendor_id;
|
uint64_t hypervisor_vendor_id;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct acpi_xsdt
|
struct xsdt
|
||||||
{
|
{
|
||||||
TABLE_HEADER('XSDT');
|
TABLE_HEADER('XSDT');
|
||||||
acpi_table_header *headers[0];
|
table_header *headers[0];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct acpi_apic
|
struct apic
|
||||||
{
|
{
|
||||||
TABLE_HEADER('APIC');
|
TABLE_HEADER('APIC');
|
||||||
uint32_t local_address;
|
uint32_t local_address;
|
||||||
@@ -171,7 +175,7 @@ struct acpi_apic
|
|||||||
uint8_t controller_data[0];
|
uint8_t controller_data[0];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct acpi_mcfg_entry
|
struct mcfg_entry
|
||||||
{
|
{
|
||||||
uint64_t base;
|
uint64_t base;
|
||||||
uint16_t group;
|
uint16_t group;
|
||||||
@@ -180,24 +184,24 @@ struct acpi_mcfg_entry
|
|||||||
uint32_t reserved;
|
uint32_t reserved;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct acpi_mcfg
|
struct mcfg
|
||||||
{
|
{
|
||||||
TABLE_HEADER('MCFG');
|
TABLE_HEADER('MCFG');
|
||||||
uint64_t reserved;
|
uint64_t reserved;
|
||||||
acpi_mcfg_entry entries[0];
|
mcfg_entry entries[0];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct acpi_hpet
|
struct hpet
|
||||||
{
|
{
|
||||||
TABLE_HEADER('HPET');
|
TABLE_HEADER('HPET');
|
||||||
uint32_t hardware_id;
|
uint32_t hardware_id;
|
||||||
acpi_gas base_address;
|
gas base_address;
|
||||||
uint8_t index;
|
uint8_t index;
|
||||||
uint16_t periodic_min;
|
uint16_t periodic_min;
|
||||||
uint8_t attributes;
|
uint8_t attributes;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct acpi_bgrt
|
struct bgrt
|
||||||
{
|
{
|
||||||
TABLE_HEADER('BGRT');
|
TABLE_HEADER('BGRT');
|
||||||
uint16_t version;
|
uint16_t version;
|
||||||
@@ -208,3 +212,35 @@ struct acpi_bgrt
|
|||||||
uint32_t offset_y;
|
uint32_t offset_y;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct rsdp1
|
||||||
|
{
|
||||||
|
char signature[8];
|
||||||
|
uint8_t checksum;
|
||||||
|
char oem_id[6];
|
||||||
|
uint8_t revision;
|
||||||
|
uint32_t rsdt_address;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct rsdp2
|
||||||
|
{
|
||||||
|
char signature[8];
|
||||||
|
uint8_t checksum10;
|
||||||
|
char oem_id[6];
|
||||||
|
uint8_t revision;
|
||||||
|
uint32_t rsdt_address;
|
||||||
|
|
||||||
|
uint32_t length;
|
||||||
|
table_header *xsdt_address;
|
||||||
|
uint8_t checksum20;
|
||||||
|
uint8_t reserved[3];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
template <typename T> static const T *
|
||||||
|
check_get_table(const table_header *header)
|
||||||
|
{
|
||||||
|
if (!header || header->type != T::type_id)
|
||||||
|
return nullptr;
|
||||||
|
return reinterpret_cast<const T *>(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace acpi
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "apic.h"
|
#include "apic.h"
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
#include "interrupts.h"
|
#include "interrupts.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
#include "assert.h"
|
|
||||||
#include "idt.h"
|
|
||||||
|
|
||||||
namespace panic {
|
|
||||||
|
|
||||||
uint32_t *apic_icr = reinterpret_cast<uint32_t*>(0xffffc000fee00300);
|
|
||||||
void const *symbol_table = nullptr;
|
|
||||||
|
|
||||||
void
|
|
||||||
install(uintptr_t entrypoint, util::const_buffer symbol_data)
|
|
||||||
{
|
|
||||||
IDT::set_nmi_handler(entrypoint);
|
|
||||||
symbol_table = symbol_data.pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace panic
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
void __assert_fail(const char *message, const char *file, unsigned line, const char *function) {
|
|
||||||
panic::panic(message, nullptr, function, file, line);
|
|
||||||
}
|
|
||||||
@@ -68,6 +68,7 @@ cap_table::derive(j6_handle_t base, j6_cap_t caps)
|
|||||||
capability *
|
capability *
|
||||||
cap_table::find_without_retain(j6_handle_t id)
|
cap_table::find_without_retain(j6_handle_t id)
|
||||||
{
|
{
|
||||||
|
util::scoped_lock lock {m_lock};
|
||||||
return m_caps.find(id);
|
return m_caps.find(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
|
|
||||||
using __exit_func = void (*)(void *);
|
using __exit_func = void (*)(void *);
|
||||||
|
|
||||||
|
|||||||
@@ -1,58 +1,72 @@
|
|||||||
#include <new>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <j6/memutils.h>
|
||||||
#include <util/bitset.h>
|
#include <util/bitset.h>
|
||||||
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "cpu/cpu_id.h"
|
|
||||||
#include "device_manager.h"
|
#include "device_manager.h"
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "msr.h"
|
#include "msr.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
#include "scheduler.h"
|
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "tss.h"
|
#include "tss.h"
|
||||||
|
#include "xsave.h"
|
||||||
|
|
||||||
unsigned g_num_cpus = 1;
|
unsigned g_num_cpus = 1;
|
||||||
|
|
||||||
panic_data g_panic_data;
|
panic_data g_panic_data;
|
||||||
panic_data *g_panic_data_p = &g_panic_data;
|
panic_data *g_panic_data_p = &g_panic_data;
|
||||||
|
|
||||||
cpu_data g_bsp_cpu_data;
|
static util::no_construct<cpu_data> __g_bsp_cpu_storage;
|
||||||
|
cpu_data &g_bsp_cpu_data = __g_bsp_cpu_storage.value;
|
||||||
|
|
||||||
cpu_data **g_cpu_data = nullptr;
|
cpu_data **g_cpu_data = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
static cpu::features
|
||||||
|
get_features()
|
||||||
|
{
|
||||||
|
cpu::cpu_id cpuid;
|
||||||
|
return cpuid.features();
|
||||||
|
}
|
||||||
|
|
||||||
// Validate the required CPU features are present. Really, the bootloader already
|
// Validate the required CPU features are present. Really, the bootloader already
|
||||||
// validated the required features, but still iterate the options and log about them.
|
// validated the required features, but still iterate the options and log about them.
|
||||||
void
|
static cpu::features
|
||||||
cpu_validate()
|
cpu_validate(cpu_data *c)
|
||||||
{
|
{
|
||||||
cpu::cpu_id cpu;
|
cpu::cpu_id cpuid;
|
||||||
|
|
||||||
char brand_name[50];
|
char brand_name[50];
|
||||||
cpu.brand_name(brand_name);
|
cpuid.brand_name(brand_name);
|
||||||
|
|
||||||
cpu::cpu_id::features features = cpu.validate();
|
cpu::features &features = c->features;
|
||||||
|
|
||||||
log::info(logs::boot, "CPU: %s", brand_name);
|
log::info(logs::boot, "CPU %2d: %s", c->index, brand_name);
|
||||||
log::info(logs::boot, " Vendor is %s", cpu.vendor_id());
|
log::info(logs::boot, " Vendor is %s", cpuid.vendor_id());
|
||||||
|
|
||||||
log::spam(logs::boot, " Higest basic CPUID: 0x%02x", cpu.highest_basic());
|
log::spam(logs::boot, " Higest basic CPUID: 0x%02x", cpuid.highest_basic());
|
||||||
log::spam(logs::boot, " Higest ext CPUID: 0x%02x", cpu.highest_ext() & ~cpu::cpu_id::cpuid_extended);
|
log::spam(logs::boot, " Higest ext CPUID: 0x%02x", cpuid.highest_ext() & ~cpu::cpu_id::cpuid_extended);
|
||||||
|
|
||||||
#define CPU_FEATURE_OPT(name, ...) \
|
#define CPU_FEATURE_OPT(name, ...) \
|
||||||
log::verbose(logs::boot, " Supports %9s: %s", #name, features[cpu::feature::name] ? "yes" : "no");
|
log::verbose(logs::boot, " Flag %11s: %s", #name, features[cpu::feature::name] ? "yes" : "no");
|
||||||
|
|
||||||
|
#define CPU_FEATURE_WRN(name, feat_leaf, feat_sub, regname, bit) \
|
||||||
|
log::verbose(logs::boot, " Flag %11s: %s", #name, features[cpu::feature::name] ? "yes" : "no"); \
|
||||||
|
if (!features[cpu::feature::name]) log::warn(logs::boot, "Missing cpu feature %s but continuing", #name);
|
||||||
|
|
||||||
#define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \
|
#define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \
|
||||||
log::verbose(logs::boot, " Supports %9s: %s", #name, features[cpu::feature::name] ? "yes" : "no"); \
|
log::verbose(logs::boot, " Flag %11s: %s", #name, features[cpu::feature::name] ? "yes" : "no"); \
|
||||||
kassert(features[cpu::feature::name], "Missing required CPU feature " #name );
|
kassert(features[cpu::feature::name], "Missing required CPU feature " #name );
|
||||||
|
|
||||||
#include "cpu/features.inc"
|
#include "cpu/features.inc"
|
||||||
#undef CPU_FEATURE_OPT
|
#undef CPU_FEATURE_OPT
|
||||||
#undef CPU_FEATURE_REQ
|
#undef CPU_FEATURE_REQ
|
||||||
|
|
||||||
|
return features;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -64,13 +78,31 @@ cpu_early_init(cpu_data *cpu)
|
|||||||
cpu->idt->install();
|
cpu->idt->install();
|
||||||
cpu->gdt->install();
|
cpu->gdt->install();
|
||||||
|
|
||||||
|
util::bitset64 cr0_val = 0;
|
||||||
|
asm ("mov %%cr0, %0" : "=r"(cr0_val));
|
||||||
|
cr0_val
|
||||||
|
.set(cr0::WP)
|
||||||
|
.clear(cr0::CD);
|
||||||
|
asm volatile ( "mov %0, %%cr0" :: "r" (cr0_val) );
|
||||||
|
|
||||||
|
cpu->features = get_features();
|
||||||
|
|
||||||
|
uintptr_t cr3_val;
|
||||||
|
asm ("mov %%cr3, %0" : "=r"(cr3_val));
|
||||||
|
|
||||||
util::bitset64 cr4_val = 0;
|
util::bitset64 cr4_val = 0;
|
||||||
asm ("mov %%cr4, %0" : "=r"(cr4_val));
|
asm ("mov %%cr4, %0" : "=r"(cr4_val));
|
||||||
cr4_val
|
cr4_val
|
||||||
.set(cr4::OSXFSR)
|
.set(cr4::OSXFSR)
|
||||||
.set(cr4::OSXMMEXCPT)
|
.set(cr4::OSXMMEXCPT)
|
||||||
.set(cr4::PCIDE)
|
|
||||||
.set(cr4::OSXSAVE);
|
.set(cr4::OSXSAVE);
|
||||||
|
|
||||||
|
// TODO: On KVM setting PCIDE generates a #GP even though
|
||||||
|
// the feature is listed as available in CPUID.
|
||||||
|
/*
|
||||||
|
if (cpu->features[cpu::feature::pcid])
|
||||||
|
cr4_val.set(cr4::PCIDE);
|
||||||
|
*/
|
||||||
asm volatile ( "mov %0, %%cr4" :: "r" (cr4_val) );
|
asm volatile ( "mov %0, %%cr4" :: "r" (cr4_val) );
|
||||||
|
|
||||||
// Enable SYSCALL and NX bit
|
// Enable SYSCALL and NX bit
|
||||||
@@ -80,6 +112,24 @@ cpu_early_init(cpu_data *cpu)
|
|||||||
.set(efer::NXE);
|
.set(efer::NXE);
|
||||||
wrmsr(msr::ia32_efer, efer_val);
|
wrmsr(msr::ia32_efer, efer_val);
|
||||||
|
|
||||||
|
util::bitset64 xcr0_val = get_xcr0();
|
||||||
|
xcr0_val
|
||||||
|
.set(xcr0::SSE);
|
||||||
|
set_xcr0(xcr0_val);
|
||||||
|
|
||||||
|
// Set initial floating point state
|
||||||
|
const util::bitset32 mxcsr_val {
|
||||||
|
mxcsr::DAZ,
|
||||||
|
mxcsr::IM,
|
||||||
|
mxcsr::DM,
|
||||||
|
mxcsr::ZM,
|
||||||
|
mxcsr::OM,
|
||||||
|
mxcsr::UM,
|
||||||
|
mxcsr::PM,
|
||||||
|
mxcsr::FTZ,
|
||||||
|
};
|
||||||
|
asm ( "ldmxcsr %0" :: "m"(mxcsr_val) );
|
||||||
|
|
||||||
// Install the GS base pointint to the cpu_data
|
// Install the GS base pointint to the cpu_data
|
||||||
wrmsr(msr::ia32_gs_base, reinterpret_cast<uintptr_t>(cpu));
|
wrmsr(msr::ia32_gs_base, reinterpret_cast<uintptr_t>(cpu));
|
||||||
}
|
}
|
||||||
@@ -87,7 +137,6 @@ cpu_early_init(cpu_data *cpu)
|
|||||||
cpu_data *
|
cpu_data *
|
||||||
bsp_early_init()
|
bsp_early_init()
|
||||||
{
|
{
|
||||||
cpu_validate();
|
|
||||||
memset(&g_panic_data, 0, sizeof(g_panic_data));
|
memset(&g_panic_data, 0, sizeof(g_panic_data));
|
||||||
|
|
||||||
extern IDT &g_bsp_idt;
|
extern IDT &g_bsp_idt;
|
||||||
@@ -104,6 +153,7 @@ bsp_early_init()
|
|||||||
cpu->gdt = new (&g_bsp_gdt) GDT {cpu->tss};
|
cpu->gdt = new (&g_bsp_gdt) GDT {cpu->tss};
|
||||||
cpu->rsp0 = reinterpret_cast<uintptr_t>(&idle_stack_end);
|
cpu->rsp0 = reinterpret_cast<uintptr_t>(&idle_stack_end);
|
||||||
cpu_early_init(cpu);
|
cpu_early_init(cpu);
|
||||||
|
xsave_init();
|
||||||
|
|
||||||
return cpu;
|
return cpu;
|
||||||
}
|
}
|
||||||
@@ -120,8 +170,12 @@ bsp_late_init()
|
|||||||
asm ("mov %%cr0, %0" : "=r"(cr0v));
|
asm ("mov %%cr0, %0" : "=r"(cr0v));
|
||||||
asm ("mov %%cr4, %0" : "=r"(cr4v));
|
asm ("mov %%cr4, %0" : "=r"(cr4v));
|
||||||
|
|
||||||
|
uint32_t mxcsrv = get_mxcsr();
|
||||||
|
uint64_t xcr0v = get_xcr0();
|
||||||
|
|
||||||
uint64_t efer = rdmsr(msr::ia32_efer);
|
uint64_t efer = rdmsr(msr::ia32_efer);
|
||||||
log::spam(logs::boot, "Control regs: cr0:%lx cr4:%lx efer:%lx", cr0v, cr4v, efer);
|
log::spam(logs::boot, "Control regs: cr0:%lx cr4:%lx efer:%lx mxcsr:%x xcr0:%x", cr0v, cr4v, efer, mxcsrv, xcr0v);
|
||||||
|
cpu_validate(&g_bsp_cpu_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_data *
|
cpu_data *
|
||||||
@@ -162,7 +216,6 @@ cpu_init(cpu_data *cpu, bool bsp)
|
|||||||
|
|
||||||
obj::thread *idle = obj::thread::create_idle_thread(
|
obj::thread *idle = obj::thread::create_idle_thread(
|
||||||
g_kernel_process,
|
g_kernel_process,
|
||||||
scheduler::max_priority,
|
|
||||||
cpu->rsp0);
|
cpu->rsp0);
|
||||||
|
|
||||||
cpu->thread = idle;
|
cpu->thread = idle;
|
||||||
@@ -190,4 +243,16 @@ cpu_init(cpu_data *cpu, bool bsp)
|
|||||||
cpu->id = apic->get_id();
|
cpu->id = apic->get_id();
|
||||||
apic->calibrate_timer();
|
apic->calibrate_timer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xsave_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set up initial per-thread CPU state. Called once from initialize_user_cpu in
|
||||||
|
/// syscall.s, the first code run after a thread comes out of task_switch for the
|
||||||
|
/// very first time.
|
||||||
|
extern "C" void
|
||||||
|
cpu_initialize_thread_state()
|
||||||
|
{
|
||||||
|
const util::bitset32 &mxcsr_val = obj::thread::current().m_mxcsr;
|
||||||
|
asm ( "ldmxcsr %0" :: "m"(mxcsr_val) );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <cpu/cpu_id.h>
|
||||||
|
|
||||||
class GDT;
|
class GDT;
|
||||||
class IDT;
|
class IDT;
|
||||||
@@ -17,9 +18,12 @@ enum class cr0
|
|||||||
{
|
{
|
||||||
PE = 0, // Protected mode enable
|
PE = 0, // Protected mode enable
|
||||||
MP = 1, // Monitor co-processor
|
MP = 1, // Monitor co-processor
|
||||||
|
EM = 2, // (FPU) Emulation
|
||||||
|
TS = 3, // Task switched
|
||||||
ET = 4, // Extension type
|
ET = 4, // Extension type
|
||||||
NE = 5, // Numeric error
|
NE = 5, // Numeric error
|
||||||
WP = 16, // (ring 0) Write protect
|
WP = 16, // (ring 0) Write protect
|
||||||
|
CD = 30, // Cache disable
|
||||||
PG = 31, // Paging
|
PG = 31, // Paging
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -47,6 +51,8 @@ enum class xcr0
|
|||||||
ZMM_Hi256,
|
ZMM_Hi256,
|
||||||
ZMM_Hi16,
|
ZMM_Hi16,
|
||||||
PKRU = 9,
|
PKRU = 9,
|
||||||
|
|
||||||
|
J6_SUPPORTED = X87 | SSE | AVX | BINDREG | BINDCSR | OPMASK | ZMM_Hi16 | ZMM_Hi256,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class efer
|
enum class efer
|
||||||
@@ -58,6 +64,26 @@ enum class efer
|
|||||||
FFXSR = 14, // Fast FXSAVE
|
FFXSR = 14, // Fast FXSAVE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class mxcsr
|
||||||
|
{
|
||||||
|
IE = 0, // Invalid operation flag
|
||||||
|
DE = 1, // Denormal flag
|
||||||
|
ZE = 2, // Divide by zero flag
|
||||||
|
OE = 3, // Overflow flag
|
||||||
|
UE = 4, // Underflow flag
|
||||||
|
PE = 5, // Precision flag
|
||||||
|
DAZ = 6, // Denormals are zero
|
||||||
|
IM = 7, // Invalid operation mask
|
||||||
|
DM = 8, // Denormal mask
|
||||||
|
ZM = 9, // Divide by zero mask
|
||||||
|
OM = 10, // Overflow mask
|
||||||
|
UM = 11, // Underflow mask
|
||||||
|
PM = 12, // Precision mask
|
||||||
|
RC0 = 13, // Rounding control bit 0
|
||||||
|
RC1 = 14, // Rounding control bit 1
|
||||||
|
FTZ = 15, // Flush to zero
|
||||||
|
};
|
||||||
|
|
||||||
struct cpu_state
|
struct cpu_state
|
||||||
{
|
{
|
||||||
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
|
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
|
||||||
@@ -105,9 +131,20 @@ struct cpu_data
|
|||||||
// the assembly version
|
// the assembly version
|
||||||
lapic *apic;
|
lapic *apic;
|
||||||
panic_data *panic;
|
panic_data *panic;
|
||||||
|
cpu::features features;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" cpu_data * _current_gsbase();
|
extern "C" {
|
||||||
|
uint32_t get_mxcsr();
|
||||||
|
uint32_t set_mxcsr(uint32_t val);
|
||||||
|
|
||||||
|
uint64_t get_xcr0();
|
||||||
|
uint64_t set_xcr0(uint64_t val);
|
||||||
|
|
||||||
|
cpu_data * _current_gsbase();
|
||||||
|
|
||||||
|
void cpu_initialize_thread_state();
|
||||||
|
}
|
||||||
|
|
||||||
/// Do early initialization of the BSP CPU.
|
/// Do early initialization of the BSP CPU.
|
||||||
/// \returns A pointer to the BSP cpu_data structure
|
/// \returns A pointer to the BSP cpu_data structure
|
||||||
|
|||||||
@@ -1,3 +1,34 @@
|
|||||||
|
global get_mxcsr: function hidden (get_mxcsr.end - get_mxcsr)
|
||||||
|
get_mxcsr:
|
||||||
|
push 0
|
||||||
|
stmxcsr [rsp]
|
||||||
|
pop rax
|
||||||
|
ret
|
||||||
|
.end:
|
||||||
|
|
||||||
|
global set_mxcsr: function hidden (set_mxcsr.end - set_mxcsr)
|
||||||
|
set_mxcsr:
|
||||||
|
push rdi
|
||||||
|
ldmxcsr [rsp]
|
||||||
|
pop rax
|
||||||
|
ret
|
||||||
|
.end:
|
||||||
|
|
||||||
|
global get_xcr0: function hidden (get_xcr0.end - get_xcr0)
|
||||||
|
get_xcr0:
|
||||||
|
xor rcx, rcx ; there is no dana there is only xcr0
|
||||||
|
xgetbv
|
||||||
|
ret ; technically edx has the high 32 bits, but bits 10+ are reserved
|
||||||
|
.end:
|
||||||
|
|
||||||
|
global set_xcr0: function hidden (set_xcr0.end - set_xcr0)
|
||||||
|
set_xcr0:
|
||||||
|
xor rcx, rcx ; there is no dana there is only xcr0
|
||||||
|
mov rax, rdi ; technically edx should be or'd into the high bits, but xcr0 bits 10+ are resereved
|
||||||
|
xsetbv
|
||||||
|
ret
|
||||||
|
.end:
|
||||||
|
|
||||||
global get_rsp: function hidden (get_rsp.end - get_rsp)
|
global get_rsp: function hidden (get_rsp.end - get_rsp)
|
||||||
get_rsp:
|
get_rsp:
|
||||||
mov rax, rsp
|
mov rax, rsp
|
||||||
87
src/kernel/debugcon.cpp
Normal file
87
src/kernel/debugcon.cpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include <util/format.h>
|
||||||
|
|
||||||
|
#include "debugcon.h"
|
||||||
|
#include "interrupts.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
namespace debugcon {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
static const uint8_t level_colors[] = {0x00, 0x09, 0x01, 0x0b, 0x0f, 0x07, 0x08};
|
||||||
|
const char *level_names[] = {"", "fatal", "error", "warn", "info", "verbose", "spam"};
|
||||||
|
const char *area_names[] = {
|
||||||
|
#define LOG(name, lvl) #name ,
|
||||||
|
#include <j6/tables/log_areas.inc>
|
||||||
|
#undef LOG
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void debug_out(const char *msg, size_t size) {
|
||||||
|
asm ( "rep outsb;" :: "c"(size), "d"(port), "S"(msg) );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void debug_endline() {
|
||||||
|
static const char *newline = "\e[0m\r\n";
|
||||||
|
asm ( "rep outsb;" :: "c"(6), "d"(port), "S"(newline) );
|
||||||
|
}
|
||||||
|
} // anon namespace
|
||||||
|
|
||||||
|
void
|
||||||
|
write(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char buffer[256];
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
size_t n = util::vformat({buffer, sizeof(buffer)}, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
debug_out(buffer, n);
|
||||||
|
debug_out("\r\n", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
output(j6_log_entry *entry)
|
||||||
|
{
|
||||||
|
char buffer [256];
|
||||||
|
size_t dlen = util::format({buffer, sizeof(buffer)}, "\e[38;5;%dm%7s %7s\e[38;5;14m|\e[38;5;%dm ",
|
||||||
|
level_colors[entry->severity],
|
||||||
|
area_names[entry->area],
|
||||||
|
level_names[entry->severity],
|
||||||
|
level_colors[entry->severity]);
|
||||||
|
|
||||||
|
debug_out(buffer, dlen);
|
||||||
|
|
||||||
|
debug_out(entry->message, entry->bytes - sizeof(j6_log_entry));
|
||||||
|
debug_endline();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logger_task()
|
||||||
|
{
|
||||||
|
using entry = j6_log_entry;
|
||||||
|
|
||||||
|
uint64_t seen = 0;
|
||||||
|
size_t buf_size = 128;
|
||||||
|
uint8_t *buf = new uint8_t [buf_size];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
size_t size = g_logger.get_entry(seen, buf, buf_size);
|
||||||
|
if (size > buf_size) {
|
||||||
|
delete [] buf;
|
||||||
|
buf_size *= 2;
|
||||||
|
buf = new uint8_t [buf_size];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry *header = reinterpret_cast<entry*>(buf);
|
||||||
|
while (size > sizeof(entry)) {
|
||||||
|
output(header);
|
||||||
|
seen = header->id;
|
||||||
|
size -= header->bytes;
|
||||||
|
header = util::offset_pointer(header, header->bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace debugcon
|
||||||
31
src/kernel/debugcon.h
Normal file
31
src/kernel/debugcon.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file debugcon.h
|
||||||
|
/// Kernel debugcon log output process
|
||||||
|
|
||||||
|
#include "scheduler.h"
|
||||||
|
|
||||||
|
namespace debugcon {
|
||||||
|
|
||||||
|
static constexpr bool enable =
|
||||||
|
#ifdef __jsix_config_debug
|
||||||
|
true;
|
||||||
|
#else
|
||||||
|
false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr uint16_t port = 0x6600;
|
||||||
|
|
||||||
|
void logger_task();
|
||||||
|
void write(const char *fmt, ...);
|
||||||
|
|
||||||
|
inline void
|
||||||
|
init_logger()
|
||||||
|
{
|
||||||
|
if constexpr (enable) {
|
||||||
|
static constexpr uint8_t pri = scheduler::max_priority - 1;
|
||||||
|
scheduler &s = scheduler::get();
|
||||||
|
s.create_kernel_task(logger_task, pri, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace debugcon
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
#include <new>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <util/misc.h> // for checksum
|
#include <util/misc.h> // for checksum
|
||||||
#include <util/pointers.h>
|
#include <util/pointers.h>
|
||||||
|
#include <arch/acpi/tables.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "acpi_tables.h"
|
|
||||||
#include "apic.h"
|
#include "apic.h"
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
#include "device_manager.h"
|
#include "device_manager.h"
|
||||||
@@ -21,37 +20,6 @@ static const char expected_signature[] = "RSD PTR ";
|
|||||||
|
|
||||||
device_manager device_manager::s_instance;
|
device_manager device_manager::s_instance;
|
||||||
|
|
||||||
struct acpi1_rsdp
|
|
||||||
{
|
|
||||||
char signature[8];
|
|
||||||
uint8_t checksum;
|
|
||||||
char oem_id[6];
|
|
||||||
uint8_t revision;
|
|
||||||
uint32_t rsdt_address;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct acpi2_rsdp
|
|
||||||
{
|
|
||||||
char signature[8];
|
|
||||||
uint8_t checksum10;
|
|
||||||
char oem_id[6];
|
|
||||||
uint8_t revision;
|
|
||||||
uint32_t rsdt_address;
|
|
||||||
|
|
||||||
uint32_t length;
|
|
||||||
acpi_table_header *xsdt_address;
|
|
||||||
uint8_t checksum20;
|
|
||||||
uint8_t reserved[3];
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
bool
|
|
||||||
acpi_table_header::validate(uint32_t expected_type) const
|
|
||||||
{
|
|
||||||
if (util::checksum(this, length) != 0) return false;
|
|
||||||
return !expected_type || (expected_type == type);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
device_manager::device_manager() :
|
device_manager::device_manager() :
|
||||||
m_lapic_base(0)
|
m_lapic_base(0)
|
||||||
{
|
{
|
||||||
@@ -63,37 +31,32 @@ device_manager::device_manager() :
|
|||||||
m_irqs[2] = {ignore_event, 0};
|
m_irqs[2] = {ignore_event, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> static const T *
|
|
||||||
check_get_table(const acpi_table_header *header)
|
|
||||||
{
|
|
||||||
kassert(header && header->validate(T::type_id), "Invalid ACPI table.");
|
|
||||||
return reinterpret_cast<const T *>(header);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
device_manager::parse_acpi(const void *root_table)
|
device_manager::parse_acpi(const void *root_table)
|
||||||
{
|
{
|
||||||
kassert(root_table != 0, "ACPI root table pointer is null.");
|
kassert(root_table != 0, "ACPI root table pointer is null.");
|
||||||
|
|
||||||
const acpi1_rsdp *acpi1 = mem::to_virtual(
|
const acpi::rsdp1 *acpi1 = mem::to_virtual(
|
||||||
reinterpret_cast<const acpi1_rsdp *>(root_table));
|
reinterpret_cast<const acpi::rsdp1 *>(root_table));
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(acpi1->signature); ++i)
|
for (int i = 0; i < sizeof(acpi1->signature); ++i)
|
||||||
kassert(acpi1->signature[i] == expected_signature[i],
|
kassert(acpi1->signature[i] == expected_signature[i],
|
||||||
"ACPI RSDP table signature mismatch");
|
"ACPI RSDP table signature mismatch");
|
||||||
|
|
||||||
uint8_t sum = util::checksum(acpi1, sizeof(acpi1_rsdp), 0);
|
uint8_t sum = util::checksum(acpi1, sizeof(acpi::rsdp1), 0);
|
||||||
kassert(sum == 0, "ACPI 1.0 RSDP checksum mismatch.");
|
kassert(sum == 0, "ACPI 1.0 RSDP checksum mismatch.");
|
||||||
|
|
||||||
kassert(acpi1->revision > 1, "ACPI 1.0 not supported.");
|
kassert(acpi1->revision > 1, "ACPI 1.0 not supported.");
|
||||||
|
|
||||||
const acpi2_rsdp *acpi2 =
|
const acpi::rsdp2 *acpi2 =
|
||||||
reinterpret_cast<const acpi2_rsdp *>(acpi1);
|
reinterpret_cast<const acpi::rsdp2 *>(acpi1);
|
||||||
|
|
||||||
sum = util::checksum(acpi2, sizeof(acpi2_rsdp), sizeof(acpi1_rsdp));
|
sum = util::checksum(acpi2, sizeof(acpi::rsdp2), sizeof(acpi::rsdp1));
|
||||||
kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch.");
|
kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch.");
|
||||||
|
|
||||||
load_xsdt(mem::to_virtual(acpi2->xsdt_address));
|
const acpi::table_header *xsdt = mem::to_virtual(acpi2->xsdt_address);
|
||||||
|
kassert(xsdt->validate(), "Bad XSDT table");
|
||||||
|
load_xsdt(xsdt);
|
||||||
}
|
}
|
||||||
|
|
||||||
const device_manager::apic_nmi *
|
const device_manager::apic_nmi *
|
||||||
@@ -129,53 +92,50 @@ put_sig(char *into, uint32_t type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
device_manager::load_xsdt(const acpi_table_header *header)
|
device_manager::load_xsdt(const acpi::table_header *header)
|
||||||
{
|
{
|
||||||
const auto *xsdt = check_get_table<acpi_xsdt>(header);
|
const auto *xsdt = acpi::check_get_table<acpi::xsdt>(header);
|
||||||
|
|
||||||
char sig[5] = {0,0,0,0,0};
|
char sig[5] = {0,0,0,0,0};
|
||||||
log::info(logs::device, "ACPI 2.0+ tables loading");
|
log::info(logs::device, "ACPI 2.0+ tables loading");
|
||||||
|
|
||||||
put_sig(sig, xsdt->header.type);
|
put_sig(sig, xsdt->header.type);
|
||||||
log::verbose(logs::device, " Found table %s", sig);
|
log::verbose(logs::device, " Loading table %s", sig);
|
||||||
|
|
||||||
size_t num_tables = acpi_table_entries(xsdt, sizeof(void*));
|
size_t num_tables = acpi::table_entries(xsdt, sizeof(void*));
|
||||||
for (size_t i = 0; i < num_tables; ++i) {
|
for (size_t i = 0; i < num_tables; ++i) {
|
||||||
const acpi_table_header *header =
|
const acpi::table_header *header =
|
||||||
mem::to_virtual(xsdt->headers[i]);
|
mem::to_virtual(xsdt->headers[i]);
|
||||||
|
|
||||||
put_sig(sig, header->type);
|
|
||||||
log::verbose(logs::device, " Found table %s", sig);
|
|
||||||
|
|
||||||
kassert(header->validate(), "Table failed validation.");
|
kassert(header->validate(), "Table failed validation.");
|
||||||
|
put_sig(sig, header->type);
|
||||||
|
|
||||||
switch (header->type) {
|
switch (header->type) {
|
||||||
case acpi_apic::type_id:
|
case acpi::apic::type_id:
|
||||||
|
log::verbose(logs::device, " Loading table %s", sig);
|
||||||
load_apic(header);
|
load_apic(header);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case acpi_mcfg::type_id:
|
case acpi::hpet::type_id:
|
||||||
load_mcfg(header);
|
log::verbose(logs::device, " Loading table %s", sig);
|
||||||
break;
|
|
||||||
|
|
||||||
case acpi_hpet::type_id:
|
|
||||||
load_hpet(header);
|
load_hpet(header);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
log::verbose(logs::device, " Skipping table %s", sig);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
device_manager::load_apic(const acpi_table_header *header)
|
device_manager::load_apic(const acpi::table_header *header)
|
||||||
{
|
{
|
||||||
const auto *apic = check_get_table<acpi_apic>(header);
|
const auto *apic = acpi::check_get_table<acpi::apic>(header);
|
||||||
|
|
||||||
m_lapic_base = apic->local_address;
|
m_lapic_base = apic->local_address;
|
||||||
|
|
||||||
size_t count = acpi_table_entries(apic, 1);
|
size_t count = acpi::table_entries(apic, 1);
|
||||||
uint8_t const *p = apic->controller_data;
|
uint8_t const *p = apic->controller_data;
|
||||||
uint8_t const *end = p + count;
|
uint8_t const *end = p + count;
|
||||||
|
|
||||||
@@ -265,33 +225,9 @@ device_manager::load_apic(const acpi_table_header *header)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
device_manager::load_mcfg(const acpi_table_header *header)
|
device_manager::load_hpet(const acpi::table_header *header)
|
||||||
{
|
{
|
||||||
const auto *mcfg = check_get_table<acpi_mcfg>(header);
|
const auto *hpet = acpi::check_get_table<acpi::hpet>(header);
|
||||||
|
|
||||||
size_t count = acpi_table_entries(mcfg, sizeof(acpi_mcfg_entry));
|
|
||||||
m_pci.set_size(count);
|
|
||||||
m_devices.set_capacity(16);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
|
||||||
const acpi_mcfg_entry &mcfge = mcfg->entries[i];
|
|
||||||
|
|
||||||
m_pci[i].group = mcfge.group;
|
|
||||||
m_pci[i].bus_start = mcfge.bus_start;
|
|
||||||
m_pci[i].bus_end = mcfge.bus_end;
|
|
||||||
m_pci[i].base = mem::to_virtual<uint32_t>(mcfge.base);
|
|
||||||
|
|
||||||
log::spam(logs::device, " Found MCFG entry: base %lx group %d bus %d-%d",
|
|
||||||
mcfge.base, mcfge.group, mcfge.bus_start, mcfge.bus_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
probe_pci();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
device_manager::load_hpet(const acpi_table_header *header)
|
|
||||||
{
|
|
||||||
const auto *hpet = check_get_table<acpi_hpet>(header);
|
|
||||||
|
|
||||||
log::verbose(logs::device, " Found HPET device #%3d: base %016lx pmin %d attr %02x",
|
log::verbose(logs::device, " Found HPET device #%3d: base %016lx pmin %d attr %02x",
|
||||||
hpet->index, hpet->base_address.address, hpet->periodic_min, hpet->attributes);
|
hpet->index, hpet->base_address.address, hpet->periodic_min, hpet->attributes);
|
||||||
@@ -311,28 +247,6 @@ device_manager::load_hpet(const acpi_table_header *header)
|
|||||||
reinterpret_cast<uint64_t*>(hpet->base_address.address + mem::linear_offset));
|
reinterpret_cast<uint64_t*>(hpet->base_address.address + mem::linear_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
device_manager::probe_pci()
|
|
||||||
{
|
|
||||||
for (auto &pci : m_pci) {
|
|
||||||
log::verbose(logs::device, "Probing PCI group at base %016lx", pci.base);
|
|
||||||
|
|
||||||
for (int bus = pci.bus_start; bus <= pci.bus_end; ++bus) {
|
|
||||||
for (int dev = 0; dev < 32; ++dev) {
|
|
||||||
if (!pci.has_device(bus, dev, 0)) continue;
|
|
||||||
|
|
||||||
auto &d0 = m_devices.emplace(pci, bus, dev, 0);
|
|
||||||
if (!d0.multi()) continue;
|
|
||||||
|
|
||||||
for (int i = 1; i < 8; ++i) {
|
|
||||||
if (pci.has_device(bus, dev, i))
|
|
||||||
m_devices.emplace(pci, bus, dev, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t
|
static uint64_t
|
||||||
tsc_clock_source(void*)
|
tsc_clock_source(void*)
|
||||||
{
|
{
|
||||||
@@ -366,7 +280,7 @@ device_manager::init_drivers()
|
|||||||
|
|
||||||
// becomes the singleton
|
// becomes the singleton
|
||||||
master_clock = new clock(h.rate(), hpet_clock_source, &h);
|
master_clock = new clock(h.rate(), hpet_clock_source, &h);
|
||||||
log::info(logs::clock, "Created master clock using HPET 0: Rate %d", h.rate());
|
log::info(logs::timer, "Created master clock using HPET 0: Rate %d", h.rate());
|
||||||
} else {
|
} else {
|
||||||
//TODO: Other clocks, APIC clock?
|
//TODO: Other clocks, APIC clock?
|
||||||
master_clock = new clock(5000, tsc_clock_source, nullptr);
|
master_clock = new clock(5000, tsc_clock_source, nullptr);
|
||||||
@@ -385,7 +299,7 @@ device_manager::dispatch_irq(unsigned irq)
|
|||||||
if (!binding.target || binding.target == ignore_event)
|
if (!binding.target || binding.target == ignore_event)
|
||||||
return binding.target == ignore_event;
|
return binding.target == ignore_event;
|
||||||
|
|
||||||
binding.target->signal(1 << binding.signal);
|
binding.target->signal(1ull << binding.signal);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,10 +324,10 @@ device_manager::unbind_irqs(obj::event *target)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
bool
|
bool
|
||||||
device_manager::allocate_msi(const char *name, pci_device &device, irq_callback cb, void *data)
|
device_manager::allocate_msi(const char *name, pci_device &device, irq_callback cb, void *data)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
// TODO: find gaps to fill
|
// TODO: find gaps to fill
|
||||||
uint8_t irq = m_irqs.count();
|
uint8_t irq = m_irqs.count();
|
||||||
isr vector = isr::irq00 + irq;
|
isr vector = isr::irq00 + irq;
|
||||||
@@ -424,12 +338,6 @@ device_manager::allocate_msi(const char *name, pci_device &device, irq_callback
|
|||||||
device.write_msi_regs(
|
device.write_msi_regs(
|
||||||
0xFEE00000,
|
0xFEE00000,
|
||||||
static_cast<uint16_t>(vector));
|
static_cast<uint16_t>(vector));
|
||||||
*/
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
void
|
|
||||||
device_manager::register_block_device(block_device *blockdev)
|
|
||||||
{
|
|
||||||
m_blockdevs.append(blockdev);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,11 +6,13 @@
|
|||||||
|
|
||||||
#include "apic.h"
|
#include "apic.h"
|
||||||
#include "hpet.h"
|
#include "hpet.h"
|
||||||
#include "pci.h"
|
|
||||||
|
|
||||||
struct acpi_table_header;
|
|
||||||
class block_device;
|
class block_device;
|
||||||
|
|
||||||
|
namespace acpi {
|
||||||
|
struct table_header;
|
||||||
|
}
|
||||||
|
|
||||||
namespace obj {
|
namespace obj {
|
||||||
class event;
|
class event;
|
||||||
}
|
}
|
||||||
@@ -53,18 +55,6 @@ public:
|
|||||||
/// \arg target The endpoint to remove
|
/// \arg target The endpoint to remove
|
||||||
void unbind_irqs(obj::event *target);
|
void unbind_irqs(obj::event *target);
|
||||||
|
|
||||||
/// Allocate an MSI IRQ for a device
|
|
||||||
/// \arg name Name of the interrupt, for display to user
|
|
||||||
/// \arg device Device this MSI is being allocated for
|
|
||||||
/// \arg cb Callback to call when the interrupt is received
|
|
||||||
/// \arg data Data to pass to the callback
|
|
||||||
/// \returns True if an interrupt was allocated successfully
|
|
||||||
bool allocate_msi(
|
|
||||||
const char *name,
|
|
||||||
pci_device &device,
|
|
||||||
irq_callback cb,
|
|
||||||
void *data);
|
|
||||||
|
|
||||||
/// Dispatch an IRQ interrupt
|
/// Dispatch an IRQ interrupt
|
||||||
/// \arg irq The irq number of the interrupt
|
/// \arg irq The irq number of the interrupt
|
||||||
/// \returns True if the interrupt was handled
|
/// \returns True if the interrupt was handled
|
||||||
@@ -103,23 +93,6 @@ public:
|
|||||||
/// configuration, or null if no configuration was provided
|
/// configuration, or null if no configuration was provided
|
||||||
const irq_override * get_irq_override(uint8_t irq) const;
|
const irq_override * get_irq_override(uint8_t irq) const;
|
||||||
|
|
||||||
/// Register the existance of a block device.
|
|
||||||
/// \arg blockdev Pointer to the block device
|
|
||||||
void register_block_device(block_device *blockdev);
|
|
||||||
|
|
||||||
/// Get the number of block devices in the system
|
|
||||||
/// \returns A count of devices
|
|
||||||
inline unsigned get_num_block_devices() const { return m_blockdevs.count(); }
|
|
||||||
|
|
||||||
/// Get a block device
|
|
||||||
/// \arg i Index of the device to get
|
|
||||||
/// \returns A pointer to the requested device, or nullptr
|
|
||||||
inline block_device * get_block_device(unsigned i)
|
|
||||||
{
|
|
||||||
return i < m_blockdevs.count() ?
|
|
||||||
m_blockdevs[i] : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get an HPET device
|
/// Get an HPET device
|
||||||
/// \arg i Index of the device to get
|
/// \arg i Index of the device to get
|
||||||
/// \returns A pointer to the requested device, or nullptr
|
/// \returns A pointer to the requested device, or nullptr
|
||||||
@@ -132,23 +105,15 @@ public:
|
|||||||
private:
|
private:
|
||||||
/// Parse the ACPI XSDT and load relevant sub-tables.
|
/// Parse the ACPI XSDT and load relevant sub-tables.
|
||||||
/// \arg xsdt Pointer to the XSDT from the firmware
|
/// \arg xsdt Pointer to the XSDT from the firmware
|
||||||
void load_xsdt(const acpi_table_header *xsdt);
|
void load_xsdt(const acpi::table_header *xsdt);
|
||||||
|
|
||||||
/// Parse the ACPI MADT and initialize APICs from it.
|
/// Parse the ACPI MADT and initialize APICs from it.
|
||||||
/// \arg apic Pointer to the MADT from the XSDT
|
/// \arg apic Pointer to the MADT from the XSDT
|
||||||
void load_apic(const acpi_table_header *apic);
|
void load_apic(const acpi::table_header *apic);
|
||||||
|
|
||||||
/// Parse the ACPI MCFG and initialize PCIe from it.
|
|
||||||
/// \arg mcfg Pointer to the MCFG from the XSDT
|
|
||||||
void load_mcfg(const acpi_table_header *mcfg);
|
|
||||||
|
|
||||||
/// Parse the ACPI HPET and initialize an HPET from it.
|
/// Parse the ACPI HPET and initialize an HPET from it.
|
||||||
/// \arg hpet Pointer to the HPET from the XSDT
|
/// \arg hpet Pointer to the HPET from the XSDT
|
||||||
void load_hpet(const acpi_table_header *hpet);
|
void load_hpet(const acpi::table_header *hpet);
|
||||||
|
|
||||||
/// Probe the PCIe busses and add found devices to our
|
|
||||||
/// device list. The device list is destroyed and rebuilt.
|
|
||||||
void probe_pci();
|
|
||||||
|
|
||||||
/// Handle a bad IRQ. Called when an interrupt is dispatched
|
/// Handle a bad IRQ. Called when an interrupt is dispatched
|
||||||
/// that has no callback.
|
/// that has no callback.
|
||||||
@@ -162,9 +127,6 @@ private:
|
|||||||
util::vector<apic_nmi> m_nmis;
|
util::vector<apic_nmi> m_nmis;
|
||||||
util::vector<irq_override> m_overrides;
|
util::vector<irq_override> m_overrides;
|
||||||
|
|
||||||
util::vector<pci_group> m_pci;
|
|
||||||
util::vector<pci_device> m_devices;
|
|
||||||
|
|
||||||
struct irq_binding
|
struct irq_binding
|
||||||
{
|
{
|
||||||
obj::event *target = nullptr;
|
obj::event *target = nullptr;
|
||||||
@@ -172,8 +134,6 @@ private:
|
|||||||
};
|
};
|
||||||
util::vector<irq_binding> m_irqs;
|
util::vector<irq_binding> m_irqs;
|
||||||
|
|
||||||
util::vector<block_device *> m_blockdevs;
|
|
||||||
|
|
||||||
static device_manager s_instance;
|
static device_manager s_instance;
|
||||||
|
|
||||||
device_manager(const device_manager &) = delete;
|
device_manager(const device_manager &) = delete;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <bootproto/kernel.h>
|
#include <bootproto/kernel.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
|
#include "debugcon.h"
|
||||||
#include "frame_allocator.h"
|
#include "frame_allocator.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
@@ -51,7 +52,7 @@ frame_allocator::allocate(size_t count, uintptr_t *address)
|
|||||||
unsigned frame = (o1 << 12) + (o2 << 6) + o3;
|
unsigned frame = (o1 << 12) + (o2 << 6) + o3;
|
||||||
|
|
||||||
// See how many contiguous pages are here
|
// See how many contiguous pages are here
|
||||||
unsigned n = bsf(~m3 >> o3);
|
unsigned n = bsf(~(m3 >> o3));
|
||||||
if (n > count)
|
if (n > count)
|
||||||
n = count;
|
n = count;
|
||||||
|
|
||||||
@@ -71,6 +72,7 @@ frame_allocator::allocate(size_t count, uintptr_t *address)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//debugcon::write("Allocated %2d frames at %016lx - %016lx", n, *address, *address + n * frame_size);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +90,8 @@ frame_allocator::free(uintptr_t address, size_t count)
|
|||||||
if (!count)
|
if (!count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//debugcon::write("Freeing %2d frames at %016lx - %016lx", count, address, address + count * frame_size);
|
||||||
|
|
||||||
for (long i = 0; i < m_count; ++i) {
|
for (long i = 0; i < m_count; ++i) {
|
||||||
frame_block &block = m_blocks[i];
|
frame_block &block = m_blocks[i];
|
||||||
uintptr_t end = block.base + block.count * frame_size;
|
uintptr_t end = block.base + block.count * frame_size;
|
||||||
@@ -101,9 +105,9 @@ frame_allocator::free(uintptr_t address, size_t count)
|
|||||||
unsigned o3 = frame & 0x3f;
|
unsigned o3 = frame & 0x3f;
|
||||||
|
|
||||||
while (count--) {
|
while (count--) {
|
||||||
block.map1 |= (1 << o1);
|
block.map1 |= (1ull << o1);
|
||||||
block.map2[o1] |= (1 << o2);
|
block.map2[o1] |= (1ull << o2);
|
||||||
block.bitmap[o2] |= (1 << o3);
|
block.bitmap[o2] |= (1ull << o3);
|
||||||
if (++o3 == 64) {
|
if (++o3 == 64) {
|
||||||
o3 = 0;
|
o3 = 0;
|
||||||
if (++o2 == 64) {
|
if (++o2 == 64) {
|
||||||
@@ -139,12 +143,12 @@ frame_allocator::used(uintptr_t address, size_t count)
|
|||||||
unsigned o3 = frame & 0x3f;
|
unsigned o3 = frame & 0x3f;
|
||||||
|
|
||||||
while (count--) {
|
while (count--) {
|
||||||
block.bitmap[o2] &= ~(1 << o3);
|
block.bitmap[o2] &= ~(1ull << o3);
|
||||||
if (!block.bitmap[o2]) {
|
if (!block.bitmap[o2]) {
|
||||||
block.map2[o1] &= ~(1 << o2);
|
block.map2[o1] &= ~(1ull << o2);
|
||||||
|
|
||||||
if (!block.map2[o1]) {
|
if (!block.map2[o1]) {
|
||||||
block.map1 &= ~(1 << o1);
|
block.map1 &= ~(1ull << o1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
#include <stdint.h>
|
#include <j6/memutils.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <util/no_construct.h>
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
#include <new>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
#include <j6/memutils.h>
|
||||||
#include <util/pointers.h>
|
#include <util/pointers.h>
|
||||||
#include <util/util.h>
|
#include <util/util.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "heap_allocator.h"
|
#include "heap_allocator.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "objects/vm_area.h"
|
||||||
|
#include "vm_space.h"
|
||||||
|
|
||||||
uint32_t & get_map_key(heap_allocator::block_info &info) { return info.offset; }
|
uint32_t & get_map_key(heap_allocator::block_info &info) { return info.offset; }
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ struct heap_allocator::free_header
|
|||||||
|
|
||||||
inline free_header * buddy() const {
|
inline free_header * buddy() const {
|
||||||
return reinterpret_cast<free_header *>(
|
return reinterpret_cast<free_header *>(
|
||||||
reinterpret_cast<uintptr_t>(this) ^ (1 << order));
|
reinterpret_cast<uintptr_t>(this) ^ (1ull << order));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool eldest() const { return this < buddy(); }
|
inline bool eldest() const { return this < buddy(); }
|
||||||
@@ -46,7 +47,6 @@ heap_allocator::heap_allocator(uintptr_t start, size_t size, uintptr_t heapmap)
|
|||||||
m_maxsize {size},
|
m_maxsize {size},
|
||||||
m_allocated_size {0},
|
m_allocated_size {0},
|
||||||
m_map (reinterpret_cast<block_info*>(heapmap), 512)
|
m_map (reinterpret_cast<block_info*>(heapmap), 512)
|
||||||
|
|
||||||
{
|
{
|
||||||
memset(m_free, 0, sizeof(m_free));
|
memset(m_free, 0, sizeof(m_free));
|
||||||
}
|
}
|
||||||
@@ -57,6 +57,11 @@ heap_allocator::allocate(size_t length)
|
|||||||
if (length == 0)
|
if (length == 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
static constexpr unsigned min_order =
|
||||||
|
__debug_heap_allocation ?
|
||||||
|
12 : // allocating full pages in debug mode
|
||||||
|
heap_allocator::min_order;
|
||||||
|
|
||||||
unsigned order = util::log2(length);
|
unsigned order = util::log2(length);
|
||||||
if (order < min_order)
|
if (order < min_order)
|
||||||
order = min_order;
|
order = min_order;
|
||||||
@@ -67,7 +72,7 @@ heap_allocator::allocate(size_t length)
|
|||||||
|
|
||||||
util::scoped_lock lock {m_lock};
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
m_allocated_size += (1 << order);
|
m_allocated_size += (1ull << order);
|
||||||
|
|
||||||
free_header *block = pop_free(order);
|
free_header *block = pop_free(order);
|
||||||
if (!block && !split_off(order, block)) {
|
if (!block && !split_off(order, block)) {
|
||||||
@@ -95,7 +100,17 @@ heap_allocator::free(void *p)
|
|||||||
kassert(info, "Attempt to free pointer not known to the heap");
|
kassert(info, "Attempt to free pointer not known to the heap");
|
||||||
if (!info) return;
|
if (!info) return;
|
||||||
|
|
||||||
m_allocated_size -= (1 << info->order);
|
size_t size = (1ull << info->order);
|
||||||
|
m_allocated_size -= size;
|
||||||
|
|
||||||
|
if constexpr (__debug_heap_allocation) {
|
||||||
|
extern obj::vm_area_untracked &g_kernel_heap_area;
|
||||||
|
|
||||||
|
size_t offset = reinterpret_cast<uintptr_t>(p) - mem::heap_offset;
|
||||||
|
size_t pages = mem::bytes_to_pages(size);
|
||||||
|
vm_space::kernel_space().lock(g_kernel_heap_area, offset, pages);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
block->clear(info->order);
|
block->clear(info->order);
|
||||||
block = merge_block(block);
|
block = merge_block(block);
|
||||||
@@ -118,15 +133,15 @@ heap_allocator::reallocate(void *p, size_t old_length, size_t new_length)
|
|||||||
if (!info)
|
if (!info)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (new_length <= (1 << info->order))
|
if (new_length <= (1ull << info->order))
|
||||||
return p;
|
return p;
|
||||||
|
|
||||||
lock.release();
|
lock.release();
|
||||||
void *new_block = allocate(new_length);
|
void *reallocated = allocate(new_length);
|
||||||
memcpy(new_block, p, old_length);
|
memcpy(reallocated, p, old_length);
|
||||||
free(p);
|
free(p);
|
||||||
|
|
||||||
return new_block;
|
return reallocated;
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_allocator::free_header *
|
heap_allocator::free_header *
|
||||||
@@ -180,13 +195,15 @@ heap_allocator::new_block(unsigned order)
|
|||||||
unsigned current = address_order(m_end);
|
unsigned current = address_order(m_end);
|
||||||
while (current < order) {
|
while (current < order) {
|
||||||
register_free_block(reinterpret_cast<free_header*>(m_end), current);
|
register_free_block(reinterpret_cast<free_header*>(m_end), current);
|
||||||
m_end += 1 << current;
|
m_end += 1ull << current;
|
||||||
current = address_order(m_end);
|
current = address_order(m_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *block = reinterpret_cast<void*>(m_end);
|
void *block = reinterpret_cast<void*>(m_end);
|
||||||
m_end += 1 << order;
|
m_end += 1ull << order;
|
||||||
m_map[map_key(block)].order = order;
|
block_info &info = m_map[map_key(block)];
|
||||||
|
info.order = order;
|
||||||
|
info.free = false;
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,9 @@ public:
|
|||||||
/// allocation with the contents copied over.
|
/// allocation with the contents copied over.
|
||||||
void * reallocate(void *p, size_t old_length, size_t new_length);
|
void * reallocate(void *p, size_t old_length, size_t new_length);
|
||||||
|
|
||||||
/// Minimum block size is (2^min_order). Must be at least 6.
|
/// Minimum block size is (2^min_order). Must be at least 5 in
|
||||||
static const unsigned min_order = 6; // 2^6 == 64 B
|
/// order to hold a free_header.
|
||||||
|
static const unsigned min_order = 5; // 2^5 == 32 B
|
||||||
|
|
||||||
/// Maximum block size is (2^max_order). Must be less than 32 + min_order.
|
/// Maximum block size is (2^max_order). Must be less than 32 + min_order.
|
||||||
static const unsigned max_order = 22; // 2^22 == 4 MiB
|
static const unsigned max_order = 22; // 2^22 == 4 MiB
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "device_manager.h"
|
#include "device_manager.h"
|
||||||
#include "hpet.h"
|
#include "hpet.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include <string.h>
|
#include <j6/memutils.h>
|
||||||
|
|
||||||
#include <util/no_construct.h>
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
/// \file idt.h
|
/// \file idt.h
|
||||||
/// Definitions relating to a CPU's IDT table
|
/// Definitions relating to a CPU's IDT table
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
|
|
||||||
class IDT
|
class IDT
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <util/format.h>
|
#include <util/format.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "device_manager.h"
|
#include "device_manager.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
@@ -145,6 +145,30 @@ isr_handler(cpu_state *regs)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case isr::isrSIMDFPE: {
|
||||||
|
uint32_t mxcsr = 0;
|
||||||
|
asm volatile ("stmxcsr %0" : "=m"(mxcsr));
|
||||||
|
util::format({message, sizeof(message)},
|
||||||
|
"SIMD Exception; MXCSR[%s%s%s%s%s%s%s%s%s%s%s%s%s%s rc:%d]",
|
||||||
|
(mxcsr & 0x0001) ? " IE" : "",
|
||||||
|
(mxcsr & 0x0002) ? " DE" : "",
|
||||||
|
(mxcsr & 0x0004) ? " ZE" : "",
|
||||||
|
(mxcsr & 0x0008) ? " OE" : "",
|
||||||
|
(mxcsr & 0x0010) ? " UE" : "",
|
||||||
|
(mxcsr & 0x0020) ? " PE" : "",
|
||||||
|
(mxcsr & 0x0040) ? " DAZ" : "",
|
||||||
|
(mxcsr & 0x0080) ? " IM" : "",
|
||||||
|
(mxcsr & 0x0100) ? " DM" : "",
|
||||||
|
(mxcsr & 0x0200) ? " ZM" : "",
|
||||||
|
(mxcsr & 0x0400) ? " OM" : "",
|
||||||
|
(mxcsr & 0x0800) ? " UM" : "",
|
||||||
|
(mxcsr & 0x1000) ? " PM" : "",
|
||||||
|
(mxcsr & 0x8000) ? " FTZ" : "",
|
||||||
|
((mxcsr >> 13) & 0x3));
|
||||||
|
kassert(false, message, regs);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case isr::isrSpurious:
|
case isr::isrSpurious:
|
||||||
// No EOI for the spurious interrupt
|
// No EOI for the spurious interrupt
|
||||||
return;
|
return;
|
||||||
|
|||||||
49
src/kernel/ipc_message.cpp
Normal file
49
src/kernel/ipc_message.cpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#include <j6/memutils.h>
|
||||||
|
#include <util/basic_types.h>
|
||||||
|
|
||||||
|
#include "ipc_message.h"
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
|
||||||
|
message::message() : tag {0}, data {nullptr, 0}, handles {nullptr, 0} {}
|
||||||
|
|
||||||
|
message::message(
|
||||||
|
uint64_t in_tag,
|
||||||
|
const util::buffer &in_data,
|
||||||
|
const util::counted<j6_handle_t> &in_handles) :
|
||||||
|
tag {in_tag}, data {nullptr, in_data.count}, handles {nullptr, in_handles.count}
|
||||||
|
{
|
||||||
|
if (data.count) {
|
||||||
|
data.pointer = new uint8_t [data.count];
|
||||||
|
memcpy(data.pointer, in_data.pointer, data.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handles.count) {
|
||||||
|
handles.pointer = new j6_handle_t [handles.count];
|
||||||
|
memcpy(handles.pointer, in_handles.pointer, handles.count * sizeof(j6_handle_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message::message(message &&other) { *this = util::move(other); }
|
||||||
|
|
||||||
|
message::~message()
|
||||||
|
{
|
||||||
|
delete [] reinterpret_cast<uint8_t*>(data.pointer);
|
||||||
|
delete [] handles.pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
message &
|
||||||
|
message::operator=(message &&other)
|
||||||
|
{
|
||||||
|
tag = other.tag;
|
||||||
|
other.tag = 0;
|
||||||
|
|
||||||
|
data = other.data;
|
||||||
|
other.data = {nullptr, 0};
|
||||||
|
|
||||||
|
handles = other.handles;
|
||||||
|
other.handles = {nullptr, 0};
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ipc
|
||||||
25
src/kernel/ipc_message.h
Normal file
25
src/kernel/ipc_message.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file ipc_message.h
|
||||||
|
/// Definition of shared message structure
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <j6/types.h>
|
||||||
|
#include <util/counted.h>
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
|
||||||
|
struct message
|
||||||
|
{
|
||||||
|
uint64_t tag;
|
||||||
|
util::buffer data;
|
||||||
|
util::counted<j6_handle_t> handles;
|
||||||
|
|
||||||
|
message();
|
||||||
|
message(uint64_t in_tag, const util::buffer &in_data, const util::counted<j6_handle_t> &in_handles);
|
||||||
|
message(message &&other);
|
||||||
|
~message();
|
||||||
|
|
||||||
|
message & operator=(message &&other);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ipc
|
||||||
57
src/kernel/kassert.cpp
Normal file
57
src/kernel/kassert.cpp
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#include "kassert.h"
|
||||||
|
#include "idt.h"
|
||||||
|
|
||||||
|
namespace panic {
|
||||||
|
|
||||||
|
uint32_t *apic_icr = reinterpret_cast<uint32_t*>(0xffffc000fee00300);
|
||||||
|
void const *symbol_table = nullptr;
|
||||||
|
|
||||||
|
void
|
||||||
|
install(uintptr_t entrypoint, util::const_buffer symbol_data)
|
||||||
|
{
|
||||||
|
IDT::set_nmi_handler(entrypoint);
|
||||||
|
symbol_table = symbol_data.pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ noreturn ]]
|
||||||
|
void panic(
|
||||||
|
const char *message,
|
||||||
|
const cpu_state *user,
|
||||||
|
const char *function,
|
||||||
|
const char *file,
|
||||||
|
uint64_t line)
|
||||||
|
{
|
||||||
|
cpu_data &cpu = current_cpu();
|
||||||
|
|
||||||
|
// Grab the global panic block for ourselves
|
||||||
|
cpu.panic = __atomic_exchange_n(&g_panic_data_p, nullptr, __ATOMIC_ACQ_REL);
|
||||||
|
|
||||||
|
// If we aren't the first CPU to panic, cpu.panic will be null
|
||||||
|
if (cpu.panic) {
|
||||||
|
cpu.panic->symbol_data = symbol_table;
|
||||||
|
cpu.panic->user_state = user;
|
||||||
|
|
||||||
|
cpu.panic->message = message;
|
||||||
|
cpu.panic->function = function;
|
||||||
|
cpu.panic->file = file;
|
||||||
|
cpu.panic->line = line;
|
||||||
|
|
||||||
|
cpu.panic->cpus = g_num_cpus;
|
||||||
|
|
||||||
|
static constexpr uint32_t send_nmi_command =
|
||||||
|
(4 << 8) | // Delivery mode NMI
|
||||||
|
(1 << 14) | // assert level high
|
||||||
|
(2 << 18); // destination all
|
||||||
|
|
||||||
|
*apic_icr = send_nmi_command;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) asm ("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace panic
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
void __assert_fail(const char *message, const char *file, unsigned line, const char *function) {
|
||||||
|
panic::panic(message, nullptr, function, file, line);
|
||||||
|
}
|
||||||
@@ -7,45 +7,13 @@
|
|||||||
|
|
||||||
namespace panic {
|
namespace panic {
|
||||||
|
|
||||||
constexpr uint32_t send_nmi_command =
|
|
||||||
(4 << 8) | // Delivery mode NMI
|
|
||||||
(1 << 14) | // assert level high
|
|
||||||
(2 << 18); // destination all
|
|
||||||
|
|
||||||
extern uint32_t *apic_icr;
|
|
||||||
extern void const *symbol_table;
|
|
||||||
|
|
||||||
[[ noreturn ]]
|
[[ noreturn ]]
|
||||||
__attribute__ ((always_inline))
|
void panic(
|
||||||
inline void panic(
|
|
||||||
const char *message = nullptr,
|
const char *message = nullptr,
|
||||||
const cpu_state *user = nullptr,
|
const cpu_state *user = nullptr,
|
||||||
const char *function = __builtin_FUNCTION(),
|
const char *function = __builtin_FUNCTION(),
|
||||||
const char *file = __builtin_FILE(),
|
const char *file = __builtin_FILE(),
|
||||||
uint64_t line = __builtin_LINE())
|
uint64_t line = __builtin_LINE());
|
||||||
{
|
|
||||||
cpu_data &cpu = current_cpu();
|
|
||||||
|
|
||||||
// Grab the global panic block for ourselves
|
|
||||||
cpu.panic = __atomic_exchange_n(&g_panic_data_p, nullptr, __ATOMIC_ACQ_REL);
|
|
||||||
|
|
||||||
// If we aren't the first CPU to panic, cpu.panic will be null
|
|
||||||
if (cpu.panic) {
|
|
||||||
cpu.panic->symbol_data = symbol_table;
|
|
||||||
cpu.panic->user_state = user;
|
|
||||||
|
|
||||||
cpu.panic->message = message;
|
|
||||||
cpu.panic->function = function;
|
|
||||||
cpu.panic->file = file;
|
|
||||||
cpu.panic->line = line;
|
|
||||||
|
|
||||||
cpu.panic->cpus = g_num_cpus;
|
|
||||||
|
|
||||||
*apic_icr = send_nmi_command;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) asm ("hlt");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Install a panic handler.
|
/// Install a panic handler.
|
||||||
/// \arg entrypoint Virtual address of the panic handler's entrypoint
|
/// \arg entrypoint Virtual address of the panic handler's entrypoint
|
||||||
@@ -1,22 +1,22 @@
|
|||||||
# vim: ft=python
|
# vim: ft=python
|
||||||
|
|
||||||
kernel = module("kernel",
|
kernel = module("kernel",
|
||||||
kind = "exe",
|
|
||||||
default = True,
|
default = True,
|
||||||
output = "jsix.elf",
|
basename = "jsix",
|
||||||
targets = [ "kernel" ],
|
targets = [ "kernel" ],
|
||||||
description = "jsix kernel",
|
description = "jsix kernel",
|
||||||
deps = [ "util", "cpu", "bootproto", "j6" ],
|
deps = [ "util", "cpu", "bootproto", "j6" ],
|
||||||
|
static = True,
|
||||||
ld_script = "kernel.ld",
|
ld_script = "kernel.ld",
|
||||||
sources = [
|
sources = [
|
||||||
"apic.cpp",
|
"apic.cpp",
|
||||||
"assert.cpp",
|
"kassert.cpp",
|
||||||
"boot.s",
|
"boot.s",
|
||||||
"capabilities.cpp",
|
"capabilities.cpp",
|
||||||
"clock.cpp",
|
"clock.cpp",
|
||||||
"cpprt.cpp",
|
"cpprt.cpp",
|
||||||
"cpu.cpp",
|
"cpu.cpp",
|
||||||
"debug.s",
|
"cpu.s",
|
||||||
"device_manager.cpp",
|
"device_manager.cpp",
|
||||||
"frame_allocator.cpp",
|
"frame_allocator.cpp",
|
||||||
"gdt.cpp",
|
"gdt.cpp",
|
||||||
@@ -27,13 +27,13 @@ kernel = module("kernel",
|
|||||||
"interrupts.cpp",
|
"interrupts.cpp",
|
||||||
"interrupts.s",
|
"interrupts.s",
|
||||||
"io.cpp",
|
"io.cpp",
|
||||||
|
"ipc_message.cpp",
|
||||||
"kernel_main.cpp",
|
"kernel_main.cpp",
|
||||||
"logger.cpp",
|
"logger.cpp",
|
||||||
"memory.cpp",
|
"memory.cpp",
|
||||||
"memory.h.cog",
|
"memory.h.cog",
|
||||||
"memory_bootstrap.cpp",
|
"memory_bootstrap.cpp",
|
||||||
"msr.cpp",
|
"msr.cpp",
|
||||||
"objects/channel.cpp",
|
|
||||||
"objects/event.cpp",
|
"objects/event.cpp",
|
||||||
"objects/kobject.cpp",
|
"objects/kobject.cpp",
|
||||||
"objects/mailbox.cpp",
|
"objects/mailbox.cpp",
|
||||||
@@ -43,7 +43,6 @@ kernel = module("kernel",
|
|||||||
"objects/vm_area.cpp",
|
"objects/vm_area.cpp",
|
||||||
"page_table.cpp",
|
"page_table.cpp",
|
||||||
"page_tree.cpp",
|
"page_tree.cpp",
|
||||||
"pci.cpp",
|
|
||||||
"scheduler.cpp",
|
"scheduler.cpp",
|
||||||
"smp.cpp",
|
"smp.cpp",
|
||||||
"smp.s",
|
"smp.s",
|
||||||
@@ -52,12 +51,12 @@ kernel = module("kernel",
|
|||||||
"syscall.s",
|
"syscall.s",
|
||||||
"syscall_verify.cpp.cog",
|
"syscall_verify.cpp.cog",
|
||||||
"syscalls.inc.cog",
|
"syscalls.inc.cog",
|
||||||
"syscalls/channel.cpp",
|
|
||||||
"syscalls/event.cpp",
|
"syscalls/event.cpp",
|
||||||
"syscalls/handle.cpp",
|
"syscalls/handle.cpp",
|
||||||
"syscalls/mailbox.cpp",
|
"syscalls/mailbox.cpp",
|
||||||
"syscalls/object.cpp",
|
"syscalls/object.cpp",
|
||||||
"syscalls/process.cpp",
|
"syscalls/process.cpp",
|
||||||
|
"syscalls/futex.cpp",
|
||||||
"syscalls/system.cpp",
|
"syscalls/system.cpp",
|
||||||
"syscalls/thread.cpp",
|
"syscalls/thread.cpp",
|
||||||
"syscalls/vm_area.cpp",
|
"syscalls/vm_area.cpp",
|
||||||
@@ -67,8 +66,12 @@ kernel = module("kernel",
|
|||||||
"tss.cpp",
|
"tss.cpp",
|
||||||
"vm_space.cpp",
|
"vm_space.cpp",
|
||||||
"wait_queue.cpp",
|
"wait_queue.cpp",
|
||||||
|
"xsave.cpp",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
if config == "debug":
|
||||||
|
kernel.add_input("debugcon.cpp")
|
||||||
|
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from os.path import join
|
from os.path import join
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
#include <j6/memutils.h>
|
||||||
#include <bootproto/kernel.h>
|
#include <bootproto/kernel.h>
|
||||||
#include <util/vector.h>
|
#include <util/vector.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "capabilities.h"
|
#include "capabilities.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
#include "debugcon.h"
|
||||||
#include "device_manager.h"
|
#include "device_manager.h"
|
||||||
#include "interrupts.h"
|
#include "interrupts.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
@@ -36,9 +37,8 @@ kernel_main(bootproto::args *args)
|
|||||||
panic::install(args->panic_handler, args->symbol_table);
|
panic::install(args->panic_handler, args->symbol_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger_init();
|
|
||||||
|
|
||||||
cpu_data *cpu = bsp_early_init();
|
cpu_data *cpu = bsp_early_init();
|
||||||
|
mem::initialize(*args);
|
||||||
|
|
||||||
kassert(args->magic == bootproto::args_magic,
|
kassert(args->magic == bootproto::args_magic,
|
||||||
"Bad kernel args magic number");
|
"Bad kernel args magic number");
|
||||||
@@ -51,8 +51,6 @@ kernel_main(bootproto::args *args)
|
|||||||
|
|
||||||
disable_legacy_pic();
|
disable_legacy_pic();
|
||||||
|
|
||||||
mem::initialize(*args);
|
|
||||||
|
|
||||||
bsp_late_init();
|
bsp_late_init();
|
||||||
|
|
||||||
using bootproto::boot_flags;
|
using bootproto::boot_flags;
|
||||||
@@ -73,6 +71,10 @@ kernel_main(bootproto::args *args)
|
|||||||
scheduler *sched = new scheduler {g_num_cpus};
|
scheduler *sched = new scheduler {g_num_cpus};
|
||||||
smp::ready();
|
smp::ready();
|
||||||
|
|
||||||
|
// Initialize the debug console logger (does nothing if not built
|
||||||
|
// in debug mode)
|
||||||
|
debugcon::init_logger();
|
||||||
|
|
||||||
// Load the init server
|
// Load the init server
|
||||||
load_init_server(args->init, args->init_modules);
|
load_init_server(args->init, args->init_modules);
|
||||||
|
|
||||||
@@ -98,18 +100,12 @@ load_init_server(bootproto::program &program, uintptr_t modules_address)
|
|||||||
((sect.type && section_flags::write) ? vm_flags::write : vm_flags::none);
|
((sect.type && section_flags::write) ? vm_flags::write : vm_flags::none);
|
||||||
|
|
||||||
obj::vm_area *vma = new obj::vm_area_fixed(sect.phys_addr, sect.size, flags);
|
obj::vm_area *vma = new obj::vm_area_fixed(sect.phys_addr, sect.size, flags);
|
||||||
space.add(sect.virt_addr, vma);
|
space.add(sect.virt_addr, vma, obj::vm_flags::exact);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t iopl = (3ull << 12);
|
uint64_t iopl = (3ull << 12);
|
||||||
|
|
||||||
obj::thread *main = p->create_thread();
|
obj::thread *main = p->create_thread();
|
||||||
main->add_thunk_user(program.entrypoint, 0, iopl);
|
main->add_thunk_user(program.entrypoint, modules_address, 0, 0, iopl);
|
||||||
main->set_state(obj::thread::state::ready);
|
main->set_state(obj::thread::state::ready);
|
||||||
|
|
||||||
// Hacky: No process exists to have created a stack for init; it needs to create
|
|
||||||
// its own stack. We take advantage of that to use rsp to pass it the init modules
|
|
||||||
// address.
|
|
||||||
auto *tcb = main->tcb();
|
|
||||||
tcb->rsp3 = modules_address;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,12 @@
|
|||||||
#include <new>
|
#include <j6/memutils.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <util/format.h>
|
#include <util/format.h>
|
||||||
#include <util/no_construct.h>
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "memory.h"
|
|
||||||
#include "objects/system.h"
|
#include "objects/system.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
|
|
||||||
static constexpr bool j6_debugcon_enable = false;
|
|
||||||
static constexpr uint16_t j6_debugcon_port = 0x6600;
|
|
||||||
|
|
||||||
static uint8_t log_buffer[log::logger::log_pages * arch::frame_size];
|
|
||||||
|
|
||||||
// The logger is initialized _before_ global constructors are called,
|
// The logger is initialized _before_ global constructors are called,
|
||||||
// so that we can start log output immediately. Keep its constructor
|
// so that we can start log output immediately. Keep its constructor
|
||||||
// from being called here so as to not overwrite the previous initialization.
|
// from being called here so as to not overwrite the previous initialization.
|
||||||
@@ -24,38 +16,31 @@ log::logger &g_logger = __g_logger_storage.value;
|
|||||||
|
|
||||||
namespace log {
|
namespace log {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
} // anon namespace
|
||||||
|
|
||||||
logger *logger::s_log = nullptr;
|
logger *logger::s_log = nullptr;
|
||||||
const char *logger::s_level_names[] = {"", "fatal", "error", "warn", "info", "verbose", "spam"};
|
|
||||||
const char *logger::s_area_names[] = {
|
|
||||||
#define LOG(name, lvl) #name ,
|
|
||||||
#include <j6/tables/log_areas.inc>
|
|
||||||
#undef LOG
|
|
||||||
nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void
|
|
||||||
debug_out(const char *msg, size_t size)
|
|
||||||
{
|
|
||||||
asm ( "rep outsb;" :: "c"(size), "d"(j6_debugcon_port), "S"(msg) );
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
debug_newline()
|
|
||||||
{
|
|
||||||
static const char *newline = "\r\n";
|
|
||||||
asm ( "rep outsb;" :: "c"(2), "d"(j6_debugcon_port), "S"(newline) );
|
|
||||||
}
|
|
||||||
|
|
||||||
logger::logger() :
|
logger::logger() :
|
||||||
m_buffer(nullptr, 0)
|
m_buffer {nullptr, 0},
|
||||||
|
m_start {0},
|
||||||
|
m_end {0},
|
||||||
|
m_count {0}
|
||||||
{
|
{
|
||||||
memset(&m_levels, 0, sizeof(m_levels));
|
memset(&m_levels, 0, sizeof(m_levels));
|
||||||
s_log = this;
|
s_log = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger::logger(uint8_t *buffer, size_t size) :
|
logger::logger(util::buffer data) :
|
||||||
m_buffer(buffer, size)
|
m_buffer {data},
|
||||||
|
m_start {0},
|
||||||
|
m_end {0},
|
||||||
|
m_count {0}
|
||||||
{
|
{
|
||||||
|
kassert((data.count & (data.count - 1)) == 0,
|
||||||
|
"log buffer size must be a power of two");
|
||||||
|
|
||||||
memset(&m_levels, 0, sizeof(m_levels));
|
memset(&m_levels, 0, sizeof(m_levels));
|
||||||
s_log = this;
|
s_log = this;
|
||||||
|
|
||||||
@@ -68,71 +53,56 @@ logger::logger(uint8_t *buffer, size_t size) :
|
|||||||
void
|
void
|
||||||
logger::output(level severity, logs area, const char *fmt, va_list args)
|
logger::output(level severity, logs area, const char *fmt, va_list args)
|
||||||
{
|
{
|
||||||
char buffer[256];
|
static constexpr size_t buffer_len = 256;
|
||||||
|
static constexpr size_t message_len = buffer_len - sizeof(j6_log_entry);
|
||||||
|
|
||||||
if constexpr (j6_debugcon_enable) {
|
char buffer[buffer_len];
|
||||||
size_t dlen = util::format({buffer, sizeof(buffer)}, "%7s %7s| ",
|
j6_log_entry *header = reinterpret_cast<j6_log_entry *>(buffer);
|
||||||
s_area_names[static_cast<uint8_t>(area)],
|
|
||||||
s_level_names[static_cast<uint8_t>(severity)]);
|
|
||||||
debug_out(buffer, dlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
entry *header = reinterpret_cast<entry *>(buffer);
|
size_t size = sizeof(j6_log_entry);
|
||||||
header->bytes = sizeof(entry);
|
size += util::vformat({header->message, message_len}, fmt, args);
|
||||||
header->area = area;
|
|
||||||
header->severity = severity;
|
|
||||||
|
|
||||||
size_t mlen = util::vformat({header->message, sizeof(buffer) - sizeof(entry) - 1}, fmt, args);
|
|
||||||
header->message[mlen] = 0;
|
|
||||||
header->bytes += mlen + 1;
|
|
||||||
|
|
||||||
if constexpr (j6_debugcon_enable) {
|
|
||||||
debug_out(header->message, mlen);
|
|
||||||
debug_newline();
|
|
||||||
}
|
|
||||||
|
|
||||||
util::scoped_lock lock {m_lock};
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
uint8_t *out;
|
while (free() < size) {
|
||||||
size_t n = m_buffer.reserve(header->bytes, reinterpret_cast<void**>(&out));
|
// Remove old entries until there's enough space
|
||||||
if (n < header->bytes) {
|
const j6_log_entry *first = util::at<const j6_log_entry>(m_buffer, start());
|
||||||
m_buffer.commit(0); // Cannot write the message, give up
|
m_start += first->bytes;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(out, buffer, n);
|
header->id = ++m_count;
|
||||||
m_buffer.commit(n);
|
header->bytes = size;
|
||||||
|
header->severity = static_cast<uint8_t>(severity);
|
||||||
|
header->area = static_cast<uint8_t>(area);
|
||||||
|
|
||||||
m_event.signal(1);
|
memcpy(util::at<void>(m_buffer, end()), buffer, size);
|
||||||
|
m_end += size;
|
||||||
|
|
||||||
|
m_waiting.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
logger::get_entry(void *buffer, size_t size)
|
logger::get_entry(uint64_t seen, void *buffer, size_t size)
|
||||||
{
|
{
|
||||||
util::scoped_lock lock {m_lock};
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
void *out;
|
while (seen == m_count) {
|
||||||
size_t out_size = m_buffer.get_block(&out);
|
|
||||||
if (out_size == 0 || out == 0) {
|
|
||||||
lock.release();
|
lock.release();
|
||||||
m_event.wait();
|
m_waiting.wait();
|
||||||
lock.reacquire();
|
lock.reacquire();
|
||||||
out_size = m_buffer.get_block(&out);
|
|
||||||
|
|
||||||
if (out_size == 0 || out == 0)
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kassert(out_size >= sizeof(entry), "Couldn't read a full entry");
|
size_t off = m_start;
|
||||||
if (out_size < sizeof(entry))
|
j6_log_entry *ent = util::at<j6_log_entry>(m_buffer, offset(off));
|
||||||
return 0;
|
while (seen >= ent->id) {
|
||||||
|
off += ent->bytes;
|
||||||
entry *ent = reinterpret_cast<entry *>(out);
|
kassert(off < m_end, "Got to the end while looking for new log entry");
|
||||||
if (size >= ent->bytes) {
|
ent = util::at<j6_log_entry>(m_buffer, offset(off));
|
||||||
memcpy(buffer, out, ent->bytes);
|
|
||||||
m_buffer.consume(ent->bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (size >= ent->bytes)
|
||||||
|
memcpy(buffer, ent, ent->bytes);
|
||||||
|
|
||||||
return ent->bytes;
|
return ent->bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,9 +138,3 @@ void fatal(logs area, const char *fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace log
|
} // namespace log
|
||||||
|
|
||||||
|
|
||||||
void logger_init()
|
|
||||||
{
|
|
||||||
new (&g_logger) log::logger(log_buffer, sizeof(log_buffer));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <util/bip_buffer.h>
|
#include <util/counted.h>
|
||||||
#include <util/spinlock.h>
|
#include <util/spinlock.h>
|
||||||
|
|
||||||
#include "objects/event.h"
|
#include "objects/event.h"
|
||||||
@@ -19,6 +19,9 @@ enum class logs : uint8_t {
|
|||||||
|
|
||||||
namespace log {
|
namespace log {
|
||||||
|
|
||||||
|
/// Size of the log ring buffer. Must be a power of two.
|
||||||
|
inline constexpr unsigned log_pages = 16;
|
||||||
|
|
||||||
enum class level : uint8_t {
|
enum class level : uint8_t {
|
||||||
silent, fatal, error, warn, info, verbose, spam, max
|
silent, fatal, error, warn, info, verbose, spam, max
|
||||||
};
|
};
|
||||||
@@ -29,26 +32,16 @@ constexpr unsigned areas_count =
|
|||||||
class logger
|
class logger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Size of the log ring buffer
|
|
||||||
static constexpr unsigned log_pages = 16;
|
|
||||||
|
|
||||||
/// Default constructor. Creates a logger without a backing store.
|
/// Default constructor. Creates a logger without a backing store.
|
||||||
logger();
|
logger();
|
||||||
|
|
||||||
/// Constructor. Logs are written to the given buffer.
|
/// Constructor. Logs are written to the given buffer.
|
||||||
/// \arg buffer Buffer to which logs are written
|
/// \arg buffer Buffer to which logs are written
|
||||||
/// \arg size Size of `buffer`, in bytes
|
logger(util::buffer buffer);
|
||||||
logger(uint8_t *buffer, size_t size);
|
|
||||||
|
|
||||||
/// Get the default logger.
|
/// Get the default logger.
|
||||||
inline logger & get() { return *s_log; }
|
inline logger & get() { return *s_log; }
|
||||||
|
|
||||||
/// Get the registered name for a given area
|
|
||||||
inline const char * area_name(logs area) const { return s_area_names[static_cast<unsigned>(area)]; }
|
|
||||||
|
|
||||||
/// Get the name of a level
|
|
||||||
inline const char * level_name(level l) const { return s_level_names[static_cast<unsigned>(l)]; }
|
|
||||||
|
|
||||||
/// Write to the log
|
/// Write to the log
|
||||||
/// \arg severity The severity of the message
|
/// \arg severity The severity of the message
|
||||||
/// \arg area The log area to write to
|
/// \arg area The log area to write to
|
||||||
@@ -64,23 +57,18 @@ public:
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct entry
|
/// Get the next log entry from the buffer. Blocks the current thread until
|
||||||
{
|
/// a log arrives if there are no entries newer than `seen`.
|
||||||
uint8_t bytes;
|
/// \arg seen The id of the last-seen log entry, or 0 for none
|
||||||
logs area;
|
|
||||||
level severity;
|
|
||||||
char message[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Get the next log entry from the buffer
|
|
||||||
/// \arg buffer The buffer to copy the log message into
|
/// \arg buffer The buffer to copy the log message into
|
||||||
/// \arg size Size of the passed-in buffer, in bytes
|
/// \arg size Size of the passed-in buffer, in bytes
|
||||||
/// \returns The size of the log entry (if larger than the
|
/// \returns The size of the log entry (if larger than the
|
||||||
/// buffer, then no data was copied)
|
/// buffer, then no data was copied)
|
||||||
size_t get_entry(void *buffer, size_t size);
|
size_t get_entry(uint64_t seen, void *buffer, size_t size);
|
||||||
|
|
||||||
/// Get whether there is currently data in the log buffer
|
/// Check whether or not there's a new log entry to get
|
||||||
inline bool has_log() const { return m_buffer.size(); }
|
/// \arg seen The id of the last-seen log entry, or 0 for none
|
||||||
|
inline bool has_entry(uint64_t seen) { return seen < m_count; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend void spam (logs area, const char *fmt, ...);
|
friend void spam (logs area, const char *fmt, ...);
|
||||||
@@ -100,16 +88,22 @@ private:
|
|||||||
return m_levels[static_cast<unsigned>(area)];
|
return m_levels[static_cast<unsigned>(area)];
|
||||||
}
|
}
|
||||||
|
|
||||||
obj::event m_event;
|
inline size_t offset(size_t i) const { return i & (m_buffer.count - 1); }
|
||||||
|
|
||||||
|
inline size_t start() const { return offset(m_start); }
|
||||||
|
inline size_t end() const { return offset(m_end); }
|
||||||
|
inline size_t free() const { return m_buffer.count - (m_end - m_start); }
|
||||||
|
|
||||||
level m_levels[areas_count];
|
level m_levels[areas_count];
|
||||||
|
|
||||||
util::bip_buffer m_buffer;
|
util::buffer m_buffer;
|
||||||
|
size_t m_start, m_end;
|
||||||
|
uint64_t m_count;
|
||||||
|
|
||||||
|
wait_queue m_waiting;
|
||||||
util::spinlock m_lock;
|
util::spinlock m_lock;
|
||||||
|
|
||||||
static logger *s_log;
|
static logger *s_log;
|
||||||
static const char *s_area_names[areas_count+1];
|
|
||||||
static const char *s_level_names[static_cast<unsigned>(level::max)];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void spam (logs area, const char *fmt, ...);
|
void spam (logs area, const char *fmt, ...);
|
||||||
@@ -119,8 +113,6 @@ void warn (logs area, const char *fmt, ...);
|
|||||||
void error (logs area, const char *fmt, ...);
|
void error (logs area, const char *fmt, ...);
|
||||||
void fatal (logs area, const char *fmt, ...);
|
void fatal (logs area, const char *fmt, ...);
|
||||||
|
|
||||||
extern log::logger &g_logger;
|
|
||||||
|
|
||||||
} // namespace log
|
} // namespace log
|
||||||
|
|
||||||
void logger_init();
|
extern log::logger &g_logger;
|
||||||
|
|||||||
@@ -3,26 +3,3 @@
|
|||||||
namespace std {
|
namespace std {
|
||||||
enum class __attribute__ ((__type_visibility("default"))) align_val_t : size_t { };
|
enum class __attribute__ ((__type_visibility("default"))) align_val_t : size_t { };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation of memset and memcpy because we're not
|
|
||||||
// linking libc into the kernel
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
void *
|
|
||||||
memset(void *s, uint8_t v, size_t n)
|
|
||||||
{
|
|
||||||
uint8_t *p = reinterpret_cast<uint8_t *>(s);
|
|
||||||
for (size_t i = 0; i < n; ++i) p[i] = v;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
memcpy(void *dest, const void *src, size_t n)
|
|
||||||
{
|
|
||||||
const uint8_t *s = reinterpret_cast<const uint8_t *>(src);
|
|
||||||
uint8_t *d = reinterpret_cast<uint8_t *>(dest);
|
|
||||||
for (size_t i = 0; i < n; ++i) d[i] = s[i];
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -88,3 +88,6 @@ constexpr uintptr_t page_align_up(uintptr_t a) { return page_align_down(a-1) + f
|
|||||||
void initialize(bootproto::args &args);
|
void initialize(bootproto::args &args);
|
||||||
|
|
||||||
} // namespace mem
|
} // namespace mem
|
||||||
|
|
||||||
|
static constexpr bool __debug_heap_allocation = false;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
#include <new>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include <arch/memory.h>
|
#include <arch/memory.h>
|
||||||
#include <bootproto/kernel.h>
|
#include <bootproto/kernel.h>
|
||||||
#include <util/no_construct.h>
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "capabilities.h"
|
#include "capabilities.h"
|
||||||
#include "device_manager.h"
|
#include "device_manager.h"
|
||||||
#include "frame_allocator.h"
|
#include "frame_allocator.h"
|
||||||
@@ -40,6 +37,9 @@ frame_allocator &g_frame_allocator = __g_frame_allocator_storage.value;
|
|||||||
static util::no_construct<obj::vm_area_untracked> __g_kernel_heap_area_storage;
|
static util::no_construct<obj::vm_area_untracked> __g_kernel_heap_area_storage;
|
||||||
obj::vm_area_untracked &g_kernel_heap_area = __g_kernel_heap_area_storage.value;
|
obj::vm_area_untracked &g_kernel_heap_area = __g_kernel_heap_area_storage.value;
|
||||||
|
|
||||||
|
static util::no_construct<obj::vm_area_ring> __g_kernel_log_area_storage;
|
||||||
|
obj::vm_area_ring &g_kernel_log_area = __g_kernel_log_area_storage.value;
|
||||||
|
|
||||||
static util::no_construct<obj::vm_area_untracked> __g_kernel_heapmap_area_storage;
|
static util::no_construct<obj::vm_area_untracked> __g_kernel_heapmap_area_storage;
|
||||||
obj::vm_area_untracked &g_kernel_heapmap_area = __g_kernel_heapmap_area_storage.value;
|
obj::vm_area_untracked &g_kernel_heapmap_area = __g_kernel_heapmap_area_storage.value;
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
|
|||||||
|
|
||||||
page_table *kpml4 = static_cast<page_table*>(kargs.pml4);
|
page_table *kpml4 = static_cast<page_table*>(kargs.pml4);
|
||||||
|
|
||||||
|
// Initialize the frame allocator
|
||||||
frame_block *blocks = reinterpret_cast<frame_block*>(mem::bitmap_offset);
|
frame_block *blocks = reinterpret_cast<frame_block*>(mem::bitmap_offset);
|
||||||
new (&g_frame_allocator) frame_allocator {blocks, kargs.frame_blocks.count};
|
new (&g_frame_allocator) frame_allocator {blocks, kargs.frame_blocks.count};
|
||||||
|
|
||||||
@@ -91,25 +91,36 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
|
|||||||
reg = reg->next;
|
reg = reg->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the kernel "process" and vm_space
|
||||||
obj::process *kp = obj::process::create_kernel_process(kpml4);
|
obj::process *kp = obj::process::create_kernel_process(kpml4);
|
||||||
vm_space &vm = kp->space();
|
vm_space &vm = kp->space();
|
||||||
|
|
||||||
|
// Create the heap space and heap allocator
|
||||||
obj::vm_area *heap = new (&g_kernel_heap_area)
|
obj::vm_area *heap = new (&g_kernel_heap_area)
|
||||||
obj::vm_area_untracked(mem::heap_size, vm_flags::write);
|
obj::vm_area_untracked(mem::heap_size, vm_flags::write);
|
||||||
|
|
||||||
obj::vm_area *heap_map = new (&g_kernel_heapmap_area)
|
obj::vm_area *heap_map = new (&g_kernel_heapmap_area)
|
||||||
obj::vm_area_untracked(mem::heapmap_size, vm_flags::write);
|
obj::vm_area_untracked(mem::heapmap_size, vm_flags::write);
|
||||||
|
|
||||||
vm.add(mem::heap_offset, heap);
|
vm.add(mem::heap_offset, heap, vm_flags::exact);
|
||||||
vm.add(mem::heapmap_offset, heap_map);
|
vm.add(mem::heapmap_offset, heap_map, vm_flags::exact);
|
||||||
|
|
||||||
new (&g_kernel_heap) heap_allocator {mem::heap_offset, mem::heap_size, mem::heapmap_offset};
|
new (&g_kernel_heap) heap_allocator {mem::heap_offset, mem::heap_size, mem::heapmap_offset};
|
||||||
|
|
||||||
|
// Set up the log area and logger
|
||||||
|
size_t log_buffer_size = log::log_pages * arch::frame_size;
|
||||||
|
obj::vm_area *logs = new (&g_kernel_log_area)
|
||||||
|
obj::vm_area_ring(log_buffer_size, vm_flags::write);
|
||||||
|
vm.add(mem::logs_offset, logs, vm_flags::exact);
|
||||||
|
|
||||||
|
new (&g_logger) log::logger(
|
||||||
|
util::buffer::from(mem::logs_offset, log_buffer_size));
|
||||||
|
|
||||||
|
// Set up the capability tables
|
||||||
obj::vm_area *caps = new (&g_cap_table_area)
|
obj::vm_area *caps = new (&g_cap_table_area)
|
||||||
obj::vm_area_untracked(mem::caps_size, vm_flags::write);
|
obj::vm_area_untracked(mem::caps_size, vm_flags::write);
|
||||||
|
|
||||||
vm.add(mem::caps_offset, caps);
|
vm.add(mem::caps_offset, caps, vm_flags::exact);
|
||||||
|
|
||||||
new (&g_cap_table) cap_table {mem::caps_offset};
|
new (&g_cap_table) cap_table {mem::caps_offset};
|
||||||
|
|
||||||
@@ -118,7 +129,7 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
|
|||||||
mem::kernel_stack_pages,
|
mem::kernel_stack_pages,
|
||||||
mem::stacks_size,
|
mem::stacks_size,
|
||||||
vm_flags::write};
|
vm_flags::write};
|
||||||
vm.add(mem::stacks_offset, &g_kernel_stacks);
|
vm.add(mem::stacks_offset, &g_kernel_stacks, vm_flags::exact);
|
||||||
|
|
||||||
// Clean out any remaning bootloader page table entries
|
// Clean out any remaning bootloader page table entries
|
||||||
for (unsigned i = 0; i < arch::kernel_root_index; ++i)
|
for (unsigned i = 0; i < arch::kernel_root_index; ++i)
|
||||||
@@ -129,7 +140,7 @@ void
|
|||||||
memory_initialize_post_ctors(bootproto::args &kargs)
|
memory_initialize_post_ctors(bootproto::args &kargs)
|
||||||
{
|
{
|
||||||
vm_space &vm = vm_space::kernel_space();
|
vm_space &vm = vm_space::kernel_space();
|
||||||
vm.add(mem::buffers_offset, &g_kernel_buffers);
|
vm.add(mem::buffers_offset, &g_kernel_buffers, vm_flags::exact);
|
||||||
|
|
||||||
g_frame_allocator.free(
|
g_frame_allocator.free(
|
||||||
get_physical_page(kargs.page_tables.pointer),
|
get_physical_page(kargs.page_tables.pointer),
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "assert.h"
|
|
||||||
#include "memory.h"
|
|
||||||
#include "objects/channel.h"
|
|
||||||
#include "objects/thread.h"
|
|
||||||
#include "objects/vm_area.h"
|
|
||||||
|
|
||||||
extern obj::vm_area_guarded g_kernel_buffers;
|
|
||||||
|
|
||||||
namespace obj {
|
|
||||||
|
|
||||||
constexpr size_t buffer_bytes = mem::kernel_buffer_pages * mem::frame_size;
|
|
||||||
|
|
||||||
channel::channel() :
|
|
||||||
m_len {0},
|
|
||||||
m_data {g_kernel_buffers.get_section()},
|
|
||||||
m_closed {false},
|
|
||||||
m_buffer {reinterpret_cast<uint8_t*>(m_data), buffer_bytes},
|
|
||||||
kobject {kobject::type::channel}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
channel::~channel()
|
|
||||||
{
|
|
||||||
if (!closed()) close();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
channel::enqueue(const util::buffer &data)
|
|
||||||
{
|
|
||||||
util::scoped_lock lock {m_close_lock};
|
|
||||||
|
|
||||||
if (closed()) return 0;
|
|
||||||
|
|
||||||
size_t len = data.count;
|
|
||||||
void *buffer = nullptr;
|
|
||||||
len = m_buffer.reserve(len, &buffer);
|
|
||||||
|
|
||||||
memcpy(buffer, data.pointer, len);
|
|
||||||
m_buffer.commit(len);
|
|
||||||
|
|
||||||
if (len) {
|
|
||||||
thread *t = m_queue.pop_next();
|
|
||||||
|
|
||||||
lock.release();
|
|
||||||
if (t) t->wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
channel::dequeue(util::buffer buffer, bool block)
|
|
||||||
{
|
|
||||||
util::scoped_lock lock {m_close_lock};
|
|
||||||
|
|
||||||
if (closed()) return 0;
|
|
||||||
|
|
||||||
void *data = nullptr;
|
|
||||||
size_t avail = m_buffer.get_block(&data);
|
|
||||||
if (!avail && block) {
|
|
||||||
thread &cur = thread::current();
|
|
||||||
m_queue.add_thread(&cur);
|
|
||||||
|
|
||||||
lock.release();
|
|
||||||
cur.block();
|
|
||||||
lock.reacquire();
|
|
||||||
avail = m_buffer.get_block(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len = buffer.count > avail ? avail : buffer.count;
|
|
||||||
|
|
||||||
memcpy(buffer.pointer, data, len);
|
|
||||||
m_buffer.consume(len);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
channel::close()
|
|
||||||
{
|
|
||||||
util::scoped_lock lock {m_close_lock};
|
|
||||||
m_queue.clear();
|
|
||||||
g_kernel_buffers.return_section(m_data);
|
|
||||||
m_closed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace obj
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
/// \file channel.h
|
|
||||||
/// Definition of channel objects and related functions
|
|
||||||
|
|
||||||
#include <j6/cap_flags.h>
|
|
||||||
#include <util/bip_buffer.h>
|
|
||||||
#include <util/counted.h>
|
|
||||||
#include <util/spinlock.h>
|
|
||||||
|
|
||||||
#include "objects/kobject.h"
|
|
||||||
#include "wait_queue.h"
|
|
||||||
|
|
||||||
namespace obj {
|
|
||||||
|
|
||||||
/// Channels are uni-directional means of sending data
|
|
||||||
class channel :
|
|
||||||
public kobject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// Capabilities on a newly constructed channel handle
|
|
||||||
static constexpr j6_cap_t creation_caps = j6_cap_channel_all;
|
|
||||||
static constexpr kobject::type type = kobject::type::channel;
|
|
||||||
|
|
||||||
channel();
|
|
||||||
virtual ~channel();
|
|
||||||
|
|
||||||
/// Put a message into the channel
|
|
||||||
/// \arg data Buffer of data to write
|
|
||||||
/// \returns The number of bytes successfully written
|
|
||||||
size_t enqueue(const util::buffer &data);
|
|
||||||
|
|
||||||
/// Get a message from the channel, copied into a provided buffer
|
|
||||||
/// \arg buffer The buffer to copy data into
|
|
||||||
/// \arg block If true, block the calling thread until there is data
|
|
||||||
/// \returns The number of bytes copied into the provided buffer
|
|
||||||
size_t dequeue(util::buffer buffer, bool block = false);
|
|
||||||
|
|
||||||
/// Mark this channel as closed, all future calls to enqueue or
|
|
||||||
/// dequeue messages will fail with j6_status_closed.
|
|
||||||
void close();
|
|
||||||
|
|
||||||
/// Check if this channel has been closed.
|
|
||||||
inline bool closed() const { return m_closed; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t m_len;
|
|
||||||
uintptr_t m_data;
|
|
||||||
bool m_closed;
|
|
||||||
util::bip_buffer m_buffer;
|
|
||||||
util::spinlock m_close_lock;
|
|
||||||
wait_queue m_queue;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace obj
|
|
||||||
@@ -28,22 +28,15 @@ event::wait()
|
|||||||
// Wait for event::signal() to wake us with a value
|
// Wait for event::signal() to wake us with a value
|
||||||
thread ¤t = thread::current();
|
thread ¤t = thread::current();
|
||||||
m_queue.add_thread(¤t);
|
m_queue.add_thread(¤t);
|
||||||
return current.block();
|
current.block();
|
||||||
|
return read();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
event::wake_observer()
|
event::wake_observer()
|
||||||
{
|
{
|
||||||
util::scoped_lock lock {m_queue.get_lock()};
|
thread *t = m_queue.pop_next();
|
||||||
thread *t = m_queue.get_next_unlocked();
|
if (t) t->wake();
|
||||||
if (!t) return;
|
|
||||||
|
|
||||||
uint64_t value = read();
|
|
||||||
if (value) {
|
|
||||||
m_queue.pop_next_unlocked();
|
|
||||||
lock.release();
|
|
||||||
t->wake(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace obj
|
} // namespace obj
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#include <j6/errors.h>
|
#include <j6/errors.h>
|
||||||
#include <j6/types.h>
|
#include <j6/types.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
|
#include "logger.h"
|
||||||
#include "objects/kobject.h"
|
#include "objects/kobject.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
|
|
||||||
@@ -14,6 +15,13 @@ static uint32_t next_oids [types_count] = { 0 };
|
|||||||
static_assert(types_count <= (1 << kobject::koid_type_bits),
|
static_assert(types_count <= (1 << kobject::koid_type_bits),
|
||||||
"kobject::koid_type_bits cannot represent all kobject types");
|
"kobject::koid_type_bits cannot represent all kobject types");
|
||||||
|
|
||||||
|
static const char *type_names[] = {
|
||||||
|
#define OBJECT_TYPE( name ) #name ,
|
||||||
|
#include <j6/tables/object_types.inc>
|
||||||
|
#undef OBJECT_TYPE
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
|
||||||
static uint32_t
|
static uint32_t
|
||||||
oid_generate(kobject::type t)
|
oid_generate(kobject::type t)
|
||||||
{
|
{
|
||||||
@@ -26,13 +34,25 @@ kobject::kobject(type t) :
|
|||||||
m_handle_count {0},
|
m_handle_count {0},
|
||||||
m_type {t},
|
m_type {t},
|
||||||
m_obj_id {oid_generate(t)}
|
m_obj_id {oid_generate(t)}
|
||||||
{}
|
{
|
||||||
|
log::spam(logs::objs, "%s[%02lx] created @ 0x%lx", type_name(m_type), m_obj_id, this);
|
||||||
|
}
|
||||||
|
|
||||||
kobject::~kobject() {}
|
kobject::~kobject()
|
||||||
|
{
|
||||||
|
log::spam(logs::objs, "%s[%02lx] deleted", type_name(m_type), m_obj_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
kobject::type_name(type t)
|
||||||
|
{
|
||||||
|
return type_names[static_cast<int>(t)];
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kobject::on_no_handles()
|
kobject::on_no_handles()
|
||||||
{
|
{
|
||||||
|
log::verbose(logs::objs, "Deleting %s[%02lx] on no handles", type_name(m_type), m_obj_id);
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public:
|
|||||||
/// Types of kernel objects.
|
/// Types of kernel objects.
|
||||||
enum class type : uint8_t
|
enum class type : uint8_t
|
||||||
{
|
{
|
||||||
#define OBJECT_TYPE( name, val ) name = val,
|
#define OBJECT_TYPE( name ) name ,
|
||||||
#include <j6/tables/object_types.inc>
|
#include <j6/tables/object_types.inc>
|
||||||
#undef OBJECT_TYPE
|
#undef OBJECT_TYPE
|
||||||
|
|
||||||
@@ -38,6 +38,8 @@ public:
|
|||||||
return static_cast<type>((koid >> koid_type_shift) & koid_type_mask);
|
return static_cast<type>((koid >> koid_type_shift) & koid_type_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char * type_name(type t);
|
||||||
|
|
||||||
/// Get this object's type
|
/// Get this object's type
|
||||||
inline type get_type() const { return m_type; }
|
inline type get_type() const { return m_type; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
#include <util/basic_types.h>
|
||||||
#include <util/counted.h>
|
#include <util/counted.h>
|
||||||
|
#include <j6/memutils.h>
|
||||||
|
|
||||||
#include "objects/mailbox.h"
|
#include "objects/mailbox.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
@@ -26,6 +28,10 @@ mailbox::close()
|
|||||||
|
|
||||||
m_callers.clear(j6_status_closed);
|
m_callers.clear(j6_status_closed);
|
||||||
m_responders.clear(j6_status_closed);
|
m_responders.clear(j6_status_closed);
|
||||||
|
|
||||||
|
util::scoped_lock lock {m_reply_lock};
|
||||||
|
for (auto &waiting : m_reply_map)
|
||||||
|
waiting.thread->wake(j6_status_closed);
|
||||||
}
|
}
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
@@ -45,7 +51,7 @@ mailbox::call()
|
|||||||
}
|
}
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
mailbox::receive(thread::message_data &data, reply_tag_t &reply_tag, bool block)
|
mailbox::receive(ipc::message &data, reply_tag_t &reply_tag, bool block)
|
||||||
{
|
{
|
||||||
if (closed())
|
if (closed())
|
||||||
return j6_status_closed;
|
return j6_status_closed;
|
||||||
@@ -77,7 +83,7 @@ mailbox::receive(thread::message_data &data, reply_tag_t &reply_tag, bool block)
|
|||||||
}
|
}
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
mailbox::reply(reply_tag_t reply_tag, const thread::message_data &data)
|
mailbox::reply(reply_tag_t reply_tag, ipc::message &&data)
|
||||||
{
|
{
|
||||||
if (closed())
|
if (closed())
|
||||||
return j6_status_closed;
|
return j6_status_closed;
|
||||||
@@ -91,7 +97,7 @@ mailbox::reply(reply_tag_t reply_tag, const thread::message_data &data)
|
|||||||
m_reply_map.erase(reply_tag);
|
m_reply_map.erase(reply_tag);
|
||||||
lock.release();
|
lock.release();
|
||||||
|
|
||||||
caller->get_message_data() = data;
|
caller->set_message_data(util::move(data));
|
||||||
caller->wake(j6_status_ok);
|
caller->wake(j6_status_ok);
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,9 @@
|
|||||||
#include <util/spinlock.h>
|
#include <util/spinlock.h>
|
||||||
|
|
||||||
#include "heap_allocator.h"
|
#include "heap_allocator.h"
|
||||||
|
#include "ipc_message.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "objects/kobject.h"
|
#include "objects/kobject.h"
|
||||||
#include "objects/thread.h"
|
|
||||||
#include "slab_allocated.h"
|
|
||||||
#include "wait_queue.h"
|
#include "wait_queue.h"
|
||||||
|
|
||||||
namespace obj {
|
namespace obj {
|
||||||
@@ -23,6 +22,7 @@ class mailbox :
|
|||||||
public kobject
|
public kobject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using reply_tag_t = uint64_t;
|
using reply_tag_t = uint64_t;
|
||||||
|
|
||||||
/// Capabilities on a newly constructed mailbox handle
|
/// Capabilities on a newly constructed mailbox handle
|
||||||
@@ -43,23 +43,23 @@ public:
|
|||||||
|
|
||||||
/// Send a message to a thread waiting to receive on this mailbox, and block the
|
/// Send a message to a thread waiting to receive on this mailbox, and block the
|
||||||
/// current thread awaiting a response. The message contents should be in the calling
|
/// current thread awaiting a response. The message contents should be in the calling
|
||||||
/// thread's message_data.
|
/// thread's message data.
|
||||||
/// \returns j6_status_ok if a reply was received
|
/// \returns j6_status_ok if a reply was received
|
||||||
j6_status_t call();
|
j6_status_t call();
|
||||||
|
|
||||||
/// Receive the next available message, optionally blocking if no messages are available.
|
/// Receive the next available message, optionally blocking if no messages are available.
|
||||||
/// \arg data [out] a thread::message_data structure to fill
|
/// \arg data [out] an ipc::message structure to fill
|
||||||
/// \arg reply_tag [out] the reply_tag to use when replying to this message
|
/// \arg reply_tag [out] the reply_tag to use when replying to this message
|
||||||
/// \arg block True if this call should block when no messages are available.
|
/// \arg block True if this call should block when no messages are available.
|
||||||
/// \returns j6_status_ok if a message was received
|
/// \returns j6_status_ok if a message was received
|
||||||
j6_status_t receive(thread::message_data &data, reply_tag_t &reply_tag, bool block);
|
j6_status_t receive(ipc::message &data, reply_tag_t &reply_tag, bool block);
|
||||||
|
|
||||||
/// Find a given pending message to be responded to. Returns a replyer object, which will
|
/// Find a given pending message to be responded to. Returns a replyer object, which will
|
||||||
/// wake the calling thread upon destruction.
|
/// wake the calling read upon destruction.
|
||||||
/// \arg reply_tag The reply tag in the original message
|
/// \arg reply_tag The reply tag in the original message
|
||||||
/// \arg data Message data to pass on to the caller
|
/// \arg data Message data to pass on to the caller
|
||||||
/// \returns j6_status_ok if the reply was successfully sent
|
/// \returns j6_status_ok if the reply was successfully sent
|
||||||
j6_status_t reply(reply_tag_t reply_tag, const thread::message_data &data);
|
j6_status_t reply(reply_tag_t reply_tag, ipc::message &&data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wait_queue m_callers;
|
wait_queue m_callers;
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#include <new>
|
|
||||||
|
|
||||||
#include <util/no_construct.h>
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "capabilities.h"
|
#include "capabilities.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "objects/process.h"
|
#include "objects/process.h"
|
||||||
@@ -24,8 +22,6 @@ process::process() :
|
|||||||
kobject {kobject::type::process},
|
kobject {kobject::type::process},
|
||||||
m_state {state::running}
|
m_state {state::running}
|
||||||
{
|
{
|
||||||
m_self_handle = g_cap_table.create(this, process::self_caps);
|
|
||||||
add_handle(m_self_handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The "kernel process"-only constructor
|
// The "kernel process"-only constructor
|
||||||
@@ -52,75 +48,80 @@ process::create_kernel_process(page_table *pml4)
|
|||||||
void
|
void
|
||||||
process::exit(int32_t code)
|
process::exit(int32_t code)
|
||||||
{
|
{
|
||||||
// TODO: make this thread-safe
|
if (m_state == state::exited)
|
||||||
|
return;
|
||||||
|
|
||||||
m_state = state::exited;
|
m_state = state::exited;
|
||||||
m_return_code = code;
|
m_return_code = code;
|
||||||
|
|
||||||
|
thread ¤t = thread::current();
|
||||||
|
|
||||||
|
util::scoped_lock lock {m_threads_lock};
|
||||||
for (auto *thread : m_threads) {
|
for (auto *thread : m_threads) {
|
||||||
thread->exit();
|
if (thread != ¤t) {
|
||||||
}
|
thread->exit();
|
||||||
|
|
||||||
if (this == current_cpu().process)
|
|
||||||
scheduler::get().schedule();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
process::update()
|
|
||||||
{
|
|
||||||
kassert(m_threads.count() > 0, "process::update with zero threads!");
|
|
||||||
|
|
||||||
size_t i = 0;
|
|
||||||
while (i < m_threads.count()) {
|
|
||||||
thread *th = m_threads[i];
|
|
||||||
if (th->has_state(thread::state::exited)) {
|
|
||||||
m_threads.remove_swap_at(i);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_threads.count() == 0)
|
lock.release();
|
||||||
exit(-1);
|
if (¤t.parent() == this)
|
||||||
|
current.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
thread *
|
thread *
|
||||||
process::create_thread(uintptr_t rsp3, uint8_t priority)
|
process::create_thread(uintptr_t rsp3, uint8_t priority)
|
||||||
{
|
{
|
||||||
|
util::scoped_lock lock {m_threads_lock};
|
||||||
|
|
||||||
|
if (m_state == state::exited)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
if (priority == default_priority)
|
if (priority == default_priority)
|
||||||
priority = scheduler::default_priority;
|
priority = scheduler::default_priority;
|
||||||
|
|
||||||
thread *th = new thread(*this, priority);
|
thread *th = new thread(*this, priority);
|
||||||
kassert(th, "Failed to create thread!");
|
kassert(th, "Failed to create thread!");
|
||||||
|
th->handle_retain();
|
||||||
|
|
||||||
if (rsp3)
|
if (rsp3)
|
||||||
th->tcb()->rsp3 = rsp3;
|
th->tcb()->rsp3 = rsp3;
|
||||||
|
|
||||||
|
if (this != &g_kernel_process)
|
||||||
|
th->init_xsave_area();
|
||||||
|
|
||||||
m_threads.append(th);
|
m_threads.append(th);
|
||||||
scheduler::get().add_thread(th->tcb());
|
scheduler::get().add_thread(th->tcb());
|
||||||
return th;
|
return th;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
process::thread_exited(thread *th)
|
process::thread_exited(thread *th)
|
||||||
{
|
{
|
||||||
kassert(&th->m_parent == this, "Process got thread_exited for non-child!");
|
kassert(&th->m_parent == this, "Process got thread_exited for non-child!");
|
||||||
m_threads.remove_swap(th);
|
|
||||||
remove_handle(th->self_handle());
|
|
||||||
delete th;
|
|
||||||
|
|
||||||
// TODO: delete the thread's stack VMA
|
if (m_state != state::exited) {
|
||||||
|
// if we're already going away, just release
|
||||||
|
// the thread's handle and skip all this
|
||||||
|
util::scoped_lock lock {m_threads_lock};
|
||||||
|
m_threads.remove_swap(th);
|
||||||
|
|
||||||
if (m_threads.count() == 0) {
|
// TODO: delete the thread's stack VMA
|
||||||
exit(-1);
|
if (m_threads.empty()) {
|
||||||
return true;
|
lock.release();
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
th->handle_release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
process::add_handle(j6_handle_t handle)
|
process::add_handle(j6_handle_t handle)
|
||||||
{
|
{
|
||||||
|
// Passing the invalid handle is fine, just don't add anything
|
||||||
|
if (handle == j6_handle_invalid)
|
||||||
|
return;
|
||||||
|
|
||||||
capability *c = g_cap_table.retain(handle);
|
capability *c = g_cap_table.retain(handle);
|
||||||
kassert(c, "Trying to add a non-existant handle to a process!");
|
kassert(c, "Trying to add a non-existant handle to a process!");
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,6 @@ public:
|
|||||||
/// Capabilities on a newly constructed process handle
|
/// Capabilities on a newly constructed process handle
|
||||||
static constexpr j6_cap_t creation_caps = j6_cap_process_all;
|
static constexpr j6_cap_t creation_caps = j6_cap_process_all;
|
||||||
|
|
||||||
/// Capabilities on a process to itself
|
|
||||||
static constexpr j6_cap_t self_caps = j6_cap_process_all;
|
|
||||||
|
|
||||||
/// Top of memory area where thread stacks are allocated
|
/// Top of memory area where thread stacks are allocated
|
||||||
static constexpr uintptr_t stacks_top = 0x0000800000000000;
|
static constexpr uintptr_t stacks_top = 0x0000800000000000;
|
||||||
|
|
||||||
@@ -47,9 +44,6 @@ public:
|
|||||||
/// \arg code The return code to exit with.
|
/// \arg code The return code to exit with.
|
||||||
void exit(int32_t code);
|
void exit(int32_t code);
|
||||||
|
|
||||||
/// Update internal bookkeeping about threads.
|
|
||||||
void update();
|
|
||||||
|
|
||||||
/// Get the process' virtual memory space
|
/// Get the process' virtual memory space
|
||||||
vm_space & space() { return m_space; }
|
vm_space & space() { return m_space; }
|
||||||
|
|
||||||
@@ -81,11 +75,7 @@ public:
|
|||||||
|
|
||||||
/// Inform the process of an exited thread
|
/// Inform the process of an exited thread
|
||||||
/// \args th The thread which has exited
|
/// \args th The thread which has exited
|
||||||
/// \returns True if this thread ending has ended the process
|
void thread_exited(thread *th);
|
||||||
bool thread_exited(thread *th);
|
|
||||||
|
|
||||||
/// Get the handle for this process to refer to itself
|
|
||||||
inline j6_handle_t self_handle() const { return m_self_handle; }
|
|
||||||
|
|
||||||
/// Get the process object that owns kernel threads and the
|
/// Get the process object that owns kernel threads and the
|
||||||
/// kernel address space
|
/// kernel address space
|
||||||
@@ -105,12 +95,12 @@ private:
|
|||||||
// This constructor is called by create_kernel_process
|
// This constructor is called by create_kernel_process
|
||||||
process(page_table *kpml4);
|
process(page_table *kpml4);
|
||||||
|
|
||||||
j6_handle_t m_self_handle;
|
|
||||||
int32_t m_return_code;
|
int32_t m_return_code;
|
||||||
|
|
||||||
vm_space m_space;
|
vm_space m_space;
|
||||||
|
|
||||||
util::vector<thread*> m_threads;
|
util::vector<thread*> m_threads;
|
||||||
|
util::spinlock m_threads_lock;
|
||||||
|
|
||||||
util::node_set<j6_handle_t, j6_handle_invalid, heap_allocated> m_handles;
|
util::node_set<j6_handle_t, j6_handle_invalid, heap_allocated> m_handles;
|
||||||
util::spinlock m_handles_lock;
|
util::spinlock m_handles_lock;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
#include <util/basic_types.h>
|
||||||
#include <util/pointers.h>
|
#include <util/pointers.h>
|
||||||
|
|
||||||
|
#include "kassert.h"
|
||||||
#include "capabilities.h"
|
#include "capabilities.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
@@ -8,8 +10,9 @@
|
|||||||
#include "objects/process.h"
|
#include "objects/process.h"
|
||||||
#include "objects/vm_area.h"
|
#include "objects/vm_area.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
|
#include "xsave.h"
|
||||||
|
|
||||||
extern "C" void kernel_to_user_trampoline();
|
extern "C" void initialize_user_cpu();
|
||||||
extern obj::vm_area_guarded &g_kernel_stacks;
|
extern obj::vm_area_guarded &g_kernel_stacks;
|
||||||
|
|
||||||
|
|
||||||
@@ -22,6 +25,7 @@ thread::thread(process &parent, uint8_t pri, uintptr_t rsp0) :
|
|||||||
m_wake_value {0},
|
m_wake_value {0},
|
||||||
m_wake_timeout {0}
|
m_wake_timeout {0}
|
||||||
{
|
{
|
||||||
|
parent.handle_retain();
|
||||||
parent.space().initialize_tcb(m_tcb);
|
parent.space().initialize_tcb(m_tcb);
|
||||||
m_tcb.priority = pri;
|
m_tcb.priority = pri;
|
||||||
m_tcb.thread = this;
|
m_tcb.thread = this;
|
||||||
@@ -32,13 +36,24 @@ thread::thread(process &parent, uint8_t pri, uintptr_t rsp0) :
|
|||||||
m_tcb.rsp0 = rsp0;
|
m_tcb.rsp0 = rsp0;
|
||||||
|
|
||||||
m_creator = current_cpu().thread;
|
m_creator = current_cpu().thread;
|
||||||
m_self_handle = g_cap_table.create(this, thread::parent_caps);
|
|
||||||
parent.add_handle(m_self_handle);
|
asm volatile ( "stmxcsr %0" : "=m"(m_mxcsr) );
|
||||||
|
m_mxcsr
|
||||||
|
.clear(mxcsr::IE)
|
||||||
|
.clear(mxcsr::DE)
|
||||||
|
.clear(mxcsr::ZE)
|
||||||
|
.clear(mxcsr::OE)
|
||||||
|
.clear(mxcsr::UE)
|
||||||
|
.clear(mxcsr::PE);
|
||||||
}
|
}
|
||||||
|
|
||||||
thread::~thread()
|
thread::~thread()
|
||||||
{
|
{
|
||||||
|
if (m_tcb.xsave)
|
||||||
|
delete [] reinterpret_cast<uint8_t*>(m_tcb.xsave);
|
||||||
|
|
||||||
g_kernel_stacks.return_section(m_tcb.kernel_stack);
|
g_kernel_stacks.return_section(m_tcb.kernel_stack);
|
||||||
|
m_parent.handle_release();
|
||||||
}
|
}
|
||||||
|
|
||||||
thread & thread::current() { return *current_cpu().thread; }
|
thread & thread::current() { return *current_cpu().thread; }
|
||||||
@@ -52,6 +67,18 @@ thread::block()
|
|||||||
return m_wake_value;
|
return m_wake_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
thread::block(util::scoped_lock &lock)
|
||||||
|
{
|
||||||
|
kassert(current_cpu().thread == this,
|
||||||
|
"unlocking block() called on non-current thread");
|
||||||
|
|
||||||
|
clear_state(state::ready);
|
||||||
|
lock.release();
|
||||||
|
scheduler::get().schedule();
|
||||||
|
return m_wake_value;
|
||||||
|
}
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
thread::join()
|
thread::join()
|
||||||
{
|
{
|
||||||
@@ -84,11 +111,15 @@ thread::wake_only()
|
|||||||
set_state(state::ready);
|
set_state(state::ready);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void thread::set_message_data(ipc::message &&md) { m_message = util::move(md); }
|
||||||
|
ipc::message && thread::get_message_data() { return util::move(m_message); }
|
||||||
|
|
||||||
void
|
void
|
||||||
thread::exit()
|
thread::exit()
|
||||||
{
|
{
|
||||||
m_wake_timeout = 0;
|
m_wake_timeout = 0;
|
||||||
set_state(state::exited);
|
set_state(state::exited);
|
||||||
|
m_parent.thread_exited(this);
|
||||||
m_join_queue.clear();
|
m_join_queue.clear();
|
||||||
block();
|
block();
|
||||||
}
|
}
|
||||||
@@ -113,7 +144,7 @@ thread::add_thunk_kernel(uintptr_t rip)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
thread::add_thunk_user(uintptr_t rip3, uintptr_t rip0, uint64_t flags)
|
thread::add_thunk_user(uintptr_t rip3, uint64_t arg0, uint64_t arg1, uintptr_t rip0, uint64_t flags)
|
||||||
{
|
{
|
||||||
// This sets up the stack to:
|
// This sets up the stack to:
|
||||||
// a) come out of task_switch and return to rip0 (default is the
|
// a) come out of task_switch and return to rip0 (default is the
|
||||||
@@ -126,22 +157,33 @@ thread::add_thunk_user(uintptr_t rip3, uintptr_t rip0, uint64_t flags)
|
|||||||
flags |= 0x200;
|
flags |= 0x200;
|
||||||
m_tcb.rflags3 = flags;
|
m_tcb.rflags3 = flags;
|
||||||
|
|
||||||
m_tcb.rsp -= sizeof(uintptr_t) * 7;
|
m_tcb.rsp -= sizeof(uintptr_t) * 9;
|
||||||
uintptr_t *stack = reinterpret_cast<uintptr_t*>(m_tcb.rsp);
|
uintptr_t *stack = reinterpret_cast<uintptr_t*>(m_tcb.rsp);
|
||||||
|
|
||||||
stack[6] = rip3; // return rip in rcx
|
stack[8] = rip3; // return rip in rcx
|
||||||
stack[5] = m_tcb.rsp3; // rbp
|
stack[7] = m_tcb.rsp3; // rbp
|
||||||
stack[4] = 0xbbbbbbbb; // rbx
|
stack[6] = 0xbbbbbbbb; // rbx
|
||||||
stack[3] = 0x12121212; // r12
|
stack[5] = 0x12121212; // r12
|
||||||
stack[2] = 0x13131313; // r13
|
stack[4] = 0x13131313; // r13
|
||||||
stack[1] = 0x14141414; // r14
|
stack[3] = 0x14141414; // r14
|
||||||
stack[0] = 0x15151515; // r15
|
stack[2] = 0x15151515; // r15
|
||||||
|
|
||||||
|
stack[1] = arg1; // rsi
|
||||||
|
stack[0] = arg0; // rdi
|
||||||
|
|
||||||
static const uintptr_t trampoline =
|
static const uintptr_t trampoline =
|
||||||
reinterpret_cast<uintptr_t>(kernel_to_user_trampoline);
|
reinterpret_cast<uintptr_t>(initialize_user_cpu);
|
||||||
add_thunk_kernel(rip0 ? rip0 : trampoline);
|
add_thunk_kernel(rip0 ? rip0 : trampoline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
thread::init_xsave_area()
|
||||||
|
{
|
||||||
|
void *xsave_area = new uint8_t [xsave_size];
|
||||||
|
memset(xsave_area, 0, xsave_size);
|
||||||
|
m_tcb.xsave = reinterpret_cast<uintptr_t>(xsave_area);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
thread::setup_kernel_stack()
|
thread::setup_kernel_stack()
|
||||||
{
|
{
|
||||||
@@ -149,8 +191,8 @@ thread::setup_kernel_stack()
|
|||||||
using mem::kernel_stack_pages;
|
using mem::kernel_stack_pages;
|
||||||
static constexpr size_t stack_bytes = kernel_stack_pages * frame_size;
|
static constexpr size_t stack_bytes = kernel_stack_pages * frame_size;
|
||||||
|
|
||||||
constexpr unsigned null_frame_entries = 2;
|
static constexpr unsigned null_frame_entries = 2;
|
||||||
constexpr size_t null_frame_size = null_frame_entries * sizeof(uint64_t);
|
static constexpr size_t null_frame_size = null_frame_entries * sizeof(uint64_t);
|
||||||
|
|
||||||
uintptr_t stack_addr = g_kernel_stacks.get_section();
|
uintptr_t stack_addr = g_kernel_stacks.get_section();
|
||||||
uintptr_t stack_end = stack_addr + stack_bytes;
|
uintptr_t stack_end = stack_addr + stack_bytes;
|
||||||
@@ -168,12 +210,19 @@ thread::setup_kernel_stack()
|
|||||||
}
|
}
|
||||||
|
|
||||||
thread *
|
thread *
|
||||||
thread::create_idle_thread(process &kernel, uint8_t pri, uintptr_t rsp0)
|
thread::create_idle_thread(process &kernel, uintptr_t rsp0)
|
||||||
{
|
{
|
||||||
thread *idle = new thread(kernel, pri, rsp0);
|
thread *idle = new thread(kernel, scheduler::idle_priority, rsp0);
|
||||||
idle->set_state(state::constant);
|
idle->set_state(state::constant);
|
||||||
idle->set_state(state::ready);
|
idle->set_state(state::ready);
|
||||||
return idle;
|
return idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace obj
|
} // namespace obj
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
__current_thread_id()
|
||||||
|
{
|
||||||
|
cpu_data &cpu = current_cpu();
|
||||||
|
return cpu.thread ? cpu.thread->obj_id() : -1u;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
#include <util/linked_list.h>
|
#include <util/linked_list.h>
|
||||||
#include <util/spinlock.h>
|
#include <util/spinlock.h>
|
||||||
|
|
||||||
|
#include "cpu.h"
|
||||||
|
#include "ipc_message.h"
|
||||||
#include "objects/kobject.h"
|
#include "objects/kobject.h"
|
||||||
#include "wait_queue.h"
|
#include "wait_queue.h"
|
||||||
|
|
||||||
struct cpu_data;
|
|
||||||
struct page_table;
|
struct page_table;
|
||||||
|
|
||||||
namespace obj {
|
namespace obj {
|
||||||
@@ -26,6 +27,7 @@ struct TCB
|
|||||||
uintptr_t rsp3;
|
uintptr_t rsp3;
|
||||||
uintptr_t rflags3;
|
uintptr_t rflags3;
|
||||||
uintptr_t pml4;
|
uintptr_t pml4;
|
||||||
|
uintptr_t xsave;
|
||||||
// End of area used by asembly
|
// End of area used by asembly
|
||||||
|
|
||||||
obj::thread* thread;
|
obj::thread* thread;
|
||||||
@@ -57,9 +59,6 @@ public:
|
|||||||
/// Capabilities on a newly constructed thread handle
|
/// Capabilities on a newly constructed thread handle
|
||||||
static constexpr j6_cap_t creation_caps = j6_cap_thread_all;
|
static constexpr j6_cap_t creation_caps = j6_cap_thread_all;
|
||||||
|
|
||||||
/// Capabilities the parent process gets on new thread handles
|
|
||||||
static constexpr j6_cap_t parent_caps = j6_cap_thread_all;
|
|
||||||
|
|
||||||
static constexpr kobject::type type = kobject::type::thread;
|
static constexpr kobject::type type = kobject::type::thread;
|
||||||
|
|
||||||
enum class state : uint8_t {
|
enum class state : uint8_t {
|
||||||
@@ -96,9 +95,14 @@ public:
|
|||||||
inline void set_priority(uint8_t p) { if (!constant()) m_tcb.priority = p; }
|
inline void set_priority(uint8_t p) { if (!constant()) m_tcb.priority = p; }
|
||||||
|
|
||||||
/// Block this thread, waiting for a value
|
/// Block this thread, waiting for a value
|
||||||
/// \returns The value passed to wake()
|
/// \returns The value passed to wake()
|
||||||
uint64_t block();
|
uint64_t block();
|
||||||
|
|
||||||
|
/// Block this thread, waiting for a value
|
||||||
|
/// \arg held A held lock to unlock when blocking
|
||||||
|
/// \returns The value passed to wake()
|
||||||
|
uint64_t block(util::scoped_lock &held);
|
||||||
|
|
||||||
/// Block the calling thread until this thread exits
|
/// Block the calling thread until this thread exits
|
||||||
j6_status_t join();
|
j6_status_t join();
|
||||||
|
|
||||||
@@ -118,13 +122,8 @@ public:
|
|||||||
/// \returns The clock time at which to wake. 0 for no timeout.
|
/// \returns The clock time at which to wake. 0 for no timeout.
|
||||||
inline uint64_t wake_timeout() const { return m_wake_timeout; }
|
inline uint64_t wake_timeout() const { return m_wake_timeout; }
|
||||||
|
|
||||||
struct message_data
|
void set_message_data(ipc::message &&md);
|
||||||
{
|
ipc::message && get_message_data();
|
||||||
uint64_t tag, subtag;
|
|
||||||
j6_handle_t handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
message_data & get_message_data() { return m_message_data; }
|
|
||||||
|
|
||||||
inline bool has_state(state s) const {
|
inline bool has_state(state s) const {
|
||||||
return __atomic_load_n(reinterpret_cast<const uint8_t*>(&m_state), __ATOMIC_ACQUIRE) &
|
return __atomic_load_n(reinterpret_cast<const uint8_t*>(&m_state), __ATOMIC_ACQUIRE) &
|
||||||
@@ -152,29 +151,28 @@ public:
|
|||||||
/// Add a stack header that returns to the given address in user space
|
/// Add a stack header that returns to the given address in user space
|
||||||
/// via a function in kernel space.
|
/// via a function in kernel space.
|
||||||
/// \arg rip3 The user space address to return to
|
/// \arg rip3 The user space address to return to
|
||||||
|
/// \arg arg0 An argument passed to the userspace function
|
||||||
|
/// \arg arg1 An argument passed to the userspace function
|
||||||
/// \arg rip0 The kernel function to pass through, optional
|
/// \arg rip0 The kernel function to pass through, optional
|
||||||
/// \arg flags Extra RFLAGS values to set, optional
|
/// \arg flags Extra RFLAGS values to set, optional
|
||||||
void add_thunk_user(uintptr_t rip3, uintptr_t rip0 = 0, uint64_t flags = 0);
|
void add_thunk_user(
|
||||||
|
uintptr_t rip3,
|
||||||
/// Get the handle representing this thread to its process
|
uint64_t arg0 = 0,
|
||||||
j6_handle_t self_handle() const { return m_self_handle; }
|
uint64_t arg1 = 0,
|
||||||
|
uintptr_t rip0 = 0,
|
||||||
|
uint64_t flags = 0);
|
||||||
|
|
||||||
/// Create the kernel idle thread
|
/// Create the kernel idle thread
|
||||||
/// \arg kernel The process object that owns kernel tasks
|
/// \arg kernel The process object that owns kernel tasks
|
||||||
/// \arg pri The idle thread priority value
|
|
||||||
/// \arg rsp The existing stack for the idle thread
|
/// \arg rsp The existing stack for the idle thread
|
||||||
static thread * create_idle_thread(process &kernel, uint8_t pri, uintptr_t rsp);
|
static thread * create_idle_thread(process &kernel, uintptr_t rsp);
|
||||||
|
|
||||||
protected:
|
|
||||||
/// Don't delete a thread on no handles, the scheduler takes
|
|
||||||
/// care of that.
|
|
||||||
virtual void on_no_handles() override {}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
thread() = delete;
|
thread() = delete;
|
||||||
thread(const thread &other) = delete;
|
thread(const thread &other) = delete;
|
||||||
thread(const thread &&other) = delete;
|
thread(const thread &&other) = delete;
|
||||||
friend class process;
|
friend class process;
|
||||||
|
friend void ::cpu_initialize_thread_state();
|
||||||
|
|
||||||
/// Constructor. Used when a kernel stack already exists.
|
/// Constructor. Used when a kernel stack already exists.
|
||||||
/// \arg parent The process which owns this thread
|
/// \arg parent The process which owns this thread
|
||||||
@@ -182,6 +180,9 @@ private:
|
|||||||
/// \arg rsp0 The existing kernel stack rsp, 0 for none
|
/// \arg rsp0 The existing kernel stack rsp, 0 for none
|
||||||
thread(process &parent, uint8_t pri, uintptr_t rsp0 = 0);
|
thread(process &parent, uint8_t pri, uintptr_t rsp0 = 0);
|
||||||
|
|
||||||
|
/// Set up the XSAVE saved processor state area for this thread
|
||||||
|
void init_xsave_area();
|
||||||
|
|
||||||
/// Set up a new empty kernel stack for this thread.
|
/// Set up a new empty kernel stack for this thread.
|
||||||
void setup_kernel_stack();
|
void setup_kernel_stack();
|
||||||
|
|
||||||
@@ -191,13 +192,16 @@ private:
|
|||||||
thread *m_creator;
|
thread *m_creator;
|
||||||
|
|
||||||
state m_state;
|
state m_state;
|
||||||
|
util::bitset32 m_mxcsr;
|
||||||
|
|
||||||
uint64_t m_wake_value;
|
uint64_t m_wake_value;
|
||||||
uint64_t m_wake_timeout;
|
uint64_t m_wake_timeout;
|
||||||
message_data m_message_data;
|
|
||||||
|
ipc::message m_message;
|
||||||
|
|
||||||
wait_queue m_join_queue;
|
wait_queue m_join_queue;
|
||||||
j6_handle_t m_self_handle;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace obj
|
} // namespace obj
|
||||||
|
|
||||||
|
extern "C" uint32_t __current_thread_id();
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
|
|
||||||
#include "assert.h"
|
#include "kassert.h"
|
||||||
#include "frame_allocator.h"
|
#include "frame_allocator.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "objects/vm_area.h"
|
#include "objects/vm_area.h"
|
||||||
#include "page_tree.h"
|
|
||||||
#include "vm_space.h"
|
#include "vm_space.h"
|
||||||
|
|
||||||
namespace obj {
|
namespace obj {
|
||||||
@@ -86,7 +85,7 @@ vm_area_fixed::resize(size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
vm_area_fixed::get_page(uintptr_t offset, uintptr_t &phys)
|
vm_area_fixed::get_page(uintptr_t offset, uintptr_t &phys, bool alloc)
|
||||||
{
|
{
|
||||||
if (offset > m_size)
|
if (offset > m_size)
|
||||||
return false;
|
return false;
|
||||||
@@ -106,11 +105,16 @@ vm_area_untracked::~vm_area_untracked()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
vm_area_untracked::get_page(uintptr_t offset, uintptr_t &phys)
|
vm_area_untracked::get_page(uintptr_t offset, uintptr_t &phys, bool alloc)
|
||||||
{
|
{
|
||||||
if (offset > m_size)
|
if (offset > m_size)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!alloc) {
|
||||||
|
phys = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return frame_allocator::get().allocate(1, &phys);
|
return frame_allocator::get().allocate(1, &phys);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,9 +140,17 @@ vm_area_open::~vm_area_open()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
vm_area_open::get_page(uintptr_t offset, uintptr_t &phys)
|
vm_area_open::get_page(uintptr_t offset, uintptr_t &phys, bool alloc)
|
||||||
|
{
|
||||||
|
if (alloc)
|
||||||
|
return page_tree::find_or_add(m_mapped, offset, phys);
|
||||||
|
else
|
||||||
|
return page_tree::find(m_mapped, offset, &phys);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vm_area_open::add_existing(uintptr_t offset, uintptr_t phys)
|
||||||
{
|
{
|
||||||
return page_tree::find_or_add(m_mapped, offset, phys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -166,7 +178,7 @@ vm_area_guarded::return_section(uintptr_t addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
vm_area_guarded::get_page(uintptr_t offset, uintptr_t &phys)
|
vm_area_guarded::get_page(uintptr_t offset, uintptr_t &phys, bool alloc)
|
||||||
{
|
{
|
||||||
if (offset >= m_stacks.end())
|
if (offset >= m_stacks.end())
|
||||||
return false;
|
return false;
|
||||||
@@ -176,7 +188,23 @@ vm_area_guarded::get_page(uintptr_t offset, uintptr_t &phys)
|
|||||||
if ((offset >> 12) % m_pages == 0)
|
if ((offset >> 12) % m_pages == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return vm_area_open::get_page(offset, phys);
|
return vm_area_open::get_page(offset, phys, alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
vm_area_ring::vm_area_ring(size_t size, vm_flags flags) :
|
||||||
|
vm_area_open {size * 2, flags},
|
||||||
|
m_bufsize {size}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
vm_area_ring::~vm_area_ring() {}
|
||||||
|
|
||||||
|
bool
|
||||||
|
vm_area_ring::get_page(uintptr_t offset, uintptr_t &phys, bool alloc)
|
||||||
|
{
|
||||||
|
if (offset > m_bufsize)
|
||||||
|
offset -= m_bufsize;
|
||||||
|
return vm_area_open::get_page(offset, phys, alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace obj
|
} // namespace obj
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user