📄 emumem.cpp
字号:
/************************************************************************* Copyright (C) 2002 - 2007 Wei Qin See file COPYING for more information. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 GNU General Public License for more details.*************************************************************************/#include "emumem.h"#include <cassert>#include <csignal>#include <cstring>#include <cstdlib>using namespace simit;memory::memory(unsigned int def_perm, int sig){ def_perm &= MEMORY_PAGE_PERM_MASK; /* if nonempty permission, then all pages are valid by default */ if (def_perm) { for (unsigned int ii=0; ii<MEMORY_PAGE_TABLE_SIZE; ii++) page_table[ii].flag = MEMORY_PAGE_EMPTY | (def_perm << MEMORY_PAGE_PERM_SHIFT); } /* otherwise all pages are invalid by default */ else { for (unsigned int ii=0; ii<MEMORY_PAGE_TABLE_SIZE; ii++) page_table[ii].flag = MEMORY_PAGE_UNAVAIL; } page_count = 0; fault_sig = sig;}memory::~memory(){ for(unsigned int ii = 0; ii < MEMORY_PAGE_TABLE_SIZE; ii++) { memory_page_table_entry_t *pte = page_table + ii; if (page_allocated(pte)) free_page(pte); }}memory::memory(const memory& mem){ page_count = 0; fault_sig = mem.fault_sig; for(unsigned ii = 0; ii < MEMORY_PAGE_TABLE_SIZE; ii++) { page_table[ii].flag = mem.page_table[ii].flag; if (page_allocated(mem.page_table + ii)) { page_table[ii].ptr = (byte_t *)malloc(MEMORY_PAGE_SIZE); if (page_table[ii].ptr == NULL) { report_fault(MEM_NOMEMORY_FAULT, 0); return; } memcpy(page_table[ii].ptr, mem.page_table[ii].ptr + (ii << MEMORY_PAGE_SIZE_BITS), MEMORY_PAGE_SIZE); page_table[ii].ptr -= ii << MEMORY_PAGE_SIZE_BITS; page_count++; } }}void memory::reset(){ for(unsigned int ii = 0; ii < MEMORY_PAGE_TABLE_SIZE; ii++) { memory_page_table_entry_t *pte = page_table + ii; if (page_allocated(pte)) { free_page(pte); } else if (page_remapped(pte)) { reinterpret_cast<memory_ext_interface *>(pte->ptr)->reset(); } } page_count = 0;}unsigned int memory::get_page_permission(target_addr_t addr) const{ const memory_page_table_entry_t *pte = get_page(addr); unsigned int flag = pte->flag; if (flag & MEMORY_PAGE_SLOW) flag >>= MEMORY_PAGE_PERM_SHIFT; return (flag & MEMORY_PAGE_PERM_MASK);}void memory::set_page_permission(target_addr_t addr, unsigned int perm){ memory_page_table_entry_t *pte = get_page(addr); // do nothing if the page is not available if (pte->flag & MEMORY_PAGE_UNAVAIL) return; // otherwise set permission perm &= MEMORY_PAGE_PERM_MASK; if (pte->flag & MEMORY_PAGE_SLOW) { perm = perm << MEMORY_PAGE_PERM_SHIFT; pte->flag &= ~(MEMORY_PAGE_PERM_MASK << MEMORY_PAGE_PERM_SHIFT); pte->flag |= perm; } else { pte->flag &= ~MEMORY_PAGE_PERM_MASK; pte->flag |= perm; }}void memory::set_region_permission(target_addr_t addr, unsigned int size, unsigned int perm){ target_addr_t end_addr = /* avoid overflow */ (addr + size) < addr ? (target_addr_t)-1 : (addr + size); addr = align_to_page_boundary(addr); while (addr < end_addr) { set_page_permission(addr, perm); addr += MEMORY_PAGE_SIZE; if (addr == 0) break; /* no wrap-around */ }}void memory::remap_page(target_addr_t addr, memory_ext_interface *mif, unsigned int perm){ memory_page_table_entry_t *pte = get_page(addr); /* free space if the page is allocated some space */ if (page_allocated(pte)) free_page(pte); pte->flag = MEMORY_PAGE_REMAPPED; pte->flag |= (perm & MEMORY_PAGE_PERM_MASK) << MEMORY_PAGE_PERM_SHIFT; pte->ptr = reinterpret_cast<byte_t *>(mif);}void memory::unmap_page(target_addr_t addr){ memory_page_table_entry_t *pte = get_page(addr); if (pte->flag & MEMORY_PAGE_REMAPPED) pte->flag = MEMORY_PAGE_UNAVAIL;}void memory::remap_region(target_addr_t addr, unsigned int size, memory_ext_interface *mif, unsigned int perm){ target_addr_t end_addr = /* avoid overflow */ (addr + size) < addr ? (target_addr_t)-1 : (addr + size); addr = align_to_page_boundary(addr); while (addr < end_addr) { remap_page(addr, mif, perm); addr += MEMORY_PAGE_SIZE; if (addr == 0) break; /* no wrap-around */ }}void memory::unmap_region(target_addr_t addr, unsigned int size){ target_addr_t end_addr = /* avoid overflow */ (addr + size) < addr ? (target_addr_t)-1 : (addr + size); addr = align_to_page_boundary(addr); while (addr < end_addr) { unmap_page(addr); addr += MEMORY_PAGE_SIZE; if (addr == 0) break; /* no wrap-around */ }}void memory::mark_page_available(target_addr_t addr, unsigned int perm){ memory_page_table_entry_t *pte = get_page(addr); perm &= MEMORY_PAGE_PERM_MASK; /* if already available, change the permission only */ if (pte->flag & MEMORY_PAGE_UNAVAIL) pte->flag = MEMORY_PAGE_EMPTY | (perm << MEMORY_PAGE_PERM_SHIFT); else set_page_permission(addr, perm);}void memory::mark_page_unavailable(target_addr_t addr){ memory_page_table_entry_t *pte = get_page(addr); /* free space if the page is allocated some space */ if (page_allocated(pte)) free_page(pte); pte->flag = MEMORY_PAGE_UNAVAIL; }void memory::mark_region_available(target_addr_t addr, unsigned int size, unsigned int perm){ target_addr_t end_addr = /* avoid overflow */ (addr + size) < addr ? (target_addr_t)-1 : (addr + size); addr = align_to_page_boundary(addr); while (addr < end_addr) { mark_page_available(addr, perm); addr += MEMORY_PAGE_SIZE; if (addr == 0) break; /* no wrap-around */ }}void memory::mark_region_unavailable(target_addr_t addr, unsigned int size){ target_addr_t end_addr = /* avoid overflow */ (addr + size) < addr ? (target_addr_t)-1 : (addr + size); addr = align_to_page_boundary(addr); addr = align_to_page_boundary(addr); while (addr < end_addr) { mark_page_unavailable(addr); addr += MEMORY_PAGE_SIZE; if (addr == 0) break; /* no wrap-around */ }}memory_fault_t memory::allocate_page(memory_page_table_entry_t *pte){ assert(!page_allocated(pte)); pte->ptr = (byte_t *)calloc(MEMORY_PAGE_SIZE, 1); if (pte->ptr==NULL) return MEM_NOMEMORY_FAULT; // inherit the permission bits if any pte->flag = (pte->flag >> MEMORY_PAGE_PERM_SHIFT) & MEMORY_PAGE_PERM_MASK; // subtract the starting address from the ptr so that it is easier // to compute the actual address, see translate() for clue pte->ptr -= (pte - page_table) << MEMORY_PAGE_SIZE_BITS; page_count++; return MEM_NO_FAULT;}void memory::free_page(memory_page_table_entry_t *pte){ assert(page_allocated(pte)); free (pte->ptr + ((pte - page_table) << MEMORY_PAGE_SIZE_BITS)); pte->flag = MEMORY_PAGE_EMPTY | ((pte->flag & MEMORY_PAGE_PERM_MASK) << MEMORY_PAGE_PERM_SHIFT); page_count--;}memory_fault_t memory::read_block_within_page(void *buf, target_addr_t addr, unsigned int size, unsigned int *psize){ memory_fault_t fault; memory_page_table_entry_t *pte = get_page(addr); *psize = 0; if ((fault = check_page_permission(pte, MEMORY_PAGE_READABLE)) != MEM_NO_FAULT) { report_fault(fault, addr); return fault; } // I/O remapped space does not understand block operation if (pte->flag & MEMORY_PAGE_REMAPPED) { report_fault(MEM_BADADDR_FAULT, addr); return MEM_BADADDR_FAULT; } /* check if crossing page boundary */ if ((addr >> MEMORY_PAGE_SIZE_BITS) != ((addr + size - 1) >> MEMORY_PAGE_SIZE_BITS)) size = MEMORY_PAGE_SIZE - (addr & (MEMORY_PAGE_SIZE - 1)); if ((pte->flag & MEMORY_PAGE_EMPTY) && (fault = allocate_page(pte)) != MEM_NO_FAULT) { report_fault(fault, addr); return fault; } memcpy(buf, pte->ptr + addr, size); *psize = size; return MEM_NO_FAULT;}memory_fault_t memory::read_block(void *buf, target_addr_t addr, unsigned int size){ memory_fault_t ft; unsigned int sz, len = 0; /* crossing the page boundary */ while (len < size) { if ((ft = read_block_within_page(buf, addr+len, size-len, &sz)) != MEM_NO_FAULT) return ft; len += sz; buf = reinterpret_cast<byte_t *>(buf) + sz; } return MEM_NO_FAULT;}memory_fault_t memory::write_block_within_page(void *buf, target_addr_t addr, unsigned int size, unsigned int *psize){ memory_fault_t fault; memory_page_table_entry_t *pte = get_page(addr); *psize = 0; if ((fault = check_page_permission(pte, MEMORY_PAGE_WRITABLE)) != MEM_NO_FAULT) { report_fault(fault, addr); return fault; } if (pte->flag & MEMORY_PAGE_REMAPPED) { report_fault(MEM_BADADDR_FAULT, addr); return MEM_BADADDR_FAULT; } /* check if crossing page boundary */ if ((addr >> MEMORY_PAGE_SIZE_BITS) != ((addr + size - 1) >> MEMORY_PAGE_SIZE_BITS)) size = MEMORY_PAGE_SIZE - (addr & (MEMORY_PAGE_SIZE - 1)); if ((pte->flag & MEMORY_PAGE_EMPTY) && (fault = allocate_page(pte)) != MEM_NO_FAULT) { report_fault(fault, addr); return fault; } memcpy(pte->ptr + addr, buf, size); *psize = size; return MEM_NO_FAULT;}memory_fault_t memory::write_block(void *buf, target_addr_t addr, unsigned int size){ memory_fault_t ft; unsigned int sz, len = 0; /* crossing the page boundary */ while (len < size) { if ((ft = write_block_within_page(buf, addr+len, size-len, &sz)) != MEM_NO_FAULT) return ft; len += sz; buf = reinterpret_cast<byte_t *>(buf) + sz; } return MEM_NO_FAULT;}memory_fault_t memory::set_block_within_page(target_addr_t addr, byte_t value, unsigned int size, unsigned int *psize){ memory_fault_t fault; memory_page_table_entry_t *pte = get_page(addr); *psize = 0; if ((fault = check_page_permission(pte, MEMORY_PAGE_WRITABLE)) != MEM_NO_FAULT) { report_fault(fault, addr); return fault; } if (pte->flag & MEMORY_PAGE_REMAPPED) { report_fault(MEM_BADADDR_FAULT, addr); return MEM_BADADDR_FAULT; } /* check if crossing page boundary */ if ((addr >> MEMORY_PAGE_SIZE_BITS) != ((addr + size - 1) >> MEMORY_PAGE_SIZE_BITS)) size = MEMORY_PAGE_SIZE - (addr & (MEMORY_PAGE_SIZE - 1));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -