mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
[metal] Add a uprintf() routine, for non-emergency boot logging (#905)
* [metal] Add a uprintf() routine, for non-emergency boot logging * [metal] _Really_ push forward timing of VGA TTY initialization * [metal] Do something useful with uprintf() * [metal] Locate some ACPI tables, for later hardware detection Specifically the code now tries to find the ACPI RSDP, RSDT/XSDT, FADT, & MADT tables, whether in legacy BIOS bootup mode or in a UEFI bootup. These are useful for figuring out how to (re)enable asynchronous interrupts in legacy 8259 PIC mode.
This commit is contained in:
parent
062b2d776e
commit
ed17d3008b
25 changed files with 999 additions and 36 deletions
11
Makefile
11
Makefile
|
@ -170,11 +170,13 @@ include third_party/puff/puff.mk # │
|
||||||
include libc/elf/elf.mk # │
|
include libc/elf/elf.mk # │
|
||||||
include ape/ape.mk # │
|
include ape/ape.mk # │
|
||||||
include libc/fmt/fmt.mk # │
|
include libc/fmt/fmt.mk # │
|
||||||
include libc/vga/vga.mk #─┘
|
include libc/vga/vga.mk # │
|
||||||
|
include libc/irq/irq.mk #─┘
|
||||||
include libc/calls/calls.mk #─┐
|
include libc/calls/calls.mk #─┐
|
||||||
include third_party/nsync/nsync.mk # │
|
include libc/irq/irq.mk # ├──SYSTEMS RUNTIME
|
||||||
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
|
include third_party/nsync/nsync.mk # │ You can issue system calls
|
||||||
include third_party/double-conversion/dc.mk # │ You can issue system calls
|
include libc/runtime/runtime.mk # │
|
||||||
|
include third_party/double-conversion/dc.mk # │
|
||||||
include libc/crt/crt.mk # │
|
include libc/crt/crt.mk # │
|
||||||
include third_party/dlmalloc/dlmalloc.mk #─┘
|
include third_party/dlmalloc/dlmalloc.mk #─┘
|
||||||
include libc/mem/mem.mk #─┐
|
include libc/mem/mem.mk #─┐
|
||||||
|
@ -374,6 +376,7 @@ COSMOPOLITAN_OBJECTS = \
|
||||||
LIBC_RUNTIME \
|
LIBC_RUNTIME \
|
||||||
THIRD_PARTY_NSYNC \
|
THIRD_PARTY_NSYNC \
|
||||||
LIBC_ELF \
|
LIBC_ELF \
|
||||||
|
LIBC_IRQ \
|
||||||
LIBC_CALLS \
|
LIBC_CALLS \
|
||||||
LIBC_SYSV_CALLS \
|
LIBC_SYSV_CALLS \
|
||||||
LIBC_VGA \
|
LIBC_VGA \
|
||||||
|
|
|
@ -46,6 +46,7 @@ EXAMPLES_DIRECTDEPS = \
|
||||||
LIBC_DNS \
|
LIBC_DNS \
|
||||||
LIBC_FMT \
|
LIBC_FMT \
|
||||||
LIBC_INTRIN \
|
LIBC_INTRIN \
|
||||||
|
LIBC_IRQ \
|
||||||
LIBC_LOG \
|
LIBC_LOG \
|
||||||
LIBC_MEM \
|
LIBC_MEM \
|
||||||
LIBC_NEXGEN32E \
|
LIBC_NEXGEN32E \
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
|
|
||||||
__static_yoink("vga_console");
|
__static_yoink("vga_console");
|
||||||
__static_yoink("_idt");
|
__static_yoink("_idt");
|
||||||
|
__static_yoink("_AcpiMadtFlags");
|
||||||
|
__static_yoink("_AcpiBootFlags");
|
||||||
__static_yoink("EfiMain");
|
__static_yoink("EfiMain");
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/metalfile.internal.h"
|
#include "libc/calls/metalfile.internal.h"
|
||||||
#include "libc/intrin/directmap.internal.h"
|
#include "libc/intrin/directmap.internal.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/intrin/weaken.h"
|
#include "libc/intrin/weaken.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
@ -74,6 +75,7 @@ textstartup void InitializeMetalFile(void) {
|
||||||
memcpy(copied_base, (void *)(BANE + IMAGE_BASE_PHYSICAL), size);
|
memcpy(copied_base, (void *)(BANE + IMAGE_BASE_PHYSICAL), size);
|
||||||
__ape_com_base = copied_base;
|
__ape_com_base = copied_base;
|
||||||
__ape_com_size = size;
|
__ape_com_size = size;
|
||||||
|
KINFOF("%s @ %p,+%#zx", APE_COM_NAME, copied_base, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,12 @@
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/calls/metalfile.internal.h"
|
#include "libc/calls/metalfile.internal.h"
|
||||||
|
|
||||||
.init.start 101,_init_metalfile
|
.init.start 102,_init_metalfile
|
||||||
push %rdi
|
push %rdi
|
||||||
push %rsi
|
push %rsi
|
||||||
call InitializeMetalFile
|
call InitializeMetalFile
|
||||||
pop %rsi
|
pop %rsi
|
||||||
pop %rdi
|
pop %rdi
|
||||||
.init.end 101,_init_metalfile
|
.init.end 102,_init_metalfile
|
||||||
APE_COM_NAME:
|
APE_COM_NAME:
|
||||||
.endobj APE_COM_NAME,globl,hidden
|
.endobj APE_COM_NAME,globl,hidden
|
||||||
|
|
|
@ -728,6 +728,8 @@ void abort(void) wontreturn;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define __weak_reference(sym, alias) \
|
#define __weak_reference(sym, alias) \
|
||||||
|
__weak_reference_impl(sym, alias)
|
||||||
|
#define __weak_reference_impl(sym, alias) \
|
||||||
__asm__(".weak\t" #alias "\n\t" \
|
__asm__(".weak\t" #alias "\n\t" \
|
||||||
".equ\t" #alias ", " #sym "\n\t" \
|
".equ\t" #alias ", " #sym "\n\t" \
|
||||||
".type\t" #alias ",@notype")
|
".type\t" #alias ",@notype")
|
||||||
|
|
|
@ -25,7 +25,9 @@
|
||||||
│ OTHER DEALINGS IN THE SOFTWARE. │
|
│ OTHER DEALINGS IN THE SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/runtime/pc.internal.h"
|
#include "libc/runtime/pc.internal.h"
|
||||||
|
|
||||||
// Code and data structures for bare metal interrupt handling.
|
// Code and data structures for bare metal interrupt handling.
|
||||||
|
|
|
@ -385,14 +385,29 @@ privileged long kloghandle(void) {
|
||||||
return __klog_handle;
|
return __klog_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
privileged void _klog_serial(const char *b, size_t n) {
|
||||||
|
size_t i;
|
||||||
|
uint16_t dx;
|
||||||
|
unsigned char al;
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
for (;;) {
|
||||||
|
dx = 0x3F8 + UART_LSR;
|
||||||
|
asm("inb\t%1,%0" : "=a"(al) : "dN"(dx));
|
||||||
|
if (al & UART_TTYTXR) break;
|
||||||
|
asm("pause");
|
||||||
|
}
|
||||||
|
dx = 0x3F8;
|
||||||
|
asm volatile("outb\t%0,%1"
|
||||||
|
: /* no inputs */
|
||||||
|
: "a"(b[i]), "dN"(dx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
privileged void klog(const char *b, size_t n) {
|
privileged void klog(const char *b, size_t n) {
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
int e;
|
int e;
|
||||||
long h;
|
long h;
|
||||||
size_t i;
|
|
||||||
uint16_t dx;
|
|
||||||
uint32_t wrote;
|
uint32_t wrote;
|
||||||
unsigned char al;
|
|
||||||
long rax, rdi, rsi, rdx;
|
long rax, rdi, rsi, rdx;
|
||||||
if ((h = kloghandle()) == -1) {
|
if ((h = kloghandle()) == -1) {
|
||||||
return;
|
return;
|
||||||
|
@ -407,18 +422,7 @@ privileged void klog(const char *b, size_t n) {
|
||||||
if (_weaken(_klog_vga)) {
|
if (_weaken(_klog_vga)) {
|
||||||
_weaken(_klog_vga)(b, n);
|
_weaken(_klog_vga)(b, n);
|
||||||
}
|
}
|
||||||
for (i = 0; i < n; ++i) {
|
_klog_serial(b, n);
|
||||||
for (;;) {
|
|
||||||
dx = 0x3F8 + UART_LSR;
|
|
||||||
asm("inb\t%1,%0" : "=a"(al) : "dN"(dx));
|
|
||||||
if (al & UART_TTYTXR) break;
|
|
||||||
asm("pause");
|
|
||||||
}
|
|
||||||
dx = 0x3F8;
|
|
||||||
asm volatile("outb\t%0,%1"
|
|
||||||
: /* no inputs */
|
|
||||||
: "a"(b[i]), "dN"(dx));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
asm volatile("syscall"
|
asm volatile("syscall"
|
||||||
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
|
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
|
||||||
|
@ -1152,3 +1156,6 @@ privileged void kprintf(const char *fmt, ...) {
|
||||||
kvprintf(fmt, v);
|
kvprintf(fmt, v);
|
||||||
va_end(v);
|
va_end(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__weak_reference(kprintf, uprintf);
|
||||||
|
__weak_reference(kvprintf, uvprintf);
|
||||||
|
|
|
@ -9,25 +9,49 @@
|
||||||
#define kvsnprintf __kvsnprintf
|
#define kvsnprintf __kvsnprintf
|
||||||
#define kloghandle __kloghandle
|
#define kloghandle __kloghandle
|
||||||
#define kisdangerous __kisdangerous
|
#define kisdangerous __kisdangerous
|
||||||
|
#define uprintf __uprintf
|
||||||
|
#define uvprintf __uvprintf
|
||||||
|
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
void kprintf(const char *, ...);
|
|
||||||
size_t ksnprintf(char *, size_t, const char *, ...);
|
|
||||||
void kvprintf(const char *, va_list);
|
|
||||||
size_t kvsnprintf(char *, size_t, const char *, va_list);
|
|
||||||
bool kisdangerous(const void *);
|
|
||||||
|
|
||||||
void kprintf(const char *, ...);
|
void kprintf(const char *, ...);
|
||||||
size_t ksnprintf(char *, size_t, const char *, ...);
|
size_t ksnprintf(char *, size_t, const char *, ...);
|
||||||
void kvprintf(const char *, va_list);
|
void kvprintf(const char *, va_list);
|
||||||
size_t kvsnprintf(char *, size_t, const char *, va_list);
|
size_t kvsnprintf(char *, size_t, const char *, va_list);
|
||||||
|
|
||||||
bool kisdangerous(const void *);
|
bool kisdangerous(const void *);
|
||||||
|
|
||||||
void klog(const char *, size_t);
|
void klog(const char *, size_t);
|
||||||
|
void _klog_serial(const char *, size_t);
|
||||||
long kloghandle(void);
|
long kloghandle(void);
|
||||||
|
|
||||||
|
void uprintf(const char *, ...);
|
||||||
|
void uvprintf(const char *, va_list);
|
||||||
|
|
||||||
|
#ifndef TINY
|
||||||
|
#define KINFOF(FMT, ...) \
|
||||||
|
do { \
|
||||||
|
uprintf("\r\e[35m%s:%d: " FMT "\e[0m\n", \
|
||||||
|
__FILE__, __LINE__, ## __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#define KWARNF(FMT, ...) \
|
||||||
|
do { \
|
||||||
|
uprintf("\r\e[94;49mwarn: %s:%d: " FMT "\e[0m\n", \
|
||||||
|
__FILE__, __LINE__, ## __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define KINFOF(FMT, ...) ((void)0)
|
||||||
|
#define KWARNF(FMT, ...) ((void)0)
|
||||||
|
#endif
|
||||||
|
#define KDIEF(FMT, ...) \
|
||||||
|
do { \
|
||||||
|
kprintf("\r\e[30;101mfatal: %s:%d: " FMT "\e[0m\n", \
|
||||||
|
__FILE__, __LINE__, ## __VA_ARGS__); \
|
||||||
|
for (;;) asm volatile("cli\n\thlt"); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* _COSMO_SOURCE */
|
#endif /* _COSMO_SOURCE */
|
||||||
|
|
43
libc/irq/acpi-fadt-init.S
Normal file
43
libc/irq/acpi-fadt-init.S
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||||
|
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ This is free and unencumbered software released into the public domain. │
|
||||||
|
│ │
|
||||||
|
│ Anyone is free to copy, modify, publish, use, compile, sell, or │
|
||||||
|
│ distribute this software, either in source code form or as a compiled │
|
||||||
|
│ binary, for any purpose, commercial or non-commercial, and by any │
|
||||||
|
│ means. │
|
||||||
|
│ │
|
||||||
|
│ In jurisdictions that recognize copyright laws, the author or authors │
|
||||||
|
│ of this software dedicate any and all copyright interest in the │
|
||||||
|
│ software to the public domain. We make this dedication for the benefit │
|
||||||
|
│ of the public at large and to the detriment of our heirs and │
|
||||||
|
│ successors. We intend this dedication to be an overt act of │
|
||||||
|
│ relinquishment in perpetuity of all present and future rights to this │
|
||||||
|
│ software under copyright law. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||||
|
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||||
|
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||||
|
│ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR │
|
||||||
|
│ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
|
||||||
|
│ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR │
|
||||||
|
│ OTHER DEALINGS IN THE SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/irq/acpi.internal.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/runtime/pc.internal.h"
|
||||||
|
|
||||||
|
.init.start 312,_init_acpi_fadt
|
||||||
|
push %rdi
|
||||||
|
push %rsi
|
||||||
|
call _AcpiFadtInit
|
||||||
|
pop %rsi
|
||||||
|
pop %rdi
|
||||||
|
.init.end 312,_init_acpi_fadt
|
||||||
|
.data
|
||||||
|
_AcpiBootFlags:
|
||||||
|
.short kAcpiFadtLegacyDevices | kAcpiFadt8042
|
||||||
|
.endobj _AcpiBootFlags,globl
|
||||||
|
.previous
|
80
libc/irq/acpi-fadt.c
Normal file
80
libc/irq/acpi-fadt.c
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ This is free and unencumbered software released into the public domain. │
|
||||||
|
│ │
|
||||||
|
│ Anyone is free to copy, modify, publish, use, compile, sell, or │
|
||||||
|
│ distribute this software, either in source code form or as a compiled │
|
||||||
|
│ binary, for any purpose, commercial or non-commercial, and by any │
|
||||||
|
│ means. │
|
||||||
|
│ │
|
||||||
|
│ In jurisdictions that recognize copyright laws, the author or authors │
|
||||||
|
│ of this software dedicate any and all copyright interest in the │
|
||||||
|
│ software to the public domain. We make this dedication for the benefit │
|
||||||
|
│ of the public at large and to the detriment of our heirs and │
|
||||||
|
│ successors. We intend this dedication to be an overt act of │
|
||||||
|
│ relinquishment in perpetuity of all present and future rights to this │
|
||||||
|
│ software under copyright law. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||||
|
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||||
|
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||||
|
│ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR │
|
||||||
|
│ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
|
||||||
|
│ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR │
|
||||||
|
│ OTHER DEALINGS IN THE SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/irq/acpi.internal.h"
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
|
||||||
|
textstartup static void _AcpiDsdtInit(uintptr_t dsdt_phy) {
|
||||||
|
const AcpiTableDsdt *dsdt;
|
||||||
|
size_t length;
|
||||||
|
if (!dsdt_phy) {
|
||||||
|
KWARNF("FADT: no DSDT");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dsdt = _AcpiMapTable(dsdt_phy);
|
||||||
|
KINFOF("FADT: DSDT @ %p", dsdt);
|
||||||
|
length = dsdt->Header.Length;
|
||||||
|
if (length <= offsetof(AcpiTableDsdt, Aml)) {
|
||||||
|
KWARNF("DSDT: no AML?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* TODO: parse AML to discover hardware configuration */
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup void _AcpiFadtInit(void) {
|
||||||
|
if (IsMetal()) {
|
||||||
|
const AcpiTableFadt *fadt;
|
||||||
|
size_t length;
|
||||||
|
uint16_t flags;
|
||||||
|
uintptr_t dsdt_phy = 0;
|
||||||
|
if (!_AcpiSuccess(_AcpiGetTable("FACP", 0, (void **)&fadt))) {
|
||||||
|
KINFOF("no FADT found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
length = fadt->Header.Length;
|
||||||
|
KINFOF("FADT @ %p,+%#zx", fadt, length);
|
||||||
|
_Static_assert(offsetof(AcpiTableFadt, Dsdt) == 40);
|
||||||
|
_Static_assert(offsetof(AcpiTableFadt, BootFlags) == 109);
|
||||||
|
_Static_assert(offsetof(AcpiTableFadt, XDsdt) == 140);
|
||||||
|
if (length >= offsetof(AcpiTableFadt, BootFlags) + sizeof(fadt->BootFlags))
|
||||||
|
{
|
||||||
|
_AcpiBootFlags = flags = fadt->BootFlags;
|
||||||
|
KINFOF("FADT: boot flags %#x", (unsigned)flags);
|
||||||
|
}
|
||||||
|
if (length >= offsetof(AcpiTableFadt, XDsdt) + sizeof(fadt->XDsdt) &&
|
||||||
|
fadt->XDsdt) {
|
||||||
|
dsdt_phy = fadt->XDsdt;
|
||||||
|
} else if (length >= offsetof(AcpiTableFadt, Dsdt) + sizeof(fadt->Dsdt)) {
|
||||||
|
dsdt_phy = fadt->Dsdt;
|
||||||
|
}
|
||||||
|
_AcpiDsdtInit(dsdt_phy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __x86_64__ */
|
51
libc/irq/acpi-madt-init.S
Normal file
51
libc/irq/acpi-madt-init.S
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||||
|
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ This is free and unencumbered software released into the public domain. │
|
||||||
|
│ │
|
||||||
|
│ Anyone is free to copy, modify, publish, use, compile, sell, or │
|
||||||
|
│ distribute this software, either in source code form or as a compiled │
|
||||||
|
│ binary, for any purpose, commercial or non-commercial, and by any │
|
||||||
|
│ means. │
|
||||||
|
│ │
|
||||||
|
│ In jurisdictions that recognize copyright laws, the author or authors │
|
||||||
|
│ of this software dedicate any and all copyright interest in the │
|
||||||
|
│ software to the public domain. We make this dedication for the benefit │
|
||||||
|
│ of the public at large and to the detriment of our heirs and │
|
||||||
|
│ successors. We intend this dedication to be an overt act of │
|
||||||
|
│ relinquishment in perpetuity of all present and future rights to this │
|
||||||
|
│ software under copyright law. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||||
|
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||||
|
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||||
|
│ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR │
|
||||||
|
│ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
|
||||||
|
│ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR │
|
||||||
|
│ OTHER DEALINGS IN THE SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/irq/acpi.internal.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/runtime/pc.internal.h"
|
||||||
|
|
||||||
|
.init.start 311,_init_acpi_madt
|
||||||
|
push %rdi
|
||||||
|
push %rsi
|
||||||
|
call _AcpiMadtInit
|
||||||
|
pop %rsi
|
||||||
|
pop %rdi
|
||||||
|
.init.end 311,_init_acpi_madt
|
||||||
|
.data
|
||||||
|
_AcpiMadtFlags:
|
||||||
|
.long kAcpiMadtPcAtCompat
|
||||||
|
.endobj _AcpiMadtFlags,globl
|
||||||
|
.previous
|
||||||
|
.bss
|
||||||
|
_AcpiNumIoApics:
|
||||||
|
.skip 8
|
||||||
|
.endobj _AcpiNumIoApics,globl
|
||||||
|
_AcpiIoApics:
|
||||||
|
.skip 8
|
||||||
|
.endobj _AcpiIoApics,globl
|
||||||
|
.previous
|
81
libc/irq/acpi-madt.c
Normal file
81
libc/irq/acpi-madt.c
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ This is free and unencumbered software released into the public domain. │
|
||||||
|
│ │
|
||||||
|
│ Anyone is free to copy, modify, publish, use, compile, sell, or │
|
||||||
|
│ distribute this software, either in source code form or as a compiled │
|
||||||
|
│ binary, for any purpose, commercial or non-commercial, and by any │
|
||||||
|
│ means. │
|
||||||
|
│ │
|
||||||
|
│ In jurisdictions that recognize copyright laws, the author or authors │
|
||||||
|
│ of this software dedicate any and all copyright interest in the │
|
||||||
|
│ software to the public domain. We make this dedication for the benefit │
|
||||||
|
│ of the public at large and to the detriment of our heirs and │
|
||||||
|
│ successors. We intend this dedication to be an overt act of │
|
||||||
|
│ relinquishment in perpetuity of all present and future rights to this │
|
||||||
|
│ software under copyright law. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||||
|
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||||
|
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||||
|
│ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR │
|
||||||
|
│ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
|
||||||
|
│ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR │
|
||||||
|
│ OTHER DEALINGS IN THE SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/inttypes.h"
|
||||||
|
#include "libc/irq/acpi.internal.h"
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
|
||||||
|
textstartup void _AcpiMadtInit(void) {
|
||||||
|
if (IsMetal()) {
|
||||||
|
const AcpiTableMadt *madt;
|
||||||
|
size_t length, num_io_apics = 0;
|
||||||
|
const char *madt_end, *p;
|
||||||
|
const AcpiSubtableHeader *h;
|
||||||
|
const AcpiMadtIoApic **icp;
|
||||||
|
uint32_t flags;
|
||||||
|
if (!_AcpiSuccess(_AcpiGetTable("APIC", 0, (void **)&madt))) {
|
||||||
|
KINFOF("no MADT found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
length = madt->Header.Length;
|
||||||
|
if (length < sizeof(*madt)) {
|
||||||
|
KDIEF("MADT has short length %#zx", length);
|
||||||
|
}
|
||||||
|
_AcpiMadtFlags = flags = madt->Flags;
|
||||||
|
KINFOF("MADT @ %p, flags %#" PRIx32, madt, flags);
|
||||||
|
madt_end = (char *)madt + length;
|
||||||
|
p = madt->Subtable;
|
||||||
|
while (p != madt_end) {
|
||||||
|
h = (const AcpiSubtableHeader *)p;
|
||||||
|
switch (h->Type) {
|
||||||
|
case kAcpiMadtIoApic:
|
||||||
|
++num_io_apics;
|
||||||
|
}
|
||||||
|
p += h->Length;
|
||||||
|
}
|
||||||
|
KINFOF("MADT: %zu I/O APIC(s)", num_io_apics);
|
||||||
|
icp = _AcpiOsAllocate(num_io_apics * sizeof(const AcpiMadtIoApic *));
|
||||||
|
if (icp) {
|
||||||
|
_AcpiIoApics = icp;
|
||||||
|
p = madt->Subtable;
|
||||||
|
while (p != madt_end) {
|
||||||
|
h = (const AcpiSubtableHeader *)p;
|
||||||
|
switch (h->Type) {
|
||||||
|
case kAcpiMadtIoApic:
|
||||||
|
*icp++ = (const AcpiMadtIoApic *)p;
|
||||||
|
}
|
||||||
|
p += h->Length;
|
||||||
|
}
|
||||||
|
_AcpiNumIoApics = num_io_apics;
|
||||||
|
} else {
|
||||||
|
KWARNF("MADT: no memory for I/O APICs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __x86_64__ */
|
46
libc/irq/acpi-xsdt-init.S
Normal file
46
libc/irq/acpi-xsdt-init.S
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||||
|
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ This is free and unencumbered software released into the public domain. │
|
||||||
|
│ │
|
||||||
|
│ Anyone is free to copy, modify, publish, use, compile, sell, or │
|
||||||
|
│ distribute this software, either in source code form or as a compiled │
|
||||||
|
│ binary, for any purpose, commercial or non-commercial, and by any │
|
||||||
|
│ means. │
|
||||||
|
│ │
|
||||||
|
│ In jurisdictions that recognize copyright laws, the author or authors │
|
||||||
|
│ of this software dedicate any and all copyright interest in the │
|
||||||
|
│ software to the public domain. We make this dedication for the benefit │
|
||||||
|
│ of the public at large and to the detriment of our heirs and │
|
||||||
|
│ successors. We intend this dedication to be an overt act of │
|
||||||
|
│ relinquishment in perpetuity of all present and future rights to this │
|
||||||
|
│ software under copyright law. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||||
|
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||||
|
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||||
|
│ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR │
|
||||||
|
│ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
|
||||||
|
│ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR │
|
||||||
|
│ OTHER DEALINGS IN THE SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/irq/acpi.internal.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/runtime/pc.internal.h"
|
||||||
|
|
||||||
|
.init.start 310,_init_acpi_xsdt
|
||||||
|
push %rdi
|
||||||
|
push %rsi
|
||||||
|
call _AcpiXsdtInit
|
||||||
|
pop %rsi
|
||||||
|
pop %rdi
|
||||||
|
.init.end 310,_init_acpi_xsdt
|
||||||
|
.bss
|
||||||
|
_AcpiXsdtNumEntries:
|
||||||
|
.skip 8
|
||||||
|
.endobj _AcpiXsdtNumEntries,globl
|
||||||
|
_AcpiXsdtEntries:
|
||||||
|
.skip 8
|
||||||
|
.endobj _AcpiXsdtEntries,globl
|
||||||
|
.previous
|
243
libc/irq/acpi-xsdt.c
Normal file
243
libc/irq/acpi-xsdt.c
Normal file
|
@ -0,0 +1,243 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ This is free and unencumbered software released into the public domain. │
|
||||||
|
│ │
|
||||||
|
│ Anyone is free to copy, modify, publish, use, compile, sell, or │
|
||||||
|
│ distribute this software, either in source code form or as a compiled │
|
||||||
|
│ binary, for any purpose, commercial or non-commercial, and by any │
|
||||||
|
│ means. │
|
||||||
|
│ │
|
||||||
|
│ In jurisdictions that recognize copyright laws, the author or authors │
|
||||||
|
│ of this software dedicate any and all copyright interest in the │
|
||||||
|
│ software to the public domain. We make this dedication for the benefit │
|
||||||
|
│ of the public at large and to the detriment of our heirs and │
|
||||||
|
│ successors. We intend this dedication to be an overt act of │
|
||||||
|
│ relinquishment in perpetuity of all present and future rights to this │
|
||||||
|
│ software under copyright law. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||||
|
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||||
|
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||||
|
│ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR │
|
||||||
|
│ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
|
||||||
|
│ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR │
|
||||||
|
│ OTHER DEALINGS IN THE SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/intrin/atomic.h"
|
||||||
|
#include "libc/intrin/bits.h"
|
||||||
|
#include "libc/intrin/directmap.internal.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/irq/acpi.internal.h"
|
||||||
|
#include "libc/log/color.internal.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/nt/efi.h"
|
||||||
|
#include "libc/runtime/pc.internal.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/map.h"
|
||||||
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
|
||||||
|
textstartup static void *_AcpiOsMapRoMemory(uintptr_t phy, size_t n) {
|
||||||
|
__invert_and_perm_ref_memory_area(__get_mm(), __get_pml4t(), phy, n,
|
||||||
|
PAGE_XD);
|
||||||
|
return (void *)(BANE + phy);
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static void *_AcpiOsMapMemory(uintptr_t phy, size_t n) {
|
||||||
|
__invert_and_perm_ref_memory_area(__get_mm(), __get_pml4t(), phy, n,
|
||||||
|
PAGE_XD | PAGE_RW);
|
||||||
|
return (void *)(BANE + phy);
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup void *_AcpiOsMapUncachedMemory(uintptr_t phy, size_t n) {
|
||||||
|
__invert_and_perm_ref_memory_area(__get_mm(), __get_pml4t(), phy, n,
|
||||||
|
PAGE_XD | PAGE_PCD | PAGE_RW);
|
||||||
|
return (void *)(BANE + phy);
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static void *_AcpiOsAllocatePages(size_t n) {
|
||||||
|
struct DirectMap dm = sys_mmap_metal(NULL, n, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
void *addr = dm.addr;
|
||||||
|
if (addr == (void *)-1) addr = NULL;
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup void *_AcpiOsAllocate(size_t n) {
|
||||||
|
static _Atomic(char *) slack = NULL;
|
||||||
|
char *addr = NULL;
|
||||||
|
size_t align = __BIGGEST_ALIGNMENT__, use;
|
||||||
|
if (n >= 4096) return _AcpiOsAllocatePages(n);
|
||||||
|
n = ROUNDUP(n, align);
|
||||||
|
for (;;) {
|
||||||
|
addr = atomic_exchange(&slack, NULL);
|
||||||
|
if (!addr) {
|
||||||
|
addr = _AcpiOsAllocatePages(4096);
|
||||||
|
if (!addr) return NULL;
|
||||||
|
}
|
||||||
|
use = (uintptr_t)addr % 4096 + n;
|
||||||
|
if (use <= 4096) {
|
||||||
|
if (use < 4096) atomic_store(&slack, addr + n);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static uint8_t _AcpiTbChecksum(const uint8_t *p, size_t n) {
|
||||||
|
uint8_t c = 0;
|
||||||
|
while (n-- != 0) c += *p++;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static AcpiStatus _AcpiTbVerifyChecksum(const uint8_t *p,
|
||||||
|
size_t n) {
|
||||||
|
uint8_t sum = _AcpiTbChecksum(p, n);
|
||||||
|
if (!sum) return kAcpiOk;
|
||||||
|
KWARNF("bad ACPI table cksum %#x != 0 @ %p,+%#zx", (unsigned)sum, p, n);
|
||||||
|
return kAcpiExBadChecksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static AcpiStatus _AcpiRsdpVerifyChecksums(const uint8_t *p) {
|
||||||
|
const AcpiTableRsdp *q = (const AcpiTableRsdp *)p;
|
||||||
|
size_t length = offsetof(AcpiTableRsdp, Length);
|
||||||
|
AcpiStatus sta = _AcpiTbVerifyChecksum(p, length);
|
||||||
|
if (!_AcpiSuccess(sta)) return sta;
|
||||||
|
if (q->Revision <= 1) return kAcpiOk;
|
||||||
|
length = q->Length;
|
||||||
|
if (length < offsetof(AcpiTableRsdp, Reserved)) {
|
||||||
|
KWARNF("malformed ACPI 2+ RSDP, length %#zx < %#zx",
|
||||||
|
length, offsetof(AcpiTableRsdp, Reserved));
|
||||||
|
if (length < offsetof(AcpiTableRsdp, RsdtPhysicalAddress)
|
||||||
|
+ sizeof(q->RsdtPhysicalAddress)) {
|
||||||
|
return kAcpiExBadHeader;
|
||||||
|
}
|
||||||
|
return kAcpiOk;
|
||||||
|
}
|
||||||
|
return _AcpiTbVerifyChecksum(p, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static bool _AcpiTbIsValidRsdp(const uint8_t *p) {
|
||||||
|
const AcpiTableRsdp *q = (const AcpiTableRsdp *)p;
|
||||||
|
if (READ64LE(q->Signature) != READ64LE("RSD PTR ")) return false;
|
||||||
|
KINFOF("\"RSD PTR \" @ %p, ACPI rev %u", q, (unsigned)q->Revision);
|
||||||
|
if (!_AcpiSuccess(_AcpiRsdpVerifyChecksums(p))) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static const AcpiTableRsdp *_AcpiFindRsdp(void) {
|
||||||
|
const size_t PARA_SZ = 0x10;
|
||||||
|
size_t off;
|
||||||
|
struct mman *mm = __get_mm();
|
||||||
|
uint64_t rsdp_phy = mm->pc_acpi_rsdp;
|
||||||
|
uint16_t ebda_para;
|
||||||
|
const uint8_t *area;
|
||||||
|
if (rsdp_phy) return _AcpiOsMapRoMemory(rsdp_phy, sizeof(AcpiTableRsdp));
|
||||||
|
/*
|
||||||
|
* "OSPM finds the Root System Description Pointer (RSDP) structure by
|
||||||
|
* searching physical memory ranges on 16-byte boundaries for a valid
|
||||||
|
* Root System Description Pointer structure signature and checksum match
|
||||||
|
* as follows:
|
||||||
|
* * The first 1 KB of the Extended BIOS Data Area (EBDA). For EISA or
|
||||||
|
* MCA systems, the EBDA can be found in the two-byte location 40:0Eh
|
||||||
|
* on the BIOS data area.
|
||||||
|
* * The BIOS read-only memory space between 0E0000h and 0FFFFFh."
|
||||||
|
* — Advanced Configuration and Power Interface (ACPI) Specification,
|
||||||
|
* Release 6.5, §5.2.5.1
|
||||||
|
*/
|
||||||
|
ebda_para = *(const uint16_t *)(BANE + PC_BIOS_DATA_AREA + 0xE);
|
||||||
|
if (ebda_para) {
|
||||||
|
area = _AcpiOsMapMemory((uint32_t)ebda_para * PARA_SZ, 1024);
|
||||||
|
KINFOF("search EBDA @ %p for RSDP", area);
|
||||||
|
off = 1024;
|
||||||
|
while (off != 0) {
|
||||||
|
off -= PARA_SZ;
|
||||||
|
if (_AcpiTbIsValidRsdp(area + off)) {
|
||||||
|
return (const AcpiTableRsdp *)(area + off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
area = _AcpiOsMapMemory(0xE0000, 0xFFFFF + 1 - 0xE0000);
|
||||||
|
KINFOF("search ROM BIOS for RSDP");
|
||||||
|
off = ROUNDUP(0xFFFFF + 1 - 0xE0000, PARA_SZ);
|
||||||
|
while (off != 0) {
|
||||||
|
off -= PARA_SZ;
|
||||||
|
if (_AcpiTbIsValidRsdp(area + off)) {
|
||||||
|
return (const AcpiTableRsdp *)(area + off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup void *_AcpiMapTable(uintptr_t phy) {
|
||||||
|
void *p = _AcpiOsMapRoMemory(phy, sizeof(AcpiTableHeader));
|
||||||
|
AcpiTableHeader *hdr = p;
|
||||||
|
size_t length = hdr->Length;
|
||||||
|
if (length < sizeof(*hdr)) {
|
||||||
|
KDIEF("ACPI table @ %p has short length %#zx", p, length);
|
||||||
|
} else {
|
||||||
|
p = _AcpiOsMapRoMemory(phy, length);
|
||||||
|
}
|
||||||
|
_AcpiTbVerifyChecksum((const uint8_t *)p, length);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup void _AcpiXsdtInit(void) {
|
||||||
|
if (IsMetal()) {
|
||||||
|
size_t nents, i;
|
||||||
|
void **ents = NULL;
|
||||||
|
const AcpiTableRsdp *rsdp = _AcpiFindRsdp();
|
||||||
|
if (!rsdp) {
|
||||||
|
KINFOF("no RSDP found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
KINFOF("RSDP @ %p", rsdp);
|
||||||
|
if (rsdp->Revision <= 1 ||
|
||||||
|
rsdp->Length < offsetof(AcpiTableRsdp, Reserved) ||
|
||||||
|
!rsdp->XsdtPhysicalAddress) {
|
||||||
|
const AcpiTableRsdt *rsdt = _AcpiMapTable(rsdp->RsdtPhysicalAddress);
|
||||||
|
nents = (rsdt->Header.Length - sizeof(rsdt->Header)) / sizeof(uint32_t);
|
||||||
|
KINFOF("RSDT @ %p, %#zx entries", rsdt, nents);
|
||||||
|
ents = _AcpiOsAllocate(nents * sizeof(AcpiTableHeader *));
|
||||||
|
if (ents) {
|
||||||
|
for (i = 0; i < nents; ++i) {
|
||||||
|
ents[i] = _AcpiMapTable(rsdt->TableOffsetEntry[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const AcpiTableXsdt *xsdt = _AcpiMapTable(rsdp->XsdtPhysicalAddress);
|
||||||
|
nents = (xsdt->Header.Length - sizeof(xsdt->Header)) / sizeof(uint64_t);
|
||||||
|
KINFOF("XSDT @ %p, %#zx entries", xsdt, nents);
|
||||||
|
ents = _AcpiOsAllocate(nents * sizeof(AcpiTableHeader *));
|
||||||
|
if (ents) {
|
||||||
|
for (i = 0; i < nents; ++i) {
|
||||||
|
ents[i] = _AcpiMapTable(xsdt->TableOffsetEntry[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ents) {
|
||||||
|
KWARNF("no memory for mapped RSDT/XSDT entries");
|
||||||
|
nents = 0;
|
||||||
|
}
|
||||||
|
_AcpiXsdtEntries = ents;
|
||||||
|
_AcpiXsdtNumEntries = nents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup AcpiStatus _AcpiGetTableImpl(uint32_t sig, uint32_t inst,
|
||||||
|
void **phdr) {
|
||||||
|
void **p = _AcpiXsdtEntries;
|
||||||
|
size_t n = _AcpiXsdtNumEntries;
|
||||||
|
while (n-- != 0) {
|
||||||
|
AcpiTableHeader *h = *p++;
|
||||||
|
if (READ32LE(h->Signature) != sig) continue;
|
||||||
|
if (inst-- != 0) continue;
|
||||||
|
*phdr = h;
|
||||||
|
return kAcpiOk;
|
||||||
|
}
|
||||||
|
return kAcpiExNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __x86_64__ */
|
232
libc/irq/acpi.internal.h
Normal file
232
libc/irq/acpi.internal.h
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_IRQ_ACPI_INTERNAL_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_IRQ_ACPI_INTERNAL_H_
|
||||||
|
#include "libc/intrin/bits.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/log/color.internal.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AcpiStatus values.
|
||||||
|
*/
|
||||||
|
#define kAcpiOk 0x0000
|
||||||
|
#define kAcpiExNotFound 0x0005
|
||||||
|
#define kAcpiExBadHeader 0x2002
|
||||||
|
#define kAcpiExBadChecksum 0x2003
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags for AcpiTableMadt::Flags.
|
||||||
|
*/
|
||||||
|
#define kAcpiMadtPcAtCompat 0x0001
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags for AcpiTableFadt::BootFlags.
|
||||||
|
*/
|
||||||
|
#define kAcpiFadtLegacyDevices 0x0001
|
||||||
|
#define kAcpiFadt8042 0x0002
|
||||||
|
#define kAcpiFadtNoVga 0x0004
|
||||||
|
#define kAcpiFadtNoMsi 0x0008
|
||||||
|
#define kAcpiFadtNoAspm 0x0010
|
||||||
|
#define kAcpiFadtNoCmosRtc 0x0020
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Values for AcpiSubtableHeader::Type under an AcpiTableMadt.
|
||||||
|
*/
|
||||||
|
#define kAcpiMadtLocalApic 0
|
||||||
|
#define kAcpiMadtIoApic 1
|
||||||
|
#define kAcpiMadtIntOverride 2
|
||||||
|
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fileoverview Declarations for bare metal code to interact with ACPI
|
||||||
|
*
|
||||||
|
* @see UEFI Forum, Inc. Advanced Configuration and Power Interface (ACPI)
|
||||||
|
* Specification, Version 6.5, 2022. https://uefi.org/specifications
|
||||||
|
* @see Intel Corporation. ACPI Component Architecture: User Guide and
|
||||||
|
* Programmer Reference, Revision 6.2, 2017. https://acpica.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* Structure of an ACPI Root System Description Pointer (RSDP) table. This
|
||||||
|
* points to either an RSDT, or an XSDT, or both.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t Signature[8];
|
||||||
|
uint8_t Checksum;
|
||||||
|
uint8_t OemId[6];
|
||||||
|
uint8_t Revision;
|
||||||
|
uint32_t RsdtPhysicalAddress;
|
||||||
|
uint32_t Length;
|
||||||
|
uint64_t XsdtPhysicalAddress;
|
||||||
|
uint8_t ExtendedChecksum;
|
||||||
|
uint8_t Reserved[3];
|
||||||
|
} AcpiTableRsdp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* Structure of a System Description Table Header, which appears at the
|
||||||
|
* beginning of each ACPI system description table.
|
||||||
|
*/
|
||||||
|
typedef struct thatispacked {
|
||||||
|
uint8_t Signature[4];
|
||||||
|
uint32_t Length;
|
||||||
|
uint8_t Revision;
|
||||||
|
uint8_t Checksum;
|
||||||
|
uint8_t OemId[6];
|
||||||
|
uint8_t OemTableId[8];
|
||||||
|
uint32_t OemRevision;
|
||||||
|
uint8_t AslCompilerId[4];
|
||||||
|
uint32_t AslCompilerRevision;
|
||||||
|
} AcpiTableHeader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* ACPI Root System Description Table (RSDT) structure.
|
||||||
|
*/
|
||||||
|
typedef struct thatispacked {
|
||||||
|
AcpiTableHeader Header;
|
||||||
|
uint32_t TableOffsetEntry[];
|
||||||
|
} AcpiTableRsdt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* ACPI Extended System Description Table (XSDT) structure.
|
||||||
|
*/
|
||||||
|
typedef struct thatispacked {
|
||||||
|
AcpiTableHeader Header;
|
||||||
|
uint64_t TableOffsetEntry[];
|
||||||
|
} AcpiTableXsdt;
|
||||||
|
|
||||||
|
typedef struct thatispacked {
|
||||||
|
uint8_t SpaceId;
|
||||||
|
uint8_t BitWidth;
|
||||||
|
uint8_t BitOffset;
|
||||||
|
uint8_t AccessWidth;
|
||||||
|
uint64_t Address;
|
||||||
|
} AcpiGenericAddress;
|
||||||
|
|
||||||
|
typedef struct thatispacked {
|
||||||
|
uint8_t Type;
|
||||||
|
uint8_t Length;
|
||||||
|
} AcpiSubtableHeader;
|
||||||
|
|
||||||
|
typedef struct thatispacked {
|
||||||
|
AcpiSubtableHeader Header;
|
||||||
|
uint8_t Id;
|
||||||
|
uint8_t Reserved;
|
||||||
|
uint32_t Address;
|
||||||
|
uint32_t GlobalIrqBase;
|
||||||
|
} AcpiMadtIoApic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* ACPI Multiple APIC Description Table (MADT) structure.
|
||||||
|
*/
|
||||||
|
typedef struct thatispacked {
|
||||||
|
AcpiTableHeader Header;
|
||||||
|
uint32_t Address; /* local APIC address */
|
||||||
|
uint32_t Flags; /* multiple APIC flags */
|
||||||
|
char Subtable[]; /* ...interrupt controller structures... */
|
||||||
|
} AcpiTableMadt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* Fixed ACPI Description Table (FADT) structure.
|
||||||
|
*/
|
||||||
|
typedef struct thatispacked {
|
||||||
|
AcpiTableHeader Header;
|
||||||
|
uint32_t Facs;
|
||||||
|
uint32_t Dsdt;
|
||||||
|
uint8_t Model;
|
||||||
|
uint8_t PreferredProfile;
|
||||||
|
uint16_t SciInterrupt;
|
||||||
|
uint32_t SmiCommand;
|
||||||
|
uint8_t AcpiEnable;
|
||||||
|
uint8_t AcpiDisable;
|
||||||
|
uint8_t S4BiosRequest;
|
||||||
|
uint8_t PstateControl;
|
||||||
|
uint32_t Pm1aEventBlock;
|
||||||
|
uint32_t Pm1bEventBlock;
|
||||||
|
uint32_t Pm1aControlBlock;
|
||||||
|
uint32_t Pm1bControlBlock;
|
||||||
|
uint32_t Pm2ControlBlock;
|
||||||
|
uint32_t PmTimerBlock;
|
||||||
|
uint32_t Gpe0Block;
|
||||||
|
uint32_t Gpe1Block;
|
||||||
|
uint8_t Pm1EventLength;
|
||||||
|
uint8_t Pm1ControlLength;
|
||||||
|
uint8_t Pm2ControlLength;
|
||||||
|
uint8_t PmTimerLength;
|
||||||
|
uint8_t Gpe0BlockLength;
|
||||||
|
uint8_t Gpe1BlockLength;
|
||||||
|
uint8_t Gpe1Base;
|
||||||
|
uint8_t CstControl;
|
||||||
|
uint16_t C2Latency;
|
||||||
|
uint16_t C3Latency;
|
||||||
|
uint16_t FlushSize;
|
||||||
|
uint16_t FlushStride;
|
||||||
|
uint8_t DutyOffset;
|
||||||
|
uint8_t DutyWidth;
|
||||||
|
uint8_t DayAlarm;
|
||||||
|
uint8_t MonthAlarm;
|
||||||
|
uint8_t Century;
|
||||||
|
uint16_t BootFlags;
|
||||||
|
uint8_t Reserved;
|
||||||
|
uint32_t Flags;
|
||||||
|
AcpiGenericAddress ResetRegister;
|
||||||
|
uint8_t ResetValue;
|
||||||
|
uint16_t ArmBootFlags;
|
||||||
|
uint8_t MinorRevision;
|
||||||
|
uint64_t XFacs;
|
||||||
|
uint64_t XDsdt;
|
||||||
|
AcpiGenericAddress XPm1aEventBlock;
|
||||||
|
AcpiGenericAddress XPm1bEventBlock;
|
||||||
|
AcpiGenericAddress XPm1aControlBlock;
|
||||||
|
AcpiGenericAddress XPm1bControlBlock;
|
||||||
|
AcpiGenericAddress XPm2ControlBlock;
|
||||||
|
AcpiGenericAddress XPmTimerBlock;
|
||||||
|
AcpiGenericAddress XGpe0Block;
|
||||||
|
AcpiGenericAddress XGpe1Block;
|
||||||
|
AcpiGenericAddress SleepControl;
|
||||||
|
AcpiGenericAddress SleepStatus;
|
||||||
|
uint64_t HypervisorId;
|
||||||
|
} AcpiTableFadt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* ACPI Differentiated System Description Table (DSDT) structure.
|
||||||
|
*/
|
||||||
|
typedef struct thatispacked {
|
||||||
|
AcpiTableHeader Header;
|
||||||
|
uint8_t Aml[];
|
||||||
|
} AcpiTableDsdt;
|
||||||
|
|
||||||
|
typedef uint32_t AcpiStatus;
|
||||||
|
|
||||||
|
extern size_t _AcpiXsdtNumEntries, _AcpiNumIoApics;
|
||||||
|
extern void **_AcpiXsdtEntries;
|
||||||
|
extern uint16_t _AcpiBootFlags;
|
||||||
|
extern uint32_t _AcpiMadtFlags;
|
||||||
|
extern const AcpiMadtIoApic **_AcpiIoApics;
|
||||||
|
|
||||||
|
extern void *_AcpiOsMapUncachedMemory(uintptr_t, size_t);
|
||||||
|
extern void *_AcpiOsAllocate(size_t);
|
||||||
|
extern void *_AcpiMapTable(uintptr_t);
|
||||||
|
|
||||||
|
extern AcpiStatus _AcpiGetTableImpl(uint32_t, uint32_t, void **);
|
||||||
|
|
||||||
|
forceinline bool _AcpiSuccess(AcpiStatus __sta) {
|
||||||
|
return __sta == kAcpiOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline AcpiStatus _AcpiGetTable(const char __sig[4], uint32_t __inst,
|
||||||
|
void **__phdr) {
|
||||||
|
uint8_t __sig_copy[4] = { __sig[0], __sig[1], __sig[2], __sig[3] };
|
||||||
|
return _AcpiGetTableImpl(READ32LE(__sig_copy), __inst, __phdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_IRQ_ACPI_INTERNAL_H_ */
|
57
libc/irq/irq.mk
Normal file
57
libc/irq/irq.mk
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||||
|
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||||
|
|
||||||
|
PKGS += LIBC_IRQ
|
||||||
|
|
||||||
|
LIBC_IRQ_ARTIFACTS += LIBC_IRQ_A
|
||||||
|
LIBC_IRQ_A = o/$(MODE)/libc/irq/irq.a
|
||||||
|
LIBC_IRQ_A_FILES := $(wildcard libc/irq/*)
|
||||||
|
LIBC_IRQ_A_HDRS = $(filter %.h,$(LIBC_IRQ_A_FILES))
|
||||||
|
LIBC_IRQ_A_INCS = $(filter %.inc,$(LIBC_IRQ_A_FILES))
|
||||||
|
LIBC_IRQ_A_SRCS_S = $(filter %.S,$(LIBC_IRQ_A_FILES))
|
||||||
|
LIBC_IRQ_A_SRCS_C = $(filter %.c,$(LIBC_IRQ_A_FILES))
|
||||||
|
|
||||||
|
LIBC_IRQ = \
|
||||||
|
$(LIBC_IRQ_A_DEPS) \
|
||||||
|
$(LIBC_IRQ_A)
|
||||||
|
|
||||||
|
LIBC_IRQ_A_SRCS = \
|
||||||
|
$(LIBC_IRQ_A_SRCS_S) \
|
||||||
|
$(LIBC_IRQ_A_SRCS_C)
|
||||||
|
|
||||||
|
LIBC_IRQ_A_OBJS = \
|
||||||
|
$(LIBC_IRQ_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||||
|
$(LIBC_IRQ_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||||
|
|
||||||
|
LIBC_IRQ_A_CHECKS = \
|
||||||
|
$(LIBC_IRQ_A).pkg \
|
||||||
|
$(LIBC_IRQ_A_HDRS:%=o/$(MODE)/%.ok)
|
||||||
|
|
||||||
|
LIBC_IRQ_A_DIRECTDEPS = \
|
||||||
|
LIBC_INTRIN \
|
||||||
|
LIBC_STR \
|
||||||
|
LIBC_SYSV
|
||||||
|
|
||||||
|
LIBC_IRQ_A_DEPS := \
|
||||||
|
$(call uniq,$(foreach x,$(LIBC_IRQ_A_DIRECTDEPS),$($(x))))
|
||||||
|
|
||||||
|
$(LIBC_IRQ_A):libc/irq/ \
|
||||||
|
$(LIBC_IRQ_A).pkg \
|
||||||
|
$(LIBC_IRQ_A_OBJS)
|
||||||
|
|
||||||
|
$(LIBC_IRQ_A).pkg: \
|
||||||
|
$(LIBC_IRQ_A_OBJS) \
|
||||||
|
$(foreach x,$(LIBC_IRQ_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||||
|
|
||||||
|
LIBC_IRQ_LIBS = $(foreach x,$(LIBC_IRQ_ARTIFACTS),$($(x)))
|
||||||
|
LIBC_IRQ_SRCS = $(foreach x,$(LIBC_IRQ_ARTIFACTS),$($(x)_SRCS))
|
||||||
|
LIBC_IRQ_HDRS = $(foreach x,$(LIBC_IRQ_ARTIFACTS),$($(x)_HDRS))
|
||||||
|
LIBC_IRQ_INCS = $(foreach x,$(LIBC_IRQ_ARTIFACTS),$($(x)_INCS))
|
||||||
|
LIBC_IRQ_BINS = $(foreach x,$(LIBC_IRQ_ARTIFACTS),$($(x)_BINS))
|
||||||
|
LIBC_IRQ_CHECKS = $(foreach x,$(LIBC_IRQ_ARTIFACTS),$($(x)_CHECKS))
|
||||||
|
LIBC_IRQ_OBJS = $(foreach x,$(LIBC_IRQ_ARTIFACTS),$($(x)_OBJS))
|
||||||
|
LIBC_IRQ_TESTS = $(foreach x,$(LIBC_IRQ_ARTIFACTS),$($(x)_TESTS))
|
||||||
|
$(LIBC_IRQ_OBJS): $(BUILD_FILES) libc/irq/irq.mk
|
||||||
|
|
||||||
|
.PHONY: o/$(MODE)/libc/irq
|
||||||
|
o/$(MODE)/libc/irq: $(LIBC_IRQ_CHECKS)
|
|
@ -20,6 +20,7 @@ o/$(MODE)/libc: o/$(MODE)/libc/calls \
|
||||||
o/$(MODE)/libc/elf \
|
o/$(MODE)/libc/elf \
|
||||||
o/$(MODE)/libc/fmt \
|
o/$(MODE)/libc/fmt \
|
||||||
o/$(MODE)/libc/intrin \
|
o/$(MODE)/libc/intrin \
|
||||||
|
o/$(MODE)/libc/irq \
|
||||||
o/$(MODE)/libc/log \
|
o/$(MODE)/libc/log \
|
||||||
o/$(MODE)/libc/mem \
|
o/$(MODE)/libc/mem \
|
||||||
o/$(MODE)/libc/nexgen32e \
|
o/$(MODE)/libc/nexgen32e \
|
||||||
|
|
|
@ -103,6 +103,18 @@
|
||||||
0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A \
|
0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
#define ACPI_20_TABLE_GUID \
|
||||||
|
{ \
|
||||||
|
0x8868E871, 0xE4F1, 0x11D3, { \
|
||||||
|
0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#define ACPI_10_TABLE_GUID \
|
||||||
|
{ \
|
||||||
|
0xEB9D2D30, 0x2D88, 0x11D3, { \
|
||||||
|
0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
|
@ -43,6 +43,8 @@ struct EfiArgs {
|
||||||
|
|
||||||
static EFI_GUID kEfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
|
static EFI_GUID kEfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
|
||||||
static EFI_GUID kEfiGraphicsOutputProtocol = GRAPHICS_OUTPUT_PROTOCOL;
|
static EFI_GUID kEfiGraphicsOutputProtocol = GRAPHICS_OUTPUT_PROTOCOL;
|
||||||
|
static const EFI_GUID kEfiAcpi20TableGuid = ACPI_20_TABLE_GUID;
|
||||||
|
static const EFI_GUID kEfiAcpi10TableGuid = ACPI_10_TABLE_GUID;
|
||||||
|
|
||||||
extern const char vga_console[];
|
extern const char vga_console[];
|
||||||
extern void _EfiPostboot(struct mman *, uint64_t *, uintptr_t, char **);
|
extern void _EfiPostboot(struct mman *, uint64_t *, uintptr_t, char **);
|
||||||
|
@ -117,6 +119,25 @@ static void EfiInitVga(struct mman *mm, EFI_SYSTEM_TABLE *SystemTable) {
|
||||||
GraphMode->FrameBufferSize, 0);
|
GraphMode->FrameBufferSize, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void EfiInitAcpi(struct mman *mm, EFI_SYSTEM_TABLE *SystemTable) {
|
||||||
|
void *rsdp1 = NULL, *rsdp2 = NULL;
|
||||||
|
uintptr_t n = SystemTable->NumberOfTableEntries, i;
|
||||||
|
EFI_CONFIGURATION_TABLE *tab;
|
||||||
|
for (i = 0, tab = SystemTable->ConfigurationTable; i < n; ++i, ++tab) {
|
||||||
|
EFI_GUID *guid = &tab->VendorGuid;
|
||||||
|
if (memcmp(guid, &kEfiAcpi20TableGuid, sizeof(EFI_GUID)) == 0) {
|
||||||
|
rsdp2 = tab->VendorTable;
|
||||||
|
} else if (memcmp(guid, &kEfiAcpi20TableGuid, sizeof(EFI_GUID)) == 0) {
|
||||||
|
rsdp1 = tab->VendorTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rsdp2) {
|
||||||
|
mm->pc_acpi_rsdp = (uintptr_t)rsdp2;
|
||||||
|
} else {
|
||||||
|
mm->pc_acpi_rsdp = (uintptr_t)rsdp1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EFI Application Entrypoint.
|
* EFI Application Entrypoint.
|
||||||
*
|
*
|
||||||
|
@ -203,6 +224,11 @@ __msabi EFI_STATUS EfiMain(EFI_HANDLE ImageHandle,
|
||||||
*/
|
*/
|
||||||
if (_weaken(vga_console)) EfiInitVga(mm, SystemTable);
|
if (_weaken(vga_console)) EfiInitVga(mm, SystemTable);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets a pointer to the ACPI RSDP.
|
||||||
|
*/
|
||||||
|
EfiInitAcpi(mm, SystemTable);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Asks UEFI which parts of our RAM we're allowed to use.
|
* Asks UEFI which parts of our RAM we're allowed to use.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -39,9 +39,12 @@ struct mman {
|
||||||
struct { /* 0x1d48 — starting cursor pos. */
|
struct { /* 0x1d48 — starting cursor pos. */
|
||||||
unsigned short y, x;
|
unsigned short y, x;
|
||||||
} pc_video_curs_info;
|
} pc_video_curs_info;
|
||||||
unsigned short pc_video_char_height; /* 0x1d4c — character height (useful
|
unsigned short pc_video_char_height; /* 0x1d4c — character height (useful
|
||||||
for setting cursor shape
|
for setting cursor shape
|
||||||
in text mode) */
|
in text mode) */
|
||||||
|
uint64_t pc_acpi_rsdp; /* 0x1d50 — pointer to ACPI RSDP;
|
||||||
|
NULL means to search for
|
||||||
|
it in legacy BIOS areas */
|
||||||
};
|
};
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
|
@ -91,12 +91,12 @@
|
||||||
vga_console:
|
vga_console:
|
||||||
.endobj vga_console,globl,hidden
|
.endobj vga_console,globl,hidden
|
||||||
.previous
|
.previous
|
||||||
.init.start 305,_init_vga
|
.init.start 101,_init_vga
|
||||||
push %rdi
|
push %rdi
|
||||||
push %rsi
|
push %rsi
|
||||||
call _vga_init
|
call _vga_init
|
||||||
pop %rsi
|
pop %rsi
|
||||||
pop %rdi
|
pop %rdi
|
||||||
.init.end 305,_init_vga
|
.init.end 101,_init_vga
|
||||||
.yoink sys_writev_vga
|
.yoink sys_writev_vga
|
||||||
.yoink sys_readv_vga
|
.yoink sys_readv_vga
|
||||||
|
|
|
@ -33,8 +33,8 @@
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @fileoverview Instantiation of routines for emergency or system console
|
* @fileoverview Instantiation of routines for emergency console output in
|
||||||
* output in graphical video modes.
|
* graphical video modes.
|
||||||
*
|
*
|
||||||
* @see libc/vga/tty-graph.inc
|
* @see libc/vga/tty-graph.inc
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -25,7 +25,10 @@
|
||||||
│ OTHER DEALINGS IN THE SOFTWARE. │
|
│ OTHER DEALINGS IN THE SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/runtime/pc.internal.h"
|
#include "libc/runtime/pc.internal.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/runtime/stack.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/vga/vga.internal.h"
|
#include "libc/vga/vga.internal.h"
|
||||||
|
|
||||||
|
@ -72,4 +75,47 @@ textstartup void _vga_init(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !IsTiny()
|
||||||
|
/**
|
||||||
|
* Non-emergency console vprintf(), useful for dumping debugging or
|
||||||
|
* informational messages at program startup.
|
||||||
|
*
|
||||||
|
* @see uprintf()
|
||||||
|
*/
|
||||||
|
void uvprintf(const char *fmt, va_list v) {
|
||||||
|
if (!IsMetal()) {
|
||||||
|
kvprintf(fmt, v);
|
||||||
|
} else {
|
||||||
|
long size = __get_safe_size(8000, 3000);
|
||||||
|
char *buf = alloca(size);
|
||||||
|
CheckLargeStackAllocation(buf, size);
|
||||||
|
size_t count = kvsnprintf(buf, size, fmt, v);
|
||||||
|
if (count >= size) count = size - 1;
|
||||||
|
_TtyWrite(&_vga_tty, buf, count);
|
||||||
|
_klog_serial(buf, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-emergency console printf(), useful for dumping debugging or
|
||||||
|
* informational messages at program startup.
|
||||||
|
*
|
||||||
|
* uprintf() is similar to kprintf(), but on bare metal with VGA support, it
|
||||||
|
* uses the normal, fast graphical console, rather than initializing an
|
||||||
|
* emergency console. This makes uprintf() faster — on bare metal — at the
|
||||||
|
* expense of being less crash-proof.
|
||||||
|
*
|
||||||
|
* (The uprintf() function name comes from the FreeBSD kernel.)
|
||||||
|
*
|
||||||
|
* @see kprintf()
|
||||||
|
* @see https://man.freebsd.org/cgi/man.cgi?query=uprintf&sektion=9&n=1
|
||||||
|
*/
|
||||||
|
void uprintf(const char *fmt, ...) {
|
||||||
|
va_list v;
|
||||||
|
va_start(v, fmt);
|
||||||
|
uvprintf(fmt, v);
|
||||||
|
va_end(v);
|
||||||
|
}
|
||||||
|
#endif /* !IsTiny() */
|
||||||
|
|
||||||
#endif /* __x86_64__ */
|
#endif /* __x86_64__ */
|
||||||
|
|
|
@ -255,8 +255,7 @@ void _TtyGraphMoveLineCells(struct Tty *, size_t, size_t, size_t, size_t,
|
||||||
size_t);
|
size_t);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Routines that implement emergency or system console output in graphical
|
* Routines that implement emergency console output in graphical video modes.
|
||||||
* video modes.
|
|
||||||
*/
|
*/
|
||||||
void _TtyKlog16Update(struct Tty *);
|
void _TtyKlog16Update(struct Tty *);
|
||||||
void _TtyKlog16DrawChar(struct Tty *, size_t, size_t, wchar_t);
|
void _TtyKlog16DrawChar(struct Tty *, size_t, size_t, wchar_t);
|
||||||
|
|
Loading…
Reference in a new issue