1
The following changes since commit 4c41341af76cfc85b5a6c0f87de4838672ab9f89:
1
Arm queue; not huge but I figured I might as well send it out since
2
I've been doing code review today and there's no queue of unprocessed
3
pullreqs...
2
4
3
Merge remote-tracking branch 'remotes/aperard/tags/pull-xen-20201020' into staging (2020-10-20 11:20:36 +0100)
5
thanks
6
-- PMM
7
8
The following changes since commit b3f846c59d8405bb87c551187721fc92ff2f1b92:
9
10
Merge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2021-01-11v2' into staging (2021-01-11 15:15:35 +0000)
4
11
5
are available in the Git repository at:
12
are available in the Git repository at:
6
13
7
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20201020
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210112
8
15
9
for you to fetch changes up to 6358890cb939192f6169fdf7664d903bf9b1d338:
16
for you to fetch changes up to 19d131395ccaf503db21dadd8257e6dc9fc1d7de:
10
17
11
tests/tcg/aarch64: Add bti smoke tests (2020-10-20 16:12:02 +0100)
18
ui/cocoa: Fix openFile: deprecation on Big Sur (2021-01-12 11:38:37 +0000)
12
19
13
----------------------------------------------------------------
20
----------------------------------------------------------------
14
target-arm queue:
21
target-arm queue:
15
* Fix AArch32 SMLAD incorrect setting of Q bit
22
* arm: Support emulation of ARMv8.4-TTST extension
16
* AArch32 VCVT fixed-point to float is always round-to-nearest
23
* arm: Update cpu.h ID register field definitions
17
* strongarm: Fix 'time to transmit a char' unit comment
24
* arm: Fix breakage of XScale instruction emulation
18
* Restrict APEI tables generation to the 'virt' machine
25
* hw/net/lan9118: Fix RX Status FIFO PEEK value
19
* bcm2835: minor code cleanups
26
* npcm7xx: Add ADC and PWM emulation
20
* correctly flush TLBs when TBI is enabled
27
* ui/cocoa: Make "open docs" help menu entry work again when binary
21
* tests/qtest: Add npcm7xx timer test
28
is run from the build tree
22
* loads-stores.rst: add footnote that clarifies GETPC usage
29
* ui/cocoa: Fix openFile: deprecation on Big Sur
23
* Fix reported EL for mte_check_fail
30
* docs: Add qemu-storage-daemon(1) manpage to meson.build
24
* Ignore HCR_EL2.ATA when {E2H,TGE} != 11
31
* docs: Build and install all the docs in a single manual
25
* microbit_i2c: Fix coredump when dump-vmstate
26
* nseries: Fix loading kernel image on n8x0 machines
27
* Implement v8.1M low-overhead-loops
28
* linux-user: Support AArch64 BTI
29
32
30
----------------------------------------------------------------
33
----------------------------------------------------------------
31
Emanuele Giuseppe Esposito (1):
34
Hao Wu (6):
32
loads-stores.rst: add footnote that clarifies GETPC usage
35
hw/misc: Add clock converter in NPCM7XX CLK module
36
hw/timer: Refactor NPCM7XX Timer to use CLK clock
37
hw/adc: Add an ADC module for NPCM7XX
38
hw/misc: Add a PWM module for NPCM7XX
39
hw/misc: Add QTest for NPCM7XX PWM Module
40
hw/*: Use type casting for SysBusDevice in NPCM7XX
33
41
34
Havard Skinnemoen (1):
42
Leif Lindholm (6):
35
tests/qtest: Add npcm7xx timer test
43
target/arm: fix typo in cpu.h ID_AA64PFR1 field name
44
target/arm: make ARMCPU.clidr 64-bit
45
target/arm: make ARMCPU.ctr 64-bit
46
target/arm: add descriptions of CLIDR_EL1, CCSIDR_EL1, CTR_EL0 to cpu.h
47
target/arm: add aarch64 ID register fields to cpu.h
48
target/arm: add aarch32 ID register fields to cpu.h
36
49
37
Peng Liang (1):
50
Peter Maydell (5):
38
microbit_i2c: Fix coredump when dump-vmstate
51
docs: Add qemu-storage-daemon(1) manpage to meson.build
52
docs: Build and install all the docs in a single manual
53
target/arm: Don't decode insns in the XScale/iWMMXt space as cp insns
54
hw/net/lan9118: Fix RX Status FIFO PEEK value
55
hw/net/lan9118: Add symbolic constants for register offsets
39
56
40
Peter Maydell (12):
57
Roman Bolshakov (2):
41
target/arm: Fix SMLAD incorrect setting of Q bit
58
ui/cocoa: Update path to docs in build tree
42
target/arm: AArch32 VCVT fixed-point to float is always round-to-nearest
59
ui/cocoa: Fix openFile: deprecation on Big Sur
43
decodetree: Fix codegen for non-overlapping group inside overlapping group
44
target/arm: Implement v8.1M NOCP handling
45
target/arm: Implement v8.1M conditional-select insns
46
target/arm: Make the t32 insn[25:23]=111 group non-overlapping
47
target/arm: Don't allow BLX imm for M-profile
48
target/arm: Implement v8.1M branch-future insns (as NOPs)
49
target/arm: Implement v8.1M low-overhead-loop instructions
50
target/arm: Fix has_vfp/has_neon ID reg squashing for M-profile
51
target/arm: Allow M-profile CPUs with FP16 to set FPSCR.FP16
52
target/arm: Implement FPSCR.LTPSIZE for M-profile LOB extension
53
60
54
Philippe Mathieu-Daudé (10):
61
Rémi Denis-Courmont (2):
55
hw/arm/strongarm: Fix 'time to transmit a char' unit comment
62
target/arm: ARMv8.4-TTST extension
56
hw/arm: Restrict APEI tables generation to the 'virt' machine
63
target/arm: enable Small Translation tables in max CPU
57
hw/timer/bcm2835: Introduce BCM2835_SYSTIMER_COUNT definition
58
hw/timer/bcm2835: Rename variable holding CTRL_STATUS register
59
hw/timer/bcm2835: Support the timer COMPARE registers
60
hw/arm/bcm2835_peripherals: Correctly wire the SYS_timer IRQs
61
hw/intc/bcm2835_ic: Trace GPU/CPU IRQ handlers
62
hw/intc/bcm2836_control: Use IRQ definitions instead of magic numbers
63
hw/arm/nseries: Fix loading kernel image on n8x0 machines
64
linux-user/elfload: Avoid leaking interp_name using GLib memory API
65
64
66
Richard Henderson (16):
65
docs/conf.py | 46 ++-
67
accel/tcg: Add tlb_flush_page_bits_by_mmuidx*
66
docs/devel/conf.py | 15 -
68
target/arm: Use tlb_flush_page_bits_by_mmuidx*
67
docs/index.html.in | 17 -
69
target/arm: Remove redundant mmu_idx lookup
68
docs/interop/conf.py | 28 --
70
target/arm: Fix reported EL for mte_check_fail
69
docs/meson.build | 65 ++--
71
target/arm: Ignore HCR_EL2.ATA when {E2H,TGE} != 11
70
docs/specs/conf.py | 16 -
72
linux-user/aarch64: Reset btype for signals
71
docs/system/arm/nuvoton.rst | 4 +-
73
linux-user: Set PAGE_TARGET_1 for TARGET_PROT_BTI
72
docs/system/conf.py | 28 --
74
include/elf: Add defines related to GNU property notes for AArch64
73
docs/tools/conf.py | 37 --
75
linux-user/elfload: Fix coding style in load_elf_image
74
docs/user/conf.py | 15 -
76
linux-user/elfload: Adjust iteration over phdr
75
meson.build | 1 +
77
linux-user/elfload: Move PT_INTERP detection to first loop
76
hw/adc/trace.h | 1 +
78
linux-user/elfload: Use Error for load_elf_image
77
include/hw/adc/npcm7xx_adc.h | 69 ++++
79
linux-user/elfload: Use Error for load_elf_interp
78
include/hw/arm/npcm7xx.h | 4 +
80
linux-user/elfload: Parse NT_GNU_PROPERTY_TYPE_0 notes
79
include/hw/misc/npcm7xx_clk.h | 146 ++++++-
81
linux-user/elfload: Parse GNU_PROPERTY_AARCH64_FEATURE_1_AND
80
include/hw/misc/npcm7xx_pwm.h | 105 +++++
82
tests/tcg/aarch64: Add bti smoke tests
81
include/hw/timer/npcm7xx_timer.h | 1 +
82
target/arm/cpu.h | 85 ++++-
83
hw/adc/npcm7xx_adc.c | 301 +++++++++++++++
84
hw/arm/npcm7xx.c | 55 ++-
85
hw/arm/npcm7xx_boards.c | 2 +-
86
hw/mem/npcm7xx_mc.c | 2 +-
87
hw/misc/npcm7xx_clk.c | 807 ++++++++++++++++++++++++++++++++++++++-
88
hw/misc/npcm7xx_gcr.c | 2 +-
89
hw/misc/npcm7xx_pwm.c | 550 ++++++++++++++++++++++++++
90
hw/misc/npcm7xx_rng.c | 2 +-
91
hw/net/lan9118.c | 26 +-
92
hw/nvram/npcm7xx_otp.c | 2 +-
93
hw/ssi/npcm7xx_fiu.c | 2 +-
94
hw/timer/npcm7xx_timer.c | 39 +-
95
target/arm/cpu64.c | 1 +
96
target/arm/helper.c | 15 +-
97
target/arm/translate.c | 7 +
98
tests/qtest/npcm7xx_adc-test.c | 377 ++++++++++++++++++
99
tests/qtest/npcm7xx_pwm-test.c | 490 ++++++++++++++++++++++++
100
hw/adc/meson.build | 1 +
101
hw/adc/trace-events | 5 +
102
hw/misc/meson.build | 1 +
103
hw/misc/trace-events | 6 +
104
tests/qtest/meson.build | 4 +-
105
ui/cocoa.m | 7 +-
106
41 files changed, 3124 insertions(+), 263 deletions(-)
107
delete mode 100644 docs/devel/conf.py
108
delete mode 100644 docs/index.html.in
109
delete mode 100644 docs/interop/conf.py
110
delete mode 100644 docs/specs/conf.py
111
delete mode 100644 docs/system/conf.py
112
delete mode 100644 docs/tools/conf.py
113
delete mode 100644 docs/user/conf.py
114
create mode 100644 hw/adc/trace.h
115
create mode 100644 include/hw/adc/npcm7xx_adc.h
116
create mode 100644 include/hw/misc/npcm7xx_pwm.h
117
create mode 100644 hw/adc/npcm7xx_adc.c
118
create mode 100644 hw/misc/npcm7xx_pwm.c
119
create mode 100644 tests/qtest/npcm7xx_adc-test.c
120
create mode 100644 tests/qtest/npcm7xx_pwm-test.c
121
create mode 100644 hw/adc/trace-events
83
122
84
docs/devel/loads-stores.rst | 8 +-
85
default-configs/devices/arm-softmmu.mak | 1 -
86
include/elf.h | 22 ++
87
include/exec/cpu-all.h | 2 +
88
include/exec/exec-all.h | 36 ++
89
include/hw/timer/bcm2835_systmr.h | 17 +-
90
linux-user/qemu.h | 4 +
91
linux-user/syscall_defs.h | 4 +
92
target/arm/cpu.h | 13 +
93
target/arm/helper.h | 13 +
94
target/arm/internals.h | 9 +-
95
target/arm/m-nocp.decode | 10 +-
96
target/arm/t32.decode | 50 ++-
97
accel/tcg/cputlb.c | 275 +++++++++++++++-
98
hw/arm/bcm2835_peripherals.c | 13 +-
99
hw/arm/nseries.c | 1 +
100
hw/arm/strongarm.c | 2 +-
101
hw/i2c/microbit_i2c.c | 1 +
102
hw/intc/bcm2835_ic.c | 4 +-
103
hw/intc/bcm2836_control.c | 8 +-
104
hw/timer/bcm2835_systmr.c | 57 ++--
105
linux-user/aarch64/signal.c | 10 +-
106
linux-user/elfload.c | 326 ++++++++++++++----
107
linux-user/mmap.c | 16 +
108
target/arm/cpu.c | 38 ++-
109
target/arm/helper.c | 55 +++-
110
target/arm/mte_helper.c | 13 +-
111
target/arm/translate-a64.c | 6 +-
112
target/arm/translate.c | 239 +++++++++++++-
113
target/arm/vfp_helper.c | 76 +++--
114
tests/qtest/npcm7xx_timer-test.c | 562 ++++++++++++++++++++++++++++++++
115
tests/tcg/aarch64/bti-1.c | 62 ++++
116
tests/tcg/aarch64/bti-2.c | 108 ++++++
117
tests/tcg/aarch64/bti-crt.inc.c | 51 +++
118
hw/arm/Kconfig | 1 +
119
hw/intc/trace-events | 4 +
120
hw/timer/trace-events | 6 +-
121
scripts/decodetree.py | 2 +-
122
target/arm/translate-vfp.c.inc | 41 ++-
123
tests/qtest/meson.build | 1 +
124
tests/tcg/aarch64/Makefile.target | 10 +
125
tests/tcg/configure.sh | 4 +
126
42 files changed, 1973 insertions(+), 208 deletions(-)
127
create mode 100644 tests/qtest/npcm7xx_timer-test.c
128
create mode 100644 tests/tcg/aarch64/bti-1.c
129
create mode 100644 tests/tcg/aarch64/bti-2.c
130
create mode 100644 tests/tcg/aarch64/bti-crt.inc.c
131
diff view generated by jsdifflib
1
v8.1M implements a new 'branch future' feature, which is a
1
From: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
2
set of instructions that request the CPU to perform a branch
3
"in the future", when it reaches a particular execution address.
4
In hardware, the expected implementation is that the information
5
about the branch location and destination is cached and then
6
acted upon when execution reaches the specified address.
7
However the architecture permits an implementation to discard
8
this cached information at any point, and so guest code must
9
always include a normal branch insn at the branch point as
10
a fallback. In particular, an implementation is specifically
11
permitted to treat all BF insns as NOPs (which is equivalent
12
to discarding the cached information immediately).
13
2
14
For QEMU, implementing this caching of branch information
3
This adds for the Small Translation tables extension in AArch64 state.
15
would be complicated and would not improve the speed of
16
execution at all, so we make the IMPDEF choice to implement
17
all BF insns as NOPs.
18
4
5
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
19
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Message-id: 20201019151301.2046-7-peter.maydell@linaro.org
22
---
8
---
23
target/arm/cpu.h | 6 ++++++
9
target/arm/cpu.h | 5 +++++
24
target/arm/t32.decode | 13 ++++++++++++-
10
target/arm/helper.c | 15 +++++++++++++--
25
target/arm/translate.c | 20 ++++++++++++++++++++
11
2 files changed, 18 insertions(+), 2 deletions(-)
26
3 files changed, 38 insertions(+), 1 deletion(-)
27
12
28
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
13
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
29
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
30
--- a/target/arm/cpu.h
15
--- a/target/arm/cpu.h
31
+++ b/target/arm/cpu.h
16
+++ b/target/arm/cpu.h
32
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa32_arm_div(const ARMISARegisters *id)
17
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_uao(const ARMISARegisters *id)
33
return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) > 1;
18
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0;
34
}
19
}
35
20
36
+static inline bool isar_feature_aa32_lob(const ARMISARegisters *id)
21
+static inline bool isar_feature_aa64_st(const ARMISARegisters *id)
37
+{
22
+{
38
+ /* (M-profile) low-overhead loops and branch future */
23
+ return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0;
39
+ return FIELD_EX32(id->id_isar0, ID_ISAR0, CMPBRANCH) >= 3;
40
+}
24
+}
41
+
25
+
42
static inline bool isar_feature_aa32_jazelle(const ARMISARegisters *id)
26
static inline bool isar_feature_aa64_bti(const ARMISARegisters *id)
43
{
27
{
44
return FIELD_EX32(id->id_isar1, ID_ISAR1, JAZELLE) != 0;
28
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0;
45
diff --git a/target/arm/t32.decode b/target/arm/t32.decode
29
diff --git a/target/arm/helper.c b/target/arm/helper.c
46
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
47
--- a/target/arm/t32.decode
31
--- a/target/arm/helper.c
48
+++ b/target/arm/t32.decode
32
+++ b/target/arm/helper.c
49
@@ -XXX,XX +XXX,XX @@ MRC 1110 1110 ... 1 .... .... .... ... 1 .... @mcr
33
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
50
34
{
51
B 1111 0. .......... 10.1 ............ @branch24
35
uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
52
BL 1111 0. .......... 11.1 ............ @branch24
36
bool epd, hpd, using16k, using64k;
53
-BLX_i 1111 0. .......... 11.0 ............ @branch24
37
- int select, tsz, tbi;
54
+{
38
+ int select, tsz, tbi, max_tsz;
55
+ # BLX_i is non-M-profile only
39
56
+ BLX_i 1111 0. .......... 11.0 ............ @branch24
40
if (!regime_has_2_ranges(mmu_idx)) {
57
+ # M-profile only: loop and branch insns
41
select = 0;
58
+ [
42
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
59
+ # All these BF insns have boff != 0b0000; we NOP them all
43
hpd = extract64(tcr, 42, 1);
60
+ BF 1111 0 boff:4 ------- 1100 - ---------- 1 # BFL
44
}
61
+ BF 1111 0 boff:4 0 ------ 1110 - ---------- 1 # BFCSEL
45
}
62
+ BF 1111 0 boff:4 10 ----- 1110 - ---------- 1 # BF
46
- tsz = MIN(tsz, 39); /* TODO: ARMv8.4-TTST */
63
+ BF 1111 0 boff:4 11 ----- 1110 0 0000000000 1 # BFX, BFLX
47
+
64
+ ]
48
+ if (cpu_isar_feature(aa64_st, env_archcpu(env))) {
65
+}
49
+ max_tsz = 48 - using64k;
66
diff --git a/target/arm/translate.c b/target/arm/translate.c
50
+ } else {
67
index XXXXXXX..XXXXXXX 100644
51
+ max_tsz = 39;
68
--- a/target/arm/translate.c
69
+++ b/target/arm/translate.c
70
@@ -XXX,XX +XXX,XX @@ static bool trans_BLX_suffix(DisasContext *s, arg_BLX_suffix *a)
71
return true;
72
}
73
74
+static bool trans_BF(DisasContext *s, arg_BF *a)
75
+{
76
+ /*
77
+ * M-profile branch future insns. The architecture permits an
78
+ * implementation to implement these as NOPs (equivalent to
79
+ * discarding the LO_BRANCH_INFO cache immediately), and we
80
+ * take that IMPDEF option because for QEMU a "real" implementation
81
+ * would be complicated and wouldn't execute any faster.
82
+ */
83
+ if (!dc_isar_feature(aa32_lob, s)) {
84
+ return false;
85
+ }
52
+ }
86
+ if (a->boff == 0) {
87
+ /* SEE "Related encodings" (loop insns) */
88
+ return false;
89
+ }
90
+ /* Handle as NOP */
91
+ return true;
92
+}
93
+
53
+
94
static bool op_tbranch(DisasContext *s, arg_tbranch *a, bool half)
54
+ tsz = MIN(tsz, max_tsz);
95
{
55
tsz = MAX(tsz, 16); /* TODO: ARMv8.2-LVA */
96
TCGv_i32 addr, tmp;
56
57
/* Present TBI as a composite with TBID. */
58
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
59
if (!aarch64 || stride == 9) {
60
/* AArch32 or 4KB pages */
61
startlevel = 2 - sl0;
62
+
63
+ if (cpu_isar_feature(aa64_st, cpu)) {
64
+ startlevel &= 3;
65
+ }
66
} else {
67
/* 16KB or 64KB pages */
68
startlevel = 3 - sl0;
97
--
69
--
98
2.20.1
70
2.20.1
99
71
100
72
diff view generated by jsdifflib
1
From: Peng Liang <liangpeng10@huawei.com>
1
From: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
2
2
3
VMStateDescription.fields should be end with VMSTATE_END_OF_LIST().
3
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
4
However, microbit_i2c_vmstate doesn't follow it. Let's change it.
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
6
Fixes: 9d68bf564e ("arm: Stub out NRF51 TWI magnetometer/accelerometer detection")
7
Reported-by: Euler Robot <euler.robot@huawei.com>
8
Signed-off-by: Peng Liang <liangpeng10@huawei.com>
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
10
Message-id: 20201019093401.2993833-1-liangpeng10@huawei.com
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
6
---
13
hw/i2c/microbit_i2c.c | 1 +
7
target/arm/cpu64.c | 1 +
14
1 file changed, 1 insertion(+)
8
1 file changed, 1 insertion(+)
15
9
16
diff --git a/hw/i2c/microbit_i2c.c b/hw/i2c/microbit_i2c.c
10
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
17
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/i2c/microbit_i2c.c
12
--- a/target/arm/cpu64.c
19
+++ b/hw/i2c/microbit_i2c.c
13
+++ b/target/arm/cpu64.c
20
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription microbit_i2c_vmstate = {
14
@@ -XXX,XX +XXX,XX @@ static void aarch64_max_initfn(Object *obj)
21
.fields = (VMStateField[]) {
15
t = cpu->isar.id_aa64mmfr2;
22
VMSTATE_UINT32_ARRAY(regs, MicrobitI2CState, MICROBIT_I2C_NREGS),
16
t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);
23
VMSTATE_UINT32(read_idx, MicrobitI2CState),
17
t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */
24
+ VMSTATE_END_OF_LIST()
18
+ t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */
25
},
19
cpu->isar.id_aa64mmfr2 = t;
26
};
20
27
21
/* Replicate the same data to the 32-bit id registers. */
28
--
22
--
29
2.20.1
23
2.20.1
30
24
31
25
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
This is generic support, with the code disabled for all targets.
3
SBSS -> SSBS
4
4
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
6
Message-id: 20201016184207.786698-11-richard.henderson@linaro.org
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
9
Message-id: 20210108185154.8108-2-leif@nuviainc.com
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
11
---
10
linux-user/qemu.h | 4 ++
12
target/arm/cpu.h | 2 +-
11
linux-user/elfload.c | 157 +++++++++++++++++++++++++++++++++++++++++++
13
1 file changed, 1 insertion(+), 1 deletion(-)
12
2 files changed, 161 insertions(+)
13
14
14
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
15
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/linux-user/qemu.h
17
--- a/target/arm/cpu.h
17
+++ b/linux-user/qemu.h
18
+++ b/target/arm/cpu.h
18
@@ -XXX,XX +XXX,XX @@ struct image_info {
19
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64PFR0, RAS, 28, 4)
19
abi_ulong interpreter_loadmap_addr;
20
FIELD(ID_AA64PFR0, SVE, 32, 4)
20
abi_ulong interpreter_pt_dynamic_addr;
21
21
struct image_info *other_info;
22
FIELD(ID_AA64PFR1, BT, 0, 4)
22
+
23
-FIELD(ID_AA64PFR1, SBSS, 4, 4)
23
+ /* For target-specific processing of NT_GNU_PROPERTY_TYPE_0. */
24
+FIELD(ID_AA64PFR1, SSBS, 4, 4)
24
+ uint32_t note_flags;
25
FIELD(ID_AA64PFR1, MTE, 8, 4)
25
+
26
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
26
#ifdef TARGET_MIPS
27
int fp_abi;
28
int interp_fp_abi;
29
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/linux-user/elfload.c
32
+++ b/linux-user/elfload.c
33
@@ -XXX,XX +XXX,XX @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
34
35
#include "elf.h"
36
37
+static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
38
+ const uint32_t *data,
39
+ struct image_info *info,
40
+ Error **errp)
41
+{
42
+ g_assert_not_reached();
43
+}
44
+#define ARCH_USE_GNU_PROPERTY 0
45
+
46
struct exec
47
{
48
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
49
@@ -XXX,XX +XXX,XX @@ void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
50
"@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
51
}
52
53
+enum {
54
+ /* The string "GNU\0" as a magic number. */
55
+ GNU0_MAGIC = const_le32('G' | 'N' << 8 | 'U' << 16),
56
+ NOTE_DATA_SZ = 1 * KiB,
57
+ NOTE_NAME_SZ = 4,
58
+ ELF_GNU_PROPERTY_ALIGN = ELF_CLASS == ELFCLASS32 ? 4 : 8,
59
+};
60
+
61
+/*
62
+ * Process a single gnu_property entry.
63
+ * Return false for error.
64
+ */
65
+static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
66
+ struct image_info *info, bool have_prev_type,
67
+ uint32_t *prev_type, Error **errp)
68
+{
69
+ uint32_t pr_type, pr_datasz, step;
70
+
71
+ if (*off > datasz || !QEMU_IS_ALIGNED(*off, ELF_GNU_PROPERTY_ALIGN)) {
72
+ goto error_data;
73
+ }
74
+ datasz -= *off;
75
+ data += *off / sizeof(uint32_t);
76
+
77
+ if (datasz < 2 * sizeof(uint32_t)) {
78
+ goto error_data;
79
+ }
80
+ pr_type = data[0];
81
+ pr_datasz = data[1];
82
+ data += 2;
83
+ datasz -= 2 * sizeof(uint32_t);
84
+ step = ROUND_UP(pr_datasz, ELF_GNU_PROPERTY_ALIGN);
85
+ if (step > datasz) {
86
+ goto error_data;
87
+ }
88
+
89
+ /* Properties are supposed to be unique and sorted on pr_type. */
90
+ if (have_prev_type && pr_type <= *prev_type) {
91
+ if (pr_type == *prev_type) {
92
+ error_setg(errp, "Duplicate property in PT_GNU_PROPERTY");
93
+ } else {
94
+ error_setg(errp, "Unsorted property in PT_GNU_PROPERTY");
95
+ }
96
+ return false;
97
+ }
98
+ *prev_type = pr_type;
99
+
100
+ if (!arch_parse_elf_property(pr_type, pr_datasz, data, info, errp)) {
101
+ return false;
102
+ }
103
+
104
+ *off += 2 * sizeof(uint32_t) + step;
105
+ return true;
106
+
107
+ error_data:
108
+ error_setg(errp, "Ill-formed property in PT_GNU_PROPERTY");
109
+ return false;
110
+}
111
+
112
+/* Process NT_GNU_PROPERTY_TYPE_0. */
113
+static bool parse_elf_properties(int image_fd,
114
+ struct image_info *info,
115
+ const struct elf_phdr *phdr,
116
+ char bprm_buf[BPRM_BUF_SIZE],
117
+ Error **errp)
118
+{
119
+ union {
120
+ struct elf_note nhdr;
121
+ uint32_t data[NOTE_DATA_SZ / sizeof(uint32_t)];
122
+ } note;
123
+
124
+ int n, off, datasz;
125
+ bool have_prev_type;
126
+ uint32_t prev_type;
127
+
128
+ /* Unless the arch requires properties, ignore them. */
129
+ if (!ARCH_USE_GNU_PROPERTY) {
130
+ return true;
131
+ }
132
+
133
+ /* If the properties are crazy large, that's too bad. */
134
+ n = phdr->p_filesz;
135
+ if (n > sizeof(note)) {
136
+ error_setg(errp, "PT_GNU_PROPERTY too large");
137
+ return false;
138
+ }
139
+ if (n < sizeof(note.nhdr)) {
140
+ error_setg(errp, "PT_GNU_PROPERTY too small");
141
+ return false;
142
+ }
143
+
144
+ if (phdr->p_offset + n <= BPRM_BUF_SIZE) {
145
+ memcpy(&note, bprm_buf + phdr->p_offset, n);
146
+ } else {
147
+ ssize_t len = pread(image_fd, &note, n, phdr->p_offset);
148
+ if (len != n) {
149
+ error_setg_errno(errp, errno, "Error reading file header");
150
+ return false;
151
+ }
152
+ }
153
+
154
+ /*
155
+ * The contents of a valid PT_GNU_PROPERTY is a sequence
156
+ * of uint32_t -- swap them all now.
157
+ */
158
+#ifdef BSWAP_NEEDED
159
+ for (int i = 0; i < n / 4; i++) {
160
+ bswap32s(note.data + i);
161
+ }
162
+#endif
163
+
164
+ /*
165
+ * Note that nhdr is 3 words, and that the "name" described by namesz
166
+ * immediately follows nhdr and is thus at the 4th word. Further, all
167
+ * of the inputs to the kernel's round_up are multiples of 4.
168
+ */
169
+ if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 ||
170
+ note.nhdr.n_namesz != NOTE_NAME_SZ ||
171
+ note.data[3] != GNU0_MAGIC) {
172
+ error_setg(errp, "Invalid note in PT_GNU_PROPERTY");
173
+ return false;
174
+ }
175
+ off = sizeof(note.nhdr) + NOTE_NAME_SZ;
176
+
177
+ datasz = note.nhdr.n_descsz + off;
178
+ if (datasz > n) {
179
+ error_setg(errp, "Invalid note size in PT_GNU_PROPERTY");
180
+ return false;
181
+ }
182
+
183
+ have_prev_type = false;
184
+ prev_type = 0;
185
+ while (1) {
186
+ if (off == datasz) {
187
+ return true; /* end, exit ok */
188
+ }
189
+ if (!parse_elf_property(note.data, &off, datasz, info,
190
+ have_prev_type, &prev_type, errp)) {
191
+ return false;
192
+ }
193
+ have_prev_type = true;
194
+ }
195
+}
196
+
197
/* Load an ELF image into the address space.
198
199
IMAGE_NAME is the filename of the image, to use in error messages.
200
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
201
goto exit_errmsg;
202
}
203
*pinterp_name = g_steal_pointer(&interp_name);
204
+ } else if (eppnt->p_type == PT_GNU_PROPERTY) {
205
+ if (!parse_elf_properties(image_fd, info, eppnt, bprm_buf, &err)) {
206
+ goto exit_errmsg;
207
+ }
208
}
209
}
210
27
211
--
28
--
212
2.20.1
29
2.20.1
213
30
214
31
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
Use the new generic support for NT_GNU_PROPERTY_TYPE_0.
3
The AArch64 view of CLIDR_EL1 extends the ICB field to include also bit
4
32, as well as adding a Ttype<n> field when FEAT_MTE is implemented.
5
Extend the clidr field to be able to hold this context.
4
6
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
6
Message-id: 20201016184207.786698-12-richard.henderson@linaro.org
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
11
Message-id: 20210108185154.8108-3-leif@nuviainc.com
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
13
---
10
linux-user/elfload.c | 48 ++++++++++++++++++++++++++++++++++++++++++--
14
target/arm/cpu.h | 2 +-
11
1 file changed, 46 insertions(+), 2 deletions(-)
15
1 file changed, 1 insertion(+), 1 deletion(-)
12
16
13
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
14
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
15
--- a/linux-user/elfload.c
19
--- a/target/arm/cpu.h
16
+++ b/linux-user/elfload.c
20
+++ b/target/arm/cpu.h
17
@@ -XXX,XX +XXX,XX @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
18
22
uint32_t id_afr0;
19
#include "elf.h"
23
uint64_t id_aa64afr0;
20
24
uint64_t id_aa64afr1;
21
+/* We must delay the following stanzas until after "elf.h". */
25
- uint32_t clidr;
22
+#if defined(TARGET_AARCH64)
26
+ uint64_t clidr;
23
+
27
uint64_t mp_affinity; /* MP ID without feature bits */
24
+static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
28
/* The elements of this array are the CCSIDR values for each cache,
25
+ const uint32_t *data,
29
* in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
26
+ struct image_info *info,
27
+ Error **errp)
28
+{
29
+ if (pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
30
+ if (pr_datasz != sizeof(uint32_t)) {
31
+ error_setg(errp, "Ill-formed GNU_PROPERTY_AARCH64_FEATURE_1_AND");
32
+ return false;
33
+ }
34
+ /* We will extract GNU_PROPERTY_AARCH64_FEATURE_1_BTI later. */
35
+ info->note_flags = *data;
36
+ }
37
+ return true;
38
+}
39
+#define ARCH_USE_GNU_PROPERTY 1
40
+
41
+#else
42
+
43
static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
44
const uint32_t *data,
45
struct image_info *info,
46
@@ -XXX,XX +XXX,XX @@ static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
47
}
48
#define ARCH_USE_GNU_PROPERTY 0
49
50
+#endif
51
+
52
struct exec
53
{
54
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
55
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
56
struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
57
struct elf_phdr *phdr;
58
abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
59
- int i, retval;
60
+ int i, retval, prot_exec;
61
Error *err = NULL;
62
63
/* First of all, some simple consistency checks */
64
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
65
info->brk = 0;
66
info->elf_flags = ehdr->e_flags;
67
68
+ prot_exec = PROT_EXEC;
69
+#ifdef TARGET_AARCH64
70
+ /*
71
+ * If the BTI feature is present, this indicates that the executable
72
+ * pages of the startup binary should be mapped with PROT_BTI, so that
73
+ * branch targets are enforced.
74
+ *
75
+ * The startup binary is either the interpreter or the static executable.
76
+ * The interpreter is responsible for all pages of a dynamic executable.
77
+ *
78
+ * Elf notes are backward compatible to older cpus.
79
+ * Do not enable BTI unless it is supported.
80
+ */
81
+ if ((info->note_flags & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
82
+ && (pinterp_name == NULL || *pinterp_name == 0)
83
+ && cpu_isar_feature(aa64_bti, ARM_CPU(thread_cpu))) {
84
+ prot_exec |= TARGET_PROT_BTI;
85
+ }
86
+#endif
87
+
88
for (i = 0; i < ehdr->e_phnum; i++) {
89
struct elf_phdr *eppnt = phdr + i;
90
if (eppnt->p_type == PT_LOAD) {
91
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
92
elf_prot |= PROT_WRITE;
93
}
94
if (eppnt->p_flags & PF_X) {
95
- elf_prot |= PROT_EXEC;
96
+ elf_prot |= prot_exec;
97
}
98
99
vaddr = load_bias + eppnt->p_vaddr;
100
--
30
--
101
2.20.1
31
2.20.1
102
32
103
33
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
This is slightly clearer than just using strerror, though
3
When FEAT_MTE is implemented, the AArch64 view of CTR_EL0 adds the
4
the different forms produced by error_setg_file_open and
4
TminLine field in bits [37:32].
5
error_setg_errno isn't entirely convenient.
5
Extend the ctr field to be able to hold this context.
6
6
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Reviewed-by: Hao Wu <wuhaotsh@google.com>
9
Message-id: 20201016184207.786698-10-richard.henderson@linaro.org
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
11
Message-id: 20210108185154.8108-4-leif@nuviainc.com
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
13
---
12
linux-user/elfload.c | 15 ++++++++-------
14
target/arm/cpu.h | 2 +-
13
1 file changed, 8 insertions(+), 7 deletions(-)
15
1 file changed, 1 insertion(+), 1 deletion(-)
14
16
15
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
16
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
17
--- a/linux-user/elfload.c
19
--- a/target/arm/cpu.h
18
+++ b/linux-user/elfload.c
20
+++ b/target/arm/cpu.h
19
@@ -XXX,XX +XXX,XX @@ static void load_elf_interp(const char *filename, struct image_info *info,
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
20
char bprm_buf[BPRM_BUF_SIZE])
22
uint64_t midr;
21
{
23
uint32_t revidr;
22
int fd, retval;
24
uint32_t reset_fpsid;
23
+ Error *err = NULL;
25
- uint32_t ctr;
24
26
+ uint64_t ctr;
25
fd = open(path(filename), O_RDONLY);
27
uint32_t reset_sctlr;
26
if (fd < 0) {
28
uint64_t pmceid0;
27
- goto exit_perror;
29
uint64_t pmceid1;
28
+ error_setg_file_open(&err, errno, filename);
29
+ error_report_err(err);
30
+ exit(-1);
31
}
32
33
retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
34
if (retval < 0) {
35
- goto exit_perror;
36
+ error_setg_errno(&err, errno, "Error reading file header");
37
+ error_reportf_err(err, "%s: ", filename);
38
+ exit(-1);
39
}
40
+
41
if (retval < BPRM_BUF_SIZE) {
42
memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
43
}
44
45
load_elf_image(filename, fd, info, NULL, bprm_buf);
46
- return;
47
-
48
- exit_perror:
49
- fprintf(stderr, "%s: %s\n", filename, strerror(errno));
50
- exit(-1);
51
}
52
53
static int symfind(const void *s0, const void *s1)
54
--
30
--
55
2.20.1
31
2.20.1
56
32
57
33
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
Transform the prot bit to a qemu internal page bit, and save
3
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
4
it in the page tables.
4
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
5
5
Message-id: 20210108185154.8108-5-leif@nuviainc.com
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201016184207.786698-3-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
7
---
11
include/exec/cpu-all.h | 2 ++
8
target/arm/cpu.h | 31 +++++++++++++++++++++++++++++++
12
linux-user/syscall_defs.h | 4 ++++
9
1 file changed, 31 insertions(+)
13
target/arm/cpu.h | 5 +++++
14
linux-user/mmap.c | 16 ++++++++++++++++
15
target/arm/translate-a64.c | 6 +++---
16
5 files changed, 30 insertions(+), 3 deletions(-)
17
10
18
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/include/exec/cpu-all.h
21
+++ b/include/exec/cpu-all.h
22
@@ -XXX,XX +XXX,XX @@ extern intptr_t qemu_host_page_mask;
23
/* FIXME: Code that sets/uses this is broken and needs to go away. */
24
#define PAGE_RESERVED 0x0020
25
#endif
26
+/* Target-specific bits that will be used via page_get_flags(). */
27
+#define PAGE_TARGET_1 0x0080
28
29
#if defined(CONFIG_USER_ONLY)
30
void page_dump(FILE *f);
31
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/linux-user/syscall_defs.h
34
+++ b/linux-user/syscall_defs.h
35
@@ -XXX,XX +XXX,XX @@ struct target_winsize {
36
#define TARGET_PROT_SEM 0x08
37
#endif
38
39
+#ifdef TARGET_AARCH64
40
+#define TARGET_PROT_BTI 0x10
41
+#endif
42
+
43
/* Common */
44
#define TARGET_MAP_SHARED    0x01        /* Share changes */
45
#define TARGET_MAP_PRIVATE    0x02        /* Changes are private */
46
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
11
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
47
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
48
--- a/target/arm/cpu.h
13
--- a/target/arm/cpu.h
49
+++ b/target/arm/cpu.h
14
+++ b/target/arm/cpu.h
50
@@ -XXX,XX +XXX,XX @@ static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x)
15
@@ -XXX,XX +XXX,XX @@ FIELD(V7M_FPCCR, ASPEN, 31, 1)
51
#define arm_tlb_bti_gp(x) (typecheck_memtxattrs(x)->target_tlb_bit0)
16
/*
52
#define arm_tlb_mte_tagged(x) (typecheck_memtxattrs(x)->target_tlb_bit1)
17
* System register ID fields.
53
18
*/
54
+/*
19
+FIELD(CLIDR_EL1, CTYPE1, 0, 3)
55
+ * AArch64 usage of the PAGE_TARGET_* bits for linux-user.
20
+FIELD(CLIDR_EL1, CTYPE2, 3, 3)
56
+ */
21
+FIELD(CLIDR_EL1, CTYPE3, 6, 3)
57
+#define PAGE_BTI PAGE_TARGET_1
22
+FIELD(CLIDR_EL1, CTYPE4, 9, 3)
23
+FIELD(CLIDR_EL1, CTYPE5, 12, 3)
24
+FIELD(CLIDR_EL1, CTYPE6, 15, 3)
25
+FIELD(CLIDR_EL1, CTYPE7, 18, 3)
26
+FIELD(CLIDR_EL1, LOUIS, 21, 3)
27
+FIELD(CLIDR_EL1, LOC, 24, 3)
28
+FIELD(CLIDR_EL1, LOUU, 27, 3)
29
+FIELD(CLIDR_EL1, ICB, 30, 3)
58
+
30
+
59
/*
31
+/* When FEAT_CCIDX is implemented */
60
* Naming convention for isar_feature functions:
32
+FIELD(CCSIDR_EL1, CCIDX_LINESIZE, 0, 3)
61
* Functions which test 32-bit ID registers should have _aa32_ in
33
+FIELD(CCSIDR_EL1, CCIDX_ASSOCIATIVITY, 3, 21)
62
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
34
+FIELD(CCSIDR_EL1, CCIDX_NUMSETS, 32, 24)
63
index XXXXXXX..XXXXXXX 100644
64
--- a/linux-user/mmap.c
65
+++ b/linux-user/mmap.c
66
@@ -XXX,XX +XXX,XX @@ static int validate_prot_to_pageflags(int *host_prot, int prot)
67
*host_prot = (prot & (PROT_READ | PROT_WRITE))
68
| (prot & PROT_EXEC ? PROT_READ : 0);
69
70
+#ifdef TARGET_AARCH64
71
+ /*
72
+ * The PROT_BTI bit is only accepted if the cpu supports the feature.
73
+ * Since this is the unusual case, don't bother checking unless
74
+ * the bit has been requested. If set and valid, record the bit
75
+ * within QEMU's page_flags.
76
+ */
77
+ if (prot & TARGET_PROT_BTI) {
78
+ ARMCPU *cpu = ARM_CPU(thread_cpu);
79
+ if (cpu_isar_feature(aa64_bti, cpu)) {
80
+ valid |= TARGET_PROT_BTI;
81
+ page_flags |= PAGE_BTI;
82
+ }
83
+ }
84
+#endif
85
+
35
+
86
return prot & ~valid ? 0 : page_flags;
36
+/* When FEAT_CCIDX is not implemented */
87
}
37
+FIELD(CCSIDR_EL1, LINESIZE, 0, 3)
88
38
+FIELD(CCSIDR_EL1, ASSOCIATIVITY, 3, 10)
89
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
39
+FIELD(CCSIDR_EL1, NUMSETS, 13, 15)
90
index XXXXXXX..XXXXXXX 100644
40
+
91
--- a/target/arm/translate-a64.c
41
+FIELD(CTR_EL0, IMINLINE, 0, 4)
92
+++ b/target/arm/translate-a64.c
42
+FIELD(CTR_EL0, L1IP, 14, 2)
93
@@ -XXX,XX +XXX,XX @@ static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
43
+FIELD(CTR_EL0, DMINLINE, 16, 4)
94
*/
44
+FIELD(CTR_EL0, ERG, 20, 4)
95
static bool is_guarded_page(CPUARMState *env, DisasContext *s)
45
+FIELD(CTR_EL0, CWG, 24, 4)
96
{
46
+FIELD(CTR_EL0, IDC, 28, 1)
97
-#ifdef CONFIG_USER_ONLY
47
+FIELD(CTR_EL0, DIC, 29, 1)
98
- return false; /* FIXME */
48
+FIELD(CTR_EL0, TMINLINE, 32, 6)
99
-#else
49
+
100
uint64_t addr = s->base.pc_first;
50
FIELD(MIDR_EL1, REVISION, 0, 4)
101
+#ifdef CONFIG_USER_ONLY
51
FIELD(MIDR_EL1, PARTNUM, 4, 12)
102
+ return page_get_flags(addr) & PAGE_BTI;
52
FIELD(MIDR_EL1, ARCHITECTURE, 16, 4)
103
+#else
104
int mmu_idx = arm_to_core_mmu_idx(s->mmu_idx);
105
unsigned int index = tlb_index(env, mmu_idx, addr);
106
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
107
--
53
--
108
2.20.1
54
2.20.1
109
55
110
56
diff view generated by jsdifflib
1
If the M-profile low-overhead-branch extension is implemented, FPSCR
1
From: Leif Lindholm <leif@nuviainc.com>
2
bits [18:16] are a new field LTPSIZE. If MVE is not implemented
3
(currently always true for us) then this field always reads as 4 and
4
ignores writes.
5
2
6
These bits used to be the vector-length field for the old
3
Add entries present in ARM DDI 0487F.c (August 2020).
7
short-vector extension, so we need to take care that they are not
8
misinterpreted as setting vec_len. We do this with a rearrangement
9
of the vfp_set_fpscr() code that deals with vec_len, vec_stride
10
and also the QC bit; this obviates the need for the M-profile
11
only masking step that we used to have at the start of the function.
12
4
13
We provide a new field in CPUState for LTPSIZE, even though this
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
14
will always be 4, in preparation for MVE, so we don't have to
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
15
come back later and split it out of the vfp.xregs[FPSCR] value.
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
16
(This state struct field will be saved and restored as part of
8
Message-id: 20210108185154.8108-6-leif@nuviainc.com
17
the FPSCR value via the vmstate_fpscr in machine.c.)
18
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
21
Message-id: 20201019151301.2046-11-peter.maydell@linaro.org
22
---
10
---
23
target/arm/cpu.h | 1 +
11
target/arm/cpu.h | 15 +++++++++++++++
24
target/arm/cpu.c | 9 +++++++++
12
1 file changed, 15 insertions(+)
25
target/arm/vfp_helper.c | 6 ++++++
26
3 files changed, 16 insertions(+)
27
13
28
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
29
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
30
--- a/target/arm/cpu.h
16
--- a/target/arm/cpu.h
31
+++ b/target/arm/cpu.h
17
+++ b/target/arm/cpu.h
32
@@ -XXX,XX +XXX,XX @@ typedef struct CPUARMState {
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64ISAR1, GPI, 28, 4)
33
uint32_t fpdscr[M_REG_NUM_BANKS];
19
FIELD(ID_AA64ISAR1, FRINTTS, 32, 4)
34
uint32_t cpacr[M_REG_NUM_BANKS];
20
FIELD(ID_AA64ISAR1, SB, 36, 4)
35
uint32_t nsacr;
21
FIELD(ID_AA64ISAR1, SPECRES, 40, 4)
36
+ int ltpsize;
22
+FIELD(ID_AA64ISAR1, BF16, 44, 4)
37
} v7m;
23
+FIELD(ID_AA64ISAR1, DGH, 48, 4)
38
24
+FIELD(ID_AA64ISAR1, I8MM, 52, 4)
39
/* Information associated with an exception about to be taken:
25
40
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
26
FIELD(ID_AA64PFR0, EL0, 0, 4)
41
index XXXXXXX..XXXXXXX 100644
27
FIELD(ID_AA64PFR0, EL1, 4, 4)
42
--- a/target/arm/cpu.c
28
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64PFR0, ADVSIMD, 20, 4)
43
+++ b/target/arm/cpu.c
29
FIELD(ID_AA64PFR0, GIC, 24, 4)
44
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset(DeviceState *dev)
30
FIELD(ID_AA64PFR0, RAS, 28, 4)
45
uint8_t *rom;
31
FIELD(ID_AA64PFR0, SVE, 32, 4)
46
uint32_t vecbase;
32
+FIELD(ID_AA64PFR0, SEL2, 36, 4)
47
33
+FIELD(ID_AA64PFR0, MPAM, 40, 4)
48
+ if (cpu_isar_feature(aa32_lob, cpu)) {
34
+FIELD(ID_AA64PFR0, AMU, 44, 4)
49
+ /*
35
+FIELD(ID_AA64PFR0, DIT, 48, 4)
50
+ * LTPSIZE is constant 4 if MVE not implemented, and resets
36
+FIELD(ID_AA64PFR0, CSV2, 56, 4)
51
+ * to an UNKNOWN value if MVE is implemented. We choose to
37
+FIELD(ID_AA64PFR0, CSV3, 60, 4)
52
+ * always reset to 4.
38
53
+ */
39
FIELD(ID_AA64PFR1, BT, 0, 4)
54
+ env->v7m.ltpsize = 4;
40
FIELD(ID_AA64PFR1, SSBS, 4, 4)
55
+ }
41
FIELD(ID_AA64PFR1, MTE, 8, 4)
56
+
42
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
57
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
43
+FIELD(ID_AA64PFR1, MPAM_FRAC, 16, 4)
58
env->v7m.secure = true;
44
59
} else {
45
FIELD(ID_AA64MMFR0, PARANGE, 0, 4)
60
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
46
FIELD(ID_AA64MMFR0, ASIDBITS, 4, 4)
61
index XXXXXXX..XXXXXXX 100644
47
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64MMFR0, TGRAN16_2, 32, 4)
62
--- a/target/arm/vfp_helper.c
48
FIELD(ID_AA64MMFR0, TGRAN64_2, 36, 4)
63
+++ b/target/arm/vfp_helper.c
49
FIELD(ID_AA64MMFR0, TGRAN4_2, 40, 4)
64
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
50
FIELD(ID_AA64MMFR0, EXS, 44, 4)
65
| (env->vfp.vec_len << 16)
51
+FIELD(ID_AA64MMFR0, FGT, 56, 4)
66
| (env->vfp.vec_stride << 20);
52
+FIELD(ID_AA64MMFR0, ECV, 60, 4)
67
53
68
+ /*
54
FIELD(ID_AA64MMFR1, HAFDBS, 0, 4)
69
+ * M-profile LTPSIZE overlaps A-profile Stride; whichever of the
55
FIELD(ID_AA64MMFR1, VMIDBITS, 4, 4)
70
+ * two is not applicable to this CPU will always be zero.
56
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64MMFR1, LO, 16, 4)
71
+ */
57
FIELD(ID_AA64MMFR1, PAN, 20, 4)
72
+ fpscr |= env->v7m.ltpsize << 16;
58
FIELD(ID_AA64MMFR1, SPECSEI, 24, 4)
73
+
59
FIELD(ID_AA64MMFR1, XNX, 28, 4)
74
fpscr |= vfp_get_fpscr_from_host(env);
60
+FIELD(ID_AA64MMFR1, TWED, 32, 4)
75
61
+FIELD(ID_AA64MMFR1, ETS, 36, 4)
76
i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
62
63
FIELD(ID_AA64MMFR2, CNP, 0, 4)
64
FIELD(ID_AA64MMFR2, UAO, 4, 4)
65
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64DFR0, CTX_CMPS, 28, 4)
66
FIELD(ID_AA64DFR0, PMSVER, 32, 4)
67
FIELD(ID_AA64DFR0, DOUBLELOCK, 36, 4)
68
FIELD(ID_AA64DFR0, TRACEFILT, 40, 4)
69
+FIELD(ID_AA64DFR0, MTPMU, 48, 4)
70
71
FIELD(ID_DFR0, COPDBG, 0, 4)
72
FIELD(ID_DFR0, COPSDBG, 4, 4)
77
--
73
--
78
2.20.1
74
2.20.1
79
75
80
76
diff view generated by jsdifflib
1
From v8.1M, disabled-coprocessor handling changes slightly:
1
From: Leif Lindholm <leif@nuviainc.com>
2
* coprocessors 8, 9, 14 and 15 are also governed by the
3
cp10 enable bit, like cp11
4
* an extra range of instruction patterns is considered
5
to be inside the coprocessor space
6
2
7
We previously marked these up with TODO comments; implement the
3
Add entries present in ARM DDI 0487F.c (August 2020).
8
correct behaviour.
9
4
10
Unfortunately there is no ID register field which indicates this
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
11
behaviour. We could in theory test an unrelated ID register which
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
indicates guaranteed-to-be-in-v8.1M behaviour like ID_ISAR0.CmpBranch
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
13
>= 3 (low-overhead-loops), but it seems better to simply define a new
8
Message-id: 20210108185154.8108-7-leif@nuviainc.com
14
ARM_FEATURE_V8_1M feature flag and use it for this and other
15
new-in-v8.1M behaviour that isn't identifiable from the ID registers.
16
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
19
Message-id: 20201019151301.2046-3-peter.maydell@linaro.org
20
---
10
---
21
target/arm/cpu.h | 1 +
11
target/arm/cpu.h | 28 ++++++++++++++++++++++++++++
22
target/arm/m-nocp.decode | 10 ++++++----
12
1 file changed, 28 insertions(+)
23
target/arm/translate-vfp.c.inc | 17 +++++++++++++++--
24
3 files changed, 22 insertions(+), 6 deletions(-)
25
13
26
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
27
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
28
--- a/target/arm/cpu.h
16
--- a/target/arm/cpu.h
29
+++ b/target/arm/cpu.h
17
+++ b/target/arm/cpu.h
30
@@ -XXX,XX +XXX,XX @@ enum arm_features {
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_ISAR6, DP, 4, 4)
31
ARM_FEATURE_VBAR, /* has cp15 VBAR */
19
FIELD(ID_ISAR6, FHM, 8, 4)
32
ARM_FEATURE_M_SECURITY, /* M profile Security Extension */
20
FIELD(ID_ISAR6, SB, 12, 4)
33
ARM_FEATURE_M_MAIN, /* M profile Main Extension */
21
FIELD(ID_ISAR6, SPECRES, 16, 4)
34
+ ARM_FEATURE_V8_1M, /* M profile extras only in v8.1M and later */
22
+FIELD(ID_ISAR6, BF16, 20, 4)
35
};
23
+FIELD(ID_ISAR6, I8MM, 24, 4)
36
24
37
static inline int arm_feature(CPUARMState *env, int feature)
25
FIELD(ID_MMFR0, VMSA, 0, 4)
38
diff --git a/target/arm/m-nocp.decode b/target/arm/m-nocp.decode
26
FIELD(ID_MMFR0, PMSA, 4, 4)
39
index XXXXXXX..XXXXXXX 100644
27
@@ -XXX,XX +XXX,XX @@ FIELD(ID_MMFR0, AUXREG, 20, 4)
40
--- a/target/arm/m-nocp.decode
28
FIELD(ID_MMFR0, FCSE, 24, 4)
41
+++ b/target/arm/m-nocp.decode
29
FIELD(ID_MMFR0, INNERSHR, 28, 4)
42
@@ -XXX,XX +XXX,XX @@
30
43
# If the coprocessor is not present or disabled then we will generate
31
+FIELD(ID_MMFR1, L1HVDVA, 0, 4)
44
# the NOCP exception; otherwise we let the insn through to the main decode.
32
+FIELD(ID_MMFR1, L1UNIVA, 4, 4)
45
33
+FIELD(ID_MMFR1, L1HVDSW, 8, 4)
46
+&nocp cp
34
+FIELD(ID_MMFR1, L1UNISW, 12, 4)
35
+FIELD(ID_MMFR1, L1HVD, 16, 4)
36
+FIELD(ID_MMFR1, L1UNI, 20, 4)
37
+FIELD(ID_MMFR1, L1TSTCLN, 24, 4)
38
+FIELD(ID_MMFR1, BPRED, 28, 4)
47
+
39
+
48
{
40
+FIELD(ID_MMFR2, L1HVDFG, 0, 4)
49
# Special cases which do not take an early NOCP: VLLDM and VLSTM
41
+FIELD(ID_MMFR2, L1HVDBG, 4, 4)
50
VLLDM_VLSTM 1110 1100 001 l:1 rn:4 0000 1010 0000 0000
42
+FIELD(ID_MMFR2, L1HVDRNG, 8, 4)
51
# TODO: VSCCLRM (new in v8.1M) is similar:
43
+FIELD(ID_MMFR2, HVDTLB, 12, 4)
52
#VSCCLRM 1110 1100 1-01 1111 ---- 1011 ---- ---0
44
+FIELD(ID_MMFR2, UNITLB, 16, 4)
53
45
+FIELD(ID_MMFR2, MEMBARR, 20, 4)
54
- NOCP 111- 1110 ---- ---- ---- cp:4 ---- ----
46
+FIELD(ID_MMFR2, WFISTALL, 24, 4)
55
- NOCP 111- 110- ---- ---- ---- cp:4 ---- ----
47
+FIELD(ID_MMFR2, HWACCFLG, 28, 4)
56
- # TODO: From v8.1M onwards we will also want this range to NOCP
57
- #NOCP_8_1 111- 1111 ---- ---- ---- ---- ---- ---- cp=10
58
+ NOCP 111- 1110 ---- ---- ---- cp:4 ---- ---- &nocp
59
+ NOCP 111- 110- ---- ---- ---- cp:4 ---- ---- &nocp
60
+ # From v8.1M onwards this range will also NOCP:
61
+ NOCP_8_1 111- 1111 ---- ---- ---- ---- ---- ---- &nocp cp=10
62
}
63
diff --git a/target/arm/translate-vfp.c.inc b/target/arm/translate-vfp.c.inc
64
index XXXXXXX..XXXXXXX 100644
65
--- a/target/arm/translate-vfp.c.inc
66
+++ b/target/arm/translate-vfp.c.inc
67
@@ -XXX,XX +XXX,XX @@ static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
68
return true;
69
}
70
71
-static bool trans_NOCP(DisasContext *s, arg_NOCP *a)
72
+static bool trans_NOCP(DisasContext *s, arg_nocp *a)
73
{
74
/*
75
* Handle M-profile early check for disabled coprocessor:
76
@@ -XXX,XX +XXX,XX @@ static bool trans_NOCP(DisasContext *s, arg_NOCP *a)
77
if (a->cp == 11) {
78
a->cp = 10;
79
}
80
- /* TODO: in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
81
+ if (arm_dc_feature(s, ARM_FEATURE_V8_1M) &&
82
+ (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) {
83
+ /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
84
+ a->cp = 10;
85
+ }
86
87
if (a->cp != 10) {
88
gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
89
@@ -XXX,XX +XXX,XX @@ static bool trans_NOCP(DisasContext *s, arg_NOCP *a)
90
return false;
91
}
92
93
+static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a)
94
+{
95
+ /* This range needs a coprocessor check for v8.1M and later only */
96
+ if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
97
+ return false;
98
+ }
99
+ return trans_NOCP(s, a);
100
+}
101
+
48
+
102
static bool trans_VINS(DisasContext *s, arg_VINS *a)
49
FIELD(ID_MMFR3, CMAINTVA, 0, 4)
103
{
50
FIELD(ID_MMFR3, CMAINTSW, 4, 4)
104
TCGv_i32 rd, rm;
51
FIELD(ID_MMFR3, BPMAINT, 8, 4)
52
@@ -XXX,XX +XXX,XX @@ FIELD(ID_MMFR4, LSM, 20, 4)
53
FIELD(ID_MMFR4, CCIDX, 24, 4)
54
FIELD(ID_MMFR4, EVT, 28, 4)
55
56
+FIELD(ID_MMFR5, ETS, 0, 4)
57
+
58
FIELD(ID_PFR0, STATE0, 0, 4)
59
FIELD(ID_PFR0, STATE1, 4, 4)
60
FIELD(ID_PFR0, STATE2, 8, 4)
61
@@ -XXX,XX +XXX,XX @@ FIELD(ID_PFR1, SEC_FRAC, 20, 4)
62
FIELD(ID_PFR1, VIRT_FRAC, 24, 4)
63
FIELD(ID_PFR1, GIC, 28, 4)
64
65
+FIELD(ID_PFR2, CSV3, 0, 4)
66
+FIELD(ID_PFR2, SSBS, 4, 4)
67
+FIELD(ID_PFR2, RAS_FRAC, 8, 4)
68
+
69
FIELD(ID_AA64ISAR0, AES, 4, 4)
70
FIELD(ID_AA64ISAR0, SHA1, 8, 4)
71
FIELD(ID_AA64ISAR0, SHA2, 12, 4)
72
@@ -XXX,XX +XXX,XX @@ FIELD(ID_DFR0, MPROFDBG, 20, 4)
73
FIELD(ID_DFR0, PERFMON, 24, 4)
74
FIELD(ID_DFR0, TRACEFILT, 28, 4)
75
76
+FIELD(ID_DFR1, MTPMU, 0, 4)
77
+
78
FIELD(DBGDIDR, SE_IMP, 12, 1)
79
FIELD(DBGDIDR, NSUHD_IMP, 14, 1)
80
FIELD(DBGDIDR, VERSION, 16, 4)
105
--
81
--
106
2.20.1
82
2.20.1
107
83
108
84
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
2
2
3
The time to transmit a char is expressed in nanoseconds, not in ticks.
3
QEMU documentation can't be opened if QEMU is run from build tree
4
because executables are placed in the top of build tree after conversion
5
to meson.
4
6
5
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
6
Message-id: 20201014213601.205222-1-f4bug@amsat.org
8
Reported-by: Peter Maydell <peter.maydell@linaro.org>
9
Message-id: 20210108213815.64678-1-r.bolshakov@yadro.com
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
12
---
10
hw/arm/strongarm.c | 2 +-
13
ui/cocoa.m | 2 +-
11
1 file changed, 1 insertion(+), 1 deletion(-)
14
1 file changed, 1 insertion(+), 1 deletion(-)
12
15
13
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
16
diff --git a/ui/cocoa.m b/ui/cocoa.m
14
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/arm/strongarm.c
18
--- a/ui/cocoa.m
16
+++ b/hw/arm/strongarm.c
19
+++ b/ui/cocoa.m
17
@@ -XXX,XX +XXX,XX @@ struct StrongARMUARTState {
20
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
18
uint8_t rx_start;
21
- (void) openDocumentation: (NSString *) filename
19
uint8_t rx_len;
22
{
20
23
/* Where to look for local files */
21
- uint64_t char_transmit_time; /* time to transmit a char in ticks*/
24
- NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"../docs/"};
22
+ uint64_t char_transmit_time; /* time to transmit a char in nanoseconds */
25
+ NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
23
bool wait_break_end;
26
NSString *full_file_path;
24
QEMUTimer *rx_timeout_timer;
27
25
QEMUTimer *tx_timer;
28
/* iterate thru the possible paths until the file is found */
26
--
29
--
27
2.20.1
30
2.20.1
28
31
29
32
diff view generated by jsdifflib
1
M-profile CPUs with half-precision floating point support should
1
In commit 1982e1602d15 we added a new qemu-storage-daemon(1) manpage.
2
be able to write to FPSCR.FZ16, but an M-profile specific masking
2
At the moment new manpages have to be listed both in the conf.py for
3
of the value at the top of vfp_set_fpscr() currently prevents that.
3
Sphinx and also in docs/meson.build for Meson. We forgot the second
4
This is not yet an active bug because we have no M-profile
4
of those -- correct the omission.
5
FP16 CPUs, but needs to be fixed before we can add any.
6
7
The bits that the masking is effectively preventing from being
8
set are the A-profile only short-vector Len and Stride fields,
9
plus the Neon QC bit. Rearrange the order of the function so
10
that those fields are handled earlier and only under a suitable
11
guard; this allows us to drop the M-profile specific masking,
12
making FZ16 writeable.
13
14
This change also makes the QC bit correctly RAZ/WI for older
15
no-Neon A-profile cores.
16
17
This refactoring also paves the way for the low-overhead-branch
18
LTPSIZE field, which uses some of the bits that are used for
19
A-profile Stride and Len.
20
5
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
23
Message-id: 20201019151301.2046-10-peter.maydell@linaro.org
8
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
9
Message-id: 20210108161416.21129-2-peter.maydell@linaro.org
24
---
10
---
25
target/arm/vfp_helper.c | 47 ++++++++++++++++++++++++-----------------
11
docs/meson.build | 1 +
26
1 file changed, 28 insertions(+), 19 deletions(-)
12
1 file changed, 1 insertion(+)
27
13
28
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
14
diff --git a/docs/meson.build b/docs/meson.build
29
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
30
--- a/target/arm/vfp_helper.c
16
--- a/docs/meson.build
31
+++ b/target/arm/vfp_helper.c
17
+++ b/docs/meson.build
32
@@ -XXX,XX +XXX,XX @@ void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
18
@@ -XXX,XX +XXX,XX @@ if build_docs
33
val &= ~FPCR_FZ16;
19
'qemu-img.1': (have_tools ? 'man1' : ''),
34
}
20
'qemu-nbd.8': (have_tools ? 'man8' : ''),
35
21
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
36
- if (arm_feature(env, ARM_FEATURE_M)) {
22
+ 'qemu-storage-daemon.1': (have_tools ? 'man1' : ''),
37
+ vfp_set_fpscr_to_host(env, val);
23
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
38
+
24
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
39
+ if (!arm_feature(env, ARM_FEATURE_M)) {
25
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
40
/*
41
- * M profile FPSCR is RES0 for the QC, STRIDE, FZ16, LEN bits
42
- * and also for the trapped-exception-handling bits IxE.
43
+ * Short-vector length and stride; on M-profile these bits
44
+ * are used for different purposes.
45
+ * We can't make this conditional be "if MVFR0.FPShVec != 0",
46
+ * because in v7A no-short-vector-support cores still had to
47
+ * allow Stride/Len to be written with the only effect that
48
+ * some insns are required to UNDEF if the guest sets them.
49
+ *
50
+ * TODO: if M-profile MVE implemented, set LTPSIZE.
51
*/
52
- val &= 0xf7c0009f;
53
+ env->vfp.vec_len = extract32(val, 16, 3);
54
+ env->vfp.vec_stride = extract32(val, 20, 2);
55
}
56
57
- vfp_set_fpscr_to_host(env, val);
58
+ if (arm_feature(env, ARM_FEATURE_NEON)) {
59
+ /*
60
+ * The bit we set within fpscr_q is arbitrary; the register as a
61
+ * whole being zero/non-zero is what counts.
62
+ * TODO: M-profile MVE also has a QC bit.
63
+ */
64
+ env->vfp.qc[0] = val & FPCR_QC;
65
+ env->vfp.qc[1] = 0;
66
+ env->vfp.qc[2] = 0;
67
+ env->vfp.qc[3] = 0;
68
+ }
69
70
/*
71
* We don't implement trapped exception handling, so the
72
* trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
73
*
74
- * If we exclude the exception flags, IOC|DZC|OFC|UFC|IXC|IDC
75
- * (which are stored in fp_status), and the other RES0 bits
76
- * in between, then we clear all of the low 16 bits.
77
+ * The exception flags IOC|DZC|OFC|UFC|IXC|IDC are stored in
78
+ * fp_status; QC, Len and Stride are stored separately earlier.
79
+ * Clear out all of those and the RES0 bits: only NZCV, AHP, DN,
80
+ * FZ, RMode and FZ16 are kept in vfp.xregs[FPSCR].
81
*/
82
env->vfp.xregs[ARM_VFP_FPSCR] = val & 0xf7c80000;
83
- env->vfp.vec_len = (val >> 16) & 7;
84
- env->vfp.vec_stride = (val >> 20) & 3;
85
-
86
- /*
87
- * The bit we set within fpscr_q is arbitrary; the register as a
88
- * whole being zero/non-zero is what counts.
89
- */
90
- env->vfp.qc[0] = val & FPCR_QC;
91
- env->vfp.qc[1] = 0;
92
- env->vfp.qc[2] = 0;
93
- env->vfp.qc[3] = 0;
94
}
95
96
void vfp_set_fpscr(CPUARMState *env, uint32_t val)
97
--
26
--
98
2.20.1
27
2.20.1
99
28
100
29
diff view generated by jsdifflib
1
The SMLAD instruction is supposed to:
1
When we first converted our documentation to Sphinx, we split it into
2
* signed multiply Rn[15:0] * Rm[15:0]
2
multiple manuals (system, interop, tools, etc), which are all built
3
* signed multiply Rn[31:16] * Rm[31:16]
3
separately. The primary driver for this was wanting to be able to
4
* perform a signed addition of the products and Ra
4
avoid shipping the 'devel' manual to end-users. However, this is
5
* set Rd to the low 32 bits of the theoretical
5
working against the grain of the way Sphinx wants to be used and
6
infinite-precision result
6
causes some annoyances:
7
* set the Q flag if the sign-extension of Rd
7
* Cross-references between documents become much harder or
8
would differ from the infinite-precision result
8
possibly impossible
9
(ie on overflow)
9
* There is no single index to the whole documentation
10
10
* Within one manual there's no links or table-of-contents info
11
Our current implementation doesn't quite do this, though: it performs
11
that lets you easily navigate to the others
12
an addition of the products setting Q on overflow, and then it adds
12
* The devel manual doesn't get published on the QEMU website
13
Ra, again possibly setting Q. This sometimes incorrectly sets Q when
13
(it would be nice to able to refer to it there)
14
the architecturally mandated only-check-for-overflow-once algorithm
14
15
does not. For instance:
15
Merely hiding our developer documentation from end users seems like
16
r1 = 0x80008000; r2 = 0x80008000; r3 = 0xffffffff
16
it's not enough benefit for these costs. Combine all the
17
smlad r0, r1, r2, r3
17
documentation into a single manual (the same way that the readthedocs
18
This is (-32768 * -32768) + (-32768 * -32768) - 1
18
site builds it) and install the whole thing. The previous manual
19
19
divisions remain as the new top level sections in the manual.
20
The products are both 0x4000_0000, so when added together as 32-bit
20
21
signed numbers they overflow (and QEMU sets Q), but because the
21
* The per-manual conf.py files are no longer needed
22
addition of Ra == -1 brings the total back down to 0x7fff_ffff
22
* The man_pages[] specifications previously in each per-manual
23
there is no overflow for the complete operation and setting Q is
23
conf.py move to the top level conf.py
24
incorrect.
24
* docs/meson.build logic is simplified as we now only need to run
25
25
Sphinx once for the HTML and then once for the manpages5B
26
Fix this edge case by resorting to 64-bit arithmetic for the
26
* The old index.html.in that produced the top-level page with
27
case where we need to add three values together.
27
links to each manual is no longer needed
28
29
Unfortunately this means that we now have to build the HTML
30
documentation into docs/manual in the build tree rather than directly
31
into docs/; otherwise it is too awkward to ensure we install only the
32
built manual and not also the dependency info, stamp file, etc. The
33
manual still ends up in the same place in the final installed
34
directory, but anybody who was consulting documentation from within
35
the build tree will have to adjust where they're looking.
28
36
29
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
37
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
30
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
38
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
31
Message-id: 20201009144712.11187-1-peter.maydell@linaro.org
39
Message-id: 20210108161416.21129-3-peter.maydell@linaro.org
32
---
40
---
33
target/arm/translate.c | 58 ++++++++++++++++++++++++++++++++++--------
41
docs/conf.py | 46 ++++++++++++++++++++++++++++++-
34
1 file changed, 48 insertions(+), 10 deletions(-)
42
docs/devel/conf.py | 15 -----------
35
43
docs/index.html.in | 17 ------------
36
diff --git a/target/arm/translate.c b/target/arm/translate.c
44
docs/interop/conf.py | 28 -------------------
45
docs/meson.build | 64 +++++++++++++++++---------------------------
46
docs/specs/conf.py | 16 -----------
47
docs/system/conf.py | 28 -------------------
48
docs/tools/conf.py | 37 -------------------------
49
docs/user/conf.py | 15 -----------
50
9 files changed, 70 insertions(+), 196 deletions(-)
51
delete mode 100644 docs/devel/conf.py
52
delete mode 100644 docs/index.html.in
53
delete mode 100644 docs/interop/conf.py
54
delete mode 100644 docs/specs/conf.py
55
delete mode 100644 docs/system/conf.py
56
delete mode 100644 docs/tools/conf.py
57
delete mode 100644 docs/user/conf.py
58
59
diff --git a/docs/conf.py b/docs/conf.py
37
index XXXXXXX..XXXXXXX 100644
60
index XXXXXXX..XXXXXXX 100644
38
--- a/target/arm/translate.c
61
--- a/docs/conf.py
39
+++ b/target/arm/translate.c
62
+++ b/docs/conf.py
40
@@ -XXX,XX +XXX,XX @@ static bool op_smlad(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub)
63
@@ -XXX,XX +XXX,XX @@ latex_documents = [
41
gen_smul_dual(t1, t2);
64
42
65
# -- Options for manual page output ---------------------------------------
43
if (sub) {
66
# Individual manual/conf.py can override this to create man pages
44
- /* This subtraction cannot overflow. */
67
-man_pages = []
45
+ /*
68
+man_pages = [
46
+ * This subtraction cannot overflow, so we can do a simple
69
+ ('interop/qemu-ga', 'qemu-ga',
47
+ * 32-bit subtraction and then a possible 32-bit saturating
70
+ 'QEMU Guest Agent',
48
+ * addition of Ra.
71
+ ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
49
+ */
72
+ ('interop/qemu-ga-ref', 'qemu-ga-ref',
50
tcg_gen_sub_i32(t1, t1, t2);
73
+ 'QEMU Guest Agent Protocol Reference',
51
+ tcg_temp_free_i32(t2);
74
+ [], 7),
75
+ ('interop/qemu-qmp-ref', 'qemu-qmp-ref',
76
+ 'QEMU QMP Reference Manual',
77
+ [], 7),
78
+ ('interop/qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
79
+ 'QEMU Storage Daemon QMP Reference Manual',
80
+ [], 7),
81
+ ('system/qemu-manpage', 'qemu',
82
+ 'QEMU User Documentation',
83
+ ['Fabrice Bellard'], 1),
84
+ ('system/qemu-block-drivers', 'qemu-block-drivers',
85
+ 'QEMU block drivers reference',
86
+ ['Fabrice Bellard and the QEMU Project developers'], 7),
87
+ ('system/qemu-cpu-models', 'qemu-cpu-models',
88
+ 'QEMU CPU Models',
89
+ ['The QEMU Project developers'], 7),
90
+ ('tools/qemu-img', 'qemu-img',
91
+ 'QEMU disk image utility',
92
+ ['Fabrice Bellard'], 1),
93
+ ('tools/qemu-nbd', 'qemu-nbd',
94
+ 'QEMU Disk Network Block Device Server',
95
+ ['Anthony Liguori <anthony@codemonkey.ws>'], 8),
96
+ ('tools/qemu-pr-helper', 'qemu-pr-helper',
97
+ 'QEMU persistent reservation helper',
98
+ [], 8),
99
+ ('tools/qemu-storage-daemon', 'qemu-storage-daemon',
100
+ 'QEMU storage daemon',
101
+ [], 1),
102
+ ('tools/qemu-trace-stap', 'qemu-trace-stap',
103
+ 'QEMU SystemTap trace tool',
104
+ [], 1),
105
+ ('tools/virtfs-proxy-helper', 'virtfs-proxy-helper',
106
+ 'QEMU 9p virtfs proxy filesystem helper',
107
+ ['M. Mohan Kumar'], 1),
108
+ ('tools/virtiofsd', 'virtiofsd',
109
+ 'QEMU virtio-fs shared file system daemon',
110
+ ['Stefan Hajnoczi <stefanha@redhat.com>',
111
+ 'Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>'], 1),
112
+]
113
114
# -- Options for Texinfo output -------------------------------------------
115
116
diff --git a/docs/devel/conf.py b/docs/devel/conf.py
117
deleted file mode 100644
118
index XXXXXXX..XXXXXXX
119
--- a/docs/devel/conf.py
120
+++ /dev/null
121
@@ -XXX,XX +XXX,XX @@
122
-# -*- coding: utf-8 -*-
123
-#
124
-# QEMU documentation build configuration file for the 'devel' manual.
125
-#
126
-# This includes the top level conf file and then makes any necessary tweaks.
127
-import sys
128
-import os
129
-
130
-qemu_docdir = os.path.abspath("..")
131
-parent_config = os.path.join(qemu_docdir, "conf.py")
132
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
133
-
134
-# This slightly misuses the 'description', but is the best way to get
135
-# the manual title to appear in the sidebar.
136
-html_theme_options['description'] = u'Developer''s Guide'
137
diff --git a/docs/index.html.in b/docs/index.html.in
138
deleted file mode 100644
139
index XXXXXXX..XXXXXXX
140
--- a/docs/index.html.in
141
+++ /dev/null
142
@@ -XXX,XX +XXX,XX @@
143
-<!DOCTYPE html>
144
-<html lang="en">
145
- <head>
146
- <meta charset="UTF-8">
147
- <title>QEMU @VERSION@ Documentation</title>
148
- </head>
149
- <body>
150
- <h1>QEMU @VERSION@ Documentation</h1>
151
- <ul>
152
- <li><a href="system/index.html">System Emulation User's Guide</a></li>
153
- <li><a href="user/index.html">User Mode Emulation User's Guide</a></li>
154
- <li><a href="tools/index.html">Tools Guide</a></li>
155
- <li><a href="interop/index.html">System Emulation Management and Interoperability Guide</a></li>
156
- <li><a href="specs/index.html">System Emulation Guest Hardware Specifications</a></li>
157
- </ul>
158
- </body>
159
-</html>
160
diff --git a/docs/interop/conf.py b/docs/interop/conf.py
161
deleted file mode 100644
162
index XXXXXXX..XXXXXXX
163
--- a/docs/interop/conf.py
164
+++ /dev/null
165
@@ -XXX,XX +XXX,XX @@
166
-# -*- coding: utf-8 -*-
167
-#
168
-# QEMU documentation build configuration file for the 'interop' manual.
169
-#
170
-# This includes the top level conf file and then makes any necessary tweaks.
171
-import sys
172
-import os
173
-
174
-qemu_docdir = os.path.abspath("..")
175
-parent_config = os.path.join(qemu_docdir, "conf.py")
176
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
177
-
178
-# This slightly misuses the 'description', but is the best way to get
179
-# the manual title to appear in the sidebar.
180
-html_theme_options['description'] = u'System Emulation Management and Interoperability Guide'
181
-
182
-# One entry per manual page. List of tuples
183
-# (source start file, name, description, authors, manual section).
184
-man_pages = [
185
- ('qemu-ga', 'qemu-ga', u'QEMU Guest Agent',
186
- ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
187
- ('qemu-ga-ref', 'qemu-ga-ref', 'QEMU Guest Agent Protocol Reference',
188
- [], 7),
189
- ('qemu-qmp-ref', 'qemu-qmp-ref', 'QEMU QMP Reference Manual',
190
- [], 7),
191
- ('qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
192
- 'QEMU Storage Daemon QMP Reference Manual', [], 7),
193
-]
194
diff --git a/docs/meson.build b/docs/meson.build
195
index XXXXXXX..XXXXXXX 100644
196
--- a/docs/meson.build
197
+++ b/docs/meson.build
198
@@ -XXX,XX +XXX,XX @@ if build_docs
199
meson.source_root() / 'docs/sphinx/qmp_lexer.py',
200
qapi_gen_depends ]
201
202
- configure_file(output: 'index.html',
203
- input: files('index.html.in'),
204
- configuration: {'VERSION': meson.project_version()},
205
- install_dir: qemu_docdir)
206
- manuals = [ 'devel', 'interop', 'tools', 'specs', 'system', 'user' ]
207
man_pages = {
208
- 'interop' : {
209
'qemu-ga.8': (have_tools ? 'man8' : ''),
210
'qemu-ga-ref.7': 'man7',
211
'qemu-qmp-ref.7': 'man7',
212
'qemu-storage-daemon-qmp-ref.7': (have_tools ? 'man7' : ''),
213
- },
214
- 'tools': {
215
'qemu-img.1': (have_tools ? 'man1' : ''),
216
'qemu-nbd.8': (have_tools ? 'man8' : ''),
217
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
218
@@ -XXX,XX +XXX,XX @@ if build_docs
219
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
220
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
221
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
222
- },
223
- 'system': {
224
'qemu.1': 'man1',
225
'qemu-block-drivers.7': 'man7',
226
'qemu-cpu-models.7': 'man7'
227
- },
228
}
229
230
sphinxdocs = []
231
sphinxmans = []
232
- foreach manual : manuals
233
- private_dir = meson.current_build_dir() / (manual + '.p')
234
- output_dir = meson.current_build_dir() / manual
235
- input_dir = meson.current_source_dir() / manual
236
237
- this_manual = custom_target(manual + ' manual',
238
+ private_dir = meson.current_build_dir() / 'manual.p'
239
+ output_dir = meson.current_build_dir() / 'manual'
240
+ input_dir = meson.current_source_dir()
52
+
241
+
53
+ if (a->ra != 15) {
242
+ this_manual = custom_target('QEMU manual',
54
+ t2 = load_reg(s, a->ra);
243
build_by_default: build_docs,
55
+ gen_helper_add_setq(t1, cpu_env, t1, t2);
244
- output: [manual + '.stamp'],
56
+ tcg_temp_free_i32(t2);
245
- input: [files('conf.py'), files(manual / 'conf.py')],
57
+ }
246
- depfile: manual + '.d',
58
+ } else if (a->ra == 15) {
247
+ output: 'docs.stamp',
59
+ /* Single saturation-checking addition */
248
+ input: files('conf.py'),
60
+ gen_helper_add_setq(t1, cpu_env, t1, t2);
249
+ depfile: 'docs.d',
61
+ tcg_temp_free_i32(t2);
250
depend_files: sphinx_extn_depends,
62
} else {
251
command: [SPHINX_ARGS, '-Ddepfile=@DEPFILE@',
63
/*
252
'-Ddepfile_stamp=@OUTPUT0@',
64
- * This addition cannot overflow 32 bits; however it may
253
'-b', 'html', '-d', private_dir,
65
- * overflow considered as a signed operation, in which case
254
input_dir, output_dir])
66
- * we must set the Q flag.
255
- sphinxdocs += this_manual
67
+ * We need to add the products and Ra together and then
256
- if build_docs and manual != 'devel'
68
+ * determine whether the final result overflowed. Doing
257
- install_subdir(output_dir, install_dir: qemu_docdir)
69
+ * this as two separate add-and-check-overflow steps incorrectly
258
- endif
70
+ * sets Q for cases like (-32768 * -32768) + (-32768 * -32768) + -1.
259
+ sphinxdocs += this_manual
71
+ * Do all the arithmetic at 64-bits and then check for overflow.
260
+ install_subdir(output_dir, install_dir: qemu_docdir, strip_directory: true)
72
*/
261
73
- gen_helper_add_setq(t1, cpu_env, t1, t2);
262
- these_man_pages = []
74
- }
263
- install_dirs = []
75
- tcg_temp_free_i32(t2);
264
- foreach page, section : man_pages.get(manual, {})
76
+ TCGv_i64 p64, q64;
265
- these_man_pages += page
77
+ TCGv_i32 t3, qf, one;
266
- install_dirs += section == '' ? false : get_option('mandir') / section
78
267
- endforeach
79
- if (a->ra != 15) {
268
- if these_man_pages.length() > 0
80
- t2 = load_reg(s, a->ra);
269
- sphinxmans += custom_target(manual + ' man pages',
81
- gen_helper_add_setq(t1, cpu_env, t1, t2);
270
- build_by_default: build_docs,
82
+ p64 = tcg_temp_new_i64();
271
- output: these_man_pages,
83
+ q64 = tcg_temp_new_i64();
272
- input: this_manual,
84
+ tcg_gen_ext_i32_i64(p64, t1);
273
- install: build_docs,
85
+ tcg_gen_ext_i32_i64(q64, t2);
274
- install_dir: install_dirs,
86
+ tcg_gen_add_i64(p64, p64, q64);
275
- command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
87
+ load_reg_var(s, t2, a->ra);
276
- input_dir, meson.current_build_dir()])
88
+ tcg_gen_ext_i32_i64(q64, t2);
277
- endif
89
+ tcg_gen_add_i64(p64, p64, q64);
278
+ these_man_pages = []
90
+ tcg_temp_free_i64(q64);
279
+ install_dirs = []
280
+ foreach page, section : man_pages
281
+ these_man_pages += page
282
+ install_dirs += section == '' ? false : get_option('mandir') / section
283
endforeach
91
+
284
+
92
+ tcg_gen_extr_i64_i32(t1, t2, p64);
285
+ sphinxmans += custom_target('QEMU man pages',
93
+ tcg_temp_free_i64(p64);
286
+ build_by_default: build_docs,
94
+ /*
287
+ output: these_man_pages,
95
+ * t1 is the low half of the result which goes into Rd.
288
+ input: this_manual,
96
+ * We have overflow and must set Q if the high half (t2)
289
+ install: build_docs,
97
+ * is different from the sign-extension of t1.
290
+ install_dir: install_dirs,
98
+ */
291
+ command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
99
+ t3 = tcg_temp_new_i32();
292
+ input_dir, meson.current_build_dir()])
100
+ tcg_gen_sari_i32(t3, t1, 31);
293
+
101
+ qf = load_cpu_field(QF);
294
alias_target('sphinxdocs', sphinxdocs)
102
+ one = tcg_const_i32(1);
295
alias_target('html', sphinxdocs)
103
+ tcg_gen_movcond_i32(TCG_COND_NE, qf, t2, t3, one, qf);
296
alias_target('man', sphinxmans)
104
+ store_cpu_field(qf, QF);
297
diff --git a/docs/specs/conf.py b/docs/specs/conf.py
105
+ tcg_temp_free_i32(one);
298
deleted file mode 100644
106
+ tcg_temp_free_i32(t3);
299
index XXXXXXX..XXXXXXX
107
tcg_temp_free_i32(t2);
300
--- a/docs/specs/conf.py
108
}
301
+++ /dev/null
109
store_reg(s, a->rd, t1);
302
@@ -XXX,XX +XXX,XX @@
303
-# -*- coding: utf-8 -*-
304
-#
305
-# QEMU documentation build configuration file for the 'specs' manual.
306
-#
307
-# This includes the top level conf file and then makes any necessary tweaks.
308
-import sys
309
-import os
310
-
311
-qemu_docdir = os.path.abspath("..")
312
-parent_config = os.path.join(qemu_docdir, "conf.py")
313
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
314
-
315
-# This slightly misuses the 'description', but is the best way to get
316
-# the manual title to appear in the sidebar.
317
-html_theme_options['description'] = \
318
- u'System Emulation Guest Hardware Specifications'
319
diff --git a/docs/system/conf.py b/docs/system/conf.py
320
deleted file mode 100644
321
index XXXXXXX..XXXXXXX
322
--- a/docs/system/conf.py
323
+++ /dev/null
324
@@ -XXX,XX +XXX,XX @@
325
-# -*- coding: utf-8 -*-
326
-#
327
-# QEMU documentation build configuration file for the 'system' manual.
328
-#
329
-# This includes the top level conf file and then makes any necessary tweaks.
330
-import sys
331
-import os
332
-
333
-qemu_docdir = os.path.abspath("..")
334
-parent_config = os.path.join(qemu_docdir, "conf.py")
335
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
336
-
337
-# This slightly misuses the 'description', but is the best way to get
338
-# the manual title to appear in the sidebar.
339
-html_theme_options['description'] = u'System Emulation User''s Guide'
340
-
341
-# One entry per manual page. List of tuples
342
-# (source start file, name, description, authors, manual section).
343
-man_pages = [
344
- ('qemu-manpage', 'qemu', u'QEMU User Documentation',
345
- ['Fabrice Bellard'], 1),
346
- ('qemu-block-drivers', 'qemu-block-drivers',
347
- u'QEMU block drivers reference',
348
- ['Fabrice Bellard and the QEMU Project developers'], 7),
349
- ('qemu-cpu-models', 'qemu-cpu-models',
350
- u'QEMU CPU Models',
351
- ['The QEMU Project developers'], 7)
352
-]
353
diff --git a/docs/tools/conf.py b/docs/tools/conf.py
354
deleted file mode 100644
355
index XXXXXXX..XXXXXXX
356
--- a/docs/tools/conf.py
357
+++ /dev/null
358
@@ -XXX,XX +XXX,XX @@
359
-# -*- coding: utf-8 -*-
360
-#
361
-# QEMU documentation build configuration file for the 'tools' manual.
362
-#
363
-# This includes the top level conf file and then makes any necessary tweaks.
364
-import sys
365
-import os
366
-
367
-qemu_docdir = os.path.abspath("..")
368
-parent_config = os.path.join(qemu_docdir, "conf.py")
369
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
370
-
371
-# This slightly misuses the 'description', but is the best way to get
372
-# the manual title to appear in the sidebar.
373
-html_theme_options['description'] = \
374
- u'Tools Guide'
375
-
376
-# One entry per manual page. List of tuples
377
-# (source start file, name, description, authors, manual section).
378
-man_pages = [
379
- ('qemu-img', 'qemu-img', u'QEMU disk image utility',
380
- ['Fabrice Bellard'], 1),
381
- ('qemu-storage-daemon', 'qemu-storage-daemon', u'QEMU storage daemon',
382
- [], 1),
383
- ('qemu-nbd', 'qemu-nbd', u'QEMU Disk Network Block Device Server',
384
- ['Anthony Liguori <anthony@codemonkey.ws>'], 8),
385
- ('qemu-pr-helper', 'qemu-pr-helper', 'QEMU persistent reservation helper',
386
- [], 8),
387
- ('qemu-trace-stap', 'qemu-trace-stap', u'QEMU SystemTap trace tool',
388
- [], 1),
389
- ('virtfs-proxy-helper', 'virtfs-proxy-helper',
390
- u'QEMU 9p virtfs proxy filesystem helper',
391
- ['M. Mohan Kumar'], 1),
392
- ('virtiofsd', 'virtiofsd', u'QEMU virtio-fs shared file system daemon',
393
- ['Stefan Hajnoczi <stefanha@redhat.com>',
394
- 'Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>'], 1),
395
-]
396
diff --git a/docs/user/conf.py b/docs/user/conf.py
397
deleted file mode 100644
398
index XXXXXXX..XXXXXXX
399
--- a/docs/user/conf.py
400
+++ /dev/null
401
@@ -XXX,XX +XXX,XX @@
402
-# -*- coding: utf-8 -*-
403
-#
404
-# QEMU documentation build configuration file for the 'user' manual.
405
-#
406
-# This includes the top level conf file and then makes any necessary tweaks.
407
-import sys
408
-import os
409
-
410
-qemu_docdir = os.path.abspath("..")
411
-parent_config = os.path.join(qemu_docdir, "conf.py")
412
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
413
-
414
-# This slightly misuses the 'description', but is the best way to get
415
-# the manual title to appear in the sidebar.
416
-html_theme_options['description'] = u'User Mode Emulation User''s Guide'
110
--
417
--
111
2.20.1
418
2.20.1
112
419
113
420
diff view generated by jsdifflib
1
v8.1M's "low-overhead-loop" extension has three instructions
1
In commit cd8be50e58f63413c0 we converted the A32 coprocessor
2
for looping:
2
insns to decodetree. This accidentally broke XScale/iWMMXt insns,
3
* DLS (start of a do-loop)
3
because it moved the handling of "cp insns which are handled
4
* WLS (start of a while-loop)
4
by looking up the cp register in the hashtable" from after the
5
* LE (end of a loop)
5
call to the legacy disas_xscale_insn() decode to before it,
6
with the result that all XScale/iWMMXt insns now UNDEF.
6
7
7
The loop-start instructions are both simple operations to start a
8
Update valid_cp() so that it knows that on XScale cp 0 and 1
8
loop whose iteration count (if any) is in LR. The loop-end
9
are not standard coprocessor instructions; this will cause
9
instruction handles "decrement iteration count and jump back to loop
10
the decodetree trans_ functions to ignore them, so that
10
start"; it also caches the information about the branch back to the
11
execution will correctly get through to the legacy decode again.
11
start of the loop to improve performance of the branch on subsequent
12
iterations.
13
12
14
As with the branch-future instructions, the architecture permits an
13
Cc: qemu-stable@nongnu.org
15
implementation to discard the LO_BRANCH_INFO cache at any time, and
14
Reported-by: Guenter Roeck <linux@roeck-us.net>
16
QEMU takes the IMPDEF option to never set it in the first place
17
(equivalent to discarding it immediately), because for us a "real"
18
implementation would be unnecessary complexity.
19
20
(This implementation only provides the simple looping constructs; the
21
vector extension MVE (Helium) adds some extra variants to handle
22
looping across vectors. We'll add those later when we implement
23
MVE.)
24
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
26
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
27
Message-id: 20201019151301.2046-8-peter.maydell@linaro.org
17
Tested-by: Guenter Roeck <linux@roeck-us.net>
18
Message-id: 20210108195157.32067-1-peter.maydell@linaro.org
28
---
19
---
29
target/arm/t32.decode | 8 ++++
20
target/arm/translate.c | 7 +++++++
30
target/arm/translate.c | 93 +++++++++++++++++++++++++++++++++++++++++-
21
1 file changed, 7 insertions(+)
31
2 files changed, 99 insertions(+), 2 deletions(-)
32
22
33
diff --git a/target/arm/t32.decode b/target/arm/t32.decode
34
index XXXXXXX..XXXXXXX 100644
35
--- a/target/arm/t32.decode
36
+++ b/target/arm/t32.decode
37
@@ -XXX,XX +XXX,XX @@ BL 1111 0. .......... 11.1 ............ @branch24
38
BF 1111 0 boff:4 10 ----- 1110 - ---------- 1 # BF
39
BF 1111 0 boff:4 11 ----- 1110 0 0000000000 1 # BFX, BFLX
40
]
41
+ [
42
+ # LE and WLS immediate
43
+ %lob_imm 1:10 11:1 !function=times_2
44
+
45
+ DLS 1111 0 0000 100 rn:4 1110 0000 0000 0001
46
+ WLS 1111 0 0000 100 rn:4 1100 . .......... 1 imm=%lob_imm
47
+ LE 1111 0 0000 0 f:1 0 1111 1100 . .......... 1 imm=%lob_imm
48
+ ]
49
}
50
diff --git a/target/arm/translate.c b/target/arm/translate.c
23
diff --git a/target/arm/translate.c b/target/arm/translate.c
51
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
52
--- a/target/arm/translate.c
25
--- a/target/arm/translate.c
53
+++ b/target/arm/translate.c
26
+++ b/target/arm/translate.c
54
@@ -XXX,XX +XXX,XX @@ static void gen_goto_tb(DisasContext *s, int n, target_ulong dest)
27
@@ -XXX,XX +XXX,XX @@ static bool valid_cp(DisasContext *s, int cp)
55
s->base.is_jmp = DISAS_NORETURN;
28
* only cp14 and cp15 are valid, and other values aren't considered
56
}
29
* to be in the coprocessor-instruction space at all. v8M still
57
30
* permits coprocessors 0..7.
58
-static inline void gen_jmp (DisasContext *s, uint32_t dest)
31
+ * For XScale, we must not decode the XScale cp0, cp1 space as
59
+/* Jump, specifying which TB number to use if we gen_goto_tb() */
32
+ * a standard coprocessor insn, because we want to fall through to
60
+static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
33
+ * the legacy disas_xscale_insn() decoder after decodetree is done.
61
{
34
*/
62
if (unlikely(is_singlestepping(s))) {
35
+ if (arm_dc_feature(s, ARM_FEATURE_XSCALE) && (cp == 0 || cp == 1)) {
63
/* An indirect jump so that we still trigger the debug exception. */
64
gen_set_pc_im(s, dest);
65
s->base.is_jmp = DISAS_JUMP;
66
} else {
67
- gen_goto_tb(s, 0, dest);
68
+ gen_goto_tb(s, tbno, dest);
69
}
70
}
71
72
+static inline void gen_jmp(DisasContext *s, uint32_t dest)
73
+{
74
+ gen_jmp_tb(s, dest, 0);
75
+}
76
+
77
static inline void gen_mulxy(TCGv_i32 t0, TCGv_i32 t1, int x, int y)
78
{
79
if (x)
80
@@ -XXX,XX +XXX,XX @@ static bool trans_BF(DisasContext *s, arg_BF *a)
81
return true;
82
}
83
84
+static bool trans_DLS(DisasContext *s, arg_DLS *a)
85
+{
86
+ /* M-profile low-overhead loop start */
87
+ TCGv_i32 tmp;
88
+
89
+ if (!dc_isar_feature(aa32_lob, s)) {
90
+ return false;
91
+ }
92
+ if (a->rn == 13 || a->rn == 15) {
93
+ /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
94
+ return false;
36
+ return false;
95
+ }
37
+ }
96
+
38
+
97
+ /* Not a while loop, no tail predication: just set LR to the count */
39
if (arm_dc_feature(s, ARM_FEATURE_V8) &&
98
+ tmp = load_reg(s, a->rn);
40
!arm_dc_feature(s, ARM_FEATURE_M)) {
99
+ store_reg(s, 14, tmp);
41
return cp >= 14;
100
+ return true;
101
+}
102
+
103
+static bool trans_WLS(DisasContext *s, arg_WLS *a)
104
+{
105
+ /* M-profile low-overhead while-loop start */
106
+ TCGv_i32 tmp;
107
+ TCGLabel *nextlabel;
108
+
109
+ if (!dc_isar_feature(aa32_lob, s)) {
110
+ return false;
111
+ }
112
+ if (a->rn == 13 || a->rn == 15) {
113
+ /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
114
+ return false;
115
+ }
116
+ if (s->condexec_mask) {
117
+ /*
118
+ * WLS in an IT block is CONSTRAINED UNPREDICTABLE;
119
+ * we choose to UNDEF, because otherwise our use of
120
+ * gen_goto_tb(1) would clash with the use of TB exit 1
121
+ * in the dc->condjmp condition-failed codepath in
122
+ * arm_tr_tb_stop() and we'd get an assertion.
123
+ */
124
+ return false;
125
+ }
126
+ nextlabel = gen_new_label();
127
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_R[a->rn], 0, nextlabel);
128
+ tmp = load_reg(s, a->rn);
129
+ store_reg(s, 14, tmp);
130
+ gen_jmp_tb(s, s->base.pc_next, 1);
131
+
132
+ gen_set_label(nextlabel);
133
+ gen_jmp(s, read_pc(s) + a->imm);
134
+ return true;
135
+}
136
+
137
+static bool trans_LE(DisasContext *s, arg_LE *a)
138
+{
139
+ /*
140
+ * M-profile low-overhead loop end. The architecture permits an
141
+ * implementation to discard the LO_BRANCH_INFO cache at any time,
142
+ * and we take the IMPDEF option to never set it in the first place
143
+ * (equivalent to always discarding it immediately), because for QEMU
144
+ * a "real" implementation would be complicated and wouldn't execute
145
+ * any faster.
146
+ */
147
+ TCGv_i32 tmp;
148
+
149
+ if (!dc_isar_feature(aa32_lob, s)) {
150
+ return false;
151
+ }
152
+
153
+ if (!a->f) {
154
+ /* Not loop-forever. If LR <= 1 this is the last loop: do nothing. */
155
+ arm_gen_condlabel(s);
156
+ tcg_gen_brcondi_i32(TCG_COND_LEU, cpu_R[14], 1, s->condlabel);
157
+ /* Decrement LR */
158
+ tmp = load_reg(s, 14);
159
+ tcg_gen_addi_i32(tmp, tmp, -1);
160
+ store_reg(s, 14, tmp);
161
+ }
162
+ /* Jump back to the loop start */
163
+ gen_jmp(s, read_pc(s) - a->imm);
164
+ return true;
165
+}
166
+
167
static bool op_tbranch(DisasContext *s, arg_tbranch *a, bool half)
168
{
169
TCGv_i32 addr, tmp;
170
--
42
--
171
2.20.1
43
2.20.1
172
44
173
45
diff view generated by jsdifflib
1
For nested groups like:
1
A copy-and-paste error meant that the return value for register offset 0x44
2
(the RX Status FIFO PEEK register) returned a byte from a bogus offset in
3
the rx status FIFO. Fix the typo.
2
4
3
{
5
Cc: qemu-stable@nongnu.org
4
[
6
Fixes: https://bugs.launchpad.net/qemu/+bug/1904954
5
pattern 1
6
pattern 2
7
]
8
pattern 3
9
}
10
11
the intended behaviour is that patterns 1 and 2 must not
12
overlap with each other; if the insn matches neither then
13
we fall through to pattern 3 as the next thing in the
14
outer overlapping group.
15
16
Currently we generate incorrect code for this situation,
17
because in the code path for a failed match inside the
18
inner non-overlapping group we generate a "return" statement,
19
which causes decode to stop entirely rather than continuing
20
to the next thing in the outer group.
21
22
Generate a "break" instead, so that decode flow behaves
23
as required for this nested group case.
24
25
Suggested-by: Richard Henderson <richard.henderson@linaro.org>
26
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
27
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
28
Message-id: 20201019151301.2046-2-peter.maydell@linaro.org
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Message-id: 20210108180401.2263-2-peter.maydell@linaro.org
29
---
10
---
30
scripts/decodetree.py | 2 +-
11
hw/net/lan9118.c | 2 +-
31
1 file changed, 1 insertion(+), 1 deletion(-)
12
1 file changed, 1 insertion(+), 1 deletion(-)
32
13
33
diff --git a/scripts/decodetree.py b/scripts/decodetree.py
14
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
34
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
35
--- a/scripts/decodetree.py
16
--- a/hw/net/lan9118.c
36
+++ b/scripts/decodetree.py
17
+++ b/hw/net/lan9118.c
37
@@ -XXX,XX +XXX,XX @@ class Tree:
18
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
38
output(ind, ' /* ',
19
case 0x40:
39
str_match_bits(innerbits, innermask), ' */\n')
20
return rx_status_fifo_pop(s);
40
s.output_code(i + 4, extracted, innerbits, innermask)
21
case 0x44:
41
- output(ind, ' return false;\n')
22
- return s->rx_status_fifo[s->tx_status_fifo_head];
42
+ output(ind, ' break;\n')
23
+ return s->rx_status_fifo[s->rx_status_fifo_head];
43
output(ind, '}\n')
24
case 0x48:
44
# end Tree
25
return tx_status_fifo_pop(s);
45
26
case 0x4c:
46
--
27
--
47
2.20.1
28
2.20.1
48
29
49
30
diff view generated by jsdifflib
1
For AArch32, unlike the VCVT of integer to float, which honours the
1
The lan9118 code mostly uses symbolic constants for register offsets;
2
rounding mode specified by the FPSCR, VCVT of fixed-point to float is
2
the exceptions are those which the datasheet doesn't give an official
3
always round-to-nearest. (AArch64 fixed-point-to-float conversions
3
symbolic name to.
4
always honour the FPCR rounding mode.)
5
4
6
Implement this by providing _round_to_nearest versions of the
5
Add some names for the registers which don't already have them, based
7
relevant helpers which set the rounding mode temporarily when making
6
on the longer names they are given in the memory map.
8
the call to the underlying softfloat function.
9
10
We only need to change the VFP VCVT instructions, because the
11
standard- FPSCR value used by the Neon VCVT is always set to
12
round-to-nearest, so we don't need to do the extra work of saving
13
and restoring the rounding mode.
14
7
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
17
Message-id: 20201013103532.13391-1-peter.maydell@linaro.org
10
Message-id: 20210108180401.2263-3-peter.maydell@linaro.org
18
---
11
---
19
target/arm/helper.h | 13 +++++++++++++
12
hw/net/lan9118.c | 24 ++++++++++++++++++------
20
target/arm/vfp_helper.c | 23 ++++++++++++++++++++++-
13
1 file changed, 18 insertions(+), 6 deletions(-)
21
target/arm/translate-vfp.c.inc | 24 ++++++++++++------------
22
3 files changed, 47 insertions(+), 13 deletions(-)
23
14
24
diff --git a/target/arm/helper.h b/target/arm/helper.h
15
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
25
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
26
--- a/target/arm/helper.h
17
--- a/hw/net/lan9118.c
27
+++ b/target/arm/helper.h
18
+++ b/hw/net/lan9118.c
28
@@ -XXX,XX +XXX,XX @@ DEF_HELPER_3(vfp_ultoh, f16, i32, i32, ptr)
19
@@ -XXX,XX +XXX,XX @@ do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
29
DEF_HELPER_3(vfp_sqtoh, f16, i64, i32, ptr)
20
do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
30
DEF_HELPER_3(vfp_uqtoh, f16, i64, i32, ptr)
21
#endif
31
22
32
+DEF_HELPER_3(vfp_shtos_round_to_nearest, f32, i32, i32, ptr)
23
+/* The tx and rx fifo ports are a range of aliased 32-bit registers */
33
+DEF_HELPER_3(vfp_sltos_round_to_nearest, f32, i32, i32, ptr)
24
+#define RX_DATA_FIFO_PORT_FIRST 0x00
34
+DEF_HELPER_3(vfp_uhtos_round_to_nearest, f32, i32, i32, ptr)
25
+#define RX_DATA_FIFO_PORT_LAST 0x1f
35
+DEF_HELPER_3(vfp_ultos_round_to_nearest, f32, i32, i32, ptr)
26
+#define TX_DATA_FIFO_PORT_FIRST 0x20
36
+DEF_HELPER_3(vfp_shtod_round_to_nearest, f64, i64, i32, ptr)
27
+#define TX_DATA_FIFO_PORT_LAST 0x3f
37
+DEF_HELPER_3(vfp_sltod_round_to_nearest, f64, i64, i32, ptr)
38
+DEF_HELPER_3(vfp_uhtod_round_to_nearest, f64, i64, i32, ptr)
39
+DEF_HELPER_3(vfp_ultod_round_to_nearest, f64, i64, i32, ptr)
40
+DEF_HELPER_3(vfp_shtoh_round_to_nearest, f16, i32, i32, ptr)
41
+DEF_HELPER_3(vfp_uhtoh_round_to_nearest, f16, i32, i32, ptr)
42
+DEF_HELPER_3(vfp_sltoh_round_to_nearest, f16, i32, i32, ptr)
43
+DEF_HELPER_3(vfp_ultoh_round_to_nearest, f16, i32, i32, ptr)
44
+
28
+
45
DEF_HELPER_FLAGS_2(set_rmode, TCG_CALL_NO_RWG, i32, i32, ptr)
29
+#define RX_STATUS_FIFO_PORT 0x40
46
30
+#define RX_STATUS_FIFO_PEEK 0x44
47
DEF_HELPER_FLAGS_3(vfp_fcvt_f16_to_f32, TCG_CALL_NO_RWG, f32, f16, ptr, i32)
31
+#define TX_STATUS_FIFO_PORT 0x48
48
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
32
+#define TX_STATUS_FIFO_PEEK 0x4c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/target/arm/vfp_helper.c
51
+++ b/target/arm/vfp_helper.c
52
@@ -XXX,XX +XXX,XX @@ float32 VFP_HELPER(fcvts, d)(float64 x, CPUARMState *env)
53
return float64_to_float32(x, &env->vfp.fp_status);
54
}
55
56
-/* VFP3 fixed point conversion. */
57
+/*
58
+ * VFP3 fixed point conversion. The AArch32 versions of fix-to-float
59
+ * must always round-to-nearest; the AArch64 ones honour the FPSCR
60
+ * rounding mode. (For AArch32 Neon the standard-FPSCR is set to
61
+ * round-to-nearest so either helper will work.) AArch32 float-to-fix
62
+ * must round-to-zero.
63
+ */
64
#define VFP_CONV_FIX_FLOAT(name, p, fsz, ftype, isz, itype) \
65
ftype HELPER(vfp_##name##to##p)(uint##isz##_t x, uint32_t shift, \
66
void *fpstp) \
67
{ return itype##_to_##float##fsz##_scalbn(x, -shift, fpstp); }
68
69
+#define VFP_CONV_FIX_FLOAT_ROUND(name, p, fsz, ftype, isz, itype) \
70
+ ftype HELPER(vfp_##name##to##p##_round_to_nearest)(uint##isz##_t x, \
71
+ uint32_t shift, \
72
+ void *fpstp) \
73
+ { \
74
+ ftype ret; \
75
+ float_status *fpst = fpstp; \
76
+ FloatRoundMode oldmode = fpst->float_rounding_mode; \
77
+ fpst->float_rounding_mode = float_round_nearest_even; \
78
+ ret = itype##_to_##float##fsz##_scalbn(x, -shift, fpstp); \
79
+ fpst->float_rounding_mode = oldmode; \
80
+ return ret; \
81
+ }
82
+
33
+
83
#define VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, ROUND, suff) \
34
#define CSR_ID_REV 0x50
84
uint##isz##_t HELPER(vfp_to##name##p##suff)(ftype x, uint32_t shift, \
35
#define CSR_IRQ_CFG 0x54
85
void *fpst) \
36
#define CSR_INT_STS 0x58
86
@@ -XXX,XX +XXX,XX @@ uint##isz##_t HELPER(vfp_to##name##p##suff)(ftype x, uint32_t shift, \
37
@@ -XXX,XX +XXX,XX @@ static void lan9118_writel(void *opaque, hwaddr offset,
87
38
offset &= 0xff;
88
#define VFP_CONV_FIX(name, p, fsz, ftype, isz, itype) \
39
89
VFP_CONV_FIX_FLOAT(name, p, fsz, ftype, isz, itype) \
40
//DPRINTF("Write reg 0x%02x = 0x%08x\n", (int)offset, val);
90
+VFP_CONV_FIX_FLOAT_ROUND(name, p, fsz, ftype, isz, itype) \
41
- if (offset >= 0x20 && offset < 0x40) {
91
VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, \
42
+ if (offset >= TX_DATA_FIFO_PORT_FIRST &&
92
float_round_to_zero, _round_to_zero) \
43
+ offset <= TX_DATA_FIFO_PORT_LAST) {
93
VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, \
44
/* TX FIFO */
94
diff --git a/target/arm/translate-vfp.c.inc b/target/arm/translate-vfp.c.inc
45
tx_fifo_push(s, val);
95
index XXXXXXX..XXXXXXX 100644
46
return;
96
--- a/target/arm/translate-vfp.c.inc
47
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
97
+++ b/target/arm/translate-vfp.c.inc
48
lan9118_state *s = (lan9118_state *)opaque;
98
@@ -XXX,XX +XXX,XX @@ static bool trans_VCVT_fix_hp(DisasContext *s, arg_VCVT_fix_sp *a)
49
99
/* Switch on op:U:sx bits */
50
//DPRINTF("Read reg 0x%02x\n", (int)offset);
100
switch (a->opc) {
51
- if (offset < 0x20) {
101
case 0:
52
+ if (offset <= RX_DATA_FIFO_PORT_LAST) {
102
- gen_helper_vfp_shtoh(vd, vd, shift, fpst);
53
/* RX FIFO */
103
+ gen_helper_vfp_shtoh_round_to_nearest(vd, vd, shift, fpst);
54
return rx_fifo_pop(s);
104
break;
55
}
105
case 1:
56
switch (offset) {
106
- gen_helper_vfp_sltoh(vd, vd, shift, fpst);
57
- case 0x40:
107
+ gen_helper_vfp_sltoh_round_to_nearest(vd, vd, shift, fpst);
58
+ case RX_STATUS_FIFO_PORT:
108
break;
59
return rx_status_fifo_pop(s);
109
case 2:
60
- case 0x44:
110
- gen_helper_vfp_uhtoh(vd, vd, shift, fpst);
61
+ case RX_STATUS_FIFO_PEEK:
111
+ gen_helper_vfp_uhtoh_round_to_nearest(vd, vd, shift, fpst);
62
return s->rx_status_fifo[s->rx_status_fifo_head];
112
break;
63
- case 0x48:
113
case 3:
64
+ case TX_STATUS_FIFO_PORT:
114
- gen_helper_vfp_ultoh(vd, vd, shift, fpst);
65
return tx_status_fifo_pop(s);
115
+ gen_helper_vfp_ultoh_round_to_nearest(vd, vd, shift, fpst);
66
- case 0x4c:
116
break;
67
+ case TX_STATUS_FIFO_PEEK:
117
case 4:
68
return s->tx_status_fifo[s->tx_status_fifo_head];
118
gen_helper_vfp_toshh_round_to_zero(vd, vd, shift, fpst);
69
case CSR_ID_REV:
119
@@ -XXX,XX +XXX,XX @@ static bool trans_VCVT_fix_sp(DisasContext *s, arg_VCVT_fix_sp *a)
70
return 0x01180001;
120
/* Switch on op:U:sx bits */
121
switch (a->opc) {
122
case 0:
123
- gen_helper_vfp_shtos(vd, vd, shift, fpst);
124
+ gen_helper_vfp_shtos_round_to_nearest(vd, vd, shift, fpst);
125
break;
126
case 1:
127
- gen_helper_vfp_sltos(vd, vd, shift, fpst);
128
+ gen_helper_vfp_sltos_round_to_nearest(vd, vd, shift, fpst);
129
break;
130
case 2:
131
- gen_helper_vfp_uhtos(vd, vd, shift, fpst);
132
+ gen_helper_vfp_uhtos_round_to_nearest(vd, vd, shift, fpst);
133
break;
134
case 3:
135
- gen_helper_vfp_ultos(vd, vd, shift, fpst);
136
+ gen_helper_vfp_ultos_round_to_nearest(vd, vd, shift, fpst);
137
break;
138
case 4:
139
gen_helper_vfp_toshs_round_to_zero(vd, vd, shift, fpst);
140
@@ -XXX,XX +XXX,XX @@ static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a)
141
/* Switch on op:U:sx bits */
142
switch (a->opc) {
143
case 0:
144
- gen_helper_vfp_shtod(vd, vd, shift, fpst);
145
+ gen_helper_vfp_shtod_round_to_nearest(vd, vd, shift, fpst);
146
break;
147
case 1:
148
- gen_helper_vfp_sltod(vd, vd, shift, fpst);
149
+ gen_helper_vfp_sltod_round_to_nearest(vd, vd, shift, fpst);
150
break;
151
case 2:
152
- gen_helper_vfp_uhtod(vd, vd, shift, fpst);
153
+ gen_helper_vfp_uhtod_round_to_nearest(vd, vd, shift, fpst);
154
break;
155
case 3:
156
- gen_helper_vfp_ultod(vd, vd, shift, fpst);
157
+ gen_helper_vfp_ultod_round_to_nearest(vd, vd, shift, fpst);
158
break;
159
case 4:
160
gen_helper_vfp_toshd_round_to_zero(vd, vd, shift, fpst);
161
--
71
--
162
2.20.1
72
2.20.1
163
73
164
74
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
1
3
While APEI is a generic ACPI feature (usable by X86 and ARM64), only
4
the 'virt' machine uses it, by enabling the RAS Virtualization. See
5
commit 2afa8c8519: "hw/arm/virt: Introduce a RAS machine option").
6
7
Restrict the APEI tables generation code to the single user: the virt
8
machine. If another machine wants to use it, it simply has to 'select
9
ACPI_APEI' in its Kconfig.
10
11
Fixes: aa16508f1d ("ACPI: Build related register address fields via hardware error fw_cfg blob")
12
Acked-by: Michael S. Tsirkin <mst@redhat.com>
13
Reviewed-by: Dongjiu Geng <gengdongjiu@huawei.com>
14
Acked-by: Laszlo Ersek <lersek@redhat.com>
15
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
16
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
17
Message-id: 20201008161414.2672569-1-philmd@redhat.com
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
---
20
default-configs/devices/arm-softmmu.mak | 1 -
21
hw/arm/Kconfig | 1 +
22
2 files changed, 1 insertion(+), 1 deletion(-)
23
24
diff --git a/default-configs/devices/arm-softmmu.mak b/default-configs/devices/arm-softmmu.mak
25
index XXXXXXX..XXXXXXX 100644
26
--- a/default-configs/devices/arm-softmmu.mak
27
+++ b/default-configs/devices/arm-softmmu.mak
28
@@ -XXX,XX +XXX,XX @@ CONFIG_FSL_IMX7=y
29
CONFIG_FSL_IMX6UL=y
30
CONFIG_SEMIHOSTING=y
31
CONFIG_ALLWINNER_H3=y
32
-CONFIG_ACPI_APEI=y
33
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
34
index XXXXXXX..XXXXXXX 100644
35
--- a/hw/arm/Kconfig
36
+++ b/hw/arm/Kconfig
37
@@ -XXX,XX +XXX,XX @@ config ARM_VIRT
38
select ACPI_MEMORY_HOTPLUG
39
select ACPI_HW_REDUCED
40
select ACPI_NVDIMM
41
+ select ACPI_APEI
42
43
config CHEETAH
44
bool
45
--
46
2.20.1
47
48
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
1
3
Use the BCM2835_SYSTIMER_COUNT definition instead of the
4
magic '4' value.
5
6
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Message-id: 20201010203709.3116542-2-f4bug@amsat.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
include/hw/timer/bcm2835_systmr.h | 4 +++-
13
hw/timer/bcm2835_systmr.c | 3 ++-
14
2 files changed, 5 insertions(+), 2 deletions(-)
15
16
diff --git a/include/hw/timer/bcm2835_systmr.h b/include/hw/timer/bcm2835_systmr.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/hw/timer/bcm2835_systmr.h
19
+++ b/include/hw/timer/bcm2835_systmr.h
20
@@ -XXX,XX +XXX,XX @@
21
#define TYPE_BCM2835_SYSTIMER "bcm2835-sys-timer"
22
OBJECT_DECLARE_SIMPLE_TYPE(BCM2835SystemTimerState, BCM2835_SYSTIMER)
23
24
+#define BCM2835_SYSTIMER_COUNT 4
25
+
26
struct BCM2835SystemTimerState {
27
/*< private >*/
28
SysBusDevice parent_obj;
29
@@ -XXX,XX +XXX,XX @@ struct BCM2835SystemTimerState {
30
31
struct {
32
uint32_t status;
33
- uint32_t compare[4];
34
+ uint32_t compare[BCM2835_SYSTIMER_COUNT];
35
} reg;
36
};
37
38
diff --git a/hw/timer/bcm2835_systmr.c b/hw/timer/bcm2835_systmr.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/hw/timer/bcm2835_systmr.c
41
+++ b/hw/timer/bcm2835_systmr.c
42
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription bcm2835_systmr_vmstate = {
43
.minimum_version_id = 1,
44
.fields = (VMStateField[]) {
45
VMSTATE_UINT32(reg.status, BCM2835SystemTimerState),
46
- VMSTATE_UINT32_ARRAY(reg.compare, BCM2835SystemTimerState, 4),
47
+ VMSTATE_UINT32_ARRAY(reg.compare, BCM2835SystemTimerState,
48
+ BCM2835_SYSTIMER_COUNT),
49
VMSTATE_END_OF_LIST()
50
}
51
};
52
--
53
2.20.1
54
55
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
1
3
The variable holding the CTRL_STATUS register is misnamed
4
'status'. Rename it 'ctrl_status' to make it more obvious
5
this register is also used to control the peripheral.
6
7
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Message-id: 20201010203709.3116542-3-f4bug@amsat.org
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
include/hw/timer/bcm2835_systmr.h | 2 +-
14
hw/timer/bcm2835_systmr.c | 8 ++++----
15
2 files changed, 5 insertions(+), 5 deletions(-)
16
17
diff --git a/include/hw/timer/bcm2835_systmr.h b/include/hw/timer/bcm2835_systmr.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/include/hw/timer/bcm2835_systmr.h
20
+++ b/include/hw/timer/bcm2835_systmr.h
21
@@ -XXX,XX +XXX,XX @@ struct BCM2835SystemTimerState {
22
qemu_irq irq;
23
24
struct {
25
- uint32_t status;
26
+ uint32_t ctrl_status;
27
uint32_t compare[BCM2835_SYSTIMER_COUNT];
28
} reg;
29
};
30
diff --git a/hw/timer/bcm2835_systmr.c b/hw/timer/bcm2835_systmr.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/hw/timer/bcm2835_systmr.c
33
+++ b/hw/timer/bcm2835_systmr.c
34
@@ -XXX,XX +XXX,XX @@ REG32(COMPARE3, 0x18)
35
36
static void bcm2835_systmr_update_irq(BCM2835SystemTimerState *s)
37
{
38
- bool enable = !!s->reg.status;
39
+ bool enable = !!s->reg.ctrl_status;
40
41
trace_bcm2835_systmr_irq(enable);
42
qemu_set_irq(s->irq, enable);
43
@@ -XXX,XX +XXX,XX @@ static uint64_t bcm2835_systmr_read(void *opaque, hwaddr offset,
44
45
switch (offset) {
46
case A_CTRL_STATUS:
47
- r = s->reg.status;
48
+ r = s->reg.ctrl_status;
49
break;
50
case A_COMPARE0 ... A_COMPARE3:
51
r = s->reg.compare[(offset - A_COMPARE0) >> 2];
52
@@ -XXX,XX +XXX,XX @@ static void bcm2835_systmr_write(void *opaque, hwaddr offset,
53
trace_bcm2835_systmr_write(offset, value);
54
switch (offset) {
55
case A_CTRL_STATUS:
56
- s->reg.status &= ~value; /* Ack */
57
+ s->reg.ctrl_status &= ~value; /* Ack */
58
bcm2835_systmr_update_irq(s);
59
break;
60
case A_COMPARE0 ... A_COMPARE3:
61
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription bcm2835_systmr_vmstate = {
62
.version_id = 1,
63
.minimum_version_id = 1,
64
.fields = (VMStateField[]) {
65
- VMSTATE_UINT32(reg.status, BCM2835SystemTimerState),
66
+ VMSTATE_UINT32(reg.ctrl_status, BCM2835SystemTimerState),
67
VMSTATE_UINT32_ARRAY(reg.compare, BCM2835SystemTimerState,
68
BCM2835_SYSTIMER_COUNT),
69
VMSTATE_END_OF_LIST()
70
--
71
2.20.1
72
73
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
1
3
This peripheral has 1 free-running timer and 4 compare registers.
4
5
Only the free-running timer is implemented. Add support the
6
COMPARE registers (each register is wired to an IRQ).
7
8
Reference: "BCM2835 ARM Peripherals" datasheet [*]
9
chapter 12 "System Timer":
10
11
The System Timer peripheral provides four 32-bit timer channels
12
and a single 64-bit free running counter. Each channel has an
13
output compare register, which is compared against the 32 least
14
significant bits of the free running counter values. When the
15
two values match, the system timer peripheral generates a signal
16
to indicate a match for the appropriate channel. The match signal
17
is then fed into the interrupt controller.
18
19
This peripheral is used since Linux 3.7, commit ee4af5696720
20
("ARM: bcm2835: add system timer").
21
22
[*] https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
23
24
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
25
Reviewed-by: Luc Michel <luc@lmichel.fr>
26
Message-id: 20201010203709.3116542-4-f4bug@amsat.org
27
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
28
---
29
include/hw/timer/bcm2835_systmr.h | 11 +++++--
30
hw/timer/bcm2835_systmr.c | 48 ++++++++++++++++++++-----------
31
hw/timer/trace-events | 6 ++--
32
3 files changed, 44 insertions(+), 21 deletions(-)
33
34
diff --git a/include/hw/timer/bcm2835_systmr.h b/include/hw/timer/bcm2835_systmr.h
35
index XXXXXXX..XXXXXXX 100644
36
--- a/include/hw/timer/bcm2835_systmr.h
37
+++ b/include/hw/timer/bcm2835_systmr.h
38
@@ -XXX,XX +XXX,XX @@
39
40
#include "hw/sysbus.h"
41
#include "hw/irq.h"
42
+#include "qemu/timer.h"
43
#include "qom/object.h"
44
45
#define TYPE_BCM2835_SYSTIMER "bcm2835-sys-timer"
46
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(BCM2835SystemTimerState, BCM2835_SYSTIMER)
47
48
#define BCM2835_SYSTIMER_COUNT 4
49
50
+typedef struct {
51
+ unsigned id;
52
+ QEMUTimer timer;
53
+ qemu_irq irq;
54
+ BCM2835SystemTimerState *state;
55
+} BCM2835SystemTimerCompare;
56
+
57
struct BCM2835SystemTimerState {
58
/*< private >*/
59
SysBusDevice parent_obj;
60
61
/*< public >*/
62
MemoryRegion iomem;
63
- qemu_irq irq;
64
-
65
struct {
66
uint32_t ctrl_status;
67
uint32_t compare[BCM2835_SYSTIMER_COUNT];
68
} reg;
69
+ BCM2835SystemTimerCompare tmr[BCM2835_SYSTIMER_COUNT];
70
};
71
72
#endif
73
diff --git a/hw/timer/bcm2835_systmr.c b/hw/timer/bcm2835_systmr.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/hw/timer/bcm2835_systmr.c
76
+++ b/hw/timer/bcm2835_systmr.c
77
@@ -XXX,XX +XXX,XX @@ REG32(COMPARE1, 0x10)
78
REG32(COMPARE2, 0x14)
79
REG32(COMPARE3, 0x18)
80
81
-static void bcm2835_systmr_update_irq(BCM2835SystemTimerState *s)
82
+static void bcm2835_systmr_timer_expire(void *opaque)
83
{
84
- bool enable = !!s->reg.ctrl_status;
85
+ BCM2835SystemTimerCompare *tmr = opaque;
86
87
- trace_bcm2835_systmr_irq(enable);
88
- qemu_set_irq(s->irq, enable);
89
-}
90
-
91
-static void bcm2835_systmr_update_compare(BCM2835SystemTimerState *s,
92
- unsigned timer_index)
93
-{
94
- /* TODO fow now, since neither Linux nor U-boot use these timers. */
95
- qemu_log_mask(LOG_UNIMP, "COMPARE register %u not implemented\n",
96
- timer_index);
97
+ trace_bcm2835_systmr_timer_expired(tmr->id);
98
+ tmr->state->reg.ctrl_status |= 1 << tmr->id;
99
+ qemu_set_irq(tmr->irq, 1);
100
}
101
102
static uint64_t bcm2835_systmr_read(void *opaque, hwaddr offset,
103
@@ -XXX,XX +XXX,XX @@ static uint64_t bcm2835_systmr_read(void *opaque, hwaddr offset,
104
}
105
106
static void bcm2835_systmr_write(void *opaque, hwaddr offset,
107
- uint64_t value, unsigned size)
108
+ uint64_t value64, unsigned size)
109
{
110
BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque);
111
+ int index;
112
+ uint32_t value = value64;
113
+ uint32_t triggers_delay_us;
114
+ uint64_t now;
115
116
trace_bcm2835_systmr_write(offset, value);
117
switch (offset) {
118
case A_CTRL_STATUS:
119
s->reg.ctrl_status &= ~value; /* Ack */
120
- bcm2835_systmr_update_irq(s);
121
+ for (index = 0; index < ARRAY_SIZE(s->tmr); index++) {
122
+ if (extract32(value, index, 1)) {
123
+ trace_bcm2835_systmr_irq_ack(index);
124
+ qemu_set_irq(s->tmr[index].irq, 0);
125
+ }
126
+ }
127
break;
128
case A_COMPARE0 ... A_COMPARE3:
129
- s->reg.compare[(offset - A_COMPARE0) >> 2] = value;
130
- bcm2835_systmr_update_compare(s, (offset - A_COMPARE0) >> 2);
131
+ index = (offset - A_COMPARE0) >> 2;
132
+ s->reg.compare[index] = value;
133
+ now = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
134
+ /* Compare lower 32-bits of the free-running counter. */
135
+ triggers_delay_us = value - now;
136
+ trace_bcm2835_systmr_run(index, triggers_delay_us);
137
+ timer_mod(&s->tmr[index].timer, now + triggers_delay_us);
138
break;
139
case A_COUNTER_LOW:
140
case A_COUNTER_HIGH:
141
@@ -XXX,XX +XXX,XX @@ static void bcm2835_systmr_realize(DeviceState *dev, Error **errp)
142
memory_region_init_io(&s->iomem, OBJECT(dev), &bcm2835_systmr_ops,
143
s, "bcm2835-sys-timer", 0x20);
144
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
145
- sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
146
+
147
+ for (size_t i = 0; i < ARRAY_SIZE(s->tmr); i++) {
148
+ s->tmr[i].id = i;
149
+ s->tmr[i].state = s;
150
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->tmr[i].irq);
151
+ timer_init_us(&s->tmr[i].timer, QEMU_CLOCK_VIRTUAL,
152
+ bcm2835_systmr_timer_expire, &s->tmr[i]);
153
+ }
154
}
155
156
static const VMStateDescription bcm2835_systmr_vmstate = {
157
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
158
index XXXXXXX..XXXXXXX 100644
159
--- a/hw/timer/trace-events
160
+++ b/hw/timer/trace-events
161
@@ -XXX,XX +XXX,XX @@ nrf51_timer_write(uint8_t timer_id, uint64_t addr, uint32_t value, unsigned size
162
nrf51_timer_set_count(uint8_t timer_id, uint8_t counter_id, uint32_t value) "timer %u counter %u count 0x%" PRIx32
163
164
# bcm2835_systmr.c
165
-bcm2835_systmr_irq(bool enable) "timer irq state %u"
166
+bcm2835_systmr_timer_expired(unsigned id) "timer #%u expired"
167
+bcm2835_systmr_irq_ack(unsigned id) "timer #%u acked"
168
bcm2835_systmr_read(uint64_t offset, uint64_t data) "timer read: offset 0x%" PRIx64 " data 0x%" PRIx64
169
-bcm2835_systmr_write(uint64_t offset, uint64_t data) "timer write: offset 0x%" PRIx64 " data 0x%" PRIx64
170
+bcm2835_systmr_write(uint64_t offset, uint32_t data) "timer write: offset 0x%" PRIx64 " data 0x%" PRIx32
171
+bcm2835_systmr_run(unsigned id, uint64_t delay_us) "timer #%u expiring in %"PRIu64" us"
172
173
# avr_timer16.c
174
avr_timer16_read(uint8_t addr, uint8_t value) "timer16 read addr:%u value:%u"
175
--
176
2.20.1
177
178
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
1
3
The SYS_timer is not directly wired to the ARM core, but to the
4
SoC (peripheral) interrupt controller.
5
6
Fixes: 0e5bbd74064 ("hw/arm/bcm2835_peripherals: Use the SYS_timer")
7
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Message-id: 20201010203709.3116542-5-f4bug@amsat.org
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
hw/arm/bcm2835_peripherals.c | 13 +++++++++++--
14
1 file changed, 11 insertions(+), 2 deletions(-)
15
16
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/arm/bcm2835_peripherals.c
19
+++ b/hw/arm/bcm2835_peripherals.c
20
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
21
memory_region_add_subregion(&s->peri_mr, ST_OFFSET,
22
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systmr), 0));
23
sysbus_connect_irq(SYS_BUS_DEVICE(&s->systmr), 0,
24
- qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ,
25
- INTERRUPT_ARM_TIMER));
26
+ qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
27
+ INTERRUPT_TIMER0));
28
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->systmr), 1,
29
+ qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
30
+ INTERRUPT_TIMER1));
31
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->systmr), 2,
32
+ qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
33
+ INTERRUPT_TIMER2));
34
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->systmr), 3,
35
+ qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
36
+ INTERRUPT_TIMER3));
37
38
/* UART0 */
39
qdev_prop_set_chr(DEVICE(&s->uart0), "chardev", serial_hd(0));
40
--
41
2.20.1
42
43
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
When TBI is enabled in a given regime, 56 bits of the address
3
This patch allows NPCM7XX CLK module to compute clocks that are used by
4
are significant and we need to clear out any other matching
4
other NPCM7XX modules.
5
virtual addresses with differing tags.
6
5
7
The other uses of tlb_flush_page (without mmuidx) in this file
6
Add a new struct NPCM7xxClockConverterState which represents a
8
are only used by aarch32 mode.
7
single converter. Each clock converter in CLK module represents one
8
converter in NPCM7XX CLK Module(PLL, SEL or Divider). Each converter
9
takes one or more input clocks and converts them into one output clock.
10
They form a clock hierarchy in the CLK module and are responsible for
11
outputing clocks for various other modules in an NPCM7XX SoC.
9
12
10
Fixes: 38d931687fa1
13
Each converter has a function pointer called "convert" which represents
11
Reported-by: Jordan Frank <jordanfrank@fb.com>
14
the unique logic for that converter.
15
16
The clock contains two initialization information: ConverterInitInfo and
17
ConverterConnectionInfo. They represent the vertices and edges in the
18
clock diagram respectively.
19
20
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
21
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
22
Signed-off-by: Hao Wu <wuhaotsh@google.com>
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
23
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
24
Message-id: 20210108190945.949196-2-wuhaotsh@google.com
14
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
15
Message-id: 20201016210754.818257-3-richard.henderson@linaro.org
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
---
26
---
18
target/arm/helper.c | 46 ++++++++++++++++++++++++++++++++++++++-------
27
include/hw/misc/npcm7xx_clk.h | 140 +++++-
19
1 file changed, 39 insertions(+), 7 deletions(-)
28
hw/misc/npcm7xx_clk.c | 805 +++++++++++++++++++++++++++++++++-
29
2 files changed, 932 insertions(+), 13 deletions(-)
20
30
21
diff --git a/target/arm/helper.c b/target/arm/helper.c
31
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
22
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
23
--- a/target/arm/helper.c
33
--- a/include/hw/misc/npcm7xx_clk.h
24
+++ b/target/arm/helper.c
34
+++ b/include/hw/misc/npcm7xx_clk.h
25
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
35
@@ -XXX,XX +XXX,XX @@
26
#endif
36
#define NPCM7XX_CLK_H
27
37
28
static void switch_mode(CPUARMState *env, int mode);
38
#include "exec/memory.h"
29
+static int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx);
39
+#include "hw/clock.h"
30
40
#include "hw/sysbus.h"
31
static int vfp_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
41
42
/*
43
@@ -XXX,XX +XXX,XX @@
44
45
#define NPCM7XX_WATCHDOG_RESET_GPIO_IN "npcm7xx-clk-watchdog-reset-gpio-in"
46
47
-typedef struct NPCM7xxCLKState {
48
+/* Maximum amount of clock inputs in a SEL module. */
49
+#define NPCM7XX_CLK_SEL_MAX_INPUT 5
50
+
51
+/* PLLs in CLK module. */
52
+typedef enum NPCM7xxClockPLL {
53
+ NPCM7XX_CLOCK_PLL0,
54
+ NPCM7XX_CLOCK_PLL1,
55
+ NPCM7XX_CLOCK_PLL2,
56
+ NPCM7XX_CLOCK_PLLG,
57
+ NPCM7XX_CLOCK_NR_PLLS,
58
+} NPCM7xxClockPLL;
59
+
60
+/* SEL/MUX in CLK module. */
61
+typedef enum NPCM7xxClockSEL {
62
+ NPCM7XX_CLOCK_PIXCKSEL,
63
+ NPCM7XX_CLOCK_MCCKSEL,
64
+ NPCM7XX_CLOCK_CPUCKSEL,
65
+ NPCM7XX_CLOCK_CLKOUTSEL,
66
+ NPCM7XX_CLOCK_UARTCKSEL,
67
+ NPCM7XX_CLOCK_TIMCKSEL,
68
+ NPCM7XX_CLOCK_SDCKSEL,
69
+ NPCM7XX_CLOCK_GFXMSEL,
70
+ NPCM7XX_CLOCK_SUCKSEL,
71
+ NPCM7XX_CLOCK_NR_SELS,
72
+} NPCM7xxClockSEL;
73
+
74
+/* Dividers in CLK module. */
75
+typedef enum NPCM7xxClockDivider {
76
+ NPCM7XX_CLOCK_PLL1D2, /* PLL1/2 */
77
+ NPCM7XX_CLOCK_PLL2D2, /* PLL2/2 */
78
+ NPCM7XX_CLOCK_MC_DIVIDER,
79
+ NPCM7XX_CLOCK_AXI_DIVIDER,
80
+ NPCM7XX_CLOCK_AHB_DIVIDER,
81
+ NPCM7XX_CLOCK_AHB3_DIVIDER,
82
+ NPCM7XX_CLOCK_SPI0_DIVIDER,
83
+ NPCM7XX_CLOCK_SPIX_DIVIDER,
84
+ NPCM7XX_CLOCK_APB1_DIVIDER,
85
+ NPCM7XX_CLOCK_APB2_DIVIDER,
86
+ NPCM7XX_CLOCK_APB3_DIVIDER,
87
+ NPCM7XX_CLOCK_APB4_DIVIDER,
88
+ NPCM7XX_CLOCK_APB5_DIVIDER,
89
+ NPCM7XX_CLOCK_CLKOUT_DIVIDER,
90
+ NPCM7XX_CLOCK_UART_DIVIDER,
91
+ NPCM7XX_CLOCK_TIMER_DIVIDER,
92
+ NPCM7XX_CLOCK_ADC_DIVIDER,
93
+ NPCM7XX_CLOCK_MMC_DIVIDER,
94
+ NPCM7XX_CLOCK_SDHC_DIVIDER,
95
+ NPCM7XX_CLOCK_GFXM_DIVIDER, /* divide by 3 */
96
+ NPCM7XX_CLOCK_UTMI_DIVIDER,
97
+ NPCM7XX_CLOCK_NR_DIVIDERS,
98
+} NPCM7xxClockConverter;
99
+
100
+typedef struct NPCM7xxCLKState NPCM7xxCLKState;
101
+
102
+/**
103
+ * struct NPCM7xxClockPLLState - A PLL module in CLK module.
104
+ * @name: The name of the module.
105
+ * @clk: The CLK module that owns this module.
106
+ * @clock_in: The input clock of this module.
107
+ * @clock_out: The output clock of this module.
108
+ * @reg: The control registers for this PLL module.
109
+ */
110
+typedef struct NPCM7xxClockPLLState {
111
+ DeviceState parent;
112
+
113
+ const char *name;
114
+ NPCM7xxCLKState *clk;
115
+ Clock *clock_in;
116
+ Clock *clock_out;
117
+
118
+ int reg;
119
+} NPCM7xxClockPLLState;
120
+
121
+/**
122
+ * struct NPCM7xxClockSELState - A SEL module in CLK module.
123
+ * @name: The name of the module.
124
+ * @clk: The CLK module that owns this module.
125
+ * @input_size: The size of inputs of this module.
126
+ * @clock_in: The input clocks of this module.
127
+ * @clock_out: The output clocks of this module.
128
+ * @offset: The offset of this module in the control register.
129
+ * @len: The length of this module in the control register.
130
+ */
131
+typedef struct NPCM7xxClockSELState {
132
+ DeviceState parent;
133
+
134
+ const char *name;
135
+ NPCM7xxCLKState *clk;
136
+ uint8_t input_size;
137
+ Clock *clock_in[NPCM7XX_CLK_SEL_MAX_INPUT];
138
+ Clock *clock_out;
139
+
140
+ int offset;
141
+ int len;
142
+} NPCM7xxClockSELState;
143
+
144
+/**
145
+ * struct NPCM7xxClockDividerState - A Divider module in CLK module.
146
+ * @name: The name of the module.
147
+ * @clk: The CLK module that owns this module.
148
+ * @clock_in: The input clock of this module.
149
+ * @clock_out: The output clock of this module.
150
+ * @divide: The function the divider uses to divide the input.
151
+ * @reg: The index of the control register that contains the divisor.
152
+ * @offset: The offset of the divisor in the control register.
153
+ * @len: The length of the divisor in the control register.
154
+ * @divisor: The divisor for a constant divisor
155
+ */
156
+typedef struct NPCM7xxClockDividerState {
157
+ DeviceState parent;
158
+
159
+ const char *name;
160
+ NPCM7xxCLKState *clk;
161
+ Clock *clock_in;
162
+ Clock *clock_out;
163
+
164
+ uint32_t (*divide)(struct NPCM7xxClockDividerState *s);
165
+ union {
166
+ struct {
167
+ int reg;
168
+ int offset;
169
+ int len;
170
+ };
171
+ int divisor;
172
+ };
173
+} NPCM7xxClockDividerState;
174
+
175
+struct NPCM7xxCLKState {
176
SysBusDevice parent;
177
178
MemoryRegion iomem;
179
180
+ /* Clock converters */
181
+ NPCM7xxClockPLLState plls[NPCM7XX_CLOCK_NR_PLLS];
182
+ NPCM7xxClockSELState sels[NPCM7XX_CLOCK_NR_SELS];
183
+ NPCM7xxClockDividerState dividers[NPCM7XX_CLOCK_NR_DIVIDERS];
184
+
185
uint32_t regs[NPCM7XX_CLK_NR_REGS];
186
187
/* Time reference for SECCNT and CNTR25M, initialized by power on reset */
188
int64_t ref_ns;
189
-} NPCM7xxCLKState;
190
+
191
+ /* The incoming reference clock. */
192
+ Clock *clkref;
193
+};
194
195
#define TYPE_NPCM7XX_CLK "npcm7xx-clk"
196
#define NPCM7XX_CLK(obj) OBJECT_CHECK(NPCM7xxCLKState, (obj), TYPE_NPCM7XX_CLK)
197
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
198
index XXXXXXX..XXXXXXX 100644
199
--- a/hw/misc/npcm7xx_clk.c
200
+++ b/hw/misc/npcm7xx_clk.c
201
@@ -XXX,XX +XXX,XX @@
202
203
#include "hw/misc/npcm7xx_clk.h"
204
#include "hw/timer/npcm7xx_timer.h"
205
+#include "hw/qdev-clock.h"
206
#include "migration/vmstate.h"
207
#include "qemu/error-report.h"
208
#include "qemu/log.h"
209
@@ -XXX,XX +XXX,XX @@
210
#include "trace.h"
211
#include "sysemu/watchdog.h"
212
213
+/*
214
+ * The reference clock hz, and the SECCNT and CNTR25M registers in this module,
215
+ * is always 25 MHz.
216
+ */
217
+#define NPCM7XX_CLOCK_REF_HZ (25000000)
218
+
219
+/* Register Field Definitions */
220
+#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
221
+
222
#define PLLCON_LOKI BIT(31)
223
#define PLLCON_LOKS BIT(30)
224
#define PLLCON_PWDEN BIT(12)
225
+#define PLLCON_FBDV(con) extract32((con), 16, 12)
226
+#define PLLCON_OTDV2(con) extract32((con), 13, 3)
227
+#define PLLCON_OTDV1(con) extract32((con), 8, 3)
228
+#define PLLCON_INDV(con) extract32((con), 0, 6)
229
230
enum NPCM7xxCLKRegisters {
231
NPCM7XX_CLK_CLKEN1,
232
@@ -XXX,XX +XXX,XX @@ static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
233
[NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
234
};
235
236
-/* Register Field Definitions */
237
-#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
238
-
239
/* The number of watchdogs that can trigger a reset. */
240
#define NPCM7XX_NR_WATCHDOGS (3)
241
242
+/* Clock converter functions */
243
+
244
+#define TYPE_NPCM7XX_CLOCK_PLL "npcm7xx-clock-pll"
245
+#define NPCM7XX_CLOCK_PLL(obj) OBJECT_CHECK(NPCM7xxClockPLLState, \
246
+ (obj), TYPE_NPCM7XX_CLOCK_PLL)
247
+#define TYPE_NPCM7XX_CLOCK_SEL "npcm7xx-clock-sel"
248
+#define NPCM7XX_CLOCK_SEL(obj) OBJECT_CHECK(NPCM7xxClockSELState, \
249
+ (obj), TYPE_NPCM7XX_CLOCK_SEL)
250
+#define TYPE_NPCM7XX_CLOCK_DIVIDER "npcm7xx-clock-divider"
251
+#define NPCM7XX_CLOCK_DIVIDER(obj) OBJECT_CHECK(NPCM7xxClockDividerState, \
252
+ (obj), TYPE_NPCM7XX_CLOCK_DIVIDER)
253
+
254
+static void npcm7xx_clk_update_pll(void *opaque)
255
+{
256
+ NPCM7xxClockPLLState *s = opaque;
257
+ uint32_t con = s->clk->regs[s->reg];
258
+ uint64_t freq;
259
+
260
+ /* The PLL is grounded if it is not locked yet. */
261
+ if (con & PLLCON_LOKI) {
262
+ freq = clock_get_hz(s->clock_in);
263
+ freq *= PLLCON_FBDV(con);
264
+ freq /= PLLCON_INDV(con) * PLLCON_OTDV1(con) * PLLCON_OTDV2(con);
265
+ } else {
266
+ freq = 0;
267
+ }
268
+
269
+ clock_update_hz(s->clock_out, freq);
270
+}
271
+
272
+static void npcm7xx_clk_update_sel(void *opaque)
273
+{
274
+ NPCM7xxClockSELState *s = opaque;
275
+ uint32_t index = extract32(s->clk->regs[NPCM7XX_CLK_CLKSEL], s->offset,
276
+ s->len);
277
+
278
+ if (index >= s->input_size) {
279
+ qemu_log_mask(LOG_GUEST_ERROR,
280
+ "%s: SEL index: %u out of range\n",
281
+ __func__, index);
282
+ index = 0;
283
+ }
284
+ clock_update_hz(s->clock_out, clock_get_hz(s->clock_in[index]));
285
+}
286
+
287
+static void npcm7xx_clk_update_divider(void *opaque)
288
+{
289
+ NPCM7xxClockDividerState *s = opaque;
290
+ uint32_t freq;
291
+
292
+ freq = s->divide(s);
293
+ clock_update_hz(s->clock_out, freq);
294
+}
295
+
296
+static uint32_t divide_by_constant(NPCM7xxClockDividerState *s)
297
+{
298
+ return clock_get_hz(s->clock_in) / s->divisor;
299
+}
300
+
301
+static uint32_t divide_by_reg_divisor(NPCM7xxClockDividerState *s)
302
+{
303
+ return clock_get_hz(s->clock_in) /
304
+ (extract32(s->clk->regs[s->reg], s->offset, s->len) + 1);
305
+}
306
+
307
+static uint32_t divide_by_reg_divisor_times_2(NPCM7xxClockDividerState *s)
308
+{
309
+ return divide_by_reg_divisor(s) / 2;
310
+}
311
+
312
+static uint32_t shift_by_reg_divisor(NPCM7xxClockDividerState *s)
313
+{
314
+ return clock_get_hz(s->clock_in) >>
315
+ extract32(s->clk->regs[s->reg], s->offset, s->len);
316
+}
317
+
318
+static NPCM7xxClockPLL find_pll_by_reg(enum NPCM7xxCLKRegisters reg)
319
+{
320
+ switch (reg) {
321
+ case NPCM7XX_CLK_PLLCON0:
322
+ return NPCM7XX_CLOCK_PLL0;
323
+ case NPCM7XX_CLK_PLLCON1:
324
+ return NPCM7XX_CLOCK_PLL1;
325
+ case NPCM7XX_CLK_PLLCON2:
326
+ return NPCM7XX_CLOCK_PLL2;
327
+ case NPCM7XX_CLK_PLLCONG:
328
+ return NPCM7XX_CLOCK_PLLG;
329
+ default:
330
+ g_assert_not_reached();
331
+ }
332
+}
333
+
334
+static void npcm7xx_clk_update_all_plls(NPCM7xxCLKState *clk)
335
+{
336
+ int i;
337
+
338
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
339
+ npcm7xx_clk_update_pll(&clk->plls[i]);
340
+ }
341
+}
342
+
343
+static void npcm7xx_clk_update_all_sels(NPCM7xxCLKState *clk)
344
+{
345
+ int i;
346
+
347
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
348
+ npcm7xx_clk_update_sel(&clk->sels[i]);
349
+ }
350
+}
351
+
352
+static void npcm7xx_clk_update_all_dividers(NPCM7xxCLKState *clk)
353
+{
354
+ int i;
355
+
356
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
357
+ npcm7xx_clk_update_divider(&clk->dividers[i]);
358
+ }
359
+}
360
+
361
+static void npcm7xx_clk_update_all_clocks(NPCM7xxCLKState *clk)
362
+{
363
+ clock_update_hz(clk->clkref, NPCM7XX_CLOCK_REF_HZ);
364
+ npcm7xx_clk_update_all_plls(clk);
365
+ npcm7xx_clk_update_all_sels(clk);
366
+ npcm7xx_clk_update_all_dividers(clk);
367
+}
368
+
369
+/* Types of clock sources. */
370
+typedef enum ClockSrcType {
371
+ CLKSRC_REF,
372
+ CLKSRC_PLL,
373
+ CLKSRC_SEL,
374
+ CLKSRC_DIV,
375
+} ClockSrcType;
376
+
377
+typedef struct PLLInitInfo {
378
+ const char *name;
379
+ ClockSrcType src_type;
380
+ int src_index;
381
+ int reg;
382
+ const char *public_name;
383
+} PLLInitInfo;
384
+
385
+typedef struct SELInitInfo {
386
+ const char *name;
387
+ uint8_t input_size;
388
+ ClockSrcType src_type[NPCM7XX_CLK_SEL_MAX_INPUT];
389
+ int src_index[NPCM7XX_CLK_SEL_MAX_INPUT];
390
+ int offset;
391
+ int len;
392
+ const char *public_name;
393
+} SELInitInfo;
394
+
395
+typedef struct DividerInitInfo {
396
+ const char *name;
397
+ ClockSrcType src_type;
398
+ int src_index;
399
+ uint32_t (*divide)(NPCM7xxClockDividerState *s);
400
+ int reg; /* not used when type == CONSTANT */
401
+ int offset; /* not used when type == CONSTANT */
402
+ int len; /* not used when type == CONSTANT */
403
+ int divisor; /* used only when type == CONSTANT */
404
+ const char *public_name;
405
+} DividerInitInfo;
406
+
407
+static const PLLInitInfo pll_init_info_list[] = {
408
+ [NPCM7XX_CLOCK_PLL0] = {
409
+ .name = "pll0",
410
+ .src_type = CLKSRC_REF,
411
+ .reg = NPCM7XX_CLK_PLLCON0,
412
+ },
413
+ [NPCM7XX_CLOCK_PLL1] = {
414
+ .name = "pll1",
415
+ .src_type = CLKSRC_REF,
416
+ .reg = NPCM7XX_CLK_PLLCON1,
417
+ },
418
+ [NPCM7XX_CLOCK_PLL2] = {
419
+ .name = "pll2",
420
+ .src_type = CLKSRC_REF,
421
+ .reg = NPCM7XX_CLK_PLLCON2,
422
+ },
423
+ [NPCM7XX_CLOCK_PLLG] = {
424
+ .name = "pllg",
425
+ .src_type = CLKSRC_REF,
426
+ .reg = NPCM7XX_CLK_PLLCONG,
427
+ },
428
+};
429
+
430
+static const SELInitInfo sel_init_info_list[] = {
431
+ [NPCM7XX_CLOCK_PIXCKSEL] = {
432
+ .name = "pixcksel",
433
+ .input_size = 2,
434
+ .src_type = {CLKSRC_PLL, CLKSRC_REF},
435
+ .src_index = {NPCM7XX_CLOCK_PLLG, 0},
436
+ .offset = 5,
437
+ .len = 1,
438
+ .public_name = "pixel-clock",
439
+ },
440
+ [NPCM7XX_CLOCK_MCCKSEL] = {
441
+ .name = "mccksel",
442
+ .input_size = 4,
443
+ .src_type = {CLKSRC_DIV, CLKSRC_REF, CLKSRC_REF,
444
+ /*MCBPCK, shouldn't be used in normal operation*/
445
+ CLKSRC_REF},
446
+ .src_index = {NPCM7XX_CLOCK_PLL1D2, 0, 0, 0},
447
+ .offset = 12,
448
+ .len = 2,
449
+ .public_name = "mc-phy-clock",
450
+ },
451
+ [NPCM7XX_CLOCK_CPUCKSEL] = {
452
+ .name = "cpucksel",
453
+ .input_size = 4,
454
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF,
455
+ /*SYSBPCK, shouldn't be used in normal operation*/
456
+ CLKSRC_REF},
457
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0, 0},
458
+ .offset = 0,
459
+ .len = 2,
460
+ .public_name = "system-clock",
461
+ },
462
+ [NPCM7XX_CLOCK_CLKOUTSEL] = {
463
+ .name = "clkoutsel",
464
+ .input_size = 5,
465
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF,
466
+ CLKSRC_PLL, CLKSRC_DIV},
467
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
468
+ NPCM7XX_CLOCK_PLLG, NPCM7XX_CLOCK_PLL2D2},
469
+ .offset = 18,
470
+ .len = 3,
471
+ .public_name = "tock",
472
+ },
473
+ [NPCM7XX_CLOCK_UARTCKSEL] = {
474
+ .name = "uartcksel",
475
+ .input_size = 4,
476
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
477
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
478
+ NPCM7XX_CLOCK_PLL2D2},
479
+ .offset = 8,
480
+ .len = 2,
481
+ },
482
+ [NPCM7XX_CLOCK_TIMCKSEL] = {
483
+ .name = "timcksel",
484
+ .input_size = 4,
485
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
486
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
487
+ NPCM7XX_CLOCK_PLL2D2},
488
+ .offset = 14,
489
+ .len = 2,
490
+ },
491
+ [NPCM7XX_CLOCK_SDCKSEL] = {
492
+ .name = "sdcksel",
493
+ .input_size = 4,
494
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
495
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
496
+ NPCM7XX_CLOCK_PLL2D2},
497
+ .offset = 6,
498
+ .len = 2,
499
+ },
500
+ [NPCM7XX_CLOCK_GFXMSEL] = {
501
+ .name = "gfxmksel",
502
+ .input_size = 2,
503
+ .src_type = {CLKSRC_REF, CLKSRC_PLL},
504
+ .src_index = {0, NPCM7XX_CLOCK_PLL2},
505
+ .offset = 21,
506
+ .len = 1,
507
+ },
508
+ [NPCM7XX_CLOCK_SUCKSEL] = {
509
+ .name = "sucksel",
510
+ .input_size = 4,
511
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
512
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
513
+ NPCM7XX_CLOCK_PLL2D2},
514
+ .offset = 10,
515
+ .len = 2,
516
+ },
517
+};
518
+
519
+static const DividerInitInfo divider_init_info_list[] = {
520
+ [NPCM7XX_CLOCK_PLL1D2] = {
521
+ .name = "pll1d2",
522
+ .src_type = CLKSRC_PLL,
523
+ .src_index = NPCM7XX_CLOCK_PLL1,
524
+ .divide = divide_by_constant,
525
+ .divisor = 2,
526
+ },
527
+ [NPCM7XX_CLOCK_PLL2D2] = {
528
+ .name = "pll2d2",
529
+ .src_type = CLKSRC_PLL,
530
+ .src_index = NPCM7XX_CLOCK_PLL2,
531
+ .divide = divide_by_constant,
532
+ .divisor = 2,
533
+ },
534
+ [NPCM7XX_CLOCK_MC_DIVIDER] = {
535
+ .name = "mc-divider",
536
+ .src_type = CLKSRC_SEL,
537
+ .src_index = NPCM7XX_CLOCK_MCCKSEL,
538
+ .divide = divide_by_constant,
539
+ .divisor = 2,
540
+ .public_name = "mc-clock"
541
+ },
542
+ [NPCM7XX_CLOCK_AXI_DIVIDER] = {
543
+ .name = "axi-divider",
544
+ .src_type = CLKSRC_SEL,
545
+ .src_index = NPCM7XX_CLOCK_CPUCKSEL,
546
+ .divide = shift_by_reg_divisor,
547
+ .reg = NPCM7XX_CLK_CLKDIV1,
548
+ .offset = 0,
549
+ .len = 1,
550
+ .public_name = "clk2"
551
+ },
552
+ [NPCM7XX_CLOCK_AHB_DIVIDER] = {
553
+ .name = "ahb-divider",
554
+ .src_type = CLKSRC_DIV,
555
+ .src_index = NPCM7XX_CLOCK_AXI_DIVIDER,
556
+ .divide = divide_by_reg_divisor,
557
+ .reg = NPCM7XX_CLK_CLKDIV1,
558
+ .offset = 26,
559
+ .len = 2,
560
+ .public_name = "clk4"
561
+ },
562
+ [NPCM7XX_CLOCK_AHB3_DIVIDER] = {
563
+ .name = "ahb3-divider",
564
+ .src_type = CLKSRC_DIV,
565
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
566
+ .divide = divide_by_reg_divisor,
567
+ .reg = NPCM7XX_CLK_CLKDIV1,
568
+ .offset = 6,
569
+ .len = 5,
570
+ .public_name = "ahb3-spi3-clock"
571
+ },
572
+ [NPCM7XX_CLOCK_SPI0_DIVIDER] = {
573
+ .name = "spi0-divider",
574
+ .src_type = CLKSRC_DIV,
575
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
576
+ .divide = divide_by_reg_divisor,
577
+ .reg = NPCM7XX_CLK_CLKDIV3,
578
+ .offset = 6,
579
+ .len = 5,
580
+ .public_name = "spi0-clock",
581
+ },
582
+ [NPCM7XX_CLOCK_SPIX_DIVIDER] = {
583
+ .name = "spix-divider",
584
+ .src_type = CLKSRC_DIV,
585
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
586
+ .divide = divide_by_reg_divisor,
587
+ .reg = NPCM7XX_CLK_CLKDIV3,
588
+ .offset = 1,
589
+ .len = 5,
590
+ .public_name = "spix-clock",
591
+ },
592
+ [NPCM7XX_CLOCK_APB1_DIVIDER] = {
593
+ .name = "apb1-divider",
594
+ .src_type = CLKSRC_DIV,
595
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
596
+ .divide = shift_by_reg_divisor,
597
+ .reg = NPCM7XX_CLK_CLKDIV2,
598
+ .offset = 24,
599
+ .len = 2,
600
+ .public_name = "apb1-clock",
601
+ },
602
+ [NPCM7XX_CLOCK_APB2_DIVIDER] = {
603
+ .name = "apb2-divider",
604
+ .src_type = CLKSRC_DIV,
605
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
606
+ .divide = shift_by_reg_divisor,
607
+ .reg = NPCM7XX_CLK_CLKDIV2,
608
+ .offset = 26,
609
+ .len = 2,
610
+ .public_name = "apb2-clock",
611
+ },
612
+ [NPCM7XX_CLOCK_APB3_DIVIDER] = {
613
+ .name = "apb3-divider",
614
+ .src_type = CLKSRC_DIV,
615
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
616
+ .divide = shift_by_reg_divisor,
617
+ .reg = NPCM7XX_CLK_CLKDIV2,
618
+ .offset = 28,
619
+ .len = 2,
620
+ .public_name = "apb3-clock",
621
+ },
622
+ [NPCM7XX_CLOCK_APB4_DIVIDER] = {
623
+ .name = "apb4-divider",
624
+ .src_type = CLKSRC_DIV,
625
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
626
+ .divide = shift_by_reg_divisor,
627
+ .reg = NPCM7XX_CLK_CLKDIV2,
628
+ .offset = 30,
629
+ .len = 2,
630
+ .public_name = "apb4-clock",
631
+ },
632
+ [NPCM7XX_CLOCK_APB5_DIVIDER] = {
633
+ .name = "apb5-divider",
634
+ .src_type = CLKSRC_DIV,
635
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
636
+ .divide = shift_by_reg_divisor,
637
+ .reg = NPCM7XX_CLK_CLKDIV2,
638
+ .offset = 22,
639
+ .len = 2,
640
+ .public_name = "apb5-clock",
641
+ },
642
+ [NPCM7XX_CLOCK_CLKOUT_DIVIDER] = {
643
+ .name = "clkout-divider",
644
+ .src_type = CLKSRC_SEL,
645
+ .src_index = NPCM7XX_CLOCK_CLKOUTSEL,
646
+ .divide = divide_by_reg_divisor,
647
+ .reg = NPCM7XX_CLK_CLKDIV2,
648
+ .offset = 16,
649
+ .len = 5,
650
+ .public_name = "clkout",
651
+ },
652
+ [NPCM7XX_CLOCK_UART_DIVIDER] = {
653
+ .name = "uart-divider",
654
+ .src_type = CLKSRC_SEL,
655
+ .src_index = NPCM7XX_CLOCK_UARTCKSEL,
656
+ .divide = divide_by_reg_divisor,
657
+ .reg = NPCM7XX_CLK_CLKDIV1,
658
+ .offset = 16,
659
+ .len = 5,
660
+ .public_name = "uart-clock",
661
+ },
662
+ [NPCM7XX_CLOCK_TIMER_DIVIDER] = {
663
+ .name = "timer-divider",
664
+ .src_type = CLKSRC_SEL,
665
+ .src_index = NPCM7XX_CLOCK_TIMCKSEL,
666
+ .divide = divide_by_reg_divisor,
667
+ .reg = NPCM7XX_CLK_CLKDIV1,
668
+ .offset = 21,
669
+ .len = 5,
670
+ .public_name = "timer-clock",
671
+ },
672
+ [NPCM7XX_CLOCK_ADC_DIVIDER] = {
673
+ .name = "adc-divider",
674
+ .src_type = CLKSRC_DIV,
675
+ .src_index = NPCM7XX_CLOCK_TIMER_DIVIDER,
676
+ .divide = shift_by_reg_divisor,
677
+ .reg = NPCM7XX_CLK_CLKDIV1,
678
+ .offset = 28,
679
+ .len = 3,
680
+ .public_name = "adc-clock",
681
+ },
682
+ [NPCM7XX_CLOCK_MMC_DIVIDER] = {
683
+ .name = "mmc-divider",
684
+ .src_type = CLKSRC_SEL,
685
+ .src_index = NPCM7XX_CLOCK_SDCKSEL,
686
+ .divide = divide_by_reg_divisor,
687
+ .reg = NPCM7XX_CLK_CLKDIV1,
688
+ .offset = 11,
689
+ .len = 5,
690
+ .public_name = "mmc-clock",
691
+ },
692
+ [NPCM7XX_CLOCK_SDHC_DIVIDER] = {
693
+ .name = "sdhc-divider",
694
+ .src_type = CLKSRC_SEL,
695
+ .src_index = NPCM7XX_CLOCK_SDCKSEL,
696
+ .divide = divide_by_reg_divisor_times_2,
697
+ .reg = NPCM7XX_CLK_CLKDIV2,
698
+ .offset = 0,
699
+ .len = 4,
700
+ .public_name = "sdhc-clock",
701
+ },
702
+ [NPCM7XX_CLOCK_GFXM_DIVIDER] = {
703
+ .name = "gfxm-divider",
704
+ .src_type = CLKSRC_SEL,
705
+ .src_index = NPCM7XX_CLOCK_GFXMSEL,
706
+ .divide = divide_by_constant,
707
+ .divisor = 3,
708
+ .public_name = "gfxm-clock",
709
+ },
710
+ [NPCM7XX_CLOCK_UTMI_DIVIDER] = {
711
+ .name = "utmi-divider",
712
+ .src_type = CLKSRC_SEL,
713
+ .src_index = NPCM7XX_CLOCK_SUCKSEL,
714
+ .divide = divide_by_reg_divisor,
715
+ .reg = NPCM7XX_CLK_CLKDIV2,
716
+ .offset = 8,
717
+ .len = 5,
718
+ .public_name = "utmi-clock",
719
+ },
720
+};
721
+
722
+static void npcm7xx_clk_pll_init(Object *obj)
723
+{
724
+ NPCM7xxClockPLLState *pll = NPCM7XX_CLOCK_PLL(obj);
725
+
726
+ pll->clock_in = qdev_init_clock_in(DEVICE(pll), "clock-in",
727
+ npcm7xx_clk_update_pll, pll);
728
+ pll->clock_out = qdev_init_clock_out(DEVICE(pll), "clock-out");
729
+}
730
+
731
+static void npcm7xx_clk_sel_init(Object *obj)
732
+{
733
+ int i;
734
+ NPCM7xxClockSELState *sel = NPCM7XX_CLOCK_SEL(obj);
735
+
736
+ for (i = 0; i < NPCM7XX_CLK_SEL_MAX_INPUT; ++i) {
737
+ sel->clock_in[i] = qdev_init_clock_in(DEVICE(sel),
738
+ g_strdup_printf("clock-in[%d]", i),
739
+ npcm7xx_clk_update_sel, sel);
740
+ }
741
+ sel->clock_out = qdev_init_clock_out(DEVICE(sel), "clock-out");
742
+}
743
+static void npcm7xx_clk_divider_init(Object *obj)
744
+{
745
+ NPCM7xxClockDividerState *div = NPCM7XX_CLOCK_DIVIDER(obj);
746
+
747
+ div->clock_in = qdev_init_clock_in(DEVICE(div), "clock-in",
748
+ npcm7xx_clk_update_divider, div);
749
+ div->clock_out = qdev_init_clock_out(DEVICE(div), "clock-out");
750
+}
751
+
752
+static void npcm7xx_init_clock_pll(NPCM7xxClockPLLState *pll,
753
+ NPCM7xxCLKState *clk, const PLLInitInfo *init_info)
754
+{
755
+ pll->name = init_info->name;
756
+ pll->clk = clk;
757
+ pll->reg = init_info->reg;
758
+ if (init_info->public_name != NULL) {
759
+ qdev_alias_clock(DEVICE(pll), "clock-out", DEVICE(clk),
760
+ init_info->public_name);
761
+ }
762
+}
763
+
764
+static void npcm7xx_init_clock_sel(NPCM7xxClockSELState *sel,
765
+ NPCM7xxCLKState *clk, const SELInitInfo *init_info)
766
+{
767
+ int input_size = init_info->input_size;
768
+
769
+ sel->name = init_info->name;
770
+ sel->clk = clk;
771
+ sel->input_size = init_info->input_size;
772
+ g_assert(input_size <= NPCM7XX_CLK_SEL_MAX_INPUT);
773
+ sel->offset = init_info->offset;
774
+ sel->len = init_info->len;
775
+ if (init_info->public_name != NULL) {
776
+ qdev_alias_clock(DEVICE(sel), "clock-out", DEVICE(clk),
777
+ init_info->public_name);
778
+ }
779
+}
780
+
781
+static void npcm7xx_init_clock_divider(NPCM7xxClockDividerState *div,
782
+ NPCM7xxCLKState *clk, const DividerInitInfo *init_info)
783
+{
784
+ div->name = init_info->name;
785
+ div->clk = clk;
786
+
787
+ div->divide = init_info->divide;
788
+ if (div->divide == divide_by_constant) {
789
+ div->divisor = init_info->divisor;
790
+ } else {
791
+ div->reg = init_info->reg;
792
+ div->offset = init_info->offset;
793
+ div->len = init_info->len;
794
+ }
795
+ if (init_info->public_name != NULL) {
796
+ qdev_alias_clock(DEVICE(div), "clock-out", DEVICE(clk),
797
+ init_info->public_name);
798
+ }
799
+}
800
+
801
+static Clock *npcm7xx_get_clock(NPCM7xxCLKState *clk, ClockSrcType type,
802
+ int index)
803
+{
804
+ switch (type) {
805
+ case CLKSRC_REF:
806
+ return clk->clkref;
807
+ case CLKSRC_PLL:
808
+ return clk->plls[index].clock_out;
809
+ case CLKSRC_SEL:
810
+ return clk->sels[index].clock_out;
811
+ case CLKSRC_DIV:
812
+ return clk->dividers[index].clock_out;
813
+ default:
814
+ g_assert_not_reached();
815
+ }
816
+}
817
+
818
+static void npcm7xx_connect_clocks(NPCM7xxCLKState *clk)
819
+{
820
+ int i, j;
821
+ Clock *src;
822
+
823
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
824
+ src = npcm7xx_get_clock(clk, pll_init_info_list[i].src_type,
825
+ pll_init_info_list[i].src_index);
826
+ clock_set_source(clk->plls[i].clock_in, src);
827
+ }
828
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
829
+ for (j = 0; j < sel_init_info_list[i].input_size; ++j) {
830
+ src = npcm7xx_get_clock(clk, sel_init_info_list[i].src_type[j],
831
+ sel_init_info_list[i].src_index[j]);
832
+ clock_set_source(clk->sels[i].clock_in[j], src);
833
+ }
834
+ }
835
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
836
+ src = npcm7xx_get_clock(clk, divider_init_info_list[i].src_type,
837
+ divider_init_info_list[i].src_index);
838
+ clock_set_source(clk->dividers[i].clock_in, src);
839
+ }
840
+}
841
+
842
static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
32
{
843
{
33
@@ -XXX,XX +XXX,XX @@ static int vae1_tlbmask(CPUARMState *env)
844
uint32_t reg = offset / sizeof(uint32_t);
845
@@ -XXX,XX +XXX,XX @@ static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
846
*
847
* The 4 LSBs are always zero: (1e9 / 640) << 4 = 25000000.
848
*/
849
- value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_TIMER_REF_HZ;
850
+ value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_CLOCK_REF_HZ;
851
break;
852
853
default:
854
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_write(void *opaque, hwaddr offset,
855
value |= (value & PLLCON_LOKS);
856
}
857
}
858
+ /* Only update PLL when it is locked. */
859
+ if (value & PLLCON_LOKI) {
860
+ npcm7xx_clk_update_pll(&s->plls[find_pll_by_reg(reg)]);
861
+ }
862
+ break;
863
+
864
+ case NPCM7XX_CLK_CLKSEL:
865
+ npcm7xx_clk_update_all_sels(s);
866
+ break;
867
+
868
+ case NPCM7XX_CLK_CLKDIV1:
869
+ case NPCM7XX_CLK_CLKDIV2:
870
+ case NPCM7XX_CLK_CLKDIV3:
871
+ npcm7xx_clk_update_all_dividers(s);
872
break;
873
874
case NPCM7XX_CLK_CNTR25M:
875
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
876
case RESET_TYPE_COLD:
877
memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
878
s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
879
+ npcm7xx_clk_update_all_clocks(s);
880
return;
34
}
881
}
882
883
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
884
__func__, type);
35
}
885
}
36
886
37
+/* Return 56 if TBI is enabled, 64 otherwise. */
887
+static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
38
+static int tlbbits_for_regime(CPUARMState *env, ARMMMUIdx mmu_idx,
888
+{
39
+ uint64_t addr)
889
+ int i;
40
+{
890
+
41
+ uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
891
+ s->clkref = qdev_init_clock_in(DEVICE(s), "clkref", NULL, NULL);
42
+ int tbi = aa64_va_parameter_tbi(tcr, mmu_idx);
892
+
43
+ int select = extract64(addr, 55, 1);
893
+ /* First pass: init all converter modules */
44
+
894
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(pll_init_info_list) != NPCM7XX_CLOCK_NR_PLLS);
45
+ return (tbi >> select) & 1 ? 56 : 64;
895
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(sel_init_info_list) != NPCM7XX_CLOCK_NR_SELS);
46
+}
896
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(divider_init_info_list)
47
+
897
+ != NPCM7XX_CLOCK_NR_DIVIDERS);
48
+static int vae1_tlbbits(CPUARMState *env, uint64_t addr)
898
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
49
+{
899
+ object_initialize_child(OBJECT(s), pll_init_info_list[i].name,
50
+ ARMMMUIdx mmu_idx;
900
+ &s->plls[i], TYPE_NPCM7XX_CLOCK_PLL);
51
+
901
+ npcm7xx_init_clock_pll(&s->plls[i], s,
52
+ /* Only the regime of the mmu_idx below is significant. */
902
+ &pll_init_info_list[i]);
53
+ if (arm_is_secure_below_el3(env)) {
903
+ }
54
+ mmu_idx = ARMMMUIdx_SE10_0;
904
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
55
+ } else if ((env->cp15.hcr_el2 & (HCR_E2H | HCR_TGE))
905
+ object_initialize_child(OBJECT(s), sel_init_info_list[i].name,
56
+ == (HCR_E2H | HCR_TGE)) {
906
+ &s->sels[i], TYPE_NPCM7XX_CLOCK_SEL);
57
+ mmu_idx = ARMMMUIdx_E20_0;
907
+ npcm7xx_init_clock_sel(&s->sels[i], s,
58
+ } else {
908
+ &sel_init_info_list[i]);
59
+ mmu_idx = ARMMMUIdx_E10_0;
909
+ }
60
+ }
910
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
61
+ return tlbbits_for_regime(env, mmu_idx, addr);
911
+ object_initialize_child(OBJECT(s), divider_init_info_list[i].name,
62
+}
912
+ &s->dividers[i], TYPE_NPCM7XX_CLOCK_DIVIDER);
63
+
913
+ npcm7xx_init_clock_divider(&s->dividers[i], s,
64
static void tlbi_aa64_vmalle1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
914
+ &divider_init_info_list[i]);
65
uint64_t value)
915
+ }
916
+
917
+ /* Second pass: connect converter modules */
918
+ npcm7xx_connect_clocks(s);
919
+
920
+ clock_update_hz(s->clkref, NPCM7XX_CLOCK_REF_HZ);
921
+}
922
+
923
static void npcm7xx_clk_init(Object *obj)
66
{
924
{
67
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vae1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
925
NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
68
CPUState *cs = env_cpu(env);
926
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
69
int mask = vae1_tlbmask(env);
927
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
70
uint64_t pageaddr = sextract64(value << 12, 0, 56);
928
TYPE_NPCM7XX_CLK, 4 * KiB);
71
+ int bits = vae1_tlbbits(env, pageaddr);
929
sysbus_init_mmio(&s->parent, &s->iomem);
72
930
- qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
73
- tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, mask);
931
- NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
74
+ tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);
75
}
932
}
76
933
77
static void tlbi_aa64_vae1_write(CPUARMState *env, const ARMCPRegInfo *ri,
934
-static const VMStateDescription vmstate_npcm7xx_clk = {
78
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vae1_write(CPUARMState *env, const ARMCPRegInfo *ri,
935
- .name = "npcm7xx-clk",
79
CPUState *cs = env_cpu(env);
936
+static int npcm7xx_clk_post_load(void *opaque, int version_id)
80
int mask = vae1_tlbmask(env);
937
+{
81
uint64_t pageaddr = sextract64(value << 12, 0, 56);
938
+ if (version_id >= 1) {
82
+ int bits = vae1_tlbbits(env, pageaddr);
939
+ NPCM7xxCLKState *clk = opaque;
83
940
+
84
if (tlb_force_broadcast(env)) {
941
+ npcm7xx_clk_update_all_clocks(clk);
85
- tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, mask);
942
+ }
86
+ tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);
943
+
87
} else {
944
+ return 0;
88
- tlb_flush_page_by_mmuidx(cs, pageaddr, mask);
945
+}
89
+ tlb_flush_page_bits_by_mmuidx(cs, pageaddr, mask, bits);
946
+
90
}
947
+static void npcm7xx_clk_realize(DeviceState *dev, Error **errp)
948
+{
949
+ int i;
950
+ NPCM7xxCLKState *s = NPCM7XX_CLK(dev);
951
+
952
+ qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
953
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
954
+ npcm7xx_clk_init_clock_hierarchy(s);
955
+
956
+ /* Realize child devices */
957
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
958
+ if (!qdev_realize(DEVICE(&s->plls[i]), NULL, errp)) {
959
+ return;
960
+ }
961
+ }
962
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
963
+ if (!qdev_realize(DEVICE(&s->sels[i]), NULL, errp)) {
964
+ return;
965
+ }
966
+ }
967
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
968
+ if (!qdev_realize(DEVICE(&s->dividers[i]), NULL, errp)) {
969
+ return;
970
+ }
971
+ }
972
+}
973
+
974
+static const VMStateDescription vmstate_npcm7xx_clk_pll = {
975
+ .name = "npcm7xx-clock-pll",
976
.version_id = 0,
977
.minimum_version_id = 0,
978
- .fields = (VMStateField[]) {
979
- VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS),
980
- VMSTATE_INT64(ref_ns, NPCM7xxCLKState),
981
+ .fields = (VMStateField[]) {
982
+ VMSTATE_CLOCK(clock_in, NPCM7xxClockPLLState),
983
VMSTATE_END_OF_LIST(),
984
},
985
};
986
987
+static const VMStateDescription vmstate_npcm7xx_clk_sel = {
988
+ .name = "npcm7xx-clock-sel",
989
+ .version_id = 0,
990
+ .minimum_version_id = 0,
991
+ .fields = (VMStateField[]) {
992
+ VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(clock_in, NPCM7xxClockSELState,
993
+ NPCM7XX_CLK_SEL_MAX_INPUT, 0, vmstate_clock, Clock),
994
+ VMSTATE_END_OF_LIST(),
995
+ },
996
+};
997
+
998
+static const VMStateDescription vmstate_npcm7xx_clk_divider = {
999
+ .name = "npcm7xx-clock-divider",
1000
+ .version_id = 0,
1001
+ .minimum_version_id = 0,
1002
+ .fields = (VMStateField[]) {
1003
+ VMSTATE_CLOCK(clock_in, NPCM7xxClockDividerState),
1004
+ VMSTATE_END_OF_LIST(),
1005
+ },
1006
+};
1007
+
1008
+static const VMStateDescription vmstate_npcm7xx_clk = {
1009
+ .name = "npcm7xx-clk",
1010
+ .version_id = 1,
1011
+ .minimum_version_id = 1,
1012
+ .post_load = npcm7xx_clk_post_load,
1013
+ .fields = (VMStateField[]) {
1014
+ VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS),
1015
+ VMSTATE_INT64(ref_ns, NPCM7xxCLKState),
1016
+ VMSTATE_CLOCK(clkref, NPCM7xxCLKState),
1017
+ VMSTATE_END_OF_LIST(),
1018
+ },
1019
+};
1020
+
1021
+static void npcm7xx_clk_pll_class_init(ObjectClass *klass, void *data)
1022
+{
1023
+ DeviceClass *dc = DEVICE_CLASS(klass);
1024
+
1025
+ dc->desc = "NPCM7xx Clock PLL Module";
1026
+ dc->vmsd = &vmstate_npcm7xx_clk_pll;
1027
+}
1028
+
1029
+static void npcm7xx_clk_sel_class_init(ObjectClass *klass, void *data)
1030
+{
1031
+ DeviceClass *dc = DEVICE_CLASS(klass);
1032
+
1033
+ dc->desc = "NPCM7xx Clock SEL Module";
1034
+ dc->vmsd = &vmstate_npcm7xx_clk_sel;
1035
+}
1036
+
1037
+static void npcm7xx_clk_divider_class_init(ObjectClass *klass, void *data)
1038
+{
1039
+ DeviceClass *dc = DEVICE_CLASS(klass);
1040
+
1041
+ dc->desc = "NPCM7xx Clock Divider Module";
1042
+ dc->vmsd = &vmstate_npcm7xx_clk_divider;
1043
+}
1044
+
1045
static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
1046
{
1047
ResettableClass *rc = RESETTABLE_CLASS(klass);
1048
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
1049
1050
dc->desc = "NPCM7xx Clock Control Registers";
1051
dc->vmsd = &vmstate_npcm7xx_clk;
1052
+ dc->realize = npcm7xx_clk_realize;
1053
rc->phases.enter = npcm7xx_clk_enter_reset;
91
}
1054
}
92
1055
93
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri,
1056
+static const TypeInfo npcm7xx_clk_pll_info = {
1057
+ .name = TYPE_NPCM7XX_CLOCK_PLL,
1058
+ .parent = TYPE_DEVICE,
1059
+ .instance_size = sizeof(NPCM7xxClockPLLState),
1060
+ .instance_init = npcm7xx_clk_pll_init,
1061
+ .class_init = npcm7xx_clk_pll_class_init,
1062
+};
1063
+
1064
+static const TypeInfo npcm7xx_clk_sel_info = {
1065
+ .name = TYPE_NPCM7XX_CLOCK_SEL,
1066
+ .parent = TYPE_DEVICE,
1067
+ .instance_size = sizeof(NPCM7xxClockSELState),
1068
+ .instance_init = npcm7xx_clk_sel_init,
1069
+ .class_init = npcm7xx_clk_sel_class_init,
1070
+};
1071
+
1072
+static const TypeInfo npcm7xx_clk_divider_info = {
1073
+ .name = TYPE_NPCM7XX_CLOCK_DIVIDER,
1074
+ .parent = TYPE_DEVICE,
1075
+ .instance_size = sizeof(NPCM7xxClockDividerState),
1076
+ .instance_init = npcm7xx_clk_divider_init,
1077
+ .class_init = npcm7xx_clk_divider_class_init,
1078
+};
1079
+
1080
static const TypeInfo npcm7xx_clk_info = {
1081
.name = TYPE_NPCM7XX_CLK,
1082
.parent = TYPE_SYS_BUS_DEVICE,
1083
@@ -XXX,XX +XXX,XX @@ static const TypeInfo npcm7xx_clk_info = {
1084
1085
static void npcm7xx_clk_register_type(void)
94
{
1086
{
95
CPUState *cs = env_cpu(env);
1087
+ type_register_static(&npcm7xx_clk_pll_info);
96
uint64_t pageaddr = sextract64(value << 12, 0, 56);
1088
+ type_register_static(&npcm7xx_clk_sel_info);
97
+ int bits = tlbbits_for_regime(env, ARMMMUIdx_E2, pageaddr);
1089
+ type_register_static(&npcm7xx_clk_divider_info);
98
1090
type_register_static(&npcm7xx_clk_info);
99
- tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr,
100
- ARMMMUIdxBit_E2);
101
+ tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr,
102
+ ARMMMUIdxBit_E2, bits);
103
}
1091
}
104
1092
type_init(npcm7xx_clk_register_type);
105
static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
106
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
107
{
108
CPUState *cs = env_cpu(env);
109
uint64_t pageaddr = sextract64(value << 12, 0, 56);
110
+ int bits = tlbbits_for_regime(env, ARMMMUIdx_SE3, pageaddr);
111
112
- tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr,
113
- ARMMMUIdxBit_SE3);
114
+ tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr,
115
+ ARMMMUIdxBit_SE3, bits);
116
}
117
118
static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri,
119
--
1093
--
120
2.20.1
1094
2.20.1
121
1095
122
1096
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
The IRQ values are defined few lines earlier, use them instead of
3
This patch makes NPCM7XX Timer to use a the timer clock generated by the
4
the magic numbers.
4
CLK module instead of the magic number TIMER_REF_HZ.
5
5
6
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
7
Message-id: 20201017180731.1165871-3-f4bug@amsat.org
7
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
8
Signed-off-by: Hao Wu <wuhaotsh@google.com>
9
Message-id: 20210108190945.949196-3-wuhaotsh@google.com
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
12
---
11
hw/intc/bcm2836_control.c | 8 ++++----
13
include/hw/misc/npcm7xx_clk.h | 6 -----
12
1 file changed, 4 insertions(+), 4 deletions(-)
14
include/hw/timer/npcm7xx_timer.h | 1 +
15
hw/arm/npcm7xx.c | 5 ++++
16
hw/timer/npcm7xx_timer.c | 39 +++++++++++++++-----------------
17
4 files changed, 24 insertions(+), 27 deletions(-)
13
18
14
diff --git a/hw/intc/bcm2836_control.c b/hw/intc/bcm2836_control.c
19
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
15
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/intc/bcm2836_control.c
21
--- a/include/hw/misc/npcm7xx_clk.h
17
+++ b/hw/intc/bcm2836_control.c
22
+++ b/include/hw/misc/npcm7xx_clk.h
18
@@ -XXX,XX +XXX,XX @@ static void bcm2836_control_set_local_irq(void *opaque, int core, int local_irq,
23
@@ -XXX,XX +XXX,XX @@
19
24
#include "hw/clock.h"
20
static void bcm2836_control_set_local_irq0(void *opaque, int core, int level)
25
#include "hw/sysbus.h"
26
27
-/*
28
- * The reference clock frequency for the timer modules, and the SECCNT and
29
- * CNTR25M registers in this module, is always 25 MHz.
30
- */
31
-#define NPCM7XX_TIMER_REF_HZ (25000000)
32
-
33
/*
34
* Number of registers in our device state structure. Don't change this without
35
* incrementing the version_id in the vmstate.
36
diff --git a/include/hw/timer/npcm7xx_timer.h b/include/hw/timer/npcm7xx_timer.h
37
index XXXXXXX..XXXXXXX 100644
38
--- a/include/hw/timer/npcm7xx_timer.h
39
+++ b/include/hw/timer/npcm7xx_timer.h
40
@@ -XXX,XX +XXX,XX @@ struct NPCM7xxTimerCtrlState {
41
42
uint32_t tisr;
43
44
+ Clock *clock;
45
NPCM7xxTimer timer[NPCM7XX_TIMERS_PER_CTRL];
46
NPCM7xxWatchdogTimer watchdog_timer;
47
};
48
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/hw/arm/npcm7xx.c
51
+++ b/hw/arm/npcm7xx.c
52
@@ -XXX,XX +XXX,XX @@
53
#include "hw/char/serial.h"
54
#include "hw/loader.h"
55
#include "hw/misc/unimp.h"
56
+#include "hw/qdev-clock.h"
57
#include "hw/qdev-properties.h"
58
#include "qapi/error.h"
59
#include "qemu/units.h"
60
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
61
int first_irq;
62
int j;
63
64
+ /* Connect the timer clock. */
65
+ qdev_connect_clock_in(DEVICE(&s->tim[i]), "clock", qdev_get_clock_out(
66
+ DEVICE(&s->clk), "timer-clock"));
67
+
68
sysbus_realize(sbd, &error_abort);
69
sysbus_mmio_map(sbd, 0, npcm7xx_tim_addr[i]);
70
71
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
72
index XXXXXXX..XXXXXXX 100644
73
--- a/hw/timer/npcm7xx_timer.c
74
+++ b/hw/timer/npcm7xx_timer.c
75
@@ -XXX,XX +XXX,XX @@
76
#include "qemu/osdep.h"
77
78
#include "hw/irq.h"
79
+#include "hw/qdev-clock.h"
80
#include "hw/qdev-properties.h"
81
-#include "hw/misc/npcm7xx_clk.h"
82
#include "hw/timer/npcm7xx_timer.h"
83
#include "migration/vmstate.h"
84
#include "qemu/bitops.h"
85
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_tcsr_prescaler(uint32_t tcsr)
86
/* Convert a timer cycle count to a time interval in nanoseconds. */
87
static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count)
21
{
88
{
22
- bcm2836_control_set_local_irq(opaque, core, 0, level);
89
- int64_t ns = count;
23
+ bcm2836_control_set_local_irq(opaque, core, IRQ_CNTPSIRQ, level);
90
+ int64_t ticks = count;
91
92
- ns *= NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ;
93
- ns *= npcm7xx_tcsr_prescaler(t->tcsr);
94
+ ticks *= npcm7xx_tcsr_prescaler(t->tcsr);
95
96
- return ns;
97
+ return clock_ticks_to_ns(t->ctrl->clock, ticks);
24
}
98
}
25
99
26
static void bcm2836_control_set_local_irq1(void *opaque, int core, int level)
100
/* Convert a time interval in nanoseconds to a timer cycle count. */
101
static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
27
{
102
{
28
- bcm2836_control_set_local_irq(opaque, core, 1, level);
103
- int64_t count;
29
+ bcm2836_control_set_local_irq(opaque, core, IRQ_CNTPNSIRQ, level);
104
-
105
- count = ns / (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ);
106
- count /= npcm7xx_tcsr_prescaler(t->tcsr);
107
-
108
- return count;
109
+ return ns / clock_ticks_to_ns(t->ctrl->clock,
110
+ npcm7xx_tcsr_prescaler(t->tcsr));
30
}
111
}
31
112
32
static void bcm2836_control_set_local_irq2(void *opaque, int core, int level)
113
static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
114
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
115
static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
116
int64_t cycles)
33
{
117
{
34
- bcm2836_control_set_local_irq(opaque, core, 2, level);
118
- uint32_t prescaler = npcm7xx_watchdog_timer_prescaler(t);
35
+ bcm2836_control_set_local_irq(opaque, core, IRQ_CNTHPIRQ, level);
119
- int64_t ns = (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ) * cycles;
120
+ int64_t ticks = cycles * npcm7xx_watchdog_timer_prescaler(t);
121
+ int64_t ns = clock_ticks_to_ns(t->ctrl->clock, ticks);
122
123
/*
124
* The reset function always clears the current timer. The caller of the
125
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
126
*/
127
npcm7xx_timer_clear(&t->base_timer);
128
129
- ns *= prescaler;
130
t->base_timer.remaining_ns = ns;
36
}
131
}
37
132
38
static void bcm2836_control_set_local_irq3(void *opaque, int core, int level)
133
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_hold_reset(Object *obj)
134
qemu_irq_lower(s->watchdog_timer.irq);
135
}
136
137
-static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
138
+static void npcm7xx_timer_init(Object *obj)
39
{
139
{
40
- bcm2836_control_set_local_irq(opaque, core, 3, level);
140
- NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev);
41
+ bcm2836_control_set_local_irq(opaque, core, IRQ_CNTVIRQ, level);
141
- SysBusDevice *sbd = &s->parent;
142
+ NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj);
143
+ DeviceState *dev = DEVICE(obj);
144
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
145
int i;
146
NPCM7xxWatchdogTimer *w;
147
148
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
149
npcm7xx_watchdog_timer_expired, w);
150
sysbus_init_irq(sbd, &w->irq);
151
152
- memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_timer_ops, s,
153
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_timer_ops, s,
154
TYPE_NPCM7XX_TIMER, 4 * KiB);
155
sysbus_init_mmio(sbd, &s->iomem);
156
qdev_init_gpio_out_named(dev, &w->reset_signal,
157
NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 1);
158
+ s->clock = qdev_init_clock_in(dev, "clock", NULL, NULL);
42
}
159
}
43
160
44
static void bcm2836_control_set_gpu_irq(void *opaque, int irq, int level)
161
static const VMStateDescription vmstate_npcm7xx_base_timer = {
162
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_npcm7xx_watchdog_timer = {
163
164
static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
165
.name = "npcm7xx-timer-ctrl",
166
- .version_id = 1,
167
- .minimum_version_id = 1,
168
+ .version_id = 2,
169
+ .minimum_version_id = 2,
170
.fields = (VMStateField[]) {
171
VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState),
172
+ VMSTATE_CLOCK(clock, NPCM7xxTimerCtrlState),
173
VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState,
174
NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer,
175
NPCM7xxTimer),
176
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_class_init(ObjectClass *klass, void *data)
177
QEMU_BUILD_BUG_ON(NPCM7XX_TIMER_REGS_END > NPCM7XX_TIMER_NR_REGS);
178
179
dc->desc = "NPCM7xx Timer Controller";
180
- dc->realize = npcm7xx_timer_realize;
181
dc->vmsd = &vmstate_npcm7xx_timer_ctrl;
182
rc->phases.enter = npcm7xx_timer_enter_reset;
183
rc->phases.hold = npcm7xx_timer_hold_reset;
184
@@ -XXX,XX +XXX,XX @@ static const TypeInfo npcm7xx_timer_info = {
185
.parent = TYPE_SYS_BUS_DEVICE,
186
.instance_size = sizeof(NPCM7xxTimerCtrlState),
187
.class_init = npcm7xx_timer_class_init,
188
+ .instance_init = npcm7xx_timer_init,
189
};
190
191
static void npcm7xx_timer_register_type(void)
45
--
192
--
46
2.20.1
193
2.20.1
47
194
48
195
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
On ARM, the Top Byte Ignore feature means that only 56 bits of
3
The ADC is part of NPCM7XX Module. Its behavior is controled by the
4
the address are significant in the virtual address. We are
4
ADC_CON register. It converts one of the eight analog inputs into a
5
required to give the entire 64-bit address to FAR_ELx on fault,
5
digital input and stores it in the ADC_DATA register when enabled.
6
which means that we do not "clean" the top byte early in TCG.
7
6
8
This new interface allows us to flush all 256 possible aliases
7
Users can alter input value by using qom-set QMP command.
9
for a given page, currently missed by tlb_flush_page*.
10
8
11
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
12
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
11
Signed-off-by: Hao Wu <wuhaotsh@google.com>
12
Message-id: 20210108190945.949196-4-wuhaotsh@google.com
13
[PMM: Added missing hw/adc/trace.h file]
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Message-id: 20201016210754.818257-2-richard.henderson@linaro.org
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
16
---
17
include/exec/exec-all.h | 36 ++++++
17
docs/system/arm/nuvoton.rst | 2 +-
18
accel/tcg/cputlb.c | 275 ++++++++++++++++++++++++++++++++++++++--
18
meson.build | 1 +
19
2 files changed, 302 insertions(+), 9 deletions(-)
19
hw/adc/trace.h | 1 +
20
include/hw/adc/npcm7xx_adc.h | 69 ++++++
21
include/hw/arm/npcm7xx.h | 2 +
22
hw/adc/npcm7xx_adc.c | 301 ++++++++++++++++++++++++++
23
hw/arm/npcm7xx.c | 24 ++-
24
tests/qtest/npcm7xx_adc-test.c | 377 +++++++++++++++++++++++++++++++++
25
hw/adc/meson.build | 1 +
26
hw/adc/trace-events | 5 +
27
tests/qtest/meson.build | 3 +-
28
11 files changed, 783 insertions(+), 3 deletions(-)
29
create mode 100644 hw/adc/trace.h
30
create mode 100644 include/hw/adc/npcm7xx_adc.h
31
create mode 100644 hw/adc/npcm7xx_adc.c
32
create mode 100644 tests/qtest/npcm7xx_adc-test.c
33
create mode 100644 hw/adc/trace-events
20
34
21
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
35
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
22
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
23
--- a/include/exec/exec-all.h
37
--- a/docs/system/arm/nuvoton.rst
24
+++ b/include/exec/exec-all.h
38
+++ b/docs/system/arm/nuvoton.rst
25
@@ -XXX,XX +XXX,XX @@ void tlb_flush_by_mmuidx_all_cpus(CPUState *cpu, uint16_t idxmap);
39
@@ -XXX,XX +XXX,XX @@ Supported devices
26
* depend on when the guests translation ends the TB.
40
* Random Number Generator (RNG)
41
* USB host (USBH)
42
* GPIO controller
43
+ * Analog to Digital Converter (ADC)
44
45
Missing devices
46
---------------
47
@@ -XXX,XX +XXX,XX @@ Missing devices
48
* USB device (USBD)
49
* SMBus controller (SMBF)
50
* Peripheral SPI controller (PSPI)
51
- * Analog to Digital Converter (ADC)
52
* SD/MMC host
53
* PECI interface
54
* Pulse Width Modulation (PWM)
55
diff --git a/meson.build b/meson.build
56
index XXXXXXX..XXXXXXX 100644
57
--- a/meson.build
58
+++ b/meson.build
59
@@ -XXX,XX +XXX,XX @@ if have_system
60
'chardev',
61
'hw/9pfs',
62
'hw/acpi',
63
+ 'hw/adc',
64
'hw/alpha',
65
'hw/arm',
66
'hw/audio',
67
diff --git a/hw/adc/trace.h b/hw/adc/trace.h
68
new file mode 100644
69
index XXXXXXX..XXXXXXX
70
--- /dev/null
71
+++ b/hw/adc/trace.h
72
@@ -0,0 +1 @@
73
+#include "trace/trace-hw_adc.h"
74
diff --git a/include/hw/adc/npcm7xx_adc.h b/include/hw/adc/npcm7xx_adc.h
75
new file mode 100644
76
index XXXXXXX..XXXXXXX
77
--- /dev/null
78
+++ b/include/hw/adc/npcm7xx_adc.h
79
@@ -XXX,XX +XXX,XX @@
80
+/*
81
+ * Nuvoton NPCM7xx ADC Module
82
+ *
83
+ * Copyright 2020 Google LLC
84
+ *
85
+ * This program is free software; you can redistribute it and/or modify it
86
+ * under the terms of the GNU General Public License as published by the
87
+ * Free Software Foundation; either version 2 of the License, or
88
+ * (at your option) any later version.
89
+ *
90
+ * This program is distributed in the hope that it will be useful, but WITHOUT
91
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
92
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
93
+ * for more details.
94
+ */
95
+#ifndef NPCM7XX_ADC_H
96
+#define NPCM7XX_ADC_H
97
+
98
+#include "hw/clock.h"
99
+#include "hw/irq.h"
100
+#include "hw/sysbus.h"
101
+#include "qemu/timer.h"
102
+
103
+#define NPCM7XX_ADC_NUM_INPUTS 8
104
+/**
105
+ * This value should not be changed unless write_adc_calibration function in
106
+ * hw/arm/npcm7xx.c is also changed.
107
+ */
108
+#define NPCM7XX_ADC_NUM_CALIB 2
109
+
110
+/**
111
+ * struct NPCM7xxADCState - Analog to Digital Converter Module device state.
112
+ * @parent: System bus device.
113
+ * @iomem: Memory region through which registers are accessed.
114
+ * @conv_timer: The timer counts down remaining cycles for the conversion.
115
+ * @irq: GIC interrupt line to fire on expiration (if enabled).
116
+ * @con: The Control Register.
117
+ * @data: The Data Buffer.
118
+ * @clock: The ADC Clock.
119
+ * @adci: The input voltage in units of uV. 1uv = 1e-6V.
120
+ * @vref: The external reference voltage.
121
+ * @iref: The internal reference voltage, initialized at launch time.
122
+ * @rv: The calibrated output values of 0.5V and 1.5V for the ADC.
123
+ */
124
+typedef struct {
125
+ SysBusDevice parent;
126
+
127
+ MemoryRegion iomem;
128
+
129
+ QEMUTimer conv_timer;
130
+
131
+ qemu_irq irq;
132
+ uint32_t con;
133
+ uint32_t data;
134
+ Clock *clock;
135
+
136
+ /* Voltages are in unit of uV. 1V = 1000000uV. */
137
+ uint32_t adci[NPCM7XX_ADC_NUM_INPUTS];
138
+ uint32_t vref;
139
+ uint32_t iref;
140
+
141
+ uint16_t calibration_r_values[NPCM7XX_ADC_NUM_CALIB];
142
+} NPCM7xxADCState;
143
+
144
+#define TYPE_NPCM7XX_ADC "npcm7xx-adc"
145
+#define NPCM7XX_ADC(obj) \
146
+ OBJECT_CHECK(NPCM7xxADCState, (obj), TYPE_NPCM7XX_ADC)
147
+
148
+#endif /* NPCM7XX_ADC_H */
149
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
150
index XXXXXXX..XXXXXXX 100644
151
--- a/include/hw/arm/npcm7xx.h
152
+++ b/include/hw/arm/npcm7xx.h
153
@@ -XXX,XX +XXX,XX @@
154
#define NPCM7XX_H
155
156
#include "hw/boards.h"
157
+#include "hw/adc/npcm7xx_adc.h"
158
#include "hw/cpu/a9mpcore.h"
159
#include "hw/gpio/npcm7xx_gpio.h"
160
#include "hw/mem/npcm7xx_mc.h"
161
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
162
NPCM7xxGCRState gcr;
163
NPCM7xxCLKState clk;
164
NPCM7xxTimerCtrlState tim[3];
165
+ NPCM7xxADCState adc;
166
NPCM7xxOTPState key_storage;
167
NPCM7xxOTPState fuse_array;
168
NPCM7xxMCState mc;
169
diff --git a/hw/adc/npcm7xx_adc.c b/hw/adc/npcm7xx_adc.c
170
new file mode 100644
171
index XXXXXXX..XXXXXXX
172
--- /dev/null
173
+++ b/hw/adc/npcm7xx_adc.c
174
@@ -XXX,XX +XXX,XX @@
175
+/*
176
+ * Nuvoton NPCM7xx ADC Module
177
+ *
178
+ * Copyright 2020 Google LLC
179
+ *
180
+ * This program is free software; you can redistribute it and/or modify it
181
+ * under the terms of the GNU General Public License as published by the
182
+ * Free Software Foundation; either version 2 of the License, or
183
+ * (at your option) any later version.
184
+ *
185
+ * This program is distributed in the hope that it will be useful, but WITHOUT
186
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
187
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
188
+ * for more details.
189
+ */
190
+
191
+#include "qemu/osdep.h"
192
+#include "hw/adc/npcm7xx_adc.h"
193
+#include "hw/qdev-clock.h"
194
+#include "hw/qdev-properties.h"
195
+#include "hw/registerfields.h"
196
+#include "migration/vmstate.h"
197
+#include "qemu/log.h"
198
+#include "qemu/module.h"
199
+#include "qemu/timer.h"
200
+#include "qemu/units.h"
201
+#include "trace.h"
202
+
203
+REG32(NPCM7XX_ADC_CON, 0x0)
204
+REG32(NPCM7XX_ADC_DATA, 0x4)
205
+
206
+/* Register field definitions. */
207
+#define NPCM7XX_ADC_CON_MUX(rv) extract32(rv, 24, 4)
208
+#define NPCM7XX_ADC_CON_INT_EN BIT(21)
209
+#define NPCM7XX_ADC_CON_REFSEL BIT(19)
210
+#define NPCM7XX_ADC_CON_INT BIT(18)
211
+#define NPCM7XX_ADC_CON_EN BIT(17)
212
+#define NPCM7XX_ADC_CON_RST BIT(16)
213
+#define NPCM7XX_ADC_CON_CONV BIT(14)
214
+#define NPCM7XX_ADC_CON_DIV(rv) extract32(rv, 1, 8)
215
+
216
+#define NPCM7XX_ADC_MAX_RESULT 1023
217
+#define NPCM7XX_ADC_DEFAULT_IREF 2000000
218
+#define NPCM7XX_ADC_CONV_CYCLES 20
219
+#define NPCM7XX_ADC_RESET_CYCLES 10
220
+#define NPCM7XX_ADC_R0_INPUT 500000
221
+#define NPCM7XX_ADC_R1_INPUT 1500000
222
+
223
+static void npcm7xx_adc_reset(NPCM7xxADCState *s)
224
+{
225
+ timer_del(&s->conv_timer);
226
+ s->con = 0x000c0001;
227
+ s->data = 0x00000000;
228
+}
229
+
230
+static uint32_t npcm7xx_adc_convert(uint32_t input, uint32_t ref)
231
+{
232
+ uint32_t result;
233
+
234
+ result = input * (NPCM7XX_ADC_MAX_RESULT + 1) / ref;
235
+ if (result > NPCM7XX_ADC_MAX_RESULT) {
236
+ result = NPCM7XX_ADC_MAX_RESULT;
237
+ }
238
+
239
+ return result;
240
+}
241
+
242
+static uint32_t npcm7xx_adc_prescaler(NPCM7xxADCState *s)
243
+{
244
+ return 2 * (NPCM7XX_ADC_CON_DIV(s->con) + 1);
245
+}
246
+
247
+static void npcm7xx_adc_start_timer(Clock *clk, QEMUTimer *timer,
248
+ uint32_t cycles, uint32_t prescaler)
249
+{
250
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
251
+ int64_t ticks = cycles;
252
+ int64_t ns;
253
+
254
+ ticks *= prescaler;
255
+ ns = clock_ticks_to_ns(clk, ticks);
256
+ ns += now;
257
+ timer_mod(timer, ns);
258
+}
259
+
260
+static void npcm7xx_adc_start_convert(NPCM7xxADCState *s)
261
+{
262
+ uint32_t prescaler = npcm7xx_adc_prescaler(s);
263
+
264
+ npcm7xx_adc_start_timer(s->clock, &s->conv_timer, NPCM7XX_ADC_CONV_CYCLES,
265
+ prescaler);
266
+}
267
+
268
+static void npcm7xx_adc_convert_done(void *opaque)
269
+{
270
+ NPCM7xxADCState *s = opaque;
271
+ uint32_t input = NPCM7XX_ADC_CON_MUX(s->con);
272
+ uint32_t ref = (s->con & NPCM7XX_ADC_CON_REFSEL)
273
+ ? s->iref : s->vref;
274
+
275
+ if (input >= NPCM7XX_ADC_NUM_INPUTS) {
276
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid input: %u\n",
277
+ __func__, input);
278
+ return;
279
+ }
280
+ s->data = npcm7xx_adc_convert(s->adci[input], ref);
281
+ if (s->con & NPCM7XX_ADC_CON_INT_EN) {
282
+ s->con |= NPCM7XX_ADC_CON_INT;
283
+ qemu_irq_raise(s->irq);
284
+ }
285
+ s->con &= ~NPCM7XX_ADC_CON_CONV;
286
+}
287
+
288
+static void npcm7xx_adc_calibrate(NPCM7xxADCState *adc)
289
+{
290
+ adc->calibration_r_values[0] = npcm7xx_adc_convert(NPCM7XX_ADC_R0_INPUT,
291
+ adc->iref);
292
+ adc->calibration_r_values[1] = npcm7xx_adc_convert(NPCM7XX_ADC_R1_INPUT,
293
+ adc->iref);
294
+}
295
+
296
+static void npcm7xx_adc_write_con(NPCM7xxADCState *s, uint32_t new_con)
297
+{
298
+ uint32_t old_con = s->con;
299
+
300
+ /* Write ADC_INT to 1 to clear it */
301
+ if (new_con & NPCM7XX_ADC_CON_INT) {
302
+ new_con &= ~NPCM7XX_ADC_CON_INT;
303
+ qemu_irq_lower(s->irq);
304
+ } else if (old_con & NPCM7XX_ADC_CON_INT) {
305
+ new_con |= NPCM7XX_ADC_CON_INT;
306
+ }
307
+
308
+ s->con = new_con;
309
+
310
+ if (s->con & NPCM7XX_ADC_CON_RST) {
311
+ npcm7xx_adc_reset(s);
312
+ return;
313
+ }
314
+
315
+ if ((s->con & NPCM7XX_ADC_CON_EN)) {
316
+ if (s->con & NPCM7XX_ADC_CON_CONV) {
317
+ if (!(old_con & NPCM7XX_ADC_CON_CONV)) {
318
+ npcm7xx_adc_start_convert(s);
319
+ }
320
+ } else {
321
+ timer_del(&s->conv_timer);
322
+ }
323
+ }
324
+}
325
+
326
+static uint64_t npcm7xx_adc_read(void *opaque, hwaddr offset, unsigned size)
327
+{
328
+ uint64_t value = 0;
329
+ NPCM7xxADCState *s = opaque;
330
+
331
+ switch (offset) {
332
+ case A_NPCM7XX_ADC_CON:
333
+ value = s->con;
334
+ break;
335
+
336
+ case A_NPCM7XX_ADC_DATA:
337
+ value = s->data;
338
+ break;
339
+
340
+ default:
341
+ qemu_log_mask(LOG_GUEST_ERROR,
342
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
343
+ __func__, offset);
344
+ break;
345
+ }
346
+
347
+ trace_npcm7xx_adc_read(DEVICE(s)->canonical_path, offset, value);
348
+ return value;
349
+}
350
+
351
+static void npcm7xx_adc_write(void *opaque, hwaddr offset, uint64_t v,
352
+ unsigned size)
353
+{
354
+ NPCM7xxADCState *s = opaque;
355
+
356
+ trace_npcm7xx_adc_write(DEVICE(s)->canonical_path, offset, v);
357
+ switch (offset) {
358
+ case A_NPCM7XX_ADC_CON:
359
+ npcm7xx_adc_write_con(s, v);
360
+ break;
361
+
362
+ case A_NPCM7XX_ADC_DATA:
363
+ qemu_log_mask(LOG_GUEST_ERROR,
364
+ "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
365
+ __func__, offset);
366
+ break;
367
+
368
+ default:
369
+ qemu_log_mask(LOG_GUEST_ERROR,
370
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
371
+ __func__, offset);
372
+ break;
373
+ }
374
+
375
+}
376
+
377
+static const struct MemoryRegionOps npcm7xx_adc_ops = {
378
+ .read = npcm7xx_adc_read,
379
+ .write = npcm7xx_adc_write,
380
+ .endianness = DEVICE_LITTLE_ENDIAN,
381
+ .valid = {
382
+ .min_access_size = 4,
383
+ .max_access_size = 4,
384
+ .unaligned = false,
385
+ },
386
+};
387
+
388
+static void npcm7xx_adc_enter_reset(Object *obj, ResetType type)
389
+{
390
+ NPCM7xxADCState *s = NPCM7XX_ADC(obj);
391
+
392
+ npcm7xx_adc_reset(s);
393
+}
394
+
395
+static void npcm7xx_adc_hold_reset(Object *obj)
396
+{
397
+ NPCM7xxADCState *s = NPCM7XX_ADC(obj);
398
+
399
+ qemu_irq_lower(s->irq);
400
+}
401
+
402
+static void npcm7xx_adc_init(Object *obj)
403
+{
404
+ NPCM7xxADCState *s = NPCM7XX_ADC(obj);
405
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
406
+ int i;
407
+
408
+ sysbus_init_irq(sbd, &s->irq);
409
+
410
+ timer_init_ns(&s->conv_timer, QEMU_CLOCK_VIRTUAL,
411
+ npcm7xx_adc_convert_done, s);
412
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_adc_ops, s,
413
+ TYPE_NPCM7XX_ADC, 4 * KiB);
414
+ sysbus_init_mmio(sbd, &s->iomem);
415
+ s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
416
+
417
+ for (i = 0; i < NPCM7XX_ADC_NUM_INPUTS; ++i) {
418
+ object_property_add_uint32_ptr(obj, "adci[*]",
419
+ &s->adci[i], OBJ_PROP_FLAG_WRITE);
420
+ }
421
+ object_property_add_uint32_ptr(obj, "vref",
422
+ &s->vref, OBJ_PROP_FLAG_WRITE);
423
+ npcm7xx_adc_calibrate(s);
424
+}
425
+
426
+static const VMStateDescription vmstate_npcm7xx_adc = {
427
+ .name = "npcm7xx-adc",
428
+ .version_id = 0,
429
+ .minimum_version_id = 0,
430
+ .fields = (VMStateField[]) {
431
+ VMSTATE_TIMER(conv_timer, NPCM7xxADCState),
432
+ VMSTATE_UINT32(con, NPCM7xxADCState),
433
+ VMSTATE_UINT32(data, NPCM7xxADCState),
434
+ VMSTATE_CLOCK(clock, NPCM7xxADCState),
435
+ VMSTATE_UINT32_ARRAY(adci, NPCM7xxADCState, NPCM7XX_ADC_NUM_INPUTS),
436
+ VMSTATE_UINT32(vref, NPCM7xxADCState),
437
+ VMSTATE_UINT32(iref, NPCM7xxADCState),
438
+ VMSTATE_UINT16_ARRAY(calibration_r_values, NPCM7xxADCState,
439
+ NPCM7XX_ADC_NUM_CALIB),
440
+ VMSTATE_END_OF_LIST(),
441
+ },
442
+};
443
+
444
+static Property npcm7xx_timer_properties[] = {
445
+ DEFINE_PROP_UINT32("iref", NPCM7xxADCState, iref, NPCM7XX_ADC_DEFAULT_IREF),
446
+ DEFINE_PROP_END_OF_LIST(),
447
+};
448
+
449
+static void npcm7xx_adc_class_init(ObjectClass *klass, void *data)
450
+{
451
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
452
+ DeviceClass *dc = DEVICE_CLASS(klass);
453
+
454
+ dc->desc = "NPCM7xx ADC Module";
455
+ dc->vmsd = &vmstate_npcm7xx_adc;
456
+ rc->phases.enter = npcm7xx_adc_enter_reset;
457
+ rc->phases.hold = npcm7xx_adc_hold_reset;
458
+
459
+ device_class_set_props(dc, npcm7xx_timer_properties);
460
+}
461
+
462
+static const TypeInfo npcm7xx_adc_info = {
463
+ .name = TYPE_NPCM7XX_ADC,
464
+ .parent = TYPE_SYS_BUS_DEVICE,
465
+ .instance_size = sizeof(NPCM7xxADCState),
466
+ .class_init = npcm7xx_adc_class_init,
467
+ .instance_init = npcm7xx_adc_init,
468
+};
469
+
470
+static void npcm7xx_adc_register_types(void)
471
+{
472
+ type_register_static(&npcm7xx_adc_info);
473
+}
474
+
475
+type_init(npcm7xx_adc_register_types);
476
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
477
index XXXXXXX..XXXXXXX 100644
478
--- a/hw/arm/npcm7xx.c
479
+++ b/hw/arm/npcm7xx.c
480
@@ -XXX,XX +XXX,XX @@
481
#define NPCM7XX_EHCI_BA (0xf0806000)
482
#define NPCM7XX_OHCI_BA (0xf0807000)
483
484
+/* ADC Module */
485
+#define NPCM7XX_ADC_BA (0xf000c000)
486
+
487
/* Internal AHB SRAM */
488
#define NPCM7XX_RAM3_BA (0xc0008000)
489
#define NPCM7XX_RAM3_SZ (4 * KiB)
490
@@ -XXX,XX +XXX,XX @@
491
#define NPCM7XX_ROM_BA (0xffff0000)
492
#define NPCM7XX_ROM_SZ (64 * KiB)
493
494
+
495
/* Clock configuration values to be fixed up when bypassing bootloader */
496
497
/* Run PLL1 at 1600 MHz */
498
@@ -XXX,XX +XXX,XX @@
499
* interrupts.
27
*/
500
*/
28
void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu, uint16_t idxmap);
501
enum NPCM7xxInterrupt {
29
+
502
+ NPCM7XX_ADC_IRQ = 0,
30
+/**
503
NPCM7XX_UART0_IRQ = 2,
31
+ * tlb_flush_page_bits_by_mmuidx
504
NPCM7XX_UART1_IRQ,
32
+ * @cpu: CPU whose TLB should be flushed
505
NPCM7XX_UART2_IRQ,
33
+ * @addr: virtual address of page to be flushed
506
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init_fuses(NPCM7xxState *s)
34
+ * @idxmap: bitmap of mmu indexes to flush
507
sizeof(value));
35
+ * @bits: number of significant bits in address
508
}
509
510
+static void npcm7xx_write_adc_calibration(NPCM7xxState *s)
511
+{
512
+ /* Both ADC and the fuse array must have realized. */
513
+ QEMU_BUILD_BUG_ON(sizeof(s->adc.calibration_r_values) != 4);
514
+ npcm7xx_otp_array_write(&s->fuse_array, s->adc.calibration_r_values,
515
+ NPCM7XX_FUSE_ADC_CALIB, sizeof(s->adc.calibration_r_values));
516
+}
517
+
518
static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n)
519
{
520
return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n);
521
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
522
TYPE_NPCM7XX_FUSE_ARRAY);
523
object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
524
object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
525
+ object_initialize_child(obj, "adc", &s->adc, TYPE_NPCM7XX_ADC);
526
527
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
528
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
529
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
530
sysbus_realize(SYS_BUS_DEVICE(&s->mc), &error_abort);
531
sysbus_mmio_map(SYS_BUS_DEVICE(&s->mc), 0, NPCM7XX_MC_BA);
532
533
+ /* ADC Modules. Cannot fail. */
534
+ qdev_connect_clock_in(DEVICE(&s->adc), "clock", qdev_get_clock_out(
535
+ DEVICE(&s->clk), "adc-clock"));
536
+ sysbus_realize(SYS_BUS_DEVICE(&s->adc), &error_abort);
537
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, NPCM7XX_ADC_BA);
538
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
539
+ npcm7xx_irq(s, NPCM7XX_ADC_IRQ));
540
+ npcm7xx_write_adc_calibration(s);
541
+
542
/* Timer Modules (TIM). Cannot fail. */
543
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim));
544
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
545
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
546
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
547
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
548
create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB);
549
- create_unimplemented_device("npcm7xx.adc", 0xf000c000, 4 * KiB);
550
create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB);
551
create_unimplemented_device("npcm7xx.gpio[0]", 0xf0010000, 4 * KiB);
552
create_unimplemented_device("npcm7xx.gpio[1]", 0xf0011000, 4 * KiB);
553
diff --git a/tests/qtest/npcm7xx_adc-test.c b/tests/qtest/npcm7xx_adc-test.c
554
new file mode 100644
555
index XXXXXXX..XXXXXXX
556
--- /dev/null
557
+++ b/tests/qtest/npcm7xx_adc-test.c
558
@@ -XXX,XX +XXX,XX @@
559
+/*
560
+ * QTests for Nuvoton NPCM7xx ADCModules.
36
+ *
561
+ *
37
+ * Similar to tlb_flush_page_mask, but with a bitmap of indexes.
562
+ * Copyright 2020 Google LLC
563
+ *
564
+ * This program is free software; you can redistribute it and/or modify it
565
+ * under the terms of the GNU General Public License as published by the
566
+ * Free Software Foundation; either version 2 of the License, or
567
+ * (at your option) any later version.
568
+ *
569
+ * This program is distributed in the hope that it will be useful, but WITHOUT
570
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
571
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
572
+ * for more details.
38
+ */
573
+ */
39
+void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, target_ulong addr,
574
+
40
+ uint16_t idxmap, unsigned bits);
575
+#include "qemu/osdep.h"
41
+
576
+#include "qemu/bitops.h"
42
+/* Similarly, with broadcast and syncing. */
577
+#include "qemu/timer.h"
43
+void tlb_flush_page_bits_by_mmuidx_all_cpus(CPUState *cpu, target_ulong addr,
578
+#include "libqos/libqtest.h"
44
+ uint16_t idxmap, unsigned bits);
579
+#include "qapi/qmp/qdict.h"
45
+void tlb_flush_page_bits_by_mmuidx_all_cpus_synced
580
+
46
+ (CPUState *cpu, target_ulong addr, uint16_t idxmap, unsigned bits);
581
+#define REF_HZ (25000000)
47
+
582
+
48
/**
583
+#define CON_OFFSET 0x0
49
* tlb_set_page_with_attrs:
584
+#define DATA_OFFSET 0x4
50
* @cpu: CPU to add this TLB entry for
585
+
51
@@ -XXX,XX +XXX,XX @@ static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu,
586
+#define NUM_INPUTS 8
52
uint16_t idxmap)
587
+#define DEFAULT_IREF 2000000
53
{
588
+#define CONV_CYCLES 20
54
}
589
+#define RESET_CYCLES 10
55
+static inline void tlb_flush_page_bits_by_mmuidx(CPUState *cpu,
590
+#define R0_INPUT 500000
56
+ target_ulong addr,
591
+#define R1_INPUT 1500000
57
+ uint16_t idxmap,
592
+#define MAX_RESULT 1023
58
+ unsigned bits)
593
+
59
+{
594
+#define DEFAULT_CLKDIV 5
60
+}
595
+
61
+static inline void tlb_flush_page_bits_by_mmuidx_all_cpus(CPUState *cpu,
596
+#define FUSE_ARRAY_BA 0xf018a000
62
+ target_ulong addr,
597
+#define FCTL_OFFSET 0x14
63
+ uint16_t idxmap,
598
+#define FST_OFFSET 0x0
64
+ unsigned bits)
599
+#define FADDR_OFFSET 0x4
65
+{
600
+#define FDATA_OFFSET 0x8
66
+}
601
+#define ADC_CALIB_ADDR 24
67
+static inline void
602
+#define FUSE_READ 0x2
68
+tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *cpu, target_ulong addr,
603
+
69
+ uint16_t idxmap, unsigned bits)
604
+/* Register field definitions. */
70
+{
605
+#define CON_MUX(rv) ((rv) << 24)
71
+}
606
+#define CON_INT_EN BIT(21)
72
#endif
607
+#define CON_REFSEL BIT(19)
73
/**
608
+#define CON_INT BIT(18)
74
* probe_access:
609
+#define CON_EN BIT(17)
75
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
610
+#define CON_RST BIT(16)
76
index XXXXXXX..XXXXXXX 100644
611
+#define CON_CONV BIT(14)
77
--- a/accel/tcg/cputlb.c
612
+#define CON_DIV(rv) extract32(rv, 1, 8)
78
+++ b/accel/tcg/cputlb.c
613
+
79
@@ -XXX,XX +XXX,XX @@ void tlb_flush_all_cpus_synced(CPUState *src_cpu)
614
+#define FST_RDST BIT(1)
80
tlb_flush_by_mmuidx_all_cpus_synced(src_cpu, ALL_MMUIDX_BITS);
615
+#define FDATA_MASK 0xff
81
}
616
+
82
617
+#define MAX_ERROR 10000
83
+static bool tlb_hit_page_mask_anyprot(CPUTLBEntry *tlb_entry,
618
+#define MIN_CALIB_INPUT 100000
84
+ target_ulong page, target_ulong mask)
619
+#define MAX_CALIB_INPUT 1800000
85
+{
620
+
86
+ page &= mask;
621
+static const uint32_t input_list[] = {
87
+ mask &= TARGET_PAGE_MASK | TLB_INVALID_MASK;
622
+ 100000,
88
+
623
+ 500000,
89
+ return (page == (tlb_entry->addr_read & mask) ||
624
+ 1000000,
90
+ page == (tlb_addr_write(tlb_entry) & mask) ||
625
+ 1500000,
91
+ page == (tlb_entry->addr_code & mask));
626
+ 1800000,
92
+}
627
+ 2000000,
93
+
628
+};
94
static inline bool tlb_hit_page_anyprot(CPUTLBEntry *tlb_entry,
629
+
95
target_ulong page)
630
+static const uint32_t vref_list[] = {
96
{
631
+ 2000000,
97
- return tlb_hit_page(tlb_entry->addr_read, page) ||
632
+ 2200000,
98
- tlb_hit_page(tlb_addr_write(tlb_entry), page) ||
633
+ 2500000,
99
- tlb_hit_page(tlb_entry->addr_code, page);
634
+};
100
+ return tlb_hit_page_mask_anyprot(tlb_entry, page, -1);
635
+
101
}
636
+static const uint32_t iref_list[] = {
102
637
+ 1800000,
103
/**
638
+ 1900000,
104
@@ -XXX,XX +XXX,XX @@ static inline bool tlb_entry_is_empty(const CPUTLBEntry *te)
639
+ 2000000,
105
}
640
+ 2100000,
106
641
+ 2200000,
107
/* Called with tlb_c.lock held */
642
+};
108
-static inline bool tlb_flush_entry_locked(CPUTLBEntry *tlb_entry,
643
+
109
- target_ulong page)
644
+static const uint32_t div_list[] = {0, 1, 3, 7, 15};
110
+static bool tlb_flush_entry_mask_locked(CPUTLBEntry *tlb_entry,
645
+
111
+ target_ulong page,
646
+typedef struct ADC {
112
+ target_ulong mask)
647
+ int irq;
113
{
648
+ uint64_t base_addr;
114
- if (tlb_hit_page_anyprot(tlb_entry, page)) {
649
+} ADC;
115
+ if (tlb_hit_page_mask_anyprot(tlb_entry, page, mask)) {
650
+
116
memset(tlb_entry, -1, sizeof(*tlb_entry));
651
+ADC adc = {
117
return true;
652
+ .irq = 0,
118
}
653
+ .base_addr = 0xf000c000
119
return false;
654
+};
120
}
655
+
121
656
+static uint32_t adc_read_con(QTestState *qts, const ADC *adc)
122
+static inline bool tlb_flush_entry_locked(CPUTLBEntry *tlb_entry,
657
+{
123
+ target_ulong page)
658
+ return qtest_readl(qts, adc->base_addr + CON_OFFSET);
124
+{
659
+}
125
+ return tlb_flush_entry_mask_locked(tlb_entry, page, -1);
660
+
126
+}
661
+static void adc_write_con(QTestState *qts, const ADC *adc, uint32_t value)
127
+
662
+{
128
/* Called with tlb_c.lock held */
663
+ qtest_writel(qts, adc->base_addr + CON_OFFSET, value);
129
-static inline void tlb_flush_vtlb_page_locked(CPUArchState *env, int mmu_idx,
664
+}
130
- target_ulong page)
665
+
131
+static void tlb_flush_vtlb_page_mask_locked(CPUArchState *env, int mmu_idx,
666
+static uint32_t adc_read_data(QTestState *qts, const ADC *adc)
132
+ target_ulong page,
667
+{
133
+ target_ulong mask)
668
+ return qtest_readl(qts, adc->base_addr + DATA_OFFSET);
134
{
669
+}
135
CPUTLBDesc *d = &env_tlb(env)->d[mmu_idx];
670
+
136
int k;
671
+static uint32_t adc_calibrate(uint32_t measured, uint32_t *rv)
137
672
+{
138
assert_cpu_is_self(env_cpu(env));
673
+ return R0_INPUT + (R1_INPUT - R0_INPUT) * (int32_t)(measured - rv[0])
139
for (k = 0; k < CPU_VTLB_SIZE; k++) {
674
+ / (int32_t)(rv[1] - rv[0]);
140
- if (tlb_flush_entry_locked(&d->vtable[k], page)) {
675
+}
141
+ if (tlb_flush_entry_mask_locked(&d->vtable[k], page, mask)) {
676
+
142
tlb_n_used_entries_dec(env, mmu_idx);
677
+static void adc_qom_set(QTestState *qts, const ADC *adc,
143
}
678
+ const char *name, uint32_t value)
144
}
679
+{
145
}
680
+ QDict *response;
146
681
+ const char *path = "/machine/soc/adc";
147
+static inline void tlb_flush_vtlb_page_locked(CPUArchState *env, int mmu_idx,
682
+
148
+ target_ulong page)
683
+ g_test_message("Setting properties %s of %s with value %u",
149
+{
684
+ name, path, value);
150
+ tlb_flush_vtlb_page_mask_locked(env, mmu_idx, page, -1);
685
+ response = qtest_qmp(qts, "{ 'execute': 'qom-set',"
151
+}
686
+ " 'arguments': { 'path': %s, 'property': %s, 'value': %u}}",
152
+
687
+ path, name, value);
153
static void tlb_flush_page_locked(CPUArchState *env, int midx,
688
+ /* The qom set message returns successfully. */
154
target_ulong page)
689
+ g_assert_true(qdict_haskey(response, "return"));
155
{
690
+}
156
@@ -XXX,XX +XXX,XX @@ void tlb_flush_page_all_cpus_synced(CPUState *src, target_ulong addr)
691
+
157
tlb_flush_page_by_mmuidx_all_cpus_synced(src, addr, ALL_MMUIDX_BITS);
692
+static void adc_write_input(QTestState *qts, const ADC *adc,
158
}
693
+ uint32_t index, uint32_t value)
159
694
+{
160
+static void tlb_flush_page_bits_locked(CPUArchState *env, int midx,
695
+ char name[100];
161
+ target_ulong page, unsigned bits)
696
+
162
+{
697
+ sprintf(name, "adci[%u]", index);
163
+ CPUTLBDesc *d = &env_tlb(env)->d[midx];
698
+ adc_qom_set(qts, adc, name, value);
164
+ CPUTLBDescFast *f = &env_tlb(env)->f[midx];
699
+}
165
+ target_ulong mask = MAKE_64BIT_MASK(0, bits);
700
+
701
+static void adc_write_vref(QTestState *qts, const ADC *adc, uint32_t value)
702
+{
703
+ adc_qom_set(qts, adc, "vref", value);
704
+}
705
+
706
+static uint32_t adc_calculate_output(uint32_t input, uint32_t ref)
707
+{
708
+ uint32_t output;
709
+
710
+ g_assert_cmpuint(input, <=, ref);
711
+ output = (input * (MAX_RESULT + 1)) / ref;
712
+ if (output > MAX_RESULT) {
713
+ output = MAX_RESULT;
714
+ }
715
+
716
+ return output;
717
+}
718
+
719
+static uint32_t adc_prescaler(QTestState *qts, const ADC *adc)
720
+{
721
+ uint32_t div = extract32(adc_read_con(qts, adc), 1, 8);
722
+
723
+ return 2 * (div + 1);
724
+}
725
+
726
+static int64_t adc_calculate_steps(uint32_t cycles, uint32_t prescale,
727
+ uint32_t clkdiv)
728
+{
729
+ return (NANOSECONDS_PER_SECOND / (REF_HZ >> clkdiv)) * cycles * prescale;
730
+}
731
+
732
+static void adc_wait_conv_finished(QTestState *qts, const ADC *adc,
733
+ uint32_t clkdiv)
734
+{
735
+ uint32_t prescaler = adc_prescaler(qts, adc);
166
+
736
+
167
+ /*
737
+ /*
168
+ * If @bits is smaller than the tlb size, there may be multiple entries
738
+ * ADC should takes roughly 20 cycles to convert one sample. So we assert it
169
+ * within the TLB; otherwise all addresses that match under @mask hit
739
+ * should take 10~30 cycles here.
170
+ * the same TLB entry.
171
+ *
172
+ * TODO: Perhaps allow bits to be a few bits less than the size.
173
+ * For now, just flush the entire TLB.
174
+ */
740
+ */
175
+ if (mask < f->mask) {
741
+ qtest_clock_step(qts, adc_calculate_steps(CONV_CYCLES / 2, prescaler,
176
+ tlb_debug("forcing full flush midx %d ("
742
+ clkdiv));
177
+ TARGET_FMT_lx "/" TARGET_FMT_lx ")\n",
743
+ /* ADC is still converting. */
178
+ midx, page, mask);
744
+ g_assert_true(adc_read_con(qts, adc) & CON_CONV);
179
+ tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime());
745
+ qtest_clock_step(qts, adc_calculate_steps(CONV_CYCLES, prescaler, clkdiv));
180
+ return;
746
+ /* ADC has finished conversion. */
181
+ }
747
+ g_assert_false(adc_read_con(qts, adc) & CON_CONV);
182
+
748
+}
183
+ /* Check if we need to flush due to large pages. */
749
+
184
+ if ((page & d->large_page_mask) == d->large_page_addr) {
750
+/* Check ADC can be reset to default value. */
185
+ tlb_debug("forcing full flush midx %d ("
751
+static void test_init(gconstpointer adc_p)
186
+ TARGET_FMT_lx "/" TARGET_FMT_lx ")\n",
752
+{
187
+ midx, d->large_page_addr, d->large_page_mask);
753
+ const ADC *adc = adc_p;
188
+ tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime());
754
+
189
+ return;
755
+ QTestState *qts = qtest_init("-machine quanta-gsj");
190
+ }
756
+ adc_write_con(qts, adc, CON_REFSEL | CON_INT);
191
+
757
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_REFSEL);
192
+ if (tlb_flush_entry_mask_locked(tlb_entry(env, midx, page), page, mask)) {
758
+ qtest_quit(qts);
193
+ tlb_n_used_entries_dec(env, midx);
759
+}
194
+ }
760
+
195
+ tlb_flush_vtlb_page_mask_locked(env, midx, page, mask);
761
+/* Check ADC can convert from an internal reference. */
196
+}
762
+static void test_convert_internal(gconstpointer adc_p)
197
+
763
+{
198
+typedef struct {
764
+ const ADC *adc = adc_p;
199
+ target_ulong addr;
765
+ uint32_t index, input, output, expected_output;
200
+ uint16_t idxmap;
766
+ QTestState *qts = qtest_init("-machine quanta-gsj");
201
+ uint16_t bits;
767
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
202
+} TLBFlushPageBitsByMMUIdxData;
768
+
203
+
769
+ for (index = 0; index < NUM_INPUTS; ++index) {
204
+static void
770
+ for (size_t i = 0; i < ARRAY_SIZE(input_list); ++i) {
205
+tlb_flush_page_bits_by_mmuidx_async_0(CPUState *cpu,
771
+ input = input_list[i];
206
+ TLBFlushPageBitsByMMUIdxData d)
772
+ expected_output = adc_calculate_output(input, DEFAULT_IREF);
207
+{
773
+
208
+ CPUArchState *env = cpu->env_ptr;
774
+ adc_write_input(qts, adc, index, input);
209
+ int mmu_idx;
775
+ adc_write_con(qts, adc, CON_MUX(index) | CON_REFSEL | CON_INT |
210
+
776
+ CON_EN | CON_CONV);
211
+ assert_cpu_is_self(cpu);
777
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
212
+
778
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_MUX(index) |
213
+ tlb_debug("page addr:" TARGET_FMT_lx "/%u mmu_map:0x%x\n",
779
+ CON_REFSEL | CON_EN);
214
+ d.addr, d.bits, d.idxmap);
780
+ g_assert_false(qtest_get_irq(qts, adc->irq));
215
+
781
+ output = adc_read_data(qts, adc);
216
+ qemu_spin_lock(&env_tlb(env)->c.lock);
782
+ g_assert_cmpuint(output, ==, expected_output);
217
+ for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
218
+ if ((d.idxmap >> mmu_idx) & 1) {
219
+ tlb_flush_page_bits_locked(env, mmu_idx, d.addr, d.bits);
220
+ }
783
+ }
221
+ }
784
+ }
222
+ qemu_spin_unlock(&env_tlb(env)->c.lock);
785
+
223
+
786
+ qtest_quit(qts);
224
+ tb_flush_jmp_cache(cpu, d.addr);
787
+}
225
+}
788
+
226
+
789
+/* Check ADC can convert from an external reference. */
227
+static bool encode_pbm_to_runon(run_on_cpu_data *out,
790
+static void test_convert_external(gconstpointer adc_p)
228
+ TLBFlushPageBitsByMMUIdxData d)
791
+{
229
+{
792
+ const ADC *adc = adc_p;
230
+ /* We need 6 bits to hold to hold @bits up to 63. */
793
+ uint32_t index, input, vref, output, expected_output;
231
+ if (d.idxmap <= MAKE_64BIT_MASK(0, TARGET_PAGE_BITS - 6)) {
794
+ QTestState *qts = qtest_init("-machine quanta-gsj");
232
+ *out = RUN_ON_CPU_TARGET_PTR(d.addr | (d.idxmap << 6) | d.bits);
795
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
233
+ return true;
796
+
234
+ }
797
+ for (index = 0; index < NUM_INPUTS; ++index) {
235
+ return false;
798
+ for (size_t i = 0; i < ARRAY_SIZE(input_list); ++i) {
236
+}
799
+ for (size_t j = 0; j < ARRAY_SIZE(vref_list); ++j) {
237
+
800
+ input = input_list[i];
238
+static TLBFlushPageBitsByMMUIdxData
801
+ vref = vref_list[j];
239
+decode_runon_to_pbm(run_on_cpu_data data)
802
+ expected_output = adc_calculate_output(input, vref);
240
+{
803
+
241
+ target_ulong addr_map_bits = (target_ulong) data.target_ptr;
804
+ adc_write_input(qts, adc, index, input);
242
+ return (TLBFlushPageBitsByMMUIdxData){
805
+ adc_write_vref(qts, adc, vref);
243
+ .addr = addr_map_bits & TARGET_PAGE_MASK,
806
+ adc_write_con(qts, adc, CON_MUX(index) | CON_INT | CON_EN |
244
+ .idxmap = (addr_map_bits & ~TARGET_PAGE_MASK) >> 6,
807
+ CON_CONV);
245
+ .bits = addr_map_bits & 0x3f
808
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
246
+ };
809
+ g_assert_cmphex(adc_read_con(qts, adc), ==,
247
+}
810
+ CON_MUX(index) | CON_EN);
248
+
811
+ g_assert_false(qtest_get_irq(qts, adc->irq));
249
+static void tlb_flush_page_bits_by_mmuidx_async_1(CPUState *cpu,
812
+ output = adc_read_data(qts, adc);
250
+ run_on_cpu_data runon)
813
+ g_assert_cmpuint(output, ==, expected_output);
251
+{
252
+ tlb_flush_page_bits_by_mmuidx_async_0(cpu, decode_runon_to_pbm(runon));
253
+}
254
+
255
+static void tlb_flush_page_bits_by_mmuidx_async_2(CPUState *cpu,
256
+ run_on_cpu_data data)
257
+{
258
+ TLBFlushPageBitsByMMUIdxData *d = data.host_ptr;
259
+ tlb_flush_page_bits_by_mmuidx_async_0(cpu, *d);
260
+ g_free(d);
261
+}
262
+
263
+void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, target_ulong addr,
264
+ uint16_t idxmap, unsigned bits)
265
+{
266
+ TLBFlushPageBitsByMMUIdxData d;
267
+ run_on_cpu_data runon;
268
+
269
+ /* If all bits are significant, this devolves to tlb_flush_page. */
270
+ if (bits >= TARGET_LONG_BITS) {
271
+ tlb_flush_page_by_mmuidx(cpu, addr, idxmap);
272
+ return;
273
+ }
274
+ /* If no page bits are significant, this devolves to tlb_flush. */
275
+ if (bits < TARGET_PAGE_BITS) {
276
+ tlb_flush_by_mmuidx(cpu, idxmap);
277
+ return;
278
+ }
279
+
280
+ /* This should already be page aligned */
281
+ d.addr = addr & TARGET_PAGE_MASK;
282
+ d.idxmap = idxmap;
283
+ d.bits = bits;
284
+
285
+ if (qemu_cpu_is_self(cpu)) {
286
+ tlb_flush_page_bits_by_mmuidx_async_0(cpu, d);
287
+ } else if (encode_pbm_to_runon(&runon, d)) {
288
+ async_run_on_cpu(cpu, tlb_flush_page_bits_by_mmuidx_async_1, runon);
289
+ } else {
290
+ TLBFlushPageBitsByMMUIdxData *p
291
+ = g_new(TLBFlushPageBitsByMMUIdxData, 1);
292
+
293
+ /* Otherwise allocate a structure, freed by the worker. */
294
+ *p = d;
295
+ async_run_on_cpu(cpu, tlb_flush_page_bits_by_mmuidx_async_2,
296
+ RUN_ON_CPU_HOST_PTR(p));
297
+ }
298
+}
299
+
300
+void tlb_flush_page_bits_by_mmuidx_all_cpus(CPUState *src_cpu,
301
+ target_ulong addr,
302
+ uint16_t idxmap,
303
+ unsigned bits)
304
+{
305
+ TLBFlushPageBitsByMMUIdxData d;
306
+ run_on_cpu_data runon;
307
+
308
+ /* If all bits are significant, this devolves to tlb_flush_page. */
309
+ if (bits >= TARGET_LONG_BITS) {
310
+ tlb_flush_page_by_mmuidx_all_cpus(src_cpu, addr, idxmap);
311
+ return;
312
+ }
313
+ /* If no page bits are significant, this devolves to tlb_flush. */
314
+ if (bits < TARGET_PAGE_BITS) {
315
+ tlb_flush_by_mmuidx_all_cpus(src_cpu, idxmap);
316
+ return;
317
+ }
318
+
319
+ /* This should already be page aligned */
320
+ d.addr = addr & TARGET_PAGE_MASK;
321
+ d.idxmap = idxmap;
322
+ d.bits = bits;
323
+
324
+ if (encode_pbm_to_runon(&runon, d)) {
325
+ flush_all_helper(src_cpu, tlb_flush_page_bits_by_mmuidx_async_1, runon);
326
+ } else {
327
+ CPUState *dst_cpu;
328
+ TLBFlushPageBitsByMMUIdxData *p;
329
+
330
+ /* Allocate a separate data block for each destination cpu. */
331
+ CPU_FOREACH(dst_cpu) {
332
+ if (dst_cpu != src_cpu) {
333
+ p = g_new(TLBFlushPageBitsByMMUIdxData, 1);
334
+ *p = d;
335
+ async_run_on_cpu(dst_cpu,
336
+ tlb_flush_page_bits_by_mmuidx_async_2,
337
+ RUN_ON_CPU_HOST_PTR(p));
338
+ }
814
+ }
339
+ }
815
+ }
340
+ }
816
+ }
341
+
817
+
342
+ tlb_flush_page_bits_by_mmuidx_async_0(src_cpu, d);
818
+ qtest_quit(qts);
343
+}
819
+}
344
+
820
+
345
+void tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *src_cpu,
821
+/* Check ADC interrupt files if and only if CON_INT_EN is set. */
346
+ target_ulong addr,
822
+static void test_interrupt(gconstpointer adc_p)
347
+ uint16_t idxmap,
823
+{
348
+ unsigned bits)
824
+ const ADC *adc = adc_p;
349
+{
825
+ uint32_t index, input, output, expected_output;
350
+ TLBFlushPageBitsByMMUIdxData d;
826
+ QTestState *qts = qtest_init("-machine quanta-gsj");
351
+ run_on_cpu_data runon;
827
+
352
+
828
+ index = 1;
353
+ /* If all bits are significant, this devolves to tlb_flush_page. */
829
+ input = input_list[1];
354
+ if (bits >= TARGET_LONG_BITS) {
830
+ expected_output = adc_calculate_output(input, DEFAULT_IREF);
355
+ tlb_flush_page_by_mmuidx_all_cpus_synced(src_cpu, addr, idxmap);
831
+
356
+ return;
832
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
357
+ }
833
+ adc_write_input(qts, adc, index, input);
358
+ /* If no page bits are significant, this devolves to tlb_flush. */
834
+ g_assert_false(qtest_get_irq(qts, adc->irq));
359
+ if (bits < TARGET_PAGE_BITS) {
835
+ adc_write_con(qts, adc, CON_MUX(index) | CON_INT_EN | CON_REFSEL | CON_INT
360
+ tlb_flush_by_mmuidx_all_cpus_synced(src_cpu, idxmap);
836
+ | CON_EN | CON_CONV);
361
+ return;
837
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
362
+ }
838
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_MUX(index) | CON_INT_EN
363
+
839
+ | CON_REFSEL | CON_INT | CON_EN);
364
+ /* This should already be page aligned */
840
+ g_assert_true(qtest_get_irq(qts, adc->irq));
365
+ d.addr = addr & TARGET_PAGE_MASK;
841
+ output = adc_read_data(qts, adc);
366
+ d.idxmap = idxmap;
842
+ g_assert_cmpuint(output, ==, expected_output);
367
+ d.bits = bits;
843
+
368
+
844
+ qtest_quit(qts);
369
+ if (encode_pbm_to_runon(&runon, d)) {
845
+}
370
+ flush_all_helper(src_cpu, tlb_flush_page_bits_by_mmuidx_async_1, runon);
846
+
371
+ async_safe_run_on_cpu(src_cpu, tlb_flush_page_bits_by_mmuidx_async_1,
847
+/* Check ADC is reset after setting ADC_RST for 10 ADC cycles. */
372
+ runon);
848
+static void test_reset(gconstpointer adc_p)
373
+ } else {
849
+{
374
+ CPUState *dst_cpu;
850
+ const ADC *adc = adc_p;
375
+ TLBFlushPageBitsByMMUIdxData *p;
851
+ QTestState *qts = qtest_init("-machine quanta-gsj");
376
+
852
+
377
+ /* Allocate a separate data block for each destination cpu. */
853
+ for (size_t i = 0; i < ARRAY_SIZE(div_list); ++i) {
378
+ CPU_FOREACH(dst_cpu) {
854
+ uint32_t div = div_list[i];
379
+ if (dst_cpu != src_cpu) {
855
+
380
+ p = g_new(TLBFlushPageBitsByMMUIdxData, 1);
856
+ adc_write_con(qts, adc, CON_INT | CON_EN | CON_RST | CON_DIV(div));
381
+ *p = d;
857
+ qtest_clock_step(qts, adc_calculate_steps(RESET_CYCLES,
382
+ async_run_on_cpu(dst_cpu, tlb_flush_page_bits_by_mmuidx_async_2,
858
+ adc_prescaler(qts, adc), DEFAULT_CLKDIV));
383
+ RUN_ON_CPU_HOST_PTR(p));
859
+ g_assert_false(adc_read_con(qts, adc) & CON_EN);
860
+ }
861
+ qtest_quit(qts);
862
+}
863
+
864
+/* Check ADC Calibration works as desired. */
865
+static void test_calibrate(gconstpointer adc_p)
866
+{
867
+ int i, j;
868
+ const ADC *adc = adc_p;
869
+
870
+ for (j = 0; j < ARRAY_SIZE(iref_list); ++j) {
871
+ uint32_t iref = iref_list[j];
872
+ uint32_t expected_rv[] = {
873
+ adc_calculate_output(R0_INPUT, iref),
874
+ adc_calculate_output(R1_INPUT, iref),
875
+ };
876
+ char buf[100];
877
+ QTestState *qts;
878
+
879
+ sprintf(buf, "-machine quanta-gsj -global npcm7xx-adc.iref=%u", iref);
880
+ qts = qtest_init(buf);
881
+
882
+ /* Check the converted value is correct using the calibration value. */
883
+ for (i = 0; i < ARRAY_SIZE(input_list); ++i) {
884
+ uint32_t input;
885
+ uint32_t output;
886
+ uint32_t expected_output;
887
+ uint32_t calibrated_voltage;
888
+ uint32_t index = 0;
889
+
890
+ input = input_list[i];
891
+ /* Calibration only works for input range 0.1V ~ 1.8V. */
892
+ if (input < MIN_CALIB_INPUT || input > MAX_CALIB_INPUT) {
893
+ continue;
384
+ }
894
+ }
895
+ expected_output = adc_calculate_output(input, iref);
896
+
897
+ adc_write_input(qts, adc, index, input);
898
+ adc_write_con(qts, adc, CON_MUX(index) | CON_REFSEL | CON_INT |
899
+ CON_EN | CON_CONV);
900
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
901
+ g_assert_cmphex(adc_read_con(qts, adc), ==,
902
+ CON_REFSEL | CON_MUX(index) | CON_EN);
903
+ output = adc_read_data(qts, adc);
904
+ g_assert_cmpuint(output, ==, expected_output);
905
+
906
+ calibrated_voltage = adc_calibrate(output, expected_rv);
907
+ g_assert_cmpuint(calibrated_voltage, >, input - MAX_ERROR);
908
+ g_assert_cmpuint(calibrated_voltage, <, input + MAX_ERROR);
385
+ }
909
+ }
386
+
910
+
387
+ p = g_new(TLBFlushPageBitsByMMUIdxData, 1);
911
+ qtest_quit(qts);
388
+ *p = d;
912
+ }
389
+ async_safe_run_on_cpu(src_cpu, tlb_flush_page_bits_by_mmuidx_async_2,
913
+}
390
+ RUN_ON_CPU_HOST_PTR(p));
914
+
391
+ }
915
+static void adc_add_test(const char *name, const ADC* wd,
392
+}
916
+ GTestDataFunc fn)
393
+
917
+{
394
/* update the TLBs so that writes to code in the virtual page 'addr'
918
+ g_autofree char *full_name = g_strdup_printf("npcm7xx_adc/%s", name);
395
can be detected */
919
+ qtest_add_data_func(full_name, wd, fn);
396
void tlb_protect_code(ram_addr_t ram_addr)
920
+}
921
+#define add_test(name, td) adc_add_test(#name, td, test_##name)
922
+
923
+int main(int argc, char **argv)
924
+{
925
+ g_test_init(&argc, &argv, NULL);
926
+
927
+ add_test(init, &adc);
928
+ add_test(convert_internal, &adc);
929
+ add_test(convert_external, &adc);
930
+ add_test(interrupt, &adc);
931
+ add_test(reset, &adc);
932
+ add_test(calibrate, &adc);
933
+
934
+ return g_test_run();
935
+}
936
diff --git a/hw/adc/meson.build b/hw/adc/meson.build
937
index XXXXXXX..XXXXXXX 100644
938
--- a/hw/adc/meson.build
939
+++ b/hw/adc/meson.build
940
@@ -1 +1,2 @@
941
softmmu_ss.add(when: 'CONFIG_STM32F2XX_ADC', if_true: files('stm32f2xx_adc.c'))
942
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_adc.c'))
943
diff --git a/hw/adc/trace-events b/hw/adc/trace-events
944
new file mode 100644
945
index XXXXXXX..XXXXXXX
946
--- /dev/null
947
+++ b/hw/adc/trace-events
948
@@ -XXX,XX +XXX,XX @@
949
+# See docs/devel/tracing.txt for syntax documentation.
950
+
951
+# npcm7xx_adc.c
952
+npcm7xx_adc_read(const char *id, uint64_t offset, uint32_t value) " %s offset: 0x%04" PRIx64 " value 0x%04" PRIx32
953
+npcm7xx_adc_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value 0x%04" PRIx32
954
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
955
index XXXXXXX..XXXXXXX 100644
956
--- a/tests/qtest/meson.build
957
+++ b/tests/qtest/meson.build
958
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
959
['prom-env-test', 'boot-serial-test']
960
961
qtests_npcm7xx = \
962
- ['npcm7xx_gpio-test',
963
+ ['npcm7xx_adc-test',
964
+ 'npcm7xx_gpio-test',
965
'npcm7xx_rng-test',
966
'npcm7xx_timer-test',
967
'npcm7xx_watchdog_timer-test']
397
--
968
--
398
2.20.1
969
2.20.1
399
970
400
971
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
The note test requires gcc 10 for -mbranch-protection=standard.
3
The PWM module is part of NPCM7XX module. Each NPCM7XX module has two
4
The mmap test uses PROT_BTI and does not require special compiler support.
4
identical PWM modules. Each module contains 4 PWM entries. Each PWM has
5
two outputs: frequency and duty_cycle. Both are computed using inputs
6
from software side.
5
7
6
Acked-by: Alex Bennée <alex.bennee@linaro.org>
8
This module does not model detail pulse signals since it is expensive.
9
It also does not model interrupts and watchdogs that are dependant on
10
the detail models. The interfaces for these are left in the module so
11
that anyone in need for these functionalities can implement on their
12
own.
13
14
The user can read the duty cycle and frequency using qom-get command.
15
16
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
17
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
18
Signed-off-by: Hao Wu <wuhaotsh@google.com>
19
Message-id: 20210108190945.949196-5-wuhaotsh@google.com
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
20
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20201016184207.786698-13-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
22
---
12
tests/tcg/aarch64/bti-1.c | 62 +++++++++++++++++
23
docs/system/arm/nuvoton.rst | 2 +-
13
tests/tcg/aarch64/bti-2.c | 108 ++++++++++++++++++++++++++++++
24
include/hw/arm/npcm7xx.h | 2 +
14
tests/tcg/aarch64/bti-crt.inc.c | 51 ++++++++++++++
25
include/hw/misc/npcm7xx_pwm.h | 105 +++++++
15
tests/tcg/aarch64/Makefile.target | 10 +++
26
hw/arm/npcm7xx.c | 26 +-
16
tests/tcg/configure.sh | 4 ++
27
hw/misc/npcm7xx_pwm.c | 550 ++++++++++++++++++++++++++++++++++
17
5 files changed, 235 insertions(+)
28
hw/misc/meson.build | 1 +
18
create mode 100644 tests/tcg/aarch64/bti-1.c
29
hw/misc/trace-events | 6 +
19
create mode 100644 tests/tcg/aarch64/bti-2.c
30
7 files changed, 689 insertions(+), 3 deletions(-)
20
create mode 100644 tests/tcg/aarch64/bti-crt.inc.c
31
create mode 100644 include/hw/misc/npcm7xx_pwm.h
32
create mode 100644 hw/misc/npcm7xx_pwm.c
21
33
22
diff --git a/tests/tcg/aarch64/bti-1.c b/tests/tcg/aarch64/bti-1.c
34
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
35
index XXXXXXX..XXXXXXX 100644
36
--- a/docs/system/arm/nuvoton.rst
37
+++ b/docs/system/arm/nuvoton.rst
38
@@ -XXX,XX +XXX,XX @@ Supported devices
39
* USB host (USBH)
40
* GPIO controller
41
* Analog to Digital Converter (ADC)
42
+ * Pulse Width Modulation (PWM)
43
44
Missing devices
45
---------------
46
@@ -XXX,XX +XXX,XX @@ Missing devices
47
* Peripheral SPI controller (PSPI)
48
* SD/MMC host
49
* PECI interface
50
- * Pulse Width Modulation (PWM)
51
* Tachometer
52
* PCI and PCIe root complex and bridges
53
* VDM and MCTP support
54
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
55
index XXXXXXX..XXXXXXX 100644
56
--- a/include/hw/arm/npcm7xx.h
57
+++ b/include/hw/arm/npcm7xx.h
58
@@ -XXX,XX +XXX,XX @@
59
#include "hw/mem/npcm7xx_mc.h"
60
#include "hw/misc/npcm7xx_clk.h"
61
#include "hw/misc/npcm7xx_gcr.h"
62
+#include "hw/misc/npcm7xx_pwm.h"
63
#include "hw/misc/npcm7xx_rng.h"
64
#include "hw/nvram/npcm7xx_otp.h"
65
#include "hw/timer/npcm7xx_timer.h"
66
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
67
NPCM7xxCLKState clk;
68
NPCM7xxTimerCtrlState tim[3];
69
NPCM7xxADCState adc;
70
+ NPCM7xxPWMState pwm[2];
71
NPCM7xxOTPState key_storage;
72
NPCM7xxOTPState fuse_array;
73
NPCM7xxMCState mc;
74
diff --git a/include/hw/misc/npcm7xx_pwm.h b/include/hw/misc/npcm7xx_pwm.h
23
new file mode 100644
75
new file mode 100644
24
index XXXXXXX..XXXXXXX
76
index XXXXXXX..XXXXXXX
25
--- /dev/null
77
--- /dev/null
26
+++ b/tests/tcg/aarch64/bti-1.c
78
+++ b/include/hw/misc/npcm7xx_pwm.h
27
@@ -XXX,XX +XXX,XX @@
79
@@ -XXX,XX +XXX,XX @@
28
+/*
80
+/*
29
+ * Branch target identification, basic notskip cases.
81
+ * Nuvoton NPCM7xx PWM Module
82
+ *
83
+ * Copyright 2020 Google LLC
84
+ *
85
+ * This program is free software; you can redistribute it and/or modify it
86
+ * under the terms of the GNU General Public License as published by the
87
+ * Free Software Foundation; either version 2 of the License, or
88
+ * (at your option) any later version.
89
+ *
90
+ * This program is distributed in the hope that it will be useful, but WITHOUT
91
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
92
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
93
+ * for more details.
30
+ */
94
+ */
31
+
95
+#ifndef NPCM7XX_PWM_H
32
+#include "bti-crt.inc.c"
96
+#define NPCM7XX_PWM_H
33
+
97
+
34
+static void skip2_sigill(int sig, siginfo_t *info, ucontext_t *uc)
98
+#include "hw/clock.h"
35
+{
99
+#include "hw/sysbus.h"
36
+ uc->uc_mcontext.pc += 8;
100
+#include "hw/irq.h"
37
+ uc->uc_mcontext.pstate = 1;
101
+
38
+}
102
+/* Each PWM module holds 4 PWM channels. */
39
+
103
+#define NPCM7XX_PWM_PER_MODULE 4
40
+#define NOP "nop"
104
+
41
+#define BTI_N "hint #32"
105
+/*
42
+#define BTI_C "hint #34"
106
+ * Number of registers in one pwm module. Don't change this without increasing
43
+#define BTI_J "hint #36"
107
+ * the version_id in vmstate.
44
+#define BTI_JC "hint #38"
108
+ */
45
+
109
+#define NPCM7XX_PWM_NR_REGS (0x54 / sizeof(uint32_t))
46
+#define BTYPE_1(DEST) \
110
+
47
+ asm("mov %0,#1; adr x16, 1f; br x16; 1: " DEST "; mov %0,#0" \
111
+/*
48
+ : "=r"(skipped) : : "x16")
112
+ * The maximum duty values. Each duty unit represents 1/NPCM7XX_PWM_MAX_DUTY
49
+
113
+ * cycles. For example, if NPCM7XX_PWM_MAX_DUTY=1,000,000 and a PWM has a duty
50
+#define BTYPE_2(DEST) \
114
+ * value of 100,000 the duty cycle for that PWM is 10%.
51
+ asm("mov %0,#1; adr x16, 1f; blr x16; 1: " DEST "; mov %0,#0" \
115
+ */
52
+ : "=r"(skipped) : : "x16", "x30")
116
+#define NPCM7XX_PWM_MAX_DUTY 1000000
53
+
117
+
54
+#define BTYPE_3(DEST) \
118
+typedef struct NPCM7xxPWMState NPCM7xxPWMState;
55
+ asm("mov %0,#1; adr x15, 1f; br x15; 1: " DEST "; mov %0,#0" \
119
+
56
+ : "=r"(skipped) : : "x15")
120
+/**
57
+
121
+ * struct NPCM7xxPWM - The state of a single PWM channel.
58
+#define TEST(WHICH, DEST, EXPECT) \
122
+ * @module: The PWM module that contains this channel.
59
+ do { WHICH(DEST); fail += skipped ^ EXPECT; } while (0)
123
+ * @irq: GIC interrupt line to fire on expiration if enabled.
60
+
124
+ * @running: Whether this PWM channel is generating output.
61
+
125
+ * @inverted: Whether this PWM channel is inverted.
62
+int main()
126
+ * @index: The index of this PWM channel.
63
+{
127
+ * @cnr: The counter register.
64
+ int fail = 0;
128
+ * @cmr: The comparator register.
65
+ int skipped;
129
+ * @pdr: The data register.
66
+
130
+ * @pwdr: The watchdog register.
67
+ /* Signal-like with SA_SIGINFO. */
131
+ * @freq: The frequency of this PWM channel.
68
+ signal_info(SIGILL, skip2_sigill);
132
+ * @duty: The duty cycle of this PWM channel. One unit represents
69
+
133
+ * 1/NPCM7XX_MAX_DUTY cycles.
70
+ TEST(BTYPE_1, NOP, 1);
134
+ */
71
+ TEST(BTYPE_1, BTI_N, 1);
135
+typedef struct NPCM7xxPWM {
72
+ TEST(BTYPE_1, BTI_C, 0);
136
+ NPCM7xxPWMState *module;
73
+ TEST(BTYPE_1, BTI_J, 0);
137
+
74
+ TEST(BTYPE_1, BTI_JC, 0);
138
+ qemu_irq irq;
75
+
139
+
76
+ TEST(BTYPE_2, NOP, 1);
140
+ bool running;
77
+ TEST(BTYPE_2, BTI_N, 1);
141
+ bool inverted;
78
+ TEST(BTYPE_2, BTI_C, 0);
142
+
79
+ TEST(BTYPE_2, BTI_J, 1);
143
+ uint8_t index;
80
+ TEST(BTYPE_2, BTI_JC, 0);
144
+ uint32_t cnr;
81
+
145
+ uint32_t cmr;
82
+ TEST(BTYPE_3, NOP, 1);
146
+ uint32_t pdr;
83
+ TEST(BTYPE_3, BTI_N, 1);
147
+ uint32_t pwdr;
84
+ TEST(BTYPE_3, BTI_C, 1);
148
+
85
+ TEST(BTYPE_3, BTI_J, 0);
149
+ uint32_t freq;
86
+ TEST(BTYPE_3, BTI_JC, 0);
150
+ uint32_t duty;
87
+
151
+} NPCM7xxPWM;
88
+ return fail;
152
+
89
+}
153
+/**
90
diff --git a/tests/tcg/aarch64/bti-2.c b/tests/tcg/aarch64/bti-2.c
154
+ * struct NPCM7xxPWMState - Pulse Width Modulation device state.
155
+ * @parent: System bus device.
156
+ * @iomem: Memory region through which registers are accessed.
157
+ * @clock: The PWM clock.
158
+ * @pwm: The PWM channels owned by this module.
159
+ * @ppr: The prescaler register.
160
+ * @csr: The clock selector register.
161
+ * @pcr: The control register.
162
+ * @pier: The interrupt enable register.
163
+ * @piir: The interrupt indication register.
164
+ */
165
+struct NPCM7xxPWMState {
166
+ SysBusDevice parent;
167
+
168
+ MemoryRegion iomem;
169
+
170
+ Clock *clock;
171
+ NPCM7xxPWM pwm[NPCM7XX_PWM_PER_MODULE];
172
+
173
+ uint32_t ppr;
174
+ uint32_t csr;
175
+ uint32_t pcr;
176
+ uint32_t pier;
177
+ uint32_t piir;
178
+};
179
+
180
+#define TYPE_NPCM7XX_PWM "npcm7xx-pwm"
181
+#define NPCM7XX_PWM(obj) \
182
+ OBJECT_CHECK(NPCM7xxPWMState, (obj), TYPE_NPCM7XX_PWM)
183
+
184
+#endif /* NPCM7XX_PWM_H */
185
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
186
index XXXXXXX..XXXXXXX 100644
187
--- a/hw/arm/npcm7xx.c
188
+++ b/hw/arm/npcm7xx.c
189
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
190
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
191
NPCM7XX_EHCI_IRQ = 61,
192
NPCM7XX_OHCI_IRQ = 62,
193
+ NPCM7XX_PWM0_IRQ = 93, /* PWM module 0 */
194
+ NPCM7XX_PWM1_IRQ, /* PWM module 1 */
195
NPCM7XX_GPIO0_IRQ = 116,
196
NPCM7XX_GPIO1_IRQ,
197
NPCM7XX_GPIO2_IRQ,
198
@@ -XXX,XX +XXX,XX @@ static const hwaddr npcm7xx_fiu3_flash_addr[] = {
199
0xb8000000, /* CS3 */
200
};
201
202
+/* Register base address for each PWM Module */
203
+static const hwaddr npcm7xx_pwm_addr[] = {
204
+ 0xf0103000,
205
+ 0xf0104000,
206
+};
207
+
208
static const struct {
209
hwaddr regs_addr;
210
uint32_t unconnected_pins;
211
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
212
object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i],
213
TYPE_NPCM7XX_FIU);
214
}
215
+
216
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
217
+ object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
218
+ }
219
}
220
221
static void npcm7xx_realize(DeviceState *dev, Error **errp)
222
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
223
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0,
224
npcm7xx_irq(s, NPCM7XX_OHCI_IRQ));
225
226
+ /* PWM Modules. Cannot fail. */
227
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pwm_addr) != ARRAY_SIZE(s->pwm));
228
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
229
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pwm[i]);
230
+
231
+ qdev_connect_clock_in(DEVICE(&s->pwm[i]), "clock", qdev_get_clock_out(
232
+ DEVICE(&s->clk), "apb3-clock"));
233
+ sysbus_realize(sbd, &error_abort);
234
+ sysbus_mmio_map(sbd, 0, npcm7xx_pwm_addr[i]);
235
+ sysbus_connect_irq(sbd, i, npcm7xx_irq(s, NPCM7XX_PWM0_IRQ + i));
236
+ }
237
+
238
/*
239
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
240
* specified, but this is a programming error.
241
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
242
create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB);
243
create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB);
244
create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB);
245
- create_unimplemented_device("npcm7xx.pwm[0]", 0xf0103000, 4 * KiB);
246
- create_unimplemented_device("npcm7xx.pwm[1]", 0xf0104000, 4 * KiB);
247
create_unimplemented_device("npcm7xx.mft[0]", 0xf0180000, 4 * KiB);
248
create_unimplemented_device("npcm7xx.mft[1]", 0xf0181000, 4 * KiB);
249
create_unimplemented_device("npcm7xx.mft[2]", 0xf0182000, 4 * KiB);
250
diff --git a/hw/misc/npcm7xx_pwm.c b/hw/misc/npcm7xx_pwm.c
91
new file mode 100644
251
new file mode 100644
92
index XXXXXXX..XXXXXXX
252
index XXXXXXX..XXXXXXX
93
--- /dev/null
253
--- /dev/null
94
+++ b/tests/tcg/aarch64/bti-2.c
254
+++ b/hw/misc/npcm7xx_pwm.c
95
@@ -XXX,XX +XXX,XX @@
255
@@ -XXX,XX +XXX,XX @@
96
+/*
256
+/*
97
+ * Branch target identification, basic notskip cases.
257
+ * Nuvoton NPCM7xx PWM Module
258
+ *
259
+ * Copyright 2020 Google LLC
260
+ *
261
+ * This program is free software; you can redistribute it and/or modify it
262
+ * under the terms of the GNU General Public License as published by the
263
+ * Free Software Foundation; either version 2 of the License, or
264
+ * (at your option) any later version.
265
+ *
266
+ * This program is distributed in the hope that it will be useful, but WITHOUT
267
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
268
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
269
+ * for more details.
98
+ */
270
+ */
99
+
271
+
100
+#include <stdio.h>
272
+#include "qemu/osdep.h"
101
+#include <signal.h>
273
+#include "hw/irq.h"
102
+#include <string.h>
274
+#include "hw/qdev-clock.h"
103
+#include <unistd.h>
275
+#include "hw/qdev-properties.h"
104
+#include <sys/mman.h>
276
+#include "hw/misc/npcm7xx_pwm.h"
105
+
277
+#include "hw/registerfields.h"
106
+#ifndef PROT_BTI
278
+#include "migration/vmstate.h"
107
+#define PROT_BTI 0x10
279
+#include "qemu/bitops.h"
108
+#endif
280
+#include "qemu/error-report.h"
109
+
281
+#include "qemu/log.h"
110
+static void skip2_sigill(int sig, siginfo_t *info, void *vuc)
282
+#include "qemu/module.h"
111
+{
283
+#include "qemu/units.h"
112
+ ucontext_t *uc = vuc;
284
+#include "trace.h"
113
+ uc->uc_mcontext.pc += 8;
285
+
114
+ uc->uc_mcontext.pstate = 1;
286
+REG32(NPCM7XX_PWM_PPR, 0x00);
115
+}
287
+REG32(NPCM7XX_PWM_CSR, 0x04);
116
+
288
+REG32(NPCM7XX_PWM_PCR, 0x08);
117
+#define NOP "nop"
289
+REG32(NPCM7XX_PWM_CNR0, 0x0c);
118
+#define BTI_N "hint #32"
290
+REG32(NPCM7XX_PWM_CMR0, 0x10);
119
+#define BTI_C "hint #34"
291
+REG32(NPCM7XX_PWM_PDR0, 0x14);
120
+#define BTI_J "hint #36"
292
+REG32(NPCM7XX_PWM_CNR1, 0x18);
121
+#define BTI_JC "hint #38"
293
+REG32(NPCM7XX_PWM_CMR1, 0x1c);
122
+
294
+REG32(NPCM7XX_PWM_PDR1, 0x20);
123
+#define BTYPE_1(DEST) \
295
+REG32(NPCM7XX_PWM_CNR2, 0x24);
124
+ "mov x1, #1\n\t" \
296
+REG32(NPCM7XX_PWM_CMR2, 0x28);
125
+ "adr x16, 1f\n\t" \
297
+REG32(NPCM7XX_PWM_PDR2, 0x2c);
126
+ "br x16\n" \
298
+REG32(NPCM7XX_PWM_CNR3, 0x30);
127
+"1: " DEST "\n\t" \
299
+REG32(NPCM7XX_PWM_CMR3, 0x34);
128
+ "mov x1, #0"
300
+REG32(NPCM7XX_PWM_PDR3, 0x38);
129
+
301
+REG32(NPCM7XX_PWM_PIER, 0x3c);
130
+#define BTYPE_2(DEST) \
302
+REG32(NPCM7XX_PWM_PIIR, 0x40);
131
+ "mov x1, #1\n\t" \
303
+REG32(NPCM7XX_PWM_PWDR0, 0x44);
132
+ "adr x16, 1f\n\t" \
304
+REG32(NPCM7XX_PWM_PWDR1, 0x48);
133
+ "blr x16\n" \
305
+REG32(NPCM7XX_PWM_PWDR2, 0x4c);
134
+"1: " DEST "\n\t" \
306
+REG32(NPCM7XX_PWM_PWDR3, 0x50);
135
+ "mov x1, #0"
307
+
136
+
308
+/* Register field definitions. */
137
+#define BTYPE_3(DEST) \
309
+#define NPCM7XX_PPR(rv, index) extract32((rv), npcm7xx_ppr_base[index], 8)
138
+ "mov x1, #1\n\t" \
310
+#define NPCM7XX_CSR(rv, index) extract32((rv), npcm7xx_csr_base[index], 3)
139
+ "adr x15, 1f\n\t" \
311
+#define NPCM7XX_CH(rv, index) extract32((rv), npcm7xx_ch_base[index], 4)
140
+ "br x15\n" \
312
+#define NPCM7XX_CH_EN BIT(0)
141
+"1: " DEST "\n\t" \
313
+#define NPCM7XX_CH_INV BIT(2)
142
+ "mov x1, #0"
314
+#define NPCM7XX_CH_MOD BIT(3)
143
+
315
+
144
+#define TEST(WHICH, DEST, EXPECT) \
316
+/* Offset of each PWM channel's prescaler in the PPR register. */
145
+ WHICH(DEST) "\n" \
317
+static const int npcm7xx_ppr_base[] = { 0, 0, 8, 8 };
146
+ ".if " #EXPECT "\n\t" \
318
+/* Offset of each PWM channel's clock selector in the CSR register. */
147
+ "eor x1, x1," #EXPECT "\n" \
319
+static const int npcm7xx_csr_base[] = { 0, 4, 8, 12 };
148
+ ".endif\n\t" \
320
+/* Offset of each PWM channel's control variable in the PCR register. */
149
+ "add x0, x0, x1\n\t"
321
+static const int npcm7xx_ch_base[] = { 0, 8, 12, 16 };
150
+
322
+
151
+extern char test_begin[], test_end[];
323
+static uint32_t npcm7xx_pwm_calculate_freq(NPCM7xxPWM *p)
152
+
324
+{
153
+asm("\n"
325
+ uint32_t ppr;
154
+"test_begin:\n\t"
326
+ uint32_t csr;
155
+ BTI_C "\n\t"
327
+ uint32_t freq;
156
+ "mov x2, x30\n\t"
328
+
157
+ "mov x0, #0\n\t"
329
+ if (!p->running) {
158
+
330
+ return 0;
159
+ TEST(BTYPE_1, NOP, 1)
331
+ }
160
+ TEST(BTYPE_1, BTI_N, 1)
332
+
161
+ TEST(BTYPE_1, BTI_C, 0)
333
+ csr = NPCM7XX_CSR(p->module->csr, p->index);
162
+ TEST(BTYPE_1, BTI_J, 0)
334
+ ppr = NPCM7XX_PPR(p->module->ppr, p->index);
163
+ TEST(BTYPE_1, BTI_JC, 0)
335
+ freq = clock_get_hz(p->module->clock);
164
+
336
+ freq /= ppr + 1;
165
+ TEST(BTYPE_2, NOP, 1)
337
+ /* csr can only be 0~4 */
166
+ TEST(BTYPE_2, BTI_N, 1)
338
+ if (csr > 4) {
167
+ TEST(BTYPE_2, BTI_C, 0)
339
+ qemu_log_mask(LOG_GUEST_ERROR,
168
+ TEST(BTYPE_2, BTI_J, 1)
340
+ "%s: invalid csr value %u\n",
169
+ TEST(BTYPE_2, BTI_JC, 0)
341
+ __func__, csr);
170
+
342
+ csr = 4;
171
+ TEST(BTYPE_3, NOP, 1)
343
+ }
172
+ TEST(BTYPE_3, BTI_N, 1)
344
+ /* freq won't be changed if csr == 4. */
173
+ TEST(BTYPE_3, BTI_C, 1)
345
+ if (csr < 4) {
174
+ TEST(BTYPE_3, BTI_J, 0)
346
+ freq >>= csr + 1;
175
+ TEST(BTYPE_3, BTI_JC, 0)
347
+ }
176
+
348
+
177
+ "ret x2\n"
349
+ return freq / (p->cnr + 1);
178
+"test_end:"
350
+}
179
+);
351
+
180
+
352
+static uint32_t npcm7xx_pwm_calculate_duty(NPCM7xxPWM *p)
181
+int main()
353
+{
182
+{
354
+ uint64_t duty;
183
+ struct sigaction sa;
355
+
184
+
356
+ if (p->running) {
185
+ void *p = mmap(0, getpagesize(),
357
+ if (p->cnr == 0) {
186
+ PROT_EXEC | PROT_READ | PROT_WRITE | PROT_BTI,
358
+ duty = 0;
187
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
359
+ } else if (p->cmr >= p->cnr) {
188
+ if (p == MAP_FAILED) {
360
+ duty = NPCM7XX_PWM_MAX_DUTY;
189
+ perror("mmap");
361
+ } else {
362
+ duty = NPCM7XX_PWM_MAX_DUTY * (p->cmr + 1) / (p->cnr + 1);
363
+ }
364
+ } else {
365
+ duty = 0;
366
+ }
367
+
368
+ if (p->inverted) {
369
+ duty = NPCM7XX_PWM_MAX_DUTY - duty;
370
+ }
371
+
372
+ return duty;
373
+}
374
+
375
+static void npcm7xx_pwm_update_freq(NPCM7xxPWM *p)
376
+{
377
+ uint32_t freq = npcm7xx_pwm_calculate_freq(p);
378
+
379
+ if (freq != p->freq) {
380
+ trace_npcm7xx_pwm_update_freq(DEVICE(p->module)->canonical_path,
381
+ p->index, p->freq, freq);
382
+ p->freq = freq;
383
+ }
384
+}
385
+
386
+static void npcm7xx_pwm_update_duty(NPCM7xxPWM *p)
387
+{
388
+ uint32_t duty = npcm7xx_pwm_calculate_duty(p);
389
+
390
+ if (duty != p->duty) {
391
+ trace_npcm7xx_pwm_update_duty(DEVICE(p->module)->canonical_path,
392
+ p->index, p->duty, duty);
393
+ p->duty = duty;
394
+ }
395
+}
396
+
397
+static void npcm7xx_pwm_update_output(NPCM7xxPWM *p)
398
+{
399
+ npcm7xx_pwm_update_freq(p);
400
+ npcm7xx_pwm_update_duty(p);
401
+}
402
+
403
+static void npcm7xx_pwm_write_ppr(NPCM7xxPWMState *s, uint32_t new_ppr)
404
+{
405
+ int i;
406
+ uint32_t old_ppr = s->ppr;
407
+
408
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_ppr_base) != NPCM7XX_PWM_PER_MODULE);
409
+ s->ppr = new_ppr;
410
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
411
+ if (NPCM7XX_PPR(old_ppr, i) != NPCM7XX_PPR(new_ppr, i)) {
412
+ npcm7xx_pwm_update_freq(&s->pwm[i]);
413
+ }
414
+ }
415
+}
416
+
417
+static void npcm7xx_pwm_write_csr(NPCM7xxPWMState *s, uint32_t new_csr)
418
+{
419
+ int i;
420
+ uint32_t old_csr = s->csr;
421
+
422
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_csr_base) != NPCM7XX_PWM_PER_MODULE);
423
+ s->csr = new_csr;
424
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
425
+ if (NPCM7XX_CSR(old_csr, i) != NPCM7XX_CSR(new_csr, i)) {
426
+ npcm7xx_pwm_update_freq(&s->pwm[i]);
427
+ }
428
+ }
429
+}
430
+
431
+static void npcm7xx_pwm_write_pcr(NPCM7xxPWMState *s, uint32_t new_pcr)
432
+{
433
+ int i;
434
+ bool inverted;
435
+ uint32_t pcr;
436
+ NPCM7xxPWM *p;
437
+
438
+ s->pcr = new_pcr;
439
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_ch_base) != NPCM7XX_PWM_PER_MODULE);
440
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
441
+ p = &s->pwm[i];
442
+ pcr = NPCM7XX_CH(new_pcr, i);
443
+ inverted = pcr & NPCM7XX_CH_INV;
444
+
445
+ /*
446
+ * We only run a PWM channel with toggle mode. Single-shot mode does not
447
+ * generate frequency and duty-cycle values.
448
+ */
449
+ if ((pcr & NPCM7XX_CH_EN) && (pcr & NPCM7XX_CH_MOD)) {
450
+ if (p->running) {
451
+ /* Re-run this PWM channel if inverted changed. */
452
+ if (p->inverted ^ inverted) {
453
+ p->inverted = inverted;
454
+ npcm7xx_pwm_update_duty(p);
455
+ }
456
+ } else {
457
+ /* Run this PWM channel. */
458
+ p->running = true;
459
+ p->inverted = inverted;
460
+ npcm7xx_pwm_update_output(p);
461
+ }
462
+ } else {
463
+ /* Clear this PWM channel. */
464
+ p->running = false;
465
+ p->inverted = inverted;
466
+ npcm7xx_pwm_update_output(p);
467
+ }
468
+ }
469
+
470
+}
471
+
472
+static hwaddr npcm7xx_cnr_index(hwaddr offset)
473
+{
474
+ switch (offset) {
475
+ case A_NPCM7XX_PWM_CNR0:
476
+ return 0;
477
+ case A_NPCM7XX_PWM_CNR1:
190
+ return 1;
478
+ return 1;
191
+ }
479
+ case A_NPCM7XX_PWM_CNR2:
192
+
480
+ return 2;
193
+ memset(&sa, 0, sizeof(sa));
481
+ case A_NPCM7XX_PWM_CNR3:
194
+ sa.sa_sigaction = skip2_sigill;
482
+ return 3;
195
+ sa.sa_flags = SA_SIGINFO;
483
+ default:
196
+ if (sigaction(SIGILL, &sa, NULL) < 0) {
484
+ g_assert_not_reached();
197
+ perror("sigaction");
485
+ }
486
+}
487
+
488
+static hwaddr npcm7xx_cmr_index(hwaddr offset)
489
+{
490
+ switch (offset) {
491
+ case A_NPCM7XX_PWM_CMR0:
492
+ return 0;
493
+ case A_NPCM7XX_PWM_CMR1:
198
+ return 1;
494
+ return 1;
199
+ }
495
+ case A_NPCM7XX_PWM_CMR2:
200
+
496
+ return 2;
201
+ memcpy(p, test_begin, test_end - test_begin);
497
+ case A_NPCM7XX_PWM_CMR3:
202
+ return ((int (*)(void))p)();
498
+ return 3;
203
+}
499
+ default:
204
diff --git a/tests/tcg/aarch64/bti-crt.inc.c b/tests/tcg/aarch64/bti-crt.inc.c
500
+ g_assert_not_reached();
205
new file mode 100644
501
+ }
206
index XXXXXXX..XXXXXXX
502
+}
207
--- /dev/null
503
+
208
+++ b/tests/tcg/aarch64/bti-crt.inc.c
504
+static hwaddr npcm7xx_pdr_index(hwaddr offset)
209
@@ -XXX,XX +XXX,XX @@
505
+{
210
+/*
506
+ switch (offset) {
211
+ * Minimal user-environment for testing BTI.
507
+ case A_NPCM7XX_PWM_PDR0:
212
+ *
508
+ return 0;
213
+ * Normal libc is not (yet) built with BTI support enabled,
509
+ case A_NPCM7XX_PWM_PDR1:
214
+ * and so could generate a BTI TRAP before ever reaching main.
510
+ return 1;
215
+ */
511
+ case A_NPCM7XX_PWM_PDR2:
216
+
512
+ return 2;
217
+#include <stdlib.h>
513
+ case A_NPCM7XX_PWM_PDR3:
218
+#include <signal.h>
514
+ return 3;
219
+#include <ucontext.h>
515
+ default:
220
+#include <asm/unistd.h>
516
+ g_assert_not_reached();
221
+
517
+ }
222
+int main(void);
518
+}
223
+
519
+
224
+void _start(void)
520
+static hwaddr npcm7xx_pwdr_index(hwaddr offset)
225
+{
521
+{
226
+ exit(main());
522
+ switch (offset) {
227
+}
523
+ case A_NPCM7XX_PWM_PWDR0:
228
+
524
+ return 0;
229
+void exit(int ret)
525
+ case A_NPCM7XX_PWM_PWDR1:
230
+{
526
+ return 1;
231
+ register int x0 __asm__("x0") = ret;
527
+ case A_NPCM7XX_PWM_PWDR2:
232
+ register int x8 __asm__("x8") = __NR_exit;
528
+ return 2;
233
+
529
+ case A_NPCM7XX_PWM_PWDR3:
234
+ asm volatile("svc #0" : : "r"(x0), "r"(x8));
530
+ return 3;
235
+ __builtin_unreachable();
531
+ default:
236
+}
532
+ g_assert_not_reached();
237
+
533
+ }
238
+/*
534
+}
239
+ * Irritatingly, the user API struct sigaction does not match the
535
+
240
+ * kernel API struct sigaction. So for simplicity, isolate the
536
+static uint64_t npcm7xx_pwm_read(void *opaque, hwaddr offset, unsigned size)
241
+ * kernel ABI here, and make this act like signal.
537
+{
242
+ */
538
+ NPCM7xxPWMState *s = opaque;
243
+void signal_info(int sig, void (*fn)(int, siginfo_t *, ucontext_t *))
539
+ uint64_t value = 0;
244
+{
540
+
245
+ struct kernel_sigaction {
541
+ switch (offset) {
246
+ void (*handler)(int, siginfo_t *, ucontext_t *);
542
+ case A_NPCM7XX_PWM_CNR0:
247
+ unsigned long flags;
543
+ case A_NPCM7XX_PWM_CNR1:
248
+ unsigned long restorer;
544
+ case A_NPCM7XX_PWM_CNR2:
249
+ unsigned long mask;
545
+ case A_NPCM7XX_PWM_CNR3:
250
+ } sa = { fn, SA_SIGINFO, 0, 0 };
546
+ value = s->pwm[npcm7xx_cnr_index(offset)].cnr;
251
+
547
+ break;
252
+ register int x0 __asm__("x0") = sig;
548
+
253
+ register void *x1 __asm__("x1") = &sa;
549
+ case A_NPCM7XX_PWM_CMR0:
254
+ register void *x2 __asm__("x2") = 0;
550
+ case A_NPCM7XX_PWM_CMR1:
255
+ register int x3 __asm__("x3") = sizeof(unsigned long);
551
+ case A_NPCM7XX_PWM_CMR2:
256
+ register int x8 __asm__("x8") = __NR_rt_sigaction;
552
+ case A_NPCM7XX_PWM_CMR3:
257
+
553
+ value = s->pwm[npcm7xx_cmr_index(offset)].cmr;
258
+ asm volatile("svc #0"
554
+ break;
259
+ : : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x8) : "memory");
555
+
260
+}
556
+ case A_NPCM7XX_PWM_PDR0:
261
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
557
+ case A_NPCM7XX_PWM_PDR1:
558
+ case A_NPCM7XX_PWM_PDR2:
559
+ case A_NPCM7XX_PWM_PDR3:
560
+ value = s->pwm[npcm7xx_pdr_index(offset)].pdr;
561
+ break;
562
+
563
+ case A_NPCM7XX_PWM_PWDR0:
564
+ case A_NPCM7XX_PWM_PWDR1:
565
+ case A_NPCM7XX_PWM_PWDR2:
566
+ case A_NPCM7XX_PWM_PWDR3:
567
+ value = s->pwm[npcm7xx_pwdr_index(offset)].pwdr;
568
+ break;
569
+
570
+ case A_NPCM7XX_PWM_PPR:
571
+ value = s->ppr;
572
+ break;
573
+
574
+ case A_NPCM7XX_PWM_CSR:
575
+ value = s->csr;
576
+ break;
577
+
578
+ case A_NPCM7XX_PWM_PCR:
579
+ value = s->pcr;
580
+ break;
581
+
582
+ case A_NPCM7XX_PWM_PIER:
583
+ value = s->pier;
584
+ break;
585
+
586
+ case A_NPCM7XX_PWM_PIIR:
587
+ value = s->piir;
588
+ break;
589
+
590
+ default:
591
+ qemu_log_mask(LOG_GUEST_ERROR,
592
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
593
+ __func__, offset);
594
+ break;
595
+ }
596
+
597
+ trace_npcm7xx_pwm_read(DEVICE(s)->canonical_path, offset, value);
598
+ return value;
599
+}
600
+
601
+static void npcm7xx_pwm_write(void *opaque, hwaddr offset,
602
+ uint64_t v, unsigned size)
603
+{
604
+ NPCM7xxPWMState *s = opaque;
605
+ NPCM7xxPWM *p;
606
+ uint32_t value = v;
607
+
608
+ trace_npcm7xx_pwm_write(DEVICE(s)->canonical_path, offset, value);
609
+ switch (offset) {
610
+ case A_NPCM7XX_PWM_CNR0:
611
+ case A_NPCM7XX_PWM_CNR1:
612
+ case A_NPCM7XX_PWM_CNR2:
613
+ case A_NPCM7XX_PWM_CNR3:
614
+ p = &s->pwm[npcm7xx_cnr_index(offset)];
615
+ p->cnr = value;
616
+ npcm7xx_pwm_update_output(p);
617
+ break;
618
+
619
+ case A_NPCM7XX_PWM_CMR0:
620
+ case A_NPCM7XX_PWM_CMR1:
621
+ case A_NPCM7XX_PWM_CMR2:
622
+ case A_NPCM7XX_PWM_CMR3:
623
+ p = &s->pwm[npcm7xx_cmr_index(offset)];
624
+ p->cmr = value;
625
+ npcm7xx_pwm_update_output(p);
626
+ break;
627
+
628
+ case A_NPCM7XX_PWM_PDR0:
629
+ case A_NPCM7XX_PWM_PDR1:
630
+ case A_NPCM7XX_PWM_PDR2:
631
+ case A_NPCM7XX_PWM_PDR3:
632
+ qemu_log_mask(LOG_GUEST_ERROR,
633
+ "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
634
+ __func__, offset);
635
+ break;
636
+
637
+ case A_NPCM7XX_PWM_PWDR0:
638
+ case A_NPCM7XX_PWM_PWDR1:
639
+ case A_NPCM7XX_PWM_PWDR2:
640
+ case A_NPCM7XX_PWM_PWDR3:
641
+ qemu_log_mask(LOG_UNIMP,
642
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
643
+ __func__, offset);
644
+ break;
645
+
646
+ case A_NPCM7XX_PWM_PPR:
647
+ npcm7xx_pwm_write_ppr(s, value);
648
+ break;
649
+
650
+ case A_NPCM7XX_PWM_CSR:
651
+ npcm7xx_pwm_write_csr(s, value);
652
+ break;
653
+
654
+ case A_NPCM7XX_PWM_PCR:
655
+ npcm7xx_pwm_write_pcr(s, value);
656
+ break;
657
+
658
+ case A_NPCM7XX_PWM_PIER:
659
+ qemu_log_mask(LOG_UNIMP,
660
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
661
+ __func__, offset);
662
+ break;
663
+
664
+ case A_NPCM7XX_PWM_PIIR:
665
+ qemu_log_mask(LOG_UNIMP,
666
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
667
+ __func__, offset);
668
+ break;
669
+
670
+ default:
671
+ qemu_log_mask(LOG_GUEST_ERROR,
672
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
673
+ __func__, offset);
674
+ break;
675
+ }
676
+}
677
+
678
+static const struct MemoryRegionOps npcm7xx_pwm_ops = {
679
+ .read = npcm7xx_pwm_read,
680
+ .write = npcm7xx_pwm_write,
681
+ .endianness = DEVICE_LITTLE_ENDIAN,
682
+ .valid = {
683
+ .min_access_size = 4,
684
+ .max_access_size = 4,
685
+ .unaligned = false,
686
+ },
687
+};
688
+
689
+static void npcm7xx_pwm_enter_reset(Object *obj, ResetType type)
690
+{
691
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
692
+ int i;
693
+
694
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
695
+ NPCM7xxPWM *p = &s->pwm[i];
696
+
697
+ p->cnr = 0x00000000;
698
+ p->cmr = 0x00000000;
699
+ p->pdr = 0x00000000;
700
+ p->pwdr = 0x00000000;
701
+ }
702
+
703
+ s->ppr = 0x00000000;
704
+ s->csr = 0x00000000;
705
+ s->pcr = 0x00000000;
706
+ s->pier = 0x00000000;
707
+ s->piir = 0x00000000;
708
+}
709
+
710
+static void npcm7xx_pwm_hold_reset(Object *obj)
711
+{
712
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
713
+ int i;
714
+
715
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
716
+ qemu_irq_lower(s->pwm[i].irq);
717
+ }
718
+}
719
+
720
+static void npcm7xx_pwm_init(Object *obj)
721
+{
722
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
723
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
724
+ int i;
725
+
726
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
727
+ NPCM7xxPWM *p = &s->pwm[i];
728
+ p->module = s;
729
+ p->index = i;
730
+ sysbus_init_irq(sbd, &p->irq);
731
+ }
732
+
733
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_pwm_ops, s,
734
+ TYPE_NPCM7XX_PWM, 4 * KiB);
735
+ sysbus_init_mmio(sbd, &s->iomem);
736
+ s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
737
+
738
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
739
+ object_property_add_uint32_ptr(obj, "freq[*]",
740
+ &s->pwm[i].freq, OBJ_PROP_FLAG_READ);
741
+ object_property_add_uint32_ptr(obj, "duty[*]",
742
+ &s->pwm[i].duty, OBJ_PROP_FLAG_READ);
743
+ }
744
+}
745
+
746
+static const VMStateDescription vmstate_npcm7xx_pwm = {
747
+ .name = "npcm7xx-pwm",
748
+ .version_id = 0,
749
+ .minimum_version_id = 0,
750
+ .fields = (VMStateField[]) {
751
+ VMSTATE_BOOL(running, NPCM7xxPWM),
752
+ VMSTATE_BOOL(inverted, NPCM7xxPWM),
753
+ VMSTATE_UINT8(index, NPCM7xxPWM),
754
+ VMSTATE_UINT32(cnr, NPCM7xxPWM),
755
+ VMSTATE_UINT32(cmr, NPCM7xxPWM),
756
+ VMSTATE_UINT32(pdr, NPCM7xxPWM),
757
+ VMSTATE_UINT32(pwdr, NPCM7xxPWM),
758
+ VMSTATE_UINT32(freq, NPCM7xxPWM),
759
+ VMSTATE_UINT32(duty, NPCM7xxPWM),
760
+ VMSTATE_END_OF_LIST(),
761
+ },
762
+};
763
+
764
+static const VMStateDescription vmstate_npcm7xx_pwm_module = {
765
+ .name = "npcm7xx-pwm-module",
766
+ .version_id = 0,
767
+ .minimum_version_id = 0,
768
+ .fields = (VMStateField[]) {
769
+ VMSTATE_CLOCK(clock, NPCM7xxPWMState),
770
+ VMSTATE_STRUCT_ARRAY(pwm, NPCM7xxPWMState,
771
+ NPCM7XX_PWM_PER_MODULE, 0, vmstate_npcm7xx_pwm,
772
+ NPCM7xxPWM),
773
+ VMSTATE_UINT32(ppr, NPCM7xxPWMState),
774
+ VMSTATE_UINT32(csr, NPCM7xxPWMState),
775
+ VMSTATE_UINT32(pcr, NPCM7xxPWMState),
776
+ VMSTATE_UINT32(pier, NPCM7xxPWMState),
777
+ VMSTATE_UINT32(piir, NPCM7xxPWMState),
778
+ VMSTATE_END_OF_LIST(),
779
+ },
780
+};
781
+
782
+static void npcm7xx_pwm_class_init(ObjectClass *klass, void *data)
783
+{
784
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
785
+ DeviceClass *dc = DEVICE_CLASS(klass);
786
+
787
+ dc->desc = "NPCM7xx PWM Controller";
788
+ dc->vmsd = &vmstate_npcm7xx_pwm_module;
789
+ rc->phases.enter = npcm7xx_pwm_enter_reset;
790
+ rc->phases.hold = npcm7xx_pwm_hold_reset;
791
+}
792
+
793
+static const TypeInfo npcm7xx_pwm_info = {
794
+ .name = TYPE_NPCM7XX_PWM,
795
+ .parent = TYPE_SYS_BUS_DEVICE,
796
+ .instance_size = sizeof(NPCM7xxPWMState),
797
+ .class_init = npcm7xx_pwm_class_init,
798
+ .instance_init = npcm7xx_pwm_init,
799
+};
800
+
801
+static void npcm7xx_pwm_register_type(void)
802
+{
803
+ type_register_static(&npcm7xx_pwm_info);
804
+}
805
+type_init(npcm7xx_pwm_register_type);
806
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
262
index XXXXXXX..XXXXXXX 100644
807
index XXXXXXX..XXXXXXX 100644
263
--- a/tests/tcg/aarch64/Makefile.target
808
--- a/hw/misc/meson.build
264
+++ b/tests/tcg/aarch64/Makefile.target
809
+++ b/hw/misc/meson.build
265
@@ -XXX,XX +XXX,XX @@ run-pauth-%: QEMU_OPTS += -cpu max
810
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
266
run-plugin-pauth-%: QEMU_OPTS += -cpu max
811
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
267
endif
812
'npcm7xx_clk.c',
268
813
'npcm7xx_gcr.c',
269
+# BTI Tests
814
+ 'npcm7xx_pwm.c',
270
+# bti-1 tests the elf notes, so we require special compiler support.
815
'npcm7xx_rng.c',
271
+ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_BTI),)
816
))
272
+AARCH64_TESTS += bti-1
817
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files(
273
+bti-1: CFLAGS += -mbranch-protection=standard
818
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
274
+bti-1: LDFLAGS += -nostdlib
819
index XXXXXXX..XXXXXXX 100644
275
+endif
820
--- a/hw/misc/trace-events
276
+# bti-2 tests PROT_BTI, so no special compiler support required.
821
+++ b/hw/misc/trace-events
277
+AARCH64_TESTS += bti-2
822
@@ -XXX,XX +XXX,XX @@ npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " valu
278
+
823
npcm7xx_rng_read(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
279
# Semihosting smoke test for linux-user
824
npcm7xx_rng_write(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
280
AARCH64_TESTS += semihosting
825
281
run-semihosting: semihosting
826
+# npcm7xx_pwm.c
282
diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh
827
+npcm7xx_pwm_read(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
283
index XXXXXXX..XXXXXXX 100755
828
+npcm7xx_pwm_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
284
--- a/tests/tcg/configure.sh
829
+npcm7xx_pwm_update_freq(const char *id, uint8_t index, uint32_t old_value, uint32_t new_value) "%s pwm[%u] Update Freq: old_freq: %u, new_freq: %u"
285
+++ b/tests/tcg/configure.sh
830
+npcm7xx_pwm_update_duty(const char *id, uint8_t index, uint32_t old_value, uint32_t new_value) "%s pwm[%u] Update Duty: old_duty: %u, new_duty: %u"
286
@@ -XXX,XX +XXX,XX @@ for target in $target_list; do
831
+
287
-march=armv8.3-a -o $TMPE $TMPC; then
832
# stm32f4xx_syscfg.c
288
echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak
833
stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d"
289
fi
834
stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
290
+ if do_compiler "$target_compiler" $target_compiler_cflags \
291
+ -mbranch-protection=standard -o $TMPE $TMPC; then
292
+ echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak
293
+ fi
294
;;
295
esac
296
297
--
835
--
298
2.20.1
836
2.20.1
299
837
300
838
diff view generated by jsdifflib
1
From: Havard Skinnemoen <hskinnemoen@google.com>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
This test exercises the various modes of the npcm7xx timer. In
3
We add a qtest for the PWM in the previous patch. It proves it works as
4
particular, it triggers the bug found by the fuzzer, as reported here:
4
expected.
5
5
6
https://lists.gnu.org/archive/html/qemu-devel/2020-09/msg02992.html
6
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
7
8
It also found several other bugs, especially related to interrupt
9
handling.
10
11
The test exercises all the timers in all the timer modules, which
12
expands to 180 test cases in total.
13
14
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
7
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
15
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
8
Signed-off-by: Hao Wu <wuhaotsh@google.com>
16
Message-id: 20201008232154.94221-2-hskinnemoen@google.com
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Message-id: 20210108190945.949196-6-wuhaotsh@google.com
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
---
12
---
19
tests/qtest/npcm7xx_timer-test.c | 562 +++++++++++++++++++++++++++++++
13
tests/qtest/npcm7xx_pwm-test.c | 490 +++++++++++++++++++++++++++++++++
20
tests/qtest/meson.build | 1 +
14
tests/qtest/meson.build | 1 +
21
2 files changed, 563 insertions(+)
15
2 files changed, 491 insertions(+)
22
create mode 100644 tests/qtest/npcm7xx_timer-test.c
16
create mode 100644 tests/qtest/npcm7xx_pwm-test.c
23
17
24
diff --git a/tests/qtest/npcm7xx_timer-test.c b/tests/qtest/npcm7xx_timer-test.c
18
diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c
25
new file mode 100644
19
new file mode 100644
26
index XXXXXXX..XXXXXXX
20
index XXXXXXX..XXXXXXX
27
--- /dev/null
21
--- /dev/null
28
+++ b/tests/qtest/npcm7xx_timer-test.c
22
+++ b/tests/qtest/npcm7xx_pwm-test.c
29
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@
30
+/*
24
+/*
31
+ * QTest testcase for the Nuvoton NPCM7xx Timer
25
+ * QTests for Nuvoton NPCM7xx PWM Modules.
32
+ *
26
+ *
33
+ * Copyright 2020 Google LLC
27
+ * Copyright 2020 Google LLC
34
+ *
28
+ *
35
+ * This program is free software; you can redistribute it and/or modify it
29
+ * This program is free software; you can redistribute it and/or modify it
36
+ * under the terms of the GNU General Public License as published by the
30
+ * under the terms of the GNU General Public License as published by the
...
...
42
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
36
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
43
+ * for more details.
37
+ * for more details.
44
+ */
38
+ */
45
+
39
+
46
+#include "qemu/osdep.h"
40
+#include "qemu/osdep.h"
47
+#include "qemu/timer.h"
41
+#include "qemu/bitops.h"
48
+#include "libqtest-single.h"
42
+#include "libqos/libqtest.h"
49
+
43
+#include "qapi/qmp/qdict.h"
50
+#define TIM_REF_HZ (25000000)
44
+#include "qapi/qmp/qnum.h"
51
+
45
+
52
+/* Bits in TCSRx */
46
+#define REF_HZ 25000000
53
+#define CEN BIT(30)
47
+
54
+#define IE BIT(29)
48
+/* Register field definitions. */
55
+#define MODE_ONESHOT (0 << 27)
49
+#define CH_EN BIT(0)
56
+#define MODE_PERIODIC (1 << 27)
50
+#define CH_INV BIT(2)
57
+#define CRST BIT(26)
51
+#define CH_MOD BIT(3)
58
+#define CACT BIT(25)
52
+
59
+#define PRESCALE(x) (x)
53
+/* Registers shared between all PWMs in a module */
60
+
54
+#define PPR 0x00
61
+/* Registers shared between all timers in a module. */
55
+#define CSR 0x04
62
+#define TISR 0x18
56
+#define PCR 0x08
63
+#define WTCR 0x1c
57
+#define PIER 0x3c
64
+# define WTCLK(x) ((x) << 10)
58
+#define PIIR 0x40
65
+
59
+
66
+/* Power-on default; used to re-initialize timers before each test. */
60
+/* CLK module related */
67
+#define TCSR_DEFAULT PRESCALE(5)
61
+#define CLK_BA 0xf0801000
68
+
62
+#define CLKSEL 0x04
69
+/* Register offsets for a timer within a timer block. */
63
+#define CLKDIV1 0x08
70
+typedef struct Timer {
64
+#define CLKDIV2 0x2c
71
+ unsigned int tcsr_offset;
65
+#define PLLCON0 0x0c
72
+ unsigned int ticr_offset;
66
+#define PLLCON1 0x10
73
+ unsigned int tdr_offset;
67
+#define PLL_INDV(rv) extract32((rv), 0, 6)
74
+} Timer;
68
+#define PLL_FBDV(rv) extract32((rv), 16, 12)
75
+
69
+#define PLL_OTDV1(rv) extract32((rv), 8, 3)
76
+/* A timer block containing 5 timers. */
70
+#define PLL_OTDV2(rv) extract32((rv), 13, 3)
77
+typedef struct TimerBlock {
71
+#define APB3CKDIV(rv) extract32((rv), 28, 2)
78
+ int irq_base;
72
+#define CLK2CKDIV(rv) extract32((rv), 0, 1)
73
+#define CLK4CKDIV(rv) extract32((rv), 26, 2)
74
+#define CPUCKSEL(rv) extract32((rv), 0, 2)
75
+
76
+#define MAX_DUTY 1000000
77
+
78
+typedef struct PWMModule {
79
+ int irq;
79
+ uint64_t base_addr;
80
+ uint64_t base_addr;
80
+} TimerBlock;
81
+} PWMModule;
81
+
82
+
82
+/* Testdata for testing a particular timer within a timer block. */
83
+typedef struct PWM {
84
+ uint32_t cnr_offset;
85
+ uint32_t cmr_offset;
86
+ uint32_t pdr_offset;
87
+ uint32_t pwdr_offset;
88
+} PWM;
89
+
83
+typedef struct TestData {
90
+typedef struct TestData {
84
+ const TimerBlock *tim;
91
+ const PWMModule *module;
85
+ const Timer *timer;
92
+ const PWM *pwm;
86
+} TestData;
93
+} TestData;
87
+
94
+
88
+const TimerBlock timer_block[] = {
95
+static const PWMModule pwm_module_list[] = {
89
+ {
96
+ {
90
+ .irq_base = 32,
97
+ .irq = 93,
91
+ .base_addr = 0xf0008000,
98
+ .base_addr = 0xf0103000
92
+ },
99
+ },
93
+ {
100
+ {
94
+ .irq_base = 37,
101
+ .irq = 94,
95
+ .base_addr = 0xf0009000,
102
+ .base_addr = 0xf0104000
103
+ }
104
+};
105
+
106
+static const PWM pwm_list[] = {
107
+ {
108
+ .cnr_offset = 0x0c,
109
+ .cmr_offset = 0x10,
110
+ .pdr_offset = 0x14,
111
+ .pwdr_offset = 0x44,
96
+ },
112
+ },
97
+ {
113
+ {
98
+ .irq_base = 42,
114
+ .cnr_offset = 0x18,
99
+ .base_addr = 0xf000a000,
115
+ .cmr_offset = 0x1c,
116
+ .pdr_offset = 0x20,
117
+ .pwdr_offset = 0x48,
118
+ },
119
+ {
120
+ .cnr_offset = 0x24,
121
+ .cmr_offset = 0x28,
122
+ .pdr_offset = 0x2c,
123
+ .pwdr_offset = 0x4c,
124
+ },
125
+ {
126
+ .cnr_offset = 0x30,
127
+ .cmr_offset = 0x34,
128
+ .pdr_offset = 0x38,
129
+ .pwdr_offset = 0x50,
100
+ },
130
+ },
101
+};
131
+};
102
+
132
+
103
+const Timer timer[] = {
133
+static const int ppr_base[] = { 0, 0, 8, 8 };
104
+ {
134
+static const int csr_base[] = { 0, 4, 8, 12 };
105
+ .tcsr_offset = 0x00,
135
+static const int pcr_base[] = { 0, 8, 12, 16 };
106
+ .ticr_offset = 0x08,
136
+
107
+ .tdr_offset = 0x10,
137
+static const uint32_t ppr_list[] = {
108
+ }, {
138
+ 0,
109
+ .tcsr_offset = 0x04,
139
+ 1,
110
+ .ticr_offset = 0x0c,
140
+ 10,
111
+ .tdr_offset = 0x14,
141
+ 100,
112
+ }, {
142
+ 255, /* Max possible value. */
113
+ .tcsr_offset = 0x20,
114
+ .ticr_offset = 0x28,
115
+ .tdr_offset = 0x30,
116
+ }, {
117
+ .tcsr_offset = 0x24,
118
+ .ticr_offset = 0x2c,
119
+ .tdr_offset = 0x34,
120
+ }, {
121
+ .tcsr_offset = 0x40,
122
+ .ticr_offset = 0x48,
123
+ .tdr_offset = 0x50,
124
+ },
125
+};
143
+};
126
+
144
+
127
+/* Returns the index of the timer block. */
145
+static const uint32_t csr_list[] = {
128
+static int tim_index(const TimerBlock *tim)
146
+ 0,
129
+{
147
+ 1,
130
+ ptrdiff_t diff = tim - timer_block;
148
+ 2,
131
+
149
+ 3,
132
+ g_assert(diff >= 0 && diff < ARRAY_SIZE(timer_block));
150
+ 4, /* Max possible value. */
151
+};
152
+
153
+static const uint32_t cnr_list[] = {
154
+ 0,
155
+ 1,
156
+ 50,
157
+ 100,
158
+ 150,
159
+ 200,
160
+ 1000,
161
+ 10000,
162
+ 65535, /* Max possible value. */
163
+};
164
+
165
+static const uint32_t cmr_list[] = {
166
+ 0,
167
+ 1,
168
+ 10,
169
+ 50,
170
+ 100,
171
+ 150,
172
+ 200,
173
+ 1000,
174
+ 10000,
175
+ 65535, /* Max possible value. */
176
+};
177
+
178
+/* Returns the index of the PWM module. */
179
+static int pwm_module_index(const PWMModule *module)
180
+{
181
+ ptrdiff_t diff = module - pwm_module_list;
182
+
183
+ g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_module_list));
133
+
184
+
134
+ return diff;
185
+ return diff;
135
+}
186
+}
136
+
187
+
137
+/* Returns the index of a timer within a timer block. */
188
+/* Returns the index of the PWM entry. */
138
+static int timer_index(const Timer *t)
189
+static int pwm_index(const PWM *pwm)
139
+{
190
+{
140
+ ptrdiff_t diff = t - timer;
191
+ ptrdiff_t diff = pwm - pwm_list;
141
+
192
+
142
+ g_assert(diff >= 0 && diff < ARRAY_SIZE(timer));
193
+ g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_list));
143
+
194
+
144
+ return diff;
195
+ return diff;
145
+}
196
+}
146
+
197
+
147
+/* Returns the irq line for a given timer. */
198
+static uint64_t pwm_qom_get(QTestState *qts, const char *path, const char *name)
148
+static int tim_timer_irq(const TestData *td)
199
+{
149
+{
200
+ QDict *response;
150
+ return td->tim->irq_base + timer_index(td->timer);
201
+
151
+}
202
+ g_test_message("Getting properties %s from %s", name, path);
152
+
203
+ response = qtest_qmp(qts, "{ 'execute': 'qom-get',"
153
+/* Register read/write accessors. */
204
+ " 'arguments': { 'path': %s, 'property': %s}}",
154
+
205
+ path, name);
155
+static void tim_write(const TestData *td,
206
+ /* The qom set message returns successfully. */
156
+ unsigned int offset, uint32_t value)
207
+ g_assert_true(qdict_haskey(response, "return"));
157
+{
208
+ return qnum_get_uint(qobject_to(QNum, qdict_get(response, "return")));
158
+ writel(td->tim->base_addr + offset, value);
209
+}
159
+}
210
+
160
+
211
+static uint64_t pwm_get_freq(QTestState *qts, int module_index, int pwm_index)
161
+static uint32_t tim_read(const TestData *td, unsigned int offset)
212
+{
162
+{
213
+ char path[100];
163
+ return readl(td->tim->base_addr + offset);
214
+ char name[100];
164
+}
215
+
165
+
216
+ sprintf(path, "/machine/soc/pwm[%d]", module_index);
166
+static void tim_write_tcsr(const TestData *td, uint32_t value)
217
+ sprintf(name, "freq[%d]", pwm_index);
167
+{
218
+
168
+ tim_write(td, td->timer->tcsr_offset, value);
219
+ return pwm_qom_get(qts, path, name);
169
+}
220
+}
170
+
221
+
171
+static uint32_t tim_read_tcsr(const TestData *td)
222
+static uint64_t pwm_get_duty(QTestState *qts, int module_index, int pwm_index)
172
+{
223
+{
173
+ return tim_read(td, td->timer->tcsr_offset);
224
+ char path[100];
174
+}
225
+ char name[100];
175
+
226
+
176
+static void tim_write_ticr(const TestData *td, uint32_t value)
227
+ sprintf(path, "/machine/soc/pwm[%d]", module_index);
177
+{
228
+ sprintf(name, "duty[%d]", pwm_index);
178
+ tim_write(td, td->timer->ticr_offset, value);
229
+
179
+}
230
+ return pwm_qom_get(qts, path, name);
180
+
231
+}
181
+static uint32_t tim_read_ticr(const TestData *td)
232
+
182
+{
233
+static uint32_t get_pll(uint32_t con)
183
+ return tim_read(td, td->timer->ticr_offset);
234
+{
184
+}
235
+ return REF_HZ * PLL_FBDV(con) / (PLL_INDV(con) * PLL_OTDV1(con)
185
+
236
+ * PLL_OTDV2(con));
186
+static uint32_t tim_read_tdr(const TestData *td)
237
+}
187
+{
238
+
188
+ return tim_read(td, td->timer->tdr_offset);
239
+static uint64_t read_pclk(QTestState *qts)
189
+}
240
+{
190
+
241
+ uint64_t freq = REF_HZ;
191
+/* Returns the number of nanoseconds to count the given number of cycles. */
242
+ uint32_t clksel = qtest_readl(qts, CLK_BA + CLKSEL);
192
+static int64_t tim_calculate_step(uint32_t count, uint32_t prescale)
243
+ uint32_t pllcon;
193
+{
244
+ uint32_t clkdiv1 = qtest_readl(qts, CLK_BA + CLKDIV1);
194
+ return (1000000000LL / TIM_REF_HZ) * count * (prescale + 1);
245
+ uint32_t clkdiv2 = qtest_readl(qts, CLK_BA + CLKDIV2);
195
+}
246
+
196
+
247
+ switch (CPUCKSEL(clksel)) {
197
+/* Returns a bitmask corresponding to the timer under test. */
248
+ case 0:
198
+static uint32_t tim_timer_bit(const TestData *td)
249
+ pllcon = qtest_readl(qts, CLK_BA + PLLCON0);
199
+{
250
+ freq = get_pll(pllcon);
200
+ return BIT(timer_index(td->timer));
251
+ break;
201
+}
252
+ case 1:
202
+
253
+ pllcon = qtest_readl(qts, CLK_BA + PLLCON1);
203
+/* Resets all timers to power-on defaults. */
254
+ freq = get_pll(pllcon);
204
+static void tim_reset(const TestData *td)
255
+ break;
205
+{
256
+ case 2:
257
+ break;
258
+ case 3:
259
+ break;
260
+ default:
261
+ g_assert_not_reached();
262
+ }
263
+
264
+ freq >>= (CLK2CKDIV(clkdiv1) + CLK4CKDIV(clkdiv1) + APB3CKDIV(clkdiv2));
265
+
266
+ return freq;
267
+}
268
+
269
+static uint32_t pwm_selector(uint32_t csr)
270
+{
271
+ switch (csr) {
272
+ case 0:
273
+ return 2;
274
+ case 1:
275
+ return 4;
276
+ case 2:
277
+ return 8;
278
+ case 3:
279
+ return 16;
280
+ case 4:
281
+ return 1;
282
+ default:
283
+ g_assert_not_reached();
284
+ }
285
+}
286
+
287
+static uint64_t pwm_compute_freq(QTestState *qts, uint32_t ppr, uint32_t csr,
288
+ uint32_t cnr)
289
+{
290
+ return read_pclk(qts) / ((ppr + 1) * pwm_selector(csr) * (cnr + 1));
291
+}
292
+
293
+static uint64_t pwm_compute_duty(uint32_t cnr, uint32_t cmr, bool inverted)
294
+{
295
+ uint64_t duty;
296
+
297
+ if (cnr == 0) {
298
+ /* PWM is stopped. */
299
+ duty = 0;
300
+ } else if (cmr >= cnr) {
301
+ duty = MAX_DUTY;
302
+ } else {
303
+ duty = MAX_DUTY * (cmr + 1) / (cnr + 1);
304
+ }
305
+
306
+ if (inverted) {
307
+ duty = MAX_DUTY - duty;
308
+ }
309
+
310
+ return duty;
311
+}
312
+
313
+static uint32_t pwm_read(QTestState *qts, const TestData *td, unsigned offset)
314
+{
315
+ return qtest_readl(qts, td->module->base_addr + offset);
316
+}
317
+
318
+static void pwm_write(QTestState *qts, const TestData *td, unsigned offset,
319
+ uint32_t value)
320
+{
321
+ qtest_writel(qts, td->module->base_addr + offset, value);
322
+}
323
+
324
+static uint32_t pwm_read_ppr(QTestState *qts, const TestData *td)
325
+{
326
+ return extract32(pwm_read(qts, td, PPR), ppr_base[pwm_index(td->pwm)], 8);
327
+}
328
+
329
+static void pwm_write_ppr(QTestState *qts, const TestData *td, uint32_t value)
330
+{
331
+ pwm_write(qts, td, PPR, value << ppr_base[pwm_index(td->pwm)]);
332
+}
333
+
334
+static uint32_t pwm_read_csr(QTestState *qts, const TestData *td)
335
+{
336
+ return extract32(pwm_read(qts, td, CSR), csr_base[pwm_index(td->pwm)], 3);
337
+}
338
+
339
+static void pwm_write_csr(QTestState *qts, const TestData *td, uint32_t value)
340
+{
341
+ pwm_write(qts, td, CSR, value << csr_base[pwm_index(td->pwm)]);
342
+}
343
+
344
+static uint32_t pwm_read_pcr(QTestState *qts, const TestData *td)
345
+{
346
+ return extract32(pwm_read(qts, td, PCR), pcr_base[pwm_index(td->pwm)], 4);
347
+}
348
+
349
+static void pwm_write_pcr(QTestState *qts, const TestData *td, uint32_t value)
350
+{
351
+ pwm_write(qts, td, PCR, value << pcr_base[pwm_index(td->pwm)]);
352
+}
353
+
354
+static uint32_t pwm_read_cnr(QTestState *qts, const TestData *td)
355
+{
356
+ return pwm_read(qts, td, td->pwm->cnr_offset);
357
+}
358
+
359
+static void pwm_write_cnr(QTestState *qts, const TestData *td, uint32_t value)
360
+{
361
+ pwm_write(qts, td, td->pwm->cnr_offset, value);
362
+}
363
+
364
+static uint32_t pwm_read_cmr(QTestState *qts, const TestData *td)
365
+{
366
+ return pwm_read(qts, td, td->pwm->cmr_offset);
367
+}
368
+
369
+static void pwm_write_cmr(QTestState *qts, const TestData *td, uint32_t value)
370
+{
371
+ pwm_write(qts, td, td->pwm->cmr_offset, value);
372
+}
373
+
374
+/* Check pwm registers can be reset to default value */
375
+static void test_init(gconstpointer test_data)
376
+{
377
+ const TestData *td = test_data;
378
+ QTestState *qts = qtest_init("-machine quanta-gsj");
379
+ int module = pwm_module_index(td->module);
380
+ int pwm = pwm_index(td->pwm);
381
+
382
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
383
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
384
+
385
+ qtest_quit(qts);
386
+}
387
+
388
+/* One-shot mode should not change frequency and duty cycle. */
389
+static void test_oneshot(gconstpointer test_data)
390
+{
391
+ const TestData *td = test_data;
392
+ QTestState *qts = qtest_init("-machine quanta-gsj");
393
+ int module = pwm_module_index(td->module);
394
+ int pwm = pwm_index(td->pwm);
395
+ uint32_t ppr, csr, pcr;
206
+ int i, j;
396
+ int i, j;
207
+
397
+
208
+ /* Reset all the timers, in case a previous test left a timer running. */
398
+ pcr = CH_EN;
209
+ for (i = 0; i < ARRAY_SIZE(timer_block); i++) {
399
+ for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
210
+ for (j = 0; j < ARRAY_SIZE(timer); j++) {
400
+ ppr = ppr_list[i];
211
+ writel(timer_block[i].base_addr + timer[j].tcsr_offset,
401
+ pwm_write_ppr(qts, td, ppr);
212
+ CRST | TCSR_DEFAULT);
402
+
403
+ for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
404
+ csr = csr_list[j];
405
+ pwm_write_csr(qts, td, csr);
406
+ pwm_write_pcr(qts, td, pcr);
407
+
408
+ g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
409
+ g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
410
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
411
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
412
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
213
+ }
413
+ }
214
+ writel(timer_block[i].base_addr + TISR, -1);
414
+ }
215
+ }
415
+
216
+}
416
+ qtest_quit(qts);
217
+
417
+}
218
+/* Verifies the reset state of a timer. */
418
+
219
+static void test_reset(gconstpointer test_data)
419
+/* In toggle mode, the PWM generates correct outputs. */
420
+static void test_toggle(gconstpointer test_data)
220
+{
421
+{
221
+ const TestData *td = test_data;
422
+ const TestData *td = test_data;
222
+
423
+ QTestState *qts = qtest_init("-machine quanta-gsj");
223
+ tim_reset(td);
424
+ int module = pwm_module_index(td->module);
224
+
425
+ int pwm = pwm_index(td->pwm);
225
+ g_assert_cmphex(tim_read_tcsr(td), ==, TCSR_DEFAULT);
426
+ uint32_t ppr, csr, pcr, cnr, cmr;
226
+ g_assert_cmphex(tim_read_ticr(td), ==, 0);
427
+ int i, j, k, l;
227
+ g_assert_cmphex(tim_read_tdr(td), ==, 0);
428
+ uint64_t expected_freq, expected_duty;
228
+ g_assert_cmphex(tim_read(td, TISR), ==, 0);
429
+
229
+ g_assert_cmphex(tim_read(td, WTCR), ==, WTCLK(1));
430
+ pcr = CH_EN | CH_MOD;
230
+}
431
+ for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
231
+
432
+ ppr = ppr_list[i];
232
+/* Verifies that CRST wins if both CEN and CRST are set. */
433
+ pwm_write_ppr(qts, td, ppr);
233
+static void test_reset_overrides_enable(gconstpointer test_data)
434
+
234
+{
435
+ for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
235
+ const TestData *td = test_data;
436
+ csr = csr_list[j];
236
+
437
+ pwm_write_csr(qts, td, csr);
237
+ tim_reset(td);
438
+
238
+
439
+ for (k = 0; k < ARRAY_SIZE(cnr_list); ++k) {
239
+ /* CRST should force CEN to 0 */
440
+ cnr = cnr_list[k];
240
+ tim_write_tcsr(td, CEN | CRST | TCSR_DEFAULT);
441
+ pwm_write_cnr(qts, td, cnr);
241
+
442
+
242
+ g_assert_cmphex(tim_read_tcsr(td), ==, TCSR_DEFAULT);
443
+ for (l = 0; l < ARRAY_SIZE(cmr_list); ++l) {
243
+ g_assert_cmphex(tim_read_tdr(td), ==, 0);
444
+ cmr = cmr_list[l];
244
+ g_assert_cmphex(tim_read(td, TISR), ==, 0);
445
+ pwm_write_cmr(qts, td, cmr);
245
+}
446
+ expected_freq = pwm_compute_freq(qts, ppr, csr, cnr);
246
+
447
+ expected_duty = pwm_compute_duty(cnr, cmr, false);
247
+/* Verifies the behavior when CEN is set and then cleared. */
448
+
248
+static void test_oneshot_enable_then_disable(gconstpointer test_data)
449
+ pwm_write_pcr(qts, td, pcr);
249
+{
450
+ g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
250
+ const TestData *td = test_data;
451
+ g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
251
+
452
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
252
+ tim_reset(td);
453
+ g_assert_cmpuint(pwm_read_cnr(qts, td), ==, cnr);
253
+
454
+ g_assert_cmpuint(pwm_read_cmr(qts, td), ==, cmr);
254
+ /* Enable the timer with zero initial count, then disable it again. */
455
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
255
+ tim_write_tcsr(td, CEN | TCSR_DEFAULT);
456
+ ==, expected_duty);
256
+ tim_write_tcsr(td, TCSR_DEFAULT);
457
+ if (expected_duty != 0 && expected_duty != 100) {
257
+
458
+ /* Duty cycle with 0 or 100 doesn't need frequency. */
258
+ g_assert_cmphex(tim_read_tcsr(td), ==, TCSR_DEFAULT);
459
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
259
+ g_assert_cmphex(tim_read_tdr(td), ==, 0);
460
+ ==, expected_freq);
260
+ /* Timer interrupt flag should be set, but interrupts are not enabled. */
461
+ }
261
+ g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
462
+
262
+ g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
463
+ /* Test inverted mode */
263
+}
464
+ expected_duty = pwm_compute_duty(cnr, cmr, true);
264
+
465
+ pwm_write_pcr(qts, td, pcr | CH_INV);
265
+/* Verifies that a one-shot timer fires when expected with prescaler 5. */
466
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr | CH_INV);
266
+static void test_oneshot_ps5(gconstpointer test_data)
467
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
267
+{
468
+ ==, expected_duty);
268
+ const TestData *td = test_data;
469
+ if (expected_duty != 0 && expected_duty != 100) {
269
+ unsigned int count = 256;
470
+ /* Duty cycle with 0 or 100 doesn't need frequency. */
270
+ unsigned int ps = 5;
471
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
271
+
472
+ ==, expected_freq);
272
+ tim_reset(td);
473
+ }
273
+
474
+
274
+ tim_write_ticr(td, count);
475
+ }
275
+ tim_write_tcsr(td, CEN | PRESCALE(ps));
476
+ }
276
+ g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps));
477
+ }
277
+ g_assert_cmpuint(tim_read_tdr(td), ==, count);
478
+ }
278
+
479
+
279
+ clock_step(tim_calculate_step(count, ps) - 1);
480
+ qtest_quit(qts);
280
+
481
+}
281
+ g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps));
482
+
282
+ g_assert_cmpuint(tim_read_tdr(td), <, count);
483
+static void pwm_add_test(const char *name, const TestData* td,
283
+ g_assert_cmphex(tim_read(td, TISR), ==, 0);
484
+ GTestDataFunc fn)
284
+
485
+{
285
+ clock_step(1);
486
+ g_autofree char *full_name = g_strdup_printf(
286
+
487
+ "npcm7xx_pwm/module[%d]/pwm[%d]/%s", pwm_module_index(td->module),
287
+ g_assert_cmphex(tim_read_tcsr(td), ==, PRESCALE(ps));
488
+ pwm_index(td->pwm), name);
288
+ g_assert_cmpuint(tim_read_tdr(td), ==, count);
289
+ g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
290
+ g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
291
+
292
+ /* Clear the interrupt flag. */
293
+ tim_write(td, TISR, tim_timer_bit(td));
294
+ g_assert_cmphex(tim_read(td, TISR), ==, 0);
295
+ g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
296
+
297
+ /* Verify that this isn't a periodic timer. */
298
+ clock_step(2 * tim_calculate_step(count, ps));
299
+ g_assert_cmphex(tim_read(td, TISR), ==, 0);
300
+ g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
301
+}
302
+
303
+/* Verifies that a one-shot timer fires when expected with prescaler 0. */
304
+static void test_oneshot_ps0(gconstpointer test_data)
305
+{
306
+ const TestData *td = test_data;
307
+ unsigned int count = 1;
308
+ unsigned int ps = 0;
309
+
310
+ tim_reset(td);
311
+
312
+ tim_write_ticr(td, count);
313
+ tim_write_tcsr(td, CEN | PRESCALE(ps));
314
+ g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps));
315
+ g_assert_cmpuint(tim_read_tdr(td), ==, count);
316
+
317
+ clock_step(tim_calculate_step(count, ps) - 1);
318
+
319
+ g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps));
320
+ g_assert_cmpuint(tim_read_tdr(td), <, count);
321
+ g_assert_cmphex(tim_read(td, TISR), ==, 0);
322
+
323
+ clock_step(1);
324
+
325
+ g_assert_cmphex(tim_read_tcsr(td), ==, PRESCALE(ps));
326
+ g_assert_cmpuint(tim_read_tdr(td), ==, count);
327
+ g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
328
+ g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
329
+}
330
+
331
+/* Verifies that a one-shot timer fires when expected with highest prescaler. */
332
+static void test_oneshot_ps255(gconstpointer test_data)
333
+{
334
+ const TestData *td = test_data;
335
+ unsigned int count = (1U << 24) - 1;
336
+ unsigned int ps = 255;
337
+
338
+ tim_reset(td);
339
+
340
+ tim_write_ticr(td, count);
341
+ tim_write_tcsr(td, CEN | PRESCALE(ps));
342
+ g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps));
343
+ g_assert_cmpuint(tim_read_tdr(td), ==, count);
344
+
345
+ clock_step(tim_calculate_step(count, ps) - 1);
346
+
347
+ g_assert_cmphex(tim_read_tcsr(td), ==, CEN | CACT | PRESCALE(ps));
348
+ g_assert_cmpuint(tim_read_tdr(td), <, count);
349
+ g_assert_cmphex(tim_read(td, TISR), ==, 0);
350
+
351
+ clock_step(1);
352
+
353
+ g_assert_cmphex(tim_read_tcsr(td), ==, PRESCALE(ps));
354
+ g_assert_cmpuint(tim_read_tdr(td), ==, count);
355
+ g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
356
+ g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
357
+}
358
+
359
+/* Verifies that a oneshot timer fires an interrupt when expected. */
360
+static void test_oneshot_interrupt(gconstpointer test_data)
361
+{
362
+ const TestData *td = test_data;
363
+ unsigned int count = 256;
364
+ unsigned int ps = 7;
365
+
366
+ tim_reset(td);
367
+
368
+ tim_write_ticr(td, count);
369
+ tim_write_tcsr(td, IE | CEN | MODE_ONESHOT | PRESCALE(ps));
370
+
371
+ clock_step_next();
372
+
373
+ g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
374
+ g_assert_true(qtest_get_irq(global_qtest, tim_timer_irq(td)));
375
+}
376
+
377
+/*
378
+ * Verifies that the timer can be paused and later resumed, and it still fires
379
+ * at the right moment.
380
+ */
381
+static void test_pause_resume(gconstpointer test_data)
382
+{
383
+ const TestData *td = test_data;
384
+ unsigned int count = 256;
385
+ unsigned int ps = 1;
386
+
387
+ tim_reset(td);
388
+
389
+ tim_write_ticr(td, count);
390
+ tim_write_tcsr(td, IE | CEN | MODE_ONESHOT | PRESCALE(ps));
391
+
392
+ /* Pause the timer halfway to expiration. */
393
+ clock_step(tim_calculate_step(count / 2, ps));
394
+ tim_write_tcsr(td, IE | MODE_ONESHOT | PRESCALE(ps));
395
+ g_assert_cmpuint(tim_read_tdr(td), ==, count / 2);
396
+
397
+ /* Counter should not advance during the following step. */
398
+ clock_step(2 * tim_calculate_step(count, ps));
399
+ g_assert_cmpuint(tim_read_tdr(td), ==, count / 2);
400
+ g_assert_cmphex(tim_read(td, TISR), ==, 0);
401
+ g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
402
+
403
+ /* Resume the timer and run _almost_ to expiration. */
404
+ tim_write_tcsr(td, IE | CEN | MODE_ONESHOT | PRESCALE(ps));
405
+ clock_step(tim_calculate_step(count / 2, ps) - 1);
406
+ g_assert_cmpuint(tim_read_tdr(td), <, count);
407
+ g_assert_cmphex(tim_read(td, TISR), ==, 0);
408
+ g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
409
+
410
+ /* Now, run the rest of the way and verify that the interrupt fires. */
411
+ clock_step(1);
412
+ g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
413
+ g_assert_true(qtest_get_irq(global_qtest, tim_timer_irq(td)));
414
+}
415
+
416
+/* Verifies that the prescaler can be changed while the timer is runnin. */
417
+static void test_prescaler_change(gconstpointer test_data)
418
+{
419
+ const TestData *td = test_data;
420
+ unsigned int count = 256;
421
+ unsigned int ps = 5;
422
+
423
+ tim_reset(td);
424
+
425
+ tim_write_ticr(td, count);
426
+ tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps));
427
+
428
+ /* Run a quarter of the way, and change the prescaler. */
429
+ clock_step(tim_calculate_step(count / 4, ps));
430
+ g_assert_cmpuint(tim_read_tdr(td), ==, 3 * count / 4);
431
+ ps = 2;
432
+ tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps));
433
+ /* The counter must not change. */
434
+ g_assert_cmpuint(tim_read_tdr(td), ==, 3 * count / 4);
435
+
436
+ /* Run another quarter of the way, and change the prescaler again. */
437
+ clock_step(tim_calculate_step(count / 4, ps));
438
+ g_assert_cmpuint(tim_read_tdr(td), ==, count / 2);
439
+ ps = 8;
440
+ tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps));
441
+ /* The counter must not change. */
442
+ g_assert_cmpuint(tim_read_tdr(td), ==, count / 2);
443
+
444
+ /* Run another quarter of the way, and change the prescaler again. */
445
+ clock_step(tim_calculate_step(count / 4, ps));
446
+ g_assert_cmpuint(tim_read_tdr(td), ==, count / 4);
447
+ ps = 0;
448
+ tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps));
449
+ /* The counter must not change. */
450
+ g_assert_cmpuint(tim_read_tdr(td), ==, count / 4);
451
+
452
+ /* Run almost to expiration, and verify the timer didn't fire yet. */
453
+ clock_step(tim_calculate_step(count / 4, ps) - 1);
454
+ g_assert_cmpuint(tim_read_tdr(td), <, count);
455
+ g_assert_cmphex(tim_read(td, TISR), ==, 0);
456
+
457
+ /* Now, run the rest of the way and verify that the timer fires. */
458
+ clock_step(1);
459
+ g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
460
+}
461
+
462
+/* Verifies that a periodic timer automatically restarts after expiration. */
463
+static void test_periodic_no_interrupt(gconstpointer test_data)
464
+{
465
+ const TestData *td = test_data;
466
+ unsigned int count = 2;
467
+ unsigned int ps = 3;
468
+ int i;
469
+
470
+ tim_reset(td);
471
+
472
+ tim_write_ticr(td, count);
473
+ tim_write_tcsr(td, CEN | MODE_PERIODIC | PRESCALE(ps));
474
+
475
+ for (i = 0; i < 4; i++) {
476
+ clock_step_next();
477
+
478
+ g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
479
+ g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
480
+
481
+ tim_write(td, TISR, tim_timer_bit(td));
482
+
483
+ g_assert_cmphex(tim_read(td, TISR), ==, 0);
484
+ g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
485
+ }
486
+}
487
+
488
+/* Verifies that a periodict timer fires an interrupt every time it expires. */
489
+static void test_periodic_interrupt(gconstpointer test_data)
490
+{
491
+ const TestData *td = test_data;
492
+ unsigned int count = 65535;
493
+ unsigned int ps = 2;
494
+ int i;
495
+
496
+ tim_reset(td);
497
+
498
+ tim_write_ticr(td, count);
499
+ tim_write_tcsr(td, CEN | IE | MODE_PERIODIC | PRESCALE(ps));
500
+
501
+ for (i = 0; i < 4; i++) {
502
+ clock_step_next();
503
+
504
+ g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
505
+ g_assert_true(qtest_get_irq(global_qtest, tim_timer_irq(td)));
506
+
507
+ tim_write(td, TISR, tim_timer_bit(td));
508
+
509
+ g_assert_cmphex(tim_read(td, TISR), ==, 0);
510
+ g_assert_false(qtest_get_irq(global_qtest, tim_timer_irq(td)));
511
+ }
512
+}
513
+
514
+/*
515
+ * Verifies that the timer behaves correctly when disabled right before and
516
+ * exactly when it's supposed to expire.
517
+ */
518
+static void test_disable_on_expiration(gconstpointer test_data)
519
+{
520
+ const TestData *td = test_data;
521
+ unsigned int count = 8;
522
+ unsigned int ps = 255;
523
+
524
+ tim_reset(td);
525
+
526
+ tim_write_ticr(td, count);
527
+ tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps));
528
+
529
+ clock_step(tim_calculate_step(count, ps) - 1);
530
+
531
+ tim_write_tcsr(td, MODE_ONESHOT | PRESCALE(ps));
532
+ tim_write_tcsr(td, CEN | MODE_ONESHOT | PRESCALE(ps));
533
+ clock_step(1);
534
+ tim_write_tcsr(td, MODE_ONESHOT | PRESCALE(ps));
535
+ g_assert_cmphex(tim_read(td, TISR), ==, tim_timer_bit(td));
536
+}
537
+
538
+/*
539
+ * Constructs a name that includes the timer block, timer and testcase name,
540
+ * and adds the test to the test suite.
541
+ */
542
+static void tim_add_test(const char *name, const TestData *td, GTestDataFunc fn)
543
+{
544
+ g_autofree char *full_name;
545
+
546
+ full_name = g_strdup_printf("npcm7xx_timer/tim[%d]/timer[%d]/%s",
547
+ tim_index(td->tim), timer_index(td->timer),
548
+ name);
549
+ qtest_add_data_func(full_name, td, fn);
489
+ qtest_add_data_func(full_name, td, fn);
550
+}
490
+}
551
+
491
+#define add_test(name, td) pwm_add_test(#name, td, test_##name)
552
+/* Convenience macro for adding a test with a predictable function name. */
553
+#define add_test(name, td) tim_add_test(#name, td, test_##name)
554
+
492
+
555
+int main(int argc, char **argv)
493
+int main(int argc, char **argv)
556
+{
494
+{
557
+ TestData testdata[ARRAY_SIZE(timer_block) * ARRAY_SIZE(timer)];
495
+ TestData test_data_list[ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list)];
558
+ int ret;
559
+ int i, j;
560
+
496
+
561
+ g_test_init(&argc, &argv, NULL);
497
+ g_test_init(&argc, &argv, NULL);
562
+ g_test_set_nonfatal_assertions();
498
+
563
+
499
+ for (int i = 0; i < ARRAY_SIZE(pwm_module_list); ++i) {
564
+ for (i = 0; i < ARRAY_SIZE(timer_block); i++) {
500
+ for (int j = 0; j < ARRAY_SIZE(pwm_list); ++j) {
565
+ for (j = 0; j < ARRAY_SIZE(timer); j++) {
501
+ TestData *td = &test_data_list[i * ARRAY_SIZE(pwm_list) + j];
566
+ TestData *td = &testdata[i * ARRAY_SIZE(timer) + j];
502
+
567
+ td->tim = &timer_block[i];
503
+ td->module = &pwm_module_list[i];
568
+ td->timer = &timer[j];
504
+ td->pwm = &pwm_list[j];
569
+
505
+
570
+ add_test(reset, td);
506
+ add_test(init, td);
571
+ add_test(reset_overrides_enable, td);
507
+ add_test(oneshot, td);
572
+ add_test(oneshot_enable_then_disable, td);
508
+ add_test(toggle, td);
573
+ add_test(oneshot_ps5, td);
574
+ add_test(oneshot_ps0, td);
575
+ add_test(oneshot_ps255, td);
576
+ add_test(oneshot_interrupt, td);
577
+ add_test(pause_resume, td);
578
+ add_test(prescaler_change, td);
579
+ add_test(periodic_no_interrupt, td);
580
+ add_test(periodic_interrupt, td);
581
+ add_test(disable_on_expiration, td);
582
+ }
509
+ }
583
+ }
510
+ }
584
+
511
+
585
+ qtest_start("-machine npcm750-evb");
512
+ return g_test_run();
586
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/a9mpcore/gic");
587
+ ret = g_test_run();
588
+ qtest_end();
589
+
590
+ return ret;
591
+}
513
+}
592
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
514
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
593
index XXXXXXX..XXXXXXX 100644
515
index XXXXXXX..XXXXXXX 100644
594
--- a/tests/qtest/meson.build
516
--- a/tests/qtest/meson.build
595
+++ b/tests/qtest/meson.build
517
+++ b/tests/qtest/meson.build
596
@@ -XXX,XX +XXX,XX @@ qtests_arm = \
518
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
597
['arm-cpu-features',
519
qtests_npcm7xx = \
598
'microbit-test',
520
['npcm7xx_adc-test',
599
'm25p80-test',
521
'npcm7xx_gpio-test',
600
+ 'npcm7xx_timer-test',
522
+ 'npcm7xx_pwm-test',
601
'test-arm-mptimer',
523
'npcm7xx_rng-test',
602
'boot-serial-test',
524
'npcm7xx_timer-test',
603
'hexloader-test']
525
'npcm7xx_watchdog_timer-test']
604
--
526
--
605
2.20.1
527
2.20.1
606
528
607
529
diff view generated by jsdifflib
Deleted patch
1
From: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
2
1
3
Current documentation is not too clear on the GETPC usage.
4
In particular, when used outside the top level helper function
5
it causes unexpected behavior.
6
7
Signed-off-by: Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
8
Message-id: 20201015095147.1691-1-e.emanuelegiuseppe@gmail.com
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
docs/devel/loads-stores.rst | 8 +++++++-
13
1 file changed, 7 insertions(+), 1 deletion(-)
14
15
diff --git a/docs/devel/loads-stores.rst b/docs/devel/loads-stores.rst
16
index XXXXXXX..XXXXXXX 100644
17
--- a/docs/devel/loads-stores.rst
18
+++ b/docs/devel/loads-stores.rst
19
@@ -XXX,XX +XXX,XX @@ guest CPU state in case of a guest CPU exception. This is passed
20
to ``cpu_restore_state()``. Therefore the value should either be 0,
21
to indicate that the guest CPU state is already synchronized, or
22
the result of ``GETPC()`` from the top level ``HELPER(foo)``
23
-function, which is a return address into the generated code.
24
+function, which is a return address into the generated code [#gpc]_.
25
+
26
+.. [#gpc] Note that ``GETPC()`` should be used with great care: calling
27
+ it in other functions that are *not* the top level
28
+ ``HELPER(foo)`` will cause unexpected behavior. Instead, the
29
+ value of ``GETPC()`` should be read from the helper and passed
30
+ if needed to the functions that the helper calls.
31
32
Function names follow the pattern:
33
34
--
35
2.20.1
36
37
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
1
3
Add trace events for GPU and CPU IRQs.
4
5
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
6
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Message-id: 20201017180731.1165871-2-f4bug@amsat.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
hw/intc/bcm2835_ic.c | 4 +++-
11
hw/intc/trace-events | 4 ++++
12
2 files changed, 7 insertions(+), 1 deletion(-)
13
14
diff --git a/hw/intc/bcm2835_ic.c b/hw/intc/bcm2835_ic.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/intc/bcm2835_ic.c
17
+++ b/hw/intc/bcm2835_ic.c
18
@@ -XXX,XX +XXX,XX @@
19
#include "migration/vmstate.h"
20
#include "qemu/log.h"
21
#include "qemu/module.h"
22
+#include "trace.h"
23
24
#define GPU_IRQS 64
25
#define ARM_IRQS 8
26
@@ -XXX,XX +XXX,XX @@ static void bcm2835_ic_update(BCM2835ICState *s)
27
set = (s->gpu_irq_level & s->gpu_irq_enable)
28
|| (s->arm_irq_level & s->arm_irq_enable);
29
qemu_set_irq(s->irq, set);
30
-
31
}
32
33
static void bcm2835_ic_set_gpu_irq(void *opaque, int irq, int level)
34
@@ -XXX,XX +XXX,XX @@ static void bcm2835_ic_set_gpu_irq(void *opaque, int irq, int level)
35
BCM2835ICState *s = opaque;
36
37
assert(irq >= 0 && irq < 64);
38
+ trace_bcm2835_ic_set_gpu_irq(irq, level);
39
s->gpu_irq_level = deposit64(s->gpu_irq_level, irq, 1, level != 0);
40
bcm2835_ic_update(s);
41
}
42
@@ -XXX,XX +XXX,XX @@ static void bcm2835_ic_set_arm_irq(void *opaque, int irq, int level)
43
BCM2835ICState *s = opaque;
44
45
assert(irq >= 0 && irq < 8);
46
+ trace_bcm2835_ic_set_cpu_irq(irq, level);
47
s->arm_irq_level = deposit32(s->arm_irq_level, irq, 1, level != 0);
48
bcm2835_ic_update(s);
49
}
50
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
51
index XXXXXXX..XXXXXXX 100644
52
--- a/hw/intc/trace-events
53
+++ b/hw/intc/trace-events
54
@@ -XXX,XX +XXX,XX @@ nvic_sysreg_write(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg wri
55
heathrow_write(uint64_t addr, unsigned int n, uint64_t value) "0x%"PRIx64" %u: 0x%"PRIx64
56
heathrow_read(uint64_t addr, unsigned int n, uint64_t value) "0x%"PRIx64" %u: 0x%"PRIx64
57
heathrow_set_irq(int num, int level) "set_irq: num=0x%02x level=%d"
58
+
59
+# bcm2835_ic.c
60
+bcm2835_ic_set_gpu_irq(int irq, int level) "GPU irq #%d level %d"
61
+bcm2835_ic_set_cpu_irq(int irq, int level) "CPU irq #%d level %d"
62
--
63
2.20.1
64
65
diff view generated by jsdifflib
Deleted patch
1
From: Richard Henderson <richard.henderson@linaro.org>
2
1
3
We already have the full ARMMMUIdx as computed from the
4
function parameter.
5
6
For the purpose of regime_has_2_ranges, we can ignore any
7
difference between AccType_Normal and AccType_Unpriv, which
8
would be the only difference between the passed mmu_idx
9
and arm_mmu_idx_el.
10
11
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
Reviewed-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
14
Tested-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
15
Message-id: 20201008162155.161886-2-richard.henderson@linaro.org
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
---
18
target/arm/mte_helper.c | 3 +--
19
1 file changed, 1 insertion(+), 2 deletions(-)
20
21
diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/target/arm/mte_helper.c
24
+++ b/target/arm/mte_helper.c
25
@@ -XXX,XX +XXX,XX @@ static void mte_check_fail(CPUARMState *env, uint32_t desc,
26
27
case 2:
28
/* Tag check fail causes asynchronous flag set. */
29
- mmu_idx = arm_mmu_idx_el(env, el);
30
- if (regime_has_2_ranges(mmu_idx)) {
31
+ if (regime_has_2_ranges(arm_mmu_idx)) {
32
select = extract64(dirty_ptr, 55, 1);
33
} else {
34
select = 0;
35
--
36
2.20.1
37
38
diff view generated by jsdifflib
Deleted patch
1
From: Richard Henderson <richard.henderson@linaro.org>
2
1
3
The reporting in AArch64.TagCheckFail only depends on PSTATE.EL,
4
and not the AccType of the operation. There are two guest
5
visible problems that affect LDTR and STTR because of this:
6
7
(1) Selecting TCF0 vs TCF1 to decide on reporting,
8
(2) Report "data abort same el" not "data abort lower el".
9
10
Reported-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
11
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
Reviewed-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
13
Tested-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
14
Message-id: 20201008162155.161886-3-richard.henderson@linaro.org
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
17
target/arm/mte_helper.c | 10 +++-------
18
1 file changed, 3 insertions(+), 7 deletions(-)
19
20
diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/target/arm/mte_helper.c
23
+++ b/target/arm/mte_helper.c
24
@@ -XXX,XX +XXX,XX @@ static void mte_check_fail(CPUARMState *env, uint32_t desc,
25
reg_el = regime_el(env, arm_mmu_idx);
26
sctlr = env->cp15.sctlr_el[reg_el];
27
28
- switch (arm_mmu_idx) {
29
- case ARMMMUIdx_E10_0:
30
- case ARMMMUIdx_E20_0:
31
- el = 0;
32
+ el = arm_current_el(env);
33
+ if (el == 0) {
34
tcf = extract64(sctlr, 38, 2);
35
- break;
36
- default:
37
- el = reg_el;
38
+ } else {
39
tcf = extract64(sctlr, 40, 2);
40
}
41
42
--
43
2.20.1
44
45
diff view generated by jsdifflib
Deleted patch
1
From: Richard Henderson <richard.henderson@linaro.org>
2
1
3
Unlike many other bits in HCR_EL2, the description for this
4
bit does not contain the phrase "if ... this field behaves
5
as 0 for all purposes other than", so do not squash the bit
6
in arm_hcr_el2_eff.
7
8
Instead, replicate the E2H+TGE test in the two places that
9
require it.
10
11
Reported-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
12
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
13
Reviewed-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
14
Tested-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
15
Message-id: 20201008162155.161886-4-richard.henderson@linaro.org
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
---
18
target/arm/internals.h | 9 +++++----
19
target/arm/helper.c | 9 +++++----
20
2 files changed, 10 insertions(+), 8 deletions(-)
21
22
diff --git a/target/arm/internals.h b/target/arm/internals.h
23
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/internals.h
25
+++ b/target/arm/internals.h
26
@@ -XXX,XX +XXX,XX @@ static inline bool allocation_tag_access_enabled(CPUARMState *env, int el,
27
&& !(env->cp15.scr_el3 & SCR_ATA)) {
28
return false;
29
}
30
- if (el < 2
31
- && arm_feature(env, ARM_FEATURE_EL2)
32
- && !(arm_hcr_el2_eff(env) & HCR_ATA)) {
33
- return false;
34
+ if (el < 2 && arm_feature(env, ARM_FEATURE_EL2)) {
35
+ uint64_t hcr = arm_hcr_el2_eff(env);
36
+ if (!(hcr & HCR_ATA) && (!(hcr & HCR_E2H) || !(hcr & HCR_TGE))) {
37
+ return false;
38
+ }
39
}
40
sctlr &= (el == 0 ? SCTLR_ATA0 : SCTLR_ATA);
41
return sctlr != 0;
42
diff --git a/target/arm/helper.c b/target/arm/helper.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/target/arm/helper.c
45
+++ b/target/arm/helper.c
46
@@ -XXX,XX +XXX,XX @@ static CPAccessResult access_mte(CPUARMState *env, const ARMCPRegInfo *ri,
47
{
48
int el = arm_current_el(env);
49
50
- if (el < 2 &&
51
- arm_feature(env, ARM_FEATURE_EL2) &&
52
- !(arm_hcr_el2_eff(env) & HCR_ATA)) {
53
- return CP_ACCESS_TRAP_EL2;
54
+ if (el < 2 && arm_feature(env, ARM_FEATURE_EL2)) {
55
+ uint64_t hcr = arm_hcr_el2_eff(env);
56
+ if (!(hcr & HCR_ATA) && (!(hcr & HCR_E2H) || !(hcr & HCR_TGE))) {
57
+ return CP_ACCESS_TRAP_EL2;
58
+ }
59
}
60
if (el < 3 &&
61
arm_feature(env, ARM_FEATURE_EL3) &&
62
--
63
2.20.1
64
65
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
1
3
Commit 7998beb9c2e removed the ram_size initialization in the
4
arm_boot_info structure, however it is used by arm_load_kernel().
5
6
Initialize the field to fix:
7
8
$ qemu-system-arm -M n800 -append 'console=ttyS1' \
9
-kernel meego-arm-n8x0-1.0.80.20100712.1431-vmlinuz-2.6.35~rc4-129.1-n8x0
10
qemu-system-arm: kernel 'meego-arm-n8x0-1.0.80.20100712.1431-vmlinuz-2.6.35~rc4-129.1-n8x0' is too large to fit in RAM (kernel size 1964608, RAM size 0)
11
12
Noticed while running the test introduced in commit 050a82f0c5b
13
("tests/acceptance: Add a test for the N800 and N810 arm machines").
14
15
Fixes: 7998beb9c2e ("arm/nseries: use memdev for RAM")
16
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
17
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
18
Tested-by: Thomas Huth <thuth@redhat.com>
19
Message-id: 20201019095148.1602119-1-f4bug@amsat.org
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
---
22
hw/arm/nseries.c | 1 +
23
1 file changed, 1 insertion(+)
24
25
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/hw/arm/nseries.c
28
+++ b/hw/arm/nseries.c
29
@@ -XXX,XX +XXX,XX @@ static void n8x0_init(MachineState *machine,
30
g_free(sz);
31
exit(EXIT_FAILURE);
32
}
33
+ binfo->ram_size = machine->ram_size;
34
35
memory_region_add_subregion(get_system_memory(), OMAP2_Q2_BASE,
36
machine->ram);
37
--
38
2.20.1
39
40
diff view generated by jsdifflib
Deleted patch
1
v8.1M brings four new insns to M-profile:
2
* CSEL : Rd = cond ? Rn : Rm
3
* CSINC : Rd = cond ? Rn : Rm+1
4
* CSINV : Rd = cond ? Rn : ~Rm
5
* CSNEG : Rd = cond ? Rn : -Rm
6
1
7
Implement these.
8
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Message-id: 20201019151301.2046-4-peter.maydell@linaro.org
12
---
13
target/arm/t32.decode | 3 +++
14
target/arm/translate.c | 60 ++++++++++++++++++++++++++++++++++++++++++
15
2 files changed, 63 insertions(+)
16
17
diff --git a/target/arm/t32.decode b/target/arm/t32.decode
18
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/t32.decode
20
+++ b/target/arm/t32.decode
21
@@ -XXX,XX +XXX,XX @@ SBC_rrri 1110101 1011 . .... 0 ... .... .... .... @s_rrr_shi
22
}
23
RSB_rrri 1110101 1110 . .... 0 ... .... .... .... @s_rrr_shi
24
25
+# v8.1M CSEL and friends
26
+CSEL 1110101 0010 1 rn:4 10 op:2 rd:4 fcond:4 rm:4
27
+
28
# Data-processing (register-shifted register)
29
30
MOV_rxrr 1111 1010 0 shty:2 s:1 rm:4 1111 rd:4 0000 rs:4 \
31
diff --git a/target/arm/translate.c b/target/arm/translate.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/target/arm/translate.c
34
+++ b/target/arm/translate.c
35
@@ -XXX,XX +XXX,XX @@ static bool trans_IT(DisasContext *s, arg_IT *a)
36
return true;
37
}
38
39
+/* v8.1M CSEL/CSINC/CSNEG/CSINV */
40
+static bool trans_CSEL(DisasContext *s, arg_CSEL *a)
41
+{
42
+ TCGv_i32 rn, rm, zero;
43
+ DisasCompare c;
44
+
45
+ if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
46
+ return false;
47
+ }
48
+
49
+ if (a->rm == 13) {
50
+ /* SEE "Related encodings" (MVE shifts) */
51
+ return false;
52
+ }
53
+
54
+ if (a->rd == 13 || a->rd == 15 || a->rn == 13 || a->fcond >= 14) {
55
+ /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
56
+ return false;
57
+ }
58
+
59
+ /* In this insn input reg fields of 0b1111 mean "zero", not "PC" */
60
+ if (a->rn == 15) {
61
+ rn = tcg_const_i32(0);
62
+ } else {
63
+ rn = load_reg(s, a->rn);
64
+ }
65
+ if (a->rm == 15) {
66
+ rm = tcg_const_i32(0);
67
+ } else {
68
+ rm = load_reg(s, a->rm);
69
+ }
70
+
71
+ switch (a->op) {
72
+ case 0: /* CSEL */
73
+ break;
74
+ case 1: /* CSINC */
75
+ tcg_gen_addi_i32(rm, rm, 1);
76
+ break;
77
+ case 2: /* CSINV */
78
+ tcg_gen_not_i32(rm, rm);
79
+ break;
80
+ case 3: /* CSNEG */
81
+ tcg_gen_neg_i32(rm, rm);
82
+ break;
83
+ default:
84
+ g_assert_not_reached();
85
+ }
86
+
87
+ arm_test_cc(&c, a->fcond);
88
+ zero = tcg_const_i32(0);
89
+ tcg_gen_movcond_i32(c.cond, rn, c.value, zero, rn, rm);
90
+ arm_free_cc(&c);
91
+ tcg_temp_free_i32(zero);
92
+
93
+ store_reg(s, a->rd, rn);
94
+ tcg_temp_free_i32(rm);
95
+
96
+ return true;
97
+}
98
+
99
/*
100
* Legacy decoder.
101
*/
102
--
103
2.20.1
104
105
diff view generated by jsdifflib
Deleted patch
1
The t32 decode has a group which represents a set of insns
2
which overlap with B_cond_thumb because they have [25:23]=111
3
(which is an invalid condition code field for the branch insn).
4
This group is currently defined using the {} overlap-OK syntax,
5
but it is almost entirely non-overlapping patterns. Switch
6
it over to use a non-overlapping group.
7
1
8
For this to be valid syntactically, CPS must move into the same
9
overlapping-group as the hint insns (CPS vs hints was the
10
only actual use of the overlap facility for the group).
11
12
The non-overlapping subgroup for CLREX/DSB/DMB/ISB/SB is no longer
13
necessary and so we can remove it (promoting those insns to
14
be members of the parent group).
15
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
Message-id: 20201019151301.2046-5-peter.maydell@linaro.org
19
---
20
target/arm/t32.decode | 26 ++++++++++++--------------
21
1 file changed, 12 insertions(+), 14 deletions(-)
22
23
diff --git a/target/arm/t32.decode b/target/arm/t32.decode
24
index XXXXXXX..XXXXXXX 100644
25
--- a/target/arm/t32.decode
26
+++ b/target/arm/t32.decode
27
@@ -XXX,XX +XXX,XX @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
28
{
29
# Group insn[25:23] = 111, which is cond=111x for the branch below,
30
# or unconditional, which would be illegal for the branch.
31
- {
32
- # Hints
33
+ [
34
+ # Hints, and CPS
35
{
36
YIELD 1111 0011 1010 1111 1000 0000 0000 0001
37
WFE 1111 0011 1010 1111 1000 0000 0000 0010
38
@@ -XXX,XX +XXX,XX @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
39
# The canonical nop ends in 0000 0000, but the whole rest
40
# of the space is "reserved hint, behaves as nop".
41
NOP 1111 0011 1010 1111 1000 0000 ---- ----
42
+
43
+ # If imod == '00' && M == '0' then SEE "Hint instructions", above.
44
+ CPS 1111 0011 1010 1111 1000 0 imod:2 M:1 A:1 I:1 F:1 mode:5 \
45
+ &cps
46
}
47
48
- # If imod == '00' && M == '0' then SEE "Hint instructions", above.
49
- CPS 1111 0011 1010 1111 1000 0 imod:2 M:1 A:1 I:1 F:1 mode:5 \
50
- &cps
51
-
52
# Miscellaneous control
53
- [
54
- CLREX 1111 0011 1011 1111 1000 1111 0010 1111
55
- DSB 1111 0011 1011 1111 1000 1111 0100 ----
56
- DMB 1111 0011 1011 1111 1000 1111 0101 ----
57
- ISB 1111 0011 1011 1111 1000 1111 0110 ----
58
- SB 1111 0011 1011 1111 1000 1111 0111 0000
59
- ]
60
+ CLREX 1111 0011 1011 1111 1000 1111 0010 1111
61
+ DSB 1111 0011 1011 1111 1000 1111 0100 ----
62
+ DMB 1111 0011 1011 1111 1000 1111 0101 ----
63
+ ISB 1111 0011 1011 1111 1000 1111 0110 ----
64
+ SB 1111 0011 1011 1111 1000 1111 0111 0000
65
66
# Note that the v7m insn overlaps both the normal and banked insn.
67
{
68
@@ -XXX,XX +XXX,XX @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
69
HVC 1111 0111 1110 .... 1000 .... .... .... \
70
&i imm=%imm16_16_0
71
UDF 1111 0111 1111 ---- 1010 ---- ---- ----
72
- }
73
+ ]
74
B_cond_thumb 1111 0. cond:4 ...... 10.0 ............ &ci imm=%imm21
75
}
76
77
--
78
2.20.1
79
80
diff view generated by jsdifflib
Deleted patch
1
The BLX immediate insn in the Thumb encoding always performs
2
a switch from Thumb to Arm state. This would be totally useless
3
in M-profile which has no Arm decoder, and so the instruction
4
does not exist at all there. Make the encoding UNDEF for M-profile.
5
1
6
(This part of the encoding space is used for the branch-future
7
and low-overhead-loop insns in v8.1M.)
8
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Message-id: 20201019151301.2046-6-peter.maydell@linaro.org
12
---
13
target/arm/translate.c | 8 ++++++++
14
1 file changed, 8 insertions(+)
15
16
diff --git a/target/arm/translate.c b/target/arm/translate.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/translate.c
19
+++ b/target/arm/translate.c
20
@@ -XXX,XX +XXX,XX @@ static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
21
{
22
TCGv_i32 tmp;
23
24
+ /*
25
+ * BLX <imm> would be useless on M-profile; the encoding space
26
+ * is used for other insns from v8.1M onward, and UNDEFs before that.
27
+ */
28
+ if (arm_dc_feature(s, ARM_FEATURE_M)) {
29
+ return false;
30
+ }
31
+
32
/* For A32, ARM_FEATURE_V5 is checked near the start of the uncond block. */
33
if (s->thumb && (a->imm & 2)) {
34
return false;
35
--
36
2.20.1
37
38
diff view generated by jsdifflib
Deleted patch
1
In arm_cpu_realizefn(), if the CPU has VFP or Neon disabled then we
2
squash the ID register fields so that we don't advertise it to the
3
guest. This code was written for A-profile and needs some tweaks to
4
work correctly on M-profile:
5
1
6
* A-profile only fields should not be zeroed on M-profile:
7
- MVFR0.FPSHVEC,FPTRAP
8
- MVFR1.SIMDLS,SIMDINT,SIMDSP,SIMDHP
9
- MVFR2.SIMDMISC
10
* M-profile only fields should be zeroed on M-profile:
11
- MVFR1.FP16
12
13
In particular, because MVFR1.SIMDHP on A-profile is the same field as
14
MVFR1.FP16 on M-profile this code was incorrectly disabling FP16
15
support on an M-profile CPU (where has_neon is always false). This
16
isn't a visible bug yet because we don't have any M-profile CPUs with
17
FP16 support, but the change is necessary before we introduce any.
18
19
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Message-id: 20201019151301.2046-9-peter.maydell@linaro.org
22
---
23
target/arm/cpu.c | 29 ++++++++++++++++++-----------
24
1 file changed, 18 insertions(+), 11 deletions(-)
25
26
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/target/arm/cpu.c
29
+++ b/target/arm/cpu.c
30
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
31
u = cpu->isar.mvfr0;
32
u = FIELD_DP32(u, MVFR0, FPSP, 0);
33
u = FIELD_DP32(u, MVFR0, FPDP, 0);
34
- u = FIELD_DP32(u, MVFR0, FPTRAP, 0);
35
u = FIELD_DP32(u, MVFR0, FPDIVIDE, 0);
36
u = FIELD_DP32(u, MVFR0, FPSQRT, 0);
37
- u = FIELD_DP32(u, MVFR0, FPSHVEC, 0);
38
u = FIELD_DP32(u, MVFR0, FPROUND, 0);
39
+ if (!arm_feature(env, ARM_FEATURE_M)) {
40
+ u = FIELD_DP32(u, MVFR0, FPTRAP, 0);
41
+ u = FIELD_DP32(u, MVFR0, FPSHVEC, 0);
42
+ }
43
cpu->isar.mvfr0 = u;
44
45
u = cpu->isar.mvfr1;
46
u = FIELD_DP32(u, MVFR1, FPFTZ, 0);
47
u = FIELD_DP32(u, MVFR1, FPDNAN, 0);
48
u = FIELD_DP32(u, MVFR1, FPHP, 0);
49
+ if (arm_feature(env, ARM_FEATURE_M)) {
50
+ u = FIELD_DP32(u, MVFR1, FP16, 0);
51
+ }
52
cpu->isar.mvfr1 = u;
53
54
u = cpu->isar.mvfr2;
55
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
56
u = FIELD_DP32(u, ID_ISAR6, FHM, 0);
57
cpu->isar.id_isar6 = u;
58
59
- u = cpu->isar.mvfr1;
60
- u = FIELD_DP32(u, MVFR1, SIMDLS, 0);
61
- u = FIELD_DP32(u, MVFR1, SIMDINT, 0);
62
- u = FIELD_DP32(u, MVFR1, SIMDSP, 0);
63
- u = FIELD_DP32(u, MVFR1, SIMDHP, 0);
64
- cpu->isar.mvfr1 = u;
65
+ if (!arm_feature(env, ARM_FEATURE_M)) {
66
+ u = cpu->isar.mvfr1;
67
+ u = FIELD_DP32(u, MVFR1, SIMDLS, 0);
68
+ u = FIELD_DP32(u, MVFR1, SIMDINT, 0);
69
+ u = FIELD_DP32(u, MVFR1, SIMDSP, 0);
70
+ u = FIELD_DP32(u, MVFR1, SIMDHP, 0);
71
+ cpu->isar.mvfr1 = u;
72
73
- u = cpu->isar.mvfr2;
74
- u = FIELD_DP32(u, MVFR2, SIMDMISC, 0);
75
- cpu->isar.mvfr2 = u;
76
+ u = cpu->isar.mvfr2;
77
+ u = FIELD_DP32(u, MVFR2, SIMDMISC, 0);
78
+ cpu->isar.mvfr2 = u;
79
+ }
80
}
81
82
if (!cpu->has_neon && !cpu->has_vfp) {
83
--
84
2.20.1
85
86
diff view generated by jsdifflib
Deleted patch
1
From: Richard Henderson <richard.henderson@linaro.org>
2
1
3
The kernel sets btype for the signal handler as if for a call.
4
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20201016184207.786698-2-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
linux-user/aarch64/signal.c | 10 ++++++++--
11
1 file changed, 8 insertions(+), 2 deletions(-)
12
13
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/linux-user/aarch64/signal.c
16
+++ b/linux-user/aarch64/signal.c
17
@@ -XXX,XX +XXX,XX @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
18
+ offsetof(struct target_rt_frame_record, tramp);
19
}
20
env->xregs[0] = usig;
21
- env->xregs[31] = frame_addr;
22
env->xregs[29] = frame_addr + fr_ofs;
23
- env->pc = ka->_sa_handler;
24
env->xregs[30] = return_addr;
25
+ env->xregs[31] = frame_addr;
26
+ env->pc = ka->_sa_handler;
27
+
28
+ /* Invoke the signal handler as if by indirect call. */
29
+ if (cpu_isar_feature(aa64_bti, env_archcpu(env))) {
30
+ env->btype = 2;
31
+ }
32
+
33
if (info) {
34
tswap_siginfo(&frame->info, info);
35
env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
36
--
37
2.20.1
38
39
diff view generated by jsdifflib
Deleted patch
1
From: Richard Henderson <richard.henderson@linaro.org>
2
1
3
These are all of the defines required to parse
4
GNU_PROPERTY_AARCH64_FEATURE_1_AND, copied from binutils.
5
Other missing defines related to other GNU program headers
6
and notes are elided for now.
7
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20201016184207.786698-4-richard.henderson@linaro.org
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
include/elf.h | 22 ++++++++++++++++++++++
14
1 file changed, 22 insertions(+)
15
16
diff --git a/include/elf.h b/include/elf.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/elf.h
19
+++ b/include/elf.h
20
@@ -XXX,XX +XXX,XX @@ typedef int64_t Elf64_Sxword;
21
#define PT_NOTE 4
22
#define PT_SHLIB 5
23
#define PT_PHDR 6
24
+#define PT_LOOS 0x60000000
25
+#define PT_HIOS 0x6fffffff
26
#define PT_LOPROC 0x70000000
27
#define PT_HIPROC 0x7fffffff
28
29
+#define PT_GNU_PROPERTY (PT_LOOS + 0x474e553)
30
+
31
#define PT_MIPS_REGINFO 0x70000000
32
#define PT_MIPS_RTPROC 0x70000001
33
#define PT_MIPS_OPTIONS 0x70000002
34
@@ -XXX,XX +XXX,XX @@ typedef struct elf64_shdr {
35
#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
36
#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension regs */
37
38
+/* Defined note types for GNU systems. */
39
+
40
+#define NT_GNU_PROPERTY_TYPE_0 5 /* Program property */
41
+
42
+/* Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0). */
43
+
44
+#define GNU_PROPERTY_STACK_SIZE 1
45
+#define GNU_PROPERTY_NO_COPY_ON_PROTECTED 2
46
+
47
+#define GNU_PROPERTY_LOPROC 0xc0000000
48
+#define GNU_PROPERTY_HIPROC 0xdfffffff
49
+#define GNU_PROPERTY_LOUSER 0xe0000000
50
+#define GNU_PROPERTY_HIUSER 0xffffffff
51
+
52
+#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
53
+#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1u << 0)
54
+#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC (1u << 1)
55
+
56
/*
57
* Physical entry point into the kernel.
58
*
59
--
60
2.20.1
61
62
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
1
3
Fix an unlikely memory leak in load_elf_image().
4
5
Fixes: bf858897b7 ("linux-user: Re-use load_elf_image for the main binary.")
6
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201016184207.786698-5-richard.henderson@linaro.org
9
Message-Id: <20201003174944.1972444-1-f4bug@amsat.org>
10
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
14
linux-user/elfload.c | 8 ++++----
15
1 file changed, 4 insertions(+), 4 deletions(-)
16
17
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/linux-user/elfload.c
20
+++ b/linux-user/elfload.c
21
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
22
info->brk = vaddr_em;
23
}
24
} else if (eppnt->p_type == PT_INTERP && pinterp_name) {
25
- char *interp_name;
26
+ g_autofree char *interp_name = NULL;
27
28
if (*pinterp_name) {
29
errmsg = "Multiple PT_INTERP entries";
30
goto exit_errmsg;
31
}
32
- interp_name = malloc(eppnt->p_filesz);
33
+ interp_name = g_malloc(eppnt->p_filesz);
34
if (!interp_name) {
35
goto exit_perror;
36
}
37
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
38
errmsg = "Invalid PT_INTERP entry";
39
goto exit_errmsg;
40
}
41
- *pinterp_name = interp_name;
42
+ *pinterp_name = g_steal_pointer(&interp_name);
43
#ifdef TARGET_MIPS
44
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
45
Mips_elf_abiflags_v0 abiflags;
46
@@ -XXX,XX +XXX,XX @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
47
if (elf_interpreter) {
48
info->load_bias = interp_info.load_bias;
49
info->entry = interp_info.entry;
50
- free(elf_interpreter);
51
+ g_free(elf_interpreter);
52
}
53
54
#ifdef USE_ELF_CORE_DUMP
55
--
56
2.20.1
57
58
diff view generated by jsdifflib
Deleted patch
1
From: Richard Henderson <richard.henderson@linaro.org>
2
1
3
Fixing this now will clarify following patches.
4
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Message-id: 20201016184207.786698-6-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
linux-user/elfload.c | 12 +++++++++---
11
1 file changed, 9 insertions(+), 3 deletions(-)
12
13
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/linux-user/elfload.c
16
+++ b/linux-user/elfload.c
17
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
18
abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em, vaddr_len;
19
int elf_prot = 0;
20
21
- if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
22
- if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
23
- if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
24
+ if (eppnt->p_flags & PF_R) {
25
+ elf_prot |= PROT_READ;
26
+ }
27
+ if (eppnt->p_flags & PF_W) {
28
+ elf_prot |= PROT_WRITE;
29
+ }
30
+ if (eppnt->p_flags & PF_X) {
31
+ elf_prot |= PROT_EXEC;
32
+ }
33
34
vaddr = load_bias + eppnt->p_vaddr;
35
vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
36
--
37
2.20.1
38
39
diff view generated by jsdifflib
Deleted patch
1
From: Richard Henderson <richard.henderson@linaro.org>
2
1
3
The second loop uses a loop induction variable, and the first
4
does not. Transform the first to match the second, to simplify
5
a following patch moving code between them.
6
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Message-id: 20201016184207.786698-7-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
linux-user/elfload.c | 9 +++++----
13
1 file changed, 5 insertions(+), 4 deletions(-)
14
15
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/linux-user/elfload.c
18
+++ b/linux-user/elfload.c
19
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
20
loaddr = -1, hiaddr = 0;
21
info->alignment = 0;
22
for (i = 0; i < ehdr->e_phnum; ++i) {
23
- if (phdr[i].p_type == PT_LOAD) {
24
- abi_ulong a = phdr[i].p_vaddr - phdr[i].p_offset;
25
+ struct elf_phdr *eppnt = phdr + i;
26
+ if (eppnt->p_type == PT_LOAD) {
27
+ abi_ulong a = eppnt->p_vaddr - eppnt->p_offset;
28
if (a < loaddr) {
29
loaddr = a;
30
}
31
- a = phdr[i].p_vaddr + phdr[i].p_memsz;
32
+ a = eppnt->p_vaddr + eppnt->p_memsz;
33
if (a > hiaddr) {
34
hiaddr = a;
35
}
36
++info->nsegs;
37
- info->alignment |= phdr[i].p_align;
38
+ info->alignment |= eppnt->p_align;
39
}
40
}
41
42
--
43
2.20.1
44
45
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
This is a bit clearer than open-coding some of this
3
A device shouldn't access its parent object which is QOM internal.
4
with a bare c string.
4
Instead it should use type cast for this purporse. This patch fixes this
5
issue for all NPCM7XX Devices.
5
6
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Signed-off-by: Hao Wu <wuhaotsh@google.com>
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20201016184207.786698-9-richard.henderson@linaro.org
9
Message-id: 20210108190945.949196-7-wuhaotsh@google.com
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
---
11
linux-user/elfload.c | 37 ++++++++++++++++++++-----------------
12
hw/arm/npcm7xx_boards.c | 2 +-
12
1 file changed, 20 insertions(+), 17 deletions(-)
13
hw/mem/npcm7xx_mc.c | 2 +-
14
hw/misc/npcm7xx_clk.c | 2 +-
15
hw/misc/npcm7xx_gcr.c | 2 +-
16
hw/misc/npcm7xx_rng.c | 2 +-
17
hw/nvram/npcm7xx_otp.c | 2 +-
18
hw/ssi/npcm7xx_fiu.c | 2 +-
19
7 files changed, 7 insertions(+), 7 deletions(-)
13
20
14
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
21
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
15
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
16
--- a/linux-user/elfload.c
23
--- a/hw/arm/npcm7xx_boards.c
17
+++ b/linux-user/elfload.c
24
+++ b/hw/arm/npcm7xx_boards.c
18
@@ -XXX,XX +XXX,XX @@
25
@@ -XXX,XX +XXX,XX @@ static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
19
#include "qemu/guest-random.h"
26
uint32_t hw_straps)
20
#include "qemu/units.h"
27
{
21
#include "qemu/selfmap.h"
28
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_GET_CLASS(machine);
22
+#include "qapi/error.h"
29
- MachineClass *mc = &nmc->parent;
23
30
+ MachineClass *mc = MACHINE_CLASS(nmc);
24
#ifdef _ARCH_PPC64
31
Object *obj;
25
#undef ARCH_DLINFO
32
26
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
33
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
27
struct elf_phdr *phdr;
34
diff --git a/hw/mem/npcm7xx_mc.c b/hw/mem/npcm7xx_mc.c
28
abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
35
index XXXXXXX..XXXXXXX 100644
29
int i, retval;
36
--- a/hw/mem/npcm7xx_mc.c
30
- const char *errmsg;
37
+++ b/hw/mem/npcm7xx_mc.c
31
+ Error *err = NULL;
38
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_mc_realize(DeviceState *dev, Error **errp)
32
39
33
/* First of all, some simple consistency checks */
40
memory_region_init_io(&s->mmio, OBJECT(s), &npcm7xx_mc_ops, s, "regs",
34
- errmsg = "Invalid ELF image for this architecture";
41
NPCM7XX_MC_REGS_SIZE);
35
if (!elf_check_ident(ehdr)) {
42
- sysbus_init_mmio(&s->parent, &s->mmio);
36
+ error_setg(&err, "Invalid ELF image for this architecture");
43
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio);
37
goto exit_errmsg;
38
}
39
bswap_ehdr(ehdr);
40
if (!elf_check_ehdr(ehdr)) {
41
+ error_setg(&err, "Invalid ELF image for this architecture");
42
goto exit_errmsg;
43
}
44
45
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
46
g_autofree char *interp_name = NULL;
47
48
if (*pinterp_name) {
49
- errmsg = "Multiple PT_INTERP entries";
50
+ error_setg(&err, "Multiple PT_INTERP entries");
51
goto exit_errmsg;
52
}
53
+
54
interp_name = g_malloc(eppnt->p_filesz);
55
- if (!interp_name) {
56
- goto exit_perror;
57
- }
58
59
if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
60
memcpy(interp_name, bprm_buf + eppnt->p_offset,
61
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
62
retval = pread(image_fd, interp_name, eppnt->p_filesz,
63
eppnt->p_offset);
64
if (retval != eppnt->p_filesz) {
65
- goto exit_perror;
66
+ goto exit_read;
67
}
68
}
69
if (interp_name[eppnt->p_filesz - 1] != 0) {
70
- errmsg = "Invalid PT_INTERP entry";
71
+ error_setg(&err, "Invalid PT_INTERP entry");
72
goto exit_errmsg;
73
}
74
*pinterp_name = g_steal_pointer(&interp_name);
75
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
76
(ehdr->e_type == ET_EXEC ? MAP_FIXED : 0),
77
-1, 0);
78
if (load_addr == -1) {
79
- goto exit_perror;
80
+ goto exit_mmap;
81
}
82
load_bias = load_addr - loaddr;
83
84
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
85
image_fd, eppnt->p_offset - vaddr_po);
86
87
if (error == -1) {
88
- goto exit_perror;
89
+ goto exit_mmap;
90
}
91
}
92
93
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
94
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
95
Mips_elf_abiflags_v0 abiflags;
96
if (eppnt->p_filesz < sizeof(Mips_elf_abiflags_v0)) {
97
- errmsg = "Invalid PT_MIPS_ABIFLAGS entry";
98
+ error_setg(&err, "Invalid PT_MIPS_ABIFLAGS entry");
99
goto exit_errmsg;
100
}
101
if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
102
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
103
retval = pread(image_fd, &abiflags, sizeof(Mips_elf_abiflags_v0),
104
eppnt->p_offset);
105
if (retval != sizeof(Mips_elf_abiflags_v0)) {
106
- goto exit_perror;
107
+ goto exit_read;
108
}
109
}
110
bswap_mips_abiflags(&abiflags);
111
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
112
113
exit_read:
114
if (retval >= 0) {
115
- errmsg = "Incomplete read of file header";
116
- goto exit_errmsg;
117
+ error_setg(&err, "Incomplete read of file header");
118
+ } else {
119
+ error_setg_errno(&err, errno, "Error reading file header");
120
}
121
- exit_perror:
122
- errmsg = strerror(errno);
123
+ goto exit_errmsg;
124
+ exit_mmap:
125
+ error_setg_errno(&err, errno, "Error mapping file");
126
+ goto exit_errmsg;
127
exit_errmsg:
128
- fprintf(stderr, "%s: %s\n", image_name, errmsg);
129
+ error_reportf_err(err, "%s: ", image_name);
130
exit(-1);
131
}
44
}
132
45
46
static void npcm7xx_mc_class_init(ObjectClass *klass, void *data)
47
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/hw/misc/npcm7xx_clk.c
50
+++ b/hw/misc/npcm7xx_clk.c
51
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
52
53
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
54
TYPE_NPCM7XX_CLK, 4 * KiB);
55
- sysbus_init_mmio(&s->parent, &s->iomem);
56
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
57
}
58
59
static int npcm7xx_clk_post_load(void *opaque, int version_id)
60
diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/hw/misc/npcm7xx_gcr.c
63
+++ b/hw/misc/npcm7xx_gcr.c
64
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_gcr_init(Object *obj)
65
66
memory_region_init_io(&s->iomem, obj, &npcm7xx_gcr_ops, s,
67
TYPE_NPCM7XX_GCR, 4 * KiB);
68
- sysbus_init_mmio(&s->parent, &s->iomem);
69
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
70
}
71
72
static const VMStateDescription vmstate_npcm7xx_gcr = {
73
diff --git a/hw/misc/npcm7xx_rng.c b/hw/misc/npcm7xx_rng.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/hw/misc/npcm7xx_rng.c
76
+++ b/hw/misc/npcm7xx_rng.c
77
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_rng_init(Object *obj)
78
79
memory_region_init_io(&s->iomem, obj, &npcm7xx_rng_ops, s, "regs",
80
NPCM7XX_RNG_REGS_SIZE);
81
- sysbus_init_mmio(&s->parent, &s->iomem);
82
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
83
}
84
85
static const VMStateDescription vmstate_npcm7xx_rng = {
86
diff --git a/hw/nvram/npcm7xx_otp.c b/hw/nvram/npcm7xx_otp.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/hw/nvram/npcm7xx_otp.c
89
+++ b/hw/nvram/npcm7xx_otp.c
90
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_otp_realize(DeviceState *dev, Error **errp)
91
{
92
NPCM7xxOTPClass *oc = NPCM7XX_OTP_GET_CLASS(dev);
93
NPCM7xxOTPState *s = NPCM7XX_OTP(dev);
94
- SysBusDevice *sbd = &s->parent;
95
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
96
97
memset(s->array, 0, sizeof(s->array));
98
99
diff --git a/hw/ssi/npcm7xx_fiu.c b/hw/ssi/npcm7xx_fiu.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/hw/ssi/npcm7xx_fiu.c
102
+++ b/hw/ssi/npcm7xx_fiu.c
103
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_fiu_hold_reset(Object *obj)
104
static void npcm7xx_fiu_realize(DeviceState *dev, Error **errp)
105
{
106
NPCM7xxFIUState *s = NPCM7XX_FIU(dev);
107
- SysBusDevice *sbd = &s->parent;
108
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
109
int i;
110
111
if (s->cs_count <= 0) {
133
--
112
--
134
2.20.1
113
2.20.1
135
114
136
115
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
2
2
3
For BTI, we need to know if the executable is static or dynamic,
3
ui/cocoa.m:1188:44: warning: 'openFile:' is deprecated: first deprecated in macOS 11.0 - Use -[NSWorkspace openURL:] instead.
4
which means looking for PT_INTERP earlier.
4
[-Wdeprecated-declarations]
5
if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) {
6
^
7
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSWorkspace.h:350:1: note:
8
'openFile:' has been explicitly marked deprecated here
9
- (BOOL)openFile:(NSString *)fullPath API_DEPRECATED("Use -[NSWorkspace openURL:] instead.", macos(10.0, 11.0));
10
^
5
11
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
7
Message-id: 20201016184207.786698-8-richard.henderson@linaro.org
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Message-id: 20210102150718.47618-1-r.bolshakov@yadro.com
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
16
---
11
linux-user/elfload.c | 60 +++++++++++++++++++++++---------------------
17
ui/cocoa.m | 5 ++++-
12
1 file changed, 31 insertions(+), 29 deletions(-)
18
1 file changed, 4 insertions(+), 1 deletion(-)
13
19
14
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
20
diff --git a/ui/cocoa.m b/ui/cocoa.m
15
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
16
--- a/linux-user/elfload.c
22
--- a/ui/cocoa.m
17
+++ b/linux-user/elfload.c
23
+++ b/ui/cocoa.m
18
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
24
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
19
25
/* Where to look for local files */
20
mmap_lock();
26
NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
21
27
NSString *full_file_path;
22
- /* Find the maximum size of the image and allocate an appropriate
28
+ NSURL *full_file_url;
23
- amount of memory to handle that. */
29
24
+ /*
30
/* iterate thru the possible paths until the file is found */
25
+ * Find the maximum size of the image and allocate an appropriate
31
int index;
26
+ * amount of memory to handle that. Locate the interpreter, if any.
32
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
27
+ */
33
full_file_path = [full_file_path stringByDeletingLastPathComponent];
28
loaddr = -1, hiaddr = 0;
34
full_file_path = [NSString stringWithFormat: @"%@/%@%@", full_file_path,
29
info->alignment = 0;
35
path_array[index], filename];
30
for (i = 0; i < ehdr->e_phnum; ++i) {
36
- if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) {
31
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
37
+ full_file_url = [NSURL fileURLWithPath: full_file_path
32
}
38
+ isDirectory: false];
33
++info->nsegs;
39
+ if ([[NSWorkspace sharedWorkspace] openURL: full_file_url] == YES) {
34
info->alignment |= eppnt->p_align;
40
return;
35
+ } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
36
+ g_autofree char *interp_name = NULL;
37
+
38
+ if (*pinterp_name) {
39
+ errmsg = "Multiple PT_INTERP entries";
40
+ goto exit_errmsg;
41
+ }
42
+ interp_name = g_malloc(eppnt->p_filesz);
43
+ if (!interp_name) {
44
+ goto exit_perror;
45
+ }
46
+
47
+ if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
48
+ memcpy(interp_name, bprm_buf + eppnt->p_offset,
49
+ eppnt->p_filesz);
50
+ } else {
51
+ retval = pread(image_fd, interp_name, eppnt->p_filesz,
52
+ eppnt->p_offset);
53
+ if (retval != eppnt->p_filesz) {
54
+ goto exit_perror;
55
+ }
56
+ }
57
+ if (interp_name[eppnt->p_filesz - 1] != 0) {
58
+ errmsg = "Invalid PT_INTERP entry";
59
+ goto exit_errmsg;
60
+ }
61
+ *pinterp_name = g_steal_pointer(&interp_name);
62
}
41
}
63
}
42
}
64
65
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
66
if (vaddr_em > info->brk) {
67
info->brk = vaddr_em;
68
}
69
- } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
70
- g_autofree char *interp_name = NULL;
71
-
72
- if (*pinterp_name) {
73
- errmsg = "Multiple PT_INTERP entries";
74
- goto exit_errmsg;
75
- }
76
- interp_name = g_malloc(eppnt->p_filesz);
77
- if (!interp_name) {
78
- goto exit_perror;
79
- }
80
-
81
- if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
82
- memcpy(interp_name, bprm_buf + eppnt->p_offset,
83
- eppnt->p_filesz);
84
- } else {
85
- retval = pread(image_fd, interp_name, eppnt->p_filesz,
86
- eppnt->p_offset);
87
- if (retval != eppnt->p_filesz) {
88
- goto exit_perror;
89
- }
90
- }
91
- if (interp_name[eppnt->p_filesz - 1] != 0) {
92
- errmsg = "Invalid PT_INTERP entry";
93
- goto exit_errmsg;
94
- }
95
- *pinterp_name = g_steal_pointer(&interp_name);
96
#ifdef TARGET_MIPS
97
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
98
Mips_elf_abiflags_v0 abiflags;
99
--
43
--
100
2.20.1
44
2.20.1
101
45
102
46
diff view generated by jsdifflib