* [Qemu-devel] [PULL 01/62] target-arm: add support for v8 AES instructions
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 02/62] rename pflash_t member width to bank_width Peter Maydell
` (61 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
This adds support for the AESE/AESD/AESMC/AESIMC instructions that
are available on some v8 implementations of Aarch32.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Message-id: 1386266078-6976-1-git-send-email-ard.biesheuvel@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/Makefile.objs | 1 +
target-arm/cpu.c | 1 +
target-arm/cpu.h | 1 +
target-arm/crypto_helper.c | 281 +++++++++++++++++++++++++++++++++++++++++++++
target-arm/helper.h | 3 +
target-arm/translate.c | 26 +++++
6 files changed, 313 insertions(+)
create mode 100644 target-arm/crypto_helper.c
diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
index 356fbfc..f428b5b 100644
--- a/target-arm/Makefile.objs
+++ b/target-arm/Makefile.objs
@@ -6,3 +6,4 @@ obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += neon_helper.o iwmmxt_helper.o
obj-y += gdbstub.o
obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o gdbstub64.o
+obj-y += crypto_helper.o
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 0635e78..a03743f 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -249,6 +249,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
set_feature(env, ARM_FEATURE_V7);
set_feature(env, ARM_FEATURE_ARM_DIV);
set_feature(env, ARM_FEATURE_LPAE);
+ set_feature(env, ARM_FEATURE_V8_AES);
}
if (arm_feature(env, ARM_FEATURE_V7)) {
set_feature(env, ARM_FEATURE_VAPA);
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c3f007f..00fd80d 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -467,6 +467,7 @@ enum arm_features {
ARM_FEATURE_LPAE, /* has Large Physical Address Extension */
ARM_FEATURE_V8,
ARM_FEATURE_AARCH64, /* supports 64 bit mode */
+ ARM_FEATURE_V8_AES, /* implements AES part of v8 Crypto Extensions */
};
static inline int arm_feature(CPUARMState *env, int feature)
diff --git a/target-arm/crypto_helper.c b/target-arm/crypto_helper.c
new file mode 100644
index 0000000..f94be69
--- /dev/null
+++ b/target-arm/crypto_helper.c
@@ -0,0 +1,281 @@
+/*
+ * crypto_helper.c - emulate v8 Crypto Extensions instructions
+ *
+ * Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ */
+
+#include <stdlib.h>
+
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "helper.h"
+
+union AES_STATE {
+ uint8_t bytes[16];
+ uint32_t cols[4];
+ uint64_t l[2];
+};
+
+void HELPER(crypto_aese)(CPUARMState *env, uint32_t rd, uint32_t rm,
+ uint32_t decrypt)
+{
+ static uint8_t const sbox[][256] = { {
+ /* S-box for encryption */
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
+ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
+ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
+ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
+ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
+ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
+ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
+ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
+ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
+ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
+ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
+ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+ }, {
+ /* S-box for decryption */
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
+ 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
+ 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
+ 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
+ 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
+ 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
+ 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
+ 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
+ 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
+ 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
+ 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
+ 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
+ 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
+ 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
+ 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
+ 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
+ } };
+ static uint8_t const shift[][16] = {
+ /* ShiftRows permutation vector for encryption */
+ { 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11 },
+ /* ShiftRows permutation vector for decryption */
+ { 0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3 },
+ };
+ union AES_STATE rk = { .l = {
+ float64_val(env->vfp.regs[rm]),
+ float64_val(env->vfp.regs[rm + 1])
+ } };
+ union AES_STATE st = { .l = {
+ float64_val(env->vfp.regs[rd]),
+ float64_val(env->vfp.regs[rd + 1])
+ } };
+ int i;
+
+ assert(decrypt < 2);
+
+ /* xor state vector with round key */
+ rk.l[0] ^= st.l[0];
+ rk.l[1] ^= st.l[1];
+
+ /* combine ShiftRows operation and sbox substitution */
+ for (i = 0; i < 16; i++) {
+ st.bytes[i] = sbox[decrypt][rk.bytes[shift[decrypt][i]]];
+ }
+
+ env->vfp.regs[rd] = make_float64(st.l[0]);
+ env->vfp.regs[rd + 1] = make_float64(st.l[1]);
+}
+
+void HELPER(crypto_aesmc)(CPUARMState *env, uint32_t rd, uint32_t rm,
+ uint32_t decrypt)
+{
+ static uint32_t const mc[][256] = { {
+ /* MixColumns lookup table */
+ 0x00000000, 0x03010102, 0x06020204, 0x05030306,
+ 0x0c040408, 0x0f05050a, 0x0a06060c, 0x0907070e,
+ 0x18080810, 0x1b090912, 0x1e0a0a14, 0x1d0b0b16,
+ 0x140c0c18, 0x170d0d1a, 0x120e0e1c, 0x110f0f1e,
+ 0x30101020, 0x33111122, 0x36121224, 0x35131326,
+ 0x3c141428, 0x3f15152a, 0x3a16162c, 0x3917172e,
+ 0x28181830, 0x2b191932, 0x2e1a1a34, 0x2d1b1b36,
+ 0x241c1c38, 0x271d1d3a, 0x221e1e3c, 0x211f1f3e,
+ 0x60202040, 0x63212142, 0x66222244, 0x65232346,
+ 0x6c242448, 0x6f25254a, 0x6a26264c, 0x6927274e,
+ 0x78282850, 0x7b292952, 0x7e2a2a54, 0x7d2b2b56,
+ 0x742c2c58, 0x772d2d5a, 0x722e2e5c, 0x712f2f5e,
+ 0x50303060, 0x53313162, 0x56323264, 0x55333366,
+ 0x5c343468, 0x5f35356a, 0x5a36366c, 0x5937376e,
+ 0x48383870, 0x4b393972, 0x4e3a3a74, 0x4d3b3b76,
+ 0x443c3c78, 0x473d3d7a, 0x423e3e7c, 0x413f3f7e,
+ 0xc0404080, 0xc3414182, 0xc6424284, 0xc5434386,
+ 0xcc444488, 0xcf45458a, 0xca46468c, 0xc947478e,
+ 0xd8484890, 0xdb494992, 0xde4a4a94, 0xdd4b4b96,
+ 0xd44c4c98, 0xd74d4d9a, 0xd24e4e9c, 0xd14f4f9e,
+ 0xf05050a0, 0xf35151a2, 0xf65252a4, 0xf55353a6,
+ 0xfc5454a8, 0xff5555aa, 0xfa5656ac, 0xf95757ae,
+ 0xe85858b0, 0xeb5959b2, 0xee5a5ab4, 0xed5b5bb6,
+ 0xe45c5cb8, 0xe75d5dba, 0xe25e5ebc, 0xe15f5fbe,
+ 0xa06060c0, 0xa36161c2, 0xa66262c4, 0xa56363c6,
+ 0xac6464c8, 0xaf6565ca, 0xaa6666cc, 0xa96767ce,
+ 0xb86868d0, 0xbb6969d2, 0xbe6a6ad4, 0xbd6b6bd6,
+ 0xb46c6cd8, 0xb76d6dda, 0xb26e6edc, 0xb16f6fde,
+ 0x907070e0, 0x937171e2, 0x967272e4, 0x957373e6,
+ 0x9c7474e8, 0x9f7575ea, 0x9a7676ec, 0x997777ee,
+ 0x887878f0, 0x8b7979f2, 0x8e7a7af4, 0x8d7b7bf6,
+ 0x847c7cf8, 0x877d7dfa, 0x827e7efc, 0x817f7ffe,
+ 0x9b80801b, 0x98818119, 0x9d82821f, 0x9e83831d,
+ 0x97848413, 0x94858511, 0x91868617, 0x92878715,
+ 0x8388880b, 0x80898909, 0x858a8a0f, 0x868b8b0d,
+ 0x8f8c8c03, 0x8c8d8d01, 0x898e8e07, 0x8a8f8f05,
+ 0xab90903b, 0xa8919139, 0xad92923f, 0xae93933d,
+ 0xa7949433, 0xa4959531, 0xa1969637, 0xa2979735,
+ 0xb398982b, 0xb0999929, 0xb59a9a2f, 0xb69b9b2d,
+ 0xbf9c9c23, 0xbc9d9d21, 0xb99e9e27, 0xba9f9f25,
+ 0xfba0a05b, 0xf8a1a159, 0xfda2a25f, 0xfea3a35d,
+ 0xf7a4a453, 0xf4a5a551, 0xf1a6a657, 0xf2a7a755,
+ 0xe3a8a84b, 0xe0a9a949, 0xe5aaaa4f, 0xe6abab4d,
+ 0xefacac43, 0xecadad41, 0xe9aeae47, 0xeaafaf45,
+ 0xcbb0b07b, 0xc8b1b179, 0xcdb2b27f, 0xceb3b37d,
+ 0xc7b4b473, 0xc4b5b571, 0xc1b6b677, 0xc2b7b775,
+ 0xd3b8b86b, 0xd0b9b969, 0xd5baba6f, 0xd6bbbb6d,
+ 0xdfbcbc63, 0xdcbdbd61, 0xd9bebe67, 0xdabfbf65,
+ 0x5bc0c09b, 0x58c1c199, 0x5dc2c29f, 0x5ec3c39d,
+ 0x57c4c493, 0x54c5c591, 0x51c6c697, 0x52c7c795,
+ 0x43c8c88b, 0x40c9c989, 0x45caca8f, 0x46cbcb8d,
+ 0x4fcccc83, 0x4ccdcd81, 0x49cece87, 0x4acfcf85,
+ 0x6bd0d0bb, 0x68d1d1b9, 0x6dd2d2bf, 0x6ed3d3bd,
+ 0x67d4d4b3, 0x64d5d5b1, 0x61d6d6b7, 0x62d7d7b5,
+ 0x73d8d8ab, 0x70d9d9a9, 0x75dadaaf, 0x76dbdbad,
+ 0x7fdcdca3, 0x7cdddda1, 0x79dedea7, 0x7adfdfa5,
+ 0x3be0e0db, 0x38e1e1d9, 0x3de2e2df, 0x3ee3e3dd,
+ 0x37e4e4d3, 0x34e5e5d1, 0x31e6e6d7, 0x32e7e7d5,
+ 0x23e8e8cb, 0x20e9e9c9, 0x25eaeacf, 0x26ebebcd,
+ 0x2fececc3, 0x2cededc1, 0x29eeeec7, 0x2aefefc5,
+ 0x0bf0f0fb, 0x08f1f1f9, 0x0df2f2ff, 0x0ef3f3fd,
+ 0x07f4f4f3, 0x04f5f5f1, 0x01f6f6f7, 0x02f7f7f5,
+ 0x13f8f8eb, 0x10f9f9e9, 0x15fafaef, 0x16fbfbed,
+ 0x1ffcfce3, 0x1cfdfde1, 0x19fefee7, 0x1affffe5,
+ }, {
+ /* Inverse MixColumns lookup table */
+ 0x00000000, 0x0b0d090e, 0x161a121c, 0x1d171b12,
+ 0x2c342438, 0x27392d36, 0x3a2e3624, 0x31233f2a,
+ 0x58684870, 0x5365417e, 0x4e725a6c, 0x457f5362,
+ 0x745c6c48, 0x7f516546, 0x62467e54, 0x694b775a,
+ 0xb0d090e0, 0xbbdd99ee, 0xa6ca82fc, 0xadc78bf2,
+ 0x9ce4b4d8, 0x97e9bdd6, 0x8afea6c4, 0x81f3afca,
+ 0xe8b8d890, 0xe3b5d19e, 0xfea2ca8c, 0xf5afc382,
+ 0xc48cfca8, 0xcf81f5a6, 0xd296eeb4, 0xd99be7ba,
+ 0x7bbb3bdb, 0x70b632d5, 0x6da129c7, 0x66ac20c9,
+ 0x578f1fe3, 0x5c8216ed, 0x41950dff, 0x4a9804f1,
+ 0x23d373ab, 0x28de7aa5, 0x35c961b7, 0x3ec468b9,
+ 0x0fe75793, 0x04ea5e9d, 0x19fd458f, 0x12f04c81,
+ 0xcb6bab3b, 0xc066a235, 0xdd71b927, 0xd67cb029,
+ 0xe75f8f03, 0xec52860d, 0xf1459d1f, 0xfa489411,
+ 0x9303e34b, 0x980eea45, 0x8519f157, 0x8e14f859,
+ 0xbf37c773, 0xb43ace7d, 0xa92dd56f, 0xa220dc61,
+ 0xf66d76ad, 0xfd607fa3, 0xe07764b1, 0xeb7a6dbf,
+ 0xda595295, 0xd1545b9b, 0xcc434089, 0xc74e4987,
+ 0xae053edd, 0xa50837d3, 0xb81f2cc1, 0xb31225cf,
+ 0x82311ae5, 0x893c13eb, 0x942b08f9, 0x9f2601f7,
+ 0x46bde64d, 0x4db0ef43, 0x50a7f451, 0x5baafd5f,
+ 0x6a89c275, 0x6184cb7b, 0x7c93d069, 0x779ed967,
+ 0x1ed5ae3d, 0x15d8a733, 0x08cfbc21, 0x03c2b52f,
+ 0x32e18a05, 0x39ec830b, 0x24fb9819, 0x2ff69117,
+ 0x8dd64d76, 0x86db4478, 0x9bcc5f6a, 0x90c15664,
+ 0xa1e2694e, 0xaaef6040, 0xb7f87b52, 0xbcf5725c,
+ 0xd5be0506, 0xdeb30c08, 0xc3a4171a, 0xc8a91e14,
+ 0xf98a213e, 0xf2872830, 0xef903322, 0xe49d3a2c,
+ 0x3d06dd96, 0x360bd498, 0x2b1ccf8a, 0x2011c684,
+ 0x1132f9ae, 0x1a3ff0a0, 0x0728ebb2, 0x0c25e2bc,
+ 0x656e95e6, 0x6e639ce8, 0x737487fa, 0x78798ef4,
+ 0x495ab1de, 0x4257b8d0, 0x5f40a3c2, 0x544daacc,
+ 0xf7daec41, 0xfcd7e54f, 0xe1c0fe5d, 0xeacdf753,
+ 0xdbeec879, 0xd0e3c177, 0xcdf4da65, 0xc6f9d36b,
+ 0xafb2a431, 0xa4bfad3f, 0xb9a8b62d, 0xb2a5bf23,
+ 0x83868009, 0x888b8907, 0x959c9215, 0x9e919b1b,
+ 0x470a7ca1, 0x4c0775af, 0x51106ebd, 0x5a1d67b3,
+ 0x6b3e5899, 0x60335197, 0x7d244a85, 0x7629438b,
+ 0x1f6234d1, 0x146f3ddf, 0x097826cd, 0x02752fc3,
+ 0x335610e9, 0x385b19e7, 0x254c02f5, 0x2e410bfb,
+ 0x8c61d79a, 0x876cde94, 0x9a7bc586, 0x9176cc88,
+ 0xa055f3a2, 0xab58faac, 0xb64fe1be, 0xbd42e8b0,
+ 0xd4099fea, 0xdf0496e4, 0xc2138df6, 0xc91e84f8,
+ 0xf83dbbd2, 0xf330b2dc, 0xee27a9ce, 0xe52aa0c0,
+ 0x3cb1477a, 0x37bc4e74, 0x2aab5566, 0x21a65c68,
+ 0x10856342, 0x1b886a4c, 0x069f715e, 0x0d927850,
+ 0x64d90f0a, 0x6fd40604, 0x72c31d16, 0x79ce1418,
+ 0x48ed2b32, 0x43e0223c, 0x5ef7392e, 0x55fa3020,
+ 0x01b79aec, 0x0aba93e2, 0x17ad88f0, 0x1ca081fe,
+ 0x2d83bed4, 0x268eb7da, 0x3b99acc8, 0x3094a5c6,
+ 0x59dfd29c, 0x52d2db92, 0x4fc5c080, 0x44c8c98e,
+ 0x75ebf6a4, 0x7ee6ffaa, 0x63f1e4b8, 0x68fcedb6,
+ 0xb1670a0c, 0xba6a0302, 0xa77d1810, 0xac70111e,
+ 0x9d532e34, 0x965e273a, 0x8b493c28, 0x80443526,
+ 0xe90f427c, 0xe2024b72, 0xff155060, 0xf418596e,
+ 0xc53b6644, 0xce366f4a, 0xd3217458, 0xd82c7d56,
+ 0x7a0ca137, 0x7101a839, 0x6c16b32b, 0x671bba25,
+ 0x5638850f, 0x5d358c01, 0x40229713, 0x4b2f9e1d,
+ 0x2264e947, 0x2969e049, 0x347efb5b, 0x3f73f255,
+ 0x0e50cd7f, 0x055dc471, 0x184adf63, 0x1347d66d,
+ 0xcadc31d7, 0xc1d138d9, 0xdcc623cb, 0xd7cb2ac5,
+ 0xe6e815ef, 0xede51ce1, 0xf0f207f3, 0xfbff0efd,
+ 0x92b479a7, 0x99b970a9, 0x84ae6bbb, 0x8fa362b5,
+ 0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d,
+ } };
+ union AES_STATE st = { .l = {
+ float64_val(env->vfp.regs[rm]),
+ float64_val(env->vfp.regs[rm + 1])
+ } };
+ int i;
+
+ assert(decrypt < 2);
+
+ for (i = 0; i < 16; i += 4) {
+ st.cols[i >> 2] = cpu_to_le32(
+ mc[decrypt][st.bytes[i]] ^
+ rol32(mc[decrypt][st.bytes[i + 1]], 8) ^
+ rol32(mc[decrypt][st.bytes[i + 2]], 16) ^
+ rol32(mc[decrypt][st.bytes[i + 3]], 24));
+ }
+
+ env->vfp.regs[rd] = make_float64(st.l[0]);
+ env->vfp.regs[rd + 1] = make_float64(st.l[1]);
+}
diff --git a/target-arm/helper.h b/target-arm/helper.h
index d459a39..496eb65 100644
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -463,4 +463,7 @@ DEF_HELPER_3(neon_qzip8, void, env, i32, i32)
DEF_HELPER_3(neon_qzip16, void, env, i32, i32)
DEF_HELPER_3(neon_qzip32, void, env, i32, i32)
+DEF_HELPER_4(crypto_aese, void, env, i32, i32, i32)
+DEF_HELPER_4(crypto_aesmc, void, env, i32, i32, i32)
+
#include "exec/def-helper.h"
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 8c479ff..9131467 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -4592,6 +4592,8 @@ static const uint8_t neon_3r_sizes[] = {
#define NEON_2RM_VREV16 2
#define NEON_2RM_VPADDL 4
#define NEON_2RM_VPADDL_U 5
+#define NEON_2RM_AESE 6 /* Includes AESD */
+#define NEON_2RM_AESMC 7 /* Includes AESIMC */
#define NEON_2RM_VCLS 8
#define NEON_2RM_VCLZ 9
#define NEON_2RM_VCNT 10
@@ -4649,6 +4651,8 @@ static const uint8_t neon_2rm_sizes[] = {
[NEON_2RM_VREV16] = 0x1,
[NEON_2RM_VPADDL] = 0x7,
[NEON_2RM_VPADDL_U] = 0x7,
+ [NEON_2RM_AESE] = 0x1,
+ [NEON_2RM_AESMC] = 0x1,
[NEON_2RM_VCLS] = 0x7,
[NEON_2RM_VCLZ] = 0x7,
[NEON_2RM_VCNT] = 0x1,
@@ -6184,6 +6188,28 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins
tcg_temp_free_i32(tmp2);
tcg_temp_free_i32(tmp3);
break;
+ case NEON_2RM_AESE: case NEON_2RM_AESMC:
+ if (!arm_feature(env, ARM_FEATURE_V8_AES)
+ || ((rm | rd) & 1)) {
+ return 1;
+ }
+ tmp = tcg_const_i32(rd);
+ tmp2 = tcg_const_i32(rm);
+
+ /* Bit 6 is the lowest opcode bit; it distinguishes between
+ * encryption (AESE/AESMC) and decryption (AESD/AESIMC)
+ */
+ tmp3 = tcg_const_i32(extract32(insn, 6, 1));
+
+ if (op == NEON_2RM_AESE) {
+ gen_helper_crypto_aese(cpu_env, tmp, tmp2, tmp3);
+ } else {
+ gen_helper_crypto_aesmc(cpu_env, tmp, tmp2, tmp3);
+ }
+ tcg_temp_free_i32(tmp);
+ tcg_temp_free_i32(tmp2);
+ tcg_temp_free_i32(tmp3);
+ break;
default:
elementwise:
for (pass = 0; pass < (q ? 4 : 2); pass++) {
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 02/62] rename pflash_t member width to bank_width
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 01/62] target-arm: add support for v8 AES instructions Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 03/62] Add device-width property to pflash_cfi01 Peter Maydell
` (60 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Roy Franz <roy.franz@linaro.org>
Rename the 'width' member of the pflash_t structure
in preparation for adding a bank_width member.
Signed-off-by: Roy Franz <roy.franz@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1386279359-32286-2-git-send-email-roy.franz@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/block/pflash_cfi01.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 018a967..a0d7a16 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -71,7 +71,7 @@ struct pflash_t {
BlockDriverState *bs;
uint32_t nb_blocs;
uint64_t sector_len;
- uint8_t width;
+ uint8_t bank_width;
uint8_t be;
uint8_t wcycle; /* if 0, the flash is read normally */
int ro;
@@ -126,10 +126,11 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
ret = -1;
boff = offset & 0xFF; /* why this here ?? */
- if (pfl->width == 2)
+ if (pfl->bank_width == 2) {
boff = boff >> 1;
- else if (pfl->width == 4)
+ } else if (pfl->bank_width == 4) {
boff = boff >> 2;
+ }
#if 0
DPRINTF("%s: reading offset " TARGET_FMT_plx " under cmd %02x width %d\n",
@@ -665,7 +666,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
pfl->cfi_table[0x28] = 0x02;
pfl->cfi_table[0x29] = 0x00;
/* Max number of bytes in multi-bytes write */
- if (pfl->width == 1) {
+ if (pfl->bank_width == 1) {
pfl->cfi_table[0x2A] = 0x08;
} else {
pfl->cfi_table[0x2A] = 0x0B;
@@ -706,7 +707,7 @@ static Property pflash_cfi01_properties[] = {
DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
DEFINE_PROP_UINT64("sector-length", struct pflash_t, sector_len, 0),
- DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
+ DEFINE_PROP_UINT8("width", struct pflash_t, bank_width, 0),
DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
@@ -745,8 +746,8 @@ pflash_t *pflash_cfi01_register(hwaddr base,
DeviceState *qdev, const char *name,
hwaddr size,
BlockDriverState *bs,
- uint32_t sector_len, int nb_blocs, int width,
- uint16_t id0, uint16_t id1,
+ uint32_t sector_len, int nb_blocs,
+ int bank_width, uint16_t id0, uint16_t id1,
uint16_t id2, uint16_t id3, int be)
{
DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH01);
@@ -756,7 +757,7 @@ pflash_t *pflash_cfi01_register(hwaddr base,
}
qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
qdev_prop_set_uint64(dev, "sector-length", sector_len);
- qdev_prop_set_uint8(dev, "width", width);
+ qdev_prop_set_uint8(dev, "width", bank_width);
qdev_prop_set_uint8(dev, "big-endian", !!be);
qdev_prop_set_uint16(dev, "id0", id0);
qdev_prop_set_uint16(dev, "id1", id1);
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 03/62] Add device-width property to pflash_cfi01
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 01/62] target-arm: add support for v8 AES instructions Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 02/62] rename pflash_t member width to bank_width Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 04/62] return status for each NOR flash device Peter Maydell
` (59 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Roy Franz <roy.franz@linaro.org>
The width of the devices that make up the flash interface
is required to mask certain commands, in particular the
write length for buffered writes. This length will be presented
to each device on the interface by the program writing the flash,
and the flash emulation code needs to be able to determine
the length of the write as recieved by each flash device.
The device-width defaults to the bank width which should
maintain existing behavior for platforms that don't need
this change.
This change is required to support buffered writes on the
vexpress platform that has a 32 bit flash interface with 2
16 bit devices on it.
Signed-off-by: Roy Franz <roy.franz@linaro.org>
Message-id: 1386279359-32286-3-git-send-email-roy.franz@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/block/pflash_cfi01.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index a0d7a16..a458ad6 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -40,6 +40,7 @@
#include "hw/block/flash.h"
#include "block/block.h"
#include "qemu/timer.h"
+#include "qemu/bitops.h"
#include "exec/address-spaces.h"
#include "qemu/host-utils.h"
#include "hw/sysbus.h"
@@ -72,6 +73,7 @@ struct pflash_t {
uint32_t nb_blocs;
uint64_t sector_len;
uint8_t bank_width;
+ uint8_t device_width; /* If 0, device width not specified. */
uint8_t be;
uint8_t wcycle; /* if 0, the flash is read normally */
int ro;
@@ -379,6 +381,14 @@ static void pflash_write(pflash_t *pfl, hwaddr offset,
break;
case 0xe8:
+ /* Mask writeblock size based on device width, or bank width if
+ * device width not specified.
+ */
+ if (pfl->device_width) {
+ value = extract32(value, 0, pfl->device_width * 8);
+ } else {
+ value = extract32(value, 0, pfl->bank_width * 8);
+ }
DPRINTF("%s: block write of %x bytes\n", __func__, value);
pfl->counter = value;
pfl->wcycle++;
@@ -708,6 +718,7 @@ static Property pflash_cfi01_properties[] = {
DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
DEFINE_PROP_UINT64("sector-length", struct pflash_t, sector_len, 0),
DEFINE_PROP_UINT8("width", struct pflash_t, bank_width, 0),
+ DEFINE_PROP_UINT8("device-width", struct pflash_t, device_width, 0),
DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 04/62] return status for each NOR flash device
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (2 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 03/62] Add device-width property to pflash_cfi01 Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 05/62] Set proper device-width for vexpress flash Peter Maydell
` (58 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Roy Franz <roy.franz@linaro.org>
Now that we know how wide each flash device that makes up the bank is,
return status for each device in the bank. Leave existing code
that treats 32 bit wide banks as composed of two 16 bit devices as otherwise
we may break configurations that do not set the device_width propery.
Signed-off-by: Roy Franz <roy.franz@linaro.org>
Message-id: 1386279359-32286-4-git-send-email-roy.franz@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/block/pflash_cfi01.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index a458ad6..82a2519 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -193,9 +193,20 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
case 0x60: /* Block /un)lock */
case 0x70: /* Status Register */
case 0xe8: /* Write block */
- /* Status register read */
+ /* Status register read. Return status from each device in
+ * bank.
+ */
ret = pfl->status;
- if (width > 2) {
+ if (pfl->device_width && width > pfl->device_width) {
+ int shift = pfl->device_width * 8;
+ while (shift + pfl->device_width * 8 <= width * 8) {
+ ret |= pfl->status << shift;
+ shift += pfl->device_width * 8;
+ }
+ } else if (!pfl->device_width && width > 2) {
+ /* Handle 32 bit flash cases where device width is not
+ * set. (Existing behavior before device width added.)
+ */
ret |= pfl->status << 16;
}
DPRINTF("%s: status %x\n", __func__, ret);
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 05/62] Set proper device-width for vexpress flash
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (3 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 04/62] return status for each NOR flash device Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 06/62] Add max device width parameter for NOR devices Peter Maydell
` (57 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Roy Franz <roy.franz@linaro.org>
Create vexpress specific pflash registration
function which properly configures the device-width
of 16 bits (2 bytes) for the NOR flash on the
vexpress platform. This change is required for
buffered flash writes to work properly.
Signed-off-by: Roy Franz <roy.franz@linaro.org>
Message-id: 1386279359-32286-5-git-send-email-roy.franz@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/vexpress.c | 44 ++++++++++++++++++++++++++++++++++----------
1 file changed, 34 insertions(+), 10 deletions(-)
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index f48de00..939b468 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -480,6 +480,36 @@ static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt)
}
}
+
+/* Open code a private version of pflash registration since we
+ * need to set non-default device width for VExpress platform.
+ */
+static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
+ DriveInfo *di)
+{
+ DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
+
+ if (di && qdev_prop_set_drive(dev, "drive", di->bdrv)) {
+ abort();
+ }
+
+ qdev_prop_set_uint32(dev, "num-blocks",
+ VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE);
+ qdev_prop_set_uint64(dev, "sector-length", VEXPRESS_FLASH_SECT_SIZE);
+ qdev_prop_set_uint8(dev, "width", 4);
+ qdev_prop_set_uint8(dev, "device-width", 2);
+ qdev_prop_set_uint8(dev, "big-endian", 0);
+ qdev_prop_set_uint16(dev, "id0", 0x00);
+ qdev_prop_set_uint16(dev, "id1", 0x89);
+ qdev_prop_set_uint16(dev, "id2", 0x00);
+ qdev_prop_set_uint16(dev, "id3", 0x18);
+ qdev_prop_set_string(dev, "name", name);
+ qdev_init_nofail(dev);
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+ return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01");
+}
+
static void vexpress_common_init(VEDBoardInfo *daughterboard,
QEMUMachineInitArgs *args)
{
@@ -561,11 +591,8 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
sysbus_create_simple("pl111", map[VE_CLCD], pic[14]);
dinfo = drive_get_next(IF_PFLASH);
- pflash0 = pflash_cfi01_register(map[VE_NORFLASH0], NULL, "vexpress.flash0",
- VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
- VEXPRESS_FLASH_SECT_SIZE,
- VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE, 4,
- 0x00, 0x89, 0x00, 0x18, 0);
+ pflash0 = ve_pflash_cfi01_register(map[VE_NORFLASH0], "vexpress.flash0",
+ dinfo);
if (!pflash0) {
fprintf(stderr, "vexpress: error registering flash 0.\n");
exit(1);
@@ -580,11 +607,8 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
}
dinfo = drive_get_next(IF_PFLASH);
- if (!pflash_cfi01_register(map[VE_NORFLASH1], NULL, "vexpress.flash1",
- VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
- VEXPRESS_FLASH_SECT_SIZE,
- VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE, 4,
- 0x00, 0x89, 0x00, 0x18, 0)) {
+ if (!ve_pflash_cfi01_register(map[VE_NORFLASH1], "vexpress.flash1",
+ dinfo)) {
fprintf(stderr, "vexpress: error registering flash 1.\n");
exit(1);
}
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 06/62] Add max device width parameter for NOR devices
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (4 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 05/62] Set proper device-width for vexpress flash Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 07/62] Fix CFI query responses for NOR flash Peter Maydell
` (56 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Roy Franz <roy.franz@linaro.org>
For handling CFI and device ID reads, we need to not only know the
width that a NOR flash device is configured for, but also its maximum
width. The maximum width addressing mode is used for multi-width
parts no matter which width they are configured for. The most common
case is x16 parts that also support x8 mode. When configured for x8
operation these devices respond to CFI and device ID requests differently
than native x8 NOR parts.
Signed-off-by: Roy Franz <roy.franz@linaro.org>
Message-id: 1386279359-32286-6-git-send-email-roy.franz@linaro.org
[PMM: Added comment explaining the semantics of width vs device-width
vs max-device-width]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/block/pflash_cfi01.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 82a2519..de7a6c0 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -74,6 +74,7 @@ struct pflash_t {
uint64_t sector_len;
uint8_t bank_width;
uint8_t device_width; /* If 0, device width not specified. */
+ uint8_t max_device_width; /* max device width in bytes */
uint8_t be;
uint8_t wcycle; /* if 0, the flash is read normally */
int ro;
@@ -635,6 +636,13 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
pfl->ro = 0;
}
+ /* Default to devices being used at their maximum device width. This was
+ * assumed before the device_width support was added.
+ */
+ if (!pfl->max_device_width) {
+ pfl->max_device_width = pfl->device_width;
+ }
+
pfl->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl);
pfl->wcycle = 0;
pfl->cmd = 0;
@@ -728,8 +736,25 @@ static Property pflash_cfi01_properties[] = {
DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
DEFINE_PROP_UINT64("sector-length", struct pflash_t, sector_len, 0),
+ /* width here is the overall width of this QEMU device in bytes.
+ * The QEMU device may be emulating a number of flash devices
+ * wired up in parallel; the width of each individual flash
+ * device should be specified via device-width. If the individual
+ * devices have a maximum width which is greater than the width
+ * they are being used for, this maximum width should be set via
+ * max-device-width (which otherwise defaults to device-width).
+ * So for instance a 32-bit wide QEMU flash device made from four
+ * 16-bit flash devices used in 8-bit wide mode would be configured
+ * with width = 4, device-width = 1, max-device-width = 2.
+ *
+ * If device-width is not specified we default to backwards
+ * compatible behaviour which is a bad emulation of two
+ * 16 bit devices making up a 32 bit wide QEMU device. This
+ * is deprecated for new uses of this device.
+ */
DEFINE_PROP_UINT8("width", struct pflash_t, bank_width, 0),
DEFINE_PROP_UINT8("device-width", struct pflash_t, device_width, 0),
+ DEFINE_PROP_UINT8("max-device-width", struct pflash_t, max_device_width, 0),
DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 07/62] Fix CFI query responses for NOR flash
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (5 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 06/62] Add max device width parameter for NOR devices Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 08/62] Fix NOR flash device ID reading Peter Maydell
` (55 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Roy Franz <roy.franz@linaro.org>
This change fixes the CFI query responses to handle NOR device
widths that are different from the bank width. Support is also
added for multi-width devices in a x8 configuration. This is
typically x8/x16 devices, but the CFI specification mentions
x8/x32 devices so those should be supported as well if they
exist.
The query response data is now replicated per-device in the bank,
and is adjusted for x16 or x32 parts configured in x8 mode.
The existing code is left in place for boards that have not
been updated to specify an explicit device_width. The VExpress
board has been updated in an earlier patch in this series so
this is the only board currently affected.
Signed-off-by: Roy Franz <roy.franz@linaro.org>
Message-id: 1386279359-32286-7-git-send-email-roy.franz@linaro.org
[PMM: fixed a few formatting nits]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/block/pflash_cfi01.c | 105 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 94 insertions(+), 11 deletions(-)
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index de7a6c0..8fd50fb 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -119,6 +119,67 @@ static void pflash_timer (void *opaque)
pfl->cmd = 0;
}
+/* Perform a CFI query based on the bank width of the flash.
+ * If this code is called we know we have a device_width set for
+ * this flash.
+ */
+static uint32_t pflash_cfi_query(pflash_t *pfl, hwaddr offset)
+{
+ int i;
+ uint32_t resp = 0;
+ hwaddr boff;
+
+ /* Adjust incoming offset to match expected device-width
+ * addressing. CFI query addresses are always specified in terms of
+ * the maximum supported width of the device. This means that x8
+ * devices and x8/x16 devices in x8 mode behave differently. For
+ * devices that are not used at their max width, we will be
+ * provided with addresses that use higher address bits than
+ * expected (based on the max width), so we will shift them lower
+ * so that they will match the addresses used when
+ * device_width==max_device_width.
+ */
+ boff = offset >> (ctz32(pfl->bank_width) +
+ ctz32(pfl->max_device_width) - ctz32(pfl->device_width));
+
+ if (boff > pfl->cfi_len) {
+ return 0;
+ }
+ /* Now we will construct the CFI response generated by a single
+ * device, then replicate that for all devices that make up the
+ * bus. For wide parts used in x8 mode, CFI query responses
+ * are different than native byte-wide parts.
+ */
+ resp = pfl->cfi_table[boff];
+ if (pfl->device_width != pfl->max_device_width) {
+ /* The only case currently supported is x8 mode for a
+ * wider part.
+ */
+ if (pfl->device_width != 1 || pfl->bank_width > 4) {
+ DPRINTF("%s: Unsupported device configuration: "
+ "device_width=%d, max_device_width=%d\n",
+ __func__, pfl->device_width,
+ pfl->max_device_width);
+ return 0;
+ }
+ /* CFI query data is repeated, rather than zero padded for
+ * wide devices used in x8 mode.
+ */
+ for (i = 1; i < pfl->max_device_width; i++) {
+ resp = deposit32(resp, 8 * i, 8, pfl->cfi_table[boff]);
+ }
+ }
+ /* Replicate responses for each device in bank. */
+ if (pfl->device_width < pfl->bank_width) {
+ for (i = pfl->device_width;
+ i < pfl->bank_width; i += pfl->device_width) {
+ resp = deposit32(resp, 8 * i, 8 * pfl->device_width, resp);
+ }
+ }
+
+ return resp;
+}
+
static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
int width, int be)
{
@@ -127,13 +188,6 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
uint8_t *p;
ret = -1;
- boff = offset & 0xFF; /* why this here ?? */
-
- if (pfl->bank_width == 2) {
- boff = boff >> 1;
- } else if (pfl->bank_width == 4) {
- boff = boff >> 2;
- }
#if 0
DPRINTF("%s: reading offset " TARGET_FMT_plx " under cmd %02x width %d\n",
@@ -213,6 +267,13 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
DPRINTF("%s: status %x\n", __func__, ret);
break;
case 0x90:
+ boff = offset & 0xFF;
+ if (pfl->bank_width == 2) {
+ boff = boff >> 1;
+ } else if (pfl->bank_width == 4) {
+ boff = boff >> 2;
+ }
+
switch (boff) {
case 0:
ret = pfl->ident0 << 8 | pfl->ident1;
@@ -230,10 +291,32 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
}
break;
case 0x98: /* Query mode */
- if (boff > pfl->cfi_len)
- ret = 0;
- else
- ret = pfl->cfi_table[boff];
+ if (!pfl->device_width) {
+ /* Preserve old behavior if device width not specified */
+ boff = offset & 0xFF;
+ if (pfl->bank_width == 2) {
+ boff = boff >> 1;
+ } else if (pfl->bank_width == 4) {
+ boff = boff >> 2;
+ }
+
+ if (boff > pfl->cfi_len) {
+ ret = 0;
+ } else {
+ ret = pfl->cfi_table[boff];
+ }
+ } else {
+ /* If we have a read larger than the bank_width, combine multiple
+ * CFI queries into a single response.
+ */
+ int i;
+ for (i = 0; i < width; i += pfl->bank_width) {
+ ret = deposit32(ret, i * 8, pfl->bank_width * 8,
+ pflash_cfi_query(pfl,
+ offset + i * pfl->bank_width));
+ }
+ }
+
break;
}
return ret;
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 08/62] Fix NOR flash device ID reading
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (6 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 07/62] Fix CFI query responses for NOR flash Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 09/62] target-arm/helper.c: Allow cp15.c15 dummy override Peter Maydell
` (54 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Roy Franz <roy.franz@linaro.org>
Fix NOR flash manufacturer and device ID reading. This now
properly takes into account device widths and device max widths
as required. The reading of these IDs uses the same max_width
dependent addressing as CFI queries.
The old code remains for chips that don't specify a device width,
as the new code relies on a device width being set in order to
properly operate. The existing code seems very broken.
Only ident0 and ident1 are used in the new code, as other fields
relate to the lock state of blocks in flash.
The VExpress flash configuration has been updated to match
the new code, as the existing definition was 'wrong' in order
to return the expected results with the broken device ID code.
Signed-off-by: Roy Franz <roy.franz@linaro.org>
Message-id: 1386279359-32286-8-git-send-email-roy.franz@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/vexpress.c | 6 +--
hw/block/pflash_cfi01.c | 105 +++++++++++++++++++++++++++++++++++++++---------
2 files changed, 88 insertions(+), 23 deletions(-)
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index 939b468..aaa863e 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -499,10 +499,10 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
qdev_prop_set_uint8(dev, "width", 4);
qdev_prop_set_uint8(dev, "device-width", 2);
qdev_prop_set_uint8(dev, "big-endian", 0);
- qdev_prop_set_uint16(dev, "id0", 0x00);
- qdev_prop_set_uint16(dev, "id1", 0x89);
+ qdev_prop_set_uint16(dev, "id0", 0x89);
+ qdev_prop_set_uint16(dev, "id1", 0x18);
qdev_prop_set_uint16(dev, "id2", 0x00);
- qdev_prop_set_uint16(dev, "id3", 0x18);
+ qdev_prop_set_uint16(dev, "id3", 0x00);
qdev_prop_set_string(dev, "name", name);
qdev_init_nofail(dev);
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 8fd50fb..0c95d53 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -180,6 +180,58 @@ static uint32_t pflash_cfi_query(pflash_t *pfl, hwaddr offset)
return resp;
}
+
+
+/* Perform a device id query based on the bank width of the flash. */
+static uint32_t pflash_devid_query(pflash_t *pfl, hwaddr offset)
+{
+ int i;
+ uint32_t resp;
+ hwaddr boff;
+
+ /* Adjust incoming offset to match expected device-width
+ * addressing. Device ID read addresses are always specified in
+ * terms of the maximum supported width of the device. This means
+ * that x8 devices and x8/x16 devices in x8 mode behave
+ * differently. For devices that are not used at their max width,
+ * we will be provided with addresses that use higher address bits
+ * than expected (based on the max width), so we will shift them
+ * lower so that they will match the addresses used when
+ * device_width==max_device_width.
+ */
+ boff = offset >> (ctz32(pfl->bank_width) +
+ ctz32(pfl->max_device_width) - ctz32(pfl->device_width));
+
+ /* Mask off upper bits which may be used in to query block
+ * or sector lock status at other addresses.
+ * Offsets 2/3 are block lock status, is not emulated.
+ */
+ switch (boff & 0xFF) {
+ case 0:
+ resp = pfl->ident0;
+ DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret);
+ break;
+ case 1:
+ resp = pfl->ident1;
+ DPRINTF("%s: Device ID Code %04x\n", __func__, ret);
+ break;
+ default:
+ DPRINTF("%s: Read Device Information offset=%x\n", __func__,
+ (unsigned)offset);
+ return 0;
+ break;
+ }
+ /* Replicate responses for each device in bank. */
+ if (pfl->device_width < pfl->bank_width) {
+ for (i = pfl->device_width;
+ i < pfl->bank_width; i += pfl->device_width) {
+ resp = deposit32(resp, 8 * i, 8 * pfl->device_width, resp);
+ }
+ }
+
+ return resp;
+}
+
static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
int width, int be)
{
@@ -267,27 +319,40 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
DPRINTF("%s: status %x\n", __func__, ret);
break;
case 0x90:
- boff = offset & 0xFF;
- if (pfl->bank_width == 2) {
- boff = boff >> 1;
- } else if (pfl->bank_width == 4) {
- boff = boff >> 2;
- }
+ if (!pfl->device_width) {
+ /* Preserve old behavior if device width not specified */
+ boff = offset & 0xFF;
+ if (pfl->bank_width == 2) {
+ boff = boff >> 1;
+ } else if (pfl->bank_width == 4) {
+ boff = boff >> 2;
+ }
- switch (boff) {
- case 0:
- ret = pfl->ident0 << 8 | pfl->ident1;
- DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret);
- break;
- case 1:
- ret = pfl->ident2 << 8 | pfl->ident3;
- DPRINTF("%s: Device ID Code %04x\n", __func__, ret);
- break;
- default:
- DPRINTF("%s: Read Device Information boff=%x\n", __func__,
- (unsigned)boff);
- ret = 0;
- break;
+ switch (boff) {
+ case 0:
+ ret = pfl->ident0 << 8 | pfl->ident1;
+ DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret);
+ break;
+ case 1:
+ ret = pfl->ident2 << 8 | pfl->ident3;
+ DPRINTF("%s: Device ID Code %04x\n", __func__, ret);
+ break;
+ default:
+ DPRINTF("%s: Read Device Information boff=%x\n", __func__,
+ (unsigned)boff);
+ ret = 0;
+ break;
+ }
+ } else {
+ /* If we have a read larger than the bank_width, combine multiple
+ * manufacturer/device ID queries into a single response.
+ */
+ int i;
+ for (i = 0; i < width; i += pfl->bank_width) {
+ ret = deposit32(ret, i * 8, pfl->bank_width * 8,
+ pflash_devid_query(pfl,
+ offset + i * pfl->bank_width));
+ }
}
break;
case 0x98: /* Query mode */
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 09/62] target-arm/helper.c: Allow cp15.c15 dummy override
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (7 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 08/62] Fix NOR flash device ID reading Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 10/62] target-arm: Define and use ARM_FEATURE_CBAR Peter Maydell
` (53 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
The cp15.c15 space is implementation defined. Currently there is a
dummy placeholder register RAZing it. Allow overriding of this RAZ
so implementations of specific registers can take precedence.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: ed1bacec56dae00cb398c798f8240e8e685f949c.1387160489.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/helper.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 5e5e5aa..71d6be3 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1338,7 +1338,8 @@ static const ARMCPRegInfo dummy_c15_cp_reginfo[] = {
*/
{ .name = "C15_IMPDEF", .cp = 15, .crn = 15,
.crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY,
- .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_NO_MIGRATE,
+ .access = PL1_RW,
+ .type = ARM_CP_CONST | ARM_CP_NO_MIGRATE | ARM_CP_OVERRIDE,
.resetvalue = 0 },
REGINFO_SENTINEL
};
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 10/62] target-arm: Define and use ARM_FEATURE_CBAR
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (8 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 09/62] target-arm/helper.c: Allow cp15.c15 dummy override Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 11/62] target-arm/cpu: Convert reset CBAR to a property Peter Maydell
` (52 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Some processors (notably A9 within Highbank) define and use the
CP15 configuration base address (CBAR). This is vendor specific
so its best implemented as a CPU property (otherwise we would need
vendor specific child classes for every ARM implementation).
This patch prepares support for converting CBAR reset value to
a CPU property by moving the CP registration out of the CPU
init fn, as registration will need to happen at realize time
to pick up any property updates. The easiest way to do this
is via definition of a new ARM_FEATURE to flag the existence
of the register.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 9f697ef1e2ee60a3b9ef971a7f3bc3fa6752a9b7.1387160489.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/cpu.c | 12 +++---------
target-arm/cpu.h | 1 +
target-arm/helper.c | 9 +++++++++
3 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index a03743f..f21e995 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -617,6 +617,7 @@ static void cortex_a9_initfn(Object *obj)
* and valid configurations; we don't model A9UP).
*/
set_feature(&cpu->env, ARM_FEATURE_V7MP);
+ set_feature(&cpu->env, ARM_FEATURE_CBAR);
cpu->midr = 0x410fc090;
cpu->reset_fpsid = 0x41033090;
cpu->mvfr0 = 0x11110222;
@@ -639,15 +640,7 @@ static void cortex_a9_initfn(Object *obj)
cpu->clidr = (1 << 27) | (1 << 24) | 3;
cpu->ccsidr[0] = 0xe00fe015; /* 16k L1 dcache. */
cpu->ccsidr[1] = 0x200fe015; /* 16k L1 icache. */
- {
- ARMCPRegInfo cbar = {
- .name = "CBAR", .cp = 15, .crn = 15, .crm = 0, .opc1 = 4,
- .opc2 = 0, .access = PL1_R|PL3_W, .resetvalue = cpu->reset_cbar,
- .fieldoffset = offsetof(CPUARMState, cp15.c15_config_base_address)
- };
- define_one_arm_cp_reg(cpu, &cbar);
- define_arm_cp_regs(cpu, cortexa9_cp_reginfo);
- }
+ define_arm_cp_regs(cpu, cortexa9_cp_reginfo);
}
#ifndef CONFIG_USER_ONLY
@@ -686,6 +679,7 @@ static void cortex_a15_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
+ set_feature(&cpu->env, ARM_FEATURE_CBAR);
set_feature(&cpu->env, ARM_FEATURE_LPAE);
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15;
cpu->midr = 0x412fc0f1;
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 00fd80d..c6c19e9 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -468,6 +468,7 @@ enum arm_features {
ARM_FEATURE_V8,
ARM_FEATURE_AARCH64, /* supports 64 bit mode */
ARM_FEATURE_V8_AES, /* implements AES part of v8 Crypto Extensions */
+ ARM_FEATURE_CBAR, /* has cp15 CBAR */
};
static inline int arm_feature(CPUARMState *env, int feature)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 71d6be3..cfbb14c 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1745,6 +1745,15 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_one_arm_cp_reg(cpu, &auxcr);
}
+ if (arm_feature(env, ARM_FEATURE_CBAR)) {
+ ARMCPRegInfo cbar = {
+ .name = "CBAR", .cp = 15, .crn = 15, .crm = 0, .opc1 = 4, .opc2 = 0,
+ .access = PL1_R|PL3_W, .resetvalue = cpu->reset_cbar,
+ .fieldoffset = offsetof(CPUARMState, cp15.c15_config_base_address)
+ };
+ define_one_arm_cp_reg(cpu, &cbar);
+ }
+
/* Generic registers whose values depend on the implementation */
{
ARMCPRegInfo sctlr = {
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 11/62] target-arm/cpu: Convert reset CBAR to a property
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (9 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 10/62] target-arm: Define and use ARM_FEATURE_CBAR Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 12/62] arm/highbank: Use object_new() rather than cpu_arm_init() Peter Maydell
` (51 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
The reset value of the CP15 CBAR is a vendor (machine) configurable
property. If ARM_FEATURE_CBAR is set, add it as a property at
post_init time.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: 2f1eec3f912135deea6252360e03645003d12e0a.1387160489.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/cpu.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index f21e995..fd04b36 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -21,6 +21,7 @@
#include "cpu.h"
#include "qemu-common.h"
#include "hw/qdev-properties.h"
+#include "qapi/qmp/qerror.h"
#if !defined(CONFIG_USER_ONLY)
#include "hw/loader.h"
#endif
@@ -231,6 +232,21 @@ static void arm_cpu_initfn(Object *obj)
}
}
+static Property arm_cpu_reset_cbar_property =
+ DEFINE_PROP_UINT32("reset-cbar", ARMCPU, reset_cbar, 0);
+
+static void arm_cpu_post_init(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ Error *err = NULL;
+
+ if (arm_feature(&cpu->env, ARM_FEATURE_CBAR)) {
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_cbar_property,
+ &err);
+ assert_no_error(err);
+ }
+}
+
static void arm_cpu_finalizefn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -994,6 +1010,7 @@ static const TypeInfo arm_cpu_type_info = {
.parent = TYPE_CPU,
.instance_size = sizeof(ARMCPU),
.instance_init = arm_cpu_initfn,
+ .instance_post_init = arm_cpu_post_init,
.instance_finalize = arm_cpu_finalizefn,
.abstract = true,
.class_size = sizeof(ARMCPUClass),
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 12/62] arm/highbank: Use object_new() rather than cpu_arm_init()
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (10 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 11/62] target-arm/cpu: Convert reset CBAR to a property Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 13/62] arm/highbank: Fix CBAR initialisation Peter Maydell
` (50 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
To allow the machine model to set device properties before CPU
realization.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 8c671e500390c8be0cc363e887e32867d1d1b0d2.1387160489.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/highbank.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index fe98ef1..1d19d8f 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -26,6 +26,7 @@
#include "hw/boards.h"
#include "sysemu/blockdev.h"
#include "exec/address-spaces.h"
+#include "qemu/error-report.h"
#define SMP_BOOT_ADDR 0x100
#define SMP_BOOT_REG 0x40
@@ -229,10 +230,15 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
}
for (n = 0; n < smp_cpus; n++) {
+ ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
ARMCPU *cpu;
- cpu = cpu_arm_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
+ Error *err = NULL;
+
+ cpu = ARM_CPU(object_new(object_class_get_name(oc)));
+
+ object_property_set_bool(OBJECT(cpu), true, "realized", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
exit(1);
}
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 13/62] arm/highbank: Fix CBAR initialisation
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (11 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 12/62] arm/highbank: Use object_new() rather than cpu_arm_init() Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 14/62] arm/xilinx_zynq: Use object_new() rather than cpu_arm_init() Peter Maydell
` (49 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Fix the CBAR initialisation by using the newly defined static property.
CBAR is now set before realization, so the intended value is now
actually used.
So I have kind of tested this. I booted an ARM kernel on Highbank with
the stock Highbank DTB. It doesn't boot (and I will be doing something
wrong), but before this patch I got this:
------------[ cut here ]------------
WARNING: CPU: 0 PID: 0 at /workspaces/pcrost/public/linux2.git/arch/arm/mm/ioremap.c:301 __arm_ioremap_pfn_caller+0x180/0x198()
CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 3.13.0-rc1-next-20131126-dirty #2
[<c0015164>] (unwind_backtrace) from [<c00118c0>] (show_stack+0x10/0x14)
[<c00118c0>] (show_stack) from [<c02bd5fc>] (dump_stack+0x78/0x90)
[<c02bd5fc>] (dump_stack) from [<c001f110>] (warn_slowpath_common+0x68/0x84)
[<c001f110>] (warn_slowpath_common) from [<c001f1f4>] (warn_slowpath_null+0x1c/0x24)
[<c001f1f4>] (warn_slowpath_null) from [<c0017c6c>] (__arm_ioremap_pfn_caller+0x180/0x198)
[<c0017c6c>] (__arm_ioremap_pfn_caller) from [<c0017cd8>] (__arm_ioremap_caller+0x54/0x5c)
[<c0017cd8>] (__arm_ioremap_caller) from [<c0017d10>] (__arm_ioremap+0x18/0x1c)
[<c0017d10>] (__arm_ioremap) from [<c03913c0>] (highbank_init_irq+0x34/0x8c)
[<c03913c0>] (highbank_init_irq) from [<c038c228>] (init_IRQ+0x28/0x2c)
[<c038c228>] (init_IRQ) from [<c03899ec>] (start_kernel+0x234/0x398)
[<c03899ec>] (start_kernel) from [<00008074>] (0x8074)
---[ end trace 3406ff24bd97382f ]---
Which disappears with this patch.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: fedec366aaa512d75093635f523d1dbcb3358361.1387160489.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/highbank.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index 1d19d8f..cb32325 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -236,14 +236,16 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
cpu = ARM_CPU(object_new(object_class_get_name(oc)));
+ object_property_set_int(OBJECT(cpu), GIC_BASE_ADDR, "reset-cbar", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
object_property_set_bool(OBJECT(cpu), true, "realized", &err);
if (err) {
error_report("%s", error_get_pretty(err));
exit(1);
}
-
- /* This will become a QOM property eventually */
- cpu->reset_cbar = GIC_BASE_ADDR;
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
}
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 14/62] arm/xilinx_zynq: Use object_new() rather than cpu_arm_init()
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (12 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 13/62] arm/highbank: Fix CBAR initialisation Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 15/62] arm/xilinx_zynq: Implement CBAR initialisation Peter Maydell
` (48 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
To allow the machine model to set device properties before CPU
realization.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: e57658b4506b26ab6b6fadbe6d7827f669f51895.1387160489.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/xilinx_zynq.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 46924a0..1c954a3 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -25,6 +25,7 @@
#include "sysemu/blockdev.h"
#include "hw/loader.h"
#include "hw/ssi.h"
+#include "qemu/error-report.h"
#define NUM_SPI_FLASHES 4
#define NUM_QSPI_FLASHES 2
@@ -102,6 +103,7 @@ static void zynq_init(QEMUMachineInitArgs *args)
const char *kernel_filename = args->kernel_filename;
const char *kernel_cmdline = args->kernel_cmdline;
const char *initrd_filename = args->initrd_filename;
+ ObjectClass *cpu_oc;
ARMCPU *cpu;
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *ext_ram = g_new(MemoryRegion, 1);
@@ -110,15 +112,19 @@ static void zynq_init(QEMUMachineInitArgs *args)
SysBusDevice *busdev;
qemu_irq pic[64];
NICInfo *nd;
+ Error *err = NULL;
int n;
if (!cpu_model) {
cpu_model = "cortex-a9";
}
+ cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
- cpu = cpu_arm_init(cpu_model);
- if (!cpu) {
- fprintf(stderr, "Unable to find CPU definition\n");
+ cpu = ARM_CPU(object_new(object_class_get_name(cpu_oc)));
+
+ object_property_set_bool(OBJECT(cpu), true, "realized", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
exit(1);
}
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 15/62] arm/xilinx_zynq: Implement CBAR initialisation
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (13 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 14/62] arm/xilinx_zynq: Use object_new() rather than cpu_arm_init() Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 16/62] arm/highbank.c: Fix MPCore periphbase name Peter Maydell
` (47 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Fix the CBAR initialisation by using the newly defined static property.
Zynq will now correctly init the CBAR to the SCU base address.
Needed to boot Linux on the xilinx_zynq machine model.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 8db7d57ebe5418fed397fcc86ea719f98446c178.1387160489.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/xilinx_zynq.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 1c954a3..17251c7 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -36,6 +36,8 @@
#define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
+#define MPCORE_PERIPHBASE 0xF8F00000
+
static const int dma_irqs[8] = {
46, 47, 48, 49, 72, 73, 74, 75
};
@@ -122,6 +124,11 @@ static void zynq_init(QEMUMachineInitArgs *args)
cpu = ARM_CPU(object_new(object_class_get_name(cpu_oc)));
+ object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar", &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
object_property_set_bool(OBJECT(cpu), true, "realized", &err);
if (err) {
error_report("%s", error_get_pretty(err));
@@ -160,7 +167,7 @@ static void zynq_init(QEMUMachineInitArgs *args)
qdev_prop_set_uint32(dev, "num-cpu", 1);
qdev_init_nofail(dev);
busdev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(busdev, 0, 0xF8F00000);
+ sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE);
sysbus_connect_irq(busdev, 0,
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 16/62] arm/highbank.c: Fix MPCore periphbase name
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (14 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 15/62] arm/xilinx_zynq: Implement CBAR initialisation Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 17/62] ARM: cpu: add "reset_hivecs" property Peter Maydell
` (46 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
GIC_BASE_ADDR is not the base address of the GIC. Its clear from the
code that this is the base address of the MPCore. Rename to
MPCORE_PERIPHBASE accordingly.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 90798bd3507205c16238b8b19a1a58c5437cf7ca.1387160489.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/highbank.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index cb32325..c75b425 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -28,11 +28,11 @@
#include "exec/address-spaces.h"
#include "qemu/error-report.h"
-#define SMP_BOOT_ADDR 0x100
-#define SMP_BOOT_REG 0x40
-#define GIC_BASE_ADDR 0xfff10000
+#define SMP_BOOT_ADDR 0x100
+#define SMP_BOOT_REG 0x40
+#define MPCORE_PERIPHBASE 0xfff10000
-#define NIRQ_GIC 160
+#define NIRQ_GIC 160
/* Board init. */
@@ -55,7 +55,7 @@ static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
0xe1110001, /* tst r1, r1 */
0x0afffffb, /* beq <wfi> */
0xe12fff11, /* bx r1 */
- GIC_BASE_ADDR /* privbase: gic address. */
+ MPCORE_PERIPHBASE /* privbase: MPCore peripheral base address. */
};
for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
smpboot[n] = tswap32(smpboot[n]);
@@ -236,7 +236,8 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
cpu = ARM_CPU(object_new(object_class_get_name(oc)));
- object_property_set_int(OBJECT(cpu), GIC_BASE_ADDR, "reset-cbar", &err);
+ object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar",
+ &err);
if (err) {
error_report("%s", error_get_pretty(err));
exit(1);
@@ -287,7 +288,7 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC);
qdev_init_nofail(dev);
busdev = SYS_BUS_DEVICE(dev);
- sysbus_mmio_map(busdev, 0, GIC_BASE_ADDR);
+ sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE);
for (n = 0; n < smp_cpus; n++) {
sysbus_connect_irq(busdev, n, cpu_irq[n]);
}
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 17/62] ARM: cpu: add "reset_hivecs" property
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (15 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 16/62] arm/highbank.c: Fix MPCore periphbase name Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 18/62] ARM: arm_cpu_reset: make it possible to use high vectors for reset_exc Peter Maydell
` (45 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Antony Pavlov <antonynpavlov@gmail.com>
Add an ARM CPU property for the reset value of hivecs as it is a
board/SoC configurable setting.
The existence of the property is conditional on the ARM CPU not being M
class.
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: b04216c6bda4bd163f44a55bba552d0e8267481f.1387160489.git.peter.crosthwaite@xilinx.com
[ PC Changes:
* Elaborated commit message
* refactored to use qdev_property_add_static
]
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/cpu-qom.h | 1 +
target-arm/cpu.c | 13 +++++++++++++
2 files changed, 14 insertions(+)
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index f32178a..afbd422 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -139,6 +139,7 @@ typedef struct ARMCPU {
uint32_t ccsidr[16];
uint32_t reset_cbar;
uint32_t reset_auxcr;
+ bool reset_hivecs;
} ARMCPU;
#define TYPE_AARCH64_CPU "aarch64-cpu"
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index fd04b36..3bce1d6 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -235,6 +235,9 @@ static void arm_cpu_initfn(Object *obj)
static Property arm_cpu_reset_cbar_property =
DEFINE_PROP_UINT32("reset-cbar", ARMCPU, reset_cbar, 0);
+static Property arm_cpu_reset_hivecs_property =
+ DEFINE_PROP_BOOL("reset-hivecs", ARMCPU, reset_hivecs, false);
+
static void arm_cpu_post_init(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -245,6 +248,12 @@ static void arm_cpu_post_init(Object *obj)
&err);
assert_no_error(err);
}
+
+ if (!arm_feature(&cpu->env, ARM_FEATURE_M)) {
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_hivecs_property,
+ &err);
+ assert_no_error(err);
+ }
}
static void arm_cpu_finalizefn(Object *obj)
@@ -307,6 +316,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
set_feature(env, ARM_FEATURE_PXN);
}
+ if (cpu->reset_hivecs) {
+ cpu->reset_sctlr |= (1 << 13);
+ }
+
register_cp_regs_for_features(cpu);
arm_cpu_register_gdb_regs_for_features(cpu);
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 18/62] ARM: arm_cpu_reset: make it possible to use high vectors for reset_exc
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (16 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 17/62] ARM: cpu: add "reset_hivecs" property Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 19/62] target-arm/kvm: Split 32 bit only code into its own file Peter Maydell
` (44 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Antony Pavlov <antonynpavlov@gmail.com>
If hivecs are being used on reset, the CPU should come out of reset at
the hivecs reset vector (0xFFFF0000)
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: 3afc69c4f58f60aa2bbee7b91574a4eb414b1c23.1387160489.git.peter.crosthwaite@xilinx.com
[ PC Changes:
* Fixed Grammar error in commit message
* Elaborated commit message.
]
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/cpu.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 3bce1d6..8288c7d 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -121,6 +121,11 @@ static void arm_cpu_reset(CPUState *s)
env->regs[15] = pc & ~1;
}
}
+
+ if (env->cp15.c1_sys & (1 << 13)) {
+ env->regs[15] = 0xFFFF0000;
+ }
+
env->vfp.xregs[ARM_VFP_FPEXC] = 0;
#endif
set_flush_to_zero(1, &env->vfp.standard_fp_status);
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 19/62] target-arm/kvm: Split 32 bit only code into its own file
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (17 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 18/62] ARM: arm_cpu_reset: make it possible to use high vectors for reset_exc Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 20/62] target-arm: Clean up handling of AArch64 PSTATE Peter Maydell
` (43 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
Split ARM KVM support code which is 32 bit specific out into its
own file, which we only compile on 32 bit hosts. This will give
us a place to add the 64 bit support code without adding lots of
ifdefs to kvm.c.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1385645602-18662-2-git-send-email-peter.maydell@linaro.org
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
---
target-arm/Makefile.objs | 1 +
target-arm/kvm.c | 491 --------------------------------------------
target-arm/kvm32.c | 515 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 516 insertions(+), 491 deletions(-)
create mode 100644 target-arm/kvm32.c
diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
index f428b5b..869ecd0 100644
--- a/target-arm/Makefile.objs
+++ b/target-arm/Makefile.objs
@@ -1,6 +1,7 @@
obj-y += arm-semi.o
obj-$(CONFIG_SOFTMMU) += machine.o
obj-$(CONFIG_KVM) += kvm.o
+obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += neon_helper.o iwmmxt_helper.o
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index f865dac..5cdb3b9 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -100,120 +100,6 @@ void kvm_arm_destroy_scratch_host_vcpu(int *fdarray)
}
}
-static inline void set_feature(uint64_t *features, int feature)
-{
- *features |= 1ULL << feature;
-}
-
-bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
-{
- /* Identify the feature bits corresponding to the host CPU, and
- * fill out the ARMHostCPUClass fields accordingly. To do this
- * we have to create a scratch VM, create a single CPU inside it,
- * and then query that CPU for the relevant ID registers.
- */
- int i, ret, fdarray[3];
- uint32_t midr, id_pfr0, id_isar0, mvfr1;
- uint64_t features = 0;
- /* Old kernels may not know about the PREFERRED_TARGET ioctl: however
- * we know these will only support creating one kind of guest CPU,
- * which is its preferred CPU type.
- */
- static const uint32_t cpus_to_try[] = {
- QEMU_KVM_ARM_TARGET_CORTEX_A15,
- QEMU_KVM_ARM_TARGET_NONE
- };
- struct kvm_vcpu_init init;
- struct kvm_one_reg idregs[] = {
- {
- .id = KVM_REG_ARM | KVM_REG_SIZE_U32
- | ENCODE_CP_REG(15, 0, 0, 0, 0, 0),
- .addr = (uintptr_t)&midr,
- },
- {
- .id = KVM_REG_ARM | KVM_REG_SIZE_U32
- | ENCODE_CP_REG(15, 0, 0, 1, 0, 0),
- .addr = (uintptr_t)&id_pfr0,
- },
- {
- .id = KVM_REG_ARM | KVM_REG_SIZE_U32
- | ENCODE_CP_REG(15, 0, 0, 2, 0, 0),
- .addr = (uintptr_t)&id_isar0,
- },
- {
- .id = KVM_REG_ARM | KVM_REG_SIZE_U32
- | KVM_REG_ARM_VFP | KVM_REG_ARM_VFP_MVFR1,
- .addr = (uintptr_t)&mvfr1,
- },
- };
-
- if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
- return false;
- }
-
- ahcc->target = init.target;
-
- /* This is not strictly blessed by the device tree binding docs yet,
- * but in practice the kernel does not care about this string so
- * there is no point maintaining an KVM_ARM_TARGET_* -> string table.
- */
- ahcc->dtb_compatible = "arm,arm-v7";
-
- for (i = 0; i < ARRAY_SIZE(idregs); i++) {
- ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &idregs[i]);
- if (ret) {
- break;
- }
- }
-
- kvm_arm_destroy_scratch_host_vcpu(fdarray);
-
- if (ret) {
- return false;
- }
-
- /* Now we've retrieved all the register information we can
- * set the feature bits based on the ID register fields.
- * We can assume any KVM supporting CPU is at least a v7
- * with VFPv3, LPAE and the generic timers; this in turn implies
- * most of the other feature bits, but a few must be tested.
- */
- set_feature(&features, ARM_FEATURE_V7);
- set_feature(&features, ARM_FEATURE_VFP3);
- set_feature(&features, ARM_FEATURE_LPAE);
- set_feature(&features, ARM_FEATURE_GENERIC_TIMER);
-
- switch (extract32(id_isar0, 24, 4)) {
- case 1:
- set_feature(&features, ARM_FEATURE_THUMB_DIV);
- break;
- case 2:
- set_feature(&features, ARM_FEATURE_ARM_DIV);
- set_feature(&features, ARM_FEATURE_THUMB_DIV);
- break;
- default:
- break;
- }
-
- if (extract32(id_pfr0, 12, 4) == 1) {
- set_feature(&features, ARM_FEATURE_THUMB2EE);
- }
- if (extract32(mvfr1, 20, 4) == 1) {
- set_feature(&features, ARM_FEATURE_VFP_FP16);
- }
- if (extract32(mvfr1, 12, 4) == 1) {
- set_feature(&features, ARM_FEATURE_NEON);
- }
- if (extract32(mvfr1, 28, 4) == 1) {
- /* FMAC support implies VFPv4 */
- set_feature(&features, ARM_FEATURE_VFP4);
- }
-
- ahcc->features = features;
-
- return true;
-}
-
static void kvm_arm_host_cpu_class_init(ObjectClass *oc, void *data)
{
ARMHostCPUClass *ahcc = ARM_HOST_CPU_CLASS(oc);
@@ -265,144 +151,6 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu)
return cpu->cpu_index;
}
-static bool reg_syncs_via_tuple_list(uint64_t regidx)
-{
- /* Return true if the regidx is a register we should synchronize
- * via the cpreg_tuples array (ie is not a core reg we sync by
- * hand in kvm_arch_get/put_registers())
- */
- switch (regidx & KVM_REG_ARM_COPROC_MASK) {
- case KVM_REG_ARM_CORE:
- case KVM_REG_ARM_VFP:
- return false;
- default:
- return true;
- }
-}
-
-static int compare_u64(const void *a, const void *b)
-{
- if (*(uint64_t *)a > *(uint64_t *)b) {
- return 1;
- }
- if (*(uint64_t *)a < *(uint64_t *)b) {
- return -1;
- }
- return 0;
-}
-
-int kvm_arch_init_vcpu(CPUState *cs)
-{
- struct kvm_vcpu_init init;
- int i, ret, arraylen;
- uint64_t v;
- struct kvm_one_reg r;
- struct kvm_reg_list rl;
- struct kvm_reg_list *rlp;
- ARMCPU *cpu = ARM_CPU(cs);
-
- if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE) {
- fprintf(stderr, "KVM is not supported for this guest CPU type\n");
- return -EINVAL;
- }
-
- init.target = cpu->kvm_target;
- memset(init.features, 0, sizeof(init.features));
- if (cpu->start_powered_off) {
- init.features[0] = 1 << KVM_ARM_VCPU_POWER_OFF;
- }
- ret = kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init);
- if (ret) {
- return ret;
- }
- /* Query the kernel to make sure it supports 32 VFP
- * registers: QEMU's "cortex-a15" CPU is always a
- * VFP-D32 core. The simplest way to do this is just
- * to attempt to read register d31.
- */
- r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP | 31;
- r.addr = (uintptr_t)(&v);
- ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
- if (ret == -ENOENT) {
- return -EINVAL;
- }
-
- /* Populate the cpreg list based on the kernel's idea
- * of what registers exist (and throw away the TCG-created list).
- */
- rl.n = 0;
- ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, &rl);
- if (ret != -E2BIG) {
- return ret;
- }
- rlp = g_malloc(sizeof(struct kvm_reg_list) + rl.n * sizeof(uint64_t));
- rlp->n = rl.n;
- ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, rlp);
- if (ret) {
- goto out;
- }
- /* Sort the list we get back from the kernel, since cpreg_tuples
- * must be in strictly ascending order.
- */
- qsort(&rlp->reg, rlp->n, sizeof(rlp->reg[0]), compare_u64);
-
- for (i = 0, arraylen = 0; i < rlp->n; i++) {
- if (!reg_syncs_via_tuple_list(rlp->reg[i])) {
- continue;
- }
- switch (rlp->reg[i] & KVM_REG_SIZE_MASK) {
- case KVM_REG_SIZE_U32:
- case KVM_REG_SIZE_U64:
- break;
- default:
- fprintf(stderr, "Can't handle size of register in kernel list\n");
- ret = -EINVAL;
- goto out;
- }
-
- arraylen++;
- }
-
- cpu->cpreg_indexes = g_renew(uint64_t, cpu->cpreg_indexes, arraylen);
- cpu->cpreg_values = g_renew(uint64_t, cpu->cpreg_values, arraylen);
- cpu->cpreg_vmstate_indexes = g_renew(uint64_t, cpu->cpreg_vmstate_indexes,
- arraylen);
- cpu->cpreg_vmstate_values = g_renew(uint64_t, cpu->cpreg_vmstate_values,
- arraylen);
- cpu->cpreg_array_len = arraylen;
- cpu->cpreg_vmstate_array_len = arraylen;
-
- for (i = 0, arraylen = 0; i < rlp->n; i++) {
- uint64_t regidx = rlp->reg[i];
- if (!reg_syncs_via_tuple_list(regidx)) {
- continue;
- }
- cpu->cpreg_indexes[arraylen] = regidx;
- arraylen++;
- }
- assert(cpu->cpreg_array_len == arraylen);
-
- if (!write_kvmstate_to_list(cpu)) {
- /* Shouldn't happen unless kernel is inconsistent about
- * what registers exist.
- */
- fprintf(stderr, "Initial read of kernel register state failed\n");
- ret = -EINVAL;
- goto out;
- }
-
- /* Save a copy of the initial register values so that we can
- * feed it back to the kernel on VCPU reset.
- */
- cpu->cpreg_reset_values = g_memdup(cpu->cpreg_values,
- cpu->cpreg_array_len *
- sizeof(cpu->cpreg_values[0]));
-
-out:
- g_free(rlp);
- return ret;
-}
-
/* We track all the KVM devices which need their memory addresses
* passing to the kernel in a list of these structures.
* When board init is complete we run through the list and
@@ -563,232 +311,6 @@ bool write_list_to_kvmstate(ARMCPU *cpu)
return ok;
}
-typedef struct Reg {
- uint64_t id;
- int offset;
-} Reg;
-
-#define COREREG(KERNELNAME, QEMUFIELD) \
- { \
- KVM_REG_ARM | KVM_REG_SIZE_U32 | \
- KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(KERNELNAME), \
- offsetof(CPUARMState, QEMUFIELD) \
- }
-
-#define VFPSYSREG(R) \
- { \
- KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | \
- KVM_REG_ARM_VFP_##R, \
- offsetof(CPUARMState, vfp.xregs[ARM_VFP_##R]) \
- }
-
-static const Reg regs[] = {
- /* R0_usr .. R14_usr */
- COREREG(usr_regs.uregs[0], regs[0]),
- COREREG(usr_regs.uregs[1], regs[1]),
- COREREG(usr_regs.uregs[2], regs[2]),
- COREREG(usr_regs.uregs[3], regs[3]),
- COREREG(usr_regs.uregs[4], regs[4]),
- COREREG(usr_regs.uregs[5], regs[5]),
- COREREG(usr_regs.uregs[6], regs[6]),
- COREREG(usr_regs.uregs[7], regs[7]),
- COREREG(usr_regs.uregs[8], usr_regs[0]),
- COREREG(usr_regs.uregs[9], usr_regs[1]),
- COREREG(usr_regs.uregs[10], usr_regs[2]),
- COREREG(usr_regs.uregs[11], usr_regs[3]),
- COREREG(usr_regs.uregs[12], usr_regs[4]),
- COREREG(usr_regs.uregs[13], banked_r13[0]),
- COREREG(usr_regs.uregs[14], banked_r14[0]),
- /* R13, R14, SPSR for SVC, ABT, UND, IRQ banks */
- COREREG(svc_regs[0], banked_r13[1]),
- COREREG(svc_regs[1], banked_r14[1]),
- COREREG(svc_regs[2], banked_spsr[1]),
- COREREG(abt_regs[0], banked_r13[2]),
- COREREG(abt_regs[1], banked_r14[2]),
- COREREG(abt_regs[2], banked_spsr[2]),
- COREREG(und_regs[0], banked_r13[3]),
- COREREG(und_regs[1], banked_r14[3]),
- COREREG(und_regs[2], banked_spsr[3]),
- COREREG(irq_regs[0], banked_r13[4]),
- COREREG(irq_regs[1], banked_r14[4]),
- COREREG(irq_regs[2], banked_spsr[4]),
- /* R8_fiq .. R14_fiq and SPSR_fiq */
- COREREG(fiq_regs[0], fiq_regs[0]),
- COREREG(fiq_regs[1], fiq_regs[1]),
- COREREG(fiq_regs[2], fiq_regs[2]),
- COREREG(fiq_regs[3], fiq_regs[3]),
- COREREG(fiq_regs[4], fiq_regs[4]),
- COREREG(fiq_regs[5], banked_r13[5]),
- COREREG(fiq_regs[6], banked_r14[5]),
- COREREG(fiq_regs[7], banked_spsr[5]),
- /* R15 */
- COREREG(usr_regs.uregs[15], regs[15]),
- /* VFP system registers */
- VFPSYSREG(FPSID),
- VFPSYSREG(MVFR1),
- VFPSYSREG(MVFR0),
- VFPSYSREG(FPEXC),
- VFPSYSREG(FPINST),
- VFPSYSREG(FPINST2),
-};
-
-int kvm_arch_put_registers(CPUState *cs, int level)
-{
- ARMCPU *cpu = ARM_CPU(cs);
- CPUARMState *env = &cpu->env;
- struct kvm_one_reg r;
- int mode, bn;
- int ret, i;
- uint32_t cpsr, fpscr;
-
- /* Make sure the banked regs are properly set */
- mode = env->uncached_cpsr & CPSR_M;
- bn = bank_number(mode);
- if (mode == ARM_CPU_MODE_FIQ) {
- memcpy(env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t));
- } else {
- memcpy(env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
- }
- env->banked_r13[bn] = env->regs[13];
- env->banked_r14[bn] = env->regs[14];
- env->banked_spsr[bn] = env->spsr;
-
- /* Now we can safely copy stuff down to the kernel */
- for (i = 0; i < ARRAY_SIZE(regs); i++) {
- r.id = regs[i].id;
- r.addr = (uintptr_t)(env) + regs[i].offset;
- ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
- if (ret) {
- return ret;
- }
- }
-
- /* Special cases which aren't a single CPUARMState field */
- cpsr = cpsr_read(env);
- r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 |
- KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr);
- r.addr = (uintptr_t)(&cpsr);
- ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
- if (ret) {
- return ret;
- }
-
- /* VFP registers */
- r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
- for (i = 0; i < 32; i++) {
- r.addr = (uintptr_t)(&env->vfp.regs[i]);
- ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
- if (ret) {
- return ret;
- }
- r.id++;
- }
-
- r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP |
- KVM_REG_ARM_VFP_FPSCR;
- fpscr = vfp_get_fpscr(env);
- r.addr = (uintptr_t)&fpscr;
- ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
- if (ret) {
- return ret;
- }
-
- /* Note that we do not call write_cpustate_to_list()
- * here, so we are only writing the tuple list back to
- * KVM. This is safe because nothing can change the
- * CPUARMState cp15 fields (in particular gdb accesses cannot)
- * and so there are no changes to sync. In fact syncing would
- * be wrong at this point: for a constant register where TCG and
- * KVM disagree about its value, the preceding write_list_to_cpustate()
- * would not have had any effect on the CPUARMState value (since the
- * register is read-only), and a write_cpustate_to_list() here would
- * then try to write the TCG value back into KVM -- this would either
- * fail or incorrectly change the value the guest sees.
- *
- * If we ever want to allow the user to modify cp15 registers via
- * the gdb stub, we would need to be more clever here (for instance
- * tracking the set of registers kvm_arch_get_registers() successfully
- * managed to update the CPUARMState with, and only allowing those
- * to be written back up into the kernel).
- */
- if (!write_list_to_kvmstate(cpu)) {
- return EINVAL;
- }
-
- return ret;
-}
-
-int kvm_arch_get_registers(CPUState *cs)
-{
- ARMCPU *cpu = ARM_CPU(cs);
- CPUARMState *env = &cpu->env;
- struct kvm_one_reg r;
- int mode, bn;
- int ret, i;
- uint32_t cpsr, fpscr;
-
- for (i = 0; i < ARRAY_SIZE(regs); i++) {
- r.id = regs[i].id;
- r.addr = (uintptr_t)(env) + regs[i].offset;
- ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
- if (ret) {
- return ret;
- }
- }
-
- /* Special cases which aren't a single CPUARMState field */
- r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 |
- KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr);
- r.addr = (uintptr_t)(&cpsr);
- ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
- if (ret) {
- return ret;
- }
- cpsr_write(env, cpsr, 0xffffffff);
-
- /* Make sure the current mode regs are properly set */
- mode = env->uncached_cpsr & CPSR_M;
- bn = bank_number(mode);
- if (mode == ARM_CPU_MODE_FIQ) {
- memcpy(env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
- } else {
- memcpy(env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
- }
- env->regs[13] = env->banked_r13[bn];
- env->regs[14] = env->banked_r14[bn];
- env->spsr = env->banked_spsr[bn];
-
- /* VFP registers */
- r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
- for (i = 0; i < 32; i++) {
- r.addr = (uintptr_t)(&env->vfp.regs[i]);
- ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
- if (ret) {
- return ret;
- }
- r.id++;
- }
-
- r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP |
- KVM_REG_ARM_VFP_FPSCR;
- r.addr = (uintptr_t)&fpscr;
- ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
- if (ret) {
- return ret;
- }
- vfp_set_fpscr(env, fpscr);
-
- if (!write_kvmstate_to_list(cpu)) {
- return EINVAL;
- }
- /* Note that it's OK to have registers which aren't in CPUState,
- * so we can ignore a failure return here.
- */
- write_list_to_cpustate(cpu);
-
- return 0;
-}
-
void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
{
}
@@ -802,19 +324,6 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
return 0;
}
-void kvm_arch_reset_vcpu(CPUState *cs)
-{
- /* Feed the kernel back its initial register state */
- ARMCPU *cpu = ARM_CPU(cs);
-
- memmove(cpu->cpreg_values, cpu->cpreg_reset_values,
- cpu->cpreg_array_len * sizeof(cpu->cpreg_values[0]));
-
- if (!write_list_to_kvmstate(cpu)) {
- abort();
- }
-}
-
bool kvm_arch_stop_on_emulation_error(CPUState *cs)
{
return true;
diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c
new file mode 100644
index 0000000..a4fde07
--- /dev/null
+++ b/target-arm/kvm32.c
@@ -0,0 +1,515 @@
+/*
+ * ARM implementation of KVM hooks, 32 bit specific code.
+ *
+ * Copyright Christoffer Dall 2009-2010
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <linux/kvm.h>
+
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/kvm.h"
+#include "kvm_arm.h"
+#include "cpu.h"
+#include "hw/arm/arm.h"
+
+static inline void set_feature(uint64_t *features, int feature)
+{
+ *features |= 1ULL << feature;
+}
+
+bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
+{
+ /* Identify the feature bits corresponding to the host CPU, and
+ * fill out the ARMHostCPUClass fields accordingly. To do this
+ * we have to create a scratch VM, create a single CPU inside it,
+ * and then query that CPU for the relevant ID registers.
+ */
+ int i, ret, fdarray[3];
+ uint32_t midr, id_pfr0, id_isar0, mvfr1;
+ uint64_t features = 0;
+ /* Old kernels may not know about the PREFERRED_TARGET ioctl: however
+ * we know these will only support creating one kind of guest CPU,
+ * which is its preferred CPU type.
+ */
+ static const uint32_t cpus_to_try[] = {
+ QEMU_KVM_ARM_TARGET_CORTEX_A15,
+ QEMU_KVM_ARM_TARGET_NONE
+ };
+ struct kvm_vcpu_init init;
+ struct kvm_one_reg idregs[] = {
+ {
+ .id = KVM_REG_ARM | KVM_REG_SIZE_U32
+ | ENCODE_CP_REG(15, 0, 0, 0, 0, 0),
+ .addr = (uintptr_t)&midr,
+ },
+ {
+ .id = KVM_REG_ARM | KVM_REG_SIZE_U32
+ | ENCODE_CP_REG(15, 0, 0, 1, 0, 0),
+ .addr = (uintptr_t)&id_pfr0,
+ },
+ {
+ .id = KVM_REG_ARM | KVM_REG_SIZE_U32
+ | ENCODE_CP_REG(15, 0, 0, 2, 0, 0),
+ .addr = (uintptr_t)&id_isar0,
+ },
+ {
+ .id = KVM_REG_ARM | KVM_REG_SIZE_U32
+ | KVM_REG_ARM_VFP | KVM_REG_ARM_VFP_MVFR1,
+ .addr = (uintptr_t)&mvfr1,
+ },
+ };
+
+ if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
+ return false;
+ }
+
+ ahcc->target = init.target;
+
+ /* This is not strictly blessed by the device tree binding docs yet,
+ * but in practice the kernel does not care about this string so
+ * there is no point maintaining an KVM_ARM_TARGET_* -> string table.
+ */
+ ahcc->dtb_compatible = "arm,arm-v7";
+
+ for (i = 0; i < ARRAY_SIZE(idregs); i++) {
+ ret = ioctl(fdarray[2], KVM_GET_ONE_REG, &idregs[i]);
+ if (ret) {
+ break;
+ }
+ }
+
+ kvm_arm_destroy_scratch_host_vcpu(fdarray);
+
+ if (ret) {
+ return false;
+ }
+
+ /* Now we've retrieved all the register information we can
+ * set the feature bits based on the ID register fields.
+ * We can assume any KVM supporting CPU is at least a v7
+ * with VFPv3, LPAE and the generic timers; this in turn implies
+ * most of the other feature bits, but a few must be tested.
+ */
+ set_feature(&features, ARM_FEATURE_V7);
+ set_feature(&features, ARM_FEATURE_VFP3);
+ set_feature(&features, ARM_FEATURE_LPAE);
+ set_feature(&features, ARM_FEATURE_GENERIC_TIMER);
+
+ switch (extract32(id_isar0, 24, 4)) {
+ case 1:
+ set_feature(&features, ARM_FEATURE_THUMB_DIV);
+ break;
+ case 2:
+ set_feature(&features, ARM_FEATURE_ARM_DIV);
+ set_feature(&features, ARM_FEATURE_THUMB_DIV);
+ break;
+ default:
+ break;
+ }
+
+ if (extract32(id_pfr0, 12, 4) == 1) {
+ set_feature(&features, ARM_FEATURE_THUMB2EE);
+ }
+ if (extract32(mvfr1, 20, 4) == 1) {
+ set_feature(&features, ARM_FEATURE_VFP_FP16);
+ }
+ if (extract32(mvfr1, 12, 4) == 1) {
+ set_feature(&features, ARM_FEATURE_NEON);
+ }
+ if (extract32(mvfr1, 28, 4) == 1) {
+ /* FMAC support implies VFPv4 */
+ set_feature(&features, ARM_FEATURE_VFP4);
+ }
+
+ ahcc->features = features;
+
+ return true;
+}
+
+static bool reg_syncs_via_tuple_list(uint64_t regidx)
+{
+ /* Return true if the regidx is a register we should synchronize
+ * via the cpreg_tuples array (ie is not a core reg we sync by
+ * hand in kvm_arch_get/put_registers())
+ */
+ switch (regidx & KVM_REG_ARM_COPROC_MASK) {
+ case KVM_REG_ARM_CORE:
+ case KVM_REG_ARM_VFP:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static int compare_u64(const void *a, const void *b)
+{
+ if (*(uint64_t *)a > *(uint64_t *)b) {
+ return 1;
+ }
+ if (*(uint64_t *)a < *(uint64_t *)b) {
+ return -1;
+ }
+ return 0;
+}
+
+int kvm_arch_init_vcpu(CPUState *cs)
+{
+ struct kvm_vcpu_init init;
+ int i, ret, arraylen;
+ uint64_t v;
+ struct kvm_one_reg r;
+ struct kvm_reg_list rl;
+ struct kvm_reg_list *rlp;
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE) {
+ fprintf(stderr, "KVM is not supported for this guest CPU type\n");
+ return -EINVAL;
+ }
+
+ init.target = cpu->kvm_target;
+ memset(init.features, 0, sizeof(init.features));
+ if (cpu->start_powered_off) {
+ init.features[0] = 1 << KVM_ARM_VCPU_POWER_OFF;
+ }
+ ret = kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init);
+ if (ret) {
+ return ret;
+ }
+ /* Query the kernel to make sure it supports 32 VFP
+ * registers: QEMU's "cortex-a15" CPU is always a
+ * VFP-D32 core. The simplest way to do this is just
+ * to attempt to read register d31.
+ */
+ r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP | 31;
+ r.addr = (uintptr_t)(&v);
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
+ if (ret == -ENOENT) {
+ return -EINVAL;
+ }
+
+ /* Populate the cpreg list based on the kernel's idea
+ * of what registers exist (and throw away the TCG-created list).
+ */
+ rl.n = 0;
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, &rl);
+ if (ret != -E2BIG) {
+ return ret;
+ }
+ rlp = g_malloc(sizeof(struct kvm_reg_list) + rl.n * sizeof(uint64_t));
+ rlp->n = rl.n;
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_REG_LIST, rlp);
+ if (ret) {
+ goto out;
+ }
+ /* Sort the list we get back from the kernel, since cpreg_tuples
+ * must be in strictly ascending order.
+ */
+ qsort(&rlp->reg, rlp->n, sizeof(rlp->reg[0]), compare_u64);
+
+ for (i = 0, arraylen = 0; i < rlp->n; i++) {
+ if (!reg_syncs_via_tuple_list(rlp->reg[i])) {
+ continue;
+ }
+ switch (rlp->reg[i] & KVM_REG_SIZE_MASK) {
+ case KVM_REG_SIZE_U32:
+ case KVM_REG_SIZE_U64:
+ break;
+ default:
+ fprintf(stderr, "Can't handle size of register in kernel list\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ arraylen++;
+ }
+
+ cpu->cpreg_indexes = g_renew(uint64_t, cpu->cpreg_indexes, arraylen);
+ cpu->cpreg_values = g_renew(uint64_t, cpu->cpreg_values, arraylen);
+ cpu->cpreg_vmstate_indexes = g_renew(uint64_t, cpu->cpreg_vmstate_indexes,
+ arraylen);
+ cpu->cpreg_vmstate_values = g_renew(uint64_t, cpu->cpreg_vmstate_values,
+ arraylen);
+ cpu->cpreg_array_len = arraylen;
+ cpu->cpreg_vmstate_array_len = arraylen;
+
+ for (i = 0, arraylen = 0; i < rlp->n; i++) {
+ uint64_t regidx = rlp->reg[i];
+ if (!reg_syncs_via_tuple_list(regidx)) {
+ continue;
+ }
+ cpu->cpreg_indexes[arraylen] = regidx;
+ arraylen++;
+ }
+ assert(cpu->cpreg_array_len == arraylen);
+
+ if (!write_kvmstate_to_list(cpu)) {
+ /* Shouldn't happen unless kernel is inconsistent about
+ * what registers exist.
+ */
+ fprintf(stderr, "Initial read of kernel register state failed\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Save a copy of the initial register values so that we can
+ * feed it back to the kernel on VCPU reset.
+ */
+ cpu->cpreg_reset_values = g_memdup(cpu->cpreg_values,
+ cpu->cpreg_array_len *
+ sizeof(cpu->cpreg_values[0]));
+
+out:
+ g_free(rlp);
+ return ret;
+}
+
+typedef struct Reg {
+ uint64_t id;
+ int offset;
+} Reg;
+
+#define COREREG(KERNELNAME, QEMUFIELD) \
+ { \
+ KVM_REG_ARM | KVM_REG_SIZE_U32 | \
+ KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(KERNELNAME), \
+ offsetof(CPUARMState, QEMUFIELD) \
+ }
+
+#define VFPSYSREG(R) \
+ { \
+ KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | \
+ KVM_REG_ARM_VFP_##R, \
+ offsetof(CPUARMState, vfp.xregs[ARM_VFP_##R]) \
+ }
+
+static const Reg regs[] = {
+ /* R0_usr .. R14_usr */
+ COREREG(usr_regs.uregs[0], regs[0]),
+ COREREG(usr_regs.uregs[1], regs[1]),
+ COREREG(usr_regs.uregs[2], regs[2]),
+ COREREG(usr_regs.uregs[3], regs[3]),
+ COREREG(usr_regs.uregs[4], regs[4]),
+ COREREG(usr_regs.uregs[5], regs[5]),
+ COREREG(usr_regs.uregs[6], regs[6]),
+ COREREG(usr_regs.uregs[7], regs[7]),
+ COREREG(usr_regs.uregs[8], usr_regs[0]),
+ COREREG(usr_regs.uregs[9], usr_regs[1]),
+ COREREG(usr_regs.uregs[10], usr_regs[2]),
+ COREREG(usr_regs.uregs[11], usr_regs[3]),
+ COREREG(usr_regs.uregs[12], usr_regs[4]),
+ COREREG(usr_regs.uregs[13], banked_r13[0]),
+ COREREG(usr_regs.uregs[14], banked_r14[0]),
+ /* R13, R14, SPSR for SVC, ABT, UND, IRQ banks */
+ COREREG(svc_regs[0], banked_r13[1]),
+ COREREG(svc_regs[1], banked_r14[1]),
+ COREREG(svc_regs[2], banked_spsr[1]),
+ COREREG(abt_regs[0], banked_r13[2]),
+ COREREG(abt_regs[1], banked_r14[2]),
+ COREREG(abt_regs[2], banked_spsr[2]),
+ COREREG(und_regs[0], banked_r13[3]),
+ COREREG(und_regs[1], banked_r14[3]),
+ COREREG(und_regs[2], banked_spsr[3]),
+ COREREG(irq_regs[0], banked_r13[4]),
+ COREREG(irq_regs[1], banked_r14[4]),
+ COREREG(irq_regs[2], banked_spsr[4]),
+ /* R8_fiq .. R14_fiq and SPSR_fiq */
+ COREREG(fiq_regs[0], fiq_regs[0]),
+ COREREG(fiq_regs[1], fiq_regs[1]),
+ COREREG(fiq_regs[2], fiq_regs[2]),
+ COREREG(fiq_regs[3], fiq_regs[3]),
+ COREREG(fiq_regs[4], fiq_regs[4]),
+ COREREG(fiq_regs[5], banked_r13[5]),
+ COREREG(fiq_regs[6], banked_r14[5]),
+ COREREG(fiq_regs[7], banked_spsr[5]),
+ /* R15 */
+ COREREG(usr_regs.uregs[15], regs[15]),
+ /* VFP system registers */
+ VFPSYSREG(FPSID),
+ VFPSYSREG(MVFR1),
+ VFPSYSREG(MVFR0),
+ VFPSYSREG(FPEXC),
+ VFPSYSREG(FPINST),
+ VFPSYSREG(FPINST2),
+};
+
+int kvm_arch_put_registers(CPUState *cs, int level)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ struct kvm_one_reg r;
+ int mode, bn;
+ int ret, i;
+ uint32_t cpsr, fpscr;
+
+ /* Make sure the banked regs are properly set */
+ mode = env->uncached_cpsr & CPSR_M;
+ bn = bank_number(mode);
+ if (mode == ARM_CPU_MODE_FIQ) {
+ memcpy(env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t));
+ } else {
+ memcpy(env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
+ }
+ env->banked_r13[bn] = env->regs[13];
+ env->banked_r14[bn] = env->regs[14];
+ env->banked_spsr[bn] = env->spsr;
+
+ /* Now we can safely copy stuff down to the kernel */
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ r.id = regs[i].id;
+ r.addr = (uintptr_t)(env) + regs[i].offset;
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ /* Special cases which aren't a single CPUARMState field */
+ cpsr = cpsr_read(env);
+ r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 |
+ KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr);
+ r.addr = (uintptr_t)(&cpsr);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
+ if (ret) {
+ return ret;
+ }
+
+ /* VFP registers */
+ r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
+ for (i = 0; i < 32; i++) {
+ r.addr = (uintptr_t)(&env->vfp.regs[i]);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
+ if (ret) {
+ return ret;
+ }
+ r.id++;
+ }
+
+ r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP |
+ KVM_REG_ARM_VFP_FPSCR;
+ fpscr = vfp_get_fpscr(env);
+ r.addr = (uintptr_t)&fpscr;
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
+ if (ret) {
+ return ret;
+ }
+
+ /* Note that we do not call write_cpustate_to_list()
+ * here, so we are only writing the tuple list back to
+ * KVM. This is safe because nothing can change the
+ * CPUARMState cp15 fields (in particular gdb accesses cannot)
+ * and so there are no changes to sync. In fact syncing would
+ * be wrong at this point: for a constant register where TCG and
+ * KVM disagree about its value, the preceding write_list_to_cpustate()
+ * would not have had any effect on the CPUARMState value (since the
+ * register is read-only), and a write_cpustate_to_list() here would
+ * then try to write the TCG value back into KVM -- this would either
+ * fail or incorrectly change the value the guest sees.
+ *
+ * If we ever want to allow the user to modify cp15 registers via
+ * the gdb stub, we would need to be more clever here (for instance
+ * tracking the set of registers kvm_arch_get_registers() successfully
+ * managed to update the CPUARMState with, and only allowing those
+ * to be written back up into the kernel).
+ */
+ if (!write_list_to_kvmstate(cpu)) {
+ return EINVAL;
+ }
+
+ return ret;
+}
+
+int kvm_arch_get_registers(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ struct kvm_one_reg r;
+ int mode, bn;
+ int ret, i;
+ uint32_t cpsr, fpscr;
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ r.id = regs[i].id;
+ r.addr = (uintptr_t)(env) + regs[i].offset;
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ /* Special cases which aren't a single CPUARMState field */
+ r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 |
+ KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr);
+ r.addr = (uintptr_t)(&cpsr);
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
+ if (ret) {
+ return ret;
+ }
+ cpsr_write(env, cpsr, 0xffffffff);
+
+ /* Make sure the current mode regs are properly set */
+ mode = env->uncached_cpsr & CPSR_M;
+ bn = bank_number(mode);
+ if (mode == ARM_CPU_MODE_FIQ) {
+ memcpy(env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
+ } else {
+ memcpy(env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
+ }
+ env->regs[13] = env->banked_r13[bn];
+ env->regs[14] = env->banked_r14[bn];
+ env->spsr = env->banked_spsr[bn];
+
+ /* VFP registers */
+ r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
+ for (i = 0; i < 32; i++) {
+ r.addr = (uintptr_t)(&env->vfp.regs[i]);
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
+ if (ret) {
+ return ret;
+ }
+ r.id++;
+ }
+
+ r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP |
+ KVM_REG_ARM_VFP_FPSCR;
+ r.addr = (uintptr_t)&fpscr;
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
+ if (ret) {
+ return ret;
+ }
+ vfp_set_fpscr(env, fpscr);
+
+ if (!write_kvmstate_to_list(cpu)) {
+ return EINVAL;
+ }
+ /* Note that it's OK to have registers which aren't in CPUState,
+ * so we can ignore a failure return here.
+ */
+ write_list_to_cpustate(cpu);
+
+ return 0;
+}
+
+void kvm_arch_reset_vcpu(CPUState *cs)
+{
+ /* Feed the kernel back its initial register state */
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ memmove(cpu->cpreg_values, cpu->cpreg_reset_values,
+ cpu->cpreg_array_len * sizeof(cpu->cpreg_values[0]));
+
+ if (!write_list_to_kvmstate(cpu)) {
+ abort();
+ }
+}
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 20/62] target-arm: Clean up handling of AArch64 PSTATE
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (18 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 19/62] target-arm/kvm: Split 32 bit only code into its own file Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 21/62] target-arm: Add minimal KVM AArch64 support Peter Maydell
` (42 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
The env->pstate field is a little odd since it doesn't strictly
speaking represent an architectural register. However it's convenient
for QEMU to use it to hold the various PSTATE architectural bits
in the same format the architecture specifies for SPSR registers
(since this is the same format the kernel uses for signal handlers
and the KVM register). Add some structure to how we deal with it:
* document what env->pstate is
* add some #defines for various bits in it
* add helpers for reading/writing it taking account of caching
of NZCV, and use them where appropriate
* reset it on startup
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1385645602-18662-3-git-send-email-peter.maydell@linaro.org
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
---
linux-user/signal.c | 6 ++--
target-arm/cpu.c | 6 ++++
target-arm/cpu.h | 70 ++++++++++++++++++++++++++++++++++++++--------
target-arm/gdbstub64.c | 4 +--
target-arm/translate-a64.c | 12 ++++----
5 files changed, 78 insertions(+), 20 deletions(-)
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 7751c47..4e7148a 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1171,7 +1171,7 @@ static int target_setup_sigframe(struct target_rt_sigframe *sf,
}
__put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
__put_user(env->pc, &sf->uc.tuc_mcontext.pc);
- __put_user(env->pstate, &sf->uc.tuc_mcontext.pstate);
+ __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
__put_user(/*current->thread.fault_address*/ 0,
&sf->uc.tuc_mcontext.fault_address);
@@ -1210,6 +1210,7 @@ static int target_restore_sigframe(CPUARMState *env,
struct target_aux_context *aux =
(struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
uint32_t magic, size;
+ uint64_t pstate;
target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
sigprocmask(SIG_SETMASK, &set, NULL);
@@ -1220,7 +1221,8 @@ static int target_restore_sigframe(CPUARMState *env,
__get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
__get_user(env->pc, &sf->uc.tuc_mcontext.pc);
- __get_user(env->pstate, &sf->uc.tuc_mcontext.pstate);
+ __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
+ pstate_write(env, pstate);
__get_user(magic, &aux->fpsimd.head.magic);
__get_user(size, &aux->fpsimd.head.size);
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 8288c7d..408d207 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -89,6 +89,12 @@ static void arm_cpu_reset(CPUState *s)
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
/* 64 bit CPUs always start in 64 bit mode */
env->aarch64 = 1;
+#if defined(CONFIG_USER_ONLY)
+ env->pstate = PSTATE_MODE_EL0t;
+#else
+ env->pstate = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F
+ | PSTATE_MODE_EL1h;
+#endif
}
#if defined(CONFIG_USER_ONLY)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c6c19e9..3af4ed3 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -113,8 +113,15 @@ typedef struct CPUARMState {
/* Regs for A64 mode. */
uint64_t xregs[32];
uint64_t pc;
- /* TODO: pstate doesn't correspond to an architectural register;
- * it would be better modelled as the underlying fields.
+ /* PSTATE isn't an architectural register for ARMv8. However, it is
+ * convenient for us to assemble the underlying state into a 32 bit format
+ * identical to the architectural format used for the SPSR. (This is also
+ * what the Linux kernel's 'pstate' field in signal handlers and KVM's
+ * 'pstate' register are.) Of the PSTATE bits:
+ * NZCV are kept in the split out env->CF/VF/NF/ZF, (which have the same
+ * semantics as for AArch32, as described in the comments on each field)
+ * nRW (also known as M[4]) is kept, inverted, in env->aarch64
+ * all other bits are stored in their correct places in env->pstate
*/
uint32_t pstate;
uint32_t aarch64; /* 1 if CPU is in aarch64 state; inverse of PSTATE.nRW */
@@ -309,15 +316,6 @@ static inline bool is_a64(CPUARMState *env)
return env->aarch64;
}
-#define PSTATE_N_SHIFT 3
-#define PSTATE_N (1 << PSTATE_N_SHIFT)
-#define PSTATE_Z_SHIFT 2
-#define PSTATE_Z (1 << PSTATE_Z_SHIFT)
-#define PSTATE_C_SHIFT 1
-#define PSTATE_C (1 << PSTATE_C_SHIFT)
-#define PSTATE_V_SHIFT 0
-#define PSTATE_V (1 << PSTATE_V_SHIFT)
-
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
@@ -352,6 +350,56 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
/* Execution state bits. MRS read as zero, MSR writes ignored. */
#define CPSR_EXEC (CPSR_T | CPSR_IT | CPSR_J)
+/* Bit definitions for ARMv8 SPSR (PSTATE) format.
+ * Only these are valid when in AArch64 mode; in
+ * AArch32 mode SPSRs are basically CPSR-format.
+ */
+#define PSTATE_M (0xFU)
+#define PSTATE_nRW (1U << 4)
+#define PSTATE_F (1U << 6)
+#define PSTATE_I (1U << 7)
+#define PSTATE_A (1U << 8)
+#define PSTATE_D (1U << 9)
+#define PSTATE_IL (1U << 20)
+#define PSTATE_SS (1U << 21)
+#define PSTATE_V (1U << 28)
+#define PSTATE_C (1U << 29)
+#define PSTATE_Z (1U << 30)
+#define PSTATE_N (1U << 31)
+#define PSTATE_NZCV (PSTATE_N | PSTATE_Z | PSTATE_C | PSTATE_V)
+#define CACHED_PSTATE_BITS (PSTATE_NZCV)
+/* Mode values for AArch64 */
+#define PSTATE_MODE_EL3h 13
+#define PSTATE_MODE_EL3t 12
+#define PSTATE_MODE_EL2h 9
+#define PSTATE_MODE_EL2t 8
+#define PSTATE_MODE_EL1h 5
+#define PSTATE_MODE_EL1t 4
+#define PSTATE_MODE_EL0t 0
+
+/* Return the current PSTATE value. For the moment we don't support 32<->64 bit
+ * interprocessing, so we don't attempt to sync with the cpsr state used by
+ * the 32 bit decoder.
+ */
+static inline uint32_t pstate_read(CPUARMState *env)
+{
+ int ZF;
+
+ ZF = (env->ZF == 0);
+ return (env->NF & 0x80000000) | (ZF << 30)
+ | (env->CF << 29) | ((env->VF & 0x80000000) >> 3)
+ | env->pstate;
+}
+
+static inline void pstate_write(CPUARMState *env, uint32_t val)
+{
+ env->ZF = (~val) & PSTATE_Z;
+ env->NF = val;
+ env->CF = (val >> 29) & 1;
+ env->VF = (val << 3) & 0x80000000;
+ env->pstate = val & ~CACHED_PSTATE_BITS;
+}
+
/* Return the current CPSR value. */
uint32_t cpsr_read(CPUARMState *env);
/* Set the CPSR. Note that some bits of mask must be all-set or all-clear. */
diff --git a/target-arm/gdbstub64.c b/target-arm/gdbstub64.c
index 7cb6a7c..e8a8295 100644
--- a/target-arm/gdbstub64.c
+++ b/target-arm/gdbstub64.c
@@ -37,7 +37,7 @@ int aarch64_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
return gdb_get_reg64(mem_buf, env->pc);
break;
case 33:
- return gdb_get_reg32(mem_buf, env->pstate);
+ return gdb_get_reg32(mem_buf, pstate_read(env));
}
/* Unknown register. */
return 0;
@@ -65,7 +65,7 @@ int aarch64_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return 8;
case 33:
/* CPSR */
- env->pstate = tmp;
+ pstate_write(env, tmp);
return 4;
}
/* Unknown register. */
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index f120088..932b601 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -67,6 +67,7 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
+ uint32_t psr = pstate_read(env);
int i;
cpu_fprintf(f, "PC=%016"PRIx64" SP=%016"PRIx64"\n",
@@ -79,11 +80,12 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
cpu_fprintf(f, " ");
}
}
- cpu_fprintf(f, "PSTATE=%c%c%c%c\n",
- env->pstate & PSTATE_N ? 'n' : '.',
- env->pstate & PSTATE_Z ? 'z' : '.',
- env->pstate & PSTATE_C ? 'c' : '.',
- env->pstate & PSTATE_V ? 'v' : '.');
+ cpu_fprintf(f, "PSTATE=%08x (flags %c%c%c%c)\n",
+ psr,
+ psr & PSTATE_N ? 'N' : '-',
+ psr & PSTATE_Z ? 'Z' : '-',
+ psr & PSTATE_C ? 'C' : '-',
+ psr & PSTATE_V ? 'V' : '-');
cpu_fprintf(f, "\n");
}
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 21/62] target-arm: Add minimal KVM AArch64 support
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (19 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 20/62] target-arm: Clean up handling of AArch64 PSTATE Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 22/62] configure: Enable KVM for aarch64 host/target combination Peter Maydell
` (41 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: "Mian M. Hamayun" <m.hamayun@virtualopensystems.com>
Add the bare minimum set of functions needed for control of an
AArch64 KVM vcpu:
* CPU initialization
* minimal get/put register functions which only handle the
basic state of the CPU
Signed-off-by: Mian M. Hamayun <m.hamayun@virtualopensystems.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1385645602-18662-4-git-send-email-peter.maydell@linaro.org
[PMM: significantly overhauled; most notably:
* code lives in kvm64.c rather than using #ifdefs
* support '-cpu host' rather than implicitly using whatever the
host's CPU is regardless of what the user requests
* fix bug attempting to get/set nonexistent X[31]
* fix bug writing 64 bit kernel pstate into uint32_t env field
]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
---
target-arm/Makefile.objs | 1 +
target-arm/kvm.c | 4 +
target-arm/kvm64.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 209 insertions(+)
create mode 100644 target-arm/kvm64.c
diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
index 869ecd0..190499f 100644
--- a/target-arm/Makefile.objs
+++ b/target-arm/Makefile.objs
@@ -2,6 +2,7 @@ obj-y += arm-semi.o
obj-$(CONFIG_SOFTMMU) += machine.o
obj-$(CONFIG_KVM) += kvm.o
obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
+obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += neon_helper.o iwmmxt_helper.o
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index 5cdb3b9..1d2688d 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -128,7 +128,11 @@ static void kvm_arm_host_cpu_initfn(Object *obj)
static const TypeInfo host_arm_cpu_type_info = {
.name = TYPE_ARM_HOST_CPU,
+#ifdef TARGET_AARCH64
+ .parent = TYPE_AARCH64_CPU,
+#else
.parent = TYPE_ARM_CPU,
+#endif
.instance_init = kvm_arm_host_cpu_initfn,
.class_init = kvm_arm_host_cpu_class_init,
.class_size = sizeof(ARMHostCPUClass),
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
new file mode 100644
index 0000000..1b7ca90
--- /dev/null
+++ b/target-arm/kvm64.c
@@ -0,0 +1,204 @@
+/*
+ * ARM implementation of KVM hooks, 64 bit specific code
+ *
+ * Copyright Mian-M. Hamayun 2013, Virtual Open Systems
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <linux/kvm.h>
+
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/kvm.h"
+#include "kvm_arm.h"
+#include "cpu.h"
+#include "hw/arm/arm.h"
+
+static inline void set_feature(uint64_t *features, int feature)
+{
+ *features |= 1ULL << feature;
+}
+
+bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
+{
+ /* Identify the feature bits corresponding to the host CPU, and
+ * fill out the ARMHostCPUClass fields accordingly. To do this
+ * we have to create a scratch VM, create a single CPU inside it,
+ * and then query that CPU for the relevant ID registers.
+ * For AArch64 we currently don't care about ID registers at
+ * all; we just want to know the CPU type.
+ */
+ int fdarray[3];
+ uint64_t features = 0;
+ /* Old kernels may not know about the PREFERRED_TARGET ioctl: however
+ * we know these will only support creating one kind of guest CPU,
+ * which is its preferred CPU type. Fortunately these old kernels
+ * support only a very limited number of CPUs.
+ */
+ static const uint32_t cpus_to_try[] = {
+ KVM_ARM_TARGET_AEM_V8,
+ KVM_ARM_TARGET_FOUNDATION_V8,
+ KVM_ARM_TARGET_CORTEX_A57,
+ QEMU_KVM_ARM_TARGET_NONE
+ };
+ struct kvm_vcpu_init init;
+
+ if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
+ return false;
+ }
+
+ ahcc->target = init.target;
+ ahcc->dtb_compatible = "arm,arm-v8";
+
+ kvm_arm_destroy_scratch_host_vcpu(fdarray);
+
+ /* We can assume any KVM supporting CPU is at least a v8
+ * with VFPv4+Neon; this in turn implies most of the other
+ * feature bits.
+ */
+ set_feature(&features, ARM_FEATURE_V8);
+ set_feature(&features, ARM_FEATURE_VFP4);
+ set_feature(&features, ARM_FEATURE_NEON);
+ set_feature(&features, ARM_FEATURE_AARCH64);
+
+ ahcc->features = features;
+
+ return true;
+}
+
+int kvm_arch_init_vcpu(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ struct kvm_vcpu_init init;
+ int ret;
+
+ if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
+ !arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
+ fprintf(stderr, "KVM is not supported for this guest CPU type\n");
+ return -EINVAL;
+ }
+
+ init.target = cpu->kvm_target;
+ memset(init.features, 0, sizeof(init.features));
+ if (cpu->start_powered_off) {
+ init.features[0] = 1 << KVM_ARM_VCPU_POWER_OFF;
+ }
+ ret = kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init);
+
+ /* TODO : support for save/restore/reset of system regs via tuple list */
+
+ return ret;
+}
+
+#define AARCH64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
+ KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))
+
+int kvm_arch_put_registers(CPUState *cs, int level)
+{
+ struct kvm_one_reg reg;
+ uint64_t val;
+ int i;
+ int ret;
+
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ for (i = 0; i < 31; i++) {
+ reg.id = AARCH64_CORE_REG(regs.regs[i]);
+ reg.addr = (uintptr_t) &env->xregs[i];
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ reg.id = AARCH64_CORE_REG(regs.sp);
+ reg.addr = (uintptr_t) &env->xregs[31];
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+
+ /* Note that KVM thinks pstate is 64 bit but we use a uint32_t */
+ val = pstate_read(env);
+ reg.id = AARCH64_CORE_REG(regs.pstate);
+ reg.addr = (uintptr_t) &val;
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+
+ reg.id = AARCH64_CORE_REG(regs.pc);
+ reg.addr = (uintptr_t) &env->pc;
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+
+ /* TODO:
+ * SP_EL1
+ * ELR_EL1
+ * SPSR[]
+ * FP state
+ * system registers
+ */
+ return ret;
+}
+
+int kvm_arch_get_registers(CPUState *cs)
+{
+ struct kvm_one_reg reg;
+ uint64_t val;
+ int i;
+ int ret;
+
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ for (i = 0; i < 31; i++) {
+ reg.id = AARCH64_CORE_REG(regs.regs[i]);
+ reg.addr = (uintptr_t) &env->xregs[i];
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ reg.id = AARCH64_CORE_REG(regs.sp);
+ reg.addr = (uintptr_t) &env->xregs[31];
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+
+ reg.id = AARCH64_CORE_REG(regs.pstate);
+ reg.addr = (uintptr_t) &val;
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+ pstate_write(env, val);
+
+ reg.id = AARCH64_CORE_REG(regs.pc);
+ reg.addr = (uintptr_t) &env->pc;
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (ret) {
+ return ret;
+ }
+
+ /* TODO: other registers */
+ return ret;
+}
+
+void kvm_arch_reset_vcpu(CPUState *cs)
+{
+}
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 22/62] configure: Enable KVM for aarch64 host/target combination
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (20 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 21/62] target-arm: Add minimal KVM AArch64 support Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 23/62] hw/arm/boot: Allow easier swapping in of different loader code Peter Maydell
` (40 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
Enable KVM if the host and target CPU are both aarch64. Note
that host aarch64 + target arm is not valid for KVM acceleration:
the 64 bit kernel does not support the ioctl interface for
32 bit CPUs. 32 bit VMs on 64 bit hosts need to be created
using the 64 bit ioctl interface; when QEMU supports this it
will be on the arch64-softmmu target with a -cpu parameter for
a 32 bit CPU, which is still an aarch64/aarch64 combination
as far as configure is concerned.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1385645602-18662-5-git-send-email-peter.maydell@linaro.org
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
---
configure | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure b/configure
index edfea95..02c94e2 100755
--- a/configure
+++ b/configure
@@ -4550,7 +4550,7 @@ case "$target_name" in
*)
esac
case "$target_name" in
- arm|i386|x86_64|ppcemb|ppc|ppc64|s390x)
+ aarch64|arm|i386|x86_64|ppcemb|ppc|ppc64|s390x)
# Make sure the target and host cpus are compatible
if test "$kvm" = "yes" -a "$target_softmmu" = "yes" -a \
\( "$target_name" = "$cpu" -o \
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 23/62] hw/arm/boot: Allow easier swapping in of different loader code
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (21 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 22/62] configure: Enable KVM for aarch64 host/target combination Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 24/62] hw/arm/boot: Add boot support for AArch64 processor Peter Maydell
` (39 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
For AArch64 we will obviously require a different set of
primary and secondary boot loader code fragments. However currently
we hardcode the offsets into the loader code where we must write
the entrypoint and other data into arm_load_kernel(). This makes it
hard to substitute a different loader fragment, so switch to a more
flexible scheme where instead of a raw array of instructions we use
an array of (instruction, fixup-type) pairs that indicate which
words need special action or data written into them.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1385645602-18662-6-git-send-email-peter.maydell@linaro.org
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---
hw/arm/boot.c | 152 +++++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 107 insertions(+), 45 deletions(-)
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 55d552f..0c05a64 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -20,15 +20,33 @@
#define KERNEL_ARGS_ADDR 0x100
#define KERNEL_LOAD_ADDR 0x00010000
+typedef enum {
+ FIXUP_NONE = 0, /* do nothing */
+ FIXUP_TERMINATOR, /* end of insns */
+ FIXUP_BOARDID, /* overwrite with board ID number */
+ FIXUP_ARGPTR, /* overwrite with pointer to kernel args */
+ FIXUP_ENTRYPOINT, /* overwrite with kernel entry point */
+ FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */
+ FIXUP_BOOTREG, /* overwrite with boot register address */
+ FIXUP_DSB, /* overwrite with correct DSB insn for cpu */
+ FIXUP_MAX,
+} FixupType;
+
+typedef struct ARMInsnFixup {
+ uint32_t insn;
+ FixupType fixup;
+} ARMInsnFixup;
+
/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */
-static uint32_t bootloader[] = {
- 0xe3a00000, /* mov r0, #0 */
- 0xe59f1004, /* ldr r1, [pc, #4] */
- 0xe59f2004, /* ldr r2, [pc, #4] */
- 0xe59ff004, /* ldr pc, [pc, #4] */
- 0, /* Board ID */
- 0, /* Address of kernel args. Set by integratorcp_init. */
- 0 /* Kernel entry point. Set by integratorcp_init. */
+static const ARMInsnFixup bootloader[] = {
+ { 0xe3a00000 }, /* mov r0, #0 */
+ { 0xe59f1004 }, /* ldr r1, [pc, #4] */
+ { 0xe59f2004 }, /* ldr r2, [pc, #4] */
+ { 0xe59ff004 }, /* ldr pc, [pc, #4] */
+ { 0, FIXUP_BOARDID },
+ { 0, FIXUP_ARGPTR },
+ { 0, FIXUP_ENTRYPOINT },
+ { 0, FIXUP_TERMINATOR }
};
/* Handling for secondary CPU boot in a multicore system.
@@ -48,39 +66,83 @@ static uint32_t bootloader[] = {
#define DSB_INSN 0xf57ff04f
#define CP15_DSB_INSN 0xee070f9a /* mcr cp15, 0, r0, c7, c10, 4 */
-static uint32_t smpboot[] = {
- 0xe59f2028, /* ldr r2, gic_cpu_if */
- 0xe59f0028, /* ldr r0, startaddr */
- 0xe3a01001, /* mov r1, #1 */
- 0xe5821000, /* str r1, [r2] - set GICC_CTLR.Enable */
- 0xe3a010ff, /* mov r1, #0xff */
- 0xe5821004, /* str r1, [r2, 4] - set GIC_PMR.Priority to 0xff */
- DSB_INSN, /* dsb */
- 0xe320f003, /* wfi */
- 0xe5901000, /* ldr r1, [r0] */
- 0xe1110001, /* tst r1, r1 */
- 0x0afffffb, /* beq <wfi> */
- 0xe12fff11, /* bx r1 */
- 0, /* gic_cpu_if: base address of GIC CPU interface */
- 0 /* bootreg: Boot register address is held here */
+static const ARMInsnFixup smpboot[] = {
+ { 0xe59f2028 }, /* ldr r2, gic_cpu_if */
+ { 0xe59f0028 }, /* ldr r0, bootreg_addr */
+ { 0xe3a01001 }, /* mov r1, #1 */
+ { 0xe5821000 }, /* str r1, [r2] - set GICC_CTLR.Enable */
+ { 0xe3a010ff }, /* mov r1, #0xff */
+ { 0xe5821004 }, /* str r1, [r2, 4] - set GIC_PMR.Priority to 0xff */
+ { 0, FIXUP_DSB }, /* dsb */
+ { 0xe320f003 }, /* wfi */
+ { 0xe5901000 }, /* ldr r1, [r0] */
+ { 0xe1110001 }, /* tst r1, r1 */
+ { 0x0afffffb }, /* beq <wfi> */
+ { 0xe12fff11 }, /* bx r1 */
+ { 0, FIXUP_GIC_CPU_IF }, /* gic_cpu_if: .word 0x.... */
+ { 0, FIXUP_BOOTREG }, /* bootreg_addr: .word 0x.... */
+ { 0, FIXUP_TERMINATOR }
};
+static void write_bootloader(const char *name, hwaddr addr,
+ const ARMInsnFixup *insns, uint32_t *fixupcontext)
+{
+ /* Fix up the specified bootloader fragment and write it into
+ * guest memory using rom_add_blob_fixed(). fixupcontext is
+ * an array giving the values to write in for the fixup types
+ * which write a value into the code array.
+ */
+ int i, len;
+ uint32_t *code;
+
+ len = 0;
+ while (insns[len].fixup != FIXUP_TERMINATOR) {
+ len++;
+ }
+
+ code = g_new0(uint32_t, len);
+
+ for (i = 0; i < len; i++) {
+ uint32_t insn = insns[i].insn;
+ FixupType fixup = insns[i].fixup;
+
+ switch (fixup) {
+ case FIXUP_NONE:
+ break;
+ case FIXUP_BOARDID:
+ case FIXUP_ARGPTR:
+ case FIXUP_ENTRYPOINT:
+ case FIXUP_GIC_CPU_IF:
+ case FIXUP_BOOTREG:
+ case FIXUP_DSB:
+ insn = fixupcontext[fixup];
+ break;
+ default:
+ abort();
+ }
+ code[i] = tswap32(insn);
+ }
+
+ rom_add_blob_fixed(name, code, len * sizeof(uint32_t), addr);
+
+ g_free(code);
+}
+
static void default_write_secondary(ARMCPU *cpu,
const struct arm_boot_info *info)
{
- int n;
- smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
- smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
- for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
- /* Replace DSB with the pre-v7 DSB if necessary. */
- if (!arm_feature(&cpu->env, ARM_FEATURE_V7) &&
- smpboot[n] == DSB_INSN) {
- smpboot[n] = CP15_DSB_INSN;
- }
- smpboot[n] = tswap32(smpboot[n]);
+ uint32_t fixupcontext[FIXUP_MAX];
+
+ fixupcontext[FIXUP_GIC_CPU_IF] = info->gic_cpu_if_addr;
+ fixupcontext[FIXUP_BOOTREG] = info->smp_bootreg_addr;
+ if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+ fixupcontext[FIXUP_DSB] = DSB_INSN;
+ } else {
+ fixupcontext[FIXUP_DSB] = CP15_DSB_INSN;
}
- rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
- info->smp_loader_start);
+
+ write_bootloader("smpboot", info->smp_loader_start,
+ smpboot, fixupcontext);
}
static void default_reset_secondary(ARMCPU *cpu,
@@ -354,7 +416,6 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
CPUState *cs = CPU(cpu);
int kernel_size;
int initrd_size;
- int n;
int is_linux = 0;
uint64_t elf_entry;
hwaddr entry;
@@ -420,6 +481,8 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
}
info->entry = entry;
if (is_linux) {
+ uint32_t fixupcontext[FIXUP_MAX];
+
if (info->initrd_filename) {
initrd_size = load_ramdisk(info->initrd_filename,
info->initrd_start,
@@ -441,7 +504,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
}
info->initrd_size = initrd_size;
- bootloader[4] = info->board_id;
+ fixupcontext[FIXUP_BOARDID] = info->board_id;
/* for device tree boot, we pass the DTB directly in r2. Otherwise
* we point to the kernel args.
@@ -456,9 +519,9 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
if (load_dtb(dtb_start, info)) {
exit(1);
}
- bootloader[5] = dtb_start;
+ fixupcontext[FIXUP_ARGPTR] = dtb_start;
} else {
- bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR;
+ fixupcontext[FIXUP_ARGPTR] = info->loader_start + KERNEL_ARGS_ADDR;
if (info->ram_size >= (1ULL << 32)) {
fprintf(stderr, "qemu: RAM size must be less than 4GB to boot"
" Linux kernel using ATAGS (try passing a device tree"
@@ -466,12 +529,11 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
exit(1);
}
}
- bootloader[6] = entry;
- for (n = 0; n < sizeof(bootloader) / 4; n++) {
- bootloader[n] = tswap32(bootloader[n]);
- }
- rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader),
- info->loader_start);
+ fixupcontext[FIXUP_ENTRYPOINT] = entry;
+
+ write_bootloader("bootloader", info->loader_start,
+ bootloader, fixupcontext);
+
if (info->nb_cpus > 1) {
info->write_secondary_boot(cpu, info);
}
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 24/62] hw/arm/boot: Add boot support for AArch64 processor
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (22 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 23/62] hw/arm/boot: Allow easier swapping in of different loader code Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 25/62] default-configs: Add config for aarch64-softmmu Peter Maydell
` (38 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: "Mian M. Hamayun" <m.hamayun@virtualopensystems.com>
This commit adds support for booting a single AArch64 CPU by setting
appropriate registers. The bootloader includes placeholders for Board-ID
that are used to implement uniform indexing across different bootloaders.
Signed-off-by: Mian M. Hamayun <m.hamayun@virtualopensystems.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1385645602-18662-7-git-send-email-peter.maydell@linaro.org
[PMM:
* updated to use ARMInsnFixup style bootloader fragments
* dropped virt.c additions
* use runtime checks for "is this an AArch64 core" rather than ifdefs
* drop some unnecessary setting of registers in reset hook
]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
---
hw/arm/boot.c | 43 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 38 insertions(+), 5 deletions(-)
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 0c05a64..90e9534 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -17,8 +17,13 @@
#include "sysemu/device_tree.h"
#include "qemu/config-file.h"
+/* Kernel boot protocol is specified in the kernel docs
+ * Documentation/arm/Booting and Documentation/arm64/booting.txt
+ * They have different preferred image load offsets from system RAM base.
+ */
#define KERNEL_ARGS_ADDR 0x100
#define KERNEL_LOAD_ADDR 0x00010000
+#define KERNEL64_LOAD_ADDR 0x00080000
typedef enum {
FIXUP_NONE = 0, /* do nothing */
@@ -37,6 +42,20 @@ typedef struct ARMInsnFixup {
FixupType fixup;
} ARMInsnFixup;
+static const ARMInsnFixup bootloader_aarch64[] = {
+ { 0x580000c0 }, /* ldr x0, arg ; Load the lower 32-bits of DTB */
+ { 0xaa1f03e1 }, /* mov x1, xzr */
+ { 0xaa1f03e2 }, /* mov x2, xzr */
+ { 0xaa1f03e3 }, /* mov x3, xzr */
+ { 0x58000084 }, /* ldr x4, entry ; Load the lower 32-bits of kernel entry */
+ { 0xd61f0080 }, /* br x4 ; Jump to the kernel entry point */
+ { 0, FIXUP_ARGPTR }, /* arg: .word @DTB Lower 32-bits */
+ { 0 }, /* .word @DTB Higher 32-bits */
+ { 0, FIXUP_ENTRYPOINT }, /* entry: .word @Kernel Entry Lower 32-bits */
+ { 0 }, /* .word @Kernel Entry Higher 32-bits */
+ { 0, FIXUP_TERMINATOR }
+};
+
/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */
static const ARMInsnFixup bootloader[] = {
{ 0xe3a00000 }, /* mov r0, #0 */
@@ -396,7 +415,12 @@ static void do_cpu_reset(void *opaque)
env->thumb = info->entry & 1;
} else {
if (CPU(cpu) == first_cpu) {
- env->regs[15] = info->loader_start;
+ if (env->aarch64) {
+ env->pc = info->loader_start;
+ } else {
+ env->regs[15] = info->loader_start;
+ }
+
if (!info->dtb_filename) {
if (old_param) {
set_kernel_args_old(info);
@@ -418,8 +442,9 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
int initrd_size;
int is_linux = 0;
uint64_t elf_entry;
- hwaddr entry;
+ hwaddr entry, kernel_load_offset;
int big_endian;
+ static const ARMInsnFixup *primary_loader;
/* Load the kernel. */
if (!info->kernel_filename) {
@@ -429,6 +454,14 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
return;
}
+ if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
+ primary_loader = bootloader_aarch64;
+ kernel_load_offset = KERNEL64_LOAD_ADDR;
+ } else {
+ primary_loader = bootloader;
+ kernel_load_offset = KERNEL_LOAD_ADDR;
+ }
+
info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
if (!info->secondary_cpu_reset_hook) {
@@ -469,9 +502,9 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
&is_linux);
}
if (kernel_size < 0) {
- entry = info->loader_start + KERNEL_LOAD_ADDR;
+ entry = info->loader_start + kernel_load_offset;
kernel_size = load_image_targphys(info->kernel_filename, entry,
- info->ram_size - KERNEL_LOAD_ADDR);
+ info->ram_size - kernel_load_offset);
is_linux = 1;
}
if (kernel_size < 0) {
@@ -532,7 +565,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
fixupcontext[FIXUP_ENTRYPOINT] = entry;
write_bootloader("bootloader", info->loader_start,
- bootloader, fixupcontext);
+ primary_loader, fixupcontext);
if (info->nb_cpus > 1) {
info->write_secondary_boot(cpu, info);
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 25/62] default-configs: Add config for aarch64-softmmu
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (23 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 24/62] hw/arm/boot: Add boot support for AArch64 processor Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 26/62] target-arm: Split A64 from A32/T32 gen_intermediate_code_internal() Peter Maydell
` (37 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
Add a config for aarch64-softmmu; this enables building of this target.
The resulting executable doesn't know about any 64 bit CPUs, but all
the 32 bit CPUs and board models work.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1385645602-18662-8-git-send-email-peter.maydell@linaro.org
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---
default-configs/aarch64-softmmu.mak | 6 ++++++
1 file changed, 6 insertions(+)
create mode 100644 default-configs/aarch64-softmmu.mak
diff --git a/default-configs/aarch64-softmmu.mak b/default-configs/aarch64-softmmu.mak
new file mode 100644
index 0000000..6d3b5c7
--- /dev/null
+++ b/default-configs/aarch64-softmmu.mak
@@ -0,0 +1,6 @@
+# Default configuration for aarch64-softmmu
+
+# We support all the 32 bit boards so need all their config
+include arm-softmmu.mak
+
+# Currently no 64-bit specific config requirements
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 26/62] target-arm: Split A64 from A32/T32 gen_intermediate_code_internal()
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (24 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 25/62] default-configs: Add config for aarch64-softmmu Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 27/62] target-arm: A64: add set_pc cpu method Peter Maydell
` (36 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
The A32/T32 gen_intermediate_code_internal() is complicated because it
has to deal with:
* conditionally executed instructions
* Thumb IT blocks
* kernel helper page
* M profile exception-exit special casing
None of these apply to A64, so putting the "this is A64 so
call the A64 decoder" check in the middle of the A32/T32
loop is confusing and means the A64 decoder's handling of
things like conditional jump and singlestepping has to take
account of the conditional-execution jumps the main loop
might emit.
Refactor the code to give A64 its own gen_intermediate_code_internal
function instead.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 209 +++++++++++++++++++++++++++++++++++++++++++--
target-arm/translate.c | 62 ++++++--------
target-arm/translate.h | 20 ++++-
3 files changed, 246 insertions(+), 45 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 932b601..a713137 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -28,6 +28,8 @@
#include "translate.h"
#include "qemu/host-utils.h"
+#include "exec/gen-icount.h"
+
#include "helper.h"
#define GEN_HELPER 1
#include "helper.h"
@@ -106,7 +108,42 @@ static void gen_exception_insn(DisasContext *s, int offset, int excp)
{
gen_a64_set_pc_im(s->pc - offset);
gen_exception(excp);
- s->is_jmp = DISAS_JUMP;
+ s->is_jmp = DISAS_EXC;
+}
+
+static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
+{
+ /* No direct tb linking with singlestep or deterministic io */
+ if (s->singlestep_enabled || (s->tb->cflags & CF_LAST_IO)) {
+ return false;
+ }
+
+ /* Only link tbs from inside the same guest page */
+ if ((s->tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
+ return false;
+ }
+
+ return true;
+}
+
+static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
+{
+ TranslationBlock *tb;
+
+ tb = s->tb;
+ if (use_goto_tb(s, n, dest)) {
+ tcg_gen_goto_tb(n);
+ gen_a64_set_pc_im(dest);
+ tcg_gen_exit_tb((tcg_target_long)tb + n);
+ s->is_jmp = DISAS_TB_JUMP;
+ } else {
+ gen_a64_set_pc_im(dest);
+ if (s->singlestep_enabled) {
+ gen_exception(EXCP_DEBUG);
+ }
+ tcg_gen_exit_tb(0);
+ s->is_jmp = DISAS_JUMP;
+ }
}
static void real_unallocated_encoding(DisasContext *s)
@@ -120,7 +157,7 @@ static void real_unallocated_encoding(DisasContext *s)
real_unallocated_encoding(s); \
} while (0)
-void disas_a64_insn(CPUARMState *env, DisasContext *s)
+static void disas_a64_insn(CPUARMState *env, DisasContext *s)
{
uint32_t insn;
@@ -133,9 +170,171 @@ void disas_a64_insn(CPUARMState *env, DisasContext *s)
unallocated_encoding(s);
break;
}
+}
- if (unlikely(s->singlestep_enabled) && (s->is_jmp == DISAS_TB_JUMP)) {
- /* go through the main loop for single step */
- s->is_jmp = DISAS_JUMP;
+void gen_intermediate_code_internal_a64(ARMCPU *cpu,
+ TranslationBlock *tb,
+ bool search_pc)
+{
+ CPUState *cs = CPU(cpu);
+ CPUARMState *env = &cpu->env;
+ DisasContext dc1, *dc = &dc1;
+ CPUBreakpoint *bp;
+ uint16_t *gen_opc_end;
+ int j, lj;
+ target_ulong pc_start;
+ target_ulong next_page_start;
+ int num_insns;
+ int max_insns;
+
+ pc_start = tb->pc;
+
+ dc->tb = tb;
+
+ gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
+
+ dc->is_jmp = DISAS_NEXT;
+ dc->pc = pc_start;
+ dc->singlestep_enabled = cs->singlestep_enabled;
+ dc->condjmp = 0;
+
+ dc->aarch64 = 1;
+ dc->thumb = 0;
+ dc->bswap_code = 0;
+ dc->condexec_mask = 0;
+ dc->condexec_cond = 0;
+#if !defined(CONFIG_USER_ONLY)
+ dc->user = 0;
+#endif
+ dc->vfp_enabled = 0;
+ dc->vec_len = 0;
+ dc->vec_stride = 0;
+
+ next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+ lj = -1;
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+ if (max_insns == 0) {
+ max_insns = CF_COUNT_MASK;
+ }
+
+ gen_tb_start();
+
+ tcg_clear_temp_count();
+
+ do {
+ if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+ QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+ if (bp->pc == dc->pc) {
+ gen_exception_insn(dc, 0, EXCP_DEBUG);
+ /* Advance PC so that clearing the breakpoint will
+ invalidate this TB. */
+ dc->pc += 2;
+ goto done_generating;
+ }
+ }
+ }
+
+ if (search_pc) {
+ j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
+ if (lj < j) {
+ lj++;
+ while (lj < j) {
+ tcg_ctx.gen_opc_instr_start[lj++] = 0;
+ }
+ }
+ tcg_ctx.gen_opc_pc[lj] = dc->pc;
+ tcg_ctx.gen_opc_instr_start[lj] = 1;
+ tcg_ctx.gen_opc_icount[lj] = num_insns;
+ }
+
+ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
+ gen_io_start();
+ }
+
+ if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
+ tcg_gen_debug_insn_start(dc->pc);
+ }
+
+ disas_a64_insn(env, dc);
+
+ if (tcg_check_temp_count()) {
+ fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
+ dc->pc);
+ }
+
+ /* Translation stops when a conditional branch is encountered.
+ * Otherwise the subsequent code could get translated several times.
+ * Also stop translation when a page boundary is reached. This
+ * ensures prefetch aborts occur at the right place.
+ */
+ num_insns++;
+ } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
+ !cs->singlestep_enabled &&
+ !singlestep &&
+ dc->pc < next_page_start &&
+ num_insns < max_insns);
+
+ if (tb->cflags & CF_LAST_IO) {
+ gen_io_end();
+ }
+
+ if (unlikely(cs->singlestep_enabled) && dc->is_jmp != DISAS_EXC) {
+ /* Note that this means single stepping WFI doesn't halt the CPU.
+ * For conditional branch insns this is harmless unreachable code as
+ * gen_goto_tb() has already handled emitting the debug exception
+ * (and thus a tb-jump is not possible when singlestepping).
+ */
+ assert(dc->is_jmp != DISAS_TB_JUMP);
+ if (dc->is_jmp != DISAS_JUMP) {
+ gen_a64_set_pc_im(dc->pc);
+ }
+ gen_exception(EXCP_DEBUG);
+ } else {
+ switch (dc->is_jmp) {
+ case DISAS_NEXT:
+ gen_goto_tb(dc, 1, dc->pc);
+ break;
+ default:
+ case DISAS_JUMP:
+ case DISAS_UPDATE:
+ /* indicate that the hash table must be used to find the next TB */
+ tcg_gen_exit_tb(0);
+ break;
+ case DISAS_TB_JUMP:
+ case DISAS_EXC:
+ case DISAS_SWI:
+ break;
+ case DISAS_WFI:
+ /* This is a special case because we don't want to just halt the CPU
+ * if trying to debug across a WFI.
+ */
+ gen_helper_wfi(cpu_env);
+ break;
+ }
+ }
+
+done_generating:
+ gen_tb_end(tb, num_insns);
+ *tcg_ctx.gen_opc_ptr = INDEX_op_end;
+
+#ifdef DEBUG_DISAS
+ if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+ qemu_log("----------------\n");
+ qemu_log("IN: %s\n", lookup_symbol(pc_start));
+ log_target_disas(env, pc_start, dc->pc - pc_start,
+ dc->thumb | (dc->bswap_code << 1));
+ qemu_log("\n");
+ }
+#endif
+ if (search_pc) {
+ j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
+ lj++;
+ while (lj <= j) {
+ tcg_ctx.gen_opc_instr_start[lj++] = 0;
+ }
+ } else {
+ tb->size = dc->pc - pc_start;
+ tb->icount = num_insns;
}
}
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 9131467..679b3c3 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -56,11 +56,6 @@ static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE];
#define IS_USER(s) (s->user)
#endif
-/* These instructions trap after executing, so defer them until after the
- conditional execution state has been updated. */
-#define DISAS_WFI 4
-#define DISAS_SWI 5
-
TCGv_ptr cpu_env;
/* We reuse the same 64-bit temporaries for efficiency. */
static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
@@ -900,11 +895,7 @@ DO_GEN_ST(32, MO_TEUL)
static inline void gen_set_pc_im(DisasContext *s, target_ulong val)
{
- if (s->aarch64) {
- gen_a64_set_pc_im(val);
- } else {
- tcg_gen_movi_i32(cpu_R[15], val);
- }
+ tcg_gen_movi_i32(cpu_R[15], val);
}
/* Force a TB lookup after an instruction that changes the CPU state. */
@@ -10243,6 +10234,15 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
int max_insns;
/* generate intermediate code */
+
+ /* The A64 decoder has its own top level loop, because it doesn't need
+ * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
+ */
+ if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
+ gen_intermediate_code_internal_a64(cpu, tb, search_pc);
+ return;
+ }
+
pc_start = tb->pc;
dc->tb = tb;
@@ -10254,31 +10254,18 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
dc->singlestep_enabled = cs->singlestep_enabled;
dc->condjmp = 0;
- if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
- dc->aarch64 = 1;
- dc->thumb = 0;
- dc->bswap_code = 0;
- dc->condexec_mask = 0;
- dc->condexec_cond = 0;
+ dc->aarch64 = 0;
+ dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
+ dc->bswap_code = ARM_TBFLAG_BSWAP_CODE(tb->flags);
+ dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
+ dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
#if !defined(CONFIG_USER_ONLY)
- dc->user = 0;
+ dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
#endif
- dc->vfp_enabled = 0;
- dc->vec_len = 0;
- dc->vec_stride = 0;
- } else {
- dc->aarch64 = 0;
- dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
- dc->bswap_code = ARM_TBFLAG_BSWAP_CODE(tb->flags);
- dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
- dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
-#if !defined(CONFIG_USER_ONLY)
- dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
-#endif
- dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
- dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
- dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
- }
+ dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
+ dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
+ dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
+
cpu_F0s = tcg_temp_new_i32();
cpu_F1s = tcg_temp_new_i32();
cpu_F0d = tcg_temp_new_i64();
@@ -10340,7 +10327,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
do {
#ifdef CONFIG_USER_ONLY
/* Intercept jump to the magic kernel page. */
- if (!dc->aarch64 && dc->pc >= 0xffff0000) {
+ if (dc->pc >= 0xffff0000) {
/* We always get here via a jump, so know we are not in a
conditional execution block. */
gen_exception(EXCP_KERNEL_TRAP);
@@ -10388,9 +10375,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
tcg_gen_debug_insn_start(dc->pc);
}
- if (dc->aarch64) {
- disas_a64_insn(env, dc);
- } else if (dc->thumb) {
+ if (dc->thumb) {
disas_thumb_insn(env, dc);
if (dc->condexec_mask) {
dc->condexec_cond = (dc->condexec_cond & 0xe)
@@ -10585,8 +10570,9 @@ void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, int pc_pos)
{
if (is_a64(env)) {
env->pc = tcg_ctx.gen_opc_pc[pc_pos];
+ env->condexec_bits = 0;
} else {
env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
+ env->condexec_bits = gen_opc_condexec_bits[pc_pos];
}
- env->condexec_bits = gen_opc_condexec_bits[pc_pos];
}
diff --git a/target-arm/translate.h b/target-arm/translate.h
index 67c7760..8789181 100644
--- a/target-arm/translate.h
+++ b/target-arm/translate.h
@@ -28,16 +28,32 @@ typedef struct DisasContext {
extern TCGv_ptr cpu_env;
+/* target-specific extra values for is_jmp */
+/* These instructions trap after executing, so the A32/T32 decoder must
+ * defer them until after the conditional execution state has been updated.
+ * WFI also needs special handling when single-stepping.
+ */
+#define DISAS_WFI 4
+#define DISAS_SWI 5
+/* For instructions which unconditionally cause an exception we can skip
+ * emitting unreachable code at the end of the TB in the A64 decoder
+ */
+#define DISAS_EXC 6
+
#ifdef TARGET_AARCH64
void a64_translate_init(void);
-void disas_a64_insn(CPUARMState *env, DisasContext *s);
+void gen_intermediate_code_internal_a64(ARMCPU *cpu,
+ TranslationBlock *tb,
+ bool search_pc);
void gen_a64_set_pc_im(uint64_t val);
#else
static inline void a64_translate_init(void)
{
}
-static inline void disas_a64_insn(CPUARMState *env, DisasContext *s)
+static inline void gen_intermediate_code_internal_a64(ARMCPU *cpu,
+ TranslationBlock *tb,
+ bool search_pc)
{
}
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 27/62] target-arm: A64: add set_pc cpu method
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (25 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 26/62] target-arm: Split A64 from A32/T32 gen_intermediate_code_internal() Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 28/62] target-arm: A64: provide functions for accessing FPCR and FPSR Peter Maydell
` (35 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
When executing translation blocks we need to be able to recover
our program counter. Add a method to set it for AArch64 CPUs.
This covers user-mode, but for system mode emulation we will
need to check if the CPU is in an AArch32 execution state.
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/cpu64.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
index 3e99c21..04ce879 100644
--- a/target-arm/cpu64.c
+++ b/target-arm/cpu64.c
@@ -68,11 +68,22 @@ static void aarch64_cpu_finalizefn(Object *obj)
{
}
+static void aarch64_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ /*
+ * TODO: this will need updating for system emulation,
+ * when the core may be in AArch32 mode.
+ */
+ cpu->env.pc = value;
+}
+
static void aarch64_cpu_class_init(ObjectClass *oc, void *data)
{
CPUClass *cc = CPU_CLASS(oc);
cc->dump_state = aarch64_cpu_dump_state;
+ cc->set_pc = aarch64_cpu_set_pc;
cc->gdb_read_register = aarch64_cpu_gdb_read_register;
cc->gdb_write_register = aarch64_cpu_gdb_write_register;
cc->gdb_num_core_regs = 34;
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 28/62] target-arm: A64: provide functions for accessing FPCR and FPSR
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (26 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 27/62] target-arm: A64: add set_pc cpu method Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 29/62] target-arm: Support fp registers in gdb stub Peter Maydell
` (34 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
The information which AArch32 holds in the FPSCR is split for
AArch64 into two logically distinct registers, FPSR and FPCR.
Since they are carefully arranged to use non-overlapping bits,
we leave the underlying state in the same place, and provide
accessor functions which just update the appropriate bits
via vfp_get_fpscr() and vfp_set_fpscr().
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/cpu.h | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 3af4ed3..56ed591 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -447,6 +447,34 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
uint32_t vfp_get_fpscr(CPUARMState *env);
void vfp_set_fpscr(CPUARMState *env, uint32_t val);
+/* For A64 the FPSCR is split into two logically distinct registers,
+ * FPCR and FPSR. However since they still use non-overlapping bits
+ * we store the underlying state in fpscr and just mask on read/write.
+ */
+#define FPSR_MASK 0xf800009f
+#define FPCR_MASK 0x07f79f00
+static inline uint32_t vfp_get_fpsr(CPUARMState *env)
+{
+ return vfp_get_fpscr(env) & FPSR_MASK;
+}
+
+static inline void vfp_set_fpsr(CPUARMState *env, uint32_t val)
+{
+ uint32_t new_fpscr = (vfp_get_fpscr(env) & ~FPSR_MASK) | (val & FPSR_MASK);
+ vfp_set_fpscr(env, new_fpscr);
+}
+
+static inline uint32_t vfp_get_fpcr(CPUARMState *env)
+{
+ return vfp_get_fpscr(env) & FPCR_MASK;
+}
+
+static inline void vfp_set_fpcr(CPUARMState *env, uint32_t val)
+{
+ uint32_t new_fpscr = (vfp_get_fpscr(env) & ~FPCR_MASK) | (val & FPCR_MASK);
+ vfp_set_fpscr(env, new_fpscr);
+}
+
enum arm_cpu_mode {
ARM_CPU_MODE_USR = 0x10,
ARM_CPU_MODE_FIQ = 0x11,
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 29/62] target-arm: Support fp registers in gdb stub
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (27 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 28/62] target-arm: A64: provide functions for accessing FPCR and FPSR Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 30/62] target-arm: A64: add stubs for a64 specific helpers Peter Maydell
` (33 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
Register the aarch64-fpu XML and implement the necessary
read/write handlers so we can support reading and writing
of FP registers in the gdb stub.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
configure | 2 +-
gdb-xml/aarch64-fpu.xml | 86 +++++++++++++++++++++++++++++++++++++++++++++++++
target-arm/helper.c | 48 ++++++++++++++++++++++++++-
3 files changed, 134 insertions(+), 2 deletions(-)
create mode 100644 gdb-xml/aarch64-fpu.xml
diff --git a/configure b/configure
index 02c94e2..07b6be3 100755
--- a/configure
+++ b/configure
@@ -4438,7 +4438,7 @@ case "$target_name" in
aarch64)
TARGET_BASE_ARCH=arm
bflt="yes"
- gdb_xml_files="aarch64-core.xml"
+ gdb_xml_files="aarch64-core.xml aarch64-fpu.xml"
;;
cris)
;;
diff --git a/gdb-xml/aarch64-fpu.xml b/gdb-xml/aarch64-fpu.xml
new file mode 100644
index 0000000..997197e
--- /dev/null
+++ b/gdb-xml/aarch64-fpu.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009-2012 Free Software Foundation, Inc.
+ Contributed by ARM Ltd.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.aarch64.fpu">
+ <vector id="v2d" type="ieee_double" count="2"/>
+ <vector id="v2u" type="uint64" count="2"/>
+ <vector id="v2i" type="int64" count="2"/>
+ <vector id="v4f" type="ieee_single" count="4"/>
+ <vector id="v4u" type="uint32" count="4"/>
+ <vector id="v4i" type="int32" count="4"/>
+ <vector id="v8u" type="uint16" count="8"/>
+ <vector id="v8i" type="int16" count="8"/>
+ <vector id="v16u" type="uint8" count="16"/>
+ <vector id="v16i" type="int8" count="16"/>
+ <vector id="v1u" type="uint128" count="1"/>
+ <vector id="v1i" type="int128" count="1"/>
+ <union id="vnd">
+ <field name="f" type="v2d"/>
+ <field name="u" type="v2u"/>
+ <field name="s" type="v2i"/>
+ </union>
+ <union id="vns">
+ <field name="f" type="v4f"/>
+ <field name="u" type="v4u"/>
+ <field name="s" type="v4i"/>
+ </union>
+ <union id="vnh">
+ <field name="u" type="v8u"/>
+ <field name="s" type="v8i"/>
+ </union>
+ <union id="vnb">
+ <field name="u" type="v16u"/>
+ <field name="s" type="v16i"/>
+ </union>
+ <union id="vnq">
+ <field name="u" type="v1u"/>
+ <field name="s" type="v1i"/>
+ </union>
+ <union id="aarch64v">
+ <field name="d" type="vnd"/>
+ <field name="s" type="vns"/>
+ <field name="h" type="vnh"/>
+ <field name="b" type="vnb"/>
+ <field name="q" type="vnq"/>
+ </union>
+ <reg name="v0" bitsize="128" type="aarch64v" regnum="34"/>
+ <reg name="v1" bitsize="128" type="aarch64v" />
+ <reg name="v2" bitsize="128" type="aarch64v" />
+ <reg name="v3" bitsize="128" type="aarch64v" />
+ <reg name="v4" bitsize="128" type="aarch64v" />
+ <reg name="v5" bitsize="128" type="aarch64v" />
+ <reg name="v6" bitsize="128" type="aarch64v" />
+ <reg name="v7" bitsize="128" type="aarch64v" />
+ <reg name="v8" bitsize="128" type="aarch64v" />
+ <reg name="v9" bitsize="128" type="aarch64v" />
+ <reg name="v10" bitsize="128" type="aarch64v"/>
+ <reg name="v11" bitsize="128" type="aarch64v"/>
+ <reg name="v12" bitsize="128" type="aarch64v"/>
+ <reg name="v13" bitsize="128" type="aarch64v"/>
+ <reg name="v14" bitsize="128" type="aarch64v"/>
+ <reg name="v15" bitsize="128" type="aarch64v"/>
+ <reg name="v16" bitsize="128" type="aarch64v"/>
+ <reg name="v17" bitsize="128" type="aarch64v"/>
+ <reg name="v18" bitsize="128" type="aarch64v"/>
+ <reg name="v19" bitsize="128" type="aarch64v"/>
+ <reg name="v20" bitsize="128" type="aarch64v"/>
+ <reg name="v21" bitsize="128" type="aarch64v"/>
+ <reg name="v22" bitsize="128" type="aarch64v"/>
+ <reg name="v23" bitsize="128" type="aarch64v"/>
+ <reg name="v24" bitsize="128" type="aarch64v"/>
+ <reg name="v25" bitsize="128" type="aarch64v"/>
+ <reg name="v26" bitsize="128" type="aarch64v"/>
+ <reg name="v27" bitsize="128" type="aarch64v"/>
+ <reg name="v28" bitsize="128" type="aarch64v"/>
+ <reg name="v29" bitsize="128" type="aarch64v"/>
+ <reg name="v30" bitsize="128" type="aarch64v"/>
+ <reg name="v31" bitsize="128" type="aarch64v"/>
+ <reg name="fpsr" bitsize="32"/>
+ <reg name="fpcr" bitsize="32"/>
+</feature>
diff --git a/target-arm/helper.c b/target-arm/helper.c
index cfbb14c..6ebd7dc 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -65,6 +65,48 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
return 0;
}
+static int aarch64_fpu_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
+{
+ switch (reg) {
+ case 0 ... 31:
+ /* 128 bit FP register */
+ stfq_le_p(buf, env->vfp.regs[reg * 2]);
+ stfq_le_p(buf + 8, env->vfp.regs[reg * 2 + 1]);
+ return 16;
+ case 32:
+ /* FPSR */
+ stl_p(buf, vfp_get_fpsr(env));
+ return 4;
+ case 33:
+ /* FPCR */
+ stl_p(buf, vfp_get_fpcr(env));
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+static int aarch64_fpu_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
+{
+ switch (reg) {
+ case 0 ... 31:
+ /* 128 bit FP register */
+ env->vfp.regs[reg * 2] = ldfq_le_p(buf);
+ env->vfp.regs[reg * 2 + 1] = ldfq_le_p(buf + 8);
+ return 16;
+ case 32:
+ /* FPSR */
+ vfp_set_fpsr(env, ldl_p(buf));
+ return 4;
+ case 33:
+ /* FPCR */
+ vfp_set_fpcr(env, ldl_p(buf));
+ return 4;
+ default:
+ return 0;
+ }
+}
+
static int raw_read(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t *value)
{
@@ -1795,7 +1837,11 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
CPUState *cs = CPU(cpu);
CPUARMState *env = &cpu->env;
- if (arm_feature(env, ARM_FEATURE_NEON)) {
+ 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);
+ } 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);
} else if (arm_feature(env, ARM_FEATURE_VFP3)) {
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 30/62] target-arm: A64: add stubs for a64 specific helpers
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (28 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 29/62] target-arm: Support fp registers in gdb stub Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 31/62] target-arm: A64: provide skeleton for a64 insn decoding Peter Maydell
` (32 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
We will need helpers that only make sense with AArch64. Add
helper-a64.{c,h} files as stubs that we can fill with these
helpers in the following patches.
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/Makefile.objs | 2 +-
target-arm/helper-a64.c | 25 +++++++++++++++++++++++++
target-arm/helper-a64.h | 18 ++++++++++++++++++
target-arm/helper.h | 4 ++++
4 files changed, 48 insertions(+), 1 deletion(-)
create mode 100644 target-arm/helper-a64.c
create mode 100644 target-arm/helper-a64.h
diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
index 190499f..dcd167e 100644
--- a/target-arm/Makefile.objs
+++ b/target-arm/Makefile.objs
@@ -7,5 +7,5 @@ obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += neon_helper.o iwmmxt_helper.o
obj-y += gdbstub.o
-obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o gdbstub64.o
+obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
obj-y += crypto_helper.o
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
new file mode 100644
index 0000000..adb8428
--- /dev/null
+++ b/target-arm/helper-a64.c
@@ -0,0 +1,25 @@
+/*
+ * AArch64 specific helpers
+ *
+ * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "exec/gdbstub.h"
+#include "helper.h"
+#include "qemu/host-utils.h"
+#include "sysemu/sysemu.h"
+#include "qemu/bitops.h"
diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h
new file mode 100644
index 0000000..dd28306
--- /dev/null
+++ b/target-arm/helper-a64.h
@@ -0,0 +1,18 @@
+/*
+ * AArch64 specific helper definitions
+ *
+ * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
diff --git a/target-arm/helper.h b/target-arm/helper.h
index 496eb65..73d67dc 100644
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -466,4 +466,8 @@ DEF_HELPER_3(neon_qzip32, void, env, i32, i32)
DEF_HELPER_4(crypto_aese, void, env, i32, i32, i32)
DEF_HELPER_4(crypto_aesmc, void, env, i32, i32, i32)
+#ifdef TARGET_AARCH64
+#include "helper-a64.h"
+#endif
+
#include "exec/def-helper.h"
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 31/62] target-arm: A64: provide skeleton for a64 insn decoding
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (29 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 30/62] target-arm: A64: add stubs for a64 specific helpers Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 32/62] target-arm: A64: expand decoding skeleton for system instructions Peter Maydell
` (31 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Claudio Fontana <claudio.fontana@linaro.org>
Provide a skeleton for a64 instruction decoding in translate-a64.c,
by dividing instructions into the classes defined by the
ARM Architecture Reference Manual(DDI0487A_a) section C3.
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 370 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 362 insertions(+), 8 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index a713137..8e16cb1 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -146,17 +146,348 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
}
}
-static void real_unallocated_encoding(DisasContext *s)
+static void unallocated_encoding(DisasContext *s)
{
- fprintf(stderr, "Unknown instruction: %#x\n", s->insn);
gen_exception_insn(s, 4, EXCP_UDEF);
}
-#define unallocated_encoding(s) do { \
- fprintf(stderr, "unallocated encoding at line: %d\n", __LINE__); \
- real_unallocated_encoding(s); \
- } while (0)
+#define unsupported_encoding(s, insn) \
+ do { \
+ qemu_log_mask(LOG_UNIMP, \
+ "%s:%d: unsupported instruction encoding 0x%08x " \
+ "at pc=%016" PRIx64 "\n", \
+ __FILE__, __LINE__, insn, s->pc - 4); \
+ unallocated_encoding(s); \
+ } while (0);
+/*
+ * the instruction disassembly implemented here matches
+ * the instruction encoding classifications in chapter 3 (C3)
+ * of the ARM Architecture Reference Manual (DDI0487A_a)
+ */
+
+/* Unconditional branch (immediate) */
+static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Compare & branch (immediate) */
+static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Test & branch (immediate) */
+static void disas_test_b_imm(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Conditional branch (immediate) */
+static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* System */
+static void disas_system(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Exception generation */
+static void disas_exc(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Unconditional branch (register) */
+static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* C3.2 Branches, exception generating and system instructions */
+static void disas_b_exc_sys(DisasContext *s, uint32_t insn)
+{
+ switch (extract32(insn, 25, 7)) {
+ case 0x0a: case 0x0b:
+ case 0x4a: case 0x4b: /* Unconditional branch (immediate) */
+ disas_uncond_b_imm(s, insn);
+ break;
+ case 0x1a: case 0x5a: /* Compare & branch (immediate) */
+ disas_comp_b_imm(s, insn);
+ break;
+ case 0x1b: case 0x5b: /* Test & branch (immediate) */
+ disas_test_b_imm(s, insn);
+ break;
+ case 0x2a: /* Conditional branch (immediate) */
+ disas_cond_b_imm(s, insn);
+ break;
+ case 0x6a: /* Exception generation / System */
+ if (insn & (1 << 24)) {
+ disas_system(s, insn);
+ } else {
+ disas_exc(s, insn);
+ }
+ break;
+ case 0x6b: /* Unconditional branch (register) */
+ disas_uncond_b_reg(s, insn);
+ break;
+ default:
+ unallocated_encoding(s);
+ break;
+ }
+}
+
+/* Load/store exclusive */
+static void disas_ldst_excl(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Load register (literal) */
+static void disas_ld_lit(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Load/store pair (all forms) */
+static void disas_ldst_pair(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Load/store register (all forms) */
+static void disas_ldst_reg(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* AdvSIMD load/store multiple structures */
+static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* AdvSIMD load/store single structure */
+static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* C3.3 Loads and stores */
+static void disas_ldst(DisasContext *s, uint32_t insn)
+{
+ switch (extract32(insn, 24, 6)) {
+ case 0x08: /* Load/store exclusive */
+ disas_ldst_excl(s, insn);
+ break;
+ case 0x18: case 0x1c: /* Load register (literal) */
+ disas_ld_lit(s, insn);
+ break;
+ case 0x28: case 0x29:
+ case 0x2c: case 0x2d: /* Load/store pair (all forms) */
+ disas_ldst_pair(s, insn);
+ break;
+ case 0x38: case 0x39:
+ case 0x3c: case 0x3d: /* Load/store register (all forms) */
+ disas_ldst_reg(s, insn);
+ break;
+ case 0x0c: /* AdvSIMD load/store multiple structures */
+ disas_ldst_multiple_struct(s, insn);
+ break;
+ case 0x0d: /* AdvSIMD load/store single structure */
+ disas_ldst_single_struct(s, insn);
+ break;
+ default:
+ unallocated_encoding(s);
+ break;
+ }
+}
+
+/* PC-rel. addressing */
+static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Add/subtract (immediate) */
+static void disas_add_sub_imm(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Logical (immediate) */
+static void disas_logic_imm(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Move wide (immediate) */
+static void disas_movw_imm(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Bitfield */
+static void disas_bitfield(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Extract */
+static void disas_extract(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* C3.4 Data processing - immediate */
+static void disas_data_proc_imm(DisasContext *s, uint32_t insn)
+{
+ switch (extract32(insn, 23, 6)) {
+ case 0x20: case 0x21: /* PC-rel. addressing */
+ disas_pc_rel_adr(s, insn);
+ break;
+ case 0x22: case 0x23: /* Add/subtract (immediate) */
+ disas_add_sub_imm(s, insn);
+ break;
+ case 0x24: /* Logical (immediate) */
+ disas_logic_imm(s, insn);
+ break;
+ case 0x25: /* Move wide (immediate) */
+ disas_movw_imm(s, insn);
+ break;
+ case 0x26: /* Bitfield */
+ disas_bitfield(s, insn);
+ break;
+ case 0x27: /* Extract */
+ disas_extract(s, insn);
+ break;
+ default:
+ unallocated_encoding(s);
+ break;
+ }
+}
+
+/* Logical (shifted register) */
+static void disas_logic_reg(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Add/subtract (extended register) */
+static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Add/subtract (shifted register) */
+static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Data-processing (3 source) */
+static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Add/subtract (with carry) */
+static void disas_adc_sbc(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Conditional compare (immediate) */
+static void disas_cc_imm(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Conditional compare (register) */
+static void disas_cc_reg(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Conditional select */
+static void disas_cond_select(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Data-processing (1 source) */
+static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* Data-processing (2 source) */
+static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* C3.5 Data processing - register */
+static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
+{
+ switch (extract32(insn, 24, 5)) {
+ case 0x0a: /* Logical (shifted register) */
+ disas_logic_reg(s, insn);
+ break;
+ case 0x0b: /* Add/subtract */
+ if (insn & (1 << 21)) { /* (extended register) */
+ disas_add_sub_ext_reg(s, insn);
+ } else {
+ disas_add_sub_reg(s, insn);
+ }
+ break;
+ case 0x1b: /* Data-processing (3 source) */
+ disas_data_proc_3src(s, insn);
+ break;
+ case 0x1a:
+ switch (extract32(insn, 21, 3)) {
+ case 0x0: /* Add/subtract (with carry) */
+ disas_adc_sbc(s, insn);
+ break;
+ case 0x2: /* Conditional compare */
+ if (insn & (1 << 11)) { /* (immediate) */
+ disas_cc_imm(s, insn);
+ } else { /* (register) */
+ disas_cc_reg(s, insn);
+ }
+ break;
+ case 0x4: /* Conditional select */
+ disas_cond_select(s, insn);
+ break;
+ case 0x6: /* Data-processing */
+ if (insn & (1 << 30)) { /* (1 source) */
+ disas_data_proc_1src(s, insn);
+ } else { /* (2 source) */
+ disas_data_proc_2src(s, insn);
+ }
+ break;
+ default:
+ unallocated_encoding(s);
+ break;
+ }
+ break;
+ default:
+ unallocated_encoding(s);
+ break;
+ }
+}
+
+/* C3.6 Data processing - SIMD and floating point */
+static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* C3.1 A64 instruction index by encoding */
static void disas_a64_insn(CPUARMState *env, DisasContext *s)
{
uint32_t insn;
@@ -165,10 +496,33 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
s->insn = insn;
s->pc += 4;
- switch ((insn >> 24) & 0x1f) {
- default:
+ switch (extract32(insn, 25, 4)) {
+ case 0x0: case 0x1: case 0x2: case 0x3: /* UNALLOCATED */
unallocated_encoding(s);
break;
+ case 0x8: case 0x9: /* Data processing - immediate */
+ disas_data_proc_imm(s, insn);
+ break;
+ case 0xa: case 0xb: /* Branch, exception generation and system insns */
+ disas_b_exc_sys(s, insn);
+ break;
+ case 0x4:
+ case 0x6:
+ case 0xc:
+ case 0xe: /* Loads and stores */
+ disas_ldst(s, insn);
+ break;
+ case 0x5:
+ case 0xd: /* Data processing - register */
+ disas_data_proc_reg(s, insn);
+ break;
+ case 0x7:
+ case 0xf: /* Data processing - SIMD and floating point */
+ disas_data_proc_simd_fp(s, insn);
+ break;
+ default:
+ assert(FALSE); /* all 15 cases should be handled above */
+ break;
}
}
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 32/62] target-arm: A64: expand decoding skeleton for system instructions
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (30 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 31/62] target-arm: A64: provide skeleton for a64 insn decoding Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 33/62] target-arm: A64: add support for B and BL insns Peter Maydell
` (30 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Claudio Fontana <claudio.fontana@linaro.org>
Decode the various kinds of system instructions:
hints (HINT), which include NOP, YIELD, WFE, WFI, SEV, SEL
sync instructions, which include CLREX, DSB, DMB, ISB
msr_i, which move immediate to processor state field
sys, which include all SYS and SYSL instructions
msr, which move from a gp register to a system register
mrs, which move from a system register to a gp register
Provide implementations where they are trivial nops.
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 131 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 129 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 8e16cb1..1e2b371 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -190,12 +190,139 @@ static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
unsupported_encoding(s, insn);
}
-/* System */
-static void disas_system(DisasContext *s, uint32_t insn)
+/* C5.6.68 HINT */
+static void handle_hint(DisasContext *s, uint32_t insn,
+ unsigned int op1, unsigned int op2, unsigned int crm)
+{
+ unsigned int selector = crm << 3 | op2;
+
+ if (op1 != 3) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ switch (selector) {
+ case 0: /* NOP */
+ return;
+ case 1: /* YIELD */
+ case 2: /* WFE */
+ case 3: /* WFI */
+ case 4: /* SEV */
+ case 5: /* SEVL */
+ /* we treat all as NOP at least for now */
+ return;
+ default:
+ /* default specified as NOP equivalent */
+ return;
+ }
+}
+
+/* CLREX, DSB, DMB, ISB */
+static void handle_sync(DisasContext *s, uint32_t insn,
+ unsigned int op1, unsigned int op2, unsigned int crm)
+{
+ if (op1 != 3) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ switch (op2) {
+ case 2: /* CLREX */
+ unsupported_encoding(s, insn);
+ return;
+ case 4: /* DSB */
+ case 5: /* DMB */
+ case 6: /* ISB */
+ /* We don't emulate caches so barriers are no-ops */
+ return;
+ default:
+ unallocated_encoding(s);
+ return;
+ }
+}
+
+/* C5.6.130 MSR (immediate) - move immediate to processor state field */
+static void handle_msr_i(DisasContext *s, uint32_t insn,
+ unsigned int op1, unsigned int op2, unsigned int crm)
{
unsupported_encoding(s, insn);
}
+/* C5.6.204 SYS */
+static void handle_sys(DisasContext *s, uint32_t insn, unsigned int l,
+ unsigned int op1, unsigned int op2,
+ unsigned int crn, unsigned int crm, unsigned int rt)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* C5.6.129 MRS - move from system register */
+static void handle_mrs(DisasContext *s, uint32_t insn, unsigned int op0,
+ unsigned int op1, unsigned int op2,
+ unsigned int crn, unsigned int crm, unsigned int rt)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* C5.6.131 MSR (register) - move to system register */
+static void handle_msr(DisasContext *s, uint32_t insn, unsigned int op0,
+ unsigned int op1, unsigned int op2,
+ unsigned int crn, unsigned int crm, unsigned int rt)
+{
+ unsupported_encoding(s, insn);
+}
+
+/* C3.2.4 System
+ * 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
+ * +---------------------+---+-----+-----+-------+-------+-----+------+
+ * | 1 1 0 1 0 1 0 1 0 0 | L | op0 | op1 | CRn | CRm | op2 | Rt |
+ * +---------------------+---+-----+-----+-------+-------+-----+------+
+ */
+static void disas_system(DisasContext *s, uint32_t insn)
+{
+ unsigned int l, op0, op1, crn, crm, op2, rt;
+ l = extract32(insn, 21, 1);
+ op0 = extract32(insn, 19, 2);
+ op1 = extract32(insn, 16, 3);
+ crn = extract32(insn, 12, 4);
+ crm = extract32(insn, 8, 4);
+ op2 = extract32(insn, 5, 3);
+ rt = extract32(insn, 0, 5);
+
+ if (op0 == 0) {
+ if (l || rt != 31) {
+ unallocated_encoding(s);
+ return;
+ }
+ switch (crn) {
+ case 2: /* C5.6.68 HINT */
+ handle_hint(s, insn, op1, op2, crm);
+ break;
+ case 3: /* CLREX, DSB, DMB, ISB */
+ handle_sync(s, insn, op1, op2, crm);
+ break;
+ case 4: /* C5.6.130 MSR (immediate) */
+ handle_msr_i(s, insn, op1, op2, crm);
+ break;
+ default:
+ unallocated_encoding(s);
+ break;
+ }
+ return;
+ }
+
+ if (op0 == 1) {
+ /* C5.6.204 SYS */
+ handle_sys(s, insn, l, op1, op2, crn, crm, rt);
+ } else if (l) { /* op0 > 1 */
+ /* C5.6.129 MRS - move from system register */
+ handle_mrs(s, insn, op0, op1, op2, crn, crm, rt);
+ } else {
+ /* C5.6.131 MSR (register) - move to system register */
+ handle_msr(s, insn, op0, op1, op2, crn, crm, rt);
+ }
+}
+
/* Exception generation */
static void disas_exc(DisasContext *s, uint32_t insn)
{
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 33/62] target-arm: A64: add support for B and BL insns
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (31 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 32/62] target-arm: A64: expand decoding skeleton for system instructions Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 34/62] target-arm: A64: add support for BR, BLR and RET insns Peter Maydell
` (29 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
Implement the B and BL instructions (PC relative branches and calls).
For convenience in managing TCG temporaries which might be generated
if a source register is the zero-register XZR, we provide a simple
mechanism for creating a new temp which is automatically freed at the
end of decode of the instruction.
Signed-off-by: Alexander Graf <agraf@suse.de>
[claudio: renamed functions, adapted to new decoder layout]
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 64 ++++++++++++++++++++++++++++++++++++++++++++--
target-arm/translate.h | 3 +++
2 files changed, 65 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 1e2b371..ead5658 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -160,16 +160,71 @@ static void unallocated_encoding(DisasContext *s)
unallocated_encoding(s); \
} while (0);
+static void init_tmp_a64_array(DisasContext *s)
+{
+#ifdef CONFIG_DEBUG_TCG
+ int i;
+ for (i = 0; i < ARRAY_SIZE(s->tmp_a64); i++) {
+ TCGV_UNUSED_I64(s->tmp_a64[i]);
+ }
+#endif
+ s->tmp_a64_count = 0;
+}
+
+static void free_tmp_a64(DisasContext *s)
+{
+ int i;
+ for (i = 0; i < s->tmp_a64_count; i++) {
+ tcg_temp_free_i64(s->tmp_a64[i]);
+ }
+ init_tmp_a64_array(s);
+}
+
+static TCGv_i64 new_tmp_a64(DisasContext *s)
+{
+ assert(s->tmp_a64_count < TMP_A64_MAX);
+ return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_new_i64();
+}
+
+static TCGv_i64 new_tmp_a64_zero(DisasContext *s)
+{
+ TCGv_i64 t = new_tmp_a64(s);
+ tcg_gen_movi_i64(t, 0);
+ return t;
+}
+
+static TCGv_i64 cpu_reg(DisasContext *s, int reg)
+{
+ if (reg == 31) {
+ return new_tmp_a64_zero(s);
+ } else {
+ return cpu_X[reg];
+ }
+}
+
/*
* the instruction disassembly implemented here matches
* the instruction encoding classifications in chapter 3 (C3)
* of the ARM Architecture Reference Manual (DDI0487A_a)
*/
-/* Unconditional branch (immediate) */
+/* C3.2.7 Unconditional branch (immediate)
+ * 31 30 26 25 0
+ * +----+-----------+-------------------------------------+
+ * | op | 0 0 1 0 1 | imm26 |
+ * +----+-----------+-------------------------------------+
+ */
static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ uint64_t addr = s->pc + sextract32(insn, 0, 26) * 4 - 4;
+
+ if (insn & (1 << 31)) {
+ /* C5.6.26 BL Branch with link */
+ tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
+ }
+
+ /* C5.6.20 B Branch / C5.6.26 BL Branch with link */
+ gen_goto_tb(s, 0, addr);
}
/* Compare & branch (immediate) */
@@ -651,6 +706,9 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
assert(FALSE); /* all 15 cases should be handled above */
break;
}
+
+ /* if we allocated any temporaries, free them here */
+ free_tmp_a64(s);
}
void gen_intermediate_code_internal_a64(ARMCPU *cpu,
@@ -691,6 +749,8 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
dc->vec_len = 0;
dc->vec_stride = 0;
+ init_tmp_a64_array(dc);
+
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
lj = -1;
num_insns = 0;
diff --git a/target-arm/translate.h b/target-arm/translate.h
index 8789181..23a45da 100644
--- a/target-arm/translate.h
+++ b/target-arm/translate.h
@@ -24,6 +24,9 @@ typedef struct DisasContext {
int vec_len;
int vec_stride;
int aarch64;
+#define TMP_A64_MAX 16
+ int tmp_a64_count;
+ TCGv_i64 tmp_a64[TMP_A64_MAX];
} DisasContext;
extern TCGv_ptr cpu_env;
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 34/62] target-arm: A64: add support for BR, BLR and RET insns
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (32 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 33/62] target-arm: A64: add support for B and BL insns Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 35/62] target-arm: A64: add support for conditional branches Peter Maydell
` (28 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
Implement BR, BLR and RET. This is all of the 'unconditional
branch (register)' instruction category except for ERET
and DPRS (which are system mode only).
Signed-off-by: Alexander Graf <agraf@suse.de>
[claudio: reimplemented on top of new decoder structure]
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 43 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 41 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index ead5658..b694665 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -384,10 +384,49 @@ static void disas_exc(DisasContext *s, uint32_t insn)
unsupported_encoding(s, insn);
}
-/* Unconditional branch (register) */
+/* C3.2.7 Unconditional branch (register)
+ * 31 25 24 21 20 16 15 10 9 5 4 0
+ * +---------------+-------+-------+-------+------+-------+
+ * | 1 1 0 1 0 1 1 | opc | op2 | op3 | Rn | op4 |
+ * +---------------+-------+-------+-------+------+-------+
+ */
static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ unsigned int opc, op2, op3, rn, op4;
+
+ opc = extract32(insn, 21, 4);
+ op2 = extract32(insn, 16, 5);
+ op3 = extract32(insn, 10, 6);
+ rn = extract32(insn, 5, 5);
+ op4 = extract32(insn, 0, 5);
+
+ if (op4 != 0x0 || op3 != 0x0 || op2 != 0x1f) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ switch (opc) {
+ case 0: /* BR */
+ case 2: /* RET */
+ break;
+ case 1: /* BLR */
+ tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
+ break;
+ case 4: /* ERET */
+ case 5: /* DRPS */
+ if (rn != 0x1f) {
+ unallocated_encoding(s);
+ } else {
+ unsupported_encoding(s, insn);
+ }
+ return;
+ default:
+ unallocated_encoding(s);
+ return;
+ }
+
+ tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn));
+ s->is_jmp = DISAS_JUMP;
}
/* C3.2 Branches, exception generating and system instructions */
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 35/62] target-arm: A64: add support for conditional branches
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (33 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 34/62] target-arm: A64: add support for BR, BLR and RET insns Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 36/62] target-arm: A64: add support for 'test and branch' imm Peter Maydell
` (27 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
This patch adds emulation for the conditional branch (b.cond) instruction.
Signed-off-by: Alexander Graf <agraf@suse.de>
[claudio: adapted to new decoder structure,
reused arm infrastructure for checking the flags]
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 29 +++++++++++++++++++++++++++--
target-arm/translate.c | 14 +++++++++-----
target-arm/translate.h | 2 ++
3 files changed, 38 insertions(+), 7 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index b694665..4eb2992 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -239,10 +239,35 @@ static void disas_test_b_imm(DisasContext *s, uint32_t insn)
unsupported_encoding(s, insn);
}
-/* Conditional branch (immediate) */
+/* C3.2.2 / C5.6.19 Conditional branch (immediate)
+ * 31 25 24 23 5 4 3 0
+ * +---------------+----+---------------------+----+------+
+ * | 0 1 0 1 0 1 0 | o1 | imm19 | o0 | cond |
+ * +---------------+----+---------------------+----+------+
+ */
static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ unsigned int cond;
+ uint64_t addr;
+
+ if ((insn & (1 << 4)) || (insn & (1 << 24))) {
+ unallocated_encoding(s);
+ return;
+ }
+ addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
+ cond = extract32(insn, 0, 4);
+
+ if (cond < 0x0e) {
+ /* genuinely conditional branches */
+ int label_match = gen_new_label();
+ arm_gen_test_cc(cond, label_match);
+ gen_goto_tb(s, 0, s->pc);
+ gen_set_label(label_match);
+ gen_goto_tb(s, 1, addr);
+ } else {
+ /* 0xe and 0xf are both "always" conditions */
+ gen_goto_tb(s, 0, addr);
+ }
}
/* C5.6.68 HINT */
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 679b3c3..1403ecf 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -671,7 +671,11 @@ static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b)
}
#undef PAS_OP
-static void gen_test_cc(int cc, int label)
+/*
+ * generate a conditional branch based on ARM condition code cc.
+ * This is common between ARM and Aarch64 targets.
+ */
+void arm_gen_test_cc(int cc, int label)
{
TCGv_i32 tmp;
int inv;
@@ -7131,7 +7135,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
/* if not always execute, we generate a conditional jump to
next instruction */
s->condlabel = gen_new_label();
- gen_test_cc(cond ^ 1, s->condlabel);
+ arm_gen_test_cc(cond ^ 1, s->condlabel);
s->condjmp = 1;
}
if ((insn & 0x0f900000) == 0x03000000) {
@@ -9148,7 +9152,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
op = (insn >> 22) & 0xf;
/* Generate a conditional jump to next instruction. */
s->condlabel = gen_new_label();
- gen_test_cc(op ^ 1, s->condlabel);
+ arm_gen_test_cc(op ^ 1, s->condlabel);
s->condjmp = 1;
/* offset[11:1] = insn[10:0] */
@@ -9505,7 +9509,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
cond = s->condexec_cond;
if (cond != 0x0e) { /* Skip conditional when condition is AL. */
s->condlabel = gen_new_label();
- gen_test_cc(cond ^ 1, s->condlabel);
+ arm_gen_test_cc(cond ^ 1, s->condlabel);
s->condjmp = 1;
}
}
@@ -10178,7 +10182,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
}
/* generate a conditional jump to next instruction */
s->condlabel = gen_new_label();
- gen_test_cc(cond ^ 1, s->condlabel);
+ arm_gen_test_cc(cond ^ 1, s->condlabel);
s->condjmp = 1;
/* jump to the offset */
diff --git a/target-arm/translate.h b/target-arm/translate.h
index 23a45da..a6f6b3e 100644
--- a/target-arm/translate.h
+++ b/target-arm/translate.h
@@ -65,4 +65,6 @@ static inline void gen_a64_set_pc_im(uint64_t val)
}
#endif
+void arm_gen_test_cc(int cc, int label);
+
#endif /* TARGET_ARM_TRANSLATE_H */
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 36/62] target-arm: A64: add support for 'test and branch' imm
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (34 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 35/62] target-arm: A64: add support for conditional branches Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 37/62] target-arm: A64: add support for compare and branch imm Peter Maydell
` (26 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
This patch adds emulation for the test and branch insns,
TBZ and TBNZ.
Signed-off-by: Alexander Graf <agraf@suse.de>
[claudio:
adapted for new decoder
always compare with 0
remove a TCG temporary
]
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 4eb2992..1d04303 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -233,10 +233,33 @@ static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
unsupported_encoding(s, insn);
}
-/* Test & branch (immediate) */
+/* C3.2.5 Test & branch (immediate)
+ * 31 30 25 24 23 19 18 5 4 0
+ * +----+-------------+----+-------+-------------+------+
+ * | b5 | 0 1 1 0 1 1 | op | b40 | imm14 | Rt |
+ * +----+-------------+----+-------+-------------+------+
+ */
static void disas_test_b_imm(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ unsigned int bit_pos, op, rt;
+ uint64_t addr;
+ int label_match;
+ TCGv_i64 tcg_cmp;
+
+ bit_pos = (extract32(insn, 31, 1) << 5) | extract32(insn, 19, 5);
+ op = extract32(insn, 24, 1); /* 0: TBZ; 1: TBNZ */
+ addr = s->pc + sextract32(insn, 5, 14) * 4 - 4;
+ rt = extract32(insn, 0, 5);
+
+ tcg_cmp = tcg_temp_new_i64();
+ tcg_gen_andi_i64(tcg_cmp, cpu_reg(s, rt), (1ULL << bit_pos));
+ label_match = gen_new_label();
+ tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
+ tcg_cmp, 0, label_match);
+ tcg_temp_free_i64(tcg_cmp);
+ gen_goto_tb(s, 0, s->pc);
+ gen_set_label(label_match);
+ gen_goto_tb(s, 1, addr);
}
/* C3.2.2 / C5.6.19 Conditional branch (immediate)
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 37/62] target-arm: A64: add support for compare and branch imm
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (35 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 36/62] target-arm: A64: add support for 'test and branch' imm Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 38/62] target-arm: A64: add support for conditional select Peter Maydell
` (25 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
This patch adds emulation for the compare and branch insns,
CBZ and CBNZ.
Signed-off-by: Alexander Graf <agraf@suse.de>
[claudio: adapted to new decoder,
compare with immediate 0,
introduce read_cpu_reg to get the 0 extension on (!sf)]
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 46 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 1d04303..5ae3a85 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -202,6 +202,25 @@ static TCGv_i64 cpu_reg(DisasContext *s, int reg)
}
}
+/* read a cpu register in 32bit/64bit mode. Returns a TCGv_i64
+ * representing the register contents. This TCGv is an auto-freed
+ * temporary so it need not be explicitly freed, and may be modified.
+ */
+static TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf)
+{
+ TCGv_i64 v = new_tmp_a64(s);
+ if (reg != 31) {
+ if (sf) {
+ tcg_gen_mov_i64(v, cpu_X[reg]);
+ } else {
+ tcg_gen_ext32u_i64(v, cpu_X[reg]);
+ }
+ } else {
+ tcg_gen_movi_i64(v, 0);
+ }
+ return v;
+}
+
/*
* the instruction disassembly implemented here matches
* the instruction encoding classifications in chapter 3 (C3)
@@ -227,10 +246,33 @@ static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
gen_goto_tb(s, 0, addr);
}
-/* Compare & branch (immediate) */
+/* C3.2.1 Compare & branch (immediate)
+ * 31 30 25 24 23 5 4 0
+ * +----+-------------+----+---------------------+--------+
+ * | sf | 0 1 1 0 1 0 | op | imm19 | Rt |
+ * +----+-------------+----+---------------------+--------+
+ */
static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ unsigned int sf, op, rt;
+ uint64_t addr;
+ int label_match;
+ TCGv_i64 tcg_cmp;
+
+ sf = extract32(insn, 31, 1);
+ op = extract32(insn, 24, 1); /* 0: CBZ; 1: CBNZ */
+ rt = extract32(insn, 0, 5);
+ addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
+
+ tcg_cmp = read_cpu_reg(s, rt, sf);
+ label_match = gen_new_label();
+
+ tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
+ tcg_cmp, 0, label_match);
+
+ gen_goto_tb(s, 0, s->pc);
+ gen_set_label(label_match);
+ gen_goto_tb(s, 1, addr);
}
/* C3.2.5 Test & branch (immediate)
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 38/62] target-arm: A64: add support for conditional select
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (36 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 37/62] target-arm: A64: add support for compare and branch imm Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 39/62] target-arm: A64: add support for logical (shifted register) Peter Maydell
` (24 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Claudio Fontana <claudio.fontana@linaro.org>
This patch adds support for the instruction group "C3.5.6
Conditional select": CSEL, CSINC, CSINV, CSNEG.
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
[PMM: Improved code generated in the nomatch case as per RTH suggestions]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 67 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 65 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 5ae3a85..13eedf4 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -724,10 +724,73 @@ static void disas_cc_reg(DisasContext *s, uint32_t insn)
unsupported_encoding(s, insn);
}
-/* Conditional select */
+/* C3.5.6 Conditional select
+ * 31 30 29 28 21 20 16 15 12 11 10 9 5 4 0
+ * +----+----+---+-----------------+------+------+-----+------+------+
+ * | sf | op | S | 1 1 0 1 0 1 0 0 | Rm | cond | op2 | Rn | Rd |
+ * +----+----+---+-----------------+------+------+-----+------+------+
+ */
static void disas_cond_select(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ unsigned int sf, else_inv, rm, cond, else_inc, rn, rd;
+ TCGv_i64 tcg_rd, tcg_src;
+
+ if (extract32(insn, 29, 1) || extract32(insn, 11, 1)) {
+ /* S == 1 or op2<1> == 1 */
+ unallocated_encoding(s);
+ return;
+ }
+ sf = extract32(insn, 31, 1);
+ else_inv = extract32(insn, 30, 1);
+ rm = extract32(insn, 16, 5);
+ cond = extract32(insn, 12, 4);
+ else_inc = extract32(insn, 10, 1);
+ rn = extract32(insn, 5, 5);
+ rd = extract32(insn, 0, 5);
+
+ if (rd == 31) {
+ /* silly no-op write; until we use movcond we must special-case
+ * this to avoid a dead temporary across basic blocks.
+ */
+ return;
+ }
+
+ tcg_rd = cpu_reg(s, rd);
+
+ if (cond >= 0x0e) { /* condition "always" */
+ tcg_src = read_cpu_reg(s, rn, sf);
+ tcg_gen_mov_i64(tcg_rd, tcg_src);
+ } else {
+ /* OPTME: we could use movcond here, at the cost of duplicating
+ * a lot of the arm_gen_test_cc() logic.
+ */
+ int label_match = gen_new_label();
+ int label_continue = gen_new_label();
+
+ arm_gen_test_cc(cond, label_match);
+ /* nomatch: */
+ tcg_src = cpu_reg(s, rm);
+
+ if (else_inv && else_inc) {
+ tcg_gen_neg_i64(tcg_rd, tcg_src);
+ } else if (else_inv) {
+ tcg_gen_not_i64(tcg_rd, tcg_src);
+ } else if (else_inc) {
+ tcg_gen_addi_i64(tcg_rd, tcg_src, 1);
+ } else {
+ tcg_gen_mov_i64(tcg_rd, tcg_src);
+ }
+ if (!sf) {
+ tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
+ }
+ tcg_gen_br(label_continue);
+ /* match: */
+ gen_set_label(label_match);
+ tcg_src = read_cpu_reg(s, rn, sf);
+ tcg_gen_mov_i64(tcg_rd, tcg_src);
+ /* continue: */
+ gen_set_label(label_continue);
+ }
}
/* Data-processing (1 source) */
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 39/62] target-arm: A64: add support for logical (shifted register)
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (37 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 38/62] target-arm: A64: add support for conditional select Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 40/62] target-arm: A64: add support for ADR and ADRP Peter Maydell
` (23 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
Add support for the instructions described in "C3.5.10 Logical
(shifted register)".
We store the flags in the same locations as the 32 bit decoder.
This is slightly awkward when calculating 64 bit results, but seems
a better tradeoff than having to rework the whole 32 bit decoder
and also make 32 bit result calculation in A64 awkward.
Signed-off-by: Alexander Graf <agraf@suse.de>
[claudio: some refactoring to avoid hidden allocation of temps,
rework flags, use enums for shift types,
renaming of functions]
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
[PMM: Use TCG's andc/orc/eqv ops rather than manually inverting]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 197 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 191 insertions(+), 6 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 13eedf4..a459ce6 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -36,7 +36,7 @@
static TCGv_i64 cpu_X[32];
static TCGv_i64 cpu_pc;
-static TCGv_i32 pstate;
+static TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
static const char *regnames[] = {
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
@@ -45,6 +45,13 @@ static const char *regnames[] = {
"x24", "x25", "x26", "x27", "x28", "x29", "lr", "sp"
};
+enum a64_shift_type {
+ A64_SHIFT_TYPE_LSL = 0,
+ A64_SHIFT_TYPE_LSR = 1,
+ A64_SHIFT_TYPE_ASR = 2,
+ A64_SHIFT_TYPE_ROR = 3
+};
+
/* initialize TCG globals. */
void a64_translate_init(void)
{
@@ -59,9 +66,10 @@ void a64_translate_init(void)
regnames[i]);
}
- pstate = tcg_global_mem_new_i32(TCG_AREG0,
- offsetof(CPUARMState, pstate),
- "pstate");
+ cpu_NF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, NF), "NF");
+ cpu_ZF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, ZF), "ZF");
+ cpu_CF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, CF), "CF");
+ cpu_VF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, VF), "VF");
}
void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
@@ -221,6 +229,33 @@ static TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf)
return v;
}
+/* Set ZF and NF based on a 64 bit result. This is alas fiddlier
+ * than the 32 bit equivalent.
+ */
+static inline void gen_set_NZ64(TCGv_i64 result)
+{
+ TCGv_i64 flag = tcg_temp_new_i64();
+
+ tcg_gen_setcondi_i64(TCG_COND_NE, flag, result, 0);
+ tcg_gen_trunc_i64_i32(cpu_ZF, flag);
+ tcg_gen_shri_i64(flag, result, 32);
+ tcg_gen_trunc_i64_i32(cpu_NF, flag);
+ tcg_temp_free_i64(flag);
+}
+
+/* Set NZCV as for a logical operation: NZ as per result, CV cleared. */
+static inline void gen_logic_CC(int sf, TCGv_i64 result)
+{
+ if (sf) {
+ gen_set_NZ64(result);
+ } else {
+ tcg_gen_trunc_i64_i32(cpu_ZF, result);
+ tcg_gen_trunc_i64_i32(cpu_NF, result);
+ }
+ tcg_gen_movi_i32(cpu_CF, 0);
+ tcg_gen_movi_i32(cpu_VF, 0);
+}
+
/*
* the instruction disassembly implemented here matches
* the instruction encoding classifications in chapter 3 (C3)
@@ -682,10 +717,160 @@ static void disas_data_proc_imm(DisasContext *s, uint32_t insn)
}
}
-/* Logical (shifted register) */
+/* Shift a TCGv src by TCGv shift_amount, put result in dst.
+ * Note that it is the caller's responsibility to ensure that the
+ * shift amount is in range (ie 0..31 or 0..63) and provide the ARM
+ * mandated semantics for out of range shifts.
+ */
+static void shift_reg(TCGv_i64 dst, TCGv_i64 src, int sf,
+ enum a64_shift_type shift_type, TCGv_i64 shift_amount)
+{
+ switch (shift_type) {
+ case A64_SHIFT_TYPE_LSL:
+ tcg_gen_shl_i64(dst, src, shift_amount);
+ break;
+ case A64_SHIFT_TYPE_LSR:
+ tcg_gen_shr_i64(dst, src, shift_amount);
+ break;
+ case A64_SHIFT_TYPE_ASR:
+ if (!sf) {
+ tcg_gen_ext32s_i64(dst, src);
+ }
+ tcg_gen_sar_i64(dst, sf ? src : dst, shift_amount);
+ break;
+ case A64_SHIFT_TYPE_ROR:
+ if (sf) {
+ tcg_gen_rotr_i64(dst, src, shift_amount);
+ } else {
+ TCGv_i32 t0, t1;
+ t0 = tcg_temp_new_i32();
+ t1 = tcg_temp_new_i32();
+ tcg_gen_trunc_i64_i32(t0, src);
+ tcg_gen_trunc_i64_i32(t1, shift_amount);
+ tcg_gen_rotr_i32(t0, t0, t1);
+ tcg_gen_extu_i32_i64(dst, t0);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+ }
+ break;
+ default:
+ assert(FALSE); /* all shift types should be handled */
+ break;
+ }
+
+ if (!sf) { /* zero extend final result */
+ tcg_gen_ext32u_i64(dst, dst);
+ }
+}
+
+/* Shift a TCGv src by immediate, put result in dst.
+ * The shift amount must be in range (this should always be true as the
+ * relevant instructions will UNDEF on bad shift immediates).
+ */
+static void shift_reg_imm(TCGv_i64 dst, TCGv_i64 src, int sf,
+ enum a64_shift_type shift_type, unsigned int shift_i)
+{
+ assert(shift_i < (sf ? 64 : 32));
+
+ if (shift_i == 0) {
+ tcg_gen_mov_i64(dst, src);
+ } else {
+ TCGv_i64 shift_const;
+
+ shift_const = tcg_const_i64(shift_i);
+ shift_reg(dst, src, sf, shift_type, shift_const);
+ tcg_temp_free_i64(shift_const);
+ }
+}
+
+/* C3.5.10 Logical (shifted register)
+ * 31 30 29 28 24 23 22 21 20 16 15 10 9 5 4 0
+ * +----+-----+-----------+-------+---+------+--------+------+------+
+ * | sf | opc | 0 1 0 1 0 | shift | N | Rm | imm6 | Rn | Rd |
+ * +----+-----+-----------+-------+---+------+--------+------+------+
+ */
static void disas_logic_reg(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ TCGv_i64 tcg_rd, tcg_rn, tcg_rm;
+ unsigned int sf, opc, shift_type, invert, rm, shift_amount, rn, rd;
+
+ sf = extract32(insn, 31, 1);
+ opc = extract32(insn, 29, 2);
+ shift_type = extract32(insn, 22, 2);
+ invert = extract32(insn, 21, 1);
+ rm = extract32(insn, 16, 5);
+ shift_amount = extract32(insn, 10, 6);
+ rn = extract32(insn, 5, 5);
+ rd = extract32(insn, 0, 5);
+
+ if (!sf && (shift_amount & (1 << 5))) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ tcg_rd = cpu_reg(s, rd);
+
+ if (opc == 1 && shift_amount == 0 && shift_type == 0 && rn == 31) {
+ /* Unshifted ORR and ORN with WZR/XZR is the standard encoding for
+ * register-register MOV and MVN, so it is worth special casing.
+ */
+ tcg_rm = cpu_reg(s, rm);
+ if (invert) {
+ tcg_gen_not_i64(tcg_rd, tcg_rm);
+ if (!sf) {
+ tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
+ }
+ } else {
+ if (sf) {
+ tcg_gen_mov_i64(tcg_rd, tcg_rm);
+ } else {
+ tcg_gen_ext32u_i64(tcg_rd, tcg_rm);
+ }
+ }
+ return;
+ }
+
+ tcg_rm = read_cpu_reg(s, rm, sf);
+
+ if (shift_amount) {
+ shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, shift_amount);
+ }
+
+ tcg_rn = cpu_reg(s, rn);
+
+ switch (opc | (invert << 2)) {
+ case 0: /* AND */
+ case 3: /* ANDS */
+ tcg_gen_and_i64(tcg_rd, tcg_rn, tcg_rm);
+ break;
+ case 1: /* ORR */
+ tcg_gen_or_i64(tcg_rd, tcg_rn, tcg_rm);
+ break;
+ case 2: /* EOR */
+ tcg_gen_xor_i64(tcg_rd, tcg_rn, tcg_rm);
+ break;
+ case 4: /* BIC */
+ case 7: /* BICS */
+ tcg_gen_andc_i64(tcg_rd, tcg_rn, tcg_rm);
+ break;
+ case 5: /* ORN */
+ tcg_gen_orc_i64(tcg_rd, tcg_rn, tcg_rm);
+ break;
+ case 6: /* EON */
+ tcg_gen_eqv_i64(tcg_rd, tcg_rn, tcg_rm);
+ break;
+ default:
+ assert(FALSE);
+ break;
+ }
+
+ if (!sf) {
+ tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
+ }
+
+ if (opc == 3) {
+ gen_logic_CC(sf, tcg_rd);
+ }
}
/* Add/subtract (extended register) */
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 40/62] target-arm: A64: add support for ADR and ADRP
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (38 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 39/62] target-arm: A64: add support for logical (shifted register) Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:28 ` [Qemu-devel] [PULL 41/62] target-arm: A64: add support for EXTR Peter Maydell
` (22 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
Add support for the instructions described in
"C3.4.6 PC-rel. addressing" (ADR and ADRP).
Signed-off-by: Alexander Graf <agraf@suse.de>
[claudio: adapted to new decoder structure]
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/translate-a64.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index a459ce6..9677d01 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -653,10 +653,31 @@ static void disas_ldst(DisasContext *s, uint32_t insn)
}
}
-/* PC-rel. addressing */
+/* C3.4.6 PC-rel. addressing
+ * 31 30 29 28 24 23 5 4 0
+ * +----+-------+-----------+-------------------+------+
+ * | op | immlo | 1 0 0 0 0 | immhi | Rd |
+ * +----+-------+-----------+-------------------+------+
+ */
static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ unsigned int page, rd;
+ uint64_t base;
+ int64_t offset;
+
+ page = extract32(insn, 31, 1);
+ /* SignExtend(immhi:immlo) -> offset */
+ offset = ((int64_t)sextract32(insn, 5, 19) << 2) | extract32(insn, 29, 2);
+ rd = extract32(insn, 0, 5);
+ base = s->pc - 4;
+
+ if (page) {
+ /* ADRP (page based) */
+ base &= ~0xfff;
+ offset <<= 12;
+ }
+
+ tcg_gen_movi_i64(cpu_reg(s, rd), base + offset);
}
/* Add/subtract (immediate) */
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 41/62] target-arm: A64: add support for EXTR
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (39 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 40/62] target-arm: A64: add support for ADR and ADRP Peter Maydell
@ 2013-12-17 20:28 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 42/62] target-arm: A64: add support for 2-src data processing and DIV Peter Maydell
` (21 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
This patch adds emulation support for the EXTR instruction.
Signed-off-by: Alexander Graf <agraf@suse.de>
[claudio: adapted for new decoder, removed a few temporaries,
fixed the 32bit bug, added checks for more
unallocated cases]
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 49 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 47 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 9677d01..f9336de 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -704,10 +704,55 @@ static void disas_bitfield(DisasContext *s, uint32_t insn)
unsupported_encoding(s, insn);
}
-/* Extract */
+/* C3.4.3 Extract
+ * 31 30 29 28 23 22 21 20 16 15 10 9 5 4 0
+ * +----+------+-------------+---+----+------+--------+------+------+
+ * | sf | op21 | 1 0 0 1 1 1 | N | o0 | Rm | imms | Rn | Rd |
+ * +----+------+-------------+---+----+------+--------+------+------+
+ */
static void disas_extract(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ unsigned int sf, n, rm, imm, rn, rd, bitsize, op21, op0;
+
+ sf = extract32(insn, 31, 1);
+ n = extract32(insn, 22, 1);
+ rm = extract32(insn, 16, 5);
+ imm = extract32(insn, 10, 6);
+ rn = extract32(insn, 5, 5);
+ rd = extract32(insn, 0, 5);
+ op21 = extract32(insn, 29, 2);
+ op0 = extract32(insn, 21, 1);
+ bitsize = sf ? 64 : 32;
+
+ if (sf != n || op21 || op0 || imm >= bitsize) {
+ unallocated_encoding(s);
+ } else {
+ TCGv_i64 tcg_rd, tcg_rm, tcg_rn;
+
+ tcg_rd = cpu_reg(s, rd);
+
+ if (imm) {
+ /* OPTME: we can special case rm==rn as a rotate */
+ tcg_rm = read_cpu_reg(s, rm, sf);
+ tcg_rn = read_cpu_reg(s, rn, sf);
+ tcg_gen_shri_i64(tcg_rm, tcg_rm, imm);
+ tcg_gen_shli_i64(tcg_rn, tcg_rn, bitsize - imm);
+ tcg_gen_or_i64(tcg_rd, tcg_rm, tcg_rn);
+ if (!sf) {
+ tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
+ }
+ } else {
+ /* tcg shl_i32/shl_i64 is undefined for 32/64 bit shifts,
+ * so an extract from bit 0 is a special case.
+ */
+ if (sf) {
+ tcg_gen_mov_i64(tcg_rd, cpu_reg(s, rm));
+ } else {
+ tcg_gen_ext32u_i64(tcg_rd, cpu_reg(s, rm));
+ }
+ }
+
+ }
}
/* C3.4 Data processing - immediate */
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 42/62] target-arm: A64: add support for 2-src data processing and DIV
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (40 preceding siblings ...)
2013-12-17 20:28 ` [Qemu-devel] [PULL 41/62] target-arm: A64: add support for EXTR Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 43/62] target-arm: A64: add support for 2-src shift reg insns Peter Maydell
` (20 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
This patch adds support for decoding 2-src data processing insns,
and the first users, UDIV and SDIV.
Signed-off-by: Alexander Graf <agraf@suse.de>
[claudio: adapted to new decoder adding the 2-src decoding level,
always zero-extend result in 32bit mode]
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/helper-a64.c | 21 ++++++++++++++
target-arm/helper-a64.h | 2 ++
target-arm/translate-a64.c | 72 ++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 93 insertions(+), 2 deletions(-)
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index adb8428..abb98c0 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -23,3 +23,24 @@
#include "qemu/host-utils.h"
#include "sysemu/sysemu.h"
#include "qemu/bitops.h"
+
+/* C2.4.7 Multiply and divide */
+/* special cases for 0 and LLONG_MIN are mandated by the standard */
+uint64_t HELPER(udiv64)(uint64_t num, uint64_t den)
+{
+ if (den == 0) {
+ return 0;
+ }
+ return num / den;
+}
+
+int64_t HELPER(sdiv64)(int64_t num, int64_t den)
+{
+ if (den == 0) {
+ return 0;
+ }
+ if (num == LLONG_MIN && den == -1) {
+ return LLONG_MIN;
+ }
+ return num / den;
+}
diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h
index dd28306..e0d6506 100644
--- a/target-arm/helper-a64.h
+++ b/target-arm/helper-a64.h
@@ -16,3 +16,5 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+DEF_HELPER_FLAGS_2(udiv64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(sdiv64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index f9336de..a0bc876 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1050,10 +1050,78 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
unsupported_encoding(s, insn);
}
-/* Data-processing (2 source) */
+static void handle_div(DisasContext *s, bool is_signed, unsigned int sf,
+ unsigned int rm, unsigned int rn, unsigned int rd)
+{
+ TCGv_i64 tcg_n, tcg_m, tcg_rd;
+ tcg_rd = cpu_reg(s, rd);
+
+ if (!sf && is_signed) {
+ tcg_n = new_tmp_a64(s);
+ tcg_m = new_tmp_a64(s);
+ tcg_gen_ext32s_i64(tcg_n, cpu_reg(s, rn));
+ tcg_gen_ext32s_i64(tcg_m, cpu_reg(s, rm));
+ } else {
+ tcg_n = read_cpu_reg(s, rn, sf);
+ tcg_m = read_cpu_reg(s, rm, sf);
+ }
+
+ if (is_signed) {
+ gen_helper_sdiv64(tcg_rd, tcg_n, tcg_m);
+ } else {
+ gen_helper_udiv64(tcg_rd, tcg_n, tcg_m);
+ }
+
+ if (!sf) { /* zero extend final result */
+ tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
+ }
+}
+
+/* C3.5.8 Data-processing (2 source)
+ * 31 30 29 28 21 20 16 15 10 9 5 4 0
+ * +----+---+---+-----------------+------+--------+------+------+
+ * | sf | 0 | S | 1 1 0 1 0 1 1 0 | Rm | opcode | Rn | Rd |
+ * +----+---+---+-----------------+------+--------+------+------+
+ */
static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ unsigned int sf, rm, opcode, rn, rd;
+ sf = extract32(insn, 31, 1);
+ rm = extract32(insn, 16, 5);
+ opcode = extract32(insn, 10, 6);
+ rn = extract32(insn, 5, 5);
+ rd = extract32(insn, 0, 5);
+
+ if (extract32(insn, 29, 1)) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ switch (opcode) {
+ case 2: /* UDIV */
+ handle_div(s, false, sf, rm, rn, rd);
+ break;
+ case 3: /* SDIV */
+ handle_div(s, true, sf, rm, rn, rd);
+ break;
+ case 8: /* LSLV */
+ case 9: /* LSRV */
+ case 10: /* ASRV */
+ case 11: /* RORV */
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23: /* CRC32 */
+ unsupported_encoding(s, insn);
+ break;
+ default:
+ unallocated_encoding(s);
+ break;
+ }
}
/* C3.5 Data processing - register */
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 43/62] target-arm: A64: add support for 2-src shift reg insns
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (41 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 42/62] target-arm: A64: add support for 2-src data processing and DIV Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 44/62] target-arm: A64: add support for 1-src data processing and CLZ Peter Maydell
` (19 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
This adds 2-src variable shift register instructions:
C5.6.115 LSLV, C5.6.118 LSRV, C5.6.17 ASRV, C5.6.154 RORV
Signed-off-by: Alexander Graf <agraf@suse.de>
[claudio: adapted to new decoder, use enums for shift types]
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index a0bc876..acf30c3 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1077,6 +1077,20 @@ static void handle_div(DisasContext *s, bool is_signed, unsigned int sf,
}
}
+/* C5.6.115 LSLV, C5.6.118 LSRV, C5.6.17 ASRV, C5.6.154 RORV */
+static void handle_shift_reg(DisasContext *s,
+ enum a64_shift_type shift_type, unsigned int sf,
+ unsigned int rm, unsigned int rn, unsigned int rd)
+{
+ TCGv_i64 tcg_shift = tcg_temp_new_i64();
+ TCGv_i64 tcg_rd = cpu_reg(s, rd);
+ TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
+
+ tcg_gen_andi_i64(tcg_shift, cpu_reg(s, rm), sf ? 63 : 31);
+ shift_reg(tcg_rd, tcg_rn, sf, shift_type, tcg_shift);
+ tcg_temp_free_i64(tcg_shift);
+}
+
/* C3.5.8 Data-processing (2 source)
* 31 30 29 28 21 20 16 15 10 9 5 4 0
* +----+---+---+-----------------+------+--------+------+------+
@@ -1105,9 +1119,17 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
handle_div(s, true, sf, rm, rn, rd);
break;
case 8: /* LSLV */
+ handle_shift_reg(s, A64_SHIFT_TYPE_LSL, sf, rm, rn, rd);
+ break;
case 9: /* LSRV */
+ handle_shift_reg(s, A64_SHIFT_TYPE_LSR, sf, rm, rn, rd);
+ break;
case 10: /* ASRV */
+ handle_shift_reg(s, A64_SHIFT_TYPE_ASR, sf, rm, rn, rd);
+ break;
case 11: /* RORV */
+ handle_shift_reg(s, A64_SHIFT_TYPE_ROR, sf, rm, rn, rd);
+ break;
case 16:
case 17:
case 18:
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 44/62] target-arm: A64: add support for 1-src data processing and CLZ
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (42 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 43/62] target-arm: A64: add support for 2-src shift reg insns Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 45/62] target-arm: A64: add support for 1-src RBIT insn Peter Maydell
` (18 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Claudio Fontana <claudio.fontana@linaro.org>
This patch adds support for decoding 1-src data processing insns,
and the first user, C5.6.40 CLZ (count leading zeroes).
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/helper-a64.c | 5 +++++
target-arm/helper-a64.h | 1 +
target-arm/translate-a64.c | 52 ++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 56 insertions(+), 2 deletions(-)
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index abb98c0..e4c5346 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -44,3 +44,8 @@ int64_t HELPER(sdiv64)(int64_t num, int64_t den)
}
return num / den;
}
+
+uint64_t HELPER(clz64)(uint64_t x)
+{
+ return clz64(x);
+}
diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h
index e0d6506..b10b6c3 100644
--- a/target-arm/helper-a64.h
+++ b/target-arm/helper-a64.h
@@ -18,3 +18,4 @@
*/
DEF_HELPER_FLAGS_2(udiv64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(sdiv64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
+DEF_HELPER_FLAGS_1(clz64, TCG_CALL_NO_RWG_SE, i64, i64)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index acf30c3..e5481da 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1044,10 +1044,58 @@ static void disas_cond_select(DisasContext *s, uint32_t insn)
}
}
-/* Data-processing (1 source) */
+static void handle_clz(DisasContext *s, unsigned int sf,
+ unsigned int rn, unsigned int rd)
+{
+ TCGv_i64 tcg_rd, tcg_rn;
+ tcg_rd = cpu_reg(s, rd);
+ tcg_rn = cpu_reg(s, rn);
+
+ if (sf) {
+ gen_helper_clz64(tcg_rd, tcg_rn);
+ } else {
+ TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
+ tcg_gen_trunc_i64_i32(tcg_tmp32, tcg_rn);
+ gen_helper_clz(tcg_tmp32, tcg_tmp32);
+ tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
+ tcg_temp_free_i32(tcg_tmp32);
+ }
+}
+
+/* C3.5.7 Data-processing (1 source)
+ * 31 30 29 28 21 20 16 15 10 9 5 4 0
+ * +----+---+---+-----------------+---------+--------+------+------+
+ * | sf | 1 | S | 1 1 0 1 0 1 1 0 | opcode2 | opcode | Rn | Rd |
+ * +----+---+---+-----------------+---------+--------+------+------+
+ */
static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ unsigned int sf, opcode, rn, rd;
+
+ if (extract32(insn, 29, 1) || extract32(insn, 16, 5)) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ sf = extract32(insn, 31, 1);
+ opcode = extract32(insn, 10, 6);
+ rn = extract32(insn, 5, 5);
+ rd = extract32(insn, 0, 5);
+
+ switch (opcode) {
+ case 0: /* RBIT */
+ case 1: /* REV16 */
+ case 2: /* REV32 */
+ case 3: /* REV64 */
+ unsupported_encoding(s, insn);
+ break;
+ case 4: /* CLZ */
+ handle_clz(s, sf, rn, rd);
+ break;
+ case 5: /* CLS */
+ unsupported_encoding(s, insn);
+ break;
+ }
}
static void handle_div(DisasContext *s, bool is_signed, unsigned int sf,
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 45/62] target-arm: A64: add support for 1-src RBIT insn
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (43 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 44/62] target-arm: A64: add support for 1-src data processing and CLZ Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 46/62] target-arm: A64: add support for 1-src REV insns Peter Maydell
` (17 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
This adds support for the C5.6.147 RBIT instruction.
Signed-off-by: Alexander Graf <agraf@suse.de>
[claudio: adapted to new decoder, use bswap64,
make RBIT part standalone from the rest of the patch,
splitting REV into a separate patch]
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/helper-a64.c | 18 ++++++++++++++++++
target-arm/helper-a64.h | 1 +
target-arm/translate-a64.c | 20 ++++++++++++++++++++
3 files changed, 39 insertions(+)
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index e4c5346..cccaac6 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -49,3 +49,21 @@ uint64_t HELPER(clz64)(uint64_t x)
{
return clz64(x);
}
+
+uint64_t HELPER(rbit64)(uint64_t x)
+{
+ /* assign the correct byte position */
+ x = bswap64(x);
+
+ /* assign the correct nibble position */
+ x = ((x & 0xf0f0f0f0f0f0f0f0ULL) >> 4)
+ | ((x & 0x0f0f0f0f0f0f0f0fULL) << 4);
+
+ /* assign the correct bit position */
+ x = ((x & 0x8888888888888888ULL) >> 3)
+ | ((x & 0x4444444444444444ULL) >> 1)
+ | ((x & 0x2222222222222222ULL) << 1)
+ | ((x & 0x1111111111111111ULL) << 3);
+
+ return x;
+}
diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h
index b10b6c3..9959139 100644
--- a/target-arm/helper-a64.h
+++ b/target-arm/helper-a64.h
@@ -19,3 +19,4 @@
DEF_HELPER_FLAGS_2(udiv64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(sdiv64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
DEF_HELPER_FLAGS_1(clz64, TCG_CALL_NO_RWG_SE, i64, i64)
+DEF_HELPER_FLAGS_1(rbit64, TCG_CALL_NO_RWG_SE, i64, i64)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index e5481da..0ed21fc 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1062,6 +1062,24 @@ static void handle_clz(DisasContext *s, unsigned int sf,
}
}
+static void handle_rbit(DisasContext *s, unsigned int sf,
+ unsigned int rn, unsigned int rd)
+{
+ TCGv_i64 tcg_rd, tcg_rn;
+ tcg_rd = cpu_reg(s, rd);
+ tcg_rn = cpu_reg(s, rn);
+
+ if (sf) {
+ gen_helper_rbit64(tcg_rd, tcg_rn);
+ } else {
+ TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
+ tcg_gen_trunc_i64_i32(tcg_tmp32, tcg_rn);
+ gen_helper_rbit(tcg_tmp32, tcg_tmp32);
+ tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
+ tcg_temp_free_i32(tcg_tmp32);
+ }
+}
+
/* C3.5.7 Data-processing (1 source)
* 31 30 29 28 21 20 16 15 10 9 5 4 0
* +----+---+---+-----------------+---------+--------+------+------+
@@ -1084,6 +1102,8 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
switch (opcode) {
case 0: /* RBIT */
+ handle_rbit(s, sf, rn, rd);
+ break;
case 1: /* REV16 */
case 2: /* REV32 */
case 3: /* REV64 */
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 46/62] target-arm: A64: add support for 1-src REV insns
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (44 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 45/62] target-arm: A64: add support for 1-src RBIT insn Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 47/62] target-arm: A64: add support for bitfield insns Peter Maydell
` (16 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Claudio Fontana <claudio.fontana@linaro.org>
This adds support for C5.6.149 REV, C5.6.151 REV32, C5.6.150 REV16.
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 73 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 72 insertions(+), 1 deletion(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 0ed21fc..3c702a9 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1080,6 +1080,73 @@ static void handle_rbit(DisasContext *s, unsigned int sf,
}
}
+/* C5.6.149 REV with sf==1, opcode==3 ("REV64") */
+static void handle_rev64(DisasContext *s, unsigned int sf,
+ unsigned int rn, unsigned int rd)
+{
+ if (!sf) {
+ unallocated_encoding(s);
+ return;
+ }
+ tcg_gen_bswap64_i64(cpu_reg(s, rd), cpu_reg(s, rn));
+}
+
+/* C5.6.149 REV with sf==0, opcode==2
+ * C5.6.151 REV32 (sf==1, opcode==2)
+ */
+static void handle_rev32(DisasContext *s, unsigned int sf,
+ unsigned int rn, unsigned int rd)
+{
+ TCGv_i64 tcg_rd = cpu_reg(s, rd);
+
+ if (sf) {
+ TCGv_i64 tcg_tmp = tcg_temp_new_i64();
+ TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
+
+ /* bswap32_i64 requires zero high word */
+ tcg_gen_ext32u_i64(tcg_tmp, tcg_rn);
+ tcg_gen_bswap32_i64(tcg_rd, tcg_tmp);
+ tcg_gen_shri_i64(tcg_tmp, tcg_rn, 32);
+ tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp);
+ tcg_gen_concat32_i64(tcg_rd, tcg_rd, tcg_tmp);
+
+ tcg_temp_free_i64(tcg_tmp);
+ } else {
+ tcg_gen_ext32u_i64(tcg_rd, cpu_reg(s, rn));
+ tcg_gen_bswap32_i64(tcg_rd, tcg_rd);
+ }
+}
+
+/* C5.6.150 REV16 (opcode==1) */
+static void handle_rev16(DisasContext *s, unsigned int sf,
+ unsigned int rn, unsigned int rd)
+{
+ TCGv_i64 tcg_rd = cpu_reg(s, rd);
+ TCGv_i64 tcg_tmp = tcg_temp_new_i64();
+ TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
+
+ tcg_gen_andi_i64(tcg_tmp, tcg_rn, 0xffff);
+ tcg_gen_bswap16_i64(tcg_rd, tcg_tmp);
+
+ tcg_gen_shri_i64(tcg_tmp, tcg_rn, 16);
+ tcg_gen_andi_i64(tcg_tmp, tcg_tmp, 0xffff);
+ tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp);
+ tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, 16, 16);
+
+ if (sf) {
+ tcg_gen_shri_i64(tcg_tmp, tcg_rn, 32);
+ tcg_gen_andi_i64(tcg_tmp, tcg_tmp, 0xffff);
+ tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp);
+ tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, 32, 16);
+
+ tcg_gen_shri_i64(tcg_tmp, tcg_rn, 48);
+ tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp);
+ tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, 48, 16);
+ }
+
+ tcg_temp_free_i64(tcg_tmp);
+}
+
/* C3.5.7 Data-processing (1 source)
* 31 30 29 28 21 20 16 15 10 9 5 4 0
* +----+---+---+-----------------+---------+--------+------+------+
@@ -1105,9 +1172,13 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
handle_rbit(s, sf, rn, rd);
break;
case 1: /* REV16 */
+ handle_rev16(s, sf, rn, rd);
+ break;
case 2: /* REV32 */
+ handle_rev32(s, sf, rn, rd);
+ break;
case 3: /* REV64 */
- unsupported_encoding(s, insn);
+ handle_rev64(s, sf, rn, rd);
break;
case 4: /* CLZ */
handle_clz(s, sf, rn, rd);
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 47/62] target-arm: A64: add support for bitfield insns
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (45 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 46/62] target-arm: A64: add support for 1-src REV insns Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 48/62] host-utils: add clrsb32/64 - count leading redundant sign bits Peter Maydell
` (15 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Claudio Fontana <claudio.fontana@linaro.org>
This patch implements the C3.4.2 Bitfield instructions:
SBFM, BFM, UBFM.
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 56 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 54 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 3c702a9..2111bcd 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -698,10 +698,62 @@ static void disas_movw_imm(DisasContext *s, uint32_t insn)
unsupported_encoding(s, insn);
}
-/* Bitfield */
+/* C3.4.2 Bitfield
+ * 31 30 29 28 23 22 21 16 15 10 9 5 4 0
+ * +----+-----+-------------+---+------+------+------+------+
+ * | sf | opc | 1 0 0 1 1 0 | N | immr | imms | Rn | Rd |
+ * +----+-----+-------------+---+------+------+------+------+
+ */
static void disas_bitfield(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ unsigned int sf, n, opc, ri, si, rn, rd, bitsize, pos, len;
+ TCGv_i64 tcg_rd, tcg_tmp;
+
+ sf = extract32(insn, 31, 1);
+ opc = extract32(insn, 29, 2);
+ n = extract32(insn, 22, 1);
+ ri = extract32(insn, 16, 6);
+ si = extract32(insn, 10, 6);
+ rn = extract32(insn, 5, 5);
+ rd = extract32(insn, 0, 5);
+ bitsize = sf ? 64 : 32;
+
+ if (sf != n || ri >= bitsize || si >= bitsize || opc > 2) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ tcg_rd = cpu_reg(s, rd);
+ tcg_tmp = read_cpu_reg(s, rn, sf);
+
+ /* OPTME: probably worth recognizing common cases of ext{8,16,32}{u,s} */
+
+ if (opc != 1) { /* SBFM or UBFM */
+ tcg_gen_movi_i64(tcg_rd, 0);
+ }
+
+ /* do the bit move operation */
+ if (si >= ri) {
+ /* Wd<s-r:0> = Wn<s:r> */
+ tcg_gen_shri_i64(tcg_tmp, tcg_tmp, ri);
+ pos = 0;
+ len = (si - ri) + 1;
+ } else {
+ /* Wd<32+s-r,32-r> = Wn<s:0> */
+ pos = bitsize - ri;
+ len = si + 1;
+ }
+
+ tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, pos, len);
+
+ if (opc == 0) { /* SBFM - sign extend the destination field */
+ tcg_gen_shli_i64(tcg_rd, tcg_rd, 64 - (pos + len));
+ tcg_gen_sari_i64(tcg_rd, tcg_rd, 64 - (pos + len));
+ }
+
+ if (!sf) { /* zero extend final result */
+ tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
+ }
}
/* C3.4.3 Extract
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 48/62] host-utils: add clrsb32/64 - count leading redundant sign bits
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (46 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 47/62] target-arm: A64: add support for bitfield insns Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 49/62] target-arm: A64: add support for 1-src CLS insn Peter Maydell
` (14 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Claudio Fontana <claudio.fontana@linaro.org>
this patch introduces wrappers for the clrsb builtins,
which count the leading redundant sign bits.
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
include/qemu/host-utils.h | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h
index 0f688c1..de85d28 100644
--- a/include/qemu/host-utils.h
+++ b/include/qemu/host-utils.h
@@ -228,6 +228,38 @@ static inline int cto64(uint64_t val)
}
/**
+ * clrsb32 - count leading redundant sign bits in a 32-bit value.
+ * @val: The value to search
+ *
+ * Returns the number of bits following the sign bit that are equal to it.
+ * No special cases; output range is [0-31].
+ */
+static inline int clrsb32(uint32_t val)
+{
+#if QEMU_GNUC_PREREQ(4, 7)
+ return __builtin_clrsb(val);
+#else
+ return clz32(val ^ ((int32_t)val >> 1)) - 1;
+#endif
+}
+
+/**
+ * clrsb64 - count leading redundant sign bits in a 64-bit value.
+ * @val: The value to search
+ *
+ * Returns the number of bits following the sign bit that are equal to it.
+ * No special cases; output range is [0-63].
+ */
+static inline int clrsb64(uint64_t val)
+{
+#if QEMU_GNUC_PREREQ(4, 7)
+ return __builtin_clrsbll(val);
+#else
+ return clz64(val ^ ((int64_t)val >> 1)) - 1;
+#endif
+}
+
+/**
* ctpop8 - count the population of one bits in an 8-bit value.
* @val: The value to search
*/
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 49/62] target-arm: A64: add support for 1-src CLS insn
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (47 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 48/62] host-utils: add clrsb32/64 - count leading redundant sign bits Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 50/62] target-arm: A64: add support for logical (immediate) insns Peter Maydell
` (13 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Claudio Fontana <claudio.fontana@linaro.org>
this patch adds support for the CLS instruction.
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/helper-a64.c | 10 ++++++++++
target-arm/helper-a64.h | 2 ++
target-arm/translate-a64.c | 20 +++++++++++++++++++-
3 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index cccaac6..d3f7067 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -50,6 +50,16 @@ uint64_t HELPER(clz64)(uint64_t x)
return clz64(x);
}
+uint64_t HELPER(cls64)(uint64_t x)
+{
+ return clrsb64(x);
+}
+
+uint32_t HELPER(cls32)(uint32_t x)
+{
+ return clrsb32(x);
+}
+
uint64_t HELPER(rbit64)(uint64_t x)
{
/* assign the correct byte position */
diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h
index 9959139..a163a94 100644
--- a/target-arm/helper-a64.h
+++ b/target-arm/helper-a64.h
@@ -19,4 +19,6 @@
DEF_HELPER_FLAGS_2(udiv64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(sdiv64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
DEF_HELPER_FLAGS_1(clz64, TCG_CALL_NO_RWG_SE, i64, i64)
+DEF_HELPER_FLAGS_1(cls64, TCG_CALL_NO_RWG_SE, i64, i64)
+DEF_HELPER_FLAGS_1(cls32, TCG_CALL_NO_RWG_SE, i32, i32)
DEF_HELPER_FLAGS_1(rbit64, TCG_CALL_NO_RWG_SE, i64, i64)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 2111bcd..2bb1795 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1114,6 +1114,24 @@ static void handle_clz(DisasContext *s, unsigned int sf,
}
}
+static void handle_cls(DisasContext *s, unsigned int sf,
+ unsigned int rn, unsigned int rd)
+{
+ TCGv_i64 tcg_rd, tcg_rn;
+ tcg_rd = cpu_reg(s, rd);
+ tcg_rn = cpu_reg(s, rn);
+
+ if (sf) {
+ gen_helper_cls64(tcg_rd, tcg_rn);
+ } else {
+ TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
+ tcg_gen_trunc_i64_i32(tcg_tmp32, tcg_rn);
+ gen_helper_cls32(tcg_tmp32, tcg_tmp32);
+ tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
+ tcg_temp_free_i32(tcg_tmp32);
+ }
+}
+
static void handle_rbit(DisasContext *s, unsigned int sf,
unsigned int rn, unsigned int rd)
{
@@ -1236,7 +1254,7 @@ static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
handle_clz(s, sf, rn, rd);
break;
case 5: /* CLS */
- unsupported_encoding(s, insn);
+ handle_cls(s, sf, rn, rd);
break;
}
}
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 50/62] target-arm: A64: add support for logical (immediate) insns
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (48 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 49/62] target-arm: A64: add support for 1-src CLS insn Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 51/62] hw/arm: add very initial support for Canon DIGIC SoC Peter Maydell
` (12 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Alexander Graf <agraf@suse.de>
This patch adds support for C3.4.4 Logical (immediate),
which include AND, ANDS, ORR, EOR.
Signed-off-by: Alexander Graf <agraf@suse.de>
[claudio: adapted to new decoder, function renaming,
removed a TCG temp variable]
Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
[PMM: cleaned up some unnecessary code in logic_imm_decode_wmask
and added clarifying commentary on what it's actually doing.
Dropped an ext32u that's not needed if we've just done an AND.]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 175 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 173 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 2bb1795..0a76130 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -201,6 +201,21 @@ static TCGv_i64 new_tmp_a64_zero(DisasContext *s)
return t;
}
+/*
+ * Register access functions
+ *
+ * These functions are used for directly accessing a register in where
+ * changes to the final register value are likely to be made. If you
+ * need to use a register for temporary calculation (e.g. index type
+ * operations) use the read_* form.
+ *
+ * B1.2.1 Register mappings
+ *
+ * In instruction register encoding 31 can refer to ZR (zero register) or
+ * the SP (stack pointer) depending on context. In QEMU's case we map SP
+ * to cpu_X[31] and ZR accesses to a temporary which can be discarded.
+ * This is the point of the _sp forms.
+ */
static TCGv_i64 cpu_reg(DisasContext *s, int reg)
{
if (reg == 31) {
@@ -210,6 +225,12 @@ static TCGv_i64 cpu_reg(DisasContext *s, int reg)
}
}
+/* register access for when 31 == SP */
+static TCGv_i64 cpu_reg_sp(DisasContext *s, int reg)
+{
+ return cpu_X[reg];
+}
+
/* read a cpu register in 32bit/64bit mode. Returns a TCGv_i64
* representing the register contents. This TCGv is an auto-freed
* temporary so it need not be explicitly freed, and may be modified.
@@ -686,10 +707,160 @@ static void disas_add_sub_imm(DisasContext *s, uint32_t insn)
unsupported_encoding(s, insn);
}
-/* Logical (immediate) */
+/* The input should be a value in the bottom e bits (with higher
+ * bits zero); returns that value replicated into every element
+ * of size e in a 64 bit integer.
+ */
+static uint64_t bitfield_replicate(uint64_t mask, unsigned int e)
+{
+ assert(e != 0);
+ while (e < 64) {
+ mask |= mask << e;
+ e *= 2;
+ }
+ return mask;
+}
+
+/* Return a value with the bottom len bits set (where 0 < len <= 64) */
+static inline uint64_t bitmask64(unsigned int length)
+{
+ assert(length > 0 && length <= 64);
+ return ~0ULL >> (64 - length);
+}
+
+/* Simplified variant of pseudocode DecodeBitMasks() for the case where we
+ * only require the wmask. Returns false if the imms/immr/immn are a reserved
+ * value (ie should cause a guest UNDEF exception), and true if they are
+ * valid, in which case the decoded bit pattern is written to result.
+ */
+static bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn,
+ unsigned int imms, unsigned int immr)
+{
+ uint64_t mask;
+ unsigned e, levels, s, r;
+ int len;
+
+ assert(immn < 2 && imms < 64 && immr < 64);
+
+ /* The bit patterns we create here are 64 bit patterns which
+ * are vectors of identical elements of size e = 2, 4, 8, 16, 32 or
+ * 64 bits each. Each element contains the same value: a run
+ * of between 1 and e-1 non-zero bits, rotated within the
+ * element by between 0 and e-1 bits.
+ *
+ * The element size and run length are encoded into immn (1 bit)
+ * and imms (6 bits) as follows:
+ * 64 bit elements: immn = 1, imms = <length of run - 1>
+ * 32 bit elements: immn = 0, imms = 0 : <length of run - 1>
+ * 16 bit elements: immn = 0, imms = 10 : <length of run - 1>
+ * 8 bit elements: immn = 0, imms = 110 : <length of run - 1>
+ * 4 bit elements: immn = 0, imms = 1110 : <length of run - 1>
+ * 2 bit elements: immn = 0, imms = 11110 : <length of run - 1>
+ * Notice that immn = 0, imms = 11111x is the only combination
+ * not covered by one of the above options; this is reserved.
+ * Further, <length of run - 1> all-ones is a reserved pattern.
+ *
+ * In all cases the rotation is by immr % e (and immr is 6 bits).
+ */
+
+ /* First determine the element size */
+ len = 31 - clz32((immn << 6) | (~imms & 0x3f));
+ if (len < 1) {
+ /* This is the immn == 0, imms == 0x11111x case */
+ return false;
+ }
+ e = 1 << len;
+
+ levels = e - 1;
+ s = imms & levels;
+ r = immr & levels;
+
+ if (s == levels) {
+ /* <length of run - 1> mustn't be all-ones. */
+ return false;
+ }
+
+ /* Create the value of one element: s+1 set bits rotated
+ * by r within the element (which is e bits wide)...
+ */
+ mask = bitmask64(s + 1);
+ mask = (mask >> r) | (mask << (e - r));
+ /* ...then replicate the element over the whole 64 bit value */
+ mask = bitfield_replicate(mask, e);
+ *result = mask;
+ return true;
+}
+
+/* C3.4.4 Logical (immediate)
+ * 31 30 29 28 23 22 21 16 15 10 9 5 4 0
+ * +----+-----+-------------+---+------+------+------+------+
+ * | sf | opc | 1 0 0 1 0 0 | N | immr | imms | Rn | Rd |
+ * +----+-----+-------------+---+------+------+------+------+
+ */
static void disas_logic_imm(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ unsigned int sf, opc, is_n, immr, imms, rn, rd;
+ TCGv_i64 tcg_rd, tcg_rn;
+ uint64_t wmask;
+ bool is_and = false;
+
+ sf = extract32(insn, 31, 1);
+ opc = extract32(insn, 29, 2);
+ is_n = extract32(insn, 22, 1);
+ immr = extract32(insn, 16, 6);
+ imms = extract32(insn, 10, 6);
+ rn = extract32(insn, 5, 5);
+ rd = extract32(insn, 0, 5);
+
+ if (!sf && is_n) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ if (opc == 0x3) { /* ANDS */
+ tcg_rd = cpu_reg(s, rd);
+ } else {
+ tcg_rd = cpu_reg_sp(s, rd);
+ }
+ tcg_rn = cpu_reg(s, rn);
+
+ if (!logic_imm_decode_wmask(&wmask, is_n, imms, immr)) {
+ /* some immediate field values are reserved */
+ unallocated_encoding(s);
+ return;
+ }
+
+ if (!sf) {
+ wmask &= 0xffffffff;
+ }
+
+ switch (opc) {
+ case 0x3: /* ANDS */
+ case 0x0: /* AND */
+ tcg_gen_andi_i64(tcg_rd, tcg_rn, wmask);
+ is_and = true;
+ break;
+ case 0x1: /* ORR */
+ tcg_gen_ori_i64(tcg_rd, tcg_rn, wmask);
+ break;
+ case 0x2: /* EOR */
+ tcg_gen_xori_i64(tcg_rd, tcg_rn, wmask);
+ break;
+ default:
+ assert(FALSE); /* must handle all above */
+ break;
+ }
+
+ if (!sf && !is_and) {
+ /* zero extend final result; we know we can skip this for AND
+ * since the immediate had the high 32 bits clear.
+ */
+ tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
+ }
+
+ if (opc == 3) { /* ANDS */
+ gen_logic_CC(sf, tcg_rd);
+ }
}
/* Move wide (immediate) */
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 51/62] hw/arm: add very initial support for Canon DIGIC SoC
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (49 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 50/62] target-arm: A64: add support for logical (immediate) insns Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 52/62] hw/arm/digic: prepare DIGIC-based boards support Peter Maydell
` (11 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Antony Pavlov <antonynpavlov@gmail.com>
DIGIC is Canon Inc.'s name for a family of SoC
for digital cameras and camcorders.
There is no publicly available specification for
DIGIC chips. All information about DIGIC chip
internals is based on reverse engineering efforts
made by CHDK (http://chdk.wikia.com) and
Magic Lantern (http://www.magiclantern.fm) projects
contributors.
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Reviewed-by: Andreas Färber <afaerber@suse.de>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: 1387188908-754-2-git-send-email-antonynpavlov@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
default-configs/arm-softmmu.mak | 1 +
hw/arm/Makefile.objs | 1 +
hw/arm/digic.c | 71 +++++++++++++++++++++++++++++++++++++++++
include/hw/arm/digic.h | 35 ++++++++++++++++++++
4 files changed, 108 insertions(+)
create mode 100644 hw/arm/digic.c
create mode 100644 include/hw/arm/digic.h
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index e48f102..2135be3 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -64,6 +64,7 @@ CONFIG_XILINX_SPIPS=y
CONFIG_ARM11SCU=y
CONFIG_A9SCU=y
+CONFIG_DIGIC=y
CONFIG_MARVELL_88W8618=y
CONFIG_OMAP=y
CONFIG_TSC210X=y
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 78b5614..8789807 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -4,4 +4,5 @@ obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
+obj-$(CONFIG_DIGIC) += digic.o
obj-y += omap1.o omap2.o strongarm.o
diff --git a/hw/arm/digic.c b/hw/arm/digic.c
new file mode 100644
index 0000000..2620262
--- /dev/null
+++ b/hw/arm/digic.c
@@ -0,0 +1,71 @@
+/*
+ * QEMU model of the Canon DIGIC SoC.
+ *
+ * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * This model is based on reverse engineering efforts
+ * made by CHDK (http://chdk.wikia.com) and
+ * Magic Lantern (http://www.magiclantern.fm) projects
+ * contributors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "hw/arm/digic.h"
+
+static void digic_init(Object *obj)
+{
+ DigicState *s = DIGIC(obj);
+
+ object_initialize(&s->cpu, sizeof(s->cpu), "arm946-" TYPE_ARM_CPU);
+ object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL);
+}
+
+static void digic_realize(DeviceState *dev, Error **errp)
+{
+ DigicState *s = DIGIC(dev);
+ Error *err = NULL;
+
+ object_property_set_bool(OBJECT(&s->cpu), true, "reset-hivecs", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+}
+
+static void digic_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = digic_realize;
+}
+
+static const TypeInfo digic_type_info = {
+ .name = TYPE_DIGIC,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(DigicState),
+ .instance_init = digic_init,
+ .class_init = digic_class_init,
+};
+
+static void digic_register_types(void)
+{
+ type_register_static(&digic_type_info);
+}
+
+type_init(digic_register_types)
diff --git a/include/hw/arm/digic.h b/include/hw/arm/digic.h
new file mode 100644
index 0000000..b7d16fb
--- /dev/null
+++ b/include/hw/arm/digic.h
@@ -0,0 +1,35 @@
+/*
+ * Misc Canon DIGIC declarations.
+ *
+ * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef HW_ARM_DIGIC_H
+#define HW_ARM_DIGIC_H
+
+#include "cpu.h"
+
+#define TYPE_DIGIC "digic"
+
+#define DIGIC(obj) OBJECT_CHECK(DigicState, (obj), TYPE_DIGIC)
+
+typedef struct DigicState {
+ /*< private >*/
+ DeviceState parent_obj;
+ /*< public >*/
+
+ ARMCPU cpu;
+} DigicState;
+
+#endif /* HW_ARM_DIGIC_H */
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 52/62] hw/arm/digic: prepare DIGIC-based boards support
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (50 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 51/62] hw/arm: add very initial support for Canon DIGIC SoC Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 53/62] hw/arm/digic: add timer support Peter Maydell
` (10 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Antony Pavlov <antonynpavlov@gmail.com>
Also this patch adds initial support for Canon
PowerShot A1100 IS compact camera.
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Message-id: 1387188908-754-3-git-send-email-antonynpavlov@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/Makefile.objs | 1 +
hw/arm/digic_boards.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++
tests/qom-test.c | 1 +
3 files changed, 86 insertions(+)
create mode 100644 hw/arm/digic_boards.c
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 8789807..d7d37f2 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -1,4 +1,5 @@
obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o
+obj-$(CONFIG_DIGIC) += digic_boards.o
obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c
new file mode 100644
index 0000000..87a9c4b
--- /dev/null
+++ b/hw/arm/digic_boards.c
@@ -0,0 +1,84 @@
+/*
+ * QEMU model of the Canon DIGIC boards (cameras indeed :).
+ *
+ * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * This model is based on reverse engineering efforts
+ * made by CHDK (http://chdk.wikia.com) and
+ * Magic Lantern (http://www.magiclantern.fm) projects
+ * contributors.
+ *
+ * See docs here:
+ * http://magiclantern.wikia.com/wiki/Register_Map
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "hw/boards.h"
+#include "exec/address-spaces.h"
+#include "qemu/error-report.h"
+#include "hw/arm/digic.h"
+
+typedef struct DigicBoardState {
+ DigicState *digic;
+ MemoryRegion ram;
+} DigicBoardState;
+
+typedef struct DigicBoard {
+ hwaddr ram_size;
+} DigicBoard;
+
+static void digic4_board_setup_ram(DigicBoardState *s, hwaddr ram_size)
+{
+ memory_region_init_ram(&s->ram, NULL, "ram", ram_size);
+ memory_region_add_subregion(get_system_memory(), 0, &s->ram);
+ vmstate_register_ram_global(&s->ram);
+}
+
+static void digic4_board_init(DigicBoard *board)
+{
+ Error *err = NULL;
+
+ DigicBoardState *s = g_new(DigicBoardState, 1);
+
+ s->digic = DIGIC(object_new(TYPE_DIGIC));
+ object_property_set_bool(OBJECT(s->digic), true, "realized", &err);
+ if (err != NULL) {
+ error_report("Couldn't realize DIGIC SoC: %s\n",
+ error_get_pretty(err));
+ exit(1);
+ }
+
+ digic4_board_setup_ram(s, board->ram_size);
+}
+
+static DigicBoard digic4_board_canon_a1100 = {
+ .ram_size = 64 * 1024 * 1024,
+};
+
+static void canon_a1100_init(QEMUMachineInitArgs *args)
+{
+ digic4_board_init(&digic4_board_canon_a1100);
+}
+
+static QEMUMachine canon_a1100 = {
+ .name = "canon-a1100",
+ .desc = "Canon PowerShot A1100 IS",
+ .init = &canon_a1100_init,
+};
+
+static void digic_register_machines(void)
+{
+ qemu_register_machine(&canon_a1100);
+}
+
+machine_init(digic_register_machines)
diff --git a/tests/qom-test.c b/tests/qom-test.c
index 499be40..f67f7c2 100644
--- a/tests/qom-test.c
+++ b/tests/qom-test.c
@@ -70,6 +70,7 @@ static const char *arm_machines[] = {
"xilinx-zynq-a9",
"highbank",
"midway",
+ "canon-a1100",
};
static const char *cris_machines[] = {
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 53/62] hw/arm/digic: add timer support
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (51 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 52/62] hw/arm/digic: prepare DIGIC-based boards support Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 54/62] hw/arm/digic: add UART support Peter Maydell
` (9 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: 1387188908-754-4-git-send-email-antonynpavlov@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/digic.c | 28 +++++++
hw/timer/Makefile.objs | 1 +
hw/timer/digic-timer.c | 163 +++++++++++++++++++++++++++++++++++++++++
include/hw/arm/digic.h | 6 ++
include/hw/timer/digic-timer.h | 46 ++++++++++++
5 files changed, 244 insertions(+)
create mode 100644 hw/timer/digic-timer.c
create mode 100644 include/hw/timer/digic-timer.h
diff --git a/hw/arm/digic.c b/hw/arm/digic.c
index 2620262..e8eb0de 100644
--- a/hw/arm/digic.c
+++ b/hw/arm/digic.c
@@ -22,18 +22,35 @@
#include "hw/arm/digic.h"
+#define DIGIC4_TIMER_BASE(n) (0xc0210000 + (n) * 0x100)
+
static void digic_init(Object *obj)
{
DigicState *s = DIGIC(obj);
+ DeviceState *dev;
+ int i;
object_initialize(&s->cpu, sizeof(s->cpu), "arm946-" TYPE_ARM_CPU);
object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL);
+
+ for (i = 0; i < DIGIC4_NB_TIMERS; i++) {
+#define DIGIC_TIMER_NAME_MLEN 11
+ char name[DIGIC_TIMER_NAME_MLEN];
+
+ object_initialize(&s->timer[i], sizeof(s->timer[i]), TYPE_DIGIC_TIMER);
+ dev = DEVICE(&s->timer[i]);
+ qdev_set_parent_bus(dev, sysbus_get_default());
+ snprintf(name, DIGIC_TIMER_NAME_MLEN, "timer[%d]", i);
+ object_property_add_child(obj, name, OBJECT(&s->timer[i]), NULL);
+ }
}
static void digic_realize(DeviceState *dev, Error **errp)
{
DigicState *s = DIGIC(dev);
Error *err = NULL;
+ SysBusDevice *sbd;
+ int i;
object_property_set_bool(OBJECT(&s->cpu), true, "reset-hivecs", &err);
if (err != NULL) {
@@ -46,6 +63,17 @@ static void digic_realize(DeviceState *dev, Error **errp)
error_propagate(errp, err);
return;
}
+
+ for (i = 0; i < DIGIC4_NB_TIMERS; i++) {
+ object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sbd = SYS_BUS_DEVICE(&s->timer[i]);
+ sysbus_mmio_map(sbd, 0, DIGIC4_TIMER_BASE(i));
+ }
}
static void digic_class_init(ObjectClass *oc, void *data)
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 3ae091c..ea9f11f 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -26,5 +26,6 @@ obj-$(CONFIG_OMAP) += omap_synctimer.o
obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o
obj-$(CONFIG_SH4) += sh_timer.o
obj-$(CONFIG_TUSB6010) += tusb6010.o
+obj-$(CONFIG_DIGIC) += digic-timer.o
obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c
new file mode 100644
index 0000000..1fde22c
--- /dev/null
+++ b/hw/timer/digic-timer.c
@@ -0,0 +1,163 @@
+/*
+ * QEMU model of the Canon DIGIC timer block.
+ *
+ * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * This model is based on reverse engineering efforts
+ * made by CHDK (http://chdk.wikia.com) and
+ * Magic Lantern (http://www.magiclantern.fm) projects
+ * contributors.
+ *
+ * See "Timer/Clock Module" docs here:
+ * http://magiclantern.wikia.com/wiki/Register_Map
+ *
+ * The QEMU model of the OSTimer in PKUnity SoC by Guan Xuetao
+ * is used as a template.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "hw/sysbus.h"
+#include "hw/ptimer.h"
+#include "qemu/main-loop.h"
+
+#include "hw/timer/digic-timer.h"
+
+static const VMStateDescription vmstate_digic_timer = {
+ .name = "digic.timer",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PTIMER(ptimer, DigicTimerState),
+ VMSTATE_UINT32(control, DigicTimerState),
+ VMSTATE_UINT32(relvalue, DigicTimerState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void digic_timer_reset(DeviceState *dev)
+{
+ DigicTimerState *s = DIGIC_TIMER(dev);
+
+ ptimer_stop(s->ptimer);
+ s->control = 0;
+ s->relvalue = 0;
+}
+
+static uint64_t digic_timer_read(void *opaque, hwaddr offset, unsigned size)
+{
+ DigicTimerState *s = opaque;
+ uint64_t ret = 0;
+
+ switch (offset) {
+ case DIGIC_TIMER_CONTROL:
+ ret = s->control;
+ break;
+ case DIGIC_TIMER_RELVALUE:
+ ret = s->relvalue;
+ break;
+ case DIGIC_TIMER_VALUE:
+ ret = ptimer_get_count(s->ptimer) & 0xffff;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "digic-timer: read access to unknown register 0x"
+ TARGET_FMT_plx, offset);
+ }
+
+ return ret;
+}
+
+static void digic_timer_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ DigicTimerState *s = opaque;
+
+ switch (offset) {
+ case DIGIC_TIMER_CONTROL:
+ if (value & DIGIC_TIMER_CONTROL_RST) {
+ digic_timer_reset((DeviceState *)s);
+ break;
+ }
+
+ if (value & DIGIC_TIMER_CONTROL_EN) {
+ ptimer_run(s->ptimer, 0);
+ }
+
+ s->control = (uint32_t)value;
+ break;
+
+ case DIGIC_TIMER_RELVALUE:
+ s->relvalue = extract32(value, 0, 16);
+ ptimer_set_limit(s->ptimer, s->relvalue, 1);
+ break;
+
+ case DIGIC_TIMER_VALUE:
+ break;
+
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "digic-timer: read access to unknown register 0x"
+ TARGET_FMT_plx, offset);
+ }
+}
+
+static const MemoryRegionOps digic_timer_ops = {
+ .read = digic_timer_read,
+ .write = digic_timer_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void digic_timer_init(Object *obj)
+{
+ DigicTimerState *s = DIGIC_TIMER(obj);
+
+ s->ptimer = ptimer_init(NULL);
+
+ /*
+ * FIXME: there is no documentation on Digic timer
+ * frequency setup so let it always run at 1 MHz
+ */
+ ptimer_set_freq(s->ptimer, 1 * 1000 * 1000);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &digic_timer_ops, s,
+ TYPE_DIGIC_TIMER, 0x100);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
+}
+
+static void digic_timer_class_init(ObjectClass *klass, void *class_data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = digic_timer_reset;
+ dc->vmsd = &vmstate_digic_timer;
+}
+
+static const TypeInfo digic_timer_info = {
+ .name = TYPE_DIGIC_TIMER,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(DigicTimerState),
+ .instance_init = digic_timer_init,
+ .class_init = digic_timer_class_init,
+};
+
+static void digic_timer_register_type(void)
+{
+ type_register_static(&digic_timer_info);
+}
+
+type_init(digic_timer_register_type)
diff --git a/include/hw/arm/digic.h b/include/hw/arm/digic.h
index b7d16fb..177a06d 100644
--- a/include/hw/arm/digic.h
+++ b/include/hw/arm/digic.h
@@ -20,16 +20,22 @@
#include "cpu.h"
+#include "hw/timer/digic-timer.h"
+
#define TYPE_DIGIC "digic"
#define DIGIC(obj) OBJECT_CHECK(DigicState, (obj), TYPE_DIGIC)
+#define DIGIC4_NB_TIMERS 3
+
typedef struct DigicState {
/*< private >*/
DeviceState parent_obj;
/*< public >*/
ARMCPU cpu;
+
+ DigicTimerState timer[DIGIC4_NB_TIMERS];
} DigicState;
#endif /* HW_ARM_DIGIC_H */
diff --git a/include/hw/timer/digic-timer.h b/include/hw/timer/digic-timer.h
new file mode 100644
index 0000000..ae91348
--- /dev/null
+++ b/include/hw/timer/digic-timer.h
@@ -0,0 +1,46 @@
+/*
+ * Canon DIGIC timer block declarations.
+ *
+ * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef HW_TIMER_DIGIC_TIMER_H
+#define HW_TIMER_DIGIC_TIMER_H
+
+#include "hw/sysbus.h"
+#include "qemu/typedefs.h"
+#include "hw/ptimer.h"
+
+#define TYPE_DIGIC_TIMER "digic-timer"
+#define DIGIC_TIMER(obj) OBJECT_CHECK(DigicTimerState, (obj), TYPE_DIGIC_TIMER)
+
+#define DIGIC_TIMER_CONTROL 0x00
+#define DIGIC_TIMER_CONTROL_RST 0x80000000
+#define DIGIC_TIMER_CONTROL_EN 0x00000001
+#define DIGIC_TIMER_RELVALUE 0x08
+#define DIGIC_TIMER_VALUE 0x0c
+
+typedef struct DigicTimerState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
+ MemoryRegion iomem;
+ ptimer_state *ptimer;
+
+ uint32_t control;
+ uint32_t relvalue;
+} DigicTimerState;
+
+#endif /* HW_TIMER_DIGIC_TIMER_H */
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 54/62] hw/arm/digic: add UART support
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (52 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 53/62] hw/arm/digic: add timer support Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 55/62] hw/arm/digic: add NOR ROM support Peter Maydell
` (8 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: 1387188908-754-5-git-send-email-antonynpavlov@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/digic.c | 16 ++++
hw/char/Makefile.objs | 1 +
hw/char/digic-uart.c | 195 +++++++++++++++++++++++++++++++++++++++++++
include/hw/arm/digic.h | 2 +
include/hw/char/digic-uart.h | 47 +++++++++++
5 files changed, 261 insertions(+)
create mode 100644 hw/char/digic-uart.c
create mode 100644 include/hw/char/digic-uart.h
diff --git a/hw/arm/digic.c b/hw/arm/digic.c
index e8eb0de..ec8c330 100644
--- a/hw/arm/digic.c
+++ b/hw/arm/digic.c
@@ -24,6 +24,8 @@
#define DIGIC4_TIMER_BASE(n) (0xc0210000 + (n) * 0x100)
+#define DIGIC_UART_BASE 0xc0800000
+
static void digic_init(Object *obj)
{
DigicState *s = DIGIC(obj);
@@ -43,6 +45,11 @@ static void digic_init(Object *obj)
snprintf(name, DIGIC_TIMER_NAME_MLEN, "timer[%d]", i);
object_property_add_child(obj, name, OBJECT(&s->timer[i]), NULL);
}
+
+ object_initialize(&s->uart, sizeof(s->uart), TYPE_DIGIC_UART);
+ dev = DEVICE(&s->uart);
+ qdev_set_parent_bus(dev, sysbus_get_default());
+ object_property_add_child(obj, "uart", OBJECT(&s->uart), NULL);
}
static void digic_realize(DeviceState *dev, Error **errp)
@@ -74,6 +81,15 @@ static void digic_realize(DeviceState *dev, Error **errp)
sbd = SYS_BUS_DEVICE(&s->timer[i]);
sysbus_mmio_map(sbd, 0, DIGIC4_TIMER_BASE(i));
}
+
+ object_property_set_bool(OBJECT(&s->uart), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sbd = SYS_BUS_DEVICE(&s->uart);
+ sysbus_mmio_map(sbd, 0, DIGIC_UART_BASE);
}
static void digic_class_init(ObjectClass *oc, void *data)
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index cbd6a00..be2a7d9 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -14,6 +14,7 @@ obj-$(CONFIG_COLDFIRE) += mcf_uart.o
obj-$(CONFIG_OMAP) += omap_uart.o
obj-$(CONFIG_SH4) += sh_serial.o
obj-$(CONFIG_PSERIES) += spapr_vty.o
+obj-$(CONFIG_DIGIC) += digic-uart.o
common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o
common-obj-$(CONFIG_ISA_DEBUG) += debugcon.o
diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c
new file mode 100644
index 0000000..fd8e077
--- /dev/null
+++ b/hw/char/digic-uart.c
@@ -0,0 +1,195 @@
+/*
+ * QEMU model of the Canon DIGIC UART block.
+ *
+ * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * This model is based on reverse engineering efforts
+ * made by CHDK (http://chdk.wikia.com) and
+ * Magic Lantern (http://www.magiclantern.fm) projects
+ * contributors.
+ *
+ * See "Serial terminal" docs here:
+ * http://magiclantern.wikia.com/wiki/Register_Map#Misc_Registers
+ *
+ * The QEMU model of the Milkymist UART block by Michael Walle
+ * is used as a template.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "sysemu/char.h"
+
+#include "hw/char/digic-uart.h"
+
+enum {
+ ST_RX_RDY = (1 << 0),
+ ST_TX_RDY = (1 << 1),
+};
+
+static uint64_t digic_uart_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ DigicUartState *s = opaque;
+ uint64_t ret = 0;
+
+ addr >>= 2;
+
+ switch (addr) {
+ case R_RX:
+ s->reg_st &= ~(ST_RX_RDY);
+ ret = s->reg_rx;
+ break;
+
+ case R_ST:
+ ret = s->reg_st;
+ break;
+
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "digic-uart: read access to unknown register 0x"
+ TARGET_FMT_plx, addr << 2);
+ }
+
+ return ret;
+}
+
+static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value,
+ unsigned size)
+{
+ DigicUartState *s = opaque;
+ unsigned char ch = value;
+
+ addr >>= 2;
+
+ switch (addr) {
+ case R_TX:
+ if (s->chr) {
+ qemu_chr_fe_write_all(s->chr, &ch, 1);
+ }
+ break;
+
+ case R_ST:
+ /*
+ * Ignore write to R_ST.
+ *
+ * The point is that this register is actively used
+ * during receiving and transmitting symbols,
+ * but we don't know the function of most of bits.
+ *
+ * Ignoring writes to R_ST is only a simplification
+ * of the model. It has no perceptible side effects
+ * for existing guests.
+ */
+ break;
+
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "digic-uart: write access to unknown register 0x"
+ TARGET_FMT_plx, addr << 2);
+ }
+}
+
+static const MemoryRegionOps uart_mmio_ops = {
+ .read = digic_uart_read,
+ .write = digic_uart_write,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int uart_can_rx(void *opaque)
+{
+ DigicUartState *s = opaque;
+
+ return !(s->reg_st & ST_RX_RDY);
+}
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+ DigicUartState *s = opaque;
+
+ assert(uart_can_rx(opaque));
+
+ s->reg_st |= ST_RX_RDY;
+ s->reg_rx = *buf;
+}
+
+static void uart_event(void *opaque, int event)
+{
+}
+
+static void digic_uart_reset(DeviceState *d)
+{
+ DigicUartState *s = DIGIC_UART(d);
+
+ s->reg_rx = 0;
+ s->reg_st = ST_TX_RDY;
+}
+
+static void digic_uart_realize(DeviceState *dev, Error **errp)
+{
+ DigicUartState *s = DIGIC_UART(dev);
+
+ s->chr = qemu_char_get_next_serial();
+ if (s->chr) {
+ qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+ }
+}
+
+static void digic_uart_init(Object *obj)
+{
+ DigicUartState *s = DIGIC_UART(obj);
+
+ memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s,
+ TYPE_DIGIC_UART, 0x18);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->regs_region);
+}
+
+static const VMStateDescription vmstate_digic_uart = {
+ .name = "digic-uart",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(reg_rx, DigicUartState),
+ VMSTATE_UINT32(reg_st, DigicUartState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void digic_uart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = digic_uart_realize;
+ dc->reset = digic_uart_reset;
+ dc->vmsd = &vmstate_digic_uart;
+}
+
+static const TypeInfo digic_uart_info = {
+ .name = TYPE_DIGIC_UART,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(DigicUartState),
+ .instance_init = digic_uart_init,
+ .class_init = digic_uart_class_init,
+};
+
+static void digic_uart_register_types(void)
+{
+ type_register_static(&digic_uart_info);
+}
+
+type_init(digic_uart_register_types)
diff --git a/include/hw/arm/digic.h b/include/hw/arm/digic.h
index 177a06d..a739d6a 100644
--- a/include/hw/arm/digic.h
+++ b/include/hw/arm/digic.h
@@ -21,6 +21,7 @@
#include "cpu.h"
#include "hw/timer/digic-timer.h"
+#include "hw/char/digic-uart.h"
#define TYPE_DIGIC "digic"
@@ -36,6 +37,7 @@ typedef struct DigicState {
ARMCPU cpu;
DigicTimerState timer[DIGIC4_NB_TIMERS];
+ DigicUartState uart;
} DigicState;
#endif /* HW_ARM_DIGIC_H */
diff --git a/include/hw/char/digic-uart.h b/include/hw/char/digic-uart.h
new file mode 100644
index 0000000..ef83a30
--- /dev/null
+++ b/include/hw/char/digic-uart.h
@@ -0,0 +1,47 @@
+/*
+ * Canon DIGIC UART block declarations.
+ *
+ * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef HW_CHAR_DIGIC_UART_H
+#define HW_CHAR_DIGIC_UART_H
+
+#include "hw/sysbus.h"
+#include "qemu/typedefs.h"
+
+#define TYPE_DIGIC_UART "digic-uart"
+#define DIGIC_UART(obj) \
+ OBJECT_CHECK(DigicUartState, (obj), TYPE_DIGIC_UART)
+
+enum {
+ R_TX = 0x00,
+ R_RX,
+ R_ST = (0x14 >> 2),
+ R_MAX
+};
+
+typedef struct DigicUartState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
+ MemoryRegion regs_region;
+ CharDriverState *chr;
+
+ uint32_t reg_rx;
+ uint32_t reg_st;
+} DigicUartState;
+
+#endif /* HW_CHAR_DIGIC_UART_H */
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 55/62] hw/arm/digic: add NOR ROM support
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (53 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 54/62] hw/arm/digic: add UART support Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 56/62] MAINTAINERS: Document 'Canon DIGIC' machine Peter Maydell
` (7 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Message-id: 1387188908-754-6-git-send-email-antonynpavlov@gmail.com
[PMM: don't try to load ROM blob if qtest_enabled()]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/digic_boards.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 78 insertions(+)
diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c
index 87a9c4b..32fc30a 100644
--- a/hw/arm/digic_boards.c
+++ b/hw/arm/digic_boards.c
@@ -27,6 +27,14 @@
#include "exec/address-spaces.h"
#include "qemu/error-report.h"
#include "hw/arm/digic.h"
+#include "hw/block/flash.h"
+#include "hw/loader.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/qtest.h"
+
+#define DIGIC4_ROM0_BASE 0xf0000000
+#define DIGIC4_ROM1_BASE 0xf8000000
+#define DIGIC4_ROM_MAX_SIZE 0x08000000
typedef struct DigicBoardState {
DigicState *digic;
@@ -35,6 +43,10 @@ typedef struct DigicBoardState {
typedef struct DigicBoard {
hwaddr ram_size;
+ void (*add_rom0)(DigicBoardState *, hwaddr, const char *);
+ const char *rom0_def_filename;
+ void (*add_rom1)(DigicBoardState *, hwaddr, const char *);
+ const char *rom1_def_filename;
} DigicBoard;
static void digic4_board_setup_ram(DigicBoardState *s, hwaddr ram_size)
@@ -59,10 +71,76 @@ static void digic4_board_init(DigicBoard *board)
}
digic4_board_setup_ram(s, board->ram_size);
+
+ if (board->add_rom0) {
+ board->add_rom0(s, DIGIC4_ROM0_BASE, board->rom0_def_filename);
+ }
+
+ if (board->add_rom1) {
+ board->add_rom1(s, DIGIC4_ROM1_BASE, board->rom1_def_filename);
+ }
+}
+
+static void digic_load_rom(DigicBoardState *s, hwaddr addr,
+ hwaddr max_size, const char *def_filename)
+{
+ target_long rom_size;
+ const char *filename;
+
+ if (qtest_enabled()) {
+ /* qtest runs no code so don't attempt a ROM load which
+ * could fail and result in a spurious test failure.
+ */
+ return;
+ }
+
+ if (bios_name) {
+ filename = bios_name;
+ } else {
+ filename = def_filename;
+ }
+
+ if (filename) {
+ char *fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, filename);
+
+ if (!fn) {
+ error_report("Couldn't find rom image '%s'.\n", filename);
+ exit(1);
+ }
+
+ rom_size = load_image_targphys(fn, addr, max_size);
+ if (rom_size < 0 || rom_size > max_size) {
+ error_report("Couldn't load rom image '%s'.\n", filename);
+ exit(1);
+ }
+ }
+}
+
+/*
+ * Samsung K8P3215UQB
+ * 64M Bit (4Mx16) Page Mode / Multi-Bank NOR Flash Memory
+ */
+static void digic4_add_k8p3215uqb_rom(DigicBoardState *s, hwaddr addr,
+ const char *def_filename)
+{
+#define FLASH_K8P3215UQB_SIZE (4 * 1024 * 1024)
+#define FLASH_K8P3215UQB_SECTOR_SIZE (64 * 1024)
+
+ pflash_cfi02_register(addr, NULL, "pflash", FLASH_K8P3215UQB_SIZE,
+ NULL, FLASH_K8P3215UQB_SECTOR_SIZE,
+ FLASH_K8P3215UQB_SIZE / FLASH_K8P3215UQB_SECTOR_SIZE,
+ DIGIC4_ROM_MAX_SIZE / FLASH_K8P3215UQB_SIZE,
+ 4,
+ 0x00EC, 0x007E, 0x0003, 0x0001,
+ 0x0555, 0x2aa, 0);
+
+ digic_load_rom(s, addr, FLASH_K8P3215UQB_SIZE, def_filename);
}
static DigicBoard digic4_board_canon_a1100 = {
.ram_size = 64 * 1024 * 1024,
+ .add_rom1 = digic4_add_k8p3215uqb_rom,
+ .rom1_def_filename = "canon-a1100-rom1.bin",
};
static void canon_a1100_init(QEMUMachineInitArgs *args)
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 56/62] MAINTAINERS: Document 'Canon DIGIC' machine
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (54 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 55/62] hw/arm/digic: add NOR ROM support Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 57/62] vmstate: Add support for an array of ptimer_state * Peter Maydell
` (6 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Message-id: 1387188908-754-7-git-send-email-antonynpavlov@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
MAINTAINERS | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 7f45d1d..1fce9a5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -233,6 +233,12 @@ S: Supported
F: hw/arm/highbank.c
F: hw/net/xgmac.c
+Canon DIGIC
+M: Antony Pavlov <antonynpavlov@gmail.com>
+S: Maintained
+F: include/hw/arm/digic.h
+F: hw/*/digic*
+
Gumstix
M: qemu-devel@nongnu.org
S: Orphan
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 57/62] vmstate: Add support for an array of ptimer_state *
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (55 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 56/62] MAINTAINERS: Document 'Canon DIGIC' machine Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 58/62] hw/timer: add allwinner a10 timer Peter Maydell
` (5 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
Add support for defining a vmstate field which is an array
of pointers to structures, and use this to define a
VMSTATE_PTIMER_ARRAY() which allows an array of ptimer_state*
to be used by devices.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1387159292-10436-2-git-send-email-lig.fnst@cn.fujitsu.com
---
include/hw/ptimer.h | 4 ++++
include/migration/vmstate.h | 10 ++++++++++
2 files changed, 14 insertions(+)
diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h
index 28fcaf1..a33edf4 100644
--- a/include/hw/ptimer.h
+++ b/include/hw/ptimer.h
@@ -36,4 +36,8 @@ extern const VMStateDescription vmstate_ptimer;
.offset = vmstate_offset_pointer(_state, _field, ptimer_state), \
}
+#define VMSTATE_PTIMER_ARRAY(_f, _s, _n) \
+ VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(_f, _s, _n, 0, \
+ vmstate_ptimer, ptimer_state)
+
#endif
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 9d09e60..be193ba 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -339,6 +339,16 @@ extern const VMStateInfo vmstate_info_bitmap;
.offset = vmstate_offset_array(_state, _field, _type, _num), \
}
+#define VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(_f, _s, _n, _v, _vmsd, _type) { \
+ .name = (stringify(_f)), \
+ .version_id = (_v), \
+ .num = (_n), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type *), \
+ .flags = VMS_ARRAY|VMS_STRUCT|VMS_ARRAY_OF_POINTER, \
+ .offset = vmstate_offset_array(_s, _f, _type*, _n), \
+}
+
#define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, _vmsd, _type) { \
.name = (stringify(_field)), \
.num = (_num), \
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 58/62] hw/timer: add allwinner a10 timer
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (56 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 57/62] vmstate: Add support for an array of ptimer_state * Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 59/62] hw/intc: add allwinner A10 interrupt controller Peter Maydell
` (4 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: liguang <lig.fnst@cn.fujitsu.com>
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: 1387159292-10436-3-git-send-email-lig.fnst@cn.fujitsu.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
default-configs/arm-softmmu.mak | 2 +
hw/timer/Makefile.objs | 2 +
hw/timer/allwinner-a10-pit.c | 254 +++++++++++++++++++++++++++++++++++
include/hw/timer/allwinner-a10-pit.h | 58 ++++++++
4 files changed, 316 insertions(+)
create mode 100644 hw/timer/allwinner-a10-pit.c
create mode 100644 include/hw/timer/allwinner-a10-pit.h
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 2135be3..14c68b4 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -83,3 +83,5 @@ CONFIG_VERSATILE_I2C=y
CONFIG_SDHCI=y
CONFIG_INTEGRATOR_DEBUG=y
+
+CONFIG_ALLWINNER_A10_PIT=y
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index ea9f11f..2c86c3d 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -29,3 +29,5 @@ obj-$(CONFIG_TUSB6010) += tusb6010.o
obj-$(CONFIG_DIGIC) += digic-timer.o
obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
+
+obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c
new file mode 100644
index 0000000..b27fce8
--- /dev/null
+++ b/hw/timer/allwinner-a10-pit.c
@@ -0,0 +1,254 @@
+/*
+ * Allwinner A10 timer device emulation
+ *
+ * Copyright (C) 2013 Li Guang
+ * Written by Li Guang <lig.fnst@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "hw/timer/allwinner-a10-pit.h"
+
+static uint64_t a10_pit_read(void *opaque, hwaddr offset, unsigned size)
+{
+ AwA10PITState *s = AW_A10_PIT(opaque);
+ uint8_t index;
+
+ switch (offset) {
+ case AW_A10_PIT_TIMER_IRQ_EN:
+ return s->irq_enable;
+ case AW_A10_PIT_TIMER_IRQ_ST:
+ return s->irq_status;
+ case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE_END:
+ index = offset & 0xf0;
+ index >>= 4;
+ index -= 1;
+ switch (offset & 0x0f) {
+ case AW_A10_PIT_TIMER_CONTROL:
+ return s->control[index];
+ case AW_A10_PIT_TIMER_INTERVAL:
+ return s->interval[index];
+ case AW_A10_PIT_TIMER_COUNT:
+ s->count[index] = ptimer_get_count(s->timer[index]);
+ return s->count[index];
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ break;
+ }
+ case AW_A10_PIT_WDOG_CONTROL:
+ break;
+ case AW_A10_PIT_WDOG_MODE:
+ break;
+ case AW_A10_PIT_COUNT_LO:
+ return s->count_lo;
+ case AW_A10_PIT_COUNT_HI:
+ return s->count_hi;
+ case AW_A10_PIT_COUNT_CTL:
+ return s->count_ctl;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ break;
+ }
+
+ return 0;
+}
+
+static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ AwA10PITState *s = AW_A10_PIT(opaque);
+ uint8_t index;
+
+ switch (offset) {
+ case AW_A10_PIT_TIMER_IRQ_EN:
+ s->irq_enable = value;
+ break;
+ case AW_A10_PIT_TIMER_IRQ_ST:
+ s->irq_status &= ~value;
+ break;
+ case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE_END:
+ index = offset & 0xf0;
+ index >>= 4;
+ index -= 1;
+ switch (offset & 0x0f) {
+ case AW_A10_PIT_TIMER_CONTROL:
+ s->control[index] = value;
+ if (s->control[index] & AW_A10_PIT_TIMER_RELOAD) {
+ ptimer_set_count(s->timer[index], s->interval[index]);
+ }
+ if (s->control[index] & AW_A10_PIT_TIMER_EN) {
+ int oneshot = 0;
+ if (s->control[index] & AW_A10_PIT_TIMER_MODE) {
+ oneshot = 1;
+ }
+ ptimer_run(s->timer[index], oneshot);
+ } else {
+ ptimer_stop(s->timer[index]);
+ }
+ break;
+ case AW_A10_PIT_TIMER_INTERVAL:
+ s->interval[index] = value;
+ ptimer_set_limit(s->timer[index], s->interval[index], 1);
+ break;
+ case AW_A10_PIT_TIMER_COUNT:
+ s->count[index] = value;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ }
+ break;
+ case AW_A10_PIT_WDOG_CONTROL:
+ s->watch_dog_control = value;
+ break;
+ case AW_A10_PIT_WDOG_MODE:
+ s->watch_dog_mode = value;
+ break;
+ case AW_A10_PIT_COUNT_LO:
+ s->count_lo = value;
+ break;
+ case AW_A10_PIT_COUNT_HI:
+ s->count_hi = value;
+ break;
+ case AW_A10_PIT_COUNT_CTL:
+ s->count_ctl = value;
+ if (s->count_ctl & AW_A10_PIT_COUNT_RL_EN) {
+ uint64_t tmp_count = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ s->count_lo = tmp_count;
+ s->count_hi = tmp_count >> 32;
+ s->count_ctl &= ~AW_A10_PIT_COUNT_RL_EN;
+ }
+ if (s->count_ctl & AW_A10_PIT_COUNT_CLR_EN) {
+ s->count_lo = 0;
+ s->count_hi = 0;
+ s->count_ctl &= ~AW_A10_PIT_COUNT_CLR_EN;
+ }
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ break;
+ }
+}
+
+static const MemoryRegionOps a10_pit_ops = {
+ .read = a10_pit_read,
+ .write = a10_pit_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_a10_pit = {
+ .name = "a10.pit",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(irq_enable, AwA10PITState),
+ VMSTATE_UINT32(irq_status, AwA10PITState),
+ VMSTATE_UINT32_ARRAY(control, AwA10PITState, AW_A10_PIT_TIMER_NR),
+ VMSTATE_UINT32_ARRAY(interval, AwA10PITState, AW_A10_PIT_TIMER_NR),
+ VMSTATE_UINT32_ARRAY(count, AwA10PITState, AW_A10_PIT_TIMER_NR),
+ VMSTATE_UINT32(watch_dog_mode, AwA10PITState),
+ VMSTATE_UINT32(watch_dog_control, AwA10PITState),
+ VMSTATE_UINT32(count_lo, AwA10PITState),
+ VMSTATE_UINT32(count_hi, AwA10PITState),
+ VMSTATE_UINT32(count_ctl, AwA10PITState),
+ VMSTATE_PTIMER_ARRAY(timer, AwA10PITState, AW_A10_PIT_TIMER_NR),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void a10_pit_reset(DeviceState *dev)
+{
+ AwA10PITState *s = AW_A10_PIT(dev);
+ uint8_t i;
+
+ s->irq_enable = 0;
+ s->irq_status = 0;
+ for (i = 0; i < 6; i++) {
+ s->control[i] = AW_A10_PIT_DEFAULT_CLOCK;
+ s->interval[i] = 0;
+ s->count[i] = 0;
+ ptimer_stop(s->timer[i]);
+ }
+ s->watch_dog_mode = 0;
+ s->watch_dog_control = 0;
+ s->count_lo = 0;
+ s->count_hi = 0;
+ s->count_ctl = 0;
+}
+
+static void a10_pit_timer_cb(void *opaque)
+{
+ AwA10PITState *s = AW_A10_PIT(opaque);
+ uint8_t i;
+
+ for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
+ if (s->control[i] & AW_A10_PIT_TIMER_EN) {
+ s->irq_status |= 1 << i;
+ if (s->control[i] & AW_A10_PIT_TIMER_MODE) {
+ ptimer_stop(s->timer[i]);
+ s->control[i] &= ~AW_A10_PIT_TIMER_EN;
+ }
+ qemu_irq_pulse(s->irq[i]);
+ }
+ }
+}
+
+static void a10_pit_init(Object *obj)
+{
+ AwA10PITState *s = AW_A10_PIT(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ QEMUBH * bh[AW_A10_PIT_TIMER_NR];
+ uint8_t i;
+
+ for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
+ sysbus_init_irq(sbd, &s->irq[i]);
+ }
+ memory_region_init_io(&s->iomem, OBJECT(s), &a10_pit_ops, s,
+ TYPE_AW_A10_PIT, 0x400);
+ sysbus_init_mmio(sbd, &s->iomem);
+
+ for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
+ bh[i] = qemu_bh_new(a10_pit_timer_cb, s);
+ s->timer[i] = ptimer_init(bh[i]);
+ ptimer_set_freq(s->timer[i], 240000);
+ }
+}
+
+static void a10_pit_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = a10_pit_reset;
+ dc->desc = "allwinner a10 timer";
+ dc->vmsd = &vmstate_a10_pit;
+}
+
+static const TypeInfo a10_pit_info = {
+ .name = TYPE_AW_A10_PIT,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AwA10PITState),
+ .instance_init = a10_pit_init,
+ .class_init = a10_pit_class_init,
+};
+
+static void a10_register_types(void)
+{
+ type_register_static(&a10_pit_info);
+}
+
+type_init(a10_register_types);
diff --git a/include/hw/timer/allwinner-a10-pit.h b/include/hw/timer/allwinner-a10-pit.h
new file mode 100644
index 0000000..15efab8
--- /dev/null
+++ b/include/hw/timer/allwinner-a10-pit.h
@@ -0,0 +1,58 @@
+#ifndef AW_A10_PIT_H
+#define AW_A10_PIT_H
+
+#include "hw/ptimer.h"
+
+#define TYPE_AW_A10_PIT "allwinner-A10-timer"
+#define AW_A10_PIT(obj) OBJECT_CHECK(AwA10PITState, (obj), TYPE_AW_A10_PIT)
+
+#define AW_A10_PIT_TIMER_NR 6
+#define AW_A10_PIT_TIMER_IRQ 0x1
+#define AW_A10_PIT_WDOG_IRQ 0x100
+
+#define AW_A10_PIT_TIMER_IRQ_EN 0
+#define AW_A10_PIT_TIMER_IRQ_ST 0x4
+
+#define AW_A10_PIT_TIMER_CONTROL 0x0
+#define AW_A10_PIT_TIMER_EN 0x1
+#define AW_A10_PIT_TIMER_RELOAD 0x2
+#define AW_A10_PIT_TIMER_MODE 0x80
+
+#define AW_A10_PIT_TIMER_INTERVAL 0x4
+#define AW_A10_PIT_TIMER_COUNT 0x8
+#define AW_A10_PIT_WDOG_CONTROL 0x90
+#define AW_A10_PIT_WDOG_MODE 0x94
+
+#define AW_A10_PIT_COUNT_CTL 0xa0
+#define AW_A10_PIT_COUNT_RL_EN 0x2
+#define AW_A10_PIT_COUNT_CLR_EN 0x1
+#define AW_A10_PIT_COUNT_LO 0xa4
+#define AW_A10_PIT_COUNT_HI 0xa8
+
+#define AW_A10_PIT_TIMER_BASE 0x10
+#define AW_A10_PIT_TIMER_BASE_END \
+ (AW_A10_PIT_TIMER_BASE * 6 + AW_A10_PIT_TIMER_COUNT)
+
+#define AW_A10_PIT_DEFAULT_CLOCK 0x4
+
+typedef struct AwA10PITState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+ qemu_irq irq[AW_A10_PIT_TIMER_NR];
+ ptimer_state * timer[AW_A10_PIT_TIMER_NR];
+ MemoryRegion iomem;
+
+ uint32_t irq_enable;
+ uint32_t irq_status;
+ uint32_t control[AW_A10_PIT_TIMER_NR];
+ uint32_t interval[AW_A10_PIT_TIMER_NR];
+ uint32_t count[AW_A10_PIT_TIMER_NR];
+ uint32_t watch_dog_mode;
+ uint32_t watch_dog_control;
+ uint32_t count_lo;
+ uint32_t count_hi;
+ uint32_t count_ctl;
+} AwA10PITState;
+
+#endif
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 59/62] hw/intc: add allwinner A10 interrupt controller
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (57 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 58/62] hw/timer: add allwinner a10 timer Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 60/62] hw/arm: add allwinner a10 SoC support Peter Maydell
` (3 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: liguang <lig.fnst@cn.fujitsu.com>
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1387159292-10436-4-git-send-email-lig.fnst@cn.fujitsu.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
default-configs/arm-softmmu.mak | 1 +
hw/intc/Makefile.objs | 1 +
hw/intc/allwinner-a10-pic.c | 200 ++++++++++++++++++++++++++++++++++++
include/hw/intc/allwinner-a10-pic.h | 40 ++++++++
4 files changed, 242 insertions(+)
create mode 100644 hw/intc/allwinner-a10-pic.c
create mode 100644 include/hw/intc/allwinner-a10-pic.h
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 14c68b4..216651e 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -85,3 +85,4 @@ CONFIG_SDHCI=y
CONFIG_INTEGRATOR_DEBUG=y
CONFIG_ALLWINNER_A10_PIT=y
+CONFIG_ALLWINNER_A10_PIC=y
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 47ac442..60eb936 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -24,3 +24,4 @@ obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o
obj-$(CONFIG_SH4) += sh_intc.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
+obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
diff --git a/hw/intc/allwinner-a10-pic.c b/hw/intc/allwinner-a10-pic.c
new file mode 100644
index 0000000..407d563
--- /dev/null
+++ b/hw/intc/allwinner-a10-pic.c
@@ -0,0 +1,200 @@
+/*
+ * Allwinner A10 interrupt controller device emulation
+ *
+ * Copyright (C) 2013 Li Guang
+ * Written by Li Guang <lig.fnst@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "sysemu/sysemu.h"
+#include "hw/intc/allwinner-a10-pic.h"
+
+static void aw_a10_pic_update(AwA10PICState *s)
+{
+ uint8_t i;
+ int irq = 0, fiq = 0;
+
+ for (i = 0; i < AW_A10_PIC_REG_NUM; i++) {
+ irq |= s->irq_pending[i] & ~s->mask[i];
+ fiq |= s->select[i] & s->irq_pending[i] & ~s->mask[i];
+ }
+
+ qemu_set_irq(s->parent_irq, !!irq);
+ qemu_set_irq(s->parent_fiq, !!fiq);
+}
+
+static void aw_a10_pic_set_irq(void *opaque, int irq, int level)
+{
+ AwA10PICState *s = opaque;
+
+ if (level) {
+ set_bit(irq % 32, (void *)&s->irq_pending[irq / 32]);
+ }
+ aw_a10_pic_update(s);
+}
+
+static uint64_t aw_a10_pic_read(void *opaque, hwaddr offset, unsigned size)
+{
+ AwA10PICState *s = opaque;
+ uint8_t index = (offset & 0xc) / 4;
+
+ switch (offset) {
+ case AW_A10_PIC_VECTOR:
+ return s->vector;
+ case AW_A10_PIC_BASE_ADDR:
+ return s->base_addr;
+ case AW_A10_PIC_PROTECT:
+ return s->protect;
+ case AW_A10_PIC_NMI:
+ return s->nmi;
+ case AW_A10_PIC_IRQ_PENDING ... AW_A10_PIC_IRQ_PENDING + 8:
+ return s->irq_pending[index];
+ case AW_A10_PIC_FIQ_PENDING ... AW_A10_PIC_FIQ_PENDING + 8:
+ return s->fiq_pending[index];
+ case AW_A10_PIC_SELECT ... AW_A10_PIC_SELECT + 8:
+ return s->select[index];
+ case AW_A10_PIC_ENABLE ... AW_A10_PIC_ENABLE + 8:
+ return s->enable[index];
+ case AW_A10_PIC_MASK ... AW_A10_PIC_MASK + 8:
+ return s->mask[index];
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ break;
+ }
+
+ return 0;
+}
+
+static void aw_a10_pic_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ AwA10PICState *s = opaque;
+ uint8_t index = (offset & 0xc) / 4;
+
+ switch (offset) {
+ case AW_A10_PIC_VECTOR:
+ s->vector = value & ~0x3;
+ break;
+ case AW_A10_PIC_BASE_ADDR:
+ s->base_addr = value & ~0x3;
+ case AW_A10_PIC_PROTECT:
+ s->protect = value;
+ break;
+ case AW_A10_PIC_NMI:
+ s->nmi = value;
+ break;
+ case AW_A10_PIC_IRQ_PENDING ... AW_A10_PIC_IRQ_PENDING + 8:
+ s->irq_pending[index] &= ~value;
+ break;
+ case AW_A10_PIC_FIQ_PENDING ... AW_A10_PIC_FIQ_PENDING + 8:
+ s->fiq_pending[index] &= ~value;
+ break;
+ case AW_A10_PIC_SELECT ... AW_A10_PIC_SELECT + 8:
+ s->select[index] = value;
+ break;
+ case AW_A10_PIC_ENABLE ... AW_A10_PIC_ENABLE + 8:
+ s->enable[index] = value;
+ break;
+ case AW_A10_PIC_MASK ... AW_A10_PIC_MASK + 8:
+ s->mask[index] = value;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%x\n", __func__, (int)offset);
+ break;
+ }
+
+ aw_a10_pic_update(s);
+}
+
+static const MemoryRegionOps aw_a10_pic_ops = {
+ .read = aw_a10_pic_read,
+ .write = aw_a10_pic_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_aw_a10_pic = {
+ .name = "a10.pic",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(vector, AwA10PICState),
+ VMSTATE_UINT32(base_addr, AwA10PICState),
+ VMSTATE_UINT32(protect, AwA10PICState),
+ VMSTATE_UINT32(nmi, AwA10PICState),
+ VMSTATE_UINT32_ARRAY(irq_pending, AwA10PICState, AW_A10_PIC_REG_NUM),
+ VMSTATE_UINT32_ARRAY(fiq_pending, AwA10PICState, AW_A10_PIC_REG_NUM),
+ VMSTATE_UINT32_ARRAY(enable, AwA10PICState, AW_A10_PIC_REG_NUM),
+ VMSTATE_UINT32_ARRAY(select, AwA10PICState, AW_A10_PIC_REG_NUM),
+ VMSTATE_UINT32_ARRAY(mask, AwA10PICState, AW_A10_PIC_REG_NUM),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void aw_a10_pic_init(Object *obj)
+{
+ AwA10PICState *s = AW_A10_PIC(obj);
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
+
+ qdev_init_gpio_in(DEVICE(dev), aw_a10_pic_set_irq, AW_A10_PIC_INT_NR);
+ sysbus_init_irq(dev, &s->parent_irq);
+ sysbus_init_irq(dev, &s->parent_fiq);
+ memory_region_init_io(&s->iomem, OBJECT(s), &aw_a10_pic_ops, s,
+ TYPE_AW_A10_PIC, 0x400);
+ sysbus_init_mmio(dev, &s->iomem);
+}
+
+static void aw_a10_pic_reset(DeviceState *d)
+{
+ AwA10PICState *s = AW_A10_PIC(d);
+ uint8_t i;
+
+ s->base_addr = 0;
+ s->protect = 0;
+ s->nmi = 0;
+ s->vector = 0;
+ for (i = 0; i < AW_A10_PIC_REG_NUM; i++) {
+ s->irq_pending[i] = 0;
+ s->fiq_pending[i] = 0;
+ s->select[i] = 0;
+ s->enable[i] = 0;
+ s->mask[i] = 0;
+ }
+}
+
+static void aw_a10_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = aw_a10_pic_reset;
+ dc->desc = "allwinner a10 pic";
+ dc->vmsd = &vmstate_aw_a10_pic;
+ }
+
+static const TypeInfo aw_a10_pic_info = {
+ .name = TYPE_AW_A10_PIC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AwA10PICState),
+ .instance_init = aw_a10_pic_init,
+ .class_init = aw_a10_pic_class_init,
+};
+
+static void aw_a10_register_types(void)
+{
+ type_register_static(&aw_a10_pic_info);
+}
+
+type_init(aw_a10_register_types);
diff --git a/include/hw/intc/allwinner-a10-pic.h b/include/hw/intc/allwinner-a10-pic.h
new file mode 100644
index 0000000..5721b2e
--- /dev/null
+++ b/include/hw/intc/allwinner-a10-pic.h
@@ -0,0 +1,40 @@
+#ifndef AW_A10_PIC_H
+#define AW_A10_PIC_H
+
+#define TYPE_AW_A10_PIC "allwinner-a10-pic"
+#define AW_A10_PIC(obj) OBJECT_CHECK(AwA10PICState, (obj), TYPE_AW_A10_PIC)
+
+#define AW_A10_PIC_VECTOR 0
+#define AW_A10_PIC_BASE_ADDR 4
+#define AW_A10_PIC_PROTECT 8
+#define AW_A10_PIC_NMI 0xc
+#define AW_A10_PIC_IRQ_PENDING 0x10
+#define AW_A10_PIC_FIQ_PENDING 0x20
+#define AW_A10_PIC_SELECT 0x30
+#define AW_A10_PIC_ENABLE 0x40
+#define AW_A10_PIC_MASK 0x50
+
+#define AW_A10_PIC_INT_NR 95
+#define AW_A10_PIC_REG_NUM DIV_ROUND_UP(AW_A10_PIC_INT_NR, 32)
+
+typedef struct AwA10PICState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+ MemoryRegion iomem;
+ qemu_irq parent_fiq;
+ qemu_irq parent_irq;
+
+ uint32_t vector;
+ uint32_t base_addr;
+ uint32_t protect;
+ uint32_t nmi;
+ uint32_t irq_pending[AW_A10_PIC_REG_NUM];
+ uint32_t fiq_pending[AW_A10_PIC_REG_NUM];
+ uint32_t select[AW_A10_PIC_REG_NUM];
+ uint32_t enable[AW_A10_PIC_REG_NUM];
+ uint32_t mask[AW_A10_PIC_REG_NUM];
+ /*priority setting here*/
+} AwA10PICState;
+
+#endif
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 60/62] hw/arm: add allwinner a10 SoC support
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (58 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 59/62] hw/intc: add allwinner A10 interrupt controller Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 61/62] hw/arm: add cubieboard support Peter Maydell
` (2 subsequent siblings)
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: liguang <lig.fnst@cn.fujitsu.com>
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: 1387159292-10436-5-git-send-email-lig.fnst@cn.fujitsu.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
default-configs/arm-softmmu.mak | 1 +
hw/arm/Makefile.objs | 1 +
hw/arm/allwinner-a10.c | 103 ++++++++++++++++++++++++++++++++++++++++
include/hw/arm/allwinner-a10.h | 35 ++++++++++++++
4 files changed, 140 insertions(+)
create mode 100644 hw/arm/allwinner-a10.c
create mode 100644 include/hw/arm/allwinner-a10.h
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 216651e..ce1d620 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -86,3 +86,4 @@ CONFIG_INTEGRATOR_DEBUG=y
CONFIG_ALLWINNER_A10_PIT=y
CONFIG_ALLWINNER_A10_PIC=y
+CONFIG_ALLWINNER_A10=y
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index d7d37f2..fab30a7 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -7,3 +7,4 @@ obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
obj-$(CONFIG_DIGIC) += digic.o
obj-y += omap1.o omap2.o strongarm.o
+obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o
diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c
new file mode 100644
index 0000000..4658e19
--- /dev/null
+++ b/hw/arm/allwinner-a10.c
@@ -0,0 +1,103 @@
+/*
+ * Allwinner A10 SoC emulation
+ *
+ * Copyright (C) 2013 Li Guang
+ * Written by Li Guang <lig.fnst@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "hw/arm/allwinner-a10.h"
+
+static void aw_a10_init(Object *obj)
+{
+ AwA10State *s = AW_A10(obj);
+
+ object_initialize(&s->cpu, sizeof(s->cpu), "cortex-a8-" TYPE_ARM_CPU);
+ object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL);
+
+ object_initialize(&s->intc, sizeof(s->intc), TYPE_AW_A10_PIC);
+ qdev_set_parent_bus(DEVICE(&s->intc), sysbus_get_default());
+
+ object_initialize(&s->timer, sizeof(s->timer), TYPE_AW_A10_PIT);
+ qdev_set_parent_bus(DEVICE(&s->timer), sysbus_get_default());
+}
+
+static void aw_a10_realize(DeviceState *dev, Error **errp)
+{
+ AwA10State *s = AW_A10(dev);
+ SysBusDevice *sysbusdev;
+ uint8_t i;
+ qemu_irq fiq, irq;
+ Error *err = NULL;
+
+ object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ irq = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ);
+ fiq = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ);
+
+ object_property_set_bool(OBJECT(&s->intc), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbusdev = SYS_BUS_DEVICE(&s->intc);
+ sysbus_mmio_map(sysbusdev, 0, AW_A10_PIC_REG_BASE);
+ sysbus_connect_irq(sysbusdev, 0, irq);
+ sysbus_connect_irq(sysbusdev, 1, fiq);
+ for (i = 0; i < AW_A10_PIC_INT_NR; i++) {
+ s->irq[i] = qdev_get_gpio_in(DEVICE(&s->intc), i);
+ }
+
+ object_property_set_bool(OBJECT(&s->timer), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbusdev = SYS_BUS_DEVICE(&s->timer);
+ sysbus_mmio_map(sysbusdev, 0, AW_A10_PIT_REG_BASE);
+ sysbus_connect_irq(sysbusdev, 0, s->irq[22]);
+ sysbus_connect_irq(sysbusdev, 1, s->irq[23]);
+ sysbus_connect_irq(sysbusdev, 2, s->irq[24]);
+ sysbus_connect_irq(sysbusdev, 3, s->irq[25]);
+ sysbus_connect_irq(sysbusdev, 4, s->irq[67]);
+ sysbus_connect_irq(sysbusdev, 5, s->irq[68]);
+
+ serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2, s->irq[1],
+ 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
+}
+
+static void aw_a10_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = aw_a10_realize;
+}
+
+static const TypeInfo aw_a10_type_info = {
+ .name = TYPE_AW_A10,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(AwA10State),
+ .instance_init = aw_a10_init,
+ .class_init = aw_a10_class_init,
+};
+
+static void aw_a10_register_types(void)
+{
+ type_register_static(&aw_a10_type_info);
+}
+
+type_init(aw_a10_register_types)
diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h
new file mode 100644
index 0000000..da36647
--- /dev/null
+++ b/include/hw/arm/allwinner-a10.h
@@ -0,0 +1,35 @@
+#ifndef ALLWINNER_H_
+
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "hw/char/serial.h"
+#include "hw/arm/arm.h"
+#include "hw/timer/allwinner-a10-pit.h"
+#include "hw/intc/allwinner-a10-pic.h"
+
+#include "sysemu/sysemu.h"
+#include "exec/address-spaces.h"
+
+
+#define AW_A10_PIC_REG_BASE 0x01c20400
+#define AW_A10_PIT_REG_BASE 0x01c20c00
+#define AW_A10_UART0_REG_BASE 0x01c28000
+
+#define AW_A10_SDRAM_BASE 0x40000000
+
+#define TYPE_AW_A10 "allwinner-a10"
+#define AW_A10(obj) OBJECT_CHECK(AwA10State, (obj), TYPE_AW_A10)
+
+typedef struct AwA10State {
+ /*< private >*/
+ DeviceState parent_obj;
+ /*< public >*/
+
+ ARMCPU cpu;
+ qemu_irq irq[AW_A10_PIC_INT_NR];
+ AwA10PITState timer;
+ AwA10PICState intc;
+} AwA10State;
+
+#define ALLWINNER_H_
+#endif
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 61/62] hw/arm: add cubieboard support
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (59 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 60/62] hw/arm: add allwinner a10 SoC support Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-17 20:29 ` [Qemu-devel] [PULL 62/62] MAINTAINERS: add myself to maintain allwinner-a10 Peter Maydell
2013-12-20 0:14 ` [Qemu-devel] [PULL 00/62] target-arm queue Anthony Liguori
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: liguang <lig.fnst@cn.fujitsu.com>
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: 1387159292-10436-6-git-send-email-lig.fnst@cn.fujitsu.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/Makefile.objs | 2 +-
hw/arm/cubieboard.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++
tests/qom-test.c | 1 +
3 files changed, 71 insertions(+), 1 deletion(-)
create mode 100644 hw/arm/cubieboard.c
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index fab30a7..6088e53 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -7,4 +7,4 @@ obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
obj-$(CONFIG_DIGIC) += digic.o
obj-y += omap1.o omap2.o strongarm.o
-obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o
+obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c
new file mode 100644
index 0000000..3fcb6d2
--- /dev/null
+++ b/hw/arm/cubieboard.c
@@ -0,0 +1,69 @@
+/*
+ * cubieboard emulation
+ *
+ * Copyright (C) 2013 Li Guang
+ * Written by Li Guang <lig.fnst@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "hw/boards.h"
+#include "hw/arm/allwinner-a10.h"
+
+static struct arm_boot_info cubieboard_binfo = {
+ .loader_start = AW_A10_SDRAM_BASE,
+ .board_id = 0x1008,
+};
+
+typedef struct CubieBoardState {
+ AwA10State *a10;
+ MemoryRegion sdram;
+} CubieBoardState;
+
+static void cubieboard_init(QEMUMachineInitArgs *args)
+{
+ CubieBoardState *s = g_new(CubieBoardState, 1);
+ Error *err = NULL;
+
+ s->a10 = AW_A10(object_new(TYPE_AW_A10));
+ object_property_set_bool(OBJECT(s->a10), true, "realized", &err);
+ if (err != NULL) {
+ error_report("Couldn't realize Allwinner A10: %s\n",
+ error_get_pretty(err));
+ exit(1);
+ }
+
+ memory_region_init_ram(&s->sdram, NULL, "cubieboard.ram", args->ram_size);
+ vmstate_register_ram_global(&s->sdram);
+ memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE,
+ &s->sdram);
+
+ cubieboard_binfo.ram_size = args->ram_size;
+ cubieboard_binfo.kernel_filename = args->kernel_filename;
+ cubieboard_binfo.kernel_cmdline = args->kernel_cmdline;
+ arm_load_kernel(&s->a10->cpu, &cubieboard_binfo);
+}
+
+static QEMUMachine cubieboard_machine = {
+ .name = "cubieboard",
+ .desc = "cubietech cubieboard",
+ .init = cubieboard_init,
+};
+
+
+static void cubieboard_machine_init(void)
+{
+ qemu_register_machine(&cubieboard_machine);
+}
+
+machine_init(cubieboard_machine_init)
diff --git a/tests/qom-test.c b/tests/qom-test.c
index f67f7c2..5e5af7a 100644
--- a/tests/qom-test.c
+++ b/tests/qom-test.c
@@ -71,6 +71,7 @@ static const char *arm_machines[] = {
"highbank",
"midway",
"canon-a1100",
+ "cubieboard",
};
static const char *cris_machines[] = {
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [Qemu-devel] [PULL 62/62] MAINTAINERS: add myself to maintain allwinner-a10
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (60 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 61/62] hw/arm: add cubieboard support Peter Maydell
@ 2013-12-17 20:29 ` Peter Maydell
2013-12-20 0:14 ` [Qemu-devel] [PULL 00/62] target-arm queue Anthony Liguori
62 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-17 20:29 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
From: liguang <lig.fnst@cn.fujitsu.com>
Signed-off-by: liguang <lig.fnst@cn.fujitsu.com>
Message-id: 1387159292-10436-7-git-send-email-lig.fnst@cn.fujitsu.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 1fce9a5..a5ab8f8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -219,6 +219,13 @@ F: *win32*
ARM Machines
------------
+Allwinner-a10
+M: Li Guang <lig.fnst@cn.fujitsu.com>
+S: Maintained
+F: hw/*/allwinner-a10*
+F: include/hw/*/allwinner-a10*
+F: hw/arm/cubieboard.c
+
Exynos
M: Evgeny Voevodin <e.voevodin@samsung.com>
M: Maksim Kozlov <m.kozlov@samsung.com>
--
1.8.5
^ permalink raw reply related [flat|nested] 65+ messages in thread
* Re: [Qemu-devel] [PULL 00/62] target-arm queue
2013-12-17 20:28 [Qemu-devel] [PULL 00/62] target-arm queue Peter Maydell
` (61 preceding siblings ...)
2013-12-17 20:29 ` [Qemu-devel] [PULL 62/62] MAINTAINERS: add myself to maintain allwinner-a10 Peter Maydell
@ 2013-12-20 0:14 ` Anthony Liguori
2013-12-20 0:31 ` Peter Maydell
62 siblings, 1 reply; 65+ messages in thread
From: Anthony Liguori @ 2013-12-20 0:14 UTC (permalink / raw)
To: Peter Maydell, Anthony Liguori; +Cc: Blue Swirl, qemu-devel, Aurelien Jarno
Peter Maydell <peter.maydell@linaro.org> writes:
> Only took a week for the target-arm queue to fill up again :-)
> Please pull...
ubuntu@build:~/build/qemu$ make
CC aarch64-softmmu/gdbstub-xml.o
CC aarch64-softmmu/target-arm/cpu.o
/home/ubuntu/git/qemu/target-arm/cpu.c: In function ‘arm_cpu_post_init’:
/home/ubuntu/git/qemu/target-arm/cpu.c:260:9: error: implicit declaration of function ‘assert_no_error’ [-Werror=implicit-function-declaration]
/home/ubuntu/git/qemu/target-arm/cpu.c:260:9: error: nested extern declaration of ‘assert_no_error’ [-Werror=nested-externs]
cc1: all warnings being treated as errors
make[1]: *** [target-arm/cpu.o] Error 1
make: *** [subdir-aarch64-softmmu] Error 2
Regards,
Anthony Liguori
>
> thanks
> -- PMM
>
> The following changes since commit f46e720a82ccdf1a521cf459448f3f96ed895d43:
>
> qemu_opts_parse(): always check return value (2013-12-16 15:33:48 -0800)
>
> are available in the git repository at:
>
> git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20131217
>
> for you to fetch changes up to 84291fe7a34f8c2d595bcdb77ff506d1d60fcd7c:
>
> MAINTAINERS: add myself to maintain allwinner-a10 (2013-12-17 20:12:51 +0000)
>
> ----------------------------------------------------------------
> target-arm queue:
> * AES instruction support for 32 bit ARM
> * pflash01: much better emulation of 2x16bit and similar configs
> where multiple flash devices are banked together
> * fixed CBAR handling on Zynq, Highbank
> * initial AArch64 KVM control support
> * first two chunks of patches for A64 instruction emulation
> * new board: canon-a1100 (Canon DIGIC SoC)
> * new board: cubieboard (Allwinner A10 SoC)
>
> ----------------------------------------------------------------
> Alexander Graf (14):
> target-arm: A64: add set_pc cpu method
> target-arm: A64: add stubs for a64 specific helpers
> target-arm: A64: add support for B and BL insns
> target-arm: A64: add support for BR, BLR and RET insns
> target-arm: A64: add support for conditional branches
> target-arm: A64: add support for 'test and branch' imm
> target-arm: A64: add support for compare and branch imm
> target-arm: A64: add support for logical (shifted register)
> target-arm: A64: add support for ADR and ADRP
> target-arm: A64: add support for EXTR
> target-arm: A64: add support for 2-src data processing and DIV
> target-arm: A64: add support for 2-src shift reg insns
> target-arm: A64: add support for 1-src RBIT insn
> target-arm: A64: add support for logical (immediate) insns
>
> Antony Pavlov (8):
> ARM: cpu: add "reset_hivecs" property
> ARM: arm_cpu_reset: make it possible to use high vectors for reset_exc
> hw/arm: add very initial support for Canon DIGIC SoC
> hw/arm/digic: prepare DIGIC-based boards support
> hw/arm/digic: add timer support
> hw/arm/digic: add UART support
> hw/arm/digic: add NOR ROM support
> MAINTAINERS: Document 'Canon DIGIC' machine
>
> Ard Biesheuvel (1):
> target-arm: add support for v8 AES instructions
>
> Claudio Fontana (8):
> target-arm: A64: provide skeleton for a64 insn decoding
> target-arm: A64: expand decoding skeleton for system instructions
> target-arm: A64: add support for conditional select
> target-arm: A64: add support for 1-src data processing and CLZ
> target-arm: A64: add support for 1-src REV insns
> target-arm: A64: add support for bitfield insns
> host-utils: add clrsb32/64 - count leading redundant sign bits
> target-arm: A64: add support for 1-src CLS insn
>
> Mian M. Hamayun (2):
> target-arm: Add minimal KVM AArch64 support
> hw/arm/boot: Add boot support for AArch64 processor
>
> Peter Crosthwaite (8):
> target-arm/helper.c: Allow cp15.c15 dummy override
> target-arm: Define and use ARM_FEATURE_CBAR
> target-arm/cpu: Convert reset CBAR to a property
> arm/highbank: Use object_new() rather than cpu_arm_init()
> arm/highbank: Fix CBAR initialisation
> arm/xilinx_zynq: Use object_new() rather than cpu_arm_init()
> arm/xilinx_zynq: Implement CBAR initialisation
> arm/highbank.c: Fix MPCore periphbase name
>
> Peter Maydell (9):
> target-arm/kvm: Split 32 bit only code into its own file
> target-arm: Clean up handling of AArch64 PSTATE
> configure: Enable KVM for aarch64 host/target combination
> hw/arm/boot: Allow easier swapping in of different loader code
> default-configs: Add config for aarch64-softmmu
> target-arm: Split A64 from A32/T32 gen_intermediate_code_internal()
> target-arm: A64: provide functions for accessing FPCR and FPSR
> target-arm: Support fp registers in gdb stub
> vmstate: Add support for an array of ptimer_state *
>
> Roy Franz (7):
> rename pflash_t member width to bank_width
> Add device-width property to pflash_cfi01
> return status for each NOR flash device
> Set proper device-width for vexpress flash
> Add max device width parameter for NOR devices
> Fix CFI query responses for NOR flash
> Fix NOR flash device ID reading
>
> liguang (5):
> hw/timer: add allwinner a10 timer
> hw/intc: add allwinner A10 interrupt controller
> hw/arm: add allwinner a10 SoC support
> hw/arm: add cubieboard support
> MAINTAINERS: add myself to maintain allwinner-a10
>
> MAINTAINERS | 13 +
> configure | 4 +-
> default-configs/aarch64-softmmu.mak | 6 +
> default-configs/arm-softmmu.mak | 5 +
> gdb-xml/aarch64-fpu.xml | 86 ++
> hw/arm/Makefile.objs | 3 +
> hw/arm/allwinner-a10.c | 103 ++
> hw/arm/boot.c | 193 +++-
> hw/arm/cubieboard.c | 69 ++
> hw/arm/digic.c | 115 +++
> hw/arm/digic_boards.c | 162 ++++
> hw/arm/highbank.c | 33 +-
> hw/arm/vexpress.c | 44 +-
> hw/arm/xilinx_zynq.c | 21 +-
> hw/block/pflash_cfi01.c | 260 +++++-
> hw/char/Makefile.objs | 1 +
> hw/char/digic-uart.c | 195 ++++
> hw/intc/Makefile.objs | 1 +
> hw/intc/allwinner-a10-pic.c | 200 ++++
> hw/timer/Makefile.objs | 3 +
> hw/timer/allwinner-a10-pit.c | 254 +++++
> hw/timer/digic-timer.c | 163 ++++
> include/hw/arm/allwinner-a10.h | 35 +
> include/hw/arm/digic.h | 43 +
> include/hw/char/digic-uart.h | 47 +
> include/hw/intc/allwinner-a10-pic.h | 40 +
> include/hw/ptimer.h | 4 +
> include/hw/timer/allwinner-a10-pit.h | 58 ++
> include/hw/timer/digic-timer.h | 46 +
> include/migration/vmstate.h | 10 +
> include/qemu/host-utils.h | 32 +
> linux-user/signal.c | 6 +-
> target-arm/Makefile.objs | 5 +-
> target-arm/cpu-qom.h | 1 +
> target-arm/cpu.c | 54 +-
> target-arm/cpu.h | 100 +-
> target-arm/cpu64.c | 11 +
> target-arm/crypto_helper.c | 281 ++++++
> target-arm/gdbstub64.c | 4 +-
> target-arm/helper-a64.c | 79 ++
> target-arm/helper-a64.h | 24 +
> target-arm/helper.c | 60 +-
> target-arm/helper.h | 7 +
> target-arm/kvm.c | 495 +---------
> target-arm/kvm32.c | 515 ++++++++++
> target-arm/kvm64.c | 204 ++++
> target-arm/translate-a64.c | 1705 +++++++++++++++++++++++++++++++++-
> target-arm/translate.c | 102 +-
> target-arm/translate.h | 25 +-
> tests/qom-test.c | 2 +
> 50 files changed, 5232 insertions(+), 697 deletions(-)
> create mode 100644 default-configs/aarch64-softmmu.mak
> create mode 100644 gdb-xml/aarch64-fpu.xml
> create mode 100644 hw/arm/allwinner-a10.c
> create mode 100644 hw/arm/cubieboard.c
> create mode 100644 hw/arm/digic.c
> create mode 100644 hw/arm/digic_boards.c
> create mode 100644 hw/char/digic-uart.c
> create mode 100644 hw/intc/allwinner-a10-pic.c
> create mode 100644 hw/timer/allwinner-a10-pit.c
> create mode 100644 hw/timer/digic-timer.c
> create mode 100644 include/hw/arm/allwinner-a10.h
> create mode 100644 include/hw/arm/digic.h
> create mode 100644 include/hw/char/digic-uart.h
> create mode 100644 include/hw/intc/allwinner-a10-pic.h
> create mode 100644 include/hw/timer/allwinner-a10-pit.h
> create mode 100644 include/hw/timer/digic-timer.h
> create mode 100644 target-arm/crypto_helper.c
> create mode 100644 target-arm/helper-a64.c
> create mode 100644 target-arm/helper-a64.h
> create mode 100644 target-arm/kvm32.c
> create mode 100644 target-arm/kvm64.c
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [Qemu-devel] [PULL 00/62] target-arm queue
2013-12-20 0:14 ` [Qemu-devel] [PULL 00/62] target-arm queue Anthony Liguori
@ 2013-12-20 0:31 ` Peter Maydell
0 siblings, 0 replies; 65+ messages in thread
From: Peter Maydell @ 2013-12-20 0:31 UTC (permalink / raw)
To: Anthony Liguori
Cc: Blue Swirl, Aurelien Jarno, QEMU Developers, Anthony Liguori
On 20 December 2013 00:14, Anthony Liguori <anthony@codemonkey.ws> wrote:
> Peter Maydell <peter.maydell@linaro.org> writes:
>
>> Only took a week for the target-arm queue to fill up again :-)
>> Please pull...
>
> ubuntu@build:~/build/qemu$ make
> CC aarch64-softmmu/gdbstub-xml.o
> CC aarch64-softmmu/target-arm/cpu.o
> /home/ubuntu/git/qemu/target-arm/cpu.c: In function ‘arm_cpu_post_init’:
> /home/ubuntu/git/qemu/target-arm/cpu.c:260:9: error: implicit declaration of function ‘assert_no_error’ [-Werror=implicit-function-declaration]
> /home/ubuntu/git/qemu/target-arm/cpu.c:260:9: error: nested extern declaration of ‘assert_no_error’ [-Werror=nested-externs]
> cc1: all warnings being treated as errors
> make[1]: *** [target-arm/cpu.o] Error 1
> make: *** [subdir-aarch64-softmmu] Error 2
Urgh. Looks like the QMP queue included a patch which removes
assert_no_error! If you applied pullrequests in chronological
order you'd have found this one built and that one didn't :-)
thanks
-- PMM
^ permalink raw reply [flat|nested] 65+ messages in thread