diff --git a/devel/qemu/grub.cfg b/devel/qemu/grub.cfg index fa12792a..ae42ae85 100644 --- a/devel/qemu/grub.cfg +++ b/devel/qemu/grub.cfg @@ -34,6 +34,8 @@ linux16 /boot/jinue \ DEBUG_DUMP_SYSCALL_IMPLEMENTATION=1 \ DEBUG_DUMP_RAMDISK=1 \ DEBUG_DO_REBOOT=1 \ + RUN_TEST_ACPI=1 \ RUN_TEST_IPC=1 + initrd16 /boot/jinue-testapp-initrd.tar.gz boot diff --git a/devel/virtualbox/grub.cfg b/devel/virtualbox/grub.cfg index 9af1634d..a5ab4137 100644 --- a/devel/virtualbox/grub.cfg +++ b/devel/virtualbox/grub.cfg @@ -32,6 +32,8 @@ linux16 /boot/jinue \ DEBUG_DUMP_MEMORY_MAP=1 \ DEBUG_DUMP_SYSCALL_IMPLEMENTATION=1 \ DEBUG_DUMP_RAMDISK=1 \ + RUN_TEST_ACPI=1 \ RUN_TEST_IPC=1 + initrd16 /boot/jinue-testapp-initrd.tar.gz boot diff --git a/doc/init-process.md b/doc/init-process.md index 55067b02..51776bda 100644 --- a/doc/init-process.md +++ b/doc/init-process.md @@ -171,6 +171,7 @@ The following table lists the auxiliary vectors: | 6 | `JINUE_AT_ENTRY` | Address of program entry point | | 7 | `JINUE_AT_STACKBASE` | Stack base address | | 8 | `JINUE_AT_HOWSYSCALL` | System call implementation | +| 9 | `JINUE_AT_ACPI_RSDP` | Physical address of ACPI RSDP | The value of the `JINUE_AT_HOWSYSCALL` auxiliary vector identifies the system call implementation to use on architectures where there can be diff --git a/doc/syscalls/README.md b/doc/syscalls/README.md index 3352db9b..c18ea29d 100644 --- a/doc/syscalls/README.md +++ b/doc/syscalls/README.md @@ -28,8 +28,9 @@ | 19 | [MINT](mint.md) | Mint a Descriptor | | 20 | [START_THREAD](start-thread.md) | Start a Thread | | 21 | [AWAIT_THREAD](await-thread.md) | Wait for a Thread to Exit | -| 22 | [REPLY_ERROR](reply-error.md) | Reply to Message with an Error ! -| 23-4095 | - | Reserved | +| 22 | [REPLY_ERROR](reply-error.md) | Reply to Message with an Error | +| 23 | [SET_ACPI](set-acpi.md) | Provide Mapped ACPI Tables | +| 24-4095 | - | Reserved | | 4096+ | [SEND](send.md) | Send Message | #### Reserved Function Numbers diff --git a/doc/syscalls/set-acpi.md b/doc/syscalls/set-acpi.md new file mode 100644 index 00000000..cb2bec6e --- /dev/null +++ b/doc/syscalls/set-acpi.md @@ -0,0 +1,59 @@ +# SET_ACPI - Provide Mapped ACPI Tables + +## Description + +Provide the mapped ACPI tables to the kernel. + +This system call is reserved for use by the user space loader. It fails if +called by another process. + +The user space loader must make a best effort to map the relevant ACPI tables +and must call this system call with the result, unless the `JINUE_AT_ACPI_RSDP` +auxiliary vector has been set to zero or omitted. + +## Arguments + +Function number (`arg0`) is 23. + +A pointer to a [jinue_acpi_tables_t structure](../../include/jinue/shared/types.h) +(i.e. the ACPI tables structure) that contains pointers to mapped ACPI tables +is set in `arg1`. + +If the user space loader could not map certain ACPI tables, it should set the +relevant pointers to zero (C language `NULL` value) and still call this +function. + +``` + +----------------------------------------------------------------+ + | function = 23 | arg0 + +----------------------------------------------------------------+ + 31 0 + + +----------------------------------------------------------------+ + | pointer to ACPI tables structure | arg1 + +----------------------------------------------------------------+ + 31 0 + + +----------------------------------------------------------------+ + | reserved (0) | arg2 + +----------------------------------------------------------------+ + 31 0 + + +----------------------------------------------------------------+ + | reserved (0) | arg3 + +----------------------------------------------------------------+ + 31 0 +``` + +## Return Value + +On success, this function returns 0 (in `arg0`). On failure, this function +returns -1 and an error number is set (in `arg1`). + +## Errors + +* JINUE_EINVAL if any part of the ACPI tables structure as specified by `arg1` +belongs to the kernel. +* JINUE_ENOSYS if this function does not exist on this CPU architecture. +* JINUE_ENOSYS if this function is called by a process other than the user +space loader. diff --git a/header.mk b/header.mk index adbd6c7b..a3f187f0 100644 --- a/header.mk +++ b/header.mk @@ -115,12 +115,12 @@ endif # # These flags are used when preprocessing C and assembly language files. CPPFLAGS.includes = -I$(includes) -CPPFLAGS.arch = -m32 -march=i686 +CPPFLAGS.arch = -m32 -march=i686 CPPFLAGS.others = -nostdinc CPPFLAGS = $(CPPFLAGS.arch) $(CPPFLAGS.includes) $(CPPFLAGS.debug) $(CPPFLAGS.others) $(CPPFLAGS.extra) # C compiler flags -CFLAGS.warnings = -std=c99 -pedantic -Wall -Werror=implicit -Werror=uninitialized -Werror=return-type +CFLAGS.warnings = -std=c99 -pedantic -Wall -Wno-array-bounds -Werror=implicit -Werror=uninitialized -Werror=return-type CFLAGS.arch = -m32 -march=i686 CFLAGS.optimization = -O3 CFLAGS.others = -ffreestanding -fno-pie -fno-common -fno-omit-frame-pointer -fno-delete-null-pointer-checks diff --git a/include/jinue/jinue.h b/include/jinue/jinue.h index 596ff574..ffe1834f 100644 --- a/include/jinue/jinue.h +++ b/include/jinue/jinue.h @@ -119,4 +119,6 @@ int jinue_await_thread(int fd, int *perrno); int jinue_reply_error(uintptr_t errcode, int *perrno); +int jinue_set_acpi(jinue_acpi_tables_t *tables, int *perrno); + #endif diff --git a/include/jinue/shared/asm/auxv.h b/include/jinue/shared/asm/auxv.h index 5cd921ba..40a5f132 100644 --- a/include/jinue/shared/asm/auxv.h +++ b/include/jinue/shared/asm/auxv.h @@ -59,4 +59,7 @@ /** System call implementation */ #define JINUE_AT_HOWSYSCALL 8 +/** Address of RSDP (ACPI) */ +#define JINUE_AT_ACPI_RSDP 9 + #endif diff --git a/include/jinue/shared/asm/syscalls.h b/include/jinue/shared/asm/syscalls.h index 1f0d89e4..ad1e82e6 100644 --- a/include/jinue/shared/asm/syscalls.h +++ b/include/jinue/shared/asm/syscalls.h @@ -92,6 +92,9 @@ /** reply to current message with an error code */ #define JINUE_SYS_REPLY_ERROR 22 +/** provide the mapped ACPI tables */ +#define JINUE_SYS_SET_ACPI 23 + /** start of function numbers for user space messages */ #define JINUE_SYS_USER_BASE 4096 diff --git a/include/jinue/shared/types.h b/include/jinue/shared/types.h index 7e0fa8da..2c39e4d8 100644 --- a/include/jinue/shared/types.h +++ b/include/jinue/shared/types.h @@ -113,4 +113,10 @@ typedef struct { uintptr_t cookie; } jinue_mint_args_t; +typedef struct { + const void *rsdt; + const void *fadt; + const void *madt; +} jinue_acpi_tables_t; + #endif diff --git a/include/kernel/application/syscalls.h b/include/kernel/application/syscalls.h index 51e17547..be6e5412 100644 --- a/include/kernel/application/syscalls.h +++ b/include/kernel/application/syscalls.h @@ -72,6 +72,8 @@ int reply_error(uintptr_t errcode); int send(uintptr_t *errcode, int fd, int function, const jinue_message_t *message); +int set_acpi(const jinue_acpi_tables_t *tables); + void set_thread_local(void *addr, size_t size); int start_thread(int fd, const thread_params_t *params); diff --git a/include/kernel/infrastructure/i686/drivers/acpi.h b/include/kernel/infrastructure/i686/drivers/acpi.h new file mode 100644 index 00000000..e5ae275c --- /dev/null +++ b/include/kernel/infrastructure/i686/drivers/acpi.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_ACPI_H +#define JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_ACPI_H + +#include <kernel/infrastructure/i686/drivers/asm/acpi.h> +#include <stdint.h> + +typedef struct { + char signature[8]; + uint8_t checksum; + char oemid[6]; + uint8_t revision; + uint32_t rsdt_address; + uint32_t length; + uint64_t xsdt_address; + uint8_t extended_checksum; + uint8_t reserved[3]; +} acpi_rsdp_t; + +void acpi_init(void); + +uint32_t acpi_get_rsdp_paddr(void); + +#endif diff --git a/include/kernel/infrastructure/i686/drivers/asm/acpi.h b/include/kernel/infrastructure/i686/drivers/asm/acpi.h new file mode 100644 index 00000000..caf1a150 --- /dev/null +++ b/include/kernel/infrastructure/i686/drivers/asm/acpi.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_ASM_ACPI_H +#define JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_ASM_ACPI_H + +#define ACPI_BDA_EBDA 0x40e + +#define ACPI_V1_REVISION 0 + +#define ACPI_V2_REVISION 2 + +#define ACPI_V1_RSDP_SIZE 20 + +#endif diff --git a/include/kernel/machine/acpi.h b/include/kernel/machine/acpi.h new file mode 100644 index 00000000..2f95086b --- /dev/null +++ b/include/kernel/machine/acpi.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JINUE_KERNEL_MACHINE_ACPI_H +#define JINUE_KERNEL_MACHINE_ACPI_H + +#include <jinue/shared/types.h> +#include <stdint.h> + +void machine_set_acpi_tables(const jinue_acpi_tables_t *tables); + +#endif + diff --git a/include/kernel/machine/auxv.h b/include/kernel/machine/auxv.h index 2ef4add1..b04c6eb0 100644 --- a/include/kernel/machine/auxv.h +++ b/include/kernel/machine/auxv.h @@ -36,5 +36,7 @@ uint32_t machine_at_howsyscall(void); +uint32_t machine_at_acpi_rsdp(void); + #endif diff --git a/include/kernel/types.h b/include/kernel/types.h index 14071b39..19293f2c 100644 --- a/include/kernel/types.h +++ b/include/kernel/types.h @@ -87,10 +87,17 @@ struct descriptor_t { uintptr_t cookie; }; +typedef enum { + PROCESS_ID_KERNEL, + PROCESS_ID_LOADER, + PROCESS_ID_USER +} process_id; + typedef struct { object_header_t header; addr_space_t addr_space; int running_threads_count; + process_id id; spinlock_t descriptors_lock; descriptor_t descriptors[JINUE_DESC_NUM]; } process_t; diff --git a/kernel/Makefile b/kernel/Makefile index e7d1b4cf..92614e36 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -63,6 +63,7 @@ sources.kernel.c = \ application/interrupts/hardware.c \ application/interrupts/spurious.c \ application/interrupts/tick.c \ + application/syscalls/acpi.c \ application/syscalls/close.c \ application/syscalls/create_endpoint.c \ application/syscalls/create_process.c \ @@ -100,10 +101,11 @@ sources.kernel.c = \ domain/services/panic.c \ domain/services/scheduler.c \ domain/config.c \ - infrastructure/i686/drivers/vga.c \ + infrastructure/i686/drivers/acpi.c \ infrastructure/i686/drivers/pic8259.c \ infrastructure/i686/drivers/pit8253.c \ infrastructure/i686/drivers/uart16550a.c \ + infrastructure/i686/drivers/vga.c \ infrastructure/i686/pmap/nopae.c \ infrastructure/i686/pmap/pmap.c \ infrastructure/i686/pmap/pae.c \ diff --git a/kernel/application/kmain.c b/kernel/application/kmain.c index 673f7c44..7e93b575 100644 --- a/kernel/application/kmain.c +++ b/kernel/application/kmain.c @@ -91,6 +91,7 @@ void kmain(const char *cmdline) { panic("Could not create initial process."); } + process->id = PROCESS_ID_LOADER; process_switch_to(process); /* create user space loader main thread */ diff --git a/kernel/application/syscalls/acpi.c b/kernel/application/syscalls/acpi.c new file mode 100644 index 00000000..8660bd12 --- /dev/null +++ b/kernel/application/syscalls/acpi.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <jinue/shared/asm/errno.h> +#include <kernel/application/syscalls.h> +#include <kernel/domain/entities/process.h> +#include <kernel/machine/acpi.h> + +int set_acpi(const jinue_acpi_tables_t *tables) { + process_t *process = get_current_process(); + + if(process->id != PROCESS_ID_LOADER) { + return -JINUE_ENOSYS; + } + + machine_set_acpi_tables(tables); + + return 0; +} diff --git a/kernel/domain/entities/process.c b/kernel/domain/entities/process.c index c3c2032a..b4a11173 100644 --- a/kernel/domain/entities/process.c +++ b/kernel/domain/entities/process.c @@ -37,6 +37,7 @@ #include <kernel/machine/atomic.h> #include <kernel/machine/pmap.h> #include <kernel/machine/process.h> +#include <kernel/machine/spinlock.h> #include <kernel/machine/thread.h> #include <stddef.h> #include <string.h> @@ -83,6 +84,7 @@ static slab_cache_t process_cache; static void cache_ctor_op(void *buffer, size_t ignore) { process_t *process = buffer; object_init_header(&process->header, object_type_process); + init_spinlock(&process->descriptors_lock); } /** @@ -121,6 +123,8 @@ process_t *process_new(void) { process_t *process = slab_cache_alloc(&process_cache); if(process != NULL) { + process->running_threads_count = 0; + process->id = PROCESS_ID_USER; initialize_descriptors(process); if(!machine_init_process(process)) { diff --git a/kernel/infrastructure/elf.c b/kernel/infrastructure/elf.c index 6478ee53..63b92862 100644 --- a/kernel/infrastructure/elf.c +++ b/kernel/infrastructure/elf.c @@ -456,7 +456,7 @@ static void initialize_stack( /* Auxiliary vectors */ Elf32_auxv_t *auxvp = (Elf32_auxv_t *)sp; - sp = (uintptr_t *)(auxvp + 8); + sp = (uintptr_t *)(auxvp + 9); auxvp[0].a_type = JINUE_AT_PHDR; auxvp[0].a_un.a_val = (uint32_t)elf_info->at_phdr; @@ -479,8 +479,11 @@ static void initialize_stack( auxvp[6].a_type = JINUE_AT_HOWSYSCALL; auxvp[6].a_un.a_val = machine_at_howsyscall(); - auxvp[7].a_type = JINUE_AT_NULL; - auxvp[7].a_un.a_val = 0; + auxvp[7].a_type = JINUE_AT_ACPI_RSDP; + auxvp[7].a_un.a_val = machine_at_acpi_rsdp(); + + auxvp[8].a_type = JINUE_AT_NULL; + auxvp[8].a_un.a_val = 0; /* Write arguments and environment variables (i.e. the actual strings). */ char *const args = (char *)sp; diff --git a/kernel/infrastructure/i686/drivers/acpi.c b/kernel/infrastructure/i686/drivers/acpi.c new file mode 100644 index 00000000..6d9eb81d --- /dev/null +++ b/kernel/infrastructure/i686/drivers/acpi.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <kernel/infrastructure/i686/drivers/asm/vga.h> +#include <kernel/infrastructure/i686/drivers/acpi.h> +#include <kernel/machine/acpi.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +static uint32_t rsdp_paddr = 0; + +/** + * Verify the checksum of an ACPI data structure + * + * @param buffer pointer to ACPI data structure + * @param buflen size of ACPI data structure + * @return true for correct checksum, false for checksum mismatch + */ +static bool verify_checksum(const void *buffer, size_t buflen) { + uint8_t sum = 0; + + for(int idx = 0; idx < buflen; ++idx) { + sum += ((const uint8_t *)buffer)[idx]; + } + + return sum == 0; +} + +/** + * Validate the ACPI RSDP + * + * At the stage of the boot process where this function is called, the memory + * where the RSDP is located is mapped 1:1 so a pointer to the RSDP has the + * same value as its physical address. + * + * @param rsdp pointer to ACPI RSDP + * @return true is RSDP is valid, false otherwise + */ +static bool check_rsdp(const acpi_rsdp_t *rsdp) { + const char *const signature = "RSD PTR "; + + if(strncmp(rsdp->signature, signature, strlen(signature)) != 0) { + return false; + } + + if(!verify_checksum(rsdp, ACPI_V1_RSDP_SIZE)) { + return false; + } + + if(rsdp->revision == ACPI_V1_REVISION) { + return true; + } + + if(rsdp->revision != ACPI_V2_REVISION) { + return false; + } + + return verify_checksum(rsdp, sizeof(acpi_rsdp_t)); +} + +/** + * Find the RSDP in memory + * + * At the stage of the boot process where this function is called, the memory + * where the RSDP is located is mapped 1:1 so a pointer to the RSDP has the + * same value as its physical address. + * + * @return pointer to RSDP if found, NULL otherwise + */ +static const acpi_rsdp_t *find_rsdp(void) { + const char *const start = (const char *)0x0e0000; + const char *const end = (const char *)0x100000; + + for(const char *addr = start; addr < end; addr += 16) { + const acpi_rsdp_t *rsdp = (const acpi_rsdp_t *)addr; + + if(check_rsdp(rsdp)) { + return rsdp; + } + } + + const char *bottom = (const char *)0x10000; + const char *top = (const char *)(0xa0000 - 1024); + const char *ebda = (const char *)(16 * (*(uint16_t *)ACPI_BDA_EBDA)); + + if(ebda < bottom || ebda > top) { + return NULL; + } + + for(const char *addr = ebda; addr < ebda + 1024; addr += 16) { + const acpi_rsdp_t *rsdp = (const acpi_rsdp_t *)addr; + + if(check_rsdp(rsdp)) { + return rsdp; + } + } + + return NULL; +} + +/** + * Initialize ACPI + */ +void acpi_init(void) { + /* At the stage of the boot process where this function is called, the memory + * where the RSDP is located is mapped 1:1 so a pointer to the RSDP has the + * same value as its physical address. */ + rsdp_paddr = (uint32_t)find_rsdp(); +} + +/** + * Get the physical address of the ACPI RSDP + * + * @return physical address of RSDP if found, zero otherwise + */ +uint32_t acpi_get_rsdp_paddr(void) { + return rsdp_paddr; +} + +/** + * Process the ACPI tables mapped by user space + * + * @param tables structure with pointers to ACPI tables + */ +void machine_set_acpi_tables(const jinue_acpi_tables_t *tables) { + /* TODO implement this */ +} diff --git a/kernel/infrastructure/i686/init.c b/kernel/infrastructure/i686/init.c index f445a668..6534db82 100644 --- a/kernel/infrastructure/i686/init.c +++ b/kernel/infrastructure/i686/init.c @@ -35,6 +35,7 @@ #include <kernel/domain/services/logging.h> #include <kernel/domain/services/panic.h> #include <kernel/infrastructure/i686/asm/msr.h> +#include <kernel/infrastructure/i686/drivers/acpi.h> #include <kernel/infrastructure/i686/drivers/pic8259.h> #include <kernel/infrastructure/i686/drivers/pit8253.h> #include <kernel/infrastructure/i686/drivers/uart16550a.h> @@ -373,6 +374,8 @@ void machine_init(const config_t *config) { pit8253_init(); pic8259_unmask(IRQ_TIMER); + acpi_init(); + exec_file_t kernel; get_kernel_exec_file(&kernel, bootinfo); diff --git a/kernel/interface/i686/auxv.c b/kernel/interface/i686/auxv.c index ae535ce0..cc13ef60 100644 --- a/kernel/interface/i686/auxv.c +++ b/kernel/interface/i686/auxv.c @@ -29,9 +29,14 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <kernel/infrastructure/i686/drivers/acpi.h> #include <kernel/interface/i686/trap.h> #include <kernel/machine/auxv.h> uint32_t machine_at_howsyscall(void) { return syscall_implementation; } + +uint32_t machine_at_acpi_rsdp(void) { + return acpi_get_rsdp_paddr(); +} diff --git a/kernel/interface/syscalls.c b/kernel/interface/syscalls.c index 56ca7d07..93e26021 100644 --- a/kernel/interface/syscalls.c +++ b/kernel/interface/syscalls.c @@ -554,6 +554,20 @@ static void sys_reply_error(jinue_syscall_args_t *args) { set_return_value_or_error(args, retval); } +static void sys_acpi(jinue_syscall_args_t *args) { + const jinue_acpi_tables_t *userspace_tables = (const void *)args->arg1; + + if(! check_userspace_buffer(userspace_tables, sizeof(jinue_acpi_tables_t))) { + set_error(args, JINUE_EINVAL); + return; + } + + const jinue_acpi_tables_t tables = *userspace_tables; + + int retval = set_acpi(&tables); + set_return_value_or_error(args, retval); +} + /** * System call dispatching function * @@ -631,6 +645,9 @@ void handle_syscall(jinue_syscall_args_t *args) { case JINUE_SYS_REPLY_ERROR: sys_reply_error(args); break; + case JINUE_SYS_SET_ACPI: + sys_acpi(args); + break; default: sys_nosys(args); } diff --git a/userspace/lib/jinue/syscalls.c b/userspace/lib/jinue/syscalls.c index 06ac1b3d..45ca6522 100644 --- a/userspace/lib/jinue/syscalls.c +++ b/userspace/lib/jinue/syscalls.c @@ -336,3 +336,14 @@ int jinue_reply_error(uintptr_t errcode, int *perrno) { return call_with_usual_convention(&args, perrno); } + +int jinue_set_acpi(jinue_acpi_tables_t *tables, int *perrno) { + jinue_syscall_args_t args; + + args.arg0 = JINUE_SYS_SET_ACPI; + args.arg1 = (uintptr_t)tables; + args.arg2 = 0; + args.arg3 = 0; + + return call_with_usual_convention(&args, perrno); +} diff --git a/userspace/loader/Makefile b/userspace/loader/Makefile index ef48d1f7..ff112b62 100644 --- a/userspace/loader/Makefile +++ b/userspace/loader/Makefile @@ -31,6 +31,7 @@ jinue_root = ../.. include $(jinue_root)/header.mk sources.c = \ + acpi/acpi.c \ archives/alloc.c \ archives/tar.c \ binfmt/elf.c \ diff --git a/userspace/loader/acpi/acpi.c b/userspace/loader/acpi/acpi.c new file mode 100644 index 00000000..4e6bc6be --- /dev/null +++ b/userspace/loader/acpi/acpi.c @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <jinue/jinue.h> +#include <jinue/utils.h> +#include <sys/auxv.h> +#include <sys/mman.h> +#include <errno.h> +#include <inttypes.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include "../debug.h" +#include "acpi.h" + +/** + * Verify the checksum of an ACPI data structure + * + * @param buffer pointer to ACPI data structure + * @param buflen size of ACPI data structure + * @return true for correct checksum, false for checksum mismatch + * + * */ +static bool verify_checksum(const void *buffer, size_t buflen) { + uint8_t sum = 0; + + for(int idx = 0; idx < buflen; ++idx) { + sum += ((const uint8_t *)buffer)[idx]; + } + + return sum == 0; +} + +/** + * Verify the checksum of an ACPI table header + * + * @param header mapped ACPI table header + * @param signature expected signature + * @return true if the signature matches, false otherwise + * + * */ +static bool verify_signature(const acpi_header_t *header, const char *signature) { + return strncmp(header->signature, signature, sizeof(header->signature)) == 0; +} + +/** + * Map an ACPI data structure + * + * @param paddr physical memory address of data structure + * @param size size of data structure + * @return pointer to mapped data on success, NULL on error + * + * */ +static const void *map_size(uint64_t paddr, size_t size) { + size_t offset = paddr % JINUE_PAGE_SIZE; + + size += offset; + paddr -= offset; + + void *mapped = mmap(NULL, size, PROT_READ, MAP_SHARED, 0, paddr); + + if(mapped == MAP_FAILED) { + return NULL; + } + + return (const char *)mapped + offset; +} + +/** + * Map ACPI RSDP + * + * We don't validate the contents (checksum, revision) because we assume the + * kernel has done so before setting the address in the auxiliary vector. + * + * @param paddr physical memory address of ACPI RSDP + * @return pointer to mapped RSDP on success, NULL on error + * + * */ +static const acpi_rsdp_t *map_rsdp(uint64_t paddr) { + const acpi_rsdp_t *rsdp = map_size(paddr, ACPI_V1_RSDP_SIZE); + + if(rsdp == NULL || rsdp->revision == ACPI_V1_REVISION) { + return rsdp; + } + + size_t offset = paddr % JINUE_PAGE_SIZE; + + if(JINUE_PAGE_SIZE - offset >= sizeof(acpi_rsdp_t)) { + return rsdp; + } + + /* Here, we rely on the fact that our implementation of mmap() allocates + * virtual memory sequentially to simply extend the existing mapping. */ + size_t extsize = sizeof(acpi_rsdp_t) - (JINUE_PAGE_SIZE - offset); + const void *extension = map_size(paddr - offset + JINUE_PAGE_SIZE, extsize); + + if(extension == NULL) { + return NULL; + } + + return rsdp; +} + +/** + * Map ACPI table header + * + * @param paddr physical memory address of ACPI table header + * @return pointer to mapped header on success, NULL on error + * + * */ +static const acpi_header_t *map_header(uint64_t paddr) { + return map_size(paddr, sizeof(acpi_header_t)); +} + +/** + * Extend the existing mapping of a table header to the full table + * + * This function relies on the fact that our implementation of mmap() allocates + * virtual memory sequentially to extend an existing mapping. It assumes that + * mmap() wasn't called since the call to map_header() that mapped the table + * header passed as agument. + * + * @param paddr physical memory address of the ACPI table + * @param header mapped ACPI table header + * @param name table name, for log messages + * @return pointer to mapped table on success, NULL on error + * + * */ +static const void *map_table(uint64_t paddr, const acpi_header_t *header, const char *name) { + if(header->length < sizeof(acpi_header_t)) { + jinue_warning("Value of ACPI table length member is too small (%" PRIu32 ", %s)", name); + return NULL; + } + + if(header->length > ACPI_TABLE_MAX_SIZE) { + jinue_warning("Value of ACPI table length member is too large (%" PRIu32 ", %s)", name); + return NULL; + } + + size_t offset = paddr % JINUE_PAGE_SIZE; + size_t allocated = JINUE_PAGE_SIZE - offset; + + if(allocated < sizeof(acpi_header_t)) { + allocated += JINUE_PAGE_SIZE; + } + + if(header->length > allocated) { + /* Here, we rely on the fact that our implementation of mmap() allocates + * virtual memory sequentially to simply extend the existing mapping. */ + size_t extsize = header->length - allocated; + const void *extension = map_size(paddr + allocated, extsize); + + if(extension == NULL) { + jinue_warning("Failed mapping ACPI table (%s)", name); + return NULL; + } + } + + if(! verify_checksum(header, header->length)) { + jinue_warning("ACPI table checksum mismatch (%s)", name); + return NULL; + } + + return header; +} + +/* Size of the fixed part of the RSDT, excluding hte entries. */ +#define RSDT_BASE_SIZE ((size_t)(const char *)&(((const acpi_rsdt_t *)0)->entries)) + +/** + * Map the RSDT/XSDT + * + * @param paddr physical memory address of RSDT/XSDT + * @param is_xsdt whether the table is a XSDT (true) or a RSDT (false) + * @return mapped RSDT/XSDT on success, NULL on error + * + * */ +static const acpi_rsdt_t *map_rsdt(uint64_t paddr, bool is_xsdt) { + const acpi_header_t *header = map_header(paddr); + + if(header == NULL) { + return NULL; + } + + const char *const signature = is_xsdt ? "XSDT" : "RSDT"; + + if(! verify_signature(header, signature)) { + jinue_warning("Signature mismatch for ACPI %s", signature); + return NULL; + } + + if(header->length < RSDT_BASE_SIZE) { + jinue_warning("ACPI %s table is too small", signature); + return NULL; + } + + return map_table(paddr, header, signature); +} + +/** + * Process the entries of the mapped RSDT/XSDT to find relevant tables + * + * @param tables tables structure (output) + * @param rsdt mapped RSDT/XSDT + * @param is_xsdt whether the table is a XSDT (true) or RSDT (false) + * + * */ +void process_rsdt(jinue_acpi_tables_t *tables, const acpi_rsdt_t *rsdt, bool is_xsdt) { + size_t entries = (rsdt->length - RSDT_BASE_SIZE) / sizeof(uint32_t); + + if(is_xsdt && entries % 2 != 0) { + --entries; + } + + for(int idx = 0; idx < entries; ++idx) { + /* x86 is little endian */ + uint64_t paddr = rsdt->entries[idx]; + + if(is_xsdt) { + paddr |= ((uint64_t)rsdt->entries[++idx]) << 32; + } + + const acpi_header_t *header = map_header(paddr); + + if(header == NULL) { + continue; + } + + const char *signature = "FACP"; + + if(verify_signature(header, signature) && tables->fadt == NULL) { + tables->fadt = map_table(paddr, header, "FADT"); + } + + signature = "APIC"; + + if(verify_signature(header, signature) && tables->madt == NULL) { + tables->madt = map_table(paddr, header, "MADT"); + } + } +} + +/** + * Map the RSDT/XSDT and then iterate over its entries to find relevant tables + * + * @param tables tables structure (output) + * @param paddr physical memory address of RSDT/XSDT + * @param is_xsdt whether the table is a XSDT (true) or RSDT (false) + * + * */ +static void load_rsdt(jinue_acpi_tables_t *tables, uint64_t paddr, bool is_xsdt) { + const acpi_rsdt_t *rsdt = map_rsdt(paddr, is_xsdt); + + if(rsdt == NULL) { + return; + } + + tables->rsdt = rsdt; + process_rsdt(tables, rsdt, is_xsdt); +} + +/** + * Map the RSDP/XSDT and then call load_rsdt() with the RSDT/XSDT address + * + * @param tables tables structure (output) + * @param rsdp_paddr physical memory address of the RSDP + * + * */ +static void load_rsdp(jinue_acpi_tables_t *tables, uint32_t rsdp_paddr) { + const acpi_rsdp_t *rsdp = map_rsdp(rsdp_paddr); + + if(rsdp == NULL) { + return; + } + + uint64_t rsdt_paddr; + bool is_xsdt; + + if(rsdp->revision == ACPI_V1_REVISION) { + rsdt_paddr = rsdp->rsdt_address; + is_xsdt = false; + } else { + /* TODO handle the case where the address > 4GB and PAE is disabled. */ + rsdt_paddr = rsdp->xsdt_address; + is_xsdt = true; + } + + load_rsdt(tables, rsdt_paddr, is_xsdt); +} + +/** + * Map relevant ACPI tables and report to kernel + * + * Map the ACPI tables needed by the kernel in memory, set the pointers to them + * in a tables structure (jinue_acpi_tables_t) and call the kernel with this + * information. + * + * @return EXIT_SUCCESS on success, EXIT_FAILURE on error + * + * */ +int load_acpi_tables(void) { + jinue_acpi_tables_t tables; + tables.rsdt = NULL; + tables.fadt = NULL; + tables.madt = NULL; + + uint32_t rsdp_paddr = getauxval(JINUE_AT_ACPI_RSDP); + + /* If the kernel set this auxiliary vector to zero, it knows the RSDP is + * nowhere to be found and doesn't expect to be called. Since this is + * expected, it is not a failure (i.e. we return EXIT_SUCCESS). + * + * In any other situation, the kernel does expect to be called with our + * best effort to map the tables so it can complete its initialization and + * it will deal with NULL entries in the tables structure if need be. */ + if(rsdp_paddr == 0) { + return EXIT_SUCCESS; + } + + load_rsdp(&tables, rsdp_paddr); + + dump_acpi_tables(&tables); + + int status = jinue_set_acpi(&tables, &errno); + + if(status != 0) { + jinue_error("error: ACPI call failed: %s", strerror(errno)); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/userspace/loader/acpi/acpi.h b/userspace/loader/acpi/acpi.h new file mode 100644 index 00000000..b820b9ef --- /dev/null +++ b/userspace/loader/acpi/acpi.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LOADER_ACPI_ACPI_H_ +#define LOADER_ACPI_ACPI_H_ + +#include <stdint.h> + +#define ACPI_V1_REVISION 0 + +#define ACPI_V1_RSDP_SIZE 20 + +/* Arbitrary value expected to be large enough to accomodate any real table + * while ensuring we don't create arbitrary large mappings because of garbage + * data in length members. */ +#define ACPI_TABLE_MAX_SIZE (32 * 1024) + +typedef struct { + char signature[8]; + uint8_t checksum; + char oemid[6]; + uint8_t revision; + uint32_t rsdt_address; + uint32_t length; + uint64_t xsdt_address; + uint8_t extended_checksum; + uint8_t reserved[3]; +} acpi_rsdp_t; + +typedef struct { + char signature[4]; + uint32_t length; + uint8_t revision; + uint8_t checksum; + /* There are more fields but we are not interested in them. */ +} acpi_header_t; + +typedef struct { + char signature[4]; + uint32_t length; + uint8_t revision; + uint8_t checksum; + char oemid[6]; + char oem_table_id[8]; + uint32_t oem_revision; + uint32_t creator_id; + uint32_t creator_revision; + uint32_t entries[]; +} acpi_rsdt_t; + +int load_acpi_tables(void); + +#endif diff --git a/userspace/loader/binfmt/elf.c b/userspace/loader/binfmt/elf.c index 386401eb..b60f1b22 100644 --- a/userspace/loader/binfmt/elf.c +++ b/userspace/loader/binfmt/elf.c @@ -443,7 +443,7 @@ static void initialize_stack( /* Auxiliary vectors */ Elf32_auxv_t *auxvp = (Elf32_auxv_t *)&wlocal[index]; - index += 8 * sizeof(auxvp[0]) / sizeof(wlocal[0]); + index += 9 * sizeof(auxvp[0]) / sizeof(wlocal[0]); auxvp[0].a_type = JINUE_AT_PHDR; auxvp[0].a_un.a_val = (uint32_t)elf_info->at_phdr; @@ -466,8 +466,11 @@ static void initialize_stack( auxvp[6].a_type = JINUE_AT_HOWSYSCALL; auxvp[6].a_un.a_val = getauxval(JINUE_AT_HOWSYSCALL); - auxvp[7].a_type = JINUE_AT_NULL; - auxvp[7].a_un.a_val = 0; + auxvp[7].a_type = JINUE_AT_ACPI_RSDP; + auxvp[7].a_un.a_val = getauxval(JINUE_AT_ACPI_RSDP); + + auxvp[8].a_type = JINUE_AT_NULL; + auxvp[8].a_un.a_val = 0; char *const args = (char *)&wlocal[index]; diff --git a/userspace/loader/debug.c b/userspace/loader/debug.c index f800585a..08fa7efc 100644 --- a/userspace/loader/debug.c +++ b/userspace/loader/debug.c @@ -29,10 +29,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <jinue/jinue.h> -#include <jinue/loader.h> #include <jinue/utils.h> #include <inttypes.h> +#include "acpi/acpi.h" #include "debug.h" #include "utils.h" @@ -116,3 +115,27 @@ void dump_ramdisk(const jinue_dirent_t *root) { dirent = jinue_dirent_get_next(dirent); } } + +static void dump_table(const acpi_header_t *table, const char *name) { + jinue_info(" %s:", name); + jinue_info(" address: %#p", table); + + if(table != NULL) { + jinue_info(" revision: %" PRIu8, table->revision); + jinue_info(" length: %" PRIu32, table->length); + } +} + +void dump_acpi_tables(const jinue_acpi_tables_t *tables) { + if(! bool_getenv("DEBUG_DUMP_ACPI_TABLES")) { + return; + } + + const acpi_header_t *rsdt = tables->rsdt; + const char *rsdt_name = (rsdt != NULL && rsdt->signature[0] == 'X') ? "XSDT" : "RSDT"; + + jinue_info("ACPI tables:"); + dump_table(rsdt, rsdt_name); + dump_table(tables->fadt, "FADT"); + dump_table(tables->madt, "MADT"); +} diff --git a/userspace/loader/debug.h b/userspace/loader/debug.h index 61c9c568..49f74887 100644 --- a/userspace/loader/debug.h +++ b/userspace/loader/debug.h @@ -32,6 +32,11 @@ #ifndef LOADER_DEBUG_H_ #define LOADER_DEBUG_H_ +#include <jinue/jinue.h> +#include <jinue/loader.h> + void dump_ramdisk(const jinue_dirent_t *root); +void dump_acpi_tables(const jinue_acpi_tables_t *tables); + #endif diff --git a/userspace/loader/loader.c b/userspace/loader/loader.c index 328e1cbb..db8e6ff8 100644 --- a/userspace/loader/loader.c +++ b/userspace/loader/loader.c @@ -35,6 +35,7 @@ #include <errno.h> #include <stdlib.h> #include <string.h> +#include "acpi/acpi.h" #include "binfmt/elf.h" #include "core/meminfo.h" #include "core/server.h" @@ -176,14 +177,14 @@ static int start_initial_thread(thread_params_t *thread_params) { &errno ); - if (status != 0) { + if(status != 0) { jinue_error("error: could not start thread: %s", strerror(errno)); return EXIT_FAILURE; } status = jinue_close(INIT_THREAD_DESCRIPTOR, &errno); - if (status != 0) { + if(status != 0) { jinue_error("error: could not close thread descriptor: %s", strerror(errno)); return EXIT_FAILURE; } @@ -194,6 +195,12 @@ static int start_initial_thread(thread_params_t *thread_params) { int main(int argc, char *argv[]) { jinue_info("Jinue user space loader (%s) started.", argv[0]); + int status = load_acpi_tables(); + + if(status != EXIT_SUCCESS) { + return status; + } + initialize_meminfo(); char map_buffer[MAP_BUFFER_SIZE]; @@ -205,7 +212,7 @@ int main(int argc, char *argv[]) { ramdisk_t ramdisk; - int status = map_ramdisk(&ramdisk, map); + status = map_ramdisk(&ramdisk, map); if(status != EXIT_SUCCESS) { return status; diff --git a/userspace/testapp/Makefile b/userspace/testapp/Makefile index af073dd4..873dde6c 100644 --- a/userspace/testapp/Makefile +++ b/userspace/testapp/Makefile @@ -30,7 +30,7 @@ jinue_root = ../.. include $(jinue_root)/header.mk -sources.c = tests/ipc.c debug.c testapp.c utils.c +sources.c = tests/acpi.c tests/ipc.c debug.c testapp.c utils.c testapp = testapp stripped = $(testapp)-stripped temp_ramdisk_fs = ramdisk-tmp diff --git a/userspace/testapp/debug.c b/userspace/testapp/debug.c index e7af154a..ca8a94df 100644 --- a/userspace/testapp/debug.c +++ b/userspace/testapp/debug.c @@ -88,6 +88,7 @@ static const char *auxv_type_name(int type) { {"AT_ENTRY", JINUE_AT_ENTRY}, {"AT_STACKBASE", JINUE_AT_STACKBASE}, {"AT_HOWSYSCALL", JINUE_AT_HOWSYSCALL}, + {"AT_ACPI_RSDP", JINUE_AT_ACPI_RSDP}, {NULL, 0} }; diff --git a/userspace/testapp/testapp.c b/userspace/testapp/testapp.c index f84b0ec9..80333a56 100644 --- a/userspace/testapp/testapp.c +++ b/userspace/testapp/testapp.c @@ -37,6 +37,7 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> +#include "tests/acpi.h" #include "tests/ipc.h" #include "debug.h" #include "utils.h" @@ -61,6 +62,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } + run_acpi_test(); run_ipc_test(); if(bool_getenv("DEBUG_DO_REBOOT")) { diff --git a/userspace/testapp/tests/acpi.c b/userspace/testapp/tests/acpi.c new file mode 100644 index 00000000..d1219d83 --- /dev/null +++ b/userspace/testapp/tests/acpi.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <jinue/jinue.h> +#include <jinue/utils.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include "../utils.h" +#include "acpi.h" + +void run_acpi_test(void) { + if(! bool_getenv("RUN_TEST_ACPI")) { + return; + } + + jinue_info("Running ACPI test..."); + + jinue_acpi_tables_t tables; + tables.rsdt = NULL; + tables.fadt = NULL; + tables.madt = NULL; + + int status = jinue_set_acpi(&tables, &errno); + + if(status >= 0) { + jinue_error("error: jinue_set_acpi() unexpectedly succeeded"); + return; + } + + if(errno != JINUE_ENOSYS) { + jinue_error("error: jinue_set_acpi() failed: %s.", strerror(errno)); + return; + } + + jinue_info("expected: jinue_set_acpi() set errno to: %s.", strerror(errno)); +} diff --git a/userspace/testapp/tests/acpi.h b/userspace/testapp/tests/acpi.h new file mode 100644 index 00000000..bf7c69a0 --- /dev/null +++ b/userspace/testapp/tests/acpi.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTAPP_TEST_ACPI_H_ +#define TESTAPP_TEST_ACPI_H_ + +void run_acpi_test(void); + +#endif