target-arm queue:
* allwinner-h3: Fix I2C controller model for Sun6i SoCs * allwinner-h3: Add missing i2c controllers * Expose M-profile system registers to gdbstub * Expose pauth information to gdbstub * Support direct boot for Linux/arm64 EFI zboot images * Fix incorrect stage 2 MMU setup validation -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmQGB+wZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3gdQEACVfgbs77mxbOb6u8yWHKGZ tVnQr9KZMv2lmwt5H3ROJPXznchrIIAwdMeRgKnbI+lC5jTq9L+Q8RJch3t/EbAd f0VMyiPe3DzCbCrAR9cW6EWzbYnEVo3Ioj4k7qjxK6u1BIKhXz99DLYd1KRdTxnx BAYmcl857Uir1q2FrBVMZ/ItCLbk4ejn+YaDIawNue2/s1oGa+we473x9rosCFvp L9bzT3R46e0o+Mfkn1OYRmgCmURTalWPpWAxyOUFR9YbrzXleLgAKEB3o3PPcvls u26uxztyRMqje1q06VjUzwaLw7zN9XPhmir+NXX7KXp2/x9PZjApOpPtt0kl+6qe FbByKfl24O9w/OKewsJw+udCBYdYrRPm6tWv2D71iAwjBUzBJgNGe5VPRdPFtPDn uSRO65o34w1nPzRpAheUciZueiabYrVmIgVltFxj0JlrKGfgiYHPLVyU0Uu0K/A7 F2kUEQIzIcWdo+c8SlvlWOEA2ojVd/KoLVLgndqr40Tk5pbc65TRS08kkVVl4cMT jUGscl7Dyxe+yo8+nHdycAJpnKYDllJOh2JbGv3r2FqCy5FMuIqW4hHeuUxwpE+O nxm7lzjnaVHSAFHdzhk9x4E4uH/GTcdWzX1EsmpgGqe5oejLJOrCINb+Dj44+Y8h 8aGRvE7kxMs11upxc7BcAw== =KIMt -----END PGP SIGNATURE----- Merge tag 'pull-target-arm-20230306' of https://git.linaro.org/people/pmaydell/qemu-arm into staging target-arm queue: * allwinner-h3: Fix I2C controller model for Sun6i SoCs * allwinner-h3: Add missing i2c controllers * Expose M-profile system registers to gdbstub * Expose pauth information to gdbstub * Support direct boot for Linux/arm64 EFI zboot images * Fix incorrect stage 2 MMU setup validation # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmQGB+wZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3gdQEACVfgbs77mxbOb6u8yWHKGZ # tVnQr9KZMv2lmwt5H3ROJPXznchrIIAwdMeRgKnbI+lC5jTq9L+Q8RJch3t/EbAd # f0VMyiPe3DzCbCrAR9cW6EWzbYnEVo3Ioj4k7qjxK6u1BIKhXz99DLYd1KRdTxnx # BAYmcl857Uir1q2FrBVMZ/ItCLbk4ejn+YaDIawNue2/s1oGa+we473x9rosCFvp # L9bzT3R46e0o+Mfkn1OYRmgCmURTalWPpWAxyOUFR9YbrzXleLgAKEB3o3PPcvls # u26uxztyRMqje1q06VjUzwaLw7zN9XPhmir+NXX7KXp2/x9PZjApOpPtt0kl+6qe # FbByKfl24O9w/OKewsJw+udCBYdYrRPm6tWv2D71iAwjBUzBJgNGe5VPRdPFtPDn # uSRO65o34w1nPzRpAheUciZueiabYrVmIgVltFxj0JlrKGfgiYHPLVyU0Uu0K/A7 # F2kUEQIzIcWdo+c8SlvlWOEA2ojVd/KoLVLgndqr40Tk5pbc65TRS08kkVVl4cMT # jUGscl7Dyxe+yo8+nHdycAJpnKYDllJOh2JbGv3r2FqCy5FMuIqW4hHeuUxwpE+O # nxm7lzjnaVHSAFHdzhk9x4E4uH/GTcdWzX1EsmpgGqe5oejLJOrCINb+Dj44+Y8h # 8aGRvE7kxMs11upxc7BcAw== # =KIMt # -----END PGP SIGNATURE----- # gpg: Signature made Mon 06 Mar 2023 15:34:04 GMT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # gpg: aka "Peter Maydell <peter@archaic.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * tag 'pull-target-arm-20230306' of https://git.linaro.org/people/pmaydell/qemu-arm: (21 commits) hw: arm: allwinner-h3: Fix and complete H3 i2c devices hw: allwinner-i2c: Fix TWI_CNTR_INT_FLAG on SUN6i SoCs hw: arm: Support direct boot for Linux/arm64 EFI zboot images target/arm: Rewrite check_s2_mmu_setup target/arm: Diagnose incorrect usage of arm_is_secure subroutines target/arm: Stub arm_hcr_el2_eff for m-profile target/arm: Handle m-profile in arm_is_secure target/arm: Implement gdbstub m-profile systemreg and secext target/arm: Export arm_v7m_get_sp_ptr target/arm: Export arm_v7m_mrs_control target/arm: Implement gdbstub pauth extension target/arm: Create pauth_ptr_mask target/arm: Simplify iteration over bit widths target/arm: Add name argument to output_vector_union_type target/arm: Fix svep width in arm_gen_dynamic_svereg_xml target/arm: Hoist pred_width in arm_gen_dynamic_svereg_xml target/arm: Simplify register counting in arm_gen_dynamic_svereg_xml target/arm: Split out output_vector_union_type target/arm: Move arm_gen_dynamic_svereg_xml to gdbstub64.c target/arm: Unexport arm_gen_dynamic_sysreg_xml ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
c29a2f40cd
|
@ -1,6 +1,6 @@
|
||||||
TARGET_ARCH=aarch64
|
TARGET_ARCH=aarch64
|
||||||
TARGET_BASE_ARCH=arm
|
TARGET_BASE_ARCH=arm
|
||||||
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
|
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/aarch64-pauth.xml
|
||||||
TARGET_HAS_BFLT=y
|
TARGET_HAS_BFLT=y
|
||||||
CONFIG_SEMIHOSTING=y
|
CONFIG_SEMIHOSTING=y
|
||||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
TARGET_ARCH=aarch64
|
TARGET_ARCH=aarch64
|
||||||
TARGET_BASE_ARCH=arm
|
TARGET_BASE_ARCH=arm
|
||||||
TARGET_SUPPORTS_MTTCG=y
|
TARGET_SUPPORTS_MTTCG=y
|
||||||
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml
|
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml gdb-xml/aarch64-pauth.xml
|
||||||
TARGET_NEED_FDT=y
|
TARGET_NEED_FDT=y
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
TARGET_ARCH=aarch64
|
TARGET_ARCH=aarch64
|
||||||
TARGET_BASE_ARCH=arm
|
TARGET_BASE_ARCH=arm
|
||||||
TARGET_BIG_ENDIAN=y
|
TARGET_BIG_ENDIAN=y
|
||||||
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
|
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/aarch64-pauth.xml
|
||||||
TARGET_HAS_BFLT=y
|
TARGET_HAS_BFLT=y
|
||||||
CONFIG_SEMIHOSTING=y
|
CONFIG_SEMIHOSTING=y
|
||||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
Copying and distribution of this file, with or without modification,
|
||||||
|
are permitted in any medium without royalty provided the copyright
|
||||||
|
notice and this notice are preserved. -->
|
||||||
|
|
||||||
|
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||||
|
<feature name="org.gnu.gdb.aarch64.pauth">
|
||||||
|
<reg name="pauth_dmask" bitsize="64"/>
|
||||||
|
<reg name="pauth_cmask" bitsize="64"/>
|
||||||
|
<reg name="pauth_dmask_high" bitsize="64"/>
|
||||||
|
<reg name="pauth_cmask_high" bitsize="64"/>
|
||||||
|
</feature>
|
||||||
|
|
|
@ -54,6 +54,8 @@ const hwaddr allwinner_h3_memmap[] = {
|
||||||
[AW_H3_DEV_UART2] = 0x01c28800,
|
[AW_H3_DEV_UART2] = 0x01c28800,
|
||||||
[AW_H3_DEV_UART3] = 0x01c28c00,
|
[AW_H3_DEV_UART3] = 0x01c28c00,
|
||||||
[AW_H3_DEV_TWI0] = 0x01c2ac00,
|
[AW_H3_DEV_TWI0] = 0x01c2ac00,
|
||||||
|
[AW_H3_DEV_TWI1] = 0x01c2b000,
|
||||||
|
[AW_H3_DEV_TWI2] = 0x01c2b400,
|
||||||
[AW_H3_DEV_EMAC] = 0x01c30000,
|
[AW_H3_DEV_EMAC] = 0x01c30000,
|
||||||
[AW_H3_DEV_DRAMCOM] = 0x01c62000,
|
[AW_H3_DEV_DRAMCOM] = 0x01c62000,
|
||||||
[AW_H3_DEV_DRAMCTL] = 0x01c63000,
|
[AW_H3_DEV_DRAMCTL] = 0x01c63000,
|
||||||
|
@ -64,6 +66,7 @@ const hwaddr allwinner_h3_memmap[] = {
|
||||||
[AW_H3_DEV_GIC_VCPU] = 0x01c86000,
|
[AW_H3_DEV_GIC_VCPU] = 0x01c86000,
|
||||||
[AW_H3_DEV_RTC] = 0x01f00000,
|
[AW_H3_DEV_RTC] = 0x01f00000,
|
||||||
[AW_H3_DEV_CPUCFG] = 0x01f01c00,
|
[AW_H3_DEV_CPUCFG] = 0x01f01c00,
|
||||||
|
[AW_H3_DEV_R_TWI] = 0x01f02400,
|
||||||
[AW_H3_DEV_SDRAM] = 0x40000000
|
[AW_H3_DEV_SDRAM] = 0x40000000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,8 +110,6 @@ struct AwH3Unimplemented {
|
||||||
{ "uart1", 0x01c28400, 1 * KiB },
|
{ "uart1", 0x01c28400, 1 * KiB },
|
||||||
{ "uart2", 0x01c28800, 1 * KiB },
|
{ "uart2", 0x01c28800, 1 * KiB },
|
||||||
{ "uart3", 0x01c28c00, 1 * KiB },
|
{ "uart3", 0x01c28c00, 1 * KiB },
|
||||||
{ "twi1", 0x01c2b000, 1 * KiB },
|
|
||||||
{ "twi2", 0x01c2b400, 1 * KiB },
|
|
||||||
{ "scr", 0x01c2c400, 1 * KiB },
|
{ "scr", 0x01c2c400, 1 * KiB },
|
||||||
{ "gpu", 0x01c40000, 64 * KiB },
|
{ "gpu", 0x01c40000, 64 * KiB },
|
||||||
{ "hstmr", 0x01c60000, 4 * KiB },
|
{ "hstmr", 0x01c60000, 4 * KiB },
|
||||||
|
@ -123,7 +124,6 @@ struct AwH3Unimplemented {
|
||||||
{ "r_prcm", 0x01f01400, 1 * KiB },
|
{ "r_prcm", 0x01f01400, 1 * KiB },
|
||||||
{ "r_twd", 0x01f01800, 1 * KiB },
|
{ "r_twd", 0x01f01800, 1 * KiB },
|
||||||
{ "r_cir-rx", 0x01f02000, 1 * KiB },
|
{ "r_cir-rx", 0x01f02000, 1 * KiB },
|
||||||
{ "r_twi", 0x01f02400, 1 * KiB },
|
|
||||||
{ "r_uart", 0x01f02800, 1 * KiB },
|
{ "r_uart", 0x01f02800, 1 * KiB },
|
||||||
{ "r_pio", 0x01f02c00, 1 * KiB },
|
{ "r_pio", 0x01f02c00, 1 * KiB },
|
||||||
{ "r_pwm", 0x01f03800, 1 * KiB },
|
{ "r_pwm", 0x01f03800, 1 * KiB },
|
||||||
|
@ -151,8 +151,11 @@ enum {
|
||||||
AW_H3_GIC_SPI_UART2 = 2,
|
AW_H3_GIC_SPI_UART2 = 2,
|
||||||
AW_H3_GIC_SPI_UART3 = 3,
|
AW_H3_GIC_SPI_UART3 = 3,
|
||||||
AW_H3_GIC_SPI_TWI0 = 6,
|
AW_H3_GIC_SPI_TWI0 = 6,
|
||||||
|
AW_H3_GIC_SPI_TWI1 = 7,
|
||||||
|
AW_H3_GIC_SPI_TWI2 = 8,
|
||||||
AW_H3_GIC_SPI_TIMER0 = 18,
|
AW_H3_GIC_SPI_TIMER0 = 18,
|
||||||
AW_H3_GIC_SPI_TIMER1 = 19,
|
AW_H3_GIC_SPI_TIMER1 = 19,
|
||||||
|
AW_H3_GIC_SPI_R_TWI = 44,
|
||||||
AW_H3_GIC_SPI_MMC0 = 60,
|
AW_H3_GIC_SPI_MMC0 = 60,
|
||||||
AW_H3_GIC_SPI_EHCI0 = 72,
|
AW_H3_GIC_SPI_EHCI0 = 72,
|
||||||
AW_H3_GIC_SPI_OHCI0 = 73,
|
AW_H3_GIC_SPI_OHCI0 = 73,
|
||||||
|
@ -227,7 +230,10 @@ static void allwinner_h3_init(Object *obj)
|
||||||
|
|
||||||
object_initialize_child(obj, "rtc", &s->rtc, TYPE_AW_RTC_SUN6I);
|
object_initialize_child(obj, "rtc", &s->rtc, TYPE_AW_RTC_SUN6I);
|
||||||
|
|
||||||
object_initialize_child(obj, "twi0", &s->i2c0, TYPE_AW_I2C);
|
object_initialize_child(obj, "twi0", &s->i2c0, TYPE_AW_I2C_SUN6I);
|
||||||
|
object_initialize_child(obj, "twi1", &s->i2c1, TYPE_AW_I2C_SUN6I);
|
||||||
|
object_initialize_child(obj, "twi2", &s->i2c2, TYPE_AW_I2C_SUN6I);
|
||||||
|
object_initialize_child(obj, "r_twi", &s->r_twi, TYPE_AW_I2C_SUN6I);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void allwinner_h3_realize(DeviceState *dev, Error **errp)
|
static void allwinner_h3_realize(DeviceState *dev, Error **errp)
|
||||||
|
@ -432,6 +438,21 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp)
|
||||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c0), 0,
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c0), 0,
|
||||||
qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_TWI0));
|
qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_TWI0));
|
||||||
|
|
||||||
|
sysbus_realize(SYS_BUS_DEVICE(&s->i2c1), &error_fatal);
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c1), 0, s->memmap[AW_H3_DEV_TWI1]);
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c1), 0,
|
||||||
|
qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_TWI1));
|
||||||
|
|
||||||
|
sysbus_realize(SYS_BUS_DEVICE(&s->i2c2), &error_fatal);
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c2), 0, s->memmap[AW_H3_DEV_TWI2]);
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c2), 0,
|
||||||
|
qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_TWI2));
|
||||||
|
|
||||||
|
sysbus_realize(SYS_BUS_DEVICE(&s->r_twi), &error_fatal);
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->r_twi), 0, s->memmap[AW_H3_DEV_R_TWI]);
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->r_twi), 0,
|
||||||
|
qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_R_TWI));
|
||||||
|
|
||||||
/* Unimplemented devices */
|
/* Unimplemented devices */
|
||||||
for (i = 0; i < ARRAY_SIZE(unimplemented); i++) {
|
for (i = 0; i < ARRAY_SIZE(unimplemented); i++) {
|
||||||
create_unimplemented_device(unimplemented[i].device_name,
|
create_unimplemented_device(unimplemented[i].device_name,
|
||||||
|
|
|
@ -926,6 +926,12 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
size = len;
|
size = len;
|
||||||
|
|
||||||
|
/* Unpack the image if it is a EFI zboot image */
|
||||||
|
if (unpack_efi_zboot_image(&buffer, &size) < 0) {
|
||||||
|
g_free(buffer);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check the arm64 magic header value -- very old kernels may not have it */
|
/* check the arm64 magic header value -- very old kernels may not have it */
|
||||||
|
|
|
@ -857,6 +857,97 @@ ssize_t load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz)
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The PE/COFF MS-DOS stub magic number */
|
||||||
|
#define EFI_PE_MSDOS_MAGIC "MZ"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Linux header magic number for a EFI PE/COFF
|
||||||
|
* image targetting an unspecified architecture.
|
||||||
|
*/
|
||||||
|
#define EFI_PE_LINUX_MAGIC "\xcd\x23\x82\x81"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bootable Linux kernel images may be packaged as EFI zboot images, which are
|
||||||
|
* self-decompressing executables when loaded via EFI. The compressed payload
|
||||||
|
* can also be extracted from the image and decompressed by a non-EFI loader.
|
||||||
|
*
|
||||||
|
* The de facto specification for this format is at the following URL:
|
||||||
|
*
|
||||||
|
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/efi/libstub/zboot-header.S
|
||||||
|
*
|
||||||
|
* This definition is based on Linux upstream commit 29636a5ce87beba.
|
||||||
|
*/
|
||||||
|
struct linux_efi_zboot_header {
|
||||||
|
uint8_t msdos_magic[2]; /* PE/COFF 'MZ' magic number */
|
||||||
|
uint8_t reserved0[2];
|
||||||
|
uint8_t zimg[4]; /* "zimg" for Linux EFI zboot images */
|
||||||
|
uint32_t payload_offset; /* LE offset to compressed payload */
|
||||||
|
uint32_t payload_size; /* LE size of the compressed payload */
|
||||||
|
uint8_t reserved1[8];
|
||||||
|
char compression_type[32]; /* Compression type, NUL terminated */
|
||||||
|
uint8_t linux_magic[4]; /* Linux header magic */
|
||||||
|
uint32_t pe_header_offset; /* LE offset to the PE header */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether *buffer points to a Linux EFI zboot image in memory.
|
||||||
|
*
|
||||||
|
* If it does, attempt to decompress it to a new buffer, and free the old one.
|
||||||
|
* If any of this fails, return an error to the caller.
|
||||||
|
*
|
||||||
|
* If the image is not a Linux EFI zboot image, do nothing and return success.
|
||||||
|
*/
|
||||||
|
ssize_t unpack_efi_zboot_image(uint8_t **buffer, int *size)
|
||||||
|
{
|
||||||
|
const struct linux_efi_zboot_header *header;
|
||||||
|
uint8_t *data = NULL;
|
||||||
|
int ploff, plsize;
|
||||||
|
ssize_t bytes;
|
||||||
|
|
||||||
|
/* ignore if this is too small to be a EFI zboot image */
|
||||||
|
if (*size < sizeof(*header)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
header = (struct linux_efi_zboot_header *)*buffer;
|
||||||
|
|
||||||
|
/* ignore if this is not a Linux EFI zboot image */
|
||||||
|
if (memcmp(&header->msdos_magic, EFI_PE_MSDOS_MAGIC, 2) != 0 ||
|
||||||
|
memcmp(&header->zimg, "zimg", 4) != 0 ||
|
||||||
|
memcmp(&header->linux_magic, EFI_PE_LINUX_MAGIC, 4) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(header->compression_type, "gzip") != 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"unable to handle EFI zboot image with \"%.*s\" compression\n",
|
||||||
|
(int)sizeof(header->compression_type) - 1,
|
||||||
|
header->compression_type);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ploff = ldl_le_p(&header->payload_offset);
|
||||||
|
plsize = ldl_le_p(&header->payload_size);
|
||||||
|
|
||||||
|
if (ploff < 0 || plsize < 0 || ploff + plsize > *size) {
|
||||||
|
fprintf(stderr, "unable to handle corrupt EFI zboot image\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = g_malloc(LOAD_IMAGE_MAX_GUNZIP_BYTES);
|
||||||
|
bytes = gunzip(data, LOAD_IMAGE_MAX_GUNZIP_BYTES, *buffer + ploff, plsize);
|
||||||
|
if (bytes < 0) {
|
||||||
|
fprintf(stderr, "failed to decompress EFI zboot image\n");
|
||||||
|
g_free(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(*buffer);
|
||||||
|
*buffer = g_realloc(data, bytes);
|
||||||
|
*size = bytes;
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functions for reboot-persistent memory regions.
|
* Functions for reboot-persistent memory regions.
|
||||||
* - used for vga bios and option roms.
|
* - used for vga bios and option roms.
|
||||||
|
|
|
@ -357,10 +357,16 @@ static void allwinner_i2c_write(void *opaque, hwaddr offset,
|
||||||
s->stat = STAT_FROM_STA(STAT_IDLE);
|
s->stat = STAT_FROM_STA(STAT_IDLE);
|
||||||
s->cntr &= ~TWI_CNTR_M_STP;
|
s->cntr &= ~TWI_CNTR_M_STP;
|
||||||
}
|
}
|
||||||
if ((s->cntr & TWI_CNTR_INT_FLAG) == 0) {
|
|
||||||
/* Interrupt flag cleared */
|
if (!s->irq_clear_inverted && !(s->cntr & TWI_CNTR_INT_FLAG)) {
|
||||||
|
/* Write 0 to clear this flag */
|
||||||
|
qemu_irq_lower(s->irq);
|
||||||
|
} else if (s->irq_clear_inverted && (s->cntr & TWI_CNTR_INT_FLAG)) {
|
||||||
|
/* Write 1 to clear this flag */
|
||||||
|
s->cntr &= ~TWI_CNTR_INT_FLAG;
|
||||||
qemu_irq_lower(s->irq);
|
qemu_irq_lower(s->irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((s->cntr & TWI_CNTR_A_ACK) == 0) {
|
if ((s->cntr & TWI_CNTR_A_ACK) == 0) {
|
||||||
if (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_ACK) {
|
if (STAT_TO_STA(s->stat) == STAT_M_DATA_RX_ACK) {
|
||||||
s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK);
|
s->stat = STAT_FROM_STA(STAT_M_DATA_RX_NACK);
|
||||||
|
@ -451,9 +457,25 @@ static const TypeInfo allwinner_i2c_type_info = {
|
||||||
.class_init = allwinner_i2c_class_init,
|
.class_init = allwinner_i2c_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void allwinner_i2c_sun6i_init(Object *obj)
|
||||||
|
{
|
||||||
|
AWI2CState *s = AW_I2C(obj);
|
||||||
|
|
||||||
|
s->irq_clear_inverted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo allwinner_i2c_sun6i_type_info = {
|
||||||
|
.name = TYPE_AW_I2C_SUN6I,
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(AWI2CState),
|
||||||
|
.instance_init = allwinner_i2c_sun6i_init,
|
||||||
|
.class_init = allwinner_i2c_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
static void allwinner_i2c_register_types(void)
|
static void allwinner_i2c_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&allwinner_i2c_type_info);
|
type_register_static(&allwinner_i2c_type_info);
|
||||||
|
type_register_static(&allwinner_i2c_sun6i_type_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(allwinner_i2c_register_types)
|
type_init(allwinner_i2c_register_types)
|
||||||
|
|
|
@ -84,6 +84,8 @@ enum {
|
||||||
AW_H3_DEV_UART3,
|
AW_H3_DEV_UART3,
|
||||||
AW_H3_DEV_EMAC,
|
AW_H3_DEV_EMAC,
|
||||||
AW_H3_DEV_TWI0,
|
AW_H3_DEV_TWI0,
|
||||||
|
AW_H3_DEV_TWI1,
|
||||||
|
AW_H3_DEV_TWI2,
|
||||||
AW_H3_DEV_DRAMCOM,
|
AW_H3_DEV_DRAMCOM,
|
||||||
AW_H3_DEV_DRAMCTL,
|
AW_H3_DEV_DRAMCTL,
|
||||||
AW_H3_DEV_DRAMPHY,
|
AW_H3_DEV_DRAMPHY,
|
||||||
|
@ -93,6 +95,7 @@ enum {
|
||||||
AW_H3_DEV_GIC_VCPU,
|
AW_H3_DEV_GIC_VCPU,
|
||||||
AW_H3_DEV_RTC,
|
AW_H3_DEV_RTC,
|
||||||
AW_H3_DEV_CPUCFG,
|
AW_H3_DEV_CPUCFG,
|
||||||
|
AW_H3_DEV_R_TWI,
|
||||||
AW_H3_DEV_SDRAM
|
AW_H3_DEV_SDRAM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -133,6 +136,9 @@ struct AwH3State {
|
||||||
AwSidState sid;
|
AwSidState sid;
|
||||||
AwSdHostState mmc0;
|
AwSdHostState mmc0;
|
||||||
AWI2CState i2c0;
|
AWI2CState i2c0;
|
||||||
|
AWI2CState i2c1;
|
||||||
|
AWI2CState i2c2;
|
||||||
|
AWI2CState r_twi;
|
||||||
AwSun8iEmacState emac;
|
AwSun8iEmacState emac;
|
||||||
AwRtcState rtc;
|
AwRtcState rtc;
|
||||||
GICState gic;
|
GICState gic;
|
||||||
|
|
|
@ -28,6 +28,10 @@
|
||||||
#include "qom/object.h"
|
#include "qom/object.h"
|
||||||
|
|
||||||
#define TYPE_AW_I2C "allwinner.i2c"
|
#define TYPE_AW_I2C "allwinner.i2c"
|
||||||
|
|
||||||
|
/** Allwinner I2C sun6i family and newer (A31, H2+, H3, etc) */
|
||||||
|
#define TYPE_AW_I2C_SUN6I TYPE_AW_I2C "-sun6i"
|
||||||
|
|
||||||
OBJECT_DECLARE_SIMPLE_TYPE(AWI2CState, AW_I2C)
|
OBJECT_DECLARE_SIMPLE_TYPE(AWI2CState, AW_I2C)
|
||||||
|
|
||||||
#define AW_I2C_MEM_SIZE 0x24
|
#define AW_I2C_MEM_SIZE 0x24
|
||||||
|
@ -50,6 +54,8 @@ struct AWI2CState {
|
||||||
uint8_t srst;
|
uint8_t srst;
|
||||||
uint8_t efr;
|
uint8_t efr;
|
||||||
uint8_t lcr;
|
uint8_t lcr;
|
||||||
|
|
||||||
|
bool irq_clear_inverted;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* ALLWINNER_I2C_H */
|
#endif /* ALLWINNER_I2C_H */
|
||||||
|
|
|
@ -86,6 +86,25 @@ ssize_t load_image_gzipped_buffer(const char *filename, uint64_t max_sz,
|
||||||
uint8_t **buffer);
|
uint8_t **buffer);
|
||||||
ssize_t load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz);
|
ssize_t load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unpack_efi_zboot_image:
|
||||||
|
* @buffer: pointer to a variable holding the address of a buffer containing the
|
||||||
|
* image
|
||||||
|
* @size: pointer to a variable holding the size of the buffer
|
||||||
|
*
|
||||||
|
* Check whether the buffer contains a EFI zboot image, and if it does, extract
|
||||||
|
* the compressed payload and decompress it into a new buffer. If successful,
|
||||||
|
* the old buffer is freed, and the *buffer and size variables pointed to by the
|
||||||
|
* function arguments are updated to refer to the newly populated buffer.
|
||||||
|
*
|
||||||
|
* Returns 0 if the image could not be identified as a EFI zboot image.
|
||||||
|
* Returns -1 if the buffer contents were identified as a EFI zboot image, but
|
||||||
|
* unpacking failed for any reason.
|
||||||
|
* Returns the size of the decompressed payload if decompression was performed
|
||||||
|
* successfully.
|
||||||
|
*/
|
||||||
|
ssize_t unpack_efi_zboot_image(uint8_t **buffer, int *size);
|
||||||
|
|
||||||
#define ELF_LOAD_FAILED -1
|
#define ELF_LOAD_FAILED -1
|
||||||
#define ELF_LOAD_NOT_ELF -2
|
#define ELF_LOAD_NOT_ELF -2
|
||||||
#define ELF_LOAD_WRONG_ARCH -3
|
#define ELF_LOAD_WRONG_ARCH -3
|
||||||
|
|
|
@ -869,6 +869,8 @@ struct ArchCPU {
|
||||||
|
|
||||||
DynamicGDBXMLInfo dyn_sysreg_xml;
|
DynamicGDBXMLInfo dyn_sysreg_xml;
|
||||||
DynamicGDBXMLInfo dyn_svereg_xml;
|
DynamicGDBXMLInfo dyn_svereg_xml;
|
||||||
|
DynamicGDBXMLInfo dyn_m_systemreg_xml;
|
||||||
|
DynamicGDBXMLInfo dyn_m_secextreg_xml;
|
||||||
|
|
||||||
/* Timers used by the generic (architected) timer */
|
/* Timers used by the generic (architected) timer */
|
||||||
QEMUTimer *gt_timer[NUM_GTIMERS];
|
QEMUTimer *gt_timer[NUM_GTIMERS];
|
||||||
|
@ -1112,13 +1114,6 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
|
||||||
int arm_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
int arm_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
/*
|
|
||||||
* Helpers to dynamically generates XML descriptions of the sysregs
|
|
||||||
* and SVE registers. Returns the number of registers in each set.
|
|
||||||
*/
|
|
||||||
int arm_gen_dynamic_sysreg_xml(CPUState *cpu, int base_reg);
|
|
||||||
int arm_gen_dynamic_svereg_xml(CPUState *cpu, int base_reg);
|
|
||||||
|
|
||||||
/* Returns the dynamically generated XML for the gdb stub.
|
/* Returns the dynamically generated XML for the gdb stub.
|
||||||
* Returns a pointer to the XML contents for the specified XML file or NULL
|
* Returns a pointer to the XML contents for the specified XML file or NULL
|
||||||
* if the XML name doesn't match the predefined one.
|
* if the XML name doesn't match the predefined one.
|
||||||
|
@ -2389,7 +2384,8 @@ static inline int arm_feature(CPUARMState *env, int feature)
|
||||||
void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp);
|
void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp);
|
||||||
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
/* Return true if exception levels below EL3 are in secure state,
|
/*
|
||||||
|
* Return true if exception levels below EL3 are in secure state,
|
||||||
* or would be following an exception return to that level.
|
* or would be following an exception return to that level.
|
||||||
* Unlike arm_is_secure() (which is always a question about the
|
* Unlike arm_is_secure() (which is always a question about the
|
||||||
* _current_ state of the CPU) this doesn't care about the current
|
* _current_ state of the CPU) this doesn't care about the current
|
||||||
|
@ -2397,6 +2393,7 @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp);
|
||||||
*/
|
*/
|
||||||
static inline bool arm_is_secure_below_el3(CPUARMState *env)
|
static inline bool arm_is_secure_below_el3(CPUARMState *env)
|
||||||
{
|
{
|
||||||
|
assert(!arm_feature(env, ARM_FEATURE_M));
|
||||||
if (arm_feature(env, ARM_FEATURE_EL3)) {
|
if (arm_feature(env, ARM_FEATURE_EL3)) {
|
||||||
return !(env->cp15.scr_el3 & SCR_NS);
|
return !(env->cp15.scr_el3 & SCR_NS);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2410,6 +2407,7 @@ static inline bool arm_is_secure_below_el3(CPUARMState *env)
|
||||||
/* Return true if the CPU is AArch64 EL3 or AArch32 Mon */
|
/* Return true if the CPU is AArch64 EL3 or AArch32 Mon */
|
||||||
static inline bool arm_is_el3_or_mon(CPUARMState *env)
|
static inline bool arm_is_el3_or_mon(CPUARMState *env)
|
||||||
{
|
{
|
||||||
|
assert(!arm_feature(env, ARM_FEATURE_M));
|
||||||
if (arm_feature(env, ARM_FEATURE_EL3)) {
|
if (arm_feature(env, ARM_FEATURE_EL3)) {
|
||||||
if (is_a64(env) && extract32(env->pstate, 2, 2) == 3) {
|
if (is_a64(env) && extract32(env->pstate, 2, 2) == 3) {
|
||||||
/* CPU currently in AArch64 state and EL3 */
|
/* CPU currently in AArch64 state and EL3 */
|
||||||
|
@ -2426,6 +2424,9 @@ static inline bool arm_is_el3_or_mon(CPUARMState *env)
|
||||||
/* Return true if the processor is in secure state */
|
/* Return true if the processor is in secure state */
|
||||||
static inline bool arm_is_secure(CPUARMState *env)
|
static inline bool arm_is_secure(CPUARMState *env)
|
||||||
{
|
{
|
||||||
|
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||||
|
return env->v7m.secure;
|
||||||
|
}
|
||||||
if (arm_is_el3_or_mon(env)) {
|
if (arm_is_el3_or_mon(env)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,7 +305,7 @@ static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg)
|
static int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = ARM_CPU(cs);
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
GString *s = g_string_new(NULL);
|
GString *s = g_string_new(NULL);
|
||||||
|
@ -322,125 +322,163 @@ int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg)
|
||||||
return cpu->dyn_sysreg_xml.num;
|
return cpu->dyn_sysreg_xml.num;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TypeSize {
|
typedef enum {
|
||||||
const char *gdb_type;
|
M_SYSREG_MSP,
|
||||||
int size;
|
M_SYSREG_PSP,
|
||||||
const char sz, suffix;
|
M_SYSREG_PRIMASK,
|
||||||
|
M_SYSREG_CONTROL,
|
||||||
|
M_SYSREG_BASEPRI,
|
||||||
|
M_SYSREG_FAULTMASK,
|
||||||
|
M_SYSREG_MSPLIM,
|
||||||
|
M_SYSREG_PSPLIM,
|
||||||
|
} MProfileSysreg;
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
const char *name;
|
||||||
|
int feature;
|
||||||
|
} m_sysreg_def[] = {
|
||||||
|
[M_SYSREG_MSP] = { "msp", ARM_FEATURE_M },
|
||||||
|
[M_SYSREG_PSP] = { "psp", ARM_FEATURE_M },
|
||||||
|
[M_SYSREG_PRIMASK] = { "primask", ARM_FEATURE_M },
|
||||||
|
[M_SYSREG_CONTROL] = { "control", ARM_FEATURE_M },
|
||||||
|
[M_SYSREG_BASEPRI] = { "basepri", ARM_FEATURE_M_MAIN },
|
||||||
|
[M_SYSREG_FAULTMASK] = { "faultmask", ARM_FEATURE_M_MAIN },
|
||||||
|
[M_SYSREG_MSPLIM] = { "msplim", ARM_FEATURE_V8 },
|
||||||
|
[M_SYSREG_PSPLIM] = { "psplim", ARM_FEATURE_V8 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct TypeSize vec_lanes[] = {
|
static uint32_t *m_sysreg_ptr(CPUARMState *env, MProfileSysreg reg, bool sec)
|
||||||
/* quads */
|
{
|
||||||
{ "uint128", 128, 'q', 'u' },
|
uint32_t *ptr;
|
||||||
{ "int128", 128, 'q', 's' },
|
|
||||||
/* 64 bit */
|
|
||||||
{ "ieee_double", 64, 'd', 'f' },
|
|
||||||
{ "uint64", 64, 'd', 'u' },
|
|
||||||
{ "int64", 64, 'd', 's' },
|
|
||||||
/* 32 bit */
|
|
||||||
{ "ieee_single", 32, 's', 'f' },
|
|
||||||
{ "uint32", 32, 's', 'u' },
|
|
||||||
{ "int32", 32, 's', 's' },
|
|
||||||
/* 16 bit */
|
|
||||||
{ "ieee_half", 16, 'h', 'f' },
|
|
||||||
{ "uint16", 16, 'h', 'u' },
|
|
||||||
{ "int16", 16, 'h', 's' },
|
|
||||||
/* bytes */
|
|
||||||
{ "uint8", 8, 'b', 'u' },
|
|
||||||
{ "int8", 8, 'b', 's' },
|
|
||||||
};
|
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
case M_SYSREG_MSP:
|
||||||
|
ptr = arm_v7m_get_sp_ptr(env, sec, false, true);
|
||||||
|
break;
|
||||||
|
case M_SYSREG_PSP:
|
||||||
|
ptr = arm_v7m_get_sp_ptr(env, sec, true, true);
|
||||||
|
break;
|
||||||
|
case M_SYSREG_MSPLIM:
|
||||||
|
ptr = &env->v7m.msplim[sec];
|
||||||
|
break;
|
||||||
|
case M_SYSREG_PSPLIM:
|
||||||
|
ptr = &env->v7m.psplim[sec];
|
||||||
|
break;
|
||||||
|
case M_SYSREG_PRIMASK:
|
||||||
|
ptr = &env->v7m.primask[sec];
|
||||||
|
break;
|
||||||
|
case M_SYSREG_BASEPRI:
|
||||||
|
ptr = &env->v7m.basepri[sec];
|
||||||
|
break;
|
||||||
|
case M_SYSREG_FAULTMASK:
|
||||||
|
ptr = &env->v7m.faultmask[sec];
|
||||||
|
break;
|
||||||
|
case M_SYSREG_CONTROL:
|
||||||
|
ptr = &env->v7m.control[sec];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return arm_feature(env, m_sysreg_def[reg].feature) ? ptr : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int arm_gen_dynamic_svereg_xml(CPUState *cs, int base_reg)
|
static int m_sysreg_get(CPUARMState *env, GByteArray *buf,
|
||||||
|
MProfileSysreg reg, bool secure)
|
||||||
|
{
|
||||||
|
uint32_t *ptr = m_sysreg_ptr(env, reg, secure);
|
||||||
|
|
||||||
|
if (ptr == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return gdb_get_reg32(buf, *ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int arm_gdb_get_m_systemreg(CPUARMState *env, GByteArray *buf, int reg)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Here, we emulate MRS instruction, where CONTROL has a mix of
|
||||||
|
* banked and non-banked bits.
|
||||||
|
*/
|
||||||
|
if (reg == M_SYSREG_CONTROL) {
|
||||||
|
return gdb_get_reg32(buf, arm_v7m_mrs_control(env, env->v7m.secure));
|
||||||
|
}
|
||||||
|
return m_sysreg_get(env, buf, reg, env->v7m.secure);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int arm_gdb_set_m_systemreg(CPUARMState *env, uint8_t *buf, int reg)
|
||||||
|
{
|
||||||
|
return 0; /* TODO */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int arm_gen_dynamic_m_systemreg_xml(CPUState *cs, int orig_base_reg)
|
||||||
|
{
|
||||||
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
|
CPUARMState *env = &cpu->env;
|
||||||
|
GString *s = g_string_new(NULL);
|
||||||
|
int base_reg = orig_base_reg;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
g_string_printf(s, "<?xml version=\"1.0\"?>");
|
||||||
|
g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
|
||||||
|
g_string_append_printf(s, "<feature name=\"org.gnu.gdb.arm.m-system\">\n");
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) {
|
||||||
|
if (arm_feature(env, m_sysreg_def[i].feature)) {
|
||||||
|
g_string_append_printf(s,
|
||||||
|
"<reg name=\"%s\" bitsize=\"32\" regnum=\"%d\"/>\n",
|
||||||
|
m_sysreg_def[i].name, base_reg++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append_printf(s, "</feature>");
|
||||||
|
cpu->dyn_m_systemreg_xml.desc = g_string_free(s, false);
|
||||||
|
cpu->dyn_m_systemreg_xml.num = base_reg - orig_base_reg;
|
||||||
|
|
||||||
|
return cpu->dyn_m_systemreg_xml.num;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
/*
|
||||||
|
* For user-only, we see the non-secure registers via m_systemreg above.
|
||||||
|
* For secext, encode the non-secure view as even and secure view as odd.
|
||||||
|
*/
|
||||||
|
static int arm_gdb_get_m_secextreg(CPUARMState *env, GByteArray *buf, int reg)
|
||||||
|
{
|
||||||
|
return m_sysreg_get(env, buf, reg >> 1, reg & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int arm_gdb_set_m_secextreg(CPUARMState *env, uint8_t *buf, int reg)
|
||||||
|
{
|
||||||
|
return 0; /* TODO */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int arm_gen_dynamic_m_secextreg_xml(CPUState *cs, int orig_base_reg)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = ARM_CPU(cs);
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
GString *s = g_string_new(NULL);
|
GString *s = g_string_new(NULL);
|
||||||
DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml;
|
int base_reg = orig_base_reg;
|
||||||
g_autoptr(GString) ts = g_string_new("");
|
int i;
|
||||||
int i, j, bits, reg_width = (cpu->sve_max_vq * 128);
|
|
||||||
info->num = 0;
|
|
||||||
g_string_printf(s, "<?xml version=\"1.0\"?>");
|
g_string_printf(s, "<?xml version=\"1.0\"?>");
|
||||||
g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
|
g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
|
||||||
g_string_append_printf(s, "<feature name=\"org.gnu.gdb.aarch64.sve\">");
|
g_string_append_printf(s, "<feature name=\"org.gnu.gdb.arm.secext\">\n");
|
||||||
|
|
||||||
/* First define types and totals in a whole VL */
|
for (i = 0; i < ARRAY_SIZE(m_sysreg_def); i++) {
|
||||||
for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
|
|
||||||
int count = reg_width / vec_lanes[i].size;
|
|
||||||
g_string_printf(ts, "svev%c%c", vec_lanes[i].sz, vec_lanes[i].suffix);
|
|
||||||
g_string_append_printf(s,
|
g_string_append_printf(s,
|
||||||
"<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
|
"<reg name=\"%s_ns\" bitsize=\"32\" regnum=\"%d\"/>\n",
|
||||||
ts->str, vec_lanes[i].gdb_type, count);
|
m_sysreg_def[i].name, base_reg++);
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Now define a union for each size group containing unsigned and
|
|
||||||
* signed and potentially float versions of each size from 128 to
|
|
||||||
* 8 bits.
|
|
||||||
*/
|
|
||||||
for (bits = 128, i = 0; bits >= 8; bits /= 2, i++) {
|
|
||||||
const char suf[] = { 'q', 'd', 's', 'h', 'b' };
|
|
||||||
g_string_append_printf(s, "<union id=\"svevn%c\">", suf[i]);
|
|
||||||
for (j = 0; j < ARRAY_SIZE(vec_lanes); j++) {
|
|
||||||
if (vec_lanes[j].size == bits) {
|
|
||||||
g_string_append_printf(s, "<field name=\"%c\" type=\"svev%c%c\"/>",
|
|
||||||
vec_lanes[j].suffix,
|
|
||||||
vec_lanes[j].sz, vec_lanes[j].suffix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_string_append(s, "</union>");
|
|
||||||
}
|
|
||||||
/* And now the final union of unions */
|
|
||||||
g_string_append(s, "<union id=\"svev\">");
|
|
||||||
for (bits = 128, i = 0; bits >= 8; bits /= 2, i++) {
|
|
||||||
const char suf[] = { 'q', 'd', 's', 'h', 'b' };
|
|
||||||
g_string_append_printf(s, "<field name=\"%c\" type=\"svevn%c\"/>",
|
|
||||||
suf[i], suf[i]);
|
|
||||||
}
|
|
||||||
g_string_append(s, "</union>");
|
|
||||||
|
|
||||||
/* Finally the sve prefix type */
|
|
||||||
g_string_append_printf(s,
|
|
||||||
"<vector id=\"svep\" type=\"uint8\" count=\"%d\"/>",
|
|
||||||
reg_width / 8);
|
|
||||||
|
|
||||||
/* Then define each register in parts for each vq */
|
|
||||||
for (i = 0; i < 32; i++) {
|
|
||||||
g_string_append_printf(s,
|
g_string_append_printf(s,
|
||||||
"<reg name=\"z%d\" bitsize=\"%d\""
|
"<reg name=\"%s_s\" bitsize=\"32\" regnum=\"%d\"/>\n",
|
||||||
" regnum=\"%d\" type=\"svev\"/>",
|
m_sysreg_def[i].name, base_reg++);
|
||||||
i, reg_width, base_reg++);
|
|
||||||
info->num++;
|
|
||||||
}
|
}
|
||||||
/* fpscr & status registers */
|
|
||||||
g_string_append_printf(s, "<reg name=\"fpsr\" bitsize=\"32\""
|
|
||||||
" regnum=\"%d\" group=\"float\""
|
|
||||||
" type=\"int\"/>", base_reg++);
|
|
||||||
g_string_append_printf(s, "<reg name=\"fpcr\" bitsize=\"32\""
|
|
||||||
" regnum=\"%d\" group=\"float\""
|
|
||||||
" type=\"int\"/>", base_reg++);
|
|
||||||
info->num += 2;
|
|
||||||
|
|
||||||
for (i = 0; i < 16; i++) {
|
|
||||||
g_string_append_printf(s,
|
|
||||||
"<reg name=\"p%d\" bitsize=\"%d\""
|
|
||||||
" regnum=\"%d\" type=\"svep\"/>",
|
|
||||||
i, cpu->sve_max_vq * 16, base_reg++);
|
|
||||||
info->num++;
|
|
||||||
}
|
|
||||||
g_string_append_printf(s,
|
|
||||||
"<reg name=\"ffr\" bitsize=\"%d\""
|
|
||||||
" regnum=\"%d\" group=\"vector\""
|
|
||||||
" type=\"svep\"/>",
|
|
||||||
cpu->sve_max_vq * 16, base_reg++);
|
|
||||||
g_string_append_printf(s,
|
|
||||||
"<reg name=\"vg\" bitsize=\"64\""
|
|
||||||
" regnum=\"%d\" type=\"int\"/>",
|
|
||||||
base_reg++);
|
|
||||||
info->num += 2;
|
|
||||||
g_string_append_printf(s, "</feature>");
|
g_string_append_printf(s, "</feature>");
|
||||||
cpu->dyn_svereg_xml.desc = g_string_free(s, false);
|
cpu->dyn_m_secextreg_xml.desc = g_string_free(s, false);
|
||||||
|
cpu->dyn_m_secextreg_xml.num = base_reg - orig_base_reg;
|
||||||
|
|
||||||
return cpu->dyn_svereg_xml.num;
|
return cpu->dyn_m_secextreg_xml.num;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
|
const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
|
||||||
{
|
{
|
||||||
|
@ -450,6 +488,12 @@ const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
|
||||||
return cpu->dyn_sysreg_xml.desc;
|
return cpu->dyn_sysreg_xml.desc;
|
||||||
} else if (strcmp(xmlname, "sve-registers.xml") == 0) {
|
} else if (strcmp(xmlname, "sve-registers.xml") == 0) {
|
||||||
return cpu->dyn_svereg_xml.desc;
|
return cpu->dyn_svereg_xml.desc;
|
||||||
|
} else if (strcmp(xmlname, "arm-m-system.xml") == 0) {
|
||||||
|
return cpu->dyn_m_systemreg_xml.desc;
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
} else if (strcmp(xmlname, "arm-m-secext.xml") == 0) {
|
||||||
|
return cpu->dyn_m_secextreg_xml.desc;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -466,14 +510,20 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
|
||||||
*/
|
*/
|
||||||
#ifdef TARGET_AARCH64
|
#ifdef TARGET_AARCH64
|
||||||
if (isar_feature_aa64_sve(&cpu->isar)) {
|
if (isar_feature_aa64_sve(&cpu->isar)) {
|
||||||
gdb_register_coprocessor(cs, arm_gdb_get_svereg, arm_gdb_set_svereg,
|
int nreg = arm_gen_dynamic_svereg_xml(cs, cs->gdb_num_regs);
|
||||||
arm_gen_dynamic_svereg_xml(cs, cs->gdb_num_regs),
|
gdb_register_coprocessor(cs, aarch64_gdb_get_sve_reg,
|
||||||
|
aarch64_gdb_set_sve_reg, nreg,
|
||||||
"sve-registers.xml", 0);
|
"sve-registers.xml", 0);
|
||||||
} else {
|
} else {
|
||||||
gdb_register_coprocessor(cs, aarch64_fpu_gdb_get_reg,
|
gdb_register_coprocessor(cs, aarch64_gdb_get_fpu_reg,
|
||||||
aarch64_fpu_gdb_set_reg,
|
aarch64_gdb_set_fpu_reg,
|
||||||
34, "aarch64-fpu.xml", 0);
|
34, "aarch64-fpu.xml", 0);
|
||||||
}
|
}
|
||||||
|
if (isar_feature_aa64_pauth(&cpu->isar)) {
|
||||||
|
gdb_register_coprocessor(cs, aarch64_gdb_get_pauth_reg,
|
||||||
|
aarch64_gdb_set_pauth_reg,
|
||||||
|
4, "aarch64-pauth.xml", 0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
if (arm_feature(env, ARM_FEATURE_NEON)) {
|
if (arm_feature(env, ARM_FEATURE_NEON)) {
|
||||||
|
@ -503,4 +553,18 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
|
||||||
arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs),
|
arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs),
|
||||||
"system-registers.xml", 0);
|
"system-registers.xml", 0);
|
||||||
|
|
||||||
|
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||||
|
gdb_register_coprocessor(cs,
|
||||||
|
arm_gdb_get_m_systemreg, arm_gdb_set_m_systemreg,
|
||||||
|
arm_gen_dynamic_m_systemreg_xml(cs, cs->gdb_num_regs),
|
||||||
|
"arm-m-system.xml", 0);
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||||
|
gdb_register_coprocessor(cs,
|
||||||
|
arm_gdb_get_m_secextreg, arm_gdb_set_m_secextreg,
|
||||||
|
arm_gen_dynamic_m_secextreg_xml(cs, cs->gdb_num_regs),
|
||||||
|
"arm-m-secext.xml", 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ int aarch64_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int aarch64_fpu_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
|
int aarch64_gdb_get_fpu_reg(CPUARMState *env, GByteArray *buf, int reg)
|
||||||
{
|
{
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case 0 ... 31:
|
case 0 ... 31:
|
||||||
|
@ -92,7 +92,7 @@ int aarch64_fpu_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int aarch64_fpu_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
|
int aarch64_gdb_set_fpu_reg(CPUARMState *env, uint8_t *buf, int reg)
|
||||||
{
|
{
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case 0 ... 31:
|
case 0 ... 31:
|
||||||
|
@ -116,7 +116,7 @@ int aarch64_fpu_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int arm_gdb_get_svereg(CPUARMState *env, GByteArray *buf, int reg)
|
int aarch64_gdb_get_sve_reg(CPUARMState *env, GByteArray *buf, int reg)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = env_archcpu(env);
|
ARMCPU *cpu = env_archcpu(env);
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ int arm_gdb_get_svereg(CPUARMState *env, GByteArray *buf, int reg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int arm_gdb_set_svereg(CPUARMState *env, uint8_t *buf, int reg)
|
int aarch64_gdb_set_sve_reg(CPUARMState *env, uint8_t *buf, int reg)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = env_archcpu(env);
|
ARMCPU *cpu = env_archcpu(env);
|
||||||
|
|
||||||
|
@ -209,3 +209,170 @@ int arm_gdb_set_svereg(CPUARMState *env, uint8_t *buf, int reg)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int aarch64_gdb_get_pauth_reg(CPUARMState *env, GByteArray *buf, int reg)
|
||||||
|
{
|
||||||
|
switch (reg) {
|
||||||
|
case 0: /* pauth_dmask */
|
||||||
|
case 1: /* pauth_cmask */
|
||||||
|
case 2: /* pauth_dmask_high */
|
||||||
|
case 3: /* pauth_cmask_high */
|
||||||
|
/*
|
||||||
|
* Note that older versions of this feature only contained
|
||||||
|
* pauth_{d,c}mask, for use with Linux user processes, and
|
||||||
|
* thus exclusively in the low half of the address space.
|
||||||
|
*
|
||||||
|
* To support system mode, and to debug kernels, two new regs
|
||||||
|
* were added to cover the high half of the address space.
|
||||||
|
* For the purpose of pauth_ptr_mask, we can use any well-formed
|
||||||
|
* address within the address space half -- here, 0 and -1.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
bool is_data = !(reg & 1);
|
||||||
|
bool is_high = reg & 2;
|
||||||
|
uint64_t mask = pauth_ptr_mask(env, -is_high, is_data);
|
||||||
|
return gdb_get_reg64(buf, mask);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int aarch64_gdb_set_pauth_reg(CPUARMState *env, uint8_t *buf, int reg)
|
||||||
|
{
|
||||||
|
/* All pseudo registers are read-only. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void output_vector_union_type(GString *s, int reg_width,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct TypeSize {
|
||||||
|
const char *gdb_type;
|
||||||
|
short size;
|
||||||
|
char sz, suffix;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct TypeSize vec_lanes[] = {
|
||||||
|
/* quads */
|
||||||
|
{ "uint128", 128, 'q', 'u' },
|
||||||
|
{ "int128", 128, 'q', 's' },
|
||||||
|
/* 64 bit */
|
||||||
|
{ "ieee_double", 64, 'd', 'f' },
|
||||||
|
{ "uint64", 64, 'd', 'u' },
|
||||||
|
{ "int64", 64, 'd', 's' },
|
||||||
|
/* 32 bit */
|
||||||
|
{ "ieee_single", 32, 's', 'f' },
|
||||||
|
{ "uint32", 32, 's', 'u' },
|
||||||
|
{ "int32", 32, 's', 's' },
|
||||||
|
/* 16 bit */
|
||||||
|
{ "ieee_half", 16, 'h', 'f' },
|
||||||
|
{ "uint16", 16, 'h', 'u' },
|
||||||
|
{ "int16", 16, 'h', 's' },
|
||||||
|
/* bytes */
|
||||||
|
{ "uint8", 8, 'b', 'u' },
|
||||||
|
{ "int8", 8, 'b', 's' },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char suf[] = { 'b', 'h', 's', 'd', 'q' };
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
/* First define types and totals in a whole VL */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
|
||||||
|
g_string_append_printf(s,
|
||||||
|
"<vector id=\"%s%c%c\" type=\"%s\" count=\"%d\"/>",
|
||||||
|
name, vec_lanes[i].sz, vec_lanes[i].suffix,
|
||||||
|
vec_lanes[i].gdb_type, reg_width / vec_lanes[i].size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now define a union for each size group containing unsigned and
|
||||||
|
* signed and potentially float versions of each size from 128 to
|
||||||
|
* 8 bits.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ARRAY_SIZE(suf); i++) {
|
||||||
|
int bits = 8 << i;
|
||||||
|
|
||||||
|
g_string_append_printf(s, "<union id=\"%sn%c\">", name, suf[i]);
|
||||||
|
for (j = 0; j < ARRAY_SIZE(vec_lanes); j++) {
|
||||||
|
if (vec_lanes[j].size == bits) {
|
||||||
|
g_string_append_printf(s, "<field name=\"%c\" type=\"%s%c%c\"/>",
|
||||||
|
vec_lanes[j].suffix, name,
|
||||||
|
vec_lanes[j].sz, vec_lanes[j].suffix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_string_append(s, "</union>");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And now the final union of unions */
|
||||||
|
g_string_append_printf(s, "<union id=\"%s\">", name);
|
||||||
|
for (i = ARRAY_SIZE(suf) - 1; i >= 0; i--) {
|
||||||
|
g_string_append_printf(s, "<field name=\"%c\" type=\"%sn%c\"/>",
|
||||||
|
suf[i], name, suf[i]);
|
||||||
|
}
|
||||||
|
g_string_append(s, "</union>");
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm_gen_dynamic_svereg_xml(CPUState *cs, int orig_base_reg)
|
||||||
|
{
|
||||||
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
|
GString *s = g_string_new(NULL);
|
||||||
|
DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml;
|
||||||
|
int reg_width = cpu->sve_max_vq * 128;
|
||||||
|
int pred_width = cpu->sve_max_vq * 16;
|
||||||
|
int base_reg = orig_base_reg;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
g_string_printf(s, "<?xml version=\"1.0\"?>");
|
||||||
|
g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
|
||||||
|
g_string_append_printf(s, "<feature name=\"org.gnu.gdb.aarch64.sve\">");
|
||||||
|
|
||||||
|
/* Create the vector union type. */
|
||||||
|
output_vector_union_type(s, reg_width, "svev");
|
||||||
|
|
||||||
|
/* Create the predicate vector type. */
|
||||||
|
g_string_append_printf(s,
|
||||||
|
"<vector id=\"svep\" type=\"uint8\" count=\"%d\"/>",
|
||||||
|
pred_width / 8);
|
||||||
|
|
||||||
|
/* Define the vector registers. */
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
g_string_append_printf(s,
|
||||||
|
"<reg name=\"z%d\" bitsize=\"%d\""
|
||||||
|
" regnum=\"%d\" type=\"svev\"/>",
|
||||||
|
i, reg_width, base_reg++);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fpscr & status registers */
|
||||||
|
g_string_append_printf(s, "<reg name=\"fpsr\" bitsize=\"32\""
|
||||||
|
" regnum=\"%d\" group=\"float\""
|
||||||
|
" type=\"int\"/>", base_reg++);
|
||||||
|
g_string_append_printf(s, "<reg name=\"fpcr\" bitsize=\"32\""
|
||||||
|
" regnum=\"%d\" group=\"float\""
|
||||||
|
" type=\"int\"/>", base_reg++);
|
||||||
|
|
||||||
|
/* Define the predicate registers. */
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
g_string_append_printf(s,
|
||||||
|
"<reg name=\"p%d\" bitsize=\"%d\""
|
||||||
|
" regnum=\"%d\" type=\"svep\"/>",
|
||||||
|
i, pred_width, base_reg++);
|
||||||
|
}
|
||||||
|
g_string_append_printf(s,
|
||||||
|
"<reg name=\"ffr\" bitsize=\"%d\""
|
||||||
|
" regnum=\"%d\" group=\"vector\""
|
||||||
|
" type=\"svep\"/>",
|
||||||
|
pred_width, base_reg++);
|
||||||
|
|
||||||
|
/* Define the vector length pseudo-register. */
|
||||||
|
g_string_append_printf(s,
|
||||||
|
"<reg name=\"vg\" bitsize=\"64\""
|
||||||
|
" regnum=\"%d\" type=\"int\"/>",
|
||||||
|
base_reg++);
|
||||||
|
|
||||||
|
g_string_append_printf(s, "</feature>");
|
||||||
|
|
||||||
|
info->desc = g_string_free(s, false);
|
||||||
|
info->num = base_reg - orig_base_reg;
|
||||||
|
return info->num;
|
||||||
|
}
|
||||||
|
|
|
@ -5787,6 +5787,9 @@ uint64_t arm_hcr_el2_eff_secstate(CPUARMState *env, bool secure)
|
||||||
|
|
||||||
uint64_t arm_hcr_el2_eff(CPUARMState *env)
|
uint64_t arm_hcr_el2_eff(CPUARMState *env)
|
||||||
{
|
{
|
||||||
|
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return arm_hcr_el2_eff_secstate(env, arm_is_secure_below_el3(env));
|
return arm_hcr_el2_eff_secstate(env, arm_is_secure_below_el3(env));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1344,16 +1344,32 @@ static inline uint64_t pmu_counter_mask(CPUARMState *env)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TARGET_AARCH64
|
#ifdef TARGET_AARCH64
|
||||||
int arm_gdb_get_svereg(CPUARMState *env, GByteArray *buf, int reg);
|
int arm_gen_dynamic_svereg_xml(CPUState *cpu, int base_reg);
|
||||||
int arm_gdb_set_svereg(CPUARMState *env, uint8_t *buf, int reg);
|
int aarch64_gdb_get_sve_reg(CPUARMState *env, GByteArray *buf, int reg);
|
||||||
int aarch64_fpu_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg);
|
int aarch64_gdb_set_sve_reg(CPUARMState *env, uint8_t *buf, int reg);
|
||||||
int aarch64_fpu_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg);
|
int aarch64_gdb_get_fpu_reg(CPUARMState *env, GByteArray *buf, int reg);
|
||||||
|
int aarch64_gdb_set_fpu_reg(CPUARMState *env, uint8_t *buf, int reg);
|
||||||
|
int aarch64_gdb_get_pauth_reg(CPUARMState *env, GByteArray *buf, int reg);
|
||||||
|
int aarch64_gdb_set_pauth_reg(CPUARMState *env, uint8_t *buf, int reg);
|
||||||
void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp);
|
void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp);
|
||||||
void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp);
|
void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp);
|
||||||
void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp);
|
void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp);
|
||||||
void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp);
|
void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Read the CONTROL register as the MRS instruction would. */
|
||||||
|
uint32_t arm_v7m_mrs_control(CPUARMState *env, uint32_t secure);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return a pointer to the location where we currently store the
|
||||||
|
* stack pointer for the requested security state and thread mode.
|
||||||
|
* This pointer will become invalid if the CPU state is updated
|
||||||
|
* such that the stack pointers are switched around (eg changing
|
||||||
|
* the SPSEL control bit).
|
||||||
|
*/
|
||||||
|
uint32_t *arm_v7m_get_sp_ptr(CPUARMState *env, bool secure,
|
||||||
|
bool threadmode, bool spsel);
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
static inline void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) { }
|
static inline void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) { }
|
||||||
#else
|
#else
|
||||||
|
@ -1367,6 +1383,16 @@ int exception_target_el(CPUARMState *env);
|
||||||
bool arm_singlestep_active(CPUARMState *env);
|
bool arm_singlestep_active(CPUARMState *env);
|
||||||
bool arm_generate_debug_exceptions(CPUARMState *env);
|
bool arm_generate_debug_exceptions(CPUARMState *env);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pauth_ptr_mask:
|
||||||
|
* @env: cpu context
|
||||||
|
* @ptr: selects between TTBR0 and TTBR1
|
||||||
|
* @data: selects between TBI and TBID
|
||||||
|
*
|
||||||
|
* Return a mask of the bits of @ptr that contain the authentication code.
|
||||||
|
*/
|
||||||
|
uint64_t pauth_ptr_mask(CPUARMState *env, uint64_t ptr, bool data);
|
||||||
|
|
||||||
/* Add the cpreg definitions for debug related system registers */
|
/* Add the cpreg definitions for debug related system registers */
|
||||||
void define_debug_regs(ARMCPU *cpu);
|
void define_debug_regs(ARMCPU *cpu);
|
||||||
|
|
||||||
|
|
173
target/arm/ptw.c
173
target/arm/ptw.c
|
@ -1081,70 +1081,119 @@ static ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va,
|
||||||
* check_s2_mmu_setup
|
* check_s2_mmu_setup
|
||||||
* @cpu: ARMCPU
|
* @cpu: ARMCPU
|
||||||
* @is_aa64: True if the translation regime is in AArch64 state
|
* @is_aa64: True if the translation regime is in AArch64 state
|
||||||
* @startlevel: Suggested starting level
|
* @tcr: VTCR_EL2 or VSTCR_EL2
|
||||||
* @inputsize: Bitsize of IPAs
|
* @ds: Effective value of TCR.DS.
|
||||||
|
* @iasize: Bitsize of IPAs
|
||||||
* @stride: Page-table stride (See the ARM ARM)
|
* @stride: Page-table stride (See the ARM ARM)
|
||||||
*
|
*
|
||||||
* Returns true if the suggested S2 translation parameters are OK and
|
* Decode the starting level of the S2 lookup, returning INT_MIN if
|
||||||
* false otherwise.
|
* the configuration is invalid.
|
||||||
*/
|
*/
|
||||||
static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level,
|
static int check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, uint64_t tcr,
|
||||||
int inputsize, int stride, int outputsize)
|
bool ds, int iasize, int stride)
|
||||||
{
|
{
|
||||||
const int grainsize = stride + 3;
|
int sl0, sl2, startlevel, granulebits, levels;
|
||||||
int startsizecheck;
|
int s1_min_iasize, s1_max_iasize;
|
||||||
|
|
||||||
/*
|
|
||||||
* Negative levels are usually not allowed...
|
|
||||||
* Except for FEAT_LPA2, 4k page table, 52-bit address space, which
|
|
||||||
* begins with level -1. Note that previous feature tests will have
|
|
||||||
* eliminated this combination if it is not enabled.
|
|
||||||
*/
|
|
||||||
if (level < (inputsize == 52 && stride == 9 ? -1 : 0)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
startsizecheck = inputsize - ((3 - level) * stride + grainsize);
|
|
||||||
if (startsizecheck < 1 || startsizecheck > stride + 4) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
sl0 = extract32(tcr, 6, 2);
|
||||||
if (is_aa64) {
|
if (is_aa64) {
|
||||||
|
/*
|
||||||
|
* AArch64.S2InvalidTxSZ: While we checked tsz_oob near the top of
|
||||||
|
* get_phys_addr_lpae, that used aa64_va_parameters which apply
|
||||||
|
* to aarch64. If Stage1 is aarch32, the min_txsz is larger.
|
||||||
|
* See AArch64.S2MinTxSZ, where min_tsz is 24, translated to
|
||||||
|
* inputsize is 64 - 24 = 40.
|
||||||
|
*/
|
||||||
|
if (iasize < 40 && !arm_el_is_aa64(&cpu->env, 1)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AArch64.S2InvalidSL: Interpretation of SL depends on the page size,
|
||||||
|
* so interleave AArch64.S2StartLevel.
|
||||||
|
*/
|
||||||
switch (stride) {
|
switch (stride) {
|
||||||
case 13: /* 64KB Pages. */
|
case 9: /* 4KB */
|
||||||
if (level == 0 || (level == 1 && outputsize <= 42)) {
|
/* SL2 is RES0 unless DS=1 & 4KB granule. */
|
||||||
return false;
|
sl2 = extract64(tcr, 33, 1);
|
||||||
|
if (ds && sl2) {
|
||||||
|
if (sl0 != 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
startlevel = -1;
|
||||||
|
} else {
|
||||||
|
startlevel = 2 - sl0;
|
||||||
|
switch (sl0) {
|
||||||
|
case 2:
|
||||||
|
if (arm_pamax(cpu) < 44) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (!cpu_isar_feature(aa64_st, cpu)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
startlevel = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 11: /* 16KB Pages. */
|
case 11: /* 16KB */
|
||||||
if (level == 0 || (level == 1 && outputsize <= 40)) {
|
switch (sl0) {
|
||||||
return false;
|
case 2:
|
||||||
|
if (arm_pamax(cpu) < 42) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (!ds) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
startlevel = 3 - sl0;
|
||||||
break;
|
break;
|
||||||
case 9: /* 4KB Pages. */
|
case 13: /* 64KB */
|
||||||
if (level == 0 && outputsize <= 42) {
|
switch (sl0) {
|
||||||
return false;
|
case 2:
|
||||||
|
if (arm_pamax(cpu) < 44) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
startlevel = 3 - sl0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inputsize checks. */
|
|
||||||
if (inputsize > outputsize &&
|
|
||||||
(arm_el_is_aa64(&cpu->env, 1) || inputsize > 40)) {
|
|
||||||
/* This is CONSTRAINED UNPREDICTABLE and we choose to fault. */
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* AArch32 only supports 4KB pages. Assert on that. */
|
/*
|
||||||
|
* Things are simpler for AArch32 EL2, with only 4k pages.
|
||||||
|
* There is no separate S2InvalidSL function, but AArch32.S2Walk
|
||||||
|
* begins with walkparms.sl0 in {'1x'}.
|
||||||
|
*/
|
||||||
assert(stride == 9);
|
assert(stride == 9);
|
||||||
|
if (sl0 >= 2) {
|
||||||
if (level == 0) {
|
goto fail;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
startlevel = 2 - sl0;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
/* AArch{64,32}.S2InconsistentSL are functionally equivalent. */
|
||||||
|
levels = 3 - startlevel;
|
||||||
|
granulebits = stride + 3;
|
||||||
|
|
||||||
|
s1_min_iasize = levels * stride + granulebits + 1;
|
||||||
|
s1_max_iasize = s1_min_iasize + (stride - 1) + 4;
|
||||||
|
|
||||||
|
if (iasize >= s1_min_iasize && iasize <= s1_max_iasize) {
|
||||||
|
return startlevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return INT_MIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1300,38 +1349,10 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
|
||||||
*/
|
*/
|
||||||
level = 4 - (inputsize - 4) / stride;
|
level = 4 - (inputsize - 4) / stride;
|
||||||
} else {
|
} else {
|
||||||
/*
|
int startlevel = check_s2_mmu_setup(cpu, aarch64, tcr, param.ds,
|
||||||
* For stage 2 translations the starting level is specified by the
|
inputsize, stride);
|
||||||
* VTCR_EL2.SL0 field (whose interpretation depends on the page size)
|
if (startlevel == INT_MIN) {
|
||||||
*/
|
level = 0;
|
||||||
uint32_t sl0 = extract32(tcr, 6, 2);
|
|
||||||
uint32_t sl2 = extract64(tcr, 33, 1);
|
|
||||||
int32_t startlevel;
|
|
||||||
bool ok;
|
|
||||||
|
|
||||||
/* SL2 is RES0 unless DS=1 & 4kb granule. */
|
|
||||||
if (param.ds && stride == 9 && sl2) {
|
|
||||||
if (sl0 != 0) {
|
|
||||||
level = 0;
|
|
||||||
goto do_translation_fault;
|
|
||||||
}
|
|
||||||
startlevel = -1;
|
|
||||||
} else if (!aarch64 || stride == 9) {
|
|
||||||
/* AArch32 or 4KB pages */
|
|
||||||
startlevel = 2 - sl0;
|
|
||||||
|
|
||||||
if (cpu_isar_feature(aa64_st, cpu)) {
|
|
||||||
startlevel &= 3;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* 16KB or 64KB pages */
|
|
||||||
startlevel = 3 - sl0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check that the starting level is valid. */
|
|
||||||
ok = check_s2_mmu_setup(cpu, aarch64, startlevel,
|
|
||||||
inputsize, stride, outputsize);
|
|
||||||
if (!ok) {
|
|
||||||
goto do_translation_fault;
|
goto do_translation_fault;
|
||||||
}
|
}
|
||||||
level = startlevel;
|
level = startlevel;
|
||||||
|
|
|
@ -56,7 +56,7 @@ static uint32_t v7m_mrs_xpsr(CPUARMState *env, uint32_t reg, unsigned el)
|
||||||
return xpsr_read(env) & mask;
|
return xpsr_read(env) & mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t v7m_mrs_control(CPUARMState *env, uint32_t secure)
|
uint32_t arm_v7m_mrs_control(CPUARMState *env, uint32_t secure)
|
||||||
{
|
{
|
||||||
uint32_t value = env->v7m.control[secure];
|
uint32_t value = env->v7m.control[secure];
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
|
||||||
case 0 ... 7: /* xPSR sub-fields */
|
case 0 ... 7: /* xPSR sub-fields */
|
||||||
return v7m_mrs_xpsr(env, reg, 0);
|
return v7m_mrs_xpsr(env, reg, 0);
|
||||||
case 20: /* CONTROL */
|
case 20: /* CONTROL */
|
||||||
return v7m_mrs_control(env, 0);
|
return arm_v7m_mrs_control(env, 0);
|
||||||
default:
|
default:
|
||||||
/* Unprivileged reads others as zero. */
|
/* Unprivileged reads others as zero. */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -650,42 +650,6 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
|
||||||
arm_rebuild_hflags(env);
|
arm_rebuild_hflags(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
|
|
||||||
bool spsel)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Return a pointer to the location where we currently store the
|
|
||||||
* stack pointer for the requested security state and thread mode.
|
|
||||||
* This pointer will become invalid if the CPU state is updated
|
|
||||||
* such that the stack pointers are switched around (eg changing
|
|
||||||
* the SPSEL control bit).
|
|
||||||
* Compare the v8M ARM ARM pseudocode LookUpSP_with_security_mode().
|
|
||||||
* Unlike that pseudocode, we require the caller to pass us in the
|
|
||||||
* SPSEL control bit value; this is because we also use this
|
|
||||||
* function in handling of pushing of the callee-saves registers
|
|
||||||
* part of the v8M stack frame (pseudocode PushCalleeStack()),
|
|
||||||
* and in the tailchain codepath the SPSEL bit comes from the exception
|
|
||||||
* return magic LR value from the previous exception. The pseudocode
|
|
||||||
* opencodes the stack-selection in PushCalleeStack(), but we prefer
|
|
||||||
* to make this utility function generic enough to do the job.
|
|
||||||
*/
|
|
||||||
bool want_psp = threadmode && spsel;
|
|
||||||
|
|
||||||
if (secure == env->v7m.secure) {
|
|
||||||
if (want_psp == v7m_using_psp(env)) {
|
|
||||||
return &env->regs[13];
|
|
||||||
} else {
|
|
||||||
return &env->v7m.other_sp;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (want_psp) {
|
|
||||||
return &env->v7m.other_ss_psp;
|
|
||||||
} else {
|
|
||||||
return &env->v7m.other_ss_msp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure,
|
static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure,
|
||||||
uint32_t *pvec)
|
uint32_t *pvec)
|
||||||
{
|
{
|
||||||
|
@ -810,8 +774,8 @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
|
||||||
!mode;
|
!mode;
|
||||||
|
|
||||||
mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, M_REG_S, priv);
|
mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, M_REG_S, priv);
|
||||||
frame_sp_p = get_v7m_sp_ptr(env, M_REG_S, mode,
|
frame_sp_p = arm_v7m_get_sp_ptr(env, M_REG_S, mode,
|
||||||
lr & R_V7M_EXCRET_SPSEL_MASK);
|
lr & R_V7M_EXCRET_SPSEL_MASK);
|
||||||
want_psp = mode && (lr & R_V7M_EXCRET_SPSEL_MASK);
|
want_psp = mode && (lr & R_V7M_EXCRET_SPSEL_MASK);
|
||||||
if (want_psp) {
|
if (want_psp) {
|
||||||
limit = env->v7m.psplim[M_REG_S];
|
limit = env->v7m.psplim[M_REG_S];
|
||||||
|
@ -1656,10 +1620,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
||||||
* use 'frame_sp_p' after we do something that makes it invalid.
|
* use 'frame_sp_p' after we do something that makes it invalid.
|
||||||
*/
|
*/
|
||||||
bool spsel = env->v7m.control[return_to_secure] & R_V7M_CONTROL_SPSEL_MASK;
|
bool spsel = env->v7m.control[return_to_secure] & R_V7M_CONTROL_SPSEL_MASK;
|
||||||
uint32_t *frame_sp_p = get_v7m_sp_ptr(env,
|
uint32_t *frame_sp_p = arm_v7m_get_sp_ptr(env, return_to_secure,
|
||||||
return_to_secure,
|
!return_to_handler, spsel);
|
||||||
!return_to_handler,
|
|
||||||
spsel);
|
|
||||||
uint32_t frameptr = *frame_sp_p;
|
uint32_t frameptr = *frame_sp_p;
|
||||||
bool pop_ok = true;
|
bool pop_ok = true;
|
||||||
ARMMMUIdx mmu_idx;
|
ARMMMUIdx mmu_idx;
|
||||||
|
@ -1965,7 +1927,7 @@ static bool do_v7m_function_return(ARMCPU *cpu)
|
||||||
threadmode = !arm_v7m_is_handler_mode(env);
|
threadmode = !arm_v7m_is_handler_mode(env);
|
||||||
spsel = env->v7m.control[M_REG_S] & R_V7M_CONTROL_SPSEL_MASK;
|
spsel = env->v7m.control[M_REG_S] & R_V7M_CONTROL_SPSEL_MASK;
|
||||||
|
|
||||||
frame_sp_p = get_v7m_sp_ptr(env, true, threadmode, spsel);
|
frame_sp_p = arm_v7m_get_sp_ptr(env, true, threadmode, spsel);
|
||||||
frameptr = *frame_sp_p;
|
frameptr = *frame_sp_p;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2465,7 +2427,7 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
|
||||||
case 0 ... 7: /* xPSR sub-fields */
|
case 0 ... 7: /* xPSR sub-fields */
|
||||||
return v7m_mrs_xpsr(env, reg, el);
|
return v7m_mrs_xpsr(env, reg, el);
|
||||||
case 20: /* CONTROL */
|
case 20: /* CONTROL */
|
||||||
return v7m_mrs_control(env, env->v7m.secure);
|
return arm_v7m_mrs_control(env, env->v7m.secure);
|
||||||
case 0x94: /* CONTROL_NS */
|
case 0x94: /* CONTROL_NS */
|
||||||
/*
|
/*
|
||||||
* We have to handle this here because unprivileged Secure code
|
* We have to handle this here because unprivileged Secure code
|
||||||
|
@ -2900,3 +2862,39 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !CONFIG_USER_ONLY */
|
#endif /* !CONFIG_USER_ONLY */
|
||||||
|
|
||||||
|
uint32_t *arm_v7m_get_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
|
||||||
|
bool spsel)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Return a pointer to the location where we currently store the
|
||||||
|
* stack pointer for the requested security state and thread mode.
|
||||||
|
* This pointer will become invalid if the CPU state is updated
|
||||||
|
* such that the stack pointers are switched around (eg changing
|
||||||
|
* the SPSEL control bit).
|
||||||
|
* Compare the v8M ARM ARM pseudocode LookUpSP_with_security_mode().
|
||||||
|
* Unlike that pseudocode, we require the caller to pass us in the
|
||||||
|
* SPSEL control bit value; this is because we also use this
|
||||||
|
* function in handling of pushing of the callee-saves registers
|
||||||
|
* part of the v8M stack frame (pseudocode PushCalleeStack()),
|
||||||
|
* and in the tailchain codepath the SPSEL bit comes from the exception
|
||||||
|
* return magic LR value from the previous exception. The pseudocode
|
||||||
|
* opencodes the stack-selection in PushCalleeStack(), but we prefer
|
||||||
|
* to make this utility function generic enough to do the job.
|
||||||
|
*/
|
||||||
|
bool want_psp = threadmode && spsel;
|
||||||
|
|
||||||
|
if (secure == env->v7m.secure) {
|
||||||
|
if (want_psp == v7m_using_psp(env)) {
|
||||||
|
return &env->regs[13];
|
||||||
|
} else {
|
||||||
|
return &env->v7m.other_sp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (want_psp) {
|
||||||
|
return &env->v7m.other_ss_psp;
|
||||||
|
} else {
|
||||||
|
return &env->v7m.other_ss_msp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -339,14 +339,32 @@ static uint64_t pauth_addpac(CPUARMState *env, uint64_t ptr, uint64_t modifier,
|
||||||
return pac | ext | ptr;
|
return pac | ext | ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t pauth_original_ptr(uint64_t ptr, ARMVAParameters param)
|
static uint64_t pauth_ptr_mask_internal(ARMVAParameters param)
|
||||||
{
|
{
|
||||||
/* Note that bit 55 is used whether or not the regime has 2 ranges. */
|
|
||||||
uint64_t extfield = sextract64(ptr, 55, 1);
|
|
||||||
int bot_pac_bit = 64 - param.tsz;
|
int bot_pac_bit = 64 - param.tsz;
|
||||||
int top_pac_bit = 64 - 8 * param.tbi;
|
int top_pac_bit = 64 - 8 * param.tbi;
|
||||||
|
|
||||||
return deposit64(ptr, bot_pac_bit, top_pac_bit - bot_pac_bit, extfield);
|
return MAKE_64BIT_MASK(bot_pac_bit, top_pac_bit - bot_pac_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t pauth_original_ptr(uint64_t ptr, ARMVAParameters param)
|
||||||
|
{
|
||||||
|
uint64_t mask = pauth_ptr_mask_internal(param);
|
||||||
|
|
||||||
|
/* Note that bit 55 is used whether or not the regime has 2 ranges. */
|
||||||
|
if (extract64(ptr, 55, 1)) {
|
||||||
|
return ptr | mask;
|
||||||
|
} else {
|
||||||
|
return ptr & ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t pauth_ptr_mask(CPUARMState *env, uint64_t ptr, bool data)
|
||||||
|
{
|
||||||
|
ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env);
|
||||||
|
ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, data);
|
||||||
|
|
||||||
|
return pauth_ptr_mask_internal(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t pauth_auth(CPUARMState *env, uint64_t ptr, uint64_t modifier,
|
static uint64_t pauth_auth(CPUARMState *env, uint64_t ptr, uint64_t modifier,
|
||||||
|
|
Loading…
Reference in New Issue