- MAIN_SOFTMMU_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
- CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime"
- CCACHE_MAXSIZE=1G
+ - G_MESSAGES_DEBUG=error
git:
- name: "GCC check-acceptance"
dist: bionic
env:
- - CONFIG="--target-list=aarch64-softmmu,alpha-softmmu,arm-softmmu,m68k-softmmu,microblaze-softmmu,mips-softmmu,mips64el-softmmu,nios2-softmmu,or1k-softmmu,ppc-softmmu,ppc64-softmmu,s390x-softmmu,sparc-softmmu,x86_64-softmmu,xtensa-softmmu"
+ - CONFIG="--enable-tools --target-list=aarch64-softmmu,alpha-softmmu,arm-softmmu,m68k-softmmu,microblaze-softmmu,mips-softmmu,mips64el-softmmu,nios2-softmmu,or1k-softmmu,ppc-softmmu,ppc64-softmmu,s390x-softmmu,sparc-softmmu,x86_64-softmmu,xtensa-softmmu"
- TEST_CMD="make check-acceptance"
after_script:
- python3 -c 'import json; r = json.load(open("tests/results/latest/results.json")); [print(t["logfile"]) for t in r["tests"] if t["status"] not in ("PASS", "SKIP")]' | xargs cat
#include "tcg/tcg-gvec-desc.h"
-/* Virtually all hosts support 16-byte vectors. Those that don't can emulate
- * them via GCC's generic vector extension. This turns out to be simpler and
- * more reliable than getting the compiler to autovectorize.
- *
- * In tcg-op-gvec.c, we asserted that both the size and alignment of the data
- * are multiples of 16.
- *
- * When the compiler does not support all of the operations we require, the
- * loops are written so that we can always fall back on the base types.
- */
-#ifdef CONFIG_VECTOR16
-typedef uint8_t vec8 __attribute__((vector_size(16)));
-typedef uint16_t vec16 __attribute__((vector_size(16)));
-typedef uint32_t vec32 __attribute__((vector_size(16)));
-typedef uint64_t vec64 __attribute__((vector_size(16)));
-
-typedef int8_t svec8 __attribute__((vector_size(16)));
-typedef int16_t svec16 __attribute__((vector_size(16)));
-typedef int32_t svec32 __attribute__((vector_size(16)));
-typedef int64_t svec64 __attribute__((vector_size(16)));
-
-#define DUP16(X) { X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X }
-#define DUP8(X) { X, X, X, X, X, X, X, X }
-#define DUP4(X) { X, X, X, X }
-#define DUP2(X) { X, X }
-#else
-typedef uint8_t vec8;
-typedef uint16_t vec16;
-typedef uint32_t vec32;
-typedef uint64_t vec64;
-
-typedef int8_t svec8;
-typedef int16_t svec16;
-typedef int32_t svec32;
-typedef int64_t svec64;
-
-#define DUP16(X) X
-#define DUP8(X) X
-#define DUP4(X) X
-#define DUP2(X) X
-#endif /* CONFIG_VECTOR16 */
-
static inline void clear_high(void *d, intptr_t oprsz, uint32_t desc)
{
intptr_t maxsz = simd_maxsz(desc);
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) + *(vec8 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) + *(uint8_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) + *(vec16 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) + *(uint16_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) + *(vec32 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) + *(uint32_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) + *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) + *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_adds8)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec8 vecb = (vec8)DUP16(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) + vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) + (uint8_t)b;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_adds16)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec16 vecb = (vec16)DUP8(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) + vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) + (uint16_t)b;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_adds32)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec32 vecb = (vec32)DUP4(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) + vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) + (uint32_t)b;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_adds64)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec64 vecb = (vec64)DUP2(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) + vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) + b;
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) - *(vec8 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) - *(uint8_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) - *(vec16 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) - *(uint16_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) - *(vec32 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) - *(uint32_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) - *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) - *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_subs8)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec8 vecb = (vec8)DUP16(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) - vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) - (uint8_t)b;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_subs16)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec16 vecb = (vec16)DUP8(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) - vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) - (uint16_t)b;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_subs32)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec32 vecb = (vec32)DUP4(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) - vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) - (uint32_t)b;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_subs64)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec64 vecb = (vec64)DUP2(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) - vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) - b;
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) * *(vec8 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) * *(uint8_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) * *(vec16 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) * *(uint16_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) * *(vec32 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) * *(uint32_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) * *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) * *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_muls8)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec8 vecb = (vec8)DUP16(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) * vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) * (uint8_t)b;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_muls16)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec16 vecb = (vec16)DUP8(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) * vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) * (uint16_t)b;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_muls32)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec32 vecb = (vec32)DUP4(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) * vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) * (uint32_t)b;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_muls64)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec64 vecb = (vec64)DUP2(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) * vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) * b;
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = -*(vec8 *)(a + i);
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = -*(uint8_t *)(a + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = -*(vec16 *)(a + i);
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = -*(uint16_t *)(a + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = -*(vec32 *)(a + i);
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = -*(uint32_t *)(a + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = -*(vec64 *)(a + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = -*(uint64_t *)(a + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = ~*(vec64 *)(a + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = ~*(uint64_t *)(a + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) & *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) & *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) | *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) | *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) ^ *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) ^ *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) &~ *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) &~ *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) |~ *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) |~ *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = ~(*(vec64 *)(a + i) & *(vec64 *)(b + i));
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = ~(*(uint64_t *)(a + i) & *(uint64_t *)(b + i));
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = ~(*(vec64 *)(a + i) | *(vec64 *)(b + i));
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = ~(*(uint64_t *)(a + i) | *(uint64_t *)(b + i));
}
clear_high(d, oprsz, desc);
}
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = ~(*(vec64 *)(a + i) ^ *(vec64 *)(b + i));
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = ~(*(uint64_t *)(a + i) ^ *(uint64_t *)(b + i));
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_ands)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec64 vecb = (vec64)DUP2(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) & vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) & b;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_xors)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec64 vecb = (vec64)DUP2(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) ^ vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) ^ b;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_ors)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec64 vecb = (vec64)DUP2(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) | vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) | b;
}
clear_high(d, oprsz, desc);
}
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) << shift;
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) << shift;
}
clear_high(d, oprsz, desc);
}
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) << shift;
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) << shift;
}
clear_high(d, oprsz, desc);
}
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) << shift;
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) << shift;
}
clear_high(d, oprsz, desc);
}
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) << shift;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) << shift;
}
clear_high(d, oprsz, desc);
}
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(svec8 *)(d + i) = *(svec8 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(int8_t *)(d + i) = *(int8_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(svec16 *)(d + i) = *(svec16 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(int16_t *)(d + i) = *(int16_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(svec32 *)(d + i) = *(svec32 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(int32_t *)(d + i) = *(int32_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(svec64 *)(d + i) = *(svec64 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(int64_t *)(d + i) = *(int64_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
clear_high(d, oprsz, desc);
}
-/* If vectors are enabled, the compiler fills in -1 for true.
- Otherwise, we must take care of this by hand. */
-#ifdef CONFIG_VECTOR16
-# define DO_CMP0(X) X
-#else
-# define DO_CMP0(X) -(X)
-#endif
-
#define DO_CMP1(NAME, TYPE, OP) \
void HELPER(NAME)(void *d, void *a, void *b, uint32_t desc) \
{ \
intptr_t oprsz = simd_oprsz(desc); \
intptr_t i; \
for (i = 0; i < oprsz; i += sizeof(TYPE)) { \
- *(TYPE *)(d + i) = DO_CMP0(*(TYPE *)(a + i) OP *(TYPE *)(b + i)); \
+ *(TYPE *)(d + i) = -(*(TYPE *)(a + i) OP *(TYPE *)(b + i)); \
} \
clear_high(d, oprsz, desc); \
}
#define DO_CMP2(SZ) \
- DO_CMP1(gvec_eq##SZ, vec##SZ, ==) \
- DO_CMP1(gvec_ne##SZ, vec##SZ, !=) \
- DO_CMP1(gvec_lt##SZ, svec##SZ, <) \
- DO_CMP1(gvec_le##SZ, svec##SZ, <=) \
- DO_CMP1(gvec_ltu##SZ, vec##SZ, <) \
- DO_CMP1(gvec_leu##SZ, vec##SZ, <=)
+ DO_CMP1(gvec_eq##SZ, uint##SZ##_t, ==) \
+ DO_CMP1(gvec_ne##SZ, uint##SZ##_t, !=) \
+ DO_CMP1(gvec_lt##SZ, int##SZ##_t, <) \
+ DO_CMP1(gvec_le##SZ, int##SZ##_t, <=) \
+ DO_CMP1(gvec_ltu##SZ, uint##SZ##_t, <) \
+ DO_CMP1(gvec_leu##SZ, uint##SZ##_t, <=)
DO_CMP2(8)
DO_CMP2(16)
DO_CMP2(32)
DO_CMP2(64)
-#undef DO_CMP0
#undef DO_CMP1
#undef DO_CMP2
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- vec64 aa = *(vec64 *)(a + i);
- vec64 bb = *(vec64 *)(b + i);
- vec64 cc = *(vec64 *)(c + i);
- *(vec64 *)(d + i) = (bb & aa) | (cc & ~aa);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ uint64_t aa = *(uint64_t *)(a + i);
+ uint64_t bb = *(uint64_t *)(b + i);
+ uint64_t cc = *(uint64_t *)(c + i);
+ *(uint64_t *)(d + i) = (bb & aa) | (cc & ~aa);
}
clear_high(d, oprsz, desc);
}
void hmp_info_block_jobs(Monitor *mon, const QDict *qdict)
{
BlockJobInfoList *list;
- Error *err = NULL;
- list = qmp_query_block_jobs(&err);
- assert(!err);
+ list = qmp_query_block_jobs(&error_abort);
if (!list) {
monitor_printf(mon, "No active jobs\n");
debug_info="yes"
stack_protector=""
use_containers="yes"
+gdb_bin=$(command -v "gdb")
if test -e "$source_path/.git"
then
;;
--disable-fuzzing) fuzzing=no
;;
+ --gdb=*) gdb_bin="$optarg"
+ ;;
*)
echo "ERROR: unknown option $opt"
echo "Try '$0 --help' for more information"
--enable-plugins
enable plugins via shared library loading
--disable-containers don't use containers for cross-building
+ --gdb=GDB-path gdb to use for gdbstub tests [$gdb_bin]
Optional features, enabled with --enable-FEATURE and
disabled with --disable-FEATURE, default is enabled if available:
"for this purpose. You can't build with --static."
fi
-########################################
-# See if 16-byte vector operations are supported.
-# Even without a vector unit the compiler may expand these.
-# There is a bug in old GCC for PPC that crashes here.
-# Unfortunately it's the system compiler for Centos 7.
-
-cat > $TMPC << EOF
-typedef unsigned char U1 __attribute__((vector_size(16)));
-typedef unsigned short U2 __attribute__((vector_size(16)));
-typedef unsigned int U4 __attribute__((vector_size(16)));
-typedef unsigned long long U8 __attribute__((vector_size(16)));
-typedef signed char S1 __attribute__((vector_size(16)));
-typedef signed short S2 __attribute__((vector_size(16)));
-typedef signed int S4 __attribute__((vector_size(16)));
-typedef signed long long S8 __attribute__((vector_size(16)));
-static U1 a1, b1;
-static U2 a2, b2;
-static U4 a4, b4;
-static U8 a8, b8;
-static S1 c1;
-static S2 c2;
-static S4 c4;
-static S8 c8;
-static int i;
-void helper(void *d, void *a, int shift, int i);
-void helper(void *d, void *a, int shift, int i)
-{
- *(U1 *)(d + i) = *(U1 *)(a + i) << shift;
- *(U2 *)(d + i) = *(U2 *)(a + i) << shift;
- *(U4 *)(d + i) = *(U4 *)(a + i) << shift;
- *(U8 *)(d + i) = *(U8 *)(a + i) << shift;
-}
-int main(void)
-{
- a1 += b1; a2 += b2; a4 += b4; a8 += b8;
- a1 -= b1; a2 -= b2; a4 -= b4; a8 -= b8;
- a1 *= b1; a2 *= b2; a4 *= b4; a8 *= b8;
- a1 &= b1; a2 &= b2; a4 &= b4; a8 &= b8;
- a1 |= b1; a2 |= b2; a4 |= b4; a8 |= b8;
- a1 ^= b1; a2 ^= b2; a4 ^= b4; a8 ^= b8;
- a1 <<= i; a2 <<= i; a4 <<= i; a8 <<= i;
- a1 >>= i; a2 >>= i; a4 >>= i; a8 >>= i;
- c1 >>= i; c2 >>= i; c4 >>= i; c8 >>= i;
- return 0;
-}
-EOF
-
-vector16=no
-if compile_prog "" "" ; then
- vector16=yes
-fi
-
########################################
# See if __attribute__((alias)) is supported.
# This false for Xcode 9, but has been remedied for Xcode 10.
echo "default devices $default_devices"
echo "plugin support $plugins"
echo "fuzzing support $fuzzing"
+echo "gdb $gdb_bin"
if test "$supported_cpu" = "no"; then
echo
echo "CONFIG_ATOMIC64=y" >> $config_host_mak
fi
-if test "$vector16" = "yes" ; then
- echo "CONFIG_VECTOR16=y" >> $config_host_mak
-fi
-
if test "$attralias" = "yes" ; then
echo "CONFIG_ATTRIBUTE_ALIAS=y" >> $config_host_mak
fi
fi
fi
+if test -n "$gdb_bin" ; then
+ echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak
+fi
+
if test "$tcg_interpreter" = "yes"; then
QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
elif test "$ARCH" = "sparc64" ; then
ENUM = { 'enum': STRING,
'data': [ ENUM-VALUE, ... ],
'*prefix': STRING,
- '*if': COND }
+ '*if': COND,
+ '*features': FEATURES }
ENUM-VALUE = STRING
| { 'name': STRING, '*if': COND }
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.
+The optional 'features' member specifies features. See "Features"
+below for more on this.
+
=== Type references and array types ===
'*features': FEATURES }
MEMBERS = { MEMBER, ... }
MEMBER = STRING : TYPE-REF
- | STRING : { 'type': TYPE-REF, '*if': COND }
+ | STRING : { 'type': TYPE-REF,
+ '*if': COND,
+ '*features': FEATURES }
Member 'struct' names the struct type.
Syntax:
UNION = { 'union': STRING,
'data': BRANCHES,
- '*if': COND }
+ '*if': COND,
+ '*features': FEATURES }
| { 'union': STRING,
'data': BRANCHES,
'base': ( MEMBERS | STRING ),
'discriminator': STRING,
- '*if': COND }
+ '*if': COND,
+ '*features': FEATURES }
BRANCHES = { BRANCH, ... }
BRANCH = STRING : TYPE-REF
| STRING : { 'type': TYPE-REF, '*if': COND }
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.
+The optional 'features' member specifies features. See "Features"
+below for more on this.
+
=== Alternate types ===
Syntax:
ALTERNATE = { 'alternate': STRING,
'data': ALTERNATIVES,
- '*if': COND }
+ '*if': COND,
+ '*features': FEATURES }
ALTERNATIVES = { ALTERNATIVE, ... }
- ALTERNATIVE = STRING : TYPE-REF
+ ALTERNATIVE = STRING : STRING
| STRING : { 'type': STRING, '*if': COND }
Member 'alternate' names the alternate type.
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.
+The optional 'features' member specifies features. See "Features"
+below for more on this.
+
=== Commands ===
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.
+The optional 'features' member specifies features. See "Features"
+below for more on this.
+
=== Events ===
'data': STRING,
'boxed': true,
)
- '*if': COND }
+ '*if': COND,
+ '*features': FEATURES }
Member 'event' names the event. This is the event name used in the
Client JSON Protocol.
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.
+The optional 'features' member specifies features. See "Features"
+below for more on this.
+
=== Features ===
know whether the extension is available.
For this purpose, a list of features can be specified for a command or
-struct type. This is exposed to the client as a list of strings,
-where each string signals that this build of QEMU shows a certain
-behaviour.
-
-Each member of the 'features' array defines a feature. It can either
-be { 'name': STRING, '*if': COND }, or STRING, which is shorthand for
-{ 'name': STRING }.
+struct type. Each list member can either be { 'name': STRING, '*if':
+COND }, or STRING, which is shorthand for { 'name': STRING }.
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.
'data': { 'number': 'int' },
'features': [ 'allow-negative-numbers' ] }
+The feature strings are exposed to clients in introspection, as
+explained in section "Client JSON Protocol introspection".
+
+Intended use is to have each feature string signal that this build of
+QEMU shows a certain behaviour.
+
+
+==== Special features ====
+
+Feature "deprecated" marks a command, event, or struct member as
+deprecated. It is not supported elsewhere so far.
+
=== Naming rules and reserved names ===
overview how things work. For details you need to consult the QAPI
schema.
-SchemaInfo objects have common members "name" and "meta-type", and
-additional variant members depending on the value of meta-type.
+SchemaInfo objects have common members "name", "meta-type",
+"features", and additional variant members depending on the value of
+meta-type.
Each SchemaInfo object describes a wire ABI entity of a certain
meta-type: a command, event or one of several kinds of type.
meaningless names. For readability, the examples in this section use
meaningful type names instead.
+Optional member "features" exposes the entity's feature strings as a
+JSON array of strings.
+
To examine a type, start with a command or event using it, then follow
references by name.
members "arg-type", "ret-type" and "allow-oob". On the wire, the
"arguments" member of a client's "execute" command must conform to the
object type named by "arg-type". The "return" member that the server
-passes in a success response conforms to the type named by
-"ret-type". When "allow-oob" is set, it means the command supports
-out-of-band execution.
+passes in a success response conforms to the type named by "ret-type".
+When "allow-oob" is true, it means the command supports out-of-band
+execution. It defaults to false.
If the command takes no arguments, "arg-type" names an object type
without members. Likewise, if the command returns nothing, "ret-type"
{ "name": "member2", "type": "int" },
{ "name": "member3", "type": "str", "default": null } ] }
+"features" exposes the command's feature strings as a JSON array of
+strings.
+
+Example: the SchemaInfo for TestType from section Features:
+
+ { "name": "TestType", "meta-type": "object",
+ "members": [
+ { "name": "number", "type": "int" } ],
+ "features": ["allow-negative-numbers"] }
+
"tag" is the name of the common member serving as type tag.
"variants" is a JSON array describing the object's variant members.
Each element is a JSON object with members "case" (the value of type
Use ``blockdev-change-medium`` or ``change-vnc-password`` instead.
+``blockdev-open-tray``, ``blockdev-close-tray`` argument ``device`` (since 2.8.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Use argument ``id`` instead.
+
+``eject`` argument ``device`` (since 2.8.0)
+'''''''''''''''''''''''''''''''''''''''''''
+
+Use argument ``id`` instead.
+
+``blockdev-change-medium`` argument ``device`` (since 2.8.0)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Use argument ``id`` instead.
+
+``block_set_io_throttle`` argument ``device`` (since 2.8.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Use argument ``id`` instead.
+
``migrate_set_downtime`` and ``migrate_set_speed`` (since 2.8.0)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Use ``migrate-set-parameters`` instead.
+``query-named-block-nodes`` result ``encryption_key_missing`` (since 2.10.0)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Always false.
+
+``query-block`` result ``inserted.encryption_key_missing`` (since 2.10.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Always false.
+
+``blockdev-add`` empty string argument ``backing`` (since 2.10.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Use argument value ``null`` instead.
+
``migrate-set-cache-size`` and ``query-migrate-cache-size`` (since 2.11.0)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Use ``migrate-set-parameters`` and ``query-migrate-parameters`` instead.
+``block-commit`` arguments ``base`` and ``top`` (since 3.1.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Use arguments ``base-node`` and ``top-node`` instead.
+
``object-add`` option ``props`` (since 5.0)
'''''''''''''''''''''''''''''''''''''''''''
Specify the properties for the object as top-level arguments instead.
-``query-block`` result field ``dirty-bitmaps[i].status`` (since 4.0)
-''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+``query-named-block-nodes`` and ``query-block`` result dirty-bitmaps[i].status (since 4.0)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
The ``status`` field of the ``BlockDirtyInfo`` structure, returned by
-the query-block command is deprecated. Two new boolean fields,
-``recording`` and ``busy`` effectively replace it.
+these commands is deprecated. Two new boolean fields, ``recording`` and
+``busy`` effectively replace it.
``query-block`` result field ``dirty-bitmaps`` (Since 4.2)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
``rv64imacu-nommu`` should no longer be used. Instead the MMU status can be specified
via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs.
+``compat`` property of server class POWER CPUs (since 5.0)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+The ``compat`` property used to set backwards compatibility modes for
+the processor has been deprecated. The ``max-cpu-compat`` property of
+the ``pseries`` machine type should be used instead.
+
System emulator devices
-----------------------
typedef struct GDBRegisterState {
int base_reg;
int num_regs;
- gdb_reg_cb get_reg;
- gdb_reg_cb set_reg;
+ gdb_get_reg_cb get_reg;
+ gdb_set_reg_cb set_reg;
const char *xml;
struct GDBRegisterState *next;
} GDBRegisterState;
RS_CHKSUM2,
};
typedef struct GDBState {
+ bool init; /* have we been initialised? */
CPUState *c_cpu; /* current CPU for step/continue ops */
CPUState *g_cpu; /* current CPU for other ops */
CPUState *query_cpu; /* for q{f|s}ThreadInfo */
int line_buf_index;
int line_sum; /* running checksum */
int line_csum; /* checksum at the end of the packet */
- uint8_t last_packet[MAX_PACKET_LENGTH + 4];
- int last_packet_len;
+ GByteArray *last_packet;
int signal;
#ifdef CONFIG_USER_ONLY
int fd;
int process_num;
char syscall_buf[256];
gdb_syscall_complete_cb current_syscall_cb;
+ GString *str_buf;
+ GByteArray *mem_buf;
} GDBState;
/* By default use no IRQs and no timers while single stepping so as to
*/
static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
-static GDBState *gdbserver_state;
+static GDBState gdbserver_state;
+
+static void init_gdbserver_state(void)
+{
+ g_assert(!gdbserver_state.init);
+ memset(&gdbserver_state, 0, sizeof(GDBState));
+ gdbserver_state.init = true;
+ gdbserver_state.str_buf = g_string_new(NULL);
+ gdbserver_state.mem_buf = g_byte_array_sized_new(MAX_PACKET_LENGTH);
+ gdbserver_state.last_packet = g_byte_array_sized_new(MAX_PACKET_LENGTH + 4);
+}
+
+#ifndef CONFIG_USER_ONLY
+static void reset_gdbserver_state(void)
+{
+ g_free(gdbserver_state.processes);
+ gdbserver_state.processes = NULL;
+ gdbserver_state.process_num = 0;
+}
+#endif
bool gdb_has_xml;
/* XXX: This is not thread safe. Do we care? */
static int gdbserver_fd = -1;
-static int get_char(GDBState *s)
+static int get_char(void)
{
uint8_t ch;
int ret;
for(;;) {
- ret = qemu_recv(s->fd, &ch, 1, 0);
+ ret = qemu_recv(gdbserver_state.fd, &ch, 1, 0);
if (ret < 0) {
if (errno == ECONNRESET)
- s->fd = -1;
+ gdbserver_state.fd = -1;
if (errno != EINTR)
return -1;
} else if (ret == 0) {
- close(s->fd);
- s->fd = -1;
+ close(gdbserver_state.fd);
+ gdbserver_state.fd = -1;
return -1;
} else {
break;
/* -semihosting-config target=auto */
/* On the first call check if gdb is connected and remember. */
if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
- gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED
- : GDB_SYS_DISABLED);
+ gdb_syscall_mode = gdbserver_state.init ?
+ GDB_SYS_ENABLED : GDB_SYS_DISABLED;
}
return gdb_syscall_mode == GDB_SYS_ENABLED;
}
/* Resume execution. */
-static inline void gdb_continue(GDBState *s)
+static inline void gdb_continue(void)
{
#ifdef CONFIG_USER_ONLY
- s->running_state = 1;
+ gdbserver_state.running_state = 1;
trace_gdbstub_op_continue();
#else
if (!runstate_needs_reset()) {
* Resume execution, per CPU actions. For user-mode emulation it's
* equivalent to gdb_continue.
*/
-static int gdb_continue_partial(GDBState *s, char *newstates)
+static int gdb_continue_partial(char *newstates)
{
CPUState *cpu;
int res = 0;
cpu_single_step(cpu, sstep_flags);
}
}
- s->running_state = 1;
+ gdbserver_state.running_state = 1;
#else
int flag = 0;
return res;
}
-static void put_buffer(GDBState *s, const uint8_t *buf, int len)
+static void put_buffer(const uint8_t *buf, int len)
{
#ifdef CONFIG_USER_ONLY
int ret;
while (len > 0) {
- ret = send(s->fd, buf, len, 0);
+ ret = send(gdbserver_state.fd, buf, len, 0);
if (ret < 0) {
if (errno != EINTR)
return;
#else
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(&s->chr, buf, len);
+ qemu_chr_fe_write_all(&gdbserver_state.chr, buf, len);
#endif
}
}
/* writes 2*len+1 bytes in buf */
-static void memtohex(char *buf, const uint8_t *mem, int len)
+static void memtohex(GString *buf, const uint8_t *mem, int len)
{
int i, c;
- char *q;
- q = buf;
for(i = 0; i < len; i++) {
c = mem[i];
- *q++ = tohex(c >> 4);
- *q++ = tohex(c & 0xf);
+ g_string_append_c(buf, tohex(c >> 4));
+ g_string_append_c(buf, tohex(c & 0xf));
}
- *q = '\0';
+ g_string_append_c(buf, '\0');
}
-static void hextomem(uint8_t *mem, const char *buf, int len)
+static void hextomem(GByteArray *mem, const char *buf, int len)
{
int i;
for(i = 0; i < len; i++) {
- mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]);
+ guint8 byte = fromhex(buf[0]) << 4 | fromhex(buf[1]);
+ g_byte_array_append(mem, &byte, 1);
buf += 2;
}
}
}
/* return -1 if error, 0 if OK */
-static int put_packet_binary(GDBState *s, const char *buf, int len, bool dump)
+static int put_packet_binary(const char *buf, int len, bool dump)
{
int csum, i;
- uint8_t *p;
+ uint8_t footer[3];
if (dump && trace_event_get_state_backends(TRACE_GDBSTUB_IO_BINARYREPLY)) {
hexdump(buf, len, trace_gdbstub_io_binaryreply);
}
for(;;) {
- p = s->last_packet;
- *(p++) = '$';
- memcpy(p, buf, len);
- p += len;
+ g_byte_array_set_size(gdbserver_state.last_packet, 0);
+ g_byte_array_append(gdbserver_state.last_packet,
+ (const uint8_t *) "$", 1);
+ g_byte_array_append(gdbserver_state.last_packet,
+ (const uint8_t *) buf, len);
csum = 0;
for(i = 0; i < len; i++) {
csum += buf[i];
}
- *(p++) = '#';
- *(p++) = tohex((csum >> 4) & 0xf);
- *(p++) = tohex((csum) & 0xf);
+ footer[0] = '#';
+ footer[1] = tohex((csum >> 4) & 0xf);
+ footer[2] = tohex((csum) & 0xf);
+ g_byte_array_append(gdbserver_state.last_packet, footer, 3);
- s->last_packet_len = p - s->last_packet;
- put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len);
+ put_buffer(gdbserver_state.last_packet->data,
+ gdbserver_state.last_packet->len);
#ifdef CONFIG_USER_ONLY
- i = get_char(s);
+ i = get_char();
if (i < 0)
return -1;
if (i == '+')
}
/* return -1 if error, 0 if OK */
-static int put_packet(GDBState *s, const char *buf)
+static int put_packet(const char *buf)
{
trace_gdbstub_io_reply(buf);
- return put_packet_binary(s, buf, strlen(buf), false);
+ return put_packet_binary(buf, strlen(buf), false);
+}
+
+static void put_strbuf(void)
+{
+ put_packet(gdbserver_state.str_buf->str);
}
/* Encode data using the encoding for 'x' packets. */
-static int memtox(char *buf, const char *mem, int len)
+static void memtox(GString *buf, const char *mem, int len)
{
- char *p = buf;
char c;
while (len--) {
c = *(mem++);
switch (c) {
case '#': case '$': case '*': case '}':
- *(p++) = '}';
- *(p++) = c ^ 0x20;
+ g_string_append_c(buf, '}');
+ g_string_append_c(buf, c ^ 0x20);
break;
default:
- *(p++) = c;
+ g_string_append_c(buf, c);
break;
}
}
- return p - buf;
}
-static uint32_t gdb_get_cpu_pid(const GDBState *s, CPUState *cpu)
+static uint32_t gdb_get_cpu_pid(CPUState *cpu)
{
/* TODO: In user mode, we should use the task state PID */
if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
/* Return the default process' PID */
- return s->processes[s->process_num - 1].pid;
+ int index = gdbserver_state.process_num - 1;
+ return gdbserver_state.processes[index].pid;
}
return cpu->cluster_index + 1;
}
-static GDBProcess *gdb_get_process(const GDBState *s, uint32_t pid)
+static GDBProcess *gdb_get_process(uint32_t pid)
{
int i;
if (!pid) {
/* 0 means any process, we take the first one */
- return &s->processes[0];
+ return &gdbserver_state.processes[0];
}
- for (i = 0; i < s->process_num; i++) {
- if (s->processes[i].pid == pid) {
- return &s->processes[i];
+ for (i = 0; i < gdbserver_state.process_num; i++) {
+ if (gdbserver_state.processes[i].pid == pid) {
+ return &gdbserver_state.processes[i];
}
}
return NULL;
}
-static GDBProcess *gdb_get_cpu_process(const GDBState *s, CPUState *cpu)
+static GDBProcess *gdb_get_cpu_process(CPUState *cpu)
{
- return gdb_get_process(s, gdb_get_cpu_pid(s, cpu));
+ return gdb_get_process(gdb_get_cpu_pid(cpu));
}
static CPUState *find_cpu(uint32_t thread_id)
return NULL;
}
-static CPUState *get_first_cpu_in_process(const GDBState *s,
- GDBProcess *process)
+static CPUState *get_first_cpu_in_process(GDBProcess *process)
{
CPUState *cpu;
CPU_FOREACH(cpu) {
- if (gdb_get_cpu_pid(s, cpu) == process->pid) {
+ if (gdb_get_cpu_pid(cpu) == process->pid) {
return cpu;
}
}
return NULL;
}
-static CPUState *gdb_next_cpu_in_process(const GDBState *s, CPUState *cpu)
+static CPUState *gdb_next_cpu_in_process(CPUState *cpu)
{
- uint32_t pid = gdb_get_cpu_pid(s, cpu);
+ uint32_t pid = gdb_get_cpu_pid(cpu);
cpu = CPU_NEXT(cpu);
while (cpu) {
- if (gdb_get_cpu_pid(s, cpu) == pid) {
+ if (gdb_get_cpu_pid(cpu) == pid) {
break;
}
}
/* Return the cpu following @cpu, while ignoring unattached processes. */
-static CPUState *gdb_next_attached_cpu(const GDBState *s, CPUState *cpu)
+static CPUState *gdb_next_attached_cpu(CPUState *cpu)
{
cpu = CPU_NEXT(cpu);
while (cpu) {
- if (gdb_get_cpu_process(s, cpu)->attached) {
+ if (gdb_get_cpu_process(cpu)->attached) {
break;
}
}
/* Return the first attached cpu */
-static CPUState *gdb_first_attached_cpu(const GDBState *s)
+static CPUState *gdb_first_attached_cpu(void)
{
CPUState *cpu = first_cpu;
- GDBProcess *process = gdb_get_cpu_process(s, cpu);
+ GDBProcess *process = gdb_get_cpu_process(cpu);
if (!process->attached) {
- return gdb_next_attached_cpu(s, cpu);
+ return gdb_next_attached_cpu(cpu);
}
return cpu;
}
-static CPUState *gdb_get_cpu(const GDBState *s, uint32_t pid, uint32_t tid)
+static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid)
{
GDBProcess *process;
CPUState *cpu;
if (!pid && !tid) {
/* 0 means any process/thread, we take the first attached one */
- return gdb_first_attached_cpu(s);
+ return gdb_first_attached_cpu();
} else if (pid && !tid) {
/* any thread in a specific process */
- process = gdb_get_process(s, pid);
+ process = gdb_get_process(pid);
if (process == NULL) {
return NULL;
return NULL;
}
- return get_first_cpu_in_process(s, process);
+ return get_first_cpu_in_process(process);
} else {
/* a specific thread */
cpu = find_cpu(tid);
return NULL;
}
- process = gdb_get_cpu_process(s, cpu);
+ process = gdb_get_cpu_process(cpu);
if (pid && process->pid != pid) {
return NULL;
}
}
-static const char *get_feature_xml(const GDBState *s, const char *p,
- const char **newp, GDBProcess *process)
+static const char *get_feature_xml(const char *p, const char **newp,
+ GDBProcess *process)
{
size_t len;
int i;
const char *name;
- CPUState *cpu = get_first_cpu_in_process(s, process);
+ CPUState *cpu = get_first_cpu_in_process(process);
CPUClass *cc = CPU_GET_CLASS(cpu);
len = 0;
return name ? xml_builtin[i][1] : NULL;
}
-static int gdb_read_register(CPUState *cpu, uint8_t *mem_buf, int reg)
+static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
CPUArchState *env = cpu->env_ptr;
GDBRegisterState *r;
if (reg < cc->gdb_num_core_regs) {
- return cc->gdb_read_register(cpu, mem_buf, reg);
+ return cc->gdb_read_register(cpu, buf, reg);
}
for (r = cpu->gdb_regs; r; r = r->next) {
if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
- return r->get_reg(env, mem_buf, reg - r->base_reg);
+ return r->get_reg(env, buf, reg - r->base_reg);
}
}
return 0;
*/
void gdb_register_coprocessor(CPUState *cpu,
- gdb_reg_cb get_reg, gdb_reg_cb set_reg,
+ gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
int num_regs, const char *xml, int g_pos)
{
GDBRegisterState *s;
int err = 0;
if (kvm_enabled()) {
- return kvm_insert_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+ return kvm_insert_breakpoint(gdbserver_state.c_cpu, addr, len, type);
}
switch (type) {
int err = 0;
if (kvm_enabled()) {
- return kvm_remove_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+ return kvm_remove_breakpoint(gdbserver_state.c_cpu, addr, len, type);
}
switch (type) {
#endif
}
-static void gdb_process_breakpoint_remove_all(const GDBState *s, GDBProcess *p)
+static void gdb_process_breakpoint_remove_all(GDBProcess *p)
{
- CPUState *cpu = get_first_cpu_in_process(s, p);
+ CPUState *cpu = get_first_cpu_in_process(p);
while (cpu) {
gdb_cpu_breakpoint_remove_all(cpu);
- cpu = gdb_next_cpu_in_process(s, cpu);
+ cpu = gdb_next_cpu_in_process(cpu);
}
}
CPUState *cpu;
if (kvm_enabled()) {
- kvm_remove_all_breakpoints(gdbserver_state->c_cpu);
+ kvm_remove_all_breakpoints(gdbserver_state.c_cpu);
return;
}
}
}
-static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
+static void gdb_set_cpu_pc(target_ulong pc)
{
- CPUState *cpu = s->c_cpu;
+ CPUState *cpu = gdbserver_state.c_cpu;
cpu_synchronize_state(cpu);
cpu_set_pc(cpu, pc);
}
-static char *gdb_fmt_thread_id(const GDBState *s, CPUState *cpu,
- char *buf, size_t buf_size)
+static void gdb_append_thread_id(CPUState *cpu, GString *buf)
{
- if (s->multiprocess) {
- snprintf(buf, buf_size, "p%02x.%02x",
- gdb_get_cpu_pid(s, cpu), cpu_gdb_index(cpu));
+ if (gdbserver_state.multiprocess) {
+ g_string_append_printf(buf, "p%02x.%02x",
+ gdb_get_cpu_pid(cpu), cpu_gdb_index(cpu));
} else {
- snprintf(buf, buf_size, "%02x", cpu_gdb_index(cpu));
+ g_string_append_printf(buf, "%02x", cpu_gdb_index(cpu));
}
-
- return buf;
}
typedef enum GDBThreadIdKind {
* returns -ENOTSUP if a command is unsupported, -EINVAL or -ERANGE if there is
* a format error, 0 on success.
*/
-static int gdb_handle_vcont(GDBState *s, const char *p)
+static int gdb_handle_vcont(const char *p)
{
int res, signal = 0;
char cur_action;
goto out;
case GDB_ALL_PROCESSES:
- cpu = gdb_first_attached_cpu(s);
+ cpu = gdb_first_attached_cpu();
while (cpu) {
if (newstates[cpu->cpu_index] == 1) {
newstates[cpu->cpu_index] = cur_action;
}
- cpu = gdb_next_attached_cpu(s, cpu);
+ cpu = gdb_next_attached_cpu(cpu);
}
break;
case GDB_ALL_THREADS:
- process = gdb_get_process(s, pid);
+ process = gdb_get_process(pid);
if (!process->attached) {
res = -EINVAL;
goto out;
}
- cpu = get_first_cpu_in_process(s, process);
+ cpu = get_first_cpu_in_process(process);
while (cpu) {
if (newstates[cpu->cpu_index] == 1) {
newstates[cpu->cpu_index] = cur_action;
}
- cpu = gdb_next_cpu_in_process(s, cpu);
+ cpu = gdb_next_cpu_in_process(cpu);
}
break;
case GDB_ONE_THREAD:
- cpu = gdb_get_cpu(s, pid, tid);
+ cpu = gdb_get_cpu(pid, tid);
/* invalid CPU/thread specified */
if (!cpu) {
break;
}
}
- s->signal = signal;
- gdb_continue_partial(s, newstates);
+ gdbserver_state.signal = signal;
+ gdb_continue_partial(newstates);
out:
g_free(newstates);
}
typedef struct GdbCmdContext {
- GDBState *s;
GdbCmdVariant *params;
int num_params;
- uint8_t mem_buf[MAX_PACKET_LENGTH];
- char str_buf[MAX_PACKET_LENGTH + 1];
} GdbCmdContext;
typedef void (*GdbCmdHandler)(GdbCmdContext *gdb_ctx, void *user_ctx);
return !strncmp(string, pattern, strlen(pattern));
}
-static int process_string_cmd(GDBState *s, void *user_ctx, const char *data,
+static int process_string_cmd(void *user_ctx, const char *data,
const GdbCmdParseEntry *cmds, int num_cmds)
{
int i, schema_len, max_num_params = 0;
return -1;
}
- gdb_ctx.s = s;
cmd->handler(&gdb_ctx, user_ctx);
return 0;
}
return -1;
}
-static void run_cmd_parser(GDBState *s, const char *data,
- const GdbCmdParseEntry *cmd)
+static void run_cmd_parser(const char *data, const GdbCmdParseEntry *cmd)
{
if (!data) {
return;
}
+ g_string_set_size(gdbserver_state.str_buf, 0);
+ g_byte_array_set_size(gdbserver_state.mem_buf, 0);
+
/* In case there was an error during the command parsing we must
* send a NULL packet to indicate the command is not supported */
- if (process_string_cmd(s, NULL, data, cmd, 1)) {
- put_packet(s, "");
+ if (process_string_cmd(NULL, data, cmd, 1)) {
+ put_packet("");
}
}
static void handle_detach(GdbCmdContext *gdb_ctx, void *user_ctx)
{
GDBProcess *process;
- GDBState *s = gdb_ctx->s;
uint32_t pid = 1;
- if (s->multiprocess) {
+ if (gdbserver_state.multiprocess) {
if (!gdb_ctx->num_params) {
- put_packet(s, "E22");
+ put_packet("E22");
return;
}
pid = gdb_ctx->params[0].val_ul;
}
- process = gdb_get_process(s, pid);
- gdb_process_breakpoint_remove_all(s, process);
+ process = gdb_get_process(pid);
+ gdb_process_breakpoint_remove_all(process);
process->attached = false;
- if (pid == gdb_get_cpu_pid(s, s->c_cpu)) {
- s->c_cpu = gdb_first_attached_cpu(s);
+ if (pid == gdb_get_cpu_pid(gdbserver_state.c_cpu)) {
+ gdbserver_state.c_cpu = gdb_first_attached_cpu();
}
- if (pid == gdb_get_cpu_pid(s, s->g_cpu)) {
- s->g_cpu = gdb_first_attached_cpu(s);
+ if (pid == gdb_get_cpu_pid(gdbserver_state.g_cpu)) {
+ gdbserver_state.g_cpu = gdb_first_attached_cpu();
}
- if (!s->c_cpu) {
+ if (!gdbserver_state.c_cpu) {
/* No more process attached */
gdb_syscall_mode = GDB_SYS_DISABLED;
- gdb_continue(s);
+ gdb_continue();
}
- put_packet(s, "OK");
+ put_packet("OK");
}
static void handle_thread_alive(GdbCmdContext *gdb_ctx, void *user_ctx)
CPUState *cpu;
if (!gdb_ctx->num_params) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
if (gdb_ctx->params[0].thread_id.kind == GDB_READ_THREAD_ERR) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
- cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[0].thread_id.pid,
+ cpu = gdb_get_cpu(gdb_ctx->params[0].thread_id.pid,
gdb_ctx->params[0].thread_id.tid);
if (!cpu) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
}
static void handle_continue(GdbCmdContext *gdb_ctx, void *user_ctx)
{
if (gdb_ctx->num_params) {
- gdb_set_cpu_pc(gdb_ctx->s, gdb_ctx->params[0].val_ull);
+ gdb_set_cpu_pc(gdb_ctx->params[0].val_ull);
}
- gdb_ctx->s->signal = 0;
- gdb_continue(gdb_ctx->s);
+ gdbserver_state.signal = 0;
+ gdb_continue();
}
static void handle_cont_with_sig(GdbCmdContext *gdb_ctx, void *user_ctx)
signal = gdb_ctx->params[0].val_ul;
}
- gdb_ctx->s->signal = gdb_signal_to_target(signal);
- if (gdb_ctx->s->signal == -1) {
- gdb_ctx->s->signal = 0;
+ gdbserver_state.signal = gdb_signal_to_target(signal);
+ if (gdbserver_state.signal == -1) {
+ gdbserver_state.signal = 0;
}
- gdb_continue(gdb_ctx->s);
+ gdb_continue();
}
static void handle_set_thread(GdbCmdContext *gdb_ctx, void *user_ctx)
CPUState *cpu;
if (gdb_ctx->num_params != 2) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
if (gdb_ctx->params[1].thread_id.kind == GDB_READ_THREAD_ERR) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
if (gdb_ctx->params[1].thread_id.kind != GDB_ONE_THREAD) {
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
return;
}
- cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[1].thread_id.pid,
+ cpu = gdb_get_cpu(gdb_ctx->params[1].thread_id.pid,
gdb_ctx->params[1].thread_id.tid);
if (!cpu) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
*/
switch (gdb_ctx->params[0].opcode) {
case 'c':
- gdb_ctx->s->c_cpu = cpu;
- put_packet(gdb_ctx->s, "OK");
+ gdbserver_state.c_cpu = cpu;
+ put_packet("OK");
break;
case 'g':
- gdb_ctx->s->g_cpu = cpu;
- put_packet(gdb_ctx->s, "OK");
+ gdbserver_state.g_cpu = cpu;
+ put_packet("OK");
break;
default:
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
break;
}
}
int res;
if (gdb_ctx->num_params != 3) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
gdb_ctx->params[1].val_ull,
gdb_ctx->params[2].val_ull);
if (res >= 0) {
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
return;
} else if (res == -ENOSYS) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
return;
}
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
}
static void handle_remove_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
int res;
if (gdb_ctx->num_params != 3) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
gdb_ctx->params[1].val_ull,
gdb_ctx->params[2].val_ull);
if (res >= 0) {
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
return;
} else if (res == -ENOSYS) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
return;
}
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
}
/*
int reg_size;
if (!gdb_has_xml) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
return;
}
if (gdb_ctx->num_params != 2) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
reg_size = strlen(gdb_ctx->params[1].data) / 2;
- hextomem(gdb_ctx->mem_buf, gdb_ctx->params[1].data, reg_size);
- gdb_write_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf,
+ hextomem(gdbserver_state.mem_buf, gdb_ctx->params[1].data, reg_size);
+ gdb_write_register(gdbserver_state.g_cpu, gdbserver_state.mem_buf->data,
gdb_ctx->params[0].val_ull);
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
}
static void handle_get_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
int reg_size;
if (!gdb_has_xml) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
return;
}
if (!gdb_ctx->num_params) {
- put_packet(gdb_ctx->s, "E14");
+ put_packet("E14");
return;
}
- reg_size = gdb_read_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf,
+ reg_size = gdb_read_register(gdbserver_state.g_cpu,
+ gdbserver_state.mem_buf,
gdb_ctx->params[0].val_ull);
if (!reg_size) {
- put_packet(gdb_ctx->s, "E14");
+ put_packet("E14");
return;
+ } else {
+ g_byte_array_set_size(gdbserver_state.mem_buf, reg_size);
}
- memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, reg_size);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, reg_size);
+ put_strbuf();
}
static void handle_write_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
{
if (gdb_ctx->num_params != 3) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
/* hextomem() reads 2*len bytes */
if (gdb_ctx->params[1].val_ull > strlen(gdb_ctx->params[2].data) / 2) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
- hextomem(gdb_ctx->mem_buf, gdb_ctx->params[2].data,
+ hextomem(gdbserver_state.mem_buf, gdb_ctx->params[2].data,
gdb_ctx->params[1].val_ull);
- if (target_memory_rw_debug(gdb_ctx->s->g_cpu, gdb_ctx->params[0].val_ull,
- gdb_ctx->mem_buf,
- gdb_ctx->params[1].val_ull, true)) {
- put_packet(gdb_ctx->s, "E14");
+ if (target_memory_rw_debug(gdbserver_state.g_cpu, gdb_ctx->params[0].val_ull,
+ gdbserver_state.mem_buf->data,
+ gdbserver_state.mem_buf->len, true)) {
+ put_packet("E14");
return;
}
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
}
static void handle_read_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
{
if (gdb_ctx->num_params != 2) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
/* memtohex() doubles the required space */
if (gdb_ctx->params[1].val_ull > MAX_PACKET_LENGTH / 2) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
- if (target_memory_rw_debug(gdb_ctx->s->g_cpu, gdb_ctx->params[0].val_ull,
- gdb_ctx->mem_buf,
- gdb_ctx->params[1].val_ull, false)) {
- put_packet(gdb_ctx->s, "E14");
+ g_byte_array_set_size(gdbserver_state.mem_buf, gdb_ctx->params[1].val_ull);
+
+ if (target_memory_rw_debug(gdbserver_state.g_cpu, gdb_ctx->params[0].val_ull,
+ gdbserver_state.mem_buf->data,
+ gdbserver_state.mem_buf->len, false)) {
+ put_packet("E14");
return;
}
- memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, gdb_ctx->params[1].val_ull);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data,
+ gdbserver_state.mem_buf->len);
+ put_strbuf();
}
static void handle_write_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
return;
}
- cpu_synchronize_state(gdb_ctx->s->g_cpu);
- registers = gdb_ctx->mem_buf;
+ cpu_synchronize_state(gdbserver_state.g_cpu);
len = strlen(gdb_ctx->params[0].data) / 2;
- hextomem(registers, gdb_ctx->params[0].data, len);
- for (addr = 0; addr < gdb_ctx->s->g_cpu->gdb_num_g_regs && len > 0;
+ hextomem(gdbserver_state.mem_buf, gdb_ctx->params[0].data, len);
+ registers = gdbserver_state.mem_buf->data;
+ for (addr = 0; addr < gdbserver_state.g_cpu->gdb_num_g_regs && len > 0;
addr++) {
- reg_size = gdb_write_register(gdb_ctx->s->g_cpu, registers, addr);
+ reg_size = gdb_write_register(gdbserver_state.g_cpu, registers, addr);
len -= reg_size;
registers += reg_size;
}
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
}
static void handle_read_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
{
target_ulong addr, len;
- cpu_synchronize_state(gdb_ctx->s->g_cpu);
+ cpu_synchronize_state(gdbserver_state.g_cpu);
+ g_byte_array_set_size(gdbserver_state.mem_buf, 0);
len = 0;
- for (addr = 0; addr < gdb_ctx->s->g_cpu->gdb_num_g_regs; addr++) {
- len += gdb_read_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf + len,
+ for (addr = 0; addr < gdbserver_state.g_cpu->gdb_num_g_regs; addr++) {
+ len += gdb_read_register(gdbserver_state.g_cpu,
+ gdbserver_state.mem_buf,
addr);
}
+ g_assert(len == gdbserver_state.mem_buf->len);
- memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, len);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, len);
+ put_strbuf();
}
static void handle_file_io(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- if (gdb_ctx->num_params >= 1 && gdb_ctx->s->current_syscall_cb) {
+ if (gdb_ctx->num_params >= 1 && gdbserver_state.current_syscall_cb) {
target_ulong ret, err;
ret = (target_ulong)gdb_ctx->params[0].val_ull;
} else {
err = 0;
}
- gdb_ctx->s->current_syscall_cb(gdb_ctx->s->c_cpu, ret, err);
- gdb_ctx->s->current_syscall_cb = NULL;
+ gdbserver_state.current_syscall_cb(gdbserver_state.c_cpu, ret, err);
+ gdbserver_state.current_syscall_cb = NULL;
}
if (gdb_ctx->num_params >= 3 && gdb_ctx->params[2].opcode == (uint8_t)'C') {
- put_packet(gdb_ctx->s, "T02");
+ put_packet("T02");
return;
}
- gdb_continue(gdb_ctx->s);
+ gdb_continue();
}
static void handle_step(GdbCmdContext *gdb_ctx, void *user_ctx)
{
if (gdb_ctx->num_params) {
- gdb_set_cpu_pc(gdb_ctx->s, (target_ulong)gdb_ctx->params[0].val_ull);
+ gdb_set_cpu_pc((target_ulong)gdb_ctx->params[0].val_ull);
}
- cpu_single_step(gdb_ctx->s->c_cpu, sstep_flags);
- gdb_continue(gdb_ctx->s);
+ cpu_single_step(gdbserver_state.c_cpu, sstep_flags);
+ gdb_continue();
}
static void handle_v_cont_query(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- put_packet(gdb_ctx->s, "vCont;c;C;s;S");
+ put_packet("vCont;c;C;s;S");
}
static void handle_v_cont(GdbCmdContext *gdb_ctx, void *user_ctx)
return;
}
- res = gdb_handle_vcont(gdb_ctx->s, gdb_ctx->params[0].data);
+ res = gdb_handle_vcont(gdb_ctx->params[0].data);
if ((res == -EINVAL) || (res == -ERANGE)) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
} else if (res) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
}
}
{
GDBProcess *process;
CPUState *cpu;
- char thread_id[16];
- pstrcpy(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "E22");
+ g_string_assign(gdbserver_state.str_buf, "E22");
if (!gdb_ctx->num_params) {
goto cleanup;
}
- process = gdb_get_process(gdb_ctx->s, gdb_ctx->params[0].val_ul);
+ process = gdb_get_process(gdb_ctx->params[0].val_ul);
if (!process) {
goto cleanup;
}
- cpu = get_first_cpu_in_process(gdb_ctx->s, process);
+ cpu = get_first_cpu_in_process(process);
if (!cpu) {
goto cleanup;
}
process->attached = true;
- gdb_ctx->s->g_cpu = cpu;
- gdb_ctx->s->c_cpu = cpu;
+ gdbserver_state.g_cpu = cpu;
+ gdbserver_state.c_cpu = cpu;
- gdb_fmt_thread_id(gdb_ctx->s, cpu, thread_id, sizeof(thread_id));
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "T%02xthread:%s;",
- GDB_SIGNAL_TRAP, thread_id);
+ g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
+ gdb_append_thread_id(cpu, gdbserver_state.str_buf);
+ g_string_append_c(gdbserver_state.str_buf, ';');
cleanup:
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ put_strbuf();
}
static void handle_v_kill(GdbCmdContext *gdb_ctx, void *user_ctx)
{
/* Kill the target */
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
error_report("QEMU: Terminated via GDBstub");
exit(0);
}
return;
}
- if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ if (process_string_cmd(NULL, gdb_ctx->params[0].data,
gdb_v_commands_table,
ARRAY_SIZE(gdb_v_commands_table))) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
}
}
static void handle_query_qemu_sstepbits(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
- "ENABLE=%x,NOIRQ=%x,NOTIMER=%x", SSTEP_ENABLE,
- SSTEP_NOIRQ, SSTEP_NOTIMER);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ g_string_printf(gdbserver_state.str_buf, "ENABLE=%x,NOIRQ=%x,NOTIMER=%x",
+ SSTEP_ENABLE, SSTEP_NOIRQ, SSTEP_NOTIMER);
+ put_strbuf();
}
static void handle_set_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
}
sstep_flags = gdb_ctx->params[0].val_ul;
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
}
static void handle_query_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "0x%x", sstep_flags);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ g_string_printf(gdbserver_state.str_buf, "0x%x", sstep_flags);
+ put_strbuf();
}
static void handle_query_curr_tid(GdbCmdContext *gdb_ctx, void *user_ctx)
{
CPUState *cpu;
GDBProcess *process;
- char thread_id[16];
/*
* "Current thread" remains vague in the spec, so always return
* the first thread of the current process (gdb returns the
* first thread).
*/
- process = gdb_get_cpu_process(gdb_ctx->s, gdb_ctx->s->g_cpu);
- cpu = get_first_cpu_in_process(gdb_ctx->s, process);
- gdb_fmt_thread_id(gdb_ctx->s, cpu, thread_id, sizeof(thread_id));
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "QC%s", thread_id);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ process = gdb_get_cpu_process(gdbserver_state.g_cpu);
+ cpu = get_first_cpu_in_process(process);
+ g_string_assign(gdbserver_state.str_buf, "QC");
+ gdb_append_thread_id(cpu, gdbserver_state.str_buf);
+ put_strbuf();
}
static void handle_query_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- char thread_id[16];
-
- if (!gdb_ctx->s->query_cpu) {
- put_packet(gdb_ctx->s, "l");
+ if (!gdbserver_state.query_cpu) {
+ put_packet("l");
return;
}
- gdb_fmt_thread_id(gdb_ctx->s, gdb_ctx->s->query_cpu, thread_id,
- sizeof(thread_id));
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "m%s", thread_id);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
- gdb_ctx->s->query_cpu =
- gdb_next_attached_cpu(gdb_ctx->s, gdb_ctx->s->query_cpu);
+ g_string_assign(gdbserver_state.str_buf, "m");
+ gdb_append_thread_id(gdbserver_state.query_cpu, gdbserver_state.str_buf);
+ put_strbuf();
+ gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu);
}
static void handle_query_first_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- gdb_ctx->s->query_cpu = gdb_first_attached_cpu(gdb_ctx->s);
+ gdbserver_state.query_cpu = gdb_first_attached_cpu();
handle_query_threads(gdb_ctx, user_ctx);
}
static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx)
{
+ g_autoptr(GString) rs = g_string_new(NULL);
CPUState *cpu;
- int len;
if (!gdb_ctx->num_params ||
gdb_ctx->params[0].thread_id.kind == GDB_READ_THREAD_ERR) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
- cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[0].thread_id.pid,
+ cpu = gdb_get_cpu(gdb_ctx->params[0].thread_id.pid,
gdb_ctx->params[0].thread_id.tid);
if (!cpu) {
return;
cpu_synchronize_state(cpu);
- if (gdb_ctx->s->multiprocess && (gdb_ctx->s->process_num > 1)) {
+ if (gdbserver_state.multiprocess && (gdbserver_state.process_num > 1)) {
/* Print the CPU model and name in multiprocess mode */
ObjectClass *oc = object_get_class(OBJECT(cpu));
const char *cpu_model = object_class_get_name(oc);
- char *cpu_name = object_get_canonical_path_component(OBJECT(cpu));
- len = snprintf((char *)gdb_ctx->mem_buf, sizeof(gdb_ctx->str_buf) / 2,
- "%s %s [%s]", cpu_model, cpu_name,
- cpu->halted ? "halted " : "running");
- g_free(cpu_name);
+ g_autofree char *cpu_name;
+ cpu_name = object_get_canonical_path_component(OBJECT(cpu));
+ g_string_printf(rs, "%s %s [%s]", cpu_model, cpu_name,
+ cpu->halted ? "halted " : "running");
} else {
- /* memtohex() doubles the required space */
- len = snprintf((char *)gdb_ctx->mem_buf, sizeof(gdb_ctx->str_buf) / 2,
- "CPU#%d [%s]", cpu->cpu_index,
+ g_string_printf(rs, "CPU#%d [%s]", cpu->cpu_index,
cpu->halted ? "halted " : "running");
}
- trace_gdbstub_op_extra_info((char *)gdb_ctx->mem_buf);
- memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, len);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ trace_gdbstub_op_extra_info(rs->str);
+ memtohex(gdbserver_state.str_buf, (uint8_t *)rs->str, rs->len);
+ put_strbuf();
}
#ifdef CONFIG_USER_ONLY
{
TaskState *ts;
- ts = gdb_ctx->s->c_cpu->opaque;
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
- "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx
- ";Bss=" TARGET_ABI_FMT_lx,
- ts->info->code_offset,
- ts->info->data_offset,
- ts->info->data_offset);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ ts = gdbserver_state.c_cpu->opaque;
+ g_string_printf(gdbserver_state.str_buf,
+ "Text=" TARGET_ABI_FMT_lx
+ ";Data=" TARGET_ABI_FMT_lx
+ ";Bss=" TARGET_ABI_FMT_lx,
+ ts->info->code_offset,
+ ts->info->data_offset,
+ ts->info->data_offset);
+ put_strbuf();
}
#else
static void handle_query_rcmd(GdbCmdContext *gdb_ctx, void *user_ctx)
{
+ const guint8 zero = 0;
int len;
if (!gdb_ctx->num_params) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
len = strlen(gdb_ctx->params[0].data);
if (len % 2) {
- put_packet(gdb_ctx->s, "E01");
+ put_packet("E01");
return;
}
+ g_assert(gdbserver_state.mem_buf->len == 0);
len = len / 2;
- hextomem(gdb_ctx->mem_buf, gdb_ctx->params[0].data, len);
- gdb_ctx->mem_buf[len++] = 0;
- qemu_chr_be_write(gdb_ctx->s->mon_chr, gdb_ctx->mem_buf, len);
- put_packet(gdb_ctx->s, "OK");
-
+ hextomem(gdbserver_state.mem_buf, gdb_ctx->params[0].data, len);
+ g_byte_array_append(gdbserver_state.mem_buf, &zero, 1);
+ qemu_chr_be_write(gdbserver_state.mon_chr, gdbserver_state.mem_buf->data,
+ gdbserver_state.mem_buf->len);
+ put_packet("OK");
}
#endif
{
CPUClass *cc;
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "PacketSize=%x",
- MAX_PACKET_LENGTH);
+ g_string_printf(gdbserver_state.str_buf, "PacketSize=%x", MAX_PACKET_LENGTH);
cc = CPU_GET_CLASS(first_cpu);
if (cc->gdb_core_xml_file) {
- pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
- ";qXfer:features:read+");
+ g_string_append(gdbserver_state.str_buf, ";qXfer:features:read+");
}
if (gdb_ctx->num_params &&
strstr(gdb_ctx->params[0].data, "multiprocess+")) {
- gdb_ctx->s->multiprocess = true;
+ gdbserver_state.multiprocess = true;
}
- pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), ";multiprocess+");
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+");
+ put_strbuf();
}
static void handle_query_xfer_features(GdbCmdContext *gdb_ctx, void *user_ctx)
const char *p;
if (gdb_ctx->num_params < 3) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
- process = gdb_get_cpu_process(gdb_ctx->s, gdb_ctx->s->g_cpu);
- cc = CPU_GET_CLASS(gdb_ctx->s->g_cpu);
+ process = gdb_get_cpu_process(gdbserver_state.g_cpu);
+ cc = CPU_GET_CLASS(gdbserver_state.g_cpu);
if (!cc->gdb_core_xml_file) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
return;
}
gdb_has_xml = true;
p = gdb_ctx->params[0].data;
- xml = get_feature_xml(gdb_ctx->s, p, &p, process);
+ xml = get_feature_xml(p, &p, process);
if (!xml) {
- put_packet(gdb_ctx->s, "E00");
+ put_packet("E00");
return;
}
len = gdb_ctx->params[2].val_ul;
total_len = strlen(xml);
if (addr > total_len) {
- put_packet(gdb_ctx->s, "E00");
+ put_packet("E00");
return;
}
}
if (len < total_len - addr) {
- gdb_ctx->str_buf[0] = 'm';
- len = memtox(gdb_ctx->str_buf + 1, xml + addr, len);
+ g_string_assign(gdbserver_state.str_buf, "m");
+ memtox(gdbserver_state.str_buf, xml + addr, len);
} else {
- gdb_ctx->str_buf[0] = 'l';
- len = memtox(gdb_ctx->str_buf + 1, xml + addr, total_len - addr);
+ g_string_assign(gdbserver_state.str_buf, "l");
+ memtox(gdbserver_state.str_buf, xml + addr, total_len - addr);
}
- put_packet_binary(gdb_ctx->s, gdb_ctx->str_buf, len + 1, true);
+ put_packet_binary(gdbserver_state.str_buf->str,
+ gdbserver_state.str_buf->len, true);
}
static void handle_query_attached(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- put_packet(gdb_ctx->s, GDB_ATTACHED);
+ put_packet(GDB_ATTACHED);
}
static void handle_query_qemu_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "sstepbits;sstep");
+ g_string_printf(gdbserver_state.str_buf, "sstepbits;sstep");
#ifndef CONFIG_USER_ONLY
- pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), ";PhyMemMode");
+ g_string_append(gdbserver_state.str_buf, ";PhyMemMode");
#endif
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ put_strbuf();
}
#ifndef CONFIG_USER_ONLY
static void handle_query_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx,
void *user_ctx)
{
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "%d", phy_memory_mode);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ g_string_printf(gdbserver_state.str_buf, "%d", phy_memory_mode);
+ put_strbuf();
}
static void handle_set_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx, void *user_ctx)
{
if (!gdb_ctx->num_params) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
} else {
phy_memory_mode = 1;
}
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
}
#endif
return;
}
- if (!process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ if (!process_string_cmd(NULL, gdb_ctx->params[0].data,
gdb_gen_query_set_common_table,
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
return;
}
- if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ if (process_string_cmd(NULL, gdb_ctx->params[0].data,
gdb_gen_query_table,
ARRAY_SIZE(gdb_gen_query_table))) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
}
}
return;
}
- if (!process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ if (!process_string_cmd(NULL, gdb_ctx->params[0].data,
gdb_gen_query_set_common_table,
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
return;
}
- if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ if (process_string_cmd(NULL, gdb_ctx->params[0].data,
gdb_gen_set_table,
ARRAY_SIZE(gdb_gen_set_table))) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
}
}
static void handle_target_halt(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- char thread_id[16];
-
- gdb_fmt_thread_id(gdb_ctx->s, gdb_ctx->s->c_cpu, thread_id,
- sizeof(thread_id));
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "T%02xthread:%s;",
- GDB_SIGNAL_TRAP, thread_id);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
+ gdb_append_thread_id(gdbserver_state.c_cpu, gdbserver_state.str_buf);
+ g_string_append_c(gdbserver_state.str_buf, ';');
+ put_strbuf();
/*
* Remove all the breakpoints when this query is issued,
* because gdb is doing an initial connect and the state
gdb_breakpoint_remove_all();
}
-static int gdb_handle_packet(GDBState *s, const char *line_buf)
+static int gdb_handle_packet(const char *line_buf)
{
const GdbCmdParseEntry *cmd_parser = NULL;
switch (line_buf[0]) {
case '!':
- put_packet(s, "OK");
+ put_packet("OK");
break;
case '?':
{
break;
default:
/* put empty packet */
- put_packet(s, "");
+ put_packet("");
break;
}
if (cmd_parser) {
- run_cmd_parser(s, line_buf, cmd_parser);
+ run_cmd_parser(line_buf, cmd_parser);
}
return RS_IDLE;
void gdb_set_stop_cpu(CPUState *cpu)
{
- GDBProcess *p = gdb_get_cpu_process(gdbserver_state, cpu);
+ GDBProcess *p = gdb_get_cpu_process(cpu);
if (!p->attached) {
/*
return;
}
- gdbserver_state->c_cpu = cpu;
- gdbserver_state->g_cpu = cpu;
+ gdbserver_state.c_cpu = cpu;
+ gdbserver_state.g_cpu = cpu;
}
#ifndef CONFIG_USER_ONLY
static void gdb_vm_state_change(void *opaque, int running, RunState state)
{
- GDBState *s = gdbserver_state;
- CPUState *cpu = s->c_cpu;
- char buf[256];
- char thread_id[16];
+ CPUState *cpu = gdbserver_state.c_cpu;
+ g_autoptr(GString) buf = g_string_new(NULL);
+ g_autoptr(GString) tid = g_string_new(NULL);
const char *type;
int ret;
- if (running || s->state == RS_INACTIVE) {
+ if (running || gdbserver_state.state == RS_INACTIVE) {
return;
}
/* Is there a GDB syscall waiting to be sent? */
- if (s->current_syscall_cb) {
- put_packet(s, s->syscall_buf);
+ if (gdbserver_state.current_syscall_cb) {
+ put_packet(gdbserver_state.syscall_buf);
return;
}
return;
}
- gdb_fmt_thread_id(s, cpu, thread_id, sizeof(thread_id));
+ gdb_append_thread_id(cpu, tid);
switch (state) {
case RUN_STATE_DEBUG:
}
trace_gdbstub_hit_watchpoint(type, cpu_gdb_index(cpu),
(target_ulong)cpu->watchpoint_hit->vaddr);
- snprintf(buf, sizeof(buf),
- "T%02xthread:%s;%swatch:" TARGET_FMT_lx ";",
- GDB_SIGNAL_TRAP, thread_id, type,
- (target_ulong)cpu->watchpoint_hit->vaddr);
+ g_string_printf(buf, "T%02xthread:%s;%swatch:" TARGET_FMT_lx ";",
+ GDB_SIGNAL_TRAP, tid->str, type,
+ (target_ulong)cpu->watchpoint_hit->vaddr);
cpu->watchpoint_hit = NULL;
goto send_packet;
} else {
break;
}
gdb_set_stop_cpu(cpu);
- snprintf(buf, sizeof(buf), "T%02xthread:%s;", ret, thread_id);
+ g_string_printf(buf, "T%02xthread:%s;", ret, tid->str);
send_packet:
- put_packet(s, buf);
+ put_packet(buf->str);
/* disable single step if it was enabled */
cpu_single_step(cpu, 0);
char *p_end;
target_ulong addr;
uint64_t i64;
- GDBState *s;
- s = gdbserver_state;
- if (!s)
+ if (!gdbserver_state.init) {
return;
- s->current_syscall_cb = cb;
+ }
+
+ gdbserver_state.current_syscall_cb = cb;
#ifndef CONFIG_USER_ONLY
vm_stop(RUN_STATE_DEBUG);
#endif
- p = s->syscall_buf;
- p_end = &s->syscall_buf[sizeof(s->syscall_buf)];
+ p = &gdbserver_state.syscall_buf[0];
+ p_end = &gdbserver_state.syscall_buf[sizeof(gdbserver_state.syscall_buf)];
*(p++) = 'F';
while (*fmt) {
if (*fmt == '%') {
}
*p = 0;
#ifdef CONFIG_USER_ONLY
- put_packet(s, s->syscall_buf);
+ put_packet(gdbserver_state.syscall_buf);
/* Return control to gdb for it to process the syscall request.
* Since the protocol requires that gdb hands control back to us
* using a "here are the results" F packet, we don't need to check
* gdb_handlesig's return value (which is the signal to deliver if
* execution was resumed via a continue packet).
*/
- gdb_handlesig(s->c_cpu, 0);
+ gdb_handlesig(gdbserver_state.c_cpu, 0);
#else
/* In this case wait to send the syscall packet until notification that
the CPU has stopped. This must be done because if the packet is sent
is still in the running state, which can cause packets to be dropped
and state transition 'T' packets to be sent while the syscall is still
being processed. */
- qemu_cpu_kick(s->c_cpu);
+ qemu_cpu_kick(gdbserver_state.c_cpu);
#endif
}
va_end(va);
}
-static void gdb_read_byte(GDBState *s, uint8_t ch)
+static void gdb_read_byte(uint8_t ch)
{
uint8_t reply;
#ifndef CONFIG_USER_ONLY
- if (s->last_packet_len) {
+ if (gdbserver_state.last_packet->len) {
/* Waiting for a response to the last packet. If we see the start
of a new command then abandon the previous response. */
if (ch == '-') {
trace_gdbstub_err_got_nack();
- put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len);
+ put_buffer(gdbserver_state.last_packet->data,
+ gdbserver_state.last_packet->len);
} else if (ch == '+') {
trace_gdbstub_io_got_ack();
} else {
trace_gdbstub_io_got_unexpected(ch);
}
- if (ch == '+' || ch == '$')
- s->last_packet_len = 0;
+ if (ch == '+' || ch == '$') {
+ g_byte_array_set_size(gdbserver_state.last_packet, 0);
+ }
if (ch != '$')
return;
}
} else
#endif
{
- switch(s->state) {
+ switch(gdbserver_state.state) {
case RS_IDLE:
if (ch == '$') {
/* start of command packet */
- s->line_buf_index = 0;
- s->line_sum = 0;
- s->state = RS_GETLINE;
+ gdbserver_state.line_buf_index = 0;
+ gdbserver_state.line_sum = 0;
+ gdbserver_state.state = RS_GETLINE;
} else {
trace_gdbstub_err_garbage(ch);
}
case RS_GETLINE:
if (ch == '}') {
/* start escape sequence */
- s->state = RS_GETLINE_ESC;
- s->line_sum += ch;
+ gdbserver_state.state = RS_GETLINE_ESC;
+ gdbserver_state.line_sum += ch;
} else if (ch == '*') {
/* start run length encoding sequence */
- s->state = RS_GETLINE_RLE;
- s->line_sum += ch;
+ gdbserver_state.state = RS_GETLINE_RLE;
+ gdbserver_state.line_sum += ch;
} else if (ch == '#') {
/* end of command, start of checksum*/
- s->state = RS_CHKSUM1;
- } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+ gdbserver_state.state = RS_CHKSUM1;
+ } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) {
trace_gdbstub_err_overrun();
- s->state = RS_IDLE;
+ gdbserver_state.state = RS_IDLE;
} else {
/* unescaped command character */
- s->line_buf[s->line_buf_index++] = ch;
- s->line_sum += ch;
+ gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch;
+ gdbserver_state.line_sum += ch;
}
break;
case RS_GETLINE_ESC:
if (ch == '#') {
/* unexpected end of command in escape sequence */
- s->state = RS_CHKSUM1;
- } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+ gdbserver_state.state = RS_CHKSUM1;
+ } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) {
/* command buffer overrun */
trace_gdbstub_err_overrun();
- s->state = RS_IDLE;
+ gdbserver_state.state = RS_IDLE;
} else {
/* parse escaped character and leave escape state */
- s->line_buf[s->line_buf_index++] = ch ^ 0x20;
- s->line_sum += ch;
- s->state = RS_GETLINE;
+ gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch ^ 0x20;
+ gdbserver_state.line_sum += ch;
+ gdbserver_state.state = RS_GETLINE;
}
break;
case RS_GETLINE_RLE:
if (ch < ' ' || ch == '#' || ch == '$' || ch > 126) {
/* invalid RLE count encoding */
trace_gdbstub_err_invalid_repeat(ch);
- s->state = RS_GETLINE;
+ gdbserver_state.state = RS_GETLINE;
} else {
/* decode repeat length */
int repeat = ch - ' ' + 3;
- if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) {
+ if (gdbserver_state.line_buf_index + repeat >= sizeof(gdbserver_state.line_buf) - 1) {
/* that many repeats would overrun the command buffer */
trace_gdbstub_err_overrun();
- s->state = RS_IDLE;
- } else if (s->line_buf_index < 1) {
+ gdbserver_state.state = RS_IDLE;
+ } else if (gdbserver_state.line_buf_index < 1) {
/* got a repeat but we have nothing to repeat */
trace_gdbstub_err_invalid_rle();
- s->state = RS_GETLINE;
+ gdbserver_state.state = RS_GETLINE;
} else {
/* repeat the last character */
- memset(s->line_buf + s->line_buf_index,
- s->line_buf[s->line_buf_index - 1], repeat);
- s->line_buf_index += repeat;
- s->line_sum += ch;
- s->state = RS_GETLINE;
+ memset(gdbserver_state.line_buf + gdbserver_state.line_buf_index,
+ gdbserver_state.line_buf[gdbserver_state.line_buf_index - 1], repeat);
+ gdbserver_state.line_buf_index += repeat;
+ gdbserver_state.line_sum += ch;
+ gdbserver_state.state = RS_GETLINE;
}
}
break;
/* get high hex digit of checksum */
if (!isxdigit(ch)) {
trace_gdbstub_err_checksum_invalid(ch);
- s->state = RS_GETLINE;
+ gdbserver_state.state = RS_GETLINE;
break;
}
- s->line_buf[s->line_buf_index] = '\0';
- s->line_csum = fromhex(ch) << 4;
- s->state = RS_CHKSUM2;
+ gdbserver_state.line_buf[gdbserver_state.line_buf_index] = '\0';
+ gdbserver_state.line_csum = fromhex(ch) << 4;
+ gdbserver_state.state = RS_CHKSUM2;
break;
case RS_CHKSUM2:
/* get low hex digit of checksum */
if (!isxdigit(ch)) {
trace_gdbstub_err_checksum_invalid(ch);
- s->state = RS_GETLINE;
+ gdbserver_state.state = RS_GETLINE;
break;
}
- s->line_csum |= fromhex(ch);
+ gdbserver_state.line_csum |= fromhex(ch);
- if (s->line_csum != (s->line_sum & 0xff)) {
- trace_gdbstub_err_checksum_incorrect(s->line_sum, s->line_csum);
+ if (gdbserver_state.line_csum != (gdbserver_state.line_sum & 0xff)) {
+ trace_gdbstub_err_checksum_incorrect(gdbserver_state.line_sum, gdbserver_state.line_csum);
/* send NAK reply */
reply = '-';
- put_buffer(s, &reply, 1);
- s->state = RS_IDLE;
+ put_buffer(&reply, 1);
+ gdbserver_state.state = RS_IDLE;
} else {
/* send ACK reply */
reply = '+';
- put_buffer(s, &reply, 1);
- s->state = gdb_handle_packet(s, s->line_buf);
+ put_buffer(&reply, 1);
+ gdbserver_state.state = gdb_handle_packet(gdbserver_state.line_buf);
}
break;
default:
/* Tell the remote gdb that the process has exited. */
void gdb_exit(CPUArchState *env, int code)
{
- GDBState *s;
char buf[4];
- s = gdbserver_state;
- if (!s) {
+ if (!gdbserver_state.init) {
return;
}
#ifdef CONFIG_USER_ONLY
- if (gdbserver_fd < 0 || s->fd < 0) {
+ if (gdbserver_fd < 0 || gdbserver_state.fd < 0) {
return;
}
#endif
trace_gdbstub_op_exiting((uint8_t)code);
snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
- put_packet(s, buf);
+ put_packet(buf);
#ifndef CONFIG_USER_ONLY
- qemu_chr_fe_deinit(&s->chr, true);
+ qemu_chr_fe_deinit(&gdbserver_state.chr, true);
#endif
}
GDBProcess *process;
int max_pid = 0;
- if (s->process_num) {
+ if (gdbserver_state.process_num) {
max_pid = s->processes[s->process_num - 1].pid;
}
int
gdb_handlesig(CPUState *cpu, int sig)
{
- GDBState *s;
char buf[256];
int n;
- s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0) {
+ if (gdbserver_fd < 0 || gdbserver_state.fd < 0) {
return sig;
}
if (sig != 0) {
snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb(sig));
- put_packet(s, buf);
+ put_packet(buf);
}
/* put_packet() might have detected that the peer terminated the
connection. */
- if (s->fd < 0) {
+ if (gdbserver_state.fd < 0) {
return sig;
}
sig = 0;
- s->state = RS_IDLE;
- s->running_state = 0;
- while (s->running_state == 0) {
- n = read(s->fd, buf, 256);
+ gdbserver_state.state = RS_IDLE;
+ gdbserver_state.running_state = 0;
+ while (gdbserver_state.running_state == 0) {
+ n = read(gdbserver_state.fd, buf, 256);
if (n > 0) {
int i;
for (i = 0; i < n; i++) {
- gdb_read_byte(s, buf[i]);
+ gdb_read_byte(buf[i]);
}
} else {
/* XXX: Connection closed. Should probably wait for another
connection before continuing. */
if (n == 0) {
- close(s->fd);
+ close(gdbserver_state.fd);
}
- s->fd = -1;
+ gdbserver_state.fd = -1;
return sig;
}
}
- sig = s->signal;
- s->signal = 0;
+ sig = gdbserver_state.signal;
+ gdbserver_state.signal = 0;
return sig;
}
/* Tell the remote gdb that the process has exited due to SIG. */
void gdb_signalled(CPUArchState *env, int sig)
{
- GDBState *s;
char buf[4];
- s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0) {
+ if (gdbserver_fd < 0 || gdbserver_state.fd < 0) {
return;
}
snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb(sig));
- put_packet(s, buf);
+ put_packet(buf);
}
static bool gdb_accept(void)
{
- GDBState *s;
struct sockaddr_in sockaddr;
socklen_t len;
int fd;
return false;
}
- s = g_malloc0(sizeof(GDBState));
- create_default_process(s);
- s->processes[0].attached = true;
- s->c_cpu = gdb_first_attached_cpu(s);
- s->g_cpu = s->c_cpu;
- s->fd = fd;
+ init_gdbserver_state();
+ create_default_process(&gdbserver_state);
+ gdbserver_state.processes[0].attached = true;
+ gdbserver_state.c_cpu = gdb_first_attached_cpu();
+ gdbserver_state.g_cpu = gdbserver_state.c_cpu;
+ gdbserver_state.fd = fd;
gdb_has_xml = false;
-
- gdbserver_state = s;
return true;
}
/* Disable gdb stub for child processes. */
void gdbserver_fork(CPUState *cpu)
{
- GDBState *s = gdbserver_state;
-
- if (gdbserver_fd < 0 || s->fd < 0) {
+ if (gdbserver_fd < 0 || gdbserver_state.fd < 0) {
return;
}
- close(s->fd);
- s->fd = -1;
+ close(gdbserver_state.fd);
+ gdbserver_state.fd = -1;
cpu_breakpoint_remove_all(cpu, BP_GDB);
cpu_watchpoint_remove_all(cpu, BP_GDB);
}
int i;
for (i = 0; i < size; i++) {
- gdb_read_byte(gdbserver_state, buf[i]);
+ gdb_read_byte(buf[i]);
}
}
s->processes[i].attached = !i;
}
- s->c_cpu = gdb_first_attached_cpu(s);
+ s->c_cpu = gdb_first_attached_cpu();
s->g_cpu = s->c_cpu;
vm_stop(RUN_STATE_PAUSED);
}
}
-static void gdb_monitor_output(GDBState *s, const char *msg, int len)
-{
- char buf[MAX_PACKET_LENGTH];
-
- buf[0] = 'O';
- if (len > (MAX_PACKET_LENGTH/2) - 1)
- len = (MAX_PACKET_LENGTH/2) - 1;
- memtohex(buf + 1, (uint8_t *)msg, len);
- put_packet(s, buf);
-}
-
static int gdb_monitor_write(Chardev *chr, const uint8_t *buf, int len)
{
- const char *p = (const char *)buf;
- int max_sz;
-
- max_sz = (sizeof(gdbserver_state->last_packet) - 2) / 2;
- for (;;) {
- if (len <= max_sz) {
- gdb_monitor_output(gdbserver_state, p, len);
- break;
- }
- gdb_monitor_output(gdbserver_state, p, max_sz);
- p += max_sz;
- len -= max_sz;
- }
+ g_autoptr(GString) hex_buf = g_string_new("O");
+ memtohex(hex_buf, buf, len);
+ put_packet(hex_buf->str);
return len;
}
{
object_child_foreach(object_get_root(), find_cpu_clusters, s);
- if (s->processes) {
+ if (gdbserver_state.processes) {
/* Sort by PID */
- qsort(s->processes, s->process_num, sizeof(s->processes[0]), pid_order);
+ qsort(gdbserver_state.processes, gdbserver_state.process_num, sizeof(gdbserver_state.processes[0]), pid_order);
}
create_default_process(s);
}
-static void cleanup_processes(GDBState *s)
-{
- g_free(s->processes);
- s->process_num = 0;
- s->processes = NULL;
-}
-
int gdbserver_start(const char *device)
{
trace_gdbstub_op_start(device);
- GDBState *s;
char gdbstub_device_name[128];
Chardev *chr = NULL;
Chardev *mon_chr;
return -1;
}
- s = gdbserver_state;
- if (!s) {
- s = g_malloc0(sizeof(GDBState));
- gdbserver_state = s;
+ if (!gdbserver_state.init) {
+ init_gdbserver_state();
qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
NULL, NULL, &error_abort);
monitor_init_hmp(mon_chr, false, &error_abort);
} else {
- qemu_chr_fe_deinit(&s->chr, true);
- mon_chr = s->mon_chr;
- cleanup_processes(s);
- memset(s, 0, sizeof(GDBState));
- s->mon_chr = mon_chr;
+ qemu_chr_fe_deinit(&gdbserver_state.chr, true);
+ mon_chr = gdbserver_state.mon_chr;
+ reset_gdbserver_state();
}
- create_processes(s);
+ create_processes(&gdbserver_state);
if (chr) {
- qemu_chr_fe_init(&s->chr, chr, &error_abort);
- qemu_chr_fe_set_handlers(&s->chr, gdb_chr_can_receive, gdb_chr_receive,
- gdb_chr_event, NULL, s, NULL, true);
+ qemu_chr_fe_init(&gdbserver_state.chr, chr, &error_abort);
+ qemu_chr_fe_set_handlers(&gdbserver_state.chr, gdb_chr_can_receive,
+ gdb_chr_receive, gdb_chr_event,
+ NULL, &gdbserver_state, NULL, true);
}
- s->state = chr ? RS_IDLE : RS_INACTIVE;
- s->mon_chr = mon_chr;
- s->current_syscall_cb = NULL;
+ gdbserver_state.state = chr ? RS_IDLE : RS_INACTIVE;
+ gdbserver_state.mon_chr = mon_chr;
+ gdbserver_state.current_syscall_cb = NULL;
return 0;
}
void gdbserver_cleanup(void)
{
- if (gdbserver_state) {
- put_packet(gdbserver_state, "W00");
+ if (gdbserver_state.init) {
+ put_packet("W00");
}
}
#include "qemu/error-report.h"
#include "sysemu/sysemu.h"
#include "hw/rtc/mc146818rtc.h"
-#include "hw/ide.h"
+#include "hw/ide/pci.h"
#include "hw/timer/i8254.h"
#include "hw/isa/superio.h"
#include "hw/dma/i8257.h"
const char *initrd_filename = machine->initrd_filename;
AlphaCPU *cpus[4];
PCIBus *pci_bus;
+ PCIDevice *pci_dev;
ISABus *isa_bus;
qemu_irq rtc_irq;
long size, i;
isa_create_simple(isa_bus, TYPE_SMC37C669_SUPERIO);
/* IDE disk setup. */
- {
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- ide_drive_get(hd, ARRAY_SIZE(hd));
-
- pci_cmd646_ide_init(pci_bus, hd, 0);
- }
+ pci_dev = pci_create_simple(pci_bus, -1, "cmd646-ide");
+ pci_ide_create_devs(pci_dev);
/* Load PALcode. Given that this is not "real" cpu palcode,
but one explicitly written for the emulation, we might as
XenBlockVdev *vdev = &blockdev->props.vdev;
XenBlockDrive *drive = blockdev->drive;
XenBlockIOThread *iothread = blockdev->iothread;
+ Error *local_err = NULL;
trace_xen_block_device_destroy(vdev->number);
object_unparent(OBJECT(xendev));
if (iothread) {
- Error *local_err = NULL;
-
xen_block_iothread_destroy(iothread, &local_err);
if (local_err) {
error_propagate_prepend(errp, local_err,
- "failed to destroy iothread: ");
+ "failed to destroy iothread: ");
return;
}
}
if (drive) {
- Error *local_err = NULL;
-
xen_block_drive_destroy(drive, &local_err);
if (local_err) {
error_propagate_prepend(errp, local_err,
- "failed to destroy drive: ");
+ "failed to destroy drive: ");
+ return;
}
}
}
}
-static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg)
+static int cpu_common_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
{
return 0;
}
#include "hw/pci/pci.h"
#include "hw/pci/pci_host.h"
-#include "hw/ide.h"
#include "hw/boards.h"
#include "hw/intc/i8259.h"
#include "sysemu/reset.h"
#include "sysemu/sysemu.h"
#include "hw/rtc/mc146818rtc.h"
-#include "hw/ide.h"
#include "hw/timer/i8254.h"
#include "hw/char/serial.h"
#include "hw/net/lasi_82596.h"
#include "hw/pci/pci_ids.h"
#include "hw/usb.h"
#include "net/net.h"
-#include "hw/ide.h"
+#include "hw/ide/pci.h"
#include "hw/irq.h"
#include "sysemu/kvm.h"
#include "hw/kvm/clock.h"
int piix3_devfn = -1;
qemu_irq smi_irq;
GSIState *gsi_state;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
BusState *idebus[MAX_IDE_BUS];
ISADevice *rtc_state;
MemoryRegion *ram_memory;
pc_nic_init(pcmc, isa_bus, pci_bus);
- ide_drive_get(hd, ARRAY_SIZE(hd));
if (pcmc->pci_enabled) {
PCIDevice *dev;
- if (xen_enabled()) {
- dev = pci_piix3_xen_ide_init(pci_bus, hd, piix3_devfn + 1);
- } else {
- dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
- }
+
+ dev = pci_create_simple(pci_bus, piix3_devfn + 1,
+ xen_enabled() ? "piix3-ide-xen" : "piix3-ide");
+ pci_ide_create_devs(dev);
idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
}
#ifdef CONFIG_IDE_ISA
-else {
+ else {
+ DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
int i;
+
+ ide_drive_get(hd, ARRAY_SIZE(hd));
for (i = 0; i < MAX_IDE_BUS; i++) {
ISADevice *dev;
char busname[] = "ide.0";
#include "hw/ide/ahci.h"
#include "hw/ide/internal.h"
#include "hw/sysbus.h"
+#include "hw/pci/pci.h"
#define AHCI_MEM_BAR_SIZE 0x1000
#define AHCI_MAX_PORTS 32
cmd646_update_irq(pd);
}
-static void cmd646_reset(void *opaque)
+static void cmd646_reset(DeviceState *dev)
{
- PCIIDEState *d = opaque;
+ PCIIDEState *d = PCI_IDE(dev);
unsigned int i;
for (i = 0; i < 2; i++) {
ide_register_restart_cb(&d->bus[i]);
}
g_free(irq);
-
- vmstate_register(VMSTATE_IF(dev), 0, &vmstate_ide_pci, d);
- qemu_register_reset(cmd646_reset, d);
}
static void pci_cmd646_ide_exitfn(PCIDevice *dev)
}
}
-void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
- int secondary_ide_enabled)
-{
- PCIDevice *dev;
-
- dev = pci_create(bus, -1, "cmd646-ide");
- qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled);
- qdev_init_nofail(&dev->qdev);
-
- pci_ide_create_devs(dev, hd_table);
-}
-
static Property cmd646_ide_properties[] = {
DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
DEFINE_PROP_END_OF_LIST(),
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ dc->reset = cmd646_reset;
+ dc->vmsd = &vmstate_ide_pci;
k->realize = pci_cmd646_ide_realize;
k->exit = pci_cmd646_ide_exitfn;
k->vendor_id = PCI_VENDOR_ID_CMD;
}
};
-void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table)
+/* hd_table must contain 4 block drivers */
+void pci_ide_create_devs(PCIDevice *dev)
{
PCIIDEState *d = PCI_IDE(dev);
+ DriveInfo *hd_table[2 * MAX_IDE_DEVS];
static const int bus[4] = { 0, 0, 1, 1 };
static const int unit[4] = { 0, 1, 0, 1 };
int i;
+ ide_drive_get(hd_table, ARRAY_SIZE(hd_table));
for (i = 0; i < 4; i++) {
- if (hd_table[i] == NULL)
- continue;
- ide_create_drive(d->bus+bus[i], unit[i], hd_table[i]);
+ if (hd_table[i]) {
+ ide_create_drive(d->bus + bus[i], unit[i], hd_table[i]);
+ }
}
}
return 0;
}
-PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create_simple(bus, devfn, "piix3-ide-xen");
- pci_ide_create_devs(dev, hd_table);
- return dev;
-}
-
static void pci_piix_ide_exitfn(PCIDevice *dev)
{
PCIIDEState *d = PCI_IDE(dev);
}
}
-/* hd_table must contain 4 block drivers */
/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
-PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create_simple(bus, devfn, "piix3-ide");
- pci_ide_create_devs(dev, hd_table);
- return dev;
-}
-
-/* hd_table must contain 4 block drivers */
-/* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */
-PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create_simple(bus, devfn, "piix4-ide");
- pci_ide_create_devs(dev, hd_table);
- return dev;
-}
-
static void piix3_ide_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
.class_init = piix3_ide_class_init,
};
+/* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */
static void piix4_ide_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
}
level = (d->config[0x70] & 0x80) || (d->config[0x78] & 0x80);
- n = pci_get_byte(d->config + PCI_INTERRUPT_LINE);
- if (n) {
- qemu_set_irq(isa_get_irq(NULL, n), level);
- }
+ qemu_set_irq(isa_get_irq(NULL, 14 + n), level);
}
static void via_ide_reset(DeviceState *dev)
uint8_t *pci_conf = dev->config;
int i;
- pci_config_set_prog_interface(pci_conf, 0x8f); /* native PCI ATA mode */
+ pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy mode */
pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
- dev->wmask[PCI_INTERRUPT_LINE] = 0xf;
+ dev->wmask[PCI_INTERRUPT_LINE] = 0;
+ dev->wmask[PCI_CLASS_PROG] = 5;
memory_region_init_io(&d->data_bar[0], OBJECT(d), &pci_ide_data_le_ops,
&d->bus[0], "via-ide0-data", 8);
bmdma_setup_bar(d);
pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
- vmstate_register(VMSTATE_IF(dev), 0, &vmstate_ide_pci, d);
-
for (i = 0; i < 2; i++) {
ide_bus_new(&d->bus[i], sizeof(d->bus[i]), DEVICE(d), i, 2);
ide_init2(&d->bus[i], qemu_allocate_irq(via_ide_set_irq, d, i));
}
}
-void via_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create_simple(bus, devfn, "via-ide");
- pci_ide_create_devs(dev, hd_table);
-}
-
static void via_ide_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
dc->reset = via_ide_reset;
+ dc->vmsd = &vmstate_ide_pci;
k->realize = via_ide_realize;
k->exit = via_ide_exitfn;
k->vendor_id = PCI_VENDOR_ID_VIA;
uint64_t timas[2 * 2];
/* Interrupt number ranges for the IPIs */
uint32_t lisn_ranges[] = {
- cpu_to_be32(0),
- cpu_to_be32(nr_servers),
+ cpu_to_be32(SPAPR_IRQ_IPI),
+ cpu_to_be32(SPAPR_IRQ_IPI + nr_servers),
};
/*
* EQ size - the sizes of pages supported by the system 4K, 64K,
#include "hw/dma/i8257.h"
#include "hw/timer/i8254.h"
#include "hw/rtc/mc146818rtc.h"
-#include "hw/ide.h"
+#include "hw/ide/pci.h"
#include "migration/vmstate.h"
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
type_init(piix4_register_types)
-DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus,
- I2CBus **smbus, size_t ide_buses)
+DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, I2CBus **smbus)
{
- size_t ide_drives = ide_buses * MAX_IDE_DEVS;
- DriveInfo **hd;
PCIDevice *pci;
DeviceState *dev;
+ int devfn = PCI_DEVFN(10, 0);
- pci = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(10, 0),
- true, TYPE_PIIX4_PCI_DEVICE);
+ pci = pci_create_simple_multifunction(pci_bus, devfn, true,
+ TYPE_PIIX4_PCI_DEVICE);
dev = DEVICE(pci);
if (isa_bus) {
*isa_bus = ISA_BUS(qdev_get_child_bus(dev, "isa.0"));
}
- hd = g_new(DriveInfo *, ide_drives);
- ide_drive_get(hd, ide_drives);
- pci_piix4_ide_init(pci_bus, hd, pci->devfn + 1);
- g_free(hd);
- pci_create_simple(pci_bus, pci->devfn + 2, "piix4-usb-uhci");
+ pci = pci_create_simple(pci_bus, devfn + 1, "piix4-ide");
+ pci_ide_create_devs(pci);
+
+ pci_create_simple(pci_bus, devfn + 2, "piix4-usb-uhci");
if (smbus) {
- *smbus = piix4_pm_init(pci_bus, pci->devfn + 3, 0x1100,
+ *smbus = piix4_pm_init(pci_bus, devfn + 3, 0x1100,
isa_get_irq(NULL, 9), NULL, 0, NULL);
}
#include "audio/audio.h"
#include "qemu/log.h"
#include "hw/loader.h"
-#include "hw/ide.h"
+#include "hw/ide/pci.h"
#include "elf.h"
#include "hw/isa/vt82c686.h"
#include "hw/rtc/mc146818rtc.h"
{
qemu_irq *i8259;
ISABus *isa_bus;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+ PCIDevice *dev;
isa_bus = vt82c686b_isa_init(pci_bus, PCI_DEVFN(slot, 0));
if (!isa_bus) {
/* Super I/O */
isa_create_simple(isa_bus, TYPE_VT82C686B_SUPERIO);
- ide_drive_get(hd, ARRAY_SIZE(hd));
- via_ide_init(pci_bus, hd, PCI_DEVFN(slot, 1));
+ dev = pci_create_simple(pci_bus, PCI_DEVFN(slot, 1), "via-ide");
+ pci_ide_create_devs(dev);
pci_create_simple(pci_bus, PCI_DEVFN(slot, 2), "vt82c686b-usb-uhci");
pci_create_simple(pci_bus, PCI_DEVFN(slot, 3), "vt82c686b-usb-uhci");
pci_bus = gt64120_register(s->i8259);
/* Southbridge */
- dev = piix4_create(pci_bus, &isa_bus, &smbus, MAX_IDE_BUS);
+ dev = piix4_create(pci_bus, &isa_bus, &smbus);
/* Interrupt controller */
qdev_connect_gpio_out_named(dev, "intr", 0, i8259_irq);
#include "qemu/log.h"
#include "hw/mips/bios.h"
#include "hw/ide.h"
+#include "hw/ide/internal.h"
#include "hw/loader.h"
#include "elf.h"
#include "hw/rtc/mc146818rtc.h"
IVShmemState *s = IVSHMEM_COMMON(dev);
Error *err = NULL;
uint8_t *pci_conf;
- Error *local_err = NULL;
/* IRQFD requires MSI */
if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
if (!ivshmem_is_master(s)) {
error_setg(&s->migration_blocker,
"Migration is disabled when using feature 'peer mode' in device 'ivshmem'");
- migrate_add_blocker(s->migration_blocker, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ migrate_add_blocker(s->migration_blocker, &err);
+ if (err) {
+ error_propagate(errp, err);
error_free(s->migration_blocker);
return;
}
pci_word_test_and_clear_mask(dev->config + PCI_STATUS,
pci_get_word(dev->wmask + PCI_STATUS) |
pci_get_word(dev->w1cmask + PCI_STATUS));
+ /* Some devices make bits of PCI_INTERRUPT_LINE read only */
+ pci_byte_test_and_clear_mask(dev->config + PCI_INTERRUPT_LINE,
+ pci_get_word(dev->wmask + PCI_INTERRUPT_LINE) |
+ pci_get_word(dev->w1cmask + PCI_INTERRUPT_LINE));
dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
- dev->config[PCI_INTERRUPT_LINE] = 0x0;
for (r = 0; r < PCI_NUM_REGIONS; ++r) {
PCIIORegion *region = &dev->io_regions[r];
if (!region->size) {
#include "hw/char/escc.h"
#include "hw/misc/macio/macio.h"
#include "hw/ppc/openpic.h"
-#include "hw/ide.h"
#include "hw/loader.h"
#include "hw/fw-path-provider.h"
#include "elf.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/char/escc.h"
#include "hw/misc/macio/macio.h"
-#include "hw/ide.h"
#include "hw/loader.h"
#include "hw/fw-path-provider.h"
#include "elf.h"
bool hostboot_mode = !!pnv->fw_load_addr;
/* let isa_bus_new() create its own bridge on SysBus otherwise
- * devices speficied on the command line won't find the bus and
+ * devices specified on the command line won't find the bus and
* will fail to create.
*/
isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io, &local_err);
#include "hw/boards.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
-#include "hw/ide.h"
#include "hw/irq.h"
#include "hw/loader.h"
#include "hw/rtc/mc146818rtc.h"
#define FW_OVERHEAD 0x2800000
#define KERNEL_LOAD_ADDR FW_MAX_SIZE
-#define MIN_RMA_SLOF 128UL
+#define MIN_RMA_SLOF (128 * MiB)
#define PHANDLE_INTC 0x00001111
sizeof(associativity));
}
-/* Populate the "ibm,pa-features" property */
-static void spapr_populate_pa_features(SpaprMachineState *spapr,
- PowerPCCPU *cpu,
- void *fdt, int offset)
+static void spapr_dt_pa_features(SpaprMachineState *spapr,
+ PowerPCCPU *cpu,
+ void *fdt, int offset)
{
uint8_t pa_features_206[] = { 6, 0,
0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
g_string_append_len(s, s1, strlen(s1) + 1);
}
-static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
- hwaddr size)
+static int spapr_dt_memory_node(void *fdt, int nodeid, hwaddr start,
+ hwaddr size)
{
uint32_t associativity[] = {
cpu_to_be32(0x4), /* length */
return off;
}
-static int spapr_populate_memory(SpaprMachineState *spapr, void *fdt)
-{
- MachineState *machine = MACHINE(spapr);
- hwaddr mem_start, node_size;
- int i, nb_nodes = machine->numa_state->num_nodes;
- NodeInfo *nodes = machine->numa_state->nodes;
-
- for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
- if (!nodes[i].node_mem) {
- continue;
- }
- if (mem_start >= machine->ram_size) {
- node_size = 0;
- } else {
- node_size = nodes[i].node_mem;
- if (node_size > machine->ram_size - mem_start) {
- node_size = machine->ram_size - mem_start;
- }
- }
- if (!mem_start) {
- /* spapr_machine_init() checks for rma_size <= node0_size
- * already */
- spapr_populate_memory_node(fdt, i, 0, spapr->rma_size);
- mem_start += spapr->rma_size;
- node_size -= spapr->rma_size;
- }
- for ( ; node_size; ) {
- hwaddr sizetmp = pow2floor(node_size);
-
- /* mem_start != 0 here */
- if (ctzl(mem_start) < ctzl(sizetmp)) {
- sizetmp = 1ULL << ctzl(mem_start);
- }
-
- spapr_populate_memory_node(fdt, i, mem_start, sizetmp);
- node_size -= sizetmp;
- mem_start += sizetmp;
- }
- }
-
- return 0;
-}
-
-static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
- SpaprMachineState *spapr)
-{
- MachineState *ms = MACHINE(spapr);
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- CPUPPCState *env = &cpu->env;
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
- int index = spapr_get_vcpu_id(cpu);
- uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
- 0xffffffff, 0xffffffff};
- uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
- : SPAPR_TIMEBASE_FREQ;
- uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
- uint32_t page_sizes_prop[64];
- size_t page_sizes_prop_size;
- unsigned int smp_threads = ms->smp.threads;
- uint32_t vcpus_per_socket = smp_threads * ms->smp.cores;
- uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
- int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
- SpaprDrc *drc;
- int drc_index;
- uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
- int i;
-
- drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
- if (drc) {
- drc_index = spapr_drc_index(drc);
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
- }
-
- _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
- _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
-
- _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
- _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
- env->dcache_line_size)));
- _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
- env->dcache_line_size)));
- _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
- env->icache_line_size)));
- _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
- env->icache_line_size)));
-
- if (pcc->l1_dcache_size) {
- _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
- pcc->l1_dcache_size)));
- } else {
- warn_report("Unknown L1 dcache size for cpu");
- }
- if (pcc->l1_icache_size) {
- _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
- pcc->l1_icache_size)));
- } else {
- warn_report("Unknown L1 icache size for cpu");
- }
-
- _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
- _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
- _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
- _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
- _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
-
- if (env->spr_cb[SPR_PURR].oea_read) {
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
- }
- if (env->spr_cb[SPR_SPURR].oea_read) {
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
- }
-
- if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
- _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
- segs, sizeof(segs))));
- }
-
- /* Advertise VSX (vector extensions) if available
- * 1 == VMX / Altivec available
- * 2 == VSX available
- *
- * Only CPUs for which we create core types in spapr_cpu_core.c
- * are possible, and all of those have VMX */
- if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
- } else {
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
- }
-
- /* Advertise DFP (Decimal Floating Point) if available
- * 0 / no property == no DFP
- * 1 == DFP available */
- if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
- }
-
- page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
- sizeof(page_sizes_prop));
- if (page_sizes_prop_size) {
- _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
- page_sizes_prop, page_sizes_prop_size)));
- }
-
- spapr_populate_pa_features(spapr, cpu, fdt, offset);
-
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
- cs->cpu_index / vcpus_per_socket)));
-
- _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
- pft_size_prop, sizeof(pft_size_prop))));
-
- if (ms->numa_state->num_nodes > 1) {
- _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cpu));
- }
-
- _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
-
- if (pcc->radix_page_info) {
- for (i = 0; i < pcc->radix_page_info->count; i++) {
- radix_AP_encodings[i] =
- cpu_to_be32(pcc->radix_page_info->entries[i]);
- }
- _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
- radix_AP_encodings,
- pcc->radix_page_info->count *
- sizeof(radix_AP_encodings[0]))));
- }
-
- /*
- * We set this property to let the guest know that it can use the large
- * decrementer and its width in bits.
- */
- if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
- _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
- pcc->lrg_decr_bits)));
-}
-
-static void spapr_populate_cpus_dt_node(void *fdt, SpaprMachineState *spapr)
-{
- CPUState **rev;
- CPUState *cs;
- int n_cpus;
- int cpus_offset;
- char *nodename;
- int i;
-
- cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
- _FDT(cpus_offset);
- _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
- _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
-
- /*
- * We walk the CPUs in reverse order to ensure that CPU DT nodes
- * created by fdt_add_subnode() end up in the right order in FDT
- * for the guest kernel the enumerate the CPUs correctly.
- *
- * The CPU list cannot be traversed in reverse order, so we need
- * to do extra work.
- */
- n_cpus = 0;
- rev = NULL;
- CPU_FOREACH(cs) {
- rev = g_renew(CPUState *, rev, n_cpus + 1);
- rev[n_cpus++] = cs;
- }
-
- for (i = n_cpus - 1; i >= 0; i--) {
- CPUState *cs = rev[i];
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- int index = spapr_get_vcpu_id(cpu);
- DeviceClass *dc = DEVICE_GET_CLASS(cs);
- int offset;
-
- if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
- continue;
- }
-
- nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
- offset = fdt_add_subnode(fdt, cpus_offset, nodename);
- g_free(nodename);
- _FDT(offset);
- spapr_populate_cpu_dt(cs, fdt, offset, spapr);
- }
-
- g_free(rev);
-}
-
-static int spapr_rng_populate_dt(void *fdt)
-{
- int node;
- int ret;
-
- node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
- if (node <= 0) {
- return -1;
- }
- ret = fdt_setprop_string(fdt, node, "device_type",
- "ibm,platform-facilities");
- ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
- ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
-
- node = fdt_add_subnode(fdt, node, "ibm,random-v1");
- if (node <= 0) {
- return -1;
- }
- ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
-
- return ret ? -1 : 0;
-}
-
static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr)
{
MemoryDeviceInfoList *info;
return elem;
}
-/* ibm,dynamic-memory-v2 */
-static int spapr_populate_drmem_v2(SpaprMachineState *spapr, void *fdt,
- int offset, MemoryDeviceInfoList *dimms)
+static int spapr_dt_dynamic_memory_v2(SpaprMachineState *spapr, void *fdt,
+ int offset, MemoryDeviceInfoList *dimms)
{
MachineState *machine = MACHINE(spapr);
uint8_t *int_buf, *cur_index;
return 0;
}
-/* ibm,dynamic-memory */
-static int spapr_populate_drmem_v1(SpaprMachineState *spapr, void *fdt,
+static int spapr_dt_dynamic_memory(SpaprMachineState *spapr, void *fdt,
int offset, MemoryDeviceInfoList *dimms)
{
MachineState *machine = MACHINE(spapr);
if (ret < 0) {
return -1;
}
- return 0;
-}
-
-/*
- * Adds ibm,dynamic-reconfiguration-memory node.
- * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
- * of this device tree node.
- */
-static int spapr_populate_drconf_memory(SpaprMachineState *spapr, void *fdt)
-{
- MachineState *machine = MACHINE(spapr);
- int nb_numa_nodes = machine->numa_state->num_nodes;
- int ret, i, offset;
- uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
- uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)};
- uint32_t *int_buf, *cur_index, buf_len;
- int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1;
- MemoryDeviceInfoList *dimms = NULL;
+ return 0;
+}
+
+/*
+ * Adds ibm,dynamic-reconfiguration-memory node.
+ * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
+ * of this device tree node.
+ */
+static int spapr_dt_dynamic_reconfiguration_memory(SpaprMachineState *spapr,
+ void *fdt)
+{
+ MachineState *machine = MACHINE(spapr);
+ int nb_numa_nodes = machine->numa_state->num_nodes;
+ int ret, i, offset;
+ uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
+ uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)};
+ uint32_t *int_buf, *cur_index, buf_len;
+ int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1;
+ MemoryDeviceInfoList *dimms = NULL;
+
+ /*
+ * Don't create the node if there is no device memory
+ */
+ if (machine->ram_size == machine->maxram_size) {
+ return 0;
+ }
+
+ offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
+
+ ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
+ sizeof(prop_lmb_size));
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* ibm,dynamic-memory or ibm,dynamic-memory-v2 */
+ dimms = qmp_memory_device_list();
+ if (spapr_ovec_test(spapr->ov5_cas, OV5_DRMEM_V2)) {
+ ret = spapr_dt_dynamic_memory_v2(spapr, fdt, offset, dimms);
+ } else {
+ ret = spapr_dt_dynamic_memory(spapr, fdt, offset, dimms);
+ }
+ qapi_free_MemoryDeviceInfoList(dimms);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* ibm,associativity-lookup-arrays */
+ buf_len = (nr_nodes * 4 + 2) * sizeof(uint32_t);
+ cur_index = int_buf = g_malloc0(buf_len);
+ int_buf[0] = cpu_to_be32(nr_nodes);
+ int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */
+ cur_index += 2;
+ for (i = 0; i < nr_nodes; i++) {
+ uint32_t associativity[] = {
+ cpu_to_be32(0x0),
+ cpu_to_be32(0x0),
+ cpu_to_be32(0x0),
+ cpu_to_be32(i)
+ };
+ memcpy(cur_index, associativity, sizeof(associativity));
+ cur_index += 4;
+ }
+ ret = fdt_setprop(fdt, offset, "ibm,associativity-lookup-arrays", int_buf,
+ (cur_index - int_buf) * sizeof(uint32_t));
+ g_free(int_buf);
+
+ return ret;
+}
+
+static int spapr_dt_memory(SpaprMachineState *spapr, void *fdt)
+{
+ MachineState *machine = MACHINE(spapr);
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ hwaddr mem_start, node_size;
+ int i, nb_nodes = machine->numa_state->num_nodes;
+ NodeInfo *nodes = machine->numa_state->nodes;
+
+ for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
+ if (!nodes[i].node_mem) {
+ continue;
+ }
+ if (mem_start >= machine->ram_size) {
+ node_size = 0;
+ } else {
+ node_size = nodes[i].node_mem;
+ if (node_size > machine->ram_size - mem_start) {
+ node_size = machine->ram_size - mem_start;
+ }
+ }
+ if (!mem_start) {
+ /* spapr_machine_init() checks for rma_size <= node0_size
+ * already */
+ spapr_dt_memory_node(fdt, i, 0, spapr->rma_size);
+ mem_start += spapr->rma_size;
+ node_size -= spapr->rma_size;
+ }
+ for ( ; node_size; ) {
+ hwaddr sizetmp = pow2floor(node_size);
+
+ /* mem_start != 0 here */
+ if (ctzl(mem_start) < ctzl(sizetmp)) {
+ sizetmp = 1ULL << ctzl(mem_start);
+ }
+
+ spapr_dt_memory_node(fdt, i, mem_start, sizetmp);
+ node_size -= sizetmp;
+ mem_start += sizetmp;
+ }
+ }
+
+ /* Generate ibm,dynamic-reconfiguration-memory node if required */
+ if (spapr_ovec_test(spapr->ov5_cas, OV5_DRCONF_MEMORY)) {
+ int ret;
+
+ g_assert(smc->dr_lmb_enabled);
+ ret = spapr_dt_dynamic_reconfiguration_memory(spapr, fdt);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset,
+ SpaprMachineState *spapr)
+{
+ MachineState *ms = MACHINE(spapr);
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
+ int index = spapr_get_vcpu_id(cpu);
+ uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
+ 0xffffffff, 0xffffffff};
+ uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
+ : SPAPR_TIMEBASE_FREQ;
+ uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
+ uint32_t page_sizes_prop[64];
+ size_t page_sizes_prop_size;
+ unsigned int smp_threads = ms->smp.threads;
+ uint32_t vcpus_per_socket = smp_threads * ms->smp.cores;
+ uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
+ int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
+ SpaprDrc *drc;
+ int drc_index;
+ uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
+ int i;
+
+ drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
+ if (drc) {
+ drc_index = spapr_drc_index(drc);
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
+ }
+
+ _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
+ _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
+
+ _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
+ _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
+ env->dcache_line_size)));
+ _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
+ env->dcache_line_size)));
+ _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
+ env->icache_line_size)));
+ _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
+ env->icache_line_size)));
+
+ if (pcc->l1_dcache_size) {
+ _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
+ pcc->l1_dcache_size)));
+ } else {
+ warn_report("Unknown L1 dcache size for cpu");
+ }
+ if (pcc->l1_icache_size) {
+ _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
+ pcc->l1_icache_size)));
+ } else {
+ warn_report("Unknown L1 icache size for cpu");
+ }
+
+ _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
+ _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
+ _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
+ _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
+ _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
+
+ if (env->spr_cb[SPR_PURR].oea_read) {
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
+ }
+ if (env->spr_cb[SPR_SPURR].oea_read) {
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
+ }
- /*
- * Don't create the node if there is no device memory
- */
- if (machine->ram_size == machine->maxram_size) {
- return 0;
+ if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
+ _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
+ segs, sizeof(segs))));
}
- offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
+ /* Advertise VSX (vector extensions) if available
+ * 1 == VMX / Altivec available
+ * 2 == VSX available
+ *
+ * Only CPUs for which we create core types in spapr_cpu_core.c
+ * are possible, and all of those have VMX */
+ if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
+ } else {
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
+ }
- ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
- sizeof(prop_lmb_size));
- if (ret < 0) {
- return ret;
+ /* Advertise DFP (Decimal Floating Point) if available
+ * 0 / no property == no DFP
+ * 1 == DFP available */
+ if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
}
- ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
- if (ret < 0) {
- return ret;
+ page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
+ sizeof(page_sizes_prop));
+ if (page_sizes_prop_size) {
+ _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
+ page_sizes_prop, page_sizes_prop_size)));
}
- ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
- if (ret < 0) {
- return ret;
+ spapr_dt_pa_features(spapr, cpu, fdt, offset);
+
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
+ cs->cpu_index / vcpus_per_socket)));
+
+ _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
+ pft_size_prop, sizeof(pft_size_prop))));
+
+ if (ms->numa_state->num_nodes > 1) {
+ _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cpu));
}
- /* ibm,dynamic-memory or ibm,dynamic-memory-v2 */
- dimms = qmp_memory_device_list();
- if (spapr_ovec_test(spapr->ov5_cas, OV5_DRMEM_V2)) {
- ret = spapr_populate_drmem_v2(spapr, fdt, offset, dimms);
- } else {
- ret = spapr_populate_drmem_v1(spapr, fdt, offset, dimms);
+ _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
+
+ if (pcc->radix_page_info) {
+ for (i = 0; i < pcc->radix_page_info->count; i++) {
+ radix_AP_encodings[i] =
+ cpu_to_be32(pcc->radix_page_info->entries[i]);
+ }
+ _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
+ radix_AP_encodings,
+ pcc->radix_page_info->count *
+ sizeof(radix_AP_encodings[0]))));
}
- qapi_free_MemoryDeviceInfoList(dimms);
- if (ret < 0) {
- return ret;
+ /*
+ * We set this property to let the guest know that it can use the large
+ * decrementer and its width in bits.
+ */
+ if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
+ _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
+ pcc->lrg_decr_bits)));
+}
+
+static void spapr_dt_cpus(void *fdt, SpaprMachineState *spapr)
+{
+ CPUState **rev;
+ CPUState *cs;
+ int n_cpus;
+ int cpus_offset;
+ char *nodename;
+ int i;
+
+ cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
+ _FDT(cpus_offset);
+ _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
+ _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
+
+ /*
+ * We walk the CPUs in reverse order to ensure that CPU DT nodes
+ * created by fdt_add_subnode() end up in the right order in FDT
+ * for the guest kernel the enumerate the CPUs correctly.
+ *
+ * The CPU list cannot be traversed in reverse order, so we need
+ * to do extra work.
+ */
+ n_cpus = 0;
+ rev = NULL;
+ CPU_FOREACH(cs) {
+ rev = g_renew(CPUState *, rev, n_cpus + 1);
+ rev[n_cpus++] = cs;
}
- /* ibm,associativity-lookup-arrays */
- buf_len = (nr_nodes * 4 + 2) * sizeof(uint32_t);
- cur_index = int_buf = g_malloc0(buf_len);
- int_buf[0] = cpu_to_be32(nr_nodes);
- int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */
- cur_index += 2;
- for (i = 0; i < nr_nodes; i++) {
- uint32_t associativity[] = {
- cpu_to_be32(0x0),
- cpu_to_be32(0x0),
- cpu_to_be32(0x0),
- cpu_to_be32(i)
- };
- memcpy(cur_index, associativity, sizeof(associativity));
- cur_index += 4;
+ for (i = n_cpus - 1; i >= 0; i--) {
+ CPUState *cs = rev[i];
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ int index = spapr_get_vcpu_id(cpu);
+ DeviceClass *dc = DEVICE_GET_CLASS(cs);
+ int offset;
+
+ if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
+ continue;
+ }
+
+ nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
+ offset = fdt_add_subnode(fdt, cpus_offset, nodename);
+ g_free(nodename);
+ _FDT(offset);
+ spapr_dt_cpu(cs, fdt, offset, spapr);
}
- ret = fdt_setprop(fdt, offset, "ibm,associativity-lookup-arrays", int_buf,
- (cur_index - int_buf) * sizeof(uint32_t));
- g_free(int_buf);
- return ret;
+ g_free(rev);
}
-static int spapr_dt_cas_updates(SpaprMachineState *spapr, void *fdt,
- SpaprOptionVector *ov5_updates)
+static int spapr_dt_rng(void *fdt)
{
- SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
- int ret = 0, offset;
+ int node;
+ int ret;
- /* Generate ibm,dynamic-reconfiguration-memory node if required */
- if (spapr_ovec_test(ov5_updates, OV5_DRCONF_MEMORY)) {
- g_assert(smc->dr_lmb_enabled);
- ret = spapr_populate_drconf_memory(spapr, fdt);
- if (ret) {
- return ret;
- }
+ node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
+ if (node <= 0) {
+ return -1;
}
+ ret = fdt_setprop_string(fdt, node, "device_type",
+ "ibm,platform-facilities");
+ ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
+ ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
- offset = fdt_path_offset(fdt, "/chosen");
- if (offset < 0) {
- offset = fdt_add_subnode(fdt, 0, "chosen");
- if (offset < 0) {
- return offset;
- }
+ node = fdt_add_subnode(fdt, node, "ibm,random-v1");
+ if (node <= 0) {
+ return -1;
}
- return spapr_ovec_populate_dt(fdt, offset, spapr->ov5_cas,
- "ibm,architecture-vec-5");
+ ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
+
+ return ret ? -1 : 0;
}
static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
_FDT(fdt_setprop(fdt, rtas, "ibm,max-associativity-domains",
maxdomains, sizeof(maxdomains)));
+ /*
+ * FWNMI reserves RTAS_ERROR_LOG_MAX for the machine check error log,
+ * and 16 bytes per CPU for system reset error log plus an extra 8 bytes.
+ *
+ * The system reset requirements are driven by existing Linux and PowerVM
+ * implementation which (contrary to PAPR) saves r3 in the error log
+ * structure like machine check, so Linux expects to find the saved r3
+ * value at the address in r3 upon FWNMI-enabled sreset interrupt (and
+ * does not look at the error value).
+ *
+ * System reset interrupts are not subject to interlock like machine
+ * check, so this memory area could be corrupted if the sreset is
+ * interrupted by a machine check (or vice versa) if it was shared. To
+ * prevent this, system reset uses per-CPU areas for the sreset save
+ * area. A system reset that interrupts a system reset handler could
+ * still overwrite this area, but Linux doesn't try to recover in that
+ * case anyway.
+ *
+ * The extra 8 bytes is required because Linux's FWNMI error log check
+ * is off-by-one.
+ */
+ _FDT(fdt_setprop_cell(fdt, rtas, "rtas-size", RTAS_ERROR_LOG_MAX +
+ ms->smp.max_cpus * sizeof(uint64_t)*2 + sizeof(uint64_t)));
_FDT(fdt_setprop_cell(fdt, rtas, "rtas-error-log-max",
RTAS_ERROR_LOG_MAX));
_FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate",
val, sizeof(val)));
}
-static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt)
+static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset)
{
MachineState *machine = MACHINE(spapr);
SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
int chosen;
- const char *boot_device = machine->boot_order;
- char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
- size_t cb = 0;
- char *bootlist = get_boot_devices_list(&cb);
_FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
- if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
- _FDT(fdt_setprop_string(fdt, chosen, "bootargs",
- machine->kernel_cmdline));
- }
- if (spapr->initrd_size) {
- _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
- spapr->initrd_base));
- _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
- spapr->initrd_base + spapr->initrd_size));
- }
+ if (reset) {
+ const char *boot_device = machine->boot_order;
+ char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
+ size_t cb = 0;
+ char *bootlist = get_boot_devices_list(&cb);
+
+ if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
+ _FDT(fdt_setprop_string(fdt, chosen, "bootargs",
+ machine->kernel_cmdline));
+ }
+
+ if (spapr->initrd_size) {
+ _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
+ spapr->initrd_base));
+ _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
+ spapr->initrd_base + spapr->initrd_size));
+ }
- if (spapr->kernel_size) {
- uint64_t kprop[2] = { cpu_to_be64(spapr->kernel_addr),
- cpu_to_be64(spapr->kernel_size) };
+ if (spapr->kernel_size) {
+ uint64_t kprop[2] = { cpu_to_be64(spapr->kernel_addr),
+ cpu_to_be64(spapr->kernel_size) };
- _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
+ _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
&kprop, sizeof(kprop)));
- if (spapr->kernel_le) {
- _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
+ if (spapr->kernel_le) {
+ _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
+ }
}
- }
- if (boot_menu) {
- _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu)));
- }
- _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
- _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
- _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
+ if (boot_menu) {
+ _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu)));
+ }
+ _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
+ _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
+ _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
- if (cb && bootlist) {
- int i;
+ if (cb && bootlist) {
+ int i;
- for (i = 0; i < cb; i++) {
- if (bootlist[i] == '\n') {
- bootlist[i] = ' ';
+ for (i = 0; i < cb; i++) {
+ if (bootlist[i] == '\n') {
+ bootlist[i] = ' ';
+ }
}
+ _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
}
- _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
- }
- if (boot_device && strlen(boot_device)) {
- _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
- }
+ if (boot_device && strlen(boot_device)) {
+ _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
+ }
+
+ if (!spapr->has_graphics && stdout_path) {
+ /*
+ * "linux,stdout-path" and "stdout" properties are
+ * deprecated by linux kernel. New platforms should only
+ * use the "stdout-path" property. Set the new property
+ * and continue using older property to remain compatible
+ * with the existing firmware.
+ */
+ _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
+ _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
+ }
- if (!spapr->has_graphics && stdout_path) {
/*
- * "linux,stdout-path" and "stdout" properties are deprecated by linux
- * kernel. New platforms should only use the "stdout-path" property. Set
- * the new property and continue using older property to remain
- * compatible with the existing firmware.
+ * We can deal with BAR reallocation just fine, advertise it
+ * to the guest
*/
- _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
- _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
- }
+ if (smc->linux_pci_probe) {
+ _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
+ }
- /* We can deal with BAR reallocation just fine, advertise it to the guest */
- if (smc->linux_pci_probe) {
- _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
- }
+ spapr_dt_ov5_platform_support(spapr, fdt, chosen);
- spapr_dt_ov5_platform_support(spapr, fdt, chosen);
+ g_free(stdout_path);
+ g_free(bootlist);
+ }
- g_free(stdout_path);
- g_free(bootlist);
+ _FDT(spapr_dt_ovec(fdt, chosen, spapr->ov5_cas, "ibm,architecture-vec-5"));
}
static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
/* /interrupt controller */
spapr_irq_dt(spapr, spapr_max_server_number(spapr), fdt, PHANDLE_INTC);
- ret = spapr_populate_memory(spapr, fdt);
+ ret = spapr_dt_memory(spapr, fdt);
if (ret < 0) {
error_report("couldn't setup memory nodes in fdt");
exit(1);
spapr_dt_vdevice(spapr->vio_bus, fdt);
if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
- ret = spapr_rng_populate_dt(fdt);
+ ret = spapr_dt_rng(fdt);
if (ret < 0) {
error_report("could not set up rng device in the fdt");
exit(1);
}
}
- /* cpus */
- spapr_populate_cpus_dt_node(fdt, spapr);
+ spapr_dt_cpus(fdt, spapr);
if (smc->dr_lmb_enabled) {
_FDT(spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
spapr_dt_rtas(spapr, fdt);
/* /chosen */
- if (reset) {
- spapr_dt_chosen(spapr, fdt);
- }
+ spapr_dt_chosen(spapr, fdt, reset);
/* /hypervisor */
if (kvm_enabled()) {
}
}
- /* ibm,client-architecture-support updates */
- ret = spapr_dt_cas_updates(spapr, fdt, spapr->ov5_cas);
- if (ret < 0) {
- error_report("couldn't setup CAS properties fdt");
- exit(1);
- }
-
if (smc->dr_phb_enabled) {
ret = spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_PHB);
if (ret < 0) {
spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
}
-void spapr_setup_hpt_and_vrma(SpaprMachineState *spapr)
+void spapr_setup_hpt(SpaprMachineState *spapr)
{
int hpt_shift;
}
spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
- if (spapr->vrma_adjust) {
- spapr->rma_size = kvmppc_rma_size(spapr_node0_size(MACHINE(spapr)),
- spapr->htab_shift);
+ if (kvm_enabled()) {
+ hwaddr vrma_limit = kvmppc_vrma_limit(spapr->htab_shift);
+
+ /* Check our RMA fits in the possible VRMA */
+ if (vrma_limit < spapr->rma_size) {
+ error_report("Unable to create %" HWADDR_PRIu
+ "MiB RMA (VRMA only allows %" HWADDR_PRIu "MiB",
+ spapr->rma_size / MiB, vrma_limit / MiB);
+ exit(EXIT_FAILURE);
+ }
}
}
spapr->patb_entry = PATE1_GR;
spapr_set_all_lpcrs(LPCR_HR | LPCR_UPRT, LPCR_HR | LPCR_UPRT);
} else {
- spapr_setup_hpt_and_vrma(spapr);
+ spapr_setup_hpt(spapr);
}
qemu_devices_reset();
spapr->fdt_blob = fdt;
/* Set up the entry state */
- spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, fdt_addr);
+ spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, 0, fdt_addr, 0);
first_ppc_cpu->env.gpr[5] = 0;
spapr->cas_reboot = false;
- spapr->mc_status = -1;
- spapr->guest_machine_check_addr = -1;
+ spapr->fwnmi_system_reset_addr = -1;
+ spapr->fwnmi_machine_check_addr = -1;
+ spapr->fwnmi_machine_check_interlock = -1;
/* Signal all vCPUs waiting on this condition */
- qemu_cond_broadcast(&spapr->mc_delivery_cond);
+ qemu_cond_broadcast(&spapr->fwnmi_machine_check_interlock_cond);
migrate_del_blocker(spapr->fwnmi_migration_blocker);
}
{
SpaprMachineState *spapr = (SpaprMachineState *)opaque;
- return spapr->guest_machine_check_addr != -1;
+ return spapr->fwnmi_machine_check_addr != -1;
}
static int spapr_fwnmi_pre_save(void *opaque)
* Check if machine check handling is in progress and print a
* warning message.
*/
- if (spapr->mc_status != -1) {
+ if (spapr->fwnmi_machine_check_interlock != -1) {
warn_report("A machine check is being handled during migration. The"
"handler may run and log hardware error on the destination");
}
return 0;
}
-static const VMStateDescription vmstate_spapr_machine_check = {
- .name = "spapr_machine_check",
+static const VMStateDescription vmstate_spapr_fwnmi = {
+ .name = "spapr_fwnmi",
.version_id = 1,
.minimum_version_id = 1,
.needed = spapr_fwnmi_needed,
.pre_save = spapr_fwnmi_pre_save,
.fields = (VMStateField[]) {
- VMSTATE_UINT64(guest_machine_check_addr, SpaprMachineState),
- VMSTATE_INT32(mc_status, SpaprMachineState),
+ VMSTATE_UINT64(fwnmi_system_reset_addr, SpaprMachineState),
+ VMSTATE_UINT64(fwnmi_machine_check_addr, SpaprMachineState),
+ VMSTATE_INT32(fwnmi_machine_check_interlock, SpaprMachineState),
VMSTATE_END_OF_LIST()
},
};
&vmstate_spapr_cap_large_decr,
&vmstate_spapr_cap_ccf_assist,
&vmstate_spapr_cap_fwnmi,
- &vmstate_spapr_machine_check,
+ &vmstate_spapr_fwnmi,
NULL
}
};
return PCI_HOST_BRIDGE(dev);
}
+static hwaddr spapr_rma_size(SpaprMachineState *spapr, Error **errp)
+{
+ MachineState *machine = MACHINE(spapr);
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ hwaddr rma_size = machine->ram_size;
+ hwaddr node0_size = spapr_node0_size(machine);
+
+ /* RMA has to fit in the first NUMA node */
+ rma_size = MIN(rma_size, node0_size);
+
+ /*
+ * VRMA access is via a special 1TiB SLB mapping, so the RMA can
+ * never exceed that
+ */
+ rma_size = MIN(rma_size, 1 * TiB);
+
+ /*
+ * Clamp the RMA size based on machine type. This is for
+ * migration compatibility with older qemu versions, which limited
+ * the RMA size for complicated and mostly bad reasons.
+ */
+ if (smc->rma_limit) {
+ rma_size = MIN(rma_size, smc->rma_limit);
+ }
+
+ if (rma_size < MIN_RMA_SLOF) {
+ error_setg(errp,
+ "pSeries SLOF firmware requires >= %" HWADDR_PRIx
+ "ldMiB guest RMA (Real Mode Area memory)",
+ MIN_RMA_SLOF / MiB);
+ return 0;
+ }
+
+ return rma_size;
+}
+
/* pSeries LPAR / sPAPR hardware init */
static void spapr_machine_init(MachineState *machine)
{
PCIHostState *phb;
int i;
MemoryRegion *sysmem = get_system_memory();
- hwaddr node0_size = spapr_node0_size(machine);
long load_limit, fw_size;
char *filename;
Error *resize_hpt_err = NULL;
exit(1);
}
- spapr->rma_size = node0_size;
-
- /* With KVM, we don't actually know whether KVM supports an
- * unbounded RMA (PR KVM) or is limited by the hash table size
- * (HV KVM using VRMA), so we always assume the latter
- *
- * In that case, we also limit the initial allocations for RTAS
- * etc... to 256M since we have no way to know what the VRMA size
- * is going to be as it depends on the size of the hash table
- * which isn't determined yet.
- */
- if (kvm_enabled()) {
- spapr->vrma_adjust = 1;
- spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
- }
-
- /* Actually we don't support unbounded RMA anymore since we added
- * proper emulation of HV mode. The max we can get is 16G which
- * also happens to be what we configure for PAPR mode so make sure
- * we don't do anything bigger than that
- */
- spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull);
-
- if (spapr->rma_size > node0_size) {
- error_report("Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")",
- spapr->rma_size);
- exit(1);
- }
+ spapr->rma_size = spapr_rma_size(spapr, &error_fatal);
/* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
spapr_create_lmb_dr_connectors(spapr);
}
- if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI_MCE) == SPAPR_CAP_ON) {
+ if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_ON) {
/* Create the error string for live migration blocker */
error_setg(&spapr->fwnmi_migration_blocker,
"A machine check is being handled during migration. The handler"
}
}
- if (spapr->rma_size < (MIN_RMA_SLOF * MiB)) {
- error_report(
- "pSeries SLOF firmware requires >= %ldM guest RMA (Real Mode Area memory)",
- MIN_RMA_SLOF);
- exit(1);
- }
-
if (kernel_filename) {
uint64_t lowaddr = 0;
kvmppc_spapr_enable_inkernel_multitce();
}
- qemu_cond_init(&spapr->mc_delivery_cond);
+ qemu_cond_init(&spapr->fwnmi_machine_check_interlock_cond);
}
static int spapr_kvm_type(MachineState *machine, const char *vm_type)
void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
{
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+
cpu_synchronize_state(cs);
- ppc_cpu_do_system_reset(cs);
+ /* If FWNMI is inactive, addr will be -1, which will deliver to 0x100 */
+ if (spapr->fwnmi_system_reset_addr != -1) {
+ uint64_t rtas_addr, addr;
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
+ /* get rtas addr from fdt */
+ rtas_addr = spapr_get_rtas_addr();
+ if (!rtas_addr) {
+ qemu_system_guest_panicked(NULL);
+ return;
+ }
+
+ addr = rtas_addr + RTAS_ERROR_LOG_MAX + cs->cpu_index * sizeof(uint64_t)*2;
+ stq_be_phys(&address_space_memory, addr, env->gpr[3]);
+ stq_be_phys(&address_space_memory, addr + sizeof(uint64_t), 0);
+ env->gpr[3] = addr;
+ }
+ ppc_cpu_do_system_reset(cs, spapr->fwnmi_system_reset_addr);
}
static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
addr = spapr_drc_index(drc) * SPAPR_MEMORY_BLOCK_SIZE;
node = object_property_get_uint(OBJECT(drc->dev), PC_DIMM_NODE_PROP,
&error_abort);
- *fdt_start_offset = spapr_populate_memory_node(fdt, node, addr,
- SPAPR_MEMORY_BLOCK_SIZE);
+ *fdt_start_offset = spapr_dt_memory_node(fdt, node, addr,
+ SPAPR_MEMORY_BLOCK_SIZE);
return 0;
}
offset = fdt_add_subnode(fdt, 0, nodename);
g_free(nodename);
- spapr_populate_cpu_dt(cs, fdt, offset, spapr);
+ spapr_dt_cpu(cs, fdt, offset, spapr);
*fdt_start_offset = offset;
return 0;
smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_ON;
- smc->default_caps.caps[SPAPR_CAP_FWNMI_MCE] = SPAPR_CAP_ON;
+ smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_ON;
spapr_caps_add_properties(smc, &error_abort);
smc->irq = &spapr_irq_dual;
smc->dr_phb_enabled = true;
spapr_machine_5_0_class_options(mc);
compat_props_add(mc->compat_props, hw_compat_4_2, hw_compat_4_2_len);
smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
- smc->default_caps.caps[SPAPR_CAP_FWNMI_MCE] = SPAPR_CAP_OFF;
+ smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_OFF;
+ smc->rma_limit = 16 * GiB;
mc->nvdimm_supported = false;
}
}
}
-static void cap_fwnmi_mce_apply(SpaprMachineState *spapr, uint8_t val,
+static void cap_fwnmi_apply(SpaprMachineState *spapr, uint8_t val,
Error **errp)
{
if (!val) {
return; /* Disabled by default */
}
- if (tcg_enabled()) {
- warn_report("Firmware Assisted Non-Maskable Interrupts(FWNMI) not "
- "supported in TCG");
- } else if (kvm_enabled()) {
+ if (kvm_enabled()) {
if (kvmppc_set_fwnmi() < 0) {
error_setg(errp, "Firmware Assisted Non-Maskable Interrupts(FWNMI) "
"not supported by KVM");
.type = "bool",
.apply = cap_ccf_assist_apply,
},
- [SPAPR_CAP_FWNMI_MCE] = {
- .name = "fwnmi-mce",
- .description = "Handle fwnmi machine check exceptions",
- .index = SPAPR_CAP_FWNMI_MCE,
+ [SPAPR_CAP_FWNMI] = {
+ .name = "fwnmi",
+ .description = "Implements PAPR FWNMI option",
+ .index = SPAPR_CAP_FWNMI,
.get = spapr_cap_get_bool,
.set = spapr_cap_set_bool,
.type = "bool",
- .apply = cap_fwnmi_mce_apply,
+ .apply = cap_fwnmi_apply,
},
};
SPAPR_CAP_MIG_STATE(nested_kvm_hv, SPAPR_CAP_NESTED_KVM_HV);
SPAPR_CAP_MIG_STATE(large_decr, SPAPR_CAP_LARGE_DECREMENTER);
SPAPR_CAP_MIG_STATE(ccf_assist, SPAPR_CAP_CCF_ASSIST);
-SPAPR_CAP_MIG_STATE(fwnmi, SPAPR_CAP_FWNMI_MCE);
+SPAPR_CAP_MIG_STATE(fwnmi, SPAPR_CAP_FWNMI);
void spapr_caps_init(SpaprMachineState *spapr)
{
* the settings below ensure proper operations with TCG in absence of
* a real hypervisor.
*
- * Clearing VPM0 will also cause us to use RMOR in mmu-hash64.c for
- * real mode accesses, which thankfully defaults to 0 and isn't
- * accessible in guest mode.
- *
* Disable Power-saving mode Exit Cause exceptions for the CPU, so
* we don't get spurious wakups before an RTAS start-cpu call.
* For the same reason, set PSSCR_EC.
*/
- lpcr &= ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV | pcc->lpcr_pm);
+ lpcr &= ~(LPCR_VPM1 | LPCR_ISL | LPCR_KBV | pcc->lpcr_pm);
lpcr |= LPCR_LPES0 | LPCR_LPES1;
env->spr[SPR_PSSCR] |= PSSCR_EC;
- /* Set RMLS to the max (ie, 16G) */
- lpcr &= ~LPCR_RMLS;
- lpcr |= 1ull << LPCR_RMLS_SHIFT;
-
ppc_store_lpcr(cpu, lpcr);
/* Set a full AMOR so guest can use the AMR as it sees fit */
spapr_irq_cpu_intc_reset(spapr, cpu);
}
-void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3)
+void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip,
+ target_ulong r1, target_ulong r3,
+ target_ulong r4)
{
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
CPUPPCState *env = &cpu->env;
env->nip = nip;
+ env->gpr[1] = r1;
env->gpr[3] = r3;
+ env->gpr[4] = r4;
kvmppc_set_reg_ppc_online(cpu, 1);
CPU(cpu)->halted = 0;
/* Enable Power-saving mode Exit Cause exceptions */
{
SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
CPUState *cs = CPU(cpu);
- uint64_t rtas_addr;
CPUPPCState *env = &cpu->env;
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
- target_ulong msr = 0;
+ uint64_t rtas_addr;
struct rtas_error_log log;
struct mc_extended_log *ext_elog;
uint32_t summary;
- /*
- * Properly set bits in MSR before we invoke the handler.
- * SRR0/1, DAR and DSISR are properly set by KVM
- */
- if (!(*pcc->interrupts_big_endian)(cpu)) {
- msr |= (1ULL << MSR_LE);
- }
-
- if (env->msr & (1ULL << MSR_SF)) {
- msr |= (1ULL << MSR_SF);
- }
-
- msr |= (1ULL << MSR_ME);
-
ext_elog = g_malloc0(sizeof(*ext_elog));
summary = spapr_mce_get_elog_type(cpu, recovered, ext_elog);
/* get rtas addr from fdt */
rtas_addr = spapr_get_rtas_addr();
if (!rtas_addr) {
- /* Unable to fetch rtas_addr. Hence reset the guest */
- ppc_cpu_do_system_reset(cs);
+ qemu_system_guest_panicked(NULL);
g_free(ext_elog);
return;
}
cpu_physical_memory_write(rtas_addr + RTAS_ERROR_LOG_OFFSET +
sizeof(env->gpr[3]) + sizeof(log), ext_elog,
sizeof(*ext_elog));
+ g_free(ext_elog);
env->gpr[3] = rtas_addr + RTAS_ERROR_LOG_OFFSET;
- env->msr = msr;
- env->nip = spapr->guest_machine_check_addr;
- g_free(ext_elog);
+ ppc_cpu_do_fwnmi_machine_check(cs, spapr->fwnmi_machine_check_addr);
}
void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered)
int ret;
Error *local_err = NULL;
- if (spapr->guest_machine_check_addr == -1) {
+ if (spapr->fwnmi_machine_check_addr == -1) {
/*
* This implies that we have hit a machine check either when the
* guest has not registered FWNMI (i.e., "ibm,nmi-register" not
return;
}
- while (spapr->mc_status != -1) {
+ while (spapr->fwnmi_machine_check_interlock != -1) {
/*
* Check whether the same CPU got machine check error
* while still handling the mc error (i.e., before
* that CPU called "ibm,nmi-interlock")
*/
- if (spapr->mc_status == cpu->vcpu_id) {
+ if (spapr->fwnmi_machine_check_interlock == cpu->vcpu_id) {
qemu_system_guest_panicked(NULL);
return;
}
- qemu_cond_wait_iothread(&spapr->mc_delivery_cond);
+ qemu_cond_wait_iothread(&spapr->fwnmi_machine_check_interlock_cond);
/* Meanwhile if the system is reset, then just return */
- if (spapr->guest_machine_check_addr == -1) {
+ if (spapr->fwnmi_machine_check_addr == -1) {
return;
}
}
warn_report("Received a fwnmi while migration was in progress");
}
- spapr->mc_status = cpu->vcpu_id;
+ spapr->fwnmi_machine_check_interlock = cpu->vcpu_id;
spapr_mce_dispatch_elog(cpu, recovered);
}
}
}
+void spapr_clear_pending_hotplug_events(SpaprMachineState *spapr)
+{
+ SpaprEventLogEntry *entry = NULL, *next_entry;
+
+ QTAILQ_FOREACH_SAFE(entry, &spapr->pending_events, next, next_entry) {
+ if (spapr_event_log_entry_type(entry) == RTAS_LOG_TYPE_HOTPLUG) {
+ QTAILQ_REMOVE(&spapr->pending_events, entry, next);
+ g_free(entry->extended_log);
+ g_free(entry);
+ }
+ }
+}
+
void spapr_events_init(SpaprMachineState *spapr)
{
int epow_irq = SPAPR_IRQ_EPOW;
spapr_free_hpt(spapr);
} else if (!(patbe_new & PATE1_GR)) {
/* RADIX->HASH || NOTHING->HASH : Allocate HPT */
- spapr_setup_hpt_and_vrma(spapr);
+ spapr_setup_hpt(spapr);
}
return;
}
return best_compat;
}
-static bool spapr_transient_dev_before_cas(void)
+static void spapr_handle_transient_dev_before_cas(SpaprMachineState *spapr)
{
Object *drc_container;
ObjectProperty *prop;
prop->name, NULL));
if (spapr_drc_transient(drc)) {
- return true;
+ spapr_drc_reset(drc);
}
}
- return false;
+
+ spapr_clear_pending_hotplug_events(spapr);
}
static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
spapr_irq_update_active_intc(spapr);
- if (spapr_transient_dev_before_cas()) {
- spapr->cas_reboot = true;
- }
+ spapr_handle_transient_dev_before_cas(spapr);
if (!spapr->cas_reboot) {
void *fdt;
* (because the guest isn't going to use radix) then set it up here. */
if ((spapr->patb_entry & PATE1_GR) && !guest_radix) {
/* legacy hash or new hash: */
- spapr_setup_hpt_and_vrma(spapr);
+ spapr_setup_hpt(spapr);
}
if (fdt_bufsize < sizeof(hdr)) {
{
char *uuidstr = NULL;
QemuUUID uuid;
+ int ret;
if (size % SPAPR_MINIMUM_SCM_BLOCK_SIZE) {
error_setg(errp, "NVDIMM memory size excluding the label area"
return;
}
- uuidstr = object_property_get_str(OBJECT(nvdimm), NVDIMM_UUID_PROP, NULL);
- qemu_uuid_parse(uuidstr, &uuid);
+ uuidstr = object_property_get_str(OBJECT(nvdimm), NVDIMM_UUID_PROP,
+ &error_abort);
+ ret = qemu_uuid_parse(uuidstr, &uuid);
+ g_assert(!ret);
g_free(uuidstr);
if (qemu_uuid_is_null(&uuid)) {
return ov;
}
-int spapr_ovec_populate_dt(void *fdt, int fdt_offset,
- SpaprOptionVector *ov, const char *name)
+int spapr_dt_ovec(void *fdt, int fdt_offset,
+ SpaprOptionVector *ov, const char *name)
{
uint8_t vec[OV_MAXBYTES + 1];
uint16_t vec_len;
*/
newcpu->env.tb_env->tb_offset = callcpu->env.tb_env->tb_offset;
- spapr_cpu_set_entry_state(newcpu, start, r3);
+ spapr_cpu_set_entry_state(newcpu, start, 0, r3, 0);
qemu_cpu_kick(CPU(newcpu));
uint32_t nret, target_ulong rets)
{
hwaddr rtas_addr;
+ target_ulong sreset_addr, mce_addr;
- if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI_MCE) == SPAPR_CAP_OFF) {
+ if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_OFF) {
rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
return;
}
return;
}
- spapr->guest_machine_check_addr = rtas_ld(args, 1);
+ sreset_addr = rtas_ld(args, 0);
+ mce_addr = rtas_ld(args, 1);
+
+ /* PAPR requires these are in the first 32M of memory and within RMA */
+ if (sreset_addr >= 32 * MiB || sreset_addr >= spapr->rma_size ||
+ mce_addr >= 32 * MiB || mce_addr >= spapr->rma_size) {
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+ return;
+ }
+
+ spapr->fwnmi_system_reset_addr = sreset_addr;
+ spapr->fwnmi_machine_check_addr = mce_addr;
+
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
target_ulong args,
uint32_t nret, target_ulong rets)
{
- if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI_MCE) == SPAPR_CAP_OFF) {
+ if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_OFF) {
rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
return;
}
- if (spapr->guest_machine_check_addr == -1) {
+ if (spapr->fwnmi_machine_check_addr == -1) {
/* NMI register not called */
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
- if (spapr->mc_status != cpu->vcpu_id) {
- /* The vCPU that hit the NMI should invoke "ibm,nmi-interlock" */
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+ if (spapr->fwnmi_machine_check_interlock != cpu->vcpu_id) {
+ /*
+ * The vCPU that hit the NMI should invoke "ibm,nmi-interlock"
+ * This should be PARAM_ERROR, but Linux calls "ibm,nmi-interlock"
+ * for system reset interrupts, despite them not being interlocked.
+ * PowerVM silently ignores this and returns success here. Returning
+ * failure causes Linux to print the error "FWNMI: nmi-interlock
+ * failed: -3", although no other apparent ill effects, this is a
+ * regression for the user when enabling FWNMI. So for now, match
+ * PowerVM. When most Linux clients are fixed, this could be
+ * changed.
+ */
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
return;
}
/*
* vCPU issuing "ibm,nmi-interlock" is done with NMI handling,
- * hence unset mc_status.
+ * hence unset fwnmi_machine_check_interlock.
*/
- spapr->mc_status = -1;
- qemu_cond_signal(&spapr->mc_delivery_cond);
+ spapr->fwnmi_machine_check_interlock = -1;
+ qemu_cond_signal(&spapr->fwnmi_machine_check_interlock_cond);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
migrate_del_blocker(spapr->fwnmi_migration_blocker);
}
#define VSCSI_MAX_SECTORS 4096
#define VSCSI_REQ_LIMIT 24
+/* Maximum size of a IU payload */
+#define SRP_MAX_IU_DATA_LEN (SRP_MAX_IU_LEN - sizeof(union srp_iu))
#define SRP_RSP_SENSE_DATA_LEN 18
#define SRP_REPORT_LUNS_WLUN 0xc10100000000000ULL
typedef struct vscsi_req {
vscsi_crq crq;
- union viosrp_iu iu;
+ uint8_t viosrp_iu_buf[SRP_MAX_IU_LEN];
/* SCSI request tracking */
SCSIRequest *sreq;
vscsi_req reqs[VSCSI_REQ_LIMIT];
} VSCSIState;
+static union viosrp_iu *req_iu(vscsi_req *req)
+{
+ return (union viosrp_iu *)req->viosrp_iu_buf;
+}
+
static struct vscsi_req *vscsi_get_req(VSCSIState *s)
{
vscsi_req *req;
for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
req = &s->reqs[i];
- if (req->iu.srp.cmd.tag == srp_tag) {
+ if (req_iu(req)->srp.cmd.tag == srp_tag) {
return req;
}
}
{
long rc, rc1;
+ assert(length <= SRP_MAX_IU_LEN);
+
/* First copy the SRP */
rc = spapr_vio_dma_write(&s->vdev, req->crq.s.IU_data_ptr,
- &req->iu, length);
+ &req->viosrp_iu_buf, length);
if (rc) {
fprintf(stderr, "vscsi_send_iu: DMA write failure !\n");
}
req->crq.s.reserved = 0x00;
req->crq.s.timeout = cpu_to_be16(0x0000);
req->crq.s.IU_length = cpu_to_be16(length);
- req->crq.s.IU_data_ptr = req->iu.srp.rsp.tag; /* right byte order */
+ req->crq.s.IU_data_ptr = req_iu(req)->srp.rsp.tag; /* right byte order */
if (rc == 0) {
req->crq.s.status = VIOSRP_OK;
static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req,
uint8_t status, int32_t res_in, int32_t res_out)
{
- union viosrp_iu *iu = &req->iu;
+ union viosrp_iu *iu = req_iu(req);
uint64_t tag = iu->srp.rsp.tag;
int total_len = sizeof(iu->srp.rsp);
uint8_t sol_not = iu->srp.cmd.sol_not;
if (status) {
iu->srp.rsp.sol_not = (sol_not & 0x04) >> 2;
if (req->senselen) {
- req->iu.srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
- req->iu.srp.rsp.sense_data_len = cpu_to_be32(req->senselen);
- memcpy(req->iu.srp.rsp.data, req->sense, req->senselen);
- total_len += req->senselen;
+ int sense_data_len = MIN(req->senselen, SRP_MAX_IU_DATA_LEN);
+
+ iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+ iu->srp.rsp.sense_data_len = cpu_to_be32(sense_data_len);
+ memcpy(iu->srp.rsp.data, req->sense, sense_data_len);
+ total_len += sense_data_len;
}
} else {
iu->srp.rsp.sol_not = (sol_not & 0x02) >> 1;
unsigned n, unsigned buf_offset,
struct srp_direct_buf *ret)
{
- struct srp_cmd *cmd = &req->iu.srp.cmd;
+ struct srp_cmd *cmd = &req_iu(req)->srp.cmd;
switch (req->dma_fmt) {
case SRP_NO_DATA_DESC: {
static int vscsi_preprocess_desc(vscsi_req *req)
{
- struct srp_cmd *cmd = &req->iu.srp.cmd;
+ struct srp_cmd *cmd = &req_iu(req)->srp.cmd;
req->cdb_offset = cmd->add_cdb_len & ~3;
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_BUFFER(crq.raw, vscsi_req),
- VMSTATE_BUFFER(iu.srp.reserved, vscsi_req),
+ VMSTATE_BUFFER(viosrp_iu_buf, vscsi_req),
VMSTATE_UINT32(qtag, vscsi_req),
VMSTATE_BOOL(active, vscsi_req),
VMSTATE_UINT32(data_len, vscsi_req),
static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
{
- union viosrp_iu *iu = &req->iu;
+ union viosrp_iu *iu = req_iu(req);
struct srp_login_rsp *rsp = &iu->srp.login_rsp;
uint64_t tag = iu->srp.rsp.tag;
*/
rsp->req_lim_delta = cpu_to_be32(VSCSI_REQ_LIMIT-2);
rsp->tag = tag;
- rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
- rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu));
+ rsp->max_it_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
+ rsp->max_ti_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
/* direct and indirect */
rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT);
static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
{
- uint8_t *cdb = req->iu.srp.cmd.cdb;
+ uint8_t *cdb = req_iu(req)->srp.cmd.cdb;
uint8_t resp_data[36];
int rc, len, alen;
static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
{
- union srp_iu *srp = &req->iu.srp;
+ union srp_iu *srp = &req_iu(req)->srp;
SCSIDevice *sdev;
int n, lun;
static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
{
- union viosrp_iu *iu = &req->iu;
+ union viosrp_iu *iu = req_iu(req);
vscsi_req *tmpreq;
int i, lun = 0, resp = SRP_TSK_MGMT_COMPLETE;
SCSIDevice *d;
uint64_t tag = iu->srp.rsp.tag;
uint8_t sol_not = iu->srp.cmd.sol_not;
- fprintf(stderr, "vscsi_process_tsk_mgmt %02x\n",
- iu->srp.tsk_mgmt.tsk_mgmt_func);
-
- d = vscsi_device_find(&s->bus, be64_to_cpu(req->iu.srp.tsk_mgmt.lun), &lun);
+ trace_spapr_vscsi_process_tsk_mgmt(iu->srp.tsk_mgmt.tsk_mgmt_func);
+ d = vscsi_device_find(&s->bus,
+ be64_to_cpu(req_iu(req)->srp.tsk_mgmt.lun), &lun);
if (!d) {
resp = SRP_TSK_MGMT_FIELDS_INVALID;
} else {
break;
}
- tmpreq = vscsi_find_req(s, req->iu.srp.tsk_mgmt.task_tag);
+ tmpreq = vscsi_find_req(s, req_iu(req)->srp.tsk_mgmt.task_tag);
if (tmpreq && tmpreq->sreq) {
assert(tmpreq->sreq->hba_private);
scsi_req_cancel(tmpreq->sreq);
for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
tmpreq = &s->reqs[i];
- if (tmpreq->iu.srp.cmd.lun != req->iu.srp.tsk_mgmt.lun) {
+ if (req_iu(tmpreq)->srp.cmd.lun
+ != req_iu(req)->srp.tsk_mgmt.lun) {
continue;
}
if (!tmpreq->active || !tmpreq->sreq) {
}
/* Compose the response here as */
+ QEMU_BUILD_BUG_ON(SRP_MAX_IU_DATA_LEN < 4);
memset(iu, 0, sizeof(struct srp_rsp) + 4);
iu->srp.rsp.opcode = SRP_RSP;
iu->srp.rsp.req_lim_delta = cpu_to_be32(1);
static int vscsi_handle_srp_req(VSCSIState *s, vscsi_req *req)
{
- union srp_iu *srp = &req->iu.srp;
+ union srp_iu *srp = &req_iu(req)->srp;
int done = 1;
uint8_t opcode = srp->rsp.opcode;
struct mad_adapter_info_data info;
int rc;
- sinfo = &req->iu.mad.adapter_info;
+ sinfo = &req_iu(req)->mad.adapter_info;
#if 0 /* What for ? */
rc = spapr_vio_dma_read(&s->vdev, be64_to_cpu(sinfo->buffer),
uint64_t buffer;
int rc;
- vcap = &req->iu.mad.capabilities;
+ vcap = &req_iu(req)->mad.capabilities;
req_len = len = be16_to_cpu(vcap->common.length);
buffer = be64_to_cpu(vcap->buffer);
if (len > sizeof(cap)) {
static int vscsi_handle_mad_req(VSCSIState *s, vscsi_req *req)
{
- union mad_iu *mad = &req->iu.mad;
+ union mad_iu *mad = &req_iu(req)->mad;
bool request_handled = false;
uint64_t retlen = 0;
* in our 256 bytes IUs. If not we'll have to increase the size
* of the structure.
*/
- if (crq->s.IU_length > sizeof(union viosrp_iu)) {
+ if (crq->s.IU_length > SRP_MAX_IU_LEN) {
fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n",
crq->s.IU_length);
vscsi_put_req(req);
}
/* XXX Handle failure differently ? */
- if (spapr_vio_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu,
+ if (spapr_vio_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->viosrp_iu_buf,
crq->s.IU_length)) {
fprintf(stderr, "vscsi_got_payload: DMA read failure !\n");
vscsi_put_req(req);
spapr_vscsi_save_request(uint32_t qtag, unsigned desc, unsigned offset) "saving tag=%"PRIu32", current desc#%u, offset=0x%x"
spapr_vscsi_load_request(uint32_t qtag, unsigned desc, unsigned offset) "restoring tag=%"PRIu32", current desc#%u, offset=0x%x"
spapr_vscsi_process_login(void) "Got login, sending response !"
+spapr_vscsi_process_tsk_mgmt(uint8_t func) "tsk_mgmt_func 0x%02x"
spapr_vscsi_queue_cmd_no_drive(uint64_t lun) "Command for lun 0x%08" PRIx64 " with no drive"
spapr_vscsi_queue_cmd(uint32_t qtag, unsigned cdb, const char *cmd, int lun, int ret) "Queued command tag 0x%"PRIx32" CMD 0x%x=%s LUN %d ret: %d"
spapr_vscsi_do_crq(unsigned c0, unsigned c1) "crq: %02x %02x ..."
#ifndef PPC_VIOSRP_H
#define PPC_VIOSRP_H
+#include "hw/scsi/srp.h"
+
#define SRP_VERSION "16.a"
#define SRP_MAX_IU_LEN 256
#define SRP_MAX_LOC_LEN 32
struct srp_tsk_mgmt tsk_mgmt;
struct srp_cmd cmd;
struct srp_rsp rsp;
- uint8_t reserved[SRP_MAX_IU_LEN];
};
enum viosrp_crq_formats {
carddev = qdev_create(BUS(&s->sdbus), TYPE_SD_CARD);
if (dinfo) {
qdev_prop_set_drive(carddev, "drive", blk_by_legacy_dinfo(dinfo), &err);
+ if (err) {
+ goto fail;
+ }
}
+
object_property_set_bool(OBJECT(carddev), true, "spi", &err);
+ if (err) {
+ goto fail;
+ }
+
object_property_set_bool(OBJECT(carddev), true, "realized", &err);
if (err) {
- error_setg(errp, "failed to init SD card: %s", error_get_pretty(err));
- return;
+ goto fail;
}
+
+ return;
+
+fail:
+ error_propagate_prepend(errp, err, "failed to init SD card: ");
}
static void ssi_sd_reset(DeviceState *dev)
#include "hw/sparc/sparc64.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/sysbus.h"
-#include "hw/ide.h"
#include "hw/ide/pci.h"
#include "hw/loader.h"
#include "hw/fw-path-provider.h"
PCIBus *pci_bus, *pci_busA, *pci_busB;
PCIDevice *ebus, *pci_dev;
SysBusDevice *s;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
DeviceState *iommu, *dev;
FWCfgState *fw_cfg;
NICInfo *nd;
qemu_macaddr_default_if_unset(&macaddr);
}
- ide_drive_get(hd, ARRAY_SIZE(hd));
-
pci_dev = pci_create(pci_busA, PCI_DEVFN(3, 0), "cmd646-ide");
qdev_prop_set_uint32(&pci_dev->qdev, "secondary", 1);
qdev_init_nofail(&pci_dev->qdev);
- pci_ide_create_devs(pci_dev, hd);
+ pci_ide_create_devs(pci_dev);
/* Map NVRAM into I/O (ebus) space */
nvram = m48t59_init(NULL, 0, 0, NVRAM_SIZE, 1968, 59);
void gdbserver_fork(CPUState *);
#endif
/* Get or set a register. Returns the size of the register. */
-typedef int (*gdb_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
+typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg);
+typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
void gdb_register_coprocessor(CPUState *cpu,
- gdb_reg_cb get_reg, gdb_reg_cb set_reg,
+ gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
int num_regs, const char *xml, int g_pos);
-/* The GDB remote protocol transfers values in target byte order. This means
- * we can use the raw memory access routines to access the value buffer.
- * Conveniently, these also handle the case where the buffer is mis-aligned.
+/*
+ * The GDB remote protocol transfers values in target byte order. As
+ * the gdbstub may be batching up several register values we always
+ * append to the array.
*/
-static inline int gdb_get_reg8(uint8_t *mem_buf, uint8_t val)
+static inline int gdb_get_reg8(GByteArray *buf, uint8_t val)
{
- stb_p(mem_buf, val);
+ g_byte_array_append(buf, &val, 1);
return 1;
}
-static inline int gdb_get_reg16(uint8_t *mem_buf, uint16_t val)
+static inline int gdb_get_reg16(GByteArray *buf, uint16_t val)
{
- stw_p(mem_buf, val);
+ uint16_t to_word = tswap16(val);
+ g_byte_array_append(buf, (uint8_t *) &to_word, 2);
return 2;
}
-static inline int gdb_get_reg32(uint8_t *mem_buf, uint32_t val)
+static inline int gdb_get_reg32(GByteArray *buf, uint32_t val)
{
- stl_p(mem_buf, val);
+ uint32_t to_long = tswap32(val);
+ g_byte_array_append(buf, (uint8_t *) &to_long, 4);
return 4;
}
-static inline int gdb_get_reg64(uint8_t *mem_buf, uint64_t val)
+static inline int gdb_get_reg64(GByteArray *buf, uint64_t val)
{
- stq_p(mem_buf, val);
+ uint64_t to_quad = tswap64(val);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
return 8;
}
+static inline int gdb_get_reg128(GByteArray *buf, uint64_t val_hi,
+ uint64_t val_lo)
+{
+ uint64_t to_quad;
+#ifdef TARGET_WORDS_BIGENDIAN
+ to_quad = tswap64(val_hi);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+ to_quad = tswap64(val_lo);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+#else
+ to_quad = tswap64(val_lo);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+ to_quad = tswap64(val_hi);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+#endif
+ return 16;
+}
+
+/**
+ * gdb_get_reg_ptr: get pointer to start of last element
+ * @len: length of element
+ *
+ * This is a helper function to extract the pointer to the last
+ * element for additional processing. Some front-ends do additional
+ * dynamic swapping of the elements based on CPU state.
+ */
+static inline uint8_t * gdb_get_reg_ptr(GByteArray *buf, int len)
+{
+ return buf->data + buf->len - len;
+}
+
#if TARGET_LONG_BITS == 64
#define gdb_get_regl(buf, val) gdb_get_reg64(buf, val)
#define ldtul_p(addr) ldq_p(addr)
hwaddr (*get_phys_page_attrs_debug)(CPUState *cpu, vaddr addr,
MemTxAttrs *attrs);
int (*asidx_from_attrs)(CPUState *cpu, MemTxAttrs attrs);
- int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg);
+ int (*gdb_read_register)(CPUState *cpu, GByteArray *buf, int reg);
int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
bool (*debug_check_watchpoint)(CPUState *cpu, CPUWatchpoint *wp);
void (*debug_excp_handler)(CPUState *cpu);
#define HW_IDE_H
#include "hw/isa/isa.h"
-#include "hw/pci/pci.h"
#include "exec/memory.h"
-#define MAX_IDE_DEVS 2
-
/* ide-isa.c */
ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq,
DriveInfo *hd0, DriveInfo *hd1);
/* ide-pci.c */
-void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
- int secondary_ide_enabled);
-PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
-PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
-PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux);
-void via_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
/* ide-mmio.c */
void mmio_ide_init_drives(DeviceState *dev, DriveInfo *hd0, DriveInfo *hd1);
#define TYPE_IDE_BUS "IDE"
#define IDE_BUS(obj) OBJECT_CHECK(IDEBus, (obj), TYPE_IDE_BUS)
+#define MAX_IDE_DEVS 2
+
/* Bits of HD_STATUS */
#define ERR_STAT 0x01
#define INDEX_STAT 0x02
#define HW_IDE_PCI_H
#include "hw/ide/internal.h"
+#include "hw/pci/pci.h"
#define BM_STATUS_DMAING 0x01
#define BM_STATUS_ERROR 0x02
void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d);
void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val);
extern MemoryRegionOps bmdma_addr_ioport_ops;
-void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table);
+void pci_ide_create_devs(PCIDevice *dev);
extern const VMStateDescription vmstate_ide_pci;
extern const MemoryRegionOps pci_ide_cmd_le_ops;
#define MACIO_H
#include "hw/char/escc.h"
+#include "hw/pci/pci.h"
#include "hw/ide/internal.h"
#include "hw/intc/heathrow_pic.h"
#include "hw/misc/macio/cuda.h"
#define SPAPR_CAP_LARGE_DECREMENTER 0x08
/* Count Cache Flush Assist HW Instruction */
#define SPAPR_CAP_CCF_ASSIST 0x09
-/* FWNMI machine check handling */
-#define SPAPR_CAP_FWNMI_MCE 0x0A
+/* Implements PAPR FWNMI option */
+#define SPAPR_CAP_FWNMI 0x0A
/* Num Caps */
-#define SPAPR_CAP_NUM (SPAPR_CAP_FWNMI_MCE + 1)
+#define SPAPR_CAP_NUM (SPAPR_CAP_FWNMI + 1)
/*
* Capability Values
bool pre_4_1_migration; /* don't migrate hpt-max-page-size */
bool linux_pci_probe;
bool smp_threads_vsmt; /* set VSMT to smp_threads by default */
+ hwaddr rma_limit; /* clamp the RMA to this size */
void (*phb_placement)(SpaprMachineState *spapr, uint32_t index,
uint64_t *buid, hwaddr *pio,
SpaprPendingHpt *pending_hpt; /* in-progress resize */
hwaddr rma_size;
- int vrma_adjust;
uint32_t fdt_size;
uint32_t fdt_initial_size;
void *fdt_blob;
* occurs during the unplug process. */
QTAILQ_HEAD(, SpaprDimmState) pending_dimm_unplugs;
- /* State related to "ibm,nmi-register" and "ibm,nmi-interlock" calls */
- target_ulong guest_machine_check_addr;
- /*
- * mc_status is set to -1 if mc is not in progress, else is set to the CPU
- * handling the mc.
+ /* State related to FWNMI option */
+
+ /* System Reset and Machine Check Notification Routine addresses
+ * registered by "ibm,nmi-register" RTAS call.
+ */
+ target_ulong fwnmi_system_reset_addr;
+ target_ulong fwnmi_machine_check_addr;
+
+ /* Machine Check FWNMI synchronization, fwnmi_machine_check_interlock is
+ * set to -1 if a FWNMI machine check is not in progress, else is set to
+ * the CPU that was delivered the machine check, and is set back to -1
+ * when that CPU makes an "ibm,nmi-interlock" RTAS call. The cond is used
+ * to synchronize other CPUs.
*/
- int mc_status;
- QemuCond mc_delivery_cond;
+ int fwnmi_machine_check_interlock;
+ QemuCond fwnmi_machine_check_interlock_cond;
/*< public >*/
char *kvm_type;
#define SPAPR_IS_PCI_LIOBN(liobn) (!!((liobn) & 0x80000000))
#define SPAPR_PCI_DMA_WINDOW_NUM(liobn) ((liobn) & 0xff)
+#define RTAS_SIZE 2048
#define RTAS_ERROR_LOG_MAX 2048
/* Offset from rtas-base where error log is placed */
void spapr_events_init(SpaprMachineState *sm);
void spapr_dt_events(SpaprMachineState *sm, void *fdt);
void close_htab_fd(SpaprMachineState *spapr);
-void spapr_setup_hpt_and_vrma(SpaprMachineState *spapr);
+void spapr_setup_hpt(SpaprMachineState *spapr);
void spapr_free_hpt(SpaprMachineState *spapr);
SpaprTceTable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn);
void spapr_tce_table_enable(SpaprTceTable *tcet,
void spapr_reallocate_hpt(SpaprMachineState *spapr, int shift,
Error **errp);
void spapr_clear_pending_events(SpaprMachineState *spapr);
+void spapr_clear_pending_hotplug_events(SpaprMachineState *spapr);
int spapr_max_server_number(SpaprMachineState *spapr);
void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
uint64_t pte0, uint64_t pte1);
} SpaprCpuCoreClass;
const char *spapr_get_cpu_core_type(const char *cpu_type);
-void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3);
+void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip,
+ target_ulong r1, target_ulong r3,
+ target_ulong r4);
typedef struct SpaprCpuState {
uint64_t vpa_addr;
void spapr_ovec_clear(SpaprOptionVector *ov, long bitnr);
bool spapr_ovec_test(SpaprOptionVector *ov, long bitnr);
SpaprOptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector);
-int spapr_ovec_populate_dt(void *fdt, int fdt_offset,
- SpaprOptionVector *ov, const char *name);
+int spapr_dt_ovec(void *fdt, int fdt_offset,
+ SpaprOptionVector *ov, const char *name);
/* migration */
extern const VMStateDescription vmstate_spapr_ovec;
PIIX3State *piix3_create(PCIBus *pci_bus, ISABus **isa_bus);
-DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus,
- I2CBus **smbus, size_t ide_buses);
+DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, I2CBus **smbus);
#endif
unsigned rxfilter_notify_enabled:1;
int vring_enable;
int vnet_hdr_len;
+ bool is_netdev;
QTAILQ_HEAD(, NetFilterState) filters;
};
void hmp_host_net_add(Monitor *mon, const QDict *qdict);
void hmp_host_net_remove(Monitor *mon, const QDict *qdict);
void netdev_add(QemuOpts *opts, Error **errp);
-void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp);
int net_hub_id_for_client(NetClientState *nc, int *id);
NetClientState *net_hub_port_find(int hub_id);
void qmp_register_command(QmpCommandList *cmds, const char *name,
QmpCommandFunc *fn, QmpCommandOptions options);
-QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name);
+const QmpCommand *qmp_find_command(const QmpCommandList *cmds,
+ const char *name);
void qmp_disable_command(QmpCommandList *cmds, const char *name);
void qmp_enable_command(QmpCommandList *cmds, const char *name);
const char *qmp_command_name(const QmpCommand *cmd);
bool qmp_has_success_response(const QmpCommand *cmd);
QDict *qmp_error_response(Error *err);
-QDict *qmp_dispatch(QmpCommandList *cmds, QObject *request,
+QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
bool allow_oob);
bool qmp_is_oob(const QDict *dict);
-typedef void (*qmp_cmd_callback_fn)(QmpCommand *cmd, void *opaque);
+typedef void (*qmp_cmd_callback_fn)(const QmpCommand *cmd, void *opaque);
-void qmp_for_each_command(QmpCommandList *cmds, qmp_cmd_callback_fn fn,
+void qmp_for_each_command(const QmpCommandList *cmds, qmp_cmd_callback_fn fn,
void *opaque);
#endif
qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
QCO_NO_OPTIONS);
- qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add,
- QCO_NO_OPTIONS);
qmp_register_command(&qmp_commands, "object-add", qmp_object_add,
QCO_NO_OPTIONS);
count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_DRIVER_NIC,
MAX_QUEUE_NUM);
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
- QemuOpts *opts;
const char *name = ncs[i]->name;
if (strncmp(str, name, len)) {
continue;
}
- opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), name);
- if (opts) {
+ if (ncs[i]->is_netdev) {
readline_add_completion(rs, name);
}
}
* qmp_capabilities succeeds, we go into command mode, and
* @command becomes &qmp_commands.
*/
- QmpCommandList *commands;
+ const QmpCommandList *commands;
bool capab_offered[QMP_CAPABILITY__MAX]; /* capabilities offered */
bool capab[QMP_CAPABILITY__MAX]; /* offered and accepted */
/*
return info;
}
-static void query_commands_cb(QmpCommand *cmd, void *opaque)
+static void query_commands_cb(const QmpCommand *cmd, void *opaque)
{
CommandInfoList *info, **list = opaque;
}
return -1;
}
+
+ if (is_netdev) {
+ NetClientState *nc;
+
+ nc = qemu_find_netdev(netdev->id);
+ assert(nc);
+ nc->is_netdev = true;
+ }
+
return 0;
}
net_client_init(opts, true, errp);
}
-void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp)
+void qmp_netdev_add(Netdev *netdev, Error **errp)
{
- Error *local_err = NULL;
- QemuOptsList *opts_list;
- QemuOpts *opts;
-
- opts_list = qemu_find_opts_err("netdev", &local_err);
- if (local_err) {
- goto out;
- }
-
- opts = qemu_opts_from_qdict(opts_list, qdict, &local_err);
- if (local_err) {
- goto out;
- }
-
- netdev_add(opts, &local_err);
- if (local_err) {
- qemu_opts_del(opts);
- goto out;
- }
-
-out:
- error_propagate(errp, local_err);
+ net_client_init1(netdev, true, errp);
}
void qmp_netdev_del(const char *id, Error **errp)
{
NetClientState *nc;
- QemuOpts *opts;
nc = qemu_find_netdev(id);
if (!nc) {
return;
}
- opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), id);
- if (!opts) {
+ if (!nc->is_netdev) {
error_setg(errp, "Device '%s' is not a netdev", id);
return;
}
qemu_del_net_client(nc);
- qemu_opts_del(opts);
}
static void netfilter_print_info(Monitor *mon, NetFilterState *nf)
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
https://github.com/aik/SLOF, and the image currently in qemu is
- built from git tag qemu-slof-20191217.
+ built from git tag qemu-slof-20200317.
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as
self._vm_monitor = os.path.join(self._sock_dir,
self._name + "-monitor.sock")
self._remove_files.append(self._vm_monitor)
- self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True)
+ self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True,
+ nickname=self._name)
def _post_launch(self):
if self._qmp:
#: Logger object for debugging messages
logger = logging.getLogger('QMP')
- def __init__(self, address, server=False):
+ def __init__(self, address, server=False, nickname=None):
"""
Create a QEMUMonitorProtocol class.
self.__address = address
self.__sock = self.__get_sock()
self.__sockfile = None
+ self._nickname = nickname
+ if self._nickname:
+ self.logger = logging.getLogger('QMP').getChild(self._nickname)
if server:
self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.__sock.bind(self.__address)
#
# @encrypted: true if the backing device is encrypted
#
-# @encryption_key_missing: Deprecated; always false
+# @encryption_key_missing: always false
#
# @detect_zeroes: detect and optimize zero writes (Since 2.1)
#
# @dirty-bitmaps: dirty bitmaps information (only present if node
# has one or more dirty bitmaps) (Since 4.2)
#
+# Features:
+# @deprecated: Member @encryption_key_missing is deprecated. It is
+# always false.
+#
# Since: 0.14.0
#
##
{ 'struct': 'BlockDeviceInfo',
'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str',
'*backing_file': 'str', 'backing_file_depth': 'int',
- 'encrypted': 'bool', 'encryption_key_missing': 'bool',
+ 'encrypted': 'bool',
+ 'encryption_key_missing': { 'type': 'bool',
+ 'features': [ 'deprecated' ] },
'detect_zeroes': 'BlockdevDetectZeroesOptions',
'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
#
# @granularity: granularity of the dirty bitmap in bytes (since 1.4)
#
-# @status: Deprecated in favor of @recording and @locked. (since 2.4)
+# @status: current status of the dirty bitmap (since 2.4)
#
# @recording: true if the bitmap is recording new writes from the guest.
# Replaces `active` and `disabled` statuses. (since 4.0)
# @busy to be false. This bitmap cannot be used. To remove
# it, use @block-dirty-bitmap-remove. (Since 4.0)
#
+# Features:
+# @deprecated: Member @status is deprecated. Use @recording and
+# @locked instead.
+#
# Since: 1.3
##
{ 'struct': 'BlockDirtyInfo',
'data': {'*name': 'str', 'count': 'int', 'granularity': 'uint32',
- 'recording': 'bool', 'busy': 'bool', 'status': 'DirtyBitmapStatus',
+ 'recording': 'bool', 'busy': 'bool',
+ 'status': { 'type': 'DirtyBitmapStatus',
+ 'features': [ 'deprecated' ] },
'persistent': 'bool', '*inconsistent': 'bool' } }
##
#
# @dirty-bitmaps: dirty bitmaps information (only present if the
# driver has one or more dirty bitmaps) (Since 2.0)
-# Deprecated in 4.2; see BlockDeviceInfo instead.
#
# @io-status: @BlockDeviceIoStatus. Only present if the device
# supports it and the VM is configured to stop on errors
# @inserted: @BlockDeviceInfo describing the device if media is
# present
#
+# Features:
+# @deprecated: Member @dirty-bitmaps is deprecated. Use @inserted
+# member @dirty-bitmaps instead.
+#
# Since: 0.14.0
##
{ 'struct': 'BlockInfo',
'data': {'device': 'str', '*qdev': 'str', 'type': 'str', 'removable': 'bool',
'locked': 'bool', '*inserted': 'BlockDeviceInfo',
'*tray_open': 'bool', '*io-status': 'BlockDeviceIoStatus',
- '*dirty-bitmaps': ['BlockDirtyInfo'] } }
+ '*dirty-bitmaps': { 'type': ['BlockDirtyInfo'],
+ 'features': [ 'deprecated' ] } } }
##
# @BlockMeasureInfo:
# @base: Same as @base-node, except that it is a file name rather than a node
# name. This must be the exact filename string that was used to open the
# node; other strings, even if addressing the same file, are not
-# accepted (deprecated, use @base-node instead)
+# accepted
#
# @top-node: The node name of the backing image within the image chain
# which contains the topmost data to be committed down. If
# @top: Same as @top-node, except that it is a file name rather than a node
# name. This must be the exact filename string that was used to open the
# node; other strings, even if addressing the same file, are not
-# accepted (deprecated, use @base-node instead)
+# accepted
#
# @backing-file: The backing file string to write into the overlay
# image of 'top'. If 'top' is the active layer,
# list without user intervention.
# Defaults to true. (Since 3.1)
#
+# Features:
+# @deprecated: Members @base and @top are deprecated. Use @base-node
+# and @top-node instead.
+#
# Returns: - Nothing on success
# - If @device does not exist, DeviceNotFound
# - Any other error returns a GenericError.
##
{ 'command': 'block-commit',
'data': { '*job-id': 'str', 'device': 'str', '*base-node': 'str',
- '*base': 'str', '*top-node': 'str', '*top': 'str',
+ '*base': { 'type': 'str', 'features': [ 'deprecated' ] },
+ '*top-node': 'str',
+ '*top': { 'type': 'str', 'features': [ 'deprecated' ] },
'*backing-file': 'str', '*speed': 'int',
'*on-error': 'BlockdevOnError',
'*filter-node-name': 'str',
#
# A set of parameters describing block throttling.
#
-# @device: Block device name (deprecated, use @id instead)
+# @device: Block device name
#
# @id: The name or QOM path of the guest device (since: 2.8)
#
#
# @group: throttle group name (Since 2.4)
#
+# Features:
+# @deprecated: Member @device is deprecated. Use @id instead.
+#
# Since: 1.1
##
{ 'struct': 'BlockIOThrottle',
- 'data': { '*device': 'str', '*id': 'str', 'bps': 'int', 'bps_rd': 'int',
+ 'data': { '*device': { 'type': 'str', 'features': [ 'deprecated' ] },
+ '*id': 'str', 'bps': 'int', 'bps_rd': 'int',
'bps_wr': 'int', 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
'*bps_max': 'int', '*bps_rd_max': 'int',
'*bps_wr_max': 'int', '*iops_max': 'int',
##
# @eject:
#
-# Ejects a device from a removable drive.
+# Ejects the medium from a removable drive.
#
-# @device: Block device name (deprecated, use @id instead)
+# @device: Block device name
#
# @id: The name or QOM path of the guest device (since: 2.8)
#
# @force: If true, eject regardless of whether the drive is locked.
# If not specified, the default value is false.
#
+# Features:
+# @deprecated: Member @device is deprecated. Use @id instead.
+#
# Returns: - Nothing on success
# - If @device is not a valid block device, DeviceNotFound
# Notes: Ejecting a device with no media results in success
# <- { "return": {} }
##
{ 'command': 'eject',
- 'data': { '*device': 'str',
+ 'data': { '*device': { 'type': 'str', 'features': [ 'deprecated' ] },
'*id': 'str',
'*force': 'bool' } }
# to it
# - if the guest device does not have an actual tray
#
-# @device: Block device name (deprecated, use @id instead)
+# @device: Block device name
#
# @id: The name or QOM path of the guest device (since: 2.8)
#
# immediately); if true, the tray will be opened regardless of whether
# it is locked
#
+# Features:
+# @deprecated: Member @device is deprecated. Use @id instead.
+#
# Since: 2.5
#
# Example:
#
##
{ 'command': 'blockdev-open-tray',
- 'data': { '*device': 'str',
+ 'data': { '*device': { 'type': 'str', 'features': [ 'deprecated' ] },
'*id': 'str',
'*force': 'bool' } }
#
# If the tray was already closed before, this will be a no-op.
#
-# @device: Block device name (deprecated, use @id instead)
+# @device: Block device name
#
# @id: The name or QOM path of the guest device (since: 2.8)
#
+# Features:
+# @deprecated: Member @device is deprecated. Use @id instead.
+#
# Since: 2.5
#
# Example:
#
##
{ 'command': 'blockdev-close-tray',
- 'data': { '*device': 'str',
+ 'data': { '*device': { 'type': 'str', 'features': [ 'deprecated' ] },
'*id': 'str' } }
##
# combines blockdev-open-tray, blockdev-remove-medium, blockdev-insert-medium
# and blockdev-close-tray).
#
-# @device: Block device name (deprecated, use @id instead)
+# @device: Block device name
#
# @id: The name or QOM path of the guest device
# (since: 2.8)
# @read-only-mode: change the read-only mode of the device; defaults
# to 'retain'
#
+# Features:
+# @deprecated: Member @device is deprecated. Use @id instead.
+#
# Since: 2.5
#
# Examples:
#
##
{ 'command': 'blockdev-change-medium',
- 'data': { '*device': 'str',
+ 'data': { '*device': { 'type': 'str', 'features': [ 'deprecated' ] },
'*id': 'str',
'filename': 'str',
'*format': 'str',
# @server: create server socket (default: true)
# @wait: wait for incoming connection on server
# sockets (default: false).
+# Silently ignored with server: false. This use is deprecated.
# @nodelay: set TCP_NODELAY socket option (default: false)
# @telnet: enable telnet protocol on server
# sockets (default: false)
#
# Return information on QMP events.
#
+# Features:
+# @deprecated: This command is deprecated, because its output doesn't
+# reflect compile-time configuration. Use 'query-qmp-schema'
+# instead.
+#
# Returns: A list of @EventInfo.
#
# Since: 1.2.0
#
-# Note: This command is deprecated, because its output doesn't reflect
-# compile-time configuration. Use query-qmp-schema instead.
-#
# Example:
#
# -> { "execute": "query-events" }
# Note: This example has been shortened as the real response is too long.
#
##
-{ 'command': 'query-events', 'returns': ['EventInfo'] }
+{ 'command': 'query-events', 'returns': ['EventInfo'],
+ 'features': [ 'deprecated' ] }
##
# @quit:
#
# @meta-type: the entity's meta type, inherited from @base.
#
+# @features: names of features associated with the entity, in no
+# particular order.
+# (since 4.1 for object types, 4.2 for commands, 5.0 for
+# the rest)
+#
# Additional members depend on the value of @meta-type.
#
# Since: 2.5
##
{ 'union': 'SchemaInfo',
- 'base': { 'name': 'str', 'meta-type': 'SchemaMetaType' },
+ 'base': { 'name': 'str', 'meta-type': 'SchemaMetaType',
+ '*features': [ 'str' ] },
'discriminator': 'meta-type',
'data': {
'builtin': 'SchemaInfoBuiltin',
# and may even differ from the order of the values of the
# enum type of the @tag.
#
-# @features: names of features associated with the type, in no particular
-# order. (since: 4.1)
-#
# Values of this type are JSON object on the wire.
#
# Since: 2.5
{ 'struct': 'SchemaInfoObject',
'data': { 'members': [ 'SchemaInfoObjectMember' ],
'*tag': 'str',
- '*variants': [ 'SchemaInfoObjectVariant' ],
- '*features': [ 'str' ] } }
+ '*variants': [ 'SchemaInfoObjectVariant' ] } }
##
# @SchemaInfoObjectMember:
# Future extension: if present and non-null, the parameter
# is optional, and defaults to this value.
#
+# @features: names of features associated with the member, in no
+# particular order. (since 5.0)
+#
# Since: 2.5
##
{ 'struct': 'SchemaInfoObjectMember',
- 'data': { 'name': 'str', 'type': 'str', '*default': 'any' } }
+ 'data': { 'name': 'str', 'type': 'str', '*default': 'any',
# @default's type must be null or match @type
+ '*features': [ 'str' ] } }
##
# @SchemaInfoObjectVariant:
# @allow-oob: whether the command allows out-of-band execution,
# defaults to false (Since: 2.12)
#
-# @features: names of features associated with the command, in no particular
-# order. (since 4.2)
-#
# TODO: @success-response (currently irrelevant, because it's QGA, not QMP)
#
# Since: 2.5
##
{ 'struct': 'SchemaInfoCommand',
'data': { 'arg-type': 'str', 'ret-type': 'str',
- '*allow-oob': 'bool',
- '*features': [ 'str' ] } }
+ '*allow-oob': 'bool' } }
##
# @SchemaInfoEvent:
# This command causes vCPU threads to exit to userspace, which causes
# a small interruption to guest CPU execution. This will have a negative
# impact on realtime guests and other latency sensitive guest workloads.
-# It is recommended to use @query-cpus-fast instead of this command to
-# avoid the vCPU interruption.
+#
+# Features:
+# @deprecated: This command is deprecated, because it interferes with
+# the guest. Use 'query-cpus-fast' instead to avoid the vCPU
+# interruption.
#
# Returns: a list of @CpuInfo for each virtual CPU
#
# ]
# }
#
-# Notes: This interface is deprecated (since 2.12.0), and it is strongly
-# recommended that you avoid using it. Use @query-cpus-fast to
-# obtain information about virtual CPUs.
-#
##
-{ 'command': 'query-cpus', 'returns': ['CpuInfo'] }
+{ 'command': 'query-cpus', 'returns': ['CpuInfo'],
+ 'features': [ 'deprecated' ] }
##
# @CpuInfoFast:
# @props: properties describing to which node/socket/core/thread
# virtual CPU belongs to, provided if supported by board
#
-# @arch: base architecture of the cpu; deprecated since 3.0.0 in favor
-# of @target
+# @arch: base architecture of the cpu
#
# @target: the QEMU system emulation target, which determines which
# additional fields will be listed (since 3.0)
#
+# Features:
+# @deprecated: Member @arch is deprecated. Use @target instead.
+#
# Since: 2.12
#
##
'qom-path' : 'str',
'thread-id' : 'int',
'*props' : 'CpuInstanceProperties',
- 'arch' : 'CpuInfoArch',
+ 'arch' : { 'type': 'CpuInfoArch',
+ 'features': [ 'deprecated' ] },
'target' : 'SysEmuTarget' },
'discriminator' : 'target',
'data' : { 's390x' : 'CpuInfoS390' } }
#
# @id: ID of CPU to be created, valid values [0..max_cpus)
#
+# Features:
+# @deprecated: This command is deprecated. Use `device_add` instead.
+# See the `query-hotpluggable-cpus` command for details.
+#
# Returns: Nothing on success
#
# Since: 1.5
#
-# Note: This command is deprecated. The `device_add` command should be
-# used instead. See the `query-hotpluggable-cpus` command for
-# details.
-#
# Example:
#
# -> { "execute": "cpu-add", "arguments": { "id": 2 } }
# <- { "return": {} }
#
##
-{ 'command': 'cpu-add', 'data': {'id': 'int'} }
+{ 'command': 'cpu-add', 'data': {'id': 'int'},
+ 'features': [ 'deprecated' ] }
##
# @MachineInfo:
#
# @value: maximum downtime in seconds
#
-# Returns: nothing on success
+# Features:
+# @deprecated: This command is deprecated. Use
+# 'migrate-set-parameters' instead.
#
-# Notes: This command is deprecated in favor of 'migrate-set-parameters'
+# Returns: nothing on success
#
# Since: 0.14.0
#
# <- { "return": {} }
#
##
-{ 'command': 'migrate_set_downtime', 'data': {'value': 'number'} }
+{ 'command': 'migrate_set_downtime', 'data': {'value': 'number'},
+ 'features': [ 'deprecated' ] }
##
# @migrate_set_speed:
#
# @value: maximum speed in bytes per second.
#
-# Returns: nothing on success
+# Features:
+# @deprecated: This command is deprecated. Use
+# 'migrate-set-parameters' instead.
#
-# Notes: This command is deprecated in favor of 'migrate-set-parameters'
+# Returns: nothing on success
#
# Since: 0.14.0
#
# <- { "return": {} }
#
##
-{ 'command': 'migrate_set_speed', 'data': {'value': 'int'} }
+{ 'command': 'migrate_set_speed', 'data': {'value': 'int'},
+ 'features': [ 'deprecated' ] }
##
# @migrate-set-cache-size:
#
# @value: cache size in bytes
#
+# Features:
+# @deprecated: This command is deprecated. Use
+# 'migrate-set-parameters' instead.
+#
# The size will be rounded down to the nearest power of 2.
# The cache size can be modified before and during ongoing migration
#
# Returns: nothing on success
#
-# Notes: This command is deprecated in favor of 'migrate-set-parameters'
-#
# Since: 1.2
#
# Example:
# <- { "return": {} }
#
##
-{ 'command': 'migrate-set-cache-size', 'data': {'value': 'int'} }
+{ 'command': 'migrate-set-cache-size', 'data': {'value': 'int'},
+ 'features': [ 'deprecated' ] }
##
# @query-migrate-cache-size:
#
# Query migration XBZRLE cache size
#
-# Returns: XBZRLE cache size in bytes
+# Features:
+# @deprecated: This command is deprecated. Use
+# 'query-migrate-parameters' instead.
#
-# Notes: This command is deprecated in favor of 'query-migrate-parameters'
+# Returns: XBZRLE cache size in bytes
#
# Since: 1.2
#
# <- { "return": 67108864 }
#
##
-{ 'command': 'query-migrate-cache-size', 'returns': 'int' }
+{ 'command': 'query-migrate-cache-size', 'returns': 'int',
+ 'features': [ 'deprecated' ] }
##
# @migrate:
# If @device is 'vnc' and @target is 'password', this is the new VNC
# password to set. See change-vnc-password for additional notes.
#
+# Features:
+# @deprecated: This command is deprecated. For changing block
+# devices, use 'blockdev-change-medium' instead; for changing VNC
+# parameters, use 'change-vnc-password' instead.
+#
# Returns: - Nothing on success.
# - If @device is not a valid block device, DeviceNotFound
#
-# Notes: This interface is deprecated, and it is strongly recommended that you
-# avoid using it. For changing block devices, use
-# blockdev-change-medium; for changing VNC parameters, use
-# change-vnc-password.
-#
# Since: 0.14.0
#
# Example:
#
##
{ 'command': 'change',
- 'data': {'device': 'str', 'target': 'str', '*arg': 'str'} }
+ 'data': {'device': 'str', 'target': 'str', '*arg': 'str'},
+ 'features': [ 'deprecated' ] }
##
# @xen-set-global-dirty-log:
#
# Add a network backend.
#
-# @type: the type of network backend. Possible values are listed in
-# NetClientDriver (excluding 'none' and 'nic')
-#
-# @id: the name of the new network backend
-#
# Additional arguments depend on the type.
#
-# TODO: This command effectively bypasses QAPI completely due to its
-# "additional arguments" business. It shouldn't have been added to
-# the schema in this form. It should be qapified properly, or
-# replaced by a properly qapified command.
-#
# Since: 0.14.0
#
# Returns: Nothing on success
# <- { "return": {} }
#
##
-{ 'command': 'netdev_add',
- 'data': {'type': 'str', 'id': 'str'},
- 'gen': false } # so we can get the additional arguments
+{ 'command': 'netdev_add', 'data': 'Netdev', 'boxed': true }
##
# @netdev_del:
#include "sysemu/runstate.h"
#include "qapi/qmp/qbool.h"
-static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob,
+static QDict *qmp_dispatch_check_obj(QDict *dict, bool allow_oob,
Error **errp)
{
const char *exec_key = NULL;
const QDictEntry *ent;
const char *arg_name;
const QObject *arg_obj;
- QDict *dict;
-
- dict = qobject_to(QDict, request);
- if (!dict) {
- error_setg(errp, "QMP input must be a JSON object");
- return NULL;
- }
for (ent = qdict_first(dict); ent;
ent = qdict_next(dict, ent)) {
return dict;
}
-static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
- bool allow_oob, Error **errp)
+QDict *qmp_error_response(Error *err)
+{
+ QDict *rsp;
+
+ rsp = qdict_from_jsonf_nofail("{ 'error': { 'class': %s, 'desc': %s } }",
+ QapiErrorClass_str(error_get_class(err)),
+ error_get_pretty(err));
+ error_free(err);
+ return rsp;
+}
+
+/*
+ * Does @qdict look like a command to be run out-of-band?
+ */
+bool qmp_is_oob(const QDict *dict)
+{
+ return qdict_haskey(dict, "exec-oob")
+ && !qdict_haskey(dict, "execute");
+}
+
+QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
+ bool allow_oob)
{
- Error *local_err = NULL;
+ Error *err = NULL;
bool oob;
const char *command;
- QDict *args, *dict;
- QmpCommand *cmd;
+ QDict *args;
+ const QmpCommand *cmd;
+ QDict *dict;
+ QObject *id;
QObject *ret = NULL;
+ QDict *rsp = NULL;
- dict = qmp_dispatch_check_obj(request, allow_oob, errp);
+ dict = qobject_to(QDict, request);
if (!dict) {
- return NULL;
+ id = NULL;
+ error_setg(&err, "QMP input must be a JSON object");
+ goto out;
+ }
+
+ id = qdict_get(dict, "id");
+
+ if (!qmp_dispatch_check_obj(dict, allow_oob, &err)) {
+ goto out;
}
command = qdict_get_try_str(dict, "execute");
}
cmd = qmp_find_command(cmds, command);
if (cmd == NULL) {
- error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
+ error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
"The command %s has not been found", command);
- return NULL;
+ goto out;
}
if (!cmd->enabled) {
- error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
+ error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
"The command %s has been disabled for this instance",
command);
- return NULL;
+ goto out;
}
if (oob && !(cmd->options & QCO_ALLOW_OOB)) {
- error_setg(errp, "The command %s does not support OOB",
+ error_setg(&err, "The command %s does not support OOB",
command);
- return NULL;
+ goto out;
}
if (runstate_check(RUN_STATE_PRECONFIG) &&
!(cmd->options & QCO_ALLOW_PRECONFIG)) {
- error_setg(errp, "The command '%s' isn't permitted in '%s' state",
+ error_setg(&err, "The command '%s' isn't permitted in '%s' state",
cmd->name, RunState_str(RUN_STATE_PRECONFIG));
- return NULL;
+ goto out;
}
if (!qdict_haskey(dict, "arguments")) {
args = qdict_get_qdict(dict, "arguments");
qobject_ref(args);
}
+ cmd->fn(args, &ret, &err);
+ qobject_unref(args);
+ if (err) {
+ goto out;
+ }
- cmd->fn(args, &ret, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- } else if (cmd->options & QCO_NO_SUCCESS_RESP) {
+ if (cmd->options & QCO_NO_SUCCESS_RESP) {
g_assert(!ret);
+ return NULL;
} else if (!ret) {
- /* TODO turn into assertion */
+ /*
+ * When the command's schema has no 'returns', cmd->fn()
+ * leaves @ret null. The QMP spec calls for an empty object
+ * then; supply it.
+ */
ret = QOBJECT(qdict_new());
}
- qobject_unref(args);
-
- return ret;
-}
-
-QDict *qmp_error_response(Error *err)
-{
- QDict *rsp;
-
- rsp = qdict_from_jsonf_nofail("{ 'error': { 'class': %s, 'desc': %s } }",
- QapiErrorClass_str(error_get_class(err)),
- error_get_pretty(err));
- error_free(err);
- return rsp;
-}
-
-/*
- * Does @qdict look like a command to be run out-of-band?
- */
-bool qmp_is_oob(const QDict *dict)
-{
- return qdict_haskey(dict, "exec-oob")
- && !qdict_haskey(dict, "execute");
-}
-
-QDict *qmp_dispatch(QmpCommandList *cmds, QObject *request,
- bool allow_oob)
-{
- Error *err = NULL;
- QDict *dict = qobject_to(QDict, request);
- QObject *ret, *id = dict ? qdict_get(dict, "id") : NULL;
- QDict *rsp;
+ rsp = qdict_new();
+ qdict_put_obj(rsp, "return", ret);
- ret = do_qmp_dispatch(cmds, request, allow_oob, &err);
+out:
if (err) {
+ assert(!rsp);
rsp = qmp_error_response(err);
- } else if (ret) {
- rsp = qdict_new();
- qdict_put_obj(rsp, "return", ret);
- } else {
- /* Can only happen for commands with QCO_NO_SUCCESS_RESP */
- rsp = NULL;
}
- if (rsp && id) {
+ assert(rsp);
+
+ if (id) {
qdict_put_obj(rsp, "id", qobject_ref(id));
}
QTAILQ_INSERT_TAIL(cmds, cmd, node);
}
-QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name)
+const QmpCommand *qmp_find_command(const QmpCommandList *cmds, const char *name)
{
QmpCommand *cmd;
return !(cmd->options & QCO_NO_SUCCESS_RESP);
}
-void qmp_for_each_command(QmpCommandList *cmds, qmp_cmd_callback_fn fn,
+void qmp_for_each_command(const QmpCommandList *cmds, qmp_cmd_callback_fn fn,
void *opaque)
{
- QmpCommand *cmd;
+ const QmpCommand *cmd;
QTAILQ_FOREACH(cmd, cmds, node) {
fn(cmd, opaque);
slog("guest-ping called");
}
-static void qmp_command_info(QmpCommand *cmd, void *opaque)
+static void qmp_command_info(const QmpCommand *cmd, void *opaque)
{
GuestAgentInfo *info = opaque;
GuestAgentCommandInfo *cmd_info;
}
/* disable commands that aren't safe for fsfreeze */
-static void ga_disable_non_whitelisted(QmpCommand *cmd, void *opaque)
+static void ga_disable_non_whitelisted(const QmpCommand *cmd, void *opaque)
{
bool whitelisted = false;
int i = 0;
}
/* [re-]enable all commands, except those explicitly blacklisted by user */
-static void ga_enable_non_blacklisted(QmpCommand *cmd, void *opaque)
+static void ga_enable_non_blacklisted(const QmpCommand *cmd, void *opaque)
{
GList *blacklist = opaque;
const char *name = qmp_command_name(cmd);
return handle;
}
-static void ga_print_cmd(QmpCommand *cmd, void *opaque)
+static void ga_print_cmd(const QmpCommand *cmd, void *opaque)
{
printf("%s\n", qmp_command_name(cmd));
}
-Subproject commit 9546892a80d5a4c73deea6719de46372f007f4a6
+Subproject commit ab6984f5a6d054e1f634dda855b32e5357111974
prefix=self._prefix))
self._genc.add(gen_registry(self._regy.get_content(), self._prefix))
- def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
- success_response, boxed, allow_oob, allow_preconfig,
- features):
+ def visit_command(self, name, info, ifcond, features,
+ arg_type, ret_type, gen, success_response, boxed,
+ allow_oob, allow_preconfig):
if not gen:
return
# FIXME: If T is a user-defined type, the user is responsible
def write(self, output_dir):
self._gen.write(output_dir)
- def visit_enum_type(self, name, info, ifcond, members, prefix):
+ def visit_enum_type(self, name, info, ifcond, features, members, prefix):
doc = self.cur_doc
self._gen.add(texi_type('Enum', doc, ifcond,
texi_members(doc, 'Values',
member_func=texi_enum_value)))
- def visit_object_type(self, name, info, ifcond, base, members, variants,
- features):
+ def visit_object_type(self, name, info, ifcond, features,
+ base, members, variants):
doc = self.cur_doc
if base and base.is_implicit():
base = None
self._gen.add(texi_type('Object', doc, ifcond,
texi_members(doc, 'Members', base, variants)))
- def visit_alternate_type(self, name, info, ifcond, variants):
+ def visit_alternate_type(self, name, info, ifcond, features, variants):
doc = self.cur_doc
self._gen.add(texi_type('Alternate', doc, ifcond,
texi_members(doc, 'Members')))
- def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
- success_response, boxed, allow_oob, allow_preconfig,
- features):
+ def visit_command(self, name, info, ifcond, features,
+ arg_type, ret_type, gen, success_response, boxed,
+ allow_oob, allow_preconfig):
doc = self.cur_doc
self._gen.add(texi_msg('Command', doc, ifcond,
texi_arguments(doc,
arg_type if boxed else None)))
- def visit_event(self, name, info, ifcond, arg_type, boxed):
+ def visit_event(self, name, info, ifcond, features, arg_type, boxed):
doc = self.cur_doc
self._gen.add(texi_msg('Event', doc, ifcond,
texi_arguments(doc,
event_emit=self._event_emit_name,
event_enum=self._event_enum_name))
- def visit_event(self, name, info, ifcond, arg_type, boxed):
+ def visit_event(self, name, info, ifcond, features, arg_type, boxed):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_event_send_decl(name, arg_type, boxed))
self._genc.add(gen_event_send(name, arg_type, boxed,
allow_optional=True, permit_upper=permit_upper)
if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
raise QAPISemError(info, "%s uses reserved name" % key_source)
- check_keys(arg, info, key_source, ['type'], ['if'])
+ check_keys(arg, info, key_source, ['type'], ['if', 'features'])
check_if(arg, info, key_source)
+ check_features(arg.get('features'), info)
check_type(arg['type'], info, key_source, allow_array=True)
check_type(members, info, "'data'", allow_dict=name)
check_type(expr.get('base'), info, "'base'")
- check_features(expr.get('features'), info)
def check_union(expr, info):
raise QAPISemError(info, "'boxed': true requires 'data'")
check_type(args, info, "'data'", allow_dict=not boxed)
check_type(rets, info, "'returns'", allow_array=True)
- check_features(expr.get('features'), info)
def check_event(expr, info):
if meta == 'enum':
check_keys(expr, info, meta,
- ['enum', 'data'], ['if', 'prefix'])
+ ['enum', 'data'], ['if', 'features', 'prefix'])
check_enum(expr, info)
elif meta == 'union':
check_keys(expr, info, meta,
['union', 'data'],
- ['base', 'discriminator', 'if'])
+ ['base', 'discriminator', 'if', 'features'])
normalize_members(expr.get('base'))
normalize_members(expr['data'])
check_union(expr, info)
elif meta == 'alternate':
check_keys(expr, info, meta,
- ['alternate', 'data'], ['if'])
+ ['alternate', 'data'], ['if', 'features'])
normalize_members(expr['data'])
check_alternate(expr, info)
elif meta == 'struct':
check_command(expr, info)
elif meta == 'event':
check_keys(expr, info, meta,
- ['event'], ['data', 'boxed', 'if'])
+ ['event'], ['data', 'boxed', 'if', 'features'])
normalize_members(expr.get('data'))
check_event(expr, info)
else:
assert False, 'unexpected meta type'
check_if(expr, info, meta)
+ check_features(expr.get('features'), info)
check_flags(expr, info)
return exprs
QAPISchemaType)
-def to_qlit(obj, level=0, suppress_first_indent=False):
+def _make_tree(obj, ifcond, features, extra=None):
+ if extra is None:
+ extra = {}
+ if ifcond:
+ extra['if'] = ifcond
+ if features:
+ obj['features'] = [(f.name, {'if': f.ifcond}) for f in features]
+ if extra:
+ return (obj, extra)
+ return obj
+
+
+def _tree_to_qlit(obj, level=0, suppress_first_indent=False):
def indent(level):
return level * 4 * ' '
ret += indent(level) + '/* %s */\n' % comment
if ifcond:
ret += gen_if(ifcond)
- ret += to_qlit(ifobj, level)
+ ret += _tree_to_qlit(ifobj, level)
if ifcond:
ret += '\n' + gen_endif(ifcond)
return ret
elif isinstance(obj, str):
ret += 'QLIT_QSTR(' + to_c_string(obj) + ')'
elif isinstance(obj, list):
- elts = [to_qlit(elt, level + 1).strip('\n')
+ elts = [_tree_to_qlit(elt, level + 1).strip('\n')
for elt in obj]
elts.append(indent(level + 1) + "{}")
ret += 'QLIT_QLIST(((QLitObject[]) {\n'
elts = []
for key, value in sorted(obj.items()):
elts.append(indent(level + 1) + '{ %s, %s }' %
- (to_c_string(key), to_qlit(value, level + 1, True)))
+ (to_c_string(key),
+ _tree_to_qlit(value, level + 1, True)))
elts.append(indent(level + 1) + '{}')
ret += 'QLIT_QDICT(((QLitDictEntry[]) {\n'
ret += ',\n'.join(elts) + '\n'
' * QAPI/QMP schema introspection', __doc__)
self._unmask = unmask
self._schema = None
- self._qlits = []
+ self._trees = []
self._used_types = []
self._name_map = {}
self._genc.add(mcgen('''
const QLitObject %(c_name)s = %(c_string)s;
''',
c_name=c_name(name),
- c_string=to_qlit(self._qlits)))
+ c_string=_tree_to_qlit(self._trees)))
self._schema = None
- self._qlits = []
+ self._trees = []
self._used_types = []
self._name_map = {}
return '[' + self._use_type(typ.element_type) + ']'
return self._name(typ.name)
- def _gen_qlit(self, name, mtype, obj, ifcond):
- extra = {}
+ def _gen_tree(self, name, mtype, obj, ifcond, features):
+ extra = None
if mtype not in ('command', 'event', 'builtin', 'array'):
if not self._unmask:
# Output a comment to make it easy to map masked names
# back to the source when reading the generated output.
- extra['comment'] = '"%s" = %s' % (self._name(name), name)
+ extra = {'comment': '"%s" = %s' % (self._name(name), name)}
name = self._name(name)
obj['name'] = name
obj['meta-type'] = mtype
- if ifcond:
- extra['if'] = ifcond
- if extra:
- self._qlits.append((obj, extra))
- else:
- self._qlits.append(obj)
+ self._trees.append(_make_tree(obj, ifcond, features, extra))
def _gen_member(self, member):
- ret = {'name': member.name, 'type': self._use_type(member.type)}
+ obj = {'name': member.name, 'type': self._use_type(member.type)}
if member.optional:
- ret['default'] = None
- if member.ifcond:
- ret = (ret, {'if': member.ifcond})
- return ret
+ obj['default'] = None
+ return _make_tree(obj, member.ifcond, member.features)
def _gen_variants(self, tag_name, variants):
return {'tag': tag_name,
'variants': [self._gen_variant(v) for v in variants]}
def _gen_variant(self, variant):
- return ({'case': variant.name, 'type': self._use_type(variant.type)},
- {'if': variant.ifcond})
+ obj = {'case': variant.name, 'type': self._use_type(variant.type)}
+ return _make_tree(obj, variant.ifcond, None)
def visit_builtin_type(self, name, info, json_type):
- self._gen_qlit(name, 'builtin', {'json-type': json_type}, [])
+ self._gen_tree(name, 'builtin', {'json-type': json_type}, [], None)
- def visit_enum_type(self, name, info, ifcond, members, prefix):
- self._gen_qlit(name, 'enum',
- {'values':
- [(m.name, {'if': m.ifcond}) for m in members]},
- ifcond)
+ def visit_enum_type(self, name, info, ifcond, features, members, prefix):
+ self._gen_tree(name, 'enum',
+ {'values': [_make_tree(m.name, m.ifcond, None)
+ for m in members]},
+ ifcond, features)
def visit_array_type(self, name, info, ifcond, element_type):
element = self._use_type(element_type)
- self._gen_qlit('[' + element + ']', 'array', {'element-type': element},
- ifcond)
+ self._gen_tree('[' + element + ']', 'array', {'element-type': element},
+ ifcond, None)
- def visit_object_type_flat(self, name, info, ifcond, members, variants,
- features):
+ def visit_object_type_flat(self, name, info, ifcond, features,
+ members, variants):
obj = {'members': [self._gen_member(m) for m in members]}
if variants:
obj.update(self._gen_variants(variants.tag_member.name,
variants.variants))
- if features:
- obj['features'] = [(f.name, {'if': f.ifcond}) for f in features]
- self._gen_qlit(name, 'object', obj, ifcond)
+ self._gen_tree(name, 'object', obj, ifcond, features)
- def visit_alternate_type(self, name, info, ifcond, variants):
- self._gen_qlit(name, 'alternate',
+ def visit_alternate_type(self, name, info, ifcond, features, variants):
+ self._gen_tree(name, 'alternate',
{'members': [
- ({'type': self._use_type(m.type)}, {'if': m.ifcond})
- for m in variants.variants]}, ifcond)
-
- def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
- success_response, boxed, allow_oob, allow_preconfig,
- features):
+ _make_tree({'type': self._use_type(m.type)},
+ m.ifcond, None)
+ for m in variants.variants]},
+ ifcond, features)
+
+ def visit_command(self, name, info, ifcond, features,
+ arg_type, ret_type, gen, success_response, boxed,
+ allow_oob, allow_preconfig):
arg_type = arg_type or self._schema.the_empty_object_type
ret_type = ret_type or self._schema.the_empty_object_type
obj = {'arg-type': self._use_type(arg_type),
'ret-type': self._use_type(ret_type)}
if allow_oob:
obj['allow-oob'] = allow_oob
+ self._gen_tree(name, 'command', obj, ifcond, features)
- if features:
- obj['features'] = [(f.name, {'if': f.ifcond}) for f in features]
-
- self._gen_qlit(name, 'command', obj, ifcond)
-
- def visit_event(self, name, info, ifcond, arg_type, boxed):
+ def visit_event(self, name, info, ifcond, features, arg_type, boxed):
arg_type = arg_type or self._schema.the_empty_object_type
- self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type)},
- ifcond)
+ self._gen_tree(name, 'event', {'arg-type': self._use_type(arg_type)},
+ ifcond, features)
def gen_introspect(schema, output_dir, prefix, opt_unmask):
seen = {}
for f in self.features:
f.check_clash(self.info, seen)
- if self.doc:
- self.doc.connect_feature(f)
-
self._checked = True
def connect_doc(self, doc=None):
- pass
+ doc = doc or self.doc
+ if doc:
+ for f in self.features:
+ doc.connect_feature(f)
def check_doc(self):
if self.doc:
def visit_builtin_type(self, name, info, json_type):
pass
- def visit_enum_type(self, name, info, ifcond, members, prefix):
+ def visit_enum_type(self, name, info, ifcond, features, members, prefix):
pass
def visit_array_type(self, name, info, ifcond, element_type):
pass
- def visit_object_type(self, name, info, ifcond, base, members, variants,
- features):
+ def visit_object_type(self, name, info, ifcond, features,
+ base, members, variants):
pass
- def visit_object_type_flat(self, name, info, ifcond, members, variants,
- features):
+ def visit_object_type_flat(self, name, info, ifcond, features,
+ members, variants):
pass
- def visit_alternate_type(self, name, info, ifcond, variants):
+ def visit_alternate_type(self, name, info, ifcond, features, variants):
pass
- def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
- success_response, boxed, allow_oob, allow_preconfig,
- features):
+ def visit_command(self, name, info, ifcond, features,
+ arg_type, ret_type, gen, success_response, boxed,
+ allow_oob, allow_preconfig):
pass
- def visit_event(self, name, info, ifcond, arg_type, boxed):
+ def visit_event(self, name, info, ifcond, features, arg_type, boxed):
pass
return None
return self.name
+ def check(self, schema):
+ QAPISchemaEntity.check(self, schema)
+ if 'deprecated' in [f.name for f in self.features]:
+ raise QAPISemError(
+ self.info, "feature 'deprecated' is not supported for types")
+
def describe(self):
assert self.meta
return "%s type '%s'" % (self.meta, self.name)
class QAPISchemaEnumType(QAPISchemaType):
meta = 'enum'
- def __init__(self, name, info, doc, ifcond, members, prefix):
- super().__init__(name, info, doc, ifcond)
+ def __init__(self, name, info, doc, ifcond, features, members, prefix):
+ super().__init__(name, info, doc, ifcond, features)
for m in members:
assert isinstance(m, QAPISchemaEnumMember)
m.set_defined_in(name)
m.check_clash(self.info, seen)
def connect_doc(self, doc=None):
+ super().connect_doc(doc)
doc = doc or self.doc
- if doc:
- for m in self.members:
- doc.connect_member(m)
+ for m in self.members:
+ m.connect_doc(doc)
def is_implicit(self):
# See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
def visit(self, visitor):
super().visit(visitor)
- visitor.visit_enum_type(self.name, self.info, self.ifcond,
- self.members, self.prefix)
+ visitor.visit_enum_type(
+ self.name, self.info, self.ifcond, self.features,
+ self.members, self.prefix)
class QAPISchemaArrayType(QAPISchemaType):
meta = 'array'
def __init__(self, name, info, element_type):
- super().__init__(name, info, None, None)
+ super().__init__(name, info, None)
assert isinstance(element_type, str)
self._element_type_name = element_type
self.element_type = None
class QAPISchemaObjectType(QAPISchemaType):
- def __init__(self, name, info, doc, ifcond,
- base, local_members, variants, features):
+ def __init__(self, name, info, doc, ifcond, features,
+ base, local_members, variants):
# struct has local_members, optional base, and no variants
# flat union has base, variants, and no local_members
# simple union has local_members, variants, and no base
assert isinstance(m, QAPISchemaObjectTypeMember)
m.set_defined_in(name)
if variants is not None:
- assert isinstance(variants, QAPISchemaObjectTypeVariants)
+ assert isinstance(variants, QAPISchemaVariants)
variants.set_defined_in(name)
self._base_name = base
self.base = None
m.check_clash(info, seen)
def connect_doc(self, doc=None):
+ super().connect_doc(doc)
doc = doc or self.doc
- if doc:
- if self.base and self.base.is_implicit():
- self.base.connect_doc(doc)
- for m in self.local_members:
- doc.connect_member(m)
+ if self.base and self.base.is_implicit():
+ self.base.connect_doc(doc)
+ for m in self.local_members:
+ m.connect_doc(doc)
@property
def ifcond(self):
def visit(self, visitor):
super().visit(visitor)
- visitor.visit_object_type(self.name, self.info, self.ifcond,
- self.base, self.local_members, self.variants,
- self.features)
- visitor.visit_object_type_flat(self.name, self.info, self.ifcond,
- self.members, self.variants,
- self.features)
-
-
-class QAPISchemaMember:
- """ Represents object members, enum members and features """
- role = 'member'
-
- def __init__(self, name, info, ifcond=None):
- assert isinstance(name, str)
- self.name = name
- self.info = info
- self.ifcond = ifcond or []
- self.defined_in = None
-
- def set_defined_in(self, name):
- assert not self.defined_in
- self.defined_in = name
-
- def check_clash(self, info, seen):
- cname = c_name(self.name)
- if cname in seen:
- raise QAPISemError(
- info,
- "%s collides with %s"
- % (self.describe(info), seen[cname].describe(info)))
- seen[cname] = self
+ visitor.visit_object_type(
+ self.name, self.info, self.ifcond, self.features,
+ self.base, self.local_members, self.variants)
+ visitor.visit_object_type_flat(
+ self.name, self.info, self.ifcond, self.features,
+ self.members, self.variants)
- def describe(self, info):
- role = self.role
- defined_in = self.defined_in
- assert defined_in
-
- if defined_in.startswith('q_obj_'):
- # See QAPISchema._make_implicit_object_type() - reverse the
- # mapping there to create a nice human-readable description
- defined_in = defined_in[6:]
- if defined_in.endswith('-arg'):
- # Implicit type created for a command's dict 'data'
- assert role == 'member'
- role = 'parameter'
- elif defined_in.endswith('-base'):
- # Implicit type created for a flat union's dict 'base'
- role = 'base ' + role
- else:
- # Implicit type created for a simple union's branch
- assert defined_in.endswith('-wrapper')
- # Unreachable and not implemented
- assert False
- elif defined_in.endswith('Kind'):
- # See QAPISchema._make_implicit_enum_type()
- # Implicit enum created for simple union's branches
- assert role == 'value'
- role = 'branch'
- elif defined_in != info.defn_name:
- return "%s '%s' of type '%s'" % (role, self.name, defined_in)
- return "%s '%s'" % (role, self.name)
+class QAPISchemaAlternateType(QAPISchemaType):
+ meta = 'alternate'
-class QAPISchemaEnumMember(QAPISchemaMember):
- role = 'value'
+ def __init__(self, name, info, doc, ifcond, features, variants):
+ super().__init__(name, info, doc, ifcond, features)
+ assert isinstance(variants, QAPISchemaVariants)
+ assert variants.tag_member
+ variants.set_defined_in(name)
+ variants.tag_member.set_defined_in(self.name)
+ self.variants = variants
+ def check(self, schema):
+ super().check(schema)
+ self.variants.tag_member.check(schema)
+ # Not calling self.variants.check_clash(), because there's nothing
+ # to clash with
+ self.variants.check(schema, {})
+ # Alternate branch names have no relation to the tag enum values;
+ # so we have to check for potential name collisions ourselves.
+ seen = {}
+ types_seen = {}
+ for v in self.variants.variants:
+ v.check_clash(self.info, seen)
+ qtype = v.type.alternate_qtype()
+ if not qtype:
+ raise QAPISemError(
+ self.info,
+ "%s cannot use %s"
+ % (v.describe(self.info), v.type.describe()))
+ conflicting = set([qtype])
+ if qtype == 'QTYPE_QSTRING':
+ if isinstance(v.type, QAPISchemaEnumType):
+ for m in v.type.members:
+ if m.name in ['on', 'off']:
+ conflicting.add('QTYPE_QBOOL')
+ if re.match(r'[-+0-9.]', m.name):
+ # lazy, could be tightened
+ conflicting.add('QTYPE_QNUM')
+ else:
+ conflicting.add('QTYPE_QNUM')
+ conflicting.add('QTYPE_QBOOL')
+ for qt in conflicting:
+ if qt in types_seen:
+ raise QAPISemError(
+ self.info,
+ "%s can't be distinguished from '%s'"
+ % (v.describe(self.info), types_seen[qt]))
+ types_seen[qt] = v.name
-class QAPISchemaFeature(QAPISchemaMember):
- role = 'feature'
+ def connect_doc(self, doc=None):
+ super().connect_doc(doc)
+ doc = doc or self.doc
+ for v in self.variants.variants:
+ v.connect_doc(doc)
+ def c_type(self):
+ return c_name(self.name) + pointer_suffix
-class QAPISchemaObjectTypeMember(QAPISchemaMember):
- def __init__(self, name, info, typ, optional, ifcond=None):
- super().__init__(name, info, ifcond)
- assert isinstance(typ, str)
- assert isinstance(optional, bool)
- self._type_name = typ
- self.type = None
- self.optional = optional
+ def json_type(self):
+ return 'value'
- def check(self, schema):
- assert self.defined_in
- self.type = schema.resolve_type(self._type_name, self.info,
- self.describe)
+ def visit(self, visitor):
+ super().visit(visitor)
+ visitor.visit_alternate_type(
+ self.name, self.info, self.ifcond, self.features, self.variants)
-class QAPISchemaObjectTypeVariants:
+class QAPISchemaVariants:
def __init__(self, tag_name, info, tag_member, variants):
# Flat unions pass tag_name but not tag_member.
# Simple unions and alternates pass tag_member but not tag_name.
assert (isinstance(tag_name, str) or
isinstance(tag_member, QAPISchemaObjectTypeMember))
for v in variants:
- assert isinstance(v, QAPISchemaObjectTypeVariant)
+ assert isinstance(v, QAPISchemaVariant)
self._tag_name = tag_name
self.info = info
self.tag_member = tag_member
cases = {v.name for v in self.variants}
for m in self.tag_member.type.members:
if m.name not in cases:
- v = QAPISchemaObjectTypeVariant(m.name, self.info,
- 'q_empty', m.ifcond)
+ v = QAPISchemaVariant(m.name, self.info,
+ 'q_empty', m.ifcond)
v.set_defined_in(self.tag_member.defined_in)
self.variants.append(v)
if not self.variants:
v.type.check_clash(info, dict(seen))
-class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
- role = 'branch'
+class QAPISchemaMember:
+ """ Represents object members, enum members and features """
+ role = 'member'
- def __init__(self, name, info, typ, ifcond=None):
- super().__init__(name, info, typ, False, ifcond)
+ def __init__(self, name, info, ifcond=None):
+ assert isinstance(name, str)
+ self.name = name
+ self.info = info
+ self.ifcond = ifcond or []
+ self.defined_in = None
+ def set_defined_in(self, name):
+ assert not self.defined_in
+ self.defined_in = name
-class QAPISchemaAlternateType(QAPISchemaType):
- meta = 'alternate'
+ def check_clash(self, info, seen):
+ cname = c_name(self.name)
+ if cname in seen:
+ raise QAPISemError(
+ info,
+ "%s collides with %s"
+ % (self.describe(info), seen[cname].describe(info)))
+ seen[cname] = self
+
+ def connect_doc(self, doc):
+ if doc:
+ doc.connect_member(self)
+
+ def describe(self, info):
+ role = self.role
+ defined_in = self.defined_in
+ assert defined_in
+
+ if defined_in.startswith('q_obj_'):
+ # See QAPISchema._make_implicit_object_type() - reverse the
+ # mapping there to create a nice human-readable description
+ defined_in = defined_in[6:]
+ if defined_in.endswith('-arg'):
+ # Implicit type created for a command's dict 'data'
+ assert role == 'member'
+ role = 'parameter'
+ elif defined_in.endswith('-base'):
+ # Implicit type created for a flat union's dict 'base'
+ role = 'base ' + role
+ else:
+ # Implicit type created for a simple union's branch
+ assert defined_in.endswith('-wrapper')
+ # Unreachable and not implemented
+ assert False
+ elif defined_in.endswith('Kind'):
+ # See QAPISchema._make_implicit_enum_type()
+ # Implicit enum created for simple union's branches
+ assert role == 'value'
+ role = 'branch'
+ elif defined_in != info.defn_name:
+ return "%s '%s' of type '%s'" % (role, self.name, defined_in)
+ return "%s '%s'" % (role, self.name)
+
+
+class QAPISchemaEnumMember(QAPISchemaMember):
+ role = 'value'
+
+
+class QAPISchemaFeature(QAPISchemaMember):
+ role = 'feature'
- def __init__(self, name, info, doc, ifcond, variants):
- super().__init__(name, info, doc, ifcond)
- assert isinstance(variants, QAPISchemaObjectTypeVariants)
- assert variants.tag_member
- variants.set_defined_in(name)
- variants.tag_member.set_defined_in(self.name)
- self.variants = variants
+
+class QAPISchemaObjectTypeMember(QAPISchemaMember):
+ def __init__(self, name, info, typ, optional, ifcond=None, features=None):
+ super().__init__(name, info, ifcond)
+ assert isinstance(typ, str)
+ assert isinstance(optional, bool)
+ for f in features or []:
+ assert isinstance(f, QAPISchemaFeature)
+ f.set_defined_in(name)
+ self._type_name = typ
+ self.type = None
+ self.optional = optional
+ self.features = features or []
def check(self, schema):
- super().check(schema)
- self.variants.tag_member.check(schema)
- # Not calling self.variants.check_clash(), because there's nothing
- # to clash with
- self.variants.check(schema, {})
- # Alternate branch names have no relation to the tag enum values;
- # so we have to check for potential name collisions ourselves.
+ assert self.defined_in
+ self.type = schema.resolve_type(self._type_name, self.info,
+ self.describe)
seen = {}
- types_seen = {}
- for v in self.variants.variants:
- v.check_clash(self.info, seen)
- qtype = v.type.alternate_qtype()
- if not qtype:
- raise QAPISemError(
- self.info,
- "%s cannot use %s"
- % (v.describe(self.info), v.type.describe()))
- conflicting = set([qtype])
- if qtype == 'QTYPE_QSTRING':
- if isinstance(v.type, QAPISchemaEnumType):
- for m in v.type.members:
- if m.name in ['on', 'off']:
- conflicting.add('QTYPE_QBOOL')
- if re.match(r'[-+0-9.]', m.name):
- # lazy, could be tightened
- conflicting.add('QTYPE_QNUM')
- else:
- conflicting.add('QTYPE_QNUM')
- conflicting.add('QTYPE_QBOOL')
- for qt in conflicting:
- if qt in types_seen:
- raise QAPISemError(
- self.info,
- "%s can't be distinguished from '%s'"
- % (v.describe(self.info), types_seen[qt]))
- types_seen[qt] = v.name
+ for f in self.features:
+ f.check_clash(self.info, seen)
- def connect_doc(self, doc=None):
- doc = doc or self.doc
+ def connect_doc(self, doc):
+ super().connect_doc(doc)
if doc:
- for v in self.variants.variants:
- doc.connect_member(v)
+ for f in self.features:
+ doc.connect_feature(f)
- def c_type(self):
- return c_name(self.name) + pointer_suffix
- def json_type(self):
- return 'value'
+class QAPISchemaVariant(QAPISchemaObjectTypeMember):
+ role = 'branch'
- def visit(self, visitor):
- super().visit(visitor)
- visitor.visit_alternate_type(self.name, self.info, self.ifcond,
- self.variants)
+ def __init__(self, name, info, typ, ifcond=None):
+ super().__init__(name, info, typ, False, ifcond)
class QAPISchemaCommand(QAPISchemaEntity):
meta = 'command'
- def __init__(self, name, info, doc, ifcond, arg_type, ret_type,
- gen, success_response, boxed, allow_oob, allow_preconfig,
- features):
+ def __init__(self, name, info, doc, ifcond, features,
+ arg_type, ret_type,
+ gen, success_response, boxed, allow_oob, allow_preconfig):
super().__init__(name, info, doc, ifcond, features)
assert not arg_type or isinstance(arg_type, str)
assert not ret_type or isinstance(ret_type, str)
% self.ret_type.describe())
def connect_doc(self, doc=None):
+ super().connect_doc(doc)
doc = doc or self.doc
if doc:
if self.arg_type and self.arg_type.is_implicit():
def visit(self, visitor):
super().visit(visitor)
- visitor.visit_command(self.name, self.info, self.ifcond,
- self.arg_type, self.ret_type,
- self.gen, self.success_response,
- self.boxed, self.allow_oob,
- self.allow_preconfig,
- self.features)
+ visitor.visit_command(
+ self.name, self.info, self.ifcond, self.features,
+ self.arg_type, self.ret_type, self.gen, self.success_response,
+ self.boxed, self.allow_oob, self.allow_preconfig)
class QAPISchemaEvent(QAPISchemaEntity):
meta = 'event'
- def __init__(self, name, info, doc, ifcond, arg_type, boxed):
- super().__init__(name, info, doc, ifcond)
+ def __init__(self, name, info, doc, ifcond, features, arg_type, boxed):
+ super().__init__(name, info, doc, ifcond, features)
assert not arg_type or isinstance(arg_type, str)
self._arg_type_name = arg_type
self.arg_type = None
% self.arg_type.describe())
def connect_doc(self, doc=None):
+ super().connect_doc(doc)
doc = doc or self.doc
if doc:
if self.arg_type and self.arg_type.is_implicit():
def visit(self, visitor):
super().visit(visitor)
- visitor.visit_event(self.name, self.info, self.ifcond,
- self.arg_type, self.boxed)
+ visitor.visit_event(
+ self.name, self.info, self.ifcond, self.features,
+ self.arg_type, self.boxed)
class QAPISchema:
('null', 'null', 'QNull' + pointer_suffix)]:
self._def_builtin_type(*t)
self.the_empty_object_type = QAPISchemaObjectType(
- 'q_empty', None, None, None, None, [], None, [])
+ 'q_empty', None, None, None, None, None, [], None)
self._def_entity(self.the_empty_object_type)
qtypes = ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist',
qtype_values = self._make_enum_members(
[{'name': n} for n in qtypes], None)
- self._def_entity(QAPISchemaEnumType('QType', None, None, None,
+ self._def_entity(QAPISchemaEnumType('QType', None, None, None, None,
qtype_values, 'QTYPE'))
def _make_features(self, features, info):
+ if features is None:
+ return []
return [QAPISchemaFeature(f['name'], info, f.get('if'))
for f in features]
# See also QAPISchemaObjectTypeMember.describe()
name = name + 'Kind' # reserved by check_defn_name_str()
self._def_entity(QAPISchemaEnumType(
- name, info, None, ifcond, self._make_enum_members(values, info),
+ name, info, None, ifcond, None,
+ self._make_enum_members(values, info),
None))
return name
# TODO kill simple unions or implement the disjunction
assert (ifcond or []) == typ._ifcond # pylint: disable=protected-access
else:
- self._def_entity(QAPISchemaObjectType(name, info, None, ifcond,
- None, members, None, []))
+ self._def_entity(QAPISchemaObjectType(
+ name, info, None, ifcond, None, None, members, None))
return name
def _def_enum_type(self, expr, info, doc):
data = expr['data']
prefix = expr.get('prefix')
ifcond = expr.get('if')
+ features = self._make_features(expr.get('features'), info)
self._def_entity(QAPISchemaEnumType(
- name, info, doc, ifcond,
+ name, info, doc, ifcond, features,
self._make_enum_members(data, info), prefix))
- def _make_member(self, name, typ, ifcond, info):
+ def _make_member(self, name, typ, ifcond, features, info):
optional = False
if name.startswith('*'):
name = name[1:]
if isinstance(typ, list):
assert len(typ) == 1
typ = self._make_array_type(typ[0], info)
- return QAPISchemaObjectTypeMember(name, info, typ, optional, ifcond)
+ return QAPISchemaObjectTypeMember(name, info, typ, optional, ifcond,
+ self._make_features(features, info))
def _make_members(self, data, info):
- return [self._make_member(key, value['type'], value.get('if'), info)
+ return [self._make_member(key, value['type'], value.get('if'),
+ value.get('features'), info)
for (key, value) in data.items()]
def _def_struct_type(self, expr, info, doc):
base = expr.get('base')
data = expr['data']
ifcond = expr.get('if')
- features = expr.get('features', [])
+ features = self._make_features(expr.get('features'), info)
self._def_entity(QAPISchemaObjectType(
- name, info, doc, ifcond, base,
+ name, info, doc, ifcond, features, base,
self._make_members(data, info),
- None,
- self._make_features(features, info)))
+ None))
def _make_variant(self, case, typ, ifcond, info):
- return QAPISchemaObjectTypeVariant(case, info, typ, ifcond)
+ return QAPISchemaVariant(case, info, typ, ifcond)
def _make_simple_variant(self, case, typ, ifcond, info):
if isinstance(typ, list):
typ = self._make_array_type(typ[0], info)
typ = self._make_implicit_object_type(
typ, info, self.lookup_type(typ),
- 'wrapper', [self._make_member('data', typ, None, info)])
- return QAPISchemaObjectTypeVariant(case, info, typ, ifcond)
+ 'wrapper', [self._make_member('data', typ, None, None, info)])
+ return QAPISchemaVariant(case, info, typ, ifcond)
def _def_union_type(self, expr, info, doc):
name = expr['union']
data = expr['data']
base = expr.get('base')
ifcond = expr.get('if')
+ features = self._make_features(expr.get('features'), info)
tag_name = expr.get('discriminator')
tag_member = None
if isinstance(base, dict):
tag_member = QAPISchemaObjectTypeMember('type', info, typ, False)
members = [tag_member]
self._def_entity(
- QAPISchemaObjectType(name, info, doc, ifcond, base, members,
- QAPISchemaObjectTypeVariants(
- tag_name, info, tag_member, variants),
- []))
+ QAPISchemaObjectType(name, info, doc, ifcond, features,
+ base, members,
+ QAPISchemaVariants(
+ tag_name, info, tag_member, variants)))
def _def_alternate_type(self, expr, info, doc):
name = expr['alternate']
data = expr['data']
ifcond = expr.get('if')
+ features = self._make_features(expr.get('features'), info)
variants = [self._make_variant(key, value['type'], value.get('if'),
info)
for (key, value) in data.items()]
tag_member = QAPISchemaObjectTypeMember('type', info, 'QType', False)
self._def_entity(
- QAPISchemaAlternateType(name, info, doc, ifcond,
- QAPISchemaObjectTypeVariants(
+ QAPISchemaAlternateType(name, info, doc, ifcond, features,
+ QAPISchemaVariants(
None, info, tag_member, variants)))
def _def_command(self, expr, info, doc):
allow_oob = expr.get('allow-oob', False)
allow_preconfig = expr.get('allow-preconfig', False)
ifcond = expr.get('if')
- features = expr.get('features', [])
+ features = self._make_features(expr.get('features'), info)
if isinstance(data, OrderedDict):
data = self._make_implicit_object_type(
- name, info, ifcond, 'arg', self._make_members(data, info))
+ name, info, ifcond,
+ 'arg', self._make_members(data, info))
if isinstance(rets, list):
assert len(rets) == 1
rets = self._make_array_type(rets[0], info)
- self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, data, rets,
+ self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, features,
+ data, rets,
gen, success_response,
- boxed, allow_oob, allow_preconfig,
- self._make_features(features, info)))
+ boxed, allow_oob, allow_preconfig))
def _def_event(self, expr, info, doc):
name = expr['event']
data = expr.get('data')
boxed = expr.get('boxed', False)
ifcond = expr.get('if')
+ features = self._make_features(expr.get('features'), info)
if isinstance(data, OrderedDict):
data = self._make_implicit_object_type(
- name, info, ifcond, 'arg', self._make_members(data, info))
- self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, data, boxed))
+ name, info, ifcond,
+ 'arg', self._make_members(data, info))
+ self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, features,
+ data, boxed))
def _def_exprs(self, exprs):
for expr_elem in exprs:
self._genh.add(gen_type_cleanup_decl(name))
self._genc.add(gen_type_cleanup(name))
- def visit_enum_type(self, name, info, ifcond, members, prefix):
+ def visit_enum_type(self, name, info, ifcond, features, members, prefix):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.preamble_add(gen_enum(name, members, prefix))
self._genc.add(gen_enum_lookup(name, members, prefix))
self._genh.add(gen_array(name, element_type))
self._gen_type_cleanup(name)
- def visit_object_type(self, name, info, ifcond, base, members, variants,
- features):
+ def visit_object_type(self, name, info, ifcond, features,
+ base, members, variants):
# Nothing to do for the special empty builtin
if name == 'q_empty':
return
# implicit types won't be directly allocated/freed
self._gen_type_cleanup(name)
- def visit_alternate_type(self, name, info, ifcond, variants):
+ def visit_alternate_type(self, name, info, ifcond, features, variants):
with ifcontext(ifcond, self._genh):
self._genh.preamble_add(gen_fwd_object_or_array(name))
self._genh.add(gen_object(name, ifcond, None,
''',
types=types))
- def visit_enum_type(self, name, info, ifcond, members, prefix):
+ def visit_enum_type(self, name, info, ifcond, features, members, prefix):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_visit_decl(name, scalar=True))
self._genc.add(gen_visit_enum(name))
self._genh.add(gen_visit_decl(name))
self._genc.add(gen_visit_list(name, element_type))
- def visit_object_type(self, name, info, ifcond, base, members, variants,
- features):
+ def visit_object_type(self, name, info, ifcond, features,
+ base, members, variants):
# Nothing to do for the special empty builtin
if name == 'q_empty':
return
self._genh.add(gen_visit_decl(name))
self._genc.add(gen_visit_object(name, base, members, variants))
- def visit_alternate_type(self, name, info, ifcond, variants):
+ def visit_alternate_type(self, name, info, ifcond, features, variants):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_visit_decl(name))
self._genc.add(gen_visit_alternate(name, variants))
bool alpha_cpu_exec_interrupt(CPUState *cpu, int int_req);
void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags);
hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int alpha_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int alpha_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void alpha_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
#include "cpu.h"
#include "exec/gdbstub.h"
-int alpha_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int alpha_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
AlphaCPU *cpu = ALPHA_CPU(cs);
CPUAlphaState *env = &cpu->env;
env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 2, 3);
/* and to the SVE instructions */
env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 16, 2, 3);
- /* with maximum vector length */
- env->vfp.zcr_el[1] = cpu_isar_feature(aa64_sve, cpu) ?
- cpu->sve_max_vq - 1 : 0;
+ /* with reasonable vector length */
+ if (cpu_isar_feature(aa64_sve, cpu)) {
+ env->vfp.zcr_el[1] = MIN(cpu->sve_max_vq - 1, 3);
+ }
/*
* Enable TBI0 and TBI1. While the real kernel only enables TBI0,
* turning on both here will produce smaller code and otherwise
/**
* DynamicGDBXMLInfo:
* @desc: Contains the XML descriptions.
- * @num_cpregs: Number of the Coprocessor registers seen by GDB.
- * @cpregs_keys: Array that contains the corresponding Key of
- * a given cpreg with the same order of the cpreg in the XML description.
+ * @num: Number of the registers in this XML seen by GDB.
+ * @data: A union with data specific to the set of registers
+ * @cpregs_keys: Array that contains the corresponding Key of
+ * a given cpreg with the same order of the cpreg
+ * in the XML description.
*/
typedef struct DynamicGDBXMLInfo {
char *desc;
- int num_cpregs;
- uint32_t *cpregs_keys;
+ int num;
+ union {
+ struct {
+ uint32_t *keys;
+ } cpregs;
+ } data;
} DynamicGDBXMLInfo;
/* CPU state for each instance of a generic timer (in cp15 c14) */
uint64_t *cpreg_vmstate_values;
int32_t cpreg_vmstate_array_len;
- DynamicGDBXMLInfo dyn_xml;
+ DynamicGDBXMLInfo dyn_sysreg_xml;
+ DynamicGDBXMLInfo dyn_svereg_xml;
/* Timers used by the generic (architected) timer */
QEMUTimer *gt_timer[NUM_GTIMERS];
hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
MemTxAttrs *attrs);
-int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int arm_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
-/* Dynamically generates for gdb stub an XML description of the sysregs from
- * the cp_regs hashtable. Returns the registered sysregs number.
+/*
+ * Helpers to dynamically generates XML descriptions of the sysregs
+ * and SVE registers. Returns the number of registers in each set.
*/
-int arm_gen_dynamic_xml(CPUState *cpu);
+int arm_gen_dynamic_sysreg_xml(CPUState *cpu, int base_reg);
+int arm_gen_dynamic_svereg_xml(CPUState *cpu, int base_reg);
/* Returns the dynamically generated XML for the gdb stub.
* Returns a pointer to the XML contents for the specified XML file or NULL
int cpuid, void *opaque);
#ifdef TARGET_AARCH64
-int aarch64_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int aarch64_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq);
void aarch64_sve_change_el(CPUARMState *env, int old_el,
typedef struct RegisterSysregXmlParam {
CPUState *cs;
GString *s;
+ int n;
} RegisterSysregXmlParam;
/* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect
We hack round this by giving the FPA regs zero size when talking to a
newer gdb. */
-int arm_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
return 0;
}
-static void arm_gen_one_xml_reg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
- ARMCPRegInfo *ri, uint32_t ri_key,
- int bitsize)
+static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
+ ARMCPRegInfo *ri, uint32_t ri_key,
+ int bitsize, int regnum)
{
g_string_append_printf(s, "<reg name=\"%s\"", ri->name);
g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
+ g_string_append_printf(s, " regnum=\"%d\"", regnum);
g_string_append_printf(s, " group=\"cp_regs\"/>");
- dyn_xml->num_cpregs++;
- dyn_xml->cpregs_keys[dyn_xml->num_cpregs - 1] = ri_key;
+ dyn_xml->data.cpregs.keys[dyn_xml->num] = ri_key;
+ dyn_xml->num++;
}
static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
GString *s = param->s;
ARMCPU *cpu = ARM_CPU(param->cs);
CPUARMState *env = &cpu->env;
- DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_xml;
+ DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_sysreg_xml;
if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) {
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
if (ri->state == ARM_CP_STATE_AA64) {
- arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64);
+ arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
+ param->n++);
}
} else {
if (ri->state == ARM_CP_STATE_AA32) {
return;
}
if (ri->type & ARM_CP_64BIT) {
- arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64);
+ arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
+ param->n++);
} else {
- arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 32);
+ arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32,
+ param->n++);
}
}
}
}
}
-int arm_gen_dynamic_xml(CPUState *cs)
+int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg)
{
ARMCPU *cpu = ARM_CPU(cs);
GString *s = g_string_new(NULL);
- RegisterSysregXmlParam param = {cs, s};
+ RegisterSysregXmlParam param = {cs, s, base_reg};
- cpu->dyn_xml.num_cpregs = 0;
- cpu->dyn_xml.cpregs_keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
+ cpu->dyn_sysreg_xml.num = 0;
+ cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
g_string_printf(s, "<?xml version=\"1.0\"?>");
g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">");
g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, ¶m);
g_string_append_printf(s, "</feature>");
- cpu->dyn_xml.desc = g_string_free(s, false);
- return cpu->dyn_xml.num_cpregs;
+ cpu->dyn_sysreg_xml.desc = g_string_free(s, false);
+ return cpu->dyn_sysreg_xml.num;
}
+struct TypeSize {
+ const char *gdb_type;
+ int size;
+ const char sz, suffix;
+};
+
+static const struct TypeSize vec_lanes[] = {
+ /* quads */
+ { "uint128", 128, 'q', 'u' },
+ { "int128", 128, 'q', 's' },
+ /* 64 bit */
+ { "uint64", 64, 'd', 'u' },
+ { "int64", 64, 'd', 's' },
+ { "ieee_double", 64, 'd', 'f' },
+ /* 32 bit */
+ { "uint32", 32, 's', 'u' },
+ { "int32", 32, 's', 's' },
+ { "ieee_single", 32, 's', 'f' },
+ /* 16 bit */
+ { "uint16", 16, 'h', 'u' },
+ { "int16", 16, 'h', 's' },
+ { "ieee_half", 16, 'h', 'f' },
+ /* bytes */
+ { "uint8", 8, 'b', 'u' },
+ { "int8", 8, 'b', 's' },
+};
+
+
+int arm_gen_dynamic_svereg_xml(CPUState *cs, int base_reg)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ GString *s = g_string_new(NULL);
+ DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml;
+ g_autoptr(GString) ts = g_string_new("");
+ int i, bits, reg_width = (cpu->sve_max_vq * 128);
+ info->num = 0;
+ g_string_printf(s, "<?xml version=\"1.0\"?>");
+ g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
+ g_string_append_printf(s, "<feature name=\"org.qemu.gdb.aarch64.sve\">");
+
+ /* First define types and totals in a whole VL */
+ for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
+ int count = reg_width / vec_lanes[i].size;
+ g_string_printf(ts, "vq%d%c%c", count,
+ vec_lanes[i].sz, vec_lanes[i].suffix);
+ g_string_append_printf(s,
+ "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
+ ts->str, vec_lanes[i].gdb_type, count);
+ }
+ /*
+ * Now define a union for each size group containing unsigned and
+ * signed and potentially float versions of each size from 128 to
+ * 8 bits.
+ */
+ for (bits = 128; bits >= 8; bits /= 2) {
+ int count = reg_width / bits;
+ g_string_append_printf(s, "<union id=\"vq%dn\">", count);
+ for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
+ if (vec_lanes[i].size == bits) {
+ g_string_append_printf(s, "<field name=\"%c\" type=\"vq%d%c%c\"/>",
+ vec_lanes[i].suffix,
+ count,
+ vec_lanes[i].sz, vec_lanes[i].suffix);
+ }
+ }
+ g_string_append(s, "</union>");
+ }
+ /* And now the final union of unions */
+ g_string_append(s, "<union id=\"vq\">");
+ for (bits = 128; bits >= 8; bits /= 2) {
+ int count = reg_width / bits;
+ for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
+ if (vec_lanes[i].size == bits) {
+ g_string_append_printf(s, "<field name=\"%c\" type=\"vq%dn\"/>",
+ vec_lanes[i].sz, count);
+ break;
+ }
+ }
+ }
+ g_string_append(s, "</union>");
+
+ /* Then define each register in parts for each vq */
+ for (i = 0; i < 32; i++) {
+ g_string_append_printf(s,
+ "<reg name=\"z%d\" bitsize=\"%d\""
+ " regnum=\"%d\" group=\"vector\""
+ " type=\"vq\"/>",
+ i, reg_width, base_reg++);
+ info->num++;
+ }
+ /* fpscr & status registers */
+ g_string_append_printf(s, "<reg name=\"fpsr\" bitsize=\"32\""
+ " regnum=\"%d\" group=\"float\""
+ " type=\"int\"/>", base_reg++);
+ g_string_append_printf(s, "<reg name=\"fpcr\" bitsize=\"32\""
+ " regnum=\"%d\" group=\"float\""
+ " type=\"int\"/>", base_reg++);
+ info->num += 2;
+ /*
+ * Predicate registers aren't so big they are worth splitting up
+ * but we do need to define a type to hold the array of quad
+ * references.
+ */
+ g_string_append_printf(s,
+ "<vector id=\"vqp\" type=\"uint16\" count=\"%d\"/>",
+ cpu->sve_max_vq);
+ for (i = 0; i < 16; i++) {
+ g_string_append_printf(s,
+ "<reg name=\"p%d\" bitsize=\"%d\""
+ " regnum=\"%d\" group=\"vector\""
+ " type=\"vqp\"/>",
+ i, cpu->sve_max_vq * 16, base_reg++);
+ info->num++;
+ }
+ g_string_append_printf(s,
+ "<reg name=\"ffr\" bitsize=\"%d\""
+ " regnum=\"%d\" group=\"vector\""
+ " type=\"vqp\"/>",
+ cpu->sve_max_vq * 16, base_reg++);
+ g_string_append_printf(s,
+ "<reg name=\"vg\" bitsize=\"64\""
+ " regnum=\"%d\" group=\"vector\""
+ " type=\"uint32\"/>",
+ base_reg++);
+ info->num += 2;
+ g_string_append_printf(s, "</feature>");
+ cpu->dyn_svereg_xml.desc = g_string_free(s, false);
+
+ return cpu->dyn_svereg_xml.num;
+}
+
+
const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
{
ARMCPU *cpu = ARM_CPU(cs);
if (strcmp(xmlname, "system-registers.xml") == 0) {
- return cpu->dyn_xml.desc;
+ return cpu->dyn_sysreg_xml.desc;
+ } else if (strcmp(xmlname, "sve-registers.xml") == 0) {
+ return cpu->dyn_svereg_xml.desc;
}
return NULL;
}
#include "cpu.h"
#include "exec/gdbstub.h"
-int aarch64_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int aarch64_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
static void switch_mode(CPUARMState *env, int mode);
-static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
+static int vfp_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
{
ARMCPU *cpu = env_archcpu(env);
int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16;
/* VFP data registers are always little-endian. */
if (reg < nregs) {
- stq_le_p(buf, *aa32_vfp_dreg(env, reg));
- return 8;
+ return gdb_get_reg64(buf, *aa32_vfp_dreg(env, reg));
}
if (arm_feature(env, ARM_FEATURE_NEON)) {
/* Aliases for Q regs. */
nregs += 16;
if (reg < nregs) {
uint64_t *q = aa32_vfp_qreg(env, reg - 32);
- stq_le_p(buf, q[0]);
- stq_le_p(buf + 8, q[1]);
- return 16;
+ return gdb_get_reg128(buf, q[0], q[1]);
}
}
switch (reg - nregs) {
- case 0: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSID]); return 4;
- case 1: stl_p(buf, vfp_get_fpscr(env)); return 4;
- case 2: stl_p(buf, env->vfp.xregs[ARM_VFP_FPEXC]); return 4;
+ case 0: return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPSID]); break;
+ case 1: return gdb_get_reg32(buf, vfp_get_fpscr(env)); break;
+ case 2: return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPEXC]); break;
}
return 0;
}
return 0;
}
-static int aarch64_fpu_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
+static int aarch64_fpu_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
{
switch (reg) {
case 0 ... 31:
- /* 128 bit FP register */
- {
- uint64_t *q = aa64_vfp_qreg(env, reg);
- stq_le_p(buf, q[0]);
- stq_le_p(buf + 8, q[1]);
- return 16;
- }
+ {
+ /* 128 bit FP register - quads are in LE order */
+ uint64_t *q = aa64_vfp_qreg(env, reg);
+ return gdb_get_reg128(buf, q[1], q[0]);
+ }
case 32:
/* FPSR */
- stl_p(buf, vfp_get_fpsr(env));
- return 4;
+ return gdb_get_reg32(buf, vfp_get_fpsr(env));
case 33:
/* FPCR */
- stl_p(buf, vfp_get_fpcr(env));
- return 4;
+ return gdb_get_reg32(buf,vfp_get_fpcr(env));
default:
return 0;
}
}
}
-static int arm_gdb_get_sysreg(CPUARMState *env, uint8_t *buf, int reg)
+/**
+ * arm_get/set_gdb_*: get/set a gdb register
+ * @env: the CPU state
+ * @buf: a buffer to copy to/from
+ * @reg: register number (offset from start of group)
+ *
+ * We return the number of bytes copied
+ */
+
+static int arm_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg)
{
ARMCPU *cpu = env_archcpu(env);
const ARMCPRegInfo *ri;
uint32_t key;
- key = cpu->dyn_xml.cpregs_keys[reg];
+ key = cpu->dyn_sysreg_xml.data.cpregs.keys[reg];
ri = get_arm_cp_reginfo(cpu->cp_regs, key);
if (ri) {
if (cpreg_field_is_64bit(ri)) {
return 0;
}
+#ifdef TARGET_AARCH64
+static int arm_gdb_get_svereg(CPUARMState *env, GByteArray *buf, int reg)
+{
+ ARMCPU *cpu = env_archcpu(env);
+
+ switch (reg) {
+ /* The first 32 registers are the zregs */
+ case 0 ... 31:
+ {
+ int vq, len = 0;
+ for (vq = 0; vq < cpu->sve_max_vq; vq++) {
+ len += gdb_get_reg128(buf,
+ env->vfp.zregs[reg].d[vq * 2 + 1],
+ env->vfp.zregs[reg].d[vq * 2]);
+ }
+ return len;
+ }
+ case 32:
+ return gdb_get_reg32(buf, vfp_get_fpsr(env));
+ case 33:
+ return gdb_get_reg32(buf, vfp_get_fpcr(env));
+ /* then 16 predicates and the ffr */
+ case 34 ... 50:
+ {
+ int preg = reg - 34;
+ int vq, len = 0;
+ for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) {
+ len += gdb_get_reg64(buf, env->vfp.pregs[preg].p[vq / 4]);
+ }
+ return len;
+ }
+ case 51:
+ {
+ /*
+ * We report in Vector Granules (VG) which is 64bit in a Z reg
+ * while the ZCR works in Vector Quads (VQ) which is 128bit chunks.
+ */
+ int vq = sve_zcr_len_for_el(env, arm_current_el(env)) + 1;
+ return gdb_get_reg32(buf, vq * 2);
+ }
+ default:
+ /* gdbstub asked for something out our range */
+ qemu_log_mask(LOG_UNIMP, "%s: out of range register %d", __func__, reg);
+ break;
+ }
+
+ return 0;
+}
+
+static int arm_gdb_set_svereg(CPUARMState *env, uint8_t *buf, int reg)
+{
+ ARMCPU *cpu = env_archcpu(env);
+
+ /* The first 32 registers are the zregs */
+ switch (reg) {
+ /* The first 32 registers are the zregs */
+ case 0 ... 31:
+ {
+ int vq, len = 0;
+ uint64_t *p = (uint64_t *) buf;
+ for (vq = 0; vq < cpu->sve_max_vq; vq++) {
+ env->vfp.zregs[reg].d[vq * 2 + 1] = *p++;
+ env->vfp.zregs[reg].d[vq * 2] = *p++;
+ len += 16;
+ }
+ return len;
+ }
+ case 32:
+ vfp_set_fpsr(env, *(uint32_t *)buf);
+ return 4;
+ case 33:
+ vfp_set_fpcr(env, *(uint32_t *)buf);
+ return 4;
+ case 34 ... 50:
+ {
+ int preg = reg - 34;
+ int vq, len = 0;
+ uint64_t *p = (uint64_t *) buf;
+ for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) {
+ env->vfp.pregs[preg].p[vq / 4] = *p++;
+ len += 8;
+ }
+ return len;
+ }
+ case 51:
+ /* cannot set vg via gdbstub */
+ return 0;
+ default:
+ /* gdbstub asked for something out our range */
+ break;
+ }
+
+ return 0;
+}
+#endif /* TARGET_AARCH64 */
+
static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
{
/* Return true if the regdef would cause an assertion if you called
return pfr1;
}
+#ifndef CONFIG_USER_ONLY
static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
ARMCPU *cpu = env_archcpu(env);
}
return pfr0;
}
+#endif
/* Shared logic between LORID and the rest of the LOR* registers.
* Secure state has already been delt with.
* define new registers here.
*/
ARMCPRegInfo v8_idregs[] = {
- /* ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST because we don't
- * know the right value for the GIC field until after we
- * define these regs.
+ /*
+ * ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST in system
+ * emulation because we don't know the right value for the
+ * GIC field until after we define these regs.
*/
{ .name = "ID_AA64PFR0_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 0,
- .access = PL1_R, .type = ARM_CP_NO_RAW,
+ .access = PL1_R,
+#ifdef CONFIG_USER_ONLY
+ .type = ARM_CP_CONST,
+ .resetvalue = cpu->isar.id_aa64pfr0
+#else
+ .type = ARM_CP_NO_RAW,
.accessfn = access_aa64_tid3,
.readfn = id_aa64pfr0_read,
- .writefn = arm_cp_write_ignore },
+ .writefn = arm_cp_write_ignore
+#endif
+ },
{ .name = "ID_AA64PFR1_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1,
.access = PL1_R, .type = ARM_CP_CONST,
CPUARMState *env = &cpu->env;
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
- gdb_register_coprocessor(cs, aarch64_fpu_gdb_get_reg,
- aarch64_fpu_gdb_set_reg,
- 34, "aarch64-fpu.xml", 0);
+ /*
+ * The lower part of each SVE register aliases to the FPU
+ * registers so we don't need to include both.
+ */
+#ifdef TARGET_AARCH64
+ if (isar_feature_aa64_sve(&cpu->isar)) {
+ gdb_register_coprocessor(cs, arm_gdb_get_svereg, arm_gdb_set_svereg,
+ arm_gen_dynamic_svereg_xml(cs, cs->gdb_num_regs),
+ "sve-registers.xml", 0);
+ } else
+#endif
+ {
+ gdb_register_coprocessor(cs, aarch64_fpu_gdb_get_reg,
+ aarch64_fpu_gdb_set_reg,
+ 34, "aarch64-fpu.xml", 0);
+ }
} else if (arm_feature(env, ARM_FEATURE_NEON)) {
gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
51, "arm-neon.xml", 0);
19, "arm-vfp.xml", 0);
}
gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg,
- arm_gen_dynamic_xml(cs),
+ arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs),
"system-registers.xml", 0);
+
}
/* Sort alphabetically by type name, except for "any". */
return NULL;
}
} else {
- Error *err = NULL;
- arm_cpu_finalize_features(ARM_CPU(obj), &err);
- assert(err == NULL);
+ arm_cpu_finalize_features(ARM_CPU(obj), &error_abort);
}
expansion_info = g_new0(CpuModelExpansionInfo, 1);
while ((name = cpu_model_advertised_features[i++]) != NULL) {
ObjectProperty *prop = object_property_find(obj, name, NULL);
if (prop) {
- Error *err = NULL;
QObject *value;
assert(prop->get);
- value = object_property_get_qobject(obj, name, &err);
- assert(!err);
+ value = object_property_get_qobject(obj, name, &error_abort);
qdict_put_obj(qdict_out, name, value);
}
hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int crisv10_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
-int cris_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int crisv10_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
+int cris_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
/* you can call this signal handler from your SIGBUS and SIGSEGV
#include "cpu.h"
#include "exec/gdbstub.h"
-int crisv10_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int crisv10_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
CRISCPU *cpu = CRIS_CPU(cs);
CPUCRISState *env = &cpu->env;
return 0;
}
-int cris_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int cris_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
CRISCPU *cpu = CRIS_CPU(cs);
CPUCRISState *env = &cpu->env;
int cpu_hppa_signal_handler(int host_signum, void *pinfo, void *puc);
hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr);
-int hppa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int hppa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void hppa_cpu_do_interrupt(CPUState *cpu);
bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req);
#include "cpu.h"
#include "exec/gdbstub.h"
-int hppa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int hppa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
HPPACPU *cpu = HPPA_CPU(cs);
CPUHPPAState *env = &cpu->env;
hwaddr x86_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
MemTxAttrs *attrs);
-int x86_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int x86_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void x86_cpu_exec_enter(CPUState *cpu);
#endif
-int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
return gdb_get_reg64(mem_buf,
env->regs[gpr_map[n]] & 0xffffffffUL);
} else {
- memset(mem_buf, 0, sizeof(target_ulong));
- return sizeof(target_ulong);
+ return gdb_get_regl(mem_buf, 0);
}
} else {
return gdb_get_reg32(mem_buf, env->regs[gpr_map32[n]]);
}
} else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
-#ifdef USE_X86LDOUBLE
- /* FIXME: byteswap float values - after fixing fpregs layout. */
- memcpy(mem_buf, &env->fpregs[n - IDX_FP_REGS], 10);
-#else
- memset(mem_buf, 0, 10);
-#endif
- return 10;
+ floatx80 *fp = (floatx80 *) &env->fpregs[n - IDX_FP_REGS];
+ int len = gdb_get_reg64(mem_buf, cpu_to_le64(fp->low));
+ len += gdb_get_reg16(mem_buf + len, cpu_to_le16(fp->high));
+ return len;
} else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
n -= IDX_XMM_REGS;
if (n < CPU_NB_REGS32 || TARGET_LONG_BITS == 64) {
- stq_p(mem_buf, env->xmm_regs[n].ZMM_Q(0));
- stq_p(mem_buf + 8, env->xmm_regs[n].ZMM_Q(1));
- return 16;
+ return gdb_get_reg128(mem_buf,
+ env->xmm_regs[n].ZMM_Q(0),
+ env->xmm_regs[n].ZMM_Q(1));
}
} else {
switch (n) {
return 4;
}
} else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
-#ifdef USE_X86LDOUBLE
- /* FIXME: byteswap float values - after fixing fpregs layout. */
- memcpy(&env->fpregs[n - IDX_FP_REGS], mem_buf, 10);
-#endif
+ floatx80 *fp = (floatx80 *) &env->fpregs[n - IDX_FP_REGS];
+ fp->low = le64_to_cpu(* (uint64_t *) mem_buf);
+ fp->high = le16_to_cpu(* (uint16_t *) (mem_buf + 8));
return 10;
} else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
n -= IDX_XMM_REGS;
bool lm32_cpu_exec_interrupt(CPUState *cs, int int_req);
void lm32_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int lm32_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int lm32_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
typedef enum {
#include "exec/gdbstub.h"
#include "hw/lm32/lm32_pic.h"
-int lm32_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int lm32_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
LM32CPU *cpu = LM32_CPU(cs);
CPULM32State *env = &cpu->env;
bool m68k_cpu_exec_interrupt(CPUState *cpu, int int_req);
void m68k_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr m68k_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int m68k_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int m68k_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int m68k_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void m68k_tcg_init(void);
#include "cpu.h"
#include "exec/gdbstub.h"
-int m68k_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int m68k_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
M68kCPU *cpu = M68K_CPU(cs);
CPUM68KState *env = &cpu->env;
g_slist_free(list);
}
-static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
+static int cf_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
{
if (n < 8) {
float_status s;
- stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
- return 8;
+ return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
}
switch (n) {
case 8: /* fpcontrol */
- stl_be_p(mem_buf, env->fpcr);
- return 4;
+ return gdb_get_reg32(mem_buf, env->fpcr);
case 9: /* fpstatus */
- stl_be_p(mem_buf, env->fpsr);
- return 4;
+ return gdb_get_reg32(mem_buf, env->fpsr);
case 10: /* fpiar, not implemented */
- memset(mem_buf, 0, 4);
- return 4;
+ return gdb_get_reg32(mem_buf, 0);
}
return 0;
}
return 0;
}
-static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
+static int m68k_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
{
if (n < 8) {
- stw_be_p(mem_buf, env->fregs[n].l.upper);
- memset(mem_buf + 2, 0, 2);
- stq_be_p(mem_buf + 4, env->fregs[n].l.lower);
- return 12;
+ int len = gdb_get_reg16(mem_buf, env->fregs[n].l.upper);
+ len += gdb_get_reg16(mem_buf + len, 0);
+ len += gdb_get_reg64(mem_buf + len, env->fregs[n].l.lower);
+ return len;
}
switch (n) {
case 8: /* fpcontrol */
- stl_be_p(mem_buf, env->fpcr);
- return 4;
+ return gdb_get_reg32(mem_buf, env->fpcr);
case 9: /* fpstatus */
- stl_be_p(mem_buf, env->fpsr);
- return 4;
+ return gdb_get_reg32(mem_buf, env->fpsr);
case 10: /* fpiar, not implemented */
- memset(mem_buf, 0, 4);
- return 4;
+ return gdb_get_reg32(mem_buf, 0);
}
return 0;
}
bool mb_cpu_exec_interrupt(CPUState *cs, int int_req);
void mb_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int mb_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int mb_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void mb_tcg_init(void);
#include "cpu.h"
#include "exec/gdbstub.h"
-int mb_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
CPUMBState *env = &cpu->env;
#include "internal.h"
#include "exec/gdbstub.h"
-int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int mips_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req);
void mips_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int mips_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
#endif
}
-static int nios2_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+static int nios2_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
Nios2CPU *cpu = NIOS2_CPU(cs);
CPUClass *cc = CPU_GET_CLASS(cs);
bool openrisc_cpu_exec_interrupt(CPUState *cpu, int int_req);
void openrisc_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int openrisc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int openrisc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int openrisc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void openrisc_translate_init(void);
bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
#include "cpu.h"
#include "exec/gdbstub.h"
-int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int openrisc_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
CPUOpenRISCState *env = &cpu->env;
uint64_t insns_flags;
uint64_t insns_flags2;
uint64_t msr_mask;
+ uint64_t lpcr_mask; /* Available bits in the LPCR */
uint64_t lpcr_pm; /* Power-saving mode Exit Cause Enable bits */
powerpc_mmu_t mmu_model;
powerpc_excp_t excp_model;
#include "exec/cpu-defs.h"
#include "cpu-qom.h"
-/* #define PPC_EMULATE_32BITS_HYPV */
-
#define TCG_GUEST_DEFAULT_MO 0
#define TARGET_PAGE_BITS_64K 16
#define MSR_SF 63 /* Sixty-four-bit mode hflags */
#define MSR_TAG 62 /* Tag-active mode (POWERx ?) */
#define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */
-#define MSR_SHV 60 /* hypervisor state hflags */
+#define MSR_HV 60 /* hypervisor state hflags */
#define MSR_TS0 34 /* Transactional state, 2 bits (Book3s) */
#define MSR_TS1 33
#define MSR_TM 32 /* Transactional Memory Available (Book3s) */
#define MSR_CM 31 /* Computation mode for BookE hflags */
#define MSR_ICM 30 /* Interrupt computation mode for BookE */
-#define MSR_THV 29 /* hypervisor state for 32 bits PowerPC hflags */
#define MSR_GS 28 /* guest state for BookE */
#define MSR_UCLE 26 /* User-mode cache lock enable for BookE */
#define MSR_VR 25 /* altivec available x hflags */
#define msr_sf ((env->msr >> MSR_SF) & 1)
#define msr_isf ((env->msr >> MSR_ISF) & 1)
-#define msr_shv ((env->msr >> MSR_SHV) & 1)
+#if defined(TARGET_PPC64)
+#define msr_hv ((env->msr >> MSR_HV) & 1)
+#else
+#define msr_hv (0)
+#endif
#define msr_cm ((env->msr >> MSR_CM) & 1)
#define msr_icm ((env->msr >> MSR_ICM) & 1)
-#define msr_thv ((env->msr >> MSR_THV) & 1)
#define msr_gs ((env->msr >> MSR_GS) & 1)
#define msr_ucle ((env->msr >> MSR_UCLE) & 1)
#define msr_vr ((env->msr >> MSR_VR) & 1)
/* Hypervisor bit is more specific */
#if defined(TARGET_PPC64)
-#define MSR_HVB (1ULL << MSR_SHV)
-#define msr_hv msr_shv
-#else
-#if defined(PPC_EMULATE_32BITS_HYPV)
-#define MSR_HVB (1ULL << MSR_THV)
-#define msr_hv msr_thv
+#define MSR_HVB (1ULL << MSR_HV)
#else
#define MSR_HVB (0ULL)
-#define msr_hv (0)
-#endif
#endif
/* DSISR */
uint32_t flags;
uint64_t insns_flags;
uint64_t insns_flags2;
-#if defined(TARGET_PPC64)
- ppc_slb_t vrma_slb;
- target_ulong rmls;
-#endif
int error_code;
uint32_t pending_interrupts;
void ppc_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
void ppc_cpu_dump_statistics(CPUState *cpu, int flags);
hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
-int ppc_cpu_gdb_read_register_apple(CPUState *cpu, uint8_t *buf, int reg);
+int ppc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
+int ppc_cpu_gdb_read_register_apple(CPUState *cpu, GByteArray *buf, int reg);
int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
int ppc_cpu_gdb_write_register_apple(CPUState *cpu, uint8_t *buf, int reg);
#ifndef CONFIG_USER_ONLY
int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque);
#ifndef CONFIG_USER_ONLY
-void ppc_cpu_do_system_reset(CPUState *cs);
+void ppc_cpu_do_system_reset(CPUState *cs, target_ulong vector);
+void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector);
extern const VMStateDescription vmstate_ppc_cpu;
#endif
return offset;
}
+static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
+ target_ulong vector, target_ulong msr)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+
+ /*
+ * We don't use hreg_store_msr here as already have treated any
+ * special case that could occur. Just store MSR and update hflags
+ *
+ * Note: We *MUST* not use hreg_store_msr() as-is anyway because it
+ * will prevent setting of the HV bit which some exceptions might need
+ * to do.
+ */
+ env->msr = msr & env->msr_mask;
+ hreg_compute_hflags(env);
+ env->nip = vector;
+ /* Reset exception state */
+ cs->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+
+ /* Reset the reservation */
+ env->reserve_addr = -1;
+
+ /*
+ * Any interrupt is context synchronizing, check if TCG TLB needs
+ * a delayed flush on ppc64
+ */
+ check_tlb_flush(env, false);
+}
+
/*
* Note that this function should be greatly optimized when called
* with a constant excp, from ppc_hw_interrupt
}
}
#endif
- /*
- * We don't use hreg_store_msr here as already have treated any
- * special case that could occur. Just store MSR and update hflags
- *
- * Note: We *MUST* not use hreg_store_msr() as-is anyway because it
- * will prevent setting of the HV bit which some exceptions might need
- * to do.
- */
- env->msr = new_msr & env->msr_mask;
- hreg_compute_hflags(env);
- env->nip = vector;
- /* Reset exception state */
- cs->exception_index = POWERPC_EXCP_NONE;
- env->error_code = 0;
- /* Reset the reservation */
- env->reserve_addr = -1;
-
- /*
- * Any interrupt is context synchronizing, check if TCG TLB needs
- * a delayed flush on ppc64
- */
- check_tlb_flush(env, false);
+ powerpc_set_excp_state(cpu, vector, new_msr);
}
void ppc_cpu_do_interrupt(CPUState *cs)
}
}
-void ppc_cpu_do_system_reset(CPUState *cs)
+void ppc_cpu_do_system_reset(CPUState *cs, target_ulong vector)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
+ if (vector != -1) {
+ env->nip = vector;
+ }
+}
+
+void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ target_ulong msr = 0;
+
+ /*
+ * Set MSR and NIP for the handler, SRR0/1, DAR and DSISR have already
+ * been set by KVM.
+ */
+ msr = (1ULL << MSR_ME);
+ msr |= env->msr & (1ULL << MSR_SF);
+ if (!(*pcc->interrupts_big_endian)(cpu)) {
+ msr |= (1ULL << MSR_LE);
+ }
+
+ powerpc_set_excp_state(cpu, vector, msr);
}
#endif /* !CONFIG_USER_ONLY */
* the FP regs zero size when talking to a newer gdb.
*/
-int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int ppc_cpu_gdb_read_register(CPUState *cs, GByteArray *buf, int n)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
+ uint8_t *mem_buf;
int r = ppc_gdb_register_len(n);
if (!r) {
if (n < 32) {
/* gprs */
- gdb_get_regl(mem_buf, env->gpr[n]);
+ gdb_get_regl(buf, env->gpr[n]);
} else if (n < 64) {
/* fprs */
- stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32));
+ gdb_get_reg64(buf, *cpu_fpr_ptr(env, n - 32));
} else {
switch (n) {
case 64:
- gdb_get_regl(mem_buf, env->nip);
+ gdb_get_regl(buf, env->nip);
break;
case 65:
- gdb_get_regl(mem_buf, env->msr);
+ gdb_get_regl(buf, env->msr);
break;
case 66:
{
for (i = 0; i < 8; i++) {
cr |= env->crf[i] << (32 - ((i + 1) * 4));
}
- gdb_get_reg32(mem_buf, cr);
+ gdb_get_reg32(buf, cr);
break;
}
case 67:
- gdb_get_regl(mem_buf, env->lr);
+ gdb_get_regl(buf, env->lr);
break;
case 68:
- gdb_get_regl(mem_buf, env->ctr);
+ gdb_get_regl(buf, env->ctr);
break;
case 69:
- gdb_get_reg32(mem_buf, env->xer);
+ gdb_get_reg32(buf, env->xer);
break;
case 70:
- gdb_get_reg32(mem_buf, env->fpscr);
+ gdb_get_reg32(buf, env->fpscr);
break;
}
}
+ mem_buf = buf->data + buf->len - r;
ppc_maybe_bswap_register(env, mem_buf, r);
return r;
}
-int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
+int ppc_cpu_gdb_read_register_apple(CPUState *cs, GByteArray *buf, int n)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
+ uint8_t *mem_buf;
int r = ppc_gdb_register_len_apple(n);
if (!r) {
if (n < 32) {
/* gprs */
- gdb_get_reg64(mem_buf, env->gpr[n]);
+ gdb_get_reg64(buf, env->gpr[n]);
} else if (n < 64) {
/* fprs */
- stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32));
+ gdb_get_reg64(buf, *cpu_fpr_ptr(env, n - 32));
} else if (n < 96) {
/* Altivec */
- stq_p(mem_buf, n - 64);
- stq_p(mem_buf + 8, 0);
+ gdb_get_reg64(buf, n - 64);
+ gdb_get_reg64(buf, 0);
} else {
switch (n) {
case 64 + 32:
- gdb_get_reg64(mem_buf, env->nip);
+ gdb_get_reg64(buf, env->nip);
break;
case 65 + 32:
- gdb_get_reg64(mem_buf, env->msr);
+ gdb_get_reg64(buf, env->msr);
break;
case 66 + 32:
{
for (i = 0; i < 8; i++) {
cr |= env->crf[i] << (32 - ((i + 1) * 4));
}
- gdb_get_reg32(mem_buf, cr);
+ gdb_get_reg32(buf, cr);
break;
}
case 67 + 32:
- gdb_get_reg64(mem_buf, env->lr);
+ gdb_get_reg64(buf, env->lr);
break;
case 68 + 32:
- gdb_get_reg64(mem_buf, env->ctr);
+ gdb_get_reg64(buf, env->ctr);
break;
case 69 + 32:
- gdb_get_reg32(mem_buf, env->xer);
+ gdb_get_reg32(buf, env->xer);
break;
case 70 + 32:
- gdb_get_reg64(mem_buf, env->fpscr);
+ gdb_get_reg64(buf, env->fpscr);
break;
}
}
+ mem_buf = buf->data + buf->len - r;
ppc_maybe_bswap_register(env, mem_buf, r);
return r;
}
#ifdef TARGET_PPC64
-uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
+uint64_t kvmppc_vrma_limit(unsigned int hash_shift)
{
struct kvm_ppc_smmu_info info;
long rampagesize, best_page_shift;
}
}
- return MIN(current_size,
- 1ULL << (best_page_shift + hash_shift - 7));
+ return 1ULL << (best_page_shift + hash_shift - 7);
}
#endif
int *pfd, bool need_vfio);
int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
int kvmppc_reset_htab(int shift_hint);
-uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
+uint64_t kvmppc_vrma_limit(unsigned int hash_shift);
bool kvmppc_has_cap_spapr_vfio(void);
#endif /* !CONFIG_USER_ONLY */
bool kvmppc_has_cap_epr(void);
return 0;
}
-static inline uint64_t kvmppc_rma_size(uint64_t current_size,
- unsigned int hash_shift)
+static inline uint64_t kvmppc_vrma_limit(unsigned int hash_shift)
{
- return ram_size;
+ g_assert_not_reached();
}
static inline bool kvmppc_hpt_needs_host_contiguous_pages(void)
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
return 0;
}
+static bool ppc_hash64_use_vrma(CPUPPCState *env)
+{
+ switch (env->mmu_model) {
+ case POWERPC_MMU_3_00:
+ /*
+ * ISAv3.0 (POWER9) always uses VRMA, the VPM0 field and RMOR
+ * register no longer exist
+ */
+ return true;
+
+ default:
+ return !!(env->spr[SPR_LPCR] & LPCR_VPM0);
+ }
+}
+
static void ppc_hash64_set_isi(CPUState *cs, uint64_t error_code)
{
CPUPPCState *env = &POWERPC_CPU(cs)->env;
if (msr_ir) {
vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
} else {
- switch (env->mmu_model) {
- case POWERPC_MMU_3_00:
- /* Field deprecated in ISAv3.00 - interrupts always go to hyperv */
- vpm = true;
- break;
- default:
- vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
- break;
- }
+ vpm = ppc_hash64_use_vrma(env);
}
if (vpm && !msr_hv) {
cs->exception_index = POWERPC_EXCP_HISI;
if (msr_dr) {
vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
} else {
- switch (env->mmu_model) {
- case POWERPC_MMU_3_00:
- /* Field deprecated in ISAv3.00 - interrupts always go to hyperv */
- vpm = true;
- break;
- default:
- vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
- break;
- }
+ vpm = ppc_hash64_use_vrma(env);
}
if (vpm && !msr_hv) {
cs->exception_index = POWERPC_EXCP_HDSI;
stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80);
}
+static target_ulong rmls_limit(PowerPCCPU *cpu)
+{
+ CPUPPCState *env = &cpu->env;
+ /*
+ * In theory the meanings of RMLS values are implementation
+ * dependent. In practice, this seems to have been the set from
+ * POWER4+..POWER8, and RMLS is no longer supported in POWER9.
+ *
+ * Unsupported values mean the OS has shot itself in the
+ * foot. Return a 0-sized RMA in this case, which we expect
+ * to trigger an immediate DSI or ISI
+ */
+ static const target_ulong rma_sizes[16] = {
+ [0] = 256 * GiB,
+ [1] = 16 * GiB,
+ [2] = 1 * GiB,
+ [3] = 64 * MiB,
+ [4] = 256 * MiB,
+ [7] = 128 * MiB,
+ [8] = 32 * MiB,
+ };
+ target_ulong rmls = (env->spr[SPR_LPCR] & LPCR_RMLS) >> LPCR_RMLS_SHIFT;
+
+ return rma_sizes[rmls];
+}
+
+static int build_vrma_slbe(PowerPCCPU *cpu, ppc_slb_t *slb)
+{
+ CPUPPCState *env = &cpu->env;
+ target_ulong lpcr = env->spr[SPR_LPCR];
+ uint32_t vrmasd = (lpcr & LPCR_VRMASD) >> LPCR_VRMASD_SHIFT;
+ target_ulong vsid = SLB_VSID_VRMA | ((vrmasd << 4) & SLB_VSID_LLP_MASK);
+ int i;
+
+ for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
+ const PPCHash64SegmentPageSizes *sps = &cpu->hash64_opts->sps[i];
+
+ if (!sps->page_shift) {
+ break;
+ }
+
+ if ((vsid & SLB_VSID_LLP_MASK) == sps->slb_enc) {
+ slb->esid = SLB_ESID_V;
+ slb->vsid = vsid;
+ slb->sps = sps;
+ return 0;
+ }
+ }
+
+ error_report("Bad page size encoding in LPCR[VRMASD]; LPCR=0x"
+ TARGET_FMT_lx"\n", lpcr);
+
+ return -1;
+}
+
int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
int rwx, int mmu_idx)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
+ ppc_slb_t vrma_slbe;
ppc_slb_t *slb;
unsigned apshift;
hwaddr ptex;
*/
raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
- /* In HV mode, add HRMOR if top EA bit is clear */
- if (msr_hv || !env->has_hv_mode) {
+ if (cpu->vhyp) {
+ /*
+ * In virtual hypervisor mode, there's nothing to do:
+ * EA == GPA == qemu guest address
+ */
+ } else if (msr_hv || !env->has_hv_mode) {
+ /* In HV mode, add HRMOR if top EA bit is clear */
if (!(eaddr >> 63)) {
raddr |= env->spr[SPR_HRMOR];
}
- } else {
- /* Otherwise, check VPM for RMA vs VRMA */
- if (env->spr[SPR_LPCR] & LPCR_VPM0) {
- slb = &env->vrma_slb;
- if (slb->sps) {
- goto skip_slb_search;
- }
- /* Not much else to do here */
+ } else if (ppc_hash64_use_vrma(env)) {
+ /* Emulated VRMA mode */
+ slb = &vrma_slbe;
+ if (build_vrma_slbe(cpu, slb) != 0) {
+ /* Invalid VRMA setup, machine check */
cs->exception_index = POWERPC_EXCP_MCHECK;
env->error_code = 0;
return 1;
- } else if (raddr < env->rmls) {
- /* RMA. Check bounds in RMLS */
- raddr |= env->spr[SPR_RMOR];
- } else {
- /* The access failed, generate the approriate interrupt */
+ }
+
+ goto skip_slb_search;
+ } else {
+ target_ulong limit = rmls_limit(cpu);
+
+ /* Emulated old-style RMO mode, bounds check against RMLS */
+ if (raddr >= limit) {
if (rwx == 2) {
ppc_hash64_set_isi(cs, SRR1_PROTFAULT);
} else {
}
return 1;
}
+
+ raddr |= env->spr[SPR_RMOR];
}
tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
{
CPUPPCState *env = &cpu->env;
+ ppc_slb_t vrma_slbe;
ppc_slb_t *slb;
hwaddr ptex, raddr;
ppc_hash_pte64_t pte;
/* In real mode the top 4 effective address bits are ignored */
raddr = addr & 0x0FFFFFFFFFFFFFFFULL;
- /* In HV mode, add HRMOR if top EA bit is clear */
- if ((msr_hv || !env->has_hv_mode) && !(addr >> 63)) {
+ if (cpu->vhyp) {
+ /*
+ * In virtual hypervisor mode, there's nothing to do:
+ * EA == GPA == qemu guest address
+ */
+ return raddr;
+ } else if ((msr_hv || !env->has_hv_mode) && !(addr >> 63)) {
+ /* In HV mode, add HRMOR if top EA bit is clear */
return raddr | env->spr[SPR_HRMOR];
- }
+ } else if (ppc_hash64_use_vrma(env)) {
+ /* Emulated VRMA mode */
+ slb = &vrma_slbe;
+ if (build_vrma_slbe(cpu, slb) != 0) {
+ return -1;
+ }
+ } else {
+ target_ulong limit = rmls_limit(cpu);
- /* Otherwise, check VPM for RMA vs VRMA */
- if (env->spr[SPR_LPCR] & LPCR_VPM0) {
- slb = &env->vrma_slb;
- if (!slb->sps) {
+ /* Emulated old-style RMO mode, bounds check against RMLS */
+ if (raddr >= limit) {
return -1;
}
- } else if (raddr < env->rmls) {
- /* RMA. Check bounds in RMLS */
return raddr | env->spr[SPR_RMOR];
- } else {
- return -1;
}
} else {
slb = slb_lookup(cpu, addr);
cpu->env.tlb_need_flush = TLB_NEED_GLOBAL_FLUSH | TLB_NEED_LOCAL_FLUSH;
}
-static void ppc_hash64_update_rmls(PowerPCCPU *cpu)
-{
- CPUPPCState *env = &cpu->env;
- uint64_t lpcr = env->spr[SPR_LPCR];
-
- /*
- * This is the full 4 bits encoding of POWER8. Previous
- * CPUs only support a subset of these but the filtering
- * is done when writing LPCR
- */
- switch ((lpcr & LPCR_RMLS) >> LPCR_RMLS_SHIFT) {
- case 0x8: /* 32MB */
- env->rmls = 0x2000000ull;
- break;
- case 0x3: /* 64MB */
- env->rmls = 0x4000000ull;
- break;
- case 0x7: /* 128MB */
- env->rmls = 0x8000000ull;
- break;
- case 0x4: /* 256MB */
- env->rmls = 0x10000000ull;
- break;
- case 0x2: /* 1GB */
- env->rmls = 0x40000000ull;
- break;
- case 0x1: /* 16GB */
- env->rmls = 0x400000000ull;
- break;
- default:
- /* What to do here ??? */
- env->rmls = 0;
- }
-}
-
-static void ppc_hash64_update_vrma(PowerPCCPU *cpu)
-{
- CPUPPCState *env = &cpu->env;
- const PPCHash64SegmentPageSizes *sps = NULL;
- target_ulong esid, vsid, lpcr;
- ppc_slb_t *slb = &env->vrma_slb;
- uint32_t vrmasd;
- int i;
-
- /* First clear it */
- slb->esid = slb->vsid = 0;
- slb->sps = NULL;
-
- /* Is VRMA enabled ? */
- lpcr = env->spr[SPR_LPCR];
- if (!(lpcr & LPCR_VPM0)) {
- return;
- }
-
- /*
- * Make one up. Mostly ignore the ESID which will not be needed
- * for translation
- */
- vsid = SLB_VSID_VRMA;
- vrmasd = (lpcr & LPCR_VRMASD) >> LPCR_VRMASD_SHIFT;
- vsid |= (vrmasd << 4) & (SLB_VSID_L | SLB_VSID_LP);
- esid = SLB_ESID_V;
-
- for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
- const PPCHash64SegmentPageSizes *sps1 = &cpu->hash64_opts->sps[i];
-
- if (!sps1->page_shift) {
- break;
- }
-
- if ((vsid & SLB_VSID_LLP_MASK) == sps1->slb_enc) {
- sps = sps1;
- break;
- }
- }
-
- if (!sps) {
- error_report("Bad page size encoding esid 0x"TARGET_FMT_lx
- " vsid 0x"TARGET_FMT_lx, esid, vsid);
- return;
- }
-
- slb->vsid = vsid;
- slb->esid = esid;
- slb->sps = sps;
-}
-
void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
{
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
CPUPPCState *env = &cpu->env;
- uint64_t lpcr = 0;
-
- /* Filter out bits */
- switch (env->mmu_model) {
- case POWERPC_MMU_64B: /* 970 */
- if (val & 0x40) {
- lpcr |= LPCR_LPES0;
- }
- if (val & 0x8000000000000000ull) {
- lpcr |= LPCR_LPES1;
- }
- if (val & 0x20) {
- lpcr |= (0x4ull << LPCR_RMLS_SHIFT);
- }
- if (val & 0x4000000000000000ull) {
- lpcr |= (0x2ull << LPCR_RMLS_SHIFT);
- }
- if (val & 0x2000000000000000ull) {
- lpcr |= (0x1ull << LPCR_RMLS_SHIFT);
- }
- env->spr[SPR_RMOR] = ((lpcr >> 41) & 0xffffull) << 26;
- /*
- * XXX We could also write LPID from HID4 here
- * but since we don't tag any translation on it
- * it doesn't actually matter
- *
- * XXX For proper emulation of 970 we also need
- * to dig HRMOR out of HID5
- */
- break;
- case POWERPC_MMU_2_03: /* P5p */
- lpcr = val & (LPCR_RMLS | LPCR_ILE |
- LPCR_LPES0 | LPCR_LPES1 |
- LPCR_RMI | LPCR_HDICE);
- break;
- case POWERPC_MMU_2_06: /* P7 */
- lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_DPFD |
- LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
- LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2 |
- LPCR_MER | LPCR_TC |
- LPCR_LPES0 | LPCR_LPES1 | LPCR_HDICE);
- break;
- case POWERPC_MMU_2_07: /* P8 */
- lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV |
- LPCR_DPFD | LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
- LPCR_AIL | LPCR_ONL | LPCR_P8_PECE0 | LPCR_P8_PECE1 |
- LPCR_P8_PECE2 | LPCR_P8_PECE3 | LPCR_P8_PECE4 |
- LPCR_MER | LPCR_TC | LPCR_LPES0 | LPCR_HDICE);
- break;
- case POWERPC_MMU_3_00: /* P9 */
- lpcr = val & (LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
- (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
- LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
- (LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
- LPCR_DEE | LPCR_OEE)) | LPCR_MER | LPCR_GTSE | LPCR_TC |
- LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE);
- /*
- * If we have a virtual hypervisor, we need to bring back RMLS. It
- * doesn't exist on an actual P9 but that's all we know how to
- * configure with softmmu at the moment
- */
- if (cpu->vhyp) {
- lpcr |= (val & LPCR_RMLS);
- }
- break;
- default:
- ;
- }
- env->spr[SPR_LPCR] = lpcr;
- ppc_hash64_update_rmls(cpu);
- ppc_hash64_update_vrma(cpu);
+ env->spr[SPR_LPCR] = val & pcc->lpcr_mask;
}
void helper_store_lpcr(CPUPPCState *env, target_ulong val)
me += 32;
#endif
mask = MASK(mb, me);
- if (sh == 0) {
- tcg_gen_andi_tl(t_ra, t_rs, mask);
- } else if (mask <= 0xffffffffu) {
- TCGv_i32 t0 = tcg_temp_new_i32();
- tcg_gen_trunc_tl_i32(t0, t_rs);
- tcg_gen_rotli_i32(t0, t0, sh);
- tcg_gen_andi_i32(t0, t0, mask);
- tcg_gen_extu_i32_tl(t_ra, t0);
- tcg_temp_free_i32(t0);
+ if (mask <= 0xffffffffu) {
+ if (sh == 0) {
+ tcg_gen_andi_tl(t_ra, t_rs, mask);
+ } else {
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ tcg_gen_trunc_tl_i32(t0, t_rs);
+ tcg_gen_rotli_i32(t0, t0, sh);
+ tcg_gen_andi_i32(t0, t0, mask);
+ tcg_gen_extu_i32_tl(t_ra, t0);
+ tcg_temp_free_i32(t0);
+ }
} else {
#if defined(TARGET_PPC64)
tcg_gen_deposit_i64(t_ra, t_rs, t_rs, 32, 32);
{
gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]);
}
-
-static void spr_write_970_hid4(DisasContext *ctx, int sprn, int gprn)
-{
-#if defined(TARGET_PPC64)
- spr_write_generic(ctx, sprn, gprn);
- gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]);
-#endif
-}
-
#endif /* !defined(CONFIG_USER_ONLY) */
static void gen_spr_970_lpar(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
- /* Logical partitionning */
- /* PPC970: HID4 is effectively the LPCR */
+ /*
+ * PPC970: HID4 covers things later controlled by the LPCR and
+ * RMOR in later CPUs, but with a different encoding. We only
+ * support the 970 in "Apple mode" which has all hypervisor
+ * facilities disabled by strapping, so we can basically just
+ * ignore it
+ */
spr_register(env, SPR_970_HID4, "HID4",
SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_970_hid4,
+ &spr_read_generic, &spr_write_generic,
0x00000000);
#endif
}
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
- spr_register_hv(env, SPR_RMOR, "RMOR",
+ spr_register_hv(env, SPR_HRMOR, "HRMOR",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
- spr_register_hv(env, SPR_HRMOR, "HRMOR",
+}
+
+static void gen_spr_rmor(CPUPPCState *env)
+{
+ spr_register_hv(env, SPR_RMOR, "RMOR",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
(1ull << MSR_DR) |
(1ull << MSR_PMM) |
(1ull << MSR_RI);
+ pcc->lpcr_mask = LPCR_RMLS | LPCR_ILE | LPCR_LPES0 | LPCR_LPES1 |
+ LPCR_RMI | LPCR_HDICE;
pcc->mmu_model = POWERPC_MMU_2_03;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
pcc->l1_icache_size = 0x10000;
}
-/*
- * The CPU used to have a "compat" property which set the
- * compatibility mode PVR. However, this was conceptually broken - it
- * only makes sense on the pseries machine type (otherwise the guest
- * owns the PCR and can control the compatibility mode itself). It's
- * been replaced with the 'max-cpu-compat' property on the pseries
- * machine type. For backwards compatibility, pseries specially
- * parses the -cpu parameter and converts old compat= parameters into
- * the appropriate machine parameters. This stub implementation of
- * the parameter catches any uses on explicitly created CPUs.
- */
-static void getset_compat_deprecated(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- QNull *null = NULL;
-
- if (!qtest_enabled()) {
- warn_report("CPU 'compat' property is deprecated and has no effect; "
- "use max-cpu-compat machine property instead");
- }
- visit_type_null(v, name, &null, NULL);
- qobject_unref(null);
-}
-
-static const PropertyInfo ppc_compat_deprecated_propinfo = {
- .name = "str",
- .description = "compatibility mode (deprecated)",
- .get = getset_compat_deprecated,
- .set = getset_compat_deprecated,
-};
-static Property powerpc_servercpu_properties[] = {
- {
- .name = "compat",
- .info = &ppc_compat_deprecated_propinfo,
- },
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void init_proc_POWER7(CPUPPCState *env)
{
/* Common Registers */
/* POWER7 Specific Registers */
gen_spr_book3s_ids(env);
+ gen_spr_rmor(env);
gen_spr_amr(env);
gen_spr_book3s_purr(env);
gen_spr_power5p_common(env);
dc->fw_name = "PowerPC,POWER7";
dc->desc = "POWER7";
- device_class_set_props(dc, powerpc_servercpu_properties);
pcc->pvr_match = ppc_pvr_match_power7;
pcc->pcr_mask = PCR_VEC_DIS | PCR_VSX_DIS | PCR_COMPAT_2_05;
pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
(1ull << MSR_PMM) |
(1ull << MSR_RI) |
(1ull << MSR_LE);
+ pcc->lpcr_mask = LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_DPFD |
+ LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
+ LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2 |
+ LPCR_MER | LPCR_TC |
+ LPCR_LPES0 | LPCR_LPES1 | LPCR_HDICE;
+ pcc->lpcr_pm = LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2;
pcc->mmu_model = POWERPC_MMU_2_06;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
- pcc->lpcr_pm = LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2;
}
static void init_proc_POWER8(CPUPPCState *env)
/* POWER8 Specific Registers */
gen_spr_book3s_ids(env);
+ gen_spr_rmor(env);
gen_spr_amr(env);
gen_spr_iamr(env);
gen_spr_book3s_purr(env);
dc->fw_name = "PowerPC,POWER8";
dc->desc = "POWER8";
- device_class_set_props(dc, powerpc_servercpu_properties);
pcc->pvr_match = ppc_pvr_match_power8;
pcc->pcr_mask = PCR_TM_DIS | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
PPC2_TM | PPC2_PM_ISA206;
pcc->msr_mask = (1ull << MSR_SF) |
- (1ull << MSR_SHV) |
+ (1ull << MSR_HV) |
(1ull << MSR_TM) |
(1ull << MSR_VR) |
(1ull << MSR_VSX) |
(1ull << MSR_TS0) |
(1ull << MSR_TS1) |
(1ull << MSR_LE);
+ pcc->lpcr_mask = LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV |
+ LPCR_DPFD | LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
+ LPCR_AIL | LPCR_ONL | LPCR_P8_PECE0 | LPCR_P8_PECE1 |
+ LPCR_P8_PECE2 | LPCR_P8_PECE3 | LPCR_P8_PECE4 |
+ LPCR_MER | LPCR_TC | LPCR_LPES0 | LPCR_HDICE;
+ pcc->lpcr_pm = LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PECE2 |
+ LPCR_P8_PECE3 | LPCR_P8_PECE4;
pcc->mmu_model = POWERPC_MMU_2_07;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
- pcc->lpcr_pm = LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PECE2 |
- LPCR_P8_PECE3 | LPCR_P8_PECE4;
}
#ifdef CONFIG_SOFTMMU
dc->fw_name = "PowerPC,POWER9";
dc->desc = "POWER9";
- device_class_set_props(dc, powerpc_servercpu_properties);
pcc->pvr_match = ppc_pvr_match_power9;
pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07;
pcc->pcr_supported = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 |
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL;
pcc->msr_mask = (1ull << MSR_SF) |
- (1ull << MSR_SHV) |
+ (1ull << MSR_HV) |
(1ull << MSR_TM) |
(1ull << MSR_VR) |
(1ull << MSR_VSX) |
(1ull << MSR_PMM) |
(1ull << MSR_RI) |
(1ull << MSR_LE);
+ pcc->lpcr_mask = LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
+ (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
+ LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
+ (LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
+ LPCR_DEE | LPCR_OEE))
+ | LPCR_MER | LPCR_GTSE | LPCR_TC |
+ LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE;
+ pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
pcc->mmu_model = POWERPC_MMU_3_00;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc64_v3_handle_mmu_fault;
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
- pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
}
#ifdef CONFIG_SOFTMMU
dc->fw_name = "PowerPC,POWER10";
dc->desc = "POWER10";
- device_class_set_props(dc, powerpc_servercpu_properties);
pcc->pvr_match = ppc_pvr_match_power10;
pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07 |
PCR_COMPAT_3_00;
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL;
pcc->msr_mask = (1ull << MSR_SF) |
- (1ull << MSR_SHV) |
+ (1ull << MSR_HV) |
(1ull << MSR_TM) |
(1ull << MSR_VR) |
(1ull << MSR_VSX) |
(1ull << MSR_PMM) |
(1ull << MSR_RI) |
(1ull << MSR_LE);
+ pcc->lpcr_mask = LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
+ (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
+ LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
+ (LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
+ LPCR_DEE | LPCR_OEE))
+ | LPCR_MER | LPCR_GTSE | LPCR_TC |
+ LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE;
+ pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
pcc->mmu_model = POWERPC_MMU_3_00;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc64_v3_handle_mmu_fault;
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
- pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
}
#if !defined(CONFIG_USER_ONLY)
return -1;
}
-static int gdb_get_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_spr_reg(CPUPPCState *env, GByteArray *buf, int n)
{
int reg;
int len;
}
len = TARGET_LONG_SIZE;
- stn_p(mem_buf, len, env->spr[reg]);
- ppc_maybe_bswap_register(env, mem_buf, len);
+ gdb_get_regl(buf, env->spr[reg]);
+ ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, len), len);
return len;
}
}
#endif
-static int gdb_get_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_float_reg(CPUPPCState *env, GByteArray *buf, int n)
{
+ uint8_t *mem_buf;
if (n < 32) {
- stfq_p(mem_buf, *cpu_fpr_ptr(env, n));
+ gdb_get_reg64(buf, *cpu_fpr_ptr(env, n));
+ mem_buf = gdb_get_reg_ptr(buf, 8);
ppc_maybe_bswap_register(env, mem_buf, 8);
return 8;
}
if (n == 32) {
- stl_p(mem_buf, env->fpscr);
+ gdb_get_reg32(buf, env->fpscr);
+ mem_buf = gdb_get_reg_ptr(buf, 4);
ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
return 0;
}
-static int gdb_get_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_avr_reg(CPUPPCState *env, GByteArray *buf, int n)
{
+ uint8_t *mem_buf;
+
if (n < 32) {
ppc_avr_t *avr = cpu_avr_ptr(env, n);
if (!avr_need_swap(env)) {
- stq_p(mem_buf, avr->u64[0]);
- stq_p(mem_buf + 8, avr->u64[1]);
+ gdb_get_reg128(buf, avr->u64[0] , avr->u64[1]);
} else {
- stq_p(mem_buf, avr->u64[1]);
- stq_p(mem_buf + 8, avr->u64[0]);
+ gdb_get_reg128(buf, avr->u64[1] , avr->u64[0]);
}
+ mem_buf = gdb_get_reg_ptr(buf, 16);
ppc_maybe_bswap_register(env, mem_buf, 8);
ppc_maybe_bswap_register(env, mem_buf + 8, 8);
return 16;
}
if (n == 32) {
- stl_p(mem_buf, helper_mfvscr(env));
+ gdb_get_reg32(buf, helper_mfvscr(env));
+ mem_buf = gdb_get_reg_ptr(buf, 4);
ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
if (n == 33) {
- stl_p(mem_buf, (uint32_t)env->spr[SPR_VRSAVE]);
+ gdb_get_reg32(buf, (uint32_t)env->spr[SPR_VRSAVE]);
+ mem_buf = gdb_get_reg_ptr(buf, 4);
ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
return 0;
}
-static int gdb_get_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_spe_reg(CPUPPCState *env, GByteArray *buf, int n)
{
if (n < 32) {
#if defined(TARGET_PPC64)
- stl_p(mem_buf, env->gpr[n] >> 32);
- ppc_maybe_bswap_register(env, mem_buf, 4);
+ gdb_get_reg32(buf, env->gpr[n] >> 32);
+ ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4);
#else
- stl_p(mem_buf, env->gprh[n]);
+ gdb_get_reg32(buf, env->gprh[n]);
#endif
return 4;
}
if (n == 32) {
- stq_p(mem_buf, env->spe_acc);
- ppc_maybe_bswap_register(env, mem_buf, 8);
+ gdb_get_reg64(buf, env->spe_acc);
+ ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8);
return 8;
}
if (n == 33) {
- stl_p(mem_buf, env->spe_fscr);
- ppc_maybe_bswap_register(env, mem_buf, 4);
+ gdb_get_reg32(buf, env->spe_fscr);
+ ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4);
return 4;
}
return 0;
return 0;
}
-static int gdb_get_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_vsx_reg(CPUPPCState *env, GByteArray *buf, int n)
{
if (n < 32) {
- stq_p(mem_buf, *cpu_vsrl_ptr(env, n));
- ppc_maybe_bswap_register(env, mem_buf, 8);
+ gdb_get_reg64(buf, *cpu_vsrl_ptr(env, n));
+ ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8);
return 8;
}
return 0;
*s = '\0';
for (i = 0; inpieces[i]; i++) {
if (g_str_has_prefix(inpieces[i], "compat=")) {
+ warn_report_once("CPU 'compat' property is deprecated; "
+ "use max-cpu-compat machine property instead");
compat_str = inpieces[i];
continue;
}
extern const char * const riscv_intr_names[];
void riscv_cpu_do_interrupt(CPUState *cpu);
-int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
bool riscv_cpu_fp_enabled(CPURISCVState *env);
CSR_MHCOUNTEREN,
};
-int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
return 0;
}
-static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
+static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n)
{
if (n < 32) {
if (env->misa & RVD) {
- return gdb_get_reg64(mem_buf, env->fpr[n]);
+ return gdb_get_reg64(buf, env->fpr[n]);
}
if (env->misa & RVF) {
- return gdb_get_reg32(mem_buf, env->fpr[n]);
+ return gdb_get_reg32(buf, env->fpr[n]);
}
/* there is hole between ft11 and fflags in fpu.xml */
} else if (n < 36 && n > 32) {
result = riscv_csrrw_debug(env, n - 33 + csr_register_map[8], &val,
0, 0);
if (result == 0) {
- return gdb_get_regl(mem_buf, val);
+ return gdb_get_regl(buf, val);
}
}
return 0;
return 0;
}
-static int riscv_gdb_get_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
+static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n)
{
if (n < ARRAY_SIZE(csr_register_map)) {
target_ulong val = 0;
result = riscv_csrrw_debug(env, csr_register_map[n], &val, 0, 0);
if (result == 0) {
- return gdb_get_regl(mem_buf, val);
+ return gdb_get_regl(buf, val);
}
}
return 0;
return 0;
}
-static int riscv_gdb_get_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n)
+static int riscv_gdb_get_virtual(CPURISCVState *cs, GByteArray *buf, int n)
{
if (n == 0) {
#ifdef CONFIG_USER_ONLY
- return gdb_get_regl(mem_buf, 0);
+ return gdb_get_regl(buf, 0);
#else
- return gdb_get_regl(mem_buf, cs->priv);
+ return gdb_get_regl(buf, cs->priv);
#endif
}
return 0;
#include "sysemu/hw_accel.h"
#include "sysemu/tcg.h"
-int s390_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int s390_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
/* total number of registers in s390-acr.xml */
#define S390_NUM_AC_REGS 16
-static int cpu_read_ac_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_ac_reg(CPUS390XState *env, GByteArray *buf, int n)
{
switch (n) {
case S390_A0_REGNUM ... S390_A15_REGNUM:
- return gdb_get_reg32(mem_buf, env->aregs[n]);
+ return gdb_get_reg32(buf, env->aregs[n]);
default:
return 0;
}
/* total number of registers in s390-fpr.xml */
#define S390_NUM_FP_REGS 17
-static int cpu_read_fp_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_fp_reg(CPUS390XState *env, GByteArray *buf, int n)
{
switch (n) {
case S390_FPC_REGNUM:
- return gdb_get_reg32(mem_buf, env->fpc);
+ return gdb_get_reg32(buf, env->fpc);
case S390_F0_REGNUM ... S390_F15_REGNUM:
- return gdb_get_reg64(mem_buf, *get_freg(env, n - S390_F0_REGNUM));
+ return gdb_get_reg64(buf, *get_freg(env, n - S390_F0_REGNUM));
default:
return 0;
}
/* total number of registers in s390-vx.xml */
#define S390_NUM_VREGS 32
-static int cpu_read_vreg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_vreg(CPUS390XState *env, GByteArray *buf, int n)
{
int ret;
switch (n) {
case S390_V0L_REGNUM ... S390_V15L_REGNUM:
- ret = gdb_get_reg64(mem_buf, env->vregs[n][1]);
+ ret = gdb_get_reg64(buf, env->vregs[n][1]);
break;
case S390_V16_REGNUM ... S390_V31_REGNUM:
- ret = gdb_get_reg64(mem_buf, env->vregs[n][0]);
- ret += gdb_get_reg64(mem_buf + 8, env->vregs[n][1]);
+ ret = gdb_get_reg64(buf, env->vregs[n][0]);
+ ret += gdb_get_reg64(buf, env->vregs[n][1]);
break;
default:
ret = 0;
#define S390_NUM_C_REGS 16
#ifndef CONFIG_USER_ONLY
-static int cpu_read_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_c_reg(CPUS390XState *env, GByteArray *buf, int n)
{
switch (n) {
case S390_C0_REGNUM ... S390_C15_REGNUM:
- return gdb_get_regl(mem_buf, env->cregs[n]);
+ return gdb_get_regl(buf, env->cregs[n]);
default:
return 0;
}
/* total number of registers in s390-virt.xml */
#define S390_NUM_VIRT_REGS 8
-static int cpu_read_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_virt_reg(CPUS390XState *env, GByteArray *mem_buf, int n)
{
switch (n) {
case S390_VIRT_CKC_REGNUM:
/* total number of registers in s390-gs.xml */
#define S390_NUM_GS_REGS 4
-static int cpu_read_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_gs_reg(CPUS390XState *env, GByteArray *buf, int n)
{
- return gdb_get_regl(mem_buf, env->gscb[n]);
+ return gdb_get_regl(buf, env->gscb[n]);
}
static int cpu_write_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
/* gdbstub.c */
-int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int s390_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void s390_cpu_gdb_init(CPUState *cs);
bool superh_cpu_exec_interrupt(CPUState *cpu, int int_req);
void superh_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int superh_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int superh_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void superh_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
/* Hint: Use "set architecture sh4" in GDB to see fpu registers */
/* FIXME: We should use XML for this. */
-int superh_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int superh_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
SuperHCPU *cpu = SUPERH_CPU(cs);
CPUSH4State *env = &cpu->env;
void sparc_cpu_do_interrupt(CPUState *cpu);
void sparc_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int sparc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int sparc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
#define gdb_get_rega(buf, val) gdb_get_regl(buf, val)
#endif
-int sparc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int sparc_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
SPARCCPU *cpu = SPARC_CPU(cs);
CPUSPARCState *env = &cpu->env;
hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
void xtensa_count_regs(const XtensaConfig *config,
unsigned *n_regs, unsigned *n_core_regs);
-int xtensa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int xtensa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
}
}
-int xtensa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int xtensa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
XtensaCPU *cpu = XTENSA_CPU(cs);
CPUXtensaState *env = &cpu->env;
case MO_64:
if (imm <= 32) {
- /* We can emulate a small sign extend by performing an arithmetic
+ /*
+ * We can emulate a small sign extend by performing an arithmetic
* 32-bit shift and overwriting the high half of a 64-bit logical
- * shift (note that the ISA says shift of 32 is valid).
+ * shift. Note that the ISA says shift of 32 is valid, but TCG
+ * does not, so we have to bound the smaller shift -- we get the
+ * same result in the high half either way.
*/
t1 = tcg_temp_new_vec(type);
- tcg_gen_sari_vec(MO_32, t1, v1, imm);
+ tcg_gen_sari_vec(MO_32, t1, v1, MIN(imm, 31));
tcg_gen_shri_vec(MO_64, v0, v1, imm);
vec_gen_4(INDEX_op_x86_blend_vec, type, MO_32,
tcgv_vec_arg(v0), tcgv_vec_arg(v0),
rcutorture
test-*
!test-*.c
+!test-*.py
!docker/test-*
test-qapi-commands.[ch]
test-qapi-init-commands.[ch]
@echo " $(MAKE) check-venv Creates a Python venv for tests"
@echo " $(MAKE) check-clean Clean the tests and related data"
@echo
+ @echo " $(MAKE) get-vm-images Downloads all images used by acceptance tests, according to configured targets (~350 MB each, 1.5 GB max)"
+ @echo
@echo
@echo "The variable SPEED can be set to control the gtester speed setting."
@echo "Default options are -k and (for $(MAKE) V=1) --verbose; they can be"
qapi-schema += event-member-invalid-dict.json
qapi-schema += event-nest-struct.json
qapi-schema += features-bad-type.json
+qapi-schema += features-deprecated-type.json
qapi-schema += features-duplicate-name.json
qapi-schema += features-if-invalid.json
qapi-schema += features-missing-name.json
check-venv: $(TESTS_VENV_DIR)
-check-acceptance: check-venv $(TESTS_RESULTS_DIR)
+FEDORA_31_ARCHES_CANDIDATES=$(patsubst ppc64,ppc64le,$(TARGETS))
+FEDORA_31_ARCHES := x86_64 aarch64 ppc64le s390x
+FEDORA_31_DOWNLOAD=$(filter $(FEDORA_31_ARCHES),$(FEDORA_31_ARCHES_CANDIDATES))
+
+# download one specific Fedora 31 image
+get-vm-image-fedora-31-%: check-venv
+ $(call quiet-command, \
+ $(TESTS_VENV_DIR)/bin/python -m avocado vmimage get \
+ --distro=fedora --distro-version=31 --arch=$*, \
+ "AVOCADO", "Downloading acceptance tests VM image for $*")
+
+# download all vm images, according to defined targets
+get-vm-images: check-venv $(patsubst %,get-vm-image-fedora-31-%, $(FEDORA_31_DOWNLOAD))
+
+check-acceptance: check-venv $(TESTS_RESULTS_DIR) get-vm-images
$(call quiet-command, \
$(TESTS_VENV_DIR)/bin/python -m avocado \
--show=$(AVOCADO_SHOW) run --job-results-dir=$(TESTS_RESULTS_DIR) \
# Consolidated targets
-.PHONY: check-block check-qapi-schema check-qtest check-unit check check-clean
+.PHONY: check-block check-qapi-schema check-qtest check-unit check check-clean get-vm-images
check-qapi-schema: check-tests/qapi-schema/frontend check-tests/qapi-schema/doc-good.texi
check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS))
ifeq ($(CONFIG_TOOLS),y)
import avocado
-SRC_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..', '..', '..')
-sys.path.append(os.path.join(SRC_ROOT_DIR, 'python'))
+#: The QEMU build root directory. It may also be the source directory
+#: if building from the source dir, but it's safer to use BUILD_DIR for
+#: that purpose. Be aware that if this code is moved outside of a source
+#: and build tree, it will not be accurate.
+BUILD_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
+
+if os.path.islink(os.path.dirname(os.path.dirname(__file__))):
+ # The link to the acceptance tests dir in the source code directory
+ lnk = os.path.dirname(os.path.dirname(__file__))
+ #: The QEMU root source directory
+ SOURCE_DIR = os.path.dirname(os.path.dirname(os.readlink(lnk)))
+else:
+ SOURCE_DIR = BUILD_DIR
+
+sys.path.append(os.path.join(SOURCE_DIR, 'python'))
from qemu.machine import QEMUMachine
if is_readable_executable_file(qemu_bin_relative_path):
return qemu_bin_relative_path
- qemu_bin_from_src_dir_path = os.path.join(SRC_ROOT_DIR,
+ qemu_bin_from_bld_dir_path = os.path.join(BUILD_DIR,
qemu_bin_relative_path)
- if is_readable_executable_file(qemu_bin_from_src_dir_path):
- return qemu_bin_from_src_dir_path
+ if is_readable_executable_file(qemu_bin_from_bld_dir_path):
+ return qemu_bin_from_bld_dir_path
def _console_interaction(test, success_message, failure_message,
self.qemu_bin = self.params.get('qemu_bin',
default=default_qemu_bin)
if self.qemu_bin is None:
- self.cancel("No QEMU binary defined or found in the source tree")
+ self.cancel("No QEMU binary defined or found in the build tree")
def _new_vm(self, *args):
vm = QEMUMachine(self.qemu_bin, sock_dir=tempfile.mkdtemp())
--- /dev/null
+# Functional test that boots a complete Linux system via a cloud image
+#
+# Copyright (c) 2018-2020 Red Hat, Inc.
+#
+# Author:
+# Cleber Rosa <crosa@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import os
+
+from avocado_qemu import Test, BUILD_DIR
+
+from qemu.accel import kvm_available
+from qemu.accel import tcg_available
+
+from avocado.utils import cloudinit
+from avocado.utils import network
+from avocado.utils import vmimage
+from avocado.utils import datadrainer
+from avocado.utils.path import find_command
+
+ACCEL_NOT_AVAILABLE_FMT = "%s accelerator does not seem to be available"
+KVM_NOT_AVAILABLE = ACCEL_NOT_AVAILABLE_FMT % "KVM"
+TCG_NOT_AVAILABLE = ACCEL_NOT_AVAILABLE_FMT % "TCG"
+
+
+class BootLinux(Test):
+ """
+ Boots a Linux system, checking for a successful initialization
+ """
+
+ timeout = 900
+ chksum = None
+
+ def setUp(self):
+ super(BootLinux, self).setUp()
+ self.vm.add_args('-smp', '2')
+ self.vm.add_args('-m', '1024')
+ self.prepare_boot()
+ self.prepare_cloudinit()
+
+ def prepare_boot(self):
+ self.log.debug('Looking for and selecting a qemu-img binary to be '
+ 'used to create the bootable snapshot image')
+ # If qemu-img has been built, use it, otherwise the system wide one
+ # will be used. If none is available, the test will cancel.
+ qemu_img = os.path.join(BUILD_DIR, 'qemu-img')
+ if not os.path.exists(qemu_img):
+ qemu_img = find_command('qemu-img', False)
+ if qemu_img is False:
+ self.cancel('Could not find "qemu-img", which is required to '
+ 'create the bootable image')
+ vmimage.QEMU_IMG = qemu_img
+
+ self.log.info('Downloading/preparing boot image')
+ # Fedora 31 only provides ppc64le images
+ image_arch = self.arch
+ if image_arch == 'ppc64':
+ image_arch = 'ppc64le'
+ try:
+ self.boot = vmimage.get(
+ 'fedora', arch=image_arch, version='31',
+ checksum=self.chksum,
+ algorithm='sha256',
+ cache_dir=self.cache_dirs[0],
+ snapshot_dir=self.workdir)
+ self.vm.add_args('-drive', 'file=%s' % self.boot.path)
+ except:
+ self.cancel('Failed to download/prepare boot image')
+
+ def prepare_cloudinit(self):
+ self.log.info('Preparing cloudinit image')
+ try:
+ cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso')
+ self.phone_home_port = network.find_free_port()
+ cloudinit.iso(cloudinit_iso, self.name,
+ username='root',
+ password='password',
+ # QEMU's hard coded usermode router address
+ phone_home_host='10.0.2.2',
+ phone_home_port=self.phone_home_port)
+ self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
+ except Exception:
+ self.cancel('Failed to prepared cloudinit image')
+
+ def launch_and_wait(self):
+ self.vm.set_console()
+ self.vm.launch()
+ console_drainer = datadrainer.LineLogger(self.vm.console_socket.fileno(),
+ logger=self.log.getChild('console'))
+ console_drainer.start()
+ self.log.info('VM launched, waiting for boot confirmation from guest')
+ cloudinit.wait_for_phone_home(('0.0.0.0', self.phone_home_port), self.name)
+
+
+class BootLinuxX8664(BootLinux):
+ """
+ :avocado: tags=arch:x86_64
+ """
+
+ chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0'
+
+ def test_pc_i440fx_tcg(self):
+ """
+ :avocado: tags=machine:pc
+ :avocado: tags=accel:tcg
+ """
+ if not tcg_available(self.qemu_bin):
+ self.cancel(TCG_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "tcg")
+ self.launch_and_wait()
+
+ def test_pc_i440fx_kvm(self):
+ """
+ :avocado: tags=machine:pc
+ :avocado: tags=accel:kvm
+ """
+ if not kvm_available(self.arch, self.qemu_bin):
+ self.cancel(KVM_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "kvm")
+ self.launch_and_wait()
+
+ def test_pc_q35_tcg(self):
+ """
+ :avocado: tags=machine:q35
+ :avocado: tags=accel:tcg
+ """
+ if not tcg_available(self.qemu_bin):
+ self.cancel(TCG_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "tcg")
+ self.launch_and_wait()
+
+ def test_pc_q35_kvm(self):
+ """
+ :avocado: tags=machine:q35
+ :avocado: tags=accel:kvm
+ """
+ if not kvm_available(self.arch, self.qemu_bin):
+ self.cancel(KVM_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "kvm")
+ self.launch_and_wait()
+
+
+class BootLinuxAarch64(BootLinux):
+ """
+ :avocado: tags=arch:aarch64
+ :avocado: tags=machine:virt
+ :avocado: tags=machine:gic-version=2
+ """
+
+ chksum = '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49'
+
+ def add_common_args(self):
+ self.vm.add_args('-bios',
+ os.path.join(BUILD_DIR, 'pc-bios',
+ 'edk2-aarch64-code.fd'))
+ self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
+ self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom')
+
+ def test_virt_tcg(self):
+ """
+ :avocado: tags=accel:tcg
+ :avocado: tags=cpu:max
+ """
+ if not tcg_available(self.qemu_bin):
+ self.cancel(TCG_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "tcg")
+ self.vm.add_args("-cpu", "max")
+ self.vm.add_args("-machine", "virt,gic-version=2")
+ self.add_common_args()
+ self.launch_and_wait()
+
+ def test_virt_kvm(self):
+ """
+ :avocado: tags=accel:kvm
+ :avocado: tags=cpu:host
+ """
+ if not kvm_available(self.arch, self.qemu_bin):
+ self.cancel(KVM_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "kvm")
+ self.vm.add_args("-cpu", "host")
+ self.vm.add_args("-machine", "virt,gic-version=2")
+ self.add_common_args()
+ self.launch_and_wait()
+
+
+class BootLinuxPPC64(BootLinux):
+ """
+ :avocado: tags=arch:ppc64
+ """
+
+ chksum = '7c3528b85a3df4b2306e892199a9e1e43f991c506f2cc390dc4efa2026ad2f58'
+
+ def test_pseries_tcg(self):
+ """
+ :avocado: tags=machine:pseries
+ :avocado: tags=accel:tcg
+ """
+ if not tcg_available(self.qemu_bin):
+ self.cancel(TCG_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "tcg")
+ self.launch_and_wait()
+
+
+class BootLinuxS390X(BootLinux):
+ """
+ :avocado: tags=arch:s390x
+ """
+
+ chksum = '4caaab5a434fd4d1079149a072fdc7891e354f834d355069ca982fdcaf5a122d'
+
+ def test_s390_ccw_virtio_tcg(self):
+ """
+ :avocado: tags=machine:s390-ccw-virtio
+ :avocado: tags=accel:tcg
+ """
+ if not tcg_available(self.qemu_bin):
+ self.cancel(TCG_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "tcg")
+ self.launch_and_wait()
--- /dev/null
+FROM centos:8.1.1911
+
+RUN dnf -y update
+ENV PACKAGES \
+ SDL-devel \
+ bison \
+ bzip2 \
+ bzip2-devel \
+ dbus-daemon \
+ flex \
+ gcc \
+ gcc-c++ \
+ gettext \
+ git \
+ glib2-devel \
+ libaio-devel \
+ libepoxy-devel \
+ lzo-devel \
+ make \
+ mesa-libEGL-devel \
+ nettle-devel \
+ perl-Test-Harness \
+ pixman-devel \
+ python36 \
+ rdma-core-devel \
+ spice-glib-devel \
+ spice-server \
+ tar \
+ zlib-devel
+
+RUN dnf install -y $PACKAGES
+RUN rpm -q $PACKAGES | sort > /packages.txt
libegl1-mesa-dev \
libepoxy-dev \
libgbm-dev
-RUN git clone https://anongit.freedesktop.org/git/virglrenderer.git /usr/src/virglrenderer && \
- cd /usr/src/virglrenderer && git checkout virglrenderer-0.7.0
-RUN cd /usr/src/virglrenderer && ./autogen.sh && ./configure --with-glx --disable-tests && make install
+RUN git clone https://gitlab.freedesktop.org/virgl/virglrenderer.git /usr/src/virglrenderer && \
+ cd /usr/src/virglrenderer && git checkout virglrenderer-0.8.0
+RUN cd /usr/src/virglrenderer && ./autogen.sh && ./configure --disable-tests && make install
# netmap
RUN apt update && \
ENV TARGET i686
-ENV PATH $PATH:/usr/lib/mxe/usr/$TARGET-w64-mingw32.shared/bin
+ENV PATH $PATH:/usr/lib/mxe/usr/bin:/usr/lib/mxe/usr/$TARGET-w64-mingw32.shared/bin
ENV PKG_CONFIG_PATH \
$PKG_CONFIG_PATH:/usr/lib/mxe/usr/$TARGET-w64-mingw32.shared/lib/pkgconfig
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt install -y --no-install-recommends \
+ bc \
bison \
build-essential \
ca-certificates \
clang \
dbus \
flex \
+ gdb-multiarch \
gettext \
git \
+ libncurses5-dev \
pkg-config \
psmisc \
python3 \
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt install -y --no-install-recommends \
+ bc \
bison \
build-essential \
ca-certificates \
clang \
flex \
+ gdb-multiarch \
gettext \
git \
+ libncurses5-dev \
pkg-config \
psmisc \
python3 \
--- /dev/null
+#!/usr/bin/env python3
+#
+# Run a gdbstub test case
+#
+# Copyright (c) 2019 Linaro
+#
+# Author: Alex Bennée <alex.bennee@linaro.org>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import argparse
+import subprocess
+import shutil
+import shlex
+
+def get_args():
+ parser = argparse.ArgumentParser(description="A gdbstub test runner")
+ parser.add_argument("--qemu", help="Qemu binary for test",
+ required=True)
+ parser.add_argument("--qargs", help="Qemu arguments for test")
+ parser.add_argument("--binary", help="Binary to debug",
+ required=True)
+ parser.add_argument("--test", help="GDB test script",
+ required=True)
+ parser.add_argument("--gdb", help="The gdb binary to use", default=None)
+
+ return parser.parse_args()
+
+if __name__ == '__main__':
+ args = get_args()
+
+ # Search for a gdb we can use
+ if not args.gdb:
+ args.gdb = shutil.which("gdb-multiarch")
+ if not args.gdb:
+ args.gdb = shutil.which("gdb")
+ if not args.gdb:
+ print("We need gdb to run the test")
+ exit(-1)
+
+ # Launch QEMU with binary
+ if "system" in args.qemu:
+ cmd = "%s %s %s -s -S" % (args.qemu, args.qargs, args.binary)
+ else:
+ cmd = "%s %s -g 1234 %s" % (args.qemu, args.qargs, args.binary)
+
+ inferior = subprocess.Popen(shlex.split(cmd))
+
+ # Now launch gdb with our test and collect the result
+ gdb_cmd = "%s %s -ex 'target remote localhost:1234' -x %s" % (args.gdb, args.binary, args.test)
+
+ result = subprocess.call(gdb_cmd, shell=True);
+
+ exit(result)
alternate-base.json: In alternate 'Alt':
alternate-base.json:4: alternate has unknown key 'base'
-Valid keys are 'alternate', 'data', 'if'.
+Valid keys are 'alternate', 'data', 'features', 'if'.
# @Enum:
# @one: The _one_ {and only}
#
+# Features:
+# @enum-feat: Also _one_ {and only}
+#
# @two is undocumented
##
{ 'enum': 'Enum', 'data':
[ { 'name': 'one', 'if': 'defined(IFONE)' }, 'two' ],
+ 'features': [ 'enum-feat' ],
'if': 'defined(IFCOND)' }
##
#
# Features:
# @variant1-feat: a feature
+# @member-feat: a member feature
##
{ 'struct': 'Variant1',
'features': [ 'variant1-feat' ],
- 'data': { 'var1': { 'type': 'str', 'if': 'defined(IFSTR)' } } }
+ 'data': { 'var1': { 'type': 'str',
+ 'features': [ 'member-feat' ],
+ 'if': 'defined(IFSTR)' } } }
##
# @Variant2:
##
# @Object:
+# Features:
+# @union-feat1: a feature
##
{ 'union': 'Object',
+ 'features': [ 'union-feat1' ],
'base': 'Base',
'discriminator': 'base1',
'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } }
##
# @SugaredUnion:
+# Features:
+# @union-feat2: a feature
##
{ 'union': 'SugaredUnion',
+ 'features': [ 'union-feat2' ],
'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } }
##
# @Alternate:
# @i: an integer
# @b is undocumented
+#
+# Features:
+# @alt-feat: a feature
##
{ 'alternate': 'Alternate',
+ 'features': [ 'alt-feat' ],
'data': { 'i': 'int', 'b': 'bool' } }
##
##
# @EVT-BOXED:
+# Features:
+# @feat3: a feature
##
{ 'event': 'EVT-BOXED', 'boxed': true,
+ 'features': [ 'feat3' ],
'data': 'Object' }
if ['defined(IFONE)']
member two
if ['defined(IFCOND)']
+ feature enum-feat
object Base
member base1: Enum optional=False
object Variant1
member var1: str optional=False
if ['defined(IFSTR)']
+ feature member-feat
feature variant1-feat
object Variant2
object Object
case one: Variant1
case two: Variant2
if ['IFTWO']
+ feature union-feat1
object q_obj_Variant1-wrapper
member data: Variant1 optional=False
object q_obj_Variant2-wrapper
case one: q_obj_Variant1-wrapper
case two: q_obj_Variant2-wrapper
if ['IFTWO']
+ feature union-feat2
alternate Alternate
tag type
case i: int
case b: bool
+ feature alt-feat
object q_obj_cmd-arg
member arg1: int optional=False
member arg2: str optional=True
feature cmd-feat2
event EVT-BOXED Object
boxed=True
+ feature feat3
doc freeform
body=
= Section
The _one_ {and only}
arg=two
+ feature=enum-feat
+Also _one_ {and only}
section=None
@two is undocumented
doc symbol=Base
feature=variant1-feat
a feature
+ feature=member-feat
+a member feature
doc symbol=Variant2
body=
doc symbol=Object
body=
+ feature=union-feat1
+a feature
doc symbol=SugaredUnion
body=
arg=type
+ feature=union-feat2
+a feature
doc symbol=Alternate
body=
@b is undocumented
arg=b
+ feature=alt-feat
+a feature
doc freeform
body=
== Another subsection
doc symbol=EVT-BOXED
body=
+ feature=feat3
+a feature
@item @code{two}
Not documented
@end table
+
+@b{Features:}
+@table @asis
+@item @code{enum-feat}
+Also @emph{one} @{and only@}
+@end table
@code{two} is undocumented
@b{If:} @code{defined(IFCOND)}
@table @asis
@item @code{variant1-feat}
a feature
+@item @code{member-feat}
+a member feature
@end table
@end deftp
@item The members of @code{Variant2} when @code{base1} is @t{"two"} (@b{If:} @code{IFTWO})
@end table
+@b{Features:}
+@table @asis
+@item @code{union-feat1}
+a feature
+@end table
+
@end deftp
@item @code{data: Variant2} when @code{type} is @t{"two"} (@b{If:} @code{IFTWO})
@end table
+@b{Features:}
+@table @asis
+@item @code{union-feat2}
+a feature
+@end table
+
@end deftp
Not documented
@end table
+@b{Features:}
+@table @asis
+@item @code{alt-feat}
+a feature
+@end table
+
@end deftp
@b{Arguments:} the members of @code{Object}
+@b{Features:}
+@table @asis
+@item @code{feat3}
+a feature
+@end table
+
@end deftypefn
--- /dev/null
+features-deprecated-type.json: In struct 'S':
+features-deprecated-type.json:2: feature 'deprecated' is not supported for types
--- /dev/null
+# Feature 'deprecated' is not supported for types
+{ 'struct': 'S', 'data': {},
+ 'features': [ 'deprecated' ] }
'bar': { 'type': ['TestIfEnum'], 'if': 'defined(TEST_IF_EVT_BAR)' } },
'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
-# test 'features' for structs
+# test 'features'
{ 'struct': 'FeatureStruct0',
'data': { 'foo': 'int' },
'features': [] }
{ 'struct': 'FeatureStruct1',
- 'data': { 'foo': 'int' },
+ 'data': { 'foo': { 'type': 'int', 'features': [ 'deprecated' ] } },
'features': [ 'feature1' ] }
{ 'struct': 'FeatureStruct2',
'data': { 'foo': 'int' },
'data': { 'foo': 'int' },
'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)',
'defined(TEST_IF_COND_2)'] } ] }
-{ 'command': 'test-features',
+
+{ 'enum': 'FeatureEnum1',
+ 'data': [ 'eins', 'zwei', 'drei' ],
+ 'features': [ 'feature1' ] }
+
+{ 'union': 'FeatureUnion1',
+ 'base': { 'tag': 'FeatureEnum1' },
+ 'discriminator': 'tag',
+ 'data': { 'eins': 'FeatureStruct1' },
+ 'features': [ 'feature1' ] }
+
+{ 'alternate': 'FeatureAlternate1',
+ 'data': { 'eins': 'FeatureStruct1' },
+ 'features': [ 'feature1' ] }
+
+{ 'command': 'test-features0',
'data': { 'fs0': 'FeatureStruct0',
'fs1': 'FeatureStruct1',
'fs2': 'FeatureStruct2',
'fs4': 'FeatureStruct4',
'cfs1': 'CondFeatureStruct1',
'cfs2': 'CondFeatureStruct2',
- 'cfs3': 'CondFeatureStruct3' } }
-
-# test 'features' for command
-
-{ 'command': 'test-command-features0',
+ 'cfs3': 'CondFeatureStruct3' },
'features': [] }
+
{ 'command': 'test-command-features1',
- 'features': [ 'feature1' ] }
+ 'features': [ 'deprecated' ] }
{ 'command': 'test-command-features3',
'features': [ 'feature1', 'feature2' ] }
{ 'command': 'test-command-cond-features3',
'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)',
'defined(TEST_IF_COND_2)'] } ] }
+
+{ 'event': 'TEST-EVENT-FEATURES1',
+ 'features': [ 'deprecated' ] }
member foo: int optional=False
object FeatureStruct1
member foo: int optional=False
+ feature deprecated
feature feature1
object FeatureStruct2
member foo: int optional=False
member foo: int optional=False
feature feature1
if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)']
-object q_obj_test-features-arg
+enum FeatureEnum1
+ member eins
+ member zwei
+ member drei
+ feature feature1
+object q_obj_FeatureUnion1-base
+ member tag: FeatureEnum1 optional=False
+object FeatureUnion1
+ base q_obj_FeatureUnion1-base
+ tag tag
+ case eins: FeatureStruct1
+ case zwei: q_empty
+ case drei: q_empty
+ feature feature1
+alternate FeatureAlternate1
+ tag type
+ case eins: FeatureStruct1
+ feature feature1
+object q_obj_test-features0-arg
member fs0: FeatureStruct0 optional=False
member fs1: FeatureStruct1 optional=False
member fs2: FeatureStruct2 optional=False
member cfs1: CondFeatureStruct1 optional=False
member cfs2: CondFeatureStruct2 optional=False
member cfs3: CondFeatureStruct3 optional=False
-command test-features q_obj_test-features-arg -> None
- gen=True success_response=True boxed=False oob=False preconfig=False
-command test-command-features0 None -> None
+command test-features0 q_obj_test-features0-arg -> None
gen=True success_response=True boxed=False oob=False preconfig=False
command test-command-features1 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
- feature feature1
+ feature deprecated
command test-command-features3 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1
gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1
if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)']
+event TEST-EVENT-FEATURES1 None
+ boxed=False
+ feature deprecated
module include/sub-module.json
include sub-sub-module.json
object SecondArrayRef
def visit_include(self, name, info):
print('include %s' % name)
- def visit_enum_type(self, name, info, ifcond, members, prefix):
+ def visit_enum_type(self, name, info, ifcond, features, members, prefix):
print('enum %s' % name)
if prefix:
print(' prefix %s' % prefix)
print(' member %s' % m.name)
self._print_if(m.ifcond, indent=8)
self._print_if(ifcond)
+ self._print_features(features)
def visit_array_type(self, name, info, ifcond, element_type):
if not info:
print('array %s %s' % (name, element_type.name))
self._print_if(ifcond)
- def visit_object_type(self, name, info, ifcond, base, members, variants,
- features):
+ def visit_object_type(self, name, info, ifcond, features,
+ base, members, variants):
print('object %s' % name)
if base:
print(' base %s' % base.name)
print(' member %s: %s optional=%s'
% (m.name, m.type.name, m.optional))
self._print_if(m.ifcond, 8)
+ self._print_features(m.features, indent=8)
self._print_variants(variants)
self._print_if(ifcond)
self._print_features(features)
- def visit_alternate_type(self, name, info, ifcond, variants):
+ def visit_alternate_type(self, name, info, ifcond, features, variants):
print('alternate %s' % name)
self._print_variants(variants)
self._print_if(ifcond)
+ self._print_features(features)
- def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
- success_response, boxed, allow_oob, allow_preconfig,
- features):
+ def visit_command(self, name, info, ifcond, features,
+ arg_type, ret_type, gen, success_response, boxed,
+ allow_oob, allow_preconfig):
print('command %s %s -> %s'
% (name, arg_type and arg_type.name,
ret_type and ret_type.name))
self._print_if(ifcond)
self._print_features(features)
- def visit_event(self, name, info, ifcond, arg_type, boxed):
+ def visit_event(self, name, info, ifcond, features, arg_type, boxed):
print('event %s %s' % (name, arg_type and arg_type.name))
print(' boxed=%s' % boxed)
self._print_if(ifcond)
+ self._print_features(features)
@staticmethod
def _print_variants(variants):
print('%sif %s' % (' ' * indent, ifcond))
@classmethod
- def _print_features(cls, features):
+ def _print_features(cls, features, indent=4):
if features:
for f in features:
- print(' feature %s' % f.name)
- cls._print_if(f.ifcond, 8)
+ print('%sfeature %s' % (' ' * indent, f.name))
+ cls._print_if(f.ifcond, indent + 4)
def test_frontend(fname):
QObject *response;
QDict *args = qdict_new();
QList *lst;
- Error *err = NULL;
- qmp_marshal_query_machines(NULL, &response, &err);
- assert(!err);
+ qmp_marshal_query_machines(NULL, &response, &error_abort);
lst = qobject_to(QList, response);
apply_to_qlist(lst, true);
qdict_put_bool(args, "abstract", true);
qdict_put_obj(req, "arguments", (QObject *) args);
- qmp_marshal_qom_list_types(args, &response, &err);
- assert(!err);
+ qmp_marshal_qom_list_types(args, &response, &error_abort);
lst = qobject_to(QList, response);
apply_to_qlist(lst, false);
qobject_unref(response);
char *raw_path = strdup(template);
char *qcow2_path = strdup(template);
char cmd[100 + 2 * PATH_MAX];
- uint8_t buf[512];
+ uint8_t buf[512] = {};
int i, ret, fd, offset;
uint64_t qcow2_size = sectors * 512;
uint8_t status, parttype, head, sector, cyl;
buf[offset + 0x6] = sector;
buf[offset + 0x7] = cyl;
- (*(uint32_t *)&buf[offset + 0x8]) = cpu_to_le32(mbr[i].start_sect);
- (*(uint32_t *)&buf[offset + 0xc]) = cpu_to_le32(mbr[i].nr_sects);
+ stl_le_p(&buf[offset + 0x8], mbr[i].start_sect);
+ stl_le_p(&buf[offset + 0xc], mbr[i].nr_sects);
offset += 0x10;
}
"cap-cfpc=broken," \
"cap-sbbc=broken," \
"cap-ibs=broken," \
- "cap-ccf-assist=off," \
- "cap-fwnmi-mce=off"
+ "cap-ccf-assist=off,"
#endif
# in the tests/venv Python virtual environment. For more info,
# refer to: https://pip.pypa.io/en/stable/user_guide/#id1
avocado-framework==76.0
+pycdlib==1.9.0
run-plugin-semiconsole-with-%:
$(call skip-test, $<, "MANUAL ONLY")
+ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_SVE),)
+# System Registers Tests
+AARCH64_TESTS += sysregs
+sysregs: CFLAGS+=-march=armv8.1-a+sve
+
+# SVE ioctl test
+AARCH64_TESTS += sve-ioctls
+sve-ioctls: CFLAGS+=-march=armv8.1-a+sve
+
+ifneq ($(HAVE_GDB_BIN),)
+GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py
+
+AARCH64_TESTS += gdbstub-sysregs gdbstub-sve-ioctls
+
+.PHONY: gdbstub-sysregs gdbstub-sve-ioctls
+run-gdbstub-sysregs: sysregs
+ $(call run-test, $@, $(GDB_SCRIPT) \
+ --gdb $(HAVE_GDB_BIN) \
+ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
+ --bin $< --test $(AARCH64_SRC)/gdbstub/test-sve.py, \
+ "basic gdbstub SVE support")
+
+run-gdbstub-sve-ioctls: sve-ioctls
+ $(call run-test, $@, $(GDB_SCRIPT) \
+ --gdb $(HAVE_GDB_BIN) \
+ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
+ --bin $< --test $(AARCH64_SRC)/gdbstub/test-sve-ioctl.py, \
+ "basic gdbstub SVE ZLEN support")
+endif
+
+endif
+
TESTS += $(AARCH64_TESTS)
--- /dev/null
+from __future__ import print_function
+#
+# Test the SVE ZReg reports the right amount of data. It uses the
+# sve-ioctl test and examines the register data each time the
+# __sve_ld_done breakpoint is hit.
+#
+# This is launched via tests/guest-debug/run-test.py
+#
+
+import gdb
+import sys
+
+initial_vlen = 0
+failcount = 0
+
+def report(cond, msg):
+ "Report success/fail of test"
+ if cond:
+ print ("PASS: %s" % (msg))
+ else:
+ print ("FAIL: %s" % (msg))
+ global failcount
+ failcount += 1
+
+class TestBreakpoint(gdb.Breakpoint):
+ def __init__(self, sym_name="__sve_ld_done"):
+ super(TestBreakpoint, self).__init__(sym_name)
+ # self.sym, ok = gdb.lookup_symbol(sym_name)
+
+ def stop(self):
+ val_i = gdb.parse_and_eval('i')
+ global initial_vlen
+ try:
+ for i in range(0, int(val_i)):
+ val_z = gdb.parse_and_eval("$z0.b.u[%d]" % i)
+ report(int(val_z) == i, "z0.b.u[%d] == %d" % (i, i))
+ for i in range(i + 1, initial_vlen):
+ val_z = gdb.parse_and_eval("$z0.b.u[%d]" % i)
+ report(int(val_z) == 0, "z0.b.u[%d] == 0" % (i))
+ except gdb.error:
+ report(False, "checking zregs (out of range)")
+
+
+def run_test():
+ "Run through the tests one by one"
+
+ print ("Setup breakpoint")
+ bp = TestBreakpoint()
+
+ global initial_vlen
+ vg = gdb.parse_and_eval("$vg")
+ initial_vlen = int(vg) * 8
+
+ gdb.execute("c")
+
+#
+# This runs as the script it sourced (via -x, via run-test.py)
+#
+try:
+ inferior = gdb.selected_inferior()
+ if inferior.was_attached == False:
+ print("SKIPPING (failed to attach)", file=sys.stderr)
+ exit(0)
+ arch = inferior.architecture()
+ report(arch.name() == "aarch64", "connected to aarch64")
+except (gdb.error, AttributeError):
+ print("SKIPPING (not connected)", file=sys.stderr)
+ exit(0)
+
+try:
+ # These are not very useful in scripts
+ gdb.execute("set pagination off")
+ gdb.execute("set confirm off")
+
+ # Run the actual tests
+ run_test()
+except:
+ print ("GDB Exception: %s" % (sys.exc_info()[0]))
+ failcount += 1
+ import code
+ code.InteractiveConsole(locals=globals()).interact()
+ raise
+
+print("All tests complete: %d failures" % failcount)
+exit(failcount)
--- /dev/null
+from __future__ import print_function
+#
+# Test the SVE registers are visable and changeable via gdbstub
+#
+# This is launched via tests/guest-debug/run-test.py
+#
+
+import gdb
+import sys
+
+MAGIC = 0xDEADBEEF
+
+failcount = 0
+
+def report(cond, msg):
+ "Report success/fail of test"
+ if cond:
+ print ("PASS: %s" % (msg))
+ else:
+ print ("FAIL: %s" % (msg))
+ global failcount
+ failcount += 1
+
+def run_test():
+ "Run through the tests one by one"
+
+ gdb.execute("info registers")
+ report(True, "info registers")
+
+ gdb.execute("info registers vector")
+ report(True, "info registers vector")
+
+ # Now all the zregs
+ frame = gdb.selected_frame()
+ for i in range(0, 32):
+ rname = "z%d" % (i)
+ zreg = frame.read_register(rname)
+ report(True, "Reading %s" % rname)
+ for j in range(0, 4):
+ cmd = "set $%s.q.u[%d] = 0x%x" % (rname, j, MAGIC)
+ gdb.execute(cmd)
+ report(True, "%s" % cmd)
+ for j in range(0, 4):
+ reg = "$%s.q.u[%d]" % (rname, j)
+ v = gdb.parse_and_eval(reg)
+ report(str(v.type) == "uint128_t", "size of %s" % (reg))
+ for j in range(0, 8):
+ cmd = "set $%s.d.u[%d] = 0x%x" % (rname, j, MAGIC)
+ gdb.execute(cmd)
+ report(True, "%s" % cmd)
+ for j in range(0, 8):
+ reg = "$%s.d.u[%d]" % (rname, j)
+ v = gdb.parse_and_eval(reg)
+ report(str(v.type) == "uint64_t", "size of %s" % (reg))
+ report(int(v) == MAGIC, "%s is 0x%x" % (reg, MAGIC))
+
+#
+# This runs as the script it sourced (via -x, via run-test.py)
+#
+try:
+ inferior = gdb.selected_inferior()
+ if inferior.was_attached == False:
+ print("SKIPPING (failed to attach)", file=sys.stderr)
+ exit(0)
+ arch = inferior.architecture()
+ report(arch.name() == "aarch64", "connected to aarch64")
+except (gdb.error, AttributeError):
+ print("SKIPPING (not connected)", file=sys.stderr)
+ exit(0)
+
+try:
+ # These are not very useful in scripts
+ gdb.execute("set pagination off")
+ gdb.execute("set confirm off")
+
+ # Run the actual tests
+ run_test()
+except:
+ print ("GDB Exception: %s" % (sys.exc_info()[0]))
+ failcount += 1
+
+print("All tests complete: %d failures" % failcount)
+
+exit(failcount)
--- /dev/null
+/*
+ * SVE ioctls tests
+ *
+ * Test the SVE width setting ioctls work and provide a base for
+ * testing the gdbstub.
+ *
+ * Copyright (c) 2019 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <sys/prctl.h>
+#include <asm/hwcap.h>
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#ifndef HWCAP_CPUID
+#define HWCAP_CPUID (1 << 11)
+#endif
+
+#define SVE_MAX_QUADS (2048 / 128)
+#define BYTES_PER_QUAD (128 / 8)
+
+#define get_cpu_reg(id) ({ \
+ unsigned long __val; \
+ asm("mrs %0, "#id : "=r" (__val)); \
+ __val; \
+ })
+
+static int do_sve_ioctl_test(void)
+{
+ int i, res, init_vq;
+
+ res = prctl(PR_SVE_GET_VL, 0, 0, 0, 0);
+ if (res < 0) {
+ printf("FAILED to PR_SVE_GET_VL (%d)", res);
+ return -1;
+ }
+ init_vq = res & PR_SVE_VL_LEN_MASK;
+
+ for (i = init_vq; i > 15; i /= 2) {
+ printf("Checking PR_SVE_SET_VL=%d\n", i);
+ res = prctl(PR_SVE_SET_VL, i, 0, 0, 0, 0);
+ if (res < 0) {
+ printf("FAILED to PR_SVE_SET_VL (%d)", res);
+ return -1;
+ }
+ asm("index z0.b, #0, #1\n"
+ ".global __sve_ld_done\n"
+ "__sve_ld_done:\n"
+ "mov z0.b, #0\n"
+ : /* no outputs kept */
+ : /* no inputs */
+ : "memory", "z0");
+ }
+ printf("PASS\n");
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ /* we also need to probe for the ioctl support */
+ if (getauxval(AT_HWCAP) & HWCAP_SVE) {
+ return do_sve_ioctl_test();
+ } else {
+ printf("SKIP: no HWCAP_SVE on this system\n");
+ return 0;
+ }
+}
--- /dev/null
+/*
+ * Check emulated system register access for linux-user mode.
+ *
+ * See: https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
+ *
+ * Copyright (c) 2019 Linaro
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <asm/hwcap.h>
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <signal.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifndef HWCAP_CPUID
+#define HWCAP_CPUID (1 << 11)
+#endif
+
+int failed_bit_count;
+
+/* Read and print system register `id' value */
+#define get_cpu_reg(id) ({ \
+ unsigned long __val = 0xdeadbeef; \
+ asm("mrs %0, "#id : "=r" (__val)); \
+ printf("%-20s: 0x%016lx\n", #id, __val); \
+ __val; \
+ })
+
+/* As above but also check no bits outside of `mask' are set*/
+#define get_cpu_reg_check_mask(id, mask) ({ \
+ unsigned long __cval = get_cpu_reg(id); \
+ unsigned long __extra = __cval & ~mask; \
+ if (__extra) { \
+ printf("%-20s: 0x%016lx\n", " !!extra bits!!", __extra); \
+ failed_bit_count++; \
+ } \
+})
+
+/* As above but check RAZ */
+#define get_cpu_reg_check_zero(id) ({ \
+ unsigned long __val = 0xdeadbeef; \
+ asm("mrs %0, "#id : "=r" (__val)); \
+ if (__val) { \
+ printf("%-20s: 0x%016lx (not RAZ!)\n", #id, __val); \
+ failed_bit_count++; \
+ } \
+})
+
+/* Chunk up mask into 63:48, 47:32, 31:16, 15:0 to ease counting */
+#define _m(a, b, c, d) (0x ## a ## b ## c ## d ##ULL)
+
+bool should_fail;
+int should_fail_count;
+int should_not_fail_count;
+uintptr_t failed_pc[10];
+
+void sigill_handler(int signo, siginfo_t *si, void *data)
+{
+ ucontext_t *uc = (ucontext_t *)data;
+
+ if (should_fail) {
+ should_fail_count++;
+ } else {
+ uintptr_t pc = (uintptr_t) uc->uc_mcontext.pc;
+ failed_pc[should_not_fail_count++] = pc;
+ }
+ uc->uc_mcontext.pc += 4;
+}
+
+int main(void)
+{
+ struct sigaction sa;
+
+ /* Hook in a SIGILL handler */
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_sigaction = &sigill_handler;
+ sigemptyset(&sa.sa_mask);
+
+ if (sigaction(SIGILL, &sa, 0) != 0) {
+ perror("sigaction");
+ return 1;
+ }
+
+ /* Counter values have been exposed since Linux 4.12 */
+ printf("Checking Counter registers\n");
+
+ get_cpu_reg(ctr_el0);
+ get_cpu_reg(cntvct_el0);
+ get_cpu_reg(cntfrq_el0);
+
+ /* HWCAP_CPUID indicates we can read feature registers, since Linux 4.11 */
+ if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) {
+ printf("CPUID registers unavailable\n");
+ return 1;
+ } else {
+ printf("Checking CPUID registers\n");
+ }
+
+ /*
+ * Some registers only expose some bits to user-space. Anything
+ * that is IMPDEF is exported as 0 to user-space. The _mask checks
+ * assert no extra bits are set.
+ *
+ * This check is *not* comprehensive as some fields are set to
+ * 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));
+ /* 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);
+ /* 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));
+ /* 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_zero(id_aa64afr0_el1);
+ get_cpu_reg_check_zero(id_aa64afr1_el1);
+
+ get_cpu_reg_check_mask(midr_el1, _m(0000,0000,ffff,ffff));
+ /* mpidr sets bit 31, everything else hidden */
+ get_cpu_reg_check_mask(mpidr_el1, _m(0000,0000,8000,0000));
+ /* REVIDR is all IMPDEF so should be all zeros to user-space */
+ get_cpu_reg_check_zero(revidr_el1);
+
+ /*
+ * There are a block of more registers that are RAZ in the rest of
+ * the Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7 space. However for
+ * brevity we don't check stuff that is currently un-allocated
+ * here. Feel free to add them ;-)
+ */
+
+ printf("Remaining registers should fail\n");
+ should_fail = true;
+
+ /* Unexposed register access causes SIGILL */
+ get_cpu_reg(id_mmfr0_el1);
+ get_cpu_reg(id_mmfr1_el1);
+ get_cpu_reg(id_mmfr2_el1);
+ get_cpu_reg(id_mmfr3_el1);
+
+ get_cpu_reg(mvfr0_el1);
+ get_cpu_reg(mvfr1_el1);
+
+ if (should_not_fail_count > 0) {
+ int i;
+ for (i = 0; i < should_not_fail_count; i++) {
+ uintptr_t pc = failed_pc[i];
+ uint32_t insn = *(uint32_t *) pc;
+ printf("insn %#x @ %#lx unexpected FAIL\n", insn, pc);
+ }
+ return 1;
+ }
+
+ if (failed_bit_count > 0) {
+ printf("Extra information leaked to user-space!\n");
+ return 1;
+ }
+
+ return should_fail_count == 6 ? 0 : 1;
+}
#include "qemu/osdep.h"
#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qnum.h"
#include "qapi/qmp/qstring.h"
#include "qapi/error.h"
{
}
-void qmp_test_features(FeatureStruct0 *fs0, FeatureStruct1 *fs1,
+void qmp_test_features0(FeatureStruct0 *fs0, FeatureStruct1 *fs1,
FeatureStruct2 *fs2, FeatureStruct3 *fs3,
FeatureStruct4 *fs4, CondFeatureStruct1 *cfs1,
CondFeatureStruct2 *cfs2, CondFeatureStruct3 *cfs3,
{
}
-void qmp_test_command_features0(Error **errp)
-{
-}
-
void qmp_test_command_features1(Error **errp)
{
}
}
-/* test commands with no input and no return value */
-static void test_dispatch_cmd(void)
+static QObject *do_qmp_dispatch(bool allow_oob, const char *template, ...)
{
- QDict *req = qdict_new();
- QDict *resp;
+ va_list ap;
+ QDict *req, *resp;
+ QObject *ret;
- qdict_put_str(req, "execute", "user_def_cmd");
+ va_start(ap, template);
+ req = qdict_from_vjsonf_nofail(template, ap);
+ va_end(ap);
- resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false);
- assert(resp != NULL);
- assert(!qdict_haskey(resp, "error"));
+ resp = qmp_dispatch(&qmp_commands, QOBJECT(req), allow_oob);
+ g_assert(resp);
+ ret = qdict_get(resp, "return");
+ g_assert(ret);
+ g_assert(qdict_size(resp) == 1);
+ qobject_ref(ret);
qobject_unref(resp);
qobject_unref(req);
+ return ret;
}
-static void test_dispatch_cmd_oob(void)
+static void do_qmp_dispatch_error(bool allow_oob, ErrorClass cls,
+ const char *template, ...)
{
- QDict *req = qdict_new();
- QDict *resp;
-
- qdict_put_str(req, "exec-oob", "test-flags-command");
-
- resp = qmp_dispatch(&qmp_commands, QOBJECT(req), true);
- assert(resp != NULL);
- assert(!qdict_haskey(resp, "error"));
+ va_list ap;
+ QDict *req, *resp;
+ QDict *error;
+
+ va_start(ap, template);
+ req = qdict_from_vjsonf_nofail(template, ap);
+ va_end(ap);
+
+ resp = qmp_dispatch(&qmp_commands, QOBJECT(req), allow_oob);
+ g_assert(resp);
+ error = qdict_get_qdict(resp, "error");
+ g_assert(error);
+ g_assert_cmpstr(qdict_get_try_str(error, "class"),
+ ==, QapiErrorClass_str(cls));
+ g_assert(qdict_get_try_str(error, "desc"));
+ g_assert(qdict_size(error) == 2);
+ g_assert(qdict_size(resp) == 1);
qobject_unref(resp);
qobject_unref(req);
}
-/* test commands that return an error due to invalid parameters */
-static void test_dispatch_cmd_failure(void)
+/* test commands with no input and no return value */
+static void test_dispatch_cmd(void)
{
- QDict *req = qdict_new();
- QDict *args = qdict_new();
- QDict *resp;
-
- qdict_put_str(req, "execute", "user_def_cmd2");
-
- resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false);
- assert(resp != NULL);
- assert(qdict_haskey(resp, "error"));
-
- qobject_unref(resp);
- qobject_unref(req);
+ QDict *ret;
- /* check that with extra arguments it throws an error */
- req = qdict_new();
- qdict_put_int(args, "a", 66);
- qdict_put(req, "arguments", args);
+ ret = qobject_to(QDict,
+ do_qmp_dispatch(false,
+ "{ 'execute': 'user_def_cmd' }"));
+ assert(ret && qdict_size(ret) == 0);
+ qobject_unref(ret);
+}
- qdict_put_str(req, "execute", "user_def_cmd");
+static void test_dispatch_cmd_oob(void)
+{
+ QDict *ret;
- resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false);
- assert(resp != NULL);
- assert(qdict_haskey(resp, "error"));
+ ret = qobject_to(QDict,
+ do_qmp_dispatch(true,
+ "{ 'exec-oob': 'test-flags-command' }"));
+ assert(ret && qdict_size(ret) == 0);
+ qobject_unref(ret);
+}
- qobject_unref(resp);
- qobject_unref(req);
+/* test commands that return an error due to invalid parameters */
+static void test_dispatch_cmd_failure(void)
+{
+ /* missing arguments */
+ do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR,
+ "{ 'execute': 'user_def_cmd2' }");
+
+ /* extra arguments */
+ do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR,
+ "{ 'execute': 'user_def_cmd',"
+ " 'arguments': { 'a': 66 } }");
}
static void test_dispatch_cmd_success_response(void)
qobject_unref(req);
}
-static QObject *test_qmp_dispatch(QDict *req)
-{
- QDict *resp;
- QObject *ret;
-
- resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false);
- assert(resp && !qdict_haskey(resp, "error"));
- ret = qdict_get(resp, "return");
- assert(ret);
- qobject_ref(ret);
- qobject_unref(resp);
- return ret;
-}
-
/* test commands that involve both input parameters and return values */
static void test_dispatch_cmd_io(void)
{
- QDict *req = qdict_new();
- QDict *args = qdict_new();
- QDict *args3 = qdict_new();
- QDict *ud1a = qdict_new();
- QDict *ud1b = qdict_new();
QDict *ret, *ret_dict, *ret_dict_dict, *ret_dict_dict_userdef;
QDict *ret_dict_dict2, *ret_dict_dict2_userdef;
QNum *ret3;
int64_t val;
- qdict_put_int(ud1a, "integer", 42);
- qdict_put_str(ud1a, "string", "hello");
- qdict_put_int(ud1b, "integer", 422);
- qdict_put_str(ud1b, "string", "hello2");
- qdict_put(args, "ud1a", ud1a);
- qdict_put(args, "ud1b", ud1b);
- qdict_put(req, "arguments", args);
- qdict_put_str(req, "execute", "user_def_cmd2");
-
- ret = qobject_to(QDict, test_qmp_dispatch(req));
+ ret = qobject_to(QDict, do_qmp_dispatch(false,
+ "{ 'execute': 'user_def_cmd2', 'arguments': {"
+ " 'ud1a': { 'integer': 42, 'string': 'hello' },"
+ " 'ud1b': { 'integer': 422, 'string': 'hello2' } } }"));
assert(!strcmp(qdict_get_str(ret, "string0"), "blah1"));
ret_dict = qdict_get_qdict(ret, "dict1");
assert(!strcmp(qdict_get_str(ret_dict_dict2, "string"), "blah4"));
qobject_unref(ret);
- qdict_put_int(args3, "a", 66);
- qdict_put(req, "arguments", args3);
- qdict_put_str(req, "execute", "guest-get-time");
-
- ret3 = qobject_to(QNum, test_qmp_dispatch(req));
+ ret3 = qobject_to(QNum, do_qmp_dispatch(false,
+ "{ 'execute': 'guest-get-time', 'arguments': { 'a': 66 } }"));
g_assert(qnum_get_try_int(ret3, &val));
g_assert_cmpint(val, ==, 66);
qobject_unref(ret3);
-
- qobject_unref(req);
}
/* test generated dealloc functions for generated types */
#include "qapi/error.h"
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qnum.h"
#include "qapi/qmp/qstring.h"
#include "qapi/qmp-event.h"
typedef struct TestEventData {
QDict *expect;
+ bool emitted;
} TestEventData;
-typedef struct QDictCmpData {
- QDict *expect;
- bool result;
-} QDictCmpData;
-
TestEventData *test_event_data;
static GMutex test_event_lock;
-/* Only compares bool, int, string */
-static
-void qdict_cmp_do_simple(const char *key, QObject *obj1, void *opaque)
-
-{
- QObject *obj2;
- QDictCmpData d_new, *d = opaque;
- int64_t val1, val2;
-
- if (!d->result) {
- return;
- }
-
- obj2 = qdict_get(d->expect, key);
- if (!obj2) {
- d->result = false;
- return;
- }
-
- if (qobject_type(obj1) != qobject_type(obj2)) {
- d->result = false;
- return;
- }
-
- switch (qobject_type(obj1)) {
- case QTYPE_QBOOL:
- d->result = (qbool_get_bool(qobject_to(QBool, obj1)) ==
- qbool_get_bool(qobject_to(QBool, obj2)));
- return;
- case QTYPE_QNUM:
- g_assert(qnum_get_try_int(qobject_to(QNum, obj1), &val1));
- g_assert(qnum_get_try_int(qobject_to(QNum, obj2), &val2));
- d->result = val1 == val2;
- return;
- case QTYPE_QSTRING:
- d->result = g_strcmp0(qstring_get_str(qobject_to(QString, obj1)),
- qstring_get_str(qobject_to(QString, obj2))) == 0;
- return;
- case QTYPE_QDICT:
- d_new.expect = qobject_to(QDict, obj2);
- d_new.result = true;
- qdict_iter(qobject_to(QDict, obj1), qdict_cmp_do_simple, &d_new);
- d->result = d_new.result;
- return;
- default:
- abort();
- }
-}
-
-static bool qdict_cmp_simple(QDict *a, QDict *b)
-{
- QDictCmpData d;
-
- d.expect = b;
- d.result = true;
- qdict_iter(a, qdict_cmp_do_simple, &d);
- return d.result;
-}
-
void test_qapi_event_emit(test_QAPIEvent event, QDict *d)
{
QDict *t;
qdict_del(d, "timestamp");
- g_assert(qdict_cmp_simple(d, test_event_data->expect));
-
+ g_assert(qobject_is_equal(QOBJECT(d), QOBJECT(test_event_data->expect)));
+ test_event_data->emitted = true;
}
static void event_prepare(TestEventData *data,
/* Global variable test_event_data was used to pass the expectation, so
test cases can't be executed at same time. */
g_mutex_lock(&test_event_lock);
-
- data->expect = qdict_new();
test_event_data = data;
}
static void event_teardown(TestEventData *data,
const void *unused)
{
- qobject_unref(data->expect);
test_event_data = NULL;
-
g_mutex_unlock(&test_event_lock);
}
static void test_event_a(TestEventData *data,
const void *unused)
{
- QDict *d;
- d = data->expect;
- qdict_put_str(d, "event", "EVENT_A");
+ data->expect = qdict_from_jsonf_nofail("{ 'event': 'EVENT_A' }");
qapi_event_send_event_a();
+ g_assert(data->emitted);
+ qobject_unref(data->expect);
}
static void test_event_b(TestEventData *data,
const void *unused)
{
- QDict *d;
- d = data->expect;
- qdict_put_str(d, "event", "EVENT_B");
+ data->expect = qdict_from_jsonf_nofail("{ 'event': 'EVENT_B' }");
qapi_event_send_event_b();
+ g_assert(data->emitted);
+ qobject_unref(data->expect);
}
static void test_event_c(TestEventData *data,
const void *unused)
{
- QDict *d, *d_data, *d_b;
-
- UserDefOne b;
- b.integer = 2;
- b.string = g_strdup("test1");
- b.has_enum1 = false;
-
- d_b = qdict_new();
- qdict_put_int(d_b, "integer", 2);
- qdict_put_str(d_b, "string", "test1");
-
- d_data = qdict_new();
- qdict_put_int(d_data, "a", 1);
- qdict_put(d_data, "b", d_b);
- qdict_put_str(d_data, "c", "test2");
-
- d = data->expect;
- qdict_put_str(d, "event", "EVENT_C");
- qdict_put(d, "data", d_data);
+ UserDefOne b = { .integer = 2, .string = (char *)"test1" };
+ data->expect = qdict_from_jsonf_nofail(
+ "{ 'event': 'EVENT_C', 'data': {"
+ " 'a': 1, 'b': { 'integer': 2, 'string': 'test1' }, 'c': 'test2' } }");
qapi_event_send_event_c(true, 1, true, &b, "test2");
-
- g_free(b.string);
+ g_assert(data->emitted);
+ qobject_unref(data->expect);
}
/* Complex type */
static void test_event_d(TestEventData *data,
const void *unused)
{
- UserDefOne struct1;
- EventStructOne a;
- QDict *d, *d_data, *d_a, *d_struct1;
-
- struct1.integer = 2;
- struct1.string = g_strdup("test1");
- struct1.has_enum1 = true;
- struct1.enum1 = ENUM_ONE_VALUE1;
-
- a.struct1 = &struct1;
- a.string = g_strdup("test2");
- a.has_enum2 = true;
- a.enum2 = ENUM_ONE_VALUE2;
-
- d_struct1 = qdict_new();
- qdict_put_int(d_struct1, "integer", 2);
- qdict_put_str(d_struct1, "string", "test1");
- qdict_put_str(d_struct1, "enum1", "value1");
-
- d_a = qdict_new();
- qdict_put(d_a, "struct1", d_struct1);
- qdict_put_str(d_a, "string", "test2");
- qdict_put_str(d_a, "enum2", "value2");
-
- d_data = qdict_new();
- qdict_put(d_data, "a", d_a);
- qdict_put_str(d_data, "b", "test3");
- qdict_put_str(d_data, "enum3", "value3");
-
- d = data->expect;
- qdict_put_str(d, "event", "EVENT_D");
- qdict_put(d, "data", d_data);
-
+ UserDefOne struct1 = {
+ .integer = 2, .string = (char *)"test1",
+ .has_enum1 = true, .enum1 = ENUM_ONE_VALUE1,
+ };
+ EventStructOne a = {
+ .struct1 = &struct1,
+ .string = (char *)"test2",
+ .has_enum2 = true,
+ .enum2 = ENUM_ONE_VALUE2,
+ };
+
+ data->expect = qdict_from_jsonf_nofail(
+ "{ 'event': 'EVENT_D', 'data': {"
+ " 'a': {"
+ " 'struct1': { 'integer': 2, 'string': 'test1', 'enum1': 'value1' },"
+ " 'string': 'test2', 'enum2': 'value2' },"
+ " 'b': 'test3', 'enum3': 'value3' } }");
qapi_event_send_event_d(&a, "test3", false, NULL, true, ENUM_ONE_VALUE3);
-
- g_free(struct1.string);
- g_free(a.string);
+ g_assert(data->emitted);
+ qobject_unref(data->expect);
}
int main(int argc, char **argv)