Kernel: rework the whole PageTable structure

We now have page table structure for kernel memory which is shared
between all processes.
This commit is contained in:
Bananymous
2023-07-05 23:41:35 +03:00
parent 60fe5a656c
commit 4086d7c3be
13 changed files with 215 additions and 165 deletions

View File

@@ -6,6 +6,8 @@
#define RSPD_SIZE 20
#define RSPDv2_SIZE 36
extern uint8_t g_kernel_end[];
namespace Kernel
{
@@ -104,42 +106,73 @@ namespace Kernel
if (rsdp->revision >= 2)
{
const XSDT* xsdt = (const XSDT*)rsdp->xsdt_address;
PageTable::kernel().identity_map_page((uintptr_t)xsdt, PageTable::Flags::Present);
BAN::ScopeGuard _([xsdt] { PageTable::kernel().unmap_page((uintptr_t)xsdt); });
PageTable::kernel().map_page_at(rsdp->xsdt_address & PAGE_ADDR_MASK, 0, PageTable::Flags::Present);
const XSDT* xsdt = (const XSDT*)(rsdp->xsdt_address % PAGE_SIZE);
BAN::ScopeGuard _([xsdt] { PageTable::kernel().unmap_page(0); });
if (memcmp(xsdt->signature, "XSDT", 4) != 0)
return BAN::Error::from_error_code(ErrorCode::ACPI_RootInvalid);
if (!is_valid_std_header(xsdt))
return BAN::Error::from_error_code(ErrorCode::ACPI_RootInvalid);
m_header_table = (uintptr_t)xsdt->entries;
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;
}
else
{
const RSDT* rsdt = (const RSDT*)(uintptr_t)rsdp->rsdt_address;
PageTable::kernel().identity_map_page((vaddr_t)rsdt, PageTable::Flags::Present);
BAN::ScopeGuard _([rsdt] { PageTable::kernel().unmap_page((vaddr_t)rsdt); });
PageTable::kernel().map_page_at(rsdp->rsdt_address & PAGE_ADDR_MASK, 0, PageTable::Flags::Present);
const RSDT* rsdt = (const RSDT*)((vaddr_t)rsdp->rsdt_address % PAGE_SIZE);
BAN::ScopeGuard _([rsdt] { PageTable::kernel().unmap_page(0); });
if (memcmp(rsdt->signature, "RSDT", 4) != 0)
return BAN::Error::from_error_code(ErrorCode::ACPI_RootInvalid);
if (!is_valid_std_header(rsdt))
return BAN::Error::from_error_code(ErrorCode::ACPI_RootInvalid);
m_header_table = (uintptr_t)rsdt->entries;
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;
}
PageTable::kernel().identity_map_range(m_header_table, m_entry_count * m_entry_size, PageTable::Flags::Present);
size_t needed_pages = range_page_count(m_header_table_paddr, m_entry_count * m_entry_size);
m_header_table_vaddr = PageTable::kernel().get_free_contiguous_pages(needed_pages, (vaddr_t)g_kernel_end);
ASSERT(m_header_table_vaddr);
m_header_table_vaddr += m_header_table_paddr % PAGE_SIZE;
PageTable::kernel().map_range_at(
m_header_table_paddr & PAGE_ADDR_MASK,
m_header_table_vaddr & PAGE_ADDR_MASK,
needed_pages * PAGE_SIZE,
PageTable::Flags::Present
);
for (uint32_t i = 0; i < m_entry_count; i++)
{
auto* header = get_header_from_index(i);
PageTable::kernel().identity_map_page((uintptr_t)header, PageTable::Flags::Present);
PageTable::kernel().identity_map_range((uintptr_t)header, header->length, PageTable::Flags::Present);
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().get_free_contiguous_pages(needed_pages, (vaddr_t)g_kernel_end);
ASSERT(page_vaddr);
PageTable::kernel().map_range_at(
header_paddr & PAGE_ADDR_MASK,
page_vaddr,
needed_pages * PAGE_SIZE,
PageTable::Flags::Present
);
MUST(m_mapped_headers.push_back({
.paddr = header_paddr,
.vaddr = page_vaddr + (header_paddr % PAGE_SIZE)
}));
}
return {};
@@ -161,8 +194,15 @@ namespace Kernel
ASSERT(index < m_entry_count);
ASSERT(m_entry_size == 4 || m_entry_size == 8);
uintptr_t header_address = (m_entry_size == 4) ? ((uint32_t*)m_header_table)[index] : ((uint64_t*)m_header_table)[index];
return (SDTHeader*)header_address;
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();
}
}

View File

@@ -81,6 +81,8 @@ union RedirectionEntry
};
};
extern uint8_t g_kernel_end[];
using namespace Kernel;
APIC* APIC::create()
@@ -101,7 +103,7 @@ APIC* APIC::create()
}
APIC* apic = new APIC;
apic->m_local_apic = madt->local_apic;
apic->m_local_apic_paddr = madt->local_apic;
for (uint32_t i = 0x00; i <= 0xFF; i++)
apic->m_irq_overrides[i] = i;
@@ -121,7 +123,7 @@ APIC* APIC::create()
case 1:
IOAPIC ioapic;
ioapic.id = entry->entry1.ioapic_id;
ioapic.address = entry->entry1.ioapic_address;
ioapic.paddr = entry->entry1.ioapic_address;
ioapic.gsi_base = entry->entry1.gsi_base;
ioapic.max_redirs = 0;
MUST(apic->m_io_apics.push_back(ioapic));
@@ -130,7 +132,7 @@ APIC* APIC::create()
apic->m_irq_overrides[entry->entry2.irq_source] = entry->entry2.gsi;
break;
case 5:
apic->m_local_apic = entry->entry5.address;
apic->m_local_apic_paddr = entry->entry5.address;
break;
default:
dprintln("Unhandled madt entry, type {}", entry->type);
@@ -139,17 +141,40 @@ APIC* APIC::create()
madt_entry_addr += entry->length;
}
if (apic->m_local_apic == 0 || apic->m_io_apics.empty())
if (apic->m_local_apic_paddr == 0 || apic->m_io_apics.empty())
{
dprintln("MADT did not provide necessary information");
delete apic;
return nullptr;
}
PageTable::kernel().identity_map_page(apic->m_local_apic, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
// Map the local apic to kernel memory
{
vaddr_t vaddr = PageTable::kernel().get_free_page((vaddr_t)g_kernel_end);
ASSERT(vaddr);
dprintln("lapic paddr {8H}", apic->m_local_apic_paddr);
apic->m_local_apic_vaddr = vaddr + (apic->m_local_apic_paddr % PAGE_SIZE);
dprintln("lapic vaddr {8H}", apic->m_local_apic_vaddr);
PageTable::kernel().map_page_at(
apic->m_local_apic_paddr & PAGE_ADDR_MASK,
apic->m_local_apic_vaddr & PAGE_ADDR_MASK,
PageTable::Flags::ReadWrite | PageTable::Flags::Present
);
}
// Map io apics to kernel memory
for (auto& io_apic : apic->m_io_apics)
{
PageTable::kernel().identity_map_page(io_apic.address, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
vaddr_t vaddr = PageTable::kernel().get_free_page((vaddr_t)g_kernel_end);
ASSERT(vaddr);
io_apic.vaddr = vaddr + (io_apic.paddr % PAGE_SIZE);
PageTable::kernel().map_page_at(
io_apic.paddr & PAGE_ADDR_MASK,
io_apic.vaddr & PAGE_ADDR_MASK,
PageTable::Flags::ReadWrite | PageTable::Flags::Present
);
io_apic.max_redirs = io_apic.read(IOAPIC_MAX_REDIRS);
}
@@ -171,24 +196,24 @@ APIC* APIC::create()
uint32_t APIC::read_from_local_apic(ptrdiff_t offset)
{
return *(uint32_t*)(m_local_apic + offset);
return *(uint32_t*)(m_local_apic_vaddr + offset);
}
void APIC::write_to_local_apic(ptrdiff_t offset, uint32_t data)
{
*(uint32_t*)(m_local_apic + offset) = data;
*(uint32_t*)(m_local_apic_vaddr + offset) = data;
}
uint32_t APIC::IOAPIC::read(uint8_t offset)
{
volatile uint32_t* ioapic = (volatile uint32_t*)address;
volatile uint32_t* ioapic = (volatile uint32_t*)vaddr;
ioapic[0] = offset;
return ioapic[4];
}
void APIC::IOAPIC::write(uint8_t offset, uint32_t data)
{
volatile uint32_t* ioapic = (volatile uint32_t*)address;
volatile uint32_t* ioapic = (volatile uint32_t*)vaddr;
ioapic[0] = offset;
ioapic[4] = data;
}

View File

@@ -196,7 +196,6 @@ namespace Kernel
page_vaddr = m_page_table.get_free_page();
m_page_table.map_page_at(page_paddr, page_vaddr, PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present);
m_page_table.invalidate(page_vaddr);
}
bool FixedWidthAllocator::allocate_page_if_needed(vaddr_t vaddr, uint8_t flags)
@@ -251,7 +250,6 @@ namespace Kernel
{
paddr_t paddr = new_page_table.physical_address_of(page_begin);
m_page_table.map_page_at(paddr, 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
m_page_table.invalidate(0);
memcpy((void*)0, (void*)page_begin, PAGE_SIZE);
}
@@ -261,7 +259,6 @@ namespace Kernel
}
m_page_table.unmap_page(0);
m_page_table.invalidate(0);
m_page_table.unlock();

View File

@@ -109,14 +109,12 @@ namespace Kernel
new_page_table.map_page_at(paddr, vaddr, flags);
m_page_table.map_page_at(paddr, 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
m_page_table.invalidate(0);
memcpy((void*)0, (void*)vaddr, PAGE_SIZE);
}
MUST(allocator->m_allocations.push_back(BAN::move(new_allocation)));
}
m_page_table.unmap_page(0);
m_page_table.invalidate(0);
m_page_table.unlock();

View File

@@ -85,11 +85,9 @@ namespace Kernel
for (size_t i = 0; i < result->m_physical_pages.size(); i++)
{
m_page_table.map_page_at(result->m_physical_pages[i], 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
m_page_table.invalidate(0);
memcpy((void*)0, (void*)(vaddr() + i * PAGE_SIZE), PAGE_SIZE);
}
m_page_table.unmap_page(0);
m_page_table.invalidate(0);
m_page_table.unlock();
@@ -112,11 +110,9 @@ namespace Kernel
for (size_t i = 0; i < m_physical_pages.size(); i++)
{
page_table.map_page_at(m_physical_pages[i], 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
page_table.invalidate(0);
memset((void*)0, 0, PAGE_SIZE);
}
page_table.unmap_page(0);
page_table.invalidate(0);
page_table.unlock();
}
@@ -147,7 +143,6 @@ namespace Kernel
// NOTE: we map the first page separately since it needs extra calculations
page_table.map_page_at(m_physical_pages[i], 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
page_table.invalidate(0);
memcpy((void*)off, buffer, PAGE_SIZE - off);
@@ -160,7 +155,6 @@ namespace Kernel
size_t len = BAN::Math::min<size_t>(PAGE_SIZE, bytes);
page_table.map_page_at(m_physical_pages[i], 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
page_table.invalidate(0);
memcpy((void*)0, buffer, len);
@@ -169,7 +163,6 @@ namespace Kernel
i++;
}
page_table.unmap_page(0);
page_table.invalidate(0);
page_table.unlock();
}

View File

@@ -265,8 +265,6 @@ namespace Kernel
io_write(ATA_PORT_LBA2, (uint8_t)(lba >> 16));
io_write(ATA_PORT_COMMAND, ATA_COMMAND_READ_SECTORS);
PIT::sleep(1);
for (uint32_t sector = 0; sector < sector_count; sector++)
{
block_until_irq();

View File

@@ -178,7 +178,6 @@ namespace Kernel
ASSERT(page_table.is_page_free(0));
page_table.map_page_at(this->paddr, 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
page_table.invalidate(0);
for (size_t i = 0; i < PAGE_SIZE / device.sector_size(); i++)
{
@@ -188,7 +187,6 @@ namespace Kernel
}
page_table.unmap_page(0);
page_table.invalidate(0);
page_table.unlock();
@@ -210,7 +208,6 @@ namespace Kernel
ASSERT(page_table.is_page_free(0));
page_table.map_page_at(this->paddr, 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
page_table.invalidate(0);
// Sector not yet cached
if (!(this->sector_mask & (1 << sector_offset)))
@@ -222,7 +219,6 @@ namespace Kernel
memcpy(buffer, (const void*)(sector_offset * device.sector_size()), device.sector_size());
page_table.unmap_page(0);
page_table.invalidate(0);
page_table.unlock();
@@ -244,14 +240,12 @@ namespace Kernel
ASSERT(page_table.is_page_free(0));
page_table.map_page_at(this->paddr, 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
page_table.invalidate(0);
memcpy((void*)(sector_offset * device.sector_size()), buffer, device.sector_size());
this->sector_mask |= 1 << sector_offset;
this->dirty_mask |= 1 << sector_offset;
page_table.unmap_page(0);
page_table.invalidate(0);
page_table.unlock();

View File

@@ -6,6 +6,8 @@
using namespace Kernel;
extern uint8_t g_kernel_end[];
VesaTerminalDriver* VesaTerminalDriver::create()
{
if (!(g_multiboot_info->flags & MULTIBOOT_FLAGS_FRAMEBUFFER))
@@ -36,14 +38,21 @@ VesaTerminalDriver* VesaTerminalDriver::create()
return nullptr;
}
PageTable::kernel().identity_map_range(framebuffer.addr, framebuffer.pitch * framebuffer.height, PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present);
uint64_t first_page = framebuffer.addr / PAGE_SIZE;
uint64_t last_page = BAN::Math::div_round_up<uint64_t>(framebuffer.addr + framebuffer.pitch * framebuffer.height, PAGE_SIZE);
uint64_t needed_pages = last_page - first_page + 1;
vaddr_t vaddr = PageTable::kernel().get_free_contiguous_pages(needed_pages, (vaddr_t)g_kernel_end);
ASSERT(vaddr);
PageTable::kernel().map_range_at(framebuffer.addr, vaddr, needed_pages * PAGE_SIZE, PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present);
auto* driver = new VesaTerminalDriver(
framebuffer.width,
framebuffer.height,
framebuffer.pitch,
framebuffer.bpp,
framebuffer.addr
vaddr
);
driver->set_cursor_position(0, 0);
driver->clear(TerminalColor::BLACK);