⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vm.c

📁 一款类linux的操作系统源码
💻 C
字号:
/*  *  Roadrunner/pk *    Copyright (C) 1989-2001  Cornfed Systems, Inc. * *  The Roadrunner/pk operating system is free software; you can *  redistribute and/or modify it under the terms of the GNU General *  Public License, version 2, as published by the Free Software *  Foundation. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public *  License along with this program; if not, write to the Free *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, *  MA 02111-1307 USA * *  More information about the Roadrunner/pk operating system of *  which this file is a part is available on the World-Wide Web *  at: http://www.cornfed.com. * */#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys.h>#include <sys/mem.h>#include <sys/config.h>#include <sys/vm.h>/* Start of kernel ELF executable image loaded into memory */extern char _start;static pt_rec_t ptstk = NULL;static char *pagetablerecords;static char *pagetables;static struct vm_kmap_entry kmaptab[VM_KMAP_ENTRIES];static int nextkmaptabentry = 0;int npagetables;voidpt_push(pt_rec_t ptrec){    ptrec->next = ptstk;    ptstk = ptrec;}pt_rec_tpt_pop(){    pt_rec_t ptrec = ptstk;    if (ptrec != NULL)	ptstk = ptrec->next;    return ptrec;}voidvm_init(){    pt_rec_t ptrec;    struct vm_kmap_entry entry;    int npages, i;    pagetablerecords = mem_alloc(PAGE_TABLES * sizeof(struct pt_rec));    bzero(pagetablerecords, PAGE_TABLES * sizeof(struct pt_rec));    npages = (memsize + PAGE_SIZE - 1) / PAGE_SIZE;    npagetables = (npages / 1024) + (npages % 1024 > 0 ? 1 : 0);    pagetables = mem_alloc(PAGE_TABLES * (npagetables + 1) * PAGE_SIZE);    bzero(pagetables, PAGE_TABLES * (npagetables + 1) * PAGE_SIZE);    for (i = 0; i < PAGE_TABLES; i++) {	ptrec = (pt_rec_t) (pagetablerecords + i * sizeof(struct pt_rec));	ptrec->pd = (pt_t) (pagetables + i * (npagetables + 1) * PAGE_SIZE);	pt_push(ptrec);    }    vm_kmap_init();    entry.start = (void *) 0x1000;    entry.len = 18 * PAGE_SIZE;    entry.attr = PTE_WRITE | PTE_PRESENT;    vm_kmap_insert(&entry);    entry.start = (void *) &_start;    entry.len = kernsize;    /*     * XXX Temporary until I find a better way to do this.  The PTE_USER     * flag means that all the kernel code is readable by user processes.     * This is necessary because the first little stub of code that gets     * run by a new thread created using proc_exec() is a routine called     * proc_start(), which is in kernel memory.  I really need to figure     * a way around this problem.  The kernel code can't be damaged since     * its read-only, but we really don't want it to be read accessible     * either.     */    entry.attr = PTE_USER | PTE_PRESENT;    vm_kmap_insert(&entry);    entry.start = regiontab;    entry.len = REGIONS * sizeof(struct region);    entry.attr = PTE_WRITE | PTE_PRESENT;    vm_kmap_insert(&entry);    entry.start = pagetablerecords;    entry.len = PAGE_TABLES * sizeof(struct pt_rec);    entry.attr = PTE_WRITE | PTE_PRESENT;    vm_kmap_insert(&entry);    entry.start = pagetables;    entry.len = PAGE_TABLES * (npagetables + 1) * PAGE_SIZE;    entry.attr = PTE_WRITE | PTE_PRESENT;    vm_kmap_insert(&entry);}voidvm_kmap(pt_t pd){    vm_kmap_entry_t entry;    int i;    for (i = 0; i < VM_KMAP_ENTRIES; i++) {	entry = &(kmaptab[i]);	if (entry->start != NULL) {	    if ((u_long) entry->start < memsize)		vm_map_range(pd, entry->start, entry->len, entry->attr);	    else {#if _DEBUG		kprintf("vm_kmap: iomap entry %08x len %u\n",			entry->start, entry->len);#endif	    }	}    }}voidvm_kmap_init(){    bzero(kmaptab, VM_KMAP_ENTRIES * sizeof(struct vm_kmap_entry));}intvm_kmap_insert(vm_kmap_entry_t entry){    int firstkmaptabentry, found = 0, i;    /* Check for duplicate entry */    for (i = 0; i < VM_KMAP_ENTRIES; i++)	if (kmaptab[i].start == entry->start)	    return EKMAPDUP;    /* Search for a free kmap table entry */    for (firstkmaptabentry = nextkmaptabentry;;) {	if (kmaptab[nextkmaptabentry].start == NULL) {	    found = 1;	    break;	}	nextkmaptabentry = (nextkmaptabentry + 1) % VM_KMAP_ENTRIES;	if (nextkmaptabentry == firstkmaptabentry)	    break;    }    if (!found)	return EAGAIN;    /* Fill in kmap table entry */    kmaptab[nextkmaptabentry].start = entry->start;    kmaptab[nextkmaptabentry].len = entry->len;    kmaptab[nextkmaptabentry].attr = entry->attr;    nextkmaptabentry = (nextkmaptabentry + 1) % VM_KMAP_ENTRIES;    /* Update page tables of all existing processes */    for (i = 0; i < PROCS; i++)	if (proctab[i].state != PS_NULL) {	    if ((u_long) entry->start < memsize)		vm_map_range((pt_t) proctab[i].context.tss->cr3,			     entry->start, entry->len, entry->attr);	    else {#if _DEBUG		kprintf("vm_kmap_insert: iomap entry %08x len %u\n",			entry->start, entry->len);#endif	    }	}    return 0;}intvm_kmap_remove(vm_kmap_entry_t entry){    int kmaptabentry, i;    /* Search for corrensponding kmap table entry */    for (kmaptabentry = 0; kmaptabentry < VM_KMAP_ENTRIES; kmaptabentry++)	if (kmaptab[kmaptabentry].start == entry->start	    && kmaptab[kmaptabentry].len == entry->len)	    break;    if (kmaptabentry == VM_KMAP_ENTRIES)	return EINVAL;    /* Clear kmap table entry */    bzero(&(kmaptab[kmaptabentry]), sizeof(struct vm_kmap_entry));    /* Update page tables of all existing processes */    for (i = 0; i < PROCS; i++)	if (proctab[i].state != PS_NULL)	    vm_unmap_range((pt_t) proctab[i].context.tss->cr3,			   kmaptab[kmaptabentry].start,			   kmaptab[kmaptabentry].len);    return 0;}voidvm_map_init(pt_t pd){    u_long addr;    int i;    bzero(pd, (npagetables + 1) * PAGE_SIZE);    for (i = 0; i < npagetables; i++) {	addr = (u_long) pd + ((i + 1) * PAGE_SIZE);	pd[i] = ((pte_t) addr & 0xfffff000) |	    PTE_USER | PTE_WRITE | PTE_PRESENT;    }}__inline intvm_map(pt_t pd, void *page, u_long attr){    pt_t pt;    pte_t addr;    int pti;    if (pd == NULL || page == NULL)	return EINVAL;    pti = (int) ((u_long) page >> 22) & 0x03ff;    addr = (pte_t) pd[pti] & 0xfffff000;    pt = (pt_t) addr;    pti = (int) ((u_long) page >> 12) & 0x03ff;    addr = (pte_t) pt[pti] & 0xfffff000;    if (addr == (pte_t) page)	return 0;    if (addr != (pte_t) NULL)	return EPTDUP;    pt[pti] = ((pte_t) page & 0xfffff000) | attr;    return 0;}intvm_map_range(pt_t pd, void *start, size_t len, u_long attr){    u_long addr, end;    int result;    len = ALIGN(len, PAGE_SIZE);    addr = (u_long) start;    end = addr + len;    for (; addr < end; addr += PAGE_SIZE)	if ((result = vm_map(pd, (void *) addr, attr)) < 0)	    return result;    return 0;}__inline intvm_unmap(pt_t pd, void *page){    pt_t pt;    pte_t addr;    int pti;    if (pd == NULL || page == NULL)	return EINVAL;    pti = (int) ((u_long) page >> 22) & 0x03ff;    addr = (pte_t) pd[pti] & 0xfffff000;    pt = (pt_t) addr;    pti = (int) ((u_long) page >> 12) & 0x03ff;    addr = (pte_t) pt[pti] & 0xfffff000;    if (addr != (pte_t) page)	return EPTCORRUPT;    pt[pti] = 0;    return 0;}intvm_unmap_range(pt_t pd, void *start, size_t len){    u_long addr, end;    int result;    len = ALIGN(len, PAGE_SIZE);    addr = (u_long) start;    end = addr + len;    for (; addr < end; addr += PAGE_SIZE)	if ((result = vm_unmap(pd, (void *) addr)) < 0)	    return result;    return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -