Re: [PATCH] targer/riscv: Implement Zabha extension
Hi Zhiwei, On Tue, May 28, 2024 at 8:57 AM LIU Zhiwei wrote: > > Hi Alexandre, > > I have sent the patch set about Zabha before last week. Sorry I did not check! > > https://lore.kernel.org/all/fed99165-58da-458c-b68f-a9717fc15...@linux.alibaba.com/T/ > > Welcome to review it and give comments. Sure, I'll do that, your patchset seems more complete than ours. Thanks, Alex > > Thanks, > Zhiwei > > On 2024/5/28 13:45, Alexandre Ghiti wrote: > > From: Gianluca Guida > > > > Add Zabha implementation. > > > > Signed-off-by: Gianluca Guida > > Signed-off-by: Alexandre Ghiti > > --- > > target/riscv/cpu.c | 2 + > > target/riscv/cpu_cfg.h | 1 + > > target/riscv/insn32.decode | 22 +++ > > target/riscv/insn_trans/trans_rvzabha.c.inc | 149 > > target/riscv/tcg/tcg-cpu.c | 5 + > > target/riscv/translate.c| 1 + > > 6 files changed, 180 insertions(+) > > create mode 100644 target/riscv/insn_trans/trans_rvzabha.c.inc > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index 70d1a527a1..b01f82002b 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -116,6 +116,7 @@ const RISCVIsaExtData isa_edata_arr[] = { > > ISA_EXT_DATA_ENTRY(zmmul, PRIV_VERSION_1_12_0, ext_zmmul), > > ISA_EXT_DATA_ENTRY(za64rs, PRIV_VERSION_1_12_0, has_priv_1_11), > > ISA_EXT_DATA_ENTRY(zaamo, PRIV_VERSION_1_12_0, ext_zaamo), > > +ISA_EXT_DATA_ENTRY(zabha, PRIV_VERSION_1_12_0, ext_zabha), > > ISA_EXT_DATA_ENTRY(zacas, PRIV_VERSION_1_12_0, ext_zacas), > > ISA_EXT_DATA_ENTRY(zalrsc, PRIV_VERSION_1_12_0, ext_zalrsc), > > ISA_EXT_DATA_ENTRY(zawrs, PRIV_VERSION_1_12_0, ext_zawrs), > > @@ -1464,6 +1465,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = > > { > > MULTI_EXT_CFG_BOOL("zicsr", ext_zicsr, true), > > MULTI_EXT_CFG_BOOL("zihintntl", ext_zihintntl, true), > > MULTI_EXT_CFG_BOOL("zihintpause", ext_zihintpause, true), > > +MULTI_EXT_CFG_BOOL("zabha", ext_zabha, false), > > MULTI_EXT_CFG_BOOL("zacas", ext_zacas, false), > > MULTI_EXT_CFG_BOOL("zaamo", ext_zaamo, false), > > MULTI_EXT_CFG_BOOL("zalrsc", ext_zalrsc, false), > > diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h > > index d36c416ef0..7f614da4e2 100644 > > --- a/target/riscv/cpu_cfg.h > > +++ b/target/riscv/cpu_cfg.h > > @@ -81,6 +81,7 @@ struct RISCVCPUConfig { > > bool ext_svvptc; > > bool ext_zdinx; > > bool ext_zaamo; > > +bool ext_zabha; > > bool ext_zacas; > > bool ext_zalrsc; > > bool ext_zawrs; > > diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode > > index f22df04cfd..6d7726120f 100644 > > --- a/target/riscv/insn32.decode > > +++ b/target/riscv/insn32.decode > > @@ -1010,3 +1010,25 @@ amocas_w00101 . . . . 010 . 010 > > @atom_st > > amocas_d00101 . . . . 011 . 010 @atom_st > > # *** RV64 Zacas Standard Extension *** > > amocas_q00101 . . . . 100 . 010 @atom_st > > + > > +# *** Zabha Standard Extension *** > > +amoswap_b 1 . . . . 000 . 010 @atom_st > > +amoadd_b 0 . . . . 000 . 010 @atom_st > > +amoxor_b 00100 . . . . 000 . 010 @atom_st > > +amoand_b 01100 . . . . 000 . 010 @atom_st > > +amoor_b01000 . . . . 000 . 010 @atom_st > > +amomin_b 1 . . . . 000 . 010 @atom_st > > +amomax_b 10100 . . . . 000 . 010 @atom_st > > +amominu_b 11000 . . . . 000 . 010 @atom_st > > +amomaxu_b 11100 . . . . 000 . 010 @atom_st > > +amocas_b 00101 . . . . 000 . 010 @atom_st > > +amoswap_h 1 . . . . 001 . 010 @atom_st > > +amoadd_h 0 . . . . 001 . 010 @atom_st > > +amoxor_h 00100 . . . . 001 . 010 @atom_st > > +amoand_h 01100 . . . . 001 . 010 @atom_st > > +amoor_h01000 . . . . 001 . 010 @atom_st > > +amomin_h 1 . . . . 001 . 010 @atom_st > > +amomax_h 10100 . . . . 001 . 010 @atom_st > > +amominu_h 11000 . . . . 001 . 010 @atom_st > > +amomaxu_h 11100 . . . . 001
[PATCH] targer/riscv: Implement Zabha extension
From: Gianluca Guida Add Zabha implementation. Signed-off-by: Gianluca Guida Signed-off-by: Alexandre Ghiti --- target/riscv/cpu.c | 2 + target/riscv/cpu_cfg.h | 1 + target/riscv/insn32.decode | 22 +++ target/riscv/insn_trans/trans_rvzabha.c.inc | 149 target/riscv/tcg/tcg-cpu.c | 5 + target/riscv/translate.c| 1 + 6 files changed, 180 insertions(+) create mode 100644 target/riscv/insn_trans/trans_rvzabha.c.inc diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 70d1a527a1..b01f82002b 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -116,6 +116,7 @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zmmul, PRIV_VERSION_1_12_0, ext_zmmul), ISA_EXT_DATA_ENTRY(za64rs, PRIV_VERSION_1_12_0, has_priv_1_11), ISA_EXT_DATA_ENTRY(zaamo, PRIV_VERSION_1_12_0, ext_zaamo), +ISA_EXT_DATA_ENTRY(zabha, PRIV_VERSION_1_12_0, ext_zabha), ISA_EXT_DATA_ENTRY(zacas, PRIV_VERSION_1_12_0, ext_zacas), ISA_EXT_DATA_ENTRY(zalrsc, PRIV_VERSION_1_12_0, ext_zalrsc), ISA_EXT_DATA_ENTRY(zawrs, PRIV_VERSION_1_12_0, ext_zawrs), @@ -1464,6 +1465,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zicsr", ext_zicsr, true), MULTI_EXT_CFG_BOOL("zihintntl", ext_zihintntl, true), MULTI_EXT_CFG_BOOL("zihintpause", ext_zihintpause, true), +MULTI_EXT_CFG_BOOL("zabha", ext_zabha, false), MULTI_EXT_CFG_BOOL("zacas", ext_zacas, false), MULTI_EXT_CFG_BOOL("zaamo", ext_zaamo, false), MULTI_EXT_CFG_BOOL("zalrsc", ext_zalrsc, false), diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index d36c416ef0..7f614da4e2 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -81,6 +81,7 @@ struct RISCVCPUConfig { bool ext_svvptc; bool ext_zdinx; bool ext_zaamo; +bool ext_zabha; bool ext_zacas; bool ext_zalrsc; bool ext_zawrs; diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index f22df04cfd..6d7726120f 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -1010,3 +1010,25 @@ amocas_w00101 . . . . 010 . 010 @atom_st amocas_d00101 . . . . 011 . 010 @atom_st # *** RV64 Zacas Standard Extension *** amocas_q00101 . . . . 100 . 010 @atom_st + +# *** Zabha Standard Extension *** +amoswap_b 1 . . . . 000 . 010 @atom_st +amoadd_b 0 . . . . 000 . 010 @atom_st +amoxor_b 00100 . . . . 000 . 010 @atom_st +amoand_b 01100 . . . . 000 . 010 @atom_st +amoor_b01000 . . . . 000 . 010 @atom_st +amomin_b 1 . . . . 000 . 010 @atom_st +amomax_b 10100 . . . . 000 . 010 @atom_st +amominu_b 11000 . . . . 000 . 010 @atom_st +amomaxu_b 11100 . . . . 000 . 010 @atom_st +amocas_b 00101 . . . . 000 . 010 @atom_st +amoswap_h 1 . . . . 001 . 010 @atom_st +amoadd_h 0 . . . . 001 . 010 @atom_st +amoxor_h 00100 . . . . 001 . 010 @atom_st +amoand_h 01100 . . . . 001 . 010 @atom_st +amoor_h01000 . . . . 001 . 010 @atom_st +amomin_h 1 . . . . 001 . 010 @atom_st +amomax_h 10100 . . . . 001 . 010 @atom_st +amominu_h 11000 . . . . 001 . 010 @atom_st +amomaxu_h 11100 . . . . 001 . 010 @atom_st +amocas_h 00101 . . . . 001 . 010 @atom_st diff --git a/target/riscv/insn_trans/trans_rvzabha.c.inc b/target/riscv/insn_trans/trans_rvzabha.c.inc new file mode 100644 index 00..74f43bb95a --- /dev/null +++ b/target/riscv/insn_trans/trans_rvzabha.c.inc @@ -0,0 +1,149 @@ +/* + * RISC-V translation routines for the Zabha Standard Extension. + * + * Copyright (c) 2023 Rivos Inc. + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#define REQUIRE_ZABHA(ctx) do { \ +if (!ctx->cfg_ptr->ext_zabha) { \ +return false; \ +} \ +} while (0) + +#define REQUIRE_ZA
Re: [PATCH RFC] target: riscv: Add Svvptc extension support
Hi Andrew, Sorry for the very late reply, I was (and still am) off! On Tue, Feb 13, 2024 at 4:33 PM Andrew Jones wrote: > > On Tue, Feb 13, 2024 at 03:53:08PM +0100, Alexandre Ghiti wrote: > > The Svvptc extension describes a uarch that does not cache invalid TLB > > entries: that's the case for qemu so there is nothing particular to > > implement other than the introduction of this extension, which is done > > here. > > > > Signed-off-by: Alexandre Ghiti > > --- > > > > That's an RFC since the extension has not been ratified yet. > > Hi Alex, > > No need for the RFC tag. You can add not-yet-ratified extension support > to QEMU as long as the CPU property is off by default (as you've done) > and you add it to the riscv_cpu_experimental_exts[] array with an "x-" > prefix on its property name. > I'll do that next week then, Thanks, Alex > Thanks, > drew > > > > > target/riscv/cpu.c | 2 ++ > > target/riscv/cpu_cfg.h | 1 + > > 2 files changed, 3 insertions(+) > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index 1b8d001d23..4beb5d0350 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -178,6 +178,7 @@ const RISCVIsaExtData isa_edata_arr[] = { > > ISA_EXT_DATA_ENTRY(svinval, PRIV_VERSION_1_12_0, ext_svinval), > > ISA_EXT_DATA_ENTRY(svnapot, PRIV_VERSION_1_12_0, ext_svnapot), > > ISA_EXT_DATA_ENTRY(svpbmt, PRIV_VERSION_1_12_0, ext_svpbmt), > > +ISA_EXT_DATA_ENTRY(svvptc, PRIV_VERSION_1_12_0, ext_svvptc), > > ISA_EXT_DATA_ENTRY(xtheadba, PRIV_VERSION_1_11_0, ext_xtheadba), > > ISA_EXT_DATA_ENTRY(xtheadbb, PRIV_VERSION_1_11_0, ext_xtheadbb), > > ISA_EXT_DATA_ENTRY(xtheadbs, PRIV_VERSION_1_11_0, ext_xtheadbs), > > @@ -1467,6 +1468,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = > > { > > MULTI_EXT_CFG_BOOL("svinval", ext_svinval, false), > > MULTI_EXT_CFG_BOOL("svnapot", ext_svnapot, false), > > MULTI_EXT_CFG_BOOL("svpbmt", ext_svpbmt, false), > > +MULTI_EXT_CFG_BOOL("svvptc", ext_svvptc, false), > > > > MULTI_EXT_CFG_BOOL("zicntr", ext_zicntr, true), > > MULTI_EXT_CFG_BOOL("zihpm", ext_zihpm, true), > > diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h > > index 833bf58217..c973693b6e 100644 > > --- a/target/riscv/cpu_cfg.h > > +++ b/target/riscv/cpu_cfg.h > > @@ -77,6 +77,7 @@ struct RISCVCPUConfig { > > bool ext_svinval; > > bool ext_svnapot; > > bool ext_svpbmt; > > +bool ext_svvptc; > > bool ext_zdinx; > > bool ext_zaamo; > > bool ext_zacas; > > -- > > 2.39.2 > > > >
[PATCH RFC] target: riscv: Add Svvptc extension support
The Svvptc extension describes a uarch that does not cache invalid TLB entries: that's the case for qemu so there is nothing particular to implement other than the introduction of this extension, which is done here. Signed-off-by: Alexandre Ghiti --- That's an RFC since the extension has not been ratified yet. target/riscv/cpu.c | 2 ++ target/riscv/cpu_cfg.h | 1 + 2 files changed, 3 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 1b8d001d23..4beb5d0350 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -178,6 +178,7 @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(svinval, PRIV_VERSION_1_12_0, ext_svinval), ISA_EXT_DATA_ENTRY(svnapot, PRIV_VERSION_1_12_0, ext_svnapot), ISA_EXT_DATA_ENTRY(svpbmt, PRIV_VERSION_1_12_0, ext_svpbmt), +ISA_EXT_DATA_ENTRY(svvptc, PRIV_VERSION_1_12_0, ext_svvptc), ISA_EXT_DATA_ENTRY(xtheadba, PRIV_VERSION_1_11_0, ext_xtheadba), ISA_EXT_DATA_ENTRY(xtheadbb, PRIV_VERSION_1_11_0, ext_xtheadbb), ISA_EXT_DATA_ENTRY(xtheadbs, PRIV_VERSION_1_11_0, ext_xtheadbs), @@ -1467,6 +1468,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("svinval", ext_svinval, false), MULTI_EXT_CFG_BOOL("svnapot", ext_svnapot, false), MULTI_EXT_CFG_BOOL("svpbmt", ext_svpbmt, false), +MULTI_EXT_CFG_BOOL("svvptc", ext_svvptc, false), MULTI_EXT_CFG_BOOL("zicntr", ext_zicntr, true), MULTI_EXT_CFG_BOOL("zihpm", ext_zihpm, true), diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index 833bf58217..c973693b6e 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -77,6 +77,7 @@ struct RISCVCPUConfig { bool ext_svinval; bool ext_svnapot; bool ext_svpbmt; +bool ext_svvptc; bool ext_zdinx; bool ext_zaamo; bool ext_zacas; -- 2.39.2
Re: [PATCH v2] hw: riscv: Allow large kernels to boot by moving the initrd further away in RAM
On Tue, Feb 6, 2024 at 9:39 PM Daniel Henrique Barboza wrote: > > > > On 2/6/24 12:40, Alexandre Ghiti wrote: > > Currently, the initrd is placed at 128MB, which overlaps with the kernel > > when it is large (for example syzbot kernels are). From the kernel side, > > there is no reason we could not push the initrd further away in memory > > to accommodate large kernels, so move the initrd at 512MB when possible. > > > > The ideal solution would have been to place the initrd based on the > > kernel size but we actually can't since the bss size is not known when > > the image is loaded by load_image_targphys_as() and the initrd would > > then overlap with this section. > > > > Signed-off-by: Alexandre Ghiti > > --- > > Reviewed-by: Daniel Henrique Barboza Thanks for your help! Alex > > > > > Changes in v2: > > - Fix typos in commit log (Daniel) and title > > - Added to the commit log why using the kernel size does not work > >(Daniel) > > > > hw/riscv/boot.c | 12 ++-- > > 1 file changed, 6 insertions(+), 6 deletions(-) > > > > diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c > > index 0ffca05189..9a367af2fa 100644 > > --- a/hw/riscv/boot.c > > +++ b/hw/riscv/boot.c > > @@ -188,13 +188,13 @@ static void riscv_load_initrd(MachineState *machine, > > uint64_t kernel_entry) > >* kernel is uncompressed it will not clobber the initrd. However > >* on boards without much RAM we must ensure that we still leave > >* enough room for a decent sized initrd, and on boards with large > > - * amounts of RAM we must avoid the initrd being so far up in RAM > > - * that it is outside lowmem and inaccessible to the kernel. > > - * So for boards with less than 256MB of RAM we put the initrd > > - * halfway into RAM, and for boards with 256MB of RAM or more we put > > - * the initrd at 128MB. > > + * amounts of RAM, we put the initrd at 512MB to allow large kernels > > + * to boot. > > + * So for boards with less than 1GB of RAM we put the initrd > > + * halfway into RAM, and for boards with 1GB of RAM or more we put > > + * the initrd at 512MB. > >*/ > > -start = kernel_entry + MIN(mem_size / 2, 128 * MiB); > > +start = kernel_entry + MIN(mem_size / 2, 512 * MiB); > > > > size = load_ramdisk(filename, start, mem_size - start); > > if (size == -1) {
[PATCH v2] hw: riscv: Allow large kernels to boot by moving the initrd further away in RAM
Currently, the initrd is placed at 128MB, which overlaps with the kernel when it is large (for example syzbot kernels are). From the kernel side, there is no reason we could not push the initrd further away in memory to accommodate large kernels, so move the initrd at 512MB when possible. The ideal solution would have been to place the initrd based on the kernel size but we actually can't since the bss size is not known when the image is loaded by load_image_targphys_as() and the initrd would then overlap with this section. Signed-off-by: Alexandre Ghiti --- Changes in v2: - Fix typos in commit log (Daniel) and title - Added to the commit log why using the kernel size does not work (Daniel) hw/riscv/boot.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 0ffca05189..9a367af2fa 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -188,13 +188,13 @@ static void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) * kernel is uncompressed it will not clobber the initrd. However * on boards without much RAM we must ensure that we still leave * enough room for a decent sized initrd, and on boards with large - * amounts of RAM we must avoid the initrd being so far up in RAM - * that it is outside lowmem and inaccessible to the kernel. - * So for boards with less than 256MB of RAM we put the initrd - * halfway into RAM, and for boards with 256MB of RAM or more we put - * the initrd at 128MB. + * amounts of RAM, we put the initrd at 512MB to allow large kernels + * to boot. + * So for boards with less than 1GB of RAM we put the initrd + * halfway into RAM, and for boards with 1GB of RAM or more we put + * the initrd at 512MB. */ -start = kernel_entry + MIN(mem_size / 2, 128 * MiB); +start = kernel_entry + MIN(mem_size / 2, 512 * MiB); size = load_ramdisk(filename, start, mem_size - start); if (size == -1) { -- 2.39.2
Re: [PATCH] hw: riscv: Allow large kernels to boot by moving the initrd further way in RAM
Hi Daniel, On Mon, Feb 5, 2024 at 2:36 PM Alexandre Ghiti wrote: > > Hi Daniel, > > On Mon, Feb 5, 2024 at 1:17 PM Daniel Henrique Barboza > wrote: > > > > > > > > On 2/5/24 04:00, Alexandre Ghiti wrote: > > > Currently, the initrd is placed at 128MB, which overlaps with the kernel > > > when it is large (for example syzbot kernels are). From the kernel side, > > > there is no reason we could not push the initrd further away in memory > > > to accomodate large kernels, so move the initrd at 512MB when possible. > > > > typo: accommodate > > > > > > > > Signed-off-by: Alexandre Ghiti > > > --- > > > > Patch looks good - just tested with an Ubuntu guest and nothing bad > > happened. > > > > But I wonder ... what if there's an even bigger kernel we have to deal with? > > Move initrd even further away to fit it in? > > > > Instead of making assumptions about where initrd starts, we could grab the > > kernel > > size loaded in the board and use it as a reference. This would be done by > > storing > > the return of load_elf_ram_sym/load_uimage_as/load_image_targphys_as from > > riscv_load_kernel() an passing as argument to riscv_load_initrd(). So this does not work because the size returned by load_image_targphys_as() does not take into account the size of the BSS sections (and I guess other NOBITS sections) and then we end up loading the initrd there. I'm a bit surprised though because arm64 does just that https://elixir.bootlin.com/qemu/latest/source/hw/arm/boot.c#L1034. I also tried using the highaddr parameter, but that gives the same result. We could parse the Image header (a PE header) to get the "Virtual Size" of the .data section, but I did not find any PE header parser in qemu, so that would be overkill? Any idea? Thanks, Alex > > > > initrd start would then be: > > > > start = kernel_entry + MIN(mem_size / 2, kernel_size); > > > > However, I believe we would like to keep the existing 128Mb minimum initrd > > start, > > even if the kernel is smaller than 128Mb, to avoid breaking existing > > configs that > > might be making this assumption. initrd start would then become: > > > > > > start = kernel_entry + MIN(mem_size / 2, MAX(kernel_size, 128 * MiB)); > > Great, I agree with you, thanks for the pointers. I'll just align the > size on a 2MB boundary to make sure the kernel mapping (which in the > case of Linux uses PMD) does not overlap with the initrd. > > I'll get back soon with a v2. > > Thanks again, > > Alex > > > > > > > > > Thanks, > > > > > > > > Daniel > > > > > > > hw/riscv/boot.c | 12 ++-- > > > 1 file changed, 6 insertions(+), 6 deletions(-) > > > > > > diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c > > > index 0ffca05189..9a367af2fa 100644 > > > --- a/hw/riscv/boot.c > > > +++ b/hw/riscv/boot.c > > > @@ -188,13 +188,13 @@ static void riscv_load_initrd(MachineState > > > *machine, uint64_t kernel_entry) > > >* kernel is uncompressed it will not clobber the initrd. However > > >* on boards without much RAM we must ensure that we still leave > > >* enough room for a decent sized initrd, and on boards with large > > > - * amounts of RAM we must avoid the initrd being so far up in RAM > > > - * that it is outside lowmem and inaccessible to the kernel. > > > - * So for boards with less than 256MB of RAM we put the initrd > > > - * halfway into RAM, and for boards with 256MB of RAM or more we put > > > - * the initrd at 128MB. > > > + * amounts of RAM, we put the initrd at 512MB to allow large kernels > > > + * to boot. > > > + * So for boards with less than 1GB of RAM we put the initrd > > > + * halfway into RAM, and for boards with 1GB of RAM or more we put > > > + * the initrd at 512MB. > > >*/ > > > -start = kernel_entry + MIN(mem_size / 2, 128 * MiB); > > > +start = kernel_entry + MIN(mem_size / 2, 512 * MiB); > > > > > > size = load_ramdisk(filename, start, mem_size - start); > > > if (size == -1) {
Re: [PATCH] hw: riscv: Allow large kernels to boot by moving the initrd further way in RAM
Hi Daniel, On Mon, Feb 5, 2024 at 1:17 PM Daniel Henrique Barboza wrote: > > > > On 2/5/24 04:00, Alexandre Ghiti wrote: > > Currently, the initrd is placed at 128MB, which overlaps with the kernel > > when it is large (for example syzbot kernels are). From the kernel side, > > there is no reason we could not push the initrd further away in memory > > to accomodate large kernels, so move the initrd at 512MB when possible. > > typo: accommodate > > > > > Signed-off-by: Alexandre Ghiti > > --- > > Patch looks good - just tested with an Ubuntu guest and nothing bad happened. > > But I wonder ... what if there's an even bigger kernel we have to deal with? > Move initrd even further away to fit it in? > > Instead of making assumptions about where initrd starts, we could grab the > kernel > size loaded in the board and use it as a reference. This would be done by > storing > the return of load_elf_ram_sym/load_uimage_as/load_image_targphys_as from > riscv_load_kernel() an passing as argument to riscv_load_initrd(). > > initrd start would then be: > > start = kernel_entry + MIN(mem_size / 2, kernel_size); > > However, I believe we would like to keep the existing 128Mb minimum initrd > start, > even if the kernel is smaller than 128Mb, to avoid breaking existing configs > that > might be making this assumption. initrd start would then become: > > > start = kernel_entry + MIN(mem_size / 2, MAX(kernel_size, 128 * MiB)); Great, I agree with you, thanks for the pointers. I'll just align the size on a 2MB boundary to make sure the kernel mapping (which in the case of Linux uses PMD) does not overlap with the initrd. I'll get back soon with a v2. Thanks again, Alex > > > > Thanks, > > > > Daniel > > > > hw/riscv/boot.c | 12 ++-- > > 1 file changed, 6 insertions(+), 6 deletions(-) > > > > diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c > > index 0ffca05189..9a367af2fa 100644 > > --- a/hw/riscv/boot.c > > +++ b/hw/riscv/boot.c > > @@ -188,13 +188,13 @@ static void riscv_load_initrd(MachineState *machine, > > uint64_t kernel_entry) > >* kernel is uncompressed it will not clobber the initrd. However > >* on boards without much RAM we must ensure that we still leave > >* enough room for a decent sized initrd, and on boards with large > > - * amounts of RAM we must avoid the initrd being so far up in RAM > > - * that it is outside lowmem and inaccessible to the kernel. > > - * So for boards with less than 256MB of RAM we put the initrd > > - * halfway into RAM, and for boards with 256MB of RAM or more we put > > - * the initrd at 128MB. > > + * amounts of RAM, we put the initrd at 512MB to allow large kernels > > + * to boot. > > + * So for boards with less than 1GB of RAM we put the initrd > > + * halfway into RAM, and for boards with 1GB of RAM or more we put > > + * the initrd at 512MB. > >*/ > > -start = kernel_entry + MIN(mem_size / 2, 128 * MiB); > > +start = kernel_entry + MIN(mem_size / 2, 512 * MiB); > > > > size = load_ramdisk(filename, start, mem_size - start); > > if (size == -1) {
[PATCH] hw: riscv: Allow large kernels to boot by moving the initrd further way in RAM
Currently, the initrd is placed at 128MB, which overlaps with the kernel when it is large (for example syzbot kernels are). From the kernel side, there is no reason we could not push the initrd further away in memory to accomodate large kernels, so move the initrd at 512MB when possible. Signed-off-by: Alexandre Ghiti --- hw/riscv/boot.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 0ffca05189..9a367af2fa 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -188,13 +188,13 @@ static void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) * kernel is uncompressed it will not clobber the initrd. However * on boards without much RAM we must ensure that we still leave * enough room for a decent sized initrd, and on boards with large - * amounts of RAM we must avoid the initrd being so far up in RAM - * that it is outside lowmem and inaccessible to the kernel. - * So for boards with less than 256MB of RAM we put the initrd - * halfway into RAM, and for boards with 256MB of RAM or more we put - * the initrd at 128MB. + * amounts of RAM, we put the initrd at 512MB to allow large kernels + * to boot. + * So for boards with less than 1GB of RAM we put the initrd + * halfway into RAM, and for boards with 1GB of RAM or more we put + * the initrd at 512MB. */ -start = kernel_entry + MIN(mem_size / 2, 128 * MiB); +start = kernel_entry + MIN(mem_size / 2, 512 * MiB); size = load_ramdisk(filename, start, mem_size - start); if (size == -1) { -- 2.39.2
Re: [PATCH v2] riscv: Make sure an exception is raised if a pte is malformed
On Thu, Apr 20, 2023 at 1:31 AM Alistair Francis wrote: > > On Wed, Apr 19, 2023 at 8:48 PM Alexandre Ghiti > wrote: > > > > As per the privileged specification, in 64-bit, if any of the pte reserved > > bits 60-54 is set an exception should be triggered, and the same applies to > > napot/pbmt bits if those extensions are not enabled > > (see 4.4.1, "Addressing and Memory Protection"). > > > > Reported-by: Andrea Parri > > Signed-off-by: Alexandre Ghiti > > Thanks for the patch > > Do you mind sending a v3 rebased on > https://github.com/alistair23/qemu/tree/riscv-to-apply.next ? Sure, I have just sent the v3. Thanks for your quick review! Alex > > Alistair > > > --- > > target/riscv/cpu_bits.h | 1 + > > target/riscv/cpu_helper.c | 15 +++ > > 2 files changed, 12 insertions(+), 4 deletions(-) > > > > diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h > > index fca7ef0cef..8d9ba2ce11 100644 > > --- a/target/riscv/cpu_bits.h > > +++ b/target/riscv/cpu_bits.h > > @@ -640,6 +640,7 @@ typedef enum { > > #define PTE_SOFT0x300 /* Reserved for Software */ > > #define PTE_PBMT0x6000ULL /* Page-based memory > > types */ > > #define PTE_N 0x8000ULL /* NAPOT translation */ > > +#define PTE_RESERVED0x1FC0ULL /* Reserved bits */ > > #define PTE_ATTR(PTE_N | PTE_PBMT) /* All attributes bits */ > > > > /* Page table PPN shift amount */ > > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c > > index f88c503cf4..8dc832d1bb 100644 > > --- a/target/riscv/cpu_helper.c > > +++ b/target/riscv/cpu_helper.c > > @@ -946,13 +946,20 @@ restart: > > > > if (riscv_cpu_sxl(env) == MXL_RV32) { > > ppn = pte >> PTE_PPN_SHIFT; > > -} else if (pbmte || cpu->cfg.ext_svnapot) { > > -ppn = (pte & (target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT; > > } else { > > -ppn = pte >> PTE_PPN_SHIFT; > > -if ((pte & ~(target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT) { > > +if (pte & PTE_RESERVED) { > > +return TRANSLATE_FAIL; > > +} > > + > > +if (!pbmte && (pte & PTE_PBMT)) { > > return TRANSLATE_FAIL; > > } > > + > > +if (!cpu->cfg.ext_svnapot && (pte & PTE_N)) { > > +return TRANSLATE_FAIL; > > +} > > + > > +ppn = (pte & (target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT; > > } > > > > if (!(pte & PTE_V)) { > > -- > > 2.37.2 > > > >
[PATCH v3] riscv: Make sure an exception is raised if a pte is malformed
As per the specification, in 64-bit, if any of the pte reserved bits 60-54 is set an exception should be triggered (see 4.4.1, "Addressing and Memory Protection"). In addition, we must check the napot/pbmt bits are not set if those extensions are not active. Reported-by: Andrea Parri Signed-off-by: Alexandre Ghiti Reviewed-by: Alistair Francis --- Changes in v3: - Rebase on top of https://github.com/alistair23/qemu/tree/riscv-to-apply.next Changes in v2: - Handle napot and pbmt exception target/riscv/cpu_bits.h | 1 + target/riscv/cpu_helper.c | 15 +++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index fb63b8e125..59f0ffd9e1 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -644,6 +644,7 @@ typedef enum { #define PTE_SOFT0x300 /* Reserved for Software */ #define PTE_PBMT0x6000ULL /* Page-based memory types */ #define PTE_N 0x8000ULL /* NAPOT translation */ +#define PTE_RESERVED0x1FC0ULL /* Reserved bits */ #define PTE_ATTR(PTE_N | PTE_PBMT) /* All attributes bits */ /* Page table PPN shift amount */ diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index b68dcfe7b6..57d04385f1 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -927,13 +927,20 @@ restart: if (riscv_cpu_sxl(env) == MXL_RV32) { ppn = pte >> PTE_PPN_SHIFT; -} else if (pbmte || riscv_cpu_cfg(env)->ext_svnapot) { -ppn = (pte & (target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT; } else { -ppn = pte >> PTE_PPN_SHIFT; -if ((pte & ~(target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT) { +if (pte & PTE_RESERVED) { +return TRANSLATE_FAIL; +} + +if (!pbmte && (pte & PTE_PBMT)) { return TRANSLATE_FAIL; } + +if (!riscv_cpu_cfg(env)->ext_svnapot && (pte & PTE_N)) { +return TRANSLATE_FAIL; +} + +ppn = (pte & (target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT; } if (!(pte & PTE_V)) { -- 2.37.2
[PATCH v2] riscv: Make sure an exception is raised if a pte is malformed
As per the privileged specification, in 64-bit, if any of the pte reserved bits 60-54 is set an exception should be triggered, and the same applies to napot/pbmt bits if those extensions are not enabled (see 4.4.1, "Addressing and Memory Protection"). Reported-by: Andrea Parri Signed-off-by: Alexandre Ghiti --- target/riscv/cpu_bits.h | 1 + target/riscv/cpu_helper.c | 15 +++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index fca7ef0cef..8d9ba2ce11 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -640,6 +640,7 @@ typedef enum { #define PTE_SOFT0x300 /* Reserved for Software */ #define PTE_PBMT0x6000ULL /* Page-based memory types */ #define PTE_N 0x8000ULL /* NAPOT translation */ +#define PTE_RESERVED0x1FC0ULL /* Reserved bits */ #define PTE_ATTR(PTE_N | PTE_PBMT) /* All attributes bits */ /* Page table PPN shift amount */ diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index f88c503cf4..8dc832d1bb 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -946,13 +946,20 @@ restart: if (riscv_cpu_sxl(env) == MXL_RV32) { ppn = pte >> PTE_PPN_SHIFT; -} else if (pbmte || cpu->cfg.ext_svnapot) { -ppn = (pte & (target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT; } else { -ppn = pte >> PTE_PPN_SHIFT; -if ((pte & ~(target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT) { +if (pte & PTE_RESERVED) { +return TRANSLATE_FAIL; +} + +if (!pbmte && (pte & PTE_PBMT)) { return TRANSLATE_FAIL; } + +if (!cpu->cfg.ext_svnapot && (pte & PTE_N)) { +return TRANSLATE_FAIL; +} + +ppn = (pte & (target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT; } if (!(pte & PTE_V)) { -- 2.37.2
Re: [PATCH] riscv: Raise an exception if pte reserved bits are not cleared
Hi Alistair, Sorry for the late reply, I was on PTO. On Tue, Apr 18, 2023 at 4:22 AM Alistair Francis wrote: > > On Mon, Apr 17, 2023 at 8:47 PM Andrea Parri wrote: > > > > Hi Alistair, > > > > > > @@ -936,6 +936,11 @@ restart: > > > > return TRANSLATE_FAIL; > > > > } > > > > > > > > +/* PTE reserved bits must be cleared otherwise an exception is > > > > raised */ > > > > +if (riscv_cpu_mxl(env) == MXL_RV64 && (pte & PTE_RESERVED)) { > > > > +return TRANSLATE_FAIL; > > > > +} > > > > > > Isn't this caught by our existing check? > > > > > > if ((pte & ~(target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT) { > > > return TRANSLATE_FAIL; > > > } > > > > Thanks for checking this out. AFAICS, the existing check/code doesn't > > work if either svnapot or svpbmt are active. > > svpbmt uses some of the reserved fields right? No, pbmt uses bits 61-62 and napot uses bit 63, this patchset deals with bits 54-60. > > I'm not sure why svnapot excludes the check. The correct fix should be > to change this check as required (instead of adding a new check). napot and pbmt exclude the check because PTE_PPN_MASK only deals with PPN bits, and then ~PTE_PPN_MASK is too large as it tests the PBMT/NAPOT bits AND the reserved bits. But you made me notice that the pbmt/napot check isn't right either, as the napot bit could be set if !napot and then an exception would not be triggered (the same for pbmt). Let me check this completely and come back with a proper fix for that too. Thanks! Alex > > Alistair > > > > > Please let me know if you need other information. > > > > Andrea
[PATCH] riscv: Raise an exception if pte reserved bits are not cleared
As per the specification, in 64-bit, if any of the pte reserved bits 60-54 is set, an exception should be triggered (see 4.4.1, "Addressing and Memory Protection"), so implement this behaviour in the address translation process. Reported-by: Andrea Parri Signed-off-by: Alexandre Ghiti --- target/riscv/cpu_bits.h | 1 + target/riscv/cpu_helper.c | 5 + 2 files changed, 6 insertions(+) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index fca7ef0cef..8d9ba2ce11 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -640,6 +640,7 @@ typedef enum { #define PTE_SOFT0x300 /* Reserved for Software */ #define PTE_PBMT0x6000ULL /* Page-based memory types */ #define PTE_N 0x8000ULL /* NAPOT translation */ +#define PTE_RESERVED0x1FC0ULL /* Reserved bits */ #define PTE_ATTR(PTE_N | PTE_PBMT) /* All attributes bits */ /* Page table PPN shift amount */ diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index f88c503cf4..39c323a865 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -936,6 +936,11 @@ restart: return TRANSLATE_FAIL; } +/* PTE reserved bits must be cleared otherwise an exception is raised */ +if (riscv_cpu_mxl(env) == MXL_RV64 && (pte & PTE_RESERVED)) { +return TRANSLATE_FAIL; +} + bool pbmte = env->menvcfg & MENVCFG_PBMTE; bool hade = env->menvcfg & MENVCFG_HADE; -- 2.37.2
Re: [PATCH v11 0/5] riscv: Allow user to set the satp mode
Hi Palmer, On Mon, Mar 6, 2023 at 12:34 AM Palmer Dabbelt wrote: > > On Fri, 03 Mar 2023 05:12:47 PST (-0800), alexgh...@rivosinc.com wrote: > > This introduces new properties to allow the user to set the satp mode, > > see patch 3 for full syntax. In addition, it prevents cpus to boot in a > > satp mode they do not support (see patch 4). > > > > base-commit: commit c61d1a066cb6 ("Merge tag 'for-upstream' of > > https://gitlab.com/bonzini/qemu into staging") > > I have that, but I still got some merge conflicts. I've put that here > <https://github.com/palmer-dabbelt/qemu/tree/set-satp> for now, pending > Daniel's response below. Weird, I have just tried again and it applied cleanly on the base-commit I mentioned, I tried to cherry-pick a few patches, even commit d4ea71170432 ("target/riscv: introduce riscv_cpu_cfg()") does not break the merge. Anyway, FWIW I checked the patches on the set-satp branch again, and your merge seems ok. > > > > > v11: > > - rebase on top of master > > - Added RB/AB from Frank and Alistair > > - Use VM_1_10_XX directly instead of satp_mode_from_str, from Frank > > - Set satp mode max for thead c906 to sv39 > > Daniel: It looks like the feedback on v10 included dropping the first > patch > <https://lore.kernel.org/qemu-devel/66d80b94-5941-31f3-995f-e9666a91f...@ventanamicro.com/T/#macdb6c5232bd8c082966107d7b44aaaec9b29ad6>. > Sorry if I'm just misunderstanding, but it looks to me like that patch > is still useful and the v11 doesn't even build without it. No, the first commit is a preparatory commit for the series, it is required. > > > > > v10: > > - Fix user mode build by surrounding satp handling with #ifndef > > CONFIG_USER_ONLY, Frank > > - Fix AB/RB from Frank and Alistair > > > > v9: > > - Move valid_vm[i] up, Andrew > > - Fixed expansion of the bitmap map, Bin > > - Rename set_satp_mode_default into set_satp_mode_default_map, Bin > > - Remove outer parenthesis and alignment, Bin > > - Fix qemu32 build failure, Bin > > - Fixed a few typos, Bin > > - Add RB from Andrew and Bin > > > > v8: > > - Remove useless !map check, Andrew > > - Add RB from Andrew > > > > v7: > > - Expand map to contain all valid modes, Andrew > > - Fix commit log for patch 3, Andrew > > - Remove is_32_bit argument from set_satp_mode_default, Andrew > > - Move and fixed comment, Andrew > > - Fix satp_mode_map_max in riscv_cpu_satp_mode_finalize which was set > > too early, Alex > > - Remove is_32_bit argument from set_satp_mode_max_supported, Andrew > > - Use satp_mode directly instead of a string in > > set_satp_mode_max_supported, Andrew > > - Swap the patch introducing supported bitmap and the patch that sets > > sv57 in the dt, Andrew > > - Add various RB from Andrew and Alistair, thanks > > > > v6: > > - Remove the valid_vm check in validate_vm and add it to the finalize > > function > > so that map already contains the constraint, Alex > > - Add forgotten mbare to satp_mode_from_str, Alex > > - Move satp mode properties handling to riscv_cpu_satp_mode_finalize, Andrew > > - Only add satp mode properties corresponding to the cpu, and then remove > > the > > check against valid_vm_1_10_32/64 in riscv_cpu_satp_mode_finalize, > > Andrew/Alistair/Alex > > - Move mmu-type setting to its own patch, Andrew > > - patch 5 is new and is a fix, Alex > > > > v5: > > - Simplify v4 implementation by leveraging valid_vm_1_10_32/64, as > > suggested by Andrew > > - Split the v4 patch into 2 patches as suggested by Andrew > > - Lot of other minor corrections, from Andrew > > - Set the satp mode N by disabling the satp mode N + 1 > > - Add a helper to set satp mode from a string, as suggested by Frank > > > > v4: > > - Use custom boolean properties instead of OnOffAuto properties, based > > on ARMVQMap, as suggested by Andrew > > > > v3: > > - Free sv_name as pointed by Bin > > - Replace satp-mode with boolean properties as suggested by Andrew > > - Removed RB from Atish as the patch considerably changed > > > > v2: > > - Use error_setg + return as suggested by Alistair > > - Add RB from Atish > > - Fixed checkpatch issues missed in v1 > > - Replaced Ludovic email address with the rivos one > > > > Alexandre Ghiti (5): > > riscv: Pass Object to register_cpu_props instead of DeviceState > > riscv: Change type of valid_vm_1_10_[32|64] to bool > > riscv: Allow user to set the satp mode > > riscv: Introduce satp mode hw capabilities > > riscv: Correctly set the device-tree entry 'mmu-type' > > > > hw/riscv/virt.c| 19 +-- > > target/riscv/cpu.c | 288 ++--- > > target/riscv/cpu.h | 25 > > target/riscv/csr.c | 29 +++-- > > 4 files changed, 323 insertions(+), 38 deletions(-)
[PATCH v11 5/5] riscv: Correctly set the device-tree entry 'mmu-type'
The 'mmu-type' should reflect what the hardware is capable of so use the new satp_mode field in RISCVCPUConfig to do that. Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Reviewed-by: Frank Chang --- hw/riscv/virt.c | 19 ++- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 86c4adc0c9..59922d6965 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -228,8 +228,9 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, int cpu; uint32_t cpu_phandle; MachineState *ms = MACHINE(s); -char *name, *cpu_name, *core_name, *intc_name; +char *name, *cpu_name, *core_name, *intc_name, *sv_name; bool is_32_bit = riscv_is_32bit(>soc[0]); +uint8_t satp_mode_max; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { cpu_phandle = (*phandle)++; @@ -237,14 +238,14 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(ms->fdt, cpu_name); -if (riscv_feature(>soc[socket].harts[cpu].env, - RISCV_FEATURE_MMU)) { -qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", -(is_32_bit) ? "riscv,sv32" : "riscv,sv48"); -} else { -qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", -"riscv,none"); -} + +satp_mode_max = satp_mode_max_from_map( +s->soc[socket].harts[cpu].cfg.satp_mode.map); +sv_name = g_strdup_printf("riscv,%s", + satp_mode_str(satp_mode_max, is_32_bit)); +qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", sv_name); +g_free(sv_name); + name = riscv_isa_string(>soc[socket].harts[cpu]); qemu_fdt_setprop_string(ms->fdt, cpu_name, "riscv,isa", name); g_free(name); -- 2.37.2
[PATCH v11 4/5] riscv: Introduce satp mode hw capabilities
Currently, the max satp mode is set with the only constraint that it must be implemented in QEMU, i.e. set in valid_vm_1_10_[32|64]. But we actually need to add another level of constraint: what the hw is actually capable of, because currently, a linux booting on a sifive-u54 boots in sv57 mode which is incompatible with the cpu's sv39 max capability. So add a new bitmap to RISCVSATPMap which contains this capability and initialize it in every XXX_cpu_init. Finally: - valid_vm_1_10_[32|64] constrains which satp mode the CPU can use - the CPU hw capabilities constrains what the user may select - the user's selection then constrains what's available to the guest OS. Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Bin Meng Reviewed-by: Frank Chang Reviewed-by: Alistair Francis --- target/riscv/cpu.c | 93 ++ target/riscv/cpu.h | 8 +++- 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 6de2ca0eaa..d4584299db 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -306,17 +306,24 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) g_assert_not_reached(); } -/* Sets the satp mode to the max supported */ -static void set_satp_mode_default_map(RISCVCPU *cpu) +static void set_satp_mode_max_supported(RISCVCPU *cpu, +uint8_t satp_mode) { bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; +const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; -if (riscv_feature(>env, RISCV_FEATURE_MMU)) { -cpu->cfg.satp_mode.map |= (1 << (rv32 ? VM_1_10_SV32 : VM_1_10_SV57)); -} else { -cpu->cfg.satp_mode.map |= (1 << VM_1_10_MBARE); +for (int i = 0; i <= satp_mode; ++i) { +if (valid_vm[i]) { +cpu->cfg.satp_mode.supported |= (1 << i); +} } } + +/* Set the satp mode to the max supported */ +static void set_satp_mode_default_map(RISCVCPU *cpu) +{ +cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported; +} #endif static void riscv_any_cpu_init(Object *obj) @@ -327,6 +334,13 @@ static void riscv_any_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif + +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(RISCV_CPU(obj), +riscv_cpu_mxl(_CPU(obj)->env) == MXL_RV32 ? +VM_1_10_SV32 : VM_1_10_SV57); +#endif + set_priv_version(env, PRIV_VERSION_1_12_0); register_cpu_props(obj); } @@ -340,6 +354,9 @@ static void rv64_base_cpu_init(Object *obj) register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57); +#endif } static void rv64_sifive_u_cpu_init(Object *obj) @@ -348,6 +365,9 @@ static void rv64_sifive_u_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); register_cpu_props(obj); set_priv_version(env, PRIV_VERSION_1_10_0); +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV39); +#endif } static void rv64_sifive_e_cpu_init(Object *obj) @@ -359,6 +379,9 @@ static void rv64_sifive_e_cpu_init(Object *obj) register_cpu_props(obj); set_priv_version(env, PRIV_VERSION_1_10_0); cpu->cfg.mmu = false; +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(cpu, VM_1_10_MBARE); +#endif } static void rv64_thead_c906_cpu_init(Object *obj) @@ -388,6 +411,9 @@ static void rv64_thead_c906_cpu_init(Object *obj) cpu->cfg.ext_xtheadsync = true; cpu->cfg.mvendorid = THEAD_VENDOR_ID; +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(cpu, VM_1_10_SV39); +#endif } static void rv128_base_cpu_init(Object *obj) @@ -404,6 +430,9 @@ static void rv128_base_cpu_init(Object *obj) register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57); +#endif } #else static void rv32_base_cpu_init(Object *obj) @@ -414,6 +443,9 @@ static void rv32_base_cpu_init(Object *obj) register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32); +#endif } static void rv32_sifive_u_cpu_init(Object *obj) @@ -422,6 +454,9 @@ static void rv32_sifive_u_cpu_init(Object *obj) set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); register_cpu_props(obj); set_priv_version(env, PRIV_VERSION_1_10_0); +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_support
[PATCH v11 3/5] riscv: Allow user to set the satp mode
RISC-V specifies multiple sizes for addressable memory and Linux probes for the machine's support at startup via the satp CSR register (done in csr.c:validate_vm). As per the specification, sv64 must support sv57, which in turn must support sv48...etc. So we can restrict machine support by simply setting the "highest" supported mode and the bare mode is always supported. You can set the satp mode using the new properties "sv32", "sv39", "sv48", "sv57" and "sv64" as follows: -cpu rv64,sv57=on # Linux will boot using sv57 scheme -cpu rv64,sv39=on # Linux will boot using sv39 scheme -cpu rv64,sv57=off # Linux will boot using sv48 scheme -cpu rv64 # Linux will boot using sv57 scheme by default We take the highest level set by the user: -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme We make sure that invalid configurations are rejected: -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are # enabled We accept "redundant" configurations: -cpu rv64,sv48=on,sv57=off # Linux will boot using sv48 scheme And contradictory configurations: -cpu rv64,sv48=on,sv48=off # Linux will boot using sv39 scheme Co-Developed-by: Ludovic Henry Signed-off-by: Ludovic Henry Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Bin Meng Acked-by: Alistair Francis Reviewed-by: Frank Chang --- target/riscv/cpu.c | 214 + target/riscv/cpu.h | 21 + target/riscv/csr.c | 12 ++- 3 files changed, 240 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 5dc11d6670..6de2ca0eaa 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -28,6 +28,7 @@ #include "time_helper.h" #include "exec/exec-all.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "qemu/error-report.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" @@ -242,6 +243,82 @@ static void set_vext_version(CPURISCVState *env, int vext_ver) env->vext_ver = vext_ver; } +#ifndef CONFIG_USER_ONLY +static uint8_t satp_mode_from_str(const char *satp_mode_str) +{ +if (!strncmp(satp_mode_str, "mbare", 5)) { +return VM_1_10_MBARE; +} + +if (!strncmp(satp_mode_str, "sv32", 4)) { +return VM_1_10_SV32; +} + +if (!strncmp(satp_mode_str, "sv39", 4)) { +return VM_1_10_SV39; +} + +if (!strncmp(satp_mode_str, "sv48", 4)) { +return VM_1_10_SV48; +} + +if (!strncmp(satp_mode_str, "sv57", 4)) { +return VM_1_10_SV57; +} + +if (!strncmp(satp_mode_str, "sv64", 4)) { +return VM_1_10_SV64; +} + +g_assert_not_reached(); +} + +uint8_t satp_mode_max_from_map(uint32_t map) +{ +/* map here has at least one bit set, so no problem with clz */ +return 31 - __builtin_clz(map); +} + +const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) +{ +if (is_32_bit) { +switch (satp_mode) { +case VM_1_10_SV32: +return "sv32"; +case VM_1_10_MBARE: +return "none"; +} +} else { +switch (satp_mode) { +case VM_1_10_SV64: +return "sv64"; +case VM_1_10_SV57: +return "sv57"; +case VM_1_10_SV48: +return "sv48"; +case VM_1_10_SV39: +return "sv39"; +case VM_1_10_MBARE: +return "none"; +} +} + +g_assert_not_reached(); +} + +/* Sets the satp mode to the max supported */ +static void set_satp_mode_default_map(RISCVCPU *cpu) +{ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; + +if (riscv_feature(>env, RISCV_FEATURE_MMU)) { +cpu->cfg.satp_mode.map |= (1 << (rv32 ? VM_1_10_SV32 : VM_1_10_SV57)); +} else { +cpu->cfg.satp_mode.map |= (1 << VM_1_10_MBARE); +} +} +#endif + static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; @@ -870,6 +947,87 @@ static void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) set_misa(env, env->misa_mxl, ext); } +#ifndef CONFIG_USER_ONLY +static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) +{ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; +const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; +uint8_t satp_mode_max; + +if (cpu->cfg.satp_mode.map == 0) { +if (cpu->cfg.satp_mode.init == 0) { +/* If unset by the user, we fallback to the default satp mode. */ +set_satp_mode_default_map(cpu); +} else { +/* + * Find the lowest level that was disabled and then enable the + * fir
[PATCH v11 2/5] riscv: Change type of valid_vm_1_10_[32|64] to bool
This array is actually used as a boolean so swap its current char type to a boolean and at the same time, change the type of validate_vm to bool since it returns valid_vm_1_10_[32|64]. Suggested-by: Andrew Jones Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Reviewed-by: Frank Chang --- target/riscv/csr.c | 21 +++-- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 1b0a0c1693..163eb3b82b 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1123,16 +1123,16 @@ static const target_ulong hip_writable_mask = MIP_VSSIP; static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; static const target_ulong vsip_writable_mask = MIP_VSSIP; -static const char valid_vm_1_10_32[16] = { -[VM_1_10_MBARE] = 1, -[VM_1_10_SV32] = 1 +static const bool valid_vm_1_10_32[16] = { +[VM_1_10_MBARE] = true, +[VM_1_10_SV32] = true }; -static const char valid_vm_1_10_64[16] = { -[VM_1_10_MBARE] = 1, -[VM_1_10_SV39] = 1, -[VM_1_10_SV48] = 1, -[VM_1_10_SV57] = 1 +static const bool valid_vm_1_10_64[16] = { +[VM_1_10_MBARE] = true, +[VM_1_10_SV39] = true, +[VM_1_10_SV48] = true, +[VM_1_10_SV57] = true }; /* Machine Information Registers */ @@ -1215,7 +1215,7 @@ static RISCVException read_mstatus(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int validate_vm(CPURISCVState *env, target_ulong vm) +static bool validate_vm(CPURISCVState *env, target_ulong vm) { if (riscv_cpu_mxl(env) == MXL_RV32) { return valid_vm_1_10_32[vm & 0xf]; @@ -2641,7 +2641,8 @@ static RISCVException read_satp(CPURISCVState *env, int csrno, static RISCVException write_satp(CPURISCVState *env, int csrno, target_ulong val) { -target_ulong vm, mask; +target_ulong mask; +bool vm; if (!riscv_feature(env, RISCV_FEATURE_MMU)) { return RISCV_EXCP_NONE; -- 2.37.2
[PATCH v11 1/5] riscv: Pass Object to register_cpu_props instead of DeviceState
One can extract the DeviceState pointer from the Object pointer, so pass the Object for future commits to access other fields of Object. No functional changes intended. Signed-off-by: Alexandre Ghiti Reviewed-by: Alistair Francis Reviewed-by: Frank Chang Reviewed-by: Andrew Jones Reviewed-by: Bin Meng --- target/riscv/cpu.c | 29 +++-- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 9eb748a283..5dc11d6670 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -213,7 +213,7 @@ static const char * const riscv_intr_names[] = { "reserved" }; -static void register_cpu_props(DeviceState *dev); +static void register_cpu_props(Object *obj); const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) { @@ -251,7 +251,7 @@ static void riscv_any_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif set_priv_version(env, PRIV_VERSION_1_12_0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #if defined(TARGET_RISCV64) @@ -260,7 +260,7 @@ static void rv64_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -269,7 +269,7 @@ static void rv64_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); set_priv_version(env, PRIV_VERSION_1_10_0); } @@ -279,7 +279,7 @@ static void rv64_sifive_e_cpu_init(Object *obj) RISCVCPU *cpu = RISCV_CPU(obj); set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); set_priv_version(env, PRIV_VERSION_1_10_0); cpu->cfg.mmu = false; } @@ -324,7 +324,7 @@ static void rv128_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -334,7 +334,7 @@ static void rv32_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV32, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -343,7 +343,7 @@ static void rv32_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); set_priv_version(env, PRIV_VERSION_1_10_0); } @@ -353,7 +353,7 @@ static void rv32_sifive_e_cpu_init(Object *obj) RISCVCPU *cpu = RISCV_CPU(obj); set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); set_priv_version(env, PRIV_VERSION_1_10_0); cpu->cfg.mmu = false; } @@ -364,7 +364,7 @@ static void rv32_ibex_cpu_init(Object *obj) RISCVCPU *cpu = RISCV_CPU(obj); set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); set_priv_version(env, PRIV_VERSION_1_11_0); cpu->cfg.mmu = false; cpu->cfg.epmp = true; @@ -376,7 +376,7 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj) RISCVCPU *cpu = RISCV_CPU(obj); set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); set_priv_version(env, PRIV_VERSION_1_10_0); cpu->cfg.mmu = false; } @@ -391,7 +391,7 @@ static void riscv_host_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, 0); #endif -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #endif @@ -1161,11 +1161,12 @@ static Property riscv_cpu_extensions[] = { * properties and leave. env.misa_ext = 0 means that we want * all the default properties to be registered. */ -static void register_cpu_props(DeviceState *dev) +static void register_cpu_props(Object *obj) { -RISCVCPU *cpu = RISCV_CPU(OBJECT(dev)); +RISCVCPU *cpu = RISCV_CPU(obj); uint32_t misa_ext = cpu->env.misa_ext; Property *prop; +DeviceState *dev = DEVICE(obj); /* * If misa_ext is not zero, set cfg properties now to -- 2.37.2
[PATCH v11 0/5] riscv: Allow user to set the satp mode
This introduces new properties to allow the user to set the satp mode, see patch 3 for full syntax. In addition, it prevents cpus to boot in a satp mode they do not support (see patch 4). base-commit: commit c61d1a066cb6 ("Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging") v11: - rebase on top of master - Added RB/AB from Frank and Alistair - Use VM_1_10_XX directly instead of satp_mode_from_str, from Frank - Set satp mode max for thead c906 to sv39 v10: - Fix user mode build by surrounding satp handling with #ifndef CONFIG_USER_ONLY, Frank - Fix AB/RB from Frank and Alistair v9: - Move valid_vm[i] up, Andrew - Fixed expansion of the bitmap map, Bin - Rename set_satp_mode_default into set_satp_mode_default_map, Bin - Remove outer parenthesis and alignment, Bin - Fix qemu32 build failure, Bin - Fixed a few typos, Bin - Add RB from Andrew and Bin v8: - Remove useless !map check, Andrew - Add RB from Andrew v7: - Expand map to contain all valid modes, Andrew - Fix commit log for patch 3, Andrew - Remove is_32_bit argument from set_satp_mode_default, Andrew - Move and fixed comment, Andrew - Fix satp_mode_map_max in riscv_cpu_satp_mode_finalize which was set too early, Alex - Remove is_32_bit argument from set_satp_mode_max_supported, Andrew - Use satp_mode directly instead of a string in set_satp_mode_max_supported, Andrew - Swap the patch introducing supported bitmap and the patch that sets sv57 in the dt, Andrew - Add various RB from Andrew and Alistair, thanks v6: - Remove the valid_vm check in validate_vm and add it to the finalize function so that map already contains the constraint, Alex - Add forgotten mbare to satp_mode_from_str, Alex - Move satp mode properties handling to riscv_cpu_satp_mode_finalize, Andrew - Only add satp mode properties corresponding to the cpu, and then remove the check against valid_vm_1_10_32/64 in riscv_cpu_satp_mode_finalize, Andrew/Alistair/Alex - Move mmu-type setting to its own patch, Andrew - patch 5 is new and is a fix, Alex v5: - Simplify v4 implementation by leveraging valid_vm_1_10_32/64, as suggested by Andrew - Split the v4 patch into 2 patches as suggested by Andrew - Lot of other minor corrections, from Andrew - Set the satp mode N by disabling the satp mode N + 1 - Add a helper to set satp mode from a string, as suggested by Frank v4: - Use custom boolean properties instead of OnOffAuto properties, based on ARMVQMap, as suggested by Andrew v3: - Free sv_name as pointed by Bin - Replace satp-mode with boolean properties as suggested by Andrew - Removed RB from Atish as the patch considerably changed v2: - Use error_setg + return as suggested by Alistair - Add RB from Atish - Fixed checkpatch issues missed in v1 - Replaced Ludovic email address with the rivos one Alexandre Ghiti (5): riscv: Pass Object to register_cpu_props instead of DeviceState riscv: Change type of valid_vm_1_10_[32|64] to bool riscv: Allow user to set the satp mode riscv: Introduce satp mode hw capabilities riscv: Correctly set the device-tree entry 'mmu-type' hw/riscv/virt.c| 19 +-- target/riscv/cpu.c | 288 ++--- target/riscv/cpu.h | 25 target/riscv/csr.c | 29 +++-- 4 files changed, 323 insertions(+), 38 deletions(-) -- 2.37.2
Re: [PATCH v10 0/5] riscv: Allow user to set the satp mode
Hi Daniel, On Thu, Mar 2, 2023 at 10:03 PM Daniel Henrique Barboza wrote: > > > > On 3/2/23 14:42, Daniel Henrique Barboza wrote: > > Hi Palmer, > > > > I think this series can be picked. All patches are fully acked. There is a > > nit > > in patch 3 that I believe you can choose to fix in-tree if you want to. > > Update: patch 1 is not applicable anymore due to changes in current master. > All > other patches have conflicts as well. > > I guess it's easier to Alexandre to rebase and re-send it when possible. > Frank's > comment in patch 3 can also be handled during the process. Sure I'll do that today, Thanks, Alex > > > Thanks, > > > Daniel > > > > > > > > > Thanks, > > > > > > Daniel > > > > > > > > > > On 2/3/23 02:58, Alexandre Ghiti wrote: > >> This introduces new properties to allow the user to set the satp mode, > >> see patch 3 for full syntax. In addition, it prevents cpus to boot in a > >> satp mode they do not support (see patch 4). > >> > >> base-commit: commit 75cc28648574 ("configure: remove > >> backwards-compatibility code" > >> > >> v10: > >> - Fix user mode build by surrounding satp handling with #ifndef > >>CONFIG_USER_ONLY, Frank > >> - Fix AB/RB from Frank and Alistair > >> > >> v9: > >> - Move valid_vm[i] up, Andrew > >> - Fixed expansion of the bitmap map, Bin > >> - Rename set_satp_mode_default into set_satp_mode_default_map, Bin > >> - Remove outer parenthesis and alignment, Bin > >> - Fix qemu32 build failure, Bin > >> - Fixed a few typos, Bin > >> - Add RB from Andrew and Bin > >> > >> v8: > >> - Remove useless !map check, Andrew > >> - Add RB from Andrew > >> > >> v7: > >> - Expand map to contain all valid modes, Andrew > >> - Fix commit log for patch 3, Andrew > >> - Remove is_32_bit argument from set_satp_mode_default, Andrew > >> - Move and fixed comment, Andrew > >> - Fix satp_mode_map_max in riscv_cpu_satp_mode_finalize which was set > >>too early, Alex > >> - Remove is_32_bit argument from set_satp_mode_max_supported, Andrew > >> - Use satp_mode directly instead of a string in > >>set_satp_mode_max_supported, Andrew > >> - Swap the patch introducing supported bitmap and the patch that sets > >>sv57 in the dt, Andrew > >> - Add various RB from Andrew and Alistair, thanks > >> > >> v6: > >> - Remove the valid_vm check in validate_vm and add it to the finalize > >> function > >>so that map already contains the constraint, Alex > >> - Add forgotten mbare to satp_mode_from_str, Alex > >> - Move satp mode properties handling to riscv_cpu_satp_mode_finalize, > >> Andrew > >> - Only add satp mode properties corresponding to the cpu, and then remove > >> the > >>check against valid_vm_1_10_32/64 in riscv_cpu_satp_mode_finalize, > >>Andrew/Alistair/Alex > >> - Move mmu-type setting to its own patch, Andrew > >> - patch 5 is new and is a fix, Alex > >> > >> v5: > >> - Simplify v4 implementation by leveraging valid_vm_1_10_32/64, as > >>suggested by Andrew > >> - Split the v4 patch into 2 patches as suggested by Andrew > >> - Lot of other minor corrections, from Andrew > >> - Set the satp mode N by disabling the satp mode N + 1 > >> - Add a helper to set satp mode from a string, as suggested by Frank > >> > >> v4: > >> - Use custom boolean properties instead of OnOffAuto properties, based > >>on ARMVQMap, as suggested by Andrew > >> > >> v3: > >> - Free sv_name as pointed by Bin > >> - Replace satp-mode with boolean properties as suggested by Andrew > >> - Removed RB from Atish as the patch considerably changed > >> > >> v2: > >> - Use error_setg + return as suggested by Alistair > >> - Add RB from Atish > >> - Fixed checkpatch issues missed in v1 > >> - Replaced Ludovic email address with the rivos one > >> > >> Alexandre Ghiti (5): > >>riscv: Pass Object to register_cpu_props instead of DeviceState > >>riscv: Change type of valid_vm_1_10_[32|64] to bool > >>riscv: Allow user to set the satp mode > >>riscv: Introduce satp mode hw capabilities > >>riscv: Correctly set the device-tree entry 'mmu-type' > >> > >> hw/riscv/virt.c| 19 ++-- > >> target/riscv/cpu.c | 271 +++-- > >> target/riscv/cpu.h | 25 + > >> target/riscv/csr.c | 29 +++-- > >> 4 files changed, 313 insertions(+), 31 deletions(-) > >>
[PATCH v10 5/5] riscv: Correctly set the device-tree entry 'mmu-type'
The 'mmu-type' should reflect what the hardware is capable of so use the new satp_mode field in RISCVCPUConfig to do that. Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Reviewed-by: Frank Chang --- hw/riscv/virt.c | 19 ++- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 94ff2a1584..48d034a5f7 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -228,7 +228,8 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, int cpu; uint32_t cpu_phandle; MachineState *mc = MACHINE(s); -char *name, *cpu_name, *core_name, *intc_name; +uint8_t satp_mode_max; +char *name, *cpu_name, *core_name, *intc_name, *sv_name; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { cpu_phandle = (*phandle)++; @@ -236,14 +237,14 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(mc->fdt, cpu_name); -if (riscv_feature(>soc[socket].harts[cpu].env, - RISCV_FEATURE_MMU)) { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -(is_32_bit) ? "riscv,sv32" : "riscv,sv48"); -} else { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -"riscv,none"); -} + +satp_mode_max = satp_mode_max_from_map( +s->soc[socket].harts[cpu].cfg.satp_mode.map); +sv_name = g_strdup_printf("riscv,%s", + satp_mode_str(satp_mode_max, is_32_bit)); +qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); +g_free(sv_name); + name = riscv_isa_string(>soc[socket].harts[cpu]); qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); g_free(name); -- 2.37.2
[PATCH v10 4/5] riscv: Introduce satp mode hw capabilities
Currently, the max satp mode is set with the only constraint that it must be implemented in QEMU, i.e. set in valid_vm_1_10_[32|64]. But we actually need to add another level of constraint: what the hw is actually capable of, because currently, a linux booting on a sifive-u54 boots in sv57 mode which is incompatible with the cpu's sv39 max capability. So add a new bitmap to RISCVSATPMap which contains this capability and initialize it in every XXX_cpu_init. Finally: - valid_vm_1_10_[32|64] constrains which satp mode the CPU can use - the CPU hw capabilities constrains what the user may select - the user's selection then constrains what's available to the guest OS. Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Bin Meng --- target/riscv/cpu.c | 91 +- target/riscv/cpu.h | 8 +++- 2 files changed, 72 insertions(+), 27 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 56057cf87c..7e9924ede9 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -293,18 +293,24 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) g_assert_not_reached(); } -/* Sets the satp mode to the max supported */ -static void set_satp_mode_default_map(RISCVCPU *cpu) +static void set_satp_mode_max_supported(RISCVCPU *cpu, +uint8_t satp_mode) { bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; +const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; -if (riscv_feature(>env, RISCV_FEATURE_MMU)) { -cpu->cfg.satp_mode.map |= -(1 << satp_mode_from_str(rv32 ? "sv32" : "sv57")); -} else { -cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); +for (int i = 0; i <= satp_mode; ++i) { +if (valid_vm[i]) { +cpu->cfg.satp_mode.supported |= (1 << i); +} } } + +/* Set the satp mode to the max supported */ +static void set_satp_mode_default_map(RISCVCPU *cpu) +{ +cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported; +} #endif static void riscv_any_cpu_init(Object *obj) @@ -315,6 +321,13 @@ static void riscv_any_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif + +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(RISCV_CPU(obj), +riscv_cpu_mxl(_CPU(obj)->env) == MXL_RV32 ? +VM_1_10_SV32 : VM_1_10_SV57); +#endif + set_priv_version(env, PRIV_VERSION_1_12_0); register_cpu_props(obj); } @@ -328,6 +341,9 @@ static void rv64_base_cpu_init(Object *obj) register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57); +#endif } static void rv64_sifive_u_cpu_init(Object *obj) @@ -335,6 +351,9 @@ static void rv64_sifive_u_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV39); +#endif } static void rv64_sifive_e_cpu_init(Object *obj) @@ -345,6 +364,9 @@ static void rv64_sifive_e_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); cpu->cfg.mmu = false; +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(cpu, VM_1_10_MBARE); +#endif } static void rv128_base_cpu_init(Object *obj) @@ -361,6 +383,9 @@ static void rv128_base_cpu_init(Object *obj) register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57); +#endif } #else static void rv32_base_cpu_init(Object *obj) @@ -371,6 +396,9 @@ static void rv32_base_cpu_init(Object *obj) register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32); +#endif } static void rv32_sifive_u_cpu_init(Object *obj) @@ -378,6 +406,9 @@ static void rv32_sifive_u_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); +#ifndef CONFIG_USER_ONLY +set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32); +#endif } static void rv32_sifive_e_cpu_init(Object *obj) @@ -388,6 +419,9 @@ static void rv32_sifive_e_cpu_init(Object *obj) set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU);
[PATCH v10 3/5] riscv: Allow user to set the satp mode
RISC-V specifies multiple sizes for addressable memory and Linux probes for the machine's support at startup via the satp CSR register (done in csr.c:validate_vm). As per the specification, sv64 must support sv57, which in turn must support sv48...etc. So we can restrict machine support by simply setting the "highest" supported mode and the bare mode is always supported. You can set the satp mode using the new properties "sv32", "sv39", "sv48", "sv57" and "sv64" as follows: -cpu rv64,sv57=on # Linux will boot using sv57 scheme -cpu rv64,sv39=on # Linux will boot using sv39 scheme -cpu rv64,sv57=off # Linux will boot using sv48 scheme -cpu rv64 # Linux will boot using sv57 scheme by default We take the highest level set by the user: -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme We make sure that invalid configurations are rejected: -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are # enabled We accept "redundant" configurations: -cpu rv64,sv48=on,sv57=off # Linux will boot using sv48 scheme And contradictory configurations: -cpu rv64,sv48=on,sv48=off # Linux will boot using sv39 scheme Co-Developed-by: Ludovic Henry Signed-off-by: Ludovic Henry Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Bin Meng Acked-by: Alistair Francis --- target/riscv/cpu.c | 215 + target/riscv/cpu.h | 21 + target/riscv/csr.c | 12 ++- 3 files changed, 241 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 7181b34f86..56057cf87c 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -27,6 +27,7 @@ #include "time_helper.h" #include "exec/exec-all.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "qemu/error-report.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" @@ -229,6 +230,83 @@ static void set_vext_version(CPURISCVState *env, int vext_ver) env->vext_ver = vext_ver; } +#ifndef CONFIG_USER_ONLY +static uint8_t satp_mode_from_str(const char *satp_mode_str) +{ +if (!strncmp(satp_mode_str, "mbare", 5)) { +return VM_1_10_MBARE; +} + +if (!strncmp(satp_mode_str, "sv32", 4)) { +return VM_1_10_SV32; +} + +if (!strncmp(satp_mode_str, "sv39", 4)) { +return VM_1_10_SV39; +} + +if (!strncmp(satp_mode_str, "sv48", 4)) { +return VM_1_10_SV48; +} + +if (!strncmp(satp_mode_str, "sv57", 4)) { +return VM_1_10_SV57; +} + +if (!strncmp(satp_mode_str, "sv64", 4)) { +return VM_1_10_SV64; +} + +g_assert_not_reached(); +} + +uint8_t satp_mode_max_from_map(uint32_t map) +{ +/* map here has at least one bit set, so no problem with clz */ +return 31 - __builtin_clz(map); +} + +const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) +{ +if (is_32_bit) { +switch (satp_mode) { +case VM_1_10_SV32: +return "sv32"; +case VM_1_10_MBARE: +return "none"; +} +} else { +switch (satp_mode) { +case VM_1_10_SV64: +return "sv64"; +case VM_1_10_SV57: +return "sv57"; +case VM_1_10_SV48: +return "sv48"; +case VM_1_10_SV39: +return "sv39"; +case VM_1_10_MBARE: +return "none"; +} +} + +g_assert_not_reached(); +} + +/* Sets the satp mode to the max supported */ +static void set_satp_mode_default_map(RISCVCPU *cpu) +{ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; + +if (riscv_feature(>env, RISCV_FEATURE_MMU)) { +cpu->cfg.satp_mode.map |= +(1 << satp_mode_from_str(rv32 ? "sv32" : "sv57")); +} else { +cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); +} +} +#endif + static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; @@ -619,6 +697,87 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) } } +#ifndef CONFIG_USER_ONLY +static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) +{ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; +const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; +uint8_t satp_mode_max; + +if (cpu->cfg.satp_mode.map == 0) { +if (cpu->cfg.satp_mode.init == 0) { +/* If unset by the user, we fallback to the default satp mode. */ +set_satp_mode_default_map(cpu); +} else { +/* + * Find the lowest level that was disabled and then ena
[PATCH v10 2/5] riscv: Change type of valid_vm_1_10_[32|64] to bool
This array is actually used as a boolean so swap its current char type to a boolean and at the same time, change the type of validate_vm to bool since it returns valid_vm_1_10_[32|64]. Suggested-by: Andrew Jones Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Reviewed-by: Bin Meng Reviewed-by: Frank Chang --- target/riscv/csr.c | 21 +++-- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 0db2c233e5..6b157806a5 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1117,16 +1117,16 @@ static const target_ulong hip_writable_mask = MIP_VSSIP; static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; static const target_ulong vsip_writable_mask = MIP_VSSIP; -static const char valid_vm_1_10_32[16] = { -[VM_1_10_MBARE] = 1, -[VM_1_10_SV32] = 1 +static const bool valid_vm_1_10_32[16] = { +[VM_1_10_MBARE] = true, +[VM_1_10_SV32] = true }; -static const char valid_vm_1_10_64[16] = { -[VM_1_10_MBARE] = 1, -[VM_1_10_SV39] = 1, -[VM_1_10_SV48] = 1, -[VM_1_10_SV57] = 1 +static const bool valid_vm_1_10_64[16] = { +[VM_1_10_MBARE] = true, +[VM_1_10_SV39] = true, +[VM_1_10_SV48] = true, +[VM_1_10_SV57] = true }; /* Machine Information Registers */ @@ -1209,7 +1209,7 @@ static RISCVException read_mstatus(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int validate_vm(CPURISCVState *env, target_ulong vm) +static bool validate_vm(CPURISCVState *env, target_ulong vm) { if (riscv_cpu_mxl(env) == MXL_RV32) { return valid_vm_1_10_32[vm & 0xf]; @@ -2648,7 +2648,8 @@ static RISCVException read_satp(CPURISCVState *env, int csrno, static RISCVException write_satp(CPURISCVState *env, int csrno, target_ulong val) { -target_ulong vm, mask; +target_ulong mask; +bool vm; if (!riscv_feature(env, RISCV_FEATURE_MMU)) { return RISCV_EXCP_NONE; -- 2.37.2
[PATCH v10 1/5] riscv: Pass Object to register_cpu_props instead of DeviceState
One can extract the DeviceState pointer from the Object pointer, so pass the Object for future commits to access other fields of Object. No functional changes intended. Signed-off-by: Alexandre Ghiti Reviewed-by: Alistair Francis Reviewed-by: Frank Chang Reviewed-by: Andrew Jones Reviewed-by: Bin Meng --- target/riscv/cpu.c | 15 --- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index cc75ca7667..7181b34f86 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -200,7 +200,7 @@ static const char * const riscv_intr_names[] = { "reserved" }; -static void register_cpu_props(DeviceState *dev); +static void register_cpu_props(Object *obj); const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) { @@ -238,7 +238,7 @@ static void riscv_any_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif set_priv_version(env, PRIV_VERSION_1_12_0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #if defined(TARGET_RISCV64) @@ -247,7 +247,7 @@ static void rv64_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -280,7 +280,7 @@ static void rv128_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -290,7 +290,7 @@ static void rv32_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV32, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -343,7 +343,7 @@ static void riscv_host_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, 0); #endif -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #endif @@ -1083,9 +1083,10 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_END_OF_LIST(), }; -static void register_cpu_props(DeviceState *dev) +static void register_cpu_props(Object *obj) { Property *prop; +DeviceState *dev = DEVICE(obj); for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { qdev_property_add_static(dev, prop); -- 2.37.2
[PATCH v10 0/5] riscv: Allow user to set the satp mode
This introduces new properties to allow the user to set the satp mode, see patch 3 for full syntax. In addition, it prevents cpus to boot in a satp mode they do not support (see patch 4). base-commit: commit 75cc28648574 ("configure: remove backwards-compatibility code" v10: - Fix user mode build by surrounding satp handling with #ifndef CONFIG_USER_ONLY, Frank - Fix AB/RB from Frank and Alistair v9: - Move valid_vm[i] up, Andrew - Fixed expansion of the bitmap map, Bin - Rename set_satp_mode_default into set_satp_mode_default_map, Bin - Remove outer parenthesis and alignment, Bin - Fix qemu32 build failure, Bin - Fixed a few typos, Bin - Add RB from Andrew and Bin v8: - Remove useless !map check, Andrew - Add RB from Andrew v7: - Expand map to contain all valid modes, Andrew - Fix commit log for patch 3, Andrew - Remove is_32_bit argument from set_satp_mode_default, Andrew - Move and fixed comment, Andrew - Fix satp_mode_map_max in riscv_cpu_satp_mode_finalize which was set too early, Alex - Remove is_32_bit argument from set_satp_mode_max_supported, Andrew - Use satp_mode directly instead of a string in set_satp_mode_max_supported, Andrew - Swap the patch introducing supported bitmap and the patch that sets sv57 in the dt, Andrew - Add various RB from Andrew and Alistair, thanks v6: - Remove the valid_vm check in validate_vm and add it to the finalize function so that map already contains the constraint, Alex - Add forgotten mbare to satp_mode_from_str, Alex - Move satp mode properties handling to riscv_cpu_satp_mode_finalize, Andrew - Only add satp mode properties corresponding to the cpu, and then remove the check against valid_vm_1_10_32/64 in riscv_cpu_satp_mode_finalize, Andrew/Alistair/Alex - Move mmu-type setting to its own patch, Andrew - patch 5 is new and is a fix, Alex v5: - Simplify v4 implementation by leveraging valid_vm_1_10_32/64, as suggested by Andrew - Split the v4 patch into 2 patches as suggested by Andrew - Lot of other minor corrections, from Andrew - Set the satp mode N by disabling the satp mode N + 1 - Add a helper to set satp mode from a string, as suggested by Frank v4: - Use custom boolean properties instead of OnOffAuto properties, based on ARMVQMap, as suggested by Andrew v3: - Free sv_name as pointed by Bin - Replace satp-mode with boolean properties as suggested by Andrew - Removed RB from Atish as the patch considerably changed v2: - Use error_setg + return as suggested by Alistair - Add RB from Atish - Fixed checkpatch issues missed in v1 - Replaced Ludovic email address with the rivos one Alexandre Ghiti (5): riscv: Pass Object to register_cpu_props instead of DeviceState riscv: Change type of valid_vm_1_10_[32|64] to bool riscv: Allow user to set the satp mode riscv: Introduce satp mode hw capabilities riscv: Correctly set the device-tree entry 'mmu-type' hw/riscv/virt.c| 19 ++-- target/riscv/cpu.c | 271 +++-- target/riscv/cpu.h | 25 + target/riscv/csr.c | 29 +++-- 4 files changed, 313 insertions(+), 31 deletions(-) -- 2.37.2
Re: [PATCH v9 4/5] riscv: Introduce satp mode hw capabilities
Hi Frank, On Wed, Feb 1, 2023 at 4:49 PM Frank Chang wrote: > > On Tue, Jan 31, 2023 at 10:36 PM Alexandre Ghiti > wrote: >> >> Currently, the max satp mode is set with the only constraint that it must be >> implemented in QEMU, i.e. set in valid_vm_1_10_[32|64]. >> >> But we actually need to add another level of constraint: what the hw is >> actually capable of, because currently, a linux booting on a sifive-u54 >> boots in sv57 mode which is incompatible with the cpu's sv39 max >> capability. >> >> So add a new bitmap to RISCVSATPMap which contains this capability and >> initialize it in every XXX_cpu_init. >> >> Finally: >> - valid_vm_1_10_[32|64] constrains which satp mode the CPU can use >> - the CPU hw capabilities constrains what the user may select >> - the user's selection then constrains what's available to the guest >> OS. >> >> Signed-off-by: Alexandre Ghiti >> Reviewed-by: Andrew Jones >> --- >> target/riscv/cpu.c | 79 +++--- >> target/riscv/cpu.h | 8 +++-- >> 2 files changed, 60 insertions(+), 27 deletions(-) >> >> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c >> index 3a7a1746aa..6dd76355ec 100644 >> --- a/target/riscv/cpu.c >> +++ b/target/riscv/cpu.c >> @@ -292,26 +292,36 @@ const char *satp_mode_str(uint8_t satp_mode, bool >> is_32_bit) >> g_assert_not_reached(); >> } >> >> -/* Sets the satp mode to the max supported */ >> -static void set_satp_mode_default_map(RISCVCPU *cpu) >> +static void set_satp_mode_max_supported(RISCVCPU *cpu, >> +uint8_t satp_mode) >> { >> bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; >> +const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; > > > This will break user-mode QEMU. > valid_vm_1_10_32 and valid_vm_1_10_64 are defined in !CONFIG_USER_ONLY > section. > This issue also exists in patch 3. > You have to move valid_vm_1_10_32 and valid_vm_1_10_64 out from > !CONFIG_USER_ONLY. Indeed, good catch, thanks! Rather than moving valid_vm_1_10_[32|64], I'm going to try to surround all the satp handling inside #ifdef CONFIG_USER_ONLY. But if it's too cumbersome, I'll do as you suggest. Thanks again, Alex > > Regards, > Frank Chang > >> >> -if (riscv_feature(>env, RISCV_FEATURE_MMU)) { >> -cpu->cfg.satp_mode.map |= >> -(1 << satp_mode_from_str(rv32 ? "sv32" : "sv57")); >> -} else { >> -cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); >> +for (int i = 0; i <= satp_mode; ++i) { >> +if (valid_vm[i]) { >> +cpu->cfg.satp_mode.supported |= (1 << i); >> +} >> } >> } >> >> +/* Set the satp mode to the max supported */ >> +static void set_satp_mode_default_map(RISCVCPU *cpu) >> +{ >> +cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported; >> +} >> + >> static void riscv_any_cpu_init(Object *obj) >> { >> CPURISCVState *env = _CPU(obj)->env; >> +RISCVCPU *cpu = RISCV_CPU(obj); >> + >> #if defined(TARGET_RISCV32) >> set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU); >> +set_satp_mode_max_supported(cpu, VM_1_10_SV32); >> #elif defined(TARGET_RISCV64) >> set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); >> +set_satp_mode_max_supported(cpu, VM_1_10_SV57); >> #endif >> set_priv_version(env, PRIV_VERSION_1_12_0); >> register_cpu_props(obj); >> @@ -321,18 +331,24 @@ static void riscv_any_cpu_init(Object *obj) >> static void rv64_base_cpu_init(Object *obj) >> { >> CPURISCVState *env = _CPU(obj)->env; >> +RISCVCPU *cpu = RISCV_CPU(obj); >> + >> /* We set this in the realise function */ >> set_misa(env, MXL_RV64, 0); >> register_cpu_props(obj); >> /* Set latest version of privileged specification */ >> set_priv_version(env, PRIV_VERSION_1_12_0); >> +set_satp_mode_max_supported(cpu, VM_1_10_SV57); >> } >> >> static void rv64_sifive_u_cpu_init(Object *obj) >> { >> CPURISCVState *env = _CPU(obj)->env; >> +RISCVCPU *cpu = RISCV_CPU(obj); >> + >> set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); >> set_priv_version(env, PRIV_VERSION_1_10_0); >> +set_satp_mode_max_supported(cpu, VM_1_10_SV39); >> } >>
Re: [PATCH v8 4/5] riscv: Introduce satp mode hw capabilities
On Mon, Jan 30, 2023 at 5:29 AM Bin Meng wrote: > > On Thu, Jan 26, 2023 at 12:24 AM Alexandre Ghiti > wrote: > > > > Currently, the max satp mode is set with the only constraint that it must be > > implemented in qemu, i.e. set in valid_vm_1_10_[32|64]. > > nits: s/qemu/QEMU/g Ok > > > > > But we actually need to add another level of constraint: what the hw is > > actually capable of, because currently, a linux booting on a sifive-u54 > > boots in sv57 mode which is incompatible with the cpu's sv39 max > > capability. > > > > So add a new bitmap to RISCVSATPMap which contains this capability and > > initialize it in every XXX_cpu_init. > > > > Finally: > > - valid_vm_1_10_[32|64] constrains which satp mode the CPU can use > > - the CPU hw capabilities constrains what the user may select > > - the user's selection then constrains what's available to the guest > > OS. > > > > Signed-off-by: Alexandre Ghiti > > Reviewed-by: Andrew Jones > > --- > > target/riscv/cpu.c | 74 +++--- > > target/riscv/cpu.h | 8 +++-- > > 2 files changed, 56 insertions(+), 26 deletions(-) > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index 54494a72be..e7e1fb96dc 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -292,26 +292,36 @@ const char *satp_mode_str(uint8_t satp_mode, bool > > is_32_bit) > > g_assert_not_reached(); > > } > > > > -/* Sets the satp mode to the max supported */ > > -static void set_satp_mode_default(RISCVCPU *cpu) > > +static void set_satp_mode_max_supported(RISCVCPU *cpu, > > +uint8_t satp_mode) > > { > > bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; > > +const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; > > > > -if (riscv_feature(>env, RISCV_FEATURE_MMU)) { > > -cpu->cfg.satp_mode.map |= > > -(1 << satp_mode_from_str(rv32 ? "sv32" : "sv57")); > > -} else { > > -cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); > > +for (int i = 0; i <= satp_mode; ++i) { > > +if (valid_vm[i]) { > > +cpu->cfg.satp_mode.supported |= (1 << i); > > +} > > } > > } > > > > +/* Sets the satp mode to the max supported */ > > nits: s/Sets/Set Ok > > > +static void set_satp_mode_default(RISCVCPU *cpu) > > +{ > > +cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported; > > +} > > + > > static void riscv_any_cpu_init(Object *obj) > > { > > CPURISCVState *env = _CPU(obj)->env; > > +RISCVCPU *cpu = RISCV_CPU(obj); > > + > > #if defined(TARGET_RISCV32) > > set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU); > > +set_satp_mode_max_supported(cpu, VM_1_10_SV32); > > #elif defined(TARGET_RISCV64) > > set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); > > +set_satp_mode_max_supported(cpu, VM_1_10_SV57); > > #endif > > set_priv_version(env, PRIV_VERSION_1_12_0); > > register_cpu_props(obj); > > @@ -321,18 +331,24 @@ static void riscv_any_cpu_init(Object *obj) > > static void rv64_base_cpu_init(Object *obj) > > { > > CPURISCVState *env = _CPU(obj)->env; > > +RISCVCPU *cpu = RISCV_CPU(obj); > > + > > /* We set this in the realise function */ > > set_misa(env, MXL_RV64, 0); > > register_cpu_props(obj); > > /* Set latest version of privileged specification */ > > set_priv_version(env, PRIV_VERSION_1_12_0); > > +set_satp_mode_max_supported(cpu, VM_1_10_SV57); > > } > > > > static void rv64_sifive_u_cpu_init(Object *obj) > > { > > CPURISCVState *env = _CPU(obj)->env; > > +RISCVCPU *cpu = RISCV_CPU(obj); > > + > > set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); > > set_priv_version(env, PRIV_VERSION_1_10_0); > > +set_satp_mode_max_supported(cpu, VM_1_10_SV39); > > } > > > > static void rv64_sifive_e_cpu_init(Object *obj) > > @@ -343,6 +359,7 @@ static void rv64_sifive_e_cpu_init(Object *obj) > > set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); > > set_priv_version(env, PRIV_VERSION_1_10_0); > > cpu->cfg.mmu = false; > > +set_satp_mode_max_supported(cpu, VM_1_10_MBARE); > > } >
[PATCH v9 3/5] riscv: Allow user to set the satp mode
RISC-V specifies multiple sizes for addressable memory and Linux probes for the machine's support at startup via the satp CSR register (done in csr.c:validate_vm). As per the specification, sv64 must support sv57, which in turn must support sv48...etc. So we can restrict machine support by simply setting the "highest" supported mode and the bare mode is always supported. You can set the satp mode using the new properties "sv32", "sv39", "sv48", "sv57" and "sv64" as follows: -cpu rv64,sv57=on # Linux will boot using sv57 scheme -cpu rv64,sv39=on # Linux will boot using sv39 scheme -cpu rv64,sv57=off # Linux will boot using sv48 scheme -cpu rv64 # Linux will boot using sv57 scheme by default We take the highest level set by the user: -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme We make sure that invalid configurations are rejected: -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are # enabled We accept "redundant" configurations: -cpu rv64,sv48=on,sv57=off # Linux will boot using sv48 scheme And contradictory configurations: -cpu rv64,sv48=on,sv48=off # Linux will boot using sv39 scheme Co-Developed-by: Ludovic Henry Signed-off-by: Ludovic Henry Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones --- target/riscv/cpu.c | 207 + target/riscv/cpu.h | 19 + target/riscv/csr.c | 12 ++- 3 files changed, 231 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 7181b34f86..3a7a1746aa 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -27,6 +27,7 @@ #include "time_helper.h" #include "exec/exec-all.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "qemu/error-report.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" @@ -229,6 +230,81 @@ static void set_vext_version(CPURISCVState *env, int vext_ver) env->vext_ver = vext_ver; } +static uint8_t satp_mode_from_str(const char *satp_mode_str) +{ +if (!strncmp(satp_mode_str, "mbare", 5)) { +return VM_1_10_MBARE; +} + +if (!strncmp(satp_mode_str, "sv32", 4)) { +return VM_1_10_SV32; +} + +if (!strncmp(satp_mode_str, "sv39", 4)) { +return VM_1_10_SV39; +} + +if (!strncmp(satp_mode_str, "sv48", 4)) { +return VM_1_10_SV48; +} + +if (!strncmp(satp_mode_str, "sv57", 4)) { +return VM_1_10_SV57; +} + +if (!strncmp(satp_mode_str, "sv64", 4)) { +return VM_1_10_SV64; +} + +g_assert_not_reached(); +} + +uint8_t satp_mode_max_from_map(uint32_t map) +{ +/* map here has at least one bit set, so no problem with clz */ +return 31 - __builtin_clz(map); +} + +const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) +{ +if (is_32_bit) { +switch (satp_mode) { +case VM_1_10_SV32: +return "sv32"; +case VM_1_10_MBARE: +return "none"; +} +} else { +switch (satp_mode) { +case VM_1_10_SV64: +return "sv64"; +case VM_1_10_SV57: +return "sv57"; +case VM_1_10_SV48: +return "sv48"; +case VM_1_10_SV39: +return "sv39"; +case VM_1_10_MBARE: +return "none"; +} +} + +g_assert_not_reached(); +} + +/* Sets the satp mode to the max supported */ +static void set_satp_mode_default_map(RISCVCPU *cpu) +{ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; + +if (riscv_feature(>env, RISCV_FEATURE_MMU)) { +cpu->cfg.satp_mode.map |= +(1 << satp_mode_from_str(rv32 ? "sv32" : "sv57")); +} else { +cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); +} +} + static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; @@ -619,6 +695,83 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) } } +static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) +{ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; +const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; +uint8_t satp_mode_max; + +if (cpu->cfg.satp_mode.map == 0) { +if (cpu->cfg.satp_mode.init == 0) { +/* If unset by the user, we fallback to the default satp mode. */ +set_satp_mode_default_map(cpu); +} else { +/* + * Find the lowest level that was disabled and then enable the + * first valid level below which can be found in + * valid_vm_1_10_32/6
Re: [PATCH v8 3/5] riscv: Allow user to set the satp mode
On Wed, Jan 25, 2023 at 5:52 PM Andrew Jones wrote: > > On Wed, Jan 25, 2023 at 05:20:08PM +0100, Alexandre Ghiti wrote: > > RISC-V specifies multiple sizes for addressable memory and Linux probes for > > the machine's support at startup via the satp CSR register (done in > > csr.c:validate_vm). > > > > As per the specification, sv64 must support sv57, which in turn must > > support sv48...etc. So we can restrict machine support by simply setting the > > "highest" supported mode and the bare mode is always supported. > > > > You can set the satp mode using the new properties "sv32", "sv39", "sv48", > > "sv57" and "sv64" as follows: > > -cpu rv64,sv57=on # Linux will boot using sv57 scheme > > -cpu rv64,sv39=on # Linux will boot using sv39 scheme > > -cpu rv64,sv57=off # Linux will boot using sv48 scheme > > -cpu rv64 # Linux will boot using sv57 scheme by default > > > > We take the highest level set by the user: > > -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme > > > > We make sure that invalid configurations are rejected: > > -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are > ># enabled > > > > We accept "redundant" configurations: > > -cpu rv64,sv48=on,sv57=off # Linux will boot using sv48 scheme > > > > And contradictory configurations: > > -cpu rv64,sv48=on,sv48=off # Linux will boot using sv39 scheme > > > > Co-Developed-by: Ludovic Henry > > Signed-off-by: Ludovic Henry > > Signed-off-by: Alexandre Ghiti > > --- > > target/riscv/cpu.c | 206 + > > target/riscv/cpu.h | 19 + > > target/riscv/csr.c | 12 ++- > > 3 files changed, 230 insertions(+), 7 deletions(-) > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index 7181b34f86..54494a72be 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -27,6 +27,7 @@ > > #include "time_helper.h" > > #include "exec/exec-all.h" > > #include "qapi/error.h" > > +#include "qapi/visitor.h" > > #include "qemu/error-report.h" > > #include "hw/qdev-properties.h" > > #include "migration/vmstate.h" > > @@ -229,6 +230,81 @@ static void set_vext_version(CPURISCVState *env, int > > vext_ver) > > env->vext_ver = vext_ver; > > } > > > > +static uint8_t satp_mode_from_str(const char *satp_mode_str) > > +{ > > +if (!strncmp(satp_mode_str, "mbare", 5)) { > > +return VM_1_10_MBARE; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv32", 4)) { > > +return VM_1_10_SV32; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv39", 4)) { > > +return VM_1_10_SV39; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv48", 4)) { > > +return VM_1_10_SV48; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv57", 4)) { > > +return VM_1_10_SV57; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv64", 4)) { > > +return VM_1_10_SV64; > > +} > > + > > +g_assert_not_reached(); > > +} > > + > > +uint8_t satp_mode_max_from_map(uint32_t map) > > +{ > > +/* map here has at least one bit set, so no problem with clz */ > > +return 31 - __builtin_clz(map); > > +} > > + > > +const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) > > +{ > > +if (is_32_bit) { > > +switch (satp_mode) { > > +case VM_1_10_SV32: > > +return "sv32"; > > +case VM_1_10_MBARE: > > +return "none"; > > +} > > +} else { > > +switch (satp_mode) { > > +case VM_1_10_SV64: > > +return "sv64"; > > +case VM_1_10_SV57: > > +return "sv57"; > > +case VM_1_10_SV48: > > +return "sv48"; > > +case VM_1_10_SV39: > > +return "sv39"; > > +case VM_1_10_MBARE: > > +return "none"; > > +} > > +} > > + > > +g_assert_not_reached(); > > +} > > + > > +/* Sets the satp mode to the max supported */ > > +static void set_satp_mode_defau
[PATCH v9 4/5] riscv: Introduce satp mode hw capabilities
Currently, the max satp mode is set with the only constraint that it must be implemented in QEMU, i.e. set in valid_vm_1_10_[32|64]. But we actually need to add another level of constraint: what the hw is actually capable of, because currently, a linux booting on a sifive-u54 boots in sv57 mode which is incompatible with the cpu's sv39 max capability. So add a new bitmap to RISCVSATPMap which contains this capability and initialize it in every XXX_cpu_init. Finally: - valid_vm_1_10_[32|64] constrains which satp mode the CPU can use - the CPU hw capabilities constrains what the user may select - the user's selection then constrains what's available to the guest OS. Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones --- target/riscv/cpu.c | 79 +++--- target/riscv/cpu.h | 8 +++-- 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 3a7a1746aa..6dd76355ec 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -292,26 +292,36 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) g_assert_not_reached(); } -/* Sets the satp mode to the max supported */ -static void set_satp_mode_default_map(RISCVCPU *cpu) +static void set_satp_mode_max_supported(RISCVCPU *cpu, +uint8_t satp_mode) { bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; +const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; -if (riscv_feature(>env, RISCV_FEATURE_MMU)) { -cpu->cfg.satp_mode.map |= -(1 << satp_mode_from_str(rv32 ? "sv32" : "sv57")); -} else { -cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); +for (int i = 0; i <= satp_mode; ++i) { +if (valid_vm[i]) { +cpu->cfg.satp_mode.supported |= (1 << i); +} } } +/* Set the satp mode to the max supported */ +static void set_satp_mode_default_map(RISCVCPU *cpu) +{ +cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported; +} + static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + #if defined(TARGET_RISCV32) set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU); +set_satp_mode_max_supported(cpu, VM_1_10_SV32); #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); +set_satp_mode_max_supported(cpu, VM_1_10_SV57); #endif set_priv_version(env, PRIV_VERSION_1_12_0); register_cpu_props(obj); @@ -321,18 +331,24 @@ static void riscv_any_cpu_init(Object *obj) static void rv64_base_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV57); } static void rv64_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV39); } static void rv64_sifive_e_cpu_init(Object *obj) @@ -343,6 +359,7 @@ static void rv64_sifive_e_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); cpu->cfg.mmu = false; +set_satp_mode_max_supported(cpu, VM_1_10_MBARE); } static void rv128_base_cpu_init(Object *obj) @@ -354,28 +371,36 @@ static void rv128_base_cpu_init(Object *obj) exit(EXIT_FAILURE); } CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV57); } #else static void rv32_base_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + /* We set this in the realise function */ set_misa(env, MXL_RV32, 0); register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV32); } static void rv32_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); +set_satp_mode_max_supported(cpu, VM_1_10
[PATCH v9 0/5] riscv: Allow user to set the satp mode
This introduces new properties to allow the user to set the satp mode, see patch 3 for full syntax. In addition, it prevents cpus to boot in a satp mode they do not support (see patch 4). v9: - Move valid_vm[i] up, Andrew - Fixed expansion of the bitmap map, Bin - Rename set_satp_mode_default into set_satp_mode_default_map, Bin - Remove outer parenthesis and alignment, Bin - Fix qemu32 build failure, Bin - Fixed a few typos, Bin - Add RB from Andrew and Bin v8: - Remove useless !map check, Andrew - Add RB from Andrew v7: - Expand map to contain all valid modes, Andrew - Fix commit log for patch 3, Andrew - Remove is_32_bit argument from set_satp_mode_default, Andrew - Move and fixed comment, Andrew - Fix satp_mode_map_max in riscv_cpu_satp_mode_finalize which was set too early, Alex - Remove is_32_bit argument from set_satp_mode_max_supported, Andrew - Use satp_mode directly instead of a string in set_satp_mode_max_supported, Andrew - Swap the patch introducing supported bitmap and the patch that sets sv57 in the dt, Andrew - Add various RB from Andrew and Alistair, thanks v6: - Remove the valid_vm check in validate_vm and add it to the finalize function so that map already contains the constraint, Alex - Add forgotten mbare to satp_mode_from_str, Alex - Move satp mode properties handling to riscv_cpu_satp_mode_finalize, Andrew - Only add satp mode properties corresponding to the cpu, and then remove the check against valid_vm_1_10_32/64 in riscv_cpu_satp_mode_finalize, Andrew/Alistair/Alex - Move mmu-type setting to its own patch, Andrew - patch 5 is new and is a fix, Alex v5: - Simplify v4 implementation by leveraging valid_vm_1_10_32/64, as suggested by Andrew - Split the v4 patch into 2 patches as suggested by Andrew - Lot of other minor corrections, from Andrew - Set the satp mode N by disabling the satp mode N + 1 - Add a helper to set satp mode from a string, as suggested by Frank v4: - Use custom boolean properties instead of OnOffAuto properties, based on ARMVQMap, as suggested by Andrew v3: - Free sv_name as pointed by Bin - Replace satp-mode with boolean properties as suggested by Andrew - Removed RB from Atish as the patch considerably changed v2: - Use error_setg + return as suggested by Alistair - Add RB from Atish - Fixed checkpatch issues missed in v1 - Replaced Ludovic email address with the rivos one Alexandre Ghiti (5): riscv: Pass Object to register_cpu_props instead of DeviceState riscv: Change type of valid_vm_1_10_[32|64] to bool riscv: Allow user to set the satp mode riscv: Introduce satp mode hw capabilities riscv: Correctly set the device-tree entry 'mmu-type' hw/riscv/virt.c| 19 ++-- target/riscv/cpu.c | 251 +++-- target/riscv/cpu.h | 23 + target/riscv/csr.c | 29 +++--- 4 files changed, 291 insertions(+), 31 deletions(-) -- 2.37.2
[PATCH v9 1/5] riscv: Pass Object to register_cpu_props instead of DeviceState
One can extract the DeviceState pointer from the Object pointer, so pass the Object for future commits to access other fields of Object. No functional changes intended. Signed-off-by: Alexandre Ghiti Reviewed-by: Alistair Francis Reviewed-by: Frank Chang Reviewed-by: Andrew Jones Reviewed-by: Bin Meng --- target/riscv/cpu.c | 15 --- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index cc75ca7667..7181b34f86 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -200,7 +200,7 @@ static const char * const riscv_intr_names[] = { "reserved" }; -static void register_cpu_props(DeviceState *dev); +static void register_cpu_props(Object *obj); const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) { @@ -238,7 +238,7 @@ static void riscv_any_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif set_priv_version(env, PRIV_VERSION_1_12_0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #if defined(TARGET_RISCV64) @@ -247,7 +247,7 @@ static void rv64_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -280,7 +280,7 @@ static void rv128_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -290,7 +290,7 @@ static void rv32_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV32, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -343,7 +343,7 @@ static void riscv_host_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, 0); #endif -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #endif @@ -1083,9 +1083,10 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_END_OF_LIST(), }; -static void register_cpu_props(DeviceState *dev) +static void register_cpu_props(Object *obj) { Property *prop; +DeviceState *dev = DEVICE(obj); for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { qdev_property_add_static(dev, prop); -- 2.37.2
[PATCH v9 5/5] riscv: Correctly set the device-tree entry 'mmu-type'
The 'mmu-type' should reflect what the hardware is capable of so use the new satp_mode field in RISCVCPUConfig to do that. Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Reviewed-by: Bin Meng --- hw/riscv/virt.c | 19 ++- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 94ff2a1584..48d034a5f7 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -228,7 +228,8 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, int cpu; uint32_t cpu_phandle; MachineState *mc = MACHINE(s); -char *name, *cpu_name, *core_name, *intc_name; +uint8_t satp_mode_max; +char *name, *cpu_name, *core_name, *intc_name, *sv_name; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { cpu_phandle = (*phandle)++; @@ -236,14 +237,14 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(mc->fdt, cpu_name); -if (riscv_feature(>soc[socket].harts[cpu].env, - RISCV_FEATURE_MMU)) { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -(is_32_bit) ? "riscv,sv32" : "riscv,sv48"); -} else { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -"riscv,none"); -} + +satp_mode_max = satp_mode_max_from_map( +s->soc[socket].harts[cpu].cfg.satp_mode.map); +sv_name = g_strdup_printf("riscv,%s", + satp_mode_str(satp_mode_max, is_32_bit)); +qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); +g_free(sv_name); + name = riscv_isa_string(>soc[socket].harts[cpu]); qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); g_free(name); -- 2.37.2
[PATCH v9 2/5] riscv: Change type of valid_vm_1_10_[32|64] to bool
This array is actually used as a boolean so swap its current char type to a boolean and at the same time, change the type of validate_vm to bool since it returns valid_vm_1_10_[32|64]. Suggested-by: Andrew Jones Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Reviewed-by: Bin Meng --- target/riscv/csr.c | 21 +++-- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 0db2c233e5..6b157806a5 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1117,16 +1117,16 @@ static const target_ulong hip_writable_mask = MIP_VSSIP; static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; static const target_ulong vsip_writable_mask = MIP_VSSIP; -static const char valid_vm_1_10_32[16] = { -[VM_1_10_MBARE] = 1, -[VM_1_10_SV32] = 1 +static const bool valid_vm_1_10_32[16] = { +[VM_1_10_MBARE] = true, +[VM_1_10_SV32] = true }; -static const char valid_vm_1_10_64[16] = { -[VM_1_10_MBARE] = 1, -[VM_1_10_SV39] = 1, -[VM_1_10_SV48] = 1, -[VM_1_10_SV57] = 1 +static const bool valid_vm_1_10_64[16] = { +[VM_1_10_MBARE] = true, +[VM_1_10_SV39] = true, +[VM_1_10_SV48] = true, +[VM_1_10_SV57] = true }; /* Machine Information Registers */ @@ -1209,7 +1209,7 @@ static RISCVException read_mstatus(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int validate_vm(CPURISCVState *env, target_ulong vm) +static bool validate_vm(CPURISCVState *env, target_ulong vm) { if (riscv_cpu_mxl(env) == MXL_RV32) { return valid_vm_1_10_32[vm & 0xf]; @@ -2648,7 +2648,8 @@ static RISCVException read_satp(CPURISCVState *env, int csrno, static RISCVException write_satp(CPURISCVState *env, int csrno, target_ulong val) { -target_ulong vm, mask; +target_ulong mask; +bool vm; if (!riscv_feature(env, RISCV_FEATURE_MMU)) { return RISCV_EXCP_NONE; -- 2.37.2
Re: [PATCH v8 3/5] riscv: Allow user to set the satp mode
Hi Bin, On Mon, Jan 30, 2023 at 5:22 AM Bin Meng wrote: > > On Thu, Jan 26, 2023 at 12:23 AM Alexandre Ghiti > wrote: > > > > RISC-V specifies multiple sizes for addressable memory and Linux probes for > > the machine's support at startup via the satp CSR register (done in > > csr.c:validate_vm). > > > > As per the specification, sv64 must support sv57, which in turn must > > support sv48...etc. So we can restrict machine support by simply setting the > > "highest" supported mode and the bare mode is always supported. > > > > You can set the satp mode using the new properties "sv32", "sv39", "sv48", > > "sv57" and "sv64" as follows: > > -cpu rv64,sv57=on # Linux will boot using sv57 scheme > > -cpu rv64,sv39=on # Linux will boot using sv39 scheme > > -cpu rv64,sv57=off # Linux will boot using sv48 scheme > > -cpu rv64 # Linux will boot using sv57 scheme by default > > > > We take the highest level set by the user: > > -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme > > > > We make sure that invalid configurations are rejected: > > -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are > ># enabled > > > > We accept "redundant" configurations: > > -cpu rv64,sv48=on,sv57=off # Linux will boot using sv48 scheme > > > > And contradictory configurations: > > -cpu rv64,sv48=on,sv48=off # Linux will boot using sv39 scheme > > > > Co-Developed-by: Ludovic Henry > > Signed-off-by: Ludovic Henry > > Signed-off-by: Alexandre Ghiti > > --- > > target/riscv/cpu.c | 206 + > > target/riscv/cpu.h | 19 + > > target/riscv/csr.c | 12 ++- > > 3 files changed, 230 insertions(+), 7 deletions(-) > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index 7181b34f86..54494a72be 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -27,6 +27,7 @@ > > #include "time_helper.h" > > #include "exec/exec-all.h" > > #include "qapi/error.h" > > +#include "qapi/visitor.h" > > #include "qemu/error-report.h" > > #include "hw/qdev-properties.h" > > #include "migration/vmstate.h" > > @@ -229,6 +230,81 @@ static void set_vext_version(CPURISCVState *env, int > > vext_ver) > > env->vext_ver = vext_ver; > > } > > > > +static uint8_t satp_mode_from_str(const char *satp_mode_str) > > +{ > > +if (!strncmp(satp_mode_str, "mbare", 5)) { > > +return VM_1_10_MBARE; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv32", 4)) { > > +return VM_1_10_SV32; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv39", 4)) { > > +return VM_1_10_SV39; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv48", 4)) { > > +return VM_1_10_SV48; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv57", 4)) { > > +return VM_1_10_SV57; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv64", 4)) { > > +return VM_1_10_SV64; > > +} > > + > > +g_assert_not_reached(); > > +} > > + > > +uint8_t satp_mode_max_from_map(uint32_t map) > > +{ > > +/* map here has at least one bit set, so no problem with clz */ > > +return 31 - __builtin_clz(map); > > +} > > + > > +const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) > > +{ > > +if (is_32_bit) { > > +switch (satp_mode) { > > +case VM_1_10_SV32: > > +return "sv32"; > > +case VM_1_10_MBARE: > > +return "none"; > > +} > > +} else { > > +switch (satp_mode) { > > +case VM_1_10_SV64: > > +return "sv64"; > > +case VM_1_10_SV57: > > +return "sv57"; > > +case VM_1_10_SV48: > > +return "sv48"; > > +case VM_1_10_SV39: > > +return "sv39"; > > +case VM_1_10_MBARE: > > +return "none"; > > +} > > +} > > + > > +g_assert_not_reached(); > > +} > > + > > +/* Sets the satp mode to the max supported */ > > +static void set
[PATCH v8 5/5] riscv: Correctly set the device-tree entry 'mmu-type'
The 'mmu-type' should reflect what the hardware is capable of so use the new satp_mode field in RISCVCPUConfig to do that. Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis --- hw/riscv/virt.c | 19 ++- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 94ff2a1584..48d034a5f7 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -228,7 +228,8 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, int cpu; uint32_t cpu_phandle; MachineState *mc = MACHINE(s); -char *name, *cpu_name, *core_name, *intc_name; +uint8_t satp_mode_max; +char *name, *cpu_name, *core_name, *intc_name, *sv_name; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { cpu_phandle = (*phandle)++; @@ -236,14 +237,14 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(mc->fdt, cpu_name); -if (riscv_feature(>soc[socket].harts[cpu].env, - RISCV_FEATURE_MMU)) { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -(is_32_bit) ? "riscv,sv32" : "riscv,sv48"); -} else { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -"riscv,none"); -} + +satp_mode_max = satp_mode_max_from_map( +s->soc[socket].harts[cpu].cfg.satp_mode.map); +sv_name = g_strdup_printf("riscv,%s", + satp_mode_str(satp_mode_max, is_32_bit)); +qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); +g_free(sv_name); + name = riscv_isa_string(>soc[socket].harts[cpu]); qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); g_free(name); -- 2.37.2
[PATCH v8 4/5] riscv: Introduce satp mode hw capabilities
Currently, the max satp mode is set with the only constraint that it must be implemented in qemu, i.e. set in valid_vm_1_10_[32|64]. But we actually need to add another level of constraint: what the hw is actually capable of, because currently, a linux booting on a sifive-u54 boots in sv57 mode which is incompatible with the cpu's sv39 max capability. So add a new bitmap to RISCVSATPMap which contains this capability and initialize it in every XXX_cpu_init. Finally: - valid_vm_1_10_[32|64] constrains which satp mode the CPU can use - the CPU hw capabilities constrains what the user may select - the user's selection then constrains what's available to the guest OS. Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones --- target/riscv/cpu.c | 74 +++--- target/riscv/cpu.h | 8 +++-- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 54494a72be..e7e1fb96dc 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -292,26 +292,36 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) g_assert_not_reached(); } -/* Sets the satp mode to the max supported */ -static void set_satp_mode_default(RISCVCPU *cpu) +static void set_satp_mode_max_supported(RISCVCPU *cpu, +uint8_t satp_mode) { bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; +const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; -if (riscv_feature(>env, RISCV_FEATURE_MMU)) { -cpu->cfg.satp_mode.map |= -(1 << satp_mode_from_str(rv32 ? "sv32" : "sv57")); -} else { -cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); +for (int i = 0; i <= satp_mode; ++i) { +if (valid_vm[i]) { +cpu->cfg.satp_mode.supported |= (1 << i); +} } } +/* Sets the satp mode to the max supported */ +static void set_satp_mode_default(RISCVCPU *cpu) +{ +cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported; +} + static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + #if defined(TARGET_RISCV32) set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU); +set_satp_mode_max_supported(cpu, VM_1_10_SV32); #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); +set_satp_mode_max_supported(cpu, VM_1_10_SV57); #endif set_priv_version(env, PRIV_VERSION_1_12_0); register_cpu_props(obj); @@ -321,18 +331,24 @@ static void riscv_any_cpu_init(Object *obj) static void rv64_base_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV57); } static void rv64_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV39); } static void rv64_sifive_e_cpu_init(Object *obj) @@ -343,6 +359,7 @@ static void rv64_sifive_e_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); cpu->cfg.mmu = false; +set_satp_mode_max_supported(cpu, VM_1_10_MBARE); } static void rv128_base_cpu_init(Object *obj) @@ -354,11 +371,13 @@ static void rv128_base_cpu_init(Object *obj) exit(EXIT_FAILURE); } CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV57); } #else static void rv32_base_cpu_init(Object *obj) @@ -369,13 +388,17 @@ static void rv32_base_cpu_init(Object *obj) register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV32); } static void rv32_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV32); } static void rv32_sifive_e_cpu_init(Object *obj) @@ -386,6 +409,7 @@ static void rv
[PATCH v8 3/5] riscv: Allow user to set the satp mode
RISC-V specifies multiple sizes for addressable memory and Linux probes for the machine's support at startup via the satp CSR register (done in csr.c:validate_vm). As per the specification, sv64 must support sv57, which in turn must support sv48...etc. So we can restrict machine support by simply setting the "highest" supported mode and the bare mode is always supported. You can set the satp mode using the new properties "sv32", "sv39", "sv48", "sv57" and "sv64" as follows: -cpu rv64,sv57=on # Linux will boot using sv57 scheme -cpu rv64,sv39=on # Linux will boot using sv39 scheme -cpu rv64,sv57=off # Linux will boot using sv48 scheme -cpu rv64 # Linux will boot using sv57 scheme by default We take the highest level set by the user: -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme We make sure that invalid configurations are rejected: -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are # enabled We accept "redundant" configurations: -cpu rv64,sv48=on,sv57=off # Linux will boot using sv48 scheme And contradictory configurations: -cpu rv64,sv48=on,sv48=off # Linux will boot using sv39 scheme Co-Developed-by: Ludovic Henry Signed-off-by: Ludovic Henry Signed-off-by: Alexandre Ghiti --- target/riscv/cpu.c | 206 + target/riscv/cpu.h | 19 + target/riscv/csr.c | 12 ++- 3 files changed, 230 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 7181b34f86..54494a72be 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -27,6 +27,7 @@ #include "time_helper.h" #include "exec/exec-all.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "qemu/error-report.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" @@ -229,6 +230,81 @@ static void set_vext_version(CPURISCVState *env, int vext_ver) env->vext_ver = vext_ver; } +static uint8_t satp_mode_from_str(const char *satp_mode_str) +{ +if (!strncmp(satp_mode_str, "mbare", 5)) { +return VM_1_10_MBARE; +} + +if (!strncmp(satp_mode_str, "sv32", 4)) { +return VM_1_10_SV32; +} + +if (!strncmp(satp_mode_str, "sv39", 4)) { +return VM_1_10_SV39; +} + +if (!strncmp(satp_mode_str, "sv48", 4)) { +return VM_1_10_SV48; +} + +if (!strncmp(satp_mode_str, "sv57", 4)) { +return VM_1_10_SV57; +} + +if (!strncmp(satp_mode_str, "sv64", 4)) { +return VM_1_10_SV64; +} + +g_assert_not_reached(); +} + +uint8_t satp_mode_max_from_map(uint32_t map) +{ +/* map here has at least one bit set, so no problem with clz */ +return 31 - __builtin_clz(map); +} + +const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) +{ +if (is_32_bit) { +switch (satp_mode) { +case VM_1_10_SV32: +return "sv32"; +case VM_1_10_MBARE: +return "none"; +} +} else { +switch (satp_mode) { +case VM_1_10_SV64: +return "sv64"; +case VM_1_10_SV57: +return "sv57"; +case VM_1_10_SV48: +return "sv48"; +case VM_1_10_SV39: +return "sv39"; +case VM_1_10_MBARE: +return "none"; +} +} + +g_assert_not_reached(); +} + +/* Sets the satp mode to the max supported */ +static void set_satp_mode_default(RISCVCPU *cpu) +{ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; + +if (riscv_feature(>env, RISCV_FEATURE_MMU)) { +cpu->cfg.satp_mode.map |= +(1 << satp_mode_from_str(rv32 ? "sv32" : "sv57")); +} else { +cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); +} +} + static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; @@ -619,6 +695,82 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) } } +static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) +{ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; +const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; +uint8_t satp_mode_max; + +if (cpu->cfg.satp_mode.map == 0) { +if (cpu->cfg.satp_mode.init == 0) { +/* If unset by the user, we fallback to the default satp mode. */ +set_satp_mode_default(cpu); +} else { +/* + * Find the lowest level that was disabled and then enable the + * first valid level below which can be found in + * valid_vm_1_10_32/64. + */ +
[PATCH v8 2/5] riscv: Change type of valid_vm_1_10_[32|64] to bool
This array is actually used as a boolean so swap its current char type to a boolean and at the same time, change the type of validate_vm to bool since it returns valid_vm_1_10_[32|64]. Suggested-by: Andrew Jones Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis --- target/riscv/csr.c | 21 +++-- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 0db2c233e5..6b157806a5 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1117,16 +1117,16 @@ static const target_ulong hip_writable_mask = MIP_VSSIP; static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; static const target_ulong vsip_writable_mask = MIP_VSSIP; -static const char valid_vm_1_10_32[16] = { -[VM_1_10_MBARE] = 1, -[VM_1_10_SV32] = 1 +static const bool valid_vm_1_10_32[16] = { +[VM_1_10_MBARE] = true, +[VM_1_10_SV32] = true }; -static const char valid_vm_1_10_64[16] = { -[VM_1_10_MBARE] = 1, -[VM_1_10_SV39] = 1, -[VM_1_10_SV48] = 1, -[VM_1_10_SV57] = 1 +static const bool valid_vm_1_10_64[16] = { +[VM_1_10_MBARE] = true, +[VM_1_10_SV39] = true, +[VM_1_10_SV48] = true, +[VM_1_10_SV57] = true }; /* Machine Information Registers */ @@ -1209,7 +1209,7 @@ static RISCVException read_mstatus(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int validate_vm(CPURISCVState *env, target_ulong vm) +static bool validate_vm(CPURISCVState *env, target_ulong vm) { if (riscv_cpu_mxl(env) == MXL_RV32) { return valid_vm_1_10_32[vm & 0xf]; @@ -2648,7 +2648,8 @@ static RISCVException read_satp(CPURISCVState *env, int csrno, static RISCVException write_satp(CPURISCVState *env, int csrno, target_ulong val) { -target_ulong vm, mask; +target_ulong mask; +bool vm; if (!riscv_feature(env, RISCV_FEATURE_MMU)) { return RISCV_EXCP_NONE; -- 2.37.2
[PATCH v8 1/5] riscv: Pass Object to register_cpu_props instead of DeviceState
One can extract the DeviceState pointer from the Object pointer, so pass the Object for future commits to access other fields of Object. No functional changes intended. Signed-off-by: Alexandre Ghiti Reviewed-by: Alistair Francis Reviewed-by: Frank Chang Reviewed-by: Andrew Jones --- target/riscv/cpu.c | 15 --- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index cc75ca7667..7181b34f86 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -200,7 +200,7 @@ static const char * const riscv_intr_names[] = { "reserved" }; -static void register_cpu_props(DeviceState *dev); +static void register_cpu_props(Object *obj); const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) { @@ -238,7 +238,7 @@ static void riscv_any_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif set_priv_version(env, PRIV_VERSION_1_12_0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #if defined(TARGET_RISCV64) @@ -247,7 +247,7 @@ static void rv64_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -280,7 +280,7 @@ static void rv128_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -290,7 +290,7 @@ static void rv32_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV32, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -343,7 +343,7 @@ static void riscv_host_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, 0); #endif -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #endif @@ -1083,9 +1083,10 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_END_OF_LIST(), }; -static void register_cpu_props(DeviceState *dev) +static void register_cpu_props(Object *obj) { Property *prop; +DeviceState *dev = DEVICE(obj); for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { qdev_property_add_static(dev, prop); -- 2.37.2
[PATCH v8 0/5] riscv: Allow user to set the satp mode
This introduces new properties to allow the user to set the satp mode, see patch 3 for full syntax. In addition, it prevents cpus to boot in a satp mode they do not support (see patch 4). v8: - Remove useless !map check, Andrew - Add RB from Andrew v7: - Expand map to contain all valid modes, Andrew - Fix commit log for patch 3, Andrew - Remove is_32_bit argument from set_satp_mode_default, Andrew - Move and fixed comment, Andrew - Fix satp_mode_map_max in riscv_cpu_satp_mode_finalize which was set too early, Alex - Remove is_32_bit argument from set_satp_mode_max_supported, Andrew - Use satp_mode directly instead of a string in set_satp_mode_max_supported, Andrew - Swap the patch introducing supported bitmap and the patch that sets sv57 in the dt, Andrew - Add various RB from Andrew and Alistair, thanks v6: - Remove the valid_vm check in validate_vm and add it to the finalize function so that map already contains the constraint, Alex - Add forgotten mbare to satp_mode_from_str, Alex - Move satp mode properties handling to riscv_cpu_satp_mode_finalize, Andrew - Only add satp mode properties corresponding to the cpu, and then remove the check against valid_vm_1_10_32/64 in riscv_cpu_satp_mode_finalize, Andrew/Alistair/Alex - Move mmu-type setting to its own patch, Andrew - patch 5 is new and is a fix, Alex v5: - Simplify v4 implementation by leveraging valid_vm_1_10_32/64, as suggested by Andrew - Split the v4 patch into 2 patches as suggested by Andrew - Lot of other minor corrections, from Andrew - Set the satp mode N by disabling the satp mode N + 1 - Add a helper to set satp mode from a string, as suggested by Frank v4: - Use custom boolean properties instead of OnOffAuto properties, based on ARMVQMap, as suggested by Andrew v3: - Free sv_name as pointed by Bin - Replace satp-mode with boolean properties as suggested by Andrew - Removed RB from Atish as the patch considerably changed v2: - Use error_setg + return as suggested by Alistair - Add RB from Atish - Fixed checkpatch issues missed in v1 - Replaced Ludovic email address with the rivos one Alexandre Ghiti (5): riscv: Pass Object to register_cpu_props instead of DeviceState riscv: Change type of valid_vm_1_10_[32|64] to bool riscv: Allow user to set the satp mode riscv: Introduce satp mode hw capabilities riscv: Correctly set the device-tree entry 'mmu-type' hw/riscv/virt.c| 19 ++-- target/riscv/cpu.c | 247 +++-- target/riscv/cpu.h | 23 + target/riscv/csr.c | 29 +++--- 4 files changed, 287 insertions(+), 31 deletions(-) -- 2.37.2
Re: [PATCH v7 3/5] riscv: Allow user to set the satp mode
On Wed, Jan 25, 2023 at 1:01 PM Andrew Jones wrote: > > On Wed, Jan 25, 2023 at 09:41:05AM +0100, Alexandre Ghiti wrote: > > RISC-V specifies multiple sizes for addressable memory and Linux probes for > > the machine's support at startup via the satp CSR register (done in > > csr.c:validate_vm). > > > > As per the specification, sv64 must support sv57, which in turn must > > support sv48...etc. So we can restrict machine support by simply setting the > > "highest" supported mode and the bare mode is always supported. > > > > You can set the satp mode using the new properties "sv32", "sv39", "sv48", > > "sv57" and "sv64" as follows: > > -cpu rv64,sv57=on # Linux will boot using sv57 scheme > > -cpu rv64,sv39=on # Linux will boot using sv39 scheme > > -cpu rv64,sv57=off # Linux will boot using sv48 scheme > > -cpu rv64 # Linux will boot using sv57 scheme by default > > > > We take the highest level set by the user: > > -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme > > > > We make sure that invalid configurations are rejected: > > -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are > ># enabled > > > > We accept "redundant" configurations: > > -cpu rv64,sv48=on,sv57=off # Linux will boot using sv48 scheme > > > > And contradictory configurations: > > -cpu rv64,sv48=on,sv48=off # Linux will boot using sv39 scheme > > > > Co-Developed-by: Ludovic Henry > > Signed-off-by: Ludovic Henry > > Signed-off-by: Alexandre Ghiti > > --- > > target/riscv/cpu.c | 207 + > > target/riscv/cpu.h | 19 + > > target/riscv/csr.c | 12 ++- > > 3 files changed, 231 insertions(+), 7 deletions(-) > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index 7181b34f86..87153a0219 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -27,6 +27,7 @@ > > #include "time_helper.h" > > #include "exec/exec-all.h" > > #include "qapi/error.h" > > +#include "qapi/visitor.h" > > #include "qemu/error-report.h" > > #include "hw/qdev-properties.h" > > #include "migration/vmstate.h" > > @@ -229,6 +230,81 @@ static void set_vext_version(CPURISCVState *env, int > > vext_ver) > > env->vext_ver = vext_ver; > > } > > > > +static uint8_t satp_mode_from_str(const char *satp_mode_str) > > +{ > > +if (!strncmp(satp_mode_str, "mbare", 5)) { > > +return VM_1_10_MBARE; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv32", 4)) { > > +return VM_1_10_SV32; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv39", 4)) { > > +return VM_1_10_SV39; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv48", 4)) { > > +return VM_1_10_SV48; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv57", 4)) { > > +return VM_1_10_SV57; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv64", 4)) { > > +return VM_1_10_SV64; > > +} > > + > > +g_assert_not_reached(); > > +} > > + > > +uint8_t satp_mode_max_from_map(uint32_t map) > > +{ > > +/* map here has at least one bit set, so no problem with clz */ > > +return 31 - __builtin_clz(map); > > +} > > + > > +const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) > > +{ > > +if (is_32_bit) { > > +switch (satp_mode) { > > +case VM_1_10_SV32: > > +return "sv32"; > > +case VM_1_10_MBARE: > > +return "none"; > > +} > > +} else { > > +switch (satp_mode) { > > +case VM_1_10_SV64: > > +return "sv64"; > > +case VM_1_10_SV57: > > +return "sv57"; > > +case VM_1_10_SV48: > > +return "sv48"; > > +case VM_1_10_SV39: > > +return "sv39"; > > +case VM_1_10_MBARE: > > +return "none"; > > +} > > +} > > + > > +g_assert_not_reached(); > > +} > > + > > +/* Sets the satp mode to the max supported */ > > +static void set_satp_mode_defau
[PATCH v7 5/5] riscv: Correctly set the device-tree entry 'mmu-type'
The 'mmu-type' should reflect what the hardware is capable of so use the new satp_mode field in RISCVCPUConfig to do that. Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis --- hw/riscv/virt.c | 19 ++- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 94ff2a1584..48d034a5f7 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -228,7 +228,8 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, int cpu; uint32_t cpu_phandle; MachineState *mc = MACHINE(s); -char *name, *cpu_name, *core_name, *intc_name; +uint8_t satp_mode_max; +char *name, *cpu_name, *core_name, *intc_name, *sv_name; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { cpu_phandle = (*phandle)++; @@ -236,14 +237,14 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(mc->fdt, cpu_name); -if (riscv_feature(>soc[socket].harts[cpu].env, - RISCV_FEATURE_MMU)) { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -(is_32_bit) ? "riscv,sv32" : "riscv,sv48"); -} else { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -"riscv,none"); -} + +satp_mode_max = satp_mode_max_from_map( +s->soc[socket].harts[cpu].cfg.satp_mode.map); +sv_name = g_strdup_printf("riscv,%s", + satp_mode_str(satp_mode_max, is_32_bit)); +qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); +g_free(sv_name); + name = riscv_isa_string(>soc[socket].harts[cpu]); qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); g_free(name); -- 2.37.2
[PATCH v7 4/5] riscv: Introduce satp mode hw capabilities
Currently, the max satp mode is set with the only constraint that it must be implemented in qemu, i.e. set in valid_vm_1_10_[32|64]. But we actually need to add another level of constraint: what the hw is actually capable of, because currently, a linux booting on a sifive-u54 boots in sv57 mode which is incompatible with the cpu's sv39 max capability. So add a new bitmap to RISCVSATPMap which contains this capability and initialize it in every XXX_cpu_init. Finally: - valid_vm_1_10_[32|64] constrains which satp mode the CPU can use - the CPU hw capabilities constrains what the user may select - the user's selection then constrains what's available to the guest OS. Signed-off-by: Alexandre Ghiti --- target/riscv/cpu.c | 74 +++--- target/riscv/cpu.h | 8 +++-- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 87153a0219..bba9c39bb8 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -292,26 +292,36 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) g_assert_not_reached(); } -/* Sets the satp mode to the max supported */ -static void set_satp_mode_default(RISCVCPU *cpu) +static void set_satp_mode_max_supported(RISCVCPU *cpu, +uint8_t satp_mode) { bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; +const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; -if (riscv_feature(>env, RISCV_FEATURE_MMU)) { -cpu->cfg.satp_mode.map |= -(1 << satp_mode_from_str(rv32 ? "sv32" : "sv57")); -} else { -cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); +for (int i = 0; i <= satp_mode; ++i) { +if (valid_vm[i]) { +cpu->cfg.satp_mode.supported |= (1 << i); +} } } +/* Sets the satp mode to the max supported */ +static void set_satp_mode_default(RISCVCPU *cpu) +{ +cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported; +} + static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + #if defined(TARGET_RISCV32) set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU); +set_satp_mode_max_supported(cpu, VM_1_10_SV32); #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); +set_satp_mode_max_supported(cpu, VM_1_10_SV57); #endif set_priv_version(env, PRIV_VERSION_1_12_0); register_cpu_props(obj); @@ -321,18 +331,24 @@ static void riscv_any_cpu_init(Object *obj) static void rv64_base_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV57); } static void rv64_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV39); } static void rv64_sifive_e_cpu_init(Object *obj) @@ -343,6 +359,7 @@ static void rv64_sifive_e_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); cpu->cfg.mmu = false; +set_satp_mode_max_supported(cpu, VM_1_10_MBARE); } static void rv128_base_cpu_init(Object *obj) @@ -354,11 +371,13 @@ static void rv128_base_cpu_init(Object *obj) exit(EXIT_FAILURE); } CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV57); } #else static void rv32_base_cpu_init(Object *obj) @@ -369,13 +388,17 @@ static void rv32_base_cpu_init(Object *obj) register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV32); } static void rv32_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); +set_satp_mode_max_supported(cpu, VM_1_10_SV32); } static void rv32_sifive_e_cpu_init(Object *obj) @@ -386,6 +409,7 @@ static void rv32_sifive_e_cpu_init(Object
[PATCH v7 3/5] riscv: Allow user to set the satp mode
RISC-V specifies multiple sizes for addressable memory and Linux probes for the machine's support at startup via the satp CSR register (done in csr.c:validate_vm). As per the specification, sv64 must support sv57, which in turn must support sv48...etc. So we can restrict machine support by simply setting the "highest" supported mode and the bare mode is always supported. You can set the satp mode using the new properties "sv32", "sv39", "sv48", "sv57" and "sv64" as follows: -cpu rv64,sv57=on # Linux will boot using sv57 scheme -cpu rv64,sv39=on # Linux will boot using sv39 scheme -cpu rv64,sv57=off # Linux will boot using sv48 scheme -cpu rv64 # Linux will boot using sv57 scheme by default We take the highest level set by the user: -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme We make sure that invalid configurations are rejected: -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are # enabled We accept "redundant" configurations: -cpu rv64,sv48=on,sv57=off # Linux will boot using sv48 scheme And contradictory configurations: -cpu rv64,sv48=on,sv48=off # Linux will boot using sv39 scheme Co-Developed-by: Ludovic Henry Signed-off-by: Ludovic Henry Signed-off-by: Alexandre Ghiti --- target/riscv/cpu.c | 207 + target/riscv/cpu.h | 19 + target/riscv/csr.c | 12 ++- 3 files changed, 231 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 7181b34f86..87153a0219 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -27,6 +27,7 @@ #include "time_helper.h" #include "exec/exec-all.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "qemu/error-report.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" @@ -229,6 +230,81 @@ static void set_vext_version(CPURISCVState *env, int vext_ver) env->vext_ver = vext_ver; } +static uint8_t satp_mode_from_str(const char *satp_mode_str) +{ +if (!strncmp(satp_mode_str, "mbare", 5)) { +return VM_1_10_MBARE; +} + +if (!strncmp(satp_mode_str, "sv32", 4)) { +return VM_1_10_SV32; +} + +if (!strncmp(satp_mode_str, "sv39", 4)) { +return VM_1_10_SV39; +} + +if (!strncmp(satp_mode_str, "sv48", 4)) { +return VM_1_10_SV48; +} + +if (!strncmp(satp_mode_str, "sv57", 4)) { +return VM_1_10_SV57; +} + +if (!strncmp(satp_mode_str, "sv64", 4)) { +return VM_1_10_SV64; +} + +g_assert_not_reached(); +} + +uint8_t satp_mode_max_from_map(uint32_t map) +{ +/* map here has at least one bit set, so no problem with clz */ +return 31 - __builtin_clz(map); +} + +const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) +{ +if (is_32_bit) { +switch (satp_mode) { +case VM_1_10_SV32: +return "sv32"; +case VM_1_10_MBARE: +return "none"; +} +} else { +switch (satp_mode) { +case VM_1_10_SV64: +return "sv64"; +case VM_1_10_SV57: +return "sv57"; +case VM_1_10_SV48: +return "sv48"; +case VM_1_10_SV39: +return "sv39"; +case VM_1_10_MBARE: +return "none"; +} +} + +g_assert_not_reached(); +} + +/* Sets the satp mode to the max supported */ +static void set_satp_mode_default(RISCVCPU *cpu) +{ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; + +if (riscv_feature(>env, RISCV_FEATURE_MMU)) { +cpu->cfg.satp_mode.map |= +(1 << satp_mode_from_str(rv32 ? "sv32" : "sv57")); +} else { +cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); +} +} + static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; @@ -619,6 +695,83 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) } } +static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) +{ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; +const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; +uint8_t satp_mode_max; + +if (cpu->cfg.satp_mode.map == 0) { +if (cpu->cfg.satp_mode.init == 0) { +/* If unset by the user, we fallback to the default satp mode. */ +set_satp_mode_default(cpu); +} else { +/* + * Find the lowest level that was disabled and then enable the + * first valid level below which can be found in + * valid_vm_1_10_32/64. + */ +for (int i =
[PATCH v7 2/5] riscv: Change type of valid_vm_1_10_[32|64] to bool
This array is actually used as a boolean so swap its current char type to a boolean and at the same time, change the type of validate_vm to bool since it returns valid_vm_1_10_[32|64]. Suggested-by: Andrew Jones Signed-off-by: Alexandre Ghiti Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis --- target/riscv/csr.c | 21 +++-- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 0db2c233e5..6b157806a5 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1117,16 +1117,16 @@ static const target_ulong hip_writable_mask = MIP_VSSIP; static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; static const target_ulong vsip_writable_mask = MIP_VSSIP; -static const char valid_vm_1_10_32[16] = { -[VM_1_10_MBARE] = 1, -[VM_1_10_SV32] = 1 +static const bool valid_vm_1_10_32[16] = { +[VM_1_10_MBARE] = true, +[VM_1_10_SV32] = true }; -static const char valid_vm_1_10_64[16] = { -[VM_1_10_MBARE] = 1, -[VM_1_10_SV39] = 1, -[VM_1_10_SV48] = 1, -[VM_1_10_SV57] = 1 +static const bool valid_vm_1_10_64[16] = { +[VM_1_10_MBARE] = true, +[VM_1_10_SV39] = true, +[VM_1_10_SV48] = true, +[VM_1_10_SV57] = true }; /* Machine Information Registers */ @@ -1209,7 +1209,7 @@ static RISCVException read_mstatus(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int validate_vm(CPURISCVState *env, target_ulong vm) +static bool validate_vm(CPURISCVState *env, target_ulong vm) { if (riscv_cpu_mxl(env) == MXL_RV32) { return valid_vm_1_10_32[vm & 0xf]; @@ -2648,7 +2648,8 @@ static RISCVException read_satp(CPURISCVState *env, int csrno, static RISCVException write_satp(CPURISCVState *env, int csrno, target_ulong val) { -target_ulong vm, mask; +target_ulong mask; +bool vm; if (!riscv_feature(env, RISCV_FEATURE_MMU)) { return RISCV_EXCP_NONE; -- 2.37.2
[PATCH v7 1/5] riscv: Pass Object to register_cpu_props instead of DeviceState
One can extract the DeviceState pointer from the Object pointer, so pass the Object for future commits to access other fields of Object. No functional changes intended. Signed-off-by: Alexandre Ghiti Reviewed-by: Alistair Francis Reviewed-by: Frank Chang Reviewed-by: Andrew Jones --- target/riscv/cpu.c | 15 --- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index cc75ca7667..7181b34f86 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -200,7 +200,7 @@ static const char * const riscv_intr_names[] = { "reserved" }; -static void register_cpu_props(DeviceState *dev); +static void register_cpu_props(Object *obj); const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) { @@ -238,7 +238,7 @@ static void riscv_any_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif set_priv_version(env, PRIV_VERSION_1_12_0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #if defined(TARGET_RISCV64) @@ -247,7 +247,7 @@ static void rv64_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -280,7 +280,7 @@ static void rv128_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -290,7 +290,7 @@ static void rv32_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV32, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -343,7 +343,7 @@ static void riscv_host_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, 0); #endif -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #endif @@ -1083,9 +1083,10 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_END_OF_LIST(), }; -static void register_cpu_props(DeviceState *dev) +static void register_cpu_props(Object *obj) { Property *prop; +DeviceState *dev = DEVICE(obj); for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { qdev_property_add_static(dev, prop); -- 2.37.2
[PATCH v7 0/5] riscv: Allow user to set the satp mode
This introduces new properties to allow the user to set the satp mode, see patch 3 for full syntax. In addition, it prevents cpus to boot in a satp mode they do not support (see patch 5). v7: - Expand map to contain all valid modes, Andrew - Fix commit log for patch 3, Andrew - Remove is_32_bit argument from set_satp_mode_default, Andrew - Move and fixed comment, Andrew - Fix satp_mode_map_max in riscv_cpu_satp_mode_finalize which was set too early, Alex - Remove is_32_bit argument from set_satp_mode_max_supported, Andrew - Use satp_mode directly instead of a string in set_satp_mode_max_supported, Andrew - Swap the patch introducing supported bitmap and the patch that sets sv57 in the dt, Andrew - Add various RB from Andrew and Alistair, thanks v6: - Remove the valid_vm check in validate_vm and add it to the finalize function so that map already contains the constraint, Alex - Add forgotten mbare to satp_mode_from_str, Alex - Move satp mode properties handling to riscv_cpu_satp_mode_finalize, Andrew - Only add satp mode properties corresponding to the cpu, and then remove the check against valid_vm_1_10_32/64 in riscv_cpu_satp_mode_finalize, Andrew/Alistair/Alex - Move mmu-type setting to its own patch, Andrew - patch 5 is new and is a fix, Alex v5: - Simplify v4 implementation by leveraging valid_vm_1_10_32/64, as suggested by Andrew - Split the v4 patch into 2 patches as suggested by Andrew - Lot of other minor corrections, from Andrew - Set the satp mode N by disabling the satp mode N + 1 - Add a helper to set satp mode from a string, as suggested by Frank v4: - Use custom boolean properties instead of OnOffAuto properties, based on ARMVQMap, as suggested by Andrew v3: - Free sv_name as pointed by Bin - Replace satp-mode with boolean properties as suggested by Andrew - Removed RB from Atish as the patch considerably changed v2: - Use error_setg + return as suggested by Alistair - Add RB from Atish - Fixed checkpatch issues missed in v1 - Replaced Ludovic email address with the rivos one Alexandre Ghiti (5): riscv: Pass Object to register_cpu_props instead of DeviceState riscv: Change type of valid_vm_1_10_[32|64] to bool riscv: Allow user to set the satp mode riscv: Introduce satp mode hw capabilities riscv: Correctly set the device-tree entry 'mmu-type' hw/riscv/virt.c| 19 ++-- target/riscv/cpu.c | 248 +++-- target/riscv/cpu.h | 23 + target/riscv/csr.c | 29 +++--- 4 files changed, 288 insertions(+), 31 deletions(-) -- 2.37.2
Re: [PATCH v6 5/5] riscv: Introduce satp mode hw capabilities
On Mon, Jan 23, 2023 at 2:51 PM Andrew Jones wrote: > > On Mon, Jan 23, 2023 at 10:03:24AM +0100, Alexandre Ghiti wrote: > > Currently, the max satp mode is set with the only constraint that it must be > > implemented in qemu, i.e. set in valid_vm_1_10_[32|64]. > > > > But we actually need to add another level of constraint: what the hw is > > actually capable of, because currently, a linux booting on a sifive-u54 > > boots in sv57 mode which is incompatible with the cpu's sv39 max > > capability. > > > > So add a new bitmap to RISCVSATPMap which contains this capability and > > initialize it in every XXX_cpu_init. > > > > Finally, we have the following chain of constraints: > > > > Qemu capability > HW capability > User choice > Software capability > > > > Signed-off-by: Alexandre Ghiti > > --- > > target/riscv/cpu.c | 78 +++--- > > target/riscv/cpu.h | 8 +++-- > > 2 files changed, 59 insertions(+), 27 deletions(-) > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index e409e6ab64..19a37fee2b 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool > > is_32_bit) > > g_assert_not_reached(); > > } > > > > -/* Sets the satp mode to the max supported */ > > -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit) > > +static void set_satp_mode_max_supported(RISCVCPU *cpu, > > +const char *satp_mode_str, > > +bool is_32_bit) > > I'd drop 'is_32_bit' and get it from 'cpu', which would "clean up" all the > callsites by getting rid of all the true/false stuff. Indeed, better this way > Also, why take the string instead of the VM_1_10_SV* define? No particular reason, but I changed it to VM_1_10_SV*, thanks > > > { > > -if (riscv_feature(>env, RISCV_FEATURE_MMU)) { > > -cpu->cfg.satp_mode.map |= > > -(1 << satp_mode_from_str(is_32_bit ? "sv32" : > > "sv57")); > > -} else { > > -cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); > > +uint8_t satp_mode = satp_mode_from_str(satp_mode_str); > > +const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64; > > + > > +for (int i = 0; i <= satp_mode; ++i) { > > +if (valid_vm[i]) { > > +cpu->cfg.satp_mode.supported |= (1 << i); > > +} > > } > > } > > > > +/* Sets the satp mode to the max supported */ > > +static void set_satp_mode_default(RISCVCPU *cpu) > > +{ > > +uint8_t satp_mode = > > satp_mode_max_from_map(cpu->cfg.satp_mode.supported); > > + > > +cpu->cfg.satp_mode.map |= (1 << satp_mode); > > Let's do 'cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported' to make > sure 'map' has all supported bits set for property probing. Indeed now the map is fully set. > > > +} > > + > > static void riscv_any_cpu_init(Object *obj) > > { > > CPURISCVState *env = _CPU(obj)->env; > > +RISCVCPU *cpu = RISCV_CPU(obj); > > + > > #if defined(TARGET_RISCV32) > > set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU); > > +set_satp_mode_max_supported(cpu, "sv32", true); > > #elif defined(TARGET_RISCV64) > > set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); > > +set_satp_mode_max_supported(cpu, "sv57", false); > > #endif > > set_priv_version(env, PRIV_VERSION_1_12_0); > > register_cpu_props(obj); > > @@ -319,18 +334,24 @@ static void riscv_any_cpu_init(Object *obj) > > static void rv64_base_cpu_init(Object *obj) > > { > > CPURISCVState *env = _CPU(obj)->env; > > +RISCVCPU *cpu = RISCV_CPU(obj); > > + > > /* We set this in the realise function */ > > set_misa(env, MXL_RV64, 0); > > register_cpu_props(obj); > > /* Set latest version of privileged specification */ > > set_priv_version(env, PRIV_VERSION_1_12_0); > > +set_satp_mode_max_supported(cpu, "sv57", false); > > } > > > > static void rv64_sifive_u_cpu_init(Object *obj) > > { > > CPURISCVState *env = _CPU(obj)->env; > > +RISCVCPU *cpu = RISCV_CPU(obj); > > + > > set_misa(env, MXL_RV64, RVI | RVM | RVA | R
Re: [PATCH v6 5/5] riscv: Introduce satp mode hw capabilities
On Mon, Jan 23, 2023 at 2:31 PM Andrew Jones wrote: > > On Mon, Jan 23, 2023 at 12:15:08PM +0100, Alexandre Ghiti wrote: > > On Mon, Jan 23, 2023 at 11:51 AM Andrew Jones > > wrote: > > > > > > On Mon, Jan 23, 2023 at 10:03:24AM +0100, Alexandre Ghiti wrote: > > > > Currently, the max satp mode is set with the only constraint that it > > > > must be > > > > implemented in qemu, i.e. set in valid_vm_1_10_[32|64]. > > > > > > > > But we actually need to add another level of constraint: what the hw is > > > > actually capable of, because currently, a linux booting on a sifive-u54 > > > > boots in sv57 mode which is incompatible with the cpu's sv39 max > > > > capability. > > > > > > > > So add a new bitmap to RISCVSATPMap which contains this capability and > > > > initialize it in every XXX_cpu_init. > > > > > > > > Finally, we have the following chain of constraints: > > > > > > > > Qemu capability > HW capability > User choice > Software capability > > > > > > ^ What software is this? > > > I'd think the user's choice would always be last. > > > > > > > > > > > Signed-off-by: Alexandre Ghiti > > > > --- > > > > target/riscv/cpu.c | 78 +++--- > > > > target/riscv/cpu.h | 8 +++-- > > > > 2 files changed, 59 insertions(+), 27 deletions(-) > > > > > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > > > index e409e6ab64..19a37fee2b 100644 > > > > --- a/target/riscv/cpu.c > > > > +++ b/target/riscv/cpu.c > > > > @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool > > > > is_32_bit) > > > > g_assert_not_reached(); > > > > } > > > > > > > > -/* Sets the satp mode to the max supported */ > > > > -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit) > > > > +static void set_satp_mode_max_supported(RISCVCPU *cpu, > > > > +const char *satp_mode_str, > > > > +bool is_32_bit) > > > > { > > > > -if (riscv_feature(>env, RISCV_FEATURE_MMU)) { > > > > -cpu->cfg.satp_mode.map |= > > > > -(1 << satp_mode_from_str(is_32_bit ? "sv32" : > > > > "sv57")); > > > > -} else { > > > > -cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); > > > > +uint8_t satp_mode = satp_mode_from_str(satp_mode_str); > > > > +const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : > > > > valid_vm_1_10_64; > > > > + > > > > +for (int i = 0; i <= satp_mode; ++i) { > > > > +if (valid_vm[i]) { > > > > +cpu->cfg.satp_mode.supported |= (1 << i); > > > > > > I don't think we need a new 'supported' bitmap, I think each board that > > > needs to further constrain va-bits from what QEMU supports should just set > > > valid_vm_1_10_32/64. I.e. drop const from the arrays and add an init > > > function something like > > > > This was my first idea too, but those arrays are global and I have to > > admit that I thought it was possible to emulate a cpu with different > > cores. Anyway, isn't it a bit weird to store this into some global > > array whereas it is intimately linked to the CPU? To me, it makes > > sense to keep those variables as a way to know what qemu is able to > > emulate and have a CPU specific map like in this patch for the hw > > capabilities. Does it make sense to you? > > Ah, yes, to support heterogeneous configs it's best to keep this > information per-cpu. I'll take another look at the patch. > > > > > > > > > #define QEMU_SATP_MODE_MAX VM_1_10_SV64 > > > > > > void riscv_cpu_set_satp_mode_max(RISCVCPU *cpu, uint8_t satp_mode_max) > > > { > > > bool is_32_bit = cpu->env.misa_mxl == MXL_RV32; > > > bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64; > > > > > > g_assert(satp_mode_max <= QEMU_SATP_MODE_MAX); > > > g_assert(!is_32_bit || satp_mode_max < 2); > > > > > > memset(valid_vm, 0, sizeof(*valid_vm)); > > > > > > for (int i = 0; i <= satp_mode_max; i++) { > > > valid_vm[i] = true; > > > } > > > } > > > > > > The valid_vm[] checks already in finalize should then manage the > > > validation needed to constrain boards. Only boards that care about > > > this need to call this function, otherwise they'll get the default. > > > > > > Also, this patch should come before the patch that changes the default > > > for all boards to sv57 in order to avoid breaking bisection. > > > > As I explained earlier, I didn't change the default to sv57! Just > > fixed what was passed via the device tree, which should not be used > > anyway :) > > OK, I keep misunderstanding how we're "fixing" something which is > is wrong, but apparently doesn't exhibit any symptoms. So, assuming > it doesn't matter, then I guess it can come anywhere in the series. Actually *I* think it should not matter, but I can't be sure so I'll do what you ask. > > Thanks, > drew
Re: [PATCH v6 5/5] riscv: Introduce satp mode hw capabilities
On Mon, Jan 23, 2023 at 11:51 AM Andrew Jones wrote: > > On Mon, Jan 23, 2023 at 10:03:24AM +0100, Alexandre Ghiti wrote: > > Currently, the max satp mode is set with the only constraint that it must be > > implemented in qemu, i.e. set in valid_vm_1_10_[32|64]. > > > > But we actually need to add another level of constraint: what the hw is > > actually capable of, because currently, a linux booting on a sifive-u54 > > boots in sv57 mode which is incompatible with the cpu's sv39 max > > capability. > > > > So add a new bitmap to RISCVSATPMap which contains this capability and > > initialize it in every XXX_cpu_init. > > > > Finally, we have the following chain of constraints: > > > > Qemu capability > HW capability > User choice > Software capability > > ^ What software is this? > I'd think the user's choice would always be last. Hmm maybe that's not clear, but I meant that the last constraint was what the emulated software is capable of handling. > > > > > Signed-off-by: Alexandre Ghiti > > --- > > target/riscv/cpu.c | 78 +++--- > > target/riscv/cpu.h | 8 +++-- > > 2 files changed, 59 insertions(+), 27 deletions(-) > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index e409e6ab64..19a37fee2b 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool > > is_32_bit) > > g_assert_not_reached(); > > } > > > > -/* Sets the satp mode to the max supported */ > > -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit) > > +static void set_satp_mode_max_supported(RISCVCPU *cpu, > > +const char *satp_mode_str, > > +bool is_32_bit) > > { > > -if (riscv_feature(>env, RISCV_FEATURE_MMU)) { > > -cpu->cfg.satp_mode.map |= > > -(1 << satp_mode_from_str(is_32_bit ? "sv32" : > > "sv57")); > > -} else { > > -cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); > > +uint8_t satp_mode = satp_mode_from_str(satp_mode_str); > > +const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64; > > + > > +for (int i = 0; i <= satp_mode; ++i) { > > +if (valid_vm[i]) { > > +cpu->cfg.satp_mode.supported |= (1 << i); > > I don't think we need a new 'supported' bitmap, I think each board that > needs to further constrain va-bits from what QEMU supports should just set > valid_vm_1_10_32/64. I.e. drop const from the arrays and add an init > function something like > > #define QEMU_SATP_MODE_MAX VM_1_10_SV64 > > void riscv_cpu_set_satp_mode_max(RISCVCPU *cpu, uint8_t satp_mode_max) > { > bool is_32_bit = cpu->env.misa_mxl == MXL_RV32; > bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64; > > g_assert(satp_mode_max <= QEMU_SATP_MODE_MAX); > g_assert(!is_32_bit || satp_mode_max < 2); > > memset(valid_vm, 0, sizeof(*valid_vm)); > > for (int i = 0; i <= satp_mode_max; i++) { > valid_vm[i] = true; > } > } > > The valid_vm[] checks already in finalize should then manage the > validation needed to constrain boards. Only boards that care about > this need to call this function, otherwise they'll get the default. > > Also, this patch should come before the patch that changes the default > for all boards to sv57 in order to avoid breaking bisection. > > Thanks, > drew
Re: [PATCH v6 3/5] riscv: Allow user to set the satp mode
On Mon, Jan 23, 2023 at 11:29 AM Andrew Jones wrote: > > On Mon, Jan 23, 2023 at 10:03:22AM +0100, Alexandre Ghiti wrote: > ... > > +/* Sets the satp mode to the max supported */ > > +static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit) > > +{ > > nit: When passing in the cpu object pointer there's no need to also pass > is_32_bit, we can just use it from the pointer, cpu->env.misa_mxl == MXL_RV32 Ok Thanks, Alex > > Thanks, > drew
Re: [PATCH v6 3/5] riscv: Allow user to set the satp mode
On Mon, Jan 23, 2023 at 11:14 AM Andrew Jones wrote: > > On Mon, Jan 23, 2023 at 10:03:22AM +0100, Alexandre Ghiti wrote: > > RISC-V specifies multiple sizes for addressable memory and Linux probes for > > the machine's support at startup via the satp CSR register (done in > > csr.c:validate_vm). > > > > As per the specification, sv64 must support sv57, which in turn must > > support sv48...etc. So we can restrict machine support by simply setting the > > "highest" supported mode and the bare mode is always supported. > > > > You can set the satp mode using the new properties "sv32", "sv39", "sv48", > > "sv57" and "sv64" as follows: > > -cpu rv64,sv57=on # Linux will boot using sv57 scheme > > -cpu rv64,sv39=on # Linux will boot using sv39 scheme > > -cpu rv64,sv57=off # Linux will boot using sv48 scheme > > -cpu rv64 # Linux will boot using sv57 scheme by default > > > > We take the highest level set by the user: > > -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme > > > > We make sure that invalid configurations are rejected: > > -cpu rv64,sv32=on # Can't enable 32-bit satp mode in 64-bit > > -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are > ># enabled > > > > We accept "redundant" configurations: > > -cpu rv64,sv48=on,sv57=off # Linux will boot using sv48 scheme > > > > And contradictory configurations: > > -cpu rv64,sv48=on,sv48=off # Linux will boot using sv39 scheme > > > > In addition, we now correctly set the device-tree entry 'mmu-type' using > > those new properties. > > This sentence no longer applies to this patch. Sorry about that and thanks for noticing. Alex > > Thanks, > drew
Re: [PATCH v6 3/5] riscv: Allow user to set the satp mode
Hi Andrew, On Mon, Jan 23, 2023 at 11:11 AM Andrew Jones wrote: > > On Mon, Jan 23, 2023 at 10:03:22AM +0100, Alexandre Ghiti wrote: > > RISC-V specifies multiple sizes for addressable memory and Linux probes for > > the machine's support at startup via the satp CSR register (done in > > csr.c:validate_vm). > > > > As per the specification, sv64 must support sv57, which in turn must > > support sv48...etc. So we can restrict machine support by simply setting the > > "highest" supported mode and the bare mode is always supported. > > > > You can set the satp mode using the new properties "sv32", "sv39", "sv48", > > "sv57" and "sv64" as follows: > > -cpu rv64,sv57=on # Linux will boot using sv57 scheme > > -cpu rv64,sv39=on # Linux will boot using sv39 scheme > > -cpu rv64,sv57=off # Linux will boot using sv48 scheme > > -cpu rv64 # Linux will boot using sv57 scheme by default > > > > We take the highest level set by the user: > > -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme > > > > We make sure that invalid configurations are rejected: > > -cpu rv64,sv32=on # Can't enable 32-bit satp mode in 64-bit > > The property doesn't exist for rv64 anymore, so I'm not sure we need > this info in the commit message. Sorry about that... > > > -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are > ># enabled > > > > We accept "redundant" configurations: > > -cpu rv64,sv48=on,sv57=off # Linux will boot using sv48 scheme > > > > And contradictory configurations: > > -cpu rv64,sv48=on,sv48=off # Linux will boot using sv39 scheme > > > > In addition, we now correctly set the device-tree entry 'mmu-type' using > > those new properties. > > > > Co-Developed-by: Ludovic Henry > > Signed-off-by: Ludovic Henry > > Signed-off-by: Alexandre Ghiti > > --- > > target/riscv/cpu.c | 204 + > > target/riscv/cpu.h | 19 + > > target/riscv/csr.c | 12 ++- > > 3 files changed, 228 insertions(+), 7 deletions(-) > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index 7181b34f86..e409e6ab64 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -27,6 +27,7 @@ > > #include "time_helper.h" > > #include "exec/exec-all.h" > > #include "qapi/error.h" > > +#include "qapi/visitor.h" > > #include "qemu/error-report.h" > > #include "hw/qdev-properties.h" > > #include "migration/vmstate.h" > > @@ -229,6 +230,79 @@ static void set_vext_version(CPURISCVState *env, int > > vext_ver) > > env->vext_ver = vext_ver; > > } > > > > +static uint8_t satp_mode_from_str(const char *satp_mode_str) > > +{ > > +if (!strncmp(satp_mode_str, "mbare", 5)) { > > +return VM_1_10_MBARE; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv32", 4)) { > > +return VM_1_10_SV32; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv39", 4)) { > > +return VM_1_10_SV39; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv48", 4)) { > > +return VM_1_10_SV48; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv57", 4)) { > > +return VM_1_10_SV57; > > +} > > + > > +if (!strncmp(satp_mode_str, "sv64", 4)) { > > +return VM_1_10_SV64; > > +} > > + > > +g_assert_not_reached(); > > +} > > + > > +uint8_t satp_mode_max_from_map(uint32_t map) > > +{ > > +/* map here has at least one bit set, so no problem with clz */ > > +return 31 - __builtin_clz(map); > > +} > > + > > +const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) > > +{ > > +if (is_32_bit) { > > +switch (satp_mode) { > > +case VM_1_10_SV32: > > +return "sv32"; > > +case VM_1_10_MBARE: > > +return "none"; > > +} > > +} else { > > +switch (satp_mode) { > > +case VM_1_10_SV64: > > +return "sv64"; > > +case VM_1_10_SV57: > > +return "sv57"; > > +case VM_1_10_SV48: > > +return "sv48"; > > +case VM_1_10_S
Re: [PATCH v6 5/5] riscv: Introduce satp mode hw capabilities
Hi Alistair, On Tue, Jan 24, 2023 at 1:41 AM Alistair Francis wrote: > > On Mon, Jan 23, 2023 at 7:09 PM Alexandre Ghiti > wrote: > > > > Currently, the max satp mode is set with the only constraint that it must be > > implemented in qemu, i.e. set in valid_vm_1_10_[32|64]. > > > > But we actually need to add another level of constraint: what the hw is > > actually capable of, because currently, a linux booting on a sifive-u54 > > boots in sv57 mode which is incompatible with the cpu's sv39 max > > capability. > > > > So add a new bitmap to RISCVSATPMap which contains this capability and > > initialize it in every XXX_cpu_init. > > > > Finally, we have the following chain of constraints: > > > > Qemu capability > HW capability > User choice > Software capability > > > > Signed-off-by: Alexandre Ghiti > > --- > > target/riscv/cpu.c | 78 +++--- > > target/riscv/cpu.h | 8 +++-- > > 2 files changed, 59 insertions(+), 27 deletions(-) > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index e409e6ab64..19a37fee2b 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool > > is_32_bit) > > g_assert_not_reached(); > > } > > > > -/* Sets the satp mode to the max supported */ > > -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit) > > +static void set_satp_mode_max_supported(RISCVCPU *cpu, > > +const char *satp_mode_str, > > +bool is_32_bit) > > { > > -if (riscv_feature(>env, RISCV_FEATURE_MMU)) { > > -cpu->cfg.satp_mode.map |= > > -(1 << satp_mode_from_str(is_32_bit ? "sv32" : > > "sv57")); > > -} else { > > -cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); > > +uint8_t satp_mode = satp_mode_from_str(satp_mode_str); > > +const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64; > > + > > +for (int i = 0; i <= satp_mode; ++i) { > > +if (valid_vm[i]) { > > +cpu->cfg.satp_mode.supported |= (1 << i); > > +} > > } > > } > > > > +/* Sets the satp mode to the max supported */ > > +static void set_satp_mode_default(RISCVCPU *cpu) > > +{ > > +uint8_t satp_mode = > > satp_mode_max_from_map(cpu->cfg.satp_mode.supported); > > + > > +cpu->cfg.satp_mode.map |= (1 << satp_mode); > > +} > > + > > static void riscv_any_cpu_init(Object *obj) > > { > > CPURISCVState *env = _CPU(obj)->env; > > +RISCVCPU *cpu = RISCV_CPU(obj); > > + > > #if defined(TARGET_RISCV32) > > set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU); > > +set_satp_mode_max_supported(cpu, "sv32", true); > > #elif defined(TARGET_RISCV64) > > set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); > > +set_satp_mode_max_supported(cpu, "sv57", false); > > #endif > > set_priv_version(env, PRIV_VERSION_1_12_0); > > register_cpu_props(obj); > > @@ -319,18 +334,24 @@ static void riscv_any_cpu_init(Object *obj) > > static void rv64_base_cpu_init(Object *obj) > > { > > CPURISCVState *env = _CPU(obj)->env; > > +RISCVCPU *cpu = RISCV_CPU(obj); > > + > > /* We set this in the realise function */ > > set_misa(env, MXL_RV64, 0); > > register_cpu_props(obj); > > /* Set latest version of privileged specification */ > > set_priv_version(env, PRIV_VERSION_1_12_0); > > +set_satp_mode_max_supported(cpu, "sv57", false); > > } > > > > static void rv64_sifive_u_cpu_init(Object *obj) > > { > > CPURISCVState *env = _CPU(obj)->env; > > +RISCVCPU *cpu = RISCV_CPU(obj); > > + > > set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); > > set_priv_version(env, PRIV_VERSION_1_10_0); > > +set_satp_mode_max_supported(cpu, "sv39", false); > > Can we just not expose the properties on these vendor CPUs and then > not worry about setting maximums? > I'm not sure I understand: the properties are actually not exposed to the vendor cpus from what I see (no calls to register_cpu_props). The problem this patch fixes is that the only constraint on satp is
Re: [PATCH v6 5/5] riscv: Introduce satp mode hw capabilities
On Mon, Jan 23, 2023 at 11:51 AM Andrew Jones wrote: > > On Mon, Jan 23, 2023 at 10:03:24AM +0100, Alexandre Ghiti wrote: > > Currently, the max satp mode is set with the only constraint that it must be > > implemented in qemu, i.e. set in valid_vm_1_10_[32|64]. > > > > But we actually need to add another level of constraint: what the hw is > > actually capable of, because currently, a linux booting on a sifive-u54 > > boots in sv57 mode which is incompatible with the cpu's sv39 max > > capability. > > > > So add a new bitmap to RISCVSATPMap which contains this capability and > > initialize it in every XXX_cpu_init. > > > > Finally, we have the following chain of constraints: > > > > Qemu capability > HW capability > User choice > Software capability > > ^ What software is this? > I'd think the user's choice would always be last. > > > > > Signed-off-by: Alexandre Ghiti > > --- > > target/riscv/cpu.c | 78 +++--- > > target/riscv/cpu.h | 8 +++-- > > 2 files changed, 59 insertions(+), 27 deletions(-) > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index e409e6ab64..19a37fee2b 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool > > is_32_bit) > > g_assert_not_reached(); > > } > > > > -/* Sets the satp mode to the max supported */ > > -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit) > > +static void set_satp_mode_max_supported(RISCVCPU *cpu, > > +const char *satp_mode_str, > > +bool is_32_bit) > > { > > -if (riscv_feature(>env, RISCV_FEATURE_MMU)) { > > -cpu->cfg.satp_mode.map |= > > -(1 << satp_mode_from_str(is_32_bit ? "sv32" : > > "sv57")); > > -} else { > > -cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); > > +uint8_t satp_mode = satp_mode_from_str(satp_mode_str); > > +const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64; > > + > > +for (int i = 0; i <= satp_mode; ++i) { > > +if (valid_vm[i]) { > > +cpu->cfg.satp_mode.supported |= (1 << i); > > I don't think we need a new 'supported' bitmap, I think each board that > needs to further constrain va-bits from what QEMU supports should just set > valid_vm_1_10_32/64. I.e. drop const from the arrays and add an init > function something like This was my first idea too, but those arrays are global and I have to admit that I thought it was possible to emulate a cpu with different cores. Anyway, isn't it a bit weird to store this into some global array whereas it is intimately linked to the CPU? To me, it makes sense to keep those variables as a way to know what qemu is able to emulate and have a CPU specific map like in this patch for the hw capabilities. Does it make sense to you? > > #define QEMU_SATP_MODE_MAX VM_1_10_SV64 > > void riscv_cpu_set_satp_mode_max(RISCVCPU *cpu, uint8_t satp_mode_max) > { > bool is_32_bit = cpu->env.misa_mxl == MXL_RV32; > bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64; > > g_assert(satp_mode_max <= QEMU_SATP_MODE_MAX); > g_assert(!is_32_bit || satp_mode_max < 2); > > memset(valid_vm, 0, sizeof(*valid_vm)); > > for (int i = 0; i <= satp_mode_max; i++) { > valid_vm[i] = true; > } > } > > The valid_vm[] checks already in finalize should then manage the > validation needed to constrain boards. Only boards that care about > this need to call this function, otherwise they'll get the default. > > Also, this patch should come before the patch that changes the default > for all boards to sv57 in order to avoid breaking bisection. As I explained earlier, I didn't change the default to sv57! Just fixed what was passed via the device tree, which should not be used anyway :) Alex > > Thanks, > drew
[PATCH v6 1/5] riscv: Pass Object to register_cpu_props instead of DeviceState
One can extract the DeviceState pointer from the Object pointer, so pass the Object for future commits to access other fields of Object. No functional changes intended. Reviewed-by: Alistair Francis Reviewed-by: Frank Chang Reviewed-by: Andrew Jones Signed-off-by: Alexandre Ghiti --- target/riscv/cpu.c | 15 --- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index cc75ca7667..7181b34f86 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -200,7 +200,7 @@ static const char * const riscv_intr_names[] = { "reserved" }; -static void register_cpu_props(DeviceState *dev); +static void register_cpu_props(Object *obj); const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) { @@ -238,7 +238,7 @@ static void riscv_any_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif set_priv_version(env, PRIV_VERSION_1_12_0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #if defined(TARGET_RISCV64) @@ -247,7 +247,7 @@ static void rv64_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -280,7 +280,7 @@ static void rv128_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -290,7 +290,7 @@ static void rv32_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV32, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -343,7 +343,7 @@ static void riscv_host_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, 0); #endif -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #endif @@ -1083,9 +1083,10 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_END_OF_LIST(), }; -static void register_cpu_props(DeviceState *dev) +static void register_cpu_props(Object *obj) { Property *prop; +DeviceState *dev = DEVICE(obj); for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { qdev_property_add_static(dev, prop); -- 2.37.2
[PATCH v6 5/5] riscv: Introduce satp mode hw capabilities
Currently, the max satp mode is set with the only constraint that it must be implemented in qemu, i.e. set in valid_vm_1_10_[32|64]. But we actually need to add another level of constraint: what the hw is actually capable of, because currently, a linux booting on a sifive-u54 boots in sv57 mode which is incompatible with the cpu's sv39 max capability. So add a new bitmap to RISCVSATPMap which contains this capability and initialize it in every XXX_cpu_init. Finally, we have the following chain of constraints: Qemu capability > HW capability > User choice > Software capability Signed-off-by: Alexandre Ghiti --- target/riscv/cpu.c | 78 +++--- target/riscv/cpu.h | 8 +++-- 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index e409e6ab64..19a37fee2b 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -292,24 +292,39 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) g_assert_not_reached(); } -/* Sets the satp mode to the max supported */ -static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit) +static void set_satp_mode_max_supported(RISCVCPU *cpu, +const char *satp_mode_str, +bool is_32_bit) { -if (riscv_feature(>env, RISCV_FEATURE_MMU)) { -cpu->cfg.satp_mode.map |= -(1 << satp_mode_from_str(is_32_bit ? "sv32" : "sv57")); -} else { -cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); +uint8_t satp_mode = satp_mode_from_str(satp_mode_str); +const bool *valid_vm = is_32_bit ? valid_vm_1_10_32 : valid_vm_1_10_64; + +for (int i = 0; i <= satp_mode; ++i) { +if (valid_vm[i]) { +cpu->cfg.satp_mode.supported |= (1 << i); +} } } +/* Sets the satp mode to the max supported */ +static void set_satp_mode_default(RISCVCPU *cpu) +{ +uint8_t satp_mode = satp_mode_max_from_map(cpu->cfg.satp_mode.supported); + +cpu->cfg.satp_mode.map |= (1 << satp_mode); +} + static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + #if defined(TARGET_RISCV32) set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU); +set_satp_mode_max_supported(cpu, "sv32", true); #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); +set_satp_mode_max_supported(cpu, "sv57", false); #endif set_priv_version(env, PRIV_VERSION_1_12_0); register_cpu_props(obj); @@ -319,18 +334,24 @@ static void riscv_any_cpu_init(Object *obj) static void rv64_base_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +set_satp_mode_max_supported(cpu, "sv57", false); } static void rv64_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); +set_satp_mode_max_supported(cpu, "sv39", false); } static void rv64_sifive_e_cpu_init(Object *obj) @@ -341,6 +362,7 @@ static void rv64_sifive_e_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); cpu->cfg.mmu = false; +set_satp_mode_max_supported(cpu, "mbare", false); } static void rv128_base_cpu_init(Object *obj) @@ -352,11 +374,13 @@ static void rv128_base_cpu_init(Object *obj) exit(EXIT_FAILURE); } CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +set_satp_mode_max_supported(cpu, "sv57", false); } #else static void rv32_base_cpu_init(Object *obj) @@ -367,13 +391,17 @@ static void rv32_base_cpu_init(Object *obj) register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); +set_satp_mode_max_supported(cpu, "sv32", true); } static void rv32_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; +RISCVCPU *cpu = RISCV_CPU(obj); + set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); +
[PATCH v6 4/5] riscv: Correctly set the device-tree entry 'mmu-type'
The 'mmu-type' should reflect what the hardware is capable of so use the new satp_mode field in RISCVCPUConfig to do that. Signed-off-by: Alexandre Ghiti --- hw/riscv/virt.c | 19 ++- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 94ff2a1584..48d034a5f7 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -228,7 +228,8 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, int cpu; uint32_t cpu_phandle; MachineState *mc = MACHINE(s); -char *name, *cpu_name, *core_name, *intc_name; +uint8_t satp_mode_max; +char *name, *cpu_name, *core_name, *intc_name, *sv_name; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { cpu_phandle = (*phandle)++; @@ -236,14 +237,14 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(mc->fdt, cpu_name); -if (riscv_feature(>soc[socket].harts[cpu].env, - RISCV_FEATURE_MMU)) { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -(is_32_bit) ? "riscv,sv32" : "riscv,sv48"); -} else { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -"riscv,none"); -} + +satp_mode_max = satp_mode_max_from_map( +s->soc[socket].harts[cpu].cfg.satp_mode.map); +sv_name = g_strdup_printf("riscv,%s", + satp_mode_str(satp_mode_max, is_32_bit)); +qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); +g_free(sv_name); + name = riscv_isa_string(>soc[socket].harts[cpu]); qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); g_free(name); -- 2.37.2
[PATCH v6 3/5] riscv: Allow user to set the satp mode
RISC-V specifies multiple sizes for addressable memory and Linux probes for the machine's support at startup via the satp CSR register (done in csr.c:validate_vm). As per the specification, sv64 must support sv57, which in turn must support sv48...etc. So we can restrict machine support by simply setting the "highest" supported mode and the bare mode is always supported. You can set the satp mode using the new properties "sv32", "sv39", "sv48", "sv57" and "sv64" as follows: -cpu rv64,sv57=on # Linux will boot using sv57 scheme -cpu rv64,sv39=on # Linux will boot using sv39 scheme -cpu rv64,sv57=off # Linux will boot using sv48 scheme -cpu rv64 # Linux will boot using sv57 scheme by default We take the highest level set by the user: -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme We make sure that invalid configurations are rejected: -cpu rv64,sv32=on # Can't enable 32-bit satp mode in 64-bit -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are # enabled We accept "redundant" configurations: -cpu rv64,sv48=on,sv57=off # Linux will boot using sv48 scheme And contradictory configurations: -cpu rv64,sv48=on,sv48=off # Linux will boot using sv39 scheme In addition, we now correctly set the device-tree entry 'mmu-type' using those new properties. Co-Developed-by: Ludovic Henry Signed-off-by: Ludovic Henry Signed-off-by: Alexandre Ghiti --- target/riscv/cpu.c | 204 + target/riscv/cpu.h | 19 + target/riscv/csr.c | 12 ++- 3 files changed, 228 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 7181b34f86..e409e6ab64 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -27,6 +27,7 @@ #include "time_helper.h" #include "exec/exec-all.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "qemu/error-report.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" @@ -229,6 +230,79 @@ static void set_vext_version(CPURISCVState *env, int vext_ver) env->vext_ver = vext_ver; } +static uint8_t satp_mode_from_str(const char *satp_mode_str) +{ +if (!strncmp(satp_mode_str, "mbare", 5)) { +return VM_1_10_MBARE; +} + +if (!strncmp(satp_mode_str, "sv32", 4)) { +return VM_1_10_SV32; +} + +if (!strncmp(satp_mode_str, "sv39", 4)) { +return VM_1_10_SV39; +} + +if (!strncmp(satp_mode_str, "sv48", 4)) { +return VM_1_10_SV48; +} + +if (!strncmp(satp_mode_str, "sv57", 4)) { +return VM_1_10_SV57; +} + +if (!strncmp(satp_mode_str, "sv64", 4)) { +return VM_1_10_SV64; +} + +g_assert_not_reached(); +} + +uint8_t satp_mode_max_from_map(uint32_t map) +{ +/* map here has at least one bit set, so no problem with clz */ +return 31 - __builtin_clz(map); +} + +const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) +{ +if (is_32_bit) { +switch (satp_mode) { +case VM_1_10_SV32: +return "sv32"; +case VM_1_10_MBARE: +return "none"; +} +} else { +switch (satp_mode) { +case VM_1_10_SV64: +return "sv64"; +case VM_1_10_SV57: +return "sv57"; +case VM_1_10_SV48: +return "sv48"; +case VM_1_10_SV39: +return "sv39"; +case VM_1_10_MBARE: +return "none"; +} +} + +g_assert_not_reached(); +} + +/* Sets the satp mode to the max supported */ +static void set_satp_mode_default(RISCVCPU *cpu, bool is_32_bit) +{ +if (riscv_feature(>env, RISCV_FEATURE_MMU)) { +cpu->cfg.satp_mode.map |= +(1 << satp_mode_from_str(is_32_bit ? "sv32" : "sv57")); +} else { +cpu->cfg.satp_mode.map |= (1 << satp_mode_from_str("mbare")); +} +} + static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = _CPU(obj)->env; @@ -619,6 +693,82 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) } } +static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) +{ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; +const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; + +if (cpu->cfg.satp_mode.map == 0) { +/* + * If unset by both the user and the cpu, we fallback to the default + * satp mode. + */ +if (cpu->cfg.satp_mode.init == 0) { +set_satp_mode_default(cpu, rv32); +} else { +/* + * Find the lowest level that was disabled and then enable the +
[PATCH v6 2/5] riscv: Change type of valid_vm_1_10_[32|64] to bool
This array is actually used as a boolean so swap its current char type to a boolean and at the same time, change the type of validate_vm to bool since it returns valid_vm_1_10_[32|64]. Signed-off-by: Alexandre Ghiti --- target/riscv/csr.c | 21 +++-- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 0db2c233e5..6b157806a5 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1117,16 +1117,16 @@ static const target_ulong hip_writable_mask = MIP_VSSIP; static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; static const target_ulong vsip_writable_mask = MIP_VSSIP; -static const char valid_vm_1_10_32[16] = { -[VM_1_10_MBARE] = 1, -[VM_1_10_SV32] = 1 +static const bool valid_vm_1_10_32[16] = { +[VM_1_10_MBARE] = true, +[VM_1_10_SV32] = true }; -static const char valid_vm_1_10_64[16] = { -[VM_1_10_MBARE] = 1, -[VM_1_10_SV39] = 1, -[VM_1_10_SV48] = 1, -[VM_1_10_SV57] = 1 +static const bool valid_vm_1_10_64[16] = { +[VM_1_10_MBARE] = true, +[VM_1_10_SV39] = true, +[VM_1_10_SV48] = true, +[VM_1_10_SV57] = true }; /* Machine Information Registers */ @@ -1209,7 +1209,7 @@ static RISCVException read_mstatus(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int validate_vm(CPURISCVState *env, target_ulong vm) +static bool validate_vm(CPURISCVState *env, target_ulong vm) { if (riscv_cpu_mxl(env) == MXL_RV32) { return valid_vm_1_10_32[vm & 0xf]; @@ -2648,7 +2648,8 @@ static RISCVException read_satp(CPURISCVState *env, int csrno, static RISCVException write_satp(CPURISCVState *env, int csrno, target_ulong val) { -target_ulong vm, mask; +target_ulong mask; +bool vm; if (!riscv_feature(env, RISCV_FEATURE_MMU)) { return RISCV_EXCP_NONE; -- 2.37.2
[PATCH v6 0/5] riscv: Allow user to set the satp mode
This introduces new properties to allow the user to set the satp mode, see patch 3 for full syntax. In addition, it prevents cpus to boot in a satp mode they do not support (see patch 5). v6: - Remove the valid_vm check in validate_vm and add it to the finalize function so that map already contains the constraint, Alex - Add forgotten mbare to satp_mode_from_str, Alex - Move satp mode properties handling to riscv_cpu_satp_mode_finalize, Andrew - Only add satp mode properties corresponding to the cpu, and then remove the check against valid_vm_1_10_32/64 in riscv_cpu_satp_mode_finalize, Andrew/Alistair/Alex - Move mmu-type setting to its own patch, Andrew - patch 5 is new and is a fix, Alex v5: - Simplify v4 implementation by leveraging valid_vm_1_10_32/64, as suggested by Andrew - Split the v4 patch into 2 patches as suggested by Andrew - Lot of other minor corrections, from Andrew - Set the satp mode N by disabling the satp mode N + 1 - Add a helper to set satp mode from a string, as suggested by Frank v4: - Use custom boolean properties instead of OnOffAuto properties, based on ARMVQMap, as suggested by Andrew v3: - Free sv_name as pointed by Bin - Replace satp-mode with boolean properties as suggested by Andrew - Removed RB from Atish as the patch considerably changed v2: - Use error_setg + return as suggested by Alistair - Add RB from Atish - Fixed checkpatch issues missed in v1 - Replaced Ludovic email address with the rivos one Alexandre Ghiti (5): riscv: Pass Object to register_cpu_props instead of DeviceState riscv: Change type of valid_vm_1_10_[32|64] to bool riscv: Allow user to set the satp mode riscv: Correctly set the device-tree entry 'mmu-type' riscv: Introduce satp mode hw capabilities hw/riscv/virt.c| 19 ++-- target/riscv/cpu.c | 247 +++-- target/riscv/cpu.h | 23 + target/riscv/csr.c | 29 +++--- 4 files changed, 287 insertions(+), 31 deletions(-) -- 2.37.2
Re: [PATCH v5 2/2] riscv: Allow user to set the satp mode
On Fri, Jan 20, 2023 at 10:53 AM Andrew Jones wrote: > > On Fri, Jan 20, 2023 at 09:46:05AM +1000, Alistair Francis wrote: > > On Thu, Jan 19, 2023 at 11:00 PM Alexandre Ghiti > > wrote: > > > > > > Hi Alistair, Andrew, > > > > > > On Thu, Jan 19, 2023 at 1:25 AM Alistair Francis > > > wrote: > > > > > > > > On Wed, Jan 18, 2023 at 10:19 PM Andrew Jones > > > > wrote: > > > > > > > > > > On Wed, Jan 18, 2023 at 10:28:46AM +1000, Alistair Francis wrote: > > > > > > On Wed, Jan 18, 2023 at 2:32 AM Andrew Jones > > > > > > wrote: > > > > > > > > > > > > > > On Fri, Jan 13, 2023 at 11:34:53AM +0100, Alexandre Ghiti wrote: > > > > > ... > > > > > > > > + > > > > > > > > +/* Get rid of 32-bit/64-bit incompatibility */ > > > > > > > > +for (int i = 0; i < 16; ++i) { > > > > > > > > +if ((cpu->cfg.satp_mode.map & (1 << i)) && > > > > > > > > !valid_vm[i]) { > > > > > > > > > > > > > > If we ever define mode=1 for rv64, then 'sv32=on' will be > > > > > > > incorrectly > > > > > > > accepted as an alias. I think we should simply not define the sv32 > > > > > > > property for rv64 nor the rv64-only modes for rv32. So, down in > > > > > > > riscv_add_satp_mode_properties() we can add some > > > > > > > > > > > > > > #if defined(TARGET_RISCV32) > > > > > > > ... > > > > > > > #elif defined(TARGET_RISCV64) > > > > > > > ... > > > > > > > #endif > > > > > > > > > > > > Do not add any #if defined(TARGET_RISCV32) to QEMU. > > > > > > > > > > > > We are aiming for the riscv64-softmmu to be able to emulate 32-bit > > > > > > CPUs and compile time macros are the wrong solution here. Instead > > > > > > you > > > > > > can get the xlen of the hart and use that. > > > > > > > > > > > > > > > > Does this mean we want to be able to do the following? > > > > > > > > > > qemu-system-riscv64 -cpu rv32,sv32=on ... > > > > > > > > That's the plan > > > > > > > > > > > > > > If so, then can we move the object_property_add() for sv32 to > > > > > rv32_base_cpu_init() and the rest to rv64_base_cpu_init()? > > > > Wait! Sorry I didn't read this carefully enough. No, that is not what > > we want to do. That then won't support the vendor CPUs. > > > > We just want to add the properties to all CPUs. Then if an invalid > > option is set we should return an error. Maybe I just don't get this part... > > > > Note that the 64-bit only configs can be hidden behind a #if > > defined(TARGET_RISCV64). > > OK, so we want the original suggestion of putting an > 'if defined(TARGET_RISCV64)' in riscv_add_satp_mode_properties(), > which is called from register_cpu_props(), for the 64-bit only > configs, but to support emulation we can't put sv32 under an > 'if defined(TARGET_RISCV32)'. Instead, we need to check the xlen > supported by the cpu type. That makes sense to me, and I think > it'd be easiest to do in cpu_riscv_set_satp() with something like > > if (!strncmp(name, "rv32", 4) && > RISCV_CPU(obj)->env.misa_mxl != MXL_RV32) { > ... fail with error message ... > } > ...but what about simply using the runtime check when we add the properties? Like this: static void riscv_add_satp_mode_properties(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); if (cpu->env.misa_mxl == MXL_RV32) { object_property_add(obj, "sv32", "bool", cpu_riscv_get_satp, cpu_riscv_set_satp, NULL, >cfg.satp_mode); } else { object_property_add(obj, "sv39", "bool", cpu_riscv_get_satp, cpu_riscv_set_satp, NULL, >cfg.satp_mode); object_property_add(obj, "sv48", "bool", cpu_riscv_get_satp, cpu_riscv_set_satp, NULL, >cfg.satp_mode); object_property_add(obj, "sv57", "bool", cpu_riscv_get_satp, cpu_riscv_set_satp, NULL, >cfg.satp_mode); object_property_add(obj, "sv64", "bool", cpu_riscv_get_satp, cpu_riscv_set_satp, NULL, >cfg.satp_mode); } } > Thanks, > drew
Re: [PATCH v5 2/2] riscv: Allow user to set the satp mode
Hi Alistair, Andrew, On Thu, Jan 19, 2023 at 1:25 AM Alistair Francis wrote: > > On Wed, Jan 18, 2023 at 10:19 PM Andrew Jones wrote: > > > > On Wed, Jan 18, 2023 at 10:28:46AM +1000, Alistair Francis wrote: > > > On Wed, Jan 18, 2023 at 2:32 AM Andrew Jones > > > wrote: > > > > > > > > On Fri, Jan 13, 2023 at 11:34:53AM +0100, Alexandre Ghiti wrote: > > ... > > > > > + > > > > > +/* Get rid of 32-bit/64-bit incompatibility */ > > > > > +for (int i = 0; i < 16; ++i) { > > > > > +if ((cpu->cfg.satp_mode.map & (1 << i)) && !valid_vm[i]) { > > > > > > > > If we ever define mode=1 for rv64, then 'sv32=on' will be incorrectly > > > > accepted as an alias. I think we should simply not define the sv32 > > > > property for rv64 nor the rv64-only modes for rv32. So, down in > > > > riscv_add_satp_mode_properties() we can add some > > > > > > > > #if defined(TARGET_RISCV32) > > > > ... > > > > #elif defined(TARGET_RISCV64) > > > > ... > > > > #endif > > > > > > Do not add any #if defined(TARGET_RISCV32) to QEMU. > > > > > > We are aiming for the riscv64-softmmu to be able to emulate 32-bit > > > CPUs and compile time macros are the wrong solution here. Instead you > > > can get the xlen of the hart and use that. > > > > > > > Does this mean we want to be able to do the following? > > > > qemu-system-riscv64 -cpu rv32,sv32=on ... > > That's the plan > > > > > If so, then can we move the object_property_add() for sv32 to > > rv32_base_cpu_init() and the rest to rv64_base_cpu_init()? > > Currently, that would be doing the same thing as proposed above, > > since those functions are under TARGET_RISCV* defines, but I guess > > the object_property_add()'s would then be in more or less the right > > places for when the 32-bit emulation support work is started. > > Sounds like a good idea :) What about riscv_any_cpu_init and riscv_host_cpu_init? > > Alistair > > > > > Thanks, > > drew
Re: [PATCH v5 2/2] riscv: Allow user to set the satp mode
Hey Andrew, On Tue, Jan 17, 2023 at 5:31 PM Andrew Jones wrote: > > On Fri, Jan 13, 2023 at 11:34:53AM +0100, Alexandre Ghiti wrote: > > RISC-V specifies multiple sizes for addressable memory and Linux probes for > > the machine's support at startup via the satp CSR register (done in > > csr.c:validate_vm). > > > > As per the specification, sv64 must support sv57, which in turn must > > support sv48...etc. So we can restrict machine support by simply setting the > > "highest" supported mode and the bare mode is always supported. > > > > You can set the satp mode using the new properties "sv32", "sv39", "sv48", > > "sv57" and "sv64" as follows: > > -cpu rv64,sv57=on # Linux will boot using sv57 scheme > > -cpu rv64,sv39=on # Linux will boot using sv39 scheme > > -cpu rv64,sv57=off # Linux will boot using sv48 scheme > > -cpu rv64 # Linux will boot using sv57 scheme by default > > > > We take the highest level set by the user: > > -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme > > > > We make sure that invalid configurations are rejected: > > -cpu rv64,sv32=on # Can't enable 32-bit satp mode in 64-bit > > -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are > ># enabled > > > > We accept "redundant" configurations: > > -cpu rv64,sv48=on,sv57=off # Linux will boot using sv48 scheme > > -cpu rv64,sv32=on,sv32=off # Linux will boot using sv57 scheme (the default) > > > > In addition, we now correctly set the device-tree entry 'mmu-type' using > > those new properties. > > > > Co-Developed-by: Ludovic Henry > > Signed-off-by: Ludovic Henry > > Signed-off-by: Alexandre Ghiti > > --- > > hw/riscv/virt.c| 19 ++-- > > target/riscv/cpu.c | 221 + > > target/riscv/cpu.h | 19 > > target/riscv/csr.c | 17 +++- > > 4 files changed, 262 insertions(+), 14 deletions(-) > > > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c > > index 94ff2a1584..48d034a5f7 100644 > > --- a/hw/riscv/virt.c > > +++ b/hw/riscv/virt.c > > @@ -228,7 +228,8 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, > > int socket, > > int cpu; > > uint32_t cpu_phandle; > > MachineState *mc = MACHINE(s); > > -char *name, *cpu_name, *core_name, *intc_name; > > +uint8_t satp_mode_max; > > +char *name, *cpu_name, *core_name, *intc_name, *sv_name; > > > > for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { > > cpu_phandle = (*phandle)++; > > @@ -236,14 +237,14 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, > > int socket, > > cpu_name = g_strdup_printf("/cpus/cpu@%d", > > s->soc[socket].hartid_base + cpu); > > qemu_fdt_add_subnode(mc->fdt, cpu_name); > > -if (riscv_feature(>soc[socket].harts[cpu].env, > > - RISCV_FEATURE_MMU)) { > > -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", > > -(is_32_bit) ? "riscv,sv32" : > > "riscv,sv48"); > > I just noticed that for the virt machine type, when the user doesn't > provide a satp mode cpu property on the command line, and hence gets > the default mode, they'll be silently changed from sv48 to sv57. That > default change should be a separate patch which comes after this one. > BTW, why sv57 and not sv48 or sv64? The device tree entry should match the max available satp mode even though it makes little sense to have this entry in the first place: the max satp mode is easily discoverable at runtime (the kernel does that and does not care about the device tree entry). But yes, this fix was mentioned at the very end of the commit log, which was weird anyway, so I'll move that to its own patch. > > > -} else { > > -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", > > -"riscv,none"); > > -} > > + > > +satp_mode_max = satp_mode_max_from_map( > > +s->soc[socket].harts[cpu].cfg.satp_mode.map); > > +sv_name = g_strdup_printf("riscv,%s", > > + satp_mode_str(satp_mode_max, is_32_bit)); > > +qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); > > +g_free(sv_name); > > + > >
[PATCH v5 2/2] riscv: Allow user to set the satp mode
RISC-V specifies multiple sizes for addressable memory and Linux probes for the machine's support at startup via the satp CSR register (done in csr.c:validate_vm). As per the specification, sv64 must support sv57, which in turn must support sv48...etc. So we can restrict machine support by simply setting the "highest" supported mode and the bare mode is always supported. You can set the satp mode using the new properties "sv32", "sv39", "sv48", "sv57" and "sv64" as follows: -cpu rv64,sv57=on # Linux will boot using sv57 scheme -cpu rv64,sv39=on # Linux will boot using sv39 scheme -cpu rv64,sv57=off # Linux will boot using sv48 scheme -cpu rv64 # Linux will boot using sv57 scheme by default We take the highest level set by the user: -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme We make sure that invalid configurations are rejected: -cpu rv64,sv32=on # Can't enable 32-bit satp mode in 64-bit -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are # enabled We accept "redundant" configurations: -cpu rv64,sv48=on,sv57=off # Linux will boot using sv48 scheme -cpu rv64,sv32=on,sv32=off # Linux will boot using sv57 scheme (the default) In addition, we now correctly set the device-tree entry 'mmu-type' using those new properties. Co-Developed-by: Ludovic Henry Signed-off-by: Ludovic Henry Signed-off-by: Alexandre Ghiti --- hw/riscv/virt.c| 19 ++-- target/riscv/cpu.c | 221 + target/riscv/cpu.h | 19 target/riscv/csr.c | 17 +++- 4 files changed, 262 insertions(+), 14 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 94ff2a1584..48d034a5f7 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -228,7 +228,8 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, int cpu; uint32_t cpu_phandle; MachineState *mc = MACHINE(s); -char *name, *cpu_name, *core_name, *intc_name; +uint8_t satp_mode_max; +char *name, *cpu_name, *core_name, *intc_name, *sv_name; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { cpu_phandle = (*phandle)++; @@ -236,14 +237,14 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(mc->fdt, cpu_name); -if (riscv_feature(>soc[socket].harts[cpu].env, - RISCV_FEATURE_MMU)) { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -(is_32_bit) ? "riscv,sv32" : "riscv,sv48"); -} else { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -"riscv,none"); -} + +satp_mode_max = satp_mode_max_from_map( +s->soc[socket].harts[cpu].cfg.satp_mode.map); +sv_name = g_strdup_printf("riscv,%s", + satp_mode_str(satp_mode_max, is_32_bit)); +qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); +g_free(sv_name); + name = riscv_isa_string(>soc[socket].harts[cpu]); qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); g_free(name); diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 7181b34f86..1f0d040a80 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -27,6 +27,7 @@ #include "time_helper.h" #include "exec/exec-all.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "qemu/error-report.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" @@ -229,6 +230,85 @@ static void set_vext_version(CPURISCVState *env, int vext_ver) env->vext_ver = vext_ver; } +static uint8_t satp_mode_from_str(const char *satp_mode_str) +{ +if (!strncmp(satp_mode_str, "sv32", 4)) { +return VM_1_10_SV32; +} + +if (!strncmp(satp_mode_str, "sv39", 4)) { +return VM_1_10_SV39; +} + +if (!strncmp(satp_mode_str, "sv48", 4)) { +return VM_1_10_SV48; +} + +if (!strncmp(satp_mode_str, "sv57", 4)) { +return VM_1_10_SV57; +} + +if (!strncmp(satp_mode_str, "sv64", 4)) { +return VM_1_10_SV64; +} + +g_assert_not_reached(); +} + +uint8_t satp_mode_max_from_map(uint32_t map) +{ +/* map here has at least one bit set, so no problem with clz */ +return 31 - __builtin_clz(map); +} + +const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) +{ +if (is_32_bit) { +switch (satp_mode) { +case VM_1_10_SV32: +return "sv32"; +
[PATCH v5 1/2] riscv: Pass Object to register_cpu_props instead of DeviceState
One can extract the DeviceState pointer from the Object pointer, so pass the Object for future commits to access other fields of Object. No functional changes intended. Signed-off-by: Alexandre Ghiti --- target/riscv/cpu.c | 15 --- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index cc75ca7667..7181b34f86 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -200,7 +200,7 @@ static const char * const riscv_intr_names[] = { "reserved" }; -static void register_cpu_props(DeviceState *dev); +static void register_cpu_props(Object *obj); const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) { @@ -238,7 +238,7 @@ static void riscv_any_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif set_priv_version(env, PRIV_VERSION_1_12_0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #if defined(TARGET_RISCV64) @@ -247,7 +247,7 @@ static void rv64_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV64, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -280,7 +280,7 @@ static void rv128_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV128, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -290,7 +290,7 @@ static void rv32_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa(env, MXL_RV32, 0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); /* Set latest version of privileged specification */ set_priv_version(env, PRIV_VERSION_1_12_0); } @@ -343,7 +343,7 @@ static void riscv_host_cpu_init(Object *obj) #elif defined(TARGET_RISCV64) set_misa(env, MXL_RV64, 0); #endif -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #endif @@ -1083,9 +1083,10 @@ static Property riscv_cpu_extensions[] = { DEFINE_PROP_END_OF_LIST(), }; -static void register_cpu_props(DeviceState *dev) +static void register_cpu_props(Object *obj) { Property *prop; +DeviceState *dev = DEVICE(obj); for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { qdev_property_add_static(dev, prop); -- 2.37.2
[PATCH v5 0/2] riscv: Allow user to set the satp mode
This introduces new properties to allow the user to set the satp mode, see patch 1 for full syntax. v5: - Simplify v4 implementation by leveraging valid_vm_1_10_32/64, as suggested by Andrew - Split the v4 patch into 2 patches as suggested by Andrew - Lot of other minor corrections, from Andrew - Set the satp mode N by disabling the satp mode N + 1 - Add a helper to set satp mode from a string, as suggested by Frank v4: - Use custom boolean properties instead of OnOffAuto properties, based on ARMVQMap, as suggested by Andrew v3: - Free sv_name as pointed by Bin - Replace satp-mode with boolean properties as suggested by Andrew - Removed RB from Atish as the patch considerably changed v2: - Use error_setg + return as suggested by Alistair - Add RB from Atish - Fixed checkpatch issues missed in v1 - Replaced Ludovic email address with the rivos one Alexandre Ghiti (2): riscv: Pass Object to register_cpu_props instead of DeviceState riscv: Allow user to set the satp mode hw/riscv/virt.c| 19 ++-- target/riscv/cpu.c | 236 +++-- target/riscv/cpu.h | 19 target/riscv/csr.c | 17 +++- 4 files changed, 270 insertions(+), 21 deletions(-) -- 2.37.2
Re: [PATCH v4] riscv: Allow user to set the satp mode
Hey Andrew, Sorry about the response delay, I was traveling. On Fri, Jan 6, 2023 at 4:30 PM Andrew Jones wrote: > > On Mon, Dec 12, 2022 at 11:22:50AM +0100, Alexandre Ghiti wrote: > > RISC-V specifies multiple sizes for addressable memory and Linux probes for > > the machine's support at startup via the satp CSR register (done in > > csr.c:validate_vm). > > > > As per the specification, sv64 must support sv57, which in turn must > > support sv48...etc. So we can restrict machine support by simply setting the > > "highest" supported mode and the bare mode is always supported. > > > > You can set the satp mode using the new properties "mbare", "sv32", > > "sv39", "sv48", "sv57" and "sv64" as follows: > > -cpu rv64,sv57=on # Linux will boot using sv57 scheme > > -cpu rv64,sv39=on # Linux will boot using sv39 scheme > > > > We take the highest level set by the user: > > -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme > > > > We make sure that invalid configurations are rejected: > > -cpu rv64,sv32=on # Can't enable 32-bit satp mode in 64-bit > > -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are > > # enabled > > > > We accept "redundant" configurations: > > -cpu rv64,sv48=on,sv57=off # sv39 must be supported if higher modes are > ^ from this #, it looks like a copy+paste > mistake Yes, something is not right here, thanks. > > > > In addition, we now correctly set the device-tree entry 'mmu-type' using > > those new properties. > > > > Co-Developed-by: Ludovic Henry > > Signed-off-by: Ludovic Henry > > Signed-off-by: Alexandre Ghiti > > --- > > v4: > > - Use custom boolean properties instead of OnOffAuto properties, based > > on ARMVQMap, as suggested by Andrew > > > > v3: > > - Free sv_name as pointed by Bin > > - Replace satp-mode with boolean properties as suggested by Andrew > > - Removed RB from Atish as the patch considerably changed > > > > v2: > > - Use error_setg + return as suggested by Alistair > > - Add RB from Atish > > - Fixed checkpatch issues missed in v1 > > - Replaced Ludovic email address with the rivos one > > > > hw/riscv/virt.c| 20 +++-- > > target/riscv/cpu.c | 217 +++-- > > target/riscv/cpu.h | 25 ++ > > target/riscv/csr.c | 13 ++- > > 4 files changed, 256 insertions(+), 19 deletions(-) > > > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c > > index a5bc7353b4..9bb5ba7366 100644 > > --- a/hw/riscv/virt.c > > +++ b/hw/riscv/virt.c > > @@ -228,7 +228,8 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, > > int socket, > > int cpu; > > uint32_t cpu_phandle; > > MachineState *mc = MACHINE(s); > > -char *name, *cpu_name, *core_name, *intc_name; > > +uint8_t satp_mode_max; > > +char *name, *cpu_name, *core_name, *intc_name, *sv_name; > > > > for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { > > cpu_phandle = (*phandle)++; > > @@ -236,14 +237,15 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, > > int socket, > > cpu_name = g_strdup_printf("/cpus/cpu@%d", > > s->soc[socket].hartid_base + cpu); > > qemu_fdt_add_subnode(mc->fdt, cpu_name); > > -if (riscv_feature(>soc[socket].harts[cpu].env, > > - RISCV_FEATURE_MMU)) { > > -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", > > -(is_32_bit) ? "riscv,sv32" : > > "riscv,sv48"); > > -} else { > > -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", > > -"riscv,none"); > > -} > > + > > +satp_mode_max = satp_mode_max_from_map( > > +s->soc[socket].harts[cpu].cfg.satp_mode.map, > > +is_32_bit); > > +sv_name = g_strdup_printf("riscv,%s", > > + satp_mode_str(satp_mode_max, is_32_bit)); > > +qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); > > +g_free(sv_name); > > + > > name = riscv_isa_string(>soc[socket].harts[cpu]); > > qemu
Re: [PATCH v4] riscv: Allow user to set the satp mode
On Fri, Dec 16, 2022 at 2:03 PM Alexandre Ghiti wrote: > > Hi Frank, > > On Fri, Dec 16, 2022 at 10:32 AM Frank Chang wrote: > > > > Hi Alexandre, > > > > Thanks for the contribution. This is really helpful. > > > > It seems like if we want to specify the SATP mode for the "named" CPUs, > > we have to do, e.g.: > > cpu->cfg.satp_mode.map |= (1 << idx_satp_mode_from_str("sv39")); > > in each CPU's init function. > > > > Can we add another helper function to wrap this for the "named" CPUs? > > Yes sure, I'll add some helpers for the bit operations in general, > that will be cleaner. And I'll set the default satp mode for the > current cpus in each cpu init function too. > > Thanks for your remarks, > > Alex > > > > > Regards, > > Frank Chang > > > > > > On Mon, Dec 12, 2022 at 6:23 PM Alexandre Ghiti > > wrote: > >> > >> RISC-V specifies multiple sizes for addressable memory and Linux probes for > >> the machine's support at startup via the satp CSR register (done in > >> csr.c:validate_vm). > >> > >> As per the specification, sv64 must support sv57, which in turn must > >> support sv48...etc. So we can restrict machine support by simply setting > >> the > >> "highest" supported mode and the bare mode is always supported. > >> > >> You can set the satp mode using the new properties "mbare", "sv32", > >> "sv39", "sv48", "sv57" and "sv64" as follows: > >> -cpu rv64,sv57=on # Linux will boot using sv57 scheme > >> -cpu rv64,sv39=on # Linux will boot using sv39 scheme > >> > >> We take the highest level set by the user: > >> -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme > >> > >> We make sure that invalid configurations are rejected: > >> -cpu rv64,sv32=on # Can't enable 32-bit satp mode in 64-bit > >> -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are > >># enabled > >> > >> We accept "redundant" configurations: > >> -cpu rv64,sv48=on,sv57=off # sv39 must be supported if higher modes are > >> > >> In addition, we now correctly set the device-tree entry 'mmu-type' using > >> those new properties. > >> > >> Co-Developed-by: Ludovic Henry > >> Signed-off-by: Ludovic Henry > >> Signed-off-by: Alexandre Ghiti > >> --- > >> v4: > >> - Use custom boolean properties instead of OnOffAuto properties, based > >> on ARMVQMap, as suggested by Andrew > >> > >> v3: > >> - Free sv_name as pointed by Bin > >> - Replace satp-mode with boolean properties as suggested by Andrew > >> - Removed RB from Atish as the patch considerably changed > >> > >> v2: > >> - Use error_setg + return as suggested by Alistair > >> - Add RB from Atish > >> - Fixed checkpatch issues missed in v1 > >> - Replaced Ludovic email address with the rivos one > >> > >> hw/riscv/virt.c| 20 +++-- > >> target/riscv/cpu.c | 217 +++-- > >> target/riscv/cpu.h | 25 ++ > >> target/riscv/csr.c | 13 ++- > >> 4 files changed, 256 insertions(+), 19 deletions(-) > >> > >> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c > >> index a5bc7353b4..9bb5ba7366 100644 > >> --- a/hw/riscv/virt.c > >> +++ b/hw/riscv/virt.c > >> @@ -228,7 +228,8 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, > >> int socket, > >> int cpu; > >> uint32_t cpu_phandle; > >> MachineState *mc = MACHINE(s); > >> -char *name, *cpu_name, *core_name, *intc_name; > >> +uint8_t satp_mode_max; > >> +char *name, *cpu_name, *core_name, *intc_name, *sv_name; > >> > >> for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { > >> cpu_phandle = (*phandle)++; > >> @@ -236,14 +237,15 @@ static void create_fdt_socket_cpus(RISCVVirtState > >> *s, int socket, > >> cpu_name = g_strdup_printf("/cpus/cpu@%d", > >> s->soc[socket].hartid_base + cpu); > >> qemu_fdt_add_subnode(mc->fdt, cpu_name); > >> -if (riscv_feature(>soc[socket].harts[cpu].env, > >> - RISCV_FEATURE_MMU)) { > >> -qemu_fdt_set
Re: [PATCH v4] riscv: Allow user to set the satp mode
Hi Frank, On Fri, Dec 16, 2022 at 10:32 AM Frank Chang wrote: > > Hi Alexandre, > > Thanks for the contribution. This is really helpful. > > It seems like if we want to specify the SATP mode for the "named" CPUs, > we have to do, e.g.: > cpu->cfg.satp_mode.map |= (1 << idx_satp_mode_from_str("sv39")); > in each CPU's init function. > > Can we add another helper function to wrap this for the "named" CPUs? Yes sure, I'll add some helpers for the bit operations in general, that will be cleaner. And I'll set the default satp mode for the current cpus in each cpu init function too. Thanks for your remarks, Alex > > Regards, > Frank Chang > > > On Mon, Dec 12, 2022 at 6:23 PM Alexandre Ghiti > wrote: >> >> RISC-V specifies multiple sizes for addressable memory and Linux probes for >> the machine's support at startup via the satp CSR register (done in >> csr.c:validate_vm). >> >> As per the specification, sv64 must support sv57, which in turn must >> support sv48...etc. So we can restrict machine support by simply setting the >> "highest" supported mode and the bare mode is always supported. >> >> You can set the satp mode using the new properties "mbare", "sv32", >> "sv39", "sv48", "sv57" and "sv64" as follows: >> -cpu rv64,sv57=on # Linux will boot using sv57 scheme >> -cpu rv64,sv39=on # Linux will boot using sv39 scheme >> >> We take the highest level set by the user: >> -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme >> >> We make sure that invalid configurations are rejected: >> -cpu rv64,sv32=on # Can't enable 32-bit satp mode in 64-bit >> -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are >># enabled >> >> We accept "redundant" configurations: >> -cpu rv64,sv48=on,sv57=off # sv39 must be supported if higher modes are >> >> In addition, we now correctly set the device-tree entry 'mmu-type' using >> those new properties. >> >> Co-Developed-by: Ludovic Henry >> Signed-off-by: Ludovic Henry >> Signed-off-by: Alexandre Ghiti >> --- >> v4: >> - Use custom boolean properties instead of OnOffAuto properties, based >> on ARMVQMap, as suggested by Andrew >> >> v3: >> - Free sv_name as pointed by Bin >> - Replace satp-mode with boolean properties as suggested by Andrew >> - Removed RB from Atish as the patch considerably changed >> >> v2: >> - Use error_setg + return as suggested by Alistair >> - Add RB from Atish >> - Fixed checkpatch issues missed in v1 >> - Replaced Ludovic email address with the rivos one >> >> hw/riscv/virt.c| 20 +++-- >> target/riscv/cpu.c | 217 +++-- >> target/riscv/cpu.h | 25 ++ >> target/riscv/csr.c | 13 ++- >> 4 files changed, 256 insertions(+), 19 deletions(-) >> >> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c >> index a5bc7353b4..9bb5ba7366 100644 >> --- a/hw/riscv/virt.c >> +++ b/hw/riscv/virt.c >> @@ -228,7 +228,8 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, >> int socket, >> int cpu; >> uint32_t cpu_phandle; >> MachineState *mc = MACHINE(s); >> -char *name, *cpu_name, *core_name, *intc_name; >> +uint8_t satp_mode_max; >> +char *name, *cpu_name, *core_name, *intc_name, *sv_name; >> >> for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { >> cpu_phandle = (*phandle)++; >> @@ -236,14 +237,15 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, >> int socket, >> cpu_name = g_strdup_printf("/cpus/cpu@%d", >> s->soc[socket].hartid_base + cpu); >> qemu_fdt_add_subnode(mc->fdt, cpu_name); >> -if (riscv_feature(>soc[socket].harts[cpu].env, >> - RISCV_FEATURE_MMU)) { >> -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", >> -(is_32_bit) ? "riscv,sv32" : >> "riscv,sv48"); >> -} else { >> -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", >> -"riscv,none"); >> -} >> + >> +satp_mode_max = satp_mode_max_from_map( >> +s->soc[socket].harts[cpu].cfg.satp_mode.map, >> +is_32_bit); >> +
[PATCH v4] riscv: Allow user to set the satp mode
RISC-V specifies multiple sizes for addressable memory and Linux probes for the machine's support at startup via the satp CSR register (done in csr.c:validate_vm). As per the specification, sv64 must support sv57, which in turn must support sv48...etc. So we can restrict machine support by simply setting the "highest" supported mode and the bare mode is always supported. You can set the satp mode using the new properties "mbare", "sv32", "sv39", "sv48", "sv57" and "sv64" as follows: -cpu rv64,sv57=on # Linux will boot using sv57 scheme -cpu rv64,sv39=on # Linux will boot using sv39 scheme We take the highest level set by the user: -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme We make sure that invalid configurations are rejected: -cpu rv64,sv32=on # Can't enable 32-bit satp mode in 64-bit -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are # enabled We accept "redundant" configurations: -cpu rv64,sv48=on,sv57=off # sv39 must be supported if higher modes are In addition, we now correctly set the device-tree entry 'mmu-type' using those new properties. Co-Developed-by: Ludovic Henry Signed-off-by: Ludovic Henry Signed-off-by: Alexandre Ghiti --- v4: - Use custom boolean properties instead of OnOffAuto properties, based on ARMVQMap, as suggested by Andrew v3: - Free sv_name as pointed by Bin - Replace satp-mode with boolean properties as suggested by Andrew - Removed RB from Atish as the patch considerably changed v2: - Use error_setg + return as suggested by Alistair - Add RB from Atish - Fixed checkpatch issues missed in v1 - Replaced Ludovic email address with the rivos one hw/riscv/virt.c| 20 +++-- target/riscv/cpu.c | 217 +++-- target/riscv/cpu.h | 25 ++ target/riscv/csr.c | 13 ++- 4 files changed, 256 insertions(+), 19 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index a5bc7353b4..9bb5ba7366 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -228,7 +228,8 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, int cpu; uint32_t cpu_phandle; MachineState *mc = MACHINE(s); -char *name, *cpu_name, *core_name, *intc_name; +uint8_t satp_mode_max; +char *name, *cpu_name, *core_name, *intc_name, *sv_name; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { cpu_phandle = (*phandle)++; @@ -236,14 +237,15 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(mc->fdt, cpu_name); -if (riscv_feature(>soc[socket].harts[cpu].env, - RISCV_FEATURE_MMU)) { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -(is_32_bit) ? "riscv,sv32" : "riscv,sv48"); -} else { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -"riscv,none"); -} + +satp_mode_max = satp_mode_max_from_map( +s->soc[socket].harts[cpu].cfg.satp_mode.map, +is_32_bit); +sv_name = g_strdup_printf("riscv,%s", + satp_mode_str(satp_mode_max, is_32_bit)); +qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); +g_free(sv_name); + name = riscv_isa_string(>soc[socket].harts[cpu]); qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); g_free(name); diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d14e95c9dc..639231ce2e 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -27,6 +27,7 @@ #include "time_helper.h" #include "exec/exec-all.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "qemu/error-report.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" @@ -199,7 +200,7 @@ static const char * const riscv_intr_names[] = { "reserved" }; -static void register_cpu_props(DeviceState *dev); +static void register_cpu_props(Object *obj); const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) { @@ -237,7 +238,7 @@ static void riscv_any_cpu_init(Object *obj) set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif set_priv_version(env, PRIV_VERSION_1_12_0); -register_cpu_props(DEVICE(obj)); +register_cpu_props(obj); } #if defined(TARGET_RISCV64) @@ -246,7 +247,7 @@ static void rv64_base_cpu_init(Object *obj) CPURISCVState *env = _CPU(obj)->env; /* We set this in the realise function */ set_misa
Re: [PATCH v3] riscv: Allow user to set the satp mode
Hi Andrew, On Thu, Dec 1, 2022 at 3:47 PM Andrew Jones wrote: > On Thu, Dec 01, 2022 at 10:36:23AM +0100, Alexandre Ghiti wrote: > > RISC-V specifies multiple sizes for addressable memory and Linux probes > for > > the machine's support at startup via the satp CSR register (done in > > csr.c:validate_vm). > > > > As per the specification, sv64 must support sv57, which in turn must > > support sv48...etc. So we can restrict machine support by simply setting > the > > "highest" supported mode and the bare mode is always supported. > > > > You can set the satp mode using the new properties "mbare", "sv32", > > "sv39", "sv48", "sv57" and "sv64" as follows: > > -cpu rv64,sv57=on # Linux will boot using sv57 scheme > > -cpu rv64,sv39=on # Linux will boot using sv39 scheme > > > > We take the highest level set by the user: > > -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme > > > > We make sure that invalid configurations are rejected: > > -cpu rv64,sv32=on # Can't enable 32-bit satp mode in 64-bit > > -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are > > # enabled > > > > We accept "redundant" configurations: > > -cpu rv64,sv48=on,sv57=off # sv39 must be supported if higher modes are > > > > In addition, we now correctly set the device-tree entry 'mmu-type' using > > those new properties. > > > > Co-Developed-by: Ludovic Henry > > Signed-off-by: Ludovic Henry > > Signed-off-by: Alexandre Ghiti > > --- > > v3: > > - Free sv_name as pointed by Bin > > - Replace satp-mode with boolean properties as suggested by Andrew > > - Removed RB from Atish as the patch considerably changed > > > > v2: > > - Use error_setg + return as suggested by Alistair > > - Add RB from Atish > > - Fixed checkpatch issues missed in v1 > > - Replaced Ludovic email address with the rivos one > > > > hw/riscv/virt.c | 16 ++-- > > target/riscv/cpu.c | 164 > > target/riscv/cpu.h | 8 ++ > > target/riscv/cpu_bits.h | 1 + > > target/riscv/csr.c | 8 +- > > 5 files changed, 186 insertions(+), 11 deletions(-) > > > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c > > index a5bc7353b4..bb7c739a74 100644 > > --- a/hw/riscv/virt.c > > +++ b/hw/riscv/virt.c > > @@ -228,7 +228,7 @@ static void create_fdt_socket_cpus(RISCVVirtState > *s, int socket, > > int cpu; > > uint32_t cpu_phandle; > > MachineState *mc = MACHINE(s); > > -char *name, *cpu_name, *core_name, *intc_name; > > +char *name, *cpu_name, *core_name, *intc_name, *sv_name; > > > > for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { > > cpu_phandle = (*phandle)++; > > @@ -236,14 +236,12 @@ static void create_fdt_socket_cpus(RISCVVirtState > *s, int socket, > > cpu_name = g_strdup_printf("/cpus/cpu@%d", > > s->soc[socket].hartid_base + cpu); > > qemu_fdt_add_subnode(mc->fdt, cpu_name); > > -if (riscv_feature(>soc[socket].harts[cpu].env, > > - RISCV_FEATURE_MMU)) { > > -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", > > -(is_32_bit) ? "riscv,sv32" : > "riscv,sv48"); > > -} else { > > -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", > > -"riscv,none"); > > -} > > + > > +sv_name = g_strdup_printf("riscv,%s", > > + > s->soc[socket].harts[cpu].cfg.satp_mode_str); > > +qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); > > +g_free(sv_name); > > + > > name = riscv_isa_string(>soc[socket].harts[cpu]); > > qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); > > g_free(name); > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index d14e95c9dc..51c06ed057 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -907,6 +907,66 @@ static void riscv_cpu_realize(DeviceState *dev, > Error **errp) > > } > > #endif > > > > +/* > > + * Either a cpu sets its supported satp_mode in XXX_cpu_init > > + * or the user sets this value using
[PATCH v3] riscv: Allow user to set the satp mode
RISC-V specifies multiple sizes for addressable memory and Linux probes for the machine's support at startup via the satp CSR register (done in csr.c:validate_vm). As per the specification, sv64 must support sv57, which in turn must support sv48...etc. So we can restrict machine support by simply setting the "highest" supported mode and the bare mode is always supported. You can set the satp mode using the new properties "mbare", "sv32", "sv39", "sv48", "sv57" and "sv64" as follows: -cpu rv64,sv57=on # Linux will boot using sv57 scheme -cpu rv64,sv39=on # Linux will boot using sv39 scheme We take the highest level set by the user: -cpu rv64,sv48=on,sv57=on # Linux will boot using sv57 scheme We make sure that invalid configurations are rejected: -cpu rv64,sv32=on # Can't enable 32-bit satp mode in 64-bit -cpu rv64,sv39=off,sv48=on # sv39 must be supported if higher modes are # enabled We accept "redundant" configurations: -cpu rv64,sv48=on,sv57=off # sv39 must be supported if higher modes are In addition, we now correctly set the device-tree entry 'mmu-type' using those new properties. Co-Developed-by: Ludovic Henry Signed-off-by: Ludovic Henry Signed-off-by: Alexandre Ghiti --- v3: - Free sv_name as pointed by Bin - Replace satp-mode with boolean properties as suggested by Andrew - Removed RB from Atish as the patch considerably changed v2: - Use error_setg + return as suggested by Alistair - Add RB from Atish - Fixed checkpatch issues missed in v1 - Replaced Ludovic email address with the rivos one hw/riscv/virt.c | 16 ++-- target/riscv/cpu.c | 164 target/riscv/cpu.h | 8 ++ target/riscv/cpu_bits.h | 1 + target/riscv/csr.c | 8 +- 5 files changed, 186 insertions(+), 11 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index a5bc7353b4..bb7c739a74 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -228,7 +228,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, int cpu; uint32_t cpu_phandle; MachineState *mc = MACHINE(s); -char *name, *cpu_name, *core_name, *intc_name; +char *name, *cpu_name, *core_name, *intc_name, *sv_name; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { cpu_phandle = (*phandle)++; @@ -236,14 +236,12 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(mc->fdt, cpu_name); -if (riscv_feature(>soc[socket].harts[cpu].env, - RISCV_FEATURE_MMU)) { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -(is_32_bit) ? "riscv,sv32" : "riscv,sv48"); -} else { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -"riscv,none"); -} + +sv_name = g_strdup_printf("riscv,%s", + s->soc[socket].harts[cpu].cfg.satp_mode_str); +qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); +g_free(sv_name); + name = riscv_isa_string(>soc[socket].harts[cpu]); qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); g_free(name); diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d14e95c9dc..51c06ed057 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -907,6 +907,66 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } #endif +/* + * Either a cpu sets its supported satp_mode in XXX_cpu_init + * or the user sets this value using satp_mode property. + */ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; + +cpu->cfg.satp_mode = VM_1_10_UNDEF; + +if (rv32) { +if (cpu->cfg.sv32 == ON_OFF_AUTO_ON) { +cpu->cfg.satp_mode_str = g_strdup("sv32"); +cpu->cfg.satp_mode = VM_1_10_SV32; +} else if (cpu->cfg.mbare == ON_OFF_AUTO_ON) { +cpu->cfg.satp_mode_str = g_strdup("none"); +cpu->cfg.satp_mode = VM_1_10_MBARE; +} +} else { +if (cpu->cfg.sv64 == ON_OFF_AUTO_ON) { +cpu->cfg.satp_mode_str = g_strdup("sv64"); +cpu->cfg.satp_mode = VM_1_10_SV64; +} else if (cpu->cfg.sv57 == ON_OFF_AUTO_ON) { +cpu->cfg.satp_mode_str = g_strdup("sv57"); +cpu->cfg.satp_mode = VM_1_10_SV57; +} else if (cpu->cfg.sv48 == ON_OFF_AUTO_ON) { +cpu->cfg.satp_mode_str = g_strdup("sv48"); +cpu->cfg.satp_mode = VM_1_10_SV48; +} els
[PATCH v2] riscv: Add RISCVCPUConfig.satp_mode to set sv48, sv57, etc.
RISC-V specifies multiple sizes for addressable memory and Linux probes for the machine's support at startup via the satp CSR register (done in csr.c:validate_vm). As per the specification, sv64 must support sv57, which in turn must support sv48...etc. So we can restrict machine support by simply setting the "highest" supported mode in the satp_mode property. And the bare mode is always supported. You can set this new property as follows: -cpu rv64,satp-mode=sv48 # Linux will boot using sv48 scheme -cpu rv64,satp-mode=sv39 # Linux will boot using sv39 scheme In addition, we now correctly set the device-tree entry 'mmu-type' using this new satp_mode property. Reviewed-by: Atish Patra Co-Developed-by: Ludovic Henry Signed-off-by: Ludovic Henry Signed-off-by: Alexandre Ghiti --- v2: - Use error_setg + return as suggested by Alistair - Add RB from Atish - Fixed checkpatch issues missed in v1 - Replaced Ludovic email address with the rivos one hw/riscv/virt.c| 15 ++- target/riscv/cpu.c | 45 + target/riscv/cpu.h | 3 +++ target/riscv/csr.c | 8 ++-- 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index a5bc7353b4..77484b5cae 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -228,7 +228,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, int cpu; uint32_t cpu_phandle; MachineState *mc = MACHINE(s); -char *name, *cpu_name, *core_name, *intc_name; +char *name, *cpu_name, *core_name, *intc_name, *sv_name; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { cpu_phandle = (*phandle)++; @@ -236,14 +236,11 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(mc->fdt, cpu_name); -if (riscv_feature(>soc[socket].harts[cpu].env, - RISCV_FEATURE_MMU)) { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -(is_32_bit) ? "riscv,sv32" : "riscv,sv48"); -} else { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -"riscv,none"); -} + +sv_name = g_strdup_printf("riscv,%s", + s->soc[socket].harts[cpu].cfg.satp_mode_str); +qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); + name = riscv_isa_string(>soc[socket].harts[cpu]); qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); g_free(name); diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d14e95c9dc..c86dc5058d 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -907,6 +907,48 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } #endif +/* + * Either a cpu sets its supported satp_mode in XXX_cpu_init + * or the user sets this value using satp_mode property. + */ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; +if (cpu->cfg.satp_mode_str) { +if (!g_strcmp0(cpu->cfg.satp_mode_str, "none")) +cpu->cfg.satp_mode = VM_1_10_MBARE; +else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv32") && rv32) +cpu->cfg.satp_mode = VM_1_10_SV32; +else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv39") && !rv32) +cpu->cfg.satp_mode = VM_1_10_SV39; +else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv48") && !rv32) +cpu->cfg.satp_mode = VM_1_10_SV48; +else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv57") && !rv32) +cpu->cfg.satp_mode = VM_1_10_SV57; +else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv64") && !rv32) +cpu->cfg.satp_mode = VM_1_10_SV64; +else { +error_setg(errp, "Unknown option for satp_mode: %s", + cpu->cfg.satp_mode_str); +return; +} +} else { +/* + * If unset by both the user and the cpu, we fallback to sv32 for 32-bit + * or sv57 for 64-bit when a MMU is present, and bare otherwise. + */ +if (riscv_feature(>env, RISCV_FEATURE_MMU)) { +if (rv32) { +cpu->cfg.satp_mode_str = g_strdup("sv32"); +cpu->cfg.satp_mode = VM_1_10_SV32; +} else { +cpu->cfg.satp_mode_str = g_strdup("sv57"); +cpu->cfg.satp_mode = VM_1_10_SV57; +} +} else { +cpu->cfg.satp_mode_str = g_strdup("none"); +
[PATCH] riscv: Add RISCVCPUConfig.satp_mode to set sv48, sv57, etc.
RISC-V specifies multiple sizes for addressable memory and Linux probes for the machine's support at startup via the satp CSR register (done in csr.c:validate_vm). As per the specification, sv64 must support sv57, which in turn must support sv48...etc. So we can restrict machine support by simply setting the "highest" supported mode in the satp_mode property. And the bare mode is always supported. You can set this new property as follows: -cpu rv64,satp-mode=sv48 # Linux will boot using sv48 scheme -cpu rv64,satp-mode=sv39 # Linux will boot using sv39 scheme In addition, we now correctly set the device-tree entry 'mmu-type' using this new satp_mode property. Co-Developed-by: Ludovic Henry Signed-off-by: Ludovic Henry Signed-off-by: Alexandre Ghiti --- hw/riscv/virt.c| 15 ++- target/riscv/cpu.c | 45 + target/riscv/cpu.h | 3 +++ target/riscv/csr.c | 6 -- 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index a5bc7353b4..77484b5cae 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -228,7 +228,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, int cpu; uint32_t cpu_phandle; MachineState *mc = MACHINE(s); -char *name, *cpu_name, *core_name, *intc_name; +char *name, *cpu_name, *core_name, *intc_name, *sv_name; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { cpu_phandle = (*phandle)++; @@ -236,14 +236,11 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_name = g_strdup_printf("/cpus/cpu@%d", s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(mc->fdt, cpu_name); -if (riscv_feature(>soc[socket].harts[cpu].env, - RISCV_FEATURE_MMU)) { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -(is_32_bit) ? "riscv,sv32" : "riscv,sv48"); -} else { -qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", -"riscv,none"); -} + +sv_name = g_strdup_printf("riscv,%s", + s->soc[socket].harts[cpu].cfg.satp_mode_str); +qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", sv_name); + name = riscv_isa_string(>soc[socket].harts[cpu]); qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); g_free(name); diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d14e95c9dc..efdb530ad9 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -907,6 +907,48 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } #endif +/* + * Either a cpu sets its supported satp_mode in XXX_cpu_init + * or the user sets this value using satp_mode property. + */ +bool rv32 = riscv_cpu_mxl(>env) == MXL_RV32; +if (cpu->cfg.satp_mode_str) { +if (!g_strcmp0(cpu->cfg.satp_mode_str, "none")) +cpu->cfg.satp_mode = VM_1_10_MBARE; +else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv32") && rv32) +cpu->cfg.satp_mode = VM_1_10_SV32; +else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv39") && !rv32) +cpu->cfg.satp_mode = VM_1_10_SV39; +else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv48") && !rv32) +cpu->cfg.satp_mode = VM_1_10_SV48; +else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv57") && !rv32) +cpu->cfg.satp_mode = VM_1_10_SV57; +else if (!g_strcmp0(cpu->cfg.satp_mode_str, "sv64") && !rv32) +cpu->cfg.satp_mode = VM_1_10_SV64; +else { +error_report("Unknown option for satp_mode: %s", + cpu->cfg.satp_mode_str); +exit(EXIT_FAILURE); +} +} else { +/* + * If unset by both the user and the cpu, we fallback to sv32 for 32-bit + * or sv57 for 64-bit when a MMU is present, and bare otherwise. + */ +if (riscv_feature(>env, RISCV_FEATURE_MMU)) { +if (rv32) { +cpu->cfg.satp_mode_str = g_strdup("sv32"); +cpu->cfg.satp_mode = VM_1_10_SV32; +} else { +cpu->cfg.satp_mode_str = g_strdup("sv57"); +cpu->cfg.satp_mode = VM_1_10_SV57; +} +} else { +cpu->cfg.satp_mode_str = g_strdup("none"); +cpu->cfg.satp_mode = VM_1_10_MBARE; +} +} + riscv_cpu_register_gdb_regs_for_features(cs); qemu_init_vcpu(cs); @@ -1094,6 +1136,9 @@ static Property riscv_cpu