target-arm queue:
* Support u-boot 'noload' images for Arm (as used by NetBSD/evbarm GENERIC kernel)
  * hw/misc/tz-mpc: Fix value of BLK_MAX register
  * target/arm: Emit barriers for A32/T32 load-acquire/store-release insns
  * nRF51 SoC: add timer, GPIO, RNG peripherals
  * hw/arm/allwinner-a10: Add the 'A' SRAM and the SRAM controller
  * cpus.c: Fix race condition in cpu_stop_current()
  * hw/arm: versal: Plug memory leaks
  * Allow M profile boards to run even if -kernel not specified
  * gdbstub: Add multiprocess extension support for use when the
    board has multiple CPUs of different types (like the Xilinx Zynq boards)
  * target/arm: Don't decode S bit in SVE brk[ab] merging insns
  * target/arm: Convert ARM_TBFLAG_* to FIELDs
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJcM36AAAoJEDwlJe0UNgzepuMP/A6umcXRrO+vOZgkW+cvJ8cD
 JkDdb8H/u3S6zqNokABI3Ya/areX1P30sRV7e7mC5IsknVNZe0MqQX6TW5477HMP
 Oz/m1AbyByWMLVILFiWfte5dtRRLfs3axzrmhu6HwJXe0NIUiYQofoJzCZEDMxDn
 71cehgeNkUGA36HViPyqzHZYADFkCX3Tfmh1FEh2jD7taK9GNsff8p6cHTb05W7d
 wWk68PS8VKTb5VrYH6SyiAHW8gBVrrUkYlkPKHzemK5fwlgDOSfxVLthf8mo08SH
 QxEXI430tagdmrGNO/nKOTA2NQwMzvCk/OLf0Qwg9I9F9pYtiOJ7nXXbtqDC8eKy
 DdHsL57W0F7sFkoVt+YNHSeylyLRluDh+D+Q7OHnlvwsEYmecqsWkW/A2CYC0uWs
 8ajxPBNpGG1lIvo63YK5/4kOy0DE/6ISljYOSlYYg3iXeAZPkQZMTlUxoYmJQ+Zr
 h1tLg1N9SuyQK5g5Uuluw2GwgzIv/Bt1LFo7pnvsA2X6PKiv6nno40T8q0Lw6ah4
 lmAUWx0OUilTrvQwterHlr6hfWu2RLiRoxCg06a3C93YlRjsR3vZOBeQ5ByaE+ho
 5ItKn58EerO+UaweVoc6MDhJFPC8b16Eee281BCec8Ks4GR1tIcpP/0z2lUwhBu6
 hoPmkoPtFtu1dKBgF8Ma
 =x1jv
 -----END PGP SIGNATURE-----
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190107' into staging
target-arm queue:
 * Support u-boot 'noload' images for Arm (as used by NetBSD/evbarm GENERIC kernel)
 * hw/misc/tz-mpc: Fix value of BLK_MAX register
 * target/arm: Emit barriers for A32/T32 load-acquire/store-release insns
 * nRF51 SoC: add timer, GPIO, RNG peripherals
 * hw/arm/allwinner-a10: Add the 'A' SRAM and the SRAM controller
 * cpus.c: Fix race condition in cpu_stop_current()
 * hw/arm: versal: Plug memory leaks
 * Allow M profile boards to run even if -kernel not specified
 * gdbstub: Add multiprocess extension support for use when the
   board has multiple CPUs of different types (like the Xilinx Zynq boards)
 * target/arm: Don't decode S bit in SVE brk[ab] merging insns
 * target/arm: Convert ARM_TBFLAG_* to FIELDs
# gpg: Signature made Mon 07 Jan 2019 16:29:52 GMT
# gpg:                using RSA key 3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>"
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE
* remotes/pmaydell/tags/pull-target-arm-20190107: (37 commits)
  Support u-boot noload images for arm as used by, NetBSD/evbarm GENERIC kernel.
  hw/misc/tz-mpc: Fix value of BLK_MAX register
  target/arm: Emit barriers for A32/T32 load-acquire/store-release insns
  arm: Add Clock peripheral stub to NRF51 SOC
  tests/microbit-test: Add Tests for nRF51 Timer
  arm: Instantiate NRF51 Timers
  hw/timer/nrf51_timer: Add nRF51 Timer peripheral
  tests/microbit-test: Add Tests for nRF51 GPIO
  arm: Instantiate NRF51 general purpose I/O
  hw/gpio/nrf51_gpio: Add nRF51 GPIO peripheral
  arm: Instantiate NRF51 random number generator
  hw/misc/nrf51_rng: Add NRF51 random number generator peripheral
  arm: Add header to host common definition for nRF51 SOC peripherals
  qtest: Add set_irq_in command to set IRQ/GPIO level
  hw/arm/allwinner-a10: Add the 'A' SRAM and the SRAM controller
  cpus.c: Fix race condition in cpu_stop_current()
  MAINTAINERS: Add ARM-related files for hw/[misc|input|timer]/
  hw/arm: versal: Plug memory leaks
  Revert "armv7m: Guard against no -kernel argument"
  arm/xlnx-zynqmp: put APUs and RPUs in separate CPU clusters
  ...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
			
			
This commit is contained in:
		
						commit
						c102d9471f
					
				
							
								
								
									
										18
									
								
								MAINTAINERS
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								MAINTAINERS
									
									
									
									
									
								
							@ -515,6 +515,7 @@ F: hw/intc/arm*
 | 
				
			|||||||
F: hw/intc/gic_internal.h
 | 
					F: hw/intc/gic_internal.h
 | 
				
			||||||
F: hw/misc/a9scu.c
 | 
					F: hw/misc/a9scu.c
 | 
				
			||||||
F: hw/misc/arm11scu.c
 | 
					F: hw/misc/arm11scu.c
 | 
				
			||||||
 | 
					F: hw/misc/arm_l2x0.c
 | 
				
			||||||
F: hw/timer/a9gtimer*
 | 
					F: hw/timer/a9gtimer*
 | 
				
			||||||
F: hw/timer/arm*
 | 
					F: hw/timer/arm*
 | 
				
			||||||
F: include/hw/arm/arm*.h
 | 
					F: include/hw/arm/arm*.h
 | 
				
			||||||
@ -587,6 +588,7 @@ L: qemu-arm@nongnu.org
 | 
				
			|||||||
S: Maintained
 | 
					S: Maintained
 | 
				
			||||||
F: hw/arm/integratorcp.c
 | 
					F: hw/arm/integratorcp.c
 | 
				
			||||||
F: hw/misc/arm_integrator_debug.c
 | 
					F: hw/misc/arm_integrator_debug.c
 | 
				
			||||||
 | 
					F: include/hw/misc/arm_integrator_debug.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MCIMX6UL EVK / i.MX6ul
 | 
					MCIMX6UL EVK / i.MX6ul
 | 
				
			||||||
M: Peter Maydell <peter.maydell@linaro.org>
 | 
					M: Peter Maydell <peter.maydell@linaro.org>
 | 
				
			||||||
@ -606,7 +608,9 @@ L: qemu-arm@nongnu.org
 | 
				
			|||||||
S: Odd Fixes
 | 
					S: Odd Fixes
 | 
				
			||||||
F: hw/arm/mcimx7d-sabre.c
 | 
					F: hw/arm/mcimx7d-sabre.c
 | 
				
			||||||
F: hw/arm/fsl-imx7.c
 | 
					F: hw/arm/fsl-imx7.c
 | 
				
			||||||
 | 
					F: hw/misc/imx7_*.c
 | 
				
			||||||
F: include/hw/arm/fsl-imx7.h
 | 
					F: include/hw/arm/fsl-imx7.h
 | 
				
			||||||
 | 
					F: include/hw/misc/imx7_*.h
 | 
				
			||||||
F: hw/pci-host/designware.c
 | 
					F: hw/pci-host/designware.c
 | 
				
			||||||
F: include/hw/pci-host/designware.h
 | 
					F: include/hw/pci-host/designware.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -640,6 +644,10 @@ M: Peter Maydell <peter.maydell@linaro.org>
 | 
				
			|||||||
L: qemu-arm@nongnu.org
 | 
					L: qemu-arm@nongnu.org
 | 
				
			||||||
S: Odd Fixes
 | 
					S: Odd Fixes
 | 
				
			||||||
F: hw/arm/nseries.c
 | 
					F: hw/arm/nseries.c
 | 
				
			||||||
 | 
					F: hw/input/lm832x.c
 | 
				
			||||||
 | 
					F: hw/input/tsc2005.c
 | 
				
			||||||
 | 
					F: hw/misc/cbus.c
 | 
				
			||||||
 | 
					F: hw/timer/twl92230.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Palm
 | 
					Palm
 | 
				
			||||||
M: Andrzej Zaborowski <balrogg@gmail.com>
 | 
					M: Andrzej Zaborowski <balrogg@gmail.com>
 | 
				
			||||||
@ -647,6 +655,7 @@ M: Peter Maydell <peter.maydell@linaro.org>
 | 
				
			|||||||
L: qemu-arm@nongnu.org
 | 
					L: qemu-arm@nongnu.org
 | 
				
			||||||
S: Odd Fixes
 | 
					S: Odd Fixes
 | 
				
			||||||
F: hw/arm/palm.c
 | 
					F: hw/arm/palm.c
 | 
				
			||||||
 | 
					F: hw/input/tsc210x.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Raspberry Pi
 | 
					Raspberry Pi
 | 
				
			||||||
M: Peter Maydell <peter.maydell@linaro.org>
 | 
					M: Peter Maydell <peter.maydell@linaro.org>
 | 
				
			||||||
@ -683,6 +692,7 @@ F: hw/display/tc6393xb.c
 | 
				
			|||||||
F: hw/gpio/max7310.c
 | 
					F: hw/gpio/max7310.c
 | 
				
			||||||
F: hw/gpio/zaurus.c
 | 
					F: hw/gpio/zaurus.c
 | 
				
			||||||
F: hw/misc/mst_fpga.c
 | 
					F: hw/misc/mst_fpga.c
 | 
				
			||||||
 | 
					F: hw/misc/max111x.c
 | 
				
			||||||
F: include/hw/arm/pxa.h
 | 
					F: include/hw/arm/pxa.h
 | 
				
			||||||
F: include/hw/arm/sharpsl.h
 | 
					F: include/hw/arm/sharpsl.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -693,10 +703,10 @@ L: qemu-arm@nongnu.org
 | 
				
			|||||||
S: Odd Fixes
 | 
					S: Odd Fixes
 | 
				
			||||||
F: hw/arm/sabrelite.c
 | 
					F: hw/arm/sabrelite.c
 | 
				
			||||||
F: hw/arm/fsl-imx6.c
 | 
					F: hw/arm/fsl-imx6.c
 | 
				
			||||||
F: hw/misc/imx6_src.c
 | 
					F: hw/misc/imx6_*.c
 | 
				
			||||||
F: hw/ssi/imx_spi.c
 | 
					F: hw/ssi/imx_spi.c
 | 
				
			||||||
F: include/hw/arm/fsl-imx6.h
 | 
					F: include/hw/arm/fsl-imx6.h
 | 
				
			||||||
F: include/hw/misc/imx6_src.h
 | 
					F: include/hw/misc/imx6_*.h
 | 
				
			||||||
F: include/hw/ssi/imx_spi.h
 | 
					F: include/hw/ssi/imx_spi.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Sharp SL-5500 (Collie) PDA
 | 
					Sharp SL-5500 (Collie) PDA
 | 
				
			||||||
@ -807,7 +817,9 @@ R: Joel Stanley <joel@jms.id.au>
 | 
				
			|||||||
L: qemu-arm@nongnu.org
 | 
					L: qemu-arm@nongnu.org
 | 
				
			||||||
S: Maintained
 | 
					S: Maintained
 | 
				
			||||||
F: hw/*/*aspeed*
 | 
					F: hw/*/*aspeed*
 | 
				
			||||||
 | 
					F: hw/misc/pca9552.c
 | 
				
			||||||
F: include/hw/*/*aspeed*
 | 
					F: include/hw/*/*aspeed*
 | 
				
			||||||
 | 
					F: include/hw/misc/pca9552*.h
 | 
				
			||||||
F: hw/net/ftgmac100.c
 | 
					F: hw/net/ftgmac100.c
 | 
				
			||||||
F: include/hw/net/ftgmac100.h
 | 
					F: include/hw/net/ftgmac100.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1195,7 +1207,9 @@ M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
 | 
				
			|||||||
S: Supported
 | 
					S: Supported
 | 
				
			||||||
F: hw/core/machine.c
 | 
					F: hw/core/machine.c
 | 
				
			||||||
F: hw/core/null-machine.c
 | 
					F: hw/core/null-machine.c
 | 
				
			||||||
 | 
					F: hw/cpu/cluster.c
 | 
				
			||||||
F: include/hw/boards.h
 | 
					F: include/hw/boards.h
 | 
				
			||||||
 | 
					F: include/hw/cpu/cluster.h
 | 
				
			||||||
T: git https://github.com/ehabkost/qemu.git machine-next
 | 
					T: git https://github.com/ehabkost/qemu.git machine-next
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Xtensa Machines
 | 
					Xtensa Machines
 | 
				
			||||||
 | 
				
			|||||||
@ -184,6 +184,7 @@ trace-events-subdirs += hw/vfio
 | 
				
			|||||||
trace-events-subdirs += hw/virtio
 | 
					trace-events-subdirs += hw/virtio
 | 
				
			||||||
trace-events-subdirs += hw/watchdog
 | 
					trace-events-subdirs += hw/watchdog
 | 
				
			||||||
trace-events-subdirs += hw/xen
 | 
					trace-events-subdirs += hw/xen
 | 
				
			||||||
 | 
					trace-events-subdirs += hw/gpio
 | 
				
			||||||
trace-events-subdirs += io
 | 
					trace-events-subdirs += io
 | 
				
			||||||
trace-events-subdirs += linux-user
 | 
					trace-events-subdirs += linux-user
 | 
				
			||||||
trace-events-subdirs += migration
 | 
					trace-events-subdirs += migration
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										3
									
								
								cpus.c
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								cpus.c
									
									
									
									
									
								
							@ -2100,7 +2100,8 @@ void qemu_init_vcpu(CPUState *cpu)
 | 
				
			|||||||
void cpu_stop_current(void)
 | 
					void cpu_stop_current(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (current_cpu) {
 | 
					    if (current_cpu) {
 | 
				
			||||||
        qemu_cpu_stop(current_cpu, true);
 | 
					        current_cpu->stop = true;
 | 
				
			||||||
 | 
					        cpu_exit(current_cpu);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										672
									
								
								gdbstub.c
									
									
									
									
									
								
							
							
						
						
									
										672
									
								
								gdbstub.c
									
									
									
									
									
								
							@ -29,6 +29,7 @@
 | 
				
			|||||||
#include "chardev/char-fe.h"
 | 
					#include "chardev/char-fe.h"
 | 
				
			||||||
#include "sysemu/sysemu.h"
 | 
					#include "sysemu/sysemu.h"
 | 
				
			||||||
#include "exec/gdbstub.h"
 | 
					#include "exec/gdbstub.h"
 | 
				
			||||||
 | 
					#include "hw/cpu/cluster.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_PACKET_LENGTH 4096
 | 
					#define MAX_PACKET_LENGTH 4096
 | 
				
			||||||
@ -296,6 +297,13 @@ typedef struct GDBRegisterState {
 | 
				
			|||||||
    struct GDBRegisterState *next;
 | 
					    struct GDBRegisterState *next;
 | 
				
			||||||
} GDBRegisterState;
 | 
					} GDBRegisterState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct GDBProcess {
 | 
				
			||||||
 | 
					    uint32_t pid;
 | 
				
			||||||
 | 
					    bool attached;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char target_xml[1024];
 | 
				
			||||||
 | 
					} GDBProcess;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum RSState {
 | 
					enum RSState {
 | 
				
			||||||
    RS_INACTIVE,
 | 
					    RS_INACTIVE,
 | 
				
			||||||
    RS_IDLE,
 | 
					    RS_IDLE,
 | 
				
			||||||
@ -324,6 +332,9 @@ typedef struct GDBState {
 | 
				
			|||||||
    CharBackend chr;
 | 
					    CharBackend chr;
 | 
				
			||||||
    Chardev *mon_chr;
 | 
					    Chardev *mon_chr;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					    bool multiprocess;
 | 
				
			||||||
 | 
					    GDBProcess *processes;
 | 
				
			||||||
 | 
					    int process_num;
 | 
				
			||||||
    char syscall_buf[256];
 | 
					    char syscall_buf[256];
 | 
				
			||||||
    gdb_syscall_complete_cb current_syscall_cb;
 | 
					    gdb_syscall_complete_cb current_syscall_cb;
 | 
				
			||||||
} GDBState;
 | 
					} GDBState;
 | 
				
			||||||
@ -631,13 +642,186 @@ static int memtox(char *buf, const char *mem, int len)
 | 
				
			|||||||
    return p - buf;
 | 
					    return p - buf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *get_feature_xml(const char *p, const char **newp,
 | 
					static uint32_t gdb_get_cpu_pid(const GDBState *s, CPUState *cpu)
 | 
				
			||||||
                                   CPUClass *cc)
 | 
					{
 | 
				
			||||||
 | 
					#ifndef CONFIG_USER_ONLY
 | 
				
			||||||
 | 
					    gchar *path, *name = NULL;
 | 
				
			||||||
 | 
					    Object *obj;
 | 
				
			||||||
 | 
					    CPUClusterState *cluster;
 | 
				
			||||||
 | 
					    uint32_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    path = object_get_canonical_path(OBJECT(cpu));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (path == NULL) {
 | 
				
			||||||
 | 
					        /* Return the default process' PID */
 | 
				
			||||||
 | 
					        ret = s->processes[s->process_num - 1].pid;
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = object_get_canonical_path_component(OBJECT(cpu));
 | 
				
			||||||
 | 
					    assert(name != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Retrieve the CPU parent path by removing the last '/' and the CPU name
 | 
				
			||||||
 | 
					     * from the CPU canonical path.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    path[strlen(path) - strlen(name) - 1] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    obj = object_resolve_path_type(path, TYPE_CPU_CLUSTER, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (obj == NULL) {
 | 
				
			||||||
 | 
					        /* Return the default process' PID */
 | 
				
			||||||
 | 
					        ret = s->processes[s->process_num - 1].pid;
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cluster = CPU_CLUSTER(obj);
 | 
				
			||||||
 | 
					    ret = cluster->cluster_id + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
					    g_free(name);
 | 
				
			||||||
 | 
					    g_free(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    /* TODO: In user mode, we should use the task state PID */
 | 
				
			||||||
 | 
					    return s->processes[s->process_num - 1].pid;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GDBProcess *gdb_get_process(const GDBState *s, uint32_t pid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!pid) {
 | 
				
			||||||
 | 
					        /* 0 means any process, we take the first one */
 | 
				
			||||||
 | 
					        return &s->processes[0];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < s->process_num; i++) {
 | 
				
			||||||
 | 
					        if (s->processes[i].pid == pid) {
 | 
				
			||||||
 | 
					            return &s->processes[i];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GDBProcess *gdb_get_cpu_process(const GDBState *s, CPUState *cpu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return gdb_get_process(s, gdb_get_cpu_pid(s, cpu));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static CPUState *find_cpu(uint32_t thread_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CPUState *cpu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CPU_FOREACH(cpu) {
 | 
				
			||||||
 | 
					        if (cpu_gdb_index(cpu) == thread_id) {
 | 
				
			||||||
 | 
					            return cpu;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static CPUState *get_first_cpu_in_process(const GDBState *s,
 | 
				
			||||||
 | 
					                                          GDBProcess *process)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CPUState *cpu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CPU_FOREACH(cpu) {
 | 
				
			||||||
 | 
					        if (gdb_get_cpu_pid(s, cpu) == process->pid) {
 | 
				
			||||||
 | 
					            return cpu;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static CPUState *gdb_next_cpu_in_process(const GDBState *s, CPUState *cpu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint32_t pid = gdb_get_cpu_pid(s, cpu);
 | 
				
			||||||
 | 
					    cpu = CPU_NEXT(cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (cpu) {
 | 
				
			||||||
 | 
					        if (gdb_get_cpu_pid(s, cpu) == pid) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cpu = CPU_NEXT(cpu);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return cpu;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static CPUState *gdb_get_cpu(const GDBState *s, uint32_t pid, uint32_t tid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GDBProcess *process;
 | 
				
			||||||
 | 
					    CPUState *cpu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!tid) {
 | 
				
			||||||
 | 
					        /* 0 means any thread, we take the first one */
 | 
				
			||||||
 | 
					        tid = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cpu = find_cpu(tid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (cpu == NULL) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    process = gdb_get_cpu_process(s, cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (process->pid != pid) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!process->attached) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return cpu;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return the cpu following @cpu, while ignoring unattached processes. */
 | 
				
			||||||
 | 
					static CPUState *gdb_next_attached_cpu(const GDBState *s, CPUState *cpu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    cpu = CPU_NEXT(cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (cpu) {
 | 
				
			||||||
 | 
					        if (gdb_get_cpu_process(s, cpu)->attached) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cpu = CPU_NEXT(cpu);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return cpu;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return the first attached cpu */
 | 
				
			||||||
 | 
					static CPUState *gdb_first_attached_cpu(const GDBState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CPUState *cpu = first_cpu;
 | 
				
			||||||
 | 
					    GDBProcess *process = gdb_get_cpu_process(s, cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!process->attached) {
 | 
				
			||||||
 | 
					        return gdb_next_attached_cpu(s, cpu);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return cpu;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *get_feature_xml(const GDBState *s, const char *p,
 | 
				
			||||||
 | 
					                                   const char **newp, GDBProcess *process)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    size_t len;
 | 
					    size_t len;
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
    const char *name;
 | 
					    const char *name;
 | 
				
			||||||
    static char target_xml[1024];
 | 
					    CPUState *cpu = get_first_cpu_in_process(s, process);
 | 
				
			||||||
 | 
					    CPUClass *cc = CPU_GET_CLASS(cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    len = 0;
 | 
					    len = 0;
 | 
				
			||||||
    while (p[len] && p[len] != ':')
 | 
					    while (p[len] && p[len] != ':')
 | 
				
			||||||
@ -646,36 +830,37 @@ static const char *get_feature_xml(const char *p, const char **newp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    name = NULL;
 | 
					    name = NULL;
 | 
				
			||||||
    if (strncmp(p, "target.xml", len) == 0) {
 | 
					    if (strncmp(p, "target.xml", len) == 0) {
 | 
				
			||||||
        /* Generate the XML description for this CPU.  */
 | 
					        char *buf = process->target_xml;
 | 
				
			||||||
        if (!target_xml[0]) {
 | 
					        const size_t buf_sz = sizeof(process->target_xml);
 | 
				
			||||||
            GDBRegisterState *r;
 | 
					 | 
				
			||||||
            CPUState *cpu = first_cpu;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            pstrcat(target_xml, sizeof(target_xml),
 | 
					        /* Generate the XML description for this CPU.  */
 | 
				
			||||||
 | 
					        if (!buf[0]) {
 | 
				
			||||||
 | 
					            GDBRegisterState *r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            pstrcat(buf, buf_sz,
 | 
				
			||||||
                    "<?xml version=\"1.0\"?>"
 | 
					                    "<?xml version=\"1.0\"?>"
 | 
				
			||||||
                    "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
 | 
					                    "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
 | 
				
			||||||
                    "<target>");
 | 
					                    "<target>");
 | 
				
			||||||
            if (cc->gdb_arch_name) {
 | 
					            if (cc->gdb_arch_name) {
 | 
				
			||||||
                gchar *arch = cc->gdb_arch_name(cpu);
 | 
					                gchar *arch = cc->gdb_arch_name(cpu);
 | 
				
			||||||
                pstrcat(target_xml, sizeof(target_xml), "<architecture>");
 | 
					                pstrcat(buf, buf_sz, "<architecture>");
 | 
				
			||||||
                pstrcat(target_xml, sizeof(target_xml), arch);
 | 
					                pstrcat(buf, buf_sz, arch);
 | 
				
			||||||
                pstrcat(target_xml, sizeof(target_xml), "</architecture>");
 | 
					                pstrcat(buf, buf_sz, "</architecture>");
 | 
				
			||||||
                g_free(arch);
 | 
					                g_free(arch);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\"");
 | 
					            pstrcat(buf, buf_sz, "<xi:include href=\"");
 | 
				
			||||||
            pstrcat(target_xml, sizeof(target_xml), cc->gdb_core_xml_file);
 | 
					            pstrcat(buf, buf_sz, cc->gdb_core_xml_file);
 | 
				
			||||||
            pstrcat(target_xml, sizeof(target_xml), "\"/>");
 | 
					            pstrcat(buf, buf_sz, "\"/>");
 | 
				
			||||||
            for (r = cpu->gdb_regs; r; r = r->next) {
 | 
					            for (r = cpu->gdb_regs; r; r = r->next) {
 | 
				
			||||||
                pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\"");
 | 
					                pstrcat(buf, buf_sz, "<xi:include href=\"");
 | 
				
			||||||
                pstrcat(target_xml, sizeof(target_xml), r->xml);
 | 
					                pstrcat(buf, buf_sz, r->xml);
 | 
				
			||||||
                pstrcat(target_xml, sizeof(target_xml), "\"/>");
 | 
					                pstrcat(buf, buf_sz, "\"/>");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            pstrcat(target_xml, sizeof(target_xml), "</target>");
 | 
					            pstrcat(buf, buf_sz, "</target>");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return target_xml;
 | 
					        return buf;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (cc->gdb_get_dynamic_xml) {
 | 
					    if (cc->gdb_get_dynamic_xml) {
 | 
				
			||||||
        CPUState *cpu = first_cpu;
 | 
					 | 
				
			||||||
        char *xmlname = g_strndup(p, len);
 | 
					        char *xmlname = g_strndup(p, len);
 | 
				
			||||||
        const char *xml = cc->gdb_get_dynamic_xml(cpu, xmlname);
 | 
					        const char *xml = cc->gdb_get_dynamic_xml(cpu, xmlname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -862,6 +1047,24 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void gdb_cpu_breakpoint_remove_all(CPUState *cpu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    cpu_breakpoint_remove_all(cpu, BP_GDB);
 | 
				
			||||||
 | 
					#ifndef CONFIG_USER_ONLY
 | 
				
			||||||
 | 
					    cpu_watchpoint_remove_all(cpu, BP_GDB);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void gdb_process_breakpoint_remove_all(const GDBState *s, GDBProcess *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CPUState *cpu = get_first_cpu_in_process(s, p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (cpu) {
 | 
				
			||||||
 | 
					        gdb_cpu_breakpoint_remove_all(cpu);
 | 
				
			||||||
 | 
					        cpu = gdb_next_cpu_in_process(s, cpu);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void gdb_breakpoint_remove_all(void)
 | 
					static void gdb_breakpoint_remove_all(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUState *cpu;
 | 
					    CPUState *cpu;
 | 
				
			||||||
@ -872,10 +1075,7 @@ static void gdb_breakpoint_remove_all(void)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CPU_FOREACH(cpu) {
 | 
					    CPU_FOREACH(cpu) {
 | 
				
			||||||
        cpu_breakpoint_remove_all(cpu, BP_GDB);
 | 
					        gdb_cpu_breakpoint_remove_all(cpu);
 | 
				
			||||||
#ifndef CONFIG_USER_ONLY
 | 
					 | 
				
			||||||
        cpu_watchpoint_remove_all(cpu, BP_GDB);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -887,17 +1087,71 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
 | 
				
			|||||||
    cpu_set_pc(cpu, pc);
 | 
					    cpu_set_pc(cpu, pc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static CPUState *find_cpu(uint32_t thread_id)
 | 
					static char *gdb_fmt_thread_id(const GDBState *s, CPUState *cpu,
 | 
				
			||||||
 | 
					                           char *buf, size_t buf_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUState *cpu;
 | 
					    if (s->multiprocess) {
 | 
				
			||||||
 | 
					        snprintf(buf, buf_size, "p%02x.%02x",
 | 
				
			||||||
    CPU_FOREACH(cpu) {
 | 
					                 gdb_get_cpu_pid(s, cpu), cpu_gdb_index(cpu));
 | 
				
			||||||
        if (cpu_gdb_index(cpu) == thread_id) {
 | 
					    } else {
 | 
				
			||||||
            return cpu;
 | 
					        snprintf(buf, buf_size, "%02x", cpu_gdb_index(cpu));
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return NULL;
 | 
					    return buf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum GDBThreadIdKind {
 | 
				
			||||||
 | 
					    GDB_ONE_THREAD = 0,
 | 
				
			||||||
 | 
					    GDB_ALL_THREADS,     /* One process, all threads */
 | 
				
			||||||
 | 
					    GDB_ALL_PROCESSES,
 | 
				
			||||||
 | 
					    GDB_READ_THREAD_ERR
 | 
				
			||||||
 | 
					} GDBThreadIdKind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static GDBThreadIdKind read_thread_id(const char *buf, const char **end_buf,
 | 
				
			||||||
 | 
					                                      uint32_t *pid, uint32_t *tid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    unsigned long p, t;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (*buf == 'p') {
 | 
				
			||||||
 | 
					        buf++;
 | 
				
			||||||
 | 
					        ret = qemu_strtoul(buf, &buf, 16, &p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ret) {
 | 
				
			||||||
 | 
					            return GDB_READ_THREAD_ERR;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Skip '.' */
 | 
				
			||||||
 | 
					        buf++;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        p = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = qemu_strtoul(buf, &buf, 16, &t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret) {
 | 
				
			||||||
 | 
					        return GDB_READ_THREAD_ERR;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *end_buf = buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (p == -1) {
 | 
				
			||||||
 | 
					        return GDB_ALL_PROCESSES;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pid) {
 | 
				
			||||||
 | 
					        *pid = p;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (t == -1) {
 | 
				
			||||||
 | 
					        return GDB_ALL_THREADS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (tid) {
 | 
				
			||||||
 | 
					        *tid = t;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return GDB_ONE_THREAD;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int is_query_packet(const char *p, const char *query, char separator)
 | 
					static int is_query_packet(const char *p, const char *query, char separator)
 | 
				
			||||||
@ -915,10 +1169,12 @@ static int is_query_packet(const char *p, const char *query, char separator)
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
static int gdb_handle_vcont(GDBState *s, const char *p)
 | 
					static int gdb_handle_vcont(GDBState *s, const char *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int res, idx, signal = 0;
 | 
					    int res, signal = 0;
 | 
				
			||||||
    char cur_action;
 | 
					    char cur_action;
 | 
				
			||||||
    char *newstates;
 | 
					    char *newstates;
 | 
				
			||||||
    unsigned long tmp;
 | 
					    unsigned long tmp;
 | 
				
			||||||
 | 
					    uint32_t pid, tid;
 | 
				
			||||||
 | 
					    GDBProcess *process;
 | 
				
			||||||
    CPUState *cpu;
 | 
					    CPUState *cpu;
 | 
				
			||||||
#ifdef CONFIG_USER_ONLY
 | 
					#ifdef CONFIG_USER_ONLY
 | 
				
			||||||
    int max_cpus = 1; /* global variable max_cpus exists only in system mode */
 | 
					    int max_cpus = 1; /* global variable max_cpus exists only in system mode */
 | 
				
			||||||
@ -961,25 +1217,48 @@ static int gdb_handle_vcont(GDBState *s, const char *p)
 | 
				
			|||||||
            res = -ENOTSUP;
 | 
					            res = -ENOTSUP;
 | 
				
			||||||
            goto out;
 | 
					            goto out;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        /* thread specification. special values: (none), -1 = all; 0 = any */
 | 
					
 | 
				
			||||||
        if ((p[0] == ':' && p[1] == '-' && p[2] == '1') || (p[0] != ':')) {
 | 
					        if (*p++ != ':') {
 | 
				
			||||||
            if (*p == ':') {
 | 
					            res = -ENOTSUP;
 | 
				
			||||||
                p += 3;
 | 
					            goto out;
 | 
				
			||||||
            }
 | 
					        }
 | 
				
			||||||
            for (idx = 0; idx < max_cpus; idx++) {
 | 
					
 | 
				
			||||||
                if (newstates[idx] == 1) {
 | 
					        switch (read_thread_id(p, &p, &pid, &tid)) {
 | 
				
			||||||
                    newstates[idx] = cur_action;
 | 
					        case GDB_READ_THREAD_ERR:
 | 
				
			||||||
 | 
					            res = -EINVAL;
 | 
				
			||||||
 | 
					            goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case GDB_ALL_PROCESSES:
 | 
				
			||||||
 | 
					            cpu = gdb_first_attached_cpu(s);
 | 
				
			||||||
 | 
					            while (cpu) {
 | 
				
			||||||
 | 
					                if (newstates[cpu->cpu_index] == 1) {
 | 
				
			||||||
 | 
					                    newstates[cpu->cpu_index] = cur_action;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                cpu = gdb_next_attached_cpu(s, cpu);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else if (*p == ':') {
 | 
					            break;
 | 
				
			||||||
            p++;
 | 
					
 | 
				
			||||||
            res = qemu_strtoul(p, &p, 16, &tmp);
 | 
					        case GDB_ALL_THREADS:
 | 
				
			||||||
            if (res) {
 | 
					            process = gdb_get_process(s, pid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!process->attached) {
 | 
				
			||||||
 | 
					                res = -EINVAL;
 | 
				
			||||||
                goto out;
 | 
					                goto out;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /* 0 means any thread, so we pick the first valid CPU */
 | 
					            cpu = get_first_cpu_in_process(s, process);
 | 
				
			||||||
            cpu = tmp ? find_cpu(tmp) : first_cpu;
 | 
					            while (cpu) {
 | 
				
			||||||
 | 
					                if (newstates[cpu->cpu_index] == 1) {
 | 
				
			||||||
 | 
					                    newstates[cpu->cpu_index] = cur_action;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                cpu = gdb_next_cpu_in_process(s, cpu);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case GDB_ONE_THREAD:
 | 
				
			||||||
 | 
					            cpu = gdb_get_cpu(s, pid, tid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /* invalid CPU/thread specified */
 | 
					            /* invalid CPU/thread specified */
 | 
				
			||||||
            if (!cpu) {
 | 
					            if (!cpu) {
 | 
				
			||||||
@ -991,6 +1270,7 @@ static int gdb_handle_vcont(GDBState *s, const char *p)
 | 
				
			|||||||
            if (newstates[cpu->cpu_index] == 1) {
 | 
					            if (newstates[cpu->cpu_index] == 1) {
 | 
				
			||||||
                newstates[cpu->cpu_index] = cur_action;
 | 
					                newstates[cpu->cpu_index] = cur_action;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    s->signal = signal;
 | 
					    s->signal = signal;
 | 
				
			||||||
@ -1005,24 +1285,30 @@ out:
 | 
				
			|||||||
static int gdb_handle_packet(GDBState *s, const char *line_buf)
 | 
					static int gdb_handle_packet(GDBState *s, const char *line_buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUState *cpu;
 | 
					    CPUState *cpu;
 | 
				
			||||||
 | 
					    GDBProcess *process;
 | 
				
			||||||
    CPUClass *cc;
 | 
					    CPUClass *cc;
 | 
				
			||||||
    const char *p;
 | 
					    const char *p;
 | 
				
			||||||
    uint32_t thread;
 | 
					    uint32_t pid, tid;
 | 
				
			||||||
    int ch, reg_size, type, res;
 | 
					    int ch, reg_size, type, res;
 | 
				
			||||||
    uint8_t mem_buf[MAX_PACKET_LENGTH];
 | 
					    uint8_t mem_buf[MAX_PACKET_LENGTH];
 | 
				
			||||||
    char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
 | 
					    char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
 | 
				
			||||||
 | 
					    char thread_id[16];
 | 
				
			||||||
    uint8_t *registers;
 | 
					    uint8_t *registers;
 | 
				
			||||||
    target_ulong addr, len;
 | 
					    target_ulong addr, len;
 | 
				
			||||||
 | 
					    GDBThreadIdKind thread_kind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    trace_gdbstub_io_command(line_buf);
 | 
					    trace_gdbstub_io_command(line_buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    p = line_buf;
 | 
					    p = line_buf;
 | 
				
			||||||
    ch = *p++;
 | 
					    ch = *p++;
 | 
				
			||||||
    switch(ch) {
 | 
					    switch(ch) {
 | 
				
			||||||
 | 
					    case '!':
 | 
				
			||||||
 | 
					        put_packet(s, "OK");
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    case '?':
 | 
					    case '?':
 | 
				
			||||||
        /* TODO: Make this return the correct value for user-mode.  */
 | 
					        /* TODO: Make this return the correct value for user-mode.  */
 | 
				
			||||||
        snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
 | 
					        snprintf(buf, sizeof(buf), "T%02xthread:%s;", GDB_SIGNAL_TRAP,
 | 
				
			||||||
                 cpu_gdb_index(s->c_cpu));
 | 
					                 gdb_fmt_thread_id(s, s->c_cpu, thread_id, sizeof(thread_id)));
 | 
				
			||||||
        put_packet(s, buf);
 | 
					        put_packet(s, buf);
 | 
				
			||||||
        /* Remove all the breakpoints when this query is issued,
 | 
					        /* Remove all the breakpoints when this query is issued,
 | 
				
			||||||
         * because gdb is doing and initial connect and the state
 | 
					         * because gdb is doing and initial connect and the state
 | 
				
			||||||
@ -1062,6 +1348,41 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
 | 
				
			|||||||
                goto unknown_command;
 | 
					                goto unknown_command;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					        } else if (strncmp(p, "Attach;", 7) == 0) {
 | 
				
			||||||
 | 
					            unsigned long pid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            p += 7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (qemu_strtoul(p, &p, 16, &pid)) {
 | 
				
			||||||
 | 
					                put_packet(s, "E22");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            process = gdb_get_process(s, pid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (process == NULL) {
 | 
				
			||||||
 | 
					                put_packet(s, "E22");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            cpu = get_first_cpu_in_process(s, process);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (cpu == NULL) {
 | 
				
			||||||
 | 
					                /* Refuse to attach an empty process */
 | 
				
			||||||
 | 
					                put_packet(s, "E22");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            process->attached = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            s->g_cpu = cpu;
 | 
				
			||||||
 | 
					            s->c_cpu = cpu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            snprintf(buf, sizeof(buf), "T%02xthread:%s;", GDB_SIGNAL_TRAP,
 | 
				
			||||||
 | 
					                     gdb_fmt_thread_id(s, cpu, thread_id, sizeof(thread_id)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            put_packet(s, buf);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            goto unknown_command;
 | 
					            goto unknown_command;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -1071,9 +1392,40 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
 | 
				
			|||||||
        exit(0);
 | 
					        exit(0);
 | 
				
			||||||
    case 'D':
 | 
					    case 'D':
 | 
				
			||||||
        /* Detach packet */
 | 
					        /* Detach packet */
 | 
				
			||||||
        gdb_breakpoint_remove_all();
 | 
					        pid = 1;
 | 
				
			||||||
        gdb_syscall_mode = GDB_SYS_DISABLED;
 | 
					
 | 
				
			||||||
        gdb_continue(s);
 | 
					        if (s->multiprocess) {
 | 
				
			||||||
 | 
					            unsigned long lpid;
 | 
				
			||||||
 | 
					            if (*p != ';') {
 | 
				
			||||||
 | 
					                put_packet(s, "E22");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (qemu_strtoul(p + 1, &p, 16, &lpid)) {
 | 
				
			||||||
 | 
					                put_packet(s, "E22");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            pid = lpid;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        process = gdb_get_process(s, pid);
 | 
				
			||||||
 | 
					        gdb_process_breakpoint_remove_all(s, process);
 | 
				
			||||||
 | 
					        process->attached = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (pid == gdb_get_cpu_pid(s, s->c_cpu)) {
 | 
				
			||||||
 | 
					            s->c_cpu = gdb_first_attached_cpu(s);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (pid == gdb_get_cpu_pid(s, s->g_cpu)) {
 | 
				
			||||||
 | 
					            s->g_cpu = gdb_first_attached_cpu(s);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (s->c_cpu == NULL) {
 | 
				
			||||||
 | 
					            /* No more process attached */
 | 
				
			||||||
 | 
					            gdb_syscall_mode = GDB_SYS_DISABLED;
 | 
				
			||||||
 | 
					            gdb_continue(s);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        put_packet(s, "OK");
 | 
					        put_packet(s, "OK");
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case 's':
 | 
					    case 's':
 | 
				
			||||||
@ -1220,12 +1572,18 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case 'H':
 | 
					    case 'H':
 | 
				
			||||||
        type = *p++;
 | 
					        type = *p++;
 | 
				
			||||||
        thread = strtoull(p, (char **)&p, 16);
 | 
					
 | 
				
			||||||
        if (thread == -1 || thread == 0) {
 | 
					        thread_kind = read_thread_id(p, &p, &pid, &tid);
 | 
				
			||||||
 | 
					        if (thread_kind == GDB_READ_THREAD_ERR) {
 | 
				
			||||||
 | 
					            put_packet(s, "E22");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (thread_kind != GDB_ONE_THREAD) {
 | 
				
			||||||
            put_packet(s, "OK");
 | 
					            put_packet(s, "OK");
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        cpu = find_cpu(thread);
 | 
					        cpu = gdb_get_cpu(s, pid, tid);
 | 
				
			||||||
        if (cpu == NULL) {
 | 
					        if (cpu == NULL) {
 | 
				
			||||||
            put_packet(s, "E22");
 | 
					            put_packet(s, "E22");
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -1245,8 +1603,12 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case 'T':
 | 
					    case 'T':
 | 
				
			||||||
        thread = strtoull(p, (char **)&p, 16);
 | 
					        thread_kind = read_thread_id(p, &p, &pid, &tid);
 | 
				
			||||||
        cpu = find_cpu(thread);
 | 
					        if (thread_kind == GDB_READ_THREAD_ERR) {
 | 
				
			||||||
 | 
					            put_packet(s, "E22");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cpu = gdb_get_cpu(s, pid, tid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (cpu != NULL) {
 | 
					        if (cpu != NULL) {
 | 
				
			||||||
            put_packet(s, "OK");
 | 
					            put_packet(s, "OK");
 | 
				
			||||||
@ -1280,31 +1642,55 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
 | 
				
			|||||||
            put_packet(s, "OK");
 | 
					            put_packet(s, "OK");
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        } else if (strcmp(p,"C") == 0) {
 | 
					        } else if (strcmp(p,"C") == 0) {
 | 
				
			||||||
            /* "Current thread" remains vague in the spec, so always return
 | 
					            /*
 | 
				
			||||||
             *  the first CPU (gdb returns the first thread). */
 | 
					             * "Current thread" remains vague in the spec, so always return
 | 
				
			||||||
            put_packet(s, "QC1");
 | 
					             * the first thread of the current process (gdb returns the
 | 
				
			||||||
 | 
					             * first thread).
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            cpu = get_first_cpu_in_process(s, gdb_get_cpu_process(s, s->g_cpu));
 | 
				
			||||||
 | 
					            snprintf(buf, sizeof(buf), "QC%s",
 | 
				
			||||||
 | 
					                     gdb_fmt_thread_id(s, cpu, thread_id, sizeof(thread_id)));
 | 
				
			||||||
 | 
					            put_packet(s, buf);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        } else if (strcmp(p,"fThreadInfo") == 0) {
 | 
					        } else if (strcmp(p,"fThreadInfo") == 0) {
 | 
				
			||||||
            s->query_cpu = first_cpu;
 | 
					            s->query_cpu = gdb_first_attached_cpu(s);
 | 
				
			||||||
            goto report_cpuinfo;
 | 
					            goto report_cpuinfo;
 | 
				
			||||||
        } else if (strcmp(p,"sThreadInfo") == 0) {
 | 
					        } else if (strcmp(p,"sThreadInfo") == 0) {
 | 
				
			||||||
        report_cpuinfo:
 | 
					        report_cpuinfo:
 | 
				
			||||||
            if (s->query_cpu) {
 | 
					            if (s->query_cpu) {
 | 
				
			||||||
                snprintf(buf, sizeof(buf), "m%x", cpu_gdb_index(s->query_cpu));
 | 
					                snprintf(buf, sizeof(buf), "m%s",
 | 
				
			||||||
 | 
					                         gdb_fmt_thread_id(s, s->query_cpu,
 | 
				
			||||||
 | 
					                                       thread_id, sizeof(thread_id)));
 | 
				
			||||||
                put_packet(s, buf);
 | 
					                put_packet(s, buf);
 | 
				
			||||||
                s->query_cpu = CPU_NEXT(s->query_cpu);
 | 
					                s->query_cpu = gdb_next_attached_cpu(s, s->query_cpu);
 | 
				
			||||||
            } else
 | 
					            } else
 | 
				
			||||||
                put_packet(s, "l");
 | 
					                put_packet(s, "l");
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        } else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) {
 | 
					        } else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) {
 | 
				
			||||||
            thread = strtoull(p+16, (char **)&p, 16);
 | 
					            if (read_thread_id(p + 16, &p, &pid, &tid) == GDB_READ_THREAD_ERR) {
 | 
				
			||||||
            cpu = find_cpu(thread);
 | 
					                put_packet(s, "E22");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            cpu = gdb_get_cpu(s, pid, tid);
 | 
				
			||||||
            if (cpu != NULL) {
 | 
					            if (cpu != NULL) {
 | 
				
			||||||
                cpu_synchronize_state(cpu);
 | 
					                cpu_synchronize_state(cpu);
 | 
				
			||||||
                /* memtohex() doubles the required space */
 | 
					
 | 
				
			||||||
                len = snprintf((char *)mem_buf, sizeof(buf) / 2,
 | 
					                if (s->multiprocess && (s->process_num > 1)) {
 | 
				
			||||||
                               "CPU#%d [%s]", cpu->cpu_index,
 | 
					                    /* Print the CPU model and name in multiprocess mode */
 | 
				
			||||||
                               cpu->halted ? "halted " : "running");
 | 
					                    ObjectClass *oc = object_get_class(OBJECT(cpu));
 | 
				
			||||||
 | 
					                    const char *cpu_model = object_class_get_name(oc);
 | 
				
			||||||
 | 
					                    char *cpu_name =
 | 
				
			||||||
 | 
					                        object_get_canonical_path_component(OBJECT(cpu));
 | 
				
			||||||
 | 
					                    len = snprintf((char *)mem_buf, sizeof(buf) / 2,
 | 
				
			||||||
 | 
					                                   "%s %s [%s]", cpu_model, cpu_name,
 | 
				
			||||||
 | 
					                                   cpu->halted ? "halted " : "running");
 | 
				
			||||||
 | 
					                    g_free(cpu_name);
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    /* memtohex() doubles the required space */
 | 
				
			||||||
 | 
					                    len = snprintf((char *)mem_buf, sizeof(buf) / 2,
 | 
				
			||||||
 | 
					                                   "CPU#%d [%s]", cpu->cpu_index,
 | 
				
			||||||
 | 
					                                   cpu->halted ? "halted " : "running");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                trace_gdbstub_op_extra_info((char *)mem_buf);
 | 
					                trace_gdbstub_op_extra_info((char *)mem_buf);
 | 
				
			||||||
                memtohex(buf, mem_buf, len);
 | 
					                memtohex(buf, mem_buf, len);
 | 
				
			||||||
                put_packet(s, buf);
 | 
					                put_packet(s, buf);
 | 
				
			||||||
@ -1346,6 +1732,12 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
 | 
				
			|||||||
            if (cc->gdb_core_xml_file != NULL) {
 | 
					            if (cc->gdb_core_xml_file != NULL) {
 | 
				
			||||||
                pstrcat(buf, sizeof(buf), ";qXfer:features:read+");
 | 
					                pstrcat(buf, sizeof(buf), ";qXfer:features:read+");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (strstr(p, "multiprocess+")) {
 | 
				
			||||||
 | 
					                s->multiprocess = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            pstrcat(buf, sizeof(buf), ";multiprocess+");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            put_packet(s, buf);
 | 
					            put_packet(s, buf);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -1353,14 +1745,15 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
 | 
				
			|||||||
            const char *xml;
 | 
					            const char *xml;
 | 
				
			||||||
            target_ulong total_len;
 | 
					            target_ulong total_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            cc = CPU_GET_CLASS(first_cpu);
 | 
					            process = gdb_get_cpu_process(s, s->g_cpu);
 | 
				
			||||||
 | 
					            cc = CPU_GET_CLASS(s->g_cpu);
 | 
				
			||||||
            if (cc->gdb_core_xml_file == NULL) {
 | 
					            if (cc->gdb_core_xml_file == NULL) {
 | 
				
			||||||
                goto unknown_command;
 | 
					                goto unknown_command;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            gdb_has_xml = true;
 | 
					            gdb_has_xml = true;
 | 
				
			||||||
            p += 19;
 | 
					            p += 19;
 | 
				
			||||||
            xml = get_feature_xml(p, &p, cc);
 | 
					            xml = get_feature_xml(s, p, &p, process);
 | 
				
			||||||
            if (!xml) {
 | 
					            if (!xml) {
 | 
				
			||||||
                snprintf(buf, sizeof(buf), "E00");
 | 
					                snprintf(buf, sizeof(buf), "E00");
 | 
				
			||||||
                put_packet(s, buf);
 | 
					                put_packet(s, buf);
 | 
				
			||||||
@ -1411,6 +1804,16 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void gdb_set_stop_cpu(CPUState *cpu)
 | 
					void gdb_set_stop_cpu(CPUState *cpu)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    GDBProcess *p = gdb_get_cpu_process(gdbserver_state, cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!p->attached) {
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * Having a stop CPU corresponding to a process that is not attached
 | 
				
			||||||
 | 
					         * confuses GDB. So we ignore the request.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    gdbserver_state->c_cpu = cpu;
 | 
					    gdbserver_state->c_cpu = cpu;
 | 
				
			||||||
    gdbserver_state->g_cpu = cpu;
 | 
					    gdbserver_state->g_cpu = cpu;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1421,6 +1824,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
 | 
				
			|||||||
    GDBState *s = gdbserver_state;
 | 
					    GDBState *s = gdbserver_state;
 | 
				
			||||||
    CPUState *cpu = s->c_cpu;
 | 
					    CPUState *cpu = s->c_cpu;
 | 
				
			||||||
    char buf[256];
 | 
					    char buf[256];
 | 
				
			||||||
 | 
					    char thread_id[16];
 | 
				
			||||||
    const char *type;
 | 
					    const char *type;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1432,6 +1836,14 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
 | 
				
			|||||||
        put_packet(s, s->syscall_buf);
 | 
					        put_packet(s, s->syscall_buf);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (cpu == NULL) {
 | 
				
			||||||
 | 
					        /* No process attached */
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gdb_fmt_thread_id(s, cpu, thread_id, sizeof(thread_id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (state) {
 | 
					    switch (state) {
 | 
				
			||||||
    case RUN_STATE_DEBUG:
 | 
					    case RUN_STATE_DEBUG:
 | 
				
			||||||
        if (cpu->watchpoint_hit) {
 | 
					        if (cpu->watchpoint_hit) {
 | 
				
			||||||
@ -1449,8 +1861,8 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
 | 
				
			|||||||
            trace_gdbstub_hit_watchpoint(type, cpu_gdb_index(cpu),
 | 
					            trace_gdbstub_hit_watchpoint(type, cpu_gdb_index(cpu),
 | 
				
			||||||
                    (target_ulong)cpu->watchpoint_hit->vaddr);
 | 
					                    (target_ulong)cpu->watchpoint_hit->vaddr);
 | 
				
			||||||
            snprintf(buf, sizeof(buf),
 | 
					            snprintf(buf, sizeof(buf),
 | 
				
			||||||
                     "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
 | 
					                     "T%02xthread:%s;%swatch:" TARGET_FMT_lx ";",
 | 
				
			||||||
                     GDB_SIGNAL_TRAP, cpu_gdb_index(cpu), type,
 | 
					                     GDB_SIGNAL_TRAP, thread_id, type,
 | 
				
			||||||
                     (target_ulong)cpu->watchpoint_hit->vaddr);
 | 
					                     (target_ulong)cpu->watchpoint_hit->vaddr);
 | 
				
			||||||
            cpu->watchpoint_hit = NULL;
 | 
					            cpu->watchpoint_hit = NULL;
 | 
				
			||||||
            goto send_packet;
 | 
					            goto send_packet;
 | 
				
			||||||
@ -1492,7 +1904,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    gdb_set_stop_cpu(cpu);
 | 
					    gdb_set_stop_cpu(cpu);
 | 
				
			||||||
    snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_gdb_index(cpu));
 | 
					    snprintf(buf, sizeof(buf), "T%02xthread:%s;", ret, thread_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
send_packet:
 | 
					send_packet:
 | 
				
			||||||
    put_packet(s, buf);
 | 
					    put_packet(s, buf);
 | 
				
			||||||
@ -1751,6 +2163,31 @@ void gdb_exit(CPUArchState *env, int code)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Create the process that will contain all the "orphan" CPUs (that are not
 | 
				
			||||||
 | 
					 * part of a CPU cluster). Note that if this process contains no CPUs, it won't
 | 
				
			||||||
 | 
					 * be attachable and thus will be invisible to the user.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void create_default_process(GDBState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GDBProcess *process;
 | 
				
			||||||
 | 
					    int max_pid = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->process_num) {
 | 
				
			||||||
 | 
					        max_pid = s->processes[s->process_num - 1].pid;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->processes = g_renew(GDBProcess, s->processes, ++s->process_num);
 | 
				
			||||||
 | 
					    process = &s->processes[s->process_num - 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* We need an available PID slot for this process */
 | 
				
			||||||
 | 
					    assert(max_pid < UINT32_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    process->pid = max_pid + 1;
 | 
				
			||||||
 | 
					    process->attached = false;
 | 
				
			||||||
 | 
					    process->target_xml[0] = '\0';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_USER_ONLY
 | 
					#ifdef CONFIG_USER_ONLY
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
gdb_handlesig(CPUState *cpu, int sig)
 | 
					gdb_handlesig(CPUState *cpu, int sig)
 | 
				
			||||||
@ -1846,8 +2283,10 @@ static bool gdb_accept(void)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s = g_malloc0(sizeof(GDBState));
 | 
					    s = g_malloc0(sizeof(GDBState));
 | 
				
			||||||
    s->c_cpu = first_cpu;
 | 
					    create_default_process(s);
 | 
				
			||||||
    s->g_cpu = first_cpu;
 | 
					    s->processes[0].attached = true;
 | 
				
			||||||
 | 
					    s->c_cpu = gdb_first_attached_cpu(s);
 | 
				
			||||||
 | 
					    s->g_cpu = s->c_cpu;
 | 
				
			||||||
    s->fd = fd;
 | 
					    s->fd = fd;
 | 
				
			||||||
    gdb_has_xml = false;
 | 
					    gdb_has_xml = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1933,8 +2372,19 @@ static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void gdb_chr_event(void *opaque, int event)
 | 
					static void gdb_chr_event(void *opaque, int event)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    GDBState *s = (GDBState *) opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (event) {
 | 
					    switch (event) {
 | 
				
			||||||
    case CHR_EVENT_OPENED:
 | 
					    case CHR_EVENT_OPENED:
 | 
				
			||||||
 | 
					        /* Start with first process attached, others detached */
 | 
				
			||||||
 | 
					        for (i = 0; i < s->process_num; i++) {
 | 
				
			||||||
 | 
					            s->processes[i].attached = !i;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        s->c_cpu = gdb_first_attached_cpu(s);
 | 
				
			||||||
 | 
					        s->g_cpu = s->c_cpu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        vm_stop(RUN_STATE_PAUSED);
 | 
					        vm_stop(RUN_STATE_PAUSED);
 | 
				
			||||||
        gdb_has_xml = false;
 | 
					        gdb_has_xml = false;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
@ -2004,6 +2454,66 @@ static const TypeInfo char_gdb_type_info = {
 | 
				
			|||||||
    .class_init = char_gdb_class_init,
 | 
					    .class_init = char_gdb_class_init,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int find_cpu_clusters(Object *child, void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (object_dynamic_cast(child, TYPE_CPU_CLUSTER)) {
 | 
				
			||||||
 | 
					        GDBState *s = (GDBState *) opaque;
 | 
				
			||||||
 | 
					        CPUClusterState *cluster = CPU_CLUSTER(child);
 | 
				
			||||||
 | 
					        GDBProcess *process;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        s->processes = g_renew(GDBProcess, s->processes, ++s->process_num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        process = &s->processes[s->process_num - 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * GDB process IDs -1 and 0 are reserved. To avoid subtle errors at
 | 
				
			||||||
 | 
					         * runtime, we enforce here that the machine does not use a cluster ID
 | 
				
			||||||
 | 
					         * that would lead to PID 0.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        assert(cluster->cluster_id != UINT32_MAX);
 | 
				
			||||||
 | 
					        process->pid = cluster->cluster_id + 1;
 | 
				
			||||||
 | 
					        process->attached = false;
 | 
				
			||||||
 | 
					        process->target_xml[0] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return object_child_foreach(child, find_cpu_clusters, opaque);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int pid_order(const void *a, const void *b)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GDBProcess *pa = (GDBProcess *) a;
 | 
				
			||||||
 | 
					    GDBProcess *pb = (GDBProcess *) b;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pa->pid < pb->pid) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    } else if (pa->pid > pb->pid) {
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void create_processes(GDBState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    object_child_foreach(object_get_root(), find_cpu_clusters, s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->processes) {
 | 
				
			||||||
 | 
					        /* Sort by PID */
 | 
				
			||||||
 | 
					        qsort(s->processes, s->process_num, sizeof(s->processes[0]), pid_order);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    create_default_process(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cleanup_processes(GDBState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    g_free(s->processes);
 | 
				
			||||||
 | 
					    s->process_num = 0;
 | 
				
			||||||
 | 
					    s->processes = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gdbserver_start(const char *device)
 | 
					int gdbserver_start(const char *device)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    trace_gdbstub_op_start(device);
 | 
					    trace_gdbstub_op_start(device);
 | 
				
			||||||
@ -2060,15 +2570,17 @@ int gdbserver_start(const char *device)
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        qemu_chr_fe_deinit(&s->chr, true);
 | 
					        qemu_chr_fe_deinit(&s->chr, true);
 | 
				
			||||||
        mon_chr = s->mon_chr;
 | 
					        mon_chr = s->mon_chr;
 | 
				
			||||||
 | 
					        cleanup_processes(s);
 | 
				
			||||||
        memset(s, 0, sizeof(GDBState));
 | 
					        memset(s, 0, sizeof(GDBState));
 | 
				
			||||||
        s->mon_chr = mon_chr;
 | 
					        s->mon_chr = mon_chr;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    s->c_cpu = first_cpu;
 | 
					
 | 
				
			||||||
    s->g_cpu = first_cpu;
 | 
					    create_processes(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (chr) {
 | 
					    if (chr) {
 | 
				
			||||||
        qemu_chr_fe_init(&s->chr, chr, &error_abort);
 | 
					        qemu_chr_fe_init(&s->chr, chr, &error_abort);
 | 
				
			||||||
        qemu_chr_fe_set_handlers(&s->chr, gdb_chr_can_receive, gdb_chr_receive,
 | 
					        qemu_chr_fe_set_handlers(&s->chr, gdb_chr_can_receive, gdb_chr_receive,
 | 
				
			||||||
                                 gdb_chr_event, NULL, NULL, NULL, true);
 | 
					                                 gdb_chr_event, NULL, s, NULL, true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    s->state = chr ? RS_IDLE : RS_INACTIVE;
 | 
					    s->state = chr ? RS_IDLE : RS_INACTIVE;
 | 
				
			||||||
    s->mon_chr = mon_chr;
 | 
					    s->mon_chr = mon_chr;
 | 
				
			||||||
 | 
				
			|||||||
@ -22,6 +22,7 @@
 | 
				
			|||||||
#include "hw/sysbus.h"
 | 
					#include "hw/sysbus.h"
 | 
				
			||||||
#include "hw/devices.h"
 | 
					#include "hw/devices.h"
 | 
				
			||||||
#include "hw/arm/allwinner-a10.h"
 | 
					#include "hw/arm/allwinner-a10.h"
 | 
				
			||||||
 | 
					#include "hw/misc/unimp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void aw_a10_init(Object *obj)
 | 
					static void aw_a10_init(Object *obj)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -85,6 +86,11 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
 | 
				
			|||||||
    sysbus_connect_irq(sysbusdev, 4, s->irq[67]);
 | 
					    sysbus_connect_irq(sysbusdev, 4, s->irq[67]);
 | 
				
			||||||
    sysbus_connect_irq(sysbusdev, 5, s->irq[68]);
 | 
					    sysbus_connect_irq(sysbusdev, 5, s->irq[68]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memory_region_init_ram(&s->sram_a, OBJECT(dev), "sram A", 48 * KiB,
 | 
				
			||||||
 | 
					                           &error_fatal);
 | 
				
			||||||
 | 
					    memory_region_add_subregion(get_system_memory(), 0x00000000, &s->sram_a);
 | 
				
			||||||
 | 
					    create_unimplemented_device("a10-sram-ctrl", 0x01c00000, 4 * KiB);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* FIXME use qdev NIC properties instead of nd_table[] */
 | 
					    /* FIXME use qdev NIC properties instead of nd_table[] */
 | 
				
			||||||
    if (nd_table[0].used) {
 | 
					    if (nd_table[0].used) {
 | 
				
			||||||
        qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC);
 | 
					        qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC);
 | 
				
			||||||
 | 
				
			|||||||
@ -285,11 +285,6 @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size)
 | 
				
			|||||||
    big_endian = 0;
 | 
					    big_endian = 0;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!kernel_filename && !qtest_enabled()) {
 | 
					 | 
				
			||||||
        error_report("Guest image must be specified (using -kernel)");
 | 
					 | 
				
			||||||
        exit(1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) {
 | 
					    if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) {
 | 
				
			||||||
        asidx = ARMASIdx_S;
 | 
					        asidx = ARMASIdx_S;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
				
			|||||||
@ -30,8 +30,9 @@
 | 
				
			|||||||
 * Documentation/arm/Booting and Documentation/arm64/booting.txt
 | 
					 * Documentation/arm/Booting and Documentation/arm64/booting.txt
 | 
				
			||||||
 * They have different preferred image load offsets from system RAM base.
 | 
					 * They have different preferred image load offsets from system RAM base.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define KERNEL_ARGS_ADDR 0x100
 | 
					#define KERNEL_ARGS_ADDR   0x100
 | 
				
			||||||
#define KERNEL_LOAD_ADDR 0x00010000
 | 
					#define KERNEL_NOLOAD_ADDR 0x02000000
 | 
				
			||||||
 | 
					#define KERNEL_LOAD_ADDR   0x00010000
 | 
				
			||||||
#define KERNEL64_LOAD_ADDR 0x00080000
 | 
					#define KERNEL64_LOAD_ADDR 0x00080000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ARM64_TEXT_OFFSET_OFFSET    8
 | 
					#define ARM64_TEXT_OFFSET_OFFSET    8
 | 
				
			||||||
@ -1082,7 +1083,8 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    entry = elf_entry;
 | 
					    entry = elf_entry;
 | 
				
			||||||
    if (kernel_size < 0) {
 | 
					    if (kernel_size < 0) {
 | 
				
			||||||
        kernel_size = load_uimage_as(info->kernel_filename, &entry, NULL,
 | 
					        uint64_t loadaddr = info->loader_start + KERNEL_NOLOAD_ADDR;
 | 
				
			||||||
 | 
					        kernel_size = load_uimage_as(info->kernel_filename, &entry, &loadaddr,
 | 
				
			||||||
                                     &is_linux, NULL, NULL, as);
 | 
					                                     &is_linux, NULL, NULL, as);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && kernel_size < 0) {
 | 
					    if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && kernel_size < 0) {
 | 
				
			||||||
 | 
				
			|||||||
@ -21,35 +21,46 @@
 | 
				
			|||||||
#include "qemu/log.h"
 | 
					#include "qemu/log.h"
 | 
				
			||||||
#include "cpu.h"
 | 
					#include "cpu.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "hw/arm/nrf51.h"
 | 
				
			||||||
#include "hw/arm/nrf51_soc.h"
 | 
					#include "hw/arm/nrf51_soc.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define IOMEM_BASE      0x40000000
 | 
					 | 
				
			||||||
#define IOMEM_SIZE      0x20000000
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define FICR_BASE       0x10000000
 | 
					 | 
				
			||||||
#define FICR_SIZE       0x000000fc
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define FLASH_BASE      0x00000000
 | 
					 | 
				
			||||||
#define SRAM_BASE       0x20000000
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define PRIVATE_BASE    0xF0000000
 | 
					 | 
				
			||||||
#define PRIVATE_SIZE    0x10000000
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * The size and base is for the NRF51822 part. If other parts
 | 
					 * The size and base is for the NRF51822 part. If other parts
 | 
				
			||||||
 * are supported in the future, add a sub-class of NRF51SoC for
 | 
					 * are supported in the future, add a sub-class of NRF51SoC for
 | 
				
			||||||
 * the specific variants
 | 
					 * the specific variants
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define NRF51822_FLASH_SIZE     (256 * 1024)
 | 
					#define NRF51822_FLASH_SIZE     (256 * NRF51_PAGE_SIZE)
 | 
				
			||||||
#define NRF51822_SRAM_SIZE      (16 * 1024)
 | 
					#define NRF51822_SRAM_SIZE      (16 * NRF51_PAGE_SIZE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define BASE_TO_IRQ(base) ((base >> 12) & 0x1F)
 | 
					#define BASE_TO_IRQ(base) ((base >> 12) & 0x1F)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint64_t clock_read(void *opaque, hwaddr addr, unsigned int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n",
 | 
				
			||||||
 | 
					                  __func__, addr, size);
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void clock_write(void *opaque, hwaddr addr, uint64_t data,
 | 
				
			||||||
 | 
					                        unsigned int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n",
 | 
				
			||||||
 | 
					                  __func__, addr, data, size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const MemoryRegionOps clock_ops = {
 | 
				
			||||||
 | 
					    .read = clock_read,
 | 
				
			||||||
 | 
					    .write = clock_write
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
 | 
					static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    NRF51State *s = NRF51_SOC(dev_soc);
 | 
					    NRF51State *s = NRF51_SOC(dev_soc);
 | 
				
			||||||
    MemoryRegion *mr;
 | 
					    MemoryRegion *mr;
 | 
				
			||||||
    Error *err = NULL;
 | 
					    Error *err = NULL;
 | 
				
			||||||
 | 
					    uint8_t i = 0;
 | 
				
			||||||
 | 
					    hwaddr base_addr = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!s->board_memory) {
 | 
					    if (!s->board_memory) {
 | 
				
			||||||
        error_setg(errp, "memory property was not set");
 | 
					        error_setg(errp, "memory property was not set");
 | 
				
			||||||
@ -76,14 +87,14 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
 | 
				
			|||||||
        error_propagate(errp, err);
 | 
					        error_propagate(errp, err);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    memory_region_add_subregion(&s->container, FLASH_BASE, &s->flash);
 | 
					    memory_region_add_subregion(&s->container, NRF51_FLASH_BASE, &s->flash);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memory_region_init_ram(&s->sram, NULL, "nrf51.sram", s->sram_size, &err);
 | 
					    memory_region_init_ram(&s->sram, NULL, "nrf51.sram", s->sram_size, &err);
 | 
				
			||||||
    if (err) {
 | 
					    if (err) {
 | 
				
			||||||
        error_propagate(errp, err);
 | 
					        error_propagate(errp, err);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    memory_region_add_subregion(&s->container, SRAM_BASE, &s->sram);
 | 
					    memory_region_add_subregion(&s->container, NRF51_SRAM_BASE, &s->sram);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* UART */
 | 
					    /* UART */
 | 
				
			||||||
    object_property_set_bool(OBJECT(&s->uart), true, "realized", &err);
 | 
					    object_property_set_bool(OBJECT(&s->uart), true, "realized", &err);
 | 
				
			||||||
@ -92,19 +103,71 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->uart), 0);
 | 
					    mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->uart), 0);
 | 
				
			||||||
    memory_region_add_subregion_overlap(&s->container, UART_BASE, mr, 0);
 | 
					    memory_region_add_subregion_overlap(&s->container, NRF51_UART_BASE, mr, 0);
 | 
				
			||||||
    sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 0,
 | 
					    sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 0,
 | 
				
			||||||
                       qdev_get_gpio_in(DEVICE(&s->cpu),
 | 
					                       qdev_get_gpio_in(DEVICE(&s->cpu),
 | 
				
			||||||
                       BASE_TO_IRQ(UART_BASE)));
 | 
					                       BASE_TO_IRQ(NRF51_UART_BASE)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    create_unimplemented_device("nrf51_soc.io", IOMEM_BASE, IOMEM_SIZE);
 | 
					    /* RNG */
 | 
				
			||||||
    create_unimplemented_device("nrf51_soc.ficr", FICR_BASE, FICR_SIZE);
 | 
					    object_property_set_bool(OBJECT(&s->rng), true, "realized", &err);
 | 
				
			||||||
 | 
					    if (err) {
 | 
				
			||||||
 | 
					        error_propagate(errp, err);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->rng), 0);
 | 
				
			||||||
 | 
					    memory_region_add_subregion_overlap(&s->container, NRF51_RNG_BASE, mr, 0);
 | 
				
			||||||
 | 
					    sysbus_connect_irq(SYS_BUS_DEVICE(&s->rng), 0,
 | 
				
			||||||
 | 
					                       qdev_get_gpio_in(DEVICE(&s->cpu),
 | 
				
			||||||
 | 
					                       BASE_TO_IRQ(NRF51_RNG_BASE)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* GPIO */
 | 
				
			||||||
 | 
					    object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err);
 | 
				
			||||||
 | 
					    if (err) {
 | 
				
			||||||
 | 
					        error_propagate(errp, err);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gpio), 0);
 | 
				
			||||||
 | 
					    memory_region_add_subregion_overlap(&s->container, NRF51_GPIO_BASE, mr, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Pass all GPIOs to the SOC layer so they are available to the board */
 | 
				
			||||||
 | 
					    qdev_pass_gpios(DEVICE(&s->gpio), dev_soc, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* TIMER */
 | 
				
			||||||
 | 
					    for (i = 0; i < NRF51_NUM_TIMERS; i++) {
 | 
				
			||||||
 | 
					        object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
 | 
				
			||||||
 | 
					        if (err) {
 | 
				
			||||||
 | 
					            error_propagate(errp, err);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        base_addr = NRF51_TIMER_BASE + i * NRF51_TIMER_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sysbus_mmio_map(SYS_BUS_DEVICE(&s->timer[i]), 0, base_addr);
 | 
				
			||||||
 | 
					        sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer[i]), 0,
 | 
				
			||||||
 | 
					                           qdev_get_gpio_in(DEVICE(&s->cpu),
 | 
				
			||||||
 | 
					                                            BASE_TO_IRQ(base_addr)));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* STUB Peripherals */
 | 
				
			||||||
 | 
					    memory_region_init_io(&s->clock, NULL, &clock_ops, NULL,
 | 
				
			||||||
 | 
					                          "nrf51_soc.clock", 0x1000);
 | 
				
			||||||
 | 
					    memory_region_add_subregion_overlap(&s->container,
 | 
				
			||||||
 | 
					                                        NRF51_IOMEM_BASE, &s->clock, -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    create_unimplemented_device("nrf51_soc.io", NRF51_IOMEM_BASE,
 | 
				
			||||||
 | 
					                                NRF51_IOMEM_SIZE);
 | 
				
			||||||
 | 
					    create_unimplemented_device("nrf51_soc.ficr", NRF51_FICR_BASE,
 | 
				
			||||||
 | 
					                                NRF51_FICR_SIZE);
 | 
				
			||||||
    create_unimplemented_device("nrf51_soc.private",
 | 
					    create_unimplemented_device("nrf51_soc.private",
 | 
				
			||||||
                                PRIVATE_BASE, PRIVATE_SIZE);
 | 
					                                NRF51_PRIVATE_BASE, NRF51_PRIVATE_SIZE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nrf51_soc_init(Object *obj)
 | 
					static void nrf51_soc_init(Object *obj)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    uint8_t i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    NRF51State *s = NRF51_SOC(obj);
 | 
					    NRF51State *s = NRF51_SOC(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memory_region_init(&s->container, obj, "nrf51-container", UINT64_MAX);
 | 
					    memory_region_init(&s->container, obj, "nrf51-container", UINT64_MAX);
 | 
				
			||||||
@ -119,6 +182,18 @@ static void nrf51_soc_init(Object *obj)
 | 
				
			|||||||
                           TYPE_NRF51_UART);
 | 
					                           TYPE_NRF51_UART);
 | 
				
			||||||
    object_property_add_alias(obj, "serial0", OBJECT(&s->uart), "chardev",
 | 
					    object_property_add_alias(obj, "serial0", OBJECT(&s->uart), "chardev",
 | 
				
			||||||
                              &error_abort);
 | 
					                              &error_abort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sysbus_init_child_obj(obj, "rng", &s->rng, sizeof(s->rng),
 | 
				
			||||||
 | 
					                           TYPE_NRF51_RNG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio),
 | 
				
			||||||
 | 
					                          TYPE_NRF51_GPIO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < NRF51_NUM_TIMERS; i++) {
 | 
				
			||||||
 | 
					        sysbus_init_child_obj(obj, "timer[*]", &s->timer[i],
 | 
				
			||||||
 | 
					                              sizeof(s->timer[i]), TYPE_NRF51_TIMER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static Property nrf51_soc_properties[] = {
 | 
					static Property nrf51_soc_properties[] = {
 | 
				
			||||||
 | 
				
			|||||||
@ -130,6 +130,7 @@ static void fdt_add_gic_nodes(VersalVirt *s)
 | 
				
			|||||||
                                 2, MM_GIC_APU_REDIST_0_SIZE);
 | 
					                                 2, MM_GIC_APU_REDIST_0_SIZE);
 | 
				
			||||||
    qemu_fdt_setprop_cell(s->fdt, nodename, "#interrupt-cells", 3);
 | 
					    qemu_fdt_setprop_cell(s->fdt, nodename, "#interrupt-cells", 3);
 | 
				
			||||||
    qemu_fdt_setprop_string(s->fdt, nodename, "compatible", "arm,gic-v3");
 | 
					    qemu_fdt_setprop_string(s->fdt, nodename, "compatible", "arm,gic-v3");
 | 
				
			||||||
 | 
					    g_free(nodename);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void fdt_add_timer_nodes(VersalVirt *s)
 | 
					static void fdt_add_timer_nodes(VersalVirt *s)
 | 
				
			||||||
@ -364,6 +365,7 @@ static void create_virtio_regions(VersalVirt *s)
 | 
				
			|||||||
        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic_irq);
 | 
					        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic_irq);
 | 
				
			||||||
        mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
 | 
					        mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
 | 
				
			||||||
        memory_region_add_subregion(&s->soc.mr_ps, base, mr);
 | 
					        memory_region_add_subregion(&s->soc.mr_ps, base, mr);
 | 
				
			||||||
 | 
					        g_free(name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < NUM_VIRTIO_TRANSPORT; i++) {
 | 
					    for (i = 0; i < NUM_VIRTIO_TRANSPORT; i++) {
 | 
				
			||||||
 | 
				
			|||||||
@ -178,12 +178,19 @@ static void xlnx_zynqmp_create_rpu(XlnxZynqMPState *s, const char *boot_cpu,
 | 
				
			|||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
    int num_rpus = MIN(smp_cpus - XLNX_ZYNQMP_NUM_APU_CPUS, XLNX_ZYNQMP_NUM_RPU_CPUS);
 | 
					    int num_rpus = MIN(smp_cpus - XLNX_ZYNQMP_NUM_APU_CPUS, XLNX_ZYNQMP_NUM_RPU_CPUS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    object_initialize_child(OBJECT(s), "rpu-cluster", &s->rpu_cluster,
 | 
				
			||||||
 | 
					                            sizeof(s->rpu_cluster), TYPE_CPU_CLUSTER,
 | 
				
			||||||
 | 
					                            &error_abort, NULL);
 | 
				
			||||||
 | 
					    qdev_prop_set_uint32(DEVICE(&s->rpu_cluster), "cluster-id", 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qdev_init_nofail(DEVICE(&s->rpu_cluster));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < num_rpus; i++) {
 | 
					    for (i = 0; i < num_rpus; i++) {
 | 
				
			||||||
        char *name;
 | 
					        char *name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        object_initialize(&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]),
 | 
					        object_initialize(&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]),
 | 
				
			||||||
                          "cortex-r5f-" TYPE_ARM_CPU);
 | 
					                          "cortex-r5f-" TYPE_ARM_CPU);
 | 
				
			||||||
        object_property_add_child(OBJECT(s), "rpu-cpu[*]",
 | 
					        object_property_add_child(OBJECT(&s->rpu_cluster), "rpu-cpu[*]",
 | 
				
			||||||
                                  OBJECT(&s->rpu_cpu[i]), &error_abort);
 | 
					                                  OBJECT(&s->rpu_cpu[i]), &error_abort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i]));
 | 
					        name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i]));
 | 
				
			||||||
@ -213,10 +220,16 @@ static void xlnx_zynqmp_init(Object *obj)
 | 
				
			|||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
    int num_apus = MIN(smp_cpus, XLNX_ZYNQMP_NUM_APU_CPUS);
 | 
					    int num_apus = MIN(smp_cpus, XLNX_ZYNQMP_NUM_APU_CPUS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    object_initialize_child(obj, "apu-cluster", &s->apu_cluster,
 | 
				
			||||||
 | 
					                            sizeof(s->apu_cluster), TYPE_CPU_CLUSTER,
 | 
				
			||||||
 | 
					                            &error_abort, NULL);
 | 
				
			||||||
 | 
					    qdev_prop_set_uint32(DEVICE(&s->apu_cluster), "cluster-id", 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < num_apus; i++) {
 | 
					    for (i = 0; i < num_apus; i++) {
 | 
				
			||||||
        object_initialize_child(obj, "apu-cpu[*]", &s->apu_cpu[i],
 | 
					        object_initialize_child(OBJECT(&s->apu_cluster), "apu-cpu[*]",
 | 
				
			||||||
                                sizeof(s->apu_cpu[i]),
 | 
					                                &s->apu_cpu[i], sizeof(s->apu_cpu[i]),
 | 
				
			||||||
                                "cortex-a53-" TYPE_ARM_CPU, &error_abort, NULL);
 | 
					                                "cortex-a53-" TYPE_ARM_CPU, &error_abort,
 | 
				
			||||||
 | 
					                                NULL);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic),
 | 
					    sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic),
 | 
				
			||||||
@ -333,6 +346,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
 | 
				
			|||||||
    qdev_prop_set_bit(DEVICE(&s->gic),
 | 
					    qdev_prop_set_bit(DEVICE(&s->gic),
 | 
				
			||||||
                      "has-virtualization-extensions", s->virt);
 | 
					                      "has-virtualization-extensions", s->virt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qdev_init_nofail(DEVICE(&s->apu_cluster));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Realize APUs before realizing the GIC. KVM requires this.  */
 | 
					    /* Realize APUs before realizing the GIC. KVM requires this.  */
 | 
				
			||||||
    for (i = 0; i < num_apus; i++) {
 | 
					    for (i = 0; i < num_apus; i++) {
 | 
				
			||||||
        char *name;
 | 
					        char *name;
 | 
				
			||||||
 | 
				
			|||||||
@ -613,13 +613,26 @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
 | 
				
			|||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (hdr->ih_type != image_type) {
 | 
					    if (hdr->ih_type != image_type) {
 | 
				
			||||||
        fprintf(stderr, "Wrong image type %d, expected %d\n", hdr->ih_type,
 | 
					        if (!(image_type == IH_TYPE_KERNEL &&
 | 
				
			||||||
                image_type);
 | 
					            hdr->ih_type == IH_TYPE_KERNEL_NOLOAD)) {
 | 
				
			||||||
        goto out;
 | 
					            fprintf(stderr, "Wrong image type %d, expected %d\n", hdr->ih_type,
 | 
				
			||||||
 | 
					                    image_type);
 | 
				
			||||||
 | 
					            goto out;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* TODO: Implement other image types.  */
 | 
					    /* TODO: Implement other image types.  */
 | 
				
			||||||
    switch (hdr->ih_type) {
 | 
					    switch (hdr->ih_type) {
 | 
				
			||||||
 | 
					    case IH_TYPE_KERNEL_NOLOAD:
 | 
				
			||||||
 | 
					        if (!loadaddr || *loadaddr == LOAD_UIMAGE_LOADADDR_INVALID) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "this image format (kernel_noload) cannot be "
 | 
				
			||||||
 | 
					                    "loaded on this machine type");
 | 
				
			||||||
 | 
					            goto out;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hdr->ih_load = *loadaddr + sizeof(*hdr);
 | 
				
			||||||
 | 
					        hdr->ih_ep += hdr->ih_load;
 | 
				
			||||||
 | 
					        /* fall through */
 | 
				
			||||||
    case IH_TYPE_KERNEL:
 | 
					    case IH_TYPE_KERNEL:
 | 
				
			||||||
        address = hdr->ih_load;
 | 
					        address = hdr->ih_load;
 | 
				
			||||||
        if (translate_fn) {
 | 
					        if (translate_fn) {
 | 
				
			||||||
 | 
				
			|||||||
@ -124,6 +124,7 @@
 | 
				
			|||||||
#define IH_TYPE_SCRIPT		6	/* Script file			*/
 | 
					#define IH_TYPE_SCRIPT		6	/* Script file			*/
 | 
				
			||||||
#define IH_TYPE_FILESYSTEM	7	/* Filesystem Image (any type)	*/
 | 
					#define IH_TYPE_FILESYSTEM	7	/* Filesystem Image (any type)	*/
 | 
				
			||||||
#define IH_TYPE_FLATDT		8	/* Binary Flat Device Tree Blob	*/
 | 
					#define IH_TYPE_FLATDT		8	/* Binary Flat Device Tree Blob	*/
 | 
				
			||||||
 | 
					#define IH_TYPE_KERNEL_NOLOAD  14	/* OS Kernel Image (noload)	*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Compression Types
 | 
					 * Compression Types
 | 
				
			||||||
 | 
				
			|||||||
@ -2,4 +2,4 @@ obj-$(CONFIG_ARM11MPCORE) += arm11mpcore.o
 | 
				
			|||||||
obj-$(CONFIG_REALVIEW) += realview_mpcore.o
 | 
					obj-$(CONFIG_REALVIEW) += realview_mpcore.o
 | 
				
			||||||
obj-$(CONFIG_A9MPCORE) += a9mpcore.o
 | 
					obj-$(CONFIG_A9MPCORE) += a9mpcore.o
 | 
				
			||||||
obj-$(CONFIG_A15MPCORE) += a15mpcore.o
 | 
					obj-$(CONFIG_A15MPCORE) += a15mpcore.o
 | 
				
			||||||
common-obj-y += core.o
 | 
					common-obj-y += core.o cluster.o
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										50
									
								
								hw/cpu/cluster.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								hw/cpu/cluster.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU CPU cluster
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2018 GreenSocs SAS
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU General Public License
 | 
				
			||||||
 | 
					 * as published by the Free Software Foundation; either version 2
 | 
				
			||||||
 | 
					 * of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 * along with this program; if not, see
 | 
				
			||||||
 | 
					 * <http://www.gnu.org/licenses/gpl-2.0.html>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qemu/osdep.h"
 | 
				
			||||||
 | 
					#include "hw/cpu/cluster.h"
 | 
				
			||||||
 | 
					#include "qapi/error.h"
 | 
				
			||||||
 | 
					#include "qemu/module.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static Property cpu_cluster_properties[] = {
 | 
				
			||||||
 | 
					    DEFINE_PROP_UINT32("cluster-id", CPUClusterState, cluster_id, 0),
 | 
				
			||||||
 | 
					    DEFINE_PROP_END_OF_LIST()
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cpu_cluster_class_init(ObjectClass *klass, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DeviceClass *dc = DEVICE_CLASS(klass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dc->props = cpu_cluster_properties;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const TypeInfo cpu_cluster_type_info = {
 | 
				
			||||||
 | 
					    .name = TYPE_CPU_CLUSTER,
 | 
				
			||||||
 | 
					    .parent = TYPE_DEVICE,
 | 
				
			||||||
 | 
					    .instance_size = sizeof(CPUClusterState),
 | 
				
			||||||
 | 
					    .class_init = cpu_cluster_class_init,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cpu_cluster_register_types(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type_register_static(&cpu_cluster_type_info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type_init(cpu_cluster_register_types)
 | 
				
			||||||
@ -8,3 +8,4 @@ common-obj-$(CONFIG_GPIO_KEY) += gpio_key.o
 | 
				
			|||||||
obj-$(CONFIG_OMAP) += omap_gpio.o
 | 
					obj-$(CONFIG_OMAP) += omap_gpio.o
 | 
				
			||||||
obj-$(CONFIG_IMX) += imx_gpio.o
 | 
					obj-$(CONFIG_IMX) += imx_gpio.o
 | 
				
			||||||
obj-$(CONFIG_RASPI) += bcm2835_gpio.o
 | 
					obj-$(CONFIG_RASPI) += bcm2835_gpio.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_NRF51_SOC) += nrf51_gpio.o
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										300
									
								
								hw/gpio/nrf51_gpio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								hw/gpio/nrf51_gpio.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,300 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * nRF51 System-on-Chip general purpose input/output register definition
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
 | 
				
			||||||
 | 
					 * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This code is licensed under the GPL version 2 or later.  See
 | 
				
			||||||
 | 
					 * the COPYING file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qemu/osdep.h"
 | 
				
			||||||
 | 
					#include "qemu/log.h"
 | 
				
			||||||
 | 
					#include "hw/gpio/nrf51_gpio.h"
 | 
				
			||||||
 | 
					#include "trace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Check if the output driver is connected to the direction switch
 | 
				
			||||||
 | 
					 * given the current configuration and logic level.
 | 
				
			||||||
 | 
					 * It is not differentiated between standard and "high"(-power) drive modes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static bool is_connected(uint32_t config, uint32_t level)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    bool state;
 | 
				
			||||||
 | 
					    uint32_t drive_config = extract32(config, 8, 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (drive_config) {
 | 
				
			||||||
 | 
					    case 0 ... 3:
 | 
				
			||||||
 | 
					        state = true;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 4 ... 5:
 | 
				
			||||||
 | 
					        state = level != 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 6 ... 7:
 | 
				
			||||||
 | 
					        state = level == 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        g_assert_not_reached();
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return state;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void update_output_irq(NRF51GPIOState *s, size_t i,
 | 
				
			||||||
 | 
					                              bool connected, bool level)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int64_t irq_level = connected ? level : -1;
 | 
				
			||||||
 | 
					    bool old_connected = extract32(s->old_out_connected, i, 1);
 | 
				
			||||||
 | 
					    bool old_level = extract32(s->old_out, i, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((old_connected != connected) || (old_level != level)) {
 | 
				
			||||||
 | 
					        qemu_set_irq(s->output[i], irq_level);
 | 
				
			||||||
 | 
					        trace_nrf51_gpio_update_output_irq(i, irq_level);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->old_out = deposit32(s->old_out, i, 1, level);
 | 
				
			||||||
 | 
					    s->old_out_connected = deposit32(s->old_out_connected, i, 1, connected);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void update_state(NRF51GPIOState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint32_t pull;
 | 
				
			||||||
 | 
					    size_t i;
 | 
				
			||||||
 | 
					    bool connected_out, dir, connected_in, out, input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < NRF51_GPIO_PINS; i++) {
 | 
				
			||||||
 | 
					        pull = extract32(s->cnf[i], 2, 2);
 | 
				
			||||||
 | 
					        dir = extract32(s->cnf[i], 0, 1);
 | 
				
			||||||
 | 
					        connected_in = extract32(s->in_mask, i, 1);
 | 
				
			||||||
 | 
					        out = extract32(s->out, i, 1);
 | 
				
			||||||
 | 
					        input = !extract32(s->cnf[i], 1, 1);
 | 
				
			||||||
 | 
					        connected_out = is_connected(s->cnf[i], out) && dir;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        update_output_irq(s, i, connected_out, out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Pin both driven externally and internally */
 | 
				
			||||||
 | 
					        if (connected_out && connected_in) {
 | 
				
			||||||
 | 
					            qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * Input buffer disconnected from internal/external drives, so
 | 
				
			||||||
 | 
					         * pull-up/pull-down becomes relevant
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        if (!input || (input && !connected_in && !connected_out)) {
 | 
				
			||||||
 | 
					            if (pull == NRF51_GPIO_PULLDOWN) {
 | 
				
			||||||
 | 
					                s->in = deposit32(s->in, i, 1, 0);
 | 
				
			||||||
 | 
					            } else if (pull == NRF51_GPIO_PULLUP) {
 | 
				
			||||||
 | 
					                s->in = deposit32(s->in, i, 1, 1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Self stimulation through internal output driver */
 | 
				
			||||||
 | 
					        if (connected_out && !connected_in && input) {
 | 
				
			||||||
 | 
					            s->in = deposit32(s->in, i, 1, out);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Direction is exposed in both the DIR register and the DIR bit
 | 
				
			||||||
 | 
					 * of each PINs CNF configuration register. Reflect bits for pins in DIR
 | 
				
			||||||
 | 
					 * to individual pin configuration registers.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void reflect_dir_bit_in_cnf(NRF51GPIOState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t value = s->dir;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < NRF51_GPIO_PINS; i++) {
 | 
				
			||||||
 | 
					        s->cnf[i] = (s->cnf[i] & ~(1UL)) | ((value >> i) & 0x01);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint64_t nrf51_gpio_read(void *opaque, hwaddr offset, unsigned int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51GPIOState *s = NRF51_GPIO(opaque);
 | 
				
			||||||
 | 
					    uint64_t r = 0;
 | 
				
			||||||
 | 
					    size_t idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (offset) {
 | 
				
			||||||
 | 
					    case NRF51_GPIO_REG_OUT ... NRF51_GPIO_REG_OUTCLR:
 | 
				
			||||||
 | 
					        r = s->out;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case NRF51_GPIO_REG_IN:
 | 
				
			||||||
 | 
					        r = s->in;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case NRF51_GPIO_REG_DIR ... NRF51_GPIO_REG_DIRCLR:
 | 
				
			||||||
 | 
					        r = s->dir;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case NRF51_GPIO_REG_CNF_START ... NRF51_GPIO_REG_CNF_END:
 | 
				
			||||||
 | 
					        idx = (offset - NRF51_GPIO_REG_CNF_START) / 4;
 | 
				
			||||||
 | 
					        r = s->cnf[idx];
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        qemu_log_mask(LOG_GUEST_ERROR,
 | 
				
			||||||
 | 
					                "%s: bad read offset 0x%" HWADDR_PRIx "\n",
 | 
				
			||||||
 | 
					                      __func__, offset);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    trace_nrf51_gpio_read(offset, r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_gpio_write(void *opaque, hwaddr offset,
 | 
				
			||||||
 | 
					                       uint64_t value, unsigned int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51GPIOState *s = NRF51_GPIO(opaque);
 | 
				
			||||||
 | 
					    size_t idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    trace_nrf51_gpio_write(offset, value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (offset) {
 | 
				
			||||||
 | 
					    case NRF51_GPIO_REG_OUT:
 | 
				
			||||||
 | 
					        s->out = value;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case NRF51_GPIO_REG_OUTSET:
 | 
				
			||||||
 | 
					        s->out |= value;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case NRF51_GPIO_REG_OUTCLR:
 | 
				
			||||||
 | 
					        s->out &= ~value;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case NRF51_GPIO_REG_DIR:
 | 
				
			||||||
 | 
					        s->dir = value;
 | 
				
			||||||
 | 
					        reflect_dir_bit_in_cnf(s);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case NRF51_GPIO_REG_DIRSET:
 | 
				
			||||||
 | 
					        s->dir |= value;
 | 
				
			||||||
 | 
					        reflect_dir_bit_in_cnf(s);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case NRF51_GPIO_REG_DIRCLR:
 | 
				
			||||||
 | 
					        s->dir &= ~value;
 | 
				
			||||||
 | 
					        reflect_dir_bit_in_cnf(s);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case NRF51_GPIO_REG_CNF_START ... NRF51_GPIO_REG_CNF_END:
 | 
				
			||||||
 | 
					        idx = (offset - NRF51_GPIO_REG_CNF_START) / 4;
 | 
				
			||||||
 | 
					        s->cnf[idx] = value;
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * direction is exposed in both the DIR register and the DIR bit
 | 
				
			||||||
 | 
					         * of each PINs CNF configuration register.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        s->dir = (s->dir & ~(1UL << idx)) | ((value & 0x01) << idx);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        qemu_log_mask(LOG_GUEST_ERROR,
 | 
				
			||||||
 | 
					                      "%s: bad write offset 0x%" HWADDR_PRIx "\n",
 | 
				
			||||||
 | 
					                      __func__, offset);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    update_state(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const MemoryRegionOps gpio_ops = {
 | 
				
			||||||
 | 
					    .read =  nrf51_gpio_read,
 | 
				
			||||||
 | 
					    .write = nrf51_gpio_write,
 | 
				
			||||||
 | 
					    .endianness = DEVICE_LITTLE_ENDIAN,
 | 
				
			||||||
 | 
					    .impl.min_access_size = 4,
 | 
				
			||||||
 | 
					    .impl.max_access_size = 4,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_gpio_set(void *opaque, int line, int value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51GPIOState *s = NRF51_GPIO(opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    trace_nrf51_gpio_set(line, value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(line >= 0 && line < NRF51_GPIO_PINS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->in_mask = deposit32(s->in_mask, line, 1, value >= 0);
 | 
				
			||||||
 | 
					    if (value >= 0) {
 | 
				
			||||||
 | 
					        s->in = deposit32(s->in, line, 1, value != 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    update_state(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_gpio_reset(DeviceState *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51GPIOState *s = NRF51_GPIO(dev);
 | 
				
			||||||
 | 
					    size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->out = 0;
 | 
				
			||||||
 | 
					    s->old_out = 0;
 | 
				
			||||||
 | 
					    s->old_out_connected = 0;
 | 
				
			||||||
 | 
					    s->in = 0;
 | 
				
			||||||
 | 
					    s->in_mask = 0;
 | 
				
			||||||
 | 
					    s->dir = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < NRF51_GPIO_PINS; i++) {
 | 
				
			||||||
 | 
					        s->cnf[i] = 0x00000002;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const VMStateDescription vmstate_nrf51_gpio = {
 | 
				
			||||||
 | 
					    .name = TYPE_NRF51_GPIO,
 | 
				
			||||||
 | 
					    .version_id = 1,
 | 
				
			||||||
 | 
					    .minimum_version_id = 1,
 | 
				
			||||||
 | 
					    .fields = (VMStateField[]) {
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(out, NRF51GPIOState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(in, NRF51GPIOState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(in_mask, NRF51GPIOState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(dir, NRF51GPIOState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32_ARRAY(cnf, NRF51GPIOState, NRF51_GPIO_PINS),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(old_out, NRF51GPIOState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(old_out_connected, NRF51GPIOState),
 | 
				
			||||||
 | 
					        VMSTATE_END_OF_LIST()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_gpio_init(Object *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51GPIOState *s = NRF51_GPIO(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memory_region_init_io(&s->mmio, obj, &gpio_ops, s,
 | 
				
			||||||
 | 
					            TYPE_NRF51_GPIO, NRF51_GPIO_SIZE);
 | 
				
			||||||
 | 
					    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qdev_init_gpio_in(DEVICE(s), nrf51_gpio_set, NRF51_GPIO_PINS);
 | 
				
			||||||
 | 
					    qdev_init_gpio_out(DEVICE(s), s->output, NRF51_GPIO_PINS);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_gpio_class_init(ObjectClass *klass, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DeviceClass *dc = DEVICE_CLASS(klass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dc->vmsd = &vmstate_nrf51_gpio;
 | 
				
			||||||
 | 
					    dc->reset = nrf51_gpio_reset;
 | 
				
			||||||
 | 
					    dc->desc = "nRF51 GPIO";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const TypeInfo nrf51_gpio_info = {
 | 
				
			||||||
 | 
					    .name = TYPE_NRF51_GPIO,
 | 
				
			||||||
 | 
					    .parent = TYPE_SYS_BUS_DEVICE,
 | 
				
			||||||
 | 
					    .instance_size = sizeof(NRF51GPIOState),
 | 
				
			||||||
 | 
					    .instance_init = nrf51_gpio_init,
 | 
				
			||||||
 | 
					    .class_init = nrf51_gpio_class_init
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_gpio_register_types(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type_register_static(&nrf51_gpio_info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type_init(nrf51_gpio_register_types)
 | 
				
			||||||
							
								
								
									
										7
									
								
								hw/gpio/trace-events
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								hw/gpio/trace-events
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					# See docs/devel/tracing.txt for syntax documentation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# hw/gpio/nrf51_gpio.c
 | 
				
			||||||
 | 
					nrf51_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
 | 
				
			||||||
 | 
					nrf51_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
 | 
				
			||||||
 | 
					nrf51_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
 | 
				
			||||||
 | 
					nrf51_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
 | 
				
			||||||
@ -156,7 +156,7 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        /* If it wasn't an ELF image, try an u-boot image.  */
 | 
					        /* If it wasn't an ELF image, try an u-boot image.  */
 | 
				
			||||||
        if (kernel_size < 0) {
 | 
					        if (kernel_size < 0) {
 | 
				
			||||||
            hwaddr uentry, loadaddr;
 | 
					            hwaddr uentry, loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0,
 | 
					            kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0,
 | 
				
			||||||
                                      NULL, NULL);
 | 
					                                      NULL, NULL);
 | 
				
			||||||
 | 
				
			|||||||
@ -74,3 +74,4 @@ obj-$(CONFIG_PVPANIC) += pvpanic.o
 | 
				
			|||||||
obj-$(CONFIG_AUX) += auxbus.o
 | 
					obj-$(CONFIG_AUX) += auxbus.o
 | 
				
			||||||
obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
 | 
					obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
 | 
				
			||||||
obj-$(CONFIG_MSF2) += msf2-sysreg.o
 | 
					obj-$(CONFIG_MSF2) += msf2-sysreg.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										262
									
								
								hw/misc/nrf51_rng.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								hw/misc/nrf51_rng.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,262 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * nRF51 Random Number Generator
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.1.pdf
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This code is licensed under the GPL version 2 or later.  See
 | 
				
			||||||
 | 
					 * the COPYING file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qemu/osdep.h"
 | 
				
			||||||
 | 
					#include "qemu/log.h"
 | 
				
			||||||
 | 
					#include "qapi/error.h"
 | 
				
			||||||
 | 
					#include "hw/arm/nrf51.h"
 | 
				
			||||||
 | 
					#include "hw/misc/nrf51_rng.h"
 | 
				
			||||||
 | 
					#include "crypto/random.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void update_irq(NRF51RNGState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    bool irq = s->interrupt_enabled && s->event_valrdy;
 | 
				
			||||||
 | 
					    qemu_set_irq(s->irq, irq);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint64_t rng_read(void *opaque, hwaddr offset, unsigned int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51RNGState *s = NRF51_RNG(opaque);
 | 
				
			||||||
 | 
					    uint64_t r = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (offset) {
 | 
				
			||||||
 | 
					    case NRF51_RNG_EVENT_VALRDY:
 | 
				
			||||||
 | 
					        r = s->event_valrdy;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_RNG_REG_SHORTS:
 | 
				
			||||||
 | 
					        r = s->shortcut_stop_on_valrdy;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_RNG_REG_INTEN:
 | 
				
			||||||
 | 
					    case NRF51_RNG_REG_INTENSET:
 | 
				
			||||||
 | 
					    case NRF51_RNG_REG_INTENCLR:
 | 
				
			||||||
 | 
					        r = s->interrupt_enabled;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_RNG_REG_CONFIG:
 | 
				
			||||||
 | 
					        r = s->filter_enabled;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_RNG_REG_VALUE:
 | 
				
			||||||
 | 
					        r = s->value;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        qemu_log_mask(LOG_GUEST_ERROR,
 | 
				
			||||||
 | 
					                      "%s: bad read offset 0x%" HWADDR_PRIx "\n",
 | 
				
			||||||
 | 
					                      __func__, offset);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int64_t calc_next_timeout(NRF51RNGState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int64_t timeout = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
 | 
				
			||||||
 | 
					    if (s->filter_enabled) {
 | 
				
			||||||
 | 
					        timeout += s->period_filtered_us;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        timeout += s->period_unfiltered_us;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return timeout;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void rng_update_timer(NRF51RNGState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (s->active) {
 | 
				
			||||||
 | 
					        timer_mod(&s->timer, calc_next_timeout(s));
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        timer_del(&s->timer);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void rng_write(void *opaque, hwaddr offset,
 | 
				
			||||||
 | 
					                       uint64_t value, unsigned int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51RNGState *s = NRF51_RNG(opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (offset) {
 | 
				
			||||||
 | 
					    case NRF51_RNG_TASK_START:
 | 
				
			||||||
 | 
					        if (value == NRF51_TRIGGER_TASK) {
 | 
				
			||||||
 | 
					            s->active = 1;
 | 
				
			||||||
 | 
					            rng_update_timer(s);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_RNG_TASK_STOP:
 | 
				
			||||||
 | 
					        if (value == NRF51_TRIGGER_TASK) {
 | 
				
			||||||
 | 
					            s->active = 0;
 | 
				
			||||||
 | 
					            rng_update_timer(s);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_RNG_EVENT_VALRDY:
 | 
				
			||||||
 | 
					        if (value == NRF51_EVENT_CLEAR) {
 | 
				
			||||||
 | 
					            s->event_valrdy = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_RNG_REG_SHORTS:
 | 
				
			||||||
 | 
					        s->shortcut_stop_on_valrdy =
 | 
				
			||||||
 | 
					                (value & BIT_MASK(NRF51_RNG_REG_SHORTS_VALRDY_STOP)) ? 1 : 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_RNG_REG_INTEN:
 | 
				
			||||||
 | 
					        s->interrupt_enabled =
 | 
				
			||||||
 | 
					                (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) ? 1 : 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_RNG_REG_INTENSET:
 | 
				
			||||||
 | 
					        if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
 | 
				
			||||||
 | 
					            s->interrupt_enabled = 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_RNG_REG_INTENCLR:
 | 
				
			||||||
 | 
					        if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
 | 
				
			||||||
 | 
					            s->interrupt_enabled = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_RNG_REG_CONFIG:
 | 
				
			||||||
 | 
					        s->filter_enabled =
 | 
				
			||||||
 | 
					                      (value & BIT_MASK(NRF51_RNG_REG_CONFIG_DECEN)) ? 1 : 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        qemu_log_mask(LOG_GUEST_ERROR,
 | 
				
			||||||
 | 
					                      "%s: bad write offset 0x%" HWADDR_PRIx "\n",
 | 
				
			||||||
 | 
					                      __func__, offset);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    update_irq(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const MemoryRegionOps rng_ops = {
 | 
				
			||||||
 | 
					    .read =  rng_read,
 | 
				
			||||||
 | 
					    .write = rng_write,
 | 
				
			||||||
 | 
					    .endianness = DEVICE_LITTLE_ENDIAN,
 | 
				
			||||||
 | 
					    .impl.min_access_size = 4,
 | 
				
			||||||
 | 
					    .impl.max_access_size = 4
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_rng_timer_expire(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51RNGState *s = NRF51_RNG(opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qcrypto_random_bytes(&s->value, 1, &error_abort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->event_valrdy = 1;
 | 
				
			||||||
 | 
					    qemu_set_irq(s->eep_valrdy, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->shortcut_stop_on_valrdy) {
 | 
				
			||||||
 | 
					        s->active = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rng_update_timer(s);
 | 
				
			||||||
 | 
					    update_irq(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_rng_tep_start(void *opaque, int n, int level)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51RNGState *s = NRF51_RNG(opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (level) {
 | 
				
			||||||
 | 
					        s->active = 1;
 | 
				
			||||||
 | 
					        rng_update_timer(s);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_rng_tep_stop(void *opaque, int n, int level)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51RNGState *s = NRF51_RNG(opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (level) {
 | 
				
			||||||
 | 
					        s->active = 0;
 | 
				
			||||||
 | 
					        rng_update_timer(s);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_rng_init(Object *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51RNGState *s = NRF51_RNG(obj);
 | 
				
			||||||
 | 
					    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memory_region_init_io(&s->mmio, obj, &rng_ops, s,
 | 
				
			||||||
 | 
					            TYPE_NRF51_RNG, NRF51_RNG_SIZE);
 | 
				
			||||||
 | 
					    sysbus_init_mmio(sbd, &s->mmio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    timer_init_us(&s->timer, QEMU_CLOCK_VIRTUAL, nrf51_rng_timer_expire, s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sysbus_init_irq(sbd, &s->irq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Tasks */
 | 
				
			||||||
 | 
					    qdev_init_gpio_in_named(DEVICE(s), nrf51_rng_tep_start, "tep_start", 1);
 | 
				
			||||||
 | 
					    qdev_init_gpio_in_named(DEVICE(s), nrf51_rng_tep_stop, "tep_stop", 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Events */
 | 
				
			||||||
 | 
					    qdev_init_gpio_out_named(DEVICE(s), &s->eep_valrdy, "eep_valrdy", 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_rng_reset(DeviceState *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51RNGState *s = NRF51_RNG(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->value = 0;
 | 
				
			||||||
 | 
					    s->active = 0;
 | 
				
			||||||
 | 
					    s->event_valrdy = 0;
 | 
				
			||||||
 | 
					    s->shortcut_stop_on_valrdy = 0;
 | 
				
			||||||
 | 
					    s->interrupt_enabled = 0;
 | 
				
			||||||
 | 
					    s->filter_enabled = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rng_update_timer(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static Property nrf51_rng_properties[] = {
 | 
				
			||||||
 | 
					    DEFINE_PROP_UINT16("period_unfiltered_us", NRF51RNGState,
 | 
				
			||||||
 | 
					            period_unfiltered_us, 167),
 | 
				
			||||||
 | 
					    DEFINE_PROP_UINT16("period_filtered_us", NRF51RNGState,
 | 
				
			||||||
 | 
					            period_filtered_us, 660),
 | 
				
			||||||
 | 
					    DEFINE_PROP_END_OF_LIST(),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const VMStateDescription vmstate_rng = {
 | 
				
			||||||
 | 
					    .name = "nrf51_soc.rng",
 | 
				
			||||||
 | 
					    .version_id = 1,
 | 
				
			||||||
 | 
					    .minimum_version_id = 1,
 | 
				
			||||||
 | 
					    .fields = (VMStateField[]) {
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(active, NRF51RNGState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(event_valrdy, NRF51RNGState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(shortcut_stop_on_valrdy, NRF51RNGState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(interrupt_enabled, NRF51RNGState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(filter_enabled, NRF51RNGState),
 | 
				
			||||||
 | 
					        VMSTATE_END_OF_LIST()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_rng_class_init(ObjectClass *klass, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DeviceClass *dc = DEVICE_CLASS(klass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dc->props = nrf51_rng_properties;
 | 
				
			||||||
 | 
					    dc->vmsd = &vmstate_rng;
 | 
				
			||||||
 | 
					    dc->reset = nrf51_rng_reset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const TypeInfo nrf51_rng_info = {
 | 
				
			||||||
 | 
					    .name = TYPE_NRF51_RNG,
 | 
				
			||||||
 | 
					    .parent = TYPE_SYS_BUS_DEVICE,
 | 
				
			||||||
 | 
					    .instance_size = sizeof(NRF51RNGState),
 | 
				
			||||||
 | 
					    .instance_init = nrf51_rng_init,
 | 
				
			||||||
 | 
					    .class_init = nrf51_rng_class_init
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_rng_register_types(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type_register_static(&nrf51_rng_info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type_init(nrf51_rng_register_types)
 | 
				
			||||||
@ -150,7 +150,7 @@ static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr,
 | 
				
			|||||||
        r = s->ctrl;
 | 
					        r = s->ctrl;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case A_BLK_MAX:
 | 
					    case A_BLK_MAX:
 | 
				
			||||||
        r = s->blk_max;
 | 
					        r = s->blk_max - 1;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case A_BLK_CFG:
 | 
					    case A_BLK_CFG:
 | 
				
			||||||
        /* We are never in "init in progress state", so this just indicates
 | 
					        /* We are never in "init in progress state", so this just indicates
 | 
				
			||||||
 | 
				
			|||||||
@ -161,7 +161,7 @@ void nios2_load_kernel(Nios2CPU *cpu, hwaddr ddr_base,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        /* If it wasn't an ELF image, try an u-boot image. */
 | 
					        /* If it wasn't an ELF image, try an u-boot image. */
 | 
				
			||||||
        if (kernel_size < 0) {
 | 
					        if (kernel_size < 0) {
 | 
				
			||||||
            hwaddr uentry, loadaddr;
 | 
					            hwaddr uentry, loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0,
 | 
					            kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0,
 | 
				
			||||||
                                      NULL, NULL);
 | 
					                                      NULL, NULL);
 | 
				
			||||||
 | 
				
			|||||||
@ -995,6 +995,7 @@ void ppce500_init(MachineState *machine)
 | 
				
			|||||||
         * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
 | 
					         * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
 | 
				
			||||||
         * ePAPR compliant kernel
 | 
					         * ePAPR compliant kernel
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
 | 
					        loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
 | 
				
			||||||
        payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
 | 
					        payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
 | 
				
			||||||
                                   NULL, NULL);
 | 
					                                   NULL, NULL);
 | 
				
			||||||
        if (payload_size < 0) {
 | 
					        if (payload_size < 0) {
 | 
				
			||||||
 | 
				
			|||||||
@ -179,7 +179,7 @@ static void bamboo_init(MachineState *machine)
 | 
				
			|||||||
    CPUPPCState *env;
 | 
					    CPUPPCState *env;
 | 
				
			||||||
    uint64_t elf_entry;
 | 
					    uint64_t elf_entry;
 | 
				
			||||||
    uint64_t elf_lowaddr;
 | 
					    uint64_t elf_lowaddr;
 | 
				
			||||||
    hwaddr loadaddr = 0;
 | 
					    hwaddr loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
 | 
				
			||||||
    target_long initrd_size = 0;
 | 
					    target_long initrd_size = 0;
 | 
				
			||||||
    DeviceState *dev;
 | 
					    DeviceState *dev;
 | 
				
			||||||
    int success;
 | 
					    int success;
 | 
				
			||||||
 | 
				
			|||||||
@ -402,7 +402,7 @@ static void sam460ex_init(MachineState *machine)
 | 
				
			|||||||
    CPUPPCState *env;
 | 
					    CPUPPCState *env;
 | 
				
			||||||
    PPC4xxI2CState *i2c[2];
 | 
					    PPC4xxI2CState *i2c[2];
 | 
				
			||||||
    hwaddr entry = UBOOT_ENTRY;
 | 
					    hwaddr entry = UBOOT_ENTRY;
 | 
				
			||||||
    hwaddr loadaddr = 0;
 | 
					    hwaddr loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
 | 
				
			||||||
    target_long initrd_size = 0;
 | 
					    target_long initrd_size = 0;
 | 
				
			||||||
    DeviceState *dev;
 | 
					    DeviceState *dev;
 | 
				
			||||||
    SysBusDevice *sbdev;
 | 
					    SysBusDevice *sbdev;
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,7 @@ common-obj-$(CONFIG_IMX) += imx_gpt.o
 | 
				
			|||||||
common-obj-$(CONFIG_LM32) += lm32_timer.o
 | 
					common-obj-$(CONFIG_LM32) += lm32_timer.o
 | 
				
			||||||
common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
 | 
					common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
 | 
				
			||||||
common-obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp-rtc.o
 | 
					common-obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp-rtc.o
 | 
				
			||||||
 | 
					common-obj-$(CONFIG_NRF51_SOC) += nrf51_timer.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
 | 
					obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
 | 
				
			||||||
obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o
 | 
					obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										393
									
								
								hw/timer/nrf51_timer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										393
									
								
								hw/timer/nrf51_timer.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,393 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * nRF51 System-on-Chip Timer peripheral
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
 | 
				
			||||||
 | 
					 * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
 | 
				
			||||||
 | 
					 * Copyright (c) 2019 Red Hat, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This code is licensed under the GPL version 2 or later.  See
 | 
				
			||||||
 | 
					 * the COPYING file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qemu/osdep.h"
 | 
				
			||||||
 | 
					#include "qemu/log.h"
 | 
				
			||||||
 | 
					#include "hw/arm/nrf51.h"
 | 
				
			||||||
 | 
					#include "hw/timer/nrf51_timer.h"
 | 
				
			||||||
 | 
					#include "trace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TIMER_CLK_FREQ 16000000UL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint32_t const bitwidths[] = {16, 8, 24, 32};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint32_t ns_to_ticks(NRF51TimerState *s, int64_t ns)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint32_t freq = TIMER_CLK_FREQ >> s->prescaler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return muldiv64(ns, freq, NANOSECONDS_PER_SECOND);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int64_t ticks_to_ns(NRF51TimerState *s, uint32_t ticks)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint32_t freq = TIMER_CLK_FREQ >> s->prescaler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return muldiv64(ticks, NANOSECONDS_PER_SECOND, freq);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns number of ticks since last call */
 | 
				
			||||||
 | 
					static uint32_t update_counter(NRF51TimerState *s, int64_t now)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint32_t ticks = ns_to_ticks(s, now - s->update_counter_ns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->counter = (s->counter + ticks) % BIT(bitwidths[s->bitmode]);
 | 
				
			||||||
 | 
					    s->update_counter_ns = now;
 | 
				
			||||||
 | 
					    return ticks;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Assumes s->counter is up-to-date */
 | 
				
			||||||
 | 
					static void rearm_timer(NRF51TimerState *s, int64_t now)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int64_t min_ns = INT64_MAX;
 | 
				
			||||||
 | 
					    size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
 | 
				
			||||||
 | 
					        int64_t delta_ns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (s->events_compare[i]) {
 | 
				
			||||||
 | 
					            continue; /* already expired, ignore it for now */
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (s->cc[i] <= s->counter) {
 | 
				
			||||||
 | 
					            delta_ns = ticks_to_ns(s, BIT(bitwidths[s->bitmode]) -
 | 
				
			||||||
 | 
					                                      s->counter + s->cc[i]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            delta_ns = ticks_to_ns(s, s->cc[i] - s->counter);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (delta_ns < min_ns) {
 | 
				
			||||||
 | 
					            min_ns = delta_ns;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (min_ns != INT64_MAX) {
 | 
				
			||||||
 | 
					        timer_mod_ns(&s->timer, now + min_ns);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void update_irq(NRF51TimerState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    bool flag = false;
 | 
				
			||||||
 | 
					    size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
 | 
				
			||||||
 | 
					        flag |= s->events_compare[i] && extract32(s->inten, 16 + i, 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    qemu_set_irq(s->irq, flag);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void timer_expire(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51TimerState *s = NRF51_TIMER(opaque);
 | 
				
			||||||
 | 
					    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 | 
				
			||||||
 | 
					    uint32_t cc_remaining[NRF51_TIMER_REG_COUNT];
 | 
				
			||||||
 | 
					    bool should_stop = false;
 | 
				
			||||||
 | 
					    uint32_t ticks;
 | 
				
			||||||
 | 
					    size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
 | 
				
			||||||
 | 
					        if (s->cc[i] > s->counter) {
 | 
				
			||||||
 | 
					            cc_remaining[i] = s->cc[i] - s->counter;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            cc_remaining[i] = BIT(bitwidths[s->bitmode]) -
 | 
				
			||||||
 | 
					                              s->counter + s->cc[i];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ticks = update_counter(s, now);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
 | 
				
			||||||
 | 
					        if (cc_remaining[i] <= ticks) {
 | 
				
			||||||
 | 
					            s->events_compare[i] = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (s->shorts & BIT(i)) {
 | 
				
			||||||
 | 
					                s->timer_start_ns = now;
 | 
				
			||||||
 | 
					                s->update_counter_ns = s->timer_start_ns;
 | 
				
			||||||
 | 
					                s->counter = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            should_stop |= s->shorts & BIT(i + 8);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    update_irq(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (should_stop) {
 | 
				
			||||||
 | 
					        s->running = false;
 | 
				
			||||||
 | 
					        timer_del(&s->timer);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        rearm_timer(s, now);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void counter_compare(NRF51TimerState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint32_t counter = s->counter;
 | 
				
			||||||
 | 
					    size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
 | 
				
			||||||
 | 
					        if (counter == s->cc[i]) {
 | 
				
			||||||
 | 
					            s->events_compare[i] = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (s->shorts & BIT(i)) {
 | 
				
			||||||
 | 
					                s->counter = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint64_t nrf51_timer_read(void *opaque, hwaddr offset, unsigned int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51TimerState *s = NRF51_TIMER(opaque);
 | 
				
			||||||
 | 
					    uint64_t r = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (offset) {
 | 
				
			||||||
 | 
					    case NRF51_TIMER_EVENT_COMPARE_0 ... NRF51_TIMER_EVENT_COMPARE_3:
 | 
				
			||||||
 | 
					        r = s->events_compare[(offset - NRF51_TIMER_EVENT_COMPARE_0) / 4];
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_SHORTS:
 | 
				
			||||||
 | 
					        r = s->shorts;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_INTENSET:
 | 
				
			||||||
 | 
					        r = s->inten;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_INTENCLR:
 | 
				
			||||||
 | 
					        r = s->inten;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_MODE:
 | 
				
			||||||
 | 
					        r = s->mode;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_BITMODE:
 | 
				
			||||||
 | 
					        r = s->bitmode;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_PRESCALER:
 | 
				
			||||||
 | 
					        r = s->prescaler;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_CC0 ... NRF51_TIMER_REG_CC3:
 | 
				
			||||||
 | 
					        r = s->cc[(offset - NRF51_TIMER_REG_CC0) / 4];
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        qemu_log_mask(LOG_GUEST_ERROR,
 | 
				
			||||||
 | 
					                "%s: bad read offset 0x%" HWADDR_PRIx "\n",
 | 
				
			||||||
 | 
					                      __func__, offset);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    trace_nrf51_timer_read(offset, r, size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_timer_write(void *opaque, hwaddr offset,
 | 
				
			||||||
 | 
					                       uint64_t value, unsigned int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51TimerState *s = NRF51_TIMER(opaque);
 | 
				
			||||||
 | 
					    uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 | 
				
			||||||
 | 
					    size_t idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    trace_nrf51_timer_write(offset, value, size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (offset) {
 | 
				
			||||||
 | 
					    case NRF51_TIMER_TASK_START:
 | 
				
			||||||
 | 
					        if (value == NRF51_TRIGGER_TASK && s->mode == NRF51_TIMER_TIMER) {
 | 
				
			||||||
 | 
					            s->running = true;
 | 
				
			||||||
 | 
					            s->timer_start_ns = now - ticks_to_ns(s, s->counter);
 | 
				
			||||||
 | 
					            s->update_counter_ns = s->timer_start_ns;
 | 
				
			||||||
 | 
					            rearm_timer(s, now);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_TASK_STOP:
 | 
				
			||||||
 | 
					    case NRF51_TIMER_TASK_SHUTDOWN:
 | 
				
			||||||
 | 
					        if (value == NRF51_TRIGGER_TASK) {
 | 
				
			||||||
 | 
					            s->running = false;
 | 
				
			||||||
 | 
					            timer_del(&s->timer);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_TASK_COUNT:
 | 
				
			||||||
 | 
					        if (value == NRF51_TRIGGER_TASK && s->mode == NRF51_TIMER_COUNTER) {
 | 
				
			||||||
 | 
					            s->counter = (s->counter + 1) % BIT(bitwidths[s->bitmode]);
 | 
				
			||||||
 | 
					            counter_compare(s);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_TASK_CLEAR:
 | 
				
			||||||
 | 
					        if (value == NRF51_TRIGGER_TASK) {
 | 
				
			||||||
 | 
					            s->timer_start_ns = now;
 | 
				
			||||||
 | 
					            s->update_counter_ns = s->timer_start_ns;
 | 
				
			||||||
 | 
					            s->counter = 0;
 | 
				
			||||||
 | 
					            if (s->running) {
 | 
				
			||||||
 | 
					                rearm_timer(s, now);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_TASK_CAPTURE_0 ... NRF51_TIMER_TASK_CAPTURE_3:
 | 
				
			||||||
 | 
					        if (value == NRF51_TRIGGER_TASK) {
 | 
				
			||||||
 | 
					            if (s->running) {
 | 
				
			||||||
 | 
					                timer_expire(s); /* update counter and all state */
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            idx = (offset - NRF51_TIMER_TASK_CAPTURE_0) / 4;
 | 
				
			||||||
 | 
					            s->cc[idx] = s->counter;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_EVENT_COMPARE_0 ... NRF51_TIMER_EVENT_COMPARE_3:
 | 
				
			||||||
 | 
					        if (value == NRF51_EVENT_CLEAR) {
 | 
				
			||||||
 | 
					            s->events_compare[(offset - NRF51_TIMER_EVENT_COMPARE_0) / 4] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (s->running) {
 | 
				
			||||||
 | 
					                timer_expire(s); /* update counter and all state */
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_SHORTS:
 | 
				
			||||||
 | 
					        s->shorts = value & NRF51_TIMER_REG_SHORTS_MASK;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_INTENSET:
 | 
				
			||||||
 | 
					        s->inten |= value & NRF51_TIMER_REG_INTEN_MASK;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_INTENCLR:
 | 
				
			||||||
 | 
					        s->inten &= ~(value & NRF51_TIMER_REG_INTEN_MASK);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_MODE:
 | 
				
			||||||
 | 
					        s->mode = value;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_BITMODE:
 | 
				
			||||||
 | 
					        if (s->mode == NRF51_TIMER_TIMER && s->running) {
 | 
				
			||||||
 | 
					            qemu_log_mask(LOG_GUEST_ERROR,
 | 
				
			||||||
 | 
					                    "%s: erroneous change of BITMODE while timer is running\n",
 | 
				
			||||||
 | 
					                    __func__);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        s->bitmode = value & NRF51_TIMER_REG_BITMODE_MASK;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_PRESCALER:
 | 
				
			||||||
 | 
					        if (s->mode == NRF51_TIMER_TIMER && s->running) {
 | 
				
			||||||
 | 
					            qemu_log_mask(LOG_GUEST_ERROR,
 | 
				
			||||||
 | 
					                "%s: erroneous change of PRESCALER while timer is running\n",
 | 
				
			||||||
 | 
					                __func__);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        s->prescaler = value & NRF51_TIMER_REG_PRESCALER_MASK;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case NRF51_TIMER_REG_CC0 ... NRF51_TIMER_REG_CC3:
 | 
				
			||||||
 | 
					        if (s->running) {
 | 
				
			||||||
 | 
					            timer_expire(s); /* update counter */
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        idx = (offset - NRF51_TIMER_REG_CC0) / 4;
 | 
				
			||||||
 | 
					        s->cc[idx] = value % BIT(bitwidths[s->bitmode]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (s->running) {
 | 
				
			||||||
 | 
					            rearm_timer(s, now);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        qemu_log_mask(LOG_GUEST_ERROR,
 | 
				
			||||||
 | 
					                      "%s: bad write offset 0x%" HWADDR_PRIx "\n",
 | 
				
			||||||
 | 
					                      __func__, offset);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    update_irq(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const MemoryRegionOps rng_ops = {
 | 
				
			||||||
 | 
					    .read =  nrf51_timer_read,
 | 
				
			||||||
 | 
					    .write = nrf51_timer_write,
 | 
				
			||||||
 | 
					    .endianness = DEVICE_LITTLE_ENDIAN,
 | 
				
			||||||
 | 
					    .impl.min_access_size = 4,
 | 
				
			||||||
 | 
					    .impl.max_access_size = 4,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_timer_init(Object *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51TimerState *s = NRF51_TIMER(obj);
 | 
				
			||||||
 | 
					    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memory_region_init_io(&s->iomem, obj, &rng_ops, s,
 | 
				
			||||||
 | 
					            TYPE_NRF51_TIMER, NRF51_TIMER_SIZE);
 | 
				
			||||||
 | 
					    sysbus_init_mmio(sbd, &s->iomem);
 | 
				
			||||||
 | 
					    sysbus_init_irq(sbd, &s->irq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    timer_init_ns(&s->timer, QEMU_CLOCK_VIRTUAL, timer_expire, s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_timer_reset(DeviceState *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51TimerState *s = NRF51_TIMER(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    timer_del(&s->timer);
 | 
				
			||||||
 | 
					    s->timer_start_ns = 0x00;
 | 
				
			||||||
 | 
					    s->update_counter_ns = 0x00;
 | 
				
			||||||
 | 
					    s->counter = 0x00;
 | 
				
			||||||
 | 
					    s->running = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(s->events_compare, 0x00, sizeof(s->events_compare));
 | 
				
			||||||
 | 
					    memset(s->cc, 0x00, sizeof(s->cc));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->shorts = 0x00;
 | 
				
			||||||
 | 
					    s->inten = 0x00;
 | 
				
			||||||
 | 
					    s->mode = 0x00;
 | 
				
			||||||
 | 
					    s->bitmode = 0x00;
 | 
				
			||||||
 | 
					    s->prescaler = 0x00;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int nrf51_timer_post_load(void *opaque, int version_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NRF51TimerState *s = NRF51_TIMER(opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->running && s->mode == NRF51_TIMER_TIMER) {
 | 
				
			||||||
 | 
					        timer_expire(s);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const VMStateDescription vmstate_nrf51_timer = {
 | 
				
			||||||
 | 
					    .name = TYPE_NRF51_TIMER,
 | 
				
			||||||
 | 
					    .version_id = 1,
 | 
				
			||||||
 | 
					    .post_load = nrf51_timer_post_load,
 | 
				
			||||||
 | 
					    .fields = (VMStateField[]) {
 | 
				
			||||||
 | 
					        VMSTATE_TIMER(timer, NRF51TimerState),
 | 
				
			||||||
 | 
					        VMSTATE_INT64(timer_start_ns, NRF51TimerState),
 | 
				
			||||||
 | 
					        VMSTATE_INT64(update_counter_ns, NRF51TimerState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(counter, NRF51TimerState),
 | 
				
			||||||
 | 
					        VMSTATE_BOOL(running, NRF51TimerState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT8_ARRAY(events_compare, NRF51TimerState,
 | 
				
			||||||
 | 
					                            NRF51_TIMER_REG_COUNT),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32_ARRAY(cc, NRF51TimerState, NRF51_TIMER_REG_COUNT),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(shorts, NRF51TimerState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(inten, NRF51TimerState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(mode, NRF51TimerState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(bitmode, NRF51TimerState),
 | 
				
			||||||
 | 
					        VMSTATE_UINT32(prescaler, NRF51TimerState),
 | 
				
			||||||
 | 
					        VMSTATE_END_OF_LIST()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_timer_class_init(ObjectClass *klass, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DeviceClass *dc = DEVICE_CLASS(klass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dc->reset = nrf51_timer_reset;
 | 
				
			||||||
 | 
					    dc->vmsd = &vmstate_nrf51_timer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const TypeInfo nrf51_timer_info = {
 | 
				
			||||||
 | 
					    .name = TYPE_NRF51_TIMER,
 | 
				
			||||||
 | 
					    .parent = TYPE_SYS_BUS_DEVICE,
 | 
				
			||||||
 | 
					    .instance_size = sizeof(NRF51TimerState),
 | 
				
			||||||
 | 
					    .instance_init = nrf51_timer_init,
 | 
				
			||||||
 | 
					    .class_init = nrf51_timer_class_init
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nrf51_timer_register_types(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type_register_static(&nrf51_timer_info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type_init(nrf51_timer_register_types)
 | 
				
			||||||
@ -72,3 +72,8 @@ sun4v_rtc_write(uint64_t addr, uint64_t value) "write: addr 0x%" PRIx64 " value
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# hw/timer/xlnx-zynqmp-rtc.c
 | 
					# hw/timer/xlnx-zynqmp-rtc.c
 | 
				
			||||||
xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec) "Get time from host: %d-%d-%d %2d:%02d:%02d"
 | 
					xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec) "Get time from host: %d-%d-%d %2d:%02d:%02d"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# hw/timer/nrf51_timer.c
 | 
				
			||||||
 | 
					nrf51_timer_read(uint64_t addr, uint32_t value, unsigned size) "read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
 | 
				
			||||||
 | 
					nrf51_timer_write(uint64_t addr, uint32_t value, unsigned size) "write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -35,6 +35,7 @@ typedef struct AwA10State {
 | 
				
			|||||||
    AwA10PICState intc;
 | 
					    AwA10PICState intc;
 | 
				
			||||||
    AwEmacState emac;
 | 
					    AwEmacState emac;
 | 
				
			||||||
    AllwinnerAHCIState sata;
 | 
					    AllwinnerAHCIState sata;
 | 
				
			||||||
 | 
					    MemoryRegion sram_a;
 | 
				
			||||||
} AwA10State;
 | 
					} AwA10State;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ALLWINNER_H_
 | 
					#define ALLWINNER_H_
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										45
									
								
								include/hw/arm/nrf51.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								include/hw/arm/nrf51.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Nordic Semiconductor nRF51 Series SOC Common Defines
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This file hosts generic defines used in various nRF51 peripheral devices.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
 | 
				
			||||||
 | 
					 * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This code is licensed under the GPL version 2 or later.  See
 | 
				
			||||||
 | 
					 * the COPYING file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef NRF51_H
 | 
				
			||||||
 | 
					#define NRF51_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_FLASH_BASE      0x00000000
 | 
				
			||||||
 | 
					#define NRF51_FICR_BASE       0x10000000
 | 
				
			||||||
 | 
					#define NRF51_FICR_SIZE       0x00000100
 | 
				
			||||||
 | 
					#define NRF51_UICR_BASE       0x10001000
 | 
				
			||||||
 | 
					#define NRF51_SRAM_BASE       0x20000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_IOMEM_BASE      0x40000000
 | 
				
			||||||
 | 
					#define NRF51_IOMEM_SIZE      0x20000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_UART_BASE       0x40002000
 | 
				
			||||||
 | 
					#define NRF51_TIMER_BASE      0x40008000
 | 
				
			||||||
 | 
					#define NRF51_TIMER_SIZE      0x00001000
 | 
				
			||||||
 | 
					#define NRF51_RNG_BASE        0x4000D000
 | 
				
			||||||
 | 
					#define NRF51_NVMC_BASE       0x4001E000
 | 
				
			||||||
 | 
					#define NRF51_GPIO_BASE       0x50000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_PRIVATE_BASE    0xF0000000
 | 
				
			||||||
 | 
					#define NRF51_PRIVATE_SIZE    0x10000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_PAGE_SIZE       1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Trigger */
 | 
				
			||||||
 | 
					#define NRF51_TRIGGER_TASK 0x01
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Events */
 | 
				
			||||||
 | 
					#define NRF51_EVENT_CLEAR  0x00
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@ -13,11 +13,16 @@
 | 
				
			|||||||
#include "hw/sysbus.h"
 | 
					#include "hw/sysbus.h"
 | 
				
			||||||
#include "hw/arm/armv7m.h"
 | 
					#include "hw/arm/armv7m.h"
 | 
				
			||||||
#include "hw/char/nrf51_uart.h"
 | 
					#include "hw/char/nrf51_uart.h"
 | 
				
			||||||
 | 
					#include "hw/misc/nrf51_rng.h"
 | 
				
			||||||
 | 
					#include "hw/gpio/nrf51_gpio.h"
 | 
				
			||||||
 | 
					#include "hw/timer/nrf51_timer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TYPE_NRF51_SOC "nrf51-soc"
 | 
					#define TYPE_NRF51_SOC "nrf51-soc"
 | 
				
			||||||
#define NRF51_SOC(obj) \
 | 
					#define NRF51_SOC(obj) \
 | 
				
			||||||
    OBJECT_CHECK(NRF51State, (obj), TYPE_NRF51_SOC)
 | 
					    OBJECT_CHECK(NRF51State, (obj), TYPE_NRF51_SOC)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_NUM_TIMERS 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct NRF51State {
 | 
					typedef struct NRF51State {
 | 
				
			||||||
    /*< private >*/
 | 
					    /*< private >*/
 | 
				
			||||||
    SysBusDevice parent_obj;
 | 
					    SysBusDevice parent_obj;
 | 
				
			||||||
@ -26,10 +31,14 @@ typedef struct NRF51State {
 | 
				
			|||||||
    ARMv7MState cpu;
 | 
					    ARMv7MState cpu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    NRF51UARTState uart;
 | 
					    NRF51UARTState uart;
 | 
				
			||||||
 | 
					    NRF51RNGState rng;
 | 
				
			||||||
 | 
					    NRF51GPIOState gpio;
 | 
				
			||||||
 | 
					    NRF51TimerState timer[NRF51_NUM_TIMERS];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    MemoryRegion iomem;
 | 
					    MemoryRegion iomem;
 | 
				
			||||||
    MemoryRegion sram;
 | 
					    MemoryRegion sram;
 | 
				
			||||||
    MemoryRegion flash;
 | 
					    MemoryRegion flash;
 | 
				
			||||||
 | 
					    MemoryRegion clock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t sram_size;
 | 
					    uint32_t sram_size;
 | 
				
			||||||
    uint32_t flash_size;
 | 
					    uint32_t flash_size;
 | 
				
			||||||
 | 
				
			|||||||
@ -31,6 +31,7 @@
 | 
				
			|||||||
#include "hw/display/xlnx_dp.h"
 | 
					#include "hw/display/xlnx_dp.h"
 | 
				
			||||||
#include "hw/intc/xlnx-zynqmp-ipi.h"
 | 
					#include "hw/intc/xlnx-zynqmp-ipi.h"
 | 
				
			||||||
#include "hw/timer/xlnx-zynqmp-rtc.h"
 | 
					#include "hw/timer/xlnx-zynqmp-rtc.h"
 | 
				
			||||||
 | 
					#include "hw/cpu/cluster.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
 | 
					#define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
 | 
				
			||||||
#define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
 | 
					#define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
 | 
				
			||||||
@ -77,6 +78,8 @@ typedef struct XlnxZynqMPState {
 | 
				
			|||||||
    DeviceState parent_obj;
 | 
					    DeviceState parent_obj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*< public >*/
 | 
					    /*< public >*/
 | 
				
			||||||
 | 
					    CPUClusterState apu_cluster;
 | 
				
			||||||
 | 
					    CPUClusterState rpu_cluster;
 | 
				
			||||||
    ARMCPU apu_cpu[XLNX_ZYNQMP_NUM_APU_CPUS];
 | 
					    ARMCPU apu_cpu[XLNX_ZYNQMP_NUM_APU_CPUS];
 | 
				
			||||||
    ARMCPU rpu_cpu[XLNX_ZYNQMP_NUM_RPU_CPUS];
 | 
					    ARMCPU rpu_cpu[XLNX_ZYNQMP_NUM_RPU_CPUS];
 | 
				
			||||||
    GICState gic;
 | 
					    GICState gic;
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,6 @@
 | 
				
			|||||||
#include "hw/registerfields.h"
 | 
					#include "hw/registerfields.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define UART_FIFO_LENGTH 6
 | 
					#define UART_FIFO_LENGTH 6
 | 
				
			||||||
#define UART_BASE 0x40002000
 | 
					 | 
				
			||||||
#define UART_SIZE 0x1000
 | 
					#define UART_SIZE 0x1000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TYPE_NRF51_UART "nrf51_soc.uart"
 | 
					#define TYPE_NRF51_UART "nrf51_soc.uart"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										58
									
								
								include/hw/cpu/cluster.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								include/hw/cpu/cluster.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QEMU CPU cluster
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2018 GreenSocs SAS
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 * modify it under the terms of the GNU General Public License
 | 
				
			||||||
 | 
					 * as published by the Free Software Foundation; either version 2
 | 
				
			||||||
 | 
					 * of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 * along with this program; if not, see
 | 
				
			||||||
 | 
					 * <http://www.gnu.org/licenses/gpl-2.0.html>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef HW_CPU_CLUSTER_H
 | 
				
			||||||
 | 
					#define HW_CPU_CLUSTER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qemu/osdep.h"
 | 
				
			||||||
 | 
					#include "hw/qdev.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * CPU Cluster type
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * A cluster is a group of CPUs which are all identical and have the same view
 | 
				
			||||||
 | 
					 * of the rest of the system. It is mainly an internal QEMU representation and
 | 
				
			||||||
 | 
					 * does not necessarily match with the notion of clusters on the real hardware.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If CPUs are not identical (for example, Cortex-A53 and Cortex-A57 CPUs in an
 | 
				
			||||||
 | 
					 * Arm big.LITTLE system) they should be in different clusters. If the CPUs do
 | 
				
			||||||
 | 
					 * not have the same view of memory (for example the main CPU and a management
 | 
				
			||||||
 | 
					 * controller processor) they should be in different clusters.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TYPE_CPU_CLUSTER "cpu-cluster"
 | 
				
			||||||
 | 
					#define CPU_CLUSTER(obj) \
 | 
				
			||||||
 | 
					    OBJECT_CHECK(CPUClusterState, (obj), TYPE_CPU_CLUSTER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * CPUClusterState:
 | 
				
			||||||
 | 
					 * @cluster_id: The cluster ID. This value is for internal use only and should
 | 
				
			||||||
 | 
					 *   not be exposed directly to the user or to the guest.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * State of a CPU cluster.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct CPUClusterState {
 | 
				
			||||||
 | 
					    /*< private >*/
 | 
				
			||||||
 | 
					    DeviceState parent_obj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*< public >*/
 | 
				
			||||||
 | 
					    uint32_t cluster_id;
 | 
				
			||||||
 | 
					} CPUClusterState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										69
									
								
								include/hw/gpio/nrf51_gpio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								include/hw/gpio/nrf51_gpio.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * nRF51 System-on-Chip general purpose input/output register definition
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * QEMU interface:
 | 
				
			||||||
 | 
					 * + sysbus MMIO regions 0: GPIO registers
 | 
				
			||||||
 | 
					 * + Unnamed GPIO inputs 0-31: Set tri-state input level for GPIO pin.
 | 
				
			||||||
 | 
					 *   Level -1: Externally Disconnected/Floating; Pull-up/down will be regarded
 | 
				
			||||||
 | 
					 *   Level 0: Input externally driven LOW
 | 
				
			||||||
 | 
					 *   Level 1: Input externally driven HIGH
 | 
				
			||||||
 | 
					 * + Unnamed GPIO outputs 0-31:
 | 
				
			||||||
 | 
					 *   Level -1: Disconnected/Floating
 | 
				
			||||||
 | 
					 *   Level 0: Driven LOW
 | 
				
			||||||
 | 
					 *   Level 1: Driven HIGH
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Accuracy of the peripheral model:
 | 
				
			||||||
 | 
					 * + The nRF51 GPIO output driver supports two modes, standard and high-current
 | 
				
			||||||
 | 
					 *   mode. These different drive modes are not modeled and handled the same.
 | 
				
			||||||
 | 
					 * + Pin SENSEing is not modeled/implemented.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This code is licensed under the GPL version 2 or later.  See
 | 
				
			||||||
 | 
					 * the COPYING file in the top-level directory.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef NRF51_GPIO_H
 | 
				
			||||||
 | 
					#define NRF51_GPIO_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "hw/sysbus.h"
 | 
				
			||||||
 | 
					#define TYPE_NRF51_GPIO "nrf51_soc.gpio"
 | 
				
			||||||
 | 
					#define NRF51_GPIO(obj) OBJECT_CHECK(NRF51GPIOState, (obj), TYPE_NRF51_GPIO)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_GPIO_PINS 32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_GPIO_SIZE 0x1000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_GPIO_REG_OUT          0x504
 | 
				
			||||||
 | 
					#define NRF51_GPIO_REG_OUTSET       0x508
 | 
				
			||||||
 | 
					#define NRF51_GPIO_REG_OUTCLR       0x50C
 | 
				
			||||||
 | 
					#define NRF51_GPIO_REG_IN           0x510
 | 
				
			||||||
 | 
					#define NRF51_GPIO_REG_DIR          0x514
 | 
				
			||||||
 | 
					#define NRF51_GPIO_REG_DIRSET       0x518
 | 
				
			||||||
 | 
					#define NRF51_GPIO_REG_DIRCLR       0x51C
 | 
				
			||||||
 | 
					#define NRF51_GPIO_REG_CNF_START    0x700
 | 
				
			||||||
 | 
					#define NRF51_GPIO_REG_CNF_END      0x77F
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_GPIO_PULLDOWN 1
 | 
				
			||||||
 | 
					#define NRF51_GPIO_PULLUP 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct NRF51GPIOState {
 | 
				
			||||||
 | 
					    SysBusDevice parent_obj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MemoryRegion mmio;
 | 
				
			||||||
 | 
					    qemu_irq irq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t out;
 | 
				
			||||||
 | 
					    uint32_t in;
 | 
				
			||||||
 | 
					    uint32_t in_mask;
 | 
				
			||||||
 | 
					    uint32_t dir;
 | 
				
			||||||
 | 
					    uint32_t cnf[NRF51_GPIO_PINS];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t old_out;
 | 
				
			||||||
 | 
					    uint32_t old_out_connected;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qemu_irq output[NRF51_GPIO_PINS];
 | 
				
			||||||
 | 
					} NRF51GPIOState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@ -175,10 +175,15 @@ void load_elf_hdr(const char *filename, void *hdr, bool *is64, Error **errp);
 | 
				
			|||||||
int load_aout(const char *filename, hwaddr addr, int max_sz,
 | 
					int load_aout(const char *filename, hwaddr addr, int max_sz,
 | 
				
			||||||
              int bswap_needed, hwaddr target_page_size);
 | 
					              int bswap_needed, hwaddr target_page_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOAD_UIMAGE_LOADADDR_INVALID (-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** load_uimage_as:
 | 
					/** load_uimage_as:
 | 
				
			||||||
 * @filename: Path of uimage file
 | 
					 * @filename: Path of uimage file
 | 
				
			||||||
 * @ep: Populated with program entry point. Ignored if NULL.
 | 
					 * @ep: Populated with program entry point. Ignored if NULL.
 | 
				
			||||||
 * @loadaddr: Populated with the load address. Ignored if NULL.
 | 
					 * @loadaddr: load address if none specified in the image or when loading a
 | 
				
			||||||
 | 
					 *            ramdisk. Populated with the load address. Ignored if NULL or
 | 
				
			||||||
 | 
					 *            LOAD_UIMAGE_LOADADDR_INVALID (images which do not specify a load
 | 
				
			||||||
 | 
					 *            address will not be loadable).
 | 
				
			||||||
 * @is_linux: Is set to true if the image loaded is Linux. Ignored if NULL.
 | 
					 * @is_linux: Is set to true if the image loaded is Linux. Ignored if NULL.
 | 
				
			||||||
 * @translate_fn: optional function to translate load addresses
 | 
					 * @translate_fn: optional function to translate load addresses
 | 
				
			||||||
 * @translate_opaque: opaque data passed to @translate_fn
 | 
					 * @translate_opaque: opaque data passed to @translate_fn
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										83
									
								
								include/hw/misc/nrf51_rng.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								include/hw/misc/nrf51_rng.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,83 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * nRF51 Random Number Generator
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * QEMU interface:
 | 
				
			||||||
 | 
					 * + Property "period_unfiltered_us": Time between two biased values in
 | 
				
			||||||
 | 
					 *   microseconds.
 | 
				
			||||||
 | 
					 * + Property "period_filtered_us": Time between two unbiased values in
 | 
				
			||||||
 | 
					 *   microseconds.
 | 
				
			||||||
 | 
					 * + sysbus MMIO regions 0: Memory Region with tasks, events and registers
 | 
				
			||||||
 | 
					 *   to be mapped to the peripherals instance address by the SOC.
 | 
				
			||||||
 | 
					 * + Named GPIO output "irq": Interrupt line of the peripheral. Must be
 | 
				
			||||||
 | 
					 *   connected to the associated peripheral interrupt line of the NVIC.
 | 
				
			||||||
 | 
					 * + Named GPIO output "eep_valrdy": Event set when new random value is ready
 | 
				
			||||||
 | 
					 *   to be read.
 | 
				
			||||||
 | 
					 * + Named GPIO input "tep_start": Task that triggers start of continuous
 | 
				
			||||||
 | 
					 *   generation of random values.
 | 
				
			||||||
 | 
					 * + Named GPIO input "tep_stop": Task that ends continuous generation of
 | 
				
			||||||
 | 
					 *   random values.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Accuracy of the peripheral model:
 | 
				
			||||||
 | 
					 * + Stochastic properties of different configurations of the random source
 | 
				
			||||||
 | 
					 *   are not modeled.
 | 
				
			||||||
 | 
					 * + Generation of unfiltered and filtered random values take at least the
 | 
				
			||||||
 | 
					 *   average generation time stated in the production specification;
 | 
				
			||||||
 | 
					 *   non-deterministic generation times are not modeled.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This code is licensed under the GPL version 2 or later.  See
 | 
				
			||||||
 | 
					 * the COPYING file in the top-level directory.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef NRF51_RNG_H
 | 
				
			||||||
 | 
					#define NRF51_RNG_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "hw/sysbus.h"
 | 
				
			||||||
 | 
					#include "qemu/timer.h"
 | 
				
			||||||
 | 
					#define TYPE_NRF51_RNG "nrf51_soc.rng"
 | 
				
			||||||
 | 
					#define NRF51_RNG(obj) OBJECT_CHECK(NRF51RNGState, (obj), TYPE_NRF51_RNG)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_RNG_SIZE         0x1000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_RNG_TASK_START   0x000
 | 
				
			||||||
 | 
					#define NRF51_RNG_TASK_STOP    0x004
 | 
				
			||||||
 | 
					#define NRF51_RNG_EVENT_VALRDY 0x100
 | 
				
			||||||
 | 
					#define NRF51_RNG_REG_SHORTS   0x200
 | 
				
			||||||
 | 
					#define NRF51_RNG_REG_SHORTS_VALRDY_STOP 0
 | 
				
			||||||
 | 
					#define NRF51_RNG_REG_INTEN    0x300
 | 
				
			||||||
 | 
					#define NRF51_RNG_REG_INTEN_VALRDY 0
 | 
				
			||||||
 | 
					#define NRF51_RNG_REG_INTENSET 0x304
 | 
				
			||||||
 | 
					#define NRF51_RNG_REG_INTENCLR 0x308
 | 
				
			||||||
 | 
					#define NRF51_RNG_REG_CONFIG   0x504
 | 
				
			||||||
 | 
					#define NRF51_RNG_REG_CONFIG_DECEN 0
 | 
				
			||||||
 | 
					#define NRF51_RNG_REG_VALUE    0x508
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    SysBusDevice parent_obj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MemoryRegion mmio;
 | 
				
			||||||
 | 
					    qemu_irq irq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Event End Points */
 | 
				
			||||||
 | 
					    qemu_irq eep_valrdy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QEMUTimer timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Time between generation of successive unfiltered values in us */
 | 
				
			||||||
 | 
					    uint16_t period_unfiltered_us;
 | 
				
			||||||
 | 
					    /* Time between generation of successive filtered values in us */
 | 
				
			||||||
 | 
					    uint16_t period_filtered_us;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint8_t value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t active;
 | 
				
			||||||
 | 
					    uint32_t event_valrdy;
 | 
				
			||||||
 | 
					    uint32_t shortcut_stop_on_valrdy;
 | 
				
			||||||
 | 
					    uint32_t interrupt_enabled;
 | 
				
			||||||
 | 
					    uint32_t filter_enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} NRF51RNGState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* NRF51_RNG_H_ */
 | 
				
			||||||
							
								
								
									
										80
									
								
								include/hw/timer/nrf51_timer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								include/hw/timer/nrf51_timer.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * nRF51 System-on-Chip Timer peripheral
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * QEMU interface:
 | 
				
			||||||
 | 
					 * + sysbus MMIO regions 0: GPIO registers
 | 
				
			||||||
 | 
					 * + sysbus irq
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This code is licensed under the GPL version 2 or later.  See
 | 
				
			||||||
 | 
					 * the COPYING file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef NRF51_TIMER_H
 | 
				
			||||||
 | 
					#define NRF51_TIMER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "hw/sysbus.h"
 | 
				
			||||||
 | 
					#include "qemu/timer.h"
 | 
				
			||||||
 | 
					#define TYPE_NRF51_TIMER "nrf51_soc.timer"
 | 
				
			||||||
 | 
					#define NRF51_TIMER(obj) OBJECT_CHECK(NRF51TimerState, (obj), TYPE_NRF51_TIMER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_COUNT 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_TIMER_TASK_START 0x000
 | 
				
			||||||
 | 
					#define NRF51_TIMER_TASK_STOP 0x004
 | 
				
			||||||
 | 
					#define NRF51_TIMER_TASK_COUNT 0x008
 | 
				
			||||||
 | 
					#define NRF51_TIMER_TASK_CLEAR 0x00C
 | 
				
			||||||
 | 
					#define NRF51_TIMER_TASK_SHUTDOWN 0x010
 | 
				
			||||||
 | 
					#define NRF51_TIMER_TASK_CAPTURE_0 0x040
 | 
				
			||||||
 | 
					#define NRF51_TIMER_TASK_CAPTURE_3 0x04C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_TIMER_EVENT_COMPARE_0 0x140
 | 
				
			||||||
 | 
					#define NRF51_TIMER_EVENT_COMPARE_1 0x144
 | 
				
			||||||
 | 
					#define NRF51_TIMER_EVENT_COMPARE_2 0x148
 | 
				
			||||||
 | 
					#define NRF51_TIMER_EVENT_COMPARE_3 0x14C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_SHORTS 0x200
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_SHORTS_MASK 0xf0f
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_INTENSET 0x304
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_INTENCLR 0x308
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_INTEN_MASK 0xf0000
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_MODE 0x504
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_MODE_MASK 0x01
 | 
				
			||||||
 | 
					#define NRF51_TIMER_TIMER 0
 | 
				
			||||||
 | 
					#define NRF51_TIMER_COUNTER 1
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_BITMODE 0x508
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_BITMODE_MASK 0x03
 | 
				
			||||||
 | 
					#define NRF51_TIMER_WIDTH_16 0
 | 
				
			||||||
 | 
					#define NRF51_TIMER_WIDTH_8 1
 | 
				
			||||||
 | 
					#define NRF51_TIMER_WIDTH_24 2
 | 
				
			||||||
 | 
					#define NRF51_TIMER_WIDTH_32 3
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_PRESCALER 0x510
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_PRESCALER_MASK 0x0F
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_CC0 0x540
 | 
				
			||||||
 | 
					#define NRF51_TIMER_REG_CC3 0x54C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct NRF51TimerState {
 | 
				
			||||||
 | 
					    SysBusDevice parent_obj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MemoryRegion iomem;
 | 
				
			||||||
 | 
					    qemu_irq irq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QEMUTimer timer;
 | 
				
			||||||
 | 
					    int64_t timer_start_ns;
 | 
				
			||||||
 | 
					    int64_t update_counter_ns;
 | 
				
			||||||
 | 
					    uint32_t counter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool running;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint8_t events_compare[NRF51_TIMER_REG_COUNT];
 | 
				
			||||||
 | 
					    uint32_t cc[NRF51_TIMER_REG_COUNT];
 | 
				
			||||||
 | 
					    uint32_t shorts;
 | 
				
			||||||
 | 
					    uint32_t inten;
 | 
				
			||||||
 | 
					    uint32_t mode;
 | 
				
			||||||
 | 
					    uint32_t bitmode;
 | 
				
			||||||
 | 
					    uint32_t prescaler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} NRF51TimerState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										43
									
								
								qtest.c
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								qtest.c
									
									
									
									
									
								
							@ -164,6 +164,17 @@ static bool qtest_opened;
 | 
				
			|||||||
 * where NUM is an IRQ number.  For the PC, interrupts can be intercepted
 | 
					 * where NUM is an IRQ number.  For the PC, interrupts can be intercepted
 | 
				
			||||||
 * simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
 | 
					 * simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
 | 
				
			||||||
 * NUM=0 even though it is remapped to GSI 2).
 | 
					 * NUM=0 even though it is remapped to GSI 2).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Setting interrupt level:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  > set_irq_in QOM-PATH NAME NUM LEVEL
 | 
				
			||||||
 | 
					 *  < OK
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  where NAME is the name of the irq/gpio list, NUM is an IRQ number and
 | 
				
			||||||
 | 
					 *  LEVEL is an signed integer IRQ level.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Forcibly set the given interrupt pin to the given level.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int hex2nib(char ch)
 | 
					static int hex2nib(char ch)
 | 
				
			||||||
@ -326,7 +337,39 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
 | 
				
			|||||||
        irq_intercept_dev = dev;
 | 
					        irq_intercept_dev = dev;
 | 
				
			||||||
        qtest_send_prefix(chr);
 | 
					        qtest_send_prefix(chr);
 | 
				
			||||||
        qtest_send(chr, "OK\n");
 | 
					        qtest_send(chr, "OK\n");
 | 
				
			||||||
 | 
					    } else if (strcmp(words[0], "set_irq_in") == 0) {
 | 
				
			||||||
 | 
					        DeviceState *dev;
 | 
				
			||||||
 | 
					        qemu_irq irq;
 | 
				
			||||||
 | 
					        char *name;
 | 
				
			||||||
 | 
					        int ret;
 | 
				
			||||||
 | 
					        int num;
 | 
				
			||||||
 | 
					        int level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        g_assert(words[1] && words[2] && words[3] && words[4]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dev = DEVICE(object_resolve_path(words[1], NULL));
 | 
				
			||||||
 | 
					        if (!dev) {
 | 
				
			||||||
 | 
					            qtest_send_prefix(chr);
 | 
				
			||||||
 | 
					            qtest_send(chr, "FAIL Unknown device\n");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (strcmp(words[2], "unnamed-gpio-in") == 0) {
 | 
				
			||||||
 | 
					            name = NULL;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            name = words[2];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ret = qemu_strtoi(words[3], NULL, 0, &num);
 | 
				
			||||||
 | 
					        g_assert(!ret);
 | 
				
			||||||
 | 
					        ret = qemu_strtoi(words[4], NULL, 0, &level);
 | 
				
			||||||
 | 
					        g_assert(!ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        irq = qdev_get_gpio_in_named(dev, name, num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        qemu_set_irq(irq, level);
 | 
				
			||||||
 | 
					        qtest_send_prefix(chr);
 | 
				
			||||||
 | 
					        qtest_send(chr, "OK\n");
 | 
				
			||||||
    } else if (strcmp(words[0], "outb") == 0 ||
 | 
					    } else if (strcmp(words[0], "outb") == 0 ||
 | 
				
			||||||
               strcmp(words[0], "outw") == 0 ||
 | 
					               strcmp(words[0], "outw") == 0 ||
 | 
				
			||||||
               strcmp(words[0], "outl") == 0) {
 | 
					               strcmp(words[0], "outl") == 0) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										102
									
								
								target/arm/cpu.h
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								target/arm/cpu.h
									
									
									
									
									
								
							@ -2946,102 +2946,40 @@ static inline bool arm_cpu_data_is_big_endian(CPUARMState *env)
 | 
				
			|||||||
 * We put flags which are shared between 32 and 64 bit mode at the top
 | 
					 * We put flags which are shared between 32 and 64 bit mode at the top
 | 
				
			||||||
 * of the word, and flags which apply to only one mode at the bottom.
 | 
					 * of the word, and flags which apply to only one mode at the bottom.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define ARM_TBFLAG_AARCH64_STATE_SHIFT 31
 | 
					FIELD(TBFLAG_ANY, AARCH64_STATE, 31, 1)
 | 
				
			||||||
#define ARM_TBFLAG_AARCH64_STATE_MASK  (1U << ARM_TBFLAG_AARCH64_STATE_SHIFT)
 | 
					FIELD(TBFLAG_ANY, MMUIDX, 28, 3)
 | 
				
			||||||
#define ARM_TBFLAG_MMUIDX_SHIFT 28
 | 
					FIELD(TBFLAG_ANY, SS_ACTIVE, 27, 1)
 | 
				
			||||||
#define ARM_TBFLAG_MMUIDX_MASK (0x7 << ARM_TBFLAG_MMUIDX_SHIFT)
 | 
					FIELD(TBFLAG_ANY, PSTATE_SS, 26, 1)
 | 
				
			||||||
#define ARM_TBFLAG_SS_ACTIVE_SHIFT 27
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_SS_ACTIVE_MASK (1 << ARM_TBFLAG_SS_ACTIVE_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_PSTATE_SS_SHIFT 26
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_PSTATE_SS_MASK (1 << ARM_TBFLAG_PSTATE_SS_SHIFT)
 | 
					 | 
				
			||||||
/* Target EL if we take a floating-point-disabled exception */
 | 
					/* Target EL if we take a floating-point-disabled exception */
 | 
				
			||||||
#define ARM_TBFLAG_FPEXC_EL_SHIFT 24
 | 
					FIELD(TBFLAG_ANY, FPEXC_EL, 24, 2)
 | 
				
			||||||
#define ARM_TBFLAG_FPEXC_EL_MASK (0x3 << ARM_TBFLAG_FPEXC_EL_SHIFT)
 | 
					FIELD(TBFLAG_ANY, BE_DATA, 23, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Bit usage when in AArch32 state: */
 | 
					/* Bit usage when in AArch32 state: */
 | 
				
			||||||
#define ARM_TBFLAG_THUMB_SHIFT      0
 | 
					FIELD(TBFLAG_A32, THUMB, 0, 1)
 | 
				
			||||||
#define ARM_TBFLAG_THUMB_MASK       (1 << ARM_TBFLAG_THUMB_SHIFT)
 | 
					FIELD(TBFLAG_A32, VECLEN, 1, 3)
 | 
				
			||||||
#define ARM_TBFLAG_VECLEN_SHIFT     1
 | 
					FIELD(TBFLAG_A32, VECSTRIDE, 4, 2)
 | 
				
			||||||
#define ARM_TBFLAG_VECLEN_MASK      (0x7 << ARM_TBFLAG_VECLEN_SHIFT)
 | 
					FIELD(TBFLAG_A32, VFPEN, 7, 1)
 | 
				
			||||||
#define ARM_TBFLAG_VECSTRIDE_SHIFT  4
 | 
					FIELD(TBFLAG_A32, CONDEXEC, 8, 8)
 | 
				
			||||||
#define ARM_TBFLAG_VECSTRIDE_MASK   (0x3 << ARM_TBFLAG_VECSTRIDE_SHIFT)
 | 
					FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
 | 
				
			||||||
#define ARM_TBFLAG_VFPEN_SHIFT      7
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_VFPEN_MASK       (1 << ARM_TBFLAG_VFPEN_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_CONDEXEC_SHIFT   8
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_CONDEXEC_MASK    (0xff << ARM_TBFLAG_CONDEXEC_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_SCTLR_B_SHIFT    16
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_SCTLR_B_MASK     (1 << ARM_TBFLAG_SCTLR_B_SHIFT)
 | 
					 | 
				
			||||||
/* We store the bottom two bits of the CPAR as TB flags and handle
 | 
					/* We store the bottom two bits of the CPAR as TB flags and handle
 | 
				
			||||||
 * checks on the other bits at runtime
 | 
					 * checks on the other bits at runtime
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define ARM_TBFLAG_XSCALE_CPAR_SHIFT 17
 | 
					FIELD(TBFLAG_A32, XSCALE_CPAR, 17, 2)
 | 
				
			||||||
#define ARM_TBFLAG_XSCALE_CPAR_MASK (3 << ARM_TBFLAG_XSCALE_CPAR_SHIFT)
 | 
					 | 
				
			||||||
/* Indicates whether cp register reads and writes by guest code should access
 | 
					/* Indicates whether cp register reads and writes by guest code should access
 | 
				
			||||||
 * the secure or nonsecure bank of banked registers; note that this is not
 | 
					 * the secure or nonsecure bank of banked registers; note that this is not
 | 
				
			||||||
 * the same thing as the current security state of the processor!
 | 
					 * the same thing as the current security state of the processor!
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define ARM_TBFLAG_NS_SHIFT         19
 | 
					FIELD(TBFLAG_A32, NS, 19, 1)
 | 
				
			||||||
#define ARM_TBFLAG_NS_MASK          (1 << ARM_TBFLAG_NS_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_BE_DATA_SHIFT    20
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_BE_DATA_MASK     (1 << ARM_TBFLAG_BE_DATA_SHIFT)
 | 
					 | 
				
			||||||
/* For M profile only, Handler (ie not Thread) mode */
 | 
					/* For M profile only, Handler (ie not Thread) mode */
 | 
				
			||||||
#define ARM_TBFLAG_HANDLER_SHIFT    21
 | 
					FIELD(TBFLAG_A32, HANDLER, 21, 1)
 | 
				
			||||||
#define ARM_TBFLAG_HANDLER_MASK     (1 << ARM_TBFLAG_HANDLER_SHIFT)
 | 
					 | 
				
			||||||
/* For M profile only, whether we should generate stack-limit checks */
 | 
					/* For M profile only, whether we should generate stack-limit checks */
 | 
				
			||||||
#define ARM_TBFLAG_STACKCHECK_SHIFT 22
 | 
					FIELD(TBFLAG_A32, STACKCHECK, 22, 1)
 | 
				
			||||||
#define ARM_TBFLAG_STACKCHECK_MASK  (1 << ARM_TBFLAG_STACKCHECK_SHIFT)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Bit usage when in AArch64 state */
 | 
					/* Bit usage when in AArch64 state */
 | 
				
			||||||
#define ARM_TBFLAG_TBI0_SHIFT 0        /* TBI0 for EL0/1 or TBI for EL2/3 */
 | 
					FIELD(TBFLAG_A64, TBI0, 0, 1)
 | 
				
			||||||
#define ARM_TBFLAG_TBI0_MASK (0x1ull << ARM_TBFLAG_TBI0_SHIFT)
 | 
					FIELD(TBFLAG_A64, TBI1, 1, 1)
 | 
				
			||||||
#define ARM_TBFLAG_TBI1_SHIFT 1        /* TBI1 for EL0/1  */
 | 
					FIELD(TBFLAG_A64, SVEEXC_EL, 2, 2)
 | 
				
			||||||
#define ARM_TBFLAG_TBI1_MASK (0x1ull << ARM_TBFLAG_TBI1_SHIFT)
 | 
					FIELD(TBFLAG_A64, ZCR_LEN, 4, 4)
 | 
				
			||||||
#define ARM_TBFLAG_SVEEXC_EL_SHIFT  2
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_SVEEXC_EL_MASK   (0x3 << ARM_TBFLAG_SVEEXC_EL_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_ZCR_LEN_SHIFT    4
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_ZCR_LEN_MASK     (0xf << ARM_TBFLAG_ZCR_LEN_SHIFT)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* some convenience accessor macros */
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_AARCH64_STATE(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_AARCH64_STATE_MASK) >> ARM_TBFLAG_AARCH64_STATE_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_MMUIDX(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_MMUIDX_MASK) >> ARM_TBFLAG_MMUIDX_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_SS_ACTIVE(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_SS_ACTIVE_MASK) >> ARM_TBFLAG_SS_ACTIVE_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_PSTATE_SS(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_PSTATE_SS_MASK) >> ARM_TBFLAG_PSTATE_SS_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_FPEXC_EL(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_FPEXC_EL_MASK) >> ARM_TBFLAG_FPEXC_EL_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_THUMB(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_THUMB_MASK) >> ARM_TBFLAG_THUMB_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_VECLEN(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_VECLEN_MASK) >> ARM_TBFLAG_VECLEN_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_VECSTRIDE(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_VECSTRIDE_MASK) >> ARM_TBFLAG_VECSTRIDE_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_VFPEN(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_VFPEN_MASK) >> ARM_TBFLAG_VFPEN_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_CONDEXEC(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_CONDEXEC_MASK) >> ARM_TBFLAG_CONDEXEC_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_SCTLR_B(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_SCTLR_B_MASK) >> ARM_TBFLAG_SCTLR_B_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_XSCALE_CPAR(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_XSCALE_CPAR_MASK) >> ARM_TBFLAG_XSCALE_CPAR_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_NS(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_NS_MASK) >> ARM_TBFLAG_NS_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_BE_DATA(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_BE_DATA_MASK) >> ARM_TBFLAG_BE_DATA_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_HANDLER(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_HANDLER_MASK) >> ARM_TBFLAG_HANDLER_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_STACKCHECK(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_STACKCHECK_MASK) >> ARM_TBFLAG_STACKCHECK_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_TBI0(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_TBI0_MASK) >> ARM_TBFLAG_TBI0_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_TBI1(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_TBI1_MASK) >> ARM_TBFLAG_TBI1_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_SVEEXC_EL(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_SVEEXC_EL_MASK) >> ARM_TBFLAG_SVEEXC_EL_SHIFT)
 | 
					 | 
				
			||||||
#define ARM_TBFLAG_ZCR_LEN(F) \
 | 
					 | 
				
			||||||
    (((F) & ARM_TBFLAG_ZCR_LEN_MASK) >> ARM_TBFLAG_ZCR_LEN_SHIFT)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline bool bswap_code(bool sctlr_b)
 | 
					static inline bool bswap_code(bool sctlr_b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
				
			|||||||
@ -12955,16 +12955,18 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
 | 
				
			|||||||
    ARMMMUIdx mmu_idx = core_to_arm_mmu_idx(env, cpu_mmu_index(env, false));
 | 
					    ARMMMUIdx mmu_idx = core_to_arm_mmu_idx(env, cpu_mmu_index(env, false));
 | 
				
			||||||
    int current_el = arm_current_el(env);
 | 
					    int current_el = arm_current_el(env);
 | 
				
			||||||
    int fp_el = fp_exception_el(env, current_el);
 | 
					    int fp_el = fp_exception_el(env, current_el);
 | 
				
			||||||
    uint32_t flags;
 | 
					    uint32_t flags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (is_a64(env)) {
 | 
					    if (is_a64(env)) {
 | 
				
			||||||
        ARMCPU *cpu = arm_env_get_cpu(env);
 | 
					        ARMCPU *cpu = arm_env_get_cpu(env);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        *pc = env->pc;
 | 
					        *pc = env->pc;
 | 
				
			||||||
        flags = ARM_TBFLAG_AARCH64_STATE_MASK;
 | 
					        flags = FIELD_DP32(flags, TBFLAG_ANY, AARCH64_STATE, 1);
 | 
				
			||||||
        /* Get control bits for tagged addresses */
 | 
					        /* Get control bits for tagged addresses */
 | 
				
			||||||
        flags |= (arm_regime_tbi0(env, mmu_idx) << ARM_TBFLAG_TBI0_SHIFT);
 | 
					        flags = FIELD_DP32(flags, TBFLAG_A64, TBI0,
 | 
				
			||||||
        flags |= (arm_regime_tbi1(env, mmu_idx) << ARM_TBFLAG_TBI1_SHIFT);
 | 
					                           arm_regime_tbi0(env, mmu_idx));
 | 
				
			||||||
 | 
					        flags = FIELD_DP32(flags, TBFLAG_A64, TBI1,
 | 
				
			||||||
 | 
					                           arm_regime_tbi1(env, mmu_idx));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (cpu_isar_feature(aa64_sve, cpu)) {
 | 
					        if (cpu_isar_feature(aa64_sve, cpu)) {
 | 
				
			||||||
            int sve_el = sve_exception_el(env, current_el);
 | 
					            int sve_el = sve_exception_el(env, current_el);
 | 
				
			||||||
@ -12978,28 +12980,25 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
 | 
				
			|||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                zcr_len = sve_zcr_len_for_el(env, current_el);
 | 
					                zcr_len = sve_zcr_len_for_el(env, current_el);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            flags |= sve_el << ARM_TBFLAG_SVEEXC_EL_SHIFT;
 | 
					            flags = FIELD_DP32(flags, TBFLAG_A64, SVEEXC_EL, sve_el);
 | 
				
			||||||
            flags |= zcr_len << ARM_TBFLAG_ZCR_LEN_SHIFT;
 | 
					            flags = FIELD_DP32(flags, TBFLAG_A64, ZCR_LEN, zcr_len);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        *pc = env->regs[15];
 | 
					        *pc = env->regs[15];
 | 
				
			||||||
        flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
 | 
					        flags = FIELD_DP32(flags, TBFLAG_A32, THUMB, env->thumb);
 | 
				
			||||||
            | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
 | 
					        flags = FIELD_DP32(flags, TBFLAG_A32, VECLEN, env->vfp.vec_len);
 | 
				
			||||||
            | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
 | 
					        flags = FIELD_DP32(flags, TBFLAG_A32, VECSTRIDE, env->vfp.vec_stride);
 | 
				
			||||||
            | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
 | 
					        flags = FIELD_DP32(flags, TBFLAG_A32, CONDEXEC, env->condexec_bits);
 | 
				
			||||||
            | (arm_sctlr_b(env) << ARM_TBFLAG_SCTLR_B_SHIFT);
 | 
					        flags = FIELD_DP32(flags, TBFLAG_A32, SCTLR_B, arm_sctlr_b(env));
 | 
				
			||||||
        if (!(access_secure_reg(env))) {
 | 
					        flags = FIELD_DP32(flags, TBFLAG_A32, NS, !access_secure_reg(env));
 | 
				
			||||||
            flags |= ARM_TBFLAG_NS_MASK;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)
 | 
					        if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)
 | 
				
			||||||
            || arm_el_is_aa64(env, 1)) {
 | 
					            || arm_el_is_aa64(env, 1)) {
 | 
				
			||||||
            flags |= ARM_TBFLAG_VFPEN_MASK;
 | 
					            flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        flags |= (extract32(env->cp15.c15_cpar, 0, 2)
 | 
					        flags = FIELD_DP32(flags, TBFLAG_A32, XSCALE_CPAR, env->cp15.c15_cpar);
 | 
				
			||||||
                  << ARM_TBFLAG_XSCALE_CPAR_SHIFT);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    flags |= (arm_to_core_mmu_idx(mmu_idx) << ARM_TBFLAG_MMUIDX_SHIFT);
 | 
					    flags = FIELD_DP32(flags, TBFLAG_ANY, MMUIDX, arm_to_core_mmu_idx(mmu_idx));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* The SS_ACTIVE and PSTATE_SS bits correspond to the state machine
 | 
					    /* The SS_ACTIVE and PSTATE_SS bits correspond to the state machine
 | 
				
			||||||
     * states defined in the ARM ARM for software singlestep:
 | 
					     * states defined in the ARM ARM for software singlestep:
 | 
				
			||||||
@ -13009,24 +13008,24 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
 | 
				
			|||||||
     *     1            1       Active-not-pending
 | 
					     *     1            1       Active-not-pending
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    if (arm_singlestep_active(env)) {
 | 
					    if (arm_singlestep_active(env)) {
 | 
				
			||||||
        flags |= ARM_TBFLAG_SS_ACTIVE_MASK;
 | 
					        flags = FIELD_DP32(flags, TBFLAG_ANY, SS_ACTIVE, 1);
 | 
				
			||||||
        if (is_a64(env)) {
 | 
					        if (is_a64(env)) {
 | 
				
			||||||
            if (env->pstate & PSTATE_SS) {
 | 
					            if (env->pstate & PSTATE_SS) {
 | 
				
			||||||
                flags |= ARM_TBFLAG_PSTATE_SS_MASK;
 | 
					                flags = FIELD_DP32(flags, TBFLAG_ANY, PSTATE_SS, 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            if (env->uncached_cpsr & PSTATE_SS) {
 | 
					            if (env->uncached_cpsr & PSTATE_SS) {
 | 
				
			||||||
                flags |= ARM_TBFLAG_PSTATE_SS_MASK;
 | 
					                flags = FIELD_DP32(flags, TBFLAG_ANY, PSTATE_SS, 1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (arm_cpu_data_is_big_endian(env)) {
 | 
					    if (arm_cpu_data_is_big_endian(env)) {
 | 
				
			||||||
        flags |= ARM_TBFLAG_BE_DATA_MASK;
 | 
					        flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    flags |= fp_el << ARM_TBFLAG_FPEXC_EL_SHIFT;
 | 
					    flags = FIELD_DP32(flags, TBFLAG_ANY, FPEXC_EL, fp_el);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (arm_v7m_is_handler_mode(env)) {
 | 
					    if (arm_v7m_is_handler_mode(env)) {
 | 
				
			||||||
        flags |= ARM_TBFLAG_HANDLER_MASK;
 | 
					        flags = FIELD_DP32(flags, TBFLAG_A32, HANDLER, 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* v8M always applies stack limit checks unless CCR.STKOFHFNMIGN is
 | 
					    /* v8M always applies stack limit checks unless CCR.STKOFHFNMIGN is
 | 
				
			||||||
@ -13036,7 +13035,7 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
 | 
				
			|||||||
        arm_feature(env, ARM_FEATURE_M) &&
 | 
					        arm_feature(env, ARM_FEATURE_M) &&
 | 
				
			||||||
        !((mmu_idx  & ARM_MMU_IDX_M_NEGPRI) &&
 | 
					        !((mmu_idx  & ARM_MMU_IDX_M_NEGPRI) &&
 | 
				
			||||||
          (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKOFHFNMIGN_MASK))) {
 | 
					          (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKOFHFNMIGN_MASK))) {
 | 
				
			||||||
        flags |= ARM_TBFLAG_STACKCHECK_MASK;
 | 
					        flags = FIELD_DP32(flags, TBFLAG_A32, STACKCHECK, 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    *pflags = flags;
 | 
					    *pflags = flags;
 | 
				
			||||||
 | 
				
			|||||||
@ -99,6 +99,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Two operand with governing predicate, flags setting
 | 
					# Two operand with governing predicate, flags setting
 | 
				
			||||||
@pd_pg_pn_s     ........ . s:1 ...... .. pg:4 . rn:4 . rd:4     &rpr_s
 | 
					@pd_pg_pn_s     ........ . s:1 ...... .. pg:4 . rn:4 . rd:4     &rpr_s
 | 
				
			||||||
 | 
					@pd_pg_pn_s0    ........ . .   ...... .. pg:4 . rn:4 . rd:4     &rpr_s s=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Three operand with unused vector element size
 | 
					# Three operand with unused vector element size
 | 
				
			||||||
@rd_rn_rm_e0    ........ ... rm:5 ... ... rn:5 rd:5             &rrr_esz esz=0
 | 
					@rd_rn_rm_e0    ........ ... rm:5 ... ... rn:5 rd:5             &rrr_esz esz=0
 | 
				
			||||||
@ -667,8 +668,8 @@ BRKPB           00100101 0. 00 .... 11 .... 0 .... 1 ....       @pd_pg_pn_pm_s
 | 
				
			|||||||
# SVE partition break condition
 | 
					# SVE partition break condition
 | 
				
			||||||
BRKA_z          00100101 0. 01000001 .... 0 .... 0 ....         @pd_pg_pn_s
 | 
					BRKA_z          00100101 0. 01000001 .... 0 .... 0 ....         @pd_pg_pn_s
 | 
				
			||||||
BRKB_z          00100101 1. 01000001 .... 0 .... 0 ....         @pd_pg_pn_s
 | 
					BRKB_z          00100101 1. 01000001 .... 0 .... 0 ....         @pd_pg_pn_s
 | 
				
			||||||
BRKA_m          00100101 0. 01000001 .... 0 .... 1 ....         @pd_pg_pn_s
 | 
					BRKA_m          00100101 00 01000001 .... 0 .... 1 ....         @pd_pg_pn_s0
 | 
				
			||||||
BRKB_m          00100101 1. 01000001 .... 0 .... 1 ....         @pd_pg_pn_s
 | 
					BRKB_m          00100101 10 01000001 .... 0 .... 1 ....         @pd_pg_pn_s0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# SVE propagate break to next partition
 | 
					# SVE propagate break to next partition
 | 
				
			||||||
BRKN            00100101 0. 01100001 .... 0 .... 0 ....         @pd_pg_pn_s
 | 
					BRKN            00100101 0. 01100001 .... 0 .... 0 ....         @pd_pg_pn_s
 | 
				
			||||||
 | 
				
			|||||||
@ -13380,7 +13380,8 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
 | 
				
			|||||||
    DisasContext *dc = container_of(dcbase, DisasContext, base);
 | 
					    DisasContext *dc = container_of(dcbase, DisasContext, base);
 | 
				
			||||||
    CPUARMState *env = cpu->env_ptr;
 | 
					    CPUARMState *env = cpu->env_ptr;
 | 
				
			||||||
    ARMCPU *arm_cpu = arm_env_get_cpu(env);
 | 
					    ARMCPU *arm_cpu = arm_env_get_cpu(env);
 | 
				
			||||||
    int bound;
 | 
					    uint32_t tb_flags = dc->base.tb->flags;
 | 
				
			||||||
 | 
					    int bound, core_mmu_idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dc->isar = &arm_cpu->isar;
 | 
					    dc->isar = &arm_cpu->isar;
 | 
				
			||||||
    dc->pc = dc->base.pc_first;
 | 
					    dc->pc = dc->base.pc_first;
 | 
				
			||||||
@ -13394,19 +13395,20 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
 | 
				
			|||||||
                               !arm_el_is_aa64(env, 3);
 | 
					                               !arm_el_is_aa64(env, 3);
 | 
				
			||||||
    dc->thumb = 0;
 | 
					    dc->thumb = 0;
 | 
				
			||||||
    dc->sctlr_b = 0;
 | 
					    dc->sctlr_b = 0;
 | 
				
			||||||
    dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE;
 | 
					    dc->be_data = FIELD_EX32(tb_flags, TBFLAG_ANY, BE_DATA) ? MO_BE : MO_LE;
 | 
				
			||||||
    dc->condexec_mask = 0;
 | 
					    dc->condexec_mask = 0;
 | 
				
			||||||
    dc->condexec_cond = 0;
 | 
					    dc->condexec_cond = 0;
 | 
				
			||||||
    dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(dc->base.tb->flags));
 | 
					    core_mmu_idx = FIELD_EX32(tb_flags, TBFLAG_ANY, MMUIDX);
 | 
				
			||||||
    dc->tbi0 = ARM_TBFLAG_TBI0(dc->base.tb->flags);
 | 
					    dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx);
 | 
				
			||||||
    dc->tbi1 = ARM_TBFLAG_TBI1(dc->base.tb->flags);
 | 
					    dc->tbi0 = FIELD_EX32(tb_flags, TBFLAG_A64, TBI0);
 | 
				
			||||||
 | 
					    dc->tbi1 = FIELD_EX32(tb_flags, TBFLAG_A64, TBI1);
 | 
				
			||||||
    dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
 | 
					    dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
 | 
				
			||||||
#if !defined(CONFIG_USER_ONLY)
 | 
					#if !defined(CONFIG_USER_ONLY)
 | 
				
			||||||
    dc->user = (dc->current_el == 0);
 | 
					    dc->user = (dc->current_el == 0);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
 | 
					    dc->fp_excp_el = FIELD_EX32(tb_flags, TBFLAG_ANY, FPEXC_EL);
 | 
				
			||||||
    dc->sve_excp_el = ARM_TBFLAG_SVEEXC_EL(dc->base.tb->flags);
 | 
					    dc->sve_excp_el = FIELD_EX32(tb_flags, TBFLAG_A64, SVEEXC_EL);
 | 
				
			||||||
    dc->sve_len = (ARM_TBFLAG_ZCR_LEN(dc->base.tb->flags) + 1) * 16;
 | 
					    dc->sve_len = (FIELD_EX32(tb_flags, TBFLAG_A64, ZCR_LEN) + 1) * 16;
 | 
				
			||||||
    dc->vec_len = 0;
 | 
					    dc->vec_len = 0;
 | 
				
			||||||
    dc->vec_stride = 0;
 | 
					    dc->vec_stride = 0;
 | 
				
			||||||
    dc->cp_regs = arm_cpu->cp_regs;
 | 
					    dc->cp_regs = arm_cpu->cp_regs;
 | 
				
			||||||
@ -13427,8 +13429,8 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
 | 
				
			|||||||
     *   emit code to generate a software step exception
 | 
					     *   emit code to generate a software step exception
 | 
				
			||||||
     *   end the TB
 | 
					     *   end the TB
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
 | 
					    dc->ss_active = FIELD_EX32(tb_flags, TBFLAG_ANY, SS_ACTIVE);
 | 
				
			||||||
    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
 | 
					    dc->pstate_ss = FIELD_EX32(tb_flags, TBFLAG_ANY, PSTATE_SS);
 | 
				
			||||||
    dc->is_ldex = false;
 | 
					    dc->is_ldex = false;
 | 
				
			||||||
    dc->ss_same_el = (arm_debug_target_el(env) == dc->current_el);
 | 
					    dc->ss_same_el = (arm_debug_target_el(env) == dc->current_el);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9733,6 +9733,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
 | 
				
			|||||||
                    rd = (insn >> 12) & 0xf;
 | 
					                    rd = (insn >> 12) & 0xf;
 | 
				
			||||||
                    if (insn & (1 << 23)) {
 | 
					                    if (insn & (1 << 23)) {
 | 
				
			||||||
                        /* load/store exclusive */
 | 
					                        /* load/store exclusive */
 | 
				
			||||||
 | 
					                        bool is_ld = extract32(insn, 20, 1);
 | 
				
			||||||
 | 
					                        bool is_lasr = !extract32(insn, 8, 1);
 | 
				
			||||||
                        int op2 = (insn >> 8) & 3;
 | 
					                        int op2 = (insn >> 8) & 3;
 | 
				
			||||||
                        op1 = (insn >> 21) & 0x3;
 | 
					                        op1 = (insn >> 21) & 0x3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -9760,11 +9762,12 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
 | 
				
			|||||||
                        addr = tcg_temp_local_new_i32();
 | 
					                        addr = tcg_temp_local_new_i32();
 | 
				
			||||||
                        load_reg_var(s, addr, rn);
 | 
					                        load_reg_var(s, addr, rn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        /* Since the emulation does not have barriers,
 | 
					                        if (is_lasr && !is_ld) {
 | 
				
			||||||
                           the acquire/release semantics need no special
 | 
					                            tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
 | 
				
			||||||
                           handling */
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        if (op2 == 0) {
 | 
					                        if (op2 == 0) {
 | 
				
			||||||
                            if (insn & (1 << 20)) {
 | 
					                            if (is_ld) {
 | 
				
			||||||
                                tmp = tcg_temp_new_i32();
 | 
					                                tmp = tcg_temp_new_i32();
 | 
				
			||||||
                                switch (op1) {
 | 
					                                switch (op1) {
 | 
				
			||||||
                                case 0: /* lda */
 | 
					                                case 0: /* lda */
 | 
				
			||||||
@ -9810,7 +9813,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
 | 
				
			|||||||
                                }
 | 
					                                }
 | 
				
			||||||
                                tcg_temp_free_i32(tmp);
 | 
					                                tcg_temp_free_i32(tmp);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        } else if (insn & (1 << 20)) {
 | 
					                        } else if (is_ld) {
 | 
				
			||||||
                            switch (op1) {
 | 
					                            switch (op1) {
 | 
				
			||||||
                            case 0: /* ldrex */
 | 
					                            case 0: /* ldrex */
 | 
				
			||||||
                                gen_load_exclusive(s, rd, 15, addr, 2);
 | 
					                                gen_load_exclusive(s, rd, 15, addr, 2);
 | 
				
			||||||
@ -9847,6 +9850,10 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
 | 
				
			|||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        tcg_temp_free_i32(addr);
 | 
					                        tcg_temp_free_i32(addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (is_lasr && is_ld) {
 | 
				
			||||||
 | 
					                            tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                    } else if ((insn & 0x00300f00) == 0) {
 | 
					                    } else if ((insn & 0x00300f00) == 0) {
 | 
				
			||||||
                        /* 0bcccc_0001_0x00_xxxx_xxxx_0000_1001_xxxx
 | 
					                        /* 0bcccc_0001_0x00_xxxx_xxxx_0000_1001_xxxx
 | 
				
			||||||
                        *  - SWP, SWPB
 | 
					                        *  - SWP, SWPB
 | 
				
			||||||
@ -10862,6 +10869,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
 | 
				
			|||||||
                tcg_gen_addi_i32(tmp, tmp, s->pc);
 | 
					                tcg_gen_addi_i32(tmp, tmp, s->pc);
 | 
				
			||||||
                store_reg(s, 15, tmp);
 | 
					                store_reg(s, 15, tmp);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
 | 
					                bool is_lasr = false;
 | 
				
			||||||
 | 
					                bool is_ld = extract32(insn, 20, 1);
 | 
				
			||||||
                int op2 = (insn >> 6) & 0x3;
 | 
					                int op2 = (insn >> 6) & 0x3;
 | 
				
			||||||
                op = (insn >> 4) & 0x3;
 | 
					                op = (insn >> 4) & 0x3;
 | 
				
			||||||
                switch (op2) {
 | 
					                switch (op2) {
 | 
				
			||||||
@ -10883,12 +10892,18 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
 | 
				
			|||||||
                case 3:
 | 
					                case 3:
 | 
				
			||||||
                    /* Load-acquire/store-release exclusive */
 | 
					                    /* Load-acquire/store-release exclusive */
 | 
				
			||||||
                    ARCH(8);
 | 
					                    ARCH(8);
 | 
				
			||||||
 | 
					                    is_lasr = true;
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (is_lasr && !is_ld) {
 | 
				
			||||||
 | 
					                    tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                addr = tcg_temp_local_new_i32();
 | 
					                addr = tcg_temp_local_new_i32();
 | 
				
			||||||
                load_reg_var(s, addr, rn);
 | 
					                load_reg_var(s, addr, rn);
 | 
				
			||||||
                if (!(op2 & 1)) {
 | 
					                if (!(op2 & 1)) {
 | 
				
			||||||
                    if (insn & (1 << 20)) {
 | 
					                    if (is_ld) {
 | 
				
			||||||
                        tmp = tcg_temp_new_i32();
 | 
					                        tmp = tcg_temp_new_i32();
 | 
				
			||||||
                        switch (op) {
 | 
					                        switch (op) {
 | 
				
			||||||
                        case 0: /* ldab */
 | 
					                        case 0: /* ldab */
 | 
				
			||||||
@ -10927,12 +10942,16 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        tcg_temp_free_i32(tmp);
 | 
					                        tcg_temp_free_i32(tmp);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                } else if (insn & (1 << 20)) {
 | 
					                } else if (is_ld) {
 | 
				
			||||||
                    gen_load_exclusive(s, rs, rd, addr, op);
 | 
					                    gen_load_exclusive(s, rs, rd, addr, op);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    gen_store_exclusive(s, rm, rs, rd, addr, op);
 | 
					                    gen_store_exclusive(s, rm, rs, rd, addr, op);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                tcg_temp_free_i32(addr);
 | 
					                tcg_temp_free_i32(addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (is_lasr && is_ld) {
 | 
				
			||||||
 | 
					                    tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            /* Load/store multiple, RFE, SRS.  */
 | 
					            /* Load/store multiple, RFE, SRS.  */
 | 
				
			||||||
@ -13021,6 +13040,8 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
 | 
				
			|||||||
    DisasContext *dc = container_of(dcbase, DisasContext, base);
 | 
					    DisasContext *dc = container_of(dcbase, DisasContext, base);
 | 
				
			||||||
    CPUARMState *env = cs->env_ptr;
 | 
					    CPUARMState *env = cs->env_ptr;
 | 
				
			||||||
    ARMCPU *cpu = arm_env_get_cpu(env);
 | 
					    ARMCPU *cpu = arm_env_get_cpu(env);
 | 
				
			||||||
 | 
					    uint32_t tb_flags = dc->base.tb->flags;
 | 
				
			||||||
 | 
					    uint32_t condexec, core_mmu_idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dc->isar = &cpu->isar;
 | 
					    dc->isar = &cpu->isar;
 | 
				
			||||||
    dc->pc = dc->base.pc_first;
 | 
					    dc->pc = dc->base.pc_first;
 | 
				
			||||||
@ -13032,26 +13053,28 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
 | 
					    dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
 | 
				
			||||||
                               !arm_el_is_aa64(env, 3);
 | 
					                               !arm_el_is_aa64(env, 3);
 | 
				
			||||||
    dc->thumb = ARM_TBFLAG_THUMB(dc->base.tb->flags);
 | 
					    dc->thumb = FIELD_EX32(tb_flags, TBFLAG_A32, THUMB);
 | 
				
			||||||
    dc->sctlr_b = ARM_TBFLAG_SCTLR_B(dc->base.tb->flags);
 | 
					    dc->sctlr_b = FIELD_EX32(tb_flags, TBFLAG_A32, SCTLR_B);
 | 
				
			||||||
    dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE;
 | 
					    dc->be_data = FIELD_EX32(tb_flags, TBFLAG_ANY, BE_DATA) ? MO_BE : MO_LE;
 | 
				
			||||||
    dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) & 0xf) << 1;
 | 
					    condexec = FIELD_EX32(tb_flags, TBFLAG_A32, CONDEXEC);
 | 
				
			||||||
    dc->condexec_cond = ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) >> 4;
 | 
					    dc->condexec_mask = (condexec & 0xf) << 1;
 | 
				
			||||||
    dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(dc->base.tb->flags));
 | 
					    dc->condexec_cond = condexec >> 4;
 | 
				
			||||||
 | 
					    core_mmu_idx = FIELD_EX32(tb_flags, TBFLAG_ANY, MMUIDX);
 | 
				
			||||||
 | 
					    dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx);
 | 
				
			||||||
    dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
 | 
					    dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
 | 
				
			||||||
#if !defined(CONFIG_USER_ONLY)
 | 
					#if !defined(CONFIG_USER_ONLY)
 | 
				
			||||||
    dc->user = (dc->current_el == 0);
 | 
					    dc->user = (dc->current_el == 0);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    dc->ns = ARM_TBFLAG_NS(dc->base.tb->flags);
 | 
					    dc->ns = FIELD_EX32(tb_flags, TBFLAG_A32, NS);
 | 
				
			||||||
    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
 | 
					    dc->fp_excp_el = FIELD_EX32(tb_flags, TBFLAG_ANY, FPEXC_EL);
 | 
				
			||||||
    dc->vfp_enabled = ARM_TBFLAG_VFPEN(dc->base.tb->flags);
 | 
					    dc->vfp_enabled = FIELD_EX32(tb_flags, TBFLAG_A32, VFPEN);
 | 
				
			||||||
    dc->vec_len = ARM_TBFLAG_VECLEN(dc->base.tb->flags);
 | 
					    dc->vec_len = FIELD_EX32(tb_flags, TBFLAG_A32, VECLEN);
 | 
				
			||||||
    dc->vec_stride = ARM_TBFLAG_VECSTRIDE(dc->base.tb->flags);
 | 
					    dc->vec_stride = FIELD_EX32(tb_flags, TBFLAG_A32, VECSTRIDE);
 | 
				
			||||||
    dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(dc->base.tb->flags);
 | 
					    dc->c15_cpar = FIELD_EX32(tb_flags, TBFLAG_A32, XSCALE_CPAR);
 | 
				
			||||||
    dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(dc->base.tb->flags);
 | 
					    dc->v7m_handler_mode = FIELD_EX32(tb_flags, TBFLAG_A32, HANDLER);
 | 
				
			||||||
    dc->v8m_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
 | 
					    dc->v8m_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
 | 
				
			||||||
        regime_is_secure(env, dc->mmu_idx);
 | 
					        regime_is_secure(env, dc->mmu_idx);
 | 
				
			||||||
    dc->v8m_stackcheck = ARM_TBFLAG_STACKCHECK(dc->base.tb->flags);
 | 
					    dc->v8m_stackcheck = FIELD_EX32(tb_flags, TBFLAG_A32, STACKCHECK);
 | 
				
			||||||
    dc->cp_regs = cpu->cp_regs;
 | 
					    dc->cp_regs = cpu->cp_regs;
 | 
				
			||||||
    dc->features = env->features;
 | 
					    dc->features = env->features;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -13070,8 +13093,8 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
 | 
				
			|||||||
     *   emit code to generate a software step exception
 | 
					     *   emit code to generate a software step exception
 | 
				
			||||||
     *   end the TB
 | 
					     *   end the TB
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
 | 
					    dc->ss_active = FIELD_EX32(tb_flags, TBFLAG_ANY, SS_ACTIVE);
 | 
				
			||||||
    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
 | 
					    dc->pstate_ss = FIELD_EX32(tb_flags, TBFLAG_ANY, PSTATE_SS);
 | 
				
			||||||
    dc->is_ldex = false;
 | 
					    dc->is_ldex = false;
 | 
				
			||||||
    dc->ss_same_el = false; /* Can't be true since EL_d must be AArch64 */
 | 
					    dc->ss_same_el = false; /* Can't be true since EL_d must be AArch64 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -13516,11 +13539,11 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
 | 
				
			|||||||
    DisasContext dc;
 | 
					    DisasContext dc;
 | 
				
			||||||
    const TranslatorOps *ops = &arm_translator_ops;
 | 
					    const TranslatorOps *ops = &arm_translator_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ARM_TBFLAG_THUMB(tb->flags)) {
 | 
					    if (FIELD_EX32(tb->flags, TBFLAG_A32, THUMB)) {
 | 
				
			||||||
        ops = &thumb_translator_ops;
 | 
					        ops = &thumb_translator_ops;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#ifdef TARGET_AARCH64
 | 
					#ifdef TARGET_AARCH64
 | 
				
			||||||
    if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
 | 
					    if (FIELD_EX32(tb->flags, TBFLAG_ANY, AARCH64_STATE)) {
 | 
				
			||||||
        ops = &aarch64_translator_ops;
 | 
					        ops = &aarch64_translator_ops;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -277,6 +277,7 @@ check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
 | 
				
			|||||||
check-qtest-arm-y += tests/tmp105-test$(EXESUF)
 | 
					check-qtest-arm-y += tests/tmp105-test$(EXESUF)
 | 
				
			||||||
check-qtest-arm-y += tests/pca9552-test$(EXESUF)
 | 
					check-qtest-arm-y += tests/pca9552-test$(EXESUF)
 | 
				
			||||||
check-qtest-arm-y += tests/ds1338-test$(EXESUF)
 | 
					check-qtest-arm-y += tests/ds1338-test$(EXESUF)
 | 
				
			||||||
 | 
					check-qtest-arm-y += tests/microbit-test$(EXESUF)
 | 
				
			||||||
check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 | 
					check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 | 
				
			||||||
check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
 | 
					check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
 | 
				
			||||||
check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
 | 
					check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
 | 
				
			||||||
@ -708,6 +709,7 @@ tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
 | 
				
			|||||||
tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
 | 
					tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
 | 
				
			||||||
tests/pca9552-test$(EXESUF): tests/pca9552-test.o $(libqos-omap-obj-y)
 | 
					tests/pca9552-test$(EXESUF): tests/pca9552-test.o $(libqos-omap-obj-y)
 | 
				
			||||||
tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
 | 
					tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
 | 
				
			||||||
 | 
					tests/microbit-test$(EXESUF): tests/microbit-test.o
 | 
				
			||||||
tests/m25p80-test$(EXESUF): tests/m25p80-test.o
 | 
					tests/m25p80-test$(EXESUF): tests/m25p80-test.o
 | 
				
			||||||
tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 | 
					tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 | 
				
			||||||
tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
 | 
					tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
 | 
				
			||||||
 | 
				
			|||||||
@ -753,6 +753,16 @@ void qtest_irq_intercept_in(QTestState *s, const char *qom_path)
 | 
				
			|||||||
    qtest_rsp(s, 0);
 | 
					    qtest_rsp(s, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void qtest_set_irq_in(QTestState *s, const char *qom_path, const char *name,
 | 
				
			||||||
 | 
					                      int num, int level)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!name) {
 | 
				
			||||||
 | 
					        name = "unnamed-gpio-in";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    qtest_sendf(s, "set_irq_in %s %s %d %d\n", qom_path, name, num, level);
 | 
				
			||||||
 | 
					    qtest_rsp(s, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void qtest_out(QTestState *s, const char *cmd, uint16_t addr, uint32_t value)
 | 
					static void qtest_out(QTestState *s, const char *cmd, uint16_t addr, uint32_t value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    qtest_sendf(s, "%s 0x%x 0x%x\n", cmd, addr, value);
 | 
					    qtest_sendf(s, "%s 0x%x 0x%x\n", cmd, addr, value);
 | 
				
			||||||
 | 
				
			|||||||
@ -230,6 +230,19 @@ void qtest_irq_intercept_in(QTestState *s, const char *string);
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
void qtest_irq_intercept_out(QTestState *s, const char *string);
 | 
					void qtest_irq_intercept_out(QTestState *s, const char *string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * qtest_set_irq_in:
 | 
				
			||||||
 | 
					 * @s: QTestState instance to operate on.
 | 
				
			||||||
 | 
					 * @string: QOM path of a device
 | 
				
			||||||
 | 
					 * @name: IRQ name
 | 
				
			||||||
 | 
					 * @irq: IRQ number
 | 
				
			||||||
 | 
					 * @level: IRQ level
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Force given device/irq GPIO-in pin to the given level.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void qtest_set_irq_in(QTestState *s, const char *string, const char *name,
 | 
				
			||||||
 | 
					                      int irq, int level);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * qtest_outb:
 | 
					 * qtest_outb:
 | 
				
			||||||
 * @s: #QTestState instance to operate on.
 | 
					 * @s: #QTestState instance to operate on.
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										255
									
								
								tests/microbit-test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								tests/microbit-test.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,255 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * QTest testcase for Microbit board using the Nordic Semiconductor nRF51 SoC.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * nRF51:
 | 
				
			||||||
 | 
					 * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
 | 
				
			||||||
 | 
					 * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Microbit Board: http://microbit.org/
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This code is licensed under the GPL version 2 or later.  See
 | 
				
			||||||
 | 
					 * the COPYING file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qemu/osdep.h"
 | 
				
			||||||
 | 
					#include "exec/hwaddr.h"
 | 
				
			||||||
 | 
					#include "libqtest.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "hw/arm/nrf51.h"
 | 
				
			||||||
 | 
					#include "hw/gpio/nrf51_gpio.h"
 | 
				
			||||||
 | 
					#include "hw/timer/nrf51_timer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_nrf51_gpio(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    size_t i;
 | 
				
			||||||
 | 
					    uint32_t actual, expected;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct {
 | 
				
			||||||
 | 
					        hwaddr addr;
 | 
				
			||||||
 | 
					        uint32_t expected;
 | 
				
			||||||
 | 
					    } const reset_state[] = {
 | 
				
			||||||
 | 
					        {NRF51_GPIO_REG_OUT, 0x00000000}, {NRF51_GPIO_REG_OUTSET, 0x00000000},
 | 
				
			||||||
 | 
					        {NRF51_GPIO_REG_OUTCLR, 0x00000000}, {NRF51_GPIO_REG_IN, 0x00000000},
 | 
				
			||||||
 | 
					        {NRF51_GPIO_REG_DIR, 0x00000000}, {NRF51_GPIO_REG_DIRSET, 0x00000000},
 | 
				
			||||||
 | 
					        {NRF51_GPIO_REG_DIRCLR, 0x00000000}
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Check reset state */
 | 
				
			||||||
 | 
					    for (i = 0; i < ARRAY_SIZE(reset_state); i++) {
 | 
				
			||||||
 | 
					        expected = reset_state[i].expected;
 | 
				
			||||||
 | 
					        actual = readl(NRF51_GPIO_BASE + reset_state[i].addr);
 | 
				
			||||||
 | 
					        g_assert_cmpuint(actual, ==, expected);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < NRF51_GPIO_PINS; i++) {
 | 
				
			||||||
 | 
					        expected = 0x00000002;
 | 
				
			||||||
 | 
					        actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START + i * 4);
 | 
				
			||||||
 | 
					        g_assert_cmpuint(actual, ==, expected);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Check dir bit consistency between dir and cnf */
 | 
				
			||||||
 | 
					    /* Check set via DIRSET */
 | 
				
			||||||
 | 
					    expected = 0x80000001;
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRSET, expected);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, expected);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x01);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x01);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Check clear via DIRCLR */
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRCLR, 0x80000001);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x00000000);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x00);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x00);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Check set via DIR */
 | 
				
			||||||
 | 
					    expected = 0x80000001;
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, expected);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, expected);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x01);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x01);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Reset DIR */
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, 0x00000000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Check Input propagates */
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x00);
 | 
				
			||||||
 | 
					    qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x00);
 | 
				
			||||||
 | 
					    qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 1);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x01);
 | 
				
			||||||
 | 
					    qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, -1);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x01);
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Check pull-up working */
 | 
				
			||||||
 | 
					    qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x00);
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b1110);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x01);
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Check pull-down working */
 | 
				
			||||||
 | 
					    qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 1);
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x01);
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0110);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x00);
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
 | 
				
			||||||
 | 
					    qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Check Output propagates */
 | 
				
			||||||
 | 
					    irq_intercept_out("/machine/nrf51");
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0011);
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
 | 
				
			||||||
 | 
					    g_assert_true(get_irq(0));
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01);
 | 
				
			||||||
 | 
					    g_assert_false(get_irq(0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Check self-stimulation */
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01);
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x01);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01);
 | 
				
			||||||
 | 
					    actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
 | 
				
			||||||
 | 
					    g_assert_cmpuint(actual, ==, 0x00);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Check short-circuit - generates an guest_error which must be checked
 | 
				
			||||||
 | 
					     * manually as long as qtest can not scan qemu_log messages
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01);
 | 
				
			||||||
 | 
					    writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
 | 
				
			||||||
 | 
					    qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void timer_task(hwaddr task)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    writel(NRF51_TIMER_BASE + task, NRF51_TRIGGER_TASK);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void timer_clear_event(hwaddr event)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    writel(NRF51_TIMER_BASE + event, NRF51_EVENT_CLEAR);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void timer_set_bitmode(uint8_t mode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    writel(NRF51_TIMER_BASE + NRF51_TIMER_REG_BITMODE, mode);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void timer_set_prescaler(uint8_t prescaler)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    writel(NRF51_TIMER_BASE + NRF51_TIMER_REG_PRESCALER, prescaler);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void timer_set_cc(size_t idx, uint32_t value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    writel(NRF51_TIMER_BASE + NRF51_TIMER_REG_CC0 + idx * 4, value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void timer_assert_events(uint32_t ev0, uint32_t ev1, uint32_t ev2,
 | 
				
			||||||
 | 
					                                uint32_t ev3)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    g_assert(readl(NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_0) == ev0);
 | 
				
			||||||
 | 
					    g_assert(readl(NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_1) == ev1);
 | 
				
			||||||
 | 
					    g_assert(readl(NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_2) == ev2);
 | 
				
			||||||
 | 
					    g_assert(readl(NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_3) == ev3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_nrf51_timer(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint32_t steps_to_overflow = 408;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Compare Match */
 | 
				
			||||||
 | 
					    timer_task(NRF51_TIMER_TASK_STOP);
 | 
				
			||||||
 | 
					    timer_task(NRF51_TIMER_TASK_CLEAR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    timer_clear_event(NRF51_TIMER_EVENT_COMPARE_0);
 | 
				
			||||||
 | 
					    timer_clear_event(NRF51_TIMER_EVENT_COMPARE_1);
 | 
				
			||||||
 | 
					    timer_clear_event(NRF51_TIMER_EVENT_COMPARE_2);
 | 
				
			||||||
 | 
					    timer_clear_event(NRF51_TIMER_EVENT_COMPARE_3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    timer_set_bitmode(NRF51_TIMER_WIDTH_16); /* 16 MHz Timer */
 | 
				
			||||||
 | 
					    timer_set_prescaler(0);
 | 
				
			||||||
 | 
					    /* Swept over in first step */
 | 
				
			||||||
 | 
					    timer_set_cc(0, 2);
 | 
				
			||||||
 | 
					    /* Barely miss on first step */
 | 
				
			||||||
 | 
					    timer_set_cc(1, 162);
 | 
				
			||||||
 | 
					    /* Spot on on third step */
 | 
				
			||||||
 | 
					    timer_set_cc(2, 480);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    timer_assert_events(0, 0, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    timer_task(NRF51_TIMER_TASK_START);
 | 
				
			||||||
 | 
					    clock_step(10000);
 | 
				
			||||||
 | 
					    timer_assert_events(1, 0, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Swept over on first overflow */
 | 
				
			||||||
 | 
					    timer_set_cc(3, 114);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clock_step(10000);
 | 
				
			||||||
 | 
					    timer_assert_events(1, 1, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clock_step(10000);
 | 
				
			||||||
 | 
					    timer_assert_events(1, 1, 1, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Wrap time until internal counter overflows */
 | 
				
			||||||
 | 
					    while (steps_to_overflow--) {
 | 
				
			||||||
 | 
					        timer_assert_events(1, 1, 1, 0);
 | 
				
			||||||
 | 
					        clock_step(10000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    timer_assert_events(1, 1, 1, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    timer_clear_event(NRF51_TIMER_EVENT_COMPARE_0);
 | 
				
			||||||
 | 
					    timer_clear_event(NRF51_TIMER_EVENT_COMPARE_1);
 | 
				
			||||||
 | 
					    timer_clear_event(NRF51_TIMER_EVENT_COMPARE_2);
 | 
				
			||||||
 | 
					    timer_clear_event(NRF51_TIMER_EVENT_COMPARE_3);
 | 
				
			||||||
 | 
					    timer_assert_events(0, 0, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    timer_task(NRF51_TIMER_TASK_STOP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Test Proposal: Stop/Shutdown */
 | 
				
			||||||
 | 
					    /* Test Proposal: Shortcut Compare -> Clear */
 | 
				
			||||||
 | 
					    /* Test Proposal: Shortcut Compare -> Stop */
 | 
				
			||||||
 | 
					    /* Test Proposal: Counter Mode */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_test_init(&argc, &argv, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    global_qtest = qtest_initf("-machine microbit");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qtest_add_func("/microbit/nrf51/gpio", test_nrf51_gpio);
 | 
				
			||||||
 | 
					    qtest_add_func("/microbit/nrf51/timer", test_nrf51_timer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = g_test_run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qtest_quit(global_qtest);
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user