Compare commits

..

10 Commits

Author SHA1 Message Date
chloe b34bfdbf63 sp1: vm: Fix ups
Signed-off-by: Ian Moffett <ian@mirocom.org>
2026-04-26 00:24:15 -04:00
chloe 336d6e2c52 sp1: vm: Add function to unmap vm regions
Signed-off-by: Ian Moffett <ian@mirocom.org>
2026-04-26 00:22:01 -04:00
chloe 9fb213cc41 sp1: vm: Remove redundant length assignment
Signed-off-by: Ian Moffett <ian@mirocom.org>
2026-04-26 00:21:40 -04:00
chloe bd354fed8c sp1/amd64: mmu: Add function to unmap regions
Signed-off-by: Ian Moffett <ian@mirocom.org>
2026-04-26 00:21:19 -04:00
chloe a7577d1921 sp1/amd64: io: Add IRQ chip manager groundwork
Signed-off-by: Ian Moffett <ian@mirocom.org>
2026-04-23 22:28:24 -04:00
chloe d63c88259f sp1: mm: Add MI virtual memory management
Signed-off-by: Ian Moffett <ian@mirocom.org>
2026-04-22 23:56:01 -04:00
chloe 37fc085646 sp1: mmu: Clean up header
Signed-off-by: Ian Moffett <ian@mirocom.org>
2026-04-22 23:22:23 -04:00
chloe 353a8465a3 sp1/amd64: mmu: Use PAGESIZE instead of hardcoding
Signed-off-by: Ian Moffett <ian@mirocom.org>
2026-04-22 23:08:44 -04:00
chloe 8c650daf69 sp1/amd64: mmu: Remove redundant whitespace
Signed-off-by: Ian Moffett <ian@mirocom.org>
2026-04-22 23:07:53 -04:00
chloe 1bff60c27a sp1/amd64: mmu: Add page mapping implementation
Signed-off-by: Ian Moffett <ian@mirocom.org>
2026-04-21 21:48:13 -04:00
7 changed files with 482 additions and 0 deletions
+199
View File
@@ -9,10 +9,16 @@
* consent from Mirocom Laboratories. * consent from Mirocom Laboratories.
*/ */
#include <sys/param.h>
#include <sys/cdefs.h> #include <sys/cdefs.h>
#include <sys/status.h>
#include <mu/mmu.h> #include <mu/mmu.h>
#include <mm/vm.h> #include <mm/vm.h>
#include <mm/physmem.h> #include <mm/physmem.h>
#include <machine/tlb.h>
#include <machine/param.h>
#include <stdbool.h>
#include <string.h>
/* /*
* Page-Table Entry (PTE) flags * Page-Table Entry (PTE) flags
@@ -31,6 +37,154 @@
#define PTE_GLOBAL BIT(8) /* Global; sticky */ #define PTE_GLOBAL BIT(8) /* Global; sticky */
#define PTE_NX BIT(63) /* Execute-disable */ #define PTE_NX BIT(63) /* Execute-disable */
/* 57-bit linear addresses */
#define CR4_LA57 BIT(12)
/*
* Represents valid pagemap levels
*/
typedef enum {
PAGELVL_PML1,
PAGELVL_PML2,
PAGELVL_PML3,
PAGELVL_PML4,
PAGELVL_PML5
} pagelvl_t;
/*
* Obtain page table flags from protection flags
*
* @prot: Protection flags to extract from
*/
static size_t
mmu_prot_to_pte(int prot)
{
size_t pte_flags = PTE_P | PTE_NX;
if (ISSET(prot, PROT_WRITE))
pte_flags |= PTE_RW;
if (ISSET(prot, PROT_EXEC))
pte_flags &= ~PTE_NX;
return pte_flags;
}
/*
* Verify if a pagesize is valid
*
* @ps: Pagesize to verify
*/
static bool
mmu_ps_valid(pagelvl_t ps)
{
switch (ps) {
case PAGESIZE_4K:
return true;
}
return false;
}
/*
* Obtain the top-level in use for the current machine
* configuration.
*/
static inline pagelvl_t
mmu_get_level(void)
{
uint64_t cr4;
__asmv(
"mov %%cr4, %0"
: "=r" (cr4)
:
: "memory"
);
return ISSET(cr4, CR4_LA57)
? PAGELVL_PML5
: PAGELVL_PML4;
}
/*
* This function extracts those cute 9 bit segments that
* function as indices into pagemap levels.
*
* @vma: Virtual memory address used as key
* @lvl: Level to extract
*/
static inline size_t
mmu_extract_index(uintptr_t vma, pagelvl_t lvl)
{
switch (lvl) {
case PAGELVL_PML1:
return (vma >> 12) & 0x1FF;
case PAGELVL_PML2:
return (vma >> 21) & 0x1FF;
case PAGELVL_PML3:
return (vma >> 30) & 0x1FF;
case PAGELVL_PML4:
return (vma >> 39) & 0x1FF;
case PAGELVL_PML5:
return (vma >> 48) & 0x1FF;
}
return (size_t)-1;
}
/*
* Extract a pagemap index
*
* @vfr: Virtual fuck region
* @vma: Virtual memory address
* @lvl: Pagemap level to extract
* @alloc: If true, allocate new entries
*/
static uint64_t *
mmu_extract_level(struct mmu_vfr *vfr, uintptr_t vma, pagelvl_t lvl, bool alloc)
{
uintptr_t *pmap, pma;
void *tmp_p;
size_t index;
pagelvl_t cur_level;
if (vfr == NULL || lvl > PAGELVL_PML5) {
return NULL;
}
cur_level = mmu_get_level();
pmap = pma_to_vma((vfr->cr3 & PTE_ADDR_MASK));
while (cur_level > lvl) {
index = mmu_extract_index(vma, cur_level);
/* Is this entry present? */
if (ISSET(pmap[index], PTE_P)) {
pmap = pma_to_vma((pmap[index] & PTE_ADDR_MASK));
--cur_level;
continue;
}
if (!alloc) {
return NULL;
}
pma = mm_physmem_alloc(1);
if (pma == 0) {
return NULL;
}
tmp_p = pma_to_vma(pma);
memset(tmp_p, 0, PAGESIZE);
pmap[index] = pma | (PTE_P | PTE_RW | PTE_US);
pmap = tmp_p;
--cur_level;
}
return pmap;
}
void void
mu_mmu_readvfr(struct mmu_vfr *res) mu_mmu_readvfr(struct mmu_vfr *res)
{ {
@@ -89,3 +243,48 @@ mu_mmu_forkvfr(struct mmu_vfr *vfr, struct mmu_vfr *res)
res->cr3 = dest; res->cr3 = dest;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
status_t
mu_mmu_map(struct mmu_vfr *vfr, uintptr_t vma, uintptr_t pma,
int prot, pagesize_t ps)
{
uintptr_t *tbl;
size_t index, flags;
if (vfr == NULL || !mmu_ps_valid(ps)) {
return STATUS_INVALID_PARAM;
}
tbl = mmu_extract_level(vfr, vma, PAGELVL_PML1, true);
if (tbl == NULL) {
return STATUS_NO_MEMORY;
}
index = mmu_extract_index(vma, PAGELVL_PML1);
flags = mmu_prot_to_pte(prot);
tbl[index] = pma | flags;
md_tlb_flush(vma);
return STATUS_SUCCESS;
}
status_t
mu_mmu_unmap(struct mmu_vfr *vfr, uintptr_t vma, pagesize_t ps)
{
uintptr_t *tbl;
size_t index;
if (vfr == NULL) {
return STATUS_INVALID_PARAM;
}
tbl = mmu_extract_level(vfr, vma, PAGELVL_PML1, false);
if (tbl == NULL) {
return STATUS_NOT_FOUND;
}
index = mmu_extract_index(vma, PAGELVL_PML1);
tbl[index] = 0;
md_tlb_flush(vma);
return STATUS_SUCCESS;
}
+96
View File
@@ -0,0 +1,96 @@
/*
* Copyright (c) 2026, Mirocom Laboratories
* All rights reserved.
*
* The following sources are CONFIDENTIAL and PROPRIETARY
* property of Mirocom Laboratories. Unauthorized copying,
* use, distribution or modification of this file, in whole
* and in part, is strictly prohibited without the prior written
* consent from Mirocom Laboratories.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <os/knot.h>
#include <lib/printf.h>
#include <machine/irqchip.h>
#include <io/acpi/acpi.h>
#include <io/acpi/tables.h>
#define pr_trace(fmt, ...) \
printf("irqchip: " fmt, ##__VA_ARGS__)
/* Online capable */
#define LAPIC_ONLCAP BIT(1)
/*
* Print information about a Local APIC unit
*/
static inline void
irqchip_print_lapic(struct local_apic *lapic)
{
static uint16_t log_count = 0;
if (lapic == NULL) {
return;
}
if ((log_count++) >= 4) {
pr_trace("....\n");
return;
}
pr_trace("lapic(%d).cpu : %d\n",
lapic->apic_id, lapic->processor_id);
}
/*
* Print information about an I/O APIC unit
*/
static inline void
irqchip_print_ioapic(struct ioapic *ioapic)
{
if (ioapic == NULL) {
return;
}
pr_trace("ioapic(%d).gsi_base : %d\n",
ioapic->ioapic_id, ioapic->gsi_base);
pr_trace("ioapic(%d).mmio : %p\n",
ioapic->ioapic_id, ioapic->ioapic_addr);
}
status_t
md_irqchip_init(void)
{
struct acpi_madt *madt;
struct local_apic *lapic;
struct ioapic *ioapic;
struct apic_header *hdr;
char *cur, *end;
madt = acpi_query("APIC");
if (madt == NULL) {
knot("could not query acpi madt table\n");
}
cur = (char *)(madt + 1);
end = (char *)madt + madt->hdr.length;
while (cur < end) {
hdr = (struct apic_header *)cur;
switch (hdr->type) {
case APIC_TYPE_LOCAL_APIC:
lapic = (struct local_apic *)hdr;
irqchip_print_lapic(lapic);
break;
case APIC_TYPE_IO_APIC:
ioapic = (struct ioapic *)hdr;
irqchip_print_ioapic(ioapic);
break;
}
cur += hdr->length;
}
}
+3
View File
@@ -16,6 +16,7 @@
#include <os/bpt.h> #include <os/bpt.h>
#include <mm/vm.h> #include <mm/vm.h>
#include <string.h> #include <string.h>
#include <machine/irqchip.h> /* shared */
#define pr_trace(fmt, ...) \ #define pr_trace(fmt, ...) \
printf("acpi: " fmt, ##__VA_ARGS__) printf("acpi: " fmt, ##__VA_ARGS__)
@@ -101,4 +102,6 @@ acpi_init(void)
root_sdt = pma_to_vma((uintptr_t)rsdp->xsdt_addr); root_sdt = pma_to_vma((uintptr_t)rsdp->xsdt_addr);
root_sdt_entries = (root_sdt->hdr.length - sizeof(root_sdt->hdr)) / 8; root_sdt_entries = (root_sdt->hdr.length - sizeof(root_sdt->hdr)) / 8;
} }
md_irqchip_init();
} }
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2026, Mirocom Laboratories
* All rights reserved.
*
* The following sources are CONFIDENTIAL and PROPRIETARY
* property of Mirocom Laboratories. Unauthorized copying,
* use, distribution or modification of this file, in whole
* and in part, is strictly prohibited without the prior written
* consent from Mirocom Laboratories.
*/
#include <sys/units.h>
#include <sys/param.h>
#include <lib/printf.h>
#include <mu/mmu.h>
#include <mu/param.h>
#include <mm/vm.h>
#define pr_trace(fmt, ...) \
printf("vm_map: " fmt, ##__VA_ARGS__)
/* Used to safely convert pagesize constants */
#define GRAN(ps) \
((ps) <= PAGESIZE_1G) \
? pstab[(ps)] \
: pstab[PAGESIZE_4K]
/* Pagesize constant to length table */
static size_t pstab[] = {
[PAGESIZE_4K] = 0x1000,
[PAGESIZE_2M] = UNIT_MIB * 2,
[PAGESIZE_1G] = UNIT_GIB
};
status_t
mm_vm_map(struct mmu_vfr *vfr, struct vm_map *mapping, int prot)
{
size_t len, gran;
uintptr_t vma, pma;
status_t status;
if (vfr == NULL || mapping == NULL) {
return STATUS_INVALID_PARAM;
}
gran = GRAN(mapping->ps);
vma = ALIGN_DOWN(mapping->vma_base, gran);
pma = ALIGN_DOWN(mapping->pma_base, gran);
len = mapping->length;
len = ALIGN_UP(len + (len & (gran - 1)), gran);
for (size_t i = 0; i < len; i += gran) {
status = mu_mmu_map(vfr, vma + i, pma + i, prot, mapping->ps);
/* Destroy what we created on failure */
if (status != STATUS_SUCCESS) {
mm_vm_unmap(vfr, mapping);
return status;
}
}
return STATUS_SUCCESS;
}
status_t
mm_vm_unmap(struct mmu_vfr *vfr, struct vm_map *mapping)
{
size_t gran, len;
uintptr_t vma;
if (vfr == NULL || mapping == NULL) {
return STATUS_INVALID_PARAM;
}
gran = GRAN(mapping->ps);
vma = ALIGN_DOWN(mapping->vma_base, gran);
len = mapping->length;
len = ALIGN_UP(len + (len & (gran - 1)), gran);
for (size_t i = 0; i < len; i += gran) {
mu_mmu_unmap(vfr, vma + i, mapping->ps);
}
return STATUS_SUCCESS;
}
+22
View File
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2026, Mirocom Laboratories
* All rights reserved.
*
* The following sources are CONFIDENTIAL and PROPRIETARY
* property of Mirocom Laboratories. Unauthorized copying,
* use, distribution or modification of this file, in whole
* and in part, is strictly prohibited without the prior written
* consent from Mirocom Laboratories.
*/
#ifndef _MACHINE_IRQCHIP_H_
#define _MACHINE_IRQCHIP_H_ 1
#include <sys/status.h>
/*
* Initialize platform interrupt controller chips
*/
status_t md_irqchip_init(void);
#endif /* !_MACHINE_IRQCHIP_H_ */
+35
View File
@@ -12,8 +12,27 @@
#ifndef _MM_VM_H_ #ifndef _MM_VM_H_
#define _MM_VM_H_ 1 #define _MM_VM_H_ 1
#include <sys/types.h>
#include <sys/param.h> #include <sys/param.h>
#include <os/bpt.h> #include <os/bpt.h>
#include <mu/mmu.h>
/*
* Represents a virtual memory mapping that can be made
*
* @ps: Pagesize
* @vma_base: Virtual memory base
* @pma_base: Physical memory base
* @length: Number of bytes to map
*
* XXX: `pma_base' is unused when unmapping regions
*/
struct vm_map {
pagesize_t ps;
uintptr_t vma_base;
uintptr_t pma_base;
size_t length;
};
/* /*
* Macros used to convert physical to virtual addresses * Macros used to convert physical to virtual addresses
@@ -24,6 +43,22 @@
#define vma_to_pma(vma) \ #define vma_to_pma(vma) \
(uintptr_t)PTR_NOFFSET(vma, bpt_kload_base()) (uintptr_t)PTR_NOFFSET(vma, bpt_kload_base())
/*
* Create a virtual memory mapping
*
* @vfr: Virtual fuck region to map within
* @mapping: Mapping to create
*/
status_t mm_vm_map(struct mmu_vfr *vfr, struct vm_map *mapping, int prot);
/*
* Destroy a virtual memory mapping
*
* @vfr: Virtual fuck region to unmap within
* @mapping: Mapping to destroy
*/
status_t mm_vm_unmap(struct mmu_vfr *vfr, struct vm_map *mapping);
/* /*
* Initialize the virtual memory management * Initialize the virtual memory management
*/ */
+40
View File
@@ -13,6 +13,7 @@
#define _MU_MMU_H_ 1 #define _MU_MMU_H_ 1
#include <sys/status.h> #include <sys/status.h>
#include <sys/mman.h>
/* /*
* Each running SP1 process is to have a virtual fuck region * Each running SP1 process is to have a virtual fuck region
@@ -21,6 +22,16 @@
*/ */
#include <machine/vfr.h> /* shared; virtual fuck region~ */ #include <machine/vfr.h> /* shared; virtual fuck region~ */
/*
* Represents valid page sizes that can be used when
* creating mappings
*/
typedef enum {
PAGESIZE_4K,
PAGESIZE_2M,
PAGESIZE_1G
} pagesize_t;
/* /*
* Obtain the current VFR in-use * Obtain the current VFR in-use
* *
@@ -35,6 +46,35 @@ void mu_mmu_readvfr(struct mmu_vfr *res);
*/ */
void mu_mmu_writevfr(struct mmu_vfr *vfr); void mu_mmu_writevfr(struct mmu_vfr *vfr);
/*
* Create a virtual to physical mapping within a
* specific virtual fuck region
*
* @vfr: Virtual fuck region to map within
* @vma: Virtual memory address to map
* @pma: Physical memory address to map to
* @prot: Protection flags
* @pagesize_t: Pagesize to map
*/
status_t mu_mmu_map(
struct mmu_vfr *vfr, uintptr_t vma,
uintptr_t pma, int prot,
pagesize_t ps
);
/*
* Destroy a virtual memory mapping in the virtual
* fuck region
*
* @vfr: Virtual fuck region to unmap within
* @vma: Virtual memory address to unmap
* @ps: Pagesize of address to unmap
*/
status_t mu_mmu_unmap(
struct mmu_vfr *vfr, uintptr_t vma,
pagesize_t ps
);
/* /*
* Fork a VFR and clear out the lower half * Fork a VFR and clear out the lower half
* *