src/Emu/Utility/System/Memory/MemorySystem.cpp

説明を見る。
00001 // 
00002 // Copyright (c) 2005-2008 Kenichi Watanabe.
00003 // Copyright (c) 2005-2008 Yasuhiro Watari.
00004 // Copyright (c) 2005-2008 Hironori Ichibayashi.
00005 // Copyright (c) 2008-2009 Kazuo Horio.
00006 // Copyright (c) 2009-2013 Naruki Kurata.
00007 // Copyright (c) 2005-2013 Ryota Shioya.
00008 // Copyright (c) 2005-2013 Masahiro Goshima.
00009 // 
00010 // This software is provided 'as-is', without any express or implied
00011 // warranty. In no event will the authors be held liable for any damages
00012 // arising from the use of this software.
00013 // 
00014 // Permission is granted to anyone to use this software for any purpose,
00015 // including commercial applications, and to alter it and redistribute it
00016 // freely, subject to the following restrictions:
00017 // 
00018 // 1. The origin of this software must not be misrepresented; you must not
00019 // claim that you wrote the original software. If you use this software
00020 // in a product, an acknowledgment in the product documentation would be
00021 // appreciated but is not required.
00022 // 
00023 // 2. Altered source versions must be plainly marked as such, and must not be
00024 // misrepresented as being the original software.
00025 // 
00026 // 3. This notice may not be removed or altered from any source
00027 // distribution.
00028 // 
00029 // 
00030 
00031 
00032 #include <pch.h>
00033 #include "Emu/Utility/System/Memory/MemorySystem.h"
00034 #include "Emu/Utility/System/Memory/MemoryUtility.h"
00035 #include "SysDeps/Endian.h"
00036 
00037 using namespace std;
00038 using namespace Onikiri;
00039 using namespace EmulatorUtility;
00040 
00041 // Enable copy-on-write scheme in the mmap implement.
00042 #define ENABLE_MEMORY_SYSTEM_COPY_ON_WRITE
00043 
00044 //
00045 // MemorySystem
00046 //
00047 MemorySystem::MemorySystem( int pid, bool bigEndian, SystemIF* simSystem ) : 
00048     m_virtualMemory( pid, bigEndian, simSystem ), 
00049     m_heapAlloc( m_virtualMemory.GetPageSize() ), 
00050     m_currentBrk(0), 
00051     m_simSystem(simSystem),
00052     m_pid(pid),
00053     m_bigEndian(bigEndian)
00054 {
00055     u64 pageSize = GetPageSize();
00056 
00057     // m0y[W
00058     u64 zeroPageAddr = RESERVED_PAGE_ZERO_FILLED * pageSize;
00059     m_virtualMemory.AssignPhysicalMemory( zeroPageAddr, VIRTUAL_MEMORY_ATTR_READ ); // Read only    
00060     m_virtualMemory.TargetMemset( zeroPageAddr, 0, pageSize );  // TargetMemset ignores page attribute.
00061 
00062     if( ( pageSize & (pageSize - 1) ) != 0 ){
00063         THROW_RUNTIME_ERROR( "The page size is not power-of-two." );
00064     }
00065 }
00066 
00067 MemorySystem::~MemorySystem()
00068 {
00069     // m0y[W
00070     u64 zeroPageAddr = RESERVED_PAGE_ZERO_FILLED * GetPageSize();
00071     m_virtualMemory.FreePhysicalMemory( zeroPageAddr );
00072 }
00073 
00074 
00075 //
00076 // 
00077 //
00078 u64 MemorySystem::GetPageSize()
00079 {
00080     return m_heapAlloc.GetPageSize();
00081 }
00082 
00083 void MemorySystem::AddHeapBlock(u64 addr, u64 size)
00084 {
00085     m_heapAlloc.AddMemoryBlock(addr, size);
00086 }
00087 
00088 void MemorySystem::SetInitialBrk(u64 initialBrk)
00089 {
00090     m_currentBrk = initialBrk;
00091 }
00092 
00093 static u64 MaskPageOffset( u64 addr, u64 pageSize )
00094 {
00095     return addr & ~(pageSize - 1);
00096 }
00097 
00098 u64 MemorySystem::Brk(u64 addr)
00099 {
00100 
00101     if (addr == 0)
00102         return m_currentBrk;
00103 
00104     u64 pageSize = GetPageSize();
00105 
00106     
00107     if( addr < m_currentBrk ){
00108         // Shrink program break and free unused memory.
00109         u64 endPageAddr = MaskPageOffset( addr, pageSize );
00110         u64 pageAddr    = MaskPageOffset( m_currentBrk, pageSize );
00111         while( pageAddr != endPageAddr ){
00112             m_virtualMemory.FreePhysicalMemory( pageAddr, pageSize );
00113             pageAddr -= pageSize;
00114         }
00115         m_currentBrk = addr;
00116         return 0;
00117     }
00118     else{
00119         // Expand program break and allocate memory.
00120         u64 endPageAddr  = MaskPageOffset( addr, pageSize );
00121         u64 pageAddr     = MaskPageOffset( m_currentBrk, pageSize ) + pageSize;
00122         //u64 zeroPageAddr = RESERVED_PAGE_ZERO_FILLED * GetPageSize();
00123 
00124         while( pageAddr <= endPageAddr ){
00125             //m_virtualMemory.SetPhysicalMemoryMapping( pageAddr, zeroPageAddr );
00126             m_virtualMemory.AssignPhysicalMemory( pageAddr, VIRTUAL_MEMORY_ATTR_READ|VIRTUAL_MEMORY_ATTR_WRITE );
00127             pageAddr += pageSize;
00128         }
00129         TargetMemset(m_currentBrk, 0, addr-m_currentBrk);
00130         m_currentBrk = addr;
00131     }
00132 
00133 
00134     return 0;
00135 }
00136 
00137 
00138 u64 MemorySystem::MMap(u64 addr, u64 length)
00139 {
00140     if (addr != 0)
00141         return (u64)-1;
00142     if (length <= 0)
00143         return (u64)-1;
00144 
00145     u64 result = m_heapAlloc.Alloc(addr, length);
00146     CheckValueOnPageBoundary( result, "mmap:address" );
00147 
00148     if (result) {
00149 #ifdef ENABLE_MEMORY_SYSTEM_COPY_ON_WRITE
00150         u64 zeroPageAddr = RESERVED_PAGE_ZERO_FILLED * GetPageSize();
00151         m_virtualMemory.SetPhysicalMemoryMapping( result, zeroPageAddr, length, VIRTUAL_MEMORY_ATTR_READ|VIRTUAL_MEMORY_ATTR_WRITE );
00152 #else
00153         m_virtualMemory.AssignPhysicalMemory(result, length, VIRTUAL_MEMORY_ATTR_READ);
00154         TargetMemset(result, 0, length);
00155 #endif
00156         return result;
00157     }
00158     else{
00159         return (u64)-1;
00160     }
00161 }
00162 
00163 u64 MemorySystem::MRemap(u64 old_addr, u64 old_size, u64 new_size, bool mayMove)
00164 {
00165     // Debug
00166     //g_env.Print( "MemorySystem::MRemap\n" );
00167 
00168     CheckValueOnPageBoundary( old_addr, "mremap:old_addr" );
00169 
00170     if (new_size <= 0)
00171         return (u64)-1;
00172     // 
00173     if (m_heapAlloc.GetBlockSize(old_addr) != old_size)
00174         return (u64)-1;
00175 
00176     u64 result = m_heapAlloc.ReAlloc(old_addr, old_size, new_size);
00177     CheckValueOnPageBoundary( result, "mremap/not move" );
00178 
00179     if (result) {
00180         CheckValueOnPageBoundary( old_size, "mremap:old_size" );
00181         CheckValueOnPageBoundary( new_size, "mremap:new_size" );
00182         if( new_size > old_size ){
00183             
00184             u64 pageMask = GetPageSize() - 1;
00185             if( ( ( result + old_size ) & pageMask) != 0 ){
00186                 // y[WECy[Wm
00187                 s64 length = (s64)new_size - (s64)(( old_size + pageMask ) & ~pageMask);
00188                 u64 addr   = result + new_size - length;
00189                 if( length > 0 ){
00190                     m_virtualMemory.AssignPhysicalMemory( addr, length, VIRTUAL_MEMORY_ATTR_READ|VIRTUAL_MEMORY_ATTR_WRITE );
00191                 }
00192             }
00193             else{
00194                 m_virtualMemory.AssignPhysicalMemory(result+old_size, new_size - old_size, VIRTUAL_MEMORY_ATTR_READ|VIRTUAL_MEMORY_ATTR_WRITE );
00195             }
00196             TargetMemset(result+old_size, 0, new_size-old_size);
00197         }
00198         else if( new_size < old_size ){
00199             u64 pageMask = GetPageSize() - 1;
00200             if( ( ( result + new_size ) & pageMask ) != 0 ){
00201                 // Vy[WECy[W
00202                 // Todo: EH
00203                 s64 length = (s64)old_size - (s64)(( new_size + pageMask ) & ~pageMask);
00204                 u64 addr   = result + old_size - length;
00205                 if( length > 0 ){
00206                     m_virtualMemory.FreePhysicalMemory( addr, length );
00207                 }
00208             }
00209             else{
00210                 m_virtualMemory.FreePhysicalMemory(result+new_size, old_size - new_size);
00211             }
00212         }
00213 
00214         return result;
00215     }
00216     else if (mayMove) {
00217         // um
00218         ASSERT(old_size < new_size, "HeapAlloc::ReAlloc Logic Error");
00219         result = m_heapAlloc.Alloc(0, new_size);
00220         CheckValueOnPageBoundary( result, "mremap/move" );
00221 
00222         if (result) {
00223             m_virtualMemory.AssignPhysicalMemory(result, new_size, VIRTUAL_MEMORY_ATTR_READ|VIRTUAL_MEMORY_ATTR_WRITE );
00224 
00225             // f[^VRs[
00226             // Note: The destructor of TargetBuffer must be called before memory pages are freed.
00227             {
00228                 TargetBuffer buf(this, old_addr, static_cast<size_t>(old_size));
00229                 MemCopyToTarget(result, buf.Get(), old_size);
00230                 TargetMemset(result+old_size, 0, new_size-old_size);
00231             }
00232             
00233             MUnmap(old_addr, old_size);
00234             return result;
00235         }
00236         else {
00237             return (u64)-1;
00238         }
00239     }
00240     else {
00241         return (u64)-1;
00242     }
00243 }
00244 
00245 int MemorySystem::MUnmap(u64 addr, u64 length)
00246 {
00247     CheckValueOnPageBoundary( addr,   "munmap:address" );
00248     CheckValueOnPageBoundary( length, "munmap:length" );
00249 
00250     if (length <= 0)
00251         return -1;
00252 
00253     if (m_heapAlloc.Free(addr, length)) {
00254         // y[WECy[W
00255         u64 pageMask = GetPageSize() - 1;
00256         if( ( ( addr + length ) & pageMask ) != 0 ){
00257             length = length & ~pageMask;
00258         }
00259         m_virtualMemory.FreePhysicalMemory( addr, length );
00260         return 0;
00261     }
00262     else
00263         return -1;
00264 }
00265 
00266 // Check whether an address is aligned on a page boundary.
00267 // An address passed to munmap/mremap must be aligned to a page boundary.
00268 void MemorySystem::CheckValueOnPageBoundary( u64 addr, const char* signature  )
00269 {
00270     if( ( addr & (GetPageSize() - 1) ) != 0 ){
00271         RUNTIME_WARNING( 
00272             "The address is not aligned to a page boundary in '%s'\n"
00273             "Address : %08x%08x",
00274             (u32)(addr >> 32), (u32)addr,
00275             signature
00276         );
00277     }
00278 }
00279 

Onikiri2に対してTue Jun 18 14:34:20 2013に生成されました。  doxygen 1.4.7