mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-13 01:48:42 +00:00
pr: ACPI Power Shutdown Implemented (#14)
* Flush PS/2 Devices on boot to avoid Locking dependent on the out buffer on real hardware / emulated PS2 over USB Removed Slow and Unnessisarty flipping causing kconsole write slowdowns consequently speeding up the boot process * sod wc * ignoring dynamically created objects, added make run rule which will automatically detect the platform and then use the correct platform rule * ACPI Power Shutdown
This commit is contained in:
parent
77744464e3
commit
b85bb900e6
11 changed files with 516 additions and 98 deletions
13
Makefile
13
Makefile
|
|
@ -40,6 +40,7 @@ C_SOURCES = $(wildcard $(SRC_DIR)/core/*.c) \
|
||||||
$(wildcard $(SRC_DIR)/sys/*.c) \
|
$(wildcard $(SRC_DIR)/sys/*.c) \
|
||||||
$(wildcard $(SRC_DIR)/mem/*.c) \
|
$(wildcard $(SRC_DIR)/mem/*.c) \
|
||||||
$(wildcard $(SRC_DIR)/dev/*.c) \
|
$(wildcard $(SRC_DIR)/dev/*.c) \
|
||||||
|
$(wildcard $(SRC_DIR)/drivers/*.c) \
|
||||||
$(wildcard $(SRC_DIR)/input/*.c) \
|
$(wildcard $(SRC_DIR)/input/*.c) \
|
||||||
$(wildcard $(SRC_DIR)/net/*.c) \
|
$(wildcard $(SRC_DIR)/net/*.c) \
|
||||||
$(wildcard $(SRC_DIR)/net/nic/*.c) \
|
$(wildcard $(SRC_DIR)/net/nic/*.c) \
|
||||||
|
|
@ -55,6 +56,7 @@ OBJ_FILES = $(patsubst $(SRC_DIR)/core/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_D
|
||||||
$(patsubst $(SRC_DIR)/sys/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/sys/*.c)) \
|
$(patsubst $(SRC_DIR)/sys/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/sys/*.c)) \
|
||||||
$(patsubst $(SRC_DIR)/mem/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/mem/*.c)) \
|
$(patsubst $(SRC_DIR)/mem/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/mem/*.c)) \
|
||||||
$(patsubst $(SRC_DIR)/dev/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/dev/*.c)) \
|
$(patsubst $(SRC_DIR)/dev/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/dev/*.c)) \
|
||||||
|
$(patsubst $(SRC_DIR)/drivers/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/drivers/*.c)) \
|
||||||
$(patsubst $(SRC_DIR)/input/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/input/*.c)) \
|
$(patsubst $(SRC_DIR)/input/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/input/*.c)) \
|
||||||
$(patsubst $(SRC_DIR)/net/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/net/*.c)) \
|
$(patsubst $(SRC_DIR)/net/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/net/*.c)) \
|
||||||
$(patsubst $(SRC_DIR)/net/nic/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/net/nic/*.c)) \
|
$(patsubst $(SRC_DIR)/net/nic/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/net/nic/*.c)) \
|
||||||
|
|
@ -66,7 +68,11 @@ OBJ_FILES = $(patsubst $(SRC_DIR)/core/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_D
|
||||||
CFLAGS = -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding \
|
CFLAGS = -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding \
|
||||||
-fno-stack-protector -fno-stack-check -fno-lto -fPIE \
|
-fno-stack-protector -fno-stack-check -fno-lto -fPIE \
|
||||||
-m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone \
|
-m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone \
|
||||||
-I$(SRC_DIR) -I$(SRC_DIR)/net/third_party/lwip -I$(SRC_DIR)/core -I$(SRC_DIR)/sys -I$(SRC_DIR)/mem -I$(SRC_DIR)/dev -I$(SRC_DIR)/net -I$(SRC_DIR)/net/nic -I$(SRC_DIR)/fs -I$(SRC_DIR)/wm -I$(SRC_DIR)/input
|
-I$(SRC_DIR) -I$(SRC_DIR)/net/third_party/lwip -I$(SRC_DIR)/core \
|
||||||
|
-I$(SRC_DIR)/sys -I$(SRC_DIR)/mem -I$(SRC_DIR)/dev \
|
||||||
|
-I$(SRC_DIR)/drivers \
|
||||||
|
-I$(SRC_DIR)/net -I$(SRC_DIR)/net/nic -I$(SRC_DIR)/fs \
|
||||||
|
-I$(SRC_DIR)/wm -I$(SRC_DIR)/input
|
||||||
|
|
||||||
LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \
|
LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \
|
||||||
-z text -z max-page-size=0x1000 -T linker.ld
|
-z text -z max-page-size=0x1000 -T linker.ld
|
||||||
|
|
@ -133,6 +139,11 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/dev/%.c | $(BUILD_DIR) limine-setup
|
||||||
@printf "$(YELLOW)[CC]$(RESET)[dev] $< -> $@"
|
@printf "$(YELLOW)[CC]$(RESET)[dev] $< -> $@"
|
||||||
mkdir -p $(dir $@)
|
mkdir -p $(dir $@)
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(BUILD_DIR)/%.o: $(SRC_DIR)/drivers/%.c | $(BUILD_DIR) limine-setup
|
||||||
|
@printf "$(YELLOW)[CC]$(RESET)[drivers] $< -> $@"
|
||||||
|
mkdir -p $(dir $@)
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/input/%.c | $(BUILD_DIR) limine-setup
|
$(BUILD_DIR)/%.o: $(SRC_DIR)/input/%.c | $(BUILD_DIR) limine-setup
|
||||||
@printf "$(YELLOW)[CC]$(RESET)[input] $< -> $@"
|
@printf "$(YELLOW)[CC]$(RESET)[input] $< -> $@"
|
||||||
|
|
|
||||||
35
docs/architecture/ACPI/acpi_interface.md
Normal file
35
docs/architecture/ACPI/acpi_interface.md
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
<div align="center">
|
||||||
|
<h1>ACPI</h1>
|
||||||
|
<p><em>ACPI Power Interface</em></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
ACPI Subsystem
|
||||||
|
|
||||||
|
BoredOS implements an ACPI subsystem which manages power state transitions.
|
||||||
|
The implementation lives
|
||||||
|
in `src/acpi/`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Startup and Table Discovery
|
||||||
|
|
||||||
|
The first thing that ACPI does at boot time is to locate the RSDP.This can simply be requested fromlimine.
|
||||||
|
If the pointer is not present or the pointer is not valid we panic!It is a hardware requirement
|
||||||
|
|
||||||
|
If this is not present then we also check a checksum if that fails then the RSDP is also not valid and we panic
|
||||||
|
|
||||||
|
XSDT vs RSDT Fallback
|
||||||
|
When the RSDP specifies aRevision of 2 or greater, and we have a valid XSDT Address then we should try and use the XSDT instead,otherwise we use the RSDT.This is automatically abstracted by `acpi_get_sdt()`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Shutdown and Power Off
|
||||||
|
|
||||||
|
This works by writing an appropriate value to PM1 Control Block register, and will prompt hardware to move into S5 power state.
|
||||||
|
|
||||||
|
### Performing the power off
|
||||||
|
Once the sleep types are identified and so on, this will continue as follows
|
||||||
|
On hardware that actually obeys ACPI standards this process should only perform step 1, and your machine should be turned off. To try and handle virtual machines or emulators that are known to fail at step 1,
|
||||||
|
|
||||||
|
we send the virtual machine interrupts second in case writing bytes makes our hardware think it is acting up and we do not wish to cause an unnecessary interrupt
|
||||||
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
#include "wm.h"
|
#include "wm.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
|
#include "../drivers/acpi.h"
|
||||||
|
|
||||||
void k_memset(void *dest, int val, size_t len) {
|
void k_memset(void *dest, int val, size_t len) {
|
||||||
unsigned char *ptr = (unsigned char *)dest;
|
unsigned char *ptr = (unsigned char *)dest;
|
||||||
while (len-- > 0) *ptr++ = (unsigned char)val;
|
while (len-- > 0) *ptr++ = (unsigned char)val;
|
||||||
|
|
@ -16,6 +18,17 @@ void k_memcpy(void *dest, const void *src, size_t len) {
|
||||||
while (len-- > 0) *d++ = *s++;
|
while (len-- > 0) *d++ = *s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int k_memcmp (const void *str1, const void *str2, size_t count) {
|
||||||
|
register const unsigned char *s1 = (const unsigned char*)str1;
|
||||||
|
register const unsigned char *s2 = (const unsigned char*)str2;
|
||||||
|
|
||||||
|
while (count-- > 0) {
|
||||||
|
if (*s1++ != *s2++)
|
||||||
|
return s1[-1] < s2[-1] ? -1 : 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
size_t k_strlen(const char *str) {
|
size_t k_strlen(const char *str) {
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
while (str[len]) len++;
|
while (str[len]) len++;
|
||||||
|
|
@ -118,9 +131,7 @@ void k_reboot(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void k_shutdown(void) {
|
void k_shutdown(void) {
|
||||||
outw(0xB004, 0x2000); // QEMU older / some pc machines
|
acpi_shutdown();
|
||||||
outw(0x604, 0x2000); // QEMU newer (i440fx/q35)
|
|
||||||
outw(0x4004, 0x3400); // VirtualBox fallback
|
|
||||||
}
|
}
|
||||||
|
|
||||||
volatile uint64_t beep_end_tick = 0;
|
volatile uint64_t beep_end_tick = 0;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
// Kernel string utilities
|
// Kernel string utilities
|
||||||
void k_memset(void *dest, int val, size_t len);
|
void k_memset(void *dest, int val, size_t len);
|
||||||
void k_memcpy(void *dest, const void *src, size_t len);
|
void k_memcpy(void *dest, const void *src, size_t len);
|
||||||
|
int k_memcmp (const void *str1, const void *str2, size_t count);
|
||||||
size_t k_strlen(const char *str);
|
size_t k_strlen(const char *str);
|
||||||
int k_strcmp(const char *s1, const char *s2);
|
int k_strcmp(const char *s1, const char *s2);
|
||||||
int k_strncmp(const char *s1, const char *s2, size_t n);
|
int k_strncmp(const char *s1, const char *s2, size_t n);
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "smp.h"
|
#include "smp.h"
|
||||||
#include "work_queue.h"
|
#include "work_queue.h"
|
||||||
#include "lapic.h"
|
#include "lapic.h"
|
||||||
|
#include "panic.h"
|
||||||
#include "fs/sysfs.h"
|
#include "fs/sysfs.h"
|
||||||
#include "fs/procfs.h"
|
#include "fs/procfs.h"
|
||||||
#include "fs/bootfs.h"
|
#include "fs/bootfs.h"
|
||||||
|
|
@ -34,6 +35,7 @@
|
||||||
#include "sys/bootfs_state.h"
|
#include "sys/bootfs_state.h"
|
||||||
#include "input/keymap.h"
|
#include "input/keymap.h"
|
||||||
#include "input/keyboard.h"
|
#include "input/keyboard.h"
|
||||||
|
#include "../drivers/acpi.h"
|
||||||
|
|
||||||
extern void sysfs_init_subsystems(void);
|
extern void sysfs_init_subsystems(void);
|
||||||
|
|
||||||
|
|
@ -78,6 +80,12 @@ static volatile struct limine_kernel_file_request kernel_file_request = {
|
||||||
.revision = 0
|
.revision = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
__attribute__((used, section(".requests")))
|
||||||
|
volatile struct limine_rsdp_request acpi_rsdp_request = {
|
||||||
|
.id = LIMINE_RSDP_REQUEST,
|
||||||
|
.revision = 0
|
||||||
|
};
|
||||||
|
|
||||||
__attribute__((used, section(".requests_start")))
|
__attribute__((used, section(".requests_start")))
|
||||||
static volatile struct limine_request *const requests_start_marker[] = {
|
static volatile struct limine_request *const requests_start_marker[] = {
|
||||||
(struct limine_request *)&framebuffer_request,
|
(struct limine_request *)&framebuffer_request,
|
||||||
|
|
@ -86,6 +94,7 @@ static volatile struct limine_request *const requests_start_marker[] = {
|
||||||
(struct limine_request *)&smp_request,
|
(struct limine_request *)&smp_request,
|
||||||
(struct limine_request *)&bootloader_info_request,
|
(struct limine_request *)&bootloader_info_request,
|
||||||
(struct limine_request *)&kernel_file_request,
|
(struct limine_request *)&kernel_file_request,
|
||||||
|
(struct limine_request *)&acpi_rsdp_request,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -366,9 +375,9 @@ void kmain(void) {
|
||||||
kconsole_set_color(0xFFFFFF55);
|
kconsole_set_color(0xFFFFFF55);
|
||||||
serial_write("Welcome to BoredOS!\n");
|
serial_write("Welcome to BoredOS!\n");
|
||||||
kconsole_set_color(0xFFFFFFFF);
|
kconsole_set_color(0xFFFFFFFF);
|
||||||
|
acpi_init();
|
||||||
|
|
||||||
process_init();
|
process_init();
|
||||||
|
|
||||||
|
|
||||||
fat32_init();
|
fat32_init();
|
||||||
log_ok("FAT32 ready");
|
log_ok("FAT32 ready");
|
||||||
|
|
|
||||||
147
src/core/panic.c
147
src/core/panic.c
|
|
@ -17,129 +17,98 @@ static void draw_string_centered(int y, const char *s, uint32_t color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void kernel_panic(registers_t *regs, const char *error_name) {
|
void kernel_panic(registers_t *regs, const char *error_name) {
|
||||||
// Disable interrupts to prevent nested panics
|
|
||||||
asm volatile("cli");
|
asm volatile("cli");
|
||||||
|
|
||||||
// Clear back buffer to black
|
|
||||||
graphics_clear_back_buffer(0x00000000);
|
graphics_clear_back_buffer(0x00000000);
|
||||||
|
|
||||||
int sh = get_screen_height();
|
int sh = get_screen_height();
|
||||||
int cy = sh / 2;
|
int cy = sh / 2;
|
||||||
|
|
||||||
// Draw header
|
// Header
|
||||||
draw_string_centered(cy - 150, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", 0xFFFF0000);
|
draw_string_centered(cy - 150, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", 0xFFFF0000);
|
||||||
draw_string_centered(cy - 130, "KERNEL EXCEPTION OCCURRED", 0xFFFFFFFF);
|
draw_string_centered(cy - 130, "KERNEL PANIC", 0xFFFFFFFF);
|
||||||
draw_string_centered(cy - 110, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", 0xFFFF0000);
|
draw_string_centered(cy - 110, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", 0xFFFF0000);
|
||||||
|
|
||||||
// Error name
|
// Error name
|
||||||
char err_buf[256];
|
char buf[256];
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
const char *prefix = "Exception: ";
|
const char *prefix = "Error: ";
|
||||||
while(prefix[pos]) { err_buf[pos] = prefix[pos]; pos++; }
|
while (prefix[pos]) { buf[pos] = prefix[pos]; pos++; }
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(error_name[i]) { err_buf[pos++] = error_name[i++]; }
|
while (error_name[i]) { buf[pos++] = error_name[i++]; }
|
||||||
err_buf[pos] = 0;
|
buf[pos] = 0;
|
||||||
draw_string_centered(cy - 70, err_buf, 0xFFFFCC00);
|
draw_string_centered(cy - 70, buf, 0xFFFFCC00);
|
||||||
|
|
||||||
// Details - simplified centering by drawing them as a block or individually centered
|
if (regs != NULL) {
|
||||||
char info_buf[64];
|
// Exception details
|
||||||
|
char info_buf[64];
|
||||||
// Vector
|
const char *digits = "0123456789ABCDEF";
|
||||||
pos = 0;
|
|
||||||
prefix = "Vector: ";
|
|
||||||
while(prefix[pos]) { info_buf[pos] = prefix[pos]; pos++; }
|
|
||||||
uint64_t v = regs->int_no;
|
|
||||||
const char* digits = "0123456789ABCDEF";
|
|
||||||
info_buf[pos++] = '0'; info_buf[pos++] = 'x';
|
|
||||||
for (int i = 15; i >= 0; i--) {
|
|
||||||
info_buf[pos + i] = digits[v & 0xF];
|
|
||||||
v >>= 4;
|
|
||||||
}
|
|
||||||
info_buf[pos + 16] = 0;
|
|
||||||
draw_string_centered(cy - 40, info_buf, 0xFFFFFFFF);
|
|
||||||
|
|
||||||
// Error Code
|
#define FMT_HEX(prefix_str, value, color, y_offset) \
|
||||||
pos = 0;
|
do { \
|
||||||
prefix = "Error Code: ";
|
int pos = 0; \
|
||||||
while(prefix[pos]) { info_buf[pos] = prefix[pos]; pos++; }
|
const char *pfx = (prefix_str); \
|
||||||
v = regs->err_code;
|
while (pfx[pos]) { info_buf[pos] = pfx[pos]; pos++; } \
|
||||||
info_buf[pos++] = '0'; info_buf[pos++] = 'x';
|
info_buf[pos++] = '0'; info_buf[pos++] = 'x'; \
|
||||||
for (int i = 15; i >= 0; i--) {
|
uint64_t _v = (value); \
|
||||||
info_buf[pos + i] = digits[v & 0xF];
|
for (int _i = 15; _i >= 0; _i--) { \
|
||||||
v >>= 4;
|
info_buf[pos + _i] = digits[_v & 0xF]; _v >>= 4; \
|
||||||
}
|
} \
|
||||||
info_buf[pos + 16] = 0;
|
info_buf[pos + 16] = 0; \
|
||||||
draw_string_centered(cy - 20, info_buf, 0xFFFFFFFF);
|
draw_string_centered((y_offset), info_buf, (color)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
// RIP
|
FMT_HEX("Vector: ", regs->int_no, 0xFFFFFFFF, cy - 40);
|
||||||
pos = 0;
|
FMT_HEX("Error Code: ", regs->err_code, 0xFFFFFFFF, cy - 20);
|
||||||
prefix = "RIP: ";
|
FMT_HEX("RIP: ", regs->rip, 0xFFFFFFFF, cy);
|
||||||
while(prefix[pos]) { info_buf[pos] = prefix[pos]; pos++; }
|
|
||||||
v = regs->rip;
|
|
||||||
info_buf[pos++] = '0'; info_buf[pos++] = 'x';
|
|
||||||
for (int i = 15; i >= 0; i--) {
|
|
||||||
info_buf[pos + i] = digits[v & 0xF];
|
|
||||||
v >>= 4;
|
|
||||||
}
|
|
||||||
info_buf[pos + 16] = 0;
|
|
||||||
draw_string_centered(cy, info_buf, 0xFFFFFFFF);
|
|
||||||
|
|
||||||
// CR2 for page faults
|
if (regs->int_no == 14) {
|
||||||
if (regs->int_no == 14) {
|
uint64_t cr2;
|
||||||
uint64_t cr2;
|
asm volatile("mov %%cr2, %0" : "=r"(cr2));
|
||||||
asm volatile("mov %%cr2, %0" : "=r"(cr2));
|
FMT_HEX("CR2: ", cr2, 0xFFFF5555, cy + 20);
|
||||||
pos = 0;
|
|
||||||
prefix = "CR2: ";
|
|
||||||
while(prefix[pos]) { info_buf[pos] = prefix[pos]; pos++; }
|
|
||||||
info_buf[pos++] = '0'; info_buf[pos++] = 'x';
|
|
||||||
for (int i = 15; i >= 0; i--) {
|
|
||||||
info_buf[pos + i] = digits[cr2 & 0xF];
|
|
||||||
cr2 >>= 4;
|
|
||||||
}
|
}
|
||||||
info_buf[pos + 16] = 0;
|
|
||||||
draw_string_centered(cy + 20, info_buf, 0xFFFF5555);
|
#undef FMT_HEX
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message
|
|
||||||
draw_string_centered(cy + 100, "The system has been halted to prevent damage.", 0xFFFFFFFF);
|
draw_string_centered(cy + 100, "The system has been halted to prevent damage.", 0xFFFFFFFF);
|
||||||
draw_string_centered(cy + 120, "Please restart your computer.", 0xFFAAAAAA);
|
draw_string_centered(cy + 120, "Please restart your computer.", 0xFFAAAAAA);
|
||||||
|
|
||||||
|
|
||||||
// Flip buffer to screen
|
|
||||||
graphics_mark_screen_dirty();
|
graphics_mark_screen_dirty();
|
||||||
graphics_flip_buffer();
|
graphics_flip_buffer();
|
||||||
|
|
||||||
char hex_buf[17];
|
|
||||||
serial_write("\n*** KERNEL PANIC ***\n");
|
serial_write("\n*** KERNEL PANIC ***\n");
|
||||||
serial_write(error_name);
|
serial_write(error_name);
|
||||||
serial_write("\n");
|
serial_write("\n");
|
||||||
|
|
||||||
serial_write("Vector: 0x");
|
if (regs != NULL) {
|
||||||
k_itoa_hex(regs->int_no, hex_buf);
|
char hex_buf[17];
|
||||||
serial_write(hex_buf);
|
|
||||||
serial_write("\n");
|
|
||||||
|
|
||||||
serial_write("Error Code: 0x");
|
serial_write("Vector: 0x");
|
||||||
k_itoa_hex(regs->err_code, hex_buf);
|
k_itoa_hex(regs->int_no, hex_buf);
|
||||||
serial_write(hex_buf);
|
|
||||||
serial_write("\n");
|
|
||||||
|
|
||||||
serial_write("RIP: 0x");
|
|
||||||
k_itoa_hex(regs->rip, hex_buf);
|
|
||||||
serial_write(hex_buf);
|
|
||||||
serial_write("\n");
|
|
||||||
|
|
||||||
if (regs->int_no == 14) {
|
|
||||||
uint64_t cr2;
|
|
||||||
asm volatile("mov %%cr2, %0" : "=r"(cr2));
|
|
||||||
serial_write("CR2: 0x");
|
|
||||||
k_itoa_hex(cr2, hex_buf);
|
|
||||||
serial_write(hex_buf);
|
serial_write(hex_buf);
|
||||||
serial_write("\n");
|
serial_write("\n");
|
||||||
|
|
||||||
|
serial_write("Error Code: 0x");
|
||||||
|
k_itoa_hex(regs->err_code, hex_buf);
|
||||||
|
serial_write(hex_buf);
|
||||||
|
serial_write("\n");
|
||||||
|
|
||||||
|
serial_write("RIP: 0x");
|
||||||
|
k_itoa_hex(regs->rip, hex_buf);
|
||||||
|
serial_write(hex_buf);
|
||||||
|
serial_write("\n");
|
||||||
|
|
||||||
|
if (regs->int_no == 14) {
|
||||||
|
uint64_t cr2;
|
||||||
|
asm volatile("mov %%cr2, %0" : "=r"(cr2));
|
||||||
|
serial_write("CR2: 0x");
|
||||||
|
k_itoa_hex(cr2, hex_buf);
|
||||||
|
serial_write(hex_buf);
|
||||||
|
serial_write("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Halt
|
while (1) {
|
||||||
while(1) {
|
|
||||||
asm volatile("cli; hlt");
|
asm volatile("cli; hlt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
src/core/panic.h
Normal file
10
src/core/panic.h
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef PANIC_H
|
||||||
|
#define PANIC_H
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
#include "kutils.h"
|
||||||
|
#include "../sys/syscall.h"
|
||||||
|
|
||||||
|
void kernel_panic(registers_t *regs, const char *error_name);
|
||||||
|
|
||||||
|
#endif
|
||||||
220
src/drivers/acpi.c
Normal file
220
src/drivers/acpi.c
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "acpi_structures.h"
|
||||||
|
#include "acpi.h"
|
||||||
|
#include "../sys/idt.h"
|
||||||
|
#include "../core/limine.h"
|
||||||
|
#include "../core/panic.h"
|
||||||
|
#include "../core/platform.h"
|
||||||
|
#include "../core/kconsole.h"
|
||||||
|
|
||||||
|
#define MAX_ISO 16
|
||||||
|
|
||||||
|
static struct acpi_rsdp *acpi_rsdp = NULL;
|
||||||
|
static struct acpi_madt *acpi_madt = NULL;
|
||||||
|
|
||||||
|
static fadt_t *acpi_fadt = NULL; // my header file sucks ill make this nicer but its fine
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
uint8_t source;
|
||||||
|
uint32_t gsi;
|
||||||
|
uint16_t flags;
|
||||||
|
} iso_table[MAX_ISO];
|
||||||
|
static uint8_t iso_count = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Each ACPI table contains an 8-bit checksum field.
|
||||||
|
When all bytes in the table are added together (including the checksum byte),
|
||||||
|
the lower 8 bits of the total sum must be zero for it to pass.
|
||||||
|
*/
|
||||||
|
static int acpi_checksum(void *ptr, size_t len) {
|
||||||
|
uint8_t sum = 0;
|
||||||
|
uint8_t *p = ptr;
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
sum += p[i];
|
||||||
|
return sum == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *acpi_get_rsdp(void){
|
||||||
|
extern volatile struct limine_rsdp_request acpi_rsdp_request;
|
||||||
|
|
||||||
|
if (!acpi_rsdp_request.response)
|
||||||
|
kernel_panic(NULL, "ACPI RSDP not provided by the Bootloader");
|
||||||
|
if (!acpi_rsdp_request.response->address)
|
||||||
|
kernel_panic(NULL, "ACPI Invalid RSDP address provided by Bootloader");
|
||||||
|
|
||||||
|
return acpi_rsdp_request.response->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct acpi_sdt *acpi_get_sdt(const char signature[4]) {
|
||||||
|
if (acpi_rsdp->revision >= 2 && acpi_rsdp->xsdt_address) {
|
||||||
|
struct acpi_xsdt *acpi_xsdt = (struct acpi_xsdt *)p2v(acpi_rsdp->xsdt_address);
|
||||||
|
if (acpi_checksum(acpi_xsdt, acpi_xsdt->header.length)) {
|
||||||
|
size_t entries = (acpi_xsdt->header.length - sizeof(struct acpi_sdt)) / 8;
|
||||||
|
for (size_t i = 0; i < entries; i++) {
|
||||||
|
struct acpi_sdt *tbl = (struct acpi_sdt *)p2v(acpi_xsdt->tables[i]);
|
||||||
|
if (!tbl) continue;
|
||||||
|
if (!k_memcmp(tbl->signature, signature, 4))
|
||||||
|
return tbl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RSDT fallback
|
||||||
|
if (!acpi_rsdp->rsdt_address)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
struct acpi_sdt *acpi_rsdt = (struct acpi_sdt *)p2v(acpi_rsdp->rsdt_address);
|
||||||
|
if (!acpi_checksum(acpi_rsdt, acpi_rsdt->length))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
uint32_t *tables = (uint32_t *)((uint8_t *)acpi_rsdt + sizeof(struct acpi_sdt));
|
||||||
|
size_t entries = (acpi_rsdt->length - sizeof(struct acpi_sdt)) / 4;
|
||||||
|
for (size_t i = 0; i < entries; i++) {
|
||||||
|
struct acpi_sdt *tbl = (struct acpi_sdt *)p2v(tables[i]);
|
||||||
|
if (!tbl) continue;
|
||||||
|
if (!k_memcmp(tbl->signature, signature, 4))
|
||||||
|
return tbl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t SLP_TYPa = 0;
|
||||||
|
static uint16_t SLP_TYPb = 0;
|
||||||
|
|
||||||
|
void acpi_parse_s5(void) {
|
||||||
|
if (!acpi_fadt || !acpi_fadt->dsdt) return;
|
||||||
|
|
||||||
|
char *dsdt = (char *)p2v((uintptr_t)acpi_fadt->dsdt);
|
||||||
|
|
||||||
|
if (k_memcmp(dsdt, "DSDT", 4) != 0) return;
|
||||||
|
|
||||||
|
uint32_t dsdt_len = *(uint32_t*)(dsdt + 4);
|
||||||
|
char *ptr = dsdt + 36;
|
||||||
|
char *end = dsdt + dsdt_len;
|
||||||
|
|
||||||
|
while (ptr < end) {
|
||||||
|
if (k_memcmp(ptr, "_S5_", 4) == 0) {
|
||||||
|
ptr += 4;
|
||||||
|
if (*ptr == 0x12) {
|
||||||
|
ptr += 3;
|
||||||
|
|
||||||
|
if (*ptr == 0x0A) ptr++;
|
||||||
|
SLP_TYPa = (*(uint8_t*)ptr) << 10;
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
if (*ptr == 0x0A) ptr++;
|
||||||
|
SLP_TYPb = (*(uint8_t*)ptr) << 10;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn))
|
||||||
|
void acpi_shutdown(void) {
|
||||||
|
if (SLP_TYPa == 0) acpi_parse_s5();
|
||||||
|
if (SLP_TYPa == 0) SLP_TYPa = (5 << 10);
|
||||||
|
|
||||||
|
outw((uint16_t)acpi_fadt->pm1a_cnt_blk, SLP_TYPa | SLP_EN);
|
||||||
|
|
||||||
|
if (acpi_fadt->pm1b_cnt_blk != 0) {
|
||||||
|
outw((uint16_t)acpi_fadt->pm1b_cnt_blk, SLP_TYPb | SLP_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
//virtulizers last just incase these have some sort of unintended effect on real hw
|
||||||
|
outw(0xB004, 0x2000); // bochs
|
||||||
|
outw(0x4004, 0x3400); // vbox
|
||||||
|
outw(0x604, 0x2000); // QEMU
|
||||||
|
outw(0x600, 0x34); // Cloud Hypervisor
|
||||||
|
|
||||||
|
asm volatile("cli");
|
||||||
|
for(;;) asm volatile("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
int acpi_init(void){
|
||||||
|
acpi_rsdp = acpi_get_rsdp();
|
||||||
|
if (!acpi_rsdp)
|
||||||
|
kernel_panic(NULL, "ACPI does not provide a required RSDP");
|
||||||
|
|
||||||
|
size_t rsdp_len = acpi_rsdp->revision >= 2 ? acpi_rsdp->length : 20;
|
||||||
|
if (!acpi_checksum(acpi_rsdp, rsdp_len))
|
||||||
|
kernel_panic(NULL, "bad RSDP checksum");
|
||||||
|
|
||||||
|
acpi_fadt = (struct acpi_fadt *)acpi_get_sdt("FACP");
|
||||||
|
if (!acpi_fadt)
|
||||||
|
kernel_panic(NULL, "FADT not found");
|
||||||
|
|
||||||
|
if (!acpi_checksum(acpi_fadt, acpi_fadt->header.length))
|
||||||
|
kernel_panic(NULL, "bad FADT checksum");
|
||||||
|
|
||||||
|
if (acpi_fadt->smi_cmd && acpi_fadt->acpi_enable) {
|
||||||
|
outb(acpi_fadt->smi_cmd, acpi_fadt->acpi_enable);
|
||||||
|
|
||||||
|
int timeout = 1000000;
|
||||||
|
while (!(inw(acpi_fadt->pm1a_cnt_blk) & 1) && timeout-- > 0)
|
||||||
|
asm("pause");
|
||||||
|
if (timeout <= 0) {
|
||||||
|
kernel_panic(NULL, "Enable timeout");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
acpi_madt = (struct acpi_madt *)acpi_get_sdt("APIC");
|
||||||
|
if (!acpi_madt)
|
||||||
|
kernel_panic(NULL, "MADT not found");
|
||||||
|
|
||||||
|
if (!acpi_checksum(acpi_madt, acpi_madt->header.length))
|
||||||
|
kernel_panic(NULL, "bad MADT checksum");
|
||||||
|
|
||||||
|
uint8_t *ptr = acpi_madt->entries;
|
||||||
|
uint8_t *end = (uint8_t *)acpi_madt + acpi_madt->header.length;
|
||||||
|
|
||||||
|
while (ptr < end) {
|
||||||
|
struct madt_entry_header *h = (void *)ptr;
|
||||||
|
if (h->length < sizeof(struct madt_entry_header))
|
||||||
|
break;
|
||||||
|
if (ptr + h->length > end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (h->type) {
|
||||||
|
case 2: {
|
||||||
|
if (iso_count < MAX_ISO) {
|
||||||
|
struct madt_iso *iso = (void *)ptr;
|
||||||
|
iso_table[iso_count].source = iso->source;
|
||||||
|
iso_table[iso_count].gsi = iso->gsi;
|
||||||
|
iso_table[iso_count].flags = iso->flags;
|
||||||
|
iso_count++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr += h->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t acpi_irq_to_gsi(uint32_t irq) {
|
||||||
|
for (size_t i = 0; i < iso_count; i++) {
|
||||||
|
if (iso_table[i].source == irq)
|
||||||
|
return iso_table[i].gsi;
|
||||||
|
}
|
||||||
|
return irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t acpi_irq_flags(uint32_t irq) {
|
||||||
|
for (size_t i = 0; i < iso_count; i++) {
|
||||||
|
if (iso_table[i].source == irq)
|
||||||
|
return iso_table[i].flags;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
25
src/drivers/acpi.h
Normal file
25
src/drivers/acpi.h
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef ACPI_H
|
||||||
|
#define ACPI_H
|
||||||
|
|
||||||
|
int acpi_init(void);
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void acpi_shutdown(void);
|
||||||
|
__attribute__((noreturn)) void acpi_reboot(void);
|
||||||
|
|
||||||
|
uint32_t acpi_irq_to_gsi(uint32_t irq);
|
||||||
|
uint16_t acpi_irq_flags(uint32_t irq);
|
||||||
|
|
||||||
|
//power stuff
|
||||||
|
|
||||||
|
#define PM1A_CNT fadt->pm1a_cnt_blk
|
||||||
|
#define PM1B_CNT fadt->pm1b_cnt_blk
|
||||||
|
|
||||||
|
#define ACPI_S5 0x5
|
||||||
|
#define SLP_EN (1 << 13)
|
||||||
|
|
||||||
|
#define ACPI_PM1_SLEEP_CMD(slp_typ) (((slp_typ) << 10) | SLP_EN)
|
||||||
|
|
||||||
|
void acpi_parse_s5(void);
|
||||||
|
__attribute__((noreturn)) void acpi_shutdown(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
129
src/drivers/acpi_structures.h
Normal file
129
src/drivers/acpi_structures.h
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
#ifndef ACPI_STRUCTURES_H
|
||||||
|
#define ACPI_STRUCTURES_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct acpi_sdt {
|
||||||
|
char signature[4];
|
||||||
|
uint32_t length;
|
||||||
|
uint8_t revision;
|
||||||
|
uint8_t checksum;
|
||||||
|
char oem_id[6];
|
||||||
|
char oem_table_id[8];
|
||||||
|
uint32_t oem_revision;
|
||||||
|
uint32_t creator_id;
|
||||||
|
uint32_t creator_revision;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct acpi_rsdp {
|
||||||
|
char signature[8];
|
||||||
|
uint8_t checksum;
|
||||||
|
char oem_id[6];
|
||||||
|
uint8_t revision;
|
||||||
|
uint32_t rsdt_address;
|
||||||
|
|
||||||
|
// acpi2
|
||||||
|
uint32_t length;
|
||||||
|
uint64_t xsdt_address;
|
||||||
|
uint8_t extended_checksum;
|
||||||
|
uint8_t reserved[3];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct acpi_xsdt {
|
||||||
|
struct acpi_sdt header;
|
||||||
|
uint64_t tables[];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t address_space_id;
|
||||||
|
uint8_t register_bit_width;
|
||||||
|
uint8_t register_bit_offset;
|
||||||
|
uint8_t access_size;
|
||||||
|
uint64_t address;
|
||||||
|
} __attribute__((packed)) GenericAddressStructure;
|
||||||
|
|
||||||
|
typedef struct acpi_fadt
|
||||||
|
{
|
||||||
|
struct acpi_sdt header;
|
||||||
|
uint32_t firmware_ctrl;
|
||||||
|
uint32_t dsdt;
|
||||||
|
uint8_t __reserved;
|
||||||
|
uint8_t preferred_pm_profile;
|
||||||
|
uint16_t sci_int;
|
||||||
|
uint32_t smi_cmd;
|
||||||
|
uint8_t acpi_enable;
|
||||||
|
uint8_t acpi_disable;
|
||||||
|
uint8_t s4bios_req;
|
||||||
|
uint8_t pstate_cnt;
|
||||||
|
uint32_t pm1a_evt_blk;
|
||||||
|
uint32_t pm1b_evt_blk;
|
||||||
|
uint32_t pm1a_cnt_blk;
|
||||||
|
uint32_t pm1b_cnt_blk;
|
||||||
|
uint32_t pm2_cnt_blk;
|
||||||
|
uint32_t pm_tmr_blk;
|
||||||
|
uint32_t gpe0_blk;
|
||||||
|
uint32_t gpe1_blk;
|
||||||
|
uint8_t pm1_evt_len;
|
||||||
|
uint8_t pm1_cnt_len;
|
||||||
|
uint8_t pm2_cnt_len;
|
||||||
|
uint8_t pm_tmr_len;
|
||||||
|
uint8_t gpe0_blk_len;
|
||||||
|
uint8_t gpe1_blk_len;
|
||||||
|
uint8_t gpe1_base;
|
||||||
|
uint8_t cst_cnt;
|
||||||
|
uint16_t p_lvl2_lat;
|
||||||
|
uint16_t p_lvl3_lat;
|
||||||
|
uint16_t flush_size;
|
||||||
|
uint16_t flush_stride;
|
||||||
|
uint8_t duty_offset;
|
||||||
|
uint8_t duty_width;
|
||||||
|
uint8_t day_alrm;
|
||||||
|
uint8_t mon_alrm;
|
||||||
|
uint8_t century;
|
||||||
|
uint16_t iapc_boot_arch;
|
||||||
|
uint8_t __reserved2;
|
||||||
|
uint32_t flags;
|
||||||
|
GenericAddressStructure reset_reg;
|
||||||
|
uint8_t reset_value;
|
||||||
|
uint16_t arm_boot_arch;
|
||||||
|
uint8_t fadt_minor_version;
|
||||||
|
uint64_t x_firmware_ctrl;
|
||||||
|
uint64_t x_dsdt;
|
||||||
|
uint8_t x_pm1a_evt_blk[12];
|
||||||
|
uint8_t x_pm1b_evt_blk[12];
|
||||||
|
uint8_t x_pm1a_cnt_blk[12];
|
||||||
|
uint8_t x_pm1b_cnt_blk[12];
|
||||||
|
uint8_t x_pm2_cnt_blk[12];
|
||||||
|
uint8_t x_pm_tmr_blk[12];
|
||||||
|
uint8_t x_gpe0_blk[12];
|
||||||
|
uint8_t x_gpe1_blk[12];
|
||||||
|
uint8_t sleep_control_reg[12];
|
||||||
|
uint8_t sleep_status_reg[12];
|
||||||
|
uint64_t hypervison_vendor_identity;
|
||||||
|
} __attribute__((packed)) fadt_t;
|
||||||
|
|
||||||
|
struct acpi_madt {
|
||||||
|
struct acpi_sdt header;
|
||||||
|
uint32_t lapic_addr;
|
||||||
|
uint32_t flags;
|
||||||
|
uint8_t entries[];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct madt_iso {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t bus;
|
||||||
|
uint8_t source;
|
||||||
|
uint32_t gsi;
|
||||||
|
uint16_t flags;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct madt_entry_header {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t length;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct acpi_sdt *acpi_find_sdt(const char sig[4]);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -4,15 +4,13 @@
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "kutils.h"
|
#include "kutils.h"
|
||||||
|
#include "../core/panic.h"
|
||||||
|
|
||||||
extern void serial_write(const char *str);
|
extern void serial_write(const char *str);
|
||||||
|
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
|
|
||||||
|
|
||||||
void kernel_panic(registers_t *regs, const char *error_name);
|
|
||||||
|
|
||||||
static const char *exception_messages[] = {
|
static const char *exception_messages[] = {
|
||||||
"Division By Zero",
|
"Division By Zero",
|
||||||
"Debug",
|
"Debug",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue