mirror of https://github.com/xqemu/xqemu.git
target-arm queue:
* use the right MMU index when handling unaligned accesses * xlnx-zynqmp: Add support for high DDR memory regions * target-arm: support QMP dump-guest-memory * ARM: virt: Don't generate RTC ACPI device when using UEFI -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJWmQ1DAAoJEDwlJe0UNgzetR0P/jMwsT03RXLCqC5RpTlvLPEP 7IXElghhpoRl1AQ7BTV+tit83hjRcEGpXN9kY6k9nVu6Gj1YWfwepl0u1HSEK/Pk OziANfbr6Yp/kz1SaBycX9ek3MHKQ49+MjO5GiGWyN9RfAAzCl60mVDbmM+uir3B kd7oiFoXjtfTiHUV5DaLUHGUUj2KyIf25kBn93uKbZwZwx19WX9KP/KduGFFHWv+ GOHg3GVsGcqNdVNWoOOVTAGq+bYg+dRmS+2le1gY52cWO/WrECbA8MIMeHAkyKbn g/dejhkdYAl3/MKBllfMpMuma4DfiDW3rpxhOURUYOwqJN0theVhYnR9z985VZVp XdmMa2/f0VbRhT9Nyrvl3OUUyiD/o+uJUu1qMGqN9sVZukIJDSbxFA06ZAQZHG62 79/lXv2BdARuITmVa5piFk6QIX8Vna/4so7OiZmuHPNfUGSreHObCWUnheXFe01Z p88tmrpNCHmNWgLa/bvnOx1OaqR3VxNYTp+g4ZrdRljL98NS0kfHqp9aCI2gCP1t 8GaWHZLEfKEosfxcCiMH0J7Civ1UCPlv784hijcSqKa8GyUJGaeA/mFD+a46o9Pc +AG1v167VYtgczUjakXKqw4z/XMvhpUZ5+mAqQ67DhAu9bm+sDM5HFFd04GJzgUJ pXqTo6MeS19ZNhqJ+P40 =CIw9 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160115' into staging target-arm queue: * use the right MMU index when handling unaligned accesses * xlnx-zynqmp: Add support for high DDR memory regions * target-arm: support QMP dump-guest-memory * ARM: virt: Don't generate RTC ACPI device when using UEFI # gpg: Signature made Fri 15 Jan 2016 15:16:19 GMT using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" * remotes/pmaydell/tags/pull-target-arm-20160115: ARM: virt: Don't generate RTC ACPI device when using UEFI target-arm: dump-guest-memory: add vfp notes for arm elf: add arm note types target-arm: dump-guest-memory: add prfpreg notes for aarch64 target-arm: support QMP dump-guest-memory dump: allow target to set the physical base dump: allow target to set the page size dump: qemunotes aren't commonly needed qapi-schema: dump-guest-memory: Improve text xlnx-zynqmp: Add support for high DDR memory regions target-arm: Use the right MMU index in arm_regime_using_lpae_format Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
5a57acb66f
131
dump.c
131
dump.c
|
@ -347,18 +347,18 @@ static void write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start,
|
|||
int64_t i;
|
||||
Error *local_err = NULL;
|
||||
|
||||
for (i = 0; i < size / TARGET_PAGE_SIZE; i++) {
|
||||
write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
|
||||
TARGET_PAGE_SIZE, &local_err);
|
||||
for (i = 0; i < size / s->dump_info.page_size; i++) {
|
||||
write_data(s, block->host_addr + start + i * s->dump_info.page_size,
|
||||
s->dump_info.page_size, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((size % TARGET_PAGE_SIZE) != 0) {
|
||||
write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
|
||||
size % TARGET_PAGE_SIZE, &local_err);
|
||||
if ((size % s->dump_info.page_size) != 0) {
|
||||
write_data(s, block->host_addr + start + i * s->dump_info.page_size,
|
||||
size % s->dump_info.page_size, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
|
@ -737,7 +737,7 @@ static void create_header32(DumpState *s, Error **errp)
|
|||
|
||||
strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE));
|
||||
dh->header_version = cpu_to_dump32(s, 6);
|
||||
block_size = TARGET_PAGE_SIZE;
|
||||
block_size = s->dump_info.page_size;
|
||||
dh->block_size = cpu_to_dump32(s, block_size);
|
||||
sub_hdr_size = sizeof(struct KdumpSubHeader32) + s->note_size;
|
||||
sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
|
||||
|
@ -775,7 +775,7 @@ static void create_header32(DumpState *s, Error **errp)
|
|||
|
||||
/* 64bit max_mapnr_64 */
|
||||
kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr);
|
||||
kh->phys_base = cpu_to_dump32(s, PHYS_BASE);
|
||||
kh->phys_base = cpu_to_dump32(s, s->dump_info.phys_base);
|
||||
kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL);
|
||||
|
||||
offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
|
||||
|
@ -837,7 +837,7 @@ static void create_header64(DumpState *s, Error **errp)
|
|||
|
||||
strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE));
|
||||
dh->header_version = cpu_to_dump32(s, 6);
|
||||
block_size = TARGET_PAGE_SIZE;
|
||||
block_size = s->dump_info.page_size;
|
||||
dh->block_size = cpu_to_dump32(s, block_size);
|
||||
sub_hdr_size = sizeof(struct KdumpSubHeader64) + s->note_size;
|
||||
sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
|
||||
|
@ -875,7 +875,7 @@ static void create_header64(DumpState *s, Error **errp)
|
|||
|
||||
/* 64bit max_mapnr_64 */
|
||||
kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr);
|
||||
kh->phys_base = cpu_to_dump64(s, PHYS_BASE);
|
||||
kh->phys_base = cpu_to_dump64(s, s->dump_info.phys_base);
|
||||
kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL);
|
||||
|
||||
offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
|
||||
|
@ -933,6 +933,11 @@ static void write_dump_header(DumpState *s, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
static size_t dump_bitmap_get_bufsize(DumpState *s)
|
||||
{
|
||||
return s->dump_info.page_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* set dump_bitmap sequencely. the bit before last_pfn is not allowed to be
|
||||
* rewritten, so if need to set the first bit, set last_pfn and pfn to 0.
|
||||
|
@ -946,6 +951,8 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value,
|
|||
off_t old_offset, new_offset;
|
||||
off_t offset_bitmap1, offset_bitmap2;
|
||||
uint32_t byte, bit;
|
||||
size_t bitmap_bufsize = dump_bitmap_get_bufsize(s);
|
||||
size_t bits_per_buf = bitmap_bufsize * CHAR_BIT;
|
||||
|
||||
/* should not set the previous place */
|
||||
assert(last_pfn <= pfn);
|
||||
|
@ -956,14 +963,14 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value,
|
|||
* making new_offset be bigger than old_offset can also sync remained data
|
||||
* into vmcore.
|
||||
*/
|
||||
old_offset = BUFSIZE_BITMAP * (last_pfn / PFN_BUFBITMAP);
|
||||
new_offset = BUFSIZE_BITMAP * (pfn / PFN_BUFBITMAP);
|
||||
old_offset = bitmap_bufsize * (last_pfn / bits_per_buf);
|
||||
new_offset = bitmap_bufsize * (pfn / bits_per_buf);
|
||||
|
||||
while (old_offset < new_offset) {
|
||||
/* calculate the offset and write dump_bitmap */
|
||||
offset_bitmap1 = s->offset_dump_bitmap + old_offset;
|
||||
if (write_buffer(s->fd, offset_bitmap1, buf,
|
||||
BUFSIZE_BITMAP) < 0) {
|
||||
bitmap_bufsize) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -971,17 +978,17 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value,
|
|||
offset_bitmap2 = s->offset_dump_bitmap + s->len_dump_bitmap +
|
||||
old_offset;
|
||||
if (write_buffer(s->fd, offset_bitmap2, buf,
|
||||
BUFSIZE_BITMAP) < 0) {
|
||||
bitmap_bufsize) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buf, 0, BUFSIZE_BITMAP);
|
||||
old_offset += BUFSIZE_BITMAP;
|
||||
memset(buf, 0, bitmap_bufsize);
|
||||
old_offset += bitmap_bufsize;
|
||||
}
|
||||
|
||||
/* get the exact place of the bit in the buf, and set it */
|
||||
byte = (pfn % PFN_BUFBITMAP) / CHAR_BIT;
|
||||
bit = (pfn % PFN_BUFBITMAP) % CHAR_BIT;
|
||||
byte = (pfn % bits_per_buf) / CHAR_BIT;
|
||||
bit = (pfn % bits_per_buf) % CHAR_BIT;
|
||||
if (value) {
|
||||
buf[byte] |= 1u << bit;
|
||||
} else {
|
||||
|
@ -991,6 +998,20 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t dump_paddr_to_pfn(DumpState *s, uint64_t addr)
|
||||
{
|
||||
int target_page_shift = ctz32(s->dump_info.page_size);
|
||||
|
||||
return (addr >> target_page_shift) - ARCH_PFN_OFFSET;
|
||||
}
|
||||
|
||||
static uint64_t dump_pfn_to_paddr(DumpState *s, uint64_t pfn)
|
||||
{
|
||||
int target_page_shift = ctz32(s->dump_info.page_size);
|
||||
|
||||
return (pfn + ARCH_PFN_OFFSET) << target_page_shift;
|
||||
}
|
||||
|
||||
/*
|
||||
* exam every page and return the page frame number and the address of the page.
|
||||
* bufptr can be NULL. note: the blocks here is supposed to reflect guest-phys
|
||||
|
@ -1001,16 +1022,16 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,
|
|||
uint8_t **bufptr, DumpState *s)
|
||||
{
|
||||
GuestPhysBlock *block = *blockptr;
|
||||
hwaddr addr;
|
||||
hwaddr addr, target_page_mask = ~((hwaddr)s->dump_info.page_size - 1);
|
||||
uint8_t *buf;
|
||||
|
||||
/* block == NULL means the start of the iteration */
|
||||
if (!block) {
|
||||
block = QTAILQ_FIRST(&s->guest_phys_blocks.head);
|
||||
*blockptr = block;
|
||||
assert((block->target_start & ~TARGET_PAGE_MASK) == 0);
|
||||
assert((block->target_end & ~TARGET_PAGE_MASK) == 0);
|
||||
*pfnptr = paddr_to_pfn(block->target_start);
|
||||
assert((block->target_start & ~target_page_mask) == 0);
|
||||
assert((block->target_end & ~target_page_mask) == 0);
|
||||
*pfnptr = dump_paddr_to_pfn(s, block->target_start);
|
||||
if (bufptr) {
|
||||
*bufptr = block->host_addr;
|
||||
}
|
||||
|
@ -1018,10 +1039,10 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,
|
|||
}
|
||||
|
||||
*pfnptr = *pfnptr + 1;
|
||||
addr = pfn_to_paddr(*pfnptr);
|
||||
addr = dump_pfn_to_paddr(s, *pfnptr);
|
||||
|
||||
if ((addr >= block->target_start) &&
|
||||
(addr + TARGET_PAGE_SIZE <= block->target_end)) {
|
||||
(addr + s->dump_info.page_size <= block->target_end)) {
|
||||
buf = block->host_addr + (addr - block->target_start);
|
||||
} else {
|
||||
/* the next page is in the next block */
|
||||
|
@ -1030,9 +1051,9 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,
|
|||
if (!block) {
|
||||
return false;
|
||||
}
|
||||
assert((block->target_start & ~TARGET_PAGE_MASK) == 0);
|
||||
assert((block->target_end & ~TARGET_PAGE_MASK) == 0);
|
||||
*pfnptr = paddr_to_pfn(block->target_start);
|
||||
assert((block->target_start & ~target_page_mask) == 0);
|
||||
assert((block->target_end & ~target_page_mask) == 0);
|
||||
*pfnptr = dump_paddr_to_pfn(s, block->target_start);
|
||||
buf = block->host_addr;
|
||||
}
|
||||
|
||||
|
@ -1050,9 +1071,11 @@ static void write_dump_bitmap(DumpState *s, Error **errp)
|
|||
void *dump_bitmap_buf;
|
||||
size_t num_dumpable;
|
||||
GuestPhysBlock *block_iter = NULL;
|
||||
size_t bitmap_bufsize = dump_bitmap_get_bufsize(s);
|
||||
size_t bits_per_buf = bitmap_bufsize * CHAR_BIT;
|
||||
|
||||
/* dump_bitmap_buf is used to store dump_bitmap temporarily */
|
||||
dump_bitmap_buf = g_malloc0(BUFSIZE_BITMAP);
|
||||
dump_bitmap_buf = g_malloc0(bitmap_bufsize);
|
||||
|
||||
num_dumpable = 0;
|
||||
last_pfn = 0;
|
||||
|
@ -1074,11 +1097,11 @@ static void write_dump_bitmap(DumpState *s, Error **errp)
|
|||
|
||||
/*
|
||||
* set_dump_bitmap will always leave the recently set bit un-sync. Here we
|
||||
* set last_pfn + PFN_BUFBITMAP to 0 and those set but un-sync bit will be
|
||||
* synchronized into vmcore.
|
||||
* set the remaining bits from last_pfn to the end of the bitmap buffer to
|
||||
* 0. With those set, the un-sync bit will be synchronized into the vmcore.
|
||||
*/
|
||||
if (num_dumpable > 0) {
|
||||
ret = set_dump_bitmap(last_pfn, last_pfn + PFN_BUFBITMAP, false,
|
||||
ret = set_dump_bitmap(last_pfn, last_pfn + bits_per_buf, false,
|
||||
dump_bitmap_buf, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to sync dump_bitmap", errp);
|
||||
|
@ -1098,8 +1121,8 @@ static void prepare_data_cache(DataCache *data_cache, DumpState *s,
|
|||
{
|
||||
data_cache->fd = s->fd;
|
||||
data_cache->data_size = 0;
|
||||
data_cache->buf_size = BUFSIZE_DATA_CACHE;
|
||||
data_cache->buf = g_malloc0(BUFSIZE_DATA_CACHE);
|
||||
data_cache->buf_size = 4 * dump_bitmap_get_bufsize(s);
|
||||
data_cache->buf = g_malloc0(data_cache->buf_size);
|
||||
data_cache->offset = offset;
|
||||
}
|
||||
|
||||
|
@ -1193,7 +1216,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
|||
prepare_data_cache(&page_data, s, offset_data);
|
||||
|
||||
/* prepare buffer to store compressed data */
|
||||
len_buf_out = get_len_buf_out(TARGET_PAGE_SIZE, s->flag_compress);
|
||||
len_buf_out = get_len_buf_out(s->dump_info.page_size, s->flag_compress);
|
||||
assert(len_buf_out != 0);
|
||||
|
||||
#ifdef CONFIG_LZO
|
||||
|
@ -1206,19 +1229,19 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
|||
* init zero page's page_desc and page_data, because every zero page
|
||||
* uses the same page_data
|
||||
*/
|
||||
pd_zero.size = cpu_to_dump32(s, TARGET_PAGE_SIZE);
|
||||
pd_zero.size = cpu_to_dump32(s, s->dump_info.page_size);
|
||||
pd_zero.flags = cpu_to_dump32(s, 0);
|
||||
pd_zero.offset = cpu_to_dump64(s, offset_data);
|
||||
pd_zero.page_flags = cpu_to_dump64(s, 0);
|
||||
buf = g_malloc0(TARGET_PAGE_SIZE);
|
||||
ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false);
|
||||
buf = g_malloc0(s->dump_info.page_size);
|
||||
ret = write_cache(&page_data, buf, s->dump_info.page_size, false);
|
||||
g_free(buf);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page data (zero page)", errp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
offset_data += TARGET_PAGE_SIZE;
|
||||
offset_data += s->dump_info.page_size;
|
||||
|
||||
/*
|
||||
* dump memory to vmcore page by page. zero page will all be resided in the
|
||||
|
@ -1226,7 +1249,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
|||
*/
|
||||
while (get_next_page(&block_iter, &pfn_iter, &buf, s)) {
|
||||
/* check zero page */
|
||||
if (is_zero_page(buf, TARGET_PAGE_SIZE)) {
|
||||
if (is_zero_page(buf, s->dump_info.page_size)) {
|
||||
ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor),
|
||||
false);
|
||||
if (ret < 0) {
|
||||
|
@ -1248,8 +1271,8 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
|||
size_out = len_buf_out;
|
||||
if ((s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) &&
|
||||
(compress2(buf_out, (uLongf *)&size_out, buf,
|
||||
TARGET_PAGE_SIZE, Z_BEST_SPEED) == Z_OK) &&
|
||||
(size_out < TARGET_PAGE_SIZE)) {
|
||||
s->dump_info.page_size, Z_BEST_SPEED) == Z_OK) &&
|
||||
(size_out < s->dump_info.page_size)) {
|
||||
pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_ZLIB);
|
||||
pd.size = cpu_to_dump32(s, size_out);
|
||||
|
||||
|
@ -1260,9 +1283,9 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
|||
}
|
||||
#ifdef CONFIG_LZO
|
||||
} else if ((s->flag_compress & DUMP_DH_COMPRESSED_LZO) &&
|
||||
(lzo1x_1_compress(buf, TARGET_PAGE_SIZE, buf_out,
|
||||
(lzo1x_1_compress(buf, s->dump_info.page_size, buf_out,
|
||||
(lzo_uint *)&size_out, wrkmem) == LZO_E_OK) &&
|
||||
(size_out < TARGET_PAGE_SIZE)) {
|
||||
(size_out < s->dump_info.page_size)) {
|
||||
pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_LZO);
|
||||
pd.size = cpu_to_dump32(s, size_out);
|
||||
|
||||
|
@ -1274,9 +1297,9 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
|||
#endif
|
||||
#ifdef CONFIG_SNAPPY
|
||||
} else if ((s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) &&
|
||||
(snappy_compress((char *)buf, TARGET_PAGE_SIZE,
|
||||
(snappy_compress((char *)buf, s->dump_info.page_size,
|
||||
(char *)buf_out, &size_out) == SNAPPY_OK) &&
|
||||
(size_out < TARGET_PAGE_SIZE)) {
|
||||
(size_out < s->dump_info.page_size)) {
|
||||
pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_SNAPPY);
|
||||
pd.size = cpu_to_dump32(s, size_out);
|
||||
|
||||
|
@ -1289,13 +1312,14 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
|||
} else {
|
||||
/*
|
||||
* fall back to save in plaintext, size_out should be
|
||||
* assigned TARGET_PAGE_SIZE
|
||||
* assigned the target's page size
|
||||
*/
|
||||
pd.flags = cpu_to_dump32(s, 0);
|
||||
size_out = TARGET_PAGE_SIZE;
|
||||
size_out = s->dump_info.page_size;
|
||||
pd.size = cpu_to_dump32(s, size_out);
|
||||
|
||||
ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false);
|
||||
ret = write_cache(&page_data, buf,
|
||||
s->dump_info.page_size, false);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page data", errp);
|
||||
goto out;
|
||||
|
@ -1430,7 +1454,7 @@ static void get_max_mapnr(DumpState *s)
|
|||
GuestPhysBlock *last_block;
|
||||
|
||||
last_block = QTAILQ_LAST(&s->guest_phys_blocks.head, GuestPhysBlockHead);
|
||||
s->max_mapnr = paddr_to_pfn(last_block->target_end);
|
||||
s->max_mapnr = dump_paddr_to_pfn(s, last_block->target_end);
|
||||
}
|
||||
|
||||
static void dump_init(DumpState *s, int fd, bool has_format,
|
||||
|
@ -1489,6 +1513,10 @@ static void dump_init(DumpState *s, int fd, bool has_format,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!s->dump_info.page_size) {
|
||||
s->dump_info.page_size = TARGET_PAGE_SIZE;
|
||||
}
|
||||
|
||||
s->note_size = cpu_get_note_size(s->dump_info.d_class,
|
||||
s->dump_info.d_machine, nr_cpus);
|
||||
if (s->note_size < 0) {
|
||||
|
@ -1512,8 +1540,9 @@ static void dump_init(DumpState *s, int fd, bool has_format,
|
|||
get_max_mapnr(s);
|
||||
|
||||
uint64_t tmp;
|
||||
tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT), TARGET_PAGE_SIZE);
|
||||
s->len_dump_bitmap = tmp * TARGET_PAGE_SIZE;
|
||||
tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT),
|
||||
s->dump_info.page_size);
|
||||
s->len_dump_bitmap = tmp * s->dump_info.page_size;
|
||||
|
||||
/* init for kdump-compressed format */
|
||||
if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
|
||||
|
|
|
@ -94,23 +94,6 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
|
|||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
static void acpi_dsdt_add_rtc(Aml *scope, const MemMapEntry *rtc_memmap,
|
||||
uint32_t rtc_irq)
|
||||
{
|
||||
Aml *dev = aml_device("RTC0");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0013")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
||||
|
||||
Aml *crs = aml_resource_template();
|
||||
aml_append(crs, aml_memory32_fixed(rtc_memmap->base,
|
||||
rtc_memmap->size, AML_READ_WRITE));
|
||||
aml_append(crs,
|
||||
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
||||
AML_EXCLUSIVE, &rtc_irq, 1));
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap)
|
||||
{
|
||||
Aml *dev, *crs;
|
||||
|
@ -571,12 +554,15 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
|
|||
/* Reserve space for header */
|
||||
acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader));
|
||||
|
||||
/* When booting the VM with UEFI, UEFI takes ownership of the RTC hardware.
|
||||
* While UEFI can use libfdt to disable the RTC device node in the DTB that
|
||||
* it passes to the OS, it cannot modify AML. Therefore, we won't generate
|
||||
* the RTC ACPI device at all when using UEFI.
|
||||
*/
|
||||
scope = aml_scope("\\_SB");
|
||||
acpi_dsdt_add_cpus(scope, guest_info->smp_cpus);
|
||||
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
|
||||
(irqmap[VIRT_UART] + ARM_SPI_BASE));
|
||||
acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC],
|
||||
(irqmap[VIRT_RTC] + ARM_SPI_BASE));
|
||||
acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
|
||||
acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
|
||||
(irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
|
||||
|
|
|
@ -25,42 +25,44 @@ typedef struct XlnxEP108 {
|
|||
MemoryRegion ddr_ram;
|
||||
} XlnxEP108;
|
||||
|
||||
/* Max 2GB RAM */
|
||||
#define EP108_MAX_RAM_SIZE 0x80000000ull
|
||||
|
||||
static struct arm_boot_info xlnx_ep108_binfo;
|
||||
|
||||
static void xlnx_ep108_init(MachineState *machine)
|
||||
{
|
||||
XlnxEP108 *s = g_new0(XlnxEP108, 1);
|
||||
Error *err = NULL;
|
||||
uint64_t ram_size = machine->ram_size;
|
||||
|
||||
/* Create the memory region to pass to the SoC */
|
||||
if (ram_size > XLNX_ZYNQMP_MAX_RAM_SIZE) {
|
||||
error_report("ERROR: RAM size 0x%" PRIx64 " above max supported of "
|
||||
"0x%llx", ram_size,
|
||||
XLNX_ZYNQMP_MAX_RAM_SIZE);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ram_size < 0x08000000) {
|
||||
qemu_log("WARNING: RAM size 0x%" PRIx64 " is small for EP108",
|
||||
ram_size);
|
||||
}
|
||||
|
||||
memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram",
|
||||
ram_size);
|
||||
|
||||
object_initialize(&s->soc, sizeof(s->soc), TYPE_XLNX_ZYNQMP);
|
||||
object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
|
||||
&error_abort);
|
||||
|
||||
object_property_set_link(OBJECT(&s->soc), OBJECT(&s->ddr_ram),
|
||||
"ddr-ram", &error_abort);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->soc), true, "realized", &err);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (machine->ram_size > EP108_MAX_RAM_SIZE) {
|
||||
error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, "
|
||||
"reduced to %llx", machine->ram_size, EP108_MAX_RAM_SIZE);
|
||||
machine->ram_size = EP108_MAX_RAM_SIZE;
|
||||
}
|
||||
|
||||
if (machine->ram_size < 0x08000000) {
|
||||
qemu_log("WARNING: RAM size " RAM_ADDR_FMT " is small for EP108",
|
||||
machine->ram_size);
|
||||
}
|
||||
|
||||
memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram",
|
||||
machine->ram_size);
|
||||
memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram);
|
||||
|
||||
xlnx_ep108_binfo.ram_size = machine->ram_size;
|
||||
xlnx_ep108_binfo.ram_size = ram_size;
|
||||
xlnx_ep108_binfo.kernel_filename = machine->kernel_filename;
|
||||
xlnx_ep108_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
xlnx_ep108_binfo.initrd_filename = machine->initrd_filename;
|
||||
|
|
|
@ -90,6 +90,11 @@ static void xlnx_zynqmp_init(Object *obj)
|
|||
&error_abort);
|
||||
}
|
||||
|
||||
object_property_add_link(obj, "ddr-ram", TYPE_MEMORY_REGION,
|
||||
(Object **)&s->ddr_ram,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);
|
||||
|
||||
object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC);
|
||||
qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default());
|
||||
|
||||
|
@ -119,10 +124,42 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
|||
XlnxZynqMPState *s = XLNX_ZYNQMP(dev);
|
||||
MemoryRegion *system_memory = get_system_memory();
|
||||
uint8_t i;
|
||||
uint64_t ram_size;
|
||||
const char *boot_cpu = s->boot_cpu ? s->boot_cpu : "apu-cpu[0]";
|
||||
ram_addr_t ddr_low_size, ddr_high_size;
|
||||
qemu_irq gic_spi[GIC_NUM_SPI_INTR];
|
||||
Error *err = NULL;
|
||||
|
||||
ram_size = memory_region_size(s->ddr_ram);
|
||||
|
||||
/* Create the DDR Memory Regions. User friendly checks should happen at
|
||||
* the board level
|
||||
*/
|
||||
if (ram_size > XLNX_ZYNQMP_MAX_LOW_RAM_SIZE) {
|
||||
/* The RAM size is above the maximum available for the low DDR.
|
||||
* Create the high DDR memory region as well.
|
||||
*/
|
||||
assert(ram_size <= XLNX_ZYNQMP_MAX_RAM_SIZE);
|
||||
ddr_low_size = XLNX_ZYNQMP_MAX_LOW_RAM_SIZE;
|
||||
ddr_high_size = ram_size - XLNX_ZYNQMP_MAX_LOW_RAM_SIZE;
|
||||
|
||||
memory_region_init_alias(&s->ddr_ram_high, NULL,
|
||||
"ddr-ram-high", s->ddr_ram,
|
||||
ddr_low_size, ddr_high_size);
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
XLNX_ZYNQMP_HIGH_RAM_START,
|
||||
&s->ddr_ram_high);
|
||||
} else {
|
||||
/* RAM must be non-zero */
|
||||
assert(ram_size);
|
||||
ddr_low_size = ram_size;
|
||||
}
|
||||
|
||||
memory_region_init_alias(&s->ddr_ram_low, NULL,
|
||||
"ddr-ram-low", s->ddr_ram,
|
||||
0, ddr_low_size);
|
||||
memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram_low);
|
||||
|
||||
/* Create the four OCM banks */
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_OCM_BANKS; i++) {
|
||||
char *ocm_name = g_strdup_printf("zynqmp.ocm_ram_bank_%d", i);
|
||||
|
|
|
@ -1471,6 +1471,11 @@ typedef struct elf64_shdr {
|
|||
#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
|
||||
#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
|
||||
#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
|
||||
#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */
|
||||
#define NT_ARM_TLS 0x401 /* ARM TLS register */
|
||||
#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */
|
||||
#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */
|
||||
#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
|
||||
|
||||
|
||||
/* Note header in a PT_NOTE section */
|
||||
|
|
|
@ -51,6 +51,14 @@
|
|||
#define XLNX_ZYNQMP_GIC_REGION_SIZE 0x1000
|
||||
#define XLNX_ZYNQMP_GIC_ALIASES (0x10000 / XLNX_ZYNQMP_GIC_REGION_SIZE - 1)
|
||||
|
||||
#define XLNX_ZYNQMP_MAX_LOW_RAM_SIZE 0x80000000ull
|
||||
|
||||
#define XLNX_ZYNQMP_MAX_HIGH_RAM_SIZE 0x800000000ull
|
||||
#define XLNX_ZYNQMP_HIGH_RAM_START 0x800000000ull
|
||||
|
||||
#define XLNX_ZYNQMP_MAX_RAM_SIZE (XLNX_ZYNQMP_MAX_LOW_RAM_SIZE + \
|
||||
XLNX_ZYNQMP_MAX_HIGH_RAM_SIZE)
|
||||
|
||||
typedef struct XlnxZynqMPState {
|
||||
/*< private >*/
|
||||
DeviceState parent_obj;
|
||||
|
@ -60,8 +68,12 @@ typedef struct XlnxZynqMPState {
|
|||
ARMCPU rpu_cpu[XLNX_ZYNQMP_NUM_RPU_CPUS];
|
||||
GICState gic;
|
||||
MemoryRegion gic_mr[XLNX_ZYNQMP_GIC_REGIONS][XLNX_ZYNQMP_GIC_ALIASES];
|
||||
|
||||
MemoryRegion ocm_ram[XLNX_ZYNQMP_NUM_OCM_BANKS];
|
||||
|
||||
MemoryRegion *ddr_ram;
|
||||
MemoryRegion ddr_ram_low, ddr_ram_high;
|
||||
|
||||
CadenceGEMState gem[XLNX_ZYNQMP_NUM_GEMS];
|
||||
CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS];
|
||||
SysbusAHCIState sata;
|
||||
|
|
|
@ -15,9 +15,12 @@
|
|||
#define DUMP_ARCH_H
|
||||
|
||||
typedef struct ArchDumpInfo {
|
||||
int d_machine; /* Architecture */
|
||||
int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */
|
||||
int d_class; /* ELFCLASS32 or ELFCLASS64 */
|
||||
int d_machine; /* Architecture */
|
||||
int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */
|
||||
int d_class; /* ELFCLASS32 or ELFCLASS64 */
|
||||
uint32_t page_size; /* The target's page size. If it's variable and
|
||||
* unknown, then this should be the maximum. */
|
||||
uint64_t phys_base; /* The target's physmem base. */
|
||||
} ArchDumpInfo;
|
||||
|
||||
struct GuestPhysBlockList; /* memory_mapping.h */
|
||||
|
|
|
@ -20,12 +20,9 @@
|
|||
#define VERSION_FLAT_HEADER (1) /* version of flattened format */
|
||||
#define END_FLAG_FLAT_HEADER (-1)
|
||||
|
||||
#ifndef ARCH_PFN_OFFSET
|
||||
#define ARCH_PFN_OFFSET (0)
|
||||
|
||||
#define paddr_to_pfn(X) \
|
||||
(((unsigned long long)(X) >> TARGET_PAGE_BITS) - ARCH_PFN_OFFSET)
|
||||
#define pfn_to_paddr(X) \
|
||||
(((unsigned long long)(X) + ARCH_PFN_OFFSET) << TARGET_PAGE_BITS)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* flag for compressed format
|
||||
|
@ -36,12 +33,8 @@
|
|||
|
||||
#define KDUMP_SIGNATURE "KDUMP "
|
||||
#define SIG_LEN (sizeof(KDUMP_SIGNATURE) - 1)
|
||||
#define PHYS_BASE (0)
|
||||
#define DUMP_LEVEL (1)
|
||||
#define DISKDUMP_HEADER_BLOCKS (1)
|
||||
#define BUFSIZE_BITMAP (TARGET_PAGE_SIZE)
|
||||
#define PFN_BUFBITMAP (CHAR_BIT * BUFSIZE_BITMAP)
|
||||
#define BUFSIZE_DATA_CACHE (TARGET_PAGE_SIZE * 4)
|
||||
|
||||
#include "sysemu/dump-arch.h"
|
||||
#include "sysemu/memory_mapping.h"
|
||||
|
|
|
@ -2169,8 +2169,7 @@
|
|||
# @dump-guest-memory
|
||||
#
|
||||
# Dump guest's memory to vmcore. It is a synchronous operation that can take
|
||||
# very long depending on the amount of guest memory. This command is only
|
||||
# supported on i386 and x86_64.
|
||||
# very long depending on the amount of guest memory.
|
||||
#
|
||||
# @paging: if true, do paging to get guest's memory mapping. This allows
|
||||
# using gdb to process the core file.
|
||||
|
@ -2186,6 +2185,7 @@
|
|||
# 2. The guest can be in real-mode even if paging is enabled. For
|
||||
# example, the guest uses ACPI to sleep, and ACPI sleep state
|
||||
# goes in real-mode
|
||||
# 3. Currently only supported on i386 and x86_64.
|
||||
#
|
||||
# @protocol: the filename or file descriptor of the vmcore. The supported
|
||||
# protocols are:
|
||||
|
|
|
@ -130,7 +130,7 @@ int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
|
|||
static int cpu_common_write_elf32_qemunote(WriteCoreDumpFunction f,
|
||||
CPUState *cpu, void *opaque)
|
||||
{
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
|
||||
|
@ -159,7 +159,7 @@ int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
|
|||
static int cpu_common_write_elf64_qemunote(WriteCoreDumpFunction f,
|
||||
CPUState *cpu, void *opaque)
|
||||
{
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
obj-y += arm-semi.o
|
||||
obj-$(CONFIG_SOFTMMU) += machine.o
|
||||
obj-$(CONFIG_SOFTMMU) += machine.o psci.o arch_dump.o
|
||||
obj-$(CONFIG_KVM) += kvm.o
|
||||
obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
|
||||
obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
|
||||
|
@ -7,6 +7,5 @@ obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
|
|||
obj-y += translate.o op_helper.o helper.o cpu.o
|
||||
obj-y += neon_helper.o iwmmxt_helper.o
|
||||
obj-y += gdbstub.o
|
||||
obj-$(CONFIG_SOFTMMU) += psci.o
|
||||
obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
|
||||
obj-y += crypto_helper.o
|
||||
|
|
|
@ -0,0 +1,336 @@
|
|||
/* Support for writing ELF notes for ARM architectures
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat Inc.
|
||||
*
|
||||
* Author: Andrew Jones <drjones@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This 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 program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "elf.h"
|
||||
#include "sysemu/dump.h"
|
||||
|
||||
/* struct user_pt_regs from arch/arm64/include/uapi/asm/ptrace.h */
|
||||
struct aarch64_user_regs {
|
||||
uint64_t regs[31];
|
||||
uint64_t sp;
|
||||
uint64_t pc;
|
||||
uint64_t pstate;
|
||||
} QEMU_PACKED;
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(struct aarch64_user_regs) != 272);
|
||||
|
||||
/* struct elf_prstatus from include/uapi/linux/elfcore.h */
|
||||
struct aarch64_elf_prstatus {
|
||||
char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */
|
||||
uint32_t pr_pid;
|
||||
char pad2[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) -
|
||||
offsetof(struct elf_prstatus, pr_ppid) */
|
||||
struct aarch64_user_regs pr_reg;
|
||||
uint32_t pr_fpvalid;
|
||||
char pad3[4];
|
||||
} QEMU_PACKED;
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(struct aarch64_elf_prstatus) != 392);
|
||||
|
||||
/* struct user_fpsimd_state from arch/arm64/include/uapi/asm/ptrace.h
|
||||
*
|
||||
* While the vregs member of user_fpsimd_state is of type __uint128_t,
|
||||
* QEMU uses an array of uint64_t, where the high half of the 128-bit
|
||||
* value is always in the 2n+1'th index. Thus we also break the 128-
|
||||
* bit values into two halves in this reproduction of user_fpsimd_state.
|
||||
*/
|
||||
struct aarch64_user_vfp_state {
|
||||
uint64_t vregs[64];
|
||||
uint32_t fpsr;
|
||||
uint32_t fpcr;
|
||||
char pad[8];
|
||||
} QEMU_PACKED;
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(struct aarch64_user_vfp_state) != 528);
|
||||
|
||||
struct aarch64_note {
|
||||
Elf64_Nhdr hdr;
|
||||
char name[8]; /* align_up(sizeof("CORE"), 4) */
|
||||
union {
|
||||
struct aarch64_elf_prstatus prstatus;
|
||||
struct aarch64_user_vfp_state vfp;
|
||||
};
|
||||
} QEMU_PACKED;
|
||||
|
||||
#define AARCH64_NOTE_HEADER_SIZE offsetof(struct aarch64_note, prstatus)
|
||||
#define AARCH64_PRSTATUS_NOTE_SIZE \
|
||||
(AARCH64_NOTE_HEADER_SIZE + sizeof(struct aarch64_elf_prstatus))
|
||||
#define AARCH64_PRFPREG_NOTE_SIZE \
|
||||
(AARCH64_NOTE_HEADER_SIZE + sizeof(struct aarch64_user_vfp_state))
|
||||
|
||||
static void aarch64_note_init(struct aarch64_note *note, DumpState *s,
|
||||
const char *name, Elf64_Word namesz,
|
||||
Elf64_Word type, Elf64_Word descsz)
|
||||
{
|
||||
memset(note, 0, sizeof(*note));
|
||||
|
||||
note->hdr.n_namesz = cpu_to_dump32(s, namesz);
|
||||
note->hdr.n_descsz = cpu_to_dump32(s, descsz);
|
||||
note->hdr.n_type = cpu_to_dump32(s, type);
|
||||
|
||||
memcpy(note->name, name, namesz);
|
||||
}
|
||||
|
||||
static int aarch64_write_elf64_prfpreg(WriteCoreDumpFunction f,
|
||||
CPUARMState *env, int cpuid,
|
||||
DumpState *s)
|
||||
{
|
||||
struct aarch64_note note;
|
||||
int ret, i;
|
||||
|
||||
aarch64_note_init(¬e, s, "CORE", 5, NT_PRFPREG, sizeof(note.vfp));
|
||||
|
||||
for (i = 0; i < 64; ++i) {
|
||||
note.vfp.vregs[i] = cpu_to_dump64(s, float64_val(env->vfp.regs[i]));
|
||||
}
|
||||
|
||||
if (s->dump_info.d_endian == ELFDATA2MSB) {
|
||||
/* For AArch64 we must always swap the vfp.regs's 2n and 2n+1
|
||||
* entries when generating BE notes, because even big endian
|
||||
* hosts use 2n+1 for the high half.
|
||||
*/
|
||||
for (i = 0; i < 32; ++i) {
|
||||
uint64_t tmp = note.vfp.vregs[2*i];
|
||||
note.vfp.vregs[2*i] = note.vfp.vregs[2*i+1];
|
||||
note.vfp.vregs[2*i+1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
note.vfp.fpsr = cpu_to_dump32(s, vfp_get_fpsr(env));
|
||||
note.vfp.fpcr = cpu_to_dump32(s, vfp_get_fpcr(env));
|
||||
|
||||
ret = f(¬e, AARCH64_PRFPREG_NOTE_SIZE, s);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||
int cpuid, void *opaque)
|
||||
{
|
||||
struct aarch64_note note;
|
||||
CPUARMState *env = &ARM_CPU(cs)->env;
|
||||
DumpState *s = opaque;
|
||||
uint64_t pstate, sp;
|
||||
int ret, i;
|
||||
|
||||
aarch64_note_init(¬e, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus));
|
||||
|
||||
note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
|
||||
note.prstatus.pr_fpvalid = cpu_to_dump32(s, 1);
|
||||
|
||||
if (!is_a64(env)) {
|
||||
aarch64_sync_32_to_64(env);
|
||||
pstate = cpsr_read(env);
|
||||
sp = 0;
|
||||
} else {
|
||||
pstate = pstate_read(env);
|
||||
sp = env->xregs[31];
|
||||
}
|
||||
|
||||
for (i = 0; i < 31; ++i) {
|
||||
note.prstatus.pr_reg.regs[i] = cpu_to_dump64(s, env->xregs[i]);
|
||||
}
|
||||
note.prstatus.pr_reg.sp = cpu_to_dump64(s, sp);
|
||||
note.prstatus.pr_reg.pc = cpu_to_dump64(s, env->pc);
|
||||
note.prstatus.pr_reg.pstate = cpu_to_dump64(s, pstate);
|
||||
|
||||
ret = f(¬e, AARCH64_PRSTATUS_NOTE_SIZE, s);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return aarch64_write_elf64_prfpreg(f, env, cpuid, s);
|
||||
}
|
||||
|
||||
/* struct pt_regs from arch/arm/include/asm/ptrace.h */
|
||||
struct arm_user_regs {
|
||||
uint32_t regs[17];
|
||||
char pad[4];
|
||||
} QEMU_PACKED;
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(struct arm_user_regs) != 72);
|
||||
|
||||
/* struct elf_prstatus from include/uapi/linux/elfcore.h */
|
||||
struct arm_elf_prstatus {
|
||||
char pad1[24]; /* 24 == offsetof(struct elf_prstatus, pr_pid) */
|
||||
uint32_t pr_pid;
|
||||
char pad2[44]; /* 44 == offsetof(struct elf_prstatus, pr_reg) -
|
||||
offsetof(struct elf_prstatus, pr_ppid) */
|
||||
struct arm_user_regs pr_reg;
|
||||
uint32_t pr_fpvalid;
|
||||
} QEMU_PACKED arm_elf_prstatus;
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(struct arm_elf_prstatus) != 148);
|
||||
|
||||
/* struct user_vfp from arch/arm/include/asm/user.h */
|
||||
struct arm_user_vfp_state {
|
||||
uint64_t vregs[32];
|
||||
uint32_t fpscr;
|
||||
} QEMU_PACKED;
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(struct arm_user_vfp_state) != 260);
|
||||
|
||||
struct arm_note {
|
||||
Elf32_Nhdr hdr;
|
||||
char name[8]; /* align_up(sizeof("LINUX"), 4) */
|
||||
union {
|
||||
struct arm_elf_prstatus prstatus;
|
||||
struct arm_user_vfp_state vfp;
|
||||
};
|
||||
} QEMU_PACKED;
|
||||
|
||||
#define ARM_NOTE_HEADER_SIZE offsetof(struct arm_note, prstatus)
|
||||
#define ARM_PRSTATUS_NOTE_SIZE \
|
||||
(ARM_NOTE_HEADER_SIZE + sizeof(struct arm_elf_prstatus))
|
||||
#define ARM_VFP_NOTE_SIZE \
|
||||
(ARM_NOTE_HEADER_SIZE + sizeof(struct arm_user_vfp_state))
|
||||
|
||||
static void arm_note_init(struct arm_note *note, DumpState *s,
|
||||
const char *name, Elf32_Word namesz,
|
||||
Elf32_Word type, Elf32_Word descsz)
|
||||
{
|
||||
memset(note, 0, sizeof(*note));
|
||||
|
||||
note->hdr.n_namesz = cpu_to_dump32(s, namesz);
|
||||
note->hdr.n_descsz = cpu_to_dump32(s, descsz);
|
||||
note->hdr.n_type = cpu_to_dump32(s, type);
|
||||
|
||||
memcpy(note->name, name, namesz);
|
||||
}
|
||||
|
||||
static int arm_write_elf32_vfp(WriteCoreDumpFunction f, CPUARMState *env,
|
||||
int cpuid, DumpState *s)
|
||||
{
|
||||
struct arm_note note;
|
||||
int ret, i;
|
||||
|
||||
arm_note_init(¬e, s, "LINUX", 6, NT_ARM_VFP, sizeof(note.vfp));
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
note.vfp.vregs[i] = cpu_to_dump64(s, float64_val(env->vfp.regs[i]));
|
||||
}
|
||||
|
||||
note.vfp.fpscr = cpu_to_dump32(s, vfp_get_fpscr(env));
|
||||
|
||||
ret = f(¬e, ARM_VFP_NOTE_SIZE, s);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||
int cpuid, void *opaque)
|
||||
{
|
||||
struct arm_note note;
|
||||
CPUARMState *env = &ARM_CPU(cs)->env;
|
||||
DumpState *s = opaque;
|
||||
int ret, i, fpvalid = !!arm_feature(env, ARM_FEATURE_VFP);
|
||||
|
||||
arm_note_init(¬e, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus));
|
||||
|
||||
note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
|
||||
note.prstatus.pr_fpvalid = cpu_to_dump32(s, fpvalid);
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
note.prstatus.pr_reg.regs[i] = cpu_to_dump32(s, env->regs[i]);
|
||||
}
|
||||
note.prstatus.pr_reg.regs[16] = cpu_to_dump32(s, cpsr_read(env));
|
||||
|
||||
ret = f(¬e, ARM_PRSTATUS_NOTE_SIZE, s);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
} else if (fpvalid) {
|
||||
return arm_write_elf32_vfp(f, env, cpuid, s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_get_dump_info(ArchDumpInfo *info,
|
||||
const GuestPhysBlockList *guest_phys_blocks)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(first_cpu);
|
||||
CPUARMState *env = &cpu->env;
|
||||
GuestPhysBlock *block;
|
||||
hwaddr lowest_addr = ULLONG_MAX;
|
||||
|
||||
/* Take a best guess at the phys_base. If we get it wrong then crash
|
||||
* will need '--machdep phys_offset=<phys-offset>' added to its command
|
||||
* line, which isn't any worse than assuming we can use zero, but being
|
||||
* wrong. This is the same algorithm the crash utility uses when
|
||||
* attempting to guess as it loads non-dumpfile formatted files.
|
||||
*/
|
||||
QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) {
|
||||
if (block->target_start < lowest_addr) {
|
||||
lowest_addr = block->target_start;
|
||||
}
|
||||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
|
||||
info->d_machine = EM_AARCH64;
|
||||
info->d_class = ELFCLASS64;
|
||||
info->page_size = (1 << 16); /* aarch64 max pagesize */
|
||||
if (lowest_addr != ULLONG_MAX) {
|
||||
info->phys_base = lowest_addr;
|
||||
}
|
||||
} else {
|
||||
info->d_machine = EM_ARM;
|
||||
info->d_class = ELFCLASS32;
|
||||
info->page_size = (1 << 12);
|
||||
if (lowest_addr < UINT_MAX) {
|
||||
info->phys_base = lowest_addr;
|
||||
}
|
||||
}
|
||||
|
||||
/* We assume the relevant endianness is that of EL1; this is right
|
||||
* for kernels, but might give the wrong answer if you're trying to
|
||||
* dump a hypervisor that happens to be running an opposite-endian
|
||||
* kernel.
|
||||
*/
|
||||
info->d_endian = (env->cp15.sctlr_el[1] & SCTLR_EE) != 0
|
||||
? ELFDATA2MSB : ELFDATA2LSB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(first_cpu);
|
||||
CPUARMState *env = &cpu->env;
|
||||
size_t note_size;
|
||||
|
||||
if (class == ELFCLASS64) {
|
||||
note_size = AARCH64_PRSTATUS_NOTE_SIZE;
|
||||
note_size += AARCH64_PRFPREG_NOTE_SIZE;
|
||||
} else {
|
||||
note_size = ARM_PRSTATUS_NOTE_SIZE;
|
||||
if (arm_feature(env, ARM_FEATURE_VFP)) {
|
||||
note_size += ARM_VFP_NOTE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
return note_size * nr_cpus;
|
||||
}
|
|
@ -221,6 +221,11 @@ hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
|||
int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
|
||||
int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||
int cpuid, void *opaque);
|
||||
int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||
int cpuid, void *opaque);
|
||||
|
||||
/* Callback functions for the generic timer's timers. */
|
||||
void arm_gt_ptimer_cb(void *opaque);
|
||||
void arm_gt_vtimer_cb(void *opaque);
|
||||
|
|
|
@ -1421,6 +1421,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
|
|||
cc->get_phys_page_debug = arm_cpu_get_phys_page_debug;
|
||||
cc->vmsd = &vmstate_arm_cpu;
|
||||
cc->virtio_is_big_endian = arm_cpu_is_big_endian;
|
||||
cc->write_elf64_note = arm_cpu_write_elf64_note;
|
||||
cc->write_elf32_note = arm_cpu_write_elf32_note;
|
||||
#endif
|
||||
cc->gdb_num_core_regs = 26;
|
||||
cc->gdb_core_xml_file = "arm-core.xml";
|
||||
|
|
|
@ -5996,11 +5996,15 @@ static inline bool regime_using_lpae_format(CPUARMState *env,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Returns true if the translation regime is using LPAE format page tables.
|
||||
* Used when raising alignment exceptions, whose FSR changes depending on
|
||||
* whether the long or short descriptor format is in use. */
|
||||
bool arm_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
/* Returns true if the stage 1 translation regime is using LPAE format page
|
||||
* tables. Used when raising alignment exceptions, whose FSR changes depending
|
||||
* on whether the long or short descriptor format is in use. */
|
||||
bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
{
|
||||
if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) {
|
||||
mmu_idx += ARMMMUIdx_S1NSE0;
|
||||
}
|
||||
|
||||
return regime_using_lpae_format(env, mmu_idx);
|
||||
}
|
||||
|
||||
|
|
|
@ -441,8 +441,9 @@ struct ARMMMUFaultInfo {
|
|||
bool arm_tlb_fill(CPUState *cpu, vaddr address, int rw, int mmu_idx,
|
||||
uint32_t *fsr, ARMMMUFaultInfo *fi);
|
||||
|
||||
/* Return true if the translation regime is using LPAE format page tables */
|
||||
bool arm_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
|
||||
/* Return true if the stage 1 translation regime is using LPAE format page
|
||||
* tables */
|
||||
bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
|
||||
|
||||
/* Raise a data fault alignment exception for the specified virtual address */
|
||||
void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write,
|
||||
|
|
|
@ -149,7 +149,7 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write,
|
|||
/* the DFSR for an alignment fault depends on whether we're using
|
||||
* the LPAE long descriptor format, or the short descriptor format
|
||||
*/
|
||||
if (arm_regime_using_lpae_format(env, cpu_mmu_index(env, false))) {
|
||||
if (arm_s1_regime_using_lpae_format(env, cpu_mmu_index(env, false))) {
|
||||
env->exception.fsr = 0x21;
|
||||
} else {
|
||||
env->exception.fsr = 0x1;
|
||||
|
|
|
@ -278,9 +278,3 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
|
|||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
return ppc64_write_all_elf64_notes("CORE", f, cpu, cpuid, opaque);
|
||||
}
|
||||
|
||||
int ppc64_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
|
||||
CPUState *cpu, void *opaque)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -125,8 +125,6 @@ int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
|||
int ppc_cpu_gdb_read_register_apple(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int ppc_cpu_gdb_write_register_apple(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int ppc64_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
|
||||
CPUState *cpu, void *opaque);
|
||||
int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||
int cpuid, void *opaque);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
|
|
@ -9712,7 +9712,6 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
|
|||
cc->vmsd = &vmstate_ppc_cpu;
|
||||
#if defined(TARGET_PPC64)
|
||||
cc->write_elf64_note = ppc64_cpu_write_elf64_note;
|
||||
cc->write_elf64_qemunote = ppc64_cpu_write_elf64_qemunote;
|
||||
#endif
|
||||
#endif
|
||||
cc->cpu_exec_enter = ppc_cpu_exec_enter;
|
||||
|
|
|
@ -246,9 +246,3 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
|
|||
|
||||
return (elf_note_size) * nr_cpus;
|
||||
}
|
||||
|
||||
int s390_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
|
||||
CPUState *cpu, void *opaque)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -91,8 +91,6 @@ void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
|||
int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||
int cpuid, void *opaque);
|
||||
|
||||
int s390_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
|
||||
CPUState *cpu, void *opaque);
|
||||
hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||
hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
|
||||
int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
|
|
|
@ -353,7 +353,6 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
|
|||
cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
|
||||
cc->vmsd = &vmstate_s390_cpu;
|
||||
cc->write_elf64_note = s390_cpu_write_elf64_note;
|
||||
cc->write_elf64_qemunote = s390_cpu_write_elf64_qemunote;
|
||||
cc->cpu_exec_interrupt = s390_cpu_exec_interrupt;
|
||||
cc->debug_excp_handler = s390x_cpu_debug_excp_handler;
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue