On 16/07/2015 10:35, Efimov Vasily wrote:
> This patch improves PAM emulation.
> 
> PAM defines 4 memory access redirection modes. In mode 1 reads are directed to
> RAM and writes are directed to PCI. In mode 2 it is contrary. In mode 0 all
> access is directed to PCI. In mode 3 it is directed to RAM. Modes 0 and 3 are
> well emulated but modes 1 and 2 are not. The cause is: aliases are used
> while more complicated logic is required.
> 
> The idea is to use ROM device like memory regions for mode 1 and 2 emulation
> instead of aliases. Writes are directed to proper destination region by
> specified I/O callback. Read redirection depends on type of source region.
> In most cases source region is RAM (or ROM), so ram_addr of PAM region is set 
> to
> ram_addr of source region with offset. Otherwise, when source region is an I/O
> region, reading is redirected to source region read callback by PAM region 
> one.
> 
> Read source and write destination regions are updated by the memory
> commit callback.
> 
> Note that we cannot use I/O region for PAM as it will violate "trying to 
> execute
> code outside RAM or ROM" assertion.
> 
> Signed-off-by: Efimov Vasily <r...@ispras.ru>
> ---
>  hw/pci-host/pam.c         | 238 
> +++++++++++++++++++++++++++++++++++++++++-----
>  include/hw/pci-host/pam.h |  10 +-
>  2 files changed, 223 insertions(+), 25 deletions(-)
> 
> diff --git a/hw/pci-host/pam.c b/hw/pci-host/pam.c
> index 17d826c..9729b2b 100644
> --- a/hw/pci-host/pam.c
> +++ b/hw/pci-host/pam.c
> @@ -27,43 +27,233 @@
>   * THE SOFTWARE.
>   */
>  
> -#include "qom/object.h"
> -#include "sysemu/sysemu.h"
>  #include "hw/pci-host/pam.h"
> +#include "exec/address-spaces.h"
> +#include "exec/memory-internal.h"
> +#include "qemu/bswap.h"
> +
> +static void pam_write(void *opaque, hwaddr addr, uint64_t data,
> +                      unsigned size)
> +{
> +    PAMMemoryRegion *pam = (PAMMemoryRegion *) opaque;
> +    void *ptr;
> +
> +    /* Destination region can be both RAM and IO. */
> +    if (!memory_access_is_direct(pam->mr_write_to, true)) {
> +        memory_region_dispatch_write(pam->mr_write_to,
> +                                     addr + pam->write_offset, data, size,
> +                                     MEMTXATTRS_UNSPECIFIED);
> +    } else {
> +        ptr = memory_region_get_ram_ptr(pam->mr_write_to) + addr
> +                                                          + 
> pam->write_offset;
> +
> +        switch (size) {
> +        case 1:
> +            stb_p(ptr, data);
> +            break;
> +        case 2:
> +            stw_he_p(ptr, data);
> +            break;
> +        case 4:
> +            stl_he_p(ptr, data);
> +            break;
> +        case 8:
> +            stq_he_p(ptr, data);
> +            break;
> +        default:
> +            abort();
> +        }
> +
> +        invalidate_and_set_dirty(pam->mr_write_to, addr + pam->pam_offset,
> +                                 size);
> +    }
> +}
> +

The idea is very good, but the implementation relies on copying a lot of
code from exec.c.

Could you use an IOMMU memory region instead?  Then a single region can
be used to implement all four modes, and you don't hit the "trying to
execute code outside RAM or RAM".

Paolo

Reply via email to