73 Commits
Author SHA1 Message Date
josh 4814b51daf Dump xHCI extended capabilities 2023-09-19 11:07:18 -04:00
josh 14bb3adf37 Document xHCI capability registers 2023-09-19 11:07:02 -04:00
josh cda45b205d Remove legacy PCI bus scanning 2023-09-17 16:13:37 -04:00
josh cfd42550fc Add struct definitions for all PCI header types 2023-09-17 15:22:58 -04:00
josh 673ce8f097 Scan PCI devices via MCFG table 2023-09-17 14:49:02 -04:00
josh ba0befa21b Check that needed ACPI tables are found 2023-09-17 13:40:26 -04:00
josh fa4de31aa4 Store pertinent ACPI table pointers 2023-09-17 11:22:58 -04:00
josh 3412d9ece9 Add Klog.fatal_error() 2023-09-17 11:15:02 -04:00
josh e8978c73f2 Move PCI initialization after ACPI/APIC/RTC 2023-09-17 11:00:48 -04:00
josh f79b0098c5 Map ACPI tables as disable cache + no execute 2023-09-17 09:12:20 -04:00
josh 10d7e7f0c6 Move parsing of ACPI tables into table structures
Move mapping ACPI table memory into common location
2023-09-17 09:08:01 -04:00
josh e088f942d1 Use Acpi.Header in ACPI table structures 2023-09-17 08:53:34 -04:00
josh 6514af8e94 Begin parsing MCFG ACPI table 2023-09-17 08:41:08 -04:00
josh 602a7525d2 Add %p format specifier for printing pointers 2023-09-16 17:09:55 -04:00
josh 617b861524 Size to hulk.elf.size 2023-09-15 13:38:25 -04:00
josh 2f968de7ed Disassemble to hulk.elf.txt 2023-09-15 13:37:48 -04:00
josh 68e85999fb Drop unused sections when linking HULK 2023-09-15 13:37:00 -04:00
josh 6b1445935c Update mk-vmdk task to have a file template since VBoxManage createmedium command was failing 2023-09-15 11:04:36 -04:00
josh 665d8aef80 Update qemu command to change machine to q35
This enables PCIe
2023-09-15 11:04:12 -04:00
josh af5ad73cf7 Update instructions for VirtualBox to change machine chipset
This enables PCIe
2023-09-15 11:03:39 -04:00
josh 4c67faaad4 Rework Kfont to store glyph top as offset from top of text row 2023-09-13 13:48:11 -04:00
josh 4fcea6a283 Reverse framebuffer vertical coordinates to start with 0 at top 2023-09-13 11:57:47 -04:00
josh c958b9ffcc Remove alpha-blending framebuffer functions 2023-09-13 10:57:45 -04:00
josh 3d911ab191 Adjust console text height by font baseline offset
This fixes having leftover pixels on screen bottom when scrolling the
console up.
2023-09-13 10:52:24 -04:00
josh d04c5444c7 fontgen: put character number before character data 2023-09-13 08:54:09 -04:00
josh 209658ee09 Use cache to mkdir_p for HulkBinObj builder 2023-09-10 09:48:07 -04:00
josh f3f45445b3 Determine XHCI controller addresses 2023-09-07 14:04:30 -04:00
josh 459d5c36aa Set alignment of XSDT table pointers to 4 instead of 8 2023-09-07 12:57:26 -04:00
josh 22c9891c4f Add page_address() 2023-09-07 12:51:41 -04:00
josh 2a832bfb8b Print progress messages for cross compiler toolchain installation 2023-09-06 22:58:18 -04:00
josh 496445e533 Fix linker script section placement 2023-09-06 16:40:17 -04:00
josh 156642293f Debug output HULK memory range end addresses 2023-09-04 21:20:10 -04:00
josh 4e46b98efc Capture QEMU serial port output 2023-09-04 21:13:35 -04:00
josh ce3e2c55df Store QEMU files in local qemu directory 2023-09-04 21:12:36 -04:00
josh cb24d00e5f Document running in QEMU in README 2023-09-04 21:04:30 -04:00
josh 4500f3cbca Write HELLO memory map debug data to serial port 2023-09-04 20:59:38 -04:00
josh 0781962e9f Rework HELLO console module to use hulk.writef 2023-09-04 16:17:47 -04:00
josh e25d28ebc7 Add serial module 2023-09-04 14:56:12 -04:00
josh 93a4065dea Add path to OVMF.fd for Arch 2023-09-04 14:07:05 -04:00
josh 5b017fb810 Add some xHCI register structures 2023-06-11 17:22:50 -04:00
josh 37814b4f86 Start on XHCI struct 2023-06-10 22:55:08 -04:00
josh 238659e94b Store PCI device mapped memory ranges 2023-06-10 22:22:09 -04:00
josh c16aa0e9c3 Add hulk.range 2023-06-10 22:21:55 -04:00
josh 2935903bae Map PCI device memory regions 2023-06-10 20:12:46 -04:00
josh 5179b5881b Read PCI device header type 2023-06-10 12:01:06 -04:00
josh a0c62937ff Remove Pci.init_device() for now 2023-06-10 11:28:51 -04:00
josh 657287c160 Move Pci.scan() recursion into scan() itself 2023-06-10 11:20:50 -04:00
josh d600e089e5 Add Pci.Device class 2023-06-10 11:16:27 -04:00
josh dd07a08388 Fix A1 allocator to map the correct pages 2023-06-10 11:06:41 -04:00
josh 63fbbc9051 Use ulong for round_up_power_2() 2023-06-10 10:59:46 -04:00
josh 3e32802862 Add A1.allocate() template to allocate struct/class instances 2023-06-10 10:30:56 -04:00
josh 40ff805f7d Add Pci.Address struct 2023-06-10 09:35:52 -04:00
josh 9ac69c9003 Add Pci.write_config_register() 2023-06-10 09:19:58 -04:00
josh 7aa28da1ef Allow pointers or integers for Hurl.*map_range() 2023-06-09 23:38:52 -04:00
josh 222a1efea4 Fix address calculation in Hurl.identity_map_range() 2023-06-09 23:27:20 -04:00
josh 7a4edf38f0 Scan for multi-function PCI devices 2023-06-08 20:28:32 -04:00
josh dda1b6379f Fix in32()/out32() to use uint instead of ulong 2023-06-08 16:07:44 -04:00
josh 98134957e7 Print APIC table signatures found 2023-06-08 13:21:43 -04:00
josh 22463e729b writef: add %c format specifier support 2023-06-08 13:21:24 -04:00
josh 8de86dd647 Add Pci.init_device() skeleton 2023-06-07 16:49:54 -04:00
josh f6fde01b06 Fix build error -- import hulk.util 2023-04-05 01:08:55 -04:00
josh ea6f485bd9 Add hulk.util and round_up_power_2() 2023-02-24 21:15:33 -05:00
josh 2ab388f2e9 Remove seconds counter printout 2023-02-24 20:58:11 -05:00
josh cc891f6d4d Assign PCI header fields to named variables 2023-02-24 20:53:46 -05:00
josh f5e5c40c12 Reduce Hurl.map() template overhead 2023-01-02 20:46:12 -05:00
josh 7b09c9beed Add A1 memory allocator 2023-01-01 22:02:48 -05:00
josh 103205bff2 Move address constants into Hurl struct 2023-01-01 21:04:29 -05:00
josh 25ee1775f0 Capitalize namespacing structs
This helps to avoid name clashes when breaking up modules into packages.
2023-01-01 17:34:41 -05:00
josh a423cdf1b1 Fix RTC clock reading in 24-hour mode 2022-12-19 11:32:08 -05:00
josh 7c8744d1e0 Read RTC date and time 2022-12-18 22:29:12 -05:00
josh 4081a220ef Route I/O APIC interrupts, enable RTC tick interrupt 2022-12-16 00:32:49 -05:00
josh 9adc248225 Initialize rtc module 2022-12-15 20:41:44 -05:00
josh 676fd17bf5 Add pit and rtc modules 2022-12-15 20:41:15 -05:00
32 changed files with 1406 additions and 453 deletions

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
.rscons* .rscons*
/x86_64-elf-gcc/ /x86_64-elf-gcc/
/build/ /build/
/qemu/
+12 -2
View File
@@ -17,6 +17,8 @@ the build command.
# Running HOS # Running HOS
HOS can run on a physical machine, in VirtualBox, or in QEMU.
## Physical Machine ## Physical Machine
To install HOS to an EFI partition, follow these steps: To install HOS to an EFI partition, follow these steps:
@@ -67,5 +69,13 @@ To create a VM in VirtualBox:
12. Move the HOS.vmdk file generated to the HOS VirtualBox folder. 12. Move the HOS.vmdk file generated to the HOS VirtualBox folder.
13. In VirtualBox Manager, open HOS VM settings. 13. In VirtualBox Manager, open HOS VM settings.
14. Under System, check the Enable EFI checkbox. 14. Under System, check the Enable EFI checkbox.
15. Under Storage, add a hard disk and browse to select the HOS.vmdk file. 15. Under System, change the Chipset to ICH9.
16. To run HOS, either start the VM through VirtualBox or with "./rscons run-vb". 16. Under Storage, add a hard disk and browse to select the HOS.vmdk file.
17. To run HOS, either start the VM through VirtualBox or with "./rscons run-vb".
## QEMU
Make sure QEMU is installed (possibly the `qemu-desktop` package). Then:
1. Build HOS ("./rscons").
2. Run `./rscons run` to run HOS in QEMU.
+52 -8
View File
@@ -26,7 +26,7 @@ MB = 1024 * 1024
class HulkBinObj < Builder class HulkBinObj < Builder
def run(options) def run(options)
FileUtils.mkdir_p(File.dirname(@target)) @cache.mkdir_p(File.dirname(@target))
File.write(@target, <<EOF) File.write(@target, <<EOF)
.section ".rodata" .section ".rodata"
.balign 4096 .balign 4096
@@ -136,7 +136,7 @@ hulk_env = env "hulk", use: %w[ldc2 x86_64-elf-gcc] do |env|
env["D_IMPORT_PATH"] += %w[src] env["D_IMPORT_PATH"] += %w[src]
env["D_IMPORT_PATH"] << env.expand("^/src") env["D_IMPORT_PATH"] << env.expand("^/src")
env["LD"] = "x86_64-elf-gcc" env["LD"] = "x86_64-elf-gcc"
env["LDFLAGS"] += %w[-nostdlib -Tsrc/hulk/hulk.ld -Wl,-Map,${_TARGET}.map] env["LDFLAGS"] += %w[-nostdlib -Tsrc/hulk/hulk.ld -Wl,--gc-sections -Wl,-Map,${_TARGET}.map]
env["LDCMD"] = %w[${LD} -o ${_TARGET} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}] env["LDCMD"] = %w[${LD} -o ${_TARGET} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}]
env["OBJDUMP"] = "x86_64-elf-objdump" env["OBJDUMP"] = "x86_64-elf-objdump"
env["OBJCOPY"] = "x86_64-elf-objcopy" env["OBJCOPY"] = "x86_64-elf-objcopy"
@@ -145,8 +145,8 @@ hulk_env = env "hulk", use: %w[ldc2 x86_64-elf-gcc] do |env|
env.CheckThreadLocal(:hulk_map_check, "^/hulk.elf.map") env.CheckThreadLocal(:hulk_map_check, "^/hulk.elf.map")
env.depends("^/hulk.elf", "src/hulk/hulk.ld") env.depends("^/hulk.elf", "src/hulk/hulk.ld")
env["SIZE"] = "x86_64-elf-size" env["SIZE"] = "x86_64-elf-size"
env.Size("^/hulk.size", "^/hulk.elf") env.Size("^/hulk.elf.size", "^/hulk.elf")
env.Disassemble("^/hulk.txt", "^/hulk.elf") env.Disassemble("^/hulk.elf.txt", "^/hulk.elf")
env.Command("^/hulk.bin", "^/hulk.elf", env.Command("^/hulk.bin", "^/hulk.elf",
"CMD" => %W[${OBJCOPY} -O binary ${_SOURCES} ${_TARGET}], "CMD" => %W[${OBJCOPY} -O binary ${_SOURCES} ${_TARGET}],
"CMD_DESC" => "Convert ELF to binary:") "CMD_DESC" => "Convert ELF to binary:")
@@ -162,6 +162,10 @@ hello_env = env "hello", use: %w[ldc2 x86_64-w64-mingw32-gcc] do |env|
env.add_builder(CheckThreadLocal) env.add_builder(CheckThreadLocal)
env.add_builder(HulkBinObj) env.add_builder(HulkBinObj)
env["sources"] = glob("src/hello/**/*.d") env["sources"] = glob("src/hello/**/*.d")
env["sources"] += %w[
src/hulk/serial.d
src/hulk/writef.d
]
env["sources"] += glob("uefi-d/source/**/*.d") env["sources"] += glob("uefi-d/source/**/*.d")
env.HulkBinObj("^/hulk_bin.S", hulk_env.expand("^/hulk.bin")) env.HulkBinObj("^/hulk_bin.S", hulk_env.expand("^/hulk.bin"))
env.Object("^/hulk_bin.o", "^/hulk_bin.S") env.Object("^/hulk_bin.o", "^/hulk_bin.S")
@@ -183,16 +187,56 @@ hello_env = env "hello", use: %w[ldc2 x86_64-w64-mingw32-gcc] do |env|
end end
task "run", desc: "Run HOS in QEMU" do task "run", desc: "Run HOS in QEMU" do
Dir.mktmpdir do |tmpdir| FileUtils.rm_rf("qemu")
FileUtils.mkdir_p("qemu")
img = hello_env.expand("^/HOS.img") img = hello_env.expand("^/HOS.img")
FileUtils.cp(img, tmpdir) FileUtils.cp(img, "qemu")
sh %W[qemu-system-x86_64 -cpu max -bios OVMF.fd -drive file=#{tmpdir}/HOS.img,format=raw -device qemu-xhci -device usb-tablet] ovmf = "OVMF.fd"
if File.exist?("/usr/share/edk2/x64/OVMF.fd")
ovmf = "/usr/share/edk2/x64/OVMF.fd"
end end
sh %W[
qemu-system-x86_64
-machine q35
-cpu max
-serial file:qemu/serial.out
-bios #{ovmf}
-drive file=qemu/HOS.img,format=raw
-device qemu-xhci
-device usb-tablet]
end end
# See README.md for how to set up VirtualBox for HOS. # See README.md for how to set up VirtualBox for HOS.
task "mk-vmdk", desc: "Create VirtualBox VMDK virtual drive for HOS" do task "mk-vmdk", desc: "Create VirtualBox VMDK virtual drive for HOS" do
sh %W[VBoxManage internalcommands createrawvmdk -filename HOS.vmdk -rawdisk #{File.expand_path(hello_env.expand("^/HOS.img"))}] path = File.expand_path(hello_env.expand("^/HOS.img"))
sectors = File.stat(path).size / 512
File.binwrite("HOS.vmdk", <<EOF)
# Disk DescriptorFile
version=1
CID=1d1c3615
parentCID=ffffffff
createType="fullDevice"
# Extent description
RW #{sectors} FLAT "#{path}" 0
# The disk Data Base
#DDB
ddb.virtualHWVersion = "4"
ddb.adapterType="ide"
ddb.geometry.cylinders="8"
ddb.geometry.heads="16"
ddb.geometry.sectors="63"
ddb.uuid.image="03783b5a-7587-4d8b-ad04-9d70f70a94c2"
ddb.uuid.parent="00000000-0000-0000-0000-000000000000"
ddb.uuid.modification="00000000-0000-0000-0000-000000000000"
ddb.uuid.parentmodification="00000000-0000-0000-0000-000000000000"
ddb.geometry.biosCylinders="8"
ddb.geometry.biosHeads="16"
ddb.geometry.biosSectors="63"
EOF
#sh %W[VBoxManage createmedium disk --filename=HOS.vmdk --variant=RawDisk --format=VMDK --property RawDrive=#{File.expand_path(hello_env.expand("^/HOS.img"))}]
end end
# See README.md for how to set up VirtualBox for HOS. # See README.md for how to set up VirtualBox for HOS.
+77 -15
View File
@@ -1,5 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include <ft2build.h> #include <ft2build.h>
#include <stdio.h> #include <stdio.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
@@ -86,35 +87,43 @@ static void generate_bytes(FILE * file, const uint8_t * bytes, int count)
} }
} }
static void generate(const char * d_file_name) static bool generate(const char * d_file_name)
{ {
FILE * fh = fopen(d_file_name, "wb"); FILE * fh = fopen(d_file_name, "wb");
fprintf(fh, "module hulk.kfont;\n"); fprintf(fh, "module hulk.kfont;\n");
fprintf(fh, "struct CharInfo {\n"); fprintf(fh, "struct CharInfo {\n");
fprintf(fh, " uint width;\n"); fprintf(fh, " /** Glyph bitmap width. */\n");
fprintf(fh, " uint height;\n"); fprintf(fh, " ubyte width;\n");
fprintf(fh, " int top;\n"); fprintf(fh, " /** Glyph bitmap height. */\n");
fprintf(fh, " int left;\n"); fprintf(fh, " ubyte height;\n");
fprintf(fh, " /** Glyph bitmap top offset (descent from top of text row). */\n");
fprintf(fh, " ubyte top;\n");
fprintf(fh, " /** Glyph bitmap left offset. */\n");
fprintf(fh, " ubyte left;\n");
fprintf(fh, " /** Glyph bitmap. */\n");
fprintf(fh, " const ubyte[] bitmap;\n"); fprintf(fh, " const ubyte[] bitmap;\n");
fprintf(fh, "};\n"); fprintf(fh, "};\n");
fprintf(fh, "struct FontInfo {\n"); fprintf(fh, "struct FontInfo {\n");
fprintf(fh, " uint line_height;\n"); fprintf(fh, " /** Font line height. */\n");
fprintf(fh, " uint advance;\n"); fprintf(fh, " ubyte line_height;\n");
fprintf(fh, " int baseline_offset;\n"); fprintf(fh, " /** Font advance. */\n");
fprintf(fh, " ubyte advance;\n");
fprintf(fh, " /** Characters. */\n");
fprintf(fh, " const CharInfo[] chars;\n"); fprintf(fh, " const CharInfo[] chars;\n");
fprintf(fh, "};\n"); fprintf(fh, "};\n");
fprintf(fh, "__gshared const FontInfo kfont = {\n"); fprintf(fh, "/** Kernel font data. */\n");
fprintf(fh, "__gshared const FontInfo Kfont = {\n");
fprintf(fh, " %du,\n", line_height); fprintf(fh, " %du,\n", line_height);
fprintf(fh, " %du,\n", max_advance); fprintf(fh, " %du,\n", max_advance);
fprintf(fh, " %d,\n", baseline_offset);
fprintf(fh, " [\n"); fprintf(fh, " [\n");
for (int i = 0; i < N_CHARS; i++) for (int i = 0; i < N_CHARS; i++)
{ {
fprintf(fh, " /* %d */", i);
fprintf(fh, " CharInfo(\n"); fprintf(fh, " CharInfo(\n");
fprintf(fh, " %du,\n", char_infos[i].width); fprintf(fh, " %du /* width */,\n", char_infos[i].width);
fprintf(fh, " %du,\n", char_infos[i].height); fprintf(fh, " %du /* height */,\n", char_infos[i].height);
fprintf(fh, " %d,\n", char_infos[i].top); fprintf(fh, " %du /* top */,\n", char_infos[i].top);
fprintf(fh, " %d,\n", char_infos[i].left); fprintf(fh, " %du /* left */,\n", char_infos[i].left);
if (char_infos[i].width > 0) if (char_infos[i].width > 0)
{ {
fprintf(fh, " [\n"); fprintf(fh, " [\n");
@@ -130,6 +139,7 @@ static void generate(const char * d_file_name)
fprintf(fh, " ],\n"); fprintf(fh, " ],\n");
fprintf(fh, "};\n"); fprintf(fh, "};\n");
fclose(fh); fclose(fh);
return true;
} }
int main(int argc, char * argv[]) int main(int argc, char * argv[])
@@ -167,7 +177,59 @@ int main(int argc, char * argv[])
line_height = round_up_26_6(face->size->metrics.height); line_height = round_up_26_6(face->size->metrics.height);
baseline_offset = (line_height - (max_top - min_bottom)) / 2 - min_bottom; baseline_offset = (line_height - (max_top - min_bottom)) / 2 - min_bottom;
generate(out_file); if ((line_height < 1) || (line_height > 0xFF))
{
fprintf(stderr, "Error: invalid line_height %d\n", line_height);
return false;
}
if ((max_advance < 1) || (max_advance > 0xFF))
{
fprintf(stderr, "Error: invalid max_advance %d\n", max_advance);
return false;
}
for (int i = 0; i < N_CHARS; i++)
{
if ((char_infos[i].width < 0) || (char_infos[i].width > max_advance))
{
fprintf(stderr, "Error: invalid character %d width: %d\n", i, char_infos[i].width);
return false;
}
if ((char_infos[i].height < 0) || (char_infos[i].height > line_height))
{
fprintf(stderr, "Error: invalid character %d height: %d\n", i, char_infos[i].height);
return false;
}
if ((char_infos[i].left < 0) || (char_infos[i].left >= max_advance))
{
fprintf(stderr, "Error: invalid character %d left: %d\n", i, char_infos[i].left);
return false;
}
/* Adjust character top to be index downward from top of font box. */
char_infos[i].top = line_height - baseline_offset - char_infos[i].top;
if ((char_infos[i].top < 0) || (char_infos[i].top >= line_height))
{
fprintf(stderr, "Error: invalid character %d top: %d\n", i, char_infos[i].top);
return false;
}
if ((char_infos[i].left + char_infos[i].width) > max_advance)
{
fprintf(stderr, "Error: character %d left (%d) + width (%d) > advance (%d)\n",
i, char_infos[i].left, char_infos[i].width, max_advance);
return false;
}
if ((char_infos[i].top + char_infos[i].height) > line_height)
{
fprintf(stderr, "Error: character %d top (%d) + height (%d) > line height (%d)\n",
i, char_infos[i].top, char_infos[i].height, line_height);
return false;
}
}
if (!generate(out_file))
{
return 1;
}
return 0; return 0;
} }
+29 -122
View File
@@ -6,155 +6,62 @@ module hello.console;
import uefi; import uefi;
import hello.hello; import hello.hello;
import core.stdc.stdarg; import core.stdc.stdarg;
import hulk.writef;
struct console struct Console
{ {
/** /**
* Format a hexadecimal value to a string. * Write a character to the console.
* *
* @param s String buffer. * @param ch Character to write.
* @param v Value to format.
* @param ptr If true, always output all 16 digits, and separate the upper and
* lower halves with an underscore.
*/ */
private static size_t format_hex(CHAR16 * s, ulong v, bool ptr) public static void write(ubyte ch)
{ {
string hex_chars = "0123456789ABCDEF"; if (ch == '\n')
bool print = ptr;
size_t si = 0u;
for (size_t i = 0u; i < 16u; i++)
{ {
if (ptr && (i == 8u)) write('\r');
{
s[si++] = '_';
} }
ulong n = (v >> (60u - 4u * i)) & 0xFu; CHAR16[2] s16 = [ch, 0];
if (n != 0u)
{
print = true;
}
if (print || (i == 15u))
{
s[si++] = hex_chars[n];
}
}
return si;
}
/**
* Format a decimal value to a string.
*
* @param s String buffer.
* @param v Value to format.
*/
private static size_t format_dec(CHAR16 * s, ulong v)
{
string dec_chars = "0123456789";
bool print;
char[20] buf;
size_t buf_i;
while ((buf_i == 0u) || (v != 0u))
{
ulong n = v % 10u;
buf[buf_i++] = dec_chars[n];
v /= 10u;
}
for (size_t si = 0u; si < buf_i; si++)
{
s[si] = buf[buf_i - si - 1u];
}
return buf_i;
}
/**
* Write a string to the console.
*
* @param s Format string.
* @param args Variable arguments structure.
*/
public static void write(string s, va_list args)
{
__gshared static CHAR16[256] s16;
size_t i = 0u;
bool escape = false;
foreach (char c; s)
{
if (escape)
{
if (c == '%')
{
s16[i++] = '%';
}
else if (c == 'x')
{
ulong v;
va_arg(args, v);
i += format_hex(&s16[i], v, false);
}
else if (c == 'p')
{
ulong v;
va_arg(args, v);
i += format_hex(&s16[i], v, true);
}
else if (c == 'S')
{
const(CHAR16) * s2;
va_arg(args, s2);
for (size_t s2_i = 0u; s2[s2_i] != 0; s2_i++)
{
s16[i++] = s2[s2_i];
}
}
else if (c == 'u')
{
ulong v;
va_arg(args, v);
i += format_dec(&s16[i], v);
}
else
{
s16[i++] = c;
}
escape = false;
}
else if (c == '%')
{
escape = true;
}
else
{
s16[i++] = c;
}
}
s16[i++] = 0u;
st.ConOut.OutputString(st.ConOut, &s16[0]); st.ConOut.OutputString(st.ConOut, &s16[0]);
} }
/** /**
* Write a string to the console. * Write a formatted string to the console.
*
* @param s Format string.
* @param args Variable arguments structure.
*/
public static void writef(string s, va_list args)
{
hulk.writef.writef(s, args, function void(ubyte ch) {
Console.write(ch);
});
}
/**
* Write a formatted string to the console.
* *
* @param s Format string. * @param s Format string.
*/ */
public static extern (C) void write(string s, ...) public static extern (C) void writef(string s, ...)
{ {
va_list args; va_list args;
va_start(args, s); va_start(args, s);
write(s, args); writef(s, args);
va_end(args); va_end(args);
} }
/** /**
* Write a string to the console. * Write a formatted string and newline to the console.
* *
* @param s Format string. * @param s Format string.
*/ */
public static extern (C) void writeln(string s, ...) public static extern (C) void writefln(string s, ...)
{ {
va_list args; va_list args;
va_start(args, s); va_start(args, s);
write(s, args); writef(s, args);
write("\r\n", args); writef("\n", args);
va_end(args); va_end(args);
} }
@@ -163,7 +70,7 @@ struct console
*/ */
public static void wait_key() public static void wait_key()
{ {
writeln("Press any key..."); writefln("Press any key...");
st.ConIn.Reset(st.ConIn, FALSE); st.ConIn.Reset(st.ConIn, FALSE);
EFI_INPUT_KEY key; EFI_INPUT_KEY key;
while (st.ConIn.ReadKeyStroke(st.ConIn, &key) == EFI_NOT_READY) while (st.ConIn.ReadKeyStroke(st.ConIn, &key) == EFI_NOT_READY)
+29 -14
View File
@@ -11,6 +11,7 @@ import hulk.pagetable;
import hulk.cpu; import hulk.cpu;
import hulk.memory; import hulk.memory;
import ldc.llvmasm; import ldc.llvmasm;
import hulk.serial;
__gshared EFI_SYSTEM_TABLE * st; __gshared EFI_SYSTEM_TABLE * st;
/** HULK binary start address, 4KB-aligned. */ /** HULK binary start address, 4KB-aligned. */
@@ -93,7 +94,7 @@ private bool set_graphics_mode()
&gop_guid, null, &buffer_size, handles); &gop_guid, null, &buffer_size, handles);
if (status != EFI_SUCCESS) if (status != EFI_SUCCESS)
{ {
console.writeln("LocateHandle: error %x", status); Console.writefln("LocateHandle: error %x", status);
return false; return false;
} }
EFI_HANDLE gop_handle = handles[0]; EFI_HANDLE gop_handle = handles[0];
@@ -102,12 +103,12 @@ private bool set_graphics_mode()
&gop_guid, &gop_interface); &gop_guid, &gop_interface);
if (status != EFI_SUCCESS) if (status != EFI_SUCCESS)
{ {
console.writeln("HandleProtocol: error %x", status); Console.writefln("HandleProtocol: error %x", status);
return false; return false;
} }
if (gop_interface == null) if (gop_interface == null)
{ {
console.writeln("null interface from HandleProtocol"); Console.writefln("null interface from HandleProtocol");
return false; return false;
} }
EFI_GRAPHICS_OUTPUT_PROTOCOL * gop = cast(EFI_GRAPHICS_OUTPUT_PROTOCOL *)gop_interface; EFI_GRAPHICS_OUTPUT_PROTOCOL * gop = cast(EFI_GRAPHICS_OUTPUT_PROTOCOL *)gop_interface;
@@ -129,7 +130,7 @@ private bool set_graphics_mode()
} }
if ((status = gop.SetMode(gop, best_mode_number)) != EFI_SUCCESS) if ((status = gop.SetMode(gop, best_mode_number)) != EFI_SUCCESS)
{ {
console.writeln("SetMode: Error %x\n", status); Console.writefln("SetMode: Error %x\n", status);
return false; return false;
} }
bootinfo().fb.buffer = cast(uint *)gop.Mode.FrameBufferBase; bootinfo().fb.buffer = cast(uint *)gop.Mode.FrameBufferBase;
@@ -174,7 +175,7 @@ private void get_memory_map(ulong * physical_address_limit, UINTN * memory_map_k
&descriptor_version); &descriptor_version);
if (status != EFI_SUCCESS) if (status != EFI_SUCCESS)
{ {
console.writeln("GetMemoryMap: Error %x", status); Console.writefln("GetMemoryMap: Error %x", status);
for (;;) {} for (;;) {}
} }
size_t n_entries = memory_map_size / descriptor_size; size_t n_entries = memory_map_size / descriptor_size;
@@ -187,7 +188,7 @@ private void get_memory_map(ulong * physical_address_limit, UINTN * memory_map_k
{ {
if (count > bootinfo().memory_map.length) if (count > bootinfo().memory_map.length)
{ {
console.writeln("Memory map too large"); Console.writefln("Memory map too large");
for (;;) {} for (;;) {}
} }
EFI_MEMORY_DESCRIPTOR * descriptor = cast(EFI_MEMORY_DESCRIPTOR *)&scratch_base[count * descriptor_size]; EFI_MEMORY_DESCRIPTOR * descriptor = cast(EFI_MEMORY_DESCRIPTOR *)&scratch_base[count * descriptor_size];
@@ -205,6 +206,7 @@ private void get_memory_map(ulong * physical_address_limit, UINTN * memory_map_k
} }
if (descriptor.Type >= efi_to_hulk_memory_map_type.length) if (descriptor.Type >= efi_to_hulk_memory_map_type.length)
{ {
Serial.writefln("Unexpected descriptor type %u", descriptor.Type);
continue; continue;
} }
bootinfo().memory_map[count].base = descriptor.PhysicalStart; bootinfo().memory_map[count].base = descriptor.PhysicalStart;
@@ -217,6 +219,9 @@ private void get_memory_map(ulong * physical_address_limit, UINTN * memory_map_k
bootinfo().bss_phys = bootinfo().memory_map[count].base; bootinfo().bss_phys = bootinfo().memory_map[count].base;
bootinfo().memory_map[count].base += hulk_bss_size(); bootinfo().memory_map[count].base += hulk_bss_size();
bootinfo().memory_map[count].size -= hulk_bss_size(); bootinfo().memory_map[count].size -= hulk_bss_size();
Serial.writefln("Locating HULK BSS at %x:%x",
bootinfo().bss_phys,
bootinfo().bss_phys + hulk_bss_size() - 1u);
found_bss = true; found_bss = true;
} }
if ((!found_stack) && if ((!found_stack) &&
@@ -226,6 +231,9 @@ private void get_memory_map(ulong * physical_address_limit, UINTN * memory_map_k
bootinfo().stack_phys = bootinfo().memory_map[count].base; bootinfo().stack_phys = bootinfo().memory_map[count].base;
bootinfo().memory_map[count].base += hulk_stack_size(); bootinfo().memory_map[count].base += hulk_stack_size();
bootinfo().memory_map[count].size -= hulk_stack_size(); bootinfo().memory_map[count].size -= hulk_stack_size();
Serial.writefln("Locating HULK stack at %x:%x",
bootinfo().stack_phys,
bootinfo().stack_phys + hulk_stack_size() - 1u);
found_stack = true; found_stack = true;
} }
if ((!found_fb_buffer1) && if ((!found_fb_buffer1) &&
@@ -235,8 +243,15 @@ private void get_memory_map(ulong * physical_address_limit, UINTN * memory_map_k
bootinfo().fb_buffer1_phys = bootinfo().memory_map[count].base; bootinfo().fb_buffer1_phys = bootinfo().memory_map[count].base;
bootinfo().memory_map[count].base += fb_size; bootinfo().memory_map[count].base += fb_size;
bootinfo().memory_map[count].size -= fb_size; bootinfo().memory_map[count].size -= fb_size;
Serial.writefln("Locating HULK FB1 at %x:%x",
bootinfo().fb_buffer1_phys,
bootinfo().fb_buffer1_phys + fb_size - 1u);
found_fb_buffer1 = true; found_fb_buffer1 = true;
} }
Serial.writefln("Memory range %x:%x (%u)",
bootinfo().memory_map[count].base,
bootinfo().memory_map[count].base + bootinfo().memory_map[count].size - 1u,
bootinfo().memory_map[count].type);
} }
bootinfo().memory_map_count = count; bootinfo().memory_map_count = count;
if ((!found_bss) || (!found_stack) || (!found_fb_buffer1)) if ((!found_bss) || (!found_stack) || (!found_fb_buffer1))
@@ -511,21 +526,21 @@ extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st)
{ {
.st = st; .st = st;
console.clear(); Console.clear();
console.writeln("Welcome to HELLO, HOS EFI Lightweight LOader, v0.1.0"); Console.writefln("Welcome to HELLO, HOS EFI Lightweight LOader, v0.1.0");
console.writeln("Firmware vendor: '%S', version: 0x%x", st.FirmwareVendor, st.FirmwareVendor); Console.writefln("Firmware vendor: '%S', version: 0x%x", st.FirmwareVendor, st.FirmwareVendor);
if (!find_acpi_xsdt()) if (!find_acpi_xsdt())
{ {
console.writeln("Error: Could not locate ACPI XSDT"); Console.writefln("Error: Could not locate ACPI XSDT");
console.wait_key(); Console.wait_key();
return EFI_SUCCESS; return EFI_SUCCESS;
} }
if (!set_graphics_mode()) if (!set_graphics_mode())
{ {
console.wait_key(); Console.wait_key();
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@@ -544,8 +559,8 @@ extern (C) EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * st)
{ {
break; break;
} }
console.writeln("ExitBootServices: Error %x", status); Console.writefln("ExitBootServices: Error %x", status);
console.wait_key(); Console.wait_key();
return EFI_SUCCESS; return EFI_SUCCESS;
} }
+112 -48
View File
@@ -7,12 +7,18 @@ import hulk.hurl;
import hulk.klog; import hulk.klog;
import hulk.memory; import hulk.memory;
struct acpi struct Acpi
{ {
enum uint APIC_SIGNATURE = 0x43495041u; private static uint signature(string s)
enum uint XSDT_SIGNATURE = 0x54445358u; {
return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
}
static struct XsdtHeader enum uint APIC_SIGNATURE = signature("APIC");
enum uint MCFG_SIGNATURE = signature("MCFG");
enum uint XSDT_SIGNATURE = signature("XSDT");
static align(4) struct Header
{ {
uint signature; uint signature;
uint length; uint length;
@@ -25,78 +31,136 @@ struct acpi
uint creator_revision; uint creator_revision;
} }
static struct Xsdt static struct XSDT
{ {
XsdtHeader header; Header header;
uint _pad; /* Table pointers are not ulong-aligned! They begin at offset 36. */
ulong[0] tables; align(4) ulong[1] tables;
} }
static struct MadtHeader static struct MADT
{ {
uint signature; static struct Entry
uint length; {
ubyte revision; enum LOCAL_APIC_ADDRESS_OVERRIDE = 5;
ubyte checksum;
char[6] oemid;
ulong oemtableid;
uint oem_revision;
uint creator_id;
uint creator_revision;
uint local_apic_address;
uint flags;
}
static struct MadtEntry
{
ubyte type; ubyte type;
ubyte length; ubyte length;
} }
public static __gshared ulong apic_address; Header header;
uint local_apic_address;
uint flags;
void initialize()
{
apic_address = local_apic_address;
Klog.writefln("Found 32-bit APIC address: 0x%x", apic_address);
const(void) * end = cast(const(void) *)(&this) + header.length;
const(Entry) * entry = cast(const(Entry) *)(cast(ulong)&this + MADT.sizeof);
while (entry < end)
{
entry = cast(const(Entry) *)(cast(size_t)entry + entry.length);
if (entry.type == Entry.LOCAL_APIC_ADDRESS_OVERRIDE)
{
/* Found a 64-bit Local APIC Address Override entry. */
Klog.writefln("Found 64-bit APIC address: 0x%x", apic_address);
memcpy(cast(void *)&apic_address, cast(const(void) *)entry + 4u, apic_address.sizeof);
}
}
}
}
static struct MCFG
{
/* PCI Segment Group Memory Area Descriptor. */
static struct SGMADesc
{
uint[2] base_address_a;
ushort pci_segment_group_number;
ubyte start_pci_bus_number;
ubyte end_pci_bus_number;
uint _reserved;
public @property ulong base_address() const
{
return base_address_a[0] | (cast(ulong)base_address_a[1] << 32);
}
}
static assert(SGMADesc.sizeof == 16);
static assert(SGMADesc.alignof == 4);
Header header;
uint[2] _reserved;
SGMADesc[0] sgma_descs;
size_t n_sgma_descs()
{
return (header.length - MCFG.sgma_descs.offsetof) / MCFG.SGMADesc.sizeof;
}
}
public __gshared ulong apic_address;
public __gshared MADT * madt;
public __gshared MCFG * mcfg;
public static void initialize(ulong acpi_xsdt_phys) public static void initialize(ulong acpi_xsdt_phys)
{ {
/* Map the XSDT header. */ /* Map the XSDT header. */
hurl.identity_map_range(acpi_xsdt_phys, Xsdt.sizeof, 0u); map_table(acpi_xsdt_phys, PAGE_SIZE);
const(Xsdt) * xsdt = cast(const(Xsdt) *)acpi_xsdt_phys; const(XSDT) * xsdt = cast(const(XSDT) *)acpi_xsdt_phys;
if (xsdt.header.signature != XSDT_SIGNATURE) if (xsdt.header.signature != XSDT_SIGNATURE)
{ {
klog.writef("XSDT signature invalid\n"); Klog.fatal_error("XSDT signature invalid");
return; return;
} }
/* Map the entire XSDT. */ /* Map the entire XSDT. */
hurl.identity_map_range(acpi_xsdt_phys, xsdt.header.length, 0u); if (xsdt.header.length > PAGE_SIZE)
{
map_table(acpi_xsdt_phys, xsdt.header.length);
}
size_t n_entries = (xsdt.header.length - xsdt.header.sizeof) / xsdt.tables[0].sizeof; size_t n_entries = (xsdt.header.length - xsdt.header.sizeof) / xsdt.tables[0].sizeof;
for (size_t i = 0u; i < n_entries; i++) for (size_t i = 0u; i < n_entries; i++)
{ {
ulong address = xsdt.tables[i]; ulong address = xsdt.tables[i];
hurl.identity_map_range(address, 4u, 0u); map_table(address, PAGE_SIZE);
uint signature = *cast(const(uint) *)address; const(Header) * header = cast(const(Header) *)address;
uint length = header.length;
if (length > PAGE_SIZE)
{
map_table(address, length);
}
uint signature = header.signature;
Klog.writefln("Found ACPI table %08x (%c%c%c%c)",
signature,
signature & 0xFFu,
(signature >> 8u) & 0xFFu,
(signature >> 16u) & 0xFFu,
(signature >> 24u) & 0xFFu);
if (signature == APIC_SIGNATURE) if (signature == APIC_SIGNATURE)
{ {
parse_apic_table(address); madt = cast(MADT *)address;
madt.initialize();
} }
else if (signature == MCFG_SIGNATURE)
{
mcfg = cast(MCFG *)address;
}
}
if (madt == null)
{
Klog.fatal_error("MADT table not found");
}
if (mcfg == null)
{
Klog.fatal_error("MCFG table not found");
} }
} }
private static parse_apic_table(ulong address) private static void map_table(ulong address, ulong length)
{ {
const(MadtHeader) * madt_header = cast(const(MadtHeader) *)address; Hurl.identity_map_range(address, length, PT_WRITABLE | PT_DISABLE_CACHE | PT_NO_EXECUTE);
hurl.identity_map_range(address, madt_header.length, 0u);
apic_address = madt_header.local_apic_address;
klog.writefln("Found 32-bit APIC address: 0x%x", apic_address);
const(void) * madt_end = cast(const(void) *)(address + madt_header.length);
const(MadtEntry) * madt_entry = cast(const(MadtEntry) *)(address + 0x2Cu);
while (madt_entry < madt_end)
{
madt_entry = cast(const(MadtEntry) *)(cast(size_t)madt_entry + madt_entry.length);
if (madt_entry.type == 5u)
{
/* Found a 64-bit Local APIC Address Override entry. */
memcpy(cast(void *)&apic_address, cast(const(void) *)madt_entry + 4u, 8u);
klog.writefln("Found 64-bit APIC address: 0x%x", apic_address);
}
}
} }
} }
+24 -14
View File
@@ -7,11 +7,14 @@ import hulk.klog;
import hulk.hurl; import hulk.hurl;
import hulk.acpi; import hulk.acpi;
import hulk.idt; import hulk.idt;
import hulk.rtc;
struct apic struct Apic
{ {
private enum uint PERIODIC_MODE = 0x2_0000u; private enum uint PERIODIC_MODE = 0x2_0000u;
private enum ulong IRQ_RTC = 8u;
static struct ApicRegister static struct ApicRegister
{ {
public uint value; public uint value;
@@ -63,23 +66,22 @@ struct apic
public static void initialize() public static void initialize()
{ {
apic_registers = cast(ApicRegisters *)acpi.apic_address; apic_registers = cast(ApicRegisters *)Acpi.apic_address;
io_apic_registers = cast(IoApicRegisters *)0xFEC0_0000u; io_apic_registers = cast(IoApicRegisters *)0xFEC0_0000u;
hurl.map(cast(ulong)apic_registers, cast(ulong)apic_registers, Hurl.map(cast(ulong)apic_registers, cast(ulong)apic_registers,
PT_WRITABLE | PT_WRITE_THROUGH | PT_DISABLE_CACHE | PT_NO_EXECUTE); PT_WRITABLE | PT_WRITE_THROUGH | PT_DISABLE_CACHE | PT_NO_EXECUTE);
hurl.map(cast(ulong)io_apic_registers, cast(ulong)io_apic_registers, Hurl.map(cast(ulong)io_apic_registers, cast(ulong)io_apic_registers,
PT_WRITABLE | PT_WRITE_THROUGH | PT_DISABLE_CACHE | PT_NO_EXECUTE); PT_WRITABLE | PT_WRITE_THROUGH | PT_DISABLE_CACHE | PT_NO_EXECUTE);
klog.writefln("LAPIC ID: 0x%08x", apic_registers.lapic_id.value); Klog.writefln("LAPIC ID: 0x%08x", apic_registers.lapic_id.value);
klog.writefln("LAPIC version: 0x%08x", apic_registers.lapic_version.value); Klog.writefln("LAPIC version: 0x%08x", apic_registers.lapic_version.value);
/* Enable local APIC to receive interrupts and set spurious interrupt /* Enable local APIC to receive interrupts and set spurious interrupt
* vector to 0xFF. */ * vector to 0xFF. */
apic_registers.spurious_interrupt_vector.value = 0x1FFu; apic_registers.spurious_interrupt_vector.value = 0x100u | Idt.INT_APIC_SPURIOUS;
// apic_registers.lvt_timer.value = idt.INT_LAPIC_TIMER | PERIODIC_MODE; apic_registers.lvt_timer.value = Idt.INT_APIC_TIMER;
apic_registers.lvt_timer.value = idt.INT_LAPIC_TIMER; apic_registers.lvt_lint[0].value = Idt.INT_APIC_LINT0;
apic_registers.lvt_lint[0].value = idt.INT_LAPIC_LINT0; apic_registers.lvt_lint[1].value = Idt.INT_APIC_LINT1;
apic_registers.lvt_lint[1].value = idt.INT_LAPIC_LINT1; /* Enable RTC interrupt. */
// apic_registers.divide_configuration.value = 3u; configure_io_apic_irq(IRQ_RTC, Idt.INT_APIC_BASE + IRQ_RTC);
configure_io_apic_irq(8u, 0x48u);
} }
private static void configure_io_apic_irq(size_t io_apic_irq, size_t interrupt_id) private static void configure_io_apic_irq(size_t io_apic_irq, size_t interrupt_id)
@@ -98,7 +100,15 @@ struct apic
public static void isr(ulong vector) public static void isr(ulong vector)
{ {
klog.writefln("APIC ISR 0x%x", vector); switch (vector)
{
case Idt.INT_APIC_BASE + IRQ_RTC:
Rtc.isr();
break;
default:
break;
}
eoi(); eoi();
} }
} }
+17 -12
View File
@@ -6,7 +6,12 @@ module hulk.console;
import hulk.fb; import hulk.fb;
import hulk.kfont; import hulk.kfont;
struct console /**
* Represent the HULK console.
*
* Coordinate (0,0) is the top-left console position.
*/
struct Console
{ {
/** Console width in text columns. */ /** Console width in text columns. */
private static __gshared size_t m_width; private static __gshared size_t m_width;
@@ -25,8 +30,8 @@ struct console
*/ */
public static void initialize() public static void initialize()
{ {
m_width = fb.width / kfont.advance; m_width = Fb.width / Kfont.advance;
m_height = fb.height / kfont.line_height; m_height = Fb.height / Kfont.line_height;
} }
/** /**
@@ -34,7 +39,7 @@ struct console
*/ */
public static void clear() public static void clear()
{ {
fb.clear(); Fb.clear();
m_x = 0u; m_x = 0u;
m_y = 0u; m_y = 0u;
} }
@@ -64,10 +69,10 @@ struct console
if (m_y == m_height) if (m_y == m_height)
{ {
m_y--; m_y--;
fb.copy_rows_up(fb_y(m_height - 1u), Fb.copy_rows_up(fb_y(1u),
(m_height - 1u) * kfont.line_height, (m_height - 1u) * Kfont.line_height,
kfont.line_height); Kfont.line_height);
fb.rect(0u, fb_y(m_height - 1u), fb_x(m_width), kfont.line_height, 0u); Fb.rect(0u, fb_y(m_height - 1u), fb_x(m_width), Kfont.line_height, 0u);
} }
} }
@@ -80,8 +85,8 @@ struct console
*/ */
private static void render_char(size_t x, size_t y, char ch) private static void render_char(size_t x, size_t y, char ch)
{ {
const(CharInfo) * ci = &kfont.chars[ch]; const(CharInfo) * ci = &Kfont.chars[ch];
fb.blit_alpha_bitmap(fb_x(x) + ci.left, fb_y(y) + ci.top - ci.height, ci.bitmap, ci.width, ci.height); Fb.blit_alpha_bitmap(fb_x(x) + ci.left, fb_y(y) + ci.top, ci.bitmap, ci.width, ci.height);
} }
/** /**
@@ -89,7 +94,7 @@ struct console
*/ */
private static size_t fb_x(size_t x) private static size_t fb_x(size_t x)
{ {
return x * kfont.advance; return x * Kfont.advance;
} }
/** /**
@@ -97,6 +102,6 @@ struct console
*/ */
private static size_t fb_y(size_t y) private static size_t fb_y(size_t y)
{ {
return fb.height - ((y + 1u) * kfont.line_height); return y * Kfont.line_height;
} }
} }
+3 -3
View File
@@ -221,9 +221,9 @@ ushort in16(ushort ioaddr)
return __asm!ushort("inw %dx, %ax", "={ax},{dx}", ioaddr); return __asm!ushort("inw %dx, %ax", "={ax},{dx}", ioaddr);
} }
ulong in32(ushort ioaddr) uint in32(ushort ioaddr)
{ {
return __asm!ulong("inl %dx, %eax", "={eax},{dx}", ioaddr); return __asm!uint("inl %dx, %eax", "={eax},{dx}", ioaddr);
} }
void out8(ushort ioaddr, ubyte v) void out8(ushort ioaddr, ubyte v)
@@ -236,7 +236,7 @@ void out16(ushort ioaddr, ushort v)
__asm("outw %ax, %dx", "{dx},{ax}", ioaddr, v); __asm("outw %ax, %dx", "{dx},{ax}", ioaddr, v);
} }
void out32(ushort ioaddr, ulong v) void out32(ushort ioaddr, uint v)
{ {
__asm("outl %eax, %dx", "{dx},{eax}", ioaddr, v); __asm("outl %eax, %dx", "{dx},{eax}", ioaddr, v);
} }
+17 -95
View File
@@ -9,9 +9,11 @@ import hulk.kfont;
/** /**
* Represent a graphical frame buffer. * Represent a graphical frame buffer.
* *
* Coordinate (0,0) is the top-left corner of the framebuffer.
*
* TODO: Handle other pixel formats. Currently only BGRx is supported. * TODO: Handle other pixel formats. Currently only BGRx is supported.
*/ */
struct fb struct Fb
{ {
/** Device frame buffer base address. */ /** Device frame buffer base address. */
private __gshared static uint * m_device_buffer; private __gshared static uint * m_device_buffer;
@@ -80,8 +82,8 @@ struct fb
/** /**
* Draw a solid rectangle on the framebuffer. * Draw a solid rectangle on the framebuffer.
* *
* @param x X coordinate of left side of rectangle. * @param x X coordinate of left of rectangle.
* @param y Y coordinate of bottom side of rectangle. * @param y Y coordinate of top of rectangle.
* @param width Width of rectangle. * @param width Width of rectangle.
* @param height Height of rectangle. * @param height Height of rectangle.
* @param color Color of rectangle. * @param color Color of rectangle.
@@ -100,7 +102,7 @@ struct fb
/** /**
* Draw a horizontal line. * Draw a horizontal line.
* *
* @param x X coordinate of left side of line. * @param x X coordinate of left of line.
* @param y Y coordinate of line. * @param y Y coordinate of line.
* @param width Width of line. * @param width Width of line.
* @param color Color of line. * @param color Color of line.
@@ -116,7 +118,7 @@ struct fb
* Draw a vertical line. * Draw a vertical line.
* *
* @param x X coordinate of line. * @param x X coordinate of line.
* @param y Y coordinate of bottom of line. * @param y Y coordinate of top of line.
* @param height Height of line. * @param height Height of line.
* @param color Color of line. * @param color Color of line.
*/ */
@@ -127,81 +129,17 @@ struct fb
{ {
m_buffer1[buffer_index] = color; m_buffer1[buffer_index] = color;
m_device_buffer[buffer_index] = color; m_device_buffer[buffer_index] = color;
buffer_index -= m_stride; buffer_index += m_stride;
} }
} }
/**
* Draw a character.
*
* @param x X coordinate of left side of character.
* @param y Y coordinate of bottom side of character.
* @param ch Character to draw.
* @param color Color of character.
*/
static void character(int x, int y, char ch, uint color)
{
const(CharInfo) * ci = &kfont.chars[ch];
blend_alpha_bitmap(x + ci.left, y + kfont.baseline_offset + ci.top - ci.height, ci.bitmap, ci.width, ci.height, color);
}
/**
* Blend an 8-bit alpha bitmap to the framebuffer.
*
* @param x X coordinate of left side of target location.
* @param y Y coordinate of bottom side of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
* @param color Color to blend with alpha value.
*/
static void blend_alpha_bitmap(size_t x, size_t y, const(ubyte) * alpha_bitmap,
size_t width, size_t height, uint color)
{
y += height - 1u;
size_t bitmap_index;
for (size_t iy = 0u; iy < height; iy++)
{
size_t row_buffer_index = buffer_index(x, y);
for (size_t ix = 0u; ix < width; ix++)
{
size_t buffer_index = row_buffer_index + ix;
ubyte alpha = alpha_bitmap[bitmap_index];
uint current_color = m_buffer1[buffer_index];
uint in_color_scaled = scale_color(color, alpha);
uint old_color_scaled = scale_color(current_color, 255u - alpha);
uint new_color = old_color_scaled + in_color_scaled;
m_buffer1[buffer_index] = new_color;
bitmap_index++;
}
memcpy32(&m_device_buffer[row_buffer_index], &m_buffer1[row_buffer_index], width);
y--;
}
}
/**
* Blend an 8-bit alpha bitmap to the framebuffer.
*
* @param x X coordinate of left side of target location.
* @param y Y coordinate of bottom side of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
* @param color Color to blend with alpha value.
*/
static void blend_alpha_bitmap(size_t x, size_t y, const(ubyte)[] alpha_bitmap,
size_t width, size_t height, uint color)
{
blend_alpha_bitmap(x, y, alpha_bitmap.ptr, width, height, color);
}
/** /**
* Blit an 8-bit alpha bitmap to the framebuffer. * Blit an 8-bit alpha bitmap to the framebuffer.
* The foreground will be white (based on the alpha value), and the * The foreground will be white (based on the alpha value), and the
* background black. * background black.
* *
* @param x X coordinate of left side of target location. * @param x X coordinate of left of target location.
* @param y Y coordinate of bottom side of target location. * @param y Y coordinate of top of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap. * @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width. * @param width Bitmap width.
* @param height Bitmap height. * @param height Bitmap height.
@@ -209,7 +147,6 @@ struct fb
static void blit_alpha_bitmap(size_t x, size_t y, const(ubyte) * alpha_bitmap, static void blit_alpha_bitmap(size_t x, size_t y, const(ubyte) * alpha_bitmap,
size_t width, size_t height) size_t width, size_t height)
{ {
y += height - 1u;
size_t bitmap_index; size_t bitmap_index;
for (size_t iy = 0u; iy < height; iy++) for (size_t iy = 0u; iy < height; iy++)
{ {
@@ -222,7 +159,7 @@ struct fb
bitmap_index++; bitmap_index++;
} }
memcpy32(&m_device_buffer[row_buffer_index], &m_buffer1[row_buffer_index], width); memcpy32(&m_device_buffer[row_buffer_index], &m_buffer1[row_buffer_index], width);
y--; y++;
} }
} }
@@ -231,8 +168,8 @@ struct fb
* The foreground will be white (based on the alpha value), and the * The foreground will be white (based on the alpha value), and the
* background black. * background black.
* *
* @param x X coordinate of left side of target location. * @param x X coordinate of left of target location.
* @param y Y coordinate of bottom side of target location. * @param y Y coordinate of top of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap. * @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width. * @param width Bitmap width.
* @param height Bitmap height. * @param height Bitmap height.
@@ -246,14 +183,14 @@ struct fb
/** /**
* Copy framebuffer rows up in the framebuffer. * Copy framebuffer rows up in the framebuffer.
* *
* @param y Y coordinate of bottom side of region to copy up. * @param y Y coordinate of top of region to copy up.
* @param height Height of region to copy up. * @param height Height of region to copy up.
* @param offset Number of rows to copy region up by. * @param offset Number of rows to copy region up by.
*/ */
static void copy_rows_up(size_t y, size_t height, size_t offset) static void copy_rows_up(size_t y, size_t height, size_t offset)
{ {
size_t dest_buffer_index = buffer_index(0u, y + height + offset - 1u); size_t dest_buffer_index = buffer_index(0u, y - offset);
size_t src_buffer_index = buffer_index(0u, y + height - 1u); size_t src_buffer_index = buffer_index(0u, y);
memcpy32(&m_buffer1[dest_buffer_index], memcpy32(&m_buffer1[dest_buffer_index],
&m_buffer1[src_buffer_index], &m_buffer1[src_buffer_index],
(m_stride * height)); (m_stride * height));
@@ -262,21 +199,6 @@ struct fb
(m_stride * height)); (m_stride * height));
} }
/**
* Scale a color value by an alpha amount.
*
* @param color Color value.
* @param alpha Alpha amount.
*
* @return Scaled color value.
*/
private static uint scale_color(uint color, ubyte alpha)
{
return ((((color & 0xFFu) * alpha) >> 8u) & 0xFFu) |
((((color & 0xFF00u) * alpha) >> 8u) & 0xFF00u) |
((((color & 0xFF0000u) * alpha) >> 8u) & 0xFF0000u);
}
/** /**
* Return the buffer index for the given X and Y coordinates. * Return the buffer index for the given X and Y coordinates.
* *
@@ -287,6 +209,6 @@ struct fb
*/ */
private static size_t buffer_index(size_t x, size_t y) private static size_t buffer_index(size_t x, size_t y)
{ {
return (m_height - y - 1u) * m_stride + x; return y * m_stride + x;
} }
} }
+1 -1
View File
@@ -5,7 +5,7 @@ module hulk.gdt;
import ldc.llvmasm; import ldc.llvmasm;
struct gdt struct Gdt
{ {
struct gdtr_t struct gdtr_t
{ {
+1 -1
View File
@@ -7,7 +7,7 @@
*/ */
module hulk.hippo; module hulk.hippo;
struct hippo struct Hippo
{ {
/** /**
* Linked list node entry for a physical page. * Linked list node entry for a physical page.
+18 -18
View File
@@ -21,7 +21,7 @@ import hulk.pic;
import hulk.acpi; import hulk.acpi;
import hulk.apic; import hulk.apic;
import hulk.rtc; import hulk.rtc;
import hulk.pit; import hulk.serial;
extern extern(C) __gshared ubyte _hulk_bss_size; extern extern(C) __gshared ubyte _hulk_bss_size;
@@ -30,9 +30,9 @@ private __gshared HulkHeader hulk_header = {
&_hulk_bss_size, /* hulk_bss_size */ &_hulk_bss_size, /* hulk_bss_size */
&hulk_start, /* entry */ &hulk_start, /* entry */
16u * 1024u, /* stack_size */ 16u * 1024u, /* stack_size */
HULK_VIRTUAL_BASE_ADDRESS, /* virt_base */ Hurl.HULK_BASE, /* virt_base */
HULK_VIRTUAL_STACK_TOP_ADDRESS, /* virt_stack_top */ Hurl.HULK_STACK_TOP, /* virt_stack_top */
HULK_VIRTUAL_FRAMEBUFFER_ADDRESS, /* virt_fb_buffer */ Hurl.HULK_FRAMEBUFFER, /* virt_fb_buffer */
}; };
private void initialize_cpu() private void initialize_cpu()
@@ -57,26 +57,26 @@ void hulk_start()
{ {
cli(); cli();
initialize_cpu(); initialize_cpu();
gdt.initialize(); Serial.initialize();
idt.initialize(); Gdt.initialize();
fb.initialize(cast(uint *)HULK_VIRTUAL_FRAMEBUFFER_ADDRESS, Idt.initialize();
Fb.initialize(cast(uint *)Hurl.HULK_FRAMEBUFFER,
cast(uint *)hulk_header.bootinfo.fb_buffer1_phys, cast(uint *)hulk_header.bootinfo.fb_buffer1_phys,
hulk_header.bootinfo.fb.width, hulk_header.bootinfo.fb.width,
hulk_header.bootinfo.fb.height, hulk_header.bootinfo.fb.height,
hulk_header.bootinfo.fb.stride); hulk_header.bootinfo.fb.stride);
console.initialize(); Console.initialize();
console.clear(); Console.clear();
klog.initialize(); Klog.initialize();
klog.writefln("Welcome to HULK, the HOS UltraLight Kernel!"); Klog.writefln("Welcome to HULK, the HOS UltraLight Kernel!");
hurl.initialize(&hulk_header); Hurl.initialize(&hulk_header);
pci.initialize(); Pic.initialize();
pic.initialize(); Acpi.initialize(hulk_header.bootinfo.acpi_xsdt_phys);
acpi.initialize(hulk_header.bootinfo.acpi_xsdt_phys); Apic.initialize();
apic.initialize(); Rtc.initialize();
rtc.initialize(); Pci.initialize();
pit.initialize();
sti(); sti();
for (;;) for (;;)
+5 -1
View File
@@ -6,7 +6,7 @@ SECTIONS
.hulk_header : .hulk_header :
{ {
*(.hulk_header) KEEP(*(.hulk_header))
} }
. = ALIGN(4K); . = ALIGN(4K);
@@ -16,6 +16,7 @@ SECTIONS
.text : .text :
{ {
*(.text) *(.text)
*(.text.*)
} }
. = ALIGN(4K); . = ALIGN(4K);
@@ -25,6 +26,7 @@ SECTIONS
.rodata : .rodata :
{ {
*(.rodata) *(.rodata)
*(.rodata.*)
} }
. = ALIGN(4K); . = ALIGN(4K);
@@ -35,6 +37,7 @@ SECTIONS
.data : .data :
{ {
*(.data) *(.data)
*(.data.*)
} }
. = ALIGN(4K); . = ALIGN(4K);
@@ -46,6 +49,7 @@ SECTIONS
{ {
*(COMMON) *(COMMON)
*(.bss) *(.bss)
*(.bss.*)
} }
. = ALIGN(4K); . = ALIGN(4K);
+64
View File
@@ -0,0 +1,64 @@
/**
* A1 memory allocator.
*/
module hulk.hurl.a1;
import hulk.hurl;
import hulk.hippo;
import hulk.util;
import hulk.pagetable;
/**
* The A1 memory allocator is a one-shot memory allocator for kernel memory
* that is allocated but never freed.
*/
struct A1
{
/**
* Number of bytes allocated in the A1 region so far.
*/
private static __gshared size_t allocated;
/**
* Allocate memory.
*
* @param size
* Size of memory to allocate.
*
* @return Address of allocated memory. This address will always be aligned
* to a multiple of 16 bytes.
*/
public static void * allocate(size_t size)
{
/* Round size up to a multiple of 16. */
size = round_up_power_2(size, 16u);
ulong address = Hurl.A1_BASE + allocated;
ulong current_limit = round_up_power_2(address, PAGE_SIZE);
allocated += size;
ulong desired_limit = round_up_power_2(Hurl.A1_BASE + allocated, PAGE_SIZE);
while (desired_limit > current_limit)
{
void * page = Hippo.allocate_page();
Hurl.map(current_limit, page, PT_WRITABLE);
current_limit += PAGE_SIZE;
}
return cast(void *)address;
}
/**
* Allocate memory to store an instance of a given type.
*
* @return Address of allocated memory. This address will always be aligned
* to a multiple of 16 bytes.
*/
public static T * allocate(T)()
{
return cast(T *)allocate(T.sizeof);
}
}
+45 -26
View File
@@ -3,7 +3,7 @@
* *
* HURL provides virtual memory management for HULK. * HURL provides virtual memory management for HULK.
*/ */
module hulk.hurl; module hulk.hurl.hurl;
public import hulk.pagetable; public import hulk.pagetable;
import hulk.cpu; import hulk.cpu;
@@ -13,18 +13,22 @@ import hulk.klog;
import hulk.bootinfo; import hulk.bootinfo;
import hulk.header; import hulk.header;
import hulk.linker_addresses; import hulk.linker_addresses;
import hulk.util;
/** HULK virtual base address. */ struct Hurl
enum ulong HULK_VIRTUAL_BASE_ADDRESS = 0xFFFF_8000_0000_0000u;
/** HULK virtual stack top address. */
enum ulong HULK_VIRTUAL_STACK_TOP_ADDRESS = 0xFFFF_A000_0000_0000u;
/** HULK virtual framebuffer address. */
enum ulong HULK_VIRTUAL_FRAMEBUFFER_ADDRESS = 0xFFFF_A000_0000_0000u;
struct hurl
{ {
/** HULK base address. */
enum ulong HULK_BASE = 0xFFFF_8000_0000_0000u;
/** HULK stack top address. */
enum ulong HULK_STACK_TOP = 0xFFFF_8001_0000_0000u;
/** HULK framebuffer address. */
enum ulong HULK_FRAMEBUFFER = 0xFFFF_8001_0000_0000u;
/** A1 allocator range base address. */
enum ulong A1_BASE = 0xFFFF_8002_0000_0000u;
/** /**
* Pointer to the base page table. * Pointer to the base page table.
*/ */
@@ -45,7 +49,7 @@ struct hurl
physical_address_limit, physical_address_limit,
PT_WRITABLE | PT_NO_EXECUTE); PT_WRITABLE | PT_NO_EXECUTE);
ulong phys_address = header.bootinfo.hulk_phys; ulong phys_address = header.bootinfo.hulk_phys;
ulong virt_address = HULK_VIRTUAL_BASE_ADDRESS; ulong virt_address = HULK_BASE;
/* Map HULK header region. */ /* Map HULK header region. */
map_range(virt_address, map_range(virt_address,
phys_address, phys_address,
@@ -79,12 +83,12 @@ struct hurl
LinkerAddresses.hulk_bss_size, LinkerAddresses.hulk_bss_size,
PT_WRITABLE | PT_NO_EXECUTE); PT_WRITABLE | PT_NO_EXECUTE);
/* Map HULK stack. */ /* Map HULK stack. */
map_range(HULK_VIRTUAL_STACK_TOP_ADDRESS - header.stack_size, map_range(HULK_STACK_TOP - header.stack_size,
header.bootinfo.stack_phys, header.bootinfo.stack_phys,
header.stack_size, header.stack_size,
PT_WRITABLE | PT_NO_EXECUTE); PT_WRITABLE | PT_NO_EXECUTE);
/* Map device framebuffer. */ /* Map device framebuffer. */
map_range(HULK_VIRTUAL_FRAMEBUFFER_ADDRESS, map_range(HULK_FRAMEBUFFER,
cast(ulong)header.bootinfo.fb.buffer, cast(ulong)header.bootinfo.fb.buffer,
header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u, header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u,
PT_WRITABLE | PT_NO_EXECUTE); PT_WRITABLE | PT_NO_EXECUTE);
@@ -121,7 +125,7 @@ struct hurl
reclaimed_pages += reclaim_bootloader_page_table_pages(pte.follow(), level + 1u); reclaimed_pages += reclaim_bootloader_page_table_pages(pte.follow(), level + 1u);
} }
} }
hippo.free_page(pt); Hippo.free_page(pt);
reclaimed_pages++; reclaimed_pages++;
return reclaimed_pages; return reclaimed_pages;
} }
@@ -152,7 +156,7 @@ struct hurl
*/ */
size_t usable_memory; size_t usable_memory;
size_t physical_address_limit; size_t physical_address_limit;
const(size_t) fb_size = (header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u + PAGE_SIZE - 1u) & ~(PAGE_SIZE - 1u); const(size_t) fb_size = round_up_power_2(header.bootinfo.fb.height * header.bootinfo.fb.stride * 4u, PAGE_SIZE);
ulong[2][2] reserved = [ ulong[2][2] reserved = [
[header.bootinfo.hulk_phys, LinkerAddresses.hulk_binary_size], [header.bootinfo.hulk_phys, LinkerAddresses.hulk_binary_size],
[cast(ulong)header.bootinfo.fb.buffer, fb_size], [cast(ulong)header.bootinfo.fb.buffer, fb_size],
@@ -186,7 +190,7 @@ struct hurl
} }
if (!is_reserved) if (!is_reserved)
{ {
hippo.free_page(phys); Hippo.free_page(phys);
} }
phys += PAGE_SIZE; phys += PAGE_SIZE;
} }
@@ -213,11 +217,11 @@ struct hurl
usable_memory += LinkerAddresses.hulk_bss_size; usable_memory += LinkerAddresses.hulk_bss_size;
usable_memory += header.stack_size; usable_memory += header.stack_size;
usable_memory += fb_size; usable_memory += fb_size;
klog.writefln("Usable memory: %uKB", usable_memory >> 10u); Klog.writefln("Usable memory: %uKB", usable_memory >> 10u);
klog.writefln("Kernel size: %uKB", (LinkerAddresses.hulk_binary_size + LinkerAddresses.hulk_bss_size + header.stack_size) >> 10u); Klog.writefln("Kernel size: %uKB", (LinkerAddresses.hulk_binary_size + LinkerAddresses.hulk_bss_size + header.stack_size) >> 10u);
} }
public static void map(T, U)(T virtual, U physical, ulong flags) public static void map(ulong virtual, ulong physical, ulong flags)
{ {
PageTable * pt = m_pt_base; PageTable * pt = m_pt_base;
for (size_t level = 0; level < 4u; level++) for (size_t level = 0; level < 4u; level++)
@@ -244,7 +248,12 @@ struct hurl
} }
} }
public static void map_range(size_t virtual, size_t physical, size_t length, ulong flags) public static void map(T, U)(T virtual, U physical, ulong flags)
{
map(cast(ulong)virtual, cast(ulong)physical, flags);
}
public static void map_range(ulong virtual, ulong physical, size_t length, ulong flags)
{ {
size_t end = virtual + length; size_t end = virtual + length;
while (virtual < end) while (virtual < end)
@@ -255,23 +264,33 @@ struct hurl
} }
} }
public static void identity_map_range(size_t address, size_t length, ulong flags) public static void map_range(T, U)(T virtual, U physical, size_t length, ulong flags)
{
map_range(cast(ulong)virtual, cast(ulong)physical, length, flags);
}
public static void identity_map_range(ulong address, size_t length, ulong flags)
{ {
size_t end = address + length; size_t end = address + length;
for (size_t page = address & ~0xFFFu; page < end; page += PAGE_SIZE) for (size_t page = address & 0xFFFF_FFFF_FFFF_F000u; page < end; page += PAGE_SIZE)
{ {
map(page, page, flags); map(page, page, flags);
} }
} }
public static void identity_map_range(T)(T address, size_t length, ulong flags)
{
identity_map_range(cast(ulong)address, length, flags);
}
public static void debug_lookup(void * address) public static void debug_lookup(void * address)
{ {
klog.writefln("Debugging page table lookup of 0x%x", address); Klog.writefln("Debugging page table lookup of 0x%x", address);
PageTable * pt = m_pt_base; PageTable * pt = m_pt_base;
for (size_t level = 0; level < 4u; level++) for (size_t level = 0; level < 4u; level++)
{ {
PageTableEntry pte = *pt.entry(address, level); PageTableEntry pte = *pt.entry(address, level);
klog.writefln("Level %u, index %u, entry = 0x%x", level, pt.index(address, level), pte); Klog.writefln("Level %u, index %u, entry = 0x%x", level, pt.index(address, level), pte);
if (pte.present) if (pte.present)
{ {
pt = pte.follow(); pt = pte.follow();
@@ -289,7 +308,7 @@ struct hurl
private static PageTable * allocate_pt() private static PageTable * allocate_pt()
{ {
PageTable * pt = cast(PageTable *)hippo.allocate_page(); PageTable * pt = cast(PageTable *)Hippo.allocate_page();
memset64(pt, 0u, PAGE_SIZE / 8u); memset64(pt, 0u, PAGE_SIZE / 8u);
return pt; return pt;
} }
+3
View File
@@ -0,0 +1,3 @@
module hulk.hurl;
public import hulk.hurl.hurl;
+23 -18
View File
@@ -9,16 +9,17 @@ import hulk.fb;
import hulk.console; import hulk.console;
import hulk.klog; import hulk.klog;
import hulk.apic; import hulk.apic;
import hulk.rtc;
struct idt struct Idt
{ {
/* The I/O APIC is configured to map IRQ 0 to interrupt 64 (0x40). */ /* The I/O APIC is configured to map IRQ 0 to interrupt 64 (0x40). */
public static enum ulong INT_RTC = 0x48u; /* IRQ 8 */ public static enum ulong INT_APIC_BASE = 0x40u; /* IRQ 0 */
public static enum ulong INT_APIC_COUNT = 24u;
public static enum ulong INT_LAPIC_TIMER = 0x70u; public static enum ulong INT_APIC_TIMER = 0x70u;
public static enum ulong INT_LAPIC_LINT0 = 0x71u; public static enum ulong INT_APIC_LINT0 = 0x71u;
public static enum ulong INT_LAPIC_LINT1 = 0x72u; public static enum ulong INT_APIC_LINT1 = 0x72u;
public static enum ulong INT_APIC_SPURIOUS = 0xFFu;
struct idtr_t struct idtr_t
{ {
@@ -95,7 +96,7 @@ struct idt
((offset & 0xFFFF_0000u) << 32u) | ((offset & 0xFFFF_0000u) << 32u) |
(dpl << 45u) | (dpl << 45u) |
((trap ? 1uL : 0uL) << 40u) | ((trap ? 1uL : 0uL) << 40u) |
(gdt.SELECTOR_KERNEL_CODE << 16u) | (Gdt.SELECTOR_KERNEL_CODE << 16u) |
(offset & 0xFFFFu); (offset & 0xFFFFu);
idt[index][1] = offset >> 32u; idt[index][1] = offset >> 32u;
} }
@@ -103,26 +104,30 @@ struct idt
public extern(C) void isr(ulong vector, ulong arg) public extern(C) void isr(ulong vector, ulong arg)
{ {
if ((vector >= Idt.INT_APIC_BASE) && (vector < (Idt.INT_APIC_BASE + Idt.INT_APIC_COUNT)))
{
Apic.isr(vector);
}
else
{
switch (vector) switch (vector)
{ {
case idt.INT_RTC: case Idt.INT_APIC_TIMER:
rtc.isr(); case Idt.INT_APIC_LINT0:
break; case Idt.INT_APIC_LINT1:
case Idt.INT_APIC_SPURIOUS:
case idt.INT_LAPIC_TIMER: Apic.isr(vector);
case idt.INT_LAPIC_LINT0:
case idt.INT_LAPIC_LINT1:
apic.isr(vector);
break; break;
default: default:
console.clear(); Console.clear();
fb.clear(0xFF8000u); Fb.clear(0xFF8000u);
klog.writefln("ISR %u, 0x%x", vector, arg); Klog.writefln("ISR %u, 0x%x", vector, arg);
__asm("cli", ""); __asm("cli", "");
for (;;) for (;;)
{ {
__asm("hlt", ""); __asm("hlt", "");
} }
} }
}
} }
+17 -3
View File
@@ -6,8 +6,9 @@ module hulk.klog;
import core.stdc.stdarg; import core.stdc.stdarg;
import hulk.console; import hulk.console;
static import hulk.writef; static import hulk.writef;
import hulk.cpu;
struct klog struct Klog
{ {
/** /**
* Kernel buffer size log. * Kernel buffer size log.
@@ -40,7 +41,7 @@ struct klog
public static void writef(string s, va_list args) public static void writef(string s, va_list args)
{ {
hulk.writef.writef(s, args, function void(ubyte ch) { hulk.writef.writef(s, args, function void(ubyte ch) {
console.write(ch); Console.write(ch);
}); });
} }
@@ -58,7 +59,7 @@ struct klog
} }
/** /**
* Write a formatted string and newline to the console. * Write a formatted string and newline to the kernel log.
* *
* @param s Format string. * @param s Format string.
*/ */
@@ -70,4 +71,17 @@ struct klog
writef("\n", args); writef("\n", args);
va_end(args); va_end(args);
} }
/**
* Print a fatal kernel error and loop forever.
*/
public static void fatal_error(T...)(T args)
{
writef("FATAL ERROR: ");
writefln(args);
cli();
for (;;)
{
}
}
} }
+2 -2
View File
@@ -31,7 +31,7 @@ enum ulong MTRRPHYSBASE_TYPE_MASK = 0xFFu;
enum ulong MTRRPHYSMASK_PHYSMASK_MASK = 0x000F_FFFF_FFFF_F000u; enum ulong MTRRPHYSMASK_PHYSMASK_MASK = 0x000F_FFFF_FFFF_F000u;
enum ulong MTRRPHYSMASK_VALID = 0x800u; enum ulong MTRRPHYSMASK_VALID = 0x800u;
struct mtrr struct Mtrr
{ {
public static void initialize() public static void initialize()
{ {
@@ -41,7 +41,7 @@ struct mtrr
cpuid1(&ebx, &ecx, &edx); cpuid1(&ebx, &ecx, &edx);
if ((edx & CPUID_1_EDX_MTRR) == 0u) if ((edx & CPUID_1_EDX_MTRR) == 0u)
{ {
klog.writefln("CPU does not support MTRR"); Klog.writefln("CPU does not support MTRR");
return; return;
} }
const(ulong) mtrrcap = rdmsr(MSR_MTRRCAP); const(ulong) mtrrcap = rdmsr(MSR_MTRRCAP);
+8
View File
@@ -183,3 +183,11 @@ struct PageTable
} }
} }
static assert(PageTable.sizeof == 4096u); static assert(PageTable.sizeof == 4096u);
/**
* Get the base address of the page containing the given address.
*/
T page_address(T)(T address)
{
return cast(T)(cast(ulong)address & ~(PAGE_SIZE - 1u));
}
+343 -19
View File
@@ -2,8 +2,13 @@ module hulk.pci;
import hulk.cpu; import hulk.cpu;
import hulk.klog; import hulk.klog;
import hulk.hurl;
import hulk.hurl.a1;
import hulk.range;
import hulk.usb.xhci;
import hulk.acpi;
struct pci struct Pci
{ {
/* IO address for PCI configuration address. */ /* IO address for PCI configuration address. */
enum IO_ADDR_CONFIG_ADDRESS = 0xCF8u; enum IO_ADDR_CONFIG_ADDRESS = 0xCF8u;
@@ -11,38 +16,357 @@ struct pci
/* IO address for PCI configuration data. */ /* IO address for PCI configuration data. */
enum IO_ADDR_CONFIG_DATA = 0xCFCu; enum IO_ADDR_CONFIG_DATA = 0xCFCu;
private static ulong read_config_register(ulong bus_id, ulong device_id, ulong register_id) enum MAX_DEVICES_PER_BUS = 32;
enum MAX_FUNCTIONS_PER_DEVICE = 8;
struct Address
{ {
ulong addr = 0x8000_0000u | (bus_id << 16u) | (device_id << 11u) | (register_id << 2u); /** Bus number (0-255). */
out32(IO_ADDR_CONFIG_ADDRESS, addr); ubyte bus_nr;
/** Device number (0-31). */
ubyte device_nr;
/** Function number (0-7). */
ubyte function_nr;
}
static struct Device
{
Configuration * config;
Address address;
bool multifunction;
Range[6] memory_ranges;
void initialize(Address address, Configuration * config)
{
this.config = config;
this.address = address;
Klog.writefln("Found PCI device %04x:%04x (%02x:%02x:%02x) at %02u:%02u.%u",
config.vendor_id, config.device_id,
config.class_id, config.subclass_id, config.interface_id,
address.bus_nr, address.device_nr, address.function_nr);
multifunction = (address.function_nr == 0u) && ((config.header_type & 0x80u) != 0u);
ubyte header_type = config.header_type & 0x7Fu;
if (header_type == 0u)
{
map_memory_regions();
}
spawn_device_instance();
}
private void map_memory_regions()
{
size_t range_index;
uint[2] r;
uint[2] s;
for (uint bar_idx = 0u; bar_idx < config.header0.base_addresses.length; bar_idx++)
{
/* Read the BAR. */
r[0] = config.header0.base_addresses[bar_idx];
/* Skip zeroed BARs. */
if (r[0] == 0u)
{
continue;
}
/* Skip I/O BARs. */
if ((r[0] & 1u) != 0u)
{
continue;
}
bool is_64bit;
uint bar_type = (r[0] >> 1u) & 0x3u;
if (bar_type == 0u)
{
/* 32-bit region. */
r[1] = 0u;
}
else if ((bar_type == 2u) && (bar_idx < 5u))
{
/* 64-bit region. */
is_64bit = true;
r[1] = config.header0.base_addresses[bar_idx + 1];
}
else
{
continue;
}
/* Determine the region length. */
config.header0.base_addresses[bar_idx] = 0xFFFF_FFFFu;
s[0] = config.header0.base_addresses[bar_idx];
config.header0.base_addresses[bar_idx] = r[0];
if (is_64bit)
{
config.header0.base_addresses[bar_idx + 1] = 0xFFFF_FFFFu;
s[1] = config.header0.base_addresses[bar_idx + 1];
config.header0.base_addresses[bar_idx + 1] = r[1];
}
else
{
s[1] = 0xFFFF_FFFFu;
}
ulong mm_region_address = (cast(ulong)r[0] & 0xFFFF_FFF0u) | (cast(ulong)r[1] << 32u);
ulong length = ~((cast(ulong)s[0] & 0xFFFF_FFF0u) | (cast(ulong)s[1] << 32u)) + 1u;
ulong flags = (r[0] & 0x8) != 0u ? PT_WRITE_THROUGH : 0u;
Hurl.identity_map_range(mm_region_address, length, flags);
memory_ranges[range_index].address = mm_region_address;
memory_ranges[range_index].length = length;
range_index++;
if (is_64bit)
{
bar_idx++;
}
}
}
private void spawn_device_instance()
{
switch (config.class_id)
{
case SerialBusController.ID:
switch (config.subclass_id)
{
case SerialBusController.USBController.ID:
switch (config.interface_id)
{
case SerialBusController.USBController.XHCIController.ID:
XHCI.build(&this);
break;
default:
break;
}
break;
default:
break;
}
break;
default:
break;
}
}
}
struct SerialBusController
{
enum ID = 0x0Cu;
struct USBController
{
enum ID = 0x03u;
struct XHCIController
{
enum ID = 0x30u;
}
}
}
private static uint read_config_register(Address address, uint register_id)
{
uint cfg_addr = 0x8000_0000u |
(address.bus_nr << 16u) |
(address.device_nr << 11u) |
(address.function_nr << 8u) |
(register_id << 2u);
out32(IO_ADDR_CONFIG_ADDRESS, cfg_addr);
return in32(IO_ADDR_CONFIG_DATA); return in32(IO_ADDR_CONFIG_DATA);
} }
private static void scan(ulong bus_id, ulong device_id) private static void write_config_register(Address address, uint register_id, uint value)
{ {
ulong reg0 = read_config_register(bus_id, device_id, 0u); uint cfg_addr = 0x8000_0000u |
if (reg0 != 0xFFFFFFFFu) (address.bus_nr << 16u) |
(address.device_nr << 11u) |
(address.function_nr << 8u) |
(register_id << 2u);
out32(IO_ADDR_CONFIG_ADDRESS, cfg_addr);
out32(IO_ADDR_CONFIG_DATA, value);
}
static struct Configuration
{ {
ulong reg2 = read_config_register(bus_id, device_id, 2u); static struct HeaderType0
klog.writefln("Found PCI device %04x:%04x (%02x:%02x:%02x) at %02u:%02u", {
(reg0 & 0xFFFFu), (reg0 >> 16u), ushort vendor_id;
(reg2 >> 24u) & 0xFFu, ushort device_id;
(reg2 >> 16u) & 0xFFu, ushort command;
(reg2 >> 8u) & 0xFFu, ushort status;
bus_id, device_id); ubyte revision_id;
ubyte interface_id;
ubyte subclass_id;
ubyte class_id;
ubyte cache_line_size;
ubyte latency_timer;
ubyte header_type;
ubyte bist;
uint[6] base_addresses;
uint cardbus_cis_pointer;
ushort subsystem_vendor_id;
ushort subsystem_id;
uint expansion_rom_base_address;
ubyte capabilities_pointer;
ubyte[7] _reserved;
ubyte interrupt_line;
ubyte interrupt_pin;
ubyte min_grant;
ubyte max_latency;
}
/**
* PCI configuration format for header type 1 (PCI-to-PCI bridge).
*/
static struct HeaderType1
{
ushort vendor_id;
ushort device_id;
ushort command;
ushort status;
ubyte revision_id;
ubyte interface_id;
ubyte subclass_id;
ubyte class_id;
ubyte cache_line_size;
ubyte latency_timer;
ubyte header_type;
ubyte bist;
uint[2] base_addresses;
ubyte primary_bus_nr;
ubyte secondary_bus_nr;
ubyte subordinate_bus_nr;
ubyte secondary_latency_timer;
ubyte io_base;
ubyte io_limit;
ushort secondary_status;
ushort memory_base;
ushort memory_limit;
ushort prefetchable_memory_base;
ushort prefetchable_memory_limit;
uint prefetchable_base_high;
uint prefetchable_limit_high;
ushort io_base_high;
ushort io_limit_high;
ubyte capability_pointer;
ubyte[3] _reserved;
uint expansion_rom_base_address;
ubyte interrupt_line;
ubyte interrupt_pin;
ushort bridge_control;
}
/**
* PCI configuration format for header type 2 (PCI-to-CardBus bridge).
*/
static struct HeaderType2
{
ushort vendor_id;
ushort device_id;
ushort command;
ushort status;
ubyte revision_id;
ubyte interface_id;
ubyte subclass_id;
ubyte class_id;
ubyte cache_line_size;
ubyte latency_timer;
ubyte header_type;
ubyte bist;
uint cardbus_base_address;
ubyte capability_list_offset;
ubyte _reserved;
ushort secondary_status;
ubyte pci_bus_nr;
ubyte cardbus_bus_nr;
ubyte subordinate_bus_nr;
ubyte cardbus_latency_timer;
uint base_address_0;
uint memory_limit_0;
uint base_address_1;
uint memory_limit_1;
uint io_base_address_0;
uint io_limit_0;
uint io_base_address_1;
uint io_limit_1;
ubyte interrupt_line;
ubyte interrupt_pin;
ushort bridge_control;
ushort subsystem_device_id;
ushort subsystem_vendor_id;
uint legacy_base_address;
}
union
{
struct
{
ushort vendor_id;
ushort device_id;
ushort command;
ushort status;
ubyte revision_id;
ubyte interface_id;
ubyte subclass_id;
ubyte class_id;
ubyte cache_line_size;
ubyte latency_timer;
ubyte header_type;
ubyte bist;
}
HeaderType0 header0;
HeaderType1 header1;
HeaderType2 header2;
}
}
private static void scan(ubyte bus_nr, ubyte device_nr, ubyte function_nr, ulong config_address)
{
Configuration * config = cast(Configuration *)config_address;
if (config.vendor_id != 0xFFFFu)
{
Device * device = A1.allocate!Device();
device.initialize(Address(bus_nr, device_nr, function_nr), config);
if (device.multifunction)
{
for (function_nr = 1u; function_nr < MAX_FUNCTIONS_PER_DEVICE; function_nr++)
{
config_address += PAGE_SIZE;
scan(bus_nr, device_nr, function_nr, config_address);
}
}
} }
} }
public static void initialize() public static void initialize()
{ {
klog.writefln("Scanning PCI devices..."); Klog.writefln("Scanning PCI devices...");
for (ulong bus_id = 0u; bus_id < 256u; bus_id++) size_t n_sgma_descs = Acpi.mcfg.n_sgma_descs;
for (size_t i = 0u; i < n_sgma_descs; i++)
{ {
for (ulong device_id = 0u; device_id < 32u; device_id++) Acpi.MCFG.SGMADesc * sgma_desc = &Acpi.mcfg.sgma_descs[i];
ulong base_address = sgma_desc.base_address;
uint start_pci_bus = sgma_desc.start_pci_bus_number;
uint end_pci_bus = sgma_desc.end_pci_bus_number;
ulong n_buses = (end_pci_bus - start_pci_bus) + 1u;
ulong map_length = PAGE_SIZE * MAX_FUNCTIONS_PER_DEVICE * MAX_DEVICES_PER_BUS * n_buses;
Hurl.identity_map_range(base_address, map_length, PT_WRITABLE | PT_DISABLE_CACHE | PT_NO_EXECUTE);
for (uint bus_nr = start_pci_bus; bus_nr <= end_pci_bus; bus_nr++)
{ {
scan(bus_id, device_id); for (ubyte device_nr = 0u; device_nr < MAX_DEVICES_PER_BUS; device_nr++)
{
ulong device_address = base_address + ((bus_nr - start_pci_bus) * (MAX_DEVICES_PER_BUS * MAX_FUNCTIONS_PER_DEVICE) + device_nr * MAX_FUNCTIONS_PER_DEVICE) * PAGE_SIZE;
scan(cast(ubyte)bus_nr, device_nr, 0u, device_address);
} }
} }
klog.writefln("PCI scan complete."); }
Klog.writefln("PCI scan complete.");
} }
} }
+1 -1
View File
@@ -5,7 +5,7 @@ module hulk.pic;
import hulk.cpu; import hulk.cpu;
struct pic struct Pic
{ {
public static void initialize() public static void initialize()
{ {
+2 -2
View File
@@ -6,7 +6,7 @@ module hulk.pit;
import hulk.cpu; import hulk.cpu;
import hulk.klog; import hulk.klog;
struct pit struct Pit
{ {
/** PIT input frequency in 1/1000 Hz. */ /** PIT input frequency in 1/1000 Hz. */
private enum ulong PIT_FREQUENCY_1000HZ = 1_193_181_667u; private enum ulong PIT_FREQUENCY_1000HZ = 1_193_181_667u;
@@ -37,6 +37,6 @@ struct pit
public static void isr() public static void isr()
{ {
klog.writefln("PIT ISR"); Klog.writefln("PIT ISR");
} }
} }
+27
View File
@@ -0,0 +1,27 @@
module hulk.range;
/**
* Representation of a memory range.
*/
struct Range
{
/** Range base address. */
void * _address;
/** Range length. */
size_t length;
/** Set the range address. */
@property void * address(T)(T a)
{
static assert(T.sizeof == size_t.sizeof);
_address = cast(void *)a;
return _address;
}
/** Get the range address. */
@property void * address()
{
return _address;
}
}
+106 -15
View File
@@ -5,41 +5,77 @@ module hulk.rtc;
import hulk.cpu; import hulk.cpu;
import hulk.klog; import hulk.klog;
import hulk.apic;
struct rtc struct Rtc
{ {
private enum ubyte PORT_SELECT = 0x70u; private enum ubyte PORT_SELECT = 0x70u;
private enum ubyte PORT_DATA = 0x71u; private enum ubyte PORT_DATA = 0x71u;
private enum ubyte DISABLE_NMI = 0x80u; private enum ubyte DISABLE_NMI = 0x80u;
private enum ubyte SR_A = 0xAu; private enum ubyte REG_RTC_SECONDS = 0x0u;
private enum ubyte SR_B = 0xBu; private enum ubyte REG_RTC_MINUTES = 0x2u;
private enum ubyte SR_C = 0xCu; private enum ubyte REG_RTC_HOURS = 0x4u;
private enum ubyte REG_RTC_DAY = 0x7u;
private enum ubyte REG_RTC_MONTH = 0x8u;
private enum ubyte REG_RTC_YEAR = 0x9u;
private enum ubyte REG_SR_A = 0xAu;
private enum ubyte REG_SR_B = 0xBu;
private enum ubyte REG_SR_C = 0xCu;
private enum ubyte SR_A_RTC_UPDATE_IN_PROGRESS = 0x80u;
private enum ubyte SR_B_24HOUR = 0x02u;
private enum ubyte SR_B_BINARY = 0x04u;
private enum ubyte SR_B_ENABLE_IRQ = 0x40u; private enum ubyte SR_B_ENABLE_IRQ = 0x40u;
private static __gshared bool rtc_24hour_mode;
private static __gshared bool rtc_binary_mode;
static struct time
{
public ubyte year;
public ubyte month;
public ubyte day;
public ubyte hour;
public ubyte minute;
public ubyte second;
}
public static void initialize() public static void initialize()
{ {
/* Enable IRQ 8 to receive RTC interrupts. */ /* Enable IRQ 8 to receive RTC interrupts. */
out8(PORT_SELECT, DISABLE_NMI | SR_B); ubyte sr_b = read_register(REG_SR_B, true);
ubyte sr_b = in8(PORT_DATA); write_register(REG_SR_B, sr_b | SR_B_ENABLE_IRQ, true);
out8(PORT_SELECT, DISABLE_NMI | SR_B);
out8(PORT_DATA, sr_b | SR_B_ENABLE_IRQ);
out8(PORT_SELECT, DISABLE_NMI | SR_A); /* Record RTC mode flags from status register B. */
klog.writefln("SR_A = 0x%x", in8(PORT_DATA)); rtc_24hour_mode = (sr_b & SR_B_24HOUR) != 0u;
rtc_binary_mode = (sr_b & SR_B_BINARY) != 0u;
/* Read the current system time. */
time t = read_rtc_time();
Klog.writefln("System time is 20%02u-%02u-%02u %02u:%02u:%02u",
t.year, t.month, t.day, t.hour, t.minute, t.second);
/* Send EOI to enable more RTC interrupts and re-enable NMIs. */ /* Send EOI to enable more RTC interrupts and re-enable NMIs. */
eoi(); eoi();
} }
private static ubyte read_register(ubyte register, bool disable_nmi = false)
{
out8(PORT_SELECT, register | (disable_nmi ? DISABLE_NMI : 0u));
return in8(PORT_DATA);
}
private static void write_register(ubyte register, ubyte value, bool disable_nmi = false)
{
out8(PORT_SELECT, register | (disable_nmi ? DISABLE_NMI : 0u));
out8(PORT_DATA, value);
}
private static void eoi() private static void eoi()
{ {
/* Read from status register C to clear the interrupt. */ /* Read from status register C to clear the interrupt. */
out8(PORT_SELECT, SR_C); read_register(REG_SR_C);
in8(PORT_DATA);
} }
public static void isr() public static void isr()
@@ -50,9 +86,64 @@ struct rtc
if ((count % 1024) == 0u) if ((count % 1024) == 0u)
{ {
seconds++; seconds++;
klog.writefln("Seconds: %u", seconds);
} }
eoi(); eoi();
apic.eoi(); }
private static time read_rtc_time()
{
time[2] times;
size_t reads;
do
{
times[reads & 1] = read_rtc_time_unsafe();
reads++;
} while ((reads < 2u) || (times[0] != times[1]));
return times[0];
}
private static time read_rtc_time_unsafe()
{
time t;
while ((read_register(REG_SR_A) & SR_A_RTC_UPDATE_IN_PROGRESS) != 0u)
{
}
t.year = read_rtc_time_register(REG_RTC_YEAR);
t.month = read_rtc_time_register(REG_RTC_MONTH);
t.day = read_rtc_time_register(REG_RTC_DAY);
t.minute = read_rtc_time_register(REG_RTC_MINUTES);
t.second = read_rtc_time_register(REG_RTC_SECONDS);
/* Hour field is treated differently because it might have 'PM' flag
* in highest bit if we're in 24-hour mode. */
ubyte hour = read_register(REG_RTC_HOURS);
ubyte pm = hour >> 7u;
hour &= 0x7Fu;
if (!rtc_binary_mode)
{
/* Hour is in BCD format; convert to binary. */
hour = bcd_to_binary(hour);
}
if (!rtc_24hour_mode)
{
/* Hour is in 12-hour format; convert to 24-hour format. */
hour = cast(ubyte)((hour % 12u) + pm * 12u);
}
t.hour = hour;
return t;
}
private static ubyte read_rtc_time_register(ubyte register)
{
ubyte value = read_register(register);
if (!rtc_binary_mode)
{
value = bcd_to_binary(value);
}
return value;
}
private static ubyte bcd_to_binary(ubyte bcd)
{
return (bcd & 0xFu) + ((bcd & 0xF0u) >> 4u) * 10u;
} }
} }
+74
View File
@@ -0,0 +1,74 @@
/**
* Serial port access.
*/
module hulk.serial;
import hulk.cpu;
import core.stdc.stdarg;
static import hulk.writef;
struct Serial
{
enum BASE_PORT = 0x3F8;
/**
* Initialize the serial module.
*/
static void initialize()
{
}
/**
* Write a character to the serial port.
*
* @param ch Character to write.
*/
static void write(ubyte ch)
{
if (ch == '\n')
{
out8(BASE_PORT, '\r');
}
out8(BASE_PORT, ch);
}
/**
* Write a formatted string to the serial port.
*
* @param s Format string.
* @param args Variable arguments structure.
*/
public static void writef(string s, va_list args)
{
hulk.writef.writef(s, args, function void(ubyte ch) {
Serial.write(ch);
});
}
/**
* Write a formatted string to the serial port.
*
* @param s Format string.
*/
public static extern (C) void writef(string s, ...)
{
va_list args;
va_start(args, s);
writef(s, args);
va_end(args);
}
/**
* Write a formatted string and newline to the serial port.
*
* @param s Format string.
*/
public static extern (C) void writefln(string s, ...)
{
va_list args;
va_start(args, s);
writef(s, args);
writef("\n", args);
va_end(args);
}
}
+231
View File
@@ -0,0 +1,231 @@
/**
* eXtensible Host Controller Interface for Universal Serial Bus
*
* Documentation:
* - https://wiki.osdev.org/EXtensible_Host_Controller_Interface
* - https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf
*/
module hulk.usb.xhci;
import hulk.pci;
import hulk.hurl.a1;
import hulk.klog;
struct XHCI
{
/**
* Located at PCI base address.
*
* All are read-only.
*/
struct CapabilityRegisters
{
/**
* Offset from beginning of capability registers to beginning of
* operational registers.
*/
ubyte capability_length;
ubyte _reserved01;
/**
* Interface version number supported (psuedo-BSD).
*/
ushort hci_version;
/**
* 7:0 number of device slots (MaxSlots)
* 18:8 number of interrupters (MaxIntrs)
* 23:19 reserved
* 31:24 number of ports (MaxPorts)
*/
uint hcs_params1;
/**
* 3:0 isochronous scheduling threshold (IST)
* 7:4 event ring segment table max (ERST Max)
* 20:8 reserved
* 25:21 max scratchpad buffers (high 5 bits; xHCI v1.1+)
* 26 scratchpad restore (SPR)
* 31:27 max scratchpad buffers (low 5 bits)
*/
uint hcs_params2;
/**
* 7:0 U1 device exit latency
* 15:8 reserved
* 31:16 U2 device exit latency
*/
uint hcs_params3;
/**
* 0 64-bit addressing capability (AC64)
* 1 BW negotiation capability (BNC)
* 2 context size (CSZ)
* 3 port power control (PPC)
* 4 port indicators (PIND)
* 5 light HC reset capability (LHRC)
* 6 latency tolerance messaging capability (LTC)
* 7 no secondary SID support (NSS)
* 8 parse all event data (PAE; xHCI v1.1+)
* 9 stopped - short packet capability (SPC; xHCI v1.1+)
* 10 stopped EDTLA capability (SEC; xHCI v1.1+)
* 11 continuous frame ID capability (CFC; xHCI v1.1+)
* 15:12 maximum primary stream array size (MaxPSASize)
* 31:16 xHCI extended capabilities pointer (xECP)
* offset in 32-bit words from base of capability registers to base
* of capabilities list
*/
uint hcc_params1;
/**
* 1:0 reserved
* 31:2 doorbell array offset in 32-bit words
* offset in 32-bit words from base of capability registers to the
* doorbell array
*/
uint doorbell_offset;
/**
* 4:0 reserved
* 31:5 runtime register space offset
*/
uint rts_offset;
/**
* 0 U3 entry capability (U3C)
* 1 ConfigEP command max exit latency too large (CMC)
* 2 force save context capability (FSC)
* 3 compliance transition capability (CTC)
* 4 large ESIT payload capability (LEC)
* 5 configuration information capability (CIC)
* 6 extended TBC capability (ETC)
* 7 extended TBC TRB status capability (ETC_TSC)
* 8 get/set extended property capability (GSC; xHCI v1.1+)
* 9 virtualization based trusted I/O capability (VTC; xHCI v1.2+)
* 31:10 reserved
*/
uint hcc_params2;
/**
* 11:0 reserved
* 31:12 VTIO register space offset (xHCI v1.2+)
*/
uint vtios_offset;
}
static assert(CapabilityRegisters.sizeof == 0x24u);
/**
* Located at offset capability_length from PCI base address.
*/
struct OperationalRegisters
{
uint usb_command;
uint usb_status;
uint page_size;
uint[2] _reserved01;
uint dn_ctrl;
ulong cr_ctrl;
uint[4] _reserved02;
ulong dcbaap;
uint config;
uint _reserved03;
}
static assert(OperationalRegisters.sizeof == 0x40u);
/**
* Located at offset 0x400 from start of Operational Registers.
*/
struct PortRegisters
{
uint portsc;
uint portpmsc;
uint portli;
uint porthlpmc;
}
static assert(PortRegisters.sizeof == 0x10u);
struct RuntimeRegisters
{
uint mfindex;
uint[7] _reserved01;
uint ir;
}
struct DoorbellRegister
{
ubyte target;
ubyte _reserved01;
ushort task_id;
}
static assert(DoorbellRegister.sizeof == 4u);
private CapabilityRegisters * m_capability_registers;
private OperationalRegisters * m_operational_registers;
private PortRegisters * m_port_registers;
private RuntimeRegisters * m_runtime_registers;
private DoorbellRegister * m_doorbell_registers;
void initialize(Pci.Device * pci_device)
{
void * base_address = pci_device.memory_ranges[0].address;
Klog.writefln("Found XHCI controller at address %p", base_address);
m_capability_registers = cast(CapabilityRegisters *)base_address;
m_operational_registers = cast(OperationalRegisters *)(base_address + m_capability_registers.capability_length);
/* TODO: confirm if 0x400 offset is from m_operation_registers or base_address. */
m_port_registers = cast(PortRegisters *)(cast(void *)m_operational_registers + 0x400);
m_runtime_registers = cast(RuntimeRegisters *)(base_address + m_capability_registers.rts_offset);
m_doorbell_registers = cast(DoorbellRegister *)(base_address + m_capability_registers.doorbell_offset);
dump_extended_capabilities();
}
private void dump_extended_capabilities()
{
size_t ext_cap_off = (m_capability_registers.hcc_params1 >> 16u);
if (ext_cap_off != 0u)
{
Klog.writefln("Extended capabilities:");
uint * extended_capabilities = cast(uint *)m_capability_registers + ext_cap_off;
for (;;)
{
uint ec0 = extended_capabilities[0];
size_t next_offset = (ec0 >> 8u) & 0xFFu;
size_t len = next_offset;
if (len < 1u)
{
len = 1u;
}
ubyte type = ec0 & 0xFFu;
if (type == 2u)
{
len = 4u;
}
for (size_t i = 0u; i < len; i++)
{
uint ecv = extended_capabilities[i];
Klog.writef(" %02X %02X %02X %02X",
ecv & 0xFFu,
(ecv >> 8u) & 0xFFu,
(ecv >> 16u) & 0xFFu,
(ecv >> 24u) & 0xFFu);
}
Klog.writef("\n");
if (next_offset == 0u)
{
break;
}
extended_capabilities += next_offset;
}
}
}
static void build(Pci.Device * pci_device)
{
if (pci_device.memory_ranges[0].address != null)
{
XHCI * xhci = A1.allocate!XHCI();
xhci.initialize(pci_device);
}
}
}
+17
View File
@@ -0,0 +1,17 @@
/**
* HULK utility functions.
*/
module hulk.util;
/**
* Round a value up to the next power of 2.
*
* @param v Value to round up.
* @param p Power of 2 to round up to.
*
* @return Rounded up value.
*/
ulong round_up_power_2(ulong v, ulong p)
{
return (v + p - 1u) & ~(p - 1u);
}
+36 -13
View File
@@ -26,18 +26,33 @@ size_t writef(string s, va_list args, ch_out_fn ch_out)
{ {
if (escape) if (escape)
{ {
if (c == 'x') if (c == 'c')
{
ulong ch;
va_arg(args, ch);
ch_out(cast(ubyte)ch);
length_written++;
escape = false;
}
else if (c == 'p')
{ {
ulong v; ulong v;
va_arg(args, v); va_arg(args, v);
length_written += write_hex(v, false, pad, width, ch_out); length_written += write_hex(v, true, true, pad, width, ch_out);
escape = false;
}
else if (c == 'x')
{
ulong v;
va_arg(args, v);
length_written += write_hex(v, false, false, pad, width, ch_out);
escape = false; escape = false;
} }
else if (c == 'X') else if (c == 'X')
{ {
ulong v; ulong v;
va_arg(args, v); va_arg(args, v);
length_written += write_hex(v, true, pad, width, ch_out); length_written += write_hex(v, true, false, pad, width, ch_out);
escape = false; escape = false;
} }
else if (c == 'u') else if (c == 'u')
@@ -80,27 +95,35 @@ size_t writef(string s, va_list args, ch_out_fn ch_out)
* *
* @param v Value to format. * @param v Value to format.
* @param upper Whether to use uppercase letters. * @param upper Whether to use uppercase letters.
* @param pointer Whether to format as a pointer.
* @param pad Pad character to use. * @param pad Pad character to use.
* @param width Field width. * @param width Field width.
* @param ch_out Character output function. * @param ch_out Character output function.
* *
* @return Number of characters written. * @return Number of characters written.
*/ */
private size_t write_hex(ulong v, bool upper, char pad, size_t width, ch_out_fn ch_out) private size_t write_hex(ulong v, bool upper, bool pointer, char pad, size_t width, ch_out_fn ch_out)
{ {
static __gshared const(char)[16] hex_chars_lower = "0123456789abcdef"; static __gshared const(char)[16] hex_chars_lower = "0123456789abcdef";
static __gshared const(char)[16] hex_chars_upper = "0123456789ABCDEF"; static __gshared const(char)[16] hex_chars_upper = "0123456789ABCDEF";
char[16] buf; char[19] buf;
size_t i; size_t digit;
size_t buf_idx;
do do
{ {
ulong n = v & 0xFu; ulong n = v & 0xFu;
buf[i] = upper ? hex_chars_upper[n] : hex_chars_lower[n]; buf[buf_idx] = upper ? hex_chars_upper[n] : hex_chars_lower[n];
v >>= 4u; v >>= 4u;
i++; buf_idx++;
digit++;
if (pointer && ((digit % 4) == 0) && (v != 0u))
{
buf[buf_idx] = '_';
buf_idx++;
}
} while (v != 0u); } while (v != 0u);
size_t length_written = i; size_t length_written = buf_idx;
while (width > i) while (width > buf_idx)
{ {
ch_out(pad); ch_out(pad);
width--; width--;
@@ -108,9 +131,9 @@ private size_t write_hex(ulong v, bool upper, char pad, size_t width, ch_out_fn
} }
do do
{ {
i--; buf_idx--;
ch_out(buf[i]); ch_out(buf[buf_idx]);
} while (i != 0u); } while (buf_idx != 0u);
return length_written; return length_written;
} }
+9
View File
@@ -21,23 +21,30 @@ end
default do default do
unless Dir.exist?(install_path) unless Dir.exist?(install_path)
puts "Building cross compiler toolchain..."
# Download archives. # Download archives.
puts "Downloading binutils..."
download "https://ftp.gnu.org/gnu/binutils/binutils-#{binutils_version}.tar.xz", download "https://ftp.gnu.org/gnu/binutils/binutils-#{binutils_version}.tar.xz",
"#{build_dir}/binutils-#{binutils_version}.tar.xz", "#{build_dir}/binutils-#{binutils_version}.tar.xz",
sha256sum: binutils_checksum sha256sum: binutils_checksum
puts "Downloading gcc..."
download "https://ftp.gnu.org/gnu/gcc/gcc-#{gcc_version}/gcc-#{gcc_version}.tar.xz", download "https://ftp.gnu.org/gnu/gcc/gcc-#{gcc_version}/gcc-#{gcc_version}.tar.xz",
"#{build_dir}/gcc-#{gcc_version}.tar.xz", "#{build_dir}/gcc-#{gcc_version}.tar.xz",
sha256sum: gcc_checksum sha256sum: gcc_checksum
# Extract archives. # Extract archives.
puts "Extracting binutils..."
sh "tar", "xJf", "binutils-#{binutils_version}.tar.xz", sh "tar", "xJf", "binutils-#{binutils_version}.tar.xz",
chdir: build_dir chdir: build_dir
puts "Extracting gcc..."
sh "tar", "xJf", "gcc-#{gcc_version}.tar.xz", sh "tar", "xJf", "gcc-#{gcc_version}.tar.xz",
chdir: build_dir chdir: build_dir
# Build binutils. # Build binutils.
puts "Building binutils..."
rm_rf "#{build_dir}/build-binutils" rm_rf "#{build_dir}/build-binutils"
mkdir_p "#{build_dir}/build-binutils" mkdir_p "#{build_dir}/build-binutils"
cd "#{build_dir}/build-binutils" do cd "#{build_dir}/build-binutils" do
@@ -49,6 +56,7 @@ default do
end end
# Build gcc. # Build gcc.
puts "Building gcc..."
rm_rf "#{build_dir}/build-gcc" rm_rf "#{build_dir}/build-gcc"
mkdir_p "#{build_dir}/build-gcc" mkdir_p "#{build_dir}/build-gcc"
cd "#{build_dir}/build-gcc" do cd "#{build_dir}/build-gcc" do
@@ -62,6 +70,7 @@ default do
end end
# Remove archives and build directories if everything succeeded. # Remove archives and build directories if everything succeeded.
puts "Cleaning up..."
rm_f "#{build_dir}/binutils-#{binutils_version}.tar.xz" rm_f "#{build_dir}/binutils-#{binutils_version}.tar.xz"
rm_rf "#{build_dir}/binutils-#{binutils_version}" rm_rf "#{build_dir}/binutils-#{binutils_version}"
rm_rf "#{build_dir}/build-binutils" rm_rf "#{build_dir}/build-binutils"