diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index d10ad4e..bea3028 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -8,38 +8,20 @@ on: jobs: build-linux: - strategy: - matrix: - linux-version: - - version: 6.6.0-13-generic - deb: - all: http://launchpadlibrarian.net/698860017/linux-headers-6.6.0-13_6.6.0-13.13_all.deb - generic: http://launchpadlibrarian.net/698860014/linux-headers-6.6.0-13-generic_6.6.0-13.13_amd64.deb - - version: 6.11.0-9-generic - deb: - all: http://launchpadlibrarian.net/754119749/linux-headers-6.11.0-9_6.11.0-9.9_all.deb - generic: http://launchpadlibrarian.net/754119748/linux-headers-6.11.0-9-generic_6.11.0-9.9_amd64.deb runs-on: ubuntu-latest env: - LINUX_HEADERS: /lib/modules/${{ matrix.linux-version.version }}/build GNU_EFI: ${{ github.workspace }}/gnu-efi steps: - uses: actions/checkout@v4 with: submodules: 'true' - - name: Install kernel headers - run: | - 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 - cd ${{ github.workspace }}/gnu-efi - make -j $(nproc) + git clone https://git.code.sf.net/p/gnu-efi/code $GNU_EFI + make -C $GNU_EFI -j $(nproc) - name: Build run: make build diff --git a/Makefile b/Makefile index 1e63f0c..20a8d32 100644 --- a/Makefile +++ b/Makefile @@ -30,18 +30,11 @@ ifdef QEMU_DEBUG endif clean: - $(MAKE) -C module clean $(MAKE) -C core clean $(MAKE) -C uefi clean - rm -rf module/*_shipped - rm -rf $(VM_MOUNT_DIR) .PHONY: clean -module/%.o_shipped: core/build/%.o - touch module/.$*.o.cmd - cp $^ $@ - uefi/obj/%.o: core/build/%.o mkdir -p $(dir $@) cp $^ $@ @@ -49,24 +42,17 @@ uefi/obj/%.o: core/build/%.o core/build/core.o: $(MAKE) -C core -module/switch_os.ko: module/core.o_shipped - $(MAKE) -C module - uefi/build/app.efi: uefi/obj/core.o $(MAKE) -C uefi -.PHONY: core/build/core.o module/switch_os.ko uefi/build/app.efi - -build/vm_mount: module/switch_os.ko - mkdir -p $@ - cp -f $^ $@ +.PHONY: core/build/core.o uefi/build/app.efi build/efi: uefi/build/app.efi mkdir -p $@ mkdir -p $@/EFI/BOOT cp -f $^ $@/EFI/BOOT/BOOTX64.efi -build: build/vm_mount build/efi +build: build/efi qemu: build $(QEMU) \ @@ -76,7 +62,6 @@ qemu: build -drive if=pflash,format=raw,file=$(OVMF_VARS) \ -hda fat:rw:build/efi \ -hdb fat:rw:$(LINUX_DISK_PATH) \ - -virtfs local,path=build/vm_mount,mount_tag=qemu_root,security_model=passthrough,id=qemu_root,readonly=on \ -drive id=buffer_drive,file=$(BUFFER_DRIVE_IMG),if=none,format=raw -device virtio-blk-pci,drive=buffer_drive \ -enable-kvm \ -vga virtio \ diff --git a/core/drivers/virtio/virtio_blk.c b/core/drivers/virtio/virtio_blk.c index 2da9cdc..a0df336 100644 --- a/core/drivers/virtio/virtio_blk.c +++ b/core/drivers/virtio/virtio_blk.c @@ -150,7 +150,7 @@ static err_t negotiate_virtio_features(struct virtio_blk_dev* virtio_blk_dev) { err_t init_virtio_blk_dev(struct virtio_blk_dev* virtio_blk_dev) { err_t err = SUCCESS; - // We expect module to fill the device's pci address for us. + // We expect the UEFI app to fill the device's pci address for us. virtio_blk_dev->pci_dev.addr.bus = g_core_header.disk_pci.addr.bus; virtio_blk_dev->pci_dev.addr.device = g_core_header.disk_pci.addr.device; virtio_blk_dev->pci_dev.addr.function = g_core_header.disk_pci.addr.function; @@ -160,7 +160,7 @@ err_t init_virtio_blk_dev(struct virtio_blk_dev* virtio_blk_dev) { CHECK(virtio_blk_dev->pci_dev.vendor_id == VIRTIO_BLK_VENDOR_ID && virtio_blk_dev->pci_dev.device_id == VIRTIO_BLK_DEVICE_ID); - // Restore the device's bars using the bars module filled for us. + // Restore the device's bars using the bars the UEFI app filled for us. // This is crucial since the device loses power when entering S3 suspend, and // loses the bar values. // The BIOS is the one initially responsible for configuring the bars for the diff --git a/module/Kbuild b/module/Kbuild deleted file mode 100644 index 0ddae98..0000000 --- a/module/Kbuild +++ /dev/null @@ -1,16 +0,0 @@ -obj-m += switch_os.o - -switch_os-y += module.o -switch_os-y += devices.o -switch_os-y += acpi.o -switch_os-y += configure_core_header.o -switch_os-y += suspend/hook_sleep_prepare.o - -# Shipped core binary -switch_os-y += core.o - -ccflags-y := -I $(ROOT_DIR)/shared/include -DMODULE - -ifdef TRACE_DEBUG - ccflags-y += -D TRACE_DEBUG -endif diff --git a/module/Makefile b/module/Makefile deleted file mode 100644 index 6d6a8a0..0000000 --- a/module/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -LINUX_HEADERS ?= $(error Must pass LINUX_HEADERS variable) - -all: - make -C $(LINUX_HEADERS) M=$(CURDIR) modules - -clean: - make -C $(LINUX_HEADERS) M=$(CURDIR) clean - -.PHONY: all clean diff --git a/module/acpi.c b/module/acpi.c deleted file mode 100644 index 1083d5a..0000000 --- a/module/acpi.c +++ /dev/null @@ -1,47 +0,0 @@ -#include "acpi.h" - -#include -#include - -err_t acpi_find_rsdp(uint64_t* rsdp_out) { - err_t err = SUCCESS; - - // Taken from the kernel's `cpi_os_get_root_pointer` - CHECK(efi_enabled(EFI_CONFIG_TABLES)); - CHECK(efi.acpi20 != EFI_INVALID_TABLE_ADDR); - - *rsdp_out = efi.acpi20; - -cleanup: - return err; -} - -err_t acpi_find_waking_vector(uint32_t* waking_vector_out) { - err_t err = SUCCESS; - struct acpi_table_facs* facs = NULL; - - // The waking vector is stored in the FACS ACPI table. - // We can access this table by using the FADT ACPI table, as it stores the - // physical address of the FACS table. - - struct acpi_table_fadt fadt = acpi_gbl_FADT; - uint32_t facs_phys_addr = fadt.facs; - CHECK_TRACE(facs_phys_addr != 0, "FACS table physical address is uninitialized by the kernel\n"); - - // The ACPI tables must be mapped as write-back. - facs = ioremap_cache(facs_phys_addr, sizeof(struct acpi_table_facs)); - CHECK_TRACE(facs != NULL, "Failed to map FACS table onto virtual memory\n"); - - uint32_t waking_vector = facs->firmware_waking_vector; - CHECK_TRACE(waking_vector != 0, "Waking vector physical address is uninitialized by the kernel\n"); - - *waking_vector_out = waking_vector; - -cleanup: - if (facs != NULL) { - // Unmap FACS from virtual memory - iounmap(facs); - } - - return err; -} diff --git a/module/acpi.h b/module/acpi.h deleted file mode 100644 index 34e8e98..0000000 --- a/module/acpi.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _ACPI_H -#define _ACPI_H - -#include - -#include "error.h" - -/** - * Returns the physical address of the RSDP table. - */ -err_t acpi_find_rsdp(uint64_t* rsdp_out); - -/** - * Returns the physical address of the currently set waking vector. - */ -err_t acpi_find_waking_vector(uint32_t* waking_vector_out); - -#endif diff --git a/module/configure_core_header.c b/module/configure_core_header.c deleted file mode 100644 index 96ab297..0000000 --- a/module/configure_core_header.c +++ /dev/null @@ -1,33 +0,0 @@ -#include "configure_core_header.h" - -#include -#include -#include -#include - -#include "acpi.h" -#include "core/header.h" - -extern struct core_header* g_core_header; - -static err_t fill_original_waking_vector(void) { - err_t err = SUCCESS; - - uint32_t waking_vector; - CHECK_RETHROW(acpi_find_waking_vector(&waking_vector)); - g_core_header->original_waking_vector = waking_vector; - -cleanup: - return err; -} - -err_t configure_core_header(void) { - err_t err = SUCCESS; - - CHECK(g_core_header != NULL); - - CHECK_RETHROW(fill_original_waking_vector()); - -cleanup: - return err; -} diff --git a/module/configure_core_header.h b/module/configure_core_header.h deleted file mode 100644 index ff5fbc7..0000000 --- a/module/configure_core_header.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _CONFIGURE_CORE_HEADER_H -#define _CONFIGURE_CORE_HEADER_H - -#include "error.h" - -/** - * Configure the core header. This should be called by our `sleep_prepare` hook - * right before entering S3. - */ -err_t configure_core_header(void); - -#endif diff --git a/module/devices.c b/module/devices.c deleted file mode 100644 index 90ef8bb..0000000 --- a/module/devices.c +++ /dev/null @@ -1,93 +0,0 @@ -#include "devices.h" - -#include -#include -#include -#include - -#include "core/header.h" -#include "suspend/hook_sleep_prepare.h" - -#define SWITCH_OS_DEV_DIR "switch_os" - -extern struct core_header* g_core_header; - -struct switch_os_device { - char* name; - struct file_operations fops; - struct cdev cdev; -}; - -/** - * Calls core with the `CORE_ACTION_SWITCH` action. - * This switches the running system with the dump on the disk. - */ -static int switch_open(struct inode* inode, struct file* file) { - err_t err = SUCCESS; - - g_core_header->action = CORE_ACTION_SWITCH; - - CHECK_RETHROW(hook_sleep_prepare()); - - CHECK(pm_suspend(PM_SUSPEND_MEM) == 0); - -cleanup: - unhook_sleep_prepare(); - - return IS_SUCCESS(err) ? 0 : -EINVAL; -} - -/** - * Calls core with the `CORE_ACTION_STORE` action. - * This stores a dump of the running system on the disk. - */ -static int store_open(struct inode* inode, struct file* file) { - err_t err = SUCCESS; - - g_core_header->action = CORE_ACTION_STORE; - - CHECK_RETHROW(hook_sleep_prepare()); - - CHECK(pm_suspend(PM_SUSPEND_MEM) == 0); - -cleanup: - unhook_sleep_prepare(); - - return IS_SUCCESS(err) ? 0 : -EINVAL; -} - -static struct switch_os_device g_devices[] = { - { - .name = "switch", - .fops = {.open = switch_open}, - }, - { - .name = "store", - .fops = {.open = store_open}, - }, -}; - -err_t register_devices(void) { - err_t err = SUCCESS; - - // Receive a free dynamic major number for the character devices. - dev_t region_id = 0; - CHECK(alloc_chrdev_region(®ion_id, 0, ARRAY_SIZE(g_devices), "switch_os") == 0); - int major = MAJOR(region_id); - - for (size_t i = 0; i < ARRAY_SIZE(g_devices); i++) { - struct switch_os_device* device = &g_devices[i]; - dev_t dev_id = MKDEV(major, i); - - // Create the device so it shows in `/dev`. - struct class* class = class_create(device->name); - CHECK(!IS_ERR(device_create(class, NULL, dev_id, NULL, SWITCH_OS_DEV_DIR "/%s", device->name))); - - // Add the file operations. - cdev_init(&device->cdev, &device->fops); - CHECK(cdev_add(&device->cdev, dev_id, 1) == 0); - } - -cleanup: - return err; -} diff --git a/module/devices.h b/module/devices.h deleted file mode 100644 index 2cd67bb..0000000 --- a/module/devices.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _DEVICES_H -#define _DEVICES_H - -#include "error.h" - -/** - * Register module's character devices. - * These devices are used to communicate with this module from usermode, and call core. - */ -err_t register_devices(void); - -#endif diff --git a/module/module.c b/module/module.c deleted file mode 100644 index 41f80c8..0000000 --- a/module/module.c +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include -#include -#include - -#include "core/consts.h" -#include "core/header.h" -#include "devices.h" -#include "error.h" -#include "suspend/hook_sleep_prepare.h" -#include "trace.h" - -struct core_header* g_core_header = NULL; - -unsigned long trace(const char* fmt, ...) { - va_list args; - va_start(args, fmt); - unsigned long res = vprintk(fmt, args); - va_end(args); - return res; -} - -static err_t get_core_header_virt(struct core_header** core_header_out) { - err_t err = SUCCESS; - - // The UEFI application has already loaded core into `CORE_PHYS_ADDR`. - struct core_header* core_header = ioremap(CORE_PHYS_ADDR, sizeof(struct core_header)); - CHECK_TRACE(core_header != NULL, "Failed to map physical address %lx\n", (uintptr_t)CORE_PHYS_ADDR); - - // Sanity check to make sure this is really the core header. - CHECK(is_core_header_magic_valid(core_header)); - - *core_header_out = core_header; - -cleanup: - return err; -} - -static int __init switchos_init(void) { - err_t err = SUCCESS; - - TRACE("Init switch_os kernel module\n"); - - CHECK_RETHROW(get_core_header_virt(&g_core_header)); - CHECK_RETHROW(register_devices()); - -cleanup: - return IS_SUCCESS(err) ? 0 : -1; -} - -static void __exit switchos_exit(void) { - TRACE("Unloading switch_os kernel module\n"); - - unhook_sleep_prepare(); -} - -MODULE_LICENSE("GPL"); - -module_init(switchos_init); -module_exit(switchos_exit); diff --git a/module/suspend/hook_sleep_prepare.c b/module/suspend/hook_sleep_prepare.c deleted file mode 100644 index 5cd283e..0000000 --- a/module/suspend/hook_sleep_prepare.c +++ /dev/null @@ -1,50 +0,0 @@ -#include "hook_sleep_prepare.h" - -#include -#include -#include - -#include "../configure_core_header.h" -#include "core/consts.h" - -/** - * Called right when `acpi_sleep_prepare` ends. - * We configure core's header and hook the waking vector. - * - * `acpi_sleep_prepare` sets the ACPI waking vector. We access it by using - * `get_acpi_waking_vector`, and override the waking vector to - * core's wakeup procedure. - */ -static int my_acpi_sleep_prepare(struct kretprobe_instance* ri, struct pt_regs* regs) { - if (configure_core_header() != SUCCESS) { - return 0; - } - - acpi_set_firmware_waking_vector(CORE_WAKEUP_PHYS_ADDR, 0); - return 0; -} - -static struct kretprobe g_kretprobe; - -static atomic_t g_is_hooked = ATOMIC_INIT(false); - -err_t hook_sleep_prepare(void) { - err_t err = SUCCESS; - - memset(&g_kretprobe, 0, sizeof(g_kretprobe)); - g_kretprobe.kp.symbol_name = "acpi_sleep_prepare"; - g_kretprobe.handler = my_acpi_sleep_prepare; - - if (atomic_xchg(&g_is_hooked, true) == false) { - CHECK(register_kretprobe(&g_kretprobe) == 0); - } - -cleanup: - return err; -} - -void unhook_sleep_prepare(void) { - if (atomic_xchg(&g_is_hooked, false) == true) { - unregister_kretprobe(&g_kretprobe); - } -} diff --git a/module/suspend/hook_sleep_prepare.h b/module/suspend/hook_sleep_prepare.h deleted file mode 100644 index e2cb8fb..0000000 --- a/module/suspend/hook_sleep_prepare.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _HOOK_SLEEP_PREPARE -#define _HOOK_SLEEP_PREPARE - -#include - -#include "error.h" - -/* - * `acpi_sleep_prepare` is called right before the kernel enters suspend mode, - * and sets the waking vector. Therefore, we have to interrupt it and override - * the waking vector to core's wakeup procedure. - */ -err_t hook_sleep_prepare(void); - -/* - * Removes the hook placed by `hook_sleep_prepare`. - */ -void unhook_sleep_prepare(void); - -#endif