Compare commits
187 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf22ed57a2 | ||
|
|
b6772ac2ea | ||
|
|
f0025dbc47 | ||
|
|
2a347942bc | ||
|
|
36da65e15b | ||
|
|
214ff3eff0 | ||
|
|
8c0d52d0fe | ||
|
|
793bba95b5 | ||
|
|
2d4a65c654 | ||
|
|
872f178d94 | ||
|
|
70d6094f46 | ||
|
|
31289436f5 | ||
|
|
5e7792c11f | ||
|
|
e73064a438 | ||
|
|
72787c0652 | ||
|
|
c88170f6e0 | ||
|
|
a65ecb157d | ||
|
|
eb8a3c0e09 | ||
|
|
572fade7ff | ||
|
|
b5885ae35f | ||
|
|
335bc01185 | ||
|
|
c87563a520 | ||
|
|
e4aafca7c3 | ||
|
|
fe05d45cde | ||
|
|
b3861decc3 | ||
|
|
b3f59acf7e | ||
|
|
4f8e35e409 | ||
|
|
b898949ffc | ||
|
|
2244764777 | ||
|
|
e4c8a36577 | ||
|
|
41eb45402e | ||
|
|
33ed95bd8e | ||
|
|
4985b2d1f4 | ||
|
|
68a2250886 | ||
|
|
8575939b20 | ||
|
|
634a1c5f6a | ||
|
|
c364e30240 | ||
|
|
3595c3a440 | ||
|
|
c3dd65457d | ||
|
|
3aa909b917 | ||
|
|
35d8d2ab2d | ||
|
|
e3ebaeb2c8 | ||
|
|
71dc332dae | ||
|
|
211a3c2358 | ||
|
|
16b9d4fd8b | ||
|
|
c0f304559f | ||
|
|
8d325184ad | ||
|
|
0df93eaa98 | ||
|
|
aae18fd035 | ||
|
|
fd8552ca3a | ||
|
|
452457412b | ||
|
|
521df1f4b7 | ||
|
|
0ae2f935af | ||
|
|
3282a3ae34 | ||
|
|
cb612c36ea | ||
|
|
14aad62e02 | ||
|
|
847d7ab38d | ||
|
|
99ef9166ae | ||
|
|
0305830e32 | ||
|
|
9f342dff49 | ||
|
|
02766d82eb | ||
|
|
3e372faf5e | ||
|
|
786b4ea8c0 | ||
|
|
20ff0ed30b | ||
|
|
2a490a1bbc | ||
|
|
89391e5be1 | ||
|
|
c3cb41f78a | ||
|
|
c3a0266354 | ||
|
|
55a5c97034 | ||
|
|
dcb8a3f3fb | ||
|
|
3dffe564af | ||
|
|
1820972fb7 | ||
|
|
67534faa78 | ||
|
|
12605843ce | ||
|
|
8dbdebff3f | ||
|
|
61845b8761 | ||
|
|
1ba44c99d1 | ||
|
|
6716ab251f | ||
|
|
e3b9c0140a | ||
|
|
d1c0723b44 | ||
|
|
14ed6af433 | ||
|
|
1325706c7c | ||
|
|
f5ab00a055 | ||
|
|
dcdfc30c45 | ||
|
|
a0d165c79b | ||
|
|
7b23310d8b | ||
|
|
e477dea5c7 | ||
|
|
dccb136c99 | ||
|
|
6af29a7181 | ||
| 7ca3a19eed | |||
| 7fcb4efab6 | |||
| a8024d3dd3 | |||
| 8bb78c95a8 | |||
| 19cbf1ca67 | |||
|
|
e70eb5a926 | ||
| 7bdde2d359 | |||
|
|
3daa07e311 | ||
|
|
47fab631d0 | ||
| 2e3d7b1656 | |||
| bf600a7608 | |||
| 6b00805d04 | |||
| 82b7082fc5 | |||
| 8bb9e22218 | |||
| 2ad90dcb5c | |||
| 97ea77bd27 | |||
| 1904e240cf | |||
| 4ccaa2dfea | |||
| da38006f44 | |||
| 87b0a93d32 | |||
| ff78c951f0 | |||
| 2d44e8112b | |||
| f7f8bb3f45 | |||
| 67ebc58812 | |||
| 13aee1755e | |||
| 0e0975e5f6 | |||
| d4283731e4 | |||
| 6780ab1b67 | |||
| 41eac2764a | |||
| 113d14c440 | |||
| abe523be77 | |||
| 1b392a0551 | |||
| deb2fa0a09 | |||
| 671a0ce0fb | |||
| ac67111b83 | |||
| 09575370ce | |||
| 9aa08a70cf | |||
| ca7f78565d | |||
| dcb4d1823f | |||
| e8564c755b | |||
| 9dee5e4138 | |||
| 245f260d67 | |||
| 5f27727e52 | |||
| 1238608430 | |||
| 71cd7af17b | |||
| 8490472581 | |||
| 8534d8d3c5 | |||
| 53d260cc6e | |||
| 53a4682418 | |||
| 42455873ff | |||
| 724b846ee4 | |||
| f27b133089 | |||
| 773617cbf3 | |||
| 44e29b3c4a | |||
| 95a35cd0bf | |||
| 28b800a497 | |||
| 838776d7df | |||
| e19fa377d7 | |||
| d63a30728c | |||
| 4819920b4e | |||
| bbb9aae198 | |||
| 0d94776c46 | |||
| 565a5ee960 | |||
| e7f9d8f1d7 | |||
| 55bc49598e | |||
| 579eaaf4a0 | |||
| b98334db28 | |||
| e1b1b5d357 | |||
| cf582c4ce4 | |||
| 911b4c0b10 | |||
| 94c1f0d3fc | |||
| 73221dfe34 | |||
| 4ffd4949ca | |||
| 3f137805bc | |||
| 6a00057817 | |||
| 58bc5acb1e | |||
| d3e9d92466 | |||
| ae3290c53d | |||
| 4cf222a5bb | |||
| c3abe035c8 | |||
| ef5c333030 | |||
| f4cbb9498f | |||
| 794c86f9b4 | |||
|
|
8687fe3786 | ||
|
|
0a28d2db07 | ||
|
|
6c468a134b | ||
|
|
9b67f87062 | ||
|
|
b4adc29d7f | ||
|
|
a10aca573d | ||
|
|
ea1224e213 | ||
|
|
64ad65fa1b | ||
|
|
b881b2639d | ||
|
|
a5f72edf82 | ||
|
|
ea2a3e6f16 | ||
|
|
2125f043b6 | ||
|
|
655b5c88d4 | ||
|
|
88b090fe94 | ||
|
|
c6c3a556b3 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,8 +3,10 @@
|
||||
*.bak
|
||||
tags
|
||||
jsix.log
|
||||
*.out
|
||||
*.o
|
||||
*.a
|
||||
sysroot
|
||||
.gdb_history
|
||||
.peru
|
||||
__pycache__
|
||||
|
||||
94
README.md
94
README.md
@@ -1,15 +1,18 @@
|
||||
# jsix: A toy OS kernel
|
||||

|
||||
|
||||
**jsix** is the kernel for the hobby OS that I am currently building. It's
|
||||
far from finished, or even being usable. Instead, it's a sandbox for me to play
|
||||
with kernel-level code and explore architectures.
|
||||
# The jsix operating system
|
||||
|
||||
**jsix** is a custom multi-core x64 operating system that I am building from
|
||||
scratch. It's far from finished, or even being usable - see the *Status and
|
||||
Roadmap* section, below.
|
||||
|
||||
The design goals of the project are:
|
||||
|
||||
* Modernity - I'm not interested in designing for legacy systems, or running on
|
||||
all hardware out there. My target is only 64 bit architecutres, and modern
|
||||
commodity hardware. Currently that means x64 systems with Nehalem or newer
|
||||
CPUs and UEFI firmware. Eventually I'd like to work on an AArch64 port,
|
||||
CPUs and UEFI firmware. (See [this list][cpu_features] for the currently
|
||||
required CPU features.) Eventually I'd like to work on an AArch64 port,
|
||||
partly to force myself to factor out the architecture-dependent pieces of the
|
||||
code base.
|
||||
|
||||
@@ -17,13 +20,11 @@ The design goals of the project are:
|
||||
processes as possible, in the microkernel fashion. A sub-goal of this is to
|
||||
explore where the bottlenecks of such a microkernel are now, and whether
|
||||
eschewing legacy hardware will let me design a system that's less bogged down
|
||||
by the traditional microkernel problems. Given that there are no processes
|
||||
yet, the kernel is monolithic by default.
|
||||
by the traditional microkernel problems.
|
||||
|
||||
* Exploration - I'm really mostly doing this to have fun learning and exploring
|
||||
modern OS development. Modular design may be tossed out (hopefully
|
||||
temporarily) in some places to allow me to play around with the related
|
||||
hardware.
|
||||
modern OS development. Initial feature implementations may temporarily throw
|
||||
away modular design to allow for exploration of the related hardware.
|
||||
|
||||
A note on the name: This kernel was originally named Popcorn, but I have since
|
||||
discovered that the Popcorn Linux project is also developing a kernel with that
|
||||
@@ -31,6 +32,69 @@ name, started around the same time as this project. So I've renamed this kernel
|
||||
jsix (Always styled _jsix_ or `j6`, never capitalized) as an homage to L4, xv6,
|
||||
and my wonderful wife.
|
||||
|
||||
[cpu_features]: https://github.com/justinian/jsix/blob/master/src/libraries/cpu/include/cpu/features.inc
|
||||
|
||||
## Status and Roadmap
|
||||
|
||||
The following major feature areas are targets for jsix development:
|
||||
|
||||
#### UEFI boot loader
|
||||
|
||||
_Done._ The bootloader loads the kernel and initial userspace programs, and
|
||||
sets up necessary kernel arguments about the memory map and EFI GOP
|
||||
framebuffer. Possible future ideas:
|
||||
|
||||
- take over more init-time functions from the kernel
|
||||
- rewrite it in Zig
|
||||
|
||||
#### Memory
|
||||
|
||||
_Virtual memory: Sufficient._ The kernel manages virtual memory with a number
|
||||
of kinds of `vm_area` objects representing mapped areas, which can belong to
|
||||
one or more `vm_space` objects which represent a whole virtual memory space.
|
||||
(Each process has a `vm_space`, and so does the kernel itself.)
|
||||
|
||||
Remaining to do:
|
||||
|
||||
- TLB shootdowns
|
||||
- Page swapping
|
||||
|
||||
_Physical page allocation: Sufficient._ The current physical page allocator
|
||||
implementation suses a group of block representing up-to-1GiB areas of usable
|
||||
memory as defined by the bootloader. Each block has a three-level bitmap
|
||||
denoting free/used pages.
|
||||
|
||||
#### Multitasking
|
||||
|
||||
_Sufficient._ The global scheduler object keeps separate ready/blocked lists
|
||||
per core. Cores periodically attempt to balance load via work stealing.
|
||||
|
||||
User-space tasks are able to create threads as well as other processes.
|
||||
|
||||
Several kernel-only tasks exist, though I'm trying to reduce that. Eventually
|
||||
only the timekeeping task should be a separate kernel-only thread.
|
||||
|
||||
#### API
|
||||
|
||||
_In progress._ User-space tasks are able to make syscalls to the kernel via
|
||||
fast SYSCALL/SYSRET instructions.
|
||||
|
||||
Major tasks still to do:
|
||||
|
||||
- The process initialization protocol needs to be re-built entirely.
|
||||
- Processes' handles to kernel objects need the ability to check capabilities
|
||||
|
||||
#### Hardware Support
|
||||
|
||||
* Framebuffer driver: _In progress._ Currently on machines with a video
|
||||
device accessible by UEFI, jsix starts a user-space framebuffer driver that
|
||||
only prints out kernel logs.
|
||||
* Serial driver: _To do._ Machines without a video device should have a
|
||||
user-space log output task like the framebuffer driver, but currently this
|
||||
is done inside the kernel.
|
||||
* USB driver: _To do_
|
||||
* AHCI (SATA) driver: _To do_
|
||||
|
||||
## Building
|
||||
|
||||
jsix uses the [Ninja][] build tool, and generates the build files for it with a
|
||||
@@ -38,7 +102,7 @@ custom tool called [Bonnibel][]. Bonnibel can be installed with [Cargo][], or
|
||||
downloaded as a prebuilt binary from its Github repository.
|
||||
|
||||
[Ninja]: https://ninja-build.org
|
||||
[Bonnibel]: https://github.com/justinian/bonnibel
|
||||
[Bonnibel]: https://github.com/justinian/bonnibel_rs
|
||||
[Cargo]: https://crates.io/crates/bonnibel
|
||||
|
||||
Requrirements:
|
||||
@@ -71,8 +135,8 @@ I personally run this either from a real debian amd64 testing/buster machine or
|
||||
a windows WSL debian testing/buster installation. The following should be
|
||||
enough to set up such a system to build the kernel:
|
||||
|
||||
sudo apt install qemu-system-x86 nasm clang-6.0 mtools curl
|
||||
sudo update-alternatives /usr/bin/clang clang /usr/bin/clang-6.0 1000
|
||||
sudo update-alternatives /usr/bin/clang++ clang++ /usr/bin/clang++-6.0 1000
|
||||
curl -L -o pb https://github.com/justinian/bonnibel/releases/download/2.0.0/pb_linux_amd64 && chmod a+x pb
|
||||
sudo apt install qemu-system-x86 nasm clang-10 mtools curl ninja-build
|
||||
sudo update-alternatives /usr/bin/clang clang /usr/bin/clang-10 1000
|
||||
sudo update-alternatives /usr/bin/clang++ clang++ /usr/bin/clang++-10 1000
|
||||
curl -L -o pb https://github.com/justinian/bonnibel_rs/releases/download/v2.3.0/pb-linux-amd64 && chmod a+x pb
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import gdb
|
||||
|
||||
class PrintStackCommand(gdb.Command):
|
||||
def __init__(self):
|
||||
super().__init__("popc_stack", gdb.COMMAND_DATA)
|
||||
super().__init__("j6stack", gdb.COMMAND_DATA)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
args = gdb.string_to_argv(arg)
|
||||
@@ -16,13 +16,117 @@ class PrintStackCommand(gdb.Command):
|
||||
depth = int(args[1])
|
||||
|
||||
for i in range(depth-1, -1, -1):
|
||||
offset = i * 8
|
||||
base_addr = gdb.parse_and_eval(base)
|
||||
value = gdb.parse_and_eval(f"*(uint64_t*)({base} + {offset})")
|
||||
print("{:016x} (+{:04x}): {:016x}".format(int(base_addr) + offset, offset, int(value)))
|
||||
try:
|
||||
offset = i * 8
|
||||
base_addr = gdb.parse_and_eval(base)
|
||||
value = gdb.parse_and_eval(f"*(uint64_t*)({base} + {offset})")
|
||||
print("{:016x} (+{:04x}): {:016x}".format(int(base_addr) + offset, offset, int(value)))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
continue
|
||||
|
||||
|
||||
class PrintBacktraceCommand(gdb.Command):
|
||||
def __init__(self):
|
||||
super().__init__("j6bt", gdb.COMMAND_DATA)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
args = gdb.string_to_argv(arg)
|
||||
|
||||
depth = 30
|
||||
if len(args) > 0:
|
||||
depth = int(args[0])
|
||||
|
||||
frame = "$rbp"
|
||||
if len(args) > 1:
|
||||
frame = args[1]
|
||||
|
||||
for i in range(depth-1, -1, -1):
|
||||
ret = gdb.parse_and_eval(f"*(uint64_t*)({frame} + 8)")
|
||||
frame = gdb.parse_and_eval(f"*(uint64_t*)({frame})")
|
||||
|
||||
name = ""
|
||||
block = gdb.block_for_pc(int(ret))
|
||||
if block:
|
||||
name = block.function or ""
|
||||
|
||||
print("{:016x} {}".format(int(ret), name))
|
||||
|
||||
if frame == 0 or ret == 0:
|
||||
return
|
||||
|
||||
|
||||
class TableWalkCommand(gdb.Command):
|
||||
def __init__(self):
|
||||
super().__init__("j6tw", gdb.COMMAND_DATA)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
args = gdb.string_to_argv(arg)
|
||||
if len(args) < 2:
|
||||
raise Exception("Must be: j6tw <pml4> <addr>")
|
||||
|
||||
pml4 = int(gdb.parse_and_eval(args[0]))
|
||||
addr = int(gdb.parse_and_eval(args[1]))
|
||||
|
||||
indices = [
|
||||
(addr >> 39) & 0x1ff,
|
||||
(addr >> 30) & 0x1ff,
|
||||
(addr >> 21) & 0x1ff,
|
||||
(addr >> 12) & 0x1ff,
|
||||
]
|
||||
|
||||
names = ["PML4", "PDP", "PD", "PT"]
|
||||
|
||||
table_flags = [
|
||||
(0x0001, "present"),
|
||||
(0x0002, "write"),
|
||||
(0x0004, "user"),
|
||||
(0x0008, "pwt"),
|
||||
(0x0010, "pcd"),
|
||||
(0x0020, "accessed"),
|
||||
(0x0040, "dirty"),
|
||||
(0x0080, "largepage"),
|
||||
(0x0100, "global"),
|
||||
(0x1080, "pat"),
|
||||
((1<<63), "xd"),
|
||||
]
|
||||
|
||||
page_flags = [
|
||||
(0x0001, "present"),
|
||||
(0x0002, "write"),
|
||||
(0x0004, "user"),
|
||||
(0x0008, "pwt"),
|
||||
(0x0010, "pcd"),
|
||||
(0x0020, "accessed"),
|
||||
(0x0040, "dirty"),
|
||||
(0x0080, "pat"),
|
||||
(0x0100, "global"),
|
||||
((1<<63), "xd"),
|
||||
]
|
||||
|
||||
flagsets = [table_flags, table_flags, table_flags, page_flags]
|
||||
|
||||
table = pml4
|
||||
entry = 0
|
||||
for i in range(len(indices)):
|
||||
entry = int(gdb.parse_and_eval(f'((uint64_t*){table})[{indices[i]}]'))
|
||||
flagset = flagsets[i]
|
||||
flag_names = " | ".join([f[1] for f in flagset if (entry & f[0]) == f[0]])
|
||||
|
||||
print(f"{names[i]:>4}: {table:016x}")
|
||||
print(f" index: {indices[i]:3} {entry:016x}")
|
||||
print(f" flags: {flag_names}")
|
||||
|
||||
if (entry & 1) == 0 or (i < 3 and (entry & 0x80)):
|
||||
break
|
||||
|
||||
table = (entry & 0x7ffffffffffffe00) | 0xffffc00000000000
|
||||
|
||||
|
||||
|
||||
PrintStackCommand()
|
||||
PrintBacktraceCommand()
|
||||
TableWalkCommand()
|
||||
|
||||
gdb.execute("target remote :1234")
|
||||
gdb.execute("display/i $rip")
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
dest = "screenfont.psf"
|
||||
source = "../assets/fonts/tamsyn8x16r.psf"
|
||||
|
||||
[[files]]
|
||||
dest = "symbol_table.dat"
|
||||
source = "symbol_table.dat"
|
||||
symbols = true
|
||||
|
||||
[[files]]
|
||||
dest = "nulldrv1"
|
||||
source = "user/nulldrv"
|
||||
|
||||
1
assets/jsix.svg
Executable file
1
assets/jsix.svg
Executable file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!-- Generator: Gravit.io --><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="isolation:isolate" viewBox="176.562 356.069 211.11 113" width="211.11pt" height="113pt"><g><g><rect x="176.562" y="356.069" width="211.11" height="113" transform="matrix(1,0,0,1,0,0)" fill="rgb(255,255,255)"/><g><path d=" M 212.981 372.36 L 219.564 376.16 L 226.147 379.961 L 226.147 387.563 L 226.147 395.164 L 219.564 398.965 L 212.981 402.766 L 206.398 398.965 L 199.815 395.164 L 199.815 387.563 L 199.815 379.961 L 206.398 376.16 L 212.981 372.36 L 212.981 372.36 L 212.981 372.36 Z M 256.292 397.366 L 262.875 401.166 L 269.458 404.967 L 269.458 412.569 L 269.458 420.17 L 262.875 423.971 L 256.292 427.772 L 249.709 423.971 L 243.126 420.17 L 243.126 412.569 L 243.126 404.967 L 249.709 401.166 L 256.292 397.366 L 256.292 397.366 Z M 183.622 387.283 L 205.52 374.64 L 227.418 361.997 L 249.316 374.64 L 271.214 387.283 L 271.214 412.569 L 271.214 437.854 L 249.316 450.497 L 227.418 463.14 L 205.52 450.497 L 183.622 437.854 L 183.622 412.569 L 183.622 387.283 L 183.622 387.283 L 183.622 387.283 Z M 241.855 372.36 L 248.438 376.16 L 255.021 379.961 L 255.021 387.563 L 255.021 395.164 L 248.438 398.965 L 241.855 402.766 L 235.272 398.965 L 228.689 395.164 L 228.689 387.563 L 228.689 379.961 L 235.272 376.16 L 241.855 372.36 Z " fill-rule="evenodd" fill="rgb(49,79,128)"/><path d=" M 298.642 379.579 L 291.621 379.579 L 291.621 372.558 L 298.642 372.558 L 298.642 379.579 Z M 285.214 446.718 L 285.214 441.452 L 287.32 441.452 L 287.32 441.452 Q 289.339 441.452 290.524 440.092 L 290.524 440.092 L 290.524 440.092 Q 291.708 438.731 291.708 436.625 L 291.708 436.625 L 291.708 387.039 L 298.729 387.039 L 298.729 436.011 L 298.729 436.011 Q 298.729 440.925 295.921 443.822 L 295.921 443.822 L 295.921 443.822 Q 293.113 446.718 288.286 446.718 L 288.286 446.718 L 285.214 446.718 Z M 306.628 432.676 L 306.628 427.41 L 314.088 427.41 L 314.088 427.41 Q 317.862 427.41 319.573 425.347 L 319.573 425.347 L 319.573 425.347 Q 321.285 423.285 321.285 419.95 L 321.285 419.95 L 321.285 419.95 Q 321.285 417.317 319.705 415.474 L 319.705 415.474 L 319.705 415.474 Q 318.125 413.631 314.966 411.174 L 314.966 411.174 L 314.966 411.174 Q 312.245 408.98 310.621 407.356 L 310.621 407.356 L 310.621 407.356 Q 308.998 405.732 307.813 403.319 L 307.813 403.319 L 307.813 403.319 Q 306.628 400.905 306.628 397.746 L 306.628 397.746 L 306.628 397.746 Q 306.628 393.095 309.744 390.067 L 309.744 390.067 L 309.744 390.067 Q 312.859 387.039 318.125 387.039 L 318.125 387.039 L 325.76 387.039 L 325.76 392.305 L 319.441 392.305 L 319.441 392.305 Q 313.21 392.305 313.21 398.185 L 313.21 398.185 L 313.21 398.185 Q 313.21 400.467 314.615 402.134 L 314.615 402.134 L 314.615 402.134 Q 316.019 403.802 319.003 406.083 L 319.003 406.083 L 319.003 406.083 Q 321.723 408.19 323.479 409.901 L 323.479 409.901 L 323.479 409.901 Q 325.234 411.613 326.463 414.202 L 326.463 414.202 L 326.463 414.202 Q 327.691 416.791 327.691 420.301 L 327.691 420.301 L 327.691 420.301 Q 327.691 426.532 324.4 429.604 L 324.4 429.604 L 324.4 429.604 Q 321.109 432.676 315.141 432.676 L 315.141 432.676 L 306.628 432.676 Z M 342.611 379.579 L 335.59 379.579 L 335.59 372.558 L 342.611 372.558 L 342.611 379.579 Z M 342.611 432.676 L 335.59 432.676 L 335.59 387.039 L 342.611 387.039 L 342.611 432.676 Z M 356.126 432.676 L 348.754 432.676 L 361.392 409.77 L 349.632 387.039 L 356.39 387.039 L 364.639 403.187 L 372.977 387.039 L 379.735 387.039 L 367.974 409.77 L 380.612 432.676 L 373.24 432.676 L 364.639 416.001 L 356.126 432.676 Z " fill="rgb(49,79,128)"/></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
2385
external/catch/catch.hpp
vendored
2385
external/catch/catch.hpp
vendored
File diff suppressed because it is too large
Load Diff
6
external/uefi/boot_services.h
vendored
6
external/uefi/boot_services.h
vendored
@@ -14,8 +14,10 @@
|
||||
namespace uefi {
|
||||
namespace bs_impl {
|
||||
using allocate_pages = status (*)(allocate_type, memory_type, size_t, void**);
|
||||
using free_pages = status (*)(void*, size_t);
|
||||
using get_memory_map = status (*)(size_t*, memory_descriptor*, size_t*, size_t*, uint32_t*);
|
||||
using allocate_pool = status (*)(memory_type, uint64_t, void**);
|
||||
using free_pool = status (*)(void*);
|
||||
using handle_protocol = status (*)(handle, const guid*, void**);
|
||||
using create_event = status (*)(evt, tpl, event_notify, void*, event*);
|
||||
using exit_boot_services = status (*)(handle, size_t);
|
||||
@@ -35,10 +37,10 @@ struct boot_services {
|
||||
|
||||
// Memory Services
|
||||
bs_impl::allocate_pages allocate_pages;
|
||||
void *free_pages;
|
||||
bs_impl::free_pages free_pages;
|
||||
bs_impl::get_memory_map get_memory_map;
|
||||
bs_impl::allocate_pool allocate_pool;
|
||||
void *free_pool;
|
||||
bs_impl::free_pool free_pool;
|
||||
|
||||
// Event & Timer Services
|
||||
bs_impl::create_event create_event;
|
||||
|
||||
390
external/uefi/networking.h
vendored
Normal file
390
external/uefi/networking.h
vendored
Normal file
@@ -0,0 +1,390 @@
|
||||
#pragma once
|
||||
#ifndef _uefi_networking_h_
|
||||
#define _uefi_networking_h_
|
||||
|
||||
// This Source Code Form is part of the j6-uefi-headers project and is subject
|
||||
// to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was
|
||||
// not distributed with this file, You can obtain one at
|
||||
// http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <uefi/types.h>
|
||||
|
||||
namespace uefi {
|
||||
|
||||
//
|
||||
// IPv4 definitions
|
||||
//
|
||||
struct ipv4_address
|
||||
{
|
||||
uint8_t addr[4];
|
||||
};
|
||||
|
||||
//
|
||||
// IPv6 definitions
|
||||
//
|
||||
struct ipv6_address
|
||||
{
|
||||
uint8_t addr[16];
|
||||
};
|
||||
|
||||
struct ip6_address_info
|
||||
{
|
||||
ipv6_address address;
|
||||
uint8_t prefix_length;
|
||||
};
|
||||
|
||||
struct ip6_route_table
|
||||
{
|
||||
ipv6_address gateway;
|
||||
ipv6_address destination;
|
||||
uint8_t prefix_length;
|
||||
};
|
||||
|
||||
enum class ip6_neighbor_state : int {
|
||||
incomplete,
|
||||
reachable,
|
||||
stale,
|
||||
delay,
|
||||
probe,
|
||||
}
|
||||
|
||||
struct ip6_neighbor_cache
|
||||
{
|
||||
ipv6_address neighbor;
|
||||
mac_address link_address;
|
||||
ip6_neighbor_state state;
|
||||
};
|
||||
|
||||
enum class icmpv6_type : uint8_t
|
||||
{
|
||||
dest_unreachable = 0x1,
|
||||
packet_too_big = 0x2,
|
||||
time_exceeded = 0x3,
|
||||
parameter_problem = 0x4,
|
||||
echo_request = 0x80,
|
||||
echo_reply = 0x81,
|
||||
listener_query = 0x82,
|
||||
listener_report = 0x83,
|
||||
listener_done = 0x84,
|
||||
router_solicit = 0x85,
|
||||
router_advertise = 0x86,
|
||||
neighbor_solicit = 0x87,
|
||||
neighbor_advertise = 0x88,
|
||||
redirect = 0x89,
|
||||
listener_report_2 = 0x8f,
|
||||
};
|
||||
|
||||
enum class icmpv6_code : uint8_t
|
||||
{
|
||||
// codes for icmpv6_type::dest_unreachable
|
||||
no_route_to_dest = 0x0,
|
||||
comm_prohibited = 0x1,
|
||||
beyond_scope = 0x2,
|
||||
addr_unreachable = 0x3,
|
||||
port_unreachable = 0x4,
|
||||
source_addr_failed = 0x5,
|
||||
route_rejected = 0x6,
|
||||
|
||||
// codes for icmpv6_type::time_exceeded
|
||||
timeout_hop_limit = 0x0,
|
||||
timeout_reassemble = 0x1,
|
||||
|
||||
// codes for icmpv6_type::parameter_problem
|
||||
erroneous_header = 0x0,
|
||||
unrecognize_next_hdr = 0x1,
|
||||
unrecognize_option = 0x2,
|
||||
};
|
||||
|
||||
struct ip6_icmp_type
|
||||
{
|
||||
icmpv6_type type;
|
||||
icmpv6_code code;
|
||||
};
|
||||
|
||||
struct ip6_config_data
|
||||
{
|
||||
uint8_t default_protocol;
|
||||
bool accept_any_protocol;
|
||||
bool accept_icmp_errors;
|
||||
bool accept_promiscuous;
|
||||
ipv6_address destination_address;
|
||||
ipv6_address station_address;
|
||||
uint8_t traffic_class;
|
||||
uint8_t hop_limit;
|
||||
uint32_t flow_label;
|
||||
uint32_t receive_timeout;
|
||||
uint32_t transmit_timeout;
|
||||
};
|
||||
|
||||
struct ip6_mode_data
|
||||
{
|
||||
bool is_started;
|
||||
uint32_t max_packet_size;
|
||||
ip6_config_data config_data;
|
||||
bool is_configured;
|
||||
uint32_t address_count;
|
||||
ip6_address_info * address_list;
|
||||
uint32_t group_count;
|
||||
ipv6_address * group_table;
|
||||
uint32_t route_count;
|
||||
ip6_route_table * route_table;
|
||||
uint32_t neighbor_count;
|
||||
ip6_neighbor_cache * neighbor_cache;
|
||||
uint32_t prefix_count;
|
||||
ip6_address_info * prefix_table;
|
||||
uint32_t icmp_type_count;
|
||||
* icmp_type_list;
|
||||
};
|
||||
|
||||
struct ip6_header
|
||||
{
|
||||
uint8_t traffic_class_h : 4;
|
||||
uint8_t version : 4;
|
||||
uint8_t flow_label_h : 4;
|
||||
uint8_t traffic_class_l : 4;
|
||||
uint16_t flow_label_l;
|
||||
uint16_t payload_length;
|
||||
uint8_t next_header;
|
||||
uint8_t hop_limit;
|
||||
ipv6_address source_address;
|
||||
ipv6_address destination_address;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ip6_fragment_data
|
||||
{
|
||||
uint32_t fragment_length;
|
||||
void *fragment_buffer;
|
||||
};
|
||||
|
||||
struct ip6_override_data
|
||||
{
|
||||
uint8_t protocol;
|
||||
uint8_t hop_limit;
|
||||
uint32_t flow_label;
|
||||
};
|
||||
|
||||
struct ip6_receive_data
|
||||
{
|
||||
time time_stamp;
|
||||
event recycle_signal;
|
||||
uint32_t header_length;
|
||||
ip6_header *header;
|
||||
uint32_t data_length;
|
||||
uint32_t fragment_count;
|
||||
ip6_fragment_data fragment_table[1];
|
||||
};
|
||||
|
||||
struct ip6_transmit_data
|
||||
{
|
||||
ipv6_address destination_address;
|
||||
ip6_override_data *override_data;
|
||||
|
||||
uint32_t ext_hdrs_length;
|
||||
void *ext_hdrs;
|
||||
uint8_t next_header;
|
||||
uint32_t data_length;
|
||||
uint32_t fragment_count;
|
||||
ip6_fragment_data fragment_table[1];
|
||||
};
|
||||
|
||||
struct ip6_completion_token
|
||||
{
|
||||
event event;
|
||||
status status;
|
||||
union {
|
||||
ip6_receive_data *rx_data;
|
||||
ip6_transmit_data *tx_data;
|
||||
} packet;
|
||||
};
|
||||
|
||||
enum class ip6_config_data_type : int
|
||||
{
|
||||
interface_info,
|
||||
alt_interface_id,
|
||||
policy,
|
||||
dup_addr_detect_transmits,
|
||||
manual_address,
|
||||
gateway,
|
||||
dns_server,
|
||||
maximum
|
||||
};
|
||||
|
||||
struct ip6_config_interface_info
|
||||
{
|
||||
wchar_t name[32];
|
||||
uint8_t if_type;
|
||||
uint32_t hw_address_size;
|
||||
mac_address hw_address;
|
||||
uint32_t address_info_count;
|
||||
ip6_address_info *address_info;
|
||||
uint32_t route_count;
|
||||
ip6_route_table *route_table;
|
||||
};
|
||||
|
||||
struct ip6_config_interface_id
|
||||
{
|
||||
uint8_t id[8];
|
||||
};
|
||||
|
||||
enum class ip6_config_policy : int
|
||||
{
|
||||
manual,
|
||||
automatic
|
||||
};
|
||||
|
||||
struct ip6_config_dup_addr_detect_transmits
|
||||
{
|
||||
uint32_t dup_addr_detect_transmits;
|
||||
};
|
||||
|
||||
struct ip6_config_manual_address
|
||||
{
|
||||
ipv6_address address;
|
||||
bool is_anycast;
|
||||
uint8_t prefix_length;
|
||||
};
|
||||
|
||||
//
|
||||
// IP definitions
|
||||
//
|
||||
union ip_address
|
||||
{
|
||||
uint8_t addr[4];
|
||||
ipv4_address v4;
|
||||
ipv6_address v6;
|
||||
};
|
||||
|
||||
//
|
||||
// HTTP definitions
|
||||
//
|
||||
struct httpv4_access_point
|
||||
{
|
||||
bool use_default_address;
|
||||
ipv4_address local_address;
|
||||
ipv4_address local_subnet;
|
||||
uint16_t local_port;
|
||||
};
|
||||
|
||||
struct httpv6_access_point
|
||||
{
|
||||
ipv6_address local_address;
|
||||
uint16_t local_port;
|
||||
};
|
||||
|
||||
enum class http_version : int {
|
||||
v10,
|
||||
v11,
|
||||
unsupported,
|
||||
};
|
||||
|
||||
struct http_config_data
|
||||
{
|
||||
http_version http_version;
|
||||
uint32_t time_out_millisec;
|
||||
bool local_address_is_ipv6;
|
||||
union {
|
||||
httpv4_access_point *ipv4_node;
|
||||
httpv6_access_point *ipv6_node;
|
||||
} access_point;
|
||||
};
|
||||
|
||||
enum class http_method : int {
|
||||
get,
|
||||
post,
|
||||
patch,
|
||||
options,
|
||||
connect,
|
||||
head,
|
||||
put,
|
||||
delete_,
|
||||
trace,
|
||||
};
|
||||
|
||||
struct http_request_data
|
||||
{
|
||||
http_method method;
|
||||
wchar_t *url;
|
||||
};
|
||||
|
||||
enum class http_status_code : int {
|
||||
unsupported,
|
||||
continue_,
|
||||
switching_protocols,
|
||||
ok,
|
||||
created,
|
||||
accepted,
|
||||
non_authoritative_information,
|
||||
no_content,
|
||||
reset_content,
|
||||
partial_content,
|
||||
multiple_choices,
|
||||
moved_permanently,
|
||||
found,
|
||||
see_other,
|
||||
not_modified,
|
||||
use_proxy,
|
||||
temporary_redirect,
|
||||
bad_request,
|
||||
unauthorized,
|
||||
payment_required,
|
||||
forbidden,
|
||||
not_found,
|
||||
method_not_allowed,
|
||||
not_acceptable,
|
||||
proxy_authentication_required,
|
||||
request_time_out,
|
||||
conflict,
|
||||
gone,
|
||||
length_required,
|
||||
precondition_failed,
|
||||
request_entity_too_large,
|
||||
request_uri_too_large,
|
||||
unsupported_media_type,
|
||||
requested_range_not_satisfied,
|
||||
expectation_failed,
|
||||
internal_server_error,
|
||||
not_implemented,
|
||||
bad_gateway,
|
||||
service_unavailable,
|
||||
gateway_timeout,
|
||||
http_version_not_supported,
|
||||
permanent_redirect, // I hate your decisions, uefi.
|
||||
};
|
||||
|
||||
struct http_response_data
|
||||
{
|
||||
http_status_code status_code;
|
||||
};
|
||||
|
||||
struct http_header
|
||||
{
|
||||
char *field_name;
|
||||
char *field_value;
|
||||
};
|
||||
|
||||
struct http_message
|
||||
{
|
||||
union {
|
||||
http_request_data *request;
|
||||
http_response_data *response;
|
||||
} data;
|
||||
|
||||
size_t header_count;
|
||||
http_header *headers;
|
||||
|
||||
size_t body_length;
|
||||
void *body;
|
||||
};
|
||||
|
||||
struct http_token
|
||||
{
|
||||
event event;
|
||||
status status;
|
||||
http_message *message;
|
||||
};
|
||||
|
||||
|
||||
} // namespace uefi
|
||||
|
||||
#endif
|
||||
1
external/uefi/protos/device_path.h
vendored
1
external/uefi/protos/device_path.h
vendored
@@ -16,6 +16,7 @@ struct device_path
|
||||
{
|
||||
static constexpr uefi::guid guid{ 0x09576e91,0x6d3f,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
|
||||
|
||||
|
||||
uint8_t type;
|
||||
uint8_t sub_type;
|
||||
uint16_t length;
|
||||
|
||||
1
external/uefi/protos/file_info.h
vendored
1
external/uefi/protos/file_info.h
vendored
@@ -16,6 +16,7 @@ struct file_info
|
||||
{
|
||||
static constexpr uefi::guid guid{ 0x09576e92,0x6d3f,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
|
||||
|
||||
|
||||
uint64_t size;
|
||||
uint64_t file_size;
|
||||
uint64_t physical_size;
|
||||
|
||||
1
external/uefi/protos/graphics_output.h
vendored
1
external/uefi/protos/graphics_output.h
vendored
@@ -17,6 +17,7 @@ struct graphics_output
|
||||
{
|
||||
static constexpr uefi::guid guid{ 0x9042a9de,0x23dc,0x4a38,{0x96,0xfb,0x7a,0xde,0xd0,0x80,0x51,0x6a} };
|
||||
|
||||
|
||||
inline uefi::status query_mode(uint32_t mode_number, uint64_t * size_of_info, uefi::graphics_output_mode_info ** info) {
|
||||
return _query_mode(this, mode_number, size_of_info, info);
|
||||
}
|
||||
|
||||
72
external/uefi/protos/http.h
vendored
Normal file
72
external/uefi/protos/http.h
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
#ifndef _uefi_protos_http_h_
|
||||
#define _uefi_protos_http_h_
|
||||
|
||||
// This file was auto generated by the j6-uefi-headers project. Please see
|
||||
// https://github.com/justinian/j6-uefi-headers for more information.
|
||||
|
||||
#include <uefi/guid.h>
|
||||
#include <uefi/types.h>
|
||||
#include <uefi/networking.h>
|
||||
|
||||
namespace uefi {
|
||||
namespace protos {
|
||||
struct http;
|
||||
|
||||
struct http
|
||||
{
|
||||
static constexpr uefi::guid guid{ 0x7a59b29b,0x910b,0x4171,{0x82,0x42,0xa8,0x5a,0x0d,0xf2,0x5b,0x5b} };
|
||||
static constexpr uefi::guid service_binding{ 0xbdc8e6af,0xd9bc,0x4379,{0xa7,0x2a,0xe0,0xc4,0xe7,0x5d,0xae,0x1c} };
|
||||
|
||||
|
||||
inline uefi::status get_mode_data(uefi::http_config_data * http_config_data) {
|
||||
return _get_mode_data(this, http_config_data);
|
||||
}
|
||||
|
||||
inline uefi::status configure(uefi::http_config_data * http_config_data) {
|
||||
return _configure(this, http_config_data);
|
||||
}
|
||||
|
||||
inline uefi::status request(uefi::http_token * token) {
|
||||
return _request(this, token);
|
||||
}
|
||||
|
||||
inline uefi::status cancel(uefi::http_token * token) {
|
||||
return _cancel(this, token);
|
||||
}
|
||||
|
||||
inline uefi::status response(uefi::http_token * token) {
|
||||
return _response(this, token);
|
||||
}
|
||||
|
||||
inline uefi::status poll() {
|
||||
return _poll(this);
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
using _get_mode_data_def = uefi::status (*)(uefi::protos::http *, uefi::http_config_data *);
|
||||
_get_mode_data_def _get_mode_data;
|
||||
|
||||
using _configure_def = uefi::status (*)(uefi::protos::http *, uefi::http_config_data *);
|
||||
_configure_def _configure;
|
||||
|
||||
using _request_def = uefi::status (*)(uefi::protos::http *, uefi::http_token *);
|
||||
_request_def _request;
|
||||
|
||||
using _cancel_def = uefi::status (*)(uefi::protos::http *, uefi::http_token *);
|
||||
_cancel_def _cancel;
|
||||
|
||||
using _response_def = uefi::status (*)(uefi::protos::http *, uefi::http_token *);
|
||||
_response_def _response;
|
||||
|
||||
using _poll_def = uefi::status (*)(uefi::protos::http *);
|
||||
_poll_def _poll;
|
||||
|
||||
public:
|
||||
};
|
||||
|
||||
} // namespace protos
|
||||
} // namespace uefi
|
||||
|
||||
#endif // _uefi_protos_http_h_
|
||||
93
external/uefi/protos/ip6.h
vendored
Normal file
93
external/uefi/protos/ip6.h
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
#ifndef _uefi_protos_ip6_h_
|
||||
#define _uefi_protos_ip6_h_
|
||||
|
||||
// This file was auto generated by the j6-uefi-headers project. Please see
|
||||
// https://github.com/justinian/j6-uefi-headers for more information.
|
||||
|
||||
#include <uefi/guid.h>
|
||||
#include <uefi/types.h>
|
||||
#include <uefi/networking.h>
|
||||
|
||||
namespace uefi {
|
||||
namespace protos {
|
||||
struct ip6;
|
||||
|
||||
struct ip6
|
||||
{
|
||||
static constexpr uefi::guid guid{ 0x2c8759d5,0x5c2d,0x66ef,{0x92,0x5f,0xb6,0x6c,0x10,0x19,0x57,0xe2} };
|
||||
static constexpr uefi::guid service_binding{ 0xec835dd3,0xfe0f,0x617b,{0xa6,0x21,0xb3,0x50,0xc3,0xe1,0x33,0x88} };
|
||||
|
||||
|
||||
inline uefi::status get_mode_data(uefi::ip6_mode_data * ip6_mode_data, uefi::managed_network_config_data * mnp_config_data, uefi::simple_network_mode * snp_config_data) {
|
||||
return _get_mode_data(this, ip6_mode_data, mnp_config_data, snp_config_data);
|
||||
}
|
||||
|
||||
inline uefi::status configure(uefi::ip6_config_data * ip6_config_data) {
|
||||
return _configure(this, ip6_config_data);
|
||||
}
|
||||
|
||||
inline uefi::status groups(bool join_flag, uefi::ipv6_address * group_address) {
|
||||
return _groups(this, join_flag, group_address);
|
||||
}
|
||||
|
||||
inline uefi::status routes(bool delete_route, uefi::ipv6_address * destination, uint8_t prefix_length, uefi::ipv6_address * gateway_address) {
|
||||
return _routes(this, delete_route, destination, prefix_length, gateway_address);
|
||||
}
|
||||
|
||||
inline uefi::status neighbors(bool delete_flag, uefi::ipv6_address * target_ip6_address, uefi::mac_address * target_link_address, uint32_t timeout, bool override) {
|
||||
return _neighbors(this, delete_flag, target_ip6_address, target_link_address, timeout, override);
|
||||
}
|
||||
|
||||
inline uefi::status transmit(uefi::ip6_completion_token * token) {
|
||||
return _transmit(this, token);
|
||||
}
|
||||
|
||||
inline uefi::status receive(uefi::ip6_completion_token * token) {
|
||||
return _receive(this, token);
|
||||
}
|
||||
|
||||
inline uefi::status cancel(uefi::ip6_completion_token * token) {
|
||||
return _cancel(this, token);
|
||||
}
|
||||
|
||||
inline uefi::status poll() {
|
||||
return _poll(this);
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
using _get_mode_data_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_mode_data *, uefi::managed_network_config_data *, uefi::simple_network_mode *);
|
||||
_get_mode_data_def _get_mode_data;
|
||||
|
||||
using _configure_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_config_data *);
|
||||
_configure_def _configure;
|
||||
|
||||
using _groups_def = uefi::status (*)(uefi::protos::ip6 *, bool, uefi::ipv6_address *);
|
||||
_groups_def _groups;
|
||||
|
||||
using _routes_def = uefi::status (*)(uefi::protos::ip6 *, bool, uefi::ipv6_address *, uint8_t, uefi::ipv6_address *);
|
||||
_routes_def _routes;
|
||||
|
||||
using _neighbors_def = uefi::status (*)(uefi::protos::ip6 *, bool, uefi::ipv6_address *, uefi::mac_address *, uint32_t, bool);
|
||||
_neighbors_def _neighbors;
|
||||
|
||||
using _transmit_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_completion_token *);
|
||||
_transmit_def _transmit;
|
||||
|
||||
using _receive_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_completion_token *);
|
||||
_receive_def _receive;
|
||||
|
||||
using _cancel_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_completion_token *);
|
||||
_cancel_def _cancel;
|
||||
|
||||
using _poll_def = uefi::status (*)(uefi::protos::ip6 *);
|
||||
_poll_def _poll;
|
||||
|
||||
public:
|
||||
};
|
||||
|
||||
} // namespace protos
|
||||
} // namespace uefi
|
||||
|
||||
#endif // _uefi_protos_ip6_h_
|
||||
57
external/uefi/protos/ip6_config.h
vendored
Normal file
57
external/uefi/protos/ip6_config.h
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
#ifndef _uefi_protos_ip6_config_h_
|
||||
#define _uefi_protos_ip6_config_h_
|
||||
|
||||
// This file was auto generated by the j6-uefi-headers project. Please see
|
||||
// https://github.com/justinian/j6-uefi-headers for more information.
|
||||
|
||||
#include <uefi/guid.h>
|
||||
#include <uefi/types.h>
|
||||
#include <uefi/networking.h>
|
||||
|
||||
namespace uefi {
|
||||
namespace protos {
|
||||
struct ip6_config;
|
||||
|
||||
struct ip6_config
|
||||
{
|
||||
static constexpr uefi::guid guid{ 0x937fe521,0x95ae,0x4d1a,{0x89,0x29,0x48,0xbc,0xd9,0x0a,0xd3,0x1a} };
|
||||
|
||||
|
||||
inline uefi::status set_data(uefi::ip6_config_data_type data_type, size_t data_size, void * data) {
|
||||
return _set_data(this, data_type, data_size, data);
|
||||
}
|
||||
|
||||
inline uefi::status get_data(uefi::ip6_config_data_type data_type, size_t data_size, void * data) {
|
||||
return _get_data(this, data_type, data_size, data);
|
||||
}
|
||||
|
||||
inline uefi::status register_data_notify(uefi::ip6_config_data_type data_type, uefi::event event) {
|
||||
return _register_data_notify(this, data_type, event);
|
||||
}
|
||||
|
||||
inline uefi::status unregister_data_notify(uefi::ip6_config_data_type data_type, uefi::event event) {
|
||||
return _unregister_data_notify(this, data_type, event);
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
using _set_data_def = uefi::status (*)(uefi::protos::ip6_config *, uefi::ip6_config_data_type, size_t, void *);
|
||||
_set_data_def _set_data;
|
||||
|
||||
using _get_data_def = uefi::status (*)(uefi::protos::ip6_config *, uefi::ip6_config_data_type, size_t, void *);
|
||||
_get_data_def _get_data;
|
||||
|
||||
using _register_data_notify_def = uefi::status (*)(uefi::protos::ip6_config *, uefi::ip6_config_data_type, uefi::event);
|
||||
_register_data_notify_def _register_data_notify;
|
||||
|
||||
using _unregister_data_notify_def = uefi::status (*)(uefi::protos::ip6_config *, uefi::ip6_config_data_type, uefi::event);
|
||||
_unregister_data_notify_def _unregister_data_notify;
|
||||
|
||||
public:
|
||||
};
|
||||
|
||||
} // namespace protos
|
||||
} // namespace uefi
|
||||
|
||||
#endif // _uefi_protos_ip6_config_h_
|
||||
36
external/uefi/protos/load_file.h
vendored
Normal file
36
external/uefi/protos/load_file.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#ifndef _uefi_protos_load_file_h_
|
||||
#define _uefi_protos_load_file_h_
|
||||
|
||||
// This file was auto generated by the j6-uefi-headers project. Please see
|
||||
// https://github.com/justinian/j6-uefi-headers for more information.
|
||||
|
||||
#include <uefi/guid.h>
|
||||
#include <uefi/types.h>
|
||||
#include <uefi/protos/device_path.h>
|
||||
|
||||
namespace uefi {
|
||||
namespace protos {
|
||||
struct load_file;
|
||||
|
||||
struct load_file
|
||||
{
|
||||
static constexpr uefi::guid guid{ {0x56ec3091,0x954c,0x11d2,{0x8e,0x3f,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
|
||||
|
||||
|
||||
inline uefi::status load_file(uefi::protos::device_path * file_path, bool boot_policy, size_t * buffer_size, void * buffer) {
|
||||
return _load_file(this, file_path, boot_policy, buffer_size, buffer);
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
using _load_file_def = uefi::status (*)(uefi::protos::load_file *, uefi::protos::device_path *, bool, size_t *, void *);
|
||||
_load_file_def _load_file;
|
||||
|
||||
public:
|
||||
};
|
||||
|
||||
} // namespace protos
|
||||
} // namespace uefi
|
||||
|
||||
#endif // _uefi_protos_load_file_h_
|
||||
1
external/uefi/protos/loaded_image.h
vendored
1
external/uefi/protos/loaded_image.h
vendored
@@ -18,6 +18,7 @@ struct loaded_image
|
||||
{
|
||||
static constexpr uefi::guid guid{ 0x5b1b31a1,0x9562,0x11d2,{0x8e,0x3f,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
|
||||
|
||||
|
||||
inline uefi::status unload(uefi::handle image_handle) {
|
||||
return _unload(image_handle);
|
||||
}
|
||||
|
||||
41
external/uefi/protos/service_binding.h
vendored
Normal file
41
external/uefi/protos/service_binding.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#ifndef _uefi_protos_service_binding_h_
|
||||
#define _uefi_protos_service_binding_h_
|
||||
|
||||
// This file was auto generated by the j6-uefi-headers project. Please see
|
||||
// https://github.com/justinian/j6-uefi-headers for more information.
|
||||
|
||||
#include <uefi/guid.h>
|
||||
#include <uefi/types.h>
|
||||
|
||||
namespace uefi {
|
||||
namespace protos {
|
||||
struct service_binding;
|
||||
|
||||
struct service_binding
|
||||
{
|
||||
|
||||
|
||||
inline uefi::status create_child(uefi::handle * child_handle) {
|
||||
return _create_child(this, child_handle);
|
||||
}
|
||||
|
||||
inline uefi::status destroy_child(uefi::handle child_handle) {
|
||||
return _destroy_child(this, child_handle);
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
using _create_child_def = uefi::status (*)(uefi::protos::service_binding *, uefi::handle *);
|
||||
_create_child_def _create_child;
|
||||
|
||||
using _destroy_child_def = uefi::status (*)(uefi::protos::service_binding *, uefi::handle);
|
||||
_destroy_child_def _destroy_child;
|
||||
|
||||
public:
|
||||
};
|
||||
|
||||
} // namespace protos
|
||||
} // namespace uefi
|
||||
|
||||
#endif // _uefi_protos_service_binding_h_
|
||||
1
external/uefi/protos/simple_file_system.h
vendored
1
external/uefi/protos/simple_file_system.h
vendored
@@ -17,6 +17,7 @@ struct simple_file_system
|
||||
{
|
||||
static constexpr uefi::guid guid{ 0x0964e5b22,0x6459,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
|
||||
|
||||
|
||||
inline uefi::status open_volume(uefi::protos::file ** root) {
|
||||
return _open_volume(this, root);
|
||||
}
|
||||
|
||||
1
external/uefi/protos/simple_text_output.h
vendored
1
external/uefi/protos/simple_text_output.h
vendored
@@ -17,6 +17,7 @@ struct simple_text_output
|
||||
{
|
||||
static constexpr uefi::guid guid{ 0x387477c2,0x69c7,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
|
||||
|
||||
|
||||
inline uefi::status reset(bool extended_verification) {
|
||||
return _reset(this, extended_verification);
|
||||
}
|
||||
|
||||
277
modules.yaml
277
modules.yaml
@@ -6,54 +6,67 @@ modules:
|
||||
output: jsix.elf
|
||||
target: host
|
||||
deps:
|
||||
- elf
|
||||
- initrd
|
||||
- cpu
|
||||
- kutil
|
||||
includes:
|
||||
- src/kernel
|
||||
source:
|
||||
- src/kernel/crti.s
|
||||
- src/kernel/apic.cpp
|
||||
- src/kernel/ap_startup.s
|
||||
- src/kernel/assert.cpp
|
||||
- src/kernel/boot.s
|
||||
- src/kernel/clock.cpp
|
||||
- src/kernel/console.cpp
|
||||
- src/kernel/cpprt.cpp
|
||||
- src/kernel/cpu.cpp
|
||||
- src/kernel/debug.cpp
|
||||
- src/kernel/debug.s
|
||||
- src/kernel/device_manager.cpp
|
||||
- src/kernel/font.cpp
|
||||
- src/kernel/frame_allocator.cpp
|
||||
- src/kernel/fs/gpt.cpp
|
||||
- src/kernel/gdt.cpp
|
||||
- src/kernel/gdt.s
|
||||
- src/kernel/gdtidt.s
|
||||
- src/kernel/hpet.cpp
|
||||
- src/kernel/idt.cpp
|
||||
- src/kernel/interrupts.cpp
|
||||
- src/kernel/interrupts.s
|
||||
- src/kernel/io.cpp
|
||||
- src/kernel/loader.s
|
||||
- src/kernel/log.cpp
|
||||
- src/kernel/main.cpp
|
||||
- src/kernel/memory_bootstrap.cpp
|
||||
- src/kernel/msr.cpp
|
||||
- src/kernel/objects/handle.cpp
|
||||
- src/kernel/objects/channel.cpp
|
||||
- src/kernel/objects/endpoint.cpp
|
||||
- src/kernel/objects/kobject.cpp
|
||||
- src/kernel/page_manager.cpp
|
||||
- src/kernel/objects/thread.cpp
|
||||
- src/kernel/objects/process.cpp
|
||||
- src/kernel/objects/system.cpp
|
||||
- src/kernel/objects/vm_area.cpp
|
||||
- src/kernel/page_table.cpp
|
||||
- src/kernel/page_tree.cpp
|
||||
- src/kernel/pci.cpp
|
||||
- src/kernel/process.cpp
|
||||
- src/kernel/scheduler.cpp
|
||||
- src/kernel/screen.cpp
|
||||
- src/kernel/serial.cpp
|
||||
- src/kernel/symbol_table.cpp
|
||||
- src/kernel/syscall.cpp
|
||||
- src/kernel/syscall.s
|
||||
- src/kernel/syscalls/channel.cpp
|
||||
- src/kernel/syscalls/endpoint.cpp
|
||||
- src/kernel/syscalls/object.cpp
|
||||
- src/kernel/syscalls/process.cpp
|
||||
- src/kernel/syscalls/system.cpp
|
||||
- src/kernel/syscalls/thread.cpp
|
||||
- src/kernel/syscalls/vm_area.cpp
|
||||
- src/kernel/task.s
|
||||
- src/kernel/crtn.s
|
||||
- src/kernel/tss.cpp
|
||||
- src/kernel/vm_space.cpp
|
||||
|
||||
boot:
|
||||
kind: exe
|
||||
target: boot
|
||||
output: boot.efi
|
||||
deps:
|
||||
- cpu
|
||||
source:
|
||||
- src/boot/main.cpp
|
||||
- src/boot/console.cpp
|
||||
@@ -63,35 +76,31 @@ modules:
|
||||
- src/boot/loader.cpp
|
||||
- src/boot/memory.cpp
|
||||
- src/boot/paging.cpp
|
||||
- src/boot/status.cpp
|
||||
- src/boot/support.cpp
|
||||
|
||||
nulldrv:
|
||||
kind: exe
|
||||
target: user
|
||||
output: nulldrv
|
||||
output: nulldrv.elf
|
||||
deps:
|
||||
- libc
|
||||
source:
|
||||
- src/drivers/nulldrv/io.cpp
|
||||
- src/drivers/nulldrv/main.cpp
|
||||
- src/drivers/nulldrv/main.s
|
||||
- src/drivers/nulldrv/serial.cpp
|
||||
|
||||
elf:
|
||||
kind: lib
|
||||
output: libelf.a
|
||||
fb:
|
||||
kind: exe
|
||||
target: user
|
||||
output: fb.elf
|
||||
deps:
|
||||
- kutil
|
||||
includes:
|
||||
- src/libraries/elf/include
|
||||
- libc
|
||||
source:
|
||||
- src/libraries/elf/elf.cpp
|
||||
|
||||
initrd:
|
||||
kind: lib
|
||||
output: libinitrd.a
|
||||
deps:
|
||||
- kutil
|
||||
includes:
|
||||
- src/libraries/initrd/include
|
||||
source:
|
||||
- src/libraries/initrd/initrd.cpp
|
||||
- src/drivers/fb/font.cpp
|
||||
- src/drivers/fb/main.cpp
|
||||
- src/drivers/fb/screen.cpp
|
||||
- src/drivers/fb/scrollback.cpp
|
||||
|
||||
kutil:
|
||||
kind: lib
|
||||
@@ -105,17 +114,203 @@ modules:
|
||||
- src/libraries/kutil/logger.cpp
|
||||
- src/libraries/kutil/memory.cpp
|
||||
- src/libraries/kutil/printf.c
|
||||
- src/libraries/kutil/vm_space.cpp
|
||||
- src/libraries/kutil/spinlock.cpp
|
||||
|
||||
makerd:
|
||||
kind: exe
|
||||
target: native
|
||||
output: makerd
|
||||
deps:
|
||||
- initrd
|
||||
cpu:
|
||||
kind: lib
|
||||
output: libcpu.a
|
||||
includes:
|
||||
- src/libraries/cpu/include
|
||||
source:
|
||||
- src/tools/makerd/entry.cpp
|
||||
- src/tools/makerd/main.cpp
|
||||
- src/libraries/cpu/cpu_id.cpp
|
||||
|
||||
j6:
|
||||
kind: lib
|
||||
output: libj6.a
|
||||
includes:
|
||||
- src/libraries/j6/include
|
||||
target: user
|
||||
source:
|
||||
- src/libraries/j6/syscalls.s
|
||||
|
||||
libc:
|
||||
kind: lib
|
||||
output: libc.a
|
||||
includes:
|
||||
- src/libraries/libc/include
|
||||
deps:
|
||||
- j6
|
||||
target: user
|
||||
defines:
|
||||
- DISABLE_SSE
|
||||
- LACKS_UNISTD_H
|
||||
- LACKS_FCNTL_H
|
||||
- LACKS_SYS_PARAM_H
|
||||
- LACKS_SYS_MMAN_H
|
||||
- LACKS_SCHED_H
|
||||
- LACKS_STRINGS_H
|
||||
- HAVE_MMAP=0
|
||||
#- LACKS_STRING_H
|
||||
#- LACKS_ERRNO_H
|
||||
#- LACKS_STDLIB_H
|
||||
#- LACKS_TIME_H
|
||||
source:
|
||||
- src/libraries/libc/arch/x86_64/_Exit.s
|
||||
- src/libraries/libc/arch/x86_64/crt0.s
|
||||
- src/libraries/libc/arch/x86_64/init_libc.c
|
||||
- src/libraries/libc/ctype/isalnum.c
|
||||
- src/libraries/libc/ctype/isalpha.c
|
||||
- src/libraries/libc/ctype/isblank.c
|
||||
- src/libraries/libc/ctype/iscntrl.c
|
||||
- src/libraries/libc/ctype/isdigit.c
|
||||
- src/libraries/libc/ctype/isgraph.c
|
||||
- src/libraries/libc/ctype/islower.c
|
||||
- src/libraries/libc/ctype/isprint.c
|
||||
- src/libraries/libc/ctype/ispunct.c
|
||||
- src/libraries/libc/ctype/isspace.c
|
||||
- src/libraries/libc/ctype/isupper.c
|
||||
- src/libraries/libc/ctype/isxdigit.c
|
||||
- src/libraries/libc/ctype/tolower.c
|
||||
- src/libraries/libc/ctype/toupper.c
|
||||
- src/libraries/libc/inttypes/imaxabs.c
|
||||
- src/libraries/libc/inttypes/imaxdiv.c
|
||||
- src/libraries/libc/inttypes/strtoimax.c
|
||||
- src/libraries/libc/inttypes/strtoumax.c
|
||||
- src/libraries/libc/locale/localeconv.c
|
||||
- src/libraries/libc/locale/setlocale.c
|
||||
- src/libraries/libc/j6libc/assert.c
|
||||
- src/libraries/libc/j6libc/errno.c
|
||||
- src/libraries/libc/j6libc/allocpages.c
|
||||
- src/libraries/libc/j6libc/atomax.c
|
||||
- src/libraries/libc/j6libc/closeall.c
|
||||
- src/libraries/libc/j6libc/close.c
|
||||
- src/libraries/libc/j6libc/digits.c
|
||||
- src/libraries/libc/j6libc/filemode.c
|
||||
- src/libraries/libc/j6libc/fillbuffer.c
|
||||
- src/libraries/libc/j6libc/flushbuffer.c
|
||||
- src/libraries/libc/j6libc/is_leap.c
|
||||
- src/libraries/libc/j6libc/load_lc_collate.c
|
||||
- src/libraries/libc/j6libc/load_lc_ctype.c
|
||||
- src/libraries/libc/j6libc/load_lc_messages.c
|
||||
- src/libraries/libc/j6libc/load_lc_monetary.c
|
||||
- src/libraries/libc/j6libc/load_lc_numeric.c
|
||||
- src/libraries/libc/j6libc/load_lc_time.c
|
||||
- src/libraries/libc/j6libc/load_lines.c
|
||||
- src/libraries/libc/j6libc/open.c
|
||||
- src/libraries/libc/j6libc/prepread.c
|
||||
- src/libraries/libc/j6libc/prepwrite.c
|
||||
- src/libraries/libc/j6libc/print.c
|
||||
- src/libraries/libc/j6libc/rename.c
|
||||
- src/libraries/libc/j6libc/scan.c
|
||||
- src/libraries/libc/j6libc/seed.c
|
||||
- src/libraries/libc/j6libc/seek.c
|
||||
- src/libraries/libc/j6libc/stdinit.c
|
||||
- src/libraries/libc/j6libc/strtox_main.c
|
||||
- src/libraries/libc/j6libc/strtox_prelim.c
|
||||
- src/libraries/libc/j6libc/sbrk.c
|
||||
- src/libraries/libc/signal/raise.c
|
||||
- src/libraries/libc/signal/signal.c
|
||||
- src/libraries/libc/stdio/clearerr.c
|
||||
- src/libraries/libc/stdio/fclose.c
|
||||
- src/libraries/libc/stdio/feof.c
|
||||
- src/libraries/libc/stdio/ferror.c
|
||||
- src/libraries/libc/stdio/fflush.c
|
||||
- src/libraries/libc/stdio/fgetc.c
|
||||
- src/libraries/libc/stdio/fgetpos.c
|
||||
- src/libraries/libc/stdio/fgets.c
|
||||
- src/libraries/libc/stdio/fopen.c
|
||||
- src/libraries/libc/stdio/fprintf.c
|
||||
- src/libraries/libc/stdio/fputc.c
|
||||
- src/libraries/libc/stdio/fputs.c
|
||||
- src/libraries/libc/stdio/fread.c
|
||||
- src/libraries/libc/stdio/freopen.c
|
||||
- src/libraries/libc/stdio/fscanf.c
|
||||
- src/libraries/libc/stdio/fseek.c
|
||||
- src/libraries/libc/stdio/fsetpos.c
|
||||
- src/libraries/libc/stdio/ftell.c
|
||||
- src/libraries/libc/stdio/fwrite.c
|
||||
- src/libraries/libc/stdio/getc.c
|
||||
- src/libraries/libc/stdio/getchar.c
|
||||
- src/libraries/libc/stdio/perror.c
|
||||
- src/libraries/libc/stdio/printf.c
|
||||
- src/libraries/libc/stdio/putc.c
|
||||
- src/libraries/libc/stdio/putchar.c
|
||||
- src/libraries/libc/stdio/puts.c
|
||||
- src/libraries/libc/stdio/remove.c
|
||||
- src/libraries/libc/stdio/rename.c
|
||||
- src/libraries/libc/stdio/rewind.c
|
||||
- src/libraries/libc/stdio/scanf.c
|
||||
- src/libraries/libc/stdio/setbuf.c
|
||||
- src/libraries/libc/stdio/setvbuf.c
|
||||
- src/libraries/libc/stdio/snprintf.c
|
||||
- src/libraries/libc/stdio/sprintf.c
|
||||
- src/libraries/libc/stdio/sscanf.c
|
||||
- src/libraries/libc/stdio/tmpfile.c
|
||||
- src/libraries/libc/stdio/tmpnam.c
|
||||
- src/libraries/libc/stdio/ungetc.c
|
||||
- src/libraries/libc/stdio/vfprintf.c
|
||||
- src/libraries/libc/stdio/vfscanf.c
|
||||
- src/libraries/libc/stdio/vprintf.c
|
||||
- src/libraries/libc/stdio/vscanf.c
|
||||
- src/libraries/libc/stdio/vsnprintf.c
|
||||
- src/libraries/libc/stdio/vsprintf.c
|
||||
- src/libraries/libc/stdio/vsscanf.c
|
||||
- src/libraries/libc/stdlib/abort.c
|
||||
- src/libraries/libc/stdlib/abs.c
|
||||
- src/libraries/libc/stdlib/atexit.c
|
||||
- src/libraries/libc/stdlib/atoi.c
|
||||
- src/libraries/libc/stdlib/atol.c
|
||||
- src/libraries/libc/stdlib/atoll.c
|
||||
- src/libraries/libc/stdlib/bsearch.c
|
||||
- src/libraries/libc/stdlib/div.c
|
||||
- src/libraries/libc/stdlib/exit.c
|
||||
- src/libraries/libc/stdlib/_Exit.c
|
||||
- src/libraries/libc/stdlib/getenv.c
|
||||
- src/libraries/libc/stdlib/labs.c
|
||||
- src/libraries/libc/stdlib/ldiv.c
|
||||
- src/libraries/libc/stdlib/llabs.c
|
||||
- src/libraries/libc/stdlib/lldiv.c
|
||||
- src/libraries/libc/stdlib/malloc.c
|
||||
- src/libraries/libc/stdlib/qsort.c
|
||||
- src/libraries/libc/stdlib/rand.c
|
||||
- src/libraries/libc/stdlib/srand.c
|
||||
- src/libraries/libc/stdlib/strtol.c
|
||||
- src/libraries/libc/stdlib/strtoll.c
|
||||
- src/libraries/libc/stdlib/strtoul.c
|
||||
- src/libraries/libc/stdlib/strtoull.c
|
||||
- src/libraries/libc/stdlib/system.c
|
||||
- src/libraries/libc/string/memchr.c
|
||||
- src/libraries/libc/string/memcmp.c
|
||||
- src/libraries/libc/string/memcpy.c
|
||||
- src/libraries/libc/string/memmove.c
|
||||
- src/libraries/libc/string/memset.c
|
||||
- src/libraries/libc/string/strcat.c
|
||||
- src/libraries/libc/string/strchr.c
|
||||
- src/libraries/libc/string/strcmp.c
|
||||
- src/libraries/libc/string/strcoll.c
|
||||
- src/libraries/libc/string/strcpy.c
|
||||
- src/libraries/libc/string/strcspn.c
|
||||
- src/libraries/libc/string/strerror.c
|
||||
- src/libraries/libc/string/strlen.c
|
||||
- src/libraries/libc/string/strncat.c
|
||||
- src/libraries/libc/string/strncmp.c
|
||||
- src/libraries/libc/string/strncpy.c
|
||||
- src/libraries/libc/string/strpbrk.c
|
||||
- src/libraries/libc/string/strrchr.c
|
||||
- src/libraries/libc/string/strspn.c
|
||||
- src/libraries/libc/string/strstr.c
|
||||
- src/libraries/libc/string/strtok.c
|
||||
- src/libraries/libc/string/strxfrm.c
|
||||
- src/libraries/libc/time/asctime.c
|
||||
- src/libraries/libc/time/clock.c
|
||||
- src/libraries/libc/time/ctime.c
|
||||
- src/libraries/libc/time/difftime.c
|
||||
- src/libraries/libc/time/gmtime.c
|
||||
- src/libraries/libc/time/localtime.c
|
||||
- src/libraries/libc/time/mktime.c
|
||||
- src/libraries/libc/time/strftime.c
|
||||
- src/libraries/libc/time/time.c
|
||||
- src/libraries/libc/time/timespec_get.c
|
||||
|
||||
tests:
|
||||
kind: exe
|
||||
@@ -124,12 +319,14 @@ modules:
|
||||
deps:
|
||||
- kutil
|
||||
source:
|
||||
- src/tests/address_manager.cpp
|
||||
- src/tests/constexpr_hash.cpp
|
||||
- src/tests/linked_list.cpp
|
||||
- src/tests/logger.cpp
|
||||
- src/tests/heap_allocator.cpp
|
||||
- src/tests/main.cpp
|
||||
- src/tests/map.cpp
|
||||
- src/tests/vector.cpp
|
||||
|
||||
overlays:
|
||||
- url: https://f000.backblazeb2.com/file/jsix-os/sysroot-llvm8-20190706.tar.bz2
|
||||
path: sysroot
|
||||
|
||||
11
qemu.sh
11
qemu.sh
@@ -6,6 +6,7 @@ debug=""
|
||||
debugtarget="${build}/jsix.elf"
|
||||
flash_name="ovmf_vars"
|
||||
gfx="-nographic"
|
||||
vga="-vga none"
|
||||
kvm=""
|
||||
cpu="Broadwell,+pdpe1gb"
|
||||
|
||||
@@ -22,6 +23,10 @@ for arg in $@; do
|
||||
;;
|
||||
--gfx)
|
||||
gfx=""
|
||||
vga=""
|
||||
;;
|
||||
--vga)
|
||||
vga=""
|
||||
;;
|
||||
--kvm)
|
||||
kvm="-enable-kvm"
|
||||
@@ -45,6 +50,8 @@ if [[ -n $TMUX ]]; then
|
||||
if [[ -n $debug ]]; then
|
||||
tmux split-window -h "gdb ${debugtarget}" &
|
||||
else
|
||||
tmux split-window -h -l 80 "sleep 1; telnet localhost 45455" &
|
||||
tmux last-pane
|
||||
tmux split-window -l 10 "sleep 1; telnet localhost 45454" &
|
||||
fi
|
||||
elif [[ $DESKTOP_SESSION = "i3" ]]; then
|
||||
@@ -61,6 +68,8 @@ exec qemu-system-x86_64 \
|
||||
-drive "format=raw,file=${build}/jsix.img" \
|
||||
-device "isa-debug-exit,iobase=0xf4,iosize=0x04" \
|
||||
-monitor telnet:localhost:45454,server,nowait \
|
||||
-serial stdio \
|
||||
-serial telnet:localhost:45455,server,nowait \
|
||||
-smp 4 \
|
||||
-m 512 \
|
||||
-d mmu,int,guest_errors \
|
||||
@@ -68,4 +77,4 @@ exec qemu-system-x86_64 \
|
||||
-cpu "${cpu}" \
|
||||
-M q35 \
|
||||
-no-reboot \
|
||||
$gfx $kvm $debug
|
||||
$gfx $vga $kvm $debug
|
||||
|
||||
75
scripts/build_symbol_table.py
Executable file
75
scripts/build_symbol_table.py
Executable file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Generate the jsix style symbol table. The format in memory of this table
|
||||
# is as follows:
|
||||
#
|
||||
# <num_entires> : 8 bytes
|
||||
# <index> : 16 * N bytes
|
||||
# <name data> : variable
|
||||
#
|
||||
# Each index entry has the format
|
||||
# <symbol address> : 8 bytes
|
||||
# <offset of name> : 8 bytes
|
||||
#
|
||||
# Name offsets are from the start of the symbol table as a whole. (ie,
|
||||
# where <num_entries> is located.)
|
||||
|
||||
def parse_syms(infile):
|
||||
"""Take the output of the `nm` command, and parse it into a tuple
|
||||
representing the symbols in the text segment of the binary. Returns
|
||||
a list of (address, symbol_name)."""
|
||||
|
||||
from cxxfilt import demangle, InvalidName
|
||||
|
||||
syms = []
|
||||
for line in sys.stdin:
|
||||
addr, t, mangled = line.split()
|
||||
if t not in "tTvVwW": continue
|
||||
|
||||
try:
|
||||
name = demangle(mangled)
|
||||
except InvalidName:
|
||||
continue
|
||||
|
||||
addr = int(addr, base=16)
|
||||
syms.append((addr, name))
|
||||
|
||||
return sorted(syms)
|
||||
|
||||
|
||||
def write_table(syms, outfile):
|
||||
"""Write the given symbol table as generated by parse_syms()
|
||||
to the outfile, index first, and then name character data."""
|
||||
|
||||
import struct
|
||||
|
||||
outfile.write(struct.pack("@Q", len(syms)))
|
||||
index_pos = outfile.tell()
|
||||
|
||||
outfile.seek(struct.calcsize("@QQ") * len(syms), 1)
|
||||
nul = b'\0'
|
||||
|
||||
positions = {}
|
||||
for s in syms:
|
||||
addr, name = s
|
||||
positions[addr] = outfile.tell()
|
||||
|
||||
data = name.encode('utf-8')
|
||||
outfile.write(name.encode('utf-8'))
|
||||
outfile.write(nul)
|
||||
|
||||
outfile.seek(index_pos)
|
||||
for s in syms:
|
||||
addr = s[0]
|
||||
pos = positions[addr]
|
||||
outfile.write(struct.pack("@QQ", addr, pos))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
if len(sys.argv) != 2:
|
||||
print(f"Usage: {sys.argv[0]} <output>")
|
||||
sys.exit(1)
|
||||
|
||||
outfile = open(sys.argv[1], "wb")
|
||||
write_table(parse_syms(sys.stdin), outfile)
|
||||
75
scripts/fontpsf.py
Normal file
75
scripts/fontpsf.py
Normal file
@@ -0,0 +1,75 @@
|
||||
_MAGIC = (0x72, 0xb5, 0x4a, 0x86)
|
||||
_VERSION = 0
|
||||
|
||||
class PSF2:
|
||||
from collections import namedtuple
|
||||
Header = namedtuple("PSF2Header",
|
||||
["version", "offset", "flags", "count", "charsize", "height", "width"])
|
||||
|
||||
def __init__(self, filename, header, data):
|
||||
self.__filename = filename
|
||||
self.__header = header
|
||||
self.__data = data
|
||||
|
||||
data = property(lambda self: self.__data)
|
||||
header = property(lambda self: self.__header)
|
||||
count = property(lambda self: self.__header.count)
|
||||
charsize = property(lambda self: self.__header.charsize)
|
||||
dimension = property(lambda self: (self.__header.width, self.__header.height))
|
||||
filename = property(lambda self: self.__filename)
|
||||
|
||||
@classmethod
|
||||
def load(cls, filename):
|
||||
from os.path import basename
|
||||
from struct import unpack_from
|
||||
|
||||
data = open(filename, 'rb').read()
|
||||
|
||||
fmt = "BBBBIIIIIII"
|
||||
values = unpack_from(fmt, data)
|
||||
|
||||
if values[:len(_MAGIC)] != _MAGIC:
|
||||
raise Exception("Bad magic number in header")
|
||||
|
||||
header = PSF2.Header(*values[len(_MAGIC):])
|
||||
if header.version != _VERSION:
|
||||
raise Exception(f"Bad version {header.version} in header")
|
||||
|
||||
return cls(basename(filename), header, data)
|
||||
|
||||
class Glyph:
|
||||
__slots__ = ['index', 'data']
|
||||
def __init__(self, i, data):
|
||||
self.index = i
|
||||
self.data = data
|
||||
def __index__(self):
|
||||
return self.index
|
||||
def empty(self):
|
||||
return not bool([b for b in self.data if b != 0])
|
||||
def description(self):
|
||||
c = chr(self.index)
|
||||
if c.isprintable():
|
||||
return "Glyph {:02x}: '{}'".format(self.index, c)
|
||||
else:
|
||||
return "Glyph {:02x}".format(self.index)
|
||||
|
||||
def __getitem__(self, i):
|
||||
c = self.__header.charsize
|
||||
n = i * c + self.__header.offset
|
||||
return PSF2.Glyph(i, self.__data[n:n+c])
|
||||
|
||||
class __iter:
|
||||
__slots__ = ['font', 'n']
|
||||
def __init__(self, font):
|
||||
self.font = font
|
||||
self.n = 0
|
||||
def __next__(self):
|
||||
if self.n < self.font.count:
|
||||
glyph = self.font[self.n]
|
||||
self.n += 1
|
||||
return glyph
|
||||
else:
|
||||
raise StopIteration
|
||||
|
||||
def __iter__(self):
|
||||
return PSF2.__iter(self)
|
||||
34
scripts/parse_font.py
Normal file → Executable file
34
scripts/parse_font.py
Normal file → Executable file
@@ -1,21 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
MAGIC = (0x72, 0xb5, 0x4a, 0x86)
|
||||
|
||||
from collections import namedtuple
|
||||
PSF2 = namedtuple("PSF2", ["version", "offset", "flags", "count", "charsize", "height", "width"])
|
||||
|
||||
def read_header(data):
|
||||
from struct import unpack_from, calcsize
|
||||
|
||||
fmt = "BBBBIIIIIII"
|
||||
|
||||
values = unpack_from(fmt, data)
|
||||
if values[:len(MAGIC)] != MAGIC:
|
||||
raise Exception("Bad magic number in header")
|
||||
|
||||
return PSF2(*values[len(MAGIC):])
|
||||
|
||||
from fontpsf import PSF2
|
||||
|
||||
def print_glyph(header, data):
|
||||
bw = (header.width + 7) // 8
|
||||
@@ -28,16 +13,15 @@ def print_glyph(header, data):
|
||||
|
||||
|
||||
def display_font(filename):
|
||||
data = open(filename, 'rb').read()
|
||||
font = PSF2.load(filename)
|
||||
print(font.header)
|
||||
|
||||
header = read_header(data)
|
||||
print(header)
|
||||
|
||||
c = header.charsize
|
||||
for i in range(0, header.count):
|
||||
n = i * c + header.offset
|
||||
print("Glyph {}:".format(i))
|
||||
print_glyph(header, data[n:n+c])
|
||||
for glyph in font:
|
||||
if glyph.empty():
|
||||
print("{}: BLANK".format(glyph.description()))
|
||||
else:
|
||||
print("{}:".format(glyph.description()))
|
||||
print_glyph(font.header, glyph.data)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
27
scripts/psf_to_cpp.py
Executable file
27
scripts/psf_to_cpp.py
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from fontpsf import PSF2
|
||||
|
||||
def print_header(filename):
|
||||
font = PSF2.load(filename)
|
||||
|
||||
print("#pragma once")
|
||||
print(f"// This file was autogenerated by psf_to_cpp.py from {font.filename}\n")
|
||||
|
||||
print(f"const uint8_t font_glyph_size = {font.charsize};")
|
||||
print(f"const uint8_t font_glyph_width = {font.dimension[0]};")
|
||||
print(f"const uint8_t font_glyph_height = {font.dimension[1]};")
|
||||
print(f"const uint16_t font_glyph_count = {font.count};\n")
|
||||
|
||||
print('const uint8_t font_glyph_data[] = {')
|
||||
|
||||
for glyph in font:
|
||||
print(" ", "".join([f"0x{b:02x}," for b in glyph.data]), end="")
|
||||
print(" // {}".format(glyph.description()))
|
||||
|
||||
print("};")
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
for filename in sys.argv[1:]:
|
||||
print_header(filename)
|
||||
@@ -47,10 +47,11 @@ asflags = $
|
||||
-DVERSION_MAJOR={{ version_major }} $
|
||||
-DVERSION_MINOR={{ version_minor }} $
|
||||
-DVERSION_PATCH={{ version_patch }} $
|
||||
-DVERSION_GITSHA=0x{{ version_sha }}
|
||||
-DVERSION_GITSHA=0x{{ version_sha }} $
|
||||
-I${srcroot}/src/include
|
||||
|
||||
cflags = -std=c11
|
||||
cxxflags = -std=c++14
|
||||
cxxflags = -std=c++17
|
||||
libs =
|
||||
|
||||
rule c
|
||||
@@ -67,7 +68,7 @@ rule dump_c_run
|
||||
description = Dumping C arguments for $target
|
||||
command = $
|
||||
echo "#!/bin/bash" > $out; $
|
||||
echo '$cc $ccflags $cflags $$*' > $out; $
|
||||
echo '$cc $ccflags $cflags $$*' >> $out; $
|
||||
chmod a+x $out
|
||||
|
||||
rule cpp
|
||||
@@ -84,7 +85,7 @@ rule dump_cpp_run
|
||||
description = Dumping C++ arguments for $target
|
||||
command = $
|
||||
echo "#!/bin/bash" > $out; $
|
||||
echo '$cc $cxxflags $ccflags $$*' > $out; $
|
||||
echo '$cc $cxxflags $ccflags $$*' >> $out; $
|
||||
chmod a+x $out
|
||||
|
||||
rule s
|
||||
@@ -118,9 +119,9 @@ rule dump
|
||||
description = Dumping decompiled $name
|
||||
command = objdump -DSC -M intel $in > $out
|
||||
|
||||
rule makerd
|
||||
description = Making init ramdisk
|
||||
command = $builddir/native/makerd $in $out
|
||||
rule makest
|
||||
description = Making symbol table
|
||||
command = nm $in | ${srcroot}/scripts/build_symbol_table.py $out
|
||||
|
||||
rule makeefi
|
||||
description = Converting $name
|
||||
@@ -186,12 +187,18 @@ build $builddir/fatroot/jsix.elf : cp $builddir/jsix.elf
|
||||
build $builddir/fatroot/efi/boot/bootx64.efi : cp $builddir/boot/boot.efi
|
||||
name = bootloader to FAT image
|
||||
|
||||
build $builddir/fatroot/initrd.img : makerd ${srcroot}/assets/initrd.toml | $
|
||||
${builddir}/native/makerd $
|
||||
${builddir}/user/nulldrv
|
||||
build $builddir/fatroot/nulldrv.elf : cp $builddir/user/nulldrv.elf
|
||||
name = null driver to FAT image
|
||||
|
||||
build $builddir/fatroot/fb.elf : cp $builddir/user/fb.elf
|
||||
name = fb driver to FAT image
|
||||
|
||||
build ${builddir}/fatroot/symbol_table.dat : makest ${builddir}/jsix.elf
|
||||
|
||||
build $builddir/jsix.img : makefat | $
|
||||
$builddir/fatroot/initrd.img $
|
||||
$builddir/fatroot/symbol_table.dat $
|
||||
$builddir/fatroot/nulldrv.elf $
|
||||
$builddir/fatroot/fb.elf $
|
||||
$builddir/fatroot/jsix.elf $
|
||||
$builddir/fatroot/efi/boot/bootx64.efi
|
||||
name = jsix.img
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
asflags = $asflags -I${srcroot}/src/kernel/
|
||||
libs = $libs
|
||||
ldflags = $ldflags -T ${srcroot}/src/arch/x86_64/kernel.ld
|
||||
ccflags = $ccflags -I${srcroot}/external
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -22,5 +22,10 @@ build ${builddir}/cpp.defs : dump_cpp_defs | {{ buildfile }}
|
||||
build ${builddir}/c.run : dump_c_run | {{ buildfile }}
|
||||
build ${builddir}/cpp.run : dump_cpp_run | {{ buildfile }}
|
||||
|
||||
default ${builddir}/c.defs
|
||||
default ${builddir}/cpp.defs
|
||||
default ${builddir}/c.run
|
||||
default ${builddir}/cpp.run
|
||||
|
||||
# vim: ft=ninja et ts=4 sts=4 sw=4
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ ccflags = $ccflags $
|
||||
-D__ELF__ $
|
||||
-D__JSIX__ $
|
||||
-isystem${srcroot}/sysroot/include $
|
||||
-isystem${srcroot}/src/libraries/libc/include $
|
||||
--sysroot="${srcroot}/sysroot"
|
||||
|
||||
cxxflags = $cxxflags $
|
||||
|
||||
@@ -23,6 +23,7 @@ ccflags = $ccflags $
|
||||
-D__ELF__ $
|
||||
-D__JSIX__ $
|
||||
-isystem${srcroot}/sysroot/include $
|
||||
-isystem${srcroot}/src/libraries/libc/include $
|
||||
--sysroot="${srcroot}/sysroot"
|
||||
|
||||
cxxflags = $cxxflags $
|
||||
@@ -38,9 +39,6 @@ ldflags = $ldflags $
|
||||
--sysroot="${srcroot}/sysroot" $
|
||||
-L "${srcroot}/sysroot/lib" $
|
||||
|
||||
libs = $libs $
|
||||
-lc
|
||||
|
||||
{% endblock %}
|
||||
|
||||
# vim: ft=ninja et ts=4 sts=4 sw=4
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
ENTRY(_start)
|
||||
ENTRY(_kernel_start)
|
||||
SECTIONS
|
||||
{
|
||||
OFFSET = 0xFFFF800000000000;
|
||||
. = OFFSET + 0x100000;
|
||||
. = 0xFFFF800000000000;
|
||||
|
||||
.header : {
|
||||
__header_start = .;
|
||||
@@ -20,6 +19,12 @@ SECTIONS
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
.ctors : ALIGN(8) {
|
||||
__ctors = .;
|
||||
KEEP(*(.ctors))
|
||||
__ctors_end = .;
|
||||
}
|
||||
|
||||
.bss ALIGN(4096) : {
|
||||
__bss_start = .;
|
||||
*(.bss)
|
||||
|
||||
@@ -17,23 +17,7 @@ namespace boot {
|
||||
size_t ROWS = 0;
|
||||
size_t COLS = 0;
|
||||
|
||||
static constexpr int level_ok = 0;
|
||||
static constexpr int level_warn = 1;
|
||||
static constexpr int level_fail = 2;
|
||||
|
||||
static const wchar_t *level_tags[] = {
|
||||
L" ok ",
|
||||
L" warn ",
|
||||
L"failed"
|
||||
};
|
||||
static const uefi::attribute level_colors[] = {
|
||||
uefi::attribute::green,
|
||||
uefi::attribute::brown,
|
||||
uefi::attribute::light_red
|
||||
};
|
||||
|
||||
console *console::s_console = nullptr;
|
||||
status_line *status_line::s_current = nullptr;
|
||||
|
||||
static const wchar_t digits[] = {u'0', u'1', u'2', u'3', u'4', u'5',
|
||||
u'6', u'7', u'8', u'9', u'a', u'b', u'c', u'd', u'e', u'f'};
|
||||
@@ -49,9 +33,10 @@ wstrlen(const wchar_t *s)
|
||||
|
||||
|
||||
console::console(uefi::boot_services *bs, uefi::protos::simple_text_output *out) :
|
||||
m_rows(0),
|
||||
m_cols(0),
|
||||
m_out(out)
|
||||
m_rows {0},
|
||||
m_cols {0},
|
||||
m_out {out},
|
||||
m_fb {0, 0}
|
||||
{
|
||||
pick_mode(bs);
|
||||
|
||||
@@ -70,7 +55,26 @@ console::console(uefi::boot_services *bs, uefi::protos::simple_text_output *out)
|
||||
m_out->output_string(GIT_VERSION_WIDE);
|
||||
|
||||
m_out->set_attribute(uefi::attribute::light_gray);
|
||||
m_out->output_string(L" booting...\r\n\n");
|
||||
m_out->output_string(L" booting...\r\n");
|
||||
|
||||
if (m_fb.type != kernel::args::fb_type::none) {
|
||||
wchar_t const * type = nullptr;
|
||||
switch (m_fb.type) {
|
||||
case kernel::args::fb_type::rgb8:
|
||||
type = L"rgb8";
|
||||
break;
|
||||
case kernel::args::fb_type::bgr8:
|
||||
type = L"bgr8";
|
||||
break;
|
||||
default:
|
||||
type = L"unknown";
|
||||
}
|
||||
|
||||
printf(L"Found framebuffer: %dx%d[%d] type %s @0x%x\r\n",
|
||||
m_fb.horizontal, m_fb.vertical, m_fb.scanline, type, m_fb.phys_addr);
|
||||
} else {
|
||||
printf(L"No framebuffer found.\r\n");
|
||||
}
|
||||
|
||||
s_console = this;
|
||||
}
|
||||
@@ -82,9 +86,14 @@ console::pick_mode(uefi::boot_services *bs)
|
||||
uefi::protos::graphics_output *gfx_out_proto;
|
||||
uefi::guid guid = uefi::protos::graphics_output::guid;
|
||||
|
||||
try_or_raise(
|
||||
bs->locate_protocol(&guid, nullptr, (void **)&gfx_out_proto),
|
||||
L"Failed to find a Graphics Output Protocol handle");
|
||||
m_fb.type = kernel::args::fb_type::none;
|
||||
|
||||
uefi::status has_gop = bs->locate_protocol(&guid, nullptr,
|
||||
(void **)&gfx_out_proto);
|
||||
|
||||
if (has_gop != uefi::status::success)
|
||||
// No video output found, skip it
|
||||
return;
|
||||
|
||||
const uint32_t modes = gfx_out_proto->mode->max_mode;
|
||||
uint32_t best = gfx_out_proto->mode->mode;
|
||||
@@ -93,7 +102,7 @@ console::pick_mode(uefi::boot_services *bs)
|
||||
(uefi::graphics_output_mode_info *)gfx_out_proto->mode;
|
||||
|
||||
uint32_t res = info->horizontal_resolution * info->vertical_resolution;
|
||||
int is_fb = info->pixel_format != uefi::pixel_format::blt_only;
|
||||
int pixmode = static_cast<int>(info->pixel_format);
|
||||
|
||||
for (uint32_t i = 0; i < modes; ++i) {
|
||||
size_t size = 0;
|
||||
@@ -107,17 +116,37 @@ console::pick_mode(uefi::boot_services *bs)
|
||||
#endif
|
||||
|
||||
const uint32_t new_res = info->horizontal_resolution * info->vertical_resolution;
|
||||
const int new_is_fb = info->pixel_format != uefi::pixel_format::blt_only;
|
||||
int new_pixmode = static_cast<int>(info->pixel_format);
|
||||
|
||||
if (new_is_fb > is_fb && new_res >= res) {
|
||||
if (new_pixmode <= pixmode && new_res >= res) {
|
||||
best = i;
|
||||
res = new_res;
|
||||
pixmode = new_pixmode;
|
||||
}
|
||||
}
|
||||
|
||||
try_or_raise(
|
||||
gfx_out_proto->set_mode(best),
|
||||
L"Failed to set graphics mode");
|
||||
|
||||
if (pixmode <= static_cast<int>(uefi::pixel_format::bgr8)) {
|
||||
m_fb.phys_addr = gfx_out_proto->mode->frame_buffer_base;
|
||||
m_fb.size = gfx_out_proto->mode->frame_buffer_size;
|
||||
m_fb.vertical = gfx_out_proto->mode->info->vertical_resolution;
|
||||
m_fb.horizontal = gfx_out_proto->mode->info->horizontal_resolution;
|
||||
m_fb.scanline = gfx_out_proto->mode->info->pixels_per_scanline;
|
||||
|
||||
switch (gfx_out_proto->mode->info->pixel_format) {
|
||||
case uefi::pixel_format::rgb8:
|
||||
m_fb.type = kernel::args::fb_type::rgb8;
|
||||
break;
|
||||
case uefi::pixel_format::bgr8:
|
||||
m_fb.type = kernel::args::fb_type::bgr8;
|
||||
break;
|
||||
default:
|
||||
m_fb.type = kernel::args::fb_type::none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
@@ -272,176 +301,4 @@ console::print(const wchar_t *fmt, ...)
|
||||
return result;
|
||||
}
|
||||
|
||||
status_line::status_line(const wchar_t *message, const wchar_t *context) :
|
||||
m_level(level_ok)
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
m_line = out->mode->cursor_row;
|
||||
m_depth = (s_current ? 1 + s_current->m_depth : 0);
|
||||
|
||||
int indent = 2 * m_depth;
|
||||
out->set_cursor_position(indent, m_line);
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(message);
|
||||
|
||||
if (context) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(context);
|
||||
}
|
||||
|
||||
out->output_string(L"\r\n");
|
||||
|
||||
m_next = s_current;
|
||||
s_current = this;
|
||||
}
|
||||
|
||||
status_line::~status_line()
|
||||
{
|
||||
if (s_current != this)
|
||||
error::raise(uefi::status::unsupported, L"Destroying non-current status_line");
|
||||
|
||||
finish();
|
||||
if (m_next && m_level > m_next->m_level) {
|
||||
m_next->m_level = m_level;
|
||||
m_next->print_status_tag();
|
||||
}
|
||||
s_current = m_next;
|
||||
}
|
||||
|
||||
void
|
||||
status_line::print_status_tag()
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
int col = out->mode->cursor_column;
|
||||
|
||||
uefi::attribute color = level_colors[m_level];
|
||||
const wchar_t *tag = level_tags[m_level];
|
||||
|
||||
out->set_cursor_position(50, m_line);
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"[");
|
||||
out->set_attribute(color);
|
||||
out->output_string(tag);
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"]\r\n");
|
||||
|
||||
out->set_cursor_position(col, row);
|
||||
}
|
||||
|
||||
void
|
||||
status_line::do_warn(const wchar_t *message, const wchar_t *error)
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
|
||||
if (m_level < level_warn) {
|
||||
m_level = level_warn;
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
int indent = 2 + 2 * m_depth;
|
||||
out->set_cursor_position(indent, row);
|
||||
out->set_attribute(uefi::attribute::yellow);
|
||||
out->output_string(message);
|
||||
|
||||
if (error) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(error);
|
||||
}
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"\r\n");
|
||||
}
|
||||
|
||||
void
|
||||
status_line::do_fail(const wchar_t *message, const wchar_t *error)
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
|
||||
if (s_current->m_level < level_fail) {
|
||||
m_level = level_fail;
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
int indent = 2 + 2 * m_depth;
|
||||
out->set_cursor_position(indent, row);
|
||||
out->set_attribute(uefi::attribute::red);
|
||||
out->output_string(message);
|
||||
|
||||
if (error) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(error);
|
||||
}
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"\r\n");
|
||||
}
|
||||
|
||||
void
|
||||
status_line::finish()
|
||||
{
|
||||
if (m_level <= level_ok)
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
/*
|
||||
uefi::status
|
||||
con_get_framebuffer(
|
||||
EFI_BOOT_SERVICES *bootsvc,
|
||||
void **buffer,
|
||||
size_t *buffer_size,
|
||||
uint32_t *hres,
|
||||
uint32_t *vres,
|
||||
uint32_t *rmask,
|
||||
uint32_t *gmask,
|
||||
uint32_t *bmask)
|
||||
{
|
||||
uefi::status status;
|
||||
|
||||
uefi::protos::graphics_output *gop;
|
||||
status = bootsvc->LocateProtocol(&guid_gfx_out, NULL, (void **)&gop);
|
||||
if (status != EFI_NOT_FOUND) {
|
||||
CHECK_EFI_STATUS_OR_RETURN(status, "LocateProtocol gfx");
|
||||
|
||||
*buffer = (void *)gop->Mode->FrameBufferBase;
|
||||
*buffer_size = gop->Mode->FrameBufferSize;
|
||||
*hres = gop->Mode->Info->horizontal_resolution;
|
||||
*vres = gop->Mode->Info->vertical_resolution;
|
||||
|
||||
switch (gop->Mode->Info->PixelFormat) {
|
||||
case PixelRedGreenBlueReserved8BitPerColor:
|
||||
*rmask = 0x0000ff;
|
||||
*gmask = 0x00ff00;
|
||||
*bmask = 0xff0000;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
case PixelBlueGreenRedReserved8BitPerColor:
|
||||
*bmask = 0x0000ff;
|
||||
*gmask = 0x00ff00;
|
||||
*rmask = 0xff0000;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
case PixelBitMask:
|
||||
*rmask = gop->Mode->Info->PixelInformation.RedMask;
|
||||
*gmask = gop->Mode->Info->PixelInformation.GreenMask;
|
||||
*bmask = gop->Mode->Info->PixelInformation.BlueMask;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
default:
|
||||
// Not a framebuffer, fall through to zeroing out
|
||||
// values below.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*buffer = NULL;
|
||||
*buffer_size = *hres = *vres = 0;
|
||||
*rmask = *gmask = *bmask = 0;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
} // namespace boot
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/// \file console.h
|
||||
/// Text output and status message handling
|
||||
/// Text output handler
|
||||
#pragma once
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <uefi/boot_services.h>
|
||||
#include <uefi/protos/simple_text_output.h>
|
||||
#include "kernel_args.h"
|
||||
#include "types.h"
|
||||
|
||||
namespace boot {
|
||||
|
||||
@@ -12,6 +14,8 @@ namespace boot {
|
||||
class console
|
||||
{
|
||||
public:
|
||||
using framebuffer = kernel::args::framebuffer;
|
||||
|
||||
console(uefi::boot_services *bs, uefi::protos::simple_text_output *out);
|
||||
|
||||
size_t print_hex(uint32_t n) const;
|
||||
@@ -20,6 +24,8 @@ public:
|
||||
size_t print_long_dec(uint64_t n) const;
|
||||
size_t printf(const wchar_t *fmt, ...) const;
|
||||
|
||||
const framebuffer & fb() const { return m_fb; };
|
||||
|
||||
static console & get() { return *s_console; }
|
||||
static size_t print(const wchar_t *fmt, ...);
|
||||
|
||||
@@ -31,50 +37,9 @@ private:
|
||||
|
||||
size_t m_rows, m_cols;
|
||||
uefi::protos::simple_text_output *m_out;
|
||||
framebuffer m_fb;
|
||||
|
||||
static console *s_console;
|
||||
};
|
||||
|
||||
/// Scoped status line reporter. Prints a message and an "OK" if no errors
|
||||
/// or warnings were reported before destruction, otherwise reports the
|
||||
/// error or warning.
|
||||
class status_line
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
/// \arg message Description of the operation in progress
|
||||
/// \arg context If non-null, printed after `message` and a colon
|
||||
status_line(const wchar_t *message, const wchar_t *context = nullptr);
|
||||
~status_line();
|
||||
|
||||
/// Set the state to warning, and print a message. If the state is already at
|
||||
/// warning or error, the state is unchanged but the message is still printed.
|
||||
/// \arg message The warning message to print
|
||||
/// \arg error If non-null, printed after `message`
|
||||
inline static void warn(const wchar_t *message, const wchar_t *error = nullptr) {
|
||||
if (s_current) s_current->do_warn(message, error);
|
||||
}
|
||||
|
||||
/// Set the state to error, and print a message. If the state is already at
|
||||
/// error, the state is unchanged but the message is still printed.
|
||||
/// \arg message The error message to print
|
||||
/// \arg error If non-null, printed after `message`
|
||||
inline static void fail(const wchar_t *message, const wchar_t *error = nullptr) {
|
||||
if (s_current) s_current->do_fail(message, error);
|
||||
}
|
||||
|
||||
private:
|
||||
void print_status_tag();
|
||||
void do_warn(const wchar_t *message, const wchar_t *error);
|
||||
void do_fail(const wchar_t *message, const wchar_t *error);
|
||||
void finish();
|
||||
|
||||
size_t m_line;
|
||||
int m_level;
|
||||
int m_depth;
|
||||
|
||||
status_line *m_next;
|
||||
static status_line *s_current;
|
||||
};
|
||||
|
||||
} // namespace boot
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "error.h"
|
||||
#include "console.h"
|
||||
#include "kernel_args.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace boot {
|
||||
namespace error {
|
||||
|
||||
handler *handler::s_current = nullptr;
|
||||
|
||||
struct error_code_desc {
|
||||
uefi::status code;
|
||||
const wchar_t *name;
|
||||
@@ -20,8 +20,8 @@ struct error_code_desc error_table[] = {
|
||||
{ uefi::status::success, nullptr }
|
||||
};
|
||||
|
||||
static const wchar_t *
|
||||
error_message(uefi::status status)
|
||||
const wchar_t *
|
||||
message(uefi::status status)
|
||||
{
|
||||
int32_t i = -1;
|
||||
while (error_table[++i].name != nullptr) {
|
||||
@@ -34,56 +34,32 @@ error_message(uefi::status status)
|
||||
return L"Unknown Warning";
|
||||
}
|
||||
|
||||
[[ noreturn ]] void
|
||||
raise(uefi::status status, const wchar_t *message)
|
||||
{
|
||||
if (handler::s_current) {
|
||||
handler::s_current->handle(status, message);
|
||||
}
|
||||
while (1) asm("hlt");
|
||||
}
|
||||
|
||||
handler::handler() :
|
||||
m_next(s_current)
|
||||
{
|
||||
s_current = this;
|
||||
}
|
||||
|
||||
handler::~handler()
|
||||
{
|
||||
if (s_current != this)
|
||||
raise(uefi::status::warn_stale_data,
|
||||
L"Non-current error handler destructing");
|
||||
s_current = m_next;
|
||||
}
|
||||
|
||||
uefi_handler::uefi_handler(console &con) :
|
||||
handler(),
|
||||
m_con(con)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
uefi_handler::handle(uefi::status s, const wchar_t *message)
|
||||
{
|
||||
status_line::fail(message, error_message(s));
|
||||
}
|
||||
|
||||
cpu_assert_handler::cpu_assert_handler() : handler() {}
|
||||
|
||||
void
|
||||
cpu_assert_handler::handle(uefi::status s, const wchar_t *message)
|
||||
[[ noreturn ]] static void
|
||||
cpu_assert(uefi::status s, const wchar_t *message, size_t line)
|
||||
{
|
||||
asm volatile (
|
||||
"movq $0xeeeeeeebadbadbad, %%r8;"
|
||||
"movq %0, %%r9;"
|
||||
"movq %1, %%r10;"
|
||||
"movq %2, %%r11;"
|
||||
"movq $0, %%rdx;"
|
||||
"divq %%rdx;"
|
||||
:
|
||||
: "r"((uint64_t)s)
|
||||
: "rax", "rdx", "r8", "r9");
|
||||
: "r"((uint64_t)s), "r"(message), "r"(line)
|
||||
: "rax", "rdx", "r8", "r9", "r10");
|
||||
while (1) asm("hlt");
|
||||
}
|
||||
|
||||
[[ noreturn ]] void
|
||||
raise(uefi::status status, const wchar_t *message, size_t line)
|
||||
{
|
||||
if(status_line::fail(message, status))
|
||||
while (1) asm("hlt");
|
||||
else
|
||||
cpu_assert(status, message, line);
|
||||
}
|
||||
|
||||
|
||||
} // namespace error
|
||||
} // namespace boot
|
||||
|
||||
|
||||
@@ -12,50 +12,9 @@ class console;
|
||||
namespace error {
|
||||
|
||||
/// Halt or exit the program with the given error status/message
|
||||
[[ noreturn ]] void raise(uefi::status status, const wchar_t *message);
|
||||
[[ noreturn ]] void raise(uefi::status status, const wchar_t *message, size_t line = 0);
|
||||
|
||||
/// Interface for error-handling functors
|
||||
class handler
|
||||
{
|
||||
public:
|
||||
/// Constructor must be called by implementing classes.
|
||||
handler();
|
||||
virtual ~handler();
|
||||
|
||||
/// Interface for implementations of error handling.
|
||||
virtual void handle(uefi::status, const wchar_t*) = 0;
|
||||
|
||||
private:
|
||||
friend void raise(uefi::status, const wchar_t *);
|
||||
|
||||
handler *m_next;
|
||||
static handler *s_current;
|
||||
};
|
||||
|
||||
/// Error handler using UEFI boot services. Integrates with `status_line`
|
||||
/// to print formatted error messages to the screen.
|
||||
class uefi_handler :
|
||||
public handler
|
||||
{
|
||||
public:
|
||||
uefi_handler(console &con);
|
||||
virtual ~uefi_handler() {}
|
||||
void handle(uefi::status, const wchar_t*) override;
|
||||
|
||||
private:
|
||||
console &m_con;
|
||||
};
|
||||
|
||||
/// Error handler that doesn't rely on UEFI. Sets status into CPU
|
||||
/// registers and then causes a CPU #DE exception.
|
||||
class cpu_assert_handler :
|
||||
public handler
|
||||
{
|
||||
public:
|
||||
cpu_assert_handler();
|
||||
virtual ~cpu_assert_handler() {}
|
||||
void handle(uefi::status, const wchar_t*) override;
|
||||
};
|
||||
const wchar_t * message(uefi::status status);
|
||||
|
||||
} // namespace error
|
||||
} // namespace boot
|
||||
@@ -69,6 +28,6 @@ void debug_break();
|
||||
#define try_or_raise(s, m) \
|
||||
do { \
|
||||
uefi::status _s = (s); \
|
||||
if (uefi::is_error(_s)) ::boot::error::raise(_s, (m)); \
|
||||
if (uefi::is_error(_s)) ::boot::error::raise(_s, (m), __LINE__); \
|
||||
} while(0)
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "console.h"
|
||||
#include "error.h"
|
||||
#include "memory.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace boot {
|
||||
namespace fs {
|
||||
@@ -50,19 +51,19 @@ file::open(const wchar_t *path)
|
||||
return file(fh, m_bs);
|
||||
}
|
||||
|
||||
void *
|
||||
file::load(size_t *out_size, uefi::memory_type mem_type)
|
||||
buffer
|
||||
file::load(uefi::memory_type mem_type)
|
||||
{
|
||||
uint8_t buffer[sizeof(uefi::protos::file_info) + 100];
|
||||
size_t size = sizeof(buffer);
|
||||
uint8_t info_buf[sizeof(uefi::protos::file_info) + 100];
|
||||
size_t size = sizeof(info_buf);
|
||||
uefi::guid info_guid = uefi::protos::file_info::guid;
|
||||
|
||||
try_or_raise(
|
||||
m_file->get_info(&info_guid, &size, &buffer),
|
||||
m_file->get_info(&info_guid, &size, &info_buf),
|
||||
L"Could not get file info");
|
||||
|
||||
uefi::protos::file_info *info =
|
||||
reinterpret_cast<uefi::protos::file_info*>(&buffer);
|
||||
reinterpret_cast<uefi::protos::file_info*>(&info_buf);
|
||||
|
||||
size_t pages = memory::bytes_to_pages(info->file_size);
|
||||
void *data = nullptr;
|
||||
@@ -77,8 +78,7 @@ file::load(size_t *out_size, uefi::memory_type mem_type)
|
||||
m_file->read(&size, data),
|
||||
L"Could not read from file");
|
||||
|
||||
*out_size = size;
|
||||
return data;
|
||||
return { .size = size, .data = data };
|
||||
}
|
||||
|
||||
file
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <uefi/types.h>
|
||||
#include <uefi/boot_services.h>
|
||||
#include <uefi/protos/file.h>
|
||||
#include "types.h"
|
||||
|
||||
namespace boot {
|
||||
namespace fs {
|
||||
@@ -22,13 +23,10 @@ public:
|
||||
file open(const wchar_t *path);
|
||||
|
||||
/// Load the contents of this file into memory.
|
||||
/// \arg out_size _out:_ The number of bytes loaded
|
||||
/// \arg mem_type The UEFI memory type to use for allocation
|
||||
/// \returns A pointer to the loaded memory. Memory will be
|
||||
/// page-aligned.
|
||||
void * load(
|
||||
size_t *out_size,
|
||||
uefi::memory_type mem_type = uefi::memory_type::loader_data);
|
||||
/// \returns A buffer describing the loaded memory. The
|
||||
/// memory will be page-aligned.
|
||||
buffer load(uefi::memory_type mem_type = uefi::memory_type::loader_data);
|
||||
|
||||
private:
|
||||
friend file get_boot_volume(uefi::handle, uefi::boot_services*);
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#include "guids.h"
|
||||
|
||||
#define GUID(dw, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, name) \
|
||||
EFI_GUID name __attribute__((section(".rodata"))) = {dw, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}}
|
||||
#include "guids.inc"
|
||||
#undef GUID
|
||||
|
||||
int is_guid(EFI_GUID *a, EFI_GUID *b)
|
||||
{
|
||||
uint64_t *ai = (uint64_t *)a;
|
||||
uint64_t *bi = (uint64_t *)b;
|
||||
return ai[0] == bi[0] && ai[1] == bi[1];
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
#include <efi/efi.h>
|
||||
|
||||
int is_guid(EFI_GUID *a, EFI_GUID *b);
|
||||
|
||||
#define GUID(dw, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, name) extern EFI_GUID name
|
||||
#include "guids.inc"
|
||||
#undef GUID
|
||||
@@ -1,11 +0,0 @@
|
||||
GUID(0xeb9d2d30,0x2d88,0x11d3,0x9a,0x16,0x00,0x90,0x27,0x3f,0xc1,0x4d, guid_acpi1);
|
||||
GUID(0x8868e871,0xe4f1,0x11d3,0xbc,0x22,0x00,0x80,0xc7,0x3c,0x88,0x81, guid_acpi2);
|
||||
GUID(0x09576e92,0x6d3f,0x11d2,0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b, guid_file_info);
|
||||
GUID(0x9042a9de,0x23dc,0x4a38,0x96,0xfb,0x7a,0xde,0xd0,0x80,0x51,0x6a, guid_gfx_out);
|
||||
GUID(0x964e5b22,0x6459,0x11d2,0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b, guid_simple_filesystem);
|
||||
GUID(0x09576e91,0x6d3f,0x11d2,0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b, guid_device_path);
|
||||
GUID(0x8b843e20,0x8132,0x4852,0x90,0xcc,0x55,0x1a,0x4e,0x4a,0x7f,0x1c, guid_device_path_to_text);
|
||||
|
||||
GUID(0x10d0669c,0x9ec6,0x4268,0xbc,0x48,0xff,0x74,0x75,0x21,0xfe,0x07, guid_jsix_vendor);
|
||||
|
||||
// vim: ft=c
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "hardware.h"
|
||||
#include "console.h"
|
||||
#include "error.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace boot {
|
||||
namespace hw {
|
||||
@@ -36,8 +37,25 @@ find_acpi_table(uefi::system_table *st)
|
||||
return reinterpret_cast<void*>(acpi1_table);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
rdmsr(uint32_t addr)
|
||||
{
|
||||
uint32_t low, high;
|
||||
__asm__ __volatile__ ("rdmsr" : "=a"(low), "=d"(high) : "c"(addr));
|
||||
return (static_cast<uint64_t>(high) << 32) | low;
|
||||
}
|
||||
|
||||
static void
|
||||
wrmsr(uint32_t addr, uint64_t value)
|
||||
{
|
||||
uint32_t low = value & 0xffffffff;
|
||||
uint32_t high = value >> 32;
|
||||
__asm__ __volatile__ ("wrmsr" :: "c"(addr), "a"(low), "d"(high));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
setup_cr4()
|
||||
setup_control_regs()
|
||||
{
|
||||
uint64_t cr4 = 0;
|
||||
asm volatile ( "mov %%cr4, %0" : "=r" (cr4) );
|
||||
@@ -48,6 +66,15 @@ setup_cr4()
|
||||
0x020000 | // Enable PCIDs
|
||||
0;
|
||||
asm volatile ( "mov %0, %%cr4" :: "r" (cr4) );
|
||||
|
||||
// Set up IA32_EFER
|
||||
constexpr uint32_t IA32_EFER = 0xC0000080;
|
||||
uint64_t efer = rdmsr(IA32_EFER);
|
||||
efer |=
|
||||
0x0001 | // Enable SYSCALL
|
||||
0x0800 | // Enable NX bit
|
||||
0;
|
||||
wrmsr(IA32_EFER, efer);
|
||||
}
|
||||
|
||||
} // namespace hw
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace hw {
|
||||
/// significant bit set to 1.
|
||||
void * find_acpi_table(uefi::system_table *st);
|
||||
|
||||
/// Enable CPU options in CR4 for the kernel starting state.
|
||||
void setup_cr4();
|
||||
/// Enable CPU options in CR4 etc for the kernel starting state.
|
||||
void setup_control_regs();
|
||||
|
||||
} // namespace hw
|
||||
} // namespace boot
|
||||
|
||||
@@ -5,12 +5,33 @@
|
||||
#include "console.h"
|
||||
#include "elf.h"
|
||||
#include "error.h"
|
||||
#include "fs.h"
|
||||
#include "memory.h"
|
||||
#include "paging.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace args = kernel::args;
|
||||
|
||||
namespace boot {
|
||||
namespace loader {
|
||||
|
||||
buffer
|
||||
load_file(
|
||||
fs::file &disk,
|
||||
const wchar_t *name,
|
||||
const wchar_t *path,
|
||||
uefi::memory_type type)
|
||||
{
|
||||
status_line status(L"Loading file", name);
|
||||
|
||||
fs::file file = disk.open(path);
|
||||
buffer b = file.load(type);
|
||||
|
||||
//console::print(L" Loaded at: 0x%lx, %d bytes\r\n", b.data, b.size);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
is_elfheader_valid(const elf::header *header)
|
||||
{
|
||||
@@ -26,48 +47,70 @@ is_elfheader_valid(const elf::header *header)
|
||||
header->header_version == elf::version;
|
||||
}
|
||||
|
||||
kernel::entrypoint
|
||||
load(
|
||||
const void *data, size_t size,
|
||||
kernel::args::header *args,
|
||||
void
|
||||
load_program(
|
||||
args::program &program,
|
||||
const wchar_t *name,
|
||||
buffer data,
|
||||
uefi::boot_services *bs)
|
||||
{
|
||||
status_line status(L"Loading kernel ELF binary");
|
||||
const elf::header *header = reinterpret_cast<const elf::header*>(data);
|
||||
status_line status(L"Loading program:", name);
|
||||
const elf::header *header = reinterpret_cast<const elf::header*>(data.data);
|
||||
|
||||
if (size < sizeof(elf::header) || !is_elfheader_valid(header))
|
||||
error::raise(uefi::status::load_error, L"Kernel ELF not valid");
|
||||
if (data.size < sizeof(elf::header) || !is_elfheader_valid(header))
|
||||
error::raise(uefi::status::load_error, L"ELF file not valid");
|
||||
|
||||
paging::page_table *pml4 = reinterpret_cast<paging::page_table*>(args->pml4);
|
||||
uintptr_t prog_base = uintptr_t(-1);
|
||||
uintptr_t prog_end = 0;
|
||||
|
||||
for (int i = 0; i < header->ph_num; ++i) {
|
||||
ptrdiff_t offset = header->ph_offset + i * header->ph_entsize;
|
||||
const elf::program_header *pheader =
|
||||
offset_ptr<elf::program_header>(data, offset);
|
||||
offset_ptr<elf::program_header>(data.data, offset);
|
||||
|
||||
if (pheader->type != elf::PT_LOAD)
|
||||
continue;
|
||||
|
||||
size_t num_pages = memory::bytes_to_pages(pheader->mem_size);
|
||||
void *pages = nullptr;
|
||||
|
||||
try_or_raise(
|
||||
bs->allocate_pages(uefi::allocate_type::any_pages,
|
||||
memory::kernel_type, num_pages, &pages),
|
||||
L"Failed allocating space for kernel code");
|
||||
|
||||
void *data_start = offset_ptr<void>(data, pheader->offset);
|
||||
bs->copy_mem(pages, data_start, pheader->mem_size);
|
||||
|
||||
console::print(L" section %d phys: 0x%lx\r\n", i, pages);
|
||||
console::print(L" section %d virt: 0x%lx\r\n", i, pheader->vaddr);
|
||||
|
||||
// TODO: set appropriate RWX permissions
|
||||
paging::map_pages(pml4, args, reinterpret_cast<uintptr_t>(pages), pheader->vaddr, pheader->mem_size);
|
||||
uintptr_t end = pheader->vaddr + pheader->mem_size;
|
||||
if (pheader->vaddr < prog_base) prog_base = pheader->vaddr;
|
||||
if (end > prog_end) prog_end = end;
|
||||
}
|
||||
|
||||
console::print(L" entrypoint: 0x%lx\r\n", header->entrypoint);
|
||||
return reinterpret_cast<kernel::entrypoint>(header->entrypoint);
|
||||
size_t total_size = prog_end - prog_base;
|
||||
size_t num_pages = memory::bytes_to_pages(total_size);
|
||||
void *pages = nullptr;
|
||||
|
||||
try_or_raise(
|
||||
bs->allocate_pages(uefi::allocate_type::any_pages,
|
||||
uefi::memory_type::loader_data, num_pages, &pages),
|
||||
L"Failed allocating space for program");
|
||||
|
||||
bs->set_mem(pages, total_size, 0);
|
||||
|
||||
program.base = prog_base;
|
||||
program.total_size = total_size;
|
||||
program.num_sections = 0;
|
||||
for (int i = 0; i < header->ph_num; ++i) {
|
||||
ptrdiff_t offset = header->ph_offset + i * header->ph_entsize;
|
||||
const elf::program_header *pheader =
|
||||
offset_ptr<elf::program_header>(data.data, offset);
|
||||
|
||||
if (pheader->type != elf::PT_LOAD)
|
||||
continue;
|
||||
|
||||
args::program_section §ion = program.sections[program.num_sections++];
|
||||
|
||||
void *src_start = offset_ptr<void>(data.data, pheader->offset);
|
||||
void *dest_start = offset_ptr<void>(pages, pheader->vaddr - prog_base);
|
||||
|
||||
bs->copy_mem(dest_start, src_start, pheader->file_size);
|
||||
section.phys_addr = reinterpret_cast<uintptr_t>(dest_start);
|
||||
section.virt_addr = pheader->vaddr;
|
||||
section.size = pheader->mem_size;
|
||||
section.type = static_cast<args::section_flags>(pheader->flags);
|
||||
}
|
||||
|
||||
program.entrypoint = header->entrypoint;
|
||||
}
|
||||
|
||||
} // namespace loader
|
||||
|
||||
@@ -5,18 +5,36 @@
|
||||
#include <uefi/boot_services.h>
|
||||
|
||||
#include "kernel_args.h"
|
||||
#include "memory.h"
|
||||
#include "types.h"
|
||||
|
||||
namespace boot {
|
||||
|
||||
namespace fs { class file; }
|
||||
|
||||
namespace loader {
|
||||
|
||||
/// Load a file from disk into memory.
|
||||
/// \arg disk The opened UEFI filesystem to load from
|
||||
/// \arg name Name of the module (informational only)
|
||||
/// \arg path Path on `disk` of the file to load
|
||||
/// \arg type Memory type to use for allocation
|
||||
buffer
|
||||
load_file(
|
||||
fs::file &disk,
|
||||
const wchar_t *name,
|
||||
const wchar_t *path,
|
||||
uefi::memory_type type = uefi::memory_type::loader_data);
|
||||
|
||||
/// Parse and load an ELF file in memory into a loaded image.
|
||||
/// \arg data The start of the ELF file in memory
|
||||
/// \arg size The size of the ELF file in memory
|
||||
/// \arg args The kernel args, used for modifying page tables
|
||||
/// \returns A descriptor defining the loaded image
|
||||
kernel::entrypoint load(
|
||||
const void *data, size_t size,
|
||||
kernel::args::header *args,
|
||||
/// \arg program The program structure to fill
|
||||
/// \arg data Buffer of the ELF file in memory
|
||||
/// \arg bs Boot services
|
||||
void
|
||||
load_program(
|
||||
kernel::args::program &program,
|
||||
const wchar_t *name,
|
||||
buffer data,
|
||||
uefi::boot_services *bs);
|
||||
|
||||
} // namespace loader
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "cpu/cpu_id.h"
|
||||
#include "error.h"
|
||||
#include "fs.h"
|
||||
#include "hardware.h"
|
||||
#include "loader.h"
|
||||
#include "memory.h"
|
||||
#include "paging.h"
|
||||
#include "status.h"
|
||||
|
||||
#include "kernel_args.h"
|
||||
|
||||
@@ -21,9 +23,24 @@ namespace kernel {
|
||||
#include "kernel_memory.h"
|
||||
}
|
||||
|
||||
namespace args = kernel::args;
|
||||
|
||||
namespace boot {
|
||||
|
||||
constexpr int max_modules = 10; // Max modules to allocate room for
|
||||
constexpr int max_modules = 5; // Max modules to allocate room for
|
||||
constexpr int max_programs = 5; // Max programs to allocate room for
|
||||
|
||||
struct program_desc
|
||||
{
|
||||
const wchar_t *name;
|
||||
const wchar_t *path;
|
||||
};
|
||||
|
||||
const program_desc program_list[] = {
|
||||
{L"kernel", L"jsix.elf"},
|
||||
{L"null driver", L"nulldrv.elf"},
|
||||
{L"fb driver", L"fb.elf"},
|
||||
};
|
||||
|
||||
/// Change a pointer to point to the higher-half linear-offset version
|
||||
/// of the address it points to.
|
||||
@@ -34,129 +51,165 @@ void change_pointer(T *&pointer)
|
||||
}
|
||||
|
||||
/// Allocate space for kernel args. Allocates enough space from pool
|
||||
/// memory for the args header and `max_modules` module headers.
|
||||
kernel::args::header *
|
||||
/// memory for the args header and the module and program headers.
|
||||
args::header *
|
||||
allocate_args_structure(
|
||||
uefi::boot_services *bs,
|
||||
size_t max_modules)
|
||||
size_t max_modules,
|
||||
size_t max_programs)
|
||||
{
|
||||
status_line status(L"Setting up kernel args memory");
|
||||
status_line status {L"Setting up kernel args memory"};
|
||||
|
||||
kernel::args::header *args = nullptr;
|
||||
args::header *args = nullptr;
|
||||
|
||||
size_t args_size =
|
||||
sizeof(kernel::args::header) + // The header itself
|
||||
max_modules * sizeof(kernel::args::module); // The module structures
|
||||
sizeof(args::header) + // The header itself
|
||||
max_modules * sizeof(args::module) + // The module structures
|
||||
max_programs * sizeof(args::program); // The program structures
|
||||
|
||||
try_or_raise(
|
||||
bs->allocate_pool(memory::args_type, args_size,
|
||||
bs->allocate_pool(uefi::memory_type::loader_data, args_size,
|
||||
reinterpret_cast<void**>(&args)),
|
||||
L"Could not allocate argument memory");
|
||||
|
||||
bs->set_mem(args, args_size, 0);
|
||||
|
||||
args->modules =
|
||||
reinterpret_cast<kernel::args::module*>(args + 1);
|
||||
reinterpret_cast<args::module*>(args + 1);
|
||||
args->num_modules = 0;
|
||||
|
||||
args->programs =
|
||||
reinterpret_cast<args::program*>(args->modules + max_modules);
|
||||
args->num_programs = 0;
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/// Load a file from disk into memory. Also adds an entry to the kernel
|
||||
/// args module headers pointing at the loaded data.
|
||||
/// \arg disk The opened UEFI filesystem to load from
|
||||
/// \arg args The kernel args header to update with module information
|
||||
/// \arg name Name of the module (informational only)
|
||||
/// \arg path Path on `disk` of the file to load
|
||||
/// \arg type Type specifier of this module (eg, initrd or kernel)
|
||||
kernel::args::module *
|
||||
load_module(
|
||||
fs::file &disk,
|
||||
kernel::args::header *args,
|
||||
const wchar_t *name,
|
||||
const wchar_t *path,
|
||||
kernel::args::mod_type type)
|
||||
/// Add a module to the kernel args list
|
||||
inline void
|
||||
add_module(args::header *args, args::mod_type type, buffer &data)
|
||||
{
|
||||
status_line status(L"Loading module", name);
|
||||
args::module &m = args->modules[args->num_modules++];
|
||||
m.type = type;
|
||||
m.location = data.data;
|
||||
m.size = data.size;
|
||||
|
||||
fs::file file = disk.open(path);
|
||||
kernel::args::module &module = args->modules[args->num_modules++];
|
||||
module.type = type;
|
||||
module.location = file.load(&module.size, memory::module_type);
|
||||
change_pointer(m.location);
|
||||
}
|
||||
|
||||
console::print(L" Loaded at: 0x%lx, %d bytes\r\n", module.location, module.size);
|
||||
return &module;
|
||||
/// Check that all required cpu features are supported
|
||||
void
|
||||
check_cpu_supported()
|
||||
{
|
||||
status_line status {L"Checking CPU features"};
|
||||
|
||||
cpu::cpu_id cpu;
|
||||
uint64_t missing = cpu.missing();
|
||||
if (missing) {
|
||||
#define CPU_FEATURE_OPT(...)
|
||||
#define CPU_FEATURE_REQ(name, ...) \
|
||||
if (!cpu.has_feature(cpu::feature::name)) { \
|
||||
status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \
|
||||
}
|
||||
#include "cpu/features.inc"
|
||||
#undef CPU_FEATURE_REQ
|
||||
#undef CPU_FEATURE_OPT
|
||||
|
||||
error::raise(uefi::status::unsupported, L"CPU not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// The main procedure for the portion of the loader that runs while
|
||||
/// UEFI is still in control of the machine. (ie, while the loader still
|
||||
/// has access to boot services.
|
||||
kernel::args::header *
|
||||
bootloader_main_uefi(
|
||||
uefi::handle image,
|
||||
uefi::system_table *st,
|
||||
console &con,
|
||||
kernel::entrypoint *kentry)
|
||||
args::header *
|
||||
uefi_preboot(uefi::handle image, uefi::system_table *st)
|
||||
{
|
||||
error::uefi_handler handler(con);
|
||||
status_line status(L"Performing UEFI pre-boot");
|
||||
status_line status {L"Performing UEFI pre-boot"};
|
||||
|
||||
uefi::boot_services *bs = st->boot_services;
|
||||
uefi::runtime_services *rs = st->runtime_services;
|
||||
memory::init_pointer_fixup(bs, rs);
|
||||
|
||||
kernel::args::header *args =
|
||||
allocate_args_structure(bs, max_modules);
|
||||
args::header *args =
|
||||
allocate_args_structure(bs, max_modules, max_programs);
|
||||
|
||||
args->magic = kernel::args::magic;
|
||||
args->version = kernel::args::version;
|
||||
args->magic = args::magic;
|
||||
args->version = args::version;
|
||||
args->runtime_services = rs;
|
||||
args->acpi_table = hw::find_acpi_table(st);
|
||||
paging::allocate_tables(args, bs);
|
||||
|
||||
memory::mark_pointer_fixup(&args->runtime_services);
|
||||
|
||||
fs::file disk = fs::get_boot_volume(image, bs);
|
||||
load_module(disk, args, L"initrd", L"initrd.img", kernel::args::mod_type::initrd);
|
||||
|
||||
kernel::args::module *kernel =
|
||||
load_module(disk, args, L"kernel", L"jsix.elf", kernel::args::mod_type::kernel);
|
||||
buffer symbols = loader::load_file(disk, L"symbol table", L"symbol_table.dat",
|
||||
uefi::memory_type::loader_data);
|
||||
add_module(args, args::mod_type::symbol_table, symbols);
|
||||
|
||||
paging::allocate_tables(args, bs);
|
||||
*kentry = loader::load(kernel->location, kernel->size, args, bs);
|
||||
|
||||
for (unsigned i = 0; i < args->num_modules; ++i) {
|
||||
kernel::args::module &mod = args->modules[i];
|
||||
change_pointer(mod.location);
|
||||
for (auto &desc : program_list) {
|
||||
buffer buf = loader::load_file(disk, desc.name, desc.path);
|
||||
args::program &program = args->programs[args->num_programs++];
|
||||
loader::load_program(program, desc.name, buf, bs);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
memory::efi_mem_map
|
||||
uefi_exit(args::header *args, uefi::handle image, uefi::boot_services *bs)
|
||||
{
|
||||
status_line status {L"Exiting UEFI", nullptr, false};
|
||||
|
||||
memory::efi_mem_map map =
|
||||
memory::build_kernel_mem_map(args, bs);
|
||||
|
||||
try_or_raise(
|
||||
bs->exit_boot_services(image, map.key),
|
||||
L"Failed to exit boot services");
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
} // namespace boot
|
||||
|
||||
/// The UEFI entrypoint for the loader.
|
||||
extern "C" uefi::status
|
||||
efi_main(uefi::handle image_handle, uefi::system_table *st)
|
||||
efi_main(uefi::handle image, uefi::system_table *st)
|
||||
{
|
||||
using namespace boot;
|
||||
|
||||
error::cpu_assert_handler handler;
|
||||
console con(st->boot_services, st->con_out);
|
||||
check_cpu_supported();
|
||||
|
||||
kernel::entrypoint kentry = nullptr;
|
||||
kernel::args::header *args =
|
||||
bootloader_main_uefi(image_handle, st, con, &kentry);
|
||||
args::header *args = uefi_preboot(image, st);
|
||||
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
||||
|
||||
memory::efi_mem_map map =
|
||||
memory::build_kernel_mem_map(args, st->boot_services);
|
||||
args->video = con.fb();
|
||||
status_bar status {con.fb()}; // Switch to fb status display
|
||||
|
||||
try_or_raise(
|
||||
st->boot_services->exit_boot_services(image_handle, map.key),
|
||||
L"Failed to exit boot services");
|
||||
// Map the kernel to the appropriate address
|
||||
args::program &kernel = args->programs[0];
|
||||
for (auto §ion : kernel.sections)
|
||||
if (section.size)
|
||||
paging::map_section(args, section);
|
||||
|
||||
memory::fix_frame_blocks(args);
|
||||
|
||||
kernel::entrypoint kentry =
|
||||
reinterpret_cast<kernel::entrypoint>(kernel.entrypoint);
|
||||
status.next();
|
||||
|
||||
hw::setup_control_regs();
|
||||
memory::virtualize(args->pml4, map, st->runtime_services);
|
||||
status.next();
|
||||
|
||||
change_pointer(args);
|
||||
change_pointer(args->pml4);
|
||||
hw::setup_cr4();
|
||||
change_pointer(args->modules);
|
||||
change_pointer(args->programs);
|
||||
|
||||
status.next();
|
||||
|
||||
kentry(args);
|
||||
debug_break();
|
||||
|
||||
@@ -7,12 +7,15 @@
|
||||
#include "error.h"
|
||||
#include "memory.h"
|
||||
#include "paging.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace boot {
|
||||
namespace memory {
|
||||
|
||||
using mem_entry = kernel::args::mem_entry;
|
||||
using mem_type = kernel::args::mem_type;
|
||||
using frame_block = kernel::args::frame_block;
|
||||
using kernel::args::frames_per_block;
|
||||
|
||||
size_t fixup_pointer_index = 0;
|
||||
void **fixup_pointers[64];
|
||||
@@ -35,20 +38,28 @@ static const wchar_t *memory_type_names[] = {
|
||||
L"persistent memory"
|
||||
};
|
||||
|
||||
static const wchar_t *kernel_memory_type_names[] = {
|
||||
L"free",
|
||||
L"pending",
|
||||
L"acpi",
|
||||
L"uefi_runtime",
|
||||
L"mmio",
|
||||
L"persistent"
|
||||
};
|
||||
|
||||
static const wchar_t *
|
||||
memory_type_name(uefi::memory_type t)
|
||||
{
|
||||
if (t < uefi::memory_type::max_memory_type) {
|
||||
if (t < uefi::memory_type::max_memory_type)
|
||||
return memory_type_names[static_cast<uint32_t>(t)];
|
||||
}
|
||||
|
||||
switch(t) {
|
||||
case args_type: return L"jsix kernel args";
|
||||
case module_type: return L"jsix bootloader module";
|
||||
case kernel_type: return L"jsix kernel code";
|
||||
case table_type: return L"jsix page tables";
|
||||
default: return L"Bad Type Value";
|
||||
}
|
||||
return L"Bad Type Value";
|
||||
}
|
||||
|
||||
static const wchar_t *
|
||||
kernel_memory_type_name(kernel::args::mem_type t)
|
||||
{
|
||||
return kernel_memory_type_names[static_cast<uint32_t>(t)];
|
||||
}
|
||||
|
||||
void
|
||||
@@ -98,58 +109,174 @@ can_merge(mem_entry &prev, mem_type type, uefi::memory_descriptor *next)
|
||||
}
|
||||
|
||||
void
|
||||
get_uefi_mappings(efi_mem_map *map, bool allocate, uefi::boot_services *bs)
|
||||
get_uefi_mappings(efi_mem_map &map, uefi::boot_services *bs)
|
||||
{
|
||||
status_line(L"Getting UEFI memory map");
|
||||
|
||||
size_t length = map.total;
|
||||
uefi::status status = bs->get_memory_map(
|
||||
&map->length, nullptr, &map->key, &map->size, &map->version);
|
||||
&length, map.entries, &map.key, &map.size, &map.version);
|
||||
map.length = length;
|
||||
|
||||
if (status == uefi::status::success)
|
||||
return;
|
||||
|
||||
if (status != uefi::status::buffer_too_small)
|
||||
error::raise(status, L"Error getting memory map size");
|
||||
|
||||
if (allocate) {
|
||||
map->length += 10*map->size;
|
||||
|
||||
if (map.entries) {
|
||||
try_or_raise(
|
||||
bs->allocate_pool(
|
||||
uefi::memory_type::loader_data, map->length,
|
||||
reinterpret_cast<void**>(&map->entries)),
|
||||
L"Allocating space for memory map");
|
||||
bs->free_pool(reinterpret_cast<void*>(map.entries)),
|
||||
L"Freeing previous memory map space");
|
||||
}
|
||||
|
||||
try_or_raise(
|
||||
bs->get_memory_map(&map->length, map->entries, &map->key, &map->size, &map->version),
|
||||
L"Getting UEFI memory map");
|
||||
map.total = length + 10*map.size;
|
||||
|
||||
try_or_raise(
|
||||
bs->allocate_pool(
|
||||
uefi::memory_type::loader_data, map.total,
|
||||
reinterpret_cast<void**>(&map.entries)),
|
||||
L"Allocating space for memory map");
|
||||
|
||||
map.length = map.total;
|
||||
try_or_raise(
|
||||
bs->get_memory_map(&map.length, map.entries, &map.key, &map.size, &map.version),
|
||||
L"Getting UEFI memory map");
|
||||
}
|
||||
|
||||
inline size_t bitmap_size(size_t frames) { return (frames + 63) / 64; }
|
||||
inline size_t num_blocks(size_t frames) { return (frames + (frames_per_block-1)) / frames_per_block; }
|
||||
|
||||
void
|
||||
build_kernel_frame_blocks(const mem_entry *map, size_t nent, kernel::args::header *args, uefi::boot_services *bs)
|
||||
{
|
||||
status_line status {L"Creating kernel frame accounting map"};
|
||||
|
||||
size_t block_count = 0;
|
||||
size_t total_bitmap_size = 0;
|
||||
for (size_t i = 0; i < nent; ++i) {
|
||||
const mem_entry &ent = map[i];
|
||||
if (ent.type != mem_type::free)
|
||||
continue;
|
||||
|
||||
block_count += num_blocks(ent.pages);
|
||||
total_bitmap_size += bitmap_size(ent.pages) * sizeof(uint64_t);
|
||||
}
|
||||
|
||||
size_t total_size = block_count * sizeof(frame_block) + total_bitmap_size;
|
||||
|
||||
frame_block *blocks = nullptr;
|
||||
try_or_raise(
|
||||
bs->allocate_pages(
|
||||
uefi::allocate_type::any_pages,
|
||||
uefi::memory_type::loader_data,
|
||||
bytes_to_pages(total_size),
|
||||
reinterpret_cast<void**>(&blocks)),
|
||||
L"Error allocating kernel frame block space");
|
||||
|
||||
frame_block *next_block = blocks;
|
||||
for (size_t i = 0; i < nent; ++i) {
|
||||
const mem_entry &ent = map[i];
|
||||
if (ent.type != mem_type::free)
|
||||
continue;
|
||||
|
||||
size_t page_count = ent.pages;
|
||||
uintptr_t base_addr = ent.start;
|
||||
while (page_count) {
|
||||
frame_block *blk = next_block++;
|
||||
bs->set_mem(blk, sizeof(frame_block), 0);
|
||||
|
||||
blk->attrs = ent.attr;
|
||||
blk->base = base_addr;
|
||||
base_addr += frames_per_block * page_size;
|
||||
|
||||
if (page_count >= frames_per_block) {
|
||||
page_count -= frames_per_block;
|
||||
blk->count = frames_per_block;
|
||||
blk->map1 = ~0ull;
|
||||
bs->set_mem(blk->map2, sizeof(blk->map2), 0xff);
|
||||
} else {
|
||||
blk->count = page_count;
|
||||
unsigned i = 0;
|
||||
|
||||
uint64_t b1 = (page_count + 4095) / 4096;
|
||||
blk->map1 = (1 << b1) - 1;
|
||||
|
||||
uint64_t b2 = (page_count + 63) / 64;
|
||||
uint64_t b2q = b2 / 64;
|
||||
uint64_t b2r = b2 % 64;
|
||||
bs->set_mem(blk->map2, b2q, 0xff);
|
||||
blk->map2[b2q] = (1 << b2r) - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t *bitmap = reinterpret_cast<uint64_t*>(next_block);
|
||||
bs->set_mem(bitmap, total_bitmap_size, 0);
|
||||
for (unsigned i = 0; i < block_count; ++i) {
|
||||
frame_block &blk = blocks[i];
|
||||
blk.bitmap = bitmap;
|
||||
|
||||
size_t b = blk.count / 64;
|
||||
size_t r = blk.count % 64;
|
||||
bs->set_mem(blk.bitmap, b*8, 0xff);
|
||||
blk.bitmap[b] = (1 << r) - 1;
|
||||
|
||||
bitmap += bitmap_size(blk.count);
|
||||
}
|
||||
|
||||
args->frame_block_count = block_count;
|
||||
args->frame_block_pages = bytes_to_pages(total_size);
|
||||
args->frame_blocks = blocks;
|
||||
}
|
||||
|
||||
void
|
||||
fix_frame_blocks(kernel::args::header *args)
|
||||
{
|
||||
// Map the frame blocks to the appropriate address
|
||||
paging::map_pages(args,
|
||||
reinterpret_cast<uintptr_t>(args->frame_blocks),
|
||||
::memory::bitmap_start,
|
||||
args->frame_block_pages,
|
||||
true, false);
|
||||
|
||||
uintptr_t offset = ::memory::bitmap_start -
|
||||
reinterpret_cast<uintptr_t>(args->frame_blocks);
|
||||
|
||||
for (unsigned i = 0; i < args->frame_block_count; ++i) {
|
||||
frame_block &blk = args->frame_blocks[i];
|
||||
blk.bitmap = reinterpret_cast<uint64_t*>(
|
||||
reinterpret_cast<uintptr_t>(blk.bitmap) + offset);
|
||||
}
|
||||
}
|
||||
|
||||
efi_mem_map
|
||||
build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
||||
{
|
||||
status_line(L"Creating kernel memory map");
|
||||
status_line status {L"Creating kernel memory map"};
|
||||
|
||||
efi_mem_map efi_map;
|
||||
get_uefi_mappings(&efi_map, false, bs);
|
||||
efi_mem_map map;
|
||||
get_uefi_mappings(map, bs);
|
||||
|
||||
size_t map_size = efi_map.num_entries() * sizeof(mem_entry);
|
||||
size_t map_size = map.num_entries() * sizeof(mem_entry);
|
||||
|
||||
kernel::args::mem_entry *kernel_map = nullptr;
|
||||
try_or_raise(
|
||||
bs->allocate_pages(
|
||||
uefi::allocate_type::any_pages,
|
||||
module_type,
|
||||
uefi::memory_type::loader_data,
|
||||
bytes_to_pages(map_size),
|
||||
reinterpret_cast<void**>(&kernel_map)),
|
||||
L"Error allocating kernel memory map module space");
|
||||
|
||||
bs->set_mem(kernel_map, map_size, 0);
|
||||
get_uefi_mappings(&efi_map, true, bs);
|
||||
get_uefi_mappings(map, bs);
|
||||
|
||||
size_t i = 0;
|
||||
size_t nent = 0;
|
||||
bool first = true;
|
||||
for (auto desc : efi_map) {
|
||||
for (auto desc : map) {
|
||||
/*
|
||||
console::print(L" Range %lx (%lx) %x(%s) [%lu]\r\n",
|
||||
// EFI map dump
|
||||
console::print(L" eRange %lx (%lx) %x(%s) [%lu]\r\n",
|
||||
desc->physical_start, desc->attribute, desc->type, memory_type_name(desc->type), desc->number_of_pages);
|
||||
*/
|
||||
|
||||
@@ -162,10 +289,10 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
||||
continue;
|
||||
|
||||
case uefi::memory_type::loader_code:
|
||||
case uefi::memory_type::loader_data:
|
||||
case uefi::memory_type::boot_services_code:
|
||||
case uefi::memory_type::boot_services_data:
|
||||
case uefi::memory_type::conventional_memory:
|
||||
case uefi::memory_type::loader_data:
|
||||
type = mem_type::free;
|
||||
break;
|
||||
|
||||
@@ -187,22 +314,6 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
||||
type = mem_type::persistent;
|
||||
break;
|
||||
|
||||
case args_type:
|
||||
type = mem_type::args;
|
||||
break;
|
||||
|
||||
case module_type:
|
||||
type = mem_type::module;
|
||||
break;
|
||||
|
||||
case kernel_type:
|
||||
type = mem_type::kernel;
|
||||
break;
|
||||
|
||||
case table_type:
|
||||
type = mem_type::table;
|
||||
break;
|
||||
|
||||
default:
|
||||
error::raise(
|
||||
uefi::status::invalid_parameter,
|
||||
@@ -212,18 +323,19 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
||||
// TODO: validate uefi's map is sorted
|
||||
if (first) {
|
||||
first = false;
|
||||
kernel_map[i].start = desc->physical_start;
|
||||
kernel_map[i].pages = desc->number_of_pages;
|
||||
kernel_map[i].type = type;
|
||||
kernel_map[i].attr = (desc->attribute & 0xffffffff);
|
||||
mem_entry &ent = kernel_map[nent++];
|
||||
ent.start = desc->physical_start;
|
||||
ent.pages = desc->number_of_pages;
|
||||
ent.type = type;
|
||||
ent.attr = (desc->attribute & 0xffffffff);
|
||||
continue;
|
||||
}
|
||||
|
||||
mem_entry &prev = kernel_map[i];
|
||||
mem_entry &prev = kernel_map[nent - 1];
|
||||
if (can_merge(prev, type, desc)) {
|
||||
prev.pages += desc->number_of_pages;
|
||||
} else {
|
||||
mem_entry &next = kernel_map[++i];
|
||||
mem_entry &next = kernel_map[nent++];
|
||||
next.start = desc->physical_start;
|
||||
next.pages = desc->number_of_pages;
|
||||
next.type = type;
|
||||
@@ -233,23 +345,20 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
||||
|
||||
// Give just the actually-set entries in the header
|
||||
args->mem_map = kernel_map;
|
||||
args->num_map_entries = i;
|
||||
|
||||
// But pass the entire allocated area in a module as well
|
||||
kernel::args::module &module = args->modules[args->num_modules++];
|
||||
module.location = reinterpret_cast<void*>(kernel_map);
|
||||
module.size = map_size;
|
||||
module.type = kernel::args::mod_type::memory_map;
|
||||
args->map_count = nent;
|
||||
|
||||
/*
|
||||
for (size_t i = 0; i<map.num_entries(); ++i) {
|
||||
mem_entry &ent = kernel_map[i];
|
||||
console::print(L" Range %lx (%x) %d [%lu]\r\n",
|
||||
ent.start, ent.attr, ent.type, ent.pages);
|
||||
// kernel map dump
|
||||
for (unsigned i = 0; i < nent; ++i) {
|
||||
const kernel::args::mem_entry &e = kernel_map[i];
|
||||
console::print(L" kRange %lx (%lx) %x(%s) [%lu]\r\n",
|
||||
e.start, e.attr, e.type, kernel_memory_type_name(e.type), e.pages);
|
||||
}
|
||||
*/
|
||||
|
||||
return efi_map;
|
||||
build_kernel_frame_blocks(kernel_map, nent, args, bs);
|
||||
get_uefi_mappings(map, bs);
|
||||
return map;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -18,28 +18,6 @@ inline constexpr size_t bytes_to_pages(size_t bytes) {
|
||||
return ((bytes - 1) / page_size) + 1;
|
||||
}
|
||||
|
||||
/// \defgroup memory_types
|
||||
/// Custom UEFI memory type values used for data being passed to the kernel
|
||||
/// @{
|
||||
|
||||
/// Memory containing the kernel args structure
|
||||
constexpr uefi::memory_type args_type =
|
||||
static_cast<uefi::memory_type>(0x80000000);
|
||||
|
||||
/// Memory containing any loaded modules to be passed to the kernel
|
||||
constexpr uefi::memory_type module_type =
|
||||
static_cast<uefi::memory_type>(0x80000001);
|
||||
|
||||
/// Memory containing loaded kernel code and data sections
|
||||
constexpr uefi::memory_type kernel_type =
|
||||
static_cast<uefi::memory_type>(0x80000002);
|
||||
|
||||
/// Memory containing page tables set up by the loader
|
||||
constexpr uefi::memory_type table_type =
|
||||
static_cast<uefi::memory_type>(0x80000003);
|
||||
|
||||
/// @}
|
||||
|
||||
/// \defgroup pointer_fixup
|
||||
/// Memory virtualization pointer fixup functions. Handles changing affected pointers
|
||||
/// when calling UEFI's `set_virtual_address_map` function to change the location of
|
||||
@@ -63,12 +41,13 @@ struct efi_mem_map
|
||||
using iterator = offset_iterator<desc>;
|
||||
|
||||
size_t length; ///< Total length of the map data
|
||||
size_t total; ///< Total allocated space for map data
|
||||
size_t size; ///< Size of an entry in the array
|
||||
size_t key; ///< Key for detecting changes
|
||||
uint32_t version; ///< Version of the `memory_descriptor` struct
|
||||
desc *entries; ///< The array of UEFI descriptors
|
||||
|
||||
efi_mem_map() : length(0), size(0), key(0), version(0), entries(nullptr) {}
|
||||
efi_mem_map() : length(0), total(0), size(0), key(0), version(0), entries(nullptr) {}
|
||||
|
||||
/// Get the count of entries in the array
|
||||
inline size_t num_entries() const { return length / size; }
|
||||
@@ -84,6 +63,14 @@ struct efi_mem_map
|
||||
/// \returns The uefi memory map used to build the kernel map
|
||||
efi_mem_map build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs);
|
||||
|
||||
/// Create the kernel frame allocation maps
|
||||
void build_kernel_frame_blocks(
|
||||
const kernel::args::mem_entry *map, size_t nent,
|
||||
kernel::args::header *args, uefi::boot_services *bs);
|
||||
|
||||
/// Map the frame allocation maps to the right spot and fix up pointers
|
||||
void fix_frame_blocks(kernel::args::header *args);
|
||||
|
||||
/// Activate the given memory mappings. Sets the given page tables live as well
|
||||
/// as informs UEFI runtime services of the new mappings.
|
||||
/// \arg pml4 The root page table for the new mappings
|
||||
|
||||
@@ -6,13 +6,16 @@
|
||||
#include "memory.h"
|
||||
#include "paging.h"
|
||||
#include "pointer_manipulation.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace boot {
|
||||
namespace paging {
|
||||
|
||||
using memory::page_size;
|
||||
using ::memory::pml4e_kernel;
|
||||
using ::memory::table_entries;
|
||||
|
||||
// Flags: 0 0 0 1 0 0 0 0 0 0 1 1 = 0x0103
|
||||
// Flags: 0 0 0 1 0 0 0 0 0 0 0 1 = 0x0101
|
||||
// IGN | | | | | | | | +- Present
|
||||
// | | | | | | | +--- Writeable
|
||||
// | | | | | | +----- Usermode access (supervisor only)
|
||||
@@ -23,9 +26,9 @@ using memory::page_size;
|
||||
// | +---------------- PAT (determining memory type for page)
|
||||
// +------------------- Global
|
||||
/// Page table entry flags for entries pointing at a page
|
||||
constexpr uint16_t page_flags = 0x103;
|
||||
constexpr uint64_t page_flags = 0x101;
|
||||
|
||||
// Flags: 0 0 0 0 1 1 0 0 0 0 0 1 1 = 0x0183
|
||||
// Flags: 0 0 0 0 1 1 0 0 0 1 0 1 1 = 0x018b
|
||||
// | IGN | | | | | | | | +- Present
|
||||
// | | | | | | | | +--- Writeable
|
||||
// | | | | | | | +----- Supervisor only
|
||||
@@ -37,7 +40,7 @@ constexpr uint16_t page_flags = 0x103;
|
||||
// | +------------------- Global
|
||||
// +---------------------------- PAT (determining memory type for page)
|
||||
/// Page table entry flags for entries pointing at a huge page
|
||||
constexpr uint16_t huge_page_flags = 0x183;
|
||||
constexpr uint64_t huge_page_flags = 0x18b;
|
||||
|
||||
// Flags: 0 0 0 0 0 0 0 0 0 0 1 1 = 0x0003
|
||||
// IGNORED | | | | | | | +- Present
|
||||
@@ -49,7 +52,7 @@ constexpr uint16_t huge_page_flags = 0x183;
|
||||
// | +-------------- Ignored
|
||||
// +---------------- Reserved 0 (Table pointer, not page)
|
||||
/// Page table entry flags for entries pointing at another table
|
||||
constexpr uint16_t table_flags = 0x003;
|
||||
constexpr uint64_t table_flags = 0x003;
|
||||
|
||||
/// Iterator over page table entries.
|
||||
template <unsigned D = 4>
|
||||
@@ -65,7 +68,7 @@ public:
|
||||
uintptr_t virt,
|
||||
page_table *pml4,
|
||||
void *&page_cache,
|
||||
uint32_t &cache_count) :
|
||||
size_t &cache_count) :
|
||||
m_page_cache(page_cache),
|
||||
m_cache_count(cache_count)
|
||||
{
|
||||
@@ -115,7 +118,7 @@ private:
|
||||
|
||||
if (!(parent_ent & 1)) {
|
||||
if (!m_cache_count--)
|
||||
error::raise(uefi::status::out_of_resources, L"Page table cache empty");
|
||||
error::raise(uefi::status::out_of_resources, L"Page table cache empty", 0x7ab1e5);
|
||||
|
||||
page_table *table = reinterpret_cast<page_table*>(m_page_cache);
|
||||
m_page_cache = offset_ptr<void>(m_page_cache, page_size);
|
||||
@@ -128,14 +131,14 @@ private:
|
||||
}
|
||||
|
||||
void *&m_page_cache;
|
||||
uint32_t &m_cache_count;
|
||||
size_t &m_cache_count;
|
||||
page_table *m_table[D];
|
||||
uint16_t m_index[D];
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
add_offset_mappings(page_table *pml4, void *&page_cache, uint32_t &num_pages)
|
||||
add_offset_mappings(page_table *pml4, void *&page_cache, size_t &num_pages)
|
||||
{
|
||||
uintptr_t phys = 0;
|
||||
uintptr_t virt = ::memory::page_offset; // Start of offset-mapped area
|
||||
@@ -157,6 +160,16 @@ add_offset_mappings(page_table *pml4, void *&page_cache, uint32_t &num_pages)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_kernel_pds(page_table *pml4, void *&page_cache, size_t &num_pages)
|
||||
{
|
||||
for (unsigned i = pml4e_kernel; i < table_entries; ++i) {
|
||||
pml4->set(i, page_cache, table_flags);
|
||||
page_cache = offset_ptr<void>(page_cache, page_size);
|
||||
num_pages--;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
add_current_mappings(page_table *new_pml4)
|
||||
{
|
||||
@@ -177,51 +190,73 @@ allocate_tables(kernel::args::header *args, uefi::boot_services *bs)
|
||||
{
|
||||
status_line status(L"Allocating initial page tables");
|
||||
|
||||
static constexpr size_t offset_map_tables = 128 + 1;
|
||||
static constexpr size_t tables_needed = offset_map_tables + 49;
|
||||
static constexpr size_t pd_tables = 256; // number of pages for kernelspace PDs
|
||||
static constexpr size_t extra_tables = 64; // number of extra pages
|
||||
|
||||
// number of pages for kernelspace PDs + PML4
|
||||
static constexpr size_t kernel_tables = pd_tables + 1;
|
||||
|
||||
static constexpr size_t tables_needed = kernel_tables + extra_tables;
|
||||
|
||||
void *addr = nullptr;
|
||||
try_or_raise(
|
||||
bs->allocate_pages(
|
||||
uefi::allocate_type::any_pages,
|
||||
memory::table_type,
|
||||
uefi::memory_type::loader_data,
|
||||
tables_needed,
|
||||
&addr),
|
||||
L"Error allocating page table pages.");
|
||||
|
||||
bs->set_mem(addr, tables_needed*page_size, 0);
|
||||
|
||||
kernel::args::module &mod = args->modules[++args->num_modules];
|
||||
mod.type = kernel::args::mod_type::page_tables;
|
||||
mod.location = addr;
|
||||
mod.size = tables_needed*page_size;
|
||||
|
||||
args->pml4 = addr;
|
||||
args->num_free_tables = tables_needed - 1;
|
||||
args->page_table_cache = offset_ptr<void>(addr, page_size);
|
||||
|
||||
page_table *pml4 = reinterpret_cast<page_table*>(addr);
|
||||
add_offset_mappings(pml4, args->page_table_cache, args->num_free_tables);
|
||||
|
||||
console::print(L" Set up initial mappings, %d spare tables.\r\n", args->num_free_tables);
|
||||
args->pml4 = pml4;
|
||||
args->table_pages = tables_needed;
|
||||
args->table_count = tables_needed - 1;
|
||||
args->page_tables = offset_ptr<void>(addr, page_size);
|
||||
|
||||
console::print(L" First page (pml4) at: 0x%lx\r\n", pml4);
|
||||
|
||||
add_kernel_pds(pml4, args->page_tables, args->table_count);
|
||||
add_offset_mappings(pml4, args->page_tables, args->table_count);
|
||||
|
||||
//console::print(L" Set up initial mappings, %d spare tables.\r\n", args->table_count);
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
constexpr bool has_flag(E set, E flag) {
|
||||
return
|
||||
(static_cast<uint64_t>(set) & static_cast<uint64_t>(flag)) ==
|
||||
static_cast<uint64_t>(flag);
|
||||
}
|
||||
|
||||
void
|
||||
map_pages(
|
||||
page_table *pml4,
|
||||
kernel::args::header *args,
|
||||
uintptr_t phys, uintptr_t virt,
|
||||
size_t size)
|
||||
size_t count, bool write_flag, bool exe_flag)
|
||||
{
|
||||
size_t pages = memory::bytes_to_pages(size);
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
paging::page_table *pml4 =
|
||||
reinterpret_cast<paging::page_table*>(args->pml4);
|
||||
|
||||
page_entry_iterator<4> iterator{
|
||||
virt, pml4,
|
||||
args->page_table_cache,
|
||||
args->num_free_tables};
|
||||
args->page_tables,
|
||||
args->table_count};
|
||||
|
||||
uint64_t flags = page_flags;
|
||||
if (!exe_flag)
|
||||
flags |= (1ull << 63); // set NX bit
|
||||
if (write_flag)
|
||||
flags |= 2;
|
||||
|
||||
while (true) {
|
||||
*iterator = phys | page_flags;
|
||||
if (--pages == 0)
|
||||
*iterator = phys | flags;
|
||||
if (--count == 0)
|
||||
break;
|
||||
|
||||
iterator.increment();
|
||||
@@ -229,6 +264,24 @@ map_pages(
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
map_section(
|
||||
kernel::args::header *args,
|
||||
const kernel::args::program_section §ion)
|
||||
{
|
||||
using kernel::args::section_flags;
|
||||
|
||||
size_t pages = memory::bytes_to_pages(section.size);
|
||||
|
||||
map_pages(
|
||||
args,
|
||||
section.phys_addr,
|
||||
section.virt_addr,
|
||||
pages,
|
||||
has_flag(section.type, section_flags::write),
|
||||
has_flag(section.type, section_flags::execute));
|
||||
}
|
||||
|
||||
|
||||
} // namespace paging
|
||||
} // namespace boot
|
||||
|
||||
@@ -38,17 +38,22 @@ void allocate_tables(
|
||||
/// tables in the current PML4.
|
||||
void add_current_mappings(page_table *new_pml4);
|
||||
|
||||
/// Map a physical address to a virtual address in the given page tables.
|
||||
/// \arg pml4 The root of the set of page tables to be updated
|
||||
/// \arg args The kernel args header, used for the page table cache
|
||||
/// \arg phys The phyiscal address to map in
|
||||
/// \arg virt The virtual address to map in
|
||||
/// \arg size The size in bytes of the mapping
|
||||
/// Map physical memory pages to virtual addresses in the given page tables.
|
||||
/// \arg args The kernel args header, used for the page table cache and pml4
|
||||
/// \arg section The program section to load
|
||||
void map_pages(
|
||||
page_table *pml4,
|
||||
kernel::args::header *args,
|
||||
uintptr_t phys, uintptr_t virt,
|
||||
size_t bytes);
|
||||
size_t count, bool write_flag, bool exe_flag);
|
||||
|
||||
/// Map a program section in physical memory to its virtual address in the
|
||||
/// given page tables.
|
||||
/// \arg args The kernel args header, used for the page table cache and pml4
|
||||
/// \arg section The program section to load
|
||||
void map_section(
|
||||
kernel::args::header *args,
|
||||
const kernel::args::program_section §ion);
|
||||
|
||||
|
||||
} // namespace paging
|
||||
} // namespace boot
|
||||
|
||||
265
src/boot/status.cpp
Normal file
265
src/boot/status.cpp
Normal file
@@ -0,0 +1,265 @@
|
||||
#include <uefi/types.h>
|
||||
#include <uefi/graphics.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "error.h"
|
||||
#include "kernel_args.h"
|
||||
#include "status.h"
|
||||
|
||||
constexpr int num_boxes = 30;
|
||||
|
||||
namespace boot {
|
||||
|
||||
static constexpr int level_ok = 0;
|
||||
static constexpr int level_warn = 1;
|
||||
static constexpr int level_fail = 2;
|
||||
|
||||
static const wchar_t *level_tags[] = {
|
||||
L" ok ",
|
||||
L" warn ",
|
||||
L"failed"
|
||||
};
|
||||
|
||||
static const uefi::attribute level_colors[] = {
|
||||
uefi::attribute::green,
|
||||
uefi::attribute::brown,
|
||||
uefi::attribute::light_red
|
||||
};
|
||||
|
||||
status *status::s_current = nullptr;
|
||||
unsigned status::s_current_type = 0;
|
||||
unsigned status_bar::s_count = 0;
|
||||
|
||||
status_line::status_line(const wchar_t *message, const wchar_t *context, bool fails_clean) :
|
||||
status(fails_clean),
|
||||
m_level(level_ok),
|
||||
m_depth(0),
|
||||
m_outer(nullptr)
|
||||
{
|
||||
if (status::s_current_type == status_line::type) {
|
||||
m_outer = static_cast<status_line*>(s_current);
|
||||
m_depth = (m_outer ? 1 + m_outer->m_depth : 0);
|
||||
}
|
||||
s_current = this;
|
||||
s_current_type = status_line::type;
|
||||
|
||||
auto out = console::get().m_out;
|
||||
m_line = out->mode->cursor_row;
|
||||
|
||||
int indent = 2 * m_depth;
|
||||
out->set_cursor_position(indent, m_line);
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(message);
|
||||
|
||||
if (context) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(context);
|
||||
}
|
||||
|
||||
out->output_string(L"\r\n");
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
status_line::~status_line()
|
||||
{
|
||||
if (s_current != this)
|
||||
error::raise(uefi::status::unsupported, L"Destroying non-current status_line");
|
||||
|
||||
if (m_outer && m_level > m_outer->m_level) {
|
||||
m_outer->m_level = m_level;
|
||||
m_outer->print_status_tag();
|
||||
}
|
||||
s_current = m_outer;
|
||||
}
|
||||
|
||||
void
|
||||
status_line::print_status_tag()
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
int col = out->mode->cursor_column;
|
||||
|
||||
uefi::attribute color = level_colors[m_level];
|
||||
const wchar_t *tag = level_tags[m_level];
|
||||
|
||||
out->set_cursor_position(50, m_line);
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"[");
|
||||
out->set_attribute(color);
|
||||
out->output_string(tag);
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"]\r\n");
|
||||
|
||||
out->set_cursor_position(col, row);
|
||||
}
|
||||
|
||||
void
|
||||
status_line::do_warn(const wchar_t *message, uefi::status status)
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
|
||||
if (m_level < level_warn) {
|
||||
m_level = level_warn;
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
int indent = 2 + 2 * m_depth;
|
||||
out->set_cursor_position(indent, row);
|
||||
out->set_attribute(uefi::attribute::yellow);
|
||||
out->output_string(message);
|
||||
|
||||
const wchar_t *error = error::message(status);
|
||||
if (error) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(error);
|
||||
}
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"\r\n");
|
||||
}
|
||||
|
||||
void
|
||||
status_line::do_fail(const wchar_t *message, uefi::status status)
|
||||
{
|
||||
auto out = console::get().m_out;
|
||||
int row = out->mode->cursor_row;
|
||||
|
||||
if (m_level < level_fail) {
|
||||
m_level = level_fail;
|
||||
print_status_tag();
|
||||
}
|
||||
|
||||
int indent = 2 + 2 * m_depth;
|
||||
out->set_cursor_position(indent, row);
|
||||
out->set_attribute(uefi::attribute::red);
|
||||
out->output_string(message);
|
||||
|
||||
const wchar_t *error = error::message(status);
|
||||
if (error) {
|
||||
out->output_string(L": ");
|
||||
out->output_string(error);
|
||||
}
|
||||
|
||||
out->set_attribute(uefi::attribute::light_gray);
|
||||
out->output_string(L"\r\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
status_bar::status_bar(kernel::args::framebuffer const &fb) :
|
||||
status(fb.size),
|
||||
m_outer(nullptr)
|
||||
{
|
||||
m_size = (fb.vertical / num_boxes) - 1;
|
||||
m_top = fb.vertical - m_size;
|
||||
m_horiz = fb.horizontal;
|
||||
m_fb = reinterpret_cast<uint32_t*>(fb.phys_addr);
|
||||
m_type = static_cast<uint16_t>(fb.type);
|
||||
next();
|
||||
|
||||
if (status::s_current_type == status_bar::type)
|
||||
m_outer = static_cast<status_bar*>(s_current);
|
||||
s_current = this;
|
||||
s_current_type = status_bar::type;
|
||||
}
|
||||
|
||||
status_bar::~status_bar()
|
||||
{
|
||||
if (s_current != this)
|
||||
error::raise(uefi::status::unsupported, L"Destroying non-current status_bar");
|
||||
draw_box();
|
||||
s_current = m_outer;
|
||||
}
|
||||
|
||||
void
|
||||
status_bar::do_warn(const wchar_t *message, uefi::status status)
|
||||
{
|
||||
m_status = status;
|
||||
if (m_level < level_warn) {
|
||||
m_level = level_warn;
|
||||
draw_box();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
status_bar::do_fail(const wchar_t *message, uefi::status status)
|
||||
{
|
||||
m_status = status;
|
||||
if (m_level < level_fail) {
|
||||
m_level = level_fail;
|
||||
draw_box();
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
make_color(uint8_t r, uint8_t g, uint8_t b, uint16_t type)
|
||||
{
|
||||
switch (static_cast<kernel::args::fb_type>(type)) {
|
||||
case kernel::args::fb_type::bgr8:
|
||||
return
|
||||
(static_cast<uint32_t>(b) << 0) |
|
||||
(static_cast<uint32_t>(g) << 8) |
|
||||
(static_cast<uint32_t>(r) << 16);
|
||||
|
||||
case kernel::args::fb_type::rgb8:
|
||||
return
|
||||
(static_cast<uint32_t>(r) << 0) |
|
||||
(static_cast<uint32_t>(g) << 8) |
|
||||
(static_cast<uint32_t>(b) << 16);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
status_bar::draw_box()
|
||||
{
|
||||
static const uint32_t colors[] = {0x909090, 0xf0f0f0};
|
||||
constexpr unsigned ncolors = sizeof(colors) / sizeof(uint32_t);
|
||||
|
||||
if (m_fb == nullptr)
|
||||
return;
|
||||
|
||||
unsigned x0 = m_current * m_size;
|
||||
unsigned x1 = x0 + m_size - 3;
|
||||
unsigned y0 = m_top;
|
||||
unsigned y1 = m_top + m_size - 3;
|
||||
|
||||
uint32_t color = 0;
|
||||
switch (m_level) {
|
||||
case level_ok:
|
||||
color = colors[m_current % ncolors];
|
||||
break;
|
||||
case level_warn:
|
||||
color = make_color(0xff, 0xb2, 0x34, m_type);
|
||||
break;
|
||||
case level_fail:
|
||||
color = make_color(0xfb, 0x0a, 0x1e, m_type);
|
||||
break;
|
||||
default:
|
||||
color = 0;
|
||||
}
|
||||
|
||||
for (unsigned y = y0; y < y1; ++y)
|
||||
for (unsigned x = x0; x < x1; ++x)
|
||||
m_fb[y * m_horiz + x] = color;
|
||||
|
||||
if (m_level > level_ok) {
|
||||
unsigned nbars = static_cast<uint64_t>(m_status) & 0xffff;
|
||||
constexpr unsigned bar_height = 4;
|
||||
|
||||
for (unsigned i = 1; i <= nbars; ++i) {
|
||||
y0 = m_top - 2 * i * bar_height;
|
||||
y1 = y0 + bar_height;
|
||||
|
||||
for (unsigned y = y0; y < y1; ++y)
|
||||
for (unsigned x = x0; x < x1; ++x)
|
||||
m_fb[y * m_horiz + x] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace boot
|
||||
131
src/boot/status.h
Normal file
131
src/boot/status.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/// \file status.h
|
||||
/// Status message and indicator handling
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <uefi/types.h>
|
||||
|
||||
namespace kernel {
|
||||
namespace args {
|
||||
class framebuffer;
|
||||
}
|
||||
}
|
||||
|
||||
namespace boot {
|
||||
|
||||
// Abstract base class for status reporters.
|
||||
class status
|
||||
{
|
||||
public:
|
||||
status(bool fails_clean = true) : m_fails_clean(fails_clean) {}
|
||||
|
||||
virtual void do_warn(const wchar_t *message, uefi::status status) = 0;
|
||||
virtual void do_fail(const wchar_t *message, uefi::status status) = 0;
|
||||
|
||||
/// Set the state to warning, and print a message. If the state is already at
|
||||
/// warning or error, the state is unchanged but the message is still printed.
|
||||
/// \arg message The warning message to print, if text is supported
|
||||
/// \arg status If set, the error or warning code that should be represented
|
||||
/// \returns True if there was a status handler to display the warning
|
||||
inline static bool warn(const wchar_t *message, uefi::status status = uefi::status::success) {
|
||||
if (!s_current) return false;
|
||||
s_current->do_warn(message, status);
|
||||
return s_current->m_fails_clean;
|
||||
}
|
||||
|
||||
/// Set the state to error, and print a message. If the state is already at
|
||||
/// error, the state is unchanged but the message is still printed.
|
||||
/// \arg message The error message to print, if text is supported
|
||||
/// \arg status The error or warning code that should be represented
|
||||
/// \returns True if there was a status handler to display the failure
|
||||
inline static bool fail(const wchar_t *message, uefi::status status) {
|
||||
if (!s_current) return false;
|
||||
s_current->do_fail(message, status);
|
||||
return s_current->m_fails_clean;
|
||||
}
|
||||
|
||||
protected:
|
||||
static status *s_current;
|
||||
static unsigned s_current_type;
|
||||
|
||||
private:
|
||||
bool m_fails_clean;
|
||||
};
|
||||
|
||||
/// Scoped status line reporter. Prints a message and an "OK" if no errors
|
||||
/// or warnings were reported before destruction, otherwise reports the
|
||||
/// error or warning.
|
||||
class status_line :
|
||||
public status
|
||||
{
|
||||
public:
|
||||
constexpr static unsigned type = 1;
|
||||
|
||||
/// Constructor.
|
||||
/// \arg message Description of the operation in progress
|
||||
/// \arg context If non-null, printed after `message` and a colon
|
||||
/// \arg fails_clean If true, this object can handle printing failure
|
||||
status_line(
|
||||
const wchar_t *message,
|
||||
const wchar_t *context = nullptr,
|
||||
bool fails_clean = true);
|
||||
~status_line();
|
||||
|
||||
virtual void do_warn(const wchar_t *message, uefi::status status) override;
|
||||
virtual void do_fail(const wchar_t *message, uefi::status status) override;
|
||||
|
||||
private:
|
||||
void print_status_tag();
|
||||
|
||||
size_t m_line;
|
||||
int m_level;
|
||||
int m_depth;
|
||||
|
||||
status_line *m_outer;
|
||||
};
|
||||
|
||||
/// Scoped status bar reporter. Draws a row of boxes along the bottom of
|
||||
/// the screen, turning one red if there's an error in that step.
|
||||
class status_bar :
|
||||
public status
|
||||
{
|
||||
public:
|
||||
constexpr static unsigned type = 2;
|
||||
|
||||
using framebuffer = kernel::args::framebuffer;
|
||||
|
||||
/// Constructor.
|
||||
/// \arg fb The framebuffer descriptor to draw to
|
||||
status_bar(kernel::args::framebuffer const &fb);
|
||||
~status_bar();
|
||||
|
||||
virtual void do_warn(const wchar_t *message, uefi::status status) override;
|
||||
virtual void do_fail(const wchar_t *message, uefi::status status) override;
|
||||
|
||||
inline void next() {
|
||||
m_current = s_count++;
|
||||
m_level = 0;
|
||||
m_status = uefi::status::success;
|
||||
draw_box();
|
||||
}
|
||||
|
||||
private:
|
||||
void draw_box();
|
||||
|
||||
uint32_t *m_fb;
|
||||
uint32_t m_size;
|
||||
uint32_t m_top;
|
||||
uint32_t m_horiz;
|
||||
|
||||
int m_level;
|
||||
uefi::status m_status;
|
||||
|
||||
uint16_t m_type;
|
||||
uint16_t m_current;
|
||||
|
||||
status_bar *m_outer;
|
||||
|
||||
static unsigned s_count;
|
||||
};
|
||||
|
||||
} // namespace boot
|
||||
13
src/boot/types.h
Normal file
13
src/boot/types.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/// \file types.h
|
||||
/// Definitions of shared types used throughout the bootloader
|
||||
#pragma once
|
||||
|
||||
namespace boot {
|
||||
|
||||
struct buffer
|
||||
{
|
||||
size_t size;
|
||||
void *data;
|
||||
};
|
||||
|
||||
} // namespace boot
|
||||
390
src/drivers/fb/default_font.inc
Normal file
390
src/drivers/fb/default_font.inc
Normal file
@@ -0,0 +1,390 @@
|
||||
0x72, 0xb5, 0x4a, 0x86, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
|
||||
0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
|
||||
0x22, 0x20, 0x20, 0xf8, 0x20, 0x20, 0x72, 0x8c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x7e, 0x24, 0x24,
|
||||
0x24, 0x7e, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
|
||||
0x1e, 0x20, 0x20, 0x1c, 0x02, 0x02, 0x3c, 0x08, 0x08, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x30, 0x49, 0x4a, 0x34, 0x08, 0x16, 0x29, 0x49, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x48, 0x48, 0x48, 0x30, 0x31,
|
||||
0x49, 0x46, 0x46, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10,
|
||||
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08,
|
||||
0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x24, 0x18, 0x7e, 0x18, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x7f, 0x08, 0x08, 0x08, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x18, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08,
|
||||
0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
|
||||
0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x04,
|
||||
0x08, 0x10, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
|
||||
0x04, 0x08, 0x1c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x04, 0x0c, 0x14, 0x24, 0x44, 0x7e, 0x04, 0x04, 0x04,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x7c, 0x02,
|
||||
0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
|
||||
0x20, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7e, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c,
|
||||
0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
|
||||
0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
|
||||
0x00, 0x00, 0x18, 0x18, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04,
|
||||
0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02,
|
||||
0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42,
|
||||
0x02, 0x04, 0x08, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1c, 0x22, 0x41, 0x4f, 0x51, 0x51, 0x51, 0x53, 0x4d, 0x40,
|
||||
0x20, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42,
|
||||
0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
|
||||
0x42, 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1e, 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x1e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x44, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
|
||||
0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x20, 0x40, 0x40, 0x46,
|
||||
0x42, 0x42, 0x22, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
|
||||
0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
|
||||
0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x63, 0x55, 0x49, 0x49,
|
||||
0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
|
||||
0x62, 0x52, 0x4a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c,
|
||||
0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x04, 0x02, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x48, 0x44, 0x42, 0x42,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x40, 0x20, 0x18,
|
||||
0x04, 0x02, 0x02, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x24, 0x24, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
|
||||
0x41, 0x41, 0x41, 0x49, 0x49, 0x49, 0x55, 0x63, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08, 0x14, 0x22, 0x41, 0x41,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
|
||||
0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1e, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10,
|
||||
0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x78, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00, 0x00,
|
||||
0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x02, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x10,
|
||||
0x10, 0x7e, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e,
|
||||
0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
|
||||
0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x04, 0x00, 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x38, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x44, 0x48, 0x50,
|
||||
0x70, 0x48, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7c,
|
||||
0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x2e, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x20, 0x18, 0x04, 0x02, 0x7c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x7e, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x24, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41,
|
||||
0x49, 0x49, 0x55, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x41, 0x22, 0x14, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e,
|
||||
0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08,
|
||||
0x10, 0x20, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0xe0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, 0x00, 0x00,
|
||||
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x00, 0x00, 0x00, 0x70, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x70, 0x00, 0x00, 0x00, 0x00, 0x31, 0x49,
|
||||
0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,
|
||||
0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x08, 0x08,
|
||||
0x1c, 0x22, 0x40, 0x40, 0x40, 0x22, 0x1c, 0x08, 0x08, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1c, 0x22, 0x20, 0x20, 0xf8, 0x20, 0x20, 0x72, 0x8c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3c, 0x24, 0x24,
|
||||
0x24, 0x3c, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
|
||||
0x22, 0x14, 0x08, 0x3e, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08,
|
||||
0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1c, 0x22, 0x41, 0x4d, 0x51, 0x51, 0x4d, 0x41, 0x22,
|
||||
0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x09, 0x12, 0x24, 0x48, 0x24, 0x12, 0x09, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x08, 0x08, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x24, 0x12, 0x09, 0x12, 0x24, 0x48,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00,
|
||||
0x00, 0x08, 0x10, 0x20, 0x40, 0x42, 0x3c, 0x00, 0x20, 0x10, 0x00, 0x18,
|
||||
0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x08, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24,
|
||||
0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x18,
|
||||
0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x24, 0x00, 0x18, 0x18, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x18, 0x18, 0x24, 0x24, 0x24,
|
||||
0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f,
|
||||
0x14, 0x14, 0x24, 0x27, 0x3c, 0x44, 0x44, 0x47, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1e, 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x1e,
|
||||
0x08, 0x08, 0x30, 0x00, 0x20, 0x10, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c,
|
||||
0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x7e,
|
||||
0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x24, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x7e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c,
|
||||
0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x3e,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x08, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x00, 0x3e,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3c, 0x22, 0x21, 0x21, 0x79, 0x21, 0x21, 0x22, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x42, 0x62, 0x52, 0x4a, 0x46,
|
||||
0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x1c,
|
||||
0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x08, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41,
|
||||
0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x1c,
|
||||
0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x24, 0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14,
|
||||
0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x3c,
|
||||
0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x42, 0x3c, 0x40, 0x00, 0x00, 0x00,
|
||||
0x20, 0x10, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
|
||||
0x40, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3c, 0x42, 0x44, 0x4c, 0x42, 0x42, 0x42, 0x44, 0x58,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x3c, 0x02, 0x02,
|
||||
0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08,
|
||||
0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x3c, 0x02, 0x02,
|
||||
0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24,
|
||||
0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x24, 0x24, 0x18, 0x00, 0x3c, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x09, 0x39,
|
||||
0x4f, 0x48, 0x48, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3c, 0x08, 0x08, 0x30, 0x00,
|
||||
0x00, 0x00, 0x20, 0x10, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x24, 0x24, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x38, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08,
|
||||
0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x24, 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x00, 0x38, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x06, 0x1a,
|
||||
0x01, 0x1d, 0x23, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x32, 0x4c, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x3c, 0x46, 0x4a,
|
||||
0x52, 0x62, 0x42, 0x3c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10,
|
||||
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x08, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24,
|
||||
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x08, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e,
|
||||
0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x41,
|
||||
0x41, 0x41, 0x62, 0x5c, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x24, 0x24,
|
||||
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00,
|
||||
0xff, 0xff, 0xe2, 0x96, 0x92, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0xb0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xe2, 0x94, 0x98, 0xff, 0xe2, 0x94, 0x90, 0xff,
|
||||
0xe2, 0x94, 0x8c, 0xff, 0xe2, 0x94, 0x94, 0xff, 0xe2, 0x94, 0xbc, 0xff,
|
||||
0xff, 0xff, 0xe2, 0x94, 0x80, 0xff, 0xff, 0xff, 0xe2, 0x94, 0x9c, 0xff,
|
||||
0xe2, 0x94, 0xa4, 0xff, 0xe2, 0x94, 0xb4, 0xff, 0xe2, 0x94, 0xac, 0xff,
|
||||
0xe2, 0x94, 0x82, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0xa3, 0xff, 0xff,
|
||||
0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff, 0x24, 0xff, 0x25, 0xff,
|
||||
0x26, 0xff, 0x27, 0xff, 0x28, 0xff, 0x29, 0xff, 0x2a, 0xff, 0x2b, 0xff,
|
||||
0x2c, 0xff, 0x2d, 0xff, 0x2e, 0xff, 0x2f, 0xff, 0x30, 0xff, 0x31, 0xff,
|
||||
0x32, 0xff, 0x33, 0xff, 0x34, 0xff, 0x35, 0xff, 0x36, 0xff, 0x37, 0xff,
|
||||
0x38, 0xff, 0x39, 0xff, 0x3a, 0xff, 0x3b, 0xff, 0x3c, 0xff, 0x3d, 0xff,
|
||||
0x3e, 0xff, 0x3f, 0xff, 0x40, 0xff, 0x41, 0xff, 0x42, 0xff, 0x43, 0xff,
|
||||
0x44, 0xff, 0x45, 0xff, 0x46, 0xff, 0x47, 0xff, 0x48, 0xff, 0x49, 0xff,
|
||||
0x4a, 0xff, 0x4b, 0xff, 0x4c, 0xff, 0x4d, 0xff, 0x4e, 0xff, 0x4f, 0xff,
|
||||
0x50, 0xff, 0x51, 0xff, 0x52, 0xff, 0x53, 0xff, 0x54, 0xff, 0x55, 0xff,
|
||||
0x56, 0xff, 0x57, 0xff, 0x58, 0xff, 0x59, 0xff, 0x5a, 0xff, 0x5b, 0xff,
|
||||
0x5c, 0xff, 0x5d, 0xff, 0x5e, 0xff, 0x5f, 0xff, 0x60, 0xff, 0x61, 0xff,
|
||||
0x62, 0xff, 0x63, 0xff, 0x64, 0xff, 0x65, 0xff, 0x66, 0xff, 0x67, 0xff,
|
||||
0x68, 0xff, 0x69, 0xff, 0x6a, 0xff, 0x6b, 0xff, 0x6c, 0xff, 0x6d, 0xff,
|
||||
0x6e, 0xff, 0x6f, 0xff, 0x70, 0xff, 0x71, 0xff, 0x72, 0xff, 0x73, 0xff,
|
||||
0x74, 0xff, 0x75, 0xff, 0x76, 0xff, 0x77, 0xff, 0x78, 0xff, 0x79, 0xff,
|
||||
0x7a, 0xff, 0x7b, 0xff, 0x7c, 0xff, 0x7d, 0xff, 0x7e, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0xa0, 0xff, 0xc2, 0xa1,
|
||||
0xff, 0xc2, 0xa2, 0xff, 0xc2, 0xa3, 0xff, 0xc2, 0xa4, 0xff, 0xc2, 0xa5,
|
||||
0xff, 0xc2, 0xa6, 0xff, 0xff, 0xc2, 0xa8, 0xff, 0xc2, 0xa9, 0xff, 0xff,
|
||||
0xc2, 0xab, 0xff, 0xff, 0xc2, 0xad, 0xff, 0xff, 0xff, 0xc2, 0xb0, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0xb8, 0xff, 0xff, 0xff,
|
||||
0xc2, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xc2, 0xbf, 0xff, 0xc3, 0x80, 0xff,
|
||||
0xc3, 0x81, 0xff, 0xc3, 0x82, 0xff, 0xc3, 0x83, 0xff, 0xc3, 0x84, 0xff,
|
||||
0xc3, 0x85, 0xff, 0xc3, 0x86, 0xff, 0xc3, 0x87, 0xff, 0xc3, 0x88, 0xff,
|
||||
0xc3, 0x89, 0xff, 0xc3, 0x8a, 0xff, 0xc3, 0x8b, 0xff, 0xc3, 0x8c, 0xff,
|
||||
0xc3, 0x8d, 0xff, 0xc3, 0x8e, 0xff, 0xc3, 0x8f, 0xff, 0xc3, 0x90, 0xff,
|
||||
0xc3, 0x91, 0xff, 0xc3, 0x92, 0xff, 0xc3, 0x93, 0xff, 0xc3, 0x94, 0xff,
|
||||
0xc3, 0x95, 0xff, 0xc3, 0x96, 0xff, 0xc3, 0x97, 0xff, 0xc3, 0x98, 0xff,
|
||||
0xc3, 0x99, 0xff, 0xc3, 0x9a, 0xff, 0xc3, 0x9b, 0xff, 0xc3, 0x9c, 0xff,
|
||||
0xc3, 0x9d, 0xff, 0xc3, 0x9e, 0xff, 0xc3, 0x9f, 0xff, 0xc3, 0xa0, 0xff,
|
||||
0xc3, 0xa1, 0xff, 0xc3, 0xa2, 0xff, 0xc3, 0xa3, 0xff, 0xc3, 0xa4, 0xff,
|
||||
0xc3, 0xa5, 0xff, 0xc3, 0xa6, 0xff, 0xc3, 0xa7, 0xff, 0xc3, 0xa8, 0xff,
|
||||
0xc3, 0xa9, 0xff, 0xc3, 0xaa, 0xff, 0xc3, 0xab, 0xff, 0xc3, 0xac, 0xff,
|
||||
0xc3, 0xad, 0xff, 0xc3, 0xae, 0xff, 0xc3, 0xaf, 0xff, 0xc3, 0xb0, 0xff,
|
||||
0xc3, 0xb1, 0xff, 0xc3, 0xb2, 0xff, 0xc3, 0xb3, 0xff, 0xc3, 0xb4, 0xff,
|
||||
0xc3, 0xb5, 0xff, 0xc3, 0xb6, 0xff, 0xc3, 0xb7, 0xff, 0xc3, 0xb8, 0xff,
|
||||
0xc3, 0xb9, 0xff, 0xc3, 0xba, 0xff, 0xc3, 0xbb, 0xff, 0xc3, 0xbc, 0xff,
|
||||
0xc3, 0xbd, 0xff, 0xc3, 0xbe, 0xff, 0xc3, 0xbf, 0xff
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "kutil/assert.h"
|
||||
#include <assert.h>
|
||||
#include "font.h"
|
||||
|
||||
|
||||
/* PSF2 header format
|
||||
* Taken from the Linux KBD documentation
|
||||
* http://www.win.tue.nl/~aeb/linux/kbd/font-formats-1.html
|
||||
@@ -27,43 +28,51 @@ struct psf2_header {
|
||||
uint32_t height, width; // max dimensions of glyphs
|
||||
};
|
||||
|
||||
const uint8_t default_font[] = {
|
||||
// xxd -i < font_file.psf > default_font.inc
|
||||
#include "default_font.inc"
|
||||
};
|
||||
|
||||
font::font(void const *data) :
|
||||
m_size(0, 0),
|
||||
m_count(0),
|
||||
m_data(nullptr)
|
||||
m_sizex {0},
|
||||
m_sizey {0},
|
||||
m_count {0},
|
||||
m_data {nullptr}
|
||||
{
|
||||
if (!data)
|
||||
data = default_font;
|
||||
|
||||
psf2_header const *psf2 = static_cast<psf2_header const *>(data);
|
||||
for (int i = 0; i < sizeof(magic); ++i) {
|
||||
kassert(psf2->magic[i] == magic[i], "Bad font magic number.");
|
||||
assert(psf2->magic[i] == magic[i] && "Bad font magic number.");
|
||||
}
|
||||
|
||||
m_data = static_cast<uint8_t const *>(data) + psf2->header_size;
|
||||
m_size.x = psf2->width;
|
||||
m_size.y = psf2->height;
|
||||
m_sizex = psf2->width;
|
||||
m_sizey = psf2->height;
|
||||
m_count = psf2->length;
|
||||
}
|
||||
|
||||
void
|
||||
font::draw_glyph(
|
||||
screen *s,
|
||||
screen &s,
|
||||
uint32_t glyph,
|
||||
screen::pixel_t fg,
|
||||
screen::pixel_t bg,
|
||||
unsigned x,
|
||||
unsigned y) const
|
||||
{
|
||||
unsigned bwidth = (m_size.x+7)/8;
|
||||
unsigned bwidth = (m_sizex+7)/8;
|
||||
uint8_t const *data = m_data + (glyph * glyph_bytes());
|
||||
|
||||
for (int dy = 0; dy < m_size.y; ++dy) {
|
||||
for (int dy = 0; dy < m_sizey; ++dy) {
|
||||
for (int dx = 0; dx < bwidth; ++dx) {
|
||||
uint8_t byte = data[dy * bwidth + dx];
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
if (dx*8 + i >= m_size.x) continue;
|
||||
if (dx*8 + i >= m_sizex) break;
|
||||
const uint8_t mask = 1 << (7-i);
|
||||
uint32_t c = (byte & mask) ? fg : bg;
|
||||
s->draw_pixel(x + dx*8 + i, y + dy, c);
|
||||
s.draw_pixel(x + dx*8 + i, y + dy, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/drivers/fb/font.h
Normal file
33
src/drivers/fb/font.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
class font
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
/// \arg data The font data to load. If null, will load the default
|
||||
/// built-in font.
|
||||
font(void const *data = nullptr);
|
||||
|
||||
unsigned glyph_bytes() const { return m_sizey * ((m_sizex + 7) / 8); }
|
||||
unsigned count() const { return m_count; }
|
||||
unsigned width() const { return m_sizex; }
|
||||
unsigned height() const { return m_sizey; }
|
||||
bool valid() const { return m_count > 0; }
|
||||
|
||||
void draw_glyph(
|
||||
screen &s,
|
||||
uint32_t glyph,
|
||||
screen::pixel_t fg,
|
||||
screen::pixel_t bg,
|
||||
unsigned x,
|
||||
unsigned y) const;
|
||||
|
||||
private:
|
||||
unsigned m_sizex, m_sizey;
|
||||
unsigned m_count;
|
||||
uint8_t const *m_data;
|
||||
};
|
||||
|
||||
139
src/drivers/fb/main.cpp
Normal file
139
src/drivers/fb/main.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "j6/init.h"
|
||||
#include "j6/errors.h"
|
||||
#include "j6/flags.h"
|
||||
#include "j6/signals.h"
|
||||
#include "j6/syscalls.h"
|
||||
#include "j6/types.h"
|
||||
|
||||
#include "font.h"
|
||||
#include "screen.h"
|
||||
#include "scrollback.h"
|
||||
|
||||
extern "C" {
|
||||
int main(int, const char **);
|
||||
void _get_init(size_t *initc, struct j6_init_value **initv);
|
||||
}
|
||||
|
||||
extern j6_handle_t __handle_sys;
|
||||
extern j6_handle_t __handle_self;
|
||||
|
||||
struct entry
|
||||
{
|
||||
uint8_t bytes;
|
||||
uint8_t area;
|
||||
uint8_t severity;
|
||||
uint8_t sequence;
|
||||
char message[0];
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, const char **argv)
|
||||
{
|
||||
j6_system_log("fb driver starting");
|
||||
|
||||
size_t initc = 0;
|
||||
j6_init_value *initv = nullptr;
|
||||
_get_init(&initc, &initv);
|
||||
|
||||
j6_init_framebuffer *fb = nullptr;
|
||||
for (unsigned i = 0; i < initc; ++i) {
|
||||
if (initv[i].type == j6_init_desc_framebuffer) {
|
||||
fb = reinterpret_cast<j6_init_framebuffer*>(initv[i].data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fb || fb->addr == 0) {
|
||||
j6_system_log("fb driver didn't find a framebuffer, exiting");
|
||||
return 1;
|
||||
}
|
||||
|
||||
j6_handle_t fb_handle = j6_handle_invalid;
|
||||
uint32_t flags =
|
||||
j6_vm_flag_write |
|
||||
j6_vm_flag_write_combine;
|
||||
j6_status_t s = j6_system_map_mmio(__handle_sys, &fb_handle, fb->addr, fb->size, flags);
|
||||
if (s != j6_status_ok) {
|
||||
return s;
|
||||
}
|
||||
|
||||
s = j6_vma_map(fb_handle, __handle_self, fb->addr);
|
||||
if (s != j6_status_ok) {
|
||||
return s;
|
||||
}
|
||||
|
||||
const screen::pixel_order order = (fb->flags & 1) ?
|
||||
screen::pixel_order::bgr8 : screen::pixel_order::rgb8;
|
||||
|
||||
screen scr(
|
||||
reinterpret_cast<void*>(fb->addr),
|
||||
fb->horizontal,
|
||||
fb->vertical,
|
||||
fb->scanline,
|
||||
order);
|
||||
|
||||
font fnt;
|
||||
|
||||
screen::pixel_t fg = scr.color(0xb0, 0xb0, 0xb0);
|
||||
screen::pixel_t bg = scr.color(49, 79, 128);
|
||||
scr.fill(bg);
|
||||
scr.update();
|
||||
|
||||
constexpr int margin = 2;
|
||||
const unsigned xstride = (margin + fnt.width());
|
||||
const unsigned ystride = (margin + fnt.height());
|
||||
const unsigned rows = (scr.height() - margin) / ystride;
|
||||
const unsigned cols = (scr.width() - margin) / xstride;
|
||||
|
||||
scrollback scroll(rows, cols);
|
||||
|
||||
int pending = 0;
|
||||
constexpr int pending_threshold = 5;
|
||||
|
||||
j6_handle_t sys = __handle_sys;
|
||||
size_t buffer_size = 0;
|
||||
void *message_buffer = nullptr;
|
||||
|
||||
while (true) {
|
||||
size_t size = buffer_size;
|
||||
j6_status_t s = j6_system_get_log(sys, message_buffer, &size);
|
||||
|
||||
if (s == j6_err_insufficient) {
|
||||
free(message_buffer);
|
||||
message_buffer = malloc(size * 2);
|
||||
buffer_size = size;
|
||||
continue;
|
||||
} else if (s != j6_status_ok) {
|
||||
j6_system_log("fb driver got error from get_log, quitting");
|
||||
return s;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
entry *e = reinterpret_cast<entry*>(message_buffer);
|
||||
|
||||
size_t eom = e->bytes - sizeof(entry);
|
||||
e->message[eom] = 0;
|
||||
|
||||
scroll.add_line(e->message, eom);
|
||||
if (++pending > pending_threshold) {
|
||||
scroll.render(scr, fnt);
|
||||
scr.update();
|
||||
pending = 0;
|
||||
}
|
||||
} else {
|
||||
if (pending) {
|
||||
scroll.render(scr, fnt);
|
||||
scr.update();
|
||||
pending = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
j6_system_log("fb driver done, exiting");
|
||||
return 0;
|
||||
}
|
||||
|
||||
48
src/drivers/fb/screen.cpp
Normal file
48
src/drivers/fb/screen.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "screen.h"
|
||||
|
||||
screen::screen(volatile void *addr, unsigned hres, unsigned vres, unsigned scanline, pixel_order order) :
|
||||
m_fb(static_cast<volatile pixel_t *>(addr)),
|
||||
m_order(order),
|
||||
m_scanline(scanline),
|
||||
m_resx(hres),
|
||||
m_resy(vres)
|
||||
{
|
||||
const size_t size = scanline * vres;
|
||||
m_back = reinterpret_cast<pixel_t*>(malloc(size * sizeof(pixel_t)));
|
||||
}
|
||||
|
||||
screen::pixel_t
|
||||
screen::color(uint8_t r, uint8_t g, uint8_t b) const
|
||||
{
|
||||
switch (m_order) {
|
||||
case pixel_order::bgr8:
|
||||
return
|
||||
(static_cast<uint32_t>(b) << 0) |
|
||||
(static_cast<uint32_t>(g) << 8) |
|
||||
(static_cast<uint32_t>(r) << 16);
|
||||
|
||||
case pixel_order::rgb8:
|
||||
return
|
||||
(static_cast<uint32_t>(r) << 0) |
|
||||
(static_cast<uint32_t>(g) << 8) |
|
||||
(static_cast<uint32_t>(b) << 16);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
screen::fill(pixel_t color)
|
||||
{
|
||||
const size_t len = m_scanline * m_resy;
|
||||
asm volatile ( "rep stosl" : :
|
||||
"a"(color), "c"(len), "D"(m_back) );
|
||||
}
|
||||
|
||||
void
|
||||
screen::update()
|
||||
{
|
||||
const size_t len = m_scanline * m_resy * sizeof(pixel_t);
|
||||
asm volatile ( "rep movsb" : :
|
||||
"c"(len), "S"(m_back), "D"(m_fb) );
|
||||
}
|
||||
36
src/drivers/fb/screen.h
Normal file
36
src/drivers/fb/screen.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
class screen
|
||||
{
|
||||
public:
|
||||
using pixel_t = uint32_t;
|
||||
|
||||
enum class pixel_order : uint8_t { bgr8, rgb8, };
|
||||
|
||||
screen(volatile void *addr, unsigned hres, unsigned vres, unsigned scanline, pixel_order order);
|
||||
|
||||
unsigned width() const { return m_resx; }
|
||||
unsigned height() const { return m_resy; }
|
||||
|
||||
pixel_t color(uint8_t r, uint8_t g, uint8_t b) const;
|
||||
|
||||
void fill(pixel_t color);
|
||||
|
||||
inline void draw_pixel(unsigned x, unsigned y, pixel_t color) {
|
||||
const size_t index = x + y * m_scanline;
|
||||
m_back[index] = color;
|
||||
}
|
||||
|
||||
void update();
|
||||
|
||||
private:
|
||||
volatile pixel_t *m_fb;
|
||||
pixel_t *m_back;
|
||||
pixel_order m_order;
|
||||
unsigned m_scanline;
|
||||
unsigned m_resx, m_resy;
|
||||
|
||||
screen() = delete;
|
||||
};
|
||||
58
src/drivers/fb/scrollback.cpp
Normal file
58
src/drivers/fb/scrollback.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "font.h"
|
||||
#include "screen.h"
|
||||
#include "scrollback.h"
|
||||
|
||||
scrollback::scrollback(unsigned lines, unsigned cols, unsigned margin) :
|
||||
m_rows {lines},
|
||||
m_cols {cols},
|
||||
m_count {0},
|
||||
m_margin {margin}
|
||||
{
|
||||
m_data = reinterpret_cast<char*>(malloc(lines*cols));
|
||||
memset(m_data, ' ', lines*cols);
|
||||
}
|
||||
|
||||
void
|
||||
scrollback::add_line(const char *line, size_t len)
|
||||
{
|
||||
unsigned i = m_count++ % m_rows;
|
||||
|
||||
if (len > m_cols)
|
||||
len = m_cols;
|
||||
|
||||
char *start = m_data + (i * m_cols);
|
||||
memcpy(start, line, len);
|
||||
if (len < m_cols)
|
||||
memset(start + len, ' ', m_cols - len);
|
||||
}
|
||||
|
||||
char *
|
||||
scrollback::get_line(unsigned i)
|
||||
{
|
||||
unsigned line = (i + m_count) % m_rows;
|
||||
return &m_data[line*m_cols];
|
||||
}
|
||||
|
||||
void
|
||||
scrollback::render(screen &scr, font &fnt)
|
||||
{
|
||||
screen::pixel_t fg = scr.color(0xb0, 0xb0, 0xb0);
|
||||
screen::pixel_t bg = scr.color(49, 79, 128);
|
||||
|
||||
const unsigned xstride = (m_margin + fnt.width());
|
||||
const unsigned ystride = (m_margin + fnt.height());
|
||||
|
||||
unsigned start = m_count <= m_rows ? 0 :
|
||||
m_count % m_rows;
|
||||
|
||||
for (unsigned y = 0; y < m_rows; ++y) {
|
||||
unsigned i = (start + y) % m_rows;
|
||||
char *line = &m_data[i*m_cols];
|
||||
for (unsigned x = 0; x < m_cols; ++x) {
|
||||
fnt.draw_glyph(scr, line[x], fg, bg, m_margin+x*xstride, m_margin+y*ystride);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/drivers/fb/scrollback.h
Normal file
25
src/drivers/fb/scrollback.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
/// \file scrollback.h
|
||||
|
||||
class screen;
|
||||
class font;
|
||||
|
||||
class scrollback
|
||||
{
|
||||
public:
|
||||
scrollback(unsigned lines, unsigned cols, unsigned margin = 2);
|
||||
|
||||
void add_line(const char *line, size_t len);
|
||||
|
||||
char * get_line(unsigned i);
|
||||
|
||||
void render(screen &scr, font &fnt);
|
||||
|
||||
private:
|
||||
char *m_data;
|
||||
unsigned m_rows, m_cols;
|
||||
unsigned m_start;
|
||||
unsigned m_count;
|
||||
unsigned m_margin;
|
||||
};
|
||||
|
||||
22
src/drivers/nulldrv/io.cpp
Normal file
22
src/drivers/nulldrv/io.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "io.h"
|
||||
|
||||
uint8_t
|
||||
inb(uint16_t port)
|
||||
{
|
||||
uint8_t val;
|
||||
__asm__ __volatile__ ( "inb %1, %0" : "=a"(val) : "Nd"(port) );
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
outb(uint16_t port, uint8_t val)
|
||||
{
|
||||
__asm__ __volatile__ ( "outb %0, %1" :: "a"(val), "Nd"(port) );
|
||||
}
|
||||
|
||||
void
|
||||
io_wait(unsigned times)
|
||||
{
|
||||
for (unsigned i = 0; i < times; ++i)
|
||||
outb(0x80, 0);
|
||||
}
|
||||
24
src/drivers/nulldrv/io.h
Normal file
24
src/drivers/nulldrv/io.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
/// Read a byte from an IO port.
|
||||
/// \arg port The address of the IO port
|
||||
/// \returns One byte read from the port
|
||||
uint8_t inb(uint16_t port);
|
||||
|
||||
/// Write a byte to an IO port.
|
||||
/// \arg port The addres of the IO port
|
||||
/// \arg val The byte to write
|
||||
void outb(uint16_t port, uint8_t val);
|
||||
|
||||
/// Pause briefly by doing IO to port 0x80
|
||||
/// \arg times Number of times to delay by writing
|
||||
void io_wait(unsigned times = 1);
|
||||
|
||||
}
|
||||
|
||||
constexpr uint16_t COM1 = 0x03f8;
|
||||
constexpr uint16_t COM2 = 0x02f8;
|
||||
@@ -3,36 +3,141 @@
|
||||
|
||||
#include "j6/types.h"
|
||||
#include "j6/errors.h"
|
||||
#include "j6/signals.h"
|
||||
#include "j6/syscalls.h"
|
||||
|
||||
#include "io.h"
|
||||
#include "serial.h"
|
||||
|
||||
char inbuf[1024];
|
||||
extern j6_handle_t __handle_sys;
|
||||
j6_handle_t endp = j6_handle_invalid;
|
||||
|
||||
extern "C" {
|
||||
j6_status_t getpid(uint64_t *);
|
||||
j6_status_t fork(uint64_t *);
|
||||
j6_status_t sleep(uint64_t til);
|
||||
j6_status_t debug();
|
||||
j6_status_t message(const char *msg);
|
||||
|
||||
int main(int, const char **);
|
||||
}
|
||||
|
||||
void
|
||||
thread_proc()
|
||||
{
|
||||
j6_system_log("sub thread starting");
|
||||
|
||||
char buffer[512];
|
||||
size_t len = sizeof(buffer);
|
||||
j6_tag_t tag = 0;
|
||||
j6_status_t result = j6_endpoint_receive(endp, &tag, &len, (void*)buffer);
|
||||
if (result != j6_status_ok)
|
||||
j6_thread_exit(result);
|
||||
|
||||
j6_system_log("sub thread received message");
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
if (buffer[i] >= 'A' && buffer[i] <= 'Z')
|
||||
buffer[i] += 0x20;
|
||||
|
||||
tag++;
|
||||
result = j6_endpoint_send(endp, tag, len, (void*)buffer);
|
||||
if (result != j6_status_ok)
|
||||
j6_thread_exit(result);
|
||||
|
||||
j6_system_log("sub thread sent message");
|
||||
|
||||
for (int i = 1; i < 5; ++i)
|
||||
j6_thread_sleep(i*10);
|
||||
|
||||
j6_system_log("sub thread exiting");
|
||||
j6_thread_exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char **argv)
|
||||
{
|
||||
uint64_t pid = 0;
|
||||
uint64_t child = 0;
|
||||
j6_handle_t child = j6_handle_invalid;
|
||||
j6_signal_t out = 0;
|
||||
|
||||
j6_status_t result = fork(&child);
|
||||
j6_system_log("main thread starting");
|
||||
|
||||
for (int i = 0; i < argc; ++i)
|
||||
j6_system_log(argv[i]);
|
||||
|
||||
void *base = malloc(0x1000);
|
||||
if (!base)
|
||||
return 1;
|
||||
|
||||
uint64_t *vma_ptr = reinterpret_cast<uint64_t*>(base);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
vma_ptr[i*100] = uint64_t(i);
|
||||
|
||||
j6_system_log("main thread wrote to memory area");
|
||||
|
||||
j6_status_t result = j6_endpoint_create(&endp);
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
message("hello from nulldrv!");
|
||||
j6_system_log("main thread created endpoint");
|
||||
|
||||
result = getpid(&pid);
|
||||
result = j6_thread_create(reinterpret_cast<void*>(&thread_proc), &child);
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
for (int i = 1; i < 5; ++i)
|
||||
sleep(i*10);
|
||||
j6_system_log("main thread created sub thread");
|
||||
|
||||
return pid;
|
||||
char message[] = "MAIN THREAD SUCCESSFULLY CALLED SENDRECV IF THIS IS LOWERCASE";
|
||||
size_t size = sizeof(message);
|
||||
j6_tag_t tag = 16;
|
||||
result = j6_endpoint_sendrecv(endp, &tag, &size, (void*)message);
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
if (tag != 17)
|
||||
j6_system_log("GOT WRONG TAG FROM SENDRECV");
|
||||
|
||||
result = j6_system_bind_irq(__handle_sys, endp, 3);
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
j6_system_log(message);
|
||||
|
||||
j6_system_log("main thread waiting on child");
|
||||
result = j6_object_wait(child, -1ull, &out);
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
j6_system_log("main thread creating a new process");
|
||||
j6_handle_t child_proc = j6_handle_invalid;
|
||||
result = j6_process_create(&child_proc);
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
j6_system_log("main testing irqs");
|
||||
|
||||
|
||||
serial_port com2(COM2);
|
||||
|
||||
const char *fgseq = "\x1b[2J";
|
||||
while (*fgseq)
|
||||
com2.write(*fgseq++);
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
com2.write('%');
|
||||
|
||||
size_t len = 0;
|
||||
while (true) {
|
||||
result = j6_endpoint_receive(endp, &tag, &len, nullptr);
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
if (j6_tag_is_irq(tag))
|
||||
j6_system_log("main thread got irq!");
|
||||
}
|
||||
|
||||
j6_system_log("main thread closing endpoint");
|
||||
|
||||
result = j6_object_close(endp);
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
j6_system_log("main thread done, exiting");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
section .bss
|
||||
mymessage:
|
||||
resq 1024
|
||||
|
||||
extern main
|
||||
extern exit
|
||||
|
||||
section .text
|
||||
global getpid
|
||||
getpid:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
; address of out var should already be in rdi
|
||||
mov rax, 0x13 ; getpid syscall
|
||||
syscall ; result is now already in rax, so just return
|
||||
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
global debug
|
||||
debug:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
mov rax, 0x00 ; debug syscall
|
||||
syscall
|
||||
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
global sleep
|
||||
sleep:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
mov rax, 0x16 ; sleep syscall
|
||||
syscall
|
||||
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
global fork
|
||||
fork:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
; address of out var should already be in rdi
|
||||
mov rax, 0x12
|
||||
syscall ; result left in rax
|
||||
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
|
||||
global message
|
||||
message:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
; message should already be in rdi
|
||||
mov rax, 0x14
|
||||
syscall
|
||||
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
|
||||
global _start
|
||||
_start:
|
||||
xor rbp, rbp ; Sentinel rbp
|
||||
push rbp
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
mov rdi, 0
|
||||
mov rsi, 0
|
||||
call main
|
||||
|
||||
mov rdi, rax
|
||||
call exit
|
||||
41
src/drivers/nulldrv/serial.cpp
Normal file
41
src/drivers/nulldrv/serial.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "io.h"
|
||||
#include "serial.h"
|
||||
|
||||
|
||||
serial_port::serial_port() :
|
||||
m_port(0)
|
||||
{
|
||||
}
|
||||
|
||||
serial_port::serial_port(uint16_t port) :
|
||||
m_port(port)
|
||||
{
|
||||
outb(port + 1, 0x00); // Disable all interrupts
|
||||
outb(port + 3, 0x80); // Enable the Divisor Latch Access Bit
|
||||
outb(port + 0, 0x01); // Divisor low bit: 1 (115200 baud)
|
||||
outb(port + 1, 0x00); // Divisor high bit
|
||||
outb(port + 3, 0x03); // 8-N-1
|
||||
outb(port + 2, 0xe7); // Clear and enable FIFO, enable 64 byte, 56 byte trigger
|
||||
outb(port + 4, 0x0b); // Data terminal ready, Request to send, aux output 2 (irq enable)
|
||||
outb(port + 1, 0x03); // Enable interrupts
|
||||
}
|
||||
|
||||
bool serial_port::read_ready() { return (inb(m_port + 5) & 0x01) != 0; }
|
||||
|
||||
bool serial_port::write_ready() {
|
||||
uint8_t lsr = inb(m_port + 5);
|
||||
return (lsr & 0x20) != 0;
|
||||
}
|
||||
|
||||
char
|
||||
serial_port::read() {
|
||||
while (!read_ready());
|
||||
return inb(m_port);
|
||||
}
|
||||
|
||||
void
|
||||
serial_port::write(char c) {
|
||||
while (!write_ready());
|
||||
outb(m_port, c);
|
||||
}
|
||||
|
||||
26
src/drivers/nulldrv/serial.h
Normal file
26
src/drivers/nulldrv/serial.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
/// \file serial.h
|
||||
/// Declarations related to serial ports.
|
||||
#include <stdint.h>
|
||||
|
||||
#define serial_port nulldrv_serial_port
|
||||
|
||||
class serial_port
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
/// \arg port The IO address of the serial port
|
||||
serial_port(uint16_t port);
|
||||
|
||||
serial_port();
|
||||
|
||||
void write(char c);
|
||||
char read();
|
||||
|
||||
private:
|
||||
uint16_t m_port;
|
||||
|
||||
bool read_ready();
|
||||
bool write_ready();
|
||||
};
|
||||
|
||||
@@ -8,9 +8,13 @@
|
||||
|
||||
#define j6_status_ok 0x0000
|
||||
|
||||
#define j6_status_closed 0x1000
|
||||
#define j6_status_destroyed 0x1001
|
||||
#define j6_status_exists 0x1002
|
||||
|
||||
#define j6_err_nyi j6_err(0x0001)
|
||||
#define j6_err_unexpected j6_err(0x0002)
|
||||
#define j6_err_invalid_arg j6_err(0x0003)
|
||||
#define j6_err_not_ready j6_err(0x0004)
|
||||
#define j6_err_insufficient j6_err(0x0005)
|
||||
|
||||
|
||||
10
src/include/j6/flags.h
Normal file
10
src/include/j6/flags.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
/// \file flags.h
|
||||
/// Enums used as flags for syscalls
|
||||
|
||||
enum j6_vm_flags {
|
||||
#define VM_FLAG(name, v) j6_vm_flag_ ## name = v,
|
||||
#include "j6/tables/vm_flags.inc"
|
||||
#undef VM_FLAG
|
||||
j6_vm_flags_MAX
|
||||
};
|
||||
37
src/include/j6/init.h
Normal file
37
src/include/j6/init.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
/// \file init.h
|
||||
/// Types used in process and thread initialization
|
||||
|
||||
#include <stdint.h>
|
||||
#include "j6/types.h"
|
||||
|
||||
enum j6_init_type { // `value` is a:
|
||||
j6_init_handle_self, // Handle to the system
|
||||
j6_init_handle_other, // Handle to this process
|
||||
j6_init_desc_framebuffer // Pointer to a j6_init_framebuffer descriptor
|
||||
};
|
||||
|
||||
struct j6_typed_handle {
|
||||
enum j6_object_type type;
|
||||
j6_handle_t handle;
|
||||
};
|
||||
|
||||
struct j6_init_value {
|
||||
enum j6_init_type type;
|
||||
union {
|
||||
struct j6_typed_handle handle;
|
||||
void *data;
|
||||
};
|
||||
};
|
||||
|
||||
/// Structure defining a framebuffer.
|
||||
/// `flags` has the following bits:
|
||||
/// 0-3: Pixel layout. 0000: rgb8, 0001: bgr8
|
||||
struct j6_init_framebuffer {
|
||||
uintptr_t addr;
|
||||
size_t size;
|
||||
uint32_t vertical;
|
||||
uint32_t horizontal;
|
||||
uint32_t scanline;
|
||||
uint32_t flags;
|
||||
};
|
||||
@@ -2,17 +2,73 @@
|
||||
/// \file signals.h
|
||||
/// Collection of constants for the j6_signal_t type
|
||||
|
||||
// Signals 0-7 are common to all types
|
||||
#define j6_signal_no_handles (1 << 0)
|
||||
// Signals 0-15 are common to all types
|
||||
#define j6_signal_no_handles (1ull << 0)
|
||||
#define j6_signal_closed (1ull << 1)
|
||||
|
||||
// Signals 8-15 are user-defined signals
|
||||
#define j6_signal_user0 (1 << 8)
|
||||
#define j6_signal_user1 (1 << 9)
|
||||
#define j6_signal_user2 (1 << 10)
|
||||
#define j6_signal_user3 (1 << 11)
|
||||
#define j6_signal_user4 (1 << 12)
|
||||
#define j6_signal_user5 (1 << 13)
|
||||
#define j6_signal_user6 (1 << 14)
|
||||
#define j6_signal_user7 (1 << 15)
|
||||
// Signals 16-47 are defined per-object-type
|
||||
|
||||
// All other signals are type-specific
|
||||
// Event signals
|
||||
#define j7_signal_event00 (1ull << 16)
|
||||
#define j7_signal_event01 (1ull << 17)
|
||||
#define j7_signal_event02 (1ull << 18)
|
||||
#define j7_signal_event03 (1ull << 19)
|
||||
#define j7_signal_event04 (1ull << 20)
|
||||
#define j7_signal_event05 (1ull << 21)
|
||||
#define j7_signal_event06 (1ull << 22)
|
||||
#define j7_signal_event07 (1ull << 23)
|
||||
#define j7_signal_event08 (1ull << 24)
|
||||
#define j7_signal_event09 (1ull << 25)
|
||||
#define j7_signal_event10 (1ull << 26)
|
||||
#define j7_signal_event11 (1ull << 27)
|
||||
#define j7_signal_event12 (1ull << 28)
|
||||
#define j7_signal_event13 (1ull << 29)
|
||||
#define j7_signal_event14 (1ull << 30)
|
||||
#define j7_signal_event15 (1ull << 31)
|
||||
#define j7_signal_event16 (1ull << 32)
|
||||
#define j7_signal_event17 (1ull << 33)
|
||||
#define j7_signal_event18 (1ull << 34)
|
||||
#define j7_signal_event19 (1ull << 35)
|
||||
#define j7_signal_event20 (1ull << 36)
|
||||
#define j7_signal_event21 (1ull << 37)
|
||||
#define j7_signal_event22 (1ull << 38)
|
||||
#define j7_signal_event23 (1ull << 39)
|
||||
#define j7_signal_event24 (1ull << 40)
|
||||
#define j7_signal_event25 (1ull << 41)
|
||||
#define j7_signal_event26 (1ull << 42)
|
||||
#define j7_signal_event27 (1ull << 43)
|
||||
#define j7_signal_event28 (1ull << 44)
|
||||
#define j7_signal_event29 (1ull << 45)
|
||||
#define j7_signal_event30 (1ull << 46)
|
||||
#define j7_signal_event31 (1ull << 47)
|
||||
|
||||
// System signals
|
||||
#define j6_signal_system_has_log (1ull << 16)
|
||||
|
||||
// Channel signals
|
||||
#define j6_signal_channel_can_send (1ull << 16)
|
||||
#define j6_signal_channel_can_recv (1ull << 17)
|
||||
|
||||
// Endpoint signals
|
||||
#define j6_signal_endpoint_can_send (1ull << 16)
|
||||
#define j6_signal_endpoint_can_recv (1ull << 17)
|
||||
|
||||
// Signals 48-63 are user-defined signals
|
||||
#define j6_signal_user0 (1ull << 48)
|
||||
#define j6_signal_user1 (1ull << 49)
|
||||
#define j6_signal_user2 (1ull << 50)
|
||||
#define j6_signal_user3 (1ull << 51)
|
||||
#define j6_signal_user4 (1ull << 52)
|
||||
#define j6_signal_user5 (1ull << 53)
|
||||
#define j6_signal_user6 (1ull << 54)
|
||||
#define j6_signal_user7 (1ull << 55)
|
||||
#define j6_signal_user8 (1ull << 56)
|
||||
#define j6_signal_user9 (1ull << 57)
|
||||
#define j6_signal_user10 (1ull << 58)
|
||||
#define j6_signal_user11 (1ull << 59)
|
||||
#define j6_signal_user12 (1ull << 60)
|
||||
#define j6_signal_user13 (1ull << 61)
|
||||
#define j6_signal_user14 (1ull << 62)
|
||||
#define j6_signal_user15 (1ull << 63)
|
||||
|
||||
#define j6_signal_user_mask (0xffffull << 48)
|
||||
|
||||
15
src/include/j6/tables/log_areas.inc
Normal file
15
src/include/j6/tables/log_areas.inc
Normal file
@@ -0,0 +1,15 @@
|
||||
LOG(apic, info);
|
||||
LOG(device, debug);
|
||||
LOG(paging, info);
|
||||
LOG(driver, info);
|
||||
LOG(memory, debug);
|
||||
LOG(fs, info);
|
||||
LOG(task, info);
|
||||
LOG(sched, info);
|
||||
LOG(loader, debug);
|
||||
LOG(boot, debug);
|
||||
LOG(syscall,info);
|
||||
LOG(vmem, debug);
|
||||
LOG(objs, debug);
|
||||
LOG(timer, debug);
|
||||
LOG(clock, debug);
|
||||
12
src/include/j6/tables/object_types.inc
Normal file
12
src/include/j6/tables/object_types.inc
Normal file
@@ -0,0 +1,12 @@
|
||||
OBJECT_TYPE( none, 0x00 )
|
||||
|
||||
OBJECT_TYPE( system, 0x01 )
|
||||
|
||||
OBJECT_TYPE( event, 0x02 )
|
||||
OBJECT_TYPE( channel, 0x03 )
|
||||
OBJECT_TYPE( endpoint, 0x04 )
|
||||
|
||||
OBJECT_TYPE( vma, 0x05 )
|
||||
|
||||
OBJECT_TYPE( process, 0x06 )
|
||||
OBJECT_TYPE( thread, 0x07 )
|
||||
35
src/include/j6/tables/syscalls.inc
Normal file
35
src/include/j6/tables/syscalls.inc
Normal file
@@ -0,0 +1,35 @@
|
||||
SYSCALL(0x00, system_log, const char *)
|
||||
SYSCALL(0x01, system_noop, void)
|
||||
SYSCALL(0x02, system_get_log, j6_handle_t, void *, size_t *)
|
||||
SYSCALL(0x03, system_bind_irq, j6_handle_t, j6_handle_t, unsigned)
|
||||
SYSCALL(0x04, system_map_mmio, j6_handle_t, j6_handle_t *, uintptr_t, size_t, uint32_t)
|
||||
|
||||
SYSCALL(0x08, object_koid, j6_handle_t, j6_koid_t *)
|
||||
SYSCALL(0x09, object_wait, j6_handle_t, j6_signal_t, j6_signal_t *)
|
||||
SYSCALL(0x0a, object_signal, j6_handle_t, j6_signal_t)
|
||||
SYSCALL(0x0b, object_close, j6_handle_t)
|
||||
|
||||
SYSCALL(0x10, process_create, j6_handle_t *)
|
||||
SYSCALL(0x11, process_start, j6_handle_t, uintptr_t, j6_handle_t *, size_t)
|
||||
SYSCALL(0x11, process_kill, j6_handle_t)
|
||||
SYSCALL(0x17, process_exit, int32_t)
|
||||
|
||||
SYSCALL(0x18, thread_create, void *, j6_handle_t *)
|
||||
SYSCALL(0x19, thread_exit, int32_t)
|
||||
SYSCALL(0x1a, thread_pause, void)
|
||||
SYSCALL(0x1b, thread_sleep, uint64_t)
|
||||
|
||||
SYSCALL(0x20, channel_create, j6_handle_t *)
|
||||
SYSCALL(0x21, channel_send, j6_handle_t, size_t *, void *)
|
||||
SYSCALL(0x22, channel_receive, j6_handle_t, size_t *, void *)
|
||||
|
||||
SYSCALL(0x28, endpoint_create, j6_handle_t *)
|
||||
SYSCALL(0x29, endpoint_send, j6_handle_t, j6_tag_t, size_t, void *)
|
||||
SYSCALL(0x2a, endpoint_receive, j6_handle_t, j6_tag_t *, size_t *, void *)
|
||||
SYSCALL(0x2b, endpoint_sendrecv, j6_handle_t, j6_tag_t *, size_t *, void *)
|
||||
|
||||
SYSCALL(0x30, vma_create, j6_handle_t *, size_t, uint32_t)
|
||||
SYSCALL(0x31, vma_create_map, j6_handle_t *, size_t, uintptr_t, uint32_t)
|
||||
SYSCALL(0x32, vma_map, j6_handle_t, j6_handle_t, uintptr_t)
|
||||
SYSCALL(0x33, vma_unmap, j6_handle_t, j6_handle_t)
|
||||
SYSCALL(0x34, vma_resize, j6_handle_t, size_t *)
|
||||
9
src/include/j6/tables/vm_flags.inc
Normal file
9
src/include/j6/tables/vm_flags.inc
Normal file
@@ -0,0 +1,9 @@
|
||||
VM_FLAG( none, 0x00000000)
|
||||
VM_FLAG( write, 0x00000001)
|
||||
VM_FLAG( exec, 0x00000002)
|
||||
VM_FLAG( zero, 0x00000010)
|
||||
VM_FLAG( contiguous, 0x00000020)
|
||||
VM_FLAG( large_pages, 0x00000100)
|
||||
VM_FLAG( huge_pages, 0x00000200)
|
||||
VM_FLAG( write_combine, 0x00001000)
|
||||
VM_FLAG( mmio, 0x00010000)
|
||||
@@ -10,11 +10,36 @@ typedef uint64_t j6_koid_t;
|
||||
/// Syscalls return status as this type
|
||||
typedef uint64_t j6_status_t;
|
||||
|
||||
/// Handles are references and capabilities to other objects
|
||||
typedef uint32_t j6_handle_t;
|
||||
|
||||
/// Some objects have signals, which are a bitmap of 64 possible signals
|
||||
typedef uint64_t j6_signal_t;
|
||||
|
||||
/// The rights of a handle/capability are a bitmap of 64 possible rights
|
||||
typedef uint64_t j6_rights_t;
|
||||
/// The first word of IPC messages are the tag. Tags with the high bit
|
||||
/// set are reserved for the system.
|
||||
typedef uint64_t j6_tag_t;
|
||||
|
||||
#define j6_tag_system_flag 0x8000000000000000
|
||||
#define j6_tag_invalid 0x0000000000000000
|
||||
|
||||
/// If all high bits except the last 16 are set, then the tag represents
|
||||
/// an IRQ.
|
||||
#define j6_tag_irq_base 0xffffffffffff0000
|
||||
#define j6_tag_is_irq(x) (((x) & j6_tag_irq_base) == j6_tag_irq_base)
|
||||
#define j6_tag_from_irq(x) ((x) | j6_tag_irq_base)
|
||||
#define j6_tag_to_irq(x) ((x) & ~j6_tag_irq_base)
|
||||
|
||||
/// Handles are references and capabilities to other objects. The least
|
||||
/// significant 32 bits are an identifier, and the most significant 32
|
||||
/// bits are a bitmask of capabilities this handle has on that object.
|
||||
typedef uint64_t j6_handle_t;
|
||||
|
||||
#define j6_handle_rights_shift 4
|
||||
#define j6_handle_id_mask 0xffffffffull
|
||||
#define j6_handle_invalid 0xffffffffull
|
||||
|
||||
enum j6_object_type {
|
||||
#define OBJECT_TYPE( name, val ) j6_object_type_ ## name = val,
|
||||
#include "j6/tables/object_types.inc"
|
||||
#undef OBJECT_TYPE
|
||||
|
||||
j6_object_type_max
|
||||
};
|
||||
|
||||
@@ -10,44 +10,56 @@ namespace args {
|
||||
constexpr uint32_t magic = 0x600dda7a;
|
||||
constexpr uint16_t version = 1;
|
||||
|
||||
enum class mod_flags : uint32_t
|
||||
{
|
||||
debug = 0x00000001
|
||||
};
|
||||
|
||||
enum class mod_type : uint32_t {
|
||||
unknown,
|
||||
|
||||
kernel,
|
||||
initrd,
|
||||
|
||||
memory_map,
|
||||
page_tables,
|
||||
framebuffer,
|
||||
|
||||
max
|
||||
};
|
||||
|
||||
enum class mode : uint8_t {
|
||||
normal,
|
||||
debug
|
||||
symbol_table
|
||||
};
|
||||
|
||||
struct module {
|
||||
void *location;
|
||||
size_t size;
|
||||
mod_type type;
|
||||
mod_flags flags;
|
||||
}
|
||||
__attribute__((packed));
|
||||
};
|
||||
|
||||
enum class fb_type : uint16_t {
|
||||
none,
|
||||
rgb8,
|
||||
bgr8
|
||||
};
|
||||
|
||||
struct framebuffer {
|
||||
uintptr_t phys_addr;
|
||||
size_t size;
|
||||
uint32_t vertical;
|
||||
uint32_t horizontal;
|
||||
uint16_t scanline;
|
||||
fb_type type;
|
||||
};
|
||||
|
||||
enum class section_flags : uint32_t {
|
||||
none = 0,
|
||||
execute = 1,
|
||||
write = 2,
|
||||
read = 4,
|
||||
};
|
||||
|
||||
struct program_section {
|
||||
uintptr_t phys_addr;
|
||||
uintptr_t virt_addr;
|
||||
uint32_t size;
|
||||
section_flags type;
|
||||
};
|
||||
|
||||
struct program {
|
||||
uintptr_t entrypoint;
|
||||
uintptr_t base;
|
||||
size_t total_size;
|
||||
size_t num_sections;
|
||||
program_section sections[3];
|
||||
};
|
||||
|
||||
enum class mem_type : uint32_t {
|
||||
free,
|
||||
args,
|
||||
kernel,
|
||||
module,
|
||||
table,
|
||||
pending,
|
||||
acpi,
|
||||
uefi_runtime,
|
||||
mmio,
|
||||
@@ -61,33 +73,54 @@ struct mem_entry
|
||||
size_t pages;
|
||||
mem_type type;
|
||||
uint32_t attr;
|
||||
}
|
||||
__attribute__((packed));
|
||||
};
|
||||
|
||||
constexpr size_t frames_per_block = 64 * 64 * 64;
|
||||
|
||||
struct frame_block
|
||||
{
|
||||
uintptr_t base;
|
||||
uint32_t count;
|
||||
uint32_t attrs;
|
||||
uint64_t map1;
|
||||
uint64_t map2[64];
|
||||
uint64_t *bitmap;
|
||||
};
|
||||
|
||||
enum class boot_flags : uint16_t {
|
||||
none = 0x0000,
|
||||
debug = 0x0001
|
||||
};
|
||||
|
||||
struct header {
|
||||
uint32_t magic;
|
||||
uint16_t version;
|
||||
|
||||
mode mode;
|
||||
|
||||
uint8_t _reserved0;
|
||||
boot_flags flags;
|
||||
|
||||
void *pml4;
|
||||
void *page_table_cache;
|
||||
uint32_t num_free_tables;
|
||||
void *page_tables;
|
||||
size_t table_count;
|
||||
size_t table_pages;
|
||||
|
||||
program *programs;
|
||||
size_t num_programs;
|
||||
|
||||
uint32_t num_modules;
|
||||
module *modules;
|
||||
size_t num_modules;
|
||||
|
||||
mem_entry *mem_map;
|
||||
size_t num_map_entries;
|
||||
size_t map_count;
|
||||
|
||||
frame_block *frame_blocks;
|
||||
size_t frame_block_count;
|
||||
size_t frame_block_pages;
|
||||
|
||||
void *runtime_services;
|
||||
void *acpi_table;
|
||||
|
||||
framebuffer video;
|
||||
}
|
||||
__attribute__((aligned(alignof(max_align_t))));
|
||||
#pragma pack(pop)
|
||||
|
||||
} // namespace args
|
||||
|
||||
|
||||
@@ -11,23 +11,41 @@ namespace memory {
|
||||
constexpr size_t frame_size = 0x1000;
|
||||
|
||||
/// Start of kernel memory.
|
||||
constexpr uintptr_t kernel_offset = 0xffff800000000000;
|
||||
constexpr uintptr_t kernel_offset = 0xffff800000000000ull;
|
||||
|
||||
/// Offset from physical where page tables are mapped.
|
||||
constexpr uintptr_t page_offset = 0xffffc00000000000;
|
||||
constexpr uintptr_t page_offset = 0xffffc00000000000ull;
|
||||
|
||||
/// Initial process thread's stack address
|
||||
constexpr uintptr_t initial_stack = 0x0000800000000000;
|
||||
/// Max number of pages for a kernel stack
|
||||
constexpr unsigned kernel_stack_pages = 2;
|
||||
|
||||
/// Initial process thread's stack size, in pages
|
||||
constexpr unsigned initial_stack_pages = 1;
|
||||
/// Max number of pages for a kernel buffer
|
||||
constexpr unsigned kernel_buffer_pages = 16;
|
||||
|
||||
/// Max size of the kernel heap
|
||||
constexpr size_t kernel_max_heap = 0x8000000000; // 512GiB
|
||||
constexpr size_t kernel_max_heap = 0x8000000000ull; // 512GiB
|
||||
|
||||
/// Start of the kernel heap
|
||||
constexpr uintptr_t heap_start = page_offset - kernel_max_heap;
|
||||
|
||||
/// Max size of the kernel stacks area
|
||||
constexpr size_t kernel_max_stacks = 0x8000000000ull; // 512GiB
|
||||
|
||||
/// Start of the kernel stacks
|
||||
constexpr uintptr_t stacks_start = heap_start - kernel_max_stacks;
|
||||
|
||||
/// Max size of kernel buffers area
|
||||
constexpr size_t kernel_max_buffers = 0x8000000000ull; // 512GiB
|
||||
|
||||
/// Start of kernel buffers
|
||||
constexpr uintptr_t buffers_start = stacks_start - kernel_max_buffers;
|
||||
|
||||
/// Max size of kernel bitmap area
|
||||
constexpr size_t kernel_max_bitmap = 0x8000000000ull; // 512GiB
|
||||
|
||||
/// Start of kernel bitmap
|
||||
constexpr uintptr_t bitmap_start = buffers_start - kernel_max_bitmap;
|
||||
|
||||
/// First kernel space PML4 entry
|
||||
constexpr unsigned pml4e_kernel = 256;
|
||||
|
||||
@@ -41,4 +59,27 @@ namespace memory {
|
||||
/// through the page_offset area.
|
||||
inline bool page_mappable(uintptr_t a) { return (a & page_offset) == 0; }
|
||||
|
||||
/// Convert a physical address to a virtual one (in the offset-mapped area)
|
||||
template <typename T> T * to_virtual(uintptr_t a) {
|
||||
return reinterpret_cast<T*>(a|page_offset);
|
||||
}
|
||||
|
||||
/// Convert a physical address to a virtual one (in the offset-mapped area)
|
||||
template <typename T> T * to_virtual(T *p) {
|
||||
return to_virtual<T>(reinterpret_cast<uintptr_t>(p));
|
||||
}
|
||||
|
||||
/// Get the number of pages needed for a given number of bytes.
|
||||
/// \arg bytes The number of bytes desired
|
||||
/// \returns The number of pages needed to contain the desired bytes
|
||||
inline size_t page_count(size_t bytes) {
|
||||
return ((bytes - 1) >> 12) + 1;
|
||||
}
|
||||
|
||||
/// Get the given address, aligned to the next lowest page
|
||||
inline uintptr_t page_align_down(uintptr_t a) { return a & ~(frame_size-1); }
|
||||
|
||||
/// Get the given address, aligned to the next page
|
||||
inline uintptr_t page_align_up(uintptr_t a) { return page_align_down(a-1) + frame_size; }
|
||||
|
||||
} // namespace memory
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
LOG(apic, info);
|
||||
LOG(device, info);
|
||||
LOG(paging, warn);
|
||||
LOG(driver, info);
|
||||
LOG(memory, info);
|
||||
LOG(fs, info);
|
||||
LOG(task, info);
|
||||
LOG(boot, debug);
|
||||
LOG(syscall,debug);
|
||||
LOG(vmem, debug);
|
||||
LOG(objs, debug);
|
||||
@@ -23,7 +23,7 @@ struct acpi_table_header
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define TABLE_HEADER(signature) \
|
||||
static const uint32_t type_id = kutil::byteswap(signature); \
|
||||
static constexpr uint32_t type_id = kutil::byteswap(signature); \
|
||||
acpi_table_header header;
|
||||
|
||||
|
||||
@@ -188,3 +188,24 @@ struct acpi_mcfg
|
||||
acpi_mcfg_entry entries[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct acpi_hpet
|
||||
{
|
||||
TABLE_HEADER('HPET');
|
||||
uint32_t hardware_id;
|
||||
acpi_gas base_address;
|
||||
uint8_t index;
|
||||
uint16_t periodic_min;
|
||||
uint8_t attributes;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct acpi_bgrt
|
||||
{
|
||||
TABLE_HEADER('BGRT');
|
||||
uint16_t version;
|
||||
uint8_t status;
|
||||
uint8_t type;
|
||||
uintptr_t address;
|
||||
uint32_t offset_x;
|
||||
uint32_t offset_y;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
149
src/kernel/ap_startup.s
Normal file
149
src/kernel/ap_startup.s
Normal file
@@ -0,0 +1,149 @@
|
||||
%include "tasking.inc"
|
||||
|
||||
section .ap_startup
|
||||
|
||||
BASE equ 0x8000 ; Where the kernel will map this at runtime
|
||||
|
||||
CR0_PE equ (1 << 0)
|
||||
CR0_MP equ (1 << 1)
|
||||
CR0_ET equ (1 << 4)
|
||||
CR0_NE equ (1 << 5)
|
||||
CR0_WP equ (1 << 16)
|
||||
CR0_PG equ (1 << 31)
|
||||
CR0_VAL equ CR0_PE|CR0_MP|CR0_ET|CR0_NE|CR0_WP|CR0_PG
|
||||
|
||||
CR4_DE equ (1 << 3)
|
||||
CR4_PAE equ (1 << 5)
|
||||
CR4_MCE equ (1 << 6)
|
||||
CR4_PGE equ (1 << 7)
|
||||
CR4_OSFXSR equ (1 << 9)
|
||||
CR4_OSCMMEXCPT equ (1 << 10)
|
||||
CR4_FSGSBASE equ (1 << 16)
|
||||
CR4_PCIDE equ (1 << 17)
|
||||
CR4_INIT equ CR4_PAE|CR4_PGE
|
||||
CR4_VAL equ CR4_DE|CR4_PAE|CR4_MCE|CR4_PGE|CR4_OSFXSR|CR4_OSCMMEXCPT|CR4_FSGSBASE|CR4_PCIDE
|
||||
|
||||
EFER_MSR equ 0xC0000080
|
||||
EFER_SCE equ (1 << 0)
|
||||
EFER_LME equ (1 << 8)
|
||||
EFER_NXE equ (1 << 11)
|
||||
EFER_VAL equ EFER_SCE|EFER_LME|EFER_NXE
|
||||
|
||||
bits 16
|
||||
default rel
|
||||
align 8
|
||||
|
||||
global ap_startup
|
||||
ap_startup:
|
||||
jmp .start_real
|
||||
|
||||
align 8
|
||||
.pml4: dq 0
|
||||
.cpu: dq 0
|
||||
.ret: dq 0
|
||||
|
||||
align 16
|
||||
.gdt:
|
||||
dq 0x0 ; Null GDT entry
|
||||
|
||||
dq 0x00209A0000000000 ; Code
|
||||
dq 0x0000920000000000 ; Data
|
||||
|
||||
align 4
|
||||
.gdtd:
|
||||
dw ($ - .gdt)
|
||||
dd BASE + (.gdt - ap_startup)
|
||||
|
||||
align 4
|
||||
.idtd:
|
||||
dw 0 ; zero-length IDT descriptor
|
||||
dd 0
|
||||
|
||||
.start_real:
|
||||
cli
|
||||
cld
|
||||
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
|
||||
; set the temporary null IDT
|
||||
lidt [BASE + (.idtd - ap_startup)]
|
||||
|
||||
; Enter long mode
|
||||
mov eax, cr4
|
||||
or eax, CR4_INIT
|
||||
mov cr4, eax
|
||||
|
||||
mov eax, [BASE + (.pml4 - ap_startup)]
|
||||
mov cr3, eax
|
||||
|
||||
mov ecx, EFER_MSR
|
||||
rdmsr
|
||||
or eax, EFER_VAL
|
||||
wrmsr
|
||||
|
||||
mov eax, CR0_VAL
|
||||
mov cr0, eax
|
||||
|
||||
; Set the temporary minimal GDT
|
||||
lgdt [BASE + (.gdtd - ap_startup)]
|
||||
|
||||
jmp (1 << 3):(BASE + (.start_long - ap_startup))
|
||||
|
||||
bits 64
|
||||
default abs
|
||||
align 8
|
||||
.start_long:
|
||||
; set data segments
|
||||
mov ax, (2 << 3)
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
|
||||
mov eax, CR4_VAL
|
||||
|
||||
mov rdi, [BASE + (.cpu - ap_startup)]
|
||||
mov rax, [rdi + CPU_DATA.rsp0]
|
||||
mov rsp, rax
|
||||
|
||||
mov rax, [BASE + (.ret - ap_startup)]
|
||||
jmp rax
|
||||
|
||||
|
||||
global ap_startup_code_size
|
||||
ap_startup_code_size:
|
||||
dq ($ - ap_startup)
|
||||
|
||||
|
||||
section .text
|
||||
global init_ap_trampoline
|
||||
init_ap_trampoline:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
; rdi is the kernel pml4
|
||||
mov [BASE + (ap_startup.pml4 - ap_startup)], rdi
|
||||
|
||||
; rsi is the cpu data for this AP
|
||||
mov [BASE + (ap_startup.cpu - ap_startup)], rsi
|
||||
|
||||
; rdx is the address to jump to
|
||||
mov [BASE + (ap_startup.ret - ap_startup)], rdx
|
||||
|
||||
; rcx is the processor id
|
||||
mov rdi, rdx
|
||||
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
extern long_ap_startup
|
||||
global ap_idle
|
||||
ap_idle:
|
||||
call long_ap_startup
|
||||
sti
|
||||
.hang:
|
||||
hlt
|
||||
jmp .hang
|
||||
|
||||
@@ -1,10 +1,27 @@
|
||||
#include "kutil/assert.h"
|
||||
#include "apic.h"
|
||||
#include "clock.h"
|
||||
#include "interrupts.h"
|
||||
#include "io.h"
|
||||
#include "kernel_memory.h"
|
||||
#include "log.h"
|
||||
#include "page_manager.h"
|
||||
|
||||
uint64_t lapic::s_ticks_per_us = 0;
|
||||
|
||||
static constexpr uint16_t lapic_id = 0x0020;
|
||||
static constexpr uint16_t lapic_spurious = 0x00f0;
|
||||
|
||||
static constexpr uint16_t lapic_icr_low = 0x0300;
|
||||
static constexpr uint16_t lapic_icr_high = 0x0310;
|
||||
|
||||
static constexpr uint16_t lapic_lvt_timer = 0x0320;
|
||||
static constexpr uint16_t lapic_lvt_lint0 = 0x0350;
|
||||
static constexpr uint16_t lapic_lvt_lint1 = 0x0360;
|
||||
static constexpr uint16_t lapic_lvt_error = 0x0370;
|
||||
|
||||
static constexpr uint16_t lapic_timer_init = 0x0380;
|
||||
static constexpr uint16_t lapic_timer_cur = 0x0390;
|
||||
static constexpr uint16_t lapic_timer_div = 0x03e0;
|
||||
|
||||
static uint32_t
|
||||
apic_read(uint32_t volatile *apic, uint16_t offset)
|
||||
@@ -15,6 +32,7 @@ apic_read(uint32_t volatile *apic, uint16_t offset)
|
||||
static void
|
||||
apic_write(uint32_t volatile *apic, uint16_t offset, uint32_t value)
|
||||
{
|
||||
log::debug(logs::apic, "LAPIC write: %x = %08lx", offset, value);
|
||||
*(apic + offset/sizeof(uint32_t)) = value;
|
||||
}
|
||||
|
||||
@@ -32,24 +50,64 @@ ioapic_write(uint32_t volatile *base, uint8_t reg, uint32_t value)
|
||||
*(base + 4) = value;
|
||||
}
|
||||
|
||||
apic::apic(uint32_t *base) :
|
||||
m_base(base)
|
||||
apic::apic(uintptr_t base) :
|
||||
m_base(memory::to_virtual<uint32_t>(base))
|
||||
{
|
||||
// Map 1MiB of space for the APIC registers and
|
||||
// MSI area
|
||||
page_manager::get()->map_offset_pointer(
|
||||
reinterpret_cast<void **>(&m_base),
|
||||
0x100000);
|
||||
}
|
||||
|
||||
|
||||
lapic::lapic(uint32_t *base, isr spurious) :
|
||||
apic(base)
|
||||
lapic::lapic(uintptr_t base) :
|
||||
apic(base),
|
||||
m_divisor(0)
|
||||
{
|
||||
apic_write(m_base, 0xf0, static_cast<uint32_t>(spurious));
|
||||
apic_write(m_base, lapic_lvt_error, static_cast<uint32_t>(isr::isrAPICError));
|
||||
apic_write(m_base, lapic_spurious, static_cast<uint32_t>(isr::isrSpurious));
|
||||
log::info(logs::apic, "LAPIC created, base %lx", m_base);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
lapic::get_id()
|
||||
{
|
||||
return static_cast<uint8_t>(apic_read(m_base, lapic_id) >> 24);
|
||||
}
|
||||
|
||||
void
|
||||
lapic::send_ipi(ipi mode, uint8_t vector, uint8_t dest)
|
||||
{
|
||||
// Wait until the APIC is ready to send
|
||||
ipi_wait();
|
||||
|
||||
uint32_t command =
|
||||
static_cast<uint32_t>(vector) |
|
||||
static_cast<uint32_t>(mode);
|
||||
|
||||
apic_write(m_base, lapic_icr_high, static_cast<uint32_t>(dest) << 24);
|
||||
apic_write(m_base, lapic_icr_low, command);
|
||||
}
|
||||
|
||||
void
|
||||
lapic::send_ipi_broadcast(ipi mode, bool self, uint8_t vector)
|
||||
{
|
||||
// Wait until the APIC is ready to send
|
||||
ipi_wait();
|
||||
|
||||
uint32_t command =
|
||||
static_cast<uint32_t>(vector) |
|
||||
static_cast<uint32_t>(mode) |
|
||||
(self ? 0 : (1 << 18)) |
|
||||
(1 << 19);
|
||||
|
||||
apic_write(m_base, lapic_icr_high, 0);
|
||||
apic_write(m_base, lapic_icr_low, command);
|
||||
}
|
||||
|
||||
void
|
||||
lapic::ipi_wait()
|
||||
{
|
||||
while (apic_read(m_base, lapic_icr_low) & (1<<12))
|
||||
asm volatile ("pause" : : : "memory");
|
||||
}
|
||||
|
||||
void
|
||||
lapic::calibrate_timer()
|
||||
{
|
||||
@@ -57,40 +115,25 @@ lapic::calibrate_timer()
|
||||
|
||||
log::info(logs::apic, "Calibrating APIC timer...");
|
||||
|
||||
// Set up PIT sleep
|
||||
uint8_t command = 0x30; // channel 0, loybyte/highbyte, mode 0
|
||||
outb(0x43, command);
|
||||
|
||||
const uint32_t initial = -1u;
|
||||
enable_timer_internal(isr::isrSpurious, 1, initial, false);
|
||||
enable_timer(isr::isrSpurious);
|
||||
set_divisor(1);
|
||||
apic_write(m_base, lapic_timer_init, initial);
|
||||
|
||||
const int iterations = 5;
|
||||
for (int i=0; i<iterations; ++i) {
|
||||
const uint16_t pit_33ms = 39375;
|
||||
uint16_t pit_count = pit_33ms;
|
||||
outb(0x40, pit_count & 0xff);
|
||||
io_wait();
|
||||
outb(0x40, (pit_count >> 8) & 0xff);
|
||||
uint64_t us = 20000;
|
||||
clock::get().spinwait(us);
|
||||
|
||||
uint32_t remaining = apic_read(m_base, lapic_timer_cur);
|
||||
uint64_t ticks_total = initial - remaining;
|
||||
s_ticks_per_us = ticks_total / us;
|
||||
|
||||
while (pit_count <= pit_33ms) {
|
||||
outb(0x43, 0); // latch counter values
|
||||
pit_count =
|
||||
static_cast<uint16_t>(inb(0x40)) |
|
||||
static_cast<uint16_t>(inb(0x40)) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t remain = stop_timer();
|
||||
uint32_t ticks_total = initial - remain;
|
||||
m_ticks_per_us = ticks_total / (iterations * 33000);
|
||||
log::info(logs::apic, "APIC timer ticks %d times per nanosecond.", m_ticks_per_us);
|
||||
log::info(logs::apic, "APIC timer ticks %d times per microsecond.", s_ticks_per_us);
|
||||
|
||||
interrupts_enable();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
lapic::enable_timer_internal(isr vector, uint8_t divisor, uint32_t count, bool repeat)
|
||||
void
|
||||
lapic::set_divisor(uint8_t divisor)
|
||||
{
|
||||
uint32_t divbits = 0;
|
||||
|
||||
@@ -104,42 +147,40 @@ lapic::enable_timer_internal(isr vector, uint8_t divisor, uint32_t count, bool r
|
||||
case 64: divbits = 0x9; break;
|
||||
case 128: divbits = 0xa; break;
|
||||
default:
|
||||
kassert(0, "Invalid divisor passed to lapic::enable_timer");
|
||||
kassert(0, "Invalid divisor passed to lapic::set_divisor");
|
||||
}
|
||||
|
||||
apic_write(m_base, lapic_timer_div, divbits);
|
||||
m_divisor = divisor;
|
||||
}
|
||||
|
||||
void
|
||||
lapic::enable_timer(isr vector, bool repeat)
|
||||
{
|
||||
uint32_t lvte = static_cast<uint8_t>(vector);
|
||||
if (repeat)
|
||||
lvte |= 0x20000;
|
||||
apic_write(m_base, lapic_lvt_timer, lvte);
|
||||
|
||||
log::debug(logs::apic, "Enabling APIC timer count %ld, divisor %d, isr %02x",
|
||||
count, divisor, vector);
|
||||
|
||||
apic_write(m_base, 0x320, lvte);
|
||||
apic_write(m_base, 0x3e0, divbits);
|
||||
|
||||
reset_timer(count);
|
||||
return count;
|
||||
log::debug(logs::apic, "Enabling APIC timer at isr %02x", vector);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
lapic::enable_timer(isr vector, uint64_t interval, bool repeat)
|
||||
lapic::reset_timer(uint64_t interval)
|
||||
{
|
||||
uint64_t ticks = interval * m_ticks_per_us;
|
||||
uint64_t remaining = ticks_to_us(apic_read(m_base, lapic_timer_cur));
|
||||
uint64_t ticks = us_to_ticks(interval);
|
||||
|
||||
int divisor = 1;
|
||||
while (ticks > -1u) {
|
||||
ticks /= 2;
|
||||
divisor *= 2;
|
||||
while (ticks > 0xffffffffull) {
|
||||
ticks >>= 1;
|
||||
divisor <<= 1;
|
||||
}
|
||||
|
||||
return enable_timer_internal(vector, divisor, static_cast<uint32_t>(ticks), repeat);
|
||||
}
|
||||
if (divisor != m_divisor)
|
||||
set_divisor(divisor);
|
||||
|
||||
uint32_t
|
||||
lapic::reset_timer(uint32_t count)
|
||||
{
|
||||
uint32_t remaining = apic_read(m_base, 0x390);
|
||||
apic_write(m_base, 0x380, count);
|
||||
apic_write(m_base, lapic_timer_init, ticks);
|
||||
return remaining;
|
||||
}
|
||||
|
||||
@@ -148,7 +189,7 @@ lapic::enable_lint(uint8_t num, isr vector, bool nmi, uint16_t flags)
|
||||
{
|
||||
kassert(num == 0 || num == 1, "Invalid LINT passed to lapic::enable_lint.");
|
||||
|
||||
uint16_t off = num ? 0x360 : 0x350;
|
||||
uint16_t off = num ? lapic_lvt_lint1 : lapic_lvt_lint0;
|
||||
uint32_t lvte = static_cast<uint8_t>(vector);
|
||||
|
||||
uint16_t polarity = flags & 0x3;
|
||||
@@ -169,21 +210,21 @@ lapic::enable_lint(uint8_t num, isr vector, bool nmi, uint16_t flags)
|
||||
void
|
||||
lapic::enable()
|
||||
{
|
||||
apic_write(m_base, 0xf0,
|
||||
apic_read(m_base, 0xf0) | 0x100);
|
||||
apic_write(m_base, lapic_spurious,
|
||||
apic_read(m_base, lapic_spurious) | 0x100);
|
||||
log::debug(logs::apic, "LAPIC enabled!");
|
||||
}
|
||||
|
||||
void
|
||||
lapic::disable()
|
||||
{
|
||||
apic_write(m_base, 0xf0,
|
||||
apic_read(m_base, 0xf0) & ~0x100);
|
||||
apic_write(m_base, lapic_spurious,
|
||||
apic_read(m_base, lapic_spurious) & ~0x100);
|
||||
log::debug(logs::apic, "LAPIC disabled.");
|
||||
}
|
||||
|
||||
|
||||
ioapic::ioapic(uint32_t *base, uint32_t base_gsi) :
|
||||
ioapic::ioapic(uintptr_t base, uint32_t base_gsi) :
|
||||
apic(base),
|
||||
m_base_gsi(base_gsi)
|
||||
{
|
||||
@@ -206,6 +247,9 @@ ioapic::ioapic(uint32_t *base, uint32_t base_gsi) :
|
||||
void
|
||||
ioapic::redirect(uint8_t irq, isr vector, uint16_t flags, bool masked)
|
||||
{
|
||||
log::debug(logs::apic, "IOAPIC %d redirecting irq %3d to vector %3d [%04x]%s",
|
||||
m_id, irq, vector, flags, masked ? " (masked)" : "");
|
||||
|
||||
uint64_t entry = static_cast<uint64_t>(vector);
|
||||
|
||||
uint16_t polarity = flags & 0x3;
|
||||
@@ -226,6 +270,9 @@ ioapic::redirect(uint8_t irq, isr vector, uint16_t flags, bool masked)
|
||||
void
|
||||
ioapic::mask(uint8_t irq, bool masked)
|
||||
{
|
||||
log::debug(logs::apic, "IOAPIC %d %smasking irq %3d",
|
||||
m_id, masked ? "" : "un", irq);
|
||||
|
||||
uint32_t entry = ioapic_read(m_base, (2 * irq) + 0x10);
|
||||
if (masked)
|
||||
entry |= (1 << 16);
|
||||
|
||||
@@ -3,22 +3,38 @@
|
||||
/// Classes to control both local and I/O APICs.
|
||||
|
||||
#include <stdint.h>
|
||||
#include "kutil/enum_bitfields.h"
|
||||
|
||||
enum class isr : uint8_t;
|
||||
|
||||
|
||||
/// Base class for other APIC types
|
||||
class apic
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
/// \arg base Base virtual address of the APIC's MMIO registers
|
||||
apic(uint32_t *base);
|
||||
/// \arg base Physical base address of the APIC's MMIO registers
|
||||
apic(uintptr_t base);
|
||||
|
||||
protected:
|
||||
uint32_t *m_base;
|
||||
};
|
||||
|
||||
enum class ipi : uint32_t
|
||||
{
|
||||
// Delivery modes
|
||||
fixed = 0x0000,
|
||||
smi = 0x0200,
|
||||
nmi = 0x0400,
|
||||
init = 0x0500,
|
||||
startup = 0x0600,
|
||||
|
||||
// Flags
|
||||
deassert = 0x0000,
|
||||
assert = 0x4000,
|
||||
edge = 0x0000, ///< edge-triggered
|
||||
level = 0x8000, ///< level-triggered
|
||||
};
|
||||
IS_BITFIELD(ipi);
|
||||
|
||||
/// Controller for processor-local APICs
|
||||
class lapic :
|
||||
@@ -26,24 +42,40 @@ class lapic :
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
/// \arg base Base virtual address of the APIC's MMIO registers
|
||||
/// \arg spurious Vector of the spurious interrupt handler
|
||||
lapic(uint32_t *base, isr spurious);
|
||||
/// \arg base Physicl base address of the APIC's MMIO registers
|
||||
lapic(uintptr_t base);
|
||||
|
||||
/// Get the local APIC's ID
|
||||
uint8_t get_id();
|
||||
|
||||
/// Send an inter-processor interrupt.
|
||||
/// \arg mode The sending mode
|
||||
/// \arg vector The interrupt vector
|
||||
/// \arg dest The APIC ID of the destination
|
||||
void send_ipi(ipi mode, uint8_t vector, uint8_t dest);
|
||||
|
||||
/// Send an inter-processor broadcast interrupt to all other CPUs
|
||||
/// \arg mode The sending mode
|
||||
/// \arg self If true, include this CPU in the broadcast
|
||||
/// \arg vector The interrupt vector
|
||||
void send_ipi_broadcast(ipi mode, bool self, uint8_t vector);
|
||||
|
||||
/// Wait for an IPI to finish sending. This is done automatically
|
||||
/// before sending another IPI with send_ipi().
|
||||
void ipi_wait();
|
||||
|
||||
/// Enable interrupts for the LAPIC timer.
|
||||
/// \arg vector Interrupt vector the timer should use
|
||||
/// \arg interval The timer interval, in microseconds
|
||||
/// \arg repeat If false, this timer is one-off, otherwise repeating
|
||||
/// \returns The count of ticks the timer is set for
|
||||
uint32_t enable_timer(isr vector, uint64_t interval, bool repeat = true);
|
||||
void enable_timer(isr vector, bool repeat = true);
|
||||
|
||||
/// Reset the timer countdown.
|
||||
/// \arg count The count of ticks before an interrupt, or 0 to stop the timer
|
||||
/// \returns The count of ticks that were remaining before reset
|
||||
uint32_t reset_timer(uint32_t count);
|
||||
/// \arg interval The interval in us before an interrupt, or 0 to stop the timer
|
||||
/// \returns The interval in us that was remaining before reset
|
||||
uint32_t reset_timer(uint64_t interval);
|
||||
|
||||
/// Stop the timer.
|
||||
/// \returns The count of ticks remaining before an interrupt was to happen
|
||||
/// \returns The interval in us remaining before an interrupt was to happen
|
||||
inline uint32_t stop_timer() { return reset_timer(0); }
|
||||
|
||||
/// Enable interrupts for the LAPIC LINT0 pin.
|
||||
@@ -56,13 +88,18 @@ public:
|
||||
void enable(); ///< Enable servicing of interrupts
|
||||
void disable(); ///< Disable (temporarily) servicing of interrupts
|
||||
|
||||
/// Calibrate the timer speed against the PIT
|
||||
/// Calibrate the timer speed against the clock
|
||||
void calibrate_timer();
|
||||
|
||||
private:
|
||||
uint32_t enable_timer_internal(isr vector, uint8_t divisor, uint32_t count, bool repeat);
|
||||
inline static uint64_t ticks_to_us(uint64_t ticks) { return ticks / s_ticks_per_us; }
|
||||
inline static uint64_t us_to_ticks(uint64_t interval) { return interval * s_ticks_per_us; }
|
||||
|
||||
uint32_t m_ticks_per_us;
|
||||
void set_divisor(uint8_t divisor);
|
||||
void set_repeat(bool repeat);
|
||||
|
||||
uint32_t m_divisor;
|
||||
static uint64_t s_ticks_per_us;
|
||||
};
|
||||
|
||||
|
||||
@@ -72,9 +109,9 @@ class ioapic :
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
/// \arg base Base virtual address of the APIC's MMIO registers
|
||||
/// \arg base Physical base address of the APIC's MMIO registers
|
||||
/// \arg base_gsi Starting global system interrupt number of this IOAPIC
|
||||
ioapic(uint32_t *base, uint32_t base_gsi);
|
||||
ioapic(uintptr_t base, uint32_t base_gsi);
|
||||
|
||||
uint32_t get_base_gsi() const { return m_base_gsi; }
|
||||
uint32_t get_num_gsi() const { return m_num_gsi; }
|
||||
|
||||
@@ -14,8 +14,8 @@ _header:
|
||||
|
||||
section .text
|
||||
align 16
|
||||
global _start:function (_start.end - _start)
|
||||
_start:
|
||||
global _kernel_start:function (_kernel_start.end - _kernel_start)
|
||||
_kernel_start:
|
||||
cli
|
||||
|
||||
mov rsp, idle_stack_end
|
||||
|
||||
22
src/kernel/clock.cpp
Normal file
22
src/kernel/clock.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "clock.h"
|
||||
|
||||
clock * clock::s_instance = nullptr;
|
||||
|
||||
clock::clock(uint64_t rate, clock::source source_func, void *data) :
|
||||
m_rate(rate),
|
||||
m_data(data),
|
||||
m_source(source_func)
|
||||
{
|
||||
// TODO: make this atomic
|
||||
if (s_instance == nullptr)
|
||||
s_instance = this;
|
||||
update();
|
||||
}
|
||||
|
||||
void
|
||||
clock::spinwait(uint64_t us) const
|
||||
{
|
||||
uint64_t when = value() + us;
|
||||
while (value() < when) asm ("pause");
|
||||
}
|
||||
|
||||
44
src/kernel/clock.h
Normal file
44
src/kernel/clock.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
/// \file clock.h
|
||||
/// The kernel time keeping interface
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class clock
|
||||
{
|
||||
public:
|
||||
/// A source is a function that returns the current
|
||||
/// value of some clock source.
|
||||
using source = uint64_t (*)(void*);
|
||||
|
||||
/// Constructor.
|
||||
/// \arg rate Number of source ticks per us
|
||||
/// \arg source Function for the clock source
|
||||
/// \arg data Data to pass to the source function
|
||||
clock(uint64_t rate, source source_func, void *data);
|
||||
|
||||
/// Get the current value of the clock.
|
||||
/// \returns Current value of the source, in us
|
||||
/// TODO: optimize divison by finding a multiply and
|
||||
/// shift value instead
|
||||
inline uint64_t value() const { return m_source(m_data) / m_rate; }
|
||||
|
||||
/// Update the internal state via the source
|
||||
/// \returns Current value of the clock
|
||||
inline void update() { m_current = value(); }
|
||||
|
||||
/// Wait in a tight loop
|
||||
/// \arg interval Time to wait, in us
|
||||
void spinwait(uint64_t us) const;
|
||||
|
||||
/// Get the master clock
|
||||
static clock & get() { return *s_instance; }
|
||||
|
||||
private:
|
||||
uint64_t m_current; ///< current us count
|
||||
uint64_t m_rate; ///< source ticks per us
|
||||
void *m_data;
|
||||
source m_source;
|
||||
|
||||
static clock *s_instance;
|
||||
};
|
||||
@@ -1,223 +1,24 @@
|
||||
#include "kutil/coord.h"
|
||||
#include "kutil/guid.h"
|
||||
#include "kutil/memory.h"
|
||||
#include "kutil/no_construct.h"
|
||||
#include "kutil/printf.h"
|
||||
#include "console.h"
|
||||
#include "font.h"
|
||||
#include "screen.h"
|
||||
#include "serial.h"
|
||||
|
||||
|
||||
const char digits[] = "0123456789abcdef";
|
||||
console g_console;
|
||||
|
||||
|
||||
class console::screen_out
|
||||
{
|
||||
public:
|
||||
screen_out(screen *s, font *f) :
|
||||
m_font(f),
|
||||
m_screen(s),
|
||||
m_size(s->width() / f->width(), s->height() / f->height()),
|
||||
m_fg(0xffffff),
|
||||
m_bg(0),
|
||||
m_first(0),
|
||||
m_data(nullptr),
|
||||
m_attrs(nullptr),
|
||||
m_palette(nullptr)
|
||||
{
|
||||
const unsigned count = m_size.size();
|
||||
const size_t attrs_size = 2 * count;
|
||||
|
||||
m_data = new char[count];
|
||||
kutil::memset(m_data, 0, count);
|
||||
|
||||
m_palette = new screen::pixel_t[256];
|
||||
fill_palette();
|
||||
|
||||
m_attrs = new uint16_t[count];
|
||||
set_color(7, 0); // Grey on black default
|
||||
for (unsigned i = 0; i < count; ++i) m_attrs[i] = m_attr;
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
~screen_out()
|
||||
{
|
||||
delete [] m_data;
|
||||
delete [] m_palette;
|
||||
delete [] m_attrs;
|
||||
}
|
||||
|
||||
void fill_palette()
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
// Manually add the 16 basic ANSI colors
|
||||
m_palette[index++] = m_screen->color(0x00, 0x00, 0x00);
|
||||
m_palette[index++] = m_screen->color(0xcd, 0x00, 0x00);
|
||||
m_palette[index++] = m_screen->color(0x00, 0xcd, 0x00);
|
||||
m_palette[index++] = m_screen->color(0xcd, 0xcd, 0x00);
|
||||
m_palette[index++] = m_screen->color(0x00, 0x00, 0xee);
|
||||
m_palette[index++] = m_screen->color(0xcd, 0x00, 0xcd);
|
||||
m_palette[index++] = m_screen->color(0x00, 0xcd, 0xcd);
|
||||
m_palette[index++] = m_screen->color(0xe5, 0xe5, 0xe5);
|
||||
m_palette[index++] = m_screen->color(0x7f, 0x7f, 0x7f);
|
||||
m_palette[index++] = m_screen->color(0xff, 0x00, 0x00);
|
||||
m_palette[index++] = m_screen->color(0x00, 0xff, 0x00);
|
||||
m_palette[index++] = m_screen->color(0xff, 0xff, 0x00);
|
||||
m_palette[index++] = m_screen->color(0x00, 0x50, 0xff);
|
||||
m_palette[index++] = m_screen->color(0xff, 0x00, 0xff);
|
||||
m_palette[index++] = m_screen->color(0x00, 0xff, 0xff);
|
||||
m_palette[index++] = m_screen->color(0xff, 0xff, 0xff);
|
||||
|
||||
// Build the high-color portion of the table
|
||||
const uint32_t intensity[] = {0, 0x5f, 0x87, 0xaf, 0xd7, 0xff};
|
||||
const uint32_t intensities = sizeof(intensity) / sizeof(uint32_t);
|
||||
|
||||
for (uint32_t r = 0; r < intensities; ++r) {
|
||||
for (uint32_t g = 0; g < intensities; ++g) {
|
||||
for (uint32_t b = 0; b < intensities; ++b) {
|
||||
m_palette[index++] = m_screen->color(
|
||||
intensity[r], intensity[g], intensity[b]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build the greyscale portion of the table
|
||||
for (uint8_t i = 0x08; i <= 0xee; i += 10)
|
||||
m_palette[index++] = m_screen->color(i, i, i);
|
||||
}
|
||||
|
||||
void repaint()
|
||||
{
|
||||
m_screen->fill(m_bg);
|
||||
if (!m_data) return;
|
||||
|
||||
for (unsigned y = 0; y < m_size.y; ++y) {
|
||||
const char *line = line_pointer(y);
|
||||
const uint16_t *attrs = attr_pointer(y);
|
||||
for (unsigned x = 0; x < m_size.x; ++x) {
|
||||
const uint16_t attr = attrs[x];
|
||||
|
||||
set_color(static_cast<uint8_t>(attr),
|
||||
static_cast<uint8_t>(attr >> 8));
|
||||
|
||||
m_font->draw_glyph(
|
||||
m_screen,
|
||||
line[x] ? line[x] : ' ',
|
||||
m_fg,
|
||||
m_bg,
|
||||
x * m_font->width(),
|
||||
y * m_font->height());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scroll(unsigned lines)
|
||||
{
|
||||
if (!m_data) {
|
||||
m_pos.x = 0;
|
||||
m_pos.y = 0;
|
||||
} else {
|
||||
unsigned bytes = lines * m_size.x;
|
||||
char *line = line_pointer(0);
|
||||
for (unsigned i = 0; i < bytes; ++i)
|
||||
*line++ = 0;
|
||||
|
||||
m_first = (m_first + lines) % m_size.y;
|
||||
m_pos.y -= lines;
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
void set_color(uint8_t fg, uint8_t bg)
|
||||
{
|
||||
m_bg = m_palette[bg];
|
||||
m_fg = m_palette[fg];
|
||||
m_attr = (bg << 8) | fg;
|
||||
}
|
||||
|
||||
void putc(char c)
|
||||
{
|
||||
char *line = line_pointer(m_pos.y);
|
||||
uint16_t *attrs = attr_pointer(m_pos.y);
|
||||
|
||||
|
||||
switch (c) {
|
||||
case '\t':
|
||||
m_pos.x = (m_pos.x + 4) / 4 * 4;
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
m_pos.x = 0;
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
m_pos.x = 0;
|
||||
m_pos.y++;
|
||||
break;
|
||||
|
||||
default: {
|
||||
if (line) line[m_pos.x] = c;
|
||||
if (attrs) attrs[m_pos.x] = m_attr;
|
||||
|
||||
const unsigned x = m_pos.x * m_font->width();
|
||||
const unsigned y = m_pos.y * m_font->height();
|
||||
m_font->draw_glyph(m_screen, c, m_fg, m_bg, x, y);
|
||||
|
||||
m_pos.x++;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pos.x >= m_size.x) {
|
||||
m_pos.x = m_pos.x % m_size.x;
|
||||
m_pos.y++;
|
||||
}
|
||||
|
||||
if (m_pos.y >= m_size.y) {
|
||||
scroll(1);
|
||||
line = line_pointer(m_pos.y);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
char * line_pointer(unsigned line)
|
||||
{
|
||||
if (!m_data) return nullptr;
|
||||
return m_data + ((m_first + line) % m_size.y) * m_size.x;
|
||||
}
|
||||
|
||||
uint16_t * attr_pointer(unsigned line)
|
||||
{
|
||||
if (!m_attrs) return nullptr;
|
||||
return m_attrs + ((m_first + line) % m_size.y) * m_size.x;
|
||||
}
|
||||
|
||||
font *m_font;
|
||||
screen *m_screen;
|
||||
|
||||
kutil::coord<unsigned> m_size;
|
||||
kutil::coord<unsigned> m_pos;
|
||||
screen::pixel_t m_fg, m_bg;
|
||||
uint16_t m_attr;
|
||||
|
||||
size_t m_first;
|
||||
|
||||
char *m_data;
|
||||
uint16_t *m_attrs;
|
||||
screen::pixel_t *m_palette;
|
||||
};
|
||||
static kutil::no_construct<console> __g_console_storage;
|
||||
console &g_console = __g_console_storage.value;
|
||||
|
||||
|
||||
console::console() :
|
||||
m_screen(nullptr),
|
||||
m_serial(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
console::console(serial_port *serial) :
|
||||
m_screen(nullptr),
|
||||
m_serial(serial)
|
||||
{
|
||||
if (m_serial) {
|
||||
@@ -236,9 +37,6 @@ console::echo()
|
||||
void
|
||||
console::set_color(uint8_t fg, uint8_t bg)
|
||||
{
|
||||
if (m_screen)
|
||||
m_screen->set_color(fg, bg);
|
||||
|
||||
if (m_serial) {
|
||||
const char *fgseq = "\x1b[38;5;";
|
||||
while (*fgseq)
|
||||
@@ -258,21 +56,24 @@ console::set_color(uint8_t fg, uint8_t bg)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
size_t
|
||||
console::puts(const char *message)
|
||||
{
|
||||
while (message && *message)
|
||||
size_t n = 0;
|
||||
while (message && *message) {
|
||||
n++;
|
||||
putc(*message++);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
console::putc(char c)
|
||||
{
|
||||
if (m_screen) m_screen->putc(c);
|
||||
|
||||
if (m_serial) {
|
||||
if (c == '\n') m_serial->write('\r');
|
||||
m_serial->write(c);
|
||||
if (c == '\r') m_serial->write('\n');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,9 +84,3 @@ void console::vprintf(const char *fmt, va_list args)
|
||||
vsnprintf_(buffer, buf_size, fmt, args);
|
||||
puts(buffer);
|
||||
}
|
||||
|
||||
void
|
||||
console::init_screen(screen *s, font *f)
|
||||
{
|
||||
m_screen = new screen_out(s, f);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
class font;
|
||||
struct kernel_data;
|
||||
class screen;
|
||||
class serial_port;
|
||||
|
||||
class console
|
||||
@@ -17,7 +14,7 @@ public:
|
||||
void set_color(uint8_t fg = 7, uint8_t bg = 0);
|
||||
|
||||
void putc(char c);
|
||||
void puts(const char *message);
|
||||
size_t puts(const char *message);
|
||||
void vprintf(const char *fmt, va_list args);
|
||||
|
||||
inline void printf(const char *fmt, ...)
|
||||
@@ -36,17 +33,13 @@ public:
|
||||
|
||||
void echo();
|
||||
|
||||
void init_screen(screen *s, font *f);
|
||||
|
||||
static console * get();
|
||||
|
||||
private:
|
||||
class screen_out;
|
||||
screen_out *m_screen;
|
||||
serial_port *m_serial;
|
||||
};
|
||||
|
||||
extern console g_console;
|
||||
extern console &g_console;
|
||||
inline console * console::get() { return &g_console; }
|
||||
|
||||
|
||||
@@ -61,7 +54,7 @@ void console::put_hex(T x, int width, char pad)
|
||||
int len = 1;
|
||||
for (int i = chars - 1; i >= 0; --i) {
|
||||
uint8_t nibble = (x >> (i*4)) & 0xf;
|
||||
if (nibble) len = std::max(i + 1, len);
|
||||
if (nibble) len = len > i + 1 ? len : i + 1;
|
||||
message[chars - i - 1] = digits[nibble];
|
||||
}
|
||||
message[chars] = 0;
|
||||
|
||||
@@ -1,116 +1,66 @@
|
||||
#include <stdint.h>
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/memory.h"
|
||||
#include "cpu.h"
|
||||
#include "cpu/cpu_id.h"
|
||||
#include "device_manager.h"
|
||||
#include "gdt.h"
|
||||
#include "idt.h"
|
||||
#include "kernel_memory.h"
|
||||
#include "log.h"
|
||||
#include "msr.h"
|
||||
#include "objects/vm_area.h"
|
||||
#include "syscall.h"
|
||||
#include "tss.h"
|
||||
|
||||
cpu_data bsp_cpu_data;
|
||||
|
||||
static constexpr uint32_t cpuid_extended = 0x80000000;
|
||||
|
||||
|
||||
inline static void
|
||||
__cpuid(
|
||||
uint32_t leaf,
|
||||
uint32_t subleaf,
|
||||
uint32_t *eax,
|
||||
uint32_t *ebx = nullptr,
|
||||
uint32_t *ecx = nullptr,
|
||||
uint32_t *edx = nullptr)
|
||||
{
|
||||
uint32_t a, b, c, d;
|
||||
__asm__ __volatile__ ( "cpuid"
|
||||
: "=a"(a), "=b"(b), "=c"(c), "=d"(d)
|
||||
: "a"(leaf), "c"(subleaf)
|
||||
);
|
||||
if (eax) *eax = a;
|
||||
if (ebx) *ebx = b;
|
||||
if (ecx) *ecx = c;
|
||||
if (edx) *edx = d;
|
||||
}
|
||||
|
||||
cpu_id::cpu_id() :
|
||||
m_features(0)
|
||||
{
|
||||
__cpuid(0, 0,
|
||||
&m_high_basic,
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[0]),
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[8]),
|
||||
reinterpret_cast<uint32_t *>(&m_vendor_id[4]));
|
||||
|
||||
__cpuid(cpuid_extended, 0, &m_high_ext);
|
||||
|
||||
if (m_high_ext >= cpuid_extended + 4) {
|
||||
__cpuid(cpuid_extended + 2, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[0]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[4]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[8]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[12]));
|
||||
__cpuid(cpuid_extended + 3, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[16]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[20]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[24]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[28]));
|
||||
__cpuid(cpuid_extended + 4, 0,
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[32]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[36]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[40]),
|
||||
reinterpret_cast<uint32_t *>(&m_brand_name[44]));
|
||||
} else {
|
||||
m_brand_name[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cpu_id::regs
|
||||
cpu_id::get(uint32_t leaf, uint32_t sub) const
|
||||
{
|
||||
regs ret {0, 0, 0, 0};
|
||||
|
||||
if ((leaf & cpuid_extended) == 0 && leaf > m_high_basic) return ret;
|
||||
if ((leaf & cpuid_extended) != 0 && leaf > m_high_ext) return ret;
|
||||
|
||||
__cpuid(leaf, sub, &ret.eax, &ret.ebx, &ret.ecx, &ret.edx);
|
||||
return ret;
|
||||
}
|
||||
cpu_data g_bsp_cpu_data;
|
||||
|
||||
void
|
||||
cpu_id::validate()
|
||||
cpu_validate()
|
||||
{
|
||||
bool fail = false;
|
||||
uint32_t leaf = 0;
|
||||
uint32_t sub = 0;
|
||||
regs r;
|
||||
cpu::cpu_id cpu;
|
||||
|
||||
log::info(logs::boot, "CPU: %s", brand_name());
|
||||
log::debug(logs::boot, " Vendor is %s", vendor_id());
|
||||
log::info(logs::boot, "CPU: %s", cpu.brand_name());
|
||||
log::debug(logs::boot, " Vendor is %s", cpu.vendor_id());
|
||||
|
||||
log::debug(logs::boot, " Higest basic CPUID: 0x%02x", highest_basic());
|
||||
log::debug(logs::boot, " Higest ext CPUID: 0x%02x", highest_ext() & ~cpuid_extended);
|
||||
log::debug(logs::boot, " Higest basic CPUID: 0x%02x", cpu.highest_basic());
|
||||
log::debug(logs::boot, " Higest ext CPUID: 0x%02x", cpu.highest_ext() & ~cpu::cpu_id::cpuid_extended);
|
||||
|
||||
#define CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit) \
|
||||
if (leaf != feat_leaf || sub != feat_sub) { \
|
||||
leaf = feat_leaf; sub = feat_sub; r = get(leaf, sub); \
|
||||
} \
|
||||
if (r.regname & (1 << bit)) \
|
||||
m_features |= (1 << static_cast<uint64_t>(cpu_feature::name)); \
|
||||
log::debug(logs::boot, " Supports %9s: %s", #name, (r.regname & (1<<bit)) ? "yes" : "no");
|
||||
#define CPU_FEATURE_OPT(name, ...) \
|
||||
log::debug(logs::boot, " Supports %9s: %s", #name, cpu.has_feature(cpu::feature::name) ? "yes" : "no");
|
||||
|
||||
#define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \
|
||||
CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \
|
||||
if ((r.regname & (1 << bit)) == 0) { \
|
||||
log::error(logs::boot, "CPU missing required feature " #name); \
|
||||
fail = true; \
|
||||
}
|
||||
kassert(cpu.has_feature(cpu::feature::name), "Missing required CPU feature " #name );
|
||||
|
||||
#include "cpu_features.inc"
|
||||
#include "cpu/features.inc"
|
||||
#undef CPU_FEATURE_OPT
|
||||
#undef CPU_FEATURE_REQ
|
||||
|
||||
if (fail)
|
||||
log::fatal(logs::boot, "CPU not supported.");
|
||||
}
|
||||
|
||||
bool
|
||||
cpu_id::has_feature(cpu_feature feat)
|
||||
void
|
||||
cpu_early_init(cpu_data *cpu)
|
||||
{
|
||||
return (m_features & (1 << static_cast<uint64_t>(feat))) != 0;
|
||||
IDT::get().install();
|
||||
cpu->gdt->install();
|
||||
|
||||
// Install the GS base pointint to the cpu_data
|
||||
wrmsr(msr::ia32_gs_base, reinterpret_cast<uintptr_t>(cpu));
|
||||
}
|
||||
|
||||
void
|
||||
cpu_init(cpu_data *cpu, bool bsp)
|
||||
{
|
||||
if (!bsp) {
|
||||
// The BSP already called cpu_early_init
|
||||
cpu_early_init(cpu);
|
||||
}
|
||||
|
||||
// Set up the syscall MSRs
|
||||
syscall_enable();
|
||||
|
||||
// Set up the page attributes table
|
||||
uint64_t pat = rdmsr(msr::ia32_pat);
|
||||
pat = (pat & 0x00ffffffffffffffull) | (0x01ull << 56); // set PAT 7 to WC
|
||||
wrmsr(msr::ia32_pat, pat);
|
||||
}
|
||||
|
||||
100
src/kernel/cpu.h
100
src/kernel/cpu.h
@@ -2,7 +2,12 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct process;
|
||||
class GDT;
|
||||
class lapic;
|
||||
class process;
|
||||
struct TCB;
|
||||
class thread;
|
||||
class TSS;
|
||||
|
||||
struct cpu_state
|
||||
{
|
||||
@@ -16,76 +21,39 @@ struct cpu_state
|
||||
/// version in 'tasking.inc'
|
||||
struct cpu_data
|
||||
{
|
||||
cpu_data *self;
|
||||
uint16_t id;
|
||||
uint16_t index;
|
||||
uint32_t reserved;
|
||||
uintptr_t rsp0;
|
||||
uintptr_t rsp3;
|
||||
process *tcb;
|
||||
TCB *tcb;
|
||||
thread *thread;
|
||||
process *process;
|
||||
TSS *tss;
|
||||
GDT *gdt;
|
||||
|
||||
// Members beyond this point do not appear in
|
||||
// the assembly version
|
||||
lapic *apic;
|
||||
};
|
||||
|
||||
extern cpu_data bsp_cpu_data;
|
||||
extern "C" cpu_data * _current_gsbase();
|
||||
|
||||
/// Enum of the cpu features jsix cares about
|
||||
enum class cpu_feature {
|
||||
#define CPU_FEATURE_REQ(name, ...) name,
|
||||
#define CPU_FEATURE_OPT(name, ...) name,
|
||||
#include "cpu_features.inc"
|
||||
#undef CPU_FEATURE_OPT
|
||||
#undef CPU_FEATURE_REQ
|
||||
max
|
||||
};
|
||||
/// Set up the running CPU. This sets GDT, IDT, and necessary MSRs as well as creating
|
||||
/// the cpu_data structure for this processor.
|
||||
/// \arg cpu The cpu_data structure for this CPU
|
||||
/// \arg bsp True if this CPU is the BSP
|
||||
void cpu_init(cpu_data *cpu, bool bsp);
|
||||
|
||||
class cpu_id
|
||||
{
|
||||
public:
|
||||
/// CPUID result register values
|
||||
struct regs {
|
||||
union {
|
||||
uint32_t reg[4];
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
};
|
||||
/// Do early (before cpu_init) initialization work. Only needs to be called manually for
|
||||
/// the BSP, otherwise cpu_init will call it.
|
||||
/// \arg cpu The cpu_data structure for this CPU
|
||||
void cpu_early_init(cpu_data *cpu);
|
||||
|
||||
/// Return true if bit |bit| of EAX is set
|
||||
bool eax_bit(unsigned bit) { return (eax >> bit) & 0x1; }
|
||||
/// Get the cpu_data struct for the current executing CPU
|
||||
inline cpu_data & current_cpu() { return *_current_gsbase(); }
|
||||
|
||||
/// Return true if bit |bit| of EBX is set
|
||||
bool ebx_bit(unsigned bit) { return (ebx >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of ECX is set
|
||||
bool ecx_bit(unsigned bit) { return (ecx >> bit) & 0x1; }
|
||||
|
||||
/// Return true if bit |bit| of EDX is set
|
||||
bool edx_bit(unsigned bit) { return (edx >> bit) & 0x1; }
|
||||
};
|
||||
|
||||
cpu_id();
|
||||
|
||||
/// The the result of a given CPUID leaf/subleaf
|
||||
/// \arg leaf The leaf selector (initial EAX)
|
||||
/// \arg subleaf The subleaf selector (initial ECX)
|
||||
/// \returns A |regs| struct of the values retuned
|
||||
regs get(uint32_t leaf, uint32_t sub = 0) const;
|
||||
|
||||
/// Get the name of the cpu vendor (eg, "GenuineIntel")
|
||||
inline const char * vendor_id() const { return m_vendor_id; }
|
||||
|
||||
/// Get the brand name of this processor model
|
||||
inline const char * brand_name() const { return m_brand_name; }
|
||||
|
||||
/// Get the highest basic CPUID leaf supported
|
||||
inline uint32_t highest_basic() const { return m_high_basic; }
|
||||
|
||||
/// Get the highest extended CPUID leaf supported
|
||||
inline uint32_t highest_ext() const { return m_high_ext; }
|
||||
|
||||
/// Validate the CPU supports the necessary options for jsix
|
||||
void validate();
|
||||
|
||||
/// Return true if the CPU claims to support the given feature
|
||||
bool has_feature(cpu_feature feat);
|
||||
|
||||
private:
|
||||
uint32_t m_high_basic;
|
||||
uint32_t m_high_ext;
|
||||
char m_vendor_id[13];
|
||||
char m_brand_name[48];
|
||||
uint64_t m_features;
|
||||
};
|
||||
/// Validate the required CPU features are present. Really, the bootloader already
|
||||
/// validated the required features, but still iterate the options and log about them.
|
||||
void cpu_validate();
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
CPU_FEATURE_OPT(pcid, 0x00000001, 0, ecx, 17)
|
||||
CPU_FEATURE_OPT(x2apic, 0x00000001, 0, ecx, 21)
|
||||
CPU_FEATURE_REQ(fpu, 0x00000001, 0, edx, 0)
|
||||
CPU_FEATURE_REQ(pse, 0x00000001, 0, edx, 3)
|
||||
CPU_FEATURE_OPT(tsc, 0x00000001, 0, edx, 4)
|
||||
CPU_FEATURE_REQ(msr, 0x00000001, 0, edx, 5)
|
||||
CPU_FEATURE_REQ(apic, 0x00000001, 0, edx, 9)
|
||||
CPU_FEATURE_REQ(pge, 0x00000001, 0, edx, 13)
|
||||
CPU_FEATURE_OPT(pat, 0x00000001, 0, edx, 16)
|
||||
CPU_FEATURE_REQ(fxsr, 0x00000001, 0, edx, 24)
|
||||
CPU_FEATURE_OPT(fsgsbase, 0x00000007, 0, ebx, 0)
|
||||
CPU_FEATURE_OPT(invpcid, 0x00000007, 0, ebx, 10)
|
||||
CPU_FEATURE_OPT(pku, 0x00000007, 0, ecx, 3)
|
||||
CPU_FEATURE_REQ(syscall, 0x80000001, 0, edx, 11)
|
||||
CPU_FEATURE_REQ(pdpe1gb, 0x80000001, 0, edx, 26)
|
||||
CPU_FEATURE_OPT(extapic, 0x80000001, 0, ecx, 3)
|
||||
@@ -1,14 +0,0 @@
|
||||
section .init
|
||||
global _init:function
|
||||
_init:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
; Control flow falls through to other .init sections
|
||||
|
||||
section .fini
|
||||
global _fini:function
|
||||
_fini:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
; Control flow falls through to other .fini sections
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
section .init
|
||||
; Control flow falls through to here from other .init sections
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
section .fini
|
||||
; Control flow falls through to here from other .fini sections
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#include "cpu.h"
|
||||
#include "debug.h"
|
||||
#include "gdt.h"
|
||||
#include "page_manager.h"
|
||||
#include "objects/process.h"
|
||||
#include "objects/thread.h"
|
||||
#include "symbol_table.h"
|
||||
|
||||
size_t __counter_syscall_enter = 0;
|
||||
size_t __counter_syscall_sysret = 0;
|
||||
@@ -11,10 +13,17 @@ void
|
||||
print_regs(const cpu_state ®s)
|
||||
{
|
||||
console *cons = console::get();
|
||||
cpu_data &cpu = current_cpu();
|
||||
|
||||
uint64_t cr2 = 0;
|
||||
__asm__ __volatile__ ("mov %%cr2, %0" : "=r"(cr2));
|
||||
|
||||
uintptr_t cr3 = 0;
|
||||
__asm__ __volatile__ ( "mov %%cr3, %0" : "=r" (cr3) );
|
||||
|
||||
cons->printf(" process: %llx", cpu.process->koid());
|
||||
cons->printf(" thread: %llx\n", cpu.thread->koid());
|
||||
|
||||
print_regL("rax", regs.rax);
|
||||
print_regM("rbx", regs.rbx);
|
||||
print_regR("rcx", regs.rcx);
|
||||
@@ -35,10 +44,10 @@ print_regs(const cpu_state ®s)
|
||||
cons->puts("\n\n");
|
||||
print_regL("rbp", regs.rbp);
|
||||
print_regM("rsp", regs.user_rsp);
|
||||
print_regR("sp0", bsp_cpu_data.rsp0);
|
||||
print_regR("sp0", cpu.rsp0);
|
||||
|
||||
print_regL("rip", regs.rip);
|
||||
print_regM("cr3", page_manager::get()->get_pml4());
|
||||
print_regM("cr3", cr3);
|
||||
print_regR("cr2", cr2);
|
||||
|
||||
cons->puts("\n");
|
||||
@@ -54,14 +63,26 @@ void
|
||||
print_stacktrace(int skip)
|
||||
{
|
||||
console *cons = console::get();
|
||||
symbol_table *syms = symbol_table::get();
|
||||
|
||||
frame *fp = nullptr;
|
||||
int fi = -skip;
|
||||
__asm__ __volatile__ ( "mov %%rbp, %0" : "=r" (fp) );
|
||||
|
||||
while (fp && fp->return_addr) {
|
||||
if (fi++ >= 0)
|
||||
cons->printf(" frame %2d: %lx\n", fi-1, fp->return_addr);
|
||||
if (fi++ >= 0) {
|
||||
const symbol_table::entry *e = syms ? syms->find_symbol(fp->return_addr) : nullptr;
|
||||
const char *name = e ? e->name : "";
|
||||
cons->printf(" frame %2d:", fi-1);
|
||||
|
||||
cons->set_color(5);
|
||||
cons->printf(" %016llx", fp->return_addr);
|
||||
cons->set_color();
|
||||
|
||||
cons->set_color(6);
|
||||
cons->printf(" %s\n", name);
|
||||
cons->set_color();
|
||||
}
|
||||
fp = fp->prev;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,12 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct cpu_state;
|
||||
|
||||
extern "C" {
|
||||
uintptr_t get_rsp();
|
||||
uintptr_t get_rip();
|
||||
uintptr_t get_caller();
|
||||
uintptr_t get_frame(int frame);
|
||||
uintptr_t get_gsbase();
|
||||
void _halt();
|
||||
|
||||
@@ -8,6 +8,12 @@ get_rip:
|
||||
pop rax ; do the same thing as 'ret', except with 'jmp'
|
||||
jmp rax ; with the return address still in rax
|
||||
|
||||
global get_caller
|
||||
get_caller:
|
||||
; No prelude - don't touch rsp or rbp
|
||||
mov rax, [rbp+8]
|
||||
ret
|
||||
|
||||
global get_gsbase
|
||||
get_gsbase:
|
||||
rdgsbase rax
|
||||
|
||||
@@ -5,16 +5,20 @@
|
||||
#include "kutil/memory.h"
|
||||
#include "acpi_tables.h"
|
||||
#include "apic.h"
|
||||
#include "clock.h"
|
||||
#include "console.h"
|
||||
#include "device_manager.h"
|
||||
#include "interrupts.h"
|
||||
#include "kernel_memory.h"
|
||||
#include "log.h"
|
||||
#include "page_manager.h"
|
||||
#include "objects/endpoint.h"
|
||||
|
||||
|
||||
static endpoint * const ignore_endpoint = reinterpret_cast<endpoint*>(-1ull);
|
||||
|
||||
static const char expected_signature[] = "RSD PTR ";
|
||||
|
||||
device_manager device_manager::s_instance(nullptr, kutil::allocator::invalid);
|
||||
device_manager device_manager::s_instance;
|
||||
|
||||
struct acpi1_rsdp
|
||||
{
|
||||
@@ -34,7 +38,7 @@ struct acpi2_rsdp
|
||||
uint32_t rsdt_address;
|
||||
|
||||
uint32_t length;
|
||||
uint64_t xsdt_address;
|
||||
acpi_table_header *xsdt_address;
|
||||
uint8_t checksum20;
|
||||
uint8_t reserved[3];
|
||||
} __attribute__ ((packed));
|
||||
@@ -46,7 +50,6 @@ acpi_table_header::validate(uint32_t expected_type) const
|
||||
return !expected_type || (expected_type == type);
|
||||
}
|
||||
|
||||
|
||||
void irq2_callback(void *)
|
||||
{
|
||||
}
|
||||
@@ -59,18 +62,31 @@ void irq4_callback(void *)
|
||||
}
|
||||
|
||||
|
||||
device_manager::device_manager(const void *root_table, kutil::allocator &alloc) :
|
||||
m_lapic(nullptr),
|
||||
m_ioapics(alloc),
|
||||
m_pci(alloc),
|
||||
m_devices(alloc),
|
||||
m_irqs(alloc),
|
||||
m_blockdevs(alloc)
|
||||
device_manager::device_manager() :
|
||||
m_lapic_base(0)
|
||||
{
|
||||
m_irqs.ensure_capacity(32);
|
||||
m_irqs.set_size(16);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
m_irqs[i] = nullptr;
|
||||
|
||||
m_irqs[2] = ignore_endpoint;
|
||||
}
|
||||
|
||||
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
|
||||
device_manager::parse_acpi(const void *root_table)
|
||||
{
|
||||
kassert(root_table != 0, "ACPI root table pointer is null.");
|
||||
|
||||
const acpi1_rsdp *acpi1 =
|
||||
reinterpret_cast<const acpi1_rsdp *>(root_table);
|
||||
const acpi1_rsdp *acpi1 = memory::to_virtual(
|
||||
reinterpret_cast<const acpi1_rsdp *>(root_table));
|
||||
|
||||
for (int i = 0; i < sizeof(acpi1->signature); ++i)
|
||||
kassert(acpi1->signature[i] == expected_signature[i],
|
||||
@@ -87,12 +103,27 @@ device_manager::device_manager(const void *root_table, kutil::allocator &alloc)
|
||||
sum = kutil::checksum(acpi2, sizeof(acpi2_rsdp), sizeof(acpi1_rsdp));
|
||||
kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch.");
|
||||
|
||||
load_xsdt(reinterpret_cast<const acpi_xsdt *>(acpi2->xsdt_address));
|
||||
load_xsdt(memory::to_virtual(acpi2->xsdt_address));
|
||||
}
|
||||
|
||||
m_irqs.ensure_capacity(32);
|
||||
m_irqs.set_size(16);
|
||||
m_irqs[2] = {"Clock interrupt", irq2_callback, nullptr};
|
||||
m_irqs[4] = {"Serial interrupt", irq4_callback, nullptr};
|
||||
const device_manager::apic_nmi *
|
||||
device_manager::get_lapic_nmi(uint8_t id) const
|
||||
{
|
||||
for (const auto &nmi : m_nmis) {
|
||||
if (nmi.cpu == 0xff || nmi.cpu == id)
|
||||
return &nmi;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const device_manager::irq_override *
|
||||
device_manager::get_irq_override(uint8_t irq) const
|
||||
{
|
||||
for (const auto &o : m_overrides)
|
||||
if (o.source == irq) return &o;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ioapic *
|
||||
@@ -108,9 +139,9 @@ put_sig(char *into, uint32_t type)
|
||||
}
|
||||
|
||||
void
|
||||
device_manager::load_xsdt(const acpi_xsdt *xsdt)
|
||||
device_manager::load_xsdt(const acpi_table_header *header)
|
||||
{
|
||||
kassert(xsdt && acpi_validate(xsdt), "Invalid ACPI XSDT.");
|
||||
const auto *xsdt = check_get_table<acpi_xsdt>(header);
|
||||
|
||||
char sig[5] = {0,0,0,0,0};
|
||||
log::info(logs::device, "ACPI 2.0+ tables loading");
|
||||
@@ -120,7 +151,8 @@ device_manager::load_xsdt(const acpi_xsdt *xsdt)
|
||||
|
||||
size_t num_tables = acpi_table_entries(xsdt, sizeof(void*));
|
||||
for (size_t i = 0; i < num_tables; ++i) {
|
||||
const acpi_table_header *header = xsdt->headers[i];
|
||||
const acpi_table_header *header =
|
||||
memory::to_virtual(xsdt->headers[i]);
|
||||
|
||||
put_sig(sig, header->type);
|
||||
log::debug(logs::device, " Found table %s", sig);
|
||||
@@ -129,11 +161,15 @@ device_manager::load_xsdt(const acpi_xsdt *xsdt)
|
||||
|
||||
switch (header->type) {
|
||||
case acpi_apic::type_id:
|
||||
load_apic(reinterpret_cast<const acpi_apic *>(header));
|
||||
load_apic(header);
|
||||
break;
|
||||
|
||||
case acpi_mcfg::type_id:
|
||||
load_mcfg(reinterpret_cast<const acpi_mcfg *>(header));
|
||||
load_mcfg(header);
|
||||
break;
|
||||
|
||||
case acpi_hpet::type_id:
|
||||
load_hpet(header);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -143,41 +179,42 @@ device_manager::load_xsdt(const acpi_xsdt *xsdt)
|
||||
}
|
||||
|
||||
void
|
||||
device_manager::load_apic(const acpi_apic *apic)
|
||||
device_manager::load_apic(const acpi_table_header *header)
|
||||
{
|
||||
uint32_t *local = reinterpret_cast<uint32_t *>(apic->local_address);
|
||||
const auto *apic = check_get_table<acpi_apic>(header);
|
||||
|
||||
m_lapic = new lapic(local, isr::isrSpurious);
|
||||
m_lapic_base = apic->local_address;
|
||||
|
||||
size_t count = acpi_table_entries(apic, 1);
|
||||
uint8_t const *p = apic->controller_data;
|
||||
uint8_t const *end = p + count;
|
||||
|
||||
// Pass one: count IOAPIC objcts
|
||||
int num_ioapics = 0;
|
||||
// Pass one: count objcts
|
||||
unsigned num_lapics = 0;
|
||||
unsigned num_ioapics = 0;
|
||||
unsigned num_overrides = 0;
|
||||
unsigned num_nmis = 0;
|
||||
while (p < end) {
|
||||
const uint8_t type = p[0];
|
||||
const uint8_t length = p[1];
|
||||
if (type == 1) num_ioapics++;
|
||||
p += length;
|
||||
}
|
||||
|
||||
m_ioapics.set_capacity(num_ioapics);
|
||||
|
||||
// Pass two: set up IOAPIC objcts
|
||||
p = apic->controller_data;
|
||||
while (p < end) {
|
||||
const uint8_t type = p[0];
|
||||
const uint8_t length = p[1];
|
||||
if (type == 1) {
|
||||
uint32_t *base = reinterpret_cast<uint32_t *>(kutil::read_from<uint32_t>(p+4));
|
||||
uint32_t base_gsr = kutil::read_from<uint32_t>(p+8);
|
||||
m_ioapics.emplace(base, base_gsr);
|
||||
switch (type) {
|
||||
case 0: ++num_lapics; break;
|
||||
case 1: ++num_ioapics; break;
|
||||
case 2: ++num_overrides; break;
|
||||
case 4: ++num_nmis; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
p += length;
|
||||
}
|
||||
|
||||
// Pass three: configure APIC objects
|
||||
m_apic_ids.set_capacity(num_lapics);
|
||||
m_ioapics.set_capacity(num_ioapics);
|
||||
m_overrides.set_capacity(num_overrides);
|
||||
m_nmis.set_capacity(num_nmis);
|
||||
|
||||
// Pass two: configure objects
|
||||
p = apic->controller_data;
|
||||
while (p < end) {
|
||||
const uint8_t type = p[0];
|
||||
@@ -187,38 +224,42 @@ device_manager::load_apic(const acpi_apic *apic)
|
||||
case 0: { // Local APIC
|
||||
uint8_t uid = kutil::read_from<uint8_t>(p+2);
|
||||
uint8_t id = kutil::read_from<uint8_t>(p+3);
|
||||
log::debug(logs::device, " Local APIC uid %x id %x", id);
|
||||
m_apic_ids.append(id);
|
||||
|
||||
log::debug(logs::device, " Local APIC uid %x id %x", uid, id);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // I/O APIC
|
||||
case 1: { // I/O APIC
|
||||
uintptr_t base = kutil::read_from<uint32_t>(p+4);
|
||||
uint32_t base_gsi = kutil::read_from<uint32_t>(p+8);
|
||||
m_ioapics.emplace(base, base_gsi);
|
||||
|
||||
log::debug(logs::device, " IO APIC gsi %x base %x", base_gsi, base);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: { // Interrupt source override
|
||||
uint8_t source = kutil::read_from<uint8_t>(p+3);
|
||||
isr gsi = isr::irq00 + kutil::read_from<uint32_t>(p+4);
|
||||
uint16_t flags = kutil::read_from<uint16_t>(p+8);
|
||||
irq_override o;
|
||||
o.source = kutil::read_from<uint8_t>(p+3);
|
||||
o.gsi = kutil::read_from<uint32_t>(p+4);
|
||||
o.flags = kutil::read_from<uint16_t>(p+8);
|
||||
m_overrides.append(o);
|
||||
|
||||
log::debug(logs::device, " Intr source override IRQ %d -> %d Pol %d Tri %d",
|
||||
source, gsi, (flags & 0x3), ((flags >> 2) & 0x3));
|
||||
|
||||
// TODO: in a multiple-IOAPIC system this might be elsewhere
|
||||
m_ioapics[0].redirect(source, static_cast<isr>(gsi), flags, true);
|
||||
o.source, o.gsi, (o.flags & 0x3), ((o.flags >> 2) & 0x3));
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: {// LAPIC NMI
|
||||
uint8_t cpu = kutil::read_from<uint8_t>(p + 2);
|
||||
uint8_t num = kutil::read_from<uint8_t>(p + 5);
|
||||
uint16_t flags = kutil::read_from<uint16_t>(p + 3);
|
||||
apic_nmi nmi;
|
||||
nmi.cpu = kutil::read_from<uint8_t>(p + 2);
|
||||
nmi.lint = kutil::read_from<uint8_t>(p + 5);
|
||||
nmi.flags = kutil::read_from<uint16_t>(p + 3);
|
||||
m_nmis.append(nmi);
|
||||
|
||||
log::debug(logs::device, " LAPIC NMI Proc %d LINT%d Pol %d Tri %d",
|
||||
kutil::read_from<uint8_t>(p+2),
|
||||
kutil::read_from<uint8_t>(p+5),
|
||||
kutil::read_from<uint16_t>(p+3) & 0x3,
|
||||
(kutil::read_from<uint16_t>(p+3) >> 2) & 0x3);
|
||||
|
||||
m_lapic->enable_lint(num, num == 0 ? isr::isrLINT0 : isr::isrLINT1, true, flags);
|
||||
log::debug(logs::device, " LAPIC NMI Proc %02x LINT%d Pol %d Tri %d",
|
||||
nmi.cpu, nmi.lint, nmi.flags & 0x3, (nmi.flags >> 2) & 0x3);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -228,39 +269,24 @@ device_manager::load_apic(const acpi_apic *apic)
|
||||
|
||||
p += length;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < m_ioapics[0].get_num_gsi(); ++i) {
|
||||
switch (i) {
|
||||
case 2: break;
|
||||
default: m_ioapics[0].mask(i, false);
|
||||
}
|
||||
}
|
||||
|
||||
m_lapic->enable();
|
||||
}
|
||||
|
||||
void
|
||||
device_manager::load_mcfg(const acpi_mcfg *mcfg)
|
||||
device_manager::load_mcfg(const acpi_table_header *header)
|
||||
{
|
||||
const auto *mcfg = check_get_table<acpi_mcfg>(header);
|
||||
|
||||
size_t count = acpi_table_entries(mcfg, sizeof(acpi_mcfg_entry));
|
||||
m_pci.set_size(count);
|
||||
m_devices.set_capacity(16);
|
||||
|
||||
page_manager *pm = page_manager::get();
|
||||
|
||||
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 = reinterpret_cast<uint32_t *>(mcfge.base);
|
||||
|
||||
int num_busses = m_pci[i].bus_end - m_pci[i].bus_start + 1;
|
||||
|
||||
/// Map the MMIO space into memory
|
||||
pm->map_offset_pointer(reinterpret_cast<void **>(&m_pci[i].base),
|
||||
(num_busses << 20));
|
||||
m_pci[i].base = memory::to_virtual<uint32_t>(mcfge.base);
|
||||
|
||||
log::debug(logs::device, " Found MCFG entry: base %lx group %d bus %d-%d",
|
||||
mcfge.base, mcfge.group, mcfge.bus_start, mcfge.bus_end);
|
||||
@@ -269,6 +295,29 @@ device_manager::load_mcfg(const acpi_mcfg *mcfg)
|
||||
probe_pci();
|
||||
}
|
||||
|
||||
void
|
||||
device_manager::load_hpet(const acpi_table_header *header)
|
||||
{
|
||||
const auto *hpet = check_get_table<acpi_hpet>(header);
|
||||
|
||||
log::debug(logs::device, " Found HPET device #%3d: base %016lx pmin %d attr %02x",
|
||||
hpet->index, hpet->base_address.address, hpet->periodic_min, hpet->attributes);
|
||||
|
||||
uint32_t hwid = hpet->hardware_id;
|
||||
uint8_t rev_id = hwid & 0xff;
|
||||
uint8_t comparators = (hwid >> 8) & 0x1f;
|
||||
uint8_t count_size_cap = (hwid >> 13) & 1;
|
||||
uint8_t legacy_replacement = (hwid >> 15) & 1;
|
||||
uint32_t pci_vendor_id = (hwid >> 16);
|
||||
|
||||
log::debug(logs::device, " rev:%02d comparators:%02d count_size_cap:%1d legacy_repl:%1d",
|
||||
rev_id, comparators, count_size_cap, legacy_replacement);
|
||||
log::debug(logs::device, " pci vendor id: %04x", pci_vendor_id);
|
||||
|
||||
m_hpets.emplace(hpet->index,
|
||||
reinterpret_cast<uint64_t*>(hpet->base_address.address + ::memory::page_offset));
|
||||
}
|
||||
|
||||
void
|
||||
device_manager::probe_pci()
|
||||
{
|
||||
@@ -291,6 +340,13 @@ device_manager::probe_pci()
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
fake_clock_source(void*)
|
||||
{
|
||||
static uint64_t value = 0;
|
||||
return value++;
|
||||
}
|
||||
|
||||
void
|
||||
device_manager::init_drivers()
|
||||
{
|
||||
@@ -309,11 +365,61 @@ device_manager::init_drivers()
|
||||
ahcid.register_device(&device);
|
||||
}
|
||||
*/
|
||||
clock *master_clock = nullptr;
|
||||
if (m_hpets.count() > 0) {
|
||||
hpet &h = m_hpets[0];
|
||||
h.enable();
|
||||
|
||||
// becomes the singleton
|
||||
master_clock = new clock(h.rate(), hpet_clock_source, &h);
|
||||
log::info(logs::clock, "Created master clock using HPET 0: Rate %d", h.rate());
|
||||
} else {
|
||||
//TODO: Other clocks, APIC clock?
|
||||
master_clock = new clock(5000, fake_clock_source, nullptr);
|
||||
}
|
||||
|
||||
kassert(master_clock, "Failed to allocate master clock");
|
||||
}
|
||||
|
||||
bool
|
||||
device_manager::dispatch_irq(unsigned irq)
|
||||
{
|
||||
if (irq >= m_irqs.count())
|
||||
return false;
|
||||
|
||||
endpoint *e = m_irqs[irq];
|
||||
if (!e || e == ignore_endpoint)
|
||||
return e == ignore_endpoint;
|
||||
|
||||
e->signal_irq(irq);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
device_manager::bind_irq(unsigned irq, endpoint *target)
|
||||
{
|
||||
// TODO: grow if under max size
|
||||
if (irq >= m_irqs.count())
|
||||
return false;
|
||||
|
||||
m_irqs[irq]= target;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
device_manager::unbind_irqs(endpoint *target)
|
||||
{
|
||||
const size_t count = m_irqs.count();
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
if (m_irqs[i] == target)
|
||||
m_irqs[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
device_manager::allocate_msi(const char *name, pci_device &device, irq_callback cb, void *data)
|
||||
{
|
||||
/*
|
||||
// TODO: find gaps to fill
|
||||
uint8_t irq = m_irqs.count();
|
||||
isr vector = isr::irq00 + irq;
|
||||
@@ -324,6 +430,7 @@ device_manager::allocate_msi(const char *name, pci_device &device, irq_callback
|
||||
device.write_msi_regs(
|
||||
0xFEE00000,
|
||||
static_cast<uint16_t>(vector));
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
/// The device manager definition
|
||||
#include "kutil/vector.h"
|
||||
#include "apic.h"
|
||||
#include "hpet.h"
|
||||
#include "pci.h"
|
||||
|
||||
struct acpi_xsdt;
|
||||
struct acpi_apic;
|
||||
struct acpi_mcfg;
|
||||
struct acpi_table_header;
|
||||
class block_device;
|
||||
class endpoint;
|
||||
|
||||
using irq_callback = void (*)(void *);
|
||||
|
||||
@@ -18,27 +18,35 @@ class device_manager
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
/// \arg root_table Pointer to the ACPI RSDP
|
||||
/// \arg alloc Allocator for device arrays
|
||||
device_manager(const void *root_table, kutil::allocator &alloc);
|
||||
device_manager();
|
||||
|
||||
/// Get the system global device manager.
|
||||
/// \returns A reference to the system device manager
|
||||
static device_manager & get() { return s_instance; }
|
||||
|
||||
/// Get the LAPIC
|
||||
/// \returns An object representing the local APIC
|
||||
lapic * get_lapic() { return m_lapic; }
|
||||
|
||||
/// Get an IOAPIC
|
||||
/// \arg i Index of the requested IOAPIC
|
||||
/// \returns An object representing the given IOAPIC if it exists,
|
||||
/// otherwise nullptr.
|
||||
ioapic * get_ioapic(int i);
|
||||
|
||||
/// Parse ACPI tables.
|
||||
/// \arg root_table Pointer to the ACPI RSDP
|
||||
void parse_acpi(const void *root_table);
|
||||
|
||||
/// Intialize drivers for the current device list.
|
||||
void init_drivers();
|
||||
|
||||
/// Bind an IRQ to an endpoint
|
||||
/// \arg irq The IRQ number to bind
|
||||
/// \arg target The endpoint to recieve messages when the IRQ is signalled
|
||||
/// \returns True on success
|
||||
bool bind_irq(unsigned irq, endpoint *target);
|
||||
|
||||
/// Remove IRQ bindings for an endpoint
|
||||
/// \arg target The endpoint to remove
|
||||
void unbind_irqs(endpoint *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
|
||||
@@ -54,17 +62,40 @@ public:
|
||||
/// Dispatch an IRQ interrupt
|
||||
/// \arg irq The irq number of the interrupt
|
||||
/// \returns True if the interrupt was handled
|
||||
inline bool dispatch_irq(uint8_t irq)
|
||||
bool dispatch_irq(unsigned irq);
|
||||
|
||||
struct apic_nmi
|
||||
{
|
||||
if (irq < m_irqs.count()) {
|
||||
irq_allocation &cba = m_irqs[irq];
|
||||
if (cba.callback) {
|
||||
cba.callback(cba.data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
uint8_t cpu;
|
||||
uint8_t lint;
|
||||
uint16_t flags;
|
||||
};
|
||||
|
||||
struct irq_override
|
||||
{
|
||||
uint8_t source;
|
||||
uint16_t flags;
|
||||
uint32_t gsi;
|
||||
};
|
||||
|
||||
/// Get the list of APIC ids for other CPUs
|
||||
inline const kutil::vector<uint8_t> & get_apic_ids() const { return m_apic_ids; }
|
||||
|
||||
/// Get the LAPIC base address
|
||||
/// \returns The physical base address of the local apic registers
|
||||
uintptr_t get_lapic_base() const { return m_lapic_base; }
|
||||
|
||||
/// Get the NMI mapping for the given local APIC
|
||||
/// \arg id ID of the local APIC
|
||||
/// \returns apic_nmi structure describing the NMI configuration,
|
||||
/// or null if no configuration was provided
|
||||
const apic_nmi * get_lapic_nmi(uint8_t id) const;
|
||||
|
||||
/// Get the IRQ source override for the given IRQ
|
||||
/// \arg irq IRQ number (not isr vector)
|
||||
/// \returns irq_override structure describing that IRQ's
|
||||
/// configuration, or null if no configuration was provided
|
||||
const irq_override * get_irq_override(uint8_t irq) const;
|
||||
|
||||
/// Register the existance of a block device.
|
||||
/// \arg blockdev Pointer to the block device
|
||||
@@ -83,18 +114,31 @@ public:
|
||||
m_blockdevs[i] : nullptr;
|
||||
}
|
||||
|
||||
/// Get an HPET device
|
||||
/// \arg i Index of the device to get
|
||||
/// \returns A pointer to the requested device, or nullptr
|
||||
inline hpet * get_hpet(unsigned i)
|
||||
{
|
||||
return i < m_hpets.count() ?
|
||||
&m_hpets[i] : nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Parse the ACPI XSDT and load relevant sub-tables.
|
||||
/// \arg xsdt Pointer to the XSDT from the firmware
|
||||
void load_xsdt(const acpi_xsdt *xsdt);
|
||||
void load_xsdt(const acpi_table_header *xsdt);
|
||||
|
||||
/// Parse the ACPI MADT and initialize APICs from it.
|
||||
/// \arg apic Pointer to the MADT from the XSDT
|
||||
void load_apic(const acpi_apic *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_mcfg *mcfg);
|
||||
void load_mcfg(const acpi_table_header *mcfg);
|
||||
|
||||
/// Parse the ACPI HPET and initialize an HPET from it.
|
||||
/// \arg hpet Pointer to the HPET from the XSDT
|
||||
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.
|
||||
@@ -104,25 +148,23 @@ private:
|
||||
/// that has no callback.
|
||||
void bad_irq(uint8_t irq);
|
||||
|
||||
lapic *m_lapic;
|
||||
uintptr_t m_lapic_base;
|
||||
|
||||
kutil::vector<ioapic> m_ioapics;
|
||||
kutil::vector<hpet> m_hpets;
|
||||
kutil::vector<uint8_t> m_apic_ids;
|
||||
kutil::vector<apic_nmi> m_nmis;
|
||||
kutil::vector<irq_override> m_overrides;
|
||||
|
||||
kutil::vector<pci_group> m_pci;
|
||||
kutil::vector<pci_device> m_devices;
|
||||
|
||||
struct irq_allocation
|
||||
{
|
||||
const char *name;
|
||||
irq_callback callback;
|
||||
void *data;
|
||||
};
|
||||
kutil::vector<irq_allocation> m_irqs;
|
||||
kutil::vector<endpoint*> m_irqs;
|
||||
|
||||
kutil::vector<block_device *> m_blockdevs;
|
||||
|
||||
static device_manager s_instance;
|
||||
|
||||
device_manager() = delete;
|
||||
device_manager(const device_manager &) = delete;
|
||||
device_manager operator=(const device_manager &) = delete;
|
||||
};
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#include "kutil/coord.h"
|
||||
#include "screen.h"
|
||||
|
||||
class font
|
||||
{
|
||||
public:
|
||||
font(void const *data);
|
||||
|
||||
unsigned glyph_bytes() const { return m_size.y * ((m_size.x + 7) / 8); }
|
||||
unsigned count() const { return m_count; }
|
||||
unsigned width() const { return m_size.x; }
|
||||
unsigned height() const { return m_size.y; }
|
||||
bool valid() const { return m_count > 0; }
|
||||
|
||||
void draw_glyph(
|
||||
screen *s,
|
||||
uint32_t glyph,
|
||||
screen::pixel_t fg,
|
||||
screen::pixel_t bg,
|
||||
unsigned x,
|
||||
unsigned y) const;
|
||||
|
||||
private:
|
||||
kutil::coord<unsigned> m_size;
|
||||
unsigned m_count;
|
||||
uint8_t const *m_data;
|
||||
|
||||
font() = delete;
|
||||
};
|
||||
|
||||
@@ -1,93 +1,163 @@
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/memory.h"
|
||||
|
||||
#include "frame_allocator.h"
|
||||
#include "kernel_args.h"
|
||||
#include "kernel_memory.h"
|
||||
#include "log.h"
|
||||
|
||||
using memory::frame_size;
|
||||
using memory::page_offset;
|
||||
using frame_block_node = kutil::list_node<frame_block>;
|
||||
|
||||
frame_allocator g_frame_allocator;
|
||||
|
||||
int
|
||||
frame_block::compare(const frame_block *rhs) const
|
||||
frame_allocator &
|
||||
frame_allocator::get()
|
||||
{
|
||||
if (address < rhs->address)
|
||||
return -1;
|
||||
else if (address > rhs->address)
|
||||
return 1;
|
||||
return 0;
|
||||
extern frame_allocator &g_frame_allocator;
|
||||
return g_frame_allocator;
|
||||
}
|
||||
|
||||
|
||||
frame_allocator::raw_alloc::raw_alloc(frame_allocator &fa) : m_fa(fa) {}
|
||||
|
||||
void *
|
||||
frame_allocator::raw_alloc::allocate(size_t size)
|
||||
frame_allocator::frame_allocator(kernel::args::frame_block *frames, size_t count) :
|
||||
m_blocks {frames},
|
||||
m_count {count}
|
||||
{
|
||||
kassert(size <= frame_size, "Raw allocator only allocates a single page");
|
||||
|
||||
uintptr_t addr = 0;
|
||||
if (size <= frame_size)
|
||||
m_fa.allocate(1, &addr);
|
||||
return reinterpret_cast<void*>(addr + page_offset);
|
||||
}
|
||||
|
||||
void
|
||||
frame_allocator::raw_alloc::free(void *p)
|
||||
{
|
||||
m_fa.free(reinterpret_cast<uintptr_t>(p), 1);
|
||||
}
|
||||
|
||||
|
||||
frame_allocator::frame_allocator() :
|
||||
m_raw_alloc(*this)
|
||||
inline unsigned
|
||||
bsf(uint64_t v)
|
||||
{
|
||||
asm ("tzcntq %q0, %q1" : "=r"(v) : "0"(v) : "cc");
|
||||
return v;
|
||||
}
|
||||
|
||||
size_t
|
||||
frame_allocator::allocate(size_t count, uintptr_t *address)
|
||||
{
|
||||
kassert(!m_free.empty(), "frame_allocator::pop_frames ran out of free frames!");
|
||||
if (m_free.empty())
|
||||
return 0;
|
||||
kutil::scoped_lock lock {m_lock};
|
||||
|
||||
auto *first = m_free.front();
|
||||
for (long i = m_count - 1; i >= 0; --i) {
|
||||
frame_block &block = m_blocks[i];
|
||||
|
||||
if (count >= first->count) {
|
||||
*address = first->address;
|
||||
m_free.remove(first);
|
||||
return first->count;
|
||||
} else {
|
||||
first->count -= count;
|
||||
*address = first->address + (first->count * frame_size);
|
||||
return count;
|
||||
if (!block.map1)
|
||||
continue;
|
||||
|
||||
// Tree walk to find the first available page
|
||||
unsigned o1 = bsf(block.map1);
|
||||
|
||||
uint64_t m2 = block.map2[o1];
|
||||
unsigned o2 = bsf(m2);
|
||||
|
||||
uint64_t m3 = block.bitmap[(o1 << 6) + o2];
|
||||
unsigned o3 = bsf(m3);
|
||||
|
||||
unsigned frame = (o1 << 12) + (o2 << 6) + o3;
|
||||
|
||||
// See how many contiguous pages are here
|
||||
unsigned n = bsf(~m3 >> o3);
|
||||
if (n > count)
|
||||
n = count;
|
||||
|
||||
*address = block.base + frame * frame_size;
|
||||
|
||||
// Clear the bits to mark these pages allocated
|
||||
m3 &= ~(((1 << n) - 1) << o3);
|
||||
block.bitmap[(o1 << 6) + o2] = m3;
|
||||
if (!m3) {
|
||||
// if that was it for this group, clear the next level bit
|
||||
m2 &= ~(1 << o2);
|
||||
block.map2[o1] = m2;
|
||||
|
||||
if (!m2) {
|
||||
// if that was cleared too, update the top level
|
||||
block.map1 &= ~(1 << o1);
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
inline uintptr_t end(frame_block *node) { return node->address + node->count * frame_size; }
|
||||
kassert(false, "frame_allocator ran out of free frames!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
frame_allocator::free(uintptr_t address, size_t count)
|
||||
{
|
||||
frame_block_node *node =
|
||||
reinterpret_cast<frame_block_node*>(address + page_offset);
|
||||
kutil::scoped_lock lock {m_lock};
|
||||
|
||||
kutil::memset(node, 0, sizeof(frame_block_node));
|
||||
node->address = address;
|
||||
node->count = count;
|
||||
kassert(address % frame_size == 0, "Trying to free a non page-aligned frame!");
|
||||
|
||||
m_free.sorted_insert(node);
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
frame_block_node *next = node->next();
|
||||
if (next && end(node) == next->address) {
|
||||
node->count += next->count;
|
||||
m_free.remove(next);
|
||||
}
|
||||
for (long i = 0; i < m_count; ++i) {
|
||||
frame_block &block = m_blocks[i];
|
||||
uintptr_t end = block.base + block.count * frame_size;
|
||||
|
||||
frame_block_node *prev = node->prev();
|
||||
if (prev && end(prev) == address) {
|
||||
prev->count += node->count;
|
||||
m_free.remove(node);
|
||||
if (address < block.base || address >= end)
|
||||
continue;
|
||||
|
||||
uint64_t frame = (address - block.base) >> 12;
|
||||
unsigned o1 = (frame >> 12) & 0x3f;
|
||||
unsigned o2 = (frame >> 6) & 0x3f;
|
||||
unsigned o3 = frame & 0x3f;
|
||||
|
||||
while (count--) {
|
||||
block.map1 |= (1 << o1);
|
||||
block.map2[o1] |= (1 << o2);
|
||||
block.bitmap[o2] |= (1 << o3);
|
||||
if (++o3 == 64) {
|
||||
o3 = 0;
|
||||
if (++o2 == 64) {
|
||||
o2 = 0;
|
||||
++o1;
|
||||
kassert(o1 < 64, "Tried to free pages past the end of a block");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
frame_allocator::used(uintptr_t address, size_t count)
|
||||
{
|
||||
kutil::scoped_lock lock {m_lock};
|
||||
|
||||
kassert(address % frame_size == 0, "Trying to mark a non page-aligned frame!");
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
for (long i = 0; i < m_count; ++i) {
|
||||
frame_block &block = m_blocks[i];
|
||||
uintptr_t end = block.base + block.count * frame_size;
|
||||
|
||||
if (address < block.base || address >= end)
|
||||
continue;
|
||||
|
||||
uint64_t frame = (address - block.base) >> 12;
|
||||
unsigned o1 = (frame >> 12) & 0x3f;
|
||||
unsigned o2 = (frame >> 6) & 0x3f;
|
||||
unsigned o3 = frame & 0x3f;
|
||||
|
||||
while (count--) {
|
||||
block.bitmap[o2] &= ~(1 << o3);
|
||||
if (!block.bitmap[o2]) {
|
||||
block.map2[o1] &= ~(1 << o2);
|
||||
|
||||
if (!block.map2[o1]) {
|
||||
block.map1 &= ~(1 << o1);
|
||||
}
|
||||
}
|
||||
|
||||
if (++o3 == 64) {
|
||||
o3 = 0;
|
||||
if (++o2 == 64) {
|
||||
o2 = 0;
|
||||
++o1;
|
||||
kassert(o1 < 64, "Tried to mark pages past the end of a block");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,19 +3,23 @@
|
||||
/// Allocator for physical memory frames
|
||||
|
||||
#include <stdint.h>
|
||||
#include "kutil/spinlock.h"
|
||||
|
||||
#include "kutil/allocator.h"
|
||||
#include "kutil/linked_list.h"
|
||||
|
||||
struct frame_block;
|
||||
using frame_block_list = kutil::linked_list<frame_block>;
|
||||
namespace kernel {
|
||||
namespace args {
|
||||
struct frame_block;
|
||||
}}
|
||||
|
||||
/// Allocator for physical memory frames
|
||||
class frame_allocator
|
||||
{
|
||||
public:
|
||||
/// Default constructor
|
||||
frame_allocator();
|
||||
using frame_block = kernel::args::frame_block;
|
||||
|
||||
/// Constructor
|
||||
/// \arg blocks The bootloader-supplied frame bitmap block list
|
||||
/// \arg count Number of entries in the block list
|
||||
frame_allocator(frame_block *frames, size_t count);
|
||||
|
||||
/// Get free frames from the free list. Only frames from the first free block
|
||||
/// are returned, so the number may be less than requested, but they will
|
||||
@@ -30,41 +34,20 @@ public:
|
||||
/// \arg count The number of frames to be freed
|
||||
void free(uintptr_t address, size_t count);
|
||||
|
||||
/// Get a memory allocator that allocates raw pages
|
||||
/// \returns The allocator ojbect
|
||||
kutil::allocator & raw_allocator() { return m_raw_alloc; }
|
||||
/// Mark frames as used
|
||||
/// \arg address The physical address of the first frame to free
|
||||
/// \arg count The number of frames to be freed
|
||||
void used(uintptr_t address, size_t count);
|
||||
|
||||
/// Get the global frame allocator
|
||||
static frame_allocator & get();
|
||||
|
||||
private:
|
||||
class raw_alloc :
|
||||
public kutil::allocator
|
||||
{
|
||||
public:
|
||||
raw_alloc(frame_allocator &fa);
|
||||
virtual void * allocate(size_t size) override;
|
||||
virtual void free(void *p) override;
|
||||
private:
|
||||
frame_allocator &m_fa;
|
||||
};
|
||||
frame_block *m_blocks;
|
||||
size_t m_count;
|
||||
|
||||
raw_alloc m_raw_alloc;
|
||||
frame_block_list m_free; ///< Free frames list
|
||||
kutil::spinlock m_lock;
|
||||
|
||||
frame_allocator() = delete;
|
||||
frame_allocator(const frame_allocator &) = delete;
|
||||
};
|
||||
|
||||
|
||||
/// A block of contiguous frames. Each `frame_block` represents contiguous
|
||||
/// physical frames with the same attributes.
|
||||
struct frame_block
|
||||
{
|
||||
uintptr_t address;
|
||||
uint32_t count;
|
||||
|
||||
/// Compare two blocks by address.
|
||||
/// \arg rhs The right-hand comparator
|
||||
/// \returns <0 if this is sorts earlier, >0 if this sorts later, 0 for equal
|
||||
int compare(const frame_block *rhs) const;
|
||||
};
|
||||
|
||||
|
||||
extern frame_allocator g_frame_allocator;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user