Merge branch 'paging' of https://github.com/stv0g/eduOS
Conflicts: Makefile.example
This commit is contained in:
commit
67c5b3dfd8
15 changed files with 761 additions and 84 deletions
|
@ -1,6 +1,7 @@
|
|||
TOPDIR = $(shell pwd)
|
||||
ARCH = x86
|
||||
NAME = eduos
|
||||
KERNDIRS = libkern kernel mm arch/$(ARCH)/kernel arch/$(ARCH)/mm
|
||||
KERNDIRS = libkern kernel mm arch/$(ARCH)/kernel
|
||||
SUBDIRS = $(KERNDIRS)
|
||||
|
||||
|
@ -20,10 +21,19 @@ OBJCOPY_FOR_TARGET = $(CROSSCOMPREFIX)objcopy
|
|||
RANLIB_FOR_TARGET = $(CROSSCOMPREFIX)ranlib
|
||||
STRIP_FOR_TARGET = $(CROSSCOMPREFIX)strip
|
||||
READELF_FOR_TARGET = $(CROSSCOMPREFIX)readelf
|
||||
|
||||
NASM = nasm
|
||||
GDB = gdb
|
||||
QEMU = qemu-system-i386
|
||||
|
||||
QEMU = qemu-system-i386
|
||||
NASMFLAGS = -felf32 -g -i$(TOPDIR)/include/eduos/
|
||||
GDBFLAGS = -x debug.gdb
|
||||
QEMUFLAGS = -smp 2 -monitor stdio \
|
||||
-net nic,model=rtl8139 \
|
||||
-net user,hostfwd=tcp::12345-:7 \
|
||||
-serial tcp::12346,server,nowait
|
||||
|
||||
INCLUDE = -I$(TOPDIR)/include -I$(TOPDIR)/arch/$(ARCH)/include
|
||||
# Compiler options for final code
|
||||
CFLAGS = -g -m32 -march=i586 -Wall -O2 -fno-builtin -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc $(INCLUDE) -fno-stack-protector
|
||||
|
@ -63,14 +73,15 @@ veryclean: clean
|
|||
@echo Very cleaned
|
||||
|
||||
qemu: $(NAME).elf
|
||||
$(QEMU) -monitor stdio -smp 2 -net nic,model=rtl8139 -net user,hostfwd=tcp::12345-:7 -net dump -kernel $(NAME).elf
|
||||
$(QEMU) $(QEMUFLAGS) -kernel $(NAME).elf
|
||||
|
||||
qemu-dbg: $(NAME).elf
|
||||
$(QEMU) -monitor stdio -s -S -smp 2 -net nic,model=rtl8139 -net user,hostfwd=tcp::12345-:7 -net dump -kernel $(NAME).elf
|
||||
debug: $(NAME).elf
|
||||
$(TERM) -e $(GDB) $(GDBFLAGS) &
|
||||
$(QEMU) $(QEMUFLAGS) -s -S -kernel $(NAME).elf
|
||||
|
||||
doc:
|
||||
@doxygen
|
||||
@echo Create documentation...
|
||||
@doxygen
|
||||
|
||||
%.o : %.c
|
||||
@echo [CC] $@
|
||||
|
@ -92,5 +103,5 @@ include/eduos/config.inc: include/eduos/config.h
|
|||
$Q$(CC_FOR_TARGET) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
.PHONY: default all clean emu gdb newlib tools
|
||||
|
||||
|
||||
include $(addsuffix /Makefile,$(SUBDIRS))
|
||||
|
|
|
@ -41,6 +41,13 @@
|
|||
|
||||
#include <eduos/stddef.h>
|
||||
|
||||
/// Does the bootloader provide mem_* fields?
|
||||
#define MULTIBOOT_INFO_MEM (1 << 0)
|
||||
/// Does the bootloader provide a list of modules?
|
||||
#define MULTIBOOT_INFO_MODS (1 << 3)
|
||||
/// Does the bootloader provide a full memory map?
|
||||
#define MULTIBOOT_INFO_MEM_MAP (1 << 6)
|
||||
|
||||
typedef uint16_t multiboot_uint16_t;
|
||||
typedef uint32_t multiboot_uint32_t;
|
||||
typedef uint64_t multiboot_uint64_t;
|
||||
|
@ -143,6 +150,8 @@ struct multiboot_mod_list
|
|||
};
|
||||
typedef struct multiboot_mod_list multiboot_module_t;
|
||||
|
||||
extern multiboot_info_t* mb_info;
|
||||
/// Pointer to multiboot structure
|
||||
/// This pointer is declared at set by entry.asm
|
||||
extern multiboot_info_t* mb_info;
|
||||
|
||||
#endif
|
||||
|
|
141
arch/x86/include/asm/page.h
Normal file
141
arch/x86/include/asm/page.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 REGENTS 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Steffen Vogel
|
||||
* @file arch/x86/include/asm/page.h
|
||||
* @brief Paging related functions
|
||||
*
|
||||
* This file contains the several functions to manage the page tables
|
||||
*/
|
||||
|
||||
#ifndef __PAGE_H__
|
||||
#define __PAGE_H__
|
||||
|
||||
/// Page offset bits
|
||||
#define PAGE_BITS 12
|
||||
/// The size of a single page in bytes
|
||||
#define PAGE_SIZE ( 1L << PAGE_BITS)
|
||||
/// Mask the page address without page map flags
|
||||
#define PAGE_MASK (-1L << PAGE_BITS)
|
||||
|
||||
/// Total operand width in bits
|
||||
#define BITS 32
|
||||
/// Linear/virtual address width
|
||||
#define VIRT_BITS BITS
|
||||
/// Physical address width (we dont support PAE)
|
||||
#define PHYS_BITS BITS
|
||||
/// Page map bits
|
||||
#define PAGE_MAP_BITS 10
|
||||
/// Number of page map indirections
|
||||
#define PAGE_LEVELS 2
|
||||
|
||||
/// Make address canonical
|
||||
#define CANONICAL(addr) (addr) // only for 32 bit paging
|
||||
|
||||
/// The number of entries in a page map table
|
||||
#define PAGE_MAP_ENTRIES (1L << PAGE_MAP_BITS)
|
||||
|
||||
/// Align to next page
|
||||
#define PAGE_FLOOR(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
|
||||
/// Align to page
|
||||
#define PAGE_CEIL(addr) ( (addr) & PAGE_MASK)
|
||||
|
||||
/// Page is present
|
||||
#define PG_PRESENT (1 << 0)
|
||||
/// Page is read- and writable
|
||||
#define PG_RW (1 << 1)
|
||||
/// Page is addressable from userspace
|
||||
#define PG_USER (1 << 2)
|
||||
/// Page write through is activated
|
||||
#define PG_PWT (1 << 3)
|
||||
/// Page cache is disabled
|
||||
#define PG_PCD (1 << 4)
|
||||
/// Page was recently accessed (set by CPU)
|
||||
#define PG_ACCESSED (1 << 5)
|
||||
/// Page is dirty due to recent write-access (set by CPU)
|
||||
#define PG_DIRTY (1 << 6)
|
||||
/// Huge page: 4MB (or 2MB, 1GB)
|
||||
#define PG_PSE (1 << 7)
|
||||
/// Page attribute table
|
||||
#define PG_PAT PG_PSE
|
||||
/// Global TLB entry (Pentium Pro and later)
|
||||
#define PG_GLOBAL (1 << 8)
|
||||
/// This page or table is used during the boot process
|
||||
#define PG_BOOT (1 << 9)
|
||||
|
||||
/// This page is reserved for copying
|
||||
#define PAGE_TMP (PAGE_FLOOR((size_t) &kernel_start) - PAGE_SIZE)
|
||||
|
||||
/** @brief Converts a virtual address to a physical
|
||||
*
|
||||
* A non mapped virtual address causes a pagefault!
|
||||
*
|
||||
* @param addr Virtual address to convert
|
||||
* @return physical address
|
||||
*/
|
||||
size_t page_virt_to_phys(size_t vir);
|
||||
|
||||
/** @brief Initialize paging subsystem
|
||||
*
|
||||
* This function uses the existing bootstrap page tables (boot_{pgd, pgt})
|
||||
* to map required regions (video memory, kernel, etc..).
|
||||
* Before calling page_init(), the bootstrap tables contain a simple identity
|
||||
* paging. Which is replaced by more specific mappings.
|
||||
*/
|
||||
int page_init();
|
||||
|
||||
/** @brief Map a continious region of pages
|
||||
*
|
||||
* @param viraddr
|
||||
* @param phyaddr
|
||||
* @param npages
|
||||
* @param bits
|
||||
* @return
|
||||
*/
|
||||
int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits);
|
||||
|
||||
/** @brief Unmap a continious region of pages
|
||||
*
|
||||
* @param viraddr
|
||||
* @param npages
|
||||
* @return
|
||||
*/
|
||||
int page_unmap(size_t viraddr, size_t npages);
|
||||
|
||||
/** @brief Copy a whole page map tree
|
||||
*
|
||||
* @param dest Physical address of new page map
|
||||
* @retval 0 Success. Everything went fine.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int page_map_copy(size_t dest);
|
||||
|
||||
/** @brief Free a whole page map tree */
|
||||
int page_map_drop();
|
||||
|
||||
#endif
|
|
@ -57,6 +57,38 @@ inline static uint64_t rdtsc(void)
|
|||
return x;
|
||||
}
|
||||
|
||||
/** @brief Read cr3 register
|
||||
* @return cr3's value
|
||||
*/
|
||||
static inline size_t read_cr3(void) {
|
||||
size_t val;
|
||||
asm volatile("mov %%cr3, %0" : "=r"(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/** @brief Read cr2 register
|
||||
* @return cr2's value
|
||||
*/
|
||||
static inline size_t read_cr2(void) {
|
||||
size_t val;
|
||||
asm volatile("mov %%cr2, %0" : "=r"(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/** @brief Write a value into cr2 register
|
||||
* @param val The value you want to write into cr2
|
||||
*/
|
||||
static inline void write_cr2(size_t val) {
|
||||
asm volatile("mov %0, %%cr2" : : "r"(val));
|
||||
}
|
||||
|
||||
/** @brief Write a value into cr3 register
|
||||
* @param val The value you want to write into cr3
|
||||
*/
|
||||
static inline void write_cr3(size_t val) {
|
||||
asm volatile("mov %0, %%cr3" : : "r"(val));
|
||||
}
|
||||
|
||||
/** @brief Flush cache
|
||||
*
|
||||
* The wbinvd asm instruction which stands for "Write back and invalidate"
|
||||
|
@ -66,6 +98,26 @@ inline static void flush_cache(void) {
|
|||
asm volatile ("wbinvd" : : : "memory");
|
||||
}
|
||||
|
||||
/** @brief Flush Translation Lookaside Buffer
|
||||
*
|
||||
* Just reads cr3 and writes the same value back into it.
|
||||
*/
|
||||
static inline void flush_tlb(void)
|
||||
{
|
||||
size_t val = read_cr3();
|
||||
|
||||
if (val)
|
||||
write_cr3(val);
|
||||
}
|
||||
|
||||
/** @brief Flush a specific page entry in TLB
|
||||
* @param addr The (virtual) address of the page to flush
|
||||
*/
|
||||
static inline void tlb_flush_one_page(size_t addr)
|
||||
{
|
||||
asm volatile("invlpg (%0)" : : "r"(addr) : "memory");
|
||||
}
|
||||
|
||||
/** @brief Invalidate cache
|
||||
*
|
||||
* The invd asm instruction which invalidates cache without writing back
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
C_source := tasks.c multiboot.c vga.c gdt.c irq.c idt.c isrs.c timer.c processor.c
|
||||
C_source := tasks.c vga.c gdt.c irq.c idt.c isrs.c timer.c processor.c
|
||||
ASM_source := entry.asm string32.asm
|
||||
MODULE := arch_x86_kernel
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
;
|
||||
|
||||
; Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
; All rights reserved.
|
||||
;
|
||||
|
@ -32,19 +32,20 @@
|
|||
%include "config.inc"
|
||||
|
||||
[BITS 32]
|
||||
|
||||
; We use a special name to map this section at the begin of our kernel
|
||||
; => Multiboot needs its magic number at the begin of the kernel
|
||||
; => Multiboot expects its magic number at the beginning of the kernel.
|
||||
SECTION .mboot
|
||||
global start
|
||||
start:
|
||||
jmp stublet
|
||||
|
||||
; This part MUST be 4byte aligned, so we solve that issue using 'ALIGN 4'
|
||||
; This part MUST be 4 byte aligned, so we solve that issue using 'ALIGN 4'.
|
||||
ALIGN 4
|
||||
mboot:
|
||||
; Multiboot macros to make a few lines more readable later
|
||||
MULTIBOOT_PAGE_ALIGN equ 1<<0
|
||||
MULTIBOOT_MEMORY_INFO equ 1<<1
|
||||
MULTIBOOT_PAGE_ALIGN equ (1 << 0)
|
||||
MULTIBOOT_MEMORY_INFO equ (1 << 1)
|
||||
MULTIBOOT_HEADER_MAGIC equ 0x1BADB002
|
||||
MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
|
||||
MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
|
||||
|
@ -57,37 +58,43 @@ mboot:
|
|||
SECTION .text
|
||||
ALIGN 4
|
||||
stublet:
|
||||
; initialize stack pointer
|
||||
; Initialize stack pointer
|
||||
mov esp, boot_stack
|
||||
add esp, KERNEL_STACK_SIZE-16
|
||||
; initialize cpu features
|
||||
; Initialize CPU features
|
||||
call cpu_init
|
||||
; interpret multiboot information
|
||||
extern multiboot_init
|
||||
push ebx
|
||||
call multiboot_init
|
||||
add esp, 4
|
||||
; Interpret multiboot information
|
||||
mov DWORD [mb_info], ebx
|
||||
|
||||
; jump to the boot processors's C code
|
||||
; Jump to the boot processors's C code
|
||||
extern main
|
||||
call main
|
||||
jmp $
|
||||
|
||||
; This will set up the x86 control registers:
|
||||
; Caching and the floating point unit are enabled
|
||||
; Bootstrap page tables are loaded and page size
|
||||
; extensions (huge pages) enabled.
|
||||
global cpu_init
|
||||
cpu_init:
|
||||
mov eax, cr0
|
||||
; enable caching, disable paging and fpu emulation
|
||||
and eax, 0x1ffffffb
|
||||
; ...and turn on FPU exceptions
|
||||
or eax, 0x22
|
||||
mov cr0, eax
|
||||
; clears the current pgd entry
|
||||
xor eax, eax
|
||||
; Set CR3
|
||||
mov eax, boot_pgd
|
||||
mov cr3, eax
|
||||
; at this stage, we disable the SSE support
|
||||
mov eax, cr4
|
||||
and eax, 0xfffbf9ff
|
||||
|
||||
; Set CR4
|
||||
mov cr4, eax
|
||||
and eax, ~(1 << 9) ; disable SSE
|
||||
or eax, (1 << 4) ; enable PSE
|
||||
mov cr4, eax
|
||||
|
||||
; Set CR0
|
||||
mov eax, cr0
|
||||
and eax, ~(1 << 2) ; disable FPU emulation
|
||||
and eax, ~(1 << 30) ; enable caching
|
||||
or eax, (1 << 31) ; enable paging
|
||||
or eax, (1 << 5) ; enable FPU exceptions
|
||||
mov cr0, eax
|
||||
|
||||
ret
|
||||
|
||||
; This will set up our new segment registers. We need to do
|
||||
|
@ -108,12 +115,12 @@ gdt_flush:
|
|||
flush2:
|
||||
ret
|
||||
|
||||
; The first 32 interrupt service routines (isr) entries correspond to exceptions.
|
||||
; Some exceptions will push an error code onto the stack which is specific to
|
||||
; The first 32 interrupt service routines (ISR) entries correspond to exceptions.
|
||||
; Some exceptions will push an error code onto the stack which is specific to
|
||||
; the exception caused. To decrease the complexity, we handle this by pushing a
|
||||
; dummy error code of 0 onto the stack for any ISR that doesn't push an error
|
||||
; code already.
|
||||
;
|
||||
; Dummy error code of 0 onto the stack for any ISR that doesn't push an error
|
||||
; code already.
|
||||
;
|
||||
; ISRs are registered as "Interrupt Gate".
|
||||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
|
||||
|
@ -136,8 +143,8 @@ flush2:
|
|||
jmp common_stub
|
||||
%endmacro
|
||||
|
||||
; create isr entries, where the number after the
|
||||
; pseudo error code represents following interrupts
|
||||
; Create isr entries, where the number after the
|
||||
; pseudo error code represents following interrupts:
|
||||
; 0: Divide By Zero Exception
|
||||
; 1: Debug Exception
|
||||
; 2: Non Maskable Interrupt Exception
|
||||
|
@ -189,18 +196,16 @@ isrstub_pseudo_error 9
|
|||
jmp common_stub
|
||||
%endmacro
|
||||
|
||||
; create entries for the interrupts 0 to 23
|
||||
; Create entries for the interrupts 0 to 23
|
||||
%assign i 0
|
||||
%rep 24
|
||||
irqstub i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
extern syscall_handler
|
||||
; Used to realize system calls.
|
||||
; By entering the handler, the interrupt flag is not cleared.
|
||||
global isrsyscall
|
||||
|
||||
; used to realize system calls
|
||||
; by entering the handler, the interrupt flag is not cleared
|
||||
isrsyscall:
|
||||
cli
|
||||
push es
|
||||
|
@ -213,13 +218,14 @@ isrsyscall:
|
|||
push ebx
|
||||
push eax
|
||||
|
||||
; set kernel data segmenets
|
||||
; Set kernel data segmenets
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov eax, [esp]
|
||||
sti
|
||||
|
||||
extern syscall_handler
|
||||
call syscall_handler
|
||||
|
||||
cli
|
||||
|
@ -241,12 +247,12 @@ extern irq_handler
|
|||
extern get_current_stack
|
||||
extern finish_task_switch
|
||||
|
||||
; Create a pseudo interrupt on top of the stack.
|
||||
; Afterwards, we switch to the task with iret.
|
||||
; We already are in kernel space => no pushing of SS required.
|
||||
global switch_context
|
||||
ALIGN 4
|
||||
switch_context:
|
||||
; create on the stack a pseudo interrupt
|
||||
; afterwards, we switch to the task with iret
|
||||
; we already in kernel space => no pushing of SS required
|
||||
mov eax, [esp+4] ; on the stack is already the address to store the old esp
|
||||
pushf ; push controll register
|
||||
push DWORD 0x8 ; CS
|
||||
|
@ -263,8 +269,6 @@ ALIGN 4
|
|||
rollback:
|
||||
ret
|
||||
|
||||
extern set_kernel_stack
|
||||
|
||||
ALIGN 4
|
||||
common_stub:
|
||||
pusha
|
||||
|
@ -274,8 +278,10 @@ common_stub:
|
|||
mov es, ax
|
||||
mov ds, ax
|
||||
|
||||
; use the same handler for interrupts and exceptions
|
||||
; Use the same handler for interrupts and exceptions
|
||||
push esp
|
||||
|
||||
extern set_kernel_stack
|
||||
call irq_handler
|
||||
add esp, 4
|
||||
|
||||
|
@ -287,15 +293,15 @@ common_switch:
|
|||
call get_current_stack ; get new esp
|
||||
xchg eax, esp
|
||||
|
||||
; set task switched flag
|
||||
; Set task switched flag
|
||||
mov eax, cr0
|
||||
or eax, 8
|
||||
mov cr0, eax
|
||||
|
||||
; set esp0 in the task state segment
|
||||
; Set esp0 in the task state segment
|
||||
call set_kernel_stack
|
||||
|
||||
; call cleanup code
|
||||
; Call cleanup code
|
||||
call finish_task_switch
|
||||
|
||||
no_context_switch:
|
||||
|
@ -305,9 +311,34 @@ no_context_switch:
|
|||
add esp, 8
|
||||
iret
|
||||
|
||||
global boot_stack
|
||||
ALIGN 4096
|
||||
boot_stack:
|
||||
TIMES (KERNEL_STACK_SIZE) DB 0xcd
|
||||
SECTION .data
|
||||
|
||||
global mb_info:
|
||||
ALIGN 4
|
||||
mb_info:
|
||||
DD 0
|
||||
|
||||
ALIGN 4096
|
||||
global boot_stack
|
||||
boot_stack:
|
||||
TIMES (KERNEL_STACK_SIZE) DB 0xcd
|
||||
|
||||
; Bootstrap page tables are used during the initialization.
|
||||
; These tables do a simple identity paging and will
|
||||
; be replaced in page_init() by more fine-granular mappings.
|
||||
ALIGN 4096
|
||||
global boot_map
|
||||
boot_map:
|
||||
boot_pgd:
|
||||
DD boot_pgt + 0x103 ; PG_GLOBAL | PG_RW | PG_PRESENT
|
||||
times 1022 DD 0 ; PAGE_MAP_ENTRIES - 2
|
||||
DD boot_pgd + 0x103 ; PG_GLOBAL | PG_RW | PG_PRESENT (self-reference)
|
||||
boot_pgt:
|
||||
%assign i 0
|
||||
%rep 1024 ; PAGE_MAP_ENTRIES
|
||||
DD i | 0x203 ; PG_BOOT | PG_RW | PG_PRESENT
|
||||
%assign i i + 4096 ; PAGE_SIZE
|
||||
%endrep
|
||||
|
||||
; add some hints to the ELF file
|
||||
SECTION .note.GNU-stack noalloc noexec nowrite progbits
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <eduos/time.h>
|
||||
#include <asm/gdt.h>
|
||||
#include <asm/tss.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
gdt_ptr_t gp;
|
||||
static tss_t task_state_segment __attribute__ ((aligned (PAGE_SIZE)));
|
||||
|
|
4
arch/x86/mm/Makefile
Normal file
4
arch/x86/mm/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
C_source := page.c
|
||||
MODULE := arch_x86_mm
|
||||
|
||||
include $(TOPDIR)/Makefile.inc
|
208
arch/x86/mm/page.c
Normal file
208
arch/x86/mm/page.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 REGENTS 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.
|
||||
*/
|
||||
/**
|
||||
* This is a 32/64 bit portable paging implementation for the x86 architecture
|
||||
* using self-referenced page tables.
|
||||
* See http://www.noteblok.net/2014/06/14/bachelor/ for a detailed description.
|
||||
*/
|
||||
|
||||
#include <eduos/stdio.h>
|
||||
#include <eduos/memory.h>
|
||||
#include <eduos/errno.h>
|
||||
#include <eduos/string.h>
|
||||
#include <eduos/spinlock.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/multiboot.h>
|
||||
|
||||
/* Note that linker symbols are not variables, they have no memory
|
||||
* allocated for maintaining a value, rather their address is their value. */
|
||||
extern const void kernel_start;
|
||||
extern const void kernel_end;
|
||||
|
||||
/** Lock for kernel space page tables */
|
||||
static spinlock_t kslock = SPINLOCK_INIT;
|
||||
|
||||
/** This PGD table is initialized in entry.asm */
|
||||
extern size_t boot_map[PAGE_MAP_ENTRIES];
|
||||
|
||||
/** A self-reference enables direct access to all page tables */
|
||||
static size_t* self[PAGE_LEVELS] = {
|
||||
(size_t *) 0xFFC00000,
|
||||
(size_t *) 0xFFFFF000
|
||||
};
|
||||
|
||||
/* Addresses of child/parent tables */
|
||||
#define CHILD(map, lvl, vpn) &map[lvl-1][vpn<<PAGE_MAP_BITS]
|
||||
#define PARENT(map, lvl, vpn) &map[lvl+1][vpn>>PAGE_MAP_BITS]
|
||||
|
||||
size_t page_virt_to_phys(size_t addr)
|
||||
{
|
||||
size_t vpn = addr >> PAGE_BITS; // virtual page number
|
||||
size_t entry = self[0][vpn]; // page table entry
|
||||
size_t off = addr & ~PAGE_MASK; // offset within page
|
||||
size_t phy = entry & PAGE_MASK; // physical page frame number
|
||||
|
||||
return phy | off;
|
||||
}
|
||||
|
||||
int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits)
|
||||
{
|
||||
int lvl;
|
||||
long vpn = viraddr >> PAGE_BITS;
|
||||
long first[PAGE_LEVELS], last[PAGE_LEVELS];
|
||||
|
||||
/* Calculate index boundaries for page map traversal */
|
||||
for (lvl=0; lvl<PAGE_LEVELS; lvl++) {
|
||||
first[lvl] = (vpn ) >> (lvl * PAGE_MAP_BITS);
|
||||
last[lvl] = (vpn+npages-1) >> (lvl * PAGE_MAP_BITS);
|
||||
}
|
||||
|
||||
spinlock_lock(&kslock);
|
||||
|
||||
/* Start iterating through the entries
|
||||
* beginning at the root table (PGD or PML4) */
|
||||
for (lvl=PAGE_LEVELS-1; lvl>=0; lvl--) {
|
||||
for (vpn=first[lvl]; vpn<=last[lvl]; vpn++) {
|
||||
if (lvl) { /* PML4, PDPT, PGD */
|
||||
if (!(self[lvl][vpn] & PG_PRESENT)) {
|
||||
/* There's no table available which covers the region.
|
||||
* Therefore we need to create a new empty table. */
|
||||
size_t phyaddr = get_pages(1);
|
||||
if (BUILTIN_EXPECT(!phyaddr, 0)) {
|
||||
spinlock_unlock(&kslock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Reference the new table within its parent */
|
||||
self[lvl][vpn] = phyaddr | bits;
|
||||
|
||||
/* Fill new table with zeros */
|
||||
memset(CHILD(self, lvl, vpn), 0, PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
else { /* PGT */
|
||||
if (self[lvl][vpn] & PG_PRESENT)
|
||||
/* There's already a page mapped at this address.
|
||||
* We have to flush a single TLB entry. */
|
||||
tlb_flush_one_page(vpn << PAGE_BITS);
|
||||
|
||||
self[lvl][vpn] = phyaddr | bits;
|
||||
phyaddr += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spinlock_unlock(&kslock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Tables are freed by page_map_drop() */
|
||||
int page_unmap(size_t viraddr, size_t npages)
|
||||
{
|
||||
long vpn, start = viraddr >> PAGE_BITS;
|
||||
long end = start + npages;
|
||||
|
||||
spinlock_lock(&kslock);
|
||||
|
||||
/* Start iterating through the entries.
|
||||
* Only the PGT entries are removed. Tables remain allocated. */
|
||||
for (vpn=start; vpn<end; vpn++)
|
||||
self[0][vpn] = 0;
|
||||
|
||||
spinlock_unlock(&kslock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void page_fault_handler(struct state *s)
|
||||
{
|
||||
size_t viraddr = read_cr2();
|
||||
|
||||
kprintf("Page Fault Exception (%d) at cs:ip = %#x:%#lx, task = %u, addr = %#lx, error = %#x [ %s %s %s %s %s ]\n",
|
||||
s->int_no, s->cs, s->eip, current_task->id, viraddr, s->error,
|
||||
(s->error & 0x4) ? "user" : "supervisor",
|
||||
(s->error & 0x10) ? "instruction" : "data",
|
||||
(s->error & 0x2) ? "write" : ((s->error & 0x10) ? "fetch" : "read"),
|
||||
(s->error & 0x1) ? "protection" : "not present",
|
||||
(s->error & 0x8) ? "reserved bit" : "\b");
|
||||
|
||||
while(1) HALT;
|
||||
}
|
||||
|
||||
int page_init()
|
||||
{
|
||||
size_t addr, npages;
|
||||
int i;
|
||||
|
||||
/* Replace default pagefault handler */
|
||||
irq_uninstall_handler(14);
|
||||
irq_install_handler(14, page_fault_handler);
|
||||
|
||||
/* Map kernel */
|
||||
addr = (size_t) &kernel_start;
|
||||
npages = PAGE_FLOOR((size_t) &kernel_end - (size_t) &kernel_start) >> PAGE_BITS;
|
||||
page_map(addr, addr, npages, PG_PRESENT | PG_RW | PG_GLOBAL);
|
||||
|
||||
#ifdef CONFIG_VGA
|
||||
/* Map video memory */
|
||||
page_map(VIDEO_MEM_ADDR, VIDEO_MEM_ADDR, 1, PG_PRESENT | PG_RW | PG_PCD);
|
||||
#endif
|
||||
|
||||
/* Map multiboot information and modules */
|
||||
if (mb_info) {
|
||||
addr = (size_t) mb_info & PAGE_MASK;
|
||||
npages = PAGE_FLOOR(sizeof(*mb_info)) >> PAGE_BITS;
|
||||
page_map(addr, addr, npages, PG_PRESENT | PG_GLOBAL);
|
||||
|
||||
if (mb_info->flags & MULTIBOOT_INFO_MODS) {
|
||||
addr = mb_info->mods_addr;
|
||||
npages = PAGE_FLOOR(mb_info->mods_count*sizeof(multiboot_module_t)) >> PAGE_BITS;
|
||||
page_map(addr, addr, npages, PG_PRESENT | PG_GLOBAL);
|
||||
|
||||
multiboot_module_t* mmodule = (multiboot_module_t*) ((size_t) mb_info->mods_addr);
|
||||
for(i=0; i<mb_info->mods_count; i++) {
|
||||
addr = mmodule[i].mod_start;
|
||||
npages = PAGE_FLOOR(mmodule[i].mod_end - mmodule[i].mod_start) >> PAGE_BITS;
|
||||
page_map(addr, addr, npages, PG_PRESENT | PG_USER | PG_GLOBAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Unmap bootstrap identity paging (see entry.asm, PG_BOOT) */
|
||||
for (i=0; i<PAGE_MAP_ENTRIES; i++) {
|
||||
if (self[0][i] & PG_BOOT) {
|
||||
self[0][i] = 0;
|
||||
tlb_flush_one_page(i << PAGE_BITS);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
7
debug.gdb
Normal file
7
debug.gdb
Normal file
|
@ -0,0 +1,7 @@
|
|||
# Constant part of the script
|
||||
symbol-file eduos.sym
|
||||
target remote localhost:1234
|
||||
|
||||
set architecture i386
|
||||
break main
|
||||
continue
|
|
@ -34,15 +34,15 @@ extern "C" {
|
|||
|
||||
#define EDUOS_VERSION "0.1"
|
||||
#define MAX_TASKS 16
|
||||
#define TIMER_FREQ 100 /* in HZ */
|
||||
#define CLOCK_TICK_RATE 1193182 /* 8254 chip's internal oscillator frequency */
|
||||
#define VIDEO_MEM_ADDR 0xB8000 // the video memora address
|
||||
#define TIMER_FREQ 100 /* in HZ */
|
||||
#define CLOCK_TICK_RATE 1193182 /* 8254 chip's internal oscillator frequency */
|
||||
#define VIDEO_MEM_ADDR 0xB8000 /* the video memory address */
|
||||
#define CACHE_LINE 64
|
||||
#define KERNEL_STACK_SIZE (8*1024)
|
||||
#define PAGE_SHIFT 12
|
||||
#define KERNEL_STACK_SIZE (8<<10) /* 8 KiB */
|
||||
#define BITMAP_SIZE (128<<5) /* for 128 MiB of RAM */
|
||||
#define INT_SYSCALL 0x80
|
||||
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
|
||||
#define CONFIG_VGA
|
||||
|
||||
|
|
|
@ -25,17 +25,24 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <eduos/stddef.h>
|
||||
#include <asm/multiboot.h>
|
||||
|
||||
/*
|
||||
* eduOS is able to use Multiboot (http://www.gnu.org/software/grub/manual/multiboot/),
|
||||
* which specifies an interface between a boot loader and a operating system
|
||||
/**
|
||||
* @author Steffen Vogel
|
||||
* @file include/memory.h
|
||||
* @brief Memory related functions
|
||||
*
|
||||
* This file contains platform independent memory functions
|
||||
*/
|
||||
|
||||
multiboot_info_t* mb_info __attribute__ ((section (".data"))) = NULL;
|
||||
#ifndef __MEMORY_H__
|
||||
#define __MEMORY_H__
|
||||
|
||||
void multiboot_init(void* mb)
|
||||
{
|
||||
mb_info = (multiboot_info_t*) mb;
|
||||
}
|
||||
/** @brief Initialize the memory subsystem */
|
||||
int memory_init();
|
||||
|
||||
/** @brief Request physical page frames */
|
||||
size_t get_pages(size_t npages);
|
||||
|
||||
/** @brief release physical page frames */
|
||||
int put_pages(size_t phyaddr, size_t npages);
|
||||
|
||||
#endif
|
|
@ -46,10 +46,6 @@ extern "C" {
|
|||
/// represents a task identifier
|
||||
typedef unsigned int tid_t;
|
||||
|
||||
#define PAGE_SIZE (1 << PAGE_SHIFT)
|
||||
#define PAGE_MASK ~(PAGE_SIZE - 1)
|
||||
#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
|
||||
|
||||
struct task;
|
||||
/// pointer to the current (running) task
|
||||
extern struct task* current_task;
|
||||
|
|
|
@ -33,10 +33,14 @@
|
|||
#include <eduos/processor.h>
|
||||
#include <eduos/tasks.h>
|
||||
#include <eduos/syscall.h>
|
||||
#include <eduos/memory.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irqflags.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
/*
|
||||
/*
|
||||
* Note that linker symbols are not variables, they have no memory allocated for
|
||||
* maintaining a value, rather their address is their value.
|
||||
*/
|
||||
|
@ -47,6 +51,11 @@ extern const void bss_end;
|
|||
extern char __BUILD_DATE;
|
||||
extern char __BUILD_TIME;
|
||||
|
||||
/* Page frame counters */
|
||||
extern atomic_int32_t total_pages;
|
||||
extern atomic_int32_t total_allocated_pages;
|
||||
extern atomic_int32_t total_available_pages;
|
||||
|
||||
static void userfoo(void* arg)
|
||||
{
|
||||
char str[256];
|
||||
|
@ -96,6 +105,7 @@ static int eduos_init(void)
|
|||
timer_init();
|
||||
koutput_init();
|
||||
multitasking_init();
|
||||
memory_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -104,16 +114,18 @@ int main(void)
|
|||
{
|
||||
tid_t id1;
|
||||
tid_t id2;
|
||||
|
||||
eduos_init();
|
||||
|
||||
kprintf("This is eduOS %s Build %u, %u\n", EDUOS_VERSION, &__BUILD_DATE, &__BUILD_TIME);
|
||||
kprintf("Kernel starts at %p and ends at %p\n", &kernel_start, &kernel_end);
|
||||
|
||||
irq_enable();
|
||||
system_calibration();
|
||||
|
||||
kprintf("This is eduOS %s Build %u, %u\n", EDUOS_VERSION, &__BUILD_DATE, &__BUILD_TIME);
|
||||
kprintf("Kernel starts at %p and ends at %p\n", &kernel_start, &kernel_end);
|
||||
kprintf("Processor frequency: %u MHz\n", get_cpu_frequency());
|
||||
|
||||
kprintf("Total memory: %lu KiB\n", atomic_int32_read(&total_pages) * PAGE_SIZE / 1024);
|
||||
kprintf("Total memory available: %lu KiB\n", atomic_int32_read(&total_available_pages) * PAGE_SIZE / 1024);
|
||||
|
||||
|
||||
create_kernel_task(&id1, foo, "foo1", NORMAL_PRIO);
|
||||
create_kernel_task(&id2, wrapper, "userfoo", NORMAL_PRIO);
|
||||
|
||||
|
|
198
mm/memory.c
198
mm/memory.c
|
@ -27,8 +27,29 @@
|
|||
|
||||
#include <eduos/stddef.h>
|
||||
#include <eduos/stdlib.h>
|
||||
#include <eduos/stdio.h>
|
||||
#include <eduos/string.h>
|
||||
#include <eduos/spinlock.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/multiboot.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
/*
|
||||
* Note that linker symbols are not variables, they have no memory allocated for
|
||||
* maintaining a value, rather their address is their value.
|
||||
*/
|
||||
extern const void kernel_start;
|
||||
extern const void kernel_end;
|
||||
|
||||
static char stack[MAX_TASKS-1][KERNEL_STACK_SIZE];
|
||||
static char bitmap[BITMAP_SIZE];
|
||||
|
||||
static spinlock_t bitmap_lock = SPINLOCK_INIT;
|
||||
|
||||
atomic_int32_t total_pages = ATOMIC_INIT(0);
|
||||
atomic_int32_t total_allocated_pages = ATOMIC_INIT(0);
|
||||
atomic_int32_t total_available_pages = ATOMIC_INIT(0);
|
||||
|
||||
void* create_stack(tid_t id)
|
||||
{
|
||||
|
@ -41,3 +62,180 @@ void* create_stack(tid_t id)
|
|||
|
||||
return (void*) stack[id-1];
|
||||
}
|
||||
|
||||
inline static int page_marked(size_t i)
|
||||
{
|
||||
size_t index = i >> 3;
|
||||
size_t mod = i & 0x7;
|
||||
|
||||
return (bitmap[index] & (1 << mod));
|
||||
}
|
||||
|
||||
inline static void page_set_mark(size_t i)
|
||||
{
|
||||
size_t index = i >> 3;
|
||||
size_t mod = i & 0x7;
|
||||
|
||||
bitmap[index] = bitmap[index] | (1 << mod);
|
||||
}
|
||||
|
||||
inline static void page_clear_mark(size_t i)
|
||||
{
|
||||
size_t index = i / 8;
|
||||
size_t mod = i % 8;
|
||||
|
||||
bitmap[index] = bitmap[index] & ~(1 << mod);
|
||||
}
|
||||
|
||||
size_t get_pages(size_t npages)
|
||||
{
|
||||
size_t cnt, off;
|
||||
|
||||
if (BUILTIN_EXPECT(!npages, 0))
|
||||
return 0;
|
||||
if (BUILTIN_EXPECT(npages > atomic_int32_read(&total_available_pages), 0))
|
||||
return 0;
|
||||
|
||||
spinlock_lock(&bitmap_lock);
|
||||
|
||||
off = 1;
|
||||
while (off <= BITMAP_SIZE*8 - npages) {
|
||||
for (cnt=0; cnt<npages; cnt++) {
|
||||
if (page_marked(off+cnt))
|
||||
goto next;
|
||||
}
|
||||
|
||||
for (cnt=0; cnt<npages; cnt++) {
|
||||
page_set_mark(off+cnt);
|
||||
}
|
||||
|
||||
spinlock_unlock(&bitmap_lock);
|
||||
|
||||
atomic_int32_add(&total_allocated_pages, npages);
|
||||
atomic_int32_sub(&total_available_pages, npages);
|
||||
|
||||
return off << PAGE_BITS;
|
||||
|
||||
next: off += cnt+1;
|
||||
}
|
||||
|
||||
spinlock_unlock(&bitmap_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int put_pages(size_t phyaddr, size_t npages)
|
||||
{
|
||||
size_t i, ret = 0;
|
||||
size_t base = phyaddr >> PAGE_BITS;
|
||||
|
||||
if (BUILTIN_EXPECT(!phyaddr, 0))
|
||||
return -EINVAL;
|
||||
if (BUILTIN_EXPECT(!npages, 0))
|
||||
return -EINVAL;
|
||||
|
||||
spinlock_lock(&bitmap_lock);
|
||||
|
||||
for (i=0; i<npages; i++) {
|
||||
if (page_marked(base+i)) {
|
||||
page_clear_mark(base+i);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
|
||||
spinlock_unlock(&bitmap_lock);
|
||||
|
||||
atomic_int32_sub(&total_allocated_pages, ret);
|
||||
atomic_int32_add(&total_available_pages, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int memory_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
size_t addr;
|
||||
int ret = 0;
|
||||
|
||||
// mark all memory as used
|
||||
memset(bitmap, 0xff, BITMAP_SIZE);
|
||||
|
||||
// parse multiboot information for available memory
|
||||
if (mb_info) {
|
||||
if (mb_info->flags & MULTIBOOT_INFO_MEM_MAP) {
|
||||
multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) ((size_t) mb_info->mmap_addr);
|
||||
multiboot_memory_map_t* mmap_end = (void*) ((size_t) mb_info->mmap_addr + mb_info->mmap_length);
|
||||
|
||||
// mark available memory as free
|
||||
while (mmap < mmap_end) {
|
||||
if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE) {
|
||||
for (addr=mmap->addr; addr < mmap->addr + mmap->len; addr += PAGE_SIZE) {
|
||||
page_clear_mark(addr >> PAGE_BITS);
|
||||
atomic_int32_inc(&total_pages);
|
||||
atomic_int32_inc(&total_available_pages);
|
||||
}
|
||||
}
|
||||
mmap++;
|
||||
}
|
||||
}
|
||||
else if (mb_info->flags & MULTIBOOT_INFO_MEM) {
|
||||
size_t page;
|
||||
size_t pages_lower = mb_info->mem_lower >> 2; /* KiB to page number */
|
||||
size_t pages_upper = mb_info->mem_upper >> 2;
|
||||
|
||||
for (page=0; page<pages_lower; page++)
|
||||
page_clear_mark(page);
|
||||
|
||||
for (page=0; page<pages_upper; page++)
|
||||
page_clear_mark(page + 256); /* 1 MiB == 256 pages offset */
|
||||
|
||||
atomic_int32_add(&total_pages, pages_lower + pages_upper);
|
||||
atomic_int32_add(&total_available_pages, pages_lower + pages_upper);
|
||||
}
|
||||
else {
|
||||
kputs("Unable to initialize the memory management subsystem\n");
|
||||
while (1) HALT;
|
||||
}
|
||||
|
||||
// mark mb_info as used
|
||||
page_set_mark((size_t) mb_info >> PAGE_BITS);
|
||||
atomic_int32_inc(&total_allocated_pages);
|
||||
atomic_int32_dec(&total_available_pages);
|
||||
|
||||
|
||||
if (mb_info->flags & MULTIBOOT_INFO_MODS) {
|
||||
// mark modules list as used
|
||||
for(addr=mb_info->mods_addr; addr<mb_info->mods_addr+mb_info->mods_count*sizeof(multiboot_module_t); addr+=PAGE_SIZE) {
|
||||
page_set_mark(addr >> PAGE_BITS);
|
||||
atomic_int32_inc(&total_allocated_pages);
|
||||
atomic_int32_dec(&total_available_pages);
|
||||
}
|
||||
|
||||
// mark modules as used
|
||||
multiboot_module_t* mmodule = (multiboot_module_t*) ((size_t) mb_info->mods_addr);
|
||||
for(i=0; i<mb_info->mods_count; i++) {
|
||||
for(addr=mmodule[i].mod_start; addr<mmodule[i].mod_end; addr+=PAGE_SIZE) {
|
||||
page_set_mark(addr >> PAGE_BITS);
|
||||
atomic_int32_inc(&total_allocated_pages);
|
||||
atomic_int32_dec(&total_available_pages);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mark kernel as used
|
||||
for(addr=(size_t) &kernel_start; addr<(size_t) &kernel_end; addr+=PAGE_SIZE) {
|
||||
page_set_mark(addr >> PAGE_BITS);
|
||||
atomic_int32_inc(&total_allocated_pages);
|
||||
atomic_int32_dec(&total_available_pages);
|
||||
}
|
||||
|
||||
// enable paging and map SMP, VGA, Multiboot modules etc.
|
||||
ret = page_init();
|
||||
if (BUILTIN_EXPECT(ret, 0)) {
|
||||
kputs("Failed to initialize paging!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue