Kernel: Add LAI as a dependency

I did not feel like implementing AML interpreter now, and wanted
everything AML has to offer. I will be writing my own AML interperter
at some point.
This commit is contained in:
Bananymous
2023-09-18 21:48:37 +03:00
parent 8136248a67
commit c9e09b840e
8 changed files with 258 additions and 46 deletions

View File

@@ -3,6 +3,8 @@
#include <kernel/ACPI.h>
#include <kernel/Memory/PageTable.h>
#include <lai/core.h>
#define RSPD_SIZE 20
#define RSPDv2_SIZE 36
@@ -43,6 +45,7 @@ namespace Kernel
if (s_instance == nullptr)
return BAN::Error::from_errno(ENOMEM);
TRY(s_instance->initialize_impl());
lai_create_namespace();
return {};
}
@@ -101,6 +104,9 @@ namespace Kernel
const RSDP* rsdp = locate_rsdp();
if (rsdp == nullptr)
return BAN::Error::from_error_code(ErrorCode::ACPI_NoRootSDT);
lai_set_acpi_revision(rsdp->revision);
uint32_t root_entry_count = 0;
if (rsdp->revision >= 2)
{
@@ -115,7 +121,7 @@ namespace Kernel
m_header_table_paddr = (paddr_t)xsdt->entries + (rsdp->rsdt_address & PAGE_ADDR_MASK);
m_entry_size = 8;
m_entry_count = (xsdt->length - sizeof(SDTHeader)) / 8;
root_entry_count = (xsdt->length - sizeof(SDTHeader)) / 8;
}
else
{
@@ -130,10 +136,10 @@ namespace Kernel
m_header_table_paddr = (paddr_t)rsdt->entries + (rsdp->rsdt_address & PAGE_ADDR_MASK);
m_entry_size = 4;
m_entry_count = (rsdt->length - sizeof(SDTHeader)) / 4;
root_entry_count = (rsdt->length - sizeof(SDTHeader)) / 4;
}
size_t needed_pages = range_page_count(m_header_table_paddr, m_entry_count * m_entry_size);
size_t needed_pages = range_page_count(m_header_table_paddr, root_entry_count * m_entry_size);
m_header_table_vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
ASSERT(m_header_table_vaddr);
@@ -146,61 +152,85 @@ namespace Kernel
PageTable::Flags::Present
);
for (uint32_t i = 0; i < m_entry_count; i++)
auto map_header =
[](paddr_t header_paddr) -> vaddr_t
{
PageTable::kernel().map_page_at(header_paddr & PAGE_ADDR_MASK, 0, PageTable::Flags::Present);
size_t header_length = ((SDTHeader*)(header_paddr % PAGE_SIZE))->length;
PageTable::kernel().unmap_page(0);
size_t needed_pages = range_page_count(header_paddr, header_length);
vaddr_t page_vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
ASSERT(page_vaddr);
PageTable::kernel().map_range_at(
header_paddr & PAGE_ADDR_MASK,
page_vaddr,
needed_pages * PAGE_SIZE,
PageTable::Flags::Present
);
auto* header = (SDTHeader*)(page_vaddr + (header_paddr % PAGE_SIZE));
if (!is_valid_std_header(header))
{
PageTable::kernel().unmap_range(page_vaddr, needed_pages * PAGE_SIZE);
return 0;
}
return page_vaddr + (header_paddr % PAGE_SIZE);
};
for (uint32_t i = 0; i < root_entry_count; i++)
{
paddr_t header_paddr = (m_entry_size == 4) ?
((uint32_t*)m_header_table_vaddr)[i] :
((uint64_t*)m_header_table_vaddr)[i];
PageTable::kernel().map_page_at(header_paddr & PAGE_ADDR_MASK, 0, PageTable::Flags::Present);
size_t header_length = ((SDTHeader*)(header_paddr % PAGE_SIZE))->length;
PageTable::kernel().unmap_page(0);
size_t needed_pages = range_page_count(header_paddr, header_length);
vaddr_t page_vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
ASSERT(page_vaddr);
PageTable::kernel().map_range_at(
header_paddr & PAGE_ADDR_MASK,
page_vaddr,
needed_pages * PAGE_SIZE,
PageTable::Flags::Present
);
vaddr_t header_vaddr = map_header(header_paddr);
if (header_vaddr == 0)
continue;
MUST(m_mapped_headers.push_back({
.paddr = header_paddr,
.vaddr = page_vaddr + (header_paddr % PAGE_SIZE)
.vaddr = header_vaddr
}));
}
for (size_t i = 0; i < m_mapped_headers.size(); i++)
{
auto* header = m_mapped_headers[i].as_header();
dprintln("found header {}", *header);
if (memcmp(header->signature, "FACP", 4) == 0)
{
auto* fadt = (FADT*)header;
paddr_t dsdt_paddr = fadt->x_dsdt;
if (dsdt_paddr == 0 || !PageTable::is_valid_pointer(dsdt_paddr))
dsdt_paddr = fadt->dsdt;
vaddr_t dsdt_vaddr = map_header(dsdt_paddr);
if (dsdt_vaddr == 0)
continue;
MUST(m_mapped_headers.push_back({
.paddr = dsdt_paddr,
.vaddr = dsdt_vaddr
}));
}
}
return {};
}
const ACPI::SDTHeader* ACPI::get_header(const char signature[4])
{
for (uint32_t i = 0; i < m_entry_count; i++)
for (auto& mapped_header : m_mapped_headers)
{
const SDTHeader* header = get_header_from_index(i);
if (is_valid_std_header(header) && memcmp(header->signature, signature, 4) == 0)
auto* header = mapped_header.as_header();
if (memcmp(header->signature, signature, 4) == 0)
return header;
}
return nullptr;
}
const ACPI::SDTHeader* ACPI::get_header_from_index(size_t index)
{
ASSERT(index < m_entry_count);
ASSERT(m_entry_size == 4 || m_entry_size == 8);
paddr_t header_paddr = (m_entry_size == 4) ?
((uint32_t*)m_header_table_vaddr)[index] :
((uint64_t*)m_header_table_vaddr)[index];
for (const auto& page : m_mapped_headers)
if (page.paddr == header_paddr)
return (SDTHeader*)page.vaddr;
ASSERT_NOT_REACHED();
}
}

150
kernel/kernel/lai_host.cpp Normal file
View File

@@ -0,0 +1,150 @@
#include <kernel/ACPI.h>
#include <kernel/IO.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/PCI.h>
#include <kernel/Timer/Timer.h>
#include <lai/host.h>
using namespace Kernel;
void* laihost_malloc(size_t size)
{
return kmalloc(size);
}
void* laihost_realloc(void* ptr, size_t newsize, size_t oldsize)
{
if (ptr == nullptr)
return laihost_malloc(newsize);
void* new_ptr = laihost_malloc(newsize);
if (new_ptr == nullptr)
return nullptr;
memcpy(new_ptr, ptr, BAN::Math::min(newsize, oldsize));
kfree(ptr);
return new_ptr;
}
void laihost_free(void* ptr, size_t)
{
kfree(ptr);
}
void laihost_log(int level, const char* msg)
{
if (level == LAI_DEBUG_LOG)
dprintln(msg);
else if (level == LAI_WARN_LOG)
dwarnln(msg);
else
ASSERT_NOT_REACHED();
}
void laihost_panic(const char* msg)
{
Kernel::panic(msg);
}
void* laihost_scan(const char* sig, size_t index)
{
ASSERT(index == 0);
return (void*)ACPI::get().get_header(sig);
}
void* laihost_map(size_t address, size_t count)
{
size_t needed_pages = range_page_count(address, count);
vaddr_t vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
ASSERT(vaddr);
PageTable::kernel().map_range_at(address & PAGE_ADDR_MASK, vaddr, needed_pages * PAGE_SIZE, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
return (void*)(vaddr + (address % PAGE_SIZE));
}
void laihost_unmap(void* ptr, size_t count)
{
PageTable::kernel().unmap_range((vaddr_t)ptr, count);
}
void laihost_outb(uint16_t port, uint8_t val)
{
IO::outb(port, val);
}
void laihost_outw(uint16_t port, uint16_t val)
{
IO::outw(port, val);
}
void laihost_outd(uint16_t port, uint32_t val)
{
IO::outl(port, val);
}
uint8_t laihost_inb(uint16_t port)
{
return IO::inb(port);
}
uint16_t laihost_inw(uint16_t port)
{
return IO::inw(port);
}
uint32_t laihost_ind(uint16_t port)
{
return IO::inl(port);
}
void laihost_pci_writeb(uint16_t seg, uint8_t bus, uint8_t slot, uint8_t fun, uint16_t offset, uint8_t val)
{
ASSERT(seg == 0);
PCI::PCIManager::write_config_byte(bus, slot, fun, offset, val);
}
void laihost_pci_writew(uint16_t seg, uint8_t bus, uint8_t slot, uint8_t fun, uint16_t offset, uint16_t val)
{
ASSERT(seg == 0);
PCI::PCIManager::write_config_word(bus, slot, fun, offset, val);
}
void laihost_pci_writed(uint16_t seg, uint8_t bus, uint8_t slot, uint8_t fun, uint16_t offset, uint32_t val)
{
ASSERT(seg == 0);
PCI::PCIManager::write_config_dword(bus, slot, fun, offset, val);
}
uint8_t laihost_pci_readb(uint16_t seg, uint8_t bus, uint8_t slot, uint8_t fun, uint16_t offset)
{
ASSERT(seg == 0);
return PCI::PCIManager::read_config_byte(bus, slot, fun, offset);
}
uint16_t laihost_pci_readw(uint16_t seg, uint8_t bus, uint8_t slot, uint8_t fun, uint16_t offset)
{
ASSERT(seg == 0);
return PCI::PCIManager::read_config_word(bus, slot, fun, offset);
}
uint32_t laihost_pci_readd(uint16_t seg, uint8_t bus, uint8_t slot, uint8_t fun, uint16_t offset)
{
ASSERT(seg == 0);
return PCI::PCIManager::read_config_dword(bus, slot, fun, offset);
}
void laihost_sleep(uint64_t ms)
{
SystemTimer::get().sleep(ms);
}
uint64_t laihost_timer(void)
{
auto time = SystemTimer::get().time_since_boot();
return (1'000'000'000ull * time.tv_sec + time.tv_nsec) / 100;
}