Statistics
| Branch: | Revision:

root / hw / loader.c @ 3c178e72

History | View | Annotate | Download (17.9 kB)

1
/*
2
 * QEMU Executable loader
3
 *
4
 * Copyright (c) 2006 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 *
24
 * Gunzip functionality in this file is derived from u-boot:
25
 *
26
 * (C) Copyright 2008 Semihalf
27
 *
28
 * (C) Copyright 2000-2005
29
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
30
 *
31
 * This program is free software; you can redistribute it and/or
32
 * modify it under the terms of the GNU General Public License as
33
 * published by the Free Software Foundation; either version 2 of
34
 * the License, or (at your option) any later version.
35
 *
36
 * This program is distributed in the hope that it will be useful,
37
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
39
 * GNU General Public License for more details.
40
 *
41
 * You should have received a copy of the GNU General Public License along
42
 * with this program; if not, see <http://www.gnu.org/licenses/>.
43
 */
44

    
45
#include "hw.h"
46
#include "disas.h"
47
#include "monitor.h"
48
#include "sysemu.h"
49
#include "uboot_image.h"
50
#include "loader.h"
51

    
52
#include <zlib.h>
53

    
54
/* return the size or -1 if error */
55
int get_image_size(const char *filename)
56
{
57
    int fd, size;
58
    fd = open(filename, O_RDONLY | O_BINARY);
59
    if (fd < 0)
60
        return -1;
61
    size = lseek(fd, 0, SEEK_END);
62
    close(fd);
63
    return size;
64
}
65

    
66
/* return the size or -1 if error */
67
/* deprecated, because caller does not specify buffer size! */
68
int load_image(const char *filename, uint8_t *addr)
69
{
70
    int fd, size;
71
    fd = open(filename, O_RDONLY | O_BINARY);
72
    if (fd < 0)
73
        return -1;
74
    size = lseek(fd, 0, SEEK_END);
75
    lseek(fd, 0, SEEK_SET);
76
    if (read(fd, addr, size) != size) {
77
        close(fd);
78
        return -1;
79
    }
80
    close(fd);
81
    return size;
82
}
83

    
84
/* read()-like version */
85
int read_targphys(const char *name,
86
                  int fd, target_phys_addr_t dst_addr, size_t nbytes)
87
{
88
    uint8_t *buf;
89
    size_t did;
90

    
91
    buf = qemu_malloc(nbytes);
92
    did = read(fd, buf, nbytes);
93
    if (did > 0)
94
        rom_add_blob_fixed("read", buf, did, dst_addr);
95
    qemu_free(buf);
96
    return did;
97
}
98

    
99
/* return the size or -1 if error */
100
int load_image_targphys(const char *filename,
101
                        target_phys_addr_t addr, int max_sz)
102
{
103
    int size;
104

    
105
    size = get_image_size(filename);
106
    if (size > 0)
107
        rom_add_file_fixed(filename, addr);
108
    return size;
109
}
110

    
111
void pstrcpy_targphys(const char *name, target_phys_addr_t dest, int buf_size,
112
                      const char *source)
113
{
114
    const char *nulp;
115
    char *ptr;
116

    
117
    if (buf_size <= 0) return;
118
    nulp = memchr(source, 0, buf_size);
119
    if (nulp) {
120
        rom_add_blob_fixed(name, source, (nulp - source) + 1, dest);
121
    } else {
122
        rom_add_blob_fixed(name, source, buf_size, dest);
123
        ptr = rom_ptr(dest + buf_size - 1);
124
        *ptr = 0;
125
    }
126
}
127

    
128
/* A.OUT loader */
129

    
130
struct exec
131
{
132
  uint32_t a_info;   /* Use macros N_MAGIC, etc for access */
133
  uint32_t a_text;   /* length of text, in bytes */
134
  uint32_t a_data;   /* length of data, in bytes */
135
  uint32_t a_bss;    /* length of uninitialized data area, in bytes */
136
  uint32_t a_syms;   /* length of symbol table data in file, in bytes */
137
  uint32_t a_entry;  /* start address */
138
  uint32_t a_trsize; /* length of relocation info for text, in bytes */
139
  uint32_t a_drsize; /* length of relocation info for data, in bytes */
140
};
141

    
142
static void bswap_ahdr(struct exec *e)
143
{
144
    bswap32s(&e->a_info);
145
    bswap32s(&e->a_text);
146
    bswap32s(&e->a_data);
147
    bswap32s(&e->a_bss);
148
    bswap32s(&e->a_syms);
149
    bswap32s(&e->a_entry);
150
    bswap32s(&e->a_trsize);
151
    bswap32s(&e->a_drsize);
152
}
153

    
154
#define N_MAGIC(exec) ((exec).a_info & 0xffff)
155
#define OMAGIC 0407
156
#define NMAGIC 0410
157
#define ZMAGIC 0413
158
#define QMAGIC 0314
159
#define _N_HDROFF(x) (1024 - sizeof (struct exec))
160
#define N_TXTOFF(x)                                                        \
161
    (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) :        \
162
     (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
163
#define N_TXTADDR(x, target_page_size) (N_MAGIC(x) == QMAGIC ? target_page_size : 0)
164
#define _N_SEGMENT_ROUND(x, target_page_size) (((x) + target_page_size - 1) & ~(target_page_size - 1))
165

    
166
#define _N_TXTENDADDR(x, target_page_size) (N_TXTADDR(x, target_page_size)+(x).a_text)
167

    
168
#define N_DATADDR(x, target_page_size) \
169
    (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x, target_page_size)) \
170
     : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x, target_page_size), target_page_size)))
171

    
172

    
173
int load_aout(const char *filename, target_phys_addr_t addr, int max_sz,
174
              int bswap_needed, target_phys_addr_t target_page_size)
175
{
176
    int fd, size, ret;
177
    struct exec e;
178
    uint32_t magic;
179

    
180
    fd = open(filename, O_RDONLY | O_BINARY);
181
    if (fd < 0)
182
        return -1;
183

    
184
    size = read(fd, &e, sizeof(e));
185
    if (size < 0)
186
        goto fail;
187

    
188
    if (bswap_needed) {
189
        bswap_ahdr(&e);
190
    }
191

    
192
    magic = N_MAGIC(e);
193
    switch (magic) {
194
    case ZMAGIC:
195
    case QMAGIC:
196
    case OMAGIC:
197
        if (e.a_text + e.a_data > max_sz)
198
            goto fail;
199
        lseek(fd, N_TXTOFF(e), SEEK_SET);
200
        size = read_targphys(filename, fd, addr, e.a_text + e.a_data);
201
        if (size < 0)
202
            goto fail;
203
        break;
204
    case NMAGIC:
205
        if (N_DATADDR(e, target_page_size) + e.a_data > max_sz)
206
            goto fail;
207
        lseek(fd, N_TXTOFF(e), SEEK_SET);
208
        size = read_targphys(filename, fd, addr, e.a_text);
209
        if (size < 0)
210
            goto fail;
211
        ret = read_targphys(filename, fd, addr + N_DATADDR(e, target_page_size),
212
                            e.a_data);
213
        if (ret < 0)
214
            goto fail;
215
        size += ret;
216
        break;
217
    default:
218
        goto fail;
219
    }
220
    close(fd);
221
    return size;
222
 fail:
223
    close(fd);
224
    return -1;
225
}
226

    
227
/* ELF loader */
228

    
229
static void *load_at(int fd, int offset, int size)
230
{
231
    void *ptr;
232
    if (lseek(fd, offset, SEEK_SET) < 0)
233
        return NULL;
234
    ptr = qemu_malloc(size);
235
    if (read(fd, ptr, size) != size) {
236
        qemu_free(ptr);
237
        return NULL;
238
    }
239
    return ptr;
240
}
241

    
242
#ifdef ELF_CLASS
243
#undef ELF_CLASS
244
#endif
245

    
246
#define ELF_CLASS   ELFCLASS32
247
#include "elf.h"
248

    
249
#define SZ                32
250
#define elf_word        uint32_t
251
#define elf_sword        int32_t
252
#define bswapSZs        bswap32s
253
#include "elf_ops.h"
254

    
255
#undef elfhdr
256
#undef elf_phdr
257
#undef elf_shdr
258
#undef elf_sym
259
#undef elf_note
260
#undef elf_word
261
#undef elf_sword
262
#undef bswapSZs
263
#undef SZ
264
#define elfhdr                elf64_hdr
265
#define elf_phdr        elf64_phdr
266
#define elf_note        elf64_note
267
#define elf_shdr        elf64_shdr
268
#define elf_sym                elf64_sym
269
#define elf_word        uint64_t
270
#define elf_sword        int64_t
271
#define bswapSZs        bswap64s
272
#define SZ                64
273
#include "elf_ops.h"
274

    
275
/* return < 0 if error, otherwise the number of bytes loaded in memory */
276
int load_elf(const char *filename, int64_t address_offset,
277
             uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr,
278
             int big_endian, int elf_machine, int clear_lsb)
279
{
280
    int fd, data_order, target_data_order, must_swab, ret;
281
    uint8_t e_ident[EI_NIDENT];
282

    
283
    fd = open(filename, O_RDONLY | O_BINARY);
284
    if (fd < 0) {
285
        perror(filename);
286
        return -1;
287
    }
288
    if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
289
        goto fail;
290
    if (e_ident[0] != ELFMAG0 ||
291
        e_ident[1] != ELFMAG1 ||
292
        e_ident[2] != ELFMAG2 ||
293
        e_ident[3] != ELFMAG3)
294
        goto fail;
295
#ifdef HOST_WORDS_BIGENDIAN
296
    data_order = ELFDATA2MSB;
297
#else
298
    data_order = ELFDATA2LSB;
299
#endif
300
    must_swab = data_order != e_ident[EI_DATA];
301
    if (big_endian) {
302
        target_data_order = ELFDATA2MSB;
303
    } else {
304
        target_data_order = ELFDATA2LSB;
305
    }
306

    
307
    if (target_data_order != e_ident[EI_DATA])
308
        return -1;
309

    
310
    lseek(fd, 0, SEEK_SET);
311
    if (e_ident[EI_CLASS] == ELFCLASS64) {
312
        ret = load_elf64(filename, fd, address_offset, must_swab, pentry,
313
                         lowaddr, highaddr, elf_machine, clear_lsb);
314
    } else {
315
        ret = load_elf32(filename, fd, address_offset, must_swab, pentry,
316
                         lowaddr, highaddr, elf_machine, clear_lsb);
317
    }
318

    
319
    close(fd);
320
    return ret;
321

    
322
 fail:
323
    close(fd);
324
    return -1;
325
}
326

    
327
static void bswap_uboot_header(uboot_image_header_t *hdr)
328
{
329
#ifndef HOST_WORDS_BIGENDIAN
330
    bswap32s(&hdr->ih_magic);
331
    bswap32s(&hdr->ih_hcrc);
332
    bswap32s(&hdr->ih_time);
333
    bswap32s(&hdr->ih_size);
334
    bswap32s(&hdr->ih_load);
335
    bswap32s(&hdr->ih_ep);
336
    bswap32s(&hdr->ih_dcrc);
337
#endif
338
}
339

    
340

    
341
#define ZALLOC_ALIGNMENT        16
342

    
343
static void *zalloc(void *x, unsigned items, unsigned size)
344
{
345
    void *p;
346

    
347
    size *= items;
348
    size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
349

    
350
    p = qemu_malloc(size);
351

    
352
    return (p);
353
}
354

    
355
static void zfree(void *x, void *addr)
356
{
357
    qemu_free(addr);
358
}
359

    
360

    
361
#define HEAD_CRC        2
362
#define EXTRA_FIELD        4
363
#define ORIG_NAME        8
364
#define COMMENT                0x10
365
#define RESERVED        0xe0
366

    
367
#define DEFLATED        8
368

    
369
/* This is the maximum in uboot, so if a uImage overflows this, it would
370
 * overflow on real hardware too. */
371
#define UBOOT_MAX_GUNZIP_BYTES 0x800000
372

    
373
static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
374
                      size_t srclen)
375
{
376
    z_stream s;
377
    ssize_t dstbytes;
378
    int r, i, flags;
379

    
380
    /* skip header */
381
    i = 10;
382
    flags = src[3];
383
    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
384
        puts ("Error: Bad gzipped data\n");
385
        return -1;
386
    }
387
    if ((flags & EXTRA_FIELD) != 0)
388
        i = 12 + src[10] + (src[11] << 8);
389
    if ((flags & ORIG_NAME) != 0)
390
        while (src[i++] != 0)
391
            ;
392
    if ((flags & COMMENT) != 0)
393
        while (src[i++] != 0)
394
            ;
395
    if ((flags & HEAD_CRC) != 0)
396
        i += 2;
397
    if (i >= srclen) {
398
        puts ("Error: gunzip out of data in header\n");
399
        return -1;
400
    }
401

    
402
    s.zalloc = zalloc;
403
    s.zfree = zfree;
404

    
405
    r = inflateInit2(&s, -MAX_WBITS);
406
    if (r != Z_OK) {
407
        printf ("Error: inflateInit2() returned %d\n", r);
408
        return (-1);
409
    }
410
    s.next_in = src + i;
411
    s.avail_in = srclen - i;
412
    s.next_out = dst;
413
    s.avail_out = dstlen;
414
    r = inflate(&s, Z_FINISH);
415
    if (r != Z_OK && r != Z_STREAM_END) {
416
        printf ("Error: inflate() returned %d\n", r);
417
        return -1;
418
    }
419
    dstbytes = s.next_out - (unsigned char *) dst;
420
    inflateEnd(&s);
421

    
422
    return dstbytes;
423
}
424

    
425
/* Load a U-Boot image.  */
426
int load_uimage(const char *filename, target_phys_addr_t *ep,
427
                target_phys_addr_t *loadaddr, int *is_linux)
428
{
429
    int fd;
430
    int size;
431
    uboot_image_header_t h;
432
    uboot_image_header_t *hdr = &h;
433
    uint8_t *data = NULL;
434
    int ret = -1;
435

    
436
    fd = open(filename, O_RDONLY | O_BINARY);
437
    if (fd < 0)
438
        return -1;
439

    
440
    size = read(fd, hdr, sizeof(uboot_image_header_t));
441
    if (size < 0)
442
        goto out;
443

    
444
    bswap_uboot_header(hdr);
445

    
446
    if (hdr->ih_magic != IH_MAGIC)
447
        goto out;
448

    
449
    /* TODO: Implement other image types.  */
450
    if (hdr->ih_type != IH_TYPE_KERNEL) {
451
        fprintf(stderr, "Can only load u-boot image type \"kernel\"\n");
452
        goto out;
453
    }
454

    
455
    switch (hdr->ih_comp) {
456
    case IH_COMP_NONE:
457
    case IH_COMP_GZIP:
458
        break;
459
    default:
460
        fprintf(stderr,
461
                "Unable to load u-boot images with compression type %d\n",
462
                hdr->ih_comp);
463
        goto out;
464
    }
465

    
466
    /* TODO: Check CPU type.  */
467
    if (is_linux) {
468
        if (hdr->ih_os == IH_OS_LINUX)
469
            *is_linux = 1;
470
        else
471
            *is_linux = 0;
472
    }
473

    
474
    *ep = hdr->ih_ep;
475
    data = qemu_malloc(hdr->ih_size);
476

    
477
    if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
478
        fprintf(stderr, "Error reading file\n");
479
        goto out;
480
    }
481

    
482
    if (hdr->ih_comp == IH_COMP_GZIP) {
483
        uint8_t *compressed_data;
484
        size_t max_bytes;
485
        ssize_t bytes;
486

    
487
        compressed_data = data;
488
        max_bytes = UBOOT_MAX_GUNZIP_BYTES;
489
        data = qemu_malloc(max_bytes);
490

    
491
        bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
492
        qemu_free(compressed_data);
493
        if (bytes < 0) {
494
            fprintf(stderr, "Unable to decompress gzipped image!\n");
495
            goto out;
496
        }
497
        hdr->ih_size = bytes;
498
    }
499

    
500
    rom_add_blob_fixed(filename, data, hdr->ih_size, hdr->ih_load);
501

    
502
    if (loadaddr)
503
        *loadaddr = hdr->ih_load;
504

    
505
    ret = hdr->ih_size;
506

    
507
out:
508
    if (data)
509
        qemu_free(data);
510
    close(fd);
511
    return ret;
512
}
513

    
514
/*
515
 * Functions for reboot-persistent memory regions.
516
 *  - used for vga bios and option roms.
517
 *  - also linux kernel (-kernel / -initrd).
518
 */
519

    
520
typedef struct Rom Rom;
521

    
522
struct Rom {
523
    char *name;
524
    char *path;
525
    size_t romsize;
526
    uint8_t *data;
527
    int align;
528
    int isrom;
529

    
530
    target_phys_addr_t min;
531
    target_phys_addr_t max;
532
    target_phys_addr_t addr;
533
    QTAILQ_ENTRY(Rom) next;
534
};
535

    
536
static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms);
537

    
538
static void rom_insert(Rom *rom)
539
{
540
    Rom *item;
541

    
542
    /* list is ordered by load address */
543
    QTAILQ_FOREACH(item, &roms, next) {
544
        if (rom->min >= item->min)
545
            continue;
546
        QTAILQ_INSERT_BEFORE(item, rom, next);
547
        return;
548
    }
549
    QTAILQ_INSERT_TAIL(&roms, rom, next);
550
}
551

    
552
int rom_add_file(const char *file,
553
                 target_phys_addr_t min, target_phys_addr_t max, int align)
554
{
555
    Rom *rom;
556
    int rc, fd = -1;
557

    
558
    rom = qemu_mallocz(sizeof(*rom));
559
    rom->name = qemu_strdup(file);
560
    rom->path = qemu_find_file(QEMU_FILE_TYPE_BIOS, rom->name);
561
    if (rom->path == NULL) {
562
        fprintf(stderr, "Could not find option rom '%s'\n", rom->name);
563
        goto err;
564
    }
565

    
566
    fd = open(rom->path, O_RDONLY | O_BINARY);
567
    if (fd == -1) {
568
        fprintf(stderr, "Could not open option rom '%s': %s\n",
569
                rom->path, strerror(errno));
570
        goto err;
571
    }
572

    
573
    rom->align   = align;
574
    rom->min     = min;
575
    rom->max     = max;
576
    rom->romsize = lseek(fd, 0, SEEK_END);
577
    rom->data    = qemu_mallocz(rom->romsize);
578
    lseek(fd, 0, SEEK_SET);
579
    rc = read(fd, rom->data, rom->romsize);
580
    if (rc != rom->romsize) {
581
        fprintf(stderr, "rom: file %-20s: read error: rc=%d (expected %zd)\n",
582
                rom->name, rc, rom->romsize);
583
        goto err;
584
    }
585
    close(fd);
586
    rom_insert(rom);
587
    return 0;
588

    
589
err:
590
    if (fd != -1)
591
        close(fd);
592
    qemu_free(rom->data);
593
    qemu_free(rom->path);
594
    qemu_free(rom->name);
595
    qemu_free(rom);
596
    return -1;
597
}
598

    
599
int rom_add_blob(const char *name, const void *blob, size_t len,
600
                 target_phys_addr_t min, target_phys_addr_t max, int align)
601
{
602
    Rom *rom;
603

    
604
    rom = qemu_mallocz(sizeof(*rom));
605
    rom->name    = qemu_strdup(name);
606
    rom->align   = align;
607
    rom->min     = min;
608
    rom->max     = max;
609
    rom->romsize = len;
610
    rom->data    = qemu_mallocz(rom->romsize);
611
    memcpy(rom->data, blob, len);
612
    rom_insert(rom);
613
    return 0;
614
}
615

    
616
static void rom_reset(void *unused)
617
{
618
    Rom *rom;
619

    
620
    QTAILQ_FOREACH(rom, &roms, next) {
621
        if (rom->data == NULL)
622
            continue;
623
        cpu_physical_memory_write_rom(rom->addr, rom->data, rom->romsize);
624
        if (rom->isrom) {
625
            /* rom needs to be written only once */
626
            qemu_free(rom->data);
627
            rom->data = NULL;
628
        }
629
    }
630
}
631

    
632
int rom_load_all(void)
633
{
634
    target_phys_addr_t addr = 0;
635
    int memtype;
636
    Rom *rom;
637

    
638
    QTAILQ_FOREACH(rom, &roms, next) {
639
        if (addr < rom->min)
640
            addr = rom->min;
641
        if (rom->max) {
642
            /* load address range */
643
            if (rom->align) {
644
                addr += (rom->align-1);
645
                addr &= ~(rom->align-1);
646
            }
647
            if (addr + rom->romsize > rom->max) {
648
                fprintf(stderr, "rom: out of memory (rom %s, "
649
                        "addr 0x" TARGET_FMT_plx
650
                        ", size 0x%zx, max 0x" TARGET_FMT_plx ")\n",
651
                        rom->name, addr, rom->romsize, rom->max);
652
                return -1;
653
            }
654
        } else {
655
            /* fixed address requested */
656
            if (addr != rom->min) {
657
                fprintf(stderr, "rom: requested regions overlap "
658
                        "(rom %s. free=0x" TARGET_FMT_plx
659
                        ", addr=0x" TARGET_FMT_plx ")\n",
660
                        rom->name, addr, rom->min);
661
                return -1;
662
            }
663
        }
664
        rom->addr = addr;
665
        addr += rom->romsize;
666
        memtype = cpu_get_physical_page_desc(rom->addr) & (3 << IO_MEM_SHIFT);
667
        if (memtype == IO_MEM_ROM)
668
            rom->isrom = 1;
669
    }
670
    qemu_register_reset(rom_reset, NULL);
671
    rom_reset(NULL);
672
    return 0;
673
}
674

    
675
static Rom *find_rom(target_phys_addr_t addr)
676
{
677
    Rom *rom;
678

    
679
    QTAILQ_FOREACH(rom, &roms, next) {
680
        if (rom->max)
681
            continue;
682
        if (rom->min > addr)
683
            continue;
684
        if (rom->min + rom->romsize < addr)
685
            continue;
686
        return rom;
687
    }
688
    return NULL;
689
}
690

    
691
void *rom_ptr(target_phys_addr_t addr)
692
{
693
    Rom *rom;
694

    
695
    rom = find_rom(addr);
696
    if (!rom || !rom->data)
697
        return NULL;
698
    return rom->data + (addr - rom->min);
699
}
700

    
701
void do_info_roms(Monitor *mon)
702
{
703
    Rom *rom;
704

    
705
    QTAILQ_FOREACH(rom, &roms, next) {
706
        monitor_printf(mon, "addr=" TARGET_FMT_plx
707
                       " size=0x%06zx mem=%s name=\"%s\" \n",
708
                       rom->addr, rom->romsize,
709
                       rom->isrom ? "rom" : "ram",
710
                       rom->name);
711
    }
712
}