mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 08:24:32 -08:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a45ea562b | ||
|
|
da404f520d | ||
|
|
799ad8b264 | ||
|
|
818b51d57c | ||
|
|
e8866abc7a | ||
|
|
3b560c063a | ||
|
|
a27b8d6a3a | ||
|
|
2050b89334 | ||
|
|
504de44ff3 | ||
|
|
71a6f13fa5 | ||
|
|
f62fbefe54 | ||
|
|
6c29024eac | ||
|
|
b7f18c0d31 | ||
|
|
696c29086b | ||
|
|
bce281606e | ||
|
|
2388a92085 | ||
|
|
447991e82b | ||
|
|
a8984350da | ||
|
|
4d5da72e2e |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@ build
|
|||||||
*.bak
|
*.bak
|
||||||
tags
|
tags
|
||||||
.gdbinit
|
.gdbinit
|
||||||
|
popcorn.log
|
||||||
|
|||||||
49
Makefile
49
Makefile
@@ -3,6 +3,7 @@ ARCH ?= x86_64
|
|||||||
include src/arch/$(ARCH)/config.mk
|
include src/arch/$(ARCH)/config.mk
|
||||||
|
|
||||||
BUILD_D := build
|
BUILD_D := build
|
||||||
|
KERN_D := src/kernel
|
||||||
ARCH_D := src/arch/$(ARCH)
|
ARCH_D := src/arch/$(ARCH)
|
||||||
VERSION ?= $(shell git describe --dirty --always)
|
VERSION ?= $(shell git describe --dirty --always)
|
||||||
GITSHA ?= $(shell git rev-parse --short HEAD)
|
GITSHA ?= $(shell git rev-parse --short HEAD)
|
||||||
@@ -10,7 +11,7 @@ GITSHA ?= $(shell git rev-parse --short HEAD)
|
|||||||
KERNEL_FILENAME:= popcorn.bin
|
KERNEL_FILENAME:= popcorn.bin
|
||||||
KERNEL_FONT := assets/fonts/tamsyn8x16r.psf
|
KERNEL_FONT := assets/fonts/tamsyn8x16r.psf
|
||||||
|
|
||||||
MODULES := main
|
MODULES := kutil
|
||||||
|
|
||||||
|
|
||||||
EFI_DIR := external/gnu-efi
|
EFI_DIR := external/gnu-efi
|
||||||
@@ -57,13 +58,14 @@ ASFLAGS += -p $(BUILD_D)/versions.s
|
|||||||
|
|
||||||
CFLAGS := $(INCLUDES) $(DEPENDFLAGS) $(BASEFLAGS) $(WARNFLAGS)
|
CFLAGS := $(INCLUDES) $(DEPENDFLAGS) $(BASEFLAGS) $(WARNFLAGS)
|
||||||
CFLAGS += -DGIT_VERSION="\"$(VERSION)\""
|
CFLAGS += -DGIT_VERSION="\"$(VERSION)\""
|
||||||
CFLAGS += -std=c11
|
CFLAGS += -std=c11 -mcmodel=large
|
||||||
|
|
||||||
CXXFLAGS := $(INCLUDES) $(DEPENDFLAGS) $(BASEFLAGS) $(WARNFLAGS)
|
CXXFLAGS := $(INCLUDES) $(DEPENDFLAGS) $(BASEFLAGS) $(WARNFLAGS)
|
||||||
CXXFLAGS += -DGIT_VERSION="\"$(VERSION)\""
|
CXXFLAGS += -DGIT_VERSION="\"$(VERSION)\""
|
||||||
CXXFLAGS += -std=c++14
|
CXXFLAGS += -std=c++14 -mcmodel=large
|
||||||
|
|
||||||
BOOT_CFLAGS := -I src/boot $(CFLAGS) -fPIC -fshort-wchar
|
BOOT_CFLAGS := $(INCLUDES) $(DEPENDFLAGS) $(BASEFLAGS) $(WARNFLAGS)
|
||||||
|
BOOT_CFLAGS += -std=c11 -I src/boot -fPIC -fshort-wchar
|
||||||
BOOT_CFLAGS += -DKERNEL_FILENAME="L\"$(KERNEL_FILENAME)\""
|
BOOT_CFLAGS += -DKERNEL_FILENAME="L\"$(KERNEL_FILENAME)\""
|
||||||
BOOT_CFLAGS += -DGIT_VERSION_WIDE="L\"$(VERSION)\""
|
BOOT_CFLAGS += -DGIT_VERSION_WIDE="L\"$(VERSION)\""
|
||||||
BOOT_CFLAGS += -DGNU_EFI_USE_MS_ABI -DHAVE_USE_MS_ABI
|
BOOT_CFLAGS += -DGNU_EFI_USE_MS_ABI -DHAVE_USE_MS_ABI
|
||||||
@@ -92,12 +94,15 @@ INIT_DEP := $(BUILD_D)/.builddir
|
|||||||
|
|
||||||
BOOT_SRCS := $(wildcard src/boot/*.c)
|
BOOT_SRCS := $(wildcard src/boot/*.c)
|
||||||
BOBJS += $(patsubst src/boot/%,$(BUILD_D)/boot/%,$(patsubst %,%.o,$(BOOT_SRCS)))
|
BOBJS += $(patsubst src/boot/%,$(BUILD_D)/boot/%,$(patsubst %,%.o,$(BOOT_SRCS)))
|
||||||
BDEPS := $(patsubst src/boot/%,$(BUILD_D)/boot/%,$(patsubst %,%.d,$(BOOT_SRCS)))
|
|
||||||
|
|
||||||
ARCH_SRCS := $(wildcard $(ARCH_D)/*.s)
|
KERN_SRCS := $(wildcard $(KERN_D)/*.s)
|
||||||
ARCH_SRCS += $(wildcard $(ARCH_D)/*.c)
|
KERN_SRCS += $(wildcard $(KERN_D)/*.c)
|
||||||
KOBJS += $(patsubst $(ARCH_D)/%,$(BUILD_D)/arch/%,$(patsubst %,%.o,$(ARCH_SRCS)))
|
KERN_SRCS += $(wildcard $(KERN_D)/*.cpp)
|
||||||
DEPS := $(patsubst $(ARCH_D)/%,$(BUILD_D)/arch/%,$(patsubst %,%.d,$(ARCH_SRCS)))
|
KERN_SRCS += $(wildcard $(ARCH_D)/*.s)
|
||||||
|
KERN_SRCS += $(wildcard $(ARCH_D)/*.c)
|
||||||
|
|
||||||
|
KERN_OBJS := $(patsubst src/%, $(BUILD_D)/%, $(patsubst %,%.o,$(KERN_SRCS)))
|
||||||
|
|
||||||
MOD_TARGETS :=
|
MOD_TARGETS :=
|
||||||
|
|
||||||
PARTED ?= /sbin/parted
|
PARTED ?= /sbin/parted
|
||||||
@@ -120,19 +125,24 @@ init: $(INIT_DEP)
|
|||||||
$(INIT_DEP):
|
$(INIT_DEP):
|
||||||
mkdir -p $(BUILD_D) $(patsubst %,$(BUILD_D)/d.%,$(MODULES))
|
mkdir -p $(BUILD_D) $(patsubst %,$(BUILD_D)/d.%,$(MODULES))
|
||||||
mkdir -p $(BUILD_D)/boot
|
mkdir -p $(BUILD_D)/boot
|
||||||
mkdir -p $(BUILD_D)/arch
|
mkdir -p $(patsubst src/%,$(BUILD_D)/%,$(ARCH_D))
|
||||||
|
mkdir -p $(patsubst src/%,$(BUILD_D)/%,$(KERN_D))
|
||||||
touch $(INIT_DEP)
|
touch $(INIT_DEP)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD_D)/* $(BUILD_D)/.version $(BUILD_D)/.builddir
|
rm -rf $(BUILD_D)/* $(BUILD_D)/.version $(BUILD_D)/.builddir
|
||||||
|
|
||||||
|
vars:
|
||||||
|
@echo "KERN_SRCS: " $(KERN_SRCS)
|
||||||
|
@echo "KERN_OBJS: " $(KERN_OBJS)
|
||||||
|
|
||||||
dist-clean: clean
|
dist-clean: clean
|
||||||
make -C external/gnu-efi clean
|
make -C external/gnu-efi clean
|
||||||
|
|
||||||
dump: $(BUILD_D)/kernel.dump
|
dump: $(BUILD_D)/kernel.dump
|
||||||
vim $<
|
vim $<
|
||||||
|
|
||||||
.PHONY: all clean dist-clean init dump
|
.PHONY: all clean dist-clean init dump vars
|
||||||
|
|
||||||
$(BUILD_D)/.version:
|
$(BUILD_D)/.version:
|
||||||
echo '$(VERSION)' | cmp -s - $@ || echo '$(VERSION)' > $@
|
echo '$(VERSION)' | cmp -s - $@ || echo '$(VERSION)' > $@
|
||||||
@@ -141,7 +151,7 @@ $(BUILD_D)/versions.s:
|
|||||||
./parse_version.py "$(VERSION)" "$(GITSHA)" > $@
|
./parse_version.py "$(VERSION)" "$(GITSHA)" > $@
|
||||||
|
|
||||||
-include x $(patsubst %,src/modules/%/module.mk,$(MODULES))
|
-include x $(patsubst %,src/modules/%/module.mk,$(MODULES))
|
||||||
-include x $(DEPS)
|
-include x $(shell find $(BUILD_D) -type f -name '*.d')
|
||||||
|
|
||||||
$(EFI_LIB):
|
$(EFI_LIB):
|
||||||
make -C external/gnu-efi all
|
make -C external/gnu-efi all
|
||||||
@@ -169,24 +179,27 @@ $(BUILD_D)/boot.dump: $(BUILD_D)/boot.efi
|
|||||||
$(OBJD) -D -S $< > $@
|
$(OBJD) -D -S $< > $@
|
||||||
|
|
||||||
$(BUILD_D)/boot/%.s.o: src/boot/%.s $(BUILD_D)/versions.s $(INIT_DEP)
|
$(BUILD_D)/boot/%.s.o: src/boot/%.s $(BUILD_D)/versions.s $(INIT_DEP)
|
||||||
$(AS) $(ASFLAGS) -o $@ $<
|
$(AS) $(ASFLAGS) -i src/boot/ -o $@ $<
|
||||||
|
|
||||||
$(BUILD_D)/boot/%.c.o: src/boot/%.c $(INIT_DEP)
|
$(BUILD_D)/boot/%.c.o: src/boot/%.c $(INIT_DEP)
|
||||||
$(CC) $(BOOT_CFLAGS) -c -o $@ $<
|
$(CC) $(BOOT_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
$(BUILD_D)/kernel.elf: $(KOBJS) $(MOD_TARGETS) $(ARCH_D)/kernel.ld
|
$(BUILD_D)/kernel.elf: $(KERN_OBJS) $(MOD_TARGETS) $(ARCH_D)/kernel.ld
|
||||||
$(LD) $(LDFLAGS) -u _header -T $(ARCH_D)/kernel.ld -o $@ $(patsubst %,-l%,$(MODULES)) $(KOBJS)
|
$(LD) $(LDFLAGS) -u _header -T $(ARCH_D)/kernel.ld -o $@ $(KERN_OBJS) $(patsubst %,-l%,$(MODULES))
|
||||||
$(OBJC) --only-keep-debug $@ $@.sym
|
$(OBJC) --only-keep-debug $@ $@.sym
|
||||||
|
|
||||||
$(BUILD_D)/kernel.dump: $(BUILD_D)/kernel.elf
|
$(BUILD_D)/kernel.dump: $(BUILD_D)/kernel.elf
|
||||||
$(OBJD) -D -S $< > $@
|
$(OBJD) -D -S $< > $@
|
||||||
|
|
||||||
$(BUILD_D)/arch/%.s.o: $(ARCH_D)/%.s $(BUILD_D)/versions.s $(INIT_DEP)
|
$(BUILD_D)/%.s.o: src/%.s $(BUILD_D)/versions.s $(INIT_DEP)
|
||||||
$(AS) $(ASFLAGS) -o $@ $<
|
$(AS) $(ASFLAGS) -i $(ARCH_D)/ -i $(KERN_D)/ -o $@ $<
|
||||||
|
|
||||||
$(BUILD_D)/arch/%.c.o: $(ARCH_D)/%.c $(INIT_DEP)
|
$(BUILD_D)/%.c.o: src/%.c $(INIT_DEP)
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(BUILD_D)/%.cpp.o: src/%.cpp $(INIT_DEP)
|
||||||
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
$(BUILD_D)/flash.img: $(OVMF)
|
$(BUILD_D)/flash.img: $(OVMF)
|
||||||
cp $^ $@
|
cp $^ $@
|
||||||
|
|
||||||
|
|||||||
9
NOTES.md
9
NOTES.md
@@ -1,10 +1,7 @@
|
|||||||
# Design / WIP notes
|
# Design / WIP notes
|
||||||
|
|
||||||
## Bootloader / UEFI
|
## TODO
|
||||||
|
|
||||||
* What is the interface between the UEFI boot portion and the kernel?
|
|
||||||
* Allocate pages, use UEFI reserved mapping types (0x70000000 - 0x7fffffff)
|
|
||||||
* Passing memory map: Allocate earliest pages and fill with UEFI's memory map
|
|
||||||
stuctures?
|
|
||||||
|
|
||||||
|
- Better page-allocation model
|
||||||
|
- Allow for more than one IOAPIC in ACPI module
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ $(MOD_BUILD_D)/%.cpp.o: $(MOD_SRC_D)/%.cpp $(INIT_DEP)
|
|||||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
$(MOD_BUILD_D)/%.s.o: $(MOD_SRC_D)/%.s $(BUILD_D)/versions.s $(INIT_DEP)
|
$(MOD_BUILD_D)/%.s.o: $(MOD_SRC_D)/%.s $(BUILD_D)/versions.s $(INIT_DEP)
|
||||||
$(AS) $(ASFLAGS) -o $@ $<
|
$(AS) $(ASFLAGS) -i $(MOD_SRC_D)/ -o $@ $<
|
||||||
|
|
||||||
DEPS += $(patsubst %.o,%.d,$(OBJS_$(MOD_NAME)))
|
DEPS += $(patsubst %.o,%.d,$(OBJS_$(MOD_NAME)))
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
call make.bat
|
|
||||||
qemu-system-x86_64.exe -bios .\assets\ovmf\x64\OVMF.fd -hda .\build\fs.img -m 512 -vga cirrus
|
|
||||||
4
qemu.bat
4
qemu.bat
@@ -1 +1,3 @@
|
|||||||
qemu-system-x86_64.exe -bios .\assets\ovmf\x64\OVMF.fd -hda .\build\fs.img -m 512 -nographic -echr 23
|
call make.bat
|
||||||
|
del popcorn.log
|
||||||
|
qemu-system-x86_64.exe -bios .\assets\ovmf\x64\OVMF.fd -hda .\build\fs.img -m 512 -vga cirrus -d guest_errors,int -D popcorn.log -no-reboot
|
||||||
|
|||||||
60
scripts/parse_memmap.py
Executable file
60
scripts/parse_memmap.py
Executable file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from struct import unpack_from, calcsize
|
||||||
|
import sys
|
||||||
|
|
||||||
|
memory_type_names = {
|
||||||
|
0: "EfiReservedMemoryType",
|
||||||
|
1: "EfiLoaderCode",
|
||||||
|
2: "EfiLoaderData",
|
||||||
|
3: "EfiBootServicesCode",
|
||||||
|
4: "EfiBootServicesData",
|
||||||
|
5: "EfiRuntimeServicesCode",
|
||||||
|
6: "EfiRuntimeServicesData",
|
||||||
|
7: "EfiConventionalMemory",
|
||||||
|
8: "EfiUnusableMemory",
|
||||||
|
9: "EfiACPIReclaimMemory",
|
||||||
|
10: "EfiACPIMemoryNVS",
|
||||||
|
11: "EfiMemoryMappedIO",
|
||||||
|
12: "EfiMemoryMappedIOPortSpace",
|
||||||
|
13: "EfiPalCode",
|
||||||
|
14: "EfiPersistentMemory",
|
||||||
|
|
||||||
|
0x80000000: "Kernel Image",
|
||||||
|
0x80000001: "Kernel Data",
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_MEMORY_UC = 0x0000000000000001
|
||||||
|
EFI_MEMORY_WC = 0x0000000000000002
|
||||||
|
EFI_MEMORY_WT = 0x0000000000000004
|
||||||
|
EFI_MEMORY_WB = 0x0000000000000008
|
||||||
|
EFI_MEMORY_UCE = 0x0000000000000010
|
||||||
|
EFI_MEMORY_WP = 0x0000000000001000
|
||||||
|
EFI_MEMORY_RP = 0x0000000000002000
|
||||||
|
EFI_MEMORY_XP = 0x0000000000004000
|
||||||
|
EFI_MEMORY_NV = 0x0000000000008000
|
||||||
|
EFI_MEMORY_MORE_RELIABLE = 0x0000000000010000
|
||||||
|
EFI_MEMORY_RO = 0x0000000000020000
|
||||||
|
EFI_MEMORY_RUNTIME = 0x8000000000000000
|
||||||
|
|
||||||
|
fmt = "LQQQQQ"
|
||||||
|
size = calcsize(fmt)
|
||||||
|
|
||||||
|
print("Descriptor size: {} bytes\n".format(size))
|
||||||
|
if size != 48:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
data = open(sys.argv[1], 'rb').read()
|
||||||
|
length = len(data)
|
||||||
|
consumed = 0
|
||||||
|
|
||||||
|
while length - consumed > size:
|
||||||
|
memtype, phys, virt, pages, attr, pad = unpack_from(fmt, data, consumed)
|
||||||
|
consumed += size
|
||||||
|
if pages == 0: break
|
||||||
|
|
||||||
|
memtype = memory_type_names.get(memtype, "{:016x}".format(memtype))
|
||||||
|
runtime = {EFI_MEMORY_RUNTIME: "*"}.get(attr & EFI_MEMORY_RUNTIME, " ")
|
||||||
|
|
||||||
|
print("{:>23}{} {:016x} {:016x} [{:4d}]".format(memtype, runtime, phys, virt, pages))
|
||||||
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0x100000;
|
OFFSET = 0xFFFF800000000000;
|
||||||
|
. = OFFSET + 0x100000;
|
||||||
|
|
||||||
.header : {
|
.header : {
|
||||||
header = .;
|
header = .;
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
#define KERNEL_PHYS_ADDRESS 0x100000
|
#define KERNEL_PHYS_ADDRESS 0x100000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef KERNEL_VIRT_ADDRESS
|
||||||
|
#define KERNEL_VIRT_ADDRESS 0xFFFF800000000000
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef VIRTUAL_OFFSET
|
#ifndef VIRTUAL_OFFSET
|
||||||
#define VIRTUAL_OFFSET 0xf00000000
|
#define VIRTUAL_OFFSET 0xf00000000
|
||||||
#endif
|
#endif
|
||||||
@@ -32,6 +36,10 @@
|
|||||||
#define KERNEL_LOG_PAGES 4
|
#define KERNEL_LOG_PAGES 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef KERNEL_PT_MEMTYPE
|
||||||
|
#define KERNEL_PT_MEMTYPE 0x80000004
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef KERNEL_FILENAME
|
#ifndef KERNEL_FILENAME
|
||||||
#define KERNEL_FILENAME L"kernel.bin"
|
#define KERNEL_FILENAME L"kernel.bin"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
|
|||||||
{
|
{
|
||||||
EFI_STATUS status;
|
EFI_STATUS status;
|
||||||
EFI_BOOT_SERVICES *bootsvc = system_table->BootServices;
|
EFI_BOOT_SERVICES *bootsvc = system_table->BootServices;
|
||||||
|
EFI_RUNTIME_SERVICES *runsvc = system_table->RuntimeServices;
|
||||||
|
|
||||||
// When checking console initialization, use CHECK_EFI_STATUS_OR_RETURN
|
// When checking console initialization, use CHECK_EFI_STATUS_OR_RETURN
|
||||||
// because we can't be sure if the console was fully set up
|
// because we can't be sure if the console was fully set up
|
||||||
@@ -44,6 +45,8 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
|
|||||||
CHECK_EFI_STATUS_OR_RETURN(status, "con_initialize");
|
CHECK_EFI_STATUS_OR_RETURN(status, "con_initialize");
|
||||||
// From here on out, we can use CHECK_EFI_STATUS_OR_FAIL instead
|
// From here on out, we can use CHECK_EFI_STATUS_OR_FAIL instead
|
||||||
|
|
||||||
|
memory_init_pointer_fixup(bootsvc, runsvc);
|
||||||
|
|
||||||
// Find ACPI tables. Ignore ACPI 1.0 if a 2.0 table is found.
|
// Find ACPI tables. Ignore ACPI 1.0 if a 2.0 table is found.
|
||||||
//
|
//
|
||||||
void *acpi_table = NULL;
|
void *acpi_table = NULL;
|
||||||
@@ -100,10 +103,12 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
|
|||||||
con_printf(L" Entrypoint 0x%x\r\n", version->entrypoint);
|
con_printf(L" Entrypoint 0x%x\r\n", version->entrypoint);
|
||||||
|
|
||||||
void (*kernel_main)() = version->entrypoint;
|
void (*kernel_main)() = version->entrypoint;
|
||||||
|
memory_mark_pointer_fixup((void **)&kernel_main);
|
||||||
|
|
||||||
// Set up the kernel data pages to pass to the kernel
|
// Set up the kernel data pages to pass to the kernel
|
||||||
//
|
//
|
||||||
struct popcorn_data *data_header = (struct popcorn_data *)load.data;
|
struct popcorn_data *data_header = (struct popcorn_data *)load.data;
|
||||||
|
memory_mark_pointer_fixup((void **)&data_header);
|
||||||
|
|
||||||
data_header->magic = DATA_HEADER_MAGIC;
|
data_header->magic = DATA_HEADER_MAGIC;
|
||||||
data_header->version = DATA_HEADER_VERSION;
|
data_header->version = DATA_HEADER_VERSION;
|
||||||
@@ -113,16 +118,24 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
|
|||||||
|
|
||||||
data_header->font = load.font;
|
data_header->font = load.font;
|
||||||
data_header->font_length = load.font_length;
|
data_header->font_length = load.font_length;
|
||||||
|
memory_mark_pointer_fixup((void **)&data_header->font);
|
||||||
|
|
||||||
data_header->data = load.data;
|
data_header->data = load.data;
|
||||||
data_header->data_length = load.data_length;
|
data_header->data_length = load.data_length;
|
||||||
|
memory_mark_pointer_fixup((void **)&data_header->data);
|
||||||
|
|
||||||
data_header->log = load.log;
|
data_header->log = load.log;
|
||||||
data_header->log_length = load.log_length;
|
data_header->log_length = load.log_length;
|
||||||
|
memory_mark_pointer_fixup((void **)&data_header->log);
|
||||||
|
|
||||||
data_header->memory_map = (EFI_MEMORY_DESCRIPTOR *)(data_header + 1);
|
data_header->memory_map = (EFI_MEMORY_DESCRIPTOR *)(data_header + 1);
|
||||||
data_header->runtime = system_table->RuntimeServices;
|
memory_mark_pointer_fixup((void **)&data_header->memory_map);
|
||||||
|
|
||||||
|
data_header->runtime = runsvc;
|
||||||
|
memory_mark_pointer_fixup((void **)&data_header->runtime);
|
||||||
|
|
||||||
data_header->acpi_table = acpi_table;
|
data_header->acpi_table = acpi_table;
|
||||||
|
memory_mark_pointer_fixup((void **)&data_header->acpi_table);
|
||||||
|
|
||||||
data_header->_reserved0 = 0;
|
data_header->_reserved0 = 0;
|
||||||
data_header->_reserved1 = 0;
|
data_header->_reserved1 = 0;
|
||||||
@@ -139,6 +152,7 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
|
|||||||
&data_header->gmask,
|
&data_header->gmask,
|
||||||
&data_header->bmask);
|
&data_header->bmask);
|
||||||
CHECK_EFI_STATUS_OR_FAIL(status);
|
CHECK_EFI_STATUS_OR_FAIL(status);
|
||||||
|
memory_mark_pointer_fixup((void **)&data_header->frame_buffer);
|
||||||
|
|
||||||
// Save the memory map and tell the firmware we're taking control.
|
// Save the memory map and tell the firmware we're taking control.
|
||||||
//
|
//
|
||||||
@@ -149,11 +163,16 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
|
|||||||
status = memory_get_map(bootsvc, &map);
|
status = memory_get_map(bootsvc, &map);
|
||||||
CHECK_EFI_STATUS_OR_FAIL(status);
|
CHECK_EFI_STATUS_OR_FAIL(status);
|
||||||
|
|
||||||
|
data_header->memory_map_length = map.length;
|
||||||
|
data_header->memory_map_desc_size = map.size;
|
||||||
|
|
||||||
// bootsvc->Stall(5000000);
|
// bootsvc->Stall(5000000);
|
||||||
|
|
||||||
status = bootsvc->ExitBootServices(image_handle, map.key);
|
status = bootsvc->ExitBootServices(image_handle, map.key);
|
||||||
CHECK_EFI_STATUS_OR_ASSERT(status, 0);
|
CHECK_EFI_STATUS_OR_ASSERT(status, 0);
|
||||||
|
|
||||||
|
memory_virtualize(runsvc, &map);
|
||||||
|
|
||||||
// Hand control to the kernel
|
// Hand control to the kernel
|
||||||
//
|
//
|
||||||
kernel_main(data_header);
|
kernel_main(data_header);
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
|
|
||||||
#define INCREMENT_DESC(p, b) (EFI_MEMORY_DESCRIPTOR*)(((uint8_t*)(p))+(b))
|
#define INCREMENT_DESC(p, b) (EFI_MEMORY_DESCRIPTOR*)(((uint8_t*)(p))+(b))
|
||||||
|
|
||||||
|
size_t fixup_pointer_index = 0;
|
||||||
|
void **fixup_pointers[64];
|
||||||
|
uint64_t *new_pml4 = 0;
|
||||||
|
|
||||||
const CHAR16 *memory_type_names[] = {
|
const CHAR16 *memory_type_names[] = {
|
||||||
L"EfiReservedMemoryType",
|
L"EfiReservedMemoryType",
|
||||||
L"EfiLoaderCode",
|
L"EfiLoaderCode",
|
||||||
@@ -37,6 +41,49 @@ memory_type_name(UINT32 value)
|
|||||||
return memory_type_names[value];
|
return memory_type_names[value];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EFIAPI
|
||||||
|
memory_update_marked_addresses(EFI_EVENT UNUSED *event, void *context)
|
||||||
|
{
|
||||||
|
EFI_RUNTIME_SERVICES *runsvc = (EFI_RUNTIME_SERVICES*)context;
|
||||||
|
for (size_t i = 0; i < fixup_pointer_index; ++i) {
|
||||||
|
if (fixup_pointers[i])
|
||||||
|
runsvc->ConvertPointer(0, fixup_pointers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
memory_init_pointer_fixup(EFI_BOOT_SERVICES *bootsvc, EFI_RUNTIME_SERVICES *runsvc)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
EFI_EVENT event;
|
||||||
|
|
||||||
|
status = bootsvc->CreateEvent(
|
||||||
|
EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
|
||||||
|
TPL_CALLBACK,
|
||||||
|
(EFI_EVENT_NOTIFY)&memory_update_marked_addresses,
|
||||||
|
runsvc,
|
||||||
|
&event);
|
||||||
|
|
||||||
|
CHECK_EFI_STATUS_OR_RETURN(status, "Failed to initialize pointer update event.");
|
||||||
|
|
||||||
|
// Reserve a page for our replacement PML4
|
||||||
|
EFI_PHYSICAL_ADDRESS addr = 0;
|
||||||
|
status = bootsvc->AllocatePages(AllocateAnyPages, EfiLoaderData, 4, &addr);
|
||||||
|
CHECK_EFI_STATUS_OR_RETURN(status, "Failed to allocate PML4 page.");
|
||||||
|
|
||||||
|
new_pml4 = (uint64_t *)addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
memory_mark_pointer_fixup(void **p)
|
||||||
|
{
|
||||||
|
if (fixup_pointer_index == 0) {
|
||||||
|
const size_t count = sizeof(fixup_pointers) / sizeof(void*);
|
||||||
|
for (size_t i = 0; i < count; ++i) fixup_pointers[i] = 0;
|
||||||
|
}
|
||||||
|
fixup_pointers[fixup_pointer_index++] = p;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
copy_desc(EFI_MEMORY_DESCRIPTOR *src, EFI_MEMORY_DESCRIPTOR *dst, size_t len)
|
copy_desc(EFI_MEMORY_DESCRIPTOR *src, EFI_MEMORY_DESCRIPTOR *dst, size_t len)
|
||||||
{
|
{
|
||||||
@@ -111,3 +158,48 @@ memory_dump_map(struct memory_map *map)
|
|||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
memory_virtualize(EFI_RUNTIME_SERVICES *runsvc, struct memory_map *map)
|
||||||
|
{
|
||||||
|
memory_mark_pointer_fixup((void **)&runsvc);
|
||||||
|
memory_mark_pointer_fixup((void **)&map);
|
||||||
|
|
||||||
|
// Get the pointer to the start of PML4
|
||||||
|
uint64_t* cr3 = 0;
|
||||||
|
__asm__ __volatile__ ( "mov %%cr3, %0" : "=r" (cr3) );
|
||||||
|
|
||||||
|
// PML4 is indexed with bits 39:47 of the virtual address
|
||||||
|
uint64_t offset = (KERNEL_VIRT_ADDRESS >> 39) & 0x1ff;
|
||||||
|
|
||||||
|
// Double map the lower half pages that are present into the higher half
|
||||||
|
for (unsigned i = 0; i < offset; ++i) {
|
||||||
|
if (cr3[i] & 0x1)
|
||||||
|
new_pml4[i] = new_pml4[offset+i] = cr3[i];
|
||||||
|
else
|
||||||
|
new_pml4[i] = new_pml4[offset+i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write our new PML4 pointer back to CR3
|
||||||
|
__asm__ __volatile__ ( "mov %0, %%cr3" :: "r" (new_pml4) );
|
||||||
|
|
||||||
|
EFI_MEMORY_DESCRIPTOR *end = INCREMENT_DESC(map->entries, map->length);
|
||||||
|
EFI_MEMORY_DESCRIPTOR *d = map->entries;
|
||||||
|
while (d < end) {
|
||||||
|
switch (d->Type) {
|
||||||
|
case KERNEL_MEMTYPE:
|
||||||
|
case KERNEL_FONT_MEMTYPE:
|
||||||
|
case KERNEL_DATA_MEMTYPE:
|
||||||
|
case KERNEL_LOG_MEMTYPE:
|
||||||
|
d->Attribute |= EFI_MEMORY_RUNTIME;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (d->Attribute & EFI_MEMORY_RUNTIME) {
|
||||||
|
d->VirtualStart = d->PhysicalStart + KERNEL_VIRT_ADDRESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d = INCREMENT_DESC(d, map->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
runsvc->SetVirtualAddressMap(map->length, map->size, map->version, map->entries);
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ struct memory_map {
|
|||||||
EFI_MEMORY_DESCRIPTOR *entries;
|
EFI_MEMORY_DESCRIPTOR *entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EFI_STATUS memory_init_pointer_fixup(EFI_BOOT_SERVICES *bootsvc, EFI_RUNTIME_SERVICES *runsvc);
|
||||||
|
void memory_mark_pointer_fixup(void **p);
|
||||||
|
|
||||||
EFI_STATUS memory_get_map_length(EFI_BOOT_SERVICES *bootsvc, size_t *size);
|
EFI_STATUS memory_get_map_length(EFI_BOOT_SERVICES *bootsvc, size_t *size);
|
||||||
EFI_STATUS memory_get_map(EFI_BOOT_SERVICES *bootsvc, struct memory_map *map);
|
EFI_STATUS memory_get_map(EFI_BOOT_SERVICES *bootsvc, struct memory_map *map);
|
||||||
EFI_STATUS memory_dump_map(struct memory_map *map);
|
EFI_STATUS memory_dump_map(struct memory_map *map);
|
||||||
|
|
||||||
|
void memory_virtualize(EFI_RUNTIME_SERVICES *runsvc, struct memory_map *map);
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ struct popcorn_data {
|
|||||||
size_t log_length;
|
size_t log_length;
|
||||||
|
|
||||||
void *memory_map;
|
void *memory_map;
|
||||||
|
size_t memory_map_length;
|
||||||
|
size_t memory_map_desc_size;
|
||||||
|
|
||||||
void *runtime;
|
void *runtime;
|
||||||
|
|
||||||
void *acpi_table;
|
void *acpi_table;
|
||||||
|
|||||||
52
src/kernel/acpi_tables.h
Normal file
52
src/kernel/acpi_tables.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "kutil/coord.h"
|
||||||
|
#include "kutil/misc.h"
|
||||||
|
|
||||||
|
struct acpi_table_header
|
||||||
|
{
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t length;
|
||||||
|
uint8_t revision;
|
||||||
|
uint8_t checksum;
|
||||||
|
char oem_id[6];
|
||||||
|
char oem_table[8];
|
||||||
|
uint32_t oem_revision;
|
||||||
|
uint32_t creator_id;
|
||||||
|
uint32_t creator_revision;
|
||||||
|
|
||||||
|
bool validate(uint32_t expected_type = 0) const;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define TABLE_HEADER(signature) \
|
||||||
|
static const uint32_t type_id = kutil::byteswap(signature); \
|
||||||
|
acpi_table_header header;
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool acpi_validate(const T *t) { return t->header.validate(T::type_id); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
size_t acpi_table_entries(const T *t, size_t size)
|
||||||
|
{
|
||||||
|
return (t->header.length - sizeof(T)) / size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct acpi_xsdt
|
||||||
|
{
|
||||||
|
TABLE_HEADER('XSDT');
|
||||||
|
acpi_table_header *headers[0];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct acpi_apic
|
||||||
|
{
|
||||||
|
TABLE_HEADER('APIC');
|
||||||
|
uint32_t local_address;
|
||||||
|
uint32_t flags;
|
||||||
|
uint8_t controller_data[0];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
29
src/kernel/assert.cpp
Normal file
29
src/kernel/assert.cpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#include "assert.h"
|
||||||
|
#include "console.h"
|
||||||
|
|
||||||
|
[[noreturn]] void
|
||||||
|
__kernel_assert(const char *file, unsigned line, const char *message)
|
||||||
|
{
|
||||||
|
console *cons = console::get();
|
||||||
|
if (cons) {
|
||||||
|
cons->set_color(9 , 0);
|
||||||
|
cons->puts("\n\n ERROR: ");
|
||||||
|
cons->puts(file);
|
||||||
|
cons->puts(":");
|
||||||
|
cons->put_dec(line);
|
||||||
|
cons->puts(": ");
|
||||||
|
cons->puts(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"movq %0, %%r8;"
|
||||||
|
"movq %1, %%r9;"
|
||||||
|
"movq %2, %%r10;"
|
||||||
|
"movq $0, %%rdx;"
|
||||||
|
"divq %%rdx;"
|
||||||
|
: // no outputs
|
||||||
|
: "r"((uint64_t)line), "r"(file), "r"(message)
|
||||||
|
: "rax", "rdx", "r8", "r9", "r10");
|
||||||
|
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
5
src/kernel/assert.h
Normal file
5
src/kernel/assert.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
[[noreturn]] void __kernel_assert(const char *file, unsigned line, const char *message);
|
||||||
|
|
||||||
|
#define kassert(stmt, message) if(!(stmt)) { __kernel_assert(__FILE__, __LINE__, (message)); } else {}
|
||||||
@@ -17,6 +17,8 @@ section .text
|
|||||||
align 16
|
align 16
|
||||||
global _start:function (_start.end - _start)
|
global _start:function (_start.end - _start)
|
||||||
_start:
|
_start:
|
||||||
|
cli
|
||||||
|
|
||||||
extern kernel_main
|
extern kernel_main
|
||||||
call kernel_main
|
call kernel_main
|
||||||
|
|
||||||
@@ -26,3 +28,13 @@ _start:
|
|||||||
hlt
|
hlt
|
||||||
jmp .hang
|
jmp .hang
|
||||||
.end:
|
.end:
|
||||||
|
|
||||||
|
global interrupts_enable
|
||||||
|
interrupts_enable:
|
||||||
|
sti
|
||||||
|
ret
|
||||||
|
|
||||||
|
global interrupts_disable
|
||||||
|
interrupts_disable:
|
||||||
|
cli
|
||||||
|
ret
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
const char digits[] = "0123456789abcdef";
|
const char digits[] = "0123456789abcdef";
|
||||||
|
|
||||||
|
console *console::default_console = nullptr;
|
||||||
|
|
||||||
console::console(const font &f, const screen &s, void *scratch, size_t len) :
|
console::console(const font &f, const screen &s, void *scratch, size_t len) :
|
||||||
m_font(f),
|
m_font(f),
|
||||||
m_screen(s),
|
m_screen(s),
|
||||||
@@ -73,6 +75,9 @@ console::console(const font &f, const screen &s, void *scratch, size_t len) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
repaint();
|
repaint();
|
||||||
|
|
||||||
|
if (default_console == nullptr)
|
||||||
|
default_console = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "kutil/coord.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
struct console_data;
|
struct console_data;
|
||||||
|
|
||||||
@@ -22,7 +22,10 @@ public:
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
void put_hex(T x);
|
void put_hex(T x);
|
||||||
|
|
||||||
void put_dec(uint32_t x);
|
template <typename T>
|
||||||
|
void put_dec(T x);
|
||||||
|
|
||||||
|
static console * get() { return default_console; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char * line_pointer(unsigned line);
|
char * line_pointer(unsigned line);
|
||||||
@@ -31,8 +34,8 @@ private:
|
|||||||
font m_font;
|
font m_font;
|
||||||
screen m_screen;
|
screen m_screen;
|
||||||
|
|
||||||
coord<unsigned> m_size;
|
kutil::coord<unsigned> m_size;
|
||||||
coord<unsigned> m_pos;
|
kutil::coord<unsigned> m_pos;
|
||||||
screen::pixel_t m_fg, m_bg;
|
screen::pixel_t m_fg, m_bg;
|
||||||
uint16_t m_attr;
|
uint16_t m_attr;
|
||||||
|
|
||||||
@@ -42,6 +45,8 @@ private:
|
|||||||
char *m_data;
|
char *m_data;
|
||||||
uint16_t *m_attrs;
|
uint16_t *m_attrs;
|
||||||
screen::pixel_t *m_palette;
|
screen::pixel_t *m_palette;
|
||||||
|
|
||||||
|
static console *default_console;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const char digits[];
|
extern const char digits[];
|
||||||
@@ -57,3 +62,17 @@ void console::put_hex(T x)
|
|||||||
message[chars] = 0;
|
message[chars] = 0;
|
||||||
puts(message);
|
puts(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void console::put_dec(T x)
|
||||||
|
{
|
||||||
|
static const int chars = sizeof(x) * 3;
|
||||||
|
char message[chars + 1];
|
||||||
|
char *p = message + chars;
|
||||||
|
*p-- = 0;
|
||||||
|
do {
|
||||||
|
*p-- = digits[x % 10];
|
||||||
|
x /= 10;
|
||||||
|
} while (x != 0);
|
||||||
|
puts(++p);
|
||||||
|
}
|
||||||
156
src/kernel/device_manager.cpp
Normal file
156
src/kernel/device_manager.cpp
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "kutil/memory.h"
|
||||||
|
#include "acpi_tables.h"
|
||||||
|
#include "assert.h"
|
||||||
|
#include "device_manager.h"
|
||||||
|
#include "console.h"
|
||||||
|
|
||||||
|
static const char expected_signature[] = "RSD PTR ";
|
||||||
|
|
||||||
|
struct acpi1_rsdp
|
||||||
|
{
|
||||||
|
char signature[8];
|
||||||
|
uint8_t checksum;
|
||||||
|
char oem_id[6];
|
||||||
|
uint8_t revision;
|
||||||
|
uint32_t rsdt_address;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct acpi2_rsdp
|
||||||
|
{
|
||||||
|
char signature[8];
|
||||||
|
uint8_t checksum10;
|
||||||
|
char oem_id[6];
|
||||||
|
uint8_t revision;
|
||||||
|
uint32_t rsdt_address;
|
||||||
|
|
||||||
|
uint32_t length;
|
||||||
|
uint64_t xsdt_address;
|
||||||
|
uint8_t checksum20;
|
||||||
|
uint8_t reserved[3];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
acpi_checksum(const void *p, size_t len, size_t off = 0)
|
||||||
|
{
|
||||||
|
uint8_t sum = 0;
|
||||||
|
const uint8_t *c = reinterpret_cast<const uint8_t *>(p);
|
||||||
|
for (int i = off; i < len; ++i) sum += c[i];
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
acpi_table_header::validate(uint32_t expected_type) const
|
||||||
|
{
|
||||||
|
if (acpi_checksum(this, length) != 0) return false;
|
||||||
|
return !expected_type || (expected_type == type);
|
||||||
|
}
|
||||||
|
|
||||||
|
device_manager::device_manager(const void *root_table) :
|
||||||
|
m_local_apic(nullptr)
|
||||||
|
{
|
||||||
|
console *cons = console::get();
|
||||||
|
|
||||||
|
kassert(root_table != 0, "ACPI root table pointer is null.");
|
||||||
|
|
||||||
|
const acpi1_rsdp *acpi1 =
|
||||||
|
reinterpret_cast<const acpi1_rsdp *>(root_table);
|
||||||
|
|
||||||
|
for (int i = 0; i < sizeof(acpi1->signature); ++i)
|
||||||
|
kassert(acpi1->signature[i] == expected_signature[i],
|
||||||
|
"ACPI RSDP table signature mismatch");
|
||||||
|
|
||||||
|
uint8_t sum = acpi_checksum(acpi1, sizeof(acpi1_rsdp), 0);
|
||||||
|
kassert(sum == 0, "ACPI 1.0 RSDP checksum mismatch.");
|
||||||
|
|
||||||
|
kassert(acpi1->revision > 1, "ACPI 1.0 not supported.");
|
||||||
|
|
||||||
|
const acpi2_rsdp *acpi2 =
|
||||||
|
reinterpret_cast<const acpi2_rsdp *>(acpi1);
|
||||||
|
|
||||||
|
sum = acpi_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));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
put_sig(console *cons, uint32_t type)
|
||||||
|
{
|
||||||
|
char sig[5] = {0,0,0,0,0};
|
||||||
|
for (int j=0; j<4; ++j)
|
||||||
|
sig[j] = reinterpret_cast<char *>(&type)[j];
|
||||||
|
cons->puts(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
device_manager::load_xsdt(const acpi_xsdt *xsdt)
|
||||||
|
{
|
||||||
|
kassert(xsdt && acpi_validate(xsdt), "Invalid ACPI XSDT.");
|
||||||
|
|
||||||
|
console *cons = console::get();
|
||||||
|
cons->puts("ACPI 2.0 tables loading: ");
|
||||||
|
put_sig(cons, xsdt->header.type);
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
cons->puts(" ");
|
||||||
|
put_sig(cons, header->type);
|
||||||
|
|
||||||
|
kassert(header->validate(), "Table failed validation.");
|
||||||
|
|
||||||
|
switch (header->type) {
|
||||||
|
case acpi_apic::type_id:
|
||||||
|
load_apic(reinterpret_cast<const acpi_apic *>(header));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cons->puts("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
device_manager::load_apic(const acpi_apic *apic)
|
||||||
|
{
|
||||||
|
console *cons = console::get();
|
||||||
|
|
||||||
|
m_local_apic = reinterpret_cast<uint32_t *>(apic->local_address);
|
||||||
|
cons->puts(" ");
|
||||||
|
cons->put_hex(apic->local_address);
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t const *p = apic->controller_data;
|
||||||
|
uint8_t const *end = p + acpi_table_entries(apic, 1);
|
||||||
|
|
||||||
|
while (p < end) {
|
||||||
|
const uint8_t type = p[0];
|
||||||
|
const uint8_t length = p[1];
|
||||||
|
|
||||||
|
cons->puts(" ");
|
||||||
|
cons->put_hex(type);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 0: // Local APIC
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: // I/O APIC
|
||||||
|
m_io_apic = reinterpret_cast<uint32_t *>(kutil::read_from<uint32_t>(p+4));
|
||||||
|
m_global_interrupt_base = kutil::read_from<uint32_t>(p+8);
|
||||||
|
cons->puts(" ");
|
||||||
|
cons->put_hex((uint64_t)m_io_apic);
|
||||||
|
cons->puts(" ");
|
||||||
|
cons->put_hex(m_global_interrupt_base);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += length;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/kernel/device_manager.h
Normal file
25
src/kernel/device_manager.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct acpi_xsdt;
|
||||||
|
struct acpi_apic;
|
||||||
|
|
||||||
|
class device_manager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
device_manager(const void *root_table);
|
||||||
|
|
||||||
|
device_manager() = delete;
|
||||||
|
device_manager(const device_manager &) = delete;
|
||||||
|
|
||||||
|
uint8_t * local_apic() const;
|
||||||
|
uint8_t * io_apic() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t *m_local_apic;
|
||||||
|
uint32_t *m_io_apic;
|
||||||
|
|
||||||
|
uint32_t m_global_interrupt_base;
|
||||||
|
|
||||||
|
void load_xsdt(const acpi_xsdt *xsdt);
|
||||||
|
void load_apic(const acpi_apic *apic);
|
||||||
|
};
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "kutil/coord.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
class font
|
class font
|
||||||
{
|
{
|
||||||
@@ -28,7 +28,7 @@ private:
|
|||||||
font();
|
font();
|
||||||
font(unsigned height, unsigned width, unsigned count, uint8_t const *data);
|
font(unsigned height, unsigned width, unsigned count, uint8_t const *data);
|
||||||
|
|
||||||
coord<unsigned> m_size;
|
kutil::coord<unsigned> m_size;
|
||||||
unsigned m_count;
|
unsigned m_count;
|
||||||
uint8_t const *m_data;
|
uint8_t const *m_data;
|
||||||
};
|
};
|
||||||
51
src/kernel/interrupt_isrs.inc
Normal file
51
src/kernel/interrupt_isrs.inc
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
ISR ( 0, isr0);
|
||||||
|
ISR ( 1, isr1);
|
||||||
|
ISR ( 2, isr2);
|
||||||
|
ISR ( 3, isr3);
|
||||||
|
ISR ( 4, isr4);
|
||||||
|
ISR ( 5, isr5);
|
||||||
|
ISR ( 6, isr6);
|
||||||
|
ISR ( 7, isr7);
|
||||||
|
EISR( 8, isr8);
|
||||||
|
ISR ( 9, isr9);
|
||||||
|
EISR(10, isr10);
|
||||||
|
EISR(11, isr11);
|
||||||
|
EISR(12, isr12);
|
||||||
|
EISR(13, isr13);
|
||||||
|
EISR(14, isr14);
|
||||||
|
ISR (15, isr15);
|
||||||
|
ISR (16, isr16);
|
||||||
|
ISR (17, isr17);
|
||||||
|
ISR (18, isr18);
|
||||||
|
ISR (19, isr19);
|
||||||
|
ISR (20, isr20);
|
||||||
|
ISR (21, isr21);
|
||||||
|
ISR (22, isr22);
|
||||||
|
ISR (23, isr23);
|
||||||
|
ISR (24, isr24);
|
||||||
|
ISR (25, isr25);
|
||||||
|
ISR (26, isr26);
|
||||||
|
ISR (27, isr27);
|
||||||
|
ISR (28, isr28);
|
||||||
|
ISR (29, isr29);
|
||||||
|
ISR (30, isr30);
|
||||||
|
ISR (31, isr31);
|
||||||
|
|
||||||
|
IRQ (64, 0, irq0);
|
||||||
|
IRQ (65, 1, irq1);
|
||||||
|
IRQ (66, 2, irq2);
|
||||||
|
IRQ (67, 3, irq3);
|
||||||
|
IRQ (68, 4, irq4);
|
||||||
|
IRQ (69, 5, irq5);
|
||||||
|
IRQ (70, 6, irq6);
|
||||||
|
IRQ (71, 7, irq7);
|
||||||
|
IRQ (72, 8, irq8);
|
||||||
|
IRQ (73, 9, irq9);
|
||||||
|
IRQ (74, 10, irq10);
|
||||||
|
IRQ (75, 11, irq11);
|
||||||
|
IRQ (76, 12, irq12);
|
||||||
|
IRQ (77, 13, irq13);
|
||||||
|
IRQ (78, 14, irq14);
|
||||||
|
IRQ (79, 15, irq15);
|
||||||
|
|
||||||
|
ISR (0xff, isrSpurious);
|
||||||
353
src/kernel/interrupts.cpp
Normal file
353
src/kernel/interrupts.cpp
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "kutil/memory.h"
|
||||||
|
#include "console.h"
|
||||||
|
#include "interrupts.h"
|
||||||
|
|
||||||
|
enum class gdt_flags : uint8_t
|
||||||
|
{
|
||||||
|
ac = 0x01,
|
||||||
|
rw = 0x02,
|
||||||
|
dc = 0x04,
|
||||||
|
ex = 0x08,
|
||||||
|
r1 = 0x20,
|
||||||
|
r2 = 0x40,
|
||||||
|
r3 = 0x60,
|
||||||
|
pr = 0x80,
|
||||||
|
|
||||||
|
res_1 = 0x10
|
||||||
|
};
|
||||||
|
|
||||||
|
inline gdt_flags
|
||||||
|
operator | (gdt_flags lhs, gdt_flags rhs)
|
||||||
|
{
|
||||||
|
return static_cast<gdt_flags>(
|
||||||
|
static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct gdt_descriptor
|
||||||
|
{
|
||||||
|
uint16_t limit_low;
|
||||||
|
uint16_t base_low;
|
||||||
|
uint8_t base_mid;
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t granularity;
|
||||||
|
uint8_t base_high;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct idt_descriptor
|
||||||
|
{
|
||||||
|
uint16_t base_low;
|
||||||
|
uint16_t selector;
|
||||||
|
uint8_t ist;
|
||||||
|
uint8_t flags;
|
||||||
|
uint16_t base_mid;
|
||||||
|
uint32_t base_high;
|
||||||
|
uint32_t reserved; // must be zero
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct table_ptr
|
||||||
|
{
|
||||||
|
uint16_t limit;
|
||||||
|
uint64_t base;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
gdt_descriptor g_gdt_table[10];
|
||||||
|
idt_descriptor g_idt_table[256];
|
||||||
|
table_ptr g_gdtr;
|
||||||
|
table_ptr g_idtr;
|
||||||
|
|
||||||
|
|
||||||
|
struct registers;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void idt_write();
|
||||||
|
void idt_load();
|
||||||
|
|
||||||
|
void gdt_write();
|
||||||
|
void gdt_load();
|
||||||
|
|
||||||
|
void isr_handler(registers);
|
||||||
|
void irq_handler(registers);
|
||||||
|
|
||||||
|
#define ISR(i, name) extern void name ()
|
||||||
|
#define EISR(i, name) extern void name ()
|
||||||
|
#define IRQ(i, q, name) extern void name ()
|
||||||
|
#include "interrupt_isrs.inc"
|
||||||
|
#undef IRQ
|
||||||
|
#undef EISR
|
||||||
|
#undef ISR
|
||||||
|
}
|
||||||
|
|
||||||
|
void idt_dump(const table_ptr &table);
|
||||||
|
void gdt_dump(const table_ptr &table);
|
||||||
|
|
||||||
|
void
|
||||||
|
set_gdt_entry(uint8_t i, uint32_t base, uint32_t limit, bool is64, gdt_flags flags)
|
||||||
|
{
|
||||||
|
g_gdt_table[i].limit_low = limit & 0xffff;
|
||||||
|
|
||||||
|
g_gdt_table[i].base_low = base & 0xffff;
|
||||||
|
g_gdt_table[i].base_mid = (base >> 16) & 0xff;
|
||||||
|
g_gdt_table[i].base_high = (base >> 24) & 0xff;
|
||||||
|
|
||||||
|
g_gdt_table[i].granularity =
|
||||||
|
((limit >> 16) & 0xf) | (is64 ? 0xa0 : 0xc0);
|
||||||
|
|
||||||
|
g_gdt_table[i].flags = static_cast<uint8_t>(flags | gdt_flags::res_1 | gdt_flags::pr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set_idt_entry(uint8_t i, uint64_t addr, uint16_t selector, uint8_t flags)
|
||||||
|
{
|
||||||
|
g_idt_table[i].base_low = addr & 0xffff;
|
||||||
|
g_idt_table[i].base_mid = (addr >> 16) & 0xffff;
|
||||||
|
g_idt_table[i].base_high = (addr >> 32) & 0xffffffff;
|
||||||
|
g_idt_table[i].selector = selector;
|
||||||
|
g_idt_table[i].flags = flags;
|
||||||
|
g_idt_table[i].ist = 0;
|
||||||
|
g_idt_table[i].reserved = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
interrupts_init()
|
||||||
|
{
|
||||||
|
kutil::memset(&g_gdt_table, 0, sizeof(g_gdt_table));
|
||||||
|
kutil::memset(&g_idt_table, 0, sizeof(g_idt_table));
|
||||||
|
|
||||||
|
g_gdtr.limit = sizeof(g_gdt_table) - 1;
|
||||||
|
g_gdtr.base = reinterpret_cast<uint64_t>(&g_gdt_table);
|
||||||
|
|
||||||
|
set_gdt_entry(1, 0, 0xfffff, false, gdt_flags::rw);
|
||||||
|
set_gdt_entry(2, 0, 0xfffff, false, gdt_flags::rw | gdt_flags::ex | gdt_flags::dc);
|
||||||
|
set_gdt_entry(3, 0, 0xfffff, false, gdt_flags::rw);
|
||||||
|
set_gdt_entry(4, 0, 0xfffff, false, gdt_flags::rw | gdt_flags::ex);
|
||||||
|
|
||||||
|
set_gdt_entry(6, 0, 0xfffff, false, gdt_flags::rw);
|
||||||
|
set_gdt_entry(7, 0, 0xfffff, true, gdt_flags::rw | gdt_flags::ex);
|
||||||
|
|
||||||
|
gdt_write();
|
||||||
|
|
||||||
|
g_idtr.limit = sizeof(g_idt_table) - 1;
|
||||||
|
g_idtr.base = reinterpret_cast<uint64_t>(&g_idt_table);
|
||||||
|
|
||||||
|
#define ISR(i, name) set_idt_entry(i, reinterpret_cast<uint64_t>(& name), 0x38, 0x8e);
|
||||||
|
#define EISR(i, name) set_idt_entry(i, reinterpret_cast<uint64_t>(& name), 0x38, 0x8e);
|
||||||
|
#define IRQ(i, q, name) set_idt_entry(i, reinterpret_cast<uint64_t>(& name), 0x38, 0x8e);
|
||||||
|
#include "interrupt_isrs.inc"
|
||||||
|
#undef IRQ
|
||||||
|
#undef EISR
|
||||||
|
#undef ISR
|
||||||
|
|
||||||
|
idt_write();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct registers
|
||||||
|
{
|
||||||
|
uint64_t ds;
|
||||||
|
uint64_t rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax;
|
||||||
|
uint64_t interrupt, errorcode;
|
||||||
|
uint64_t rip, cs, eflags, user_esp, ss;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define print_reg(name, value) \
|
||||||
|
cons->puts(" " name ": "); \
|
||||||
|
cons->put_hex((value)); \
|
||||||
|
cons->puts("\n");
|
||||||
|
|
||||||
|
void
|
||||||
|
isr_handler(registers regs)
|
||||||
|
{
|
||||||
|
console *cons = console::get();
|
||||||
|
|
||||||
|
cons->puts("received ISR interrupt:\n");
|
||||||
|
|
||||||
|
print_reg("ISR", regs.interrupt);
|
||||||
|
print_reg("ERR", regs.errorcode);
|
||||||
|
console::get()->puts("\n");
|
||||||
|
|
||||||
|
print_reg(" ds", regs.ds);
|
||||||
|
print_reg("rdi", regs.rdi);
|
||||||
|
print_reg("rsi", regs.rsi);
|
||||||
|
print_reg("rbp", regs.rbp);
|
||||||
|
print_reg("rsp", regs.rsp);
|
||||||
|
print_reg("rbx", regs.rbx);
|
||||||
|
print_reg("rdx", regs.rdx);
|
||||||
|
print_reg("rcx", regs.rcx);
|
||||||
|
print_reg("rax", regs.rax);
|
||||||
|
console::get()->puts("\n");
|
||||||
|
|
||||||
|
print_reg("rip", regs.rip);
|
||||||
|
print_reg(" cs", regs.cs);
|
||||||
|
print_reg(" ef", regs.eflags);
|
||||||
|
print_reg("esp", regs.user_esp);
|
||||||
|
print_reg(" ss", regs.ss);
|
||||||
|
while(1) asm("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
irq_handler(registers regs)
|
||||||
|
{
|
||||||
|
console *cons = console::get();
|
||||||
|
|
||||||
|
cons->puts("received IRQ interrupt:\n");
|
||||||
|
|
||||||
|
print_reg("ISR", regs.interrupt);
|
||||||
|
print_reg("ERR", regs.errorcode);
|
||||||
|
console::get()->puts("\n");
|
||||||
|
|
||||||
|
print_reg(" ds", regs.ds);
|
||||||
|
print_reg("rdi", regs.rdi);
|
||||||
|
print_reg("rsi", regs.rsi);
|
||||||
|
print_reg("rbp", regs.rbp);
|
||||||
|
print_reg("rsp", regs.rsp);
|
||||||
|
print_reg("rbx", regs.rbx);
|
||||||
|
print_reg("rdx", regs.rdx);
|
||||||
|
print_reg("rcx", regs.rcx);
|
||||||
|
print_reg("rax", regs.rax);
|
||||||
|
console::get()->puts("\n");
|
||||||
|
|
||||||
|
print_reg("rip", regs.rip);
|
||||||
|
print_reg(" cs", regs.cs);
|
||||||
|
print_reg(" ef", regs.eflags);
|
||||||
|
print_reg("esp", regs.user_esp);
|
||||||
|
print_reg(" ss", regs.ss);
|
||||||
|
while(1) asm("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
gdt_dump(const table_ptr &table)
|
||||||
|
{
|
||||||
|
console *cons = console::get();
|
||||||
|
|
||||||
|
cons->puts("Loaded GDT at: ");
|
||||||
|
cons->put_hex(table.base);
|
||||||
|
cons->puts(" size: ");
|
||||||
|
cons->put_dec(table.limit + 1);
|
||||||
|
cons->puts(" bytes\n");
|
||||||
|
|
||||||
|
int count = (table.limit + 1) / sizeof(gdt_descriptor);
|
||||||
|
const gdt_descriptor *gdt =
|
||||||
|
reinterpret_cast<const gdt_descriptor *>(table.base);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
uint32_t base =
|
||||||
|
(gdt[i].base_high << 24) |
|
||||||
|
(gdt[i].base_mid << 16) |
|
||||||
|
gdt[i].base_low;
|
||||||
|
|
||||||
|
uint32_t limit =
|
||||||
|
static_cast<uint32_t>(gdt[i].granularity & 0x0f) << 16 |
|
||||||
|
gdt[i].limit_low;
|
||||||
|
|
||||||
|
cons->puts(" Entry ");
|
||||||
|
cons->put_dec(i);
|
||||||
|
|
||||||
|
cons->puts(": Base ");
|
||||||
|
cons->put_hex(base);
|
||||||
|
|
||||||
|
cons->puts(" Limit ");
|
||||||
|
cons->put_hex(limit);
|
||||||
|
|
||||||
|
cons->puts(" Privs ");
|
||||||
|
cons->put_dec((gdt[i].flags >> 5) & 0x03);
|
||||||
|
|
||||||
|
cons->puts(" Flags ");
|
||||||
|
|
||||||
|
if (gdt[i].flags & 0x80) {
|
||||||
|
cons->puts("P ");
|
||||||
|
|
||||||
|
if (gdt[i].flags & 0x08)
|
||||||
|
cons->puts("EX ");
|
||||||
|
else
|
||||||
|
cons->puts(" ");
|
||||||
|
|
||||||
|
if (gdt[i].flags & 0x04)
|
||||||
|
cons->puts("DC ");
|
||||||
|
else
|
||||||
|
cons->puts(" ");
|
||||||
|
|
||||||
|
if (gdt[i].flags & 0x02)
|
||||||
|
cons->puts("RW ");
|
||||||
|
else
|
||||||
|
cons->puts(" ");
|
||||||
|
|
||||||
|
if (gdt[i].granularity & 0x80)
|
||||||
|
cons->puts("KB ");
|
||||||
|
else
|
||||||
|
cons->puts(" B ");
|
||||||
|
|
||||||
|
if ((gdt[i].granularity & 0x60) == 0x20)
|
||||||
|
cons->puts("64");
|
||||||
|
else if ((gdt[i].granularity & 0x60) == 0x40)
|
||||||
|
cons->puts("32");
|
||||||
|
else
|
||||||
|
cons->puts("16");
|
||||||
|
}
|
||||||
|
|
||||||
|
cons->puts("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
idt_dump(const table_ptr &table)
|
||||||
|
{
|
||||||
|
console *cons = console::get();
|
||||||
|
|
||||||
|
cons->puts("Loaded IDT at: ");
|
||||||
|
cons->put_hex(table.base);
|
||||||
|
cons->puts(" size: ");
|
||||||
|
cons->put_dec(table.limit + 1);
|
||||||
|
cons->puts(" bytes\n");
|
||||||
|
|
||||||
|
int count = (table.limit + 1) / sizeof(idt_descriptor);
|
||||||
|
const idt_descriptor *idt =
|
||||||
|
reinterpret_cast<const idt_descriptor *>(table.base);
|
||||||
|
|
||||||
|
if (count > 32) count = 32;
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
uint64_t base =
|
||||||
|
(static_cast<uint64_t>(idt[i].base_high) << 32) |
|
||||||
|
(static_cast<uint64_t>(idt[i].base_mid) << 16) |
|
||||||
|
idt[i].base_low;
|
||||||
|
|
||||||
|
cons->puts(" Entry ");
|
||||||
|
cons->put_dec(i);
|
||||||
|
|
||||||
|
cons->puts(": Base ");
|
||||||
|
cons->put_hex(base);
|
||||||
|
|
||||||
|
cons->puts(" Sel(");
|
||||||
|
cons->put_dec(idt[i].selector & 0x3);
|
||||||
|
cons->puts(",");
|
||||||
|
cons->put_dec((idt[i].selector & 0x4) >> 2);
|
||||||
|
cons->puts(",");
|
||||||
|
cons->put_dec(idt[i].selector >> 3);
|
||||||
|
cons->puts(") ");
|
||||||
|
|
||||||
|
cons->puts("IST ");
|
||||||
|
cons->put_dec(idt[i].ist);
|
||||||
|
|
||||||
|
switch (idt[i].flags & 0xf) {
|
||||||
|
case 0x5: cons->puts(" 32tsk "); break;
|
||||||
|
case 0x6: cons->puts(" 16int "); break;
|
||||||
|
case 0x7: cons->puts(" 16trp "); break;
|
||||||
|
case 0xe: cons->puts(" 32int "); break;
|
||||||
|
case 0xf: cons->puts(" 32trp "); break;
|
||||||
|
default:
|
||||||
|
cons->puts(" ?");
|
||||||
|
cons->put_hex(idt[i].flags & 0xf);
|
||||||
|
cons->puts(" ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cons->puts("DPL ");
|
||||||
|
cons->put_dec((idt[i].flags >> 5) & 0x3);
|
||||||
|
|
||||||
|
if (idt[i].flags & 0x80)
|
||||||
|
cons->puts(" P");
|
||||||
|
|
||||||
|
cons->puts("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/kernel/interrupts.h
Normal file
8
src/kernel/interrupts.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void interrupts_enable();
|
||||||
|
void interrupts_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void interrupts_init();
|
||||||
121
src/kernel/interrupts.s
Normal file
121
src/kernel/interrupts.s
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
extern g_idtr
|
||||||
|
extern g_gdtr
|
||||||
|
|
||||||
|
global idt_write
|
||||||
|
idt_write:
|
||||||
|
lidt [rel g_idtr]
|
||||||
|
ret
|
||||||
|
|
||||||
|
global idt_load
|
||||||
|
idt_load:
|
||||||
|
sidt [rel g_idtr]
|
||||||
|
ret
|
||||||
|
|
||||||
|
global gdt_write
|
||||||
|
gdt_write:
|
||||||
|
lgdt [rel g_gdtr]
|
||||||
|
ret
|
||||||
|
|
||||||
|
global gdt_load
|
||||||
|
gdt_load:
|
||||||
|
sgdt [rel g_gdtr]
|
||||||
|
ret
|
||||||
|
|
||||||
|
%macro push_all_and_segments 0
|
||||||
|
push rax
|
||||||
|
push rcx
|
||||||
|
push rdx
|
||||||
|
push rbx
|
||||||
|
push rsp
|
||||||
|
push rbp
|
||||||
|
push rsi
|
||||||
|
push rdi
|
||||||
|
|
||||||
|
mov ax, ds
|
||||||
|
push rax
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro pop_all_and_segments 0
|
||||||
|
pop rax
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
|
||||||
|
pop rdi
|
||||||
|
pop rsi
|
||||||
|
pop rbp
|
||||||
|
pop rsp
|
||||||
|
pop rbx
|
||||||
|
pop rdx
|
||||||
|
pop rcx
|
||||||
|
pop rax
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro load_kernel_segments 0
|
||||||
|
mov ax, 0x10 ; load the kernel data segment
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
extern isr_handler
|
||||||
|
global isr_handler_prelude
|
||||||
|
isr_handler_prelude:
|
||||||
|
push_all_and_segments
|
||||||
|
load_kernel_segments
|
||||||
|
|
||||||
|
call isr_handler
|
||||||
|
|
||||||
|
pop_all_and_segments
|
||||||
|
|
||||||
|
add rsp, 16 ; because the ISRs added err/num
|
||||||
|
sti
|
||||||
|
iretq
|
||||||
|
|
||||||
|
extern irq_handler
|
||||||
|
global irq_handler_prelude
|
||||||
|
irq_handler_prelude:
|
||||||
|
push_all_and_segments
|
||||||
|
load_kernel_segments
|
||||||
|
|
||||||
|
call irq_handler
|
||||||
|
|
||||||
|
pop_all_and_segments
|
||||||
|
|
||||||
|
add rsp, 16 ; because the ISRs added err/num
|
||||||
|
sti
|
||||||
|
iretq
|
||||||
|
|
||||||
|
%macro EMIT_ISR 2
|
||||||
|
global %1
|
||||||
|
%1:
|
||||||
|
cli
|
||||||
|
push byte 0
|
||||||
|
push byte %2
|
||||||
|
jmp isr_handler_prelude
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro EMIT_EISR 2
|
||||||
|
global %1
|
||||||
|
%1:
|
||||||
|
cli
|
||||||
|
push byte %2
|
||||||
|
jmp isr_handler_prelude
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%macro EMIT_IRQ 2
|
||||||
|
global %1
|
||||||
|
%1:
|
||||||
|
cli
|
||||||
|
push byte 0
|
||||||
|
push byte %2
|
||||||
|
jmp irq_handler_prelude
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%define EISR(i, name) EMIT_EISR name, i
|
||||||
|
%define ISR(i, name) EMIT_ISR name, i
|
||||||
|
%define IRQ(i, q, name) EMIT_IRQ name, i
|
||||||
|
|
||||||
|
%include "interrupt_isrs.inc"
|
||||||
@@ -2,8 +2,11 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
|
#include "device_manager.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
#include "interrupts.h"
|
||||||
#include "kernel_data.h"
|
#include "kernel_data.h"
|
||||||
|
#include "memory.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -14,7 +17,7 @@ extern "C" {
|
|||||||
console
|
console
|
||||||
load_console(const popcorn_data *header)
|
load_console(const popcorn_data *header)
|
||||||
{
|
{
|
||||||
return console{
|
console cons{
|
||||||
font::load(header->font),
|
font::load(header->font),
|
||||||
screen{
|
screen{
|
||||||
header->frame_buffer,
|
header->frame_buffer,
|
||||||
@@ -25,6 +28,13 @@ load_console(const popcorn_data *header)
|
|||||||
header->bmask},
|
header->bmask},
|
||||||
header->log,
|
header->log,
|
||||||
header->log_length};
|
header->log_length};
|
||||||
|
|
||||||
|
cons.set_color(0x21, 0x00);
|
||||||
|
cons.puts("Popcorn OS ");
|
||||||
|
cons.set_color(0x08, 0x00);
|
||||||
|
cons.puts(GIT_VERSION " booting...\n");
|
||||||
|
|
||||||
|
return cons;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -32,10 +42,21 @@ kernel_main(popcorn_data *header)
|
|||||||
{
|
{
|
||||||
console cons = load_console(header);
|
console cons = load_console(header);
|
||||||
|
|
||||||
cons.set_color(0x21, 0x00);
|
memory_manager::create(
|
||||||
cons.puts("Popcorn OS ");
|
header->memory_map,
|
||||||
cons.set_color(0x08, 0x00);
|
header->memory_map_length,
|
||||||
cons.puts(GIT_VERSION " booting...\n");
|
header->memory_map_desc_size);
|
||||||
|
|
||||||
|
interrupts_init();
|
||||||
|
interrupts_enable();
|
||||||
|
|
||||||
|
cons.puts("Interrupts initialized.\n");
|
||||||
|
|
||||||
|
device_manager devices(header->acpi_table);
|
||||||
|
|
||||||
|
// int x = 1 / 0;
|
||||||
|
// __asm__ __volatile__("int $15");
|
||||||
|
|
||||||
|
cons.puts("boogity!");
|
||||||
do_the_set_registers(header);
|
do_the_set_registers(header);
|
||||||
}
|
}
|
||||||
10
src/kernel/memory.cpp
Normal file
10
src/kernel/memory.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include "assert.h"
|
||||||
|
#include "console.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "memory_pages.h"
|
||||||
|
|
||||||
|
memory_manager *memory_manager::s_instance = nullptr;
|
||||||
|
|
||||||
|
memory_manager::memory_manager(page_block *free, page_block *used, void *scratch, size_t scratch_len)
|
||||||
|
{
|
||||||
|
}
|
||||||
21
src/kernel/memory.h
Normal file
21
src/kernel/memory.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct page_block;
|
||||||
|
|
||||||
|
class memory_manager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static void create(const void *memory_map, size_t map_length, size_t desc_length);
|
||||||
|
static memory_manager * get() { return s_instance; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
memory_manager(page_block *free, page_block *used, void *scratch, size_t scratch_len);
|
||||||
|
|
||||||
|
memory_manager() = delete;
|
||||||
|
memory_manager(const memory_manager &) = delete;
|
||||||
|
|
||||||
|
static memory_manager * s_instance;
|
||||||
|
};
|
||||||
296
src/kernel/memory_bootstrap.cpp
Normal file
296
src/kernel/memory_bootstrap.cpp
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
#include "assert.h"
|
||||||
|
#include "console.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "memory_pages.h"
|
||||||
|
|
||||||
|
enum class efi_memory_type : uint32_t
|
||||||
|
{
|
||||||
|
reserved,
|
||||||
|
loader_code,
|
||||||
|
loader_data,
|
||||||
|
boot_services_code,
|
||||||
|
boot_services_data,
|
||||||
|
runtime_services_code,
|
||||||
|
runtime_services_data,
|
||||||
|
available,
|
||||||
|
unusable,
|
||||||
|
acpi_reclaim,
|
||||||
|
acpi_nvs,
|
||||||
|
mmio,
|
||||||
|
mmio_port,
|
||||||
|
pal_code,
|
||||||
|
persistent,
|
||||||
|
|
||||||
|
efi_max,
|
||||||
|
|
||||||
|
popcorn_kernel = 0x80000000,
|
||||||
|
popcorn_font,
|
||||||
|
popcorn_data,
|
||||||
|
popcorn_log,
|
||||||
|
popcorn_pml4,
|
||||||
|
|
||||||
|
popcorn_max
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *efi_memory_type_names[] = {
|
||||||
|
" reserved",
|
||||||
|
" loader_code",
|
||||||
|
" loader_data",
|
||||||
|
" boot_services_code",
|
||||||
|
" boot_services_data",
|
||||||
|
"runtime_services_code",
|
||||||
|
"runtime_services_data",
|
||||||
|
" available",
|
||||||
|
" unusable",
|
||||||
|
" acpi_reclaim",
|
||||||
|
" acpi_nvs",
|
||||||
|
" mmio",
|
||||||
|
" mmio_port",
|
||||||
|
" pal_code",
|
||||||
|
|
||||||
|
" popcorn_kernel",
|
||||||
|
" popcorn_font",
|
||||||
|
" popcorn_data",
|
||||||
|
" popcorn_log",
|
||||||
|
" popcorn_pml4",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
get_efi_name(efi_memory_type t)
|
||||||
|
{
|
||||||
|
static const unsigned offset =
|
||||||
|
(unsigned)efi_memory_type::popcorn_kernel - (unsigned)efi_memory_type::efi_max;
|
||||||
|
|
||||||
|
return t >= efi_memory_type::popcorn_kernel ?
|
||||||
|
efi_memory_type_names[(unsigned)t - offset] :
|
||||||
|
efi_memory_type_names[(unsigned)t];
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class efi_memory_flag : uint64_t
|
||||||
|
{
|
||||||
|
can_mark_uc = 0x0000000000000001, // uc = un-cacheable
|
||||||
|
can_mark_wc = 0x0000000000000002, // wc = write-combining
|
||||||
|
can_mark_wt = 0x0000000000000004, // wt = write through
|
||||||
|
can_mark_wb = 0x0000000000000008, // wb = write back
|
||||||
|
can_mark_uce = 0x0000000000000010, // uce = un-cacheable exported
|
||||||
|
can_mark_wp = 0x0000000000001000, // wp = write protected
|
||||||
|
can_mark_rp = 0x0000000000002000, // rp = read protected
|
||||||
|
can_mark_xp = 0x0000000000004000, // xp = exceute protected
|
||||||
|
can_mark_ro = 0x0000000000020000, // ro = read only
|
||||||
|
|
||||||
|
non_volatile = 0x0000000000008000,
|
||||||
|
more_reliable = 0x0000000000010000,
|
||||||
|
runtime = 0x8000000000000000
|
||||||
|
};
|
||||||
|
IS_BITFIELD(efi_memory_flag);
|
||||||
|
|
||||||
|
struct efi_memory_descriptor
|
||||||
|
{
|
||||||
|
efi_memory_type type;
|
||||||
|
uint32_t pad;
|
||||||
|
uint64_t physical_start;
|
||||||
|
uint64_t virtual_start;
|
||||||
|
uint64_t pages;
|
||||||
|
efi_memory_flag flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const efi_memory_descriptor *
|
||||||
|
desc_incr(const efi_memory_descriptor *d, size_t desc_length)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const efi_memory_descriptor *>(
|
||||||
|
reinterpret_cast<const uint8_t *>(d) + desc_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct page_table
|
||||||
|
{
|
||||||
|
uint64_t entries[512];
|
||||||
|
page_table * next(int i) const { return reinterpret_cast<page_table *>(entries[i] & ~0xfffull); }
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
count_table_pages_needed(page_block *used)
|
||||||
|
{
|
||||||
|
page_table_indices last_idx{~0ull};
|
||||||
|
unsigned counts[] = {1, 0, 0, 0};
|
||||||
|
|
||||||
|
for (page_block *cur = used; cur; cur = cur->next) {
|
||||||
|
if (!cur->has_flag(page_block_flags::mapped))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
page_table_indices start{cur->virtual_address};
|
||||||
|
page_table_indices end{cur->virtual_address + (cur->count * 0x1000)};
|
||||||
|
|
||||||
|
counts[1] +=
|
||||||
|
((start[0] == last_idx[0]) ? 0 : 1) +
|
||||||
|
(end[0] - start[0]);
|
||||||
|
|
||||||
|
counts[2] +=
|
||||||
|
((start[0] == last_idx[0] &&
|
||||||
|
start[1] == last_idx[1]) ? 0 : 1) +
|
||||||
|
(end[1] - start[1]);
|
||||||
|
|
||||||
|
counts[3] +=
|
||||||
|
((start[0] == last_idx[0] &&
|
||||||
|
start[1] == last_idx[1] &&
|
||||||
|
start[2] == last_idx[2]) ? 0 : 1) +
|
||||||
|
(end[2] - start[2]);
|
||||||
|
|
||||||
|
last_idx = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
return counts[0] + counts[1] + counts[2] + counts[3];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
memory_manager::create(const void *memory_map, size_t map_length, size_t desc_length)
|
||||||
|
{
|
||||||
|
console *cons = console::get();
|
||||||
|
|
||||||
|
// The bootloader reserved 4 pages for page tables, which we'll use to bootstrap.
|
||||||
|
// The first one is the already-installed PML4, so grab it from CR3.
|
||||||
|
page_table *tables = nullptr;
|
||||||
|
__asm__ __volatile__ ( "mov %%cr3, %0" : "=r" (tables) );
|
||||||
|
|
||||||
|
// Now go through EFi's memory map and find a 4MiB region of free space to
|
||||||
|
// use as a scratch space. We'll use the 2MiB that fits naturally aligned
|
||||||
|
// into a single page table.
|
||||||
|
efi_memory_descriptor const *desc =
|
||||||
|
reinterpret_cast<efi_memory_descriptor const *>(memory_map);
|
||||||
|
efi_memory_descriptor const *end = desc_incr(desc, map_length);
|
||||||
|
|
||||||
|
while (desc < end) {
|
||||||
|
if (desc->type == efi_memory_type::available && desc->pages >= 1024)
|
||||||
|
break;
|
||||||
|
|
||||||
|
desc = desc_incr(desc, desc_length);
|
||||||
|
}
|
||||||
|
kassert(desc < end, "Couldn't find 4MiB of contiguous scratch space.");
|
||||||
|
|
||||||
|
uint64_t free_region = (desc->physical_start & 0x1fffff) == 0 ?
|
||||||
|
desc->physical_start :
|
||||||
|
desc->physical_start + 0x1fffff & ~0x1fffffull;
|
||||||
|
|
||||||
|
// Offset-map this region into the higher half.
|
||||||
|
uint64_t next_free = free_region + 0xffff800000000000;
|
||||||
|
|
||||||
|
cons->puts("Found region: ");
|
||||||
|
cons->put_hex(free_region);
|
||||||
|
cons->puts("\n");
|
||||||
|
|
||||||
|
// We'll need to copy any existing tables (except the PML4 which the
|
||||||
|
// bootloader gave us) into our 4 reserved pages so we can edit them.
|
||||||
|
page_table_indices fr_idx{free_region};
|
||||||
|
fr_idx[0] += 256; // Flip the highest bit of the address
|
||||||
|
|
||||||
|
if (tables[0].entries[fr_idx[0]] & 0x1) {
|
||||||
|
page_table *old_pdpt = tables[0].next(fr_idx[0]);
|
||||||
|
for (int i = 0; i < 512; ++i) tables[1].entries[i] = old_pdpt->entries[i];
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < 512; ++i) tables[1].entries[i] = 0;
|
||||||
|
}
|
||||||
|
tables[0].entries[fr_idx[0]] = reinterpret_cast<uint64_t>(&tables[1]) | 0xb;
|
||||||
|
|
||||||
|
if (tables[1].entries[fr_idx[1]] & 0x1) {
|
||||||
|
page_table *old_pdt = tables[1].next(fr_idx[1]);
|
||||||
|
for (int i = 0; i < 512; ++i) tables[2].entries[i] = old_pdt->entries[i];
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < 512; ++i) tables[2].entries[i] = 0;
|
||||||
|
}
|
||||||
|
tables[1].entries[fr_idx[1]] = reinterpret_cast<uint64_t>(&tables[2]) | 0xb;
|
||||||
|
|
||||||
|
for (int i = 0; i < 512; ++i)
|
||||||
|
tables[3].entries[i] = (free_region + 0x1000 * i) | 0xb;
|
||||||
|
tables[2].entries[fr_idx[2]] = reinterpret_cast<uint64_t>(&tables[3]) | 0xb;
|
||||||
|
|
||||||
|
// We now have 2MiB starting at "free_region" to bootstrap ourselves. Start by
|
||||||
|
// taking inventory of free pages.
|
||||||
|
page_block *block_list = reinterpret_cast<page_block *>(next_free);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
page_block *free_head = nullptr, **free = &free_head;
|
||||||
|
page_block *used_head = nullptr, **used = &used_head;
|
||||||
|
|
||||||
|
desc = reinterpret_cast<efi_memory_descriptor const *>(memory_map);
|
||||||
|
while (desc < end) {
|
||||||
|
page_block *block = &block_list[i++];
|
||||||
|
block->physical_address = desc->physical_start;
|
||||||
|
block->virtual_address = desc->virtual_start;
|
||||||
|
block->count = desc->pages;
|
||||||
|
block->next = nullptr;
|
||||||
|
|
||||||
|
switch (desc->type) {
|
||||||
|
case efi_memory_type::loader_code:
|
||||||
|
case efi_memory_type::loader_data:
|
||||||
|
block->flags = page_block_flags::used | page_block_flags::pending_free;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case efi_memory_type::boot_services_code:
|
||||||
|
case efi_memory_type::boot_services_data:
|
||||||
|
case efi_memory_type::available:
|
||||||
|
if (free_region >= block->physical_address && free_region < block->end()) {
|
||||||
|
// This is the scratch memory block, split off what we're not using
|
||||||
|
block->virtual_address = block->physical_address + 0xffff800000000000;
|
||||||
|
|
||||||
|
block->flags = page_block_flags::used
|
||||||
|
| page_block_flags::mapped
|
||||||
|
| page_block_flags::pending_free;
|
||||||
|
|
||||||
|
if (block->count > 1024) {
|
||||||
|
page_block *rest = &block_list[i++];
|
||||||
|
rest->physical_address = desc->physical_start + (1024*0x1000);
|
||||||
|
rest->virtual_address = 0;
|
||||||
|
rest->count = desc->pages - 1024;
|
||||||
|
rest->next = nullptr;
|
||||||
|
*free = rest;
|
||||||
|
free = &rest->next;
|
||||||
|
|
||||||
|
block->count = 1024;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
block->flags = page_block_flags::free;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case efi_memory_type::acpi_reclaim:
|
||||||
|
block->flags = page_block_flags::used | page_block_flags::acpi_wait;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case efi_memory_type::persistent:
|
||||||
|
block->flags = page_block_flags::nonvolatile;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
block->flags = page_block_flags::used | page_block_flags::permanent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block->has_flag(page_block_flags::used)) {
|
||||||
|
if (block->virtual_address != 0)
|
||||||
|
block->flags |= page_block_flags::mapped;
|
||||||
|
*used = block;
|
||||||
|
used = &block->next;
|
||||||
|
} else {
|
||||||
|
*free = block;
|
||||||
|
free = &block->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc = desc_incr(desc, desc_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the pointer to the next free page
|
||||||
|
next_free += i * sizeof(page_block);
|
||||||
|
next_free = ((next_free - 1) & ~0xfffull) + 0x1000;
|
||||||
|
|
||||||
|
// Now go back through these lists and consolidate
|
||||||
|
free_head->list_consolidate();
|
||||||
|
used_head->list_consolidate();
|
||||||
|
|
||||||
|
// Ok, now build an acutal set of kernel page tables that just contains
|
||||||
|
// what the kernel actually has mapped.
|
||||||
|
unsigned table_page_count = count_table_pages_needed(used_head);
|
||||||
|
|
||||||
|
cons->puts("To map currently-mapped pages, we need ");
|
||||||
|
cons->put_dec(table_page_count);
|
||||||
|
cons->puts(" pages of tables.\n");
|
||||||
|
}
|
||||||
74
src/kernel/memory_pages.cpp
Normal file
74
src/kernel/memory_pages.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "console.h"
|
||||||
|
#include "memory_pages.h"
|
||||||
|
|
||||||
|
page_block *
|
||||||
|
page_block::list_consolidate()
|
||||||
|
{
|
||||||
|
page_block *cur = this;
|
||||||
|
page_block *freed_head = nullptr, **freed = &freed_head;
|
||||||
|
|
||||||
|
while (cur) {
|
||||||
|
page_block *next = cur->next;
|
||||||
|
|
||||||
|
if (next && cur->flags == next->flags &&
|
||||||
|
cur->end() == next->physical_address)
|
||||||
|
{
|
||||||
|
cur->count += next->count;
|
||||||
|
cur->next = next->next;
|
||||||
|
|
||||||
|
next->next = 0;
|
||||||
|
*freed = next;
|
||||||
|
freed = &next->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return freed_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
page_block::list_dump(const char *name)
|
||||||
|
{
|
||||||
|
console *cons = console::get();
|
||||||
|
cons->puts("Block list");
|
||||||
|
if (name) {
|
||||||
|
cons->puts(" ");
|
||||||
|
cons->puts(name);
|
||||||
|
}
|
||||||
|
cons->puts(":\n");
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (page_block *cur = this; cur; cur = cur->next) {
|
||||||
|
cons->puts(" ");
|
||||||
|
cons->put_hex(cur->physical_address);
|
||||||
|
cons->puts(" ");
|
||||||
|
cons->put_hex((uint32_t)cur->flags);
|
||||||
|
if (cur->virtual_address) {
|
||||||
|
cons->puts(" ");
|
||||||
|
cons->put_hex(cur->virtual_address);
|
||||||
|
}
|
||||||
|
cons->puts(" [");
|
||||||
|
cons->put_dec(cur->count);
|
||||||
|
cons->puts("]\n");
|
||||||
|
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cons->puts(" Total: ");
|
||||||
|
cons->put_dec(count);
|
||||||
|
cons->puts("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
page_table_indices::dump()
|
||||||
|
{
|
||||||
|
console *cons = console::get();
|
||||||
|
cons->puts("{");
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
if (i) cons->puts(", ");
|
||||||
|
cons->put_dec(index[i]);
|
||||||
|
}
|
||||||
|
cons->puts("}");
|
||||||
|
}
|
||||||
54
src/kernel/memory_pages.h
Normal file
54
src/kernel/memory_pages.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "kutil/enum_bitfields.h"
|
||||||
|
|
||||||
|
enum class page_block_flags : uint32_t
|
||||||
|
{
|
||||||
|
// Not a flag value, but for comparison
|
||||||
|
free = 0x00000000,
|
||||||
|
|
||||||
|
used = 0x00000001,
|
||||||
|
mapped = 0x00000002,
|
||||||
|
pending_free = 0x00000004,
|
||||||
|
|
||||||
|
nonvolatile = 0x00000010,
|
||||||
|
acpi_wait = 0x00000020,
|
||||||
|
|
||||||
|
permanent = 0x80000000,
|
||||||
|
|
||||||
|
max_flags
|
||||||
|
};
|
||||||
|
IS_BITFIELD(page_block_flags);
|
||||||
|
|
||||||
|
struct page_block
|
||||||
|
{
|
||||||
|
uint64_t physical_address;
|
||||||
|
uint64_t virtual_address;
|
||||||
|
uint32_t count;
|
||||||
|
page_block_flags flags;
|
||||||
|
page_block *next;
|
||||||
|
|
||||||
|
bool has_flag(page_block_flags f) const { return bitfield_contains(flags, f); }
|
||||||
|
uint64_t end() const { return physical_address + (count * 0x1000); }
|
||||||
|
|
||||||
|
page_block * list_consolidate();
|
||||||
|
void list_dump(const char *name = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct page_table_indices
|
||||||
|
{
|
||||||
|
page_table_indices(uint64_t v) :
|
||||||
|
index{
|
||||||
|
(v >> 39) & 0x1ff,
|
||||||
|
(v >> 30) & 0x1ff,
|
||||||
|
(v >> 21) & 0x1ff,
|
||||||
|
(v >> 12) & 0x1ff }
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint64_t & operator[](size_t i) { return index[i]; }
|
||||||
|
uint64_t index[4];
|
||||||
|
|
||||||
|
void dump();
|
||||||
|
};
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "kutil/coord.h"
|
||||||
|
|
||||||
class screen
|
class screen
|
||||||
{
|
{
|
||||||
@@ -36,5 +36,5 @@ private:
|
|||||||
|
|
||||||
pixel_t *m_framebuffer;
|
pixel_t *m_framebuffer;
|
||||||
color_masks m_masks;
|
color_masks m_masks;
|
||||||
coord<unsigned> m_resolution;
|
kutil::coord<unsigned> m_resolution;
|
||||||
};
|
};
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
namespace kutil {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct coord {
|
struct coord
|
||||||
|
{
|
||||||
T x, y;
|
T x, y;
|
||||||
coord() : x(T{}), y(T{}) {}
|
coord() : x(T{}), y(T{}) {}
|
||||||
coord(T x, T y) : x(x), y(y) {}
|
coord(T x, T y) : x(x), y(y) {}
|
||||||
T size() const { return x * y; }
|
T size() const { return x * y; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace kutil
|
||||||
90
src/modules/kutil/enum_bitfields.h
Normal file
90
src/modules/kutil/enum_bitfields.h
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
template<typename E>
|
||||||
|
struct is_enum_bitfield { static constexpr bool value = false; };
|
||||||
|
|
||||||
|
#define IS_BITFIELD(name) \
|
||||||
|
template<> struct is_enum_bitfield<name> {static constexpr bool value=true;}
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
typename std::enable_if<is_enum_bitfield<E>::value,E>::type
|
||||||
|
operator & (E lhs, E rhs)
|
||||||
|
{
|
||||||
|
return static_cast<E> (
|
||||||
|
static_cast<typename std::underlying_type<E>::type>(lhs) &
|
||||||
|
static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
typename std::enable_if<is_enum_bitfield<E>::value,E>::type
|
||||||
|
operator | (E lhs, E rhs)
|
||||||
|
{
|
||||||
|
return static_cast<E> (
|
||||||
|
static_cast<typename std::underlying_type<E>::type>(lhs) |
|
||||||
|
static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
typename std::enable_if<is_enum_bitfield<E>::value,E>::type
|
||||||
|
operator ^ (E lhs, E rhs)
|
||||||
|
{
|
||||||
|
return static_cast<E> (
|
||||||
|
static_cast<typename std::underlying_type<E>::type>(lhs) ^
|
||||||
|
static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
typename std::enable_if<is_enum_bitfield<E>::value,E>::type
|
||||||
|
operator ~ (E rhs)
|
||||||
|
{
|
||||||
|
return static_cast<E>(~static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
typename std::enable_if<is_enum_bitfield<E>::value,E>::type&
|
||||||
|
operator |= (E &lhs, E rhs)
|
||||||
|
{
|
||||||
|
lhs = static_cast<E>(
|
||||||
|
static_cast<typename std::underlying_type<E>::type>(lhs) |
|
||||||
|
static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
typename std::enable_if<is_enum_bitfield<E>::value,E>::type&
|
||||||
|
operator &= (E &lhs, E rhs)
|
||||||
|
{
|
||||||
|
lhs = static_cast<E>(
|
||||||
|
static_cast<typename std::underlying_type<E>::type>(lhs) &
|
||||||
|
static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
typename std::enable_if<is_enum_bitfield<E>::value,E>::type&
|
||||||
|
operator ^= (E &lhs, E rhs)
|
||||||
|
{
|
||||||
|
lhs = static_cast<E>(
|
||||||
|
static_cast<typename std::underlying_type<E>::type>(lhs) ^
|
||||||
|
static_cast<typename std::underlying_type<E>::type>(rhs));
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
typename std::enable_if<is_enum_bitfield<E>::value,bool>::type
|
||||||
|
operator ! (E rhs)
|
||||||
|
{
|
||||||
|
return static_cast<typename std::underlying_type<E>::type>(rhs) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
typename std::enable_if<is_enum_bitfield<E>::value,bool>::type
|
||||||
|
bitfield_contains(E set, E flag)
|
||||||
|
{
|
||||||
|
return (set & flag) == flag;
|
||||||
|
}
|
||||||
13
src/modules/kutil/memory.cpp
Normal file
13
src/modules/kutil/memory.cpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
namespace kutil {
|
||||||
|
|
||||||
|
void *
|
||||||
|
memset(void *s, uint8_t v, size_t n)
|
||||||
|
{
|
||||||
|
uint8_t *p = reinterpret_cast<uint8_t *>(s);
|
||||||
|
for (int i = 0; i < n; ++i) p[i] = 0;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kutil
|
||||||
13
src/modules/kutil/memory.h
Normal file
13
src/modules/kutil/memory.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace kutil {
|
||||||
|
|
||||||
|
void * memset(void *p, uint8_t v, size_t n);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T read_from(const void *p) { return *reinterpret_cast<const T *>(p); }
|
||||||
|
|
||||||
|
} // namespace kutil
|
||||||
12
src/modules/kutil/misc.h
Normal file
12
src/modules/kutil/misc.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace kutil {
|
||||||
|
|
||||||
|
constexpr uint32_t
|
||||||
|
byteswap(uint32_t x)
|
||||||
|
{
|
||||||
|
return ((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00)
|
||||||
|
| ((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
MOD_NAME := main
|
MOD_NAME := kutil
|
||||||
include modules.mk
|
include modules.mk
|
||||||
Reference in New Issue
Block a user