// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: sparse_mem.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 ============================================
// this is a modular adaptation of sparse memory model in <ws>/mem.
// this approach allows for multiple sparse memory segments to co-exist
// within SAM run time image. It should even be possible to mix'n'match
// sparse segments with flat segments
SparseMemory::SparseMemory
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))
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
);
SparseMemory::~SparseMemory()/*{{{*/
for (int i1
=0; i1
< (1 << l1bits
); i1
++)
for (int i2
=0; i2
< (1 <<l2bits
); i2
++)
////////////////////////////////////////////////////////////////
int SparseMemory::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 SparseMemory::block_write(uint64_t addr
, const uint8_t *src
, int _size
)
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
enum { BUFFER_SIZE
= 512 };
static char buffer
[BUFFER_SIZE
];
int SparseMemory::load_img( const char* mem_image_filename
, uint64_t start_pa
)/*{{{*/
const char* separ
= " \t\n";
FILE* image
= fopen(mem_image_filename
,"r");
fprintf(stderr
,"No such mem image file found.");
while (fgets(buffer
,BUFFER_SIZE
,image
))
addr
= strtoull(buffer
+1,0,16);
if(addr
< start_pa
|| addr
>= start_pa
+ size
){
printf("invalid address %llx in %s\n",addr
,mem_image_filename
);
else if (isxdigit(buffer
[0]))
char* token
= strtok(buffer
,separ
);
uint64_t length
= strlen(token
);
uint64_t data
= strtoull(token
,0,16);
printf("invalid address %llx in %s\n",addr
,mem_image_filename
);
while ((token
= strtok(0,separ
)));
uint32_t data
= uint32_t(strtoul(token
,0,16));
printf("invalid address %llx in %s\n",addr
,mem_image_filename
);
while ((token
= strtok(0,separ
)));
else if ((length
== 1) && buffer
[0] == '0')
fprintf(stderr
,"A memory entry must be either 4 or 8 bytes.");
int SparseMemory::load_bin( const char *file
, uint64_t addr
)/*{{{*/
FILE *fp
= fopen (file
, "r");
uint64_t fsize
= s
.st_size
;
printf("File %s size more than allocated memory\n");
printf(" loading %s, relative base addr 0x%016llx, size 0x%llx\n", file
, addr
, fsize
);
uint64_t start_addr
= addr
;
uint8_t* paddr
= get_st_ptr (addr
);
uint64_t offset
= addr
& l3mask
;
uint64_t pagebytes
= l3size
- offset
;
uint64_t nb
= (fsize
> pagebytes
) ? pagebytes
: fsize
;
nb
= fread(paddr
, sizeof(uint8_t), nb
, fp
);
printf ("%lld bytes \n", addr
- start_addr
);
} // while more bytes to copy
int SparseMemory::load_elf(const char *filename
, uint64_t base_pa
)
/* Open the input file */
fd
= open(filename
, O_RDONLY
);
fprintf(stderr
, "load_elf <%s> not found \n", filename
);
/* Obtain the ELF descriptor */
(void) elf_version(EV_CURRENT
);
if ((elf
= elf_begin(fd
, ELF_C_READ
, NULL
)) == NULL
) {
fprintf(stderr
, "%s\n", elf_errmsg(elf_errno()));
/* Obtain the .shstrtab data buffer */
if (((ehdr
= elf64_getehdr(elf
)) == NULL
) ||
((scn
= elf_getscn(elf
, ehdr
->e_shstrndx
)) == NULL
) ||
((data
= elf_getdata(scn
, NULL
)) == NULL
)) {
fprintf(stderr
, "%s\n", elf_errmsg(elf_errno()));
/* Traverse input filename, looking for relevant sections */
for (cnt
= 1, scn
= NULL
; scn
= elf_nextscn(elf
, scn
); cnt
++) {
if ((shdr
= elf64_getshdr(scn
)) == NULL
) {
fprintf(stderr
, "%s\n", elf_errmsg(elf_errno()));
if (strcmp((char *)data
->d_buf
+shdr
->sh_name
,
load_elf64_section(shdr
, scn
, base_pa
, base_va
);
} else if (strcmp((char *)data
->d_buf
+shdr
->sh_name
,
load_elf64_section(shdr
, scn
, base_pa
, base_va
);
} else if (strcmp((char *)data
->d_buf
+shdr
->sh_name
,
load_elf64_section(shdr
, scn
, base_pa
, base_va
);
} else if (strcmp((char *)data
->d_buf
+shdr
->sh_name
,
load_elf64_section(shdr
, scn
, base_pa
, base_va
);
} else if (strcmp((char *)data
->d_buf
+shdr
->sh_name
,
load_elf64_section(shdr
, scn
, base_pa
, base_va
);
printf("elf_load file %s complete\n",filename
);
void SparseMemory::load_elf64_section(Elf64_Shdr
*shdr
, Elf_Scn
*scn
,
uint64_t base_pa
, uint64_t base_va
)
if ((data
= elf_getdata(scn
, NULL
)) == NULL
) {
fprintf(stderr
, "%s\n", elf_errmsg(elf_errno()));
offset
= shdr
->sh_addr
- base_va
;
uint8_t * d
= (uint8_t*)(data
->d_buf
);
for(int i
= 0; i
< data
->d_size
; i
++)
st8(base_pa
+ offset
+ i
, d
[i
]);
// the difference between save and dump is that save writes every byte into the
// file 'filename' where as dump writes only dirty bytes into 'filename'. Hence
// dump is easy on disk space. save can be used either as a debugging aid or to
// modify and save (eg nvram.bin) loaded files. dump is intended to be used in
// SAM dump/restore operation.
int SparseMemory::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
);
#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)
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
);
int SparseMemory::dump ( FILE * fp
)
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
);
dump_uint64(fp
, page_addr
);
if (fwrite ( (char*)l3
, l3size
, 1, fp
) != 1)
dpages
++; // number of dirty pages
npages
++; // number of pages
dump_uint64(fp
,0xFFFFFFFFFFFFFFFFLLU
);
fprintf (stderr
, "%s: dumped 0x%llx (modified 0x%llx) pages \n", name
, npages
, dpages
);
SparseMemory::restore ( FILE * fp
)
uint64_t r_l1size
= restore_uint64(fp
);
uint64_t r_l2size
= restore_uint64(fp
);
uint64_t r_l3size
= restore_uint64(fp
);
// check mem configuration
if (r_l1size
!= get_l1size() ||
r_l2size
!= get_l2size() ||
r_l3size
!= get_l3size() )
fprintf(stderr
, "%s: restore : sparse mem configuration does not match\n",name
);
uint64_t page_addr
= restore_uint64(fp
);
if (page_addr
== 0xFFFFFFFFFFFFFFFFLLU
)
break; // last page was restored
// allocate a new mem page
uint8_t* mem_page
= get_st_ptr( page_addr
);
if (fread(mem_page
, r_l3size
, 1, fp
) != 1)
fprintf(stderr
, "%s: restore : restore state failed\n",name
);
fprintf (stderr
, "%s: restored 0x%llx pages \n", name
, zpages
);