target-arm queue:
* i.MX: Fix inverted sense of register bits in watchdog timer * i.MX: Add support for WDT on i.MX6 * arm/virt: cleanups to ACPI tables * Implement ARMv8.1-VMID16 extension * Implement ARMv8.1-PAN * Implement ARMv8.2-UAO * Implement ARMv8.2-ATS1E1 * ast2400/2500/2600: Wire up EHCI controllers * hw/char/exynos4210_uart: Fix memleaks in exynos4210_uart_init * hw/arm/raspi: Clean up the board code -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl5FX+IZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3kSGEACPhcIl+ChhXd6M9iJASiXn txg1a5ww6I99G9z9PFEuCv6lHBBcmfux9slu03HPyot1ycimx62NfjrOF/d0wq2p OEw5Zs1BA9NqT6/aaB4JMV0RxkODP9xT6kKGVyufNJK1JS81V098R1EcSmaX+22+ LTa/IvQF128uqGqRwh68oU2YQ4FyP+Ow5AvGZ0JzhyDrtPxLVC5hVBqXK6iZhddk 6o6CtMRYP6v50dq6njScoAa0DOYm+FL/cOATtlZCozt2uGqkmuYmy4zP5j5JeP3c SCQZW8MnF3duG1tX4nsxFEJEljjB1JrEpllm1Nml9wXe7XrQQfFXrvXARq900Xax +hY6xMmNx/WyijXXbm3W8GVfVfzcE+/kzNb3wRcbXK4T2AB2B7qT7ShDLD84NLo4 5l+asl2bjfArcp4JQSHZbe3ZG848+qb+XIoXU7CMOswmJvKnoaXD0xXeFe84Qgnl n/bhNJPNskNcfXGhXdGjmoTRN8gEpappiimCc5nzajNuJiAFJ9mcstV+ZGMHwOui 2Y/FMm3JgtKK9ecO1p3DZHrN+rqe3/WE4LIr2v2OoEdp9mlsAsq6cO3tzxxuKKTz pyLnCW3q6t+rYDxqw6gvYudINtCSrmEHncEOAoqPxxFmc3YDJ6P3TfmiTKX3bioo jwBnZGEuPINW1MZvCdCWUQ== =Mspo -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20200213' into staging target-arm queue: * i.MX: Fix inverted sense of register bits in watchdog timer * i.MX: Add support for WDT on i.MX6 * arm/virt: cleanups to ACPI tables * Implement ARMv8.1-VMID16 extension * Implement ARMv8.1-PAN * Implement ARMv8.2-UAO * Implement ARMv8.2-ATS1E1 * ast2400/2500/2600: Wire up EHCI controllers * hw/char/exynos4210_uart: Fix memleaks in exynos4210_uart_init * hw/arm/raspi: Clean up the board code # gpg: Signature made Thu 13 Feb 2020 14:40:34 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] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20200213: (46 commits) target/arm: Implement ARMv8.1-VMID16 extension hw/arm/raspi: Extract the cores count from the board revision hw/arm/raspi: Use a unique raspi_machine_class_init() method hw/arm/raspi: Extract the board model from the board revision hw/arm/raspi: Set default RAM size to size encoded in board revision hw/arm/raspi: Let class_init() directly call raspi_machine_init() hw/arm/raspi: Make board_rev a field of RaspiMachineClass hw/arm/raspi: Make machines children of abstract RaspiMachineClass hw/arm/raspi: Trivial code movement hw/arm/raspi: Extract the processor type from the board revision hw/arm/raspi: Extract the RAM size from the board revision hw/arm/raspi: Extract the version from the board revision hw/arm/raspi: Correct the board descriptions hw/arm/raspi: Use BCM2708 machine type with pre Device Tree kernels hw/char/exynos4210_uart: Fix memleaks in exynos4210_uart_init hw/arm: ast2600: Wire up EHCI controllers hw/arm: ast2400/ast2500: Wire up EHCI controllers target/arm: Enable ARMv8.2-UAO in -cpu max target/arm: Implement UAO semantics target/arm: Update MSR access to UAO ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
bc882694a3
@ -31,6 +31,8 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = {
|
|||||||
[ASPEED_FMC] = 0x1E620000,
|
[ASPEED_FMC] = 0x1E620000,
|
||||||
[ASPEED_SPI1] = 0x1E630000,
|
[ASPEED_SPI1] = 0x1E630000,
|
||||||
[ASPEED_SPI2] = 0x1E641000,
|
[ASPEED_SPI2] = 0x1E641000,
|
||||||
|
[ASPEED_EHCI1] = 0x1E6A1000,
|
||||||
|
[ASPEED_EHCI2] = 0x1E6A3000,
|
||||||
[ASPEED_MII1] = 0x1E650000,
|
[ASPEED_MII1] = 0x1E650000,
|
||||||
[ASPEED_MII2] = 0x1E650008,
|
[ASPEED_MII2] = 0x1E650008,
|
||||||
[ASPEED_MII3] = 0x1E650010,
|
[ASPEED_MII3] = 0x1E650010,
|
||||||
@ -79,6 +81,8 @@ static const int aspeed_soc_ast2600_irqmap[] = {
|
|||||||
[ASPEED_ADC] = 78,
|
[ASPEED_ADC] = 78,
|
||||||
[ASPEED_XDMA] = 6,
|
[ASPEED_XDMA] = 6,
|
||||||
[ASPEED_SDHCI] = 43,
|
[ASPEED_SDHCI] = 43,
|
||||||
|
[ASPEED_EHCI1] = 5,
|
||||||
|
[ASPEED_EHCI2] = 9,
|
||||||
[ASPEED_EMMC] = 15,
|
[ASPEED_EMMC] = 15,
|
||||||
[ASPEED_GPIO] = 40,
|
[ASPEED_GPIO] = 40,
|
||||||
[ASPEED_GPIO_1_8V] = 11,
|
[ASPEED_GPIO_1_8V] = 11,
|
||||||
@ -166,6 +170,11 @@ static void aspeed_soc_ast2600_init(Object *obj)
|
|||||||
sizeof(s->spi[i]), typename);
|
sizeof(s->spi[i]), typename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < sc->ehcis_num; i++) {
|
||||||
|
sysbus_init_child_obj(obj, "ehci[*]", OBJECT(&s->ehci[i]),
|
||||||
|
sizeof(s->ehci[i]), TYPE_PLATFORM_EHCI);
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname);
|
snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname);
|
||||||
sysbus_init_child_obj(obj, "sdmc", OBJECT(&s->sdmc), sizeof(s->sdmc),
|
sysbus_init_child_obj(obj, "sdmc", OBJECT(&s->sdmc), sizeof(s->sdmc),
|
||||||
typename);
|
typename);
|
||||||
@ -416,6 +425,19 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
|
|||||||
s->spi[i].ctrl->flash_window_base);
|
s->spi[i].ctrl->flash_window_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* EHCI */
|
||||||
|
for (i = 0; i < sc->ehcis_num; i++) {
|
||||||
|
object_property_set_bool(OBJECT(&s->ehci[i]), true, "realized", &err);
|
||||||
|
if (err) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci[i]), 0,
|
||||||
|
sc->memmap[ASPEED_EHCI1 + i]);
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0,
|
||||||
|
aspeed_soc_get_irq(s, ASPEED_EHCI1 + i));
|
||||||
|
}
|
||||||
|
|
||||||
/* SDMC - SDRAM Memory Controller */
|
/* SDMC - SDRAM Memory Controller */
|
||||||
object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err);
|
object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -534,6 +556,7 @@ static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
|
|||||||
sc->silicon_rev = AST2600_A0_SILICON_REV;
|
sc->silicon_rev = AST2600_A0_SILICON_REV;
|
||||||
sc->sram_size = 0x10000;
|
sc->sram_size = 0x10000;
|
||||||
sc->spis_num = 2;
|
sc->spis_num = 2;
|
||||||
|
sc->ehcis_num = 2;
|
||||||
sc->wdts_num = 4;
|
sc->wdts_num = 4;
|
||||||
sc->macs_num = 4;
|
sc->macs_num = 4;
|
||||||
sc->irqmap = aspeed_soc_ast2600_irqmap;
|
sc->irqmap = aspeed_soc_ast2600_irqmap;
|
||||||
|
@ -30,6 +30,7 @@ static const hwaddr aspeed_soc_ast2400_memmap[] = {
|
|||||||
[ASPEED_IOMEM] = 0x1E600000,
|
[ASPEED_IOMEM] = 0x1E600000,
|
||||||
[ASPEED_FMC] = 0x1E620000,
|
[ASPEED_FMC] = 0x1E620000,
|
||||||
[ASPEED_SPI1] = 0x1E630000,
|
[ASPEED_SPI1] = 0x1E630000,
|
||||||
|
[ASPEED_EHCI1] = 0x1E6A1000,
|
||||||
[ASPEED_VIC] = 0x1E6C0000,
|
[ASPEED_VIC] = 0x1E6C0000,
|
||||||
[ASPEED_SDMC] = 0x1E6E0000,
|
[ASPEED_SDMC] = 0x1E6E0000,
|
||||||
[ASPEED_SCU] = 0x1E6E2000,
|
[ASPEED_SCU] = 0x1E6E2000,
|
||||||
@ -59,6 +60,8 @@ static const hwaddr aspeed_soc_ast2500_memmap[] = {
|
|||||||
[ASPEED_FMC] = 0x1E620000,
|
[ASPEED_FMC] = 0x1E620000,
|
||||||
[ASPEED_SPI1] = 0x1E630000,
|
[ASPEED_SPI1] = 0x1E630000,
|
||||||
[ASPEED_SPI2] = 0x1E631000,
|
[ASPEED_SPI2] = 0x1E631000,
|
||||||
|
[ASPEED_EHCI1] = 0x1E6A1000,
|
||||||
|
[ASPEED_EHCI2] = 0x1E6A3000,
|
||||||
[ASPEED_VIC] = 0x1E6C0000,
|
[ASPEED_VIC] = 0x1E6C0000,
|
||||||
[ASPEED_SDMC] = 0x1E6E0000,
|
[ASPEED_SDMC] = 0x1E6E0000,
|
||||||
[ASPEED_SCU] = 0x1E6E2000,
|
[ASPEED_SCU] = 0x1E6E2000,
|
||||||
@ -91,6 +94,8 @@ static const int aspeed_soc_ast2400_irqmap[] = {
|
|||||||
[ASPEED_UART5] = 10,
|
[ASPEED_UART5] = 10,
|
||||||
[ASPEED_VUART] = 8,
|
[ASPEED_VUART] = 8,
|
||||||
[ASPEED_FMC] = 19,
|
[ASPEED_FMC] = 19,
|
||||||
|
[ASPEED_EHCI1] = 5,
|
||||||
|
[ASPEED_EHCI2] = 13,
|
||||||
[ASPEED_SDMC] = 0,
|
[ASPEED_SDMC] = 0,
|
||||||
[ASPEED_SCU] = 21,
|
[ASPEED_SCU] = 21,
|
||||||
[ASPEED_ADC] = 31,
|
[ASPEED_ADC] = 31,
|
||||||
@ -180,6 +185,11 @@ static void aspeed_soc_init(Object *obj)
|
|||||||
sizeof(s->spi[i]), typename);
|
sizeof(s->spi[i]), typename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < sc->ehcis_num; i++) {
|
||||||
|
sysbus_init_child_obj(obj, "ehci[*]", OBJECT(&s->ehci[i]),
|
||||||
|
sizeof(s->ehci[i]), TYPE_PLATFORM_EHCI);
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname);
|
snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname);
|
||||||
sysbus_init_child_obj(obj, "sdmc", OBJECT(&s->sdmc), sizeof(s->sdmc),
|
sysbus_init_child_obj(obj, "sdmc", OBJECT(&s->sdmc), sizeof(s->sdmc),
|
||||||
typename);
|
typename);
|
||||||
@ -364,6 +374,19 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
|||||||
s->spi[i].ctrl->flash_window_base);
|
s->spi[i].ctrl->flash_window_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* EHCI */
|
||||||
|
for (i = 0; i < sc->ehcis_num; i++) {
|
||||||
|
object_property_set_bool(OBJECT(&s->ehci[i]), true, "realized", &err);
|
||||||
|
if (err) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci[i]), 0,
|
||||||
|
sc->memmap[ASPEED_EHCI1 + i]);
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0,
|
||||||
|
aspeed_soc_get_irq(s, ASPEED_EHCI1 + i));
|
||||||
|
}
|
||||||
|
|
||||||
/* SDMC - SDRAM Memory Controller */
|
/* SDMC - SDRAM Memory Controller */
|
||||||
object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err);
|
object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -472,6 +495,7 @@ static void aspeed_soc_ast2400_class_init(ObjectClass *oc, void *data)
|
|||||||
sc->silicon_rev = AST2400_A1_SILICON_REV;
|
sc->silicon_rev = AST2400_A1_SILICON_REV;
|
||||||
sc->sram_size = 0x8000;
|
sc->sram_size = 0x8000;
|
||||||
sc->spis_num = 1;
|
sc->spis_num = 1;
|
||||||
|
sc->ehcis_num = 1;
|
||||||
sc->wdts_num = 2;
|
sc->wdts_num = 2;
|
||||||
sc->macs_num = 2;
|
sc->macs_num = 2;
|
||||||
sc->irqmap = aspeed_soc_ast2400_irqmap;
|
sc->irqmap = aspeed_soc_ast2400_irqmap;
|
||||||
@ -496,6 +520,7 @@ static void aspeed_soc_ast2500_class_init(ObjectClass *oc, void *data)
|
|||||||
sc->silicon_rev = AST2500_A1_SILICON_REV;
|
sc->silicon_rev = AST2500_A1_SILICON_REV;
|
||||||
sc->sram_size = 0x9000;
|
sc->sram_size = 0x9000;
|
||||||
sc->spis_num = 2;
|
sc->spis_num = 2;
|
||||||
|
sc->ehcis_num = 2;
|
||||||
sc->wdts_num = 3;
|
sc->wdts_num = 3;
|
||||||
sc->macs_num = 2;
|
sc->macs_num = 2;
|
||||||
sc->irqmap = aspeed_soc_ast2500_irqmap;
|
sc->irqmap = aspeed_soc_ast2500_irqmap;
|
||||||
|
@ -91,6 +91,12 @@ static void fsl_imx6_init(Object *obj)
|
|||||||
sysbus_init_child_obj(obj, name, &s->spi[i], sizeof(s->spi[i]),
|
sysbus_init_child_obj(obj, name, &s->spi[i], sizeof(s->spi[i]),
|
||||||
TYPE_IMX_SPI);
|
TYPE_IMX_SPI);
|
||||||
}
|
}
|
||||||
|
for (i = 0; i < FSL_IMX6_NUM_WDTS; i++) {
|
||||||
|
snprintf(name, NAME_SIZE, "wdt%d", i);
|
||||||
|
sysbus_init_child_obj(obj, name, &s->wdt[i], sizeof(s->wdt[i]),
|
||||||
|
TYPE_IMX2_WDT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
sysbus_init_child_obj(obj, "eth", &s->eth, sizeof(s->eth), TYPE_IMX_ENET);
|
sysbus_init_child_obj(obj, "eth", &s->eth, sizeof(s->eth), TYPE_IMX_ENET);
|
||||||
}
|
}
|
||||||
@ -383,6 +389,21 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
|
|||||||
qdev_get_gpio_in(DEVICE(&s->a9mpcore),
|
qdev_get_gpio_in(DEVICE(&s->a9mpcore),
|
||||||
FSL_IMX6_ENET_MAC_1588_IRQ));
|
FSL_IMX6_ENET_MAC_1588_IRQ));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Watchdog
|
||||||
|
*/
|
||||||
|
for (i = 0; i < FSL_IMX6_NUM_WDTS; i++) {
|
||||||
|
static const hwaddr FSL_IMX6_WDOGn_ADDR[FSL_IMX6_NUM_WDTS] = {
|
||||||
|
FSL_IMX6_WDOG1_ADDR,
|
||||||
|
FSL_IMX6_WDOG2_ADDR,
|
||||||
|
};
|
||||||
|
|
||||||
|
object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized",
|
||||||
|
&error_abort);
|
||||||
|
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, FSL_IMX6_WDOGn_ADDR[i]);
|
||||||
|
}
|
||||||
|
|
||||||
/* ROM memory */
|
/* ROM memory */
|
||||||
memory_region_init_rom(&s->rom, NULL, "imx6.rom",
|
memory_region_init_rom(&s->rom, NULL, "imx6.rom",
|
||||||
FSL_IMX6_ROM_SIZE, &err);
|
FSL_IMX6_ROM_SIZE, &err);
|
||||||
|
190
hw/arm/raspi.c
190
hw/arm/raspi.c
@ -13,9 +13,11 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu/units.h"
|
#include "qemu/units.h"
|
||||||
|
#include "qemu/cutils.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "hw/arm/bcm2836.h"
|
#include "hw/arm/bcm2836.h"
|
||||||
|
#include "hw/registerfields.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "hw/loader.h"
|
#include "hw/loader.h"
|
||||||
@ -29,13 +31,104 @@
|
|||||||
#define FIRMWARE_ADDR_3 0x80000 /* Pi 3 loads kernel.img here by default */
|
#define FIRMWARE_ADDR_3 0x80000 /* Pi 3 loads kernel.img here by default */
|
||||||
#define SPINTABLE_ADDR 0xd8 /* Pi 3 bootloader spintable */
|
#define SPINTABLE_ADDR 0xd8 /* Pi 3 bootloader spintable */
|
||||||
|
|
||||||
/* Table of Linux board IDs for different Pi versions */
|
/* Registered machine type (matches RPi Foundation bootloader and U-Boot) */
|
||||||
static const int raspi_boardid[] = {[1] = 0xc42, [2] = 0xc43, [3] = 0xc44};
|
#define MACH_TYPE_BCM2708 3138
|
||||||
|
|
||||||
typedef struct RasPiState {
|
typedef struct RaspiMachineState {
|
||||||
|
/*< private >*/
|
||||||
|
MachineState parent_obj;
|
||||||
|
/*< public >*/
|
||||||
BCM283XState soc;
|
BCM283XState soc;
|
||||||
MemoryRegion ram;
|
MemoryRegion ram;
|
||||||
} RasPiState;
|
} RaspiMachineState;
|
||||||
|
|
||||||
|
typedef struct RaspiMachineClass {
|
||||||
|
/*< private >*/
|
||||||
|
MachineClass parent_obj;
|
||||||
|
/*< public >*/
|
||||||
|
uint32_t board_rev;
|
||||||
|
} RaspiMachineClass;
|
||||||
|
|
||||||
|
#define TYPE_RASPI_MACHINE MACHINE_TYPE_NAME("raspi-common")
|
||||||
|
#define RASPI_MACHINE(obj) \
|
||||||
|
OBJECT_CHECK(RaspiMachineState, (obj), TYPE_RASPI_MACHINE)
|
||||||
|
|
||||||
|
#define RASPI_MACHINE_CLASS(klass) \
|
||||||
|
OBJECT_CLASS_CHECK(RaspiMachineClass, (klass), TYPE_RASPI_MACHINE)
|
||||||
|
#define RASPI_MACHINE_GET_CLASS(obj) \
|
||||||
|
OBJECT_GET_CLASS(RaspiMachineClass, (obj), TYPE_RASPI_MACHINE)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Board revision codes:
|
||||||
|
* www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/
|
||||||
|
*/
|
||||||
|
FIELD(REV_CODE, REVISION, 0, 4);
|
||||||
|
FIELD(REV_CODE, TYPE, 4, 8);
|
||||||
|
FIELD(REV_CODE, PROCESSOR, 12, 4);
|
||||||
|
FIELD(REV_CODE, MANUFACTURER, 16, 4);
|
||||||
|
FIELD(REV_CODE, MEMORY_SIZE, 20, 3);
|
||||||
|
FIELD(REV_CODE, STYLE, 23, 1);
|
||||||
|
|
||||||
|
static uint64_t board_ram_size(uint32_t board_rev)
|
||||||
|
{
|
||||||
|
assert(FIELD_EX32(board_rev, REV_CODE, STYLE)); /* Only new style */
|
||||||
|
return 256 * MiB << FIELD_EX32(board_rev, REV_CODE, MEMORY_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int board_processor_id(uint32_t board_rev)
|
||||||
|
{
|
||||||
|
assert(FIELD_EX32(board_rev, REV_CODE, STYLE)); /* Only new style */
|
||||||
|
return FIELD_EX32(board_rev, REV_CODE, PROCESSOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int board_version(uint32_t board_rev)
|
||||||
|
{
|
||||||
|
return board_processor_id(board_rev) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *board_soc_type(uint32_t board_rev)
|
||||||
|
{
|
||||||
|
static const char *soc_types[] = {
|
||||||
|
NULL, TYPE_BCM2836, TYPE_BCM2837,
|
||||||
|
};
|
||||||
|
int proc_id = board_processor_id(board_rev);
|
||||||
|
|
||||||
|
if (proc_id >= ARRAY_SIZE(soc_types) || !soc_types[proc_id]) {
|
||||||
|
error_report("Unsupported processor id '%d' (board revision: 0x%x)",
|
||||||
|
proc_id, board_rev);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return soc_types[proc_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cores_count(uint32_t board_rev)
|
||||||
|
{
|
||||||
|
static const int soc_cores_count[] = {
|
||||||
|
0, BCM283X_NCPUS, BCM283X_NCPUS,
|
||||||
|
};
|
||||||
|
int proc_id = board_processor_id(board_rev);
|
||||||
|
|
||||||
|
if (proc_id >= ARRAY_SIZE(soc_cores_count) || !soc_cores_count[proc_id]) {
|
||||||
|
error_report("Unsupported processor id '%d' (board revision: 0x%x)",
|
||||||
|
proc_id, board_rev);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return soc_cores_count[proc_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *board_type(uint32_t board_rev)
|
||||||
|
{
|
||||||
|
static const char *types[] = {
|
||||||
|
"A", "B", "A+", "B+", "2B", "Alpha", "CM1", NULL, "3B", "Zero",
|
||||||
|
"CM3", NULL, "Zero W", "3B+", "3A+", NULL, "CM3+", "4B",
|
||||||
|
};
|
||||||
|
assert(FIELD_EX32(board_rev, REV_CODE, STYLE)); /* Only new style */
|
||||||
|
int bt = FIELD_EX32(board_rev, REV_CODE, TYPE);
|
||||||
|
if (bt >= ARRAY_SIZE(types) || !types[bt]) {
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
return types[bt];
|
||||||
|
}
|
||||||
|
|
||||||
static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
|
static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
|
||||||
{
|
{
|
||||||
@ -116,7 +209,7 @@ static void setup_boot(MachineState *machine, int version, size_t ram_size)
|
|||||||
static struct arm_boot_info binfo;
|
static struct arm_boot_info binfo;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
binfo.board_id = raspi_boardid[version];
|
binfo.board_id = MACH_TYPE_BCM2708;
|
||||||
binfo.ram_size = ram_size;
|
binfo.ram_size = ram_size;
|
||||||
binfo.nb_cpus = machine->smp.cpus;
|
binfo.nb_cpus = machine->smp.cpus;
|
||||||
|
|
||||||
@ -164,25 +257,26 @@ static void setup_boot(MachineState *machine, int version, size_t ram_size)
|
|||||||
arm_load_kernel(ARM_CPU(first_cpu), machine, &binfo);
|
arm_load_kernel(ARM_CPU(first_cpu), machine, &binfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void raspi_init(MachineState *machine, int version)
|
static void raspi_machine_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
RasPiState *s = g_new0(RasPiState, 1);
|
RaspiMachineClass *mc = RASPI_MACHINE_GET_CLASS(machine);
|
||||||
|
RaspiMachineState *s = RASPI_MACHINE(machine);
|
||||||
|
uint32_t board_rev = mc->board_rev;
|
||||||
|
int version = board_version(board_rev);
|
||||||
|
uint64_t ram_size = board_ram_size(board_rev);
|
||||||
uint32_t vcram_size;
|
uint32_t vcram_size;
|
||||||
DriveInfo *di;
|
DriveInfo *di;
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
BusState *bus;
|
BusState *bus;
|
||||||
DeviceState *carddev;
|
DeviceState *carddev;
|
||||||
|
|
||||||
if (machine->ram_size > 1 * GiB) {
|
if (machine->ram_size != ram_size) {
|
||||||
error_report("Requested ram size is too large for this machine: "
|
char *size_str = size_to_str(ram_size);
|
||||||
"maximum is 1GB");
|
error_report("Invalid RAM size, should be %s", size_str);
|
||||||
|
g_free(size_str);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc),
|
|
||||||
version == 3 ? TYPE_BCM2837 : TYPE_BCM2836,
|
|
||||||
&error_abort, NULL);
|
|
||||||
|
|
||||||
/* Allocate and map RAM */
|
/* Allocate and map RAM */
|
||||||
memory_region_allocate_system_memory(&s->ram, OBJECT(machine), "ram",
|
memory_region_allocate_system_memory(&s->ram, OBJECT(machine), "ram",
|
||||||
machine->ram_size);
|
machine->ram_size);
|
||||||
@ -190,9 +284,10 @@ static void raspi_init(MachineState *machine, int version)
|
|||||||
memory_region_add_subregion_overlap(get_system_memory(), 0, &s->ram, 0);
|
memory_region_add_subregion_overlap(get_system_memory(), 0, &s->ram, 0);
|
||||||
|
|
||||||
/* Setup the SOC */
|
/* Setup the SOC */
|
||||||
|
object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc),
|
||||||
|
board_soc_type(board_rev), &error_abort, NULL);
|
||||||
object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(&s->ram),
|
object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(&s->ram),
|
||||||
&error_abort);
|
&error_abort);
|
||||||
int board_rev = version == 3 ? 0xa02082 : 0xa21041;
|
|
||||||
object_property_set_int(OBJECT(&s->soc), board_rev, "board-rev",
|
object_property_set_int(OBJECT(&s->soc), board_rev, "board-rev",
|
||||||
&error_abort);
|
&error_abort);
|
||||||
object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_abort);
|
object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_abort);
|
||||||
@ -214,45 +309,46 @@ static void raspi_init(MachineState *machine, int version)
|
|||||||
setup_boot(machine, version, machine->ram_size - vcram_size);
|
setup_boot(machine, version, machine->ram_size - vcram_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void raspi2_init(MachineState *machine)
|
static void raspi_machine_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
raspi_init(machine, 2);
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
}
|
RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
|
||||||
|
uint32_t board_rev = (uint32_t)(uintptr_t)data;
|
||||||
|
|
||||||
static void raspi2_machine_init(MachineClass *mc)
|
rmc->board_rev = board_rev;
|
||||||
{
|
mc->desc = g_strdup_printf("Raspberry Pi %s", board_type(board_rev));
|
||||||
mc->desc = "Raspberry Pi 2";
|
mc->init = raspi_machine_init;
|
||||||
mc->init = raspi2_init;
|
|
||||||
mc->block_default_type = IF_SD;
|
mc->block_default_type = IF_SD;
|
||||||
mc->no_parallel = 1;
|
mc->no_parallel = 1;
|
||||||
mc->no_floppy = 1;
|
mc->no_floppy = 1;
|
||||||
mc->no_cdrom = 1;
|
mc->no_cdrom = 1;
|
||||||
mc->max_cpus = BCM283X_NCPUS;
|
mc->default_cpus = mc->min_cpus = mc->max_cpus = cores_count(board_rev);
|
||||||
mc->min_cpus = BCM283X_NCPUS;
|
mc->default_ram_size = board_ram_size(board_rev);
|
||||||
mc->default_cpus = BCM283X_NCPUS;
|
if (board_version(board_rev) == 2) {
|
||||||
mc->default_ram_size = 1 * GiB;
|
mc->ignore_memory_transaction_failures = true;
|
||||||
mc->ignore_memory_transaction_failures = true;
|
}
|
||||||
};
|
};
|
||||||
DEFINE_MACHINE("raspi2", raspi2_machine_init)
|
|
||||||
|
|
||||||
|
static const TypeInfo raspi_machine_types[] = {
|
||||||
|
{
|
||||||
|
.name = MACHINE_TYPE_NAME("raspi2"),
|
||||||
|
.parent = TYPE_RASPI_MACHINE,
|
||||||
|
.class_init = raspi_machine_class_init,
|
||||||
|
.class_data = (void *)0xa21041,
|
||||||
#ifdef TARGET_AARCH64
|
#ifdef TARGET_AARCH64
|
||||||
static void raspi3_init(MachineState *machine)
|
}, {
|
||||||
{
|
.name = MACHINE_TYPE_NAME("raspi3"),
|
||||||
raspi_init(machine, 3);
|
.parent = TYPE_RASPI_MACHINE,
|
||||||
}
|
.class_init = raspi_machine_class_init,
|
||||||
|
.class_data = (void *)0xa02082,
|
||||||
static void raspi3_machine_init(MachineClass *mc)
|
|
||||||
{
|
|
||||||
mc->desc = "Raspberry Pi 3";
|
|
||||||
mc->init = raspi3_init;
|
|
||||||
mc->block_default_type = IF_SD;
|
|
||||||
mc->no_parallel = 1;
|
|
||||||
mc->no_floppy = 1;
|
|
||||||
mc->no_cdrom = 1;
|
|
||||||
mc->max_cpus = BCM283X_NCPUS;
|
|
||||||
mc->min_cpus = BCM283X_NCPUS;
|
|
||||||
mc->default_cpus = BCM283X_NCPUS;
|
|
||||||
mc->default_ram_size = 1 * GiB;
|
|
||||||
}
|
|
||||||
DEFINE_MACHINE("raspi3", raspi3_machine_init)
|
|
||||||
#endif
|
#endif
|
||||||
|
}, {
|
||||||
|
.name = TYPE_RASPI_MACHINE,
|
||||||
|
.parent = TYPE_MACHINE,
|
||||||
|
.instance_size = sizeof(RaspiMachineState),
|
||||||
|
.class_size = sizeof(RaspiMachineClass),
|
||||||
|
.abstract = true,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_TYPES(raspi_machine_types)
|
||||||
|
@ -78,11 +78,6 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
|
|||||||
AML_EXCLUSIVE, &uart_irq, 1));
|
AML_EXCLUSIVE, &uart_irq, 1));
|
||||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||||
|
|
||||||
/* The _ADR entry is used to link this device to the UART described
|
|
||||||
* in the SPCR table, i.e. SPCR.base_address.address == _ADR.
|
|
||||||
*/
|
|
||||||
aml_append(dev, aml_name_decl("_ADR", aml_int(uart_memmap->base)));
|
|
||||||
|
|
||||||
aml_append(scope, dev);
|
aml_append(scope, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +151,7 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
|
|||||||
{
|
{
|
||||||
int ecam_id = VIRT_ECAM_ID(highmem_ecam);
|
int ecam_id = VIRT_ECAM_ID(highmem_ecam);
|
||||||
Aml *method, *crs, *ifctx, *UUID, *ifctx1, *elsectx, *buf;
|
Aml *method, *crs, *ifctx, *UUID, *ifctx1, *elsectx, *buf;
|
||||||
int i, bus_no;
|
int i, slot_no;
|
||||||
hwaddr base_mmio = memmap[VIRT_PCIE_MMIO].base;
|
hwaddr base_mmio = memmap[VIRT_PCIE_MMIO].base;
|
||||||
hwaddr size_mmio = memmap[VIRT_PCIE_MMIO].size;
|
hwaddr size_mmio = memmap[VIRT_PCIE_MMIO].size;
|
||||||
hwaddr base_pio = memmap[VIRT_PCIE_PIO].base;
|
hwaddr base_pio = memmap[VIRT_PCIE_PIO].base;
|
||||||
@ -170,18 +165,17 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
|
|||||||
aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03")));
|
aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03")));
|
||||||
aml_append(dev, aml_name_decl("_SEG", aml_int(0)));
|
aml_append(dev, aml_name_decl("_SEG", aml_int(0)));
|
||||||
aml_append(dev, aml_name_decl("_BBN", aml_int(0)));
|
aml_append(dev, aml_name_decl("_BBN", aml_int(0)));
|
||||||
aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
|
|
||||||
aml_append(dev, aml_name_decl("_UID", aml_string("PCI0")));
|
aml_append(dev, aml_name_decl("_UID", aml_string("PCI0")));
|
||||||
aml_append(dev, aml_name_decl("_STR", aml_unicode("PCIe 0 Device")));
|
aml_append(dev, aml_name_decl("_STR", aml_unicode("PCIe 0 Device")));
|
||||||
aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
|
aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
|
||||||
|
|
||||||
/* Declare the PCI Routing Table. */
|
/* Declare the PCI Routing Table. */
|
||||||
Aml *rt_pkg = aml_varpackage(nr_pcie_buses * PCI_NUM_PINS);
|
Aml *rt_pkg = aml_varpackage(PCI_SLOT_MAX * PCI_NUM_PINS);
|
||||||
for (bus_no = 0; bus_no < nr_pcie_buses; bus_no++) {
|
for (slot_no = 0; slot_no < PCI_SLOT_MAX; slot_no++) {
|
||||||
for (i = 0; i < PCI_NUM_PINS; i++) {
|
for (i = 0; i < PCI_NUM_PINS; i++) {
|
||||||
int gsi = (i + bus_no) % PCI_NUM_PINS;
|
int gsi = (i + slot_no) % PCI_NUM_PINS;
|
||||||
Aml *pkg = aml_package(4);
|
Aml *pkg = aml_package(4);
|
||||||
aml_append(pkg, aml_int((bus_no << 16) | 0xFFFF));
|
aml_append(pkg, aml_int((slot_no << 16) | 0xFFFF));
|
||||||
aml_append(pkg, aml_int(i));
|
aml_append(pkg, aml_int(i));
|
||||||
aml_append(pkg, aml_name("GSI%d", gsi));
|
aml_append(pkg, aml_name("GSI%d", gsi));
|
||||||
aml_append(pkg, aml_int(0));
|
aml_append(pkg, aml_int(0));
|
||||||
@ -195,7 +189,7 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
|
|||||||
uint32_t irqs = irq + i;
|
uint32_t irqs = irq + i;
|
||||||
Aml *dev_gsi = aml_device("GSI%d", i);
|
Aml *dev_gsi = aml_device("GSI%d", i);
|
||||||
aml_append(dev_gsi, aml_name_decl("_HID", aml_string("PNP0C0F")));
|
aml_append(dev_gsi, aml_name_decl("_HID", aml_string("PNP0C0F")));
|
||||||
aml_append(dev_gsi, aml_name_decl("_UID", aml_int(0)));
|
aml_append(dev_gsi, aml_name_decl("_UID", aml_int(i)));
|
||||||
crs = aml_resource_template();
|
crs = aml_resource_template();
|
||||||
aml_append(crs,
|
aml_append(crs,
|
||||||
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
||||||
@ -242,7 +236,6 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
|
|||||||
size_mmio_high));
|
size_mmio_high));
|
||||||
}
|
}
|
||||||
|
|
||||||
aml_append(method, aml_name_decl("RBUF", rbuf));
|
|
||||||
aml_append(method, aml_return(rbuf));
|
aml_append(method, aml_return(rbuf));
|
||||||
aml_append(dev, method);
|
aml_append(dev, method);
|
||||||
|
|
||||||
@ -317,10 +310,6 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
|
|||||||
aml_append(method, aml_return(buf));
|
aml_append(method, aml_return(buf));
|
||||||
aml_append(dev, method);
|
aml_append(dev, method);
|
||||||
|
|
||||||
Aml *dev_rp0 = aml_device("%s", "RP0");
|
|
||||||
aml_append(dev_rp0, aml_name_decl("_ADR", aml_int(0)));
|
|
||||||
aml_append(dev, dev_rp0);
|
|
||||||
|
|
||||||
Aml *dev_res0 = aml_device("%s", "RES0");
|
Aml *dev_res0 = aml_device("%s", "RES0");
|
||||||
aml_append(dev_res0, aml_name_decl("_HID", aml_string("PNP0C02")));
|
aml_append(dev_res0, aml_name_decl("_HID", aml_string("PNP0C02")));
|
||||||
crs = aml_resource_template();
|
crs = aml_resource_template();
|
||||||
@ -338,7 +327,6 @@ static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
|
|||||||
{
|
{
|
||||||
Aml *dev = aml_device("GPO0");
|
Aml *dev = aml_device("GPO0");
|
||||||
aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0061")));
|
aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0061")));
|
||||||
aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
|
|
||||||
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
||||||
|
|
||||||
Aml *crs = aml_resource_template();
|
Aml *crs = aml_resource_template();
|
||||||
@ -368,7 +356,6 @@ static void acpi_dsdt_add_power_button(Aml *scope)
|
|||||||
{
|
{
|
||||||
Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE);
|
Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE);
|
||||||
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C")));
|
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C")));
|
||||||
aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
|
|
||||||
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
||||||
aml_append(scope, dev);
|
aml_append(scope, dev);
|
||||||
}
|
}
|
||||||
|
@ -674,8 +674,6 @@ static void exynos4210_uart_init(Object *obj)
|
|||||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||||
Exynos4210UartState *s = EXYNOS4210_UART(dev);
|
Exynos4210UartState *s = EXYNOS4210_UART(dev);
|
||||||
|
|
||||||
s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
|
||||||
exynos4210_uart_timeout_int, s);
|
|
||||||
s->wordtime = NANOSECONDS_PER_SECOND * 10 / 9600;
|
s->wordtime = NANOSECONDS_PER_SECOND * 10 / 9600;
|
||||||
|
|
||||||
/* memory mapping */
|
/* memory mapping */
|
||||||
@ -691,6 +689,9 @@ static void exynos4210_uart_realize(DeviceState *dev, Error **errp)
|
|||||||
{
|
{
|
||||||
Exynos4210UartState *s = EXYNOS4210_UART(dev);
|
Exynos4210UartState *s = EXYNOS4210_UART(dev);
|
||||||
|
|
||||||
|
s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||||
|
exynos4210_uart_timeout_int, s);
|
||||||
|
|
||||||
qemu_chr_fe_set_handlers(&s->chr, exynos4210_uart_can_receive,
|
qemu_chr_fe_set_handlers(&s->chr, exynos4210_uart_can_receive,
|
||||||
exynos4210_uart_receive, exynos4210_uart_event,
|
exynos4210_uart_receive, exynos4210_uart_event,
|
||||||
NULL, s, NULL, true);
|
NULL, s, NULL, true);
|
||||||
|
@ -29,7 +29,7 @@ static void imx2_wdt_write(void *opaque, hwaddr addr,
|
|||||||
uint64_t value, unsigned int size)
|
uint64_t value, unsigned int size)
|
||||||
{
|
{
|
||||||
if (addr == IMX2_WDT_WCR &&
|
if (addr == IMX2_WDT_WCR &&
|
||||||
(value & (IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS))) {
|
(~value & (IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS))) {
|
||||||
watchdog_perform_action();
|
watchdog_perform_action();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,10 @@
|
|||||||
#include "target/arm/cpu.h"
|
#include "target/arm/cpu.h"
|
||||||
#include "hw/gpio/aspeed_gpio.h"
|
#include "hw/gpio/aspeed_gpio.h"
|
||||||
#include "hw/sd/aspeed_sdhci.h"
|
#include "hw/sd/aspeed_sdhci.h"
|
||||||
|
#include "hw/usb/hcd-ehci.h"
|
||||||
|
|
||||||
#define ASPEED_SPIS_NUM 2
|
#define ASPEED_SPIS_NUM 2
|
||||||
|
#define ASPEED_EHCIS_NUM 2
|
||||||
#define ASPEED_WDTS_NUM 4
|
#define ASPEED_WDTS_NUM 4
|
||||||
#define ASPEED_CPUS_NUM 2
|
#define ASPEED_CPUS_NUM 2
|
||||||
#define ASPEED_MACS_NUM 4
|
#define ASPEED_MACS_NUM 4
|
||||||
@ -50,6 +52,7 @@ typedef struct AspeedSoCState {
|
|||||||
AspeedXDMAState xdma;
|
AspeedXDMAState xdma;
|
||||||
AspeedSMCState fmc;
|
AspeedSMCState fmc;
|
||||||
AspeedSMCState spi[ASPEED_SPIS_NUM];
|
AspeedSMCState spi[ASPEED_SPIS_NUM];
|
||||||
|
EHCISysBusState ehci[ASPEED_EHCIS_NUM];
|
||||||
AspeedSDMCState sdmc;
|
AspeedSDMCState sdmc;
|
||||||
AspeedWDTState wdt[ASPEED_WDTS_NUM];
|
AspeedWDTState wdt[ASPEED_WDTS_NUM];
|
||||||
FTGMAC100State ftgmac100[ASPEED_MACS_NUM];
|
FTGMAC100State ftgmac100[ASPEED_MACS_NUM];
|
||||||
@ -71,6 +74,7 @@ typedef struct AspeedSoCClass {
|
|||||||
uint32_t silicon_rev;
|
uint32_t silicon_rev;
|
||||||
uint64_t sram_size;
|
uint64_t sram_size;
|
||||||
int spis_num;
|
int spis_num;
|
||||||
|
int ehcis_num;
|
||||||
int wdts_num;
|
int wdts_num;
|
||||||
int macs_num;
|
int macs_num;
|
||||||
const int *irqmap;
|
const int *irqmap;
|
||||||
@ -94,6 +98,8 @@ enum {
|
|||||||
ASPEED_FMC,
|
ASPEED_FMC,
|
||||||
ASPEED_SPI1,
|
ASPEED_SPI1,
|
||||||
ASPEED_SPI2,
|
ASPEED_SPI2,
|
||||||
|
ASPEED_EHCI1,
|
||||||
|
ASPEED_EHCI2,
|
||||||
ASPEED_VIC,
|
ASPEED_VIC,
|
||||||
ASPEED_SDMC,
|
ASPEED_SDMC,
|
||||||
ASPEED_SCU,
|
ASPEED_SCU,
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "hw/cpu/a9mpcore.h"
|
#include "hw/cpu/a9mpcore.h"
|
||||||
#include "hw/misc/imx6_ccm.h"
|
#include "hw/misc/imx6_ccm.h"
|
||||||
#include "hw/misc/imx6_src.h"
|
#include "hw/misc/imx6_src.h"
|
||||||
|
#include "hw/misc/imx2_wdt.h"
|
||||||
#include "hw/char/imx_serial.h"
|
#include "hw/char/imx_serial.h"
|
||||||
#include "hw/timer/imx_gpt.h"
|
#include "hw/timer/imx_gpt.h"
|
||||||
#include "hw/timer/imx_epit.h"
|
#include "hw/timer/imx_epit.h"
|
||||||
@ -42,6 +43,7 @@
|
|||||||
#define FSL_IMX6_NUM_GPIOS 7
|
#define FSL_IMX6_NUM_GPIOS 7
|
||||||
#define FSL_IMX6_NUM_ESDHCS 4
|
#define FSL_IMX6_NUM_ESDHCS 4
|
||||||
#define FSL_IMX6_NUM_ECSPIS 5
|
#define FSL_IMX6_NUM_ECSPIS 5
|
||||||
|
#define FSL_IMX6_NUM_WDTS 2
|
||||||
|
|
||||||
typedef struct FslIMX6State {
|
typedef struct FslIMX6State {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
@ -59,6 +61,7 @@ typedef struct FslIMX6State {
|
|||||||
IMXGPIOState gpio[FSL_IMX6_NUM_GPIOS];
|
IMXGPIOState gpio[FSL_IMX6_NUM_GPIOS];
|
||||||
SDHCIState esdhc[FSL_IMX6_NUM_ESDHCS];
|
SDHCIState esdhc[FSL_IMX6_NUM_ESDHCS];
|
||||||
IMXSPIState spi[FSL_IMX6_NUM_ECSPIS];
|
IMXSPIState spi[FSL_IMX6_NUM_ECSPIS];
|
||||||
|
IMX2WdtState wdt[FSL_IMX6_NUM_WDTS];
|
||||||
IMXFECState eth;
|
IMXFECState eth;
|
||||||
MemoryRegion rom;
|
MemoryRegion rom;
|
||||||
MemoryRegion caam;
|
MemoryRegion caam;
|
||||||
|
@ -29,6 +29,6 @@
|
|||||||
# define TARGET_PAGE_BITS_MIN 10
|
# define TARGET_PAGE_BITS_MIN 10
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NB_MMU_MODES 9
|
#define NB_MMU_MODES 12
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2709,6 +2709,10 @@ static void arm_max_initfn(Object *obj)
|
|||||||
t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */
|
t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */
|
||||||
cpu->isar.mvfr2 = t;
|
cpu->isar.mvfr2 = t;
|
||||||
|
|
||||||
|
t = cpu->id_mmfr3;
|
||||||
|
t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* ATS1E1 */
|
||||||
|
cpu->id_mmfr3 = t;
|
||||||
|
|
||||||
t = cpu->id_mmfr4;
|
t = cpu->id_mmfr4;
|
||||||
t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */
|
t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */
|
||||||
cpu->id_mmfr4 = t;
|
cpu->id_mmfr4 = t;
|
||||||
|
@ -871,6 +871,7 @@ struct ARMCPU {
|
|||||||
uint64_t id_aa64pfr1;
|
uint64_t id_aa64pfr1;
|
||||||
uint64_t id_aa64mmfr0;
|
uint64_t id_aa64mmfr0;
|
||||||
uint64_t id_aa64mmfr1;
|
uint64_t id_aa64mmfr1;
|
||||||
|
uint64_t id_aa64mmfr2;
|
||||||
} isar;
|
} isar;
|
||||||
uint32_t midr;
|
uint32_t midr;
|
||||||
uint32_t revidr;
|
uint32_t revidr;
|
||||||
@ -1186,12 +1187,7 @@ void pmu_init(ARMCPU *cpu);
|
|||||||
#define CPSR_IT_2_7 (0xfc00U)
|
#define CPSR_IT_2_7 (0xfc00U)
|
||||||
#define CPSR_GE (0xfU << 16)
|
#define CPSR_GE (0xfU << 16)
|
||||||
#define CPSR_IL (1U << 20)
|
#define CPSR_IL (1U << 20)
|
||||||
/* Note that the RESERVED bits include bit 21, which is PSTATE_SS in
|
#define CPSR_PAN (1U << 22)
|
||||||
* an AArch64 SPSR but RES0 in AArch32 SPSR and CPSR. In QEMU we use
|
|
||||||
* env->uncached_cpsr bit 21 to store PSTATE.SS when executing in AArch32,
|
|
||||||
* where it is live state but not accessible to the AArch32 code.
|
|
||||||
*/
|
|
||||||
#define CPSR_RESERVED (0x7U << 21)
|
|
||||||
#define CPSR_J (1U << 24)
|
#define CPSR_J (1U << 24)
|
||||||
#define CPSR_IT_0_1 (3U << 25)
|
#define CPSR_IT_0_1 (3U << 25)
|
||||||
#define CPSR_Q (1U << 27)
|
#define CPSR_Q (1U << 27)
|
||||||
@ -1209,8 +1205,6 @@ void pmu_init(ARMCPU *cpu);
|
|||||||
#define CPSR_USER (CPSR_NZCV | CPSR_Q | CPSR_GE)
|
#define CPSR_USER (CPSR_NZCV | CPSR_Q | CPSR_GE)
|
||||||
/* Execution state bits. MRS read as zero, MSR writes ignored. */
|
/* Execution state bits. MRS read as zero, MSR writes ignored. */
|
||||||
#define CPSR_EXEC (CPSR_T | CPSR_IT | CPSR_J | CPSR_IL)
|
#define CPSR_EXEC (CPSR_T | CPSR_IT | CPSR_J | CPSR_IL)
|
||||||
/* Mask of bits which may be set by exception return copying them from SPSR */
|
|
||||||
#define CPSR_ERET_MASK (~CPSR_RESERVED)
|
|
||||||
|
|
||||||
/* Bit definitions for M profile XPSR. Most are the same as CPSR. */
|
/* Bit definitions for M profile XPSR. Most are the same as CPSR. */
|
||||||
#define XPSR_EXCP 0x1ffU
|
#define XPSR_EXCP 0x1ffU
|
||||||
@ -1258,6 +1252,8 @@ void pmu_init(ARMCPU *cpu);
|
|||||||
#define PSTATE_BTYPE (3U << 10)
|
#define PSTATE_BTYPE (3U << 10)
|
||||||
#define PSTATE_IL (1U << 20)
|
#define PSTATE_IL (1U << 20)
|
||||||
#define PSTATE_SS (1U << 21)
|
#define PSTATE_SS (1U << 21)
|
||||||
|
#define PSTATE_PAN (1U << 22)
|
||||||
|
#define PSTATE_UAO (1U << 23)
|
||||||
#define PSTATE_V (1U << 28)
|
#define PSTATE_V (1U << 28)
|
||||||
#define PSTATE_C (1U << 29)
|
#define PSTATE_C (1U << 29)
|
||||||
#define PSTATE_Z (1U << 30)
|
#define PSTATE_Z (1U << 30)
|
||||||
@ -1727,6 +1723,15 @@ FIELD(ID_ISAR6, FHM, 8, 4)
|
|||||||
FIELD(ID_ISAR6, SB, 12, 4)
|
FIELD(ID_ISAR6, SB, 12, 4)
|
||||||
FIELD(ID_ISAR6, SPECRES, 16, 4)
|
FIELD(ID_ISAR6, SPECRES, 16, 4)
|
||||||
|
|
||||||
|
FIELD(ID_MMFR3, CMAINTVA, 0, 4)
|
||||||
|
FIELD(ID_MMFR3, CMAINTSW, 4, 4)
|
||||||
|
FIELD(ID_MMFR3, BPMAINT, 8, 4)
|
||||||
|
FIELD(ID_MMFR3, MAINTBCST, 12, 4)
|
||||||
|
FIELD(ID_MMFR3, PAN, 16, 4)
|
||||||
|
FIELD(ID_MMFR3, COHWALK, 20, 4)
|
||||||
|
FIELD(ID_MMFR3, CMEMSZ, 24, 4)
|
||||||
|
FIELD(ID_MMFR3, SUPERSEC, 28, 4)
|
||||||
|
|
||||||
FIELD(ID_MMFR4, SPECSEI, 0, 4)
|
FIELD(ID_MMFR4, SPECSEI, 0, 4)
|
||||||
FIELD(ID_MMFR4, AC2, 4, 4)
|
FIELD(ID_MMFR4, AC2, 4, 4)
|
||||||
FIELD(ID_MMFR4, XNX, 8, 4)
|
FIELD(ID_MMFR4, XNX, 8, 4)
|
||||||
@ -1800,6 +1805,22 @@ FIELD(ID_AA64MMFR1, PAN, 20, 4)
|
|||||||
FIELD(ID_AA64MMFR1, SPECSEI, 24, 4)
|
FIELD(ID_AA64MMFR1, SPECSEI, 24, 4)
|
||||||
FIELD(ID_AA64MMFR1, XNX, 28, 4)
|
FIELD(ID_AA64MMFR1, XNX, 28, 4)
|
||||||
|
|
||||||
|
FIELD(ID_AA64MMFR2, CNP, 0, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, UAO, 4, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, LSM, 8, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, IESB, 12, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, VARANGE, 16, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, CCIDX, 20, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, NV, 24, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, ST, 28, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, AT, 32, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, IDS, 36, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, FWB, 40, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, TTL, 48, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, BBM, 52, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, EVT, 56, 4)
|
||||||
|
FIELD(ID_AA64MMFR2, E0PD, 60, 4)
|
||||||
|
|
||||||
FIELD(ID_DFR0, COPDBG, 0, 4)
|
FIELD(ID_DFR0, COPDBG, 0, 4)
|
||||||
FIELD(ID_DFR0, COPSDBG, 4, 4)
|
FIELD(ID_DFR0, COPSDBG, 4, 4)
|
||||||
FIELD(ID_DFR0, MMAPDBG, 8, 4)
|
FIELD(ID_DFR0, MMAPDBG, 8, 4)
|
||||||
@ -2751,20 +2772,24 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
|
|||||||
* 5. we want to be able to use the TLB for accesses done as part of a
|
* 5. we want to be able to use the TLB for accesses done as part of a
|
||||||
* stage1 page table walk, rather than having to walk the stage2 page
|
* stage1 page table walk, rather than having to walk the stage2 page
|
||||||
* table over and over.
|
* table over and over.
|
||||||
|
* 6. we need separate EL1/EL2 mmu_idx for handling the Privileged Access
|
||||||
|
* Never (PAN) bit within PSTATE.
|
||||||
*
|
*
|
||||||
* This gives us the following list of cases:
|
* This gives us the following list of cases:
|
||||||
*
|
*
|
||||||
* NS EL0 EL1&0 stage 1+2 (aka NS PL0)
|
* NS EL0 EL1&0 stage 1+2 (aka NS PL0)
|
||||||
* NS EL1 EL1&0 stage 1+2 (aka NS PL1)
|
* NS EL1 EL1&0 stage 1+2 (aka NS PL1)
|
||||||
|
* NS EL1 EL1&0 stage 1+2 +PAN
|
||||||
* NS EL0 EL2&0
|
* NS EL0 EL2&0
|
||||||
* NS EL2 EL2&0
|
* NS EL2 EL2&0 +PAN
|
||||||
* NS EL2 (aka NS PL2)
|
* NS EL2 (aka NS PL2)
|
||||||
* S EL0 EL1&0 (aka S PL0)
|
* S EL0 EL1&0 (aka S PL0)
|
||||||
* S EL1 EL1&0 (not used if EL3 is 32 bit)
|
* S EL1 EL1&0 (not used if EL3 is 32 bit)
|
||||||
|
* S EL1 EL1&0 +PAN
|
||||||
* S EL3 (aka S PL1)
|
* S EL3 (aka S PL1)
|
||||||
* NS EL1&0 stage 2
|
* NS EL1&0 stage 2
|
||||||
*
|
*
|
||||||
* for a total of 9 different mmu_idx.
|
* for a total of 12 different mmu_idx.
|
||||||
*
|
*
|
||||||
* R profile CPUs have an MPU, but can use the same set of MMU indexes
|
* R profile CPUs have an MPU, but can use the same set of MMU indexes
|
||||||
* as A profile. They only need to distinguish NS EL0 and NS EL1 (and
|
* as A profile. They only need to distinguish NS EL0 and NS EL1 (and
|
||||||
@ -2819,19 +2844,22 @@ typedef enum ARMMMUIdx {
|
|||||||
/*
|
/*
|
||||||
* A-profile.
|
* A-profile.
|
||||||
*/
|
*/
|
||||||
ARMMMUIdx_E10_0 = 0 | ARM_MMU_IDX_A,
|
ARMMMUIdx_E10_0 = 0 | ARM_MMU_IDX_A,
|
||||||
ARMMMUIdx_E20_0 = 1 | ARM_MMU_IDX_A,
|
ARMMMUIdx_E20_0 = 1 | ARM_MMU_IDX_A,
|
||||||
|
|
||||||
ARMMMUIdx_E10_1 = 2 | ARM_MMU_IDX_A,
|
ARMMMUIdx_E10_1 = 2 | ARM_MMU_IDX_A,
|
||||||
|
ARMMMUIdx_E10_1_PAN = 3 | ARM_MMU_IDX_A,
|
||||||
|
|
||||||
ARMMMUIdx_E2 = 3 | ARM_MMU_IDX_A,
|
ARMMMUIdx_E2 = 4 | ARM_MMU_IDX_A,
|
||||||
ARMMMUIdx_E20_2 = 4 | ARM_MMU_IDX_A,
|
ARMMMUIdx_E20_2 = 5 | ARM_MMU_IDX_A,
|
||||||
|
ARMMMUIdx_E20_2_PAN = 6 | ARM_MMU_IDX_A,
|
||||||
|
|
||||||
ARMMMUIdx_SE10_0 = 5 | ARM_MMU_IDX_A,
|
ARMMMUIdx_SE10_0 = 7 | ARM_MMU_IDX_A,
|
||||||
ARMMMUIdx_SE10_1 = 6 | ARM_MMU_IDX_A,
|
ARMMMUIdx_SE10_1 = 8 | ARM_MMU_IDX_A,
|
||||||
ARMMMUIdx_SE3 = 7 | ARM_MMU_IDX_A,
|
ARMMMUIdx_SE10_1_PAN = 9 | ARM_MMU_IDX_A,
|
||||||
|
ARMMMUIdx_SE3 = 10 | ARM_MMU_IDX_A,
|
||||||
|
|
||||||
ARMMMUIdx_Stage2 = 8 | ARM_MMU_IDX_A,
|
ARMMMUIdx_Stage2 = 11 | ARM_MMU_IDX_A,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These are not allocated TLBs and are used only for AT system
|
* These are not allocated TLBs and are used only for AT system
|
||||||
@ -2839,6 +2867,7 @@ typedef enum ARMMMUIdx {
|
|||||||
*/
|
*/
|
||||||
ARMMMUIdx_Stage1_E0 = 0 | ARM_MMU_IDX_NOTLB,
|
ARMMMUIdx_Stage1_E0 = 0 | ARM_MMU_IDX_NOTLB,
|
||||||
ARMMMUIdx_Stage1_E1 = 1 | ARM_MMU_IDX_NOTLB,
|
ARMMMUIdx_Stage1_E1 = 1 | ARM_MMU_IDX_NOTLB,
|
||||||
|
ARMMMUIdx_Stage1_E1_PAN = 2 | ARM_MMU_IDX_NOTLB,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* M-profile.
|
* M-profile.
|
||||||
@ -2864,10 +2893,13 @@ typedef enum ARMMMUIdxBit {
|
|||||||
TO_CORE_BIT(E10_0),
|
TO_CORE_BIT(E10_0),
|
||||||
TO_CORE_BIT(E20_0),
|
TO_CORE_BIT(E20_0),
|
||||||
TO_CORE_BIT(E10_1),
|
TO_CORE_BIT(E10_1),
|
||||||
|
TO_CORE_BIT(E10_1_PAN),
|
||||||
TO_CORE_BIT(E2),
|
TO_CORE_BIT(E2),
|
||||||
TO_CORE_BIT(E20_2),
|
TO_CORE_BIT(E20_2),
|
||||||
|
TO_CORE_BIT(E20_2_PAN),
|
||||||
TO_CORE_BIT(SE10_0),
|
TO_CORE_BIT(SE10_0),
|
||||||
TO_CORE_BIT(SE10_1),
|
TO_CORE_BIT(SE10_1),
|
||||||
|
TO_CORE_BIT(SE10_1_PAN),
|
||||||
TO_CORE_BIT(SE3),
|
TO_CORE_BIT(SE3),
|
||||||
TO_CORE_BIT(Stage2),
|
TO_CORE_BIT(Stage2),
|
||||||
|
|
||||||
@ -3432,6 +3464,16 @@ static inline bool isar_feature_aa32_vminmaxnm(const ARMISARegisters *id)
|
|||||||
return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 4;
|
return FIELD_EX64(id->mvfr2, MVFR2, FPMISC) >= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa32_pan(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
return FIELD_EX64(id->mvfr0, ID_MMFR3, PAN) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
return FIELD_EX64(id->mvfr0, ID_MMFR3, PAN) >= 2;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 64-bit feature tests via id registers.
|
* 64-bit feature tests via id registers.
|
||||||
*/
|
*/
|
||||||
@ -3591,6 +3633,21 @@ static inline bool isar_feature_aa64_lor(const ARMISARegisters *id)
|
|||||||
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, LO) != 0;
|
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, LO) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa64_pan(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa64_ats1e1(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) >= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa64_uao(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool isar_feature_aa64_bti(const ARMISARegisters *id)
|
static inline bool isar_feature_aa64_bti(const ARMISARegisters *id)
|
||||||
{
|
{
|
||||||
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0;
|
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0;
|
||||||
|
@ -673,8 +673,14 @@ static void aarch64_max_initfn(Object *obj)
|
|||||||
t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* HPD */
|
t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* HPD */
|
||||||
t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1);
|
t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1);
|
||||||
t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1);
|
t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1);
|
||||||
|
t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* ATS1E1 */
|
||||||
|
t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* VMID16 */
|
||||||
cpu->isar.id_aa64mmfr1 = t;
|
cpu->isar.id_aa64mmfr1 = t;
|
||||||
|
|
||||||
|
t = cpu->isar.id_aa64mmfr2;
|
||||||
|
t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);
|
||||||
|
cpu->isar.id_aa64mmfr2 = t;
|
||||||
|
|
||||||
/* Replicate the same data to the 32-bit id registers. */
|
/* Replicate the same data to the 32-bit id registers. */
|
||||||
u = cpu->isar.id_isar5;
|
u = cpu->isar.id_isar5;
|
||||||
u = FIELD_DP32(u, ID_ISAR5, AES, 2); /* AES + PMULL */
|
u = FIELD_DP32(u, ID_ISAR5, AES, 2); /* AES + PMULL */
|
||||||
@ -693,6 +699,10 @@ static void aarch64_max_initfn(Object *obj)
|
|||||||
u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1);
|
u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1);
|
||||||
cpu->isar.id_isar6 = u;
|
cpu->isar.id_isar6 = u;
|
||||||
|
|
||||||
|
u = cpu->id_mmfr3;
|
||||||
|
u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */
|
||||||
|
cpu->id_mmfr3 = u;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: We do not yet support ARMv8.2-fp16 for AArch32 yet,
|
* FIXME: We do not yet support ARMv8.2-fp16 for AArch32 yet,
|
||||||
* so do not set MVFR1.FPHP. Strictly speaking this is not legal,
|
* so do not set MVFR1.FPHP. Strictly speaking this is not legal,
|
||||||
|
@ -959,7 +959,7 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
|
|||||||
{
|
{
|
||||||
int cur_el = arm_current_el(env);
|
int cur_el = arm_current_el(env);
|
||||||
unsigned int spsr_idx = aarch64_banked_spsr_index(cur_el);
|
unsigned int spsr_idx = aarch64_banked_spsr_index(cur_el);
|
||||||
uint32_t spsr = env->banked_spsr[spsr_idx];
|
uint32_t mask, spsr = env->banked_spsr[spsr_idx];
|
||||||
int new_el;
|
int new_el;
|
||||||
bool return_to_aa64 = (spsr & PSTATE_nRW) == 0;
|
bool return_to_aa64 = (spsr & PSTATE_nRW) == 0;
|
||||||
|
|
||||||
@ -1014,7 +1014,8 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
|
|||||||
* will sort the register banks out for us, and we've already
|
* will sort the register banks out for us, and we've already
|
||||||
* caught all the bad-mode cases in el_from_spsr().
|
* caught all the bad-mode cases in el_from_spsr().
|
||||||
*/
|
*/
|
||||||
cpsr_write(env, spsr, ~0, CPSRWriteRaw);
|
mask = aarch32_cpsr_valid_mask(env->features, &env_archcpu(env)->isar);
|
||||||
|
cpsr_write(env, spsr, mask, CPSRWriteRaw);
|
||||||
if (!arm_singlestep_active(env)) {
|
if (!arm_singlestep_active(env)) {
|
||||||
env->uncached_cpsr &= ~PSTATE_SS;
|
env->uncached_cpsr &= ~PSTATE_SS;
|
||||||
}
|
}
|
||||||
@ -1031,6 +1032,7 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
|
|||||||
cur_el, new_el, env->regs[15]);
|
cur_el, new_el, env->regs[15]);
|
||||||
} else {
|
} else {
|
||||||
env->aarch64 = 1;
|
env->aarch64 = 1;
|
||||||
|
spsr &= aarch64_pstate_valid_mask(&env_archcpu(env)->isar);
|
||||||
pstate_write(env, spsr);
|
pstate_write(env, spsr);
|
||||||
if (!arm_singlestep_active(env)) {
|
if (!arm_singlestep_active(env)) {
|
||||||
env->pstate &= ~PSTATE_SS;
|
env->pstate &= ~PSTATE_SS;
|
||||||
|
@ -671,6 +671,7 @@ static void tlbiall_nsnh_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||||||
|
|
||||||
tlb_flush_by_mmuidx(cs,
|
tlb_flush_by_mmuidx(cs,
|
||||||
ARMMMUIdxBit_E10_1 |
|
ARMMMUIdxBit_E10_1 |
|
||||||
|
ARMMMUIdxBit_E10_1_PAN |
|
||||||
ARMMMUIdxBit_E10_0 |
|
ARMMMUIdxBit_E10_0 |
|
||||||
ARMMMUIdxBit_Stage2);
|
ARMMMUIdxBit_Stage2);
|
||||||
}
|
}
|
||||||
@ -682,6 +683,7 @@ static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||||||
|
|
||||||
tlb_flush_by_mmuidx_all_cpus_synced(cs,
|
tlb_flush_by_mmuidx_all_cpus_synced(cs,
|
||||||
ARMMMUIdxBit_E10_1 |
|
ARMMMUIdxBit_E10_1 |
|
||||||
|
ARMMMUIdxBit_E10_1_PAN |
|
||||||
ARMMMUIdxBit_E10_0 |
|
ARMMMUIdxBit_E10_0 |
|
||||||
ARMMMUIdxBit_Stage2);
|
ARMMMUIdxBit_Stage2);
|
||||||
}
|
}
|
||||||
@ -2700,6 +2702,7 @@ static int gt_phys_redir_timeridx(CPUARMState *env)
|
|||||||
switch (arm_mmu_idx(env)) {
|
switch (arm_mmu_idx(env)) {
|
||||||
case ARMMMUIdx_E20_0:
|
case ARMMMUIdx_E20_0:
|
||||||
case ARMMMUIdx_E20_2:
|
case ARMMMUIdx_E20_2:
|
||||||
|
case ARMMMUIdx_E20_2_PAN:
|
||||||
return GTIMER_HYP;
|
return GTIMER_HYP;
|
||||||
default:
|
default:
|
||||||
return GTIMER_PHYS;
|
return GTIMER_PHYS;
|
||||||
@ -2711,6 +2714,7 @@ static int gt_virt_redir_timeridx(CPUARMState *env)
|
|||||||
switch (arm_mmu_idx(env)) {
|
switch (arm_mmu_idx(env)) {
|
||||||
case ARMMMUIdx_E20_0:
|
case ARMMMUIdx_E20_0:
|
||||||
case ARMMMUIdx_E20_2:
|
case ARMMMUIdx_E20_2:
|
||||||
|
case ARMMMUIdx_E20_2_PAN:
|
||||||
return GTIMER_HYPVIRT;
|
return GTIMER_HYPVIRT;
|
||||||
default:
|
default:
|
||||||
return GTIMER_VIRT;
|
return GTIMER_VIRT;
|
||||||
@ -3261,8 +3265,7 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
|
|||||||
bool take_exc = false;
|
bool take_exc = false;
|
||||||
|
|
||||||
if (fi.s1ptw && current_el == 1 && !arm_is_secure(env)
|
if (fi.s1ptw && current_el == 1 && !arm_is_secure(env)
|
||||||
&& (mmu_idx == ARMMMUIdx_Stage1_E1 ||
|
&& arm_mmu_idx_is_stage1_of_2(mmu_idx)) {
|
||||||
mmu_idx == ARMMMUIdx_Stage1_E0)) {
|
|
||||||
/*
|
/*
|
||||||
* Synchronous stage 2 fault on an access made as part of the
|
* Synchronous stage 2 fault on an access made as part of the
|
||||||
* translation table walk for AT S1E0* or AT S1E1* insn
|
* translation table walk for AT S1E0* or AT S1E1* insn
|
||||||
@ -3338,7 +3341,9 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
|
|||||||
format64 = arm_s1_regime_using_lpae_format(env, mmu_idx);
|
format64 = arm_s1_regime_using_lpae_format(env, mmu_idx);
|
||||||
|
|
||||||
if (arm_feature(env, ARM_FEATURE_EL2)) {
|
if (arm_feature(env, ARM_FEATURE_EL2)) {
|
||||||
if (mmu_idx == ARMMMUIdx_E10_0 || mmu_idx == ARMMMUIdx_E10_1) {
|
if (mmu_idx == ARMMMUIdx_E10_0 ||
|
||||||
|
mmu_idx == ARMMMUIdx_E10_1 ||
|
||||||
|
mmu_idx == ARMMMUIdx_E10_1_PAN) {
|
||||||
format64 |= env->cp15.hcr_el2 & (HCR_VM | HCR_DC);
|
format64 |= env->cp15.hcr_el2 & (HCR_VM | HCR_DC);
|
||||||
} else {
|
} else {
|
||||||
format64 |= arm_current_el(env) == 2;
|
format64 |= arm_current_el(env) == 2;
|
||||||
@ -3404,16 +3409,21 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
|
|||||||
|
|
||||||
switch (ri->opc2 & 6) {
|
switch (ri->opc2 & 6) {
|
||||||
case 0:
|
case 0:
|
||||||
/* stage 1 current state PL1: ATS1CPR, ATS1CPW */
|
/* stage 1 current state PL1: ATS1CPR, ATS1CPW, ATS1CPRP, ATS1CPWP */
|
||||||
switch (el) {
|
switch (el) {
|
||||||
case 3:
|
case 3:
|
||||||
mmu_idx = ARMMMUIdx_SE3;
|
mmu_idx = ARMMMUIdx_SE3;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
mmu_idx = ARMMMUIdx_Stage1_E1;
|
g_assert(!secure); /* TODO: ARMv8.4-SecEL2 */
|
||||||
break;
|
/* fall through */
|
||||||
case 1:
|
case 1:
|
||||||
mmu_idx = secure ? ARMMMUIdx_SE10_1 : ARMMMUIdx_Stage1_E1;
|
if (ri->crm == 9 && (env->uncached_cpsr & CPSR_PAN)) {
|
||||||
|
mmu_idx = (secure ? ARMMMUIdx_SE10_1_PAN
|
||||||
|
: ARMMMUIdx_Stage1_E1_PAN);
|
||||||
|
} else {
|
||||||
|
mmu_idx = secure ? ARMMMUIdx_SE10_1 : ARMMMUIdx_Stage1_E1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
@ -3482,8 +3492,13 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||||||
switch (ri->opc2 & 6) {
|
switch (ri->opc2 & 6) {
|
||||||
case 0:
|
case 0:
|
||||||
switch (ri->opc1) {
|
switch (ri->opc1) {
|
||||||
case 0: /* AT S1E1R, AT S1E1W */
|
case 0: /* AT S1E1R, AT S1E1W, AT S1E1RP, AT S1E1WP */
|
||||||
mmu_idx = secure ? ARMMMUIdx_SE10_1 : ARMMMUIdx_Stage1_E1;
|
if (ri->crm == 9 && (env->pstate & PSTATE_PAN)) {
|
||||||
|
mmu_idx = (secure ? ARMMMUIdx_SE10_1_PAN
|
||||||
|
: ARMMMUIdx_Stage1_E1_PAN);
|
||||||
|
} else {
|
||||||
|
mmu_idx = secure ? ARMMMUIdx_SE10_1 : ARMMMUIdx_Stage1_E1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 4: /* AT S1E2R, AT S1E2W */
|
case 4: /* AT S1E2R, AT S1E2W */
|
||||||
mmu_idx = ARMMMUIdx_E2;
|
mmu_idx = ARMMMUIdx_E2;
|
||||||
@ -3798,7 +3813,9 @@ static void vmsa_tcr_ttbr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||||||
if (extract64(raw_read(env, ri) ^ value, 48, 16) &&
|
if (extract64(raw_read(env, ri) ^ value, 48, 16) &&
|
||||||
(arm_hcr_el2_eff(env) & HCR_E2H)) {
|
(arm_hcr_el2_eff(env) & HCR_E2H)) {
|
||||||
tlb_flush_by_mmuidx(env_cpu(env),
|
tlb_flush_by_mmuidx(env_cpu(env),
|
||||||
ARMMMUIdxBit_E20_2 | ARMMMUIdxBit_E20_0);
|
ARMMMUIdxBit_E20_2 |
|
||||||
|
ARMMMUIdxBit_E20_2_PAN |
|
||||||
|
ARMMMUIdxBit_E20_0);
|
||||||
}
|
}
|
||||||
raw_write(env, ri, value);
|
raw_write(env, ri, value);
|
||||||
}
|
}
|
||||||
@ -3816,6 +3833,7 @@ static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||||||
if (raw_read(env, ri) != value) {
|
if (raw_read(env, ri) != value) {
|
||||||
tlb_flush_by_mmuidx(cs,
|
tlb_flush_by_mmuidx(cs,
|
||||||
ARMMMUIdxBit_E10_1 |
|
ARMMMUIdxBit_E10_1 |
|
||||||
|
ARMMMUIdxBit_E10_1_PAN |
|
||||||
ARMMMUIdxBit_E10_0 |
|
ARMMMUIdxBit_E10_0 |
|
||||||
ARMMMUIdxBit_Stage2);
|
ARMMMUIdxBit_Stage2);
|
||||||
raw_write(env, ri, value);
|
raw_write(env, ri, value);
|
||||||
@ -4155,6 +4173,42 @@ static void aa64_daif_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||||||
env->daif = value & PSTATE_DAIF;
|
env->daif = value & PSTATE_DAIF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t aa64_pan_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
return env->pstate & PSTATE_PAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aa64_pan_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
env->pstate = (env->pstate & ~PSTATE_PAN) | (value & PSTATE_PAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ARMCPRegInfo pan_reginfo = {
|
||||||
|
.name = "PAN", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 0, .crn = 4, .crm = 2, .opc2 = 3,
|
||||||
|
.type = ARM_CP_NO_RAW, .access = PL1_RW,
|
||||||
|
.readfn = aa64_pan_read, .writefn = aa64_pan_write
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint64_t aa64_uao_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
return env->pstate & PSTATE_UAO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aa64_uao_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
env->pstate = (env->pstate & ~PSTATE_UAO) | (value & PSTATE_UAO);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ARMCPRegInfo uao_reginfo = {
|
||||||
|
.name = "UAO", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 0, .crn = 4, .crm = 2, .opc2 = 4,
|
||||||
|
.type = ARM_CP_NO_RAW, .access = PL1_RW,
|
||||||
|
.readfn = aa64_uao_read, .writefn = aa64_uao_write
|
||||||
|
};
|
||||||
|
|
||||||
static CPAccessResult aa64_cacheop_access(CPUARMState *env,
|
static CPAccessResult aa64_cacheop_access(CPUARMState *env,
|
||||||
const ARMCPRegInfo *ri,
|
const ARMCPRegInfo *ri,
|
||||||
bool isread)
|
bool isread)
|
||||||
@ -4176,12 +4230,18 @@ static int vae1_tlbmask(CPUARMState *env)
|
|||||||
{
|
{
|
||||||
/* Since we exclude secure first, we may read HCR_EL2 directly. */
|
/* Since we exclude secure first, we may read HCR_EL2 directly. */
|
||||||
if (arm_is_secure_below_el3(env)) {
|
if (arm_is_secure_below_el3(env)) {
|
||||||
return ARMMMUIdxBit_SE10_1 | ARMMMUIdxBit_SE10_0;
|
return ARMMMUIdxBit_SE10_1 |
|
||||||
|
ARMMMUIdxBit_SE10_1_PAN |
|
||||||
|
ARMMMUIdxBit_SE10_0;
|
||||||
} else if ((env->cp15.hcr_el2 & (HCR_E2H | HCR_TGE))
|
} else if ((env->cp15.hcr_el2 & (HCR_E2H | HCR_TGE))
|
||||||
== (HCR_E2H | HCR_TGE)) {
|
== (HCR_E2H | HCR_TGE)) {
|
||||||
return ARMMMUIdxBit_E20_2 | ARMMMUIdxBit_E20_0;
|
return ARMMMUIdxBit_E20_2 |
|
||||||
|
ARMMMUIdxBit_E20_2_PAN |
|
||||||
|
ARMMMUIdxBit_E20_0;
|
||||||
} else {
|
} else {
|
||||||
return ARMMMUIdxBit_E10_1 | ARMMMUIdxBit_E10_0;
|
return ARMMMUIdxBit_E10_1 |
|
||||||
|
ARMMMUIdxBit_E10_1_PAN |
|
||||||
|
ARMMMUIdxBit_E10_0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4215,18 +4275,28 @@ static int alle1_tlbmask(CPUARMState *env)
|
|||||||
* stage 1 translations.
|
* stage 1 translations.
|
||||||
*/
|
*/
|
||||||
if (arm_is_secure_below_el3(env)) {
|
if (arm_is_secure_below_el3(env)) {
|
||||||
return ARMMMUIdxBit_SE10_1 | ARMMMUIdxBit_SE10_0;
|
return ARMMMUIdxBit_SE10_1 |
|
||||||
|
ARMMMUIdxBit_SE10_1_PAN |
|
||||||
|
ARMMMUIdxBit_SE10_0;
|
||||||
} else if (arm_feature(env, ARM_FEATURE_EL2)) {
|
} else if (arm_feature(env, ARM_FEATURE_EL2)) {
|
||||||
return ARMMMUIdxBit_E10_1 | ARMMMUIdxBit_E10_0 | ARMMMUIdxBit_Stage2;
|
return ARMMMUIdxBit_E10_1 |
|
||||||
|
ARMMMUIdxBit_E10_1_PAN |
|
||||||
|
ARMMMUIdxBit_E10_0 |
|
||||||
|
ARMMMUIdxBit_Stage2;
|
||||||
} else {
|
} else {
|
||||||
return ARMMMUIdxBit_E10_1 | ARMMMUIdxBit_E10_0;
|
return ARMMMUIdxBit_E10_1 |
|
||||||
|
ARMMMUIdxBit_E10_1_PAN |
|
||||||
|
ARMMMUIdxBit_E10_0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int e2_tlbmask(CPUARMState *env)
|
static int e2_tlbmask(CPUARMState *env)
|
||||||
{
|
{
|
||||||
/* TODO: ARMv8.4-SecEL2 */
|
/* TODO: ARMv8.4-SecEL2 */
|
||||||
return ARMMMUIdxBit_E20_0 | ARMMMUIdxBit_E20_2 | ARMMMUIdxBit_E2;
|
return ARMMMUIdxBit_E20_0 |
|
||||||
|
ARMMMUIdxBit_E20_2 |
|
||||||
|
ARMMMUIdxBit_E20_2_PAN |
|
||||||
|
ARMMMUIdxBit_E2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tlbi_aa64_alle1_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
static void tlbi_aa64_alle1_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
@ -6310,6 +6380,35 @@ static CPAccessResult access_lor_other(CPUARMState *env,
|
|||||||
return access_lor_ns(env);
|
return access_lor_ns(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A trivial implementation of ARMv8.1-LOR leaves all of these
|
||||||
|
* registers fixed at 0, which indicates that there are zero
|
||||||
|
* supported Limited Ordering regions.
|
||||||
|
*/
|
||||||
|
static const ARMCPRegInfo lor_reginfo[] = {
|
||||||
|
{ .name = "LORSA_EL1", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 0,
|
||||||
|
.access = PL1_RW, .accessfn = access_lor_other,
|
||||||
|
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||||
|
{ .name = "LOREA_EL1", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 1,
|
||||||
|
.access = PL1_RW, .accessfn = access_lor_other,
|
||||||
|
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||||
|
{ .name = "LORN_EL1", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 2,
|
||||||
|
.access = PL1_RW, .accessfn = access_lor_other,
|
||||||
|
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||||
|
{ .name = "LORC_EL1", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 3,
|
||||||
|
.access = PL1_RW, .accessfn = access_lor_other,
|
||||||
|
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||||
|
{ .name = "LORID_EL1", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 7,
|
||||||
|
.access = PL1_R, .accessfn = access_lorid,
|
||||||
|
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||||
|
REGINFO_SENTINEL
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef TARGET_AARCH64
|
#ifdef TARGET_AARCH64
|
||||||
static CPAccessResult access_pauth(CPUARMState *env, const ARMCPRegInfo *ri,
|
static CPAccessResult access_pauth(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
bool isread)
|
bool isread)
|
||||||
@ -6612,6 +6711,32 @@ static const ARMCPRegInfo vhe_reginfo[] = {
|
|||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
static const ARMCPRegInfo ats1e1_reginfo[] = {
|
||||||
|
{ .name = "AT_S1E1R", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 0,
|
||||||
|
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||||
|
.writefn = ats_write64 },
|
||||||
|
{ .name = "AT_S1E1W", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1,
|
||||||
|
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||||
|
.writefn = ats_write64 },
|
||||||
|
REGINFO_SENTINEL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ARMCPRegInfo ats1cp_reginfo[] = {
|
||||||
|
{ .name = "ATS1CPRP",
|
||||||
|
.cp = 15, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 0,
|
||||||
|
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||||
|
.writefn = ats_write },
|
||||||
|
{ .name = "ATS1CPWP",
|
||||||
|
.cp = 15, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1,
|
||||||
|
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||||
|
.writefn = ats_write },
|
||||||
|
REGINFO_SENTINEL
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
void register_cp_regs_for_features(ARMCPU *cpu)
|
void register_cp_regs_for_features(ARMCPU *cpu)
|
||||||
{
|
{
|
||||||
/* Register all the coprocessor registers based on feature bits */
|
/* Register all the coprocessor registers based on feature bits */
|
||||||
@ -6966,11 +7091,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
|||||||
.access = PL1_R, .type = ARM_CP_CONST,
|
.access = PL1_R, .type = ARM_CP_CONST,
|
||||||
.accessfn = access_aa64_tid3,
|
.accessfn = access_aa64_tid3,
|
||||||
.resetvalue = cpu->isar.id_aa64mmfr1 },
|
.resetvalue = cpu->isar.id_aa64mmfr1 },
|
||||||
{ .name = "ID_AA64MMFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
{ .name = "ID_AA64MMFR2_EL1", .state = ARM_CP_STATE_AA64,
|
||||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 2,
|
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 2,
|
||||||
.access = PL1_R, .type = ARM_CP_CONST,
|
.access = PL1_R, .type = ARM_CP_CONST,
|
||||||
.accessfn = access_aa64_tid3,
|
.accessfn = access_aa64_tid3,
|
||||||
.resetvalue = 0 },
|
.resetvalue = cpu->isar.id_aa64mmfr2 },
|
||||||
{ .name = "ID_AA64MMFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
{ .name = "ID_AA64MMFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 3,
|
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 3,
|
||||||
.access = PL1_R, .type = ARM_CP_CONST,
|
.access = PL1_R, .type = ARM_CP_CONST,
|
||||||
@ -7544,36 +7669,22 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cpu_isar_feature(aa64_lor, cpu)) {
|
if (cpu_isar_feature(aa64_lor, cpu)) {
|
||||||
/*
|
|
||||||
* A trivial implementation of ARMv8.1-LOR leaves all of these
|
|
||||||
* registers fixed at 0, which indicates that there are zero
|
|
||||||
* supported Limited Ordering regions.
|
|
||||||
*/
|
|
||||||
static const ARMCPRegInfo lor_reginfo[] = {
|
|
||||||
{ .name = "LORSA_EL1", .state = ARM_CP_STATE_AA64,
|
|
||||||
.opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 0,
|
|
||||||
.access = PL1_RW, .accessfn = access_lor_other,
|
|
||||||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
|
||||||
{ .name = "LOREA_EL1", .state = ARM_CP_STATE_AA64,
|
|
||||||
.opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 1,
|
|
||||||
.access = PL1_RW, .accessfn = access_lor_other,
|
|
||||||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
|
||||||
{ .name = "LORN_EL1", .state = ARM_CP_STATE_AA64,
|
|
||||||
.opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 2,
|
|
||||||
.access = PL1_RW, .accessfn = access_lor_other,
|
|
||||||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
|
||||||
{ .name = "LORC_EL1", .state = ARM_CP_STATE_AA64,
|
|
||||||
.opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 3,
|
|
||||||
.access = PL1_RW, .accessfn = access_lor_other,
|
|
||||||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
|
||||||
{ .name = "LORID_EL1", .state = ARM_CP_STATE_AA64,
|
|
||||||
.opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 7,
|
|
||||||
.access = PL1_R, .accessfn = access_lorid,
|
|
||||||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
|
||||||
REGINFO_SENTINEL
|
|
||||||
};
|
|
||||||
define_arm_cp_regs(cpu, lor_reginfo);
|
define_arm_cp_regs(cpu, lor_reginfo);
|
||||||
}
|
}
|
||||||
|
if (cpu_isar_feature(aa64_pan, cpu)) {
|
||||||
|
define_one_arm_cp_reg(cpu, &pan_reginfo);
|
||||||
|
}
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
if (cpu_isar_feature(aa64_ats1e1, cpu)) {
|
||||||
|
define_arm_cp_regs(cpu, ats1e1_reginfo);
|
||||||
|
}
|
||||||
|
if (cpu_isar_feature(aa32_ats1e1, cpu)) {
|
||||||
|
define_arm_cp_regs(cpu, ats1cp_reginfo);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (cpu_isar_feature(aa64_uao, cpu)) {
|
||||||
|
define_one_arm_cp_reg(cpu, &uao_reginfo);
|
||||||
|
}
|
||||||
|
|
||||||
if (arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu)) {
|
if (arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu)) {
|
||||||
define_arm_cp_regs(cpu, vhe_reginfo);
|
define_arm_cp_regs(cpu, vhe_reginfo);
|
||||||
@ -8717,8 +8828,12 @@ static void take_aarch32_exception(CPUARMState *env, int new_mode,
|
|||||||
uint32_t mask, uint32_t offset,
|
uint32_t mask, uint32_t offset,
|
||||||
uint32_t newpc)
|
uint32_t newpc)
|
||||||
{
|
{
|
||||||
|
int new_el;
|
||||||
|
|
||||||
/* Change the CPU state so as to actually take the exception. */
|
/* Change the CPU state so as to actually take the exception. */
|
||||||
switch_mode(env, new_mode);
|
switch_mode(env, new_mode);
|
||||||
|
new_el = arm_current_el(env);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For exceptions taken to AArch32 we must clear the SS bit in both
|
* For exceptions taken to AArch32 we must clear the SS bit in both
|
||||||
* PSTATE and in the old-state value we save to SPSR_<mode>, so zero it now.
|
* PSTATE and in the old-state value we save to SPSR_<mode>, so zero it now.
|
||||||
@ -8731,7 +8846,7 @@ static void take_aarch32_exception(CPUARMState *env, int new_mode,
|
|||||||
env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
|
env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
|
||||||
/* Set new mode endianness */
|
/* Set new mode endianness */
|
||||||
env->uncached_cpsr &= ~CPSR_E;
|
env->uncached_cpsr &= ~CPSR_E;
|
||||||
if (env->cp15.sctlr_el[arm_current_el(env)] & SCTLR_EE) {
|
if (env->cp15.sctlr_el[new_el] & SCTLR_EE) {
|
||||||
env->uncached_cpsr |= CPSR_E;
|
env->uncached_cpsr |= CPSR_E;
|
||||||
}
|
}
|
||||||
/* J and IL must always be cleared for exception entry */
|
/* J and IL must always be cleared for exception entry */
|
||||||
@ -8742,6 +8857,25 @@ static void take_aarch32_exception(CPUARMState *env, int new_mode,
|
|||||||
env->thumb = (env->cp15.sctlr_el[2] & SCTLR_TE) != 0;
|
env->thumb = (env->cp15.sctlr_el[2] & SCTLR_TE) != 0;
|
||||||
env->elr_el[2] = env->regs[15];
|
env->elr_el[2] = env->regs[15];
|
||||||
} else {
|
} else {
|
||||||
|
/* CPSR.PAN is normally preserved preserved unless... */
|
||||||
|
if (cpu_isar_feature(aa64_pan, env_archcpu(env))) {
|
||||||
|
switch (new_el) {
|
||||||
|
case 3:
|
||||||
|
if (!arm_is_secure_below_el3(env)) {
|
||||||
|
/* ... the target is EL3, from non-secure state. */
|
||||||
|
env->uncached_cpsr &= ~CPSR_PAN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* ... the target is EL3, from secure state ... */
|
||||||
|
/* fall through */
|
||||||
|
case 1:
|
||||||
|
/* ... the target is EL1 and SCTLR.SPAN is 0. */
|
||||||
|
if (!(env->cp15.sctlr_el[new_el] & SCTLR_SPAN)) {
|
||||||
|
env->uncached_cpsr |= CPSR_PAN;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* this is a lie, as there was no c1_sys on V4T/V5, but who cares
|
* this is a lie, as there was no c1_sys on V4T/V5, but who cares
|
||||||
* and we should just guard the thumb mode on V4
|
* and we should just guard the thumb mode on V4
|
||||||
@ -9004,6 +9138,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
|
|||||||
unsigned int new_el = env->exception.target_el;
|
unsigned int new_el = env->exception.target_el;
|
||||||
target_ulong addr = env->cp15.vbar_el[new_el];
|
target_ulong addr = env->cp15.vbar_el[new_el];
|
||||||
unsigned int new_mode = aarch64_pstate_mode(new_el, true);
|
unsigned int new_mode = aarch64_pstate_mode(new_el, true);
|
||||||
|
unsigned int old_mode;
|
||||||
unsigned int cur_el = arm_current_el(env);
|
unsigned int cur_el = arm_current_el(env);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -9083,20 +9218,43 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_a64(env)) {
|
if (is_a64(env)) {
|
||||||
env->banked_spsr[aarch64_banked_spsr_index(new_el)] = pstate_read(env);
|
old_mode = pstate_read(env);
|
||||||
aarch64_save_sp(env, arm_current_el(env));
|
aarch64_save_sp(env, arm_current_el(env));
|
||||||
env->elr_el[new_el] = env->pc;
|
env->elr_el[new_el] = env->pc;
|
||||||
} else {
|
} else {
|
||||||
env->banked_spsr[aarch64_banked_spsr_index(new_el)] = cpsr_read(env);
|
old_mode = cpsr_read(env);
|
||||||
env->elr_el[new_el] = env->regs[15];
|
env->elr_el[new_el] = env->regs[15];
|
||||||
|
|
||||||
aarch64_sync_32_to_64(env);
|
aarch64_sync_32_to_64(env);
|
||||||
|
|
||||||
env->condexec_bits = 0;
|
env->condexec_bits = 0;
|
||||||
}
|
}
|
||||||
|
env->banked_spsr[aarch64_banked_spsr_index(new_el)] = old_mode;
|
||||||
|
|
||||||
qemu_log_mask(CPU_LOG_INT, "...with ELR 0x%" PRIx64 "\n",
|
qemu_log_mask(CPU_LOG_INT, "...with ELR 0x%" PRIx64 "\n",
|
||||||
env->elr_el[new_el]);
|
env->elr_el[new_el]);
|
||||||
|
|
||||||
|
if (cpu_isar_feature(aa64_pan, cpu)) {
|
||||||
|
/* The value of PSTATE.PAN is normally preserved, except when ... */
|
||||||
|
new_mode |= old_mode & PSTATE_PAN;
|
||||||
|
switch (new_el) {
|
||||||
|
case 2:
|
||||||
|
/* ... the target is EL2 with HCR_EL2.{E2H,TGE} == '11' ... */
|
||||||
|
if ((arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE))
|
||||||
|
!= (HCR_E2H | HCR_TGE)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
case 1:
|
||||||
|
/* ... the target is EL1 ... */
|
||||||
|
/* ... and SCTLR_ELx.SPAN == 0, then set to 1. */
|
||||||
|
if ((env->cp15.sctlr_el[new_el] & SCTLR_SPAN) == 0) {
|
||||||
|
new_mode |= PSTATE_PAN;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pstate_write(env, PSTATE_DAIF | new_mode);
|
pstate_write(env, PSTATE_DAIF | new_mode);
|
||||||
env->aarch64 = 1;
|
env->aarch64 = 1;
|
||||||
aarch64_restore_sp(env, new_el);
|
aarch64_restore_sp(env, new_el);
|
||||||
@ -9207,6 +9365,7 @@ static uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
|
|||||||
switch (mmu_idx) {
|
switch (mmu_idx) {
|
||||||
case ARMMMUIdx_E20_0:
|
case ARMMMUIdx_E20_0:
|
||||||
case ARMMMUIdx_E20_2:
|
case ARMMMUIdx_E20_2:
|
||||||
|
case ARMMMUIdx_E20_2_PAN:
|
||||||
case ARMMMUIdx_Stage2:
|
case ARMMMUIdx_Stage2:
|
||||||
case ARMMMUIdx_E2:
|
case ARMMMUIdx_E2:
|
||||||
return 2;
|
return 2;
|
||||||
@ -9215,10 +9374,13 @@ static uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
|
|||||||
case ARMMMUIdx_SE10_0:
|
case ARMMMUIdx_SE10_0:
|
||||||
return arm_el_is_aa64(env, 3) ? 1 : 3;
|
return arm_el_is_aa64(env, 3) ? 1 : 3;
|
||||||
case ARMMMUIdx_SE10_1:
|
case ARMMMUIdx_SE10_1:
|
||||||
|
case ARMMMUIdx_SE10_1_PAN:
|
||||||
case ARMMMUIdx_Stage1_E0:
|
case ARMMMUIdx_Stage1_E0:
|
||||||
case ARMMMUIdx_Stage1_E1:
|
case ARMMMUIdx_Stage1_E1:
|
||||||
|
case ARMMMUIdx_Stage1_E1_PAN:
|
||||||
case ARMMMUIdx_E10_0:
|
case ARMMMUIdx_E10_0:
|
||||||
case ARMMMUIdx_E10_1:
|
case ARMMMUIdx_E10_1:
|
||||||
|
case ARMMMUIdx_E10_1_PAN:
|
||||||
case ARMMMUIdx_MPrivNegPri:
|
case ARMMMUIdx_MPrivNegPri:
|
||||||
case ARMMMUIdx_MUserNegPri:
|
case ARMMMUIdx_MUserNegPri:
|
||||||
case ARMMMUIdx_MPriv:
|
case ARMMMUIdx_MPriv:
|
||||||
@ -9285,8 +9447,7 @@ static inline bool regime_translation_disabled(CPUARMState *env,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((env->cp15.hcr_el2 & HCR_DC) &&
|
if ((env->cp15.hcr_el2 & HCR_DC) && arm_mmu_idx_is_stage1_of_2(mmu_idx)) {
|
||||||
(mmu_idx == ARMMMUIdx_Stage1_E0 || mmu_idx == ARMMMUIdx_Stage1_E1)) {
|
|
||||||
/* HCR.DC means SCTLR_EL1.M behaves as 0 */
|
/* HCR.DC means SCTLR_EL1.M behaves as 0 */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -9335,6 +9496,8 @@ static inline ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx)
|
|||||||
return ARMMMUIdx_Stage1_E0;
|
return ARMMMUIdx_Stage1_E0;
|
||||||
case ARMMMUIdx_E10_1:
|
case ARMMMUIdx_E10_1:
|
||||||
return ARMMMUIdx_Stage1_E1;
|
return ARMMMUIdx_Stage1_E1;
|
||||||
|
case ARMMMUIdx_E10_1_PAN:
|
||||||
|
return ARMMMUIdx_Stage1_E1_PAN;
|
||||||
default:
|
default:
|
||||||
return mmu_idx;
|
return mmu_idx;
|
||||||
}
|
}
|
||||||
@ -9381,6 +9544,7 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx)
|
|||||||
return false;
|
return false;
|
||||||
case ARMMMUIdx_E10_0:
|
case ARMMMUIdx_E10_0:
|
||||||
case ARMMMUIdx_E10_1:
|
case ARMMMUIdx_E10_1:
|
||||||
|
case ARMMMUIdx_E10_1_PAN:
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9517,6 +9681,9 @@ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64,
|
|||||||
if (is_user) {
|
if (is_user) {
|
||||||
prot_rw = user_rw;
|
prot_rw = user_rw;
|
||||||
} else {
|
} else {
|
||||||
|
if (user_rw && regime_is_pan(env, mmu_idx)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
prot_rw = simple_ap_to_rw_prot_is_user(ap, false);
|
prot_rw = simple_ap_to_rw_prot_is_user(ap, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9595,7 +9762,7 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx,
|
|||||||
hwaddr addr, MemTxAttrs txattrs,
|
hwaddr addr, MemTxAttrs txattrs,
|
||||||
ARMMMUFaultInfo *fi)
|
ARMMMUFaultInfo *fi)
|
||||||
{
|
{
|
||||||
if ((mmu_idx == ARMMMUIdx_Stage1_E0 || mmu_idx == ARMMMUIdx_Stage1_E1) &&
|
if (arm_mmu_idx_is_stage1_of_2(mmu_idx) &&
|
||||||
!regime_translation_disabled(env, ARMMMUIdx_Stage2)) {
|
!regime_translation_disabled(env, ARMMMUIdx_Stage2)) {
|
||||||
target_ulong s2size;
|
target_ulong s2size;
|
||||||
hwaddr s2pa;
|
hwaddr s2pa;
|
||||||
@ -11273,7 +11440,9 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
|
|||||||
target_ulong *page_size,
|
target_ulong *page_size,
|
||||||
ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs)
|
ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs)
|
||||||
{
|
{
|
||||||
if (mmu_idx == ARMMMUIdx_E10_0 || mmu_idx == ARMMMUIdx_E10_1) {
|
if (mmu_idx == ARMMMUIdx_E10_0 ||
|
||||||
|
mmu_idx == ARMMMUIdx_E10_1 ||
|
||||||
|
mmu_idx == ARMMMUIdx_E10_1_PAN) {
|
||||||
/* Call ourselves recursively to do the stage 1 and then stage 2
|
/* Call ourselves recursively to do the stage 1 and then stage 2
|
||||||
* translations.
|
* translations.
|
||||||
*/
|
*/
|
||||||
@ -11800,10 +11969,13 @@ int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
|
|||||||
case ARMMMUIdx_SE10_0:
|
case ARMMMUIdx_SE10_0:
|
||||||
return 0;
|
return 0;
|
||||||
case ARMMMUIdx_E10_1:
|
case ARMMMUIdx_E10_1:
|
||||||
|
case ARMMMUIdx_E10_1_PAN:
|
||||||
case ARMMMUIdx_SE10_1:
|
case ARMMMUIdx_SE10_1:
|
||||||
|
case ARMMMUIdx_SE10_1_PAN:
|
||||||
return 1;
|
return 1;
|
||||||
case ARMMMUIdx_E2:
|
case ARMMMUIdx_E2:
|
||||||
case ARMMMUIdx_E20_2:
|
case ARMMMUIdx_E20_2:
|
||||||
|
case ARMMMUIdx_E20_2_PAN:
|
||||||
return 2;
|
return 2;
|
||||||
case ARMMMUIdx_SE3:
|
case ARMMMUIdx_SE3:
|
||||||
return 3;
|
return 3;
|
||||||
@ -11838,13 +12010,22 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el)
|
|||||||
return ARMMMUIdx_E10_0;
|
return ARMMMUIdx_E10_0;
|
||||||
case 1:
|
case 1:
|
||||||
if (arm_is_secure_below_el3(env)) {
|
if (arm_is_secure_below_el3(env)) {
|
||||||
|
if (env->pstate & PSTATE_PAN) {
|
||||||
|
return ARMMMUIdx_SE10_1_PAN;
|
||||||
|
}
|
||||||
return ARMMMUIdx_SE10_1;
|
return ARMMMUIdx_SE10_1;
|
||||||
}
|
}
|
||||||
|
if (env->pstate & PSTATE_PAN) {
|
||||||
|
return ARMMMUIdx_E10_1_PAN;
|
||||||
|
}
|
||||||
return ARMMMUIdx_E10_1;
|
return ARMMMUIdx_E10_1;
|
||||||
case 2:
|
case 2:
|
||||||
/* TODO: ARMv8.4-SecEL2 */
|
/* TODO: ARMv8.4-SecEL2 */
|
||||||
/* Note that TGE does not apply at EL2. */
|
/* Note that TGE does not apply at EL2. */
|
||||||
if ((env->cp15.hcr_el2 & HCR_E2H) && arm_el_is_aa64(env, 2)) {
|
if ((env->cp15.hcr_el2 & HCR_E2H) && arm_el_is_aa64(env, 2)) {
|
||||||
|
if (env->pstate & PSTATE_PAN) {
|
||||||
|
return ARMMMUIdx_E20_2_PAN;
|
||||||
|
}
|
||||||
return ARMMMUIdx_E20_2;
|
return ARMMMUIdx_E20_2;
|
||||||
}
|
}
|
||||||
return ARMMMUIdx_E2;
|
return ARMMMUIdx_E2;
|
||||||
@ -12017,25 +12198,29 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the condition for using AccType_UNPRIV for LDTR et al. */
|
/* Compute the condition for using AccType_UNPRIV for LDTR et al. */
|
||||||
/* TODO: ARMv8.2-UAO */
|
if (!(env->pstate & PSTATE_UAO)) {
|
||||||
switch (mmu_idx) {
|
switch (mmu_idx) {
|
||||||
case ARMMMUIdx_E10_1:
|
case ARMMMUIdx_E10_1:
|
||||||
case ARMMMUIdx_SE10_1:
|
case ARMMMUIdx_E10_1_PAN:
|
||||||
/* TODO: ARMv8.3-NV */
|
case ARMMMUIdx_SE10_1:
|
||||||
flags = FIELD_DP32(flags, TBFLAG_A64, UNPRIV, 1);
|
case ARMMMUIdx_SE10_1_PAN:
|
||||||
break;
|
/* TODO: ARMv8.3-NV */
|
||||||
case ARMMMUIdx_E20_2:
|
|
||||||
/* TODO: ARMv8.4-SecEL2 */
|
|
||||||
/*
|
|
||||||
* Note that E20_2 is gated by HCR_EL2.E2H == 1, but E20_0 is
|
|
||||||
* gated by HCR_EL2.<E2H,TGE> == '11', and so is LDTR.
|
|
||||||
*/
|
|
||||||
if (env->cp15.hcr_el2 & HCR_TGE) {
|
|
||||||
flags = FIELD_DP32(flags, TBFLAG_A64, UNPRIV, 1);
|
flags = FIELD_DP32(flags, TBFLAG_A64, UNPRIV, 1);
|
||||||
|
break;
|
||||||
|
case ARMMMUIdx_E20_2:
|
||||||
|
case ARMMMUIdx_E20_2_PAN:
|
||||||
|
/* TODO: ARMv8.4-SecEL2 */
|
||||||
|
/*
|
||||||
|
* Note that EL20_2 is gated by HCR_EL2.E2H == 1, but EL20_0 is
|
||||||
|
* gated by HCR_EL2.<E2H,TGE> == '11', and so is LDTR.
|
||||||
|
*/
|
||||||
|
if (env->cp15.hcr_el2 & HCR_TGE) {
|
||||||
|
flags = FIELD_DP32(flags, TBFLAG_A64, UNPRIV, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rebuild_hflags_common(env, fp_el, mmu_idx, flags);
|
return rebuild_hflags_common(env, fp_el, mmu_idx, flags);
|
||||||
|
@ -843,12 +843,16 @@ static inline bool regime_has_2_ranges(ARMMMUIdx mmu_idx)
|
|||||||
switch (mmu_idx) {
|
switch (mmu_idx) {
|
||||||
case ARMMMUIdx_Stage1_E0:
|
case ARMMMUIdx_Stage1_E0:
|
||||||
case ARMMMUIdx_Stage1_E1:
|
case ARMMMUIdx_Stage1_E1:
|
||||||
|
case ARMMMUIdx_Stage1_E1_PAN:
|
||||||
case ARMMMUIdx_E10_0:
|
case ARMMMUIdx_E10_0:
|
||||||
case ARMMMUIdx_E10_1:
|
case ARMMMUIdx_E10_1:
|
||||||
|
case ARMMMUIdx_E10_1_PAN:
|
||||||
case ARMMMUIdx_E20_0:
|
case ARMMMUIdx_E20_0:
|
||||||
case ARMMMUIdx_E20_2:
|
case ARMMMUIdx_E20_2:
|
||||||
|
case ARMMMUIdx_E20_2_PAN:
|
||||||
case ARMMMUIdx_SE10_0:
|
case ARMMMUIdx_SE10_0:
|
||||||
case ARMMMUIdx_SE10_1:
|
case ARMMMUIdx_SE10_1:
|
||||||
|
case ARMMMUIdx_SE10_1_PAN:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@ -861,10 +865,13 @@ static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx)
|
|||||||
switch (mmu_idx) {
|
switch (mmu_idx) {
|
||||||
case ARMMMUIdx_E10_0:
|
case ARMMMUIdx_E10_0:
|
||||||
case ARMMMUIdx_E10_1:
|
case ARMMMUIdx_E10_1:
|
||||||
|
case ARMMMUIdx_E10_1_PAN:
|
||||||
case ARMMMUIdx_E20_0:
|
case ARMMMUIdx_E20_0:
|
||||||
case ARMMMUIdx_E20_2:
|
case ARMMMUIdx_E20_2:
|
||||||
|
case ARMMMUIdx_E20_2_PAN:
|
||||||
case ARMMMUIdx_Stage1_E0:
|
case ARMMMUIdx_Stage1_E0:
|
||||||
case ARMMMUIdx_Stage1_E1:
|
case ARMMMUIdx_Stage1_E1:
|
||||||
|
case ARMMMUIdx_Stage1_E1_PAN:
|
||||||
case ARMMMUIdx_E2:
|
case ARMMMUIdx_E2:
|
||||||
case ARMMMUIdx_Stage2:
|
case ARMMMUIdx_Stage2:
|
||||||
case ARMMMUIdx_MPrivNegPri:
|
case ARMMMUIdx_MPrivNegPri:
|
||||||
@ -875,6 +882,7 @@ static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx)
|
|||||||
case ARMMMUIdx_SE3:
|
case ARMMMUIdx_SE3:
|
||||||
case ARMMMUIdx_SE10_0:
|
case ARMMMUIdx_SE10_0:
|
||||||
case ARMMMUIdx_SE10_1:
|
case ARMMMUIdx_SE10_1:
|
||||||
|
case ARMMMUIdx_SE10_1_PAN:
|
||||||
case ARMMMUIdx_MSPrivNegPri:
|
case ARMMMUIdx_MSPrivNegPri:
|
||||||
case ARMMMUIdx_MSUserNegPri:
|
case ARMMMUIdx_MSUserNegPri:
|
||||||
case ARMMMUIdx_MSPriv:
|
case ARMMMUIdx_MSPriv:
|
||||||
@ -885,6 +893,19 @@ static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool regime_is_pan(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||||
|
{
|
||||||
|
switch (mmu_idx) {
|
||||||
|
case ARMMMUIdx_Stage1_E1_PAN:
|
||||||
|
case ARMMMUIdx_E10_1_PAN:
|
||||||
|
case ARMMMUIdx_E20_2_PAN:
|
||||||
|
case ARMMMUIdx_SE10_1_PAN:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the FSR value for a debug exception (watchpoint, hardware
|
/* Return the FSR value for a debug exception (watchpoint, hardware
|
||||||
* breakpoint or BKPT insn) targeting the specified exception level.
|
* breakpoint or BKPT insn) targeting the specified exception level.
|
||||||
*/
|
*/
|
||||||
@ -1034,6 +1055,70 @@ static inline ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env)
|
|||||||
ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env);
|
ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* arm_mmu_idx_is_stage1_of_2:
|
||||||
|
* @mmu_idx: The ARMMMUIdx to test
|
||||||
|
*
|
||||||
|
* Return true if @mmu_idx is a NOTLB mmu_idx that is the
|
||||||
|
* first stage of a two stage regime.
|
||||||
|
*/
|
||||||
|
static inline bool arm_mmu_idx_is_stage1_of_2(ARMMMUIdx mmu_idx)
|
||||||
|
{
|
||||||
|
switch (mmu_idx) {
|
||||||
|
case ARMMMUIdx_Stage1_E0:
|
||||||
|
case ARMMMUIdx_Stage1_E1:
|
||||||
|
case ARMMMUIdx_Stage1_E1_PAN:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t aarch32_cpsr_valid_mask(uint64_t features,
|
||||||
|
const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
uint32_t valid = CPSR_M | CPSR_AIF | CPSR_IL | CPSR_NZCV;
|
||||||
|
|
||||||
|
if ((features >> ARM_FEATURE_V4T) & 1) {
|
||||||
|
valid |= CPSR_T;
|
||||||
|
}
|
||||||
|
if ((features >> ARM_FEATURE_V5) & 1) {
|
||||||
|
valid |= CPSR_Q; /* V5TE in reality*/
|
||||||
|
}
|
||||||
|
if ((features >> ARM_FEATURE_V6) & 1) {
|
||||||
|
valid |= CPSR_E | CPSR_GE;
|
||||||
|
}
|
||||||
|
if ((features >> ARM_FEATURE_THUMB2) & 1) {
|
||||||
|
valid |= CPSR_IT;
|
||||||
|
}
|
||||||
|
if (isar_feature_jazelle(id)) {
|
||||||
|
valid |= CPSR_J;
|
||||||
|
}
|
||||||
|
if (isar_feature_aa32_pan(id)) {
|
||||||
|
valid |= CPSR_PAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t aarch64_pstate_valid_mask(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
uint32_t valid;
|
||||||
|
|
||||||
|
valid = PSTATE_M | PSTATE_DAIF | PSTATE_IL | PSTATE_SS | PSTATE_NZCV;
|
||||||
|
if (isar_feature_aa64_bti(id)) {
|
||||||
|
valid |= PSTATE_BTYPE;
|
||||||
|
}
|
||||||
|
if (isar_feature_aa64_pan(id)) {
|
||||||
|
valid |= PSTATE_PAN;
|
||||||
|
}
|
||||||
|
if (isar_feature_aa64_uao(id)) {
|
||||||
|
valid |= PSTATE_UAO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parameters of a given virtual address, as extracted from the
|
* Parameters of a given virtual address, as extracted from the
|
||||||
* translation control register (TCR) for a given regime.
|
* translation control register (TCR) for a given regime.
|
||||||
|
@ -549,6 +549,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
|
|||||||
ARM64_SYS_REG(3, 0, 0, 7, 0));
|
ARM64_SYS_REG(3, 0, 0, 7, 0));
|
||||||
err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr1,
|
err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr1,
|
||||||
ARM64_SYS_REG(3, 0, 0, 7, 1));
|
ARM64_SYS_REG(3, 0, 0, 7, 1));
|
||||||
|
err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr2,
|
||||||
|
ARM64_SYS_REG(3, 0, 0, 7, 2));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that if AArch32 support is not present in the host,
|
* Note that if AArch32 support is not present in the host,
|
||||||
|
@ -387,7 +387,14 @@ void HELPER(exception_bkpt_insn)(CPUARMState *env, uint32_t syndrome)
|
|||||||
|
|
||||||
uint32_t HELPER(cpsr_read)(CPUARMState *env)
|
uint32_t HELPER(cpsr_read)(CPUARMState *env)
|
||||||
{
|
{
|
||||||
return cpsr_read(env) & ~(CPSR_EXEC | CPSR_RESERVED);
|
/*
|
||||||
|
* We store the ARMv8 PSTATE.SS bit in env->uncached_cpsr.
|
||||||
|
* This is convenient for populating SPSR_ELx, but must be
|
||||||
|
* hidden from aarch32 mode, where it is not visible.
|
||||||
|
*
|
||||||
|
* TODO: ARMv8.4-DIT -- need to move SS somewhere else.
|
||||||
|
*/
|
||||||
|
return cpsr_read(env) & ~(CPSR_EXEC | PSTATE_SS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
|
void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
|
||||||
@ -400,11 +407,14 @@ void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
|
|||||||
/* Write the CPSR for a 32-bit exception return */
|
/* Write the CPSR for a 32-bit exception return */
|
||||||
void HELPER(cpsr_write_eret)(CPUARMState *env, uint32_t val)
|
void HELPER(cpsr_write_eret)(CPUARMState *env, uint32_t val)
|
||||||
{
|
{
|
||||||
|
uint32_t mask;
|
||||||
|
|
||||||
qemu_mutex_lock_iothread();
|
qemu_mutex_lock_iothread();
|
||||||
arm_call_pre_el_change_hook(env_archcpu(env));
|
arm_call_pre_el_change_hook(env_archcpu(env));
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
|
|
||||||
cpsr_write(env, val, CPSR_ERET_MASK, CPSRWriteExceptionReturn);
|
mask = aarch32_cpsr_valid_mask(env->features, &env_archcpu(env)->isar);
|
||||||
|
cpsr_write(env, val, mask, CPSRWriteExceptionReturn);
|
||||||
|
|
||||||
/* Generated code has already stored the new PC value, but
|
/* Generated code has already stored the new PC value, but
|
||||||
* without masking out its low bits, because which bits need
|
* without masking out its low bits, because which bits need
|
||||||
|
@ -124,12 +124,15 @@ static int get_a64_user_mem_index(DisasContext *s)
|
|||||||
*/
|
*/
|
||||||
switch (useridx) {
|
switch (useridx) {
|
||||||
case ARMMMUIdx_E10_1:
|
case ARMMMUIdx_E10_1:
|
||||||
|
case ARMMMUIdx_E10_1_PAN:
|
||||||
useridx = ARMMMUIdx_E10_0;
|
useridx = ARMMMUIdx_E10_0;
|
||||||
break;
|
break;
|
||||||
case ARMMMUIdx_E20_2:
|
case ARMMMUIdx_E20_2:
|
||||||
|
case ARMMMUIdx_E20_2_PAN:
|
||||||
useridx = ARMMMUIdx_E20_0;
|
useridx = ARMMMUIdx_E20_0;
|
||||||
break;
|
break;
|
||||||
case ARMMMUIdx_SE10_1:
|
case ARMMMUIdx_SE10_1:
|
||||||
|
case ARMMMUIdx_SE10_1_PAN:
|
||||||
useridx = ARMMMUIdx_SE10_0;
|
useridx = ARMMMUIdx_SE10_0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -1599,6 +1602,34 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
|
|||||||
s->base.is_jmp = DISAS_NEXT;
|
s->base.is_jmp = DISAS_NEXT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x03: /* UAO */
|
||||||
|
if (!dc_isar_feature(aa64_uao, s) || s->current_el == 0) {
|
||||||
|
goto do_unallocated;
|
||||||
|
}
|
||||||
|
if (crm & 1) {
|
||||||
|
set_pstate_bits(PSTATE_UAO);
|
||||||
|
} else {
|
||||||
|
clear_pstate_bits(PSTATE_UAO);
|
||||||
|
}
|
||||||
|
t1 = tcg_const_i32(s->current_el);
|
||||||
|
gen_helper_rebuild_hflags_a64(cpu_env, t1);
|
||||||
|
tcg_temp_free_i32(t1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x04: /* PAN */
|
||||||
|
if (!dc_isar_feature(aa64_pan, s) || s->current_el == 0) {
|
||||||
|
goto do_unallocated;
|
||||||
|
}
|
||||||
|
if (crm & 1) {
|
||||||
|
set_pstate_bits(PSTATE_PAN);
|
||||||
|
} else {
|
||||||
|
clear_pstate_bits(PSTATE_PAN);
|
||||||
|
}
|
||||||
|
t1 = tcg_const_i32(s->current_el);
|
||||||
|
gen_helper_rebuild_hflags_a64(cpu_env, t1);
|
||||||
|
tcg_temp_free_i32(t1);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x05: /* SPSel */
|
case 0x05: /* SPSel */
|
||||||
if (s->current_el == 0) {
|
if (s->current_el == 0) {
|
||||||
goto do_unallocated;
|
goto do_unallocated;
|
||||||
|
@ -155,10 +155,12 @@ static inline int get_a32_user_mem_index(DisasContext *s)
|
|||||||
case ARMMMUIdx_E2: /* this one is UNPREDICTABLE */
|
case ARMMMUIdx_E2: /* this one is UNPREDICTABLE */
|
||||||
case ARMMMUIdx_E10_0:
|
case ARMMMUIdx_E10_0:
|
||||||
case ARMMMUIdx_E10_1:
|
case ARMMMUIdx_E10_1:
|
||||||
|
case ARMMMUIdx_E10_1_PAN:
|
||||||
return arm_to_core_mmu_idx(ARMMMUIdx_E10_0);
|
return arm_to_core_mmu_idx(ARMMMUIdx_E10_0);
|
||||||
case ARMMMUIdx_SE3:
|
case ARMMMUIdx_SE3:
|
||||||
case ARMMMUIdx_SE10_0:
|
case ARMMMUIdx_SE10_0:
|
||||||
case ARMMMUIdx_SE10_1:
|
case ARMMMUIdx_SE10_1:
|
||||||
|
case ARMMMUIdx_SE10_1_PAN:
|
||||||
return arm_to_core_mmu_idx(ARMMMUIdx_SE10_0);
|
return arm_to_core_mmu_idx(ARMMMUIdx_SE10_0);
|
||||||
case ARMMMUIdx_MUser:
|
case ARMMMUIdx_MUser:
|
||||||
case ARMMMUIdx_MPriv:
|
case ARMMMUIdx_MPriv:
|
||||||
@ -2732,39 +2734,33 @@ static inline void gen_mulxy(TCGv_i32 t0, TCGv_i32 t1, int x, int y)
|
|||||||
/* Return the mask of PSR bits set by a MSR instruction. */
|
/* Return the mask of PSR bits set by a MSR instruction. */
|
||||||
static uint32_t msr_mask(DisasContext *s, int flags, int spsr)
|
static uint32_t msr_mask(DisasContext *s, int flags, int spsr)
|
||||||
{
|
{
|
||||||
uint32_t mask;
|
uint32_t mask = 0;
|
||||||
|
|
||||||
mask = 0;
|
if (flags & (1 << 0)) {
|
||||||
if (flags & (1 << 0))
|
|
||||||
mask |= 0xff;
|
mask |= 0xff;
|
||||||
if (flags & (1 << 1))
|
}
|
||||||
|
if (flags & (1 << 1)) {
|
||||||
mask |= 0xff00;
|
mask |= 0xff00;
|
||||||
if (flags & (1 << 2))
|
}
|
||||||
|
if (flags & (1 << 2)) {
|
||||||
mask |= 0xff0000;
|
mask |= 0xff0000;
|
||||||
if (flags & (1 << 3))
|
}
|
||||||
|
if (flags & (1 << 3)) {
|
||||||
mask |= 0xff000000;
|
mask |= 0xff000000;
|
||||||
|
}
|
||||||
|
|
||||||
/* Mask out undefined bits. */
|
/* Mask out undefined and reserved bits. */
|
||||||
mask &= ~CPSR_RESERVED;
|
mask &= aarch32_cpsr_valid_mask(s->features, s->isar);
|
||||||
if (!arm_dc_feature(s, ARM_FEATURE_V4T)) {
|
|
||||||
mask &= ~CPSR_T;
|
/* Mask out execution state. */
|
||||||
}
|
|
||||||
if (!arm_dc_feature(s, ARM_FEATURE_V5)) {
|
|
||||||
mask &= ~CPSR_Q; /* V5TE in reality*/
|
|
||||||
}
|
|
||||||
if (!arm_dc_feature(s, ARM_FEATURE_V6)) {
|
|
||||||
mask &= ~(CPSR_E | CPSR_GE);
|
|
||||||
}
|
|
||||||
if (!arm_dc_feature(s, ARM_FEATURE_THUMB2)) {
|
|
||||||
mask &= ~CPSR_IT;
|
|
||||||
}
|
|
||||||
/* Mask out execution state and reserved bits. */
|
|
||||||
if (!spsr) {
|
if (!spsr) {
|
||||||
mask &= ~(CPSR_EXEC | CPSR_RESERVED);
|
mask &= ~CPSR_EXEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mask out privileged bits. */
|
/* Mask out privileged bits. */
|
||||||
if (IS_USER(s))
|
if (IS_USER(s)) {
|
||||||
mask &= CPSR_USER;
|
mask &= CPSR_USER;
|
||||||
|
}
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user