Re: xlnx-versal-virt machine in qemu

2024-05-01 Thread abhijeet rajmane
I am using the following command to boot "xlnx-versal-virt" board with
"canbus" and connect it to host machine using "canbus"

$ qemu-system-aarch64 -M xlnx-versal-virt -m 4G -serial mon:stdio -display
none -kernel ~/linux_kernel/linux-5.15.157/arch/arm64/boot/Image \

-device virtio-rng-device,bus=virtio-mmio-bus.0 -drive
if=none,index=0,file=rootfs.img,format=raw,id=hd0 \

-device virtio-blk-device,drive=hd0 -append root=/dev/vda -nic user \

-object can-bus,id=canbus0 -machine canbus0=canbus0 -object
can-bus,id=canbus1 -machine canbus1=canbus1 \

-object can-host-socketcan,id=socketcan0,if=vcan0,canbus=canbus0



->I am using the cansend and candump application to test it.

->After sending certain packets the buffer is getting full. I am seeing
that while ":request_irq" from xilinc_can driver gets called it should
invoke "xcan_interrupt" function. I have added prints in those functions.
"xcan_interrupt" function is not getting called.

->If i check the interrupts on cpu for 'can' interface the count is 0.



Thank You in Advance!!

On Sat, Apr 20, 2024 at 11:43 PM abhijeet rajmane 
wrote:

> Hi,
> I have booted up the xlnx-versal-virt machine using qemu-system-aarch64. I
> wanted to work with can device that has been modelled with this device. I
> have used the xilinx_can.c driver for this device and can see two can
> controllers. The problem is I am not able to see any interrupts in
> /proc/interrupts for both can devices. I have set them up and running. I
> have also connected the canbus device to host to transmit and receive can
> packets. I am seeing qemu_set_irq() getting called. Am I missing something?
>
> Thanks ,
> Abhijeet, India
>


Re: [RFC 1/2] iova_tree: add an id member to DMAMap

2024-05-01 Thread Eugenio Perez Martin
On Thu, May 2, 2024 at 1:16 AM Si-Wei Liu  wrote:
>
>
>
> On 4/30/2024 10:19 AM, Eugenio Perez Martin wrote:
> > On Tue, Apr 30, 2024 at 7:55 AM Si-Wei Liu  wrote:
> >>
> >>
> >> On 4/29/2024 1:14 AM, Eugenio Perez Martin wrote:
> >>> On Thu, Apr 25, 2024 at 7:44 PM Si-Wei Liu  wrote:
> 
>  On 4/24/2024 12:33 AM, Eugenio Perez Martin wrote:
> > On Wed, Apr 24, 2024 at 12:21 AM Si-Wei Liu  
> > wrote:
> >> On 4/22/2024 1:49 AM, Eugenio Perez Martin wrote:
> >>> On Sat, Apr 20, 2024 at 1:50 AM Si-Wei Liu  
> >>> wrote:
>  On 4/19/2024 1:29 AM, Eugenio Perez Martin wrote:
> > On Thu, Apr 18, 2024 at 10:46 PM Si-Wei Liu  
> > wrote:
> >> On 4/10/2024 3:03 AM, Eugenio Pérez wrote:
> >>> IOVA tree is also used to track the mappings of virtio-net shadow
> >>> virtqueue.  This mappings may not match with the GPA->HVA ones.
> >>>
> >>> This causes a problem when overlapped regions (different GPA but 
> >>> same
> >>> translated HVA) exists in the tree, as looking them by HVA will 
> >>> return
> >>> them twice.  To solve this, create an id member so we can assign 
> >>> unique
> >>> identifiers (GPA) to the maps.
> >>>
> >>> Signed-off-by: Eugenio Pérez 
> >>> ---
> >>>include/qemu/iova-tree.h | 5 +++--
> >>>util/iova-tree.c | 3 ++-
> >>>2 files changed, 5 insertions(+), 3 deletions(-)
> >>>
> >>> diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h
> >>> index 2a10a7052e..34ee230e7d 100644
> >>> --- a/include/qemu/iova-tree.h
> >>> +++ b/include/qemu/iova-tree.h
> >>> @@ -36,6 +36,7 @@ typedef struct DMAMap {
> >>>hwaddr iova;
> >>>hwaddr translated_addr;
> >>>hwaddr size;/* Inclusive */
> >>> +uint64_t id;
> >>>IOMMUAccessFlags perm;
> >>>} QEMU_PACKED DMAMap;
> >>>typedef gboolean (*iova_tree_iterator)(DMAMap *map);
> >>> @@ -100,8 +101,8 @@ const DMAMap *iova_tree_find(const IOVATree 
> >>> *tree, const DMAMap *map);
> >>> * @map: the mapping to search
> >>> *
> >>> * Search for a mapping in the iova tree that 
> >>> translated_addr overlaps with the
> >>> - * mapping range specified.  Only the first found mapping will be
> >>> - * returned.
> >>> + * mapping range specified and map->id is equal.  Only the first 
> >>> found
> >>> + * mapping will be returned.
> >>> *
> >>> * Return: DMAMap pointer if found, or NULL if not found.  
> >>> Note that
> >>> * the returned DMAMap pointer is maintained internally.  
> >>> User should
> >>> diff --git a/util/iova-tree.c b/util/iova-tree.c
> >>> index 536789797e..0863e0a3b8 100644
> >>> --- a/util/iova-tree.c
> >>> +++ b/util/iova-tree.c
> >>> @@ -97,7 +97,8 @@ static gboolean 
> >>> iova_tree_find_address_iterator(gpointer key, gpointer value,
> >>>
> >>>needle = args->needle;
> >>>if (map->translated_addr + map->size < 
> >>> needle->translated_addr ||
> >>> -needle->translated_addr + needle->size < 
> >>> map->translated_addr) {
> >>> +needle->translated_addr + needle->size < 
> >>> map->translated_addr ||
> >>> +needle->id != map->id) {
> >> It looks this iterator can also be invoked by SVQ from
> >> vhost_svq_translate_addr() -> iova_tree_find_iova(), where guest 
> >> GPA
> >> space will be searched on without passing in the ID (GPA), and 
> >> exact
> >> match for the same GPA range is not actually needed unlike the 
> >> mapping
> >> removal case. Could we create an API variant, for the SVQ lookup 
> >> case
> >> specifically? Or alternatively, add a special flag, say 
> >> skip_id_match to
> >> DMAMap, and the id match check may look like below:
> >>
> >> (!needle->skip_id_match && needle->id != map->id)
> >>
> >> I think vhost_svq_translate_addr() could just call the API variant 
> >> or
> >> pass DMAmap with skip_id_match set to true to 
> >> svq_iova_tree_find_iova().
> >>
> > I think you're totally right. But I'd really like to not complicate
> > the API of the iova_tree more.
> >
> > I think we can look for the hwaddr using memory_region_from_host and
> > then get the hwaddr. It is another lookup though...
>  Yeah, that will be another means of doing translation without having 
>  to
> 

Re: [PATCH v4 07/17] xen: mapcache: Refactor xen_replace_cache_entry_unlocked

2024-05-01 Thread Edgar E. Iglesias
On Wed, May 1, 2024 at 10:46 PM Stefano Stabellini
 wrote:
>
> On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> > From: "Edgar E. Iglesias" 
> >
> > Add MapCache argument to xen_replace_cache_entry_unlocked in
> > preparation for supporting multiple map caches.
> >
> > No functional change.
> >
> > Signed-off-by: Edgar E. Iglesias 
> > ---
> >  hw/xen/xen-mapcache.c | 8 +---
> >  1 file changed, 5 insertions(+), 3 deletions(-)
> >
> > diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
> > index d2deff70c8..6e758eff94 100644
> > --- a/hw/xen/xen-mapcache.c
> > +++ b/hw/xen/xen-mapcache.c
> > @@ -556,7 +556,8 @@ void xen_invalidate_map_cache(void)
> >  mapcache_unlock(mapcache);
> >  }
> >
> > -static uint8_t *xen_replace_cache_entry_unlocked(hwaddr old_phys_addr,
> > +static uint8_t *xen_replace_cache_entry_unlocked(MapCache *mc,
> > + hwaddr old_phys_addr,
> >   hwaddr new_phys_addr,
> >   hwaddr size)
> >  {
> > @@ -578,7 +579,7 @@ static uint8_t *xen_replace_cache_entry_unlocked(hwaddr 
> > old_phys_addr,
> >  cache_size += MCACHE_BUCKET_SIZE - (cache_size % 
> > MCACHE_BUCKET_SIZE);
> >  }
> >
> > -entry = &mapcache->entry[address_index % mapcache->nr_buckets];
> > +entry = &mc->entry[address_index % mc->nr_buckets];
> >  while (entry && !(entry->paddr_index == address_index &&
> >entry->size == cache_size)) {
> >  entry = entry->next;
>
> There is still a global mapcache pointer in use in this function:
>
>   xen_remap_bucket(mapcache, entry, entry->vaddr_base,
>


Thanks! I had accidentally put the change to use mc in future patches.
Will fix in v5.

Cheers,
Edgar


>
> > @@ -614,7 +615,8 @@ uint8_t *xen_replace_cache_entry(hwaddr old_phys_addr,
> >  uint8_t *p;
> >
> >  mapcache_lock(mapcache);
> > -p = xen_replace_cache_entry_unlocked(old_phys_addr, new_phys_addr, 
> > size);
> > +p = xen_replace_cache_entry_unlocked(mapcache, old_phys_addr,
> > + new_phys_addr, size);
> >  mapcache_unlock(mapcache);
> >  return p;
> >  }
> > --
> > 2.40.1
> >



[PATCH] ppc/pnv: Update Power10's cfam id to use Power10 DD2

2024-05-01 Thread Aditya Gupta
Power10 DD1.0 was dropped in:

commit 8f054d9ee825 ("ppc: Drop support for POWER9 and POWER10 DD1 chips")

Use the newer Power10 DD2 chips cfam id.

Cc: Cédric Le Goater 
Cc: David Gibson 
Cc: Frédéric Barrat 
Cc: Laurent Vivier 
Cc: Mahesh J Salgaonkar 
Cc: Madhavan Srinivasan 
Cc: Nicholas Piggin 
Cc: Paolo Bonzini 
Cc: Thomas Huth 
Signed-off-by: Aditya Gupta 
---
 hw/ppc/pnv.c| 2 +-
 tests/qtest/pnv-xscom.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 6e3a5ccdec76..06a4e4d13948 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -2090,7 +2090,7 @@ static void pnv_chip_power10_class_init(ObjectClass 
*klass, void *data)
 PnvChipClass *k = PNV_CHIP_CLASS(klass);
 static const int i2c_ports_per_engine[PNV10_CHIP_MAX_I2C] = {14, 14, 2, 
16};
 
-k->chip_cfam_id = 0x120da0498000ull; /* P10 DD1.0 (with NX) */
+k->chip_cfam_id = 0x220da0498000ull; /* P10 DD2.0 (with NX) */
 k->cores_mask = POWER10_CORE_MASK;
 k->chip_pir = pnv_chip_pir_p10;
 k->intc_create = pnv_chip_power10_intc_create;
diff --git a/tests/qtest/pnv-xscom.h b/tests/qtest/pnv-xscom.h
index 6f62941744a6..5aa1701ea768 100644
--- a/tests/qtest/pnv-xscom.h
+++ b/tests/qtest/pnv-xscom.h
@@ -56,7 +56,7 @@ static const PnvChip pnv_chips[] = {
 .chip_type  = PNV_CHIP_POWER10,
 .cpu_model  = "POWER10",
 .xscom_base = 0x000603fcull,
-.cfam_id= 0x120da0498000ull,
+.cfam_id= 0x220da0498000ull,
 .first_core = 0x0,
 .num_i2c= 4,
 },
-- 
2.44.0




Re: [RFC 1/2] iova_tree: add an id member to DMAMap

2024-05-01 Thread Eugenio Perez Martin
On Thu, May 2, 2024 at 12:09 AM Si-Wei Liu  wrote:
>
>
>
> On 4/30/2024 11:11 AM, Eugenio Perez Martin wrote:
> > On Mon, Apr 29, 2024 at 1:19 PM Jonah Palmer  
> > wrote:
> >>
> >>
> >> On 4/29/24 4:14 AM, Eugenio Perez Martin wrote:
> >>> On Thu, Apr 25, 2024 at 7:44 PM Si-Wei Liu  wrote:
> 
> 
>  On 4/24/2024 12:33 AM, Eugenio Perez Martin wrote:
> > On Wed, Apr 24, 2024 at 12:21 AM Si-Wei Liu  
> > wrote:
> >>
> >> On 4/22/2024 1:49 AM, Eugenio Perez Martin wrote:
> >>> On Sat, Apr 20, 2024 at 1:50 AM Si-Wei Liu  
> >>> wrote:
>  On 4/19/2024 1:29 AM, Eugenio Perez Martin wrote:
> > On Thu, Apr 18, 2024 at 10:46 PM Si-Wei Liu  
> > wrote:
> >> On 4/10/2024 3:03 AM, Eugenio Pérez wrote:
> >>> IOVA tree is also used to track the mappings of virtio-net shadow
> >>> virtqueue.  This mappings may not match with the GPA->HVA ones.
> >>>
> >>> This causes a problem when overlapped regions (different GPA but 
> >>> same
> >>> translated HVA) exists in the tree, as looking them by HVA will 
> >>> return
> >>> them twice.  To solve this, create an id member so we can assign 
> >>> unique
> >>> identifiers (GPA) to the maps.
> >>>
> >>> Signed-off-by: Eugenio Pérez 
> >>> ---
> >>>include/qemu/iova-tree.h | 5 +++--
> >>>util/iova-tree.c | 3 ++-
> >>>2 files changed, 5 insertions(+), 3 deletions(-)
> >>>
> >>> diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h
> >>> index 2a10a7052e..34ee230e7d 100644
> >>> --- a/include/qemu/iova-tree.h
> >>> +++ b/include/qemu/iova-tree.h
> >>> @@ -36,6 +36,7 @@ typedef struct DMAMap {
> >>>hwaddr iova;
> >>>hwaddr translated_addr;
> >>>hwaddr size;/* Inclusive */
> >>> +uint64_t id;
> >>>IOMMUAccessFlags perm;
> >>>} QEMU_PACKED DMAMap;
> >>>typedef gboolean (*iova_tree_iterator)(DMAMap *map);
> >>> @@ -100,8 +101,8 @@ const DMAMap *iova_tree_find(const IOVATree 
> >>> *tree, const DMAMap *map);
> >>> * @map: the mapping to search
> >>> *
> >>> * Search for a mapping in the iova tree that 
> >>> translated_addr overlaps with the
> >>> - * mapping range specified.  Only the first found mapping will be
> >>> - * returned.
> >>> + * mapping range specified and map->id is equal.  Only the first 
> >>> found
> >>> + * mapping will be returned.
> >>> *
> >>> * Return: DMAMap pointer if found, or NULL if not found.  
> >>> Note that
> >>> * the returned DMAMap pointer is maintained internally.  
> >>> User should
> >>> diff --git a/util/iova-tree.c b/util/iova-tree.c
> >>> index 536789797e..0863e0a3b8 100644
> >>> --- a/util/iova-tree.c
> >>> +++ b/util/iova-tree.c
> >>> @@ -97,7 +97,8 @@ static gboolean 
> >>> iova_tree_find_address_iterator(gpointer key, gpointer value,
> >>>
> >>>needle = args->needle;
> >>>if (map->translated_addr + map->size < 
> >>> needle->translated_addr ||
> >>> -needle->translated_addr + needle->size < 
> >>> map->translated_addr) {
> >>> +needle->translated_addr + needle->size < 
> >>> map->translated_addr ||
> >>> +needle->id != map->id) {
> >> It looks this iterator can also be invoked by SVQ from
> >> vhost_svq_translate_addr() -> iova_tree_find_iova(), where guest 
> >> GPA
> >> space will be searched on without passing in the ID (GPA), and 
> >> exact
> >> match for the same GPA range is not actually needed unlike the 
> >> mapping
> >> removal case. Could we create an API variant, for the SVQ lookup 
> >> case
> >> specifically? Or alternatively, add a special flag, say 
> >> skip_id_match to
> >> DMAMap, and the id match check may look like below:
> >>
> >> (!needle->skip_id_match && needle->id != map->id)
> >>
> >> I think vhost_svq_translate_addr() could just call the API variant 
> >> or
> >> pass DMAmap with skip_id_match set to true to 
> >> svq_iova_tree_find_iova().
> >>
> > I think you're totally right. But I'd really like to not complicate
> > the API of the iova_tree more.
> >
> > I think we can look for the hwaddr using memory_region_from_host and
> > then get the hwaddr. It is another lookup though...
>  Yeah, that will be another means of doing translation without having 
> 

Re: QEMU headers in C++

2024-05-01 Thread Thomas Huth

On 02/05/2024 06.40, Roman Kiryanov wrote:

Hi QEMU,

I work in Android Studio Emulator and we would like to develop devices
in C++. Unfortunately, QEMU headers cannot be used with C++ as is
(e.g. they use C++ keywords as variable names or implicitly cast void*
to T*).


Can't you simply use something like:

extern "C" {
#include 
}

to include the QEMU headers?

 Thomas






[PATCH 08/14] target/s390x: Split per_breaking_event from per_branch_*

2024-05-01 Thread Richard Henderson
The breaking-event-address register is updated regardless
of PER being enabled.

Reviewed-by: Ilya Leoshkevich 
Signed-off-by: Richard Henderson 
---
 target/s390x/tcg/translate.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index e77660ee50..a384192d15 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -346,8 +346,6 @@ static void update_psw_addr(DisasContext *s)
 static void per_branch(DisasContext *s, bool to_next)
 {
 #ifndef CONFIG_USER_ONLY
-tcg_gen_movi_i64(gbea, s->base.pc_next);
-
 if (s->base.tb->flags & FLAG_MASK_PER_BRANCH) {
 TCGv_i64 next_pc = to_next ? tcg_constant_i64(s->pc_tmp) : psw_addr;
 gen_helper_per_branch(tcg_env, gbea, next_pc);
@@ -1083,13 +1081,13 @@ struct DisasInsn {
 
 static DisasJumpType help_goto_direct(DisasContext *s, uint64_t dest)
 {
+per_breaking_event(s);
 if (dest == s->pc_tmp) {
 per_branch(s, true);
 return DISAS_NEXT;
 }
 if (use_goto_tb(s, dest)) {
 update_cc_op(s);
-per_breaking_event(s);
 tcg_gen_goto_tb(0);
 tcg_gen_movi_i64(psw_addr, dest);
 tcg_gen_exit_tb(s->base.tb, 0);
@@ -1103,6 +1101,7 @@ static DisasJumpType help_goto_direct(DisasContext *s, 
uint64_t dest)
 
 static DisasJumpType help_goto_indirect(DisasContext *s, TCGv_i64 dest)
 {
+per_breaking_event(s);
 tcg_gen_mov_i64(psw_addr, dest);
 per_branch(s, false);
 return DISAS_PC_UPDATED;
@@ -1161,6 +1160,7 @@ static DisasJumpType help_branch(DisasContext *s, 
DisasCompare *c,
 }
 
 /* Branch taken.  */
+per_breaking_event(s);
 if (is_imm) {
 tcg_gen_movi_i64(psw_addr, dest);
 } else {
-- 
2.34.1




[PATCH 11/14] target/s390x: Fix helper_per_ifetch flags

2024-05-01 Thread Richard Henderson
CPU state is read on the exception path.

Fixes: 83bb161299c ("target-s390x: PER instruction-fetch nullification event 
support")
Signed-off-by: Richard Henderson 
---
 target/s390x/helper.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/s390x/helper.h b/target/s390x/helper.h
index 5611155ba1..31bd193322 100644
--- a/target/s390x/helper.h
+++ b/target/s390x/helper.h
@@ -361,7 +361,7 @@ DEF_HELPER_FLAGS_1(purge, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_3(lra, i64, env, i64, i64)
 DEF_HELPER_FLAGS_3(per_check_exception, TCG_CALL_NO_WG, void, env, i64, i32)
 DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_WG, void, env, i64, i32)
-DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_RWG, void, env, i64)
+DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_WG, void, env, i64)
 DEF_HELPER_FLAGS_2(per_store_real, TCG_CALL_NO_WG, noreturn, env, i32)
 DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
 
-- 
2.34.1




[PATCH 07/14] target/s390x: Simplify help_branch

2024-05-01 Thread Richard Henderson
Always use a tcg branch, instead of movcond.  The movcond
was not a bad idea before PER was added, but since then
we have either 2 or 3 actions to perform on each leg of
the branch, and multiple movcond is inefficient.

Reorder the taken branch to be fallthrough of the tcg branch.

Reviewed-by: Ilya Leoshkevich 
Signed-off-by: Richard Henderson 
---
 target/s390x/tcg/translate.c | 164 ---
 1 file changed, 56 insertions(+), 108 deletions(-)

diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index b1a93070cb..e77660ee50 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -355,25 +355,6 @@ static void per_branch(DisasContext *s, bool to_next)
 #endif
 }
 
-static void per_branch_cond(DisasContext *s, TCGCond cond,
-TCGv_i64 arg1, TCGv_i64 arg2)
-{
-#ifndef CONFIG_USER_ONLY
-if (s->base.tb->flags & FLAG_MASK_PER_BRANCH) {
-TCGLabel *lab = gen_new_label();
-tcg_gen_brcond_i64(tcg_invert_cond(cond), arg1, arg2, lab);
-
-tcg_gen_movi_i64(gbea, s->base.pc_next);
-gen_helper_per_branch(tcg_env, gbea, psw_addr);
-
-gen_set_label(lab);
-} else {
-TCGv_i64 pc = tcg_constant_i64(s->base.pc_next);
-tcg_gen_movcond_i64(cond, gbea, arg1, arg2, gbea, pc);
-}
-#endif
-}
-
 static void per_breaking_event(DisasContext *s)
 {
 tcg_gen_movi_i64(gbea, s->base.pc_next);
@@ -1130,14 +,12 @@ static DisasJumpType help_goto_indirect(DisasContext 
*s, TCGv_i64 dest)
 static DisasJumpType help_branch(DisasContext *s, DisasCompare *c,
  bool is_imm, int imm, TCGv_i64 cdest)
 {
-DisasJumpType ret;
 uint64_t dest = s->base.pc_next + (int64_t)imm * 2;
-TCGLabel *lab;
+TCGLabel *lab, *over;
 
 /* Take care of the special cases first.  */
 if (c->cond == TCG_COND_NEVER) {
-ret = DISAS_NEXT;
-goto egress;
+return DISAS_NEXT;
 }
 if (is_imm) {
 /*
@@ -1147,104 +1126,73 @@ static DisasJumpType help_branch(DisasContext *s, 
DisasCompare *c,
 if (c->cond == TCG_COND_ALWAYS
 || (dest == s->pc_tmp &&
 !(s->base.tb->flags & FLAG_MASK_PER_BRANCH))) {
-ret = help_goto_direct(s, dest);
-goto egress;
+return help_goto_direct(s, dest);
 }
 } else {
 if (!cdest) {
 /* E.g. bcr %r0 -> no branch.  */
-ret = DISAS_NEXT;
-goto egress;
+return DISAS_NEXT;
 }
 if (c->cond == TCG_COND_ALWAYS) {
-ret = help_goto_indirect(s, cdest);
-goto egress;
+return help_goto_indirect(s, cdest);
 }
 }
 
-if (use_goto_tb(s, s->pc_tmp)) {
-if (is_imm && use_goto_tb(s, dest)) {
-/* Both exits can use goto_tb.  */
-update_cc_op(s);
+update_cc_op(s);
 
-lab = gen_new_label();
-if (c->is_64) {
-tcg_gen_brcond_i64(c->cond, c->u.s64.a, c->u.s64.b, lab);
-} else {
-tcg_gen_brcond_i32(c->cond, c->u.s32.a, c->u.s32.b, lab);
-}
-
-/* Branch not taken.  */
-tcg_gen_goto_tb(0);
-tcg_gen_movi_i64(psw_addr, s->pc_tmp);
-tcg_gen_exit_tb(s->base.tb, 0);
-
-/* Branch taken.  */
-gen_set_label(lab);
-per_breaking_event(s);
-tcg_gen_goto_tb(1);
-tcg_gen_movi_i64(psw_addr, dest);
-tcg_gen_exit_tb(s->base.tb, 1);
-
-ret = DISAS_NORETURN;
-} else {
-/* Fallthru can use goto_tb, but taken branch cannot.  */
-/* Store taken branch destination before the brcond.  This
-   avoids having to allocate a new local temp to hold it.
-   We'll overwrite this in the not taken case anyway.  */
-if (!is_imm) {
-tcg_gen_mov_i64(psw_addr, cdest);
-}
-
-lab = gen_new_label();
-if (c->is_64) {
-tcg_gen_brcond_i64(c->cond, c->u.s64.a, c->u.s64.b, lab);
-} else {
-tcg_gen_brcond_i32(c->cond, c->u.s32.a, c->u.s32.b, lab);
-}
-
-/* Branch not taken.  */
-update_cc_op(s);
-tcg_gen_goto_tb(0);
-tcg_gen_movi_i64(psw_addr, s->pc_tmp);
-tcg_gen_exit_tb(s->base.tb, 0);
-
-gen_set_label(lab);
-if (is_imm) {
-tcg_gen_movi_i64(psw_addr, dest);
-}
-per_breaking_event(s);
-ret = DISAS_PC_UPDATED;
-}
+/*
+ * Ensure the taken branch is fall-through of the tcg branch.
+ * This keeps @cdest usage within the extended basic block,
+ * which avoids an otherwise unnecessary spill to the stack.
+ */
+lab = gen_new_label();
+if (s->base.tb->flags & FLAG_MASK_PER_BRANCH) {
+  

[PATCH 01/14] target/s390x: Do not use unwind for per_check_exception

2024-05-01 Thread Richard Henderson
Using exception unwind via tcg_s390_program_interrupt,
we discard the current value of psw.addr, which discards
the result of a branch.

Pass in the address of the next instruction, which may
not be sequential.  Pass in ilen, which we would have
gotten from unwind and is passed to the exception handler.
Sync cc_op before the call, which we would have gotten
from unwind.

Signed-off-by: Richard Henderson 
---
 target/s390x/helper.h  |  2 +-
 target/s390x/tcg/excp_helper.c |  2 +-
 target/s390x/tcg/misc_helper.c | 23 ---
 target/s390x/tcg/translate.c   | 13 +++--
 4 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/target/s390x/helper.h b/target/s390x/helper.h
index cc1c20e9e3..96ab71e877 100644
--- a/target/s390x/helper.h
+++ b/target/s390x/helper.h
@@ -359,7 +359,7 @@ DEF_HELPER_FLAGS_4(ipte, TCG_CALL_NO_RWG, void, env, i64, 
i64, i32)
 DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_FLAGS_1(purge, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_3(lra, i64, env, i64, i64)
-DEF_HELPER_1(per_check_exception, void, env)
+DEF_HELPER_FLAGS_3(per_check_exception, TCG_CALL_NO_WG, void, env, i64, i32)
 DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64)
 DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_RWG, void, env, i64)
 DEF_HELPER_FLAGS_1(per_store_real, TCG_CALL_NO_RWG, void, env)
diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c
index f1c33f7967..4c0b692c9e 100644
--- a/target/s390x/tcg/excp_helper.c
+++ b/target/s390x/tcg/excp_helper.c
@@ -209,7 +209,7 @@ static void do_program_interrupt(CPUS390XState *env)
 
 switch (env->int_pgm_code) {
 case PGM_PER:
-advance = !(env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION);
+/* advance already handled */
 break;
 case PGM_ASCE_TYPE:
 case PGM_REG_FIRST_TRANS:
diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c
index 8764846ce8..8c27998ab9 100644
--- a/target/s390x/tcg/misc_helper.c
+++ b/target/s390x/tcg/misc_helper.c
@@ -20,6 +20,7 @@
 
 #include "qemu/osdep.h"
 #include "qemu/cutils.h"
+#include "qemu/log.h"
 #include "cpu.h"
 #include "s390x-internal.h"
 #include "qemu/host-utils.h"
@@ -590,10 +591,26 @@ void HELPER(chsc)(CPUS390XState *env, uint64_t inst)
 #endif
 
 #ifndef CONFIG_USER_ONLY
-void HELPER(per_check_exception)(CPUS390XState *env)
+G_NORETURN static void per_raise_exception(CPUS390XState *env)
 {
-if (env->per_perc_atmid) {
-tcg_s390_program_interrupt(env, PGM_PER, GETPC());
+trigger_pgm_exception(env, PGM_PER);
+cpu_loop_exit(env_cpu(env));
+}
+
+G_NORETURN static void per_raise_exception_log(CPUS390XState *env)
+{
+qemu_log_mask(CPU_LOG_INT, "PER interrupt after %#" PRIx64 "\n",
+  env->per_address);
+per_raise_exception(env);
+}
+
+void HELPER(per_check_exception)(CPUS390XState *env, uint64_t next_pc,
+ uint32_t ilen)
+{
+if (unlikely(env->per_perc_atmid)) {
+env->psw.addr = next_pc;
+env->int_pgm_ilen = ilen;
+per_raise_exception_log(env);
 }
 }
 
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index 90a74ee795..2319dcf259 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -6426,13 +6426,14 @@ static DisasJumpType translate_one(CPUS390XState *env, 
DisasContext *s)
 
 #ifndef CONFIG_USER_ONLY
 if (s->base.tb->flags & FLAG_MASK_PER) {
-/* An exception might be triggered, save PSW if not already done.  */
-if (ret == DISAS_NEXT || ret == DISAS_TOO_MANY) {
-tcg_gen_movi_i64(psw_addr, s->pc_tmp);
-}
+TCGv_i64 next_pc = psw_addr;
 
-/* Call the helper to check for a possible PER exception.  */
-gen_helper_per_check_exception(tcg_env);
+if (ret == DISAS_NEXT || ret == DISAS_TOO_MANY) {
+next_pc = tcg_constant_i64(s->pc_tmp);
+}
+update_cc_op(s);
+gen_helper_per_check_exception(tcg_env, next_pc,
+   tcg_constant_i32(s->ilen));
 }
 #endif
 
-- 
2.34.1




[PATCH 03/14] target/s390x: Update CR9 bits

2024-05-01 Thread Richard Henderson
Update from the PoO 14th edition.

Signed-off-by: Richard Henderson 
---
 target/s390x/cpu.h | 18 +++---
 target/s390x/tcg/misc_helper.c |  2 +-
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index 950f84f316..1bb723a9d3 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -419,13 +419,17 @@ void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc,
 #endif /* CONFIG_TCG */
 
 /* PER bits from control register 9 */
-#define PER_CR9_EVENT_BRANCH   0x8000
-#define PER_CR9_EVENT_IFETCH   0x4000
-#define PER_CR9_EVENT_STORE0x2000
-#define PER_CR9_EVENT_STORE_REAL   0x0800
-#define PER_CR9_EVENT_NULLIFICATION0x0100
-#define PER_CR9_CONTROL_BRANCH_ADDRESS 0x0080
-#define PER_CR9_CONTROL_ALTERATION 0x0020
+#define PER_CR9_EVENT_BRANCH0x8000
+#define PER_CR9_EVENT_IFETCH0x4000
+#define PER_CR9_EVENT_STORE 0x2000
+#define PER_CR9_EVENT_STORAGE_KEY_ALTERATION0x1000
+#define PER_CR9_EVENT_STORE_REAL0x0800
+#define PER_CR9_EVENT_ZERO_ADDRESS_DETECTION0x0400
+#define PER_CR9_EVENT_TRANSACTION_END   0x0200
+#define PER_CR9_EVENT_IFETCH_NULLIFICATION  0x0100
+#define PER_CR9_CONTROL_BRANCH_ADDRESS  0x0080
+#define PER_CR9_CONTROL_TRANSACTION_SUPRESS 0x0040
+#define PER_CR9_CONTROL_STORAGE_ALTERATION  0x0020
 
 /* PER bits from the PER CODE/ATMID/AI in lowcore */
 #define PER_CODE_EVENT_BRANCH  0x8000
diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c
index 8c27998ab9..02215a7f18 100644
--- a/target/s390x/tcg/misc_helper.c
+++ b/target/s390x/tcg/misc_helper.c
@@ -644,7 +644,7 @@ void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr)
 
 /* If the instruction has to be nullified, trigger the
exception immediately. */
-if (env->cregs[9] & PER_CR9_EVENT_NULLIFICATION) {
+if (env->cregs[9] & PER_CR9_EVENT_IFETCH_NULLIFICATION) {
 CPUState *cs = env_cpu(env);
 
 env->per_perc_atmid |= PER_CODE_EVENT_NULLIFICATION;
-- 
2.34.1




[PATCH 13/14] target/s390x: Adjust check of noreturn in translate_one

2024-05-01 Thread Richard Henderson
If help_op is not set, ret == DISAS_NEXT.
Shift the test up from surrounding help_wout, help_cout
to skipping to out, as we do elsewhere in the function.

Signed-off-by: Richard Henderson 
---
 target/s390x/tcg/translate.c | 15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index 7cf2920aec..8e9c0847e3 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -6343,14 +6343,15 @@ static DisasJumpType translate_one(CPUS390XState *env, 
DisasContext *s)
 }
 if (insn->help_op) {
 ret = insn->help_op(s, &o);
+if (ret == DISAS_NORETURN) {
+goto out;
+}
 }
-if (ret != DISAS_NORETURN) {
-if (insn->help_wout) {
-insn->help_wout(s, &o);
-}
-if (insn->help_cout) {
-insn->help_cout(s, &o);
-}
+if (insn->help_wout) {
+insn->help_wout(s, &o);
+}
+if (insn->help_cout) {
+insn->help_cout(s, &o);
 }
 
 /* io should be the last instruction in tb when icount is enabled */
-- 
2.34.1




[PATCH 05/14] target/s390x: Disable conditional branch-to-next for PER

2024-05-01 Thread Richard Henderson
For PER, we require a conditional call to helper_per_branch
for the conditional branch.  Fold the remaining optimization
into a call to helper_goto_direct, which will take care of
the remaining gbea adjustment.

Reviewed-by: Ilya Leoshkevich 
Signed-off-by: Richard Henderson 
---
 target/s390x/tcg/translate.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index 3622c5c883..c3c821430d 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -1133,13 +1133,13 @@ static DisasJumpType help_branch(DisasContext *s, 
DisasCompare *c,
 goto egress;
 }
 if (is_imm) {
-if (dest == s->pc_tmp) {
-/* Branch to next.  */
-per_branch(s, true);
-ret = DISAS_NEXT;
-goto egress;
-}
-if (c->cond == TCG_COND_ALWAYS) {
+/*
+ * Do not optimize a conditional branch if PER enabled, because we
+ * still need a conditional call to helper_per_branch.
+ */
+if (c->cond == TCG_COND_ALWAYS
+|| (dest == s->pc_tmp &&
+!(s->base.tb->flags & FLAG_MASK_PER_BRANCH))) {
 ret = help_goto_direct(s, dest);
 goto egress;
 }
-- 
2.34.1




[PATCH 12/14] target/s390x: Simplify per_ifetch, per_check_exception

2024-05-01 Thread Richard Henderson
Set per_address and ilen in per_ifetch; this is valid for
all PER exceptions and will last until the end of the
instruction.  Therefore we don't need to give the same
data to per_check_exception.

Signed-off-by: Richard Henderson 

# Conflicts:
#   target/s390x/tcg/misc_helper.c
---
 target/s390x/helper.h  |  4 ++--
 target/s390x/tcg/misc_helper.c | 23 +--
 target/s390x/tcg/translate.c   | 20 
 3 files changed, 23 insertions(+), 24 deletions(-)

diff --git a/target/s390x/helper.h b/target/s390x/helper.h
index 31bd193322..1a8a76abb9 100644
--- a/target/s390x/helper.h
+++ b/target/s390x/helper.h
@@ -359,9 +359,9 @@ DEF_HELPER_FLAGS_4(ipte, TCG_CALL_NO_RWG, void, env, i64, 
i64, i32)
 DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_FLAGS_1(purge, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_3(lra, i64, env, i64, i64)
-DEF_HELPER_FLAGS_3(per_check_exception, TCG_CALL_NO_WG, void, env, i64, i32)
+DEF_HELPER_FLAGS_1(per_check_exception, TCG_CALL_NO_WG, void, env)
 DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_WG, void, env, i64, i32)
-DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_WG, void, env, i64)
+DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_WG, void, env, i32)
 DEF_HELPER_FLAGS_2(per_store_real, TCG_CALL_NO_WG, noreturn, env, i32)
 DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
 
diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c
index 5f1efc6a32..f5e674a26e 100644
--- a/target/s390x/tcg/misc_helper.c
+++ b/target/s390x/tcg/misc_helper.c
@@ -604,12 +604,10 @@ G_NORETURN static void 
per_raise_exception_log(CPUS390XState *env)
 per_raise_exception(env);
 }
 
-void HELPER(per_check_exception)(CPUS390XState *env, uint64_t next_pc,
- uint32_t ilen)
+void HELPER(per_check_exception)(CPUS390XState *env)
 {
+/* psw_addr, per_address and int_pgm_ilen are already set. */
 if (unlikely(env->per_perc_atmid)) {
-env->psw.addr = next_pc;
-env->int_pgm_ilen = ilen;
 per_raise_exception_log(env);
 }
 }
@@ -639,23 +637,20 @@ void HELPER(per_branch)(CPUS390XState *env, uint64_t 
dest, uint32_t ilen)
 per_raise_exception_log(env);
 }
 
-void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr)
+void HELPER(per_ifetch)(CPUS390XState *env, uint32_t ilen)
 {
-if (get_per_in_range(env, addr)) {
-env->per_address = addr;
+if (get_per_in_range(env, env->psw.addr)) {
+env->per_address = env->psw.addr;
+env->int_pgm_ilen = ilen;
 env->per_perc_atmid = PER_CODE_EVENT_IFETCH | get_per_atmid(env);
 
 /* If the instruction has to be nullified, trigger the
exception immediately. */
 if (env->cregs[9] & PER_CR9_EVENT_IFETCH_NULLIFICATION) {
-CPUState *cs = env_cpu(env);
-
 env->per_perc_atmid |= PER_CODE_EVENT_NULLIFICATION;
-env->int_pgm_code = PGM_PER;
-env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, addr));
-
-cs->exception_index = EXCP_PGM;
-cpu_loop_exit(cs);
+qemu_log_mask(CPU_LOG_INT, "PER interrupt before %#" PRIx64 "\n",
+  env->per_address);
+per_raise_exception(env);
 }
 }
 }
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index 041857e720..7cf2920aec 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -6260,8 +6260,8 @@ static DisasJumpType translate_one(CPUS390XState *env, 
DisasContext *s)
 
 #ifndef CONFIG_USER_ONLY
 if (s->base.tb->flags & FLAG_MASK_PER_IFETCH) {
-TCGv_i64 addr = tcg_constant_i64(s->base.pc_next);
-gen_helper_per_ifetch(tcg_env, addr);
+/* With ifetch set, psw_addr and cc_op are always up-to-date. */
+gen_helper_per_ifetch(tcg_env, tcg_constant_i32(s->ilen));
 }
 #endif
 
@@ -6360,14 +6360,18 @@ static DisasJumpType translate_one(CPUS390XState *env, 
DisasContext *s)
 
 #ifndef CONFIG_USER_ONLY
 if (s->base.tb->flags & FLAG_MASK_PER_IFETCH) {
-TCGv_i64 next_pc = psw_addr;
-
-if (ret == DISAS_NEXT || ret == DISAS_TOO_MANY) {
-next_pc = tcg_constant_i64(s->pc_tmp);
+switch (ret) {
+case DISAS_TOO_MANY:
+s->base.is_jmp = DISAS_PC_CC_UPDATED;
+/* fall through */
+case DISAS_NEXT:
+tcg_gen_movi_i64(psw_addr, s->pc_tmp);
+break;
+default:
+break;
 }
 update_cc_op(s);
-gen_helper_per_check_exception(tcg_env, next_pc,
-   tcg_constant_i32(s->ilen));
+gen_helper_per_check_exception(tcg_env);
 }
 #endif
 
-- 
2.34.1




[PATCH 09/14] target/s390x: Raise exception from helper_per_branch

2024-05-01 Thread Richard Henderson
Drop from argument, since gbea has always been updated with
this address.  Add ilen argument for setting int_pgm_ilen.
Use update_cc_op before calling per_branch.

By raising the exception here, we need not call
per_check_exception later, which means we can clean up the
normal non-exception branch path.

Signed-off-by: Richard Henderson 
---
 target/s390x/helper.h  |  2 +-
 target/s390x/tcg/misc_helper.c | 15 +++
 target/s390x/tcg/translate.c   | 48 --
 3 files changed, 27 insertions(+), 38 deletions(-)

diff --git a/target/s390x/helper.h b/target/s390x/helper.h
index 96ab71e877..061b379065 100644
--- a/target/s390x/helper.h
+++ b/target/s390x/helper.h
@@ -360,7 +360,7 @@ DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_FLAGS_1(purge, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_3(lra, i64, env, i64, i64)
 DEF_HELPER_FLAGS_3(per_check_exception, TCG_CALL_NO_WG, void, env, i64, i32)
-DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64)
+DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_WG, void, env, i64, i32)
 DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_RWG, void, env, i64)
 DEF_HELPER_FLAGS_1(per_store_real, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c
index b7100c06c0..5b1c512367 100644
--- a/target/s390x/tcg/misc_helper.c
+++ b/target/s390x/tcg/misc_helper.c
@@ -625,13 +625,18 @@ static inline bool get_per_in_range(CPUS390XState *env, 
uint64_t addr)
 }
 }
 
-void HELPER(per_branch)(CPUS390XState *env, uint64_t from, uint64_t to)
+void HELPER(per_branch)(CPUS390XState *env, uint64_t dest, uint32_t ilen)
 {
-if (!(env->cregs[9] & PER_CR9_CONTROL_BRANCH_ADDRESS)
-|| get_per_in_range(env, to)) {
-env->per_address = from;
-env->per_perc_atmid = PER_CODE_EVENT_BRANCH | get_per_atmid(env);
+if ((env->cregs[9] & PER_CR9_CONTROL_BRANCH_ADDRESS)
+&& !get_per_in_range(env, dest)) {
+return;
 }
+
+env->psw.addr = dest;
+env->int_pgm_ilen = ilen;
+env->per_address = env->gbea;
+env->per_perc_atmid = PER_CODE_EVENT_BRANCH | get_per_atmid(env);
+per_raise_exception_log(env);
 }
 
 void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr)
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index a384192d15..4a6ef144b7 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -343,12 +343,11 @@ static void update_psw_addr(DisasContext *s)
 tcg_gen_movi_i64(psw_addr, s->base.pc_next);
 }
 
-static void per_branch(DisasContext *s, bool to_next)
+static void per_branch(DisasContext *s, TCGv_i64 dest)
 {
 #ifndef CONFIG_USER_ONLY
 if (s->base.tb->flags & FLAG_MASK_PER_BRANCH) {
-TCGv_i64 next_pc = to_next ? tcg_constant_i64(s->pc_tmp) : psw_addr;
-gen_helper_per_branch(tcg_env, gbea, next_pc);
+gen_helper_per_branch(tcg_env, dest, tcg_constant_i32(s->ilen));
 }
 #endif
 }
@@ -637,9 +636,6 @@ static void gen_op_calc_cc(DisasContext *s)
 
 static bool use_goto_tb(DisasContext *s, uint64_t dest)
 {
-if (unlikely(s->base.tb->flags & FLAG_MASK_PER_BRANCH)) {
-return false;
-}
 return translator_use_goto_tb(&s->base, dest);
 }
 
@@ -1081,37 +1077,38 @@ struct DisasInsn {
 
 static DisasJumpType help_goto_direct(DisasContext *s, uint64_t dest)
 {
+update_cc_op(s);
 per_breaking_event(s);
+per_branch(s, tcg_constant_i64(dest));
+
 if (dest == s->pc_tmp) {
-per_branch(s, true);
 return DISAS_NEXT;
 }
 if (use_goto_tb(s, dest)) {
-update_cc_op(s);
 tcg_gen_goto_tb(0);
 tcg_gen_movi_i64(psw_addr, dest);
 tcg_gen_exit_tb(s->base.tb, 0);
 return DISAS_NORETURN;
 } else {
 tcg_gen_movi_i64(psw_addr, dest);
-per_branch(s, false);
-return DISAS_PC_UPDATED;
+return DISAS_PC_CC_UPDATED;
 }
 }
 
 static DisasJumpType help_goto_indirect(DisasContext *s, TCGv_i64 dest)
 {
+update_cc_op(s);
 per_breaking_event(s);
 tcg_gen_mov_i64(psw_addr, dest);
-per_branch(s, false);
-return DISAS_PC_UPDATED;
+per_branch(s, psw_addr);
+return DISAS_PC_CC_UPDATED;
 }
 
 static DisasJumpType help_branch(DisasContext *s, DisasCompare *c,
  bool is_imm, int imm, TCGv_i64 cdest)
 {
 uint64_t dest = s->base.pc_next + (int64_t)imm * 2;
-TCGLabel *lab, *over;
+TCGLabel *lab;
 
 /* Take care of the special cases first.  */
 if (c->cond == TCG_COND_NEVER) {
@@ -1145,12 +1142,6 @@ static DisasJumpType help_branch(DisasContext *s, 
DisasCompare *c,
  * which avoids an otherwise unnecessary spill to the stack.
  */
 lab = gen_new_label();
-if (s->base.tb->flags & FLAG_MASK_PER_BRANCH) {
-over = gen_new_label();
-} else {
-over = NULL;
-}
-
 if (c->is_64) {
 tcg_gen_brcond_i

[PATCH 14/14] tests/tcg/s390x: Add per.S

2024-05-01 Thread Richard Henderson
Add a small test to avoid regressions.

Signed-off-by: Richard Henderson 
---
 tests/tcg/s390x/Makefile.softmmu-target |  1 +
 tests/tcg/s390x/per.S   | 82 +
 2 files changed, 83 insertions(+)
 create mode 100644 tests/tcg/s390x/per.S

diff --git a/tests/tcg/s390x/Makefile.softmmu-target 
b/tests/tcg/s390x/Makefile.softmmu-target
index 1a1f088b28..80159cccf5 100644
--- a/tests/tcg/s390x/Makefile.softmmu-target
+++ b/tests/tcg/s390x/Makefile.softmmu-target
@@ -25,6 +25,7 @@ ASM_TESTS =   
 \
 lpswe-early
\
 lra
\
 mc 
\
+per
\
 precise-smc-softmmu
\
 ssm-early  
\
 stosm-early
\
diff --git a/tests/tcg/s390x/per.S b/tests/tcg/s390x/per.S
new file mode 100644
index 00..79e704a6ff
--- /dev/null
+++ b/tests/tcg/s390x/per.S
@@ -0,0 +1,82 @@
+   .org0x8d
+ilc:
+   .org0x8e
+program_interruption_code:
+   .org0x96
+per_code:
+   .org0x98
+per_address:
+   .org0x150
+program_old_psw:
+   .org0x1d0
+program_new_psw:
+   .quad   0, pgm_handler
+
+   .org0x200   /* exit lowcore */
+
+per_on_psw:
+   .quad   0x4000, start_per
+per_on_regs:
+   .quad   0x8000, 0, -1   /* successful-branching everywhere */
+per_off_regs:
+   .quad   0, 0 ,0
+success_psw:
+   .quad   0x2, 0xfff  /* see is_special_wait_psw() */
+failure_psw:
+   .quad   0x2, 0  /* disabled wait */
+
+   .org0x2000  /* exit lowcore pages */
+
+   .globl _start
+_start:
+   lpswe   per_on_psw
+start_per:
+   lctlg   %c9, %c11, per_on_regs
+
+/* Test unconditional relative branch. */
+   larl%r0, j1
+   larl%r1, d1
+   lhi %r2, 0
+j1:j   d1
+   lpswe   failure_psw
+d1:
+
+/* Test unconditional indirect branch. */
+   larl%r0, j2
+   larl%r1, d2
+j2:br  %r1
+   lpswe   failure_psw
+d2:
+
+/* Test conditional relative branch. */
+   larl%r0, j3
+   larl%r1, d3
+   clr %r1, %r2/* d3 != 0 */
+j3:jne d3
+   lpswe   failure_psw
+d3:
+
+/* Test conditional register branch. */
+   larl%r0, j4
+   larl%r1, d4
+   clr %r1, %r2/* d4 != 0 */
+j4:bner%r1
+   lpswe   failure_psw
+d4:
+
+/* Success! */
+   nop
+   lpswe   success_psw
+
+pgm_handler:
+   chhsi   program_interruption_code, 0x80 /* PER event? */
+   jne fail
+   cli per_code, 0x80  /* successful-branching event? */
+   jne fail
+   clg %r0, per_address/* per_address == jump insn? */
+   jne fail
+   clg %r1, program_old_psw+8  /* psw.addr updated to dest? */
+   jne fail
+   lpswe   program_old_psw
+fail:
+   lpswe   failure_psw
-- 
2.34.1




[PATCH 06/14] target/s390x: Introduce help_goto_indirect

2024-05-01 Thread Richard Henderson
Add a small helper to handle unconditional indirect jumps.

Reviewed-by: Philippe Mathieu-Daudé 
Reviewed-by: Ilya Leoshkevich 
Signed-off-by: Richard Henderson 
---
 target/s390x/tcg/translate.c | 19 ++-
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index c3c821430d..b1a93070cb 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -1120,6 +1120,13 @@ static DisasJumpType help_goto_direct(DisasContext *s, 
uint64_t dest)
 }
 }
 
+static DisasJumpType help_goto_indirect(DisasContext *s, TCGv_i64 dest)
+{
+tcg_gen_mov_i64(psw_addr, dest);
+per_branch(s, false);
+return DISAS_PC_UPDATED;
+}
+
 static DisasJumpType help_branch(DisasContext *s, DisasCompare *c,
  bool is_imm, int imm, TCGv_i64 cdest)
 {
@@ -1150,9 +1157,7 @@ static DisasJumpType help_branch(DisasContext *s, 
DisasCompare *c,
 goto egress;
 }
 if (c->cond == TCG_COND_ALWAYS) {
-tcg_gen_mov_i64(psw_addr, cdest);
-per_branch(s, false);
-ret = DISAS_PC_UPDATED;
+ret = help_goto_indirect(s, cdest);
 goto egress;
 }
 }
@@ -1465,9 +1470,7 @@ static DisasJumpType op_bas(DisasContext *s, DisasOps *o)
 {
 pc_to_link_info(o->out, s, s->pc_tmp);
 if (o->in2) {
-tcg_gen_mov_i64(psw_addr, o->in2);
-per_branch(s, false);
-return DISAS_PC_UPDATED;
+return help_goto_indirect(s, o->in2);
 } else {
 return DISAS_NEXT;
 }
@@ -1497,9 +1500,7 @@ static DisasJumpType op_bal(DisasContext *s, DisasOps *o)
 {
 save_link_info(s, o);
 if (o->in2) {
-tcg_gen_mov_i64(psw_addr, o->in2);
-per_branch(s, false);
-return DISAS_PC_UPDATED;
+return help_goto_indirect(s, o->in2);
 } else {
 return DISAS_NEXT;
 }
-- 
2.34.1




[PATCH 04/14] target/s390x: Record separate PER bits in TB flags

2024-05-01 Thread Richard Henderson
Record successful-branching, instruction-fetching, and
store-using-real-address.  The other PER bits are not used
during translation.  Having checked these at translation time,
we can remove runtime tests from the helpers.

Signed-off-by: Richard Henderson 
---
 target/s390x/cpu.h | 42 --
 target/s390x/cpu.c | 22 ++
 target/s390x/tcg/misc_helper.c | 21 +++--
 target/s390x/tcg/translate.c   | 10 
 4 files changed, 61 insertions(+), 34 deletions(-)

diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index 1bb723a9d3..d6b75ad0e0 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -342,19 +342,32 @@ extern const VMStateDescription vmstate_s390_cpu;
 
 /* tb flags */
 
-#define FLAG_MASK_PSW_SHIFT 31
-#define FLAG_MASK_PER   (PSW_MASK_PER>> FLAG_MASK_PSW_SHIFT)
-#define FLAG_MASK_DAT   (PSW_MASK_DAT>> FLAG_MASK_PSW_SHIFT)
-#define FLAG_MASK_PSTATE(PSW_MASK_PSTATE >> FLAG_MASK_PSW_SHIFT)
-#define FLAG_MASK_ASC   (PSW_MASK_ASC>> FLAG_MASK_PSW_SHIFT)
-#define FLAG_MASK_64(PSW_MASK_64 >> FLAG_MASK_PSW_SHIFT)
-#define FLAG_MASK_32(PSW_MASK_32 >> FLAG_MASK_PSW_SHIFT)
-#define FLAG_MASK_PSW   (FLAG_MASK_PER | FLAG_MASK_DAT | 
FLAG_MASK_PSTATE \
-| FLAG_MASK_ASC | FLAG_MASK_64 | FLAG_MASK_32)
+#define FLAG_MASK_PSW_SHIFT 31
+#define FLAG_MASK_320x0001u
+#define FLAG_MASK_640x0002u
+#define FLAG_MASK_AFP   0x0004u
+#define FLAG_MASK_VECTOR0x0008u
+#define FLAG_MASK_ASC   0x00018000u
+#define FLAG_MASK_PSTATE0x0002u
+#define FLAG_MASK_PER_IFETCH_NULLIFY0x0100u
+#define FLAG_MASK_DAT   0x0800u
+#define FLAG_MASK_PER_STORE_REAL0x2000u
+#define FLAG_MASK_PER_IFETCH0x4000u
+#define FLAG_MASK_PER_BRANCH0x8000u
 
-/* we'll use some unused PSW positions to store CR flags in tb flags */
-#define FLAG_MASK_AFP   (PSW_MASK_UNUSED_2 >> FLAG_MASK_PSW_SHIFT)
-#define FLAG_MASK_VECTOR(PSW_MASK_UNUSED_3 >> FLAG_MASK_PSW_SHIFT)
+QEMU_BUILD_BUG_ON(FLAG_MASK_32 != PSW_MASK_32 >> FLAG_MASK_PSW_SHIFT);
+QEMU_BUILD_BUG_ON(FLAG_MASK_64 != PSW_MASK_64 >> FLAG_MASK_PSW_SHIFT);
+QEMU_BUILD_BUG_ON(FLAG_MASK_ASC != PSW_MASK_ASC >> FLAG_MASK_PSW_SHIFT);
+QEMU_BUILD_BUG_ON(FLAG_MASK_PSTATE != PSW_MASK_PSTATE >> FLAG_MASK_PSW_SHIFT);
+QEMU_BUILD_BUG_ON(FLAG_MASK_DAT != PSW_MASK_DAT >> FLAG_MASK_PSW_SHIFT);
+
+#define FLAG_MASK_PSW   (FLAG_MASK_DAT | FLAG_MASK_PSTATE | \
+ FLAG_MASK_ASC | FLAG_MASK_64 | FLAG_MASK_32)
+#define FLAG_MASK_CR9   (FLAG_MASK_PER_BRANCH | FLAG_MASK_PER_IFETCH)
+#define FLAG_MASK_PER   (FLAG_MASK_PER_BRANCH | \
+ FLAG_MASK_PER_IFETCH | \
+ FLAG_MASK_PER_IFETCH_NULLIFY | \
+ FLAG_MASK_PER_STORE_REAL)
 
 /* Control register 0 bits */
 #define CR0_LOWPROT 0x1000ULL
@@ -431,6 +444,11 @@ void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc,
 #define PER_CR9_CONTROL_TRANSACTION_SUPRESS 0x0040
 #define PER_CR9_CONTROL_STORAGE_ALTERATION  0x0020
 
+QEMU_BUILD_BUG_ON(FLAG_MASK_PER_BRANCH != PER_CR9_EVENT_BRANCH);
+QEMU_BUILD_BUG_ON(FLAG_MASK_PER_IFETCH != PER_CR9_EVENT_IFETCH);
+QEMU_BUILD_BUG_ON(FLAG_MASK_PER_IFETCH_NULLIFY !=
+  PER_CR9_EVENT_IFETCH_NULLIFICATION);
+
 /* PER bits from the PER CODE/ATMID/AI in lowcore */
 #define PER_CODE_EVENT_BRANCH  0x8000
 #define PER_CODE_EVENT_IFETCH  0x4000
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index a8428b5a1e..2bbeaca36e 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -325,8 +325,10 @@ static void s390_cpu_reset_full(DeviceState *dev)
 #include "hw/core/tcg-cpu-ops.h"
 
 void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc,
-  uint64_t *cs_base, uint32_t *flags)
+  uint64_t *cs_base, uint32_t *pflags)
 {
+uint32_t flags;
+
 if (env->psw.addr & 1) {
 /*
  * Instructions must be at even addresses.
@@ -335,15 +337,27 @@ void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc,
 env->int_pgm_ilen = 2; /* see s390_cpu_tlb_fill() */
 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, 0);
 }
+
 *pc = env->psw.addr;
 *cs_base = env->ex_value;
-*flags = (env->psw.mask >> FLAG_MASK_PSW_SHIFT) & FLAG_MASK_PSW;
+
+flags = (env->psw.mask >> FLAG_MASK_PSW_SHIFT) & FLAG_MASK_PSW;
+if (env->psw.mask & PSW_MASK_PER) {
+flags |= env->cregs[9] & (FLAG_MASK_PER_BRANCH |
+  FLAG_MASK_PER_IFETCH |
+  FLAG_MASK_PER_IFETCH_NULLIFY);
+if (

[PATCH 10/14] target/s390x: Raise exception from per_store_real

2024-05-01 Thread Richard Henderson
At this point the instruction is complete and there's nothing
left to do but raise the exception.  With this change we need
not make two helper calls for this event.

Signed-off-by: Richard Henderson 
---
 target/s390x/helper.h  | 2 +-
 target/s390x/tcg/misc_helper.c | 4 +++-
 target/s390x/tcg/translate.c   | 7 ---
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/target/s390x/helper.h b/target/s390x/helper.h
index 061b379065..5611155ba1 100644
--- a/target/s390x/helper.h
+++ b/target/s390x/helper.h
@@ -362,7 +362,7 @@ DEF_HELPER_3(lra, i64, env, i64, i64)
 DEF_HELPER_FLAGS_3(per_check_exception, TCG_CALL_NO_WG, void, env, i64, i32)
 DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_WG, void, env, i64, i32)
 DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_RWG, void, env, i64)
-DEF_HELPER_FLAGS_1(per_store_real, TCG_CALL_NO_RWG, void, env)
+DEF_HELPER_FLAGS_2(per_store_real, TCG_CALL_NO_WG, noreturn, env, i32)
 DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
 
 DEF_HELPER_2(xsch, void, env, i64)
diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c
index 5b1c512367..5f1efc6a32 100644
--- a/target/s390x/tcg/misc_helper.c
+++ b/target/s390x/tcg/misc_helper.c
@@ -660,11 +660,13 @@ void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr)
 }
 }
 
-void HELPER(per_store_real)(CPUS390XState *env)
+void HELPER(per_store_real)(CPUS390XState *env, uint32_t ilen)
 {
 /* PSW is saved just before calling the helper.  */
 env->per_address = env->psw.addr;
+env->int_pgm_ilen = ilen;
 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
+per_raise_exception_log(env);
 }
 #endif
 
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index 4a6ef144b7..041857e720 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -4344,8 +4344,10 @@ static DisasJumpType op_stura(DisasContext *s, DisasOps 
*o)
 tcg_gen_qemu_st_tl(o->in1, o->in2, MMU_REAL_IDX, s->insn->data);
 
 if (s->base.tb->flags & FLAG_MASK_PER_STORE_REAL) {
+update_cc_op(s);
 update_psw_addr(s);
-gen_helper_per_store_real(tcg_env);
+gen_helper_per_store_real(tcg_env, tcg_constant_i32(s->ilen));
+return DISAS_NORETURN;
 }
 return DISAS_NEXT;
 }
@@ -6357,8 +6359,7 @@ static DisasJumpType translate_one(CPUS390XState *env, 
DisasContext *s)
 }
 
 #ifndef CONFIG_USER_ONLY
-if (s->base.tb->flags & (FLAG_MASK_PER_STORE_REAL |
- FLAG_MASK_PER_IFETCH)) {
+if (s->base.tb->flags & FLAG_MASK_PER_IFETCH) {
 TCGv_i64 next_pc = psw_addr;
 
 if (ret == DISAS_NEXT || ret == DISAS_TOO_MANY) {
-- 
2.34.1




[PATCH 02/14] target/s390x: Move cpu_get_tb_cpu_state out of line

2024-05-01 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/s390x/cpu.h | 23 ++-
 target/s390x/cpu.c | 22 ++
 2 files changed, 24 insertions(+), 21 deletions(-)

diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index 414680eed1..950f84f316 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -413,27 +413,8 @@ static inline int s390x_env_mmu_index(CPUS390XState *env, 
bool ifetch)
 
 #include "tcg/tcg_s390x.h"
 
-static inline void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc,
-uint64_t *cs_base, uint32_t *flags)
-{
-if (env->psw.addr & 1) {
-/*
- * Instructions must be at even addresses.
- * This needs to be checked before address translation.
- */
-env->int_pgm_ilen = 2; /* see s390_cpu_tlb_fill() */
-tcg_s390_program_interrupt(env, PGM_SPECIFICATION, 0);
-}
-*pc = env->psw.addr;
-*cs_base = env->ex_value;
-*flags = (env->psw.mask >> FLAG_MASK_PSW_SHIFT) & FLAG_MASK_PSW;
-if (env->cregs[0] & CR0_AFP) {
-*flags |= FLAG_MASK_AFP;
-}
-if (env->cregs[0] & CR0_VECTOR) {
-*flags |= FLAG_MASK_VECTOR;
-}
-}
+void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc,
+  uint64_t *cs_base, uint32_t *flags);
 
 #endif /* CONFIG_TCG */
 
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index f7194534ae..a8428b5a1e 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -324,6 +324,28 @@ static void s390_cpu_reset_full(DeviceState *dev)
 #ifdef CONFIG_TCG
 #include "hw/core/tcg-cpu-ops.h"
 
+void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc,
+  uint64_t *cs_base, uint32_t *flags)
+{
+if (env->psw.addr & 1) {
+/*
+ * Instructions must be at even addresses.
+ * This needs to be checked before address translation.
+ */
+env->int_pgm_ilen = 2; /* see s390_cpu_tlb_fill() */
+tcg_s390_program_interrupt(env, PGM_SPECIFICATION, 0);
+}
+*pc = env->psw.addr;
+*cs_base = env->ex_value;
+*flags = (env->psw.mask >> FLAG_MASK_PSW_SHIFT) & FLAG_MASK_PSW;
+if (env->cregs[0] & CR0_AFP) {
+*flags |= FLAG_MASK_AFP;
+}
+if (env->cregs[0] & CR0_VECTOR) {
+*flags |= FLAG_MASK_VECTOR;
+}
+}
+
 static const TCGCPUOps s390_tcg_ops = {
 .initialize = s390x_translate_init,
 .restore_state_to_opc = s390x_restore_state_to_opc,
-- 
2.34.1




[PATCH 00/14] target/s390x: Fix and improve PER

2024-05-01 Thread Richard Henderson
Split out from 

v1: 
https://lore.kernel.org/qemu-devel/20220906101747.344559-1-richard.hender...@linaro.org/
v4: 
https://lore.kernel.org/qemu-devel/20230220184052.163465-1-richard.hender...@linaro.org/

after I noticed that the testcase,

https://lore.kernel.org/qemu-devel/20221130174610.434590-2-...@linux.ibm.com/

does not actually work under KVM.

In fact, support for PER_CR9_EVENT_BRANCH in TCG is broken.
This cleans it up and improves things so that when only one PER bit
is set (what I assume to be the normal state of afairs), we have
less overhead.

I'm not sure that all of the interactions are correct, particularly
with multiple PER triggers or other exceptions.  For that, we'd need
a more complex test case.  But at least branches match hardware now.


r~


Richard Henderson (14):
  target/s390x: Do not use unwind for per_check_exception
  target/s390x: Move cpu_get_tb_cpu_state out of line
  target/s390x: Update CR9 bits
  target/s390x: Record separate PER bits in TB flags
  target/s390x: Disable conditional branch-to-next for PER
  target/s390x: Introduce help_goto_indirect
  target/s390x: Simplify help_branch
  target/s390x: Split per_breaking_event from per_branch_*
  target/s390x: Raise exception from helper_per_branch
  target/s390x: Raise exception from per_store_real
  target/s390x: Fix helper_per_ifetch flags
  target/s390x: Simplify per_ifetch, per_check_exception
  target/s390x: Adjust check of noreturn in translate_one
  tests/tcg/s390x: Add per.S

 target/s390x/cpu.h  |  83 
 target/s390x/helper.h   |   8 +-
 target/s390x/cpu.c  |  36 
 target/s390x/tcg/excp_helper.c  |   2 +-
 target/s390x/tcg/misc_helper.c  |  68 ---
 target/s390x/tcg/translate.c| 248 +---
 tests/tcg/s390x/Makefile.softmmu-target |   1 +
 tests/tcg/s390x/per.S   |  82 
 8 files changed, 302 insertions(+), 226 deletions(-)
 create mode 100644 tests/tcg/s390x/per.S

-- 
2.34.1




[PATCH v1 1/2] tests/qtest/bios-tables-test: Update virt SPCR golden references

2024-05-01 Thread Sia Jee Heng
Update the virt SPCR golden reference files to accommodate the
SPCR Table version 4 [1], utilizing the iasl binary compiled from the
latest ACPICA repository [2]. The SPCR table has been modified to
adhere to the version 4 format [3].

[1]: 
https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
[2]: https://github.com/acpica/acpica
[3]: https://github.com/acpica/acpica/pull/931

Diffs from iasl:
@@ -1,32 +1,32 @@
 /*
  * Intel ACPI Component Architecture
  * AML/ASL+ Disassembler version 20240322 (64-bit version)
  * Copyright (c) 2000 - 2023 Intel Corporation
  *
- * Disassembly of tests/data/acpi/virt/SPCR
+ * Disassembly of /tmp/aml-HJ5IN2
  *
  * ACPI Data Table [SPCR]
  *
  * Format: [HexOffset DecimalOffset ByteLength]  FieldName : FieldValue (in 
hex)
  */

 [000h  004h]   Signature : "SPCR"[Serial Port Console 
Redirection Table]
-[004h 0004 004h]Table Length : 0050
-[008h 0008 001h]Revision : 02
-[009h 0009 001h]Checksum : B1
+[004h 0004 004h]Table Length : 005A
+[008h 0008 001h]Revision : 04
+[009h 0009 001h]Checksum : 1D
 [00Ah 0010 006h]  Oem ID : "BOCHS "
 [010h 0016 008h]Oem Table ID : "BXPC"
 [018h 0024 004h]Oem Revision : 0001
 [01Ch 0028 004h] Asl Compiler ID : "BXPC"
 [020h 0032 004h]   Asl Compiler Revision : 0001

 [024h 0036 001h]  Interface Type : 03
 [025h 0037 003h]Reserved : 00

 [028h 0040 00Ch]Serial Port Register : [Generic Address Structure]
 [028h 0040 001h]Space ID : 00 [SystemMemory]
 [029h 0041 001h]   Bit Width : 20
 [02Ah 0042 001h]  Bit Offset : 00
 [02Bh 0043 001h]Encoded Access Width : 03 [DWord Access:32]
 [02Ch 0044 008h] Address : 0900
@@ -34,18 +34,29 @@
 [035h 0053 001h] PCAT-compatible IRQ : 00
 [036h 0054 004h]   Interrupt : 0021
 [03Ah 0058 001h]   Baud Rate : 03
 [03Bh 0059 001h]  Parity : 00
 [03Ch 0060 001h]   Stop Bits : 01
 [03Dh 0061 001h]Flow Control : 02
 [03Eh 0062 001h]   Terminal Type : 00
 [03Fh 0063 001h]Language : 00
 [040h 0064 002h]   PCI Device ID : 
 [042h 0066 002h]   PCI Vendor ID : 
 [044h 0068 001h] PCI Bus : 00
 [045h 0069 001h]  PCI Device : 00
 [046h 0070 001h]PCI Function : 00
 [047h 0071 004h]   PCI Flags : 
 [04Bh 0075 001h] PCI Segment : 00
 [04Ch 0076 004h] Uart Clock Freq : 
-/ ACPI table terminates in the middle of a data structure! (dump table)
-CurrentOffset: 50, TableLength: 50 ***/
\ No newline at end of file
+[050h 0080 004h]   Precise Baud rate : 
+[054h 0084 002h]   NameSpaceStringLength : 0002
+[056h 0086 002h]   NameSpaceStringOffset : 0058
+[058h 0088 002h] NamespaceString : "."
+
+Raw Table Data: Length 90 (0x5A)
+
+: 53 50 43 52 5A 00 00 00 04 1D 42 4F 43 48 53 20  // SPCRZ.BOCHS
+0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43  // BXPCBXPC
+0020: 01 00 00 00 03 00 00 00 00 20 00 03 00 00 00 09  // . ..
+0030: 00 00 00 00 08 00 21 00 00 00 03 00 01 02 00 00  // ..!.
+0040: FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00  // 
+0050: 00 00 00 00 02 00 58 00 2E 00// ..X...

Signed-off-by: Sia Jee Heng 
---
 tests/data/acpi/virt/SPCR | Bin 80 -> 90 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)

diff --git a/tests/data/acpi/virt/SPCR b/tests/data/acpi/virt/SPCR
index 
cf0f2b75226515097c08d2e2016a83a4f08812ba..acafd161ba2e2fdfbf081d4977ea05621152c9c9
 100644
GIT binary patch
delta 27
hcmWHD;tCFM4vJ!6U|^A*$mPZbWH2x>L@?+v002b>1KR)q

delta 16
XcmazF;0g|K4hmpkU|`xfk;@GLAfp4(

-- 
2.34.1




[PATCH v1 0/2] Upgrade ACPI SPCR table to support SPCR table version 4 format

2024-05-01 Thread Sia Jee Heng
Update the SPCR table to accommodate the SPCR Table version 4 [1].
The SPCR table has been modified to adhere to the version 4 format [2].

Meanwhile, the virt SPCR golden reference files have been updated to
accommodate the SPCR Table version 4.

[1]: 
https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
[2]: https://github.com/acpica/acpica/pull/931

Sia Jee Heng (2):
  tests/qtest/bios-tables-test: Update virt SPCR golden references
  hw/acpi: Upgrade ACPI SPCR table to support SPCR table version 4
format

 hw/acpi/aml-build.c |  14 +++---
 hw/arm/virt-acpi-build.c|  10 --
 hw/riscv/virt-acpi-build.c  |  10 --
 include/hw/acpi/acpi-defs.h |   7 +--
 include/hw/acpi/aml-build.h |   2 +-
 tests/data/acpi/virt/SPCR   | Bin 80 -> 90 bytes
 6 files changed, 33 insertions(+), 10 deletions(-)


base-commit: 4977ce198d2390bff8c71ad5cb1a5f6aa24b56fb
-- 
2.34.1




[PATCH v1 2/2] hw/acpi: Upgrade ACPI SPCR table to support SPCR table version 4 format

2024-05-01 Thread Sia Jee Heng
Update the SPCR table to accommodate the SPCR Table version 4 [1].
The SPCR table has been modified to adhere to the version 4 format [2].

[1]: 
https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
[2]: https://github.com/acpica/acpica/pull/931

Signed-off-by: Sia Jee Heng 
---
 hw/acpi/aml-build.c | 14 +++---
 hw/arm/virt-acpi-build.c| 10 --
 hw/riscv/virt-acpi-build.c  | 10 --
 include/hw/acpi/acpi-defs.h |  7 +--
 include/hw/acpi/aml-build.h |  2 +-
 5 files changed, 33 insertions(+), 10 deletions(-)

diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 6d4517cfbe..7c43573eef 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1996,7 +1996,7 @@ static void build_processor_hierarchy_node(GArray *tbl, 
uint32_t flags,
 
 void build_spcr(GArray *table_data, BIOSLinker *linker,
 const AcpiSpcrData *f, const uint8_t rev,
-const char *oem_id, const char *oem_table_id)
+const char *oem_id, const char *oem_table_id, const char *name)
 {
 AcpiTable table = { .sig = "SPCR", .rev = rev, .oem_id = oem_id,
 .oem_table_id = oem_table_id };
@@ -2042,8 +2042,16 @@ void build_spcr(GArray *table_data, BIOSLinker *linker,
 build_append_int_noprefix(table_data, f->pci_flags, 4);
 /* PCI Segment */
 build_append_int_noprefix(table_data, f->pci_segment, 1);
-/* Reserved */
-build_append_int_noprefix(table_data, 0, 4);
+/* UartClkFreq */
+build_append_int_noprefix(table_data, f->uart_clk_freq, 4);
+/* PreciseBaudrate */
+build_append_int_noprefix(table_data, f->precise_baudrate, 4);
+/* NameSpaceStringLength */
+build_append_int_noprefix(table_data, f->namespace_string_length, 2);
+/* NameSpaceStringOffset */
+build_append_int_noprefix(table_data, f->namespace_string_offset, 2);
+/* NamespaceString[] */
+g_array_append_vals(table_data, name, f->namespace_string_length);
 
 acpi_table_end(linker, &table);
 }
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index c3ccfef026..fc7b0176ed 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -429,11 +429,12 @@ build_iort(GArray *table_data, BIOSLinker *linker, 
VirtMachineState *vms)
 
 /*
  * Serial Port Console Redirection Table (SPCR)
- * Rev: 1.07
+ * Rev: 1.10
  */
 static void
 spcr_setup(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
 {
+const char name[] = ".";
 AcpiSpcrData serial = {
 .interface_type = 3,   /* ARM PL011 UART */
 .base_addr.id = AML_AS_SYSTEM_MEMORY,
@@ -457,9 +458,14 @@ spcr_setup(GArray *table_data, BIOSLinker *linker, 
VirtMachineState *vms)
 .pci_function = 0,
 .pci_flags = 0,
 .pci_segment = 0,
+.uart_clk_freq = 0,
+.precise_baudrate = 0,
+.namespace_string_length = sizeof(name),
+.namespace_string_offset = 88,
 };
 
-build_spcr(table_data, linker, &serial, 2, vms->oem_id, vms->oem_table_id);
+build_spcr(table_data, linker, &serial, 4, vms->oem_id, vms->oem_table_id,
+   name);
 }
 
 /*
diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c
index 0925528160..5712211847 100644
--- a/hw/riscv/virt-acpi-build.c
+++ b/hw/riscv/virt-acpi-build.c
@@ -176,12 +176,13 @@ acpi_dsdt_add_uart(Aml *scope, const MemMapEntry 
*uart_memmap,
 
 /*
  * Serial Port Console Redirection Table (SPCR)
- * Rev: 1.07
+ * Rev: 1.10
  */
 
 static void
 spcr_setup(GArray *table_data, BIOSLinker *linker, RISCVVirtState *s)
 {
+const char name[] = ".";
 AcpiSpcrData serial = {
 .interface_type = 0,   /* 16550 compatible */
 .base_addr.id = AML_AS_SYSTEM_MEMORY,
@@ -205,9 +206,14 @@ spcr_setup(GArray *table_data, BIOSLinker *linker, 
RISCVVirtState *s)
 .pci_function = 0,
 .pci_flags = 0,
 .pci_segment = 0,
+.uart_clk_freq = 0,
+.precise_baudrate = 0,
+.namespace_string_length = sizeof(name),
+.namespace_string_offset = 88,
 };
 
-build_spcr(table_data, linker, &serial, 2, s->oem_id, s->oem_table_id);
+build_spcr(table_data, linker, &serial, 4, s->oem_id, s->oem_table_id,
+   name);
 }
 
 /* RHCT Node[N] starts at offset 56 */
diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index 0e6e82b339..2e6e341998 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -112,7 +112,6 @@ typedef struct AcpiSpcrData {
 uint8_t flow_control;
 uint8_t terminal_type;
 uint8_t language;
-uint8_t reserved1;
 uint16_t pci_device_id;/* Must be 0x if not PCI device */
 uint16_t pci_vendor_id;/* Must be 0x if not PCI device */
 uint8_t pci_bus;
@@ -120,7 +119,11 @@ typedef struct AcpiSpcrData {
 uint8_t pci_function;
 uint32_t pci_flags;
 uint8_t pci_segment;
-uint32_t reserved

Re: [PATCH intel_iommu 0/7] FLTS for VT-d

2024-05-01 Thread CLEMENT MATHIEU--DRIF
Hi Zhenzhong,

I will rebase,

thanks

On 01/05/2024 14:40, Duan, Zhenzhong wrote:
> Caution: External email. Do not open attachments or click links, unless this 
> email comes from a known sender and you know the content is safe.
>
>
> Ah, this is a duplicate effort on stage-1 translation.
>
> Hi Clement,
>
> We had ever sent a rfcv1 series "intel_iommu: Enable stage-1 translation"
> for both emulated and passthrough device, link:
> https://lists.gnu.org/archive/html/qemu-devel/2024-01/msg02740.html
> which now evolves to rfcv2, link:
> https://github.com/yiliu1765/qemu/commits/zhenzhong/iommufd_nesting_rfcv2/
>
> It had addressed recent community comments, also the comments in old history 
> series:
> https://patchwork.kernel.org/project/kvm/cover/20210302203827.437645-1-yi.l@intel.com/
>
> Would you mind rebasing your remaining part, i.e., ATS, PRI emulation, etc on 
> to our rfcv2?
>
> Thanks
> Zhenzhong
>
>> -Original Message-
>> From: Cédric Le Goater 
>> Subject: Re: [PATCH intel_iommu 0/7] FLTS for VT-d
>>
>> Hello,
>>
>> Adding a few people in Cc: who are familiar with the Intel IOMMU.
>>
>> Thanks,
>>
>> C.
>>
>>
>>
>>
>> On 4/22/24 17:52, CLEMENT MATHIEU--DRIF wrote:
>>> This series is the first of a list that add support for SVM in the Intel 
>>> IOMMU.
>>>
>>> Here, we implement support for first-stage translation in VT-d.
>>> The PASID-based IOTLB invalidation is also added in this series as it is a
>>> requirement of FLTS.
>>>
>>> The last patch introduces the 'flts' option to enable the feature from
>>> the command line.
>>> Once enabled, several drivers of the Linux kernel use this feature.
>>>
>>> This work is based on the VT-d specification version 4.1 (March 2023)
>>>
>>> Here is a link to a GitHub repository where you can find the following
>> elements :
>>>   - Qemu with all the patches for SVM
>>>   - ATS
>>>   - PRI
>>>   - PASID based IOTLB invalidation
>>>   - Device IOTLB invalidations
>>>   - First-stage translations
>>>   - Requests with already translated addresses
>>>   - A demo device
>>>   - A simple driver for the demo device
>>>   - A userspace program (for testing and demonstration purposes)
>>>
>>> https://github.com/BullSequana/Qemu-in-guest-SVM-demo
>>>
>>> Clément Mathieu--Drif (7):
>>> intel_iommu: fix FRCD construction macro.
>>> intel_iommu: rename slpte to pte before adding FLTS
>>> intel_iommu: make types match
>>> intel_iommu: add support for first-stage translation
>>> intel_iommu: extract device IOTLB invalidation logic
>>> intel_iommu: add PASID-based IOTLB invalidation
>>> intel_iommu: add a CLI option to enable FLTS
>>>
>>>hw/i386/intel_iommu.c  | 655 ++--
>> -
>>>hw/i386/intel_iommu_internal.h | 114 --
>>>include/hw/i386/intel_iommu.h  |   3 +-
>>>3 files changed, 609 insertions(+), 163 deletions(-)
>>>


QEMU headers in C++

2024-05-01 Thread Roman Kiryanov
Hi QEMU,

I work in Android Studio Emulator and we would like to develop devices
in C++. Unfortunately, QEMU headers cannot be used with C++ as is
(e.g. they use C++ keywords as variable names or implicitly cast void*
to T*).

Will QEMU be open to accept patches from us to make QEMU headers C++ compatible?

Thank you.

Regards,
Roman.



Re: [PULL 00/20] tcg patch queue

2024-05-01 Thread Richard Henderson

On 5/1/24 07:37, Richard Henderson wrote:

The following changes since commit 9c6c079bc6723da8061ccfb44361d67b1dd785dd:

   Merge tag 'pull-target-arm-20240430' 
ofhttps://git.linaro.org/people/pmaydell/qemu-arm  into staging (2024-04-30 
09:58:54 -0700)

are available in the Git repository at:

   https://gitlab.com/rth7680/qemu.git  tags/pull-tcg-20240501

for you to fetch changes up to 917d7f8d948d706e275c9f33169b9dd0149ded1e:

   plugins: Update the documentation block for plugin-gen.c (2024-04-30 
16:12:05 -0700)


plugins: Rewrite plugin tcg expansion


Applied, thanks.  Please update https://wiki.qemu.org/ChangeLog/9.1 as 
appropriate.


r~




[PATCH v2 01/28] target/ppc: Fix gen_sc to use correct nip

2024-05-01 Thread BALATON Zoltan
Most exceptions are raised with nip pointing to the faulting
instruction but the sc instruction generating a syscall exception
leaves nip pointing to next instruction. Fix gen_sc to not use
gen_exception_err() which sets nip back but correctly set nip to
pc_next so we don't have to patch this in the exception handlers.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/excp_helper.c | 43 ++--
 target/ppc/translate.c   | 15 ++
 2 files changed, 8 insertions(+), 50 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 0712098cf7..92fe535815 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -116,7 +116,7 @@ static void dump_syscall(CPUPPCState *env)
   ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
   ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
   ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7),
-  ppc_dump_gpr(env, 8), env->nip);
+  ppc_dump_gpr(env, 8), env->nip - 4);
 }
 
 static void dump_hcall(CPUPPCState *env)
@@ -131,7 +131,7 @@ static void dump_hcall(CPUPPCState *env)
   ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
   ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
   ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
-  env->nip);
+  env->nip - 4);
 }
 
 #ifdef CONFIG_TCG
@@ -516,12 +516,6 @@ static void powerpc_excp_40x(PowerPCCPU *cpu, int excp)
 break;
 case POWERPC_EXCP_SYSCALL:   /* System call exception*/
 dump_syscall(env);
-
-/*
- * We need to correct the NIP which in this case is supposed
- * to point to the next instruction
- */
-env->nip += 4;
 break;
 case POWERPC_EXCP_FIT:   /* Fixed-interval timer interrupt   */
 trace_ppc_excp_print("FIT");
@@ -632,12 +626,6 @@ static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp)
 break;
 case POWERPC_EXCP_SYSCALL:   /* System call exception*/
 dump_syscall(env);
-
-/*
- * We need to correct the NIP which in this case is supposed
- * to point to the next instruction
- */
-env->nip += 4;
 break;
 case POWERPC_EXCP_FPU:   /* Floating-point unavailable exception */
 case POWERPC_EXCP_DECR:  /* Decrementer exception*/
@@ -780,13 +768,6 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp)
 } else {
 dump_syscall(env);
 }
-
-/*
- * We need to correct the NIP which in this case is supposed
- * to point to the next instruction
- */
-env->nip += 4;
-
 /*
  * The Virtual Open Firmware (VOF) relies on the 'sc 1'
  * instruction to communicate with QEMU. The pegasos2 machine
@@ -932,13 +913,6 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
 } else {
 dump_syscall(env);
 }
-
-/*
- * We need to correct the NIP which in this case is supposed
- * to point to the next instruction
- */
-env->nip += 4;
-
 /*
  * The Virtual Open Firmware (VOF) relies on the 'sc 1'
  * instruction to communicate with QEMU. The pegasos2 machine
@@ -1098,12 +1072,6 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
 break;
 case POWERPC_EXCP_SYSCALL:   /* System call exception*/
 dump_syscall(env);
-
-/*
- * We need to correct the NIP which in this case is supposed
- * to point to the next instruction
- */
-env->nip += 4;
 break;
 case POWERPC_EXCP_FPU:   /* Floating-point unavailable exception */
 case POWERPC_EXCP_APU:   /* Auxiliary processor unavailable  */
@@ -1428,13 +1396,6 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
 } else {
 dump_syscall(env);
 }
-
-/*
- * We need to correct the NIP which in this case is supposed
- * to point to the next instruction
- */
-env->nip += 4;
-
 /* "PAPR mode" built-in hypercall emulation */
 if (lev == 1 && books_vhyp_handles_hcall(cpu)) {
 PPCVirtualHypervisorClass *vhc =
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 93ffec787c..e112c44a02 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -4472,22 +4472,19 @@ static void gen_hrfid(DisasContext *ctx)
 #endif
 
 /* sc */
-#if defined(CONFIG_USER_ONLY)
-#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL_USER
-#else
-#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL
-#endif
 static void gen_sc(DisasContext *ctx)
 {
-uint32_t lev;
-
 /*
  * LEV is a 7-bit field, but the top 6 bits are treated as a reserved
  * field (i.e., ignored). ISA v3.1 changes that t

[PATCH v2 26/28] target/ppc/mmu_common.c: Move BookE MMU functions together

2024-05-01 Thread BALATON Zoltan
Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 300 
 1 file changed, 150 insertions(+), 150 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index b76611da80..204b8af455 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -910,6 +910,156 @@ found_tlb:
 return ret;
 }
 
+static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong 
address,
+ MMUAccessType access_type, int 
mmu_idx)
+{
+uint32_t epid;
+bool as, pr;
+uint32_t missed_tid = 0;
+bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
+
+if (access_type == MMU_INST_FETCH) {
+as = FIELD_EX64(env->msr, MSR, IR);
+}
+env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
+env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
+env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
+env->spr[SPR_BOOKE_MAS3] = 0;
+env->spr[SPR_BOOKE_MAS6] = 0;
+env->spr[SPR_BOOKE_MAS7] = 0;
+
+/* AS */
+if (as) {
+env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
+env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
+}
+
+env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
+env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
+
+if (!use_epid) {
+switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
+case MAS4_TIDSELD_PID0:
+missed_tid = env->spr[SPR_BOOKE_PID];
+break;
+case MAS4_TIDSELD_PID1:
+missed_tid = env->spr[SPR_BOOKE_PID1];
+break;
+case MAS4_TIDSELD_PID2:
+missed_tid = env->spr[SPR_BOOKE_PID2];
+break;
+}
+env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
+} else {
+missed_tid = epid;
+env->spr[SPR_BOOKE_MAS6] |= missed_tid << 16;
+}
+env->spr[SPR_BOOKE_MAS1] |= (missed_tid << MAS1_TID_SHIFT);
+
+
+/* next victim logic */
+env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
+env->last_way++;
+env->last_way &= booke206_tlb_ways(env, 0) - 1;
+env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+}
+
+static bool ppc_booke_xlate(PowerPCCPU *cpu, vaddr eaddr,
+MMUAccessType access_type,
+hwaddr *raddrp, int *psizep, int *protp,
+int mmu_idx, bool guest_visible)
+{
+CPUState *cs = CPU(cpu);
+CPUPPCState *env = &cpu->env;
+mmu_ctx_t ctx;
+int ret;
+
+if (env->mmu_model == POWERPC_MMU_BOOKE206) {
+ret = mmubooke206_get_physical_address(env, &ctx, eaddr, access_type,
+   mmu_idx);
+} else {
+ret = mmubooke_get_physical_address(env, &ctx, eaddr, access_type);
+}
+if (ret == 0) {
+*raddrp = ctx.raddr;
+*protp = ctx.prot;
+*psizep = TARGET_PAGE_BITS;
+return true;
+} else if (!guest_visible) {
+return false;
+}
+
+log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
+env->error_code = 0;
+if (env->mmu_model == POWERPC_MMU_BOOKE206 && ret == -1) {
+booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx);
+}
+if (access_type == MMU_INST_FETCH) {
+if (ret == -1) {
+/* No matches in page tables or TLB */
+cs->exception_index = POWERPC_EXCP_ITLB;
+env->spr[SPR_BOOKE_DEAR] = eaddr;
+env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
+} else {
+cs->exception_index = POWERPC_EXCP_ISI;
+if (ret == -3) {
+/* No execute protection violation */
+env->spr[SPR_BOOKE_ESR] = 0;
+}
+}
+return false;
+}
+
+switch (ret) {
+case -1:
+/* No matches in page tables or TLB */
+cs->exception_index = POWERPC_EXCP_DTLB;
+env->spr[SPR_BOOKE_DEAR] = eaddr;
+env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
+break;
+case -2:
+/* Access rights violation */
+cs->exception_index = POWERPC_EXCP_DSI;
+env->spr[SPR_BOOKE_DEAR] = eaddr;
+env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
+break;
+case -4:
+/* Direct store exception */
+env->spr[SPR_DAR] = eaddr;
+switch (env->access_type) {
+case ACCESS_FLOAT:
+/* Floating point load/store */
+cs->exception_index = POWERPC_EXCP_ALIGN;
+env->error_code = POWERPC_EXCP_ALIGN_FP;
+break;
+case ACCESS_RES:
+/* lwarx, ldarx or stwcx. */
+cs->exception_index = POWERPC_EXCP_DSI;
+if (access_type == MMU_DATA_STORE) {
+env->spr[SPR_DSISR] = 0x0600;
+} else {
+env->spr[SPR_DSISR] = 0x0400;
+

[PATCH v2 18/28] target/ppc/mmu_common.c: Deindent ppc_jumbo_xlate()

2024-05-01 Thread BALATON Zoltan
Instead of putting a large block of code in an if, invert the
condition and return early to be able to deindent the code block.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 319 
 1 file changed, 159 insertions(+), 160 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 28847c32f2..2487b4deff 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -1265,187 +1265,186 @@ static bool ppc_jumbo_xlate(PowerPCCPU *cpu, vaddr 
eaddr,
 *protp = ctx.prot;
 *psizep = TARGET_PAGE_BITS;
 return true;
+} else if (!guest_visible) {
+return false;
 }
 
-if (guest_visible) {
-log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
-if (type == ACCESS_CODE) {
-switch (ret) {
-case -1:
-/* No matches in page tables or TLB */
-switch (env->mmu_model) {
-case POWERPC_MMU_SOFT_6xx:
-cs->exception_index = POWERPC_EXCP_IFTLB;
-env->error_code = 1 << 18;
-env->spr[SPR_IMISS] = eaddr;
-env->spr[SPR_ICMP] = 0x8000 | ctx.ptem;
-goto tlb_miss;
-case POWERPC_MMU_SOFT_4xx:
-cs->exception_index = POWERPC_EXCP_ITLB;
-env->error_code = 0;
-env->spr[SPR_40x_DEAR] = eaddr;
-env->spr[SPR_40x_ESR] = 0x;
-break;
-case POWERPC_MMU_BOOKE206:
-booke206_update_mas_tlb_miss(env, eaddr, 2, mmu_idx);
-/* fall through */
-case POWERPC_MMU_BOOKE:
-cs->exception_index = POWERPC_EXCP_ITLB;
-env->error_code = 0;
-env->spr[SPR_BOOKE_DEAR] = eaddr;
-env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 
MMU_DATA_LOAD);
-break;
-case POWERPC_MMU_REAL:
-cpu_abort(cs, "PowerPC in real mode should never raise "
-  "any MMU exceptions\n");
-default:
-cpu_abort(cs, "Unknown or invalid MMU model\n");
-}
+log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
+if (type == ACCESS_CODE) {
+switch (ret) {
+case -1:
+/* No matches in page tables or TLB */
+switch (env->mmu_model) {
+case POWERPC_MMU_SOFT_6xx:
+cs->exception_index = POWERPC_EXCP_IFTLB;
+env->error_code = 1 << 18;
+env->spr[SPR_IMISS] = eaddr;
+env->spr[SPR_ICMP] = 0x8000 | ctx.ptem;
+goto tlb_miss;
+case POWERPC_MMU_SOFT_4xx:
+cs->exception_index = POWERPC_EXCP_ITLB;
+env->error_code = 0;
+env->spr[SPR_40x_DEAR] = eaddr;
+env->spr[SPR_40x_ESR] = 0x;
 break;
-case -2:
-/* Access rights violation */
-cs->exception_index = POWERPC_EXCP_ISI;
-if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
-(env->mmu_model == POWERPC_MMU_BOOKE206)) {
-env->error_code = 0;
-} else {
-env->error_code = 0x0800;
-}
+case POWERPC_MMU_BOOKE206:
+booke206_update_mas_tlb_miss(env, eaddr, 2, mmu_idx);
+/* fall through */
+case POWERPC_MMU_BOOKE:
+cs->exception_index = POWERPC_EXCP_ITLB;
+env->error_code = 0;
+env->spr[SPR_BOOKE_DEAR] = eaddr;
+env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 
MMU_DATA_LOAD);
 break;
-case -3:
-/* No execute protection violation */
-if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
-(env->mmu_model == POWERPC_MMU_BOOKE206)) {
-env->spr[SPR_BOOKE_ESR] = 0x;
-env->error_code = 0;
+case POWERPC_MMU_REAL:
+cpu_abort(cs, "PowerPC in real mode should never raise "
+  "any MMU exceptions\n");
+default:
+cpu_abort(cs, "Unknown or invalid MMU model\n");
+}
+break;
+case -2:
+/* Access rights violation */
+cs->exception_index = POWERPC_EXCP_ISI;
+if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+(env->mmu_model == POWERPC_MMU_BOOKE206)) {
+env->error_code = 0;
+} else {
+env->error_code = 0x0800;
+}
+break;
+case -3:
+/* No execute protection violation */
+if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+ 

[PATCH v2 28/28] target/ppc: Split off common 4xx TLB init

2024-05-01 Thread BALATON Zoltan
Several 4xx related CPUs have the same TLB settings. Split it off in a
common function in cpu_init.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/cpu_init.c | 46 ---
 1 file changed, 17 insertions(+), 29 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 07ad788e54..d7e85c1b07 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -2107,18 +2107,22 @@ static int check_pow_hid0_74xx(CPUPPCState *env)
 return 0;
 }
 
+static void init_tlbs_4xx(CPUPPCState *env)
+{
+#ifndef CONFIG_USER_ONLY
+env->nb_tlb = 64;
+env->nb_ways = 1;
+env->tlb_type = TLB_EMB;
+#endif
+}
+
 static void init_proc_405(CPUPPCState *env)
 {
 register_40x_sprs(env);
 register_405_sprs(env);
 register_usprgh_sprs(env);
 
-/* Memory management */
-#if !defined(CONFIG_USER_ONLY)
-env->nb_tlb = 64;
-env->nb_ways = 1;
-env->tlb_type = TLB_EMB;
-#endif
+init_tlbs_4xx(env);
 init_excp_4xx(env);
 env->dcache_line_size = 32;
 env->icache_line_size = 32;
@@ -2185,12 +2189,8 @@ static void init_proc_440EP(CPUPPCState *env)
  SPR_NOACCESS, SPR_NOACCESS,
  &spr_read_generic, &spr_write_generic,
  0x);
-/* Memory management */
-#if !defined(CONFIG_USER_ONLY)
-env->nb_tlb = 64;
-env->nb_ways = 1;
-env->tlb_type = TLB_EMB;
-#endif
+
+init_tlbs_4xx(env);
 init_excp_BookE(env);
 env->dcache_line_size = 32;
 env->icache_line_size = 32;
@@ -2282,12 +2282,7 @@ static void init_proc_440GP(CPUPPCState *env)
 register_440_sprs(env);
 register_usprgh_sprs(env);
 
-/* Memory management */
-#if !defined(CONFIG_USER_ONLY)
-env->nb_tlb = 64;
-env->nb_ways = 1;
-env->tlb_type = TLB_EMB;
-#endif
+init_tlbs_4xx(env);
 init_excp_BookE(env);
 env->dcache_line_size = 32;
 env->icache_line_size = 32;
@@ -2355,12 +2350,8 @@ static void init_proc_440x5(CPUPPCState *env)
  SPR_NOACCESS, SPR_NOACCESS,
  &spr_read_generic, &spr_write_generic,
  0x);
-/* Memory management */
-#if !defined(CONFIG_USER_ONLY)
-env->nb_tlb = 64;
-env->nb_ways = 1;
-env->tlb_type = TLB_EMB;
-#endif
+
+init_tlbs_4xx(env);
 init_excp_BookE(env);
 env->dcache_line_size = 32;
 env->icache_line_size = 32;
@@ -2717,11 +2708,8 @@ static void init_proc_e200(CPUPPCState *env)
  SPR_NOACCESS, SPR_NOACCESS,
  &spr_read_generic, &spr_write_generic,
  0x);
-#if !defined(CONFIG_USER_ONLY)
-env->nb_tlb = 64;
-env->nb_ways = 1;
-env->tlb_type = TLB_EMB;
-#endif
+
+init_tlbs_4xx(env);
 init_excp_e200(env, 0xUL);
 env->dcache_line_size = 32;
 env->icache_line_size = 32;
-- 
2.30.9




[PATCH v2 10/28] target/ppc/mmu_common.c: Introduce mmu6xx_get_physical_address()

2024-05-01 Thread BALATON Zoltan
Repurpose get_segment_6xx_tlb() to do the whole address translation
for POWERPC_MMU_SOFT_6xx MMU model by moving the BAT check there and
renaming it to match other similar functions. These are only called
once together so no need to keep these separate functions and
combining them simplifies the caller allowing further restructuring.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 32 
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 98730035b1..ef1669b01d 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -359,19 +359,25 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t 
*ctx,
 return ret;
 }
 
-/* Perform segment based translation */
-static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
-   target_ulong eaddr, MMUAccessType access_type,
-   int type)
+static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+   target_ulong eaddr,
+   MMUAccessType access_type, int type)
 {
 PowerPCCPU *cpu = env_archcpu(env);
 hwaddr hash;
-target_ulong vsid;
-int ds, target_page_bits;
+target_ulong vsid, sr, pgidx;
 bool pr;
-int ret;
-target_ulong sr, pgidx;
+int ds, target_page_bits, ret = -1;
 
+/* First try to find a BAT entry if there are any */
+if (env->nb_BATs != 0) {
+ret = get_bat_6xx_tlb(env, ctx, eaddr, access_type);
+}
+if (ret >= 0) {
+return ret;
+}
+
+/* Perform segment based translation when no BATs matched */
 pr = FIELD_EX64(env->msr, MSR, PR);
 ctx->eaddr = eaddr;
 
@@ -1193,14 +1199,8 @@ int get_physical_address_wtlb(CPUPPCState *env, 
mmu_ctx_t *ctx,
 if (real_mode) {
 ret = check_physical(env, ctx, eaddr, access_type);
 } else {
-/* Try to find a BAT */
-if (env->nb_BATs != 0) {
-ret = get_bat_6xx_tlb(env, ctx, eaddr, access_type);
-}
-if (ret < 0) {
-/* We didn't match any BAT entry or don't have BATs */
-ret = get_segment_6xx_tlb(env, ctx, eaddr, access_type, type);
-}
+ret = mmu6xx_get_physical_address(env, ctx, eaddr, access_type,
+  type);
 }
 break;
 
-- 
2.30.9




[PATCH v2 07/28] target/ppc/mmu_common.c: Remove unneeded local variable

2024-05-01 Thread BALATON Zoltan
In mmubooke_check_tlb() and mmubooke206_check_tlb() we can assign the
value directly the the destination, no need to have a separate local
variable for it.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 30 +-
 1 file changed, 13 insertions(+), 17 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index b0aca8ec02..74c3b814c9 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -627,8 +627,6 @@ static int mmubooke_check_tlb(CPUPPCState *env, 
ppcemb_tlb_t *tlb,
   hwaddr *raddr, int *prot, target_ulong address,
   MMUAccessType access_type, int i)
 {
-int prot2;
-
 if (!mmubooke_check_pid(env, tlb, raddr, address, i)) {
 qemu_log_mask(CPU_LOG_MMU, "%s: TLB entry not found\n", __func__);
 return -1;
@@ -643,17 +641,16 @@ static int mmubooke_check_tlb(CPUPPCState *env, 
ppcemb_tlb_t *tlb,
 }
 
 if (FIELD_EX64(env->msr, MSR, PR)) {
-prot2 = tlb->prot & 0xF;
+*prot = tlb->prot & 0xF;
 } else {
-prot2 = (tlb->prot >> 4) & 0xF;
+*prot = (tlb->prot >> 4) & 0xF;
 }
-*prot = prot2;
-if (prot2 & prot_for_access_type(access_type)) {
+if (*prot & prot_for_access_type(access_type)) {
 qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
 return 0;
 }
 
-qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, prot2);
+qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot);
 return access_type == MMU_INST_FETCH ? -3 : -2;
 }
 
@@ -794,7 +791,6 @@ static int mmubooke206_check_tlb(CPUPPCState *env, 
ppcmas_tlb_t *tlb,
  target_ulong address,
  MMUAccessType access_type, int mmu_idx)
 {
-int prot2 = 0;
 uint32_t epid;
 bool as, pr;
 bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
@@ -840,34 +836,34 @@ found_tlb:
 return -1;
 }
 
+*prot = 0;
 if (pr) {
 if (tlb->mas7_3 & MAS3_UR) {
-prot2 |= PAGE_READ;
+*prot |= PAGE_READ;
 }
 if (tlb->mas7_3 & MAS3_UW) {
-prot2 |= PAGE_WRITE;
+*prot |= PAGE_WRITE;
 }
 if (tlb->mas7_3 & MAS3_UX) {
-prot2 |= PAGE_EXEC;
+*prot |= PAGE_EXEC;
 }
 } else {
 if (tlb->mas7_3 & MAS3_SR) {
-prot2 |= PAGE_READ;
+*prot |= PAGE_READ;
 }
 if (tlb->mas7_3 & MAS3_SW) {
-prot2 |= PAGE_WRITE;
+*prot |= PAGE_WRITE;
 }
 if (tlb->mas7_3 & MAS3_SX) {
-prot2 |= PAGE_EXEC;
+*prot |= PAGE_EXEC;
 }
 }
-*prot = prot2;
-if (prot2 & prot_for_access_type(access_type)) {
+if (*prot & prot_for_access_type(access_type)) {
 qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
 return 0;
 }
 
-qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, prot2);
+qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot);
 return access_type == MMU_INST_FETCH ? -3 : -2;
 }
 
-- 
2.30.9




[PATCH v2 05/28] target/ppc/mmu_common.c: Move calculation of a value closer to its usage

2024-05-01 Thread BALATON Zoltan
In mmubooke_check_tlb() prot2 is calculated first but only used after
an unrelated check that can return before tha value is used. Move the
calculation after the check, closer to where it is used, to keep them
together and avoid computing it when not needed.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 751403f1c8..168ff842a5 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -634,12 +634,6 @@ static int mmubooke_check_tlb(CPUPPCState *env, 
ppcemb_tlb_t *tlb,
 return -1;
 }
 
-if (FIELD_EX64(env->msr, MSR, PR)) {
-prot2 = tlb->prot & 0xF;
-} else {
-prot2 = (tlb->prot >> 4) & 0xF;
-}
-
 /* Check the address space */
 if ((access_type == MMU_INST_FETCH ?
 FIELD_EX64(env->msr, MSR, IR) :
@@ -648,6 +642,11 @@ static int mmubooke_check_tlb(CPUPPCState *env, 
ppcemb_tlb_t *tlb,
 return -1;
 }
 
+if (FIELD_EX64(env->msr, MSR, PR)) {
+prot2 = tlb->prot & 0xF;
+} else {
+prot2 = (tlb->prot >> 4) & 0xF;
+}
 *prot = prot2;
 if (prot2 & prot_for_access_type(access_type)) {
 qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
-- 
2.30.9




[PATCH v2 04/28] target/ppc: Remove unused helper

2024-05-01 Thread BALATON Zoltan
The helper_rac function is defined but not used, remove it.

Fixes: 005b69fdcc (target/ppc: Remove PowerPC 601 CPUs)
Signed-off-by: BALATON Zoltan 
---
 target/ppc/helper.h |  2 --
 target/ppc/mmu_helper.c | 24 
 2 files changed, 26 deletions(-)

diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 86f97ee1e7..f769e01c3d 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -700,8 +700,6 @@ DEF_HELPER_2(book3s_msgclr, void, env, tl)
 
 DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32)
 #if !defined(CONFIG_USER_ONLY)
-DEF_HELPER_2(rac, tl, env, tl)
-
 DEF_HELPER_2(load_dcr, tl, env, tl)
 DEF_HELPER_3(store_dcr, void, env, tl, tl)
 #endif
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index c071b4d5e2..817836b731 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -595,30 +595,6 @@ void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
 do_6xx_tlb(env, EPN, 1);
 }
 
-/*/
-/* PowerPC 601 specific instructions (POWER bridge) */
-
-target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
-{
-mmu_ctx_t ctx;
-int nb_BATs;
-target_ulong ret = 0;
-
-/*
- * We don't have to generate many instances of this instruction,
- * as rac is supervisor only.
- *
- * XXX: FIX THIS: Pretend we have no BAT
- */
-nb_BATs = env->nb_BATs;
-env->nb_BATs = 0;
-if (get_physical_address_wtlb(env, &ctx, addr, 0, ACCESS_INT, 0) == 0) {
-ret = ctx.raddr;
-}
-env->nb_BATs = nb_BATs;
-return ret;
-}
-
 static inline target_ulong booke_tlb_to_page_size(int size)
 {
 return 1024 << (2 * size);
-- 
2.30.9




[PATCH v2 19/28] target/ppc/mmu_common.c: Replace hard coded constants in ppc_jumbo_xlate()

2024-05-01 Thread BALATON Zoltan
The "2" in booke206_update_mas_tlb_miss() call corresponds to
MMU_INST_FETCH which is the value of access_type in this branch;
mmubooke206_esr() only checks for MMU_DATA_STORE and it's called from
code access so using MMU_DATA_LOAD here seems wrong so replace it with
access_type here as well that yields the same result. This also makes
these calls the same as the data access branch further down.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 2487b4deff..762b13805b 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -1288,13 +1288,13 @@ static bool ppc_jumbo_xlate(PowerPCCPU *cpu, vaddr 
eaddr,
 env->spr[SPR_40x_ESR] = 0x;
 break;
 case POWERPC_MMU_BOOKE206:
-booke206_update_mas_tlb_miss(env, eaddr, 2, mmu_idx);
+booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx);
 /* fall through */
 case POWERPC_MMU_BOOKE:
 cs->exception_index = POWERPC_EXCP_ITLB;
 env->error_code = 0;
 env->spr[SPR_BOOKE_DEAR] = eaddr;
-env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 
MMU_DATA_LOAD);
+env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 
access_type);
 break;
 case POWERPC_MMU_REAL:
 cpu_abort(cs, "PowerPC in real mode should never raise "
-- 
2.30.9




[PATCH v2 11/28] target/ppc/mmu_common.c: Rename get_bat_6xx_tlb()

2024-05-01 Thread BALATON Zoltan
Rename to ppc6xx_tlb_get_bat() to match other similar names in the
same file.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index ef1669b01d..a069e4083f 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -288,8 +288,8 @@ static inline void bat_size_prot(CPUPPCState *env, 
target_ulong *blp,
 *protp = prot;
 }
 
-static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
-   target_ulong virtual, MMUAccessType access_type)
+static int ppc6xx_tlb_get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
+  target_ulong virtual, MMUAccessType access_type)
 {
 target_ulong *BATlt, *BATut, *BATu, *BATl;
 target_ulong BEPIl, BEPIu, bl;
@@ -371,7 +371,7 @@ static int mmu6xx_get_physical_address(CPUPPCState *env, 
mmu_ctx_t *ctx,
 
 /* First try to find a BAT entry if there are any */
 if (env->nb_BATs != 0) {
-ret = get_bat_6xx_tlb(env, ctx, eaddr, access_type);
+ret = ppc6xx_tlb_get_bat(env, ctx, eaddr, access_type);
 }
 if (ret >= 0) {
 return ret;
-- 
2.30.9




[PATCH v2 24/28] target/ppc/mmu_common.c: Remove BookE handling from get_physical_address_wtlb()

2024-05-01 Thread BALATON Zoltan
This function is no longer called for BookE MMU model so remove parts
related to it. This has uncovered a few may be used uninitialised
warnings that are also fixed.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 25 +
 1 file changed, 5 insertions(+), 20 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index a1f98f8de4..d61c41d8c9 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -684,12 +684,10 @@ static int mmubooke_get_physical_address(CPUPPCState 
*env, mmu_ctx_t *ctx,
 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address,
  access_type, i);
 if (ret != -1) {
-if (ret >= 0) {
-ctx->raddr = raddr;
-}
 break;
 }
 }
+ctx->raddr = raddr;
 qemu_log_mask(CPU_LOG_MMU,
   "%s: access %s " TARGET_FMT_lx " => " HWADDR_FMT_plx
   " %d %d\n", __func__, ret < 0 ? "refused" : "granted",
@@ -897,9 +895,6 @@ static int mmubooke206_get_physical_address(CPUPPCState 
*env, mmu_ctx_t *ctx,
 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
 access_type, mmu_idx);
 if (ret != -1) {
-if (ret >= 0) {
-ctx->raddr = raddr;
-}
 goto found_tlb;
 }
 }
@@ -907,6 +902,7 @@ static int mmubooke206_get_physical_address(CPUPPCState 
*env, mmu_ctx_t *ctx,
 
 found_tlb:
 
+ctx->raddr = raddr;
 qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => "
   HWADDR_FMT_plx " %d %d\n", __func__,
   ret < 0 ? "refused" : "granted", address, raddr,
@@ -1163,20 +1159,9 @@ static int get_physical_address_wtlb(CPUPPCState *env, 
mmu_ctx_t *ctx,
  MMUAccessType access_type, int type,
  int mmu_idx)
 {
-bool real_mode;
-
-if (env->mmu_model == POWERPC_MMU_BOOKE) {
-return mmubooke_get_physical_address(env, ctx, eaddr, access_type);
-} else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
-return mmubooke206_get_physical_address(env, ctx, eaddr, access_type,
-mmu_idx);
-}
-
-real_mode = (type == ACCESS_CODE) ? !FIELD_EX64(env->msr, MSR, IR)
-  : !FIELD_EX64(env->msr, MSR, DR);
-if (real_mode && (env->mmu_model == POWERPC_MMU_SOFT_6xx ||
-  env->mmu_model == POWERPC_MMU_SOFT_4xx ||
-  env->mmu_model == POWERPC_MMU_REAL)) {
+bool real_mode = (type == ACCESS_CODE) ? !FIELD_EX64(env->msr, MSR, IR)
+   : !FIELD_EX64(env->msr, MSR, DR);
+if (real_mode) {
 memset(ctx, 0, sizeof(*ctx));
 ctx->raddr = eaddr;
 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-- 
2.30.9




[PATCH v2 17/28] target/ppc/mmu_common.c: Fix misindented qemu_log_mask() calls

2024-05-01 Thread BALATON Zoltan
Fix several qemu_log_mask() calls that are misindented.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 42 -
 1 file changed, 20 insertions(+), 22 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index ebf18a751c..28847c32f2 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -297,8 +297,8 @@ static int ppc6xx_tlb_get_bat(CPUPPCState *env, mmu_ctx_t 
*ctx,
 int ret = -1;
 bool ifetch = access_type == MMU_INST_FETCH;
 
- qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
- ifetch ? 'I' : 'D', virtual);
+qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
+  ifetch ? 'I' : 'D', virtual);
 if (ifetch) {
 BATlt = env->IBAT[1];
 BATut = env->IBAT[0];
@@ -312,9 +312,9 @@ static int ppc6xx_tlb_get_bat(CPUPPCState *env, mmu_ctx_t 
*ctx,
 BEPIu = *BATu & 0xF000;
 BEPIl = *BATu & 0x0FFE;
 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
- qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx " BATu "
-   TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n", __func__,
-   ifetch ? 'I' : 'D', i, virtual, *BATu, *BATl);
+qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx " BATu "
+  TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n", __func__,
+  ifetch ? 'I' : 'D', i, virtual, *BATu, *BATl);
 if ((virtual & 0xF000) == BEPIu &&
 ((virtual & 0x0FFE) & ~bl) == BEPIl) {
 /* BAT matches */
@@ -346,12 +346,11 @@ static int ppc6xx_tlb_get_bat(CPUPPCState *env, mmu_ctx_t 
*ctx,
 BEPIu = *BATu & 0xF000;
 BEPIl = *BATu & 0x0FFE;
 bl = (*BATu & 0x1FFC) << 15;
- qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v "
-   TARGET_FMT_lx " BATu " TARGET_FMT_lx
-   " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
-   TARGET_FMT_lx " " TARGET_FMT_lx "\n",
-   __func__, ifetch ? 'I' : 'D', i, virtual,
-   *BATu, *BATl, BEPIu, BEPIl, bl);
+qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx
+  " BATu " TARGET_FMT_lx " BATl " TARGET_FMT_lx
+  "\n\t" TARGET_FMT_lx " " TARGET_FMT_lx " "
+  TARGET_FMT_lx "\n", __func__, ifetch ? 'I' : 'D',
+  i, virtual, *BATu, *BATl, BEPIu, BEPIl, bl);
 }
 }
 }
@@ -400,9 +399,8 @@ static int mmu6xx_get_physical_address(CPUPPCState *env, 
mmu_ctx_t *ctx,
 hash = vsid ^ pgidx;
 ctx->ptem = (vsid << 7) | (pgidx >> 10);
 
-qemu_log_mask(CPU_LOG_MMU,
-"pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
-ctx->key, ds, ctx->nx, vsid);
+qemu_log_mask(CPU_LOG_MMU, "pte segment: key=%d ds %d nx %d vsid "
+  TARGET_FMT_lx "\n", ctx->key, ds, ctx->nx, vsid);
 ret = -1;
 if (!ds) {
 /* Check if instruction fetch is allowed, if needed */
@@ -599,9 +597,9 @@ static int mmu40x_get_physical_address(CPUPPCState *env, 
mmu_ctx_t *ctx,
 return 0;
 }
 }
- qemu_log_mask(CPU_LOG_MMU, "%s: access refused " TARGET_FMT_lx
-   " => " HWADDR_FMT_plx
-   " %d %d\n", __func__, address, raddr, ctx->prot, ret);
+qemu_log_mask(CPU_LOG_MMU, "%s: access refused " TARGET_FMT_lx
+  " => " HWADDR_FMT_plx " %d %d\n",
+  __func__, address, raddr, ctx->prot, ret);
 
 return ret;
 }
@@ -713,11 +711,11 @@ int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, 
hwaddr *raddrp,
 }
 
 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
- qemu_log_mask(CPU_LOG_MMU, "%s: TLB ADDR=0x" TARGET_FMT_lx
-   " PID=0x%x MAS1=0x%x MAS2=0x%" PRIx64 " mask=0x%"
-   HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%" PRIx32 "\n",
-   __func__, address, pid, tlb->mas1, tlb->mas2, mask,
-   tlb->mas7_3, tlb->mas8);
+qemu_log_mask(CPU_LOG_MMU, "%s: TLB ADDR=0x" TARGET_FMT_lx
+  " PID=0x%x MAS1=0x%x MAS2=0x%" PRIx64 " mask=0x%"
+  HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%" PRIx32 "\n",
+  __func__, address, pid, tlb->mas1, tlb->mas2, mask,
+  tlb->mas7_3, tlb->mas8);
 
 /* Check PID */
 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
-- 
2.30.9




[PATCH v2 02/28] target/ppc: Move patching nip from exception handler to helper_scv

2024-05-01 Thread BALATON Zoltan
From: Nicholas Piggin 

Unlike sc, for scv a facility unavailable interrupt must be generated
if FSCR[SCV]=0 so we can't raise the exception with nip set to next
instruction but we can move advancing nip if the FSCR check passes to
helper_scv so the exception handler does not need to change it.

[balaton: added commit message]
Signed-off-by: BALATON Zoltan 
---
 target/ppc/excp_helper.c | 2 +-
 target/ppc/translate.c   | 6 +-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 92fe535815..5aa84bccd2 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1415,7 +1415,6 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
 case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception */
 lev = env->error_code;
 dump_syscall(env);
-env->nip += 4;
 new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
 
@@ -2524,6 +2523,7 @@ void helper_ppc_maybe_interrupt(CPUPPCState *env)
 void helper_scv(CPUPPCState *env, uint32_t lev)
 {
 if (env->spr[SPR_FSCR] & (1ull << FSCR_SCV)) {
+env->nip += 4;
 raise_exception_err(env, POWERPC_EXCP_SYSCALL_VECTORED, lev);
 } else {
 raise_exception_err(env, POWERPC_EXCP_FU, FSCR_IC_SCV);
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index e112c44a02..1d4e9f0679 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -4493,7 +4493,11 @@ static void gen_scv(DisasContext *ctx)
 {
 uint32_t lev = (ctx->opcode >> 5) & 0x7F;
 
-/* Set the PC back to the faulting instruction. */
+/*
+ * Set the PC back to the scv instruction (unlike sc), because a facility
+ * unavailable interrupt must be generated if FSCR[SCV]=0. The helper
+ * advances nip if the FSCR check passes.
+ */
 gen_update_nip(ctx, ctx->cia);
 gen_helper_scv(tcg_env, tcg_constant_i32(lev));
 
-- 
2.30.9




[PATCH v2 13/28] target/ppc/mmu_common.c: Split off real mode cases in get_physical_address_wtlb()

2024-05-01 Thread BALATON Zoltan
The real mode handling is identical in the remaining switch cases.
Split off these common real mode cases into a separate conditional to
leave only the else branches in the switch that are different.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 34 +-
 1 file changed, 9 insertions(+), 25 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 24a9b9ef19..3132030baa 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -1188,7 +1188,6 @@ int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t 
*ctx,
  MMUAccessType access_type, int type,
  int mmu_idx)
 {
-int ret = -1;
 bool real_mode;
 
 if (env->mmu_model == POWERPC_MMU_BOOKE) {
@@ -1200,38 +1199,23 @@ int get_physical_address_wtlb(CPUPPCState *env, 
mmu_ctx_t *ctx,
 
 real_mode = (type == ACCESS_CODE) ? !FIELD_EX64(env->msr, MSR, IR)
   : !FIELD_EX64(env->msr, MSR, DR);
+if (real_mode && (env->mmu_model == POWERPC_MMU_SOFT_6xx ||
+  env->mmu_model == POWERPC_MMU_SOFT_4xx ||
+  env->mmu_model == POWERPC_MMU_REAL)) {
+return check_physical(env, ctx, eaddr, access_type);
+}
 
 switch (env->mmu_model) {
 case POWERPC_MMU_SOFT_6xx:
-if (real_mode) {
-ret = check_physical(env, ctx, eaddr, access_type);
-} else {
-ret = mmu6xx_get_physical_address(env, ctx, eaddr, access_type,
-  type);
-}
-break;
-
+return mmu6xx_get_physical_address(env, ctx, eaddr, access_type, type);
 case POWERPC_MMU_SOFT_4xx:
-if (real_mode) {
-ret = check_physical(env, ctx, eaddr, access_type);
-} else {
-ret = mmu40x_get_physical_address(env, ctx, eaddr, access_type);
-}
-break;
+return mmu40x_get_physical_address(env, ctx, eaddr, access_type);
 case POWERPC_MMU_REAL:
-if (real_mode) {
-ret = check_physical(env, ctx, eaddr, access_type);
-} else {
-cpu_abort(env_cpu(env),
-  "PowerPC in real mode do not do any translation\n");
-}
-return -1;
+cpu_abort(env_cpu(env),
+  "PowerPC in real mode do not do any translation\n");
 default:
 cpu_abort(env_cpu(env), "Unknown or invalid MMU model\n");
-return -1;
 }
-
-return ret;
 }
 
 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong 
address,
-- 
2.30.9




[PATCH v2 16/28] target/ppc/mmu_common.c: Simplify mmubooke206_get_physical_address()

2024-05-01 Thread BALATON Zoltan
This function is similar to mmubooke_get_physical_address() and can be
simplified the same way.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 28 ++--
 1 file changed, 10 insertions(+), 18 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 760e4072b2..ebf18a751c 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -872,15 +872,11 @@ static int mmubooke206_get_physical_address(CPUPPCState 
*env, mmu_ctx_t *ctx,
 int mmu_idx)
 {
 ppcmas_tlb_t *tlb;
-hwaddr raddr;
-int i, j, ret;
-
-ret = -1;
-raddr = (hwaddr)-1ULL;
+hwaddr raddr = (hwaddr)-1ULL;
+int i, j, ways, ret = -1;
 
 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
-int ways = booke206_tlb_ways(env, i);
-
+ways = booke206_tlb_ways(env, i);
 for (j = 0; j < ways; j++) {
 tlb = booke206_get_tlbm(env, i, address, j);
 if (!tlb) {
@@ -889,6 +885,9 @@ static int mmubooke206_get_physical_address(CPUPPCState 
*env, mmu_ctx_t *ctx,
 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
 access_type, mmu_idx);
 if (ret != -1) {
+if (ret >= 0) {
+ctx->raddr = raddr;
+}
 goto found_tlb;
 }
 }
@@ -896,17 +895,10 @@ static int mmubooke206_get_physical_address(CPUPPCState 
*env, mmu_ctx_t *ctx,
 
 found_tlb:
 
-if (ret >= 0) {
-ctx->raddr = raddr;
- qemu_log_mask(CPU_LOG_MMU, "%s: access granted " TARGET_FMT_lx
-   " => " HWADDR_FMT_plx " %d %d\n", __func__, address,
-   ctx->raddr, ctx->prot, ret);
-} else {
- qemu_log_mask(CPU_LOG_MMU, "%s: access refused " TARGET_FMT_lx
-   " => " HWADDR_FMT_plx " %d %d\n", __func__, address,
-   raddr, ctx->prot, ret);
-}
-
+qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => "
+  HWADDR_FMT_plx " %d %d\n", __func__,
+  ret < 0 ? "refused" : "granted", address, raddr,
+  ctx->prot, ret);
 return ret;
 }
 
-- 
2.30.9




[PATCH v2 27/28] target/ppc: Remove id_tlbs flag from CPU env

2024-05-01 Thread BALATON Zoltan
This flag for split instruction/data TLBs is only set for 6xx soft TLB
MMU model and not used otherwise so no need to have a separate flag
for that.

Signed-off-by: BALATON Zoltan 
---
 hw/ppc/pegasos2.c|  2 +-
 target/ppc/cpu.h |  1 -
 target/ppc/cpu_init.c| 19 +--
 target/ppc/helper_regs.c |  1 -
 target/ppc/mmu_common.c  | 10 ++
 target/ppc/mmu_helper.c  | 12 ++--
 6 files changed, 10 insertions(+), 35 deletions(-)

diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
index 04d6decb2b..dfc6fab180 100644
--- a/hw/ppc/pegasos2.c
+++ b/hw/ppc/pegasos2.c
@@ -984,7 +984,7 @@ static void *build_fdt(MachineState *machine, int *fdt_size)
   cpu->env.icache_line_size);
 qemu_fdt_setprop_cell(fdt, cp, "i-cache-line-size",
   cpu->env.icache_line_size);
-if (cpu->env.id_tlbs) {
+if (cpu->env.tlb_type == TLB_6XX) {
 qemu_fdt_setprop_cell(fdt, cp, "i-tlb-sets", cpu->env.nb_ways);
 qemu_fdt_setprop_cell(fdt, cp, "i-tlb-size", cpu->env.tlb_per_way);
 qemu_fdt_setprop_cell(fdt, cp, "d-tlb-sets", cpu->env.nb_ways);
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 0ac55d6b25..21e12a4f0d 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1260,7 +1260,6 @@ struct CPUArchState {
 int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */
 int nb_ways; /* Number of ways in the TLB set */
 int last_way;/* Last used way used to allocate TLB in a LRU way */
-int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */
 int nb_pids; /* Number of available PID registers */
 int tlb_type;/* Type of TLB we're dealing with */
 ppc_tlb_t tlb;   /* TLB is optional. Allocate them only if needed */
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index c11a69fd90..07ad788e54 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -2117,7 +2117,6 @@ static void init_proc_405(CPUPPCState *env)
 #if !defined(CONFIG_USER_ONLY)
 env->nb_tlb = 64;
 env->nb_ways = 1;
-env->id_tlbs = 0;
 env->tlb_type = TLB_EMB;
 #endif
 init_excp_4xx(env);
@@ -2190,7 +2189,6 @@ static void init_proc_440EP(CPUPPCState *env)
 #if !defined(CONFIG_USER_ONLY)
 env->nb_tlb = 64;
 env->nb_ways = 1;
-env->id_tlbs = 0;
 env->tlb_type = TLB_EMB;
 #endif
 init_excp_BookE(env);
@@ -2288,7 +2286,6 @@ static void init_proc_440GP(CPUPPCState *env)
 #if !defined(CONFIG_USER_ONLY)
 env->nb_tlb = 64;
 env->nb_ways = 1;
-env->id_tlbs = 0;
 env->tlb_type = TLB_EMB;
 #endif
 init_excp_BookE(env);
@@ -2362,7 +2359,6 @@ static void init_proc_440x5(CPUPPCState *env)
 #if !defined(CONFIG_USER_ONLY)
 env->nb_tlb = 64;
 env->nb_ways = 1;
-env->id_tlbs = 0;
 env->tlb_type = TLB_EMB;
 #endif
 init_excp_BookE(env);
@@ -2724,7 +2720,6 @@ static void init_proc_e200(CPUPPCState *env)
 #if !defined(CONFIG_USER_ONLY)
 env->nb_tlb = 64;
 env->nb_ways = 1;
-env->id_tlbs = 0;
 env->tlb_type = TLB_EMB;
 #endif
 init_excp_e200(env, 0xUL);
@@ -2843,7 +2838,6 @@ static void init_proc_e500(CPUPPCState *env, int version)
 /* Memory management */
 env->nb_pids = 3;
 env->nb_ways = 2;
-env->id_tlbs = 0;
 switch (version) {
 case fsl_e500v1:
 tlbncfg[0] = register_tlbncfg(2, 1, 1, 0, 256);
@@ -6800,20 +6794,17 @@ static void init_ppc_proc(PowerPCCPU *cpu)
 }
 /* Allocate TLBs buffer when needed */
 #if !defined(CONFIG_USER_ONLY)
-if (env->nb_tlb != 0) {
-int nb_tlb = env->nb_tlb;
-if (env->id_tlbs != 0) {
-nb_tlb *= 2;
-}
+if (env->nb_tlb) {
 switch (env->tlb_type) {
 case TLB_6XX:
-env->tlb.tlb6 = g_new0(ppc6xx_tlb_t, nb_tlb);
+/* 6xx has separate TLBs for instructions and data hence times 2 */
+env->tlb.tlb6 = g_new0(ppc6xx_tlb_t, 2 * env->nb_tlb);
 break;
 case TLB_EMB:
-env->tlb.tlbe = g_new0(ppcemb_tlb_t, nb_tlb);
+env->tlb.tlbe = g_new0(ppcemb_tlb_t, env->nb_tlb);
 break;
 case TLB_MAS:
-env->tlb.tlbm = g_new0(ppcmas_tlb_t, nb_tlb);
+env->tlb.tlbm = g_new0(ppcmas_tlb_t, env->nb_tlb);
 break;
 }
 /* Pre-compute some useful values */
diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
index 25258986e3..ed583fe9b3 100644
--- a/target/ppc/helper_regs.c
+++ b/target/ppc/helper_regs.c
@@ -693,7 +693,6 @@ void register_6xx_7xx_soft_tlb(CPUPPCState *env, int 
nb_tlbs, int nb_ways)
 #if !defined(CONFIG_USER_ONLY)
 env->nb_tlb = nb_tlbs;
 env->nb_ways = nb_ways;
-env->id_tlbs = 1;
 env->tlb_type = TLB_6XX;
 spr_register(env, SPR_DMISS, "DMISS",
  SPR_NOACCESS, SPR_NOACCESS,
diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 204b8af455..a0b34f9637 100644

[PATCH v2 14/28] target/ppc/mmu_common.c: Inline and remove check_physical()

2024-05-01 Thread BALATON Zoltan
This function just does two assignments and and unnecessary check that
is always true so inline it in the only caller left and remove it.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 26 +++---
 1 file changed, 3 insertions(+), 23 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 3132030baa..fab86a8f3e 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -1161,28 +1161,6 @@ void dump_mmu(CPUPPCState *env)
 }
 }
 
-static int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr,
-  MMUAccessType access_type)
-{
-ctx->raddr = eaddr;
-ctx->prot = PAGE_READ | PAGE_EXEC;
-
-switch (env->mmu_model) {
-case POWERPC_MMU_SOFT_6xx:
-case POWERPC_MMU_SOFT_4xx:
-case POWERPC_MMU_REAL:
-case POWERPC_MMU_BOOKE:
-ctx->prot |= PAGE_WRITE;
-break;
-
-default:
-/* Caller's checks mean we should never get here for other models */
-g_assert_not_reached();
-}
-
-return 0;
-}
-
 int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx,
  target_ulong eaddr,
  MMUAccessType access_type, int type,
@@ -1202,7 +1180,9 @@ int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t 
*ctx,
 if (real_mode && (env->mmu_model == POWERPC_MMU_SOFT_6xx ||
   env->mmu_model == POWERPC_MMU_SOFT_4xx ||
   env->mmu_model == POWERPC_MMU_REAL)) {
-return check_physical(env, ctx, eaddr, access_type);
+ctx->raddr = eaddr;
+ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+return 0;
 }
 
 switch (env->mmu_model) {
-- 
2.30.9




[PATCH v2 08/28] target/ppc/mmu_common.c: Simplify checking for real mode

2024-05-01 Thread BALATON Zoltan
In get_physical_address_wtlb() the real_mode flag depends on either
the MSR[IR] or MSR[DR] bit depending on access_type. Extract just the
needed bit in a more straight forward way instead of doing unnecessary
computation.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 74c3b814c9..45b6501ecb 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -1183,8 +1183,10 @@ int get_physical_address_wtlb(CPUPPCState *env, 
mmu_ctx_t *ctx,
  int mmu_idx)
 {
 int ret = -1;
-bool real_mode = (type == ACCESS_CODE && !FIELD_EX64(env->msr, MSR, IR)) ||
- (type != ACCESS_CODE && !FIELD_EX64(env->msr, MSR, DR));
+bool real_mode;
+
+real_mode = (type == ACCESS_CODE) ? !FIELD_EX64(env->msr, MSR, IR)
+  : !FIELD_EX64(env->msr, MSR, DR);
 
 switch (env->mmu_model) {
 case POWERPC_MMU_SOFT_6xx:
-- 
2.30.9




[PATCH v2 06/28] target/ppc/mmu_common.c: Move calculation of a value closer to its usage

2024-05-01 Thread BALATON Zoltan
In mmubooke206_check_tlb() prot2 is calculated first but only used
after an unrelated check that can return before tha value is used.
Move the calculation after the check, closer to where it is used, to
keep them together and avoid computing it when not needed.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 25 -
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 168ff842a5..b0aca8ec02 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -828,6 +828,18 @@ static int mmubooke206_check_tlb(CPUPPCState *env, 
ppcmas_tlb_t *tlb,
 
 found_tlb:
 
+/* Check the address space and permissions */
+if (access_type == MMU_INST_FETCH) {
+/* There is no way to fetch code using epid load */
+assert(!use_epid);
+as = FIELD_EX64(env->msr, MSR, IR);
+}
+
+if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
+qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
+return -1;
+}
+
 if (pr) {
 if (tlb->mas7_3 & MAS3_UR) {
 prot2 |= PAGE_READ;
@@ -849,19 +861,6 @@ found_tlb:
 prot2 |= PAGE_EXEC;
 }
 }
-
-/* Check the address space and permissions */
-if (access_type == MMU_INST_FETCH) {
-/* There is no way to fetch code using epid load */
-assert(!use_epid);
-as = FIELD_EX64(env->msr, MSR, IR);
-}
-
-if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
-qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
-return -1;
-}
-
 *prot = prot2;
 if (prot2 & prot_for_access_type(access_type)) {
 qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
-- 
2.30.9




[PATCH v2 15/28] target/ppc/mmu_common.c: Simplify mmubooke_get_physical_address()

2024-05-01 Thread BALATON Zoltan
Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 25 +
 1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index fab86a8f3e..760e4072b2 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -665,31 +665,24 @@ static int mmubooke_get_physical_address(CPUPPCState 
*env, mmu_ctx_t *ctx,
  MMUAccessType access_type)
 {
 ppcemb_tlb_t *tlb;
-hwaddr raddr;
-int i, ret;
+hwaddr raddr = (hwaddr)-1ULL;
+int i, ret = -1;
 
-ret = -1;
-raddr = (hwaddr)-1ULL;
 for (i = 0; i < env->nb_tlb; i++) {
 tlb = &env->tlb.tlbe[i];
 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address,
  access_type, i);
 if (ret != -1) {
+if (ret >= 0) {
+ctx->raddr = raddr;
+}
 break;
 }
 }
-
-if (ret >= 0) {
-ctx->raddr = raddr;
-qemu_log_mask(CPU_LOG_MMU, "%s: access granted " TARGET_FMT_lx
-  " => " HWADDR_FMT_plx " %d %d\n", __func__,
-  address, ctx->raddr, ctx->prot, ret);
-} else {
- qemu_log_mask(CPU_LOG_MMU, "%s: access refused " TARGET_FMT_lx
-   " => " HWADDR_FMT_plx " %d %d\n", __func__,
-   address, raddr, ctx->prot, ret);
-}
-
+qemu_log_mask(CPU_LOG_MMU,
+  "%s: access %s " TARGET_FMT_lx " => " HWADDR_FMT_plx
+  " %d %d\n", __func__, ret < 0 ? "refused" : "granted",
+  address, raddr, ctx->prot, ret);
 return ret;
 }
 
-- 
2.30.9




[PATCH v2 23/28] target/ppc/mmu_common.c: Split off BookE handling from ppc_jumbo_xlate()

2024-05-01 Thread BALATON Zoltan
Introduce ppc_booke_xlate() to handle BookE and BookE 2.06 cases to
reduce ppc_jumbo_xlate() further.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 180 ++--
 1 file changed, 138 insertions(+), 42 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 0ce5c1e841..a1f98f8de4 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -1250,6 +1250,137 @@ static void booke206_update_mas_tlb_miss(CPUPPCState 
*env, target_ulong address,
 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
 }
 
+static bool ppc_booke_xlate(PowerPCCPU *cpu, vaddr eaddr,
+MMUAccessType access_type,
+hwaddr *raddrp, int *psizep, int *protp,
+int mmu_idx, bool guest_visible)
+{
+CPUState *cs = CPU(cpu);
+CPUPPCState *env = &cpu->env;
+mmu_ctx_t ctx;
+int ret;
+
+if (env->mmu_model == POWERPC_MMU_BOOKE206) {
+ret = mmubooke206_get_physical_address(env, &ctx, eaddr, access_type,
+   mmu_idx);
+} else {
+ret = mmubooke_get_physical_address(env, &ctx, eaddr, access_type);
+}
+if (ret == 0) {
+*raddrp = ctx.raddr;
+*protp = ctx.prot;
+*psizep = TARGET_PAGE_BITS;
+return true;
+} else if (!guest_visible) {
+return false;
+}
+
+log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
+if (access_type == MMU_INST_FETCH) {
+switch (ret) {
+case -1:
+/* No matches in page tables or TLB */
+switch (env->mmu_model) {
+case POWERPC_MMU_BOOKE206:
+booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx);
+/* fall through */
+case POWERPC_MMU_BOOKE:
+cs->exception_index = POWERPC_EXCP_ITLB;
+env->error_code = 0;
+env->spr[SPR_BOOKE_DEAR] = eaddr;
+env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 
access_type);
+break;
+default:
+g_assert_not_reached();
+}
+break;
+case -2:
+/* Access rights violation */
+cs->exception_index = POWERPC_EXCP_ISI;
+env->error_code = 0;
+break;
+case -3:
+/* No execute protection violation */
+cs->exception_index = POWERPC_EXCP_ISI;
+env->spr[SPR_BOOKE_ESR] = 0;
+env->error_code = 0;
+break;
+case -4:
+/* Direct store exception */
+/* No code fetch is allowed in direct-store areas */
+cs->exception_index = POWERPC_EXCP_ISI;
+env->error_code = 0;
+break;
+}
+} else {
+switch (ret) {
+case -1:
+/* No matches in page tables or TLB */
+switch (env->mmu_model) {
+case POWERPC_MMU_BOOKE206:
+booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx);
+/* fall through */
+case POWERPC_MMU_BOOKE:
+cs->exception_index = POWERPC_EXCP_DTLB;
+env->error_code = 0;
+env->spr[SPR_BOOKE_DEAR] = eaddr;
+env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 
access_type);
+break;
+default:
+g_assert_not_reached();
+}
+break;
+case -2:
+/* Access rights violation */
+cs->exception_index = POWERPC_EXCP_DSI;
+env->error_code = 0;
+env->spr[SPR_BOOKE_DEAR] = eaddr;
+env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
+break;
+case -4:
+/* Direct store exception */
+switch (env->access_type) {
+case ACCESS_FLOAT:
+/* Floating point load/store */
+cs->exception_index = POWERPC_EXCP_ALIGN;
+env->error_code = POWERPC_EXCP_ALIGN_FP;
+env->spr[SPR_DAR] = eaddr;
+break;
+case ACCESS_RES:
+/* lwarx, ldarx or stwcx. */
+cs->exception_index = POWERPC_EXCP_DSI;
+env->error_code = 0;
+env->spr[SPR_DAR] = eaddr;
+if (access_type == MMU_DATA_STORE) {
+env->spr[SPR_DSISR] = 0x0600;
+} else {
+env->spr[SPR_DSISR] = 0x0400;
+}
+break;
+case ACCESS_EXT:
+/* eciwx or ecowx */
+cs->exception_index = POWERPC_EXCP_DSI;
+env->error_code = 0;
+env->spr[SPR_DAR] = eaddr;
+if (access_type == MMU_DATA_STORE) {
+env->spr[SPR_DSISR] = 0x0610;
+} else {
+

[PATCH v2 00/28] Misc PPC exception and BookE MMU clean ups

2024-05-01 Thread BALATON Zoltan
This series does some further clean up mostly around BookE MMU to
untangle it from other MMU models. It also contains some other changes
that I've come up with while working on this. The first 3 patches are
from the last exception handling clean up series that were dropped due
to some error on CI but I'm not sure if that was because of some CI
infrastructure problem or some problem with the patches as the error
did not make much sense. So these patches are only rebased now, I made
no other change to them until the issue is understood better. The rest
are new patches I've added since tha last series. Please review.

v2:
- Fix user mode issue in patch 1 by keeping old behaviour for user mode
- Add some more MMU clean up patches

Regards,
BALATON Zoltan

BALATON Zoltan (28):
  target/ppc: Fix gen_sc to use correct nip
  target/ppc: Move patching nip from exception handler to helper_scv
  target/ppc: Simplify syscall exception handlers
  target/ppc: Remove unused helper
  target/ppc/mmu_common.c: Move calculation of a value closer to its
usage
  target/ppc/mmu_common.c: Move calculation of a value closer to its
usage
  target/ppc/mmu_common.c: Remove unneeded local variable
  target/ppc/mmu_common.c: Simplify checking for real mode
  target/ppc/mmu_common.c: Drop cases for unimplemented MPC8xx MMU
  target/ppc/mmu_common.c: Introduce mmu6xx_get_physical_address()
  target/ppc/mmu_common.c: Rename get_bat_6xx_tlb()
  target/ppc/mmu_common.c: Split out BookE cases before checking real
mode
  target/ppc/mmu_common.c: Split off real mode cases in
get_physical_address_wtlb()
  target/ppc/mmu_common.c: Inline and remove check_physical()
  target/ppc/mmu_common.c: Simplify mmubooke_get_physical_address()
  target/ppc/mmu_common.c: Simplify mmubooke206_get_physical_address()
  target/ppc/mmu_common.c: Fix misindented qemu_log_mask() calls
  target/ppc/mmu_common.c: Deindent ppc_jumbo_xlate()
  target/ppc/mmu_common.c: Replace hard coded constants in
ppc_jumbo_xlate()
  target/ppc/mmu_common.c: Make get_physical_address_wtlb() static
  target/ppc: Move mmu_ctx_t definition to mmu_common.c
  target/ppc: Remove ppc_hash32_pp_prot() and reuse common function
  target/ppc/mmu_common.c: Split off BookE handling from
ppc_jumbo_xlate()
  target/ppc/mmu_common.c: Remove BookE handling from
get_physical_address_wtlb()
  target/ppc/mmu_common.c: Simplify ppc_booke_xlate()
  target/ppc/mmu_common.c: Move BookE MMU functions together
  target/ppc: Remove id_tlbs flag from CPU env
  target/ppc: Split off common 4xx TLB init

 hw/ppc/pegasos2.c|   2 +-
 target/ppc/cpu.h |   1 -
 target/ppc/cpu_init.c|  65 ++--
 target/ppc/excp_helper.c |  67 +---
 target/ppc/helper.h  |   2 -
 target/ppc/helper_regs.c |   1 -
 target/ppc/internal.h|  19 +-
 target/ppc/mmu-hash32.c  |  47 +--
 target/ppc/mmu_common.c  | 792 +++
 target/ppc/mmu_helper.c  |  36 +-
 target/ppc/translate.c   |  21 +-
 11 files changed, 438 insertions(+), 615 deletions(-)

-- 
2.30.9




[PATCH v2 09/28] target/ppc/mmu_common.c: Drop cases for unimplemented MPC8xx MMU

2024-05-01 Thread BALATON Zoltan
The default case will catch this and abort the same way and there is
still a warning about it in ppc_tlb_invalidate_all() so drop these
from mmu_common.c to simplify this code.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 9 -
 1 file changed, 9 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 45b6501ecb..98730035b1 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -1218,10 +1218,6 @@ int get_physical_address_wtlb(CPUPPCState *env, 
mmu_ctx_t *ctx,
 ret = mmubooke206_get_physical_address(env, ctx, eaddr, access_type,
mmu_idx);
 break;
-case POWERPC_MMU_MPC8xx:
-/* XXX: TODO */
-cpu_abort(env_cpu(env), "MPC8xx MMU model is not implemented\n");
-break;
 case POWERPC_MMU_REAL:
 if (real_mode) {
 ret = check_physical(env, ctx, eaddr, access_type);
@@ -1352,8 +1348,6 @@ static bool ppc_jumbo_xlate(PowerPCCPU *cpu, vaddr eaddr,
 env->spr[SPR_BOOKE_DEAR] = eaddr;
 env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 
MMU_DATA_LOAD);
 break;
-case POWERPC_MMU_MPC8xx:
-cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
 case POWERPC_MMU_REAL:
 cpu_abort(cs, "PowerPC in real mode should never raise "
   "any MMU exceptions\n");
@@ -1426,9 +1420,6 @@ static bool ppc_jumbo_xlate(PowerPCCPU *cpu, vaddr eaddr,
 env->spr[SPR_40x_ESR] = 0x;
 }
 break;
-case POWERPC_MMU_MPC8xx:
-/* XXX: TODO */
-cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
 case POWERPC_MMU_BOOKE206:
 booke206_update_mas_tlb_miss(env, eaddr, access_type, 
mmu_idx);
 /* fall through */
-- 
2.30.9




[PATCH v2 25/28] target/ppc/mmu_common.c: Simplify ppc_booke_xlate()

2024-05-01 Thread BALATON Zoltan
Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 147 +++-
 1 file changed, 56 insertions(+), 91 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index d61c41d8c9..b76611da80 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -1261,106 +1261,71 @@ static bool ppc_booke_xlate(PowerPCCPU *cpu, vaddr 
eaddr,
 }
 
 log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
+env->error_code = 0;
+if (env->mmu_model == POWERPC_MMU_BOOKE206 && ret == -1) {
+booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx);
+}
 if (access_type == MMU_INST_FETCH) {
-switch (ret) {
-case -1:
+if (ret == -1) {
 /* No matches in page tables or TLB */
-switch (env->mmu_model) {
-case POWERPC_MMU_BOOKE206:
-booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx);
-/* fall through */
-case POWERPC_MMU_BOOKE:
-cs->exception_index = POWERPC_EXCP_ITLB;
-env->error_code = 0;
-env->spr[SPR_BOOKE_DEAR] = eaddr;
-env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 
access_type);
-break;
-default:
-g_assert_not_reached();
-}
-break;
-case -2:
-/* Access rights violation */
-cs->exception_index = POWERPC_EXCP_ISI;
-env->error_code = 0;
-break;
-case -3:
-/* No execute protection violation */
-cs->exception_index = POWERPC_EXCP_ISI;
-env->spr[SPR_BOOKE_ESR] = 0;
-env->error_code = 0;
-break;
-case -4:
-/* Direct store exception */
-/* No code fetch is allowed in direct-store areas */
+cs->exception_index = POWERPC_EXCP_ITLB;
+env->spr[SPR_BOOKE_DEAR] = eaddr;
+env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
+} else {
 cs->exception_index = POWERPC_EXCP_ISI;
-env->error_code = 0;
-break;
-}
-} else {
-switch (ret) {
-case -1:
-/* No matches in page tables or TLB */
-switch (env->mmu_model) {
-case POWERPC_MMU_BOOKE206:
-booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx);
-/* fall through */
-case POWERPC_MMU_BOOKE:
-cs->exception_index = POWERPC_EXCP_DTLB;
-env->error_code = 0;
-env->spr[SPR_BOOKE_DEAR] = eaddr;
-env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 
access_type);
-break;
-default:
-g_assert_not_reached();
+if (ret == -3) {
+/* No execute protection violation */
+env->spr[SPR_BOOKE_ESR] = 0;
 }
+}
+return false;
+}
+
+switch (ret) {
+case -1:
+/* No matches in page tables or TLB */
+cs->exception_index = POWERPC_EXCP_DTLB;
+env->spr[SPR_BOOKE_DEAR] = eaddr;
+env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
+break;
+case -2:
+/* Access rights violation */
+cs->exception_index = POWERPC_EXCP_DSI;
+env->spr[SPR_BOOKE_DEAR] = eaddr;
+env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
+break;
+case -4:
+/* Direct store exception */
+env->spr[SPR_DAR] = eaddr;
+switch (env->access_type) {
+case ACCESS_FLOAT:
+/* Floating point load/store */
+cs->exception_index = POWERPC_EXCP_ALIGN;
+env->error_code = POWERPC_EXCP_ALIGN_FP;
 break;
-case -2:
-/* Access rights violation */
+case ACCESS_RES:
+/* lwarx, ldarx or stwcx. */
 cs->exception_index = POWERPC_EXCP_DSI;
-env->error_code = 0;
-env->spr[SPR_BOOKE_DEAR] = eaddr;
-env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
+if (access_type == MMU_DATA_STORE) {
+env->spr[SPR_DSISR] = 0x0600;
+} else {
+env->spr[SPR_DSISR] = 0x0400;
+}
 break;
-case -4:
-/* Direct store exception */
-switch (env->access_type) {
-case ACCESS_FLOAT:
-/* Floating point load/store */
-cs->exception_index = POWERPC_EXCP_ALIGN;
-env->error_code = POWERPC_EXCP_ALIGN_FP;
-env->spr[SPR_DAR] = eaddr;
-break;
-case ACCESS_RES:
-/* lwarx, ldarx or stwcx. */
-cs->exception_index = POWERPC_EXCP_DSI;
-env->error_code = 0;
-env->spr[SPR_DAR] = 

[PATCH v2 20/28] target/ppc/mmu_common.c: Make get_physical_address_wtlb() static

2024-05-01 Thread BALATON Zoltan
This function is not used from any other files so make it static and
fix the maybe used uninitialised warnings this has uncovered.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/internal.h   | 5 +
 target/ppc/mmu_common.c | 5 -
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 601c0b533f..7a99f08dc8 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -261,10 +261,7 @@ typedef struct mmu_ctx_t mmu_ctx_t;
 bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
   hwaddr *raddrp, int *psizep, int *protp,
   int mmu_idx, bool guest_visible);
-int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr,
- MMUAccessType access_type, int type,
- int mmu_idx);
+
 /* Software driven TLB helpers */
 int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
 int way, int is_code);
diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 762b13805b..4852cb5571 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -666,6 +666,7 @@ static int mmubooke_get_physical_address(CPUPPCState *env, 
mmu_ctx_t *ctx,
 hwaddr raddr = (hwaddr)-1ULL;
 int i, ret = -1;
 
+ctx->prot = 0;
 for (i = 0; i < env->nb_tlb; i++) {
 tlb = &env->tlb.tlbe[i];
 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address,
@@ -873,6 +874,7 @@ static int mmubooke206_get_physical_address(CPUPPCState 
*env, mmu_ctx_t *ctx,
 hwaddr raddr = (hwaddr)-1ULL;
 int i, j, ways, ret = -1;
 
+ctx->prot = 0;
 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
 ways = booke206_tlb_ways(env, i);
 for (j = 0; j < ways; j++) {
@@ -1144,7 +1146,7 @@ void dump_mmu(CPUPPCState *env)
 }
 }
 
-int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx,
+static int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx,
  target_ulong eaddr,
  MMUAccessType access_type, int type,
  int mmu_idx)
@@ -1163,6 +1165,7 @@ int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t 
*ctx,
 if (real_mode && (env->mmu_model == POWERPC_MMU_SOFT_6xx ||
   env->mmu_model == POWERPC_MMU_SOFT_4xx ||
   env->mmu_model == POWERPC_MMU_REAL)) {
+memset(ctx, 0, sizeof(*ctx));
 ctx->raddr = eaddr;
 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
 return 0;
-- 
2.30.9




[PATCH v2 22/28] target/ppc: Remove ppc_hash32_pp_prot() and reuse common function

2024-05-01 Thread BALATON Zoltan
The ppc_hash32_pp_prot() function in mmu-hash32.c is the same as
pp_check() in mmu_common.c. Rename the latter to ppc_pte_prot() and
merge with ppc_hash32_pp_prot() to remove duplicated code.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/internal.h   |  2 +-
 target/ppc/mmu-hash32.c | 47 +
 target/ppc/mmu_common.c | 19 +
 3 files changed, 12 insertions(+), 56 deletions(-)

diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 61c2aadd0d..d7c923b017 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -255,7 +255,7 @@ static inline int prot_for_access_type(MMUAccessType 
access_type)
 #ifndef CONFIG_USER_ONLY
 
 /* PowerPC MMU emulation */
-
+int ppc_pte_prot(int key, int pp, int nx);
 bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
   hwaddr *raddrp, int *psizep, int *protp,
   int mmu_idx, bool guest_visible);
diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c
index 3976416840..ee9df351ae 100644
--- a/target/ppc/mmu-hash32.c
+++ b/target/ppc/mmu-hash32.c
@@ -42,51 +42,6 @@ struct mmu_ctx_hash32 {
 int key;   /* Access key*/
 };
 
-static int ppc_hash32_pp_prot(int key, int pp, int nx)
-{
-int prot;
-
-if (key == 0) {
-switch (pp) {
-case 0x0:
-case 0x1:
-case 0x2:
-prot = PAGE_READ | PAGE_WRITE;
-break;
-
-case 0x3:
-prot = PAGE_READ;
-break;
-
-default:
-abort();
-}
-} else {
-switch (pp) {
-case 0x0:
-prot = 0;
-break;
-
-case 0x1:
-case 0x3:
-prot = PAGE_READ;
-break;
-
-case 0x2:
-prot = PAGE_READ | PAGE_WRITE;
-break;
-
-default:
-abort();
-}
-}
-if (nx == 0) {
-prot |= PAGE_EXEC;
-}
-
-return prot;
-}
-
 static int ppc_hash32_pte_prot(int mmu_idx,
target_ulong sr, ppc_hash_pte32_t pte)
 {
@@ -95,7 +50,7 @@ static int ppc_hash32_pte_prot(int mmu_idx,
 key = !!(mmuidx_pr(mmu_idx) ? (sr & SR32_KP) : (sr & SR32_KS));
 pp = pte.pte1 & HPTE32_R_PP;
 
-return ppc_hash32_pp_prot(key, pp, !!(sr & SR32_NX));
+return ppc_pte_prot(key, pp, !!(sr & SR32_NX));
 }
 
 static target_ulong hash32_bat_size(int mmu_idx,
diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 41ef174ab4..0ce5c1e841 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -75,22 +75,23 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
 /*/
 /* PowerPC MMU emulation */
 
-static int pp_check(int key, int pp, int nx)
+int ppc_pte_prot(int key, int pp, int nx)
 {
 int access;
 
 /* Compute access rights */
-access = 0;
 if (key == 0) {
 switch (pp) {
 case 0x0:
 case 0x1:
 case 0x2:
-access |= PAGE_WRITE;
-/* fall through */
+access = PAGE_READ | PAGE_WRITE;
+break;
 case 0x3:
-access |= PAGE_READ;
+access = PAGE_READ;
 break;
+default:
+g_assert_not_reached();
 }
 } else {
 switch (pp) {
@@ -104,6 +105,8 @@ static int pp_check(int key, int pp, int nx)
 case 0x2:
 access = PAGE_READ | PAGE_WRITE;
 break;
+default:
+g_assert_not_reached();
 }
 }
 if (nx == 0) {
@@ -140,7 +143,7 @@ static int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, 
target_ulong pte0,
 MMUAccessType access_type)
 {
 target_ulong ptem, mmask;
-int access, ret, pteh, ptev, pp;
+int ret, pteh, ptev, pp;
 
 ret = -1;
 /* Check validity and table match */
@@ -159,11 +162,9 @@ static int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, 
target_ulong pte0,
 return -3;
 }
 }
-/* Compute access rights */
-access = pp_check(ctx->key, pp, ctx->nx);
 /* Keep the matching PTE information */
 ctx->raddr = pte1;
-ctx->prot = access;
+ctx->prot = ppc_pte_prot(ctx->key, pp, ctx->nx);
 ret = check_prot(ctx->prot, access_type);
 if (ret == 0) {
 /* Access granted */
-- 
2.30.9




[PATCH v2 21/28] target/ppc: Move mmu_ctx_t definition to mmu_common.c

2024-05-01 Thread BALATON Zoltan
This type is only used within mmu_common.c. Move its definition from
internal.h to there.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/internal.h   | 12 
 target/ppc/mmu_common.c | 11 +++
 2 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 7a99f08dc8..61c2aadd0d 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -256,8 +256,6 @@ static inline int prot_for_access_type(MMUAccessType 
access_type)
 
 /* PowerPC MMU emulation */
 
-typedef struct mmu_ctx_t mmu_ctx_t;
-
 bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
   hwaddr *raddrp, int *psizep, int *protp,
   int mmu_idx, bool guest_visible);
@@ -265,16 +263,6 @@ bool ppc_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType 
access_type,
 /* Software driven TLB helpers */
 int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
 int way, int is_code);
-/* Context used internally during MMU translations */
-struct mmu_ctx_t {
-hwaddr raddr;  /* Real address  */
-hwaddr eaddr;  /* Effective address */
-int prot;  /* Protection bits   */
-hwaddr hash[2];/* Pagetable hash values */
-target_ulong ptem; /* Virtual segment ID | API  */
-int key;   /* Access key*/
-int nx;/* Non-execute area  */
-};
 
 #endif /* !CONFIG_USER_ONLY */
 
diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 4852cb5571..41ef174ab4 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -35,6 +35,17 @@
 
 /* #define DUMP_PAGE_TABLES */
 
+/* Context used internally during MMU translations */
+typedef struct {
+hwaddr raddr;  /* Real address */
+hwaddr eaddr;  /* Effective address*/
+int prot;  /* Protection bits  */
+hwaddr hash[2];/* Pagetable hash values*/
+target_ulong ptem; /* Virtual segment ID | API */
+int key;   /* Access key   */
+int nx;/* Non-execute area */
+} mmu_ctx_t;
+
 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
 {
 PowerPCCPU *cpu = env_archcpu(env);
-- 
2.30.9




[PATCH v2 12/28] target/ppc/mmu_common.c: Split out BookE cases before checking real mode

2024-05-01 Thread BALATON Zoltan
BookE does not have real mode so split off and handle it first in
get_physical_address_wtlb() before checking for real mode for other
MMU models.

Signed-off-by: BALATON Zoltan 
---
 target/ppc/mmu_common.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index a069e4083f..24a9b9ef19 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -1191,6 +1191,13 @@ int get_physical_address_wtlb(CPUPPCState *env, 
mmu_ctx_t *ctx,
 int ret = -1;
 bool real_mode;
 
+if (env->mmu_model == POWERPC_MMU_BOOKE) {
+return mmubooke_get_physical_address(env, ctx, eaddr, access_type);
+} else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
+return mmubooke206_get_physical_address(env, ctx, eaddr, access_type,
+mmu_idx);
+}
+
 real_mode = (type == ACCESS_CODE) ? !FIELD_EX64(env->msr, MSR, IR)
   : !FIELD_EX64(env->msr, MSR, DR);
 
@@ -1211,13 +1218,6 @@ int get_physical_address_wtlb(CPUPPCState *env, 
mmu_ctx_t *ctx,
 ret = mmu40x_get_physical_address(env, ctx, eaddr, access_type);
 }
 break;
-case POWERPC_MMU_BOOKE:
-ret = mmubooke_get_physical_address(env, ctx, eaddr, access_type);
-break;
-case POWERPC_MMU_BOOKE206:
-ret = mmubooke206_get_physical_address(env, ctx, eaddr, access_type,
-   mmu_idx);
-break;
 case POWERPC_MMU_REAL:
 if (real_mode) {
 ret = check_physical(env, ctx, eaddr, access_type);
-- 
2.30.9




[PATCH v2 03/28] target/ppc: Simplify syscall exception handlers

2024-05-01 Thread BALATON Zoltan
After previous changes the hypercall handling in 7xx and 74xx
exception handlers can be folded into one if statement to simplify
this code. Also add "unlikely" to mark the less frequently used branch
for the compiler.

Signed-off-by: BALATON Zoltan 
Reviewed-by: Harsh Prateek Bora 
---
 target/ppc/excp_helper.c | 22 ++
 1 file changed, 6 insertions(+), 16 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 5aa84bccd2..d19212f772 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -762,26 +762,21 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp)
 case POWERPC_EXCP_SYSCALL:   /* System call exception*/
 {
 int lev = env->error_code;
-
-if (lev == 1 && cpu->vhyp) {
-dump_hcall(env);
-} else {
-dump_syscall(env);
-}
 /*
  * The Virtual Open Firmware (VOF) relies on the 'sc 1'
  * instruction to communicate with QEMU. The pegasos2 machine
  * uses VOF and the 7xx CPUs, so although the 7xx don't have
  * HV mode, we need to keep hypercall support.
  */
-if (lev == 1 && cpu->vhyp) {
+if (unlikely(lev == 1 && cpu->vhyp)) {
 PPCVirtualHypervisorClass *vhc =
 PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+dump_hcall(env);
 vhc->hypercall(cpu->vhyp, cpu);
 powerpc_reset_excp_state(cpu);
 return;
 }
-
+dump_syscall(env);
 break;
 }
 case POWERPC_EXCP_FPU:   /* Floating-point unavailable exception */
@@ -907,26 +902,21 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
 case POWERPC_EXCP_SYSCALL:   /* System call exception*/
 {
 int lev = env->error_code;
-
-if (lev == 1 && cpu->vhyp) {
-dump_hcall(env);
-} else {
-dump_syscall(env);
-}
 /*
  * The Virtual Open Firmware (VOF) relies on the 'sc 1'
  * instruction to communicate with QEMU. The pegasos2 machine
  * uses VOF and the 74xx CPUs, so although the 74xx don't have
  * HV mode, we need to keep hypercall support.
  */
-if (lev == 1 && cpu->vhyp) {
+if (unlikely(lev == 1 && cpu->vhyp)) {
 PPCVirtualHypervisorClass *vhc =
 PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+dump_hcall(env);
 vhc->hypercall(cpu->vhyp, cpu);
 powerpc_reset_excp_state(cpu);
 return;
 }
-
+dump_syscall(env);
 break;
 }
 case POWERPC_EXCP_FPU:   /* Floating-point unavailable exception */
-- 
2.30.9




Re: [RFC 1/2] iova_tree: add an id member to DMAMap

2024-05-01 Thread Si-Wei Liu




On 4/30/2024 10:19 AM, Eugenio Perez Martin wrote:

On Tue, Apr 30, 2024 at 7:55 AM Si-Wei Liu  wrote:



On 4/29/2024 1:14 AM, Eugenio Perez Martin wrote:

On Thu, Apr 25, 2024 at 7:44 PM Si-Wei Liu  wrote:


On 4/24/2024 12:33 AM, Eugenio Perez Martin wrote:

On Wed, Apr 24, 2024 at 12:21 AM Si-Wei Liu  wrote:

On 4/22/2024 1:49 AM, Eugenio Perez Martin wrote:

On Sat, Apr 20, 2024 at 1:50 AM Si-Wei Liu  wrote:

On 4/19/2024 1:29 AM, Eugenio Perez Martin wrote:

On Thu, Apr 18, 2024 at 10:46 PM Si-Wei Liu  wrote:

On 4/10/2024 3:03 AM, Eugenio Pérez wrote:

IOVA tree is also used to track the mappings of virtio-net shadow
virtqueue.  This mappings may not match with the GPA->HVA ones.

This causes a problem when overlapped regions (different GPA but same
translated HVA) exists in the tree, as looking them by HVA will return
them twice.  To solve this, create an id member so we can assign unique
identifiers (GPA) to the maps.

Signed-off-by: Eugenio Pérez 
---
   include/qemu/iova-tree.h | 5 +++--
   util/iova-tree.c | 3 ++-
   2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h
index 2a10a7052e..34ee230e7d 100644
--- a/include/qemu/iova-tree.h
+++ b/include/qemu/iova-tree.h
@@ -36,6 +36,7 @@ typedef struct DMAMap {
   hwaddr iova;
   hwaddr translated_addr;
   hwaddr size;/* Inclusive */
+uint64_t id;
   IOMMUAccessFlags perm;
   } QEMU_PACKED DMAMap;
   typedef gboolean (*iova_tree_iterator)(DMAMap *map);
@@ -100,8 +101,8 @@ const DMAMap *iova_tree_find(const IOVATree *tree, const 
DMAMap *map);
* @map: the mapping to search
*
* Search for a mapping in the iova tree that translated_addr overlaps 
with the
- * mapping range specified.  Only the first found mapping will be
- * returned.
+ * mapping range specified and map->id is equal.  Only the first found
+ * mapping will be returned.
*
* Return: DMAMap pointer if found, or NULL if not found.  Note that
* the returned DMAMap pointer is maintained internally.  User should
diff --git a/util/iova-tree.c b/util/iova-tree.c
index 536789797e..0863e0a3b8 100644
--- a/util/iova-tree.c
+++ b/util/iova-tree.c
@@ -97,7 +97,8 @@ static gboolean iova_tree_find_address_iterator(gpointer key, 
gpointer value,

   needle = args->needle;
   if (map->translated_addr + map->size < needle->translated_addr ||
-needle->translated_addr + needle->size < map->translated_addr) {
+needle->translated_addr + needle->size < map->translated_addr ||
+needle->id != map->id) {

It looks this iterator can also be invoked by SVQ from
vhost_svq_translate_addr() -> iova_tree_find_iova(), where guest GPA
space will be searched on without passing in the ID (GPA), and exact
match for the same GPA range is not actually needed unlike the mapping
removal case. Could we create an API variant, for the SVQ lookup case
specifically? Or alternatively, add a special flag, say skip_id_match to
DMAMap, and the id match check may look like below:

(!needle->skip_id_match && needle->id != map->id)

I think vhost_svq_translate_addr() could just call the API variant or
pass DMAmap with skip_id_match set to true to svq_iova_tree_find_iova().


I think you're totally right. But I'd really like to not complicate
the API of the iova_tree more.

I think we can look for the hwaddr using memory_region_from_host and
then get the hwaddr. It is another lookup though...

Yeah, that will be another means of doing translation without having to
complicate the API around iova_tree. I wonder how the lookup through
memory_region_from_host() may perform compared to the iova tree one, the
former looks to be an O(N) linear search on a linked list while the
latter would be roughly O(log N) on an AVL tree?

Even worse, as the reverse lookup (from QEMU vaddr to SVQ IOVA) is
linear too. It is not even ordered.

Oh Sorry, I misread the code and I should look for g_tree_foreach ()
instead of g_tree_search_node(). So the former is indeed linear
iteration, but it looks to be ordered?

https://github.com/GNOME/glib/blob/main/glib/gtree.c#L1115

The GPA / IOVA are ordered but we're looking by QEMU's vaddr.

If we have these translations:
[0x1000, 0x2000] -> [0x1, 0x11000]
[0x2000, 0x3000] -> [0x6000, 0x7000]

We will see them in this order, so we cannot stop the search at the first node.

Yeah, reverse lookup is unordered indeed, anyway.


But apart from this detail you're right, I have the same concerns with
this solution too. If we see a hard performance regression we could go
to more complicated solutions, like maintaining a reverse IOVATree in
vhost-iova-tree too. First RFCs of SVQ did that actually.

Agreed, yeap we can use memory_region_from_host for now.  Any reason why
reverse IOVATree was dropped, lack of users? But now we have one!


No, it is just simplicity. We already have an user in the ho

Re: [RFC 1/2] iova_tree: add an id member to DMAMap

2024-05-01 Thread Si-Wei Liu




On 4/30/2024 11:11 AM, Eugenio Perez Martin wrote:

On Mon, Apr 29, 2024 at 1:19 PM Jonah Palmer  wrote:



On 4/29/24 4:14 AM, Eugenio Perez Martin wrote:

On Thu, Apr 25, 2024 at 7:44 PM Si-Wei Liu  wrote:



On 4/24/2024 12:33 AM, Eugenio Perez Martin wrote:

On Wed, Apr 24, 2024 at 12:21 AM Si-Wei Liu  wrote:


On 4/22/2024 1:49 AM, Eugenio Perez Martin wrote:

On Sat, Apr 20, 2024 at 1:50 AM Si-Wei Liu  wrote:

On 4/19/2024 1:29 AM, Eugenio Perez Martin wrote:

On Thu, Apr 18, 2024 at 10:46 PM Si-Wei Liu  wrote:

On 4/10/2024 3:03 AM, Eugenio Pérez wrote:

IOVA tree is also used to track the mappings of virtio-net shadow
virtqueue.  This mappings may not match with the GPA->HVA ones.

This causes a problem when overlapped regions (different GPA but same
translated HVA) exists in the tree, as looking them by HVA will return
them twice.  To solve this, create an id member so we can assign unique
identifiers (GPA) to the maps.

Signed-off-by: Eugenio Pérez 
---
   include/qemu/iova-tree.h | 5 +++--
   util/iova-tree.c | 3 ++-
   2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h
index 2a10a7052e..34ee230e7d 100644
--- a/include/qemu/iova-tree.h
+++ b/include/qemu/iova-tree.h
@@ -36,6 +36,7 @@ typedef struct DMAMap {
   hwaddr iova;
   hwaddr translated_addr;
   hwaddr size;/* Inclusive */
+uint64_t id;
   IOMMUAccessFlags perm;
   } QEMU_PACKED DMAMap;
   typedef gboolean (*iova_tree_iterator)(DMAMap *map);
@@ -100,8 +101,8 @@ const DMAMap *iova_tree_find(const IOVATree *tree, const 
DMAMap *map);
* @map: the mapping to search
*
* Search for a mapping in the iova tree that translated_addr overlaps 
with the
- * mapping range specified.  Only the first found mapping will be
- * returned.
+ * mapping range specified and map->id is equal.  Only the first found
+ * mapping will be returned.
*
* Return: DMAMap pointer if found, or NULL if not found.  Note that
* the returned DMAMap pointer is maintained internally.  User should
diff --git a/util/iova-tree.c b/util/iova-tree.c
index 536789797e..0863e0a3b8 100644
--- a/util/iova-tree.c
+++ b/util/iova-tree.c
@@ -97,7 +97,8 @@ static gboolean iova_tree_find_address_iterator(gpointer key, 
gpointer value,

   needle = args->needle;
   if (map->translated_addr + map->size < needle->translated_addr ||
-needle->translated_addr + needle->size < map->translated_addr) {
+needle->translated_addr + needle->size < map->translated_addr ||
+needle->id != map->id) {

It looks this iterator can also be invoked by SVQ from
vhost_svq_translate_addr() -> iova_tree_find_iova(), where guest GPA
space will be searched on without passing in the ID (GPA), and exact
match for the same GPA range is not actually needed unlike the mapping
removal case. Could we create an API variant, for the SVQ lookup case
specifically? Or alternatively, add a special flag, say skip_id_match to
DMAMap, and the id match check may look like below:

(!needle->skip_id_match && needle->id != map->id)

I think vhost_svq_translate_addr() could just call the API variant or
pass DMAmap with skip_id_match set to true to svq_iova_tree_find_iova().


I think you're totally right. But I'd really like to not complicate
the API of the iova_tree more.

I think we can look for the hwaddr using memory_region_from_host and
then get the hwaddr. It is another lookup though...

Yeah, that will be another means of doing translation without having to
complicate the API around iova_tree. I wonder how the lookup through
memory_region_from_host() may perform compared to the iova tree one, the
former looks to be an O(N) linear search on a linked list while the
latter would be roughly O(log N) on an AVL tree?

Even worse, as the reverse lookup (from QEMU vaddr to SVQ IOVA) is
linear too. It is not even ordered.

Oh Sorry, I misread the code and I should look for g_tree_foreach ()
instead of g_tree_search_node(). So the former is indeed linear
iteration, but it looks to be ordered?

https://urldefense.com/v3/__https://github.com/GNOME/glib/blob/main/glib/gtree.c*L1115__;Iw!!ACWV5N9M2RV99hQ!Ng2rLfRd9tLyNTNocW50Mf5AcxSt0uF0wOdv120djff-z_iAdbujYK-jMi5UC1DZLxb1yLUv2vV0j3wJo8o$

The GPA / IOVA are ordered but we're looking by QEMU's vaddr.

If we have these translations:
[0x1000, 0x2000] -> [0x1, 0x11000]
[0x2000, 0x3000] -> [0x6000, 0x7000]

We will see them in this order, so we cannot stop the search at the first node.

Yeah, reverse lookup is unordered indeed, anyway.


But apart from this detail you're right, I have the same concerns with
this solution too. If we see a hard performance regression we could go
to more complicated solutions, like maintaining a reverse IOVATree in
vhost-iova-tree too. First RFCs of SVQ did that actually.

Agreed, yeap we can use memory_region_from_host for now.  Any re

Re: [PATCH v7 09/12] hw/cxl/events: Add qmp interfaces to add/release dynamic capacity extents

2024-05-01 Thread fan
Hi Markus, Michael and Jonathan,

FYI. I have updated this patch based on the feedbacks so far, and posted here:
https://lore.kernel.org/linux-cxl/20240418232902.583744-1-fan...@samsung.com/T/#ma25b6657597d39df23341dc43c22a8c49818e5f9

Comments are welcomed and appreciated.

Fan


On Wed, May 01, 2024 at 03:58:12PM +0100, Jonathan Cameron wrote:
> 
> 
> 
> > > >> > +# @hid: host id  
> > > >> 
> > > >> @host-id, unless "HID" is established terminology in CXL DCD land.  
> > > >
> > > > host-id works.  
> > > >> 
> > > >> What is a host ID?  
> > > >
> > > > It is an id identifying the host to which the capacity is being added.  
> > > 
> > > How are these IDs assigned?  
> > 
> > All the arguments passed to the command here are defined in CXL spec. I
> > will add reference to the spec.
> > 
> > Based on the spec, for LD-FAM (Fabric attached memory represented as
> > logical device), host id is the LD-ID of the host interface to which
> > the capacity is being added. LD-ID is a unique number (16-bit) assigned
> > to a host interface.
> 
> Key here is the host doesn't know it.  This ID exists purely for rooting
> to the appropriate host interface either via choosing a port on a
> multihead Single Logical Device (SLD) (so today it's always 0 as we only
> have one head) or if we ever implement a switch capable of handling MLDs
> then the switch will handle routing of host PCIe accesses so it lands
> on the interface defined by this ID (and the event turns up in that event log.
> 
> Host A Host B - could in theory be a RP on host A ;)
>   |  |  Doesn't exist (yet, but there are partial.
>  _|__|_ patches for this on list.
> | LD 0 LD 1|
> |  |
> |   Multi Head |
> |   Single Logical |
> |  Device (MH-SLD) |
> |__|
> Host view similar to the switch case, but just two direct
> connected devices.
> 
> Or Switch and MLD case - we aren't emulating this yet at all
> 
>  Wiring / real topology Host View 
>  
>   Host A Host B  Host A   Host B
> |  |   ||
>  ___|__|___   _|_  _|_
> |   \  SWITCH /| |SW0|| | |
> |\   / | | | || | |
> |LD0   LD1 | | | || | |
> |  \   /   | | | || | |
> || | | | || | |
> ||_| |_|_||_|_|
>  | ||
>   Traffic tagged with LD   ||
>  | ||
>  | |___ |___
> | Multilogical Device MLD |   ||   ||
> |||   | Simple |   | Another|
> |   / \   |   | CXL|   | CXL|
> |  /   \  |   | Memory |   | Memory |
> |Interfaces   |   | Device |   | Device |
> |   LD0 LD1   |   ||   ||
> |_|   ||   ||
> 
> Note the hosts just see separate devices and switches with the fun exception 
> that the
> memory may actually be available to both at the same time.
> 
> Control plane for the switches and MLD see what is actually going on.
> 
> At this stage upshot is we could just default this to zero and add an optional
> parameter to set it later.
> 
> 
> 
> ...
> 
> > > >> > +# @extents: Extents to release
> > > >> > +#
> > > >> > +# Since : 9.1
> > > >> > +##
> > > >> > +{ 'command': 'cxl-release-dynamic-capacity',
> > > >> > +  'data': { 'path': 'str',
> > > >> > +'hid': 'uint16',
> > > >> > +'flags': 'uint8',
> > > >> > +'region-id': 'uint8',
> > > >> > +'tag': 'str',
> > > >> > +'extents': [ 'CXLDCExtentRecord' ]
> > > >> > +   }
> > > >> > +}  
> > > >> 
> > > >> During review of v5, you wrote:
> > > >> 
> > > >> For add command, the host will send a mailbox command to response 
> > > >> to
> > > >> the add request to the device to indicate whether it accepts the 
> > > >> add
> > > >> capacity offer or not.
> > > >> 
> > > >> For release command, the host send a mailbox command (not always a
> > > >> response since the host can proactively release capacity if it does
> > > >> not need it any more) to device to ask device release the capacity.
> > > >> 
> > > >> Can you briefly sketch the protocol?  Peers and messages involved.
> > > >> Possibly as a state diagram.  
> > > >
> > > > Need to think about it. If we can polish the text nicely, maybe the
> > > > sketch is not needed. My concern is that the sketch may
> > > > introduce unwanted complexity as we expose too mu

Re: [PATCH v7 09/12] hw/cxl/events: Add qmp interfaces to add/release dynamic capacity extents

2024-05-01 Thread fan


>From 873f59ec06c38645768ada452d9b18920a34723e Mon Sep 17 00:00:00 2001
From: Fan Ni 
Date: Tue, 20 Feb 2024 09:48:31 -0800
Subject: [PATCH] hw/cxl/events: Add qmp interfaces to add/release dynamic
 capacity extents
Status: RO
Content-Length: 25172
Lines: 731

To simulate FM functionalities for initiating Dynamic Capacity Add
(Opcode 5604h) and Dynamic Capacity Release (Opcode 5605h) as in CXL spec
r3.1 7.6.7.6.5 and 7.6.7.6.6, we implemented two QMP interfaces to issue
add/release dynamic capacity extents requests.

With the change, we allow to release an extent only when its DPA range
is contained by a single accepted extent in the device. That is to say,
extent superset release is not supported yet.

1. Add dynamic capacity extents:

For example, the command to add two continuous extents (each 128MiB long)
to region 0 (starting at DPA offset 0) looks like below:

{ "execute": "qmp_capabilities" }

{ "execute": "cxl-add-dynamic-capacity",
  "arguments": {
  "path": "/machine/peripheral/cxl-dcd0",
  "host-id": 0,
  "selection-policy": 2,
  "region": 0,
  "tag": "",
  "extents": [
  {
  "offset": 0,
  "len": 134217728
  },
  {
  "offset": 134217728,
  "len": 134217728
  }
  ]
  }
}

2. Release dynamic capacity extents:

For example, the command to release an extent of size 128MiB from region 0
(DPA offset 128MiB) looks like below:

{ "execute": "cxl-release-dynamic-capacity",
  "arguments": {
  "path": "/machine/peripheral/cxl-dcd0",
  "host-id": 0,
  "flags": 1,
  "region": 0,
  "tag": "",
  "extents": [
  {
  "offset": 134217728,
  "len": 134217728
  }
  ]
  }
}

Signed-off-by: Fan Ni 
---
 hw/cxl/cxl-mailbox-utils.c  |  62 +--
 hw/mem/cxl_type3.c  | 311 +++-
 hw/mem/cxl_type3_stubs.c|  20 +++
 include/hw/cxl/cxl_device.h |  22 +++
 include/hw/cxl/cxl_events.h |  18 +++
 qapi/cxl.json   |  90 +++
 6 files changed, 510 insertions(+), 13 deletions(-)

diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index 9d54e10cd4..3569902e9e 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -1405,7 +1405,7 @@ static CXLRetCode cmd_dcd_get_dyn_cap_ext_list(const 
struct cxl_cmd *cmd,
  * Check whether any bit between addr[nr, nr+size) is set,
  * return true if any bit is set, otherwise return false
  */
-static bool test_any_bits_set(const unsigned long *addr, unsigned long nr,
+bool test_any_bits_set(const unsigned long *addr, unsigned long nr,
   unsigned long size)
 {
 unsigned long res = find_next_bit(addr, size + nr, nr);
@@ -1444,7 +1444,7 @@ CXLDCRegion *cxl_find_dc_region(CXLType3Dev *ct3d, 
uint64_t dpa, uint64_t len)
 return NULL;
 }
 
-static void cxl_insert_extent_to_extent_list(CXLDCExtentList *list,
+void cxl_insert_extent_to_extent_list(CXLDCExtentList *list,
  uint64_t dpa,
  uint64_t len,
  uint8_t *tag,
@@ -1470,6 +1470,44 @@ void cxl_remove_extent_from_extent_list(CXLDCExtentList 
*list,
 g_free(extent);
 }
 
+/*
+ * Add a new extent to the extent "group" if group exists;
+ * otherwise, create a new group
+ * Return value: return the group where the extent is inserted.
+ */
+CXLDCExtentGroup *cxl_insert_extent_to_extent_group(CXLDCExtentGroup *group,
+uint64_t dpa,
+uint64_t len,
+uint8_t *tag,
+uint16_t shared_seq)
+{
+if (!group) {
+group = g_new0(CXLDCExtentGroup, 1);
+QTAILQ_INIT(&group->list);
+}
+cxl_insert_extent_to_extent_list(&group->list, dpa, len,
+ tag, shared_seq);
+return group;
+}
+
+void cxl_extent_group_list_insert_tail(CXLDCExtentGroupList *list,
+   CXLDCExtentGroup *group)
+{
+QTAILQ_INSERT_TAIL(list, group, node);
+}
+
+void cxl_extent_group_list_delete_front(CXLDCExtentGroupList *list)
+{
+CXLDCExtent *ent, *ent_next;
+CXLDCExtentGroup *group = QTAILQ_FIRST(list);
+
+QTAILQ_REMOVE(list, group, node);
+QTAILQ_FOREACH_SAFE(ent, &group->list, node, ent_next) {
+cxl_remove_extent_from_extent_list(&group->list, ent);
+}
+g_free(group);
+}
+
 /*
  * CXL r3.1 Table 8-168: Add Dynamic Capacity Response Input Payload
  * CXL r3.1 Table 8-170: Release Dynamic Capacity Input Payload
@@ -1541,6 +1579,7 @@ static CXLRetCode 
cxl_dcd_add_dyn_cap_rsp_dry_run(CXLType3Dev *ct3d,
 {
 uint32_t i;
 CXLDCExtent *ent;
+CXLDCExtentGroup *ext_group;
 uint64_t dpa, len;
 Range range1, range2;
 
@@ -1551,9 +1590,13 @@ static CXLRetCode 

Re: [PULL 0/1] ufs queue

2024-05-01 Thread Richard Henderson

On 4/28/24 20:25, Jeuk Kim wrote:

From: Jeuk Kim

The following changes since commit fd87be1dada5672f877e03c2ca8504458292c479:

   Merge tag 'accel-20240426' ofhttps://github.com/philmd/qemu  into staging 
(2024-04-26 15:28:13 -0700)

are available in the Git repository at:

   https://gitlab.com/jeuk20.kim/qemu.git  tags/pull-ufs-20240429

for you to fetch changes up to f2c8aeb1afefcda92054c448b21fc59cdd99db30:

   hw/ufs: Fix buffer overflow bug (2024-04-29 12:13:35 +0900)


ufs queue

- Fix ufs sanitizer vulnerability


Applied, thanks.  Please update https://wiki.qemu.org/ChangeLog/9.1 as 
appropriate.


r~




Re: [PULL 0/9] QGA misc changes for 2024-05-01

2024-05-01 Thread Richard Henderson

On 5/1/24 00:43, Konstantin Kostiuk wrote:

The following changes since commit 9c6c079bc6723da8061ccfb44361d67b1dd785dd:

   Merge tag 'pull-target-arm-20240430' 
ofhttps://git.linaro.org/people/pmaydell/qemu-arm  into staging (2024-04-30 
09:58:54 -0700)

are available in the Git repository at:

   https://github.com/kostyanf14/qemu.git  tags/qga-pull-2024-05-01

for you to fetch changes up to 6b9296ba7a9cf7adb157c51c124ca522d2180739:

   qga: Implement SSH commands for Windows (2024-05-01 10:35:45 +0300)


qga-pull-2024-05-01


Applied, thanks.  Please update https://wiki.qemu.org/ChangeLog/9.1 as 
appropriate.


r~




Re: [PATCH v4 17/17] hw/arm: xen: Enable use of grant mappings

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> Signed-off-by: Edgar E. Iglesias 

Reviewed-by: Stefano Stabellini 


> ---
>  hw/arm/xen_arm.c | 5 +
>  1 file changed, 5 insertions(+)
> 
> diff --git a/hw/arm/xen_arm.c b/hw/arm/xen_arm.c
> index 15fa7dfa84..6fad829ede 100644
> --- a/hw/arm/xen_arm.c
> +++ b/hw/arm/xen_arm.c
> @@ -125,6 +125,11 @@ static void xen_init_ram(MachineState *machine)
>   GUEST_RAM1_BASE, ram_size[1]);
>  memory_region_add_subregion(sysmem, GUEST_RAM1_BASE, &ram_hi);
>  }
> +
> +/* Setup support for grants.  */
> +memory_region_init_ram(&xen_grants, NULL, "xen.grants", block_len,
> +   &error_fatal);
> +memory_region_add_subregion(sysmem, XEN_GRANT_ADDR_OFF, &xen_grants);
>  }
>  
>  void arch_handle_ioreq(XenIOState *state, ioreq_t *req)
> -- 
> 2.40.1
> 



Re: [PATCH v4 15/17] xen: mapcache: Remove assumption of RAMBlock with 0 offset

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> The current mapcache assumes that all memory is mapped
> in a single RAM MR (the first one with offset 0). Remove
> this assumption and propagate the offset to the mapcache
> so it can do reverse mappings (from hostptr -> ram_addr).
> 
> This is in preparation for adding grant mappings.
> 
> Signed-off-by: Edgar E. Iglesias 


Looking at xen_remap_bucket, it is only using address_index (without
adding ram_offset) to map foreign memory. From xen_remap_bucket, I would
understand that address_index already includes the ram_offset.

Meaning that if we want to map foreign mapping at address 0x5000, then
address_index would be 0x5000, even if ram_offset is 0x1000.

But then looking xen_ram_addr_from_mapcache_single ram_offset is added
to paddr_index to calculate the physical address. So in that case we
would want address_index to be 0x4000 and ram_offset to be 0x1000. But
xen_remap_bucket would have to sum address_index and ram_offset to map
foreign memory.

So I am a bit confused, did I get it wrong? One more comment below.


> ---
>  hw/xen/xen-mapcache.c | 25 ++---
>  include/sysemu/xen-mapcache.h |  2 ++
>  system/physmem.c  |  8 
>  3 files changed, 24 insertions(+), 11 deletions(-)
> 
> diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
> index 09b5f36d9c..1b32d0c003 100644
> --- a/hw/xen/xen-mapcache.c
> +++ b/hw/xen/xen-mapcache.c
> @@ -43,6 +43,9 @@ typedef struct MapCacheEntry {
>  #define XEN_MAPCACHE_ENTRY_DUMMY (1 << 0)
>  uint8_t flags;
>  hwaddr size;
> +
> +/* Keep ram_addr offset for reverse mappings (hostptr -> ram_addr).  */
> +ram_addr_t ram_offset;
>  struct MapCacheEntry *next;
>  } MapCacheEntry;
>  
> @@ -165,7 +168,8 @@ static void xen_remap_bucket(MapCache *mc,
>   void *vaddr,
>   hwaddr size,
>   hwaddr address_index,
> - bool dummy)
> + bool dummy,
> + ram_addr_t ram_offset)
>  {
>  uint8_t *vaddr_base;
>  xen_pfn_t *pfns;
> @@ -244,6 +248,7 @@ static void xen_remap_bucket(MapCache *mc,
>  entry->size = size;
>  entry->valid_mapping = g_new0(unsigned long,
>BITS_TO_LONGS(size >> XC_PAGE_SHIFT));
> +entry->ram_offset = ram_offset;
>  
>  if (dummy) {
>  entry->flags |= XEN_MAPCACHE_ENTRY_DUMMY;
> @@ -264,6 +269,7 @@ static void xen_remap_bucket(MapCache *mc,
>  
>  static uint8_t *xen_map_cache_unlocked(MapCache *mc,
> hwaddr phys_addr, hwaddr size,
> +   ram_addr_t ram_offset,
> uint8_t lock, bool dma, bool is_write)
>  {
>  MapCacheEntry *entry, *pentry = NULL,
> @@ -335,14 +341,16 @@ tryagain:
>  if (!entry) {
>  entry = g_new0(MapCacheEntry, 1);
>  pentry->next = entry;
> -xen_remap_bucket(mc, entry, NULL, cache_size, address_index, dummy);
> +xen_remap_bucket(mc, entry, NULL, cache_size, address_index, dummy,
> + ram_offset);
>  } else if (!entry->lock) {
>  if (!entry->vaddr_base || entry->paddr_index != address_index ||
>  entry->size != cache_size ||
>  !test_bits(address_offset >> XC_PAGE_SHIFT,
>  test_bit_size >> XC_PAGE_SHIFT,
>  entry->valid_mapping)) {
> -xen_remap_bucket(mc, entry, NULL, cache_size, address_index, 
> dummy);
> +xen_remap_bucket(mc, entry, NULL, cache_size, address_index, 
> dummy,
> + ram_offset);
>  }
>  }
>  
> @@ -389,13 +397,15 @@ tryagain:
>  
>  uint8_t *xen_map_cache(MemoryRegion *mr,
> hwaddr phys_addr, hwaddr size,
> +   ram_addr_t ram_addr_offset,
> uint8_t lock, bool dma,
> bool is_write)
>  {
>  uint8_t *p;
>  
>  mapcache_lock(mapcache);
> -p = xen_map_cache_unlocked(mapcache, phys_addr, size, lock, dma, 
> is_write);
> +p = xen_map_cache_unlocked(mapcache, phys_addr, size, ram_addr_offset,
> +   lock, dma, is_write);
>  mapcache_unlock(mapcache);
>  return p;
>  }
> @@ -432,7 +442,8 @@ static ram_addr_t 
> xen_ram_addr_from_mapcache_single(MapCache *mc, void *ptr)
>  raddr = RAM_ADDR_INVALID;
>  } else {
>  raddr = (reventry->paddr_index << mc->bucket_shift) +
> - ((unsigned long) ptr - (unsigned long) entry->vaddr_base);
> + ((unsigned long) ptr - (unsigned long) entry->vaddr_base) +
> + entry->ram_offset;
>  }
>  mapcache_unlock(mc);
>  return raddr;
> @@ -627,8 +638,8 @@ static uint8_t *xen_replace_cache_entry_unlocked(Map

Re: [PATCH v4 14/17] xen: Add xen_mr_is_memory()

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> Add xen_mr_is_memory() to abstract away tests for the
> xen_memory MR.
> 
> Signed-off-by: Edgar E. Iglesias 

There is an important change in this patch below


> ---
>  hw/xen/xen-hvm-common.c | 8 +++-
>  include/sysemu/xen.h| 8 
>  system/physmem.c| 2 +-
>  3 files changed, 16 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/xen/xen-hvm-common.c b/hw/xen/xen-hvm-common.c
> index 1627da7398..0267b88d26 100644
> --- a/hw/xen/xen-hvm-common.c
> +++ b/hw/xen/xen-hvm-common.c
> @@ -12,6 +12,12 @@
>  
>  MemoryRegion xen_memory;
>  
> +/* Check for xen memory.  */
> +bool xen_mr_is_memory(MemoryRegion *mr)
> +{
> +return mr == &xen_memory;
> +}
> +
>  void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, MemoryRegion *mr,
> Error **errp)
>  {
> @@ -28,7 +34,7 @@ void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, 
> MemoryRegion *mr,
>  return;
>  }
>  
> -if (mr == &xen_memory) {
> +if (xen_mr_is_memory(mr)) {
>  return;
>  }
>  
> diff --git a/include/sysemu/xen.h b/include/sysemu/xen.h
> index 754ec2e6cb..dc72f83bcb 100644
> --- a/include/sysemu/xen.h
> +++ b/include/sysemu/xen.h
> @@ -34,6 +34,8 @@ void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t 
> length);
>  void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size,
> struct MemoryRegion *mr, Error **errp);
>  
> +bool xen_mr_is_memory(MemoryRegion *mr);
> +
>  #else /* !CONFIG_XEN_IS_POSSIBLE */
>  
>  #define xen_enabled() 0
> @@ -47,6 +49,12 @@ static inline void xen_ram_alloc(ram_addr_t ram_addr, 
> ram_addr_t size,
>  g_assert_not_reached();
>  }
>  
> +static inline bool xen_mr_is_memory(MemoryRegion *mr)
> +{
> +g_assert_not_reached();
> +return false;
> +}
> +
>  #endif /* CONFIG_XEN_IS_POSSIBLE */
>  
>  #endif
> diff --git a/system/physmem.c b/system/physmem.c
> index ad7a8c7d95..1a5ffcba2a 100644
> --- a/system/physmem.c
> +++ b/system/physmem.c
> @@ -2227,7 +2227,7 @@ static void *qemu_ram_ptr_length(RAMBlock *block, 
> ram_addr_t addr,
>   * because we don't want to map the entire memory in QEMU.
>   * In that case just map the requested area.
>   */
> -if (block->offset == 0) {
> +if (xen_mr_is_memory(block->mr)) {

This changes this check from block->offset == 0 to block->mr ==
&xen_memory. I think that's correct in all cases (x86 machines, ARM
machines) but I wanted to highlight it.

Reviewed-by: Stefano Stabellini 





>  return xen_map_cache(block->mr, addr, len, lock, lock,
>   is_write);
>  }
> -- 
> 2.40.1
> 



Re: [PATCH v4 13/17] softmmu: Pass RAM MemoryRegion and is_write xen_map_cache()

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> Propagate MR and is_write to xen_map_cache().
> This is in preparation for adding support for grant mappings.
> 
> No functional change.
> 
> Signed-off-by: Edgar E. Iglesias 

Reviewed-by: Stefano Stabellini 


> ---
>  hw/xen/xen-mapcache.c | 10 ++
>  include/sysemu/xen-mapcache.h | 11 +++
>  system/physmem.c  | 31 +++
>  3 files changed, 36 insertions(+), 16 deletions(-)
> 
> diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
> index 0365311788..09b5f36d9c 100644
> --- a/hw/xen/xen-mapcache.c
> +++ b/hw/xen/xen-mapcache.c
> @@ -264,7 +264,7 @@ static void xen_remap_bucket(MapCache *mc,
>  
>  static uint8_t *xen_map_cache_unlocked(MapCache *mc,
> hwaddr phys_addr, hwaddr size,
> -   uint8_t lock, bool dma)
> +   uint8_t lock, bool dma, bool is_write)
>  {
>  MapCacheEntry *entry, *pentry = NULL,
>*free_entry = NULL, *free_pentry = NULL;
> @@ -387,13 +387,15 @@ tryagain:
>  return mc->last_entry->vaddr_base + address_offset;
>  }
>  
> -uint8_t *xen_map_cache(hwaddr phys_addr, hwaddr size,
> -   uint8_t lock, bool dma)
> +uint8_t *xen_map_cache(MemoryRegion *mr,
> +   hwaddr phys_addr, hwaddr size,
> +   uint8_t lock, bool dma,
> +   bool is_write)
>  {
>  uint8_t *p;
>  
>  mapcache_lock(mapcache);
> -p = xen_map_cache_unlocked(mapcache, phys_addr, size, lock, dma);
> +p = xen_map_cache_unlocked(mapcache, phys_addr, size, lock, dma, 
> is_write);
>  mapcache_unlock(mapcache);
>  return p;
>  }
> diff --git a/include/sysemu/xen-mapcache.h b/include/sysemu/xen-mapcache.h
> index 10c2e3082a..1ec9e66752 100644
> --- a/include/sysemu/xen-mapcache.h
> +++ b/include/sysemu/xen-mapcache.h
> @@ -18,8 +18,9 @@ typedef hwaddr (*phys_offset_to_gaddr_t)(hwaddr phys_offset,
>  
>  void xen_map_cache_init(phys_offset_to_gaddr_t f,
>  void *opaque);
> -uint8_t *xen_map_cache(hwaddr phys_addr, hwaddr size,
> -   uint8_t lock, bool dma);
> +uint8_t *xen_map_cache(MemoryRegion *mr, hwaddr phys_addr, hwaddr size,
> +   uint8_t lock, bool dma,
> +   bool is_write);
>  ram_addr_t xen_ram_addr_from_mapcache(void *ptr);
>  void xen_invalidate_map_cache_entry(uint8_t *buffer);
>  void xen_invalidate_map_cache(void);
> @@ -33,10 +34,12 @@ static inline void 
> xen_map_cache_init(phys_offset_to_gaddr_t f,
>  {
>  }
>  
> -static inline uint8_t *xen_map_cache(hwaddr phys_addr,
> +static inline uint8_t *xen_map_cache(MemoryRegion *mr,
> + hwaddr phys_addr,
>   hwaddr size,
>   uint8_t lock,
> - bool dma)
> + bool dma,
> + bool is_write)
>  {
>  abort();
>  }
> diff --git a/system/physmem.c b/system/physmem.c
> index f114b972a5..ad7a8c7d95 100644
> --- a/system/physmem.c
> +++ b/system/physmem.c
> @@ -2190,11 +2190,22 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t 
> length)
>  
>  /*
>   * Return a host pointer to guest's ram.
> + * For Xen, foreign mappings get created if they don't already exist.
> + *
> + * @block: block for the RAM to lookup (optional and may be NULL).
> + * @addr: address within the memory region.
> + * @size: pointer to requested size (optional and may be NULL).
> + *size may get modified and return a value smaller than
> + *what was requested.
> + * @lock: wether to lock the mapping in xen-mapcache until invalidated.
> + * @is_write: hint wether to map RW or RO in the xen-mapcache.
> + *(optional and may always be set to true).
>   *
>   * Called within RCU critical section.
>   */
>  static void *qemu_ram_ptr_length(RAMBlock *block, ram_addr_t addr,
> - hwaddr *size, bool lock)
> + hwaddr *size, bool lock,
> + bool is_write)
>  {
>  hwaddr len = 0;
>  
> @@ -2217,10 +2228,13 @@ static void *qemu_ram_ptr_length(RAMBlock *block, 
> ram_addr_t addr,
>   * In that case just map the requested area.
>   */
>  if (block->offset == 0) {
> -return xen_map_cache(addr, len, lock, lock);
> +return xen_map_cache(block->mr, addr, len, lock, lock,
> + is_write);
>  }
>  
> -block->host = xen_map_cache(block->offset, block->max_length, 1, 
> lock);
> +block->host = xen_map_cache(block->mr, block->offset,
> +block->max_length, 1,
> +lo

Re: [PATCH v4 12/17] xen: mapcache: Unmap first entries in buckets

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> When invalidating memory ranges, if we happen to hit the first
> entry in a bucket we were never unmapping it. This was harmless
> for foreign mappings but now that we're looking to reuse the
> mapcache for transient grant mappings, we must unmap entries
> when invalidated.
> 
> Signed-off-by: Edgar E. Iglesias 

Reviewed-by: Stefano Stabellini 


> ---
>  hw/xen/xen-mapcache.c | 12 
>  1 file changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
> index 4f98d284dd..0365311788 100644
> --- a/hw/xen/xen-mapcache.c
> +++ b/hw/xen/xen-mapcache.c
> @@ -486,18 +486,22 @@ static void 
> xen_invalidate_map_cache_entry_unlocked(MapCache *mc,
>  return;
>  }
>  entry->lock--;
> -if (entry->lock > 0 || pentry == NULL) {
> +if (entry->lock > 0) {
>  return;
>  }
>  
> -pentry->next = entry->next;
>  ram_block_notify_remove(entry->vaddr_base, entry->size, entry->size);
>  if (munmap(entry->vaddr_base, entry->size) != 0) {
>  perror("unmap fails");
>  exit(-1);
>  }
> -g_free(entry->valid_mapping);
> -g_free(entry);
> +if (pentry) {
> +pentry->next = entry->next;
> +g_free(entry->valid_mapping);
> +g_free(entry);
> +} else {
> +memset(entry, 0, sizeof *entry);
> +}
>  }
>  
>  typedef struct XenMapCacheData {
> -- 
> 2.40.1
> 



Re: [PATCH v4 11/17] xen: mapcache: Make MCACHE_BUCKET_SHIFT runtime configurable

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> Make MCACHE_BUCKET_SHIFT runtime configurable per cache instance.
> 
> Signed-off-by: Edgar E. Iglesias 

Reviewed-by: Stefano Stabellini 


> ---
>  hw/xen/xen-mapcache.c | 52 ++-
>  1 file changed, 31 insertions(+), 21 deletions(-)
> 
> diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
> index 72a7e25e3e..4f98d284dd 100644
> --- a/hw/xen/xen-mapcache.c
> +++ b/hw/xen/xen-mapcache.c
> @@ -23,13 +23,10 @@
>  
>  
>  #if HOST_LONG_BITS == 32
> -#  define MCACHE_BUCKET_SHIFT 16
>  #  define MCACHE_MAX_SIZE (1UL<<31) /* 2GB Cap */
>  #else
> -#  define MCACHE_BUCKET_SHIFT 20
>  #  define MCACHE_MAX_SIZE (1UL<<35) /* 32GB Cap */
>  #endif
> -#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT)
>  
>  /* This is the size of the virtual address space reserve to QEMU that will 
> not
>   * be use by MapCache.
> @@ -65,7 +62,8 @@ typedef struct MapCache {
>  /* For most cases (>99.9%), the page address is the same. */
>  MapCacheEntry *last_entry;
>  unsigned long max_mcache_size;
> -unsigned int mcache_bucket_shift;
> +unsigned int bucket_shift;
> +unsigned long bucket_size;
>  
>  phys_offset_to_gaddr_t phys_offset_to_gaddr;
>  QemuMutex lock;
> @@ -95,6 +93,7 @@ static inline int test_bits(int nr, int size, const 
> unsigned long *addr)
>  
>  static MapCache *xen_map_cache_init_single(phys_offset_to_gaddr_t f,
> void *opaque,
> +   unsigned int bucket_shift,
> unsigned long max_size)
>  {
>  unsigned long size;
> @@ -108,12 +107,14 @@ static MapCache 
> *xen_map_cache_init_single(phys_offset_to_gaddr_t f,
>  
>  QTAILQ_INIT(&mc->locked_entries);
>  
> +mc->bucket_shift = bucket_shift;
> +mc->bucket_size = 1UL << bucket_shift;
>  mc->max_mcache_size = max_size;
>  
>  mc->nr_buckets =
>  (((mc->max_mcache_size >> XC_PAGE_SHIFT) +
> -  (1UL << (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT)) - 1) >>
> - (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT));
> +  (1UL << (bucket_shift - XC_PAGE_SHIFT)) - 1) >>
> + (bucket_shift - XC_PAGE_SHIFT));
>  
>  size = mc->nr_buckets * sizeof(MapCacheEntry);
>  size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
> @@ -126,6 +127,13 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void 
> *opaque)
>  {
>  struct rlimit rlimit_as;
>  unsigned long max_mcache_size;
> +unsigned int bucket_shift;
> +
> +if (HOST_LONG_BITS == 32) {
> +bucket_shift = 16;
> +} else {
> +bucket_shift = 20;
> +}
>  
>  if (geteuid() == 0) {
>  rlimit_as.rlim_cur = RLIM_INFINITY;
> @@ -146,7 +154,9 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void 
> *opaque)
>  }
>  }
>  
> -mapcache = xen_map_cache_init_single(f, opaque, max_mcache_size);
> +mapcache = xen_map_cache_init_single(f, opaque,
> + bucket_shift,
> + max_mcache_size);
>  setrlimit(RLIMIT_AS, &rlimit_as);
>  }
>  
> @@ -195,7 +205,7 @@ static void xen_remap_bucket(MapCache *mc,
>  entry->valid_mapping = NULL;
>  
>  for (i = 0; i < nb_pfn; i++) {
> -pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-XC_PAGE_SHIFT)) + i;
> +pfns[i] = (address_index << (mc->bucket_shift - XC_PAGE_SHIFT)) + i;
>  }
>  
>  /*
> @@ -266,8 +276,8 @@ static uint8_t *xen_map_cache_unlocked(MapCache *mc,
>  bool dummy = false;
>  
>  tryagain:
> -address_index  = phys_addr >> MCACHE_BUCKET_SHIFT;
> -address_offset = phys_addr & (MCACHE_BUCKET_SIZE - 1);
> +address_index  = phys_addr >> mc->bucket_shift;
> +address_offset = phys_addr & (mc->bucket_size - 1);
>  
>  trace_xen_map_cache(phys_addr);
>  
> @@ -294,14 +304,14 @@ tryagain:
>  return mc->last_entry->vaddr_base + address_offset;
>  }
>  
> -/* size is always a multiple of MCACHE_BUCKET_SIZE */
> +/* size is always a multiple of mc->bucket_size */
>  if (size) {
>  cache_size = size + address_offset;
> -if (cache_size % MCACHE_BUCKET_SIZE) {
> -cache_size += MCACHE_BUCKET_SIZE - (cache_size % 
> MCACHE_BUCKET_SIZE);
> +if (cache_size % mc->bucket_size) {
> +cache_size += mc->bucket_size - (cache_size % mc->bucket_size);
>  }
>  } else {
> -cache_size = MCACHE_BUCKET_SIZE;
> +cache_size = mc->bucket_size;
>  }
>  
>  entry = &mc->entry[address_index % mc->nr_buckets];
> @@ -419,7 +429,7 @@ static ram_addr_t 
> xen_ram_addr_from_mapcache_single(MapCache *mc, void *ptr)
>  trace_xen_ram_addr_from_mapcache_not_in_cache(ptr);
>  raddr = RAM_ADDR_INVALID;
>  } else {
> -raddr = (reventry->paddr_index << MCACHE_BUCKET_

Re: [PATCH v4 10/17] xen: mapcache: Break out xen_map_cache_init_single()

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> Break out xen_map_cache_init_single() in preparation for
> adding multiple map caches.
> 
> Signed-off-by: Edgar E. Iglesias 

Reviewed-by: Stefano Stabellini 


> ---
>  hw/xen/xen-mapcache.c | 53 ++-
>  1 file changed, 32 insertions(+), 21 deletions(-)
> 
> diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
> index dd08cd296b..72a7e25e3e 100644
> --- a/hw/xen/xen-mapcache.c
> +++ b/hw/xen/xen-mapcache.c
> @@ -93,23 +93,44 @@ static inline int test_bits(int nr, int size, const 
> unsigned long *addr)
>  return 0;
>  }
>  
> -void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
> +static MapCache *xen_map_cache_init_single(phys_offset_to_gaddr_t f,
> +   void *opaque,
> +   unsigned long max_size)
>  {
>  unsigned long size;
> -struct rlimit rlimit_as;
> +MapCache *mc;
> +
> +mc = g_new0(MapCache, 1);
> +
> +mc->phys_offset_to_gaddr = f;
> +mc->opaque = opaque;
> +qemu_mutex_init(&mc->lock);
> +
> +QTAILQ_INIT(&mc->locked_entries);
>  
> -mapcache = g_new0(MapCache, 1);
> +mc->max_mcache_size = max_size;
>  
> -mapcache->phys_offset_to_gaddr = f;
> -mapcache->opaque = opaque;
> -qemu_mutex_init(&mapcache->lock);
> +mc->nr_buckets =
> +(((mc->max_mcache_size >> XC_PAGE_SHIFT) +
> +  (1UL << (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT)) - 1) >>
> + (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT));
>  
> -QTAILQ_INIT(&mapcache->locked_entries);
> +size = mc->nr_buckets * sizeof(MapCacheEntry);
> +size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
> +trace_xen_map_cache_init(mc->nr_buckets, size);
> +mc->entry = g_malloc0(size);
> +return mc;
> +}
> +
> +void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
> +{
> +struct rlimit rlimit_as;
> +unsigned long max_mcache_size;
>  
>  if (geteuid() == 0) {
>  rlimit_as.rlim_cur = RLIM_INFINITY;
>  rlimit_as.rlim_max = RLIM_INFINITY;
> -mapcache->max_mcache_size = MCACHE_MAX_SIZE;
> +max_mcache_size = MCACHE_MAX_SIZE;
>  } else {
>  getrlimit(RLIMIT_AS, &rlimit_as);
>  rlimit_as.rlim_cur = rlimit_as.rlim_max;
> @@ -119,24 +140,14 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void 
> *opaque)
>  " memory is not infinity");
>  }
>  if (rlimit_as.rlim_max < MCACHE_MAX_SIZE + NON_MCACHE_MEMORY_SIZE) {
> -mapcache->max_mcache_size = rlimit_as.rlim_max -
> -NON_MCACHE_MEMORY_SIZE;
> +max_mcache_size = rlimit_as.rlim_max - NON_MCACHE_MEMORY_SIZE;
>  } else {
> -mapcache->max_mcache_size = MCACHE_MAX_SIZE;
> +max_mcache_size = MCACHE_MAX_SIZE;
>  }
>  }
>  
> +mapcache = xen_map_cache_init_single(f, opaque, max_mcache_size);
>  setrlimit(RLIMIT_AS, &rlimit_as);
> -
> -mapcache->nr_buckets =
> -(((mapcache->max_mcache_size >> XC_PAGE_SHIFT) +
> -  (1UL << (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT)) - 1) >>
> - (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT));
> -
> -size = mapcache->nr_buckets * sizeof (MapCacheEntry);
> -size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
> -trace_xen_map_cache_init(mapcache->nr_buckets, size);
> -mapcache->entry = g_malloc0(size);
>  }
>  
>  static void xen_remap_bucket(MapCache *mc,
> -- 
> 2.40.1
> 



Re: [PATCH v4 09/17] xen: mapcache: Break out xen_invalidate_map_cache_single()

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> Break out xen_invalidate_map_cache_single().
> 
> No functional changes.
> 
> Signed-off-by: Edgar E. Iglesias 

Reviewed-by: Stefano Stabellini 


> ---
>  hw/xen/xen-mapcache.c | 25 +++--
>  1 file changed, 15 insertions(+), 10 deletions(-)
> 
> diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
> index 34454da2f6..dd08cd296b 100644
> --- a/hw/xen/xen-mapcache.c
> +++ b/hw/xen/xen-mapcache.c
> @@ -512,17 +512,14 @@ void coroutine_mixed_fn 
> xen_invalidate_map_cache_entry(uint8_t *buffer)
>  }
>  }
>  
> -void xen_invalidate_map_cache(void)
> +static void xen_invalidate_map_cache_single(MapCache *mc)
>  {
>  unsigned long i;
>  MapCacheRev *reventry;
>  
> -/* Flush pending AIO before destroying the mapcache */
> -bdrv_drain_all();
> -
> -mapcache_lock(mapcache);
> +mapcache_lock(mc);
>  
> -QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
> +QTAILQ_FOREACH(reventry, &mc->locked_entries, next) {
>  if (!reventry->dma) {
>  continue;
>  }
> @@ -530,8 +527,8 @@ void xen_invalidate_map_cache(void)
> reventry->vaddr_req);
>  }
>  
> -for (i = 0; i < mapcache->nr_buckets; i++) {
> -MapCacheEntry *entry = &mapcache->entry[i];
> +for (i = 0; i < mc->nr_buckets; i++) {
> +MapCacheEntry *entry = &mc->entry[i];
>  
>  if (entry->vaddr_base == NULL) {
>  continue;
> @@ -552,9 +549,17 @@ void xen_invalidate_map_cache(void)
>  entry->valid_mapping = NULL;
>  }
>  
> -mapcache->last_entry = NULL;
> +mc->last_entry = NULL;
>  
> -mapcache_unlock(mapcache);
> +mapcache_unlock(mc);
> +}
> +
> +void xen_invalidate_map_cache(void)
> +{
> +/* Flush pending AIO before destroying the mapcache */
> +bdrv_drain_all();
> +
> +xen_invalidate_map_cache_single(mapcache);
>  }
>  
>  static uint8_t *xen_replace_cache_entry_unlocked(MapCache *mc,
> -- 
> 2.40.1
> 



Re: [PATCH v4 08/17] xen: mapcache: Refactor xen_invalidate_map_cache_entry_unlocked

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> Add MapCache argument to xen_invalidate_map_cache_entry_unlocked.
> This is in preparation for supporting multiple map caches.
> 
> No functional changes.
> 
> Signed-off-by: Edgar E. Iglesias 

Reviewed-by: Stefano Stabellini 


> ---
>  hw/xen/xen-mapcache.c | 21 +++--
>  1 file changed, 11 insertions(+), 10 deletions(-)
> 
> diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
> index 6e758eff94..34454da2f6 100644
> --- a/hw/xen/xen-mapcache.c
> +++ b/hw/xen/xen-mapcache.c
> @@ -420,7 +420,8 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
>  return xen_ram_addr_from_mapcache_single(mapcache, ptr);
>  }
>  
> -static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
> +static void xen_invalidate_map_cache_entry_unlocked(MapCache *mc,
> +uint8_t *buffer)
>  {
>  MapCacheEntry *entry = NULL, *pentry = NULL;
>  MapCacheRev *reventry;
> @@ -428,7 +429,7 @@ static void 
> xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
>  hwaddr size;
>  int found = 0;
>  
> -QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
> +QTAILQ_FOREACH(reventry, &mc->locked_entries, next) {
>  if (reventry->vaddr_req == buffer) {
>  paddr_index = reventry->paddr_index;
>  size = reventry->size;
> @@ -438,7 +439,7 @@ static void 
> xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
>  }
>  if (!found) {
>  trace_xen_invalidate_map_cache_entry_unlocked_not_found(buffer);
> -QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
> +QTAILQ_FOREACH(reventry, &mc->locked_entries, next) {
>  trace_xen_invalidate_map_cache_entry_unlocked_found(
>  reventry->paddr_index,
>  reventry->vaddr_req
> @@ -446,15 +447,15 @@ static void 
> xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
>  }
>  return;
>  }
> -QTAILQ_REMOVE(&mapcache->locked_entries, reventry, next);
> +QTAILQ_REMOVE(&mc->locked_entries, reventry, next);
>  g_free(reventry);
>  
> -if (mapcache->last_entry != NULL &&
> -mapcache->last_entry->paddr_index == paddr_index) {
> -mapcache->last_entry = NULL;
> +if (mc->last_entry != NULL &&
> +mc->last_entry->paddr_index == paddr_index) {
> +mc->last_entry = NULL;
>  }
>  
> -entry = &mapcache->entry[paddr_index % mapcache->nr_buckets];
> +entry = &mc->entry[paddr_index % mc->nr_buckets];
>  while (entry && (entry->paddr_index != paddr_index || entry->size != 
> size)) {
>  pentry = entry;
>  entry = entry->next;
> @@ -488,7 +489,7 @@ static void xen_invalidate_map_cache_entry_bh(void 
> *opaque)
>  XenMapCacheData *data = opaque;
>  
>  mapcache_lock(mapcache);
> -xen_invalidate_map_cache_entry_unlocked(data->buffer);
> +xen_invalidate_map_cache_entry_unlocked(mapcache, data->buffer);
>  mapcache_unlock(mapcache);
>  
>  aio_co_wake(data->co);
> @@ -506,7 +507,7 @@ void coroutine_mixed_fn 
> xen_invalidate_map_cache_entry(uint8_t *buffer)
>  qemu_coroutine_yield();
>  } else {
>  mapcache_lock(mapcache);
> -xen_invalidate_map_cache_entry_unlocked(buffer);
> +xen_invalidate_map_cache_entry_unlocked(mapcache, buffer);
>  mapcache_unlock(mapcache);
>  }
>  }
> -- 
> 2.40.1
> 



Re: [PATCH v4 07/17] xen: mapcache: Refactor xen_replace_cache_entry_unlocked

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> Add MapCache argument to xen_replace_cache_entry_unlocked in
> preparation for supporting multiple map caches.
> 
> No functional change.
> 
> Signed-off-by: Edgar E. Iglesias 
> ---
>  hw/xen/xen-mapcache.c | 8 +---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
> index d2deff70c8..6e758eff94 100644
> --- a/hw/xen/xen-mapcache.c
> +++ b/hw/xen/xen-mapcache.c
> @@ -556,7 +556,8 @@ void xen_invalidate_map_cache(void)
>  mapcache_unlock(mapcache);
>  }
>  
> -static uint8_t *xen_replace_cache_entry_unlocked(hwaddr old_phys_addr,
> +static uint8_t *xen_replace_cache_entry_unlocked(MapCache *mc,
> + hwaddr old_phys_addr,
>   hwaddr new_phys_addr,
>   hwaddr size)
>  {
> @@ -578,7 +579,7 @@ static uint8_t *xen_replace_cache_entry_unlocked(hwaddr 
> old_phys_addr,
>  cache_size += MCACHE_BUCKET_SIZE - (cache_size % MCACHE_BUCKET_SIZE);
>  }
>  
> -entry = &mapcache->entry[address_index % mapcache->nr_buckets];
> +entry = &mc->entry[address_index % mc->nr_buckets];
>  while (entry && !(entry->paddr_index == address_index &&
>entry->size == cache_size)) {
>  entry = entry->next;

There is still a global mapcache pointer in use in this function:

  xen_remap_bucket(mapcache, entry, entry->vaddr_base,


> @@ -614,7 +615,8 @@ uint8_t *xen_replace_cache_entry(hwaddr old_phys_addr,
>  uint8_t *p;
>  
>  mapcache_lock(mapcache);
> -p = xen_replace_cache_entry_unlocked(old_phys_addr, new_phys_addr, size);
> +p = xen_replace_cache_entry_unlocked(mapcache, old_phys_addr,
> + new_phys_addr, size);
>  mapcache_unlock(mapcache);
>  return p;
>  }
> -- 
> 2.40.1
> 



Re: [PATCH v4 06/17] xen: mapcache: Break out xen_ram_addr_from_mapcache_single

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> Break out xen_ram_addr_from_mapcache_single(), a multi-cache
> aware version of xen_ram_addr_from_mapcache.
> 
> No functional changes.
> 
> Signed-off-by: Edgar E. Iglesias 

Reviewed-by: Stefano Stabellini 


> ---
>  hw/xen/xen-mapcache.c | 17 +++--
>  1 file changed, 11 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
> index 326a9b61ca..d2deff70c8 100644
> --- a/hw/xen/xen-mapcache.c
> +++ b/hw/xen/xen-mapcache.c
> @@ -377,7 +377,7 @@ uint8_t *xen_map_cache(hwaddr phys_addr, hwaddr size,
>  return p;
>  }
>  
> -ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
> +static ram_addr_t xen_ram_addr_from_mapcache_single(MapCache *mc, void *ptr)
>  {
>  MapCacheEntry *entry = NULL;
>  MapCacheRev *reventry;
> @@ -386,8 +386,8 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
>  ram_addr_t raddr;
>  int found = 0;
>  
> -mapcache_lock(mapcache);
> -QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
> +mapcache_lock(mc);
> +QTAILQ_FOREACH(reventry, &mc->locked_entries, next) {
>  if (reventry->vaddr_req == ptr) {
>  paddr_index = reventry->paddr_index;
>  size = reventry->size;
> @@ -396,11 +396,11 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
>  }
>  }
>  if (!found) {
> -mapcache_unlock(mapcache);
> +mapcache_unlock(mc);
>  return RAM_ADDR_INVALID;
>  }
>  
> -entry = &mapcache->entry[paddr_index % mapcache->nr_buckets];
> +entry = &mc->entry[paddr_index % mc->nr_buckets];
>  while (entry && (entry->paddr_index != paddr_index || entry->size != 
> size)) {
>  entry = entry->next;
>  }
> @@ -411,10 +411,15 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
>  raddr = (reventry->paddr_index << MCACHE_BUCKET_SHIFT) +
>   ((unsigned long) ptr - (unsigned long) entry->vaddr_base);
>  }
> -mapcache_unlock(mapcache);
> +mapcache_unlock(mc);
>  return raddr;
>  }
>  
> +ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
> +{
> +return xen_ram_addr_from_mapcache_single(mapcache, ptr);
> +}
> +
>  static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
>  {
>  MapCacheEntry *entry = NULL, *pentry = NULL;
> -- 
> 2.40.1
> 



Re: [PATCH v4 05/17] xen: mapcache: Refactor xen_remap_bucket for multi-instance

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> Add MapCache argument to xen_remap_bucket in preparation
> to support multiple map caches.
> 
> No functional changes.
> 
> Signed-off-by: Edgar E. Iglesias 

Reviewed-by: Stefano Stabellini 


> ---
>  hw/xen/xen-mapcache.c | 9 +
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
> index 896021d86f..326a9b61ca 100644
> --- a/hw/xen/xen-mapcache.c
> +++ b/hw/xen/xen-mapcache.c
> @@ -139,7 +139,8 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void 
> *opaque)
>  mapcache->entry = g_malloc0(size);
>  }
>  
> -static void xen_remap_bucket(MapCacheEntry *entry,
> +static void xen_remap_bucket(MapCache *mc,
> + MapCacheEntry *entry,
>   void *vaddr,
>   hwaddr size,
>   hwaddr address_index,
> @@ -313,14 +314,14 @@ tryagain:
>  if (!entry) {
>  entry = g_new0(MapCacheEntry, 1);
>  pentry->next = entry;
> -xen_remap_bucket(entry, NULL, cache_size, address_index, dummy);
> +xen_remap_bucket(mc, entry, NULL, cache_size, address_index, dummy);
>  } else if (!entry->lock) {
>  if (!entry->vaddr_base || entry->paddr_index != address_index ||
>  entry->size != cache_size ||
>  !test_bits(address_offset >> XC_PAGE_SHIFT,
>  test_bit_size >> XC_PAGE_SHIFT,
>  entry->valid_mapping)) {
> -xen_remap_bucket(entry, NULL, cache_size, address_index, dummy);
> +xen_remap_bucket(mc, entry, NULL, cache_size, address_index, 
> dummy);
>  }
>  }
>  
> @@ -587,7 +588,7 @@ static uint8_t *xen_replace_cache_entry_unlocked(hwaddr 
> old_phys_addr,
>  
>  trace_xen_replace_cache_entry_dummy(old_phys_addr, new_phys_addr);
>  
> -xen_remap_bucket(entry, entry->vaddr_base,
> +xen_remap_bucket(mapcache, entry, entry->vaddr_base,
>   cache_size, address_index, false);
>  if (!test_bits(address_offset >> XC_PAGE_SHIFT,
>  test_bit_size >> XC_PAGE_SHIFT,
> -- 
> 2.40.1
> 



Re: [PATCH v4 04/17] xen: mapcache: Refactor xen_map_cache for multi-instance

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> Make xen_map_cache take a MapCache as argument. This is in
> prepaparation to support multiple map caches.
> 
> No functional changes.
> 
> Signed-off-by: Edgar E. Iglesias 

Reviewed-by: Stefano Stabellini 


> ---
>  hw/xen/xen-mapcache.c | 35 ++-
>  1 file changed, 18 insertions(+), 17 deletions(-)
> 
> diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
> index 3f11562075..896021d86f 100644
> --- a/hw/xen/xen-mapcache.c
> +++ b/hw/xen/xen-mapcache.c
> @@ -240,7 +240,8 @@ static void xen_remap_bucket(MapCacheEntry *entry,
>  g_free(err);
>  }
>  
> -static uint8_t *xen_map_cache_unlocked(hwaddr phys_addr, hwaddr size,
> +static uint8_t *xen_map_cache_unlocked(MapCache *mc,
> +   hwaddr phys_addr, hwaddr size,
> uint8_t lock, bool dma)
>  {
>  MapCacheEntry *entry, *pentry = NULL,
> @@ -269,16 +270,16 @@ tryagain:
>  test_bit_size = XC_PAGE_SIZE;
>  }
>  
> -if (mapcache->last_entry != NULL &&
> -mapcache->last_entry->paddr_index == address_index &&
> +if (mc->last_entry != NULL &&
> +mc->last_entry->paddr_index == address_index &&
>  !lock && !size &&
>  test_bits(address_offset >> XC_PAGE_SHIFT,
>test_bit_size >> XC_PAGE_SHIFT,
> -  mapcache->last_entry->valid_mapping)) {
> +  mc->last_entry->valid_mapping)) {
>  trace_xen_map_cache_return(
> -mapcache->last_entry->vaddr_base + address_offset
> +mc->last_entry->vaddr_base + address_offset
>  );
> -return mapcache->last_entry->vaddr_base + address_offset;
> +return mc->last_entry->vaddr_base + address_offset;
>  }
>  
>  /* size is always a multiple of MCACHE_BUCKET_SIZE */
> @@ -291,7 +292,7 @@ tryagain:
>  cache_size = MCACHE_BUCKET_SIZE;
>  }
>  
> -entry = &mapcache->entry[address_index % mapcache->nr_buckets];
> +entry = &mc->entry[address_index % mc->nr_buckets];
>  
>  while (entry && (lock || entry->lock) && entry->vaddr_base &&
>  (entry->paddr_index != address_index || entry->size != 
> cache_size ||
> @@ -326,10 +327,10 @@ tryagain:
>  if(!test_bits(address_offset >> XC_PAGE_SHIFT,
>  test_bit_size >> XC_PAGE_SHIFT,
>  entry->valid_mapping)) {
> -mapcache->last_entry = NULL;
> +mc->last_entry = NULL;
>  #ifdef XEN_COMPAT_PHYSMAP
> -if (!translated && mapcache->phys_offset_to_gaddr) {
> -phys_addr = mapcache->phys_offset_to_gaddr(phys_addr, size);
> +if (!translated && mc->phys_offset_to_gaddr) {
> +phys_addr = mc->phys_offset_to_gaddr(phys_addr, size);
>  translated = true;
>  goto tryagain;
>  }
> @@ -342,7 +343,7 @@ tryagain:
>  return NULL;
>  }
>  
> -mapcache->last_entry = entry;
> +mc->last_entry = entry;
>  if (lock) {
>  MapCacheRev *reventry = g_new0(MapCacheRev, 1);
>  entry->lock++;
> @@ -352,16 +353,16 @@ tryagain:
>  abort();
>  }
>  reventry->dma = dma;
> -reventry->vaddr_req = mapcache->last_entry->vaddr_base + 
> address_offset;
> -reventry->paddr_index = mapcache->last_entry->paddr_index;
> +reventry->vaddr_req = mc->last_entry->vaddr_base + address_offset;
> +reventry->paddr_index = mc->last_entry->paddr_index;
>  reventry->size = entry->size;
> -QTAILQ_INSERT_HEAD(&mapcache->locked_entries, reventry, next);
> +QTAILQ_INSERT_HEAD(&mc->locked_entries, reventry, next);
>  }
>  
>  trace_xen_map_cache_return(
> -mapcache->last_entry->vaddr_base + address_offset
> +mc->last_entry->vaddr_base + address_offset
>  );
> -return mapcache->last_entry->vaddr_base + address_offset;
> +return mc->last_entry->vaddr_base + address_offset;
>  }
>  
>  uint8_t *xen_map_cache(hwaddr phys_addr, hwaddr size,
> @@ -370,7 +371,7 @@ uint8_t *xen_map_cache(hwaddr phys_addr, hwaddr size,
>  uint8_t *p;
>  
>  mapcache_lock(mapcache);
> -p = xen_map_cache_unlocked(phys_addr, size, lock, dma);
> +p = xen_map_cache_unlocked(mapcache, phys_addr, size, lock, dma);
>  mapcache_unlock(mapcache);
>  return p;
>  }
> -- 
> 2.40.1
> 



Re: [PATCH v4 03/17] xen: mapcache: Refactor lock functions for multi-instance

2024-05-01 Thread Stefano Stabellini
On Tue, 30 Apr 2024, Edgar E. Iglesias wrote:
> From: "Edgar E. Iglesias" 
> 
> Make the lock functions take MapCache * as argument. This is
> in preparation for supporting multiple caches.
> 
> No functional changes.
> 
> Signed-off-by: Edgar E. Iglesias 

Reviewed-by: Stefano Stabellini 


> ---
>  hw/xen/xen-mapcache.c | 34 +-
>  1 file changed, 17 insertions(+), 17 deletions(-)
> 
> diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
> index b7cefb78f7..3f11562075 100644
> --- a/hw/xen/xen-mapcache.c
> +++ b/hw/xen/xen-mapcache.c
> @@ -74,14 +74,14 @@ typedef struct MapCache {
>  
>  static MapCache *mapcache;
>  
> -static inline void mapcache_lock(void)
> +static inline void mapcache_lock(MapCache *mc)
>  {
> -qemu_mutex_lock(&mapcache->lock);
> +qemu_mutex_lock(&mc->lock);
>  }
>  
> -static inline void mapcache_unlock(void)
> +static inline void mapcache_unlock(MapCache *mc)
>  {
> -qemu_mutex_unlock(&mapcache->lock);
> +qemu_mutex_unlock(&mc->lock);
>  }
>  
>  static inline int test_bits(int nr, int size, const unsigned long *addr)
> @@ -369,9 +369,9 @@ uint8_t *xen_map_cache(hwaddr phys_addr, hwaddr size,
>  {
>  uint8_t *p;
>  
> -mapcache_lock();
> +mapcache_lock(mapcache);
>  p = xen_map_cache_unlocked(phys_addr, size, lock, dma);
> -mapcache_unlock();
> +mapcache_unlock(mapcache);
>  return p;
>  }
>  
> @@ -384,7 +384,7 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
>  ram_addr_t raddr;
>  int found = 0;
>  
> -mapcache_lock();
> +mapcache_lock(mapcache);
>  QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
>  if (reventry->vaddr_req == ptr) {
>  paddr_index = reventry->paddr_index;
> @@ -394,7 +394,7 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
>  }
>  }
>  if (!found) {
> -mapcache_unlock();
> +mapcache_unlock(mapcache);
>  return RAM_ADDR_INVALID;
>  }
>  
> @@ -409,7 +409,7 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
>  raddr = (reventry->paddr_index << MCACHE_BUCKET_SHIFT) +
>   ((unsigned long) ptr - (unsigned long) entry->vaddr_base);
>  }
> -mapcache_unlock();
> +mapcache_unlock(mapcache);
>  return raddr;
>  }
>  
> @@ -480,9 +480,9 @@ static void xen_invalidate_map_cache_entry_bh(void 
> *opaque)
>  {
>  XenMapCacheData *data = opaque;
>  
> -mapcache_lock();
> +mapcache_lock(mapcache);
>  xen_invalidate_map_cache_entry_unlocked(data->buffer);
> -mapcache_unlock();
> +mapcache_unlock(mapcache);
>  
>  aio_co_wake(data->co);
>  }
> @@ -498,9 +498,9 @@ void coroutine_mixed_fn 
> xen_invalidate_map_cache_entry(uint8_t *buffer)
>  xen_invalidate_map_cache_entry_bh, &data);
>  qemu_coroutine_yield();
>  } else {
> -mapcache_lock();
> +mapcache_lock(mapcache);
>  xen_invalidate_map_cache_entry_unlocked(buffer);
> -mapcache_unlock();
> +mapcache_unlock(mapcache);
>  }
>  }
>  
> @@ -512,7 +512,7 @@ void xen_invalidate_map_cache(void)
>  /* Flush pending AIO before destroying the mapcache */
>  bdrv_drain_all();
>  
> -mapcache_lock();
> +mapcache_lock(mapcache);
>  
>  QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
>  if (!reventry->dma) {
> @@ -546,7 +546,7 @@ void xen_invalidate_map_cache(void)
>  
>  mapcache->last_entry = NULL;
>  
> -mapcache_unlock();
> +mapcache_unlock(mapcache);
>  }
>  
>  static uint8_t *xen_replace_cache_entry_unlocked(hwaddr old_phys_addr,
> @@ -606,8 +606,8 @@ uint8_t *xen_replace_cache_entry(hwaddr old_phys_addr,
>  {
>  uint8_t *p;
>  
> -mapcache_lock();
> +mapcache_lock(mapcache);
>  p = xen_replace_cache_entry_unlocked(old_phys_addr, new_phys_addr, size);
> -mapcache_unlock();
> +mapcache_unlock(mapcache);
>  return p;
>  }
> -- 
> 2.40.1
> 



Re: [PATCH v4 00/14] Use Intel DSA accelerator to offload zero page checking in multifd live migration.

2024-05-01 Thread Peter Xu
On Thu, Apr 25, 2024 at 02:21:03AM +, Hao Xiang wrote:
> 7. Added a new migration option multifd-normal-page-ratio to make
> multifd live migration easier to test. Setting a normal page ratio will
> make live migration recognize a zero page as a normal page and send
> the entire payload over the network. If we want to send a large network
> payload and analyze throughput, this option is useful.

I didn't see this when quickly going through the series.  It's even
mentioned in test results later.  Is it removed?

Thanks,

-- 
Peter Xu




Re: [PATCH v9 09/11] virtio-gpu: Register capsets dynamically

2024-05-01 Thread Dmitry Osipenko
On 5/1/24 22:38, Dmitry Osipenko wrote:
> On 5/1/24 22:31, Dmitry Osipenko wrote:
>> On 4/27/24 10:12, Akihiko Odaki wrote:
   int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g)
   {
   uint32_t capset2_max_ver, capset2_max_size;
 +
 +    if (g->capset_ids) {
>>>
>>> Move capset_ids initialization to virtio_gpu_virgl_init() to save this
>>> conditional.
>>
>> Capsets are used before virgl is inited. At first guest queries virtio
>> device features and then enables virgl only if capset is available.
>> While virgl itself is initialized when first virtio command is
>> processed. I.e. it's not possible to move to virtio_gpu_virgl_init.
> 
> Though no, capsets aren't part of device features. I'll move it to
> virtio_gpu_virgl_init, thanks.
> 

Number of capsets actually is a part of generic virtio device cfg
descriptor. Capsets initialization can't be moved without probing
capsets twice, i.e. not worthwhile.

-- 
Best regards,
Dmitry




Re: [PATCH v9 09/11] virtio-gpu: Register capsets dynamically

2024-05-01 Thread Dmitry Osipenko
On 5/1/24 22:31, Dmitry Osipenko wrote:
> On 4/27/24 10:12, Akihiko Odaki wrote:
>>>   int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g)
>>>   {
>>>   uint32_t capset2_max_ver, capset2_max_size;
>>> +
>>> +    if (g->capset_ids) {
>>
>> Move capset_ids initialization to virtio_gpu_virgl_init() to save this
>> conditional.
> 
> Capsets are used before virgl is inited. At first guest queries virtio
> device features and then enables virgl only if capset is available.
> While virgl itself is initialized when first virtio command is
> processed. I.e. it's not possible to move to virtio_gpu_virgl_init.

Though no, capsets aren't part of device features. I'll move it to
virtio_gpu_virgl_init, thanks.

-- 
Best regards,
Dmitry




Re: [PATCH v4 11/14] migration/multifd: Add migration option set packet size.

2024-05-01 Thread Peter Xu
On Thu, Apr 25, 2024 at 02:21:14AM +, Hao Xiang wrote:
> The current multifd packet size is 128 * 4kb. This change adds
> an option to set the packet size. Both sender and receiver needs
> to set the same packet size for things to work.
> 
> Signed-off-by: Hao Xiang 
> ---
>  migration/options.c | 36 
>  migration/options.h |  1 +
>  qapi/migration.json | 21 ++---
>  3 files changed, 55 insertions(+), 3 deletions(-)
> 
> diff --git a/migration/options.c b/migration/options.c
> index dc8642df81..a9deb079eb 100644
> --- a/migration/options.c
> +++ b/migration/options.c
> @@ -79,6 +79,12 @@
>  #define DEFAULT_MIGRATE_ANNOUNCE_ROUNDS5
>  #define DEFAULT_MIGRATE_ANNOUNCE_STEP100
>  
> +/*
> + * Parameter for multifd packet size.
> + */
> +#define DEFAULT_MIGRATE_MULTIFD_PACKET_SIZE (128 * 4 * 1024)
> +#define MAX_MIGRATE_MULTIFD_PACKET_SIZE (1023 * 4 * 1024)
> +
>  #define DEFINE_PROP_MIG_CAP(name, x) \
>  DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false)
>  
> @@ -184,6 +190,9 @@ Property migration_properties[] = {
> ZERO_PAGE_DETECTION_MULTIFD),
>  DEFINE_PROP_STRING("multifd-dsa-accel", MigrationState,
> parameters.multifd_dsa_accel),
> +DEFINE_PROP_SIZE("multifd-packet-size", MigrationState,
> + parameters.multifd_packet_size,
> + DEFAULT_MIGRATE_MULTIFD_PACKET_SIZE),

Having such knob looks all fine, but I feel like this patch is half-baked,
no?  There seems to have another part in the next patch.  Maybe they need
to be squashed together.

>  
>  /* Migration capabilities */
>  DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE),
> @@ -879,6 +888,13 @@ int migrate_multifd_channels(void)
>  return s->parameters.multifd_channels;
>  }
>  
> +uint64_t migrate_multifd_packet_size(void)
> +{
> +MigrationState *s = migrate_get_current();
> +
> +return s->parameters.multifd_packet_size;
> +}
> +
>  MultiFDCompression migrate_multifd_compression(void)
>  {
>  MigrationState *s = migrate_get_current();
> @@ -1031,6 +1047,8 @@ MigrationParameters *qmp_query_migrate_parameters(Error 
> **errp)
>  params->x_checkpoint_delay = s->parameters.x_checkpoint_delay;
>  params->has_block_incremental = true;
>  params->block_incremental = s->parameters.block_incremental;
> +params->has_multifd_packet_size = true;
> +params->multifd_packet_size = s->parameters.multifd_packet_size;
>  params->has_multifd_channels = true;
>  params->multifd_channels = s->parameters.multifd_channels;
>  params->has_multifd_compression = true;
> @@ -1094,6 +1112,7 @@ void migrate_params_init(MigrationParameters *params)
>  params->has_downtime_limit = true;
>  params->has_x_checkpoint_delay = true;
>  params->has_block_incremental = true;
> +params->has_multifd_packet_size = true;
>  params->has_multifd_channels = true;
>  params->has_multifd_compression = true;
>  params->has_multifd_zlib_level = true;
> @@ -1195,6 +1214,17 @@ bool migrate_params_check(MigrationParameters *params, 
> Error **errp)
>  
>  /* x_checkpoint_delay is now always positive */
>  
> +if (params->has_multifd_packet_size &&
> +((params->multifd_packet_size < DEFAULT_MIGRATE_MULTIFD_PACKET_SIZE) 
> ||
> +(params->multifd_packet_size >  MAX_MIGRATE_MULTIFD_PACKET_SIZE) 
> ||
> +(params->multifd_packet_size % qemu_target_page_size() != 0))) {
> +error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
> +"multifd_packet_size",
> +"a value between 524288 and 4190208, "

We should reference the macros here.

> +"must be a multiple of guest VM's page size.");
> +return false;
> +}
> +
>  if (params->has_multifd_channels && (params->multifd_channels < 1)) {
>  error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
> "multifd_channels",
> @@ -1374,6 +1404,9 @@ static void 
> migrate_params_test_apply(MigrateSetParameters *params,
>  if (params->has_block_incremental) {
>  dest->block_incremental = params->block_incremental;
>  }
> +if (params->has_multifd_packet_size) {
> +dest->multifd_packet_size = params->multifd_packet_size;
> +}
>  if (params->has_multifd_channels) {
>  dest->multifd_channels = params->multifd_channels;
>  }
> @@ -1524,6 +1557,9 @@ static void migrate_params_apply(MigrateSetParameters 
> *params, Error **errp)
>  " use blockdev-mirror with NBD instead");
>  s->parameters.block_incremental = params->block_incremental;
>  }
> +if (params->has_multifd_packet_size) {
> +s->parameters.multifd_packet_size = params->multifd_packet_size;
> +}
>  if (params->has_multifd_channels) {
>  s->parameters.multifd_channels = params->multifd_channels;
>  }
> di

Re: [PATCH v9 09/11] virtio-gpu: Register capsets dynamically

2024-05-01 Thread Dmitry Osipenko
On 4/27/24 10:12, Akihiko Odaki wrote:
>>   int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g)
>>   {
>>   uint32_t capset2_max_ver, capset2_max_size;
>> +
>> +    if (g->capset_ids) {
> 
> Move capset_ids initialization to virtio_gpu_virgl_init() to save this
> conditional.

Capsets are used before virgl is inited. At first guest queries virtio
device features and then enables virgl only if capset is available.
While virgl itself is initialized when first virtio command is
processed. I.e. it's not possible to move to virtio_gpu_virgl_init.

> capset_ids also needs to be freed when the device gets
> unrealized.

ACK

-- 
Best regards,
Dmitry




Re: [PATCH v4 10/14] migration/multifd: Enable DSA offloading in multifd sender path.

2024-05-01 Thread Peter Xu
On Thu, Apr 25, 2024 at 02:21:13AM +, Hao Xiang wrote:
> Multifd sender path gets an array of pages queued by the migration
> thread. It performs zero page checking on every page in the array.
> The pages are classfied as either a zero page or a normal page. This
> change uses Intel DSA to offload the zero page checking from CPU to
> the DSA accelerator. The sender thread submits a batch of pages to DSA
> hardware and waits for the DSA completion thread to signal for work
> completion.
> 
> Signed-off-by: Hao Xiang 
> ---
>  migration/multifd-zero-page.c | 99 +--
>  migration/multifd.c   | 27 +-
>  migration/multifd.h   |  1 +
>  3 files changed, 120 insertions(+), 7 deletions(-)
> 
> diff --git a/migration/multifd-zero-page.c b/migration/multifd-zero-page.c
> index e1b8370f88..4f426289e4 100644
> --- a/migration/multifd-zero-page.c
> +++ b/migration/multifd-zero-page.c
> @@ -37,25 +37,83 @@ static void swap_page_offset(ram_addr_t *pages_offset, 
> int a, int b)
>  }
>  
>  /**
> - * multifd_send_zero_page_detect: Perform zero page detection on all pages.
> + * zero_page_detect_cpu: Perform zero page detection using CPU.
>   *
>   * Sorts normal pages before zero pages in p->pages->offset and updates
>   * p->pages->normal_num.
>   *
>   * @param p A pointer to the send params.
>   */
> -void multifd_send_zero_page_detect(MultiFDSendParams *p)
> +static void zero_page_detect_cpu(MultiFDSendParams *p)
>  {
>  MultiFDPages_t *pages = p->pages;
>  RAMBlock *rb = pages->block;
>  int i = 0;
>  int j = pages->num - 1;
>  
> -if (!multifd_zero_page_enabled()) {
> -pages->normal_num = pages->num;
> +/*
> + * Sort the page offset array by moving all normal pages to
> + * the left and all zero pages to the right of the array.
> + */
> +while (i <= j) {
> +uint64_t offset = pages->offset[i];
> +
> +if (!buffer_is_zero(rb->host + offset, p->page_size)) {
> +i++;
> +continue;
> +}
> +
> +swap_page_offset(pages->offset, i, j);
> +ram_release_page(rb->idstr, offset);
> +j--;
> +}
> +
> +pages->normal_num = i;
> +}
> +
> +
> +#ifdef CONFIG_DSA_OPT
> +
> +static void swap_result(bool *results, int a, int b)
> +{
> +bool temp;
> +
> +if (a == b) {
>  return;
>  }
>  
> +temp = results[a];
> +results[a] = results[b];
> +results[b] = temp;
> +}
> +
> +/**
> + * zero_page_detect_dsa: Perform zero page detection using
> + * Intel Data Streaming Accelerator (DSA).
> + *
> + * Sorts normal pages before zero pages in p->pages->offset and updates
> + * p->pages->normal_num.
> + *
> + * @param p A pointer to the send params.
> + */
> +static void zero_page_detect_dsa(MultiFDSendParams *p)
> +{
> +MultiFDPages_t *pages = p->pages;
> +RAMBlock *rb = pages->block;
> +bool *results = p->batch_task->results;
> +
> +for (int i = 0; i < p->pages->num; i++) {
> +p->batch_task->addr[i] = (ram_addr_t)(rb->host + 
> p->pages->offset[i]);
> +}
> +
> +buffer_is_zero_dsa_batch_async(p->batch_task,
> +   (const void **)p->batch_task->addr,
> +   p->pages->num,
> +   p->page_size);
> +
> +int i = 0;
> +int j = pages->num - 1;
> +
>  /*
>   * Sort the page offset array by moving all normal pages to
>   * the left and all zero pages to the right of the array.
> @@ -63,11 +121,12 @@ void multifd_send_zero_page_detect(MultiFDSendParams *p)
>  while (i <= j) {
>  uint64_t offset = pages->offset[i];
>  
> -if (!buffer_is_zero(rb->host + offset, p->page_size)) {
> +if (!results[i]) {
>  i++;
>  continue;
>  }
>  
> +swap_result(results, i, j);
>  swap_page_offset(pages->offset, i, j);
>  ram_release_page(rb->idstr, offset);
>  j--;
> @@ -76,6 +135,15 @@ void multifd_send_zero_page_detect(MultiFDSendParams *p)
>  pages->normal_num = i;
>  }
>  
> +#else
> +
> +static void zero_page_detect_dsa(MultiFDSendParams *p)
> +{
> +exit(1);
> +}
> +
> +#endif
> +
>  void multifd_recv_zero_page_process(MultiFDRecvParams *p)
>  {
>  for (int i = 0; i < p->zero_num; i++) {
> @@ -87,3 +155,24 @@ void multifd_recv_zero_page_process(MultiFDRecvParams *p)
>  }
>  }
>  }
> +
> +/**
> + * multifd_send_zero_page_detect: Perform zero page detection on all pages.
> + *
> + * @param p A pointer to the send params.
> + */
> +void multifd_send_zero_page_detect(MultiFDSendParams *p)
> +{
> +MultiFDPages_t *pages = p->pages;
> +
> +if (!multifd_zero_page_enabled()) {
> +pages->normal_num = pages->num;
> +return;
> +}
> +
> +if (dsa_is_running()) {
> +zero_page_detect_dsa(p);
> +} else {
> +zero_page_detect_cpu(p);
> +}
> +}
> diff --git a/migration/mul

Re: [PATCH v8 08/11] virtio-gpu: Handle resource blob commands

2024-05-01 Thread Dmitry Osipenko
On 4/27/24 08:52, Akihiko Odaki wrote:
> On 2024/04/24 19:30, Dmitry Osipenko wrote:
>> On 4/19/24 12:18, Akihiko Odaki wrote:
 @@ -61,6 +61,10 @@ struct virtio_gpu_simple_resource {
    int dmabuf_fd;
    uint8_t *remapped;
    +    MemoryRegion *mr;
 +    bool async_unmap_completed;
 +    bool async_unmap_in_progress;
 +
>>>
>>> Don't add fields to virtio_gpu_simple_resource but instead create a
>>> struct that embeds virtio_gpu_simple_resource in virtio-gpu-virgl.c.
>>
>> Please give a justification. I'd rather rename
>> virtio_gpu_simple_resource s/_simple//. Simple resource already supports
>> blob and the added fields are directly related to the blob. Don't see
>> why another struct is needed.
>>
> 
> Because mapping is only implemented in virtio-gpu-gl while blob itself
> is implemented also in virtio-gpu.

Rutubaga maps blobs and it should do unmapping blobs asynchronously as
well, AFAICT.

-- 
Best regards,
Dmitry




Re: [PATCH v4 09/14] migration/multifd: Prepare to introduce DSA acceleration on the multifd path.

2024-05-01 Thread Peter Xu
On Thu, Apr 25, 2024 at 02:21:12AM +, Hao Xiang wrote:
> 1. Refactor multifd_send_thread function.
> 2. Introduce the batch task structure in MultiFDSendParams.
> 
> Signed-off-by: Hao Xiang 
> ---
>  include/qemu/dsa.h  | 51 +++--
>  migration/multifd.c |  5 +
>  migration/multifd.h |  2 ++
>  util/dsa.c  | 51 ++---
>  4 files changed, 99 insertions(+), 10 deletions(-)
> 
> diff --git a/include/qemu/dsa.h b/include/qemu/dsa.h
> index e002652879..0c36e93016 100644
> --- a/include/qemu/dsa.h
> +++ b/include/qemu/dsa.h
> @@ -2,6 +2,7 @@
>  #define QEMU_DSA_H
>  
>  #include "qemu/error-report.h"
> +#include "exec/cpu-common.h"
>  #include "qemu/thread.h"
>  #include "qemu/queue.h"
>  
> @@ -42,6 +43,21 @@ typedef struct dsa_batch_task {
>  QSIMPLEQ_ENTRY(dsa_batch_task) entry;
>  } dsa_batch_task;
>  
> +#endif
> +
> +struct batch_task {
> +#ifdef CONFIG_DSA_OPT
> +/* Address of each pages in pages */
> +ram_addr_t *addr;
> +/* Zero page checking results */
> +bool *results;
> +/* Batch task DSA specific implementation */
> +struct dsa_batch_task *dsa_batch;
> +#endif
> +};
> +
> +#ifdef CONFIG_DSA_OPT
> +
>  /**
>   * @brief Initializes DSA devices.
>   *
> @@ -74,7 +90,7 @@ void dsa_cleanup(void);
>  bool dsa_is_running(void);
>  
>  /**
> - * @brief Initializes a buffer zero batch task.
> + * @brief Initializes a buffer zero DSA batch task.
>   *
>   * @param task A pointer to the batch task to initialize.
>   * @param results A pointer to an array of zero page checking results.
> @@ -102,9 +118,26 @@ void buffer_zero_batch_task_destroy(struct 
> dsa_batch_task *task);
>   * @return Zero if successful, otherwise non-zero.
>   */
>  int
> -buffer_is_zero_dsa_batch_async(struct dsa_batch_task *batch_task,
> +buffer_is_zero_dsa_batch_async(struct batch_task *batch_task,
> const void **buf, size_t count, size_t len);
>  
> +/**
> + * @brief Initializes a general buffer zero batch task.
> + *
> + * @param batch_size The number of zero page checking tasks in the batch.
> + * @return A pointer to the general batch task initialized.
> + */
> +struct batch_task *
> +batch_task_init(int batch_size);
> +
> +/**
> + * @brief Destroys a general buffer zero batch task.
> + *
> + * @param task A pointer to the general batch task to destroy.
> + */
> +void
> +batch_task_destroy(struct batch_task *task);
> +
>  #else
>  
>  static inline bool dsa_is_running(void)
> @@ -128,6 +161,20 @@ static inline void dsa_stop(void) {}
>  
>  static inline void dsa_cleanup(void) {}
>  
> +static inline int
> +buffer_is_zero_dsa_batch_async(struct batch_task *batch_task,
> +   const void **buf, size_t count, size_t len)
> +{
> +exit(1);
> +}
> +
> +static inline struct batch_task *batch_task_init(int batch_size)
> +{
> +return NULL;
> +}
> +
> +static inline void batch_task_destroy(struct batch_task *task) {}

I feel like there're too many things exported for DSA.

For example, at least buffer_is_zero_dsa_batch_async() looks like not
needed to be exported, maybe what should be exported is
zero_page_detect_dsa()?

We also should avoid accessing dsa internal fields in multifd*.c generic
code, for example, I think we should avoid things like below:

MultiFDSendParams:
struct batch_task *batch_task;

multifd_send_setup:

if (dsa_init(dsa_parameter)) {
error_setg(&local_err, "multifd: Sender failed to initialize DSA.");
error_report_err(local_err);
return false;
}

dsa_start();

...

for (each_thread)
p->batch_task = batch_task_init(page_count);

This is way too ugly...

We should have one multifd_dsa_send_setup() and call it once and for all,
internally you can do whatever you want, rewalk the thread pool and init
states.

The name "batch_task" isn't clear either on being consumed by DSA.  I'd
think something like "dsa_state" better.

So instead of above like:

struct batch_task {
#ifdef CONFIG_DSA_OPT
/* Address of each pages in pages */
ram_addr_t *addr;
/* Zero page checking results */
bool *results;
/* Batch task DSA specific implementation */
struct dsa_batch_task *dsa_batch;
#endif
};

The fields should always be defined (say, dsa_state), then:

struct dsa_state {
/* Address of each pages in pages */
ram_addr_t *addr;
/* Zero page checking results */
bool *results;
/* Batch task DSA specific implementation */
struct dsa_batch_task *dsa_batch;
};

MultiFDSendParams:
...
#ifdef CONFIG_DSA_OPT
struct dsa_state *dsa_state;
#endif

> +
>  #endif
>  
>  #endif
> diff --git a/migration/multifd.c b/migration/multifd.c
> index f317bff077..cfd3a92f6c 100644
> --- a/migration/multifd.c
> +++ b/migration/multifd.c
> @@ -13,6 +13,8 @@
>  #include "qemu/osdep.h"
>  #include "qemu/cutils.h"
>  #include "qemu/rcu.h"
> +#include "qemu/dsa.h"
> +#include

Re: [PATCH v8 07/11] virtio-gpu: Support suspension of commands processing

2024-05-01 Thread Dmitry Osipenko
On 4/27/24 08:48, Akihiko Odaki wrote:
>>
>> The VIRTIO_GPU_FILL_CMD() macro returns void and this macro is used by
>> every function processing commands. Changing process_cmd() to return
>> bool will require to change all those functions. Not worthwhile to
>> change it, IMO. >
>> The flag reflects the exact command status. The !finished + !suspended
>> means that command is fenced, i.e. these flags don't have exactly same
>> meaning.
> 
> It is not necessary to change the signature of process_cmd(). You can
> just refer to !finished. No need to have the suspended flag.

Not sure what you're meaning. The !finished says that cmd is fenced,
this fenced command is added to the polling list and the fence is
checked periodically by the fence_poll timer, meanwhile next virgl
commands are executed in the same time.

This is completely different from the suspension where whole cmd
processing is blocked until command is resumed.

-- 
Best regards,
Dmitry




Re: [PATCH v4 07/14] util/dsa: Implement DSA task asynchronous submission and wait for completion.

2024-05-01 Thread Peter Xu
On Thu, Apr 25, 2024 at 02:21:10AM +, Hao Xiang wrote:
> +/**
> + * @brief Performs buffer zero comparison on a DSA batch task asynchronously.
> + *
> + * @param batch_task A pointer to the batch task.
> + * @param buf An array of memory buffers.
> + * @param count The number of buffers in the array.
> + * @param len The buffer length.
> + *
> + * @return Zero if successful, otherwise non-zero.
> + */
> +int
> +buffer_is_zero_dsa_batch_async(struct dsa_batch_task *batch_task,
> +   const void **buf, size_t count, size_t len)

It says it's "async", but then..

> +{
> +if (count <= 0 || count > batch_task->batch_size) {
> +return -1;
> +}
> +
> +assert(batch_task != NULL);
> +assert(len != 0);
> +assert(buf != NULL);
> +
> +if (count == 1) {
> +/* DSA doesn't take batch operation with only 1 task. */
> +buffer_zero_dsa_async(batch_task, buf[0], len);
> +} else {
> +buffer_zero_dsa_batch_async(batch_task, buf, count, len);
> +}
> +
> +buffer_zero_dsa_wait(batch_task);

... it waits always.

Wrong function name?

> +buffer_zero_cpu_fallback(batch_task);

Is this introducing yet another path even if it internally still uses
buffer_is_zero()?

Can we allow buffer_is_zero_dsa_batch_async() (or when it's renamed) fail
directly with a hint that it should fallback?  Ultimately something like:


if (dsa_is_running() && zero_page_detect_dsa(p)) {
/* Succeeded */
return;
}

/* Use cpu detection by default, or as fallback */
zero_page_detect_cpu();

> +
> +return 0;
> +}
> +
>  #endif
>  
> -- 
> 2.30.2
> 
> 

-- 
Peter Xu




[PATCH 06/14] hw/i386: convert 'i440fx' machine definitions to use new macros

2024-05-01 Thread Daniel P . Berrangé
This changes the DEFINE_I440FX_MACHINE macro to use the common
helpers for constructing versioned symbol names and strings,
bringing greater consistency across targets.

The added benefit is that it avoids the need to repeat the
version number thrice in three different formats in the calls
to DEFINE_I440FX_MACHINE.

Signed-off-by: Daniel P. Berrangé 
---
 hw/i386/pc_piix.c| 251 +++
 include/hw/i386/pc.h |  30 ++
 2 files changed, 138 insertions(+), 143 deletions(-)

diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 8850c49c66..9f92504cc4 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -477,16 +477,13 @@ static void pc_xen_hvm_init(MachineState *machine)
 }
 #endif
 
-#define DEFINE_I440FX_MACHINE(suffix, name, compatfn, optionfn) \
-static void pc_init_##suffix(MachineState *machine) \
-{ \
-void (*compat)(MachineState *m) = (compatfn); \
-if (compat) { \
-compat(machine); \
-} \
-pc_init1(machine, TYPE_I440FX_PCI_DEVICE); \
-} \
-DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
+static void pc_i440fx_init(MachineState *machine)
+{
+pc_init1(machine, TYPE_I440FX_PCI_DEVICE);
+}
+
+#define DEFINE_I440FX_MACHINE(major, minor, compatfn) \
+DEFINE_PC_VER_MACHINE(pc_i440fx, "pc-i440fx", pc_i440fx_init, compatfn, 
major, minor);
 
 static void pc_i440fx_machine_options(MachineClass *m)
 {
@@ -513,19 +510,18 @@ static void pc_i440fx_machine_options(MachineClass *m)
  "Use a different south bridge than 
PIIX3");
 }
 
-static void pc_i440fx_9_1_machine_options(MachineClass *m)
+static void pc_i440fx_machine_9_1_options(MachineClass *m)
 {
 pc_i440fx_machine_options(m);
 m->alias = "pc";
 m->is_default = true;
 }
 
-DEFINE_I440FX_MACHINE(v9_1, "pc-i440fx-9.1", NULL,
-  pc_i440fx_9_1_machine_options);
+DEFINE_I440FX_MACHINE(9, 1, NULL);
 
-static void pc_i440fx_9_0_machine_options(MachineClass *m)
+static void pc_i440fx_machine_9_0_options(MachineClass *m)
 {
-pc_i440fx_9_1_machine_options(m);
+pc_i440fx_machine_9_1_options(m);
 m->alias = NULL;
 m->is_default = false;
 
@@ -533,14 +529,13 @@ static void pc_i440fx_9_0_machine_options(MachineClass *m)
 compat_props_add(m->compat_props, pc_compat_9_0, pc_compat_9_0_len);
 }
 
-DEFINE_I440FX_MACHINE(v9_0, "pc-i440fx-9.0", NULL,
-  pc_i440fx_9_0_machine_options);
+DEFINE_I440FX_MACHINE(9, 0, NULL);
 
-static void pc_i440fx_8_2_machine_options(MachineClass *m)
+static void pc_i440fx_machine_8_2_options(MachineClass *m)
 {
 PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
 
-pc_i440fx_9_0_machine_options(m);
+pc_i440fx_machine_9_0_options(m);
 
 compat_props_add(m->compat_props, hw_compat_8_2, hw_compat_8_2_len);
 compat_props_add(m->compat_props, pc_compat_8_2, pc_compat_8_2_len);
@@ -548,28 +543,26 @@ static void pc_i440fx_8_2_machine_options(MachineClass *m)
 pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_64;
 }
 
-DEFINE_I440FX_MACHINE(v8_2, "pc-i440fx-8.2", NULL,
-  pc_i440fx_8_2_machine_options);
+DEFINE_I440FX_MACHINE(8, 2, NULL);
 
-static void pc_i440fx_8_1_machine_options(MachineClass *m)
+static void pc_i440fx_machine_8_1_options(MachineClass *m)
 {
 PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
 
-pc_i440fx_8_2_machine_options(m);
+pc_i440fx_machine_8_2_options(m);
 pcmc->broken_32bit_mem_addr_check = true;
 
 compat_props_add(m->compat_props, hw_compat_8_1, hw_compat_8_1_len);
 compat_props_add(m->compat_props, pc_compat_8_1, pc_compat_8_1_len);
 }
 
-DEFINE_I440FX_MACHINE(v8_1, "pc-i440fx-8.1", NULL,
-  pc_i440fx_8_1_machine_options);
+DEFINE_I440FX_MACHINE(8, 1, NULL);
 
-static void pc_i440fx_8_0_machine_options(MachineClass *m)
+static void pc_i440fx_machine_8_0_options(MachineClass *m)
 {
 PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
 
-pc_i440fx_8_1_machine_options(m);
+pc_i440fx_machine_8_1_options(m);
 compat_props_add(m->compat_props, hw_compat_8_0, hw_compat_8_0_len);
 compat_props_add(m->compat_props, pc_compat_8_0, pc_compat_8_0_len);
 
@@ -577,285 +570,260 @@ static void pc_i440fx_8_0_machine_options(MachineClass 
*m)
 pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_32;
 }
 
-DEFINE_I440FX_MACHINE(v8_0, "pc-i440fx-8.0", NULL,
-  pc_i440fx_8_0_machine_options);
+DEFINE_I440FX_MACHINE(8, 0, NULL);
 
-static void pc_i440fx_7_2_machine_options(MachineClass *m)
+static void pc_i440fx_machine_7_2_options(MachineClass *m)
 {
-pc_i440fx_8_0_machine_options(m);
+pc_i440fx_machine_8_0_options(m);
 compat_props_add(m->compat_props, hw_compat_7_2, hw_compat_7_2_len);
 compat_props_add(m->compat_props, pc_compat_7_2, pc_compat_7_2_len);
 }
 
-DEFINE_I440FX_MACHINE(v7_2, "pc-i440fx-7.2", NULL,
-  pc_i440fx_7_2_machine_options);
+DEFINE_I440FX

[PATCH 12/14] hw/ppc: remove obsolete manual deprecation reason string of spapr machines

2024-05-01 Thread Daniel P . Berrangé
The automatic deprecation mechanism introduced in the preceeding patches
will mark every spapr machine upto and including 2.12 as deprecated. As
such we can revert the manually added deprecation which was a subset:

  commit 1392617d35765d5d912625fbb5cab1ffbed8e140
  Author: Cédric Le Goater 
  Date:   Tue Jan 23 16:37:02 2024 +1000

spapr: Tag pseries-2.1 - 2.11 machines as deprecated

Signed-off-by: Daniel P. Berrangé 
---
 hw/ppc/spapr.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 2aad99a2f2..1b8fa71eb8 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -5140,7 +5140,6 @@ static void spapr_machine_2_11_class_options(MachineClass 
*mc)
 spapr_machine_2_12_class_options(mc);
 smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
 compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
-mc->deprecation_reason = "old and not maintained - use a 2.12+ version";
 }
 
 DEFINE_SPAPR_MACHINE(2, 11);
-- 
2.43.0




[PATCH 10/14] hw: set deprecation info for all versioned machine types

2024-05-01 Thread Daniel P . Berrangé
This calls the MACHINE_VER_DEPRECATION() macro in the definition of
all machine type classes which support versioning. This ensures
that they will automatically get deprecation info set when they
reach the appropriate point in their lifecycle.

Signed-off-by: Daniel P. Berrangé 
---
 hw/arm/virt.c  | 1 +
 hw/m68k/virt.c | 1 +
 hw/ppc/spapr.c | 1 +
 hw/s390x/s390-virtio-ccw.c | 1 +
 include/hw/i386/pc.h   | 1 +
 5 files changed, 5 insertions(+)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 24b104dfa7..e2e10523a3 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -110,6 +110,7 @@ static void arm_virt_compat_set(MachineClass *mc)
 arm_virt_compat_set(mc); \
 MACHINE_VER_SYM(options, virt, __VA_ARGS__)(mc); \
 mc->desc = "QEMU " MACHINE_VER_STR(__VA_ARGS__) " ARM Virtual 
Machine"; \
+MACHINE_VER_DEPRECATION(__VA_ARGS__); \
 if (latest) { \
 mc->alias = "virt"; \
 } \
diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c
index cd6ee692f7..37bb36b385 100644
--- a/hw/m68k/virt.c
+++ b/hw/m68k/virt.c
@@ -343,6 +343,7 @@ type_init(virt_machine_register_types)
 MachineClass *mc = MACHINE_CLASS(oc); \
 MACHINE_VER_SYM(options, virt, __VA_ARGS__)(mc); \
 mc->desc = "QEMU " MACHINE_VER_STR(__VA_ARGS__) " M68K Virtual 
Machine"; \
+MACHINE_VER_DEPRECATION(__VA_ARGS__); \
 if (latest) { \
 mc->alias = "virt"; \
 } \
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 4ab331da57..7f5412f2ed 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -4795,6 +4795,7 @@ static void 
spapr_machine_latest_class_options(MachineClass *mc)
 {\
 MachineClass *mc = MACHINE_CLASS(oc);\
 MACHINE_VER_SYM(class_options, spapr, __VA_ARGS__)(mc);  \
+MACHINE_VER_DEPRECATION(__VA_ARGS__);\
 if (latest) {\
 spapr_machine_latest_class_options(mc);  \
 }\
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 9324fecdca..289a687434 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -841,6 +841,7 @@ bool css_migration_enabled(void)
 MachineClass *mc = MACHINE_CLASS(oc); \
 MACHINE_VER_SYM(class_options, ccw, __VA_ARGS__)(mc); \
 mc->desc = "Virtual s390x machine (version " 
MACHINE_VER_STR(__VA_ARGS__) ")"; \
+MACHINE_VER_DEPRECATION(__VA_ARGS__); \
 if (latest) { \
 mc->alias = "s390-ccw-virtio";\
 mc->is_default = true;\
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 669263dfca..acc17c7dac 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -327,6 +327,7 @@ extern const size_t pc_compat_2_0_len;
 MachineClass *mc = MACHINE_CLASS(oc); \
 MACHINE_VER_SYM(options, namesym, __VA_ARGS__)(mc); \
 mc->init = MACHINE_VER_SYM(init, namesym, __VA_ARGS__); \
+MACHINE_VER_DEPRECATION(__VA_ARGS__); \
 } \
 static const TypeInfo MACHINE_VER_SYM(info, namesym, __VA_ARGS__) = \
 { \
-- 
2.43.0




[PATCH 14/14] docs: document special exception for machine type deprecation & removal

2024-05-01 Thread Daniel P . Berrangé
This extends the deprecation policy to indicate that versioned machine
types will be marked deprecated after 3 years, and then subject to
removal after a further 3 years has passed.

Signed-off-by: Daniel P. Berrangé 
---
 docs/about/deprecated.rst | 12 
 1 file changed, 12 insertions(+)

diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index 7b8aafa15b..55120e774c 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -11,6 +11,18 @@ releases, the feature is liable to be removed. Deprecated 
features may also
 generate warnings on the console when QEMU starts up, or if activated via a
 monitor command, however, this is not a mandatory requirement.
 
+As a special exception to this general timeframe, rather than have an
+indefinite lifetime, versioned machine types are only intended to be
+supported for a period of 6 years, equivalent to 18 QEMU releases. All
+versioned machine types will be automatically marked deprecated after an
+initial 3 years (9 QEMU releases) has passed, and will then be deleted after
+a further 3 year period has passed. It is recommended that a deprecated
+machine type is only used for incoming migrations and restore of saved state,
+for pre-existing VM deployments. Newly deployed VMs should exclusively use a
+non-deprecated machine type, with use of the most recent version highly
+recommended. Non-versioned machine types follow the general feature
+deprecation policy.
+
 Prior to the 2.10.0 release there was no official policy on how
 long features would be deprecated prior to their removal, nor
 any documented list of which features were deprecated. Thus
-- 
2.43.0




[PATCH 11/14] hw: skip registration of outdated versioned machine types

2024-05-01 Thread Daniel P . Berrangé
This calls the MACHINE_VER_DELETION() macro in the machine type
registration method, so that when a versioned machine type reaches
the end of its life, it is no longer registered with QOM and thus
cannot be used.

The actual definition of the machine type should be deleted at
this point, but experience shows that can easily be forgotten.
By skipping registration the manual code deletion task can be
done at any later date.

Signed-off-by: Daniel P. Berrangé 
---
 hw/arm/virt.c  | 1 +
 hw/m68k/virt.c | 1 +
 hw/ppc/spapr.c | 1 +
 hw/s390x/s390-virtio-ccw.c | 1 +
 include/hw/i386/pc.h   | 1 +
 5 files changed, 5 insertions(+)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index e2e10523a3..0786f82da6 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -123,6 +123,7 @@ static void arm_virt_compat_set(MachineClass *mc)
 }; \
 static void MACHINE_VER_SYM(register, virt, __VA_ARGS__)(void) \
 { \
+MACHINE_VER_DELETION(__VA_ARGS__); \
 type_register_static(&MACHINE_VER_SYM(info, virt, __VA_ARGS__)); \
 } \
 type_init(MACHINE_VER_SYM(register, virt, __VA_ARGS__));
diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c
index 37bb36b385..cda199af8f 100644
--- a/hw/m68k/virt.c
+++ b/hw/m68k/virt.c
@@ -356,6 +356,7 @@ type_init(virt_machine_register_types)
 }; \
 static void MACHINE_VER_SYM(register, virt, __VA_ARGS__)(void) \
 { \
+MACHINE_VER_DELETION(__VA_ARGS__); \
 type_register_static(&MACHINE_VER_SYM(info, virt, __VA_ARGS__)); \
 } \
 type_init(MACHINE_VER_SYM(register, virt, __VA_ARGS__));
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 7f5412f2ed..2aad99a2f2 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -4808,6 +4808,7 @@ static void 
spapr_machine_latest_class_options(MachineClass *mc)
 };   \
 static void MACHINE_VER_SYM(register, spapr, __VA_ARGS__)(void)  \
 {\
+MACHINE_VER_DELETION(__VA_ARGS__);   \
 type_register(&MACHINE_VER_SYM(info, spapr, __VA_ARGS__));   \
 }\
 type_init(MACHINE_VER_SYM(register, spapr, __VA_ARGS__))
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 289a687434..723021f644 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -862,6 +862,7 @@ bool css_migration_enabled(void)
 };\
 static void MACHINE_VER_SYM(register, ccw, __VA_ARGS__)(void) \
 { \
+MACHINE_VER_DELETION(__VA_ARGS__);\
 type_register_static(&MACHINE_VER_SYM(info, ccw, __VA_ARGS__));   \
 } \
 type_init(MACHINE_VER_SYM(register, ccw, __VA_ARGS__))
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index acc17c7dac..a605f223d5 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -337,6 +337,7 @@ extern const size_t pc_compat_2_0_len;
 }; \
 static void MACHINE_VER_SYM(register, namesym, __VA_ARGS__)(void) \
 { \
+MACHINE_VER_DELETION(__VA_ARGS__); \
 type_register(&MACHINE_VER_SYM(info, namesym, __VA_ARGS__)); \
 } \
 type_init(MACHINE_VER_SYM(register, namesym, __VA_ARGS__));
-- 
2.43.0




[PATCH 13/14] hw/i386: remove obsolete manual deprecation reason string of i440fx machines

2024-05-01 Thread Daniel P . Berrangé
The automatic deprecation mechanism introduced in the preceeding patches
will mark every i440fx machine upto and including 2.12 as deprecated. As
such we can revert the manually added deprecation which was a subset:

  commit c7437f0ddb8ee45bf96d949ddfcbb7697ae3d415
  Author: Thomas Huth 
  Date:   Fri Oct 6 09:52:47 2023 +0200

docs/about: Mark the old pc-i440fx-2.0 - 2.3 machine types as deprecated

Signed-off-by: Daniel P. Berrangé 
---
 hw/i386/pc_piix.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 9f92504cc4..4137e03f6f 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -812,7 +812,6 @@ static void pc_i440fx_machine_2_3_options(MachineClass *m)
 {
 pc_i440fx_machine_2_4_options(m);
 m->hw_version = "2.3.0";
-m->deprecation_reason = "old and unattended - use a newer version instead";
 compat_props_add(m->compat_props, hw_compat_2_3, hw_compat_2_3_len);
 compat_props_add(m->compat_props, pc_compat_2_3, pc_compat_2_3_len);
 }
-- 
2.43.0




[PATCH 03/14] hw/s390x: convert 'ccw' machine definitions to use new macros

2024-05-01 Thread Daniel P . Berrangé
This changes the DEFINE_CCW_MACHINE macro to use the common
helpers for constructing versioned symbol names and strings,
bringing greater consistency across targets.

The added benefit is that it avoids the need to repeat the
version number twice in two different formats in the calls
to DEFINE_CCW_MACHINE.

A DEFINE_CCW_MACHINE_AS_LATEST helper is added so that it
is not required to pass 'false' for every single historical
machine type.

Signed-off-by: Daniel P. Berrangé 
---
 hw/s390x/s390-virtio-ccw.c | 96 +-
 1 file changed, 53 insertions(+), 43 deletions(-)

diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 4dcc213820..9324fecdca 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -15,6 +15,7 @@
 #include "qapi/error.h"
 #include "exec/ram_addr.h"
 #include "exec/confidential-guest-support.h"
+#include "hw/boards.h"
 #include "hw/s390x/s390-virtio-hcall.h"
 #include "hw/s390x/sclp.h"
 #include "hw/s390x/s390_flic.h"
@@ -832,35 +833,44 @@ bool css_migration_enabled(void)
 return get_machine_class()->css_migration_enabled;
 }
 
-#define DEFINE_CCW_MACHINE(suffix, verstr, latest)\
-static void ccw_machine_##suffix##_class_init(ObjectClass *oc,\
-  void *data) \
+#define DEFINE_CCW_MACHINE_IMPL(latest, ...)  \
+static void MACHINE_VER_SYM(class_init, ccw, __VA_ARGS__)(\
+ObjectClass *oc,  \
+void *data)   \
 { \
 MachineClass *mc = MACHINE_CLASS(oc); \
-ccw_machine_##suffix##_class_options(mc); \
-mc->desc = "Virtual s390x machine (version " verstr ")";  \
+MACHINE_VER_SYM(class_options, ccw, __VA_ARGS__)(mc); \
+mc->desc = "Virtual s390x machine (version " 
MACHINE_VER_STR(__VA_ARGS__) ")"; \
 if (latest) { \
 mc->alias = "s390-ccw-virtio";\
 mc->is_default = true;\
 } \
 } \
-static void ccw_machine_##suffix##_instance_init(Object *obj) \
+static void MACHINE_VER_SYM(instance_init, ccw, __VA_ARGS__)(Object *obj) \
 { \
 MachineState *machine = MACHINE(obj); \
-current_mc = S390_CCW_MACHINE_CLASS(MACHINE_GET_CLASS(machine));   
   \
-ccw_machine_##suffix##_instance_options(machine); \
+current_mc = S390_CCW_MACHINE_CLASS(MACHINE_GET_CLASS(machine));  \
+MACHINE_VER_SYM(instance_options, ccw, __VA_ARGS__)(machine); \
 } \
-static const TypeInfo ccw_machine_##suffix##_info = { \
-.name = MACHINE_TYPE_NAME("s390-ccw-virtio-" verstr), \
+static const TypeInfo MACHINE_VER_SYM(info, ccw, __VA_ARGS__) =   \
+{ \
+.name = MACHINE_VER_TYPE_NAME("s390-ccw-virtio", __VA_ARGS__),\
 .parent = TYPE_S390_CCW_MACHINE,  \
-.class_init = ccw_machine_##suffix##_class_init,  \
-.instance_init = ccw_machine_##suffix##_instance_init,\
+.class_init = MACHINE_VER_SYM(class_init, ccw, __VA_ARGS__),  \
+.instance_init = MACHINE_VER_SYM(instance_init, ccw, __VA_ARGS__),\
 };\
-static void ccw_machine_register_##suffix(void)   \
+static void MACHINE_VER_SYM(register, ccw, __VA_ARGS__)(void) \
 { \
-type_register_static(&ccw_machine_##suffix##_info);   \
+type_register_static(&MACHINE_VER_SYM(info, ccw, __VA_ARGS__));   \
 } \
-type_init(ccw_machine_register_##suffix)
+type_init(MACHINE_VER_SYM(register, ccw, __VA_ARGS__))
+
+#define DEFINE_CCW_MACHINE_AS_LATEST(major, minor) \
+DEFINE_CCW_MACHINE_IMPL(true, major, minor)
+
+#define DEFINE_CCW_MACHINE(major, minor) \
+DEFINE_CCW_MACHINE_IMPL

[PATCH 04/14] hw/ppc: convert 'spapr' machine definitions to use new macros

2024-05-01 Thread Daniel P . Berrangé
This changes the DEFINE_SPAPR_MACHINE macro to use the common
helpers for constructing versioned symbol names and strings,
bringing greater consistency across targets.

The added benefit is that it avoids the need to repeat the
version number twice in two different formats in the calls
to DEFINE_SPAPR_MACHINE.

A DEFINE_SPAPR_MACHINE_AS_LATEST helper is added so that it
is not required to pass 'false' for every single historical
machine type.

Due to the odd-ball '2.12-sxxm' machine type version, this
commit introduces a DEFINE_SPAPR_MACHINE_TAGGED helper to
allow defining of "tagged" machine types which have a string
suffix.

Signed-off-by: Daniel P. Berrangé 
---
 hw/ppc/spapr.c | 93 +++---
 1 file changed, 51 insertions(+), 42 deletions(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index d2d1e310a3..4ab331da57 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -4788,26 +4788,35 @@ static void 
spapr_machine_latest_class_options(MachineClass *mc)
 mc->is_default = true;
 }
 
-#define DEFINE_SPAPR_MACHINE(suffix, verstr, latest) \
-static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \
-void *data)  \
+#define DEFINE_SPAPR_MACHINE_IMPL(latest, ...)   \
+static void MACHINE_VER_SYM(class_init, spapr, __VA_ARGS__)( \
+ObjectClass *oc, \
+void *data)  \
 {\
 MachineClass *mc = MACHINE_CLASS(oc);\
-spapr_machine_##suffix##_class_options(mc);  \
+MACHINE_VER_SYM(class_options, spapr, __VA_ARGS__)(mc);  \
 if (latest) {\
 spapr_machine_latest_class_options(mc);  \
 }\
 }\
-static const TypeInfo spapr_machine_##suffix##_info = {  \
-.name = MACHINE_TYPE_NAME("pseries-" verstr),\
+static const TypeInfo MACHINE_VER_SYM(info, spapr, __VA_ARGS__) = \
+{\
+.name = MACHINE_VER_TYPE_NAME("pseries", __VA_ARGS__),   \
 .parent = TYPE_SPAPR_MACHINE,\
-.class_init = spapr_machine_##suffix##_class_init,   \
+.class_init = MACHINE_VER_SYM(class_init, spapr, __VA_ARGS__), \
 };   \
-static void spapr_machine_register_##suffix(void)\
+static void MACHINE_VER_SYM(register, spapr, __VA_ARGS__)(void)  \
 {\
-type_register(&spapr_machine_##suffix##_info);   \
+type_register(&MACHINE_VER_SYM(info, spapr, __VA_ARGS__));   \
 }\
-type_init(spapr_machine_register_##suffix)
+type_init(MACHINE_VER_SYM(register, spapr, __VA_ARGS__))
+
+#define DEFINE_SPAPR_MACHINE_AS_LATEST(major, minor) \
+DEFINE_SPAPR_MACHINE_IMPL(true, major, minor)
+#define DEFINE_SPAPR_MACHINE(major, minor) \
+DEFINE_SPAPR_MACHINE_IMPL(false, major, minor)
+#define DEFINE_SPAPR_MACHINE_TAGGED(major, minor, tag) \
+DEFINE_SPAPR_MACHINE_IMPL(false, major, minor, _, tag)
 
 /*
  * pseries-9.1
@@ -4817,7 +4826,7 @@ static void spapr_machine_9_1_class_options(MachineClass 
*mc)
 /* Defaults for the latest behaviour inherited from the base class */
 }
 
-DEFINE_SPAPR_MACHINE(9_1, "9.1", true);
+DEFINE_SPAPR_MACHINE_AS_LATEST(9, 1);
 
 /*
  * pseries-9.0
@@ -4828,7 +4837,7 @@ static void spapr_machine_9_0_class_options(MachineClass 
*mc)
 compat_props_add(mc->compat_props, hw_compat_9_0, hw_compat_9_0_len);
 }
 
-DEFINE_SPAPR_MACHINE(9_0, "9.0", false);
+DEFINE_SPAPR_MACHINE(9, 0);
 
 /*
  * pseries-8.2
@@ -4839,7 +4848,7 @@ static void spapr_machine_8_2_class_options(MachineClass 
*mc)
 compat_props_add(mc->compat_props, hw_compat_8_2, hw_compat_8_2_len);
 }
 
-DEFINE_SPAPR_MACHINE(8_2, "8.2", false);
+DEFINE_SPAPR_MACHINE(8, 2);
 
 /*
  * pseries-8.1
@@ -4850,7 +4859,7 @@ static void spapr_machine_8_1_class_options(MachineClass 
*mc)
 compat_props_add(mc->compat_props, hw_compat_8_1, hw_compat_8_1_len);
 }
 
-DEFINE_SPAPR_MACHINE(8_1, "8.1", false);
+DEFINE_SPAPR_MACHINE(8, 1);
 
 /*
  * pseries-8.0
@@ -4861,7 +4870,7 @@ static void spapr_machine_8_0_class_options(MachineClass 
*mc)
 compat_props_add(mc->compat_props, hw_compat_8_0, hw_compat_8_0_len);
 }
 
-DEFINE_SPAPR_MACHINE(8_0, "8.0", false);
+DEFINE_SPAPR_MACHINE(8, 0);
 
 /*
  * pseries-7.2
@@ -4872,7 +4881,7 @@ static void sp

[PATCH 08/14] include/hw: add macros for deprecation & removal of versioned machines

2024-05-01 Thread Daniel P . Berrangé
Versioned machines live for a long time to provide back compat for
incoming migration and restore of saved images. To guide users away from
usage of old machines, however, we want to deprecate any older than 3
years (equiv of 9 releases), and delete any older than 6 years (equiva
of 18 releases).

To get a standardized deprecation message and avoid having to remember
to manually add it after three years, this introduces two macros to be
used by targets when defining versioned machines.

* MACHINE_VER_DEPRECATION(major, minor)

  Automates the task of setting the 'deprecation_reason' field on the
  machine, if-and-only-if the major/minor version is older than 3 years.

* MACHINE_VER_DEPRECATION(major, minor)

  Simulates the deletion of by skipping registration of the QOM type
  for a versioned machine, if-and-only-if the major/minor version is
  older than 6 years.

By using these two macros there is no longer any manual work required
per-release to deprecate old machines. By preventing the use of machines
that have reached their deletion date, it is also no neccessary to
manually delete machines per-release. Deletion can be batched up once a
year or whenever makes most sense.

Signed-off-by: Daniel P. Berrangé 
---
 include/hw/boards.h | 84 +
 1 file changed, 84 insertions(+)

diff --git a/include/hw/boards.h b/include/hw/boards.h
index 47ca450fca..48b6c98c77 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -427,6 +427,7 @@ struct MachineState {
  *  MachineClass *mc = MACHINE_CLASS(oc); \
  *  MACHINE_VER_SYM(options, virt, __VA_ARGS__)(mc); \
  *  mc->desc = "QEMU " MACHINE_VER_STR(__VA_ARGS__) " Virtual 
Machine"; \
+ *  MACHINE_VER_DEPRECATION(__VA_ARGS__); \
  *  if (latest) { \
  *  mc->alias = "virt"; \
  *  } \
@@ -438,6 +439,7 @@ struct MachineState {
  *  }; \
  *  static void MACHINE_VER_SYM(register, virt, __VA_ARGS__)(void) \
  *  { \
+ *  MACHINE_VER_DELETION(__VA_ARGS__); \
  *  type_register_static(&MACHINE_VER_SYM(info, virt, __VA_ARGS__)); \
  *  } \
  *  type_init(MACHINE_VER_SYM(register, virt, __VA_ARGS__));
@@ -580,6 +582,88 @@ struct MachineState {
   _MACHINE_VER_SYM2) (sym, prefix, __VA_ARGS__)
 
 
+/*
+ * How many years/major releases for each phase
+ * of the life cycle. Assumes use of versioning
+ * scheme where major is bumped each year
+ */
+#define MACHINE_VER_DELETION_MAJOR 6
+#define MACHINE_VER_DEPRECATION_MAJOR 3
+
+/*
+ * Expands to a static string containing a deprecation
+ * message for a versioned machine type
+ */
+#define MACHINE_VER_DEPRECATION_MSG \
+"machines more than " stringify(MACHINE_VER_DEPRECATION_MAJOR) \
+" years old are subject to deletion after " \
+stringify(MACHINE_VER_DELETION_MAJOR) " years"
+
+#define _MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor) \
+(((QEMU_VERSION_MAJOR - major) > cutoff) || \
+ (((QEMU_VERSION_MAJOR - major) == cutoff) && \
+  (QEMU_VERSION_MINOR - minor) >= 0))
+
+#define _MACHINE_VER_IS_EXPIRED2(cutoff, major, minor) \
+_MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor)
+#define _MACHINE_VER_IS_EXPIRED3(cutoff, major, minor, micro) \
+_MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor)
+#define _MACHINE_VER_IS_EXPIRED4(cutoff, major, minor, _unused, tag) \
+_MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor)
+#define _MACHINE_VER_IS_EXPIRED5(cutoff, major, minor, micro, _unused, tag)   \
+_MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor)
+
+#define _MACHINE_IS_EXPIRED(cutoff, ...) \
+_MACHINE_VER_PICK(__VA_ARGS__, \
+  _MACHINE_VER_IS_EXPIRED5, \
+  _MACHINE_VER_IS_EXPIRED4, \
+  _MACHINE_VER_IS_EXPIRED3, \
+  _MACHINE_VER_IS_EXPIRED2) (cutoff, __VA_ARGS__)
+
+/*
+ * Evaluates true when a machine type with (major, minor)
+ * or (major, minor, micro) version should be considered
+ * deprecated based on the current versioned machine type
+ * lifecycle rules
+ */
+#define MACHINE_VER_IS_DEPRECATED(...) \
+_MACHINE_IS_EXPIRED(MACHINE_VER_DEPRECATION_MAJOR, __VA_ARGS__)
+
+/*
+ * Evaluates true when a machine type with (major, minor)
+ * or (major, minor, micro) version should be considered
+ * for deletion based on the current versioned machine type
+ * lifecycle rules
+ */
+#define MACHINE_VER_SHOULD_DELETE(...) \
+_MACHINE_IS_EXPIRED(MACHINE_VER_DELETION_MAJOR, __VA_ARGS__)
+
+/*
+ * Sets the deprecation reason for a versioned machine based
+ * on its lifecycle
+ *
+ * This must be unconditionally used in the _class_init
+ * function for all machine types which support versioning.
+ *
+ * Initially it will be an effective no-op, but after a
+ * suitable period of time has passed, it will set the
+ * 'deprecation_reason' field on the machine, to warn users
+ * about forthcoming removal.
+ */
+#define MACHINE_VER_DEPRECATION(.

[PATCH 07/14] hw/i386: convert 'q35' machine definitions to use new macros

2024-05-01 Thread Daniel P . Berrangé
This changes the DEFINE_Q35_MACHINE macro to use the common
helpers for constructing versioned symbol names and strings,
bringing greater consistency across targets.

The added benefit is that it avoids the need to repeat the
version number thrice in three different formats in the calls
to DEFINE_Q35_MACHINE.

Due to the odd-ball '4.0.1' machine type version, this
commit introduces a DEFINE_Q35_BUGFIX helper, to allow
defining of "bugfix" machine types which have a three
digit version.

Signed-off-by: Daniel P. Berrangé 
---
 hw/i386/pc_q35.c | 215 ---
 1 file changed, 90 insertions(+), 125 deletions(-)

diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index bb53a51ac1..b76cdca151 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -331,17 +331,11 @@ static void pc_q35_init(MachineState *machine)
 }
 }
 
-#define DEFINE_Q35_MACHINE(suffix, name, compatfn, optionfn) \
-static void pc_init_##suffix(MachineState *machine) \
-{ \
-void (*compat)(MachineState *m) = (compatfn); \
-if (compat) { \
-compat(machine); \
-} \
-pc_q35_init(machine); \
-} \
-DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
+#define DEFINE_Q35_MACHINE(major, minor) \
+DEFINE_PC_VER_MACHINE(pc_q35, "pc-q35", pc_q35_init, NULL, major, minor);
 
+#define DEFINE_Q35_MACHINE_BUGFIX(major, minor, micro) \
+DEFINE_PC_VER_MACHINE(pc_q35, "pc-q35", pc_q35_init, NULL, major, minor, 
micro);
 
 static void pc_q35_machine_options(MachineClass *m)
 {
@@ -367,30 +361,28 @@ static void pc_q35_machine_options(MachineClass *m)
  pc_q35_compat_defaults, pc_q35_compat_defaults_len);
 }
 
-static void pc_q35_9_1_machine_options(MachineClass *m)
+static void pc_q35_machine_9_1_options(MachineClass *m)
 {
 pc_q35_machine_options(m);
 m->alias = "q35";
 }
 
-DEFINE_Q35_MACHINE(v9_1, "pc-q35-9.1", NULL,
-   pc_q35_9_1_machine_options);
+DEFINE_Q35_MACHINE(9, 1);
 
-static void pc_q35_9_0_machine_options(MachineClass *m)
+static void pc_q35_machine_9_0_options(MachineClass *m)
 {
-pc_q35_9_1_machine_options(m);
+pc_q35_machine_9_1_options(m);
 m->alias = NULL;
 compat_props_add(m->compat_props, hw_compat_9_0, hw_compat_9_0_len);
 compat_props_add(m->compat_props, pc_compat_9_0, pc_compat_9_0_len);
 }
 
-DEFINE_Q35_MACHINE(v9_0, "pc-q35-9.0", NULL,
-   pc_q35_9_0_machine_options);
+DEFINE_Q35_MACHINE(9, 0);
 
-static void pc_q35_8_2_machine_options(MachineClass *m)
+static void pc_q35_machine_8_2_options(MachineClass *m)
 {
 PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
-pc_q35_9_0_machine_options(m);
+pc_q35_machine_9_0_options(m);
 m->max_cpus = 1024;
 compat_props_add(m->compat_props, hw_compat_8_2, hw_compat_8_2_len);
 compat_props_add(m->compat_props, pc_compat_8_2, pc_compat_8_2_len);
@@ -398,26 +390,24 @@ static void pc_q35_8_2_machine_options(MachineClass *m)
 pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_64;
 }
 
-DEFINE_Q35_MACHINE(v8_2, "pc-q35-8.2", NULL,
-   pc_q35_8_2_machine_options);
+DEFINE_Q35_MACHINE(8, 2);
 
-static void pc_q35_8_1_machine_options(MachineClass *m)
+static void pc_q35_machine_8_1_options(MachineClass *m)
 {
 PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
-pc_q35_8_2_machine_options(m);
+pc_q35_machine_8_2_options(m);
 pcmc->broken_32bit_mem_addr_check = true;
 compat_props_add(m->compat_props, hw_compat_8_1, hw_compat_8_1_len);
 compat_props_add(m->compat_props, pc_compat_8_1, pc_compat_8_1_len);
 }
 
-DEFINE_Q35_MACHINE(v8_1, "pc-q35-8.1", NULL,
-   pc_q35_8_1_machine_options);
+DEFINE_Q35_MACHINE(8, 1);
 
-static void pc_q35_8_0_machine_options(MachineClass *m)
+static void pc_q35_machine_8_0_options(MachineClass *m)
 {
 PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
 
-pc_q35_8_1_machine_options(m);
+pc_q35_machine_8_1_options(m);
 compat_props_add(m->compat_props, hw_compat_8_0, hw_compat_8_0_len);
 compat_props_add(m->compat_props, pc_compat_8_0, pc_compat_8_0_len);
 
@@ -426,132 +416,120 @@ static void pc_q35_8_0_machine_options(MachineClass *m)
 m->max_cpus = 288;
 }
 
-DEFINE_Q35_MACHINE(v8_0, "pc-q35-8.0", NULL,
-   pc_q35_8_0_machine_options);
+DEFINE_Q35_MACHINE(8, 0);
 
-static void pc_q35_7_2_machine_options(MachineClass *m)
+static void pc_q35_machine_7_2_options(MachineClass *m)
 {
-pc_q35_8_0_machine_options(m);
+pc_q35_machine_8_0_options(m);
 compat_props_add(m->compat_props, hw_compat_7_2, hw_compat_7_2_len);
 compat_props_add(m->compat_props, pc_compat_7_2, pc_compat_7_2_len);
 }
 
-DEFINE_Q35_MACHINE(v7_2, "pc-q35-7.2", NULL,
-   pc_q35_7_2_machine_options);
+DEFINE_Q35_MACHINE(7, 2);
 
-static void pc_q35_7_1_machine_options(MachineClass *m)
+static void pc_q35_machine_7_1_options(MachineClass *m)
 {
-pc_q35_7_2_machine_options(m);
+pc_

[PATCH 09/14] hw: temporarily disable deletion of versioned machine types

2024-05-01 Thread Daniel P . Berrangé
The new deprecation and deletion policy for versioned machine types is
being introduced in QEMU 9.1.0.

Under the new policy a number of old machine types (any prior to 2.12)
would be liable for immediate deletion which would be a violation of our
historical deprecation and removal policy

Thus automatic deletions (by skipping QOM registration) are temporarily
gated on existance of the env variable "QEMU_DELETE_MACHINES" / QEMU
version number >= 10.1.0. This allows opt-in testing of the automatic
deletion logic, while activating it fully in QEMU >= 10.1.0.

This whole commit should be reverted in the 10.1.0 dev cycle or shortly
thereafter.

Signed-off-by: Daniel P. Berrangé 
---
 include/hw/boards.h | 20 +++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/include/hw/boards.h b/include/hw/boards.h
index 48b6c98c77..d6214007ce 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -657,10 +657,28 @@ struct MachineState {
 } \
 } while (0)
 
+/*
+ * The new deprecation and deletion policy for versioned
+ * machine types was introduced in QEMU 9.1.0.
+ *
+ * Under the new policy a number of old machine types (any
+ * prior to 2.12) would be liable for immediate deletion
+ * which would be a violation of our historical deprecation
+ * and removal policy
+ *
+ * Thus deletions are temporarily gated on existance of
+ * the env variable "QEMU_DELETE_MACHINES" / QEMU version
+ * number >= 10.1.0. This gate can be deleted in the 10.1.0
+ * dev cycle
+ */
 #define MACHINE_VER_DELETION(...) \
 do { \
 if (MACHINE_VER_SHOULD_DELETE(__VA_ARGS__)) { \
-return; \
+if (getenv("QEMU_DELETE_MACHINES") || \
+QEMU_VERSION_MAJOR > 10 || (QEMU_VERSION_MAJOR == 10 && \
+QEMU_VERSION_MINOR >= 1)) { \
+return; \
+} \
 } \
 } while (0)
 
-- 
2.43.0




[PATCH 05/14] hw/m68k: convert 'virt' machine definitions to use new macros

2024-05-01 Thread Daniel P . Berrangé
This changes the DEFINE_VIRT_MACHINE macro to use the common
helpers for constructing versioned symbol names and strings,
bringing greater consistency across targets.

A DEFINE_VIRT_MACHINE_AS_LATEST helper is added so that it
is not required to pass 'false' for every single historical
machine type.

Signed-off-by: Daniel P. Berrangé 
---
 hw/m68k/virt.c | 51 --
 1 file changed, 29 insertions(+), 22 deletions(-)

diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c
index 09bc9bdfef..cd6ee692f7 100644
--- a/hw/m68k/virt.c
+++ b/hw/m68k/virt.c
@@ -335,99 +335,106 @@ static void virt_machine_register_types(void)
 
 type_init(virt_machine_register_types)
 
-#define DEFINE_VIRT_MACHINE(major, minor, latest) \
-static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
-void *data) \
+#define DEFINE_VIRT_MACHINE_IMPL(latest, ...) \
+static void MACHINE_VER_SYM(class_init, virt, __VA_ARGS__)( \
+ObjectClass *oc, \
+void *data) \
 { \
 MachineClass *mc = MACHINE_CLASS(oc); \
-virt_machine_##major##_##minor##_options(mc); \
-mc->desc = "QEMU " # major "." # minor " M68K Virtual Machine"; \
+MACHINE_VER_SYM(options, virt, __VA_ARGS__)(mc); \
+mc->desc = "QEMU " MACHINE_VER_STR(__VA_ARGS__) " M68K Virtual 
Machine"; \
 if (latest) { \
 mc->alias = "virt"; \
 } \
 } \
-static const TypeInfo machvirt_##major##_##minor##_info = { \
-.name = MACHINE_TYPE_NAME("virt-" # major "." # minor), \
+static const TypeInfo MACHINE_VER_SYM(info, virt, __VA_ARGS__) = \
+{ \
+.name = MACHINE_VER_TYPE_NAME("virt", __VA_ARGS__), \
 .parent = MACHINE_TYPE_NAME("virt"), \
-.class_init = virt_##major##_##minor##_class_init, \
+.class_init = MACHINE_VER_SYM(class_init, virt, __VA_ARGS__), \
 }; \
-static void machvirt_machine_##major##_##minor##_init(void) \
+static void MACHINE_VER_SYM(register, virt, __VA_ARGS__)(void) \
 { \
-type_register_static(&machvirt_##major##_##minor##_info); \
+type_register_static(&MACHINE_VER_SYM(info, virt, __VA_ARGS__)); \
 } \
-type_init(machvirt_machine_##major##_##minor##_init);
+type_init(MACHINE_VER_SYM(register, virt, __VA_ARGS__));
+
+#define DEFINE_VIRT_MACHINE_AS_LATEST(major, minor) \
+DEFINE_VIRT_MACHINE_IMPL(true, major, minor)
+#define DEFINE_VIRT_MACHINE(major, minor) \
+DEFINE_VIRT_MACHINE_IMPL(false, major, minor)
 
 static void virt_machine_9_1_options(MachineClass *mc)
 {
 }
-DEFINE_VIRT_MACHINE(9, 1, true)
+DEFINE_VIRT_MACHINE_AS_LATEST(9, 1)
 
 static void virt_machine_9_0_options(MachineClass *mc)
 {
 virt_machine_9_1_options(mc);
 compat_props_add(mc->compat_props, hw_compat_9_0, hw_compat_9_0_len);
 }
-DEFINE_VIRT_MACHINE(9, 0, false)
+DEFINE_VIRT_MACHINE(9, 0)
 
 static void virt_machine_8_2_options(MachineClass *mc)
 {
 virt_machine_9_0_options(mc);
 compat_props_add(mc->compat_props, hw_compat_8_2, hw_compat_8_2_len);
 }
-DEFINE_VIRT_MACHINE(8, 2, false)
+DEFINE_VIRT_MACHINE(8, 2)
 
 static void virt_machine_8_1_options(MachineClass *mc)
 {
 virt_machine_8_2_options(mc);
 compat_props_add(mc->compat_props, hw_compat_8_1, hw_compat_8_1_len);
 }
-DEFINE_VIRT_MACHINE(8, 1, false)
+DEFINE_VIRT_MACHINE(8, 1)
 
 static void virt_machine_8_0_options(MachineClass *mc)
 {
 virt_machine_8_1_options(mc);
 compat_props_add(mc->compat_props, hw_compat_8_0, hw_compat_8_0_len);
 }
-DEFINE_VIRT_MACHINE(8, 0, false)
+DEFINE_VIRT_MACHINE(8, 0)
 
 static void virt_machine_7_2_options(MachineClass *mc)
 {
 virt_machine_8_0_options(mc);
 compat_props_add(mc->compat_props, hw_compat_7_2, hw_compat_7_2_len);
 }
-DEFINE_VIRT_MACHINE(7, 2, false)
+DEFINE_VIRT_MACHINE(7, 2)
 
 static void virt_machine_7_1_options(MachineClass *mc)
 {
 virt_machine_7_2_options(mc);
 compat_props_add(mc->compat_props, hw_compat_7_1, hw_compat_7_1_len);
 }
-DEFINE_VIRT_MACHINE(7, 1, false)
+DEFINE_VIRT_MACHINE(7, 1)
 
 static void virt_machine_7_0_options(MachineClass *mc)
 {
 virt_machine_7_1_options(mc);
 compat_props_add(mc->compat_props, hw_compat_7_0, hw_compat_7_0_len);
 }
-DEFINE_VIRT_MACHINE(7, 0, false)
+DEFINE_VIRT_MACHINE(7, 0)
 
 static void virt_machine_6_2_options(MachineClass *mc)
 {
 virt_machine_7_0_options(mc);
 compat_props_add(mc->compat_props, hw_compat_6_2, hw_compat_6_2_len);
 }
-DEFINE_VIRT_MACHINE(6, 2, false)
+DEFINE_VIRT_MACHINE(6, 2)
 
 static void virt_machine_6_1_options(MachineClass *mc)
 {
 virt_machine_6_2_options(mc);
 compat_props_add(mc->compat_props, hw_compat_6_1, hw_compat_6_1_len);
 }
-DEFINE_VIRT_MACHINE(6, 1, false)
+DEFINE_VIRT_MACHINE(6, 1)
 
 static void virt_machine_6_0_options(MachineClass *mc)
 {
 virt_machine_6_1_options(mc);
 compat_props_add(mc->compat_props, hw_compat_6_0, hw_compat_6_0_len);
 }
-DEF

[PATCH 00/14] hw: define and enforce a standard lifecycle for versioned machines

2024-05-01 Thread Daniel P . Berrangé
Thomas proposed a new deprecation and removal policy for versioned
machine types that would see them liable for deletion after 6 years:

  https://lists.nongnu.org/archive/html/qemu-devel/2024-04/msg04683.html

This suggest was met with broad approval, however, I suggested that we
could take it further and actually mark them deprecated sooner, at the
3 year timeframe, and also fully automate the enablement of the runtime
deprecation warning without developer intervention on every release
cycle.

This series implements my suggestions.

The first patch introduces some helper macros and documents a standard
code pattern for defining versioned machine types across targets.

The next 6 patches convert existing targets with versioned machine
types (arm, s390x, ppc, m68k, i386) to use the new helper macros and
code patterns.

A further patch introduces some helper macros for automating the
handling of deprecation and deletion of versioned machine types.

Two more patches then enable the deprecation and deletion logic
across all versioned machines

Finally we do some cleanup and document the new policy.

a tangent about VERSION file handling...

One oddity here, is that during the development and release
candidate phases the automatic logic in this series has an off-by-1
error.

This is because when we, for example, add the "9.1" machine type
versions, the VERSION file is still reporting '9.0.50', and then
'9.0.9{1,2,3,4}'.

IOW, during development and in rc candidates, we fail to deprecate
and delete 1 machine type. We should already have deprecated the
6.1 machine types, but the most recently deprecated is 6.0.
This is pretty harmless since the final release does the right
thing.

I wonder, however, whether we would benefit from changing how we
update the VERSION file.

eg instead of re-using the micro digit to indicate a dev or rc
snapshot, represent those explicitly. eg "9.1.0-dev" and
"9.1.0-rc1", "9.1.0-rc2", etc in VERSION.

We don't use the full QEMU_VERSION in the code in all that many
places. It appears in some help messages for command line tools,
and in QMP query-version response, and in a few other misc places.
At a glance it appears all of those places would easily handle a
tagged version.

For release candidates in particular I think it would be saner
to show the user the actual version the release is about to become,
rather than the previous release's version. This would make the
reported version match the rc tarball naming too which would be
nice.

Anyway, this isn't a blocker for this machine type versioning
proposal, just a thought

Daniel P. Berrangé (14):
  include/hw: add helpers for defining versioned machine types
  hw/arm: convert 'virt' machine definitions to use new macros
  hw/s390x: convert 'ccw' machine definitions to use new macros
  hw/ppc: convert 'spapr' machine definitions to use new macros
  hw/m68k: convert 'virt' machine definitions to use new macros
  hw/i386: convert 'i440fx' machine definitions to use new macros
  hw/i386: convert 'q35' machine definitions to use new macros
  include/hw: add macros for deprecation & removal of versioned machines
  hw: temporarily disable deletion of versioned machine types
  hw: set deprecation info for all versioned machine types
  hw: skip registration of outdated versioned machine types
  hw/ppc: remove obsolete manual deprecation reason string of spapr
machines
  hw/i386: remove obsolete manual deprecation reason string of i440fx
machines
  docs: document special exception for machine type deprecation &
removal

 docs/about/deprecated.rst  |  12 ++
 hw/arm/virt.c  |  30 +++--
 hw/i386/pc_piix.c  | 252 +++---
 hw/i386/pc_q35.c   | 215 +
 hw/m68k/virt.c |  53 +---
 hw/ppc/spapr.c |  96 +++--
 hw/s390x/s390-virtio-ccw.c |  98 --
 include/hw/boards.h| 268 +
 include/hw/i386/pc.h   |  32 +
 9 files changed, 666 insertions(+), 390 deletions(-)

-- 
2.43.0




[PATCH 01/14] include/hw: add helpers for defining versioned machine types

2024-05-01 Thread Daniel P . Berrangé
The various targets which define versioned machine types have
a bunch of obfuscated macro code for defining unique function
and variable names using string concatenation.

This addes a couple of helpers to improve the clarity of such
code macro.

Signed-off-by: Daniel P. Berrangé 
---
 include/hw/boards.h | 166 
 1 file changed, 166 insertions(+)

diff --git a/include/hw/boards.h b/include/hw/boards.h
index 2fa800f11a..47ca450fca 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -414,6 +414,172 @@ struct MachineState {
 struct NumaState *numa_state;
 };
 
+/*
+ * The macros which follow are intended to facilitate the
+ * definition of versioned machine types, using a somewhat
+ * similar pattern across targets:
+ *
+ *  #define DEFINE_VIRT_MACHINE_IMPL(latest, ...) \
+ *  static void MACHINE_VER_SYM(class_init, virt, __VA_ARGS__)( \
+ *  ObjectClass *oc, \
+ *  void *data) \
+ *  { \
+ *  MachineClass *mc = MACHINE_CLASS(oc); \
+ *  MACHINE_VER_SYM(options, virt, __VA_ARGS__)(mc); \
+ *  mc->desc = "QEMU " MACHINE_VER_STR(__VA_ARGS__) " Virtual 
Machine"; \
+ *  if (latest) { \
+ *  mc->alias = "virt"; \
+ *  } \
+ *  } \
+ *  static const TypeInfo MACHINE_VER_SYM(info, virt, __VA_ARGS__) = { \
+ *  .name = MACHINE_VER_TYPE_NAME("virt", __VA_ARGS__), \
+ *  .parent = TYPE_VIRT_MACHINE, \
+ *  .class_init = MACHINE_VER_SYM(class_init, virt, __VA_ARGS__), \
+ *  }; \
+ *  static void MACHINE_VER_SYM(register, virt, __VA_ARGS__)(void) \
+ *  { \
+ *  type_register_static(&MACHINE_VER_SYM(info, virt, __VA_ARGS__)); \
+ *  } \
+ *  type_init(MACHINE_VER_SYM(register, virt, __VA_ARGS__));
+ *
+ * Following this, one (or more) helpers can be added for
+ * whichever scenarios need to be catered for with a machine:
+ *
+ *  // Normal 2 digit, marked as latest eg 'virt-9.0'
+ *  #define DEFINE_VIRT_MACHINE_LATEST(major, minor) \
+ *  DEFINE_VIRT_MACHINE_IMPL(true, major, minor)
+ *
+ *  // Normal 2 digit eg 'virt-9.0'
+ *  #define DEFINE_VIRT_MACHINE(major, minor) \
+ *  DEFINE_VIRT_MACHINE_IMPL(false, major, minor)
+ *
+ *  // Bugfix 3 digit  eg 'virt-9.0.1'
+ *  #define DEFINE_VIRT_MACHINE_BUGFIX(major, minor, micro) \
+ *  DEFINE_VIRT_MACHINE_IMPL(false, major, minor, micro)
+ *
+ *  // Tagged 2 digit  eg 'virt-9.0-extra'
+ *  #define DEFINE_VIRT_MACHINE_TAGGED(major, minor, tag) \
+ *  DEFINE_VIRT_MACHINE_IMPL(false, major, minor, _, tag)
+ *
+ *  // Tagged bugffix 2 digit  eg 'virt-9.0.1-extra'
+ *  #define DEFINE_VIRT_MACHINE_TAGGED(major, minor, micro, tag) \
+ *  DEFINE_VIRT_MACHINE_IMPL(false, major, minor, micro, _, tag)
+ */
+
+#define _MACHINE_VER_PICK(x1, x2, x3, x4, x5, x6, ...) x6
+
+/*
+ * Construct a human targetted machine version string.
+ *
+ * Can be invoked with various signatures
+ *
+ *  MACHINE_VER_STR(sym, prefix, major, minor)
+ *  MACHINE_VER_STR(sym, prefix, major, minor, micro)
+ *  MACHINE_VER_STR(sym, prefix, major, minor, _, tag)
+ *  MACHINE_VER_STR(sym, prefix, major, minor, micro, _, tag)
+ *
+ * Respectively emitting symbols with the format
+ *
+ *   "{major}.{minor}"
+ *   "{major}.{minor}-{tag}"
+ *   "{major}.{minor}.{micro}"
+ *   "{major}.{minor}.{micro}-{tag}"
+ */
+#define _MACHINE_VER_STR2(major, minor) \
+#major "." #minor
+
+#define _MACHINE_VER_STR3(major, minor, micro) \
+#major "." #minor "." #micro
+
+#define _MACHINE_VER_STR4(major, minor, _unused_, tag) \
+#major "." #minor "-" #tag
+
+#define _MACHINE_VER_STR5(major, minor, micro, _unused_, tag) \
+#major "." #minor "." #micro "-" #tag
+
+#define MACHINE_VER_STR(...) \
+_MACHINE_VER_PICK(__VA_ARGS__, \
+  _MACHINE_VER_STR5, \
+  _MACHINE_VER_STR4, \
+  _MACHINE_VER_STR3, \
+  _MACHINE_VER_STR2) (__VA_ARGS__)
+
+
+/*
+ * Construct a QAPI type name for a versioned machine
+ * type
+ *
+ * Can be invoked with various signatures
+ *
+ *  MACHINE_VER_TYPE_NAME(prefix, major, minor)
+ *  MACHINE_VER_TYPE_NAME(prefix, major, minor, micro)
+ *  MACHINE_VER_TYPE_NAME(prefix, major, minor, _, tag)
+ *  MACHINE_VER_TYPE_NAME(prefix, major, minor, micro, _, tag)
+ *
+ * Respectively emitting symbols with the format
+ *
+ *   "{prefix}-{major}.{minor}"
+ *   "{prefix}-{major}.{minor}.{micro}"
+ *   "{prefix}-{major}.{minor}-{tag}"
+ *   "{prefix}-{major}.{minor}.{micro}-{tag}"
+ */
+#define _MACHINE_VER_TYPE_NAME2(prefix, major, minor)   \
+prefix "-" #major "." #minor TYPE_MACHINE_SUFFIX
+
+#define _MACHINE_VER_TYPE_NAME3(prefix, major, minor, micro) \
+prefix "-" #major "." #minor "." #micro TYPE_MACHINE_SUFFIX
+
+#define _MACHINE_VER_TYPE_NAME4(prefix, major, minor, _unused_, tag) \
+prefix "-" #major "." #minor "-" #tag TYPE_MACHINE_SUFFIX
+
+#define _MACHINE_VER_TYPE_NAME5(prefix, major, minor, micr

  1   2   >