// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: Memory.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
// The above named 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.
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
// ========== Copyright Header End ============================================
* Copyright (C) 2005 Sun Microsystems, Inc.
char mem_help_string
[] = "Usage : mem -a <start addr> -s <num_of_bytes> [-cpu <id>][-dis -va]\n";
char memdump_help_string
[] = "memdump <filename> <start phys addr> <size>\n";
static int mem_cmd_action (void * , int argc
, char **argv
);
static int memdump_cmd_action (void * , int argc
, char **argv
);
bool_t
mem_dump (DR_OPAQUE pdr
);
bool_t
mem_restore (DR_OPAQUE pdr
);
// constructor , e.g. SMemory(uint64_t(0x1) << 36,48);
uint64_t _ram_size
, // mem size (bytes)
uint_t pa_bits
// number of valid bits in physical address
pa_mask
= (uint64_t(1)<<pa_bits
)-1;
for (int i
= 0; i
< SAM_NMEM_LOCKS
; i
++)
mutex_init(&locks
[i
], USYNC_THREAD
, NULL
);
DR_register ((char*)"mm1", mem_dump
, mem_restore
, (void*)this);
UI_register_cmd_2 ((char*)"mem", mem_help_string
, mem_cmd_action
, NULL
);
UI_register_cmd_2 ((char*)"memdump", memdump_help_string
, memdump_cmd_action
, NULL
);
char *file_name
, // file name for private mem file, default is NULL
int is_private
// 1 if private file, 0 if a temporary file (default)
// check if init method was called second time
if (mem
&& (mem
!= MAP_FAILED
))
int prot
= PROT_READ
|PROT_WRITE
;
// map anonymous fragment (in swap space);
// for large mem size it requires to have enough
// swap space on the host machine
if ( !SYSTEM_get_memreserve() )
// do not reserve swap space before the run
ui
->warning("You might run out of swap space with -nomemreserve option \n");
flags
|= MAP_NORESERVE
|MAP_PRIVATE
;
// swap space should be reserved before the run
mem
= (uint8_t*)mmap((char*)0,size
, prot
, flags
, -1, 0);
else // map memory image to a file
// this is an absolute path
mem_file
= strdup(file_name
);
else // file in the working directory
ui
->error("memory: cannot get current working directory\n");
mem_file
= (char *)calloc(strlen(path
)+strlen(file_name
)+16, sizeof(char));
sprintf(mem_file
,"%s/%s", path
, file_name
);
ui
->output("map ram image to %s, size = %lld bytes\n", mem_file
, size
);
// open a checkpoint mem image
int img
= open ( mem_file
, O_RDONLY
|O_LARGEFILE
);
ui
->error("memory: cannot open %s, %s\n",mem_file
, strerror(errno
));
// To avoid the mem image file to be modified during the run
// map it as a private - all changes will go to pages allocated in
if ( !SYSTEM_get_memreserve() )
// do not reserve swap space before the run
ui
->warning("You might run out of swap space with -nomemreserve option \n");
mem
= (uint8_t*)mmap((char*)0,size
, prot
, flags
|MAP_PRIVATE
, img
, 0);
else // temporary mem file
if (access(mem_file
, W_OK
)==0)
ui
->error("memory: another sim is already using %s file\n",mem_file
);
mfile
= open (mem_file
, O_RDWR
|O_CREAT
|O_LARGEFILE
|O_TRUNC
,
S_IRWXO
|S_IRWXG
|S_IRWXU
);
ui
->error("memory: cannot open %s, %s\n", mem_file
, strerror(errno
));
// write the very last byte in the mem file
// to set the effective size of the file
if (lseek(mfile
, size
-1, SEEK_SET
) < 0)
ui
->error("memory: cannot set mem file size, %s \n", strerror(errno
));
if (write(mfile
, "", 1) != 1)
ui
->error("memory: cannot write mem file, %s \n", strerror(errno
));
mem
= (uint8_t*)mmap((char*)0,size
, prot
, flags
|MAP_SHARED
, mfile
, 0);
ui
->error("memory: cannot mmap file, %s\n",strerror(errno
));
int SMemory::load_bin( const char *file
, uint64_t addr
)/*{{{*/
FILE *fp
= fopen (file
, "r");
uint64_t fsize
= s
.st_size
;
ui
->verbose("loading %s, base addr 0x%016llx, size 0x%llx\n", file
, addr
, fsize
);
// check if bin file could fit into the allocated memory
if (addr
+fsize
> get_size())
ui
->error("MEM: ram_size = 0x%llx, cannot load 0x%llx bytes \n", get_size(), fsize
);
uint8_t *start_addr
= (uint8_t *)(mem
+ ofs(addr
));
if(fread(start_addr
, sizeof(uint8_t), fsize
, fp
) == 0)
ui
->error("MEM: cannot read file %s \n", file
);
SMemory::~SMemory()/*{{{*/
if (mem
&& (mem
!= MAP_FAILED
))
///////////////////////////////////////////////////////////////
void SMemory::handle_out_of_range ( uint64_t addr
)
ui
->error("memory: address %llx exceeds mem range %llx, redirect access to address 0; bus error was not signaled \n", addr
, size
);
#elif defined(MEMORY_SPARSE)
l1shft((l2bits
+ l3bits
) - 3),// Compensate for pointer indexing, as I don't trust compiler
l2shft(l3bits
- 3), // for doing a good job on the index computation code
l1size((1 << l1bits
) << 3),
l2size((1 << l2bits
) << 3),
l1mask(((1 << l1bits
) - 1) << 3),
l2mask(((1 << l2bits
) - 1) << 3),
l3mask(((1 << l3bits
) - 1))
pa_mask
= (uint64_t(1)<<pa_bits
)-1;
memset(uninit_page
,0,512);
l1
= (uint8_t***)calloc(l1size
, sizeof(uint8_t));
for (int i
= 0; i
< SAM_NMEM_LOCKS
; i
++)
mutex_init(&locks
[i
], USYNC_THREAD
, NULL
);
mutex_init(&l2_lock
, USYNC_THREAD
, NULL
);
mutex_init(&l3_lock
, USYNC_THREAD
, NULL
);
DR_register ((char*)"mm1", mem_dump
, mem_restore
, (void*)this);
UI_register_cmd_2 ((char*)"mem", mem_help_string
, mem_cmd_action
, NULL
);
UI_register_cmd_2 ((char*)"memdump", memdump_help_string
, memdump_cmd_action
, NULL
);
SMemory::~SMemory()/*{{{*/
// memory object is constructed only once and
// cannot be reconfigured during the run;
// rely on the system to free up all allocated memory on exit();
/* normally we would need to
* remove sparse mem tables
for (int i1
=0; i1
< (1 << l1bits
); i1
++)
for (int i2
=0; i2
< (1 <<l2bits
); i2
++)
// it maybe mmaped to a file;
// if some random value is passed to free(),
// the results are undefined.
MappedFileEntry
*next
= mlist
->next
;
////////////////////////////////////////////////////////////////
int SMemory::block_read(uint64_t addr
, uint8_t *tgt
, int _size
)
//for (int i=0; i<_size; i++) tgt[i] = ld8u(addr+i);
uint8_t* paddr
= get_st_ptr (addr
); // page allocate
uint64_t offset
= addr
& l3mask
;
uint64_t pagebytes
= l3size
- offset
;
uint64_t nb
= (_size
> pagebytes
) ? pagebytes
: _size
;
memcpy(tgt
, paddr
, (size_t)nb
);
} // while more bytes to copy
int SMemory::block_write(uint64_t addr
, const uint8_t *src
, int _size
)
//for (int i=0; i<_size; i++) st8(addr+i, src[i]);
uint8_t* paddr
= get_st_ptr (addr
);
uint64_t offset
= addr
& l3mask
;
uint64_t pagebytes
= l3size
- offset
;
uint64_t nb
= (_size
> pagebytes
) ? pagebytes
: _size
;
memcpy(paddr
, src
, (size_t)nb
);
} // while more bytes to copy
// construct memory mapped file entry
MappedFileEntry::MappedFileEntry
const char *file_name
, // name of the file
uint64_t saddr
// starting address
addr
= saddr
; // keep starting address
// this is an absolute path
name
= strdup(file_name
);
else // file is in working directory
ui
->error("memory: cannot get current working directory\n");
// keep absolute file name
name
= (char *)calloc(strlen(path
)+strlen(file_name
)+16, sizeof(char));
sprintf(name
,"%s/%s", path
, file_name
);
ui
->verbose("loading %s, base addr 0x%016llx, size 0x%llx\n", name
, addr
, size
);
mfile
= open ( name
, O_RDONLY
|O_LARGEFILE
);
ui
->error("memory: cannot open %s, %s\n",name
, strerror(errno
));
// map file as a private - all changes will go to pages allocated in swap space
int prot
= PROT_READ
|PROT_WRITE
;
int flags
= MAP_ALIGN
|MAP_PRIVATE
;
if ( !SYSTEM_get_memreserve() )
// do not reserve swap space before the run
ui
->warning("You might run out of swap space with -nomemreserve option \n");
mem
= (uint8_t*)mmap((char*)0,size
, prot
, flags
, mfile
, 0);
MappedFileEntry::~MappedFileEntry()
if (mem
&& (mem
!= MAP_FAILED
))
int SMemory::load_bin( const char *file
, uint64_t addr
)/*{{{*/
MappedFileEntry
*mm_entry
= new MappedFileEntry(file
, addr
);
if (!mm_entry
->is_valid() || !this->map(mm_entry
))
ui
->error("cannot load %s, base addr 0x%016llx\n", file
, addr
);
// map page from the mmaped file
uint64_t paddr
, // page address
uint8_t *maddr
// page address in the mmapped file
// look up the entry in the tables where paddr suppose to reside
uint8_t*** o1
= (uint8_t***)((char*)l1
+ ((paddr
>> l1shft
) & l1mask
) );
l2
= *o1
= (uint8_t**)calloc(l2size
,sizeof(uint8_t));
ui
->error("\nMEM: Run out of memory, exit...\n");
uint8_t** o2
= (uint8_t**)((char*)l2
+ ((paddr
>> l2shft
) & l2mask
));
if (l3
== 0) // map the page
else // page is already allocated
// map sparse mem pages to mem mapped file
// init counters and pointers
int npages
= 0; // page counter
uint64_t start_addr
= entry
->addr
;
uint64_t addr
= start_addr
;
uint64_t fsize
= entry
->size
;
uint8_t *faddr
= entry
->mem
;
uint64_t offset
= addr
& l3mask
;
uint64_t pagebytes
= l3size
- offset
;
// number of bytes that should be on the same sparse mem page
uint64_t nb
= (fsize
> pagebytes
) ? pagebytes
: fsize
;
// if this address range doesn't fit exactly to the sparse mem page
// and can't be memory mapped (because a previous file as been
// mapped to this range), just allocate space with get_st_ptr and
if (nb
!= l3size
|| !map_page(addr
, faddr
))
// make a copy of this page
uint8_t* paddr
= get_st_ptr (addr
);
// seek to the beginning of the "page" to copy
if (lseek(entry
->mfile
, foff
, SEEK_SET
) == -1)
ui
->error("\nMEM: can't seek to 0x%llx for file %s\n",
if (read(entry
->mfile
, paddr
, nb
) != nb
)
ui
->error("\nMEM: can't read 0x%llx bytes from file %s\n",
} // while something left in the file
#endif // end MEMORY_SPARSE
enum { BUFFER_SIZE
= 512 };
static char buffer
[BUFFER_SIZE
];
// use st64_nl, common for all mem models
int SMemory::load( const char* mem_image_filename
)/*{{{*/
const char* separ
= " \t\n";
FILE* image
= fopen(mem_image_filename
,"r");
ui
->error("MEM: No such mem image file found.");
while (fgets(buffer
,BUFFER_SIZE
,image
))
addr
= strtoull(buffer
+1,0,16);
else if (isxdigit(buffer
[0]))
char* token
= strtok(buffer
,separ
);
uint64_t length
= strlen(token
);
uint64_t data
= strtoull(token
,0,16);
while ((token
= strtok(0,separ
)));
uint32_t data
= uint32_t(strtoul(token
,0,16));
while ((token
= strtok(0,separ
)));
else if ((length
== 1) && buffer
[0] == '0')
ui
->error("A memory entry must be either 4 or 8 bytes.");
void SMemory::save( const char* filename
, uint64_t addr
, uint64_t _size
)/*{{{*/
const int PAGE_SIZE
= 1 << 13;
const int PAGE_MASK
= PAGE_SIZE
- 1;
FILE* image
= fopen(filename
,"w");
uint8_t *buf8
= (uint8_t *)malloc(PAGE_SIZE
);
if ((addr
& PAGE_MASK
) != 0)
uint64_t n
= PAGE_SIZE
- (addr
& PAGE_MASK
);
block_read(addr
, buf8
, int(n
));
while (_size
>= PAGE_SIZE
)
block_read(addr
, buf8
, PAGE_SIZE
);
fwrite(buf8
,1,PAGE_SIZE
,image
);
block_read(addr
, buf8
, _size
);
fwrite(buf8
,1,_size
,image
);
//////////////////////////////////////////////////
/// Memory object DUMP/RESTORE
//////////////////////////////////////////////////
#define DISPLAY_SIZE (0x20000000LLU) // 512M
#define THRESHOLD_512M (0x20000000LLU)
#define THRESHOLD_4G (0x100000000LLU)
#define THRESHOLD_16G (0x400000000LLU)
#define MASK_32M (0x1ffffffLLU)
#define MASK_128M (0x7ffffffLLU)
#define MASK_1G (0x3fffffffLLU)
#define MASK_4G (0xffffffffLLU)
#define MAX_ADDR (0xFFFFFFFFFFFFFFFFLLU)
extern void dump_uint32 (FILE * fp
, uint32_t val
);
extern void dump_uint64 (FILE * fp
, uint64_t val
);
extern uint64_t restore_uint64 (FILE * fp
);
////////////////////////////////////////////////////////
// restore mem from dump file
int SMemory::restore ( char *dir
)
if (DR_restore_object (dir
, (char*)"mm1"))
bool_t
mem_dump (DR_OPAQUE pdr
)
char *name
= DR_get_name (pdr
);
char *dir
= DR_get_dir ();
SMemory
*msp
= (SMemory
*) DR_get_client_data (pdr
);
return msp
->dump(dir
, name
);
///////////////////////////////////////////////////
int SMemory::dump ( char *dir
, char *name
)
uint64_t npages
= this->get_size()/DUMPSIZE
;
sprintf (fname
, "%s/%s.dmp.img", dir
, name
);
// set to false if older mm1.dmp (v4) format is needed
if ((fp
= fopen (fname
, "w")) == NULL
)
// depending on memsize mask defines progress update frequency
if (this->get_size() <= THRESHOLD_512M
) {
else if (this->get_size() <= THRESHOLD_4G
) {
else if (this->get_size() <= THRESHOLD_16G
) {
ui
->output("MEM: ram_size = 0x%llx (%lld MB), pages = 0x%lld\n",
get_size(), get_size()>>20, npages
);
for (i
= 0; i
< npages
; i
++)
if ((cur_addr
& mask
) == 0)
uint64_t paddr
= i
*DUMPSIZE
;
uint8_t *mem_page
= get_base() + paddr
;
// check if page is modified - has non-zero values;
// sparse mem files always read 0 from address that
// was never written, by default;
for (j
= 0; j
< DUMPSIZE
; j
= j
+ 8)
if (*(uint64_t *) (mem_page
+ j
) != 0) {
if (!clean
) // dump modified page
// write the page using sparse file
if ( fseek(fp
, paddr
, SEEK_SET
) < 0 )
ui
->error("MEM: cannot set page addr 0x%llx, %s \n",
dump_uint64(fp
, i
); // page number
if ( fwrite (mem_page
, DUMPSIZE
, 1, fp
) != 1 )
ui
->perror("DUMP (mm1)");
// make sure that the very last byte is written
// to set correct file size
uint64_t last_byte
= get_size() - 1;
fseek(fp
, last_byte
, SEEK_SET
);
uint8_t *plast_byte
= get_base() + last_byte
;
if ( fwrite (plast_byte
, 1, 1, fp
) != 1 )
ui
->perror("DUMP (mm1)");
ui
->output("MEM: dumped 0x%llx (modified 0x%llx) pages \n", npages
, dpages
);
/////////////////////////////////////////////
bool_t
mem_restore (DR_OPAQUE pdr
)
char *name
= DR_get_name (pdr
);
char *dir
= DR_get_rdir (pdr
);
SMemory
*msp
= (SMemory
*) DR_get_client_data (pdr
);
uint64_t npages
= msp
->get_size()/DUMPSIZE
;
sprintf (fname
, "%s/%s.dmp.img", dir
, name
);
if ( access(fname
, R_OK
) ==0 )
// restore mem image checkpoint;
// map it as a private file
ui
->output("MEM: restored 0x%llx bytes \n", msp
->get_size());
// restore from mm1.dmp file
ui
->error("MEM: cannot allocate enough space \n");
sprintf (fname
, "%s/%s.dmp", dir
, name
);
if ((fp
= fopen (fname
, "r")) == NULL
) {
size_t fsize
= ftell(fp
);
int ztotal
= (fsize
/DUMPSIZE
);
ui
->output("(dump size %lld MB):\n", (uint64_t)(fsize
>>20));;
// copy non-zero pages to mem file
page_no
= restore_uint64(fp
);
if (page_no
== MAX_ADDR
) {
offset
= page_no
*DUMPSIZE
;
if (offset
> (msp
->get_size() - DUMPSIZE
)) {
ui
->output("MEM: restore to 0x%llx is beyond memory ram_size (0x%llx), discarding...\n",
offset
, msp
->get_size());
mem
= (char*) (msp
->get_base()+offset
);
if (fread(mem
, DUMPSIZE
, 1, fp
) != 1) {
ui
->output("MEM: restore : restore state failed\n");
int pct
= (100.0*zpages
/ztotal
);
ui
->output("%d%% ", pct
);
ui
->output("MEM: restored 0x%llx pages \n", zpages
);
#elif defined(MEMORY_SPARSE)
int SMemory::dump ( char *dir
, char* name
)
char fname
[PATH_MAX
], iname
[PATH_MAX
];
sprintf (fname
, "%s/%s.dmp.img", dir
, name
);
sprintf (iname
, "%s/%s.dmp.idx", dir
, name
);
if ((fp
= fopen (fname
, "w")) == NULL
)
if ((fidx
= fopen (iname
, "w")) == NULL
)
dump_uint64(fidx
, SAM_MEM_DUMP_VERSION
);
// dump sparse mem table sizes
dump_uint64(fidx
, l1size
);
dump_uint64(fidx
, l2size
);
dump_uint64(fidx
, l3size
);
uint64_t next_page_addr
= MAX_ADDR
;
uint64_t block_size
= l3size
;
for (uint64_t i1
=0; i1
< (1 << l1bits
); i1
++)
for (uint64_t i2
=0; i2
< (1 <<l2bits
); i2
++)
uint64_t page_addr
= (i1
<< (l2bits
+ l3bits
)) | (i2
<< l3bits
);
if (l3
) // dump this page
if ( page_addr
== next_page_addr
)
// it is a next page in the block
else // start a new block
if (next_page_addr
!= MAX_ADDR
)
// current block address,offset, size
dump_uint64(fidx
, block_addr
);
dump_uint64(fidx
, block_offs
);
dump_uint64(fidx
, block_size
);
next_page_addr
= page_addr
;
if (is_dirty(l3
)) dpages
++;
if (fwrite ( (char*)l3
, l3size
, 1, fp
) != 1)
ui
->perror("DUMP (mm1)");
next_page_addr
+= l3size
;
npages
++; // number of pages
// erase previous value using back-space chars
ui
->output("%-5d MB\r",(npages
<< (l3bits
-20)) );
dump_uint64(fidx
, block_addr
);
dump_uint64(fidx
, block_offs
);
dump_uint64(fidx
, block_size
);
dump_uint64(fidx
,MAX_ADDR
);
dump_uint64(fidx
,nblocks
);
dump_uint64(fidx
,npages
);
ui
->output("\nMEM: dumped %lld pages (%lld dirty), %lld blocks \n", npages
, dpages
, nblocks
);
// restore from a checkpoint which has
// addresses and data are in one file
uint64_t restore_mem_checkpoint
// we are here because we didn't find an index file
// if this is a blaze dump, it has to be a flat-memory dump
// otherwise, it has to be a vonk sparse memory dump with addresses & data in one file
// find the first vcpu and get its vcpu type
Vcpu
* first_vcpu
= NULL
;
for (cpuid
=0; cpuid
<=g_vcpu_id_max
; cpuid
++) {
first_vcpu
= get_vcpu(cpuid
);
if (first_vcpu
!= NULL
) break;
if ((first_vcpu
->config
.cpu_type
& VCPU_IMPL_SIM_MASK
) == VCPU_IMPL_SIM_BLAZE
) {
ui
->output("MEM: mapping in blaze flat-mem dump into sparse-memory model");
// read sparse mem table sizes
uint64_t r_l1size
; read(entry
->mfile
, &r_l1size
, 8);
uint64_t r_l2size
; read(entry
->mfile
, &r_l2size
, 8);
uint64_t r_l3size
; read(entry
->mfile
, &r_l3size
, 8);
// check mem configuration
if (r_l1size
!= msp
->get_l1size() ||
r_l2size
!= msp
->get_l2size() ||
r_l3size
!= msp
->get_l3size() )
ui
->output("MEM: restore : sparse mem configuration does not match\n");
// add three table sizes and one page address 8 bytes each = 32
uint8_t *faddr
= entry
->mem
+ 32;
uint64_t page_addr
; read(entry
->mfile
, &page_addr
, 8);
if (page_addr
== MAX_ADDR
)
break; // last page was restored
// only l3size pages are written to the file
if (msp
->map_page(page_addr
, faddr
))
// page is mapped to the mem file, adjust the file pointer
if (lseek(entry
->mfile
, r_l3size
, SEEK_CUR
) < 0)
ui
->error("MEM: cannot set file pointer, %s \n", strerror(errno
));
// allocate a new mem page
uint8_t* mem_page
= msp
->get_st_ptr( page_addr
);
// read the page from the file
uint64_t restore
= read(entry
->mfile
, mem_page
, r_l3size
);
ui
->output("MEM: read 0x%llx bytes from 0x%llx block : restore failed\n", restore
, r_l3size
);
faddr
+= (r_l3size
+8); // adjust for page address 8 bytes
// restore mem from the file;
// mem pages are set to point to mmaped file;
// use lseek() to find page addresses;
// speed of mem restore could be improved if addresses are
// stored in a serate file
bool_t
mem_restore (DR_OPAQUE pdr
)
char *name
= DR_get_name (pdr
);
char *dir
= DR_get_rdir (pdr
);
sprintf (fname
, "%s/%s.dmp.img", dir
, name
);
sprintf (iname
, "%s/%s.dmp.idx", dir
, name
);
SMemory
*msp
= (SMemory
*) DR_get_client_data (pdr
);
MappedFileEntry
*mm_entry
= new MappedFileEntry(fname
);
if (!mm_entry
->is_valid())
ui
->error("mem_restore: cannot load ");
// check if a blaze-v4 style mm1.dmp file exists
sprintf(dmpfname
, "%s/%s.dmp", dir
, name
);
if (stat(dmpfname
, &statbuf
) == 0) {
"This dump contains an old, unsupported version of the\n"
"memory dump file (%s). Please contact the owner of this\n"
"checkpoint to update this file.\n\n"
"If you are the owner, you can update this file using:\n\n"
" memdump2image -i %s -o %s\n\n",
dmpfname
, dmpfname
, fname
);
// add the file to mmapped list
int fidx
= open ( iname
, O_RDONLY
|O_LARGEFILE
);
ui
->error("MEM: cannot open %s, this is an older checkpoint version.\n",iname
);
zpages
= restore_mem_checkpoint(msp
, mm_entry
);
// read sparse mem table sizes
uint64_t r_ver
; read(fidx
, &r_ver
, 8);
uint64_t r_l1size
; read(fidx
, &r_l1size
, 8);
uint64_t r_l2size
; read(fidx
, &r_l2size
, 8);
uint64_t r_l3size
; read(fidx
, &r_l3size
, 8);
// check mem configuration
if (r_l1size
!= msp
->get_l1size() ||
r_l2size
!= msp
->get_l2size() ||
r_l3size
!= msp
->get_l3size() )
ui
->error("MEM: restore : sparse mem configuration does not match\n");
// read page address, size, offset in the file
uint64_t block_addr
; read(fidx
, &block_addr
, 8);
uint64_t block_offs
; read(fidx
, &block_offs
, 8);
uint64_t block_size
; read(fidx
, &block_size
, 8);
if (block_addr
== MAX_ADDR
)
if ( nblocks
!= block_offs
|| zpages
!= block_size
)
ui
->error("MEM: read 0x%llx blocks, 0x%llx pages - there should be 0x%llx blocks, 0x%llx pages : restore failed\n",
nblocks
, zpages
, block_offs
, block_size
);
break; // last page was restored
uint64_t page_addr
= block_addr
;
uint64_t page_offs
= block_offs
;
// try to map page to the file
if ( ! msp
->map_page(page_addr
, mm_entry
->mem
+ page_offs
) )
// cannot mmap, something is already there - need to do a copy
uint8_t* mem_page
= msp
->get_st_ptr( page_addr
);
// adjust the file pointer
if (lseek(mm_entry
->mfile
, page_offs
, SEEK_SET
) < 0)
ui
->error("MEM: cannot set file pointer, %s \n", strerror(errno
));
// read the page from the file
uint64_t restore
= read(mm_entry
->mfile
, mem_page
, r_l3size
);
ui
->error("MEM: read 0x%llx bytes from 0x%llx block : restore failed\n", restore
, r_l3size
);
ui
->output("MEM: restored 0x%llx pages, 0x%llx blocks \n", zpages
, nblocks
);
/////////////////////////////////////////////
#include "cpu_interface.h"
void print_mem_cmd_usage()
ui
->output("%s", mem_help_string
);
static int mem_cmd_action (void *, int argc
, char **argv
)
ui
->output("MEM: RAM is not allocated yet \n");
if (strcmp(argv
[i
], "-dis")==0)
ui
->output( " disassemble");
else if (strcmp(argv
[i
], "-va" )==0)
ui
->output( " addr is virtual");
else if ((strcmp(argv
[i
], "-cpu")==0) && ((i
+1)<argc
))
cpuid
= int(strtol(argv
[++i
], NULL
, 0));
Vcpu
*vcpu
= get_vcpu(cpuid
);
ui
->output( "cpu id %i is unknown \n",cpuid
);
ui
->output( " for cpu[%i]",cpuid
);
else if ((strcmp(argv
[i
], "-a")==0) && ((i
+1)<argc
))
saddr
= strtoull(argv
[++i
], NULL
, 0);
else if ((strcmp(argv
[i
], "-s")==0) && ((i
+1)<argc
))
size
= strtoull(argv
[++i
], NULL
, 0);
else if (strcmp(argv
[i
], "?" )==0)
ui
->output( " saddr=0x%llx eaddr=0x%llx\n",saddr
, eaddr
);
for (;saddr
<= eaddr
; saddr
)
for (i
= 0; i
< 4; i
++, saddr
+= 8)
if (saddr
>= mm1
->get_size()-8)
ui
->output( "MEM: phys address 0x%llx is beyond RAM \n", saddr
);
if(g_vcpu
[cpuid
]->read_mem(saddr
, &val
, 8) != 0)
ui
->output( "MEM: cannot translate virtual address \n", saddr
);
v
[i
] = mm1
->SMemory::ld64(saddr
);
uint32_t opc
= uint32_t(v
[i
]>>32);
disassemble(opc
, saddr
, iline
, LSIZE
);
ui
->output ("%i : 0x%llx: 0x%lx : %s \n", cpuid
, saddr
, opc
, iline
);
opc
= uint32_t(v
[i
] & 0xffffffff);
disassemble(opc
, saddr
+4, iline
, LSIZE
);
ui
->output ("%i : 0x%llx: 0x%lx : %s \n", cpuid
, saddr
+4, opc
, iline
);
if ( i
==0 ) ui
->output ("0x%llx:", baddr
);
ui
->output (" 0x%016llx", v
[i
] );
if ( i
==3 ) ui
->output ("\n");
/////////////////////////////////////////////
void print_memdump_cmd_usage()
ui
->error ("Usage : memdump <filename> <start addr> <size> \n");
static int memdump_cmd_action (void *, int argc
, char **argv
)
ui
->error("MEM: RAM is not allocated yet \n");
print_memdump_cmd_usage();
saddr
= strtoull(argv
[2], NULL
, 0);
size
= strtoull(argv
[3], NULL
, 0);
if ((saddr
== ~0ull) || (size
==0))
if ((size
==0) || (saddr
> mm1
->get_size()) || (saddr
+size
> mm1
->get_size()))
ui
->error("memdump: incorrect start address or size \n");
print_memdump_cmd_usage();
ui
->output("writing mem image to the file: %s, start address 0x%llx, size 0x%llx ... \n",
mm1
->save(filename
, saddr
,size
);
ui
->output("----- MEMDUMP COMPLETED -----\n");
} // memdump_cmd_action()