diff --git a/include/kernel/domain/services/mman.h b/include/kernel/domain/services/mman.h new file mode 100644 index 00000000..42254501 --- /dev/null +++ b/include/kernel/domain/services/mman.h @@ -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 +#include + +void *map_in_kernel(kern_paddr_t paddr, size_t size, int prot); + +#endif diff --git a/include/kernel/infrastructure/i686/boot_alloc.h b/include/kernel/infrastructure/i686/boot_alloc.h index b58e663f..1b6eab4a 100644 --- a/include/kernel/infrastructure/i686/boot_alloc.h +++ b/include/kernel/infrastructure/i686/boot_alloc.h @@ -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. diff --git a/include/kernel/infrastructure/i686/exports/asm/machine.h b/include/kernel/infrastructure/i686/exports/asm/machine.h new file mode 100644 index 00000000..16e0b31f --- /dev/null +++ b/include/kernel/infrastructure/i686/exports/asm/machine.h @@ -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 diff --git a/include/kernel/infrastructure/i686/pmap/pmap.h b/include/kernel/infrastructure/i686/pmap/pmap.h index 09e33507..bc693e5b 100644 --- a/include/kernel/infrastructure/i686/pmap/pmap.h +++ b/include/kernel/infrastructure/i686/pmap/pmap.h @@ -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); diff --git a/include/kernel/machine/asm/machine.h b/include/kernel/machine/asm/machine.h index 1e69b530..a424ee04 100644 --- a/include/kernel/machine/asm/machine.h +++ b/include/kernel/machine/asm/machine.h @@ -34,6 +34,10 @@ #include +#ifdef __i686__ +#include +#endif + /** number of bits in a virtual address that represent the offset within a page */ #define PAGE_BITS JINUE_PAGE_BITS diff --git a/kernel/Makefile b/kernel/Makefile index 58f2c53b..7f072c2c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -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 \ diff --git a/kernel/domain/services/mman.c b/kernel/domain/services/mman.c new file mode 100644 index 00000000..edc2b596 --- /dev/null +++ b/kernel/domain/services/mman.c @@ -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 +#include +#include +#include +#include +#include + +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; +} diff --git a/kernel/infrastructure/i686/boot_alloc.c b/kernel/infrastructure/i686/boot_alloc.c index 48a3642b..c075d429 100644 --- a/kernel/infrastructure/i686/boot_alloc.c +++ b/kernel/infrastructure/i686/boot_alloc.c @@ -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 @@ -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; } @@ -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; } diff --git a/kernel/infrastructure/i686/init.c b/kernel/infrastructure/i686/init.c index d70d8a9e..5fd1ec56 100644 --- a/kernel/infrastructure/i686/init.c +++ b/kernel/infrastructure/i686/init.c @@ -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 @@ -29,10 +29,12 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include #include +#include #include #include #include @@ -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)); @@ -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 * @@ -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 diff --git a/kernel/infrastructure/i686/pmap/pmap.c b/kernel/infrastructure/i686/pmap/pmap.c index 4ab16ded..aa94b96b 100644 --- a/kernel/infrastructure/i686/pmap/pmap.c +++ b/kernel/infrastructure/i686/pmap/pmap.c @@ -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,