Skip to content

Commit

Permalink
Map video memory to mapping area (#108)
Browse files Browse the repository at this point in the history
* Create a dedicated region of kernel virtual memory for permanent
mappings.
* Map text video memory there instead of the current hack of allocating
mapped pages and then remapping those pages.

This is done in preparation for local APIC support: the APIC's
memory-mapped registers will be mapped in this region as well. This will
likely also be useful to map ACPI tables.
  • Loading branch information
phaubertin authored Jan 12, 2025
1 parent 9b2f389 commit 95f1aba
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 50 deletions.
40 changes: 40 additions & 0 deletions include/kernel/domain/services/mman.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2025 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_SERVICES_MMAN_H
#define JINUE_KERNEL_SERVICES_MMAN_H

#include <kernel/machine/types.h>
#include <stddef.h>

void *map_in_kernel(kern_paddr_t paddr, size_t size, int prot);

#endif
4 changes: 2 additions & 2 deletions include/kernel/infrastructure/i686/boot_alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@

void boot_alloc_init(boot_alloc_t *boot_alloc, const bootinfo_t *bootinfo);

void boot_reinit_at_16mb(boot_alloc_t *boot_alloc);
void boot_alloc_reinit_at_16mb(boot_alloc_t *boot_alloc);

void boot_reinit_at_klimit(boot_alloc_t *boot_alloc);
void boot_alloc_reinit_at_klimit(boot_alloc_t *boot_alloc);

/**
* Allocate an object on the boot heap.
Expand Down
39 changes: 39 additions & 0 deletions include/kernel/infrastructure/i686/exports/asm/machine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2025 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_EXPORTS_ASM_MACHINE_H
#define JINUE_KERNEL_INFRASTRUCTURE_I686_EXPORTS_ASM_MACHINE_H

#define MAPPING_AREA_ADDR 0xf8000000

#define MAPPING_AREA_END 0xffe00000

#endif
2 changes: 0 additions & 2 deletions include/kernel/infrastructure/i686/pmap/pmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,6 @@ void pmap_destroy_addr_space(addr_space_t *addr_space);

void pmap_switch_addr_space(addr_space_t *addr_space);

void pmap_boot_map(void *addr, uint32_t paddr, int num_entries);

void pmap_map_kernel_page(void *vaddr, kern_paddr_t paddr, int flags);

void pmap_unmap_kernel_page(void *addr);
Expand Down
4 changes: 4 additions & 0 deletions include/kernel/machine/asm/machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@

#include <jinue/shared/asm/machine.h>

#ifdef __i686__
#include <kernel/infrastructure/i686/exports/asm/machine.h>
#endif

/** number of bits in a virtual address that represent the offset within a page */
#define PAGE_BITS JINUE_PAGE_BITS

Expand Down
1 change: 1 addition & 0 deletions kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ sources.kernel.c = \
domain/services/exec.c \
domain/services/ipc.c \
domain/services/logging.c \
domain/services/mman.c \
domain/services/panic.c \
domain/services/scheduler.c \
domain/config.c \
Expand Down
94 changes: 94 additions & 0 deletions kernel/domain/services/mman.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2025 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/domain/services/mman.h>
#include <kernel/domain/services/panic.h>
#include <kernel/machine/asm/machine.h>
#include <kernel/machine/pmap.h>
#include <kernel/machine/spinlock.h>
#include <kernel/utils/utils.h>

static struct {
addr_t addr;
spinlock_t lock;
} alloc_state = {
.addr = (addr_t)MAPPING_AREA_ADDR,
.lock = SPINLOCK_INITIALIZER
};

/**
* Permanently map memory in the kernel's mapping area
*
* Sufficient virtual memory is allocated in the mapping area, which ranges
* from MAPPING_AREA_ADDR to MAPPING_AREA_END. This function panics if
* sufficient virtual memory cannot be allocated in this range.
*
* There are no alignment requirements: this function takes care of aligning
* the mapping on page boundaries.
*
* @param paddr address to memory map
* @param size size of memory to map
* @param prot mapping protection flags
*/
void *map_in_kernel(kern_paddr_t paddr, size_t size, int prot) {
size_t offset = paddr % PAGE_SIZE;

size += offset;

spin_lock(&alloc_state.lock);

if((addr_t)MAPPING_AREA_END - alloc_state.addr < size) {
spin_unlock(&alloc_state.lock);
panic("No more space to map memory in kernel");
}

addr_t start = alloc_state.addr;
alloc_state.addr = ALIGN_END_PTR(start + size, PAGE_SIZE);

spin_unlock(&alloc_state.lock);

addr_t map_addr = start;
kern_paddr_t map_paddr = paddr - offset;

while(true) {
machine_map_kernel_page(map_addr, map_paddr, prot);

if(size <= PAGE_SIZE) {
break;
}

map_addr += PAGE_SIZE;
map_paddr += PAGE_SIZE;
size -= PAGE_SIZE;
}

return start + offset;
}
6 changes: 3 additions & 3 deletions kernel/infrastructure/i686/boot_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
*
* This function sets up the allocator to allocate pages after the kernel loaded
* at 0x100000 (1MB). Once the kernel has been moved to 0x1000000 (16MB), the
* boot_reinit_at_16mb() function has to be called to start allocating pages
* boot_alloc_reinit_at_16mb() function has to be called to start allocating pages
* there.
*
* @param boot_alloc the allocator state initialized by this function
Expand All @@ -71,7 +71,7 @@ void boot_alloc_init(boot_alloc_t *boot_alloc, const bootinfo_t *bootinfo) {
* @param boot_alloc the allocator state initialized by this function
*
* */
void boot_reinit_at_16mb(boot_alloc_t *boot_alloc) {
void boot_alloc_reinit_at_16mb(boot_alloc_t *boot_alloc) {
boot_alloc->current_page = boot_alloc->first_page_at_16mb;
boot_alloc->page_limit = (char *)MEMORY_ADDR_16MB + BOOT_SIZE_AT_16MB;
}
Expand All @@ -90,7 +90,7 @@ void boot_reinit_at_16mb(boot_alloc_t *boot_alloc) {
* @param boot_alloc the allocator state initialized by this function
*
* */
void boot_reinit_at_klimit(boot_alloc_t *boot_alloc) {
void boot_alloc_reinit_at_klimit(boot_alloc_t *boot_alloc) {
boot_alloc->current_page = (void *)PHYS_TO_VIRT_AT_16MB(boot_alloc->current_page);
boot_alloc->page_limit = (char *)KLIMIT + BOOT_SIZE_AT_16MB;
}
Expand Down
56 changes: 25 additions & 31 deletions kernel/infrastructure/i686/init.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2024 Philippe Aubertin.
* Copyright (C) 2019-2025 Philippe Aubertin.
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -29,10 +29,12 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <jinue/shared/asm/mman.h>
#include <jinue/shared/asm/syscalls.h>
#include <kernel/domain/alloc/page_alloc.h>
#include <kernel/domain/services/cmdline.h>
#include <kernel/domain/services/logging.h>
#include <kernel/domain/services/mman.h>
#include <kernel/domain/services/panic.h>
#include <kernel/infrastructure/i686/asm/msr.h>
#include <kernel/infrastructure/i686/drivers/acpi.h>
Expand Down Expand Up @@ -199,30 +201,24 @@ static void load_selectors(percpu_t *cpu_data, boot_alloc_t *boot_alloc) {
boot_heap_pop(boot_alloc);
}

static void remap_text_video_memory(boot_alloc_t *boot_alloc) {
size_t video_buffer_size = VGA_TEXT_VID_TOP - VGA_TEXT_VID_BASE;
size_t num_pages = video_buffer_size / PAGE_SIZE;

void *buffer = boot_page_alloc_n(boot_alloc, num_pages);
void *mapped = (void *)PHYS_TO_VIRT_AT_16MB(buffer);

pmap_boot_map(mapped, VGA_TEXT_VID_BASE, num_pages);

info("Remapping text video memory at %#p", mapped);

/* Note: after this call to vga_set_base_addr() until we switch to the new
* new address space, VGA output is not possible. Attempting it will cause
* a kernel panic due to a page fault (and the panic handler itself attempts
* to log). */
vga_set_base_addr(mapped);
}

static void enable_global_pages(void) {
if(cpu_has_feature(CPUINFO_FEATURE_PGE)) {
set_cr4(get_cr4() | X86_CR4_PGE);
}
}

static void remap_text_video_memory(void) {
void *mapped = map_in_kernel(
VGA_TEXT_VID_BASE,
VGA_TEXT_VID_TOP - VGA_TEXT_VID_BASE,
JINUE_PROT_READ | JINUE_PROT_WRITE
);

vga_set_base_addr(mapped);

info("Remapped text video memory at %#p", mapped);
}

static void initialize_page_allocator(boot_alloc_t *boot_alloc) {
while(! boot_page_alloc_is_empty(boot_alloc)) {
page_free(boot_page_alloc(boot_alloc));
Expand Down Expand Up @@ -346,7 +342,7 @@ void machine_init(const config_t *config) {
* Do this after enabling PAE: we want the temporary PAE page tables to be
* allocated after 1MB because we won't need them anymore once the final
* address space is created. */
boot_reinit_at_16mb(&boot_alloc);
boot_alloc_reinit_at_16mb(&boot_alloc);

/* allocate per-CPU data
*
Expand Down Expand Up @@ -383,21 +379,19 @@ void machine_init(const config_t *config) {

memory_initialize_array(&boot_alloc, bootinfo);

/* After this, VGA output is not possible until we switch to the
* new address space (see the call to pmap_switch_addr_space() below).
* Attempting it will cause a kernel panic due to a page fault (and the
* panic handler itself attempts to log). */
remap_text_video_memory(&boot_alloc);

/* switch to new address space */
pmap_switch_addr_space(addr_space);

enable_global_pages();

/* From this point, we are ready to switch to the new address space, so we
* don't need to allocate any more pages from the boot allocator. Transfer
* the remaining pages to the run-time page allocator. */
boot_reinit_at_klimit(&boot_alloc);

/* This should be done early after calling pmap_switch_addr_space()
* because, until it's done, any attempt to log anything to VGA will
* result in a kernel panic caused by a kernel page fault (and the
* panic handler itself will then attempt to log). */
remap_text_video_memory();

/* Transfer the remaining pages to the run-time page allocator. */
boot_alloc_reinit_at_klimit(&boot_alloc);
initialize_page_allocator(&boot_alloc);

/* create slab cache to allocate PDPTs
Expand Down
12 changes: 0 additions & 12 deletions kernel/infrastructure/i686/pmap/pmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -535,18 +535,6 @@ void pmap_switch_addr_space(addr_space_t *addr_space) {
cpu_data->current_addr_space = addr_space;
}

void pmap_boot_map(void *addr, uint32_t paddr, int num_entries) {
int offset = (uintptr_t)((char *)addr - KLIMIT) / PAGE_SIZE;

initialize_page_table_linear(
get_pte_with_offset(
(pte_t *)PTR_TO_PHYS_ADDR_AT_16MB(kernel_page_tables),
offset),
paddr,
X86_PTE_READ_WRITE,
num_entries);
}

static pte_t *pmap_lookup_page_table(
addr_space_t *addr_space,
void *addr,
Expand Down

0 comments on commit 95f1aba

Please sign in to comment.