oskit_uvm_machdep_init.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 311 行
C
311 行
/* * Copyright (c) 2001 The University of Utah and the Flux Group. * All rights reserved. * * This file is part of the Flux OSKit. The OSKit is free software, also known * as "open source;" you can redistribute it and/or modify it under the terms * of the GNU General Public License (GPL), version 2, as published by the Free * Software Foundation (FSF). To explore alternate licensing terms, contact * the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271. * * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have * received a copy of the GPL along with the OSKit; see the file COPYING. If * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA. */#include <oskit/x86/pc/phys_lmm.h>#include <oskit/x86/eflags.h>#include <oskit/x86/base_vm.h>#include <oskit/x86/base_trap.h>#include <oskit/x86/pc/phys_lmm.h>#include <oskit/x86/pc/base_real.h>#include <oskit/x86/base_stack.h>#include <oskit/x86/trap.h>#include <oskit/x86/seg.h>/* these symbols are defined in seg.h but also defined in objinclude/machine/segments.h later */#undef SEL_LDT#undef ISPL#undef USERMODE#undef KERNELMODE#include <oskit/x86/base_tss.h>#include <oskit/x86/base_idt.h>#include <oskit/x86/base_gdt.h>#include <oskit/lmm.h>/* the OSKit and NetBSD define cpu_info differently */#define cpu_info oskit_cpu_info#include <oskit/x86/base_cpu.h>#undef cpu_info#include "oskit_uvm_internal.h"/* * Combine address and mode bits into a PTE. */#define create_pte(a, m) ((pt_entry_t) (((oskit_addr_t) (a)) | (m)))static void load_physmem(void);static void protect_kernel(void);/* * Initialize machine dependent part of UVM */extern voidoskit_uvm_machdep_init(){ /* * Setup variables used in UVM and NetBSD codes */ cpu_feature = base_cpuid.feature_flags; switch (base_cpuid.family) { case CPU_FAMILY_386: cpu_class = CPUCLASS_386; break; case CPU_FAMILY_486: cpu_class = CPUCLASS_486; break; case CPU_FAMILY_PENTIUM: cpu_class = CPUCLASS_586; break; case CPU_FAMILY_PENTIUM_PRO: /* FALLTHROUGH */ default: cpu_class = CPUCLASS_686; break; } /* * Do not use superpage for kernel pages. * XXX: If we have 4MB data section alignment, we can enable this again. */ base_cpuid.feature_flags &= ~CPUF_4MB_PAGES; /* * Setup the initial page table. * UVM assumes we are running on already page translation enabled. * We don't use base_paging_init() because base_paging_init() initialize * unnecessary ptes. */ if (ptab_alloc(&base_pdir_pa)) { panic("Can't allocate kernel page directory"); } if (pdir_map_range(base_pdir_pa, 0, 0, round_page(phys_mem_max), INTEL_PDE_VALID | INTEL_PDE_WRITE)) { panic("Can't direct-map physical memory"); } base_paging_load(); /* * nkpde is a pmap variable that contains the # of page directory entries * assigned for the kernel at boot time. Since base_pagint_init() * maps all physical memory, we use phys_mem_max. */ nkpde = ((long)round_page(phys_mem_max) >> PDESHIFT) + 1; /* * Map page table recursively (PTE_BASE) */ { pd_entry_t *pde = pdir_find_pde(base_pdir_pa, (oskit_addr_t)PTE_BASE); *pde = create_pte(base_pdir_pa, INTEL_PDE_VALID|INTEL_PDE_WRITE); } printf("UVM: page directory pa = %x, PTE_BASE = %p\n", base_pdir_pa, PTE_BASE); /* * Set WP bit of CR0 to protect read only user page. */ set_cr0(get_cr0() | CR0_WP); /* * Set UVM page size */ uvm_setpagesize(); /* * Load physical memory into UVM */ load_physmem(); /* * Set curpcb. */ curpcb = &oskit_uvm_user.u_pcb; /* * Initialize pmap. kva_begin is beginning of the kernel virtual * address space used for page tables, kernel malloc and so on. */ { oskit_addr_t kva_begin; kva_begin = round_page((phys_mem_max < VM_MIN_KERNEL_VIRTUAL_AVAIL ? phys_mem_max : VM_MIN_KERNEL_VIRTUAL_AVAIL)); printf("UVM: kernel VA starts at 0x%x\n", kva_begin); pmap_bootstrap(kva_begin); } /* * Set up our page fault handler */ base_trap_handlers[T_PAGE_FAULT] = oskit_uvm_pfault_handler; /* * Protect the kernel itself */ protect_kernel(); /* * Prepare double fault handler */ oskit_uvm_redzone_init();}/* * Load physical memory into UVM system */static voidload_physmem(){ oskit_addr_t seg_start, seg_end; oskit_size_t avail; oskit_size_t uvmmem; oskit_size_t alloced = 0; int search_lower1m = 0; avail = lmm_avail(&malloc_lmm, 0); /* allocate 70% of the physical memory for UVM */ uvmmem = trunc_page(avail / 10 * 7);#if 0 /* just for debugging the swap code */ if (uvmmem > 4096*1024) { uvmmem = 4096*1024; }#endif printf("UVM: available memory 0x%lx bytes\n", (long)avail); /* first scan skips the lower 1MB memory */ while (uvmmem > 0) { oskit_addr_t maxblkaddr = 0; oskit_size_t maxblksize = 0; oskit_addr_t addr; oskit_size_t size; lmm_flags_t flags; /* Find the largest free block */ for (addr = 0 ; (lmm_find_free(&malloc_lmm, &addr, &size, &flags), size != 0) ; addr = round_page(addr + size)) { XPRINTF(OSKIT_DEBUG_INIT, "UVM: found free memory 0x%lx .. 0x%lx\n", (long)addr, (long)addr + size - 1); /* ignore lower memory at the first scan */ if ((flags & LMMF_1MB) && !search_lower1m) { continue; } if (size > maxblksize) { maxblksize = size; maxblkaddr = addr; } } /* * Register physical memory into UVM */ /* If addr is not page-aligned, resize the size */ if ((maxblkaddr & PAGE_MASK)) { maxblksize -= (PAGE_SIZE - (maxblkaddr & PAGE_MASK)); } maxblksize = trunc_page(maxblksize); /* * If we could not find a free memory block or enough big memory block, * try lower 1m area. if it does not work, give up. */ if (maxblkaddr == 0 || maxblksize == 0) { if (!search_lower1m) { search_lower1m = 1; continue; } break; } if (maxblksize > uvmmem) { maxblksize = uvmmem; } seg_start = (oskit_addr_t)lmm_alloc_gen(&malloc_lmm, maxblksize, flags, PAGE_SHIFT, 0, maxblkaddr, 0xffffffff - maxblkaddr); assert(seg_start != 0); seg_end = seg_start + maxblksize; printf("UVM: loaded physical memory block [0x%x - 0x%x]\n", seg_start, seg_end - 1); uvm_page_physload(atop(seg_start), atop(seg_end), atop(seg_start), atop(seg_end), 0); uvmmem -= maxblksize; alloced += maxblksize; } /* * physmem is a variable in the NetBSD kernel. (machdep.c) */ physmem = alloced / PAGE_SIZE; printf("UVM: %d KB (%d pages) reserved\n", alloced / 1024, physmem);}static voidprotect_kernel(){ extern int enable_gdb; /* XXX */ extern char _start[], end[], start_of_data[]; vaddr_t start_addr = (unsigned) _start & ~(PAGE_SIZE - 1); /* * Map lower part of memory (ROM and I/O). */#if 0 XPRINTF(OSKIT_DEBUG_INIT, "Mapping 0x%x to 0x%x\n", 0, (int) start_addr); /* We use pmap_protect rather than uvm_map_protect for protecting the kernel space because uvm_map_protect does not work when nothing is mapped onto the map. */ pmap_protect(pmap_kernel(), 0, (vaddr_t)start_addr, VM_PROT_NONE);#endif /* * Protect the text segment as read-only. */ XPRINTF(OSKIT_DEBUG_INIT, "Protecting 0x%x to 0x%x\n", (int) start_addr, (int)start_of_data); pmap_protect(pmap_kernel(), (vaddr_t)start_addr, (vaddr_t) start_of_data, VM_PROT_READ|VM_PROT_EXECUTE| (enable_gdb ? VM_PROT_WRITE : 0)); /* * Protect the data segment as read/write. */ XPRINTF(OSKIT_DEBUG_INIT, "Protecting 0x%x to 0x%x\n", (int) start_of_data, round_page(end)); pmap_protect(pmap_kernel(), (vaddr_t) start_of_data, (vaddr_t) round_page(end), VM_PROT_READ|UVM_PROT_WRITE); /* * Protect the bottom page of the kernel stack. * XXX: should reclaim the page. */ XPRINTF(OSKIT_DEBUG_INIT, "Mapping 0x%x to 0x%x\n", (int) base_stack_start, (int) base_stack_start + PAGE_SIZE); pmap_protect(pmap_kernel(), (vaddr_t) base_stack_start, (vaddr_t) base_stack_start + PAGE_SIZE, VM_PROT_READ); /* * XXX: We do not touch the rest of memory. Maybe lmm needs write * access to them. */}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?