target-arm queue:

* Implement AArch32 ARMv8-R support
  * Add Cortex-R52 CPU
  * fix handling of HLT semihosting in system mode
  * hw/timer/ixm_epit: cleanup and fix bug in compare handling
  * target/arm: Coding style fixes
  * target/arm: Clean up includes
  * nseries: minor code cleanups
  * target/arm: align exposed ID registers with Linux
  * hw/arm/smmu-common: remove unnecessary inlines
  * i.MX7D: Handle GPT timers
  * i.MX7D: Connect IRQs to GPIO devices
  * i.MX6UL: Add a specific GPT timer instance
  * hw/net: Fix read of uninitialized memory in imx_fec
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmO2/iYZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3sy1EACPsxR5R19BbfwuR3e2VKrA
 3ltc1ZwiEiDzKE0YJ+VL8zSyzNKFs0OD4O+ZOBPu5PegwhLdH5QI5QrhkRwlWr6T
 XJfNDF+8oUUIlNYeD9iSOiZt+W7cnaWrHoM4Oga3O610eS6f0hGmfVxlXUxUfT/4
 3x/MKcSXI4SnwXuXrxmqmTm7sVCXP8cbqrIZzN5VUo341B1uqQ5bp1hRmiLt+cvY
 pnCk3MgYCuZAXRQrLShJkFeu3lJ/W89DVAY5v5+VAMR3jD/tTvQ5bP4HdBMJP4RY
 AyoI/4cmlAnvOq4Yr8wKdWo7/fgkj9sTHV11sRWkiOdKhLZe9aNYnv1Bd2COhmvH
 gJcWZ8SNpJ364iRoQPy1PeKxuSMQaesUKWXkvkqjsaGKD9gr2QjTpI3yN6wU3O5+
 lT4wGsDMHDhpQml2r19+D3XGm5oA+t2sr1/27WjKBDYopTtZF/KuJ1xVMnIRxzJW
 M+V3BcM4RPivmv0a+ICA6f1WwE59EeBBzOfZ+VjBpnQAfTv9HRN1yCIVWRN8hIiz
 cC/iuY6tGxpdZf965fYCIj5cZ2OmCbIw1mh5hUSLDIaCd9+qXl7cgT7stpLar7kA
 tYDazF2J3v+XqUeyWtPndzAFdgr4rLNH9Q9kDKS9fyXOspIFqv6bBhAMMxiiTbT5
 zj5Y2K1lAyHLTTwWmcNruw==
 =b/pm
 -----END PGP SIGNATURE-----

Merge tag 'pull-target-arm-20230105' of https://git.linaro.org/people/pmaydell/qemu-arm into staging

target-arm queue:
 * Implement AArch32 ARMv8-R support
 * Add Cortex-R52 CPU
 * fix handling of HLT semihosting in system mode
 * hw/timer/ixm_epit: cleanup and fix bug in compare handling
 * target/arm: Coding style fixes
 * target/arm: Clean up includes
 * nseries: minor code cleanups
 * target/arm: align exposed ID registers with Linux
 * hw/arm/smmu-common: remove unnecessary inlines
 * i.MX7D: Handle GPT timers
 * i.MX7D: Connect IRQs to GPIO devices
 * i.MX6UL: Add a specific GPT timer instance
 * hw/net: Fix read of uninitialized memory in imx_fec

# gpg: Signature made Thu 05 Jan 2023 16:43:18 GMT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# gpg:                 aka "Peter Maydell <peter@archaic.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* tag 'pull-target-arm-20230105' of https://git.linaro.org/people/pmaydell/qemu-arm: (34 commits)
  hw/net: Fix read of uninitialized memory in imx_fec.
  i.MX7D: Connect IRQs to GPIO devices.
  i.MX6UL: Add a specific GPT timer instance for the i.MX6UL
  i.MX7D: Compute clock frequency for the fixed frequency clocks.
  i.MX7D: Connect GPT timers to IRQ
  hw/arm/smmu-common: Avoid using inlined functions with external linkage
  hw/arm/smmu-common: Reduce smmu_inv_notifiers_mr() scope
  target/arm: align exposed ID registers with Linux
  hw/arm/nseries: Silent -Wmissing-field-initializers warning
  hw/arm/nseries: Constify various read-only arrays
  hw/input/tsc2xxx: Constify set_transform()'s MouseTransformInfo arg
  target/arm: cleanup cpu includes
  target/arm: Remove unused includes from helper.c
  target/arm: Remove unused includes from m_helper.c
  target/arm: Fix checkpatch brace errors in helper.c
  target/arm: Fix checkpatch space errors in helper.c
  target/arm: Fix checkpatch comment style warnings in helper.c
  hw/timer/imx_epit: fix compare timer handling
  hw/timer/imx_epit: remove explicit fields cnt and freq
  hw/timer/imx_epit: factor out register write handlers
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2023-01-05 21:04:52 +00:00
commit d365cb0b9d
30 changed files with 1330 additions and 461 deletions

View File

@ -81,7 +81,7 @@ static void fsl_imx6ul_init(Object *obj)
*/
for (i = 0; i < FSL_IMX6UL_NUM_GPTS; i++) {
snprintf(name, NAME_SIZE, "gpt%d", i);
object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX7_GPT);
object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX6UL_GPT);
}
/*

View File

@ -219,9 +219,19 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
FSL_IMX7_GPT4_ADDR,
};
static const int FSL_IMX7_GPTn_IRQ[FSL_IMX7_NUM_GPTS] = {
FSL_IMX7_GPT1_IRQ,
FSL_IMX7_GPT2_IRQ,
FSL_IMX7_GPT3_IRQ,
FSL_IMX7_GPT4_IRQ,
};
s->gpt[i].ccm = IMX_CCM(&s->ccm);
sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, FSL_IMX7_GPTn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
FSL_IMX7_GPTn_IRQ[i]));
}
for (i = 0; i < FSL_IMX7_NUM_GPIOS; i++) {
@ -235,8 +245,37 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
FSL_IMX7_GPIO7_ADDR,
};
static const int FSL_IMX7_GPIOn_LOW_IRQ[FSL_IMX7_NUM_GPIOS] = {
FSL_IMX7_GPIO1_LOW_IRQ,
FSL_IMX7_GPIO2_LOW_IRQ,
FSL_IMX7_GPIO3_LOW_IRQ,
FSL_IMX7_GPIO4_LOW_IRQ,
FSL_IMX7_GPIO5_LOW_IRQ,
FSL_IMX7_GPIO6_LOW_IRQ,
FSL_IMX7_GPIO7_LOW_IRQ,
};
static const int FSL_IMX7_GPIOn_HIGH_IRQ[FSL_IMX7_NUM_GPIOS] = {
FSL_IMX7_GPIO1_HIGH_IRQ,
FSL_IMX7_GPIO2_HIGH_IRQ,
FSL_IMX7_GPIO3_HIGH_IRQ,
FSL_IMX7_GPIO4_HIGH_IRQ,
FSL_IMX7_GPIO5_HIGH_IRQ,
FSL_IMX7_GPIO6_HIGH_IRQ,
FSL_IMX7_GPIO7_HIGH_IRQ,
};
sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, FSL_IMX7_GPIOn_ADDR[i]);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0,
FSL_IMX7_GPIOn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
FSL_IMX7_GPIOn_LOW_IRQ[i]));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
FSL_IMX7_GPIOn_HIGH_IRQ[i]));
}
/*

View File

@ -230,13 +230,13 @@ static void n8x0_i2c_setup(struct n800_s *s)
}
/* Touchscreen and keypad controller */
static MouseTransformInfo n800_pointercal = {
static const MouseTransformInfo n800_pointercal = {
.x = 800,
.y = 480,
.a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 },
};
static MouseTransformInfo n810_pointercal = {
static const MouseTransformInfo n810_pointercal = {
.x = 800,
.y = 480,
.a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 },
@ -334,7 +334,7 @@ static void n810_key_event(void *opaque, int keycode)
#define M 0
static int n810_keys[0x80] = {
static const int n810_keys[0x80] = {
[0x01] = 16, /* Q */
[0x02] = 37, /* K */
[0x03] = 24, /* O */
@ -810,7 +810,7 @@ static void n8x0_usb_setup(struct n800_s *s)
/* Setup done before the main bootloader starts by some early setup code
* - used when we want to run the main bootloader in emulation. This
* isn't documented. */
static uint32_t n800_pinout[104] = {
static const uint32_t n800_pinout[104] = {
0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0,
0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808,
0x08080808, 0x180800c4, 0x00b80000, 0x08080808,
@ -1060,7 +1060,7 @@ static void n8x0_boot_init(void *opaque)
#define OMAP_TAG_CBUS 0x4e03
#define OMAP_TAG_EM_ASIC_BB5 0x4e04
static struct omap_gpiosw_info_s {
static const struct omap_gpiosw_info_s {
const char *name;
int line;
int type;
@ -1078,7 +1078,7 @@ static struct omap_gpiosw_info_s {
"headphone", N8X0_HEADPHONE_GPIO,
OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
},
{ NULL }
{ /* end of list */ }
}, n810_gpiosw_info[] = {
{
"gps_reset", N810_GPS_RESET_GPIO,
@ -1099,10 +1099,10 @@ static struct omap_gpiosw_info_s {
"slide", N810_SLIDE_GPIO,
OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
},
{ NULL }
{ /* end of list */ }
};
static struct omap_partition_info_s {
static const struct omap_partition_info_s {
uint32_t offset;
uint32_t size;
int mask;
@ -1113,27 +1113,25 @@ static struct omap_partition_info_s {
{ 0x00080000, 0x00200000, 0x0, "kernel" },
{ 0x00280000, 0x00200000, 0x3, "initfs" },
{ 0x00480000, 0x0fb80000, 0x3, "rootfs" },
{ 0, 0, 0, NULL }
{ /* end of list */ }
}, n810_part_info[] = {
{ 0x00000000, 0x00020000, 0x3, "bootloader" },
{ 0x00020000, 0x00060000, 0x0, "config" },
{ 0x00080000, 0x00220000, 0x0, "kernel" },
{ 0x002a0000, 0x00400000, 0x0, "initfs" },
{ 0x006a0000, 0x0f960000, 0x0, "rootfs" },
{ 0, 0, 0, NULL }
{ /* end of list */ }
};
static uint8_t n8x0_bd_addr[6] = { N8X0_BD_ADDR };
static const uint8_t n8x0_bd_addr[6] = { N8X0_BD_ADDR };
static int n8x0_atag_setup(void *p, int model)
{
uint8_t *b;
uint16_t *w;
uint32_t *l;
struct omap_gpiosw_info_s *gpiosw;
struct omap_partition_info_s *partition;
const struct omap_gpiosw_info_s *gpiosw;
const struct omap_partition_info_s *partition;
const char *tag;
w = p;

View File

@ -116,7 +116,7 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *new)
g_hash_table_insert(bs->iotlb, key, new);
}
inline void smmu_iotlb_inv_all(SMMUState *s)
void smmu_iotlb_inv_all(SMMUState *s)
{
trace_smmu_iotlb_inv_all();
g_hash_table_remove_all(s->iotlb);
@ -146,9 +146,8 @@ static gboolean smmu_hash_remove_by_asid_iova(gpointer key, gpointer value,
((entry->iova & ~info->mask) == info->iova);
}
inline void
smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
uint8_t tg, uint64_t num_pages, uint8_t ttl)
void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
uint8_t tg, uint64_t num_pages, uint8_t ttl)
{
/* if tg is not set we use 4KB range invalidation */
uint8_t granule = tg ? tg * 2 + 10 : 12;
@ -174,7 +173,7 @@ smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
&info);
}
inline void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid)
void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid)
{
trace_smmu_iotlb_inv_asid(asid);
g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid);
@ -374,8 +373,8 @@ error:
*
* return 0 on success
*/
inline int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
{
if (!cfg->aa64) {
/*
@ -483,7 +482,7 @@ static void smmu_unmap_notifier_range(IOMMUNotifier *n)
}
/* Unmap all notifiers attached to @mr */
inline void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr)
static void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr)
{
IOMMUNotifier *n;

View File

@ -523,7 +523,7 @@ void *tsc2005_init(qemu_irq pintdav)
* from the touchscreen. Assuming 12-bit precision was used during
* tslib calibration.
*/
void tsc2005_set_transform(void *opaque, MouseTransformInfo *info)
void tsc2005_set_transform(void *opaque, const MouseTransformInfo *info)
{
TSC2005State *s = (TSC2005State *) opaque;

View File

@ -1176,8 +1176,7 @@ I2SCodec *tsc210x_codec(uWireSlave *chip)
* from the touchscreen. Assuming 12-bit precision was used during
* tslib calibration.
*/
void tsc210x_set_transform(uWireSlave *chip,
MouseTransformInfo *info)
void tsc210x_set_transform(uWireSlave *chip, const MouseTransformInfo *info)
{
TSC210xState *s = (TSC210xState *) chip->opaque;
#if 0

View File

@ -522,12 +522,6 @@ static uint32_t imx6ul_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
case CLK_32k:
freq = CKIL_FREQ;
break;
case CLK_HIGH:
freq = CKIH_FREQ;
break;
case CLK_HIGH_DIV:
freq = CKIH_FREQ / 8;
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
TYPE_IMX6UL_CCM, __func__, clock);

View File

@ -16,6 +16,10 @@
#include "hw/misc/imx7_ccm.h"
#include "migration/vmstate.h"
#include "trace.h"
#define CKIH_FREQ 24000000 /* 24MHz crystal input */
static void imx7_analog_reset(DeviceState *dev)
{
IMX7AnalogState *s = IMX7_ANALOG(dev);
@ -219,16 +223,43 @@ static const VMStateDescription vmstate_imx7_ccm = {
static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
{
/*
* This function is "consumed" by GPT emulation code, however on
* i.MX7 each GPT block can have their own clock root. This means
* that this functions needs somehow to know requester's identity
* and the way to pass it: be it via additional IMXClk constants
* or by adding another argument to this method needs to be
* figured out
* This function is "consumed" by GPT emulation code. Some clocks
* have fixed frequencies and we can provide requested frequency
* easily. However for CCM provided clocks (like IPG) each GPT
* timer can have its own clock root.
* This means we need additionnal information when calling this
* function to know the requester's identity.
*/
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Not implemented\n",
TYPE_IMX7_CCM, __func__);
return 0;
uint32_t freq = 0;
switch (clock) {
case CLK_NONE:
break;
case CLK_32k:
freq = CKIL_FREQ;
break;
case CLK_HIGH:
freq = CKIH_FREQ;
break;
case CLK_IPG:
case CLK_IPG_HIGH:
/*
* For now we don't have a way to figure out the device this
* function is called for. Until then the IPG derived clocks
* are left unimplemented.
*/
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Clock %d Not implemented\n",
TYPE_IMX7_CCM, __func__, clock);
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
TYPE_IMX7_CCM, __func__, clock);
break;
}
trace_ccm_clock_freq(clock, freq);
return freq;
}
static void imx7_ccm_class_init(ObjectClass *klass, void *data)

View File

@ -1068,9 +1068,9 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
return 0;
}
/* 4 bytes for the CRC. */
size += 4;
crc = cpu_to_be32(crc32(~0, buf, size));
/* Increase size by 4, loop below reads the last 4 bytes from crc_ptr. */
size += 4;
crc_ptr = (uint8_t *) &crc;
/* Huge frames are truncated. */
@ -1164,9 +1164,9 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
return 0;
}
/* 4 bytes for the CRC. */
size += 4;
crc = cpu_to_be32(crc32(~0, buf, size));
/* Increase size by 4, loop below reads the last 4 bytes from crc_ptr. */
size += 4;
crc_ptr = (uint8_t *) &crc;
if (shift16) {

View File

@ -6,6 +6,7 @@
* Originally written by Hans Jiang
* Updated by Peter Chubb
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
* Updated by Axel Heider
*
* This code is licensed under GPL version 2 or later. See
* the COPYING file in the top-level directory.
@ -66,73 +67,54 @@ static const IMXClk imx_epit_clocks[] = {
*/
static void imx_epit_update_int(IMXEPITState *s)
{
if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) {
if ((s->sr & SR_OCIF) && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) {
qemu_irq_raise(s->irq);
} else {
qemu_irq_lower(s->irq);
}
}
/*
* Must be called from within a ptimer_transaction_begin/commit block
* for both s->timer_cmp and s->timer_reload.
*/
static void imx_epit_set_freq(IMXEPITState *s)
static uint32_t imx_epit_get_freq(IMXEPITState *s)
{
uint32_t clksrc;
uint32_t prescaler;
clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2);
prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12);
s->freq = imx_ccm_get_clock_frequency(s->ccm,
imx_epit_clocks[clksrc]) / prescaler;
DPRINTF("Setting ptimer frequency to %u\n", s->freq);
if (s->freq) {
ptimer_set_freq(s->timer_reload, s->freq);
ptimer_set_freq(s->timer_cmp, s->freq);
}
uint32_t clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, CR_CLKSRC_BITS);
uint32_t prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, CR_PRESCALE_BITS);
uint32_t f_in = imx_ccm_get_clock_frequency(s->ccm, imx_epit_clocks[clksrc]);
uint32_t freq = f_in / prescaler;
DPRINTF("ptimer frequency is %u\n", freq);
return freq;
}
static void imx_epit_reset(DeviceState *dev)
/*
* This is called both on hardware (device) reset and software reset.
*/
static void imx_epit_reset(IMXEPITState *s, bool is_hard_reset)
{
IMXEPITState *s = IMX_EPIT(dev);
/*
* Soft reset doesn't touch some bits; hard reset clears them
*/
s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
/* Soft reset doesn't touch some bits; hard reset clears them */
if (is_hard_reset) {
s->cr = 0;
} else {
s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
}
s->sr = 0;
s->lr = EPIT_TIMER_MAX;
s->cmp = 0;
s->cnt = 0;
ptimer_transaction_begin(s->timer_cmp);
ptimer_transaction_begin(s->timer_reload);
/* stop both timers */
/*
* The reset switches off the input clock, so even if the CR.EN is still
* set, the timers are no longer running.
*/
assert(imx_epit_get_freq(s) == 0);
ptimer_stop(s->timer_cmp);
ptimer_stop(s->timer_reload);
/* compute new frequency */
imx_epit_set_freq(s);
/* init both timers to EPIT_TIMER_MAX */
ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
if (s->freq && (s->cr & CR_EN)) {
/* if the timer is still enabled, restart it */
ptimer_run(s->timer_reload, 0);
}
ptimer_transaction_commit(s->timer_cmp);
ptimer_transaction_commit(s->timer_reload);
}
static uint32_t imx_epit_update_count(IMXEPITState *s)
{
s->cnt = ptimer_get_count(s->timer_reload);
return s->cnt;
}
static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
{
IMXEPITState *s = IMX_EPIT(opaque);
@ -156,8 +138,7 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
break;
case 4: /* CNT */
imx_epit_update_count(s);
reg_value = s->cnt;
reg_value = ptimer_get_count(s->timer_reload);
break;
default:
@ -171,144 +152,219 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
return reg_value;
}
/* Must be called from ptimer_transaction_begin/commit block for s->timer_cmp */
static void imx_epit_reload_compare_timer(IMXEPITState *s)
/*
* Must be called from a ptimer_transaction_begin/commit block for
* s->timer_cmp, but outside of a transaction block of s->timer_reload,
* so the proper counter value is read.
*/
static void imx_epit_update_compare_timer(IMXEPITState *s)
{
if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN)) {
/* if the compare feature is on and timers are running */
uint32_t tmp = imx_epit_update_count(s);
uint64_t next;
if (tmp > s->cmp) {
/* It'll fire in this round of the timer */
next = tmp - s->cmp;
} else { /* catch it next time around */
next = tmp - s->cmp + ((s->cr & CR_RLD) ? EPIT_TIMER_MAX : s->lr);
uint64_t counter = 0;
bool is_oneshot = false;
/*
* The compare timer only has to run if the timer peripheral is active
* and there is an input clock, Otherwise it can be switched off.
*/
bool is_active = (s->cr & CR_EN) && imx_epit_get_freq(s);
if (is_active) {
/*
* Calculate next timeout for compare timer. Reading the reload
* counter returns proper results only if pending transactions
* on it are committed here. Otherwise stale values are be read.
*/
counter = ptimer_get_count(s->timer_reload);
uint64_t limit = ptimer_get_limit(s->timer_cmp);
/*
* The compare timer is a periodic timer if the limit is at least
* the compare value. Otherwise it may fire at most once in the
* current round.
*/
bool is_oneshot = (limit >= s->cmp);
if (counter >= s->cmp) {
/* The compare timer fires in the current round. */
counter -= s->cmp;
} else if (!is_oneshot) {
/*
* The compare timer fires after a reload, as it is below the
* compare value already in this round. Note that the counter
* value calculated below can be above the 32-bit limit, which
* is legal here because the compare timer is an internal
* helper ptimer only.
*/
counter += limit - s->cmp;
} else {
/*
* The compare timer won't fire in this round, and the limit is
* set to a value below the compare value. This practically means
* it will never fire, so it can be switched off.
*/
is_active = false;
}
ptimer_set_count(s->timer_cmp, next);
}
/*
* Set the compare timer and let it run, or stop it. This is agnostic
* of CR.OCIEN bit, as this bit affects interrupt generation only. The
* compare timer needs to run even if no interrupts are to be generated,
* because the SR.OCIF bit must be updated also.
* Note that the timer might already be stopped or be running with
* counter values. However, finding out when an update is needed and
* when not is not trivial. It's much easier applying the setting again,
* as this does not harm either and the overhead is negligible.
*/
if (is_active) {
ptimer_set_count(s->timer_cmp, counter);
ptimer_run(s->timer_cmp, is_oneshot ? 1 : 0);
} else {
ptimer_stop(s->timer_cmp);
}
}
static void imx_epit_write_cr(IMXEPITState *s, uint32_t value)
{
uint32_t oldcr = s->cr;
s->cr = value & 0x03ffffff;
if (s->cr & CR_SWR) {
/*
* Reset clears CR.SWR again. It does not touch CR.EN, but the timers
* are still stopped because the input clock is disabled.
*/
imx_epit_reset(s, false);
} else {
uint32_t freq;
uint32_t toggled_cr_bits = oldcr ^ s->cr;
/* re-initialize the limits if CR.RLD has changed */
bool set_limit = toggled_cr_bits & CR_RLD;
/* set the counter if the timer got just enabled and CR.ENMOD is set */
bool is_switched_on = (toggled_cr_bits & s->cr) & CR_EN;
bool set_counter = is_switched_on && (s->cr & CR_ENMOD);
ptimer_transaction_begin(s->timer_cmp);
ptimer_transaction_begin(s->timer_reload);
freq = imx_epit_get_freq(s);
if (freq) {
ptimer_set_freq(s->timer_reload, freq);
ptimer_set_freq(s->timer_cmp, freq);
}
if (set_limit || set_counter) {
uint64_t limit = (s->cr & CR_RLD) ? s->lr : EPIT_TIMER_MAX;
ptimer_set_limit(s->timer_reload, limit, set_counter ? 1 : 0);
if (set_limit) {
ptimer_set_limit(s->timer_cmp, limit, 0);
}
}
/*
* If there is an input clock and the peripheral is enabled, then
* ensure the wall clock timer is ticking. Otherwise stop the timers.
* The compare timer will be updated later.
*/
if (freq && (s->cr & CR_EN)) {
ptimer_run(s->timer_reload, 0);
} else {
ptimer_stop(s->timer_reload);
}
/* Commit changes to reload timer, so they can propagate. */
ptimer_transaction_commit(s->timer_reload);
/* Update compare timer based on the committed reload timer value. */
imx_epit_update_compare_timer(s);
ptimer_transaction_commit(s->timer_cmp);
}
/*
* The interrupt state can change due to:
* - reset clears both SR.OCIF and CR.OCIE
* - write to CR.EN or CR.OCIE
*/
imx_epit_update_int(s);
}
static void imx_epit_write_sr(IMXEPITState *s, uint32_t value)
{
/* writing 1 to SR.OCIF clears this bit and turns the interrupt off */
if (value & SR_OCIF) {
s->sr = 0; /* SR.OCIF is the only bit in this register anyway */
imx_epit_update_int(s);
}
}
static void imx_epit_write_lr(IMXEPITState *s, uint32_t value)
{
s->lr = value;
ptimer_transaction_begin(s->timer_cmp);
ptimer_transaction_begin(s->timer_reload);
if (s->cr & CR_RLD) {
/* Also set the limit if the LRD bit is set */
/* If IOVW bit is set then set the timer value */
ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
ptimer_set_limit(s->timer_cmp, s->lr, 0);
} else if (s->cr & CR_IOVW) {
/* If IOVW bit is set then set the timer value */
ptimer_set_count(s->timer_reload, s->lr);
}
/* Commit the changes to s->timer_reload, so they can propagate. */
ptimer_transaction_commit(s->timer_reload);
/* Update the compare timer based on the committed reload timer value. */
imx_epit_update_compare_timer(s);
ptimer_transaction_commit(s->timer_cmp);
}
static void imx_epit_write_cmp(IMXEPITState *s, uint32_t value)
{
s->cmp = value;
/* Update the compare timer based on the committed reload timer value. */
ptimer_transaction_begin(s->timer_cmp);
imx_epit_update_compare_timer(s);
ptimer_transaction_commit(s->timer_cmp);
}
static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
unsigned size)
{
IMXEPITState *s = IMX_EPIT(opaque);
uint64_t oldcr;
DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2),
(uint32_t)value);
switch (offset >> 2) {
case 0: /* CR */
oldcr = s->cr;
s->cr = value & 0x03ffffff;
if (s->cr & CR_SWR) {
/* handle the reset */
imx_epit_reset(DEVICE(s));
/*
* TODO: could we 'break' here? following operations appear
* to duplicate the work imx_epit_reset() already did.
*/
}
ptimer_transaction_begin(s->timer_cmp);
ptimer_transaction_begin(s->timer_reload);
if (!(s->cr & CR_SWR)) {
imx_epit_set_freq(s);
}
if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) {
if (s->cr & CR_ENMOD) {
if (s->cr & CR_RLD) {
ptimer_set_limit(s->timer_reload, s->lr, 1);
ptimer_set_limit(s->timer_cmp, s->lr, 1);
} else {
ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
}
}
imx_epit_reload_compare_timer(s);
ptimer_run(s->timer_reload, 0);
if (s->cr & CR_OCIEN) {
ptimer_run(s->timer_cmp, 0);
} else {
ptimer_stop(s->timer_cmp);
}
} else if (!(s->cr & CR_EN)) {
/* stop both timers */
ptimer_stop(s->timer_reload);
ptimer_stop(s->timer_cmp);
} else if (s->cr & CR_OCIEN) {
if (!(oldcr & CR_OCIEN)) {
imx_epit_reload_compare_timer(s);
ptimer_run(s->timer_cmp, 0);
}
} else {
ptimer_stop(s->timer_cmp);
}
ptimer_transaction_commit(s->timer_cmp);
ptimer_transaction_commit(s->timer_reload);
imx_epit_write_cr(s, (uint32_t)value);
break;
case 1: /* SR - ACK*/
/* writing 1 to OCIF clear the OCIF bit */
if (value & 0x01) {
s->sr = 0;
imx_epit_update_int(s);
}
case 1: /* SR */
imx_epit_write_sr(s, (uint32_t)value);
break;
case 2: /* LR - set ticks */
s->lr = value;
ptimer_transaction_begin(s->timer_cmp);
ptimer_transaction_begin(s->timer_reload);
if (s->cr & CR_RLD) {
/* Also set the limit if the LRD bit is set */
/* If IOVW bit is set then set the timer value */
ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
ptimer_set_limit(s->timer_cmp, s->lr, 0);
} else if (s->cr & CR_IOVW) {
/* If IOVW bit is set then set the timer value */
ptimer_set_count(s->timer_reload, s->lr);
}
/*
* Commit the change to s->timer_reload, so it can propagate. Otherwise
* the timer interrupt may not fire properly. The commit must happen
* before calling imx_epit_reload_compare_timer(), which reads
* s->timer_reload internally again.
*/
ptimer_transaction_commit(s->timer_reload);
imx_epit_reload_compare_timer(s);
ptimer_transaction_commit(s->timer_cmp);
case 2: /* LR */
imx_epit_write_lr(s, (uint32_t)value);
break;
case 3: /* CMP */
s->cmp = value;
ptimer_transaction_begin(s->timer_cmp);
imx_epit_reload_compare_timer(s);
ptimer_transaction_commit(s->timer_cmp);
imx_epit_write_cmp(s, (uint32_t)value);
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset);
break;
}
}
static void imx_epit_cmp(void *opaque)
{
IMXEPITState *s = IMX_EPIT(opaque);
DPRINTF("sr was %d\n", s->sr);
/* The cmp ptimer can't be running when the peripheral is disabled */
assert(s->cr & CR_EN);
s->sr = 1;
DPRINTF("sr was %d\n", s->sr);
/* Set interrupt status bit SR.OCIF and update the interrupt state */
s->sr |= SR_OCIF;
imx_epit_update_int(s);
}
@ -325,15 +381,13 @@ static const MemoryRegionOps imx_epit_ops = {
static const VMStateDescription vmstate_imx_timer_epit = {
.name = TYPE_IMX_EPIT,
.version_id = 2,
.minimum_version_id = 2,
.version_id = 3,
.minimum_version_id = 3,
.fields = (VMStateField[]) {
VMSTATE_UINT32(cr, IMXEPITState),
VMSTATE_UINT32(sr, IMXEPITState),
VMSTATE_UINT32(lr, IMXEPITState),
VMSTATE_UINT32(cmp, IMXEPITState),
VMSTATE_UINT32(cnt, IMXEPITState),
VMSTATE_UINT32(freq, IMXEPITState),
VMSTATE_PTIMER(timer_reload, IMXEPITState),
VMSTATE_PTIMER(timer_cmp, IMXEPITState),
VMSTATE_END_OF_LIST()
@ -352,17 +406,33 @@ static void imx_epit_realize(DeviceState *dev, Error **errp)
0x00001000);
sysbus_init_mmio(sbd, &s->iomem);
/*
* The reload timer keeps running when the peripheral is enabled. It is a
* kind of wall clock that does not generate any interrupts. The callback
* needs to be provided, but it does nothing as the ptimer already supports
* all necessary reloading functionality.
*/
s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_LEGACY);
/*
* The compare timer is running only when the peripheral configuration is
* in a state that will generate compare interrupts.
*/
s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_LEGACY);
}
static void imx_epit_dev_reset(DeviceState *dev)
{
IMXEPITState *s = IMX_EPIT(dev);
imx_epit_reset(s, true);
}
static void imx_epit_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_epit_realize;
dc->reset = imx_epit_reset;
dc->reset = imx_epit_dev_reset;
dc->vmsd = &vmstate_imx_timer_epit;
dc->desc = "i.MX periodic timer";
}

View File

@ -115,6 +115,17 @@ static const IMXClk imx6_gpt_clocks[] = {
CLK_HIGH, /* 111 reference clock */
};
static const IMXClk imx6ul_gpt_clocks[] = {
CLK_NONE, /* 000 No clock source */
CLK_IPG, /* 001 ipg_clk, 532MHz*/
CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */
CLK_EXT, /* 011 External clock */
CLK_32k, /* 100 ipg_clk_32k */
CLK_NONE, /* 101 not defined */
CLK_NONE, /* 110 not defined */
CLK_NONE, /* 111 not defined */
};
static const IMXClk imx7_gpt_clocks[] = {
CLK_NONE, /* 000 No clock source */
CLK_IPG, /* 001 ipg_clk, 532MHz*/
@ -539,6 +550,13 @@ static void imx6_gpt_init(Object *obj)
s->clocks = imx6_gpt_clocks;
}
static void imx6ul_gpt_init(Object *obj)
{
IMXGPTState *s = IMX_GPT(obj);
s->clocks = imx6ul_gpt_clocks;
}
static void imx7_gpt_init(Object *obj)
{
IMXGPTState *s = IMX_GPT(obj);
@ -566,6 +584,12 @@ static const TypeInfo imx6_gpt_info = {
.instance_init = imx6_gpt_init,
};
static const TypeInfo imx6ul_gpt_info = {
.name = TYPE_IMX6UL_GPT,
.parent = TYPE_IMX25_GPT,
.instance_init = imx6ul_gpt_init,
};
static const TypeInfo imx7_gpt_info = {
.name = TYPE_IMX7_GPT,
.parent = TYPE_IMX25_GPT,
@ -577,6 +601,7 @@ static void imx_gpt_register_types(void)
type_register_static(&imx25_gpt_info);
type_register_static(&imx31_gpt_info);
type_register_static(&imx6_gpt_info);
type_register_static(&imx6ul_gpt_info);
type_register_static(&imx7_gpt_info);
}

View File

@ -235,6 +235,26 @@ enum FslIMX7IRQs {
FSL_IMX7_USB2_IRQ = 42,
FSL_IMX7_USB3_IRQ = 40,
FSL_IMX7_GPT1_IRQ = 55,
FSL_IMX7_GPT2_IRQ = 54,
FSL_IMX7_GPT3_IRQ = 53,
FSL_IMX7_GPT4_IRQ = 52,
FSL_IMX7_GPIO1_LOW_IRQ = 64,
FSL_IMX7_GPIO1_HIGH_IRQ = 65,
FSL_IMX7_GPIO2_LOW_IRQ = 66,
FSL_IMX7_GPIO2_HIGH_IRQ = 67,
FSL_IMX7_GPIO3_LOW_IRQ = 68,
FSL_IMX7_GPIO3_HIGH_IRQ = 69,
FSL_IMX7_GPIO4_LOW_IRQ = 70,
FSL_IMX7_GPIO4_HIGH_IRQ = 71,
FSL_IMX7_GPIO5_LOW_IRQ = 72,
FSL_IMX7_GPIO5_HIGH_IRQ = 73,
FSL_IMX7_GPIO6_LOW_IRQ = 74,
FSL_IMX7_GPIO6_HIGH_IRQ = 75,
FSL_IMX7_GPIO7_LOW_IRQ = 76,
FSL_IMX7_GPIO7_HIGH_IRQ = 77,
FSL_IMX7_WDOG1_IRQ = 78,
FSL_IMX7_WDOG2_IRQ = 79,
FSL_IMX7_WDOG3_IRQ = 10,

View File

@ -173,7 +173,4 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
/* Unmap the range of all the notifiers registered to any IOMMU mr */
void smmu_inv_notifiers_all(SMMUState *s);
/* Unmap the range of all the notifiers registered to @mr */
void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr);
#endif /* HW_ARM_SMMU_COMMON_H */

View File

@ -30,12 +30,12 @@ uWireSlave *tsc2102_init(qemu_irq pint);
uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav);
I2SCodec *tsc210x_codec(uWireSlave *chip);
uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len);
void tsc210x_set_transform(uWireSlave *chip, MouseTransformInfo *info);
void tsc210x_set_transform(uWireSlave *chip, const MouseTransformInfo *info);
void tsc210x_key_event(uWireSlave *chip, int key, int down);
/* tsc2005.c */
void *tsc2005_init(qemu_irq pintdav);
uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len);
void tsc2005_set_transform(void *opaque, MouseTransformInfo *info);
void tsc2005_set_transform(void *opaque, const MouseTransformInfo *info);
#endif

View File

@ -43,7 +43,7 @@
#define CR_OCIEN (1 << 2)
#define CR_RLD (1 << 3)
#define CR_PRESCALE_SHIFT (4)
#define CR_PRESCALE_MASK (0xfff)
#define CR_PRESCALE_BITS (12)
#define CR_SWR (1 << 16)
#define CR_IOVW (1 << 17)
#define CR_DBGEN (1 << 18)
@ -51,7 +51,9 @@
#define CR_DOZEN (1 << 20)
#define CR_STOPEN (1 << 21)
#define CR_CLKSRC_SHIFT (24)
#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT)
#define CR_CLKSRC_BITS (2)
#define SR_OCIF (1 << 0)
#define EPIT_TIMER_MAX 0XFFFFFFFFUL
@ -72,9 +74,7 @@ struct IMXEPITState {
uint32_t sr;
uint32_t lr;
uint32_t cmp;
uint32_t cnt;
uint32_t freq;
qemu_irq irq;
};

View File

@ -78,6 +78,7 @@
#define TYPE_IMX25_GPT "imx25.gpt"
#define TYPE_IMX31_GPT "imx31.gpt"
#define TYPE_IMX6_GPT "imx6.gpt"
#define TYPE_IMX6UL_GPT "imx6ul.gpt"
#define TYPE_IMX7_GPT "imx7.gpt"
#define TYPE_IMX_GPT TYPE_IMX25_GPT

View File

@ -26,7 +26,6 @@
#include "target/arm/idau.h"
#include "qemu/module.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "cpu.h"
#ifdef CONFIG_TCG
#include "hw/core/tcg-cpu-ops.h"
@ -309,6 +308,10 @@ static void arm_cpu_reset_hold(Object *obj)
env->cp15.cpacr_el1 = FIELD_DP64(env->cp15.cpacr_el1,
CPACR, CP11, 3);
#endif
if (arm_feature(env, ARM_FEATURE_V8)) {
env->cp15.rvbar = cpu->rvbar_prop;
env->regs[15] = cpu->rvbar_prop;
}
}
#if defined(CONFIG_USER_ONLY)
@ -487,6 +490,14 @@ static void arm_cpu_reset_hold(Object *obj)
sizeof(*env->pmsav7.dracr) * cpu->pmsav7_dregion);
}
}
if (cpu->pmsav8r_hdregion > 0) {
memset(env->pmsav8.hprbar, 0,
sizeof(*env->pmsav8.hprbar) * cpu->pmsav8r_hdregion);
memset(env->pmsav8.hprlar, 0,
sizeof(*env->pmsav8.hprlar) * cpu->pmsav8r_hdregion);
}
env->pmsav7.rnr[M_REG_NS] = 0;
env->pmsav7.rnr[M_REG_S] = 0;
env->pmsav8.mair0[M_REG_NS] = 0;
@ -1345,7 +1356,7 @@ void arm_cpu_post_init(Object *obj)
qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_hivecs_property);
}
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
object_property_add_uint64_ptr(obj, "rvbar",
&cpu->rvbar_prop,
OBJ_PROP_FLAG_READWRITE);
@ -1998,11 +2009,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
/* MPU can be configured out of a PMSA CPU either by setting has-mpu
* to false or by setting pmsav7-dregion to 0.
*/
if (!cpu->has_mpu) {
cpu->pmsav7_dregion = 0;
}
if (cpu->pmsav7_dregion == 0) {
if (!cpu->has_mpu || cpu->pmsav7_dregion == 0) {
cpu->has_mpu = false;
cpu->pmsav7_dregion = 0;
cpu->pmsav8r_hdregion = 0;
}
if (arm_feature(env, ARM_FEATURE_PMSA) &&
@ -2029,6 +2039,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
env->pmsav7.dracr = g_new0(uint32_t, nr);
}
}
if (cpu->pmsav8r_hdregion > 0xff) {
error_setg(errp, "PMSAv8 MPU EL2 #regions invalid %" PRIu32,
cpu->pmsav8r_hdregion);
return;
}
if (cpu->pmsav8r_hdregion) {
env->pmsav8.hprbar = g_new0(uint32_t,
cpu->pmsav8r_hdregion);
env->pmsav8.hprlar = g_new0(uint32_t,
cpu->pmsav8r_hdregion);
}
}
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {

View File

@ -309,6 +309,7 @@ typedef struct CPUArchState {
};
uint64_t sctlr_el[4];
};
uint64_t vsctlr; /* Virtualization System control register. */
uint64_t cpacr_el1; /* Architectural feature access control register */
uint64_t cptr_el[4]; /* ARMv8 feature trap registers */
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
@ -745,8 +746,11 @@ typedef struct CPUArchState {
*/
uint32_t *rbar[M_REG_NUM_BANKS];
uint32_t *rlar[M_REG_NUM_BANKS];
uint32_t *hprbar;
uint32_t *hprlar;
uint32_t mair0[M_REG_NUM_BANKS];
uint32_t mair1[M_REG_NUM_BANKS];
uint32_t hprselr;
} pmsav8;
/* v8M SAU */
@ -906,6 +910,8 @@ struct ArchCPU {
bool has_mpu;
/* PMSAv7 MPU number of supported regions */
uint32_t pmsav7_dregion;
/* PMSAv8 MPU number of supported hyp regions */
uint32_t pmsav8r_hdregion;
/* v8M SAU number of supported regions */
uint32_t sau_sregion;

View File

@ -21,13 +21,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "cpu.h"
#ifdef CONFIG_TCG
#include "hw/core/tcg-cpu-ops.h"
#endif /* CONFIG_TCG */
#include "qemu/module.h"
#if !defined(CONFIG_USER_ONLY)
#include "hw/loader.h"
#endif
#include "sysemu/kvm.h"
#include "sysemu/hvf.h"
#include "kvm_arm.h"

View File

@ -854,6 +854,47 @@ static void cortex_r5_initfn(Object *obj)
define_arm_cp_regs(cpu, cortexr5_cp_reginfo);
}
static void cortex_r52_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
set_feature(&cpu->env, ARM_FEATURE_V8);
set_feature(&cpu->env, ARM_FEATURE_EL2);
set_feature(&cpu->env, ARM_FEATURE_PMSA);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
cpu->midr = 0x411fd133; /* r1p3 */
cpu->revidr = 0x00000000;
cpu->reset_fpsid = 0x41034023;
cpu->isar.mvfr0 = 0x10110222;
cpu->isar.mvfr1 = 0x12111111;
cpu->isar.mvfr2 = 0x00000043;
cpu->ctr = 0x8144c004;
cpu->reset_sctlr = 0x30c50838;
cpu->isar.id_pfr0 = 0x00000131;
cpu->isar.id_pfr1 = 0x10111001;
cpu->isar.id_dfr0 = 0x03010006;
cpu->id_afr0 = 0x00000000;
cpu->isar.id_mmfr0 = 0x00211040;
cpu->isar.id_mmfr1 = 0x40000000;
cpu->isar.id_mmfr2 = 0x01200000;
cpu->isar.id_mmfr3 = 0xf0102211;
cpu->isar.id_mmfr4 = 0x00000010;
cpu->isar.id_isar0 = 0x02101110;
cpu->isar.id_isar1 = 0x13112111;
cpu->isar.id_isar2 = 0x21232142;
cpu->isar.id_isar3 = 0x01112131;
cpu->isar.id_isar4 = 0x00010142;
cpu->isar.id_isar5 = 0x00010001;
cpu->isar.dbgdidr = 0x77168000;
cpu->clidr = (1 << 27) | (1 << 24) | 0x3;
cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */
cpu->pmsav7_dregion = 16;
cpu->pmsav8r_hdregion = 16;
}
static void cortex_r5f_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@ -1163,6 +1204,7 @@ static const ARMCPUInfo arm_tcg_cpus[] = {
.class_init = arm_v7m_class_init },
{ .name = "cortex-r5", .initfn = cortex_r5_initfn },
{ .name = "cortex-r5f", .initfn = cortex_r5f_initfn },
{ .name = "cortex-r52", .initfn = cortex_r52_initfn },
{ .name = "ti925t", .initfn = ti925t_initfn },
{ .name = "sa1100", .initfn = sa1100_initfn },
{ .name = "sa1110", .initfn = sa1110_initfn },

View File

@ -437,6 +437,9 @@ static uint32_t arm_debug_exception_fsr(CPUARMState *env)
if (target_el == 2 || arm_el_is_aa64(env, target_el)) {
using_lpae = true;
} else if (arm_feature(env, ARM_FEATURE_PMSA) &&
arm_feature(env, ARM_FEATURE_V8)) {
using_lpae = true;
} else {
if (arm_feature(env, ARM_FEATURE_LPAE) &&
(env->cp15.tcr_el[target_el] & TTBCR_EAE)) {

File diff suppressed because it is too large Load Diff

View File

@ -257,6 +257,10 @@ unsigned int arm_pamax(ARMCPU *cpu);
static inline bool extended_addresses_enabled(CPUARMState *env)
{
uint64_t tcr = env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1];
if (arm_feature(env, ARM_FEATURE_PMSA) &&
arm_feature(env, ARM_FEATURE_V8)) {
return true;
}
return arm_el_is_aa64(env, 1) ||
(arm_feature(env, ARM_FEATURE_LPAE) && (tcr & TTBCR_EAE));
}

View File

@ -7,30 +7,14 @@
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "target/arm/idau.h"
#include "trace.h"
#include "cpu.h"
#include "internals.h"
#include "exec/gdbstub.h"
#include "exec/helper-proto.h"
#include "qemu/host-utils.h"
#include "qemu/main-loop.h"
#include "qemu/bitops.h"
#include "qemu/crc32c.h"
#include "qemu/qemu-print.h"
#include "qemu/log.h"
#include "exec/exec-all.h"
#include <zlib.h> /* For crc32 */
#include "semihosting/semihost.h"
#include "sysemu/cpus.h"
#include "sysemu/kvm.h"
#include "qemu/range.h"
#include "qapi/qapi-commands-machine-target.h"
#include "qapi/error.h"
#include "qemu/guest-random.h"
#ifdef CONFIG_TCG
#include "arm_ldst.h"
#include "exec/cpu_ldst.h"
#include "semihosting/common-semi.h"
#endif

View File

@ -487,6 +487,30 @@ static bool pmsav8_needed(void *opaque)
arm_feature(env, ARM_FEATURE_V8);
}
static bool pmsav8r_needed(void *opaque)
{
ARMCPU *cpu = opaque;
CPUARMState *env = &cpu->env;
return arm_feature(env, ARM_FEATURE_PMSA) &&
arm_feature(env, ARM_FEATURE_V8) &&
!arm_feature(env, ARM_FEATURE_M);
}
static const VMStateDescription vmstate_pmsav8r = {
.name = "cpu/pmsav8/pmsav8r",
.version_id = 1,
.minimum_version_id = 1,
.needed = pmsav8r_needed,
.fields = (VMStateField[]) {
VMSTATE_VARRAY_UINT32(env.pmsav8.hprbar, ARMCPU,
pmsav8r_hdregion, 0, vmstate_info_uint32, uint32_t),
VMSTATE_VARRAY_UINT32(env.pmsav8.hprlar, ARMCPU,
pmsav8r_hdregion, 0, vmstate_info_uint32, uint32_t),
VMSTATE_END_OF_LIST()
},
};
static const VMStateDescription vmstate_pmsav8 = {
.name = "cpu/pmsav8",
.version_id = 1,
@ -500,6 +524,10 @@ static const VMStateDescription vmstate_pmsav8 = {
VMSTATE_UINT32(env.pmsav8.mair0[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.pmsav8.mair1[M_REG_NS], ARMCPU),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * []) {
&vmstate_pmsav8r,
NULL
}
};

View File

@ -1758,9 +1758,13 @@ static bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx,
if (arm_feature(env, ARM_FEATURE_M)) {
return env->v7m.mpu_ctrl[is_secure] & R_V7M_MPU_CTRL_PRIVDEFENA_MASK;
} else {
return regime_sctlr(env, mmu_idx) & SCTLR_BR;
}
if (mmu_idx == ARMMMUIdx_Stage2) {
return false;
}
return regime_sctlr(env, mmu_idx) & SCTLR_BR;
}
static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
@ -1952,6 +1956,26 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
return !(result->f.prot & (1 << access_type));
}
static uint32_t *regime_rbar(CPUARMState *env, ARMMMUIdx mmu_idx,
uint32_t secure)
{
if (regime_el(env, mmu_idx) == 2) {
return env->pmsav8.hprbar;
} else {
return env->pmsav8.rbar[secure];
}
}
static uint32_t *regime_rlar(CPUARMState *env, ARMMMUIdx mmu_idx,
uint32_t secure)
{
if (regime_el(env, mmu_idx) == 2) {
return env->pmsav8.hprlar;
} else {
return env->pmsav8.rlar[secure];
}
}
bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
bool secure, GetPhysAddrResult *result,
@ -1974,6 +1998,13 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
bool hit = false;
uint32_t addr_page_base = address & TARGET_PAGE_MASK;
uint32_t addr_page_limit = addr_page_base + (TARGET_PAGE_SIZE - 1);
int region_counter;
if (regime_el(env, mmu_idx) == 2) {
region_counter = cpu->pmsav8r_hdregion;
} else {
region_counter = cpu->pmsav7_dregion;
}
result->f.lg_page_size = TARGET_PAGE_BITS;
result->f.phys_addr = address;
@ -1982,6 +2013,10 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
*mregion = -1;
}
if (mmu_idx == ARMMMUIdx_Stage2) {
fi->stage2 = true;
}
/*
* Unlike the ARM ARM pseudocode, we don't need to check whether this
* was an exception vector read from the vector table (which is always
@ -1998,17 +2033,26 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
hit = true;
}
for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) {
uint32_t bitmask;
if (arm_feature(env, ARM_FEATURE_M)) {
bitmask = 0x1f;
} else {
bitmask = 0x3f;
fi->level = 0;
}
for (n = region_counter - 1; n >= 0; n--) {
/* region search */
/*
* Note that the base address is bits [31:5] from the register
* with bits [4:0] all zeroes, but the limit address is bits
* [31:5] from the register with bits [4:0] all ones.
* Note that the base address is bits [31:x] from the register
* with bits [x-1:0] all zeroes, but the limit address is bits
* [31:x] from the register with bits [x:0] all ones. Where x is
* 5 for Cortex-M and 6 for Cortex-R
*/
uint32_t base = env->pmsav8.rbar[secure][n] & ~0x1f;
uint32_t limit = env->pmsav8.rlar[secure][n] | 0x1f;
uint32_t base = regime_rbar(env, mmu_idx, secure)[n] & ~bitmask;
uint32_t limit = regime_rlar(env, mmu_idx, secure)[n] | bitmask;
if (!(env->pmsav8.rlar[secure][n] & 0x1)) {
if (!(regime_rlar(env, mmu_idx, secure)[n] & 0x1)) {
/* Region disabled */
continue;
}
@ -2042,7 +2086,9 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
* PMSAv7 where highest-numbered-region wins)
*/
fi->type = ARMFault_Permission;
fi->level = 1;
if (arm_feature(env, ARM_FEATURE_M)) {
fi->level = 1;
}
return true;
}
@ -2052,8 +2098,11 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
}
if (!hit) {
/* background fault */
fi->type = ARMFault_Background;
if (arm_feature(env, ARM_FEATURE_M)) {
fi->type = ARMFault_Background;
} else {
fi->type = ARMFault_Permission;
}
return true;
}
@ -2061,12 +2110,14 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
/* hit using the background region */
get_phys_addr_pmsav7_default(env, mmu_idx, address, &result->f.prot);
} else {
uint32_t ap = extract32(env->pmsav8.rbar[secure][matchregion], 1, 2);
uint32_t xn = extract32(env->pmsav8.rbar[secure][matchregion], 0, 1);
uint32_t matched_rbar = regime_rbar(env, mmu_idx, secure)[matchregion];
uint32_t matched_rlar = regime_rlar(env, mmu_idx, secure)[matchregion];
uint32_t ap = extract32(matched_rbar, 1, 2);
uint32_t xn = extract32(matched_rbar, 0, 1);
bool pxn = false;
if (arm_feature(env, ARM_FEATURE_V8_1M)) {
pxn = extract32(env->pmsav8.rlar[secure][matchregion], 4, 1);
pxn = extract32(matched_rlar, 4, 1);
}
if (m_is_system_region(env, address)) {
@ -2074,21 +2125,46 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
xn = 1;
}
result->f.prot = simple_ap_to_rw_prot(env, mmu_idx, ap);
if (regime_el(env, mmu_idx) == 2) {
result->f.prot = simple_ap_to_rw_prot_is_user(ap,
mmu_idx != ARMMMUIdx_E2);
} else {
result->f.prot = simple_ap_to_rw_prot(env, mmu_idx, ap);
}
if (!arm_feature(env, ARM_FEATURE_M)) {
uint8_t attrindx = extract32(matched_rlar, 1, 3);
uint64_t mair = env->cp15.mair_el[regime_el(env, mmu_idx)];
uint8_t sh = extract32(matched_rlar, 3, 2);
if (regime_sctlr(env, mmu_idx) & SCTLR_WXN &&
result->f.prot & PAGE_WRITE && mmu_idx != ARMMMUIdx_Stage2) {
xn = 0x1;
}
if ((regime_el(env, mmu_idx) == 1) &&
regime_sctlr(env, mmu_idx) & SCTLR_UWXN && ap == 0x1) {
pxn = 0x1;
}
result->cacheattrs.is_s2_format = false;
result->cacheattrs.attrs = extract64(mair, attrindx * 8, 8);
result->cacheattrs.shareability = sh;
}
if (result->f.prot && !xn && !(pxn && !is_user)) {
result->f.prot |= PAGE_EXEC;
}
/*
* We don't need to look the attribute up in the MAIR0/MAIR1
* registers because that only tells us about cacheability.
*/
if (mregion) {
*mregion = matchregion;
}
}
fi->type = ARMFault_Permission;
fi->level = 1;
if (arm_feature(env, ARM_FEATURE_M)) {
fi->level = 1;
}
return !(result->f.prot & (1 << access_type));
}
@ -2361,7 +2437,11 @@ static uint8_t combined_attrs_nofwb(uint64_t hcr,
{
uint8_t s1lo, s2lo, s1hi, s2hi, s2_mair_attrs, ret_attrs;
s2_mair_attrs = convert_stage2_attrs(hcr, s2.attrs);
if (s2.is_s2_format) {
s2_mair_attrs = convert_stage2_attrs(hcr, s2.attrs);
} else {
s2_mair_attrs = s2.attrs;
}
s1lo = extract32(s1.attrs, 0, 4);
s2lo = extract32(s2_mair_attrs, 0, 4);
@ -2418,6 +2498,8 @@ static uint8_t force_cacheattr_nibble_wb(uint8_t attr)
*/
static uint8_t combined_attrs_fwb(ARMCacheAttrs s1, ARMCacheAttrs s2)
{
assert(s2.is_s2_format && !s1.is_s2_format);
switch (s2.attrs) {
case 7:
/* Use stage 1 attributes */
@ -2467,7 +2549,7 @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr,
ARMCacheAttrs ret;
bool tagged = false;
assert(s2.is_s2_format && !s1.is_s2_format);
assert(!s1.is_s2_format);
ret.is_s2_format = false;
if (s1.attrs == 0xf0) {
@ -2643,7 +2725,13 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
cacheattrs1 = result->cacheattrs;
memset(result, 0, sizeof(*result));
ret = get_phys_addr_lpae(env, ptw, ipa, access_type, is_el0, result, fi);
if (arm_feature(env, ARM_FEATURE_PMSA)) {
ret = get_phys_addr_pmsav8(env, ipa, access_type,
ptw->in_mmu_idx, is_secure, result, fi);
} else {
ret = get_phys_addr_lpae(env, ptw, ipa, access_type,
is_el0, result, fi);
}
fi->s2addr = ipa;
/* Combine the S1 and S2 perms. */
@ -2655,10 +2743,20 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
}
/*
* Use the maximum of the S1 & S2 page size, so that invalidation
* of pages > TARGET_PAGE_SIZE works correctly.
* If either S1 or S2 returned a result smaller than TARGET_PAGE_SIZE,
* this means "don't put this in the TLB"; in this case, return a
* result with lg_page_size == 0 to achieve that. Otherwise,
* use the maximum of the S1 & S2 page size, so that invalidation
* of pages > TARGET_PAGE_SIZE works correctly. (This works even though
* we know the combined result permissions etc only cover the minimum
* of the S1 and S2 page size, because we know that the common TLB code
* never actually creates TLB entries bigger than TARGET_PAGE_SIZE,
* and passing a larger page size value only affects invalidations.)
*/
if (result->f.lg_page_size < s1_lgpgsz) {
if (result->f.lg_page_size < TARGET_PAGE_BITS ||
s1_lgpgsz < TARGET_PAGE_BITS) {
result->f.lg_page_size = 0;
} else if (result->f.lg_page_size < s1_lgpgsz) {
result->f.lg_page_size = s1_lgpgsz;
}

View File

@ -19,6 +19,10 @@ bool regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx)
if (el == 2 || arm_el_is_aa64(env, el)) {
return true;
}
if (arm_feature(env, ARM_FEATURE_PMSA) &&
arm_feature(env, ARM_FEATURE_V8)) {
return true;
}
if (arm_feature(env, ARM_FEATURE_LPAE)
&& (regime_tcr(env, mmu_idx) & TTBCR_EAE)) {
return true;

View File

@ -1184,7 +1184,7 @@ static inline void gen_hlt(DisasContext *s, int imm)
* semihosting, to provide some semblance of security
* (and for consistency with our 32-bit semihosting).
*/
if (semihosting_enabled(s->current_el != 0) &&
if (semihosting_enabled(s->current_el == 0) &&
(imm == (s->thumb ? 0x3c : 0xf000))) {
gen_exception_internal_insn(s, EXCP_SEMIHOST);
return;

View File

@ -23,7 +23,8 @@ config-cc.mak: Makefile
$(call cc-option,-march=armv8.1-a+sve2, CROSS_CC_HAS_SVE2); \
$(call cc-option,-march=armv8.3-a, CROSS_CC_HAS_ARMV8_3); \
$(call cc-option,-mbranch-protection=standard, CROSS_CC_HAS_ARMV8_BTI); \
$(call cc-option,-march=armv8.5-a+memtag, CROSS_CC_HAS_ARMV8_MTE)) 3> config-cc.mak
$(call cc-option,-march=armv8.5-a+memtag, CROSS_CC_HAS_ARMV8_MTE); \
$(call cc-option,-march=armv9-a+sme, CROSS_CC_HAS_ARMV9_SME)) 3> config-cc.mak
-include config-cc.mak
# Pauth Tests
@ -53,7 +54,11 @@ endif
ifneq ($(CROSS_CC_HAS_SVE),)
# System Registers Tests
AARCH64_TESTS += sysregs
ifneq ($(CROSS_CC_HAS_ARMV9_SME),)
sysregs: CFLAGS+=-march=armv9-a+sme -DHAS_ARMV9_SME
else
sysregs: CFLAGS+=-march=armv8.1-a+sve
endif
# SVE ioctl test
AARCH64_TESTS += sve-ioctls

View File

@ -22,6 +22,13 @@
#define HWCAP_CPUID (1 << 11)
#endif
/*
* Older assemblers don't recognize newer system register names,
* but we can still access them by the Sn_n_Cn_Cn_n syntax.
*/
#define SYS_ID_AA64ISAR2_EL1 S3_0_C0_C6_2
#define SYS_ID_AA64MMFR2_EL1 S3_0_C0_C7_2
int failed_bit_count;
/* Read and print system register `id' value */
@ -112,18 +119,23 @@ int main(void)
* minimum valid fields - for the purposes of this check allowed
* to have non-zero values.
*/
get_cpu_reg_check_mask(id_aa64isar0_el1, _m(00ff,ffff,f0ff,fff0));
get_cpu_reg_check_mask(id_aa64isar1_el1, _m(0000,00f0,ffff,ffff));
get_cpu_reg_check_mask(id_aa64isar0_el1, _m(f0ff,ffff,f0ff,fff0));
get_cpu_reg_check_mask(id_aa64isar1_el1, _m(00ff,f0ff,ffff,ffff));
get_cpu_reg_check_mask(SYS_ID_AA64ISAR2_EL1, _m(0000,0000,0000,ffff));
/* TGran4 & TGran64 as pegged to -1 */
get_cpu_reg_check_mask(id_aa64mmfr0_el1, _m(0000,0000,ff00,0000));
get_cpu_reg_check_zero(id_aa64mmfr1_el1);
get_cpu_reg_check_mask(id_aa64mmfr0_el1, _m(f000,0000,ff00,0000));
get_cpu_reg_check_mask(id_aa64mmfr1_el1, _m(0000,f000,0000,0000));
get_cpu_reg_check_mask(SYS_ID_AA64MMFR2_EL1, _m(0000,000f,0000,0000));
/* EL1/EL0 reported as AA64 only */
get_cpu_reg_check_mask(id_aa64pfr0_el1, _m(000f,000f,00ff,0011));
get_cpu_reg_check_mask(id_aa64pfr1_el1, _m(0000,0000,0000,00f0));
get_cpu_reg_check_mask(id_aa64pfr1_el1, _m(0000,0000,0f00,0fff));
/* all hidden, DebugVer fixed to 0x6 (ARMv8 debug architecture) */
get_cpu_reg_check_mask(id_aa64dfr0_el1, _m(0000,0000,0000,0006));
get_cpu_reg_check_zero(id_aa64dfr1_el1);
get_cpu_reg_check_zero(id_aa64zfr0_el1);
get_cpu_reg_check_mask(id_aa64zfr0_el1, _m(0ff0,ff0f,00ff,00ff));
#ifdef HAS_ARMV9_SME
get_cpu_reg_check_mask(id_aa64smfr0_el1, _m(80f1,00fd,0000,0000));
#endif
get_cpu_reg_check_zero(id_aa64afr0_el1);
get_cpu_reg_check_zero(id_aa64afr1_el1);