From patchwork Fri May 27 17:27:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stafford Horne X-Patchwork-Id: 12863614 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 42F49C433F5 for ; Fri, 27 May 2022 17:29:03 +0000 (UTC) Received: from localhost ([::1]:56064 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nudlm-0005UG-7X for qemu-devel@archiver.kernel.org; Fri, 27 May 2022 13:29:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60784) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nudkZ-0003RF-Nj for qemu-devel@nongnu.org; Fri, 27 May 2022 13:27:47 -0400 Received: from mail-pf1-x42c.google.com ([2607:f8b0:4864:20::42c]:41500) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nudkX-0004A6-Ex for qemu-devel@nongnu.org; Fri, 27 May 2022 13:27:47 -0400 Received: by mail-pf1-x42c.google.com with SMTP id p8so4864971pfh.8 for ; Fri, 27 May 2022 10:27:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=wGyk9o8Y+uwTh9lPK5GKDrj4v4XTzOVoGpkFAdXL5O4=; b=P3nSeMrU2vMfTS5BIkUKgwrhwQkHf8gvkOqzh6KZDYIawtJ3Tn0v2gUYVXmwwWrGvq 43fmiEsH7LpvuAoUeMInem8yLlbwBkL+QSOqz8pTZmpk1WfqWdbRkFbog4UJDTRzPpYH VkhdMrwhXOw22g82ksMizOpPsDlcoMWqx2+oAlXTLpUM61Nzcn48Hbey8bE1wfOtZTFc Fb6W/jrN4WFQt/TWrg9PGiX7Tt4IN9khmpOGlFbcvwv3b/XaJWYfdSn0DomSDs44KE5s JGbryK8v2Q6BndoBsb9yIkmyNumVjjHL0uEhDUXFdOdUHAmi0/cUPUZiCYuz06V11O4P fnjQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=wGyk9o8Y+uwTh9lPK5GKDrj4v4XTzOVoGpkFAdXL5O4=; b=8DNjrX+pAUboKEHEq2YQl02iS0Qilhue45fQTL2VOm1B0oIZOHZT84XZvXXjFinIZA CUfEzlh0zAVLaAQRksXBUCE5xiFamoZ6Yw8RGxpiondeh3mFJIGHfiF2nnZCcX/GcCJU O+niXn+nwHRmYimC92CQhq1501vJEASQibzs0hRMAHw6Si82Em10h/xzgKTXJzn7rUMt JzjV+fCIWnPk8H78jdESBw8UMmlyMW67jbnATwlhJ+lDOWU411TB6n+GfvN2sOCGmHfC /dFTitdMSsx3PIC4UHdcBpxYFS8QrLrGJcdK6rUknGIMVzInDEebCpKtHZnRJAIiADIt Qw7A== X-Gm-Message-State: AOAM5315ep9hAZZkWLw8Wgmjh+r4xRwPuF0wdKdKTue04c5dGAmyZ3fI rM0rzq9Y8HEYF78ks/HGrCbzA2UCbDbnIw== X-Google-Smtp-Source: ABdhPJxTKtZxTGAhWXwbbTSanXiupMpTAQczRwhGIk3ky6FeUpy0ms5sJMUwtWo3DpzwcYNK//UwUg== X-Received: by 2002:a05:6a00:1588:b0:518:8ce2:7753 with SMTP id u8-20020a056a00158800b005188ce27753mr30918903pfk.51.1653672462098; Fri, 27 May 2022 10:27:42 -0700 (PDT) Received: from localhost ([2409:10:24a0:4700:e8ad:216a:2a9d:6d0c]) by smtp.gmail.com with ESMTPSA id lb14-20020a17090b4a4e00b001d9780b7779sm1903881pjb.15.2022.05.27.10.27.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 May 2022 10:27:41 -0700 (PDT) From: Stafford Horne To: QEMU Development Cc: Openrisc , "Jason A. Donenfeld" , Stafford Horne Subject: [RFC PATCH 1/3] target/openrisc: Add basic support for semihosting Date: Sat, 28 May 2022 02:27:28 +0900 Message-Id: <20220527172731.1742837-2-shorne@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20220527172731.1742837-1-shorne@gmail.com> References: <20220527172731.1742837-1-shorne@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::42c; envelope-from=shorne@gmail.com; helo=mail-pf1-x42c.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" For OpenRISC we currently only use semihosting for system exit and reset. This patch implements that. The implementation uses a helper to delegate to the semihosting facility. The helper is marked as having side effects but currently does not have any. I have defined it like this as our other unimplemented semihosting calls will have side effects and return results in register r11. Signed-off-by: Stafford Horne --- configs/devices/or1k-softmmu/default.mak | 2 + qemu-options.hx | 16 ++++--- target/openrisc/cpu.h | 2 + target/openrisc/helper.h | 1 + target/openrisc/meson.build | 1 + target/openrisc/openrisc-semi.c | 54 ++++++++++++++++++++++++ target/openrisc/sys_helper.c | 5 +++ target/openrisc/translate.c | 6 +++ 8 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 target/openrisc/openrisc-semi.c diff --git a/configs/devices/or1k-softmmu/default.mak b/configs/devices/or1k-softmmu/default.mak index 168101c39a..5b3ac89491 100644 --- a/configs/devices/or1k-softmmu/default.mak +++ b/configs/devices/or1k-softmmu/default.mak @@ -1,5 +1,7 @@ # Default configuration for or1k-softmmu +CONFIG_SEMIHOSTING=y + # Boards: # CONFIG_OR1K_SIM=y diff --git a/qemu-options.hx b/qemu-options.hx index b484640067..312c68b065 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4566,10 +4566,12 @@ ERST DEF("semihosting", 0, QEMU_OPTION_semihosting, "-semihosting semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | - QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) + QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV | + QEMU_ARCH_OPENRISC) SRST ``-semihosting`` - Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only). + Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V, + OpenRISC only). Note that this allows guest direct access to the host filesystem, so should only be used with a trusted guest OS. @@ -4581,11 +4583,12 @@ DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config, "-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \ " semihosting configuration\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | -QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) +QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV | +QEMU_ARCH_OPENRISC) SRST ``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]`` - Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V - only). + Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V, + OpenRISC only). Note that this allows guest direct access to the host filesystem, so should only be used with a trusted guest OS. @@ -4601,6 +4604,9 @@ SRST On RISC-V this implements the standard semihosting API, version 0.2. + On OpenRISC this only supports providing simulation exit and reset + facilities. + ``target=native|gdb|auto`` Defines where the semihosting calls will be addressed, to QEMU (``native``) or to GDB (``gdb``). The default is ``auto``, which diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index b9584f10d4..4617f1272b 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -407,4 +407,6 @@ void cpu_set_fpcsr(CPUOpenRISCState *env, uint32_t val); #define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_INT_0 +void do_or1k_semihosting(CPUOpenRISCState *env, uint32_t k); + #endif /* OPENRISC_CPU_H */ diff --git a/target/openrisc/helper.h b/target/openrisc/helper.h index d847814a28..2fe3e4e4ca 100644 --- a/target/openrisc/helper.h +++ b/target/openrisc/helper.h @@ -64,3 +64,4 @@ DEF_HELPER_FLAGS_1(rfe, 0, void, env) /* sys */ DEF_HELPER_FLAGS_3(mtspr, 0, void, env, tl, tl) DEF_HELPER_FLAGS_3(mfspr, TCG_CALL_NO_WG, tl, env, tl, tl) +DEF_HELPER_FLAGS_2(nop, 0, void, env, i32) diff --git a/target/openrisc/meson.build b/target/openrisc/meson.build index 84322086ec..1c1758b846 100644 --- a/target/openrisc/meson.build +++ b/target/openrisc/meson.build @@ -10,6 +10,7 @@ openrisc_ss.add(files( 'fpu_helper.c', 'gdbstub.c', 'interrupt_helper.c', + 'openrisc-semi.c', 'sys_helper.c', 'translate.c', )) diff --git a/target/openrisc/openrisc-semi.c b/target/openrisc/openrisc-semi.c new file mode 100644 index 0000000000..97d6aaacdb --- /dev/null +++ b/target/openrisc/openrisc-semi.c @@ -0,0 +1,54 @@ +/* + * OpenRISC Semihosting syscall interface. + * + * Copyright (c) 2022 Stafford Horne + * + * 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 . + */ + +#include "qemu/osdep.h" + +#include "cpu.h" +#include "exec/gdbstub.h" +#include "sysemu/runstate.h" +#include "qemu/log.h" + +#define HOSTED_EXIT 1 +#define HOSTED_RESET 13 + +static void or1k_semi_return_u32(CPUOpenRISCState *env, uint32_t ret) +{ + cpu_set_gpr(env, 11, ret); +} + +void do_or1k_semihosting(CPUOpenRISCState *env, uint32_t k) +{ + uint32_t result; + + switch (k) { + case HOSTED_EXIT: + gdb_exit(cpu_get_gpr(env, 3)); + exit(cpu_get_gpr(env, 3)); + case HOSTED_RESET: +#ifndef CONFIG_USER_ONLY + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + return; +#endif + default: + qemu_log_mask(LOG_GUEST_ERROR, "or1k-semihosting: unsupported " + "semihosting syscall %d\n", k); + result = 0; + } + or1k_semi_return_u32(env, result); +} diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 48674231e7..eb698a527e 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -314,3 +314,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, /* for rd is passed in, if rd unchanged, just keep it back. */ return rd; } + +void HELPER(nop)(CPUOpenRISCState *env, target_ulong k) +{ + do_or1k_semihosting(env, k); +} diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 7b8ad43d5f..ec7b3b46ad 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -28,6 +28,7 @@ #include "qemu/qemu-print.h" #include "exec/cpu_ldst.h" #include "exec/translator.h" +#include "semihosting/semihost.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" @@ -780,6 +781,11 @@ static bool trans_l_sh(DisasContext *dc, arg_store *a) static bool trans_l_nop(DisasContext *dc, arg_l_nop *a) { + if (semihosting_enabled() && + a->k != 0) { + gen_helper_nop(cpu_env, tcg_constant_i32(a->k)); + } + return true; } From patchwork Fri May 27 17:27:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stafford Horne X-Patchwork-Id: 12863615 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E4381C433EF for ; Fri, 27 May 2022 17:29:03 +0000 (UTC) Received: from localhost ([::1]:56114 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nudln-0005WB-3A for qemu-devel@archiver.kernel.org; Fri, 27 May 2022 13:29:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60794) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nudka-0003TE-V2 for qemu-devel@nongnu.org; Fri, 27 May 2022 13:27:49 -0400 Received: from mail-pg1-x52d.google.com ([2607:f8b0:4864:20::52d]:39910) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nudkY-0004AH-Fl for qemu-devel@nongnu.org; Fri, 27 May 2022 13:27:48 -0400 Received: by mail-pg1-x52d.google.com with SMTP id t28so4454331pga.6 for ; Fri, 27 May 2022 10:27:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=R9fEsxpNe9MAMJ+kwIPy0PaLfUO5waMOnjwlMai4hzo=; b=Asol+bbOuvDoheYbz0xneMquj36d/QZdRJg113NRqDqL2DLHJZpwrcyQgHBLa7Y146 3FYSANnofp5t9vT39/dp0Gk6BvzoxRV4m99mu84JRUwhhtxzfqrtviIQwgW6HF8q2mZB 6q4QVF2lcDnsugVuJuJ1ckWeCU7EqjZkU3ed7eR4/gGgnl6VjJgYASxyiVWs7nGi9PY/ tgYDWPPDUjhooySOB3fykuhdKttBWwi+Pf30ZPZAzbV6/sa+AuP+CZ51TSb9pqgLXw2h PgZWAMoEObfWXake+fiDo/7ytVyJcJoIIh7hdZtnzjHs1rTwSFlc3ifwYKNz1FdqVlyZ 595A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=R9fEsxpNe9MAMJ+kwIPy0PaLfUO5waMOnjwlMai4hzo=; b=R6Dgcg3H86Ybt39SSaAyRxnDFTGoeugxS//9shyYqiD9nx56udQeYXgR8JSDh0s1C9 jIHjrI4wEqSrH9bJHsbpGpWQmpn6Bw1gHNQmyfaxmfSGSK9Xgm/n7OIqlu3Hx15RuvG4 4fwsOk9oagJ4wm8IlToKwjgu3VB8CbyEANY1mt1RZpdZ24NLI1FlQ2XAbYcqbtVuClql yipIr6PlhDT87dLBzgwka3soUPXXMmnNjt4Y6Wuf+8T8neQJG2bLa8Cpufijo2KuZ4Rq x33GvgB2vQq+ZfxJSxqODwpt5ZFwEuXFVn7Mu+6VNFPkWWW+Z4InDBfcGwzBJNyqCKz3 MWTQ== X-Gm-Message-State: AOAM532pWri9w/5hv2qXlETrQ0aiO7E39bS1v+BlJKXppjSNEwLSRh0P pLUv+5AQ8J4UIZxlthDuYhyfzFnEUWwXZA== X-Google-Smtp-Source: ABdhPJw40BWHo7PH3EHHet4KPvoHKCclXDbNMW7tvZzXA3aLqe92/mQzOXVhc8yEsy0TykXVKJJ20Q== X-Received: by 2002:a63:3197:0:b0:3fb:c60e:334d with SMTP id x145-20020a633197000000b003fbc60e334dmr1325990pgx.263.1653672464607; Fri, 27 May 2022 10:27:44 -0700 (PDT) Received: from localhost ([2409:10:24a0:4700:e8ad:216a:2a9d:6d0c]) by smtp.gmail.com with ESMTPSA id i6-20020aa787c6000000b0050dc762818asm3774316pfo.100.2022.05.27.10.27.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 May 2022 10:27:44 -0700 (PDT) From: Stafford Horne To: QEMU Development Cc: Openrisc , "Jason A. Donenfeld" , Stafford Horne , Jia Liu Subject: [RFC PATCH 2/3] hw/openrisc: Split re-usable boot time apis out to boot.c Date: Sat, 28 May 2022 02:27:29 +0900 Message-Id: <20220527172731.1742837-3-shorne@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20220527172731.1742837-1-shorne@gmail.com> References: <20220527172731.1742837-1-shorne@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::52d; envelope-from=shorne@gmail.com; helo=mail-pg1-x52d.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" These will be shared with the virt platform. Signed-off-by: Stafford Horne Reviewed-by: Richard Henderson --- hw/openrisc/boot.c | 127 +++++++++++++++++++++++++++++++++++++ hw/openrisc/meson.build | 1 + hw/openrisc/openrisc_sim.c | 106 ++----------------------------- include/hw/openrisc/boot.h | 34 ++++++++++ 4 files changed, 168 insertions(+), 100 deletions(-) create mode 100644 hw/openrisc/boot.c create mode 100644 include/hw/openrisc/boot.h diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c new file mode 100644 index 0000000000..32f0925a8c --- /dev/null +++ b/hw/openrisc/boot.c @@ -0,0 +1,127 @@ +/* + * QEMU OpenRISC boot helpers. + * + * Copyright (c) 2022 Stafford Horne + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/cpu-defs.h" +#include "elf.h" +#include "hw/loader.h" +#include "hw/openrisc/boot.h" +#include "sysemu/device_tree.h" +#include "sysemu/qtest.h" + +#include + +#define KERNEL_LOAD_ADDR 0x100 + +hwaddr openrisc_load_kernel(ram_addr_t ram_size, + const char *kernel_filename, + uint32_t *bootstrap_pc) +{ + long kernel_size; + uint64_t elf_entry; + uint64_t high_addr; + hwaddr entry; + + if (kernel_filename && !qtest_enabled()) { + kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, + &elf_entry, NULL, &high_addr, NULL, 1, + EM_OPENRISC, 1, 0); + entry = elf_entry; + if (kernel_size < 0) { + kernel_size = load_uimage(kernel_filename, + &entry, NULL, NULL, NULL, NULL); + high_addr = entry + kernel_size; + } + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); + high_addr = KERNEL_LOAD_ADDR + kernel_size; + } + + if (entry <= 0) { + entry = KERNEL_LOAD_ADDR; + } + + if (kernel_size < 0) { + error_report("couldn't load the kernel '%s'", kernel_filename); + exit(1); + } + *bootstrap_pc = entry; + + return high_addr; + } + return 0; +} + +hwaddr openrisc_load_initrd(void *fdt, const char *filename, + hwaddr load_start, uint64_t mem_size) +{ + int size; + hwaddr start; + + /* We put the initrd right after the kernel; page aligned. */ + start = TARGET_PAGE_ALIGN(load_start); + + size = load_ramdisk(filename, start, mem_size - start); + if (size < 0) { + size = load_image_targphys(filename, start, mem_size - start); + if (size < 0) { + error_report("could not load ramdisk '%s'", filename); + exit(1); + } + } + + if (fdt) { + qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-start", start); + qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-end", start + size); + } + + return start + size; +} + +uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start, + uint64_t mem_size) +{ + uint32_t fdt_addr; + int ret; + int fdtsize = fdt_totalsize(fdt); + + if (fdtsize <= 0) { + error_report("invalid device-tree"); + exit(1); + } + + /* We put fdt right after the kernel and/or initrd. */ + fdt_addr = TARGET_PAGE_ALIGN(load_start); + + ret = fdt_pack(fdt); + /* Should only fail if we've built a corrupted tree */ + g_assert(ret == 0); + /* copy in the device tree */ + qemu_fdt_dumpdtb(fdt, fdtsize); + + rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, + &address_space_memory); + + return fdt_addr; +} + diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ec48172c9d..ab563820c5 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -1,5 +1,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) +openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 35adce17ac..35da123aef 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -24,10 +24,9 @@ #include "cpu.h" #include "hw/irq.h" #include "hw/boards.h" -#include "elf.h" #include "hw/char/serial.h" #include "net/net.h" -#include "hw/loader.h" +#include "hw/openrisc/boot.h" #include "hw/qdev-properties.h" #include "exec/address-spaces.h" #include "sysemu/device_tree.h" @@ -283,101 +282,6 @@ static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, g_free(nodename); } -static hwaddr openrisc_load_kernel(ram_addr_t ram_size, - const char *kernel_filename) -{ - long kernel_size; - uint64_t elf_entry; - uint64_t high_addr; - hwaddr entry; - - if (kernel_filename && !qtest_enabled()) { - kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, - &elf_entry, NULL, &high_addr, NULL, 1, - EM_OPENRISC, 1, 0); - entry = elf_entry; - if (kernel_size < 0) { - kernel_size = load_uimage(kernel_filename, - &entry, NULL, NULL, NULL, NULL); - high_addr = entry + kernel_size; - } - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, - KERNEL_LOAD_ADDR, - ram_size - KERNEL_LOAD_ADDR); - high_addr = KERNEL_LOAD_ADDR + kernel_size; - } - - if (entry <= 0) { - entry = KERNEL_LOAD_ADDR; - } - - if (kernel_size < 0) { - error_report("couldn't load the kernel '%s'", kernel_filename); - exit(1); - } - boot_info.bootstrap_pc = entry; - - return high_addr; - } - return 0; -} - -static hwaddr openrisc_load_initrd(Or1ksimState *state, const char *filename, - hwaddr load_start, uint64_t mem_size) -{ - void *fdt = state->fdt; - int size; - hwaddr start; - - /* We put the initrd right after the kernel; page aligned. */ - start = TARGET_PAGE_ALIGN(load_start); - - size = load_ramdisk(filename, start, mem_size - start); - if (size < 0) { - size = load_image_targphys(filename, start, mem_size - start); - if (size < 0) { - error_report("could not load ramdisk '%s'", filename); - exit(1); - } - } - - qemu_fdt_setprop_cell(fdt, "/chosen", - "linux,initrd-start", start); - qemu_fdt_setprop_cell(fdt, "/chosen", - "linux,initrd-end", start + size); - - return start + size; -} - -static uint32_t openrisc_load_fdt(Or1ksimState *state, hwaddr load_start, - uint64_t mem_size) -{ - void *fdt = state->fdt; - uint32_t fdt_addr; - int ret; - int fdtsize = fdt_totalsize(fdt); - - if (fdtsize <= 0) { - error_report("invalid device-tree"); - exit(1); - } - - /* We put fdt right after the kernel and/or initrd. */ - fdt_addr = TARGET_PAGE_ALIGN(load_start); - - ret = fdt_pack(fdt); - /* Should only fail if we've built a corrupted tree */ - g_assert(ret == 0); - /* copy in the device tree */ - qemu_fdt_dumpdtb(fdt, fdtsize); - - rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, - &address_space_memory); - - return fdt_addr; -} - static void openrisc_sim_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; @@ -428,13 +332,15 @@ static void openrisc_sim_init(MachineState *machine) or1ksim_memmap[OR1KSIM_UART].size, smp_cpus, cpus, OR1KSIM_UART_IRQ, n); - load_addr = openrisc_load_kernel(ram_size, kernel_filename); + load_addr = openrisc_load_kernel(ram_size, kernel_filename, + &boot_info.bootstrap_pc); if (load_addr > 0) { if (machine->initrd_filename) { - load_addr = openrisc_load_initrd(state, machine->initrd_filename, + load_addr = openrisc_load_initrd(state->fdt, + machine->initrd_filename, load_addr, machine->ram_size); } - boot_info.fdt_addr = openrisc_load_fdt(state, load_addr, + boot_info.fdt_addr = openrisc_load_fdt(state->fdt, load_addr, machine->ram_size); } } diff --git a/include/hw/openrisc/boot.h b/include/hw/openrisc/boot.h new file mode 100644 index 0000000000..25a313d63a --- /dev/null +++ b/include/hw/openrisc/boot.h @@ -0,0 +1,34 @@ +/* + * QEMU OpenRISC boot helpers. + * + * Copyright (c) 2022 Stafford Horne + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#ifndef OPENRISC_BOOT_H +#define OPENRISC_BOOT_H + +#include "exec/cpu-defs.h" + +hwaddr openrisc_load_kernel(ram_addr_t ram_size, + const char *kernel_filename, + uint32_t *bootstrap_pc); + +hwaddr openrisc_load_initrd(void *fdt, const char *filename, + hwaddr load_start, uint64_t mem_size); + +uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start, + uint64_t mem_size); + +#endif /* OPENRISC_BOOT_H */ From patchwork Fri May 27 17:27:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stafford Horne X-Patchwork-Id: 12863616 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id DB9C8C433EF for ; Fri, 27 May 2022 17:30:39 +0000 (UTC) Received: from localhost ([::1]:60542 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nudnK-0008TY-W3 for qemu-devel@archiver.kernel.org; Fri, 27 May 2022 13:30:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60808) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nudke-0003b5-I3 for qemu-devel@nongnu.org; Fri, 27 May 2022 13:27:53 -0400 Received: from mail-pl1-x635.google.com ([2607:f8b0:4864:20::635]:43808) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nudkb-0004AR-Ue for qemu-devel@nongnu.org; Fri, 27 May 2022 13:27:52 -0400 Received: by mail-pl1-x635.google.com with SMTP id b5so4678987plx.10 for ; Fri, 27 May 2022 10:27:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=hr9iiUiTeCACXFBySPfQdUnzrIKXXLExVfrLvDY1roQ=; b=TnweG+1zbX6I67W93Hg19A0oy3AkfriBi2EJwz/dlan0x70ZJuOjzwlpjd5Aa2EkQr WlBA+HUeTpo2FNFvyWa3+SQpXW0CewTlnU3CUKaquCdNKz/DJs/GxZBOuWCC+FdvZiRr S5AruSvIXNx+BfUV5lYFCEePy2A08QS02Mvq+i3v4NkpIO5+upd1s5yCJlGyrCfRkdtG t/3Q83Lh4uv8jezxRUI40rP9FCFulkA7ExsCHZb8jvdI1CT9KwB/tSWy14O2rhpqO8PL h8orW0M8NdN7nXh9F0l2DDVz+39YcoLUY0FLmeckE1cYE4cgnczUfR+yY3gEjcFlMKVE fztA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=hr9iiUiTeCACXFBySPfQdUnzrIKXXLExVfrLvDY1roQ=; b=FSideLoVe0kdtPJpuPLRy+J2Ua/4SHU8FAQ67buqxYgWaBpvaNFRCDVRh/OQKw2ONv lgKjVGeB50ArK2Z+r0INJTaZYG/fngiMqt94MxSG8IrMYm0OrVbe5V2RhapwCeZj2VNj xCv6fZmEyQX2qgivUAJtQfxcDzaA/XGVfX+3LvQaUjSKCcNlxJJZshR25EYduKYAKf23 rP+1GLEnZUPVwq+FYhVi58MO7f1m90WsPUMDhdqs2Ft1pUODzWjB8Z01Ewg/PgnxCt13 yGIDDpsN5bauXd1vb0PpFTUzQ3mfmjv2rtTNoGwJzeBmlMLSK6jlN4FX1vdHs9KIx0dG kYZA== X-Gm-Message-State: AOAM531NacuTC5z/t/Oh1eA/lDaqzkUwOAjpu3sVPw+zZqoj31EzHKOk dZPLtj1mfoNpIe7xcCbCl5aW3moACIumqg== X-Google-Smtp-Source: ABdhPJy4EFvALp3j1DaBIRoPjea2X1BIvfmED+oCQMvhYMuvG9w3PRJ+VFf3HgjJC0pZvw8jGXK4sA== X-Received: by 2002:a17:903:2305:b0:163:64c7:f9ff with SMTP id d5-20020a170903230500b0016364c7f9ffmr12885222plh.46.1653672467010; Fri, 27 May 2022 10:27:47 -0700 (PDT) Received: from localhost ([2409:10:24a0:4700:e8ad:216a:2a9d:6d0c]) by smtp.gmail.com with ESMTPSA id z12-20020aa785cc000000b0050dc762818bsm3758214pfn.101.2022.05.27.10.27.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 May 2022 10:27:46 -0700 (PDT) From: Stafford Horne To: QEMU Development Cc: Openrisc , "Jason A. Donenfeld" , Stafford Horne Subject: [RFC PATCH 3/3] hw/openrisc: Add the OpenRISC virtual machine Date: Sat, 28 May 2022 02:27:30 +0900 Message-Id: <20220527172731.1742837-4-shorne@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20220527172731.1742837-1-shorne@gmail.com> References: <20220527172731.1742837-1-shorne@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::635; envelope-from=shorne@gmail.com; helo=mail-pl1-x635.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch add the OpenRISC virtual machine 'virt' for OpenRISC. This platform allows for a convenient CI platform for toolchain, software ports and the OpenRISC linux kernel port. Much of this has been sourced from the m68k and riscv virt platforms. The platform provides: - OpenRISC SMP with up to 8 cpus - A virtio bus with up to 8 devices - Standard ns16550a serial - Goldfish RTC - SiFive TEST device for poweroff and reboot - Generated RTC to automatically configure the guest kernel Signed-off-by: Stafford Horne --- configs/devices/or1k-softmmu/default.mak | 1 + hw/openrisc/Kconfig | 9 + hw/openrisc/meson.build | 1 + hw/openrisc/virt.c | 429 +++++++++++++++++++++++ 4 files changed, 440 insertions(+) create mode 100644 hw/openrisc/virt.c diff --git a/configs/devices/or1k-softmmu/default.mak b/configs/devices/or1k-softmmu/default.mak index 5b3ac89491..f3bf816067 100644 --- a/configs/devices/or1k-softmmu/default.mak +++ b/configs/devices/or1k-softmmu/default.mak @@ -5,3 +5,4 @@ CONFIG_SEMIHOSTING=y # Boards: # CONFIG_OR1K_SIM=y +CONFIG_OR1K_VIRT=y diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 8f284f3ba0..202134668e 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -4,3 +4,12 @@ config OR1K_SIM select OPENCORES_ETH select OMPIC select SPLIT_IRQ + +config OR1K_VIRT + bool + imply VIRTIO_VGA + imply TEST_DEVICES + select GOLDFISH_RTC + select SERIAL + select SIFIVE_TEST + select VIRTIO_MMIO diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ab563820c5..2dbc6365bb 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -2,5 +2,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) +openrisc_ss.add(when: 'CONFIG_OR1K_VIRT', if_true: [files('virt.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c new file mode 100644 index 0000000000..147196fda3 --- /dev/null +++ b/hw/openrisc/virt.c @@ -0,0 +1,429 @@ +/* + * OpenRISC QEMU virtual machine. + * + * Copyright (c) 2022 Stafford Horne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "cpu.h" +#include "hw/irq.h" +#include "hw/boards.h" +#include "hw/char/serial.h" +#include "hw/openrisc/boot.h" +#include "hw/misc/sifive_test.h" +#include "hw/qdev-properties.h" +#include "exec/address-spaces.h" +#include "sysemu/device_tree.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" +#include "sysemu/qtest.h" +#include "sysemu/reset.h" +#include "hw/core/split-irq.h" + +#include + +#define VIRT_CPUS_MAX 4 +#define VIRT_CLK_MHZ 20000000 + +#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") +#define VIRT_MACHINE(obj) \ + OBJECT_CHECK(OR1KVirtState, (obj), TYPE_VIRT_MACHINE) + +typedef struct OR1KVirtState { + /*< private >*/ + MachineState parent_obj; + + /*< public >*/ + void *fdt; + int fdt_size; + +} OR1KVirtState; + +enum { + VIRT_DRAM, + VIRT_TEST, + VIRT_RTC, + VIRT_VIRTIO, + VIRT_UART, + VIRT_OMPIC, +}; + +enum { + VIRT_OMPIC_IRQ = 1, + VIRT_UART_IRQ = 2, + VIRT_RTC_IRQ = 3, + VIRT_VIRTIO_IRQ = 4, /* to 12 */ + VIRTIO_COUNT = 8, +}; + +static const struct MemmapEntry { + hwaddr base; + hwaddr size; +} virt_memmap[] = { + [VIRT_DRAM] = { 0x00000000, 0 }, + [VIRT_UART] = { 0x90000000, 0x100 }, + [VIRT_TEST] = { 0x96000000, 0x8 }, + [VIRT_RTC] = { 0x96005000, 0x1000 }, + [VIRT_VIRTIO] = { 0x97000000, 0x1000 }, + [VIRT_OMPIC] = { 0x98000000, VIRT_CPUS_MAX * 8 }, +}; + +static struct openrisc_boot_info { + uint32_t bootstrap_pc; + uint32_t fdt_addr; +} boot_info; + +static void main_cpu_reset(void *opaque) +{ + OpenRISCCPU *cpu = opaque; + CPUState *cs = CPU(cpu); + + cpu_reset(CPU(cpu)); + + cpu_set_pc(cs, boot_info.bootstrap_pc); + cpu_set_gpr(&cpu->env, 3, boot_info.fdt_addr); +} + +static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) +{ + return qdev_get_gpio_in_named(DEVICE(cpus[cpunum]), "IRQ", irq_pin); +} + +static qemu_irq get_per_cpu_irq(OpenRISCCPU *cpus[], int num_cpus, int irq_pin) +{ + int i; + + if (num_cpus > 1) { + DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ); + qdev_prop_set_uint32(splitter, "num-lines", num_cpus); + qdev_realize_and_unref(splitter, NULL, &error_fatal); + for (i = 0; i < num_cpus; i++) { + qdev_connect_gpio_out(splitter, i, get_cpu_irq(cpus, i, irq_pin)); + } + return qdev_get_gpio_in(splitter, 0); + } else { + return get_cpu_irq(cpus, 0, irq_pin); + } +} + +static void openrisc_create_fdt(OR1KVirtState *state, + const struct MemmapEntry *memmap, + int num_cpus, uint64_t mem_size, + const char *cmdline) +{ + void *fdt; + int cpu; + char *nodename; + int pic_ph; + + fdt = state->fdt = create_device_tree(&state->fdt_size); + if (!fdt) { + error_report("create_device_tree() failed"); + exit(1); + } + + qemu_fdt_setprop_string(fdt, "/", "compatible", "opencores,or1ksim"); + qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x1); + qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x1); + + qemu_fdt_add_subnode(fdt, "/soc"); + qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0); + qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus"); + qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x1); + qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x1); + + nodename = g_strdup_printf("/memory@%" HWADDR_PRIx, + memmap[VIRT_DRAM].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + memmap[VIRT_DRAM].base, mem_size); + qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory"); + g_free(nodename); + + qemu_fdt_add_subnode(fdt, "/cpus"); + qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0); + qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1); + + for (cpu = 0; cpu < num_cpus; cpu++) { + nodename = g_strdup_printf("/cpus/cpu@%d", cpu); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", + "opencores,or1200-rtlsvn481"); + qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu); + qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", + VIRT_CLK_MHZ); + g_free(nodename); + } + + nodename = (char *)"/pic"; + qemu_fdt_add_subnode(fdt, nodename); + pic_ph = qemu_fdt_alloc_phandle(fdt); + qemu_fdt_setprop_string(fdt, nodename, "compatible", + "opencores,or1k-pic-level"); + qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1); + qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", pic_ph); + + qemu_fdt_setprop_cell(fdt, "/", "interrupt-parent", pic_ph); + + qemu_fdt_add_subnode(fdt, "/chosen"); + if (cmdline) { + qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); + } + + /* Create aliases node for use by devices. */ + qemu_fdt_add_subnode(fdt, "/aliases"); +} + +static void openrisc_virt_ompic_init(OR1KVirtState *state, hwaddr base, + hwaddr size, int num_cpus, + OpenRISCCPU *cpus[], int irq_pin) +{ + void *fdt = state->fdt; + DeviceState *dev; + SysBusDevice *s; + char *nodename; + int i; + + dev = qdev_new("or1k-ompic"); + qdev_prop_set_uint32(dev, "num-cpus", num_cpus); + + s = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(s, &error_fatal); + for (i = 0; i < num_cpus; i++) { + sysbus_connect_irq(s, i, get_cpu_irq(cpus, i, irq_pin)); + } + sysbus_mmio_map(s, 0, base); + + /* Add device tree node for ompic. */ + nodename = g_strdup_printf("/ompic@%" HWADDR_PRIx, base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "openrisc,ompic"); + qemu_fdt_setprop_cells(fdt, nodename, "reg", base, size); + qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 0); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", irq_pin); + g_free(nodename); +} + +static void openrisc_virt_serial_init(OR1KVirtState *state, hwaddr base, + hwaddr size, int num_cpus, + OpenRISCCPU *cpus[], int irq_pin) +{ + void *fdt = state->fdt; + char *nodename; + qemu_irq serial_irq = get_per_cpu_irq(cpus, num_cpus, irq_pin); + + serial_mm_init(get_system_memory(), base, 0, serial_irq, 115200, + serial_hd(0), DEVICE_NATIVE_ENDIAN); + + /* Add device tree node for serial. */ + nodename = g_strdup_printf("/serial@%" HWADDR_PRIx, base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "ns16550a"); + qemu_fdt_setprop_cells(fdt, nodename, "reg", base, size); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", irq_pin); + qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", VIRT_CLK_MHZ); + qemu_fdt_setprop(fdt, nodename, "big-endian", NULL, 0); + + /* The /chosen node is created during fdt creation. */ + qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename); + qemu_fdt_setprop_string(fdt, "/aliases", "uart0", nodename); + g_free(nodename); +} + +static void openrisc_virt_test_init(OR1KVirtState *state, hwaddr base, + hwaddr size) +{ + void *fdt = state->fdt; + int test_ph; + char *nodename; + + /* SiFive Test MMIO device */ + sifive_test_create(base); + + /* SiFive Test MMIO Reset device FDT */ + nodename = g_strdup_printf("/soc/test@%" HWADDR_PRIx, base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "syscon"); + test_ph = qemu_fdt_alloc_phandle(fdt); + qemu_fdt_setprop_cells(fdt, nodename, "reg", base, size); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", test_ph); + qemu_fdt_setprop(fdt, nodename, "big-endian", NULL, 0); + g_free(nodename); + + nodename = g_strdup_printf("/soc/reboot"); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "syscon-reboot"); + qemu_fdt_setprop_cell(fdt, nodename, "regmap", test_ph); + qemu_fdt_setprop_cell(fdt, nodename, "offset", 0x0); + qemu_fdt_setprop_cell(fdt, nodename, "value", FINISHER_RESET); + g_free(nodename); + + nodename = g_strdup_printf("/soc/poweroff"); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "syscon-poweroff"); + qemu_fdt_setprop_cell(fdt, nodename, "regmap", test_ph); + qemu_fdt_setprop_cell(fdt, nodename, "offset", 0x0); + qemu_fdt_setprop_cell(fdt, nodename, "value", FINISHER_PASS); + g_free(nodename); + +} +static void openrisc_virt_rtc_init(OR1KVirtState *state, hwaddr base, + hwaddr size, int num_cpus, + OpenRISCCPU *cpus[], int irq_pin) +{ + void *fdt = state->fdt; + char *nodename; + qemu_irq rtc_irq = get_per_cpu_irq(cpus, num_cpus, irq_pin); + + /* Goldfish RTC */ + sysbus_create_simple("goldfish_rtc", base, rtc_irq); + + /* Goldfish RTC FDT */ + nodename = g_strdup_printf("/soc/rtc@%" HWADDR_PRIx, base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", + "google,goldfish-rtc"); + qemu_fdt_setprop_cells(fdt, nodename, "reg", base, size); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", irq_pin); + g_free(nodename); + +} +static void openrisc_virt_virtio_init(OR1KVirtState *state, hwaddr base, + hwaddr size, int num_cpus, + OpenRISCCPU *cpus[], int irq_pin, + int virtio_idx) +{ + void *fdt = state->fdt; + char *nodename; + DeviceState *dev; + SysBusDevice *sysbus; + qemu_irq virtio_irq = get_per_cpu_irq(cpus, num_cpus, irq_pin + virtio_idx); + + /* VirtIO MMIO devices */ + dev = qdev_new("virtio-mmio"); + qdev_prop_set_bit(dev, "force-legacy", false); + sysbus = SYS_BUS_DEVICE(dev); + sysbus_realize_and_unref(sysbus, &error_fatal); + sysbus_connect_irq(sysbus, 0, virtio_irq); + sysbus_mmio_map(sysbus, 0, base + virtio_idx * size); + + /* VirtIO MMIO devices FDT */ + nodename = g_strdup_printf("/soc/virtio_mmio@%" HWADDR_PRIx, + base + virtio_idx * size); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "virtio,mmio"); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + base + virtio_idx * size, + size); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", irq_pin + virtio_idx); + g_free(nodename); +} + +static void openrisc_virt_init(MachineState *machine) +{ + ram_addr_t ram_size = machine->ram_size; + const char *kernel_filename = machine->kernel_filename; + OpenRISCCPU *cpus[VIRT_CPUS_MAX] = {}; + OR1KVirtState *state = VIRT_MACHINE(machine); + MemoryRegion *ram; + hwaddr load_addr; + int n; + unsigned int smp_cpus = machine->smp.cpus; + + assert(smp_cpus >= 1 && smp_cpus <= VIRT_CPUS_MAX); + for (n = 0; n < smp_cpus; n++) { + cpus[n] = OPENRISC_CPU(cpu_create(machine->cpu_type)); + if (cpus[n] == NULL) { + fprintf(stderr, "Unable to find CPU definition!\n"); + exit(1); + } + + cpu_openrisc_clock_init(cpus[n]); + + qemu_register_reset(main_cpu_reset, cpus[n]); + } + + ram = g_malloc(sizeof(*ram)); + memory_region_init_ram(ram, NULL, "openrisc.ram", ram_size, &error_fatal); + memory_region_add_subregion(get_system_memory(), 0, ram); + + openrisc_create_fdt(state, virt_memmap, smp_cpus, machine->ram_size, + machine->kernel_cmdline); + + if (smp_cpus > 1) { + openrisc_virt_ompic_init(state, virt_memmap[VIRT_OMPIC].base, + virt_memmap[VIRT_OMPIC].size, + smp_cpus, cpus, VIRT_OMPIC_IRQ); + } + + openrisc_virt_serial_init(state, virt_memmap[VIRT_UART].base, + virt_memmap[VIRT_UART].size, + smp_cpus, cpus, VIRT_UART_IRQ); + + openrisc_virt_test_init(state, virt_memmap[VIRT_TEST].base, + virt_memmap[VIRT_TEST].size); + + openrisc_virt_rtc_init(state, virt_memmap[VIRT_RTC].base, + virt_memmap[VIRT_RTC].size, smp_cpus, cpus, + VIRT_RTC_IRQ); + + for (n = 0; n < VIRTIO_COUNT; n++) { + openrisc_virt_virtio_init(state, virt_memmap[VIRT_VIRTIO].base, + virt_memmap[VIRT_VIRTIO].size, + smp_cpus, cpus, VIRT_VIRTIO_IRQ, n); + } + + load_addr = openrisc_load_kernel(ram_size, kernel_filename, + &boot_info.bootstrap_pc); + if (load_addr > 0) { + if (machine->initrd_filename) { + load_addr = openrisc_load_initrd(state->fdt, + machine->initrd_filename, + load_addr, machine->ram_size); + } + boot_info.fdt_addr = openrisc_load_fdt(state->fdt, load_addr, + machine->ram_size); + } +} + +static void openrisc_virt_machine_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "or1k virtual machine"; + mc->init = openrisc_virt_init; + mc->max_cpus = VIRT_CPUS_MAX; + mc->is_default = false; + mc->default_cpu_type = OPENRISC_CPU_TYPE_NAME("or1200"); +} + +static const TypeInfo or1ksim_machine_typeinfo = { + .name = TYPE_VIRT_MACHINE, + .parent = TYPE_MACHINE, + .class_init = openrisc_virt_machine_init, + .instance_size = sizeof(OR1KVirtState), +}; + +static void or1ksim_machine_init_register_types(void) +{ + type_register_static(&or1ksim_machine_typeinfo); +} + +type_init(or1ksim_machine_init_register_types)