Data Driven device registers & Zynq DEVCFG
Subsystems (2)
v2 cover Data Driven device registers & Zynq DEVCFG
Hi All. This is a new scheme i've come up with handling device registers in a data driven way. My motivation for this is to factor out a lot of the access checking that seems to be replicated in every device. See P2 commit message for further discussion.
P1 is a trivial addition to bitops.h
P2 is the main patch, adds the register definition functionality P3 is an example new device (the Xilinx Zynq devcfg) that uses this scheme. P4 adds devcfg to the Zynq machine model
This devcfg device was particularly finnicky with per-bit restrictions which prompted all this. Im also looking for a higher-than-usual modelling fidelity on the register space, with semantics defined for random reserved bits in-between otherwise consistent fields.
Heres an example of the qemu_log output for the devcfg device. This is produced by now generic sharable code:
/machine/unattached/device[44]:Addr 0x000008:CFG: write of value 00000508 /machine/unattached/device[44]:Addr 0x000080:MCTRL: write of value 00800010 /machine/unattached/device[44]:Addr 0x000010:INT_MASK: write of value ffffffff /machine/unattached/device[44]:Addr 00000000:CTRL: write of value 0c00607f
And an example of a rogue guest banging on a bad bit:
/machine/unattached/device[44]:Addr 0x000014:STATUS bits 0x000001 may not be \
written to 1
Future work: Theres a lot of overlap here with what Peter did with the ARM coprocessor definitions. We could go further and generalise ARM CP to use this or some further evolution of it. That and converting existing models to this scheme. Some device models will lose a lot of weight. Also integrate with memory API.
Changed from v1:
Added ONES macro patch
Dropped bogus former patch 1 (PMM review)
Addressed Blue, Gerd and MST comments.
Simplified to be more Memory API compatible.
Added Memory API helpers.
Please see discussion already on list and commit msgs for more detail.
Peter A. G. Crosthwaite (2):
xilinx_devcfg: Zynq devcfg device model
xilinx_zynq: added devcfg to machine model
Peter Crosthwaite (3):
bitops: Add ONES macro
register: Add Register API
register: Add Memory API glue
Makefile.target | 2 +- hw/arm/Makefile.objs | 2 +- hw/arm/xilinx_zynq.c | 8 + hw/xilinx_devcfg.c | 489 +++++++++++++++++++++++++++++++++++++++++++++++ include/exec/register.h | 147 ++++++++++++++ include/qemu/bitops.h | 2 + register.c | 207 ++++++++++++++++++++ 7 files changed, 855 insertions(+), 2 deletions(-) create mode 100644 hw/xilinx_devcfg.c create mode 100644 include/exec/register.h create mode 100644 register.c
PATCH v2 1/5 bitops: Add ONES macro
Little macro that just gives you N ones (justified to LSB).
---
include/qemu/bitops.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
include/qemu/bitops.h +2 -0
@@ -273,4 +273,6 @@ static inline uint64_t deposit64(uint64_t value, int start, int length, return (value & ~mask) | ((fieldval << start) & mask); } +#define ONES (num) ((num) == 64 ? ~0ull : (1ull << (num)) - 1) +#endif
Signature · 1 line
1.7.0.4
Re: [Qemu-devel] [PATCH v2 1/5] bitops: Add ONES macro
Quoted 13 lines · Peter Crosthwaite
Little macro that just gives you N ones (justified to LSB).
Signed-off-by Peter Crosthwaite <[email protected]>---
include/qemu/bitops.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)include/qemu/bitops.h +0
-0
include/qemu/bitops.h static inline uint64_t deposit64(uint64_t value, int start, int length, · line 276
Quoted 4 lines
include/qemu/bitops.h +1
-0@@ -273,4 +273,6 @@ static inline uint64_t deposit64(uint64_t value, int start, int length,return (value & ~mask) | ((fieldval << start) & mask); } +#define ONES (num) ((num) == 64 ? ~0ull : (1ull << (num)) - 1)
You can avoid the ?: here (assuming you're happy to say that ONES(0) is a silly thing to ask for):
#define ONES(num) (~0ULL >> (64 - (num)))
Needs a documentation comment, anyway.
thanks
-- PMM
Re: [Qemu-devel] [PATCH v2 1/5] bitops: Add ONES macro
Hi Peter,
Quoted 17 lines · Peter Maydell
Quoted 16 lines · Peter Crosthwaite
Little macro that just gives you N ones (justified to LSB).
Signed-off-by Peter Crosthwaite <[email protected]>---
include/qemu/bitops.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)include/qemu/bitops.h +0
-0@@ -273,4 +273,6 @@ static inline uint64_t deposit64(uint64_t value, int start, int length,return (value & ~mask) | ((fieldval << start) & mask); }
Quoted 5 lines
include/qemu/bitops.h static inline uint64_t deposit64(uint64_t value, int start, int length, · line 276
Quoted 1 line
include/qemu/bitops.h +1
-0+#define ONES (num) ((num) == 64 ? ~0ull : (1ull << (num)) - 1)You can avoid the ?: here (assuming you're happy to say that ONES(0) is a silly thing to ask for):
Not that silly. ONES(0) should just stay true to the contract and return 0. Otherwise prospective clients may have to guard against 0 cases in loops which is ugly:
for (i = 0; i < N; i++) {
....
mask = ONES(i); /* rather than ones = i ? ones(i) : 0 */
....
}But I thought about this more, and perhaps just ditch the ? anyway, and rely on the shift by 64 ending up as 0. Then the -1 should return return 64 (all) ones anyway.
Quoted 4 lines
#define ONES(num) (~0ULL >> (64 - (num)))
Needs a documentation comment, anyway.
OK
Regards,
Peter
Quoted 3 lines
thanks
-- PMM
Re: [Qemu-devel] [PATCH v2 1/5] bitops: Add ONES macro
Quoted 2 lines · Peter Crosthwaite
But I thought about this more, and perhaps just ditch the ? anyway, and rely on the shift by 64 ending up as 0.
That's undefined behaviour, please don't.
-- PMM
PATCH v2 2/5 register: Add Register API
In reply to Peter CrosthwaiteThis API provides some encapsulation of registers and factors our some common functionality to common code. Bits of device state (usually MMIO registers), often have all sorts of access restrictions and semantics associated with them. This API allow you to define what those restrictions are on a bit-by-bit basis.
Helper functions are then used to access the register which observe the semantics defined by the RegisterAccessInfo struct.
Some features:
Bits can be marked as read_only (ro field)
Bits can be marked as write-1-clear (w1c field)
Bits can be marked as write only (wo)
Bits can be marked as sticky (nw0 and nw1)
Reset values can be defined (reset)
Bits can throw guest errors when written certain values (ge0, ge1) Bits can throw unimp errors when written certain values (ui0, ui1) Bits can be marked clear on read (cor)
Pre and post action callbacks can be added to read and write ops Verbose debugging info can be enabled/disabled
Useful for defining device register spaces in a data driven way. Cuts down on a lot of the verbosity and repetition in the switch-case blocks in the standard foo_mmio_read/write functions.
---
changed from v1:
Rebranded as the "Register API" - I think thats probably what it is. Near total rewrite of implementation.
De-arrayified reset (this is client/Memory APIs job).
Moved out of bitops into its own file (Blue review)
Added debug, the register pointer, and prefix to a struct (Blue Review) Made 64-bit to play friendlier with memory API (Blue review) Made backend storage uint8_t (MST review)
Added read/write callbacks (Blue review)
Added ui0, ui1 (Blue review)
Moved re-purposed width (now byte width defining actual storage size) Arrayified ge0, ge1 (ui0, ui1 too) and added .reason
Added wo field (not an April fools joke - this has genuine meaning here) Added we mask to write accessor
Makefile.target | 2 +- include/exec/register.h | 134 ++++++++++++++++++++++++++++++++++++++ register.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 299 insertions(+), 1 deletions(-) create mode 100644 include/exec/register.h create mode 100644 register.c
Makefile.target +1 -1
@@ -114,7 +114,7 @@ obj-y += hw/ obj-$(CONFIG_FDT) += device_tree.o obj-$(CONFIG_KVM) += kvm-all.o obj-$(CONFIG_NO_KVM) += kvm-stub.o -obj-y += memory.o savevm.o cputlb.o +obj-y += memory.o register.o savevm.o cputlb.o obj-$(CONFIG_HAVE_GET_MEMORY_MAPPING) += memory_mapping.o obj-$(CONFIG_HAVE_CORE_DUMP) += dump.o obj-$(CONFIG_NO_GET_MEMORY_MAPPING) += memory_mapping-stub.o
include/exec/register.h new file +134 -0
134 lines not on this page · raw message
register.c new file +164 -0
164 lines not on this page · raw message
Signature · 1 line
1.7.0.4
Re: [Qemu-devel] [PATCH v2 2/5] register: Add Register API
Quoted 68 lines · Peter Crosthwaite
This API provides some encapsulation of registers and factors our some common functionality to common code. Bits of device state (usually MMIO registers), often have all sorts of access restrictions and semantics associated with them. This API allow you to define what those restrictions are on a bit-by-bit basis.
register.c new file +63
-0+void register_write (RegisterInfo *reg,uint64_t val,uint64_t we) +{ +uint64_t old_val, new_val, test; +const RegisterAccessInfo *ac; +const RegisterAccessError *rae; + +assert (reg); + + ac = reg->access; +if (!ac || !ac->name) { +qemu_log_mask (LOG_GUEST_ERROR ,"%s: write to undefined device state " +"(written value: %#" PRIx64")\n" , reg->prefix, val); +return ; + } + +uint32_t no_w0_mask = ac->ro | ac->w1c | ac->nw0 | ~we; +uint32_t no_w1_mask = ac->ro | ac->w1c | ac->nw1 | ~we; + +if (reg->debug) { +fprintf (stderr,"%s:%s: write of value %#" PRIx64"\n" , reg->prefix, + ac->name, val); + } + +if (qemu_loglevel_mask (LOG_GUEST_ERROR )) { +for (rae = ac->ge1; rae && rae->mask; rae++) { + test = val & rae->mask; +if (test) { +register_write_log (reg,1 , test,LOG_GUEST_ERROR , +"invalid" , rae->reason); + } + } +for (rae = ac->ge0; rae && rae->mask; rae++) { + test = val & rae->mask; +if (test) { +register_write_log (reg,0 , test,LOG_GUEST_ERROR , +"invalid" , rae->reason); + } + } + } + +if (qemu_loglevel_mask (LOG_UNIMP )) { +for (rae = ac->ui1; rae && rae->mask; rae++) { + test = val & rae->mask; +if (test) { +register_write_log (reg,1 , test,LOG_GUEST_ERROR , +"unimplmented" , rae->reason); + } + } +for (rae = ac->ui0; rae && rae->mask; rae++) { + test = val & rae->mask; +if (test) { +register_write_log (reg,0 , test,LOG_GUEST_ERROR , +"unimplemented" , rae->reason); + } + } + } + +assert (reg->data); + old_val =register_read_val (reg); + + new_val = val & ~(no_w1_mask & val); + new_val |= no_w1_mask & old_val & val; + new_val |= no_w0_mask & old_val & ~val;
register.c line 117
Quoted 10 lines
register.c new file +10
-0+ new_val &= ~(val & ac->w1c); + +if (ac->pre_write) { + new_val = ac->pre_write (reg, new_val); + } +register_write_val (reg, new_val); +if (ac->post_write) { + ac->post_write (reg, new_val); + } +}
Wow, this feels pretty heavyweight for "write a register"...
-- PMM
Re: [Qemu-devel] [PATCH v2 2/5] register: Add Register API
Quoted 73 lines · Peter Maydell
Quoted 72 lines · Peter Crosthwaite
This API provides some encapsulation of registers and factors our some common functionality to common code. Bits of device state (usually MMIO registers), often have all sorts of access restrictions and semantics associated with them. This API allow you to define what those restrictions are on a bit-by-bit basis.
register.c new file +67
-0+void register_write (RegisterInfo *reg,uint64_t val,uint64_t we) +{ +uint64_t old_val, new_val, test; +const RegisterAccessInfo *ac; +const RegisterAccessError *rae; + +assert (reg); + + ac = reg->access; +if (!ac || !ac->name) { +qemu_log_mask (LOG_GUEST_ERROR ,"%s: write to undefined device state " +"(written value: %#" PRIx64")\n" , reg->prefix, val); +return ; + } + +uint32_t no_w0_mask = ac->ro | ac->w1c | ac->nw0 | ~we; +uint32_t no_w1_mask = ac->ro | ac->w1c | ac->nw1 | ~we; + +if (reg->debug) { +fprintf (stderr,"%s:%s: write of value %#" PRIx64"\n" , reg->prefix, + ac->name, val); + } + +if (qemu_loglevel_mask (LOG_GUEST_ERROR )) { +for (rae = ac->ge1; rae && rae->mask; rae++) { + test = val & rae->mask; +if (test) { +register_write_log (reg,1 , test,LOG_GUEST_ERROR , +"invalid" , rae->reason); + } + } +for (rae = ac->ge0; rae && rae->mask; rae++) { + test = val & rae->mask; +if (test) { +register_write_log (reg,0 , test,LOG_GUEST_ERROR , +"invalid" , rae->reason); + } + } + } + +if (qemu_loglevel_mask (LOG_UNIMP )) { +for (rae = ac->ui1; rae && rae->mask; rae++) { + test = val & rae->mask; +if (test) { +register_write_log (reg,1 , test,LOG_GUEST_ERROR , +"unimplmented" , rae->reason); + } + } +for (rae = ac->ui0; rae && rae->mask; rae++) { + test = val & rae->mask; +if (test) { +register_write_log (reg,0 , test,LOG_GUEST_ERROR , +"unimplemented" , rae->reason); + } + } + } + +assert (reg->data); + old_val =register_read_val (reg); + + new_val = val & ~(no_w1_mask & val); + new_val |= no_w1_mask & old_val & val; + new_val |= no_w0_mask & old_val & ~val; + new_val &= ~(val & ac->w1c); + +if (ac->pre_write) { + new_val = ac->pre_write (reg, new_val);
Quoted 9 lines
register.c line 117
Quoted 6 lines
register.c new file +6
-0+ } +register_write_val (reg, new_val); +if (ac->post_write) { + ac->post_write (reg, new_val); + } +}Wow, this feels pretty heavyweight for "write a register"...
Its a pritty fast path through if all the optionals turned off. If I was going to lighten it up, Id get rid of the reg_size and the byte loop first although that would mandate uint64_t as the data type for the backing store.
But the intended primary usage of the API is for device control and status registers, where you are generally not interested in performance, unless you are doing some form of PIO. In that case, you can opt out on a per register basis and make yourself a fast path for the critical registers (r/w fifo heads access regs etc). This is designed for developer and debugging convenience, where you have a large number or registers with a heteorgenous mix of accesses and side effects but at the same time the registers are infrequent access. This is true of most device registers.
Another solution is some sort of "lite" mode. A single check in the definition that disables a lot of this and cuts to the chase (the actual write).
Quoted 2 lines
-- PMM
Re: [Qemu-devel] [PATCH v2 2/5] register: Add Register API
Hi Peter,
Quoted 75 lines · Peter Crosthwaite
Quoted 74 lines · Peter Maydell
Quoted 73 lines · Peter Crosthwaite
This API provides some encapsulation of registers and factors our some common functionality to common code. Bits of device state (usually MMIO registers), often have all sorts of access restrictions and semantics associated with them. This API allow you to define what those restrictions are on a bit-by-bit basis.
register.c new file +68
-0+void register_write (RegisterInfo *reg,uint64_t val,uint64_t we) +{ +uint64_t old_val, new_val, test; +const RegisterAccessInfo *ac; +const RegisterAccessError *rae; + +assert (reg); + + ac = reg->access; +if (!ac || !ac->name) { +qemu_log_mask (LOG_GUEST_ERROR ,"%s: write to undefined device state " +"(written value: %#" PRIx64")\n" , reg->prefix, val); +return ; + } + +uint32_t no_w0_mask = ac->ro | ac->w1c | ac->nw0 | ~we; +uint32_t no_w1_mask = ac->ro | ac->w1c | ac->nw1 | ~we; + +if (reg->debug) { +fprintf (stderr,"%s:%s: write of value %#" PRIx64"\n" , reg->prefix, + ac->name, val); + } + +if (qemu_loglevel_mask (LOG_GUEST_ERROR )) { +for (rae = ac->ge1; rae && rae->mask; rae++) { + test = val & rae->mask; +if (test) { +register_write_log (reg,1 , test,LOG_GUEST_ERROR , +"invalid" , rae->reason); + } + } +for (rae = ac->ge0; rae && rae->mask; rae++) { + test = val & rae->mask; +if (test) { +register_write_log (reg,0 , test,LOG_GUEST_ERROR , +"invalid" , rae->reason); + } + } + } + +if (qemu_loglevel_mask (LOG_UNIMP )) { +for (rae = ac->ui1; rae && rae->mask; rae++) { + test = val & rae->mask; +if (test) { +register_write_log (reg,1 , test,LOG_GUEST_ERROR , +"unimplmented" , rae->reason); + } + } +for (rae = ac->ui0; rae && rae->mask; rae++) { + test = val & rae->mask; +if (test) { +register_write_log (reg,0 , test,LOG_GUEST_ERROR , +"unimplemented" , rae->reason); + } + } + } + +assert (reg->data); + old_val =register_read_val (reg); + + new_val = val & ~(no_w1_mask & val); + new_val |= no_w1_mask & old_val & val; + new_val |= no_w0_mask & old_val & ~val; + new_val &= ~(val & ac->w1c); + +if (ac->pre_write) { + new_val = ac->pre_write (reg, new_val); + }
Quoted 8 lines
Quoted 8 lines
register.c line 117
Quoted 5 lines
register.c new file +5
-0+register_write_val (reg, new_val); +if (ac->post_write) { + ac->post_write (reg, new_val); + } +}Wow, this feels pretty heavyweight for "write a register"...
I have been thinking about this more, and in the interest of getting something merged, I'm happy to work on this. I could use some specific feedback however, considering there was generally positive feedback on v1 so im guessing the objections come from the v2 added features (being the byte loop, ui, we and the hooks). Here are my current "lightening" proposals:
- Add a "ne" (no/native endianess) version to the memory api handlers which just passes the args straight through to register API, no byte reversal logic needed.
- Remove nw0 and nw1, They are reasonably rare and can be handled with the odd pre_write hook for those cases.
- Add a "lite" flag that is (automatically) computed once that takes a fast path through the read/write handlers. A reg is lite if it requires no read-modify-write (no ro, nw, ge, ui, wtc). Only the actual write and post_write handlers are executed.
- Remove the byte loops. Just switch on register size and cast to uint_XXt. Remove support for non power-of-two size registers and non-host endianess (needed for potential PCI conversion) but should make the code faster.
- Make data pointer optional. No data means register is read as reset and no write occurs (post write hook only). This make wo redundant (anyone wanting to do per-bit wo semantic uses pre-write hook).
If you care about performance of a particular reg, just add a post_write hook, set it up as native endianess, with a NULL data register, no access checks. Then its a very fast path from the memory API through to your handler.
Regards,
Peter
Quoted 22 lines
Its a pritty fast path through if all the optionals turned off. If I was going to lighten it up, Id get rid of the
reg_sizeand the byte loop first although that would mandateuint64_tas the data type for the backing store.But the intended primary usage of the API is for device control and status registers, where you are generally not interested in performance, unless you are doing some form of PIO. In that case, you can opt out on a per register basis and make yourself a fast path for the critical registers (r/w fifo heads access regs etc). This is designed for developer and debugging convenience, where you have a large number or registers with a heteorgenous mix of accesses and side effects but at the same time the registers are infrequent access. This is true of most device registers.
Another solution is some sort of "lite" mode. A single check in the definition that disables a lot of this and cuts to the chase (the actual write).
Quoted 2 lines
-- PMM
Re: [Qemu-devel] [PATCH v2 2/5] register: Add Register API
Hi,
Quoted 4 lines
- Add a "lite" flag that is (automatically) computed once that takes a fast path through the read/write handlers. A reg is lite if it requires no read-modify-write (no ro, nw, ge, ui, wtc). Only the actual write and
post_writehandlers are executed.
Sounds good to me.
Quoted 4 lines
- Remove the byte loops. Just switch on register size and cast to
uint_XXt. Remove support for non power-of-two size registers and non-host endianess (needed for potential PCI conversion) but should make the code faster.
This too.
Also: you might want to pass both old and new value to the post-write hook so the handler can easily figure what has actually changed.
cheers,
Gerd
PATCH v2 3/5 register: Add Memory API glue
In reply to Peter CrosthwaiteAdd memory io handlers that glue the register API to the memory API. Just translation functions at this stage. Although it does allow for devices to be created without all-in-one mmio r/w handlers.
---
include/exec/register.h | 13 +++++++++++++ register.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 0 deletions(-)
include/exec/register.h +13 -0
@@ -13,6 +13,7 @@#include <stdint.h> #include <stdbool.h> +#include "exec/memory.h" typedef struct RegisterInfo RegisterInfo ;typedef struct RegisterAccessInfo RegisterAccessInfo ;
@@ -92,6 +93,8 @@ struct RegisterAccessInfo {* @prefix: String prefix for log and debug messages * * @opaque: Opaque data for the register +* +* @mem: optional Memory region for the register */ struct RegisterInfo {
@@ -105,6 +108,8 @@ struct RegisterInfo {const char *prefix;void *opaque; + +MemoryRegion mem; };/**
@@ -131,4 +136,12 @@ uint64_t register_read(RegisterInfo *reg);void register_reset (RegisterInfo *reg); +void register_write_memory_be (void *opaque,hwaddr addr,uint64_t value, +unsigned size); +void register_write_memory_le (void *opaque,hwaddr addr,uint64_t value, +unsigned size); + +uint64_t register_read_memory_be (void *opaque,hwaddr addr,unsigned size); +uint64_t register_read_memory_le (void *opaque,hwaddr addr,unsigned size); +#endif
register.c +43 -0
46 lines not on this page · raw message
Signature · 1 line
1.7.0.4
Re: [Qemu-devel] [PATCH v2 3/5] register: Add Memory API glue
Il 05/04/2013 10:43, Peter Crosthwaite ha scritto:
Quoted 8 lines
Add memory io handlers that glue the register API to the memory API. Just translation functions at this stage. Although it does allow for devices to be created without all-in-one mmio r/w handlers.
Signed-off-by Peter Crosthwaite <[email protected]>---
include/exec/register.h | 13 +++++++++++++
Please put it in include/hw/.
Putting these five in exec/ was a mistake:
#include "exec/address-spaces.h"
#include "exec/hwaddr.h"
#include "exec/ioport.h"
#include "exec/iorange.h"
#include "exec/memory.h"
Most files in hw/ should not need include/exec/.
Quoted 1 line
register.c | 43 +++++++++++++++++++++++++++++++++++++++++++
If my reorganization goes in before, please make it hw/core/register.c.
The next step in the reorganization would be to move memory.c to hw/core too.
Paolo
PATCH v2 4/5 xilinx_devcfg: Zynq devcfg device model
In reply to Peter CrosthwaiteFrom: Peter A. G. Crosthwaite <[email protected]>
Minimal device model for devcfg module of Zynq. DMA capabilities and interrupt generation supported.
---
Changed since v1:
Rebased against new version of Register API.
Use action callbacks for side effects rather than switch. Documented reasons for ge0, ge1 (Verbatim from TRM) Added ui1 definitions for unimplemented major features Removed dead lock code
hw/arm/Makefile.objs | 2 +- hw/xilinx_devcfg.c | 489 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 490 insertions(+), 1 deletions(-) create mode 100644 hw/xilinx_devcfg.c
hw/arm/Makefile.objs +1 -1
@@ -1,4 +1,4 @@ -obj-y += zynq_slcr.o +obj-y += zynq_slcr.o xilinx_devcfg.o obj-y += xilinx_spips.o obj-y += arm_gic.o arm_gic_common.o obj-y += a9scu.o
hw/xilinx_devcfg.c new file +489 -0
489 lines not on this page · raw message
Signature · 1 line
1.7.0.4
PATCH v2 5/5 xilinx_zynq: added devcfg to machine model
In reply to Peter CrosthwaiteFrom: Peter A. G. Crosthwaite <[email protected]>
---
Changed since v1:
Added manual parenting of devcfg node (evil but needed for early access to canonical path by devcfgs realize fn).
hw/arm/xilinx_zynq.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-)
hw/arm/xilinx_zynq.c +8 -0
@@ -220,6 +220,14 @@ static void zynq_init(QEMUMachineInitArgs *args)sysbus_connect_irq (busdev, n +1 , pic[dma_irqs[n] -IRQ_OFFSET ]); } + dev =qdev_create (NULL ,"xlnx.ps7-dev-cfg" ); +object_property_add_child (qdev_get_machine (),"xilinx-devcfg" ,OBJECT (dev), +NULL ); +qdev_init_nofail (dev); + busdev =SYS_BUS_DEVICE (dev); +sysbus_connect_irq (busdev,0 , pic[40 -IRQ_OFFSET ]); +sysbus_mmio_map (busdev,0 ,0xF8007000 ); + zynq_binfo.ram_size = ram_size; zynq_binfo.kernel_filename = kernel_filename; zynq_binfo.kernel_cmdline = kernel_cmdline;
Signature · 1 line
1.7.0.4