Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / ioram / sparse_mem.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: sparse_mem.cc
4// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
6//
7// The above named program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public
9// License version 2 as published by the Free Software Foundation.
10//
11// The above named program is distributed in the hope that it will be
12// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15//
16// You should have received a copy of the GNU General Public
17// License along with this work; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19//
20// ========== Copyright Header End ============================================
21// this is a modular adaptation of sparse memory model in <ws>/mem.
22// this approach allows for multiple sparse memory segments to co-exist
23// within SAM run time image. It should even be possible to mix'n'match
24// sparse segments with flat segments
25
26#include "sparse_mem.h"
27
28SparseMemory::SparseMemory
29(
30 uint64_t ram_size,
31 uint_t _l1bits,
32 uint_t _l2bits,
33 uint_t _l3bits
34)/*{{{*/
35 :
36 l1(0),
37 l1bits(_l1bits),
38 l2bits(_l2bits),
39 l3bits(_l3bits),
40 l1shft((l2bits + l3bits) - 3),// Compensate for pointer indexing, as I don't trust compiler
41 l2shft(l3bits - 3), // for doing a good job on the index computation code
42 l1size((1 << l1bits) << 3),
43 l2size((1 << l2bits) << 3),
44 l3size( 1 << l3bits),
45 l1mask(((1 << l1bits) - 1) << 3),
46 l2mask(((1 << l2bits) - 1) << 3),
47 l3mask(((1 << l3bits) - 1))
48{
49 assert(l3bits >= 13);
50
51 size = ram_size;
52
53 memset(uninit_page,0,512);
54
55 l1 = (uint8_t***)calloc(l1size, sizeof(uint8_t));
56
57 for (int i = 0; i < SAM_NMEM_LOCKS; i++)
58 mutex_init(&locks[i], USYNC_THREAD, NULL);
59
60
61 mutex_init(&l2_lock, USYNC_THREAD, NULL);
62 mutex_init(&l3_lock, USYNC_THREAD, NULL);
63}
64
65
66SparseMemory::~SparseMemory()/*{{{*/
67{
68 for (int i1=0; i1 < (1 << l1bits); i1++)
69 {
70 uint8_t** l2 = l1[i1];
71 if (l2)
72 {
73 for (int i2=0; i2 < (1 <<l2bits); i2++)
74 {
75 uint8_t* l3= l2[i2];
76 if (l3)
77 {
78 free(l3);
79 }
80 }
81 free(l2);
82 }
83 }
84 free(l1);
85}
86
87////////////////////////////////////////////////////////////////
88//
89// mem block copy
90//
91int SparseMemory::block_read(uint64_t addr, uint8_t *tgt, int _size)
92{
93 //for (int i=0; i<_size; i++) tgt[i] = ld8u(addr+i);
94
95 while(_size)
96 {
97 uint8_t* paddr = get_st_ptr (addr); // page allocate
98 uint64_t offset = addr & l3mask;
99 uint64_t pagebytes = l3size - offset;
100
101 uint64_t nb = (_size > pagebytes) ? pagebytes : _size;
102 memcpy(tgt, paddr, (size_t)nb);
103 _size -= (int) nb;
104 addr += nb;
105 tgt += nb;
106 } // while more bytes to copy
107
108 return 0;
109}
110
111
112int SparseMemory::block_write(uint64_t addr, const uint8_t *src, int _size)
113{
114 while(_size)
115 {
116 uint8_t* paddr = get_st_ptr (addr);
117 uint64_t offset = addr & l3mask;
118 uint64_t pagebytes = l3size - offset;
119
120 uint64_t nb = (_size > pagebytes) ? pagebytes : _size;
121 memcpy(paddr, src, (size_t)nb);
122 _size -= (int) nb;
123 addr += nb;
124 src += nb;
125
126 } // while more bytes to copy
127
128
129 return 0;
130}
131
132enum { BUFFER_SIZE = 512 };
133static char buffer[BUFFER_SIZE];
134
135int SparseMemory::load_img( const char* mem_image_filename, uint64_t start_pa )/*{{{*/
136{
137 const char* separ = " \t\n";
138 FILE* image = fopen(mem_image_filename,"r");
139 uint64_t addr = 0;
140
141
142 if (!image)
143 {
144 fprintf(stderr,"No such mem image file found.");
145 return 1;
146 }
147
148 while (fgets(buffer,BUFFER_SIZE,image))
149 {
150 if (buffer[0] == '@')
151 {
152 addr = strtoull(buffer+1,0,16);
153 if(addr < start_pa || addr >= start_pa + size){
154 printf("invalid address %llx in %s\n",addr,mem_image_filename);
155 return 1;
156 }
157 addr -= start_pa;
158 }
159 else if (isxdigit(buffer[0]))
160 {
161 char* token = strtok(buffer,separ);
162 uint64_t length = strlen(token);
163
164 if (length == 16)
165 {
166 do
167 {
168 uint64_t data = strtoull(token,0,16);
169 if(addr >= size){
170 printf("invalid address %llx in %s\n",addr,mem_image_filename);
171 return 1;
172 }
173 st64_nl(addr,data);
174 addr += 8;
175 }
176 while ((token = strtok(0,separ)));
177 }
178 else if (length == 8)
179 {
180 do
181 {
182 uint32_t data = uint32_t(strtoul(token,0,16));
183 if(addr >= size){
184 printf("invalid address %llx in %s\n",addr,mem_image_filename);
185 return 1;
186 }
187 st32(addr,data);
188 addr += 4;
189 }
190 while ((token = strtok(0,separ)));
191 }
192 else if ((length == 1) && buffer[0] == '0')
193 {
194 // skip empty line
195 continue;
196 }
197 else
198 {
199 fprintf(stderr,"A memory entry must be either 4 or 8 bytes.");
200 return 1;
201 }
202 }
203 }
204
205 fclose(image);
206 return 0;
207}
208/*}}}*/
209
210
211int SparseMemory::load_bin( const char *file, uint64_t addr)/*{{{*/
212{
213 FILE *fp = fopen (file, "r");
214
215 struct stat s;
216
217 if (fp == NULL)
218 {
219 perror (file);
220 return 1;
221 }
222
223 if (stat(file, &s))
224 {
225 perror (file);
226 return 1;
227 }
228
229 uint64_t fsize = s.st_size;
230
231 if(addr + fsize > size){
232 printf("File %s size more than allocated memory\n");
233 return 1;
234 }
235
236 printf(" loading %s, relative base addr 0x%016llx, size 0x%llx\n", file, addr, fsize);
237
238
239
240 int i = 0;
241 uint64_t start_addr = addr;
242 while(fsize > 0)
243 {
244 uint8_t* paddr = get_st_ptr (addr);
245 uint64_t offset = addr & l3mask;
246 uint64_t pagebytes = l3size - offset;
247
248 uint64_t nb = (fsize > pagebytes) ? pagebytes : fsize;
249
250 nb = fread(paddr, sizeof(uint8_t), nb, fp);
251
252 fsize -= nb;
253 addr += nb;
254
255 // display the progress
256 printf (".");
257 fflush(NULL);
258 if (++i % 50 == 0)
259 printf ("%lld bytes \n", addr - start_addr);
260
261 } // while more bytes to copy
262
263 return 0;
264
265}
266
267
268int SparseMemory::load_elf(const char *filename, uint64_t base_pa)
269{
270 int fd;
271 Elf *elf;
272 Elf64_Ehdr *ehdr;
273 Elf_Scn *scn;
274 Elf64_Shdr *shdr;
275 Elf_Data *data;
276 u_int cnt;
277
278 uint64_t base_va;
279
280 /* Open the input file */
281 fd = open(filename, O_RDONLY);
282 if (fd == -1) {
283 fprintf(stderr, "load_elf <%s> not found \n", filename);
284 exit (0);
285 }
286
287 /* Obtain the ELF descriptor */
288 (void) elf_version(EV_CURRENT);
289 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
290 fprintf(stderr, "%s\n", elf_errmsg(elf_errno()));
291 exit(0);
292 }
293
294
295
296 /* Obtain the .shstrtab data buffer */
297 if (((ehdr = elf64_getehdr(elf)) == NULL) ||
298 ((scn = elf_getscn(elf, ehdr->e_shstrndx)) == NULL) ||
299 ((data = elf_getdata(scn, NULL)) == NULL)) {
300 fprintf(stderr, "%s\n", elf_errmsg(elf_errno()));
301 exit(0);
302 }
303
304 base_va = ehdr->e_entry;
305
306 /* Traverse input filename, looking for relevant sections */
307 for (cnt = 1, scn = NULL; scn = elf_nextscn(elf, scn); cnt++) {
308 if ((shdr = elf64_getshdr(scn)) == NULL) {
309 fprintf(stderr, "%s\n", elf_errmsg(elf_errno()));
310 exit(0);
311 }
312 if (strcmp((char *)data->d_buf+shdr->sh_name,
313 ".text") == 0) {
314 load_elf64_section(shdr, scn, base_pa, base_va);
315 } else if (strcmp((char *)data->d_buf+shdr->sh_name,
316 ".rodata") == 0) {
317 load_elf64_section(shdr, scn, base_pa, base_va);
318 } else if (strcmp((char *)data->d_buf+shdr->sh_name,
319 ".rodata1") == 0) {
320 load_elf64_section(shdr, scn, base_pa, base_va);
321 } else if (strcmp((char *)data->d_buf+shdr->sh_name,
322 ".data") == 0) {
323 load_elf64_section(shdr, scn, base_pa, base_va);
324 } else if (strcmp((char *)data->d_buf+shdr->sh_name,
325 ".data1") == 0) {
326 load_elf64_section(shdr, scn, base_pa, base_va);
327 }
328 }
329
330 elf_end(elf);
331 close(fd);
332
333 printf("elf_load file %s complete\n",filename);
334
335 return 0;
336}
337
338
339void SparseMemory::load_elf64_section(Elf64_Shdr *shdr, Elf_Scn *scn,
340 uint64_t base_pa, uint64_t base_va)
341{
342 uint64_t offset;
343 Elf_Data *data;
344
345 if ((data = elf_getdata(scn, NULL)) == NULL) {
346 fprintf(stderr, "%s\n", elf_errmsg(elf_errno()));
347 exit(0);
348 }
349
350 offset = shdr->sh_addr - base_va;
351 uint8_t * d = (uint8_t*)(data->d_buf);
352 for(int i = 0; i < data->d_size ; i++)
353 st8(base_pa + offset + i, d[i]);
354}
355
356
357// the difference between save and dump is that save writes every byte into the
358// file 'filename' where as dump writes only dirty bytes into 'filename'. Hence
359// dump is easy on disk space. save can be used either as a debugging aid or to
360// modify and save (eg nvram.bin) loaded files. dump is intended to be used in
361// SAM dump/restore operation.
362
363int SparseMemory::save( const char* filename, uint64_t addr, uint64_t _size )/*{{{*/
364{
365 const int PAGE_SIZE = 1 << 13;
366 const int PAGE_MASK = PAGE_SIZE - 1;
367
368 FILE* image = fopen(filename,"w");
369
370 if (!image)
371 {
372 perror (filename);
373 return 0;
374 }
375
376 if(size == 0){
377 fclose(image);
378 return 1;
379 }
380
381
382 uint8_t *buf8 = (uint8_t *)malloc(PAGE_SIZE);
383
384 if ((addr & PAGE_MASK) != 0)
385 {
386 uint64_t n = PAGE_SIZE - (addr & PAGE_MASK);
387 if (_size < n)
388 n = _size;
389
390 block_read(addr, buf8, int(n));
391 fwrite(buf8,1,n,image);
392
393 addr += n;
394 _size -= n;
395 }
396 while (_size >= PAGE_SIZE)
397 {
398 block_read(addr, buf8, PAGE_SIZE);
399 fwrite(buf8,1,PAGE_SIZE,image);
400 addr += PAGE_SIZE;
401 _size -= PAGE_SIZE;
402 }
403 if (_size)
404 {
405 block_read(addr, buf8, _size);
406 fwrite(buf8,1,_size,image);
407 }
408
409 free(buf8);
410 fclose(image);
411 return 1;
412}
413
414
415#define DUMPSIZE 1024
416#define DISPLAY_SIZE (0x20000000LLU) // 512M
417
418#define THRESHOLD_512M (0x20000000LLU)
419#define THRESHOLD_4G (0x100000000LLU)
420#define THRESHOLD_16G (0x400000000LLU)
421
422#define MASK_32M (0x1ffffffLLU)
423#define MASK_128M (0x7ffffffLLU)
424#define MASK_1G (0x3fffffffLLU)
425#define MASK_4G (0xffffffffLLU)
426
427
428extern void dump_uint32 (FILE * fp, uint32_t val);
429extern void dump_uint64 (FILE * fp, uint64_t val);
430extern uint64_t restore_uint64 (FILE * fp);
431
432
433int SparseMemory::dump ( FILE * fp )
434{
435
436 // dump page sizes
437 dump_uint64(fp, l1size);
438 dump_uint64(fp, l2size);
439 dump_uint64(fp, l3size);
440
441 uint64_t npages = 0;
442 uint64_t dpages = 0;
443
444 for (uint64_t i1=0; i1 < (1 << l1bits); i1++)
445 {
446 uint8_t** l2 = l1[i1];
447 if (l2)
448 {
449 for (uint64_t i2=0; i2 < (1 <<l2bits); i2++)
450 {
451 uint64_t page_addr = (i1 << (l2bits + l3bits)) | (i2 << l3bits);
452
453 uint8_t* l3= l2[i2];
454 if (l3)
455 {
456 // start page dump
457 fprintf (stderr,".");
458
459 // page address
460 dump_uint64(fp, page_addr);
461
462
463 // dump mem page
464 if (fwrite ( (char*)l3, l3size, 1, fp ) != 1)
465 {
466 printf("dump %s",name);
467 perror ("");
468 return 0;
469 }
470 dpages++; // number of dirty pages
471 }
472 npages++; // number of pages
473 }
474 }
475 }
476
477 // last page delimiter
478 dump_uint64(fp,0xFFFFFFFFFFFFFFFFLLU);
479 fclose (fp);
480
481 fprintf (stderr, "%s: dumped 0x%llx (modified 0x%llx) pages \n", name, npages, dpages);
482 return 1;
483
484}
485
486SparseMemory::restore ( FILE * fp)
487{
488
489 uint64_t r_l1size = restore_uint64(fp);
490 uint64_t r_l2size = restore_uint64(fp);
491 uint64_t r_l3size = restore_uint64(fp);
492
493 // check mem configuration
494 if (r_l1size != get_l1size() ||
495 r_l2size != get_l2size() ||
496 r_l3size != get_l3size() )
497 {
498 fprintf(stderr, "%s: restore : sparse mem configuration does not match\n",name);
499 return 0;
500 }
501
502 uint64_t zpages = 0;
503 while (1)
504 {
505 uint64_t page_addr = restore_uint64(fp);
506
507 if (page_addr == 0xFFFFFFFFFFFFFFFFLLU)
508 break; // last page was restored
509
510
511 // allocate a new mem page
512 uint8_t* mem_page = get_st_ptr( page_addr );
513
514 // restore page
515 if (fread(mem_page, r_l3size, 1, fp) != 1)
516 {
517 fprintf(stderr, "%s: restore : restore state failed\n",name);
518 return 0;
519 }
520 zpages++;
521 }
522
523 fprintf (stderr, "%s: restored 0x%llx pages \n", name, zpages);
524 return 1;
525}
526
527
528
529
530
531