Re: [PATCH 6/6] reset: Add RESET_TYPE_SNAPSHOT_LOAD

2024-04-16 Thread Luc Michel
On 17:08 Fri 12 Apr , Peter Maydell wrote:
> Some devices and machines need to handle the reset before a vmsave
> snapshot is loaded differently -- the main user is the handling of
> RNG seed information, which does not want to put a new RNG seed into
> a ROM blob when we are doing a snapshot load.
> 
> Currently this kind of reset handling is supported only for:
>  * TYPE_MACHINE reset methods, which take a ShutdownCause argument
>  * reset functions registered with qemu_register_reset_nosnapshotload
> 
> To allow a three-phase-reset device to also distinguish "snapshot
> load" reset from the normal kind, add a new ResetType
> RESET_TYPE_SNAPSHOT_LOAD. All our existing reset methods ignore
> the reset type, so we don't need to update any device code.
> 
> Add the enum type, and make qemu_devices_reset() use the
> right reset type for the ShutdownCause it is passed. This
> allows us to get rid of the device_reset_reason global we
> were using to implement qemu_register_reset_nosnapshotload().
> 
> Signed-off-by: Peter Maydell 

Reviewed-by: Luc Michel 

> ---
>  docs/devel/reset.rst| 17 ++---
>  include/hw/resettable.h |  1 +
>  hw/core/reset.c | 15 ---
>  hw/core/resettable.c|  4 
>  4 files changed, 19 insertions(+), 18 deletions(-)
> 
> diff --git a/docs/devel/reset.rst b/docs/devel/reset.rst
> index 49baa1ea271..9746a4e8a0b 100644
> --- a/docs/devel/reset.rst
> +++ b/docs/devel/reset.rst
> @@ -27,9 +27,7 @@ instantly reset an object, without keeping it in reset 
> state, just call
>  ``resettable_reset()``. These functions take two parameters: a pointer to the
>  object to reset and a reset type.
> 
> -Several types of reset will be supported. For now only cold reset is defined;
> -others may be added later. The Resettable interface handles reset types with 
> an
> -enum:
> +The Resettable interface handles reset types with an enum ``ResetType``:
> 
>  ``RESET_TYPE_COLD``
>Cold reset is supported by every resettable object. In QEMU, it means we 
> reset
> @@ -37,6 +35,19 @@ enum:
>from what is a real hardware cold reset. It differs from other resets (like
>warm or bus resets) which may keep certain parts untouched.
> 
> +``RESET_TYPE_SNAPSHOT_LOAD``
> +  This is called for a reset which is being done to put the system into a
> +  clean state prior to loading a snapshot. (This corresponds to a reset
> +  with ``SHUTDOWN_CAUSE_SNAPSHOT_LOAD``.) Almost all devices should treat
> +  this the same as ``RESET_TYPE_COLD``. The main exception is devices which
> +  have some non-deterministic state they want to reinitialize to a different
> +  value on each cold reset, such as RNG seed information, and which they
> +  must not reinitialize on a snapshot-load reset.
> +
> +Devices which implement reset methods must treat any unknown ``ResetType``
> +as equivalent to ``RESET_TYPE_COLD``; this will reduce the amount of
> +existing code we need to change if we add more types in future.
> +
>  Calling ``resettable_reset()`` is equivalent to calling
>  ``resettable_assert_reset()`` then ``resettable_release_reset()``. It is
>  possible to interleave multiple calls to these three functions. There may
> diff --git a/include/hw/resettable.h b/include/hw/resettable.h
> index 3161e471c9b..7e249deb8b5 100644
> --- a/include/hw/resettable.h
> +++ b/include/hw/resettable.h
> @@ -35,6 +35,7 @@ typedef struct ResettableState ResettableState;
>   */
>  typedef enum ResetType {
>  RESET_TYPE_COLD,
> +RESET_TYPE_SNAPSHOT_LOAD,
>  } ResetType;
> 
>  /*
> diff --git a/hw/core/reset.c b/hw/core/reset.c
> index f9fef45e050..58dfc8db3dc 100644
> --- a/hw/core/reset.c
> +++ b/hw/core/reset.c
> @@ -43,13 +43,6 @@ static ResettableContainer *get_root_reset_container(void)
>  return root_reset_container;
>  }
> 
> -/*
> - * Reason why the currently in-progress qemu_devices_reset() was called.
> - * If we made at least SHUTDOWN_CAUSE_SNAPSHOT_LOAD have a corresponding
> - * ResetType we could perhaps avoid the need for this global.
> - */
> -static ShutdownCause device_reset_reason;
> -
>  /*
>   * This is an Object which implements Resettable simply to call the
>   * callback function in the hold phase.
> @@ -77,8 +70,7 @@ static void legacy_reset_hold(Object *obj, ResetType type)
>  {
>  LegacyReset *lr = LEGACY_RESET(obj);
> 
> -if (device_reset_reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD &&
> -lr->skip_on_snapshot_load) {
> +if (type == RESET_TYPE_SNAPSHOT_LOAD && lr->skip_on_snapshot_load) {
>  return;
>  }
>  lr->func(lr->opaque);
> @@ -180,8 +172,9 @@ void qemu_unregis

Re: [PATCH 1/6] hw/misc: Don't special case RESET_TYPE_COLD in npcm7xx_clk, gcr

2024-04-16 Thread Luc Michel
On 17:08 Fri 12 Apr , Peter Maydell wrote:
> Caution: This message originated from an External Source. Use proper caution 
> when opening attachments, clicking links, or responding.
> 
> 
> The npcm7xx_clk and npcm7xx_gcr device reset methods look at
> the ResetType argument and only handle RESET_TYPE_COLD,
> producing a warning if another reset type is passed. This
> is different from how every other three-phase-reset method
> we have works, and makes it difficult to add new reset types.
> 
> A better pattern is "assume that any reset type you don't know
> about should be handled like RESET_TYPE_COLD"; switch these
> devices to do that. Then adding a new reset type will only
> need to touch those devices where its behaviour really needs
> to be different from the standard cold reset.
> 
> Signed-off-by: Peter Maydell 

Reviewed-by: Luc Michel 

> ---
>  hw/misc/npcm7xx_clk.c | 13 +++--
>  hw/misc/npcm7xx_gcr.c | 12 
>  2 files changed, 7 insertions(+), 18 deletions(-)
> 
> diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
> index ac1622c38aa..2098c85ee01 100644
> --- a/hw/misc/npcm7xx_clk.c
> +++ b/hw/misc/npcm7xx_clk.c
> @@ -873,20 +873,13 @@ static void npcm7xx_clk_enter_reset(Object *obj, 
> ResetType type)
> 
>  QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
> 
> -switch (type) {
> -case RESET_TYPE_COLD:
> -memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
> -s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> -npcm7xx_clk_update_all_clocks(s);
> -return;
> -}
> -
> +memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
> +s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +npcm7xx_clk_update_all_clocks(s);
>  /*
>   * A small number of registers need to be reset on a core domain reset,
>   * but no such reset type exists yet.
>   */
> -qemu_log_mask(LOG_UNIMP, "%s: reset type %d not implemented.",
> -  __func__, type);
>  }
> 
>  static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
> diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c
> index 9252f9d1488..c4c4e246d7e 100644
> --- a/hw/misc/npcm7xx_gcr.c
> +++ b/hw/misc/npcm7xx_gcr.c
> @@ -159,14 +159,10 @@ static void npcm7xx_gcr_enter_reset(Object *obj, 
> ResetType type)
> 
>  QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
> 
> -switch (type) {
> -case RESET_TYPE_COLD:
> -memcpy(s->regs, cold_reset_values, sizeof(s->regs));
> -s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron;
> -s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr;
> -s->regs[NPCM7XX_GCR_INTCR3] = s->reset_intcr3;
> -break;
> -}
> +memcpy(s->regs, cold_reset_values, sizeof(s->regs));
> +s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron;
> +s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr;
> +s->regs[NPCM7XX_GCR_INTCR3] = s->reset_intcr3;
>  }
> 
>  static void npcm7xx_gcr_realize(DeviceState *dev, Error **errp)
> --
> 2.34.1
> 
> 

-- 



Re: [PATCH 4/6] hw, target: Add ResetType argument to hold and exit phase methods

2024-04-16 Thread Luc Michel
On 17:08 Fri 12 Apr , Peter Maydell wrote:
> We pass a ResetType argument to the Resettable class enter
> phase method, but we don't pass it to hold and exit, even though
> the callsites have it readily available. This means that if
> a device cared about the ResetType it would need to record it
> in the enter phase method to use later on. Pass the type to
> all three of the phase methods to avoid having to do that.
> 
> Commit created with
> 
>   for dir in hw target include; do \
>   spatch --macro-file scripts/cocci-macro-file.h \
>  --sp-file scripts/coccinelle/reset-type.cocci \
>  --keep-comments --smpl-spacing --in-place \
>  --include-headers --dir $dir; done
> 
> and no manual edits.
> 
> Signed-off-by: Peter Maydell 

Reviewed-by: Luc Michel 

> ---
>  include/hw/resettable.h |  4 ++--
>  hw/adc/npcm7xx_adc.c|  2 +-
>  hw/arm/pxa2xx_pic.c |  2 +-
>  hw/arm/smmu-common.c|  2 +-
>  hw/arm/smmuv3.c |  4 ++--
>  hw/arm/stellaris.c  | 10 +-
>  hw/audio/asc.c  |  2 +-
>  hw/char/cadence_uart.c  |  2 +-
>  hw/char/sifive_uart.c   |  2 +-
>  hw/core/cpu-common.c|  2 +-
>  hw/core/qdev.c  |  4 ++--
>  hw/core/reset.c |  2 +-
>  hw/core/resettable.c|  4 ++--
>  hw/display/virtio-vga.c |  4 ++--
>  hw/gpio/npcm7xx_gpio.c  |  2 +-
>  hw/gpio/pl061.c |  2 +-
>  hw/gpio/stm32l4x5_gpio.c|  2 +-
>  hw/hyperv/vmbus.c   |  2 +-
>  hw/i2c/allwinner-i2c.c  |  2 +-
>  hw/i2c/npcm7xx_smbus.c  |  2 +-
>  hw/input/adb.c  |  2 +-
>  hw/input/ps2.c  | 12 ++--
>  hw/intc/arm_gic_common.c|  2 +-
>  hw/intc/arm_gic_kvm.c   |  4 ++--
>  hw/intc/arm_gicv3_common.c  |  2 +-
>  hw/intc/arm_gicv3_its.c |  4 ++--
>  hw/intc/arm_gicv3_its_common.c  |  2 +-
>  hw/intc/arm_gicv3_its_kvm.c |  4 ++--
>  hw/intc/arm_gicv3_kvm.c |  4 ++--
>  hw/intc/xics.c  |  2 +-
>  hw/m68k/q800-glue.c |  2 +-
>  hw/misc/djmemc.c|  2 +-
>  hw/misc/iosb.c  |  2 +-
>  hw/misc/mac_via.c   |  8 
>  hw/misc/macio/cuda.c|  4 ++--
>  hw/misc/macio/pmu.c |  4 ++--
>  hw/misc/mos6522.c   |  2 +-
>  hw/misc/npcm7xx_mft.c   |  2 +-
>  hw/misc/npcm7xx_pwm.c   |  2 +-
>  hw/misc/stm32l4x5_exti.c|  2 +-
>  hw/misc/stm32l4x5_rcc.c | 10 +-
>  hw/misc/stm32l4x5_syscfg.c  |  2 +-
>  hw/misc/xlnx-versal-cframe-reg.c|  2 +-
>  hw/misc/xlnx-versal-crl.c   |  2 +-
>  hw/misc/xlnx-versal-pmc-iou-slcr.c  |  2 +-
>  hw/misc/xlnx-versal-trng.c  |  2 +-
>  hw/misc/xlnx-versal-xramc.c |  2 +-
>  hw/misc/xlnx-zynqmp-apu-ctrl.c  |  2 +-
>  hw/misc/xlnx-zynqmp-crf.c   |  2 +-
>  hw/misc/zynq_slcr.c |  4 ++--
>  hw/net/can/xlnx-zynqmp-can.c|  2 +-
>  hw/net/e1000.c  |  2 +-
>  hw/net/e1000e.c |  2 +-
>  hw/net/igb.c|  2 +-
>  hw/net/igbvf.c  |  2 +-
>  hw/nvram/xlnx-bbram.c   |  2 +-
>  hw/nvram/xlnx-versal-efuse-ctrl.c   |  2 +-
>  hw/nvram/xlnx-zynqmp-efuse.c|  2 +-
>  hw/pci-bridge/cxl_root_port.c   |  4 ++--
>  hw/pci-bridge/pcie_root_port.c  |  2 +-
>  hw/pci-host/bonito.c|  2 +-
>  hw/pci-host/pnv_phb.c   |  4 ++--
>  hw/pci-host/pnv_phb3_msi.c  |  4 ++--
>  hw/pci/pci.c|  4 ++--
>  hw/rtc/mc146818rtc.c|  2 +-
>  hw/s390x/css-bridge.c   |  2 +-
>  hw/sensor/adm1266.c |  2 +-
>  hw/sensor/adm1272.c |  2 +-
>  hw/sensor/isl_pmbus_vr.c| 10 +-
>  hw/sensor/max31785.c|  2 +-
>  hw/sensor/max34451.c|  2 +-
>  hw/ssi/npcm7xx_fiu.c|  2 +-
>  hw/timer/etraxfs_timer.c|  2 +-
>  hw/timer/npcm7xx_timer.c|  2 +-
>  hw/usb/hcd-dwc2.c   |  8 
>  hw/usb/xlnx-versal-usb2-ctrl-regs.c |  2 +-
>  hw/virtio/virtio-pci.c  |  2 +-
>  target/arm/cpu.c|  4 ++--
>  target/avr/cpu.c|  4 ++--
>  target/cris/cpu.c   |  4 ++--
>  target/hexagon/cpu.c  

Re: [PATCH 5/6] docs/devel/reset: Update to new API for hold and exit phase methods

2024-04-16 Thread Luc Michel
On 17:08 Fri 12 Apr , Peter Maydell wrote:
> Update the reset documentation's example code to match the new API
> for the hold and exit phase method APIs where they take a ResetType
> argument.
> 
> Signed-off-by: Peter Maydell 

Reviewed-by: Luc Michel 

> ---
>  docs/devel/reset.rst | 8 
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/docs/devel/reset.rst b/docs/devel/reset.rst
> index 2ea85e7779b..49baa1ea271 100644
> --- a/docs/devel/reset.rst
> +++ b/docs/devel/reset.rst
> @@ -150,25 +150,25 @@ in reset.
>  mydev->var = 0;
>  }
> 
> -static void mydev_reset_hold(Object *obj)
> +static void mydev_reset_hold(Object *obj, ResetType type)
>  {
>  MyDevClass *myclass = MYDEV_GET_CLASS(obj);
>  MyDevState *mydev = MYDEV(obj);
>  /* call parent class hold phase */
>  if (myclass->parent_phases.hold) {
> -myclass->parent_phases.hold(obj);
> +myclass->parent_phases.hold(obj, type);
>  }
>  /* set an IO */
>  qemu_set_irq(mydev->irq, 1);
>  }
> 
> -static void mydev_reset_exit(Object *obj)
> +static void mydev_reset_exit(Object *obj, ResetType type)
>  {
>  MyDevClass *myclass = MYDEV_GET_CLASS(obj);
>  MyDevState *mydev = MYDEV(obj);
>  /* call parent class exit phase */
>  if (myclass->parent_phases.exit) {
> -myclass->parent_phases.exit(obj);
> +myclass->parent_phases.exit(obj, type);
>  }
>  /* clear an IO */
>  qemu_set_irq(mydev->irq, 0);
> --
> 2.34.1
> 
> 

-- 



Re: [PATCH 3/6] scripts/coccinelle: New script to add ResetType to hold and exit phases

2024-04-16 Thread Luc Michel
On 17:08 Fri 12 Apr , Peter Maydell wrote:
> We pass a ResetType argument to the Resettable class enter phase
> method, but we don't pass it to hold and exit, even though the
> callsites have it readily available.  This means that if a device
> cared about the ResetType it would need to record it in the enter
> phase method to use later on.  We should pass the type to all three
> of the phase methods to avoid having to do that.
> 
> This coccinelle script adds the ResetType argument to the hold and
> exit phases of the Resettable interface.
> 
> The first part of the script (rules holdfn_assigned, holdfn_defined,
> exitfn_assigned, exitfn_defined) update implementations of the
> interface within device models, both to change the signature of their
> method implementations and to pass on the reset type when they invoke
> reset on some other device.
> 
> The second part of the script is various special cases:
>  * method callsites in resettable_phase_hold(), resettable_phase_exit()
>and device_phases_reset()
>  * updating the typedefs for the methods
>  * isl_pmbus_vr.c has some code where one device's reset method directly
>calls the implementation of a different device's method
> 
> Signed-off-by: Peter Maydell 

Reviewed-by: Luc Michel 

(I'm not a coccinelle expert but LGTM)

> ---
> The structure here is a bit of an experiment: usually I would make
> the coccinelle script cover the main mechanical change and do the
> special cases by hand-editing. But I thought it might be clearer to
> have the entire next commit be made by coccinelle, so reviewers don't
> have to go hunting through a 99% automated commit for the 1% hand
> written part. Let me know whether you like this or not...
> ---
>  scripts/coccinelle/reset-type.cocci | 133 
>  1 file changed, 133 insertions(+)
>  create mode 100644 scripts/coccinelle/reset-type.cocci
> 
> diff --git a/scripts/coccinelle/reset-type.cocci 
> b/scripts/coccinelle/reset-type.cocci
> new file mode 100644
> index 000..14abdd7bd0c
> --- /dev/null
> +++ b/scripts/coccinelle/reset-type.cocci
> @@ -0,0 +1,133 @@
> +// Convert device code using three-phase reset to add a ResetType
> +// argument to implementations of ResettableHoldPhase and
> +// ResettableEnterPhase methods.
> +//
> +// Copyright Linaro Ltd 2024
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//
> +// for dir in include hw target; do \
> +// spatch --macro-file scripts/cocci-macro-file.h \
> +//--sp-file scripts/coccinelle/reset-type.cocci \
> +//--keep-comments --smpl-spacing --in-place --include-headers \
> +//--dir $dir; done
> +//
> +// This coccinelle script aims to produce a complete change that needs
> +// no human interaction, so as well as the generic "update device
> +// implementations of the hold and exit phase methods" it includes
> +// the special-case transformations needed for the core code and for
> +// one device model that does something a bit nonstandard. Those
> +// special cases are at the end of the file.
> +
> +// Look for where we use a function as a ResettableHoldPhase method,
> +// either by directly assigning it to phases.hold or by calling
> +// resettable_class_set_parent_phases, and remember the function name.
> +@ holdfn_assigned @
> +identifier enterfn, holdfn, exitfn;
> +identifier rc;
> +expression e;
> +@@
> +ResettableClass *rc;
> +...
> +(
> + rc->phases.hold = holdfn;
> +|
> + resettable_class_set_parent_phases(rc, enterfn, holdfn, exitfn, e);
> +)
> +
> +// Look for the definition of the function we found in holdfn_assigned,
> +// and add the new argument. If the function calls a hold function
> +// itself (probably chaining to the parent class reset) then add the
> +// new argument there too.
> +@ holdfn_defined @
> +identifier holdfn_assigned.holdfn;
> +typedef Object;
> +identifier obj;
> +expression parent;
> +@@
> +-holdfn(Object *obj)
> ++holdfn(Object *obj, ResetType type)
> +{
> +<...
> +-parent.hold(obj)
> ++parent.hold(obj, type)
> +...>
> +}
> +
> +// Similarly for ResettableExitPhase.
> +@ exitfn_assigned @
> +identifier enterfn, holdfn, exitfn;
> +identifier rc;
> +expression e;
> +@@
> +ResettableClass *rc;
> +...
> +(
> + rc->phases.exit = exitfn;
> +|
> + resettable_class_set_parent_phases(rc, enterfn, holdfn, exitfn, e);
> +)
> +@ exitfn_defined @
> +identifier exitfn_assigned.exitfn;
> +typedef Object;
> +identifier obj;
> +expression parent;
> +@@
> +-exitfn(Object *obj)
> ++exitfn(Object *obj, ResetType type)
> +{
> +<...
> +-parent.exit(obj)
> ++p

Re: [PATCH 2/6] allwinner-i2c, adm1272: Use device_cold_reset() for software-triggered reset

2024-04-16 Thread Luc Michel
On 17:08 Fri 12 Apr , Peter Maydell wrote:
> Rather than directly calling the device's implementation of its 'hold'
> reset phase, call device_cold_reset(). This means we don't have to
> adjust this callsite when we add another argument to the function
> signature for the hold and exit reset methods.
> 
> Signed-off-by: Peter Maydell 

Reviewed-by: Luc Michel 

> ---
>  hw/i2c/allwinner-i2c.c | 3 +--
>  hw/sensor/adm1272.c| 2 +-
>  2 files changed, 2 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/i2c/allwinner-i2c.c b/hw/i2c/allwinner-i2c.c
> index 8abcc39a5c2..96c20c86372 100644
> --- a/hw/i2c/allwinner-i2c.c
> +++ b/hw/i2c/allwinner-i2c.c
> @@ -385,8 +385,7 @@ static void allwinner_i2c_write(void *opaque, hwaddr 
> offset,
>  break;
>  case TWI_SRST_REG:
>  if (((value & TWI_SRST_MASK) == 0) && (s->srst & TWI_SRST_MASK)) {
> -/* Perform reset */
> -allwinner_i2c_reset_hold(OBJECT(s));
> +device_cold_reset(DEVICE(s));
>  }
>  s->srst = value & TWI_SRST_MASK;
>  break;
> diff --git a/hw/sensor/adm1272.c b/hw/sensor/adm1272.c
> index 1f7c8abb838..a19557ec9ea 100644
> --- a/hw/sensor/adm1272.c
> +++ b/hw/sensor/adm1272.c
> @@ -386,7 +386,7 @@ static int adm1272_write_data(PMBusDevice *pmdev, const 
> uint8_t *buf,
>  break;
> 
>  case ADM1272_MFR_POWER_CYCLE:
> -adm1272_exit_reset((Object *)s);
> +device_cold_reset(DEVICE(s));
>  break;
> 
>  case ADM1272_HYSTERESIS_LOW:
> --
> 2.34.1
> 
> 

-- 



Re: [PATCH for-9.0] Fix some typos in documentation (found by codespell)

2024-04-02 Thread Luc Michel
On 18:15 Sun 31 Mar , Stefan Weil wrote:
> Signed-off-by: Stefan Weil 

Reviewed-by: Luc Michel 

> ---
>  docs/devel/atomics.rst | 2 +-
>  docs/devel/ci-jobs.rst.inc | 2 +-
>  docs/devel/clocks.rst  | 2 +-
>  docs/system/i386/sgx.rst   | 2 +-
>  qapi/qom.json  | 2 +-
>  5 files changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/docs/devel/atomics.rst b/docs/devel/atomics.rst
> index ff9b5ee30c..b77c6e13e1 100644
> --- a/docs/devel/atomics.rst
> +++ b/docs/devel/atomics.rst
> @@ -119,7 +119,7 @@ The only guarantees that you can rely upon in this case 
> are:
>ordinary accesses instead cause data races if they are concurrent with
>other accesses of which at least one is a write.  In order to ensure this,
>the compiler will not optimize accesses out of existence, create 
> unsolicited
> -  accesses, or perform other similar optimzations.
> +  accesses, or perform other similar optimizations.
>  
>  - acquire operations will appear to happen, with respect to the other
>components of the system, before all the LOAD or STORE operations
> diff --git a/docs/devel/ci-jobs.rst.inc b/docs/devel/ci-jobs.rst.inc
> index ec33e6ee2b..be06322279 100644
> --- a/docs/devel/ci-jobs.rst.inc
> +++ b/docs/devel/ci-jobs.rst.inc
> @@ -115,7 +115,7 @@ CI pipeline.
>  QEMU_JOB_SKIPPED
>  
>  
> -The job is not reliably successsful in general, so is not
> +The job is not reliably successful in general, so is not
>  currently suitable to be run by default. Ideally this should
>  be a temporary marker until the problems can be addressed, or
>  the job permanently removed.
> diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst
> index b2d1148cdb..177ee1c90d 100644
> --- a/docs/devel/clocks.rst
> +++ b/docs/devel/clocks.rst
> @@ -279,7 +279,7 @@ You can change the multiplier and divider of a clock at 
> runtime,
>  so you can use this to model clock controller devices which
>  have guest-programmable frequency multipliers or dividers.
>  
> -Similary to ``clock_set()``, ``clock_set_mul_div()`` returns ``true`` if
> +Similarly to ``clock_set()``, ``clock_set_mul_div()`` returns ``true`` if
>  the clock state was modified; that is, if the multiplier or the diviser
>  or both were changed by the call.
>  
> diff --git a/docs/system/i386/sgx.rst b/docs/system/i386/sgx.rst
> index 0f0a73f758..c293f7f44e 100644
> --- a/docs/system/i386/sgx.rst
> +++ b/docs/system/i386/sgx.rst
> @@ -6,7 +6,7 @@ Overview
>  
>  Intel Software Guard eXtensions (SGX) is a set of instructions and mechanisms
>  for memory accesses in order to provide security accesses for sensitive
> -applications and data. SGX allows an application to use it's pariticular
> +applications and data. SGX allows an application to use its particular
>  address space as an *enclave*, which is a protected area provides 
> confidentiality
>  and integrity even in the presence of privileged malware. Accesses to the
>  enclave memory area from any software not resident in the enclave are 
> prevented,
> diff --git a/qapi/qom.json b/qapi/qom.json
> index 8d4ca8ed92..85e6b4f84a 100644
> --- a/qapi/qom.json
> +++ b/qapi/qom.json
> @@ -802,7 +802,7 @@
>  #
>  # @fd: file descriptor name previously passed via 'getfd' command,
>  # which represents a pre-opened /dev/iommu.  This allows the
> -# iommufd object to be shared accross several subsystems (VFIO,
> +# iommufd object to be shared across several subsystems (VFIO,
>  # VDPA, ...), and the file descriptor to be shared with other
>  # process, e.g. DPDK.  (default: QEMU opens /dev/iommu by itself)
>  #
> -- 
> 2.39.2
> 

-- 



Re: [PATCH-for-9.0 1/2] hw/clock: Let clock_set_mul_div() return boolean value

2024-03-25 Thread Luc Michel
On 09:40 Mon 25 Mar , Luc Michel wrote:
> On 16:58 Fri 22 Mar , Philippe Mathieu-Daudé wrote:
> > Let clock_set_mul_div() return a boolean value whether the
> > clock has been updated or not, similarly to clock_set().
> > 
> > Signed-off-by: Philippe Mathieu-Daudé 
> 
> Acked-by: Luc Michel 

Sorry, I forgot, as Peter suggested, can you add a word in the doc
about this?

Something in the vein of:

+ Similary to ``clock_set()``, ``clock_set_mul_div()`` returns ``true`` if
+ the clock state was modified, that it, if the multiplier or the diviser
+ or both were changed by the call.
+ 
Note that ``clock_set_mul_div()`` does not automatically
call ``clock_propagate()``. If you make a runtime change to the
multiplier or divider you must call clock_propagate() yourself.

Thanks!

-- 
Luc

> 
> > ---
> >  include/hw/clock.h | 4 +++-
> >  hw/core/clock.c| 8 +++-
> >  2 files changed, 10 insertions(+), 2 deletions(-)
> > 
> > diff --git a/include/hw/clock.h b/include/hw/clock.h
> > index bb12117f67..eb58599131 100644
> > --- a/include/hw/clock.h
> > +++ b/include/hw/clock.h
> > @@ -357,6 +357,8 @@ char *clock_display_freq(Clock *clk);
> >   * @multiplier: multiplier value
> >   * @divider: divider value
> >   *
> > + * @return: true if the clock is changed.
> > + *
> >   * By default, a Clock's children will all run with the same period
> >   * as their parent. This function allows you to adjust the multiplier
> >   * and divider used to derive the child clock frequency.
> > @@ -374,6 +376,6 @@ char *clock_display_freq(Clock *clk);
> >   * Note that this function does not call clock_propagate(); the
> >   * caller should do that if necessary.
> >   */
> > -void clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider);
> > +bool clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider);
> >  
> >  #endif /* QEMU_HW_CLOCK_H */
> > diff --git a/hw/core/clock.c b/hw/core/clock.c
> > index d82e44cd1a..a19c7db7df 100644
> > --- a/hw/core/clock.c
> > +++ b/hw/core/clock.c
> > @@ -143,14 +143,20 @@ char *clock_display_freq(Clock *clk)
> >  return freq_to_str(clock_get_hz(clk));
> >  }
> >  
> > -void clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider)
> > +bool clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider)
> >  {
> >  assert(divider != 0);
> >  
> > +if (clk->multiplier == multiplier && clk->divider == divider) {
> > +return false;
> > +}
> > +
> >  trace_clock_set_mul_div(CLOCK_PATH(clk), clk->multiplier, multiplier,
> >  clk->divider, divider);
> >  clk->multiplier = multiplier;
> >  clk->divider = divider;
> > +
> > +return true;
> >  }
> >  
> >  static void clock_initfn(Object *obj)
> > -- 
> > 2.41.0
> > 
> 

-- 



Re: [PATCH-for-9.0 2/2] hw/misc/stm32l4x5_rcc: Propagate period when enabling a clock

2024-03-25 Thread Luc Michel
On 16:39 Fri 22 Mar , Peter Maydell wrote:
> On Fri, 22 Mar 2024 at 15:59, Philippe Mathieu-Daudé  
> wrote:
> >
> > From: Arnaud Minier 
> >
> > The "clock_set_mul_div" function doesn't propagate the clock period
> > to the children if it is changed (e.g. by enabling/disabling a clock
> > multiplexer).
> > This was overlooked during the implementation due to late changes.
> >
> > This commit propagates the change if the multiplier or divider changes.
> >
> > Fixes: ec7d83acbd ("hw/misc/stm32l4x5_rcc: Add an internal clock 
> > multiplexer object")
> > Signed-off-by: Arnaud Minier 
> > Signed-off-by: Inès Varhol 
> > Message-ID: <20240317103918.44375-2-arnaud.min...@telecom-paris.fr>
> > [PMD: Check clock_set_mul_div() return value]
> > Signed-off-by: Philippe Mathieu-Daudé 
> > ---
> >  hw/misc/stm32l4x5_rcc.c | 5 -
> >  1 file changed, 4 insertions(+), 1 deletion(-)
> >
> > diff --git a/hw/misc/stm32l4x5_rcc.c b/hw/misc/stm32l4x5_rcc.c
> > index bc2d63528b..7ad628b296 100644
> > --- a/hw/misc/stm32l4x5_rcc.c
> > +++ b/hw/misc/stm32l4x5_rcc.c
> > @@ -59,7 +59,10 @@ static void clock_mux_update(RccClockMuxState *mux, bool 
> > bypass_source)
> >  freq_multiplier = mux->divider;
> >  }
> >
> > -clock_set_mul_div(mux->out, freq_multiplier, mux->multiplier);
> > +if (clock_set_mul_div(mux->out, freq_multiplier, mux->multiplier)) {
> > +clock_propagate(mux->out);
> > +}
> > +
> >  clock_update(mux->out, clock_get(current_source));
> 
> clock_update() also calls clock_propagate(), so this doesn't
> seem entirely right: shouldn't we figure out whether we need to
> do a clock_propagate() and do it once? (Maybe what seems odd to me
> is that clock_set() does clock_propagate() for you but
> clock_set_mul_div() does not...)
clock_set() does not call clock_propagate(). clock_update() is a
clock_set() followed by a clock_propagate() if the period changed.

I think this is where the problem comes from here. clock_update() call
won't call clock_propagate() if the clock period does not change.

I think you'll want something like:
bool changed;

changed = clock_set_mul_div(mux->out, freq_multiplier, mux->multiplexer);
changed ||= clock_set(clock_get(current_source));

if (changed) {
clock_propagate(mux->out);
}
 
Thanks,

-- 
Luc

> 
> (Also I think we should have the information we need now to be able
> to do the "reduce log spam" in the comment -- if neither
> clock_set_mul_div() nor clock_update() needed to do anything
> then we didn't actually change the config.)
> 
> -- PMM

-- 



Re: [PATCH-for-9.0 1/2] hw/clock: Let clock_set_mul_div() return boolean value

2024-03-25 Thread Luc Michel
On 16:58 Fri 22 Mar , Philippe Mathieu-Daudé wrote:
> Let clock_set_mul_div() return a boolean value whether the
> clock has been updated or not, similarly to clock_set().
> 
> Signed-off-by: Philippe Mathieu-Daudé 

Acked-by: Luc Michel 

> ---
>  include/hw/clock.h | 4 +++-
>  hw/core/clock.c| 8 +++-
>  2 files changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/include/hw/clock.h b/include/hw/clock.h
> index bb12117f67..eb58599131 100644
> --- a/include/hw/clock.h
> +++ b/include/hw/clock.h
> @@ -357,6 +357,8 @@ char *clock_display_freq(Clock *clk);
>   * @multiplier: multiplier value
>   * @divider: divider value
>   *
> + * @return: true if the clock is changed.
> + *
>   * By default, a Clock's children will all run with the same period
>   * as their parent. This function allows you to adjust the multiplier
>   * and divider used to derive the child clock frequency.
> @@ -374,6 +376,6 @@ char *clock_display_freq(Clock *clk);
>   * Note that this function does not call clock_propagate(); the
>   * caller should do that if necessary.
>   */
> -void clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider);
> +bool clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider);
>  
>  #endif /* QEMU_HW_CLOCK_H */
> diff --git a/hw/core/clock.c b/hw/core/clock.c
> index d82e44cd1a..a19c7db7df 100644
> --- a/hw/core/clock.c
> +++ b/hw/core/clock.c
> @@ -143,14 +143,20 @@ char *clock_display_freq(Clock *clk)
>  return freq_to_str(clock_get_hz(clk));
>  }
>  
> -void clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider)
> +bool clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider)
>  {
>  assert(divider != 0);
>  
> +if (clk->multiplier == multiplier && clk->divider == divider) {
> +return false;
> +}
> +
>  trace_clock_set_mul_div(CLOCK_PATH(clk), clk->multiplier, multiplier,
>  clk->divider, divider);
>  clk->multiplier = multiplier;
>  clk->divider = divider;
> +
> +return true;
>  }
>  
>  static void clock_initfn(Object *obj)
> -- 
> 2.41.0
> 



Re: [PATCH v5 09/12] contrib/plugins/hotblocks: migrate to new per_vcpu API

2024-03-01 Thread Luc Michel
On 14:33 Thu 29 Feb , Alex Bennée wrote:
> Caution: This message originated from an External Source. Use proper caution 
> when opening attachments, clicking links, or responding.
> 
> 
> Luc Michel  writes:
> 
> > On 15:09 Tue 27 Feb , Pierrick Bouvier wrote:
> >> On 2/27/24 2:54 PM, Luc Michel wrote:
> >> > Hi Pierrick,
> >> >
> >> > On 13:14 Mon 26 Feb , Pierrick Bouvier wrote:
> >> > > Signed-off-by: Pierrick Bouvier 
> >> > > ---
> >> > >   contrib/plugins/hotblocks.c | 50 
> >> > > ++---
> >> > >   1 file changed, 30 insertions(+), 20 deletions(-)
> >> > >
> >> > > diff --git a/contrib/plugins/hotblocks.c b/contrib/plugins/hotblocks.c
> >> > > index 4de1b134944..02bc5078bdd 100644
> >> > > --- a/contrib/plugins/hotblocks.c
> >> > > +++ b/contrib/plugins/hotblocks.c
> >> > > @@ -34,8 +34,8 @@ static guint64 limit = 20;
> >> > >*/
> >> > >   typedef struct {
> >> > >   uint64_t start_addr;
> >> > > -uint64_t exec_count;
> >> > > -int  trans_count;
> >> > > +struct qemu_plugin_scoreboard *exec_count;
> >> > > +int trans_count;
> >> > >   unsigned long insns;
> >> > >   } ExecCount;
> >> > >
> >> > > @@ -43,7 +43,17 @@ static gint cmp_exec_count(gconstpointer a, 
> >> > > gconstpointer b)
> >> > >   {
> >> > >   ExecCount *ea = (ExecCount *) a;
> >> > >   ExecCount *eb = (ExecCount *) b;
> >> > > -return ea->exec_count > eb->exec_count ? -1 : 1;
> >> > > +uint64_t count_a =
> >> > > +
> >> > > qemu_plugin_u64_sum(qemu_plugin_scoreboard_u64(ea->exec_count));
> >> > > +uint64_t count_b =
> >> > > +
> >> > > qemu_plugin_u64_sum(qemu_plugin_scoreboard_u64(eb->exec_count));
> >> > > +return count_a > count_b ? -1 : 1;
> >> > > +}
> >> > > +
> >> > > +static void exec_count_free(gpointer key, gpointer value, gpointer 
> >> > > user_data)
> >> > > +{
> >> > > +ExecCount *cnt = value;
> >> > > +qemu_plugin_scoreboard_free(cnt->exec_count);
> >> > >   }
> >> > >
> >> > >   static void plugin_exit(qemu_plugin_id_t id, void *p)
> >> > > @@ -52,7 +62,6 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
> >> > >   GList *counts, *it;
> >> > >   int i;
> >> > >
> >> > > -g_mutex_lock();
> >> >
> >> > I encountered cases before where the vCPUs continue executing while
> >> > plugin_exit is called. This can happen e.g., when QEMU calls exit(3)
> >> > from one CPU thread. Others will continue to run at the same time the
> >> > atexit callbacks are called.
> >> >
> >> > This also means that you can't really free the resources as you do at
> >> > the end of plugin_exit.
> >> >
> >>
> >> Interesting...
> >>
> >> The current documentation [1] mentions it's the right place to free
> >> resources, and from what I saw, existing plugins assume this too (see
> >> contrib/plugins/cache.c for instance).
> >>
> >> There is probably a bug related to the case you mention, and I'll try to
> >> reproduce this, and see if we can have a proper fix.
> >>
> >> I'm not sure that removing cleanup code from existing plugins is the
> >> right thing to do at the moment, even though there is an existing issue
> >> with some programs.
> >
> > Yes absolutely. The problem is on the QEMU side. FWIW I tried to fix one
> > of those exit cases (semihosted exit syscall) some time ago:
> > https://lore.kernel.org/qemu-devel/20220621125916.25257-1-lmic...@kalray.eu/
> 
> The plugin exit handler should flush all instrumented code:
> 
>   /*
>* Handle exit from linux-user. Unlike the normal atexit() mechanism
>* we need to handle the clean-up manually as it's possible threads
>* are still running. We need to remove all callbacks from code
>* generation, flush the current translations and then we can safely
>* trigger the exit callbacks.
>*/
> 
>   void qemu_plugin_user_exit(void)
>   {
>   e

Re: [PATCH v5 06/12] tests/plugin/mem: migrate to new per_vcpu API

2024-02-27 Thread Luc Michel
On 14:56 Tue 27 Feb , Pierrick Bouvier wrote:
> Hi Luc,
> 
> On 2/27/24 1:35 PM, Luc Michel wrote:
> > Hi Pierrick,
> > 
> > On 13:14 Mon 26 Feb , Pierrick Bouvier wrote:
> > > Signed-off-by: Pierrick Bouvier 
> > > ---
> > >   tests/plugin/mem.c | 40 +---
> > >   1 file changed, 25 insertions(+), 15 deletions(-)
> > > 
> > > diff --git a/tests/plugin/mem.c b/tests/plugin/mem.c
> > > index 44e91065ba7..d4729f5e015 100644
> > > --- a/tests/plugin/mem.c
> > > +++ b/tests/plugin/mem.c
> > > @@ -16,9 +16,14 @@
> > > 
> > >   QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
> > > 
> > > -static uint64_t inline_mem_count;
> > > -static uint64_t cb_mem_count;
> > > -static uint64_t io_count;
> > > +typedef struct {
> > > +uint64_t mem_count;
> > > +uint64_t io_count;
> > > +} CPUCount;
> > > +
> > > +static struct qemu_plugin_scoreboard *counts;
> > > +static qemu_plugin_u64 mem_count;
> > > +static qemu_plugin_u64 io_count;
> > 
> > I see that you merged inline and callback counts into the same variable.
> > 
> > I wonder... For this test don't you want to keep a plain uint64_t for
> > callback counts? I have the feeling that this test was made so one can
> > make sure inline and callback counts match.
> > 
> 
> Indeed, the new API guarantees thread safety (current inline
> implementation was racy), so this plugin now gives the exact same result
> whether you use inline ops or callbacks. In more, callback based
> approach can be implemented without any lock, as we are counting per
> vcpu. Thus, it's faster and safer.
> 
> Regarding the "testing" side, this series introduce a new plugin
> tests/plugin/inline.c that allows to test all thoses cases in a single
> plugin. Thus, it's not needed that other plugins offer a way to test this.

I see! Then:

Reviewed-by: Luc Michel 

> 
> Thanks for your review.
> 
> > Luc
> > 
> > >   static bool do_inline, do_callback;
> > >   static bool do_haddr;
> > >   static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW;
> > > @@ -27,16 +32,16 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
> > >   {
> > >   g_autoptr(GString) out = g_string_new("");
> > > 
> > > -if (do_inline) {
> > > -g_string_printf(out, "inline mem accesses: %" PRIu64 "\n", 
> > > inline_mem_count);
> > > -}
> > > -if (do_callback) {
> > > -g_string_append_printf(out, "callback mem accesses: %" PRIu64 
> > > "\n", cb_mem_count);
> > > +if (do_inline || do_callback) {
> > > +g_string_printf(out, "mem accesses: %" PRIu64 "\n",
> > > +qemu_plugin_u64_sum(mem_count));
> > >   }
> > >   if (do_haddr) {
> > > -g_string_append_printf(out, "io accesses: %" PRIu64 "\n", 
> > > io_count);
> > > +g_string_append_printf(out, "io accesses: %" PRIu64 "\n",
> > > +   qemu_plugin_u64_sum(io_count));
> > >   }
> > >   qemu_plugin_outs(out->str);
> > > +qemu_plugin_scoreboard_free(counts);
> > >   }
> > > 
> > >   static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t 
> > > meminfo,
> > > @@ -46,12 +51,12 @@ static void vcpu_mem(unsigned int cpu_index, 
> > > qemu_plugin_meminfo_t meminfo,
> > >   struct qemu_plugin_hwaddr *hwaddr;
> > >   hwaddr = qemu_plugin_get_hwaddr(meminfo, vaddr);
> > >   if (qemu_plugin_hwaddr_is_io(hwaddr)) {
> > > -io_count++;
> > > +qemu_plugin_u64_add(io_count, cpu_index, 1);
> > >   } else {
> > > -cb_mem_count++;
> > > +qemu_plugin_u64_add(mem_count, cpu_index, 1);
> > >   }
> > >   } else {
> > > -cb_mem_count++;
> > > +qemu_plugin_u64_add(mem_count, cpu_index, 1);
> > >   }
> > >   }
> > > 
> > > @@ -64,9 +69,10 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct 
> > > qemu_plugin_tb *tb)
> > >   struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
> > > 
> > >   if (do_inline) {
> > >

Re: [PATCH v5 09/12] contrib/plugins/hotblocks: migrate to new per_vcpu API

2024-02-27 Thread Luc Michel
On 15:09 Tue 27 Feb , Pierrick Bouvier wrote:
> On 2/27/24 2:54 PM, Luc Michel wrote:
> > Hi Pierrick,
> > 
> > On 13:14 Mon 26 Feb , Pierrick Bouvier wrote:
> > > Signed-off-by: Pierrick Bouvier 
> > > ---
> > >   contrib/plugins/hotblocks.c | 50 ++---
> > >   1 file changed, 30 insertions(+), 20 deletions(-)
> > > 
> > > diff --git a/contrib/plugins/hotblocks.c b/contrib/plugins/hotblocks.c
> > > index 4de1b134944..02bc5078bdd 100644
> > > --- a/contrib/plugins/hotblocks.c
> > > +++ b/contrib/plugins/hotblocks.c
> > > @@ -34,8 +34,8 @@ static guint64 limit = 20;
> > >*/
> > >   typedef struct {
> > >   uint64_t start_addr;
> > > -uint64_t exec_count;
> > > -int  trans_count;
> > > +struct qemu_plugin_scoreboard *exec_count;
> > > +int trans_count;
> > >   unsigned long insns;
> > >   } ExecCount;
> > > 
> > > @@ -43,7 +43,17 @@ static gint cmp_exec_count(gconstpointer a, 
> > > gconstpointer b)
> > >   {
> > >   ExecCount *ea = (ExecCount *) a;
> > >   ExecCount *eb = (ExecCount *) b;
> > > -return ea->exec_count > eb->exec_count ? -1 : 1;
> > > +uint64_t count_a =
> > > +qemu_plugin_u64_sum(qemu_plugin_scoreboard_u64(ea->exec_count));
> > > +uint64_t count_b =
> > > +qemu_plugin_u64_sum(qemu_plugin_scoreboard_u64(eb->exec_count));
> > > +return count_a > count_b ? -1 : 1;
> > > +}
> > > +
> > > +static void exec_count_free(gpointer key, gpointer value, gpointer 
> > > user_data)
> > > +{
> > > +ExecCount *cnt = value;
> > > +qemu_plugin_scoreboard_free(cnt->exec_count);
> > >   }
> > > 
> > >   static void plugin_exit(qemu_plugin_id_t id, void *p)
> > > @@ -52,7 +62,6 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
> > >   GList *counts, *it;
> > >   int i;
> > > 
> > > -g_mutex_lock();
> > 
> > I encountered cases before where the vCPUs continue executing while
> > plugin_exit is called. This can happen e.g., when QEMU calls exit(3)
> > from one CPU thread. Others will continue to run at the same time the
> > atexit callbacks are called.
> > 
> > This also means that you can't really free the resources as you do at
> > the end of plugin_exit.
> > 
> 
> Interesting...
> 
> The current documentation [1] mentions it's the right place to free
> resources, and from what I saw, existing plugins assume this too (see
> contrib/plugins/cache.c for instance).
> 
> There is probably a bug related to the case you mention, and I'll try to
> reproduce this, and see if we can have a proper fix.
> 
> I'm not sure that removing cleanup code from existing plugins is the
> right thing to do at the moment, even though there is an existing issue
> with some programs.

Yes absolutely. The problem is on the QEMU side. FWIW I tried to fix one
of those exit cases (semihosted exit syscall) some time ago:
https://lore.kernel.org/qemu-devel/20220621125916.25257-1-lmic...@kalray.eu/

IIRC Peter was not fundamentally against it. But then I was off for
several months due to medical reasons.

I can take some time to rebase it and address Peter's comments if there
is interest to it.

Luc

> 
> [1]
> https://www.qemu.org/docs/master/devel/tcg-plugins.html#c.qemu_plugin_register_atexit_cb
> 
> > >   g_string_append_printf(report, "%d entries in the hash table\n",
> > >  g_hash_table_size(hotblocks));
> > >   counts = g_hash_table_get_values(hotblocks);
> > > @@ -63,16 +72,21 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
> > > 
> > >   for (i = 0; i < limit && it->next; i++, it = it->next) {
> > >   ExecCount *rec = (ExecCount *) it->data;
> > > -g_string_append_printf(report, "0x%016"PRIx64", %d, %ld, 
> > > %"PRId64"\n",
> > > -   rec->start_addr, rec->trans_count,
> > > -   rec->insns, rec->exec_count);
> > > +g_string_append_printf(
> > > +report, "0x%016"PRIx64", %d, %ld, %"PRId64"\n",
> > > +rec->start_addr, rec->trans_count,
> > > +rec->insns,
> > > +qemu_plugin_u64_sum(
>

Re: [PATCH v5 09/12] contrib/plugins/hotblocks: migrate to new per_vcpu API

2024-02-27 Thread Luc Michel
Hi Pierrick,

On 13:14 Mon 26 Feb , Pierrick Bouvier wrote:
> Signed-off-by: Pierrick Bouvier 
> ---
>  contrib/plugins/hotblocks.c | 50 ++---
>  1 file changed, 30 insertions(+), 20 deletions(-)
> 
> diff --git a/contrib/plugins/hotblocks.c b/contrib/plugins/hotblocks.c
> index 4de1b134944..02bc5078bdd 100644
> --- a/contrib/plugins/hotblocks.c
> +++ b/contrib/plugins/hotblocks.c
> @@ -34,8 +34,8 @@ static guint64 limit = 20;
>   */
>  typedef struct {
>  uint64_t start_addr;
> -uint64_t exec_count;
> -int  trans_count;
> +struct qemu_plugin_scoreboard *exec_count;
> +int trans_count;
>  unsigned long insns;
>  } ExecCount;
> 
> @@ -43,7 +43,17 @@ static gint cmp_exec_count(gconstpointer a, gconstpointer 
> b)
>  {
>  ExecCount *ea = (ExecCount *) a;
>  ExecCount *eb = (ExecCount *) b;
> -return ea->exec_count > eb->exec_count ? -1 : 1;
> +uint64_t count_a =
> +qemu_plugin_u64_sum(qemu_plugin_scoreboard_u64(ea->exec_count));
> +uint64_t count_b =
> +qemu_plugin_u64_sum(qemu_plugin_scoreboard_u64(eb->exec_count));
> +return count_a > count_b ? -1 : 1;
> +}
> +
> +static void exec_count_free(gpointer key, gpointer value, gpointer user_data)
> +{
> +ExecCount *cnt = value;
> +qemu_plugin_scoreboard_free(cnt->exec_count);
>  }
> 
>  static void plugin_exit(qemu_plugin_id_t id, void *p)
> @@ -52,7 +62,6 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
>  GList *counts, *it;
>  int i;
> 
> -g_mutex_lock();

I encountered cases before where the vCPUs continue executing while
plugin_exit is called. This can happen e.g., when QEMU calls exit(3)
from one CPU thread. Others will continue to run at the same time the
atexit callbacks are called.

This also means that you can't really free the resources as you do at
the end of plugin_exit.

>  g_string_append_printf(report, "%d entries in the hash table\n",
> g_hash_table_size(hotblocks));
>  counts = g_hash_table_get_values(hotblocks);
> @@ -63,16 +72,21 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
> 
>  for (i = 0; i < limit && it->next; i++, it = it->next) {
>  ExecCount *rec = (ExecCount *) it->data;
> -g_string_append_printf(report, "0x%016"PRIx64", %d, %ld, 
> %"PRId64"\n",
> -   rec->start_addr, rec->trans_count,
> -   rec->insns, rec->exec_count);
> +g_string_append_printf(
> +report, "0x%016"PRIx64", %d, %ld, %"PRId64"\n",
> +rec->start_addr, rec->trans_count,
> +rec->insns,
> +qemu_plugin_u64_sum(
> +qemu_plugin_scoreboard_u64(rec->exec_count)));
>  }
> 
>  g_list_free(it);
>  }
> -g_mutex_unlock();
> 
>  qemu_plugin_outs(report->str);
> +
> +g_hash_table_foreach(hotblocks, exec_count_free, NULL);
> +g_hash_table_destroy(hotblocks);
>  }
> 
>  static void plugin_init(void)
> @@ -82,15 +96,9 @@ static void plugin_init(void)
> 
>  static void vcpu_tb_exec(unsigned int cpu_index, void *udata)
>  {
> -ExecCount *cnt;
> -uint64_t hash = (uint64_t) udata;
> -
> -g_mutex_lock();
> -cnt = (ExecCount *) g_hash_table_lookup(hotblocks, (gconstpointer) hash);
> -/* should always succeed */
> -g_assert(cnt);
> -cnt->exec_count++;
> -g_mutex_unlock();
> +ExecCount *cnt = (ExecCount *)udata;
> +qemu_plugin_u64_add(qemu_plugin_scoreboard_u64(cnt->exec_count),
> +cpu_index, 1);
>  }
> 
>  /*
> @@ -114,18 +122,20 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct 
> qemu_plugin_tb *tb)
>  cnt->start_addr = pc;
>  cnt->trans_count = 1;
>  cnt->insns = insns;
> +cnt->exec_count = qemu_plugin_scoreboard_new(sizeof(uint64_t));
>  g_hash_table_insert(hotblocks, (gpointer) hash, (gpointer) cnt);
>  }
> 
>  g_mutex_unlock();
> 
>  if (do_inline) {
> -qemu_plugin_register_vcpu_tb_exec_inline(tb, 
> QEMU_PLUGIN_INLINE_ADD_U64,
> - >exec_count, 1);
> +qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
> +tb, QEMU_PLUGIN_INLINE_ADD_U64,
> +qemu_plugin_scoreboard_u64(cnt->exec_count), 1);
>  } else {
>  qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec,
>   QEMU_PLUGIN_CB_NO_REGS,
> - (void *)hash);
> + (void *)cnt);
>  }
>  }
> 
> --
> 2.43.0
> 
> 

-- 



Re: [PATCH v5 08/12] tests/plugin/bb: migrate to new per_vcpu API

2024-02-27 Thread Luc Michel
On 13:14 Mon 26 Feb , Pierrick Bouvier wrote:
> Signed-off-by: Pierrick Bouvier 

Reviewed-by: Luc Michel 

> ---
>  tests/plugin/bb.c | 63 +++
>  1 file changed, 26 insertions(+), 37 deletions(-)
> 
> diff --git a/tests/plugin/bb.c b/tests/plugin/bb.c
> index df50d1fd3bc..36776dee1e1 100644
> --- a/tests/plugin/bb.c
> +++ b/tests/plugin/bb.c
> @@ -17,27 +17,25 @@
>  QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
> 
>  typedef struct {
> -GMutex lock;
> -int index;
>  uint64_t bb_count;
>  uint64_t insn_count;
>  } CPUCount;
> 
> -/* Used by the inline & linux-user counts */
> +static struct qemu_plugin_scoreboard *counts;
> +static qemu_plugin_u64 bb_count;
> +static qemu_plugin_u64 insn_count;
> +
>  static bool do_inline;
> -static CPUCount inline_count;
> -
>  /* Dump running CPU total on idle? */
>  static bool idle_report;
> -static GPtrArray *counts;
> -static int max_cpus;
> 
> -static void gen_one_cpu_report(CPUCount *count, GString *report)
> +static void gen_one_cpu_report(CPUCount *count, GString *report,
> +   unsigned int cpu_index)
>  {
>  if (count->bb_count) {
>  g_string_append_printf(report, "CPU%d: "
> "bb's: %" PRIu64", insns: %" PRIu64 "\n",
> -   count->index,
> +   cpu_index,
> count->bb_count, count->insn_count);
>  }
>  }
> @@ -46,20 +44,23 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
>  {
>  g_autoptr(GString) report = g_string_new("");
> 
> -if (do_inline || !max_cpus) {
> -g_string_printf(report, "bb's: %" PRIu64", insns: %" PRIu64 "\n",
> -inline_count.bb_count, inline_count.insn_count);
> -} else {
> -g_ptr_array_foreach(counts, (GFunc) gen_one_cpu_report, report);
> +for (int i = 0; i < qemu_plugin_num_vcpus(); ++i) {
> +CPUCount *count = qemu_plugin_scoreboard_find(counts, i);
> +gen_one_cpu_report(count, report, i);
>  }
> +g_string_append_printf(report, "Total: "
> +   "bb's: %" PRIu64", insns: %" PRIu64 "\n",
> +   qemu_plugin_u64_sum(bb_count),
> +   qemu_plugin_u64_sum(insn_count));
>  qemu_plugin_outs(report->str);
> +qemu_plugin_scoreboard_free(counts);
>  }
> 
>  static void vcpu_idle(qemu_plugin_id_t id, unsigned int cpu_index)
>  {
> -CPUCount *count = g_ptr_array_index(counts, cpu_index);
> +CPUCount *count = qemu_plugin_scoreboard_find(counts, cpu_index);
>  g_autoptr(GString) report = g_string_new("");
> -gen_one_cpu_report(count, report);
> +gen_one_cpu_report(count, report, cpu_index);
> 
>  if (report->len > 0) {
>  g_string_prepend(report, "Idling ");
> @@ -69,14 +70,11 @@ static void vcpu_idle(qemu_plugin_id_t id, unsigned int 
> cpu_index)
> 
>  static void vcpu_tb_exec(unsigned int cpu_index, void *udata)
>  {
> -CPUCount *count = max_cpus ?
> -g_ptr_array_index(counts, cpu_index) : _count;
> +CPUCount *count = qemu_plugin_scoreboard_find(counts, cpu_index);
> 
>  uintptr_t n_insns = (uintptr_t)udata;
> -g_mutex_lock(>lock);
>  count->insn_count += n_insns;
>  count->bb_count++;
> -g_mutex_unlock(>lock);
>  }
> 
>  static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
> @@ -84,11 +82,10 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct 
> qemu_plugin_tb *tb)
>  size_t n_insns = qemu_plugin_tb_n_insns(tb);
> 
>  if (do_inline) {
> -qemu_plugin_register_vcpu_tb_exec_inline(tb, 
> QEMU_PLUGIN_INLINE_ADD_U64,
> - _count.bb_count, 1);
> -qemu_plugin_register_vcpu_tb_exec_inline(tb, 
> QEMU_PLUGIN_INLINE_ADD_U64,
> - _count.insn_count,
> - n_insns);
> +qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
> +tb, QEMU_PLUGIN_INLINE_ADD_U64, bb_count, 1);
> +qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
> +tb, QEMU_PLUGIN_INLINE_ADD_U64, insn_count, n_insns);
>  } else {
>  qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec,
>   QEMU_PLUGIN_CB_NO_REGS,
> @@ -121,18 +118,10 @@ QEMU_P

Re: [PATCH v5 07/12] tests/plugin/insn: migrate to new per_vcpu API

2024-02-27 Thread Luc Michel
On 13:14 Mon 26 Feb , Pierrick Bouvier wrote:
> Signed-off-by: Pierrick Bouvier 

Reviewed-by: Luc Michel 

> ---
>  tests/plugin/insn.c | 106 +---
>  1 file changed, 50 insertions(+), 56 deletions(-)
> 
> diff --git a/tests/plugin/insn.c b/tests/plugin/insn.c
> index 54da06fcf26..5e0aa03223e 100644
> --- a/tests/plugin/insn.c
> +++ b/tests/plugin/insn.c
> @@ -16,25 +16,21 @@
> 
>  QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
> 
> -#define MAX_CPUS 8 /* lets not go nuts */
> -
> -typedef struct {
> -uint64_t insn_count;
> -} InstructionCount;
> -
> -static InstructionCount counts[MAX_CPUS];
> -static uint64_t inline_insn_count;
> +static qemu_plugin_u64 insn_count;
> 
>  static bool do_inline;
>  static bool do_size;
>  static GArray *sizes;
> 
> +typedef struct {
> +uint64_t hits;
> +uint64_t last_hit;
> +uint64_t total_delta;
> +} MatchCount;
> +
>  typedef struct {
>  char *match_string;
> -uint64_t hits[MAX_CPUS];
> -uint64_t last_hit[MAX_CPUS];
> -uint64_t total_delta[MAX_CPUS];
> -GPtrArray *history[MAX_CPUS];
> +struct qemu_plugin_scoreboard *counts; /* MatchCount */
>  } Match;
> 
>  static GArray *matches;
> @@ -67,41 +63,40 @@ static void vcpu_init(qemu_plugin_id_t id, unsigned int 
> vcpu_index)
> 
>  static void vcpu_insn_exec_before(unsigned int cpu_index, void *udata)
>  {
> -unsigned int i = cpu_index % MAX_CPUS;
> -InstructionCount *c = [i];
> -
> -c->insn_count++;
> +qemu_plugin_u64_add(insn_count, cpu_index, 1);
>  }
> 
>  static void vcpu_insn_matched_exec_before(unsigned int cpu_index, void 
> *udata)
>  {
> -unsigned int i = cpu_index % MAX_CPUS;
>  Instruction *insn = (Instruction *) udata;
> -Match *match = insn->match;
> +Match *insn_match = insn->match;
> +MatchCount *match = qemu_plugin_scoreboard_find(insn_match->counts,
> +cpu_index);
> +
>  g_autoptr(GString) ts = g_string_new("");
> 
>  insn->hits++;
>  g_string_append_printf(ts, "0x%" PRIx64 ", '%s', %"PRId64 " hits",
> insn->vaddr, insn->disas, insn->hits);
> 
> -uint64_t icount = counts[i].insn_count;
> -uint64_t delta = icount - match->last_hit[i];
> +uint64_t icount = qemu_plugin_u64_get(insn_count, cpu_index);
> +uint64_t delta = icount - match->last_hit;
> 
> -match->hits[i]++;
> -match->total_delta[i] += delta;
> +match->hits++;
> +match->total_delta += delta;
> 
>  g_string_append_printf(ts,
> -   ", %"PRId64" match hits, "
> -   "Δ+%"PRId64 " since last match,"
> +   " , cpu %u,"
> +   " %"PRId64" match hits,"
> +   " Δ+%"PRId64 " since last match,"
> " %"PRId64 " avg insns/match\n",
> -   match->hits[i], delta,
> -   match->total_delta[i] / match->hits[i]);
> +   cpu_index,
> +   match->hits, delta,
> +   match->total_delta / match->hits);
> 
> -match->last_hit[i] = icount;
> +match->last_hit = icount;
> 
>  qemu_plugin_outs(ts->str);
> -
> -g_ptr_array_add(match->history[i], insn);
>  }
> 
>  static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
> @@ -113,8 +108,8 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct 
> qemu_plugin_tb *tb)
>  struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
> 
>  if (do_inline) {
> -qemu_plugin_register_vcpu_insn_exec_inline(
> -insn, QEMU_PLUGIN_INLINE_ADD_U64, _insn_count, 1);
> +qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
> +insn, QEMU_PLUGIN_INLINE_ADD_U64, insn_count, 1);
>  } else {
>  uint64_t vaddr = qemu_plugin_insn_vaddr(insn);
>  qemu_plugin_register_vcpu_insn_exec_cb(
> @@ -136,10 +131,9 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct 
> qemu_plugin_tb *tb)
>   * information about the instruction which we also need to
>   * save if there is a hit.
>   */
> -if (matches) {
> +if (matches->len) {
>  char *insn_disas = qemu_plugin_insn_dis

Re: [PATCH v5 06/12] tests/plugin/mem: migrate to new per_vcpu API

2024-02-27 Thread Luc Michel
Hi Pierrick,

On 13:14 Mon 26 Feb , Pierrick Bouvier wrote:
> Signed-off-by: Pierrick Bouvier 
> ---
>  tests/plugin/mem.c | 40 +---
>  1 file changed, 25 insertions(+), 15 deletions(-)
> 
> diff --git a/tests/plugin/mem.c b/tests/plugin/mem.c
> index 44e91065ba7..d4729f5e015 100644
> --- a/tests/plugin/mem.c
> +++ b/tests/plugin/mem.c
> @@ -16,9 +16,14 @@
> 
>  QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
> 
> -static uint64_t inline_mem_count;
> -static uint64_t cb_mem_count;
> -static uint64_t io_count;
> +typedef struct {
> +uint64_t mem_count;
> +uint64_t io_count;
> +} CPUCount;
> +
> +static struct qemu_plugin_scoreboard *counts;
> +static qemu_plugin_u64 mem_count;
> +static qemu_plugin_u64 io_count;

I see that you merged inline and callback counts into the same variable.

I wonder... For this test don't you want to keep a plain uint64_t for
callback counts? I have the feeling that this test was made so one can
make sure inline and callback counts match.

Luc

>  static bool do_inline, do_callback;
>  static bool do_haddr;
>  static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW;
> @@ -27,16 +32,16 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
>  {
>  g_autoptr(GString) out = g_string_new("");
> 
> -if (do_inline) {
> -g_string_printf(out, "inline mem accesses: %" PRIu64 "\n", 
> inline_mem_count);
> -}
> -if (do_callback) {
> -g_string_append_printf(out, "callback mem accesses: %" PRIu64 "\n", 
> cb_mem_count);
> +if (do_inline || do_callback) {
> +g_string_printf(out, "mem accesses: %" PRIu64 "\n",
> +qemu_plugin_u64_sum(mem_count));
>  }
>  if (do_haddr) {
> -g_string_append_printf(out, "io accesses: %" PRIu64 "\n", io_count);
> +g_string_append_printf(out, "io accesses: %" PRIu64 "\n",
> +   qemu_plugin_u64_sum(io_count));
>  }
>  qemu_plugin_outs(out->str);
> +qemu_plugin_scoreboard_free(counts);
>  }
> 
>  static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo,
> @@ -46,12 +51,12 @@ static void vcpu_mem(unsigned int cpu_index, 
> qemu_plugin_meminfo_t meminfo,
>  struct qemu_plugin_hwaddr *hwaddr;
>  hwaddr = qemu_plugin_get_hwaddr(meminfo, vaddr);
>  if (qemu_plugin_hwaddr_is_io(hwaddr)) {
> -io_count++;
> +qemu_plugin_u64_add(io_count, cpu_index, 1);
>  } else {
> -cb_mem_count++;
> +qemu_plugin_u64_add(mem_count, cpu_index, 1);
>  }
>  } else {
> -cb_mem_count++;
> +qemu_plugin_u64_add(mem_count, cpu_index, 1);
>  }
>  }
> 
> @@ -64,9 +69,10 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct 
> qemu_plugin_tb *tb)
>  struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
> 
>  if (do_inline) {
> -qemu_plugin_register_vcpu_mem_inline(insn, rw,
> - QEMU_PLUGIN_INLINE_ADD_U64,
> - _mem_count, 1);
> +qemu_plugin_register_vcpu_mem_inline_per_vcpu(
> +insn, rw,
> +QEMU_PLUGIN_INLINE_ADD_U64,
> +mem_count, 1);
>  }
>  if (do_callback) {
>  qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem,
> @@ -117,6 +123,10 @@ QEMU_PLUGIN_EXPORT int 
> qemu_plugin_install(qemu_plugin_id_t id,
>  }
>  }
> 
> +counts = qemu_plugin_scoreboard_new(sizeof(CPUCount));
> +mem_count = qemu_plugin_scoreboard_u64_in_struct(
> +counts, CPUCount, mem_count);
> +io_count = qemu_plugin_scoreboard_u64_in_struct(counts, CPUCount, 
> io_count);
>  qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
>  qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
>  return 0;
> --
> 2.43.0
> 
> 

-- 



Re: [PATCH 0/7] hw/i386: Cleanups around 'hw/i386/pc.h'

2024-02-13 Thread Luc Michel
On 13:01 Tue 13 Feb , Philippe Mathieu-Daudé wrote:
> Trivial patches removing uses of "hw/i386/pc.h".
> 
> Philippe Mathieu-Daudé (7):
>   target/i386/monitor: Remove unused 'hw/i386/pc.h' header
>   hw/timer: Move HPET_INTCAP definition to "hpet.h"
>   hw/isa/lpc_ich9: Remove unused 'hw/i386/pc.h'
>   hw/i386/acpi: Declare pc_madt_cpu_entry() in 'acpi-common.h'
>   hw/i386/port92: Add missing 'hw/isa/isa.h' header
>   hw/acpi/cpu_hotplug: Include 'pci_device.h' instead of 'pci.h'
>   hw/acpi/cpu_hotplug: Include 'x86.h' instead of 'pc.h'
> 
>  hw/i386/acpi-common.h   | 3 +++
>  include/hw/i386/pc.h| 6 --
>  include/hw/timer/hpet.h | 2 ++
>  hw/acpi/cpu_hotplug.c   | 4 ++--
>  hw/i386/acpi-common.c   | 1 -
>  hw/i386/port92.c| 1 +
>  hw/isa/lpc_ich9.c   | 1 -
>  hw/timer/hpet.c | 1 -
>  target/i386/monitor.c   | 1 -
>  9 files changed, 8 insertions(+), 12 deletions(-)
> 
> --
> 2.41.0
> 
> 

For the series:
Reviewed-by: Luc Michel 



[PATCH v2] hw/arm/smmuv3: add support for stage 1 access fault

2024-02-13 Thread Luc Michel
An access fault is raised when the Access Flag is not set in the
looked-up PTE and the AFFD field is not set in the corresponding context
descriptor. This was already implemented for stage 2. Implement it for
stage 1 as well.

Signed-off-by: Luc Michel 
---

v2: drop erroneous submodule modification

---

 hw/arm/smmuv3-internal.h |  1 +
 include/hw/arm/smmu-common.h |  1 +
 hw/arm/smmu-common.c | 10 ++
 hw/arm/smmuv3.c  |  1 +
 4 files changed, 13 insertions(+)

diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index e987bc4686b..e4dd11e1e62 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -622,10 +622,11 @@ static inline int pa_range(STE *ste)
 #define CD_TSZ(x, sel)   extract32((x)->word[0], (16 * (sel)) + 0, 6)
 #define CD_TG(x, sel)extract32((x)->word[0], (16 * (sel)) + 6, 2)
 #define CD_EPD(x, sel)   extract32((x)->word[0], (16 * (sel)) + 14, 1)
 #define CD_ENDI(x)   extract32((x)->word[0], 15, 1)
 #define CD_IPS(x)extract32((x)->word[1], 0 , 3)
+#define CD_AFFD(x)   extract32((x)->word[1], 3 , 1)
 #define CD_TBI(x)extract32((x)->word[1], 6 , 2)
 #define CD_HD(x) extract32((x)->word[1], 10 , 1)
 #define CD_HA(x) extract32((x)->word[1], 11 , 1)
 #define CD_S(x)  extract32((x)->word[1], 12, 1)
 #define CD_R(x)  extract32((x)->word[1], 13, 1)
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index fd8d772da11..5ec2e6c1a43 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -90,10 +90,11 @@ typedef struct SMMUTransCfg {
 /* Shared fields between stage-1 and stage-2. */
 int stage; /* translation stage */
 bool disabled; /* smmu is disabled */
 bool bypassed; /* translation is bypassed */
 bool aborted;  /* translation is aborted */
+bool affd; /* AF fault disable */
 uint32_t iotlb_hits;   /* counts IOTLB hits */
 uint32_t iotlb_misses; /* counts IOTLB misses*/
 /* Used by stage-1 only. */
 bool aa64; /* arch64 or aarch32 translation table */
 bool record_faults;/* record fault events */
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 9a8ac45431a..09ff72e55f5 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -362,10 +362,20 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
 _size);
 trace_smmu_ptw_block_pte(stage, level, baseaddr,
  pte_addr, pte, iova, gpa,
  block_size >> 20);
 }
+
+/*
+ * If AFFD and PTE.AF are 0 => fault. (5.4. Context Descriptor)
+ * An Access fault takes priority over a Permission fault.
+ */
+if (!PTE_AF(pte) && !cfg->affd) {
+info->type = SMMU_PTW_ERR_ACCESS;
+goto error;
+}
+
 ap = PTE_AP(pte);
 if (is_permission_fault(ap, perm)) {
 info->type = SMMU_PTW_ERR_PERMISSION;
 goto error;
 }
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 68eeef3e1d4..c416b8c0030 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -682,10 +682,11 @@ static int decode_cd(SMMUTransCfg *cfg, CD *cd, 
SMMUEventInfo *event)
 
 cfg->oas = oas2bits(CD_IPS(cd));
 cfg->oas = MIN(oas2bits(SMMU_IDR5_OAS), cfg->oas);
 cfg->tbi = CD_TBI(cd);
 cfg->asid = CD_ASID(cd);
+cfg->affd = CD_AFFD(cd);
 
 trace_smmuv3_decode_cd(cfg->oas);
 
 /* decode data dependent on TT */
 for (i = 0; i <= 1; i++) {
-- 
2.39.2




[PATCH] hw/arm/smmuv3: add support for stage 1 access fault

2024-02-09 Thread Luc Michel
An access fault is raised when the Access Flag is not set in the
looked-up PTE and the AFFD field is not set in the corresponding context
descriptor. This was already implemented for stage 2. Implement it for
stage 1 as well.

Signed-off-by: Luc Michel 
---
 hw/arm/smmuv3-internal.h |  1 +
 include/hw/arm/smmu-common.h |  1 +
 hw/arm/smmu-common.c | 10 ++
 hw/arm/smmuv3.c  |  1 +
 roms/SLOF|  2 +-
 5 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index e987bc4686b..e4dd11e1e62 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -622,10 +622,11 @@ static inline int pa_range(STE *ste)
 #define CD_TSZ(x, sel)   extract32((x)->word[0], (16 * (sel)) + 0, 6)
 #define CD_TG(x, sel)extract32((x)->word[0], (16 * (sel)) + 6, 2)
 #define CD_EPD(x, sel)   extract32((x)->word[0], (16 * (sel)) + 14, 1)
 #define CD_ENDI(x)   extract32((x)->word[0], 15, 1)
 #define CD_IPS(x)extract32((x)->word[1], 0 , 3)
+#define CD_AFFD(x)   extract32((x)->word[1], 3 , 1)
 #define CD_TBI(x)extract32((x)->word[1], 6 , 2)
 #define CD_HD(x) extract32((x)->word[1], 10 , 1)
 #define CD_HA(x) extract32((x)->word[1], 11 , 1)
 #define CD_S(x)  extract32((x)->word[1], 12, 1)
 #define CD_R(x)  extract32((x)->word[1], 13, 1)
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index fd8d772da11..5ec2e6c1a43 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -90,10 +90,11 @@ typedef struct SMMUTransCfg {
 /* Shared fields between stage-1 and stage-2. */
 int stage; /* translation stage */
 bool disabled; /* smmu is disabled */
 bool bypassed; /* translation is bypassed */
 bool aborted;  /* translation is aborted */
+bool affd; /* AF fault disable */
 uint32_t iotlb_hits;   /* counts IOTLB hits */
 uint32_t iotlb_misses; /* counts IOTLB misses*/
 /* Used by stage-1 only. */
 bool aa64; /* arch64 or aarch32 translation table */
 bool record_faults;/* record fault events */
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 9a8ac45431a..09ff72e55f5 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -362,10 +362,20 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
 _size);
 trace_smmu_ptw_block_pte(stage, level, baseaddr,
  pte_addr, pte, iova, gpa,
  block_size >> 20);
 }
+
+/*
+ * If AFFD and PTE.AF are 0 => fault. (5.4. Context Descriptor)
+ * An Access fault takes priority over a Permission fault.
+ */
+if (!PTE_AF(pte) && !cfg->affd) {
+info->type = SMMU_PTW_ERR_ACCESS;
+goto error;
+}
+
 ap = PTE_AP(pte);
 if (is_permission_fault(ap, perm)) {
 info->type = SMMU_PTW_ERR_PERMISSION;
 goto error;
 }
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 68eeef3e1d4..c416b8c0030 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -682,10 +682,11 @@ static int decode_cd(SMMUTransCfg *cfg, CD *cd, 
SMMUEventInfo *event)
 
 cfg->oas = oas2bits(CD_IPS(cd));
 cfg->oas = MIN(oas2bits(SMMU_IDR5_OAS), cfg->oas);
 cfg->tbi = CD_TBI(cd);
 cfg->asid = CD_ASID(cd);
+cfg->affd = CD_AFFD(cd);
 
 trace_smmuv3_decode_cd(cfg->oas);
 
 /* decode data dependent on TT */
 for (i = 0; i <= 1; i++) {
diff --git a/roms/SLOF b/roms/SLOF
index 3a259df2449..6b6c16b4b40 16
--- a/roms/SLOF
+++ b/roms/SLOF
@@ -1 +1 @@
-Subproject commit 3a259df2449fc4a4e43ab5f33f0b2c66484b4bc3
+Subproject commit 6b6c16b4b40763507cf1f518096f3c3883c5cf2d
-- 
2.39.2




Re: [PATCH for-9.0] docs/devel/docs: Document .hx file syntax

2023-12-14 Thread Luc Michel
On 16:23 Tue 12 Dec , Peter Maydell wrote:
> We don't currently document the syntax of .hx files anywhere
> except in a few comments at the top of individual .hx files.
> We don't even have somewhere in the developer docs where we
> could do this.
> 
> Add a new files docs/devel/docs.rst which can be a place to
> document how our docs build process works. For the moment,
> put in only a brief introductory paragraph and the documentation
> of the .hx files. We could later add to this file by for
> example describing how the QAPI-schema-to-docs process works,
> or anything else that developers might need to know about
> how to add documentation.
> 
> Make the .hx files refer to this doc file, and clean
> up their header comments to be more accurate for the
> usage in each file and less cut-n-pasted.
> 
> Signed-off-by: Peter Maydell 

Reviewed-by: Luc Michel 

> ---
> My motivation here is that we're about to add support for
> extending the SRST directive to specify a label so we
> can hyperlink to a documentation fragment; this gives us
> somewhere we can document the syntax for that.
> ---
>  MAINTAINERS|  1 +
>  docs/devel/docs.rst| 60 ++
>  docs/devel/index-build.rst |  1 +
>  hmp-commands-info.hx   | 10 +++
>  hmp-commands.hx| 10 +++
>  qemu-img-cmds.hx   |  2 ++
>  qemu-options.hx|  2 ++
>  7 files changed, 76 insertions(+), 10 deletions(-)
>  create mode 100644 docs/devel/docs.rst
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 695e0bd34fb..49b8ca9d1a8 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4149,6 +4149,7 @@ F: docs/conf.py
>  F: docs/*/conf.py
>  F: docs/sphinx/
>  F: docs/_templates/
> +F: docs/devel/docs.rst
> 
>  Miscellaneous
>  -
> diff --git a/docs/devel/docs.rst b/docs/devel/docs.rst
> new file mode 100644
> index 000..7da067905b8
> --- /dev/null
> +++ b/docs/devel/docs.rst
> @@ -0,0 +1,60 @@
> +
> +==
> +QEMU Documentation
> +==
> +
> +QEMU's documentation is written in reStructuredText format and
> +built using the Sphinx documentation generator. We generate both
> +the HTML manual and the manpages from the some documentation sources.
> +
> +hxtool and .hx files
> +
> +
> +The documentation for QEMU command line options and Human Monitor Protocol
> +(HMP) commands is written in files with the ``.hx`` suffix. These
> +are processed in two ways:
> +
> + * ``scripts/hxtool`` creates C header files from them, which are included
> +   in QEMU to do things like handle the ``--help`` option output
> + * a Sphinx extension in ``docs/sphinx/hxtool.py`` generates rST output
> +   to be included in the HTML or manpage documentation
> +
> +The syntax of these ``.hx`` files is simple. It is broadly an
> +alternation of C code put into the C output and rST format text
> +put into the documention. A few special directives are recognised;
> +these are all-caps and must be at the beginning of the line.
> +
> +``HXCOMM`` is the comment marker. The line, including any arbitrary
> +text after the marker, is discarded and appears neither in the C output
> +nor the documentation output.
> +
> +``SRST`` starts a reStructuredText section. Following lines
> +are put into the documentation verbatim, and discarded from the C output.
> +
> +``ERST`` ends the documentation section started with ``SRST``,
> +and switches back to a C code section.
> +
> +``DEFHEADING()`` defines a heading that should appear in both the
> +``--help`` output and in the documentation. This directive should
> +be in the C code block. If there is a string inside the brackets,
> +this is the heading to use. If this string is empty, it produces
> +a blank line in the ``--help`` output and is ignored for the rST
> +output.
> +
> +``ARCHHEADING()`` is a variant of ``DEFHEADING()`` which produces
> +the heading only if the specified guest architecture was compiled
> +into QEMU. This should be avoided in new documentation.
> +
> +Within C code sections, you should check the comments at the top
> +of the file to see what the expected usage is, because this
> +varies between files. For instance in ``qemu-options.hx`` we use
> +the ``DEF()`` macro to define each option and specify its ``--help``
> +text, but in ``hmp-commands.hx`` the C code sections are elements
> +of an array of structs of type ``HMPCommand`` which define the
> +name, behaviour and help text for each monitor command.
> +
> +In the file ``qemu-options.hx``, do not try to define a
> +reStructuredText label within a documentation section. This file
> +is included into 

Re: Questions about clocks emulation

2023-12-13 Thread Luc Michel
Hi,

On 20:13 Wed 13 Dec , Philippe Mathieu-Daudé wrote:
> Caution: This message originated from an External Source. Use proper caution 
> when opening attachments, clicking links, or responding.
> 
> 
> Hi Arnaud,
> 
> (Cc'ing Peter and Luc)
> 
> On 12/12/23 14:05, Arnaud Minier wrote:
> > Hi all,
> > 
> > I tried to implement the RCC (Reset and Clock Control) for the 
> > STM32L4x5_SoC but ran into some problems regarding clock emulation in Qemu.
> > In this SoC, it is possible to change the source of several clocks used for 
> > devices like the CPU, the USART, and approximately every other device on 
> > the SoC.
> > This change can be made at runtime by writing into a specific register.
> > I tried to model this by using the clocks in hw/core/clock.c by I noticed 
> > that it is not possible to change a clock's source once it has been 
> > assigned (see clock_set_source()).
> 
> Ouch.
> 
> I thought this was what connect_mux_sources() what doing (see
> hw/misc/bcm2835_cprman.c) but it is only called (along the
> clock_set_source() calls) from the realize() handler.

>From a clock user API standpoint, we made the choice to hardwire the
clock tree, as it is in fact hardwired in the chip you are trying to
model (physical connections insides the chip do not "change" when you
write to a register). Things are usually implemented using muxes, clock
dividers and such between PLLs and devices. This is the approach you
should adopt when implementing your clock tree. As Philippe mentioned
you can have a look at hw/misc/bcm2835_cprman.c which is a real world
example of a clock tree implementation (in the Raspberry PI SoC).

> 
> > It prevents me from implementing a clock tree similar to the one on the 
> > hardware.
> > 
> > Is this limitation there for some reason or has it simply not been 
> > implemented?
> 
> There is a /* changing clock source is not supported */ comment in
> clock_set_source(), so likely not implemented :)
> 
> IIUC the only issue is how to update the src->children qlist.

IIRC from a clock API implementation standpoint, there were some serious
questions about dynamic reconfiguration of the clock tree. But I can't
remember the details (maybe some issues about migration?). But again,
the API in its current form should be enough to catch your need. If you
have a specific pattern you think is not expressible with the current
API, please expose it precisely so we can see how to fix that.

Thanks

-- 
Luc

> 
> > Thanks,
> > Arnaud Minier
> > 
> 

-- 



Re: [PATCH trivial 13/21] hw/net/cadence_gem.c: spelling fixes: Octects

2023-11-15 Thread Luc Michel
On 19:58 Tue 14 Nov , Michael Tokarev wrote:
> Fixes: c755c943aa2e "hw/net/cadence_gem: use REG32 macro for register 
> definitions"
> Cc: Luc Michel 
> Cc: Peter Maydell 
> Signed-off-by: Michael Tokarev 

Reviewed-by: Luc Michel 

> ---
>  hw/net/cadence_gem.c | 8 
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
> index 5b989f5b52..19adbc0e19 100644
> --- a/hw/net/cadence_gem.c
> +++ b/hw/net/cadence_gem.c
> @@ -225,8 +225,8 @@ REG32(WOLAN, 0xb8) /* Wake on LAN reg */
>  REG32(IPGSTRETCH, 0xbc) /* IPG Stretch reg */
>  REG32(SVLAN, 0xc0) /* Stacked VLAN reg */
>  REG32(MODID, 0xfc) /* Module ID reg */
> -REG32(OCTTXLO, 0x100) /* Octects transmitted Low reg */
> -REG32(OCTTXHI, 0x104) /* Octects transmitted High reg */
> +REG32(OCTTXLO, 0x100) /* Octets transmitted Low reg */
> +REG32(OCTTXHI, 0x104) /* Octets transmitted High reg */
>  REG32(TXCNT, 0x108) /* Error-free Frames transmitted */
>  REG32(TXBCNT, 0x10c) /* Error-free Broadcast Frames */
>  REG32(TXMCNT, 0x110) /* Error-free Multicast Frame */
> @@ -245,8 +245,8 @@ REG32(EXCESSCOLLCNT, 0x140) /* Excessive Collision Frames 
> */
>  REG32(LATECOLLCNT, 0x144) /* Late Collision Frames */
>  REG32(DEFERTXCNT, 0x148) /* Deferred Transmission Frames */
>  REG32(CSENSECNT, 0x14c) /* Carrier Sense Error Counter */
> -REG32(OCTRXLO, 0x150) /* Octects Received register Low */
> -REG32(OCTRXHI, 0x154) /* Octects Received register High */
> +REG32(OCTRXLO, 0x150) /* Octets Received register Low */
> +REG32(OCTRXHI, 0x154) /* Octets Received register High */
>  REG32(RXCNT, 0x158) /* Error-free Frames Received */
>  REG32(RXBROADCNT, 0x15c) /* Error-free Broadcast Frames RX */
>  REG32(RXMULTICNT, 0x160) /* Error-free Multicast Frames RX */
> --
> 2.39.2
> 

-- 



Re: [PATCH 10/10] hw/arm/xlnx-zynqmp: Remove 'hw/arm/boot.h' from header

2023-10-25 Thread Luc Michel
On 08:53 Wed 25 Oct , Philippe Mathieu-Daudé wrote:
> "hw/arm/boot.h" is only required on the source file.
> 
> Signed-off-by: Philippe Mathieu-Daudé 

Reviewed-by: Luc Michel 

> ---
>  include/hw/arm/xlnx-zynqmp.h | 1 -
>  hw/arm/xlnx-zcu102.c | 1 +
>  2 files changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
> index 687c75e3b0..96358d51eb 100644
> --- a/include/hw/arm/xlnx-zynqmp.h
> +++ b/include/hw/arm/xlnx-zynqmp.h
> @@ -18,7 +18,6 @@
>  #ifndef XLNX_ZYNQMP_H
>  #define XLNX_ZYNQMP_H
> 
> -#include "hw/arm/boot.h"
>  #include "hw/intc/arm_gic.h"
>  #include "hw/net/cadence_gem.h"
>  #include "hw/char/cadence_uart.h"
> diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c
> index c5a07cfe19..4667cb333c 100644
> --- a/hw/arm/xlnx-zcu102.c
> +++ b/hw/arm/xlnx-zcu102.c
> @@ -18,6 +18,7 @@
>  #include "qemu/osdep.h"
>  #include "qapi/error.h"
>  #include "hw/arm/xlnx-zynqmp.h"
> +#include "hw/arm/boot.h"
>  #include "hw/boards.h"
>  #include "qemu/error-report.h"
>  #include "qemu/log.h"
> --
> 2.41.0
> 
> 

-- 



Re: [PATCH 08/10] hw/arm/fsl-imx7: Remove 'hw/arm/boot.h' from header

2023-10-25 Thread Luc Michel
On 08:53 Wed 25 Oct , Philippe Mathieu-Daudé wrote:
> "hw/arm/boot.h" is only required on the source file.
> 
> Signed-off-by: Philippe Mathieu-Daudé 

Reviewed-by: Luc Michel 

> ---
>  include/hw/arm/fsl-imx7.h | 1 -
>  hw/arm/mcimx7d-sabre.c| 1 +
>  2 files changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h
> index 2cbfc6b2b2..411fa1c2e3 100644
> --- a/include/hw/arm/fsl-imx7.h
> +++ b/include/hw/arm/fsl-imx7.h
> @@ -19,7 +19,6 @@
>  #ifndef FSL_IMX7_H
>  #define FSL_IMX7_H
> 
> -#include "hw/arm/boot.h"
>  #include "hw/cpu/a15mpcore.h"
>  #include "hw/intc/imx_gpcv2.h"
>  #include "hw/misc/imx7_ccm.h"
> diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c
> index d1778122b6..693a1023b6 100644
> --- a/hw/arm/mcimx7d-sabre.c
> +++ b/hw/arm/mcimx7d-sabre.c
> @@ -15,6 +15,7 @@
>  #include "qemu/osdep.h"
>  #include "qapi/error.h"
>  #include "hw/arm/fsl-imx7.h"
> +#include "hw/arm/boot.h"
>  #include "hw/boards.h"
>  #include "hw/qdev-properties.h"
>  #include "qemu/error-report.h"
> --
> 2.41.0
> 
> 

-- 



Re: [PATCH 09/10] hw/arm/xlnx-versal: Remove 'hw/arm/boot.h' from header

2023-10-25 Thread Luc Michel
On 08:53 Wed 25 Oct , Philippe Mathieu-Daudé wrote:
> "hw/arm/boot.h" is only required on the source file.
> 
> Signed-off-by: Philippe Mathieu-Daudé 

Reviewed-by: Luc Michel 

> ---
>  include/hw/arm/xlnx-versal.h | 1 -
>  hw/arm/xlnx-versal-virt.c| 1 +
>  2 files changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h
> index 7b419f88c2..b710d71fb0 100644
> --- a/include/hw/arm/xlnx-versal.h
> +++ b/include/hw/arm/xlnx-versal.h
> @@ -13,7 +13,6 @@
>  #define XLNX_VERSAL_H
> 
>  #include "hw/sysbus.h"
> -#include "hw/arm/boot.h"
>  #include "hw/cpu/cluster.h"
>  #include "hw/or-irq.h"
>  #include "hw/sd/sdhci.h"
> diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
> index 88c561ff63..537118224f 100644
> --- a/hw/arm/xlnx-versal-virt.c
> +++ b/hw/arm/xlnx-versal-virt.c
> @@ -19,6 +19,7 @@
>  #include "cpu.h"
>  #include "hw/qdev-properties.h"
>  #include "hw/arm/xlnx-versal.h"
> +#include "hw/arm/boot.h"
>  #include "qom/object.h"
> 
>  #define TYPE_XLNX_VERSAL_VIRT_MACHINE MACHINE_TYPE_NAME("xlnx-versal-virt")
> --
> 2.41.0
> 
> 

-- 



Re: [PATCH 07/10] hw/arm/fsl-imx6ul: Remove 'hw/arm/boot.h' from header

2023-10-25 Thread Luc Michel
On 08:53 Wed 25 Oct , Philippe Mathieu-Daudé wrote:
> "hw/arm/boot.h" is only required on the source file.
> 
> Signed-off-by: Philippe Mathieu-Daudé 

Reviewed-by: Luc Michel 

> ---
>  include/hw/arm/fsl-imx6ul.h | 1 -
>  hw/arm/mcimx6ul-evk.c   | 1 +
>  2 files changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/hw/arm/fsl-imx6ul.h b/include/hw/arm/fsl-imx6ul.h
> index 63012628ff..14390f6014 100644
> --- a/include/hw/arm/fsl-imx6ul.h
> +++ b/include/hw/arm/fsl-imx6ul.h
> @@ -17,7 +17,6 @@
>  #ifndef FSL_IMX6UL_H
>  #define FSL_IMX6UL_H
> 
> -#include "hw/arm/boot.h"
>  #include "hw/cpu/a15mpcore.h"
>  #include "hw/misc/imx6ul_ccm.h"
>  #include "hw/misc/imx6_src.h"
> diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c
> index 3ac1e2ea9b..500427e94b 100644
> --- a/hw/arm/mcimx6ul-evk.c
> +++ b/hw/arm/mcimx6ul-evk.c
> @@ -13,6 +13,7 @@
>  #include "qemu/osdep.h"
>  #include "qapi/error.h"
>  #include "hw/arm/fsl-imx6ul.h"
> +#include "hw/arm/boot.h"
>  #include "hw/boards.h"
>  #include "hw/qdev-properties.h"
>  #include "qemu/error-report.h"
> --
> 2.41.0
> 
> 

-- 



Re: [PATCH 05/10] hw/arm/fsl-imx31: Remove 'hw/arm/boot.h' from header

2023-10-25 Thread Luc Michel
On 08:53 Wed 25 Oct , Philippe Mathieu-Daudé wrote:
> "hw/arm/boot.h" is only required on the source file.
> 
> Signed-off-by: Philippe Mathieu-Daudé 

Reviewed-by: Luc Michel 

> ---
>  include/hw/arm/fsl-imx31.h | 1 -
>  hw/arm/kzm.c   | 1 +
>  2 files changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/hw/arm/fsl-imx31.h b/include/hw/arm/fsl-imx31.h
> index c116a73e0b..40c593a5cf 100644
> --- a/include/hw/arm/fsl-imx31.h
> +++ b/include/hw/arm/fsl-imx31.h
> @@ -17,7 +17,6 @@
>  #ifndef FSL_IMX31_H
>  #define FSL_IMX31_H
> 
> -#include "hw/arm/boot.h"
>  #include "hw/intc/imx_avic.h"
>  #include "hw/misc/imx31_ccm.h"
>  #include "hw/char/imx_serial.h"
> diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c
> index b1b281c9ac..9be91ebeaa 100644
> --- a/hw/arm/kzm.c
> +++ b/hw/arm/kzm.c
> @@ -16,6 +16,7 @@
>  #include "qemu/osdep.h"
>  #include "qapi/error.h"
>  #include "hw/arm/fsl-imx31.h"
> +#include "hw/arm/boot.h"
>  #include "hw/boards.h"
>  #include "qemu/error-report.h"
>  #include "exec/address-spaces.h"
> --
> 2.41.0
> 
> 

-- 



Re: [PATCH 06/10] hw/arm/fsl-imx6: Remove 'hw/arm/boot.h' from header

2023-10-25 Thread Luc Michel
On 08:53 Wed 25 Oct , Philippe Mathieu-Daudé wrote:
> "hw/arm/boot.h" is only required on the source file.
> 
> Signed-off-by: Philippe Mathieu-Daudé 

Reviewed-by: Luc Michel 

> ---
>  include/hw/arm/fsl-imx6.h | 1 -
>  hw/arm/sabrelite.c| 1 +
>  2 files changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/hw/arm/fsl-imx6.h b/include/hw/arm/fsl-imx6.h
> index 5b4d48da08..519b871014 100644
> --- a/include/hw/arm/fsl-imx6.h
> +++ b/include/hw/arm/fsl-imx6.h
> @@ -17,7 +17,6 @@
>  #ifndef FSL_IMX6_H
>  #define FSL_IMX6_H
> 
> -#include "hw/arm/boot.h"
>  #include "hw/cpu/a9mpcore.h"
>  #include "hw/misc/imx6_ccm.h"
>  #include "hw/misc/imx6_src.h"
> diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c
> index 41191245b8..56f184b9ae 100644
> --- a/hw/arm/sabrelite.c
> +++ b/hw/arm/sabrelite.c
> @@ -13,6 +13,7 @@
>  #include "qemu/osdep.h"
>  #include "qapi/error.h"
>  #include "hw/arm/fsl-imx6.h"
> +#include "hw/arm/boot.h"
>  #include "hw/boards.h"
>  #include "hw/qdev-properties.h"
>  #include "qemu/error-report.h"
> --
> 2.41.0
> 
> 

-- 



Re: [PATCH 03/10] hw/arm/allwinner-r40: Remove 'hw/arm/boot.h' from header

2023-10-25 Thread Luc Michel
On 08:53 Wed 25 Oct , Philippe Mathieu-Daudé wrote:
> "hw/arm/boot.h" is only required on the source file.
> 
> Signed-off-by: Philippe Mathieu-Daudé 

Reviewed-by: Luc Michel 

> ---
>  include/hw/arm/allwinner-r40.h | 1 -
>  hw/arm/bananapi_m2u.c  | 1 +
>  2 files changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/hw/arm/allwinner-r40.h b/include/hw/arm/allwinner-r40.h
> index 72710d3edc..6e1ac9d4c1 100644
> --- a/include/hw/arm/allwinner-r40.h
> +++ b/include/hw/arm/allwinner-r40.h
> @@ -21,7 +21,6 @@
>  #define HW_ARM_ALLWINNER_R40_H
> 
>  #include "qom/object.h"
> -#include "hw/arm/boot.h"
>  #include "hw/timer/allwinner-a10-pit.h"
>  #include "hw/intc/arm_gic.h"
>  #include "hw/sd/allwinner-sdhost.h"
> diff --git a/hw/arm/bananapi_m2u.c b/hw/arm/bananapi_m2u.c
> index 74121d8966..a7c7a9f96d 100644
> --- a/hw/arm/bananapi_m2u.c
> +++ b/hw/arm/bananapi_m2u.c
> @@ -26,6 +26,7 @@
>  #include "hw/i2c/i2c.h"
>  #include "hw/qdev-properties.h"
>  #include "hw/arm/allwinner-r40.h"
> +#include "hw/arm/boot.h"
> 
>  static struct arm_boot_info bpim2u_binfo;
> 
> --
> 2.41.0
> 
> 

-- 



Re: [PATCH 02/10] hw/arm/allwinner-h3: Remove 'hw/arm/boot.h' from header

2023-10-25 Thread Luc Michel
On 08:53 Wed 25 Oct , Philippe Mathieu-Daudé wrote:
> "hw/arm/boot.h" is only required on the source file.
> 
> Signed-off-by: Philippe Mathieu-Daudé 

Reviewed-by: Luc Michel 

> ---
>  include/hw/arm/allwinner-h3.h | 1 -
>  hw/arm/orangepi.c | 1 +
>  2 files changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
> index f15d6d7cc7..24ba4e1bf4 100644
> --- a/include/hw/arm/allwinner-h3.h
> +++ b/include/hw/arm/allwinner-h3.h
> @@ -36,7 +36,6 @@
>  #define HW_ARM_ALLWINNER_H3_H
> 
>  #include "qom/object.h"
> -#include "hw/arm/boot.h"
>  #include "hw/timer/allwinner-a10-pit.h"
>  #include "hw/intc/arm_gic.h"
>  #include "hw/misc/allwinner-h3-ccu.h"
> diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
> index 10653361ed..d0eca54cd9 100644
> --- a/hw/arm/orangepi.c
> +++ b/hw/arm/orangepi.c
> @@ -25,6 +25,7 @@
>  #include "hw/boards.h"
>  #include "hw/qdev-properties.h"
>  #include "hw/arm/allwinner-h3.h"
> +#include "hw/arm/boot.h"
> 
>  static struct arm_boot_info orangepi_binfo;
> 
> --
> 2.41.0
> 
> 

-- 



Re: [PATCH 04/10] hw/arm/fsl-imx25: Remove 'hw/arm/boot.h' from header

2023-10-25 Thread Luc Michel
On 08:53 Wed 25 Oct , Philippe Mathieu-Daudé wrote:
> "hw/arm/boot.h" is only required on the source file.
> 
> Signed-off-by: Philippe Mathieu-Daudé 

Reviewed-by: Luc Michel 

> ---
>  include/hw/arm/fsl-imx25.h | 1 -
>  hw/arm/imx25_pdk.c | 1 +
>  2 files changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/hw/arm/fsl-imx25.h b/include/hw/arm/fsl-imx25.h
> index 1b1086e945..df2f83980f 100644
> --- a/include/hw/arm/fsl-imx25.h
> +++ b/include/hw/arm/fsl-imx25.h
> @@ -17,7 +17,6 @@
>  #ifndef FSL_IMX25_H
>  #define FSL_IMX25_H
> 
> -#include "hw/arm/boot.h"
>  #include "hw/intc/imx_avic.h"
>  #include "hw/misc/imx25_ccm.h"
>  #include "hw/char/imx_serial.h"
> diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c
> index b4f7f4e8a7..7dfddd49e2 100644
> --- a/hw/arm/imx25_pdk.c
> +++ b/hw/arm/imx25_pdk.c
> @@ -27,6 +27,7 @@
>  #include "qapi/error.h"
>  #include "hw/qdev-properties.h"
>  #include "hw/arm/fsl-imx25.h"
> +#include "hw/arm/boot.h"
>  #include "hw/boards.h"
>  #include "qemu/error-report.h"
>  #include "sysemu/qtest.h"
> --
> 2.41.0
> 
> 

-- 



Re: [PATCH 01/10] hw/arm/allwinner-a10: Remove 'hw/arm/boot.h' from header

2023-10-25 Thread Luc Michel
On 08:53 Wed 25 Oct , Philippe Mathieu-Daudé wrote:
> "hw/arm/boot.h" is only required on the source file.
> 
> Signed-off-by: Philippe Mathieu-Daudé 

Reviewed-by: Luc Michel 

> ---
>  include/hw/arm/allwinner-a10.h | 1 -
>  hw/arm/cubieboard.c| 1 +
>  2 files changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h
> index cd1465c613..2eb83a17ea 100644
> --- a/include/hw/arm/allwinner-a10.h
> +++ b/include/hw/arm/allwinner-a10.h
> @@ -1,7 +1,6 @@
>  #ifndef HW_ARM_ALLWINNER_A10_H
>  #define HW_ARM_ALLWINNER_A10_H
> 
> -#include "hw/arm/boot.h"
>  #include "hw/timer/allwinner-a10-pit.h"
>  #include "hw/intc/allwinner-a10-pic.h"
>  #include "hw/net/allwinner_emac.h"
> diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c
> index 8c7fa91529..29146f5018 100644
> --- a/hw/arm/cubieboard.c
> +++ b/hw/arm/cubieboard.c
> @@ -21,6 +21,7 @@
>  #include "hw/boards.h"
>  #include "hw/qdev-properties.h"
>  #include "hw/arm/allwinner-a10.h"
> +#include "hw/arm/boot.h"
>  #include "hw/i2c/i2c.h"
> 
>  static struct arm_boot_info cubieboard_binfo = {
> --
> 2.41.0
> 
> 

-- 



[PATCH 09/11] hw/net/cadence_gem: use FIELD to describe PHYMNTNC register fields

2023-10-17 Thread Luc Michel
Use the FIELD macro to describe the PHYMNTNC register fields.

Signed-off-by: Luc Michel 
---
 hw/net/cadence_gem.c | 27 ++-
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 955a8da134..4c5fe10316 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -192,10 +192,18 @@ REG32(ISR, 0x24) /* Interrupt Status reg */
 REG32(IER, 0x28) /* Interrupt Enable reg */
 REG32(IDR, 0x2c) /* Interrupt Disable reg */
 REG32(IMR, 0x30) /* Interrupt Mask reg */
 
 REG32(PHYMNTNC, 0x34) /* Phy Maintenance reg */
+FIELD(PHYMNTNC, DATA, 0, 16)
+FIELD(PHYMNTNC, REG_ADDR, 18, 5)
+FIELD(PHYMNTNC, PHY_ADDR, 23, 5)
+FIELD(PHYMNTNC, OP, 28, 2)
+FIELD(PHYMNTNC, ST, 30, 2)
+#define MDIO_OP_READ0x3
+#define MDIO_OP_WRITE   0x2
+
 REG32(RXPAUSE, 0x38) /* RX Pause Time reg */
 REG32(TXPAUSE, 0x3c) /* TX Pause Time reg */
 REG32(TXPARTIALSF, 0x40) /* TX Partial Store and Forward */
 REG32(RXPARTIALSF, 0x44) /* RX Partial Store and Forward */
 REG32(JUMBO_MAX_LEN, 0x48) /* Max Jumbo Frame Size */
@@ -340,17 +348,10 @@ REG32(TYPE2_COMPARE_0_WORD_1, 0x704)
 
 /*/
 
 
 
-#define GEM_PHYMNTNC_OP_R  0x2000 /* read operation */
-#define GEM_PHYMNTNC_OP_W  0x1000 /* write operation */
-#define GEM_PHYMNTNC_ADDR  0x0F80 /* Address bits */
-#define GEM_PHYMNTNC_ADDR_SHFT 23
-#define GEM_PHYMNTNC_REG   0x007C /* register bits */
-#define GEM_PHYMNTNC_REG_SHIFT 18
-
 /* Marvell PHY definitions */
 #define BOARD_PHY_ADDRESS0 /* PHY address we will emulate a device at */
 
 #define PHY_REG_CONTROL  0
 #define PHY_REG_STATUS   1
@@ -1539,16 +1540,16 @@ static uint64_t gem_read(void *opaque, hwaddr offset, 
unsigned size)
 case R_ISR:
 DB_PRINT("lowering irqs on ISR read\n");
 /* The interrupts get updated at the end of the function. */
 break;
 case R_PHYMNTNC:
-if (retval & GEM_PHYMNTNC_OP_R) {
+if (FIELD_EX32(retval, PHYMNTNC, OP) == MDIO_OP_READ) {
 uint32_t phy_addr, reg_num;
 
-phy_addr = (retval & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
+phy_addr = FIELD_EX32(retval, PHYMNTNC, PHY_ADDR);
 if (phy_addr == s->phy_addr) {
-reg_num = (retval & GEM_PHYMNTNC_REG) >> 
GEM_PHYMNTNC_REG_SHIFT;
+reg_num = FIELD_EX32(retval, PHYMNTNC, REG_ADDR);
 retval &= 0x;
 retval |= gem_phy_read(s, reg_num);
 } else {
 retval |= 0x; /* No device at this address */
 }
@@ -1662,16 +1663,16 @@ static void gem_write(void *opaque, hwaddr offset, 
uint64_t val,
 case R_SPADDR3HI:
 case R_SPADDR4HI:
 s->sar_active[(offset - R_SPADDR1HI) / 2] = true;
 break;
 case R_PHYMNTNC:
-if (val & GEM_PHYMNTNC_OP_W) {
+if (FIELD_EX32(val, PHYMNTNC, OP) == MDIO_OP_WRITE) {
 uint32_t phy_addr, reg_num;
 
-phy_addr = (val & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
+phy_addr = FIELD_EX32(val, PHYMNTNC, PHY_ADDR);
 if (phy_addr == s->phy_addr) {
-reg_num = (val & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
+reg_num = FIELD_EX32(val, PHYMNTNC, REG_ADDR);
 gem_phy_write(s, reg_num, val);
 }
 }
 break;
 }
-- 
2.39.2




[PATCH 02/11] hw/net/cadence_gem: use FIELD for screening registers

2023-10-17 Thread Luc Michel
Describe screening registers fields using the FIELD macros.

Signed-off-by: Luc Michel 
---
 hw/net/cadence_gem.c | 92 ++--
 1 file changed, 47 insertions(+), 45 deletions(-)

diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 0e5744ecd7..f01c81de97 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -168,39 +168,42 @@ REG32(INT_Q7_ENABLE, 0x618)
 
 REG32(INT_Q1_DISABLE, 0x620)
 REG32(INT_Q7_DISABLE, 0x638)
 
 REG32(SCREENING_TYPE1_REG0, 0x500)
-
-#define GEM_ST1R_UDP_PORT_MATCH_ENABLE  (1 << 29)
-#define GEM_ST1R_DSTC_ENABLE(1 << 28)
-#define GEM_ST1R_UDP_PORT_MATCH_SHIFT   (12)
-#define GEM_ST1R_UDP_PORT_MATCH_WIDTH   (27 - GEM_ST1R_UDP_PORT_MATCH_SHIFT + 
1)
-#define GEM_ST1R_DSTC_MATCH_SHIFT   (4)
-#define GEM_ST1R_DSTC_MATCH_WIDTH   (11 - GEM_ST1R_DSTC_MATCH_SHIFT + 1)
-#define GEM_ST1R_QUEUE_SHIFT(0)
-#define GEM_ST1R_QUEUE_WIDTH(3 - GEM_ST1R_QUEUE_SHIFT + 1)
+FIELD(SCREENING_TYPE1_REG0, QUEUE_NUM, 0, 4)
+FIELD(SCREENING_TYPE1_REG0, DSTC_MATCH, 4, 8)
+FIELD(SCREENING_TYPE1_REG0, UDP_PORT_MATCH, 12, 16)
+FIELD(SCREENING_TYPE1_REG0, DSTC_ENABLE, 28, 1)
+FIELD(SCREENING_TYPE1_REG0, UDP_PORT_MATCH_EN, 29, 1)
+FIELD(SCREENING_TYPE1_REG0, DROP_ON_MATCH, 30, 1)
 
 REG32(SCREENING_TYPE2_REG0, 0x540)
-
-#define GEM_ST2R_COMPARE_A_ENABLE   (1 << 18)
-#define GEM_ST2R_COMPARE_A_SHIFT(13)
-#define GEM_ST2R_COMPARE_WIDTH  (17 - GEM_ST2R_COMPARE_A_SHIFT + 1)
-#define GEM_ST2R_ETHERTYPE_ENABLE   (1 << 12)
-#define GEM_ST2R_ETHERTYPE_INDEX_SHIFT  (9)
-#define GEM_ST2R_ETHERTYPE_INDEX_WIDTH  (11 - GEM_ST2R_ETHERTYPE_INDEX_SHIFT \
-+ 1)
-#define GEM_ST2R_QUEUE_SHIFT(0)
-#define GEM_ST2R_QUEUE_WIDTH(3 - GEM_ST2R_QUEUE_SHIFT + 1)
+FIELD(SCREENING_TYPE2_REG0, QUEUE_NUM, 0, 4)
+FIELD(SCREENING_TYPE2_REG0, VLAN_PRIORITY, 4, 3)
+FIELD(SCREENING_TYPE2_REG0, VLAN_ENABLE, 8, 1)
+FIELD(SCREENING_TYPE2_REG0, ETHERTYPE_REG_INDEX, 9, 3)
+FIELD(SCREENING_TYPE2_REG0, ETHERTYPE_ENABLE, 12, 1)
+FIELD(SCREENING_TYPE2_REG0, COMPARE_A, 13, 5)
+FIELD(SCREENING_TYPE2_REG0, COMPARE_A_ENABLE, 18, 1)
+FIELD(SCREENING_TYPE2_REG0, COMPARE_B, 19, 5)
+FIELD(SCREENING_TYPE2_REG0, COMPARE_B_ENABLE, 24, 1)
+FIELD(SCREENING_TYPE2_REG0, COMPARE_C, 25, 5)
+FIELD(SCREENING_TYPE2_REG0, COMPARE_C_ENABLE, 30, 1)
+FIELD(SCREENING_TYPE2_REG0, DROP_ON_MATCH, 31, 1)
 
 REG32(SCREENING_TYPE2_ETHERTYPE_REG0, 0x6e0)
+
 REG32(TYPE2_COMPARE_0_WORD_0, 0x700)
+FIELD(TYPE2_COMPARE_0_WORD_0, MASK_VALUE, 0, 16)
+FIELD(TYPE2_COMPARE_0_WORD_0, COMPARE_VALUE, 16, 16)
 
-#define GEM_T2CW1_COMPARE_OFFSET_SHIFT  (7)
-#define GEM_T2CW1_COMPARE_OFFSET_WIDTH  (8 - GEM_T2CW1_COMPARE_OFFSET_SHIFT + 
1)
-#define GEM_T2CW1_OFFSET_VALUE_SHIFT(0)
-#define GEM_T2CW1_OFFSET_VALUE_WIDTH(6 - GEM_T2CW1_OFFSET_VALUE_SHIFT + 1)
+REG32(TYPE2_COMPARE_0_WORD_1, 0x704)
+FIELD(TYPE2_COMPARE_0_WORD_1, OFFSET_VALUE, 0, 7)
+FIELD(TYPE2_COMPARE_0_WORD_1, COMPARE_OFFSET, 7, 2)
+FIELD(TYPE2_COMPARE_0_WORD_1, DISABLE_MASK, 9, 1)
+FIELD(TYPE2_COMPARE_0_WORD_1, COMPARE_VLAN_ID, 10, 1)
 
 /*/
 #define GEM_NWCTRL_TXSTART 0x0200 /* Transmit Enable */
 #define GEM_NWCTRL_TXENA   0x0008 /* Transmit Enable */
 #define GEM_NWCTRL_RXENA   0x0004 /* Receive Enable */
@@ -753,45 +756,43 @@ static int get_queue_from_screen(CadenceGEMState *s, 
uint8_t *rxbuf_ptr,
 reg = s->regs[R_SCREENING_TYPE1_REG0 + i];
 matched = false;
 mismatched = false;
 
 /* Screening is based on UDP Port */
-if (reg & GEM_ST1R_UDP_PORT_MATCH_ENABLE) {
+if (FIELD_EX32(reg, SCREENING_TYPE1_REG0, UDP_PORT_MATCH_EN)) {
 uint16_t udp_port = rxbuf_ptr[14 + 22] << 8 | rxbuf_ptr[14 + 23];
-if (udp_port == extract32(reg, GEM_ST1R_UDP_PORT_MATCH_SHIFT,
-   GEM_ST1R_UDP_PORT_MATCH_WIDTH)) {
+if (udp_port == FIELD_EX32(reg, SCREENING_TYPE1_REG0, 
UDP_PORT_MATCH)) {
 matched = true;
 } else {
 mismatched = true;
 }
 }
 
 /* Screening is based on DS/TC */
-if (reg & GEM_ST1R_DSTC_ENABLE) {
+if (FIELD_EX32(reg, SCREENING_TYPE1_REG0, DSTC_ENABLE)) {
 uint8_t dscp = rxbuf_ptr[14 + 1];
-if (dscp == extract32(reg, GEM_ST1R_DSTC_MATCH_SHIFT,
-   GEM_ST1R_DSTC_MATCH_WIDTH)) {
+if (dscp == FIELD_EX32(reg, SCREENING_TYPE1_REG0, DSTC_MATCH)) {
 matched = true;
 } else {
 mismatched = true;
 }
 }
 
 if (matched && !mismatched) {
-return extract32(reg, GEM_ST1R_QUEUE_SHIFT, GEM_ST1R

[PATCH 03/11] hw/net/cadence_gem: use FIELD to describe NWCTRL register fields

2023-10-17 Thread Luc Michel
Use the FIELD macro to describe the NWCTRL register fields.

Signed-off-by: Luc Michel 
---
 hw/net/cadence_gem.c | 53 +---
 1 file changed, 40 insertions(+), 13 deletions(-)

diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index f01c81de97..2864f0940e 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -44,10 +44,42 @@
 qemu_log(__VA_ARGS__); \
 } \
 } while (0)
 
 REG32(NWCTRL, 0x0) /* Network Control reg */
+FIELD(NWCTRL, LOOPBACK , 0, 1)
+FIELD(NWCTRL, LOOPBACK_LOCAL , 1, 1)
+FIELD(NWCTRL, ENABLE_RECEIVE, 2, 1)
+FIELD(NWCTRL, ENABLE_TRANSMIT, 3, 1)
+FIELD(NWCTRL, MAN_PORT_EN , 4, 1)
+FIELD(NWCTRL, CLEAR_ALL_STATS_REGS , 5, 1)
+FIELD(NWCTRL, INC_ALL_STATS_REGS, 6, 1)
+FIELD(NWCTRL, STATS_WRITE_EN, 7, 1)
+FIELD(NWCTRL, BACK_PRESSURE, 8, 1)
+FIELD(NWCTRL, TRANSMIT_START , 9, 1)
+FIELD(NWCTRL, TRANSMIT_HALT, 10, 1)
+FIELD(NWCTRL, TX_PAUSE_FRAME_RE, 11, 1)
+FIELD(NWCTRL, TX_PAUSE_FRAME_ZE, 12, 1)
+FIELD(NWCTRL, STATS_TAKE_SNAP, 13, 1)
+FIELD(NWCTRL, STATS_READ_SNAP, 14, 1)
+FIELD(NWCTRL, STORE_RX_TS, 15, 1)
+FIELD(NWCTRL, PFC_ENABLE, 16, 1)
+FIELD(NWCTRL, PFC_PRIO_BASED, 17, 1)
+FIELD(NWCTRL, FLUSH_RX_PKT_PCLK , 18, 1)
+FIELD(NWCTRL, TX_LPI_EN, 19, 1)
+FIELD(NWCTRL, PTP_UNICAST_ENA, 20, 1)
+FIELD(NWCTRL, ALT_SGMII_MODE, 21, 1)
+FIELD(NWCTRL, STORE_UDP_OFFSET, 22, 1)
+FIELD(NWCTRL, EXT_TSU_PORT_EN, 23, 1)
+FIELD(NWCTRL, ONE_STEP_SYNC_MO, 24, 1)
+FIELD(NWCTRL, PFC_CTRL , 25, 1)
+FIELD(NWCTRL, EXT_RXQ_SEL_EN , 26, 1)
+FIELD(NWCTRL, OSS_CORRECTION_FIELD, 27, 1)
+FIELD(NWCTRL, SEL_MII_ON_RGMII, 28, 1)
+FIELD(NWCTRL, TWO_PT_FIVE_GIG, 29, 1)
+FIELD(NWCTRL, IFG_EATS_QAV_CREDIT, 30, 1)
+
 REG32(NWCFG, 0x4) /* Network Config reg */
 REG32(NWSTATUS, 0x8) /* Network Status reg */
 REG32(USERIO, 0xc) /* User IO reg */
 REG32(DMACFG, 0x10) /* DMA Control reg */
 REG32(TXSTATUS, 0x14) /* TX Status reg */
@@ -202,15 +234,10 @@ REG32(TYPE2_COMPARE_0_WORD_1, 0x704)
 FIELD(TYPE2_COMPARE_0_WORD_1, COMPARE_OFFSET, 7, 2)
 FIELD(TYPE2_COMPARE_0_WORD_1, DISABLE_MASK, 9, 1)
 FIELD(TYPE2_COMPARE_0_WORD_1, COMPARE_VLAN_ID, 10, 1)
 
 /*/
-#define GEM_NWCTRL_TXSTART 0x0200 /* Transmit Enable */
-#define GEM_NWCTRL_TXENA   0x0008 /* Transmit Enable */
-#define GEM_NWCTRL_RXENA   0x0004 /* Receive Enable */
-#define GEM_NWCTRL_LOCALLOOP   0x0002 /* Local Loopback */
-
 #define GEM_NWCFG_STRIP_FCS0x0002 /* Strip FCS field */
 #define GEM_NWCFG_LERR_DISC0x0001 /* Discard RX frames with len err */
 #define GEM_NWCFG_BUFF_OFST_M  0xC000 /* Receive buffer offset mask */
 #define GEM_NWCFG_BUFF_OFST_S  14 /* Receive buffer offset shift */
 #define GEM_NWCFG_RCV_1538 0x0100 /* Receive 1538 bytes frame */
@@ -558,11 +585,11 @@ static bool gem_can_receive(NetClientState *nc)
 int i;
 
 s = qemu_get_nic_opaque(nc);
 
 /* Do nothing if receive is not enabled. */
-if (!(s->regs[R_NWCTRL] & GEM_NWCTRL_RXENA)) {
+if (!FIELD_EX32(s->regs[R_NWCTRL], NWCTRL, ENABLE_RECEIVE)) {
 if (s->can_rx_state != 1) {
 s->can_rx_state = 1;
 DB_PRINT("can't receive - no enable\n");
 }
 return false;
@@ -1171,11 +1198,11 @@ static void gem_transmit(CadenceGEMState *s)
 uint8_t *p;
 unsignedtotal_bytes;
 int q = 0;
 
 /* Do nothing if transmit is not enabled. */
-if (!(s->regs[R_NWCTRL] & GEM_NWCTRL_TXENA)) {
+if (!FIELD_EX32(s->regs[R_NWCTRL], NWCTRL, ENABLE_TRANSMIT)) {
 return;
 }
 
 DB_PRINT("\n");
 
@@ -1196,11 +1223,11 @@ static void gem_transmit(CadenceGEMState *s)
sizeof(uint32_t) * gem_get_desc_len(s, false));
 /* Handle all descriptors owned by hardware */
 while (tx_desc_get_used(desc) == 0) {
 
 /* Do nothing if transmit is not enabled. */
-if (!(s->regs[R_NWCTRL] & GEM_NWCTRL_TXENA)) {
+if (!FIELD_EX32(s->regs[R_NWCTRL], NWCTRL, ENABLE_TRANSMIT)) {
 return;
 }
 print_gem_tx_desc(desc, q);
 
 /* The real hardware would eat this (and possibly crash).
@@ -1269,12 +1296,12 @@ static void gem_transmit(CadenceGEMState *s)
 
 /* Update MAC statistics */
 gem_transmit_updatestats(s, s->tx_packet, total_bytes);
 
 /* Send the packet somewhere */
-if (s->phy_loop || (s->regs[R_NWCTRL] &
-GEM_NWCTRL_LOCALLOOP)) {
+if (s->phy_loop || FIELD_EX32(s->regs[R_NWCTRL], NWCTRL,
+  LOOPBACK_LOCAL)) {
 qemu_receive_packet(qemu_get_queue(s->nic), s->tx_packe

[PATCH 08/11] hw/net/cadence_gem: use FIELD to describe DESCONF6 register fields

2023-10-17 Thread Luc Michel
Use the FIELD macro to describe the DESCONF6 register fields.

Signed-off-by: Luc Michel 
---
 hw/net/cadence_gem.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 6d084a3b31..955a8da134 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -281,11 +281,11 @@ REG32(DESCONF, 0x280)
 REG32(DESCONF2, 0x284)
 REG32(DESCONF3, 0x288)
 REG32(DESCONF4, 0x28c)
 REG32(DESCONF5, 0x290)
 REG32(DESCONF6, 0x294)
-#define GEM_DESCONF6_64B_MASK (1U << 23)
+FIELD(DESCONF6, DMA_ADDR_64B, 23, 1)
 REG32(DESCONF7, 0x298)
 
 REG32(INT_Q1_STATUS, 0x400)
 REG32(INT_Q1_MASK, 0x640)
 
@@ -1461,11 +1461,11 @@ static void gem_reset(DeviceState *d)
 s->regs[R_RXPARTIALSF] = 0x03ff;
 s->regs[R_MODID] = s->revision;
 s->regs[R_DESCONF] = 0x02D00111;
 s->regs[R_DESCONF2] = 0x2ab1 | s->jumbo_max_len;
 s->regs[R_DESCONF5] = 0x002f2045;
-s->regs[R_DESCONF6] = GEM_DESCONF6_64B_MASK;
+s->regs[R_DESCONF6] = R_DESCONF6_DMA_ADDR_64B_MASK;
 s->regs[R_INT_Q1_MASK] = 0x0CE6;
 s->regs[R_JUMBO_MAX_LEN] = s->jumbo_max_len;
 
 if (s->num_priority_queues > 1) {
 queues_mask = MAKE_64BIT_MASK(1, s->num_priority_queues - 1);
-- 
2.39.2




[PATCH 04/11] hw/net/cadence_gem: use FIELD to describe NWCFG register fields

2023-10-17 Thread Luc Michel
Use de FIELD macro to describe the NWCFG register fields.

Signed-off-by: Luc Michel 
---
 hw/net/cadence_gem.c | 60 
 1 file changed, 39 insertions(+), 21 deletions(-)

diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 2864f0940e..09f570b6fb 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -77,10 +77,39 @@ REG32(NWCTRL, 0x0) /* Network Control reg */
 FIELD(NWCTRL, SEL_MII_ON_RGMII, 28, 1)
 FIELD(NWCTRL, TWO_PT_FIVE_GIG, 29, 1)
 FIELD(NWCTRL, IFG_EATS_QAV_CREDIT, 30, 1)
 
 REG32(NWCFG, 0x4) /* Network Config reg */
+FIELD(NWCFG, SPEED, 0, 1)
+FIELD(NWCFG, FULL_DUPLEX, 1, 1)
+FIELD(NWCFG, DISCARD_NON_VLAN_FRAMES, 2, 1)
+FIELD(NWCFG, JUMBO_FRAMES, 3, 1)
+FIELD(NWCFG, PROMISC, 4, 1)
+FIELD(NWCFG, NO_BROADCAST, 5, 1)
+FIELD(NWCFG, MULTICAST_HASH_EN, 6, 1)
+FIELD(NWCFG, UNICAST_HASH_EN, 7, 1)
+FIELD(NWCFG, RECV_1536_BYTE_FRAMES, 8, 1)
+FIELD(NWCFG, EXTERNAL_ADDR_MATCH_EN, 9, 1)
+FIELD(NWCFG, GIGABIT_MODE_ENABLE, 10, 1)
+FIELD(NWCFG, PCS_SELECT, 11, 1)
+FIELD(NWCFG, RETRY_TEST, 12, 1)
+FIELD(NWCFG, PAUSE_ENABLE, 13, 1)
+FIELD(NWCFG, RECV_BUF_OFFSET, 14, 2)
+FIELD(NWCFG, LEN_ERR_DISCARD, 16, 1)
+FIELD(NWCFG, FCS_REMOVE, 17, 1)
+FIELD(NWCFG, MDC_CLOCK_DIV, 18, 3)
+FIELD(NWCFG, DATA_BUS_WIDTH, 21, 2)
+FIELD(NWCFG, DISABLE_COPY_PAUSE_FRAMES, 23, 1)
+FIELD(NWCFG, RECV_CSUM_OFFLOAD_EN, 24, 1)
+FIELD(NWCFG, EN_HALF_DUPLEX_RX, 25, 1)
+FIELD(NWCFG, IGNORE_RX_FCS, 26, 1)
+FIELD(NWCFG, SGMII_MODE_ENABLE, 27, 1)
+FIELD(NWCFG, IPG_STRETCH_ENABLE, 28, 1)
+FIELD(NWCFG, NSP_ACCEPT, 29, 1)
+FIELD(NWCFG, IGNORE_IPG_RX_ER, 30, 1)
+FIELD(NWCFG, UNI_DIRECTION_ENABLE, 31, 1)
+
 REG32(NWSTATUS, 0x8) /* Network Status reg */
 REG32(USERIO, 0xc) /* User IO reg */
 REG32(DMACFG, 0x10) /* DMA Control reg */
 REG32(TXSTATUS, 0x14) /* TX Status reg */
 REG32(RXQBASE, 0x18) /* RX Q Base address reg */
@@ -234,21 +263,10 @@ REG32(TYPE2_COMPARE_0_WORD_1, 0x704)
 FIELD(TYPE2_COMPARE_0_WORD_1, COMPARE_OFFSET, 7, 2)
 FIELD(TYPE2_COMPARE_0_WORD_1, DISABLE_MASK, 9, 1)
 FIELD(TYPE2_COMPARE_0_WORD_1, COMPARE_VLAN_ID, 10, 1)
 
 /*/
-#define GEM_NWCFG_STRIP_FCS0x0002 /* Strip FCS field */
-#define GEM_NWCFG_LERR_DISC0x0001 /* Discard RX frames with len err */
-#define GEM_NWCFG_BUFF_OFST_M  0xC000 /* Receive buffer offset mask */
-#define GEM_NWCFG_BUFF_OFST_S  14 /* Receive buffer offset shift */
-#define GEM_NWCFG_RCV_1538 0x0100 /* Receive 1538 bytes frame */
-#define GEM_NWCFG_UCAST_HASH   0x0080 /* accept unicast if hash match */
-#define GEM_NWCFG_MCAST_HASH   0x0040 /* accept multicast if hash match */
-#define GEM_NWCFG_BCAST_REJ0x0020 /* Reject broadcast packets */
-#define GEM_NWCFG_PROMISC  0x0010 /* Accept all packets */
-#define GEM_NWCFG_JUMBO_FRAME  0x0008 /* Jumbo Frames enable */
-
 #define GEM_DMACFG_ADDR_64B(1U << 30)
 #define GEM_DMACFG_TX_BD_EXT   (1U << 29)
 #define GEM_DMACFG_RX_BD_EXT   (1U << 28)
 #define GEM_DMACFG_RBUFSZ_M0x00FF /* DMA RX Buffer Size mask */
 #define GEM_DMACFG_RBUFSZ_S16 /* DMA RX Buffer Size shift */
@@ -480,21 +498,22 @@ static inline void rx_desc_set_sar(uint32_t *desc, int 
sar_idx)
 static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
 static uint32_t gem_get_max_buf_len(CadenceGEMState *s, bool tx)
 {
 uint32_t size;
-if (s->regs[R_NWCFG] & GEM_NWCFG_JUMBO_FRAME) {
+if (FIELD_EX32(s->regs[R_NWCFG], NWCFG, JUMBO_FRAMES)) {
 size = s->regs[R_JUMBO_MAX_LEN];
 if (size > s->jumbo_max_len) {
 size = s->jumbo_max_len;
 qemu_log_mask(LOG_GUEST_ERROR, "GEM_JUMBO_MAX_LEN reg cannot be"
 " greater than 0x%" PRIx32 "\n", s->jumbo_max_len);
 }
 } else if (tx) {
 size = 1518;
 } else {
-size = s->regs[R_NWCFG] & GEM_NWCFG_RCV_1538 ? 1538 : 1518;
+size = FIELD_EX32(s->regs[R_NWCFG],
+  NWCFG, RECV_1536_BYTE_FRAMES) ? 1538 : 1518;
 }
 return size;
 }
 
 static void gem_set_isr(CadenceGEMState *s, int q, uint32_t flag)
@@ -730,26 +749,26 @@ static int gem_mac_address_filter(CadenceGEMState *s, 
const uint8_t *packet)
 {
 uint8_t *gem_spaddr;
 int i, is_mc;
 
 /* Promiscuous mode? */
-if (s->regs[R_NWCFG] & GEM_NWCFG_PROMISC) {
+if (FIELD_EX32(s->regs[R_NWCFG], NWCFG, PROMISC)) {
 return GEM_RX_PROMISCUOUS_ACCEPT;
 }
 
 if (!memcmp(packet, broadcast_addr, 6)) {
 /* Reject broadcast packets? */
-if (s->regs[R_NWCFG] & GEM_NWCFG_BCAST_REJ) {
+if (FIELD_EX32(s->regs[R_NWCFG], NWCFG, NO_BROADCAST)) {
 return GEM_RX_REJECT;
 }

[PATCH 00/11] Various updates for the Cadence GEM model

2023-10-17 Thread Luc Michel
Hi,

This series brings small changes to the Cadence GEM Ethernet model.
There is (almost) no behaviour change.

Patches 1 to 9 replace handcrafted defines with the use of REG32 and
FIELDS macros for register and fields declarations.

Patch 10 fixes PHY accesses so that they are done only on a write to the
PHYMNTNC register (as the real hardware does).

Patch 11 fixes a potential bug on hosts where unsigned would not be 32
bits.

Thanks,

-- 
Luc

Luc Michel (11):
  hw/net/cadence_gem: use REG32 macro for register definitions
  hw/net/cadence_gem: use FIELD for screening registers
  hw/net/cadence_gem: use FIELD to describe NWCTRL register fields
  hw/net/cadence_gem: use FIELD to describe NWCFG register fields
  hw/net/cadence_gem: use FIELD to describe DMACFG register fields
  hw/net/cadence_gem: use FIELD to describe [TX|RX]STATUS register
fields
  hw/net/cadence_gem: use FIELD to describe IRQ register fields
  hw/net/cadence_gem: use FIELD to describe DESCONF6 register fields
  hw/net/cadence_gem: use FIELD to describe PHYMNTNC register fields
  hw/net/cadence_gem: perform PHY access on write only
  hw/net/cadence_gem: enforce 32 bits variable size for CRC

 hw/net/cadence_gem.c | 910 ---
 1 file changed, 510 insertions(+), 400 deletions(-)

-- 
2.39.2




[PATCH 11/11] hw/net/cadence_gem: enforce 32 bits variable size for CRC

2023-10-17 Thread Luc Michel
The CRC was stored in an unsigned variable in gem_receive. Change it for
a uint32_t to ensure we have the correct variable size here.

Signed-off-by: Luc Michel 
---
 hw/net/cadence_gem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 21146f4242..d52530bae4 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -1103,11 +1103,11 @@ static ssize_t gem_receive(NetClientState *nc, const 
uint8_t *buf, size_t size)
 
 /* Strip of FCS field ? (usually yes) */
 if (FIELD_EX32(s->regs[R_NWCFG], NWCFG, FCS_REMOVE)) {
 rxbuf_ptr = (void *)buf;
 } else {
-unsigned crc_val;
+uint32_t crc_val;
 
 if (size > MAX_FRAME_SIZE - sizeof(crc_val)) {
 size = MAX_FRAME_SIZE - sizeof(crc_val);
 }
 bytes_to_copy = size;
-- 
2.39.2




[PATCH 05/11] hw/net/cadence_gem: use FIELD to describe DMACFG register fields

2023-10-17 Thread Luc Michel
Use de FIELD macro to describe the DMACFG register fields.

Signed-off-by: Luc Michel 
---
 hw/net/cadence_gem.c | 48 
 1 file changed, 31 insertions(+), 17 deletions(-)

diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 09f570b6fb..5c386adff2 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -108,11 +108,31 @@ REG32(NWCFG, 0x4) /* Network Config reg */
 FIELD(NWCFG, IGNORE_IPG_RX_ER, 30, 1)
 FIELD(NWCFG, UNI_DIRECTION_ENABLE, 31, 1)
 
 REG32(NWSTATUS, 0x8) /* Network Status reg */
 REG32(USERIO, 0xc) /* User IO reg */
+
 REG32(DMACFG, 0x10) /* DMA Control reg */
+FIELD(DMACFG, SEND_BCAST_TO_ALL_QS, 31, 1)
+FIELD(DMACFG, DMA_ADDR_BUS_WIDTH, 30, 1)
+FIELD(DMACFG, TX_BD_EXT_MODE_EN , 29, 1)
+FIELD(DMACFG, RX_BD_EXT_MODE_EN , 28, 1)
+FIELD(DMACFG, FORCE_MAX_AMBA_BURST_TX, 26, 1)
+FIELD(DMACFG, FORCE_MAX_AMBA_BURST_RX, 25, 1)
+FIELD(DMACFG, FORCE_DISCARD_ON_ERR, 24, 1)
+FIELD(DMACFG, RX_BUF_SIZE, 16, 8)
+FIELD(DMACFG, CRC_ERROR_REPORT, 13, 1)
+FIELD(DMACFG, INF_LAST_DBUF_SIZE_EN, 12, 1)
+FIELD(DMACFG, TX_PBUF_CSUM_OFFLOAD, 11, 1)
+FIELD(DMACFG, TX_PBUF_SIZE, 10, 1)
+FIELD(DMACFG, RX_PBUF_SIZE, 8, 2)
+FIELD(DMACFG, ENDIAN_SWAP_PACKET, 7, 1)
+FIELD(DMACFG, ENDIAN_SWAP_MGNT, 6, 1)
+FIELD(DMACFG, HDR_DATA_SPLIT_EN, 5, 1)
+FIELD(DMACFG, AMBA_BURST_LEN , 0, 5)
+#define GEM_DMACFG_RBUFSZ_MUL  64 /* DMA RX Buffer Size multiplier */
+
 REG32(TXSTATUS, 0x14) /* TX Status reg */
 REG32(RXQBASE, 0x18) /* RX Q Base address reg */
 REG32(TXQBASE, 0x1c) /* TX Q Base address reg */
 REG32(RXSTATUS, 0x20) /* RX Status reg */
 REG32(ISR, 0x24) /* Interrupt Status reg */
@@ -263,17 +283,10 @@ REG32(TYPE2_COMPARE_0_WORD_1, 0x704)
 FIELD(TYPE2_COMPARE_0_WORD_1, COMPARE_OFFSET, 7, 2)
 FIELD(TYPE2_COMPARE_0_WORD_1, DISABLE_MASK, 9, 1)
 FIELD(TYPE2_COMPARE_0_WORD_1, COMPARE_VLAN_ID, 10, 1)
 
 /*/
-#define GEM_DMACFG_ADDR_64B(1U << 30)
-#define GEM_DMACFG_TX_BD_EXT   (1U << 29)
-#define GEM_DMACFG_RX_BD_EXT   (1U << 28)
-#define GEM_DMACFG_RBUFSZ_M0x00FF /* DMA RX Buffer Size mask */
-#define GEM_DMACFG_RBUFSZ_S16 /* DMA RX Buffer Size shift */
-#define GEM_DMACFG_RBUFSZ_MUL  64 /* DMA RX Buffer Size multiplier */
-#define GEM_DMACFG_TXCSUM_OFFL 0x0800 /* Transmit checksum offload */
 
 #define GEM_TXSTATUS_TXCMPL0x0020 /* Transmit Complete */
 #define GEM_TXSTATUS_USED  0x0001 /* sw owned descriptor encountered */
 
 #define GEM_RXSTATUS_FRMRCVD   0x0002 /* Frame received */
@@ -367,11 +380,11 @@ REG32(TYPE2_COMPARE_0_WORD_1, 0x704)
 
 static inline uint64_t tx_desc_get_buffer(CadenceGEMState *s, uint32_t *desc)
 {
 uint64_t ret = desc[0];
 
-if (s->regs[R_DMACFG] & GEM_DMACFG_ADDR_64B) {
+if (FIELD_EX32(s->regs[R_DMACFG], DMACFG, DMA_ADDR_BUS_WIDTH)) {
 ret |= (uint64_t)desc[2] << 32;
 }
 return ret;
 }
 
@@ -412,25 +425,25 @@ static inline void print_gem_tx_desc(uint32_t *desc, 
uint8_t queue)
 
 static inline uint64_t rx_desc_get_buffer(CadenceGEMState *s, uint32_t *desc)
 {
 uint64_t ret = desc[0] & ~0x3UL;
 
-if (s->regs[R_DMACFG] & GEM_DMACFG_ADDR_64B) {
+if (FIELD_EX32(s->regs[R_DMACFG], DMACFG, DMA_ADDR_BUS_WIDTH)) {
 ret |= (uint64_t)desc[2] << 32;
 }
 return ret;
 }
 
 static inline int gem_get_desc_len(CadenceGEMState *s, bool rx_n_tx)
 {
 int ret = 2;
 
-if (s->regs[R_DMACFG] & GEM_DMACFG_ADDR_64B) {
+if (FIELD_EX32(s->regs[R_DMACFG], DMACFG, DMA_ADDR_BUS_WIDTH)) {
 ret += 2;
 }
-if (s->regs[R_DMACFG] & (rx_n_tx ? GEM_DMACFG_RX_BD_EXT
-   : GEM_DMACFG_TX_BD_EXT)) {
+if (s->regs[R_DMACFG] & (rx_n_tx ? R_DMACFG_RX_BD_EXT_MODE_EN_MASK
+ : R_DMACFG_TX_BD_EXT_MODE_EN_MASK)) {
 ret += 2;
 }
 
 assert(ret <= DESC_MAX_NUM_WORDS);
 return ret;
@@ -940,11 +953,11 @@ static inline uint32_t 
gem_get_rx_queue_base_addr(CadenceGEMState *s, int q)
 
 static hwaddr gem_get_desc_addr(CadenceGEMState *s, bool tx, int q)
 {
 hwaddr desc_addr = 0;
 
-if (s->regs[R_DMACFG] & GEM_DMACFG_ADDR_64B) {
+if (FIELD_EX32(s->regs[R_DMACFG], DMACFG, DMA_ADDR_BUS_WIDTH)) {
 desc_addr = s->regs[tx ? R_TBQPH : R_RBQPH];
 }
 desc_addr <<= 32;
 desc_addr |= tx ? s->tx_desc_addr[q] : s->rx_desc_addr[q];
 return desc_addr;
@@ -1022,12 +1035,13 @@ static ssize_t gem_receive(NetClientState *nc, const 
uint8_t *buf, size_t size)
 rxbuf_offset = FIELD_EX32(s->regs[R_NWCFG], NWCFG, RECV_BUF_OFFSET);
 
 /* The configure size of each receive buffer.  Determines how many
  * buffers needed to hold this packet.
  */
-rxbufsize = ((s->regs[R_DMACFG] & GEM_DMA

[PATCH 10/11] hw/net/cadence_gem: perform PHY access on write only

2023-10-17 Thread Luc Michel
The MDIO access is done only on a write to the PHYMNTNC register. A
subsequent read is used to retrieve the result but does not trigger an
MDIO access by itself.

Refactor the PHY access logic to perform all accesses (MDIO reads and
writes) at PHYMNTNC write time.

Signed-off-by: Luc Michel 
---
 hw/net/cadence_gem.c | 56 ++--
 1 file changed, 33 insertions(+), 23 deletions(-)

diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 4c5fe10316..21146f4242 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -1519,10 +1519,42 @@ static void gem_phy_write(CadenceGEMState *s, unsigned 
reg_num, uint16_t val)
 break;
 }
 s->phy_regs[reg_num] = val;
 }
 
+static void gem_handle_phy_access(CadenceGEMState *s)
+{
+uint32_t val = s->regs[R_PHYMNTNC];
+uint32_t phy_addr, reg_num;
+
+phy_addr = FIELD_EX32(val, PHYMNTNC, PHY_ADDR);
+
+if (phy_addr != s->phy_addr) {
+/* no phy at this address */
+if (FIELD_EX32(val, PHYMNTNC, OP) == MDIO_OP_READ) {
+s->regs[R_PHYMNTNC] = FIELD_DP32(val, PHYMNTNC, DATA, 0x);
+}
+return;
+}
+
+reg_num = FIELD_EX32(val, PHYMNTNC, REG_ADDR);
+
+switch (FIELD_EX32(val, PHYMNTNC, OP)) {
+case MDIO_OP_READ:
+s->regs[R_PHYMNTNC] = FIELD_DP32(val, PHYMNTNC, DATA,
+ gem_phy_read(s, reg_num));
+break;
+
+case MDIO_OP_WRITE:
+gem_phy_write(s, reg_num, val);
+break;
+
+default:
+break; /* only clause 22 operations are supported */
+}
+}
+
 /*
  * gem_read32:
  * Read a GEM register.
  */
 static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
@@ -1539,24 +1571,10 @@ static uint64_t gem_read(void *opaque, hwaddr offset, 
unsigned size)
 switch (offset) {
 case R_ISR:
 DB_PRINT("lowering irqs on ISR read\n");
 /* The interrupts get updated at the end of the function. */
 break;
-case R_PHYMNTNC:
-if (FIELD_EX32(retval, PHYMNTNC, OP) == MDIO_OP_READ) {
-uint32_t phy_addr, reg_num;
-
-phy_addr = FIELD_EX32(retval, PHYMNTNC, PHY_ADDR);
-if (phy_addr == s->phy_addr) {
-reg_num = FIELD_EX32(retval, PHYMNTNC, REG_ADDR);
-retval &= 0x;
-retval |= gem_phy_read(s, reg_num);
-} else {
-retval |= 0x; /* No device at this address */
-}
-}
-break;
 }
 
 /* Squash read to clear bits */
 s->regs[offset] &= ~(s->regs_rtc[offset]);
 
@@ -1663,19 +1681,11 @@ static void gem_write(void *opaque, hwaddr offset, 
uint64_t val,
 case R_SPADDR3HI:
 case R_SPADDR4HI:
 s->sar_active[(offset - R_SPADDR1HI) / 2] = true;
 break;
 case R_PHYMNTNC:
-if (FIELD_EX32(val, PHYMNTNC, OP) == MDIO_OP_WRITE) {
-uint32_t phy_addr, reg_num;
-
-phy_addr = FIELD_EX32(val, PHYMNTNC, PHY_ADDR);
-if (phy_addr == s->phy_addr) {
-reg_num = FIELD_EX32(val, PHYMNTNC, REG_ADDR);
-gem_phy_write(s, reg_num, val);
-}
-}
+gem_handle_phy_access(s);
 break;
 }
 
 DB_PRINT("newval: 0x%08x\n", s->regs[offset]);
 }
-- 
2.39.2




[PATCH 07/11] hw/net/cadence_gem: use FIELD to describe IRQ register fields

2023-10-17 Thread Luc Michel
Use de FIELD macro to describe the IRQ related register fields.

Signed-off-by: Luc Michel 
---
 hw/net/cadence_gem.c | 51 +---
 1 file changed, 39 insertions(+), 12 deletions(-)

diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 0acee1d544..6d084a3b31 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -155,13 +155,46 @@ REG32(RXSTATUS, 0x20) /* RX Status reg */
 FIELD(RXSTATUS, RECEIVE_OVERRUN, 2, 1)
 FIELD(RXSTATUS, FRAME_RECEIVED, 1, 1)
 FIELD(RXSTATUS, BUF_NOT_AVAILABLE, 0, 1)
 
 REG32(ISR, 0x24) /* Interrupt Status reg */
+FIELD(ISR, TX_LOCKUP, 31, 1)
+FIELD(ISR, RX_LOCKUP, 30, 1)
+FIELD(ISR, TSU_TIMER, 29, 1)
+FIELD(ISR, WOL, 28, 1)
+FIELD(ISR, RECV_LPI, 27, 1)
+FIELD(ISR, TSU_SEC_INCR, 26, 1)
+FIELD(ISR, PTP_PDELAY_RESP_XMIT, 25, 1)
+FIELD(ISR, PTP_PDELAY_REQ_XMIT, 24, 1)
+FIELD(ISR, PTP_PDELAY_RESP_RECV, 23, 1)
+FIELD(ISR, PTP_PDELAY_REQ_RECV, 22, 1)
+FIELD(ISR, PTP_SYNC_XMIT, 21, 1)
+FIELD(ISR, PTP_DELAY_REQ_XMIT, 20, 1)
+FIELD(ISR, PTP_SYNC_RECV, 19, 1)
+FIELD(ISR, PTP_DELAY_REQ_RECV, 18, 1)
+FIELD(ISR, PCS_LP_PAGE_RECV, 17, 1)
+FIELD(ISR, PCS_AN_COMPLETE, 16, 1)
+FIELD(ISR, EXT_IRQ, 15, 1)
+FIELD(ISR, PAUSE_FRAME_XMIT, 14, 1)
+FIELD(ISR, PAUSE_TIME_ELAPSED, 13, 1)
+FIELD(ISR, PAUSE_FRAME_RECV, 12, 1)
+FIELD(ISR, RESP_NOT_OK, 11, 1)
+FIELD(ISR, RECV_OVERRUN, 10, 1)
+FIELD(ISR, LINK_CHANGE, 9, 1)
+FIELD(ISR, USXGMII_INT, 8, 1)
+FIELD(ISR, XMIT_COMPLETE, 7, 1)
+FIELD(ISR, AMBA_ERROR, 6, 1)
+FIELD(ISR, RETRY_EXCEEDED, 5, 1)
+FIELD(ISR, XMIT_UNDER_RUN, 4, 1)
+FIELD(ISR, TX_USED, 3, 1)
+FIELD(ISR, RX_USED, 2, 1)
+FIELD(ISR, RECV_COMPLETE, 1, 1)
+FIELD(ISR, MGNT_FRAME_SENT, 0, 1)
 REG32(IER, 0x28) /* Interrupt Enable reg */
 REG32(IDR, 0x2c) /* Interrupt Disable reg */
 REG32(IMR, 0x30) /* Interrupt Mask reg */
+
 REG32(PHYMNTNC, 0x34) /* Phy Maintenance reg */
 REG32(RXPAUSE, 0x38) /* RX Pause Time reg */
 REG32(TXPAUSE, 0x3c) /* TX Pause Time reg */
 REG32(TXPARTIALSF, 0x40) /* TX Partial Store and Forward */
 REG32(RXPARTIALSF, 0x44) /* RX Partial Store and Forward */
@@ -306,16 +339,10 @@ REG32(TYPE2_COMPARE_0_WORD_1, 0x704)
 FIELD(TYPE2_COMPARE_0_WORD_1, COMPARE_VLAN_ID, 10, 1)
 
 /*/
 
 
-/* GEM_ISR GEM_IER GEM_IDR GEM_IMR */
-#define GEM_INT_TXCMPL0x0080 /* Transmit Complete */
-#define GEM_INT_AMBA_ERR  0x0040
-#define GEM_INT_TXUSED 0x0008
-#define GEM_INT_RXUSED 0x0004
-#define GEM_INT_RXCMPL0x0002
 
 #define GEM_PHYMNTNC_OP_R  0x2000 /* read operation */
 #define GEM_PHYMNTNC_OP_W  0x1000 /* write operation */
 #define GEM_PHYMNTNC_ADDR  0x0F80 /* Address bits */
 #define GEM_PHYMNTNC_ADDR_SHFT 23
@@ -1002,11 +1029,11 @@ static void gem_get_rx_desc(CadenceGEMState *s, int q)
 
 /* Descriptor owned by software ? */
 if (rx_desc_get_ownership(s->rx_desc[q]) == 1) {
 DB_PRINT("descriptor 0x%" HWADDR_PRIx " owned by sw.\n", desc_addr);
 s->regs[R_RXSTATUS] |= R_RXSTATUS_BUF_NOT_AVAILABLE_MASK;
-gem_set_isr(s, q, GEM_INT_RXUSED);
+gem_set_isr(s, q, R_ISR_RX_USED_MASK);
 /* Handle interrupt consequences */
 gem_update_int_status(s);
 }
 }
 
@@ -1102,11 +1129,11 @@ static ssize_t gem_receive(NetClientState *nc, const 
uint8_t *buf, size_t size)
 /* Find which queue we are targeting */
 q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize);
 
 if (size > gem_get_max_buf_len(s, false)) {
 qemu_log_mask(LOG_GUEST_ERROR, "rx frame too long\n");
-gem_set_isr(s, q, GEM_INT_AMBA_ERR);
+gem_set_isr(s, q, R_ISR_AMBA_ERROR_MASK);
 return -1;
 }
 
 while (bytes_to_copy) {
 hwaddr desc_addr;
@@ -1179,11 +1206,11 @@ static ssize_t gem_receive(NetClientState *nc, const 
uint8_t *buf, size_t size)
 
 /* Count it */
 gem_receive_updatestats(s, buf, size);
 
 s->regs[R_RXSTATUS] |= R_RXSTATUS_FRAME_RECEIVED_MASK;
-gem_set_isr(s, q, GEM_INT_RXCMPL);
+gem_set_isr(s, q, R_ISR_RECV_COMPLETE_MASK);
 
 /* Handle interrupt consequences */
 gem_update_int_status(s);
 
 return size;
@@ -1292,11 +1319,11 @@ static void gem_transmit(CadenceGEMState *s)
(p - s->tx_packet)) {
 qemu_log_mask(LOG_GUEST_ERROR, "TX descriptor @ 0x%" \
  HWADDR_PRIx " too large: size 0x%x space 0x%zx\n",
  packet_desc_addr, tx_desc_get_length(desc),
  gem_get_max_buf_len(s, true) - (p - s->tx_packet));
-gem_set_isr(s, q, GEM_INT_AMBA_ERR);
+gem_set_isr(s, q, R_ISR_AMBA_ERROR_MASK);
 break;
 }
 
   

[PATCH 06/11] hw/net/cadence_gem: use FIELD to describe [TX|RX]STATUS register fields

2023-10-17 Thread Luc Michel
Use de FIELD macro to describe the TXSTATUS and RXSTATUS register
fields.

Signed-off-by: Luc Michel 
---
 hw/net/cadence_gem.c | 34 +-
 1 file changed, 25 insertions(+), 9 deletions(-)

diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 5c386adff2..0acee1d544 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -130,13 +130,34 @@ REG32(DMACFG, 0x10) /* DMA Control reg */
 FIELD(DMACFG, HDR_DATA_SPLIT_EN, 5, 1)
 FIELD(DMACFG, AMBA_BURST_LEN , 0, 5)
 #define GEM_DMACFG_RBUFSZ_MUL  64 /* DMA RX Buffer Size multiplier */
 
 REG32(TXSTATUS, 0x14) /* TX Status reg */
+FIELD(TXSTATUS, TX_USED_BIT_READ_MIDFRAME, 12, 1)
+FIELD(TXSTATUS, TX_FRAME_TOO_LARGE, 11, 1)
+FIELD(TXSTATUS, TX_DMA_LOCKUP, 10, 1)
+FIELD(TXSTATUS, TX_MAC_LOCKUP, 9, 1)
+FIELD(TXSTATUS, RESP_NOT_OK, 8, 1)
+FIELD(TXSTATUS, LATE_COLLISION, 7, 1)
+FIELD(TXSTATUS, TRANSMIT_UNDER_RUN, 6, 1)
+FIELD(TXSTATUS, TRANSMIT_COMPLETE, 5, 1)
+FIELD(TXSTATUS, AMBA_ERROR, 4, 1)
+FIELD(TXSTATUS, TRANSMIT_GO, 3, 1)
+FIELD(TXSTATUS, RETRY_LIMIT, 2, 1)
+FIELD(TXSTATUS, COLLISION, 1, 1)
+FIELD(TXSTATUS, USED_BIT_READ, 0, 1)
+
 REG32(RXQBASE, 0x18) /* RX Q Base address reg */
 REG32(TXQBASE, 0x1c) /* TX Q Base address reg */
 REG32(RXSTATUS, 0x20) /* RX Status reg */
+FIELD(RXSTATUS, RX_DMA_LOCKUP, 5, 1)
+FIELD(RXSTATUS, RX_MAC_LOCKUP, 4, 1)
+FIELD(RXSTATUS, RESP_NOT_OK, 3, 1)
+FIELD(RXSTATUS, RECEIVE_OVERRUN, 2, 1)
+FIELD(RXSTATUS, FRAME_RECEIVED, 1, 1)
+FIELD(RXSTATUS, BUF_NOT_AVAILABLE, 0, 1)
+
 REG32(ISR, 0x24) /* Interrupt Status reg */
 REG32(IER, 0x28) /* Interrupt Enable reg */
 REG32(IDR, 0x2c) /* Interrupt Disable reg */
 REG32(IMR, 0x30) /* Interrupt Mask reg */
 REG32(PHYMNTNC, 0x34) /* Phy Maintenance reg */
@@ -284,15 +305,10 @@ REG32(TYPE2_COMPARE_0_WORD_1, 0x704)
 FIELD(TYPE2_COMPARE_0_WORD_1, DISABLE_MASK, 9, 1)
 FIELD(TYPE2_COMPARE_0_WORD_1, COMPARE_VLAN_ID, 10, 1)
 
 /*/
 
-#define GEM_TXSTATUS_TXCMPL0x0020 /* Transmit Complete */
-#define GEM_TXSTATUS_USED  0x0001 /* sw owned descriptor encountered */
-
-#define GEM_RXSTATUS_FRMRCVD   0x0002 /* Frame received */
-#define GEM_RXSTATUS_NOBUF 0x0001 /* Buffer unavailable */
 
 /* GEM_ISR GEM_IER GEM_IDR GEM_IMR */
 #define GEM_INT_TXCMPL0x0080 /* Transmit Complete */
 #define GEM_INT_AMBA_ERR  0x0040
 #define GEM_INT_TXUSED 0x0008
@@ -985,11 +1001,11 @@ static void gem_get_rx_desc(CadenceGEMState *s, int q)
sizeof(uint32_t) * gem_get_desc_len(s, true));
 
 /* Descriptor owned by software ? */
 if (rx_desc_get_ownership(s->rx_desc[q]) == 1) {
 DB_PRINT("descriptor 0x%" HWADDR_PRIx " owned by sw.\n", desc_addr);
-s->regs[R_RXSTATUS] |= GEM_RXSTATUS_NOBUF;
+s->regs[R_RXSTATUS] |= R_RXSTATUS_BUF_NOT_AVAILABLE_MASK;
 gem_set_isr(s, q, GEM_INT_RXUSED);
 /* Handle interrupt consequences */
 gem_update_int_status(s);
 }
 }
@@ -1162,11 +1178,11 @@ static ssize_t gem_receive(NetClientState *nc, const 
uint8_t *buf, size_t size)
 }
 
 /* Count it */
 gem_receive_updatestats(s, buf, size);
 
-s->regs[R_RXSTATUS] |= GEM_RXSTATUS_FRMRCVD;
+s->regs[R_RXSTATUS] |= R_RXSTATUS_FRAME_RECEIVED_MASK;
 gem_set_isr(s, q, GEM_INT_RXCMPL);
 
 /* Handle interrupt consequences */
 gem_update_int_status(s);
 
@@ -1313,11 +1329,11 @@ static void gem_transmit(CadenceGEMState *s)
 s->tx_desc_addr[q] = packet_desc_addr +
  4 * gem_get_desc_len(s, false);
 }
 DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]);
 
-s->regs[R_TXSTATUS] |= GEM_TXSTATUS_TXCMPL;
+s->regs[R_TXSTATUS] |= R_TXSTATUS_TRANSMIT_COMPLETE_MASK;
 gem_set_isr(s, q, GEM_INT_TXCMPL);
 
 /* Handle interrupt consequences */
 gem_update_int_status(s);
 
@@ -1361,11 +1377,11 @@ static void gem_transmit(CadenceGEMState *s)
MEMTXATTRS_UNSPECIFIED, desc,
sizeof(uint32_t) * gem_get_desc_len(s, false));
 }
 
 if (tx_desc_get_used(desc)) {
-s->regs[R_TXSTATUS] |= GEM_TXSTATUS_USED;
+s->regs[R_TXSTATUS] |= R_TXSTATUS_USED_BIT_READ_MASK;
 /* IRQ TXUSED is defined only for queue 0 */
 if (q == 0) {
 gem_set_isr(s, 0, GEM_INT_TXUSED);
 }
 gem_update_int_status(s);
-- 
2.39.2




[PATCH 01/11] hw/net/cadence_gem: use REG32 macro for register definitions

2023-10-17 Thread Luc Michel
Replace register defines with the REG32 macro from registerfields.h in
the Cadence GEM device.

Signed-off-by: Luc Michel 
---
 hw/net/cadence_gem.c | 527 +--
 1 file changed, 261 insertions(+), 266 deletions(-)

diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index f445d8bb5e..0e5744ecd7 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -26,10 +26,11 @@
 #include  /* For crc32 */
 
 #include "hw/irq.h"
 #include "hw/net/cadence_gem.h"
 #include "hw/qdev-properties.h"
+#include "hw/registerfields.h"
 #include "migration/vmstate.h"
 #include "qapi/error.h"
 #include "qemu/log.h"
 #include "qemu/module.h"
 #include "sysemu/dma.h"
@@ -42,151 +43,146 @@
 qemu_log(": %s: ", __func__); \
 qemu_log(__VA_ARGS__); \
 } \
 } while (0)
 
-#define GEM_NWCTRL(0x / 4) /* Network Control reg */
-#define GEM_NWCFG (0x0004 / 4) /* Network Config reg */
-#define GEM_NWSTATUS  (0x0008 / 4) /* Network Status reg */
-#define GEM_USERIO(0x000C / 4) /* User IO reg */
-#define GEM_DMACFG(0x0010 / 4) /* DMA Control reg */
-#define GEM_TXSTATUS  (0x0014 / 4) /* TX Status reg */
-#define GEM_RXQBASE   (0x0018 / 4) /* RX Q Base address reg */
-#define GEM_TXQBASE   (0x001C / 4) /* TX Q Base address reg */
-#define GEM_RXSTATUS  (0x0020 / 4) /* RX Status reg */
-#define GEM_ISR   (0x0024 / 4) /* Interrupt Status reg */
-#define GEM_IER   (0x0028 / 4) /* Interrupt Enable reg */
-#define GEM_IDR   (0x002C / 4) /* Interrupt Disable reg */
-#define GEM_IMR   (0x0030 / 4) /* Interrupt Mask reg */
-#define GEM_PHYMNTNC  (0x0034 / 4) /* Phy Maintenance reg */
-#define GEM_RXPAUSE   (0x0038 / 4) /* RX Pause Time reg */
-#define GEM_TXPAUSE   (0x003C / 4) /* TX Pause Time reg */
-#define GEM_TXPARTIALSF   (0x0040 / 4) /* TX Partial Store and Forward */
-#define GEM_RXPARTIALSF   (0x0044 / 4) /* RX Partial Store and Forward */
-#define GEM_JUMBO_MAX_LEN (0x0048 / 4) /* Max Jumbo Frame Size */
-#define GEM_HASHLO(0x0080 / 4) /* Hash Low address reg */
-#define GEM_HASHHI(0x0084 / 4) /* Hash High address reg */
-#define GEM_SPADDR1LO (0x0088 / 4) /* Specific addr 1 low reg */
-#define GEM_SPADDR1HI (0x008C / 4) /* Specific addr 1 high reg */
-#define GEM_SPADDR2LO (0x0090 / 4) /* Specific addr 2 low reg */
-#define GEM_SPADDR2HI (0x0094 / 4) /* Specific addr 2 high reg */
-#define GEM_SPADDR3LO (0x0098 / 4) /* Specific addr 3 low reg */
-#define GEM_SPADDR3HI (0x009C / 4) /* Specific addr 3 high reg */
-#define GEM_SPADDR4LO (0x00A0 / 4) /* Specific addr 4 low reg */
-#define GEM_SPADDR4HI (0x00A4 / 4) /* Specific addr 4 high reg */
-#define GEM_TIDMATCH1 (0x00A8 / 4) /* Type ID1 Match reg */
-#define GEM_TIDMATCH2 (0x00AC / 4) /* Type ID2 Match reg */
-#define GEM_TIDMATCH3 (0x00B0 / 4) /* Type ID3 Match reg */
-#define GEM_TIDMATCH4 (0x00B4 / 4) /* Type ID4 Match reg */
-#define GEM_WOLAN (0x00B8 / 4) /* Wake on LAN reg */
-#define GEM_IPGSTRETCH(0x00BC / 4) /* IPG Stretch reg */
-#define GEM_SVLAN (0x00C0 / 4) /* Stacked VLAN reg */
-#define GEM_MODID (0x00FC / 4) /* Module ID reg */
-#define GEM_OCTTXLO   (0x0100 / 4) /* Octets transmitted Low reg */
-#define GEM_OCTTXHI   (0x0104 / 4) /* Octets transmitted High reg */
-#define GEM_TXCNT (0x0108 / 4) /* Error-free Frames transmitted */
-#define GEM_TXBCNT(0x010C / 4) /* Error-free Broadcast Frames */
-#define GEM_TXMCNT(0x0110 / 4) /* Error-free Multicast Frame */
-#define GEM_TXPAUSECNT(0x0114 / 4) /* Pause Frames Transmitted */
-#define GEM_TX64CNT   (0x0118 / 4) /* Error-free 64 TX */
-#define GEM_TX65CNT   (0x011C / 4) /* Error-free 65-127 TX */
-#define GEM_TX128CNT  (0x0120 / 4) /* Error-free 128-255 TX */
-#define GEM_TX256CNT  (0x0124 / 4) /* Error-free 256-511 */
-#define GEM_TX512CNT  (0x0128 / 4) /* Error-free 512-1023 TX */
-#define GEM_TX1024CNT (0x012C / 4) /* Error-free 1024-1518 TX */
-#define GEM_TX1519CNT (0x0130 / 4) /* Error-free larger than 1519 TX */
-#define GEM_TXURUNCNT (0x0134 / 4) /* TX under run error counter */
-#define GEM_SINGLECOLLCNT (0x0138 / 4) /* Single Collision Frames */
-#define GEM_MULTCOLLCNT   (0x013C / 4) /* Multiple Collision Frames */
-#define GEM_EXCESSCOLLCNT (0x0140 / 4) /* Excessive Collision Frames */
-#define GEM_LATECOLLCNT   (0x0144 / 4) /* Late Collision Frames */
-#define GEM_DEFERTXCNT(0x0148 / 4) /* Deferred Transmission Frames */
-#define GEM_CSENSECNT (0x014C /

[PATCH v2] mailmap: update email addresses for Luc Michel

2023-09-29 Thread Luc Michel
Map my old and now invalid work email addresses to my personal one.

Signed-off-by: Luc Michel 
---
Please ignore v1 sent with wrong e-mail address.
---
 .mailmap | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.mailmap b/.mailmap
index 64ef9f4de6..49f581bafd 100644
--- a/.mailmap
+++ b/.mailmap
@@ -65,10 +65,13 @@ Greg Kurz  
 Huacai Chen  
 Huacai Chen  
 James Hogan  
 Leif Lindholm  
 Leif Lindholm  
+Luc Michel  
+Luc Michel  
+Luc Michel  
 Radoslaw Biernacki  
 Paul Brook  
 Paul Burton  
 Paul Burton  
 Paul Burton  
-- 
2.42.0




Re: [PATCH] MAINTAINERS: update my email address for the clock framework

2023-02-13 Thread Luc Michel
On 10:53 Mon 13 Feb , Damien Hedde wrote:
> Also update mailmap
> 
> Signed-off-by: Damien Hedde 

Reviewed-by: Luc Michel 

> ---
>  MAINTAINERS | 2 +-
>  .mailmap| 1 +
>  2 files changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 96e25f62ac..ceeda49d49 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -3321,7 +3321,7 @@ F: .gitlab-ci.d/opensbi/
> 
>  Clock framework
>  M: Luc Michel 
> -R: Damien Hedde 
> +R: Damien Hedde 
>  S: Maintained
>  F: include/hw/clock.h
>  F: include/hw/qdev-clock.h
> diff --git a/.mailmap b/.mailmap
> index fad2aff5aa..7677047950 100644
> --- a/.mailmap
> +++ b/.mailmap
> @@ -56,6 +56,7 @@ Aleksandar Rikalo  
> 
>  Alexander Graf  
>  Anthony Liguori  Anthony Liguori 
>  Christian Borntraeger  
> +Damien Hedde  
>  Filip Bozuta  
>  Frederic Konrad  
>  Frederic Konrad  
> --
> 2.37.0
> 
> 

-- 



Re: [PATCH v4 27/53] semihosting: Split out semihost_sys_open

2022-06-27 Thread Luc Michel
On 08:05 Wed 22 Jun , Richard Henderson wrote:
> On 6/22/22 02:35, Luc Michel wrote:
> > On 13:45 Tue 07 Jun , Richard Henderson wrote:
> > > Split out the non-ARM specific portions of SYS_OPEN to a
> > > reusable function.  This handles gdb and host file i/o.
> > > 
> > > Add helpers to validate the length of the filename string.
> > > Prepare for usage by other semihosting by allowing the
> > > filename length parameter to be 0, and calling strlen.
> > > 
> > > Signed-off-by: Richard Henderson 
> > > ---
> > >   include/semihosting/syscalls.h |  25 ++
> > >   semihosting/arm-compat-semi.c  |  52 ++-
> > >   semihosting/guestfd.c  |   5 ++
> > >   semihosting/syscalls.c | 156 +
> > >   semihosting/meson.build|   1 +
> > >   5 files changed, 193 insertions(+), 46 deletions(-)
> > >   create mode 100644 include/semihosting/syscalls.h
> > >   create mode 100644 semihosting/syscalls.c
> > > 
> > 
> > [...]
> > 
> > >   } else {
> > > -hostfd = open(s, open_modeflags[arg1], 0644);
> > > -if (hostfd < 0) {
> > > -ret = -1;
> > > -err = errno;
> > > -} else {
> > > -ret = alloc_guestfd();
> > > -associate_guestfd(ret, hostfd);
> > > -    }
> > > +semihost_sys_open(cs, common_semi_cb, arg0, arg2 + 1,
> > > +  gdb_open_modeflags[arg1], 0644);
> > 
> > You're missing a unlock_user(s, arg0, 0); here
> 
> Good catch.  Fixed.

With this fixed:

Reviewed-by: Luc Michel 


> 
> 
> r~
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=3812.62b32fac.79d6c.0=lmichel%40kalray.eu=richard.henderson%40linaro.org=Re%3A+%5BPATCH+v4+27%2F53%5D+semihosting%3A+Split+out+semihost_sys_open=C=588dc0ed7d12e87bd5846dca36ad4d902888f28e
> 

-- 







Re: [PATCH v4 24/53] semihosting: Split out common-semi-target.h

2022-06-27 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Move the ARM and RISCV specific helpers into
> their own header file.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  target/arm/common-semi-target.h   | 62 
>  target/riscv/common-semi-target.h | 50 
>  semihosting/arm-compat-semi.c | 94 +--
>  3 files changed, 113 insertions(+), 93 deletions(-)
>  create mode 100644 target/arm/common-semi-target.h
>  create mode 100644 target/riscv/common-semi-target.h
> 
> diff --git a/target/arm/common-semi-target.h b/target/arm/common-semi-target.h
> new file mode 100644
> index 00..629d75ca5a
> --- /dev/null
> +++ b/target/arm/common-semi-target.h
> @@ -0,0 +1,62 @@
> +/*
> + * Target-specific parts of semihosting/arm-compat-semi.c.
> + *
> + * Copyright (c) 2005, 2007 CodeSourcery.
> + * Copyright (c) 2019, 2022 Linaro
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef TARGET_ARM_COMMON_SEMI_TARGET_H
> +#define TARGET_ARM_COMMON_SEMI_TARGET_H
> +
> +#ifndef CONFIG_USER_ONLY
> +#include "hw/arm/boot.h"
> +#endif
> +
> +static inline target_ulong common_semi_arg(CPUState *cs, int argno)
> +{
> +ARMCPU *cpu = ARM_CPU(cs);
> +CPUARMState *env = >env;
> +if (is_a64(env)) {
> +return env->xregs[argno];
> +} else {
> +return env->regs[argno];
> +}
> +}
> +
> +static inline void common_semi_set_ret(CPUState *cs, target_ulong ret)
> +{
> +ARMCPU *cpu = ARM_CPU(cs);
> +CPUARMState *env = >env;
> +if (is_a64(env)) {
> +env->xregs[0] = ret;
> +} else {
> +env->regs[0] = ret;
> +}
> +}
> +
> +static inline bool common_semi_sys_exit_extended(CPUState *cs, int nr)
> +{
> +return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
> +}
> +
> +static inline bool is_64bit_semihosting(CPUArchState *env)
> +{
> +return is_a64(env);
> +}
> +
> +static inline target_ulong common_semi_stack_bottom(CPUState *cs)
> +{
> +ARMCPU *cpu = ARM_CPU(cs);
> +CPUARMState *env = >env;
> +return is_a64(env) ? env->xregs[31] : env->regs[13];
> +}
> +
> +static inline bool common_semi_has_synccache(CPUArchState *env)
> +{
> +/* Ok for A64, invalid for A32/T32 */
> +return is_a64(env);
> +}
> +
> +#endif
> diff --git a/target/riscv/common-semi-target.h 
> b/target/riscv/common-semi-target.h
> new file mode 100644
> index 00..7c8a59e0cc
> --- /dev/null
> +++ b/target/riscv/common-semi-target.h
> @@ -0,0 +1,50 @@
> +/*
> + * Target-specific parts of semihosting/arm-compat-semi.c.
> + *
> + * Copyright (c) 2005, 2007 CodeSourcery.
> + * Copyright (c) 2019, 2022 Linaro
> + * Copyright © 2020 by Keith Packard 
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef TARGET_RISCV_COMMON_SEMI_TARGET_H
> +#define TARGET_RISCV_COMMON_SEMI_TARGET_H
> +
> +static inline target_ulong common_semi_arg(CPUState *cs, int argno)
> +{
> +RISCVCPU *cpu = RISCV_CPU(cs);
> +CPURISCVState *env = >env;
> +return env->gpr[xA0 + argno];
> +}
> +
> +static inline void common_semi_set_ret(CPUState *cs, target_ulong ret)
> +{
> +RISCVCPU *cpu = RISCV_CPU(cs);
> +CPURISCVState *env = >env;
> +env->gpr[xA0] = ret;
> +}
> +
> +static inline bool common_semi_sys_exit_extended(CPUState *cs, int nr)
> +{
> +return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8);
> +}
> +
> +static inline bool is_64bit_semihosting(CPUArchState *env)
> +{
> +return riscv_cpu_mxl(env) != MXL_RV32;
> +}
> +
> +static inline target_ulong common_semi_stack_bottom(CPUState *cs)
> +{
> +RISCVCPU *cpu = RISCV_CPU(cs);
> +CPURISCVState *env = >env;
> +return env->gpr[xSP];
> +}
> +
> +static inline bool common_semi_has_synccache(CPUArchState *env)
> +{
> +return true;
> +}
> +
> +#endif
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index 50f40a2a1a..5e442e549d 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -46,9 +46,6 @@
>  #else
>  #include "qemu/cutils.h"
>  #include "hw/loader.h"
> -#ifdef TARGET_ARM
> -#include "hw/arm/boot.h"
> -#endif
>  #include "hw/boards.h"
>  #endif
>  
> @@ -182,96 +179,7 @@ static LayoutInfo common_semi_find_bases(CPUState *cs)
>  
>  #endif
>  
> -#ifdef TARGET_ARM
> -static inline target_ulong
> -common_semi_arg(CPU

Re: [PATCH v4 53/53] semihosting: Create semihost_sys_poll_one

2022-06-27 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> This will be used for implementing the xtensa select_one
> system call.  Choose "poll" over "select" so that we can
> reuse Glib's g_poll constants and to avoid struct timeval.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/console.h  | 16 
>  include/semihosting/syscalls.h |  3 ++
>  semihosting/console.c  | 19 -
>  semihosting/syscalls.c | 70 ++
>  4 files changed, 106 insertions(+), 2 deletions(-)
> 
> diff --git a/include/semihosting/console.h b/include/semihosting/console.h
> index 20c31d89d4..61b0cb3a94 100644
> --- a/include/semihosting/console.h
> +++ b/include/semihosting/console.h
> @@ -53,4 +53,20 @@ int qemu_semihosting_console_write(void *buf, int len);
>   */
>  int qemu_semihosting_log_out(const char *s, int len);
>  
> +/*
> + * qemu_semihosting_console_block_until_ready:
> + * @cs: CPUState
> + *
> + * If no data is available we suspend the CPU and will re-execute the
> + * instruction when data is available.
> + */
> +void qemu_semihosting_console_block_until_ready(CPUState *cs);
> +
> +/**
> + * qemu_semihosting_console_ready:
> + *
> + * Return true if characters are available for read; does not block.
> + */
> +bool qemu_semihosting_console_ready(void);
> +
>  #endif /* SEMIHOST_CONSOLE_H */
> diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
> index 347200cb9f..3a5ec229eb 100644
> --- a/include/semihosting/syscalls.h
> +++ b/include/semihosting/syscalls.h
> @@ -69,4 +69,7 @@ void semihost_sys_system(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb 
> complete,
> target_ulong tv_addr, target_ulong tz_addr);
>  
> +void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
> +   int fd, GIOCondition cond, int timeout);
> +
>  #endif /* SEMIHOSTING_SYSCALLS_H */
> diff --git a/semihosting/console.c b/semihosting/console.c
> index c84ab97ab6..cda7cf1905 100644
> --- a/semihosting/console.c
> +++ b/semihosting/console.c
> @@ -77,10 +77,17 @@ static void console_read(void *opaque, const uint8_t 
> *buf, int size)
>  c->sleeping_cpus = NULL;
>  }
>  
> -int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
> +bool qemu_semihosting_console_ready(void)
> +{
> +SemihostingConsole *c = 
> +
> +g_assert(qemu_mutex_iothread_locked());
> +return !fifo8_is_empty(>fifo);
> +}
> +
> +void qemu_semihosting_console_block_until_ready(CPUState *cs)
>  {
>  SemihostingConsole *c = 
> -int ret = 0;
>  
>  g_assert(qemu_mutex_iothread_locked());
>  
> @@ -92,6 +99,14 @@ int qemu_semihosting_console_read(CPUState *cs, void *buf, 
> int len)
>  cpu_loop_exit(cs);
>  /* never returns */
>  }
> +}
> +
> +int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
> +{
> +SemihostingConsole *c = 
> +int ret = 0;
> +
> +qemu_semihosting_console_block_until_ready(cs);
>  
>  /* Read until buffer full or fifo exhausted. */
>  do {
> diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
> index 9e499b1751..4847f66c02 100644
> --- a/semihosting/syscalls.c
> +++ b/semihosting/syscalls.c
> @@ -520,6 +520,21 @@ static void host_gettimeofday(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  unlock_user(p, tv_addr, sizeof(struct gdb_timeval));
>  }
>  
> +#ifndef CONFIG_USER_ONLY
> +static void host_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
> +  GuestFD *gf, GIOCondition cond, int timeout)
> +{
> +/*
> + * Since this is only used by xtensa in system mode, and stdio is
> + * handled through GuestFDConsole, and there are no semihosting
> + * system calls for sockets and the like, that means this descriptor
> + * must be a normal file.  Normal files never block and are thus
> + * always ready.
> + */
> +complete(cs, cond & (G_IO_IN | G_IO_OUT), 0);
> +}
> +#endif
> +
>  /*
>   * Static file semihosting syscall implementations.
>   */
> @@ -628,6 +643,34 @@ static void console_fstat(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  complete(cs, ret ? -1 : 0, ret ? -ret : 0);
>  }
>  
> +#ifndef CONFIG_USER_ONLY
> +static void console_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
> + GuestFD *gf, GIOCondition cond, int timeout)
> +{
> +/* The semihosting con

Re: [PATCH v4 51/53] semihosting: Use console_out_gf for SYS_WRITE0

2022-06-27 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  semihosting/arm-compat-semi.c | 11 +--
>  1 file changed, 9 insertions(+), 2 deletions(-)
> 
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index dea5b2de8d..21b6bc3a0f 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -436,8 +436,15 @@ void do_common_semihosting(CPUState *cs)
>  break;
>  
>  case TARGET_SYS_WRITE0:
> -ret = qemu_semihosting_console_outs(env, args);
> -common_semi_set_ret(cs, ret);
> +{
> +ssize_t len = target_strlen(args);
> +if (len < 0) {
> +common_semi_dead_cb(cs, -1, EFAULT);
> +} else {
> +semihost_sys_write_gf(cs, common_semi_dead_cb,
> +  _out_gf, args, len);
> +}
> +}
>  break;
>  
>  case TARGET_SYS_WRITE:
> -- 
> 2.34.1
> 
> 
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=c4ea.629fd73d.b3ca0.0=lmichel%40kalrayinc.com=qemu-devel-bounces%2Blmichel%3Dkalrayinc.com%40nongnu.org=%5BPATCH+v4+51%2F53%5D+semihosting%3A+Use+console_out_gf+for+SYS_WRITE0=C=a15d92901bee73eeb1fb2b2232be37c9cb5356be
> 

-- 







Re: [PATCH v4 52/53] semihosting: Remove qemu_semihosting_console_outs

2022-06-27 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> This function has been replaced by *_write.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/console.h | 13 --
>  linux-user/semihost.c | 17 
>  semihosting/console.c | 49 ---
>  3 files changed, 79 deletions(-)
> 
> diff --git a/include/semihosting/console.h b/include/semihosting/console.h
> index d6c1cc58ab..20c31d89d4 100644
> --- a/include/semihosting/console.h
> +++ b/include/semihosting/console.h
> @@ -11,19 +11,6 @@
>  
>  #include "cpu.h"
>  
> -/**
> - * qemu_semihosting_console_outs:
> - * @env: CPUArchState
> - * @s: host address of null terminated guest string
> - *
> - * Send a null terminated guest string to the debug console. This may
> - * be the remote gdb session if a softmmu guest is currently being
> - * debugged.
> - *
> - * Returns: number of bytes written.
> - */
> -int qemu_semihosting_console_outs(CPUArchState *env, target_ulong s);
> -
>  /**
>   * qemu_semihosting_console_read:
>   * @cs: CPUState
> diff --git a/linux-user/semihost.c b/linux-user/semihost.c
> index f8bc8889f3..cee62a365c 100644
> --- a/linux-user/semihost.c
> +++ b/linux-user/semihost.c
> @@ -16,23 +16,6 @@
>  #include "user-internals.h"
>  #include 
>  
> -int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr)
> -{
> -int len = target_strlen(addr);
> -void *s;
> -if (len < 0){
> -   qemu_log_mask(LOG_GUEST_ERROR,
> - "%s: passed inaccessible address " TARGET_FMT_lx,
> - __func__, addr);
> -   return 0;
> -}
> -s = lock_user(VERIFY_READ, addr, (long)(len + 1), 1);
> -g_assert(s);  /* target_strlen has already verified this will work */
> -len = write(STDERR_FILENO, s, len);
> -unlock_user(s, addr, 0);
> -return len;
> -}
> -
>  /*
>   * For linux-user we can safely block. However as we want to return as
>   * soon as a character is read we need to tweak the termio to disable
> diff --git a/semihosting/console.c b/semihosting/console.c
> index f6fab5933a..c84ab97ab6 100644
> --- a/semihosting/console.c
> +++ b/semihosting/console.c
> @@ -47,55 +47,6 @@ int qemu_semihosting_log_out(const char *s, int len)
>  }
>  }
>  
> -/*
> - * A re-implementation of lock_user_string that we can use locally
> - * instead of relying on softmmu-semi. Hopefully we can deprecate that
> - * in time. Copy string until we find a 0 or address error.
> - */
> -static GString *copy_user_string(CPUArchState *env, target_ulong addr)
> -{
> -CPUState *cpu = env_cpu(env);
> -GString *s = g_string_sized_new(128);
> -uint8_t c;
> -
> -do {
> -if (cpu_memory_rw_debug(cpu, addr++, , 1, 0) == 0) {
> -if (c) {
> -s = g_string_append_c(s, c);
> -}
> -} else {
> -qemu_log_mask(LOG_GUEST_ERROR,
> -  "%s: passed inaccessible address " TARGET_FMT_lx,
> -  __func__, addr);
> -break;
> -}
> -} while (c!=0);
> -
> -return s;
> -}
> -
> -static void semihosting_cb(CPUState *cs, uint64_t ret, int err)
> -{
> -if (err) {
> -qemu_log("%s: gdb console output failed (%d)", __func__, err);
> -}
> -}
> -
> -int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr)
> -{
> -GString *s = copy_user_string(env, addr);
> -int out = s->len;
> -
> -if (use_gdb_syscalls()) {
> -gdb_do_syscall(semihosting_cb, "write,2,%x,%x", addr, s->len);
> -} else {
> -out = qemu_semihosting_log_out(s->str, s->len);
> -}
> -
> -g_string_free(s, true);
> -return out;
> -}
> -
>  #define FIFO_SIZE   1024
>  
>  static int console_can_read(void *opaque)
> -- 
> 2.34.1
> 
> 
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=29a4.629fd909.2884b.0=lmichel%40kalrayinc.com=qemu-devel-bounces%2Blmichel%3Dkalrayinc.com%40nongnu.org=%5BPATCH+v4+52%2F53%5D+semihosting%3A+Remove+qemu_semihosting_console_outs=C=8ee0b8982c8025f3b6af275d795772fa0673b149
> 

-- 







Re: [PATCH v4 50/53] semihosting: Remove qemu_semihosting_console_outc

2022-06-27 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> This function has been replaced by *_write.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/console.h | 13 -
>  linux-user/semihost.c | 16 
>  semihosting/console.c | 18 --
>  3 files changed, 47 deletions(-)
> 
> diff --git a/include/semihosting/console.h b/include/semihosting/console.h
> index 6994f23c82..d6c1cc58ab 100644
> --- a/include/semihosting/console.h
> +++ b/include/semihosting/console.h
> @@ -24,19 +24,6 @@
>   */
>  int qemu_semihosting_console_outs(CPUArchState *env, target_ulong s);
>  
> -/**
> - * qemu_semihosting_console_outc:
> - * @env: CPUArchState
> - * @s: host address of null terminated guest string
> - *
> - * Send single character from guest memory to the debug console. This
> - * may be the remote gdb session if a softmmu guest is currently being
> - * debugged.
> - *
> - * Returns: nothing
> - */
> -void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c);
> -
>  /**
>   * qemu_semihosting_console_read:
>   * @cs: CPUState
> diff --git a/linux-user/semihost.c b/linux-user/semihost.c
> index 871edf993a..f8bc8889f3 100644
> --- a/linux-user/semihost.c
> +++ b/linux-user/semihost.c
> @@ -33,22 +33,6 @@ int qemu_semihosting_console_outs(CPUArchState *env, 
> target_ulong addr)
>  return len;
>  }
>  
> -void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
> -{
> -char c;
> -
> -if (get_user_u8(c, addr)) {
> -qemu_log_mask(LOG_GUEST_ERROR,
> -  "%s: passed inaccessible address " TARGET_FMT_lx,
> -  __func__, addr);
> -} else {
> -if (write(STDERR_FILENO, , 1) != 1) {
> -qemu_log_mask(LOG_UNIMP, "%s: unexpected write to stdout 
> failure",
> -  __func__);
> -}
> -}
> -}
> -
>  /*
>   * For linux-user we can safely block. However as we want to return as
>   * soon as a character is read we need to tweak the termio to disable
> diff --git a/semihosting/console.c b/semihosting/console.c
> index 677ec2b176..f6fab5933a 100644
> --- a/semihosting/console.c
> +++ b/semihosting/console.c
> @@ -96,24 +96,6 @@ int qemu_semihosting_console_outs(CPUArchState *env, 
> target_ulong addr)
>  return out;
>  }
>  
> -void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
> -{
> -CPUState *cpu = env_cpu(env);
> -uint8_t c;
> -
> -if (cpu_memory_rw_debug(cpu, addr, , 1, 0) == 0) {
> -if (use_gdb_syscalls()) {
> -gdb_do_syscall(semihosting_cb, "write,2,%x,%x", addr, 1);
> -} else {
> -qemu_semihosting_log_out((const char *) , 1);
> -}
> -} else {
> -qemu_log_mask(LOG_GUEST_ERROR,
> -  "%s: passed inaccessible address " TARGET_FMT_lx,
> -  __func__, addr);
> -}
> -}
> -
>  #define FIFO_SIZE   1024
>  
>  static int console_can_read(void *opaque)
> -- 
> 2.34.1
> 
> 
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=17199.629fd830.873a5.0=lmichel%40kalrayinc.com=qemu-devel-bounces%2Blmichel%3Dkalrayinc.com%40nongnu.org=%5BPATCH+v4+50%2F53%5D+semihosting%3A+Remove+qemu_semihosting_console_outc=C=17fd1d8aafc59b73861d5d8e80dfec815f24e02d
> 

-- 







Re: [PATCH v4 49/53] semihosting: Use console_out_gf for SYS_WRITEC

2022-06-27 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  semihosting/arm-compat-semi.c | 20 
>  1 file changed, 16 insertions(+), 4 deletions(-)
> 
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index 4c8932ad54..dea5b2de8d 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -228,6 +228,15 @@ static void common_semi_cb(CPUState *cs, uint64_t ret, 
> int err)
>  common_semi_set_ret(cs, ret);
>  }
>  
> +/*
> + * Use 0xdeadbeef as the return value when there isn't a defined
> + * return value for the call.
> + */
> +static void common_semi_dead_cb(CPUState *cs, uint64_t ret, int err)
> +{
> +common_semi_set_ret(cs, 0xdeadbeef);
> +}
> +
>  /*
>   * SYS_READ and SYS_WRITE always return the number of bytes not read/written.
>   * There is no error condition, other than returning the original length.
> @@ -341,8 +350,7 @@ static const uint8_t featurefile_data[] = {
>   * The specification always says that the "return register" either
>   * returns a specific value or is corrupted, so we don't need to
>   * report to our caller whether we are returning a value or trying to
> - * leave the register unchanged. We use 0xdeadbeef as the return value
> - * when there isn't a defined return value for the call.
> + * leave the register unchanged.
>   */
>  void do_common_semihosting(CPUState *cs)
>  {
> @@ -419,8 +427,12 @@ void do_common_semihosting(CPUState *cs)
>  break;
>  
>  case TARGET_SYS_WRITEC:
> -qemu_semihosting_console_outc(env, args);
> -common_semi_set_ret(cs, 0xdeadbeef);
> +/*
> + * FIXME: the byte to be written is in a target_ulong slot,
> + * which means this is wrong for a big-endian guest.
> + */
> +semihost_sys_write_gf(cs, common_semi_dead_cb,
> +  _out_gf, args, 1);
>  break;
>  
>  case TARGET_SYS_WRITE0:
> -- 
> 2.34.1
> 
> 
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=1578f.629fd28e.3eb4d.0=lmichel%40kalrayinc.com=qemu-devel-bounces%2Blmichel%3Dkalrayinc.com%40nongnu.org=%5BPATCH+v4+49%2F53%5D+semihosting%3A+Use+console_out_gf+for+SYS_WRITEC=C=9f59ee0c491343fa50053073959ee288e2920868
> 

-- 







Re: [PATCH v4 48/53] semihosting: Use console_in_gf for SYS_READC

2022-06-27 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  semihosting/arm-compat-semi.c | 27 ++-
>  1 file changed, 18 insertions(+), 9 deletions(-)
> 
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index 20e99cdcc0..4c8932ad54 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -302,6 +302,22 @@ common_semi_flen_fstat_cb(CPUState *cs, uint64_t ret, 
> int err)
>  common_semi_cb(cs, ret, err);
>  }
>  
> +static void
> +common_semi_readc_cb(CPUState *cs, uint64_t ret, int err)
> +{
> +if (!err) {
> +CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
> +uint8_t ch;
> +
> +if (get_user_u8(ch, common_semi_stack_bottom(cs) - 1)) {
> +ret = -1, err = EFAULT;
> +} else {
> +ret = ch;
> +}
> +}
> +common_semi_cb(cs, ret, err);
> +}
> +
>  #define SHFB_MAGIC_0 0x53
>  #define SHFB_MAGIC_1 0x48
>  #define SHFB_MAGIC_2 0x46
> @@ -427,15 +443,8 @@ void do_common_semihosting(CPUState *cs)
>  break;
>  
>  case TARGET_SYS_READC:
> -{
> -uint8_t ch;
> -int ret = qemu_semihosting_console_read(cs, , 1);
> -if (ret == 1) {
> -common_semi_cb(cs, ch, 0);
> -} else {
> -common_semi_cb(cs, -1, EIO);
> -}
> -}
> +semihost_sys_read_gf(cs, common_semi_readc_cb, _in_gf,
> + common_semi_stack_bottom(cs) - 1, 1);
>  break;
>  
>  case TARGET_SYS_ISERROR:
> -- 
> 2.34.1
> 
> 
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=1799d.629fd6b1.98b43.0=lmichel%40kalrayinc.com=qemu-devel-bounces%2Blmichel%3Dkalrayinc.com%40nongnu.org=%5BPATCH+v4+48%2F53%5D+semihosting%3A+Use+console_in_gf+for+SYS_READC=C=b9cfba5cbbf5d995e5235734d7ab1a5181b14825
> 

-- 







Re: [PATCH v4 47/53] semihosting: Create qemu_semihosting_guestfd_init

2022-06-27 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> For arm-compat, initialize console_{in,out}_gf;
> otherwise, initialize stdio file descriptors.
> 
> This will go some way to cleaning up arm-compat, and
> will allow other semihosting to use normal stdio.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/guestfd.h  |  7 +
>  include/semihosting/semihost.h |  1 +
>  linux-user/main.c  |  9 ++
>  semihosting/console.c  |  2 ++
>  semihosting/guestfd.c  | 52 +++---
>  5 files changed, 61 insertions(+), 10 deletions(-)
> 
> diff --git a/include/semihosting/guestfd.h b/include/semihosting/guestfd.h
> index a7ea1041ea..3d426fedab 100644
> --- a/include/semihosting/guestfd.h
> +++ b/include/semihosting/guestfd.h
> @@ -35,6 +35,13 @@ typedef struct GuestFD {
>  };
>  } GuestFD;
>  
> +/*
> + * For ARM semihosting, we have a separate structure for routing
> + * data for the console which is outside the guest fd address space.
> + */
> +extern GuestFD console_in_gf;
> +extern GuestFD console_out_gf;
> +
>  /**
>   * alloc_guestfd:
>   *
> diff --git a/include/semihosting/semihost.h b/include/semihosting/semihost.h
> index 5b36a76f08..93a3c21b44 100644
> --- a/include/semihosting/semihost.h
> +++ b/include/semihosting/semihost.h
> @@ -64,5 +64,6 @@ int qemu_semihosting_config_options(const char *opt);
>  void qemu_semihosting_chardev_init(void);
>  void qemu_semihosting_console_init(Chardev *);
>  #endif /* CONFIG_USER_ONLY */
> +void qemu_semihosting_guestfd_init(void);
>  
>  #endif /* SEMIHOST_H */
> diff --git a/linux-user/main.c b/linux-user/main.c
> index 651e32f5f2..e44bdb17b8 100644
> --- a/linux-user/main.c
> +++ b/linux-user/main.c
> @@ -54,6 +54,10 @@
>  #include "loader.h"
>  #include "user-mmap.h"
>  
> +#ifdef CONFIG_SEMIHOSTING
> +#include "semihosting/semihost.h"
> +#endif
> +
>  #ifndef AT_FLAGS_PRESERVE_ARGV0
>  #define AT_FLAGS_PRESERVE_ARGV0_BIT 0
>  #define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
> @@ -906,6 +910,11 @@ int main(int argc, char **argv, char **envp)
>  }
>  gdb_handlesig(cpu, 0);
>  }
> +
> +#ifdef CONFIG_SEMIHOSTING
> +qemu_semihosting_guestfd_init();
> +#endif
> +
>  cpu_loop(env);
>  /* never exits */
>  return 0;
> diff --git a/semihosting/console.c b/semihosting/console.c
> index b6a342744d..677ec2b176 100644
> --- a/semihosting/console.c
> +++ b/semihosting/console.c
> @@ -190,4 +190,6 @@ void qemu_semihosting_console_init(Chardev *chr)
>   NULL, NULL, ,
>   NULL, true);
>  }
> +
> +qemu_semihosting_guestfd_init();
>  }
> diff --git a/semihosting/guestfd.c b/semihosting/guestfd.c
> index e3122ebba9..b05c52f26f 100644
> --- a/semihosting/guestfd.c
> +++ b/semihosting/guestfd.c
> @@ -10,15 +10,56 @@
>  
>  #include "qemu/osdep.h"
>  #include "exec/gdbstub.h"
> +#include "semihosting/semihost.h"
>  #include "semihosting/guestfd.h"
>  #ifdef CONFIG_USER_ONLY
>  #include "qemu.h"
>  #else
>  #include "semihosting/softmmu-uaccess.h"
> +#include CONFIG_DEVICES
>  #endif
>  
>  static GArray *guestfd_array;
>  
> +#ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
> +GuestFD console_in_gf;
> +GuestFD console_out_gf;
> +#endif
> +
> +void qemu_semihosting_guestfd_init(void)
> +{
> +/* New entries zero-initialized, i.e. type GuestFDUnused */
> +guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
> +
> +#ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
> +/* For ARM-compat, the console is in a separate namespace. */
> +if (use_gdb_syscalls()) {
> +console_in_gf.type = GuestFDGDB;
> +console_in_gf.hostfd = 0;
> +console_out_gf.type = GuestFDGDB;
> +console_out_gf.hostfd = 2;
> +} else {
> +console_in_gf.type = GuestFDConsole;
> +console_out_gf.type = GuestFDConsole;
> +}
> +#else
> +/* Otherwise, the stdio file descriptors apply. */
> +guestfd_array = g_array_set_size(guestfd_array, 3);
> +#ifndef CONFIG_USER_ONLY
> +if (!use_gdb_syscalls()) {
> +GuestFD *gf = _array_index(guestfd_array, GuestFD, 0);
> +gf[0].type = GuestFDConsole;
> +gf[1].type = GuestFDConsole;
> +gf[2].type = GuestFDConsole;
> +return;
> +}
> +#endif
> +associate_guestfd(0, 0);
> +associate_guestfd(1, 1);
> +associate_guestfd(2, 2);
> +#endif
&g

Re: [PATCH v4 46/53] semihosting: Add GuestFDConsole

2022-06-27 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Add a GuestFDType for connecting to the semihosting console.
> Hook up to read, write, isatty, and fstat syscalls.
> 
> Note that the arm-specific syscall flen cannot be applied
> to the console, because the console is not a descriptor
> exposed to the guest.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/guestfd.h |  7 ++--
>  semihosting/syscalls.c| 68 +++
>  2 files changed, 72 insertions(+), 3 deletions(-)
> 
> diff --git a/include/semihosting/guestfd.h b/include/semihosting/guestfd.h
> index ef268abe85..a7ea1041ea 100644
> --- a/include/semihosting/guestfd.h
> +++ b/include/semihosting/guestfd.h
> @@ -13,9 +13,10 @@
>  
>  typedef enum GuestFDType {
>  GuestFDUnused = 0,
> -GuestFDHost = 1,
> -GuestFDGDB = 2,
> -GuestFDStatic = 3,
> +GuestFDHost,
> +GuestFDGDB,
> +GuestFDStatic,
> +GuestFDConsole,
>  } GuestFDType;
>  
>  /*
> diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
> index 13a9bdeda6..9e499b1751 100644
> --- a/semihosting/syscalls.c
> +++ b/semihosting/syscalls.c
> @@ -10,6 +10,7 @@
>  #include "exec/gdbstub.h"
>  #include "semihosting/guestfd.h"
>  #include "semihosting/syscalls.h"
> +#include "semihosting/console.h"
>  #ifdef CONFIG_USER_ONLY
>  #include "qemu.h"
>  #else
> @@ -577,6 +578,56 @@ static void staticfile_flen(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  complete(cs, gf->staticfile.len, 0);
>  }
>  
> +/*
> + * Console semihosting syscall implementations.
> + */
> +
> +static void console_read(CPUState *cs, gdb_syscall_complete_cb complete,
> + GuestFD *gf, target_ulong buf, target_ulong len)
> +{
> +CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
> +char *ptr;
> +int ret;
> +
> +ptr = lock_user(VERIFY_WRITE, buf, len, 0);
> +if (!ptr) {
> +complete(cs, -1, EFAULT);
> +return;
> +}
> +ret = qemu_semihosting_console_read(cs, ptr, len);
> +complete(cs, ret, 0);
> +unlock_user(ptr, buf, ret);
> +}
> +
> +static void console_write(CPUState *cs, gdb_syscall_complete_cb complete,
> +  GuestFD *gf, target_ulong buf, target_ulong len)
> +{
> +CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
> +char *ptr = lock_user(VERIFY_READ, buf, len, 1);
> +int ret;
> +
> +if (!ptr) {
> +complete(cs, -1, EFAULT);
> +return;
> +}
> +ret = qemu_semihosting_console_write(ptr, len);
> +complete(cs, ret ? ret : -1, ret ? 0 : EIO);
> +unlock_user(ptr, buf, ret);
> +}
> +
> +static void console_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
> +  GuestFD *gf, target_ulong addr)
> +{
> +static const struct stat tty_buf = {
> +.st_mode = 020666,  /* S_IFCHR, ugo+rw */
> +.st_rdev = 5,   /* makedev(5, 0) -- linux /dev/tty */
> +};
> +int ret;
> +
> +ret = copy_stat_to_user(cs, addr, _buf);
> +complete(cs, ret ? -1 : 0, ret ? -ret : 0);
> +}
> +
>  /*
>   * Syscall entry points.
>   */
> @@ -608,6 +659,7 @@ void semihost_sys_close(CPUState *cs, 
> gdb_syscall_complete_cb complete, int fd)
>  host_close(cs, complete, gf);
>  break;
>  case GuestFDStatic:
> +case GuestFDConsole:
>  complete(cs, 0, 0);
>  break;
>  default:
> @@ -637,6 +689,9 @@ void semihost_sys_read_gf(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  case GuestFDStatic:
>  staticfile_read(cs, complete, gf, buf, len);
>  break;
> +case GuestFDConsole:
> +console_read(cs, complete, gf, buf, len);
> +break;
>  default:
>  g_assert_not_reached();
>  }
> @@ -672,6 +727,9 @@ void semihost_sys_write_gf(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  case GuestFDHost:
>  host_write(cs, complete, gf, buf, len);
>  break;
> +case GuestFDConsole:
> +console_write(cs, complete, gf, buf, len);
> +break;
>  case GuestFDStatic:
>  /* Static files are never open for writing: EBADF. */
>  complete(cs, -1, EBADF);
> @@ -712,6 +770,9 @@ void semihost_sys_lseek(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  case GuestFDStatic:
>  staticfile_lseek(cs, complete, gf, off, gdb_whence);
>  break;
> +case GuestFDConsole:
> +complete(cs, -1, ESPIPE);
> +break;
>  de

Re: [PATCH v4 45/53] semihosting: Create qemu_semihosting_console_write

2022-06-27 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Will replace qemu_semihosting_console_{outs,outc},
> but we need more plumbing first.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/console.h | 12 
>  linux-user/semihost.c |  5 +
>  semihosting/console.c |  9 +
>  3 files changed, 26 insertions(+)
> 
> diff --git a/include/semihosting/console.h b/include/semihosting/console.h
> index 39dbf1b062..6994f23c82 100644
> --- a/include/semihosting/console.h
> +++ b/include/semihosting/console.h
> @@ -54,6 +54,18 @@ void qemu_semihosting_console_outc(CPUArchState *env, 
> target_ulong c);
>   */
>  int qemu_semihosting_console_read(CPUState *cs, void *buf, int len);
>  
> +/**
> + * qemu_semihosting_console_write:
> + * @buf: host buffer
> + * @len: buffer size
> + *
> + * Write len bytes from buf to the debug console.
> + *
> + * Returns: number of bytes written -- this should only ever be short
> + * on some sort of i/o error.
> + */
> +int qemu_semihosting_console_write(void *buf, int len);
> +
>  /**
>   * qemu_semihosting_log_out:
>   * @s: pointer to string
> diff --git a/linux-user/semihost.c b/linux-user/semihost.c
> index 2029fb674c..871edf993a 100644
> --- a/linux-user/semihost.c
> +++ b/linux-user/semihost.c
> @@ -76,3 +76,8 @@ int qemu_semihosting_console_read(CPUState *cs, void *buf, 
> int len)
>  
>  return ret;
>  }
> +
> +int qemu_semihosting_console_write(void *buf, int len)
> +{
> +return fwrite(buf, 1, len, stderr);
> +}
> diff --git a/semihosting/console.c b/semihosting/console.c
> index 4088192842..b6a342744d 100644
> --- a/semihosting/console.c
> +++ b/semihosting/console.c
> @@ -169,6 +169,15 @@ int qemu_semihosting_console_read(CPUState *cs, void 
> *buf, int len)
>  return ret;
>  }
>  
> +int qemu_semihosting_console_write(void *buf, int len)
> +{
> +if (console.chr) {
> +return qemu_chr_write_all(console.chr, (uint8_t *)buf, len);
> +} else {
> +return fwrite(buf, 1, len, stderr);
> +}
> +}
> +
>  void qemu_semihosting_console_init(Chardev *chr)
>  {
>  console.chr = chr;
> -- 
> 2.34.1
> 
> 
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=17cb8.629fd4d3.e3b54.0=lmichel%40kalrayinc.com=qemu-devel-bounces%2Blmichel%3Dkalrayinc.com%40nongnu.org=%5BPATCH+v4+45%2F53%5D+semihosting%3A+Create+qemu_semihosting_console_write=C=62fc4b596a4980c709b5ba86793f19d99fbc6d6f
> 

-- 







Re: [PATCH v4 44/53] semihosting: Cleanup chardev init

2022-06-24 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Rename qemu_semihosting_connect_chardevs to
> qemu_semihosting_chardev_init; pass the result
> directly to qemu_semihosting_console_init.
> 
> Store the chardev in SemihostingConsole instead
> of SemihostingConfig, which lets us drop
> semihosting_get_chardev.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/semihost.h | 13 ++---
>  semihosting/config.c   | 17 +++--
>  semihosting/console.c  | 31 +++
>  softmmu/vl.c   |  3 +--
>  stubs/semihost.c   |  6 +-
>  5 files changed, 26 insertions(+), 44 deletions(-)
> 
> diff --git a/include/semihosting/semihost.h b/include/semihosting/semihost.h
> index 0c55ade3ac..5b36a76f08 100644
> --- a/include/semihosting/semihost.h
> +++ b/include/semihosting/semihost.h
> @@ -51,14 +51,6 @@ static inline const char *semihosting_get_cmdline(void)
>  {
>  return NULL;
>  }
> -
> -static inline Chardev *semihosting_get_chardev(void)
> -{
> -return NULL;
> -}
> -static inline void qemu_semihosting_console_init(void)
> -{
> -}
>  #else /* !CONFIG_USER_ONLY */
>  bool semihosting_enabled(void);
>  SemihostingTarget semihosting_get_target(void);
> @@ -66,12 +58,11 @@ const char *semihosting_get_arg(int i);
>  int semihosting_get_argc(void);
>  const char *semihosting_get_cmdline(void);
>  void semihosting_arg_fallback(const char *file, const char *cmd);
> -Chardev *semihosting_get_chardev(void);
>  /* for vl.c hooks */
>  void qemu_semihosting_enable(void);
>  int qemu_semihosting_config_options(const char *opt);
> -void qemu_semihosting_connect_chardevs(void);
> -void qemu_semihosting_console_init(void);
> +void qemu_semihosting_chardev_init(void);
> +void qemu_semihosting_console_init(Chardev *);
>  #endif /* CONFIG_USER_ONLY */
>  
>  #endif /* SEMIHOST_H */
> diff --git a/semihosting/config.c b/semihosting/config.c
> index 50d82108e6..4bca769fad 100644
> --- a/semihosting/config.c
> +++ b/semihosting/config.c
> @@ -50,7 +50,6 @@ QemuOptsList qemu_semihosting_config_opts = {
>  typedef struct SemihostingConfig {
>  bool enabled;
>  SemihostingTarget target;
> -Chardev *chardev;
>  char **argv;
>  int argc;
>  const char *cmdline; /* concatenated argv */
> @@ -121,11 +120,6 @@ void semihosting_arg_fallback(const char *file, const 
> char *cmd)
>  }
>  }
>  
> -Chardev *semihosting_get_chardev(void)
> -{
> -return semihosting.chardev;
> -}
> -
>  void qemu_semihosting_enable(void)
>  {
>  semihosting.enabled = true;
> @@ -171,16 +165,19 @@ int qemu_semihosting_config_options(const char *optarg)
>  return 0;
>  }
>  
> -void qemu_semihosting_connect_chardevs(void)
> +/* We had to defer this until chardevs were created */
> +void qemu_semihosting_chardev_init(void)
>  {
> -/* We had to defer this until chardevs were created */
> +Chardev *chr = NULL;
> +
>  if (semihost_chardev) {
> -Chardev *chr = qemu_chr_find(semihost_chardev);
> +chr = qemu_chr_find(semihost_chardev);
>  if (chr == NULL) {
>  error_report("semihosting chardev '%s' not found",
>   semihost_chardev);
>  exit(1);
>  }
> -semihosting.chardev = chr;
>  }
> +
> +qemu_semihosting_console_init(chr);
>  }
> diff --git a/semihosting/console.c b/semihosting/console.c
> index df618a28a4..4088192842 100644
> --- a/semihosting/console.c
> +++ b/semihosting/console.c
> @@ -27,11 +27,21 @@
>  #include "qapi/error.h"
>  #include "qemu/fifo8.h"
>  
> +/* Access to this structure is protected by the BQL */
> +typedef struct SemihostingConsole {
> +CharBackend backend;
> +Chardev *chr;
> +GSList  *sleeping_cpus;
> +boolgot;
> +Fifo8   fifo;
> +} SemihostingConsole;
> +
> +static SemihostingConsole console;
> +
>  int qemu_semihosting_log_out(const char *s, int len)
>  {
> -Chardev *chardev = semihosting_get_chardev();
> -if (chardev) {
> -return qemu_chr_write_all(chardev, (uint8_t *) s, len);
> +if (console.chr) {
> +return qemu_chr_write_all(console.chr, (uint8_t *) s, len);
>  } else {
>  return write(STDERR_FILENO, s, len);
>  }
> @@ -106,16 +116,6 @@ void qemu_semihosting_console_outc(CPUArchState *env, 
> target_ulong addr)
>  
>  #define FIFO_SIZE   1024
>  
> -/* Access to this structure is protected by the BQL */

Re: [PATCH v4 43/53] semihosting: Expand qemu_semihosting_console_inc to read

2022-06-24 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Allow more than one character to be read at one time.
> Will be used by m68k and nios2 semihosting for stdio.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/console.h | 12 +++-
>  linux-user/semihost.c | 10 ++
>  semihosting/arm-compat-semi.c | 11 +--
>  semihosting/console.c | 16 
>  4 files changed, 34 insertions(+), 15 deletions(-)
> 
> diff --git a/include/semihosting/console.h b/include/semihosting/console.h
> index 27f8e9ae2e..39dbf1b062 100644
> --- a/include/semihosting/console.h
> +++ b/include/semihosting/console.h
> @@ -38,19 +38,21 @@ int qemu_semihosting_console_outs(CPUArchState *env, 
> target_ulong s);
>  void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c);
>  
>  /**
> - * qemu_semihosting_console_inc:
> + * qemu_semihosting_console_read:
>   * @cs: CPUState
> + * @buf: host buffer
> + * @len: buffer size
>   *
> - * Receive single character from debug console.  As this call may block
> - * if no data is available we suspend the CPU and will re-execute the
> + * Receive at least one character from debug console.  As this call may
> + * block if no data is available we suspend the CPU and will re-execute the
>   * instruction when data is there. Therefore two conditions must be met:
>   *
>   *   - CPUState is synchronized before calling this function
>   *   - pc is only updated once the character is successfully returned
>   *
> - * Returns: character read OR cpu_loop_exit!
> + * Returns: number of characters read, OR cpu_loop_exit!
>   */
> -target_ulong qemu_semihosting_console_inc(CPUState *cs);
> +int qemu_semihosting_console_read(CPUState *cs, void *buf, int len);
>  
>  /**
>   * qemu_semihosting_log_out:
> diff --git a/linux-user/semihost.c b/linux-user/semihost.c
> index f14c6ae21d..2029fb674c 100644
> --- a/linux-user/semihost.c
> +++ b/linux-user/semihost.c
> @@ -56,21 +56,23 @@ void qemu_semihosting_console_outc(CPUArchState *env, 
> target_ulong addr)
>   * program is expecting more normal behaviour. This is slow but
>   * nothing using semihosting console reading is expecting to be fast.
>   */
> -target_ulong qemu_semihosting_console_inc(CPUState *cs)
> +int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
>  {
> -uint8_t c;
> +int ret;
>  struct termios old_tio, new_tio;
>  
>  /* Disable line-buffering and echo */
>  tcgetattr(STDIN_FILENO, _tio);
>  new_tio = old_tio;
>  new_tio.c_lflag &= (~ICANON & ~ECHO);
> +new_tio.c_cc[VMIN] = 1;
> +new_tio.c_cc[VTIME] = 0;
>  tcsetattr(STDIN_FILENO, TCSANOW, _tio);
>  
> -c = getchar();
> +ret = fread(buf, 1, len, stdin);
>  
>  /* restore config */
>  tcsetattr(STDIN_FILENO, TCSANOW, _tio);
>  
> -return (target_ulong) c;
> +return ret;
>  }
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index e7de52d042..20e99cdcc0 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -427,8 +427,15 @@ void do_common_semihosting(CPUState *cs)
>  break;
>  
>  case TARGET_SYS_READC:
> -ret = qemu_semihosting_console_inc(cs);
> -common_semi_set_ret(cs, ret);
> +{
> +uint8_t ch;
> +int ret = qemu_semihosting_console_read(cs, , 1);
> +if (ret == 1) {
> +common_semi_cb(cs, ch, 0);
> +} else {
> +common_semi_cb(cs, -1, EIO);
> +}
> +}
>  break;
>  
>  case TARGET_SYS_ISERROR:
> diff --git a/semihosting/console.c b/semihosting/console.c
> index 7b896fe43b..df618a28a4 100644
> --- a/semihosting/console.c
> +++ b/semihosting/console.c
> @@ -144,12 +144,14 @@ static void console_read(void *opaque, const uint8_t 
> *buf, int size)
>  c->sleeping_cpus = NULL;
>  }
>  
> -target_ulong qemu_semihosting_console_inc(CPUState *cs)
> +int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
>  {
> -uint8_t ch;
>  SemihostingConsole *c = 
> +int ret = 0;
>  
>  g_assert(qemu_mutex_iothread_locked());
> +
> +/* Block if the fifo is completely empty. */
>  if (fifo8_is_empty(>fifo)) {
>  c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, cs);
>  cs->halted = 1;
> @@ -157,8 +159,14 @@ target_ulong qemu_semihosting_console_inc(CPUState *cs)
>  cpu_loop_exit(cs);
>  /* never returns */
>  }
> -ch = fifo8_pop(>fifo);
> -return 

Re: [PATCH v4 40/53] gdbstub: Adjust gdb_syscall_complete_cb declaration

2022-06-24 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Change 'ret' to uint64_t.  This resolves a FIXME in the
> m68k and nios2 semihosting that we've lost data.
> Change 'err' to int.  There is nothing target-specific
> about the width of the errno value.
> 
> Signed-off-by: Richard Henderson 
> ---
>  include/exec/gdbstub.h|  3 +--
>  gdbstub.c |  7 ---
>  semihosting/arm-compat-semi.c | 12 +---
>  semihosting/console.c |  7 +++
>  semihosting/syscalls.c|  2 +-
>  target/m68k/m68k-semi.c   | 10 +++---
>  target/nios2/nios2-semi.c |  8 +++-
>  7 files changed, 20 insertions(+), 29 deletions(-)
> 
> diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
> index b588c306cc..f667014888 100644
> --- a/include/exec/gdbstub.h
> +++ b/include/exec/gdbstub.h

[...]

> -static void semihosting_cb(CPUState *cs, target_ulong ret, target_ulong err)
> +static void semihosting_cb(CPUState *cs, uint64_t ret, int err)
>  {
> -if (ret == (target_ulong) -1) {
> -qemu_log("%s: gdb console output failed ("TARGET_FMT_ld")",
> - __func__, err);
> +if (err) {
> +qemu_log("%s: gdb console output failed (%d)", __func__, err);

While you're at it, this qemu_log() call probably lacks a '\n'.


Reviewed-by: Luc Michel 


>  }
>  }







Re: [PATCH v4 42/53] semihosting: Pass CPUState to qemu_semihosting_console_inc

2022-06-24 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> We don't need CPUArchState, and we do want the CPUState of the
> thread performing the operation -- use this instead of current_cpu.
> 
> Reviewed-by: Peter Maydell 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/console.h |  4 ++--
>  linux-user/semihost.c |  2 +-
>  semihosting/arm-compat-semi.c |  2 +-
>  semihosting/console.c | 12 ++--
>  4 files changed, 10 insertions(+), 10 deletions(-)
> 
> diff --git a/include/semihosting/console.h b/include/semihosting/console.h
> index 4f6217bf10..27f8e9ae2e 100644
> --- a/include/semihosting/console.h
> +++ b/include/semihosting/console.h
> @@ -39,7 +39,7 @@ void qemu_semihosting_console_outc(CPUArchState *env, 
> target_ulong c);
>  
>  /**
>   * qemu_semihosting_console_inc:
> - * @env: CPUArchState
> + * @cs: CPUState
>   *
>   * Receive single character from debug console.  As this call may block
>   * if no data is available we suspend the CPU and will re-execute the
> @@ -50,7 +50,7 @@ void qemu_semihosting_console_outc(CPUArchState *env, 
> target_ulong c);
>   *
>   * Returns: character read OR cpu_loop_exit!
>   */
> -target_ulong qemu_semihosting_console_inc(CPUArchState *env);
> +target_ulong qemu_semihosting_console_inc(CPUState *cs);
>  
>  /**
>   * qemu_semihosting_log_out:
> diff --git a/linux-user/semihost.c b/linux-user/semihost.c
> index 17f074ac56..f14c6ae21d 100644
> --- a/linux-user/semihost.c
> +++ b/linux-user/semihost.c
> @@ -56,7 +56,7 @@ void qemu_semihosting_console_outc(CPUArchState *env, 
> target_ulong addr)
>   * program is expecting more normal behaviour. This is slow but
>   * nothing using semihosting console reading is expecting to be fast.
>   */
> -target_ulong qemu_semihosting_console_inc(CPUArchState *env)
> +target_ulong qemu_semihosting_console_inc(CPUState *cs)
>  {
>  uint8_t c;
>  struct termios old_tio, new_tio;
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index f992b60b6b..e7de52d042 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -427,7 +427,7 @@ void do_common_semihosting(CPUState *cs)
>  break;
>  
>  case TARGET_SYS_READC:
> -ret = qemu_semihosting_console_inc(env);
> +ret = qemu_semihosting_console_inc(cs);
>  common_semi_set_ret(cs, ret);
>  break;
>  
> diff --git a/semihosting/console.c b/semihosting/console.c
> index 3dd0ac60e2..7b896fe43b 100644
> --- a/semihosting/console.c
> +++ b/semihosting/console.c
> @@ -144,17 +144,17 @@ static void console_read(void *opaque, const uint8_t 
> *buf, int size)
>  c->sleeping_cpus = NULL;
>  }
>  
> -target_ulong qemu_semihosting_console_inc(CPUArchState *env)
> +target_ulong qemu_semihosting_console_inc(CPUState *cs)
>  {
>  uint8_t ch;
>  SemihostingConsole *c = 
> +
>  g_assert(qemu_mutex_iothread_locked());
> -g_assert(current_cpu);
>  if (fifo8_is_empty(>fifo)) {
> -c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, current_cpu);
> -current_cpu->halted = 1;
> -current_cpu->exception_index = EXCP_HALTED;
> -cpu_loop_exit(current_cpu);
> +c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, cs);
> +cs->halted = 1;
> +cs->exception_index = EXCP_HALTED;
> +cpu_loop_exit(cs);
>  /* never returns */
>  }
>  ch = fifo8_pop(>fifo);
> -- 
> 2.34.1
> 
> 
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=77cd.629fd666.e5059.0=lmichel%40kalrayinc.com=qemu-devel-bounces%2Blmichel%3Dkalrayinc.com%40nongnu.org=%5BPATCH+v4+42%2F53%5D+semihosting%3A+Pass+CPUState+to+qemu_semihosting_console_inc=C=f31b95a8de28ae0d1f01d90dfc034138189ae5d1
> 

-- 







Re: [PATCH v4 41/53] semihosting: Fix docs comment for qemu_semihosting_console_inc

2022-06-24 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> The implementation of qemu_semihosting_console_inc does not
> defer to gdbstub, but only reads from the fifo in console.c.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/console.h | 9 -
>  1 file changed, 4 insertions(+), 5 deletions(-)
> 
> diff --git a/include/semihosting/console.h b/include/semihosting/console.h
> index 0238f540f4..4f6217bf10 100644
> --- a/include/semihosting/console.h
> +++ b/include/semihosting/console.h
> @@ -41,11 +41,10 @@ void qemu_semihosting_console_outc(CPUArchState *env, 
> target_ulong c);
>   * qemu_semihosting_console_inc:
>   * @env: CPUArchState
>   *
> - * Receive single character from debug console. This may be the remote
> - * gdb session if a softmmu guest is currently being debugged. As this
> - * call may block if no data is available we suspend the CPU and will
> - * re-execute the instruction when data is there. Therefore two
> - * conditions must be met:
> + * Receive single character from debug console.  As this call may block
> + * if no data is available we suspend the CPU and will re-execute the
> + * instruction when data is there. Therefore two conditions must be met:
> + *
>   *   - CPUState is synchronized before calling this function
>   *   - pc is only updated once the character is successfully returned
>   *
> -- 
> 2.34.1
> 
> 
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=5699.629fd40f.c3695.0=lmichel%40kalrayinc.com=qemu-devel-bounces%2Blmichel%3Dkalrayinc.com%40nongnu.org=%5BPATCH+v4+41%2F53%5D+semihosting%3A+Fix+docs+comment+for+qemu_semihosting_console_inc=C=4edb0e3b3a44b5db8e011cdb60e9e8174e2cc844
> 

-- 







Re: [PATCH v4 38/53] semihosting: Create semihost_sys_{stat,fstat}

2022-06-24 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> These syscalls will be used by m68k and nios2 semihosting.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/syscalls.h |   7 ++
>  semihosting/syscalls.c | 137 +
>  2 files changed, 144 insertions(+)
> 
> diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
> index c9f9e66be1..ecc97751a9 100644
> --- a/include/semihosting/syscalls.h
> +++ b/include/semihosting/syscalls.h
> @@ -49,6 +49,13 @@ void semihost_sys_flen(CPUState *cs, 
> gdb_syscall_complete_cb fstat_cb,
> gdb_syscall_complete_cb flen_cb,
> int fd, target_ulong fstat_addr);
>  
> +void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
> +int fd, target_ulong addr);
> +
> +void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete,
> +   target_ulong fname, target_ulong fname_len,
> +   target_ulong addr);
> +
>  void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
>   target_ulong fname, target_ulong fname_len);
>  
> diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
> index de846ced32..d21064716d 100644
> --- a/semihosting/syscalls.c
> +++ b/semihosting/syscalls.c
> @@ -63,6 +63,52 @@ static int validate_lock_user_string(char **pstr, CPUState 
> *cs,
>  return ret;
>  }
>  
> +/*
> + * TODO: Note that gdb always stores the stat structure big-endian.
> + * So far, that's ok, as the only two targets using this are also
> + * big-endian.  Until we do something with gdb, also produce the
> + * same big-endian result from the host.
> + */
> +static int copy_stat_to_user(CPUState *cs, target_ulong addr,
> + const struct stat *s)
> +{
> +CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
> +struct gdb_stat *p;
> +
> +if (s->st_dev != (uint32_t)s->st_dev ||
> +s->st_ino != (uint32_t)s->st_ino) {
> +return -EOVERFLOW;
> +}
> +
> +p = lock_user(VERIFY_WRITE, addr, sizeof(struct gdb_stat), 0);
> +if (!p) {
> +return -EFAULT;
> +}
> +
> +p->gdb_st_dev = cpu_to_be32(s->st_dev);
> +p->gdb_st_ino = cpu_to_be32(s->st_ino);
> +p->gdb_st_mode = cpu_to_be32(s->st_mode);
> +p->gdb_st_nlink = cpu_to_be32(s->st_nlink);
> +p->gdb_st_uid = cpu_to_be32(s->st_uid);
> +p->gdb_st_gid = cpu_to_be32(s->st_gid);
> +p->gdb_st_rdev = cpu_to_be32(s->st_rdev);
> +p->gdb_st_size = cpu_to_be64(s->st_size);
> +#ifdef _WIN32
> +/* Windows stat is missing some fields.  */
> +p->gdb_st_blksize = 0;
> +p->gdb_st_blocks = 0;
> +#else
> +p->gdb_st_blksize = cpu_to_be64(s->st_blksize);
> +p->gdb_st_blocks = cpu_to_be64(s->st_blocks);
> +#endif
> +p->gdb_st_atime = cpu_to_be32(s->st_atime);
> +p->gdb_st_mtime = cpu_to_be32(s->st_mtime);
> +p->gdb_st_ctime = cpu_to_be32(s->st_ctime);
> +
> +unlock_user(p, addr, sizeof(struct gdb_stat));
> +return 0;
> +}
> +
>  /*
>   * GDB semihosting syscall implementations.
>   */
> @@ -133,6 +179,19 @@ static void gdb_fstat(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  gdb_do_syscall(complete, "fstat,%x,%x", (target_ulong)gf->hostfd, addr);
>  }
>  
> +static void gdb_stat(CPUState *cs, gdb_syscall_complete_cb complete,
> + target_ulong fname, target_ulong fname_len,
> + target_ulong addr)
> +{
> +int len = validate_strlen(cs, fname, fname_len);
> +if (len < 0) {
> +complete(cs, -1, -len);
> +return;
> +}
> +
> +gdb_do_syscall(complete, "stat,%s,%x", fname, len, addr);
> +}
> +
>  static void gdb_remove(CPUState *cs, gdb_syscall_complete_cb complete,
> target_ulong fname, target_ulong fname_len)
>  {
> @@ -321,6 +380,51 @@ static void host_flen(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  }
>  }
>  
> +static void host_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
> +   GuestFD *gf, target_ulong addr)
> +{
> +struct stat buf;
> +int ret;
> +
> +ret = fstat(gf->hostfd, );
> +if (ret) {
> +complete(cs, -1, errno);
> +return;
> +}
> +ret = copy_stat_to_user(cs, addr, );
> +complete(cs, ret ? -1 : 0, ret ? -ret : 0);
> +}
> +
> +static void host_stat(CPUState *cs, 

Re: [PATCH v4 39/53] semihosting: Create semihost_sys_gettimeofday

2022-06-24 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> This syscall will be used by m68k and nios2 semihosting.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/syscalls.h |  3 +++
>  semihosting/syscalls.c | 42 ++
>  2 files changed, 45 insertions(+)
> 
> diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
> index ecc97751a9..347200cb9f 100644
> --- a/include/semihosting/syscalls.h
> +++ b/include/semihosting/syscalls.h
> @@ -66,4 +66,7 @@ void semihost_sys_rename(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
>   target_ulong cmd, target_ulong cmd_len);
>  
> +void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb 
> complete,
> +   target_ulong tv_addr, target_ulong tz_addr);
> +
>  #endif /* SEMIHOSTING_SYSCALLS_H */
> diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
> index d21064716d..db1e9f6cc9 100644
> --- a/semihosting/syscalls.c
> +++ b/semihosting/syscalls.c
> @@ -236,6 +236,12 @@ static void gdb_system(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  gdb_do_syscall(complete, "system,%s", cmd, len);
>  }
>  
> +static void gdb_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
> + target_ulong tv_addr, target_ulong tz_addr)
> +{
> +gdb_do_syscall(complete, "gettimeofday,%x,%x", tv_addr, tz_addr);
> +}
> +
>  /*
>   * Host semihosting syscall implementations.
>   */
> @@ -487,6 +493,32 @@ static void host_system(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  unlock_user(p, cmd, 0);
>  }
>  
> +static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
> +  target_ulong tv_addr, target_ulong tz_addr)
> +{
> +CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
> +struct gdb_timeval *p;
> +int64_t rt;
> +
> +/* GDB fails on non-null TZ, so be consistent. */
> +if (tz_addr != 0) {
> +complete(cs, -1, EINVAL);
> +return;
> +}
> +
> +p = lock_user(VERIFY_WRITE, tv_addr, sizeof(struct gdb_timeval), 0);
> +if (!p) {
> +complete(cs, -1, EFAULT);
> +return;
> +}
> +
> +/* TODO: Like stat, gdb always produces big-endian results; match it. */
> +rt = g_get_real_time();
> +p->tv_sec = cpu_to_be32(rt / G_USEC_PER_SEC);
> +p->tv_usec = cpu_to_be64(rt % G_USEC_PER_SEC);
> +unlock_user(p, tv_addr, sizeof(struct gdb_timeval));
> +}
> +
>  /*
>   * Static file semihosting syscall implementations.
>   */
> @@ -796,3 +828,13 @@ void semihost_sys_system(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  host_system(cs, complete, cmd, cmd_len);
>  }
>  }
> +
> +void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb 
> complete,
> +   target_ulong tv_addr, target_ulong tz_addr)
> +{
> +if (use_gdb_syscalls()) {
> +gdb_gettimeofday(cs, complete, tv_addr, tz_addr);
> +} else {
> +host_gettimeofday(cs, complete, tv_addr, tz_addr);
> +}
> +}
> -- 
> 2.34.1
> 
> 
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=c119.629fd54f.4e3dd.0=lmichel%40kalrayinc.com=qemu-devel-bounces%2Blmichel%3Dkalrayinc.com%40nongnu.org=%5BPATCH+v4+39%2F53%5D+semihosting%3A+Create+semihost_sys_gettimeofday=C=72ff7ee6d62e9655defaed81c32535afbc86c0b7
> 

-- 







Re: [PATCH v4 38/53] semihosting: Create semihost_sys_{stat,fstat}

2022-06-24 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> These syscalls will be used by m68k and nios2 semihosting.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/syscalls.h |   7 ++
>  semihosting/syscalls.c | 137 +
>  2 files changed, 144 insertions(+)
> 
> diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
> index c9f9e66be1..ecc97751a9 100644
> --- a/include/semihosting/syscalls.h
> +++ b/include/semihosting/syscalls.h
> @@ -49,6 +49,13 @@ void semihost_sys_flen(CPUState *cs, 
> gdb_syscall_complete_cb fstat_cb,
> gdb_syscall_complete_cb flen_cb,
> int fd, target_ulong fstat_addr);
>  
> +void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
> +int fd, target_ulong addr);
> +
> +void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete,
> +   target_ulong fname, target_ulong fname_len,
> +   target_ulong addr);
> +
>  void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
>   target_ulong fname, target_ulong fname_len);
>  
> diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
> index de846ced32..d21064716d 100644
> --- a/semihosting/syscalls.c
> +++ b/semihosting/syscalls.c
> @@ -63,6 +63,52 @@ static int validate_lock_user_string(char **pstr, CPUState 
> *cs,
>  return ret;
>  }
>  
> +/*
> + * TODO: Note that gdb always stores the stat structure big-endian.
> + * So far, that's ok, as the only two targets using this are also
> + * big-endian.  Until we do something with gdb, also produce the
> + * same big-endian result from the host.
> + */
> +static int copy_stat_to_user(CPUState *cs, target_ulong addr,
> + const struct stat *s)
> +{
> +CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
> +struct gdb_stat *p;
> +
> +if (s->st_dev != (uint32_t)s->st_dev ||
> +s->st_ino != (uint32_t)s->st_ino) {
> +return -EOVERFLOW;
> +}
> +
> +p = lock_user(VERIFY_WRITE, addr, sizeof(struct gdb_stat), 0);
> +if (!p) {
> +return -EFAULT;
> +}
> +
> +p->gdb_st_dev = cpu_to_be32(s->st_dev);
> +p->gdb_st_ino = cpu_to_be32(s->st_ino);
> +p->gdb_st_mode = cpu_to_be32(s->st_mode);
> +p->gdb_st_nlink = cpu_to_be32(s->st_nlink);
> +p->gdb_st_uid = cpu_to_be32(s->st_uid);
> +p->gdb_st_gid = cpu_to_be32(s->st_gid);
> +p->gdb_st_rdev = cpu_to_be32(s->st_rdev);
> +p->gdb_st_size = cpu_to_be64(s->st_size);
> +#ifdef _WIN32
> +/* Windows stat is missing some fields.  */
> +p->gdb_st_blksize = 0;
> +p->gdb_st_blocks = 0;
> +#else
> +p->gdb_st_blksize = cpu_to_be64(s->st_blksize);
> +p->gdb_st_blocks = cpu_to_be64(s->st_blocks);
> +#endif
> +p->gdb_st_atime = cpu_to_be32(s->st_atime);
> +p->gdb_st_mtime = cpu_to_be32(s->st_mtime);
> +p->gdb_st_ctime = cpu_to_be32(s->st_ctime);
> +
> +unlock_user(p, addr, sizeof(struct gdb_stat));
> +return 0;
> +}
> +
>  /*
>   * GDB semihosting syscall implementations.
>   */
> @@ -133,6 +179,19 @@ static void gdb_fstat(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  gdb_do_syscall(complete, "fstat,%x,%x", (target_ulong)gf->hostfd, addr);
>  }
>  
> +static void gdb_stat(CPUState *cs, gdb_syscall_complete_cb complete,
> + target_ulong fname, target_ulong fname_len,
> + target_ulong addr)
> +{
> +int len = validate_strlen(cs, fname, fname_len);
> +if (len < 0) {
> +complete(cs, -1, -len);
> +return;
> +}
> +
> +gdb_do_syscall(complete, "stat,%s,%x", fname, len, addr);
> +}
> +
>  static void gdb_remove(CPUState *cs, gdb_syscall_complete_cb complete,
> target_ulong fname, target_ulong fname_len)
>  {
> @@ -321,6 +380,51 @@ static void host_flen(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  }
>  }
>  
> +static void host_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
> +   GuestFD *gf, target_ulong addr)
> +{
> +struct stat buf;
> +int ret;
> +
> +ret = fstat(gf->hostfd, );
> +if (ret) {
> +complete(cs, -1, errno);
> +return;
> +}
> +ret = copy_stat_to_user(cs, addr, );
> +complete(cs, ret ? -1 : 0, ret ? -ret : 0);
> +}
> +
> +static void host_stat(CPUState *cs, 

Re: [PATCH v4 37/53] semihosting: Split out semihost_sys_system

2022-06-24 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Split out the non-ARM specific portions of SYS_SYSTEM to a
> reusable function.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/syscalls.h |  3 +++
>  semihosting/arm-compat-semi.c  | 12 +-
>  semihosting/syscalls.c | 40 ++
>  3 files changed, 44 insertions(+), 11 deletions(-)
> 
> diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
> index 21430aa0ef..c9f9e66be1 100644
> --- a/include/semihosting/syscalls.h
> +++ b/include/semihosting/syscalls.h
> @@ -56,4 +56,7 @@ void semihost_sys_rename(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>   target_ulong oname, target_ulong oname_len,
>   target_ulong nname, target_ulong nname_len);
>  
> +void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
> + target_ulong cmd, target_ulong cmd_len);
> +
>  #endif /* SEMIHOSTING_SYSCALLS_H */
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index da5c80b3d5..8a4e22a20a 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -506,17 +506,7 @@ void do_common_semihosting(CPUState *cs)
>  case TARGET_SYS_SYSTEM:
>  GET_ARG(0);
>  GET_ARG(1);
> -if (use_gdb_syscalls()) {
> -gdb_do_syscall(common_semi_cb, "system,%s", arg0, (int)arg1 + 1);
> -break;
> -}
> -s = lock_user_string(arg0);
> -if (!s) {
> -goto do_fault;
> -}
> -ret = system(s);
> -unlock_user(s, arg0, 0);
> -common_semi_cb(cs, ret, ret == -1 ? errno : 0);
> +semihost_sys_system(cs, common_semi_cb, arg0, arg1 + 1);
>  break;
>  
>  case TARGET_SYS_ERRNO:
> diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
> index 223916b110..de846ced32 100644
> --- a/semihosting/syscalls.c
> +++ b/semihosting/syscalls.c
> @@ -165,6 +165,18 @@ static void gdb_rename(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  gdb_do_syscall(complete, "rename,%s,%s", oname, olen, nname, nlen);
>  }
>  
> +static void gdb_system(CPUState *cs, gdb_syscall_complete_cb complete,
> +   target_ulong cmd, target_ulong cmd_len)
> +{
> +int len = validate_strlen(cs, cmd, cmd_len);
> +if (len < 0) {
> +complete(cs, -1, -len);
> +return;
> +}
> +
> +gdb_do_syscall(complete, "system,%s", cmd, len);
> +}
> +
>  /*
>   * Host semihosting syscall implementations.
>   */
> @@ -353,6 +365,24 @@ static void host_rename(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  unlock_user(nstr, nname, 0);
>  }
>  
> +static void host_system(CPUState *cs, gdb_syscall_complete_cb complete,
> +target_ulong cmd, target_ulong cmd_len)
> +{
> +CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
> +char *p;
> +int ret;
> +
> +ret = validate_lock_user_string(, cs, cmd, cmd_len);
> +if (ret < 0) {
> +complete(cs, -1, -ret);
> +return;
> +}
> +
> +ret = system(p);
> +complete(cs, ret, ret == -1 ? errno : 0);
> +unlock_user(p, cmd, 0);
> +}
> +
>  /*
>   * Static file semihosting syscall implementations.
>   */
> @@ -619,3 +649,13 @@ void semihost_sys_rename(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  host_rename(cs, complete, oname, oname_len, nname, nname_len);
>  }
>  }
> +
> +void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
> + target_ulong cmd, target_ulong cmd_len)
> +{
> +if (use_gdb_syscalls()) {
> +gdb_system(cs, complete, cmd, cmd_len);
> +} else {
> +host_system(cs, complete, cmd, cmd_len);
> +}
> +}
> -- 
> 2.34.1
> 







Re: [PATCH v4 35/53] semihosting: Split out semihost_sys_remove

2022-06-24 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Split out the non-ARM specific portions of SYS_REMOVE to a
> reusable function.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/syscalls.h |  3 +++
>  semihosting/arm-compat-semi.c  | 13 +--
>  semihosting/syscalls.c | 40 ++
>  3 files changed, 44 insertions(+), 12 deletions(-)
> 
> diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
> index 1ae5ba6716..748a4b5e47 100644
> --- a/include/semihosting/syscalls.h
> +++ b/include/semihosting/syscalls.h
> @@ -49,4 +49,7 @@ void semihost_sys_flen(CPUState *cs, 
> gdb_syscall_complete_cb fstat_cb,
> gdb_syscall_complete_cb flen_cb,
> int fd, target_ulong fstat_addr);
>  
> +void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
> + target_ulong fname, target_ulong fname_len);
> +
>  #endif /* SEMIHOSTING_SYSCALLS_H */
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index 81dd22e1c5..6c9d50176a 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -483,18 +483,7 @@ void do_common_semihosting(CPUState *cs)
>  case TARGET_SYS_REMOVE:
>  GET_ARG(0);
>  GET_ARG(1);
> -if (use_gdb_syscalls()) {
> -gdb_do_syscall(common_semi_cb, "unlink,%s",
> -   arg0, (int)arg1 + 1);
> -break;
> -}
> -s = lock_user_string(arg0);
> -if (!s) {
> -goto do_fault;
> -}
> -ret = remove(s);
> -unlock_user(s, arg0, 0);
> -common_semi_cb(cs, ret, ret ? errno : 0);
> +semihost_sys_remove(cs, common_semi_cb, arg0, arg1 + 1);
>  break;
>  
>  case TARGET_SYS_RENAME:
> diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
> index fff9550c89..5ec4e8f827 100644
> --- a/semihosting/syscalls.c
> +++ b/semihosting/syscalls.c
> @@ -133,6 +133,18 @@ static void gdb_fstat(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  gdb_do_syscall(complete, "fstat,%x,%x", (target_ulong)gf->hostfd, addr);
>  }
>  
> +static void gdb_remove(CPUState *cs, gdb_syscall_complete_cb complete,
> +   target_ulong fname, target_ulong fname_len)
> +{
> +int len = validate_strlen(cs, fname, fname_len);
> +if (len < 0) {
> +complete(cs, -1, -len);
> +return;
> +}
> +
> +gdb_do_syscall(complete, "unlink,%s", fname, len);
> +}
> +
>  /*
>   * Host semihosting syscall implementations.
>   */
> @@ -277,6 +289,24 @@ static void host_flen(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  }
>  }
>  
> +static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete,
> +target_ulong fname, target_ulong fname_len)
> +{
> +CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
> +char *p;
> +int ret;
> +
> +ret = validate_lock_user_string(, cs, fname, fname_len);
> +if (ret < 0) {
> +complete(cs, -1, -ret);
> +return;
> +}
> +
> +ret = remove(p);
> +complete(cs, ret, ret ? errno : 0);
> +unlock_user(p, fname, 0);
> +}
> +
>  /*
>   * Static file semihosting syscall implementations.
>   */
> @@ -522,3 +552,13 @@ void semihost_sys_flen(CPUState *cs, 
> gdb_syscall_complete_cb fstat_cb,
>  g_assert_not_reached();
>  }
>  }
> +
> +void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
> + target_ulong fname, target_ulong fname_len)
> +{
> +if (use_gdb_syscalls()) {
> +gdb_remove(cs, complete, fname, fname_len);
> +} else {
> +host_remove(cs, complete, fname, fname_len);
> +}
> +}
> -- 
> 2.34.1
> 
> 
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=56f7.629fcfdf.1710e.0=lmichel%40kalrayinc.com=qemu-devel-bounces%2Blmichel%3Dkalrayinc.com%40nongnu.org=%5BPATCH+v4+35%2F53%5D+semihosting%3A+Split+out+semihost_sys_remove=C=39cfc6ff2d269a1766ae8f34c5c705eca3f8a07e
> 

-- 







Re: [PATCH v4 36/53] semihosting: Split out semihost_sys_rename

2022-06-24 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Split out the non-ARM specific portions of SYS_RENAME to a
> reusable function.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/syscalls.h |  4 +++
>  semihosting/arm-compat-semi.c  | 21 +
>  semihosting/syscalls.c | 57 ++
>  3 files changed, 62 insertions(+), 20 deletions(-)
> 
> diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
> index 748a4b5e47..21430aa0ef 100644
> --- a/include/semihosting/syscalls.h
> +++ b/include/semihosting/syscalls.h
> @@ -52,4 +52,8 @@ void semihost_sys_flen(CPUState *cs, 
> gdb_syscall_complete_cb fstat_cb,
>  void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
>   target_ulong fname, target_ulong fname_len);
>  
> +void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete,
> + target_ulong oname, target_ulong oname_len,
> + target_ulong nname, target_ulong nname_len);
> +
>  #endif /* SEMIHOSTING_SYSCALLS_H */
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index 6c9d50176a..da5c80b3d5 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -491,26 +491,7 @@ void do_common_semihosting(CPUState *cs)
>  GET_ARG(1);
>  GET_ARG(2);
>  GET_ARG(3);
> -if (use_gdb_syscalls()) {
> -gdb_do_syscall(common_semi_cb, "rename,%s,%s",
> -   arg0, (int)arg1 + 1, arg2, (int)arg3 + 1);
> -} else {
> -char *s2;
> -
> -s = lock_user_string(arg0);
> -if (!s) {
> -goto do_fault;
> -}
> -s2 = lock_user_string(arg2);
> -if (!s2) {
> -unlock_user(s, arg0, 0);
> -goto do_fault;
> -}
> -ret = rename(s, s2);
> -unlock_user(s2, arg2, 0);
> -unlock_user(s, arg0, 0);
> -common_semi_cb(cs, ret, ret ? errno : 0);
> -}
> +semihost_sys_rename(cs, common_semi_cb, arg0, arg1 + 1, arg2, arg3 + 
> 1);
>  break;
>  
>  case TARGET_SYS_CLOCK:
> diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
> index 5ec4e8f827..223916b110 100644
> --- a/semihosting/syscalls.c
> +++ b/semihosting/syscalls.c
> @@ -145,6 +145,26 @@ static void gdb_remove(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  gdb_do_syscall(complete, "unlink,%s", fname, len);
>  }
>  
> +static void gdb_rename(CPUState *cs, gdb_syscall_complete_cb complete,
> +   target_ulong oname, target_ulong oname_len,
> +   target_ulong nname, target_ulong nname_len)
> +{
> +int olen, nlen;
> +
> +olen = validate_strlen(cs, oname, oname_len);
> +if (olen < 0) {
> +complete(cs, -1, -olen);
> +return;
> +}
> +nlen = validate_strlen(cs, nname, nname_len);
> +if (nlen < 0) {
> +complete(cs, -1, -nlen);
> +return;
> +}
> +
> +gdb_do_syscall(complete, "rename,%s,%s", oname, olen, nname, nlen);
> +}
> +
>  /*
>   * Host semihosting syscall implementations.
>   */
> @@ -307,6 +327,32 @@ static void host_remove(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  unlock_user(p, fname, 0);
>  }
>  
> +static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete,
> +target_ulong oname, target_ulong oname_len,
> +target_ulong nname, target_ulong nname_len)
> +{
> +CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
> +char *ostr, *nstr;
> +int ret;
> +
> +ret = validate_lock_user_string(, cs, oname, oname_len);
> +if (ret < 0) {
> +complete(cs, -1, -ret);
> +return;
> +}
> +ret = validate_lock_user_string(, cs, nname, nname_len);
> +if (ret < 0) {
> +unlock_user(ostr, oname, 0);
> +complete(cs, -1, -ret);
> +return;
> +}
> +
> +ret = rename(ostr, nstr);
> +complete(cs, ret, ret ? errno : 0);
> +unlock_user(ostr, oname, 0);
> +unlock_user(nstr, nname, 0);
> +}
> +
>  /*
>   * Static file semihosting syscall implementations.
>   */
> @@ -562,3 +608,14 @@ void semihost_sys_remove(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  host_remove(cs, complete, fname, fname_len);
>  }
>  }
> +
> +void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb

Re: [PATCH v4 34/53] semihosting: Split out semihost_sys_flen

2022-06-24 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> The ARM-specific SYS_FLEN isn't really something that can be
> reused by other semihosting apis, but there are parts that can
> reused for the implementation of semihost_sys_fstat.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/syscalls.h |  4 ++
>  semihosting/arm-compat-semi.c  | 74 ++
>  semihosting/syscalls.c | 49 ++
>  3 files changed, 66 insertions(+), 61 deletions(-)
> 
> diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
> index c60ebafb85..1ae5ba6716 100644
> --- a/include/semihosting/syscalls.h
> +++ b/include/semihosting/syscalls.h
> @@ -45,4 +45,8 @@ void semihost_sys_lseek(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
>   int fd);
>  
> +void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
> +   gdb_syscall_complete_cb flen_cb,
> +   int fd, target_ulong fstat_addr);
> +
>  #endif /* SEMIHOSTING_SYSCALLS_H */
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index 4529c9df06..81dd22e1c5 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -285,44 +285,25 @@ static target_ulong common_semi_flen_buf(CPUState *cs)
>  }
>  
>  static void
> -common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
> +common_semi_flen_fstat_cb(CPUState *cs, target_ulong ret, target_ulong err)
>  {
>  if (!err) {
>  /* The size is always stored in big-endian order, extract the value. 
> */
>  uint64_t size;
> -cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) +
> -offsetof(struct gdb_stat, gdb_st_size),
> -, 8, 0);
> -ret = be64_to_cpu(size);
> +if (cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) +
> +offsetof(struct gdb_stat, gdb_st_size),
> +, 8, 0)) {
> +ret = -1, err = EFAULT;
> +} else {
> +size = be64_to_cpu(size);
> +if (ret != size) {
> +ret = -1, err = EOVERFLOW;
> +}
> +}
>  }
>  common_semi_cb(cs, ret, err);
>  }
>  
> -/*
> - * Types for functions implementing various semihosting calls
> - * for specific types of guest file descriptor. These must all
> - * do the work and return the required return value to the guest
> - * via common_semi_cb.
> - */
> -typedef void sys_flenfn(CPUState *cs, GuestFD *gf);
> -
> -static void host_flenfn(CPUState *cs, GuestFD *gf)
> -{
> -struct stat buf;
> -
> -if (fstat(gf->hostfd, )) {
> -common_semi_cb(cs, -1, errno);
> -} else {
> -common_semi_cb(cs, buf.st_size, 0);
> -}
> -}
> -
> -static void gdb_flenfn(CPUState *cs, GuestFD *gf)
> -{
> -gdb_do_syscall(common_semi_flen_cb, "fstat,%x,%x",
> -   gf->hostfd, common_semi_flen_buf(cs));
> -}
> -
>  #define SHFB_MAGIC_0 0x53
>  #define SHFB_MAGIC_1 0x48
>  #define SHFB_MAGIC_2 0x46
> @@ -340,27 +321,6 @@ static const uint8_t featurefile_data[] = {
>  SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
>  };
>  
> -static void staticfile_flenfn(CPUState *cs, GuestFD *gf)
> -{
> -common_semi_cb(cs, gf->staticfile.len, 0);
> -}
> -
> -typedef struct GuestFDFunctions {
> -sys_flenfn *flenfn;
> -} GuestFDFunctions;
> -
> -static const GuestFDFunctions guestfd_fns[] = {
> -[GuestFDHost] = {
> -.flenfn = host_flenfn,
> -},
> -[GuestFDGDB] = {
> -.flenfn = gdb_flenfn,
> -},
> -[GuestFDStatic] = {
> -.flenfn = staticfile_flenfn,
> -},
> -};
> -
>  /*
>   * Do a semihosting call.
>   *
> @@ -379,7 +339,6 @@ void do_common_semihosting(CPUState *cs)
>  char * s;
>  int nr;
>  uint32_t ret;
> -GuestFD *gf;
>  int64_t elapsed;
>  
>  nr = common_semi_arg(cs, 0) & 0xU;
> @@ -492,12 +451,8 @@ void do_common_semihosting(CPUState *cs)
>  
>  case TARGET_SYS_FLEN:
>  GET_ARG(0);
> -
> -gf = get_guestfd(arg0);
> -if (!gf) {
> -goto do_badf;
> -}
> -guestfd_fns[gf->type].flenfn(cs, gf);
> +semihost_sys_flen(cs, common_semi_flen_fstat_cb, common_semi_cb,
> +  arg0, common_semi_flen_buf(cs));
>

Re: [PATCH v2 2/7] semihosting: add the semihosting_exit_request function

2022-06-23 Thread Luc Michel
On 20:09 Wed 22 Jun , Peter Maydell wrote:
> On Tue, 21 Jun 2022 at 13:59, Luc Michel  wrote:
> >
> > Add the semihosting_exit_request function to be used by targets when
> > handling an `exit' semihosted syscall. This function calls gdb_exit to
> > close existing GDB connections, and qemu_system_shutdown_request with
> > the new `guest-semi-exit' exit reason. It sets the QEMU exit status
> > given by the exit syscall parameter. Finally it stops the CPU to prevent
> > further execution, and exit the CPU loop as the syscall caller expects
> > this syscall to not return.
> >
> > This function is meant to be used in place of a raw exit() call when
> > handling semihosted `exit' syscalls. Such a call is not safe because
> > it does not allow other CPU threads to exit properly, leading to e.g.
> > at_exit callbacks being called while other CPUs still run. This can lead
> > to strange bugs, especially in plugins with a registered at_exit function.
> 
> This is mixing up two things:
>  (1) fixing bugs with the plugin code when code (semihosting or
>  otherwise) calls exit()
>  (2) reporting to the monitor when the guest exits because it
>  asked to via semihosting
> 
> I remain unconvinced that this series is actually fixing (1),
> I think it's just working around the most common cause of it.
> For (2), maybe we want it, but that should I think be a
> separate patchset with justification of why it's useful to
> tell the monitor about it. I think on balance it probably
> is a good idea, but I disagree about (1) and would like to
> see these two things not tangled up in the same series.

OK. I'll rework this once Richard's semihosting cleanup series is
merged.

thanks.

Luc

> 
> thanks
> -- PMM
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=11a39.62b36915.466b.0=lmichel%40kalray.eu=peter.maydell%40linaro.org=Re%3A+%5BPATCH+v2+2%2F7%5D+semihosting%3A+add+the+semihosting_exit_request+function=C=b75eec0eae9b68db747812558b665a75218eca91
> 

-- 







Re: [PATCH v4 33/53] semihosting: Split out semihost_sys_isatty

2022-06-22 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Split out the non-ARM specific portions of SYS_ISTTY to a
> reusable function.  This handles all GuestFD.
> 
> Add a common_semi_istty_cb helper to translate the Posix
> error return, 0+ENOTTY, to the Arm semihosting not-a-file
> success result.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/syscalls.h |  3 +++
>  semihosting/arm-compat-semi.c  | 40 --
>  semihosting/syscalls.c | 36 ++
>  3 files changed, 53 insertions(+), 26 deletions(-)
> 
> diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
> index 841a93d25b..c60ebafb85 100644
> --- a/include/semihosting/syscalls.h
> +++ b/include/semihosting/syscalls.h
> @@ -42,4 +42,7 @@ void semihost_sys_write_gf(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
>  int fd, int64_t off, int gdb_whence);
>  
> +void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
> + int fd);
> +
>  #endif /* SEMIHOSTING_SYSCALLS_H */
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index 8c6c39daf5..4529c9df06 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -247,6 +247,19 @@ static void common_semi_rw_cb(CPUState *cs, target_ulong 
> ret, target_ulong err)
>  common_semi_set_ret(cs, arg2 - ret);
>  }
>  
> +/*
> + * Convert from Posix ret+errno to Arm SYS_ISTTY return values.
> + * With gdbstub, err is only ever set for protocol errors to EIO.
> + */
> +static void common_semi_istty_cb(CPUState *cs, target_ulong ret,
> + target_ulong err)
> +{
> +if (err) {
> +ret = (err == ENOTTY ? 0 : -1);
> +}
> +common_semi_cb(cs, ret, err);
> +}
> +
>  /*
>   * SYS_SEEK returns 0 on success, not the resulting offset.
>   */
> @@ -291,14 +304,8 @@ common_semi_flen_cb(CPUState *cs, target_ulong ret, 
> target_ulong err)
>   * do the work and return the required return value to the guest
>   * via common_semi_cb.
>   */
> -typedef void sys_isattyfn(CPUState *cs, GuestFD *gf);
>  typedef void sys_flenfn(CPUState *cs, GuestFD *gf);
>  
> -static void host_isattyfn(CPUState *cs, GuestFD *gf)
> -{
> -common_semi_cb(cs, isatty(gf->hostfd), 0);
> -}
> -
>  static void host_flenfn(CPUState *cs, GuestFD *gf)
>  {
>  struct stat buf;
> @@ -310,11 +317,6 @@ static void host_flenfn(CPUState *cs, GuestFD *gf)
>  }
>  }
>  
> -static void gdb_isattyfn(CPUState *cs, GuestFD *gf)
> -{
> -gdb_do_syscall(common_semi_cb, "isatty,%x", gf->hostfd);
> -}
> -
>  static void gdb_flenfn(CPUState *cs, GuestFD *gf)
>  {
>  gdb_do_syscall(common_semi_flen_cb, "fstat,%x,%x",
> @@ -338,32 +340,23 @@ static const uint8_t featurefile_data[] = {
>  SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
>  };
>  
> -static void staticfile_isattyfn(CPUState *cs, GuestFD *gf)
> -{
> -common_semi_cb(cs, 0, 0);
> -}
> -
>  static void staticfile_flenfn(CPUState *cs, GuestFD *gf)
>  {
>  common_semi_cb(cs, gf->staticfile.len, 0);
>  }
>  
>  typedef struct GuestFDFunctions {
> -sys_isattyfn *isattyfn;
>  sys_flenfn *flenfn;
>  } GuestFDFunctions;
>  
>  static const GuestFDFunctions guestfd_fns[] = {
>  [GuestFDHost] = {
> -.isattyfn = host_isattyfn,
>  .flenfn = host_flenfn,
>  },
>  [GuestFDGDB] = {
> -.isattyfn = gdb_isattyfn,
>  .flenfn = gdb_flenfn,
>  },
>  [GuestFDStatic] = {
> -.isattyfn = staticfile_isattyfn,
>  .flenfn = staticfile_flenfn,
>  },
>  };
> @@ -488,12 +481,7 @@ void do_common_semihosting(CPUState *cs)
>  
>  case TARGET_SYS_ISTTY:
>  GET_ARG(0);
> -
> -gf = get_guestfd(arg0);
> -if (!gf) {
> -goto do_badf;
> -}
> -guestfd_fns[gf->type].isattyfn(cs, gf);
> +semihost_sys_isatty(cs, common_semi_istty_cb, arg0);
>  break;
>  
>  case TARGET_SYS_SEEK:
> diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
> index 9e3eb464b5..1f1baf7e2d 100644
> --- a/semihosting/syscalls.c
> +++ b/semihosting/syscalls.c
> @@ -121,6 +121,12 @@ static void gdb_lseek(CPUState *cs, 
> gdb_syscall_complete_cb complete,
> (target_ulong)gf->hostfd, off, (target_ulong)gdb_whence);
>  }
>  
> +static void gdb_isatt

Re: [PATCH v4 32/53] semihosting: Split out semihost_sys_lseek

2022-06-22 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Split out the non-ARM specific portions of SYS_SEEK to a
> reusable function.  This handles all GuestFD.  Isolate the
> curious ARM-specific return value processing to a new
> callback, common_semi_seek_cb.
> 
> Expand the internal type of the offset to int64_t, and
> provide the whence argument, which will be required by
> m68k and nios2 semihosting.
> 
> Note that gdb_do_syscall %x reads target_ulong, not int.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/exec/gdbstub.h |  5 +++
>  include/semihosting/syscalls.h |  3 ++
>  semihosting/arm-compat-semi.c  | 51 ++---
>  semihosting/syscalls.c | 81 ++
>  4 files changed, 102 insertions(+), 38 deletions(-)
> 
> diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
> index 95a8b7b056..b588c306cc 100644
> --- a/include/exec/gdbstub.h
> +++ b/include/exec/gdbstub.h
> @@ -41,6 +41,11 @@
>  #define GDB_ENAMETOOLONG   91
>  #define GDB_EUNKNOWN   
>  
> +/* For gdb file i/o remote protocol lseek whence. */
> +#define GDB_SEEK_SET  0
> +#define GDB_SEEK_CUR  1
> +#define GDB_SEEK_END  2
> +
>  /* For gdb file i/o stat/fstat. */
>  typedef uint32_t gdb_mode_t;
>  typedef uint32_t gdb_time_t;
> diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
> index 2464467579..841a93d25b 100644
> --- a/include/semihosting/syscalls.h
> +++ b/include/semihosting/syscalls.h
> @@ -39,4 +39,7 @@ void semihost_sys_write(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
> GuestFD *gf, target_ulong buf, target_ulong len);
>  
> +void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
> +int fd, int64_t off, int gdb_whence);
> +
>  #endif /* SEMIHOSTING_SYSCALLS_H */
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index d1d35e6032..8c6c39daf5 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -224,16 +224,6 @@ static void common_semi_cb(CPUState *cs, target_ulong 
> ret, target_ulong err)
>  #else
>  syscall_err = err;
>  #endif
> -} else {
> -/* Fixup syscalls that use nonstardard return conventions.  */
> -target_ulong reg0 = common_semi_arg(cs, 0);
> -switch (reg0) {
> -case TARGET_SYS_SEEK:
> -ret = 0;
> -break;
> -default:
> -break;
> -}
>  }
>  common_semi_set_ret(cs, ret);
>  }
> @@ -257,6 +247,18 @@ static void common_semi_rw_cb(CPUState *cs, target_ulong 
> ret, target_ulong err)
>  common_semi_set_ret(cs, arg2 - ret);
>  }
>  
> +/*
> + * SYS_SEEK returns 0 on success, not the resulting offset.
> + */
> +static void common_semi_seek_cb(CPUState *cs, target_ulong ret,
> +target_ulong err)
> +{
> +if (!err) {
> +ret = 0;
> +}
> +common_semi_cb(cs, ret, err);
> +}
> +
>  /*
>   * Return an address in target memory of 64 bytes where the remote
>   * gdb should write its stat struct. (The format of this structure
> @@ -290,7 +292,6 @@ common_semi_flen_cb(CPUState *cs, target_ulong ret, 
> target_ulong err)
>   * via common_semi_cb.
>   */
>  typedef void sys_isattyfn(CPUState *cs, GuestFD *gf);
> -typedef void sys_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset);
>  typedef void sys_flenfn(CPUState *cs, GuestFD *gf);
>  
>  static void host_isattyfn(CPUState *cs, GuestFD *gf)
> @@ -298,12 +299,6 @@ static void host_isattyfn(CPUState *cs, GuestFD *gf)
>  common_semi_cb(cs, isatty(gf->hostfd), 0);
>  }
>  
> -static void host_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
> -{
> -off_t ret = lseek(gf->hostfd, offset, SEEK_SET);
> -common_semi_cb(cs, ret, ret == -1 ? errno : 0);
> -}
> -
>  static void host_flenfn(CPUState *cs, GuestFD *gf)
>  {
>  struct stat buf;
> @@ -320,11 +315,6 @@ static void gdb_isattyfn(CPUState *cs, GuestFD *gf)
>  gdb_do_syscall(common_semi_cb, "isatty,%x", gf->hostfd);
>  }
>  
> -static void gdb_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
> -{
> -gdb_do_syscall(common_semi_cb, "lseek,%x,%x,0", gf->hostfd, offset);
> -}
> -
>  static void gdb_flenfn(CPUState *cs, GuestFD *gf)
>  {
>  gdb_do_syscall(common_semi_flen_cb, "fstat,%x,%x",
> @@ -353,12 +343,6 @@ static void staticfile_isattyfn(CPUState *cs, GuestFD 
> *gf)
>

Re: [PATCH v4 31/53] semihosting: Bound length for semihost_sys_{read, write}

2022-06-22 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Fixes a minor bug in which a 64-bit guest on a 32-bit host could
> truncate the length.  This would only ever cause a problem if
> there were no bits set in the low 32, so that it truncates to 0.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  semihosting/syscalls.c | 16 
>  1 file changed, 16 insertions(+)
> 
> diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
> index 5cb12d6adc..eefbae74f1 100644
> --- a/semihosting/syscalls.c
> +++ b/semihosting/syscalls.c
> @@ -283,6 +283,14 @@ void semihost_sys_close(CPUState *cs, 
> gdb_syscall_complete_cb complete, int fd)
>  void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
>GuestFD *gf, target_ulong buf, target_ulong len)
>  {
> +/*
> + * Bound length for 64-bit guests on 32-bit hosts, not overlowing 
> ssize_t.
> + * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad
> + * idea to do this unconditionally.
> + */
> +if (len > INT32_MAX) {
> +len = INT32_MAX;
> +}
>  switch (gf->type) {
>  case GuestFDGDB:
>  gdb_read(cs, complete, gf, buf, len);
> @@ -313,6 +321,14 @@ void semihost_sys_read(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
> GuestFD *gf, target_ulong buf, target_ulong len)
>  {
> +/*
> + * Bound length for 64-bit guests on 32-bit hosts, not overlowing 
> ssize_t.
> + * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad
> + * idea to do this unconditionally.
> + */
> +if (len > INT32_MAX) {
> +len = INT32_MAX;
> +}
>  switch (gf->type) {
>  case GuestFDGDB:
>  gdb_write(cs, complete, gf, buf, len);
> -- 
> 2.34.1
> 
> 
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=17321.629fcd3b.c73a0.0=lmichel%40kalrayinc.com=qemu-devel-bounces%2Blmichel%3Dkalrayinc.com%40nongnu.org=%5BPATCH+v4+31%2F53%5D+semihosting%3A+Bound+length+for+semihost_sys_%7Bread%2C+write%7D=C=7f9ee3dfa94cc38c566bd57258d2a28de21afd3e
> 

-- 







Re: [PATCH v4 30/53] semihosting: Split out semihost_sys_write

2022-06-22 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Split out the non-ARM specific portions of SYS_WRITE to a
> reusable function.  This handles all GuestFD.  This removes
> the last use of common_semi_syscall_len.
> 
> Note that gdb_do_syscall %x reads target_ulong, not int.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/syscalls.h |  6 
>  semihosting/arm-compat-semi.c  | 52 +---
>  semihosting/syscalls.c | 54 ++
>  3 files changed, 61 insertions(+), 51 deletions(-)
> 
> diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
> index 20da8138b0..2464467579 100644
> --- a/include/semihosting/syscalls.h
> +++ b/include/semihosting/syscalls.h
> @@ -33,4 +33,10 @@ void semihost_sys_read(CPUState *cs, 
> gdb_syscall_complete_cb complete,
>  void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
>GuestFD *gf, target_ulong buf, target_ulong len);
>  
> +void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete,
> +int fd, target_ulong buf, target_ulong len);
> +
> +void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
> +   GuestFD *gf, target_ulong buf, target_ulong len);
> +
>  #endif /* SEMIHOSTING_SYSCALLS_H */
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index 5e11ec307a..d1d35e6032 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -215,8 +215,6 @@ static inline uint32_t get_swi_errno(CPUState *cs)
>  #endif
>  }
>  
> -static target_ulong common_semi_syscall_len;
> -
>  static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
>  {
>  if (err) {
> @@ -230,9 +228,6 @@ static void common_semi_cb(CPUState *cs, target_ulong 
> ret, target_ulong err)
>  /* Fixup syscalls that use nonstardard return conventions.  */
>  target_ulong reg0 = common_semi_arg(cs, 0);
>  switch (reg0) {
> -case TARGET_SYS_WRITE:
> -ret = common_semi_syscall_len - ret;
> -break;
>  case TARGET_SYS_SEEK:
>  ret = 0;
>  break;
> @@ -294,30 +289,10 @@ common_semi_flen_cb(CPUState *cs, target_ulong ret, 
> target_ulong err)
>   * do the work and return the required return value to the guest
>   * via common_semi_cb.
>   */
> -typedef void sys_writefn(CPUState *cs, GuestFD *gf,
> - target_ulong buf, uint32_t len);
>  typedef void sys_isattyfn(CPUState *cs, GuestFD *gf);
>  typedef void sys_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset);
>  typedef void sys_flenfn(CPUState *cs, GuestFD *gf);
>  
> -static void host_writefn(CPUState *cs, GuestFD *gf,
> - target_ulong buf, uint32_t len)
> -{
> -CPUArchState *env = cs->env_ptr;
> -uint32_t ret = 0;
> -char *s = lock_user(VERIFY_READ, buf, len, 1);
> -(void) env; /* Used in arm softmmu lock_user implicitly */
> -if (s) {
> -ret = write(gf->hostfd, s, len);
> -unlock_user(s, buf, 0);
> -if (ret == (uint32_t)-1) {
> -ret = 0;
> -}
> -}
> -/* Return bytes not written, on error as well. */
> -common_semi_cb(cs, len - ret, 0);
> -}
> -
>  static void host_isattyfn(CPUState *cs, GuestFD *gf)
>  {
>  common_semi_cb(cs, isatty(gf->hostfd), 0);
> @@ -340,13 +315,6 @@ static void host_flenfn(CPUState *cs, GuestFD *gf)
>  }
>  }
>  
> -static void gdb_writefn(CPUState *cs, GuestFD *gf,
> -target_ulong buf, uint32_t len)
> -{
> -common_semi_syscall_len = len;
> -gdb_do_syscall(common_semi_cb, "write,%x,%x,%x", gf->hostfd, buf, len);
> -}
> -
>  static void gdb_isattyfn(CPUState *cs, GuestFD *gf)
>  {
>  gdb_do_syscall(common_semi_cb, "isatty,%x", gf->hostfd);
> @@ -380,13 +348,6 @@ static const uint8_t featurefile_data[] = {
>  SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
>  };
>  
> -static void staticfile_writefn(CPUState *cs, GuestFD *gf,
> -   target_ulong buf, uint32_t len)
> -{
> -/* This fd can never be open for writing */
> -common_semi_cb(cs, -1, EBADF);
> -}
> -
>  static void staticfile_isattyfn(CPUState *cs, GuestFD *gf)
>  {
>  common_semi_cb(cs, 0, 0);
> @@ -404,7 +365,6 @@ static void staticfile_flenfn(CPUState *cs, GuestFD *gf)
>  }
>  
>  typedef struct GuestFDFunctions {
> -sys_writefn *writefn;
>

Re: [PATCH v4 29/53] semihosting: Split out semihost_sys_read

2022-06-22 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Split out the non-ARM specific portions of SYS_READ to a
> reusable function.  This handles all GuestFD.  Isolate the
> curious ARM-specific return value processing to a new
> callback, common_semi_rw_cb.
> 
> Note that gdb_do_syscall %x reads target_ulong, not int.
> 
> Signed-off-by: Richard Henderson 
> ---
>  include/semihosting/syscalls.h |  8 
>  semihosting/arm-compat-semi.c  | 85 --
>  semihosting/syscalls.c | 85 ++
>  3 files changed, 113 insertions(+), 65 deletions(-)
> 

[...]

> +/*
> + * SYS_READ and SYS_WRITE always return the number of bytes not read/written.
> + * There is no error condition, other than returning the original length.
> + */
> +static void common_semi_rw_cb(CPUState *cs, target_ulong ret, target_ulong 
> err)
> +{
> +/* Recover the original length from the third argument. */
> +CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
> +target_ulong args = common_semi_arg(cs, 1);
> +target_ulong arg2;
> +GET_ARG(2);
> +
> +if (err) {
> + do_fault:
Leftover label?

otherwise:

Reviewed-by: Luc Michel 

> +ret = 0; /* error: no bytes transmitted */
> +}
> +common_semi_set_ret(cs, arg2 - ret);
> +}
> +







Re: [PATCH v4 28/53] semihosting: Split out semihost_sys_close

2022-06-22 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Split out the non-ARM specific portions of SYS_CLOSE to a
> reusable function.  This handles all GuestFD.
> 
> Note that gdb_do_syscall %x reads target_ulong, not int.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  include/semihosting/syscalls.h |  3 +++
>  semihosting/arm-compat-semi.c  | 41 +
>  semihosting/guestfd.c  |  7 -
>  semihosting/syscalls.c | 47 ++
>  4 files changed, 57 insertions(+), 41 deletions(-)
> 
> diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
> index 991658bf79..00e718f11d 100644
> --- a/include/semihosting/syscalls.h
> +++ b/include/semihosting/syscalls.h
> @@ -22,4 +22,7 @@ void semihost_sys_open(CPUState *cs, 
> gdb_syscall_complete_cb complete,
> target_ulong fname, target_ulong fname_len,
> int gdb_flags, int mode);
>  
> +void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete,
> +int fd);
> +
>  #endif /* SEMIHOSTING_SYSCALLS_H */
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index 3239eda513..a6dddb2aa2 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -276,7 +276,6 @@ common_semi_flen_cb(CPUState *cs, target_ulong ret, 
> target_ulong err)
>   * do the work and return the required return value to the guest
>   * via common_semi_cb.
>   */
> -typedef void sys_closefn(CPUState *cs, GuestFD *gf);
>  typedef void sys_writefn(CPUState *cs, GuestFD *gf,
>   target_ulong buf, uint32_t len);
>  typedef void sys_readfn(CPUState *cs, GuestFD *gf,
> @@ -285,23 +284,6 @@ typedef void sys_isattyfn(CPUState *cs, GuestFD *gf);
>  typedef void sys_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset);
>  typedef void sys_flenfn(CPUState *cs, GuestFD *gf);
>  
> -static void host_closefn(CPUState *cs, GuestFD *gf)
> -{
> -int ret;
> -/*
> - * Only close the underlying host fd if it's one we opened on behalf
> - * of the guest in SYS_OPEN.
> - */
> -if (gf->hostfd == STDIN_FILENO ||
> -gf->hostfd == STDOUT_FILENO ||
> -gf->hostfd == STDERR_FILENO) {
> -ret = 0;
> -} else {
> -ret = close(gf->hostfd);
> -}
> -common_semi_cb(cs, ret, ret ? errno : 0);
> -}
> -
>  static void host_writefn(CPUState *cs, GuestFD *gf,
>   target_ulong buf, uint32_t len)
>  {
> @@ -362,11 +344,6 @@ static void host_flenfn(CPUState *cs, GuestFD *gf)
>  }
>  }
>  
> -static void gdb_closefn(CPUState *cs, GuestFD *gf)
> -{
> -gdb_do_syscall(common_semi_cb, "close,%x", gf->hostfd);
> -}
> -
>  static void gdb_writefn(CPUState *cs, GuestFD *gf,
>  target_ulong buf, uint32_t len)
>  {
> @@ -414,12 +391,6 @@ static const uint8_t featurefile_data[] = {
>  SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
>  };
>  
> -static void staticfile_closefn(CPUState *cs, GuestFD *gf)
> -{
> -/* Nothing to do */
> -common_semi_cb(cs, 0, 0);
> -}
> -
>  static void staticfile_writefn(CPUState *cs, GuestFD *gf,
> target_ulong buf, uint32_t len)
>  {
> @@ -468,7 +439,6 @@ static void staticfile_flenfn(CPUState *cs, GuestFD *gf)
>  }
>  
>  typedef struct GuestFDFunctions {
> -sys_closefn *closefn;
>  sys_writefn *writefn;
>  sys_readfn *readfn;
>  sys_isattyfn *isattyfn;
> @@ -478,7 +448,6 @@ typedef struct GuestFDFunctions {
>  
>  static const GuestFDFunctions guestfd_fns[] = {
>  [GuestFDHost] = {
> -.closefn = host_closefn,
>  .writefn = host_writefn,
>  .readfn = host_readfn,
>  .isattyfn = host_isattyfn,
> @@ -486,7 +455,6 @@ static const GuestFDFunctions guestfd_fns[] = {
>  .flenfn = host_flenfn,
>  },
>  [GuestFDGDB] = {
> -.closefn = gdb_closefn,
>  .writefn = gdb_writefn,
>  .readfn = gdb_readfn,
>  .isattyfn = gdb_isattyfn,
> @@ -494,7 +462,6 @@ static const GuestFDFunctions guestfd_fns[] = {
>  .flenfn = gdb_flenfn,
>  },
>  [GuestFDStatic] = {
> -.closefn = staticfile_closefn,
>  .writefn = staticfile_writefn,
>  .readfn = staticfile_readfn,
>  .isattyfn = staticfile_isattyfn,
> @@ -585,13 +552,7 @@ void do_common_semihosting(CPUState *cs)
>  
>  case TARGET_SYS_CLOSE:
>  GET_ARG(0);
> -
> -gf = get_guestf

Re: [PATCH v4 27/53] semihosting: Split out semihost_sys_open

2022-06-22 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Split out the non-ARM specific portions of SYS_OPEN to a
> reusable function.  This handles gdb and host file i/o.
> 
> Add helpers to validate the length of the filename string.
> Prepare for usage by other semihosting by allowing the
> filename length parameter to be 0, and calling strlen.
> 
> Signed-off-by: Richard Henderson 
> ---
>  include/semihosting/syscalls.h |  25 ++
>  semihosting/arm-compat-semi.c  |  52 ++-
>  semihosting/guestfd.c  |   5 ++
>  semihosting/syscalls.c | 156 +
>  semihosting/meson.build|   1 +
>  5 files changed, 193 insertions(+), 46 deletions(-)
>  create mode 100644 include/semihosting/syscalls.h
>  create mode 100644 semihosting/syscalls.c
> 

[...]

>  } else {
> -hostfd = open(s, open_modeflags[arg1], 0644);
> -if (hostfd < 0) {
> -ret = -1;
> -err = errno;
> -} else {
> -ret = alloc_guestfd();
> -associate_guestfd(ret, hostfd);
> -}
> +semihost_sys_open(cs, common_semi_cb, arg0, arg2 + 1,
> +  gdb_open_modeflags[arg1], 0644);

You're missing a unlock_user(s, arg0, 0); here







Re: [PATCH v4 25/53] semihosting: Use env more often in do_common_semihosting

2022-06-22 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> We've already loaded cs->env_ptr into a local variable; use it.
> Since env is unconditionally used, we don't need a dummy use.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  semihosting/arm-compat-semi.c | 7 +++
>  1 file changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index 5e442e549d..adb4e5b581 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -553,7 +553,6 @@ void do_common_semihosting(CPUState *cs)
>  GuestFD *gf;
>  int64_t elapsed;
>  
> -(void) env; /* Used implicitly by arm lock_user macro */
>  nr = common_semi_arg(cs, 0) & 0xU;
>  args = common_semi_arg(cs, 1);
>  
> @@ -636,12 +635,12 @@ void do_common_semihosting(CPUState *cs)
>  break;
>  
>  case TARGET_SYS_WRITEC:
> -qemu_semihosting_console_outc(cs->env_ptr, args);
> +qemu_semihosting_console_outc(env, args);
>  common_semi_set_ret(cs, 0xdeadbeef);
>  break;
>  
>  case TARGET_SYS_WRITE0:
> -ret = qemu_semihosting_console_outs(cs->env_ptr, args);
> +ret = qemu_semihosting_console_outs(env, args);
>  common_semi_set_ret(cs, ret);
>  break;
>  
> @@ -672,7 +671,7 @@ void do_common_semihosting(CPUState *cs)
>  break;
>  
>  case TARGET_SYS_READC:
> -ret = qemu_semihosting_console_inc(cs->env_ptr);
> +ret = qemu_semihosting_console_inc(env);
>  common_semi_set_ret(cs, ret);
>  break;
>  
> -- 
> 2.34.1
> 







Re: [PATCH v4 19/53] gdbstub: Convert GDB error numbers to host error numbers

2022-06-22 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Provide the callback with consistent state -- always use
> host error numbers.  The individual callback can then
> decide if the errno requires conversion for the guest.
> 
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  gdbstub.c | 31 +++
>  1 file changed, 31 insertions(+)
> 
> diff --git a/gdbstub.c b/gdbstub.c
> index a3ff8702ce..ecc9d9cd6f 100644
> --- a/gdbstub.c
> +++ b/gdbstub.c
> @@ -1878,6 +1878,37 @@ static void handle_file_io(GArray *params, void 
> *user_ctx)
>  } else {
>  err = 0;
>  }
> +
> +/* Convert GDB error numbers back to host error numbers. */
> +#define E(X)  case GDB_E##X: err = E##X; break
> +switch (err) {
> +case 0:
> +break;
> +E(PERM);
> +E(NOENT);
> +E(INTR);
> +E(BADF);
> +E(ACCES);
> +E(FAULT);
> +E(BUSY);
> +E(EXIST);
> +E(NODEV);
> +E(NOTDIR);
> +E(ISDIR);
> +E(INVAL);
> +E(NFILE);
> +E(MFILE);
> +E(FBIG);
> +E(NOSPC);
> +E(SPIPE);
> +E(ROFS);
> +E(NAMETOOLONG);
> +default:
> +err = EINVAL;
> +break;
> +}
> +#undef E
> +
>  gdbserver_state.current_syscall_cb(gdbserver_state.c_cpu, ret, err);
>  gdbserver_state.current_syscall_cb = NULL;
>  }
> -- 
> 2.34.1
> 
> 
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=12eb3.629fd0dd.8c7c2.0=lmichel%40kalrayinc.com=qemu-devel-bounces%2Blmichel%3Dkalrayinc.com%40nongnu.org=%5BPATCH+v4+19%2F53%5D+gdbstub%3A+Convert+GDB+error+numbers+to+host+error+numbers=C=cdb84b0ad101f626e700d163f173cb52e6d969f7
> 

-- 







Re: [PATCH v4 05/53] accel/stubs: Add tcg stub for probe_access_flags

2022-06-22 Thread Luc Michel
On 13:45 Tue 07 Jun , Richard Henderson wrote:
> Signed-off-by: Richard Henderson 

Reviewed-by: Luc Michel 

> ---
>  accel/stubs/tcg-stub.c | 7 +++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c
> index ea4a0dd2fb..6ce8a34228 100644
> --- a/accel/stubs/tcg-stub.c
> +++ b/accel/stubs/tcg-stub.c
> @@ -21,6 +21,13 @@ void tlb_set_dirty(CPUState *cpu, target_ulong vaddr)
>  {
>  }
>  
> +int probe_access_flags(CPUArchState *env, target_ulong addr,
> +   MMUAccessType access_type, int mmu_idx,
> +   bool nonfault, void **phost, uintptr_t retaddr)
> +{
> + g_assert_not_reached();
> +}
> +
>  void *probe_access(CPUArchState *env, target_ulong addr, int size,
> MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
>  {
> -- 
> 2.34.1
> 







Re: [PATCH v2 0/7] semihosting: proper QEMU exit on semihosted exit syscall

2022-06-22 Thread Luc Michel
On 07:37 Tue 21 Jun , Richard Henderson wrote:
> On 6/21/22 05:59, Luc Michel wrote:
> > v2:
> >- fix linux-user compilation. Declare semihosting_exit_request "static
> >  inline G_NORETURN" on CONFIG_USER_ONLY side. Use
> >  g_assert_not_reached() to enforce the G_NORETURN since this function
> >  is unused in linux-user mode.
> 
> Not true.  It *is* used with semihosting linux-user.
> 
> Anyway, before you go too far down this road, see
> 
> https://patchew.org/QEMU/20220607204557.658541-1-richard.hender...@linaro.org/

aww OK. Let's have your series merged first then.

> 
> 
> r~
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=16699.62b1d79b.16c49.0=lmichel%40kalray.eu=richard.henderson%40linaro.org=Re%3A+%5BPATCH+v2+0%2F7%5D+semihosting%3A+proper+QEMU+exit+on+semihosted+exit+syscall=C=71759fc2b76b8b9bc7813e449355fa174c40ee7b
> 

-- 







[PATCH v2 7/7] target/xtensa: use semihosting_exit_request on semihosted exit syscall

2022-06-21 Thread Luc Michel
Use the new semihosting_exit_request instead of a call to exit when
handling a semihosted exit syscall.

Signed-off-by: Luc Michel 
---
 target/xtensa/xtensa-semi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/xtensa/xtensa-semi.c b/target/xtensa/xtensa-semi.c
index fa21b7e11f..0e9a9edc16 100644
--- a/target/xtensa/xtensa-semi.c
+++ b/target/xtensa/xtensa-semi.c
@@ -193,11 +193,11 @@ void HELPER(simcall)(CPUXtensaState *env)
 CPUState *cs = env_cpu(env);
 uint32_t *regs = env->regs;
 
 switch (regs[2]) {
 case TARGET_SYS_exit:
-exit(regs[3]);
+semihosting_exit_request(regs[3]);
 break;
 
 case TARGET_SYS_read:
 case TARGET_SYS_write:
 {
-- 
2.17.1




[PATCH v2 6/7] target/nios2: use semihosting_exit_request on semihosted exit syscall

2022-06-21 Thread Luc Michel via
Use the new semihosting_exit_request instead of a call to exit when
handling a semihosted exit syscall.

Signed-off-by: Luc Michel 
---
 target/nios2/nios2-semi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
index ec88474a73..2624ef1539 100644
--- a/target/nios2/nios2-semi.c
+++ b/target/nios2/nios2-semi.c
@@ -29,10 +29,11 @@
 #include "qemu.h"
 #else
 #include "exec/softmmu-semi.h"
 #endif
 #include "qemu/log.h"
+#include "semihosting/semihost.h"
 
 #define HOSTED_EXIT  0
 #define HOSTED_INIT_SIM 1
 #define HOSTED_OPEN 2
 #define HOSTED_CLOSE 3
@@ -212,12 +213,11 @@ void do_nios2_semihosting(CPUNios2State *env)
 
 nr = env->regs[R_ARG0];
 args = env->regs[R_ARG1];
 switch (nr) {
 case HOSTED_EXIT:
-gdb_exit(env->regs[R_ARG0]);
-exit(env->regs[R_ARG0]);
+semihosting_exit_request(env->regs[R_ARG0]);
 case HOSTED_OPEN:
 GET_ARG(0);
 GET_ARG(1);
 GET_ARG(2);
 GET_ARG(3);
-- 
2.17.1




[PATCH v2 0/7] semihosting: proper QEMU exit on semihosted exit syscall

2022-06-21 Thread Luc Michel
v2:
  - fix linux-user compilation. Declare semihosting_exit_request "static
inline G_NORETURN" on CONFIG_USER_ONLY side. Use
g_assert_not_reached() to enforce the G_NORETURN since this function
is unused in linux-user mode.
  - do not call gdb_exit() in semihosting_exit_request() as it is called in
qemu_cleanup().
  - pass qemu_get_exit_status() to gdb_exit() in qemu_cleanup() instead
of 0.

Hi,

This series implements a clean way for semihosted exit syscalls to
terminate QEMU with a given return code.

Until now, exit syscalls implementations consisted in calling exit()
with the wanted return code. The problem with this approach is that
other CPUs are not properly stopped, leading to possible crashes in
MTTCG mode, especially when at_exit callbacks have been registered. This
can be the case e.g., when plugins are in use. Plugins can register
at_exit callbacks. Those will be called on the CPU thread the exit
syscall is comming from, while other CPUs can continue to run and thus
call other plugin callbacks.

The semihosting_exit_request function provides a mean to cleanly
terminate QEMU. It introduces an new exit reason
(SHUTDOWN_CAUSE_GUEST_SEMI_EXIT) used in this case. The CPU is stopped
and returns to the main CPU loop so that no more instruction get
executed (the semihosting_exit_request is declared G_NORETURN).

All targets are converted to use this new function.

Thanks,
Luc

Luc Michel (7):
  softmmu: add qemu_[set|get]_exit_status functions
  semihosting: add the semihosting_exit_request function
  semihosting/arm-compat-semi: use semihosting_exit_request
  target/m68k: use semihosting_exit_request on semihosted exit syscall
  target/mips: use semihosting_exit_request on semihosted exit syscall
  target/nios2: use semihosting_exit_request on semihosted exit syscall
  target/xtensa: use semihosting_exit_request on semihosted exit syscall

 qapi/run-state.json|  4 +++-
 include/semihosting/semihost.h |  5 +
 include/sysemu/sysemu.h|  2 ++
 semihosting/arm-compat-semi.c  |  3 +--
 semihosting/config.c   | 16 
 softmmu/main.c |  2 +-
 softmmu/runstate.c | 13 -
 target/m68k/m68k-semi.c|  4 ++--
 target/mips/tcg/sysemu/mips-semi.c |  2 +-
 target/nios2/nios2-semi.c  |  4 ++--
 target/xtensa/xtensa-semi.c|  2 +-
 11 files changed, 46 insertions(+), 11 deletions(-)

-- 
2.17.1




[PATCH v2 1/7] softmmu: add qemu_[set|get]_exit_status functions

2022-06-21 Thread Luc Michel
Add the two function qemu_set_exit_status() and qemu_get_exit_status().
Use qemu_get_exit_status() in main instead of 0 as the return value.

This is in preparation for the semihosting exit request implementation.

Signed-off-by: Luc Michel 
---
 include/sysemu/sysemu.h |  2 ++
 softmmu/main.c  |  2 +-
 softmmu/runstate.c  | 13 -
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 812f66a31a..49b6970d0e 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -103,10 +103,12 @@ void qemu_boot_set(const char *boot_order, Error **errp);
 bool defaults_enabled(void);
 
 void qemu_init(int argc, char **argv, char **envp);
 void qemu_main_loop(void);
 void qemu_cleanup(void);
+void qemu_set_exit_status(int status);
+int qemu_get_exit_status(void);
 
 extern QemuOptsList qemu_legacy_drive_opts;
 extern QemuOptsList qemu_common_drive_opts;
 extern QemuOptsList qemu_drive_opts;
 extern QemuOptsList bdrv_runtime_opts;
diff --git a/softmmu/main.c b/softmmu/main.c
index c00432ff09..67b4bb111e 100644
--- a/softmmu/main.c
+++ b/softmmu/main.c
@@ -34,11 +34,11 @@ int qemu_main(int argc, char **argv, char **envp)
 {
 qemu_init(argc, argv, envp);
 qemu_main_loop();
 qemu_cleanup();
 
-return 0;
+return qemu_get_exit_status();
 }
 
 #ifndef CONFIG_COCOA
 int main(int argc, char **argv)
 {
diff --git a/softmmu/runstate.c b/softmmu/runstate.c
index fac7b63259..a86ffa91e5 100644
--- a/softmmu/runstate.c
+++ b/softmmu/runstate.c
@@ -336,10 +336,11 @@ void vm_state_notify(bool running, RunState state)
 }
 
 static ShutdownCause reset_requested;
 static ShutdownCause shutdown_requested;
 static int shutdown_signal;
+static int exit_status;
 static pid_t shutdown_pid;
 static int powerdown_requested;
 static int debug_requested;
 static int suspend_requested;
 static WakeupReason wakeup_reason;
@@ -351,10 +352,20 @@ static NotifierList wakeup_notifiers =
 NOTIFIER_LIST_INITIALIZER(wakeup_notifiers);
 static NotifierList shutdown_notifiers =
 NOTIFIER_LIST_INITIALIZER(shutdown_notifiers);
 static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE);
 
+void qemu_set_exit_status(int status)
+{
+exit_status = status;
+}
+
+int qemu_get_exit_status(void)
+{
+return exit_status;
+}
+
 ShutdownCause qemu_shutdown_requested_get(void)
 {
 return shutdown_requested;
 }
 
@@ -779,11 +790,11 @@ void qemu_init_subsystems(void)
 }
 
 
 void qemu_cleanup(void)
 {
-gdb_exit(0);
+gdb_exit(qemu_get_exit_status());
 
 /*
  * cleaning up the migration object cancels any existing migration
  * try to do this early so that it also stops using devices.
  */
-- 
2.17.1




[PATCH v2 2/7] semihosting: add the semihosting_exit_request function

2022-06-21 Thread Luc Michel
Add the semihosting_exit_request function to be used by targets when
handling an `exit' semihosted syscall. This function calls gdb_exit to
close existing GDB connections, and qemu_system_shutdown_request with
the new `guest-semi-exit' exit reason. It sets the QEMU exit status
given by the exit syscall parameter. Finally it stops the CPU to prevent
further execution, and exit the CPU loop as the syscall caller expects
this syscall to not return.

This function is meant to be used in place of a raw exit() call when
handling semihosted `exit' syscalls. Such a call is not safe because
it does not allow other CPU threads to exit properly, leading to e.g.
at_exit callbacks being called while other CPUs still run. This can lead
to strange bugs, especially in plugins with a registered at_exit function.

Signed-off-by: Luc Michel 
---
 qapi/run-state.json|  4 +++-
 include/semihosting/semihost.h |  5 +
 semihosting/config.c   | 16 
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/qapi/run-state.json b/qapi/run-state.json
index 6e2162d7b3..a4f08dd32e 100644
--- a/qapi/run-state.json
+++ b/qapi/run-state.json
@@ -80,20 +80,22 @@
 # @guest-reset: Guest reset request, and command line turns that into
 #   a shutdown
 #
 # @guest-panic: Guest panicked, and command line turns that into a shutdown
 #
+# @guest-semi-exit: Guest exit request via a semi-hosted exit syscall
+#
 # @subsystem-reset: Partial guest reset that does not trigger QMP events and
 #   ignores --no-reboot. This is useful for sanitizing
 #   hypercalls on s390 that are used during kexec/kdump/boot
 #
 ##
 { 'enum': 'ShutdownCause',
   # Beware, shutdown_caused_by_guest() depends on enumeration order
   'data': [ 'none', 'host-error', 'host-qmp-quit', 'host-qmp-system-reset',
 'host-signal', 'host-ui', 'guest-shutdown', 'guest-reset',
-'guest-panic', 'subsystem-reset'] }
+'guest-panic', 'guest-semi-exit', 'subsystem-reset'] }
 
 ##
 # @StatusInfo:
 #
 # Information about VCPU run state
diff --git a/include/semihosting/semihost.h b/include/semihosting/semihost.h
index 0c55ade3ac..63b5641241 100644
--- a/include/semihosting/semihost.h
+++ b/include/semihosting/semihost.h
@@ -54,10 +54,14 @@ static inline const char *semihosting_get_cmdline(void)
 
 static inline Chardev *semihosting_get_chardev(void)
 {
 return NULL;
 }
+static inline G_NORETURN void semihosting_exit_request(int status)
+{
+g_assert_not_reached();
+}
 static inline void qemu_semihosting_console_init(void)
 {
 }
 #else /* !CONFIG_USER_ONLY */
 bool semihosting_enabled(void);
@@ -65,10 +69,11 @@ SemihostingTarget semihosting_get_target(void);
 const char *semihosting_get_arg(int i);
 int semihosting_get_argc(void);
 const char *semihosting_get_cmdline(void);
 void semihosting_arg_fallback(const char *file, const char *cmd);
 Chardev *semihosting_get_chardev(void);
+G_NORETURN void semihosting_exit_request(int status);
 /* for vl.c hooks */
 void qemu_semihosting_enable(void);
 int qemu_semihosting_config_options(const char *opt);
 void qemu_semihosting_connect_chardevs(void);
 void qemu_semihosting_console_init(void);
diff --git a/semihosting/config.c b/semihosting/config.c
index 3afacf54ab..e60a32a3f7 100644
--- a/semihosting/config.c
+++ b/semihosting/config.c
@@ -22,10 +22,15 @@
 #include "qemu/option.h"
 #include "qemu/config-file.h"
 #include "qemu/error-report.h"
 #include "semihosting/semihost.h"
 #include "chardev/char.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/runstate.h"
+#include "sysemu/cpus.h"
+#include "exec/exec-all.h"
+#include "exec/gdbstub.h"
 
 QemuOptsList qemu_semihosting_config_opts = {
 .name = "semihosting-config",
 .merge_lists = true,
 .implied_opt_name = "enable",
@@ -183,5 +188,16 @@ void qemu_semihosting_connect_chardevs(void)
 exit(1);
 }
 semihosting.chardev = chr;
 }
 }
+
+void semihosting_exit_request(int status)
+{
+qemu_set_exit_status(status);
+qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SEMI_EXIT);
+cpu_stop_current();
+
+current_cpu->exception_index = EXCP_HLT;
+current_cpu->halted = 1;
+cpu_loop_exit(current_cpu);
+}
-- 
2.17.1




[PATCH v2 5/7] target/mips: use semihosting_exit_request on semihosted exit syscall

2022-06-21 Thread Luc Michel
Use the new semihosting_exit_request instead of a call to exit when
handling a semihosted exit syscall.

Signed-off-by: Luc Michel 
---
 target/mips/tcg/sysemu/mips-semi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/mips/tcg/sysemu/mips-semi.c 
b/target/mips/tcg/sysemu/mips-semi.c
index b4a383ae90..94be486925 100644
--- a/target/mips/tcg/sysemu/mips-semi.c
+++ b/target/mips/tcg/sysemu/mips-semi.c
@@ -245,11 +245,11 @@ void helper_do_semihosting(CPUMIPSState *env)
 char *p, *p2;
 
 switch (op) {
 case UHI_exit:
 qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]);
-exit(gpr[4]);
+semihosting_exit_request(gpr[4]);
 case UHI_open:
 GET_TARGET_STRING(p, gpr[4]);
 if (!strcmp("/dev/stdin", p)) {
 gpr[2] = 0;
 } else if (!strcmp("/dev/stdout", p)) {
-- 
2.17.1




[PATCH v2 4/7] target/m68k: use semihosting_exit_request on semihosted exit syscall

2022-06-21 Thread Luc Michel
Use the new semihosting_exit_request instead of a call to exit when
handling a semihosted exit syscall.

Signed-off-by: Luc Michel 
---
 target/m68k/m68k-semi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c
index 37343d47e2..b3de3c6874 100644
--- a/target/m68k/m68k-semi.c
+++ b/target/m68k/m68k-semi.c
@@ -27,10 +27,11 @@
 #else
 #include "exec/softmmu-semi.h"
 #include "hw/boards.h"
 #endif
 #include "qemu/log.h"
+#include "semihosting/semihost.h"
 
 #define HOSTED_EXIT  0
 #define HOSTED_INIT_SIM 1
 #define HOSTED_OPEN 2
 #define HOSTED_CLOSE 3
@@ -193,12 +194,11 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
 uint32_t result;
 
 args = env->dregs[1];
 switch (nr) {
 case HOSTED_EXIT:
-gdb_exit(env->dregs[0]);
-exit(env->dregs[0]);
+semihosting_exit_request(env->dregs[0]);
 case HOSTED_OPEN:
 GET_ARG(0);
 GET_ARG(1);
 GET_ARG(2);
 GET_ARG(3);
-- 
2.17.1




[PATCH v2 3/7] semihosting/arm-compat-semi: use semihosting_exit_request

2022-06-21 Thread Luc Michel
Use the new semihosting_exit_request instead of a call to exit when
handling a semihosted exit syscall.

Signed-off-by: Luc Michel 
---
 semihosting/arm-compat-semi.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index b6ddaf863a..fad5116f3c 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -1253,12 +1253,11 @@ target_ulong do_common_semihosting(CPUState *cs)
  * allow the guest to specify the exit status code.
  * Everything else is considered an error.
  */
 ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
 }
-gdb_exit(ret);
-exit(ret);
+semihosting_exit_request(ret);
 case TARGET_SYS_ELAPSED:
 elapsed = get_clock() - clock_start;
 if (sizeof(target_ulong) == 8) {
 SET_ARG(0, elapsed);
 } else {
-- 
2.17.1




Re: [PATCH 0/7] semihosting: proper QEMU exit on semihosted exit syscall

2022-06-20 Thread Luc Michel
On 08:59 Mon 20 Jun , Richard Henderson wrote:
> On 6/20/22 07:24, Luc Michel wrote:
> > Hi,
> > 
> > This series implements a clean way for semihosted exit syscalls to
> > terminate QEMU with a given return code.
> > 
> > Until now, exit syscalls implementations consisted in calling exit()
> > with the wanted return code. The problem with this approach is that
> > other CPUs are not properly stopped, leading to possible crashes in
> > MTTCG mode, especially when at_exit callbacks have been registered. This
> > can be the case e.g., when plugins are in use. Plugins can register
> > at_exit callbacks. Those will be called on the CPU thread the exit
> > syscall is comming from, while other CPUs can continue to run and thus
> > call other plugin callbacks.
> > 
> > The semihosting_exit_request function provides a mean to cleanly
> > terminate QEMU. It introduces an new exit reason
> > (SHUTDOWN_CAUSE_GUEST_SEMI_EXIT) used in this case. The CPU is stopped
> > and returns to the main CPU loop so that no more instruction get
> > executed (the semihosting_exit_request is declared G_NORETURN).
> > 
> > All targets are converted to use this new function.
> 
> Did you test a complete build?  At a glance I would guess that
> arm-linux-user will no longer link because qemu_set/get_exit_status is
> missing.

You are right I forgot to test build *-linux-user. There is a
compilation issue because I forgot "static inline" on the
semihosting_exit_request function on the CONFIG_USER_ONLY side. I'll fix
that in v2.

qemu_set/get_exit_status is fine though as it is only called from
softmmu-only code (and declared in sysemu/sysemu.h).

thanks,
Luc

> 
> 
> r~
> 
> > 
> > Thanks,
> > Luc
> > 
> > Luc Michel (7):
> >softmmu: add qemu_[set|get]_exit_status functions
> >semihosting: add the semihosting_exit_request function
> >semihosting/arm-compat-semi: use semihosting_exit_request
> >target/m68k: use semihosting_exit_request on semihosted exit syscall
> >target/mips: use semihosting_exit_request on semihosted exit syscall
> >target/nios2: use semihosting_exit_request on semihosted exit syscall
> >target/xtensa: use semihosting_exit_request on semihosted exit syscall
> > 
> >   qapi/run-state.json|  4 +++-
> >   include/semihosting/semihost.h |  4 
> >   include/sysemu/sysemu.h|  2 ++
> >   semihosting/arm-compat-semi.c  |  3 +--
> >   semihosting/config.c   | 17 +
> >   softmmu/main.c |  2 +-
> >   softmmu/runstate.c | 11 +++
> >   target/m68k/m68k-semi.c|  4 ++--
> >   target/mips/tcg/sysemu/mips-semi.c |  2 +-
> >   target/nios2/nios2-semi.c  |  4 ++--
> >   target/xtensa/xtensa-semi.c|  2 +-
> >   11 files changed, 45 insertions(+), 10 deletions(-)
> > 
> 
> 
> 
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=bb16.62b09954.79e61.0=lmichel%40kalray.eu=richard.henderson%40linaro.org=Re%3A+%5BPATCH+0%2F7%5D+semihosting%3A+proper+QEMU+exit+on+semihosted+exit+syscall=C=d52db680df8df28629e4a26f18787c389730fd78
> 

-- 







Re: [PATCH 0/7] semihosting: proper QEMU exit on semihosted exit syscall

2022-06-20 Thread Luc Michel
On 15:35 Mon 20 Jun , Peter Maydell wrote:
> On Mon, 20 Jun 2022 at 15:25, Luc Michel  wrote:
> > This series implements a clean way for semihosted exit syscalls to
> > terminate QEMU with a given return code.
> >
> > Until now, exit syscalls implementations consisted in calling exit()
> > with the wanted return code. The problem with this approach is that
> > other CPUs are not properly stopped, leading to possible crashes in
> > MTTCG mode, especially when at_exit callbacks have been registered. This
> > can be the case e.g., when plugins are in use. Plugins can register
> > at_exit callbacks. Those will be called on the CPU thread the exit
> > syscall is comming from, while other CPUs can continue to run and thus
> > call other plugin callbacks.
> 
> The other option would be to say "if you register an atexit
> callback in your plugin that's your problem to sort out" :-)
> There's lots of situations where code inside QEMU might just
> call exit(), not just this one. (Mostly these are "we detected
> an error and decided to just bail out" codepaths.)

Sorry I was a bit unclear. I meant plugins using the
qemu_plugin_register_atexit_cb() register function, not directly calling
atexit(). This function documentation stats:

"Plugins should be able to free all their resources at this point much like
after a reset/uninstall callback is called."

If other CPUs are still running, this is not possible. I guess it's
reasonable to assume CPUs have reached a quiescent state when those
callbacks are called.

> 
> Is there a situation where we get a crash that doesn't involve
> code in a plugin doing something odd?

I'm not sure... I always feel a bit uncomfortable calling exit() from
a CPU thread in the middle of a translation block :)
I guess if you're monitoring QEMU through a QMP connection, it's better
to have a proper exit reason than having the connection suddenly
dropped. I guess the semihosting mode is not that popular among QEMU
users so there are probably other corner cases I'm not aware about. 

Thanks,

Luc







Re: [PATCH] accel/tcg/cpu-exec: fix precise single-stepping after interrupt

2022-06-20 Thread Luc Michel
On 16:24 Mon 20 Jun , Luc Michel wrote:
> In some cases, cpu->exit_request can be false after handling the
> interrupt, leading to another TB being executed instead of returning
> to the main loop.
> 
> Fix this by returning true unconditionally when in single-step mode.
> 
> Fixes: ba3c35d9c4026361fd380b269dc6def9510b7166
> 

Please ignore this old patch







[PATCH 6/7] target/nios2: use semihosting_exit_request on semihosted exit syscall

2022-06-20 Thread Luc Michel
Use the new semihosting_exit_request instead of a call to exit when
handling a semihosted exit syscall.

Signed-off-by: Luc Michel 
---
 target/nios2/nios2-semi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
index ec88474a73..2624ef1539 100644
--- a/target/nios2/nios2-semi.c
+++ b/target/nios2/nios2-semi.c
@@ -29,10 +29,11 @@
 #include "qemu.h"
 #else
 #include "exec/softmmu-semi.h"
 #endif
 #include "qemu/log.h"
+#include "semihosting/semihost.h"
 
 #define HOSTED_EXIT  0
 #define HOSTED_INIT_SIM 1
 #define HOSTED_OPEN 2
 #define HOSTED_CLOSE 3
@@ -212,12 +213,11 @@ void do_nios2_semihosting(CPUNios2State *env)
 
 nr = env->regs[R_ARG0];
 args = env->regs[R_ARG1];
 switch (nr) {
 case HOSTED_EXIT:
-gdb_exit(env->regs[R_ARG0]);
-exit(env->regs[R_ARG0]);
+semihosting_exit_request(env->regs[R_ARG0]);
 case HOSTED_OPEN:
 GET_ARG(0);
 GET_ARG(1);
 GET_ARG(2);
 GET_ARG(3);
-- 
2.17.1




[PATCH 3/7] semihosting/arm-compat-semi: use semihosting_exit_request

2022-06-20 Thread Luc Michel
Use the new semihosting_exit_request instead of a call to exit when
handling a semihosted exit syscall.

Signed-off-by: Luc Michel 
---
 semihosting/arm-compat-semi.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index b6ddaf863a..fad5116f3c 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -1253,12 +1253,11 @@ target_ulong do_common_semihosting(CPUState *cs)
  * allow the guest to specify the exit status code.
  * Everything else is considered an error.
  */
 ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
 }
-gdb_exit(ret);
-exit(ret);
+semihosting_exit_request(ret);
 case TARGET_SYS_ELAPSED:
 elapsed = get_clock() - clock_start;
 if (sizeof(target_ulong) == 8) {
 SET_ARG(0, elapsed);
 } else {
-- 
2.17.1




[PATCH 4/7] target/m68k: use semihosting_exit_request on semihosted exit syscall

2022-06-20 Thread Luc Michel
Use the new semihosting_exit_request instead of a call to exit when
handling a semihosted exit syscall.

Signed-off-by: Luc Michel 
---
 target/m68k/m68k-semi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c
index 37343d47e2..b3de3c6874 100644
--- a/target/m68k/m68k-semi.c
+++ b/target/m68k/m68k-semi.c
@@ -27,10 +27,11 @@
 #else
 #include "exec/softmmu-semi.h"
 #include "hw/boards.h"
 #endif
 #include "qemu/log.h"
+#include "semihosting/semihost.h"
 
 #define HOSTED_EXIT  0
 #define HOSTED_INIT_SIM 1
 #define HOSTED_OPEN 2
 #define HOSTED_CLOSE 3
@@ -193,12 +194,11 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
 uint32_t result;
 
 args = env->dregs[1];
 switch (nr) {
 case HOSTED_EXIT:
-gdb_exit(env->dregs[0]);
-exit(env->dregs[0]);
+semihosting_exit_request(env->dregs[0]);
 case HOSTED_OPEN:
 GET_ARG(0);
 GET_ARG(1);
 GET_ARG(2);
 GET_ARG(3);
-- 
2.17.1




[PATCH 0/7] semihosting: proper QEMU exit on semihosted exit syscall

2022-06-20 Thread Luc Michel
Hi,

This series implements a clean way for semihosted exit syscalls to
terminate QEMU with a given return code.

Until now, exit syscalls implementations consisted in calling exit()
with the wanted return code. The problem with this approach is that
other CPUs are not properly stopped, leading to possible crashes in
MTTCG mode, especially when at_exit callbacks have been registered. This
can be the case e.g., when plugins are in use. Plugins can register
at_exit callbacks. Those will be called on the CPU thread the exit
syscall is comming from, while other CPUs can continue to run and thus
call other plugin callbacks.

The semihosting_exit_request function provides a mean to cleanly
terminate QEMU. It introduces an new exit reason
(SHUTDOWN_CAUSE_GUEST_SEMI_EXIT) used in this case. The CPU is stopped
and returns to the main CPU loop so that no more instruction get
executed (the semihosting_exit_request is declared G_NORETURN).

All targets are converted to use this new function.

Thanks,
Luc

Luc Michel (7):
  softmmu: add qemu_[set|get]_exit_status functions
  semihosting: add the semihosting_exit_request function
  semihosting/arm-compat-semi: use semihosting_exit_request
  target/m68k: use semihosting_exit_request on semihosted exit syscall
  target/mips: use semihosting_exit_request on semihosted exit syscall
  target/nios2: use semihosting_exit_request on semihosted exit syscall
  target/xtensa: use semihosting_exit_request on semihosted exit syscall

 qapi/run-state.json|  4 +++-
 include/semihosting/semihost.h |  4 
 include/sysemu/sysemu.h|  2 ++
 semihosting/arm-compat-semi.c  |  3 +--
 semihosting/config.c   | 17 +
 softmmu/main.c |  2 +-
 softmmu/runstate.c | 11 +++
 target/m68k/m68k-semi.c|  4 ++--
 target/mips/tcg/sysemu/mips-semi.c |  2 +-
 target/nios2/nios2-semi.c  |  4 ++--
 target/xtensa/xtensa-semi.c|  2 +-
 11 files changed, 45 insertions(+), 10 deletions(-)

-- 
2.17.1




[PATCH 1/7] softmmu: add qemu_[set|get]_exit_status functions

2022-06-20 Thread Luc Michel
Add the two function qemu_set_exit_status() and qemu_get_exit_status().
Use qemu_get_exit_status() in main instead of 0 as the return value.

This is in preparation for the semihosting exit request implementation.

Signed-off-by: Luc Michel 
---
 include/sysemu/sysemu.h |  2 ++
 softmmu/main.c  |  2 +-
 softmmu/runstate.c  | 11 +++
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 812f66a31a..49b6970d0e 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -103,10 +103,12 @@ void qemu_boot_set(const char *boot_order, Error **errp);
 bool defaults_enabled(void);
 
 void qemu_init(int argc, char **argv, char **envp);
 void qemu_main_loop(void);
 void qemu_cleanup(void);
+void qemu_set_exit_status(int status);
+int qemu_get_exit_status(void);
 
 extern QemuOptsList qemu_legacy_drive_opts;
 extern QemuOptsList qemu_common_drive_opts;
 extern QemuOptsList qemu_drive_opts;
 extern QemuOptsList bdrv_runtime_opts;
diff --git a/softmmu/main.c b/softmmu/main.c
index c00432ff09..67b4bb111e 100644
--- a/softmmu/main.c
+++ b/softmmu/main.c
@@ -34,11 +34,11 @@ int qemu_main(int argc, char **argv, char **envp)
 {
 qemu_init(argc, argv, envp);
 qemu_main_loop();
 qemu_cleanup();
 
-return 0;
+return qemu_get_exit_status();
 }
 
 #ifndef CONFIG_COCOA
 int main(int argc, char **argv)
 {
diff --git a/softmmu/runstate.c b/softmmu/runstate.c
index fac7b63259..d2491b8a59 100644
--- a/softmmu/runstate.c
+++ b/softmmu/runstate.c
@@ -336,10 +336,11 @@ void vm_state_notify(bool running, RunState state)
 }
 
 static ShutdownCause reset_requested;
 static ShutdownCause shutdown_requested;
 static int shutdown_signal;
+static int exit_status;
 static pid_t shutdown_pid;
 static int powerdown_requested;
 static int debug_requested;
 static int suspend_requested;
 static WakeupReason wakeup_reason;
@@ -351,10 +352,20 @@ static NotifierList wakeup_notifiers =
 NOTIFIER_LIST_INITIALIZER(wakeup_notifiers);
 static NotifierList shutdown_notifiers =
 NOTIFIER_LIST_INITIALIZER(shutdown_notifiers);
 static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE);
 
+void qemu_set_exit_status(int status)
+{
+exit_status = status;
+}
+
+int qemu_get_exit_status(void)
+{
+return exit_status;
+}
+
 ShutdownCause qemu_shutdown_requested_get(void)
 {
 return shutdown_requested;
 }
 
-- 
2.17.1




[PATCH 2/7] semihosting: add the semihosting_exit_request function

2022-06-20 Thread Luc Michel
Add the semihosting_exit_request function to be used by targets when
handling an `exit' semihosted syscall. This function calls gdb_exit to
close existing GDB connections, and qemu_system_shutdown_request with
the new `guest-semi-exit' exit reason. It sets the QEMU exit status
given by the exit syscall parameter. Finally it stops the CPU to prevent
further execution, and exit the CPU loop as the syscall caller expects
this syscall to not return.

This function is meant to be used in place of a raw exit() call when
handling semihosted `exit' syscalls. Such a call is not safe because
it does not allow other CPU threads to exit properly, leading to e.g.
at_exit callbacks being called while other CPUs still run. This can lead
to strange bugs, especially in plugins with a registered at_exit function.

Signed-off-by: Luc Michel 
---
 qapi/run-state.json|  4 +++-
 include/semihosting/semihost.h |  4 
 semihosting/config.c   | 17 +
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/qapi/run-state.json b/qapi/run-state.json
index 6e2162d7b3..a4f08dd32e 100644
--- a/qapi/run-state.json
+++ b/qapi/run-state.json
@@ -80,20 +80,22 @@
 # @guest-reset: Guest reset request, and command line turns that into
 #   a shutdown
 #
 # @guest-panic: Guest panicked, and command line turns that into a shutdown
 #
+# @guest-semi-exit: Guest exit request via a semi-hosted exit syscall
+#
 # @subsystem-reset: Partial guest reset that does not trigger QMP events and
 #   ignores --no-reboot. This is useful for sanitizing
 #   hypercalls on s390 that are used during kexec/kdump/boot
 #
 ##
 { 'enum': 'ShutdownCause',
   # Beware, shutdown_caused_by_guest() depends on enumeration order
   'data': [ 'none', 'host-error', 'host-qmp-quit', 'host-qmp-system-reset',
 'host-signal', 'host-ui', 'guest-shutdown', 'guest-reset',
-'guest-panic', 'subsystem-reset'] }
+'guest-panic', 'guest-semi-exit', 'subsystem-reset'] }
 
 ##
 # @StatusInfo:
 #
 # Information about VCPU run state
diff --git a/include/semihosting/semihost.h b/include/semihosting/semihost.h
index 0c55ade3ac..9a3214a0c8 100644
--- a/include/semihosting/semihost.h
+++ b/include/semihosting/semihost.h
@@ -54,10 +54,13 @@ static inline const char *semihosting_get_cmdline(void)
 
 static inline Chardev *semihosting_get_chardev(void)
 {
 return NULL;
 }
+void semihosting_exit_request(int status)
+{
+}
 static inline void qemu_semihosting_console_init(void)
 {
 }
 #else /* !CONFIG_USER_ONLY */
 bool semihosting_enabled(void);
@@ -65,10 +68,11 @@ SemihostingTarget semihosting_get_target(void);
 const char *semihosting_get_arg(int i);
 int semihosting_get_argc(void);
 const char *semihosting_get_cmdline(void);
 void semihosting_arg_fallback(const char *file, const char *cmd);
 Chardev *semihosting_get_chardev(void);
+G_NORETURN void semihosting_exit_request(int status);
 /* for vl.c hooks */
 void qemu_semihosting_enable(void);
 int qemu_semihosting_config_options(const char *opt);
 void qemu_semihosting_connect_chardevs(void);
 void qemu_semihosting_console_init(void);
diff --git a/semihosting/config.c b/semihosting/config.c
index 3afacf54ab..7913c83033 100644
--- a/semihosting/config.c
+++ b/semihosting/config.c
@@ -22,10 +22,15 @@
 #include "qemu/option.h"
 #include "qemu/config-file.h"
 #include "qemu/error-report.h"
 #include "semihosting/semihost.h"
 #include "chardev/char.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/runstate.h"
+#include "sysemu/cpus.h"
+#include "exec/exec-all.h"
+#include "exec/gdbstub.h"
 
 QemuOptsList qemu_semihosting_config_opts = {
 .name = "semihosting-config",
 .merge_lists = true,
 .implied_opt_name = "enable",
@@ -183,5 +188,17 @@ void qemu_semihosting_connect_chardevs(void)
 exit(1);
 }
 semihosting.chardev = chr;
 }
 }
+
+void semihosting_exit_request(int status)
+{
+gdb_exit(status);
+qemu_set_exit_status(status);
+qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SEMI_EXIT);
+cpu_stop_current();
+
+current_cpu->exception_index = EXCP_HLT;
+current_cpu->halted = 1;
+cpu_loop_exit(current_cpu);
+}
-- 
2.17.1




[PATCH 7/7] target/xtensa: use semihosting_exit_request on semihosted exit syscall

2022-06-20 Thread Luc Michel
Use the new semihosting_exit_request instead of a call to exit when
handling a semihosted exit syscall.

Signed-off-by: Luc Michel 
---
 target/xtensa/xtensa-semi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/xtensa/xtensa-semi.c b/target/xtensa/xtensa-semi.c
index fa21b7e11f..0e9a9edc16 100644
--- a/target/xtensa/xtensa-semi.c
+++ b/target/xtensa/xtensa-semi.c
@@ -193,11 +193,11 @@ void HELPER(simcall)(CPUXtensaState *env)
 CPUState *cs = env_cpu(env);
 uint32_t *regs = env->regs;
 
 switch (regs[2]) {
 case TARGET_SYS_exit:
-exit(regs[3]);
+semihosting_exit_request(regs[3]);
 break;
 
 case TARGET_SYS_read:
 case TARGET_SYS_write:
 {
-- 
2.17.1




  1   2   3   4   5   6   7   >