1
First pullreq for arm of the 4.1 series, since I'm back from
1
Last minute pullreq for arm related patches; quite large because
2
holiday now. This is mostly my M-profile FPU series and Philippe's
2
there were several series that only just made it through code review
3
devices.h cleanup. I have a pile of other patchsets to work through
3
in time.
4
in my to-review folder, but 42 patches is definitely quite
5
big enough to send now...
6
4
7
thanks
5
thanks
8
-- PMM
6
-- PMM
9
7
10
The following changes since commit 413a99a92c13ec408dcf2adaa87918dc81e890c8:
8
The following changes since commit 091e3e3dbc499d84c004e1c50bc9870af37f6e99:
11
9
12
Add Nios II semihosting support. (2019-04-29 16:09:51 +0100)
10
Merge remote-tracking branch 'remotes/ericb/tags/pull-bitmaps-2020-10-26' into staging (2020-10-26 22:36:35 +0000)
13
11
14
are available in the Git repository at:
12
are available in the Git repository at:
15
13
16
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20190429
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20201027-1
17
15
18
for you to fetch changes up to 437cc27ddfded3bbab6afd5ac1761e0e195edba7:
16
for you to fetch changes up to 32bd322a0134ed89db00f2b9b3894982db3dedcb:
19
17
20
hw/devices: Move SMSC 91C111 declaration into a new header (2019-04-29 17:57:21 +0100)
18
hw/timer/armv7m_systick: Rewrite to use ptimers (2020-10-27 11:15:31 +0000)
21
19
22
----------------------------------------------------------------
20
----------------------------------------------------------------
23
target-arm queue:
21
target-arm queue:
24
* remove "bag of random stuff" hw/devices.h header
22
* raspi: add model of cprman clock manager
25
* implement FPU for Cortex-M and enable it for Cortex-M4 and -M33
23
* sbsa-ref: add an SBSA generic watchdog device
26
* hw/dma: Compile the bcm2835_dma device as common object
24
* arm/trace: Fix hex printing
27
* configure: Remove --source-path option
25
* raspi: Add models of Pi 3 model A+, Pi Zero and Pi A+
28
* hw/ssi/xilinx_spips: Avoid variable length array
26
* hw/arm/smmuv3: Set the restoration priority of the vSMMUv3 explicitly
29
* hw/arm/smmuv3: Remove SMMUNotifierNode
27
* Nuvoton NPCM7xx: Add USB, RNG, GPIO and watchdog support
28
* hw/arm: fix min_cpus for xlnx-versal-virt platform
29
* hw/arm/highbank: Silence warnings about missing fallthrough statements
30
* linux-user: Support Aarch64 BTI
31
* Armv7M systick: fix corner case bugs by rewriting to use ptimer
30
32
31
----------------------------------------------------------------
33
----------------------------------------------------------------
32
Eric Auger (1):
34
Dr. David Alan Gilbert (1):
33
hw/arm/smmuv3: Remove SMMUNotifierNode
35
arm/trace: Fix hex printing
34
36
35
Peter Maydell (28):
37
Hao Wu (1):
36
hw/ssi/xilinx_spips: Avoid variable length array
38
hw/timer: Adding watchdog for NPCM7XX Timer.
37
configure: Remove --source-path option
38
target/arm: Make sure M-profile FPSCR RES0 bits are not settable
39
hw/intc/armv7m_nvic: Allow reading of M-profile MVFR* registers
40
target/arm: Implement dummy versions of M-profile FP-related registers
41
target/arm: Disable most VFP sysregs for M-profile
42
target/arm: Honour M-profile FP enable bits
43
target/arm: Decode FP instructions for M profile
44
target/arm: Clear CONTROL_S.SFPA in SG insn if FPU present
45
target/arm: Handle SFPA and FPCA bits in reads and writes of CONTROL
46
target/arm/helper: don't return early for STKOF faults during stacking
47
target/arm: Handle floating point registers in exception entry
48
target/arm: Implement v7m_update_fpccr()
49
target/arm: Clear CONTROL.SFPA in BXNS and BLXNS
50
target/arm: Clean excReturn bits when tail chaining
51
target/arm: Allow for floating point in callee stack integrity check
52
target/arm: Handle floating point registers in exception return
53
target/arm: Move NS TBFLAG from bit 19 to bit 6
54
target/arm: Overlap VECSTRIDE and XSCALE_CPAR TB flags
55
target/arm: Set FPCCR.S when executing M-profile floating point insns
56
target/arm: Activate M-profile floating point context when FPCCR.ASPEN is set
57
target/arm: New helper function arm_v7m_mmu_idx_all()
58
target/arm: New function armv7m_nvic_set_pending_lazyfp()
59
target/arm: Add lazy-FP-stacking support to v7m_stack_write()
60
target/arm: Implement M-profile lazy FP state preservation
61
target/arm: Implement VLSTM for v7M CPUs with an FPU
62
target/arm: Implement VLLDM for v7M CPUs with an FPU
63
target/arm: Enable FPU for Cortex-M4 and Cortex-M33
64
39
65
Philippe Mathieu-Daudé (13):
40
Havard Skinnemoen (4):
66
hw/dma: Compile the bcm2835_dma device as common object
41
Move npcm7xx_timer_reached_zero call out of npcm7xx_timer_pause
67
hw/arm/aspeed: Use TYPE_TMP105/TYPE_PCA9552 instead of hardcoded string
42
hw/misc: Add npcm7xx random number generator
68
hw/arm/nseries: Use TYPE_TMP105 instead of hardcoded string
43
hw/arm/npcm7xx: Add EHCI and OHCI controllers
69
hw/display/tc6393xb: Remove unused functions
44
hw/gpio: Add GPIO model for Nuvoton NPCM7xx
70
hw/devices: Move TC6393XB declarations into a new header
71
hw/devices: Move Blizzard declarations into a new header
72
hw/devices: Move CBus declarations into a new header
73
hw/devices: Move Gamepad declarations into a new header
74
hw/devices: Move TI touchscreen declarations into a new header
75
hw/devices: Move LAN9118 declarations into a new header
76
hw/net/ne2000-isa: Add guards to the header
77
hw/net/lan9118: Export TYPE_LAN9118 and use it instead of hardcoded string
78
hw/devices: Move SMSC 91C111 declaration into a new header
79
45
80
configure | 10 +-
46
Luc Michel (14):
81
hw/dma/Makefile.objs | 2 +-
47
hw/core/clock: provide the VMSTATE_ARRAY_CLOCK macro
82
include/hw/arm/omap.h | 6 +-
48
hw/core/clock: trace clock values in Hz instead of ns
83
include/hw/arm/smmu-common.h | 8 +-
49
hw/arm/raspi: fix CPRMAN base address
84
include/hw/devices.h | 62 ---
50
hw/arm/raspi: add a skeleton implementation of the CPRMAN
85
include/hw/display/blizzard.h | 22 ++
51
hw/misc/bcm2835_cprman: add a PLL skeleton implementation
86
include/hw/display/tc6393xb.h | 24 ++
52
hw/misc/bcm2835_cprman: implement PLLs behaviour
87
include/hw/input/gamepad.h | 19 +
53
hw/misc/bcm2835_cprman: add a PLL channel skeleton implementation
88
include/hw/input/tsc2xxx.h | 36 ++
54
hw/misc/bcm2835_cprman: implement PLL channels behaviour
89
include/hw/misc/cbus.h | 32 ++
55
hw/misc/bcm2835_cprman: add a clock mux skeleton implementation
90
include/hw/net/lan9118.h | 21 +
56
hw/misc/bcm2835_cprman: implement clock mux behaviour
91
include/hw/net/ne2000-isa.h | 6 +
57
hw/misc/bcm2835_cprman: add the DSI0HSCK multiplexer
92
include/hw/net/smc91c111.h | 19 +
58
hw/misc/bcm2835_cprman: add sane reset values to the registers
93
include/qemu/typedefs.h | 1 -
59
hw/char/pl011: add a clock input
94
target/arm/cpu.h | 95 ++++-
60
hw/arm/bcm2835_peripherals: connect the UART clock
95
target/arm/helper.h | 5 +
96
target/arm/translate.h | 3 +
97
hw/arm/aspeed.c | 13 +-
98
hw/arm/exynos4_boards.c | 3 +-
99
hw/arm/gumstix.c | 2 +-
100
hw/arm/integratorcp.c | 2 +-
101
hw/arm/kzm.c | 2 +-
102
hw/arm/mainstone.c | 2 +-
103
hw/arm/mps2-tz.c | 3 +-
104
hw/arm/mps2.c | 2 +-
105
hw/arm/nseries.c | 7 +-
106
hw/arm/palm.c | 2 +-
107
hw/arm/realview.c | 3 +-
108
hw/arm/smmu-common.c | 6 +-
109
hw/arm/smmuv3.c | 28 +-
110
hw/arm/stellaris.c | 2 +-
111
hw/arm/tosa.c | 2 +-
112
hw/arm/versatilepb.c | 2 +-
113
hw/arm/vexpress.c | 2 +-
114
hw/display/blizzard.c | 2 +-
115
hw/display/tc6393xb.c | 18 +-
116
hw/input/stellaris_input.c | 2 +-
117
hw/input/tsc2005.c | 2 +-
118
hw/input/tsc210x.c | 4 +-
119
hw/intc/armv7m_nvic.c | 261 +++++++++++++
120
hw/misc/cbus.c | 2 +-
121
hw/net/lan9118.c | 3 +-
122
hw/net/smc91c111.c | 2 +-
123
hw/ssi/xilinx_spips.c | 6 +-
124
target/arm/cpu.c | 20 +
125
target/arm/helper.c | 873 +++++++++++++++++++++++++++++++++++++++---
126
target/arm/machine.c | 16 +
127
target/arm/translate.c | 150 +++++++-
128
target/arm/vfp_helper.c | 8 +
129
MAINTAINERS | 7 +
130
50 files changed, 1595 insertions(+), 235 deletions(-)
131
delete mode 100644 include/hw/devices.h
132
create mode 100644 include/hw/display/blizzard.h
133
create mode 100644 include/hw/display/tc6393xb.h
134
create mode 100644 include/hw/input/gamepad.h
135
create mode 100644 include/hw/input/tsc2xxx.h
136
create mode 100644 include/hw/misc/cbus.h
137
create mode 100644 include/hw/net/lan9118.h
138
create mode 100644 include/hw/net/smc91c111.h
139
61
62
Pavel Dovgalyuk (1):
63
hw/arm: fix min_cpus for xlnx-versal-virt platform
64
65
Peter Maydell (2):
66
hw/core/ptimer: Support ptimer being disabled by timer callback
67
hw/timer/armv7m_systick: Rewrite to use ptimers
68
69
Philippe Mathieu-Daudé (10):
70
linux-user/elfload: Avoid leaking interp_name using GLib memory API
71
hw/arm/bcm2836: Restrict BCM283XInfo declaration to C source
72
hw/arm/bcm2836: QOM'ify more by adding class_init() to each SoC type
73
hw/arm/bcm2836: Introduce BCM283XClass::core_count
74
hw/arm/bcm2836: Only provide "enabled-cpus" property to multicore SoCs
75
hw/arm/bcm2836: Split out common realize() code
76
hw/arm/bcm2836: Introduce the BCM2835 SoC
77
hw/arm/raspi: Add the Raspberry Pi A+ machine
78
hw/arm/raspi: Add the Raspberry Pi Zero machine
79
hw/arm/raspi: Add the Raspberry Pi 3 model A+
80
81
Richard Henderson (11):
82
linux-user/aarch64: Reset btype for signals
83
linux-user: Set PAGE_TARGET_1 for TARGET_PROT_BTI
84
include/elf: Add defines related to GNU property notes for AArch64
85
linux-user/elfload: Fix coding style in load_elf_image
86
linux-user/elfload: Adjust iteration over phdr
87
linux-user/elfload: Move PT_INTERP detection to first loop
88
linux-user/elfload: Use Error for load_elf_image
89
linux-user/elfload: Use Error for load_elf_interp
90
linux-user/elfload: Parse NT_GNU_PROPERTY_TYPE_0 notes
91
linux-user/elfload: Parse GNU_PROPERTY_AARCH64_FEATURE_1_AND
92
tests/tcg/aarch64: Add bti smoke tests
93
94
Shashi Mallela (2):
95
hw/watchdog: Implement SBSA watchdog device
96
hw/arm/sbsa-ref: add SBSA watchdog device
97
98
Thomas Huth (1):
99
hw/arm/highbank: Silence warnings about missing fallthrough statements
100
101
Zenghui Yu (1):
102
hw/arm/smmuv3: Set the restoration priority of the vSMMUv3 explicitly
103
104
docs/system/arm/nuvoton.rst | 6 +-
105
hw/usb/hcd-ehci.h | 1 +
106
include/elf.h | 22 +
107
include/exec/cpu-all.h | 2 +
108
include/hw/arm/bcm2835_peripherals.h | 5 +-
109
include/hw/arm/bcm2836.h | 9 +-
110
include/hw/arm/npcm7xx.h | 8 +
111
include/hw/arm/raspi_platform.h | 5 +-
112
include/hw/char/pl011.h | 1 +
113
include/hw/clock.h | 5 +
114
include/hw/gpio/npcm7xx_gpio.h | 55 ++
115
include/hw/misc/bcm2835_cprman.h | 210 ++++++
116
include/hw/misc/bcm2835_cprman_internals.h | 1019 ++++++++++++++++++++++++++++
117
include/hw/misc/npcm7xx_clk.h | 2 +
118
include/hw/misc/npcm7xx_rng.h | 34 +
119
include/hw/timer/armv7m_systick.h | 3 +-
120
include/hw/timer/npcm7xx_timer.h | 48 +-
121
include/hw/watchdog/sbsa_gwdt.h | 79 +++
122
linux-user/qemu.h | 4 +
123
linux-user/syscall_defs.h | 4 +
124
target/arm/cpu.h | 5 +
125
hw/arm/bcm2835_peripherals.c | 15 +-
126
hw/arm/bcm2836.c | 182 +++--
127
hw/arm/highbank.c | 2 +
128
hw/arm/npcm7xx.c | 126 +++-
129
hw/arm/raspi.c | 41 ++
130
hw/arm/sbsa-ref.c | 23 +
131
hw/arm/smmuv3.c | 1 +
132
hw/arm/xlnx-versal-virt.c | 1 +
133
hw/char/pl011.c | 45 ++
134
hw/core/clock.c | 6 +-
135
hw/core/ptimer.c | 4 +
136
hw/gpio/npcm7xx_gpio.c | 424 ++++++++++++
137
hw/misc/bcm2835_cprman.c | 808 ++++++++++++++++++++++
138
hw/misc/npcm7xx_clk.c | 28 +
139
hw/misc/npcm7xx_rng.c | 180 +++++
140
hw/timer/armv7m_systick.c | 124 ++--
141
hw/timer/npcm7xx_timer.c | 270 ++++++--
142
hw/usb/hcd-ehci-sysbus.c | 19 +
143
hw/watchdog/sbsa_gwdt.c | 293 ++++++++
144
linux-user/aarch64/signal.c | 10 +-
145
linux-user/elfload.c | 326 +++++++--
146
linux-user/mmap.c | 16 +
147
target/arm/translate-a64.c | 6 +-
148
tests/qtest/npcm7xx_gpio-test.c | 385 +++++++++++
149
tests/qtest/npcm7xx_rng-test.c | 278 ++++++++
150
tests/qtest/npcm7xx_watchdog_timer-test.c | 319 +++++++++
151
tests/tcg/aarch64/bti-1.c | 62 ++
152
tests/tcg/aarch64/bti-2.c | 116 ++++
153
tests/tcg/aarch64/bti-crt.inc.c | 51 ++
154
MAINTAINERS | 1 +
155
hw/arm/Kconfig | 1 +
156
hw/arm/trace-events | 2 +-
157
hw/char/trace-events | 1 +
158
hw/core/trace-events | 4 +-
159
hw/gpio/meson.build | 1 +
160
hw/gpio/trace-events | 7 +
161
hw/misc/meson.build | 2 +
162
hw/misc/trace-events | 9 +
163
hw/watchdog/Kconfig | 3 +
164
hw/watchdog/meson.build | 1 +
165
tests/qtest/meson.build | 6 +-
166
tests/tcg/aarch64/Makefile.target | 10 +
167
tests/tcg/configure.sh | 4 +
168
64 files changed, 5461 insertions(+), 279 deletions(-)
169
create mode 100644 include/hw/gpio/npcm7xx_gpio.h
170
create mode 100644 include/hw/misc/bcm2835_cprman.h
171
create mode 100644 include/hw/misc/bcm2835_cprman_internals.h
172
create mode 100644 include/hw/misc/npcm7xx_rng.h
173
create mode 100644 include/hw/watchdog/sbsa_gwdt.h
174
create mode 100644 hw/gpio/npcm7xx_gpio.c
175
create mode 100644 hw/misc/bcm2835_cprman.c
176
create mode 100644 hw/misc/npcm7xx_rng.c
177
create mode 100644 hw/watchdog/sbsa_gwdt.c
178
create mode 100644 tests/qtest/npcm7xx_gpio-test.c
179
create mode 100644 tests/qtest/npcm7xx_rng-test.c
180
create mode 100644 tests/qtest/npcm7xx_watchdog_timer-test.c
181
create mode 100644 tests/tcg/aarch64/bti-1.c
182
create mode 100644 tests/tcg/aarch64/bti-2.c
183
create mode 100644 tests/tcg/aarch64/bti-crt.inc.c
184
diff view generated by jsdifflib
1
The TailChain() pseudocode specifies that a tail chaining
1
From: Richard Henderson <richard.henderson@linaro.org>
2
exception should sanitize the excReturn all-ones bits and
3
(if there is no FPU) the excReturn FType bits; we weren't
4
doing this.
5
2
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: 20201021173749.111103-2-richard.henderson@linaro.org
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20190416125744.27770-14-peter.maydell@linaro.org
9
---
9
---
10
target/arm/helper.c | 8 ++++++++
10
linux-user/aarch64/signal.c | 10 ++++++++--
11
1 file changed, 8 insertions(+)
11
1 file changed, 8 insertions(+), 2 deletions(-)
12
12
13
diff --git a/target/arm/helper.c b/target/arm/helper.c
13
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
14
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/helper.c
15
--- a/linux-user/aarch64/signal.c
16
+++ b/target/arm/helper.c
16
+++ b/linux-user/aarch64/signal.c
17
@@ -XXX,XX +XXX,XX @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
17
@@ -XXX,XX +XXX,XX @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
18
qemu_log_mask(CPU_LOG_INT, "...taking pending %s exception %d\n",
18
+ offsetof(struct target_rt_frame_record, tramp);
19
targets_secure ? "secure" : "nonsecure", exc);
19
}
20
20
env->xregs[0] = usig;
21
+ if (dotailchain) {
21
- env->xregs[31] = frame_addr;
22
+ /* Sanitize LR FType and PREFIX bits */
22
env->xregs[29] = frame_addr + fr_ofs;
23
+ if (!arm_feature(env, ARM_FEATURE_VFP)) {
23
- env->pc = ka->_sa_handler;
24
+ lr |= R_V7M_EXCRET_FTYPE_MASK;
24
env->xregs[30] = return_addr;
25
+ }
25
+ env->xregs[31] = frame_addr;
26
+ lr = deposit32(lr, 24, 8, 0xff);
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;
27
+ }
31
+ }
28
+
32
+
29
if (arm_feature(env, ARM_FEATURE_V8)) {
33
if (info) {
30
if (arm_feature(env, ARM_FEATURE_M_SECURITY) &&
34
tswap_siginfo(&frame->info, info);
31
(lr & R_V7M_EXCRET_S_MASK)) {
35
env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
32
--
36
--
33
2.20.1
37
2.20.1
34
38
35
39
diff view generated by jsdifflib
1
Move the NS TBFLAG down from bit 19 to bit 6, which has not
1
From: Richard Henderson <richard.henderson@linaro.org>
2
been used since commit c1e3781090b9d36c60 in 2015, when we
3
started passing the entire MMU index in the TB flags rather
4
than just a 'privilege level' bit.
5
2
6
This rearrangement is not strictly necessary, but means that
3
Transform the prot bit to a qemu internal page bit, and save
7
we can put M-profile-only bits next to each other rather
4
it in the page tables.
8
than scattered across the flag word.
9
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201021173749.111103-3-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 20190416125744.27770-17-peter.maydell@linaro.org
13
---
10
---
14
target/arm/cpu.h | 11 ++++++-----
11
include/exec/cpu-all.h | 2 ++
15
1 file changed, 6 insertions(+), 5 deletions(-)
12
linux-user/syscall_defs.h | 4 ++++
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(-)
16
17
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 */
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
46
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
18
index XXXXXXX..XXXXXXX 100644
47
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpu.h
48
--- a/target/arm/cpu.h
20
+++ b/target/arm/cpu.h
49
+++ b/target/arm/cpu.h
21
@@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_ANY, BE_DATA, 23, 1)
50
@@ -XXX,XX +XXX,XX @@ static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x)
22
FIELD(TBFLAG_A32, THUMB, 0, 1)
51
#define arm_tlb_bti_gp(x) (typecheck_memtxattrs(x)->target_tlb_bit0)
23
FIELD(TBFLAG_A32, VECLEN, 1, 3)
52
#define arm_tlb_mte_tagged(x) (typecheck_memtxattrs(x)->target_tlb_bit1)
24
FIELD(TBFLAG_A32, VECSTRIDE, 4, 2)
53
25
+/*
54
+/*
26
+ * Indicates whether cp register reads and writes by guest code should access
55
+ * AArch64 usage of the PAGE_TARGET_* bits for linux-user.
27
+ * the secure or nonsecure bank of banked registers; note that this is not
28
+ * the same thing as the current security state of the processor!
29
+ */
56
+ */
30
+FIELD(TBFLAG_A32, NS, 6, 1)
57
+#define PAGE_BTI PAGE_TARGET_1
31
FIELD(TBFLAG_A32, VFPEN, 7, 1)
58
+
32
FIELD(TBFLAG_A32, CONDEXEC, 8, 8)
59
/*
33
FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
60
* Naming convention for isar_feature functions:
34
@@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
61
* Functions which test 32-bit ID registers should have _aa32_ in
35
* checks on the other bits at runtime
62
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
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
+
86
return prot & ~valid ? 0 : page_flags;
87
}
88
89
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
90
index XXXXXXX..XXXXXXX 100644
91
--- a/target/arm/translate-a64.c
92
+++ b/target/arm/translate-a64.c
93
@@ -XXX,XX +XXX,XX @@ static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
36
*/
94
*/
37
FIELD(TBFLAG_A32, XSCALE_CPAR, 17, 2)
95
static bool is_guarded_page(CPUARMState *env, DisasContext *s)
38
-/* Indicates whether cp register reads and writes by guest code should access
96
{
39
- * the secure or nonsecure bank of banked registers; note that this is not
97
-#ifdef CONFIG_USER_ONLY
40
- * the same thing as the current security state of the processor!
98
- return false; /* FIXME */
41
- */
99
-#else
42
-FIELD(TBFLAG_A32, NS, 19, 1)
100
uint64_t addr = s->base.pc_first;
43
/* For M profile only, Handler (ie not Thread) mode */
101
+#ifdef CONFIG_USER_ONLY
44
FIELD(TBFLAG_A32, HANDLER, 21, 1)
102
+ return page_get_flags(addr) & PAGE_BTI;
45
/* For M profile only, whether we should generate stack-limit checks */
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);
46
--
107
--
47
2.20.1
108
2.20.1
48
109
49
110
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
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: 20201021173749.111103-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
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
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: 20201021173749.111103-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
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
Fixing this now will clarify following patches.
4
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20201021173749.111103-6-richard.henderson@linaro.org
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.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
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
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
Message-id: 20201021173749.111103-7-richard.henderson@linaro.org
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.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
Handle floating point registers in exception return.
1
From: Richard Henderson <richard.henderson@linaro.org>
2
This corresponds to pseudocode functions ValidateExceptionReturn(),
3
ExceptionReturn(), PopStack() and ConsumeExcStackFrame().
4
2
3
For BTI, we need to know if the executable is static or dynamic,
4
which means looking for PT_INTERP earlier.
5
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20201021173749.111103-8-richard.henderson@linaro.org
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20190416125744.27770-16-peter.maydell@linaro.org
8
---
10
---
9
target/arm/helper.c | 142 +++++++++++++++++++++++++++++++++++++++++++-
11
linux-user/elfload.c | 60 +++++++++++++++++++++++---------------------
10
1 file changed, 141 insertions(+), 1 deletion(-)
12
1 file changed, 31 insertions(+), 29 deletions(-)
11
13
12
diff --git a/target/arm/helper.c b/target/arm/helper.c
14
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
13
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/helper.c
16
--- a/linux-user/elfload.c
15
+++ b/target/arm/helper.c
17
+++ b/linux-user/elfload.c
16
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
18
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
17
bool rettobase = false;
19
18
bool exc_secure = false;
20
mmap_lock();
19
bool return_to_secure;
21
20
+ bool ftype;
22
- /* Find the maximum size of the image and allocate an appropriate
21
+ bool restore_s16_s31;
23
- amount of memory to handle that. */
22
24
+ /*
23
/* If we're not in Handler mode then jumps to magic exception-exit
25
+ * Find the maximum size of the image and allocate an appropriate
24
* addresses don't have magic behaviour. However for the v8M
26
+ * amount of memory to handle that. Locate the interpreter, if any.
25
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
27
+ */
26
excret);
28
loaddr = -1, hiaddr = 0;
27
}
29
info->alignment = 0;
28
30
for (i = 0; i < ehdr->e_phnum; ++i) {
29
+ ftype = excret & R_V7M_EXCRET_FTYPE_MASK;
31
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
32
}
33
++info->nsegs;
34
info->alignment |= eppnt->p_align;
35
+ } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
36
+ g_autofree char *interp_name = NULL;
30
+
37
+
31
+ if (!arm_feature(env, ARM_FEATURE_VFP) && !ftype) {
38
+ if (*pinterp_name) {
32
+ qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero FTYPE in exception "
39
+ errmsg = "Multiple PT_INTERP entries";
33
+ "exit PC value 0x%" PRIx32 " is UNPREDICTABLE "
40
+ goto exit_errmsg;
34
+ "if FPU not present\n",
35
+ excret);
36
+ ftype = true;
37
+ }
38
+
39
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
40
/* EXC_RETURN.ES validation check (R_SMFL). We must do this before
41
* we pick which FAULTMASK to clear.
42
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
43
*/
44
write_v7m_control_spsel_for_secstate(env, return_to_sp_process, exc_secure);
45
46
+ /*
47
+ * Clear scratch FP values left in caller saved registers; this
48
+ * must happen before any kind of tail chaining.
49
+ */
50
+ if ((env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_CLRONRET_MASK) &&
51
+ (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
52
+ if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) {
53
+ env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
54
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
55
+ qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
56
+ "stackframe: error during lazy state deactivation\n");
57
+ v7m_exception_taken(cpu, excret, true, false);
58
+ return;
59
+ } else {
60
+ /* Clear s0..s15 and FPSCR */
61
+ int i;
62
+
63
+ for (i = 0; i < 16; i += 2) {
64
+ *aa32_vfp_dreg(env, i / 2) = 0;
65
+ }
41
+ }
66
+ vfp_set_fpscr(env, 0);
42
+ interp_name = g_malloc(eppnt->p_filesz);
67
+ }
43
+ if (!interp_name) {
68
+ }
44
+ goto exit_perror;
69
+
70
if (sfault) {
71
env->v7m.sfsr |= R_V7M_SFSR_INVER_MASK;
72
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
73
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
74
}
75
}
76
77
+ if (!ftype) {
78
+ /* FP present and we need to handle it */
79
+ if (!return_to_secure &&
80
+ (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK)) {
81
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
82
+ env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
83
+ qemu_log_mask(CPU_LOG_INT,
84
+ "...taking SecureFault on existing stackframe: "
85
+ "Secure LSPACT set but exception return is "
86
+ "not to secure state\n");
87
+ v7m_exception_taken(cpu, excret, true, false);
88
+ return;
89
+ }
45
+ }
90
+
46
+
91
+ restore_s16_s31 = return_to_secure &&
47
+ if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
92
+ (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
48
+ memcpy(interp_name, bprm_buf + eppnt->p_offset,
93
+
49
+ eppnt->p_filesz);
94
+ if (env->v7m.fpccr[return_to_secure] & R_V7M_FPCCR_LSPACT_MASK) {
95
+ /* State in FPU is still valid, just clear LSPACT */
96
+ env->v7m.fpccr[return_to_secure] &= ~R_V7M_FPCCR_LSPACT_MASK;
97
+ } else {
50
+ } else {
98
+ int i;
51
+ retval = pread(image_fd, interp_name, eppnt->p_filesz,
99
+ uint32_t fpscr;
52
+ eppnt->p_offset);
100
+ bool cpacr_pass, nsacr_pass;
53
+ if (retval != eppnt->p_filesz) {
101
+
54
+ goto exit_perror;
102
+ cpacr_pass = v7m_cpacr_pass(env, return_to_secure,
103
+ return_to_priv);
104
+ nsacr_pass = return_to_secure ||
105
+ extract32(env->v7m.nsacr, 10, 1);
106
+
107
+ if (!cpacr_pass) {
108
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
109
+ return_to_secure);
110
+ env->v7m.cfsr[return_to_secure] |= R_V7M_CFSR_NOCP_MASK;
111
+ qemu_log_mask(CPU_LOG_INT,
112
+ "...taking UsageFault on existing "
113
+ "stackframe: CPACR.CP10 prevents unstacking "
114
+ "FP regs\n");
115
+ v7m_exception_taken(cpu, excret, true, false);
116
+ return;
117
+ } else if (!nsacr_pass) {
118
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, true);
119
+ env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_INVPC_MASK;
120
+ qemu_log_mask(CPU_LOG_INT,
121
+ "...taking Secure UsageFault on existing "
122
+ "stackframe: NSACR.CP10 prevents unstacking "
123
+ "FP regs\n");
124
+ v7m_exception_taken(cpu, excret, true, false);
125
+ return;
126
+ }
127
+
128
+ for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
129
+ uint32_t slo, shi;
130
+ uint64_t dn;
131
+ uint32_t faddr = frameptr + 0x20 + 4 * i;
132
+
133
+ if (i >= 16) {
134
+ faddr += 8; /* Skip the slot for the FPSCR */
135
+ }
136
+
137
+ pop_ok = pop_ok &&
138
+ v7m_stack_read(cpu, &slo, faddr, mmu_idx) &&
139
+ v7m_stack_read(cpu, &shi, faddr + 4, mmu_idx);
140
+
141
+ if (!pop_ok) {
142
+ break;
143
+ }
144
+
145
+ dn = (uint64_t)shi << 32 | slo;
146
+ *aa32_vfp_dreg(env, i / 2) = dn;
147
+ }
148
+ pop_ok = pop_ok &&
149
+ v7m_stack_read(cpu, &fpscr, frameptr + 0x60, mmu_idx);
150
+ if (pop_ok) {
151
+ vfp_set_fpscr(env, fpscr);
152
+ }
153
+ if (!pop_ok) {
154
+ /*
155
+ * These regs are 0 if security extension present;
156
+ * otherwise merely UNKNOWN. We zero always.
157
+ */
158
+ for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
159
+ *aa32_vfp_dreg(env, i / 2) = 0;
160
+ }
161
+ vfp_set_fpscr(env, 0);
162
+ }
55
+ }
163
+ }
56
+ }
164
+ }
57
+ if (interp_name[eppnt->p_filesz - 1] != 0) {
165
+ env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
58
+ errmsg = "Invalid PT_INTERP entry";
166
+ V7M_CONTROL, FPCA, !ftype);
59
+ goto exit_errmsg;
167
+
168
/* Commit to consuming the stack frame */
169
frameptr += 0x20;
170
+ if (!ftype) {
171
+ frameptr += 0x48;
172
+ if (restore_s16_s31) {
173
+ frameptr += 0x40;
174
+ }
60
+ }
175
+ }
61
+ *pinterp_name = g_steal_pointer(&interp_name);
176
/* Undo stack alignment (the SPREALIGN bit indicates that the original
62
}
177
* pre-exception SP was not 8-aligned and we added a padding word to
178
* align it, so we undo this by ORing in the bit that increases it
179
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
180
*frame_sp_p = frameptr;
181
}
63
}
182
/* This xpsr_write() will invalidate frame_sp_p as it may switch stack */
64
183
- xpsr_write(env, xpsr, ~XPSR_SPREALIGN);
65
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
184
+ xpsr_write(env, xpsr, ~(XPSR_SPREALIGN | XPSR_SFPA));
66
if (vaddr_em > info->brk) {
185
+
67
info->brk = vaddr_em;
186
+ if (env->v7m.secure) {
68
}
187
+ bool sfpa = xpsr & XPSR_SFPA;
69
- } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
188
+
70
- g_autofree char *interp_name = NULL;
189
+ env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
71
-
190
+ V7M_CONTROL, SFPA, sfpa);
72
- if (*pinterp_name) {
191
+ }
73
- errmsg = "Multiple PT_INTERP entries";
192
74
- goto exit_errmsg;
193
/* The restored xPSR exception field will be zero if we're
75
- }
194
* resuming in Thread mode. If that doesn't match what the
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;
195
--
99
--
196
2.20.1
100
2.20.1
197
101
198
102
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Reviewed-by: Thomas Huth <thuth@redhat.com>
3
This is a bit clearer than open-coding some of this
4
Reviewed-by: Cédric Le Goater <clg@kaod.org>
4
with a bare c string.
5
Reviewed-by: Markus Armbruster <armbru@redhat.com>
5
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20190412165416.7977-2-philmd@redhat.com
7
Message-id: 20201021173749.111103-9-richard.henderson@linaro.org
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
---
10
hw/arm/aspeed.c | 13 +++++++++----
11
linux-user/elfload.c | 37 ++++++++++++++++++++-----------------
11
1 file changed, 9 insertions(+), 4 deletions(-)
12
1 file changed, 20 insertions(+), 17 deletions(-)
12
13
13
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
14
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
14
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/arm/aspeed.c
16
--- a/linux-user/elfload.c
16
+++ b/hw/arm/aspeed.c
17
+++ b/linux-user/elfload.c
17
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@
18
#include "hw/arm/aspeed_soc.h"
19
#include "qemu/guest-random.h"
19
#include "hw/boards.h"
20
#include "qemu/units.h"
20
#include "hw/i2c/smbus_eeprom.h"
21
#include "qemu/selfmap.h"
21
+#include "hw/misc/pca9552.h"
22
+#include "qapi/error.h"
22
+#include "hw/misc/tmp105.h"
23
23
#include "qemu/log.h"
24
#ifdef _ARCH_PPC64
24
#include "sysemu/block-backend.h"
25
#undef ARCH_DLINFO
25
#include "hw/loader.h"
26
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
26
@@ -XXX,XX +XXX,XX @@ static void ast2500_evb_i2c_init(AspeedBoardState *bmc)
27
struct elf_phdr *phdr;
27
eeprom_buf);
28
abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
28
29
int i, retval;
29
/* The AST2500 EVB expects a LM75 but a TMP105 is compatible */
30
- const char *errmsg;
30
- i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7), "tmp105", 0x4d);
31
+ Error *err = NULL;
31
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7),
32
32
+ TYPE_TMP105, 0x4d);
33
/* First of all, some simple consistency checks */
33
34
- errmsg = "Invalid ELF image for this architecture";
34
/* The AST2500 EVB does not have an RTC. Let's pretend that one is
35
if (!elf_check_ident(ehdr)) {
35
* plugged on the I2C bus header */
36
+ error_setg(&err, "Invalid ELF image for this architecture");
36
@@ -XXX,XX +XXX,XX @@ static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc)
37
goto exit_errmsg;
37
AspeedSoCState *soc = &bmc->soc;
38
}
38
uint8_t *eeprom_buf = g_malloc0(8 * 1024);
39
bswap_ehdr(ehdr);
39
40
if (!elf_check_ehdr(ehdr)) {
40
- i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), "pca9552", 0x60);
41
+ error_setg(&err, "Invalid ELF image for this architecture");
41
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), TYPE_PCA9552,
42
goto exit_errmsg;
42
+ 0x60);
43
}
43
44
44
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 4), "tmp423", 0x4c);
45
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
45
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 5), "tmp423", 0x4c);
46
g_autofree char *interp_name = NULL;
46
47
47
/* The Witherspoon expects a TMP275 but a TMP105 is compatible */
48
if (*pinterp_name) {
48
- i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 9), "tmp105", 0x4a);
49
- errmsg = "Multiple PT_INTERP entries";
49
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 9), TYPE_TMP105,
50
+ error_setg(&err, "Multiple PT_INTERP entries");
50
+ 0x4a);
51
goto exit_errmsg;
51
52
}
52
/* The witherspoon board expects Epson RX8900 I2C RTC but a ds1338 is
53
+
53
* good enough */
54
interp_name = g_malloc(eppnt->p_filesz);
54
@@ -XXX,XX +XXX,XX @@ static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc)
55
- if (!interp_name) {
55
56
- goto exit_perror;
56
smbus_eeprom_init_one(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), 0x51,
57
- }
57
eeprom_buf);
58
58
- i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "pca9552",
59
if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
59
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), TYPE_PCA9552,
60
memcpy(interp_name, bprm_buf + eppnt->p_offset,
60
0x60);
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);
61
}
131
}
62
132
63
--
133
--
64
2.20.1
134
2.20.1
65
135
66
136
diff view generated by jsdifflib
1
We are close to running out of TB flags for AArch32; we could
1
From: Richard Henderson <richard.henderson@linaro.org>
2
start using the cs_base word, but before we do that we can
3
economise on our usage by sharing the same bits for the VFP
4
VECSTRIDE field and the XScale XSCALE_CPAR field. This
5
works because no XScale CPU ever had VFP.
6
2
3
This is slightly clearer than just using strerror, though
4
the different forms produced by error_setg_file_open and
5
error_setg_errno isn't entirely convenient.
6
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201021173749.111103-10-richard.henderson@linaro.org
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20190416125744.27770-18-peter.maydell@linaro.org
10
---
11
---
11
target/arm/cpu.h | 10 ++++++----
12
linux-user/elfload.c | 15 ++++++++-------
12
target/arm/cpu.c | 7 +++++++
13
1 file changed, 8 insertions(+), 7 deletions(-)
13
target/arm/helper.c | 6 +++++-
14
target/arm/translate.c | 9 +++++++--
15
4 files changed, 25 insertions(+), 7 deletions(-)
16
14
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
15
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
18
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpu.h
17
--- a/linux-user/elfload.c
20
+++ b/target/arm/cpu.h
18
+++ b/linux-user/elfload.c
21
@@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_ANY, BE_DATA, 23, 1)
19
@@ -XXX,XX +XXX,XX @@ static void load_elf_interp(const char *filename, struct image_info *info,
22
FIELD(TBFLAG_A32, THUMB, 0, 1)
20
char bprm_buf[BPRM_BUF_SIZE])
23
FIELD(TBFLAG_A32, VECLEN, 1, 3)
21
{
24
FIELD(TBFLAG_A32, VECSTRIDE, 4, 2)
22
int fd, retval;
25
+/*
23
+ Error *err = NULL;
26
+ * We store the bottom two bits of the CPAR as TB flags and handle
24
27
+ * checks on the other bits at runtime. This shares the same bits as
25
fd = open(path(filename), O_RDONLY);
28
+ * VECSTRIDE, which is OK as no XScale CPU has VFP.
26
if (fd < 0) {
29
+ */
27
- goto exit_perror;
30
+FIELD(TBFLAG_A32, XSCALE_CPAR, 4, 2)
28
+ error_setg_file_open(&err, errno, filename);
31
/*
29
+ error_report_err(err);
32
* Indicates whether cp register reads and writes by guest code should access
30
+ exit(-1);
33
* the secure or nonsecure bank of banked registers; note that this is not
34
@@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A32, NS, 6, 1)
35
FIELD(TBFLAG_A32, VFPEN, 7, 1)
36
FIELD(TBFLAG_A32, CONDEXEC, 8, 8)
37
FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
38
-/* We store the bottom two bits of the CPAR as TB flags and handle
39
- * checks on the other bits at runtime
40
- */
41
-FIELD(TBFLAG_A32, XSCALE_CPAR, 17, 2)
42
/* For M profile only, Handler (ie not Thread) mode */
43
FIELD(TBFLAG_A32, HANDLER, 21, 1)
44
/* For M profile only, whether we should generate stack-limit checks */
45
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
46
index XXXXXXX..XXXXXXX 100644
47
--- a/target/arm/cpu.c
48
+++ b/target/arm/cpu.c
49
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
50
set_feature(env, ARM_FEATURE_THUMB_DSP);
51
}
31
}
52
32
53
+ /*
33
retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
54
+ * We rely on no XScale CPU having VFP so we can use the same bits in the
34
if (retval < 0) {
55
+ * TB flags field for VECSTRIDE and XSCALE_CPAR.
35
- goto exit_perror;
56
+ */
36
+ error_setg_errno(&err, errno, "Error reading file header");
57
+ assert(!(arm_feature(env, ARM_FEATURE_VFP) &&
37
+ error_reportf_err(err, "%s: ", filename);
58
+ arm_feature(env, ARM_FEATURE_XSCALE)));
38
+ exit(-1);
39
}
59
+
40
+
60
if (arm_feature(env, ARM_FEATURE_V7) &&
41
if (retval < BPRM_BUF_SIZE) {
61
!arm_feature(env, ARM_FEATURE_M) &&
42
memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
62
!arm_feature(env, ARM_FEATURE_PMSA)) {
63
diff --git a/target/arm/helper.c b/target/arm/helper.c
64
index XXXXXXX..XXXXXXX 100644
65
--- a/target/arm/helper.c
66
+++ b/target/arm/helper.c
67
@@ -XXX,XX +XXX,XX @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
68
|| arm_el_is_aa64(env, 1) || arm_feature(env, ARM_FEATURE_M)) {
69
flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1);
70
}
71
- flags = FIELD_DP32(flags, TBFLAG_A32, XSCALE_CPAR, env->cp15.c15_cpar);
72
+ /* Note that XSCALE_CPAR shares bits with VECSTRIDE */
73
+ if (arm_feature(env, ARM_FEATURE_XSCALE)) {
74
+ flags = FIELD_DP32(flags, TBFLAG_A32,
75
+ XSCALE_CPAR, env->cp15.c15_cpar);
76
+ }
77
}
43
}
78
44
79
flags = FIELD_DP32(flags, TBFLAG_ANY, MMUIDX, arm_to_core_mmu_idx(mmu_idx));
45
load_elf_image(filename, fd, info, NULL, bprm_buf);
80
diff --git a/target/arm/translate.c b/target/arm/translate.c
46
- return;
81
index XXXXXXX..XXXXXXX 100644
47
-
82
--- a/target/arm/translate.c
48
- exit_perror:
83
+++ b/target/arm/translate.c
49
- fprintf(stderr, "%s: %s\n", filename, strerror(errno));
84
@@ -XXX,XX +XXX,XX @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
50
- exit(-1);
85
dc->fp_excp_el = FIELD_EX32(tb_flags, TBFLAG_ANY, FPEXC_EL);
51
}
86
dc->vfp_enabled = FIELD_EX32(tb_flags, TBFLAG_A32, VFPEN);
52
87
dc->vec_len = FIELD_EX32(tb_flags, TBFLAG_A32, VECLEN);
53
static int symfind(const void *s0, const void *s1)
88
- dc->vec_stride = FIELD_EX32(tb_flags, TBFLAG_A32, VECSTRIDE);
89
- dc->c15_cpar = FIELD_EX32(tb_flags, TBFLAG_A32, XSCALE_CPAR);
90
+ if (arm_feature(env, ARM_FEATURE_XSCALE)) {
91
+ dc->c15_cpar = FIELD_EX32(tb_flags, TBFLAG_A32, XSCALE_CPAR);
92
+ dc->vec_stride = 0;
93
+ } else {
94
+ dc->vec_stride = FIELD_EX32(tb_flags, TBFLAG_A32, VECSTRIDE);
95
+ dc->c15_cpar = 0;
96
+ }
97
dc->v7m_handler_mode = FIELD_EX32(tb_flags, TBFLAG_A32, HANDLER);
98
dc->v8m_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
99
regime_is_secure(env, dc->mmu_idx);
100
--
54
--
101
2.20.1
55
2.20.1
102
56
103
57
diff view generated by jsdifflib
1
Like AArch64, M-profile floating point has no FPEXC enable
1
From: Richard Henderson <richard.henderson@linaro.org>
2
bit to gate floating point; so always set the VFPEN TB flag.
2
3
3
This is generic support, with the code disabled for all targets.
4
M-profile also has CPACR and NSACR similar to A-profile;
4
5
they behave slightly differently:
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
* the CPACR is banked between Secure and Non-Secure
6
Message-id: 20201021173749.111103-11-richard.henderson@linaro.org
7
* if the NSACR forces a trap then this is taken to
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
the Secure state, not the Non-Secure state
9
10
Honour the CPACR and NSACR settings. The NSACR handling
11
requires us to borrow the exception.target_el field
12
(usually meaningless for M profile) to distinguish the
13
NOCP UsageFault taken to Secure state from the more
14
usual fault taken to the current security state.
15
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
18
Message-id: 20190416125744.27770-6-peter.maydell@linaro.org
19
---
9
---
20
target/arm/helper.c | 55 +++++++++++++++++++++++++++++++++++++++---
10
linux-user/qemu.h | 4 ++
21
target/arm/translate.c | 10 ++++++--
11
linux-user/elfload.c | 157 +++++++++++++++++++++++++++++++++++++++++++
22
2 files changed, 60 insertions(+), 5 deletions(-)
12
2 files changed, 161 insertions(+)
23
13
24
diff --git a/target/arm/helper.c b/target/arm/helper.c
14
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
25
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
26
--- a/target/arm/helper.c
16
--- a/linux-user/qemu.h
27
+++ b/target/arm/helper.c
17
+++ b/linux-user/qemu.h
28
@@ -XXX,XX +XXX,XX @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
18
@@ -XXX,XX +XXX,XX @@ struct image_info {
29
return target_el;
19
abi_ulong interpreter_loadmap_addr;
20
abi_ulong interpreter_pt_dynamic_addr;
21
struct image_info *other_info;
22
+
23
+ /* For target-specific processing of NT_GNU_PROPERTY_TYPE_0. */
24
+ uint32_t note_flags;
25
+
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);
30
}
51
}
31
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
+
32
+/*
61
+/*
33
+ * Return true if the v7M CPACR permits access to the FPU for the specified
62
+ * Process a single gnu_property entry.
34
+ * security state and privilege level.
63
+ * Return false for error.
35
+ */
64
+ */
36
+static bool v7m_cpacr_pass(CPUARMState *env, bool is_secure, bool is_priv)
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)
37
+{
68
+{
38
+ switch (extract32(env->v7m.cpacr[is_secure], 20, 2)) {
69
+ uint32_t pr_type, pr_datasz, step;
39
+ case 0:
70
+
40
+ case 2: /* UNPREDICTABLE: we treat like 0 */
71
+ if (*off > datasz || !QEMU_IS_ALIGNED(*off, ELF_GNU_PROPERTY_ALIGN)) {
41
+ return false;
72
+ goto error_data;
42
+ case 1:
73
+ }
43
+ return is_priv;
74
+ datasz -= *off;
44
+ case 3:
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) {
45
+ return true;
130
+ return true;
46
+ default:
131
+ }
47
+ g_assert_not_reached();
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;
48
+ }
194
+ }
49
+}
195
+}
50
+
196
+
51
static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value,
197
/* Load an ELF image into the address space.
52
ARMMMUIdx mmu_idx, bool ignfault)
198
53
{
199
IMAGE_NAME is the filename of the image, to use in error messages.
54
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
200
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
55
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNDEFINSTR_MASK;
201
goto exit_errmsg;
56
break;
202
}
57
case EXCP_NOCP:
203
*pinterp_name = g_steal_pointer(&interp_name);
58
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
204
+ } else if (eppnt->p_type == PT_GNU_PROPERTY) {
59
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK;
205
+ if (!parse_elf_properties(image_fd, info, eppnt, bprm_buf, &err)) {
60
+ {
206
+ goto exit_errmsg;
61
+ /*
207
+ }
62
+ * NOCP might be directed to something other than the current
208
}
63
+ * security state if this fault is because of NSACR; we indicate
64
+ * the target security state using exception.target_el.
65
+ */
66
+ int target_secstate;
67
+
68
+ if (env->exception.target_el == 3) {
69
+ target_secstate = M_REG_S;
70
+ } else {
71
+ target_secstate = env->v7m.secure;
72
+ }
73
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, target_secstate);
74
+ env->v7m.cfsr[target_secstate] |= R_V7M_CFSR_NOCP_MASK;
75
break;
76
+ }
77
case EXCP_INVSTATE:
78
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
79
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
80
@@ -XXX,XX +XXX,XX @@ int fp_exception_el(CPUARMState *env, int cur_el)
81
return 0;
82
}
209
}
83
84
+ if (arm_feature(env, ARM_FEATURE_M)) {
85
+ /* CPACR can cause a NOCP UsageFault taken to current security state */
86
+ if (!v7m_cpacr_pass(env, env->v7m.secure, cur_el != 0)) {
87
+ return 1;
88
+ }
89
+
90
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY) && !env->v7m.secure) {
91
+ if (!extract32(env->v7m.nsacr, 10, 1)) {
92
+ /* FP insns cause a NOCP UsageFault taken to Secure */
93
+ return 3;
94
+ }
95
+ }
96
+
97
+ return 0;
98
+ }
99
+
100
/* The CPACR controls traps to EL1, or PL1 if we're 32 bit:
101
* 0, 2 : trap EL0 and EL1/PL1 accesses
102
* 1 : trap only EL0 accesses
103
@@ -XXX,XX +XXX,XX @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
104
flags = FIELD_DP32(flags, TBFLAG_A32, SCTLR_B, arm_sctlr_b(env));
105
flags = FIELD_DP32(flags, TBFLAG_A32, NS, !access_secure_reg(env));
106
if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)
107
- || arm_el_is_aa64(env, 1)) {
108
+ || arm_el_is_aa64(env, 1) || arm_feature(env, ARM_FEATURE_M)) {
109
flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1);
110
}
111
flags = FIELD_DP32(flags, TBFLAG_A32, XSCALE_CPAR, env->cp15.c15_cpar);
112
diff --git a/target/arm/translate.c b/target/arm/translate.c
113
index XXXXXXX..XXXXXXX 100644
114
--- a/target/arm/translate.c
115
+++ b/target/arm/translate.c
116
@@ -XXX,XX +XXX,XX @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
117
* for attempts to execute invalid vfp/neon encodings with FP disabled.
118
*/
119
if (s->fp_excp_el) {
120
- gen_exception_insn(s, 4, EXCP_UDEF,
121
- syn_fp_access_trap(1, 0xe, false), s->fp_excp_el);
122
+ if (arm_dc_feature(s, ARM_FEATURE_M)) {
123
+ gen_exception_insn(s, 4, EXCP_NOCP, syn_uncategorized(),
124
+ s->fp_excp_el);
125
+ } else {
126
+ gen_exception_insn(s, 4, EXCP_UDEF,
127
+ syn_fp_access_trap(1, 0xe, false),
128
+ s->fp_excp_el);
129
+ }
130
return 0;
131
}
132
210
133
--
211
--
134
2.20.1
212
2.20.1
135
213
136
214
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
Use the new generic support for NT_GNU_PROPERTY_TYPE_0.
4
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20201021173749.111103-12-richard.henderson@linaro.org
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
linux-user/elfload.c | 48 ++++++++++++++++++++++++++++++++++++++++++--
11
1 file changed, 46 insertions(+), 2 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 elf_core_copy_regs(target_elf_gregset_t *regs,
18
19
#include "elf.h"
20
21
+/* We must delay the following stanzas until after "elf.h". */
22
+#if defined(TARGET_AARCH64)
23
+
24
+static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
25
+ const uint32_t *data,
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
--
101
2.20.1
102
103
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
This commit finally deletes "hw/devices.h".
3
The note test requires gcc 10 for -mbranch-protection=standard.
4
4
The mmap test uses PROT_BTI and does not require special compiler support.
5
Reviewed-by: Markus Armbruster <armbru@redhat.com>
5
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
6
Acked-by: Alex Bennée <alex.bennee@linaro.org>
7
Message-id: 20190412165416.7977-13-philmd@redhat.com
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20201021173749.111103-13-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
11
---
10
include/hw/devices.h | 11 -----------
12
tests/tcg/aarch64/bti-1.c | 62 ++++++++++++++++
11
include/hw/net/smc91c111.h | 19 +++++++++++++++++++
13
tests/tcg/aarch64/bti-2.c | 116 ++++++++++++++++++++++++++++++
12
hw/arm/gumstix.c | 2 +-
14
tests/tcg/aarch64/bti-crt.inc.c | 51 +++++++++++++
13
hw/arm/integratorcp.c | 2 +-
15
tests/tcg/aarch64/Makefile.target | 10 +++
14
hw/arm/mainstone.c | 2 +-
16
tests/tcg/configure.sh | 4 ++
15
hw/arm/realview.c | 2 +-
17
5 files changed, 243 insertions(+)
16
hw/arm/versatilepb.c | 2 +-
18
create mode 100644 tests/tcg/aarch64/bti-1.c
17
hw/net/smc91c111.c | 2 +-
19
create mode 100644 tests/tcg/aarch64/bti-2.c
18
8 files changed, 25 insertions(+), 17 deletions(-)
20
create mode 100644 tests/tcg/aarch64/bti-crt.inc.c
19
delete mode 100644 include/hw/devices.h
21
20
create mode 100644 include/hw/net/smc91c111.h
22
diff --git a/tests/tcg/aarch64/bti-1.c b/tests/tcg/aarch64/bti-1.c
21
22
diff --git a/include/hw/devices.h b/include/hw/devices.h
23
deleted file mode 100644
24
index XXXXXXX..XXXXXXX
25
--- a/include/hw/devices.h
26
+++ /dev/null
27
@@ -XXX,XX +XXX,XX @@
28
-#ifndef QEMU_DEVICES_H
29
-#define QEMU_DEVICES_H
30
-
31
-/* Devices that have nowhere better to go. */
32
-
33
-#include "hw/hw.h"
34
-
35
-/* smc91c111.c */
36
-void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
37
-
38
-#endif
39
diff --git a/include/hw/net/smc91c111.h b/include/hw/net/smc91c111.h
40
new file mode 100644
23
new file mode 100644
41
index XXXXXXX..XXXXXXX
24
index XXXXXXX..XXXXXXX
42
--- /dev/null
25
--- /dev/null
43
+++ b/include/hw/net/smc91c111.h
26
+++ b/tests/tcg/aarch64/bti-1.c
44
@@ -XXX,XX +XXX,XX @@
27
@@ -XXX,XX +XXX,XX @@
45
+/*
28
+/*
46
+ * SMSC 91C111 Ethernet interface emulation
29
+ * Branch target identification, basic notskip cases.
30
+ */
31
+
32
+#include "bti-crt.inc.c"
33
+
34
+static void skip2_sigill(int sig, siginfo_t *info, ucontext_t *uc)
35
+{
36
+ uc->uc_mcontext.pc += 8;
37
+ uc->uc_mcontext.pstate = 1;
38
+}
39
+
40
+#define NOP "nop"
41
+#define BTI_N "hint #32"
42
+#define BTI_C "hint #34"
43
+#define BTI_J "hint #36"
44
+#define BTI_JC "hint #38"
45
+
46
+#define BTYPE_1(DEST) \
47
+ asm("mov %0,#1; adr x16, 1f; br x16; 1: " DEST "; mov %0,#0" \
48
+ : "=r"(skipped) : : "x16")
49
+
50
+#define BTYPE_2(DEST) \
51
+ asm("mov %0,#1; adr x16, 1f; blr x16; 1: " DEST "; mov %0,#0" \
52
+ : "=r"(skipped) : : "x16", "x30")
53
+
54
+#define BTYPE_3(DEST) \
55
+ asm("mov %0,#1; adr x15, 1f; br x15; 1: " DEST "; mov %0,#0" \
56
+ : "=r"(skipped) : : "x15")
57
+
58
+#define TEST(WHICH, DEST, EXPECT) \
59
+ do { WHICH(DEST); fail += skipped ^ EXPECT; } while (0)
60
+
61
+
62
+int main()
63
+{
64
+ int fail = 0;
65
+ int skipped;
66
+
67
+ /* Signal-like with SA_SIGINFO. */
68
+ signal_info(SIGILL, skip2_sigill);
69
+
70
+ TEST(BTYPE_1, NOP, 1);
71
+ TEST(BTYPE_1, BTI_N, 1);
72
+ TEST(BTYPE_1, BTI_C, 0);
73
+ TEST(BTYPE_1, BTI_J, 0);
74
+ TEST(BTYPE_1, BTI_JC, 0);
75
+
76
+ TEST(BTYPE_2, NOP, 1);
77
+ TEST(BTYPE_2, BTI_N, 1);
78
+ TEST(BTYPE_2, BTI_C, 0);
79
+ TEST(BTYPE_2, BTI_J, 1);
80
+ TEST(BTYPE_2, BTI_JC, 0);
81
+
82
+ TEST(BTYPE_3, NOP, 1);
83
+ TEST(BTYPE_3, BTI_N, 1);
84
+ TEST(BTYPE_3, BTI_C, 1);
85
+ TEST(BTYPE_3, BTI_J, 0);
86
+ TEST(BTYPE_3, BTI_JC, 0);
87
+
88
+ return fail;
89
+}
90
diff --git a/tests/tcg/aarch64/bti-2.c b/tests/tcg/aarch64/bti-2.c
91
new file mode 100644
92
index XXXXXXX..XXXXXXX
93
--- /dev/null
94
+++ b/tests/tcg/aarch64/bti-2.c
95
@@ -XXX,XX +XXX,XX @@
96
+/*
97
+ * Branch target identification, basic notskip cases.
98
+ */
99
+
100
+#include <stdio.h>
101
+#include <signal.h>
102
+#include <string.h>
103
+#include <unistd.h>
104
+#include <sys/mman.h>
105
+
106
+#ifndef PROT_BTI
107
+#define PROT_BTI 0x10
108
+#endif
109
+
110
+static void skip2_sigill(int sig, siginfo_t *info, void *vuc)
111
+{
112
+ ucontext_t *uc = vuc;
113
+ uc->uc_mcontext.pc += 8;
114
+ uc->uc_mcontext.pstate = 1;
115
+}
116
+
117
+#define NOP "nop"
118
+#define BTI_N "hint #32"
119
+#define BTI_C "hint #34"
120
+#define BTI_J "hint #36"
121
+#define BTI_JC "hint #38"
122
+
123
+#define BTYPE_1(DEST) \
124
+ "mov x1, #1\n\t" \
125
+ "adr x16, 1f\n\t" \
126
+ "br x16\n" \
127
+"1: " DEST "\n\t" \
128
+ "mov x1, #0"
129
+
130
+#define BTYPE_2(DEST) \
131
+ "mov x1, #1\n\t" \
132
+ "adr x16, 1f\n\t" \
133
+ "blr x16\n" \
134
+"1: " DEST "\n\t" \
135
+ "mov x1, #0"
136
+
137
+#define BTYPE_3(DEST) \
138
+ "mov x1, #1\n\t" \
139
+ "adr x15, 1f\n\t" \
140
+ "br x15\n" \
141
+"1: " DEST "\n\t" \
142
+ "mov x1, #0"
143
+
144
+#define TEST(WHICH, DEST, EXPECT) \
145
+ WHICH(DEST) "\n" \
146
+ ".if " #EXPECT "\n\t" \
147
+ "eor x1, x1," #EXPECT "\n" \
148
+ ".endif\n\t" \
149
+ "add x0, x0, x1\n\t"
150
+
151
+asm("\n"
152
+"test_begin:\n\t"
153
+ BTI_C "\n\t"
154
+ "mov x2, x30\n\t"
155
+ "mov x0, #0\n\t"
156
+
157
+ TEST(BTYPE_1, NOP, 1)
158
+ TEST(BTYPE_1, BTI_N, 1)
159
+ TEST(BTYPE_1, BTI_C, 0)
160
+ TEST(BTYPE_1, BTI_J, 0)
161
+ TEST(BTYPE_1, BTI_JC, 0)
162
+
163
+ TEST(BTYPE_2, NOP, 1)
164
+ TEST(BTYPE_2, BTI_N, 1)
165
+ TEST(BTYPE_2, BTI_C, 0)
166
+ TEST(BTYPE_2, BTI_J, 1)
167
+ TEST(BTYPE_2, BTI_JC, 0)
168
+
169
+ TEST(BTYPE_3, NOP, 1)
170
+ TEST(BTYPE_3, BTI_N, 1)
171
+ TEST(BTYPE_3, BTI_C, 1)
172
+ TEST(BTYPE_3, BTI_J, 0)
173
+ TEST(BTYPE_3, BTI_JC, 0)
174
+
175
+ "ret x2\n"
176
+"test_end:"
177
+);
178
+
179
+int main()
180
+{
181
+ struct sigaction sa;
182
+ void *tb, *te;
183
+
184
+ void *p = mmap(0, getpagesize(),
185
+ PROT_EXEC | PROT_READ | PROT_WRITE | PROT_BTI,
186
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
187
+ if (p == MAP_FAILED) {
188
+ perror("mmap");
189
+ return 1;
190
+ }
191
+
192
+ memset(&sa, 0, sizeof(sa));
193
+ sa.sa_sigaction = skip2_sigill;
194
+ sa.sa_flags = SA_SIGINFO;
195
+ if (sigaction(SIGILL, &sa, NULL) < 0) {
196
+ perror("sigaction");
197
+ return 1;
198
+ }
199
+
200
+ /*
201
+ * ??? With "extern char test_begin[]", some compiler versions
202
+ * will use :got references, and some linker versions will
203
+ * resolve this reference to a static symbol incorrectly.
204
+ * Bypass this error by using a pc-relative reference directly.
205
+ */
206
+ asm("adr %0, test_begin; adr %1, test_end" : "=r"(tb), "=r"(te));
207
+
208
+ memcpy(p, tb, te - tb);
209
+
210
+ return ((int (*)(void))p)();
211
+}
212
diff --git a/tests/tcg/aarch64/bti-crt.inc.c b/tests/tcg/aarch64/bti-crt.inc.c
213
new file mode 100644
214
index XXXXXXX..XXXXXXX
215
--- /dev/null
216
+++ b/tests/tcg/aarch64/bti-crt.inc.c
217
@@ -XXX,XX +XXX,XX @@
218
+/*
219
+ * Minimal user-environment for testing BTI.
47
+ *
220
+ *
48
+ * Copyright (c) 2005 CodeSourcery, LLC.
221
+ * Normal libc is not (yet) built with BTI support enabled,
49
+ * Written by Paul Brook
222
+ * and so could generate a BTI TRAP before ever reaching main.
50
+ *
51
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
52
+ * See the COPYING file in the top-level directory.
53
+ */
223
+ */
54
+
224
+
55
+#ifndef HW_NET_SMC91C111_H
225
+#include <stdlib.h>
56
+#define HW_NET_SMC91C111_H
226
+#include <signal.h>
57
+
227
+#include <ucontext.h>
58
+#include "hw/irq.h"
228
+#include <asm/unistd.h>
59
+#include "net/net.h"
229
+
60
+
230
+int main(void);
61
+void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
231
+
62
+
232
+void _start(void)
63
+#endif
233
+{
64
diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c
234
+ exit(main());
235
+}
236
+
237
+void exit(int ret)
238
+{
239
+ register int x0 __asm__("x0") = ret;
240
+ register int x8 __asm__("x8") = __NR_exit;
241
+
242
+ asm volatile("svc #0" : : "r"(x0), "r"(x8));
243
+ __builtin_unreachable();
244
+}
245
+
246
+/*
247
+ * Irritatingly, the user API struct sigaction does not match the
248
+ * kernel API struct sigaction. So for simplicity, isolate the
249
+ * kernel ABI here, and make this act like signal.
250
+ */
251
+void signal_info(int sig, void (*fn)(int, siginfo_t *, ucontext_t *))
252
+{
253
+ struct kernel_sigaction {
254
+ void (*handler)(int, siginfo_t *, ucontext_t *);
255
+ unsigned long flags;
256
+ unsigned long restorer;
257
+ unsigned long mask;
258
+ } sa = { fn, SA_SIGINFO, 0, 0 };
259
+
260
+ register int x0 __asm__("x0") = sig;
261
+ register void *x1 __asm__("x1") = &sa;
262
+ register void *x2 __asm__("x2") = 0;
263
+ register int x3 __asm__("x3") = sizeof(unsigned long);
264
+ register int x8 __asm__("x8") = __NR_rt_sigaction;
265
+
266
+ asm volatile("svc #0"
267
+ : : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x8) : "memory");
268
+}
269
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
65
index XXXXXXX..XXXXXXX 100644
270
index XXXXXXX..XXXXXXX 100644
66
--- a/hw/arm/gumstix.c
271
--- a/tests/tcg/aarch64/Makefile.target
67
+++ b/hw/arm/gumstix.c
272
+++ b/tests/tcg/aarch64/Makefile.target
68
@@ -XXX,XX +XXX,XX @@
273
@@ -XXX,XX +XXX,XX @@ run-pauth-%: QEMU_OPTS += -cpu max
69
#include "hw/arm/pxa.h"
274
run-plugin-pauth-%: QEMU_OPTS += -cpu max
70
#include "net/net.h"
275
endif
71
#include "hw/block/flash.h"
276
72
-#include "hw/devices.h"
277
+# BTI Tests
73
+#include "hw/net/smc91c111.h"
278
+# bti-1 tests the elf notes, so we require special compiler support.
74
#include "hw/boards.h"
279
+ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_BTI),)
75
#include "exec/address-spaces.h"
280
+AARCH64_TESTS += bti-1
76
#include "sysemu/qtest.h"
281
+bti-1: CFLAGS += -mbranch-protection=standard
77
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
282
+bti-1: LDFLAGS += -nostdlib
78
index XXXXXXX..XXXXXXX 100644
283
+endif
79
--- a/hw/arm/integratorcp.c
284
+# bti-2 tests PROT_BTI, so no special compiler support required.
80
+++ b/hw/arm/integratorcp.c
285
+AARCH64_TESTS += bti-2
81
@@ -XXX,XX +XXX,XX @@
286
+
82
#include "qemu-common.h"
287
# Semihosting smoke test for linux-user
83
#include "cpu.h"
288
AARCH64_TESTS += semihosting
84
#include "hw/sysbus.h"
289
run-semihosting: semihosting
85
-#include "hw/devices.h"
290
diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh
86
#include "hw/boards.h"
291
index XXXXXXX..XXXXXXX 100755
87
#include "hw/arm/arm.h"
292
--- a/tests/tcg/configure.sh
88
#include "hw/misc/arm_integrator_debug.h"
293
+++ b/tests/tcg/configure.sh
89
+#include "hw/net/smc91c111.h"
294
@@ -XXX,XX +XXX,XX @@ for target in $target_list; do
90
#include "net/net.h"
295
-march=armv8.3-a -o $TMPE $TMPC; then
91
#include "exec/address-spaces.h"
296
echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak
92
#include "sysemu/sysemu.h"
297
fi
93
diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c
298
+ if do_compiler "$target_compiler" $target_compiler_cflags \
94
index XXXXXXX..XXXXXXX 100644
299
+ -mbranch-protection=standard -o $TMPE $TMPC; then
95
--- a/hw/arm/mainstone.c
300
+ echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak
96
+++ b/hw/arm/mainstone.c
301
+ fi
97
@@ -XXX,XX +XXX,XX @@
302
;;
98
#include "hw/arm/pxa.h"
303
esac
99
#include "hw/arm/arm.h"
304
100
#include "net/net.h"
101
-#include "hw/devices.h"
102
+#include "hw/net/smc91c111.h"
103
#include "hw/boards.h"
104
#include "hw/block/flash.h"
105
#include "hw/sysbus.h"
106
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
107
index XXXXXXX..XXXXXXX 100644
108
--- a/hw/arm/realview.c
109
+++ b/hw/arm/realview.c
110
@@ -XXX,XX +XXX,XX @@
111
#include "hw/sysbus.h"
112
#include "hw/arm/arm.h"
113
#include "hw/arm/primecell.h"
114
-#include "hw/devices.h"
115
#include "hw/net/lan9118.h"
116
+#include "hw/net/smc91c111.h"
117
#include "hw/pci/pci.h"
118
#include "net/net.h"
119
#include "sysemu/sysemu.h"
120
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
121
index XXXXXXX..XXXXXXX 100644
122
--- a/hw/arm/versatilepb.c
123
+++ b/hw/arm/versatilepb.c
124
@@ -XXX,XX +XXX,XX @@
125
#include "cpu.h"
126
#include "hw/sysbus.h"
127
#include "hw/arm/arm.h"
128
-#include "hw/devices.h"
129
+#include "hw/net/smc91c111.h"
130
#include "net/net.h"
131
#include "sysemu/sysemu.h"
132
#include "hw/pci/pci.h"
133
diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c
134
index XXXXXXX..XXXXXXX 100644
135
--- a/hw/net/smc91c111.c
136
+++ b/hw/net/smc91c111.c
137
@@ -XXX,XX +XXX,XX @@
138
#include "qemu/osdep.h"
139
#include "hw/sysbus.h"
140
#include "net/net.h"
141
-#include "hw/devices.h"
142
+#include "hw/net/smc91c111.h"
143
#include "qemu/log.h"
144
/* For crc32 */
145
#include <zlib.h>
146
--
305
--
147
2.20.1
306
2.20.1
148
307
149
308
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
Suggested-by: Markus Armbruster <armbru@redhat.com>
3
When compiling with -Werror=implicit-fallthrough, gcc complains about
4
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
4
missing fallthrough annotations in this file. Looking at the code,
5
Message-id: 20190412165416.7977-3-philmd@redhat.com
5
the fallthrough is very likely intended here, so add some comments
6
to silence the compiler warnings.
7
8
Signed-off-by: Thomas Huth <thuth@redhat.com>
9
Message-id: 20201020105938.23209-1-thuth@redhat.com
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
12
---
9
hw/arm/nseries.c | 3 ++-
13
hw/arm/highbank.c | 2 ++
10
1 file changed, 2 insertions(+), 1 deletion(-)
14
1 file changed, 2 insertions(+)
11
15
12
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
16
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
13
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/arm/nseries.c
18
--- a/hw/arm/highbank.c
15
+++ b/hw/arm/nseries.c
19
+++ b/hw/arm/highbank.c
16
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
17
#include "hw/boards.h"
21
address_space_stl_notdirty(&address_space_memory,
18
#include "hw/i2c/i2c.h"
22
SMP_BOOT_REG + 0x30, 0,
19
#include "hw/devices.h"
23
MEMTXATTRS_UNSPECIFIED, NULL);
20
+#include "hw/misc/tmp105.h"
24
+ /* fallthrough */
21
#include "hw/block/flash.h"
25
case 3:
22
#include "hw/hw.h"
26
address_space_stl_notdirty(&address_space_memory,
23
#include "hw/bt.h"
27
SMP_BOOT_REG + 0x20, 0,
24
@@ -XXX,XX +XXX,XX @@ static void n8x0_i2c_setup(struct n800_s *s)
28
MEMTXATTRS_UNSPECIFIED, NULL);
25
qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier);
29
+ /* fallthrough */
26
30
case 2:
27
/* Attach a TMP105 PM chip (A0 wired to ground) */
31
address_space_stl_notdirty(&address_space_memory,
28
- dev = i2c_create_slave(i2c, "tmp105", N8X0_TMP105_ADDR);
32
SMP_BOOT_REG + 0x10, 0,
29
+ dev = i2c_create_slave(i2c, TYPE_TMP105, N8X0_TMP105_ADDR);
30
qdev_connect_gpio_out(dev, 0, tmp_irq);
31
}
32
33
--
33
--
34
2.20.1
34
2.20.1
35
35
36
36
diff view generated by jsdifflib
1
If the floating point extension is present, then the SG instruction
1
From: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
2
must clear the CONTROL_S.SFPA bit. Implement this.
3
2
4
(On a no-FPU system the bit will always be zero, so we don't need
3
This patch sets min_cpus field for xlnx-versal-virt platform,
5
to make the clearing of the bit conditional on ARM_FEATURE_VFP.)
4
because it always creates XLNX_VERSAL_NR_ACPUS cpus even with
5
-smp 1 command line option.
6
6
7
Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
10
Message-id: 160343854912.8460.17915238517799132371.stgit@pasha-ThinkPad-X280
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20190416125744.27770-8-peter.maydell@linaro.org
10
---
12
---
11
target/arm/helper.c | 1 +
13
hw/arm/xlnx-versal-virt.c | 1 +
12
1 file changed, 1 insertion(+)
14
1 file changed, 1 insertion(+)
13
15
14
diff --git a/target/arm/helper.c b/target/arm/helper.c
16
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/helper.c
18
--- a/hw/arm/xlnx-versal-virt.c
17
+++ b/target/arm/helper.c
19
+++ b/hw/arm/xlnx-versal-virt.c
18
@@ -XXX,XX +XXX,XX @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu)
20
@@ -XXX,XX +XXX,XX @@ static void versal_virt_machine_class_init(ObjectClass *oc, void *data)
19
qemu_log_mask(CPU_LOG_INT, "...really an SG instruction at 0x%08" PRIx32
21
20
", executing it\n", env->regs[15]);
22
mc->desc = "Xilinx Versal Virtual development board";
21
env->regs[14] &= ~1;
23
mc->init = versal_virt_init;
22
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
24
+ mc->min_cpus = XLNX_VERSAL_NR_ACPUS;
23
switch_v7m_security_state(env, true);
25
mc->max_cpus = XLNX_VERSAL_NR_ACPUS;
24
xpsr_write(env, 0, XPSR_IT);
26
mc->default_cpus = XLNX_VERSAL_NR_ACPUS;
25
env->regs[15] += 4;
27
mc->no_cdrom = true;
26
--
28
--
27
2.20.1
29
2.20.1
28
30
29
31
diff view generated by jsdifflib
1
Currently the code in v7m_push_stack() which detects a violation
1
From: Havard Skinnemoen <hskinnemoen@google.com>
2
of the v8M stack limit simply returns early if it does so. This
3
is OK for the current integer-only code, but won't work for the
4
floating point handling we're about to add. We need to continue
5
executing the rest of the function so that we check for other
6
exceptions like not having permission to use the FPU and so
7
that we correctly set the FPCCR state if we are doing lazy
8
stacking. Refactor to avoid the early return.
9
2
3
This allows us to reuse npcm7xx_timer_pause for the watchdog timer.
4
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 20190416125744.27770-10-peter.maydell@linaro.org
13
---
8
---
14
target/arm/helper.c | 23 ++++++++++++++++++-----
9
hw/timer/npcm7xx_timer.c | 6 +++---
15
1 file changed, 18 insertions(+), 5 deletions(-)
10
1 file changed, 3 insertions(+), 3 deletions(-)
16
11
17
diff --git a/target/arm/helper.c b/target/arm/helper.c
12
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
18
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/helper.c
14
--- a/hw/timer/npcm7xx_timer.c
20
+++ b/target/arm/helper.c
15
+++ b/hw/timer/npcm7xx_timer.c
21
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_stack(ARMCPU *cpu)
16
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_pause(NPCM7xxTimer *t)
22
* should ignore further stack faults trying to process
17
timer_del(&t->qtimer);
23
* that derived exception.)
18
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
24
*/
19
t->remaining_ns = t->expires_ns - now;
25
- bool stacked_ok;
20
- if (t->remaining_ns <= 0) {
26
+ bool stacked_ok = true, limitviol = false;
21
- npcm7xx_timer_reached_zero(t);
27
CPUARMState *env = &cpu->env;
22
- }
28
uint32_t xpsr = xpsr_read(env);
23
}
29
uint32_t frameptr = env->regs[13];
24
30
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_stack(ARMCPU *cpu)
25
/*
31
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
26
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
32
env->v7m.secure);
27
} else {
33
env->regs[13] = limit;
28
t->tcsr &= ~NPCM7XX_TCSR_CACT;
34
- return true;
29
npcm7xx_timer_pause(t);
35
+ /*
30
+ if (t->remaining_ns <= 0) {
36
+ * We won't try to perform any further memory accesses but
31
+ npcm7xx_timer_reached_zero(t);
37
+ * we must continue through the following code to check for
32
+ }
38
+ * permission faults during FPU state preservation, and we
39
+ * must update FPCCR if lazy stacking is enabled.
40
+ */
41
+ limitviol = true;
42
+ stacked_ok = false;
43
}
33
}
44
}
34
}
45
46
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_stack(ARMCPU *cpu)
47
* (which may be taken in preference to the one we started with
48
* if it has higher priority).
49
*/
50
- stacked_ok =
51
+ stacked_ok = stacked_ok &&
52
v7m_stack_write(cpu, frameptr, env->regs[0], mmu_idx, false) &&
53
v7m_stack_write(cpu, frameptr + 4, env->regs[1], mmu_idx, false) &&
54
v7m_stack_write(cpu, frameptr + 8, env->regs[2], mmu_idx, false) &&
55
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_stack(ARMCPU *cpu)
56
v7m_stack_write(cpu, frameptr + 24, env->regs[15], mmu_idx, false) &&
57
v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, false);
58
59
- /* Update SP regardless of whether any of the stack accesses failed. */
60
- env->regs[13] = frameptr;
61
+ /*
62
+ * If we broke a stack limit then SP was already updated earlier;
63
+ * otherwise we update SP regardless of whether any of the stack
64
+ * accesses failed or we took some other kind of fault.
65
+ */
66
+ if (!limitviol) {
67
+ env->regs[13] = frameptr;
68
+ }
69
70
return !stacked_ok;
71
}
35
}
72
--
36
--
73
2.20.1
37
2.20.1
74
38
75
39
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
Since uWireSlave is only used in this new header, there is no
3
The watchdog is part of NPCM7XX's timer module. Its behavior is
4
need to expose it via "qemu/typedefs.h".
4
controlled by the WTCR register in the timer.
5
5
6
Reviewed-by: Markus Armbruster <armbru@redhat.com>
6
When enabled, the watchdog issues an interrupt signal after a pre-set
7
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
amount of cycles, and issues a reset signal shortly after that.
8
Message-id: 20190412165416.7977-9-philmd@redhat.com
8
9
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
10
Signed-off-by: Hao Wu <wuhaotsh@google.com>
11
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
[PMM: deleted blank line at end of npcm_watchdog_timer-test.c]
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
15
---
11
include/hw/arm/omap.h | 6 +-----
16
include/hw/misc/npcm7xx_clk.h | 2 +
12
include/hw/devices.h | 15 ---------------
17
include/hw/timer/npcm7xx_timer.h | 48 +++-
13
include/hw/input/tsc2xxx.h | 36 ++++++++++++++++++++++++++++++++++++
18
hw/arm/npcm7xx.c | 12 +
14
include/qemu/typedefs.h | 1 -
19
hw/misc/npcm7xx_clk.c | 28 ++
15
hw/arm/nseries.c | 2 +-
20
hw/timer/npcm7xx_timer.c | 266 ++++++++++++++----
16
hw/arm/palm.c | 2 +-
21
tests/qtest/npcm7xx_watchdog_timer-test.c | 319 ++++++++++++++++++++++
17
hw/input/tsc2005.c | 2 +-
22
MAINTAINERS | 1 +
18
hw/input/tsc210x.c | 4 ++--
23
tests/qtest/meson.build | 2 +-
19
MAINTAINERS | 2 ++
24
8 files changed, 624 insertions(+), 54 deletions(-)
20
9 files changed, 44 insertions(+), 26 deletions(-)
25
create mode 100644 tests/qtest/npcm7xx_watchdog_timer-test.c
21
create mode 100644 include/hw/input/tsc2xxx.h
22
26
23
diff --git a/include/hw/arm/omap.h b/include/hw/arm/omap.h
27
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
24
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
25
--- a/include/hw/arm/omap.h
29
--- a/include/hw/misc/npcm7xx_clk.h
26
+++ b/include/hw/arm/omap.h
30
+++ b/include/hw/misc/npcm7xx_clk.h
27
@@ -XXX,XX +XXX,XX @@
31
@@ -XXX,XX +XXX,XX @@
28
#include "exec/memory.h"
32
*/
29
# define hw_omap_h        "omap.h"
33
#define NPCM7XX_CLK_NR_REGS (0x70 / sizeof(uint32_t))
34
35
+#define NPCM7XX_WATCHDOG_RESET_GPIO_IN "npcm7xx-clk-watchdog-reset-gpio-in"
36
+
37
typedef struct NPCM7xxCLKState {
38
SysBusDevice parent;
39
40
diff --git a/include/hw/timer/npcm7xx_timer.h b/include/hw/timer/npcm7xx_timer.h
41
index XXXXXXX..XXXXXXX 100644
42
--- a/include/hw/timer/npcm7xx_timer.h
43
+++ b/include/hw/timer/npcm7xx_timer.h
44
@@ -XXX,XX +XXX,XX @@
45
*/
46
#define NPCM7XX_TIMER_NR_REGS (0x54 / sizeof(uint32_t))
47
48
+/* The basic watchdog timer period is 2^14 clock cycles. */
49
+#define NPCM7XX_WATCHDOG_BASETIME_SHIFT 14
50
+
51
+#define NPCM7XX_WATCHDOG_RESET_GPIO_OUT "npcm7xx-clk-watchdog-reset-gpio-out"
52
+
53
typedef struct NPCM7xxTimerCtrlState NPCM7xxTimerCtrlState;
54
55
/**
56
- * struct NPCM7xxTimer - Individual timer state.
57
- * @irq: GIC interrupt line to fire on expiration (if enabled).
58
+ * struct NPCM7xxBaseTimer - Basic functionality that both regular timer and
59
+ * watchdog timer use.
60
* @qtimer: QEMU timer that notifies us on expiration.
61
* @expires_ns: Absolute virtual expiration time.
62
* @remaining_ns: Remaining time until expiration if timer is paused.
63
+ */
64
+typedef struct NPCM7xxBaseTimer {
65
+ QEMUTimer qtimer;
66
+ int64_t expires_ns;
67
+ int64_t remaining_ns;
68
+} NPCM7xxBaseTimer;
69
+
70
+/**
71
+ * struct NPCM7xxTimer - Individual timer state.
72
+ * @ctrl: The timer module that owns this timer.
73
+ * @irq: GIC interrupt line to fire on expiration (if enabled).
74
+ * @base_timer: The basic timer functionality for this timer.
75
* @tcsr: The Timer Control and Status Register.
76
* @ticr: The Timer Initial Count Register.
77
*/
78
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxTimer {
79
NPCM7xxTimerCtrlState *ctrl;
80
81
qemu_irq irq;
82
- QEMUTimer qtimer;
83
- int64_t expires_ns;
84
- int64_t remaining_ns;
85
+ NPCM7xxBaseTimer base_timer;
86
87
uint32_t tcsr;
88
uint32_t ticr;
89
} NPCM7xxTimer;
90
91
+/**
92
+ * struct NPCM7xxWatchdogTimer - The watchdog timer state.
93
+ * @ctrl: The timer module that owns this timer.
94
+ * @irq: GIC interrupt line to fire on expiration (if enabled).
95
+ * @reset_signal: The GPIO used to send a reset signal.
96
+ * @base_timer: The basic timer functionality for this timer.
97
+ * @wtcr: The Watchdog Timer Control Register.
98
+ */
99
+typedef struct NPCM7xxWatchdogTimer {
100
+ NPCM7xxTimerCtrlState *ctrl;
101
+
102
+ qemu_irq irq;
103
+ qemu_irq reset_signal;
104
+ NPCM7xxBaseTimer base_timer;
105
+
106
+ uint32_t wtcr;
107
+} NPCM7xxWatchdogTimer;
108
+
109
/**
110
* struct NPCM7xxTimerCtrlState - Timer Module device state.
111
* @parent: System bus device.
112
* @iomem: Memory region through which registers are accessed.
113
+ * @index: The index of this timer module.
114
* @tisr: The Timer Interrupt Status Register.
115
- * @wtcr: The Watchdog Timer Control Register.
116
* @timer: The five individual timers managed by this module.
117
+ * @watchdog_timer: The watchdog timer managed by this module.
118
*/
119
struct NPCM7xxTimerCtrlState {
120
SysBusDevice parent;
121
@@ -XXX,XX +XXX,XX @@ struct NPCM7xxTimerCtrlState {
122
MemoryRegion iomem;
123
124
uint32_t tisr;
125
- uint32_t wtcr;
126
127
NPCM7xxTimer timer[NPCM7XX_TIMERS_PER_CTRL];
128
+ NPCM7xxWatchdogTimer watchdog_timer;
129
};
130
131
#define TYPE_NPCM7XX_TIMER "npcm7xx-timer"
132
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
133
index XXXXXXX..XXXXXXX 100644
134
--- a/hw/arm/npcm7xx.c
135
+++ b/hw/arm/npcm7xx.c
136
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
137
NPCM7XX_TIMER12_IRQ,
138
NPCM7XX_TIMER13_IRQ,
139
NPCM7XX_TIMER14_IRQ,
140
+ NPCM7XX_WDG0_IRQ = 47, /* Timer Module 0 Watchdog */
141
+ NPCM7XX_WDG1_IRQ, /* Timer Module 1 Watchdog */
142
+ NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
143
};
144
145
/* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */
146
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
147
qemu_irq irq = npcm7xx_irq(s, first_irq + j);
148
sysbus_connect_irq(sbd, j, irq);
149
}
150
+
151
+ /* IRQ for watchdogs */
152
+ sysbus_connect_irq(sbd, NPCM7XX_TIMERS_PER_CTRL,
153
+ npcm7xx_irq(s, NPCM7XX_WDG0_IRQ + i));
154
+ /* GPIO that connects clk module with watchdog */
155
+ qdev_connect_gpio_out_named(DEVICE(&s->tim[i]),
156
+ NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 0,
157
+ qdev_get_gpio_in_named(DEVICE(&s->clk),
158
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, i));
159
}
160
161
/* UART0..3 (16550 compatible) */
162
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
163
index XXXXXXX..XXXXXXX 100644
164
--- a/hw/misc/npcm7xx_clk.c
165
+++ b/hw/misc/npcm7xx_clk.c
166
@@ -XXX,XX +XXX,XX @@
167
#include "qemu/osdep.h"
168
169
#include "hw/misc/npcm7xx_clk.h"
170
+#include "hw/timer/npcm7xx_timer.h"
171
#include "migration/vmstate.h"
172
#include "qemu/error-report.h"
173
#include "qemu/log.h"
174
@@ -XXX,XX +XXX,XX @@
175
#include "qemu/timer.h"
176
#include "qemu/units.h"
177
#include "trace.h"
178
+#include "sysemu/watchdog.h"
179
180
#define PLLCON_LOKI BIT(31)
181
#define PLLCON_LOKS BIT(30)
182
@@ -XXX,XX +XXX,XX @@ static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
183
[NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
184
};
185
186
+/* Register Field Definitions */
187
+#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
188
+
189
+/* The number of watchdogs that can trigger a reset. */
190
+#define NPCM7XX_NR_WATCHDOGS (3)
191
+
192
static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
193
{
194
uint32_t reg = offset / sizeof(uint32_t);
195
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_write(void *opaque, hwaddr offset,
196
s->regs[reg] = value;
197
}
198
199
+/* Perform reset action triggered by a watchdog */
200
+static void npcm7xx_clk_perform_watchdog_reset(void *opaque, int n,
201
+ int level)
202
+{
203
+ NPCM7xxCLKState *clk = NPCM7XX_CLK(opaque);
204
+ uint32_t rcr;
205
+
206
+ g_assert(n >= 0 && n <= NPCM7XX_NR_WATCHDOGS);
207
+ rcr = clk->regs[NPCM7XX_CLK_WD0RCR + n];
208
+ if (rcr & NPCM7XX_CLK_WDRCR_CA9C) {
209
+ watchdog_perform_action();
210
+ } else {
211
+ qemu_log_mask(LOG_UNIMP,
212
+ "%s: only CPU reset is implemented. (requested 0x%" PRIx32")\n",
213
+ __func__, rcr);
214
+ }
215
+}
216
+
217
static const struct MemoryRegionOps npcm7xx_clk_ops = {
218
.read = npcm7xx_clk_read,
219
.write = npcm7xx_clk_write,
220
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
221
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
222
TYPE_NPCM7XX_CLK, 4 * KiB);
223
sysbus_init_mmio(&s->parent, &s->iomem);
224
+ qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
225
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
226
}
227
228
static const VMStateDescription vmstate_npcm7xx_clk = {
229
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
230
index XXXXXXX..XXXXXXX 100644
231
--- a/hw/timer/npcm7xx_timer.c
232
+++ b/hw/timer/npcm7xx_timer.c
233
@@ -XXX,XX +XXX,XX @@
234
#include "qemu/osdep.h"
235
30
#include "hw/irq.h"
236
#include "hw/irq.h"
31
+#include "hw/input/tsc2xxx.h"
237
+#include "hw/qdev-properties.h"
32
#include "target/arm/cpu-qom.h"
238
#include "hw/misc/npcm7xx_clk.h"
33
#include "qemu/log.h"
239
#include "hw/timer/npcm7xx_timer.h"
34
240
#include "migration/vmstate.h"
35
@@ -XXX,XX +XXX,XX @@ qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s);
241
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxTimerRegisters {
36
void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler);
242
#define NPCM7XX_TCSR_PRESCALE_START 0
37
void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down);
243
#define NPCM7XX_TCSR_PRESCALE_LEN 8
38
244
39
-struct uWireSlave {
245
+#define NPCM7XX_WTCR_WTCLK(rv) extract32(rv, 10, 2)
40
- uint16_t (*receive)(void *opaque);
246
+#define NPCM7XX_WTCR_FREEZE_EN BIT(9)
41
- void (*send)(void *opaque, uint16_t data);
247
+#define NPCM7XX_WTCR_WTE BIT(7)
42
- void *opaque;
248
+#define NPCM7XX_WTCR_WTIE BIT(6)
43
-};
249
+#define NPCM7XX_WTCR_WTIS(rv) extract32(rv, 4, 2)
44
struct omap_uwire_s;
250
+#define NPCM7XX_WTCR_WTIF BIT(3)
45
void omap_uwire_attach(struct omap_uwire_s *s,
251
+#define NPCM7XX_WTCR_WTRF BIT(2)
46
uWireSlave *slave, int chipselect);
252
+#define NPCM7XX_WTCR_WTRE BIT(1)
47
diff --git a/include/hw/devices.h b/include/hw/devices.h
253
+#define NPCM7XX_WTCR_WTR BIT(0)
48
index XXXXXXX..XXXXXXX 100644
254
+
49
--- a/include/hw/devices.h
255
+/*
50
+++ b/include/hw/devices.h
256
+ * The number of clock cycles between interrupt and reset in watchdog, used
51
@@ -XXX,XX +XXX,XX @@
257
+ * by the software to handle the interrupt before system is reset.
52
/* Devices that have nowhere better to go. */
258
+ */
53
259
+#define NPCM7XX_WATCHDOG_INTERRUPT_TO_RESET_CYCLES 1024
54
#include "hw/hw.h"
260
+
55
-#include "ui/console.h"
261
+/* Start or resume the timer. */
56
262
+static void npcm7xx_timer_start(NPCM7xxBaseTimer *t)
57
/* smc91c111.c */
263
+{
58
void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
264
+ int64_t now;
59
@@ -XXX,XX +XXX,XX @@ void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
265
+
60
/* lan9118.c */
266
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
61
void lan9118_init(NICInfo *, uint32_t, qemu_irq);
267
+ t->expires_ns = now + t->remaining_ns;
62
268
+ timer_mod(&t->qtimer, t->expires_ns);
63
-/* tsc210x.c */
269
+}
64
-uWireSlave *tsc2102_init(qemu_irq pint);
270
+
65
-uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav);
271
+/* Stop counting. Record the time remaining so we can continue later. */
66
-I2SCodec *tsc210x_codec(uWireSlave *chip);
272
+static void npcm7xx_timer_pause(NPCM7xxBaseTimer *t)
67
-uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len);
273
+{
68
-void tsc210x_set_transform(uWireSlave *chip,
274
+ int64_t now;
69
- MouseTransformInfo *info);
275
+
70
-void tsc210x_key_event(uWireSlave *chip, int key, int down);
276
+ timer_del(&t->qtimer);
277
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
278
+ t->remaining_ns = t->expires_ns - now;
279
+}
280
+
281
+/* Delete the timer and reset it to default state. */
282
+static void npcm7xx_timer_clear(NPCM7xxBaseTimer *t)
283
+{
284
+ timer_del(&t->qtimer);
285
+ t->expires_ns = 0;
286
+ t->remaining_ns = 0;
287
+}
288
+
289
/*
290
* Returns the index of timer in the tc->timer array. This can be used to
291
* locate the registers that belong to this timer.
292
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
293
return count;
294
}
295
296
+static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
297
+{
298
+ switch (NPCM7XX_WTCR_WTCLK(t->wtcr)) {
299
+ case 0:
300
+ return 1;
301
+ case 1:
302
+ return 256;
303
+ case 2:
304
+ return 2048;
305
+ case 3:
306
+ return 65536;
307
+ default:
308
+ g_assert_not_reached();
309
+ }
310
+}
311
+
312
+static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
313
+ int64_t cycles)
314
+{
315
+ uint32_t prescaler = npcm7xx_watchdog_timer_prescaler(t);
316
+ int64_t ns = (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ) * cycles;
317
+
318
+ /*
319
+ * The reset function always clears the current timer. The caller of the
320
+ * this needs to decide whether to start the watchdog timer based on
321
+ * specific flag in WTCR.
322
+ */
323
+ npcm7xx_timer_clear(&t->base_timer);
324
+
325
+ ns *= prescaler;
326
+ t->base_timer.remaining_ns = ns;
327
+}
328
+
329
+static void npcm7xx_watchdog_timer_reset(NPCM7xxWatchdogTimer *t)
330
+{
331
+ int64_t cycles = 1;
332
+ uint32_t s = NPCM7XX_WTCR_WTIS(t->wtcr);
333
+
334
+ g_assert(s <= 3);
335
+
336
+ cycles <<= NPCM7XX_WATCHDOG_BASETIME_SHIFT;
337
+ cycles <<= 2 * s;
338
+
339
+ npcm7xx_watchdog_timer_reset_cycles(t, cycles);
340
+}
341
+
342
/*
343
* Raise the interrupt line if there's a pending interrupt and interrupts are
344
* enabled for this timer. If not, lower it.
345
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_check_interrupt(NPCM7xxTimer *t)
346
trace_npcm7xx_timer_irq(DEVICE(tc)->canonical_path, index, pending);
347
}
348
349
-/* Start or resume the timer. */
350
-static void npcm7xx_timer_start(NPCM7xxTimer *t)
351
-{
352
- int64_t now;
71
-
353
-
72
-/* tsc2005.c */
354
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
73
-void *tsc2005_init(qemu_irq pintdav);
355
- t->expires_ns = now + t->remaining_ns;
74
-uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len);
356
- timer_mod(&t->qtimer, t->expires_ns);
75
-void tsc2005_set_transform(void *opaque, MouseTransformInfo *info);
357
-}
76
-
358
-
77
#endif
359
/*
78
diff --git a/include/hw/input/tsc2xxx.h b/include/hw/input/tsc2xxx.h
360
* Called when the counter reaches zero. Sets the interrupt flag, and either
361
* restarts or disables the timer.
362
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t)
363
tc->tisr |= BIT(index);
364
365
if (t->tcsr & NPCM7XX_TCSR_PERIODIC) {
366
- t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
367
+ t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
368
if (t->tcsr & NPCM7XX_TCSR_CEN) {
369
- npcm7xx_timer_start(t);
370
+ npcm7xx_timer_start(&t->base_timer);
371
}
372
} else {
373
t->tcsr &= ~(NPCM7XX_TCSR_CEN | NPCM7XX_TCSR_CACT);
374
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t)
375
npcm7xx_timer_check_interrupt(t);
376
}
377
378
-/* Stop counting. Record the time remaining so we can continue later. */
379
-static void npcm7xx_timer_pause(NPCM7xxTimer *t)
380
-{
381
- int64_t now;
382
-
383
- timer_del(&t->qtimer);
384
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
385
- t->remaining_ns = t->expires_ns - now;
386
-}
387
388
/*
389
* Restart the timer from its initial value. If the timer was enabled and stays
390
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_pause(NPCM7xxTimer *t)
391
*/
392
static void npcm7xx_timer_restart(NPCM7xxTimer *t, uint32_t old_tcsr)
393
{
394
- t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
395
+ t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
396
397
if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) {
398
- npcm7xx_timer_start(t);
399
+ npcm7xx_timer_start(&t->base_timer);
400
}
401
}
402
403
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_timer_read_tdr(NPCM7xxTimer *t)
404
if (t->tcsr & NPCM7XX_TCSR_CEN) {
405
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
406
407
- return npcm7xx_timer_ns_to_count(t, t->expires_ns - now);
408
+ return npcm7xx_timer_ns_to_count(t, t->base_timer.expires_ns - now);
409
}
410
411
- return npcm7xx_timer_ns_to_count(t, t->remaining_ns);
412
+ return npcm7xx_timer_ns_to_count(t, t->base_timer.remaining_ns);
413
}
414
415
static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
416
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
417
418
if (npcm7xx_tcsr_prescaler(old_tcsr) != npcm7xx_tcsr_prescaler(new_tcsr)) {
419
/* Recalculate time remaining based on the current TDR value. */
420
- t->remaining_ns = npcm7xx_timer_count_to_ns(t, tdr);
421
+ t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, tdr);
422
if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) {
423
- npcm7xx_timer_start(t);
424
+ npcm7xx_timer_start(&t->base_timer);
425
}
426
}
427
428
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
429
if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_CEN) {
430
if (new_tcsr & NPCM7XX_TCSR_CEN) {
431
t->tcsr |= NPCM7XX_TCSR_CACT;
432
- npcm7xx_timer_start(t);
433
+ npcm7xx_timer_start(&t->base_timer);
434
} else {
435
t->tcsr &= ~NPCM7XX_TCSR_CACT;
436
- npcm7xx_timer_pause(t);
437
- if (t->remaining_ns <= 0) {
438
+ npcm7xx_timer_pause(&t->base_timer);
439
+ if (t->base_timer.remaining_ns <= 0) {
440
npcm7xx_timer_reached_zero(t);
441
}
442
}
443
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tisr(NPCM7xxTimerCtrlState *s, uint32_t value)
444
if (value & (1U << i)) {
445
npcm7xx_timer_check_interrupt(&s->timer[i]);
446
}
447
+
448
}
449
}
450
451
+static void npcm7xx_timer_write_wtcr(NPCM7xxWatchdogTimer *t, uint32_t new_wtcr)
452
+{
453
+ uint32_t old_wtcr = t->wtcr;
454
+
455
+ /*
456
+ * WTIF and WTRF are cleared by writing 1. Writing 0 makes these bits
457
+ * unchanged.
458
+ */
459
+ if (new_wtcr & NPCM7XX_WTCR_WTIF) {
460
+ new_wtcr &= ~NPCM7XX_WTCR_WTIF;
461
+ } else if (old_wtcr & NPCM7XX_WTCR_WTIF) {
462
+ new_wtcr |= NPCM7XX_WTCR_WTIF;
463
+ }
464
+ if (new_wtcr & NPCM7XX_WTCR_WTRF) {
465
+ new_wtcr &= ~NPCM7XX_WTCR_WTRF;
466
+ } else if (old_wtcr & NPCM7XX_WTCR_WTRF) {
467
+ new_wtcr |= NPCM7XX_WTCR_WTRF;
468
+ }
469
+
470
+ t->wtcr = new_wtcr;
471
+
472
+ if (new_wtcr & NPCM7XX_WTCR_WTR) {
473
+ t->wtcr &= ~NPCM7XX_WTCR_WTR;
474
+ npcm7xx_watchdog_timer_reset(t);
475
+ if (new_wtcr & NPCM7XX_WTCR_WTE) {
476
+ npcm7xx_timer_start(&t->base_timer);
477
+ }
478
+ } else if ((old_wtcr ^ new_wtcr) & NPCM7XX_WTCR_WTE) {
479
+ if (new_wtcr & NPCM7XX_WTCR_WTE) {
480
+ npcm7xx_timer_start(&t->base_timer);
481
+ } else {
482
+ npcm7xx_timer_pause(&t->base_timer);
483
+ }
484
+ }
485
+
486
+}
487
+
488
static hwaddr npcm7xx_tcsr_index(hwaddr reg)
489
{
490
switch (reg) {
491
@@ -XXX,XX +XXX,XX @@ static uint64_t npcm7xx_timer_read(void *opaque, hwaddr offset, unsigned size)
492
break;
493
494
case NPCM7XX_TIMER_WTCR:
495
- value = s->wtcr;
496
+ value = s->watchdog_timer.wtcr;
497
break;
498
499
default:
500
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write(void *opaque, hwaddr offset,
501
return;
502
503
case NPCM7XX_TIMER_WTCR:
504
- qemu_log_mask(LOG_UNIMP, "%s: WTCR write not implemented: 0x%08x\n",
505
- __func__, value);
506
+ npcm7xx_timer_write_wtcr(&s->watchdog_timer, value);
507
return;
508
}
509
510
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_enter_reset(Object *obj, ResetType type)
511
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
512
NPCM7xxTimer *t = &s->timer[i];
513
514
- timer_del(&t->qtimer);
515
- t->expires_ns = 0;
516
- t->remaining_ns = 0;
517
+ npcm7xx_timer_clear(&t->base_timer);
518
t->tcsr = 0x00000005;
519
t->ticr = 0x00000000;
520
}
521
522
s->tisr = 0x00000000;
523
- s->wtcr = 0x00000400;
524
+ /*
525
+ * Set WTCLK to 1(default) and reset all flags except WTRF.
526
+ * WTRF is not reset during a core domain reset.
527
+ */
528
+ s->watchdog_timer.wtcr = 0x00000400 | (s->watchdog_timer.wtcr &
529
+ NPCM7XX_WTCR_WTRF);
530
+}
531
+
532
+static void npcm7xx_watchdog_timer_expired(void *opaque)
533
+{
534
+ NPCM7xxWatchdogTimer *t = opaque;
535
+
536
+ if (t->wtcr & NPCM7XX_WTCR_WTE) {
537
+ if (t->wtcr & NPCM7XX_WTCR_WTIF) {
538
+ if (t->wtcr & NPCM7XX_WTCR_WTRE) {
539
+ t->wtcr |= NPCM7XX_WTCR_WTRF;
540
+ /* send reset signal to CLK module*/
541
+ qemu_irq_raise(t->reset_signal);
542
+ }
543
+ } else {
544
+ t->wtcr |= NPCM7XX_WTCR_WTIF;
545
+ if (t->wtcr & NPCM7XX_WTCR_WTIE) {
546
+ /* send interrupt */
547
+ qemu_irq_raise(t->irq);
548
+ }
549
+ npcm7xx_watchdog_timer_reset_cycles(t,
550
+ NPCM7XX_WATCHDOG_INTERRUPT_TO_RESET_CYCLES);
551
+ npcm7xx_timer_start(&t->base_timer);
552
+ }
553
+ }
554
}
555
556
static void npcm7xx_timer_hold_reset(Object *obj)
557
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_hold_reset(Object *obj)
558
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
559
qemu_irq_lower(s->timer[i].irq);
560
}
561
+ qemu_irq_lower(s->watchdog_timer.irq);
562
}
563
564
static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
565
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
566
NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev);
567
SysBusDevice *sbd = &s->parent;
568
int i;
569
+ NPCM7xxWatchdogTimer *w;
570
571
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
572
NPCM7xxTimer *t = &s->timer[i];
573
t->ctrl = s;
574
- timer_init_ns(&t->qtimer, QEMU_CLOCK_VIRTUAL, npcm7xx_timer_expired, t);
575
+ timer_init_ns(&t->base_timer.qtimer, QEMU_CLOCK_VIRTUAL,
576
+ npcm7xx_timer_expired, t);
577
sysbus_init_irq(sbd, &t->irq);
578
}
579
580
+ w = &s->watchdog_timer;
581
+ w->ctrl = s;
582
+ timer_init_ns(&w->base_timer.qtimer, QEMU_CLOCK_VIRTUAL,
583
+ npcm7xx_watchdog_timer_expired, w);
584
+ sysbus_init_irq(sbd, &w->irq);
585
+
586
memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_timer_ops, s,
587
TYPE_NPCM7XX_TIMER, 4 * KiB);
588
sysbus_init_mmio(sbd, &s->iomem);
589
+ qdev_init_gpio_out_named(dev, &w->reset_signal,
590
+ NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 1);
591
}
592
593
-static const VMStateDescription vmstate_npcm7xx_timer = {
594
- .name = "npcm7xx-timer",
595
+static const VMStateDescription vmstate_npcm7xx_base_timer = {
596
+ .name = "npcm7xx-base-timer",
597
.version_id = 0,
598
.minimum_version_id = 0,
599
.fields = (VMStateField[]) {
600
- VMSTATE_TIMER(qtimer, NPCM7xxTimer),
601
- VMSTATE_INT64(expires_ns, NPCM7xxTimer),
602
- VMSTATE_INT64(remaining_ns, NPCM7xxTimer),
603
+ VMSTATE_TIMER(qtimer, NPCM7xxBaseTimer),
604
+ VMSTATE_INT64(expires_ns, NPCM7xxBaseTimer),
605
+ VMSTATE_INT64(remaining_ns, NPCM7xxBaseTimer),
606
+ VMSTATE_END_OF_LIST(),
607
+ },
608
+};
609
+
610
+static const VMStateDescription vmstate_npcm7xx_timer = {
611
+ .name = "npcm7xx-timer",
612
+ .version_id = 1,
613
+ .minimum_version_id = 1,
614
+ .fields = (VMStateField[]) {
615
+ VMSTATE_STRUCT(base_timer, NPCM7xxTimer,
616
+ 0, vmstate_npcm7xx_base_timer,
617
+ NPCM7xxBaseTimer),
618
VMSTATE_UINT32(tcsr, NPCM7xxTimer),
619
VMSTATE_UINT32(ticr, NPCM7xxTimer),
620
VMSTATE_END_OF_LIST(),
621
},
622
};
623
624
-static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
625
- .name = "npcm7xx-timer-ctrl",
626
+static const VMStateDescription vmstate_npcm7xx_watchdog_timer = {
627
+ .name = "npcm7xx-watchdog-timer",
628
.version_id = 0,
629
.minimum_version_id = 0,
630
+ .fields = (VMStateField[]) {
631
+ VMSTATE_STRUCT(base_timer, NPCM7xxWatchdogTimer,
632
+ 0, vmstate_npcm7xx_base_timer,
633
+ NPCM7xxBaseTimer),
634
+ VMSTATE_UINT32(wtcr, NPCM7xxWatchdogTimer),
635
+ VMSTATE_END_OF_LIST(),
636
+ },
637
+};
638
+
639
+static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
640
+ .name = "npcm7xx-timer-ctrl",
641
+ .version_id = 1,
642
+ .minimum_version_id = 1,
643
.fields = (VMStateField[]) {
644
VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState),
645
- VMSTATE_UINT32(wtcr, NPCM7xxTimerCtrlState),
646
VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState,
647
NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer,
648
NPCM7xxTimer),
649
+ VMSTATE_STRUCT(watchdog_timer, NPCM7xxTimerCtrlState,
650
+ 0, vmstate_npcm7xx_watchdog_timer,
651
+ NPCM7xxWatchdogTimer),
652
VMSTATE_END_OF_LIST(),
653
},
654
};
655
diff --git a/tests/qtest/npcm7xx_watchdog_timer-test.c b/tests/qtest/npcm7xx_watchdog_timer-test.c
79
new file mode 100644
656
new file mode 100644
80
index XXXXXXX..XXXXXXX
657
index XXXXXXX..XXXXXXX
81
--- /dev/null
658
--- /dev/null
82
+++ b/include/hw/input/tsc2xxx.h
659
+++ b/tests/qtest/npcm7xx_watchdog_timer-test.c
83
@@ -XXX,XX +XXX,XX @@
660
@@ -XXX,XX +XXX,XX @@
84
+/*
661
+/*
85
+ * TI touchscreen controller
662
+ * QTests for Nuvoton NPCM7xx Timer Watchdog Modules.
86
+ *
663
+ *
87
+ * Copyright (c) 2006 Andrzej Zaborowski
664
+ * Copyright 2020 Google LLC
88
+ * Copyright (C) 2008 Nokia Corporation
89
+ *
665
+ *
90
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
666
+ * This program is free software; you can redistribute it and/or modify it
91
+ * See the COPYING file in the top-level directory.
667
+ * under the terms of the GNU General Public License as published by the
668
+ * Free Software Foundation; either version 2 of the License, or
669
+ * (at your option) any later version.
670
+ *
671
+ * This program is distributed in the hope that it will be useful, but WITHOUT
672
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
673
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
674
+ * for more details.
92
+ */
675
+ */
93
+
676
+
94
+#ifndef HW_INPUT_TSC2XXX_H
677
+#include "qemu/osdep.h"
95
+#define HW_INPUT_TSC2XXX_H
678
+#include "qemu/timer.h"
96
+
679
+
97
+#include "hw/irq.h"
680
+#include "libqos/libqtest.h"
98
+#include "ui/console.h"
681
+#include "qapi/qmp/qdict.h"
99
+
682
+
100
+typedef struct uWireSlave {
683
+#define WTCR_OFFSET 0x1c
101
+ uint16_t (*receive)(void *opaque);
684
+#define REF_HZ (25000000)
102
+ void (*send)(void *opaque, uint16_t data);
685
+
103
+ void *opaque;
686
+/* WTCR bit fields */
104
+} uWireSlave;
687
+#define WTCLK(rv) ((rv) << 10)
105
+
688
+#define WTE BIT(7)
106
+/* tsc210x.c */
689
+#define WTIE BIT(6)
107
+uWireSlave *tsc2102_init(qemu_irq pint);
690
+#define WTIS(rv) ((rv) << 4)
108
+uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav);
691
+#define WTIF BIT(3)
109
+I2SCodec *tsc210x_codec(uWireSlave *chip);
692
+#define WTRF BIT(2)
110
+uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len);
693
+#define WTRE BIT(1)
111
+void tsc210x_set_transform(uWireSlave *chip, MouseTransformInfo *info);
694
+#define WTR BIT(0)
112
+void tsc210x_key_event(uWireSlave *chip, int key, int down);
695
+
113
+
696
+typedef struct Watchdog {
114
+/* tsc2005.c */
697
+ int irq;
115
+void *tsc2005_init(qemu_irq pintdav);
698
+ uint64_t base_addr;
116
+uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len);
699
+} Watchdog;
117
+void tsc2005_set_transform(void *opaque, MouseTransformInfo *info);
700
+
118
+
701
+static const Watchdog watchdog_list[] = {
119
+#endif
702
+ {
120
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
703
+ .irq = 47,
121
index XXXXXXX..XXXXXXX 100644
704
+ .base_addr = 0xf0008000
122
--- a/include/qemu/typedefs.h
705
+ },
123
+++ b/include/qemu/typedefs.h
706
+ {
124
@@ -XXX,XX +XXX,XX @@ typedef struct RAMBlock RAMBlock;
707
+ .irq = 48,
125
typedef struct Range Range;
708
+ .base_addr = 0xf0009000
126
typedef struct SHPCDevice SHPCDevice;
709
+ },
127
typedef struct SSIBus SSIBus;
710
+ {
128
-typedef struct uWireSlave uWireSlave;
711
+ .irq = 49,
129
typedef struct VirtIODevice VirtIODevice;
712
+ .base_addr = 0xf000a000
130
typedef struct Visitor Visitor;
713
+ }
131
typedef void SaveStateHandler(QEMUFile *f, void *opaque);
714
+};
132
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
715
+
133
index XXXXXXX..XXXXXXX 100644
716
+static int watchdog_index(const Watchdog *wd)
134
--- a/hw/arm/nseries.c
717
+{
135
+++ b/hw/arm/nseries.c
718
+ ptrdiff_t diff = wd - watchdog_list;
136
@@ -XXX,XX +XXX,XX @@
719
+
137
#include "ui/console.h"
720
+ g_assert(diff >= 0 && diff < ARRAY_SIZE(watchdog_list));
138
#include "hw/boards.h"
721
+
139
#include "hw/i2c/i2c.h"
722
+ return diff;
140
-#include "hw/devices.h"
723
+}
141
#include "hw/display/blizzard.h"
724
+
142
+#include "hw/input/tsc2xxx.h"
725
+static uint32_t watchdog_read_wtcr(QTestState *qts, const Watchdog *wd)
143
#include "hw/misc/cbus.h"
726
+{
144
#include "hw/misc/tmp105.h"
727
+ return qtest_readl(qts, wd->base_addr + WTCR_OFFSET);
145
#include "hw/block/flash.h"
728
+}
146
diff --git a/hw/arm/palm.c b/hw/arm/palm.c
729
+
147
index XXXXXXX..XXXXXXX 100644
730
+static void watchdog_write_wtcr(QTestState *qts, const Watchdog *wd,
148
--- a/hw/arm/palm.c
731
+ uint32_t value)
149
+++ b/hw/arm/palm.c
732
+{
150
@@ -XXX,XX +XXX,XX @@
733
+ qtest_writel(qts, wd->base_addr + WTCR_OFFSET, value);
151
#include "hw/arm/omap.h"
734
+}
152
#include "hw/boards.h"
735
+
153
#include "hw/arm/arm.h"
736
+static uint32_t watchdog_prescaler(QTestState *qts, const Watchdog *wd)
154
-#include "hw/devices.h"
737
+{
155
+#include "hw/input/tsc2xxx.h"
738
+ switch (extract32(watchdog_read_wtcr(qts, wd), 10, 2)) {
156
#include "hw/loader.h"
739
+ case 0:
157
#include "exec/address-spaces.h"
740
+ return 1;
158
#include "cpu.h"
741
+ case 1:
159
diff --git a/hw/input/tsc2005.c b/hw/input/tsc2005.c
742
+ return 256;
160
index XXXXXXX..XXXXXXX 100644
743
+ case 2:
161
--- a/hw/input/tsc2005.c
744
+ return 2048;
162
+++ b/hw/input/tsc2005.c
745
+ case 3:
163
@@ -XXX,XX +XXX,XX @@
746
+ return 65536;
164
#include "hw/hw.h"
747
+ default:
165
#include "qemu/timer.h"
748
+ g_assert_not_reached();
166
#include "ui/console.h"
749
+ }
167
-#include "hw/devices.h"
750
+}
168
+#include "hw/input/tsc2xxx.h"
751
+
169
#include "trace.h"
752
+static QDict *get_watchdog_action(QTestState *qts)
170
753
+{
171
#define TSC_CUT_RESOLUTION(value, p)    ((value) >> (16 - (p ? 12 : 10)))
754
+ QDict *ev = qtest_qmp_eventwait_ref(qts, "WATCHDOG");
172
diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c
755
+ QDict *data;
173
index XXXXXXX..XXXXXXX 100644
756
+
174
--- a/hw/input/tsc210x.c
757
+ data = qdict_get_qdict(ev, "data");
175
+++ b/hw/input/tsc210x.c
758
+ qobject_ref(data);
176
@@ -XXX,XX +XXX,XX @@
759
+ qobject_unref(ev);
177
#include "audio/audio.h"
760
+ return data;
178
#include "qemu/timer.h"
761
+}
179
#include "ui/console.h"
762
+
180
-#include "hw/arm/omap.h"    /* For I2SCodec and uWireSlave */
763
+#define RESET_CYCLES 1024
181
-#include "hw/devices.h"
764
+static uint32_t watchdog_interrupt_cycles(QTestState *qts, const Watchdog *wd)
182
+#include "hw/arm/omap.h" /* For I2SCodec */
765
+{
183
+#include "hw/input/tsc2xxx.h"
766
+ uint32_t wtis = extract32(watchdog_read_wtcr(qts, wd), 4, 2);
184
767
+ return 1 << (14 + 2 * wtis);
185
#define TSC_DATA_REGISTERS_PAGE        0x0
768
+}
186
#define TSC_CONTROL_REGISTERS_PAGE    0x1
769
+
770
+static int64_t watchdog_calculate_steps(uint32_t count, uint32_t prescale)
771
+{
772
+ return (NANOSECONDS_PER_SECOND / REF_HZ) * count * prescale;
773
+}
774
+
775
+static int64_t watchdog_interrupt_steps(QTestState *qts, const Watchdog *wd)
776
+{
777
+ return watchdog_calculate_steps(watchdog_interrupt_cycles(qts, wd),
778
+ watchdog_prescaler(qts, wd));
779
+}
780
+
781
+/* Check wtcr can be reset to default value */
782
+static void test_init(gconstpointer watchdog)
783
+{
784
+ const Watchdog *wd = watchdog;
785
+ QTestState *qts = qtest_init("-machine quanta-gsj");
786
+
787
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
788
+
789
+ watchdog_write_wtcr(qts, wd, WTCLK(1) | WTRF | WTIF | WTR);
790
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(1));
791
+
792
+ qtest_quit(qts);
793
+}
794
+
795
+/* Check a watchdog can generate interrupt and reset actions */
796
+static void test_reset_action(gconstpointer watchdog)
797
+{
798
+ const Watchdog *wd = watchdog;
799
+ QTestState *qts = qtest_init("-machine quanta-gsj");
800
+ QDict *ad;
801
+
802
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
803
+
804
+ watchdog_write_wtcr(qts, wd,
805
+ WTCLK(0) | WTE | WTRF | WTRE | WTIF | WTIE | WTR);
806
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==,
807
+ WTCLK(0) | WTE | WTRE | WTIE);
808
+
809
+ /* Check a watchdog can generate an interrupt */
810
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
811
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==,
812
+ WTCLK(0) | WTE | WTIF | WTIE | WTRE);
813
+ g_assert_true(qtest_get_irq(qts, wd->irq));
814
+
815
+ /* Check a watchdog can generate a reset signal */
816
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
817
+ watchdog_prescaler(qts, wd)));
818
+ ad = get_watchdog_action(qts);
819
+ /* The signal is a reset signal */
820
+ g_assert_false(strcmp(qdict_get_str(ad, "action"), "reset"));
821
+ qobject_unref(ad);
822
+ qtest_qmp_eventwait(qts, "RESET");
823
+ /*
824
+ * Make sure WTCR is reset to default except for WTRF bit which shouldn't
825
+ * be reset.
826
+ */
827
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(1) | WTRF);
828
+ qtest_quit(qts);
829
+}
830
+
831
+/* Check a watchdog works with all possible WTCLK prescalers and WTIS cycles */
832
+static void test_prescaler(gconstpointer watchdog)
833
+{
834
+ const Watchdog *wd = watchdog;
835
+
836
+ for (int wtclk = 0; wtclk < 4; ++wtclk) {
837
+ for (int wtis = 0; wtis < 4; ++wtis) {
838
+ QTestState *qts = qtest_init("-machine quanta-gsj");
839
+
840
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
841
+ watchdog_write_wtcr(qts, wd,
842
+ WTCLK(wtclk) | WTE | WTIF | WTIS(wtis) | WTIE | WTR);
843
+ /*
844
+ * The interrupt doesn't fire until watchdog_interrupt_steps()
845
+ * cycles passed
846
+ */
847
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd) - 1);
848
+ g_assert_false(watchdog_read_wtcr(qts, wd) & WTIF);
849
+ g_assert_false(qtest_get_irq(qts, wd->irq));
850
+ qtest_clock_step(qts, 1);
851
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
852
+ g_assert_true(qtest_get_irq(qts, wd->irq));
853
+
854
+ qtest_quit(qts);
855
+ }
856
+ }
857
+}
858
+
859
+/*
860
+ * Check a watchdog doesn't fire if corresponding flags (WTIE and WTRE) are not
861
+ * set.
862
+ */
863
+static void test_enabling_flags(gconstpointer watchdog)
864
+{
865
+ const Watchdog *wd = watchdog;
866
+ QTestState *qts;
867
+
868
+ /* Neither WTIE or WTRE is set, no interrupt or reset should happen */
869
+ qts = qtest_init("-machine quanta-gsj");
870
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
871
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTRF | WTR);
872
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
873
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
874
+ g_assert_false(qtest_get_irq(qts, wd->irq));
875
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
876
+ watchdog_prescaler(qts, wd)));
877
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
878
+ g_assert_false(watchdog_read_wtcr(qts, wd) & WTRF);
879
+ qtest_quit(qts);
880
+
881
+ /* Only WTIE is set, interrupt is triggered but reset should not happen */
882
+ qts = qtest_init("-machine quanta-gsj");
883
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
884
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTIE | WTRF | WTR);
885
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
886
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
887
+ g_assert_true(qtest_get_irq(qts, wd->irq));
888
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
889
+ watchdog_prescaler(qts, wd)));
890
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
891
+ g_assert_false(watchdog_read_wtcr(qts, wd) & WTRF);
892
+ qtest_quit(qts);
893
+
894
+ /* Only WTRE is set, interrupt is triggered but reset should not happen */
895
+ qts = qtest_init("-machine quanta-gsj");
896
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
897
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTRE | WTRF | WTR);
898
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
899
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
900
+ g_assert_false(qtest_get_irq(qts, wd->irq));
901
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
902
+ watchdog_prescaler(qts, wd)));
903
+ g_assert_false(strcmp(qdict_get_str(get_watchdog_action(qts), "action"),
904
+ "reset"));
905
+ qtest_qmp_eventwait(qts, "RESET");
906
+ qtest_quit(qts);
907
+
908
+ /*
909
+ * The case when both flags are set is already tested in
910
+ * test_reset_action().
911
+ */
912
+}
913
+
914
+/* Check a watchdog can pause and resume by setting WTE bits */
915
+static void test_pause(gconstpointer watchdog)
916
+{
917
+ const Watchdog *wd = watchdog;
918
+ QTestState *qts;
919
+ int64_t remaining_steps, steps;
920
+
921
+ qts = qtest_init("-machine quanta-gsj");
922
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
923
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTIE | WTRF | WTR);
924
+ remaining_steps = watchdog_interrupt_steps(qts, wd);
925
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTE | WTIE);
926
+
927
+ /* Run for half of the execution period. */
928
+ steps = remaining_steps / 2;
929
+ remaining_steps -= steps;
930
+ qtest_clock_step(qts, steps);
931
+
932
+ /* Pause the watchdog */
933
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTIE);
934
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTIE);
935
+
936
+ /* Run for a long period of time, the watchdog shouldn't fire */
937
+ qtest_clock_step(qts, steps << 4);
938
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTIE);
939
+ g_assert_false(qtest_get_irq(qts, wd->irq));
940
+
941
+ /* Resume the watchdog */
942
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIE);
943
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTE | WTIE);
944
+
945
+ /* Run for the reset of the execution period, the watchdog should fire */
946
+ qtest_clock_step(qts, remaining_steps);
947
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==,
948
+ WTCLK(0) | WTE | WTIF | WTIE);
949
+ g_assert_true(qtest_get_irq(qts, wd->irq));
950
+
951
+ qtest_quit(qts);
952
+}
953
+
954
+static void watchdog_add_test(const char *name, const Watchdog* wd,
955
+ GTestDataFunc fn)
956
+{
957
+ g_autofree char *full_name = g_strdup_printf(
958
+ "npcm7xx_watchdog_timer[%d]/%s", watchdog_index(wd), name);
959
+ qtest_add_data_func(full_name, wd, fn);
960
+}
961
+#define add_test(name, td) watchdog_add_test(#name, td, test_##name)
962
+
963
+int main(int argc, char **argv)
964
+{
965
+ g_test_init(&argc, &argv, NULL);
966
+ g_test_set_nonfatal_assertions();
967
+
968
+ for (int i = 0; i < ARRAY_SIZE(watchdog_list); ++i) {
969
+ const Watchdog *wd = &watchdog_list[i];
970
+
971
+ add_test(init, wd);
972
+ add_test(reset_action, wd);
973
+ add_test(prescaler, wd);
974
+ add_test(enabling_flags, wd);
975
+ add_test(pause, wd);
976
+ }
977
+
978
+ return g_test_run();
979
+}
187
diff --git a/MAINTAINERS b/MAINTAINERS
980
diff --git a/MAINTAINERS b/MAINTAINERS
188
index XXXXXXX..XXXXXXX 100644
981
index XXXXXXX..XXXXXXX 100644
189
--- a/MAINTAINERS
982
--- a/MAINTAINERS
190
+++ b/MAINTAINERS
983
+++ b/MAINTAINERS
191
@@ -XXX,XX +XXX,XX @@ F: hw/input/tsc2005.c
192
F: hw/misc/cbus.c
193
F: hw/timer/twl92230.c
194
F: include/hw/display/blizzard.h
195
+F: include/hw/input/tsc2xxx.h
196
F: include/hw/misc/cbus.h
197
198
Palm
199
@@ -XXX,XX +XXX,XX @@ L: qemu-arm@nongnu.org
984
@@ -XXX,XX +XXX,XX @@ L: qemu-arm@nongnu.org
200
S: Odd Fixes
985
S: Supported
201
F: hw/arm/palm.c
986
F: hw/*/npcm7xx*
202
F: hw/input/tsc210x.c
987
F: include/hw/*/npcm7xx*
203
+F: include/hw/input/tsc2xxx.h
988
+F: tests/qtest/npcm7xx*
204
989
F: pc-bios/npcm7xx_bootrom.bin
205
Raspberry Pi
990
F: roms/vbootrom
206
M: Peter Maydell <peter.maydell@linaro.org>
991
992
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
993
index XXXXXXX..XXXXXXX 100644
994
--- a/tests/qtest/meson.build
995
+++ b/tests/qtest/meson.build
996
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
997
(config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \
998
['prom-env-test', 'boot-serial-test']
999
1000
-qtests_npcm7xx = ['npcm7xx_timer-test']
1001
+qtests_npcm7xx = ['npcm7xx_timer-test', 'npcm7xx_watchdog_timer-test']
1002
qtests_arm = \
1003
(config_all_devices.has_key('CONFIG_PFLASH_CFI02') ? ['pflash-cfi02-test'] : []) + \
1004
(config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
207
--
1005
--
208
2.20.1
1006
2.20.1
209
1007
210
1008
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Havard Skinnemoen <hskinnemoen@google.com>
2
2
3
Reviewed-by: Markus Armbruster <armbru@redhat.com>
3
The RNG module returns a byte of randomness when the Data Valid bit is
4
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
4
set.
5
Message-id: 20190412165416.7977-10-philmd@redhat.com
5
6
This implementation ignores the prescaler setting, and loads a new value
7
into RNGD every time RNGCS is read while the RNG is enabled and random
8
data is available.
9
10
A qtest featuring some simple randomness tests is included.
11
12
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
16
---
8
include/hw/devices.h | 3 ---
17
docs/system/arm/nuvoton.rst | 2 +-
9
include/hw/net/lan9118.h | 19 +++++++++++++++++++
18
include/hw/arm/npcm7xx.h | 2 +
10
hw/arm/kzm.c | 2 +-
19
include/hw/misc/npcm7xx_rng.h | 34 ++++
11
hw/arm/mps2.c | 2 +-
20
hw/arm/npcm7xx.c | 7 +-
12
hw/arm/realview.c | 1 +
21
hw/misc/npcm7xx_rng.c | 180 +++++++++++++++++++++
13
hw/arm/vexpress.c | 2 +-
22
tests/qtest/npcm7xx_rng-test.c | 278 +++++++++++++++++++++++++++++++++
14
hw/net/lan9118.c | 2 +-
23
hw/misc/meson.build | 1 +
15
7 files changed, 24 insertions(+), 7 deletions(-)
24
hw/misc/trace-events | 4 +
16
create mode 100644 include/hw/net/lan9118.h
25
tests/qtest/meson.build | 5 +-
26
9 files changed, 510 insertions(+), 3 deletions(-)
27
create mode 100644 include/hw/misc/npcm7xx_rng.h
28
create mode 100644 hw/misc/npcm7xx_rng.c
29
create mode 100644 tests/qtest/npcm7xx_rng-test.c
17
30
18
diff --git a/include/hw/devices.h b/include/hw/devices.h
31
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
19
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
20
--- a/include/hw/devices.h
33
--- a/docs/system/arm/nuvoton.rst
21
+++ b/include/hw/devices.h
34
+++ b/docs/system/arm/nuvoton.rst
35
@@ -XXX,XX +XXX,XX @@ Supported devices
36
* DDR4 memory controller (dummy interface indicating memory training is done)
37
* OTP controllers (no protection features)
38
* Flash Interface Unit (FIU; no protection features)
39
+ * Random Number Generator (RNG)
40
41
Missing devices
42
---------------
43
@@ -XXX,XX +XXX,XX @@ Missing devices
44
* Peripheral SPI controller (PSPI)
45
* Analog to Digital Converter (ADC)
46
* SD/MMC host
47
- * Random Number Generator (RNG)
48
* PECI interface
49
* Pulse Width Modulation (PWM)
50
* Tachometer
51
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
52
index XXXXXXX..XXXXXXX 100644
53
--- a/include/hw/arm/npcm7xx.h
54
+++ b/include/hw/arm/npcm7xx.h
22
@@ -XXX,XX +XXX,XX @@
55
@@ -XXX,XX +XXX,XX @@
23
/* smc91c111.c */
56
#include "hw/mem/npcm7xx_mc.h"
24
void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
57
#include "hw/misc/npcm7xx_clk.h"
25
58
#include "hw/misc/npcm7xx_gcr.h"
26
-/* lan9118.c */
59
+#include "hw/misc/npcm7xx_rng.h"
27
-void lan9118_init(NICInfo *, uint32_t, qemu_irq);
60
#include "hw/nvram/npcm7xx_otp.h"
28
-
61
#include "hw/timer/npcm7xx_timer.h"
29
#endif
62
#include "hw/ssi/npcm7xx_fiu.h"
30
diff --git a/include/hw/net/lan9118.h b/include/hw/net/lan9118.h
63
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
64
NPCM7xxOTPState key_storage;
65
NPCM7xxOTPState fuse_array;
66
NPCM7xxMCState mc;
67
+ NPCM7xxRNGState rng;
68
NPCM7xxFIUState fiu[2];
69
} NPCM7xxState;
70
71
diff --git a/include/hw/misc/npcm7xx_rng.h b/include/hw/misc/npcm7xx_rng.h
31
new file mode 100644
72
new file mode 100644
32
index XXXXXXX..XXXXXXX
73
index XXXXXXX..XXXXXXX
33
--- /dev/null
74
--- /dev/null
34
+++ b/include/hw/net/lan9118.h
75
+++ b/include/hw/misc/npcm7xx_rng.h
35
@@ -XXX,XX +XXX,XX @@
76
@@ -XXX,XX +XXX,XX @@
36
+/*
77
+/*
37
+ * SMSC LAN9118 Ethernet interface emulation
78
+ * Nuvoton NPCM7xx Random Number Generator.
38
+ *
79
+ *
39
+ * Copyright (c) 2009 CodeSourcery, LLC.
80
+ * Copyright 2020 Google LLC
40
+ * Written by Paul Brook
81
+ *
41
+ *
82
+ * This program is free software; you can redistribute it and/or modify it
42
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
83
+ * under the terms of the GNU General Public License as published by the
43
+ * See the COPYING file in the top-level directory.
84
+ * Free Software Foundation; either version 2 of the License, or
44
+ */
85
+ * (at your option) any later version.
45
+
86
+ *
46
+#ifndef HW_NET_LAN9118_H
87
+ * This program is distributed in the hope that it will be useful, but WITHOUT
47
+#define HW_NET_LAN9118_H
88
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
48
+
89
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
49
+#include "hw/irq.h"
90
+ * for more details.
50
+#include "net/net.h"
91
+ */
51
+
92
+#ifndef NPCM7XX_RNG_H
52
+void lan9118_init(NICInfo *, uint32_t, qemu_irq);
93
+#define NPCM7XX_RNG_H
53
+
94
+
54
+#endif
95
+#include "hw/sysbus.h"
55
diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c
96
+
97
+typedef struct NPCM7xxRNGState {
98
+ SysBusDevice parent;
99
+
100
+ MemoryRegion iomem;
101
+
102
+ uint8_t rngcs;
103
+ uint8_t rngd;
104
+ uint8_t rngmode;
105
+} NPCM7xxRNGState;
106
+
107
+#define TYPE_NPCM7XX_RNG "npcm7xx-rng"
108
+#define NPCM7XX_RNG(obj) OBJECT_CHECK(NPCM7xxRNGState, (obj), TYPE_NPCM7XX_RNG)
109
+
110
+#endif /* NPCM7XX_RNG_H */
111
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
56
index XXXXXXX..XXXXXXX 100644
112
index XXXXXXX..XXXXXXX 100644
57
--- a/hw/arm/kzm.c
113
--- a/hw/arm/npcm7xx.c
58
+++ b/hw/arm/kzm.c
114
+++ b/hw/arm/npcm7xx.c
59
@@ -XXX,XX +XXX,XX @@
115
@@ -XXX,XX +XXX,XX @@
60
#include "qemu/error-report.h"
116
#define NPCM7XX_GCR_BA (0xf0800000)
61
#include "exec/address-spaces.h"
117
#define NPCM7XX_CLK_BA (0xf0801000)
62
#include "net/net.h"
118
#define NPCM7XX_MC_BA (0xf0824000)
63
-#include "hw/devices.h"
119
+#define NPCM7XX_RNG_BA (0xf000b000)
64
+#include "hw/net/lan9118.h"
120
65
#include "hw/char/serial.h"
121
/* Internal AHB SRAM */
66
#include "sysemu/qtest.h"
122
#define NPCM7XX_RAM3_BA (0xc0008000)
67
123
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
68
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
124
object_initialize_child(obj, "otp2", &s->fuse_array,
125
TYPE_NPCM7XX_FUSE_ARRAY);
126
object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
127
+ object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
128
129
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
130
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
131
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
132
serial_hd(i), DEVICE_LITTLE_ENDIAN);
133
}
134
135
+ /* Random Number Generator. Cannot fail. */
136
+ sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
137
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA);
138
+
139
/*
140
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
141
* specified, but this is a programming error.
142
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
143
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
144
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
145
create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB);
146
- create_unimplemented_device("npcm7xx.rng", 0xf000b000, 4 * KiB);
147
create_unimplemented_device("npcm7xx.adc", 0xf000c000, 4 * KiB);
148
create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB);
149
create_unimplemented_device("npcm7xx.gpio[0]", 0xf0010000, 4 * KiB);
150
diff --git a/hw/misc/npcm7xx_rng.c b/hw/misc/npcm7xx_rng.c
151
new file mode 100644
152
index XXXXXXX..XXXXXXX
153
--- /dev/null
154
+++ b/hw/misc/npcm7xx_rng.c
155
@@ -XXX,XX +XXX,XX @@
156
+/*
157
+ * Nuvoton NPCM7xx Random Number Generator.
158
+ *
159
+ * Copyright 2020 Google LLC
160
+ *
161
+ * This program is free software; you can redistribute it and/or modify it
162
+ * under the terms of the GNU General Public License as published by the
163
+ * Free Software Foundation; either version 2 of the License, or
164
+ * (at your option) any later version.
165
+ *
166
+ * This program is distributed in the hope that it will be useful, but WITHOUT
167
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
168
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
169
+ * for more details.
170
+ */
171
+
172
+#include "qemu/osdep.h"
173
+
174
+#include "hw/misc/npcm7xx_rng.h"
175
+#include "migration/vmstate.h"
176
+#include "qemu/bitops.h"
177
+#include "qemu/guest-random.h"
178
+#include "qemu/log.h"
179
+#include "qemu/module.h"
180
+#include "qemu/units.h"
181
+
182
+#include "trace.h"
183
+
184
+#define NPCM7XX_RNG_REGS_SIZE (4 * KiB)
185
+
186
+#define NPCM7XX_RNGCS (0x00)
187
+#define NPCM7XX_RNGCS_CLKP(rv) extract32(rv, 2, 4)
188
+#define NPCM7XX_RNGCS_DVALID BIT(1)
189
+#define NPCM7XX_RNGCS_RNGE BIT(0)
190
+
191
+#define NPCM7XX_RNGD (0x04)
192
+#define NPCM7XX_RNGMODE (0x08)
193
+#define NPCM7XX_RNGMODE_NORMAL (0x02)
194
+
195
+static bool npcm7xx_rng_is_enabled(NPCM7xxRNGState *s)
196
+{
197
+ return (s->rngcs & NPCM7XX_RNGCS_RNGE) &&
198
+ (s->rngmode == NPCM7XX_RNGMODE_NORMAL);
199
+}
200
+
201
+static uint64_t npcm7xx_rng_read(void *opaque, hwaddr offset, unsigned size)
202
+{
203
+ NPCM7xxRNGState *s = opaque;
204
+ uint64_t value = 0;
205
+
206
+ switch (offset) {
207
+ case NPCM7XX_RNGCS:
208
+ /*
209
+ * If the RNG is enabled, but we don't have any valid random data, try
210
+ * obtaining some and update the DVALID bit accordingly.
211
+ */
212
+ if (!npcm7xx_rng_is_enabled(s)) {
213
+ s->rngcs &= ~NPCM7XX_RNGCS_DVALID;
214
+ } else if (!(s->rngcs & NPCM7XX_RNGCS_DVALID)) {
215
+ uint8_t byte = 0;
216
+
217
+ if (qemu_guest_getrandom(&byte, sizeof(byte), NULL) == 0) {
218
+ s->rngd = byte;
219
+ s->rngcs |= NPCM7XX_RNGCS_DVALID;
220
+ }
221
+ }
222
+ value = s->rngcs;
223
+ break;
224
+ case NPCM7XX_RNGD:
225
+ if (npcm7xx_rng_is_enabled(s) && s->rngcs & NPCM7XX_RNGCS_DVALID) {
226
+ s->rngcs &= ~NPCM7XX_RNGCS_DVALID;
227
+ value = s->rngd;
228
+ s->rngd = 0;
229
+ }
230
+ break;
231
+ case NPCM7XX_RNGMODE:
232
+ value = s->rngmode;
233
+ break;
234
+
235
+ default:
236
+ qemu_log_mask(LOG_GUEST_ERROR,
237
+ "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
238
+ DEVICE(s)->canonical_path, offset);
239
+ break;
240
+ }
241
+
242
+ trace_npcm7xx_rng_read(offset, value, size);
243
+
244
+ return value;
245
+}
246
+
247
+static void npcm7xx_rng_write(void *opaque, hwaddr offset, uint64_t value,
248
+ unsigned size)
249
+{
250
+ NPCM7xxRNGState *s = opaque;
251
+
252
+ trace_npcm7xx_rng_write(offset, value, size);
253
+
254
+ switch (offset) {
255
+ case NPCM7XX_RNGCS:
256
+ s->rngcs &= NPCM7XX_RNGCS_DVALID;
257
+ s->rngcs |= value & ~NPCM7XX_RNGCS_DVALID;
258
+ break;
259
+ case NPCM7XX_RNGD:
260
+ qemu_log_mask(LOG_GUEST_ERROR,
261
+ "%s: write to read-only register @ 0x%" HWADDR_PRIx "\n",
262
+ DEVICE(s)->canonical_path, offset);
263
+ break;
264
+ case NPCM7XX_RNGMODE:
265
+ s->rngmode = value;
266
+ break;
267
+ default:
268
+ qemu_log_mask(LOG_GUEST_ERROR,
269
+ "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
270
+ DEVICE(s)->canonical_path, offset);
271
+ break;
272
+ }
273
+}
274
+
275
+static const MemoryRegionOps npcm7xx_rng_ops = {
276
+ .read = npcm7xx_rng_read,
277
+ .write = npcm7xx_rng_write,
278
+ .endianness = DEVICE_LITTLE_ENDIAN,
279
+ .valid = {
280
+ .min_access_size = 1,
281
+ .max_access_size = 4,
282
+ .unaligned = false,
283
+ },
284
+};
285
+
286
+static void npcm7xx_rng_enter_reset(Object *obj, ResetType type)
287
+{
288
+ NPCM7xxRNGState *s = NPCM7XX_RNG(obj);
289
+
290
+ s->rngcs = 0;
291
+ s->rngd = 0;
292
+ s->rngmode = 0;
293
+}
294
+
295
+static void npcm7xx_rng_init(Object *obj)
296
+{
297
+ NPCM7xxRNGState *s = NPCM7XX_RNG(obj);
298
+
299
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_rng_ops, s, "regs",
300
+ NPCM7XX_RNG_REGS_SIZE);
301
+ sysbus_init_mmio(&s->parent, &s->iomem);
302
+}
303
+
304
+static const VMStateDescription vmstate_npcm7xx_rng = {
305
+ .name = "npcm7xx-rng",
306
+ .version_id = 0,
307
+ .minimum_version_id = 0,
308
+ .fields = (VMStateField[]) {
309
+ VMSTATE_UINT8(rngcs, NPCM7xxRNGState),
310
+ VMSTATE_UINT8(rngd, NPCM7xxRNGState),
311
+ VMSTATE_UINT8(rngmode, NPCM7xxRNGState),
312
+ VMSTATE_END_OF_LIST(),
313
+ },
314
+};
315
+
316
+static void npcm7xx_rng_class_init(ObjectClass *klass, void *data)
317
+{
318
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
319
+ DeviceClass *dc = DEVICE_CLASS(klass);
320
+
321
+ dc->desc = "NPCM7xx Random Number Generator";
322
+ dc->vmsd = &vmstate_npcm7xx_rng;
323
+ rc->phases.enter = npcm7xx_rng_enter_reset;
324
+}
325
+
326
+static const TypeInfo npcm7xx_rng_types[] = {
327
+ {
328
+ .name = TYPE_NPCM7XX_RNG,
329
+ .parent = TYPE_SYS_BUS_DEVICE,
330
+ .instance_size = sizeof(NPCM7xxRNGState),
331
+ .class_init = npcm7xx_rng_class_init,
332
+ .instance_init = npcm7xx_rng_init,
333
+ },
334
+};
335
+DEFINE_TYPES(npcm7xx_rng_types);
336
diff --git a/tests/qtest/npcm7xx_rng-test.c b/tests/qtest/npcm7xx_rng-test.c
337
new file mode 100644
338
index XXXXXXX..XXXXXXX
339
--- /dev/null
340
+++ b/tests/qtest/npcm7xx_rng-test.c
341
@@ -XXX,XX +XXX,XX @@
342
+/*
343
+ * QTest testcase for the Nuvoton NPCM7xx Random Number Generator
344
+ *
345
+ * Copyright 2020 Google LLC
346
+ *
347
+ * This program is free software; you can redistribute it and/or modify it
348
+ * under the terms of the GNU General Public License as published by the
349
+ * Free Software Foundation; either version 2 of the License, or
350
+ * (at your option) any later version.
351
+ *
352
+ * This program is distributed in the hope that it will be useful, but WITHOUT
353
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
354
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
355
+ * for more details.
356
+ */
357
+
358
+#include "qemu/osdep.h"
359
+
360
+#include <math.h>
361
+
362
+#include "libqtest-single.h"
363
+#include "qemu/bitops.h"
364
+
365
+#define RNG_BASE_ADDR 0xf000b000
366
+
367
+/* Control and Status Register */
368
+#define RNGCS 0x00
369
+# define DVALID BIT(1) /* Data Valid */
370
+# define RNGE BIT(0) /* RNG Enable */
371
+/* Data Register */
372
+#define RNGD 0x04
373
+/* Mode Register */
374
+#define RNGMODE 0x08
375
+# define ROSEL_NORMAL (2) /* RNG only works in this mode */
376
+
377
+/* Number of bits to collect for randomness tests. */
378
+#define TEST_INPUT_BITS (128)
379
+
380
+static void rng_writeb(unsigned int offset, uint8_t value)
381
+{
382
+ writeb(RNG_BASE_ADDR + offset, value);
383
+}
384
+
385
+static uint8_t rng_readb(unsigned int offset)
386
+{
387
+ return readb(RNG_BASE_ADDR + offset);
388
+}
389
+
390
+/* Disable RNG and set normal ring oscillator mode. */
391
+static void rng_reset(void)
392
+{
393
+ rng_writeb(RNGCS, 0);
394
+ rng_writeb(RNGMODE, ROSEL_NORMAL);
395
+}
396
+
397
+/* Reset RNG and then enable it. */
398
+static void rng_reset_enable(void)
399
+{
400
+ rng_reset();
401
+ rng_writeb(RNGCS, RNGE);
402
+}
403
+
404
+/* Wait until Data Valid bit is set. */
405
+static bool rng_wait_ready(void)
406
+{
407
+ /* qemu_guest_getrandom may fail. Assume it won't fail 10 times in a row. */
408
+ int retries = 10;
409
+
410
+ while (retries-- > 0) {
411
+ if (rng_readb(RNGCS) & DVALID) {
412
+ return true;
413
+ }
414
+ }
415
+
416
+ return false;
417
+}
418
+
419
+/*
420
+ * Perform a frequency (monobit) test, as defined by NIST SP 800-22, on the
421
+ * sequence in buf and return the P-value. This represents the probability of a
422
+ * truly random sequence having the same proportion of zeros and ones as the
423
+ * sequence in buf.
424
+ *
425
+ * An RNG which always returns 0x00 or 0xff, or has some bits stuck at 0 or 1,
426
+ * will fail this test. However, an RNG which always returns 0x55, 0xf0 or some
427
+ * other value with an equal number of zeroes and ones will pass.
428
+ */
429
+static double calc_monobit_p(const uint8_t *buf, unsigned int len)
430
+{
431
+ unsigned int i;
432
+ double s_obs;
433
+ int sn = 0;
434
+
435
+ for (i = 0; i < len; i++) {
436
+ /*
437
+ * Each 1 counts as 1, each 0 counts as -1.
438
+ * s = cp - (8 - cp) = 2 * cp - 8
439
+ */
440
+ sn += 2 * ctpop8(buf[i]) - 8;
441
+ }
442
+
443
+ s_obs = abs(sn) / sqrt(len * BITS_PER_BYTE);
444
+
445
+ return erfc(s_obs / sqrt(2));
446
+}
447
+
448
+/*
449
+ * Perform a runs test, as defined by NIST SP 800-22, and return the P-value.
450
+ * This represents the probability of a truly random sequence having the same
451
+ * number of runs (i.e. uninterrupted sequences of identical bits) as the
452
+ * sequence in buf.
453
+ */
454
+static double calc_runs_p(const unsigned long *buf, unsigned int nr_bits)
455
+{
456
+ unsigned int j;
457
+ unsigned int k;
458
+ int nr_ones = 0;
459
+ int vn_obs = 0;
460
+ double pi;
461
+
462
+ g_assert(nr_bits % BITS_PER_LONG == 0);
463
+
464
+ for (j = 0; j < nr_bits / BITS_PER_LONG; j++) {
465
+ nr_ones += __builtin_popcountl(buf[j]);
466
+ }
467
+ pi = (double)nr_ones / nr_bits;
468
+
469
+ for (k = 0; k < nr_bits - 1; k++) {
470
+ vn_obs += !(test_bit(k, buf) ^ test_bit(k + 1, buf));
471
+ }
472
+ vn_obs += 1;
473
+
474
+ return erfc(fabs(vn_obs - 2 * nr_bits * pi * (1.0 - pi))
475
+ / (2 * sqrt(2 * nr_bits) * pi * (1.0 - pi)));
476
+}
477
+
478
+/*
479
+ * Verifies that DVALID is clear, and RNGD reads zero, when RNGE is cleared,
480
+ * and DVALID eventually becomes set when RNGE is set.
481
+ */
482
+static void test_enable_disable(void)
483
+{
484
+ /* Disable: DVALID should not be set, and RNGD should read zero */
485
+ rng_reset();
486
+ g_assert_cmphex(rng_readb(RNGCS), ==, 0);
487
+ g_assert_cmphex(rng_readb(RNGD), ==, 0);
488
+
489
+ /* Enable: DVALID should be set, but we can't make assumptions about RNGD */
490
+ rng_writeb(RNGCS, RNGE);
491
+ g_assert_true(rng_wait_ready());
492
+ g_assert_cmphex(rng_readb(RNGCS), ==, DVALID | RNGE);
493
+
494
+ /* Disable: DVALID should not be set, and RNGD should read zero */
495
+ rng_writeb(RNGCS, 0);
496
+ g_assert_cmphex(rng_readb(RNGCS), ==, 0);
497
+ g_assert_cmphex(rng_readb(RNGD), ==, 0);
498
+}
499
+
500
+/*
501
+ * Verifies that the RNG only produces data when RNGMODE is set to 'normal'
502
+ * ring oscillator mode.
503
+ */
504
+static void test_rosel(void)
505
+{
506
+ rng_reset_enable();
507
+ g_assert_true(rng_wait_ready());
508
+ rng_writeb(RNGMODE, 0);
509
+ g_assert_false(rng_wait_ready());
510
+ rng_writeb(RNGMODE, ROSEL_NORMAL);
511
+ g_assert_true(rng_wait_ready());
512
+ rng_writeb(RNGMODE, 0);
513
+ g_assert_false(rng_wait_ready());
514
+}
515
+
516
+/*
517
+ * Verifies that a continuous sequence of bits collected after enabling the RNG
518
+ * satisfies a monobit test.
519
+ */
520
+static void test_continuous_monobit(void)
521
+{
522
+ uint8_t buf[TEST_INPUT_BITS / BITS_PER_BYTE];
523
+ unsigned int i;
524
+
525
+ rng_reset_enable();
526
+ for (i = 0; i < sizeof(buf); i++) {
527
+ g_assert_true(rng_wait_ready());
528
+ buf[i] = rng_readb(RNGD);
529
+ }
530
+
531
+ g_assert_cmpfloat(calc_monobit_p(buf, sizeof(buf)), >, 0.01);
532
+}
533
+
534
+/*
535
+ * Verifies that a continuous sequence of bits collected after enabling the RNG
536
+ * satisfies a runs test.
537
+ */
538
+static void test_continuous_runs(void)
539
+{
540
+ union {
541
+ unsigned long l[TEST_INPUT_BITS / BITS_PER_LONG];
542
+ uint8_t c[TEST_INPUT_BITS / BITS_PER_BYTE];
543
+ } buf;
544
+ unsigned int i;
545
+
546
+ rng_reset_enable();
547
+ for (i = 0; i < sizeof(buf); i++) {
548
+ g_assert_true(rng_wait_ready());
549
+ buf.c[i] = rng_readb(RNGD);
550
+ }
551
+
552
+ g_assert_cmpfloat(calc_runs_p(buf.l, sizeof(buf) * BITS_PER_BYTE), >, 0.01);
553
+}
554
+
555
+/*
556
+ * Verifies that the first data byte collected after enabling the RNG satisfies
557
+ * a monobit test.
558
+ */
559
+static void test_first_byte_monobit(void)
560
+{
561
+ /* Enable, collect one byte, disable. Repeat until we have 100 bits. */
562
+ uint8_t buf[TEST_INPUT_BITS / BITS_PER_BYTE];
563
+ unsigned int i;
564
+
565
+ rng_reset();
566
+ for (i = 0; i < sizeof(buf); i++) {
567
+ rng_writeb(RNGCS, RNGE);
568
+ g_assert_true(rng_wait_ready());
569
+ buf[i] = rng_readb(RNGD);
570
+ rng_writeb(RNGCS, 0);
571
+ }
572
+
573
+ g_assert_cmpfloat(calc_monobit_p(buf, sizeof(buf)), >, 0.01);
574
+}
575
+
576
+/*
577
+ * Verifies that the first data byte collected after enabling the RNG satisfies
578
+ * a runs test.
579
+ */
580
+static void test_first_byte_runs(void)
581
+{
582
+ /* Enable, collect one byte, disable. Repeat until we have 100 bits. */
583
+ union {
584
+ unsigned long l[TEST_INPUT_BITS / BITS_PER_LONG];
585
+ uint8_t c[TEST_INPUT_BITS / BITS_PER_BYTE];
586
+ } buf;
587
+ unsigned int i;
588
+
589
+ rng_reset();
590
+ for (i = 0; i < sizeof(buf); i++) {
591
+ rng_writeb(RNGCS, RNGE);
592
+ g_assert_true(rng_wait_ready());
593
+ buf.c[i] = rng_readb(RNGD);
594
+ rng_writeb(RNGCS, 0);
595
+ }
596
+
597
+ g_assert_cmpfloat(calc_runs_p(buf.l, sizeof(buf) * BITS_PER_BYTE), >, 0.01);
598
+}
599
+
600
+int main(int argc, char **argv)
601
+{
602
+ int ret;
603
+
604
+ g_test_init(&argc, &argv, NULL);
605
+ g_test_set_nonfatal_assertions();
606
+
607
+ qtest_add_func("npcm7xx_rng/enable_disable", test_enable_disable);
608
+ qtest_add_func("npcm7xx_rng/rosel", test_rosel);
609
+ qtest_add_func("npcm7xx_rng/continuous/monobit", test_continuous_monobit);
610
+ qtest_add_func("npcm7xx_rng/continuous/runs", test_continuous_runs);
611
+ qtest_add_func("npcm7xx_rng/first_byte/monobit", test_first_byte_monobit);
612
+ qtest_add_func("npcm7xx_rng/first_byte/runs", test_first_byte_runs);
613
+
614
+ qtest_start("-machine npcm750-evb");
615
+ ret = g_test_run();
616
+ qtest_end();
617
+
618
+ return ret;
619
+}
620
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
69
index XXXXXXX..XXXXXXX 100644
621
index XXXXXXX..XXXXXXX 100644
70
--- a/hw/arm/mps2.c
622
--- a/hw/misc/meson.build
71
+++ b/hw/arm/mps2.c
623
+++ b/hw/misc/meson.build
72
@@ -XXX,XX +XXX,XX @@
624
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
73
#include "hw/timer/cmsdk-apb-timer.h"
625
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
74
#include "hw/timer/cmsdk-apb-dualtimer.h"
626
'npcm7xx_clk.c',
75
#include "hw/misc/mps2-scc.h"
627
'npcm7xx_gcr.c',
76
-#include "hw/devices.h"
628
+ 'npcm7xx_rng.c',
77
+#include "hw/net/lan9118.h"
629
))
78
#include "net/net.h"
630
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files(
79
631
'omap_clk.c',
80
typedef enum MPS2FPGAType {
632
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
81
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
82
index XXXXXXX..XXXXXXX 100644
633
index XXXXXXX..XXXXXXX 100644
83
--- a/hw/arm/realview.c
634
--- a/hw/misc/trace-events
84
+++ b/hw/arm/realview.c
635
+++ b/hw/misc/trace-events
85
@@ -XXX,XX +XXX,XX @@
636
@@ -XXX,XX +XXX,XX @@ npcm7xx_clk_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " valu
86
#include "hw/arm/arm.h"
637
npcm7xx_gcr_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
87
#include "hw/arm/primecell.h"
638
npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
88
#include "hw/devices.h"
639
89
+#include "hw/net/lan9118.h"
640
+# npcm7xx_rng.c
90
#include "hw/pci/pci.h"
641
+npcm7xx_rng_read(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
91
#include "net/net.h"
642
+npcm7xx_rng_write(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
92
#include "sysemu/sysemu.h"
643
+
93
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
644
# stm32f4xx_syscfg.c
645
stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d"
646
stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
647
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
94
index XXXXXXX..XXXXXXX 100644
648
index XXXXXXX..XXXXXXX 100644
95
--- a/hw/arm/vexpress.c
649
--- a/tests/qtest/meson.build
96
+++ b/hw/arm/vexpress.c
650
+++ b/tests/qtest/meson.build
97
@@ -XXX,XX +XXX,XX @@
651
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
98
#include "hw/sysbus.h"
652
(config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \
99
#include "hw/arm/arm.h"
653
['prom-env-test', 'boot-serial-test']
100
#include "hw/arm/primecell.h"
654
101
-#include "hw/devices.h"
655
-qtests_npcm7xx = ['npcm7xx_timer-test', 'npcm7xx_watchdog_timer-test']
102
+#include "hw/net/lan9118.h"
656
+qtests_npcm7xx = \
103
#include "hw/i2c/i2c.h"
657
+ ['npcm7xx_rng-test',
104
#include "net/net.h"
658
+ 'npcm7xx_timer-test',
105
#include "sysemu/sysemu.h"
659
+ 'npcm7xx_watchdog_timer-test']
106
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
660
qtests_arm = \
107
index XXXXXXX..XXXXXXX 100644
661
(config_all_devices.has_key('CONFIG_PFLASH_CFI02') ? ['pflash-cfi02-test'] : []) + \
108
--- a/hw/net/lan9118.c
662
(config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
109
+++ b/hw/net/lan9118.c
110
@@ -XXX,XX +XXX,XX @@
111
#include "hw/sysbus.h"
112
#include "net/net.h"
113
#include "net/eth.h"
114
-#include "hw/devices.h"
115
+#include "hw/net/lan9118.h"
116
#include "sysemu/sysemu.h"
117
#include "hw/ptimer.h"
118
#include "qemu/log.h"
119
--
663
--
120
2.20.1
664
2.20.1
121
665
122
666
diff view generated by jsdifflib
1
Enforce that for M-profile various FPSCR bits which are RES0 there
1
From: Havard Skinnemoen <hskinnemoen@google.com>
2
but have defined meanings on A-profile are never settable. This
3
ensures that M-profile code can't enable the A-profile behaviour
4
(notably vector length/stride handling) by accident.
5
2
3
The NPCM730 and NPCM750 chips have a single USB host port shared between
4
a USB 2.0 EHCI host controller and a USB 1.1 OHCI host controller. This
5
adds support for both of them.
6
7
Testing notes:
8
* With -device usb-kbd, qemu will automatically insert a full-speed
9
hub, and the keyboard becomes controlled by the OHCI controller.
10
* With -device usb-kbd,bus=usb-bus.0,port=1, the keyboard is directly
11
attached to the port without any hubs, and the device becomes
12
controlled by the EHCI controller since it's high speed capable.
13
* With -device usb-kbd,bus=usb-bus.0,port=1,usb_version=1, the
14
keyboard is directly attached to the port, but it only advertises
15
itself as full-speed capable, so it becomes controlled by the OHCI
16
controller.
17
18
In all cases, the keyboard device enumerates correctly.
19
20
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
21
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
22
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20190416125744.27770-2-peter.maydell@linaro.org
9
---
24
---
10
target/arm/vfp_helper.c | 8 ++++++++
25
docs/system/arm/nuvoton.rst | 2 +-
11
1 file changed, 8 insertions(+)
26
hw/usb/hcd-ehci.h | 1 +
27
include/hw/arm/npcm7xx.h | 4 ++++
28
hw/arm/npcm7xx.c | 27 +++++++++++++++++++++++++--
29
hw/usb/hcd-ehci-sysbus.c | 19 +++++++++++++++++++
30
5 files changed, 50 insertions(+), 3 deletions(-)
12
31
13
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
32
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
14
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/vfp_helper.c
34
--- a/docs/system/arm/nuvoton.rst
16
+++ b/target/arm/vfp_helper.c
35
+++ b/docs/system/arm/nuvoton.rst
17
@@ -XXX,XX +XXX,XX @@ void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
36
@@ -XXX,XX +XXX,XX @@ Supported devices
18
val &= ~FPCR_FZ16;
37
* OTP controllers (no protection features)
38
* Flash Interface Unit (FIU; no protection features)
39
* Random Number Generator (RNG)
40
+ * USB host (USBH)
41
42
Missing devices
43
---------------
44
@@ -XXX,XX +XXX,XX @@ Missing devices
45
* eSPI slave interface
46
47
* Ethernet controllers (GMAC and EMC)
48
- * USB host (USBH)
49
* USB device (USBD)
50
* SMBus controller (SMBF)
51
* Peripheral SPI controller (PSPI)
52
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
53
index XXXXXXX..XXXXXXX 100644
54
--- a/hw/usb/hcd-ehci.h
55
+++ b/hw/usb/hcd-ehci.h
56
@@ -XXX,XX +XXX,XX @@ struct EHCIPCIState {
57
#define TYPE_PLATFORM_EHCI "platform-ehci-usb"
58
#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
59
#define TYPE_AW_H3_EHCI "aw-h3-ehci-usb"
60
+#define TYPE_NPCM7XX_EHCI "npcm7xx-ehci-usb"
61
#define TYPE_TEGRA2_EHCI "tegra2-ehci-usb"
62
#define TYPE_PPC4xx_EHCI "ppc4xx-ehci-usb"
63
#define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb"
64
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
65
index XXXXXXX..XXXXXXX 100644
66
--- a/include/hw/arm/npcm7xx.h
67
+++ b/include/hw/arm/npcm7xx.h
68
@@ -XXX,XX +XXX,XX @@
69
#include "hw/nvram/npcm7xx_otp.h"
70
#include "hw/timer/npcm7xx_timer.h"
71
#include "hw/ssi/npcm7xx_fiu.h"
72
+#include "hw/usb/hcd-ehci.h"
73
+#include "hw/usb/hcd-ohci.h"
74
#include "target/arm/cpu.h"
75
76
#define NPCM7XX_MAX_NUM_CPUS (2)
77
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
78
NPCM7xxOTPState fuse_array;
79
NPCM7xxMCState mc;
80
NPCM7xxRNGState rng;
81
+ EHCISysBusState ehci;
82
+ OHCISysBusState ohci;
83
NPCM7xxFIUState fiu[2];
84
} NPCM7xxState;
85
86
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/hw/arm/npcm7xx.c
89
+++ b/hw/arm/npcm7xx.c
90
@@ -XXX,XX +XXX,XX @@
91
#define NPCM7XX_MC_BA (0xf0824000)
92
#define NPCM7XX_RNG_BA (0xf000b000)
93
94
+/* USB Host modules */
95
+#define NPCM7XX_EHCI_BA (0xf0806000)
96
+#define NPCM7XX_OHCI_BA (0xf0807000)
97
+
98
/* Internal AHB SRAM */
99
#define NPCM7XX_RAM3_BA (0xc0008000)
100
#define NPCM7XX_RAM3_SZ (4 * KiB)
101
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
102
NPCM7XX_WDG0_IRQ = 47, /* Timer Module 0 Watchdog */
103
NPCM7XX_WDG1_IRQ, /* Timer Module 1 Watchdog */
104
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
105
+ NPCM7XX_EHCI_IRQ = 61,
106
+ NPCM7XX_OHCI_IRQ = 62,
107
};
108
109
/* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */
110
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
111
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
19
}
112
}
20
113
21
+ if (arm_feature(env, ARM_FEATURE_M)) {
114
+ object_initialize_child(obj, "ehci", &s->ehci, TYPE_NPCM7XX_EHCI);
22
+ /*
115
+ object_initialize_child(obj, "ohci", &s->ohci, TYPE_SYSBUS_OHCI);
23
+ * M profile FPSCR is RES0 for the QC, STRIDE, FZ16, LEN bits
116
+
24
+ * and also for the trapped-exception-handling bits IxE.
117
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu));
25
+ */
118
for (i = 0; i < ARRAY_SIZE(s->fiu); i++) {
26
+ val &= 0xf7c0009f;
119
object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i],
27
+ }
120
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
121
sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
122
sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA);
123
124
+ /* USB Host */
125
+ object_property_set_bool(OBJECT(&s->ehci), "companion-enable", true,
126
+ &error_abort);
127
+ sysbus_realize(SYS_BUS_DEVICE(&s->ehci), &error_abort);
128
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci), 0, NPCM7XX_EHCI_BA);
129
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci), 0,
130
+ npcm7xx_irq(s, NPCM7XX_EHCI_IRQ));
131
+
132
+ object_property_set_str(OBJECT(&s->ohci), "masterbus", "usb-bus.0",
133
+ &error_abort);
134
+ object_property_set_uint(OBJECT(&s->ohci), "num-ports", 1, &error_abort);
135
+ sysbus_realize(SYS_BUS_DEVICE(&s->ohci), &error_abort);
136
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ohci), 0, NPCM7XX_OHCI_BA);
137
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0,
138
+ npcm7xx_irq(s, NPCM7XX_OHCI_IRQ));
28
+
139
+
29
/*
140
/*
30
* We don't implement trapped exception handling, so the
141
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
31
* trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
142
* specified, but this is a programming error.
143
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
144
create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB);
145
create_unimplemented_device("npcm7xx.gmac1", 0xf0802000, 8 * KiB);
146
create_unimplemented_device("npcm7xx.gmac2", 0xf0804000, 8 * KiB);
147
- create_unimplemented_device("npcm7xx.ehci", 0xf0806000, 4 * KiB);
148
- create_unimplemented_device("npcm7xx.ohci", 0xf0807000, 4 * KiB);
149
create_unimplemented_device("npcm7xx.vcd", 0xf0810000, 64 * KiB);
150
create_unimplemented_device("npcm7xx.ece", 0xf0820000, 8 * KiB);
151
create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB);
152
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
153
index XXXXXXX..XXXXXXX 100644
154
--- a/hw/usb/hcd-ehci-sysbus.c
155
+++ b/hw/usb/hcd-ehci-sysbus.c
156
@@ -XXX,XX +XXX,XX @@ static const TypeInfo ehci_aw_h3_type_info = {
157
.class_init = ehci_aw_h3_class_init,
158
};
159
160
+static void ehci_npcm7xx_class_init(ObjectClass *oc, void *data)
161
+{
162
+ SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
163
+ DeviceClass *dc = DEVICE_CLASS(oc);
164
+
165
+ sec->capsbase = 0x0;
166
+ sec->opregbase = 0x10;
167
+ sec->portscbase = 0x44;
168
+ sec->portnr = 1;
169
+ set_bit(DEVICE_CATEGORY_USB, dc->categories);
170
+}
171
+
172
+static const TypeInfo ehci_npcm7xx_type_info = {
173
+ .name = TYPE_NPCM7XX_EHCI,
174
+ .parent = TYPE_SYS_BUS_EHCI,
175
+ .class_init = ehci_npcm7xx_class_init,
176
+};
177
+
178
static void ehci_tegra2_class_init(ObjectClass *oc, void *data)
179
{
180
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
181
@@ -XXX,XX +XXX,XX @@ static void ehci_sysbus_register_types(void)
182
type_register_static(&ehci_platform_type_info);
183
type_register_static(&ehci_exynos4210_type_info);
184
type_register_static(&ehci_aw_h3_type_info);
185
+ type_register_static(&ehci_npcm7xx_type_info);
186
type_register_static(&ehci_tegra2_type_info);
187
type_register_static(&ehci_ppc4xx_type_info);
188
type_register_static(&ehci_fusbh200_type_info);
32
--
189
--
33
2.20.1
190
2.20.1
34
191
35
192
diff view generated by jsdifflib
1
In the v7M architecture, if an exception is generated in the process
1
From: Havard Skinnemoen <hskinnemoen@google.com>
2
of doing the lazy stacking of FP registers, the handling of
3
possible escalation to HardFault is treated differently to the normal
4
approach: it works based on the saved information about exception
5
readiness that was stored in the FPCCR when the stack frame was
6
created. Provide a new function armv7m_nvic_set_pending_lazyfp()
7
which pends exceptions during lazy stacking, and implements
8
this logic.
9
2
10
This corresponds to the pseudocode TakePreserveFPException().
3
The NPCM7xx chips have multiple GPIO controllers that are mostly
4
identical except for some minor differences like the reset values of
5
some registers. Each controller controls up to 32 pins.
11
6
7
Each individual pin is modeled as a pair of unnamed GPIOs -- one for
8
emitting the actual pin state, and one for driving the pin externally.
9
Like the nRF51 GPIO controller, a gpio level may be negative, which
10
means the pin is not driven, or floating.
11
12
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
13
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
14
Message-id: 20190416125744.27770-22-peter.maydell@linaro.org
15
---
16
---
16
target/arm/cpu.h | 12 ++++++
17
docs/system/arm/nuvoton.rst | 2 +-
17
hw/intc/armv7m_nvic.c | 96 +++++++++++++++++++++++++++++++++++++++++++
18
include/hw/arm/npcm7xx.h | 2 +
18
2 files changed, 108 insertions(+)
19
include/hw/gpio/npcm7xx_gpio.h | 55 +++++
20
hw/arm/npcm7xx.c | 80 ++++++
21
hw/gpio/npcm7xx_gpio.c | 424 ++++++++++++++++++++++++++++++++
22
tests/qtest/npcm7xx_gpio-test.c | 385 +++++++++++++++++++++++++++++
23
hw/gpio/meson.build | 1 +
24
hw/gpio/trace-events | 7 +
25
tests/qtest/meson.build | 3 +-
26
9 files changed, 957 insertions(+), 2 deletions(-)
27
create mode 100644 include/hw/gpio/npcm7xx_gpio.h
28
create mode 100644 hw/gpio/npcm7xx_gpio.c
29
create mode 100644 tests/qtest/npcm7xx_gpio-test.c
19
30
20
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
31
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
21
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
22
--- a/target/arm/cpu.h
33
--- a/docs/system/arm/nuvoton.rst
23
+++ b/target/arm/cpu.h
34
+++ b/docs/system/arm/nuvoton.rst
24
@@ -XXX,XX +XXX,XX @@ void armv7m_nvic_set_pending(void *opaque, int irq, bool secure);
35
@@ -XXX,XX +XXX,XX @@ Supported devices
25
* a different exception).
36
* Flash Interface Unit (FIU; no protection features)
26
*/
37
* Random Number Generator (RNG)
27
void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure);
38
* USB host (USBH)
28
+/**
39
+ * GPIO controller
29
+ * armv7m_nvic_set_pending_lazyfp: mark this lazy FP exception as pending
40
30
+ * @opaque: the NVIC
41
Missing devices
31
+ * @irq: the exception number to mark pending
42
---------------
32
+ * @secure: false for non-banked exceptions or for the nonsecure
43
33
+ * version of a banked exception, true for the secure version of a banked
44
- * GPIO controller
34
+ * exception.
45
* LPC/eSPI host-to-BMC interface, including
46
47
* Keyboard and mouse controller interface (KBCI)
48
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
49
index XXXXXXX..XXXXXXX 100644
50
--- a/include/hw/arm/npcm7xx.h
51
+++ b/include/hw/arm/npcm7xx.h
52
@@ -XXX,XX +XXX,XX @@
53
54
#include "hw/boards.h"
55
#include "hw/cpu/a9mpcore.h"
56
+#include "hw/gpio/npcm7xx_gpio.h"
57
#include "hw/mem/npcm7xx_mc.h"
58
#include "hw/misc/npcm7xx_clk.h"
59
#include "hw/misc/npcm7xx_gcr.h"
60
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
61
NPCM7xxOTPState fuse_array;
62
NPCM7xxMCState mc;
63
NPCM7xxRNGState rng;
64
+ NPCM7xxGPIOState gpio[8];
65
EHCISysBusState ehci;
66
OHCISysBusState ohci;
67
NPCM7xxFIUState fiu[2];
68
diff --git a/include/hw/gpio/npcm7xx_gpio.h b/include/hw/gpio/npcm7xx_gpio.h
69
new file mode 100644
70
index XXXXXXX..XXXXXXX
71
--- /dev/null
72
+++ b/include/hw/gpio/npcm7xx_gpio.h
73
@@ -XXX,XX +XXX,XX @@
74
+/*
75
+ * Nuvoton NPCM7xx General Purpose Input / Output (GPIO)
35
+ *
76
+ *
36
+ * Similar to armv7m_nvic_set_pending(), but specifically for exceptions
77
+ * Copyright 2020 Google LLC
37
+ * generated in the course of lazy stacking of FP registers.
78
+ *
79
+ * This program is free software; you can redistribute it and/or
80
+ * modify it under the terms of the GNU General Public License
81
+ * version 2 as published by the Free Software Foundation.
82
+ *
83
+ * This program is distributed in the hope that it will be useful,
84
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
85
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
86
+ * GNU General Public License for more details.
38
+ */
87
+ */
39
+void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure);
88
+#ifndef NPCM7XX_GPIO_H
40
/**
89
+#define NPCM7XX_GPIO_H
41
* armv7m_nvic_get_pending_irq_info: return highest priority pending
90
+
42
* exception, and whether it targets Secure state
91
+#include "exec/memory.h"
43
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
92
+#include "hw/sysbus.h"
93
+
94
+/* Number of pins managed by each controller. */
95
+#define NPCM7XX_GPIO_NR_PINS (32)
96
+
97
+/*
98
+ * Number of registers in our device state structure. Don't change this without
99
+ * incrementing the version_id in the vmstate.
100
+ */
101
+#define NPCM7XX_GPIO_NR_REGS (0x80 / sizeof(uint32_t))
102
+
103
+typedef struct NPCM7xxGPIOState {
104
+ SysBusDevice parent;
105
+
106
+ /* Properties to be defined by the SoC */
107
+ uint32_t reset_pu;
108
+ uint32_t reset_pd;
109
+ uint32_t reset_osrc;
110
+ uint32_t reset_odsc;
111
+
112
+ MemoryRegion mmio;
113
+
114
+ qemu_irq irq;
115
+ qemu_irq output[NPCM7XX_GPIO_NR_PINS];
116
+
117
+ uint32_t pin_level;
118
+ uint32_t ext_level;
119
+ uint32_t ext_driven;
120
+
121
+ uint32_t regs[NPCM7XX_GPIO_NR_REGS];
122
+} NPCM7xxGPIOState;
123
+
124
+#define TYPE_NPCM7XX_GPIO "npcm7xx-gpio"
125
+#define NPCM7XX_GPIO(obj) \
126
+ OBJECT_CHECK(NPCM7xxGPIOState, (obj), TYPE_NPCM7XX_GPIO)
127
+
128
+#endif /* NPCM7XX_GPIO_H */
129
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
44
index XXXXXXX..XXXXXXX 100644
130
index XXXXXXX..XXXXXXX 100644
45
--- a/hw/intc/armv7m_nvic.c
131
--- a/hw/arm/npcm7xx.c
46
+++ b/hw/intc/armv7m_nvic.c
132
+++ b/hw/arm/npcm7xx.c
47
@@ -XXX,XX +XXX,XX @@ void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure)
133
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
48
do_armv7m_nvic_set_pending(opaque, irq, secure, true);
134
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
49
}
135
NPCM7XX_EHCI_IRQ = 61,
50
136
NPCM7XX_OHCI_IRQ = 62,
51
+void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure)
137
+ NPCM7XX_GPIO0_IRQ = 116,
52
+{
138
+ NPCM7XX_GPIO1_IRQ,
139
+ NPCM7XX_GPIO2_IRQ,
140
+ NPCM7XX_GPIO3_IRQ,
141
+ NPCM7XX_GPIO4_IRQ,
142
+ NPCM7XX_GPIO5_IRQ,
143
+ NPCM7XX_GPIO6_IRQ,
144
+ NPCM7XX_GPIO7_IRQ,
145
};
146
147
/* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */
148
@@ -XXX,XX +XXX,XX @@ static const hwaddr npcm7xx_fiu3_flash_addr[] = {
149
0xb8000000, /* CS3 */
150
};
151
152
+static const struct {
153
+ hwaddr regs_addr;
154
+ uint32_t unconnected_pins;
155
+ uint32_t reset_pu;
156
+ uint32_t reset_pd;
157
+ uint32_t reset_osrc;
158
+ uint32_t reset_odsc;
159
+} npcm7xx_gpio[] = {
160
+ {
161
+ .regs_addr = 0xf0010000,
162
+ .reset_pu = 0xff03ffff,
163
+ .reset_pd = 0x00fc0000,
164
+ }, {
165
+ .regs_addr = 0xf0011000,
166
+ .unconnected_pins = 0x0000001e,
167
+ .reset_pu = 0xfefffe07,
168
+ .reset_pd = 0x010001e0,
169
+ }, {
170
+ .regs_addr = 0xf0012000,
171
+ .reset_pu = 0x780fffff,
172
+ .reset_pd = 0x07f00000,
173
+ .reset_odsc = 0x00700000,
174
+ }, {
175
+ .regs_addr = 0xf0013000,
176
+ .reset_pu = 0x00fc0000,
177
+ .reset_pd = 0xff000000,
178
+ }, {
179
+ .regs_addr = 0xf0014000,
180
+ .reset_pu = 0xffffffff,
181
+ }, {
182
+ .regs_addr = 0xf0015000,
183
+ .reset_pu = 0xbf83f801,
184
+ .reset_pd = 0x007c0000,
185
+ .reset_osrc = 0x000000f1,
186
+ .reset_odsc = 0x3f9f80f1,
187
+ }, {
188
+ .regs_addr = 0xf0016000,
189
+ .reset_pu = 0xfc00f801,
190
+ .reset_pd = 0x000007fe,
191
+ .reset_odsc = 0x00000800,
192
+ }, {
193
+ .regs_addr = 0xf0017000,
194
+ .unconnected_pins = 0xffffff00,
195
+ .reset_pu = 0x0000007f,
196
+ .reset_osrc = 0x0000007f,
197
+ .reset_odsc = 0x0000007f,
198
+ },
199
+};
200
+
201
static const struct {
202
const char *name;
203
hwaddr regs_addr;
204
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
205
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
206
}
207
208
+ for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
209
+ object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_NPCM7XX_GPIO);
210
+ }
211
+
212
object_initialize_child(obj, "ehci", &s->ehci, TYPE_NPCM7XX_EHCI);
213
object_initialize_child(obj, "ohci", &s->ohci, TYPE_SYSBUS_OHCI);
214
215
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
216
sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
217
sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA);
218
219
+ /* GPIO modules. Cannot fail. */
220
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_gpio) != ARRAY_SIZE(s->gpio));
221
+ for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
222
+ Object *obj = OBJECT(&s->gpio[i]);
223
+
224
+ object_property_set_uint(obj, "reset-pullup",
225
+ npcm7xx_gpio[i].reset_pu, &error_abort);
226
+ object_property_set_uint(obj, "reset-pulldown",
227
+ npcm7xx_gpio[i].reset_pd, &error_abort);
228
+ object_property_set_uint(obj, "reset-osrc",
229
+ npcm7xx_gpio[i].reset_osrc, &error_abort);
230
+ object_property_set_uint(obj, "reset-odsc",
231
+ npcm7xx_gpio[i].reset_odsc, &error_abort);
232
+ sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort);
233
+ sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm7xx_gpio[i].regs_addr);
234
+ sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0,
235
+ npcm7xx_irq(s, NPCM7XX_GPIO0_IRQ + i));
236
+ }
237
+
238
/* USB Host */
239
object_property_set_bool(OBJECT(&s->ehci), "companion-enable", true,
240
&error_abort);
241
diff --git a/hw/gpio/npcm7xx_gpio.c b/hw/gpio/npcm7xx_gpio.c
242
new file mode 100644
243
index XXXXXXX..XXXXXXX
244
--- /dev/null
245
+++ b/hw/gpio/npcm7xx_gpio.c
246
@@ -XXX,XX +XXX,XX @@
247
+/*
248
+ * Nuvoton NPCM7xx General Purpose Input / Output (GPIO)
249
+ *
250
+ * Copyright 2020 Google LLC
251
+ *
252
+ * This program is free software; you can redistribute it and/or
253
+ * modify it under the terms of the GNU General Public License
254
+ * version 2 as published by the Free Software Foundation.
255
+ *
256
+ * This program is distributed in the hope that it will be useful,
257
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
258
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
259
+ * GNU General Public License for more details.
260
+ */
261
+
262
+#include "qemu/osdep.h"
263
+
264
+#include "hw/gpio/npcm7xx_gpio.h"
265
+#include "hw/irq.h"
266
+#include "hw/qdev-properties.h"
267
+#include "migration/vmstate.h"
268
+#include "qapi/error.h"
269
+#include "qemu/log.h"
270
+#include "qemu/module.h"
271
+#include "qemu/units.h"
272
+#include "trace.h"
273
+
274
+/* 32-bit register indices. */
275
+enum NPCM7xxGPIORegister {
276
+ NPCM7XX_GPIO_TLOCK1,
277
+ NPCM7XX_GPIO_DIN,
278
+ NPCM7XX_GPIO_POL,
279
+ NPCM7XX_GPIO_DOUT,
280
+ NPCM7XX_GPIO_OE,
281
+ NPCM7XX_GPIO_OTYP,
282
+ NPCM7XX_GPIO_MP,
283
+ NPCM7XX_GPIO_PU,
284
+ NPCM7XX_GPIO_PD,
285
+ NPCM7XX_GPIO_DBNC,
286
+ NPCM7XX_GPIO_EVTYP,
287
+ NPCM7XX_GPIO_EVBE,
288
+ NPCM7XX_GPIO_OBL0,
289
+ NPCM7XX_GPIO_OBL1,
290
+ NPCM7XX_GPIO_OBL2,
291
+ NPCM7XX_GPIO_OBL3,
292
+ NPCM7XX_GPIO_EVEN,
293
+ NPCM7XX_GPIO_EVENS,
294
+ NPCM7XX_GPIO_EVENC,
295
+ NPCM7XX_GPIO_EVST,
296
+ NPCM7XX_GPIO_SPLCK,
297
+ NPCM7XX_GPIO_MPLCK,
298
+ NPCM7XX_GPIO_IEM,
299
+ NPCM7XX_GPIO_OSRC,
300
+ NPCM7XX_GPIO_ODSC,
301
+ NPCM7XX_GPIO_DOS = 0x68 / sizeof(uint32_t),
302
+ NPCM7XX_GPIO_DOC,
303
+ NPCM7XX_GPIO_OES,
304
+ NPCM7XX_GPIO_OEC,
305
+ NPCM7XX_GPIO_TLOCK2 = 0x7c / sizeof(uint32_t),
306
+ NPCM7XX_GPIO_REGS_END,
307
+};
308
+
309
+#define NPCM7XX_GPIO_REGS_SIZE (4 * KiB)
310
+
311
+#define NPCM7XX_GPIO_LOCK_MAGIC1 (0xc0defa73)
312
+#define NPCM7XX_GPIO_LOCK_MAGIC2 (0xc0de1248)
313
+
314
+static void npcm7xx_gpio_update_events(NPCM7xxGPIOState *s, uint32_t din_diff)
315
+{
316
+ uint32_t din_new = s->regs[NPCM7XX_GPIO_DIN];
317
+
318
+ /* Trigger on high level */
319
+ s->regs[NPCM7XX_GPIO_EVST] |= din_new & ~s->regs[NPCM7XX_GPIO_EVTYP];
320
+ /* Trigger on both edges */
321
+ s->regs[NPCM7XX_GPIO_EVST] |= (din_diff & s->regs[NPCM7XX_GPIO_EVTYP]
322
+ & s->regs[NPCM7XX_GPIO_EVBE]);
323
+ /* Trigger on rising edge */
324
+ s->regs[NPCM7XX_GPIO_EVST] |= (din_diff & din_new
325
+ & s->regs[NPCM7XX_GPIO_EVTYP]);
326
+
327
+ trace_npcm7xx_gpio_update_events(DEVICE(s)->canonical_path,
328
+ s->regs[NPCM7XX_GPIO_EVST],
329
+ s->regs[NPCM7XX_GPIO_EVEN]);
330
+ qemu_set_irq(s->irq, !!(s->regs[NPCM7XX_GPIO_EVST]
331
+ & s->regs[NPCM7XX_GPIO_EVEN]));
332
+}
333
+
334
+static void npcm7xx_gpio_update_pins(NPCM7xxGPIOState *s, uint32_t diff)
335
+{
336
+ uint32_t drive_en;
337
+ uint32_t drive_lvl;
338
+ uint32_t not_driven;
339
+ uint32_t undefined;
340
+ uint32_t pin_diff;
341
+ uint32_t din_old;
342
+
343
+ /* Calculate level of each pin driven by GPIO controller. */
344
+ drive_lvl = s->regs[NPCM7XX_GPIO_DOUT] ^ s->regs[NPCM7XX_GPIO_POL];
345
+ /* If OTYP=1, only drive low (open drain) */
346
+ drive_en = s->regs[NPCM7XX_GPIO_OE] & ~(s->regs[NPCM7XX_GPIO_OTYP]
347
+ & drive_lvl);
53
+ /*
348
+ /*
54
+ * Pend an exception during lazy FP stacking. This differs
349
+ * If a pin is driven to opposite levels by the GPIO controller and the
55
+ * from the usual exception pending because the logic for
350
+ * external driver, the result is undefined.
56
+ * whether we should escalate depends on the saved context
57
+ * in the FPCCR register, not on the current state of the CPU/NVIC.
58
+ */
351
+ */
59
+ NVICState *s = (NVICState *)opaque;
352
+ undefined = drive_en & s->ext_driven & (drive_lvl ^ s->ext_level);
60
+ bool banked = exc_is_banked(irq);
353
+ if (undefined) {
61
+ VecInfo *vec;
354
+ qemu_log_mask(LOG_GUEST_ERROR,
62
+ bool targets_secure;
355
+ "%s: pins have multiple drivers: 0x%" PRIx32 "\n",
63
+ bool escalate = false;
356
+ DEVICE(s)->canonical_path, undefined);
64
+ /*
65
+ * We will only look at bits in fpccr if this is a banked exception
66
+ * (in which case 'secure' tells us whether it is the S or NS version).
67
+ * All the bits for the non-banked exceptions are in fpccr_s.
68
+ */
69
+ uint32_t fpccr_s = s->cpu->env.v7m.fpccr[M_REG_S];
70
+ uint32_t fpccr = s->cpu->env.v7m.fpccr[secure];
71
+
72
+ assert(irq > ARMV7M_EXCP_RESET && irq < s->num_irq);
73
+ assert(!secure || banked);
74
+
75
+ vec = (banked && secure) ? &s->sec_vectors[irq] : &s->vectors[irq];
76
+
77
+ targets_secure = banked ? secure : exc_targets_secure(s, irq);
78
+
79
+ switch (irq) {
80
+ case ARMV7M_EXCP_DEBUG:
81
+ if (!(fpccr_s & R_V7M_FPCCR_MONRDY_MASK)) {
82
+ /* Ignore DebugMonitor exception */
83
+ return;
84
+ }
85
+ break;
86
+ case ARMV7M_EXCP_MEM:
87
+ escalate = !(fpccr & R_V7M_FPCCR_MMRDY_MASK);
88
+ break;
89
+ case ARMV7M_EXCP_USAGE:
90
+ escalate = !(fpccr & R_V7M_FPCCR_UFRDY_MASK);
91
+ break;
92
+ case ARMV7M_EXCP_BUS:
93
+ escalate = !(fpccr_s & R_V7M_FPCCR_BFRDY_MASK);
94
+ break;
95
+ case ARMV7M_EXCP_SECURE:
96
+ escalate = !(fpccr_s & R_V7M_FPCCR_SFRDY_MASK);
97
+ break;
98
+ default:
99
+ g_assert_not_reached();
100
+ }
357
+ }
101
+
358
+
102
+ if (escalate) {
359
+ not_driven = ~(drive_en | s->ext_driven);
103
+ /*
360
+ pin_diff = s->pin_level;
104
+ * Escalate to HardFault: faults that initially targeted Secure
361
+
105
+ * continue to do so, even if HF normally targets NonSecure.
362
+ /* Set pins to externally driven level. */
106
+ */
363
+ s->pin_level = s->ext_level & s->ext_driven;
107
+ irq = ARMV7M_EXCP_HARD;
364
+ /* Set internally driven pins, ignoring any conflicts. */
108
+ if (arm_feature(&s->cpu->env, ARM_FEATURE_M_SECURITY) &&
365
+ s->pin_level |= drive_lvl & drive_en;
109
+ (targets_secure ||
366
+ /* Pull up undriven pins with internal pull-up enabled. */
110
+ !(s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK))) {
367
+ s->pin_level |= not_driven & s->regs[NPCM7XX_GPIO_PU];
111
+ vec = &s->sec_vectors[irq];
368
+ /* Pins not driven, pulled up or pulled down are undefined */
112
+ } else {
369
+ undefined |= not_driven & ~(s->regs[NPCM7XX_GPIO_PU]
113
+ vec = &s->vectors[irq];
370
+ | s->regs[NPCM7XX_GPIO_PD]);
371
+
372
+ /* If any pins changed state, update the outgoing GPIOs. */
373
+ pin_diff ^= s->pin_level;
374
+ pin_diff |= undefined & diff;
375
+ if (pin_diff) {
376
+ int i;
377
+
378
+ for (i = 0; i < NPCM7XX_GPIO_NR_PINS; i++) {
379
+ uint32_t mask = BIT(i);
380
+ if (pin_diff & mask) {
381
+ int level = (undefined & mask) ? -1 : !!(s->pin_level & mask);
382
+ trace_npcm7xx_gpio_set_output(DEVICE(s)->canonical_path,
383
+ i, level);
384
+ qemu_set_irq(s->output[i], level);
385
+ }
114
+ }
386
+ }
115
+ }
387
+ }
116
+
388
+
117
+ if (!vec->enabled ||
389
+ /* Calculate new value of DIN after masking and polarity setting. */
118
+ nvic_exec_prio(s) <= exc_group_prio(s, vec->prio, secure)) {
390
+ din_old = s->regs[NPCM7XX_GPIO_DIN];
119
+ if (!(fpccr_s & R_V7M_FPCCR_HFRDY_MASK)) {
391
+ s->regs[NPCM7XX_GPIO_DIN] = ((s->pin_level & s->regs[NPCM7XX_GPIO_IEM])
120
+ /*
392
+ ^ s->regs[NPCM7XX_GPIO_POL]);
121
+ * We want to escalate to HardFault but the context the
393
+
122
+ * FP state belongs to prevents the exception pre-empting.
394
+ /* See if any new events triggered because of all this. */
123
+ */
395
+ npcm7xx_gpio_update_events(s, din_old ^ s->regs[NPCM7XX_GPIO_DIN]);
124
+ cpu_abort(&s->cpu->parent_obj,
396
+}
125
+ "Lockup: can't escalate to HardFault during "
397
+
126
+ "lazy FP register stacking\n");
398
+static bool npcm7xx_gpio_is_locked(NPCM7xxGPIOState *s)
399
+{
400
+ return s->regs[NPCM7XX_GPIO_TLOCK1] == 1;
401
+}
402
+
403
+static uint64_t npcm7xx_gpio_regs_read(void *opaque, hwaddr addr,
404
+ unsigned int size)
405
+{
406
+ hwaddr reg = addr / sizeof(uint32_t);
407
+ NPCM7xxGPIOState *s = opaque;
408
+ uint64_t value = 0;
409
+
410
+ switch (reg) {
411
+ case NPCM7XX_GPIO_TLOCK1 ... NPCM7XX_GPIO_EVEN:
412
+ case NPCM7XX_GPIO_EVST ... NPCM7XX_GPIO_ODSC:
413
+ value = s->regs[reg];
414
+ break;
415
+
416
+ case NPCM7XX_GPIO_EVENS ... NPCM7XX_GPIO_EVENC:
417
+ case NPCM7XX_GPIO_DOS ... NPCM7XX_GPIO_TLOCK2:
418
+ qemu_log_mask(LOG_GUEST_ERROR,
419
+ "%s: read from write-only register 0x%" HWADDR_PRIx "\n",
420
+ DEVICE(s)->canonical_path, addr);
421
+ break;
422
+
423
+ default:
424
+ qemu_log_mask(LOG_GUEST_ERROR,
425
+ "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
426
+ DEVICE(s)->canonical_path, addr);
427
+ break;
428
+ }
429
+
430
+ trace_npcm7xx_gpio_read(DEVICE(s)->canonical_path, addr, value);
431
+
432
+ return value;
433
+}
434
+
435
+static void npcm7xx_gpio_regs_write(void *opaque, hwaddr addr, uint64_t v,
436
+ unsigned int size)
437
+{
438
+ hwaddr reg = addr / sizeof(uint32_t);
439
+ NPCM7xxGPIOState *s = opaque;
440
+ uint32_t value = v;
441
+ uint32_t diff;
442
+
443
+ trace_npcm7xx_gpio_write(DEVICE(s)->canonical_path, addr, v);
444
+
445
+ if (npcm7xx_gpio_is_locked(s)) {
446
+ switch (reg) {
447
+ case NPCM7XX_GPIO_TLOCK1:
448
+ if (s->regs[NPCM7XX_GPIO_TLOCK2] == NPCM7XX_GPIO_LOCK_MAGIC2 &&
449
+ value == NPCM7XX_GPIO_LOCK_MAGIC1) {
450
+ s->regs[NPCM7XX_GPIO_TLOCK1] = 0;
451
+ s->regs[NPCM7XX_GPIO_TLOCK2] = 0;
452
+ }
453
+ break;
454
+
455
+ case NPCM7XX_GPIO_TLOCK2:
456
+ s->regs[reg] = value;
457
+ break;
458
+
459
+ default:
460
+ qemu_log_mask(LOG_GUEST_ERROR,
461
+ "%s: write to locked register @ 0x%" HWADDR_PRIx "\n",
462
+ DEVICE(s)->canonical_path, addr);
463
+ break;
127
+ }
464
+ }
465
+
466
+ return;
128
+ }
467
+ }
129
+
468
+
130
+ if (escalate) {
469
+ diff = s->regs[reg] ^ value;
131
+ s->cpu->env.v7m.hfsr |= R_V7M_HFSR_FORCED_MASK;
470
+
471
+ switch (reg) {
472
+ case NPCM7XX_GPIO_TLOCK1:
473
+ case NPCM7XX_GPIO_TLOCK2:
474
+ s->regs[NPCM7XX_GPIO_TLOCK1] = 1;
475
+ s->regs[NPCM7XX_GPIO_TLOCK2] = 0;
476
+ break;
477
+
478
+ case NPCM7XX_GPIO_DIN:
479
+ qemu_log_mask(LOG_GUEST_ERROR,
480
+ "%s: write to read-only register @ 0x%" HWADDR_PRIx "\n",
481
+ DEVICE(s)->canonical_path, addr);
482
+ break;
483
+
484
+ case NPCM7XX_GPIO_POL:
485
+ case NPCM7XX_GPIO_DOUT:
486
+ case NPCM7XX_GPIO_OE:
487
+ case NPCM7XX_GPIO_OTYP:
488
+ case NPCM7XX_GPIO_PU:
489
+ case NPCM7XX_GPIO_PD:
490
+ case NPCM7XX_GPIO_IEM:
491
+ s->regs[reg] = value;
492
+ npcm7xx_gpio_update_pins(s, diff);
493
+ break;
494
+
495
+ case NPCM7XX_GPIO_DOS:
496
+ s->regs[NPCM7XX_GPIO_DOUT] |= value;
497
+ npcm7xx_gpio_update_pins(s, value);
498
+ break;
499
+ case NPCM7XX_GPIO_DOC:
500
+ s->regs[NPCM7XX_GPIO_DOUT] &= ~value;
501
+ npcm7xx_gpio_update_pins(s, value);
502
+ break;
503
+ case NPCM7XX_GPIO_OES:
504
+ s->regs[NPCM7XX_GPIO_OE] |= value;
505
+ npcm7xx_gpio_update_pins(s, value);
506
+ break;
507
+ case NPCM7XX_GPIO_OEC:
508
+ s->regs[NPCM7XX_GPIO_OE] &= ~value;
509
+ npcm7xx_gpio_update_pins(s, value);
510
+ break;
511
+
512
+ case NPCM7XX_GPIO_EVTYP:
513
+ case NPCM7XX_GPIO_EVBE:
514
+ case NPCM7XX_GPIO_EVEN:
515
+ s->regs[reg] = value;
516
+ npcm7xx_gpio_update_events(s, 0);
517
+ break;
518
+
519
+ case NPCM7XX_GPIO_EVENS:
520
+ s->regs[NPCM7XX_GPIO_EVEN] |= value;
521
+ npcm7xx_gpio_update_events(s, 0);
522
+ break;
523
+ case NPCM7XX_GPIO_EVENC:
524
+ s->regs[NPCM7XX_GPIO_EVEN] &= ~value;
525
+ npcm7xx_gpio_update_events(s, 0);
526
+ break;
527
+
528
+ case NPCM7XX_GPIO_EVST:
529
+ s->regs[reg] &= ~value;
530
+ npcm7xx_gpio_update_events(s, 0);
531
+ break;
532
+
533
+ case NPCM7XX_GPIO_MP:
534
+ case NPCM7XX_GPIO_DBNC:
535
+ case NPCM7XX_GPIO_OSRC:
536
+ case NPCM7XX_GPIO_ODSC:
537
+ /* Nothing to do; just store the value. */
538
+ s->regs[reg] = value;
539
+ break;
540
+
541
+ case NPCM7XX_GPIO_OBL0:
542
+ case NPCM7XX_GPIO_OBL1:
543
+ case NPCM7XX_GPIO_OBL2:
544
+ case NPCM7XX_GPIO_OBL3:
545
+ s->regs[reg] = value;
546
+ qemu_log_mask(LOG_UNIMP, "%s: Blinking is not implemented\n",
547
+ __func__);
548
+ break;
549
+
550
+ case NPCM7XX_GPIO_SPLCK:
551
+ case NPCM7XX_GPIO_MPLCK:
552
+ qemu_log_mask(LOG_UNIMP, "%s: Per-pin lock is not implemented\n",
553
+ __func__);
554
+ break;
555
+
556
+ default:
557
+ qemu_log_mask(LOG_GUEST_ERROR,
558
+ "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
559
+ DEVICE(s)->canonical_path, addr);
560
+ break;
132
+ }
561
+ }
133
+ if (!vec->pending) {
562
+}
134
+ vec->pending = 1;
563
+
135
+ /*
564
+static const MemoryRegionOps npcm7xx_gpio_regs_ops = {
136
+ * We do not call nvic_irq_update(), because we know our caller
565
+ .read = npcm7xx_gpio_regs_read,
137
+ * is going to handle causing us to take the exception by
566
+ .write = npcm7xx_gpio_regs_write,
138
+ * raising EXCP_LAZYFP, so raising the IRQ line would be
567
+ .endianness = DEVICE_NATIVE_ENDIAN,
139
+ * pointless extra work. We just need to recompute the
568
+ .valid = {
140
+ * priorities so that armv7m_nvic_can_take_pending_exception()
569
+ .min_access_size = 4,
141
+ * returns the right answer.
570
+ .max_access_size = 4,
142
+ */
571
+ .unaligned = false,
143
+ nvic_recompute_state(s);
572
+ },
573
+};
574
+
575
+static void npcm7xx_gpio_set_input(void *opaque, int line, int level)
576
+{
577
+ NPCM7xxGPIOState *s = opaque;
578
+
579
+ trace_npcm7xx_gpio_set_input(DEVICE(s)->canonical_path, line, level);
580
+
581
+ g_assert(line >= 0 && line < NPCM7XX_GPIO_NR_PINS);
582
+
583
+ s->ext_driven = deposit32(s->ext_driven, line, 1, level >= 0);
584
+ s->ext_level = deposit32(s->ext_level, line, 1, level > 0);
585
+
586
+ npcm7xx_gpio_update_pins(s, BIT(line));
587
+}
588
+
589
+static void npcm7xx_gpio_enter_reset(Object *obj, ResetType type)
590
+{
591
+ NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
592
+
593
+ memset(s->regs, 0, sizeof(s->regs));
594
+
595
+ s->regs[NPCM7XX_GPIO_PU] = s->reset_pu;
596
+ s->regs[NPCM7XX_GPIO_PD] = s->reset_pd;
597
+ s->regs[NPCM7XX_GPIO_OSRC] = s->reset_osrc;
598
+ s->regs[NPCM7XX_GPIO_ODSC] = s->reset_odsc;
599
+}
600
+
601
+static void npcm7xx_gpio_hold_reset(Object *obj)
602
+{
603
+ NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
604
+
605
+ npcm7xx_gpio_update_pins(s, -1);
606
+}
607
+
608
+static void npcm7xx_gpio_init(Object *obj)
609
+{
610
+ NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
611
+ DeviceState *dev = DEVICE(obj);
612
+
613
+ memory_region_init_io(&s->mmio, obj, &npcm7xx_gpio_regs_ops, s,
614
+ "regs", NPCM7XX_GPIO_REGS_SIZE);
615
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
616
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
617
+
618
+ qdev_init_gpio_in(dev, npcm7xx_gpio_set_input, NPCM7XX_GPIO_NR_PINS);
619
+ qdev_init_gpio_out(dev, s->output, NPCM7XX_GPIO_NR_PINS);
620
+}
621
+
622
+static const VMStateDescription vmstate_npcm7xx_gpio = {
623
+ .name = "npcm7xx-gpio",
624
+ .version_id = 0,
625
+ .minimum_version_id = 0,
626
+ .fields = (VMStateField[]) {
627
+ VMSTATE_UINT32(pin_level, NPCM7xxGPIOState),
628
+ VMSTATE_UINT32(ext_level, NPCM7xxGPIOState),
629
+ VMSTATE_UINT32(ext_driven, NPCM7xxGPIOState),
630
+ VMSTATE_UINT32_ARRAY(regs, NPCM7xxGPIOState, NPCM7XX_GPIO_NR_REGS),
631
+ VMSTATE_END_OF_LIST(),
632
+ },
633
+};
634
+
635
+static Property npcm7xx_gpio_properties[] = {
636
+ /* Bit n set => pin n has pullup enabled by default. */
637
+ DEFINE_PROP_UINT32("reset-pullup", NPCM7xxGPIOState, reset_pu, 0),
638
+ /* Bit n set => pin n has pulldown enabled by default. */
639
+ DEFINE_PROP_UINT32("reset-pulldown", NPCM7xxGPIOState, reset_pd, 0),
640
+ /* Bit n set => pin n has high slew rate by default. */
641
+ DEFINE_PROP_UINT32("reset-osrc", NPCM7xxGPIOState, reset_osrc, 0),
642
+ /* Bit n set => pin n has high drive strength by default. */
643
+ DEFINE_PROP_UINT32("reset-odsc", NPCM7xxGPIOState, reset_odsc, 0),
644
+ DEFINE_PROP_END_OF_LIST(),
645
+};
646
+
647
+static void npcm7xx_gpio_class_init(ObjectClass *klass, void *data)
648
+{
649
+ ResettableClass *reset = RESETTABLE_CLASS(klass);
650
+ DeviceClass *dc = DEVICE_CLASS(klass);
651
+
652
+ QEMU_BUILD_BUG_ON(NPCM7XX_GPIO_REGS_END > NPCM7XX_GPIO_NR_REGS);
653
+
654
+ dc->desc = "NPCM7xx GPIO Controller";
655
+ dc->vmsd = &vmstate_npcm7xx_gpio;
656
+ reset->phases.enter = npcm7xx_gpio_enter_reset;
657
+ reset->phases.hold = npcm7xx_gpio_hold_reset;
658
+ device_class_set_props(dc, npcm7xx_gpio_properties);
659
+}
660
+
661
+static const TypeInfo npcm7xx_gpio_types[] = {
662
+ {
663
+ .name = TYPE_NPCM7XX_GPIO,
664
+ .parent = TYPE_SYS_BUS_DEVICE,
665
+ .instance_size = sizeof(NPCM7xxGPIOState),
666
+ .class_init = npcm7xx_gpio_class_init,
667
+ .instance_init = npcm7xx_gpio_init,
668
+ },
669
+};
670
+DEFINE_TYPES(npcm7xx_gpio_types);
671
diff --git a/tests/qtest/npcm7xx_gpio-test.c b/tests/qtest/npcm7xx_gpio-test.c
672
new file mode 100644
673
index XXXXXXX..XXXXXXX
674
--- /dev/null
675
+++ b/tests/qtest/npcm7xx_gpio-test.c
676
@@ -XXX,XX +XXX,XX @@
677
+/*
678
+ * QTest testcase for the Nuvoton NPCM7xx GPIO modules.
679
+ *
680
+ * Copyright 2020 Google LLC
681
+ *
682
+ * This program is free software; you can redistribute it and/or modify it
683
+ * under the terms of the GNU General Public License as published by the
684
+ * Free Software Foundation; either version 2 of the License, or
685
+ * (at your option) any later version.
686
+ *
687
+ * This program is distributed in the hope that it will be useful, but WITHOUT
688
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
689
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
690
+ * for more details.
691
+ */
692
+
693
+#include "qemu/osdep.h"
694
+#include "libqtest-single.h"
695
+
696
+#define NR_GPIO_DEVICES (8)
697
+#define GPIO(x) (0xf0010000 + (x) * 0x1000)
698
+#define GPIO_IRQ(x) (116 + (x))
699
+
700
+/* GPIO registers */
701
+#define GP_N_TLOCK1 0x00
702
+#define GP_N_DIN 0x04 /* Data IN */
703
+#define GP_N_POL 0x08 /* Polarity */
704
+#define GP_N_DOUT 0x0c /* Data OUT */
705
+#define GP_N_OE 0x10 /* Output Enable */
706
+#define GP_N_OTYP 0x14
707
+#define GP_N_MP 0x18
708
+#define GP_N_PU 0x1c /* Pull-up */
709
+#define GP_N_PD 0x20 /* Pull-down */
710
+#define GP_N_DBNC 0x24 /* Debounce */
711
+#define GP_N_EVTYP 0x28 /* Event Type */
712
+#define GP_N_EVBE 0x2c /* Event Both Edge */
713
+#define GP_N_OBL0 0x30
714
+#define GP_N_OBL1 0x34
715
+#define GP_N_OBL2 0x38
716
+#define GP_N_OBL3 0x3c
717
+#define GP_N_EVEN 0x40 /* Event Enable */
718
+#define GP_N_EVENS 0x44 /* Event Set (enable) */
719
+#define GP_N_EVENC 0x48 /* Event Clear (disable) */
720
+#define GP_N_EVST 0x4c /* Event Status */
721
+#define GP_N_SPLCK 0x50
722
+#define GP_N_MPLCK 0x54
723
+#define GP_N_IEM 0x58 /* Input Enable */
724
+#define GP_N_OSRC 0x5c
725
+#define GP_N_ODSC 0x60
726
+#define GP_N_DOS 0x68 /* Data OUT Set */
727
+#define GP_N_DOC 0x6c /* Data OUT Clear */
728
+#define GP_N_OES 0x70 /* Output Enable Set */
729
+#define GP_N_OEC 0x74 /* Output Enable Clear */
730
+#define GP_N_TLOCK2 0x7c
731
+
732
+static void gpio_unlock(int n)
733
+{
734
+ if (readl(GPIO(n) + GP_N_TLOCK1) != 0) {
735
+ writel(GPIO(n) + GP_N_TLOCK2, 0xc0de1248);
736
+ writel(GPIO(n) + GP_N_TLOCK1, 0xc0defa73);
144
+ }
737
+ }
145
+}
738
+}
146
+
739
+
147
/* Make pending IRQ active. */
740
+/* Restore the GPIO controller to a sensible default state. */
148
void armv7m_nvic_acknowledge_irq(void *opaque)
741
+static void gpio_reset(int n)
149
{
742
+{
743
+ gpio_unlock(0);
744
+
745
+ writel(GPIO(n) + GP_N_EVEN, 0x00000000);
746
+ writel(GPIO(n) + GP_N_EVST, 0xffffffff);
747
+ writel(GPIO(n) + GP_N_POL, 0x00000000);
748
+ writel(GPIO(n) + GP_N_DOUT, 0x00000000);
749
+ writel(GPIO(n) + GP_N_OE, 0x00000000);
750
+ writel(GPIO(n) + GP_N_OTYP, 0x00000000);
751
+ writel(GPIO(n) + GP_N_PU, 0xffffffff);
752
+ writel(GPIO(n) + GP_N_PD, 0x00000000);
753
+ writel(GPIO(n) + GP_N_IEM, 0xffffffff);
754
+}
755
+
756
+static void test_dout_to_din(void)
757
+{
758
+ gpio_reset(0);
759
+
760
+ /* When output is enabled, DOUT should be reflected on DIN. */
761
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
762
+ /* PU and PD shouldn't have any impact on DIN. */
763
+ writel(GPIO(0) + GP_N_PU, 0xffff0000);
764
+ writel(GPIO(0) + GP_N_PD, 0x0000ffff);
765
+ writel(GPIO(0) + GP_N_DOUT, 0x12345678);
766
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x12345678);
767
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x12345678);
768
+}
769
+
770
+static void test_pullup_pulldown(void)
771
+{
772
+ gpio_reset(0);
773
+
774
+ /*
775
+ * When output is disabled, and PD is the inverse of PU, PU should be
776
+ * reflected on DIN. If PD is not the inverse of PU, the state of DIN is
777
+ * undefined, so we don't test that.
778
+ */
779
+ writel(GPIO(0) + GP_N_OE, 0x00000000);
780
+ /* DOUT shouldn't have any impact on DIN. */
781
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
782
+ writel(GPIO(0) + GP_N_PU, 0x23456789);
783
+ writel(GPIO(0) + GP_N_PD, ~0x23456789U);
784
+ g_assert_cmphex(readl(GPIO(0) + GP_N_PU), ==, 0x23456789);
785
+ g_assert_cmphex(readl(GPIO(0) + GP_N_PD), ==, ~0x23456789U);
786
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x23456789);
787
+}
788
+
789
+static void test_output_enable(void)
790
+{
791
+ gpio_reset(0);
792
+
793
+ /*
794
+ * With all pins weakly pulled down, and DOUT all-ones, OE should be
795
+ * reflected on DIN.
796
+ */
797
+ writel(GPIO(0) + GP_N_DOUT, 0xffffffff);
798
+ writel(GPIO(0) + GP_N_PU, 0x00000000);
799
+ writel(GPIO(0) + GP_N_PD, 0xffffffff);
800
+ writel(GPIO(0) + GP_N_OE, 0x3456789a);
801
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x3456789a);
802
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x3456789a);
803
+
804
+ writel(GPIO(0) + GP_N_OEC, 0x00030002);
805
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x34547898);
806
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x34547898);
807
+
808
+ writel(GPIO(0) + GP_N_OES, 0x0000f001);
809
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x3454f899);
810
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x3454f899);
811
+}
812
+
813
+static void test_open_drain(void)
814
+{
815
+ gpio_reset(0);
816
+
817
+ /*
818
+ * Upper half of DOUT drives a 1 only if the corresponding bit in OTYP is
819
+ * not set. If OTYP is set, DIN is determined by PU/PD. Lower half of
820
+ * DOUT always drives a 0 regardless of OTYP; PU/PD have no effect. When
821
+ * OE is 0, output is determined by PU/PD; OTYP has no effect.
822
+ */
823
+ writel(GPIO(0) + GP_N_OTYP, 0x456789ab);
824
+ writel(GPIO(0) + GP_N_OE, 0xf0f0f0f0);
825
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
826
+ writel(GPIO(0) + GP_N_PU, 0xff00ff00);
827
+ writel(GPIO(0) + GP_N_PD, 0x00ff00ff);
828
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OTYP), ==, 0x456789ab);
829
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff900f00);
830
+}
831
+
832
+static void test_polarity(void)
833
+{
834
+ gpio_reset(0);
835
+
836
+ /*
837
+ * In push-pull mode, DIN should reflect DOUT because the signal is
838
+ * inverted in both directions.
839
+ */
840
+ writel(GPIO(0) + GP_N_OTYP, 0x00000000);
841
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
842
+ writel(GPIO(0) + GP_N_DOUT, 0x56789abc);
843
+ writel(GPIO(0) + GP_N_POL, 0x6789abcd);
844
+ g_assert_cmphex(readl(GPIO(0) + GP_N_POL), ==, 0x6789abcd);
845
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x56789abc);
846
+
847
+ /*
848
+ * When turning off the drivers, DIN should reflect the inverse of the
849
+ * pulled-up lines.
850
+ */
851
+ writel(GPIO(0) + GP_N_OE, 0x00000000);
852
+ writel(GPIO(0) + GP_N_POL, 0xffffffff);
853
+ writel(GPIO(0) + GP_N_PU, 0x789abcde);
854
+ writel(GPIO(0) + GP_N_PD, ~0x789abcdeU);
855
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, ~0x789abcdeU);
856
+
857
+ /*
858
+ * In open-drain mode, DOUT=1 will appear to drive the pin high (since DIN
859
+ * is inverted), while DOUT=0 will leave the pin floating.
860
+ */
861
+ writel(GPIO(0) + GP_N_OTYP, 0xffffffff);
862
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
863
+ writel(GPIO(0) + GP_N_PU, 0xffff0000);
864
+ writel(GPIO(0) + GP_N_PD, 0x0000ffff);
865
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
866
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff00ffff);
867
+}
868
+
869
+static void test_input_mask(void)
870
+{
871
+ gpio_reset(0);
872
+
873
+ /* IEM=0 forces the input to zero before polarity inversion. */
874
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
875
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
876
+ writel(GPIO(0) + GP_N_POL, 0xffff0000);
877
+ writel(GPIO(0) + GP_N_IEM, 0x87654321);
878
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff9a4300);
879
+}
880
+
881
+static void test_temp_lock(void)
882
+{
883
+ gpio_reset(0);
884
+
885
+ writel(GPIO(0) + GP_N_DOUT, 0x98765432);
886
+
887
+ /* Make sure we're unlocked initially. */
888
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
889
+ /* Writing any value to TLOCK1 will lock. */
890
+ writel(GPIO(0) + GP_N_TLOCK1, 0);
891
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 1);
892
+ writel(GPIO(0) + GP_N_DOUT, 0xa9876543);
893
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x98765432);
894
+ /* Now, try to unlock. */
895
+ gpio_unlock(0);
896
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
897
+ writel(GPIO(0) + GP_N_DOUT, 0xa9876543);
898
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0xa9876543);
899
+
900
+ /* Try it again, but write TLOCK2 to lock. */
901
+ writel(GPIO(0) + GP_N_TLOCK2, 0);
902
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 1);
903
+ writel(GPIO(0) + GP_N_DOUT, 0x98765432);
904
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0xa9876543);
905
+ /* Now, try to unlock. */
906
+ gpio_unlock(0);
907
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
908
+ writel(GPIO(0) + GP_N_DOUT, 0x98765432);
909
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x98765432);
910
+}
911
+
912
+static void test_events_level(void)
913
+{
914
+ gpio_reset(0);
915
+
916
+ writel(GPIO(0) + GP_N_EVTYP, 0x00000000);
917
+ writel(GPIO(0) + GP_N_DOUT, 0xba987654);
918
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
919
+ writel(GPIO(0) + GP_N_EVST, 0xffffffff);
920
+
921
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba987654);
922
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
923
+ writel(GPIO(0) + GP_N_DOUT, 0x00000000);
924
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba987654);
925
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
926
+ writel(GPIO(0) + GP_N_EVST, 0x00007654);
927
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba980000);
928
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
929
+ writel(GPIO(0) + GP_N_EVST, 0xba980000);
930
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
931
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
932
+}
933
+
934
+static void test_events_rising_edge(void)
935
+{
936
+ gpio_reset(0);
937
+
938
+ writel(GPIO(0) + GP_N_EVTYP, 0xffffffff);
939
+ writel(GPIO(0) + GP_N_EVBE, 0x00000000);
940
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
941
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
942
+ writel(GPIO(0) + GP_N_EVST, 0xffffffff);
943
+
944
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
945
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
946
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
947
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x0000ff00);
948
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
949
+ writel(GPIO(0) + GP_N_DOUT, 0x00ff0000);
950
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ffff00);
951
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
952
+ writel(GPIO(0) + GP_N_EVST, 0x0000f000);
953
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ff0f00);
954
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
955
+ writel(GPIO(0) + GP_N_EVST, 0x00ff0f00);
956
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
957
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
958
+}
959
+
960
+static void test_events_both_edges(void)
961
+{
962
+ gpio_reset(0);
963
+
964
+ writel(GPIO(0) + GP_N_EVTYP, 0xffffffff);
965
+ writel(GPIO(0) + GP_N_EVBE, 0xffffffff);
966
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
967
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
968
+ writel(GPIO(0) + GP_N_EVST, 0xffffffff);
969
+
970
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
971
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
972
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
973
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ffff00);
974
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
975
+ writel(GPIO(0) + GP_N_DOUT, 0xef00ff08);
976
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x10ffff08);
977
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
978
+ writel(GPIO(0) + GP_N_EVST, 0x0000f000);
979
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x10ff0f08);
980
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
981
+ writel(GPIO(0) + GP_N_EVST, 0x10ff0f08);
982
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
983
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
984
+}
985
+
986
+static void test_gpion_irq(gconstpointer test_data)
987
+{
988
+ intptr_t n = (intptr_t)test_data;
989
+
990
+ gpio_reset(n);
991
+
992
+ writel(GPIO(n) + GP_N_EVTYP, 0x00000000);
993
+ writel(GPIO(n) + GP_N_DOUT, 0x00000000);
994
+ writel(GPIO(n) + GP_N_OE, 0xffffffff);
995
+ writel(GPIO(n) + GP_N_EVST, 0xffffffff);
996
+ writel(GPIO(n) + GP_N_EVEN, 0x00000000);
997
+
998
+ /* Trigger an event; interrupts are masked. */
999
+ g_assert_cmphex(readl(GPIO(n) + GP_N_EVST), ==, 0x00000000);
1000
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1001
+ writel(GPIO(n) + GP_N_DOS, 0x00008000);
1002
+ g_assert_cmphex(readl(GPIO(n) + GP_N_EVST), ==, 0x00008000);
1003
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1004
+
1005
+ /* Unmask all event interrupts; verify that the interrupt fired. */
1006
+ writel(GPIO(n) + GP_N_EVEN, 0xffffffff);
1007
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1008
+
1009
+ /* Clear the current bit, set a new bit, irq stays asserted. */
1010
+ writel(GPIO(n) + GP_N_DOC, 0x00008000);
1011
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1012
+ writel(GPIO(n) + GP_N_DOS, 0x00000200);
1013
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1014
+ writel(GPIO(n) + GP_N_EVST, 0x00008000);
1015
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1016
+
1017
+ /* Mask/unmask the event that's currently active. */
1018
+ writel(GPIO(n) + GP_N_EVENC, 0x00000200);
1019
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1020
+ writel(GPIO(n) + GP_N_EVENS, 0x00000200);
1021
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1022
+
1023
+ /* Clear the input and the status bit, irq is deasserted. */
1024
+ writel(GPIO(n) + GP_N_DOC, 0x00000200);
1025
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1026
+ writel(GPIO(n) + GP_N_EVST, 0x00000200);
1027
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1028
+}
1029
+
1030
+int main(int argc, char **argv)
1031
+{
1032
+ int ret;
1033
+ int i;
1034
+
1035
+ g_test_init(&argc, &argv, NULL);
1036
+ g_test_set_nonfatal_assertions();
1037
+
1038
+ qtest_add_func("/npcm7xx_gpio/dout_to_din", test_dout_to_din);
1039
+ qtest_add_func("/npcm7xx_gpio/pullup_pulldown", test_pullup_pulldown);
1040
+ qtest_add_func("/npcm7xx_gpio/output_enable", test_output_enable);
1041
+ qtest_add_func("/npcm7xx_gpio/open_drain", test_open_drain);
1042
+ qtest_add_func("/npcm7xx_gpio/polarity", test_polarity);
1043
+ qtest_add_func("/npcm7xx_gpio/input_mask", test_input_mask);
1044
+ qtest_add_func("/npcm7xx_gpio/temp_lock", test_temp_lock);
1045
+ qtest_add_func("/npcm7xx_gpio/events/level", test_events_level);
1046
+ qtest_add_func("/npcm7xx_gpio/events/rising_edge", test_events_rising_edge);
1047
+ qtest_add_func("/npcm7xx_gpio/events/both_edges", test_events_both_edges);
1048
+
1049
+ for (i = 0; i < NR_GPIO_DEVICES; i++) {
1050
+ g_autofree char *test_name =
1051
+ g_strdup_printf("/npcm7xx_gpio/gpio[%d]/irq", i);
1052
+ qtest_add_data_func(test_name, (void *)(intptr_t)i, test_gpion_irq);
1053
+ }
1054
+
1055
+ qtest_start("-machine npcm750-evb");
1056
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/a9mpcore/gic");
1057
+ ret = g_test_run();
1058
+ qtest_end();
1059
+
1060
+ return ret;
1061
+}
1062
diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build
1063
index XXXXXXX..XXXXXXX 100644
1064
--- a/hw/gpio/meson.build
1065
+++ b/hw/gpio/meson.build
1066
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_gpio.c'))
1067
softmmu_ss.add(when: 'CONFIG_ZAURUS', if_true: files('zaurus.c'))
1068
1069
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpio.c'))
1070
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_gpio.c'))
1071
softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_gpio.c'))
1072
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gpio.c'))
1073
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_gpio.c'))
1074
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
1075
index XXXXXXX..XXXXXXX 100644
1076
--- a/hw/gpio/trace-events
1077
+++ b/hw/gpio/trace-events
1078
@@ -XXX,XX +XXX,XX @@
1079
# See docs/devel/tracing.txt for syntax documentation.
1080
1081
+# npcm7xx_gpio.c
1082
+npcm7xx_gpio_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
1083
+npcm7xx_gpio_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
1084
+npcm7xx_gpio_set_input(const char *id, int32_t line, int32_t level) "%s line: %" PRIi32 " level: %" PRIi32
1085
+npcm7xx_gpio_set_output(const char *id, int32_t line, int32_t level) "%s line: %" PRIi32 " level: %" PRIi32
1086
+npcm7xx_gpio_update_events(const char *id, uint32_t evst, uint32_t even) "%s evst: 0x%08" PRIx32 " even: 0x%08" PRIx32
1087
+
1088
# nrf51_gpio.c
1089
nrf51_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
1090
nrf51_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
1091
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
1092
index XXXXXXX..XXXXXXX 100644
1093
--- a/tests/qtest/meson.build
1094
+++ b/tests/qtest/meson.build
1095
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
1096
['prom-env-test', 'boot-serial-test']
1097
1098
qtests_npcm7xx = \
1099
- ['npcm7xx_rng-test',
1100
+ ['npcm7xx_gpio-test',
1101
+ 'npcm7xx_rng-test',
1102
'npcm7xx_timer-test',
1103
'npcm7xx_watchdog_timer-test']
1104
qtests_arm = \
150
--
1105
--
151
2.20.1
1106
2.20.1
152
1107
153
1108
diff view generated by jsdifflib
1
From: Eric Auger <eric.auger@redhat.com>
1
From: Zenghui Yu <yuzenghui@huawei.com>
2
2
3
The SMMUNotifierNode struct is not necessary and brings extra
3
Ensure the vSMMUv3 will be restored before all PCIe devices so that DMA
4
complexity so let's remove it. We now directly track the SMMUDevices
4
translation can work properly during migration.
5
which have registered IOMMU MR notifiers.
6
5
7
This is inspired from the same transformation on intel-iommu
6
Signed-off-by: Zenghui Yu <yuzenghui@huawei.com>
8
done in commit b4a4ba0d68f50f218ee3957b6638dbee32a5eeef
7
Message-id: 20201019091508.197-1-yuzenghui@huawei.com
9
("intel-iommu: remove IntelIOMMUNotifierNode")
8
Acked-by: Eric Auger <eric.auger@redhat.com>
10
11
Signed-off-by: Eric Auger <eric.auger@redhat.com>
12
Reviewed-by: Peter Xu <peterx@redhat.com>
13
Message-id: 20190409160219.19026-1-eric.auger@redhat.com
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
---
10
---
16
include/hw/arm/smmu-common.h | 8 ++------
11
hw/arm/smmuv3.c | 1 +
17
hw/arm/smmu-common.c | 6 +++---
12
1 file changed, 1 insertion(+)
18
hw/arm/smmuv3.c | 28 +++++++---------------------
19
3 files changed, 12 insertions(+), 30 deletions(-)
20
13
21
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
22
index XXXXXXX..XXXXXXX 100644
23
--- a/include/hw/arm/smmu-common.h
24
+++ b/include/hw/arm/smmu-common.h
25
@@ -XXX,XX +XXX,XX @@ typedef struct SMMUDevice {
26
AddressSpace as;
27
uint32_t cfg_cache_hits;
28
uint32_t cfg_cache_misses;
29
+ QLIST_ENTRY(SMMUDevice) next;
30
} SMMUDevice;
31
32
-typedef struct SMMUNotifierNode {
33
- SMMUDevice *sdev;
34
- QLIST_ENTRY(SMMUNotifierNode) next;
35
-} SMMUNotifierNode;
36
-
37
typedef struct SMMUPciBus {
38
PCIBus *bus;
39
SMMUDevice *pbdev[0]; /* Parent array is sparse, so dynamically alloc */
40
@@ -XXX,XX +XXX,XX @@ typedef struct SMMUState {
41
GHashTable *iotlb;
42
SMMUPciBus *smmu_pcibus_by_bus_num[SMMU_PCI_BUS_MAX];
43
PCIBus *pci_bus;
44
- QLIST_HEAD(, SMMUNotifierNode) notifiers_list;
45
+ QLIST_HEAD(, SMMUDevice) devices_with_notifiers;
46
uint8_t bus_num;
47
PCIBus *primary_bus;
48
} SMMUState;
49
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/hw/arm/smmu-common.c
52
+++ b/hw/arm/smmu-common.c
53
@@ -XXX,XX +XXX,XX @@ inline void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr)
54
/* Unmap all notifiers of all mr's */
55
void smmu_inv_notifiers_all(SMMUState *s)
56
{
57
- SMMUNotifierNode *node;
58
+ SMMUDevice *sdev;
59
60
- QLIST_FOREACH(node, &s->notifiers_list, next) {
61
- smmu_inv_notifiers_mr(&node->sdev->iommu);
62
+ QLIST_FOREACH(sdev, &s->devices_with_notifiers, next) {
63
+ smmu_inv_notifiers_mr(&sdev->iommu);
64
}
65
}
66
67
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
14
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
68
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
69
--- a/hw/arm/smmuv3.c
16
--- a/hw/arm/smmuv3.c
70
+++ b/hw/arm/smmuv3.c
17
+++ b/hw/arm/smmuv3.c
71
@@ -XXX,XX +XXX,XX @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
18
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_smmuv3 = {
72
/* invalidate an asid/iova tuple in all mr's */
19
.name = "smmuv3",
73
static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova)
20
.version_id = 1,
74
{
21
.minimum_version_id = 1,
75
- SMMUNotifierNode *node;
22
+ .priority = MIG_PRI_IOMMU,
76
+ SMMUDevice *sdev;
23
.fields = (VMStateField[]) {
77
24
VMSTATE_UINT32(features, SMMUv3State),
78
- QLIST_FOREACH(node, &s->notifiers_list, next) {
25
VMSTATE_UINT8(sid_size, SMMUv3State),
79
- IOMMUMemoryRegion *mr = &node->sdev->iommu;
80
+ QLIST_FOREACH(sdev, &s->devices_with_notifiers, next) {
81
+ IOMMUMemoryRegion *mr = &sdev->iommu;
82
IOMMUNotifier *n;
83
84
trace_smmuv3_inv_notifiers_iova(mr->parent_obj.name, asid, iova);
85
@@ -XXX,XX +XXX,XX @@ static void smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu,
86
SMMUDevice *sdev = container_of(iommu, SMMUDevice, iommu);
87
SMMUv3State *s3 = sdev->smmu;
88
SMMUState *s = &(s3->smmu_state);
89
- SMMUNotifierNode *node = NULL;
90
- SMMUNotifierNode *next_node = NULL;
91
92
if (new & IOMMU_NOTIFIER_MAP) {
93
int bus_num = pci_bus_num(sdev->bus);
94
@@ -XXX,XX +XXX,XX @@ static void smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu,
95
96
if (old == IOMMU_NOTIFIER_NONE) {
97
trace_smmuv3_notify_flag_add(iommu->parent_obj.name);
98
- node = g_malloc0(sizeof(*node));
99
- node->sdev = sdev;
100
- QLIST_INSERT_HEAD(&s->notifiers_list, node, next);
101
- return;
102
- }
103
-
104
- /* update notifier node with new flags */
105
- QLIST_FOREACH_SAFE(node, &s->notifiers_list, next, next_node) {
106
- if (node->sdev == sdev) {
107
- if (new == IOMMU_NOTIFIER_NONE) {
108
- trace_smmuv3_notify_flag_del(iommu->parent_obj.name);
109
- QLIST_REMOVE(node, next);
110
- g_free(node);
111
- }
112
- return;
113
- }
114
+ QLIST_INSERT_HEAD(&s->devices_with_notifiers, sdev, next);
115
+ } else if (new == IOMMU_NOTIFIER_NONE) {
116
+ trace_smmuv3_notify_flag_del(iommu->parent_obj.name);
117
+ QLIST_REMOVE(sdev, next);
118
}
119
}
120
121
--
26
--
122
2.20.1
27
2.20.1
123
28
124
29
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
No code out of bcm2836.c uses (or requires) the BCM283XInfo
4
declarations. Move it locally to the C source file.
5
6
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
7
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20201024170127.3592182-2-f4bug@amsat.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
include/hw/arm/bcm2836.h | 8 --------
12
hw/arm/bcm2836.c | 14 ++++++++++++++
13
2 files changed, 14 insertions(+), 8 deletions(-)
14
15
diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h
16
index XXXXXXX..XXXXXXX 100644
17
--- a/include/hw/arm/bcm2836.h
18
+++ b/include/hw/arm/bcm2836.h
19
@@ -XXX,XX +XXX,XX @@ struct BCM283XState {
20
BCM2835PeripheralState peripherals;
21
};
22
23
-typedef struct BCM283XInfo BCM283XInfo;
24
-
25
-struct BCM283XClass {
26
- DeviceClass parent_class;
27
- const BCM283XInfo *info;
28
-};
29
-
30
-
31
#endif /* BCM2836_H */
32
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/hw/arm/bcm2836.c
35
+++ b/hw/arm/bcm2836.c
36
@@ -XXX,XX +XXX,XX @@
37
#include "hw/arm/raspi_platform.h"
38
#include "hw/sysbus.h"
39
40
+typedef struct BCM283XInfo BCM283XInfo;
41
+
42
+typedef struct BCM283XClass {
43
+ /*< private >*/
44
+ DeviceClass parent_class;
45
+ /*< public >*/
46
+ const BCM283XInfo *info;
47
+} BCM283XClass;
48
+
49
struct BCM283XInfo {
50
const char *name;
51
const char *cpu_type;
52
@@ -XXX,XX +XXX,XX @@ struct BCM283XInfo {
53
int clusterid;
54
};
55
56
+#define BCM283X_CLASS(klass) \
57
+ OBJECT_CLASS_CHECK(BCM283XClass, (klass), TYPE_BCM283X)
58
+#define BCM283X_GET_CLASS(obj) \
59
+ OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
60
+
61
static const BCM283XInfo bcm283x_socs[] = {
62
{
63
.name = TYPE_BCM2836,
64
--
65
2.20.1
66
67
diff view generated by jsdifflib
1
The M-profile CONTROL register has two bits -- SFPA and FPCA --
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
which relate to floating-point support, and should be RES0 otherwise.
2
3
Handle them correctly in the MSR/MRS register access code.
3
Remove usage of TypeInfo::class_data. Instead fill the fields in
4
Neither is banked between security states, so they are stored
4
the corresponding class_init().
5
in v7m.control[M_REG_S] regardless of current security state.
5
6
6
So far all children use the same values for almost all fields,
7
but we are going to add the BCM2711/BCM2838 SoC for the raspi4
8
machine which use different fields.
9
10
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
11
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Message-id: 20201024170127.3592182-3-f4bug@amsat.org
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20190416125744.27770-9-peter.maydell@linaro.org
10
---
14
---
11
target/arm/helper.c | 57 ++++++++++++++++++++++++++++++++++++++-------
15
hw/arm/bcm2836.c | 108 ++++++++++++++++++++++-------------------------
12
1 file changed, 49 insertions(+), 8 deletions(-)
16
1 file changed, 51 insertions(+), 57 deletions(-)
13
17
14
diff --git a/target/arm/helper.c b/target/arm/helper.c
18
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
15
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/helper.c
20
--- a/hw/arm/bcm2836.c
17
+++ b/target/arm/helper.c
21
+++ b/hw/arm/bcm2836.c
18
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
22
@@ -XXX,XX +XXX,XX @@
19
return xpsr_read(env) & mask;
23
#include "hw/arm/raspi_platform.h"
20
break;
24
#include "hw/sysbus.h"
21
case 20: /* CONTROL */
25
22
- return env->v7m.control[env->v7m.secure];
26
-typedef struct BCM283XInfo BCM283XInfo;
23
+ {
27
-
24
+ uint32_t value = env->v7m.control[env->v7m.secure];
28
typedef struct BCM283XClass {
25
+ if (!env->v7m.secure) {
29
/*< private >*/
26
+ /* SFPA is RAZ/WI from NS; FPCA is stored in the M_REG_S bank */
30
DeviceClass parent_class;
27
+ value |= env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK;
31
/*< public >*/
28
+ }
32
- const BCM283XInfo *info;
29
+ return value;
33
-} BCM283XClass;
30
+ }
34
-
31
case 0x94: /* CONTROL_NS */
35
-struct BCM283XInfo {
32
/* We have to handle this here because unprivileged Secure code
36
const char *name;
33
* can read the NS CONTROL register.
37
const char *cpu_type;
34
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
38
hwaddr peri_base; /* Peripheral base address seen by the CPU */
35
if (!env->v7m.secure) {
39
hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
36
return 0;
40
int clusterid;
37
}
41
-};
38
- return env->v7m.control[M_REG_NS];
42
+} BCM283XClass;
39
+ return env->v7m.control[M_REG_NS] |
43
40
+ (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK);
44
#define BCM283X_CLASS(klass) \
45
OBJECT_CLASS_CHECK(BCM283XClass, (klass), TYPE_BCM283X)
46
#define BCM283X_GET_CLASS(obj) \
47
OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
48
49
-static const BCM283XInfo bcm283x_socs[] = {
50
- {
51
- .name = TYPE_BCM2836,
52
- .cpu_type = ARM_CPU_TYPE_NAME("cortex-a7"),
53
- .peri_base = 0x3f000000,
54
- .ctrl_base = 0x40000000,
55
- .clusterid = 0xf,
56
- },
57
-#ifdef TARGET_AARCH64
58
- {
59
- .name = TYPE_BCM2837,
60
- .cpu_type = ARM_CPU_TYPE_NAME("cortex-a53"),
61
- .peri_base = 0x3f000000,
62
- .ctrl_base = 0x40000000,
63
- .clusterid = 0x0,
64
- },
65
-#endif
66
-};
67
-
68
static void bcm2836_init(Object *obj)
69
{
70
BCM283XState *s = BCM283X(obj);
71
BCM283XClass *bc = BCM283X_GET_CLASS(obj);
72
- const BCM283XInfo *info = bc->info;
73
int n;
74
75
for (n = 0; n < BCM283X_NCPUS; n++) {
76
object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
77
- info->cpu_type);
78
+ bc->cpu_type);
41
}
79
}
42
80
43
if (el == 0) {
81
object_initialize_child(obj, "control", &s->control, TYPE_BCM2836_CONTROL);
44
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
82
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
45
*/
83
{
46
uint32_t mask = extract32(maskreg, 8, 4);
84
BCM283XState *s = BCM283X(dev);
47
uint32_t reg = extract32(maskreg, 0, 8);
85
BCM283XClass *bc = BCM283X_GET_CLASS(dev);
48
+ int cur_el = arm_current_el(env);
86
- const BCM283XInfo *info = bc->info;
49
87
Object *obj;
50
- if (arm_current_el(env) == 0 && reg > 7) {
88
int n;
51
- /* only xPSR sub-fields may be written by unprivileged */
89
52
+ if (cur_el == 0 && reg > 7 && reg != 20) {
90
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
53
+ /*
91
"sd-bus");
54
+ * only xPSR sub-fields and CONTROL.SFPA may be written by
92
55
+ * unprivileged code
93
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
56
+ */
94
- info->peri_base, 1);
95
+ bc->peri_base, 1);
96
97
/* bcm2836 interrupt controller (and mailboxes, etc.) */
98
if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), errp)) {
57
return;
99
return;
58
}
100
}
59
101
60
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
102
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, info->ctrl_base);
61
env->v7m.control[M_REG_NS] &= ~R_V7M_CONTROL_NPRIV_MASK;
103
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, bc->ctrl_base);
62
env->v7m.control[M_REG_NS] |= val & R_V7M_CONTROL_NPRIV_MASK;
104
63
}
105
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
64
+ /*
106
qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
65
+ * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 0,
107
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
66
+ * RES0 if the FPU is not present, and is stored in the S bank
108
67
+ */
109
for (n = 0; n < BCM283X_NCPUS; n++) {
68
+ if (arm_feature(env, ARM_FEATURE_VFP) &&
110
/* TODO: this should be converted to a property of ARM_CPU */
69
+ extract32(env->v7m.nsacr, 10, 1)) {
111
- s->cpu[n].core.mp_affinity = (info->clusterid << 8) | n;
70
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
112
+ s->cpu[n].core.mp_affinity = (bc->clusterid << 8) | n;
71
+ env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
113
72
+ }
114
/* set periphbase/CBAR value for CPU-local registers */
115
if (!object_property_set_int(OBJECT(&s->cpu[n].core), "reset-cbar",
116
- info->peri_base, errp)) {
117
+ bc->peri_base, errp)) {
73
return;
118
return;
74
case 0x98: /* SP_NS */
75
{
76
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
77
env->v7m.faultmask[env->v7m.secure] = val & 1;
78
break;
79
case 20: /* CONTROL */
80
- /* Writing to the SPSEL bit only has an effect if we are in
81
+ /*
82
+ * Writing to the SPSEL bit only has an effect if we are in
83
* thread mode; other bits can be updated by any privileged code.
84
* write_v7m_control_spsel() deals with updating the SPSEL bit in
85
* env->v7m.control, so we only need update the others.
86
* For v7M, we must just ignore explicit writes to SPSEL in handler
87
* mode; for v8M the write is permitted but will have no effect.
88
+ * All these bits are writes-ignored from non-privileged code,
89
+ * except for SFPA.
90
*/
91
- if (arm_feature(env, ARM_FEATURE_V8) ||
92
- !arm_v7m_is_handler_mode(env)) {
93
+ if (cur_el > 0 && (arm_feature(env, ARM_FEATURE_V8) ||
94
+ !arm_v7m_is_handler_mode(env))) {
95
write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
96
}
119
}
97
- if (arm_feature(env, ARM_FEATURE_M_MAIN)) {
120
98
+ if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) {
121
@@ -XXX,XX +XXX,XX @@ static Property bcm2836_props[] = {
99
env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
122
static void bcm283x_class_init(ObjectClass *oc, void *data)
100
env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
123
{
101
}
124
DeviceClass *dc = DEVICE_CLASS(oc);
102
+ if (arm_feature(env, ARM_FEATURE_VFP)) {
125
- BCM283XClass *bc = BCM283X_CLASS(oc);
103
+ /*
126
104
+ * SFPA is RAZ/WI from NS or if no FPU.
127
- bc->info = data;
105
+ * FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
128
- dc->realize = bcm2836_realize;
106
+ * Both are stored in the S bank.
129
- device_class_set_props(dc, bcm2836_props);
107
+ */
130
/* Reason: Must be wired up in code (see raspi_init() function) */
108
+ if (env->v7m.secure) {
131
dc->user_creatable = false;
109
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
132
}
110
+ env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_SFPA_MASK;
133
111
+ }
134
-static const TypeInfo bcm283x_type_info = {
112
+ if (cur_el > 0 &&
135
- .name = TYPE_BCM283X,
113
+ (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURITY) ||
136
- .parent = TYPE_DEVICE,
114
+ extract32(env->v7m.nsacr, 10, 1))) {
137
- .instance_size = sizeof(BCM283XState),
115
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
138
- .instance_init = bcm2836_init,
116
+ env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
139
- .class_size = sizeof(BCM283XClass),
117
+ }
140
- .abstract = true,
118
+ }
141
+static void bcm2836_class_init(ObjectClass *oc, void *data)
119
break;
142
+{
120
default:
143
+ DeviceClass *dc = DEVICE_CLASS(oc);
121
bad_reg:
144
+ BCM283XClass *bc = BCM283X_CLASS(oc);
145
+
146
+ bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
147
+ bc->peri_base = 0x3f000000;
148
+ bc->ctrl_base = 0x40000000;
149
+ bc->clusterid = 0xf;
150
+ dc->realize = bcm2836_realize;
151
+ device_class_set_props(dc, bcm2836_props);
152
};
153
154
-static void bcm2836_register_types(void)
155
+#ifdef TARGET_AARCH64
156
+static void bcm2837_class_init(ObjectClass *oc, void *data)
157
{
158
- int i;
159
+ DeviceClass *dc = DEVICE_CLASS(oc);
160
+ BCM283XClass *bc = BCM283X_CLASS(oc);
161
162
- type_register_static(&bcm283x_type_info);
163
- for (i = 0; i < ARRAY_SIZE(bcm283x_socs); i++) {
164
- TypeInfo ti = {
165
- .name = bcm283x_socs[i].name,
166
- .parent = TYPE_BCM283X,
167
- .class_init = bcm283x_class_init,
168
- .class_data = (void *) &bcm283x_socs[i],
169
- };
170
- type_register(&ti);
171
+ bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
172
+ bc->peri_base = 0x3f000000;
173
+ bc->ctrl_base = 0x40000000;
174
+ bc->clusterid = 0x0;
175
+ dc->realize = bcm2836_realize;
176
+ device_class_set_props(dc, bcm2836_props);
177
+};
178
+#endif
179
+
180
+static const TypeInfo bcm283x_types[] = {
181
+ {
182
+ .name = TYPE_BCM2836,
183
+ .parent = TYPE_BCM283X,
184
+ .class_init = bcm2836_class_init,
185
+#ifdef TARGET_AARCH64
186
+ }, {
187
+ .name = TYPE_BCM2837,
188
+ .parent = TYPE_BCM283X,
189
+ .class_init = bcm2837_class_init,
190
+#endif
191
+ }, {
192
+ .name = TYPE_BCM283X,
193
+ .parent = TYPE_DEVICE,
194
+ .instance_size = sizeof(BCM283XState),
195
+ .instance_init = bcm2836_init,
196
+ .class_size = sizeof(BCM283XClass),
197
+ .class_init = bcm283x_class_init,
198
+ .abstract = true,
199
}
200
-}
201
+};
202
203
-type_init(bcm2836_register_types)
204
+DEFINE_TYPES(bcm283x_types)
122
--
205
--
123
2.20.1
206
2.20.1
124
207
125
208
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
Reviewed-by: Thomas Huth <thuth@redhat.com>
3
The BCM2835 has only one core. Introduce the core_count field to
4
Reviewed-by: Markus Armbruster <armbru@redhat.com>
4
be able to use values different than BCM283X_NCPUS (4).
5
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
5
6
Message-id: 20190412165416.7977-11-philmd@redhat.com
6
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
7
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20201024170127.3592182-4-f4bug@amsat.org
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
10
---
9
include/hw/net/ne2000-isa.h | 6 ++++++
11
hw/arm/bcm2836.c | 5 ++++-
10
1 file changed, 6 insertions(+)
12
1 file changed, 4 insertions(+), 1 deletion(-)
11
13
12
diff --git a/include/hw/net/ne2000-isa.h b/include/hw/net/ne2000-isa.h
14
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
13
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
14
--- a/include/hw/net/ne2000-isa.h
16
--- a/hw/arm/bcm2836.c
15
+++ b/include/hw/net/ne2000-isa.h
17
+++ b/hw/arm/bcm2836.c
16
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ typedef struct BCM283XClass {
17
* This work is licensed under the terms of the GNU GPL, version 2 or later.
19
/*< public >*/
18
* See the COPYING file in the top-level directory.
20
const char *name;
19
*/
21
const char *cpu_type;
20
+
22
+ unsigned core_count;
21
+#ifndef HW_NET_NE2K_ISA_H
23
hwaddr peri_base; /* Peripheral base address seen by the CPU */
22
+#define HW_NET_NE2K_ISA_H
24
hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
23
+
25
int clusterid;
24
#include "hw/hw.h"
26
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
25
#include "hw/qdev.h"
27
BCM283XClass *bc = BCM283X_GET_CLASS(obj);
26
#include "hw/isa/isa.h"
28
int n;
27
@@ -XXX,XX +XXX,XX @@ static inline ISADevice *isa_ne2000_init(ISABus *bus, int base, int irq,
29
30
- for (n = 0; n < BCM283X_NCPUS; n++) {
31
+ for (n = 0; n < bc->core_count; n++) {
32
object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
33
bc->cpu_type);
28
}
34
}
29
return d;
35
@@ -XXX,XX +XXX,XX @@ static void bcm2836_class_init(ObjectClass *oc, void *data)
30
}
36
BCM283XClass *bc = BCM283X_CLASS(oc);
31
+
37
32
+#endif
38
bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
39
+ bc->core_count = BCM283X_NCPUS;
40
bc->peri_base = 0x3f000000;
41
bc->ctrl_base = 0x40000000;
42
bc->clusterid = 0xf;
43
@@ -XXX,XX +XXX,XX @@ static void bcm2837_class_init(ObjectClass *oc, void *data)
44
BCM283XClass *bc = BCM283X_CLASS(oc);
45
46
bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
47
+ bc->core_count = BCM283X_NCPUS;
48
bc->peri_base = 0x3f000000;
49
bc->ctrl_base = 0x40000000;
50
bc->clusterid = 0x0;
33
--
51
--
34
2.20.1
52
2.20.1
35
53
36
54
diff view generated by jsdifflib
1
Pushing registers to the stack for v7M needs to handle three cases:
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
* the "normal" case where we pend exceptions
3
* an "ignore faults" case where we set FSR bits but
4
do not pend exceptions (this is used when we are
5
handling some kinds of derived exception on exception entry)
6
* a "lazy FP stacking" case, where different FSR bits
7
are set and the exception is pended differently
8
2
9
Implement this by changing the existing flag argument that
3
It makes no sense to set enabled-cpus=0 on single core SoCs.
10
tells us whether to ignore faults or not into an enum that
11
specifies which of the 3 modes we should handle.
12
4
5
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
6
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Message-id: 20201024170127.3592182-5-f4bug@amsat.org
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
Message-id: 20190416125744.27770-23-peter.maydell@linaro.org
16
---
9
---
17
target/arm/helper.c | 118 +++++++++++++++++++++++++++++---------------
10
hw/arm/bcm2836.c | 15 +++++++--------
18
1 file changed, 79 insertions(+), 39 deletions(-)
11
1 file changed, 7 insertions(+), 8 deletions(-)
19
12
20
diff --git a/target/arm/helper.c b/target/arm/helper.c
13
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
21
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
22
--- a/target/arm/helper.c
15
--- a/hw/arm/bcm2836.c
23
+++ b/target/arm/helper.c
16
+++ b/hw/arm/bcm2836.c
24
@@ -XXX,XX +XXX,XX @@ static bool v7m_cpacr_pass(CPUARMState *env, bool is_secure, bool is_priv)
17
@@ -XXX,XX +XXX,XX @@ typedef struct BCM283XClass {
18
#define BCM283X_GET_CLASS(obj) \
19
OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
20
21
+static Property bcm2836_enabled_cores_property =
22
+ DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus, 0);
23
+
24
static void bcm2836_init(Object *obj)
25
{
26
BCM283XState *s = BCM283X(obj);
27
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
28
object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
29
bc->cpu_type);
30
}
31
+ if (bc->core_count > 1) {
32
+ qdev_property_add_static(DEVICE(obj), &bcm2836_enabled_cores_property);
33
+ qdev_prop_set_uint32(DEVICE(obj), "enabled-cpus", bc->core_count);
34
+ }
35
36
object_initialize_child(obj, "control", &s->control, TYPE_BCM2836_CONTROL);
37
38
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
25
}
39
}
26
}
40
}
27
41
28
+/*
42
-static Property bcm2836_props[] = {
29
+ * What kind of stack write are we doing? This affects how exceptions
43
- DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus,
30
+ * generated during the stacking are treated.
44
- BCM283X_NCPUS),
31
+ */
45
- DEFINE_PROP_END_OF_LIST()
32
+typedef enum StackingMode {
46
-};
33
+ STACK_NORMAL,
47
-
34
+ STACK_IGNFAULTS,
48
static void bcm283x_class_init(ObjectClass *oc, void *data)
35
+ STACK_LAZYFP,
36
+} StackingMode;
37
+
38
static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value,
39
- ARMMMUIdx mmu_idx, bool ignfault)
40
+ ARMMMUIdx mmu_idx, StackingMode mode)
41
{
49
{
42
CPUState *cs = CPU(cpu);
50
DeviceClass *dc = DEVICE_CLASS(oc);
43
CPUARMState *env = &cpu->env;
51
@@ -XXX,XX +XXX,XX @@ static void bcm2836_class_init(ObjectClass *oc, void *data)
44
@@ -XXX,XX +XXX,XX @@ static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value,
52
bc->ctrl_base = 0x40000000;
45
&attrs, &prot, &page_size, &fi, NULL)) {
53
bc->clusterid = 0xf;
46
/* MPU/SAU lookup failed */
54
dc->realize = bcm2836_realize;
47
if (fi.type == ARMFault_QEMU_SFault) {
55
- device_class_set_props(dc, bcm2836_props);
48
- qemu_log_mask(CPU_LOG_INT,
56
};
49
- "...SecureFault with SFSR.AUVIOL during stacking\n");
57
50
- env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVALID_MASK;
58
#ifdef TARGET_AARCH64
51
+ if (mode == STACK_LAZYFP) {
59
@@ -XXX,XX +XXX,XX @@ static void bcm2837_class_init(ObjectClass *oc, void *data)
52
+ qemu_log_mask(CPU_LOG_INT,
60
bc->ctrl_base = 0x40000000;
53
+ "...SecureFault with SFSR.LSPERR "
61
bc->clusterid = 0x0;
54
+ "during lazy stacking\n");
62
dc->realize = bcm2836_realize;
55
+ env->v7m.sfsr |= R_V7M_SFSR_LSPERR_MASK;
63
- device_class_set_props(dc, bcm2836_props);
56
+ } else {
64
};
57
+ qemu_log_mask(CPU_LOG_INT,
65
#endif
58
+ "...SecureFault with SFSR.AUVIOL "
66
59
+ "during stacking\n");
60
+ env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
61
+ }
62
+ env->v7m.sfsr |= R_V7M_SFSR_SFARVALID_MASK;
63
env->v7m.sfar = addr;
64
exc = ARMV7M_EXCP_SECURE;
65
exc_secure = false;
66
} else {
67
- qemu_log_mask(CPU_LOG_INT, "...MemManageFault with CFSR.MSTKERR\n");
68
- env->v7m.cfsr[secure] |= R_V7M_CFSR_MSTKERR_MASK;
69
+ if (mode == STACK_LAZYFP) {
70
+ qemu_log_mask(CPU_LOG_INT,
71
+ "...MemManageFault with CFSR.MLSPERR\n");
72
+ env->v7m.cfsr[secure] |= R_V7M_CFSR_MLSPERR_MASK;
73
+ } else {
74
+ qemu_log_mask(CPU_LOG_INT,
75
+ "...MemManageFault with CFSR.MSTKERR\n");
76
+ env->v7m.cfsr[secure] |= R_V7M_CFSR_MSTKERR_MASK;
77
+ }
78
exc = ARMV7M_EXCP_MEM;
79
exc_secure = secure;
80
}
81
@@ -XXX,XX +XXX,XX @@ static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value,
82
attrs, &txres);
83
if (txres != MEMTX_OK) {
84
/* BusFault trying to write the data */
85
- qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n");
86
- env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_STKERR_MASK;
87
+ if (mode == STACK_LAZYFP) {
88
+ qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.LSPERR\n");
89
+ env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_LSPERR_MASK;
90
+ } else {
91
+ qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n");
92
+ env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_STKERR_MASK;
93
+ }
94
exc = ARMV7M_EXCP_BUS;
95
exc_secure = false;
96
goto pend_fault;
97
@@ -XXX,XX +XXX,XX @@ pend_fault:
98
* later if we have two derived exceptions.
99
* The only case when we must not pend the exception but instead
100
* throw it away is if we are doing the push of the callee registers
101
- * and we've already generated a derived exception. Even in this
102
- * case we will still update the fault status registers.
103
+ * and we've already generated a derived exception (this is indicated
104
+ * by the caller passing STACK_IGNFAULTS). Even in this case we will
105
+ * still update the fault status registers.
106
*/
107
- if (!ignfault) {
108
+ switch (mode) {
109
+ case STACK_NORMAL:
110
armv7m_nvic_set_pending_derived(env->nvic, exc, exc_secure);
111
+ break;
112
+ case STACK_LAZYFP:
113
+ armv7m_nvic_set_pending_lazyfp(env->nvic, exc, exc_secure);
114
+ break;
115
+ case STACK_IGNFAULTS:
116
+ break;
117
}
118
return false;
119
}
120
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
121
uint32_t limit;
122
bool want_psp;
123
uint32_t sig;
124
+ StackingMode smode = ignore_faults ? STACK_IGNFAULTS : STACK_NORMAL;
125
126
if (dotailchain) {
127
bool mode = lr & R_V7M_EXCRET_MODE_MASK;
128
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
129
*/
130
sig = v7m_integrity_sig(env, lr);
131
stacked_ok =
132
- v7m_stack_write(cpu, frameptr, sig, mmu_idx, ignore_faults) &&
133
- v7m_stack_write(cpu, frameptr + 0x8, env->regs[4], mmu_idx,
134
- ignore_faults) &&
135
- v7m_stack_write(cpu, frameptr + 0xc, env->regs[5], mmu_idx,
136
- ignore_faults) &&
137
- v7m_stack_write(cpu, frameptr + 0x10, env->regs[6], mmu_idx,
138
- ignore_faults) &&
139
- v7m_stack_write(cpu, frameptr + 0x14, env->regs[7], mmu_idx,
140
- ignore_faults) &&
141
- v7m_stack_write(cpu, frameptr + 0x18, env->regs[8], mmu_idx,
142
- ignore_faults) &&
143
- v7m_stack_write(cpu, frameptr + 0x1c, env->regs[9], mmu_idx,
144
- ignore_faults) &&
145
- v7m_stack_write(cpu, frameptr + 0x20, env->regs[10], mmu_idx,
146
- ignore_faults) &&
147
- v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx,
148
- ignore_faults);
149
+ v7m_stack_write(cpu, frameptr, sig, mmu_idx, smode) &&
150
+ v7m_stack_write(cpu, frameptr + 0x8, env->regs[4], mmu_idx, smode) &&
151
+ v7m_stack_write(cpu, frameptr + 0xc, env->regs[5], mmu_idx, smode) &&
152
+ v7m_stack_write(cpu, frameptr + 0x10, env->regs[6], mmu_idx, smode) &&
153
+ v7m_stack_write(cpu, frameptr + 0x14, env->regs[7], mmu_idx, smode) &&
154
+ v7m_stack_write(cpu, frameptr + 0x18, env->regs[8], mmu_idx, smode) &&
155
+ v7m_stack_write(cpu, frameptr + 0x1c, env->regs[9], mmu_idx, smode) &&
156
+ v7m_stack_write(cpu, frameptr + 0x20, env->regs[10], mmu_idx, smode) &&
157
+ v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, smode);
158
159
/* Update SP regardless of whether any of the stack accesses failed. */
160
*frame_sp_p = frameptr;
161
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_stack(ARMCPU *cpu)
162
* if it has higher priority).
163
*/
164
stacked_ok = stacked_ok &&
165
- v7m_stack_write(cpu, frameptr, env->regs[0], mmu_idx, false) &&
166
- v7m_stack_write(cpu, frameptr + 4, env->regs[1], mmu_idx, false) &&
167
- v7m_stack_write(cpu, frameptr + 8, env->regs[2], mmu_idx, false) &&
168
- v7m_stack_write(cpu, frameptr + 12, env->regs[3], mmu_idx, false) &&
169
- v7m_stack_write(cpu, frameptr + 16, env->regs[12], mmu_idx, false) &&
170
- v7m_stack_write(cpu, frameptr + 20, env->regs[14], mmu_idx, false) &&
171
- v7m_stack_write(cpu, frameptr + 24, env->regs[15], mmu_idx, false) &&
172
- v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, false);
173
+ v7m_stack_write(cpu, frameptr, env->regs[0], mmu_idx, STACK_NORMAL) &&
174
+ v7m_stack_write(cpu, frameptr + 4, env->regs[1],
175
+ mmu_idx, STACK_NORMAL) &&
176
+ v7m_stack_write(cpu, frameptr + 8, env->regs[2],
177
+ mmu_idx, STACK_NORMAL) &&
178
+ v7m_stack_write(cpu, frameptr + 12, env->regs[3],
179
+ mmu_idx, STACK_NORMAL) &&
180
+ v7m_stack_write(cpu, frameptr + 16, env->regs[12],
181
+ mmu_idx, STACK_NORMAL) &&
182
+ v7m_stack_write(cpu, frameptr + 20, env->regs[14],
183
+ mmu_idx, STACK_NORMAL) &&
184
+ v7m_stack_write(cpu, frameptr + 24, env->regs[15],
185
+ mmu_idx, STACK_NORMAL) &&
186
+ v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, STACK_NORMAL);
187
188
if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) {
189
/* FPU is active, try to save its registers */
190
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_stack(ARMCPU *cpu)
191
faddr += 8; /* skip the slot for the FPSCR */
192
}
193
stacked_ok = stacked_ok &&
194
- v7m_stack_write(cpu, faddr, slo, mmu_idx, false) &&
195
- v7m_stack_write(cpu, faddr + 4, shi, mmu_idx, false);
196
+ v7m_stack_write(cpu, faddr, slo,
197
+ mmu_idx, STACK_NORMAL) &&
198
+ v7m_stack_write(cpu, faddr + 4, shi,
199
+ mmu_idx, STACK_NORMAL);
200
}
201
stacked_ok = stacked_ok &&
202
v7m_stack_write(cpu, frameptr + 0x60,
203
- vfp_get_fpscr(env), mmu_idx, false);
204
+ vfp_get_fpscr(env), mmu_idx, STACK_NORMAL);
205
if (cpacr_pass) {
206
for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
207
*aa32_vfp_dreg(env, i / 2) = 0;
208
--
67
--
209
2.20.1
68
2.20.1
210
69
211
70
diff view generated by jsdifflib
1
Add a new helper function which returns the MMU index to use
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
for v7M, where the caller specifies all of the security
3
state, privilege level and whether the execution priority
4
is negative, and reimplement the existing
5
arm_v7m_mmu_idx_for_secstate_and_priv() in terms of it.
6
2
7
We are going to need this for the lazy-FP-stacking code.
3
The realize() function is clearly composed of two parts,
4
each described by a comment:
8
5
6
void realize()
7
{
8
/* common peripherals from bcm2835 */
9
...
10
/* bcm2836 interrupt controller (and mailboxes, etc.) */
11
...
12
}
13
14
Split the two part, so we can reuse the common part with other
15
SoCs from this family.
16
17
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
18
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
19
Message-id: 20201024170127.3592182-6-f4bug@amsat.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
Message-id: 20190416125744.27770-21-peter.maydell@linaro.org
12
---
21
---
13
target/arm/cpu.h | 7 +++++++
22
hw/arm/bcm2836.c | 22 ++++++++++++++++++----
14
target/arm/helper.c | 14 +++++++++++---
23
1 file changed, 18 insertions(+), 4 deletions(-)
15
2 files changed, 18 insertions(+), 3 deletions(-)
16
24
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
25
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
18
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpu.h
27
--- a/hw/arm/bcm2836.c
20
+++ b/target/arm/cpu.h
28
+++ b/hw/arm/bcm2836.c
21
@@ -XXX,XX +XXX,XX @@ static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
29
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
30
qdev_prop_set_uint32(DEVICE(obj), "enabled-cpus", bc->core_count);
22
}
31
}
32
33
- object_initialize_child(obj, "control", &s->control, TYPE_BCM2836_CONTROL);
34
+ if (bc->ctrl_base) {
35
+ object_initialize_child(obj, "control", &s->control,
36
+ TYPE_BCM2836_CONTROL);
37
+ }
38
39
object_initialize_child(obj, "peripherals", &s->peripherals,
40
TYPE_BCM2835_PERIPHERALS);
41
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
42
"vcram-size");
23
}
43
}
24
44
25
+/*
45
-static void bcm2836_realize(DeviceState *dev, Error **errp)
26
+ * Return the MMU index for a v7M CPU with all relevant information
46
+static bool bcm283x_common_realize(DeviceState *dev, Error **errp)
27
+ * manually specified.
28
+ */
29
+ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env,
30
+ bool secstate, bool priv, bool negpri);
31
+
32
/* Return the MMU index for a v7M CPU in the specified security and
33
* privilege state.
34
*/
35
diff --git a/target/arm/helper.c b/target/arm/helper.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/target/arm/helper.c
38
+++ b/target/arm/helper.c
39
@@ -XXX,XX +XXX,XX @@ int fp_exception_el(CPUARMState *env, int cur_el)
40
return 0;
41
}
42
43
-ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
44
- bool secstate, bool priv)
45
+ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env,
46
+ bool secstate, bool priv, bool negpri)
47
{
47
{
48
ARMMMUIdx mmu_idx = ARM_MMU_IDX_M;
48
BCM283XState *s = BCM283X(dev);
49
49
BCM283XClass *bc = BCM283X_GET_CLASS(dev);
50
@@ -XXX,XX +XXX,XX @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
50
Object *obj;
51
mmu_idx |= ARM_MMU_IDX_M_PRIV;
51
- int n;
52
53
/* common peripherals from bcm2835 */
54
55
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
56
object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj);
57
58
if (!sysbus_realize(SYS_BUS_DEVICE(&s->peripherals), errp)) {
59
- return;
60
+ return false;
52
}
61
}
53
62
54
- if (armv7m_nvic_neg_prio_requested(env->nvic, secstate)) {
63
object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals),
55
+ if (negpri) {
64
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
56
mmu_idx |= ARM_MMU_IDX_M_NEGPRI;
65
57
}
66
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
58
67
bc->peri_base, 1);
59
@@ -XXX,XX +XXX,XX @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
68
+ return true;
60
return mmu_idx;
61
}
62
63
+ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
64
+ bool secstate, bool priv)
65
+{
66
+ bool negpri = armv7m_nvic_neg_prio_requested(env->nvic, secstate);
67
+
68
+ return arm_v7m_mmu_idx_all(env, secstate, priv, negpri);
69
+}
69
+}
70
+
70
+
71
/* Return the MMU index for a v7M CPU in the specified security state */
71
+static void bcm2836_realize(DeviceState *dev, Error **errp)
72
ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate)
72
+{
73
{
73
+ BCM283XState *s = BCM283X(dev);
74
+ BCM283XClass *bc = BCM283X_GET_CLASS(dev);
75
+ int n;
76
+
77
+ if (!bcm283x_common_realize(dev, errp)) {
78
+ return;
79
+ }
80
81
/* bcm2836 interrupt controller (and mailboxes, etc.) */
82
if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), errp)) {
74
--
83
--
75
2.20.1
84
2.20.1
76
85
77
86
diff view generated by jsdifflib
1
Implement the VLLDM instruction for v7M for the FPU present cas.
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
4
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
Message-id: 20201024170127.3592182-7-f4bug@amsat.org
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20190416125744.27770-26-peter.maydell@linaro.org
6
---
7
---
7
target/arm/helper.h | 1 +
8
include/hw/arm/bcm2836.h | 1 +
8
target/arm/helper.c | 54 ++++++++++++++++++++++++++++++++++++++++++
9
hw/arm/bcm2836.c | 34 ++++++++++++++++++++++++++++++++++
9
target/arm/translate.c | 2 +-
10
hw/arm/raspi.c | 2 ++
10
3 files changed, 56 insertions(+), 1 deletion(-)
11
3 files changed, 37 insertions(+)
11
12
12
diff --git a/target/arm/helper.h b/target/arm/helper.h
13
diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h
13
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/helper.h
15
--- a/include/hw/arm/bcm2836.h
15
+++ b/target/arm/helper.h
16
+++ b/include/hw/arm/bcm2836.h
16
@@ -XXX,XX +XXX,XX @@ DEF_HELPER_3(v7m_tt, i32, env, i32, i32)
17
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_TYPE(BCM283XState, BCM283XClass, BCM283X)
17
DEF_HELPER_1(v7m_preserve_fp_state, void, env)
18
* them, code using these devices should always handle them via the
18
19
* BCM283x base class, so they have no BCM2836(obj) etc macros.
19
DEF_HELPER_2(v7m_vlstm, void, env, i32)
20
*/
20
+DEF_HELPER_2(v7m_vlldm, void, env, i32)
21
+#define TYPE_BCM2835 "bcm2835"
21
22
#define TYPE_BCM2836 "bcm2836"
22
DEF_HELPER_2(v8m_stackcheck, void, env, i32)
23
#define TYPE_BCM2837 "bcm2837"
23
24
24
diff --git a/target/arm/helper.c b/target/arm/helper.c
25
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
25
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
26
--- a/target/arm/helper.c
27
--- a/hw/arm/bcm2836.c
27
+++ b/target/arm/helper.c
28
+++ b/hw/arm/bcm2836.c
28
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
29
@@ -XXX,XX +XXX,XX @@ static bool bcm283x_common_realize(DeviceState *dev, Error **errp)
29
g_assert_not_reached();
30
return true;
30
}
31
}
31
32
32
+void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
33
+static void bcm2835_realize(DeviceState *dev, Error **errp)
33
+{
34
+{
34
+ /* translate.c should never generate calls here in user-only mode */
35
+ BCM283XState *s = BCM283X(dev);
35
+ g_assert_not_reached();
36
+}
37
+
36
+
38
uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
37
+ if (!bcm283x_common_realize(dev, errp)) {
39
{
40
/* The TT instructions can be used by unprivileged code, but in
41
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
42
env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
43
}
44
45
+void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
46
+{
47
+ /* fptr is the value of Rn, the frame pointer we load the FP regs from */
48
+ assert(env->v7m.secure);
49
+
50
+ if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
51
+ return;
38
+ return;
52
+ }
39
+ }
53
+
40
+
54
+ /* Check access to the coprocessor is permitted */
41
+ if (!qdev_realize(DEVICE(&s->cpu[0].core), NULL, errp)) {
55
+ if (!v7m_cpacr_pass(env, true, arm_current_el(env) != 0)) {
42
+ return;
56
+ raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC());
57
+ }
43
+ }
58
+
44
+
59
+ if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) {
45
+ /* Connect irq/fiq outputs from the interrupt controller. */
60
+ /* State in FP is still valid */
46
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
61
+ env->v7m.fpccr[M_REG_S] &= ~R_V7M_FPCCR_LSPACT_MASK;
47
+ qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_IRQ));
62
+ } else {
48
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
63
+ bool ts = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
49
+ qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_FIQ));
64
+ int i;
65
+ uint32_t fpscr;
66
+
67
+ if (fptr & 7) {
68
+ raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC());
69
+ }
70
+
71
+ for (i = 0; i < (ts ? 32 : 16); i += 2) {
72
+ uint32_t slo, shi;
73
+ uint64_t dn;
74
+ uint32_t faddr = fptr + 4 * i;
75
+
76
+ if (i >= 16) {
77
+ faddr += 8; /* skip the slot for the FPSCR */
78
+ }
79
+
80
+ slo = cpu_ldl_data(env, faddr);
81
+ shi = cpu_ldl_data(env, faddr + 4);
82
+
83
+ dn = (uint64_t) shi << 32 | slo;
84
+ *aa32_vfp_dreg(env, i / 2) = dn;
85
+ }
86
+ fpscr = cpu_ldl_data(env, fptr + 0x40);
87
+ vfp_set_fpscr(env, fpscr);
88
+ }
89
+
90
+ env->v7m.control[M_REG_S] |= R_V7M_CONTROL_FPCA_MASK;
91
+}
50
+}
92
+
51
+
93
static bool v7m_push_stack(ARMCPU *cpu)
52
static void bcm2836_realize(DeviceState *dev, Error **errp)
94
{
53
{
95
/* Do the "set up stack frame" part of exception entry,
54
BCM283XState *s = BCM283X(dev);
96
diff --git a/target/arm/translate.c b/target/arm/translate.c
55
@@ -XXX,XX +XXX,XX @@ static void bcm283x_class_init(ObjectClass *oc, void *data)
56
dc->user_creatable = false;
57
}
58
59
+static void bcm2835_class_init(ObjectClass *oc, void *data)
60
+{
61
+ DeviceClass *dc = DEVICE_CLASS(oc);
62
+ BCM283XClass *bc = BCM283X_CLASS(oc);
63
+
64
+ bc->cpu_type = ARM_CPU_TYPE_NAME("arm1176");
65
+ bc->core_count = 1;
66
+ bc->peri_base = 0x20000000;
67
+ dc->realize = bcm2835_realize;
68
+};
69
+
70
static void bcm2836_class_init(ObjectClass *oc, void *data)
71
{
72
DeviceClass *dc = DEVICE_CLASS(oc);
73
@@ -XXX,XX +XXX,XX @@ static void bcm2837_class_init(ObjectClass *oc, void *data)
74
75
static const TypeInfo bcm283x_types[] = {
76
{
77
+ .name = TYPE_BCM2835,
78
+ .parent = TYPE_BCM283X,
79
+ .class_init = bcm2835_class_init,
80
+ }, {
81
.name = TYPE_BCM2836,
82
.parent = TYPE_BCM283X,
83
.class_init = bcm2836_class_init,
84
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
97
index XXXXXXX..XXXXXXX 100644
85
index XXXXXXX..XXXXXXX 100644
98
--- a/target/arm/translate.c
86
--- a/hw/arm/raspi.c
99
+++ b/target/arm/translate.c
87
+++ b/hw/arm/raspi.c
100
@@ -XXX,XX +XXX,XX @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
88
@@ -XXX,XX +XXX,XX @@ FIELD(REV_CODE, MEMORY_SIZE, 20, 3);
101
TCGv_i32 fptr = load_reg(s, rn);
89
FIELD(REV_CODE, STYLE, 23, 1);
102
90
103
if (extract32(insn, 20, 1)) {
91
typedef enum RaspiProcessorId {
104
- /* VLLDM */
92
+ PROCESSOR_ID_BCM2835 = 0,
105
+ gen_helper_v7m_vlldm(cpu_env, fptr);
93
PROCESSOR_ID_BCM2836 = 1,
106
} else {
94
PROCESSOR_ID_BCM2837 = 2,
107
gen_helper_v7m_vlstm(cpu_env, fptr);
95
} RaspiProcessorId;
108
}
96
@@ -XXX,XX +XXX,XX @@ static const struct {
97
const char *type;
98
int cores_count;
99
} soc_property[] = {
100
+ [PROCESSOR_ID_BCM2835] = {TYPE_BCM2835, 1},
101
[PROCESSOR_ID_BCM2836] = {TYPE_BCM2836, BCM283X_NCPUS},
102
[PROCESSOR_ID_BCM2837] = {TYPE_BCM2837, BCM283X_NCPUS},
103
};
109
--
104
--
110
2.20.1
105
2.20.1
111
106
112
107
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
Reviewed-by: Markus Armbruster <armbru@redhat.com>
3
The Pi A is almost the first machine released.
4
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
4
It uses a BCM2835 SoC which includes a ARMv6Z core.
5
Message-id: 20190412165416.7977-8-philmd@redhat.com
5
6
Example booting the machine using content from [*]
7
(we use the device tree from the B model):
8
9
$ qemu-system-arm -M raspi1ap -serial stdio \
10
-kernel raspberrypi/firmware/boot/kernel.img \
11
-dtb raspberrypi/firmware/boot/bcm2708-rpi-b-plus.dtb \
12
-append 'earlycon=pl011,0x20201000 console=ttyAMA0'
13
[ 0.000000] Booting Linux on physical CPU 0x0
14
[ 0.000000] Linux version 4.19.118+ (dom@buildbot) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1311 Mon Apr 27 14:16:15 BST 2020
15
[ 0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
16
[ 0.000000] CPU: VIPT aliasing data cache, unknown instruction cache
17
[ 0.000000] OF: fdt: Machine model: Raspberry Pi Model B+
18
...
19
20
[*] http://archive.raspberrypi.org/debian/pool/main/r/raspberrypi-firmware/raspberrypi-kernel_1.20200512-2_armhf.deb
21
22
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
23
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Message-id: 20201024170127.3592182-8-f4bug@amsat.org
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
26
---
8
include/hw/devices.h | 3 ---
27
hw/arm/raspi.c | 13 +++++++++++++
9
include/hw/input/gamepad.h | 19 +++++++++++++++++++
28
1 file changed, 13 insertions(+)
10
hw/arm/stellaris.c | 2 +-
11
hw/input/stellaris_input.c | 2 +-
12
MAINTAINERS | 1 +
13
5 files changed, 22 insertions(+), 5 deletions(-)
14
create mode 100644 include/hw/input/gamepad.h
15
29
16
diff --git a/include/hw/devices.h b/include/hw/devices.h
30
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
17
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
18
--- a/include/hw/devices.h
32
--- a/hw/arm/raspi.c
19
+++ b/include/hw/devices.h
33
+++ b/hw/arm/raspi.c
20
@@ -XXX,XX +XXX,XX @@ void *tsc2005_init(qemu_irq pintdav);
34
@@ -XXX,XX +XXX,XX @@ static void raspi_machine_class_common_init(MachineClass *mc,
21
uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len);
35
mc->default_ram_id = "ram";
22
void tsc2005_set_transform(void *opaque, MouseTransformInfo *info);
36
};
23
37
24
-/* stellaris_input.c */
38
+static void raspi1ap_machine_class_init(ObjectClass *oc, void *data)
25
-void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode);
39
+{
26
-
40
+ MachineClass *mc = MACHINE_CLASS(oc);
27
#endif
41
+ RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
28
diff --git a/include/hw/input/gamepad.h b/include/hw/input/gamepad.h
29
new file mode 100644
30
index XXXXXXX..XXXXXXX
31
--- /dev/null
32
+++ b/include/hw/input/gamepad.h
33
@@ -XXX,XX +XXX,XX @@
34
+/*
35
+ * Gamepad style buttons connected to IRQ/GPIO lines
36
+ *
37
+ * Copyright (c) 2007 CodeSourcery.
38
+ * Written by Paul Brook
39
+ *
40
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
41
+ * See the COPYING file in the top-level directory.
42
+ */
43
+
42
+
44
+#ifndef HW_INPUT_GAMEPAD_H
43
+ rmc->board_rev = 0x900021; /* Revision 1.1 */
45
+#define HW_INPUT_GAMEPAD_H
44
+ raspi_machine_class_common_init(mc, rmc->board_rev);
45
+};
46
+
46
+
47
+#include "hw/irq.h"
47
static void raspi2b_machine_class_init(ObjectClass *oc, void *data)
48
+
48
{
49
+/* stellaris_input.c */
49
MachineClass *mc = MACHINE_CLASS(oc);
50
+void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode);
50
@@ -XXX,XX +XXX,XX @@ static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
51
+
51
52
+#endif
52
static const TypeInfo raspi_machine_types[] = {
53
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
53
{
54
index XXXXXXX..XXXXXXX 100644
54
+ .name = MACHINE_TYPE_NAME("raspi1ap"),
55
--- a/hw/arm/stellaris.c
55
+ .parent = TYPE_RASPI_MACHINE,
56
+++ b/hw/arm/stellaris.c
56
+ .class_init = raspi1ap_machine_class_init,
57
@@ -XXX,XX +XXX,XX @@
57
+ }, {
58
#include "hw/sysbus.h"
58
.name = MACHINE_TYPE_NAME("raspi2b"),
59
#include "hw/ssi/ssi.h"
59
.parent = TYPE_RASPI_MACHINE,
60
#include "hw/arm/arm.h"
60
.class_init = raspi2b_machine_class_init,
61
-#include "hw/devices.h"
62
#include "qemu/timer.h"
63
#include "hw/i2c/i2c.h"
64
#include "net/net.h"
65
@@ -XXX,XX +XXX,XX @@
66
#include "sysemu/sysemu.h"
67
#include "hw/arm/armv7m.h"
68
#include "hw/char/pl011.h"
69
+#include "hw/input/gamepad.h"
70
#include "hw/watchdog/cmsdk-apb-watchdog.h"
71
#include "hw/misc/unimp.h"
72
#include "cpu.h"
73
diff --git a/hw/input/stellaris_input.c b/hw/input/stellaris_input.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/hw/input/stellaris_input.c
76
+++ b/hw/input/stellaris_input.c
77
@@ -XXX,XX +XXX,XX @@
78
*/
79
#include "qemu/osdep.h"
80
#include "hw/hw.h"
81
-#include "hw/devices.h"
82
+#include "hw/input/gamepad.h"
83
#include "ui/console.h"
84
85
typedef struct {
86
diff --git a/MAINTAINERS b/MAINTAINERS
87
index XXXXXXX..XXXXXXX 100644
88
--- a/MAINTAINERS
89
+++ b/MAINTAINERS
90
@@ -XXX,XX +XXX,XX @@ M: Peter Maydell <peter.maydell@linaro.org>
91
L: qemu-arm@nongnu.org
92
S: Maintained
93
F: hw/*/stellaris*
94
+F: include/hw/input/gamepad.h
95
96
Versatile Express
97
M: Peter Maydell <peter.maydell@linaro.org>
98
--
61
--
99
2.20.1
62
2.20.1
100
63
101
64
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
Reviewed-by: Thomas Huth <thuth@redhat.com>
3
Similarly to the Pi A, the Pi Zero uses a BCM2835 SoC (ARMv6Z core).
4
Reviewed-by: Markus Armbruster <armbru@redhat.com>
4
5
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
5
The only difference between the revision 1.2 and 1.3 is the latter
6
Message-id: 20190412165416.7977-7-philmd@redhat.com
6
exposes a CSI camera connector. As we do not implement the Unicam
7
peripheral, there is no point in exposing a camera connector :)
8
Therefore we choose to model the 1.2 revision.
9
10
Example booting the machine using content from [*]:
11
12
$ qemu-system-arm -M raspi0 -serial stdio \
13
-kernel raspberrypi/firmware/boot/kernel.img \
14
-dtb raspberrypi/firmware/boot/bcm2708-rpi-zero.dtb \
15
-append 'printk.time=0 earlycon=pl011,0x20201000 console=ttyAMA0'
16
[ 0.000000] Booting Linux on physical CPU 0x0
17
[ 0.000000] Linux version 4.19.118+ (dom@buildbot) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1311 Mon Apr 27 14:16:15 BST 2020
18
[ 0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
19
[ 0.000000] CPU: VIPT aliasing data cache, unknown instruction cache
20
[ 0.000000] OF: fdt: Machine model: Raspberry Pi Zero
21
...
22
23
[*] http://archive.raspberrypi.org/debian/pool/main/r/raspberrypi-firmware/raspberrypi-kernel_1.20200512-2_armhf.deb
24
25
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
26
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
27
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
28
Message-id: 20201024170127.3592182-9-f4bug@amsat.org
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
29
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
30
---
9
include/hw/devices.h | 14 --------------
31
hw/arm/raspi.c | 13 +++++++++++++
10
include/hw/misc/cbus.h | 32 ++++++++++++++++++++++++++++++++
32
1 file changed, 13 insertions(+)
11
hw/arm/nseries.c | 1 +
12
hw/misc/cbus.c | 2 +-
13
MAINTAINERS | 1 +
14
5 files changed, 35 insertions(+), 15 deletions(-)
15
create mode 100644 include/hw/misc/cbus.h
16
33
17
diff --git a/include/hw/devices.h b/include/hw/devices.h
34
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
18
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
19
--- a/include/hw/devices.h
36
--- a/hw/arm/raspi.c
20
+++ b/include/hw/devices.h
37
+++ b/hw/arm/raspi.c
21
@@ -XXX,XX +XXX,XX @@ void tsc2005_set_transform(void *opaque, MouseTransformInfo *info);
38
@@ -XXX,XX +XXX,XX @@ static void raspi_machine_class_common_init(MachineClass *mc,
22
/* stellaris_input.c */
39
mc->default_ram_id = "ram";
23
void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode);
40
};
24
41
25
-/* cbus.c */
42
+static void raspi0_machine_class_init(ObjectClass *oc, void *data)
26
-typedef struct {
43
+{
27
- qemu_irq clk;
44
+ MachineClass *mc = MACHINE_CLASS(oc);
28
- qemu_irq dat;
45
+ RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
29
- qemu_irq sel;
30
-} CBus;
31
-CBus *cbus_init(qemu_irq dat_out);
32
-void cbus_attach(CBus *bus, void *slave_opaque);
33
-
34
-void *retu_init(qemu_irq irq, int vilma);
35
-void *tahvo_init(qemu_irq irq, int betty);
36
-
37
-void retu_key_event(void *retu, int state);
38
-
39
#endif
40
diff --git a/include/hw/misc/cbus.h b/include/hw/misc/cbus.h
41
new file mode 100644
42
index XXXXXXX..XXXXXXX
43
--- /dev/null
44
+++ b/include/hw/misc/cbus.h
45
@@ -XXX,XX +XXX,XX @@
46
+/*
47
+ * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
48
+ * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
49
+ * Based on reverse-engineering of a linux driver.
50
+ *
51
+ * Copyright (C) 2008 Nokia Corporation
52
+ * Written by Andrzej Zaborowski
53
+ *
54
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
55
+ * See the COPYING file in the top-level directory.
56
+ */
57
+
46
+
58
+#ifndef HW_MISC_CBUS_H
47
+ rmc->board_rev = 0x920092; /* Revision 1.2 */
59
+#define HW_MISC_CBUS_H
48
+ raspi_machine_class_common_init(mc, rmc->board_rev);
49
+};
60
+
50
+
61
+#include "hw/irq.h"
51
static void raspi1ap_machine_class_init(ObjectClass *oc, void *data)
62
+
52
{
63
+typedef struct {
53
MachineClass *mc = MACHINE_CLASS(oc);
64
+ qemu_irq clk;
54
@@ -XXX,XX +XXX,XX @@ static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
65
+ qemu_irq dat;
55
66
+ qemu_irq sel;
56
static const TypeInfo raspi_machine_types[] = {
67
+} CBus;
57
{
68
+
58
+ .name = MACHINE_TYPE_NAME("raspi0"),
69
+CBus *cbus_init(qemu_irq dat_out);
59
+ .parent = TYPE_RASPI_MACHINE,
70
+void cbus_attach(CBus *bus, void *slave_opaque);
60
+ .class_init = raspi0_machine_class_init,
71
+
61
+ }, {
72
+void *retu_init(qemu_irq irq, int vilma);
62
.name = MACHINE_TYPE_NAME("raspi1ap"),
73
+void *tahvo_init(qemu_irq irq, int betty);
63
.parent = TYPE_RASPI_MACHINE,
74
+
64
.class_init = raspi1ap_machine_class_init,
75
+void retu_key_event(void *retu, int state);
76
+
77
+#endif
78
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
79
index XXXXXXX..XXXXXXX 100644
80
--- a/hw/arm/nseries.c
81
+++ b/hw/arm/nseries.c
82
@@ -XXX,XX +XXX,XX @@
83
#include "hw/i2c/i2c.h"
84
#include "hw/devices.h"
85
#include "hw/display/blizzard.h"
86
+#include "hw/misc/cbus.h"
87
#include "hw/misc/tmp105.h"
88
#include "hw/block/flash.h"
89
#include "hw/hw.h"
90
diff --git a/hw/misc/cbus.c b/hw/misc/cbus.c
91
index XXXXXXX..XXXXXXX 100644
92
--- a/hw/misc/cbus.c
93
+++ b/hw/misc/cbus.c
94
@@ -XXX,XX +XXX,XX @@
95
#include "qemu/osdep.h"
96
#include "hw/hw.h"
97
#include "hw/irq.h"
98
-#include "hw/devices.h"
99
+#include "hw/misc/cbus.h"
100
#include "sysemu/sysemu.h"
101
102
//#define DEBUG
103
diff --git a/MAINTAINERS b/MAINTAINERS
104
index XXXXXXX..XXXXXXX 100644
105
--- a/MAINTAINERS
106
+++ b/MAINTAINERS
107
@@ -XXX,XX +XXX,XX @@ F: hw/input/tsc2005.c
108
F: hw/misc/cbus.c
109
F: hw/timer/twl92230.c
110
F: include/hw/display/blizzard.h
111
+F: include/hw/misc/cbus.h
112
113
Palm
114
M: Andrzej Zaborowski <balrogg@gmail.com>
115
--
65
--
116
2.20.1
66
2.20.1
117
67
118
68
diff view generated by jsdifflib
1
Enable the FPU by default for the Cortex-M4 and Cortex-M33.
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
The Pi 3A+ is a stripped down version of the 3B:
4
- 512 MiB of RAM instead of 1 GiB
5
- no on-board ethernet chipset
6
7
Add it as it is a closer match to what we model.
8
9
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
10
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Message-id: 20201024170127.3592182-10-f4bug@amsat.org
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20190416125744.27770-27-peter.maydell@linaro.org
6
---
13
---
7
target/arm/cpu.c | 8 ++++++++
14
hw/arm/raspi.c | 13 +++++++++++++
8
1 file changed, 8 insertions(+)
15
1 file changed, 13 insertions(+)
9
16
10
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
17
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
11
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
12
--- a/target/arm/cpu.c
19
--- a/hw/arm/raspi.c
13
+++ b/target/arm/cpu.c
20
+++ b/hw/arm/raspi.c
14
@@ -XXX,XX +XXX,XX @@ static void cortex_m4_initfn(Object *obj)
21
@@ -XXX,XX +XXX,XX @@ static void raspi2b_machine_class_init(ObjectClass *oc, void *data)
15
set_feature(&cpu->env, ARM_FEATURE_M);
22
};
16
set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
23
17
set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
24
#ifdef TARGET_AARCH64
18
+ set_feature(&cpu->env, ARM_FEATURE_VFP4);
25
+static void raspi3ap_machine_class_init(ObjectClass *oc, void *data)
19
cpu->midr = 0x410fc240; /* r0p0 */
26
+{
20
cpu->pmsav7_dregion = 8;
27
+ MachineClass *mc = MACHINE_CLASS(oc);
21
+ cpu->isar.mvfr0 = 0x10110021;
28
+ RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
22
+ cpu->isar.mvfr1 = 0x11000011;
29
+
23
+ cpu->isar.mvfr2 = 0x00000000;
30
+ rmc->board_rev = 0x9020e0; /* Revision 1.0 */
24
cpu->id_pfr0 = 0x00000030;
31
+ raspi_machine_class_common_init(mc, rmc->board_rev);
25
cpu->id_pfr1 = 0x00000200;
32
+};
26
cpu->id_dfr0 = 0x00100000;
33
+
27
@@ -XXX,XX +XXX,XX @@ static void cortex_m33_initfn(Object *obj)
34
static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
28
set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
35
{
29
set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
36
MachineClass *mc = MACHINE_CLASS(oc);
30
set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
37
@@ -XXX,XX +XXX,XX @@ static const TypeInfo raspi_machine_types[] = {
31
+ set_feature(&cpu->env, ARM_FEATURE_VFP4);
38
.parent = TYPE_RASPI_MACHINE,
32
cpu->midr = 0x410fd213; /* r0p3 */
39
.class_init = raspi2b_machine_class_init,
33
cpu->pmsav7_dregion = 16;
40
#ifdef TARGET_AARCH64
34
cpu->sau_sregion = 8;
41
+ }, {
35
+ cpu->isar.mvfr0 = 0x10110021;
42
+ .name = MACHINE_TYPE_NAME("raspi3ap"),
36
+ cpu->isar.mvfr1 = 0x11000011;
43
+ .parent = TYPE_RASPI_MACHINE,
37
+ cpu->isar.mvfr2 = 0x00000040;
44
+ .class_init = raspi3ap_machine_class_init,
38
cpu->id_pfr0 = 0x00000030;
45
}, {
39
cpu->id_pfr1 = 0x00000210;
46
.name = MACHINE_TYPE_NAME("raspi3b"),
40
cpu->id_dfr0 = 0x00200000;
47
.parent = TYPE_RASPI_MACHINE,
41
--
48
--
42
2.20.1
49
2.20.1
43
50
44
51
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
2
2
3
This device is used by both ARM (BCM2836, for raspi2) and AArch64
3
Use of 0x%d - make up our mind as 0x%x
4
(BCM2837, for raspi3) targets, and is not CPU-specific.
5
Move it to common object, so we build it once for all targets.
6
4
7
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
5
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
8
Message-id: 20190427133028.12874-1-philmd@redhat.com
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Acked-by: Eric Auger <eric.auger@redhat.com>
8
Message-id: 20201014193355.53074-1-dgilbert@redhat.com
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
10
---
12
hw/dma/Makefile.objs | 2 +-
11
hw/arm/trace-events | 2 +-
13
1 file changed, 1 insertion(+), 1 deletion(-)
12
1 file changed, 1 insertion(+), 1 deletion(-)
14
13
15
diff --git a/hw/dma/Makefile.objs b/hw/dma/Makefile.objs
14
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
16
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/dma/Makefile.objs
16
--- a/hw/arm/trace-events
18
+++ b/hw/dma/Makefile.objs
17
+++ b/hw/arm/trace-events
19
@@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx-zdma.o
18
@@ -XXX,XX +XXX,XX @@ smmuv3_get_cd(uint64_t addr) "CD addr: 0x%"PRIx64
20
19
smmuv3_decode_cd(uint32_t oas) "oas=%d"
21
obj-$(CONFIG_OMAP) += omap_dma.o soc_dma.o
20
smmuv3_decode_cd_tt(int i, uint32_t tsz, uint64_t ttb, uint32_t granule_sz, bool had) "TT[%d]:tsz:%d ttb:0x%"PRIx64" granule_sz:%d had:%d"
22
obj-$(CONFIG_PXA2XX) += pxa2xx_dma.o
21
smmuv3_cmdq_cfgi_ste(int streamid) "streamid =%d"
23
-obj-$(CONFIG_RASPI) += bcm2835_dma.o
22
-smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%d - end=0x%d"
24
+common-obj-$(CONFIG_RASPI) += bcm2835_dma.o
23
+smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%x - end=0x%x"
24
smmuv3_cmdq_cfgi_cd(uint32_t sid) "streamid = %d"
25
smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid %d (hits=%d, misses=%d, hit rate=%d)"
26
smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid %d (hits=%d, misses=%d, hit rate=%d)"
25
--
27
--
26
2.20.1
28
2.20.1
27
29
28
30
diff view generated by jsdifflib
1
Correct the decode of the M-profile "coprocessor and
1
From: Luc Michel <luc@lmichel.fr>
2
floating-point instructions" space:
3
* op0 == 0b11 is always unallocated
4
* if the CPU has an FPU then all insns with op1 == 0b101
5
are floating point and go to disas_vfp_insn()
6
2
7
For the moment we leave VLLDM and VLSTM as NOPs; in
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
a later commit we will fill in the proper implementation
4
Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>
9
for the case where an FPU is present.
5
Signed-off-by: Luc Michel <luc@lmichel.fr>
6
Tested-by: Guenter Roeck <linux@roeck-us.net>
7
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
include/hw/clock.h | 5 +++++
11
1 file changed, 5 insertions(+)
10
12
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
diff --git a/include/hw/clock.h b/include/hw/clock.h
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
13
Message-id: 20190416125744.27770-7-peter.maydell@linaro.org
14
---
15
target/arm/translate.c | 26 ++++++++++++++++++++++----
16
1 file changed, 22 insertions(+), 4 deletions(-)
17
18
diff --git a/target/arm/translate.c b/target/arm/translate.c
19
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
20
--- a/target/arm/translate.c
15
--- a/include/hw/clock.h
21
+++ b/target/arm/translate.c
16
+++ b/include/hw/clock.h
22
@@ -XXX,XX +XXX,XX @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
17
@@ -XXX,XX +XXX,XX @@ extern const VMStateDescription vmstate_clock;
23
case 6: case 7: case 14: case 15:
18
VMSTATE_CLOCK_V(field, state, 0)
24
/* Coprocessor. */
19
#define VMSTATE_CLOCK_V(field, state, version) \
25
if (arm_dc_feature(s, ARM_FEATURE_M)) {
20
VMSTATE_STRUCT_POINTER_V(field, state, version, vmstate_clock, Clock)
26
- /* We don't currently implement M profile FP support,
21
+#define VMSTATE_ARRAY_CLOCK(field, state, num) \
27
- * so this entire space should give a NOCP fault, with
22
+ VMSTATE_ARRAY_CLOCK_V(field, state, num, 0)
28
- * the exception of the v8M VLLDM and VLSTM insns, which
23
+#define VMSTATE_ARRAY_CLOCK_V(field, state, num, version) \
29
- * must be NOPs in Secure state and UNDEF in Nonsecure state.
24
+ VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(field, state, num, version, \
30
+ /* 0b111x_11xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx */
25
+ vmstate_clock, Clock)
31
+ if (extract32(insn, 24, 2) == 3) {
26
32
+ goto illegal_op; /* op0 = 0b11 : unallocated */
27
/**
33
+ }
28
* clock_setup_canonical_path:
34
+
35
+ /*
36
+ * Decode VLLDM and VLSTM first: these are nonstandard because:
37
+ * * if there is no FPU then these insns must NOP in
38
+ * Secure state and UNDEF in Nonsecure state
39
+ * * if there is an FPU then these insns do not have
40
+ * the usual behaviour that disas_vfp_insn() provides of
41
+ * being controlled by CPACR/NSACR enable bits or the
42
+ * lazy-stacking logic.
43
*/
44
if (arm_dc_feature(s, ARM_FEATURE_V8) &&
45
(insn & 0xffa00f00) == 0xec200a00) {
46
@@ -XXX,XX +XXX,XX @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
47
/* Just NOP since FP support is not implemented */
48
break;
49
}
50
+ if (arm_dc_feature(s, ARM_FEATURE_VFP) &&
51
+ ((insn >> 8) & 0xe) == 10) {
52
+ /* FP, and the CPU supports it */
53
+ if (disas_vfp_insn(s, insn)) {
54
+ goto illegal_op;
55
+ }
56
+ break;
57
+ }
58
+
59
/* All other insns: NOCP */
60
gen_exception_insn(s, 4, EXCP_NOCP, syn_uncategorized(),
61
default_exception_el(s));
62
--
29
--
63
2.20.1
30
2.20.1
64
31
65
32
diff view generated by jsdifflib
1
The only "system register" that M-profile floating point exposes
1
From: Luc Michel <luc@lmichel.fr>
2
via the VMRS/VMRS instructions is FPSCR, and it does not have
3
the odd special case for rd==15. Add a check to ensure we only
4
expose FPSCR.
5
2
3
The nanosecond unit greatly limits the dynamic range we can display in
4
clock value traces, for values in the order of 1GHz and more. The
5
internal representation can go way beyond this value and it is quite
6
common for today's clocks to be within those ranges.
7
8
For example, a frequency between 500MHz+ and 1GHz will be displayed as
9
1ns. Beyond 1GHz, it will show up as 0ns.
10
11
Replace nanosecond periods traces with frequencies in the Hz unit
12
to have more dynamic range in the trace output.
13
14
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
15
Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>
16
Signed-off-by: Luc Michel <luc@lmichel.fr>
17
Tested-by: Guenter Roeck <linux@roeck-us.net>
18
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20190416125744.27770-5-peter.maydell@linaro.org
9
---
20
---
10
target/arm/translate.c | 19 +++++++++++++++++--
21
hw/core/clock.c | 6 +++---
11
1 file changed, 17 insertions(+), 2 deletions(-)
22
hw/core/trace-events | 4 ++--
23
2 files changed, 5 insertions(+), 5 deletions(-)
12
24
13
diff --git a/target/arm/translate.c b/target/arm/translate.c
25
diff --git a/hw/core/clock.c b/hw/core/clock.c
14
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/translate.c
27
--- a/hw/core/clock.c
16
+++ b/target/arm/translate.c
28
+++ b/hw/core/clock.c
17
@@ -XXX,XX +XXX,XX @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
29
@@ -XXX,XX +XXX,XX @@ bool clock_set(Clock *clk, uint64_t period)
18
}
30
if (clk->period == period) {
19
}
31
return false;
20
} else { /* !dp */
32
}
21
+ bool is_sysreg;
33
- trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_NS(clk->period),
22
+
34
- CLOCK_PERIOD_TO_NS(period));
23
if ((insn & 0x6f) != 0x00)
35
+ trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_HZ(clk->period),
24
return 1;
36
+ CLOCK_PERIOD_TO_HZ(period));
25
rn = VFP_SREG_N(insn);
37
clk->period = period;
26
+
38
27
+ is_sysreg = extract32(insn, 21, 1);
39
return true;
28
+
40
@@ -XXX,XX +XXX,XX @@ static void clock_propagate_period(Clock *clk, bool call_callbacks)
29
+ if (arm_dc_feature(s, ARM_FEATURE_M)) {
41
if (child->period != clk->period) {
30
+ /*
42
child->period = clk->period;
31
+ * The only M-profile VFP vmrs/vmsr sysreg is FPSCR.
43
trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
32
+ * Writes to R15 are UNPREDICTABLE; we choose to undef.
44
- CLOCK_PERIOD_TO_NS(clk->period),
33
+ */
45
+ CLOCK_PERIOD_TO_HZ(clk->period),
34
+ if (is_sysreg && (rd == 15 || (rn >> 1) != ARM_VFP_FPSCR)) {
46
call_callbacks);
35
+ return 1;
47
if (call_callbacks && child->callback) {
36
+ }
48
child->callback(child->callback_opaque);
37
+ }
49
diff --git a/hw/core/trace-events b/hw/core/trace-events
38
+
50
index XXXXXXX..XXXXXXX 100644
39
if (insn & ARM_CP_RW_BIT) {
51
--- a/hw/core/trace-events
40
/* vfp->arm */
52
+++ b/hw/core/trace-events
41
- if (insn & (1 << 21)) {
53
@@ -XXX,XX +XXX,XX @@ resettable_transitional_function(void *obj, const char *objtype) "obj=%p(%s)"
42
+ if (is_sysreg) {
54
# clock.c
43
/* system register */
55
clock_set_source(const char *clk, const char *src) "'%s', src='%s'"
44
rn >>= 1;
56
clock_disconnect(const char *clk) "'%s'"
45
57
-clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', ns=%"PRIu64"->%"PRIu64
46
@@ -XXX,XX +XXX,XX @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
58
+clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', %"PRIu64"Hz->%"PRIu64"Hz"
47
}
59
clock_propagate(const char *clk) "'%s'"
48
} else {
60
-clock_update(const char *clk, const char *src, uint64_t val, int cb) "'%s', src='%s', ns=%"PRIu64", cb=%d"
49
/* arm->vfp */
61
+clock_update(const char *clk, const char *src, uint64_t hz, int cb) "'%s', src='%s', val=%"PRIu64"Hz cb=%d"
50
- if (insn & (1 << 21)) {
51
+ if (is_sysreg) {
52
rn >>= 1;
53
/* system register */
54
switch (rn) {
55
--
62
--
56
2.20.1
63
2.20.1
57
64
58
65
diff view generated by jsdifflib
1
For M-profile the MVFR* ID registers are memory mapped, in the
1
From: Luc Michel <luc@lmichel.fr>
2
range we implement via the NVIC. Allow them to be read.
3
(If the CPU has no FPU, these registers are defined to be RAZ.)
4
2
3
The CPRMAN (clock controller) was mapped at the watchdog/power manager
4
address. It was also split into two unimplemented peripherals (CM and
5
A2W) but this is really the same one, as shown by this extract of the
6
Raspberry Pi 3 Linux device tree:
7
8
watchdog@7e100000 {
9
compatible = "brcm,bcm2835-pm\0brcm,bcm2835-pm-wdt";
10
[...]
11
reg = <0x7e100000 0x114 0x7e00a000 0x24>;
12
[...]
13
};
14
15
[...]
16
cprman@7e101000 {
17
compatible = "brcm,bcm2835-cprman";
18
[...]
19
reg = <0x7e101000 0x2000>;
20
[...]
21
};
22
23
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Signed-off-by: Luc Michel <luc@lmichel.fr>
25
Tested-by: Guenter Roeck <linux@roeck-us.net>
26
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
27
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20190416125744.27770-3-peter.maydell@linaro.org
8
---
28
---
9
hw/intc/armv7m_nvic.c | 6 ++++++
29
include/hw/arm/bcm2835_peripherals.h | 2 +-
10
1 file changed, 6 insertions(+)
30
include/hw/arm/raspi_platform.h | 5 ++---
31
hw/arm/bcm2835_peripherals.c | 4 ++--
32
3 files changed, 5 insertions(+), 6 deletions(-)
11
33
12
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
34
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
13
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/intc/armv7m_nvic.c
36
--- a/include/hw/arm/bcm2835_peripherals.h
15
+++ b/hw/intc/armv7m_nvic.c
37
+++ b/include/hw/arm/bcm2835_peripherals.h
16
@@ -XXX,XX +XXX,XX @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
38
@@ -XXX,XX +XXX,XX @@ struct BCM2835PeripheralState {
17
return 0;
39
BCM2835MphiState mphi;
18
}
40
UnimplementedDeviceState txp;
19
return cpu->env.v7m.sfar;
41
UnimplementedDeviceState armtmr;
20
+ case 0xf40: /* MVFR0 */
42
+ UnimplementedDeviceState powermgt;
21
+ return cpu->isar.mvfr0;
43
UnimplementedDeviceState cprman;
22
+ case 0xf44: /* MVFR1 */
44
- UnimplementedDeviceState a2w;
23
+ return cpu->isar.mvfr1;
45
PL011State uart0;
24
+ case 0xf48: /* MVFR2 */
46
BCM2835AuxState aux;
25
+ return cpu->isar.mvfr2;
47
BCM2835FBState fb;
26
default:
48
diff --git a/include/hw/arm/raspi_platform.h b/include/hw/arm/raspi_platform.h
27
bad_offset:
49
index XXXXXXX..XXXXXXX 100644
28
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
50
--- a/include/hw/arm/raspi_platform.h
51
+++ b/include/hw/arm/raspi_platform.h
52
@@ -XXX,XX +XXX,XX @@
53
#define ARMCTRL_TIMER0_1_OFFSET (ARM_OFFSET + 0x400) /* Timer 0 and 1 (SP804) */
54
#define ARMCTRL_0_SBM_OFFSET (ARM_OFFSET + 0x800) /* User 0 (ARM) Semaphores
55
* Doorbells & Mailboxes */
56
-#define CPRMAN_OFFSET 0x100000 /* Power Management, Watchdog */
57
-#define CM_OFFSET 0x101000 /* Clock Management */
58
-#define A2W_OFFSET 0x102000 /* Reset controller */
59
+#define PM_OFFSET 0x100000 /* Power Management */
60
+#define CPRMAN_OFFSET 0x101000 /* Clock Management */
61
#define AVS_OFFSET 0x103000 /* Audio Video Standard */
62
#define RNG_OFFSET 0x104000
63
#define GPIO_OFFSET 0x200000
64
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/hw/arm/bcm2835_peripherals.c
67
+++ b/hw/arm/bcm2835_peripherals.c
68
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
69
70
create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000);
71
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
72
- create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x1000);
73
- create_unimp(s, &s->a2w, "bcm2835-a2w", A2W_OFFSET, 0x1000);
74
+ create_unimp(s, &s->powermgt, "bcm2835-powermgt", PM_OFFSET, 0x114);
75
+ create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x2000);
76
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);
77
create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100);
78
create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20);
29
--
79
--
30
2.20.1
80
2.20.1
31
81
32
82
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
Add an entries the Blizzard device in MAINTAINERS.
3
The BCM2835 CPRMAN is the clock manager of the SoC. It is composed of a
4
4
main oscillator, and several sub-components (PLLs, multiplexers, ...) to
5
Reviewed-by: Thomas Huth <thuth@redhat.com>
5
generate the BCM2835 clock tree.
6
Reviewed-by: Markus Armbruster <armbru@redhat.com>
6
7
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
This commit adds a skeleton of the CPRMAN, with a dummy register
8
Message-id: 20190412165416.7977-6-philmd@redhat.com
8
read/write implementation. It embeds the main oscillator (xosc) from
9
which all the clocks will be derived.
10
11
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
Signed-off-by: Luc Michel <luc@lmichel.fr>
14
Tested-by: Guenter Roeck <linux@roeck-us.net>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
16
---
11
include/hw/devices.h | 7 -------
17
include/hw/arm/bcm2835_peripherals.h | 3 +-
12
include/hw/display/blizzard.h | 22 ++++++++++++++++++++++
18
include/hw/misc/bcm2835_cprman.h | 37 +++++
13
hw/arm/nseries.c | 1 +
19
include/hw/misc/bcm2835_cprman_internals.h | 24 +++
14
hw/display/blizzard.c | 2 +-
20
hw/arm/bcm2835_peripherals.c | 11 +-
15
MAINTAINERS | 2 ++
21
hw/misc/bcm2835_cprman.c | 163 +++++++++++++++++++++
16
5 files changed, 26 insertions(+), 8 deletions(-)
22
hw/misc/meson.build | 1 +
17
create mode 100644 include/hw/display/blizzard.h
23
hw/misc/trace-events | 5 +
18
24
7 files changed, 242 insertions(+), 2 deletions(-)
19
diff --git a/include/hw/devices.h b/include/hw/devices.h
25
create mode 100644 include/hw/misc/bcm2835_cprman.h
26
create mode 100644 include/hw/misc/bcm2835_cprman_internals.h
27
create mode 100644 hw/misc/bcm2835_cprman.c
28
29
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
20
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
21
--- a/include/hw/devices.h
31
--- a/include/hw/arm/bcm2835_peripherals.h
22
+++ b/include/hw/devices.h
32
+++ b/include/hw/arm/bcm2835_peripherals.h
23
@@ -XXX,XX +XXX,XX @@ void tsc2005_set_transform(void *opaque, MouseTransformInfo *info);
33
@@ -XXX,XX +XXX,XX @@
24
/* stellaris_input.c */
34
#include "hw/misc/bcm2835_mbox.h"
25
void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode);
35
#include "hw/misc/bcm2835_mphi.h"
26
36
#include "hw/misc/bcm2835_thermal.h"
27
-/* blizzard.c */
37
+#include "hw/misc/bcm2835_cprman.h"
28
-void *s1d13745_init(qemu_irq gpio_int);
38
#include "hw/sd/sdhci.h"
29
-void s1d13745_write(void *opaque, int dc, uint16_t value);
39
#include "hw/sd/bcm2835_sdhost.h"
30
-void s1d13745_write_block(void *opaque, int dc,
40
#include "hw/gpio/bcm2835_gpio.h"
31
- void *buf, size_t len, int pitch);
41
@@ -XXX,XX +XXX,XX @@ struct BCM2835PeripheralState {
32
-uint16_t s1d13745_read(void *opaque, int dc);
42
UnimplementedDeviceState txp;
33
-
43
UnimplementedDeviceState armtmr;
34
/* cbus.c */
44
UnimplementedDeviceState powermgt;
35
typedef struct {
45
- UnimplementedDeviceState cprman;
36
qemu_irq clk;
46
+ BCM2835CprmanState cprman;
37
diff --git a/include/hw/display/blizzard.h b/include/hw/display/blizzard.h
47
PL011State uart0;
48
BCM2835AuxState aux;
49
BCM2835FBState fb;
50
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
38
new file mode 100644
51
new file mode 100644
39
index XXXXXXX..XXXXXXX
52
index XXXXXXX..XXXXXXX
40
--- /dev/null
53
--- /dev/null
41
+++ b/include/hw/display/blizzard.h
54
+++ b/include/hw/misc/bcm2835_cprman.h
42
@@ -XXX,XX +XXX,XX @@
55
@@ -XXX,XX +XXX,XX @@
43
+/*
56
+/*
44
+ * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller.
57
+ * BCM2835 CPRMAN clock manager
45
+ *
58
+ *
46
+ * Copyright (C) 2008 Nokia Corporation
59
+ * Copyright (c) 2020 Luc Michel <luc@lmichel.fr>
47
+ * Written by Andrzej Zaborowski
60
+ *
48
+ *
61
+ * SPDX-License-Identifier: GPL-2.0-or-later
49
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
62
+ */
50
+ * See the COPYING file in the top-level directory.
63
+
51
+ */
64
+#ifndef HW_MISC_CPRMAN_H
52
+
65
+#define HW_MISC_CPRMAN_H
53
+#ifndef HW_DISPLAY_BLIZZARD_H
66
+
54
+#define HW_DISPLAY_BLIZZARD_H
67
+#include "hw/sysbus.h"
55
+
68
+#include "hw/qdev-clock.h"
56
+#include "hw/irq.h"
69
+
57
+
70
+#define TYPE_BCM2835_CPRMAN "bcm2835-cprman"
58
+void *s1d13745_init(qemu_irq gpio_int);
71
+
59
+void s1d13745_write(void *opaque, int dc, uint16_t value);
72
+typedef struct BCM2835CprmanState BCM2835CprmanState;
60
+void s1d13745_write_block(void *opaque, int dc,
73
+
61
+ void *buf, size_t len, int pitch);
74
+DECLARE_INSTANCE_CHECKER(BCM2835CprmanState, CPRMAN,
62
+uint16_t s1d13745_read(void *opaque, int dc);
75
+ TYPE_BCM2835_CPRMAN)
76
+
77
+#define CPRMAN_NUM_REGS (0x2000 / sizeof(uint32_t))
78
+
79
+struct BCM2835CprmanState {
80
+ /*< private >*/
81
+ SysBusDevice parent_obj;
82
+
83
+ /*< public >*/
84
+ MemoryRegion iomem;
85
+
86
+ uint32_t regs[CPRMAN_NUM_REGS];
87
+ uint32_t xosc_freq;
88
+
89
+ Clock *xosc;
90
+};
63
+
91
+
64
+#endif
92
+#endif
65
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
93
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
94
new file mode 100644
95
index XXXXXXX..XXXXXXX
96
--- /dev/null
97
+++ b/include/hw/misc/bcm2835_cprman_internals.h
98
@@ -XXX,XX +XXX,XX @@
99
+/*
100
+ * BCM2835 CPRMAN clock manager
101
+ *
102
+ * Copyright (c) 2020 Luc Michel <luc@lmichel.fr>
103
+ *
104
+ * SPDX-License-Identifier: GPL-2.0-or-later
105
+ */
106
+
107
+#ifndef HW_MISC_CPRMAN_INTERNALS_H
108
+#define HW_MISC_CPRMAN_INTERNALS_H
109
+
110
+#include "hw/registerfields.h"
111
+#include "hw/misc/bcm2835_cprman.h"
112
+
113
+/* Register map */
114
+
115
+/*
116
+ * This field is common to all registers. Each register write value must match
117
+ * the CPRMAN_PASSWORD magic value in its 8 MSB.
118
+ */
119
+FIELD(CPRMAN, PASSWORD, 24, 8)
120
+#define CPRMAN_PASSWORD 0x5a
121
+
122
+#endif
123
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
66
index XXXXXXX..XXXXXXX 100644
124
index XXXXXXX..XXXXXXX 100644
67
--- a/hw/arm/nseries.c
125
--- a/hw/arm/bcm2835_peripherals.c
68
+++ b/hw/arm/nseries.c
126
+++ b/hw/arm/bcm2835_peripherals.c
127
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_init(Object *obj)
128
/* DWC2 */
129
object_initialize_child(obj, "dwc2", &s->dwc2, TYPE_DWC2_USB);
130
131
+ /* CPRMAN clock manager */
132
+ object_initialize_child(obj, "cprman", &s->cprman, TYPE_BCM2835_CPRMAN);
133
+
134
object_property_add_const_link(OBJECT(&s->dwc2), "dma-mr",
135
OBJECT(&s->gpu_bus_mr));
136
}
137
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
138
return;
139
}
140
141
+ /* CPRMAN clock manager */
142
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->cprman), errp)) {
143
+ return;
144
+ }
145
+ memory_region_add_subregion(&s->peri_mr, CPRMAN_OFFSET,
146
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cprman), 0));
147
+
148
memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET,
149
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0));
150
sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic));
151
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
152
create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000);
153
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
154
create_unimp(s, &s->powermgt, "bcm2835-powermgt", PM_OFFSET, 0x114);
155
- create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x2000);
156
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);
157
create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100);
158
create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20);
159
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
160
new file mode 100644
161
index XXXXXXX..XXXXXXX
162
--- /dev/null
163
+++ b/hw/misc/bcm2835_cprman.c
69
@@ -XXX,XX +XXX,XX @@
164
@@ -XXX,XX +XXX,XX @@
70
#include "hw/boards.h"
165
+/*
71
#include "hw/i2c/i2c.h"
166
+ * BCM2835 CPRMAN clock manager
72
#include "hw/devices.h"
167
+ *
73
+#include "hw/display/blizzard.h"
168
+ * Copyright (c) 2020 Luc Michel <luc@lmichel.fr>
74
#include "hw/misc/tmp105.h"
169
+ *
75
#include "hw/block/flash.h"
170
+ * SPDX-License-Identifier: GPL-2.0-or-later
76
#include "hw/hw.h"
171
+ */
77
diff --git a/hw/display/blizzard.c b/hw/display/blizzard.c
172
+
173
+/*
174
+ * This peripheral is roughly divided into 3 main parts:
175
+ * - the PLLs
176
+ * - the PLL channels
177
+ * - the clock muxes
178
+ *
179
+ * A main oscillator (xosc) feeds all the PLLs. Each PLLs has one or more
180
+ * channels. Those channel are then connected to the clock muxes. Each mux has
181
+ * multiples sources (usually the xosc, some of the PLL channels and some "test
182
+ * debug" clocks). A mux is configured to select a given source through its
183
+ * control register. Each mux has one output clock that also goes out of the
184
+ * CPRMAN. This output clock usually connects to another peripheral in the SoC
185
+ * (so a given mux is dedicated to a peripheral).
186
+ *
187
+ * At each level (PLL, channel and mux), the clock can be altered through
188
+ * dividers (and multipliers in case of the PLLs), and can be disabled (in this
189
+ * case, the next levels see no clock).
190
+ *
191
+ * This can be sum-up as follows (this is an example and not the actual BCM2835
192
+ * clock tree):
193
+ *
194
+ * /-->[PLL]-|->[PLL channel]--... [mux]--> to peripherals
195
+ * | |->[PLL channel] muxes takes [mux]
196
+ * | \->[PLL channel] inputs from [mux]
197
+ * | some channels [mux]
198
+ * [xosc]---|-->[PLL]-|->[PLL channel] and other srcs [mux]
199
+ * | \->[PLL channel] ...-->[mux]
200
+ * | [mux]
201
+ * \-->[PLL]--->[PLL channel] [mux]
202
+ *
203
+ * The page at https://elinux.org/The_Undocumented_Pi gives the actual clock
204
+ * tree configuration.
205
+ */
206
+
207
+#include "qemu/osdep.h"
208
+#include "qemu/log.h"
209
+#include "migration/vmstate.h"
210
+#include "hw/qdev-properties.h"
211
+#include "hw/misc/bcm2835_cprman.h"
212
+#include "hw/misc/bcm2835_cprman_internals.h"
213
+#include "trace.h"
214
+
215
+/* CPRMAN "top level" model */
216
+
217
+static uint64_t cprman_read(void *opaque, hwaddr offset,
218
+ unsigned size)
219
+{
220
+ BCM2835CprmanState *s = CPRMAN(opaque);
221
+ uint64_t r = 0;
222
+ size_t idx = offset / sizeof(uint32_t);
223
+
224
+ switch (idx) {
225
+ default:
226
+ r = s->regs[idx];
227
+ }
228
+
229
+ trace_bcm2835_cprman_read(offset, r);
230
+ return r;
231
+}
232
+
233
+static void cprman_write(void *opaque, hwaddr offset,
234
+ uint64_t value, unsigned size)
235
+{
236
+ BCM2835CprmanState *s = CPRMAN(opaque);
237
+ size_t idx = offset / sizeof(uint32_t);
238
+
239
+ if (FIELD_EX32(value, CPRMAN, PASSWORD) != CPRMAN_PASSWORD) {
240
+ trace_bcm2835_cprman_write_invalid_magic(offset, value);
241
+ return;
242
+ }
243
+
244
+ value &= ~R_CPRMAN_PASSWORD_MASK;
245
+
246
+ trace_bcm2835_cprman_write(offset, value);
247
+ s->regs[idx] = value;
248
+
249
+}
250
+
251
+static const MemoryRegionOps cprman_ops = {
252
+ .read = cprman_read,
253
+ .write = cprman_write,
254
+ .endianness = DEVICE_LITTLE_ENDIAN,
255
+ .valid = {
256
+ /*
257
+ * Although this hasn't been checked against real hardware, nor the
258
+ * information can be found in a datasheet, it seems reasonable because
259
+ * of the "PASSWORD" magic value found in every registers.
260
+ */
261
+ .min_access_size = 4,
262
+ .max_access_size = 4,
263
+ .unaligned = false,
264
+ },
265
+ .impl = {
266
+ .max_access_size = 4,
267
+ },
268
+};
269
+
270
+static void cprman_reset(DeviceState *dev)
271
+{
272
+ BCM2835CprmanState *s = CPRMAN(dev);
273
+
274
+ memset(s->regs, 0, sizeof(s->regs));
275
+
276
+ clock_update_hz(s->xosc, s->xosc_freq);
277
+}
278
+
279
+static void cprman_init(Object *obj)
280
+{
281
+ BCM2835CprmanState *s = CPRMAN(obj);
282
+
283
+ s->xosc = clock_new(obj, "xosc");
284
+
285
+ memory_region_init_io(&s->iomem, obj, &cprman_ops,
286
+ s, "bcm2835-cprman", 0x2000);
287
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
288
+}
289
+
290
+static const VMStateDescription cprman_vmstate = {
291
+ .name = TYPE_BCM2835_CPRMAN,
292
+ .version_id = 1,
293
+ .minimum_version_id = 1,
294
+ .fields = (VMStateField[]) {
295
+ VMSTATE_UINT32_ARRAY(regs, BCM2835CprmanState, CPRMAN_NUM_REGS),
296
+ VMSTATE_END_OF_LIST()
297
+ }
298
+};
299
+
300
+static Property cprman_properties[] = {
301
+ DEFINE_PROP_UINT32("xosc-freq-hz", BCM2835CprmanState, xosc_freq, 19200000),
302
+ DEFINE_PROP_END_OF_LIST()
303
+};
304
+
305
+static void cprman_class_init(ObjectClass *klass, void *data)
306
+{
307
+ DeviceClass *dc = DEVICE_CLASS(klass);
308
+
309
+ dc->reset = cprman_reset;
310
+ dc->vmsd = &cprman_vmstate;
311
+ device_class_set_props(dc, cprman_properties);
312
+}
313
+
314
+static const TypeInfo cprman_info = {
315
+ .name = TYPE_BCM2835_CPRMAN,
316
+ .parent = TYPE_SYS_BUS_DEVICE,
317
+ .instance_size = sizeof(BCM2835CprmanState),
318
+ .class_init = cprman_class_init,
319
+ .instance_init = cprman_init,
320
+};
321
+
322
+static void cprman_register_types(void)
323
+{
324
+ type_register_static(&cprman_info);
325
+}
326
+
327
+type_init(cprman_register_types);
328
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
78
index XXXXXXX..XXXXXXX 100644
329
index XXXXXXX..XXXXXXX 100644
79
--- a/hw/display/blizzard.c
330
--- a/hw/misc/meson.build
80
+++ b/hw/display/blizzard.c
331
+++ b/hw/misc/meson.build
81
@@ -XXX,XX +XXX,XX @@
332
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files(
82
#include "qemu/osdep.h"
333
'bcm2835_property.c',
83
#include "qemu-common.h"
334
'bcm2835_rng.c',
84
#include "ui/console.h"
335
'bcm2835_thermal.c',
85
-#include "hw/devices.h"
336
+ 'bcm2835_cprman.c',
86
+#include "hw/display/blizzard.h"
337
))
87
#include "ui/pixel_ops.h"
338
softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c'))
88
339
softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c', 'zynq-xadc.c'))
89
typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
340
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
90
diff --git a/MAINTAINERS b/MAINTAINERS
91
index XXXXXXX..XXXXXXX 100644
341
index XXXXXXX..XXXXXXX 100644
92
--- a/MAINTAINERS
342
--- a/hw/misc/trace-events
93
+++ b/MAINTAINERS
343
+++ b/hw/misc/trace-events
94
@@ -XXX,XX +XXX,XX @@ M: Peter Maydell <peter.maydell@linaro.org>
344
@@ -XXX,XX +XXX,XX @@ grlib_apb_pnp_read(uint64_t addr, uint32_t value) "APB PnP read addr:0x%03"PRIx6
95
L: qemu-arm@nongnu.org
345
# pca9552.c
96
S: Odd Fixes
346
pca955x_gpio_status(const char *description, const char *buf) "%s GPIOs 0-15 [%s]"
97
F: hw/arm/nseries.c
347
pca955x_gpio_change(const char *description, unsigned id, unsigned prev_state, unsigned current_state) "%s GPIO id:%u status: %u -> %u"
98
+F: hw/display/blizzard.c
348
+
99
F: hw/input/lm832x.c
349
+# bcm2835_cprman.c
100
F: hw/input/tsc2005.c
350
+bcm2835_cprman_read(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
101
F: hw/misc/cbus.c
351
+bcm2835_cprman_write(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
102
F: hw/timer/twl92230.c
352
+bcm2835_cprman_write_invalid_magic(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
103
+F: include/hw/display/blizzard.h
104
105
Palm
106
M: Andrzej Zaborowski <balrogg@gmail.com>
107
--
353
--
108
2.20.1
354
2.20.1
109
355
110
356
diff view generated by jsdifflib
1
Implement the code which updates the FPCCR register on an
1
From: Luc Michel <luc@lmichel.fr>
2
exception entry where we are going to use lazy FP stacking.
2
3
We have to defer to the NVIC to determine whether the
3
There are 5 PLLs in the CPRMAN, namely PLL A, C, D, H and B. All of them
4
various exceptions are currently ready or not.
4
take the xosc clock as input and produce a new clock.
5
5
6
This commit adds a skeleton implementation for the PLLs as sub-devices
7
of the CPRMAN. The PLLs are instantiated and connected internally to the
8
main oscillator.
9
10
Each PLL has 6 registers : CM, A2W_CTRL, A2W_ANA[0,1,2,3], A2W_FRAC. A
11
write to any of them triggers a call to the (not yet implemented)
12
pll_update function.
13
14
If the main oscillator changes frequency, an update is also triggered.
15
16
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
17
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
18
Signed-off-by: Luc Michel <luc@lmichel.fr>
19
Tested-by: Guenter Roeck <linux@roeck-us.net>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Message-id: 20190416125744.27770-12-peter.maydell@linaro.org
8
---
21
---
9
target/arm/cpu.h | 14 +++++++++
22
include/hw/misc/bcm2835_cprman.h | 29 +++++
10
hw/intc/armv7m_nvic.c | 34 ++++++++++++++++++++++
23
include/hw/misc/bcm2835_cprman_internals.h | 144 +++++++++++++++++++++
11
target/arm/helper.c | 67 ++++++++++++++++++++++++++++++++++++++++++-
24
hw/misc/bcm2835_cprman.c | 108 ++++++++++++++++
12
3 files changed, 114 insertions(+), 1 deletion(-)
25
3 files changed, 281 insertions(+)
13
26
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
27
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
15
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/cpu.h
29
--- a/include/hw/misc/bcm2835_cprman.h
17
+++ b/target/arm/cpu.h
30
+++ b/include/hw/misc/bcm2835_cprman.h
18
@@ -XXX,XX +XXX,XX @@ void armv7m_nvic_acknowledge_irq(void *opaque);
31
@@ -XXX,XX +XXX,XX @@ DECLARE_INSTANCE_CHECKER(BCM2835CprmanState, CPRMAN,
19
* (Ignoring -1, this is the same as the RETTOBASE value before completion.)
32
20
*/
33
#define CPRMAN_NUM_REGS (0x2000 / sizeof(uint32_t))
21
int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure);
34
22
+/**
35
+typedef enum CprmanPll {
23
+ * armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure)
36
+ CPRMAN_PLLA = 0,
24
+ * @opaque: the NVIC
37
+ CPRMAN_PLLC,
25
+ * @irq: the exception number to mark pending
38
+ CPRMAN_PLLD,
26
+ * @secure: false for non-banked exceptions or for the nonsecure
39
+ CPRMAN_PLLH,
27
+ * version of a banked exception, true for the secure version of a banked
40
+ CPRMAN_PLLB,
28
+ * exception.
41
+
29
+ *
42
+ CPRMAN_NUM_PLL
30
+ * Return whether an exception is "ready", i.e. whether the exception is
43
+} CprmanPll;
31
+ * enabled and is configured at a priority which would allow it to
44
+
32
+ * interrupt the current execution priority. This controls whether the
45
+typedef struct CprmanPllState {
33
+ * RDY bit for it in the FPCCR is set.
46
+ /*< private >*/
34
+ */
47
+ DeviceState parent_obj;
35
+bool armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure);
48
+
36
/**
49
+ /*< public >*/
37
* armv7m_nvic_raw_execution_priority: return the raw execution priority
50
+ CprmanPll id;
38
* @opaque: the NVIC
51
+
39
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
52
+ uint32_t *reg_cm;
53
+ uint32_t *reg_a2w_ctrl;
54
+ uint32_t *reg_a2w_ana; /* ANA[0] .. ANA[3] */
55
+ uint32_t prediv_mask; /* prediv bit in ana[1] */
56
+ uint32_t *reg_a2w_frac;
57
+
58
+ Clock *xosc_in;
59
+ Clock *out;
60
+} CprmanPllState;
61
+
62
struct BCM2835CprmanState {
63
/*< private >*/
64
SysBusDevice parent_obj;
65
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
66
/*< public >*/
67
MemoryRegion iomem;
68
69
+ CprmanPllState plls[CPRMAN_NUM_PLL];
70
+
71
uint32_t regs[CPRMAN_NUM_REGS];
72
uint32_t xosc_freq;
73
74
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
40
index XXXXXXX..XXXXXXX 100644
75
index XXXXXXX..XXXXXXX 100644
41
--- a/hw/intc/armv7m_nvic.c
76
--- a/include/hw/misc/bcm2835_cprman_internals.h
42
+++ b/hw/intc/armv7m_nvic.c
77
+++ b/include/hw/misc/bcm2835_cprman_internals.h
43
@@ -XXX,XX +XXX,XX @@ int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure)
78
@@ -XXX,XX +XXX,XX @@
44
return ret;
79
#include "hw/registerfields.h"
80
#include "hw/misc/bcm2835_cprman.h"
81
82
+#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
83
+
84
+DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
85
+ TYPE_CPRMAN_PLL)
86
+
87
/* Register map */
88
89
+/* PLLs */
90
+REG32(CM_PLLA, 0x104)
91
+ FIELD(CM_PLLA, LOADDSI0, 0, 1)
92
+ FIELD(CM_PLLA, HOLDDSI0, 1, 1)
93
+ FIELD(CM_PLLA, LOADCCP2, 2, 1)
94
+ FIELD(CM_PLLA, HOLDCCP2, 3, 1)
95
+ FIELD(CM_PLLA, LOADCORE, 4, 1)
96
+ FIELD(CM_PLLA, HOLDCORE, 5, 1)
97
+ FIELD(CM_PLLA, LOADPER, 6, 1)
98
+ FIELD(CM_PLLA, HOLDPER, 7, 1)
99
+ FIELD(CM_PLLx, ANARST, 8, 1)
100
+REG32(CM_PLLC, 0x108)
101
+ FIELD(CM_PLLC, LOADCORE0, 0, 1)
102
+ FIELD(CM_PLLC, HOLDCORE0, 1, 1)
103
+ FIELD(CM_PLLC, LOADCORE1, 2, 1)
104
+ FIELD(CM_PLLC, HOLDCORE1, 3, 1)
105
+ FIELD(CM_PLLC, LOADCORE2, 4, 1)
106
+ FIELD(CM_PLLC, HOLDCORE2, 5, 1)
107
+ FIELD(CM_PLLC, LOADPER, 6, 1)
108
+ FIELD(CM_PLLC, HOLDPER, 7, 1)
109
+REG32(CM_PLLD, 0x10c)
110
+ FIELD(CM_PLLD, LOADDSI0, 0, 1)
111
+ FIELD(CM_PLLD, HOLDDSI0, 1, 1)
112
+ FIELD(CM_PLLD, LOADDSI1, 2, 1)
113
+ FIELD(CM_PLLD, HOLDDSI1, 3, 1)
114
+ FIELD(CM_PLLD, LOADCORE, 4, 1)
115
+ FIELD(CM_PLLD, HOLDCORE, 5, 1)
116
+ FIELD(CM_PLLD, LOADPER, 6, 1)
117
+ FIELD(CM_PLLD, HOLDPER, 7, 1)
118
+REG32(CM_PLLH, 0x110)
119
+ FIELD(CM_PLLH, LOADPIX, 0, 1)
120
+ FIELD(CM_PLLH, LOADAUX, 1, 1)
121
+ FIELD(CM_PLLH, LOADRCAL, 2, 1)
122
+REG32(CM_PLLB, 0x170)
123
+ FIELD(CM_PLLB, LOADARM, 0, 1)
124
+ FIELD(CM_PLLB, HOLDARM, 1, 1)
125
+
126
+REG32(A2W_PLLA_CTRL, 0x1100)
127
+ FIELD(A2W_PLLx_CTRL, NDIV, 0, 10)
128
+ FIELD(A2W_PLLx_CTRL, PDIV, 12, 3)
129
+ FIELD(A2W_PLLx_CTRL, PWRDN, 16, 1)
130
+ FIELD(A2W_PLLx_CTRL, PRST_DISABLE, 17, 1)
131
+REG32(A2W_PLLC_CTRL, 0x1120)
132
+REG32(A2W_PLLD_CTRL, 0x1140)
133
+REG32(A2W_PLLH_CTRL, 0x1160)
134
+REG32(A2W_PLLB_CTRL, 0x11e0)
135
+
136
+REG32(A2W_PLLA_ANA0, 0x1010)
137
+REG32(A2W_PLLA_ANA1, 0x1014)
138
+ FIELD(A2W_PLLx_ANA1, FB_PREDIV, 14, 1)
139
+REG32(A2W_PLLA_ANA2, 0x1018)
140
+REG32(A2W_PLLA_ANA3, 0x101c)
141
+
142
+REG32(A2W_PLLC_ANA0, 0x1030)
143
+REG32(A2W_PLLC_ANA1, 0x1034)
144
+REG32(A2W_PLLC_ANA2, 0x1038)
145
+REG32(A2W_PLLC_ANA3, 0x103c)
146
+
147
+REG32(A2W_PLLD_ANA0, 0x1050)
148
+REG32(A2W_PLLD_ANA1, 0x1054)
149
+REG32(A2W_PLLD_ANA2, 0x1058)
150
+REG32(A2W_PLLD_ANA3, 0x105c)
151
+
152
+REG32(A2W_PLLH_ANA0, 0x1070)
153
+REG32(A2W_PLLH_ANA1, 0x1074)
154
+ FIELD(A2W_PLLH_ANA1, FB_PREDIV, 11, 1)
155
+REG32(A2W_PLLH_ANA2, 0x1078)
156
+REG32(A2W_PLLH_ANA3, 0x107c)
157
+
158
+REG32(A2W_PLLB_ANA0, 0x10f0)
159
+REG32(A2W_PLLB_ANA1, 0x10f4)
160
+REG32(A2W_PLLB_ANA2, 0x10f8)
161
+REG32(A2W_PLLB_ANA3, 0x10fc)
162
+
163
+REG32(A2W_PLLA_FRAC, 0x1200)
164
+ FIELD(A2W_PLLx_FRAC, FRAC, 0, 20)
165
+REG32(A2W_PLLC_FRAC, 0x1220)
166
+REG32(A2W_PLLD_FRAC, 0x1240)
167
+REG32(A2W_PLLH_FRAC, 0x1260)
168
+REG32(A2W_PLLB_FRAC, 0x12e0)
169
+
170
/*
171
* This field is common to all registers. Each register write value must match
172
* the CPRMAN_PASSWORD magic value in its 8 MSB.
173
@@ -XXX,XX +XXX,XX @@
174
FIELD(CPRMAN, PASSWORD, 24, 8)
175
#define CPRMAN_PASSWORD 0x5a
176
177
+/* PLL init info */
178
+typedef struct PLLInitInfo {
179
+ const char *name;
180
+ size_t cm_offset;
181
+ size_t a2w_ctrl_offset;
182
+ size_t a2w_ana_offset;
183
+ uint32_t prediv_mask; /* Prediv bit in ana[1] */
184
+ size_t a2w_frac_offset;
185
+} PLLInitInfo;
186
+
187
+#define FILL_PLL_INIT_INFO(pll_) \
188
+ .cm_offset = R_CM_ ## pll_, \
189
+ .a2w_ctrl_offset = R_A2W_ ## pll_ ## _CTRL, \
190
+ .a2w_ana_offset = R_A2W_ ## pll_ ## _ANA0, \
191
+ .a2w_frac_offset = R_A2W_ ## pll_ ## _FRAC
192
+
193
+static const PLLInitInfo PLL_INIT_INFO[] = {
194
+ [CPRMAN_PLLA] = {
195
+ .name = "plla",
196
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
197
+ FILL_PLL_INIT_INFO(PLLA),
198
+ },
199
+ [CPRMAN_PLLC] = {
200
+ .name = "pllc",
201
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
202
+ FILL_PLL_INIT_INFO(PLLC),
203
+ },
204
+ [CPRMAN_PLLD] = {
205
+ .name = "plld",
206
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
207
+ FILL_PLL_INIT_INFO(PLLD),
208
+ },
209
+ [CPRMAN_PLLH] = {
210
+ .name = "pllh",
211
+ .prediv_mask = R_A2W_PLLH_ANA1_FB_PREDIV_MASK,
212
+ FILL_PLL_INIT_INFO(PLLH),
213
+ },
214
+ [CPRMAN_PLLB] = {
215
+ .name = "pllb",
216
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
217
+ FILL_PLL_INIT_INFO(PLLB),
218
+ },
219
+};
220
+
221
+#undef FILL_PLL_CHANNEL_INIT_INFO
222
+
223
+static inline void set_pll_init_info(BCM2835CprmanState *s,
224
+ CprmanPllState *pll,
225
+ CprmanPll id)
226
+{
227
+ pll->id = id;
228
+ pll->reg_cm = &s->regs[PLL_INIT_INFO[id].cm_offset];
229
+ pll->reg_a2w_ctrl = &s->regs[PLL_INIT_INFO[id].a2w_ctrl_offset];
230
+ pll->reg_a2w_ana = &s->regs[PLL_INIT_INFO[id].a2w_ana_offset];
231
+ pll->prediv_mask = PLL_INIT_INFO[id].prediv_mask;
232
+ pll->reg_a2w_frac = &s->regs[PLL_INIT_INFO[id].a2w_frac_offset];
233
+}
234
+
235
#endif
236
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
237
index XXXXXXX..XXXXXXX 100644
238
--- a/hw/misc/bcm2835_cprman.c
239
+++ b/hw/misc/bcm2835_cprman.c
240
@@ -XXX,XX +XXX,XX @@
241
#include "hw/misc/bcm2835_cprman_internals.h"
242
#include "trace.h"
243
244
+/* PLL */
245
+
246
+static void pll_update(CprmanPllState *pll)
247
+{
248
+ clock_update(pll->out, 0);
249
+}
250
+
251
+static void pll_xosc_update(void *opaque)
252
+{
253
+ pll_update(CPRMAN_PLL(opaque));
254
+}
255
+
256
+static void pll_init(Object *obj)
257
+{
258
+ CprmanPllState *s = CPRMAN_PLL(obj);
259
+
260
+ s->xosc_in = qdev_init_clock_in(DEVICE(s), "xosc-in", pll_xosc_update, s);
261
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
262
+}
263
+
264
+static const VMStateDescription pll_vmstate = {
265
+ .name = TYPE_CPRMAN_PLL,
266
+ .version_id = 1,
267
+ .minimum_version_id = 1,
268
+ .fields = (VMStateField[]) {
269
+ VMSTATE_CLOCK(xosc_in, CprmanPllState),
270
+ VMSTATE_END_OF_LIST()
271
+ }
272
+};
273
+
274
+static void pll_class_init(ObjectClass *klass, void *data)
275
+{
276
+ DeviceClass *dc = DEVICE_CLASS(klass);
277
+
278
+ dc->vmsd = &pll_vmstate;
279
+}
280
+
281
+static const TypeInfo cprman_pll_info = {
282
+ .name = TYPE_CPRMAN_PLL,
283
+ .parent = TYPE_DEVICE,
284
+ .instance_size = sizeof(CprmanPllState),
285
+ .class_init = pll_class_init,
286
+ .instance_init = pll_init,
287
+};
288
+
289
+
290
/* CPRMAN "top level" model */
291
292
static uint64_t cprman_read(void *opaque, hwaddr offset,
293
@@ -XXX,XX +XXX,XX @@ static uint64_t cprman_read(void *opaque, hwaddr offset,
294
return r;
45
}
295
}
46
296
47
+bool armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure)
297
+#define CASE_PLL_REGS(pll_) \
48
+{
298
+ case R_CM_ ## pll_: \
49
+ /*
299
+ case R_A2W_ ## pll_ ## _CTRL: \
50
+ * Return whether an exception is "ready", i.e. it is enabled and is
300
+ case R_A2W_ ## pll_ ## _ANA0: \
51
+ * configured at a priority which would allow it to interrupt the
301
+ case R_A2W_ ## pll_ ## _ANA1: \
52
+ * current execution priority.
302
+ case R_A2W_ ## pll_ ## _ANA2: \
53
+ *
303
+ case R_A2W_ ## pll_ ## _ANA3: \
54
+ * irq and secure have the same semantics as for armv7m_nvic_set_pending():
304
+ case R_A2W_ ## pll_ ## _FRAC
55
+ * for non-banked exceptions secure is always false; for banked exceptions
305
+
56
+ * it indicates which of the exceptions is required.
306
static void cprman_write(void *opaque, hwaddr offset,
57
+ */
307
uint64_t value, unsigned size)
58
+ NVICState *s = (NVICState *)opaque;
308
{
59
+ bool banked = exc_is_banked(irq);
309
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
60
+ VecInfo *vec;
310
trace_bcm2835_cprman_write(offset, value);
61
+ int running = nvic_exec_prio(s);
311
s->regs[idx] = value;
62
+
312
63
+ assert(irq > ARMV7M_EXCP_RESET && irq < s->num_irq);
313
+ switch (idx) {
64
+ assert(!secure || banked);
314
+ CASE_PLL_REGS(PLLA) :
65
+
315
+ pll_update(&s->plls[CPRMAN_PLLA]);
66
+ /*
316
+ break;
67
+ * HardFault is an odd special case: we always check against -1,
317
+
68
+ * even if we're secure and HardFault has priority -3; we never
318
+ CASE_PLL_REGS(PLLC) :
69
+ * need to check for enabled state.
319
+ pll_update(&s->plls[CPRMAN_PLLC]);
70
+ */
320
+ break;
71
+ if (irq == ARMV7M_EXCP_HARD) {
321
+
72
+ return running > -1;
322
+ CASE_PLL_REGS(PLLD) :
323
+ pll_update(&s->plls[CPRMAN_PLLD]);
324
+ break;
325
+
326
+ CASE_PLL_REGS(PLLH) :
327
+ pll_update(&s->plls[CPRMAN_PLLH]);
328
+ break;
329
+
330
+ CASE_PLL_REGS(PLLB) :
331
+ pll_update(&s->plls[CPRMAN_PLLB]);
332
+ break;
73
+ }
333
+ }
74
+
334
}
75
+ vec = (banked && secure) ? &s->sec_vectors[irq] : &s->vectors[irq];
335
76
+
336
+#undef CASE_PLL_REGS
77
+ return vec->enabled &&
337
+
78
+ exc_group_prio(s, vec->prio, secure) < running;
338
static const MemoryRegionOps cprman_ops = {
79
+}
339
.read = cprman_read,
80
+
340
.write = cprman_write,
81
/* callback when external interrupt line is changed */
341
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps cprman_ops = {
82
static void set_irq_level(void *opaque, int n, int level)
342
static void cprman_reset(DeviceState *dev)
83
{
343
{
84
diff --git a/target/arm/helper.c b/target/arm/helper.c
344
BCM2835CprmanState *s = CPRMAN(dev);
85
index XXXXXXX..XXXXXXX 100644
345
+ size_t i;
86
--- a/target/arm/helper.c
346
87
+++ b/target/arm/helper.c
347
memset(s->regs, 0, sizeof(s->regs));
88
@@ -XXX,XX +XXX,XX @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
348
89
env->thumb = addr & 1;
349
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
350
+ device_cold_reset(DEVICE(&s->plls[i]));
351
+ }
352
+
353
clock_update_hz(s->xosc, s->xosc_freq);
90
}
354
}
91
355
92
+static void v7m_update_fpccr(CPUARMState *env, uint32_t frameptr,
356
static void cprman_init(Object *obj)
93
+ bool apply_splim)
357
{
94
+{
358
BCM2835CprmanState *s = CPRMAN(obj);
95
+ /*
359
+ size_t i;
96
+ * Like the pseudocode UpdateFPCCR: save state in FPCAR and FPCCR
360
+
97
+ * that we will need later in order to do lazy FP reg stacking.
361
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
98
+ */
362
+ object_initialize_child(obj, PLL_INIT_INFO[i].name,
99
+ bool is_secure = env->v7m.secure;
363
+ &s->plls[i], TYPE_CPRMAN_PLL);
100
+ void *nvic = env->nvic;
364
+ set_pll_init_info(s, &s->plls[i], i);
101
+ /*
102
+ * Some bits are unbanked and live always in fpccr[M_REG_S]; some bits
103
+ * are banked and we want to update the bit in the bank for the
104
+ * current security state; and in one case we want to specifically
105
+ * update the NS banked version of a bit even if we are secure.
106
+ */
107
+ uint32_t *fpccr_s = &env->v7m.fpccr[M_REG_S];
108
+ uint32_t *fpccr_ns = &env->v7m.fpccr[M_REG_NS];
109
+ uint32_t *fpccr = &env->v7m.fpccr[is_secure];
110
+ bool hfrdy, bfrdy, mmrdy, ns_ufrdy, s_ufrdy, sfrdy, monrdy;
111
+
112
+ env->v7m.fpcar[is_secure] = frameptr & ~0x7;
113
+
114
+ if (apply_splim && arm_feature(env, ARM_FEATURE_V8)) {
115
+ bool splimviol;
116
+ uint32_t splim = v7m_sp_limit(env);
117
+ bool ign = armv7m_nvic_neg_prio_requested(nvic, is_secure) &&
118
+ (env->v7m.ccr[is_secure] & R_V7M_CCR_STKOFHFNMIGN_MASK);
119
+
120
+ splimviol = !ign && frameptr < splim;
121
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, SPLIMVIOL, splimviol);
122
+ }
365
+ }
123
+
366
124
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, LSPACT, 1);
367
s->xosc = clock_new(obj, "xosc");
125
+
368
126
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, S, is_secure);
369
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
127
+
370
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
128
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, USER, arm_current_el(env) == 0);
371
}
129
+
372
130
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, THREAD,
373
+static void cprman_realize(DeviceState *dev, Error **errp)
131
+ !arm_v7m_is_handler_mode(env));
374
+{
132
+
375
+ BCM2835CprmanState *s = CPRMAN(dev);
133
+ hfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_HARD, false);
376
+ size_t i;
134
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, HFRDY, hfrdy);
377
+
135
+
378
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
136
+ bfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_BUS, false);
379
+ CprmanPllState *pll = &s->plls[i];
137
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, BFRDY, bfrdy);
380
+
138
+
381
+ clock_set_source(pll->xosc_in, s->xosc);
139
+ mmrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_MEM, is_secure);
382
+
140
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, MMRDY, mmrdy);
383
+ if (!qdev_realize(DEVICE(pll), NULL, errp)) {
141
+
384
+ return;
142
+ ns_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, false);
385
+ }
143
+ *fpccr_ns = FIELD_DP32(*fpccr_ns, V7M_FPCCR, UFRDY, ns_ufrdy);
144
+
145
+ monrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_DEBUG, false);
146
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, MONRDY, monrdy);
147
+
148
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
149
+ s_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, true);
150
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, UFRDY, s_ufrdy);
151
+
152
+ sfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_SECURE, false);
153
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, SFRDY, sfrdy);
154
+ }
386
+ }
155
+}
387
+}
156
+
388
+
157
static bool v7m_push_stack(ARMCPU *cpu)
389
static const VMStateDescription cprman_vmstate = {
390
.name = TYPE_BCM2835_CPRMAN,
391
.version_id = 1,
392
@@ -XXX,XX +XXX,XX @@ static void cprman_class_init(ObjectClass *klass, void *data)
158
{
393
{
159
/* Do the "set up stack frame" part of exception entry,
394
DeviceClass *dc = DEVICE_CLASS(klass);
160
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_stack(ARMCPU *cpu)
395
161
}
396
+ dc->realize = cprman_realize;
162
} else {
397
dc->reset = cprman_reset;
163
/* Lazy stacking enabled, save necessary info to stack later */
398
dc->vmsd = &cprman_vmstate;
164
- /* TODO : equivalent of UpdateFPCCR() pseudocode */
399
device_class_set_props(dc, cprman_properties);
165
+ v7m_update_fpccr(env, frameptr + 0x20, true);
400
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_info = {
166
}
401
static void cprman_register_types(void)
167
}
402
{
168
}
403
type_register_static(&cprman_info);
404
+ type_register_static(&cprman_pll_info);
405
}
406
407
type_init(cprman_register_types);
169
--
408
--
170
2.20.1
409
2.20.1
171
410
172
411
diff view generated by jsdifflib
1
Implement the VLSTM instruction for v7M for the FPU present case.
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
The CPRMAN PLLs generate a clock based on a prescaler, a multiplier and
4
a divider. The prescaler doubles the parent (xosc) frequency, then the
5
multiplier/divider are applied. The multiplier has an integer and a
6
fractional part.
7
8
This commit also implements the CPRMAN CM_LOCK register. This register
9
reports which PLL is currently locked. We consider a PLL has being
10
locked as soon as it is enabled (on real hardware, there is a delay
11
after turning a PLL on, for it to stabilize).
12
13
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
15
Signed-off-by: Luc Michel <luc@lmichel.fr>
16
Tested-by: Guenter Roeck <linux@roeck-us.net>
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20190416125744.27770-25-peter.maydell@linaro.org
6
---
18
---
7
target/arm/cpu.h | 2 +
19
include/hw/misc/bcm2835_cprman_internals.h | 8 +++
8
target/arm/helper.h | 2 +
20
hw/misc/bcm2835_cprman.c | 64 +++++++++++++++++++++-
9
target/arm/helper.c | 84 ++++++++++++++++++++++++++++++++++++++++++
21
2 files changed, 71 insertions(+), 1 deletion(-)
10
target/arm/translate.c | 15 +++++++-
11
4 files changed, 102 insertions(+), 1 deletion(-)
12
22
13
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
23
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
14
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/cpu.h
25
--- a/include/hw/misc/bcm2835_cprman_internals.h
16
+++ b/target/arm/cpu.h
26
+++ b/include/hw/misc/bcm2835_cprman_internals.h
27
@@ -XXX,XX +XXX,XX @@ REG32(A2W_PLLD_FRAC, 0x1240)
28
REG32(A2W_PLLH_FRAC, 0x1260)
29
REG32(A2W_PLLB_FRAC, 0x12e0)
30
31
+/* misc registers */
32
+REG32(CM_LOCK, 0x114)
33
+ FIELD(CM_LOCK, FLOCKH, 12, 1)
34
+ FIELD(CM_LOCK, FLOCKD, 11, 1)
35
+ FIELD(CM_LOCK, FLOCKC, 10, 1)
36
+ FIELD(CM_LOCK, FLOCKB, 9, 1)
37
+ FIELD(CM_LOCK, FLOCKA, 8, 1)
38
+
39
/*
40
* This field is common to all registers. Each register write value must match
41
* the CPRMAN_PASSWORD magic value in its 8 MSB.
42
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/hw/misc/bcm2835_cprman.c
45
+++ b/hw/misc/bcm2835_cprman.c
17
@@ -XXX,XX +XXX,XX @@
46
@@ -XXX,XX +XXX,XX @@
18
#define EXCP_INVSTATE 18 /* v7M INVSTATE UsageFault */
47
19
#define EXCP_STKOF 19 /* v8M STKOF UsageFault */
48
/* PLL */
20
#define EXCP_LAZYFP 20 /* v7M fault during lazy FP stacking */
49
21
+#define EXCP_LSERR 21 /* v8M LSERR SecureFault */
50
+static bool pll_is_locked(const CprmanPllState *pll)
22
+#define EXCP_UNALIGNED 22 /* v7M UNALIGNED UsageFault */
23
/* NB: add new EXCP_ defines to the array in arm_log_exception() too */
24
25
#define ARMV7M_EXCP_RESET 1
26
diff --git a/target/arm/helper.h b/target/arm/helper.h
27
index XXXXXXX..XXXXXXX 100644
28
--- a/target/arm/helper.h
29
+++ b/target/arm/helper.h
30
@@ -XXX,XX +XXX,XX @@ DEF_HELPER_3(v7m_tt, i32, env, i32, i32)
31
32
DEF_HELPER_1(v7m_preserve_fp_state, void, env)
33
34
+DEF_HELPER_2(v7m_vlstm, void, env, i32)
35
+
36
DEF_HELPER_2(v8m_stackcheck, void, env, i32)
37
38
DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32)
39
diff --git a/target/arm/helper.c b/target/arm/helper.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/target/arm/helper.c
42
+++ b/target/arm/helper.c
43
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
44
g_assert_not_reached();
45
}
46
47
+void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
48
+{
51
+{
49
+ /* translate.c should never generate calls here in user-only mode */
52
+ return !FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PWRDN)
50
+ g_assert_not_reached();
53
+ && !FIELD_EX32(*pll->reg_cm, CM_PLLx, ANARST);
51
+}
54
+}
52
+
55
+
53
uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
56
static void pll_update(CprmanPllState *pll)
54
{
57
{
55
/* The TT instructions can be used by unprivileged code, but in
58
- clock_update(pll->out, 0);
56
@@ -XXX,XX +XXX,XX @@ static void v7m_update_fpccr(CPUARMState *env, uint32_t frameptr,
59
+ uint64_t freq, ndiv, fdiv, pdiv;
57
}
58
}
59
60
+void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
61
+{
62
+ /* fptr is the value of Rn, the frame pointer we store the FP regs to */
63
+ bool s = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
64
+ bool lspact = env->v7m.fpccr[s] & R_V7M_FPCCR_LSPACT_MASK;
65
+
60
+
66
+ assert(env->v7m.secure);
61
+ if (!pll_is_locked(pll)) {
67
+
62
+ clock_update(pll->out, 0);
68
+ if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
69
+ return;
63
+ return;
70
+ }
64
+ }
71
+
65
+
72
+ /* Check access to the coprocessor is permitted */
66
+ pdiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PDIV);
73
+ if (!v7m_cpacr_pass(env, true, arm_current_el(env) != 0)) {
67
+
74
+ raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC());
68
+ if (!pdiv) {
69
+ clock_update(pll->out, 0);
70
+ return;
75
+ }
71
+ }
76
+
72
+
77
+ if (lspact) {
73
+ ndiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, NDIV);
78
+ /* LSPACT should not be active when there is active FP state */
74
+ fdiv = FIELD_EX32(*pll->reg_a2w_frac, A2W_PLLx_FRAC, FRAC);
79
+ raise_exception_ra(env, EXCP_LSERR, 0, 1, GETPC());
80
+ }
81
+
75
+
82
+ if (fptr & 7) {
76
+ if (pll->reg_a2w_ana[1] & pll->prediv_mask) {
83
+ raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC());
77
+ /* The prescaler doubles the parent frequency */
78
+ ndiv *= 2;
79
+ fdiv *= 2;
84
+ }
80
+ }
85
+
81
+
86
+ /*
82
+ /*
87
+ * Note that we do not use v7m_stack_write() here, because the
83
+ * We have a multiplier with an integer part (ndiv) and a fractional part
88
+ * accesses should not set the FSR bits for stacking errors if they
84
+ * (fdiv), and a divider (pdiv).
89
+ * fail. (In pseudocode terms, they are AccType_NORMAL, not AccType_STACK
90
+ * or AccType_LAZYFP). Faults in cpu_stl_data() will throw exceptions
91
+ * and longjmp out.
92
+ */
85
+ */
93
+ if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) {
86
+ freq = clock_get_hz(pll->xosc_in) *
94
+ bool ts = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
87
+ ((ndiv << R_A2W_PLLx_FRAC_FRAC_LENGTH) + fdiv);
95
+ int i;
88
+ freq /= pdiv;
89
+ freq >>= R_A2W_PLLx_FRAC_FRAC_LENGTH;
96
+
90
+
97
+ for (i = 0; i < (ts ? 32 : 16); i += 2) {
91
+ clock_update_hz(pll->out, freq);
98
+ uint64_t dn = *aa32_vfp_dreg(env, i / 2);
92
}
99
+ uint32_t faddr = fptr + 4 * i;
93
100
+ uint32_t slo = extract64(dn, 0, 32);
94
static void pll_xosc_update(void *opaque)
101
+ uint32_t shi = extract64(dn, 32, 32);
95
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
96
97
/* CPRMAN "top level" model */
98
99
+static uint32_t get_cm_lock(const BCM2835CprmanState *s)
100
+{
101
+ static const int CM_LOCK_MAPPING[CPRMAN_NUM_PLL] = {
102
+ [CPRMAN_PLLA] = R_CM_LOCK_FLOCKA_SHIFT,
103
+ [CPRMAN_PLLC] = R_CM_LOCK_FLOCKC_SHIFT,
104
+ [CPRMAN_PLLD] = R_CM_LOCK_FLOCKD_SHIFT,
105
+ [CPRMAN_PLLH] = R_CM_LOCK_FLOCKH_SHIFT,
106
+ [CPRMAN_PLLB] = R_CM_LOCK_FLOCKB_SHIFT,
107
+ };
102
+
108
+
103
+ if (i >= 16) {
109
+ uint32_t r = 0;
104
+ faddr += 8; /* skip the slot for the FPSCR */
110
+ size_t i;
105
+ }
106
+ cpu_stl_data(env, faddr, slo);
107
+ cpu_stl_data(env, faddr + 4, shi);
108
+ }
109
+ cpu_stl_data(env, fptr + 0x40, vfp_get_fpscr(env));
110
+
111
+
111
+ /*
112
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
112
+ * If TS is 0 then s0 to s15 and FPSCR are UNKNOWN; we choose to
113
+ r |= pll_is_locked(&s->plls[i]) << CM_LOCK_MAPPING[i];
113
+ * leave them unchanged, matching our choice in v7m_preserve_fp_state.
114
+ */
115
+ if (ts) {
116
+ for (i = 0; i < 32; i += 2) {
117
+ *aa32_vfp_dreg(env, i / 2) = 0;
118
+ }
119
+ vfp_set_fpscr(env, 0);
120
+ }
121
+ } else {
122
+ v7m_update_fpccr(env, fptr, false);
123
+ }
114
+ }
124
+
115
+
125
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
116
+ return r;
126
+}
117
+}
127
+
118
+
128
static bool v7m_push_stack(ARMCPU *cpu)
119
static uint64_t cprman_read(void *opaque, hwaddr offset,
120
unsigned size)
129
{
121
{
130
/* Do the "set up stack frame" part of exception entry,
122
@@ -XXX,XX +XXX,XX @@ static uint64_t cprman_read(void *opaque, hwaddr offset,
131
@@ -XXX,XX +XXX,XX @@ static void arm_log_exception(int idx)
123
size_t idx = offset / sizeof(uint32_t);
132
[EXCP_INVSTATE] = "v7M INVSTATE UsageFault",
124
133
[EXCP_STKOF] = "v8M STKOF UsageFault",
125
switch (idx) {
134
[EXCP_LAZYFP] = "v7M exception during lazy FP stacking",
126
+ case R_CM_LOCK:
135
+ [EXCP_LSERR] = "v8M LSERR UsageFault",
127
+ r = get_cm_lock(s);
136
+ [EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault",
137
};
138
139
if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
140
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
141
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
142
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
143
break;
144
+ case EXCP_LSERR:
145
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
146
+ env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
147
+ break;
128
+ break;
148
+ case EXCP_UNALIGNED:
149
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
150
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNALIGNED_MASK;
151
+ break;
152
case EXCP_SWI:
153
/* The PC already points to the next instruction. */
154
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC, env->v7m.secure);
155
diff --git a/target/arm/translate.c b/target/arm/translate.c
156
index XXXXXXX..XXXXXXX 100644
157
--- a/target/arm/translate.c
158
+++ b/target/arm/translate.c
159
@@ -XXX,XX +XXX,XX @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
160
if (!s->v8m_secure || (insn & 0x0040f0ff)) {
161
goto illegal_op;
162
}
163
- /* Just NOP since FP support is not implemented */
164
+
129
+
165
+ if (arm_dc_feature(s, ARM_FEATURE_VFP)) {
130
default:
166
+ TCGv_i32 fptr = load_reg(s, rn);
131
r = s->regs[idx];
167
+
132
}
168
+ if (extract32(insn, 20, 1)) {
169
+ /* VLLDM */
170
+ } else {
171
+ gen_helper_v7m_vlstm(cpu_env, fptr);
172
+ }
173
+ tcg_temp_free_i32(fptr);
174
+
175
+ /* End the TB, because we have updated FP control bits */
176
+ s->base.is_jmp = DISAS_UPDATE;
177
+ }
178
break;
179
}
180
if (arm_dc_feature(s, ARM_FEATURE_VFP) &&
181
--
133
--
182
2.20.1
134
2.20.1
183
135
184
136
diff view generated by jsdifflib
1
The M-profile FPCCR.S bit indicates the security status of
1
From: Luc Michel <luc@lmichel.fr>
2
the floating point context. In the pseudocode ExecuteFPCheck()
2
3
function it is unconditionally set to match the current
3
PLLs are composed of multiple channels. Each channel outputs one clock
4
security state whenever a floating point instruction is
4
signal. They are modeled as one device taking the PLL generated clock as
5
executed.
5
input, and outputting a new clock.
6
6
7
Implement this by adding a new TB flag which tracks whether
7
A channel shares the CM register with its parent PLL, and has its own
8
FPCCR.S is different from the current security state, so
8
A2W_CTRL register. A write to the CM register will trigger an update of
9
that we only need to emit the code to update it in the
9
the PLL and all its channels, while a write to an A2W_CTRL channel
10
less-common case when it is not already set correctly.
10
register will update the required channel only.
11
11
12
Note that we will add the handling for the other work done
12
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
by ExecuteFPCheck() in later commits.
13
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
14
Signed-off-by: Luc Michel <luc@lmichel.fr>
15
Tested-by: Guenter Roeck <linux@roeck-us.net>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
17
Message-id: 20190416125744.27770-19-peter.maydell@linaro.org
18
---
17
---
19
target/arm/cpu.h | 2 ++
18
include/hw/misc/bcm2835_cprman.h | 44 ++++++
20
target/arm/translate.h | 1 +
19
include/hw/misc/bcm2835_cprman_internals.h | 146 +++++++++++++++++++
21
target/arm/helper.c | 5 +++++
20
hw/misc/bcm2835_cprman.c | 155 +++++++++++++++++++--
22
target/arm/translate.c | 20 ++++++++++++++++++++
21
3 files changed, 337 insertions(+), 8 deletions(-)
23
4 files changed, 28 insertions(+)
22
24
23
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
25
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
26
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
27
--- a/target/arm/cpu.h
25
--- a/include/hw/misc/bcm2835_cprman.h
28
+++ b/target/arm/cpu.h
26
+++ b/include/hw/misc/bcm2835_cprman.h
29
@@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A32, NS, 6, 1)
27
@@ -XXX,XX +XXX,XX @@ typedef enum CprmanPll {
30
FIELD(TBFLAG_A32, VFPEN, 7, 1)
28
CPRMAN_NUM_PLL
31
FIELD(TBFLAG_A32, CONDEXEC, 8, 8)
29
} CprmanPll;
32
FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
30
33
+/* For M profile only, set if FPCCR.S does not match current security state */
31
+typedef enum CprmanPllChannel {
34
+FIELD(TBFLAG_A32, FPCCR_S_WRONG, 20, 1)
32
+ CPRMAN_PLLA_CHANNEL_DSI0 = 0,
35
/* For M profile only, Handler (ie not Thread) mode */
33
+ CPRMAN_PLLA_CHANNEL_CORE,
36
FIELD(TBFLAG_A32, HANDLER, 21, 1)
34
+ CPRMAN_PLLA_CHANNEL_PER,
37
/* For M profile only, whether we should generate stack-limit checks */
35
+ CPRMAN_PLLA_CHANNEL_CCP2,
38
diff --git a/target/arm/translate.h b/target/arm/translate.h
36
+
37
+ CPRMAN_PLLC_CHANNEL_CORE2,
38
+ CPRMAN_PLLC_CHANNEL_CORE1,
39
+ CPRMAN_PLLC_CHANNEL_PER,
40
+ CPRMAN_PLLC_CHANNEL_CORE0,
41
+
42
+ CPRMAN_PLLD_CHANNEL_DSI0,
43
+ CPRMAN_PLLD_CHANNEL_CORE,
44
+ CPRMAN_PLLD_CHANNEL_PER,
45
+ CPRMAN_PLLD_CHANNEL_DSI1,
46
+
47
+ CPRMAN_PLLH_CHANNEL_AUX,
48
+ CPRMAN_PLLH_CHANNEL_RCAL,
49
+ CPRMAN_PLLH_CHANNEL_PIX,
50
+
51
+ CPRMAN_PLLB_CHANNEL_ARM,
52
+
53
+ CPRMAN_NUM_PLL_CHANNEL,
54
+} CprmanPllChannel;
55
+
56
typedef struct CprmanPllState {
57
/*< private >*/
58
DeviceState parent_obj;
59
@@ -XXX,XX +XXX,XX @@ typedef struct CprmanPllState {
60
Clock *out;
61
} CprmanPllState;
62
63
+typedef struct CprmanPllChannelState {
64
+ /*< private >*/
65
+ DeviceState parent_obj;
66
+
67
+ /*< public >*/
68
+ CprmanPllChannel id;
69
+ CprmanPll parent;
70
+
71
+ uint32_t *reg_cm;
72
+ uint32_t hold_mask;
73
+ uint32_t load_mask;
74
+ uint32_t *reg_a2w_ctrl;
75
+ int fixed_divider;
76
+
77
+ Clock *pll_in;
78
+ Clock *out;
79
+} CprmanPllChannelState;
80
+
81
struct BCM2835CprmanState {
82
/*< private >*/
83
SysBusDevice parent_obj;
84
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
85
MemoryRegion iomem;
86
87
CprmanPllState plls[CPRMAN_NUM_PLL];
88
+ CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
89
90
uint32_t regs[CPRMAN_NUM_REGS];
91
uint32_t xosc_freq;
92
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
39
index XXXXXXX..XXXXXXX 100644
93
index XXXXXXX..XXXXXXX 100644
40
--- a/target/arm/translate.h
94
--- a/include/hw/misc/bcm2835_cprman_internals.h
41
+++ b/target/arm/translate.h
95
+++ b/include/hw/misc/bcm2835_cprman_internals.h
42
@@ -XXX,XX +XXX,XX @@ typedef struct DisasContext {
96
@@ -XXX,XX +XXX,XX @@
43
bool v7m_handler_mode;
97
#include "hw/misc/bcm2835_cprman.h"
44
bool v8m_secure; /* true if v8M and we're in Secure mode */
98
45
bool v8m_stackcheck; /* true if we need to perform v8M stack limit checks */
99
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
46
+ bool v8m_fpccr_s_wrong; /* true if v8M FPCCR.S != v8m_secure */
100
+#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
47
/* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI
101
48
* so that top level loop can generate correct syndrome information.
102
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
49
*/
103
TYPE_CPRMAN_PLL)
50
diff --git a/target/arm/helper.c b/target/arm/helper.c
104
+DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL,
105
+ TYPE_CPRMAN_PLL_CHANNEL)
106
107
/* Register map */
108
109
@@ -XXX,XX +XXX,XX @@ REG32(A2W_PLLD_FRAC, 0x1240)
110
REG32(A2W_PLLH_FRAC, 0x1260)
111
REG32(A2W_PLLB_FRAC, 0x12e0)
112
113
+/* PLL channels */
114
+REG32(A2W_PLLA_DSI0, 0x1300)
115
+ FIELD(A2W_PLLx_CHANNELy, DIV, 0, 8)
116
+ FIELD(A2W_PLLx_CHANNELy, DISABLE, 8, 1)
117
+REG32(A2W_PLLA_CORE, 0x1400)
118
+REG32(A2W_PLLA_PER, 0x1500)
119
+REG32(A2W_PLLA_CCP2, 0x1600)
120
+
121
+REG32(A2W_PLLC_CORE2, 0x1320)
122
+REG32(A2W_PLLC_CORE1, 0x1420)
123
+REG32(A2W_PLLC_PER, 0x1520)
124
+REG32(A2W_PLLC_CORE0, 0x1620)
125
+
126
+REG32(A2W_PLLD_DSI0, 0x1340)
127
+REG32(A2W_PLLD_CORE, 0x1440)
128
+REG32(A2W_PLLD_PER, 0x1540)
129
+REG32(A2W_PLLD_DSI1, 0x1640)
130
+
131
+REG32(A2W_PLLH_AUX, 0x1360)
132
+REG32(A2W_PLLH_RCAL, 0x1460)
133
+REG32(A2W_PLLH_PIX, 0x1560)
134
+REG32(A2W_PLLH_STS, 0x1660)
135
+
136
+REG32(A2W_PLLB_ARM, 0x13e0)
137
+
138
/* misc registers */
139
REG32(CM_LOCK, 0x114)
140
FIELD(CM_LOCK, FLOCKH, 12, 1)
141
@@ -XXX,XX +XXX,XX @@ static inline void set_pll_init_info(BCM2835CprmanState *s,
142
pll->reg_a2w_frac = &s->regs[PLL_INIT_INFO[id].a2w_frac_offset];
143
}
144
145
+
146
+/* PLL channel init info */
147
+typedef struct PLLChannelInitInfo {
148
+ const char *name;
149
+ CprmanPll parent;
150
+ size_t cm_offset;
151
+ uint32_t cm_hold_mask;
152
+ uint32_t cm_load_mask;
153
+ size_t a2w_ctrl_offset;
154
+ unsigned int fixed_divider;
155
+} PLLChannelInitInfo;
156
+
157
+#define FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_) \
158
+ .parent = CPRMAN_ ## pll_, \
159
+ .cm_offset = R_CM_ ## pll_, \
160
+ .cm_load_mask = R_CM_ ## pll_ ## _ ## LOAD ## channel_ ## _MASK, \
161
+ .a2w_ctrl_offset = R_A2W_ ## pll_ ## _ ## channel_
162
+
163
+#define FILL_PLL_CHANNEL_INIT_INFO(pll_, channel_) \
164
+ FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_), \
165
+ .cm_hold_mask = R_CM_ ## pll_ ## _ ## HOLD ## channel_ ## _MASK, \
166
+ .fixed_divider = 1
167
+
168
+#define FILL_PLL_CHANNEL_INIT_INFO_nohold(pll_, channel_) \
169
+ FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_), \
170
+ .cm_hold_mask = 0
171
+
172
+static PLLChannelInitInfo PLL_CHANNEL_INIT_INFO[] = {
173
+ [CPRMAN_PLLA_CHANNEL_DSI0] = {
174
+ .name = "plla-dsi0",
175
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, DSI0),
176
+ },
177
+ [CPRMAN_PLLA_CHANNEL_CORE] = {
178
+ .name = "plla-core",
179
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, CORE),
180
+ },
181
+ [CPRMAN_PLLA_CHANNEL_PER] = {
182
+ .name = "plla-per",
183
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, PER),
184
+ },
185
+ [CPRMAN_PLLA_CHANNEL_CCP2] = {
186
+ .name = "plla-ccp2",
187
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, CCP2),
188
+ },
189
+
190
+ [CPRMAN_PLLC_CHANNEL_CORE2] = {
191
+ .name = "pllc-core2",
192
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE2),
193
+ },
194
+ [CPRMAN_PLLC_CHANNEL_CORE1] = {
195
+ .name = "pllc-core1",
196
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE1),
197
+ },
198
+ [CPRMAN_PLLC_CHANNEL_PER] = {
199
+ .name = "pllc-per",
200
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, PER),
201
+ },
202
+ [CPRMAN_PLLC_CHANNEL_CORE0] = {
203
+ .name = "pllc-core0",
204
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE0),
205
+ },
206
+
207
+ [CPRMAN_PLLD_CHANNEL_DSI0] = {
208
+ .name = "plld-dsi0",
209
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, DSI0),
210
+ },
211
+ [CPRMAN_PLLD_CHANNEL_CORE] = {
212
+ .name = "plld-core",
213
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, CORE),
214
+ },
215
+ [CPRMAN_PLLD_CHANNEL_PER] = {
216
+ .name = "plld-per",
217
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, PER),
218
+ },
219
+ [CPRMAN_PLLD_CHANNEL_DSI1] = {
220
+ .name = "plld-dsi1",
221
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, DSI1),
222
+ },
223
+
224
+ [CPRMAN_PLLH_CHANNEL_AUX] = {
225
+ .name = "pllh-aux",
226
+ .fixed_divider = 1,
227
+ FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, AUX),
228
+ },
229
+ [CPRMAN_PLLH_CHANNEL_RCAL] = {
230
+ .name = "pllh-rcal",
231
+ .fixed_divider = 10,
232
+ FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, RCAL),
233
+ },
234
+ [CPRMAN_PLLH_CHANNEL_PIX] = {
235
+ .name = "pllh-pix",
236
+ .fixed_divider = 10,
237
+ FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, PIX),
238
+ },
239
+
240
+ [CPRMAN_PLLB_CHANNEL_ARM] = {
241
+ .name = "pllb-arm",
242
+ FILL_PLL_CHANNEL_INIT_INFO(PLLB, ARM),
243
+ },
244
+};
245
+
246
+#undef FILL_PLL_CHANNEL_INIT_INFO_nohold
247
+#undef FILL_PLL_CHANNEL_INIT_INFO
248
+#undef FILL_PLL_CHANNEL_INIT_INFO_common
249
+
250
+static inline void set_pll_channel_init_info(BCM2835CprmanState *s,
251
+ CprmanPllChannelState *channel,
252
+ CprmanPllChannel id)
253
+{
254
+ channel->id = id;
255
+ channel->parent = PLL_CHANNEL_INIT_INFO[id].parent;
256
+ channel->reg_cm = &s->regs[PLL_CHANNEL_INIT_INFO[id].cm_offset];
257
+ channel->hold_mask = PLL_CHANNEL_INIT_INFO[id].cm_hold_mask;
258
+ channel->load_mask = PLL_CHANNEL_INIT_INFO[id].cm_load_mask;
259
+ channel->reg_a2w_ctrl = &s->regs[PLL_CHANNEL_INIT_INFO[id].a2w_ctrl_offset];
260
+ channel->fixed_divider = PLL_CHANNEL_INIT_INFO[id].fixed_divider;
261
+}
262
+
263
#endif
264
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
51
index XXXXXXX..XXXXXXX 100644
265
index XXXXXXX..XXXXXXX 100644
52
--- a/target/arm/helper.c
266
--- a/hw/misc/bcm2835_cprman.c
53
+++ b/target/arm/helper.c
267
+++ b/hw/misc/bcm2835_cprman.c
54
@@ -XXX,XX +XXX,XX @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
268
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
55
flags = FIELD_DP32(flags, TBFLAG_A32, STACKCHECK, 1);
269
};
270
271
272
+/* PLL channel */
273
+
274
+static void pll_channel_update(CprmanPllChannelState *channel)
275
+{
276
+ clock_update(channel->out, 0);
277
+}
278
+
279
+/* Update a PLL and all its channels */
280
+static void pll_update_all_channels(BCM2835CprmanState *s,
281
+ CprmanPllState *pll)
282
+{
283
+ size_t i;
284
+
285
+ pll_update(pll);
286
+
287
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
288
+ CprmanPllChannelState *channel = &s->channels[i];
289
+ if (channel->parent == pll->id) {
290
+ pll_channel_update(channel);
291
+ }
292
+ }
293
+}
294
+
295
+static void pll_channel_pll_in_update(void *opaque)
296
+{
297
+ pll_channel_update(CPRMAN_PLL_CHANNEL(opaque));
298
+}
299
+
300
+static void pll_channel_init(Object *obj)
301
+{
302
+ CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(obj);
303
+
304
+ s->pll_in = qdev_init_clock_in(DEVICE(s), "pll-in",
305
+ pll_channel_pll_in_update, s);
306
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
307
+}
308
+
309
+static const VMStateDescription pll_channel_vmstate = {
310
+ .name = TYPE_CPRMAN_PLL_CHANNEL,
311
+ .version_id = 1,
312
+ .minimum_version_id = 1,
313
+ .fields = (VMStateField[]) {
314
+ VMSTATE_CLOCK(pll_in, CprmanPllChannelState),
315
+ VMSTATE_END_OF_LIST()
316
+ }
317
+};
318
+
319
+static void pll_channel_class_init(ObjectClass *klass, void *data)
320
+{
321
+ DeviceClass *dc = DEVICE_CLASS(klass);
322
+
323
+ dc->vmsd = &pll_channel_vmstate;
324
+}
325
+
326
+static const TypeInfo cprman_pll_channel_info = {
327
+ .name = TYPE_CPRMAN_PLL_CHANNEL,
328
+ .parent = TYPE_DEVICE,
329
+ .instance_size = sizeof(CprmanPllChannelState),
330
+ .class_init = pll_channel_class_init,
331
+ .instance_init = pll_channel_init,
332
+};
333
+
334
+
335
/* CPRMAN "top level" model */
336
337
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
338
@@ -XXX,XX +XXX,XX @@ static uint64_t cprman_read(void *opaque, hwaddr offset,
339
return r;
340
}
341
342
-#define CASE_PLL_REGS(pll_) \
343
- case R_CM_ ## pll_: \
344
+static inline void update_pll_and_channels_from_cm(BCM2835CprmanState *s,
345
+ size_t idx)
346
+{
347
+ size_t i;
348
+
349
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
350
+ if (PLL_INIT_INFO[i].cm_offset == idx) {
351
+ pll_update_all_channels(s, &s->plls[i]);
352
+ return;
353
+ }
354
+ }
355
+}
356
+
357
+static inline void update_channel_from_a2w(BCM2835CprmanState *s, size_t idx)
358
+{
359
+ size_t i;
360
+
361
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
362
+ if (PLL_CHANNEL_INIT_INFO[i].a2w_ctrl_offset == idx) {
363
+ pll_channel_update(&s->channels[i]);
364
+ return;
365
+ }
366
+ }
367
+}
368
+
369
+#define CASE_PLL_A2W_REGS(pll_) \
370
case R_A2W_ ## pll_ ## _CTRL: \
371
case R_A2W_ ## pll_ ## _ANA0: \
372
case R_A2W_ ## pll_ ## _ANA1: \
373
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
374
s->regs[idx] = value;
375
376
switch (idx) {
377
- CASE_PLL_REGS(PLLA) :
378
+ case R_CM_PLLA ... R_CM_PLLH:
379
+ case R_CM_PLLB:
380
+ /*
381
+ * A given CM_PLLx register is shared by both the PLL and the channels
382
+ * of this PLL.
383
+ */
384
+ update_pll_and_channels_from_cm(s, idx);
385
+ break;
386
+
387
+ CASE_PLL_A2W_REGS(PLLA) :
388
pll_update(&s->plls[CPRMAN_PLLA]);
389
break;
390
391
- CASE_PLL_REGS(PLLC) :
392
+ CASE_PLL_A2W_REGS(PLLC) :
393
pll_update(&s->plls[CPRMAN_PLLC]);
394
break;
395
396
- CASE_PLL_REGS(PLLD) :
397
+ CASE_PLL_A2W_REGS(PLLD) :
398
pll_update(&s->plls[CPRMAN_PLLD]);
399
break;
400
401
- CASE_PLL_REGS(PLLH) :
402
+ CASE_PLL_A2W_REGS(PLLH) :
403
pll_update(&s->plls[CPRMAN_PLLH]);
404
break;
405
406
- CASE_PLL_REGS(PLLB) :
407
+ CASE_PLL_A2W_REGS(PLLB) :
408
pll_update(&s->plls[CPRMAN_PLLB]);
409
break;
410
+
411
+ case R_A2W_PLLA_DSI0:
412
+ case R_A2W_PLLA_CORE:
413
+ case R_A2W_PLLA_PER:
414
+ case R_A2W_PLLA_CCP2:
415
+ case R_A2W_PLLC_CORE2:
416
+ case R_A2W_PLLC_CORE1:
417
+ case R_A2W_PLLC_PER:
418
+ case R_A2W_PLLC_CORE0:
419
+ case R_A2W_PLLD_DSI0:
420
+ case R_A2W_PLLD_CORE:
421
+ case R_A2W_PLLD_PER:
422
+ case R_A2W_PLLD_DSI1:
423
+ case R_A2W_PLLH_AUX:
424
+ case R_A2W_PLLH_RCAL:
425
+ case R_A2W_PLLH_PIX:
426
+ case R_A2W_PLLB_ARM:
427
+ update_channel_from_a2w(s, idx);
428
+ break;
56
}
429
}
57
430
}
58
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY) &&
431
59
+ FIELD_EX32(env->v7m.fpccr[M_REG_S], V7M_FPCCR, S) != env->v7m.secure) {
432
-#undef CASE_PLL_REGS
60
+ flags = FIELD_DP32(flags, TBFLAG_A32, FPCCR_S_WRONG, 1);
433
+#undef CASE_PLL_A2W_REGS
61
+ }
434
62
+
435
static const MemoryRegionOps cprman_ops = {
63
*pflags = flags;
436
.read = cprman_read,
64
*cs_base = 0;
437
@@ -XXX,XX +XXX,XX @@ static void cprman_reset(DeviceState *dev)
65
}
438
device_cold_reset(DEVICE(&s->plls[i]));
66
diff --git a/target/arm/translate.c b/target/arm/translate.c
439
}
67
index XXXXXXX..XXXXXXX 100644
440
68
--- a/target/arm/translate.c
441
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
69
+++ b/target/arm/translate.c
442
+ device_cold_reset(DEVICE(&s->channels[i]));
70
@@ -XXX,XX +XXX,XX @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
443
+ }
444
+
445
clock_update_hz(s->xosc, s->xosc_freq);
446
}
447
448
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
449
set_pll_init_info(s, &s->plls[i], i);
450
}
451
452
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
453
+ object_initialize_child(obj, PLL_CHANNEL_INIT_INFO[i].name,
454
+ &s->channels[i],
455
+ TYPE_CPRMAN_PLL_CHANNEL);
456
+ set_pll_channel_init_info(s, &s->channels[i], i);
457
+ }
458
+
459
s->xosc = clock_new(obj, "xosc");
460
461
memory_region_init_io(&s->iomem, obj, &cprman_ops,
462
@@ -XXX,XX +XXX,XX @@ static void cprman_realize(DeviceState *dev, Error **errp)
463
return;
71
}
464
}
72
}
465
}
73
466
+
74
+ if (arm_dc_feature(s, ARM_FEATURE_M)) {
467
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
75
+ /* Handle M-profile lazy FP state mechanics */
468
+ CprmanPllChannelState *channel = &s->channels[i];
76
+
469
+ CprmanPll parent = PLL_CHANNEL_INIT_INFO[i].parent;
77
+ /* Update ownership of FP context: set FPCCR.S to match current state */
470
+ Clock *parent_clk = s->plls[parent].out;
78
+ if (s->v8m_fpccr_s_wrong) {
471
+
79
+ TCGv_i32 tmp;
472
+ clock_set_source(channel->pll_in, parent_clk);
80
+
473
+
81
+ tmp = load_cpu_field(v7m.fpccr[M_REG_S]);
474
+ if (!qdev_realize(DEVICE(channel), NULL, errp)) {
82
+ if (s->v8m_secure) {
475
+ return;
83
+ tcg_gen_ori_i32(tmp, tmp, R_V7M_FPCCR_S_MASK);
84
+ } else {
85
+ tcg_gen_andi_i32(tmp, tmp, ~R_V7M_FPCCR_S_MASK);
86
+ }
87
+ store_cpu_field(tmp, v7m.fpccr[M_REG_S]);
88
+ /* Don't need to do this for any further FP insns in this TB */
89
+ s->v8m_fpccr_s_wrong = false;
90
+ }
476
+ }
91
+ }
477
+ }
92
+
478
}
93
if (extract32(insn, 28, 4) == 0xf) {
479
94
/*
480
static const VMStateDescription cprman_vmstate = {
95
* Encodings with T=1 (Thumb) or unconditional (ARM):
481
@@ -XXX,XX +XXX,XX @@ static void cprman_register_types(void)
96
@@ -XXX,XX +XXX,XX @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
482
{
97
dc->v8m_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
483
type_register_static(&cprman_info);
98
regime_is_secure(env, dc->mmu_idx);
484
type_register_static(&cprman_pll_info);
99
dc->v8m_stackcheck = FIELD_EX32(tb_flags, TBFLAG_A32, STACKCHECK);
485
+ type_register_static(&cprman_pll_channel_info);
100
+ dc->v8m_fpccr_s_wrong = FIELD_EX32(tb_flags, TBFLAG_A32, FPCCR_S_WRONG);
486
}
101
dc->cp_regs = cpu->cp_regs;
487
102
dc->features = env->features;
488
type_init(cprman_register_types);
103
104
--
489
--
105
2.20.1
490
2.20.1
106
491
107
492
diff view generated by jsdifflib
1
Handle floating point registers in exception entry.
1
From: Luc Michel <luc@lmichel.fr>
2
This corresponds to the FP-specific parts of the pseudocode
3
functions ActivateException() and PushStack().
4
2
5
We defer the code corresponding to UpdateFPCCR() to a later patch.
3
A PLL channel is able to further divide the generated PLL frequency.
4
The divider is given in the CTRL_A2W register. Some channels have an
5
additional fixed divider which is always applied to the signal.
6
6
7
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Signed-off-by: Luc Michel <luc@lmichel.fr>
10
Tested-by: Guenter Roeck <linux@roeck-us.net>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20190416125744.27770-11-peter.maydell@linaro.org
10
---
12
---
11
target/arm/helper.c | 98 +++++++++++++++++++++++++++++++++++++++++++--
13
hw/misc/bcm2835_cprman.c | 33 ++++++++++++++++++++++++++++++++-
12
1 file changed, 95 insertions(+), 3 deletions(-)
14
1 file changed, 32 insertions(+), 1 deletion(-)
13
15
14
diff --git a/target/arm/helper.c b/target/arm/helper.c
16
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/helper.c
18
--- a/hw/misc/bcm2835_cprman.c
17
+++ b/target/arm/helper.c
19
+++ b/hw/misc/bcm2835_cprman.c
18
@@ -XXX,XX +XXX,XX @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
20
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
19
switch_v7m_security_state(env, targets_secure);
21
20
write_v7m_control_spsel(env, 0);
22
/* PLL channel */
21
arm_clear_exclusive(env);
23
22
+ /* Clear SFPA and FPCA (has no effect if no FPU) */
24
+static bool pll_channel_is_enabled(CprmanPllChannelState *channel)
23
+ env->v7m.control[M_REG_S] &=
25
+{
24
+ ~(R_V7M_CONTROL_FPCA_MASK | R_V7M_CONTROL_SFPA_MASK);
26
+ /*
25
/* Clear IT bits */
27
+ * XXX I'm not sure of the purpose of the LOAD field. The Linux driver does
26
env->condexec_bits = 0;
28
+ * not set it when enabling the channel, but does clear it when disabling
27
env->regs[14] = lr;
29
+ * it.
28
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_stack(ARMCPU *cpu)
30
+ */
29
uint32_t xpsr = xpsr_read(env);
31
+ return !FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DISABLE)
30
uint32_t frameptr = env->regs[13];
32
+ && !(*channel->reg_cm & channel->hold_mask);
31
ARMMMUIdx mmu_idx = arm_mmu_idx(env);
33
+}
32
+ uint32_t framesize;
33
+ bool nsacr_cp10 = extract32(env->v7m.nsacr, 10, 1);
34
+
34
+
35
+ if ((env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) &&
35
static void pll_channel_update(CprmanPllChannelState *channel)
36
+ (env->v7m.secure || nsacr_cp10)) {
36
{
37
+ if (env->v7m.secure &&
37
- clock_update(channel->out, 0);
38
+ env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK) {
38
+ uint64_t freq, div;
39
+ framesize = 0xa8;
39
+
40
+ } else {
40
+ if (!pll_channel_is_enabled(channel)) {
41
+ framesize = 0x68;
41
+ clock_update(channel->out, 0);
42
+ }
42
+ return;
43
+ } else {
44
+ framesize = 0x20;
45
+ }
46
47
/* Align stack pointer if the guest wants that */
48
if ((frameptr & 4) &&
49
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_stack(ARMCPU *cpu)
50
xpsr |= XPSR_SPREALIGN;
51
}
52
53
- frameptr -= 0x20;
54
+ xpsr &= ~XPSR_SFPA;
55
+ if (env->v7m.secure &&
56
+ (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
57
+ xpsr |= XPSR_SFPA;
58
+ }
43
+ }
59
+
44
+
60
+ frameptr -= framesize;
45
+ div = FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DIV);
61
62
if (arm_feature(env, ARM_FEATURE_V8)) {
63
uint32_t limit = v7m_sp_limit(env);
64
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_stack(ARMCPU *cpu)
65
v7m_stack_write(cpu, frameptr + 24, env->regs[15], mmu_idx, false) &&
66
v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, false);
67
68
+ if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) {
69
+ /* FPU is active, try to save its registers */
70
+ bool fpccr_s = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
71
+ bool lspact = env->v7m.fpccr[fpccr_s] & R_V7M_FPCCR_LSPACT_MASK;
72
+
46
+
73
+ if (lspact && arm_feature(env, ARM_FEATURE_M_SECURITY)) {
47
+ if (!div) {
74
+ qemu_log_mask(CPU_LOG_INT,
48
+ /*
75
+ "...SecureFault because LSPACT and FPCA both set\n");
49
+ * It seems that when the divider value is 0, it is considered as
76
+ env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
50
+ * being maximum by the hardware (see the Linux driver).
77
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
51
+ */
78
+ } else if (!env->v7m.secure && !nsacr_cp10) {
52
+ div = R_A2W_PLLx_CHANNELy_DIV_MASK;
79
+ qemu_log_mask(CPU_LOG_INT,
80
+ "...Secure UsageFault with CFSR.NOCP because "
81
+ "NSACR.CP10 prevents stacking FP regs\n");
82
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S);
83
+ env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_NOCP_MASK;
84
+ } else {
85
+ if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) {
86
+ /* Lazy stacking disabled, save registers now */
87
+ int i;
88
+ bool cpacr_pass = v7m_cpacr_pass(env, env->v7m.secure,
89
+ arm_current_el(env) != 0);
90
+
91
+ if (stacked_ok && !cpacr_pass) {
92
+ /*
93
+ * Take UsageFault if CPACR forbids access. The pseudocode
94
+ * here does a full CheckCPEnabled() but we know the NSACR
95
+ * check can never fail as we have already handled that.
96
+ */
97
+ qemu_log_mask(CPU_LOG_INT,
98
+ "...UsageFault with CFSR.NOCP because "
99
+ "CPACR.CP10 prevents stacking FP regs\n");
100
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
101
+ env->v7m.secure);
102
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK;
103
+ stacked_ok = false;
104
+ }
105
+
106
+ for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
107
+ uint64_t dn = *aa32_vfp_dreg(env, i / 2);
108
+ uint32_t faddr = frameptr + 0x20 + 4 * i;
109
+ uint32_t slo = extract64(dn, 0, 32);
110
+ uint32_t shi = extract64(dn, 32, 32);
111
+
112
+ if (i >= 16) {
113
+ faddr += 8; /* skip the slot for the FPSCR */
114
+ }
115
+ stacked_ok = stacked_ok &&
116
+ v7m_stack_write(cpu, faddr, slo, mmu_idx, false) &&
117
+ v7m_stack_write(cpu, faddr + 4, shi, mmu_idx, false);
118
+ }
119
+ stacked_ok = stacked_ok &&
120
+ v7m_stack_write(cpu, frameptr + 0x60,
121
+ vfp_get_fpscr(env), mmu_idx, false);
122
+ if (cpacr_pass) {
123
+ for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
124
+ *aa32_vfp_dreg(env, i / 2) = 0;
125
+ }
126
+ vfp_set_fpscr(env, 0);
127
+ }
128
+ } else {
129
+ /* Lazy stacking enabled, save necessary info to stack later */
130
+ /* TODO : equivalent of UpdateFPCCR() pseudocode */
131
+ }
132
+ }
133
+ }
53
+ }
134
+
54
+
135
/*
55
+ /* Some channels have an additional fixed divider */
136
* If we broke a stack limit then SP was already updated earlier;
56
+ freq = clock_get_hz(channel->pll_in) / (div * channel->fixed_divider);
137
* otherwise we update SP regardless of whether any of the stack
57
+
138
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
58
+ clock_update_hz(channel->out, freq);
139
59
}
140
if (arm_feature(env, ARM_FEATURE_V8)) {
60
141
lr = R_V7M_EXCRET_RES1_MASK |
61
/* Update a PLL and all its channels */
142
- R_V7M_EXCRET_DCRS_MASK |
143
- R_V7M_EXCRET_FTYPE_MASK;
144
+ R_V7M_EXCRET_DCRS_MASK;
145
/* The S bit indicates whether we should return to Secure
146
* or NonSecure (ie our current state).
147
* The ES bit indicates whether we're taking this exception
148
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
149
if (env->v7m.secure) {
150
lr |= R_V7M_EXCRET_S_MASK;
151
}
152
+ if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
153
+ lr |= R_V7M_EXCRET_FTYPE_MASK;
154
+ }
155
} else {
156
lr = R_V7M_EXCRET_RES1_MASK |
157
R_V7M_EXCRET_S_MASK |
158
--
62
--
159
2.20.1
63
2.20.1
160
64
161
65
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
No code used the tc6393xb_gpio_in_get() and tc6393xb_gpio_out_set()
3
The clock multiplexers are the last clock stage in the CPRMAN. Each mux
4
functions since their introduction in commit 88d2c950b002. Time to
4
outputs one clock signal that goes out of the CPRMAN to the SoC
5
remove them.
5
peripherals.
6
6
7
Suggested-by: Markus Armbruster <armbru@redhat.com>
7
Each mux has at most 10 sources. The sources 0 to 3 are common to all
8
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
muxes. They are:
9
Message-id: 20190412165416.7977-4-philmd@redhat.com
9
0. ground (no clock signal)
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
1. the main oscillator (xosc)
11
2. "test debug 0" clock
12
3. "test debug 1" clock
13
14
Test debug 0 and 1 are actual clock muxes that can be used as sources to
15
other muxes (for debug purpose).
16
17
Sources 4 to 9 are mux specific and can be unpopulated (grounded). Those
18
sources are fed by the PLL channels outputs.
19
20
One corner case exists for DSI0E and DSI0P muxes. They have their source
21
number 4 connected to an intermediate multiplexer that can select
22
between PLLA-DSI0 and PLLD-DSI0 channel. This multiplexer is called
23
DSI0HSCK and is not a clock mux as such. It is really a simple mux from
24
the hardware point of view (see https://elinux.org/The_Undocumented_Pi).
25
This mux is not implemented in this commit.
26
27
Note that there is some muxes for which sources are unknown (because of
28
a lack of documentation). For those cases all the sources are connected
29
to ground in this implementation.
30
31
Each clock mux output is exported by the CPRMAN at the qdev level,
32
adding the suffix '-out' to the mux name to form the output clock name.
33
(E.g. the 'uart' mux sees its output exported as 'uart-out' at the
34
CPRMAN level.)
35
36
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
37
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
38
Signed-off-by: Luc Michel <luc@lmichel.fr>
39
Tested-by: Guenter Roeck <linux@roeck-us.net>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
40
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
41
---
13
include/hw/devices.h | 3 ---
42
include/hw/misc/bcm2835_cprman.h | 85 +++++
14
hw/display/tc6393xb.c | 16 ----------------
43
include/hw/misc/bcm2835_cprman_internals.h | 422 +++++++++++++++++++++
15
2 files changed, 19 deletions(-)
44
hw/misc/bcm2835_cprman.c | 151 ++++++++
16
45
3 files changed, 658 insertions(+)
17
diff --git a/include/hw/devices.h b/include/hw/devices.h
46
47
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
18
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
19
--- a/include/hw/devices.h
49
--- a/include/hw/misc/bcm2835_cprman.h
20
+++ b/include/hw/devices.h
50
+++ b/include/hw/misc/bcm2835_cprman.h
21
@@ -XXX,XX +XXX,XX @@ void retu_key_event(void *retu, int state);
51
@@ -XXX,XX +XXX,XX @@ typedef enum CprmanPllChannel {
22
typedef struct TC6393xbState TC6393xbState;
52
CPRMAN_PLLB_CHANNEL_ARM,
23
TC6393xbState *tc6393xb_init(struct MemoryRegion *sysmem,
53
24
uint32_t base, qemu_irq irq);
54
CPRMAN_NUM_PLL_CHANNEL,
25
-void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
55
+
26
- qemu_irq handler);
56
+ /* Special values used when connecting clock sources to clocks */
27
-qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s);
57
+ CPRMAN_CLOCK_SRC_NORMAL = -1,
28
qemu_irq tc6393xb_l3v_get(TC6393xbState *s);
58
+ CPRMAN_CLOCK_SRC_FORCE_GROUND = -2,
59
+ CPRMAN_CLOCK_SRC_DSI0HSCK = -3,
60
} CprmanPllChannel;
61
62
+typedef enum CprmanClockMux {
63
+ CPRMAN_CLOCK_GNRIC,
64
+ CPRMAN_CLOCK_VPU,
65
+ CPRMAN_CLOCK_SYS,
66
+ CPRMAN_CLOCK_PERIA,
67
+ CPRMAN_CLOCK_PERII,
68
+ CPRMAN_CLOCK_H264,
69
+ CPRMAN_CLOCK_ISP,
70
+ CPRMAN_CLOCK_V3D,
71
+ CPRMAN_CLOCK_CAM0,
72
+ CPRMAN_CLOCK_CAM1,
73
+ CPRMAN_CLOCK_CCP2,
74
+ CPRMAN_CLOCK_DSI0E,
75
+ CPRMAN_CLOCK_DSI0P,
76
+ CPRMAN_CLOCK_DPI,
77
+ CPRMAN_CLOCK_GP0,
78
+ CPRMAN_CLOCK_GP1,
79
+ CPRMAN_CLOCK_GP2,
80
+ CPRMAN_CLOCK_HSM,
81
+ CPRMAN_CLOCK_OTP,
82
+ CPRMAN_CLOCK_PCM,
83
+ CPRMAN_CLOCK_PWM,
84
+ CPRMAN_CLOCK_SLIM,
85
+ CPRMAN_CLOCK_SMI,
86
+ CPRMAN_CLOCK_TEC,
87
+ CPRMAN_CLOCK_TD0,
88
+ CPRMAN_CLOCK_TD1,
89
+ CPRMAN_CLOCK_TSENS,
90
+ CPRMAN_CLOCK_TIMER,
91
+ CPRMAN_CLOCK_UART,
92
+ CPRMAN_CLOCK_VEC,
93
+ CPRMAN_CLOCK_PULSE,
94
+ CPRMAN_CLOCK_SDC,
95
+ CPRMAN_CLOCK_ARM,
96
+ CPRMAN_CLOCK_AVEO,
97
+ CPRMAN_CLOCK_EMMC,
98
+ CPRMAN_CLOCK_EMMC2,
99
+
100
+ CPRMAN_NUM_CLOCK_MUX
101
+} CprmanClockMux;
102
+
103
+typedef enum CprmanClockMuxSource {
104
+ CPRMAN_CLOCK_SRC_GND = 0,
105
+ CPRMAN_CLOCK_SRC_XOSC,
106
+ CPRMAN_CLOCK_SRC_TD0,
107
+ CPRMAN_CLOCK_SRC_TD1,
108
+ CPRMAN_CLOCK_SRC_PLLA,
109
+ CPRMAN_CLOCK_SRC_PLLC,
110
+ CPRMAN_CLOCK_SRC_PLLD,
111
+ CPRMAN_CLOCK_SRC_PLLH,
112
+ CPRMAN_CLOCK_SRC_PLLC_CORE1,
113
+ CPRMAN_CLOCK_SRC_PLLC_CORE2,
114
+
115
+ CPRMAN_NUM_CLOCK_MUX_SRC
116
+} CprmanClockMuxSource;
117
+
118
typedef struct CprmanPllState {
119
/*< private >*/
120
DeviceState parent_obj;
121
@@ -XXX,XX +XXX,XX @@ typedef struct CprmanPllChannelState {
122
Clock *out;
123
} CprmanPllChannelState;
124
125
+typedef struct CprmanClockMuxState {
126
+ /*< private >*/
127
+ DeviceState parent_obj;
128
+
129
+ /*< public >*/
130
+ CprmanClockMux id;
131
+
132
+ uint32_t *reg_ctl;
133
+ uint32_t *reg_div;
134
+ int int_bits;
135
+ int frac_bits;
136
+
137
+ Clock *srcs[CPRMAN_NUM_CLOCK_MUX_SRC];
138
+ Clock *out;
139
+
140
+ /*
141
+ * Used by clock srcs update callback to retrieve both the clock and the
142
+ * source number.
143
+ */
144
+ struct CprmanClockMuxState *backref[CPRMAN_NUM_CLOCK_MUX_SRC];
145
+} CprmanClockMuxState;
146
+
147
struct BCM2835CprmanState {
148
/*< private >*/
149
SysBusDevice parent_obj;
150
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
151
152
CprmanPllState plls[CPRMAN_NUM_PLL];
153
CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
154
+ CprmanClockMuxState clock_muxes[CPRMAN_NUM_CLOCK_MUX];
155
156
uint32_t regs[CPRMAN_NUM_REGS];
157
uint32_t xosc_freq;
158
159
Clock *xosc;
160
+ Clock *gnd;
161
};
29
162
30
#endif
163
#endif
31
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
164
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
32
index XXXXXXX..XXXXXXX 100644
165
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/display/tc6393xb.c
166
--- a/include/hw/misc/bcm2835_cprman_internals.h
34
+++ b/hw/display/tc6393xb.c
167
+++ b/include/hw/misc/bcm2835_cprman_internals.h
35
@@ -XXX,XX +XXX,XX @@ struct TC6393xbState {
168
@@ -XXX,XX +XXX,XX @@
36
blanked : 1;
169
170
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
171
#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
172
+#define TYPE_CPRMAN_CLOCK_MUX "bcm2835-cprman-clock-mux"
173
174
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
175
TYPE_CPRMAN_PLL)
176
DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL,
177
TYPE_CPRMAN_PLL_CHANNEL)
178
+DECLARE_INSTANCE_CHECKER(CprmanClockMuxState, CPRMAN_CLOCK_MUX,
179
+ TYPE_CPRMAN_CLOCK_MUX)
180
181
/* Register map */
182
183
@@ -XXX,XX +XXX,XX @@ REG32(A2W_PLLH_STS, 0x1660)
184
185
REG32(A2W_PLLB_ARM, 0x13e0)
186
187
+/* Clock muxes */
188
+REG32(CM_GNRICCTL, 0x000)
189
+ FIELD(CM_CLOCKx_CTL, SRC, 0, 4)
190
+ FIELD(CM_CLOCKx_CTL, ENABLE, 4, 1)
191
+ FIELD(CM_CLOCKx_CTL, KILL, 5, 1)
192
+ FIELD(CM_CLOCKx_CTL, GATE, 6, 1)
193
+ FIELD(CM_CLOCKx_CTL, BUSY, 7, 1)
194
+ FIELD(CM_CLOCKx_CTL, BUSYD, 8, 1)
195
+ FIELD(CM_CLOCKx_CTL, MASH, 9, 2)
196
+ FIELD(CM_CLOCKx_CTL, FLIP, 11, 1)
197
+REG32(CM_GNRICDIV, 0x004)
198
+ FIELD(CM_CLOCKx_DIV, FRAC, 0, 12)
199
+REG32(CM_VPUCTL, 0x008)
200
+REG32(CM_VPUDIV, 0x00c)
201
+REG32(CM_SYSCTL, 0x010)
202
+REG32(CM_SYSDIV, 0x014)
203
+REG32(CM_PERIACTL, 0x018)
204
+REG32(CM_PERIADIV, 0x01c)
205
+REG32(CM_PERIICTL, 0x020)
206
+REG32(CM_PERIIDIV, 0x024)
207
+REG32(CM_H264CTL, 0x028)
208
+REG32(CM_H264DIV, 0x02c)
209
+REG32(CM_ISPCTL, 0x030)
210
+REG32(CM_ISPDIV, 0x034)
211
+REG32(CM_V3DCTL, 0x038)
212
+REG32(CM_V3DDIV, 0x03c)
213
+REG32(CM_CAM0CTL, 0x040)
214
+REG32(CM_CAM0DIV, 0x044)
215
+REG32(CM_CAM1CTL, 0x048)
216
+REG32(CM_CAM1DIV, 0x04c)
217
+REG32(CM_CCP2CTL, 0x050)
218
+REG32(CM_CCP2DIV, 0x054)
219
+REG32(CM_DSI0ECTL, 0x058)
220
+REG32(CM_DSI0EDIV, 0x05c)
221
+REG32(CM_DSI0PCTL, 0x060)
222
+REG32(CM_DSI0PDIV, 0x064)
223
+REG32(CM_DPICTL, 0x068)
224
+REG32(CM_DPIDIV, 0x06c)
225
+REG32(CM_GP0CTL, 0x070)
226
+REG32(CM_GP0DIV, 0x074)
227
+REG32(CM_GP1CTL, 0x078)
228
+REG32(CM_GP1DIV, 0x07c)
229
+REG32(CM_GP2CTL, 0x080)
230
+REG32(CM_GP2DIV, 0x084)
231
+REG32(CM_HSMCTL, 0x088)
232
+REG32(CM_HSMDIV, 0x08c)
233
+REG32(CM_OTPCTL, 0x090)
234
+REG32(CM_OTPDIV, 0x094)
235
+REG32(CM_PCMCTL, 0x098)
236
+REG32(CM_PCMDIV, 0x09c)
237
+REG32(CM_PWMCTL, 0x0a0)
238
+REG32(CM_PWMDIV, 0x0a4)
239
+REG32(CM_SLIMCTL, 0x0a8)
240
+REG32(CM_SLIMDIV, 0x0ac)
241
+REG32(CM_SMICTL, 0x0b0)
242
+REG32(CM_SMIDIV, 0x0b4)
243
+REG32(CM_TCNTCTL, 0x0c0)
244
+REG32(CM_TCNTCNT, 0x0c4)
245
+REG32(CM_TECCTL, 0x0c8)
246
+REG32(CM_TECDIV, 0x0cc)
247
+REG32(CM_TD0CTL, 0x0d0)
248
+REG32(CM_TD0DIV, 0x0d4)
249
+REG32(CM_TD1CTL, 0x0d8)
250
+REG32(CM_TD1DIV, 0x0dc)
251
+REG32(CM_TSENSCTL, 0x0e0)
252
+REG32(CM_TSENSDIV, 0x0e4)
253
+REG32(CM_TIMERCTL, 0x0e8)
254
+REG32(CM_TIMERDIV, 0x0ec)
255
+REG32(CM_UARTCTL, 0x0f0)
256
+REG32(CM_UARTDIV, 0x0f4)
257
+REG32(CM_VECCTL, 0x0f8)
258
+REG32(CM_VECDIV, 0x0fc)
259
+REG32(CM_PULSECTL, 0x190)
260
+REG32(CM_PULSEDIV, 0x194)
261
+REG32(CM_SDCCTL, 0x1a8)
262
+REG32(CM_SDCDIV, 0x1ac)
263
+REG32(CM_ARMCTL, 0x1b0)
264
+REG32(CM_AVEOCTL, 0x1b8)
265
+REG32(CM_AVEODIV, 0x1bc)
266
+REG32(CM_EMMCCTL, 0x1c0)
267
+REG32(CM_EMMCDIV, 0x1c4)
268
+REG32(CM_EMMC2CTL, 0x1d0)
269
+REG32(CM_EMMC2DIV, 0x1d4)
270
+
271
/* misc registers */
272
REG32(CM_LOCK, 0x114)
273
FIELD(CM_LOCK, FLOCKH, 12, 1)
274
@@ -XXX,XX +XXX,XX @@ static inline void set_pll_channel_init_info(BCM2835CprmanState *s,
275
channel->fixed_divider = PLL_CHANNEL_INIT_INFO[id].fixed_divider;
276
}
277
278
+/* Clock mux init info */
279
+typedef struct ClockMuxInitInfo {
280
+ const char *name;
281
+ size_t cm_offset; /* cm_offset[0]->CM_CTL, cm_offset[1]->CM_DIV */
282
+ int int_bits;
283
+ int frac_bits;
284
+
285
+ CprmanPllChannel src_mapping[CPRMAN_NUM_CLOCK_MUX_SRC];
286
+} ClockMuxInitInfo;
287
+
288
+/*
289
+ * Each clock mux can have up to 10 sources. Sources 0 to 3 are always the
290
+ * same (ground, xosc, td0, td1). Sources 4 to 9 are mux specific, and are not
291
+ * always populated. The following macros catch all those cases.
292
+ */
293
+
294
+/* Unknown mapping. Connect everything to ground */
295
+#define SRC_MAPPING_INFO_unknown \
296
+ .src_mapping = { \
297
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* gnd */ \
298
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* xosc */ \
299
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* test debug 0 */ \
300
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* test debug 1 */ \
301
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll a */ \
302
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c */ \
303
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll d */ \
304
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll h */ \
305
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c, core1 */ \
306
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c, core2 */ \
307
+ }
308
+
309
+/* Only the oscillator and the two test debug clocks */
310
+#define SRC_MAPPING_INFO_xosc \
311
+ .src_mapping = { \
312
+ CPRMAN_CLOCK_SRC_NORMAL, \
313
+ CPRMAN_CLOCK_SRC_NORMAL, \
314
+ CPRMAN_CLOCK_SRC_NORMAL, \
315
+ CPRMAN_CLOCK_SRC_NORMAL, \
316
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
317
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
318
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
319
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
320
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
321
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
322
+ }
323
+
324
+/* All the PLL "core" channels */
325
+#define SRC_MAPPING_INFO_core \
326
+ .src_mapping = { \
327
+ CPRMAN_CLOCK_SRC_NORMAL, \
328
+ CPRMAN_CLOCK_SRC_NORMAL, \
329
+ CPRMAN_CLOCK_SRC_NORMAL, \
330
+ CPRMAN_CLOCK_SRC_NORMAL, \
331
+ CPRMAN_PLLA_CHANNEL_CORE, \
332
+ CPRMAN_PLLC_CHANNEL_CORE0, \
333
+ CPRMAN_PLLD_CHANNEL_CORE, \
334
+ CPRMAN_PLLH_CHANNEL_AUX, \
335
+ CPRMAN_PLLC_CHANNEL_CORE1, \
336
+ CPRMAN_PLLC_CHANNEL_CORE2, \
337
+ }
338
+
339
+/* All the PLL "per" channels */
340
+#define SRC_MAPPING_INFO_periph \
341
+ .src_mapping = { \
342
+ CPRMAN_CLOCK_SRC_NORMAL, \
343
+ CPRMAN_CLOCK_SRC_NORMAL, \
344
+ CPRMAN_CLOCK_SRC_NORMAL, \
345
+ CPRMAN_CLOCK_SRC_NORMAL, \
346
+ CPRMAN_PLLA_CHANNEL_PER, \
347
+ CPRMAN_PLLC_CHANNEL_PER, \
348
+ CPRMAN_PLLD_CHANNEL_PER, \
349
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
350
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
351
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
352
+ }
353
+
354
+/*
355
+ * The DSI0 channels. This one got an intermediate mux between the PLL channels
356
+ * and the clock input.
357
+ */
358
+#define SRC_MAPPING_INFO_dsi0 \
359
+ .src_mapping = { \
360
+ CPRMAN_CLOCK_SRC_NORMAL, \
361
+ CPRMAN_CLOCK_SRC_NORMAL, \
362
+ CPRMAN_CLOCK_SRC_NORMAL, \
363
+ CPRMAN_CLOCK_SRC_NORMAL, \
364
+ CPRMAN_CLOCK_SRC_DSI0HSCK, \
365
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
366
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
367
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
368
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
369
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
370
+ }
371
+
372
+/* The DSI1 channel */
373
+#define SRC_MAPPING_INFO_dsi1 \
374
+ .src_mapping = { \
375
+ CPRMAN_CLOCK_SRC_NORMAL, \
376
+ CPRMAN_CLOCK_SRC_NORMAL, \
377
+ CPRMAN_CLOCK_SRC_NORMAL, \
378
+ CPRMAN_CLOCK_SRC_NORMAL, \
379
+ CPRMAN_PLLD_CHANNEL_DSI1, \
380
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
381
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
382
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
383
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
384
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
385
+ }
386
+
387
+#define FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO(kind_) \
388
+ SRC_MAPPING_INFO_ ## kind_
389
+
390
+#define FILL_CLOCK_MUX_INIT_INFO(clock_, kind_) \
391
+ .cm_offset = R_CM_ ## clock_ ## CTL, \
392
+ FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO(kind_)
393
+
394
+static ClockMuxInitInfo CLOCK_MUX_INIT_INFO[] = {
395
+ [CPRMAN_CLOCK_GNRIC] = {
396
+ .name = "gnric",
397
+ FILL_CLOCK_MUX_INIT_INFO(GNRIC, unknown),
398
+ },
399
+ [CPRMAN_CLOCK_VPU] = {
400
+ .name = "vpu",
401
+ .int_bits = 12,
402
+ .frac_bits = 8,
403
+ FILL_CLOCK_MUX_INIT_INFO(VPU, core),
404
+ },
405
+ [CPRMAN_CLOCK_SYS] = {
406
+ .name = "sys",
407
+ FILL_CLOCK_MUX_INIT_INFO(SYS, unknown),
408
+ },
409
+ [CPRMAN_CLOCK_PERIA] = {
410
+ .name = "peria",
411
+ FILL_CLOCK_MUX_INIT_INFO(PERIA, unknown),
412
+ },
413
+ [CPRMAN_CLOCK_PERII] = {
414
+ .name = "perii",
415
+ FILL_CLOCK_MUX_INIT_INFO(PERII, unknown),
416
+ },
417
+ [CPRMAN_CLOCK_H264] = {
418
+ .name = "h264",
419
+ .int_bits = 4,
420
+ .frac_bits = 8,
421
+ FILL_CLOCK_MUX_INIT_INFO(H264, core),
422
+ },
423
+ [CPRMAN_CLOCK_ISP] = {
424
+ .name = "isp",
425
+ .int_bits = 4,
426
+ .frac_bits = 8,
427
+ FILL_CLOCK_MUX_INIT_INFO(ISP, core),
428
+ },
429
+ [CPRMAN_CLOCK_V3D] = {
430
+ .name = "v3d",
431
+ FILL_CLOCK_MUX_INIT_INFO(V3D, core),
432
+ },
433
+ [CPRMAN_CLOCK_CAM0] = {
434
+ .name = "cam0",
435
+ .int_bits = 4,
436
+ .frac_bits = 8,
437
+ FILL_CLOCK_MUX_INIT_INFO(CAM0, periph),
438
+ },
439
+ [CPRMAN_CLOCK_CAM1] = {
440
+ .name = "cam1",
441
+ .int_bits = 4,
442
+ .frac_bits = 8,
443
+ FILL_CLOCK_MUX_INIT_INFO(CAM1, periph),
444
+ },
445
+ [CPRMAN_CLOCK_CCP2] = {
446
+ .name = "ccp2",
447
+ FILL_CLOCK_MUX_INIT_INFO(CCP2, unknown),
448
+ },
449
+ [CPRMAN_CLOCK_DSI0E] = {
450
+ .name = "dsi0e",
451
+ .int_bits = 4,
452
+ .frac_bits = 8,
453
+ FILL_CLOCK_MUX_INIT_INFO(DSI0E, dsi0),
454
+ },
455
+ [CPRMAN_CLOCK_DSI0P] = {
456
+ .name = "dsi0p",
457
+ .int_bits = 0,
458
+ .frac_bits = 0,
459
+ FILL_CLOCK_MUX_INIT_INFO(DSI0P, dsi0),
460
+ },
461
+ [CPRMAN_CLOCK_DPI] = {
462
+ .name = "dpi",
463
+ .int_bits = 4,
464
+ .frac_bits = 8,
465
+ FILL_CLOCK_MUX_INIT_INFO(DPI, periph),
466
+ },
467
+ [CPRMAN_CLOCK_GP0] = {
468
+ .name = "gp0",
469
+ .int_bits = 12,
470
+ .frac_bits = 12,
471
+ FILL_CLOCK_MUX_INIT_INFO(GP0, periph),
472
+ },
473
+ [CPRMAN_CLOCK_GP1] = {
474
+ .name = "gp1",
475
+ .int_bits = 12,
476
+ .frac_bits = 12,
477
+ FILL_CLOCK_MUX_INIT_INFO(GP1, periph),
478
+ },
479
+ [CPRMAN_CLOCK_GP2] = {
480
+ .name = "gp2",
481
+ .int_bits = 12,
482
+ .frac_bits = 12,
483
+ FILL_CLOCK_MUX_INIT_INFO(GP2, periph),
484
+ },
485
+ [CPRMAN_CLOCK_HSM] = {
486
+ .name = "hsm",
487
+ .int_bits = 4,
488
+ .frac_bits = 8,
489
+ FILL_CLOCK_MUX_INIT_INFO(HSM, periph),
490
+ },
491
+ [CPRMAN_CLOCK_OTP] = {
492
+ .name = "otp",
493
+ .int_bits = 4,
494
+ .frac_bits = 0,
495
+ FILL_CLOCK_MUX_INIT_INFO(OTP, xosc),
496
+ },
497
+ [CPRMAN_CLOCK_PCM] = {
498
+ .name = "pcm",
499
+ .int_bits = 12,
500
+ .frac_bits = 12,
501
+ FILL_CLOCK_MUX_INIT_INFO(PCM, periph),
502
+ },
503
+ [CPRMAN_CLOCK_PWM] = {
504
+ .name = "pwm",
505
+ .int_bits = 12,
506
+ .frac_bits = 12,
507
+ FILL_CLOCK_MUX_INIT_INFO(PWM, periph),
508
+ },
509
+ [CPRMAN_CLOCK_SLIM] = {
510
+ .name = "slim",
511
+ .int_bits = 12,
512
+ .frac_bits = 12,
513
+ FILL_CLOCK_MUX_INIT_INFO(SLIM, periph),
514
+ },
515
+ [CPRMAN_CLOCK_SMI] = {
516
+ .name = "smi",
517
+ .int_bits = 4,
518
+ .frac_bits = 8,
519
+ FILL_CLOCK_MUX_INIT_INFO(SMI, periph),
520
+ },
521
+ [CPRMAN_CLOCK_TEC] = {
522
+ .name = "tec",
523
+ .int_bits = 6,
524
+ .frac_bits = 0,
525
+ FILL_CLOCK_MUX_INIT_INFO(TEC, xosc),
526
+ },
527
+ [CPRMAN_CLOCK_TD0] = {
528
+ .name = "td0",
529
+ FILL_CLOCK_MUX_INIT_INFO(TD0, unknown),
530
+ },
531
+ [CPRMAN_CLOCK_TD1] = {
532
+ .name = "td1",
533
+ FILL_CLOCK_MUX_INIT_INFO(TD1, unknown),
534
+ },
535
+ [CPRMAN_CLOCK_TSENS] = {
536
+ .name = "tsens",
537
+ .int_bits = 5,
538
+ .frac_bits = 0,
539
+ FILL_CLOCK_MUX_INIT_INFO(TSENS, xosc),
540
+ },
541
+ [CPRMAN_CLOCK_TIMER] = {
542
+ .name = "timer",
543
+ .int_bits = 6,
544
+ .frac_bits = 12,
545
+ FILL_CLOCK_MUX_INIT_INFO(TIMER, xosc),
546
+ },
547
+ [CPRMAN_CLOCK_UART] = {
548
+ .name = "uart",
549
+ .int_bits = 10,
550
+ .frac_bits = 12,
551
+ FILL_CLOCK_MUX_INIT_INFO(UART, periph),
552
+ },
553
+ [CPRMAN_CLOCK_VEC] = {
554
+ .name = "vec",
555
+ .int_bits = 4,
556
+ .frac_bits = 0,
557
+ FILL_CLOCK_MUX_INIT_INFO(VEC, periph),
558
+ },
559
+ [CPRMAN_CLOCK_PULSE] = {
560
+ .name = "pulse",
561
+ FILL_CLOCK_MUX_INIT_INFO(PULSE, xosc),
562
+ },
563
+ [CPRMAN_CLOCK_SDC] = {
564
+ .name = "sdram",
565
+ .int_bits = 6,
566
+ .frac_bits = 0,
567
+ FILL_CLOCK_MUX_INIT_INFO(SDC, core),
568
+ },
569
+ [CPRMAN_CLOCK_ARM] = {
570
+ .name = "arm",
571
+ FILL_CLOCK_MUX_INIT_INFO(ARM, unknown),
572
+ },
573
+ [CPRMAN_CLOCK_AVEO] = {
574
+ .name = "aveo",
575
+ .int_bits = 4,
576
+ .frac_bits = 0,
577
+ FILL_CLOCK_MUX_INIT_INFO(AVEO, periph),
578
+ },
579
+ [CPRMAN_CLOCK_EMMC] = {
580
+ .name = "emmc",
581
+ .int_bits = 4,
582
+ .frac_bits = 8,
583
+ FILL_CLOCK_MUX_INIT_INFO(EMMC, periph),
584
+ },
585
+ [CPRMAN_CLOCK_EMMC2] = {
586
+ .name = "emmc2",
587
+ .int_bits = 4,
588
+ .frac_bits = 8,
589
+ FILL_CLOCK_MUX_INIT_INFO(EMMC2, unknown),
590
+ },
591
+};
592
+
593
+#undef FILL_CLOCK_MUX_INIT_INFO
594
+#undef FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO
595
+#undef SRC_MAPPING_INFO_dsi1
596
+#undef SRC_MAPPING_INFO_dsi0
597
+#undef SRC_MAPPING_INFO_periph
598
+#undef SRC_MAPPING_INFO_core
599
+#undef SRC_MAPPING_INFO_xosc
600
+#undef SRC_MAPPING_INFO_unknown
601
+
602
+static inline void set_clock_mux_init_info(BCM2835CprmanState *s,
603
+ CprmanClockMuxState *mux,
604
+ CprmanClockMux id)
605
+{
606
+ mux->id = id;
607
+ mux->reg_ctl = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset];
608
+ mux->reg_div = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset + 1];
609
+ mux->int_bits = CLOCK_MUX_INIT_INFO[id].int_bits;
610
+ mux->frac_bits = CLOCK_MUX_INIT_INFO[id].frac_bits;
611
+}
612
+
613
#endif
614
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
615
index XXXXXXX..XXXXXXX 100644
616
--- a/hw/misc/bcm2835_cprman.c
617
+++ b/hw/misc/bcm2835_cprman.c
618
@@ -XXX,XX +XXX,XX @@
619
*
620
* The page at https://elinux.org/The_Undocumented_Pi gives the actual clock
621
* tree configuration.
622
+ *
623
+ * The CPRMAN exposes clock outputs with the name of the clock mux suffixed
624
+ * with "-out" (e.g. "uart-out", "h264-out", ...).
625
*/
626
627
#include "qemu/osdep.h"
628
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_channel_info = {
37
};
629
};
38
630
39
-qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s)
631
40
-{
632
+/* clock mux */
41
- return s->gpio_in;
633
+
42
-}
634
+static void clock_mux_update(CprmanClockMuxState *mux)
43
-
635
+{
44
static void tc6393xb_gpio_set(void *opaque, int line, int level)
636
+ clock_update(mux->out, 0);
637
+}
638
+
639
+static void clock_mux_src_update(void *opaque)
640
+{
641
+ CprmanClockMuxState **backref = opaque;
642
+ CprmanClockMuxState *s = *backref;
643
+
644
+ clock_mux_update(s);
645
+}
646
+
647
+static void clock_mux_init(Object *obj)
648
+{
649
+ CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj);
650
+ size_t i;
651
+
652
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) {
653
+ char *name = g_strdup_printf("srcs[%zu]", i);
654
+ s->backref[i] = s;
655
+ s->srcs[i] = qdev_init_clock_in(DEVICE(s), name,
656
+ clock_mux_src_update,
657
+ &s->backref[i]);
658
+ g_free(name);
659
+ }
660
+
661
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
662
+}
663
+
664
+static const VMStateDescription clock_mux_vmstate = {
665
+ .name = TYPE_CPRMAN_CLOCK_MUX,
666
+ .version_id = 1,
667
+ .minimum_version_id = 1,
668
+ .fields = (VMStateField[]) {
669
+ VMSTATE_ARRAY_CLOCK(srcs, CprmanClockMuxState,
670
+ CPRMAN_NUM_CLOCK_MUX_SRC),
671
+ VMSTATE_END_OF_LIST()
672
+ }
673
+};
674
+
675
+static void clock_mux_class_init(ObjectClass *klass, void *data)
676
+{
677
+ DeviceClass *dc = DEVICE_CLASS(klass);
678
+
679
+ dc->vmsd = &clock_mux_vmstate;
680
+}
681
+
682
+static const TypeInfo cprman_clock_mux_info = {
683
+ .name = TYPE_CPRMAN_CLOCK_MUX,
684
+ .parent = TYPE_DEVICE,
685
+ .instance_size = sizeof(CprmanClockMuxState),
686
+ .class_init = clock_mux_class_init,
687
+ .instance_init = clock_mux_init,
688
+};
689
+
690
+
691
/* CPRMAN "top level" model */
692
693
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
694
@@ -XXX,XX +XXX,XX @@ static inline void update_channel_from_a2w(BCM2835CprmanState *s, size_t idx)
695
}
696
}
697
698
+static inline void update_mux_from_cm(BCM2835CprmanState *s, size_t idx)
699
+{
700
+ size_t i;
701
+
702
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
703
+ if ((CLOCK_MUX_INIT_INFO[i].cm_offset == idx) ||
704
+ (CLOCK_MUX_INIT_INFO[i].cm_offset + 4 == idx)) {
705
+ /* matches CM_CTL or CM_DIV mux register */
706
+ clock_mux_update(&s->clock_muxes[i]);
707
+ return;
708
+ }
709
+ }
710
+}
711
+
712
#define CASE_PLL_A2W_REGS(pll_) \
713
case R_A2W_ ## pll_ ## _CTRL: \
714
case R_A2W_ ## pll_ ## _ANA0: \
715
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
716
case R_A2W_PLLB_ARM:
717
update_channel_from_a2w(s, idx);
718
break;
719
+
720
+ case R_CM_GNRICCTL ... R_CM_SMIDIV:
721
+ case R_CM_TCNTCNT ... R_CM_VECDIV:
722
+ case R_CM_PULSECTL ... R_CM_PULSEDIV:
723
+ case R_CM_SDCCTL ... R_CM_ARMCTL:
724
+ case R_CM_AVEOCTL ... R_CM_EMMCDIV:
725
+ case R_CM_EMMC2CTL ... R_CM_EMMC2DIV:
726
+ update_mux_from_cm(s, idx);
727
+ break;
728
}
729
}
730
731
@@ -XXX,XX +XXX,XX @@ static void cprman_reset(DeviceState *dev)
732
device_cold_reset(DEVICE(&s->channels[i]));
733
}
734
735
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
736
+ device_cold_reset(DEVICE(&s->clock_muxes[i]));
737
+ }
738
+
739
clock_update_hz(s->xosc, s->xosc_freq);
740
}
741
742
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
743
set_pll_channel_init_info(s, &s->channels[i], i);
744
}
745
746
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
747
+ char *alias;
748
+
749
+ object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name,
750
+ &s->clock_muxes[i],
751
+ TYPE_CPRMAN_CLOCK_MUX);
752
+ set_clock_mux_init_info(s, &s->clock_muxes[i], i);
753
+
754
+ /* Expose muxes output as CPRMAN outputs */
755
+ alias = g_strdup_printf("%s-out", CLOCK_MUX_INIT_INFO[i].name);
756
+ qdev_alias_clock(DEVICE(&s->clock_muxes[i]), "out", DEVICE(obj), alias);
757
+ g_free(alias);
758
+ }
759
+
760
s->xosc = clock_new(obj, "xosc");
761
+ s->gnd = clock_new(obj, "gnd");
762
+
763
+ clock_set(s->gnd, 0);
764
765
memory_region_init_io(&s->iomem, obj, &cprman_ops,
766
s, "bcm2835-cprman", 0x2000);
767
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
768
}
769
770
+static void connect_mux_sources(BCM2835CprmanState *s,
771
+ CprmanClockMuxState *mux,
772
+ const CprmanPllChannel *clk_mapping)
773
+{
774
+ size_t i;
775
+ Clock *td0 = s->clock_muxes[CPRMAN_CLOCK_TD0].out;
776
+ Clock *td1 = s->clock_muxes[CPRMAN_CLOCK_TD1].out;
777
+
778
+ /* For sources from 0 to 3. Source 4 to 9 are mux specific */
779
+ Clock * const CLK_SRC_MAPPING[] = {
780
+ [CPRMAN_CLOCK_SRC_GND] = s->gnd,
781
+ [CPRMAN_CLOCK_SRC_XOSC] = s->xosc,
782
+ [CPRMAN_CLOCK_SRC_TD0] = td0,
783
+ [CPRMAN_CLOCK_SRC_TD1] = td1,
784
+ };
785
+
786
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) {
787
+ CprmanPllChannel mapping = clk_mapping[i];
788
+ Clock *src;
789
+
790
+ if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) {
791
+ src = s->gnd;
792
+ } else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) {
793
+ src = s->gnd; /* TODO */
794
+ } else if (i < CPRMAN_CLOCK_SRC_PLLA) {
795
+ src = CLK_SRC_MAPPING[i];
796
+ } else {
797
+ src = s->channels[mapping].out;
798
+ }
799
+
800
+ clock_set_source(mux->srcs[i], src);
801
+ }
802
+}
803
+
804
static void cprman_realize(DeviceState *dev, Error **errp)
45
{
805
{
46
// TC6393xbState *s = opaque;
806
BCM2835CprmanState *s = CPRMAN(dev);
47
@@ -XXX,XX +XXX,XX @@ static void tc6393xb_gpio_set(void *opaque, int line, int level)
807
@@ -XXX,XX +XXX,XX @@ static void cprman_realize(DeviceState *dev, Error **errp)
48
// FIXME: how does the chip reflect the GPIO input level change?
808
return;
809
}
810
}
811
+
812
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
813
+ CprmanClockMuxState *clock_mux = &s->clock_muxes[i];
814
+
815
+ connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mapping);
816
+
817
+ if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) {
818
+ return;
819
+ }
820
+ }
49
}
821
}
50
822
51
-void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
823
static const VMStateDescription cprman_vmstate = {
52
- qemu_irq handler)
824
@@ -XXX,XX +XXX,XX @@ static void cprman_register_types(void)
53
-{
825
type_register_static(&cprman_info);
54
- if (line >= TC6393XB_GPIOS) {
826
type_register_static(&cprman_pll_info);
55
- fprintf(stderr, "TC6393xb: no GPIO pin %d\n", line);
827
type_register_static(&cprman_pll_channel_info);
56
- return;
828
+ type_register_static(&cprman_clock_mux_info);
57
- }
829
}
58
-
830
59
- s->handler[line] = handler;
831
type_init(cprman_register_types);
60
-}
61
-
62
static void tc6393xb_gpio_handler_update(TC6393xbState *s)
63
{
64
uint32_t level, diff;
65
--
832
--
66
2.20.1
833
2.20.1
67
834
68
835
diff view generated by jsdifflib
1
The M-profile architecture floating point system supports
1
From: Luc Michel <luc@lmichel.fr>
2
lazy FP state preservation, where FP registers are not
3
pushed to the stack when an exception occurs but are instead
4
only saved if and when the first FP instruction in the exception
5
handler is executed. Implement this in QEMU, corresponding
6
to the check of LSPACT in the pseudocode ExecuteFPCheck().
7
2
3
A clock mux can be configured to select one of its 10 sources through
4
the CM_CTL register. It also embeds yet another clock divider, composed
5
of an integer part and a fractional part. The number of bits of each
6
part is mux dependent.
7
8
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Signed-off-by: Luc Michel <luc@lmichel.fr>
10
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Tested-by: Guenter Roeck <linux@roeck-us.net>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20190416125744.27770-24-peter.maydell@linaro.org
11
---
13
---
12
target/arm/cpu.h | 3 ++
14
hw/misc/bcm2835_cprman.c | 53 +++++++++++++++++++++++++++++++++++++++-
13
target/arm/helper.h | 2 +
15
1 file changed, 52 insertions(+), 1 deletion(-)
14
target/arm/translate.h | 1 +
15
target/arm/helper.c | 112 +++++++++++++++++++++++++++++++++++++++++
16
target/arm/translate.c | 22 ++++++++
17
5 files changed, 140 insertions(+)
18
16
19
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
17
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
20
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
21
--- a/target/arm/cpu.h
19
--- a/hw/misc/bcm2835_cprman.c
22
+++ b/target/arm/cpu.h
20
+++ b/hw/misc/bcm2835_cprman.c
23
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_channel_info = {
24
#define EXCP_NOCP 17 /* v7M NOCP UsageFault */
22
25
#define EXCP_INVSTATE 18 /* v7M INVSTATE UsageFault */
23
/* clock mux */
26
#define EXCP_STKOF 19 /* v8M STKOF UsageFault */
24
27
+#define EXCP_LAZYFP 20 /* v7M fault during lazy FP stacking */
25
+static bool clock_mux_is_enabled(CprmanClockMuxState *mux)
28
/* NB: add new EXCP_ defines to the array in arm_log_exception() too */
29
30
#define ARMV7M_EXCP_RESET 1
31
@@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A32, NS, 6, 1)
32
FIELD(TBFLAG_A32, VFPEN, 7, 1)
33
FIELD(TBFLAG_A32, CONDEXEC, 8, 8)
34
FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
35
+/* For M profile only, set if FPCCR.LSPACT is set */
36
+FIELD(TBFLAG_A32, LSPACT, 18, 1)
37
/* For M profile only, set if we must create a new FP context */
38
FIELD(TBFLAG_A32, NEW_FP_CTXT_NEEDED, 19, 1)
39
/* For M profile only, set if FPCCR.S does not match current security state */
40
diff --git a/target/arm/helper.h b/target/arm/helper.h
41
index XXXXXXX..XXXXXXX 100644
42
--- a/target/arm/helper.h
43
+++ b/target/arm/helper.h
44
@@ -XXX,XX +XXX,XX @@ DEF_HELPER_2(v7m_blxns, void, env, i32)
45
46
DEF_HELPER_3(v7m_tt, i32, env, i32, i32)
47
48
+DEF_HELPER_1(v7m_preserve_fp_state, void, env)
49
+
50
DEF_HELPER_2(v8m_stackcheck, void, env, i32)
51
52
DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32)
53
diff --git a/target/arm/translate.h b/target/arm/translate.h
54
index XXXXXXX..XXXXXXX 100644
55
--- a/target/arm/translate.h
56
+++ b/target/arm/translate.h
57
@@ -XXX,XX +XXX,XX @@ typedef struct DisasContext {
58
bool v8m_stackcheck; /* true if we need to perform v8M stack limit checks */
59
bool v8m_fpccr_s_wrong; /* true if v8M FPCCR.S != v8m_secure */
60
bool v7m_new_fp_ctxt_needed; /* ASPEN set but no active FP context */
61
+ bool v7m_lspact; /* FPCCR.LSPACT set */
62
/* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI
63
* so that top level loop can generate correct syndrome information.
64
*/
65
diff --git a/target/arm/helper.c b/target/arm/helper.c
66
index XXXXXXX..XXXXXXX 100644
67
--- a/target/arm/helper.c
68
+++ b/target/arm/helper.c
69
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
70
g_assert_not_reached();
71
}
72
73
+void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
74
+{
26
+{
75
+ /* translate.c should never generate calls here in user-only mode */
27
+ return FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, ENABLE);
76
+ g_assert_not_reached();
77
+}
28
+}
78
+
29
+
79
uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
30
static void clock_mux_update(CprmanClockMuxState *mux)
80
{
31
{
81
/* The TT instructions can be used by unprivileged code, but in
32
- clock_update(mux->out, 0);
82
@@ -XXX,XX +XXX,XX @@ pend_fault:
33
+ uint64_t freq;
83
return false;
34
+ uint32_t div, src = FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, SRC);
84
}
35
+ bool enabled = clock_mux_is_enabled(mux);
85
86
+void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
87
+{
88
+ /*
89
+ * Preserve FP state (because LSPACT was set and we are about
90
+ * to execute an FP instruction). This corresponds to the
91
+ * PreserveFPState() pseudocode.
92
+ * We may throw an exception if the stacking fails.
93
+ */
94
+ ARMCPU *cpu = arm_env_get_cpu(env);
95
+ bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
96
+ bool negpri = !(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_HFRDY_MASK);
97
+ bool is_priv = !(env->v7m.fpccr[is_secure] & R_V7M_FPCCR_USER_MASK);
98
+ bool splimviol = env->v7m.fpccr[is_secure] & R_V7M_FPCCR_SPLIMVIOL_MASK;
99
+ uint32_t fpcar = env->v7m.fpcar[is_secure];
100
+ bool stacked_ok = true;
101
+ bool ts = is_secure && (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
102
+ bool take_exception;
103
+
36
+
104
+ /* Take the iothread lock as we are going to touch the NVIC */
37
+ *mux->reg_ctl = FIELD_DP32(*mux->reg_ctl, CM_CLOCKx_CTL, BUSY, enabled);
105
+ qemu_mutex_lock_iothread();
106
+
38
+
107
+ /* Check the background context had access to the FPU */
39
+ if (!enabled) {
108
+ if (!v7m_cpacr_pass(env, is_secure, is_priv)) {
40
+ clock_update(mux->out, 0);
109
+ armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, is_secure);
41
+ return;
110
+ env->v7m.cfsr[is_secure] |= R_V7M_CFSR_NOCP_MASK;
111
+ stacked_ok = false;
112
+ } else if (!is_secure && !extract32(env->v7m.nsacr, 10, 1)) {
113
+ armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S);
114
+ env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_NOCP_MASK;
115
+ stacked_ok = false;
116
+ }
42
+ }
117
+
43
+
118
+ if (!splimviol && stacked_ok) {
44
+ freq = clock_get_hz(mux->srcs[src]);
119
+ /* We only stack if the stack limit wasn't violated */
120
+ int i;
121
+ ARMMMUIdx mmu_idx;
122
+
45
+
123
+ mmu_idx = arm_v7m_mmu_idx_all(env, is_secure, is_priv, negpri);
46
+ if (mux->int_bits == 0 && mux->frac_bits == 0) {
124
+ for (i = 0; i < (ts ? 32 : 16); i += 2) {
47
+ clock_update_hz(mux->out, freq);
125
+ uint64_t dn = *aa32_vfp_dreg(env, i / 2);
48
+ return;
126
+ uint32_t faddr = fpcar + 4 * i;
127
+ uint32_t slo = extract64(dn, 0, 32);
128
+ uint32_t shi = extract64(dn, 32, 32);
129
+
130
+ if (i >= 16) {
131
+ faddr += 8; /* skip the slot for the FPSCR */
132
+ }
133
+ stacked_ok = stacked_ok &&
134
+ v7m_stack_write(cpu, faddr, slo, mmu_idx, STACK_LAZYFP) &&
135
+ v7m_stack_write(cpu, faddr + 4, shi, mmu_idx, STACK_LAZYFP);
136
+ }
137
+
138
+ stacked_ok = stacked_ok &&
139
+ v7m_stack_write(cpu, fpcar + 0x40,
140
+ vfp_get_fpscr(env), mmu_idx, STACK_LAZYFP);
141
+ }
49
+ }
142
+
50
+
143
+ /*
51
+ /*
144
+ * We definitely pended an exception, but it's possible that it
52
+ * The divider has an integer and a fractional part. The size of each part
145
+ * might not be able to be taken now. If its priority permits us
53
+ * varies with the muxes (int_bits and frac_bits). Both parts are
146
+ * to take it now, then we must not update the LSPACT or FP regs,
54
+ * concatenated, with the integer part always starting at bit 12.
147
+ * but instead jump out to take the exception immediately.
55
+ *
148
+ * If it's just pending and won't be taken until the current
56
+ * 31 12 11 0
149
+ * handler exits, then we do update LSPACT and the FP regs.
57
+ * ------------------------------
58
+ * CM_DIV | | int | frac | |
59
+ * ------------------------------
60
+ * <-----> <------>
61
+ * int_bits frac_bits
150
+ */
62
+ */
151
+ take_exception = !stacked_ok &&
63
+ div = extract32(*mux->reg_div,
152
+ armv7m_nvic_can_take_pending_exception(env->nvic);
64
+ R_CM_CLOCKx_DIV_FRAC_LENGTH - mux->frac_bits,
65
+ mux->int_bits + mux->frac_bits);
153
+
66
+
154
+ qemu_mutex_unlock_iothread();
67
+ if (!div) {
155
+
68
+ clock_update(mux->out, 0);
156
+ if (take_exception) {
69
+ return;
157
+ raise_exception_ra(env, EXCP_LAZYFP, 0, 1, GETPC());
158
+ }
70
+ }
159
+
71
+
160
+ env->v7m.fpccr[is_secure] &= ~R_V7M_FPCCR_LSPACT_MASK;
72
+ freq = muldiv64(freq, 1 << mux->frac_bits, div);
161
+
73
+
162
+ if (ts) {
74
+ clock_update_hz(mux->out, freq);
163
+ /* Clear s0 to s31 and the FPSCR */
75
}
164
+ int i;
76
77
static void clock_mux_src_update(void *opaque)
78
{
79
CprmanClockMuxState **backref = opaque;
80
CprmanClockMuxState *s = *backref;
81
+ CprmanClockMuxSource src = backref - s->backref;
165
+
82
+
166
+ for (i = 0; i < 32; i += 2) {
83
+ if (FIELD_EX32(*s->reg_ctl, CM_CLOCKx_CTL, SRC) != src) {
167
+ *aa32_vfp_dreg(env, i / 2) = 0;
84
+ return;
168
+ }
169
+ vfp_set_fpscr(env, 0);
170
+ }
85
+ }
171
+ /*
86
172
+ * Otherwise s0 to s15 and FPSCR are UNKNOWN; we choose to leave them
87
clock_mux_update(s);
173
+ * unchanged.
174
+ */
175
+}
176
+
177
/* Write to v7M CONTROL.SPSEL bit for the specified security bank.
178
* This may change the current stack pointer between Main and Process
179
* stack pointers if it is done for the CONTROL register for the current
180
@@ -XXX,XX +XXX,XX @@ static void arm_log_exception(int idx)
181
[EXCP_NOCP] = "v7M NOCP UsageFault",
182
[EXCP_INVSTATE] = "v7M INVSTATE UsageFault",
183
[EXCP_STKOF] = "v8M STKOF UsageFault",
184
+ [EXCP_LAZYFP] = "v7M exception during lazy FP stacking",
185
};
186
187
if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
188
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
189
return;
190
}
191
break;
192
+ case EXCP_LAZYFP:
193
+ /*
194
+ * We already pended the specific exception in the NVIC in the
195
+ * v7m_preserve_fp_state() helper function.
196
+ */
197
+ break;
198
default:
199
cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
200
return; /* Never happens. Keep compiler happy. */
201
@@ -XXX,XX +XXX,XX @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
202
flags = FIELD_DP32(flags, TBFLAG_A32, NEW_FP_CTXT_NEEDED, 1);
203
}
204
205
+ if (arm_feature(env, ARM_FEATURE_M)) {
206
+ bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
207
+
208
+ if (env->v7m.fpccr[is_secure] & R_V7M_FPCCR_LSPACT_MASK) {
209
+ flags = FIELD_DP32(flags, TBFLAG_A32, LSPACT, 1);
210
+ }
211
+ }
212
+
213
*pflags = flags;
214
*cs_base = 0;
215
}
88
}
216
diff --git a/target/arm/translate.c b/target/arm/translate.c
217
index XXXXXXX..XXXXXXX 100644
218
--- a/target/arm/translate.c
219
+++ b/target/arm/translate.c
220
@@ -XXX,XX +XXX,XX @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
221
if (arm_dc_feature(s, ARM_FEATURE_M)) {
222
/* Handle M-profile lazy FP state mechanics */
223
224
+ /* Trigger lazy-state preservation if necessary */
225
+ if (s->v7m_lspact) {
226
+ /*
227
+ * Lazy state saving affects external memory and also the NVIC,
228
+ * so we must mark it as an IO operation for icount.
229
+ */
230
+ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
231
+ gen_io_start();
232
+ }
233
+ gen_helper_v7m_preserve_fp_state(cpu_env);
234
+ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
235
+ gen_io_end();
236
+ }
237
+ /*
238
+ * If the preserve_fp_state helper doesn't throw an exception
239
+ * then it will clear LSPACT; we don't need to repeat this for
240
+ * any further FP insns in this TB.
241
+ */
242
+ s->v7m_lspact = false;
243
+ }
244
+
245
/* Update ownership of FP context: set FPCCR.S to match current state */
246
if (s->v8m_fpccr_s_wrong) {
247
TCGv_i32 tmp;
248
@@ -XXX,XX +XXX,XX @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
249
dc->v8m_fpccr_s_wrong = FIELD_EX32(tb_flags, TBFLAG_A32, FPCCR_S_WRONG);
250
dc->v7m_new_fp_ctxt_needed =
251
FIELD_EX32(tb_flags, TBFLAG_A32, NEW_FP_CTXT_NEEDED);
252
+ dc->v7m_lspact = FIELD_EX32(tb_flags, TBFLAG_A32, LSPACT);
253
dc->cp_regs = cpu->cp_regs;
254
dc->features = env->features;
255
256
--
89
--
257
2.20.1
90
2.20.1
258
91
259
92
diff view generated by jsdifflib
1
The M-profile floating point support has three associated config
1
From: Luc Michel <luc@lmichel.fr>
2
registers: FPCAR, FPCCR and FPDSCR. It also makes the registers
2
3
CPACR and NSACR have behaviour other than reads-as-zero.
3
This simple mux sits between the PLL channels and the DSI0E and DSI0P
4
Add support for all of these as simple reads-as-written registers.
4
clock muxes. This mux selects between PLLA-DSI0 and PLLD-DSI0 channel
5
We will hook up actual functionality later.
5
and outputs the selected signal to source number 4 of DSI0E/P clock
6
6
muxes. It is controlled by the cm_dsi0hsck register.
7
The main complexity here is handling the FPCCR register, which
7
8
has a mix of banked and unbanked bits.
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
9
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Note that we don't share storage with the A-profile
10
Signed-off-by: Luc Michel <luc@lmichel.fr>
11
cpu->cp15.nsacr and cpu->cp15.cpacr_el1, though the behaviour
11
Tested-by: Guenter Roeck <linux@roeck-us.net>
12
is quite similar, for two reasons:
13
* the M profile CPACR is banked between security states
14
* it preserves the invariant that M profile uses no state
15
inside the cp15 substruct
16
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
19
Message-id: 20190416125744.27770-4-peter.maydell@linaro.org
20
---
13
---
21
target/arm/cpu.h | 34 ++++++++++++
14
include/hw/misc/bcm2835_cprman.h | 15 +++++
22
hw/intc/armv7m_nvic.c | 125 ++++++++++++++++++++++++++++++++++++++++++
15
include/hw/misc/bcm2835_cprman_internals.h | 6 ++
23
target/arm/cpu.c | 5 ++
16
hw/misc/bcm2835_cprman.c | 74 +++++++++++++++++++++-
24
target/arm/machine.c | 16 ++++++
17
3 files changed, 94 insertions(+), 1 deletion(-)
25
4 files changed, 180 insertions(+)
18
26
19
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
27
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
28
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
29
--- a/target/arm/cpu.h
21
--- a/include/hw/misc/bcm2835_cprman.h
30
+++ b/target/arm/cpu.h
22
+++ b/include/hw/misc/bcm2835_cprman.h
31
@@ -XXX,XX +XXX,XX @@ typedef struct CPUARMState {
23
@@ -XXX,XX +XXX,XX @@ typedef struct CprmanClockMuxState {
32
uint32_t scr[M_REG_NUM_BANKS];
24
struct CprmanClockMuxState *backref[CPRMAN_NUM_CLOCK_MUX_SRC];
33
uint32_t msplim[M_REG_NUM_BANKS];
25
} CprmanClockMuxState;
34
uint32_t psplim[M_REG_NUM_BANKS];
26
35
+ uint32_t fpcar[M_REG_NUM_BANKS];
27
+typedef struct CprmanDsi0HsckMuxState {
36
+ uint32_t fpccr[M_REG_NUM_BANKS];
28
+ /*< private >*/
37
+ uint32_t fpdscr[M_REG_NUM_BANKS];
29
+ DeviceState parent_obj;
38
+ uint32_t cpacr[M_REG_NUM_BANKS];
30
+
39
+ uint32_t nsacr;
31
+ /*< public >*/
40
} v7m;
32
+ CprmanClockMux id;
41
33
+
42
/* Information associated with an exception about to be taken:
34
+ uint32_t *reg_cm;
43
@@ -XXX,XX +XXX,XX @@ FIELD(V7M_CSSELR, LEVEL, 1, 3)
35
+
44
*/
36
+ Clock *plla_in;
45
FIELD(V7M_CSSELR, INDEX, 0, 4)
37
+ Clock *plld_in;
46
38
+ Clock *out;
47
+/* v7M FPCCR bits */
39
+} CprmanDsi0HsckMuxState;
48
+FIELD(V7M_FPCCR, LSPACT, 0, 1)
40
+
49
+FIELD(V7M_FPCCR, USER, 1, 1)
41
struct BCM2835CprmanState {
50
+FIELD(V7M_FPCCR, S, 2, 1)
42
/*< private >*/
51
+FIELD(V7M_FPCCR, THREAD, 3, 1)
43
SysBusDevice parent_obj;
52
+FIELD(V7M_FPCCR, HFRDY, 4, 1)
44
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
53
+FIELD(V7M_FPCCR, MMRDY, 5, 1)
45
CprmanPllState plls[CPRMAN_NUM_PLL];
54
+FIELD(V7M_FPCCR, BFRDY, 6, 1)
46
CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
55
+FIELD(V7M_FPCCR, SFRDY, 7, 1)
47
CprmanClockMuxState clock_muxes[CPRMAN_NUM_CLOCK_MUX];
56
+FIELD(V7M_FPCCR, MONRDY, 8, 1)
48
+ CprmanDsi0HsckMuxState dsi0hsck_mux;
57
+FIELD(V7M_FPCCR, SPLIMVIOL, 9, 1)
49
58
+FIELD(V7M_FPCCR, UFRDY, 10, 1)
50
uint32_t regs[CPRMAN_NUM_REGS];
59
+FIELD(V7M_FPCCR, RES0, 11, 15)
51
uint32_t xosc_freq;
60
+FIELD(V7M_FPCCR, TS, 26, 1)
52
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
61
+FIELD(V7M_FPCCR, CLRONRETS, 27, 1)
53
index XXXXXXX..XXXXXXX 100644
62
+FIELD(V7M_FPCCR, CLRONRET, 28, 1)
54
--- a/include/hw/misc/bcm2835_cprman_internals.h
63
+FIELD(V7M_FPCCR, LSPENS, 29, 1)
55
+++ b/include/hw/misc/bcm2835_cprman_internals.h
64
+FIELD(V7M_FPCCR, LSPEN, 30, 1)
56
@@ -XXX,XX +XXX,XX @@
65
+FIELD(V7M_FPCCR, ASPEN, 31, 1)
57
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
66
+/* These bits are banked. Others are non-banked and live in the M_REG_S bank */
58
#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
67
+#define R_V7M_FPCCR_BANKED_MASK \
59
#define TYPE_CPRMAN_CLOCK_MUX "bcm2835-cprman-clock-mux"
68
+ (R_V7M_FPCCR_LSPACT_MASK | \
60
+#define TYPE_CPRMAN_DSI0HSCK_MUX "bcm2835-cprman-dsi0hsck-mux"
69
+ R_V7M_FPCCR_USER_MASK | \
61
70
+ R_V7M_FPCCR_THREAD_MASK | \
62
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
71
+ R_V7M_FPCCR_MMRDY_MASK | \
63
TYPE_CPRMAN_PLL)
72
+ R_V7M_FPCCR_SPLIMVIOL_MASK | \
64
@@ -XXX,XX +XXX,XX @@ DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL,
73
+ R_V7M_FPCCR_UFRDY_MASK | \
65
TYPE_CPRMAN_PLL_CHANNEL)
74
+ R_V7M_FPCCR_ASPEN_MASK)
66
DECLARE_INSTANCE_CHECKER(CprmanClockMuxState, CPRMAN_CLOCK_MUX,
67
TYPE_CPRMAN_CLOCK_MUX)
68
+DECLARE_INSTANCE_CHECKER(CprmanDsi0HsckMuxState, CPRMAN_DSI0HSCK_MUX,
69
+ TYPE_CPRMAN_DSI0HSCK_MUX)
70
71
/* Register map */
72
73
@@ -XXX,XX +XXX,XX @@ REG32(CM_LOCK, 0x114)
74
FIELD(CM_LOCK, FLOCKB, 9, 1)
75
FIELD(CM_LOCK, FLOCKA, 8, 1)
76
77
+REG32(CM_DSI0HSCK, 0x120)
78
+ FIELD(CM_DSI0HSCK, SELPLLD, 0, 1)
75
+
79
+
76
/*
80
/*
77
* System register ID fields.
81
* This field is common to all registers. Each register write value must match
78
*/
82
* the CPRMAN_PASSWORD magic value in its 8 MSB.
79
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
83
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
80
index XXXXXXX..XXXXXXX 100644
84
index XXXXXXX..XXXXXXX 100644
81
--- a/hw/intc/armv7m_nvic.c
85
--- a/hw/misc/bcm2835_cprman.c
82
+++ b/hw/intc/armv7m_nvic.c
86
+++ b/hw/misc/bcm2835_cprman.c
83
@@ -XXX,XX +XXX,XX @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
87
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_clock_mux_info = {
84
}
85
case 0xd84: /* CSSELR */
86
return cpu->env.v7m.csselr[attrs.secure];
87
+ case 0xd88: /* CPACR */
88
+ if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
89
+ return 0;
90
+ }
91
+ return cpu->env.v7m.cpacr[attrs.secure];
92
+ case 0xd8c: /* NSACR */
93
+ if (!attrs.secure || !arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
94
+ return 0;
95
+ }
96
+ return cpu->env.v7m.nsacr;
97
/* TODO: Implement debug registers. */
98
case 0xd90: /* MPU_TYPE */
99
/* Unified MPU; if the MPU is not present this value is zero */
100
@@ -XXX,XX +XXX,XX @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
101
return 0;
102
}
103
return cpu->env.v7m.sfar;
104
+ case 0xf34: /* FPCCR */
105
+ if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
106
+ return 0;
107
+ }
108
+ if (attrs.secure) {
109
+ return cpu->env.v7m.fpccr[M_REG_S];
110
+ } else {
111
+ /*
112
+ * NS can read LSPEN, CLRONRET and MONRDY. It can read
113
+ * BFRDY and HFRDY if AIRCR.BFHFNMINS != 0;
114
+ * other non-banked bits RAZ.
115
+ * TODO: MONRDY should RAZ/WI if DEMCR.SDME is set.
116
+ */
117
+ uint32_t value = cpu->env.v7m.fpccr[M_REG_S];
118
+ uint32_t mask = R_V7M_FPCCR_LSPEN_MASK |
119
+ R_V7M_FPCCR_CLRONRET_MASK |
120
+ R_V7M_FPCCR_MONRDY_MASK;
121
+
122
+ if (s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) {
123
+ mask |= R_V7M_FPCCR_BFRDY_MASK | R_V7M_FPCCR_HFRDY_MASK;
124
+ }
125
+
126
+ value &= mask;
127
+
128
+ value |= cpu->env.v7m.fpccr[M_REG_NS];
129
+ return value;
130
+ }
131
+ case 0xf38: /* FPCAR */
132
+ if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
133
+ return 0;
134
+ }
135
+ return cpu->env.v7m.fpcar[attrs.secure];
136
+ case 0xf3c: /* FPDSCR */
137
+ if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
138
+ return 0;
139
+ }
140
+ return cpu->env.v7m.fpdscr[attrs.secure];
141
case 0xf40: /* MVFR0 */
142
return cpu->isar.mvfr0;
143
case 0xf44: /* MVFR1 */
144
@@ -XXX,XX +XXX,XX @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
145
cpu->env.v7m.csselr[attrs.secure] = value & R_V7M_CSSELR_INDEX_MASK;
146
}
147
break;
148
+ case 0xd88: /* CPACR */
149
+ if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
150
+ /* We implement only the Floating Point extension's CP10/CP11 */
151
+ cpu->env.v7m.cpacr[attrs.secure] = value & (0xf << 20);
152
+ }
153
+ break;
154
+ case 0xd8c: /* NSACR */
155
+ if (attrs.secure && arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
156
+ /* We implement only the Floating Point extension's CP10/CP11 */
157
+ cpu->env.v7m.nsacr = value & (3 << 10);
158
+ }
159
+ break;
160
case 0xd90: /* MPU_TYPE */
161
return; /* RO */
162
case 0xd94: /* MPU_CTRL */
163
@@ -XXX,XX +XXX,XX @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
164
}
165
break;
166
}
167
+ case 0xf34: /* FPCCR */
168
+ if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
169
+ /* Not all bits here are banked. */
170
+ uint32_t fpccr_s;
171
+
172
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
173
+ /* Don't allow setting of bits not present in v7M */
174
+ value &= (R_V7M_FPCCR_LSPACT_MASK |
175
+ R_V7M_FPCCR_USER_MASK |
176
+ R_V7M_FPCCR_THREAD_MASK |
177
+ R_V7M_FPCCR_HFRDY_MASK |
178
+ R_V7M_FPCCR_MMRDY_MASK |
179
+ R_V7M_FPCCR_BFRDY_MASK |
180
+ R_V7M_FPCCR_MONRDY_MASK |
181
+ R_V7M_FPCCR_LSPEN_MASK |
182
+ R_V7M_FPCCR_ASPEN_MASK);
183
+ }
184
+ value &= ~R_V7M_FPCCR_RES0_MASK;
185
+
186
+ if (!attrs.secure) {
187
+ /* Some non-banked bits are configurably writable by NS */
188
+ fpccr_s = cpu->env.v7m.fpccr[M_REG_S];
189
+ if (!(fpccr_s & R_V7M_FPCCR_LSPENS_MASK)) {
190
+ uint32_t lspen = FIELD_EX32(value, V7M_FPCCR, LSPEN);
191
+ fpccr_s = FIELD_DP32(fpccr_s, V7M_FPCCR, LSPEN, lspen);
192
+ }
193
+ if (!(fpccr_s & R_V7M_FPCCR_CLRONRETS_MASK)) {
194
+ uint32_t cor = FIELD_EX32(value, V7M_FPCCR, CLRONRET);
195
+ fpccr_s = FIELD_DP32(fpccr_s, V7M_FPCCR, CLRONRET, cor);
196
+ }
197
+ if ((s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
198
+ uint32_t hfrdy = FIELD_EX32(value, V7M_FPCCR, HFRDY);
199
+ uint32_t bfrdy = FIELD_EX32(value, V7M_FPCCR, BFRDY);
200
+ fpccr_s = FIELD_DP32(fpccr_s, V7M_FPCCR, HFRDY, hfrdy);
201
+ fpccr_s = FIELD_DP32(fpccr_s, V7M_FPCCR, BFRDY, bfrdy);
202
+ }
203
+ /* TODO MONRDY should RAZ/WI if DEMCR.SDME is set */
204
+ {
205
+ uint32_t monrdy = FIELD_EX32(value, V7M_FPCCR, MONRDY);
206
+ fpccr_s = FIELD_DP32(fpccr_s, V7M_FPCCR, MONRDY, monrdy);
207
+ }
208
+
209
+ /*
210
+ * All other non-banked bits are RAZ/WI from NS; write
211
+ * just the banked bits to fpccr[M_REG_NS].
212
+ */
213
+ value &= R_V7M_FPCCR_BANKED_MASK;
214
+ cpu->env.v7m.fpccr[M_REG_NS] = value;
215
+ } else {
216
+ fpccr_s = value;
217
+ }
218
+ cpu->env.v7m.fpccr[M_REG_S] = fpccr_s;
219
+ }
220
+ break;
221
+ case 0xf38: /* FPCAR */
222
+ if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
223
+ value &= ~7;
224
+ cpu->env.v7m.fpcar[attrs.secure] = value;
225
+ }
226
+ break;
227
+ case 0xf3c: /* FPDSCR */
228
+ if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
229
+ value &= 0x07c00000;
230
+ cpu->env.v7m.fpdscr[attrs.secure] = value;
231
+ }
232
+ break;
233
case 0xf50: /* ICIALLU */
234
case 0xf58: /* ICIMVAU */
235
case 0xf5c: /* DCIMVAC */
236
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
237
index XXXXXXX..XXXXXXX 100644
238
--- a/target/arm/cpu.c
239
+++ b/target/arm/cpu.c
240
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset(CPUState *s)
241
env->v7m.ccr[M_REG_S] |= R_V7M_CCR_UNALIGN_TRP_MASK;
242
}
243
244
+ if (arm_feature(env, ARM_FEATURE_VFP)) {
245
+ env->v7m.fpccr[M_REG_NS] = R_V7M_FPCCR_ASPEN_MASK;
246
+ env->v7m.fpccr[M_REG_S] = R_V7M_FPCCR_ASPEN_MASK |
247
+ R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK;
248
+ }
249
/* Unlike A/R profile, M profile defines the reset LR value */
250
env->regs[14] = 0xffffffff;
251
252
diff --git a/target/arm/machine.c b/target/arm/machine.c
253
index XXXXXXX..XXXXXXX 100644
254
--- a/target/arm/machine.c
255
+++ b/target/arm/machine.c
256
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_m_v8m = {
257
}
258
};
88
};
259
89
260
+static const VMStateDescription vmstate_m_fp = {
90
261
+ .name = "cpu/m/fp",
91
+/* DSI0HSCK mux */
92
+
93
+static void dsi0hsck_mux_update(CprmanDsi0HsckMuxState *s)
94
+{
95
+ bool src_is_plld = FIELD_EX32(*s->reg_cm, CM_DSI0HSCK, SELPLLD);
96
+ Clock *src = src_is_plld ? s->plld_in : s->plla_in;
97
+
98
+ clock_update(s->out, clock_get(src));
99
+}
100
+
101
+static void dsi0hsck_mux_in_update(void *opaque)
102
+{
103
+ dsi0hsck_mux_update(CPRMAN_DSI0HSCK_MUX(opaque));
104
+}
105
+
106
+static void dsi0hsck_mux_init(Object *obj)
107
+{
108
+ CprmanDsi0HsckMuxState *s = CPRMAN_DSI0HSCK_MUX(obj);
109
+ DeviceState *dev = DEVICE(obj);
110
+
111
+ s->plla_in = qdev_init_clock_in(dev, "plla-in", dsi0hsck_mux_in_update, s);
112
+ s->plld_in = qdev_init_clock_in(dev, "plld-in", dsi0hsck_mux_in_update, s);
113
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
114
+}
115
+
116
+static const VMStateDescription dsi0hsck_mux_vmstate = {
117
+ .name = TYPE_CPRMAN_DSI0HSCK_MUX,
262
+ .version_id = 1,
118
+ .version_id = 1,
263
+ .minimum_version_id = 1,
119
+ .minimum_version_id = 1,
264
+ .needed = vfp_needed,
265
+ .fields = (VMStateField[]) {
120
+ .fields = (VMStateField[]) {
266
+ VMSTATE_UINT32_ARRAY(env.v7m.fpcar, ARMCPU, M_REG_NUM_BANKS),
121
+ VMSTATE_CLOCK(plla_in, CprmanDsi0HsckMuxState),
267
+ VMSTATE_UINT32_ARRAY(env.v7m.fpccr, ARMCPU, M_REG_NUM_BANKS),
122
+ VMSTATE_CLOCK(plld_in, CprmanDsi0HsckMuxState),
268
+ VMSTATE_UINT32_ARRAY(env.v7m.fpdscr, ARMCPU, M_REG_NUM_BANKS),
269
+ VMSTATE_UINT32_ARRAY(env.v7m.cpacr, ARMCPU, M_REG_NUM_BANKS),
270
+ VMSTATE_UINT32(env.v7m.nsacr, ARMCPU),
271
+ VMSTATE_END_OF_LIST()
123
+ VMSTATE_END_OF_LIST()
272
+ }
124
+ }
273
+};
125
+};
274
+
126
+
275
static const VMStateDescription vmstate_m = {
127
+static void dsi0hsck_mux_class_init(ObjectClass *klass, void *data)
276
.name = "cpu/m",
128
+{
277
.version_id = 4,
129
+ DeviceClass *dc = DEVICE_CLASS(klass);
278
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_m = {
130
+
279
&vmstate_m_scr,
131
+ dc->vmsd = &dsi0hsck_mux_vmstate;
280
&vmstate_m_other_sp,
132
+}
281
&vmstate_m_v8m,
133
+
282
+ &vmstate_m_fp,
134
+static const TypeInfo cprman_dsi0hsck_mux_info = {
283
NULL
135
+ .name = TYPE_CPRMAN_DSI0HSCK_MUX,
284
}
136
+ .parent = TYPE_DEVICE,
285
};
137
+ .instance_size = sizeof(CprmanDsi0HsckMuxState),
138
+ .class_init = dsi0hsck_mux_class_init,
139
+ .instance_init = dsi0hsck_mux_init,
140
+};
141
+
142
+
143
/* CPRMAN "top level" model */
144
145
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
146
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
147
case R_CM_EMMC2CTL ... R_CM_EMMC2DIV:
148
update_mux_from_cm(s, idx);
149
break;
150
+
151
+ case R_CM_DSI0HSCK:
152
+ dsi0hsck_mux_update(&s->dsi0hsck_mux);
153
+ break;
154
}
155
}
156
157
@@ -XXX,XX +XXX,XX @@ static void cprman_reset(DeviceState *dev)
158
device_cold_reset(DEVICE(&s->channels[i]));
159
}
160
161
+ device_cold_reset(DEVICE(&s->dsi0hsck_mux));
162
+
163
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
164
device_cold_reset(DEVICE(&s->clock_muxes[i]));
165
}
166
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
167
set_pll_channel_init_info(s, &s->channels[i], i);
168
}
169
170
+ object_initialize_child(obj, "dsi0hsck-mux",
171
+ &s->dsi0hsck_mux, TYPE_CPRMAN_DSI0HSCK_MUX);
172
+ s->dsi0hsck_mux.reg_cm = &s->regs[R_CM_DSI0HSCK];
173
+
174
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
175
char *alias;
176
177
@@ -XXX,XX +XXX,XX @@ static void connect_mux_sources(BCM2835CprmanState *s,
178
if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) {
179
src = s->gnd;
180
} else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) {
181
- src = s->gnd; /* TODO */
182
+ src = s->dsi0hsck_mux.out;
183
} else if (i < CPRMAN_CLOCK_SRC_PLLA) {
184
src = CLK_SRC_MAPPING[i];
185
} else {
186
@@ -XXX,XX +XXX,XX @@ static void cprman_realize(DeviceState *dev, Error **errp)
187
}
188
}
189
190
+ clock_set_source(s->dsi0hsck_mux.plla_in,
191
+ s->channels[CPRMAN_PLLA_CHANNEL_DSI0].out);
192
+ clock_set_source(s->dsi0hsck_mux.plld_in,
193
+ s->channels[CPRMAN_PLLD_CHANNEL_DSI0].out);
194
+
195
+ if (!qdev_realize(DEVICE(&s->dsi0hsck_mux), NULL, errp)) {
196
+ return;
197
+ }
198
+
199
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
200
CprmanClockMuxState *clock_mux = &s->clock_muxes[i];
201
202
@@ -XXX,XX +XXX,XX @@ static void cprman_register_types(void)
203
type_register_static(&cprman_pll_info);
204
type_register_static(&cprman_pll_channel_info);
205
type_register_static(&cprman_clock_mux_info);
206
+ type_register_static(&cprman_dsi0hsck_mux_info);
207
}
208
209
type_init(cprman_register_types);
286
--
210
--
287
2.20.1
211
2.20.1
288
212
289
213
diff view generated by jsdifflib
1
The M-profile FPCCR.ASPEN bit indicates that automatic floating-point
1
From: Luc Michel <luc@lmichel.fr>
2
context preservation is enabled. Before executing any floating-point
2
3
instruction, if FPCCR.ASPEN is set and the CONTROL FPCA/SFPA bits
3
Those reset values have been extracted from a Raspberry Pi 3 model B
4
indicate that there is no active floating point context then we
4
v1.2, using the 2020-08-20 version of raspios. The dump was done using
5
must create a new context (by initializing FPSCR and setting
5
the debugfs interface of the CPRMAN driver in Linux (under
6
FPCA/SFPA to indicate that the context is now active). In the
6
'/sys/kernel/debug/clk'). Each exposed clock tree stage (PLLs, channels
7
pseudocode this is handled by ExecuteFPCheck().
7
and muxes) can be observed by reading the 'regdump' file (e.g.
8
8
'plla/regdump').
9
Implement this with a new TB flag which tracks whether we
9
10
need to create a new FP context.
10
Those values are set by the Raspberry Pi firmware at boot time (Linux
11
11
expects them to be set when it boots up).
12
13
Some stages are not exposed by the Linux driver (e.g. the PLL B). For
14
those, the reset values are unknown and left to 0 which implies a
15
disabled output.
16
17
Once booted in QEMU, the final clock tree is very similar to the one
18
visible on real hardware. The differences come from some unimplemented
19
devices for which the driver simply disable the corresponding clock.
20
21
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
22
Signed-off-by: Luc Michel <luc@lmichel.fr>
23
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Tested-by: Guenter Roeck <linux@roeck-us.net>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
14
Message-id: 20190416125744.27770-20-peter.maydell@linaro.org
15
---
26
---
16
target/arm/cpu.h | 2 ++
27
include/hw/misc/bcm2835_cprman_internals.h | 269 +++++++++++++++++++++
17
target/arm/translate.h | 1 +
28
hw/misc/bcm2835_cprman.c | 31 +++
18
target/arm/helper.c | 13 +++++++++++++
29
2 files changed, 300 insertions(+)
19
target/arm/translate.c | 29 +++++++++++++++++++++++++++++
30
20
4 files changed, 45 insertions(+)
31
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
21
22
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
23
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/cpu.h
33
--- a/include/hw/misc/bcm2835_cprman_internals.h
25
+++ b/target/arm/cpu.h
34
+++ b/include/hw/misc/bcm2835_cprman_internals.h
26
@@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A32, NS, 6, 1)
35
@@ -XXX,XX +XXX,XX @@ static inline void set_clock_mux_init_info(BCM2835CprmanState *s,
27
FIELD(TBFLAG_A32, VFPEN, 7, 1)
36
mux->frac_bits = CLOCK_MUX_INIT_INFO[id].frac_bits;
28
FIELD(TBFLAG_A32, CONDEXEC, 8, 8)
37
}
29
FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
38
30
+/* For M profile only, set if we must create a new FP context */
39
+
31
+FIELD(TBFLAG_A32, NEW_FP_CTXT_NEEDED, 19, 1)
40
+/*
32
/* For M profile only, set if FPCCR.S does not match current security state */
41
+ * Object reset info
33
FIELD(TBFLAG_A32, FPCCR_S_WRONG, 20, 1)
42
+ * Those values have been dumped from a Raspberry Pi 3 Model B v1.2 using the
34
/* For M profile only, Handler (ie not Thread) mode */
43
+ * clk debugfs interface in Linux.
35
diff --git a/target/arm/translate.h b/target/arm/translate.h
44
+ */
45
+typedef struct PLLResetInfo {
46
+ uint32_t cm;
47
+ uint32_t a2w_ctrl;
48
+ uint32_t a2w_ana[4];
49
+ uint32_t a2w_frac;
50
+} PLLResetInfo;
51
+
52
+static const PLLResetInfo PLL_RESET_INFO[] = {
53
+ [CPRMAN_PLLA] = {
54
+ .cm = 0x0000008a,
55
+ .a2w_ctrl = 0x0002103a,
56
+ .a2w_frac = 0x00098000,
57
+ .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 }
58
+ },
59
+
60
+ [CPRMAN_PLLC] = {
61
+ .cm = 0x00000228,
62
+ .a2w_ctrl = 0x0002103e,
63
+ .a2w_frac = 0x00080000,
64
+ .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 }
65
+ },
66
+
67
+ [CPRMAN_PLLD] = {
68
+ .cm = 0x0000020a,
69
+ .a2w_ctrl = 0x00021034,
70
+ .a2w_frac = 0x00015556,
71
+ .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 }
72
+ },
73
+
74
+ [CPRMAN_PLLH] = {
75
+ .cm = 0x00000000,
76
+ .a2w_ctrl = 0x0002102d,
77
+ .a2w_frac = 0x00000000,
78
+ .a2w_ana = { 0x00900000, 0x0000000c, 0x00000000, 0x00000000 }
79
+ },
80
+
81
+ [CPRMAN_PLLB] = {
82
+ /* unknown */
83
+ .cm = 0x00000000,
84
+ .a2w_ctrl = 0x00000000,
85
+ .a2w_frac = 0x00000000,
86
+ .a2w_ana = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }
87
+ }
88
+};
89
+
90
+typedef struct PLLChannelResetInfo {
91
+ /*
92
+ * Even though a PLL channel has a CM register, it shares it with its
93
+ * parent PLL. The parent already takes care of the reset value.
94
+ */
95
+ uint32_t a2w_ctrl;
96
+} PLLChannelResetInfo;
97
+
98
+static const PLLChannelResetInfo PLL_CHANNEL_RESET_INFO[] = {
99
+ [CPRMAN_PLLA_CHANNEL_DSI0] = { .a2w_ctrl = 0x00000100 },
100
+ [CPRMAN_PLLA_CHANNEL_CORE] = { .a2w_ctrl = 0x00000003 },
101
+ [CPRMAN_PLLA_CHANNEL_PER] = { .a2w_ctrl = 0x00000000 }, /* unknown */
102
+ [CPRMAN_PLLA_CHANNEL_CCP2] = { .a2w_ctrl = 0x00000100 },
103
+
104
+ [CPRMAN_PLLC_CHANNEL_CORE2] = { .a2w_ctrl = 0x00000100 },
105
+ [CPRMAN_PLLC_CHANNEL_CORE1] = { .a2w_ctrl = 0x00000100 },
106
+ [CPRMAN_PLLC_CHANNEL_PER] = { .a2w_ctrl = 0x00000002 },
107
+ [CPRMAN_PLLC_CHANNEL_CORE0] = { .a2w_ctrl = 0x00000002 },
108
+
109
+ [CPRMAN_PLLD_CHANNEL_DSI0] = { .a2w_ctrl = 0x00000100 },
110
+ [CPRMAN_PLLD_CHANNEL_CORE] = { .a2w_ctrl = 0x00000004 },
111
+ [CPRMAN_PLLD_CHANNEL_PER] = { .a2w_ctrl = 0x00000004 },
112
+ [CPRMAN_PLLD_CHANNEL_DSI1] = { .a2w_ctrl = 0x00000100 },
113
+
114
+ [CPRMAN_PLLH_CHANNEL_AUX] = { .a2w_ctrl = 0x00000004 },
115
+ [CPRMAN_PLLH_CHANNEL_RCAL] = { .a2w_ctrl = 0x00000000 },
116
+ [CPRMAN_PLLH_CHANNEL_PIX] = { .a2w_ctrl = 0x00000000 },
117
+
118
+ [CPRMAN_PLLB_CHANNEL_ARM] = { .a2w_ctrl = 0x00000000 }, /* unknown */
119
+};
120
+
121
+typedef struct ClockMuxResetInfo {
122
+ uint32_t cm_ctl;
123
+ uint32_t cm_div;
124
+} ClockMuxResetInfo;
125
+
126
+static const ClockMuxResetInfo CLOCK_MUX_RESET_INFO[] = {
127
+ [CPRMAN_CLOCK_GNRIC] = {
128
+ .cm_ctl = 0, /* unknown */
129
+ .cm_div = 0
130
+ },
131
+
132
+ [CPRMAN_CLOCK_VPU] = {
133
+ .cm_ctl = 0x00000245,
134
+ .cm_div = 0x00003000,
135
+ },
136
+
137
+ [CPRMAN_CLOCK_SYS] = {
138
+ .cm_ctl = 0, /* unknown */
139
+ .cm_div = 0
140
+ },
141
+
142
+ [CPRMAN_CLOCK_PERIA] = {
143
+ .cm_ctl = 0, /* unknown */
144
+ .cm_div = 0
145
+ },
146
+
147
+ [CPRMAN_CLOCK_PERII] = {
148
+ .cm_ctl = 0, /* unknown */
149
+ .cm_div = 0
150
+ },
151
+
152
+ [CPRMAN_CLOCK_H264] = {
153
+ .cm_ctl = 0x00000244,
154
+ .cm_div = 0x00003000,
155
+ },
156
+
157
+ [CPRMAN_CLOCK_ISP] = {
158
+ .cm_ctl = 0x00000244,
159
+ .cm_div = 0x00003000,
160
+ },
161
+
162
+ [CPRMAN_CLOCK_V3D] = {
163
+ .cm_ctl = 0, /* unknown */
164
+ .cm_div = 0
165
+ },
166
+
167
+ [CPRMAN_CLOCK_CAM0] = {
168
+ .cm_ctl = 0x00000000,
169
+ .cm_div = 0x00000000,
170
+ },
171
+
172
+ [CPRMAN_CLOCK_CAM1] = {
173
+ .cm_ctl = 0x00000000,
174
+ .cm_div = 0x00000000,
175
+ },
176
+
177
+ [CPRMAN_CLOCK_CCP2] = {
178
+ .cm_ctl = 0, /* unknown */
179
+ .cm_div = 0
180
+ },
181
+
182
+ [CPRMAN_CLOCK_DSI0E] = {
183
+ .cm_ctl = 0x00000000,
184
+ .cm_div = 0x00000000,
185
+ },
186
+
187
+ [CPRMAN_CLOCK_DSI0P] = {
188
+ .cm_ctl = 0x00000000,
189
+ .cm_div = 0x00000000,
190
+ },
191
+
192
+ [CPRMAN_CLOCK_DPI] = {
193
+ .cm_ctl = 0x00000000,
194
+ .cm_div = 0x00000000,
195
+ },
196
+
197
+ [CPRMAN_CLOCK_GP0] = {
198
+ .cm_ctl = 0x00000200,
199
+ .cm_div = 0x00000000,
200
+ },
201
+
202
+ [CPRMAN_CLOCK_GP1] = {
203
+ .cm_ctl = 0x00000096,
204
+ .cm_div = 0x00014000,
205
+ },
206
+
207
+ [CPRMAN_CLOCK_GP2] = {
208
+ .cm_ctl = 0x00000291,
209
+ .cm_div = 0x00249f00,
210
+ },
211
+
212
+ [CPRMAN_CLOCK_HSM] = {
213
+ .cm_ctl = 0x00000000,
214
+ .cm_div = 0x00000000,
215
+ },
216
+
217
+ [CPRMAN_CLOCK_OTP] = {
218
+ .cm_ctl = 0x00000091,
219
+ .cm_div = 0x00004000,
220
+ },
221
+
222
+ [CPRMAN_CLOCK_PCM] = {
223
+ .cm_ctl = 0x00000200,
224
+ .cm_div = 0x00000000,
225
+ },
226
+
227
+ [CPRMAN_CLOCK_PWM] = {
228
+ .cm_ctl = 0x00000200,
229
+ .cm_div = 0x00000000,
230
+ },
231
+
232
+ [CPRMAN_CLOCK_SLIM] = {
233
+ .cm_ctl = 0x00000200,
234
+ .cm_div = 0x00000000,
235
+ },
236
+
237
+ [CPRMAN_CLOCK_SMI] = {
238
+ .cm_ctl = 0x00000000,
239
+ .cm_div = 0x00000000,
240
+ },
241
+
242
+ [CPRMAN_CLOCK_TEC] = {
243
+ .cm_ctl = 0x00000000,
244
+ .cm_div = 0x00000000,
245
+ },
246
+
247
+ [CPRMAN_CLOCK_TD0] = {
248
+ .cm_ctl = 0, /* unknown */
249
+ .cm_div = 0
250
+ },
251
+
252
+ [CPRMAN_CLOCK_TD1] = {
253
+ .cm_ctl = 0, /* unknown */
254
+ .cm_div = 0
255
+ },
256
+
257
+ [CPRMAN_CLOCK_TSENS] = {
258
+ .cm_ctl = 0x00000091,
259
+ .cm_div = 0x0000a000,
260
+ },
261
+
262
+ [CPRMAN_CLOCK_TIMER] = {
263
+ .cm_ctl = 0x00000291,
264
+ .cm_div = 0x00013333,
265
+ },
266
+
267
+ [CPRMAN_CLOCK_UART] = {
268
+ .cm_ctl = 0x00000296,
269
+ .cm_div = 0x0000a6ab,
270
+ },
271
+
272
+ [CPRMAN_CLOCK_VEC] = {
273
+ .cm_ctl = 0x00000097,
274
+ .cm_div = 0x00002000,
275
+ },
276
+
277
+ [CPRMAN_CLOCK_PULSE] = {
278
+ .cm_ctl = 0, /* unknown */
279
+ .cm_div = 0
280
+ },
281
+
282
+ [CPRMAN_CLOCK_SDC] = {
283
+ .cm_ctl = 0x00004006,
284
+ .cm_div = 0x00003000,
285
+ },
286
+
287
+ [CPRMAN_CLOCK_ARM] = {
288
+ .cm_ctl = 0, /* unknown */
289
+ .cm_div = 0
290
+ },
291
+
292
+ [CPRMAN_CLOCK_AVEO] = {
293
+ .cm_ctl = 0x00000000,
294
+ .cm_div = 0x00000000,
295
+ },
296
+
297
+ [CPRMAN_CLOCK_EMMC] = {
298
+ .cm_ctl = 0x00000295,
299
+ .cm_div = 0x00006000,
300
+ },
301
+
302
+ [CPRMAN_CLOCK_EMMC2] = {
303
+ .cm_ctl = 0, /* unknown */
304
+ .cm_div = 0
305
+ },
306
+};
307
+
308
#endif
309
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
36
index XXXXXXX..XXXXXXX 100644
310
index XXXXXXX..XXXXXXX 100644
37
--- a/target/arm/translate.h
311
--- a/hw/misc/bcm2835_cprman.c
38
+++ b/target/arm/translate.h
312
+++ b/hw/misc/bcm2835_cprman.c
39
@@ -XXX,XX +XXX,XX @@ typedef struct DisasContext {
313
@@ -XXX,XX +XXX,XX @@
40
bool v8m_secure; /* true if v8M and we're in Secure mode */
314
41
bool v8m_stackcheck; /* true if we need to perform v8M stack limit checks */
315
/* PLL */
42
bool v8m_fpccr_s_wrong; /* true if v8M FPCCR.S != v8m_secure */
316
43
+ bool v7m_new_fp_ctxt_needed; /* ASPEN set but no active FP context */
317
+static void pll_reset(DeviceState *dev)
44
/* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI
318
+{
45
* so that top level loop can generate correct syndrome information.
319
+ CprmanPllState *s = CPRMAN_PLL(dev);
46
*/
320
+ const PLLResetInfo *info = &PLL_RESET_INFO[s->id];
47
diff --git a/target/arm/helper.c b/target/arm/helper.c
321
+
48
index XXXXXXX..XXXXXXX 100644
322
+ *s->reg_cm = info->cm;
49
--- a/target/arm/helper.c
323
+ *s->reg_a2w_ctrl = info->a2w_ctrl;
50
+++ b/target/arm/helper.c
324
+ memcpy(s->reg_a2w_ana, info->a2w_ana, sizeof(info->a2w_ana));
51
@@ -XXX,XX +XXX,XX @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
325
+ *s->reg_a2w_frac = info->a2w_frac;
52
flags = FIELD_DP32(flags, TBFLAG_A32, FPCCR_S_WRONG, 1);
326
+}
53
}
327
+
54
328
static bool pll_is_locked(const CprmanPllState *pll)
55
+ if (arm_feature(env, ARM_FEATURE_M) &&
329
{
56
+ (env->v7m.fpccr[env->v7m.secure] & R_V7M_FPCCR_ASPEN_MASK) &&
330
return !FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PWRDN)
57
+ (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) ||
331
@@ -XXX,XX +XXX,XX @@ static void pll_class_init(ObjectClass *klass, void *data)
58
+ (env->v7m.secure &&
332
{
59
+ !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)))) {
333
DeviceClass *dc = DEVICE_CLASS(klass);
60
+ /*
334
61
+ * ASPEN is set, but FPCA/SFPA indicate that there is no active
335
+ dc->reset = pll_reset;
62
+ * FP context; we must create a new FP context before executing
336
dc->vmsd = &pll_vmstate;
63
+ * any FP insn.
337
}
64
+ */
338
65
+ flags = FIELD_DP32(flags, TBFLAG_A32, NEW_FP_CTXT_NEEDED, 1);
339
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
66
+ }
340
67
+
341
/* PLL channel */
68
*pflags = flags;
342
69
*cs_base = 0;
343
+static void pll_channel_reset(DeviceState *dev)
70
}
344
+{
71
diff --git a/target/arm/translate.c b/target/arm/translate.c
345
+ CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(dev);
72
index XXXXXXX..XXXXXXX 100644
346
+ const PLLChannelResetInfo *info = &PLL_CHANNEL_RESET_INFO[s->id];
73
--- a/target/arm/translate.c
347
+
74
+++ b/target/arm/translate.c
348
+ *s->reg_a2w_ctrl = info->a2w_ctrl;
75
@@ -XXX,XX +XXX,XX @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
349
+}
76
/* Don't need to do this for any further FP insns in this TB */
350
+
77
s->v8m_fpccr_s_wrong = false;
351
static bool pll_channel_is_enabled(CprmanPllChannelState *channel)
78
}
352
{
79
+
353
/*
80
+ if (s->v7m_new_fp_ctxt_needed) {
354
@@ -XXX,XX +XXX,XX @@ static void pll_channel_class_init(ObjectClass *klass, void *data)
81
+ /*
355
{
82
+ * Create new FP context by updating CONTROL.FPCA, CONTROL.SFPA
356
DeviceClass *dc = DEVICE_CLASS(klass);
83
+ * and the FPSCR.
357
84
+ */
358
+ dc->reset = pll_channel_reset;
85
+ TCGv_i32 control, fpscr;
359
dc->vmsd = &pll_channel_vmstate;
86
+ uint32_t bits = R_V7M_CONTROL_FPCA_MASK;
360
}
87
+
361
88
+ fpscr = load_cpu_field(v7m.fpdscr[s->v8m_secure]);
362
@@ -XXX,XX +XXX,XX @@ static void clock_mux_src_update(void *opaque)
89
+ gen_helper_vfp_set_fpscr(cpu_env, fpscr);
363
clock_mux_update(s);
90
+ tcg_temp_free_i32(fpscr);
364
}
91
+ /*
365
92
+ * We don't need to arrange to end the TB, because the only
366
+static void clock_mux_reset(DeviceState *dev)
93
+ * parts of FPSCR which we cache in the TB flags are the VECLEN
367
+{
94
+ * and VECSTRIDE, and those don't exist for M-profile.
368
+ CprmanClockMuxState *clock = CPRMAN_CLOCK_MUX(dev);
95
+ */
369
+ const ClockMuxResetInfo *info = &CLOCK_MUX_RESET_INFO[clock->id];
96
+
370
+
97
+ if (s->v8m_secure) {
371
+ *clock->reg_ctl = info->cm_ctl;
98
+ bits |= R_V7M_CONTROL_SFPA_MASK;
372
+ *clock->reg_div = info->cm_div;
99
+ }
373
+}
100
+ control = load_cpu_field(v7m.control[M_REG_S]);
374
+
101
+ tcg_gen_ori_i32(control, control, bits);
375
static void clock_mux_init(Object *obj)
102
+ store_cpu_field(control, v7m.control[M_REG_S]);
376
{
103
+ /* Don't need to do this for any further FP insns in this TB */
377
CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj);
104
+ s->v7m_new_fp_ctxt_needed = false;
378
@@ -XXX,XX +XXX,XX @@ static void clock_mux_class_init(ObjectClass *klass, void *data)
105
+ }
379
{
106
}
380
DeviceClass *dc = DEVICE_CLASS(klass);
107
381
108
if (extract32(insn, 28, 4) == 0xf) {
382
+ dc->reset = clock_mux_reset;
109
@@ -XXX,XX +XXX,XX @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
383
dc->vmsd = &clock_mux_vmstate;
110
regime_is_secure(env, dc->mmu_idx);
384
}
111
dc->v8m_stackcheck = FIELD_EX32(tb_flags, TBFLAG_A32, STACKCHECK);
112
dc->v8m_fpccr_s_wrong = FIELD_EX32(tb_flags, TBFLAG_A32, FPCCR_S_WRONG);
113
+ dc->v7m_new_fp_ctxt_needed =
114
+ FIELD_EX32(tb_flags, TBFLAG_A32, NEW_FP_CTXT_NEEDED);
115
dc->cp_regs = cpu->cp_regs;
116
dc->features = env->features;
117
385
118
--
386
--
119
2.20.1
387
2.20.1
120
388
121
389
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
Reviewed-by: Markus Armbruster <armbru@redhat.com>
3
Add a clock input to the PL011 UART so we can compute the current baud
4
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
4
rate and trace it. This is intended for developers who wish to use QEMU
5
Message-id: 20190412165416.7977-12-philmd@redhat.com
5
to e.g. debug their firmware or to figure out the baud rate configured
6
by an unknown/closed source binary.
7
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Signed-off-by: Luc Michel <luc@lmichel.fr>
10
Tested-by: Guenter Roeck <linux@roeck-us.net>
11
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
13
---
8
include/hw/net/lan9118.h | 2 ++
14
include/hw/char/pl011.h | 1 +
9
hw/arm/exynos4_boards.c | 3 ++-
15
hw/char/pl011.c | 45 +++++++++++++++++++++++++++++++++++++++++
10
hw/arm/mps2-tz.c | 3 ++-
16
hw/char/trace-events | 1 +
11
hw/net/lan9118.c | 1 -
17
3 files changed, 47 insertions(+)
12
4 files changed, 6 insertions(+), 3 deletions(-)
13
18
14
diff --git a/include/hw/net/lan9118.h b/include/hw/net/lan9118.h
19
diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h
15
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
16
--- a/include/hw/net/lan9118.h
21
--- a/include/hw/char/pl011.h
17
+++ b/include/hw/net/lan9118.h
22
+++ b/include/hw/char/pl011.h
23
@@ -XXX,XX +XXX,XX @@ struct PL011State {
24
int read_trigger;
25
CharBackend chr;
26
qemu_irq irq[6];
27
+ Clock *clk;
28
const unsigned char *id;
29
};
30
31
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/char/pl011.c
34
+++ b/hw/char/pl011.c
18
@@ -XXX,XX +XXX,XX @@
35
@@ -XXX,XX +XXX,XX @@
36
#include "hw/char/pl011.h"
19
#include "hw/irq.h"
37
#include "hw/irq.h"
20
#include "net/net.h"
38
#include "hw/sysbus.h"
21
39
+#include "hw/qdev-clock.h"
22
+#define TYPE_LAN9118 "lan9118"
40
#include "migration/vmstate.h"
41
#include "chardev/char-fe.h"
42
#include "qemu/log.h"
43
@@ -XXX,XX +XXX,XX @@ static void pl011_set_read_trigger(PL011State *s)
44
s->read_trigger = 1;
45
}
46
47
+static unsigned int pl011_get_baudrate(const PL011State *s)
48
+{
49
+ uint64_t clk;
23
+
50
+
24
void lan9118_init(NICInfo *, uint32_t, qemu_irq);
51
+ if (s->fbrd == 0) {
25
52
+ return 0;
26
#endif
53
+ }
27
diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c
54
+
28
index XXXXXXX..XXXXXXX 100644
55
+ clk = clock_get_hz(s->clk);
29
--- a/hw/arm/exynos4_boards.c
56
+ return (clk / ((s->ibrd << 6) + s->fbrd)) << 2;
30
+++ b/hw/arm/exynos4_boards.c
57
+}
31
@@ -XXX,XX +XXX,XX @@
58
+
32
#include "hw/arm/arm.h"
59
+static void pl011_trace_baudrate_change(const PL011State *s)
33
#include "exec/address-spaces.h"
60
+{
34
#include "hw/arm/exynos4210.h"
61
+ trace_pl011_baudrate_change(pl011_get_baudrate(s),
35
+#include "hw/net/lan9118.h"
62
+ clock_get_hz(s->clk),
36
#include "hw/boards.h"
63
+ s->ibrd, s->fbrd);
37
64
+}
38
#undef DEBUG
65
+
39
@@ -XXX,XX +XXX,XX @@ static void lan9215_init(uint32_t base, qemu_irq irq)
66
static void pl011_write(void *opaque, hwaddr offset,
40
/* This should be a 9215 but the 9118 is close enough */
67
uint64_t value, unsigned size)
41
if (nd_table[0].used) {
68
{
42
qemu_check_nic_model(&nd_table[0], "lan9118");
69
@@ -XXX,XX +XXX,XX @@ static void pl011_write(void *opaque, hwaddr offset,
43
- dev = qdev_create(NULL, "lan9118");
70
break;
44
+ dev = qdev_create(NULL, TYPE_LAN9118);
71
case 9: /* UARTIBRD */
45
qdev_set_nic_properties(dev, &nd_table[0]);
72
s->ibrd = value;
46
qdev_prop_set_uint32(dev, "mode_16bit", 1);
73
+ pl011_trace_baudrate_change(s);
47
qdev_init_nofail(dev);
74
break;
48
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
75
case 10: /* UARTFBRD */
49
index XXXXXXX..XXXXXXX 100644
76
s->fbrd = value;
50
--- a/hw/arm/mps2-tz.c
77
+ pl011_trace_baudrate_change(s);
51
+++ b/hw/arm/mps2-tz.c
78
break;
52
@@ -XXX,XX +XXX,XX @@
79
case 11: /* UARTLCR_H */
53
#include "hw/arm/armsse.h"
80
/* Reset the FIFO state on FIFO enable or disable */
54
#include "hw/dma/pl080.h"
81
@@ -XXX,XX +XXX,XX @@ static void pl011_event(void *opaque, QEMUChrEvent event)
55
#include "hw/ssi/pl022.h"
82
pl011_put_fifo(opaque, 0x400);
56
+#include "hw/net/lan9118.h"
83
}
57
#include "net/net.h"
84
58
#include "hw/core/split-irq.h"
85
+static void pl011_clock_update(void *opaque)
59
86
+{
60
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_eth_dev(MPS2TZMachineState *mms, void *opaque,
87
+ PL011State *s = PL011(opaque);
61
* except that it doesn't support the checksum-offload feature.
88
+
62
*/
89
+ pl011_trace_baudrate_change(s);
63
qemu_check_nic_model(nd, "lan9118");
90
+}
64
- mms->lan9118 = qdev_create(NULL, "lan9118");
91
+
65
+ mms->lan9118 = qdev_create(NULL, TYPE_LAN9118);
92
static const MemoryRegionOps pl011_ops = {
66
qdev_set_nic_properties(mms->lan9118, nd);
93
.read = pl011_read,
67
qdev_init_nofail(mms->lan9118);
94
.write = pl011_write,
68
95
.endianness = DEVICE_NATIVE_ENDIAN,
69
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
96
};
70
index XXXXXXX..XXXXXXX 100644
97
71
--- a/hw/net/lan9118.c
98
+static const VMStateDescription vmstate_pl011_clock = {
72
+++ b/hw/net/lan9118.c
99
+ .name = "pl011/clock",
73
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_lan9118_packet = {
100
+ .version_id = 1,
101
+ .minimum_version_id = 1,
102
+ .fields = (VMStateField[]) {
103
+ VMSTATE_CLOCK(clk, PL011State),
104
+ VMSTATE_END_OF_LIST()
105
+ }
106
+};
107
+
108
static const VMStateDescription vmstate_pl011 = {
109
.name = "pl011",
110
.version_id = 2,
111
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_pl011 = {
112
VMSTATE_INT32(read_count, PL011State),
113
VMSTATE_INT32(read_trigger, PL011State),
114
VMSTATE_END_OF_LIST()
115
+ },
116
+ .subsections = (const VMStateDescription * []) {
117
+ &vmstate_pl011_clock,
118
+ NULL
74
}
119
}
75
};
120
};
76
121
77
-#define TYPE_LAN9118 "lan9118"
122
@@ -XXX,XX +XXX,XX @@ static void pl011_init(Object *obj)
78
#define LAN9118(obj) OBJECT_CHECK(lan9118_state, (obj), TYPE_LAN9118)
123
sysbus_init_irq(sbd, &s->irq[i]);
79
124
}
80
typedef struct {
125
126
+ s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s);
127
+
128
s->read_trigger = 1;
129
s->ifl = 0x12;
130
s->cr = 0x300;
131
diff --git a/hw/char/trace-events b/hw/char/trace-events
132
index XXXXXXX..XXXXXXX 100644
133
--- a/hw/char/trace-events
134
+++ b/hw/char/trace-events
135
@@ -XXX,XX +XXX,XX @@ pl011_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
136
pl011_can_receive(uint32_t lcr, int read_count, int r) "LCR 0x%08x read_count %d returning %d"
137
pl011_put_fifo(uint32_t c, int read_count) "new char 0x%x read_count now %d"
138
pl011_put_fifo_full(void) "FIFO now full, RXFF set"
139
+pl011_baudrate_change(unsigned int baudrate, uint64_t clock, uint32_t ibrd, uint32_t fbrd) "new baudrate %u (clk: %" PRIu64 "hz, ibrd: %" PRIu32 ", fbrd: %" PRIu32 ")"
140
141
# cmsdk-apb-uart.c
142
cmsdk_apb_uart_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB UART read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
81
--
143
--
82
2.20.1
144
2.20.1
83
145
84
146
diff view generated by jsdifflib
1
Normally configure identifies the source path by looking
1
From: Luc Michel <luc@lmichel.fr>
2
at the location where the configure script itself exists.
3
We also provide a --source-path option which lets the user
4
manually override this.
5
2
6
There isn't really an obvious use case for the --source-path
3
Connect the 'uart-out' clock from the CPRMAN to the PL011 instance.
7
option, and in commit 927128222b0a91f56c13a in 2017 we
8
accidentally added some logic that looks at $source_path
9
before the command line option that overrides it has been
10
processed.
11
4
12
The fact that nobody complained suggests that there isn't
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
any use of this option and we aren't testing it either;
6
Signed-off-by: Luc Michel <luc@lmichel.fr>
14
remove it. This allows us to move the "make $source_path
7
Tested-by: Guenter Roeck <linux@roeck-us.net>
15
absolute" logic up so that there is no window in the script
8
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
16
where $source_path is set but not yet absolute.
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
hw/arm/bcm2835_peripherals.c | 2 ++
12
1 file changed, 2 insertions(+)
17
13
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
19
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
15
index XXXXXXX..XXXXXXX 100644
20
Message-id: 20190318134019.23729-1-peter.maydell@linaro.org
16
--- a/hw/arm/bcm2835_peripherals.c
21
---
17
+++ b/hw/arm/bcm2835_peripherals.c
22
configure | 10 ++--------
18
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
23
1 file changed, 2 insertions(+), 8 deletions(-)
19
}
24
20
memory_region_add_subregion(&s->peri_mr, CPRMAN_OFFSET,
25
diff --git a/configure b/configure
21
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cprman), 0));
26
index XXXXXXX..XXXXXXX 100755
22
+ qdev_connect_clock_in(DEVICE(&s->uart0), "clk",
27
--- a/configure
23
+ qdev_get_clock_out(DEVICE(&s->cprman), "uart-out"));
28
+++ b/configure
24
29
@@ -XXX,XX +XXX,XX @@ ld_has() {
25
memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET,
30
26
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0));
31
# default parameters
32
source_path=$(dirname "$0")
33
+# make source path absolute
34
+source_path=$(cd "$source_path"; pwd)
35
cpu=""
36
iasl="iasl"
37
interp_prefix="/usr/gnemul/qemu-%M"
38
@@ -XXX,XX +XXX,XX @@ for opt do
39
;;
40
--cxx=*) CXX="$optarg"
41
;;
42
- --source-path=*) source_path="$optarg"
43
- ;;
44
--cpu=*) cpu="$optarg"
45
;;
46
--extra-cflags=*) QEMU_CFLAGS="$QEMU_CFLAGS $optarg"
47
@@ -XXX,XX +XXX,XX @@ if test "$debug_info" = "yes"; then
48
LDFLAGS="-g $LDFLAGS"
49
fi
50
51
-# make source path absolute
52
-source_path=$(cd "$source_path"; pwd)
53
-
54
# running configure in the source tree?
55
# we know that's the case if configure is there.
56
if test -f "./configure"; then
57
@@ -XXX,XX +XXX,XX @@ for opt do
58
;;
59
--interp-prefix=*) interp_prefix="$optarg"
60
;;
61
- --source-path=*)
62
- ;;
63
--cross-prefix=*)
64
;;
65
--cc=*)
66
@@ -XXX,XX +XXX,XX @@ $(echo Available targets: $default_target_list | \
67
--target-list-exclude=LIST exclude a set of targets from the default target-list
68
69
Advanced options (experts only):
70
- --source-path=PATH path of source code [$source_path]
71
--cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]
72
--cc=CC use C compiler CC [$cc]
73
--iasl=IASL use ACPI compiler IASL [$iasl]
74
--
27
--
75
2.20.1
28
2.20.1
76
29
77
30
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Shashi Mallela <shashi.mallela@linaro.org>
2
2
3
Reviewed-by: Markus Armbruster <armbru@redhat.com>
3
Generic watchdog device model implementation as per ARM SBSA v6.0
4
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
4
5
Message-id: 20190412165416.7977-5-philmd@redhat.com
5
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
6
Message-id: 20201027015927.29495-2-shashi.mallela@linaro.org
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
9
---
8
include/hw/devices.h | 6 ------
10
include/hw/watchdog/sbsa_gwdt.h | 79 +++++++++
9
include/hw/display/tc6393xb.h | 24 ++++++++++++++++++++++++
11
hw/watchdog/sbsa_gwdt.c | 293 ++++++++++++++++++++++++++++++++
10
hw/arm/tosa.c | 2 +-
12
hw/arm/Kconfig | 1 +
11
hw/display/tc6393xb.c | 2 +-
13
hw/watchdog/Kconfig | 3 +
12
MAINTAINERS | 1 +
14
hw/watchdog/meson.build | 1 +
13
5 files changed, 27 insertions(+), 8 deletions(-)
15
5 files changed, 377 insertions(+)
14
create mode 100644 include/hw/display/tc6393xb.h
16
create mode 100644 include/hw/watchdog/sbsa_gwdt.h
17
create mode 100644 hw/watchdog/sbsa_gwdt.c
15
18
16
diff --git a/include/hw/devices.h b/include/hw/devices.h
19
diff --git a/include/hw/watchdog/sbsa_gwdt.h b/include/hw/watchdog/sbsa_gwdt.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/hw/devices.h
19
+++ b/include/hw/devices.h
20
@@ -XXX,XX +XXX,XX @@ void *tahvo_init(qemu_irq irq, int betty);
21
22
void retu_key_event(void *retu, int state);
23
24
-/* tc6393xb.c */
25
-typedef struct TC6393xbState TC6393xbState;
26
-TC6393xbState *tc6393xb_init(struct MemoryRegion *sysmem,
27
- uint32_t base, qemu_irq irq);
28
-qemu_irq tc6393xb_l3v_get(TC6393xbState *s);
29
-
30
#endif
31
diff --git a/include/hw/display/tc6393xb.h b/include/hw/display/tc6393xb.h
32
new file mode 100644
20
new file mode 100644
33
index XXXXXXX..XXXXXXX
21
index XXXXXXX..XXXXXXX
34
--- /dev/null
22
--- /dev/null
35
+++ b/include/hw/display/tc6393xb.h
23
+++ b/include/hw/watchdog/sbsa_gwdt.h
36
@@ -XXX,XX +XXX,XX @@
24
@@ -XXX,XX +XXX,XX @@
37
+/*
25
+/*
38
+ * Toshiba TC6393XB I/O Controller.
26
+ * Copyright (c) 2020 Linaro Limited
39
+ * Found in Sharp Zaurus SL-6000 (tosa) or some
27
+ *
40
+ * Toshiba e-Series PDAs.
28
+ * Authors:
41
+ *
29
+ * Shashi Mallela <shashi.mallela@linaro.org>
42
+ * Copyright (c) 2007 Hervé Poussineau
30
+ *
43
+ *
31
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
44
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
32
+ * option) any later version. See the COPYING file in the top-level directory.
45
+ * See the COPYING file in the top-level directory.
33
+ *
46
+ */
34
+ */
47
+
35
+
48
+#ifndef HW_DISPLAY_TC6393XB_H
36
+#ifndef WDT_SBSA_GWDT_H
49
+#define HW_DISPLAY_TC6393XB_H
37
+#define WDT_SBSA_GWDT_H
50
+
38
+
51
+#include "exec/memory.h"
39
+#include "qemu/bitops.h"
40
+#include "hw/sysbus.h"
52
+#include "hw/irq.h"
41
+#include "hw/irq.h"
53
+
42
+
54
+typedef struct TC6393xbState TC6393xbState;
43
+#define TYPE_WDT_SBSA "sbsa_gwdt"
55
+
44
+#define SBSA_GWDT(obj) \
56
+TC6393xbState *tc6393xb_init(struct MemoryRegion *sysmem,
45
+ OBJECT_CHECK(SBSA_GWDTState, (obj), TYPE_WDT_SBSA)
57
+ uint32_t base, qemu_irq irq);
46
+#define SBSA_GWDT_CLASS(klass) \
58
+qemu_irq tc6393xb_l3v_get(TC6393xbState *s);
47
+ OBJECT_CLASS_CHECK(SBSA_GWDTClass, (klass), TYPE_WDT_SBSA)
59
+
48
+#define SBSA_GWDT_GET_CLASS(obj) \
60
+#endif
49
+ OBJECT_GET_CLASS(SBSA_GWDTClass, (obj), TYPE_WDT_SBSA)
61
diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c
50
+
51
+/* SBSA Generic Watchdog register definitions */
52
+/* refresh frame */
53
+#define SBSA_GWDT_WRR 0x000
54
+
55
+/* control frame */
56
+#define SBSA_GWDT_WCS 0x000
57
+#define SBSA_GWDT_WOR 0x008
58
+#define SBSA_GWDT_WORU 0x00C
59
+#define SBSA_GWDT_WCV 0x010
60
+#define SBSA_GWDT_WCVU 0x014
61
+
62
+/* Watchdog Interface Identification Register */
63
+#define SBSA_GWDT_W_IIDR 0xFCC
64
+
65
+/* Watchdog Control and Status Register Bits */
66
+#define SBSA_GWDT_WCS_EN BIT(0)
67
+#define SBSA_GWDT_WCS_WS0 BIT(1)
68
+#define SBSA_GWDT_WCS_WS1 BIT(2)
69
+
70
+#define SBSA_GWDT_WOR_MASK 0x0000FFFF
71
+
72
+/*
73
+ * Watchdog Interface Identification Register definition
74
+ * considering JEP106 code for ARM in Bits [11:0]
75
+ */
76
+#define SBSA_GWDT_ID 0x1043B
77
+
78
+/* 2 Separate memory regions for each of refresh & control register frames */
79
+#define SBSA_GWDT_RMMIO_SIZE 0x1000
80
+#define SBSA_GWDT_CMMIO_SIZE 0x1000
81
+
82
+#define SBSA_TIMER_FREQ 62500000 /* Hz */
83
+
84
+typedef struct SBSA_GWDTState {
85
+ /* <private> */
86
+ SysBusDevice parent_obj;
87
+
88
+ /*< public >*/
89
+ MemoryRegion rmmio;
90
+ MemoryRegion cmmio;
91
+ qemu_irq irq;
92
+
93
+ QEMUTimer *timer;
94
+
95
+ uint32_t id;
96
+ uint32_t wcs;
97
+ uint32_t worl;
98
+ uint32_t woru;
99
+ uint32_t wcvl;
100
+ uint32_t wcvu;
101
+} SBSA_GWDTState;
102
+
103
+#endif /* WDT_SBSA_GWDT_H */
104
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
105
new file mode 100644
106
index XXXXXXX..XXXXXXX
107
--- /dev/null
108
+++ b/hw/watchdog/sbsa_gwdt.c
109
@@ -XXX,XX +XXX,XX @@
110
+/*
111
+ * Generic watchdog device model for SBSA
112
+ *
113
+ * The watchdog device has been implemented as revision 1 variant of
114
+ * the ARM SBSA specification v6.0
115
+ * (https://developer.arm.com/documentation/den0029/d?lang=en)
116
+ *
117
+ * Copyright Linaro.org 2020
118
+ *
119
+ * Authors:
120
+ * Shashi Mallela <shashi.mallela@linaro.org>
121
+ *
122
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
123
+ * option) any later version. See the COPYING file in the top-level directory.
124
+ *
125
+ */
126
+
127
+#include "qemu/osdep.h"
128
+#include "sysemu/reset.h"
129
+#include "sysemu/watchdog.h"
130
+#include "hw/watchdog/sbsa_gwdt.h"
131
+#include "qemu/timer.h"
132
+#include "migration/vmstate.h"
133
+#include "qemu/log.h"
134
+#include "qemu/module.h"
135
+
136
+static WatchdogTimerModel model = {
137
+ .wdt_name = TYPE_WDT_SBSA,
138
+ .wdt_description = "SBSA-compliant generic watchdog device",
139
+};
140
+
141
+static const VMStateDescription vmstate_sbsa_gwdt = {
142
+ .name = "sbsa-gwdt",
143
+ .version_id = 1,
144
+ .minimum_version_id = 1,
145
+ .fields = (VMStateField[]) {
146
+ VMSTATE_TIMER_PTR(timer, SBSA_GWDTState),
147
+ VMSTATE_UINT32(wcs, SBSA_GWDTState),
148
+ VMSTATE_UINT32(worl, SBSA_GWDTState),
149
+ VMSTATE_UINT32(woru, SBSA_GWDTState),
150
+ VMSTATE_UINT32(wcvl, SBSA_GWDTState),
151
+ VMSTATE_UINT32(wcvu, SBSA_GWDTState),
152
+ VMSTATE_END_OF_LIST()
153
+ }
154
+};
155
+
156
+typedef enum WdtRefreshType {
157
+ EXPLICIT_REFRESH = 0,
158
+ TIMEOUT_REFRESH = 1,
159
+} WdtRefreshType;
160
+
161
+static uint64_t sbsa_gwdt_rread(void *opaque, hwaddr addr, unsigned int size)
162
+{
163
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
164
+ uint32_t ret = 0;
165
+
166
+ switch (addr) {
167
+ case SBSA_GWDT_WRR:
168
+ /* watch refresh read has no effect and returns 0 */
169
+ ret = 0;
170
+ break;
171
+ case SBSA_GWDT_W_IIDR:
172
+ ret = s->id;
173
+ break;
174
+ default:
175
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in refresh frame read :"
176
+ " 0x%x\n", (int)addr);
177
+ }
178
+ return ret;
179
+}
180
+
181
+static uint64_t sbsa_gwdt_read(void *opaque, hwaddr addr, unsigned int size)
182
+{
183
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
184
+ uint32_t ret = 0;
185
+
186
+ switch (addr) {
187
+ case SBSA_GWDT_WCS:
188
+ ret = s->wcs;
189
+ break;
190
+ case SBSA_GWDT_WOR:
191
+ ret = s->worl;
192
+ break;
193
+ case SBSA_GWDT_WORU:
194
+ ret = s->woru;
195
+ break;
196
+ case SBSA_GWDT_WCV:
197
+ ret = s->wcvl;
198
+ break;
199
+ case SBSA_GWDT_WCVU:
200
+ ret = s->wcvu;
201
+ break;
202
+ case SBSA_GWDT_W_IIDR:
203
+ ret = s->id;
204
+ break;
205
+ default:
206
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame read :"
207
+ " 0x%x\n", (int)addr);
208
+ }
209
+ return ret;
210
+}
211
+
212
+static void sbsa_gwdt_update_timer(SBSA_GWDTState *s, WdtRefreshType rtype)
213
+{
214
+ uint64_t timeout = 0;
215
+
216
+ timer_del(s->timer);
217
+
218
+ if (s->wcs & SBSA_GWDT_WCS_EN) {
219
+ /*
220
+ * Extract the upper 16 bits from woru & 32 bits from worl
221
+ * registers to construct the 48 bit offset value
222
+ */
223
+ timeout = s->woru;
224
+ timeout <<= 32;
225
+ timeout |= s->worl;
226
+ timeout = muldiv64(timeout, NANOSECONDS_PER_SECOND, SBSA_TIMER_FREQ);
227
+ timeout += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
228
+
229
+ if ((rtype == EXPLICIT_REFRESH) || ((rtype == TIMEOUT_REFRESH) &&
230
+ (!(s->wcs & SBSA_GWDT_WCS_WS0)))) {
231
+ /* store the current timeout value into compare registers */
232
+ s->wcvu = timeout >> 32;
233
+ s->wcvl = timeout;
234
+ }
235
+ timer_mod(s->timer, timeout);
236
+ }
237
+}
238
+
239
+static void sbsa_gwdt_rwrite(void *opaque, hwaddr offset, uint64_t data,
240
+ unsigned size) {
241
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
242
+
243
+ if (offset == SBSA_GWDT_WRR) {
244
+ s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
245
+
246
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
247
+ } else {
248
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in refresh frame write :"
249
+ " 0x%x\n", (int)offset);
250
+ }
251
+}
252
+
253
+static void sbsa_gwdt_write(void *opaque, hwaddr offset, uint64_t data,
254
+ unsigned size) {
255
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
256
+
257
+ switch (offset) {
258
+ case SBSA_GWDT_WCS:
259
+ s->wcs = data & SBSA_GWDT_WCS_EN;
260
+ qemu_set_irq(s->irq, 0);
261
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
262
+ break;
263
+
264
+ case SBSA_GWDT_WOR:
265
+ s->worl = data;
266
+ s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
267
+ qemu_set_irq(s->irq, 0);
268
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
269
+ break;
270
+
271
+ case SBSA_GWDT_WORU:
272
+ s->woru = data & SBSA_GWDT_WOR_MASK;
273
+ s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
274
+ qemu_set_irq(s->irq, 0);
275
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
276
+ break;
277
+
278
+ case SBSA_GWDT_WCV:
279
+ s->wcvl = data;
280
+ break;
281
+
282
+ case SBSA_GWDT_WCVU:
283
+ s->wcvu = data;
284
+ break;
285
+
286
+ default:
287
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame write :"
288
+ " 0x%x\n", (int)offset);
289
+ }
290
+ return;
291
+}
292
+
293
+static void wdt_sbsa_gwdt_reset(DeviceState *dev)
294
+{
295
+ SBSA_GWDTState *s = SBSA_GWDT(dev);
296
+
297
+ timer_del(s->timer);
298
+
299
+ s->wcs = 0;
300
+ s->wcvl = 0;
301
+ s->wcvu = 0;
302
+ s->worl = 0;
303
+ s->woru = 0;
304
+ s->id = SBSA_GWDT_ID;
305
+}
306
+
307
+static void sbsa_gwdt_timer_sysinterrupt(void *opaque)
308
+{
309
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
310
+
311
+ if (!(s->wcs & SBSA_GWDT_WCS_WS0)) {
312
+ s->wcs |= SBSA_GWDT_WCS_WS0;
313
+ sbsa_gwdt_update_timer(s, TIMEOUT_REFRESH);
314
+ qemu_set_irq(s->irq, 1);
315
+ } else {
316
+ s->wcs |= SBSA_GWDT_WCS_WS1;
317
+ qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
318
+ /*
319
+ * Reset the watchdog only if the guest gets notified about
320
+ * expiry. watchdog_perform_action() may temporarily relinquish
321
+ * the BQL; reset before triggering the action to avoid races with
322
+ * sbsa_gwdt instructions.
323
+ */
324
+ switch (get_watchdog_action()) {
325
+ case WATCHDOG_ACTION_DEBUG:
326
+ case WATCHDOG_ACTION_NONE:
327
+ case WATCHDOG_ACTION_PAUSE:
328
+ break;
329
+ default:
330
+ wdt_sbsa_gwdt_reset(DEVICE(s));
331
+ }
332
+ watchdog_perform_action();
333
+ }
334
+}
335
+
336
+static const MemoryRegionOps sbsa_gwdt_rops = {
337
+ .read = sbsa_gwdt_rread,
338
+ .write = sbsa_gwdt_rwrite,
339
+ .endianness = DEVICE_LITTLE_ENDIAN,
340
+ .valid.min_access_size = 4,
341
+ .valid.max_access_size = 4,
342
+ .valid.unaligned = false,
343
+};
344
+
345
+static const MemoryRegionOps sbsa_gwdt_ops = {
346
+ .read = sbsa_gwdt_read,
347
+ .write = sbsa_gwdt_write,
348
+ .endianness = DEVICE_LITTLE_ENDIAN,
349
+ .valid.min_access_size = 4,
350
+ .valid.max_access_size = 4,
351
+ .valid.unaligned = false,
352
+};
353
+
354
+static void wdt_sbsa_gwdt_realize(DeviceState *dev, Error **errp)
355
+{
356
+ SBSA_GWDTState *s = SBSA_GWDT(dev);
357
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
358
+
359
+ memory_region_init_io(&s->rmmio, OBJECT(dev),
360
+ &sbsa_gwdt_rops, s,
361
+ "sbsa_gwdt.refresh",
362
+ SBSA_GWDT_RMMIO_SIZE);
363
+
364
+ memory_region_init_io(&s->cmmio, OBJECT(dev),
365
+ &sbsa_gwdt_ops, s,
366
+ "sbsa_gwdt.control",
367
+ SBSA_GWDT_CMMIO_SIZE);
368
+
369
+ sysbus_init_mmio(sbd, &s->rmmio);
370
+ sysbus_init_mmio(sbd, &s->cmmio);
371
+
372
+ sysbus_init_irq(sbd, &s->irq);
373
+
374
+ s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sbsa_gwdt_timer_sysinterrupt,
375
+ dev);
376
+}
377
+
378
+static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, void *data)
379
+{
380
+ DeviceClass *dc = DEVICE_CLASS(klass);
381
+
382
+ dc->realize = wdt_sbsa_gwdt_realize;
383
+ dc->reset = wdt_sbsa_gwdt_reset;
384
+ dc->hotpluggable = false;
385
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
386
+ dc->vmsd = &vmstate_sbsa_gwdt;
387
+}
388
+
389
+static const TypeInfo wdt_sbsa_gwdt_info = {
390
+ .class_init = wdt_sbsa_gwdt_class_init,
391
+ .parent = TYPE_SYS_BUS_DEVICE,
392
+ .name = TYPE_WDT_SBSA,
393
+ .instance_size = sizeof(SBSA_GWDTState),
394
+};
395
+
396
+static void wdt_sbsa_gwdt_register_types(void)
397
+{
398
+ watchdog_add_model(&model);
399
+ type_register_static(&wdt_sbsa_gwdt_info);
400
+}
401
+
402
+type_init(wdt_sbsa_gwdt_register_types)
403
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
62
index XXXXXXX..XXXXXXX 100644
404
index XXXXXXX..XXXXXXX 100644
63
--- a/hw/arm/tosa.c
405
--- a/hw/arm/Kconfig
64
+++ b/hw/arm/tosa.c
406
+++ b/hw/arm/Kconfig
65
@@ -XXX,XX +XXX,XX @@
407
@@ -XXX,XX +XXX,XX @@ config SBSA_REF
66
#include "hw/hw.h"
408
select PL031 # RTC
67
#include "hw/arm/pxa.h"
409
select PL061 # GPIO
68
#include "hw/arm/arm.h"
410
select USB_EHCI_SYSBUS
69
-#include "hw/devices.h"
411
+ select WDT_SBSA
70
#include "hw/arm/sharpsl.h"
412
71
#include "hw/pcmcia.h"
413
config SABRELITE
72
#include "hw/boards.h"
414
bool
73
+#include "hw/display/tc6393xb.h"
415
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig
74
#include "hw/i2c/i2c.h"
75
#include "hw/ssi/ssi.h"
76
#include "hw/sysbus.h"
77
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
78
index XXXXXXX..XXXXXXX 100644
416
index XXXXXXX..XXXXXXX 100644
79
--- a/hw/display/tc6393xb.c
417
--- a/hw/watchdog/Kconfig
80
+++ b/hw/display/tc6393xb.c
418
+++ b/hw/watchdog/Kconfig
81
@@ -XXX,XX +XXX,XX @@
419
@@ -XXX,XX +XXX,XX @@ config WDT_DIAG288
82
#include "qapi/error.h"
420
83
#include "qemu/host-utils.h"
421
config WDT_IMX2
84
#include "hw/hw.h"
422
bool
85
-#include "hw/devices.h"
423
+
86
+#include "hw/display/tc6393xb.h"
424
+config WDT_SBSA
87
#include "hw/block/flash.h"
425
+ bool
88
#include "ui/console.h"
426
diff --git a/hw/watchdog/meson.build b/hw/watchdog/meson.build
89
#include "ui/pixel_ops.h"
90
diff --git a/MAINTAINERS b/MAINTAINERS
91
index XXXXXXX..XXXXXXX 100644
427
index XXXXXXX..XXXXXXX 100644
92
--- a/MAINTAINERS
428
--- a/hw/watchdog/meson.build
93
+++ b/MAINTAINERS
429
+++ b/hw/watchdog/meson.build
94
@@ -XXX,XX +XXX,XX @@ F: hw/misc/mst_fpga.c
430
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_WDT_IB700', if_true: files('wdt_ib700.c'))
95
F: hw/misc/max111x.c
431
softmmu_ss.add(when: 'CONFIG_WDT_DIAG288', if_true: files('wdt_diag288.c'))
96
F: include/hw/arm/pxa.h
432
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('wdt_aspeed.c'))
97
F: include/hw/arm/sharpsl.h
433
softmmu_ss.add(when: 'CONFIG_WDT_IMX2', if_true: files('wdt_imx2.c'))
98
+F: include/hw/display/tc6393xb.h
434
+softmmu_ss.add(when: 'CONFIG_WDT_SBSA', if_true: files('sbsa_gwdt.c'))
99
100
SABRELITE / i.MX6
101
M: Peter Maydell <peter.maydell@linaro.org>
102
--
435
--
103
2.20.1
436
2.20.1
104
437
105
438
diff view generated by jsdifflib
1
The magic value pushed onto the callee stack as an integrity
1
From: Shashi Mallela <shashi.mallela@linaro.org>
2
check is different if floating point is present.
3
2
3
Included the newly implemented SBSA generic watchdog device model into
4
SBSA platform
5
6
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20201027015927.29495-3-shashi.mallela@linaro.org
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20190416125744.27770-15-peter.maydell@linaro.org
7
---
10
---
8
target/arm/helper.c | 22 +++++++++++++++++++---
11
hw/arm/sbsa-ref.c | 23 +++++++++++++++++++++++
9
1 file changed, 19 insertions(+), 3 deletions(-)
12
1 file changed, 23 insertions(+)
10
13
11
diff --git a/target/arm/helper.c b/target/arm/helper.c
14
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/helper.c
16
--- a/hw/arm/sbsa-ref.c
14
+++ b/target/arm/helper.c
17
+++ b/hw/arm/sbsa-ref.c
15
@@ -XXX,XX +XXX,XX @@ load_fail:
18
@@ -XXX,XX +XXX,XX @@
16
return false;
19
#include "hw/qdev-properties.h"
20
#include "hw/usb.h"
21
#include "hw/char/pl011.h"
22
+#include "hw/watchdog/sbsa_gwdt.h"
23
#include "net/net.h"
24
#include "qom/object.h"
25
26
@@ -XXX,XX +XXX,XX @@ enum {
27
SBSA_GIC_DIST,
28
SBSA_GIC_REDIST,
29
SBSA_SECURE_EC,
30
+ SBSA_GWDT,
31
+ SBSA_GWDT_REFRESH,
32
+ SBSA_GWDT_CONTROL,
33
SBSA_SMMU,
34
SBSA_UART,
35
SBSA_RTC,
36
@@ -XXX,XX +XXX,XX @@ static const MemMapEntry sbsa_ref_memmap[] = {
37
[SBSA_GIC_DIST] = { 0x40060000, 0x00010000 },
38
[SBSA_GIC_REDIST] = { 0x40080000, 0x04000000 },
39
[SBSA_SECURE_EC] = { 0x50000000, 0x00001000 },
40
+ [SBSA_GWDT_REFRESH] = { 0x50010000, 0x00001000 },
41
+ [SBSA_GWDT_CONTROL] = { 0x50011000, 0x00001000 },
42
[SBSA_UART] = { 0x60000000, 0x00001000 },
43
[SBSA_RTC] = { 0x60010000, 0x00001000 },
44
[SBSA_GPIO] = { 0x60020000, 0x00001000 },
45
@@ -XXX,XX +XXX,XX @@ static const int sbsa_ref_irqmap[] = {
46
[SBSA_AHCI] = 10,
47
[SBSA_EHCI] = 11,
48
[SBSA_SMMU] = 12, /* ... to 15 */
49
+ [SBSA_GWDT] = 16,
50
};
51
52
static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *sms, int idx)
53
@@ -XXX,XX +XXX,XX @@ static void create_rtc(const SBSAMachineState *sms)
54
sysbus_create_simple("pl031", base, qdev_get_gpio_in(sms->gic, irq));
17
}
55
}
18
56
19
+static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr)
57
+static void create_wdt(const SBSAMachineState *sms)
20
+{
58
+{
21
+ /*
59
+ hwaddr rbase = sbsa_ref_memmap[SBSA_GWDT_REFRESH].base;
22
+ * Return the integrity signature value for the callee-saves
60
+ hwaddr cbase = sbsa_ref_memmap[SBSA_GWDT_CONTROL].base;
23
+ * stack frame section. @lr is the exception return payload/LR value
61
+ DeviceState *dev = qdev_new(TYPE_WDT_SBSA);
24
+ * whose FType bit forms bit 0 of the signature if FP is present.
62
+ SysBusDevice *s = SYS_BUS_DEVICE(dev);
25
+ */
63
+ int irq = sbsa_ref_irqmap[SBSA_GWDT];
26
+ uint32_t sig = 0xfefa125a;
27
+
64
+
28
+ if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MASK)) {
65
+ sysbus_realize_and_unref(s, &error_fatal);
29
+ sig |= 1;
66
+ sysbus_mmio_map(s, 0, rbase);
30
+ }
67
+ sysbus_mmio_map(s, 1, cbase);
31
+ return sig;
68
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(sms->gic, irq));
32
+}
69
+}
33
+
70
+
34
static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
71
static DeviceState *gpio_key_dev;
35
bool ignore_faults)
72
static void sbsa_ref_powerdown_req(Notifier *n, void *opaque)
36
{
73
{
37
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
74
@@ -XXX,XX +XXX,XX @@ static void sbsa_ref_init(MachineState *machine)
38
bool stacked_ok;
75
39
uint32_t limit;
76
create_rtc(sms);
40
bool want_psp;
77
41
+ uint32_t sig;
78
+ create_wdt(sms);
42
79
+
43
if (dotailchain) {
80
create_gpio(sms);
44
bool mode = lr & R_V7M_EXCRET_MODE_MASK;
81
45
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
82
create_ahci(sms);
46
/* Write as much of the stack frame as we can. A write failure may
47
* cause us to pend a derived exception.
48
*/
49
+ sig = v7m_integrity_sig(env, lr);
50
stacked_ok =
51
- v7m_stack_write(cpu, frameptr, 0xfefa125b, mmu_idx, ignore_faults) &&
52
+ v7m_stack_write(cpu, frameptr, sig, mmu_idx, ignore_faults) &&
53
v7m_stack_write(cpu, frameptr + 0x8, env->regs[4], mmu_idx,
54
ignore_faults) &&
55
v7m_stack_write(cpu, frameptr + 0xc, env->regs[5], mmu_idx,
56
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
57
if (return_to_secure &&
58
((excret & R_V7M_EXCRET_ES_MASK) == 0 ||
59
(excret & R_V7M_EXCRET_DCRS_MASK) == 0)) {
60
- uint32_t expected_sig = 0xfefa125b;
61
uint32_t actual_sig;
62
63
pop_ok = v7m_stack_read(cpu, &actual_sig, frameptr, mmu_idx);
64
65
- if (pop_ok && expected_sig != actual_sig) {
66
+ if (pop_ok && v7m_integrity_sig(env, excret) != actual_sig) {
67
/* Take a SecureFault on the current stack */
68
env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;
69
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
70
--
83
--
71
2.20.1
84
2.20.1
72
85
73
86
diff view generated by jsdifflib
1
For v8M floating point support, transitions from Secure
1
In ptimer_reload(), we call the callback function provided by the
2
to Non-secure state via BLNS and BLXNS must clear the
2
timer device that is using the ptimer. This callback might disable
3
CONTROL.SFPA bit. (This corresponds to the pseudocode
3
the ptimer. The code mostly handles this correctly, except that
4
BranchToNS() function.)
4
we'll still print the warning about "Timer with delta zero,
5
disabling" if the now-disabled timer happened to be set such that it
6
would fire again immediately if it were enabled (eg because the
7
limit/reload value is zero).
8
9
Suppress the spurious warning message and the unnecessary
10
repeat-deletion of the underlying timer in this case.
5
11
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Message-id: 20190416125744.27770-13-peter.maydell@linaro.org
14
Message-id: 20201015151829.14656-2-peter.maydell@linaro.org
9
---
15
---
10
target/arm/helper.c | 4 ++++
16
hw/core/ptimer.c | 4 ++++
11
1 file changed, 4 insertions(+)
17
1 file changed, 4 insertions(+)
12
18
13
diff --git a/target/arm/helper.c b/target/arm/helper.c
19
diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
14
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/helper.c
21
--- a/hw/core/ptimer.c
16
+++ b/target/arm/helper.c
22
+++ b/hw/core/ptimer.c
17
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
23
@@ -XXX,XX +XXX,XX @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
18
/* translate.c should have made BXNS UNDEF unless we're secure */
19
assert(env->v7m.secure);
20
21
+ if (!(dest & 1)) {
22
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
23
+ }
24
switch_v7m_security_state(env, dest & 1);
25
env->thumb = 1;
26
env->regs[15] = dest & ~1;
27
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
28
*/
29
write_v7m_exception(env, 1);
30
}
24
}
31
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
25
32
switch_v7m_security_state(env, 0);
26
if (delta == 0) {
33
env->thumb = 1;
27
+ if (s->enabled == 0) {
34
env->regs[15] = dest;
28
+ /* trigger callback disabled the timer already */
29
+ return;
30
+ }
31
if (!qtest_enabled()) {
32
fprintf(stderr, "Timer with delta zero, disabling\n");
33
}
35
--
34
--
36
2.20.1
35
2.20.1
37
36
38
37
diff view generated by jsdifflib
1
In the stripe8() function we use a variable length array; however
1
The armv7m systick timer is a 24-bit decrementing, wrap-on-zero,
2
we know that the maximum length required is MAX_NUM_BUSSES. Use
2
clear-on-write counter. Our current implementation has various
3
a fixed-length array and an assert instead.
3
bugs and dubious workarounds in it (for instance see
4
https://bugs.launchpad.net/qemu/+bug/1872237).
5
6
We have an implementation of a simple decrementing counter
7
and we put a lot of effort into making sure it handles the
8
interesting corner cases (like "spend a cycle at 0 before
9
reloading") -- ptimer.
10
11
Rewrite the systick timer to use a ptimer rather than
12
a raw QEMU timer.
13
14
Unfortunately this is a migration compatibility break,
15
which will affect all M-profile boards.
16
17
Among other bugs, this fixes
18
https://bugs.launchpad.net/qemu/+bug/1872237 :
19
now writes to SYST_CVR when the timer is enabled correctly
20
do nothing; when the timer is enabled via SYST_CSR.ENABLE,
21
the ptimer code will (because of POLICY_NO_IMMEDIATE_RELOAD)
22
arrange that after one timer tick the counter is reloaded
23
from SYST_RVR and then counts down from there, as the
24
architecture requires.
4
25
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
26
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
27
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Reviewed-by: Francisco Iglesias <frasse.iglesias@gmail.com>
28
Message-id: 20201015151829.14656-3-peter.maydell@linaro.org
8
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
9
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
10
Message-id: 20190328152635.2794-1-peter.maydell@linaro.org
11
---
29
---
12
hw/ssi/xilinx_spips.c | 6 ++++--
30
include/hw/timer/armv7m_systick.h | 3 +-
13
1 file changed, 4 insertions(+), 2 deletions(-)
31
hw/timer/armv7m_systick.c | 124 +++++++++++++-----------------
14
32
2 files changed, 54 insertions(+), 73 deletions(-)
15
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
33
34
diff --git a/include/hw/timer/armv7m_systick.h b/include/hw/timer/armv7m_systick.h
16
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/ssi/xilinx_spips.c
36
--- a/include/hw/timer/armv7m_systick.h
18
+++ b/hw/ssi/xilinx_spips.c
37
+++ b/include/hw/timer/armv7m_systick.h
19
@@ -XXX,XX +XXX,XX @@ static void xlnx_zynqmp_qspips_reset(DeviceState *d)
38
@@ -XXX,XX +XXX,XX @@
20
39
21
static inline void stripe8(uint8_t *x, int num, bool dir)
40
#include "hw/sysbus.h"
41
#include "qom/object.h"
42
+#include "hw/ptimer.h"
43
44
#define TYPE_SYSTICK "armv7m_systick"
45
46
@@ -XXX,XX +XXX,XX @@ struct SysTickState {
47
uint32_t control;
48
uint32_t reload;
49
int64_t tick;
50
- QEMUTimer *timer;
51
+ ptimer_state *ptimer;
52
MemoryRegion iomem;
53
qemu_irq irq;
54
};
55
diff --git a/hw/timer/armv7m_systick.c b/hw/timer/armv7m_systick.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/hw/timer/armv7m_systick.c
58
+++ b/hw/timer/armv7m_systick.c
59
@@ -XXX,XX +XXX,XX @@ static inline int64_t systick_scale(SysTickState *s)
60
}
61
}
62
63
-static void systick_reload(SysTickState *s, int reset)
64
-{
65
- /* The Cortex-M3 Devices Generic User Guide says that "When the
66
- * ENABLE bit is set to 1, the counter loads the RELOAD value from the
67
- * SYST RVR register and then counts down". So, we need to check the
68
- * ENABLE bit before reloading the value.
69
- */
70
- trace_systick_reload();
71
-
72
- if ((s->control & SYSTICK_ENABLE) == 0) {
73
- return;
74
- }
75
-
76
- if (reset) {
77
- s->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
78
- }
79
- s->tick += (s->reload + 1) * systick_scale(s);
80
- timer_mod(s->timer, s->tick);
81
-}
82
-
83
static void systick_timer_tick(void *opaque)
22
{
84
{
23
- uint8_t r[num];
85
SysTickState *s = (SysTickState *)opaque;
24
- memset(r, 0, sizeof(uint8_t) * num);
86
@@ -XXX,XX +XXX,XX @@ static void systick_timer_tick(void *opaque)
25
+ uint8_t r[MAX_NUM_BUSSES];
87
/* Tell the NVIC to pend the SysTick exception */
26
int idx[2] = {0, 0};
88
qemu_irq_pulse(s->irq);
27
int bit[2] = {0, 7};
89
}
28
int d = dir;
90
- if (s->reload == 0) {
29
91
- s->control &= ~SYSTICK_ENABLE;
30
+ assert(num <= MAX_NUM_BUSSES);
92
- } else {
31
+ memset(r, 0, sizeof(uint8_t) * num);
93
- systick_reload(s, 0);
94
+ if (ptimer_get_limit(s->ptimer) == 0) {
95
+ /*
96
+ * Timer expiry with SYST_RVR zero disables the timer
97
+ * (but doesn't clear SYST_CSR.ENABLE)
98
+ */
99
+ ptimer_stop(s->ptimer);
100
}
101
}
102
103
@@ -XXX,XX +XXX,XX @@ static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data,
104
s->control &= ~SYSTICK_COUNTFLAG;
105
break;
106
case 0x4: /* SysTick Reload Value. */
107
- val = s->reload;
108
+ val = ptimer_get_limit(s->ptimer);
109
break;
110
case 0x8: /* SysTick Current Value. */
111
- {
112
- int64_t t;
113
-
114
- if ((s->control & SYSTICK_ENABLE) == 0) {
115
- val = 0;
116
- break;
117
- }
118
- t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
119
- if (t >= s->tick) {
120
- val = 0;
121
- break;
122
- }
123
- val = ((s->tick - (t + 1)) / systick_scale(s)) + 1;
124
- /* The interrupt in triggered when the timer reaches zero.
125
- However the counter is not reloaded until the next clock
126
- tick. This is a hack to return zero during the first tick. */
127
- if (val > s->reload) {
128
- val = 0;
129
- }
130
+ val = ptimer_get_count(s->ptimer);
131
break;
132
- }
133
case 0xc: /* SysTick Calibration Value. */
134
val = 10000;
135
break;
136
@@ -XXX,XX +XXX,XX @@ static MemTxResult systick_write(void *opaque, hwaddr addr,
137
switch (addr) {
138
case 0x0: /* SysTick Control and Status. */
139
{
140
- uint32_t oldval = s->control;
141
+ uint32_t oldval;
142
143
+ ptimer_transaction_begin(s->ptimer);
144
+ oldval = s->control;
145
s->control &= 0xfffffff8;
146
s->control |= value & 7;
32
+
147
+
33
for (idx[0] = 0; idx[0] < num; ++idx[0]) {
148
if ((oldval ^ value) & SYSTICK_ENABLE) {
34
for (bit[0] = 7; bit[0] >= 0; bit[0]--) {
149
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
35
r[idx[!d]] |= x[idx[d]] & 1 << bit[d] ? 1 << bit[!d] : 0;
150
if (value & SYSTICK_ENABLE) {
151
- if (s->tick) {
152
- s->tick += now;
153
- timer_mod(s->timer, s->tick);
154
- } else {
155
- systick_reload(s, 1);
156
- }
157
+ /*
158
+ * Always reload the period in case board code has
159
+ * changed system_clock_scale. If we ever replace that
160
+ * global with a more sensible API then we might be able
161
+ * to set the period only when it actually changes.
162
+ */
163
+ ptimer_set_period(s->ptimer, systick_scale(s));
164
+ ptimer_run(s->ptimer, 0);
165
} else {
166
- timer_del(s->timer);
167
- s->tick -= now;
168
- if (s->tick < 0) {
169
- s->tick = 0;
170
- }
171
+ ptimer_stop(s->ptimer);
172
}
173
} else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
174
- /* This is a hack. Force the timer to be reloaded
175
- when the reference clock is changed. */
176
- systick_reload(s, 1);
177
+ ptimer_set_period(s->ptimer, systick_scale(s));
178
}
179
+ ptimer_transaction_commit(s->ptimer);
180
break;
181
}
182
case 0x4: /* SysTick Reload Value. */
183
- s->reload = value;
184
+ ptimer_transaction_begin(s->ptimer);
185
+ ptimer_set_limit(s->ptimer, value & 0xffffff, 0);
186
+ ptimer_transaction_commit(s->ptimer);
187
break;
188
- case 0x8: /* SysTick Current Value. Writes reload the timer. */
189
- systick_reload(s, 1);
190
+ case 0x8: /* SysTick Current Value. */
191
+ /*
192
+ * Writing any value clears SYST_CVR to zero and clears
193
+ * SYST_CSR.COUNTFLAG. The counter will then reload from SYST_RVR
194
+ * on the next clock edge unless SYST_RVR is zero.
195
+ */
196
+ ptimer_transaction_begin(s->ptimer);
197
+ if (ptimer_get_limit(s->ptimer) == 0) {
198
+ ptimer_stop(s->ptimer);
199
+ }
200
+ ptimer_set_count(s->ptimer, 0);
201
s->control &= ~SYSTICK_COUNTFLAG;
202
+ ptimer_transaction_commit(s->ptimer);
203
break;
204
default:
205
qemu_log_mask(LOG_GUEST_ERROR,
206
@@ -XXX,XX +XXX,XX @@ static void systick_reset(DeviceState *dev)
207
*/
208
assert(system_clock_scale != 0);
209
210
+ ptimer_transaction_begin(s->ptimer);
211
s->control = 0;
212
- s->reload = 0;
213
- s->tick = 0;
214
- timer_del(s->timer);
215
+ ptimer_stop(s->ptimer);
216
+ ptimer_set_count(s->ptimer, 0);
217
+ ptimer_set_limit(s->ptimer, 0, 0);
218
+ ptimer_set_period(s->ptimer, systick_scale(s));
219
+ ptimer_transaction_commit(s->ptimer);
220
}
221
222
static void systick_instance_init(Object *obj)
223
@@ -XXX,XX +XXX,XX @@ static void systick_instance_init(Object *obj)
224
static void systick_realize(DeviceState *dev, Error **errp)
225
{
226
SysTickState *s = SYSTICK(dev);
227
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s);
228
+ s->ptimer = ptimer_init(systick_timer_tick, s,
229
+ PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
230
+ PTIMER_POLICY_NO_COUNTER_ROUND_DOWN |
231
+ PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
232
+ PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT);
233
}
234
235
static const VMStateDescription vmstate_systick = {
236
.name = "armv7m_systick",
237
- .version_id = 1,
238
- .minimum_version_id = 1,
239
+ .version_id = 2,
240
+ .minimum_version_id = 2,
241
.fields = (VMStateField[]) {
242
VMSTATE_UINT32(control, SysTickState),
243
- VMSTATE_UINT32(reload, SysTickState),
244
VMSTATE_INT64(tick, SysTickState),
245
- VMSTATE_TIMER_PTR(timer, SysTickState),
246
+ VMSTATE_PTIMER(ptimer, SysTickState),
247
VMSTATE_END_OF_LIST()
248
}
249
};
36
--
250
--
37
2.20.1
251
2.20.1
38
252
39
253
diff view generated by jsdifflib