Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ jobs:
wget ${{ matrix.linux-version.deb.all }}
wget ${{ matrix.linux-version.deb.generic }}
sudo apt install -y ./*.deb
- name: Install dependencies
run: |
sudo apt install -y iasl
- name: Install GNU-EFI
run: |
git clone https://git.code.sf.net/p/gnu-efi/code ${{ github.workspace }}/gnu-efi
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*.mod.c
*.bin
*.ld.gen
obj/

*~
.*~
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export VPATH := $(ROOT_DIR)
export CC ?= gcc
export LD ?= ld
export OBJCOPY ?= objcopy
export IASL ?= iasl

QEMU ?= qemu-system-x86_64
QEMU_ADDITIONAL_FLAGS ?=
Expand Down
6 changes: 5 additions & 1 deletion core/acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,16 @@ void acpi_destroy(void) {
}

void acpi_return_kernel(void) {
uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S3);

if (g_kernel_waking_vector != 0) {
// This might occur after `uacpi_prepare_for_sleep_state`, since it calls the `_PTS` which is still hooked to
// override the waking vector to core's entry.
// According to the ACPI specs, the `_PTS` should be executed prior to updating the waking vector anyway.
uacpi_set_waking_vector(g_kernel_waking_vector, 0);
} else {
TRACE("Kernel waking vector not set!\n");
}

uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S3);
uacpi_enter_sleep_state(UACPI_SLEEP_STATE_S3);
}
20 changes: 10 additions & 10 deletions shared/include/core/consts.h
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
#ifndef _INCLUDE_CORE_CONSTS
#define _INCLUDE_CORE_CONSTS

#define CORE_HEADER_MAGIC (0x12345678)
#define CORE_DISK_DUMP_MAGIC (0xabcdef12)
#define CORE_HEADER_MAGIC 0x12345678
#define CORE_DISK_DUMP_MAGIC 0xabcdef12

#define CORE_PHYS_ADDR (0x41000000)
#define CORE_MAIN_PHYS_ADDR (0x41001000)
#define CORE_MAX_PHYS_MEM_SIZE (0x3000000)
#define CORE_PHYS_ADDR 0x41000000
#define CORE_MAIN_PHYS_ADDR 0x41001000
#define CORE_MAX_PHYS_MEM_SIZE 0x3000000

#define CORE_RM_PHYS_ADDR (0x1000)
#define CORE_MAX_RM_PHYS_MEM_SIZE (0x1000)
#define CORE_RM_PHYS_ADDR 0x1000
#define CORE_MAX_RM_PHYS_MEM_SIZE 0x1000

#define CORE_PM_PHYS_ADDR (0x40000000)
#define CORE_MAX_PM_PHYS_MEM_SIZE (0x1000000)
#define CORE_PM_PHYS_ADDR 0x40000000
#define CORE_MAX_PM_PHYS_MEM_SIZE 0x1000000

#define CORE_MAIN_OFFSET (CORE_MAIN_PHYS_ADDR - CORE_PHYS_ADDR)

#define CORE_WAKEUP_PHYS_ADDR (CORE_RM_PHYS_ADDR)
#define CORE_WAKEUP_PHYS_ADDR CORE_RM_PHYS_ADDR

#endif
17 changes: 17 additions & 0 deletions shared/include/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ typedef enum {
} \
} while (0)

#define CHECK_RETHROW_SILENT(expr) \
do { \
err_t _err = (expr); \
if (!IS_SUCCESS(_err)) { \
err = _err; \
goto cleanup; \
} \
} while (0)

#define CHECK_TRACE(expr, fmt, ...) \
do { \
if (!(expr)) { \
Expand All @@ -29,6 +38,14 @@ typedef enum {
} \
} while (0)

#define CHECK_SILENT(expr) \
do { \
if (!(expr)) { \
err = ERROR; \
goto cleanup; \
} \
} while (0)

#define IS_SUCCESS(expr) ((expr) == SUCCESS)

#define IS_ERROR(expr) ((expr) != SUCCESS)
Expand Down
16 changes: 15 additions & 1 deletion shared/include/mem.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,21 @@ static inline int strcmp(const char* str1, const char* str2) {

while (str1[i] && str2[i]) {
if (str1[i] != str2[i]) {
return str1[i] - str2[i];
break;
}

i++;
}

return str1[i] - str2[i];
}

static inline int wstrcmp(const wchar_t* str1, const wchar_t* str2) {
size_t i = 0;

while (str1[i] && str2[i]) {
if (str1[i] != str2[i]) {
break;
}

i++;
Expand Down
5 changes: 3 additions & 2 deletions uefi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ CFLAGS := -I$(GNU_EFI)/inc \
-fpic -ffreestanding -fno-stack-protector \
-fno-stack-check -fshort-wchar -mno-red-zone -maccumulate-outgoing-args \
-I . \
-I obj/include \
-I $(ROOT_DIR)/shared/include/ \
-D GNU_EFI_USE_MS_ABI \
-D UEFI
Expand Down Expand Up @@ -31,7 +32,7 @@ OBJS += app.o
OBJS += core_header_utils.o
OBJS += core_loader.o

OBJS += acpi/tables.o
include acpi/Makefile

OBJS += hooks/hooks_loader.o
OBJS += hooks/loaders/get_memory_map.o
Expand All @@ -54,7 +55,7 @@ hooks/raw/build/hooks.o:

obj/%.o: %.c
mkdir -p $(dir $@)
$(CC) -c $^ -o $@ $(CFLAGS)
$(CC) -c $< -o $@ $(CFLAGS)

obj/app.so: $(OBJS) $(GNU_EFI)/x86_64/gnuefi/crt0-efi-x86_64.o hooks/raw/build/hooks.o
mkdir -p $(dir $@)
Expand Down
15 changes: 15 additions & 0 deletions uefi/acpi/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
OBJS += acpi/tables.o
OBJS += acpi/hook_pts.o
OBJS += acpi/patch/dsdt.o
OBJS += acpi/patch/method.o
OBJS += acpi/patch/patch_utils.o
OBJS += acpi/patch/pkg_length.o

IASL_FLAGS := -I $(ROOT_DIR)/shared/include \
-sc -so

obj/include/asl/%.c: acpi/asl/%.asl
@mkdir -p $(dir $@)
$(IASL) $(IASL_FLAGS) -p $(dir $@)$* $^

obj/acpi/hook_pts.o: obj/include/asl/pts_hook.c
12 changes: 12 additions & 0 deletions uefi/acpi/aml.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef _ACPI_AML_H
#define _ACPI_AML_H

#define AML_ZERO_OP 0x0
#define AML_METHOD_OP 0x14
#define AML_RETURN_OP 0xA4
#define AML_ARG0_OP 0x68

#define AML_METHOD_NAME_LEN 4
#define AML_METHOD_FLAGS_LEN 1

#endif
25 changes: 25 additions & 0 deletions uefi/acpi/asl/pts_hook.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "core/consts.h"

DefinitionBlock ("", "SSDT", 2, "", "", 0x0)
{
Method (_PTS, 1, NotSerialized)
{
OperationRegion (FACS, SystemMemory, 0x12345678, 64)
Field (FACS, AnyAcc, NoLock, Preserve)
{
Offset (12),
FWAK, 32,
}

// Overwrite the waking vector with core's entry.
FWAK = CORE_RM_PHYS_ADDR

SPTS(arg0)
}

Method (SPTS, 1, NotSerialized)
{
// This function is a placeholder, and won't be loaded when hooking the `_PTS`.
// In case `_PTS` already exists, it will be renamed to `SPTS` and our hook will call it.
}
}
73 changes: 73 additions & 0 deletions uefi/acpi/hook_pts.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include "hook_pts.h"

#include <stddef.h>

#include "acpi/aml.h"
#include "acpi/patch/pkg_length.h"
#include "asl/pts_hook.c"
#include "asl/pts_hook.offset.h"
#include "mem.h"
#include "patch/method.h"
#include "tables.h"
#include "utils.h"

/**
* Relocates the `FACS` OperationRegion in the `_PTS` hook to point to the physical address of the real FACS table.
*
* See the hook `pts_hook.asl` for the OperationRegion declaration, and see the generated `pts_hook.offset.h` for the
* format offsets table.
*/
static err_t pts_relocate_facs_addr(void) {
err_t err = SUCCESS;

// The offsets table in `pts_hook.offset.h` includes an entry for the `FACS` OperationRegion called `_PTS.FACS`.
// It includes the offset to the address of the `FACS` OperationRegion which we wish to relocate.
size_t facs_addr_reloc_offset = -1;
for (size_t i = 0; i < ARRAY_SIZE(SSDT__OffsetTable); i++) {
if (strcmp(SSDT__OffsetTable[i].Pathname, "_PTS.FACS") == 0) {
// The offset is from the beginning of the AML program, but we need the offset from the `SSDT___PTS_FACS` byte
// array. It comes right after the `SSDT__Header` and `SSDT____PTS`.
facs_addr_reloc_offset = SSDT__OffsetTable[i].Offset - sizeof(SSDT__Header) - sizeof(SSDT___PTS);
}
}

CHECK(facs_addr_reloc_offset != -1);
// Make sure we don't overflow.
CHECK(facs_addr_reloc_offset + sizeof(uint32_t) <= sizeof(SSDT___PTS_FACS));

// Relocate the address to the real FACS table.
uint32_t* facs_addr_reloc = (uint32_t*)(SSDT___PTS_FACS + facs_addr_reloc_offset);
*facs_addr_reloc = (uint32_t)(uintptr_t)g_facs;

cleanup:
return err;
}

err_t create_or_hook_pts(void) {
err_t err = SUCCESS;

CHECK_RETHROW(pts_relocate_facs_addr());

if (find_method("_PTS", NULL, NULL) == SUCCESS) {
// Hook the `_PTS` method by renaming it to `SPTS`, and creating a new `_PTS` method which calls the renamed `SPTS`.
// See the code in `pts_hook.asl` for its implementation.
CHECK_RETHROW(
hook_method("_PTS", "SPTS", SSDT___PTS, sizeof(SSDT___PTS), SSDT___PTS_FACS, sizeof(SSDT___PTS_FACS)));
} else {
TRACE("Creating a _PTS method\n");

// The hook in `pts_hook.asl` ends with a call to `SPTS` (the original `_PTS`). This is only necessary in the case
// we hook an existing `_PTS`. Otherwise we have to get rid of this call.
// This call is encoded as:
// 0x53, 0x50, 0x54, 0x53, 0x68 /* A call to `SPTS` with `arg0` as an argument */
// We could truncate the hook's body by 5 bytes, but this would also require fixing its PkgLength.
// Instead, we can replace these bytes with ZeroOps.
size_t call_spts_byte_count = AML_METHOD_NAME_LEN + 1;
memset(SSDT___PTS_FACS + sizeof(SSDT___PTS_FACS) - call_spts_byte_count, AML_ZERO_OP, call_spts_byte_count);

CHECK_RETHROW(append_method(SSDT___PTS, sizeof(SSDT___PTS), SSDT___PTS_FACS, sizeof(SSDT___PTS_FACS)));
}

cleanup:
return err;
}
14 changes: 14 additions & 0 deletions uefi/acpi/hook_pts.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include "error.h"

/**
* Places a hook on the `_PTS` method if it exists, or creates a new `_PTS` with the hook body if it doesn't exist.
*
* If the `_PTS` method already exists, it is renamed to `SPTS` and our hook calls it when it's done.
*
* The hook content is taken from `pts_hook.asl`. Notice it always tries to call `SPTS`. We explicitly remove this call
* if the `_PTS` doesn't exist (in this case the hook becomes the actual `_PTS` method, and the `SPTS` method does not
* exist).
*/
err_t create_or_hook_pts(void);
Loading