mirror of
https://github.com/qemu/qemu.git
synced 2024-11-23 02:43:50 +08:00
target-arm queue:
* hw/timer/exynos4210_mct: fix possible int overflow * hw/net/rocker/rocker_of_dpa.c: Remove superfluous error check * hw/intc/openpic: Avoid taking address of out-of-bounds array index * hw/watchdog/cmsdk_apb_watchdog: Fix INTEN issues * arm/ptw: Honour WXN/UWXN and SIF in short-format descriptors * hw/intc/loongarch_extioi: Use set_bit32() and clear_bit32() to avoid UB * system/dma-helpers.c: Move trace events to system/trace-events * target/arm/hvf: Add trace.h header * trace: Don't include trace-root.h in control.c or control-target.c -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmc8nrwZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3n2nEACc4N7TI2QFbuqa1k4G+C5y 1bpWVnkPjeqnTGUyYshtl/ByZi+IH4RDFqlCJxUYgfSvfD74+u78haXcx/ukZL/x zNbNu/hjP0v6nQF+upzRcQip5PIBjkbIUJSC3ga90HbsNWv8rvTjVSwQmstQ2b8J 9mCNA2ri+NVJ4+kBL5xRSzDqxdu/7sC/eooYfcETlVXcnvL/oMWoF//iThvkaBve LyySM+PS1Ni4oApx6LY9VpLzabtaCXh5R4yDMsFW0WucKZf58lm9Z1yU2wdPjuwj uauHBbQnJy03LazprIyVNXlaT7SI2Qr+7CV4lAco66DoBsaIP16+Kby1XILbY8qo JjJmuNQ8DA9c7F9bPqagZ0PLVRy9Wj0UiXKuqaTHrnnKzbgBprPCApR8bj0XPISs xv6qsSrd4u9joSCkrD3XEC9ddzdWMi1xN1Hfw+lkuHOvnWKJJ7O3hortuupGhpeq h90VBQ8Gb9S15BlLPfSmSmiO+XjRWU53CcZasQew5bFBIMEha1sPnwz01/KrSZqG sN/nBBuVUhT6YjRY/7k7tqT1ATigXrEZPtRgCjap7W+zIILWaO9QUb2y2LlJfofp febu0L++xw1JvtHnNin1vImmM5rgCMLMLx3QQ5Kq9jc5ytKnZwzJarLV4LbqIpuv h1QzI2SJQXsL2zfBem/0yg== =lqA0 -----END PGP SIGNATURE----- Merge tag 'pull-target-arm-20241119' of https://git.linaro.org/people/pmaydell/qemu-arm into staging target-arm queue: * hw/timer/exynos4210_mct: fix possible int overflow * hw/net/rocker/rocker_of_dpa.c: Remove superfluous error check * hw/intc/openpic: Avoid taking address of out-of-bounds array index * hw/watchdog/cmsdk_apb_watchdog: Fix INTEN issues * arm/ptw: Honour WXN/UWXN and SIF in short-format descriptors * hw/intc/loongarch_extioi: Use set_bit32() and clear_bit32() to avoid UB * system/dma-helpers.c: Move trace events to system/trace-events * target/arm/hvf: Add trace.h header * trace: Don't include trace-root.h in control.c or control-target.c # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmc8nrwZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3n2nEACc4N7TI2QFbuqa1k4G+C5y # 1bpWVnkPjeqnTGUyYshtl/ByZi+IH4RDFqlCJxUYgfSvfD74+u78haXcx/ukZL/x # zNbNu/hjP0v6nQF+upzRcQip5PIBjkbIUJSC3ga90HbsNWv8rvTjVSwQmstQ2b8J # 9mCNA2ri+NVJ4+kBL5xRSzDqxdu/7sC/eooYfcETlVXcnvL/oMWoF//iThvkaBve # LyySM+PS1Ni4oApx6LY9VpLzabtaCXh5R4yDMsFW0WucKZf58lm9Z1yU2wdPjuwj # uauHBbQnJy03LazprIyVNXlaT7SI2Qr+7CV4lAco66DoBsaIP16+Kby1XILbY8qo # JjJmuNQ8DA9c7F9bPqagZ0PLVRy9Wj0UiXKuqaTHrnnKzbgBprPCApR8bj0XPISs # xv6qsSrd4u9joSCkrD3XEC9ddzdWMi1xN1Hfw+lkuHOvnWKJJ7O3hortuupGhpeq # h90VBQ8Gb9S15BlLPfSmSmiO+XjRWU53CcZasQew5bFBIMEha1sPnwz01/KrSZqG # sN/nBBuVUhT6YjRY/7k7tqT1ATigXrEZPtRgCjap7W+zIILWaO9QUb2y2LlJfofp # febu0L++xw1JvtHnNin1vImmM5rgCMLMLx3QQ5Kq9jc5ytKnZwzJarLV4LbqIpuv # h1QzI2SJQXsL2zfBem/0yg== # =lqA0 # -----END PGP SIGNATURE----- # gpg: Signature made Tue 19 Nov 2024 14:20:44 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-20241119' of https://git.linaro.org/people/pmaydell/qemu-arm: trace: Don't include trace-root.h in control.c or control-target.c target/arm/hvf: Add trace.h header system/dma-helpers.c: Move trace events to system/trace-events hw/intc/loongarch_extioi: Use set_bit32() and clear_bit32() for s->isr hw/intc/arm_gicv3: Use bitops.h uint32_t bit array functions bitops.h: Define bit operations on 'uint32_t' arrays arm/ptw: Honour WXN/UWXN and SIF in short-format descriptors arm/ptw: Make get_S1prot accept decoded AP tests/qtest/cmsdk-apb-watchdog-test: Test INTEN as counter enable tests/qtest/cmsdk-apb-watchdog-test: Don't abort on assertion failure tests/qtest/cmsdk-apb-watchdog-test: Parameterize tests hw/watchdog/cmsdk_apb_watchdog: Fix INTEN issues hw/intc/openpic: Avoid taking address of out-of-bounds array index hw/net/rocker/rocker_of_dpa.c: Remove superfluous error check hw/timer/exynos4210_mct: fix possible int overflow Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e6459afb1f
@ -57,14 +57,9 @@ static void extioi_setirq(void *opaque, int irq, int level)
|
||||
LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
|
||||
trace_loongarch_extioi_setirq(irq, level);
|
||||
if (level) {
|
||||
/*
|
||||
* s->isr should be used in vmstate structure,
|
||||
* but it not support 'unsigned long',
|
||||
* so we have to switch it.
|
||||
*/
|
||||
set_bit(irq, (unsigned long *)s->isr);
|
||||
set_bit32(irq, s->isr);
|
||||
} else {
|
||||
clear_bit(irq, (unsigned long *)s->isr);
|
||||
clear_bit32(irq, s->isr);
|
||||
}
|
||||
extioi_update_irq(s, irq, level);
|
||||
}
|
||||
@ -154,7 +149,7 @@ static inline void extioi_update_sw_coremap(LoongArchExtIOI *s, int irq,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (notify && test_bit(irq + i, (unsigned long *)s->isr)) {
|
||||
if (notify && test_bit32(irq + i, s->isr)) {
|
||||
/*
|
||||
* lower irq at old cpu and raise irq at new cpu
|
||||
*/
|
||||
|
@ -1031,13 +1031,14 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
|
||||
s_IRQ = IRQ_get_next(opp, &dst->servicing);
|
||||
/* Check queued interrupts. */
|
||||
n_IRQ = IRQ_get_next(opp, &dst->raised);
|
||||
src = &opp->src[n_IRQ];
|
||||
if (n_IRQ != -1 &&
|
||||
(s_IRQ == -1 ||
|
||||
IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) {
|
||||
DPRINTF("Raise OpenPIC INT output cpu %d irq %d",
|
||||
idx, n_IRQ);
|
||||
qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]);
|
||||
if (n_IRQ != -1) {
|
||||
src = &opp->src[n_IRQ];
|
||||
if (s_IRQ == -1 ||
|
||||
IVPR_PRIORITY(src->ivpr) > dst->servicing.priority) {
|
||||
DPRINTF("Raise OpenPIC INT output cpu %d irq %d",
|
||||
idx, n_IRQ);
|
||||
qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1635,8 +1635,8 @@ static int of_dpa_cmd_add_multicast_routing(OfDpaFlow *flow,
|
||||
return ROCKER_OK;
|
||||
}
|
||||
|
||||
static int of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask,
|
||||
RockerTlv **flow_tlvs)
|
||||
static void of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask,
|
||||
RockerTlv **flow_tlvs)
|
||||
{
|
||||
key->width = FLOW_KEY_WIDTH(ip.tos);
|
||||
|
||||
@ -1669,8 +1669,6 @@ static int of_dpa_cmd_add_acl_ip(OfDpaFlowKey *key, OfDpaFlowKey *mask,
|
||||
mask->ip.tos |=
|
||||
rocker_tlv_get_u8(flow_tlvs[ROCKER_TLV_OF_DPA_IP_ECN_MASK]) << 6;
|
||||
}
|
||||
|
||||
return ROCKER_OK;
|
||||
}
|
||||
|
||||
static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs)
|
||||
@ -1689,7 +1687,6 @@ static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs)
|
||||
ACL_MODE_ANY_VLAN,
|
||||
ACL_MODE_ANY_TENANT,
|
||||
} mode = ACL_MODE_UNKNOWN;
|
||||
int err = ROCKER_OK;
|
||||
|
||||
if (!flow_tlvs[ROCKER_TLV_OF_DPA_IN_PPORT] ||
|
||||
!flow_tlvs[ROCKER_TLV_OF_DPA_ETHERTYPE]) {
|
||||
@ -1776,14 +1773,10 @@ static int of_dpa_cmd_add_acl(OfDpaFlow *flow, RockerTlv **flow_tlvs)
|
||||
switch (ntohs(key->eth.type)) {
|
||||
case 0x0800:
|
||||
case 0x86dd:
|
||||
err = of_dpa_cmd_add_acl_ip(key, mask, flow_tlvs);
|
||||
of_dpa_cmd_add_acl_ip(key, mask, flow_tlvs);
|
||||
break;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]) {
|
||||
action->write.group_id =
|
||||
rocker_tlv_get_le32(flow_tlvs[ROCKER_TLV_OF_DPA_GROUP_ID]);
|
||||
|
@ -815,7 +815,7 @@ static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s)
|
||||
/* Both are counting */
|
||||
icnto = remain / s->tcntb;
|
||||
if (icnto) {
|
||||
tcnto = remain % (icnto * s->tcntb);
|
||||
tcnto = remain % ((uint64_t)icnto * s->tcntb);
|
||||
} else {
|
||||
tcnto = remain % s->tcntb;
|
||||
}
|
||||
|
@ -196,16 +196,13 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
|
||||
|
||||
switch (offset) {
|
||||
case A_WDOGLOAD:
|
||||
/*
|
||||
* Reset the load value and the current count, and make sure
|
||||
* we're counting.
|
||||
*/
|
||||
/* Reset the load value and the current count. */
|
||||
ptimer_transaction_begin(s->timer);
|
||||
ptimer_set_limit(s->timer, value, 1);
|
||||
ptimer_run(s->timer, 0);
|
||||
ptimer_transaction_commit(s->timer);
|
||||
break;
|
||||
case A_WDOGCONTROL:
|
||||
case A_WDOGCONTROL: {
|
||||
uint32_t prev_control = s->control;
|
||||
if (s->is_luminary && 0 != (R_WDOGCONTROL_INTEN_MASK & s->control)) {
|
||||
/*
|
||||
* The Luminary version of this device ignores writes to
|
||||
@ -215,8 +212,25 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
|
||||
break;
|
||||
}
|
||||
s->control = value & R_WDOGCONTROL_VALID_MASK;
|
||||
if (R_WDOGCONTROL_INTEN_MASK & (s->control ^ prev_control)) {
|
||||
ptimer_transaction_begin(s->timer);
|
||||
if (R_WDOGCONTROL_INTEN_MASK & s->control) {
|
||||
/*
|
||||
* Set HIGH to enable the counter and the interrupt. Reloads
|
||||
* the counter from the value in WDOGLOAD when the interrupt
|
||||
* is enabled, after previously being disabled.
|
||||
*/
|
||||
ptimer_set_count(s->timer, ptimer_get_limit(s->timer));
|
||||
ptimer_run(s->timer, 0);
|
||||
} else {
|
||||
/* Or LOW to disable the counter and interrupt. */
|
||||
ptimer_stop(s->timer);
|
||||
}
|
||||
ptimer_transaction_commit(s->timer);
|
||||
}
|
||||
cmsdk_apb_watchdog_update(s);
|
||||
break;
|
||||
}
|
||||
case A_WDOGINTCLR:
|
||||
s->intstatus = 0;
|
||||
ptimer_transaction_begin(s->timer);
|
||||
@ -305,8 +319,14 @@ static void cmsdk_apb_watchdog_reset(DeviceState *dev)
|
||||
s->resetstatus = 0;
|
||||
/* Set the limit and the count */
|
||||
ptimer_transaction_begin(s->timer);
|
||||
/*
|
||||
* We need to stop the ptimer before setting its limit reset value. If the
|
||||
* order is the opposite when the code executes the stop after setting a new
|
||||
* limit it may want to recalculate the count based on the current time (if
|
||||
* the timer was currently running) and it won't get the proper reset value.
|
||||
*/
|
||||
ptimer_stop(s->timer);
|
||||
ptimer_set_limit(s->timer, 0xffffffff, 1);
|
||||
ptimer_run(s->timer, 0);
|
||||
ptimer_transaction_commit(s->timer);
|
||||
}
|
||||
|
||||
|
@ -51,13 +51,13 @@
|
||||
/* Maximum number of list registers (architectural limit) */
|
||||
#define GICV3_LR_MAX 16
|
||||
|
||||
/* For some distributor fields we want to model the array of 32-bit
|
||||
/*
|
||||
* For some distributor fields we want to model the array of 32-bit
|
||||
* register values which hold various bitmaps corresponding to enabled,
|
||||
* pending, etc bits. These macros and functions facilitate that; the
|
||||
* APIs are generally modelled on the generic bitmap.h functions
|
||||
* (which are unsuitable here because they use 'unsigned long' as the
|
||||
* underlying storage type, which is very awkward when you need to
|
||||
* access the data as 32-bit values.)
|
||||
* pending, etc bits. We use the set_bit32() etc family of functions
|
||||
* from bitops.h for this. For a few cases we need to implement some
|
||||
* extra operations.
|
||||
*
|
||||
* Each bitmap contains a bit for each interrupt. Although there is
|
||||
* space for the PPIs and SGIs, those bits (the first 32) are never
|
||||
* used as that state lives in the redistributor. The unused bits are
|
||||
@ -65,39 +65,13 @@
|
||||
* avoids bugs where we forget to subtract GIC_INTERNAL from an
|
||||
* interrupt number.
|
||||
*/
|
||||
#define GICV3_BMP_SIZE DIV_ROUND_UP(GICV3_MAXIRQ, 32)
|
||||
|
||||
#define GIC_DECLARE_BITMAP(name) \
|
||||
uint32_t name[GICV3_BMP_SIZE]
|
||||
|
||||
#define GIC_BIT_MASK(nr) (1U << ((nr) % 32))
|
||||
#define GIC_BIT_WORD(nr) ((nr) / 32)
|
||||
|
||||
static inline void gic_bmp_set_bit(int nr, uint32_t *addr)
|
||||
{
|
||||
uint32_t mask = GIC_BIT_MASK(nr);
|
||||
uint32_t *p = addr + GIC_BIT_WORD(nr);
|
||||
|
||||
*p |= mask;
|
||||
}
|
||||
|
||||
static inline void gic_bmp_clear_bit(int nr, uint32_t *addr)
|
||||
{
|
||||
uint32_t mask = GIC_BIT_MASK(nr);
|
||||
uint32_t *p = addr + GIC_BIT_WORD(nr);
|
||||
|
||||
*p &= ~mask;
|
||||
}
|
||||
|
||||
static inline int gic_bmp_test_bit(int nr, const uint32_t *addr)
|
||||
{
|
||||
return 1U & (addr[GIC_BIT_WORD(nr)] >> (nr & 31));
|
||||
}
|
||||
#define GIC_DECLARE_BITMAP(name) DECLARE_BITMAP32(name, GICV3_MAXIRQ)
|
||||
#define GICV3_BMP_SIZE BITS_TO_U32S(GICV3_MAXIRQ)
|
||||
|
||||
static inline void gic_bmp_replace_bit(int nr, uint32_t *addr, int val)
|
||||
{
|
||||
uint32_t mask = GIC_BIT_MASK(nr);
|
||||
uint32_t *p = addr + GIC_BIT_WORD(nr);
|
||||
uint32_t mask = BIT32_MASK(nr);
|
||||
uint32_t *p = addr + BIT32_WORD(nr);
|
||||
|
||||
*p &= ~mask;
|
||||
*p |= (val & 1U) << (nr % 32);
|
||||
@ -106,7 +80,7 @@ static inline void gic_bmp_replace_bit(int nr, uint32_t *addr, int val)
|
||||
/* Return a pointer to the 32-bit word containing the specified bit. */
|
||||
static inline uint32_t *gic_bmp_ptr32(uint32_t *addr, int nr)
|
||||
{
|
||||
return addr + GIC_BIT_WORD(nr);
|
||||
return addr + BIT32_WORD(nr);
|
||||
}
|
||||
|
||||
typedef struct GICv3State GICv3State;
|
||||
@ -301,15 +275,15 @@ struct GICv3State {
|
||||
#define GICV3_BITMAP_ACCESSORS(BMP) \
|
||||
static inline void gicv3_gicd_##BMP##_set(GICv3State *s, int irq) \
|
||||
{ \
|
||||
gic_bmp_set_bit(irq, s->BMP); \
|
||||
set_bit32(irq, s->BMP); \
|
||||
} \
|
||||
static inline int gicv3_gicd_##BMP##_test(GICv3State *s, int irq) \
|
||||
{ \
|
||||
return gic_bmp_test_bit(irq, s->BMP); \
|
||||
return test_bit32(irq, s->BMP); \
|
||||
} \
|
||||
static inline void gicv3_gicd_##BMP##_clear(GICv3State *s, int irq) \
|
||||
{ \
|
||||
gic_bmp_clear_bit(irq, s->BMP); \
|
||||
clear_bit32(irq, s->BMP); \
|
||||
} \
|
||||
static inline void gicv3_gicd_##BMP##_replace(GICv3State *s, \
|
||||
int irq, int value) \
|
||||
|
@ -69,6 +69,14 @@
|
||||
#define DECLARE_BITMAP(name,bits) \
|
||||
unsigned long name[BITS_TO_LONGS(bits)]
|
||||
|
||||
/*
|
||||
* This is for use with the bit32 versions of set_bit() etc;
|
||||
* we don't currently support the full range of bitmap operations
|
||||
* on bitmaps backed by an array of uint32_t.
|
||||
*/
|
||||
#define DECLARE_BITMAP32(name, bits) \
|
||||
uint32_t name[BITS_TO_U32S(bits)]
|
||||
|
||||
#define small_nbits(nbits) \
|
||||
((nbits) <= BITS_PER_LONG)
|
||||
|
||||
|
@ -18,16 +18,47 @@
|
||||
|
||||
#define BITS_PER_BYTE CHAR_BIT
|
||||
#define BITS_PER_LONG (sizeof (unsigned long) * BITS_PER_BYTE)
|
||||
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
|
||||
#define BITS_TO_U32S(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(uint32_t))
|
||||
|
||||
#define BIT(nr) (1UL << (nr))
|
||||
#define BIT_ULL(nr) (1ULL << (nr))
|
||||
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
|
||||
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
|
||||
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
|
||||
|
||||
#define MAKE_64BIT_MASK(shift, length) \
|
||||
(((~0ULL) >> (64 - (length))) << (shift))
|
||||
|
||||
/**
|
||||
* DOC: Functions operating on arrays of bits
|
||||
*
|
||||
* We provide a set of functions which work on arbitrary-length arrays of
|
||||
* bits. These come in several flavours which vary in what the type of the
|
||||
* underlying storage for the bits is:
|
||||
*
|
||||
* - Bits stored in an array of 'unsigned long': set_bit(), clear_bit(), etc
|
||||
* - Bits stored in an array of 'uint32_t': set_bit32(), clear_bit32(), etc
|
||||
*
|
||||
* Because the 'unsigned long' type has a size which varies between
|
||||
* host systems, the versions using 'uint32_t' are often preferable.
|
||||
* This is particularly the case in a device model where there may
|
||||
* be some guest-visible register view of the bit array.
|
||||
*
|
||||
* We do not currently implement uint32_t versions of find_last_bit(),
|
||||
* find_next_bit(), find_next_zero_bit(), find_first_bit() or
|
||||
* find_first_zero_bit(), because we haven't yet needed them. If you
|
||||
* need them you should implement them similarly to the 'unsigned long'
|
||||
* versions.
|
||||
*
|
||||
* You can declare a bitmap to be used with these functions via the
|
||||
* DECLARE_BITMAP and DECLARE_BITMAP32 macros in bitmap.h.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: 'unsigned long' bit array APIs
|
||||
*/
|
||||
|
||||
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
|
||||
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
|
||||
|
||||
/**
|
||||
* set_bit - Set a bit in memory
|
||||
* @nr: the bit to set
|
||||
@ -224,6 +255,141 @@ static inline unsigned long find_first_zero_bit(const unsigned long *addr,
|
||||
return find_next_zero_bit(addr, size, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* DOC: 'uint32_t' bit array APIs
|
||||
*/
|
||||
|
||||
#define BIT32_MASK(nr) (1UL << ((nr) % 32))
|
||||
#define BIT32_WORD(nr) ((nr) / 32)
|
||||
|
||||
/**
|
||||
* set_bit32 - Set a bit in memory
|
||||
* @nr: the bit to set
|
||||
* @addr: the address to start counting from
|
||||
*/
|
||||
static inline void set_bit32(long nr, uint32_t *addr)
|
||||
{
|
||||
uint32_t mask = BIT32_MASK(nr);
|
||||
uint32_t *p = addr + BIT32_WORD(nr);
|
||||
|
||||
*p |= mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* set_bit32_atomic - Set a bit in memory atomically
|
||||
* @nr: the bit to set
|
||||
* @addr: the address to start counting from
|
||||
*/
|
||||
static inline void set_bit32_atomic(long nr, uint32_t *addr)
|
||||
{
|
||||
uint32_t mask = BIT32_MASK(nr);
|
||||
uint32_t *p = addr + BIT32_WORD(nr);
|
||||
|
||||
qatomic_or(p, mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* clear_bit32 - Clears a bit in memory
|
||||
* @nr: Bit to clear
|
||||
* @addr: Address to start counting from
|
||||
*/
|
||||
static inline void clear_bit32(long nr, uint32_t *addr)
|
||||
{
|
||||
uint32_t mask = BIT32_MASK(nr);
|
||||
uint32_t *p = addr + BIT32_WORD(nr);
|
||||
|
||||
*p &= ~mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* clear_bit32_atomic - Clears a bit in memory atomically
|
||||
* @nr: Bit to clear
|
||||
* @addr: Address to start counting from
|
||||
*/
|
||||
static inline void clear_bit32_atomic(long nr, uint32_t *addr)
|
||||
{
|
||||
uint32_t mask = BIT32_MASK(nr);
|
||||
uint32_t *p = addr + BIT32_WORD(nr);
|
||||
|
||||
return qatomic_and(p, ~mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* change_bit32 - Toggle a bit in memory
|
||||
* @nr: Bit to change
|
||||
* @addr: Address to start counting from
|
||||
*/
|
||||
static inline void change_bit32(long nr, uint32_t *addr)
|
||||
{
|
||||
uint32_t mask = BIT32_MASK(nr);
|
||||
uint32_t *p = addr + BIT32_WORD(nr);
|
||||
|
||||
*p ^= mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* test_and_set_bit32 - Set a bit and return its old value
|
||||
* @nr: Bit to set
|
||||
* @addr: Address to count from
|
||||
*/
|
||||
static inline int test_and_set_bit32(long nr, uint32_t *addr)
|
||||
{
|
||||
uint32_t mask = BIT32_MASK(nr);
|
||||
uint32_t *p = addr + BIT32_WORD(nr);
|
||||
uint32_t old = *p;
|
||||
|
||||
*p = old | mask;
|
||||
return (old & mask) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* test_and_clear_bit32 - Clear a bit and return its old value
|
||||
* @nr: Bit to clear
|
||||
* @addr: Address to count from
|
||||
*/
|
||||
static inline int test_and_clear_bit32(long nr, uint32_t *addr)
|
||||
{
|
||||
uint32_t mask = BIT32_MASK(nr);
|
||||
uint32_t *p = addr + BIT32_WORD(nr);
|
||||
uint32_t old = *p;
|
||||
|
||||
*p = old & ~mask;
|
||||
return (old & mask) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* test_and_change_bit32 - Change a bit and return its old value
|
||||
* @nr: Bit to change
|
||||
* @addr: Address to count from
|
||||
*/
|
||||
static inline int test_and_change_bit32(long nr, uint32_t *addr)
|
||||
{
|
||||
uint32_t mask = BIT32_MASK(nr);
|
||||
uint32_t *p = addr + BIT32_WORD(nr);
|
||||
uint32_t old = *p;
|
||||
|
||||
*p = old ^ mask;
|
||||
return (old & mask) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* test_bit32 - Determine whether a bit is set
|
||||
* @nr: bit number to test
|
||||
* @addr: Address to start counting from
|
||||
*/
|
||||
static inline int test_bit32(long nr, const uint32_t *addr)
|
||||
{
|
||||
return 1U & (addr[BIT32_WORD(nr)] >> (nr & 31));
|
||||
}
|
||||
|
||||
/**
|
||||
* DOC: Miscellaneous bit operations on single values
|
||||
*
|
||||
* These functions are a collection of useful operations
|
||||
* (rotations, bit extract, bit deposit, etc) on single
|
||||
* integer values.
|
||||
*/
|
||||
|
||||
/**
|
||||
* rol8 - rotate an 8-bit value left
|
||||
* @word: value to rotate
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "trace/trace-root.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "sysemu/cpu-timers.h"
|
||||
|
@ -4,6 +4,13 @@
|
||||
# Since requests are raised via monitor, not many tracepoints are needed.
|
||||
balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu"
|
||||
|
||||
# dma-helpers.c
|
||||
dma_blk_io(void *dbs, void *bs, int64_t offset, bool to_dev) "dbs=%p bs=%p offset=%" PRId64 " to_dev=%d"
|
||||
dma_aio_cancel(void *dbs) "dbs=%p"
|
||||
dma_complete(void *dbs, int ret, void *cb) "dbs=%p ret=%d cb=%p"
|
||||
dma_blk_cb(void *dbs, int ret) "dbs=%p ret=%d"
|
||||
dma_map_wait(void *dbs) "dbs=%p"
|
||||
|
||||
# ioport.c
|
||||
cpu_in(unsigned int addr, char size, unsigned int val) "addr 0x%x(%c) value %u"
|
||||
cpu_out(unsigned int addr, char size, unsigned int val) "addr 0x%x(%c) value %u"
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "target/arm/internals.h"
|
||||
#include "target/arm/multiprocessing.h"
|
||||
#include "target/arm/gtimer.h"
|
||||
#include "trace/trace-target_arm_hvf.h"
|
||||
#include "trace.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
#include "gdbstub/enums.h"
|
||||
|
1
target/arm/hvf/trace.h
Normal file
1
target/arm/hvf/trace.h
Normal file
@ -0,0 +1 @@
|
||||
#include "trace/trace-target_arm_hvf.h"
|
@ -85,6 +85,10 @@ static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw,
|
||||
GetPhysAddrResult *result,
|
||||
ARMMMUFaultInfo *fi);
|
||||
|
||||
static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64,
|
||||
int user_rw, int prot_rw, int xn, int pxn,
|
||||
ARMSecuritySpace in_pa, ARMSecuritySpace out_pa);
|
||||
|
||||
/* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */
|
||||
static const uint8_t pamax_map[] = {
|
||||
[0] = 32,
|
||||
@ -1148,7 +1152,7 @@ static bool get_phys_addr_v6(CPUARMState *env, S1Translate *ptw,
|
||||
hwaddr phys_addr;
|
||||
uint32_t dacr;
|
||||
bool ns;
|
||||
int user_prot;
|
||||
ARMSecuritySpace out_space;
|
||||
|
||||
/* Pagetable walk. */
|
||||
/* Lookup l1 descriptor. */
|
||||
@ -1240,16 +1244,19 @@ static bool get_phys_addr_v6(CPUARMState *env, S1Translate *ptw,
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
out_space = ptw->in_space;
|
||||
if (ns) {
|
||||
/*
|
||||
* The NS bit will (as required by the architecture) have no effect if
|
||||
* the CPU doesn't support TZ or this is a non-secure translation
|
||||
* regime, because the output space will already be non-secure.
|
||||
*/
|
||||
out_space = ARMSS_NonSecure;
|
||||
}
|
||||
if (domain_prot == 3) {
|
||||
result->f.prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||
} else {
|
||||
if (pxn && !regime_is_user(env, mmu_idx)) {
|
||||
xn = 1;
|
||||
}
|
||||
if (xn && access_type == MMU_INST_FETCH) {
|
||||
fi->type = ARMFault_Permission;
|
||||
goto do_fault;
|
||||
}
|
||||
int user_rw, prot_rw;
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_V6K) &&
|
||||
(regime_sctlr(env, mmu_idx) & SCTLR_AFE)) {
|
||||
@ -1259,37 +1266,23 @@ static bool get_phys_addr_v6(CPUARMState *env, S1Translate *ptw,
|
||||
fi->type = ARMFault_AccessFlag;
|
||||
goto do_fault;
|
||||
}
|
||||
result->f.prot = simple_ap_to_rw_prot(env, mmu_idx, ap >> 1);
|
||||
user_prot = simple_ap_to_rw_prot_is_user(ap >> 1, 1);
|
||||
prot_rw = simple_ap_to_rw_prot(env, mmu_idx, ap >> 1);
|
||||
user_rw = simple_ap_to_rw_prot_is_user(ap >> 1, 1);
|
||||
} else {
|
||||
result->f.prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot);
|
||||
user_prot = ap_to_rw_prot_is_user(env, mmu_idx, ap, domain_prot, 1);
|
||||
}
|
||||
if (result->f.prot && !xn) {
|
||||
result->f.prot |= PAGE_EXEC;
|
||||
prot_rw = ap_to_rw_prot(env, mmu_idx, ap, domain_prot);
|
||||
user_rw = ap_to_rw_prot_is_user(env, mmu_idx, ap, domain_prot, 1);
|
||||
}
|
||||
|
||||
result->f.prot = get_S1prot(env, mmu_idx, false, user_rw, prot_rw,
|
||||
xn, pxn, result->f.attrs.space, out_space);
|
||||
if (!(result->f.prot & (1 << access_type))) {
|
||||
/* Access permission fault. */
|
||||
fi->type = ARMFault_Permission;
|
||||
goto do_fault;
|
||||
}
|
||||
if (regime_is_pan(env, mmu_idx) &&
|
||||
!regime_is_user(env, mmu_idx) &&
|
||||
user_prot &&
|
||||
access_type != MMU_INST_FETCH) {
|
||||
/* Privileged Access Never fault */
|
||||
fi->type = ARMFault_Permission;
|
||||
goto do_fault;
|
||||
}
|
||||
}
|
||||
if (ns) {
|
||||
/* The NS bit will (as required by the architecture) have no effect if
|
||||
* the CPU doesn't support TZ or this is a non-secure translation
|
||||
* regime, because the attribute will already be non-secure.
|
||||
*/
|
||||
result->f.attrs.secure = false;
|
||||
result->f.attrs.space = ARMSS_NonSecure;
|
||||
}
|
||||
result->f.attrs.space = out_space;
|
||||
result->f.attrs.secure = arm_space_is_secure(out_space);
|
||||
result->f.phys_addr = phys_addr;
|
||||
return false;
|
||||
do_fault:
|
||||
@ -1357,25 +1350,24 @@ static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0)
|
||||
* @env: CPUARMState
|
||||
* @mmu_idx: MMU index indicating required translation regime
|
||||
* @is_aa64: TRUE if AArch64
|
||||
* @ap: The 2-bit simple AP (AP[2:1])
|
||||
* @user_rw: Translated AP for user access
|
||||
* @prot_rw: Translated AP for privileged access
|
||||
* @xn: XN (execute-never) bit
|
||||
* @pxn: PXN (privileged execute-never) bit
|
||||
* @in_pa: The original input pa space
|
||||
* @out_pa: The output pa space, modified by NSTable, NS, and NSE
|
||||
*/
|
||||
static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64,
|
||||
int ap, int xn, int pxn,
|
||||
int user_rw, int prot_rw, int xn, int pxn,
|
||||
ARMSecuritySpace in_pa, ARMSecuritySpace out_pa)
|
||||
{
|
||||
ARMCPU *cpu = env_archcpu(env);
|
||||
bool is_user = regime_is_user(env, mmu_idx);
|
||||
int prot_rw, user_rw;
|
||||
bool have_wxn;
|
||||
int wxn = 0;
|
||||
|
||||
assert(!regime_is_stage2(mmu_idx));
|
||||
|
||||
user_rw = simple_ap_to_rw_prot_is_user(ap, true);
|
||||
if (is_user) {
|
||||
prot_rw = user_rw;
|
||||
} else {
|
||||
@ -1393,8 +1385,6 @@ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64,
|
||||
regime_is_pan(env, mmu_idx) &&
|
||||
(regime_sctlr(env, mmu_idx) & SCTLR_EPAN) && !xn) {
|
||||
prot_rw = 0;
|
||||
} else {
|
||||
prot_rw = simple_ap_to_rw_prot_is_user(ap, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2044,6 +2034,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
|
||||
int nse, ns = extract32(attrs, 5, 1);
|
||||
uint8_t attrindx;
|
||||
uint64_t mair;
|
||||
int user_rw, prot_rw;
|
||||
|
||||
switch (out_space) {
|
||||
case ARMSS_Root:
|
||||
@ -2110,12 +2101,15 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
|
||||
xn = 0;
|
||||
ap &= ~1;
|
||||
}
|
||||
|
||||
user_rw = simple_ap_to_rw_prot_is_user(ap, true);
|
||||
prot_rw = simple_ap_to_rw_prot_is_user(ap, false);
|
||||
/*
|
||||
* Note that we modified ptw->in_space earlier for NSTable, but
|
||||
* result->f.attrs retains a copy of the original security space.
|
||||
*/
|
||||
result->f.prot = get_S1prot(env, mmu_idx, aarch64, ap, xn, pxn,
|
||||
result->f.attrs.space, out_space);
|
||||
result->f.prot = get_S1prot(env, mmu_idx, aarch64, user_rw, prot_rw,
|
||||
xn, pxn, result->f.attrs.space, out_space);
|
||||
|
||||
/* Index into MAIR registers for cache attributes */
|
||||
attrindx = extract32(attrs, 2, 3);
|
||||
|
@ -15,14 +15,12 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "exec/hwaddr.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "libqtest-single.h"
|
||||
|
||||
/*
|
||||
* lm3s811evb watchdog; at board startup this runs at 200MHz / 16 == 12.5MHz,
|
||||
* which is 80ns per tick.
|
||||
*/
|
||||
#define WDOG_BASE 0x40000000
|
||||
#define WDOG_BASE_MPS2 0x40008000
|
||||
|
||||
#define WDOGLOAD 0
|
||||
#define WDOGVALUE 4
|
||||
@ -37,39 +35,97 @@
|
||||
#define SYSDIV_SHIFT 23
|
||||
#define SYSDIV_LENGTH 4
|
||||
|
||||
static void test_watchdog(void)
|
||||
#define WDOGLOAD_DEFAULT 0xFFFFFFFF
|
||||
#define WDOGVALUE_DEFAULT 0xFFFFFFFF
|
||||
|
||||
typedef struct CMSDKAPBWatchdogTestArgs {
|
||||
int64_t tick;
|
||||
hwaddr wdog_base;
|
||||
const char *machine;
|
||||
} CMSDKAPBWatchdogTestArgs;
|
||||
|
||||
enum {
|
||||
MACHINE_LM3S811EVB,
|
||||
MACHINE_MPS2_AN385,
|
||||
};
|
||||
|
||||
/*
|
||||
* lm3s811evb watchdog; at board startup this runs at 200MHz / 16 == 12.5MHz,
|
||||
* which is 80ns per tick.
|
||||
*
|
||||
* IoTKit/ARMSSE dualtimer; driven at 25MHz in mps2-an385, so 40ns per tick
|
||||
*/
|
||||
static const CMSDKAPBWatchdogTestArgs machine_info[] = {
|
||||
[MACHINE_LM3S811EVB] = {
|
||||
.tick = 80,
|
||||
.wdog_base = WDOG_BASE,
|
||||
.machine = "lm3s811evb",
|
||||
},
|
||||
[MACHINE_MPS2_AN385] = {
|
||||
.tick = 40,
|
||||
.wdog_base = WDOG_BASE_MPS2,
|
||||
.machine = "mps2-an385",
|
||||
},
|
||||
};
|
||||
|
||||
static void system_reset(QTestState *qtest)
|
||||
{
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
|
||||
QDict *resp;
|
||||
|
||||
writel(WDOG_BASE + WDOGCONTROL, 1);
|
||||
writel(WDOG_BASE + WDOGLOAD, 1000);
|
||||
|
||||
/* Step to just past the 500th tick */
|
||||
clock_step(500 * 80 + 1);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
|
||||
|
||||
/* Just past the 1000th tick: timer should have fired */
|
||||
clock_step(500 * 80);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 0);
|
||||
|
||||
/* VALUE reloads at following tick */
|
||||
clock_step(80);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
|
||||
|
||||
/* Writing any value to WDOGINTCLR clears the interrupt and reloads */
|
||||
clock_step(500 * 80);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
|
||||
writel(WDOG_BASE + WDOGINTCLR, 0);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
|
||||
resp = qtest_qmp(qtest, "{'execute': 'system_reset'}");
|
||||
g_assert(qdict_haskey(resp, "return"));
|
||||
qobject_unref(resp);
|
||||
qtest_qmp_eventwait(qtest, "RESET");
|
||||
}
|
||||
|
||||
static void test_clock_change(void)
|
||||
static void test_watchdog(const void *ptr)
|
||||
{
|
||||
const CMSDKAPBWatchdogTestArgs *args = ptr;
|
||||
hwaddr wdog_base = args->wdog_base;
|
||||
int64_t tick = args->tick;
|
||||
g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
|
||||
qtest_start(cmdline);
|
||||
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
|
||||
|
||||
writel(wdog_base + WDOGCONTROL, 1);
|
||||
writel(wdog_base + WDOGLOAD, 1000);
|
||||
|
||||
/* Step to just past the 500th tick */
|
||||
clock_step(500 * tick + 1);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 500);
|
||||
|
||||
/* Just past the 1000th tick: timer should have fired */
|
||||
clock_step(500 * tick);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 1);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 0);
|
||||
|
||||
/* VALUE reloads at following tick */
|
||||
clock_step(tick);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1000);
|
||||
|
||||
/* Writing any value to WDOGINTCLR clears the interrupt and reloads */
|
||||
clock_step(500 * tick);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 500);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 1);
|
||||
writel(wdog_base + WDOGINTCLR, 0);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
|
||||
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* This test can only be executed in the stellaris board since it relies on a
|
||||
* component of the board to change the clocking parameters of the watchdog.
|
||||
*/
|
||||
static void test_clock_change(const void *ptr)
|
||||
{
|
||||
uint32_t rcc;
|
||||
const CMSDKAPBWatchdogTestArgs *args = ptr;
|
||||
g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
|
||||
qtest_start(cmdline);
|
||||
|
||||
/*
|
||||
* Test that writing to the stellaris board's RCC register to
|
||||
@ -109,6 +165,201 @@ static void test_clock_change(void)
|
||||
writel(WDOG_BASE + WDOGINTCLR, 0);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
|
||||
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
/* Tests the counter is not running after reset. */
|
||||
static void test_watchdog_reset(const void *ptr)
|
||||
{
|
||||
const CMSDKAPBWatchdogTestArgs *args = ptr;
|
||||
hwaddr wdog_base = args->wdog_base;
|
||||
int64_t tick = args->tick;
|
||||
g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
|
||||
qtest_start(cmdline);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
|
||||
|
||||
g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
|
||||
g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
|
||||
|
||||
g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0);
|
||||
|
||||
/*
|
||||
* The counter should not be running if WDOGCONTROL.INTEN has not been set,
|
||||
* as it is the case after a cold reset.
|
||||
*/
|
||||
clock_step(15 * tick + 1);
|
||||
g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
|
||||
g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
|
||||
|
||||
/* Let the counter run before reset */
|
||||
writel(wdog_base + WDOGLOAD, 3000);
|
||||
writel(wdog_base + WDOGCONTROL, 1);
|
||||
|
||||
/* Verify it is running */
|
||||
clock_step(1000 * tick + 1);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 3000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 2000);
|
||||
|
||||
system_reset(global_qtest);
|
||||
|
||||
/* Check defaults after reset */
|
||||
g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
|
||||
g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
|
||||
|
||||
/* The counter should not be running after reset. */
|
||||
clock_step(1000 * tick + 1);
|
||||
g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
|
||||
g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
|
||||
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests inten works as the counter enable based on this description:
|
||||
*
|
||||
* Enable the interrupt event, WDOGINT. Set HIGH to enable the counter and the
|
||||
* interrupt, or LOW to disable the counter and interrupt. Reloads the counter
|
||||
* from the value in WDOGLOAD when the interrupt is enabled, after previously
|
||||
* being disabled.
|
||||
*/
|
||||
static void test_watchdog_inten(const void *ptr)
|
||||
{
|
||||
const CMSDKAPBWatchdogTestArgs *args = ptr;
|
||||
hwaddr wdog_base = args->wdog_base;
|
||||
int64_t tick = args->tick;
|
||||
g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
|
||||
qtest_start(cmdline);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
|
||||
|
||||
g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
|
||||
g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
|
||||
|
||||
/*
|
||||
* When WDOGLOAD is written to, the count is immediately restarted from the
|
||||
* new value.
|
||||
*
|
||||
* Note: the counter should not be running as long as WDOGCONTROL.INTEN is
|
||||
* not set
|
||||
*/
|
||||
writel(wdog_base + WDOGLOAD, 4000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
|
||||
clock_step(500 * tick + 1);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
|
||||
|
||||
/* Set HIGH WDOGCONTROL.INTEN to enable the counter and the interrupt */
|
||||
writel(wdog_base + WDOGCONTROL, 1);
|
||||
clock_step(500 * tick + 1);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500);
|
||||
|
||||
/* or LOW to disable the counter and interrupt. */
|
||||
writel(wdog_base + WDOGCONTROL, 0);
|
||||
clock_step(100 * tick);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500);
|
||||
|
||||
/*
|
||||
* Reloads the counter from the value in WDOGLOAD when the interrupt is
|
||||
* enabled, after previously being disabled.
|
||||
*/
|
||||
writel(wdog_base + WDOGCONTROL, 1);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
|
||||
|
||||
/* Test counter is still on */
|
||||
clock_step(50 * tick + 1);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3950);
|
||||
|
||||
/*
|
||||
* When WDOGLOAD is written to, the count is immediately restarted from the
|
||||
* new value.
|
||||
*
|
||||
* Note: the counter should be running since WDOGCONTROL.INTEN is set
|
||||
*/
|
||||
writel(wdog_base + WDOGLOAD, 5000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 5000);
|
||||
clock_step(4999 * tick + 1);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
|
||||
|
||||
/* Finally disable and check the conditions don't change */
|
||||
writel(wdog_base + WDOGCONTROL, 0);
|
||||
clock_step(10 * tick);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 5000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 1);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
|
||||
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests the following custom behavior:
|
||||
*
|
||||
* The Luminary version of this device ignores writes to this register after the
|
||||
* guest has enabled interrupts (so they can only be disabled again via reset).
|
||||
*/
|
||||
static void test_watchdog_inten_luminary(const void *ptr)
|
||||
{
|
||||
const CMSDKAPBWatchdogTestArgs *args = ptr;
|
||||
hwaddr wdog_base = args->wdog_base;
|
||||
int64_t tick = args->tick;
|
||||
g_autofree gchar *cmdline = g_strdup_printf("-machine %s", args->machine);
|
||||
qtest_start(cmdline);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGRIS), ==, 0);
|
||||
|
||||
g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
|
||||
g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
|
||||
|
||||
/*
|
||||
* When WDOGLOAD is written to, the count is immediately restarted from the
|
||||
* new value.
|
||||
*
|
||||
* Note: the counter should not be running as long as WDOGCONTROL.INTEN is
|
||||
* not set
|
||||
*/
|
||||
writel(wdog_base + WDOGLOAD, 4000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
|
||||
clock_step(500 * tick + 1);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 4000);
|
||||
|
||||
/* Set HIGH WDOGCONTROL.INTEN to enable the counter and the interrupt */
|
||||
writel(wdog_base + WDOGCONTROL, 1);
|
||||
clock_step(500 * tick + 1);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3500);
|
||||
|
||||
/*
|
||||
* The Luminary version of this device ignores writes to this register after
|
||||
* the guest has enabled interrupts
|
||||
*/
|
||||
writel(wdog_base + WDOGCONTROL, 0);
|
||||
clock_step(100 * tick);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGLOAD), ==, 4000);
|
||||
g_assert_cmpuint(readl(wdog_base + WDOGVALUE), ==, 3400);
|
||||
g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0x1);
|
||||
|
||||
/* They can only be disabled again via reset */
|
||||
system_reset(global_qtest);
|
||||
|
||||
/* Check defaults after reset */
|
||||
g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
|
||||
g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
|
||||
g_assert_cmphex(readl(wdog_base + WDOGCONTROL), ==, 0);
|
||||
|
||||
/* The counter should not be running after reset. */
|
||||
clock_step(1000 * tick + 1);
|
||||
g_assert_cmphex(readl(wdog_base + WDOGLOAD), ==, WDOGLOAD_DEFAULT);
|
||||
g_assert_cmphex(readl(wdog_base + WDOGVALUE), ==, WDOGVALUE_DEFAULT);
|
||||
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@ -116,16 +367,33 @@ int main(int argc, char **argv)
|
||||
int r;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
g_test_set_nonfatal_assertions();
|
||||
|
||||
qtest_start("-machine lm3s811evb");
|
||||
|
||||
qtest_add_func("/cmsdk-apb-watchdog/watchdog", test_watchdog);
|
||||
qtest_add_func("/cmsdk-apb-watchdog/watchdog_clock_change",
|
||||
test_clock_change);
|
||||
if (qtest_has_machine(machine_info[MACHINE_LM3S811EVB].machine)) {
|
||||
qtest_add_data_func("/cmsdk-apb-watchdog/watchdog",
|
||||
&machine_info[MACHINE_LM3S811EVB], test_watchdog);
|
||||
qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_clock_change",
|
||||
&machine_info[MACHINE_LM3S811EVB],
|
||||
test_clock_change);
|
||||
qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_reset",
|
||||
&machine_info[MACHINE_LM3S811EVB],
|
||||
test_watchdog_reset);
|
||||
qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_inten_luminary",
|
||||
&machine_info[MACHINE_LM3S811EVB],
|
||||
test_watchdog_inten_luminary);
|
||||
}
|
||||
if (qtest_has_machine(machine_info[MACHINE_MPS2_AN385].machine)) {
|
||||
qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_mps2",
|
||||
&machine_info[MACHINE_MPS2_AN385], test_watchdog);
|
||||
qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_reset_mps2",
|
||||
&machine_info[MACHINE_MPS2_AN385],
|
||||
test_watchdog_reset);
|
||||
qtest_add_data_func("/cmsdk-apb-watchdog/watchdog_inten",
|
||||
&machine_info[MACHINE_MPS2_AN385],
|
||||
test_watchdog_inten);
|
||||
}
|
||||
|
||||
r = g_test_run();
|
||||
|
||||
qtest_end();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -227,7 +227,8 @@ qtests_arm = \
|
||||
(config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_CMSDK_APB_DUALTIMER') ? ['cmsdk-apb-dualtimer-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_CMSDK_APB_TIMER') ? ['cmsdk-apb-timer-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_CMSDK_APB_WATCHDOG') ? ['cmsdk-apb-watchdog-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_STELLARIS') or
|
||||
config_all_devices.has_key('CONFIG_MPS2') ? ['cmsdk-apb-watchdog-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_PFLASH_CFI02') and
|
||||
config_all_devices.has_key('CONFIG_MUSICPAL') ? ['pflash-cfi02-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed : []) + \
|
||||
|
@ -30,13 +30,6 @@ breakpoint_insert(int cpu_index, uint64_t pc, int flags) "cpu=%d pc=0x%" PRIx64
|
||||
breakpoint_remove(int cpu_index, uint64_t pc, int flags) "cpu=%d pc=0x%" PRIx64 " flags=0x%x"
|
||||
breakpoint_singlestep(int cpu_index, int enabled) "cpu=%d enable=%d"
|
||||
|
||||
# dma-helpers.c
|
||||
dma_blk_io(void *dbs, void *bs, int64_t offset, bool to_dev) "dbs=%p bs=%p offset=%" PRId64 " to_dev=%d"
|
||||
dma_aio_cancel(void *dbs) "dbs=%p"
|
||||
dma_complete(void *dbs, int ret, void *cb) "dbs=%p ret=%d cb=%p"
|
||||
dma_blk_cb(void *dbs, int ret) "dbs=%p ret=%d"
|
||||
dma_map_wait(void *dbs) "dbs=%p"
|
||||
|
||||
# job.c
|
||||
job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)"
|
||||
job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)"
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/lockable.h"
|
||||
#include "cpu.h"
|
||||
#include "trace/trace-root.h"
|
||||
#include "trace/control.h"
|
||||
|
||||
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "trace/trace-root.h"
|
||||
|
||||
int trace_events_enabled_count;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user