From patchwork Tue Feb 20 18:03:07 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128947 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910155ljc; Tue, 20 Feb 2018 10:03:28 -0800 (PST) X-Google-Smtp-Source: AH8x2262OZ46WGWbEcqluPXG0CTGP/9kocSXYXJxzkWFT2xi79wezw6vQqD3sk6oPwHjP+kRhyO8 X-Received: by 10.46.29.23 with SMTP id d23mr316086ljd.7.1519149808038; Tue, 20 Feb 2018 10:03:28 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149808; cv=none; d=google.com; s=arc-20160816; b=ZfdErdj0BayVo9VXT1llUyw+DhnFEZHRyyFaSMbGUbsSZYGfp5jcF9nBCLaM/9k24w sh0MIbJQpv+xEbyM6sN/uxokKVFvpXknUdJHnbXf7oIpxiWlNYzVHTsfjFSJ8fo2DWX3 3tO8ufodBdU2a5u1VdSFN/IjneiuaGEcCce6rZljW/wuwAws3dhnddZaqexnZNp+/Lgn VeSP9qO+RNxMDN/DbvZR8FujrBrAM+uOqVa+AsMN1wepLuQkVSMrMUss868iwDjOpdol mfwIEM6KbC4PUuWmOniHA11CrPXQshXU0tAARz/qUaR/wo/JYMLGF5svsqjmrjDJ5Bjc +xiA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=7f0sNNTmrWJTgLGdjJGjEqgA0HBDv0++gqLlWY9ztKE=; b=fPheqiZLJibS7B9n/Piz0CAFbHx/oDqviJSyNNLJQVSlqooWATojvYgiXy2yZI3d97 3PWzNGIxgBm4S7sAaDOPtaipXgic4uPgDExHL2mw8tVi6W+O6Twh2dHbVV5lg///MKqC vwdeViIlLjLVR7UuJyRWdyrr3tFZn3DrgP/LmRMseaJ9bzYcaxr/q2uQqXRc6xfMuzUS 3ExqcKdwjFsaFGIvKVC8LEHxBRo4I2prH1L/+PsHzc0Z/KyIrx/GXNUagUNdHjKl5gNc 0Dv0clAATLtqQ0JMsui71ZkWdl35w0emFxYaf7H3vQ/B0c6AvyxpS8rfniHlwQQ/uPYA XqAQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id o2si816451ljd.366.2018.02.20.10.03.27 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:27 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGF-0008QD-25; Tue, 20 Feb 2018 18:03:27 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 01/19] loader: Add new load_ramdisk_as() Date: Tue, 20 Feb 2018 18:03:07 +0000 Message-Id: <20180220180325.29818-2-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> MIME-Version: 1.0 Add a function load_ramdisk_as() which behaves like the existing load_ramdisk() but allows the caller to specify the AddressSpace to use. This matches the pattern we have already for various other loader functions. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé --- include/hw/loader.h | 12 +++++++++++- hw/core/loader.c | 8 +++++++- 2 files changed, 18 insertions(+), 2 deletions(-) -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/include/hw/loader.h b/include/hw/loader.h index 5edbe02b1c..2504cc2259 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -162,16 +162,26 @@ int load_uimage(const char *filename, hwaddr *ep, void *translate_opaque); /** - * load_ramdisk: + * load_ramdisk_as: * @filename: Path to the ramdisk image * @addr: Memory address to load the ramdisk to * @max_sz: Maximum allowed ramdisk size (for non-u-boot ramdisks) + * @as: The AddressSpace to load the ELF to. The value of address_space_memory + * is used if nothing is supplied here. * * Load a ramdisk image with U-Boot header to the specified memory * address. * * Returns the size of the loaded image on success, -1 otherwise. */ +int load_ramdisk_as(const char *filename, hwaddr addr, uint64_t max_sz, + AddressSpace *as); + +/** + * load_ramdisk: + * Same as load_ramdisk_as(), but doesn't allow the caller to specify + * an AddressSpace. + */ int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz); ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, size_t srclen); diff --git a/hw/core/loader.c b/hw/core/loader.c index 91669d65aa..2b9e7394a1 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -729,9 +729,15 @@ int load_uimage_as(const char *filename, hwaddr *ep, hwaddr *loadaddr, /* Load a ramdisk. */ int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz) +{ + return load_ramdisk_as(filename, addr, max_sz, NULL); +} + +int load_ramdisk_as(const char *filename, hwaddr addr, uint64_t max_sz, + AddressSpace *as) { return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK, - NULL, NULL, NULL); + NULL, NULL, as); } /* Load a gzip-compressed kernel to a dynamically allocated buffer. */ From patchwork Tue Feb 20 18:03:08 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128949 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910161ljc; Tue, 20 Feb 2018 10:03:28 -0800 (PST) X-Google-Smtp-Source: AH8x227Ip6nNzmR9IcTdCTfv6NDX/g+JC4sDWcLj4zYmYkR+pPC+bZgeIR7htiMf3NK+B3THkSeu X-Received: by 10.28.116.14 with SMTP id p14mr924633wmc.117.1519149808361; Tue, 20 Feb 2018 10:03:28 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149808; cv=none; d=google.com; s=arc-20160816; b=F+hsHukuZrwGnOiUsDvYuTr1sMfnyqVCxGMvrng5jm8Y22YAijJYidoMNGA0yRn4Qv N9fgEcQSgUfN7DKoZyRihKRHLSY9oPTc6x0/e67S/hTMGcySvnHWggjjkZiecmKgJKx9 +/vO5qzyn9pvVucqsNzH7+vvmRXfsZ7VZbi1lhrBYJx1E4SZNqGQehiMNoXF1XptWDsD aa3DDccoLomvHd66CXkkBGClqTNyPh4kK+LGjcjMiXZ/rrLecsTwNjXf4Xam+5VcuHbU UI6LbtGjjjlEY7XqqtVLfhgcIIQ9u6VvM12ovauocDCRjF6anC2KtG8Kcv03IO4GDTei edQg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=mBFppzOvOEJzCACDUFkiiB07qFR55H6AhaTRk7fQBtw=; b=wUIoI+R0O9gokyoI7HyNFT/TmPrmiBZ29+4aGNY0oK9Ufix79gmaK5sW9BN6DhdTiR fmglMriViETctClgUjhOOx+4PEW6tze4xKcMBtN1pjfqWT5USjV4Nq5gDAg9T3P1vIsy LxwHjNZunUfug6fXPF5JofDG4WVd58UjdaLgR0noQm7R/o2lE34zBu3C2ZcQxuU0nrjL yfFhXHppUubWf6wm+tItgL/lA2/wyQ3wo255GRbriggUerGb0pqg8oxtkHP4JgBFE9TH GR4OQtlwPFVDF+3ujEW5OMFTlb0bWyNooGpbW4+GDV6tLIVsiS+bRNJASGjZ/ud+dWGv XzmQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id a5si7767329wra.143.2018.02.20.10.03.28 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:28 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGF-0008QS-Q0; Tue, 20 Feb 2018 18:03:27 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 02/19] hw/arm/boot: Honour CPU's address space for image loads Date: Tue, 20 Feb 2018 18:03:08 +0000 Message-Id: <20180220180325.29818-3-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> MIME-Version: 1.0 Instead of loading kernels, device trees, and the like to the system address space, use the CPU's address space. This is important if we're trying to load the file to memory or via an alias memory region that is provided by an SoC object and thus not mapped into the system address space. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé --- Function name changed to arm_boot_address_space() rather than arm_boot_addressspace(), following irc conversation... --- hw/arm/boot.c | 119 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 43 deletions(-) -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 05108bc42f..6d0c92ab88 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -36,6 +36,25 @@ #define ARM64_TEXT_OFFSET_OFFSET 8 #define ARM64_MAGIC_OFFSET 56 +static AddressSpace *arm_boot_address_space(ARMCPU *cpu, + const struct arm_boot_info *info) +{ + /* Return the address space to use for bootloader reads and writes. + * We prefer the secure address space if the CPU has it and we're + * going to boot the guest into it. + */ + int asidx; + CPUState *cs = CPU(cpu); + + if (arm_feature(&cpu->env, ARM_FEATURE_EL3) && info->secure_boot) { + asidx = ARMASIdx_S; + } else { + asidx = ARMASIdx_NS; + } + + return cpu_get_address_space(cs, asidx); +} + typedef enum { FIXUP_NONE = 0, /* do nothing */ FIXUP_TERMINATOR, /* end of insns */ @@ -125,7 +144,8 @@ static const ARMInsnFixup smpboot[] = { }; static void write_bootloader(const char *name, hwaddr addr, - const ARMInsnFixup *insns, uint32_t *fixupcontext) + const ARMInsnFixup *insns, uint32_t *fixupcontext, + AddressSpace *as) { /* Fix up the specified bootloader fragment and write it into * guest memory using rom_add_blob_fixed(). fixupcontext is @@ -164,7 +184,7 @@ static void write_bootloader(const char *name, hwaddr addr, code[i] = tswap32(insn); } - rom_add_blob_fixed(name, code, len * sizeof(uint32_t), addr); + rom_add_blob_fixed_as(name, code, len * sizeof(uint32_t), addr, as); g_free(code); } @@ -173,6 +193,7 @@ static void default_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { uint32_t fixupcontext[FIXUP_MAX]; + AddressSpace *as = arm_boot_address_space(cpu, info); fixupcontext[FIXUP_GIC_CPU_IF] = info->gic_cpu_if_addr; fixupcontext[FIXUP_BOOTREG] = info->smp_bootreg_addr; @@ -183,13 +204,14 @@ static void default_write_secondary(ARMCPU *cpu, } write_bootloader("smpboot", info->smp_loader_start, - smpboot, fixupcontext); + smpboot, fixupcontext, as); } void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu, const struct arm_boot_info *info, hwaddr mvbar_addr) { + AddressSpace *as = arm_boot_address_space(cpu, info); int n; uint32_t mvbar_blob[] = { /* mvbar_addr: secure monitor vectors @@ -227,22 +249,23 @@ void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu, for (n = 0; n < ARRAY_SIZE(mvbar_blob); n++) { mvbar_blob[n] = tswap32(mvbar_blob[n]); } - rom_add_blob_fixed("board-setup-mvbar", mvbar_blob, sizeof(mvbar_blob), - mvbar_addr); + rom_add_blob_fixed_as("board-setup-mvbar", mvbar_blob, sizeof(mvbar_blob), + mvbar_addr, as); for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) { board_setup_blob[n] = tswap32(board_setup_blob[n]); } - rom_add_blob_fixed("board-setup", board_setup_blob, - sizeof(board_setup_blob), info->board_setup_addr); + rom_add_blob_fixed_as("board-setup", board_setup_blob, + sizeof(board_setup_blob), info->board_setup_addr, as); } static void default_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { + AddressSpace *as = arm_boot_address_space(cpu, info); CPUState *cs = CPU(cpu); - address_space_stl_notdirty(&address_space_memory, info->smp_bootreg_addr, + address_space_stl_notdirty(as, info->smp_bootreg_addr, 0, MEMTXATTRS_UNSPECIFIED, NULL); cpu_set_pc(cs, info->smp_loader_start); } @@ -253,12 +276,12 @@ static inline bool have_dtb(const struct arm_boot_info *info) } #define WRITE_WORD(p, value) do { \ - address_space_stl_notdirty(&address_space_memory, p, value, \ + address_space_stl_notdirty(as, p, value, \ MEMTXATTRS_UNSPECIFIED, NULL); \ p += 4; \ } while (0) -static void set_kernel_args(const struct arm_boot_info *info) +static void set_kernel_args(const struct arm_boot_info *info, AddressSpace *as) { int initrd_size = info->initrd_size; hwaddr base = info->loader_start; @@ -289,8 +312,9 @@ static void set_kernel_args(const struct arm_boot_info *info) int cmdline_size; cmdline_size = strlen(info->kernel_cmdline); - cpu_physical_memory_write(p + 8, info->kernel_cmdline, - cmdline_size + 1); + address_space_write(as, p + 8, MEMTXATTRS_UNSPECIFIED, + (const uint8_t *)info->kernel_cmdline, + cmdline_size + 1); cmdline_size = (cmdline_size >> 2) + 1; WRITE_WORD(p, cmdline_size + 2); WRITE_WORD(p, 0x54410009); @@ -304,7 +328,8 @@ static void set_kernel_args(const struct arm_boot_info *info) atag_board_len = (info->atag_board(info, atag_board_buf) + 3) & ~3; WRITE_WORD(p, (atag_board_len + 8) >> 2); WRITE_WORD(p, 0x414f4d50); - cpu_physical_memory_write(p, atag_board_buf, atag_board_len); + address_space_write(as, p, MEMTXATTRS_UNSPECIFIED, + atag_board_buf, atag_board_len); p += atag_board_len; } /* ATAG_END */ @@ -312,7 +337,8 @@ static void set_kernel_args(const struct arm_boot_info *info) WRITE_WORD(p, 0); } -static void set_kernel_args_old(const struct arm_boot_info *info) +static void set_kernel_args_old(const struct arm_boot_info *info, + AddressSpace *as) { hwaddr p; const char *s; @@ -380,7 +406,8 @@ static void set_kernel_args_old(const struct arm_boot_info *info) } s = info->kernel_cmdline; if (s) { - cpu_physical_memory_write(p, s, strlen(s) + 1); + address_space_write(as, p, MEMTXATTRS_UNSPECIFIED, + (const uint8_t *)s, strlen(s) + 1); } else { WRITE_WORD(p, 0); } @@ -454,6 +481,7 @@ static void fdt_add_psci_node(void *fdt) * @addr: the address to load the image at * @binfo: struct describing the boot environment * @addr_limit: upper limit of the available memory area at @addr + * @as: address space to load image to * * Load a device tree supplied by the machine or by the user with the * '-dtb' command line option, and put it at offset @addr in target @@ -470,7 +498,7 @@ static void fdt_add_psci_node(void *fdt) * Note: Must not be called unless have_dtb(binfo) is true. */ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, - hwaddr addr_limit) + hwaddr addr_limit, AddressSpace *as) { void *fdt = NULL; int size, rc; @@ -616,7 +644,7 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, /* Put the DTB into the memory map as a ROM image: this will ensure * the DTB is copied again upon reset, even if addr points into RAM. */ - rom_add_blob_fixed("dtb", fdt, size, addr); + rom_add_blob_fixed_as("dtb", fdt, size, addr, as); g_free(fdt); @@ -703,13 +731,15 @@ static void do_cpu_reset(void *opaque) } if (cs == first_cpu) { + AddressSpace *as = arm_boot_address_space(cpu, info); + cpu_set_pc(cs, info->loader_start); if (!have_dtb(info)) { if (old_param) { - set_kernel_args_old(info); + set_kernel_args_old(info, as); } else { - set_kernel_args(info); + set_kernel_args(info, as); } } } else { @@ -784,7 +814,7 @@ static int do_arm_linux_init(Object *obj, void *opaque) static uint64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, - int elf_machine) + int elf_machine, AddressSpace *as) { bool elf_is64; union { @@ -827,9 +857,9 @@ static uint64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry, } } - ret = load_elf(info->kernel_filename, NULL, NULL, - pentry, lowaddr, highaddr, big_endian, elf_machine, - 1, data_swab); + ret = load_elf_as(info->kernel_filename, NULL, NULL, + pentry, lowaddr, highaddr, big_endian, elf_machine, + 1, data_swab, as); if (ret <= 0) { /* The header loaded but the image didn't */ exit(1); @@ -839,7 +869,7 @@ static uint64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry, } static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base, - hwaddr *entry) + hwaddr *entry, AddressSpace *as) { hwaddr kernel_load_offset = KERNEL64_LOAD_ADDR; uint8_t *buffer; @@ -874,7 +904,7 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base, } *entry = mem_base + kernel_load_offset; - rom_add_blob_fixed(filename, buffer, size, *entry); + rom_add_blob_fixed_as(filename, buffer, size, *entry, as); g_free(buffer); @@ -896,6 +926,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) ARMCPU *cpu = n->cpu; struct arm_boot_info *info = container_of(n, struct arm_boot_info, load_kernel_notifier); + AddressSpace *as = arm_boot_address_space(cpu, info); /* The board code is not supposed to set secure_board_setup unless * running its code in secure mode is actually possible, and KVM @@ -913,7 +944,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) * the kernel is supposed to be loaded by the bootloader), copy the * DTB to the base of RAM for the bootloader to pick up. */ - if (load_dtb(info->loader_start, info, 0) < 0) { + if (load_dtb(info->loader_start, info, 0, as) < 0) { exit(1); } } @@ -988,7 +1019,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) /* Assume that raw images are linux kernels, and ELF images are not. */ kernel_size = arm_load_elf(info, &elf_entry, &elf_low_addr, - &elf_high_addr, elf_machine); + &elf_high_addr, elf_machine, as); if (kernel_size > 0 && have_dtb(info)) { /* If there is still some room left at the base of RAM, try and put * the DTB there like we do for images loaded with -bios or -pflash. @@ -1001,25 +1032,26 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) if (elf_low_addr < info->loader_start) { elf_low_addr = 0; } - if (load_dtb(info->loader_start, info, elf_low_addr) < 0) { + if (load_dtb(info->loader_start, info, elf_low_addr, as) < 0) { exit(1); } } } entry = elf_entry; if (kernel_size < 0) { - kernel_size = load_uimage(info->kernel_filename, &entry, NULL, - &is_linux, NULL, NULL); + kernel_size = load_uimage_as(info->kernel_filename, &entry, NULL, + &is_linux, NULL, NULL, as); } if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && kernel_size < 0) { kernel_size = load_aarch64_image(info->kernel_filename, - info->loader_start, &entry); + info->loader_start, &entry, as); is_linux = 1; } else if (kernel_size < 0) { /* 32-bit ARM */ entry = info->loader_start + KERNEL_LOAD_ADDR; - kernel_size = load_image_targphys(info->kernel_filename, entry, - info->ram_size - KERNEL_LOAD_ADDR); + kernel_size = load_image_targphys_as(info->kernel_filename, entry, + info->ram_size - KERNEL_LOAD_ADDR, + as); is_linux = 1; } if (kernel_size < 0) { @@ -1031,15 +1063,16 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) uint32_t fixupcontext[FIXUP_MAX]; if (info->initrd_filename) { - initrd_size = load_ramdisk(info->initrd_filename, - info->initrd_start, - info->ram_size - - info->initrd_start); + initrd_size = load_ramdisk_as(info->initrd_filename, + info->initrd_start, + info->ram_size - info->initrd_start, + as); if (initrd_size < 0) { - initrd_size = load_image_targphys(info->initrd_filename, - info->initrd_start, - info->ram_size - - info->initrd_start); + initrd_size = load_image_targphys_as(info->initrd_filename, + info->initrd_start, + info->ram_size - + info->initrd_start, + as); } if (initrd_size < 0) { error_report("could not load initrd '%s'", @@ -1080,7 +1113,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) /* Place the DTB after the initrd in memory with alignment. */ dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, align); - if (load_dtb(dtb_start, info, 0) < 0) { + if (load_dtb(dtb_start, info, 0, as) < 0) { exit(1); } fixupcontext[FIXUP_ARGPTR] = dtb_start; @@ -1096,7 +1129,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) fixupcontext[FIXUP_ENTRYPOINT] = entry; write_bootloader("bootloader", info->loader_start, - primary_loader, fixupcontext); + primary_loader, fixupcontext, as); if (info->nb_cpus > 1) { info->write_secondary_boot(cpu, info); From patchwork Tue Feb 20 18:03:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128948 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910173ljc; Tue, 20 Feb 2018 10:03:29 -0800 (PST) X-Google-Smtp-Source: AH8x2241hK/qlmQV57hZwYWy+PT7roI2qUISa3yAQpg/fIpe2/T4ZOcEKcB6/aOmZiAwvGVbd0mb X-Received: by 10.223.175.230 with SMTP id y38mr490297wrd.26.1519149809074; Tue, 20 Feb 2018 10:03:29 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149809; cv=none; d=google.com; s=arc-20160816; b=WBS/UcswtwRplSGcm/SSqt7oUH1Nwutr7i+9b6J7RrwlOYhOYFeDDw46dHcs3J+8UU QebXX0ljZ5PX9l2settufqqVH6rnokTmrVou0HSsfjd9gsNzYz9dk1UYt/2mYM9PLhEv xDE2V55N81/kWRTcvvJC4WxTbrm0H2pAqbkTrSAFoUPAuwwaN3kxyhmdG3KHwuUs0oAT 5uw+7V0Gtg5ibqCfNTbOhVwqyoF2j2czBLFtNyPmIRktBMnKfG07B+F5bFMlEGcQ9kfQ wVMSP3Mrnce6Vct5WagtqEmiS3V02mx+bZsjTqe5zo9uUMKXM1fGj9fJZH7C2aI+sOBa AN2g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=gs+3cy9o14tWB2fh+L5DvULNYay+gHGxMu+JbcnZnz8=; b=HFCwMl9dmJWmuaZONJ5YMu1p+SfGf8oFCS8oSZUrQkZ7PUIkqOMiLpiY/iv1JK2mAQ gaCAnqAmbWnwlTKYDVnEKf07Ur4EfvVReQp/Uuj9Jy7GiUrgj+3So8iO4OpHF6IOOTEZ eCbCTwN56AlaqJmUJyrbfsIKsm96Q6329YvWqhBGZGy8gFHwxAwq2Z4AQ7Q3xBuCPpap IIFzCgnJaft/GgCi24Ii5X/BS+QfA44mTD7ihNdpTYnTnJhEfoHgxQBZCEyCOfVdTkqR YhkD/ExeAAs97nWObJhscxWtaSXPKHP3le2RgJFA8MIby7x9GKhBFVI8u3XTqoy52M0J q9CQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id 16si19828014wry.155.2018.02.20.10.03.28 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:29 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGG-0008Qh-Jh; Tue, 20 Feb 2018 18:03:28 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 03/19] hw/arm/armv7m: Honour CPU's address space for image loads Date: Tue, 20 Feb 2018 18:03:09 +0000 Message-Id: <20180220180325.29818-4-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> MIME-Version: 1.0 Instead of loading guest images to the system address space, use the CPU's address space. This is important if we're trying to load the file to memory or via an alias memory region that is provided by an SoC object and thus not mapped into the system address space. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé --- hw/arm/armv7m.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 56770a7048..facc536b07 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -270,6 +270,9 @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size) uint64_t entry; uint64_t lowaddr; int big_endian; + AddressSpace *as; + int asidx; + CPUState *cs = CPU(cpu); #ifdef TARGET_WORDS_BIGENDIAN big_endian = 1; @@ -282,11 +285,19 @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size) exit(1); } + if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) { + asidx = ARMASIdx_S; + } else { + asidx = ARMASIdx_NS; + } + as = cpu_get_address_space(cs, asidx); + if (kernel_filename) { - image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr, - NULL, big_endian, EM_ARM, 1, 0); + image_size = load_elf_as(kernel_filename, NULL, NULL, &entry, &lowaddr, + NULL, big_endian, EM_ARM, 1, 0, as); if (image_size < 0) { - image_size = load_image_targphys(kernel_filename, 0, mem_size); + image_size = load_image_targphys_as(kernel_filename, 0, + mem_size, as); lowaddr = 0; } if (image_size < 0) { From patchwork Tue Feb 20 18:03:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128950 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910194ljc; Tue, 20 Feb 2018 10:03:29 -0800 (PST) X-Google-Smtp-Source: AH8x226NVb42BYCoQvNgolzj9bUao650OhfYUj0qaRcPglS7ZGnL54J1ai9m/8QuZsUsDQhczh/+ X-Received: by 10.28.169.79 with SMTP id s76mr956198wme.48.1519149809800; Tue, 20 Feb 2018 10:03:29 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149809; cv=none; d=google.com; s=arc-20160816; b=fsbX7jCimiZQh9kjFpnLQxQVUXnu358vMG+OfEO1Giy5uZxEsmNH2tt+aNpammgttS FFmrJic7lYJe8ryHvppCWH/3+L/o9IGPii2s5NHG5I2Miw0Z3SqdO16CBrxZIwgHqB5W J/MOjugXqAFvqmXGe6VfvIbb7b28h7+ZzvZAr2ebozGZjHDcRaNG4zY6gniFmei1IZFb hC121anenCYfFcKr2YBM7bB5K6YcDCbbqBuP0ZOO1E4Epq4MIMcNBO+hi0I0GUZzN+qY pMCx8ZT9wvzljJQttg3OeLO+5PGZmdGzbYGeg+PKZFop+txVJ9XnQPCg5gJtrav887tU G39Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=ULO2vekmERFjep3BEXFcz5GPnunMUXER2Q3KLM/vLno=; b=tgELMWzFnIuo22esi9p+qtOOoCKBdzkNeywKghUwqNDaf43fN5JCPPmHREqZRNd6di tKWlHLpvA8S8uuvFqW+6TqgPVpx4GWcdaLlKyiL1bgytBZ622DePpWfmD6OFC3THT2v/ HuX0bKVIg9AZPTISaAu8oG6wSOeXK+8rFyXIDVs3k596Yr4HbnWbeiE0uK5dLYhRfkrT FWzGREAFfDNKH9DE1aRQUqcPj+r0jdI8a5F53MTwmL8Ox6kzhbmLt2DQ4VNCHc72Wheu ZfksAOYfCKUPIxrXF23oAqFHnvT52AWA2sGsqqVLV/FNfBZIEGk4sIjp1naXIUBvnVhW eeNQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id z1si3061171wrh.82.2018.02.20.10.03.29 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:29 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGH-0008Qx-AI; Tue, 20 Feb 2018 18:03:29 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 04/19] target/arm: Define an IDAU interface Date: Tue, 20 Feb 2018 18:03:10 +0000 Message-Id: <20180220180325.29818-5-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> In v8M, the Implementation Defined Attribution Unit (IDAU) is a small piece of hardware typically implemented in the SoC which provides board or SoC specific security attribution information for each address that the CPU performs MPU/SAU checks on. For QEMU, we model this with a QOM interface which is implemented by the board or SoC object and connected to the CPU using a link property. This commit defines the new interface class, adds the link property to the CPU object, and makes the SAU checking code call the IDAU interface if one is present. Signed-off-by: Peter Maydell --- An example of an object that implements the IDAU can be found in the later patch "hw/arm/iotkit: Model Arm IOT Kit". --- target/arm/cpu.h | 3 +++ target/arm/idau.h | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++ target/arm/cpu.c | 15 +++++++++++++ target/arm/helper.c | 28 +++++++++++++++++++++--- 4 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 target/arm/idau.h -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/target/arm/cpu.h b/target/arm/cpu.h index de62df091c..dc45b740c5 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -685,6 +685,9 @@ struct ARMCPU { /* MemoryRegion to use for secure physical accesses */ MemoryRegion *secure_memory; + /* For v8M, pointer to the IDAU interface provided by board/SoC */ + Object *idau; + /* 'compatible' string for this CPU for Linux device trees */ const char *dtb_compatible; diff --git a/target/arm/idau.h b/target/arm/idau.h new file mode 100644 index 0000000000..cac27b95fa --- /dev/null +++ b/target/arm/idau.h @@ -0,0 +1,61 @@ +/* + * QEMU ARM CPU -- interface for the Arm v8M IDAU + * + * Copyright (c) 2018 Linaro Ltd + * + * 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 + * + * + * In the v8M architecture, the IDAU is a small piece of hardware + * typically implemented in the SoC which provides board or SoC + * specific security attribution information for each address that + * the CPU performs MPU/SAU checks on. For QEMU, we model this with a + * QOM interface which is implemented by the board or SoC object and + * connected to the CPU using a link property. + */ + +#ifndef TARGET_ARM_IDAU_H +#define TARGET_ARM_IDAU_H + +#include "qom/object.h" + +#define TYPE_IDAU_INTERFACE "idau-interface" +#define IDAU_INTERFACE(obj) \ + INTERFACE_CHECK(IDAUInterface, (obj), TYPE_IDAU_INTERFACE) +#define IDAU_INTERFACE_CLASS(class) \ + OBJECT_CLASS_CHECK(IDAUInterfaceClass, (class), TYPE_IDAU_INTERFACE) +#define IDAU_INTERFACE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(IDAUInterfaceClass, (obj), TYPE_IDAU_INTERFACE) + +typedef struct IDAUInterface { + Object parent; +} IDAUInterface; + +#define IREGION_NOTVALID -1 + +typedef struct IDAUInterfaceClass { + InterfaceClass parent; + + /* Check the specified address and return the IDAU security information + * for it by filling in iregion, exempt, ns and nsc: + * iregion: IDAU region number, or IREGION_NOTVALID if not valid + * exempt: true if address is exempt from security attribution + * ns: true if the address is NonSecure + * nsc: true if the address is NonSecure-callable + */ + void (*check)(IDAUInterface *ii, uint32_t address, int *iregion, + bool *exempt, bool *ns, bool *nsc); +} IDAUInterfaceClass; + +#endif diff --git a/target/arm/cpu.c b/target/arm/cpu.c index d796085be9..99d00c3ac9 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "target/arm/idau.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "cpu.h" @@ -687,6 +688,13 @@ static void arm_cpu_post_init(Object *obj) } } + if (arm_feature(&cpu->env, ARM_FEATURE_M_SECURITY)) { + object_property_add_link(obj, "idau", TYPE_IDAU_INTERFACE, &cpu->idau, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_UNREF_ON_RELEASE, + &error_abort); + } + qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property, &error_abort); } @@ -1820,11 +1828,18 @@ static const TypeInfo arm_cpu_type_info = { .class_init = arm_cpu_class_init, }; +static const TypeInfo idau_interface_type_info = { + .name = TYPE_IDAU_INTERFACE, + .parent = TYPE_INTERFACE, + .class_size = sizeof(IDAUInterfaceClass), +}; + static void arm_cpu_register_types(void) { const ARMCPUInfo *info = arm_cpus; type_register_static(&arm_cpu_type_info); + type_register_static(&idau_interface_type_info); while (info->name) { cpu_register(info); diff --git a/target/arm/helper.c b/target/arm/helper.c index e7586fcf6c..3acbcb2a1a 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1,4 +1,5 @@ #include "qemu/osdep.h" +#include "target/arm/idau.h" #include "trace.h" #include "cpu.h" #include "internals.h" @@ -9740,19 +9741,32 @@ static void v8m_security_lookup(CPUARMState *env, uint32_t address, */ ARMCPU *cpu = arm_env_get_cpu(env); int r; + bool idau_exempt = false, idau_ns = true, idau_nsc = true; + int idau_region = IREGION_NOTVALID; - /* TODO: implement IDAU */ + if (cpu->idau) { + IDAUInterfaceClass *iic = IDAU_INTERFACE_GET_CLASS(cpu->idau); + IDAUInterface *ii = IDAU_INTERFACE(cpu->idau); + + iic->check(ii, address, &idau_region, &idau_exempt, &idau_ns, + &idau_nsc); + } if (access_type == MMU_INST_FETCH && extract32(address, 28, 4) == 0xf) { /* 0xf0000000..0xffffffff is always S for insn fetches */ return; } - if (v8m_is_sau_exempt(env, address, access_type)) { + if (idau_exempt || v8m_is_sau_exempt(env, address, access_type)) { sattrs->ns = !regime_is_secure(env, mmu_idx); return; } + if (idau_region != IREGION_NOTVALID) { + sattrs->irvalid = true; + sattrs->iregion = idau_region; + } + switch (env->sau.ctrl & 3) { case 0: /* SAU.ENABLE == 0, SAU.ALLNS == 0 */ break; @@ -9789,7 +9803,15 @@ static void v8m_security_lookup(CPUARMState *env, uint32_t address, } } - /* TODO when we support the IDAU then it may override the result here */ + /* The IDAU will override the SAU lookup results if it specifies + * higher security than the SAU does. + */ + if (!idau_ns) { + if (sattrs->ns || (!idau_nsc && sattrs->nsc)) { + sattrs->ns = false; + sattrs->nsc = idau_nsc; + } + } break; } } From patchwork Tue Feb 20 18:03:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128951 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910216ljc; Tue, 20 Feb 2018 10:03:30 -0800 (PST) X-Google-Smtp-Source: AH8x225uCnxBwLAS1A2KhWB0SIitRgd4AlgEjYdX8GZ9QiURs1UH8qZK1KZFU5V/DovDgpAdXXJB X-Received: by 10.223.160.56 with SMTP id k53mr450557wrk.5.1519149810496; Tue, 20 Feb 2018 10:03:30 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149810; cv=none; d=google.com; s=arc-20160816; b=kX9+xpBL7Fv1Gaz9n0m7dNoBpjCCMwo7hw9GS3NsYALFfN+zBfIk6sy1BNSxq29rfM Mp7FdSfGXEJvJ32m9DKSrkQp916+ezeP2IiDN0Yfu+7J6TYFShCaZP9heusWo+RhCD+h PveURQCaHMEqMeJ2zC/O9UY9jSiFikOK+lZzRmYB5wld2IatS9NadT78C+sQ64OeRgPk OeLaSC8j8jvLv0CbAL5mgHR21rQVrBm781Cv8WYeFLwmRjUqs/cX/Nn30OVvHo+hHAyu IZAtRiDYS8dVDW/o5051VsBFCOWzlXQA7NsnJrQ529yPQej1+1urrXhvJVh7A6LS2N+J BNCg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=mh7dUpPyL0HYA3nleYLaiCNrahCcX6ec2JmtwubcgdI=; b=ow56AxPQCYg739ByTXMJLUSmLj80WEnqNLn2x8m1V7SOMLQoTNS+wyw3R3FIDsLwhU cTumM0uqpxJ+buIJtyPplRoq3CpkqYPAq9HPjX4EGwUn94CO33RlLP1csXSjuB37YOJg bP+gad3pt/TYipVZFEw473jrmYisRVsfJKswcRDg8gWn3NozgOHvvm6VHyjmaie61qu1 4k5n1/daXY4hf77iL48ZG7b8MtcS+H6y/47Pc+d+Mre2BXAyourtpXvG2G0YvLUJMLbP y9yRB94a/hlGjEPwn+tXl6HphYcRMlaaD6Q6TJ8LZckzyTN3DlR6vte3ka3vFHEma5bJ 98Cg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id 59si3040002wrm.374.2018.02.20.10.03.30 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:30 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGI-0008RC-2L; Tue, 20 Feb 2018 18:03:30 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 05/19] armv7m: Forward idau property to CPU object Date: Tue, 20 Feb 2018 18:03:11 +0000 Message-Id: <20180220180325.29818-6-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> Create an "idau" property on the armv7m container object which we can forward to the CPU object. Annoyingly, we can't use object_property_add_alias() because the CPU object we want to forward to doesn't exist until the armv7m container is realized. Signed-off-by: Peter Maydell --- include/hw/arm/armv7m.h | 3 +++ hw/arm/armv7m.c | 7 +++++++ 2 files changed, 10 insertions(+) -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/include/hw/arm/armv7m.h b/include/hw/arm/armv7m.h index 35ab757264..5c3f406ccc 100644 --- a/include/hw/arm/armv7m.h +++ b/include/hw/arm/armv7m.h @@ -12,6 +12,7 @@ #include "hw/sysbus.h" #include "hw/intc/armv7m_nvic.h" +#include "target/arm/idau.h" #define TYPE_BITBAND "ARM,bitband-memory" #define BITBAND(obj) OBJECT_CHECK(BitBandState, (obj), TYPE_BITBAND) @@ -40,6 +41,7 @@ typedef struct { * + Property "memory": MemoryRegion defining the physical address space * that CPU accesses see. (The NVIC, bitbanding and other CPU-internal * devices will be automatically layered on top of this view.) + * + Property "idau": IDAU interface (forwarded to CPU object) */ typedef struct ARMv7MState { /*< private >*/ @@ -58,6 +60,7 @@ typedef struct ARMv7MState { char *cpu_type; /* MemoryRegion the board provides to us (with its devices, RAM, etc) */ MemoryRegion *board_memory; + Object *idau; } ARMv7MState; #endif diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index facc536b07..189066812c 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -19,6 +19,7 @@ #include "sysemu/qtest.h" #include "qemu/error-report.h" #include "exec/address-spaces.h" +#include "target/arm/idau.h" /* Bitbanded IO. Each word corresponds to a single bit. */ @@ -162,6 +163,11 @@ static void armv7m_realize(DeviceState *dev, Error **errp) object_property_set_link(OBJECT(s->cpu), OBJECT(&s->container), "memory", &error_abort); + object_property_set_link(OBJECT(s->cpu), s->idau, "idau", &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } object_property_set_bool(OBJECT(s->cpu), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); @@ -217,6 +223,7 @@ static Property armv7m_properties[] = { DEFINE_PROP_STRING("cpu-type", ARMv7MState, cpu_type), DEFINE_PROP_LINK("memory", ARMv7MState, board_memory, TYPE_MEMORY_REGION, MemoryRegion *), + DEFINE_PROP_LINK("idau", ARMv7MState, idau, TYPE_IDAU_INTERFACE, Object *), DEFINE_PROP_END_OF_LIST(), }; From patchwork Tue Feb 20 18:03:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128952 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910241ljc; Tue, 20 Feb 2018 10:03:31 -0800 (PST) X-Google-Smtp-Source: AH8x227hJl625YSbmkUDJmfPNyh6qs4NpJ6Cg7DKGILygs+gVWUj0N5AmtG1Obht23zOJiEQ5WLJ X-Received: by 10.28.23.205 with SMTP id 196mr930461wmx.132.1519149811514; Tue, 20 Feb 2018 10:03:31 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149811; cv=none; d=google.com; s=arc-20160816; b=T+zhwXo/MkAt6oNDmNBUpl9HxU6vd7pcBl9PYUVezlJcVlaIVZhGtorTf4bRd9qHV+ hh9+pAzK83sah/rsEnm8SOzs4Kemq6Yv1FvGpn4Z1FkXfC0bQCAdMdQyLjmC9j3L3lIv hj6L/48JpxA3SVS/RLXlVUypP2jn4pbPP3PYi7UZWMjPCm2ZrzEMv41+yBH9IukEWWHP nNhKLOsQOC5LkluUZF9ckipcDErRaUIxmEZfI7VGU1AONkDMQR0lpsXYQ0d+WbUb90T6 W8yjShQ7FuC4PSKxu92C11swrpDYZ9ksyA7a82F4f0FdAJixXXJCObKjXstDS7SutZiy GZJA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=TnzyBGDtbET45aRxf/xxqklKj8XxTqNz38CClpehMTc=; b=z92p+SHSyZlOuK/a0nw772KyJ2vUd1k582WCNp8PPtLfvjvf+2mnJweZd1vTppCg3Q HvJ8zspZzn8u2jkHvS7PL2BCcD9OaNsbYW95U9NNZFZ8nsF1Q0uAHDr3gzvIZMWopxYj Cp4++H+0jDrlKNVzDPvA8eCfWWTvZw194Sk0ygKLNM0kNMt+vO4L37tHpsbhts8i/0nx nMNTs8aQvjQfpXVXfea1rq1B74avibExJkhpDf9RqTBGxHgTXaq6fkG2ShL0AGSyawVP Rpc/vPZ8amhywiYSZM9RCoznUP1g3Sb+EugVxHcDqHBGh0YJnJSQ/p4l64hn/a+IFDch N2xw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id q131si9411606wmg.123.2018.02.20.10.03.31 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:31 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGI-0008RR-OU; Tue, 20 Feb 2018 18:03:30 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 06/19] target/arm: Define init-svtor property for the reset secure VTOR value Date: Tue, 20 Feb 2018 18:03:12 +0000 Message-Id: <20180220180325.29818-7-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> The Cortex-M33 allows the system to specify the reset value of the secure Vector Table Offset Register (VTOR) by asserting config signals. In particular, guest images for the MPS2 AN505 board rely on the MPS2's initial VTOR being correct for that board. Implement a QEMU property so board and SoC code can set the reset value to the correct value. Signed-off-by: Peter Maydell --- * This patch doesn't try to change the handling of the load itself; strictly speaking for real hardware the load of initial PC and SP should honour the secure/nonsecure attributes and check SAU settings and bus fault responses, as with other vector table loads. That is a change for a different patch, if ever. * The M33 and MPS2 are actually more flexible than "constant value set when the board is created" -- the MPS2 has a register in the FPGA which can be used to define the VTOR to use on the next (soft) reset, since the M33 samples its config signals on every reset. That would be pretty fiddly to implement in QEMU (which doesn't even really have a well-defined concept of reset which is not a powercycle) so I'm not going to implement it unless we run into guest code that needs it. --- target/arm/cpu.h | 3 +++ target/arm/cpu.c | 18 ++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/target/arm/cpu.h b/target/arm/cpu.h index dc45b740c5..c286169630 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -722,6 +722,9 @@ struct ARMCPU { */ uint32_t psci_conduit; + /* For v8M, initial value of the Secure VTOR */ + uint32_t init_svtor; + /* [QEMU_]KVM_ARM_TARGET_* constant for this CPU, or * QEMU_KVM_ARM_TARGET_NONE if the kernel doesn't support this CPU type. */ diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 99d00c3ac9..34b5a4a00b 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -186,6 +186,7 @@ static void arm_cpu_reset(CPUState *s) uint32_t initial_msp; /* Loaded from 0x0 */ uint32_t initial_pc; /* Loaded from 0x4 */ uint8_t *rom; + uint32_t vecbase; if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { env->v7m.secure = true; @@ -213,8 +214,11 @@ static void arm_cpu_reset(CPUState *s) /* Unlike A/R profile, M profile defines the reset LR value */ env->regs[14] = 0xffffffff; - /* Load the initial SP and PC from the vector table at address 0 */ - rom = rom_ptr(0); + env->v7m.vecbase[M_REG_S] = cpu->init_svtor; + + /* Load the initial SP and PC from offset 0 and 4 in the vector table */ + vecbase = env->v7m.vecbase[env->v7m.secure]; + rom = rom_ptr(vecbase); if (rom) { /* Address zero is covered by ROM which hasn't yet been * copied into physical memory. @@ -227,8 +231,8 @@ static void arm_cpu_reset(CPUState *s) * it got copied into memory. In the latter case, rom_ptr * will return a NULL pointer and we should use ldl_phys instead. */ - initial_msp = ldl_phys(s->as, 0); - initial_pc = ldl_phys(s->as, 4); + initial_msp = ldl_phys(s->as, vecbase); + initial_pc = ldl_phys(s->as, vecbase + 4); } env->regs[13] = initial_msp & 0xFFFFFFFC; @@ -623,6 +627,10 @@ static Property arm_cpu_pmsav7_dregion_property = pmsav7_dregion, qdev_prop_uint32, uint32_t); +/* M profile: initial value of the Secure VTOR */ +static Property arm_cpu_initsvtor_property = + DEFINE_PROP_UINT32("init-svtor", ARMCPU, init_svtor, 0); + static void arm_cpu_post_init(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -693,6 +701,8 @@ static void arm_cpu_post_init(Object *obj) qdev_prop_allow_set_link_before_realize, OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); + qdev_property_add_static(DEVICE(obj), &arm_cpu_initsvtor_property, + &error_abort); } qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property, From patchwork Tue Feb 20 18:03:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128953 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910250ljc; Tue, 20 Feb 2018 10:03:31 -0800 (PST) X-Google-Smtp-Source: AH8x224WxgFUrL4HqCka4SNUy/YxMoT0WmZVPP1fmGs92dpLEtJR62FT5G4q95Iqn3FywqUGqCDq X-Received: by 10.223.167.5 with SMTP id c5mr431730wrd.188.1519149811880; Tue, 20 Feb 2018 10:03:31 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149811; cv=none; d=google.com; s=arc-20160816; b=gKiY37cqLGBR0ln//XguQuzdmfO3iQ805tsyujpmksJkDrAuiMvrcrDF5eHnG3AsXG Leek0X1MBqnuyxMJZTCT0n7HPwV4gBg//mrBRRmnH06FPhmxwu96eLrCiufsiZWkQsUQ mMw6ksqPZPLBWpKuRgkRPt0ybWkmG0Ef2MxAGQ7ZWxSiocDbjN2eOw1okRxK9g5G6qSg pxwCGcTRNOQ+6LdpdpNLDDjmJCWXMz7Ow5Iqwzs6tgBpc4cTKPJlt+5mFFDYSY2Bv9ej ej3P47+DhciVOo1JUr4stADKf+JeMLYOpAnkExwjmfq+NbCCMYy2Vq/FUy7OhGaeOHAo toiw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=0Cbds/IGqZAFv9DEOSAMpbJmZBrT9NXXNd5pY9IBOVQ=; b=jlwAQBwaPkylkHU+UNEHtD0hUhSL+B8BxCo2RkqKN968ZQFfvLRJ1zkA6tXedd4IJX whpc+tmyP+0wAg907417QDeifte6NORfQIB3yWz4/uUwfyMxW9Fg4/d+cvdypSi6INIB Ofjc8x5YaiC4KbQ0ypJZVSovtqK7QF5DU64TKLUTV0+qR83AeigXSWmnYumOA7CbShpT BfTxTeADypudyFp8EGW5TxPfZ4qAUoI6SviNyl9l2i0vHnouYO2CTFnMEQ4gs0ekcRug PYvrAAwGANEKvgPL93VrtKzmmX5Jz/zhWLOKIx0yq2ZKifiMmGG8WhqHXJwPpiFqS6bt pYRw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id j18si8478030wrc.479.2018.02.20.10.03.31 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:31 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGJ-0008Rg-Ej; Tue, 20 Feb 2018 18:03:31 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 07/19] armv7m: Forward init-svtor property to CPU object Date: Tue, 20 Feb 2018 18:03:13 +0000 Message-Id: <20180220180325.29818-8-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> Create an "init-svtor" property on the armv7m container object which we can forward to the CPU object. Signed-off-by: Peter Maydell --- include/hw/arm/armv7m.h | 2 ++ hw/arm/armv7m.c | 6 ++++++ 2 files changed, 8 insertions(+) -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/include/hw/arm/armv7m.h b/include/hw/arm/armv7m.h index 5c3f406ccc..78308d1484 100644 --- a/include/hw/arm/armv7m.h +++ b/include/hw/arm/armv7m.h @@ -42,6 +42,7 @@ typedef struct { * that CPU accesses see. (The NVIC, bitbanding and other CPU-internal * devices will be automatically layered on top of this view.) * + Property "idau": IDAU interface (forwarded to CPU object) + * + Property "init-svtor": secure VTOR reset value (forwarded to CPU object) */ typedef struct ARMv7MState { /*< private >*/ @@ -61,6 +62,7 @@ typedef struct ARMv7MState { /* MemoryRegion the board provides to us (with its devices, RAM, etc) */ MemoryRegion *board_memory; Object *idau; + uint32_t init_svtor; } ARMv7MState; #endif diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 189066812c..149aa07cd5 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -168,6 +168,11 @@ static void armv7m_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } + object_property_set_uint(OBJECT(s->cpu), s->init_svtor, "init-svtor", &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } object_property_set_bool(OBJECT(s->cpu), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); @@ -224,6 +229,7 @@ static Property armv7m_properties[] = { DEFINE_PROP_LINK("memory", ARMv7MState, board_memory, TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_LINK("idau", ARMv7MState, idau, TYPE_IDAU_INTERFACE, Object *), + DEFINE_PROP_UINT32("init-svtor", ARMv7MState, init_svtor, 0), DEFINE_PROP_END_OF_LIST(), }; From patchwork Tue Feb 20 18:03:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128954 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910270ljc; Tue, 20 Feb 2018 10:03:32 -0800 (PST) X-Google-Smtp-Source: AH8x224xNcLm6sLfecqQeEo33yJi5PVFzH1k3pwS1AHXcHq63RaJ+aRZXtTfsxoThIy+FgJqM+d8 X-Received: by 10.223.149.68 with SMTP id 62mr434937wrs.249.1519149812594; Tue, 20 Feb 2018 10:03:32 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149812; cv=none; d=google.com; s=arc-20160816; b=0SjH+Czu8mMgUDycSdcFcOiN9lYTSJuh+CjwJWitBBD1nQw1CGsxL/Tm4Nb3SB/NiK Zzf/stkjh9O5NZ0fEoIl0F0VFKWNFPxpLpX5g1XMwXtV535c0w+dM9e7K1lWDFjLXneT TUHXKtt6cQtPuxJAh+RwDxpGnO6cndjAvwVRG/Fi4pSj8sCnYfDIHQ03gHUJG+QQ/H9n qDG3mH60RzveN7Qoeq49rQqC9Lev40A3y58S4G28KcCaYQhhvbb1jvktF3es0AIp+jW/ PEl0B70QjW+ZTuWA952t88AN6M6LjyEXh3eNOP1xgot157Laq4QPU2nV4aDGL2Zt2m2+ Pawg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=RYZmX90QD7DWLPkAEIgqPUG9ieSyj89Hpfjg7x6iZs8=; b=bejV/zmpbGfrRaSsB6dHn4gRIv5xjpj/m1arUn1DdG+xqd8qbw3kebcV6RshstvQX9 HLO3+PR0HUzB2W2JBhyqtzMEJo3ECGTJ5cocXtZwLe6ED2tEZFGil2xULX22AVsQP/vY +q4nHKhspY4leoF+vKq3C8YrrTRz+ryo6rDdEi7Ab4hB+EvBI3lRPIa409cwBp1f/CUl 7ePJt9ymK4gJ2YPCYsUq2/5zTgH2s8cK1Dw7PPoTvdtVVsjBYFtdEVunzDg3Q6E4aLHN VVbwtc66GPvPd7N281uChpxzg1sC9fs/XrRZhfcCEut1/NvGlxOBkOj1o3AFgGXwLNRe A/uQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id z2si791233wmg.237.2018.02.20.10.03.32 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:32 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGK-0008Rv-4p; Tue, 20 Feb 2018 18:03:32 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 08/19] target/arm: Add Cortex-M33 Date: Tue, 20 Feb 2018 18:03:14 +0000 Message-Id: <20180220180325.29818-9-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> Add a Cortex-M33 definition. The M33 is an M profile CPU which implements the ARM v8M architecture, including the M profile Security Extension. Signed-off-by: Peter Maydell --- target/arm/cpu.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 34b5a4a00b..897003a186 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1205,6 +1205,35 @@ static void cortex_m4_initfn(Object *obj) cpu->id_isar5 = 0x00000000; } +static void cortex_m33_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_M); + set_feature(&cpu->env, ARM_FEATURE_M_SECURITY); + set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); + cpu->midr = 0x410fd213; /* r0p3 */ + cpu->pmsav7_dregion = 16; + cpu->sau_sregion = 8; + cpu->id_pfr0 = 0x00000030; + cpu->id_pfr1 = 0x00000210; + cpu->id_dfr0 = 0x00200000; + cpu->id_afr0 = 0x00000000; + cpu->id_mmfr0 = 0x00101F40; + cpu->id_mmfr1 = 0x00000000; + cpu->id_mmfr2 = 0x01000000; + cpu->id_mmfr3 = 0x00000000; + cpu->id_isar0 = 0x01101110; + cpu->id_isar1 = 0x02212000; + cpu->id_isar2 = 0x20232232; + cpu->id_isar3 = 0x01111131; + cpu->id_isar4 = 0x01310132; + cpu->id_isar5 = 0x00000000; + cpu->clidr = 0x00000000; + cpu->ctr = 0x8000c000; +} + static void arm_v7m_class_init(ObjectClass *oc, void *data) { CPUClass *cc = CPU_CLASS(oc); @@ -1696,6 +1725,8 @@ static const ARMCPUInfo arm_cpus[] = { .class_init = arm_v7m_class_init }, { .name = "cortex-m4", .initfn = cortex_m4_initfn, .class_init = arm_v7m_class_init }, + { .name = "cortex-m33", .initfn = cortex_m33_initfn, + .class_init = arm_v7m_class_init }, { .name = "cortex-r5", .initfn = cortex_r5_initfn }, { .name = "cortex-a7", .initfn = cortex_a7_initfn }, { .name = "cortex-a8", .initfn = cortex_a8_initfn }, From patchwork Tue Feb 20 18:03:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128955 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910285ljc; Tue, 20 Feb 2018 10:03:33 -0800 (PST) X-Google-Smtp-Source: AH8x224BDxSlDSgp2FAdY3cHvW6PX8pkUiMum7TWoXTzE3H+Fucg6tIuLosbCMvswbYgG86PL0Zt X-Received: by 10.223.164.221 with SMTP id h29mr431451wrb.259.1519149813299; Tue, 20 Feb 2018 10:03:33 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149813; cv=none; d=google.com; s=arc-20160816; b=Z7ue+vV381Q586Ca/M5EOUPllckdSVG6KsPeNIQHonFKZ9nGjPE2WHETkAPyevg7UX aJdd1ewP7zJQyzl1/56vWpJZ0io9VjwLol6geMFU6cRAMWszBdVl1cdRthnwR7S3bwKA 17k3Nj+xGmRtUrxRoCHXpnJkmp6v74VMzwAmJDeCrqUXXmUTEagZhisGDpNe8vTan4g3 LdkAcVurZLlKKrV8F5rMKKmY85uyM4K1G5qQ/BslVOuGRVSajBfogz5mYmYrtqeVhMGe GnQYP5S91CXUkByUdZ4ZLzZTr8Sq+GL3f3aRHH0iVTcj5HhvipEOBsHzzOydZdX4pK0b bKBA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=Nu0uc5UQoBK0lrd4Q3Zr+Xjg7pTQ4WDc2ujZf06wKdo=; b=OyNO6jrQsHqhqGO1elB3fuz0d4SH/CZ7qFMXvoRQG6TRB8/7d7dJimXURrQgkbxF0+ FGZSJqUpcOZOQ1ESkMKQ84aKfXyYkfusSUvrROnee9lvtPIIIQ4gJfYiDMN2y8+0c0go q1DQh8HOOze8D8BbFgqV0XeBB5bDM2uEcW6huC8aqnzJo+sfISKrdx3VDLkhUJ5FcxNg YFgi1wxxEOBEtK8B7KFz7UgMBhCQZ4sqwbvGhR0IbeLKGe/Wl4c/7d4vcaYYsUGpWJSS BK0CL8cv5xJ+I2iSb9FVpsyP0m2yLqOlxgyS0yDAFY6P4413MAPc9eMHuEQY4XAzjLlz uwmA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id z8si7748819wrg.167.2018.02.20.10.03.33 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:33 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGK-0008SA-RT; Tue, 20 Feb 2018 18:03:32 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 09/19] hw/misc/unimp: Move struct to header file Date: Tue, 20 Feb 2018 18:03:15 +0000 Message-Id: <20180220180325.29818-10-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> Move the definition of the struct for the unimplemented-device from unimp.c to unimp.h, so that users can embed the struct in their own device structs if they prefer. Signed-off-by: Peter Maydell --- include/hw/misc/unimp.h | 10 ++++++++++ hw/misc/unimp.c | 10 ---------- 2 files changed, 10 insertions(+), 10 deletions(-) -- 2.16.1 Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson diff --git a/include/hw/misc/unimp.h b/include/hw/misc/unimp.h index 52e068ec3e..2a291ca42d 100644 --- a/include/hw/misc/unimp.h +++ b/include/hw/misc/unimp.h @@ -12,6 +12,16 @@ #define TYPE_UNIMPLEMENTED_DEVICE "unimplemented-device" +#define UNIMPLEMENTED_DEVICE(obj) \ + OBJECT_CHECK(UnimplementedDeviceState, (obj), TYPE_UNIMPLEMENTED_DEVICE) + +typedef struct { + SysBusDevice parent_obj; + MemoryRegion iomem; + char *name; + uint64_t size; +} UnimplementedDeviceState; + /** * create_unimplemented_device: create and map a dummy device * @name: name of the device for debug logging diff --git a/hw/misc/unimp.c b/hw/misc/unimp.c index bcbb585888..1c0ba2f0a7 100644 --- a/hw/misc/unimp.c +++ b/hw/misc/unimp.c @@ -18,16 +18,6 @@ #include "qemu/log.h" #include "qapi/error.h" -#define UNIMPLEMENTED_DEVICE(obj) \ - OBJECT_CHECK(UnimplementedDeviceState, (obj), TYPE_UNIMPLEMENTED_DEVICE) - -typedef struct { - SysBusDevice parent_obj; - MemoryRegion iomem; - char *name; - uint64_t size; -} UnimplementedDeviceState; - static uint64_t unimp_read(void *opaque, hwaddr offset, unsigned size) { UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(opaque); From patchwork Tue Feb 20 18:03:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128956 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910300ljc; Tue, 20 Feb 2018 10:03:34 -0800 (PST) X-Google-Smtp-Source: AH8x225+VGKduB+YcdprShwN7v2AD3ogB3hVgQhPLwzr1XDD/AyjBqHTurUygs93UxC2SHdRsM1j X-Received: by 10.223.128.104 with SMTP id 95mr455705wrk.139.1519149814014; Tue, 20 Feb 2018 10:03:34 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149814; cv=none; d=google.com; s=arc-20160816; b=o2BXVMlKOysY0khf3lJKzMun5VH4jE2x4RBoayQciV424EcMOyCCunC4FaD8JpDZnx Wrp+q7FvgldbrQ14yFKjDLFFHVdAcBmqx+oeApCp5MGgdbqIVdX5nwmkAn33CLz5Lduf oaC5HOzqfOCHqLcnvtWGbc1LPRgXhDpshsf9RyLjvxDjYmBdZeXZ/0bM/eFe8+OS/9uZ DPZEnH3556Qd/vySg9v4564woqBrRf5LDrTsAEs9oHROlWBr6ga/eJgo1+PqWio5HaE9 t2T656RUaMze3bOHMQxf7cKV8K6CmIa0eMOHGEe1bDFDj3K1c+lq3LjmLpCDLyqVZd3R tXXQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=O3BrtQx4SO5LOAQKzMgLzcMX/jSOw42djrxN0OBQ6Eo=; b=Hdtbbosu1JpZZPKavJkzjVwpvmebzmq1Ris6QgqWZ46gzVrRk1Ra0MT51Kqpn7JC76 boUjQCc1NovWr825RwGnWBJDoUEasjhRjIr9t9MQaU8pf0Q2Hvolys3K5YpgI/bfiMoM GlA2vEMIGlyD53HPU0RngCoa6cKWAoqDh9TeJwM30DcFtJ2hdjhJa4LCQgkFEfJWkWpN BfekJzU7C0+txEHqzjTklzOpJFMgd2h7Q1BM3lXdLMYCwElpDTEXXKbAyM4DMUNKqxL0 7ivQdqnNwBVGM/TGTNXDSjL0+O6ZzTmvcy+mM+0+BPEA1NYPIDnc/AWn8DyrDuO4Yt1m kThA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id 76si15949933wmy.183.2018.02.20.10.03.33 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:34 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGL-0008SP-HX; Tue, 20 Feb 2018 18:03:33 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 10/19] include/hw/or-irq.h: Add missing include guard Date: Tue, 20 Feb 2018 18:03:16 +0000 Message-Id: <20180220180325.29818-11-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> The or-irq.h header file is missing the customary guard against multiple inclusion, which means compilation fails if it gets included twice. Fix the omission. Signed-off-by: Peter Maydell --- include/hw/or-irq.h | 5 +++++ 1 file changed, 5 insertions(+) -- 2.16.1 Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson diff --git a/include/hw/or-irq.h b/include/hw/or-irq.h index fd900fcf19..3f6fc1b58a 100644 --- a/include/hw/or-irq.h +++ b/include/hw/or-irq.h @@ -22,6 +22,9 @@ * THE SOFTWARE. */ +#ifndef HW_OR_IRQ_H +#define HW_OR_IRQ_H + #include "hw/irq.h" #include "hw/sysbus.h" #include "qom/object.h" @@ -41,3 +44,5 @@ struct OrIRQState { bool levels[MAX_OR_LINES]; uint16_t num_lines; }; + +#endif From patchwork Tue Feb 20 18:03:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128957 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910316ljc; Tue, 20 Feb 2018 10:03:34 -0800 (PST) X-Google-Smtp-Source: AH8x2245yGQOI2xuW5+9CU2Yr1sKarB/Qxt8I1x5jKESZPexFSxmUjgXeDcPpbwTpP/YrHoN5Th2 X-Received: by 10.28.211.132 with SMTP id k126mr884061wmg.142.1519149814686; Tue, 20 Feb 2018 10:03:34 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149814; cv=none; d=google.com; s=arc-20160816; b=Feyd/0N5XgJnV7nsCY7RsUumHjfw2sgKB8Rsjld4VVJU1derPj0NrM+Bg+HbDP7okQ v77QHjORLclV+3mN3vWuCuK4wsM3tya/MTNwOWgk+BVrXsqhQ08E0fw4/JdJhJZXf2zF JuxQu2BZfPUIuiqoPtTy0q3qlkN/INVVQ8hHOpJVyAvl+gNe+GPJgLRrGSNgAm+EGGyj oqgzWOTbv9bQLE6rR0AJ73ajrMzz+g2PghoXxUBVYMOpYJ+p04Wb16cf5OSbWsDIBZhw cXRg8INAAhofpFkzgbGLyLwpeWHRqtQR0HGb2kNd1+vtpyemHyqlkQw63syFsRUPtovi rpWA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=r/phLS6OwwUEfyUsfYa81/e3KeqoOghb4ueFpEE3xBw=; b=TQ06w1FLqmF4Fjpl9O7Mv44Q/yOWawRdOCk59VQBW8X9H6/NKsl4DOlF66SjsIYMnd xN2OnYkzeibCWyx3+FsZpvkfOt2oV0H62IzU02GvTrHjW7Dz3h+URjxUyjkV99Ll16cj B7r2EIbWq5Rm0R+oVI2hhiiSjwECv+LdvsuyS5GSoHELdCmEEX+wxlNGnUTo4pcDD1RY uKcQWcVSQN5/OoVP+eFRi6WReJ5XZQcIlxy8TpMD6p7bPY1krz/hkf6AYXZJT1/uoNxI eubnyjaNdIi6uxm0Bn/j++QbwXX2TE6NmuFAyzTtjDpMrgCkvuSozhbEY4rMm/M8ThA3 /ehg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id 46si14372713wrc.265.2018.02.20.10.03.34 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:34 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGM-0008Se-8H; Tue, 20 Feb 2018 18:03:34 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 11/19] qdev: Add new qdev_init_gpio_in_named_with_opaque() Date: Tue, 20 Feb 2018 18:03:17 +0000 Message-Id: <20180220180325.29818-12-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> The function qdev_init_gpio_in_named() passes the DeviceState pointer as the opaque data pointor for the irq handler function. Usually this is what you want, but in some cases it would be helpful to use some other data pointer. Add a new function qdev_init_gpio_in_named_with_opaque() which allows the caller to specify the data pointer they want. Signed-off-by: Peter Maydell --- include/hw/qdev-core.h | 30 ++++++++++++++++++++++++++++-- hw/core/qdev.c | 8 +++++--- 2 files changed, 33 insertions(+), 5 deletions(-) -- 2.16.1 Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index fc9d617a76..9453588160 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -311,10 +311,36 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name); /* GPIO inputs also double as IRQ sinks. */ void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n); void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n); -void qdev_init_gpio_in_named(DeviceState *dev, qemu_irq_handler handler, - const char *name, int n); void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins, const char *name, int n); +/** + * qdev_init_gpio_in_named_with_opaque: create an array of input GPIO lines + * for the specified device + * + * @dev: Device to create input GPIOs for + * @handler: Function to call when GPIO line value is set + * @opaque: Opaque data pointer to pass to @handler + * @name: Name of the GPIO input (must be unique for this device) + * @n: Number of GPIO lines in this input set + */ +void qdev_init_gpio_in_named_with_opaque(DeviceState *dev, + qemu_irq_handler handler, + void *opaque, + const char *name, int n); + +/** + * qdev_init_gpio_in_named: create an array of input GPIO lines + * for the specified device + * + * Like qdev_init_gpio_in_named_with_opaque(), but the opaque pointer + * passed to the handler is @dev (which is the most commonly desired behaviour). + */ +static inline void qdev_init_gpio_in_named(DeviceState *dev, + qemu_irq_handler handler, + const char *name, int n) +{ + qdev_init_gpio_in_named_with_opaque(dev, handler, dev, name, n); +} void qdev_pass_gpios(DeviceState *dev, DeviceState *container, const char *name); diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 7ed1f431f0..f3754ee606 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -385,15 +385,17 @@ static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev, return ngl; } -void qdev_init_gpio_in_named(DeviceState *dev, qemu_irq_handler handler, - const char *name, int n) +void qdev_init_gpio_in_named_with_opaque(DeviceState *dev, + qemu_irq_handler handler, + void *opaque, + const char *name, int n) { int i; NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); assert(gpio_list->num_out == 0 || !name); gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler, - dev, n); + opaque, n); if (!name) { name = "unnamed-gpio-in"; From patchwork Tue Feb 20 18:03:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128958 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910331ljc; Tue, 20 Feb 2018 10:03:35 -0800 (PST) X-Google-Smtp-Source: AH8x227FG9aE+lKEzIaEa/fty3WHT1F6n17jpdlKnGBGP9vCS7pVN7oRxSJ8CgXP+oXGcdNM79R/ X-Received: by 10.28.20.206 with SMTP id 197mr891860wmu.19.1519149815472; Tue, 20 Feb 2018 10:03:35 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149815; cv=none; d=google.com; s=arc-20160816; b=xp15JsMVNN92US15X5ZI16D9fqcHzFXXsYuH8rZLw40Th7D//G6KKC9SG8n5foS7HU AYmucZgd/kC3uEhHfjkAqpPXUTIQAyNyQ7jodWmqvZ1CaWaDjIdFa+I+yJc5afNIFokM Fd5PZPW6c7uLntlcWOjIBML2WYdxnZeKcq55nyY1HWhHCTUaEmVzKVRisa0pxtlLlsxk aFtXm+G54acwhvnoto+G+Y1Yk5mqXOFDDZv0ckbELv8HvmWoeE+NcmezMnkesgOW+FBO qopwIakWu8kqHwvGRN5Bc0YgG175lIxuXRO+LXsvJIuuZVnWY4lJFT0ZU/TWQevjb29m zzkg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=oGvF1f1dEBs1zbWxuhxVmsyMpUA5XiLuKTmOn5ugjHc=; b=JtcjD4fdsK3phhGnerOTNYFkb/IXEIskoIThpZQuc3YwxSdpgLmTbg/6x/uezysVgU 4ZErIhFdXWdtNmA/wGsnIuyqZeTUn+hG2TDNa7dOY/vepEA4r4rNXxFH5B8WHjWgJv1A Okq59ylSORt5tJbA95jNnF5suJcI4tEi5vDzW8G/qwFKds17kXtMFFasjcZJuXt5Y5Oq tUO8vkVdXARlevM5GtLVf0TCvxP/XR7hN9Rx4b4CR3PuSOuPyYkkjeP1oVkcp7E6d36M LiNHwtofAvzRMi1HryLOIPD2UqNDQC46vs3gfHDdQbYyAvAoDUZQ7Qi+ky0Lls7uvg1D xPIA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id f12si19558934wrh.517.2018.02.20.10.03.35 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:35 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGM-0008St-VI; Tue, 20 Feb 2018 18:03:34 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 12/19] hw/core/split-irq: Device that splits IRQ lines Date: Tue, 20 Feb 2018 18:03:18 +0000 Message-Id: <20180220180325.29818-13-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> In some board or SoC models it is necessary to split a qemu_irq line so that one input can feed multiple outputs. We currently have qemu_irq_split() for this, but that has several deficiencies: * it can only handle splitting a line into two * it unavoidably leaks memory, so it can't be used in a device that can be deleted Implement a qdev device that encapsulates splitting of IRQs, with a configurable number of outputs. (This is in some ways the inverse of the TYPE_OR_IRQ device.) Signed-off-by: Peter Maydell --- hw/core/Makefile.objs | 1 + include/hw/core/split-irq.h | 57 +++++++++++++++++++++++++++++ include/hw/irq.h | 4 +- hw/core/split-irq.c | 89 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 include/hw/core/split-irq.h create mode 100644 hw/core/split-irq.c -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index 1240728c87..eb88ca979e 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -18,6 +18,7 @@ common-obj-$(CONFIG_FITLOADER) += loader-fit.o common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o common-obj-$(CONFIG_SOFTMMU) += register.o common-obj-$(CONFIG_SOFTMMU) += or-irq.o +common-obj-$(CONFIG_SOFTMMU) += split-irq.o common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o obj-$(CONFIG_SOFTMMU) += generic-loader.o diff --git a/include/hw/core/split-irq.h b/include/hw/core/split-irq.h new file mode 100644 index 0000000000..bb87157c5a --- /dev/null +++ b/include/hw/core/split-irq.h @@ -0,0 +1,57 @@ +/* + * IRQ splitter device. + * + * Copyright (c) 2018 Linaro Limited. + * Written by Peter Maydell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* This is a simple device which has one GPIO input line and multiple + * GPIO output lines. Any change on the input line is forwarded to all + * of the outputs. + * + * QEMU interface: + * + one unnamed GPIO input: the input line + * + N unnamed GPIO outputs: the output lines + * + QOM property "num-lines": sets the number of output lines + */ +#ifndef HW_SPLIT_IRQ_H +#define HW_SPLIT_IRQ_H + +#include "hw/irq.h" +#include "hw/sysbus.h" +#include "qom/object.h" + +#define TYPE_SPLIT_IRQ "split-irq" + +#define MAX_SPLIT_LINES 16 + +typedef struct SplitIRQ SplitIRQ; + +#define SPLIT_IRQ(obj) OBJECT_CHECK(SplitIRQ, (obj), TYPE_SPLIT_IRQ) + +struct SplitIRQ { + DeviceState parent_obj; + + qemu_irq out_irq[MAX_SPLIT_LINES]; + uint16_t num_lines; +}; + +#endif diff --git a/include/hw/irq.h b/include/hw/irq.h index 4c4c2eaf9a..7a40e3ed26 100644 --- a/include/hw/irq.h +++ b/include/hw/irq.h @@ -50,7 +50,9 @@ void qemu_free_irq(qemu_irq irq); /* Returns a new IRQ with opposite polarity. */ qemu_irq qemu_irq_invert(qemu_irq irq); -/* Returns a new IRQ which feeds into both the passed IRQs */ +/* Returns a new IRQ which feeds into both the passed IRQs. + * It's probably better to use the TYPE_SPLIT_IRQ device instead. + */ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2); /* Returns a new IRQ set which connects 1:1 to another IRQ set, which diff --git a/hw/core/split-irq.c b/hw/core/split-irq.c new file mode 100644 index 0000000000..7e64cd4969 --- /dev/null +++ b/hw/core/split-irq.c @@ -0,0 +1,89 @@ +/* + * IRQ splitter device. + * + * Copyright (c) 2018 Linaro Limited. + * Written by Peter Maydell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/core/split-irq.h" +#include "qapi/error.h" + +static void split_irq_handler(void *opaque, int n, int level) +{ + SplitIRQ *s = SPLIT_IRQ(opaque); + int i; + + for (i = 0; i < s->num_lines; i++) { + qemu_set_irq(s->out_irq[i], level); + } +} + +static void split_irq_init(Object *obj) +{ + qdev_init_gpio_in(DEVICE(obj), split_irq_handler, 1); +} + +static void split_irq_realize(DeviceState *dev, Error **errp) +{ + SplitIRQ *s = SPLIT_IRQ(dev); + + if (s->num_lines < 1 || s->num_lines >= MAX_SPLIT_LINES) { + error_setg(errp, + "IRQ splitter number of lines %d is not between 1 and %d", + s->num_lines, MAX_SPLIT_LINES); + return; + } + + qdev_init_gpio_out(dev, s->out_irq, s->num_lines); +} + +static Property split_irq_properties[] = { + DEFINE_PROP_UINT16("num-lines", SplitIRQ, num_lines, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void split_irq_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + /* No state to reset or migrate */ + dc->props = split_irq_properties; + dc->realize = split_irq_realize; + + /* Reason: Needs to be wired up to work */ + dc->user_creatable = false; +} + +static const TypeInfo split_irq_type_info = { + .name = TYPE_SPLIT_IRQ, + .parent = TYPE_DEVICE, + .instance_size = sizeof(SplitIRQ), + .instance_init = split_irq_init, + .class_init = split_irq_class_init, +}; + +static void split_irq_register_types(void) +{ + type_register_static(&split_irq_type_info); +} + +type_init(split_irq_register_types) From patchwork Tue Feb 20 18:03:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128959 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910345ljc; Tue, 20 Feb 2018 10:03:36 -0800 (PST) X-Google-Smtp-Source: AH8x227XDrTFNcasNaD/uSdlSOFhP9VUH3mCkS3DHSG0x/S+AY+lF83sYDjhCKfkXXCnNBPtvANf X-Received: by 10.223.163.207 with SMTP id m15mr477677wrb.174.1519149816221; Tue, 20 Feb 2018 10:03:36 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149816; cv=none; d=google.com; s=arc-20160816; b=YZUBMg4Si92pOWetlkFrMawNKT+GjqM3guQVKDm6dx+83PZGmNXBvUHBegjN/y5VTd I8MWNQUG7AamEcEN3UpRrnuThZzARGCTGS3c+pI9xVC5pzuFqXX4clAsiuwWQN4t+yCN 4R63iQZz2yEw3U1PNxNrXzDhPC97WVJzlgPR+UMYlm1Gj3oOHzK9EYagEnD/j+5fXhTZ qq7MMZhN7OnhZQuPYPsSO23P7wZr+762Gl7YwpAS+id0oc2NSK9hgoLmZhxh+QJO2szO OZpOMWvXfCmIPY7PRKS+bxpZiBZCsL0Al6rFUuZ4jLs72W8POFlZr/gSr+mIF5+nyG/4 F2yQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=T+H/XjeNuNq/3qCaAlIggwgYHFVamerFuaIDU4eX24w=; b=q2rs5jdCfdLQQd0ZMPYkNharHsYZUKJiRbLkWy1G+pxtCrHPZk44nV+p1g2l/qhJrd qkotJgWX2NYeODLH9FQp9ZXNL2pL93b+p2ifWFKhasIctPFVXylGutKy3JMUJRzPf3Os W0hNLIC4pMp+ZUlOiKcA5YevnvspkA5mkghHT+8rbgMcXHFGxk8y1GeWJb+JO6xb1atA BOKhH8UalCH/jx04cgjNSgil7a+PTqOnRwdevQCTV+/ECyPzOya9mkcgfnToaUPP+aot ieC+qM53OoGHW2RUpvn4qPmeu4g8Ip622/TCm2U0K9bgzl5AJCPaKI5laQcinqah0U36 6vTw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id g17si9763829wrc.62.2018.02.20.10.03.36 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:36 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGN-0008T8-NM; Tue, 20 Feb 2018 18:03:35 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 13/19] hw/misc/mps2-fpgaio: FPGA control block for MPS2 AN505 Date: Tue, 20 Feb 2018 18:03:19 +0000 Message-Id: <20180220180325.29818-14-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> The MPS2 AN505 FPGA image includes a "FPGA control block" which is a small set of registers handling LEDs, buttons and some counters. Signed-off-by: Peter Maydell --- hw/misc/Makefile.objs | 1 + include/hw/misc/mps2-fpgaio.h | 43 ++++++++++ hw/misc/mps2-fpgaio.c | 176 ++++++++++++++++++++++++++++++++++++++++ default-configs/arm-softmmu.mak | 1 + hw/misc/trace-events | 6 ++ 5 files changed, 227 insertions(+) create mode 100644 include/hw/misc/mps2-fpgaio.h create mode 100644 hw/misc/mps2-fpgaio.c -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index f33b37a8e5..31f83dcfe7 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -58,6 +58,7 @@ obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o obj-$(CONFIG_MIPS_CPS) += mips_cmgcr.o obj-$(CONFIG_MIPS_CPS) += mips_cpc.o obj-$(CONFIG_MIPS_ITU) += mips_itu.o +obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o obj-$(CONFIG_MPS2_SCC) += mps2-scc.o obj-$(CONFIG_PVPANIC) += pvpanic.o diff --git a/include/hw/misc/mps2-fpgaio.h b/include/hw/misc/mps2-fpgaio.h new file mode 100644 index 0000000000..eedf17ebc6 --- /dev/null +++ b/include/hw/misc/mps2-fpgaio.h @@ -0,0 +1,43 @@ +/* + * ARM MPS2 FPGAIO emulation + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +/* This is a model of the FPGAIO register block in the AN505 + * FPGA image for the MPS2 dev board; it is documented in the + * application note: + * http://infocenter.arm.com/help/topic/com.arm.doc.dai0505b/index.html + * + * QEMU interface: + * + sysbus MMIO region 0: the register bank + */ + +#ifndef MPS2_FPGAIO_H +#define MPS2_FPGAIO_H + +#include "hw/sysbus.h" + +#define TYPE_MPS2_FPGAIO "mps2-fpgaio" +#define MPS2_FPGAIO(obj) OBJECT_CHECK(MPS2FPGAIO, (obj), TYPE_MPS2_FPGAIO) + +typedef struct { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + + uint32_t led0; + uint32_t prescale; + uint32_t misc; + + uint32_t prescale_clk; +} MPS2FPGAIO; + +#endif diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c new file mode 100644 index 0000000000..7394a057d8 --- /dev/null +++ b/hw/misc/mps2-fpgaio.c @@ -0,0 +1,176 @@ +/* + * ARM MPS2 AN505 FPGAIO emulation + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +/* This is a model of the "FPGA system control and I/O" block found + * in the AN505 FPGA image for the MPS2 devboard. + * It is documented in AN505: + * http://infocenter.arm.com/help/topic/com.arm.doc.dai0505b/index.html + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "trace.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/mps2-fpgaio.h" + +REG32(LED0, 0) +REG32(BUTTON, 8) +REG32(CLK1HZ, 0x10) +REG32(CLK100HZ, 0x14) +REG32(COUNTER, 0x18) +REG32(PRESCALE, 0x1c) +REG32(PSCNTR, 0x20) +REG32(MISC, 0x4c) + +static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size) +{ + MPS2FPGAIO *s = MPS2_FPGAIO(opaque); + uint64_t r; + + switch (offset) { + case A_LED0: + r = s->led0; + break; + case A_BUTTON: + /* User-pressable board buttons. We don't model that, so just return + * zeroes. + */ + r = 0; + break; + case A_PRESCALE: + r = s->prescale; + break; + case A_MISC: + r = s->misc; + break; + case A_CLK1HZ: + case A_CLK100HZ: + case A_COUNTER: + case A_PSCNTR: + /* These are all upcounters of various frequencies. */ + qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n"); + r = 0; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "MPS2 FPGAIO read: bad offset %x\n", (int) offset); + r = 0; + break; + } + + trace_mps2_fpgaio_read(offset, r, size); + return r; +} + +static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + MPS2FPGAIO *s = MPS2_FPGAIO(opaque); + + trace_mps2_fpgaio_write(offset, value, size); + + switch (offset) { + case A_LED0: + /* LED bits [1:0] control board LEDs. We don't currently have + * a mechanism for displaying this graphically, so use a trace event. + */ + trace_mps2_fpgaio_leds(value & 0x02 ? '*' : '.', + value & 0x01 ? '*' : '.'); + s->led0 = value & 0x3; + break; + case A_PRESCALE: + s->prescale = value; + break; + case A_MISC: + /* These are control bits for some of the other devices on the + * board (SPI, CLCD, etc). We don't implement that yet, so just + * make the bits read as written. + */ + qemu_log_mask(LOG_UNIMP, + "MPS2 FPGAIO: MISC control bits unimplemented\n"); + s->misc = value; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset); + break; + } +} + +static const MemoryRegionOps mps2_fpgaio_ops = { + .read = mps2_fpgaio_read, + .write = mps2_fpgaio_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void mps2_fpgaio_reset(DeviceState *dev) +{ + MPS2FPGAIO *s = MPS2_FPGAIO(dev); + + trace_mps2_fpgaio_reset(); + s->led0 = 0; + s->prescale = 0; + s->misc = 0; +} + +static void mps2_fpgaio_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + MPS2FPGAIO *s = MPS2_FPGAIO(obj); + + memory_region_init_io(&s->iomem, obj, &mps2_fpgaio_ops, s, + "mps2-fpgaio", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription mps2_fpgaio_vmstate = { + .name = "mps2-fpgaio", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(led0, MPS2FPGAIO), + VMSTATE_UINT32(prescale, MPS2FPGAIO), + VMSTATE_UINT32(misc, MPS2FPGAIO), + VMSTATE_END_OF_LIST() + } +}; + +static Property mps2_fpgaio_properties[] = { + /* Frequency of the prescale counter */ + DEFINE_PROP_UINT32("prescale-clk", MPS2FPGAIO, prescale_clk, 20000000), + DEFINE_PROP_END_OF_LIST(), +}; + +static void mps2_fpgaio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &mps2_fpgaio_vmstate; + dc->reset = mps2_fpgaio_reset; + dc->props = mps2_fpgaio_properties; +} + +static const TypeInfo mps2_fpgaio_info = { + .name = TYPE_MPS2_FPGAIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MPS2FPGAIO), + .instance_init = mps2_fpgaio_init, + .class_init = mps2_fpgaio_class_init, +}; + +static void mps2_fpgaio_register_types(void) +{ + type_register_static(&mps2_fpgaio_info); +} + +type_init(mps2_fpgaio_register_types); diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index ca34cf4462..c11b55e385 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -100,6 +100,7 @@ CONFIG_STM32F205_SOC=y CONFIG_CMSDK_APB_TIMER=y CONFIG_CMSDK_APB_UART=y +CONFIG_MPS2_FPGAIO=y CONFIG_MPS2_SCC=y CONFIG_VERSATILE_PCI=y diff --git a/hw/misc/trace-events b/hw/misc/trace-events index b340d4e81c..ef852ffae7 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -62,6 +62,12 @@ mps2_scc_leds(char led7, char led6, char led5, char led4, char led3, char led2, mps2_scc_cfg_write(unsigned function, unsigned device, uint32_t value) "MPS2 SCC config write: function %d device %d data 0x%" PRIx32 mps2_scc_cfg_read(unsigned function, unsigned device, uint32_t value) "MPS2 SCC config read: function %d device %d data 0x%" PRIx32 +# hw/misc/mps2_fpgaio.c +mps2_fpgaio_read(uint64_t offset, uint64_t data, unsigned size) "MPS2 FPGAIO read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" +mps2_fpgaio_write(uint64_t offset, uint64_t data, unsigned size) "MPS2 FPGAIO write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" +mps2_fpgaio_reset(void) "MPS2 FPGAIO: reset" +mps2_fpgaio_leds(char led1, char led0) "MPS2 FPGAIO LEDs: %c%c" + # hw/misc/msf2-sysreg.c msf2_sysreg_write(uint64_t offset, uint32_t val, uint32_t prev) "msf2-sysreg write: addr 0x%08" HWADDR_PRIx " data 0x%" PRIx32 " prev 0x%" PRIx32 msf2_sysreg_read(uint64_t offset, uint32_t val) "msf2-sysreg read: addr 0x%08" HWADDR_PRIx " data 0x%08" PRIx32 From patchwork Tue Feb 20 18:03:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128961 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910370ljc; Tue, 20 Feb 2018 10:03:37 -0800 (PST) X-Google-Smtp-Source: AH8x226ZHo62vlCOXNtm6ry4n4Wk0Bz2u+hgf+vxBTRcTcNIrTej4Gb3Sr6KXgoTh4gvQ+8lMsux X-Received: by 10.28.1.14 with SMTP id 14mr913939wmb.40.1519149817058; Tue, 20 Feb 2018 10:03:37 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149817; cv=none; d=google.com; s=arc-20160816; b=Ua2qLrICqMo+ESGrQmwafTZ3YpBiLCO8WjlHks/iI8dG9M1OaK9xAkknTk/ZZDWt43 seyyxrFFSUiq/o0Rt3o9dtixq2GG4pGFbCNusphnOT8fQ/NrLza8Mpx5tpcL1tqF/ZKY B9ZDBIrQOtOrjz1aSDm7YrOEcWtBPAKjqyKlvvQHGZO1xwOu7EaRTvpRre2qG4c24Ku5 j/j7UvR2tkkVsptlPHkDBnlelblaiEMNsV6m4w6PwaMzU4IA2oZd/C7rj2ThW7ztKSVV Y+aQntfl5jykWPJeDw6cfArw9uHUG/5eNL4sc5R3HhWz4NEpyhsxb7gp+RmDkY46kMEd yiTg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=Yex/NQ7kplFui8oznVCadeqioCfkyQ1MgXRyq2b+pr0=; b=wUZD1x7CqGZeVT1UDV2bAC7OqIhNM6+tzZzeg2hyHKBeK3t72rZiKOw5hw3PYrB2DE lBILAXrQMQSU7MQRKuELNFvKdozGoaFYDUccx/oWjtAERyj+Mc932oumU3xZNcGd+vwV 2yj+B/HUlcYiGLN1piN/KUm+koTT9H9vzWWg5vwJxPsapOyIr0hLNIZu6R6sD+mY+WIf SIVMHCHjZAG1n4DaIjNy4+ZihvZjPm2lxe+/FqaZ5JfS2D8j51ht+1c20wbqVfTQaWZO FH4ML3iAnS74Rv/kzJ37bFztIRAZf3Bw2BxAQjQZrzWHTpls5lA3mrtrvI6MkTXE1Mip cmoQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id y81si14982829wrb.253.2018.02.20.10.03.36 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:37 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGO-0008TN-Fr; Tue, 20 Feb 2018 18:03:36 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 14/19] hw/misc/tz-ppc: Model TrustZone peripheral protection controller Date: Tue, 20 Feb 2018 18:03:20 +0000 Message-Id: <20180220180325.29818-15-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> Add a model of the TrustZone peripheral protection controller (PPC), which is used to gate transactions to non-TZ-aware peripherals so that secure software can configure them to not be accessible to non-secure software. Signed-off-by: Peter Maydell --- hw/misc/Makefile.objs | 2 + include/hw/misc/tz-ppc.h | 101 ++++++++++++++ hw/misc/tz-ppc.c | 302 ++++++++++++++++++++++++++++++++++++++++ default-configs/arm-softmmu.mak | 2 + hw/misc/trace-events | 11 ++ 5 files changed, 418 insertions(+) create mode 100644 include/hw/misc/tz-ppc.h create mode 100644 hw/misc/tz-ppc.c -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 31f83dcfe7..dcf413d730 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -61,6 +61,8 @@ obj-$(CONFIG_MIPS_ITU) += mips_itu.o obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o obj-$(CONFIG_MPS2_SCC) += mps2-scc.o +obj-$(CONFIG_TZ_PPC) += tz-ppc.o + obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o obj-$(CONFIG_AUX) += auxbus.o diff --git a/include/hw/misc/tz-ppc.h b/include/hw/misc/tz-ppc.h new file mode 100644 index 0000000000..fc8b806e4d --- /dev/null +++ b/include/hw/misc/tz-ppc.h @@ -0,0 +1,101 @@ +/* + * ARM TrustZone peripheral protection controller emulation + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +/* This is a model of the TrustZone peripheral protection controller (PPC). + * It is documented in the ARM CoreLink SIE-200 System IP for Embedded TRM + * (DDI 0571G): + * https://developer.arm.com/products/architecture/m-profile/docs/ddi0571/g + * + * The PPC sits in front of peripherals and allows secure software to + * configure it to either pass through or reject transactions. + * Rejected transactions may be configured to either be aborted, or to + * behave as RAZ/WI. An interrupt can be signalled for a rejected transaction. + * + * The PPC has no register interface -- it is configured purely by a + * collection of input signals from other hardware in the system. Typically + * they are either hardwired or exposed in an ad-hoc register interface by + * the SoC that uses the PPC. + * + * This QEMU model can be used to model either the AHB5 or APB4 TZ PPC, + * since the only difference between them is that the AHB version has a + * "default" port which has no security checks applied. In QEMU the default + * port can be emulated simply by wiring its downstream devices directly + * into the parent address space, since the PPC does not need to intercept + * transactions there. + * + * In the hardware, selection of which downstream port to use is done by + * the user's decode logic asserting one of the hsel[] signals. In QEMU, + * we provide 16 MMIO regions, one per port, and the user maps these into + * the desired addresses to implement the address decode. + * + * QEMU interface: + * + sysbus MMIO regions 0..15: MemoryRegions defining the upstream end + * of each of the 16 ports of the PPC + * + Property "port[0..15]": MemoryRegion defining the downstream device(s) + * for each of the 16 ports of the PPC + * + Named GPIO inputs "cfg_nonsec[0..15]": set to 1 if the port should be + * accessible to NonSecure transactions + * + Named GPIO inputs "cfg_ap[0..15]": set to 1 if the port should be + * accessible to non-privileged transactions + * + Named GPIO input "cfg_sec_resp": set to 1 if a rejected transaction should + * result in a transaction error, or 0 for the transaction to RAZ/WI + * + Named GPIO input "irq_enable": set to 1 to enable interrupts + * + Named GPIO input "irq_clear": set to 1 to clear a pending interrupt + * + Named GPIO output "irq": set for a transaction-failed interrupt + * + Property "NONSEC_MASK": if a bit is set in this mask then accesses to + * the associated port do not have the TZ security check performed. (This + * corresponds to the hardware allowing this to be set as a Verilog + * parameter.) + */ + +#ifndef TZ_PPC_H +#define TZ_PPC_H + +#include "hw/sysbus.h" + +#define TYPE_TZ_PPC "tz-ppc" +#define TZ_PPC(obj) OBJECT_CHECK(TZPPC, (obj), TYPE_TZ_PPC) + +#define TZ_NUM_PORTS 16 + +typedef struct TZPPC TZPPC; + +typedef struct TZPPCPort { + TZPPC *ppc; + MemoryRegion upstream; + AddressSpace downstream_as; + MemoryRegion *downstream; +} TZPPCPort; + +struct TZPPC { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + + /* State: these just track the values of our input signals */ + bool cfg_nonsec[TZ_NUM_PORTS]; + bool cfg_ap[TZ_NUM_PORTS]; + bool cfg_sec_resp; + bool irq_enable; + bool irq_clear; + /* State: are we asserting irq ? */ + bool irq_status; + + qemu_irq irq; + + /* Properties */ + uint32_t nonsec_mask; + + TZPPCPort port[TZ_NUM_PORTS]; +}; + +#endif diff --git a/hw/misc/tz-ppc.c b/hw/misc/tz-ppc.c new file mode 100644 index 0000000000..3dd045c15f --- /dev/null +++ b/hw/misc/tz-ppc.c @@ -0,0 +1,302 @@ +/* + * ARM TrustZone peripheral protection controller emulation + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "trace.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/tz-ppc.h" + +static void tz_ppc_update_irq(TZPPC *s) +{ + bool level = s->irq_status && s->irq_enable; + + trace_tz_ppc_update_irq(level); + qemu_set_irq(s->irq, level); +} + +static void tz_ppc_cfg_nonsec(void *opaque, int n, int level) +{ + TZPPC *s = TZ_PPC(opaque); + + assert(n < TZ_NUM_PORTS); + trace_tz_ppc_cfg_nonsec(n, level); + s->cfg_nonsec[n] = level; +} + +static void tz_ppc_cfg_ap(void *opaque, int n, int level) +{ + TZPPC *s = TZ_PPC(opaque); + + assert(n < TZ_NUM_PORTS); + trace_tz_ppc_cfg_ap(n, level); + s->cfg_ap[n] = level; +} + +static void tz_ppc_cfg_sec_resp(void *opaque, int n, int level) +{ + TZPPC *s = TZ_PPC(opaque); + + trace_tz_ppc_cfg_sec_resp(level); + s->cfg_sec_resp = level; +} + +static void tz_ppc_irq_enable(void *opaque, int n, int level) +{ + TZPPC *s = TZ_PPC(opaque); + + trace_tz_ppc_irq_enable(level); + s->irq_enable = level; + tz_ppc_update_irq(s); +} + +static void tz_ppc_irq_clear(void *opaque, int n, int level) +{ + TZPPC *s = TZ_PPC(opaque); + + trace_tz_ppc_irq_clear(level); + + s->irq_clear = level; + if (level) { + s->irq_status = false; + tz_ppc_update_irq(s); + } +} + +static bool tz_ppc_check(TZPPC *s, int n, MemTxAttrs attrs) +{ + /* Check whether to allow an access to port n; return true if + * the check passes, and false if the transaction must be blocked. + * If the latter, the caller must check cfg_sec_resp to determine + * whether to abort or RAZ/WI the transaction. + * The checks are: + * + nonsec_mask suppresses any check of the secure attribute + * + otherwise, block if cfg_nonsec is 1 and transaction is secure, + * or if cfg_nonsec is 0 and transaction is non-secure + * + block if transaction is usermode and cfg_ap is 0 + */ + if ((attrs.secure == s->cfg_nonsec[n] && !(s->nonsec_mask & (1 << n))) || + (attrs.user && !s->cfg_ap[n])) { + /* Block the transaction. */ + if (!s->irq_clear) { + /* Note that holding irq_clear high suppresses interrupts */ + s->irq_status = true; + tz_ppc_update_irq(s); + } + return false; + } + return true; +} + +static MemTxResult tz_ppc_read(void *opaque, hwaddr addr, uint64_t *pdata, + unsigned size, MemTxAttrs attrs) +{ + TZPPCPort *p = opaque; + TZPPC *s = p->ppc; + int n = p - s->port; + AddressSpace *as = &p->downstream_as; + uint64_t data; + MemTxResult res; + + if (!tz_ppc_check(s, n, attrs)) { + trace_tz_ppc_read_blocked(n, addr, attrs.secure, attrs.user); + if (s->cfg_sec_resp) { + return MEMTX_ERROR; + } else { + *pdata = 0; + return MEMTX_OK; + } + } + + switch (size) { + case 1: + data = address_space_ldub(as, addr, attrs, &res); + break; + case 2: + data = address_space_lduw_le(as, addr, attrs, &res); + break; + case 4: + data = address_space_ldl_le(as, addr, attrs, &res); + break; + case 8: + data = address_space_ldq_le(as, addr, attrs, &res); + break; + default: + g_assert_not_reached(); + } + *pdata = data; + return res; +} + +static MemTxResult tz_ppc_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size, MemTxAttrs attrs) +{ + TZPPCPort *p = opaque; + TZPPC *s = p->ppc; + AddressSpace *as = &p->downstream_as; + int n = p - s->port; + MemTxResult res; + + if (!tz_ppc_check(s, n, attrs)) { + trace_tz_ppc_write_blocked(n, addr, attrs.secure, attrs.user); + if (s->cfg_sec_resp) { + return MEMTX_ERROR; + } else { + return MEMTX_OK; + } + } + + switch (size) { + case 1: + address_space_stb(as, addr, val, attrs, &res); + break; + case 2: + address_space_stw_le(as, addr, val, attrs, &res); + break; + case 4: + address_space_stl_le(as, addr, val, attrs, &res); + break; + case 8: + address_space_stq_le(as, addr, val, attrs, &res); + break; + default: + g_assert_not_reached(); + } + return res; +} + +static const MemoryRegionOps tz_ppc_ops = { + .read_with_attrs = tz_ppc_read, + .write_with_attrs = tz_ppc_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void tz_ppc_reset(DeviceState *dev) +{ + TZPPC *s = TZ_PPC(dev); + + trace_tz_ppc_reset(); + s->cfg_sec_resp = false; + memset(s->cfg_nonsec, 0, sizeof(s->cfg_nonsec)); + memset(s->cfg_ap, 0, sizeof(s->cfg_ap)); +} + +static void tz_ppc_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + TZPPC *s = TZ_PPC(obj); + + qdev_init_gpio_in_named(dev, tz_ppc_cfg_nonsec, "cfg_nonsec", TZ_NUM_PORTS); + qdev_init_gpio_in_named(dev, tz_ppc_cfg_ap, "cfg_ap", TZ_NUM_PORTS); + qdev_init_gpio_in_named(dev, tz_ppc_cfg_sec_resp, "cfg_sec_resp", 1); + qdev_init_gpio_in_named(dev, tz_ppc_irq_enable, "irq_enable", 1); + qdev_init_gpio_in_named(dev, tz_ppc_irq_clear, "irq_clear", 1); + qdev_init_gpio_out_named(dev, &s->irq, "irq", 1); +} + +static void tz_ppc_realize(DeviceState *dev, Error **errp) +{ + Object *obj = OBJECT(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + TZPPC *s = TZ_PPC(dev); + int i; + + /* We can't create the upstream end of the port until realize, + * as we don't know the size of the MR used as the downstream until then. + */ + for (i = 0; i < TZ_NUM_PORTS; i++) { + TZPPCPort *port = &s->port[i]; + char *name; + uint64_t size; + + if (!port->downstream) { + continue; + } + + name = g_strdup_printf("tz-ppc-port[%d]", i); + + port->ppc = s; + address_space_init(&port->downstream_as, port->downstream, name); + + size = memory_region_size(port->downstream); + memory_region_init_io(&port->upstream, obj, &tz_ppc_ops, + port, name, size); + sysbus_init_mmio(sbd, &port->upstream); + g_free(name); + } +} + +static const VMStateDescription tz_ppc_vmstate = { + .name = "tz-ppc", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL_ARRAY(cfg_nonsec, TZPPC, 16), + VMSTATE_BOOL_ARRAY(cfg_ap, TZPPC, 16), + VMSTATE_BOOL(cfg_sec_resp, TZPPC), + VMSTATE_BOOL(irq_enable, TZPPC), + VMSTATE_BOOL(irq_clear, TZPPC), + VMSTATE_BOOL(irq_status, TZPPC), + VMSTATE_END_OF_LIST() + } +}; + +#define DEFINE_PORT(N) \ + DEFINE_PROP_LINK("port[" #N "]", TZPPC, port[N].downstream, \ + TYPE_MEMORY_REGION, MemoryRegion *) + +static Property tz_ppc_properties[] = { + DEFINE_PROP_UINT32("NONSEC_MASK", TZPPC, nonsec_mask, 0), + DEFINE_PORT(0), + DEFINE_PORT(1), + DEFINE_PORT(2), + DEFINE_PORT(3), + DEFINE_PORT(4), + DEFINE_PORT(5), + DEFINE_PORT(6), + DEFINE_PORT(7), + DEFINE_PORT(8), + DEFINE_PORT(9), + DEFINE_PORT(10), + DEFINE_PORT(11), + DEFINE_PORT(12), + DEFINE_PORT(13), + DEFINE_PORT(14), + DEFINE_PORT(15), + DEFINE_PROP_END_OF_LIST(), +}; + +static void tz_ppc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = tz_ppc_realize; + dc->vmsd = &tz_ppc_vmstate; + dc->reset = tz_ppc_reset; + dc->props = tz_ppc_properties; +} + +static const TypeInfo tz_ppc_info = { + .name = TYPE_TZ_PPC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(TZPPC), + .instance_init = tz_ppc_init, + .class_init = tz_ppc_class_init, +}; + +static void tz_ppc_register_types(void) +{ + type_register_static(&tz_ppc_info); +} + +type_init(tz_ppc_register_types); diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index c11b55e385..6aa564b754 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -103,6 +103,8 @@ CONFIG_CMSDK_APB_UART=y CONFIG_MPS2_FPGAIO=y CONFIG_MPS2_SCC=y +CONFIG_TZ_PPC=y + CONFIG_VERSATILE_PCI=y CONFIG_VERSATILE_I2C=y diff --git a/hw/misc/trace-events b/hw/misc/trace-events index ef852ffae7..0b638de682 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -83,3 +83,14 @@ mos6522_get_next_irq_time(uint16_t latch, int64_t d, int64_t delta) "latch=%d co mos6522_set_sr_int(void) "set sr_int" mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64 mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x" + +# hw/misc/tz-ppc.c +tz_ppc_reset(void) "TZ PPC: reset" +tz_ppc_cfg_nonsec(int n, int level) "TZ PPC: cfg_nonsec[%d] = %d" +tz_ppc_cfg_ap(int n, int level) "TZ PPC: cfg_ap[%d] = %d" +tz_ppc_cfg_sec_resp(int level) "TZ PPC: cfg_sec_resp = %d" +tz_ppc_irq_enable(int level) "TZ PPC: int_enable = %d" +tz_ppc_irq_clear(int level) "TZ PPC: int_clear = %d" +tz_ppc_update_irq(int level) "TZ PPC: setting irq line to %d" +tz_ppc_read_blocked(int n, hwaddr offset, bool secure, bool user) "TZ PPC: port %d offset 0x%" HWADDR_PRIx " read (secure %d user %d) blocked" +tz_ppc_write_blocked(int n, hwaddr offset, bool secure, bool user) "TZ PPC: port %d offset 0x%" HWADDR_PRIx " write (secure %d user %d) blocked" From patchwork Tue Feb 20 18:03:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128960 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910394ljc; Tue, 20 Feb 2018 10:03:38 -0800 (PST) X-Google-Smtp-Source: AH8x226FM8gaNlThbGynR/4PK/upeCvdcFrlzlB84cACB/3YjC7gF+CM6AM6PkQsf42CETijcGnm X-Received: by 10.28.109.10 with SMTP id i10mr957829wmc.107.1519149817935; Tue, 20 Feb 2018 10:03:37 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149817; cv=none; d=google.com; s=arc-20160816; b=fu5JHxKm0RbhejSNOd/aOYTLblpDsEiDLXu5wNOBabySxPRpUO6OLSnok/zK7QSXSv JOermRiuP8jZiw4fdZFa72OIov7qoyxL2m0vEW8ODjC8zEClPY6rlswFF35FJ1TMtYwD zTpy/zcT2EKpBY/2810OQukm7ZjoOUoWvqP2s+vQYsa8N8Ky1+6JdHY6Jexb+yHmjVpD BSs/7UCgdYFB7Z7dgbFeStEvLrVwEDlv5kxPebtyxeAV3IuW7fZBNv7mrw+HqF+zdTsa ii12aqaCz6ztv0NJ9rIerr/f0V8CscPRtXo3VelwQ5h0AhGyO1zdcTiuWNfpCu/u8DQ7 hGXg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=bHkWFdAV3M9krxv9Lj3j/nAZf/ClE8Bcqe3SXXFRGOo=; b=f+VXDYy9RPGZfkGi5NN/sL8DgnHZztj+it+R0kgtfmTwGzBv13CPQThEXYzUhZIkgv OqsPN+iJADwhF4AfQBUQew3oicoDjb+iyID/E50PtAuxaZ/DRQF3toBj7VLwjW38zePH 0WmXKT7+mZRUvu/B5C+L0lpLobu970jLc/VV0VPPwaSt1tjyv0CxLKJhH9qn59+cU2tN skF1LyeKtd9CCAe4NlAZaBaVVPkg4W854bEa+NqaiMhbiuO3Gs+pmhprNlpbOpB4RYDX dDgGUGLJ+AEDDCOe4owRmmYpGxtxdGoE0hgv8DU2iEVJw6+TjvRutAeZV8uvlHB98s3q vP6A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id l2si4830369wra.298.2018.02.20.10.03.37 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:37 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGP-0008Tf-9w; Tue, 20 Feb 2018 18:03:37 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 15/19] hw/misc/iotkit-secctl: Arm IoT Kit security controller initial skeleton Date: Tue, 20 Feb 2018 18:03:21 +0000 Message-Id: <20180220180325.29818-16-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> The Arm IoT Kit includes a "security controller" which is largely a collection of registers for controlling the PPCs and other bits of glue in the system. This commit provides the initial skeleton of the device, implementing just the ID registers, and a couple of read-only read-as-zero registers. Signed-off-by: Peter Maydell --- hw/misc/Makefile.objs | 1 + include/hw/misc/iotkit-secctl.h | 39 ++++ hw/misc/iotkit-secctl.c | 450 ++++++++++++++++++++++++++++++++++++++++ default-configs/arm-softmmu.mak | 1 + hw/misc/trace-events | 7 + 5 files changed, 498 insertions(+) create mode 100644 include/hw/misc/iotkit-secctl.h create mode 100644 hw/misc/iotkit-secctl.c -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index dcf413d730..00e834d0f0 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -62,6 +62,7 @@ obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o obj-$(CONFIG_MPS2_SCC) += mps2-scc.o obj-$(CONFIG_TZ_PPC) += tz-ppc.o +obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o diff --git a/include/hw/misc/iotkit-secctl.h b/include/hw/misc/iotkit-secctl.h new file mode 100644 index 0000000000..872f652f8d --- /dev/null +++ b/include/hw/misc/iotkit-secctl.h @@ -0,0 +1,39 @@ +/* + * ARM IoT Kit security controller + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +/* This is a model of the security controller which is part of the + * Arm IoT Kit and documented in + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html + * + * QEMU interface: + * + sysbus MMIO region 0 is the "secure privilege control block" registers + * + sysbus MMIO region 1 is the "non-secure privilege control block" registers + */ + +#ifndef IOTKIT_SECCTL_H +#define IOTKIT_SECCTL_H + +#include "hw/sysbus.h" + +#define TYPE_IOTKIT_SECCTL "iotkit-secctl" +#define IOTKIT_SECCTL(obj) OBJECT_CHECK(IoTKitSecCtl, (obj), TYPE_IOTKIT_SECCTL) + +typedef struct IoTKitSecCtl { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + + MemoryRegion s_regs; + MemoryRegion ns_regs; +} IoTKitSecCtl; + +#endif diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c new file mode 100644 index 0000000000..5da52e4706 --- /dev/null +++ b/hw/misc/iotkit-secctl.c @@ -0,0 +1,450 @@ +/* + * Arm IoT Kit security controller + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "trace.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/iotkit-secctl.h" + +/* Registers in the secure privilege control block */ +REG32(SECRESPCFG, 0x10) +REG32(NSCCFG, 0x14) +REG32(SECMPCINTSTATUS, 0x1c) +REG32(SECPPCINTSTAT, 0x20) +REG32(SECPPCINTCLR, 0x24) +REG32(SECPPCINTEN, 0x28) +REG32(SECMSCINTSTAT, 0x30) +REG32(SECMSCINTCLR, 0x34) +REG32(SECMSCINTEN, 0x38) +REG32(BRGINTSTAT, 0x40) +REG32(BRGINTCLR, 0x44) +REG32(BRGINTEN, 0x48) +REG32(AHBNSPPC0, 0x50) +REG32(AHBNSPPCEXP0, 0x60) +REG32(AHBNSPPCEXP1, 0x64) +REG32(AHBNSPPCEXP2, 0x68) +REG32(AHBNSPPCEXP3, 0x6c) +REG32(APBNSPPC0, 0x70) +REG32(APBNSPPC1, 0x74) +REG32(APBNSPPCEXP0, 0x80) +REG32(APBNSPPCEXP1, 0x84) +REG32(APBNSPPCEXP2, 0x88) +REG32(APBNSPPCEXP3, 0x8c) +REG32(AHBSPPPC0, 0x90) +REG32(AHBSPPPCEXP0, 0xa0) +REG32(AHBSPPPCEXP1, 0xa4) +REG32(AHBSPPPCEXP2, 0xa8) +REG32(AHBSPPPCEXP3, 0xac) +REG32(APBSPPPC0, 0xb0) +REG32(APBSPPPC1, 0xb4) +REG32(APBSPPPCEXP0, 0xc0) +REG32(APBSPPPCEXP1, 0xc4) +REG32(APBSPPPCEXP2, 0xc8) +REG32(APBSPPPCEXP3, 0xcc) +REG32(NSMSCEXP, 0xd0) +REG32(PID4, 0xfd0) +REG32(PID5, 0xfd4) +REG32(PID6, 0xfd8) +REG32(PID7, 0xfdc) +REG32(PID0, 0xfe0) +REG32(PID1, 0xfe4) +REG32(PID2, 0xfe8) +REG32(PID3, 0xfec) +REG32(CID0, 0xff0) +REG32(CID1, 0xff4) +REG32(CID2, 0xff8) +REG32(CID3, 0xffc) + +/* Registers in the non-secure privilege control block */ +REG32(AHBNSPPPC0, 0x90) +REG32(AHBNSPPPCEXP0, 0xa0) +REG32(AHBNSPPPCEXP1, 0xa4) +REG32(AHBNSPPPCEXP2, 0xa8) +REG32(AHBNSPPPCEXP3, 0xac) +REG32(APBNSPPPC0, 0xb0) +REG32(APBNSPPPC1, 0xb4) +REG32(APBNSPPPCEXP0, 0xc0) +REG32(APBNSPPPCEXP1, 0xc4) +REG32(APBNSPPPCEXP2, 0xc8) +REG32(APBNSPPPCEXP3, 0xcc) +/* PID and CID registers are also present in the NS block */ + +static const uint8_t iotkit_secctl_s_idregs[] = { + 0x04, 0x00, 0x00, 0x00, + 0x52, 0xb8, 0x0b, 0x00, + 0x0d, 0xf0, 0x05, 0xb1, +}; + +static const uint8_t iotkit_secctl_ns_idregs[] = { + 0x04, 0x00, 0x00, 0x00, + 0x53, 0xb8, 0x0b, 0x00, + 0x0d, 0xf0, 0x05, 0xb1, +}; + +static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr, + uint64_t *pdata, + unsigned size, MemTxAttrs attrs) +{ + uint64_t r; + uint32_t offset = addr & ~0x3; + + switch (offset) { + case A_AHBNSPPC0: + case A_AHBSPPPC0: + r = 0; + break; + case A_SECRESPCFG: + case A_NSCCFG: + case A_SECMPCINTSTATUS: + case A_SECPPCINTSTAT: + case A_SECPPCINTEN: + case A_SECMSCINTSTAT: + case A_SECMSCINTEN: + case A_BRGINTSTAT: + case A_BRGINTEN: + case A_AHBNSPPCEXP0: + case A_AHBNSPPCEXP1: + case A_AHBNSPPCEXP2: + case A_AHBNSPPCEXP3: + case A_APBNSPPC0: + case A_APBNSPPC1: + case A_APBNSPPCEXP0: + case A_APBNSPPCEXP1: + case A_APBNSPPCEXP2: + case A_APBNSPPCEXP3: + case A_AHBSPPPCEXP0: + case A_AHBSPPPCEXP1: + case A_AHBSPPPCEXP2: + case A_AHBSPPPCEXP3: + case A_APBSPPPC0: + case A_APBSPPPC1: + case A_APBSPPPCEXP0: + case A_APBSPPPCEXP1: + case A_APBSPPPCEXP2: + case A_APBSPPPCEXP3: + case A_NSMSCEXP: + qemu_log_mask(LOG_UNIMP, + "IoTKit SecCtl S block read: " + "unimplemented offset 0x%x\n", offset); + r = 0; + break; + case A_PID4: + case A_PID5: + case A_PID6: + case A_PID7: + case A_PID0: + case A_PID1: + case A_PID2: + case A_PID3: + case A_CID0: + case A_CID1: + case A_CID2: + case A_CID3: + r = iotkit_secctl_s_idregs[(offset - A_PID4) / 4]; + break; + case A_SECPPCINTCLR: + case A_SECMSCINTCLR: + case A_BRGINTCLR: + qemu_log_mask(LOG_GUEST_ERROR, + "IotKit SecCtl S block read: write-only offset 0x%x\n", + offset); + r = 0; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "IotKit SecCtl S block read: bad offset 0x%x\n", offset); + r = 0; + break; + } + + if (size != 4) { + /* None of our registers are access-sensitive, so just pull the right + * byte out of the word read result. + */ + r >>= 8 * (addr & 3); + r &= (1 << (size * 8)) - 1; + } + + trace_iotkit_secctl_s_read(offset, r, size); + *pdata = r; + return MEMTX_OK; +} + +static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr, + uint64_t value, + unsigned size, MemTxAttrs attrs) +{ + uint32_t offset = addr; + + trace_iotkit_secctl_s_write(offset, value, size); + + if (size != 4) { + /* Byte and halfword writes are ignored */ + qemu_log_mask(LOG_GUEST_ERROR, + "IotKit SecCtl S block write: bad size, ignored\n"); + return MEMTX_OK; + } + + switch (offset) { + case A_SECRESPCFG: + case A_NSCCFG: + case A_SECPPCINTCLR: + case A_SECPPCINTEN: + case A_SECMSCINTCLR: + case A_SECMSCINTEN: + case A_BRGINTCLR: + case A_BRGINTEN: + case A_AHBNSPPCEXP0: + case A_AHBNSPPCEXP1: + case A_AHBNSPPCEXP2: + case A_AHBNSPPCEXP3: + case A_APBNSPPC0: + case A_APBNSPPC1: + case A_APBNSPPCEXP0: + case A_APBNSPPCEXP1: + case A_APBNSPPCEXP2: + case A_APBNSPPCEXP3: + case A_AHBSPPPCEXP0: + case A_AHBSPPPCEXP1: + case A_AHBSPPPCEXP2: + case A_AHBSPPPCEXP3: + case A_APBSPPPC0: + case A_APBSPPPC1: + case A_APBSPPPCEXP0: + case A_APBSPPPCEXP1: + case A_APBSPPPCEXP2: + case A_APBSPPPCEXP3: + qemu_log_mask(LOG_UNIMP, + "IoTKit SecCtl S block write: " + "unimplemented offset 0x%x\n", offset); + break; + case A_SECMPCINTSTATUS: + case A_SECPPCINTSTAT: + case A_SECMSCINTSTAT: + case A_BRGINTSTAT: + case A_AHBNSPPC0: + case A_AHBSPPPC0: + case A_NSMSCEXP: + case A_PID4: + case A_PID5: + case A_PID6: + case A_PID7: + case A_PID0: + case A_PID1: + case A_PID2: + case A_PID3: + case A_CID0: + case A_CID1: + case A_CID2: + case A_CID3: + qemu_log_mask(LOG_GUEST_ERROR, + "IoTKit SecCtl S block write: " + "read-only offset 0x%x\n", offset); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "IotKit SecCtl S block write: bad offset 0x%x\n", + offset); + break; + } + + return MEMTX_OK; +} + +static MemTxResult iotkit_secctl_ns_read(void *opaque, hwaddr addr, + uint64_t *pdata, + unsigned size, MemTxAttrs attrs) +{ + uint64_t r; + uint32_t offset = addr & ~0x3; + + switch (offset) { + case A_AHBNSPPPC0: + r = 0; + break; + case A_AHBNSPPPCEXP0: + case A_AHBNSPPPCEXP1: + case A_AHBNSPPPCEXP2: + case A_AHBNSPPPCEXP3: + case A_APBNSPPPC0: + case A_APBNSPPPC1: + case A_APBNSPPPCEXP0: + case A_APBNSPPPCEXP1: + case A_APBNSPPPCEXP2: + case A_APBNSPPPCEXP3: + qemu_log_mask(LOG_UNIMP, + "IoTKit SecCtl NS block read: " + "unimplemented offset 0x%x\n", offset); + break; + case A_PID4: + case A_PID5: + case A_PID6: + case A_PID7: + case A_PID0: + case A_PID1: + case A_PID2: + case A_PID3: + case A_CID0: + case A_CID1: + case A_CID2: + case A_CID3: + r = iotkit_secctl_ns_idregs[(offset - A_PID4) / 4]; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "IotKit SecCtl NS block write: bad offset 0x%x\n", + offset); + r = 0; + break; + } + + if (size != 4) { + /* None of our registers are access-sensitive, so just pull the right + * byte out of the word read result. + */ + r >>= 8 * (addr & 3); + r &= (1 << (size * 8)) - 1; + } + + trace_iotkit_secctl_ns_read(offset, r, size); + *pdata = r; + return MEMTX_OK; +} + +static MemTxResult iotkit_secctl_ns_write(void *opaque, hwaddr addr, + uint64_t value, + unsigned size, MemTxAttrs attrs) +{ + uint32_t offset = addr; + + trace_iotkit_secctl_ns_write(offset, value, size); + + if (size != 4) { + /* Byte and halfword writes are ignored */ + qemu_log_mask(LOG_GUEST_ERROR, + "IotKit SecCtl NS block write: bad size, ignored\n"); + return MEMTX_OK; + } + + switch (offset) { + case A_AHBNSPPPCEXP0: + case A_AHBNSPPPCEXP1: + case A_AHBNSPPPCEXP2: + case A_AHBNSPPPCEXP3: + case A_APBNSPPPC0: + case A_APBNSPPPC1: + case A_APBNSPPPCEXP0: + case A_APBNSPPPCEXP1: + case A_APBNSPPPCEXP2: + case A_APBNSPPPCEXP3: + qemu_log_mask(LOG_UNIMP, + "IoTKit SecCtl NS block write: " + "unimplemented offset 0x%x\n", offset); + break; + case A_AHBNSPPPC0: + case A_PID4: + case A_PID5: + case A_PID6: + case A_PID7: + case A_PID0: + case A_PID1: + case A_PID2: + case A_PID3: + case A_CID0: + case A_CID1: + case A_CID2: + case A_CID3: + qemu_log_mask(LOG_GUEST_ERROR, + "IoTKit SecCtl NS block write: " + "read-only offset 0x%x\n", offset); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "IotKit SecCtl NS block write: bad offset 0x%x\n", + offset); + break; + } + + return MEMTX_OK; +} + +static const MemoryRegionOps iotkit_secctl_s_ops = { + .read_with_attrs = iotkit_secctl_s_read, + .write_with_attrs = iotkit_secctl_s_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 4, +}; + +static const MemoryRegionOps iotkit_secctl_ns_ops = { + .read_with_attrs = iotkit_secctl_ns_read, + .write_with_attrs = iotkit_secctl_ns_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 4, +}; + +static void iotkit_secctl_reset(DeviceState *dev) +{ + +} + +static void iotkit_secctl_init(Object *obj) +{ + IoTKitSecCtl *s = IOTKIT_SECCTL(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->s_regs, obj, &iotkit_secctl_s_ops, + s, "iotkit-secctl-s-regs", 0x1000); + memory_region_init_io(&s->ns_regs, obj, &iotkit_secctl_ns_ops, + s, "iotkit-secctl-ns-regs", 0x1000); + sysbus_init_mmio(sbd, &s->s_regs); + sysbus_init_mmio(sbd, &s->ns_regs); +} + +static const VMStateDescription iotkit_secctl_vmstate = { + .name = "iotkit-secctl", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static void iotkit_secctl_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &iotkit_secctl_vmstate; + dc->reset = iotkit_secctl_reset; +} + +static const TypeInfo iotkit_secctl_info = { + .name = TYPE_IOTKIT_SECCTL, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IoTKitSecCtl), + .instance_init = iotkit_secctl_init, + .class_init = iotkit_secctl_class_init, +}; + +static void iotkit_secctl_register_types(void) +{ + type_register_static(&iotkit_secctl_info); +} + +type_init(iotkit_secctl_register_types); diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 6aa564b754..a2057908f0 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -104,6 +104,7 @@ CONFIG_MPS2_FPGAIO=y CONFIG_MPS2_SCC=y CONFIG_TZ_PPC=y +CONFIG_IOTKIT_SECCTL=y CONFIG_VERSATILE_PCI=y CONFIG_VERSATILE_I2C=y diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 0b638de682..eb5ffcc0a8 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -94,3 +94,10 @@ tz_ppc_irq_clear(int level) "TZ PPC: int_clear = %d" tz_ppc_update_irq(int level) "TZ PPC: setting irq line to %d" tz_ppc_read_blocked(int n, hwaddr offset, bool secure, bool user) "TZ PPC: port %d offset 0x%" HWADDR_PRIx " read (secure %d user %d) blocked" tz_ppc_write_blocked(int n, hwaddr offset, bool secure, bool user) "TZ PPC: port %d offset 0x%" HWADDR_PRIx " write (secure %d user %d) blocked" + +# hw/misc/iotkit-secctl.c +iotkit_secctl_s_read(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl S regs read: offset 0x%x data 0x%" PRIx64 " size %u" +iotkit_secctl_s_write(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl S regs write: offset 0x%x data 0x%" PRIx64 " size %u" +iotkit_secctl_ns_read(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl NS regs read: offset 0x%x data 0x%" PRIx64 " size %u" +iotkit_secctl_ns_write(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl NS regs write: offset 0x%x data 0x%" PRIx64 " size %u" +iotkit_secctl_reset(void) "IoTKit SecCtl: reset" From patchwork Tue Feb 20 18:03:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128962 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910416ljc; Tue, 20 Feb 2018 10:03:39 -0800 (PST) X-Google-Smtp-Source: AH8x2269+U94VgpKe5epa3Q2XBg1+wxTl1ON9vqwnbyZk3qL5jEEJhB92FMcDBRMocTehWaOpvux X-Received: by 10.25.78.130 with SMTP id u2mr330591lfk.131.1519149819301; Tue, 20 Feb 2018 10:03:39 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149819; cv=none; d=google.com; s=arc-20160816; b=YiL4mJTFdjVlBjY33FUeVQjxWj8X1EZKjOLCo3ioB+X138V1P2AtuT+I85gTXGPP1H 3+JFe3EKa2LB6aluO4iuZlupFzvOyxQUBT30xVpfqGgU0S/DHRdAfS+Ab2nZlCR8RKcQ K6tfN5KHtcjyRttLHPXq4eOKck/R8FCq+inL69k0xOTm1FL6aKAHd/W/ploqeZws18wZ /itg+X+i/8OiO1eJ3cHzEObvBB5LI5FkO3ZGWyUL5ehg2buP8gbIO5Bf3urzII3eyU59 rpUt2J9PCXaVXwAwV8rCYPgCWEZaY4oM1jxUaQ+emD+8uSeNmu8WqtFm41FTIpGiPBor g+bg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=5ta+m1mX33dN/92rfvxR7DMjDZ0SuTmnJNJBvstvuxM=; b=qpz+9Sdys0ko5iq0xI0ZmWmhlghP3l7c4FKn7DHI5oqmOl5Q0Zzc5Npuijx23qvZe+ 7wFKcn8ar+NJN0fPwxT4V23G7BQftEl6QkXVZdH7Fl9nW+pbrZmiqg+c5NPNZv8VQ4Jm C0DmGC4wmiWWLUCDCy8/TRI5wvE3sXw2p7ayzShTp3J9oXt3e4/lS3NbZNjEAQRoOOua 1ghsBhvmMcIN/a/4mzpbP16xB2bmeVn64sI/WsIrfx9gwQcMJw55wT4jkFUWZGd1BeCb m/dWHT/jRlTy+vEw7OXnn0D6r+vv1sTNKbuDa3kzKho3jppPkYxYmuH0nvIY+JgM0dqi 6flw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id v16si10261361lfg.115.2018.02.20.10.03.38 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:39 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGQ-0008Tw-4K; Tue, 20 Feb 2018 18:03:38 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 16/19] hw/misc/iotkit-secctl: Add handling for PPCs Date: Tue, 20 Feb 2018 18:03:22 +0000 Message-Id: <20180220180325.29818-17-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> The IoTKit Security Controller includes various registers that expose to software the controls for the Peripheral Protection Controllers in the system. Implement these. Signed-off-by: Peter Maydell --- include/hw/misc/iotkit-secctl.h | 64 +++++++++- hw/misc/iotkit-secctl.c | 270 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 315 insertions(+), 19 deletions(-) -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/include/hw/misc/iotkit-secctl.h b/include/hw/misc/iotkit-secctl.h index 872f652f8d..ea3d62967f 100644 --- a/include/hw/misc/iotkit-secctl.h +++ b/include/hw/misc/iotkit-secctl.h @@ -16,6 +16,28 @@ * QEMU interface: * + sysbus MMIO region 0 is the "secure privilege control block" registers * + sysbus MMIO region 1 is the "non-secure privilege control block" registers + * + named GPIO output "sec_resp_cfg" indicating whether blocked accesses + * should RAZ/WI or bus error + * Controlling the 2 APB PPCs in the IoTKit: + * + named GPIO outputs apb_ppc0_nonsec[0..2] and apb_ppc1_nonsec + * + named GPIO outputs apb_ppc0_ap[0..2] and apb_ppc1_ap + * + named GPIO outputs apb_ppc{0,1}_irq_enable + * + named GPIO outputs apb_ppc{0,1}_irq_clear + * + named GPIO inputs apb_ppc{0,1}_irq_status + * Controlling each of the 4 expansion APB PPCs which a system using the IoTKit + * might provide: + * + named GPIO outputs apb_ppcexp{0,1,2,3}_nonsec[0..15] + * + named GPIO outputs apb_ppcexp{0,1,2,3}_ap[0..15] + * + named GPIO outputs apb_ppcexp{0,1,2,3}_irq_enable + * + named GPIO outputs apb_ppcexp{0,1,2,3}_irq_clear + * + named GPIO inputs apb_ppcexp{0,1,2,3}_irq_status + * Controlling each of the 4 expansion AHB PPCs which a system using the IoTKit + * might provide: + * + named GPIO outputs ahb_ppcexp{0,1,2,3}_nonsec[0..15] + * + named GPIO outputs ahb_ppcexp{0,1,2,3}_ap[0..15] + * + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_enable + * + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_clear + * + named GPIO inputs ahb_ppcexp{0,1,2,3}_irq_status */ #ifndef IOTKIT_SECCTL_H @@ -26,14 +48,52 @@ #define TYPE_IOTKIT_SECCTL "iotkit-secctl" #define IOTKIT_SECCTL(obj) OBJECT_CHECK(IoTKitSecCtl, (obj), TYPE_IOTKIT_SECCTL) -typedef struct IoTKitSecCtl { +#define IOTS_APB_PPC0_NUM_PORTS 3 +#define IOTS_APB_PPC1_NUM_PORTS 1 +#define IOTS_PPC_NUM_PORTS 16 +#define IOTS_NUM_APB_PPC 2 +#define IOTS_NUM_APB_EXP_PPC 4 +#define IOTS_NUM_AHB_EXP_PPC 4 + +typedef struct IoTKitSecCtl IoTKitSecCtl; + +/* State and IRQ lines relating to a PPC. For the + * PPCs in the IoTKit not all the IRQ lines are used. + */ +typedef struct IoTKitSecCtlPPC { + qemu_irq nonsec[IOTS_PPC_NUM_PORTS]; + qemu_irq ap[IOTS_PPC_NUM_PORTS]; + qemu_irq irq_enable; + qemu_irq irq_clear; + + uint32_t ns; + uint32_t sp; + uint32_t nsp; + + /* Number of ports actually present */ + int numports; + /* Offset of this PPC's interrupt bits in SECPPCINTSTAT */ + int irq_bit_offset; + IoTKitSecCtl *parent; +} IoTKitSecCtlPPC; + +struct IoTKitSecCtl { /*< private >*/ SysBusDevice parent_obj; /*< public >*/ + qemu_irq sec_resp_cfg; MemoryRegion s_regs; MemoryRegion ns_regs; -} IoTKitSecCtl; + + uint32_t secppcintstat; + uint32_t secppcinten; + uint32_t secrespcfg; + + IoTKitSecCtlPPC apb[IOTS_NUM_APB_PPC]; + IoTKitSecCtlPPC apbexp[IOTS_NUM_APB_EXP_PPC]; + IoTKitSecCtlPPC ahbexp[IOTS_NUM_APB_EXP_PPC]; +}; #endif diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c index 5da52e4706..7e1ca184ab 100644 --- a/hw/misc/iotkit-secctl.c +++ b/hw/misc/iotkit-secctl.c @@ -92,12 +92,41 @@ static const uint8_t iotkit_secctl_ns_idregs[] = { 0x0d, 0xf0, 0x05, 0xb1, }; +/* The register sets for the various PPCs (AHB internal, APB internal, + * AHB expansion, APB expansion) are all set up so that they are + * in 16-aligned blocks so offsets 0xN0, 0xN4, 0xN8, 0xNC are PPCs + * 0, 1, 2, 3 of that type, so we can convert a register address offset + * into an an index into a PPC array easily. + */ +static inline int offset_to_ppc_idx(uint32_t offset) +{ + return extract32(offset, 2, 2); +} + +typedef void PerPPCFunction(IoTKitSecCtlPPC *ppc); + +static void foreach_ppc(IoTKitSecCtl *s, PerPPCFunction *fn) +{ + int i; + + for (i = 0; i < IOTS_NUM_APB_PPC; i++) { + fn(&s->apb[i]); + } + for (i = 0; i < IOTS_NUM_APB_EXP_PPC; i++) { + fn(&s->apbexp[i]); + } + for (i = 0; i < IOTS_NUM_AHB_EXP_PPC; i++) { + fn(&s->ahbexp[i]); + } +} + static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr, uint64_t *pdata, unsigned size, MemTxAttrs attrs) { uint64_t r; uint32_t offset = addr & ~0x3; + IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); switch (offset) { case A_AHBNSPPC0: @@ -105,34 +134,52 @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr, r = 0; break; case A_SECRESPCFG: - case A_NSCCFG: - case A_SECMPCINTSTATUS: + r = s->secrespcfg; + break; case A_SECPPCINTSTAT: + r = s->secppcintstat; + break; case A_SECPPCINTEN: - case A_SECMSCINTSTAT: - case A_SECMSCINTEN: - case A_BRGINTSTAT: - case A_BRGINTEN: + r = s->secppcinten; + break; case A_AHBNSPPCEXP0: case A_AHBNSPPCEXP1: case A_AHBNSPPCEXP2: case A_AHBNSPPCEXP3: + r = s->ahbexp[offset_to_ppc_idx(offset)].ns; + break; case A_APBNSPPC0: case A_APBNSPPC1: + r = s->apb[offset_to_ppc_idx(offset)].ns; + break; case A_APBNSPPCEXP0: case A_APBNSPPCEXP1: case A_APBNSPPCEXP2: case A_APBNSPPCEXP3: + r = s->apbexp[offset_to_ppc_idx(offset)].ns; + break; case A_AHBSPPPCEXP0: case A_AHBSPPPCEXP1: case A_AHBSPPPCEXP2: case A_AHBSPPPCEXP3: + r = s->apbexp[offset_to_ppc_idx(offset)].sp; + break; case A_APBSPPPC0: case A_APBSPPPC1: + r = s->apb[offset_to_ppc_idx(offset)].sp; + break; case A_APBSPPPCEXP0: case A_APBSPPPCEXP1: case A_APBSPPPCEXP2: case A_APBSPPPCEXP3: + r = s->apbexp[offset_to_ppc_idx(offset)].sp; + break; + case A_NSCCFG: + case A_SECMPCINTSTATUS: + case A_SECMSCINTSTAT: + case A_SECMSCINTEN: + case A_BRGINTSTAT: + case A_BRGINTEN: case A_NSMSCEXP: qemu_log_mask(LOG_UNIMP, "IoTKit SecCtl S block read: " @@ -181,11 +228,66 @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr, return MEMTX_OK; } +static void iotkit_secctl_update_ppc_ap(IoTKitSecCtlPPC *ppc) +{ + int i; + + for (i = 0; i < ppc->numports; i++) { + bool v; + + if (extract32(ppc->ns, i, 1)) { + v = extract32(ppc->nsp, i, 1); + } else { + v = extract32(ppc->sp, i, 1); + } + qemu_set_irq(ppc->ap[i], v); + } +} + +static void iotkit_secctl_ppc_ns_write(IoTKitSecCtlPPC *ppc, uint32_t value) +{ + int i; + + ppc->ns = value & MAKE_64BIT_MASK(0, ppc->numports); + for (i = 0; i < ppc->numports; i++) { + qemu_set_irq(ppc->nonsec[i], extract32(ppc->ns, i, 1)); + } + iotkit_secctl_update_ppc_ap(ppc); +} + +static void iotkit_secctl_ppc_sp_write(IoTKitSecCtlPPC *ppc, uint32_t value) +{ + ppc->sp = value & MAKE_64BIT_MASK(0, ppc->numports); + iotkit_secctl_update_ppc_ap(ppc); +} + +static void iotkit_secctl_ppc_nsp_write(IoTKitSecCtlPPC *ppc, uint32_t value) +{ + ppc->nsp = value & MAKE_64BIT_MASK(0, ppc->numports); + iotkit_secctl_update_ppc_ap(ppc); +} + +static void iotkit_secctl_ppc_update_irq_clear(IoTKitSecCtlPPC *ppc) +{ + uint32_t value = ppc->parent->secppcintstat; + + qemu_set_irq(ppc->irq_clear, extract32(value, ppc->irq_bit_offset, 1)); +} + +static void iotkit_secctl_ppc_update_irq_enable(IoTKitSecCtlPPC *ppc) +{ + uint32_t value = ppc->parent->secppcinten; + + qemu_set_irq(ppc->irq_enable, extract32(value, ppc->irq_bit_offset, 1)); +} + static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr, uint64_t value, unsigned size, MemTxAttrs attrs) { + IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); uint32_t offset = addr; + IoTKitSecCtlPPC *ppc; trace_iotkit_secctl_s_write(offset, value, size); @@ -198,33 +300,61 @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr, switch (offset) { case A_SECRESPCFG: - case A_NSCCFG: + value &= 1; + s->secrespcfg = value; + qemu_set_irq(s->sec_resp_cfg, s->secrespcfg); + break; case A_SECPPCINTCLR: + value &= 0x00f000f3; + foreach_ppc(s, iotkit_secctl_ppc_update_irq_clear); + break; case A_SECPPCINTEN: - case A_SECMSCINTCLR: - case A_SECMSCINTEN: - case A_BRGINTCLR: - case A_BRGINTEN: + s->secppcinten = value & 0x00f000f3; + foreach_ppc(s, iotkit_secctl_ppc_update_irq_enable); + break; case A_AHBNSPPCEXP0: case A_AHBNSPPCEXP1: case A_AHBNSPPCEXP2: case A_AHBNSPPCEXP3: + ppc = &s->ahbexp[offset_to_ppc_idx(offset)]; + iotkit_secctl_ppc_ns_write(ppc, value); + break; case A_APBNSPPC0: case A_APBNSPPC1: + ppc = &s->apb[offset_to_ppc_idx(offset)]; + iotkit_secctl_ppc_ns_write(ppc, value); + break; case A_APBNSPPCEXP0: case A_APBNSPPCEXP1: case A_APBNSPPCEXP2: case A_APBNSPPCEXP3: + ppc = &s->apbexp[offset_to_ppc_idx(offset)]; + iotkit_secctl_ppc_ns_write(ppc, value); + break; case A_AHBSPPPCEXP0: case A_AHBSPPPCEXP1: case A_AHBSPPPCEXP2: case A_AHBSPPPCEXP3: + ppc = &s->ahbexp[offset_to_ppc_idx(offset)]; + iotkit_secctl_ppc_sp_write(ppc, value); + break; case A_APBSPPPC0: case A_APBSPPPC1: + ppc = &s->apb[offset_to_ppc_idx(offset)]; + iotkit_secctl_ppc_sp_write(ppc, value); + break; case A_APBSPPPCEXP0: case A_APBSPPPCEXP1: case A_APBSPPPCEXP2: case A_APBSPPPCEXP3: + ppc = &s->apbexp[offset_to_ppc_idx(offset)]; + iotkit_secctl_ppc_sp_write(ppc, value); + break; + case A_NSCCFG: + case A_SECMSCINTCLR: + case A_SECMSCINTEN: + case A_BRGINTCLR: + case A_BRGINTEN: qemu_log_mask(LOG_UNIMP, "IoTKit SecCtl S block write: " "unimplemented offset 0x%x\n", offset); @@ -266,6 +396,7 @@ static MemTxResult iotkit_secctl_ns_read(void *opaque, hwaddr addr, uint64_t *pdata, unsigned size, MemTxAttrs attrs) { + IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); uint64_t r; uint32_t offset = addr & ~0x3; @@ -277,15 +408,17 @@ static MemTxResult iotkit_secctl_ns_read(void *opaque, hwaddr addr, case A_AHBNSPPPCEXP1: case A_AHBNSPPPCEXP2: case A_AHBNSPPPCEXP3: + r = s->ahbexp[offset_to_ppc_idx(offset)].nsp; + break; case A_APBNSPPPC0: case A_APBNSPPPC1: + r = s->apb[offset_to_ppc_idx(offset)].nsp; + break; case A_APBNSPPPCEXP0: case A_APBNSPPPCEXP1: case A_APBNSPPPCEXP2: case A_APBNSPPPCEXP3: - qemu_log_mask(LOG_UNIMP, - "IoTKit SecCtl NS block read: " - "unimplemented offset 0x%x\n", offset); + r = s->apbexp[offset_to_ppc_idx(offset)].nsp; break; case A_PID4: case A_PID5: @@ -326,7 +459,9 @@ static MemTxResult iotkit_secctl_ns_write(void *opaque, hwaddr addr, uint64_t value, unsigned size, MemTxAttrs attrs) { + IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); uint32_t offset = addr; + IoTKitSecCtlPPC *ppc; trace_iotkit_secctl_ns_write(offset, value, size); @@ -342,15 +477,20 @@ static MemTxResult iotkit_secctl_ns_write(void *opaque, hwaddr addr, case A_AHBNSPPPCEXP1: case A_AHBNSPPPCEXP2: case A_AHBNSPPPCEXP3: + ppc = &s->ahbexp[offset_to_ppc_idx(offset)]; + iotkit_secctl_ppc_nsp_write(ppc, value); + break; case A_APBNSPPPC0: case A_APBNSPPPC1: + ppc = &s->apb[offset_to_ppc_idx(offset)]; + iotkit_secctl_ppc_nsp_write(ppc, value); + break; case A_APBNSPPPCEXP0: case A_APBNSPPPCEXP1: case A_APBNSPPPCEXP2: case A_APBNSPPPCEXP3: - qemu_log_mask(LOG_UNIMP, - "IoTKit SecCtl NS block write: " - "unimplemented offset 0x%x\n", offset); + ppc = &s->apbexp[offset_to_ppc_idx(offset)]; + iotkit_secctl_ppc_nsp_write(ppc, value); break; case A_AHBNSPPPC0: case A_PID4: @@ -399,15 +539,90 @@ static const MemoryRegionOps iotkit_secctl_ns_ops = { .impl.max_access_size = 4, }; +static void iotkit_secctl_reset_ppc(IoTKitSecCtlPPC *ppc) +{ + ppc->ns = 0; + ppc->sp = 0; + ppc->nsp = 0; +} + static void iotkit_secctl_reset(DeviceState *dev) { + IoTKitSecCtl *s = IOTKIT_SECCTL(dev); + s->secppcintstat = 0; + s->secppcinten = 0; + s->secrespcfg = 0; + + foreach_ppc(s, iotkit_secctl_reset_ppc); +} + +static void iotkit_secctl_ppc_irqstatus(void *opaque, int n, int level) +{ + IoTKitSecCtlPPC *ppc = opaque; + IoTKitSecCtl *s = IOTKIT_SECCTL(ppc->parent); + int irqbit = ppc->irq_bit_offset + n; + + s->secppcintstat = deposit32(s->secppcintstat, irqbit, 1, level); +} + +static void iotkit_secctl_init_ppc(IoTKitSecCtl *s, + IoTKitSecCtlPPC *ppc, + const char *name, + int numports, + int irq_bit_offset) +{ + char *gpioname; + DeviceState *dev = DEVICE(s); + + ppc->numports = numports; + ppc->irq_bit_offset = irq_bit_offset; + ppc->parent = s; + + gpioname = g_strdup_printf("%s_nonsec", name); + qdev_init_gpio_out_named(dev, ppc->nonsec, gpioname, numports); + g_free(gpioname); + gpioname = g_strdup_printf("%s_ap", name); + qdev_init_gpio_out_named(dev, ppc->ap, gpioname, numports); + g_free(gpioname); + gpioname = g_strdup_printf("%s_irq_enable", name); + qdev_init_gpio_out_named(dev, &ppc->irq_enable, gpioname, 1); + g_free(gpioname); + gpioname = g_strdup_printf("%s_irq_clear", name); + qdev_init_gpio_out_named(dev, &ppc->irq_clear, gpioname, 1); + g_free(gpioname); + gpioname = g_strdup_printf("%s_irq_status", name); + qdev_init_gpio_in_named_with_opaque(dev, iotkit_secctl_ppc_irqstatus, + ppc, gpioname, 1); + g_free(gpioname); } static void iotkit_secctl_init(Object *obj) { IoTKitSecCtl *s = IOTKIT_SECCTL(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(obj); + int i; + + iotkit_secctl_init_ppc(s, &s->apb[0], "apb_ppc0", + IOTS_APB_PPC0_NUM_PORTS, 0); + iotkit_secctl_init_ppc(s, &s->apb[1], "apb_ppc1", + IOTS_APB_PPC1_NUM_PORTS, 1); + + for (i = 0; i < IOTS_NUM_APB_EXP_PPC; i++) { + IoTKitSecCtlPPC *ppc = &s->apbexp[i]; + char *ppcname = g_strdup_printf("apb_ppcexp%d", i); + iotkit_secctl_init_ppc(s, ppc, ppcname, IOTS_PPC_NUM_PORTS, 4 + i); + g_free(ppcname); + } + for (i = 0; i < IOTS_NUM_AHB_EXP_PPC; i++) { + IoTKitSecCtlPPC *ppc = &s->ahbexp[i]; + char *ppcname = g_strdup_printf("ahb_ppcexp%d", i); + iotkit_secctl_init_ppc(s, ppc, ppcname, IOTS_PPC_NUM_PORTS, 20 + i); + g_free(ppcname); + } + + qdev_init_gpio_out_named(dev, &s->sec_resp_cfg, "sec_resp_cfg", 1); memory_region_init_io(&s->s_regs, obj, &iotkit_secctl_s_ops, s, "iotkit-secctl-s-regs", 0x1000); @@ -417,11 +632,32 @@ static void iotkit_secctl_init(Object *obj) sysbus_init_mmio(sbd, &s->ns_regs); } +static const VMStateDescription iotkit_secctl_ppc_vmstate = { + .name = "iotkit-secctl-ppc", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ns, IoTKitSecCtlPPC), + VMSTATE_UINT32(sp, IoTKitSecCtlPPC), + VMSTATE_UINT32(nsp, IoTKitSecCtlPPC), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription iotkit_secctl_vmstate = { .name = "iotkit-secctl", .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { + VMSTATE_UINT32(secppcintstat, IoTKitSecCtl), + VMSTATE_UINT32(secppcinten, IoTKitSecCtl), + VMSTATE_UINT32(secrespcfg, IoTKitSecCtl), + VMSTATE_STRUCT_ARRAY(apb, IoTKitSecCtl, IOTS_NUM_APB_PPC, 1, + iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC), + VMSTATE_STRUCT_ARRAY(apbexp, IoTKitSecCtl, IOTS_NUM_APB_EXP_PPC, 1, + iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC), + VMSTATE_STRUCT_ARRAY(ahbexp, IoTKitSecCtl, IOTS_NUM_AHB_EXP_PPC, 1, + iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC), VMSTATE_END_OF_LIST() } }; From patchwork Tue Feb 20 18:03:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128964 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910419ljc; Tue, 20 Feb 2018 10:03:39 -0800 (PST) X-Google-Smtp-Source: AH8x224+zCshIq5cKQ3JWPWe2YlKriqlAM9TUAYehzUhTHCqSXoKEH3iLaw9sQHtu6HHa0Z6hTez X-Received: by 10.223.183.43 with SMTP id l43mr438135wre.265.1519149819444; Tue, 20 Feb 2018 10:03:39 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149819; cv=none; d=google.com; s=arc-20160816; b=D9Mr4KUW9cUs5Hp7wLq+mPIzkoGAl5bW+9YS3ewAhPOOL7dD8rGyFX/4U0QTvlCEHI t/mSa81xdAQWiTgApyNiL2PAvzXrqNeeLR6j8EAr9AEFGRiRuQ8ghBOFgDf2LdEoymW4 yDNYCZbh8d0HwLcmXmcMHeEAAIc5auhLj/Y3gKyuKxfViSNA5JoM9IrD3ZJ2Dt3lYV1O ftqYoBhUmzqwxdZhNwOKEe+Blp0JTAkrrmXFWLyoGcQ3wbaOPZp4gFOwMBhJYbevkWXx j8Bq2hgRxdwB5DbXKG58yQKkap7CJ+YlKqFMKdAfOBrtgHiZC2+WFk0RjHiPYMtk6wZt 35ZA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=8/MzZX+q1MvGa4f4M8r++hoqe69lfv+0MbRseW6vRsA=; b=fFraQD9BRINgc2jKmmlDNxwJP4nOm2wVz0dJO2mg0hgcRjl1pHbM0pj52wvD035bir Rp2HTvqTpLAY4rZi9QS7y6zjjsMO3vrjJ8S8o9WJ2FNdVszuR9X+C3N9EMBwl5UBeOlI KSH2QlG0us/MMxBWixH6jNdDaiQJYnWNVn8RlL7k7G/exKkqabZFu9I9LsuKkvDVTFAq 08J26qqFGJyCEu7fPTS85sdesctLQWWoadnmHSRcLkIE7eSDgC4bZaco3JBufIqn3TdW eDw9ANDuO7FnByyREUifdKkA42QKJScR/9jOjfW/G4xIdeiF+kwn3aW7NwEELw6DKYkW 0Jqw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id n64si1185736wme.205.2018.02.20.10.03.39 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:39 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGQ-0008UC-VB; Tue, 20 Feb 2018 18:03:38 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 17/19] hw/misc/iotkit-secctl: Add remaining simple registers Date: Tue, 20 Feb 2018 18:03:23 +0000 Message-Id: <20180220180325.29818-18-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> Add remaining easy registers to iotkit-secctl: * NSCCFG just routes its two bits out to external GPIO lines * BRGINSTAT/BRGINTCLR/BRGINTEN can be dummies, because QEMU's bus fabric can never report errors Signed-off-by: Peter Maydell --- include/hw/misc/iotkit-secctl.h | 4 ++++ hw/misc/iotkit-secctl.c | 32 ++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) -- 2.16.1 diff --git a/include/hw/misc/iotkit-secctl.h b/include/hw/misc/iotkit-secctl.h index ea3d62967f..faad0c9190 100644 --- a/include/hw/misc/iotkit-secctl.h +++ b/include/hw/misc/iotkit-secctl.h @@ -18,6 +18,7 @@ * + sysbus MMIO region 1 is the "non-secure privilege control block" registers * + named GPIO output "sec_resp_cfg" indicating whether blocked accesses * should RAZ/WI or bus error + * + named GPIO output "nsc_cfg" whose value tracks the NSCCFG register value * Controlling the 2 APB PPCs in the IoTKit: * + named GPIO outputs apb_ppc0_nonsec[0..2] and apb_ppc1_nonsec * + named GPIO outputs apb_ppc0_ap[0..2] and apb_ppc1_ap @@ -83,6 +84,7 @@ struct IoTKitSecCtl { /*< public >*/ qemu_irq sec_resp_cfg; + qemu_irq nsc_cfg_irq; MemoryRegion s_regs; MemoryRegion ns_regs; @@ -90,6 +92,8 @@ struct IoTKitSecCtl { uint32_t secppcintstat; uint32_t secppcinten; uint32_t secrespcfg; + uint32_t nsccfg; + uint32_t brginten; IoTKitSecCtlPPC apb[IOTS_NUM_APB_PPC]; IoTKitSecCtlPPC apbexp[IOTS_NUM_APB_EXP_PPC]; diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c index 7e1ca184ab..2cefa0ec15 100644 --- a/hw/misc/iotkit-secctl.c +++ b/hw/misc/iotkit-secctl.c @@ -136,12 +136,24 @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr, case A_SECRESPCFG: r = s->secrespcfg; break; + case A_NSCCFG: + r = s->nsccfg; + break; case A_SECPPCINTSTAT: r = s->secppcintstat; break; case A_SECPPCINTEN: r = s->secppcinten; break; + case A_BRGINTSTAT: + /* QEMU's bus fabric can never report errors as it doesn't buffer + * writes, so we never report bridge interrupts. + */ + r = 0; + break; + case A_BRGINTEN: + r = s->brginten; + break; case A_AHBNSPPCEXP0: case A_AHBNSPPCEXP1: case A_AHBNSPPCEXP2: @@ -174,12 +186,9 @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr, case A_APBSPPPCEXP3: r = s->apbexp[offset_to_ppc_idx(offset)].sp; break; - case A_NSCCFG: case A_SECMPCINTSTATUS: case A_SECMSCINTSTAT: case A_SECMSCINTEN: - case A_BRGINTSTAT: - case A_BRGINTEN: case A_NSMSCEXP: qemu_log_mask(LOG_UNIMP, "IoTKit SecCtl S block read: " @@ -299,6 +308,10 @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr, } switch (offset) { + case A_NSCCFG: + s->nsccfg = value & 3; + qemu_set_irq(s->nsc_cfg_irq, s->nsccfg); + break; case A_SECRESPCFG: value &= 1; s->secrespcfg = value; @@ -312,6 +325,11 @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr, s->secppcinten = value & 0x00f000f3; foreach_ppc(s, iotkit_secctl_ppc_update_irq_enable); break; + case A_BRGINTCLR: + break; + case A_BRGINTEN: + s->brginten = value & 0xffff; + break; case A_AHBNSPPCEXP0: case A_AHBNSPPCEXP1: case A_AHBNSPPCEXP2: @@ -350,11 +368,8 @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr, ppc = &s->apbexp[offset_to_ppc_idx(offset)]; iotkit_secctl_ppc_sp_write(ppc, value); break; - case A_NSCCFG: case A_SECMSCINTCLR: case A_SECMSCINTEN: - case A_BRGINTCLR: - case A_BRGINTEN: qemu_log_mask(LOG_UNIMP, "IoTKit SecCtl S block write: " "unimplemented offset 0x%x\n", offset); @@ -553,6 +568,8 @@ static void iotkit_secctl_reset(DeviceState *dev) s->secppcintstat = 0; s->secppcinten = 0; s->secrespcfg = 0; + s->nsccfg = 0; + s->brginten = 0; foreach_ppc(s, iotkit_secctl_reset_ppc); } @@ -623,6 +640,7 @@ static void iotkit_secctl_init(Object *obj) } qdev_init_gpio_out_named(dev, &s->sec_resp_cfg, "sec_resp_cfg", 1); + qdev_init_gpio_out_named(dev, &s->nsc_cfg_irq, "nsc_cfg", 1); memory_region_init_io(&s->s_regs, obj, &iotkit_secctl_s_ops, s, "iotkit-secctl-s-regs", 0x1000); @@ -652,6 +670,8 @@ static const VMStateDescription iotkit_secctl_vmstate = { VMSTATE_UINT32(secppcintstat, IoTKitSecCtl), VMSTATE_UINT32(secppcinten, IoTKitSecCtl), VMSTATE_UINT32(secrespcfg, IoTKitSecCtl), + VMSTATE_UINT32(nsccfg, IoTKitSecCtl), + VMSTATE_UINT32(brginten, IoTKitSecCtl), VMSTATE_STRUCT_ARRAY(apb, IoTKitSecCtl, IOTS_NUM_APB_PPC, 1, iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC), VMSTATE_STRUCT_ARRAY(apbexp, IoTKitSecCtl, IOTS_NUM_APB_EXP_PPC, 1, From patchwork Tue Feb 20 18:03:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128963 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910455ljc; Tue, 20 Feb 2018 10:03:40 -0800 (PST) X-Google-Smtp-Source: AH8x226GehHxwFyloY0rgN2iY7y9Ut3Lnyrt70qndE+R4TOK0DCK8WVZAkHXoLFs0/E2wslEBZYV X-Received: by 10.28.127.145 with SMTP id a139mr932717wmd.49.1519149820680; Tue, 20 Feb 2018 10:03:40 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149820; cv=none; d=google.com; s=arc-20160816; b=c5imZVXtLv/Of8n0LnusqPgG1ZVOUufO41VpBvAfholAQEAK3wRfv8dIjw+L3vta46 dYQInR1jLcIKhriofMEA8V7Oq14D1p3Noenrc6nKctcsa6bINjRgmTnNeFGi3U1rf2Z/ Td+xo4BCrIReiOSvwXBYV82EB6Eznji60FO6/kTKSD3JqICxhiIFtIa+IpER1B7t64pV sUcnp2otm7+XU9GyC5lx7MrRVyyeUgOWQ7QhLM5G9qiZCRU776k8BGOfhaM1T63zo31H pIDVyW+hpZWeAS4tgNiX/ZnwOTh2WNzgIrGbR699yKgxME+p3GpVPR9jJRcLUdk/qFQc 46Xg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=WkD1/Ix/myvLTu/JFEollrkC5M7ij0XL5XYqqAaj//8=; b=QM7iuzN1sZP6APQOgD4Rr6+cRWY4zO4xilXY44AxgQutV8N2CZlZNGA8BlnPMWs5Q4 IL+VrQxkTrhAEf1NDd2sEwGN2uzhWh/zQGs6p84Hscy516TqdGO+OJvtl8fs9NAaa7Fi DajB7Acnk+mMxsFKWSYQjoeJwsOdV5JgeZnNJTNkOOdfXxnRpKJYE4sL3OVQXcxiVj6g s20CA+1yy7feMqb62x4hCkUmjGDUHhUV+Kdg2/0yVKJa5SThbITfjobT18/Vv8vRzzUD l1haH8RVVJec0amvy/ATh/FvzS1bOdEVd9Bniaq180bHhSMiRnAzkrLmrNNZCf06yzoP sljg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id j4si3037349wrg.211.2018.02.20.10.03.40 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:40 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGR-0008UX-OK; Tue, 20 Feb 2018 18:03:39 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 18/19] hw/arm/iotkit: Model Arm IOT Kit Date: Tue, 20 Feb 2018 18:03:24 +0000 Message-Id: <20180220180325.29818-19-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> Model the Arm IoT Kit documented in http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html The Arm IoT Kit is a subsystem which includes a CPU and some devices, and is intended be extended by adding extra devices to form a complete system. It is used in the MPS2 board's AN505 image for the Cortex-M33. Signed-off-by: Peter Maydell --- hw/arm/Makefile.objs | 1 + include/hw/arm/iotkit.h | 109 ++++++++ hw/arm/iotkit.c | 598 ++++++++++++++++++++++++++++++++++++++++ default-configs/arm-softmmu.mak | 1 + 4 files changed, 709 insertions(+) create mode 100644 include/hw/arm/iotkit.h create mode 100644 hw/arm/iotkit.c -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 1c896bafb4..79cd30bb92 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -20,3 +20,4 @@ obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o obj-$(CONFIG_MPS2) += mps2.o obj-$(CONFIG_MSF2) += msf2-soc.o msf2-som.o +obj-$(CONFIG_IOTKIT) += iotkit.o diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h new file mode 100644 index 0000000000..c6129d926b --- /dev/null +++ b/include/hw/arm/iotkit.h @@ -0,0 +1,109 @@ +/* + * ARM IoT Kit + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +/* This is a model of the Arm IoT Kit which is documented in + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html + * It contains: + * a Cortex-M33 + * the IDAU + * some timers and watchdogs + * two peripheral protection controllers + * a memory protection controller + * a security controller + * a bus fabric which arranges that some parts of the address + * space are secure and non-secure aliases of each other + * + * QEMU interface: + * + QOM property "memory" is a MemoryRegion containing the devices provided + * by the board model. + * + QOM property "MAINCLK" is the frequency of the main system clock + * + QOM property "EXP_NUMIRQ" sets the number of expansion interrupts + * + Named GPIO inputs "EXP_IRQ" 0..n are the expansion interrupts, which + * are wired to the NVIC lines 32 .. n+32 + * Controlling up to 4 AHB expansion PPBs which a system using the IoTKit + * might provide: + * + named GPIO outputs apb_ppcexp{0,1,2,3}_nonsec[0..15] + * + named GPIO outputs apb_ppcexp{0,1,2,3}_ap[0..15] + * + named GPIO outputs apb_ppcexp{0,1,2,3}_irq_enable + * + named GPIO outputs apb_ppcexp{0,1,2,3}_irq_clear + * + named GPIO inputs apb_ppcexp{0,1,2,3}_irq_status + * Controlling each of the 4 expansion AHB PPCs which a system using the IoTKit + * might provide: + * + named GPIO outputs ahb_ppcexp{0,1,2,3}_nonsec[0..15] + * + named GPIO outputs ahb_ppcexp{0,1,2,3}_ap[0..15] + * + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_enable + * + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_clear + * + named GPIO inputs ahb_ppcexp{0,1,2,3}_irq_status + */ + +#ifndef IOTKIT_H +#define IOTKIT_H + +#include "hw/sysbus.h" +#include "hw/arm/armv7m.h" +#include "hw/misc/iotkit-secctl.h" +#include "hw/misc/tz-ppc.h" +#include "hw/timer/cmsdk-apb-timer.h" +#include "hw/misc/unimp.h" +#include "hw/or-irq.h" +#include "hw/core/split-irq.h" + +#define TYPE_IOTKIT "iotkit" +#define IOTKIT(obj) OBJECT_CHECK(IoTKit, (obj), TYPE_IOTKIT) + +/* We have an IRQ splitter and an OR gate input for each external PPC + * and the 2 internal PPCs + */ +#define NUM_EXTERNAL_PPCS (IOTS_NUM_AHB_EXP_PPC + IOTS_NUM_APB_EXP_PPC) +#define NUM_PPCS (NUM_EXTERNAL_PPCS + 2) + +typedef struct IoTKit { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + ARMv7MState armv7m; + IoTKitSecCtl secctl; + TZPPC apb_ppc0; + TZPPC apb_ppc1; + CMSDKAPBTIMER timer0; + CMSDKAPBTIMER timer1; + qemu_or_irq ppc_irq_orgate; + SplitIRQ sec_resp_splitter; + SplitIRQ ppc_irq_splitter[NUM_PPCS]; + + UnimplementedDeviceState dualtimer; + UnimplementedDeviceState s32ktimer; + + MemoryRegion container; + MemoryRegion alias1; + MemoryRegion alias2; + MemoryRegion alias3; + MemoryRegion sram0; + + qemu_irq *exp_irqs; + qemu_irq ppc0_irq; + qemu_irq ppc1_irq; + qemu_irq sec_resp_cfg; + qemu_irq sec_resp_cfg_in; + qemu_irq nsc_cfg_in; + + qemu_irq irq_status_in[NUM_EXTERNAL_PPCS]; + + uint32_t nsccfg; + + /* Properties */ + MemoryRegion *board_memory; + uint32_t exp_numirq; + uint32_t mainclk_frq; +} IoTKit; + +#endif diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c new file mode 100644 index 0000000000..c5f0a5b98a --- /dev/null +++ b/hw/arm/iotkit.c @@ -0,0 +1,598 @@ +/* + * Arm IoT Kit + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "trace.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/arm/iotkit.h" +#include "hw/misc/unimp.h" +#include "hw/arm/arm.h" + +/* Create an alias region of @size bytes starting at @base + * which mirrors the memory starting at @orig. + */ +static void make_alias(IoTKit *s, MemoryRegion *mr, const char *name, + hwaddr base, hwaddr size, hwaddr orig) +{ + memory_region_init_alias(mr, NULL, name, &s->container, orig, size); + /* The alias is even lower priority than unimplemented_device regions */ + memory_region_add_subregion_overlap(&s->container, base, mr, -1500); +} + +static void init_sysbus_child(Object *parent, const char *childname, + void *child, size_t childsize, + const char *childtype) +{ + object_initialize(child, childsize, childtype); + object_property_add_child(parent, childname, OBJECT(child), &error_abort); + qdev_set_parent_bus(DEVICE(child), sysbus_get_default()); +} + +static void irq_status_forwarder(void *opaque, int n, int level) +{ + qemu_irq destirq = opaque; + + qemu_set_irq(destirq, level); +} + +static void nsccfg_handler(void *opaque, int n, int level) +{ + IoTKit *s = IOTKIT(opaque); + + s->nsccfg = level; +} + +static void iotkit_forward_ppc(IoTKit *s, const char *ppcname, int ppcnum) +{ + /* Each of the 4 AHB and 4 APB PPCs that might be present in a + * system using the IoTKit has a collection of control lines which + * are provided by the security controller and which we want to + * expose as control lines on the IoTKit device itself, so the + * code using the IoTKit can wire them up to the PPCs. + */ + SplitIRQ *splitter = &s->ppc_irq_splitter[ppcnum]; + DeviceState *iotkitdev = DEVICE(s); + DeviceState *dev_secctl = DEVICE(&s->secctl); + DeviceState *dev_splitter = DEVICE(splitter); + char *name; + + name = g_strdup_printf("%s_nonsec", ppcname); + qdev_pass_gpios(dev_secctl, iotkitdev, name); + g_free(name); + name = g_strdup_printf("%s_ap", ppcname); + qdev_pass_gpios(dev_secctl, iotkitdev, name); + g_free(name); + name = g_strdup_printf("%s_irq_enable", ppcname); + qdev_pass_gpios(dev_secctl, iotkitdev, name); + g_free(name); + name = g_strdup_printf("%s_irq_clear", ppcname); + qdev_pass_gpios(dev_secctl, iotkitdev, name); + g_free(name); + + /* irq_status is a little more tricky, because we need to + * split it so we can send it both to the security controller + * and to our OR gate for the NVIC interrupt line. + * Connect up the splitter's outputs, and create a GPIO input + * which will pass the line state to the input splitter. + */ + name = g_strdup_printf("%s_irq_status", ppcname); + qdev_connect_gpio_out(dev_splitter, 0, + qdev_get_gpio_in_named(dev_secctl, + name, 0)); + qdev_connect_gpio_out(dev_splitter, 1, + qdev_get_gpio_in(DEVICE(&s->ppc_irq_orgate), ppcnum)); + s->irq_status_in[ppcnum] = qdev_get_gpio_in(dev_splitter, 0); + qdev_init_gpio_in_named_with_opaque(iotkitdev, irq_status_forwarder, + s->irq_status_in[ppcnum], name, 1); + g_free(name); +} + +static void iotkit_forward_sec_resp_cfg(IoTKit *s) +{ + /* Forward the 3rd output from the splitter device as a + * named GPIO output of the iotkit object. + */ + DeviceState *dev = DEVICE(s); + DeviceState *dev_splitter = DEVICE(&s->sec_resp_splitter); + + qdev_init_gpio_out_named(dev, &s->sec_resp_cfg, "sec_resp_cfg", 1); + s->sec_resp_cfg_in = qemu_allocate_irq(irq_status_forwarder, + s->sec_resp_cfg, 1); + qdev_connect_gpio_out(dev_splitter, 2, s->sec_resp_cfg_in); +} + +static void iotkit_init(Object *obj) +{ + IoTKit *s = IOTKIT(obj); + int i; + + memory_region_init(&s->container, obj, "iotkit-container", UINT64_MAX); + + init_sysbus_child(obj, "armv7m", &s->armv7m, sizeof(s->armv7m), + TYPE_ARMV7M); + qdev_prop_set_string(DEVICE(&s->armv7m), "cpu-type", + ARM_CPU_TYPE_NAME("cortex-m33")); + + init_sysbus_child(obj, "secctl", &s->secctl, sizeof(s->secctl), + TYPE_IOTKIT_SECCTL); + init_sysbus_child(obj, "apb-ppc0", &s->apb_ppc0, sizeof(s->apb_ppc0), + TYPE_TZ_PPC); + init_sysbus_child(obj, "apb-ppc1", &s->apb_ppc1, sizeof(s->apb_ppc1), + TYPE_TZ_PPC); + init_sysbus_child(obj, "timer0", &s->timer0, sizeof(s->timer0), + TYPE_CMSDK_APB_TIMER); + init_sysbus_child(obj, "timer1", &s->timer1, sizeof(s->timer1), + TYPE_CMSDK_APB_TIMER); + init_sysbus_child(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer), + TYPE_UNIMPLEMENTED_DEVICE); + object_initialize(&s->ppc_irq_orgate, sizeof(s->ppc_irq_orgate), + TYPE_OR_IRQ); + object_property_add_child(obj, "ppc-irq-orgate", + OBJECT(&s->ppc_irq_orgate), &error_abort); + object_initialize(&s->sec_resp_splitter, sizeof(s->sec_resp_splitter), + TYPE_SPLIT_IRQ); + object_property_add_child(obj, "sec-resp-splitter", + OBJECT(&s->sec_resp_splitter), &error_abort); + for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) { + char *name = g_strdup_printf("ppc-irq-splitter-%d", i); + SplitIRQ *splitter = &s->ppc_irq_splitter[i]; + + object_initialize(splitter, sizeof(*splitter), TYPE_SPLIT_IRQ); + object_property_add_child(obj, name, OBJECT(splitter), &error_abort); + } + init_sysbus_child(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer), + TYPE_UNIMPLEMENTED_DEVICE); +} + +static void iotkit_exp_irq(void *opaque, int n, int level) +{ + IoTKit *s = IOTKIT(opaque); + + qemu_set_irq(s->exp_irqs[n], level); +} + +static void iotkit_realize(DeviceState *dev, Error **errp) +{ + IoTKit *s = IOTKIT(dev); + int i; + MemoryRegion *mr; + Error *err = NULL; + SysBusDevice *sbd_apb_ppc0; + SysBusDevice *sbd_secctl; + DeviceState *dev_apb_ppc0; + DeviceState *dev_apb_ppc1; + DeviceState *dev_secctl; + DeviceState *dev_splitter; + + if (!s->board_memory) { + error_setg(errp, "memory property was not set"); + return; + } + + if (!s->mainclk_frq) { + error_setg(errp, "MAINCLK property was not set"); + return; + } + + /* Handling of which devices should be available only to secure + * code is usually done differently for M profile than for A profile. + * Instead of putting some devices only into the secure address space, + * devices exist in both address spaces but with hard-wired security + * permissions that will cause the CPU to fault for non-secure accesses. + * + * The IoTKit has an IDAU (Implementation Defined Access Unit), + * which specifies hard-wired security permissions for different + * areas of the physical address space. For the IoTKit IDAU, the + * top 4 bits of the physical address are the IDAU region ID, and + * if bit 28 (ie the lowest bit of the ID) is 0 then this is an NS + * region, otherwise it is an S region. + * + * The various devices and RAMs are generally all mapped twice, + * once into a region that the IDAU defines as secure and once + * into a non-secure region. They sit behind either a Memory + * Protection Controller (for RAM) or a Peripheral Protection + * Controller (for devices), which allow a more fine grained + * configuration of whether non-secure accesses are permitted. + * + * (The other place that guest software can configure security + * permissions is in the architected SAU (Security Attribution + * Unit), which is entirely inside the CPU. The IDAU can upgrade + * the security attributes for a region to more restrictive than + * the SAU specifies, but cannot downgrade them.) + * + * 0x10000000..0x1fffffff alias of 0x00000000..0x0fffffff + * 0x20000000..0x2007ffff 32KB FPGA block RAM + * 0x30000000..0x3fffffff alias of 0x20000000..0x2fffffff + * 0x40000000..0x4000ffff base peripheral region 1 + * 0x40010000..0x4001ffff CPU peripherals (none for IoTKit) + * 0x40020000..0x4002ffff system control element peripherals + * 0x40080000..0x400fffff base peripheral region 2 + * 0x50000000..0x5fffffff alias of 0x40000000..0x4fffffff + */ + + memory_region_add_subregion_overlap(&s->container, 0, s->board_memory, -1); + + qdev_prop_set_uint32(DEVICE(&s->armv7m), "num-irq", s->exp_numirq + 32); + /* In real hardware the initial Secure VTOR is set from the INITSVTOR0 + * register in the IoT Kit System Control Register block, and the + * initial value of that is in turn specifiable by the FPGA that + * instantiates the IoT Kit. In QEMU we don't implement this wrinkle, + * and simply set the CPU's init-svtor to the IoT Kit default value. + */ + qdev_prop_set_uint32(DEVICE(&s->armv7m), "init-svtor", 0x10000000); + object_property_set_link(OBJECT(&s->armv7m), OBJECT(&s->container), + "memory", &err); + if (err) { + error_propagate(errp, err); + return; + } + object_property_set_link(OBJECT(&s->armv7m), OBJECT(s), "idau", &err); + if (err) { + error_propagate(errp, err); + return; + } + object_property_set_bool(OBJECT(&s->armv7m), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + /* Connect our EXP_IRQ GPIOs to the NVIC's lines 32 and up. */ + s->exp_irqs = g_new(qemu_irq, s->exp_numirq); + for (i = 0; i < s->exp_numirq; i++) { + s->exp_irqs[i] = qdev_get_gpio_in(DEVICE(&s->armv7m), i + 32); + } + qdev_init_gpio_in_named(dev, iotkit_exp_irq, "EXP_IRQ", s->exp_numirq); + + /* Set up the big aliases first */ + make_alias(s, &s->alias1, "alias 1", 0x10000000, 0x10000000, 0x00000000); + make_alias(s, &s->alias2, "alias 2", 0x30000000, 0x10000000, 0x20000000); + /* The 0x50000000..0x5fffffff region is not a pure alias: it has + * a few extra devices that only appear there (generally the + * control interfaces for the protection controllers). + * We implement this by mapping those devices over the top of this + * alias MR at a higher priority. + */ + make_alias(s, &s->alias3, "alias 3", 0x50000000, 0x10000000, 0x40000000); + + /* This RAM should be behind a Memory Protection Controller, but we + * don't implement that yet. + */ + memory_region_init_ram(&s->sram0, NULL, "iotkit.sram0", 0x00008000, &err); + if (err) { + error_propagate(errp, err); + return; + } + memory_region_add_subregion(&s->container, 0x20000000, &s->sram0); + + /* Security controller */ + object_property_set_bool(OBJECT(&s->secctl), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sbd_secctl = SYS_BUS_DEVICE(&s->secctl); + dev_secctl = DEVICE(&s->secctl); + sysbus_mmio_map(sbd_secctl, 0, 0x50080000); + sysbus_mmio_map(sbd_secctl, 1, 0x40080000); + + s->nsc_cfg_in = qemu_allocate_irq(nsccfg_handler, s, 1); + qdev_connect_gpio_out_named(dev_secctl, "nsc_cfg", 0, s->nsc_cfg_in); + + /* The sec_resp_cfg output from the security controller must be split into + * multiple lines, one for each of the PPCs within the IoTKit and one + * that will be an output from the IoTKit to the system. + */ + object_property_set_int(OBJECT(&s->sec_resp_splitter), 3, + "num-lines", &err); + if (err) { + error_propagate(errp, err); + return; + } + object_property_set_bool(OBJECT(&s->sec_resp_splitter), true, + "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + dev_splitter = DEVICE(&s->sec_resp_splitter); + qdev_connect_gpio_out_named(dev_secctl, "sec_resp_cfg", 0, + qdev_get_gpio_in(dev_splitter, 0)); + + /* Devices behind APB PPC0: + * 0x40000000: timer0 + * 0x40001000: timer1 + * 0x40002000: dual timer + * We must configure and realize each downstream device and connect + * it to the appropriate PPC port; then we can realize the PPC and + * map its upstream ends to the right place in the container. + */ + qdev_prop_set_uint32(DEVICE(&s->timer0), "pclk-frq", s->mainclk_frq); + object_property_set_bool(OBJECT(&s->timer0), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer0), 0, + qdev_get_gpio_in(DEVICE(&s->armv7m), 3)); + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer0), 0); + object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[0]", &err); + if (err) { + error_propagate(errp, err); + return; + } + + qdev_prop_set_uint32(DEVICE(&s->timer1), "pclk-frq", s->mainclk_frq); + object_property_set_bool(OBJECT(&s->timer1), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer1), 0, + qdev_get_gpio_in(DEVICE(&s->armv7m), 3)); + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer1), 0); + object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[1]", &err); + if (err) { + error_propagate(errp, err); + return; + } + + qdev_prop_set_string(DEVICE(&s->dualtimer), "name", "Dual timer"); + qdev_prop_set_uint64(DEVICE(&s->dualtimer), "size", 0x1000); + object_property_set_bool(OBJECT(&s->dualtimer), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0); + object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_bool(OBJECT(&s->apb_ppc0), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + sbd_apb_ppc0 = SYS_BUS_DEVICE(&s->apb_ppc0); + dev_apb_ppc0 = DEVICE(&s->apb_ppc0); + + mr = sysbus_mmio_get_region(sbd_apb_ppc0, 0); + memory_region_add_subregion(&s->container, 0x40000000, mr); + mr = sysbus_mmio_get_region(sbd_apb_ppc0, 1); + memory_region_add_subregion(&s->container, 0x40001000, mr); + mr = sysbus_mmio_get_region(sbd_apb_ppc0, 2); + memory_region_add_subregion(&s->container, 0x40002000, mr); + for (i = 0; i < IOTS_APB_PPC0_NUM_PORTS; i++) { + qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_nonsec", i, + qdev_get_gpio_in_named(dev_apb_ppc0, + "cfg_nonsec", i)); + qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_ap", i, + qdev_get_gpio_in_named(dev_apb_ppc0, + "cfg_ap", i)); + } + qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_irq_enable", 0, + qdev_get_gpio_in_named(dev_apb_ppc0, + "irq_enable", 0)); + qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_irq_clear", 0, + qdev_get_gpio_in_named(dev_apb_ppc0, + "irq_clear", 0)); + qdev_connect_gpio_out(dev_splitter, 0, + qdev_get_gpio_in_named(dev_apb_ppc0, + "cfg_sec_resp", 0)); + + /* All the PPC irq lines (from the 2 internal PPCs and the 8 external + * ones) are sent individually to the security controller, and also + * ORed together to give a single combined PPC interrupt to the NVIC. + */ + object_property_set_int(OBJECT(&s->ppc_irq_orgate), + NUM_PPCS, "num-lines", &err); + if (err) { + error_propagate(errp, err); + return; + } + object_property_set_bool(OBJECT(&s->ppc_irq_orgate), true, + "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + qdev_connect_gpio_out(DEVICE(&s->ppc_irq_orgate), 0, + qdev_get_gpio_in(DEVICE(&s->armv7m), 10)); + + /* 0x40010000 .. 0x4001ffff: private CPU region: unused in IoTKit */ + + /* 0x40020000 .. 0x4002ffff : IoTKit system control peripheral region */ + /* Devices behind APB PPC1: + * 0x4002f000: S32K timer + */ + qdev_prop_set_string(DEVICE(&s->s32ktimer), "name", "S32KTIMER"); + qdev_prop_set_uint64(DEVICE(&s->s32ktimer), "size", 0x1000); + object_property_set_bool(OBJECT(&s->s32ktimer), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0); + object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_bool(OBJECT(&s->apb_ppc1), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->apb_ppc1), 0); + memory_region_add_subregion(&s->container, 0x4002f000, mr); + + dev_apb_ppc1 = DEVICE(&s->apb_ppc1); + qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_nonsec", 0, + qdev_get_gpio_in_named(dev_apb_ppc1, + "cfg_nonsec", 0)); + qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_ap", 0, + qdev_get_gpio_in_named(dev_apb_ppc1, + "cfg_ap", 0)); + qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_irq_enable", 0, + qdev_get_gpio_in_named(dev_apb_ppc1, + "irq_enable", 0)); + qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_irq_clear", 0, + qdev_get_gpio_in_named(dev_apb_ppc1, + "irq_clear", 0)); + qdev_connect_gpio_out(dev_splitter, 1, + qdev_get_gpio_in_named(dev_apb_ppc1, + "cfg_sec_resp", 0)); + + /* Using create_unimplemented_device() maps the stub into the + * system address space rather than into our container, but the + * overall effect to the guest is the same. + */ + create_unimplemented_device("SYSINFO", 0x40020000, 0x1000); + + create_unimplemented_device("SYSCONTROL", 0x50021000, 0x1000); + create_unimplemented_device("S32KWATCHDOG", 0x5002e000, 0x1000); + + /* 0x40080000 .. 0x4008ffff : IoTKit second Base peripheral region */ + + create_unimplemented_device("NS watchdog", 0x40081000, 0x1000); + create_unimplemented_device("S watchdog", 0x50081000, 0x1000); + + create_unimplemented_device("SRAM0 MPC", 0x50083000, 0x1000); + + for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) { + Object *splitter = OBJECT(&s->ppc_irq_splitter[i]); + + object_property_set_int(splitter, 2, "num-lines", &err); + if (err) { + error_propagate(errp, err); + return; + } + object_property_set_bool(splitter, true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + } + + for (i = 0; i < IOTS_NUM_AHB_EXP_PPC; i++) { + char *ppcname = g_strdup_printf("ahb_ppcexp%d", i); + + iotkit_forward_ppc(s, ppcname, i); + g_free(ppcname); + } + + for (i = 0; i < IOTS_NUM_APB_EXP_PPC; i++) { + char *ppcname = g_strdup_printf("apb_ppcexp%d", i); + + iotkit_forward_ppc(s, ppcname, i + IOTS_NUM_AHB_EXP_PPC); + g_free(ppcname); + } + + for (i = NUM_EXTERNAL_PPCS; i < NUM_PPCS; i++) { + /* Wire up IRQ splitter for internal PPCs */ + DeviceState *devs = DEVICE(&s->ppc_irq_splitter[i]); + char *gpioname = g_strdup_printf("apb_ppc%d_irq_status", + i - NUM_EXTERNAL_PPCS); + TZPPC *ppc = (i == NUM_EXTERNAL_PPCS) ? &s->apb_ppc0 : &s->apb_ppc1; + + qdev_connect_gpio_out(devs, 0, + qdev_get_gpio_in_named(dev_secctl, gpioname, 0)); + qdev_connect_gpio_out(devs, 1, + qdev_get_gpio_in(DEVICE(&s->ppc_irq_orgate), i)); + qdev_connect_gpio_out_named(DEVICE(ppc), "irq", 0, + qdev_get_gpio_in(devs, 0)); + } + + iotkit_forward_sec_resp_cfg(s); + + system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq; +} + +static void iotkit_idau_check(IDAUInterface *ii, uint32_t address, + int *iregion, bool *exempt, bool *ns, bool *nsc) +{ + /* For IoTKit systems the IDAU responses are simple logical functions + * of the address bits. The NSC attribute is guest-adjustable via the + * NSCCFG register in the security controller. + */ + IoTKit *s = IOTKIT(ii); + int region = extract32(address, 28, 4); + + *ns = !(region & 1); + *nsc = (region == 1 && (s->nsccfg & 1)) || (region == 3 && (s->nsccfg & 2)); + /* 0xe0000000..0xe00fffff and 0xf0000000..0xf00fffff are exempt */ + *exempt = (address & 0xeff00000) == 0xe0000000; + *iregion = region; +} + +static const VMStateDescription iotkit_vmstate = { + .name = "iotkit", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(nsccfg, IoTKit), + VMSTATE_END_OF_LIST() + } +}; + +static Property iotkit_properties[] = { + DEFINE_PROP_LINK("memory", IoTKit, board_memory, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_UINT32("EXP_NUMIRQ", IoTKit, exp_numirq, 64), + DEFINE_PROP_UINT32("MAINCLK", IoTKit, mainclk_frq, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static void iotkit_reset(DeviceState *dev) +{ + IoTKit *s = IOTKIT(dev); + + s->nsccfg = 0; +} + +static void iotkit_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(klass); + + dc->realize = iotkit_realize; + dc->vmsd = &iotkit_vmstate; + dc->props = iotkit_properties; + dc->reset = iotkit_reset; + iic->check = iotkit_idau_check; +} + +static const TypeInfo iotkit_info = { + .name = TYPE_IOTKIT, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IoTKit), + .instance_init = iotkit_init, + .class_init = iotkit_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_IDAU_INTERFACE }, + { } + } +}; + +static void iotkit_register_types(void) +{ + type_register_static(&iotkit_info); +} + +type_init(iotkit_register_types); diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index a2057908f0..2f735917a5 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -104,6 +104,7 @@ CONFIG_MPS2_FPGAIO=y CONFIG_MPS2_SCC=y CONFIG_TZ_PPC=y +CONFIG_IOTKIT=y CONFIG_IOTKIT_SECCTL=y CONFIG_VERSATILE_PCI=y From patchwork Tue Feb 20 18:03:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 128965 Delivered-To: patches@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4910473ljc; Tue, 20 Feb 2018 10:03:41 -0800 (PST) X-Google-Smtp-Source: AH8x227HXt76X49AUAFrIaY2GqnOryQW50Wt0M5ao5JVxuFTlCUNLks7fmRM/mhr0X8eZJDKgnDM X-Received: by 10.46.93.148 with SMTP id v20mr331029lje.34.1519149821508; Tue, 20 Feb 2018 10:03:41 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519149821; cv=none; d=google.com; s=arc-20160816; b=vMfsIHPOEr+cB0pEVFJMeU1XSiOcPJGxJMshA7897M8Btql1U+hFc1nB12oSEdH9Ui n29UuqYSGbpj9bBt5QTbp5Op12uWdbHZ8AkPw5++vPFmBM/oq7SIn1lpABiEcsNs5Iq1 TuZ8zAku+Go7p2Nw46ujtSnnq2F69g5DZ4zm1zo7iEPQimVshhqC/Khqpr4/m+tyKIH7 BzE77H8rohK0aSUrEorAXFy24gk1hXzSVMgl0KdHbt9ih3Xxlr1aubn1iQAn+oD6k0NA rNu097wHyHYIw/RpWP3e0CiSTm47wC6lFE1hRYl9/3WX9yTnYaL1cJjSEyHwMDWC6XVK KPDw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=sqlmBXYZrvL9yPiFKwaBm8jSEWXkgwTuY9vNbPIQRCQ=; b=e5RnXdHvH/hBqKr+L/2bU2r/7UgBWnbdNuJ+6TB1vLZCUovDnkGK04K269RJ34tKao xOy/iTOAfcOCUpW2ybmQKWoH/MdIEF5sznUQa/j9HenlkMe0neI01z0Jh8+38lZvFqdq zab+X7lxBignXzXowKXew72s3EiSiNEpUn/BW/o0LSDPsFrcy2pROYDg6Ug0NcZU/JFY x3H3w9Dn/P1/kxwI8ZZ9/BZ1CkjvL2pq2WoiYaXnoErrkwgSVLarRy/z5tEyHheOwwRm ZboriHm69G7QSxSvz+wZca6erA89Zr9P3ECo116O5dLplXRxQJX+/aw0nd0aprwuOpHM Y9nA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id s12si9123261lfk.419.2018.02.20.10.03.41 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 20 Feb 2018 10:03:41 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1eoCGS-0008Ut-Ed; Tue, 20 Feb 2018 18:03:40 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org Subject: [PATCH 19/19] mps2-an505: New board model: MPS2 with AN505 Cortex-M33 FPGA image Date: Tue, 20 Feb 2018 18:03:25 +0000 Message-Id: <20180220180325.29818-20-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180220180325.29818-1-peter.maydell@linaro.org> References: <20180220180325.29818-1-peter.maydell@linaro.org> Define a new board model for the MPS2 with an AN505 FPGA image containing a Cortex-M33. Since the FPGA images for TrustZone cores (AN505, and the similar AN519 for Cortex-M23) have a significantly different layout of devices to the non-TrustZone images, we use a new source file rather than shoehorning them into the existing mps2.c. Signed-off-by: Peter Maydell --- hw/arm/Makefile.objs | 1 + hw/arm/mps2-tz.c | 504 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 505 insertions(+) create mode 100644 hw/arm/mps2-tz.c -- 2.16.1 Reviewed-by: Richard Henderson diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 79cd30bb92..232258160a 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -19,5 +19,6 @@ obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o obj-$(CONFIG_MPS2) += mps2.o +obj-$(CONFIG_MPS2) += mps2-tz.o obj-$(CONFIG_MSF2) += msf2-soc.o msf2-som.o obj-$(CONFIG_IOTKIT) += iotkit.o diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c new file mode 100644 index 0000000000..ff414c649c --- /dev/null +++ b/hw/arm/mps2-tz.c @@ -0,0 +1,504 @@ +/* + * ARM V2M MPS2 board emulation, trustzone aware FPGA images + * + * Copyright (c) 2017 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +/* The MPS2 and MPS2+ dev boards are FPGA based (the 2+ has a bigger + * FPGA but is otherwise the same as the 2). Since the CPU itself + * and most of the devices are in the FPGA, the details of the board + * as seen by the guest depend significantly on the FPGA image. + * This source file covers the following FPGA images, for TrustZone cores: + * "mps2-an505" -- Cortex-M33 as documented in ARM Application Note AN505 + * + * Links to the TRM for the board itself and to the various Application + * Notes which document the FPGA images can be found here: + * https://developer.arm.com/products/system-design/development-boards/fpga-prototyping-boards/mps2 + * + * Board TRM: + * http://infocenter.arm.com/help/topic/com.arm.doc.100112_0200_06_en/versatile_express_cortex_m_prototyping_systems_v2m_mps2_and_v2m_mps2plus_technical_reference_100112_0200_06_en.pdf + * Application Note AN505: + * http://infocenter.arm.com/help/topic/com.arm.doc.dai0505b/index.html + * + * The AN505 defers to the Cortex-M33 processor ARMv8M IoT Kit FVP User Guide + * (ARM ECM0601256) for the details of some of the device layout: + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "hw/arm/arm.h" +#include "hw/arm/armv7m.h" +#include "hw/or-irq.h" +#include "hw/boards.h" +#include "exec/address-spaces.h" +#include "sysemu/sysemu.h" +#include "hw/misc/unimp.h" +#include "hw/char/cmsdk-apb-uart.h" +#include "hw/timer/cmsdk-apb-timer.h" +#include "hw/misc/mps2-scc.h" +#include "hw/misc/mps2-fpgaio.h" +#include "hw/arm/iotkit.h" +#include "hw/devices.h" +#include "net/net.h" +#include "hw/core/split-irq.h" + +typedef enum MPS2TZFPGAType { + FPGA_AN505, +} MPS2TZFPGAType; + +typedef struct { + MachineClass parent; + MPS2TZFPGAType fpga_type; + const char *cpu_model; + uint32_t scc_id; +} MPS2TZMachineClass; + +typedef struct { + MachineState parent; + + IoTKit iotkit; + MemoryRegion psram; + MemoryRegion ssram1; + MemoryRegion ssram1_m; + MemoryRegion ssram23; + MPS2SCC scc; + MPS2FPGAIO fpgaio; + TZPPC ppc[5]; + UnimplementedDeviceState ssram_mpc[3]; + UnimplementedDeviceState spi[5]; + UnimplementedDeviceState i2c[4]; + UnimplementedDeviceState i2s_audio; + UnimplementedDeviceState gpio[5]; + UnimplementedDeviceState dma[4]; + UnimplementedDeviceState gfx; + CMSDKAPBUART uart[5]; + SplitIRQ sec_resp_splitter; + qemu_or_irq uart_irq_orgate; +} MPS2TZMachineState; + +#define TYPE_MPS2TZ_MACHINE "mps2tz" +#define TYPE_MPS2TZ_AN505_MACHINE MACHINE_TYPE_NAME("mps2-an505") + +#define MPS2TZ_MACHINE(obj) \ + OBJECT_CHECK(MPS2TZMachineState, obj, TYPE_MPS2TZ_MACHINE) +#define MPS2TZ_MACHINE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(MPS2TZMachineClass, obj, TYPE_MPS2TZ_MACHINE) +#define MPS2TZ_MACHINE_CLASS(klass) \ + OBJECT_CLASS_CHECK(MPS2TZMachineClass, klass, TYPE_MPS2TZ_MACHINE) + +/* Main SYSCLK frequency in Hz */ +#define SYSCLK_FRQ 20000000 + +/* Initialize the auxiliary RAM region @mr and map it into + * the memory map at @base. + */ +static void make_ram(MemoryRegion *mr, const char *name, + hwaddr base, hwaddr size) +{ + memory_region_init_ram(mr, NULL, name, size, &error_fatal); + memory_region_add_subregion(get_system_memory(), base, mr); +} + +/* Create an alias of an entire original MemoryRegion @orig + * located at @base in the memory map. + */ +static void make_ram_alias(MemoryRegion *mr, const char *name, + MemoryRegion *orig, hwaddr base) +{ + memory_region_init_alias(mr, NULL, name, orig, 0, + memory_region_size(orig)); + memory_region_add_subregion(get_system_memory(), base, mr); +} + +static void init_sysbus_child(Object *parent, const char *childname, + void *child, size_t childsize, + const char *childtype) +{ + object_initialize(child, childsize, childtype); + object_property_add_child(parent, childname, OBJECT(child), &error_abort); + qdev_set_parent_bus(DEVICE(child), sysbus_get_default()); + +} + +/* Most of the devices in the AN505 FPGA image sit behind + * Peripheral Protection Controllers. These data structures + * define the layout of which devices sit behind which PPCs. + * The devfn for each port is a function which creates, configures + * and initializes the device, returning the MemoryRegion which + * needs to be plugged into the downstream end of the PPC port. + */ +typedef MemoryRegion *MakeDevFn(MPS2TZMachineState *mms, void *opaque, + const char *name, hwaddr size); + +typedef struct PPCPortInfo { + const char *name; + MakeDevFn *devfn; + void *opaque; + hwaddr addr; + hwaddr size; +} PPCPortInfo; + +typedef struct PPCInfo { + const char *name; + PPCPortInfo ports[TZ_NUM_PORTS]; +} PPCInfo; + +static MemoryRegion *make_unimp_dev(MPS2TZMachineState *mms, + void *opaque, + const char *name, hwaddr size) +{ + /* Initialize, configure and realize a TYPE_UNIMPLEMENTED_DEVICE, + * and return a pointer to its MemoryRegion. + */ + UnimplementedDeviceState *uds = opaque; + + init_sysbus_child(OBJECT(mms), name, uds, + sizeof(UnimplementedDeviceState), + TYPE_UNIMPLEMENTED_DEVICE); + qdev_prop_set_string(DEVICE(uds), "name", name); + qdev_prop_set_uint64(DEVICE(uds), "size", size); + object_property_set_bool(OBJECT(uds), true, "realized", &error_fatal); + return sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0); +} + +static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque, + const char *name, hwaddr size) +{ + CMSDKAPBUART *uart = opaque; + int i = uart - &mms->uart[0]; + Chardev *uartchr = i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL; + int rxirqno = i * 2; + int txirqno = i * 2 + 1; + int combirqno = i + 10; + SysBusDevice *s; + DeviceState *iotkitdev = DEVICE(&mms->iotkit); + DeviceState *orgate_dev = DEVICE(&mms->uart_irq_orgate); + + init_sysbus_child(OBJECT(mms), name, uart, + sizeof(mms->uart[0]), TYPE_CMSDK_APB_UART); + qdev_prop_set_chr(DEVICE(uart), "chardev", uartchr); + qdev_prop_set_uint32(DEVICE(uart), "pclk-frq", SYSCLK_FRQ); + object_property_set_bool(OBJECT(uart), true, "realized", &error_fatal); + s = SYS_BUS_DEVICE(uart); + sysbus_connect_irq(s, 0, qdev_get_gpio_in_named(iotkitdev, + "EXP_IRQ", txirqno)); + sysbus_connect_irq(s, 1, qdev_get_gpio_in_named(iotkitdev, + "EXP_IRQ", rxirqno)); + sysbus_connect_irq(s, 2, qdev_get_gpio_in(orgate_dev, i * 2)); + sysbus_connect_irq(s, 3, qdev_get_gpio_in(orgate_dev, i * 2 + 1)); + sysbus_connect_irq(s, 4, qdev_get_gpio_in_named(iotkitdev, + "EXP_IRQ", combirqno)); + return sysbus_mmio_get_region(SYS_BUS_DEVICE(uart), 0); +} + +static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque, + const char *name, hwaddr size) +{ + MPS2SCC *scc = opaque; + DeviceState *sccdev; + MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); + + object_initialize(scc, sizeof(mms->scc), TYPE_MPS2_SCC); + sccdev = DEVICE(scc); + qdev_set_parent_bus(sccdev, sysbus_get_default()); + qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2); + qdev_prop_set_uint32(sccdev, "scc-aid", 0x02000008); + qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id); + object_property_set_bool(OBJECT(scc), true, "realized", &error_fatal); + return sysbus_mmio_get_region(SYS_BUS_DEVICE(sccdev), 0); +} + +static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque, + const char *name, hwaddr size) +{ + MPS2FPGAIO *fpgaio = opaque; + + object_initialize(fpgaio, sizeof(mms->fpgaio), TYPE_MPS2_FPGAIO); + qdev_set_parent_bus(DEVICE(fpgaio), sysbus_get_default()); + object_property_set_bool(OBJECT(fpgaio), true, "realized", &error_fatal); + return sysbus_mmio_get_region(SYS_BUS_DEVICE(fpgaio), 0); +} + +static void mps2tz_common_init(MachineState *machine) +{ + MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine); + MachineClass *mc = MACHINE_GET_CLASS(machine); + MemoryRegion *system_memory = get_system_memory(); + DeviceState *iotkitdev; + DeviceState *dev_splitter; + int i; + + if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) { + error_report("This board can only be used with CPU %s", + mc->default_cpu_type); + exit(1); + } + + init_sysbus_child(OBJECT(machine), "iotkit", &mms->iotkit, + sizeof(mms->iotkit), TYPE_IOTKIT); + iotkitdev = DEVICE(&mms->iotkit); + object_property_set_link(OBJECT(&mms->iotkit), OBJECT(system_memory), + "memory", &error_abort); + qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", 92); + qdev_prop_set_uint32(iotkitdev, "MAINCLK", SYSCLK_FRQ); + object_property_set_bool(OBJECT(&mms->iotkit), true, "realized", + &error_fatal); + + /* The sec_resp_cfg output from the IoTKit must be split into multiple + * lines, one for each of the PPCs we create here. + */ + object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter), + TYPE_SPLIT_IRQ); + object_property_add_child(OBJECT(machine), "sec-resp-splitter", + OBJECT(&mms->sec_resp_splitter), &error_abort); + object_property_set_int(OBJECT(&mms->sec_resp_splitter), 5, + "num-lines", &error_fatal); + object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true, + "realized", &error_fatal); + dev_splitter = DEVICE(&mms->sec_resp_splitter); + qdev_connect_gpio_out_named(iotkitdev, "sec_resp_cfg", 0, + qdev_get_gpio_in(dev_splitter, 0)); + + /* The IoTKit sets up much of the memory layout, including + * the aliases between secure and non-secure regions in the + * address space. The FPGA itself contains: + * + * 0x00000000..0x003fffff SSRAM1 + * 0x00400000..0x007fffff alias of SSRAM1 + * 0x28000000..0x283fffff 4MB SSRAM2 + SSRAM3 + * 0x40100000..0x4fffffff AHB Master Expansion 1 interface devices + * 0x80000000..0x80ffffff 16MB PSRAM + */ + + /* The FPGA images have an odd combination of different RAMs, + * because in hardware they are different implementations and + * connected to different buses, giving varying performance/size + * tradeoffs. For QEMU they're all just RAM, though. We arbitrarily + * call the 16MB our "system memory", as it's the largest lump. + */ + memory_region_allocate_system_memory(&mms->psram, + NULL, "mps.ram", 0x01000000); + memory_region_add_subregion(system_memory, 0x80000000, &mms->psram); + + /* The SSRAM memories should all be behind Memory Protection Controllers, + * but we don't implement that yet. + */ + make_ram(&mms->ssram1, "mps.ssram1", 0x00000000, 0x00400000); + make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", &mms->ssram1, 0x00400000); + + make_ram(&mms->ssram23, "mps.ssram23", 0x28000000, 0x00400000); + + /* The overflow IRQs for all UARTs are ORed together. + * Tx, Rx and "combined" IRQs are sent to the NVIC separately. + * Create the OR gate for this. + */ + object_initialize(&mms->uart_irq_orgate, sizeof(mms->uart_irq_orgate), + TYPE_OR_IRQ); + object_property_add_child(OBJECT(mms), "uart-irq-orgate", + OBJECT(&mms->uart_irq_orgate), &error_abort); + object_property_set_int(OBJECT(&mms->uart_irq_orgate), 10, "num-lines", + &error_fatal); + object_property_set_bool(OBJECT(&mms->uart_irq_orgate), true, + "realized", &error_fatal); + qdev_connect_gpio_out(DEVICE(&mms->uart_irq_orgate), 0, + qdev_get_gpio_in_named(iotkitdev, "EXP_IRQ", 15)); + + /* Most of the devices in the FPGA are behind Peripheral Protection + * Controllers. The required order for initializing things is: + * + initialize the PPC + * + initialize, configure and realize downstream devices + * + connect downstream device MemoryRegions to the PPC + * + realize the PPC + * + map the PPC's MemoryRegions to the places in the address map + * where the downstream devices should appear + * + wire up the PPC's control lines to the IoTKit object + */ + + const PPCInfo ppcs[] = { { + .name = "apb_ppcexp0", + .ports = { + { "ssram-mpc0", make_unimp_dev, &mms->ssram_mpc[0], + 0x58007000, 0x1000 }, + { "ssram-mpc1", make_unimp_dev, &mms->ssram_mpc[1], + 0x58008000, 0x1000 }, + { "ssram-mpc2", make_unimp_dev, &mms->ssram_mpc[2], + 0x58009000, 0x1000 }, + }, + }, { + .name = "apb_ppcexp1", + .ports = { + { "spi0", make_unimp_dev, &mms->spi[0], 0x40205000, 0x1000 }, + { "spi1", make_unimp_dev, &mms->spi[1], 0x40206000, 0x1000 }, + { "spi2", make_unimp_dev, &mms->spi[2], 0x40209000, 0x1000 }, + { "spi3", make_unimp_dev, &mms->spi[3], 0x4020a000, 0x1000 }, + { "spi4", make_unimp_dev, &mms->spi[4], 0x4020b000, 0x1000 }, + { "uart0", make_uart, &mms->uart[0], 0x40200000, 0x1000 }, + { "uart1", make_uart, &mms->uart[1], 0x40201000, 0x1000 }, + { "uart2", make_uart, &mms->uart[2], 0x40202000, 0x1000 }, + { "uart3", make_uart, &mms->uart[3], 0x40203000, 0x1000 }, + { "uart4", make_uart, &mms->uart[4], 0x40204000, 0x1000 }, + { "i2c0", make_unimp_dev, &mms->i2c[0], 0x40207000, 0x1000 }, + { "i2c1", make_unimp_dev, &mms->i2c[1], 0x40208000, 0x1000 }, + { "i2c2", make_unimp_dev, &mms->i2c[2], 0x4020c000, 0x1000 }, + { "i2c3", make_unimp_dev, &mms->i2c[3], 0x4020d000, 0x1000 }, + }, + }, { + .name = "apb_ppcexp2", + .ports = { + { "scc", make_scc, &mms->scc, 0x40300000, 0x1000 }, + { "i2s-audio", make_unimp_dev, &mms->i2s_audio, + 0x40301000, 0x1000 }, + { "fpgaio", make_fpgaio, &mms->fpgaio, 0x40302000, 0x1000 }, + }, + }, { + .name = "ahb_ppcexp0", + .ports = { + { "gfx", make_unimp_dev, &mms->gfx, 0x41000000, 0x140000 }, + { "gpio0", make_unimp_dev, &mms->gpio[0], 0x40100000, 0x1000 }, + { "gpio1", make_unimp_dev, &mms->gpio[1], 0x40101000, 0x1000 }, + { "gpio2", make_unimp_dev, &mms->gpio[2], 0x40102000, 0x1000 }, + { "gpio3", make_unimp_dev, &mms->gpio[3], 0x40103000, 0x1000 }, + { "gpio4", make_unimp_dev, &mms->gpio[4], 0x40104000, 0x1000 }, + }, + }, { + .name = "ahb_ppcexp1", + .ports = { + { "dma0", make_unimp_dev, &mms->dma[0], 0x40110000, 0x1000 }, + { "dma1", make_unimp_dev, &mms->dma[1], 0x40111000, 0x1000 }, + { "dma2", make_unimp_dev, &mms->dma[2], 0x40112000, 0x1000 }, + { "dma3", make_unimp_dev, &mms->dma[3], 0x40113000, 0x1000 }, + }, + }, + }; + + for (i = 0; i < ARRAY_SIZE(ppcs); i++) { + const PPCInfo *ppcinfo = &ppcs[i]; + TZPPC *ppc = &mms->ppc[i]; + DeviceState *ppcdev; + int port; + char *gpioname; + + init_sysbus_child(OBJECT(machine), ppcinfo->name, ppc, + sizeof(TZPPC), TYPE_TZ_PPC); + ppcdev = DEVICE(ppc); + + for (port = 0; port < TZ_NUM_PORTS; port++) { + const PPCPortInfo *pinfo = &ppcinfo->ports[port]; + MemoryRegion *mr; + char *portname; + + if (!pinfo->devfn) { + continue; + } + + mr = pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size); + portname = g_strdup_printf("port[%d]", port); + object_property_set_link(OBJECT(ppc), OBJECT(mr), + portname, &error_fatal); + g_free(portname); + } + + object_property_set_bool(OBJECT(ppc), true, "realized", &error_fatal); + + for (port = 0; port < TZ_NUM_PORTS; port++) { + const PPCPortInfo *pinfo = &ppcinfo->ports[port]; + + if (!pinfo->devfn) { + continue; + } + sysbus_mmio_map(SYS_BUS_DEVICE(ppc), port, pinfo->addr); + + gpioname = g_strdup_printf("%s_nonsec", ppcinfo->name); + qdev_connect_gpio_out_named(iotkitdev, gpioname, port, + qdev_get_gpio_in_named(ppcdev, + "cfg_nonsec", + port)); + g_free(gpioname); + gpioname = g_strdup_printf("%s_ap", ppcinfo->name); + qdev_connect_gpio_out_named(iotkitdev, gpioname, port, + qdev_get_gpio_in_named(ppcdev, + "cfg_ap", port)); + g_free(gpioname); + } + + gpioname = g_strdup_printf("%s_irq_enable", ppcinfo->name); + qdev_connect_gpio_out_named(iotkitdev, gpioname, 0, + qdev_get_gpio_in_named(ppcdev, + "irq_enable", 0)); + g_free(gpioname); + gpioname = g_strdup_printf("%s_irq_clear", ppcinfo->name); + qdev_connect_gpio_out_named(iotkitdev, gpioname, 0, + qdev_get_gpio_in_named(ppcdev, + "irq_clear", 0)); + g_free(gpioname); + gpioname = g_strdup_printf("%s_irq_status", ppcinfo->name); + qdev_connect_gpio_out_named(ppcdev, "irq", 0, + qdev_get_gpio_in_named(iotkitdev, + gpioname, 0)); + g_free(gpioname); + + qdev_connect_gpio_out(dev_splitter, i, + qdev_get_gpio_in_named(ppcdev, + "cfg_sec_resp", 0)); + } + + /* In hardware this is a LAN9220; the LAN9118 is software compatible + * except that it doesn't support the checksum-offload feature. + * The ethernet controller is not behind a PPC. + */ + lan9118_init(&nd_table[0], 0x42000000, + qdev_get_gpio_in_named(iotkitdev, "EXP_IRQ", 16)); + + create_unimplemented_device("FPGA NS PC", 0x48007000, 0x1000); + + armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x400000); +} + +static void mps2tz_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->init = mps2tz_common_init; + mc->max_cpus = 1; +} + +static void mps2tz_an505_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc); + + mc->desc = "ARM MPS2 with AN505 FPGA image for Cortex-M33"; + mmc->fpga_type = FPGA_AN505; + mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"); + mmc->scc_id = 0x41040000 | (505 << 4); +} + +static const TypeInfo mps2tz_info = { + .name = TYPE_MPS2TZ_MACHINE, + .parent = TYPE_MACHINE, + .abstract = true, + .instance_size = sizeof(MPS2TZMachineState), + .class_size = sizeof(MPS2TZMachineClass), + .class_init = mps2tz_class_init, +}; + +static const TypeInfo mps2tz_an505_info = { + .name = TYPE_MPS2TZ_AN505_MACHINE, + .parent = TYPE_MPS2TZ_MACHINE, + .class_init = mps2tz_an505_class_init, +}; + +static void mps2tz_machine_init(void) +{ + type_register_static(&mps2tz_info); + type_register_static(&mps2tz_an505_info); +} + +type_init(mps2tz_machine_init);