/qapi/qapi-types-*.[ch]
/qapi/qapi-types.[ch]
/qapi/qapi-visit-*.[ch]
+!/qapi/qapi-visit-core.c
/qapi/qapi-visit.[ch]
/qapi/qapi-doc.texi
/qemu-doc.html
F: contrib/vhost-user-input/*
virtio-serial
-M: Amit Shah <amit@kernel.org>
+M: Laurent Vivier <lvivier@redhat.com>
+R: Amit Shah <amit@kernel.org>
S: Supported
F: hw/char/virtio-serial-bus.c
F: hw/char/virtio-console.c
F: tests/virtio-serial-test.c
virtio-rng
-M: Amit Shah <amit@kernel.org>
+M: Laurent Vivier <lvivier@redhat.com>
+R: Amit Shah <amit@kernel.org>
S: Supported
F: hw/virtio/virtio-rng.c
F: include/hw/virtio/virtio-rng.h
endif
endif
+# Sphinx does not allow building manuals into the same directory as
+# the source files, so if we're doing an in-tree QEMU build we must
+# build the manuals into a subdirectory (and then install them from
+# there for 'make install'). For an out-of-tree build we can just
+# use the docs/ subdirectory in the build tree as normal.
+ifeq ($(realpath $(SRC_PATH)),$(realpath .))
+MANUAL_BUILDDIR := docs/built
+else
+MANUAL_BUILDDIR := docs
+endif
+
ifdef BUILD_DOCS
-DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 docs/interop/qemu-ga.8
+DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 $(MANUAL_BUILDDIR)/interop/qemu-ga.8
DOCS+=docs/interop/qemu-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7
DOCS+=docs/interop/qemu-ga-ref.html docs/interop/qemu-ga-ref.txt docs/interop/qemu-ga-ref.7
DOCS+=docs/qemu-block-drivers.7
qemu-%.tar.bz2:
$(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2,%,$@)"
-# Sphinx does not allow building manuals into the same directory as
-# the source files, so if we're doing an in-tree QEMU build we must
-# build the manuals into a subdirectory (and then install them from
-# there for 'make install'). For an out-of-tree build we can just
-# use the docs/ subdirectory in the build tree as normal.
-ifeq ($(realpath $(SRC_PATH)),$(realpath .))
-MANUAL_BUILDDIR := docs/built
-else
-MANUAL_BUILDDIR := docs
-endif
-
define clean-manual =
rm -rf $(MANUAL_BUILDDIR)/$1/_static
rm -f $(MANUAL_BUILDDIR)/$1/objects.inv $(MANUAL_BUILDDIR)/$1/searchindex.js $(MANUAL_BUILDDIR)/$1/*.html
$(INSTALL_DATA) scripts/qemu-trace-stap.1 "$(DESTDIR)$(mandir)/man1"
endif
ifneq (,$(findstring qemu-ga,$(TOOLS)))
- $(INSTALL_DATA) docs/interop/qemu-ga.8 "$(DESTDIR)$(mandir)/man8"
+ $(INSTALL_DATA) $(MANUAL_BUILDDIR)/interop/qemu-ga.8 "$(DESTDIR)$(mandir)/man8"
$(INSTALL_DATA) docs/interop/qemu-ga-ref.html "$(DESTDIR)$(qemu_docdir)"
$(INSTALL_DATA) docs/interop/qemu-ga-ref.txt "$(DESTDIR)$(qemu_docdir)"
$(INSTALL_DATA) docs/interop/qemu-ga-ref.7 "$(DESTDIR)$(mandir)/man7"
trace-events-subdirs += target/s390x
trace-events-subdirs += target/sparc
trace-events-subdirs += util
+trace-events-subdirs += hw/core
trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)
b->vdev = vdev;
b->dev.nvqs = nvqs;
- b->dev.vqs = g_new(struct vhost_virtqueue, nvqs);
+ b->dev.vqs = g_new0(struct vhost_virtqueue, nvqs);
ret = vhost_dev_init(&b->dev, &b->vhost_user, VHOST_BACKEND_TYPE_USER, 0);
if (ret < 0) {
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
+#include "qemu/cutils.h"
#include "block/qapi.h"
#include "block/block_int.h"
#include "block/throttle-groups.h"
;;
--disable-libpmem) libpmem=no
;;
+ --enable-xkbcommon) xkbcommon=yes
+ ;;
+ --disable-xkbcommon) xkbcommon=no
+ ;;
*)
echo "ERROR: unknown option $opt"
echo "Try '$0 --help' for more information"
capstone capstone disassembler support
debug-mutex mutex debugging support
libpmem libpmem support
+ xkbcommon xkbcommon support
NOTE: The object files are built at the place where configure is launched
EOF
--- /dev/null
+ QEMU Barrier Client
+
+
+* About
+
+ Barrier is a KVM (Keyboard-Video-Mouse) software forked from Symless's
+ synergy 1.9 codebase.
+
+ See https://github.com/debauchee/barrier
+
+* QEMU usage
+
+ Generally, mouse and keyboard are grabbed through the QEMU video
+ interface emulation.
+
+ But when we want to use a video graphic adapter via a PCI passthrough
+ there is no way to provide the keyboard and mouse inputs to the VM
+ except by plugging a second set of mouse and keyboard to the host
+ or by installing a KVM software in the guest OS.
+
+ The QEMU Barrier client avoids this by implementing directly the Barrier
+ protocol into QEMU.
+
+ This protocol is enabled by adding an input-barrier object to QEMU.
+
+ Syntax: input-barrier,id=<object-id>,name=<guest display name>
+ [,server=<barrier server address>][,port=<barrier server port>]
+ [,x-origin=<x-origin>][,y-origin=<y-origin>]
+ [,width=<width>][,height=<height>]
+
+ The object can be added on the QEMU command line, for instance with:
+
+ ... -object input-barrier,id=barrier0,name=VM-1 ...
+
+ where VM-1 is the name the display configured int the Barrier server
+ on the host providing the mouse and the keyboard events.
+
+ by default <barrier server address> is "localhost", port is 24800,
+ <x-origin> and <y-origin> are set to 0, <width> and <height> to
+ 1920 and 1080.
+
+ If Barrier server is stopped QEMU needs to be reconnected manually,
+ by removing and re-adding the input-barrier object, for instance
+ with the help of the HMP monitor:
+
+ (qemu) object_del barrier0
+ (qemu) object_add input-barrier,id=barrier0,name=VM-1
+
+* Message format
+
+ Message format between the server and client is in two parts:
+
+ 1- the payload length is a 32bit integer in network endianness,
+ 2- the payload
+
+ The payload starts with a 4byte string (without NUL) which is the
+ command. The first command between the server and the client
+ is the only command not encoded on 4 bytes ("Barrier").
+ The remaining part of the payload is decoded according to the command.
+
+* Protocol Description (from barrier/src/lib/barrier/protocol_types.h)
+
+ - barrierCmdHello "Barrier"
+
+ Direction: server -> client
+ Parameters: { int16_t minor, int16_t major }
+ Description:
+
+ Say hello to client
+ minor = protocol major version number supported by server
+ major = protocol minor version number supported by server
+
+ - barrierCmdHelloBack "Barrier"
+
+ Direction: client ->server
+ Parameters: { int16_t minor, int16_t major, char *name}
+ Description:
+
+ Respond to hello from server
+ minor = protocol major version number supported by client
+ major = protocol minor version number supported by client
+ name = client name
+
+ - barrierCmdDInfo "DINF"
+
+ Direction: client ->server
+ Parameters: { int16_t x_origin, int16_t y_origin, int16_t width, int16_t height, int16_t x, int16_t y}
+ Description:
+
+ The client screen must send this message in response to the
+ barrierCmdQInfo message. It must also send this message when the
+ screen's resolution changes. In this case, the client screen should
+ ignore any barrierCmdDMouseMove messages until it receives a
+ barrierCmdCInfoAck in order to prevent attempts to move the mouse off
+ the new screen area.
+
+ - barrierCmdCNoop "CNOP"
+
+ Direction: client -> server
+ Parameters: None
+ Description:
+
+ No operation
+
+ - barrierCmdCClose "CBYE"
+
+ Direction: server -> client
+ Parameters: None
+ Description:
+
+ Close connection
+
+ - barrierCmdCEnter "CINN"
+
+ Direction: server -> client
+ Parameters: { int16_t x, int16_t y, int32_t seq, int16_t modifier }
+ Description:
+
+ Enter screen.
+ x,y = entering screen absolute coordinates
+ seq = sequence number, which is used to order messages between
+ screens. the secondary screen must return this number
+ with some messages
+ modifier = modifier key mask. this will have bits set for each
+ toggle modifier key that is activated on entry to the
+ screen. the secondary screen should adjust its toggle
+ modifiers to reflect that state.
+
+ - barrierCmdCLeave "COUT"
+
+ Direction: server -> client
+ Parameters: None
+ Description:
+
+ Leaving screen. the secondary screen should send clipboard data in
+ response to this message for those clipboards that it has grabbed
+ (i.e. has sent a barrierCmdCClipboard for and has not received a
+ barrierCmdCClipboard for with a greater sequence number) and that
+ were grabbed or have changed since the last leave.
+
+ - barrierCmdCClipboard "CCLP"
+
+ Direction: server -> client
+ Parameters: { int8_t id, int32_t seq }
+ Description:
+
+ Grab clipboard. Sent by screen when some other app on that screen
+ grabs a clipboard.
+ id = the clipboard identifier
+ seq = sequence number. Client must use the sequence number passed in
+ the most recent barrierCmdCEnter. the server always sends 0.
+
+ - barrierCmdCScreenSaver "CSEC"
+
+ Direction: server -> client
+ Parameters: { int8_t started }
+ Description:
+
+ Screensaver change.
+ started = Screensaver on primary has started (1) or closed (0)
+
+ - barrierCmdCResetOptions "CROP"
+
+ Direction: server -> client
+ Parameters: None
+ Description:
+
+ Reset options. Client should reset all of its options to their
+ defaults.
+
+ - barrierCmdCInfoAck "CIAK"
+
+ Direction: server -> client
+ Parameters: None
+ Description:
+
+ Resolution change acknowledgment. Sent by server in response to a
+ client screen's barrierCmdDInfo. This is sent for every
+ barrierCmdDInfo, whether or not the server had sent a barrierCmdQInfo.
+
+ - barrierCmdCKeepAlive "CALV"
+
+ Direction: server -> client
+ Parameters: None
+ Description:
+
+ Keep connection alive. Sent by the server periodically to verify
+ that connections are still up and running. clients must reply in
+ kind on receipt. if the server gets an error sending the message or
+ does not receive a reply within a reasonable time then the server
+ disconnects the client. if the client doesn't receive these (or any
+ message) periodically then it should disconnect from the server. the
+ appropriate interval is defined by an option.
+
+ - barrierCmdDKeyDown "DKDN"
+
+ Direction: server -> client
+ Parameters: { int16_t keyid, int16_t modifier [,int16_t button] }
+ Description:
+
+ Key pressed.
+ keyid = X11 key id
+ modified = modified mask
+ button = X11 Xkb keycode (optional)
+
+ - barrierCmdDKeyRepeat "DKRP"
+
+ Direction: server -> client
+ Parameters: { int16_t keyid, int16_t modifier, int16_t repeat [,int16_t button] }
+ Description:
+
+ Key auto-repeat.
+ keyid = X11 key id
+ modified = modified mask
+ repeat = number of repeats
+ button = X11 Xkb keycode (optional)
+
+ - barrierCmdDKeyUp "DKUP"
+
+ Direction: server -> client
+ Parameters: { int16_t keyid, int16_t modifier [,int16_t button] }
+ Description:
+
+ Key released.
+ keyid = X11 key id
+ modified = modified mask
+ button = X11 Xkb keycode (optional)
+
+ - barrierCmdDMouseDown "DMDN"
+
+ Direction: server -> client
+ Parameters: { int8_t button }
+ Description:
+
+ Mouse button pressed.
+ button = button id
+
+ - barrierCmdDMouseUp "DMUP"
+
+ Direction: server -> client
+ Parameters: { int8_t button }
+ Description:
+
+ Mouse button release.
+ button = button id
+
+ - barrierCmdDMouseMove "DMMV"
+
+ Direction: server -> client
+ Parameters: { int16_t x, int16_t y }
+ Description:
+
+ Absolute mouse moved.
+ x,y = absolute screen coordinates
+
+ - barrierCmdDMouseRelMove "DMRM"
+
+ Direction: server -> client
+ Parameters: { int16_t x, int16_t y }
+ Description:
+
+ Relative mouse moved.
+ x,y = r relative screen coordinates
+
+ - barrierCmdDMouseWheel "DMWM"
+
+ Direction: server -> client
+ Parameters: { int16_t x , int16_t y } or { int16_t y }
+ Description:
+
+ Mouse scroll. The delta should be +120 for one tick forward (away
+ from the user) or right and -120 for one tick backward (toward the
+ user) or left.
+ x = x delta
+ y = y delta
+
+ - barrierCmdDClipboard "DCLP"
+
+ Direction: server -> client
+ Parameters: { int8_t id, int32_t seq, int8_t mark, char *data }
+ Description:
+
+ Clipboard data.
+ id = clipboard id
+ seq = sequence number. The sequence number is 0 when sent by the
+ server. Client screens should use the/ sequence number from
+ the most recent barrierCmdCEnter.
+
+ - barrierCmdDSetOptions "DSOP"
+
+ Direction: server -> client
+ Parameters: { int32 t nb, { int32_t id, int32_t val }[] }
+ Description:
+
+ Set options. Client should set the given option/value pairs.
+ nb = numbers of { id, val } entries
+ id = option id
+ val = option new value
+
+ - barrierCmdDFileTransfer "DFTR"
+
+ Direction: server -> client
+ Parameters: { int8_t mark, char *content }
+ Description:
+
+ Transfer file data.
+ mark = 0 means the content followed is the file size
+ 1 means the content followed is the chunk data
+ 2 means the file transfer is finished
+
+ - barrierCmdDDragInfo "DDRG" int16_t char *
+
+ Direction: server -> client
+ Parameters: { int16_t nb, char *content }
+ Description:
+
+ Drag information.
+ nb = number of dragging objects
+ content = object's directory
+
+ - barrierCmdQInfo "QINF"
+
+ Direction: server -> client
+ Parameters: None
+ Description:
+
+ Query screen info
+ Client should reply with a barrierCmdDInfo
+
+ - barrierCmdEIncompatible "EICV"
+
+ Direction: server -> client
+ Parameters: { int16_t nb, major *minor }
+ Description:
+
+ Incompatible version.
+ major = major version
+ minor = minor version
+
+ - barrierCmdEBusy "EBSY"
+
+ Direction: server -> client
+ Parameters: None
+ Description:
+
+ Name provided when connecting is already in use.
+
+ - barrierCmdEUnknown "EUNK"
+
+ Direction: server -> client
+ Parameters: None
+ Description:
+
+ Unknown client. Name provided when connecting is not in primary's
+ screen configuration map.
+
+ - barrierCmdEBad "EBAD"
+
+ Direction: server -> client
+ Parameters: None
+ Description:
+
+ Protocol violation. Server should disconnect after sending this
+ message.
+
+* TO DO
+
+ - Enable SSL
+ - Manage SetOptions/ResetOptions commands
+
Format strings should reflect the types defined in the trace event. Take
special care to use PRId64 and PRIu64 for int64_t and uint64_t types,
respectively. This ensures portability between 32- and 64-bit platforms.
+Format strings must not end with a newline character. It is the responsibility
+of backends to adapt line ending for proper logging.
Each event declaration will start with the event name, then its arguments,
finally a format string for pretty-printing. For example:
accept persistent writes. In result, for example, the guest Linux
NVDIMM driver, marks such vNVDIMM device as read-only.
+Backend File Setup Example
+--------------------------
+
+Here are two examples showing how to setup these persistent backends on
+linux using the tool ndctl [3].
+
+A. DAX device
+
+Use the following command to set up /dev/dax0.0 so that the entirety of
+namespace0.0 can be exposed as an emulated NVDIMM to the guest:
+
+ ndctl create-namespace -f -e namespace0.0 -m devdax
+
+The /dev/dax0.0 could be used directly in "mem-path" option.
+
+B. DAX file
+
+Individual files on a DAX host file system can be exposed as emulated
+NVDIMMS. First an fsdax block device is created, partitioned, and then
+mounted with the "dax" mount option:
+
+ ndctl create-namespace -f -e namespace0.0 -m fsdax
+ (partition /dev/pmem0 with name pmem0p1)
+ mount -o dax /dev/pmem0p1 /mnt
+ (create or copy a disk image file with qemu-img(1), cp(1), or dd(1)
+ in /mnt)
+
+Then the new file in /mnt could be used in "mem-path" option.
+
NVDIMM Persistence
------------------
https://www.snia.org/sites/default/files/technical_work/final/NVMProgrammingModel_v1.2.pdf
[2] Persistent Memory Development Kit (PMDK), formerly known as NVML project, home page:
http://pmem.io/pmdk/
+[3] ndctl-create-namespace - provision or reconfigure a namespace
+ http://pmem.io/ndctl/ndctl-create-namespace.html
--- /dev/null
+
+========================
+QEMU virtio pmem
+========================
+
+ This document explains the setup and usage of the virtio pmem device
+ which is available since QEMU v4.1.0.
+
+ The virtio pmem device is a paravirtualized persistent memory device
+ on regular (i.e non-NVDIMM) storage.
+
+Usecase
+--------
+
+ Virtio pmem allows to bypass the guest page cache and directly use
+ host page cache. This reduces guest memory footprint as the host can
+ make efficient memory reclaim decisions under memory pressure.
+
+o How does virtio-pmem compare to the nvdimm emulation supported by QEMU?
+
+ NVDIMM emulation on regular (i.e. non-NVDIMM) host storage does not
+ persist the guest writes as there are no defined semantics in the device
+ specification. The virtio pmem device provides guest write persistence
+ on non-NVDIMM host storage.
+
+virtio pmem usage
+-----------------
+
+ A virtio pmem device backed by a memory-backend-file can be created on
+ the QEMU command line as in the following example:
+
+ -object memory-backend-file,id=mem1,share,mem-path=./virtio_pmem.img,size=4G
+ -device virtio-pmem-pci,memdev=mem1,id=nv1
+
+ where:
+ - "object memory-backend-file,id=mem1,share,mem-path=<image>, size=<image size>"
+ creates a backend file with the specified size.
+
+ - "device virtio-pmem-pci,id=nvdimm1,memdev=mem1" creates a virtio pmem
+ pci device whose storage is provided by above memory backend device.
+
+ Multiple virtio pmem devices can be created if multiple pairs of "-object"
+ and "-device" are provided.
+
+Hotplug
+-------
+
+Virtio pmem devices can be hotplugged via the QEMU monitor. First, the
+memory backing has to be added via 'object_add'; afterwards, the virtio
+pmem device can be added via 'device_add'.
+
+For example, the following commands add another 4GB virtio pmem device to
+the guest:
+
+ (qemu) object_add memory-backend-file,id=mem2,share=on,mem-path=virtio_pmem2.img,size=4G
+ (qemu) device_add virtio-pmem-pci,id=virtio_pmem2,memdev=mem2
+
+Guest Data Persistence
+----------------------
+
+ Guest data persistence on non-NVDIMM requires guest userspace applications
+ to perform fsync/msync. This is different from a real nvdimm backend where
+ no additional fsync/msync is required. This is to persist guest writes in
+ host backing file which otherwise remains in host page cache and there is
+ risk of losing the data in case of power failure.
+
+ With virtio pmem device, MAP_SYNC mmap flag is not supported. This provides
+ a hint to application to perform fsync for write persistence.
+
+Limitations
+------------
+- Real nvdimm device backend is not supported.
+- virtio pmem hotunplug is not supported.
+- ACPI NVDIMM features like regions/namespaces are not supported.
+- ndctl command is not supported.
Show virtual to physical memory mappings.
ETEXI
-#if defined(TARGET_I386)
+#if defined(TARGET_I386) || defined(TARGET_RISCV)
{
.name = "mem",
.args_type = "",
}
s->inflight = g_new0(struct vhost_inflight, 1);
- s->vqs = g_new(struct vhost_virtqueue, s->num_queues);
+ s->vqs = g_new0(struct vhost_virtqueue, s->num_queues);
s->watch = 0;
s->connected = false;
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qapi/error.h"
+#include "trace.h"
#include "hw/hw.h"
#include "disas/disas.h"
#include "migration/vmstate.h"
* CPU definitely fetches its instructions from the just written data.
*/
cpu_flush_icache_range(rom->addr, rom->datasize);
+
+ trace_loader_write_rom(rom->name, rom->addr, rom->datasize, rom->isrom);
}
}
return NULL;
}
+bool qdev_hotplug_allowed(DeviceState *dev, Error **errp)
+{
+ MachineState *machine;
+ MachineClass *mc;
+ Object *m_obj = qdev_get_machine();
+
+ if (object_dynamic_cast(m_obj, TYPE_MACHINE)) {
+ machine = MACHINE(m_obj);
+ mc = MACHINE_GET_CLASS(machine);
+ if (mc->hotplug_allowed) {
+ return mc->hotplug_allowed(machine, dev, errp);
+ }
+ }
+
+ return true;
+}
+
HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev)
{
if (dev->parent_bus) {
--- /dev/null
+# loader.c
+loader_write_rom(const char *name, uint64_t gpa, uint64_t size, bool isrom) "%s: @0x%"PRIx64" size=0x%"PRIx64" ROM=%d"
#include "qemu/osdep.h"
#include "ati_int.h"
#include "ati_regs.h"
+#include "vga-access.h"
#include "hw/qdev-properties.h"
#include "vga_regs.h"
#include "qemu/log.h"
static void ati_cursor_define(ATIVGAState *s)
{
uint8_t data[1024];
- uint8_t *src;
+ uint32_t srcoff;
int i, j, idx = 0;
if ((s->regs.cur_offset & BIT(31)) || s->cursor_guest_mode) {
return; /* Do not update cursor if locked or rendered by guest */
}
/* FIXME handle cur_hv_offs correctly */
- src = s->vga.vram_ptr + s->regs.cur_offset -
- (s->regs.cur_hv_offs >> 16) - (s->regs.cur_hv_offs & 0xffff) * 16;
+ srcoff = s->regs.cur_offset -
+ (s->regs.cur_hv_offs >> 16) - (s->regs.cur_hv_offs & 0xffff) * 16;
for (i = 0; i < 64; i++) {
for (j = 0; j < 8; j++, idx++) {
- data[idx] = src[i * 16 + j];
- data[512 + idx] = src[i * 16 + j + 8];
+ data[idx] = vga_read_byte(&s->vga, srcoff + i * 16 + j);
+ data[512 + idx] = vga_read_byte(&s->vga, srcoff + i * 16 + j + 8);
}
}
if (!s->cursor) {
static void ati_cursor_draw_line(VGACommonState *vga, uint8_t *d, int scr_y)
{
ATIVGAState *s = container_of(vga, ATIVGAState, vga);
- uint8_t *src;
+ uint32_t srcoff;
uint32_t *dp = (uint32_t *)d;
int i, j, h;
return;
}
/* FIXME handle cur_hv_offs correctly */
- src = s->vga.vram_ptr + s->cursor_offset + (scr_y - vga->hw_cursor_y) * 16;
+ srcoff = s->cursor_offset + (scr_y - vga->hw_cursor_y) * 16;
dp = &dp[vga->hw_cursor_x];
h = ((s->regs.crtc_h_total_disp >> 16) + 1) * 8;
for (i = 0; i < 8; i++) {
uint32_t color;
- uint8_t abits = src[i];
- uint8_t xbits = src[i + 8];
+ uint8_t abits = vga_read_byte(vga, srcoff + i);
+ uint8_t xbits = vga_read_byte(vga, srcoff + i + 8);
for (j = 0; j < 8; j++, abits <<= 1, xbits <<= 1) {
if (abits & BIT(7)) {
if (xbits & BIT(7)) {
--- /dev/null
+/*
+ * QEMU VGA Emulator templates
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+static inline uint8_t vga_read_byte(VGACommonState *vga, uint32_t addr)
+{
+ return vga->vram_ptr[addr & vga->vbe_size_mask];
+}
+
+static inline uint16_t vga_read_word_le(VGACommonState *vga, uint32_t addr)
+{
+ uint32_t offset = addr & vga->vbe_size_mask & ~1;
+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
+ return lduw_le_p(ptr);
+}
+
+static inline uint16_t vga_read_word_be(VGACommonState *vga, uint32_t addr)
+{
+ uint32_t offset = addr & vga->vbe_size_mask & ~1;
+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
+ return lduw_be_p(ptr);
+}
+
+static inline uint32_t vga_read_dword_le(VGACommonState *vga, uint32_t addr)
+{
+ uint32_t offset = addr & vga->vbe_size_mask & ~3;
+ uint32_t *ptr = (uint32_t *)(vga->vram_ptr + offset);
+ return ldl_le_p(ptr);
+}
} while (--h);
}
-static inline uint8_t vga_read_byte(VGACommonState *vga, uint32_t addr)
-{
- return vga->vram_ptr[addr & vga->vbe_size_mask];
-}
-
-static inline uint16_t vga_read_word_le(VGACommonState *vga, uint32_t addr)
-{
- uint32_t offset = addr & vga->vbe_size_mask & ~1;
- uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
- return lduw_le_p(ptr);
-}
-
-static inline uint16_t vga_read_word_be(VGACommonState *vga, uint32_t addr)
-{
- uint32_t offset = addr & vga->vbe_size_mask & ~1;
- uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
- return lduw_be_p(ptr);
-}
-
-static inline uint32_t vga_read_dword_le(VGACommonState *vga, uint32_t addr)
-{
- uint32_t offset = addr & vga->vbe_size_mask & ~3;
- uint32_t *ptr = (uint32_t *)(vga->vram_ptr + offset);
- return ldl_le_p(ptr);
-}
-
/*
* 4 color mode
*/
typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
uint32_t srcaddr, int width);
+#include "vga-access.h"
#include "vga-helpers.h"
/* return true if the palette was modified */
#include "hw/i386/x86-iommu.h"
#include "hw/pci-host/q35.h"
#include "sysemu/kvm.h"
+#include "sysemu/sysemu.h"
#include "hw/i386/apic_internal.h"
#include "kvm_i386.h"
#include "migration/vmstate.h"
static void vtd_address_space_refresh_all(IntelIOMMUState *s);
static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n);
+static void vtd_panic_require_caching_mode(void)
+{
+ error_report("We need to set caching-mode=on for intel-iommu to enable "
+ "device assignment with IOMMU protection.");
+ exit(1);
+}
+
static void vtd_define_quad(IntelIOMMUState *s, hwaddr addr, uint64_t val,
uint64_t wmask, uint64_t w1cmask)
{
VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
IntelIOMMUState *s = vtd_as->iommu_state;
- if (!s->caching_mode && new & IOMMU_NOTIFIER_MAP) {
- error_report("We need to set caching-mode=on for intel-iommu to enable "
- "device assignment with IOMMU protection.");
- exit(1);
- }
-
/* Update per-address-space notifier flags */
vtd_as->notifier_flags = new;
return true;
}
+static int vtd_machine_done_notify_one(Object *child, void *unused)
+{
+ IntelIOMMUState *iommu = INTEL_IOMMU_DEVICE(x86_iommu_get_default());
+
+ /*
+ * We hard-coded here because vfio-pci is the only special case
+ * here. Let's be more elegant in the future when we can, but so
+ * far there seems to be no better way.
+ */
+ if (object_dynamic_cast(child, "vfio-pci") && !iommu->caching_mode) {
+ vtd_panic_require_caching_mode();
+ }
+
+ return 0;
+}
+
+static void vtd_machine_done_hook(Notifier *notifier, void *unused)
+{
+ object_child_foreach_recursive(object_get_root(),
+ vtd_machine_done_notify_one, NULL);
+}
+
+static Notifier vtd_machine_done_notify = {
+ .notify = vtd_machine_done_hook,
+};
+
static void vtd_realize(DeviceState *dev, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
pci_setup_iommu(bus, vtd_host_dma_iommu, dev);
/* Pseudo address space under root PCI bus. */
pcms->ioapic_as = vtd_host_dma_iommu(bus, s, Q35_PSEUDO_DEVFN_IOAPIC);
+ qemu_add_machine_init_done_notifier(&vtd_machine_done_notify);
}
static void vtd_class_init(ObjectClass *klass, void *data)
}
}
+
+static bool pc_hotplug_allowed(MachineState *ms, DeviceState *dev, Error **errp)
+{
+ X86IOMMUState *iommu = x86_iommu_get_default();
+ IntelIOMMUState *intel_iommu;
+
+ if (iommu &&
+ object_dynamic_cast((Object *)iommu, TYPE_INTEL_IOMMU_DEVICE) &&
+ object_dynamic_cast((Object *)dev, "vfio-pci")) {
+ intel_iommu = INTEL_IOMMU_DEVICE(iommu);
+ if (!intel_iommu->caching_mode) {
+ error_setg(errp, "Device assignment is not allowed without "
+ "enabling caching-mode=on for Intel IOMMU.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
static void pc_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
pcmc->pvh_enabled = true;
assert(!mc->get_hotplug_handler);
mc->get_hotplug_handler = pc_get_hotplug_handler;
+ mc->hotplug_allowed = pc_hotplug_allowed;
mc->cpu_index_to_instance_props = pc_cpu_index_to_props;
mc->get_default_cpu_node_id = pc_get_default_cpu_node_id;
mc->possible_cpu_arch_ids = pc_possible_cpu_arch_ids;
iotkit_secctl_ns_write(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl NS regs write: offset 0x%x data 0x%" PRIx64 " size %u"
# imx6ul_ccm.c
-ccm_entry(void) "\n"
-ccm_freq(uint32_t freq) "freq = %d\n"
-ccm_clock_freq(uint32_t clock, uint32_t freq) "(Clock = %d) = %d\n"
-ccm_read_reg(const char *reg_name, uint32_t value) "reg[%s] <= 0x%" PRIx32 "\n"
-ccm_write_reg(const char *reg_name, uint32_t value) "reg[%s] => 0x%" PRIx32 "\n"
+ccm_entry(void) ""
+ccm_freq(uint32_t freq) "freq = %d"
+ccm_clock_freq(uint32_t clock, uint32_t freq) "(Clock = %d) = %d"
+ccm_read_reg(const char *reg_name, uint32_t value) "reg[%s] <= 0x%" PRIx32
+ccm_write_reg(const char *reg_name, uint32_t value) "reg[%s] => 0x%" PRIx32
# iotkit-sysinfo.c
iotkit_sysinfo_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
bool
select HART
select SIFIVE
+ select UNIMP
config SIFIVE_U
bool
select CADENCE
select HART
select SIFIVE
+ select UNIMP
config SPIKE
bool
obj-$(CONFIG_SPIKE) += riscv_htif.o
obj-$(CONFIG_HART) += riscv_hart.o
obj-$(CONFIG_SIFIVE_E) += sifive_e.o
+obj-$(CONFIG_SIFIVE_E) += sifive_e_prci.o
obj-$(CONFIG_SIFIVE) += sifive_clint.o
obj-$(CONFIG_SIFIVE) += sifive_gpio.o
-obj-$(CONFIG_SIFIVE) += sifive_prci.o
obj-$(CONFIG_SIFIVE) += sifive_plic.o
obj-$(CONFIG_SIFIVE) += sifive_test.o
obj-$(CONFIG_SIFIVE_U) += sifive_u.o
+obj-$(CONFIG_SIFIVE_U) += sifive_u_otp.o
+obj-$(CONFIG_SIFIVE_U) += sifive_u_prci.o
obj-$(CONFIG_SIFIVE) += sifive_uart.o
obj-$(CONFIG_SPIKE) += spike.o
obj-$(CONFIG_RISCV_VIRT) += virt.o
* so then in the future we can make "-bios default" the default option
* if no -bios option is set without breaking anything.
*/
- firmware_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
- default_machine_firmware);
- if (firmware_filename == NULL) {
- error_report("Unable to load the default RISC-V firmware \"%s\"",
- default_machine_firmware);
- exit(1);
- }
+ firmware_filename = riscv_find_firmware(default_machine_firmware);
} else {
firmware_filename = machine->firmware;
+ if (strcmp(firmware_filename, "none")) {
+ firmware_filename = riscv_find_firmware(firmware_filename);
+ }
}
if (strcmp(firmware_filename, "none")) {
/* If not "none" load the firmware */
riscv_load_firmware(firmware_filename, firmware_load_addr);
+ g_free(firmware_filename);
}
+}
- if (!strcmp(machine->firmware, "default")) {
- g_free(firmware_filename);
+char *riscv_find_firmware(const char *firmware_filename)
+{
+ char *filename;
+
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware_filename);
+ if (filename == NULL) {
+ error_report("Unable to load the RISC-V firmware \"%s\"",
+ firmware_filename);
+ exit(1);
}
+
+ return filename;
}
target_ulong riscv_load_firmware(const char *firmware_filename,
*
* Copyright (c) 2017 SiFive, Inc.
*
- * Holds the state of a heterogenous array of RISC-V harts
+ * Holds the state of a homogeneous array of RISC-V harts
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
static Property riscv_harts_props[] = {
DEFINE_PROP_UINT32("num-harts", RISCVHartArrayState, num_harts, 1),
+ DEFINE_PROP_UINT32("hartid-base", RISCVHartArrayState, hartid_base, 0),
DEFINE_PROP_STRING("cpu-type", RISCVHartArrayState, cpu_type),
DEFINE_PROP_END_OF_LIST(),
};
cpu_reset(CPU(cpu));
}
+static void riscv_hart_realize(RISCVHartArrayState *s, int idx,
+ char *cpu_type, Error **errp)
+{
+ Error *err = NULL;
+
+ object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx],
+ sizeof(RISCVCPU), cpu_type,
+ &error_abort, NULL);
+ s->harts[idx].env.mhartid = s->hartid_base + idx;
+ qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]);
+ object_property_set_bool(OBJECT(&s->harts[idx]), true,
+ "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+}
+
static void riscv_harts_realize(DeviceState *dev, Error **errp)
{
RISCVHartArrayState *s = RISCV_HART_ARRAY(dev);
- Error *err = NULL;
int n;
s->harts = g_new0(RISCVCPU, s->num_harts);
for (n = 0; n < s->num_harts; n++) {
- object_initialize_child(OBJECT(s), "harts[*]", &s->harts[n],
- sizeof(RISCVCPU), s->cpu_type,
- &error_abort, NULL);
- s->harts[n].env.mhartid = n;
- qemu_register_reset(riscv_harts_cpu_reset, &s->harts[n]);
- object_property_set_bool(OBJECT(&s->harts[n]), true,
- "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ riscv_hart_realize(s, n, s->cpu_type, errp);
}
}
#include "hw/loader.h"
#include "hw/sysbus.h"
#include "hw/char/serial.h"
+#include "hw/misc/unimp.h"
#include "target/riscv/cpu.h"
#include "hw/riscv/riscv_hart.h"
#include "hw/riscv/sifive_plic.h"
#include "hw/riscv/sifive_clint.h"
-#include "hw/riscv/sifive_prci.h"
#include "hw/riscv/sifive_uart.h"
#include "hw/riscv/sifive_e.h"
+#include "hw/riscv/sifive_e_prci.h"
#include "hw/riscv/boot.h"
#include "chardev/char.h"
#include "sysemu/arch_init.h"
[SIFIVE_E_DTIM] = { 0x80000000, 0x4000 }
};
-static void sifive_mmio_emulate(MemoryRegion *parent, const char *name,
- uintptr_t offset, uintptr_t length)
-{
- MemoryRegion *mock_mmio = g_new(MemoryRegion, 1);
- memory_region_init_ram(mock_mmio, NULL, name, length, &error_fatal);
- memory_region_add_subregion(parent, offset, mock_mmio);
-}
-
static void riscv_sifive_e_init(MachineState *machine)
{
const struct MemmapEntry *memmap = sifive_e_memmap;
sifive_clint_create(memmap[SIFIVE_E_CLINT].base,
memmap[SIFIVE_E_CLINT].size, ms->smp.cpus,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
- sifive_mmio_emulate(sys_mem, "riscv.sifive.e.aon",
+ create_unimplemented_device("riscv.sifive.e.aon",
memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size);
- sifive_prci_create(memmap[SIFIVE_E_PRCI].base);
+ sifive_e_prci_create(memmap[SIFIVE_E_PRCI].base);
/* GPIO */
sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART0].base,
serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART0_IRQ));
- sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi0",
+ create_unimplemented_device("riscv.sifive.e.qspi0",
memmap[SIFIVE_E_QSPI0].base, memmap[SIFIVE_E_QSPI0].size);
- sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm0",
+ create_unimplemented_device("riscv.sifive.e.pwm0",
memmap[SIFIVE_E_PWM0].base, memmap[SIFIVE_E_PWM0].size);
sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART1].base,
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART1_IRQ));
- sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi1",
+ create_unimplemented_device("riscv.sifive.e.qspi1",
memmap[SIFIVE_E_QSPI1].base, memmap[SIFIVE_E_QSPI1].size);
- sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm1",
+ create_unimplemented_device("riscv.sifive.e.pwm1",
memmap[SIFIVE_E_PWM1].base, memmap[SIFIVE_E_PWM1].size);
- sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi2",
+ create_unimplemented_device("riscv.sifive.e.qspi2",
memmap[SIFIVE_E_QSPI2].base, memmap[SIFIVE_E_QSPI2].size);
- sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm2",
+ create_unimplemented_device("riscv.sifive.e.pwm2",
memmap[SIFIVE_E_PWM2].base, memmap[SIFIVE_E_PWM2].size);
/* Flash memory */
--- /dev/null
+/*
+ * QEMU SiFive E PRCI (Power, Reset, Clock, Interrupt)
+ *
+ * Copyright (c) 2017 SiFive, Inc.
+ *
+ * Simple model of the PRCI to emulate register reads made by the SDK BSP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "hw/hw.h"
+#include "hw/riscv/sifive_e_prci.h"
+
+static uint64_t sifive_e_prci_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ SiFiveEPRCIState *s = opaque;
+ switch (addr) {
+ case SIFIVE_E_PRCI_HFROSCCFG:
+ return s->hfrosccfg;
+ case SIFIVE_E_PRCI_HFXOSCCFG:
+ return s->hfxosccfg;
+ case SIFIVE_E_PRCI_PLLCFG:
+ return s->pllcfg;
+ case SIFIVE_E_PRCI_PLLOUTDIV:
+ return s->plloutdiv;
+ }
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%x\n",
+ __func__, (int)addr);
+ return 0;
+}
+
+static void sifive_e_prci_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ SiFiveEPRCIState *s = opaque;
+ switch (addr) {
+ case SIFIVE_E_PRCI_HFROSCCFG:
+ s->hfrosccfg = (uint32_t) val64;
+ /* OSC stays ready */
+ s->hfrosccfg |= SIFIVE_E_PRCI_HFROSCCFG_RDY;
+ break;
+ case SIFIVE_E_PRCI_HFXOSCCFG:
+ s->hfxosccfg = (uint32_t) val64;
+ /* OSC stays ready */
+ s->hfxosccfg |= SIFIVE_E_PRCI_HFXOSCCFG_RDY;
+ break;
+ case SIFIVE_E_PRCI_PLLCFG:
+ s->pllcfg = (uint32_t) val64;
+ /* PLL stays locked */
+ s->pllcfg |= SIFIVE_E_PRCI_PLLCFG_LOCK;
+ break;
+ case SIFIVE_E_PRCI_PLLOUTDIV:
+ s->plloutdiv = (uint32_t) val64;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n",
+ __func__, (int)addr, (int)val64);
+ }
+}
+
+static const MemoryRegionOps sifive_e_prci_ops = {
+ .read = sifive_e_prci_read,
+ .write = sifive_e_prci_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+static void sifive_e_prci_init(Object *obj)
+{
+ SiFiveEPRCIState *s = SIFIVE_E_PRCI(obj);
+
+ memory_region_init_io(&s->mmio, obj, &sifive_e_prci_ops, s,
+ TYPE_SIFIVE_E_PRCI, SIFIVE_E_PRCI_REG_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+ s->hfrosccfg = (SIFIVE_E_PRCI_HFROSCCFG_RDY | SIFIVE_E_PRCI_HFROSCCFG_EN);
+ s->hfxosccfg = (SIFIVE_E_PRCI_HFXOSCCFG_RDY | SIFIVE_E_PRCI_HFXOSCCFG_EN);
+ s->pllcfg = (SIFIVE_E_PRCI_PLLCFG_REFSEL | SIFIVE_E_PRCI_PLLCFG_BYPASS |
+ SIFIVE_E_PRCI_PLLCFG_LOCK);
+ s->plloutdiv = SIFIVE_E_PRCI_PLLOUTDIV_DIV1;
+}
+
+static const TypeInfo sifive_e_prci_info = {
+ .name = TYPE_SIFIVE_E_PRCI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SiFiveEPRCIState),
+ .instance_init = sifive_e_prci_init,
+};
+
+static void sifive_e_prci_register_types(void)
+{
+ type_register_static(&sifive_e_prci_info);
+}
+
+type_init(sifive_e_prci_register_types)
+
+
+/*
+ * Create PRCI device.
+ */
+DeviceState *sifive_e_prci_create(hwaddr addr)
+{
+ DeviceState *dev = qdev_create(NULL, TYPE_SIFIVE_E_PRCI);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
+ return dev;
+}
}
}
-void sifive_plic_raise_irq(SiFivePLICState *plic, uint32_t irq)
-{
- sifive_plic_set_pending(plic, irq, true);
- sifive_plic_update(plic);
-}
-
-void sifive_plic_lower_irq(SiFivePLICState *plic, uint32_t irq)
-{
- sifive_plic_set_pending(plic, irq, false);
- sifive_plic_update(plic);
-}
-
static uint32_t sifive_plic_claim(SiFivePLICState *plic, uint32_t addrid)
{
int i, j;
+++ /dev/null
-/*
- * QEMU SiFive PRCI (Power, Reset, Clock, Interrupt)
- *
- * Copyright (c) 2017 SiFive, Inc.
- *
- * Simple model of the PRCI to emulate register reads made by the SDK BSP
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2 or later, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "qemu/module.h"
-#include "target/riscv/cpu.h"
-#include "hw/hw.h"
-#include "hw/riscv/sifive_prci.h"
-
-static uint64_t sifive_prci_read(void *opaque, hwaddr addr, unsigned int size)
-{
- SiFivePRCIState *s = opaque;
- switch (addr) {
- case SIFIVE_PRCI_HFROSCCFG:
- return s->hfrosccfg;
- case SIFIVE_PRCI_HFXOSCCFG:
- return s->hfxosccfg;
- case SIFIVE_PRCI_PLLCFG:
- return s->pllcfg;
- case SIFIVE_PRCI_PLLOUTDIV:
- return s->plloutdiv;
- }
- hw_error("%s: read: addr=0x%x\n", __func__, (int)addr);
- return 0;
-}
-
-static void sifive_prci_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- SiFivePRCIState *s = opaque;
- switch (addr) {
- case SIFIVE_PRCI_HFROSCCFG:
- s->hfrosccfg = (uint32_t) val64;
- /* OSC stays ready */
- s->hfrosccfg |= SIFIVE_PRCI_HFROSCCFG_RDY;
- break;
- case SIFIVE_PRCI_HFXOSCCFG:
- s->hfxosccfg = (uint32_t) val64;
- /* OSC stays ready */
- s->hfxosccfg |= SIFIVE_PRCI_HFXOSCCFG_RDY;
- break;
- case SIFIVE_PRCI_PLLCFG:
- s->pllcfg = (uint32_t) val64;
- /* PLL stays locked */
- s->pllcfg |= SIFIVE_PRCI_PLLCFG_LOCK;
- break;
- case SIFIVE_PRCI_PLLOUTDIV:
- s->plloutdiv = (uint32_t) val64;
- break;
- default:
- hw_error("%s: bad write: addr=0x%x v=0x%x\n",
- __func__, (int)addr, (int)val64);
- }
-}
-
-static const MemoryRegionOps sifive_prci_ops = {
- .read = sifive_prci_read,
- .write = sifive_prci_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static void sifive_prci_init(Object *obj)
-{
- SiFivePRCIState *s = SIFIVE_PRCI(obj);
-
- memory_region_init_io(&s->mmio, obj, &sifive_prci_ops, s,
- TYPE_SIFIVE_PRCI, 0x8000);
- sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
-
- s->hfrosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN);
- s->hfxosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN);
- s->pllcfg = (SIFIVE_PRCI_PLLCFG_REFSEL | SIFIVE_PRCI_PLLCFG_BYPASS |
- SIFIVE_PRCI_PLLCFG_LOCK);
- s->plloutdiv = SIFIVE_PRCI_PLLOUTDIV_DIV1;
-
-}
-
-static const TypeInfo sifive_prci_info = {
- .name = TYPE_SIFIVE_PRCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SiFivePRCIState),
- .instance_init = sifive_prci_init,
-};
-
-static void sifive_prci_register_types(void)
-{
- type_register_static(&sifive_prci_info);
-}
-
-type_init(sifive_prci_register_types)
-
-
-/*
- * Create PRCI device.
- */
-DeviceState *sifive_prci_create(hwaddr addr)
-{
- DeviceState *dev = qdev_create(NULL, TYPE_SIFIVE_PRCI);
- qdev_init_nofail(dev);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
- return dev;
-}
*/
#include "qemu/osdep.h"
-#include "hw/hw.h"
#include "hw/sysbus.h"
+#include "qemu/log.h"
#include "qemu/module.h"
-#include "target/riscv/cpu.h"
+#include "sysemu/runstate.h"
#include "hw/hw.h"
#include "hw/riscv/sifive_test.h"
exit(code);
case FINISHER_PASS:
exit(0);
+ case FINISHER_RESET:
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ return;
default:
break;
}
}
- hw_error("%s: write: addr=0x%x val=0x%016" PRIx64 "\n",
- __func__, (int)addr, val64);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: write: addr=0x%x val=0x%016" PRIx64 "\n",
+ __func__, (int)addr, val64);
}
static const MemoryRegionOps sifive_test_ops = {
*
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
* Copyright (c) 2017 SiFive, Inc.
+ * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
*
* Provides a board compatible with the SiFive Freedom U SDK:
*
* 0) UART
* 1) CLINT (Core Level Interruptor)
* 2) PLIC (Platform Level Interrupt Controller)
+ * 3) PRCI (Power, Reset, Clock, Interrupt)
+ * 4) OTP (One-Time Programmable) memory with stored serial number
+ * 5) GEM (Gigabit Ethernet Controller) and management block
*
- * This board currently uses a hardcoded devicetree that indicates one hart.
+ * This board currently generates devicetree dynamically that indicates at least
+ * two harts and up to five harts.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
#include "hw/loader.h"
#include "hw/sysbus.h"
#include "hw/char/serial.h"
+#include "hw/cpu/cluster.h"
+#include "hw/misc/unimp.h"
#include "target/riscv/cpu.h"
#include "hw/riscv/riscv_hart.h"
#include "hw/riscv/sifive_plic.h"
#include "hw/riscv/sifive_clint.h"
#include "hw/riscv/sifive_uart.h"
-#include "hw/riscv/sifive_prci.h"
#include "hw/riscv/sifive_u.h"
#include "hw/riscv/boot.h"
#include "chardev/char.h"
+#include "net/eth.h"
#include "sysemu/arch_init.h"
#include "sysemu/device_tree.h"
#include "sysemu/sysemu.h"
[SIFIVE_U_MROM] = { 0x1000, 0x11000 },
[SIFIVE_U_CLINT] = { 0x2000000, 0x10000 },
[SIFIVE_U_PLIC] = { 0xc000000, 0x4000000 },
- [SIFIVE_U_UART0] = { 0x10013000, 0x1000 },
- [SIFIVE_U_UART1] = { 0x10023000, 0x1000 },
+ [SIFIVE_U_PRCI] = { 0x10000000, 0x1000 },
+ [SIFIVE_U_UART0] = { 0x10010000, 0x1000 },
+ [SIFIVE_U_UART1] = { 0x10011000, 0x1000 },
+ [SIFIVE_U_OTP] = { 0x10070000, 0x1000 },
[SIFIVE_U_DRAM] = { 0x80000000, 0x0 },
- [SIFIVE_U_GEM] = { 0x100900FC, 0x2000 },
+ [SIFIVE_U_GEM] = { 0x10090000, 0x2000 },
+ [SIFIVE_U_GEM_MGMT] = { 0x100a0000, 0x1000 },
};
+#define OTP_SERIAL 1
#define GEM_REVISION 0x10070109
static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
uint64_t mem_size, const char *cmdline)
{
+ MachineState *ms = MACHINE(qdev_get_machine());
void *fdt;
int cpu;
uint32_t *cells;
char *nodename;
- char ethclk_names[] = "pclk\0hclk\0tx_clk";
- uint32_t plic_phandle, ethclk_phandle, phandle = 1;
+ char ethclk_names[] = "pclk\0hclk";
+ uint32_t plic_phandle, prci_phandle, phandle = 1;
+ uint32_t hfclk_phandle, rtcclk_phandle, phy_phandle;
fdt = s->fdt = create_device_tree(&s->fdt_size);
if (!fdt) {
exit(1);
}
- qemu_fdt_setprop_string(fdt, "/", "model", "ucbbar,spike-bare,qemu");
- qemu_fdt_setprop_string(fdt, "/", "compatible", "ucbbar,spike-bare-dev");
+ qemu_fdt_setprop_string(fdt, "/", "model", "SiFive HiFive Unleashed A00");
+ qemu_fdt_setprop_string(fdt, "/", "compatible",
+ "sifive,hifive-unleashed-a00");
qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
+ hfclk_phandle = phandle++;
+ nodename = g_strdup_printf("/hfclk");
+ qemu_fdt_add_subnode(fdt, nodename);
+ qemu_fdt_setprop_cell(fdt, nodename, "phandle", hfclk_phandle);
+ qemu_fdt_setprop_string(fdt, nodename, "clock-output-names", "hfclk");
+ qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
+ SIFIVE_U_HFCLK_FREQ);
+ qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock");
+ qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0);
+ g_free(nodename);
+
+ rtcclk_phandle = phandle++;
+ nodename = g_strdup_printf("/rtcclk");
+ qemu_fdt_add_subnode(fdt, nodename);
+ qemu_fdt_setprop_cell(fdt, nodename, "phandle", rtcclk_phandle);
+ qemu_fdt_setprop_string(fdt, nodename, "clock-output-names", "rtcclk");
+ qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
+ SIFIVE_U_RTCCLK_FREQ);
+ qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock");
+ qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0);
+ g_free(nodename);
+
nodename = g_strdup_printf("/memory@%lx",
(long)memmap[SIFIVE_U_DRAM].base);
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
- for (cpu = s->soc.cpus.num_harts - 1; cpu >= 0; cpu--) {
+ for (cpu = ms->smp.cpus - 1; cpu >= 0; cpu--) {
int cpu_phandle = phandle++;
nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
- char *isa = riscv_isa_string(&s->soc.cpus.harts[cpu]);
+ char *isa;
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
SIFIVE_U_CLOCK_FREQ);
- qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
+ /* cpu 0 is the management hart that does not have mmu */
+ if (cpu != 0) {
+ qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
+ isa = riscv_isa_string(&s->soc.u_cpus.harts[cpu - 1]);
+ } else {
+ isa = riscv_isa_string(&s->soc.e_cpus.harts[0]);
+ }
qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa);
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
qemu_fdt_setprop_string(fdt, nodename, "status", "okay");
qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
qemu_fdt_add_subnode(fdt, intc);
qemu_fdt_setprop_cell(fdt, intc, "phandle", cpu_phandle);
- qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", cpu_phandle);
qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
g_free(nodename);
}
- cells = g_new0(uint32_t, s->soc.cpus.num_harts * 4);
- for (cpu = 0; cpu < s->soc.cpus.num_harts; cpu++) {
+ cells = g_new0(uint32_t, ms->smp.cpus * 4);
+ for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
nodename =
g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, nodename);
0x0, memmap[SIFIVE_U_CLINT].base,
0x0, memmap[SIFIVE_U_CLINT].size);
qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
- cells, s->soc.cpus.num_harts * sizeof(uint32_t) * 4);
+ cells, ms->smp.cpus * sizeof(uint32_t) * 4);
g_free(cells);
g_free(nodename);
+ prci_phandle = phandle++;
+ nodename = g_strdup_printf("/soc/clock-controller@%lx",
+ (long)memmap[SIFIVE_U_PRCI].base);
+ qemu_fdt_add_subnode(fdt, nodename);
+ qemu_fdt_setprop_cell(fdt, nodename, "phandle", prci_phandle);
+ qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x1);
+ qemu_fdt_setprop_cells(fdt, nodename, "clocks",
+ hfclk_phandle, rtcclk_phandle);
+ qemu_fdt_setprop_cells(fdt, nodename, "reg",
+ 0x0, memmap[SIFIVE_U_PRCI].base,
+ 0x0, memmap[SIFIVE_U_PRCI].size);
+ qemu_fdt_setprop_string(fdt, nodename, "compatible",
+ "sifive,fu540-c000-prci");
+ g_free(nodename);
+
plic_phandle = phandle++;
- cells = g_new0(uint32_t, s->soc.cpus.num_harts * 4);
- for (cpu = 0; cpu < s->soc.cpus.num_harts; cpu++) {
+ cells = g_new0(uint32_t, ms->smp.cpus * 4 - 2);
+ for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
nodename =
g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, nodename);
- cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
- cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
- cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
- cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
+ /* cpu 0 is the management hart that does not have S-mode */
+ if (cpu == 0) {
+ cells[0] = cpu_to_be32(intc_phandle);
+ cells[1] = cpu_to_be32(IRQ_M_EXT);
+ } else {
+ cells[cpu * 4 - 2] = cpu_to_be32(intc_phandle);
+ cells[cpu * 4 - 1] = cpu_to_be32(IRQ_M_EXT);
+ cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
+ cells[cpu * 4 + 1] = cpu_to_be32(IRQ_S_EXT);
+ }
g_free(nodename);
}
nodename = g_strdup_printf("/soc/interrupt-controller@%lx",
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,plic0");
qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
- cells, s->soc.cpus.num_harts * sizeof(uint32_t) * 4);
+ cells, (ms->smp.cpus * 4 - 2) * sizeof(uint32_t));
qemu_fdt_setprop_cells(fdt, nodename, "reg",
0x0, memmap[SIFIVE_U_PLIC].base,
0x0, memmap[SIFIVE_U_PLIC].size);
- qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control");
- qemu_fdt_setprop_cell(fdt, nodename, "riscv,max-priority", 7);
qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", 0x35);
- qemu_fdt_setprop_cells(fdt, nodename, "phandle", plic_phandle);
- qemu_fdt_setprop_cells(fdt, nodename, "linux,phandle", plic_phandle);
+ qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle);
plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
g_free(cells);
g_free(nodename);
- ethclk_phandle = phandle++;
- nodename = g_strdup_printf("/soc/ethclk");
- qemu_fdt_add_subnode(fdt, nodename);
- qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock");
- qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0);
- qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
- SIFIVE_U_GEM_CLOCK_FREQ);
- qemu_fdt_setprop_cell(fdt, nodename, "phandle", ethclk_phandle);
- qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", ethclk_phandle);
- ethclk_phandle = qemu_fdt_get_phandle(fdt, nodename);
- g_free(nodename);
-
+ phy_phandle = phandle++;
nodename = g_strdup_printf("/soc/ethernet@%lx",
(long)memmap[SIFIVE_U_GEM].base);
qemu_fdt_add_subnode(fdt, nodename);
- qemu_fdt_setprop_string(fdt, nodename, "compatible", "cdns,macb");
+ qemu_fdt_setprop_string(fdt, nodename, "compatible",
+ "sifive,fu540-c000-gem");
qemu_fdt_setprop_cells(fdt, nodename, "reg",
0x0, memmap[SIFIVE_U_GEM].base,
- 0x0, memmap[SIFIVE_U_GEM].size);
+ 0x0, memmap[SIFIVE_U_GEM].size,
+ 0x0, memmap[SIFIVE_U_GEM_MGMT].base,
+ 0x0, memmap[SIFIVE_U_GEM_MGMT].size);
qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control");
qemu_fdt_setprop_string(fdt, nodename, "phy-mode", "gmii");
- qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
- qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_GEM_IRQ);
+ qemu_fdt_setprop_cell(fdt, nodename, "phy-handle", phy_phandle);
+ qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
+ qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_GEM_IRQ);
qemu_fdt_setprop_cells(fdt, nodename, "clocks",
- ethclk_phandle, ethclk_phandle, ethclk_phandle);
- qemu_fdt_setprop(fdt, nodename, "clocks-names", ethclk_names,
+ prci_phandle, PRCI_CLK_GEMGXLPLL, prci_phandle, PRCI_CLK_GEMGXLPLL);
+ qemu_fdt_setprop(fdt, nodename, "clock-names", ethclk_names,
sizeof(ethclk_names));
- qemu_fdt_setprop_cells(fdt, nodename, "#address-cells", 1);
- qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0);
+ qemu_fdt_setprop(fdt, nodename, "local-mac-address",
+ s->soc.gem.conf.macaddr.a, ETH_ALEN);
+ qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1);
+ qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0);
g_free(nodename);
nodename = g_strdup_printf("/soc/ethernet@%lx/ethernet-phy@0",
(long)memmap[SIFIVE_U_GEM].base);
qemu_fdt_add_subnode(fdt, nodename);
- qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x0);
+ qemu_fdt_setprop_cell(fdt, nodename, "phandle", phy_phandle);
+ qemu_fdt_setprop_cell(fdt, nodename, "reg", 0x0);
g_free(nodename);
- nodename = g_strdup_printf("/soc/uart@%lx",
+ nodename = g_strdup_printf("/soc/serial@%lx",
(long)memmap[SIFIVE_U_UART0].base);
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,uart0");
qemu_fdt_setprop_cells(fdt, nodename, "reg",
0x0, memmap[SIFIVE_U_UART0].base,
0x0, memmap[SIFIVE_U_UART0].size);
- qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
- SIFIVE_U_CLOCK_FREQ / 2);
- qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
- qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_UART0_IRQ);
+ qemu_fdt_setprop_cells(fdt, nodename, "clocks",
+ prci_phandle, PRCI_CLK_TLCLK);
+ qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
+ qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_UART0_IRQ);
qemu_fdt_add_subnode(fdt, "/chosen");
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
if (cmdline) {
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
}
+
+ qemu_fdt_add_subnode(fdt, "/aliases");
+ qemu_fdt_setprop_string(fdt, "/aliases", "serial0", nodename);
+
g_free(nodename);
}
memmap[SIFIVE_U_DRAM].base);
if (machine->kernel_filename) {
- riscv_load_kernel(machine->kernel_filename);
+ uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename);
+
+ if (machine->initrd_filename) {
+ hwaddr start;
+ hwaddr end = riscv_load_initrd(machine->initrd_filename,
+ machine->ram_size, kernel_entry,
+ &start);
+ qemu_fdt_setprop_cell(s->fdt, "/chosen",
+ "linux,initrd-start", start);
+ qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
+ end);
+ }
}
/* reset vector */
MachineState *ms = MACHINE(qdev_get_machine());
SiFiveUSoCState *s = RISCV_U_SOC(obj);
- object_initialize_child(obj, "cpus", &s->cpus, sizeof(s->cpus),
- TYPE_RISCV_HART_ARRAY, &error_abort, NULL);
- object_property_set_str(OBJECT(&s->cpus), SIFIVE_U_CPU, "cpu-type",
- &error_abort);
- object_property_set_int(OBJECT(&s->cpus), ms->smp.cpus, "num-harts",
- &error_abort);
-
+ object_initialize_child(obj, "e-cluster", &s->e_cluster,
+ sizeof(s->e_cluster), TYPE_CPU_CLUSTER,
+ &error_abort, NULL);
+ qdev_prop_set_uint32(DEVICE(&s->e_cluster), "cluster-id", 0);
+
+ object_initialize_child(OBJECT(&s->e_cluster), "e-cpus",
+ &s->e_cpus, sizeof(s->e_cpus),
+ TYPE_RISCV_HART_ARRAY, &error_abort,
+ NULL);
+ qdev_prop_set_uint32(DEVICE(&s->e_cpus), "num-harts", 1);
+ qdev_prop_set_uint32(DEVICE(&s->e_cpus), "hartid-base", 0);
+ qdev_prop_set_string(DEVICE(&s->e_cpus), "cpu-type", SIFIVE_E_CPU);
+
+ object_initialize_child(obj, "u-cluster", &s->u_cluster,
+ sizeof(s->u_cluster), TYPE_CPU_CLUSTER,
+ &error_abort, NULL);
+ qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1);
+
+ object_initialize_child(OBJECT(&s->u_cluster), "u-cpus",
+ &s->u_cpus, sizeof(s->u_cpus),
+ TYPE_RISCV_HART_ARRAY, &error_abort,
+ NULL);
+ qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1);
+ qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1);
+ qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", SIFIVE_U_CPU);
+
+ sysbus_init_child_obj(obj, "prci", &s->prci, sizeof(s->prci),
+ TYPE_SIFIVE_U_PRCI);
+ sysbus_init_child_obj(obj, "otp", &s->otp, sizeof(s->otp),
+ TYPE_SIFIVE_U_OTP);
+ qdev_prop_set_uint32(DEVICE(&s->otp), "serial", OTP_SERIAL);
sysbus_init_child_obj(obj, "gem", &s->gem, sizeof(s->gem),
TYPE_CADENCE_GEM);
}
Error *err = NULL;
NICInfo *nd = &nd_table[0];
- object_property_set_bool(OBJECT(&s->cpus), true, "realized",
+ object_property_set_bool(OBJECT(&s->e_cpus), true, "realized",
+ &error_abort);
+ object_property_set_bool(OBJECT(&s->u_cpus), true, "realized",
+ &error_abort);
+ /*
+ * The cluster must be realized after the RISC-V hart array container,
+ * as the container's CPU object is only created on realize, and the
+ * CPU must exist and have been parented into the cluster before the
+ * cluster is realized.
+ */
+ object_property_set_bool(OBJECT(&s->e_cluster), true, "realized",
+ &error_abort);
+ object_property_set_bool(OBJECT(&s->u_cluster), true, "realized",
&error_abort);
/* boot rom */
plic_hart_config = g_malloc0(plic_hart_config_len);
for (i = 0; i < ms->smp.cpus; i++) {
if (i != 0) {
- strncat(plic_hart_config, ",", plic_hart_config_len);
+ strncat(plic_hart_config, "," SIFIVE_U_PLIC_HART_CONFIG,
+ plic_hart_config_len);
+ } else {
+ strncat(plic_hart_config, "M", plic_hart_config_len);
}
- strncat(plic_hart_config, SIFIVE_U_PLIC_HART_CONFIG,
- plic_hart_config_len);
plic_hart_config_len -= (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1);
}
memmap[SIFIVE_U_CLINT].size, ms->smp.cpus,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
+ object_property_set_bool(OBJECT(&s->prci), true, "realized", &err);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base);
+
+ object_property_set_bool(OBJECT(&s->otp), true, "realized", &err);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base);
+
for (i = 0; i < SIFIVE_U_PLIC_NUM_SOURCES; i++) {
plic_gpios[i] = qdev_get_gpio_in(DEVICE(s->plic), i);
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem), 0, memmap[SIFIVE_U_GEM].base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem), 0,
plic_gpios[SIFIVE_U_GEM_IRQ]);
+
+ create_unimplemented_device("riscv.sifive.u.gem-mgmt",
+ memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size);
}
static void riscv_sifive_u_machine_init(MachineClass *mc)
{
mc->desc = "RISC-V Board compatible with SiFive U SDK";
mc->init = riscv_sifive_u_init;
- /* The real hardware has 5 CPUs, but one of them is a small embedded power
- * management CPU.
- */
- mc->max_cpus = 4;
+ mc->max_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + SIFIVE_U_COMPUTE_CPU_COUNT;
+ mc->min_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + 1;
+ mc->default_cpus = mc->min_cpus;
}
DEFINE_MACHINE("sifive_u", riscv_sifive_u_machine_init)
--- /dev/null
+/*
+ * QEMU SiFive U OTP (One-Time Programmable) Memory interface
+ *
+ * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
+ *
+ * Simple model of the OTP to emulate register reads made by the SDK BSP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "hw/riscv/sifive_u_otp.h"
+
+static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ SiFiveUOTPState *s = opaque;
+
+ switch (addr) {
+ case SIFIVE_U_OTP_PA:
+ return s->pa;
+ case SIFIVE_U_OTP_PAIO:
+ return s->paio;
+ case SIFIVE_U_OTP_PAS:
+ return s->pas;
+ case SIFIVE_U_OTP_PCE:
+ return s->pce;
+ case SIFIVE_U_OTP_PCLK:
+ return s->pclk;
+ case SIFIVE_U_OTP_PDIN:
+ return s->pdin;
+ case SIFIVE_U_OTP_PDOUT:
+ if ((s->pce & SIFIVE_U_OTP_PCE_EN) &&
+ (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) &&
+ (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) {
+ return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK];
+ } else {
+ return 0xff;
+ }
+ case SIFIVE_U_OTP_PDSTB:
+ return s->pdstb;
+ case SIFIVE_U_OTP_PPROG:
+ return s->pprog;
+ case SIFIVE_U_OTP_PTC:
+ return s->ptc;
+ case SIFIVE_U_OTP_PTM:
+ return s->ptm;
+ case SIFIVE_U_OTP_PTM_REP:
+ return s->ptm_rep;
+ case SIFIVE_U_OTP_PTR:
+ return s->ptr;
+ case SIFIVE_U_OTP_PTRIM:
+ return s->ptrim;
+ case SIFIVE_U_OTP_PWE:
+ return s->pwe;
+ }
+
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n",
+ __func__, addr);
+ return 0;
+}
+
+static void sifive_u_otp_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ SiFiveUOTPState *s = opaque;
+ uint32_t val32 = (uint32_t)val64;
+
+ switch (addr) {
+ case SIFIVE_U_OTP_PA:
+ s->pa = val32 & SIFIVE_U_OTP_PA_MASK;
+ break;
+ case SIFIVE_U_OTP_PAIO:
+ s->paio = val32;
+ break;
+ case SIFIVE_U_OTP_PAS:
+ s->pas = val32;
+ break;
+ case SIFIVE_U_OTP_PCE:
+ s->pce = val32;
+ break;
+ case SIFIVE_U_OTP_PCLK:
+ s->pclk = val32;
+ break;
+ case SIFIVE_U_OTP_PDIN:
+ s->pdin = val32;
+ break;
+ case SIFIVE_U_OTP_PDOUT:
+ /* read-only */
+ break;
+ case SIFIVE_U_OTP_PDSTB:
+ s->pdstb = val32;
+ break;
+ case SIFIVE_U_OTP_PPROG:
+ s->pprog = val32;
+ break;
+ case SIFIVE_U_OTP_PTC:
+ s->ptc = val32;
+ break;
+ case SIFIVE_U_OTP_PTM:
+ s->ptm = val32;
+ break;
+ case SIFIVE_U_OTP_PTM_REP:
+ s->ptm_rep = val32;
+ break;
+ case SIFIVE_U_OTP_PTR:
+ s->ptr = val32;
+ break;
+ case SIFIVE_U_OTP_PTRIM:
+ s->ptrim = val32;
+ break;
+ case SIFIVE_U_OTP_PWE:
+ s->pwe = val32;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx
+ " v=0x%x\n", __func__, addr, val32);
+ }
+}
+
+static const MemoryRegionOps sifive_u_otp_ops = {
+ .read = sifive_u_otp_read,
+ .write = sifive_u_otp_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+static Property sifive_u_otp_properties[] = {
+ DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sifive_u_otp_realize(DeviceState *dev, Error **errp)
+{
+ SiFiveUOTPState *s = SIFIVE_U_OTP(dev);
+
+ memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s,
+ TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
+}
+
+static void sifive_u_otp_reset(DeviceState *dev)
+{
+ SiFiveUOTPState *s = SIFIVE_U_OTP(dev);
+
+ /* Initialize all fuses' initial value to 0xFFs */
+ memset(s->fuse, 0xff, sizeof(s->fuse));
+
+ /* Make a valid content of serial number */
+ s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial;
+ s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial);
+}
+
+static void sifive_u_otp_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->props = sifive_u_otp_properties;
+ dc->realize = sifive_u_otp_realize;
+ dc->reset = sifive_u_otp_reset;
+}
+
+static const TypeInfo sifive_u_otp_info = {
+ .name = TYPE_SIFIVE_U_OTP,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SiFiveUOTPState),
+ .class_init = sifive_u_otp_class_init,
+};
+
+static void sifive_u_otp_register_types(void)
+{
+ type_register_static(&sifive_u_otp_info);
+}
+
+type_init(sifive_u_otp_register_types)
--- /dev/null
+/*
+ * QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt)
+ *
+ * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
+ *
+ * Simple model of the PRCI to emulate register reads made by the SDK BSP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "hw/riscv/sifive_u_prci.h"
+
+static uint64_t sifive_u_prci_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ SiFiveUPRCIState *s = opaque;
+
+ switch (addr) {
+ case SIFIVE_U_PRCI_HFXOSCCFG:
+ return s->hfxosccfg;
+ case SIFIVE_U_PRCI_COREPLLCFG0:
+ return s->corepllcfg0;
+ case SIFIVE_U_PRCI_DDRPLLCFG0:
+ return s->ddrpllcfg0;
+ case SIFIVE_U_PRCI_DDRPLLCFG1:
+ return s->ddrpllcfg1;
+ case SIFIVE_U_PRCI_GEMGXLPLLCFG0:
+ return s->gemgxlpllcfg0;
+ case SIFIVE_U_PRCI_GEMGXLPLLCFG1:
+ return s->gemgxlpllcfg1;
+ case SIFIVE_U_PRCI_CORECLKSEL:
+ return s->coreclksel;
+ case SIFIVE_U_PRCI_DEVICESRESET:
+ return s->devicesreset;
+ case SIFIVE_U_PRCI_CLKMUXSTATUS:
+ return s->clkmuxstatus;
+ }
+
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n",
+ __func__, addr);
+
+ return 0;
+}
+
+static void sifive_u_prci_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ SiFiveUPRCIState *s = opaque;
+ uint32_t val32 = (uint32_t)val64;
+
+ switch (addr) {
+ case SIFIVE_U_PRCI_HFXOSCCFG:
+ s->hfxosccfg = val32;
+ /* OSC stays ready */
+ s->hfxosccfg |= SIFIVE_U_PRCI_HFXOSCCFG_RDY;
+ break;
+ case SIFIVE_U_PRCI_COREPLLCFG0:
+ s->corepllcfg0 = val32;
+ /* internal feedback */
+ s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
+ /* PLL stays locked */
+ s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
+ break;
+ case SIFIVE_U_PRCI_DDRPLLCFG0:
+ s->ddrpllcfg0 = val32;
+ /* internal feedback */
+ s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
+ /* PLL stays locked */
+ s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
+ break;
+ case SIFIVE_U_PRCI_DDRPLLCFG1:
+ s->ddrpllcfg1 = val32;
+ break;
+ case SIFIVE_U_PRCI_GEMGXLPLLCFG0:
+ s->gemgxlpllcfg0 = val32;
+ /* internal feedback */
+ s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
+ /* PLL stays locked */
+ s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
+ break;
+ case SIFIVE_U_PRCI_GEMGXLPLLCFG1:
+ s->gemgxlpllcfg1 = val32;
+ break;
+ case SIFIVE_U_PRCI_CORECLKSEL:
+ s->coreclksel = val32;
+ break;
+ case SIFIVE_U_PRCI_DEVICESRESET:
+ s->devicesreset = val32;
+ break;
+ case SIFIVE_U_PRCI_CLKMUXSTATUS:
+ s->clkmuxstatus = val32;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx
+ " v=0x%x\n", __func__, addr, val32);
+ }
+}
+
+static const MemoryRegionOps sifive_u_prci_ops = {
+ .read = sifive_u_prci_read,
+ .write = sifive_u_prci_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+static void sifive_u_prci_realize(DeviceState *dev, Error **errp)
+{
+ SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev);
+
+ memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_prci_ops, s,
+ TYPE_SIFIVE_U_PRCI, SIFIVE_U_PRCI_REG_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
+}
+
+static void sifive_u_prci_reset(DeviceState *dev)
+{
+ SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev);
+
+ /* Initialize register to power-on-reset values */
+ s->hfxosccfg = SIFIVE_U_PRCI_HFXOSCCFG_RDY | SIFIVE_U_PRCI_HFXOSCCFG_EN;
+ s->corepllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
+ SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
+ SIFIVE_U_PRCI_PLLCFG0_LOCK;
+ s->ddrpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
+ SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
+ SIFIVE_U_PRCI_PLLCFG0_LOCK;
+ s->gemgxlpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
+ SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
+ SIFIVE_U_PRCI_PLLCFG0_LOCK;
+ s->coreclksel = SIFIVE_U_PRCI_CORECLKSEL_HFCLK;
+}
+
+static void sifive_u_prci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = sifive_u_prci_realize;
+ dc->reset = sifive_u_prci_reset;
+}
+
+static const TypeInfo sifive_u_prci_info = {
+ .name = TYPE_SIFIVE_U_PRCI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SiFiveUPRCIState),
+ .class_init = sifive_u_prci_class_init,
+};
+
+static void sifive_u_prci_register_types(void)
+{
+ type_register_static(&sifive_u_prci_info);
+}
+
+type_init(sifive_u_prci_register_types)
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "qemu/log.h"
#include "hw/sysbus.h"
#include "chardev/char.h"
#include "chardev/char-fe.h"
-#include "target/riscv/cpu.h"
#include "hw/hw.h"
#include "hw/irq.h"
#include "hw/riscv/sifive_uart.h"
return s->div;
}
- hw_error("%s: bad read: addr=0x%x\n",
- __func__, (int)addr);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=0x%x\n",
+ __func__, (int)addr);
return 0;
}
s->div = val64;
return;
}
- hw_error("%s: bad write: addr=0x%x v=0x%x\n",
- __func__, (int)addr, (int)value);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n",
+ __func__, (int)addr, (int)value);
}
static const MemoryRegionOps uart_ops = {
qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
qemu_fdt_add_subnode(fdt, intc);
qemu_fdt_setprop_cell(fdt, intc, "phandle", 1);
- qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", 1);
qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
0x1800, 0, 0, 0x7);
}
-static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
+static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
uint64_t mem_size, const char *cmdline)
{
void *fdt;
qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu);
qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
qemu_fdt_setprop_cell(fdt, nodename, "phandle", cpu_phandle);
- qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", cpu_phandle);
intc_phandle = phandle++;
qemu_fdt_add_subnode(fdt, intc);
qemu_fdt_setprop_cell(fdt, intc, "phandle", intc_phandle);
- qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", intc_phandle);
qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
nodename = g_strdup_printf("/soc/interrupt-controller@%lx",
(long)memmap[VIRT_PLIC].base);
qemu_fdt_add_subnode(fdt, nodename);
- qemu_fdt_setprop_cells(fdt, nodename, "#address-cells",
- FDT_PLIC_ADDR_CELLS);
+ qemu_fdt_setprop_cell(fdt, nodename, "#address-cells",
+ FDT_PLIC_ADDR_CELLS);
qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells",
FDT_PLIC_INT_CELLS);
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,plic0");
qemu_fdt_setprop_cells(fdt, nodename, "reg",
0x0, memmap[VIRT_PLIC].base,
0x0, memmap[VIRT_PLIC].size);
- qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control");
- qemu_fdt_setprop_cell(fdt, nodename, "riscv,max-priority", 7);
qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", VIRTIO_NDEV);
- qemu_fdt_setprop_cells(fdt, nodename, "phandle", plic_phandle);
- qemu_fdt_setprop_cells(fdt, nodename, "linux,phandle", plic_phandle);
+ qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle);
plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
g_free(cells);
g_free(nodename);
qemu_fdt_setprop_cells(fdt, nodename, "reg",
0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size,
0x0, memmap[VIRT_VIRTIO].size);
- qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
- qemu_fdt_setprop_cells(fdt, nodename, "interrupts", VIRTIO_IRQ + i);
+ qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
+ qemu_fdt_setprop_cell(fdt, nodename, "interrupts", VIRTIO_IRQ + i);
g_free(nodename);
}
nodename = g_strdup_printf("/soc/pci@%lx",
(long) memmap[VIRT_PCIE_ECAM].base);
qemu_fdt_add_subnode(fdt, nodename);
- qemu_fdt_setprop_cells(fdt, nodename, "#address-cells",
- FDT_PCI_ADDR_CELLS);
- qemu_fdt_setprop_cells(fdt, nodename, "#interrupt-cells",
- FDT_PCI_INT_CELLS);
- qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0x2);
+ qemu_fdt_setprop_cell(fdt, nodename, "#address-cells",
+ FDT_PCI_ADDR_CELLS);
+ qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells",
+ FDT_PCI_INT_CELLS);
+ qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0x2);
qemu_fdt_setprop_string(fdt, nodename, "compatible",
"pci-host-ecam-generic");
qemu_fdt_setprop_string(fdt, nodename, "device_type", "pci");
0x0, memmap[VIRT_UART0].base,
0x0, memmap[VIRT_UART0].size);
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", 3686400);
- qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
- qemu_fdt_setprop_cells(fdt, nodename, "interrupts", UART0_IRQ);
+ qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
+ qemu_fdt_setprop_cell(fdt, nodename, "interrupts", UART0_IRQ);
qemu_fdt_add_subnode(fdt, "/chosen");
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
}
g_free(nodename);
-
- return fdt;
}
size_t plic_hart_config_len;
int i;
unsigned int smp_cpus = machine->smp.cpus;
- void *fdt;
/* Initialize SOC */
object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc),
main_mem);
/* create device tree */
- fdt = create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
+ create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
/* boot rom */
memory_region_init_rom(mask_rom, NULL, "riscv_virt_board.mrom",
hwaddr end = riscv_load_initrd(machine->initrd_filename,
machine->ram_size, kernel_entry,
&start);
- qemu_fdt_setprop_cell(fdt, "/chosen",
+ qemu_fdt_setprop_cell(s->fdt, "/chosen",
"linux,initrd-start", start);
- qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+ qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
end);
}
}
mptsas_mmio_unhandled_read(void *dev, uint32_t addr) "dev %p addr 0x%08x"
mptsas_mmio_unhandled_write(void *dev, uint32_t addr, uint32_t val) "dev %p addr 0x%08x value 0x%x"
mptsas_mmio_write(void *dev, uint32_t addr, uint32_t val) "dev %p addr 0x%08x value 0x%x"
-mptsas_process_message(void *dev, int msg, uint32_t ctx) "dev %p cmd %d context 0x%08x\n"
+mptsas_process_message(void *dev, int msg, uint32_t ctx) "dev %p cmd %d context 0x%08x"
mptsas_process_scsi_io_request(void *dev, int bus, int target, int lun, uint64_t len) "dev %p dev %d:%d:%d length %"PRIu64""
mptsas_reset(void *dev) "dev %p "
mptsas_scsi_overflow(void *dev, uint32_t ctx, uint64_t req, uint64_t found) "dev %p context 0x%08x: %"PRIu64"/%"PRIu64""
bcm2835_sdhost_read(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
bcm2835_sdhost_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
bcm2835_sdhost_edm_change(const char *why, uint32_t edm) "(%s) EDM now 0x%x"
-bcm2835_sdhost_update_irq(uint32_t irq) "IRQ bits 0x%x\n"
+bcm2835_sdhost_update_irq(uint32_t irq) "IRQ bits 0x%x"
# core.c
sdbus_command(const char *bus_name, uint8_t cmd, uint32_t arg) "@%s CMD%02d arg 0x%08x"
#define TYPE_VFIO_PCI "vfio-pci"
#define PCI_VFIO(obj) OBJECT_CHECK(VFIOPCIDevice, obj, TYPE_VFIO_PCI)
-#define TYPE_VIFO_PCI_NOHOTPLUG "vfio-pci-nohotplug"
+#define TYPE_VFIO_PCI_NOHOTPLUG "vfio-pci-nohotplug"
static void vfio_disable_interrupts(VFIOPCIDevice *vdev);
static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled);
}
static const TypeInfo vfio_pci_nohotplug_dev_info = {
- .name = TYPE_VIFO_PCI_NOHOTPLUG,
+ .name = TYPE_VFIO_PCI_NOHOTPLUG,
.parent = TYPE_VFIO_PCI,
.instance_size = sizeof(VFIOPCIDevice),
.class_init = vfio_pci_nohotplug_dev_class_init,
OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO)
#define VIRT_MAGIC 0x74726976 /* 'virt' */
-#define VIRT_VERSION 1
+#define VIRT_VERSION 2
+#define VIRT_VERSION_LEGACY 1
#define VIRT_VENDOR 0x554D4551 /* 'QEMU' */
+typedef struct VirtIOMMIOQueue {
+ uint16_t num;
+ bool enabled;
+ uint32_t desc[2];
+ uint32_t avail[2];
+ uint32_t used[2];
+} VirtIOMMIOQueue;
+
typedef struct {
/* Generic */
SysBusDevice parent_obj;
MemoryRegion iomem;
qemu_irq irq;
+ bool legacy;
/* Guest accessible state needing migration and reset */
uint32_t host_features_sel;
uint32_t guest_features_sel;
/* virtio-bus */
VirtioBusState bus;
bool format_transport_address;
+ /* Fields only used for non-legacy (v2) devices */
+ uint32_t guest_features[2];
+ VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX];
} VirtIOMMIOProxy;
static bool virtio_mmio_ioeventfd_enabled(DeviceState *d)
case VIRTIO_MMIO_MAGIC_VALUE:
return VIRT_MAGIC;
case VIRTIO_MMIO_VERSION:
- return VIRT_VERSION;
+ if (proxy->legacy) {
+ return VIRT_VERSION_LEGACY;
+ } else {
+ return VIRT_VERSION;
+ }
case VIRTIO_MMIO_VENDOR_ID:
return VIRT_VENDOR;
default:
case VIRTIO_MMIO_MAGIC_VALUE:
return VIRT_MAGIC;
case VIRTIO_MMIO_VERSION:
- return VIRT_VERSION;
+ if (proxy->legacy) {
+ return VIRT_VERSION_LEGACY;
+ } else {
+ return VIRT_VERSION;
+ }
case VIRTIO_MMIO_DEVICE_ID:
return vdev->device_id;
case VIRTIO_MMIO_VENDOR_ID:
return VIRT_VENDOR;
case VIRTIO_MMIO_DEVICE_FEATURES:
- if (proxy->host_features_sel) {
- return 0;
+ if (proxy->legacy) {
+ if (proxy->host_features_sel) {
+ return 0;
+ } else {
+ return vdev->host_features;
+ }
+ } else {
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
+ return (vdev->host_features & ~vdc->legacy_features)
+ >> (32 * proxy->host_features_sel);
}
- return vdev->host_features;
case VIRTIO_MMIO_QUEUE_NUM_MAX:
if (!virtio_queue_get_num(vdev, vdev->queue_sel)) {
return 0;
}
return VIRTQUEUE_MAX_SIZE;
case VIRTIO_MMIO_QUEUE_PFN:
+ if (!proxy->legacy) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: read from legacy register (0x%"
+ HWADDR_PRIx ") in non-legacy mode\n",
+ __func__, offset);
+ return 0;
+ }
return virtio_queue_get_addr(vdev, vdev->queue_sel)
>> proxy->guest_page_shift;
+ case VIRTIO_MMIO_QUEUE_READY:
+ if (proxy->legacy) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: read from non-legacy register (0x%"
+ HWADDR_PRIx ") in legacy mode\n",
+ __func__, offset);
+ return 0;
+ }
+ return proxy->vqs[vdev->queue_sel].enabled;
case VIRTIO_MMIO_INTERRUPT_STATUS:
return atomic_read(&vdev->isr);
case VIRTIO_MMIO_STATUS:
return vdev->status;
+ case VIRTIO_MMIO_CONFIG_GENERATION:
+ if (proxy->legacy) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: read from non-legacy register (0x%"
+ HWADDR_PRIx ") in legacy mode\n",
+ __func__, offset);
+ return 0;
+ }
+ return vdev->generation;
case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
case VIRTIO_MMIO_DRIVER_FEATURES:
case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
case VIRTIO_MMIO_QUEUE_ALIGN:
case VIRTIO_MMIO_QUEUE_NOTIFY:
case VIRTIO_MMIO_INTERRUPT_ACK:
+ case VIRTIO_MMIO_QUEUE_DESC_LOW:
+ case VIRTIO_MMIO_QUEUE_DESC_HIGH:
+ case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
+ case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
+ case VIRTIO_MMIO_QUEUE_USED_LOW:
+ case VIRTIO_MMIO_QUEUE_USED_HIGH:
qemu_log_mask(LOG_GUEST_ERROR,
- "%s: read of write-only register\n",
- __func__);
+ "%s: read of write-only register (0x%" HWADDR_PRIx ")\n",
+ __func__, offset);
return 0;
default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: bad register offset\n", __func__);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad register offset (0x%" HWADDR_PRIx ")\n",
+ __func__, offset);
return 0;
}
return 0;
}
switch (offset) {
case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
- proxy->host_features_sel = value;
+ if (value) {
+ proxy->host_features_sel = 1;
+ } else {
+ proxy->host_features_sel = 0;
+ }
break;
case VIRTIO_MMIO_DRIVER_FEATURES:
- if (!proxy->guest_features_sel) {
- virtio_set_features(vdev, value);
+ if (proxy->legacy) {
+ if (proxy->guest_features_sel) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: attempt to write guest features with "
+ "guest_features_sel > 0 in legacy mode\n",
+ __func__);
+ } else {
+ virtio_set_features(vdev, value);
+ }
+ } else {
+ proxy->guest_features[proxy->guest_features_sel] = value;
}
break;
case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
- proxy->guest_features_sel = value;
+ if (value) {
+ proxy->guest_features_sel = 1;
+ } else {
+ proxy->guest_features_sel = 0;
+ }
break;
case VIRTIO_MMIO_GUEST_PAGE_SIZE:
+ if (!proxy->legacy) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to legacy register (0x%"
+ HWADDR_PRIx ") in non-legacy mode\n",
+ __func__, offset);
+ return;
+ }
proxy->guest_page_shift = ctz32(value);
if (proxy->guest_page_shift > 31) {
proxy->guest_page_shift = 0;
break;
case VIRTIO_MMIO_QUEUE_NUM:
trace_virtio_mmio_queue_write(value, VIRTQUEUE_MAX_SIZE);
- virtio_queue_set_num(vdev, vdev->queue_sel, value);
- /* Note: only call this function for legacy devices */
- virtio_queue_update_rings(vdev, vdev->queue_sel);
+ if (proxy->legacy) {
+ virtio_queue_set_num(vdev, vdev->queue_sel, value);
+ virtio_queue_update_rings(vdev, vdev->queue_sel);
+ } else {
+ proxy->vqs[vdev->queue_sel].num = value;
+ }
break;
case VIRTIO_MMIO_QUEUE_ALIGN:
- /* Note: this is only valid for legacy devices */
+ if (!proxy->legacy) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to legacy register (0x%"
+ HWADDR_PRIx ") in non-legacy mode\n",
+ __func__, offset);
+ return;
+ }
virtio_queue_set_align(vdev, vdev->queue_sel, value);
break;
case VIRTIO_MMIO_QUEUE_PFN:
+ if (!proxy->legacy) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to legacy register (0x%"
+ HWADDR_PRIx ") in non-legacy mode\n",
+ __func__, offset);
+ return;
+ }
if (value == 0) {
virtio_reset(vdev);
} else {
value << proxy->guest_page_shift);
}
break;
+ case VIRTIO_MMIO_QUEUE_READY:
+ if (proxy->legacy) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to non-legacy register (0x%"
+ HWADDR_PRIx ") in legacy mode\n",
+ __func__, offset);
+ return;
+ }
+ if (value) {
+ virtio_queue_set_num(vdev, vdev->queue_sel,
+ proxy->vqs[vdev->queue_sel].num);
+ virtio_queue_set_rings(vdev, vdev->queue_sel,
+ ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 |
+ proxy->vqs[vdev->queue_sel].desc[0],
+ ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 |
+ proxy->vqs[vdev->queue_sel].avail[0],
+ ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
+ proxy->vqs[vdev->queue_sel].used[0]);
+ proxy->vqs[vdev->queue_sel].enabled = 1;
+ } else {
+ proxy->vqs[vdev->queue_sel].enabled = 0;
+ }
+ break;
case VIRTIO_MMIO_QUEUE_NOTIFY:
if (value < VIRTIO_QUEUE_MAX) {
virtio_queue_notify(vdev, value);
virtio_mmio_stop_ioeventfd(proxy);
}
+ if (!proxy->legacy && (value & VIRTIO_CONFIG_S_FEATURES_OK)) {
+ virtio_set_features(vdev,
+ ((uint64_t)proxy->guest_features[1]) << 32 |
+ proxy->guest_features[0]);
+ }
+
virtio_set_status(vdev, value & 0xff);
if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
virtio_reset(vdev);
}
break;
+ case VIRTIO_MMIO_QUEUE_DESC_LOW:
+ if (proxy->legacy) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to non-legacy register (0x%"
+ HWADDR_PRIx ") in legacy mode\n",
+ __func__, offset);
+ return;
+ }
+ proxy->vqs[vdev->queue_sel].desc[0] = value;
+ break;
+ case VIRTIO_MMIO_QUEUE_DESC_HIGH:
+ if (proxy->legacy) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to non-legacy register (0x%"
+ HWADDR_PRIx ") in legacy mode\n",
+ __func__, offset);
+ return;
+ }
+ proxy->vqs[vdev->queue_sel].desc[1] = value;
+ break;
+ case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
+ if (proxy->legacy) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to non-legacy register (0x%"
+ HWADDR_PRIx ") in legacy mode\n",
+ __func__, offset);
+ return;
+ }
+ proxy->vqs[vdev->queue_sel].avail[0] = value;
+ break;
+ case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
+ if (proxy->legacy) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to non-legacy register (0x%"
+ HWADDR_PRIx ") in legacy mode\n",
+ __func__, offset);
+ return;
+ }
+ proxy->vqs[vdev->queue_sel].avail[1] = value;
+ break;
+ case VIRTIO_MMIO_QUEUE_USED_LOW:
+ if (proxy->legacy) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to non-legacy register (0x%"
+ HWADDR_PRIx ") in legacy mode\n",
+ __func__, offset);
+ return;
+ }
+ proxy->vqs[vdev->queue_sel].used[0] = value;
+ break;
+ case VIRTIO_MMIO_QUEUE_USED_HIGH:
+ if (proxy->legacy) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to non-legacy register (0x%"
+ HWADDR_PRIx ") in legacy mode\n",
+ __func__, offset);
+ return;
+ }
+ proxy->vqs[vdev->queue_sel].used[1] = value;
+ break;
case VIRTIO_MMIO_MAGIC_VALUE:
case VIRTIO_MMIO_VERSION:
case VIRTIO_MMIO_DEVICE_ID:
case VIRTIO_MMIO_DEVICE_FEATURES:
case VIRTIO_MMIO_QUEUE_NUM_MAX:
case VIRTIO_MMIO_INTERRUPT_STATUS:
+ case VIRTIO_MMIO_CONFIG_GENERATION:
qemu_log_mask(LOG_GUEST_ERROR,
- "%s: write to readonly register\n",
- __func__);
+ "%s: write to read-only register (0x%" HWADDR_PRIx ")\n",
+ __func__, offset);
break;
default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: bad register offset\n", __func__);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad register offset (0x%" HWADDR_PRIx ")\n",
+ __func__, offset);
}
}
-static const MemoryRegionOps virtio_mem_ops = {
+static const MemoryRegionOps virtio_legacy_mem_ops = {
.read = virtio_mmio_read,
.write = virtio_mmio_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
+static const MemoryRegionOps virtio_mem_ops = {
+ .read = virtio_mmio_read,
+ .write = virtio_mmio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
static void virtio_mmio_update_irq(DeviceState *opaque, uint16_t vector)
{
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
qemu_put_be32(f, proxy->guest_page_shift);
}
+static const VMStateDescription vmstate_virtio_mmio_queue_state = {
+ .name = "virtio_mmio/queue_state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(num, VirtIOMMIOQueue),
+ VMSTATE_BOOL(enabled, VirtIOMMIOQueue),
+ VMSTATE_UINT32_ARRAY(desc, VirtIOMMIOQueue, 2),
+ VMSTATE_UINT32_ARRAY(avail, VirtIOMMIOQueue, 2),
+ VMSTATE_UINT32_ARRAY(used, VirtIOMMIOQueue, 2),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_virtio_mmio_state_sub = {
+ .name = "virtio_mmio/state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(guest_features, VirtIOMMIOProxy, 2),
+ VMSTATE_STRUCT_ARRAY(vqs, VirtIOMMIOProxy, VIRTIO_QUEUE_MAX, 0,
+ vmstate_virtio_mmio_queue_state,
+ VirtIOMMIOQueue),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_virtio_mmio = {
+ .name = "virtio_mmio",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_virtio_mmio_state_sub,
+ NULL
+ }
+};
+
+static void virtio_mmio_save_extra_state(DeviceState *opaque, QEMUFile *f)
+{
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
+
+ vmstate_save_state(f, &vmstate_virtio_mmio, proxy, NULL);
+}
+
+static int virtio_mmio_load_extra_state(DeviceState *opaque, QEMUFile *f)
+{
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
+
+ return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1);
+}
+
+static bool virtio_mmio_has_extra_state(DeviceState *opaque)
+{
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
+
+ return !proxy->legacy;
+}
+
static void virtio_mmio_reset(DeviceState *d)
{
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
+ int i;
virtio_mmio_stop_ioeventfd(proxy);
virtio_bus_reset(&proxy->bus);
proxy->host_features_sel = 0;
proxy->guest_features_sel = 0;
proxy->guest_page_shift = 0;
+
+ if (!proxy->legacy) {
+ proxy->guest_features[0] = proxy->guest_features[1] = 0;
+
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
+ proxy->vqs[i].enabled = 0;
+ proxy->vqs[i].num = 0;
+ proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
+ proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0;
+ proxy->vqs[i].used[0] = proxy->vqs[i].used[1] = 0;
+ }
+ }
}
static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign,
return r;
}
+static void virtio_mmio_pre_plugged(DeviceState *d, Error **errp)
+{
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
+ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
+
+ if (!proxy->legacy) {
+ virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
+ }
+}
+
/* virtio-mmio device */
static Property virtio_mmio_properties[] = {
DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy,
format_transport_address, true),
+ DEFINE_PROP_BOOL("force-legacy", VirtIOMMIOProxy, legacy, true),
DEFINE_PROP_END_OF_LIST(),
};
qbus_create_inplace(&proxy->bus, sizeof(proxy->bus), TYPE_VIRTIO_MMIO_BUS,
d, NULL);
sysbus_init_irq(sbd, &proxy->irq);
- memory_region_init_io(&proxy->iomem, OBJECT(d), &virtio_mem_ops, proxy,
- TYPE_VIRTIO_MMIO, 0x200);
+ if (proxy->legacy) {
+ memory_region_init_io(&proxy->iomem, OBJECT(d),
+ &virtio_legacy_mem_ops, proxy,
+ TYPE_VIRTIO_MMIO, 0x200);
+ } else {
+ memory_region_init_io(&proxy->iomem, OBJECT(d),
+ &virtio_mem_ops, proxy,
+ TYPE_VIRTIO_MMIO, 0x200);
+ }
sysbus_init_mmio(sbd, &proxy->iomem);
}
k->notify = virtio_mmio_update_irq;
k->save_config = virtio_mmio_save_config;
k->load_config = virtio_mmio_load_config;
+ k->save_extra_state = virtio_mmio_save_extra_state;
+ k->load_extra_state = virtio_mmio_load_extra_state;
+ k->has_extra_state = virtio_mmio_has_extra_state;
k->set_guest_notifiers = virtio_mmio_set_guest_notifiers;
k->ioeventfd_enabled = virtio_mmio_ioeventfd_enabled;
k->ioeventfd_assign = virtio_mmio_ioeventfd_assign;
+ k->pre_plugged = virtio_mmio_pre_plugged;
k->has_variable_vring_alignment = true;
bus_class->max_dev = 1;
bus_class->get_dev_path = virtio_mmio_bus_get_dev_path;
* The function pointer to hook different machine specific functions for
* parsing "smp-opts" from QemuOpts to MachineState::CpuTopology and more
* machine specific topology fields, such as smp_dies for PCMachine.
+ * @hotplug_allowed:
+ * If the hook is provided, then it'll be called for each device
+ * hotplug to check whether the device hotplug is allowed. Return
+ * true to grant allowance or false to reject the hotplug. When
+ * false is returned, an error must be set to show the reason of
+ * the rejection. If the hook is not provided, all hotplug will be
+ * allowed.
*/
struct MachineClass {
/*< private >*/
HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
DeviceState *dev);
+ bool (*hotplug_allowed)(MachineState *state, DeviceState *dev,
+ Error **errp);
CpuInstanceProperties (*cpu_index_to_instance_props)(MachineState *machine,
unsigned cpu_index);
const CPUArchIdList *(*possible_cpu_arch_ids)(MachineState *machine);
int required_for_version);
HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev);
HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev);
+bool qdev_hotplug_allowed(DeviceState *dev, Error **errp);
/**
* qdev_get_hotplug_handler: Get handler responsible for device wiring
*
void riscv_find_and_load_firmware(MachineState *machine,
const char *default_machine_firmware,
hwaddr firmware_load_addr);
+char *riscv_find_firmware(const char *firmware_filename);
target_ulong riscv_load_firmware(const char *firmware_filename,
hwaddr firmware_load_addr);
target_ulong riscv_load_kernel(const char *kernel_filename);
/*< public >*/
uint32_t num_harts;
+ uint32_t hartid_base;
char *cpu_type;
RISCVCPU *harts;
} RISCVHartArrayState;
--- /dev/null
+/*
+ * SiFive CPU types
+ *
+ * Copyright (c) 2017 SiFive, Inc.
+ * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_SIFIVE_CPU_H
+#define HW_SIFIVE_CPU_H
+
+#if defined(TARGET_RISCV32)
+#define SIFIVE_E_CPU TYPE_RISCV_CPU_SIFIVE_E31
+#define SIFIVE_U_CPU TYPE_RISCV_CPU_SIFIVE_U34
+#elif defined(TARGET_RISCV64)
+#define SIFIVE_E_CPU TYPE_RISCV_CPU_SIFIVE_E51
+#define SIFIVE_U_CPU TYPE_RISCV_CPU_SIFIVE_U54
+#endif
+
+#endif /* HW_SIFIVE_CPU_H */
#define HW_SIFIVE_E_H
#include "hw/riscv/riscv_hart.h"
+#include "hw/riscv/sifive_cpu.h"
#include "hw/riscv/sifive_gpio.h"
#define TYPE_RISCV_E_SOC "riscv.sifive.e.soc"
#define SIFIVE_E_PLIC_CONTEXT_BASE 0x200000
#define SIFIVE_E_PLIC_CONTEXT_STRIDE 0x1000
-#if defined(TARGET_RISCV32)
-#define SIFIVE_E_CPU TYPE_RISCV_CPU_SIFIVE_E31
-#elif defined(TARGET_RISCV64)
-#define SIFIVE_E_CPU TYPE_RISCV_CPU_SIFIVE_E51
-#endif
-
#endif
--- /dev/null
+/*
+ * QEMU SiFive E PRCI (Power, Reset, Clock, Interrupt) interface
+ *
+ * Copyright (c) 2017 SiFive, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_SIFIVE_E_PRCI_H
+#define HW_SIFIVE_E_PRCI_H
+
+enum {
+ SIFIVE_E_PRCI_HFROSCCFG = 0x0,
+ SIFIVE_E_PRCI_HFXOSCCFG = 0x4,
+ SIFIVE_E_PRCI_PLLCFG = 0x8,
+ SIFIVE_E_PRCI_PLLOUTDIV = 0xC
+};
+
+enum {
+ SIFIVE_E_PRCI_HFROSCCFG_RDY = (1 << 31),
+ SIFIVE_E_PRCI_HFROSCCFG_EN = (1 << 30)
+};
+
+enum {
+ SIFIVE_E_PRCI_HFXOSCCFG_RDY = (1 << 31),
+ SIFIVE_E_PRCI_HFXOSCCFG_EN = (1 << 30)
+};
+
+enum {
+ SIFIVE_E_PRCI_PLLCFG_PLLSEL = (1 << 16),
+ SIFIVE_E_PRCI_PLLCFG_REFSEL = (1 << 17),
+ SIFIVE_E_PRCI_PLLCFG_BYPASS = (1 << 18),
+ SIFIVE_E_PRCI_PLLCFG_LOCK = (1 << 31)
+};
+
+enum {
+ SIFIVE_E_PRCI_PLLOUTDIV_DIV1 = (1 << 8)
+};
+
+#define SIFIVE_E_PRCI_REG_SIZE 0x1000
+
+#define TYPE_SIFIVE_E_PRCI "riscv.sifive.e.prci"
+
+#define SIFIVE_E_PRCI(obj) \
+ OBJECT_CHECK(SiFiveEPRCIState, (obj), TYPE_SIFIVE_E_PRCI)
+
+typedef struct SiFiveEPRCIState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ MemoryRegion mmio;
+ uint32_t hfrosccfg;
+ uint32_t hfxosccfg;
+ uint32_t pllcfg;
+ uint32_t plloutdiv;
+} SiFiveEPRCIState;
+
+DeviceState *sifive_e_prci_create(hwaddr addr);
+
+#endif
uint32_t aperture_size;
} SiFivePLICState;
-void sifive_plic_raise_irq(SiFivePLICState *plic, uint32_t irq);
-void sifive_plic_lower_irq(SiFivePLICState *plic, uint32_t irq);
-
DeviceState *sifive_plic_create(hwaddr addr, char *hart_config,
uint32_t num_sources, uint32_t num_priorities,
uint32_t priority_base, uint32_t pending_base,
+++ /dev/null
-/*
- * QEMU SiFive PRCI (Power, Reset, Clock, Interrupt) interface
- *
- * Copyright (c) 2017 SiFive, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2 or later, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef HW_SIFIVE_PRCI_H
-#define HW_SIFIVE_PRCI_H
-
-#include "hw/sysbus.h"
-
-enum {
- SIFIVE_PRCI_HFROSCCFG = 0x0,
- SIFIVE_PRCI_HFXOSCCFG = 0x4,
- SIFIVE_PRCI_PLLCFG = 0x8,
- SIFIVE_PRCI_PLLOUTDIV = 0xC
-};
-
-enum {
- SIFIVE_PRCI_HFROSCCFG_RDY = (1 << 31),
- SIFIVE_PRCI_HFROSCCFG_EN = (1 << 30)
-};
-
-enum {
- SIFIVE_PRCI_HFXOSCCFG_RDY = (1 << 31),
- SIFIVE_PRCI_HFXOSCCFG_EN = (1 << 30)
-};
-
-enum {
- SIFIVE_PRCI_PLLCFG_PLLSEL = (1 << 16),
- SIFIVE_PRCI_PLLCFG_REFSEL = (1 << 17),
- SIFIVE_PRCI_PLLCFG_BYPASS = (1 << 18),
- SIFIVE_PRCI_PLLCFG_LOCK = (1 << 31)
-};
-
-enum {
- SIFIVE_PRCI_PLLOUTDIV_DIV1 = (1 << 8)
-};
-
-#define TYPE_SIFIVE_PRCI "riscv.sifive.prci"
-
-#define SIFIVE_PRCI(obj) \
- OBJECT_CHECK(SiFivePRCIState, (obj), TYPE_SIFIVE_PRCI)
-
-typedef struct SiFivePRCIState {
- /*< private >*/
- SysBusDevice parent_obj;
-
- /*< public >*/
- MemoryRegion mmio;
- uint32_t hfrosccfg;
- uint32_t hfxosccfg;
- uint32_t pllcfg;
- uint32_t plloutdiv;
-} SiFivePRCIState;
-
-DeviceState *sifive_prci_create(hwaddr addr);
-
-#endif
enum {
FINISHER_FAIL = 0x3333,
- FINISHER_PASS = 0x5555
+ FINISHER_PASS = 0x5555,
+ FINISHER_RESET = 0x7777
};
DeviceState *sifive_test_create(hwaddr addr);
#include "hw/net/cadence_gem.h"
#include "hw/riscv/riscv_hart.h"
+#include "hw/riscv/sifive_cpu.h"
+#include "hw/riscv/sifive_u_prci.h"
+#include "hw/riscv/sifive_u_otp.h"
#define TYPE_RISCV_U_SOC "riscv.sifive.u.soc"
#define RISCV_U_SOC(obj) \
SysBusDevice parent_obj;
/*< public >*/
- RISCVHartArrayState cpus;
+ CPUClusterState e_cluster;
+ CPUClusterState u_cluster;
+ RISCVHartArrayState e_cpus;
+ RISCVHartArrayState u_cpus;
DeviceState *plic;
+ SiFiveUPRCIState prci;
+ SiFiveUOTPState otp;
CadenceGEMState gem;
} SiFiveUSoCState;
SIFIVE_U_MROM,
SIFIVE_U_CLINT,
SIFIVE_U_PLIC,
+ SIFIVE_U_PRCI,
SIFIVE_U_UART0,
SIFIVE_U_UART1,
+ SIFIVE_U_OTP,
SIFIVE_U_DRAM,
- SIFIVE_U_GEM
+ SIFIVE_U_GEM,
+ SIFIVE_U_GEM_MGMT
};
enum {
- SIFIVE_U_UART0_IRQ = 3,
- SIFIVE_U_UART1_IRQ = 4,
+ SIFIVE_U_UART0_IRQ = 4,
+ SIFIVE_U_UART1_IRQ = 5,
SIFIVE_U_GEM_IRQ = 0x35
};
enum {
SIFIVE_U_CLOCK_FREQ = 1000000000,
- SIFIVE_U_GEM_CLOCK_FREQ = 125000000
+ SIFIVE_U_HFCLK_FREQ = 33333333,
+ SIFIVE_U_RTCCLK_FREQ = 1000000
};
+#define SIFIVE_U_MANAGEMENT_CPU_COUNT 1
+#define SIFIVE_U_COMPUTE_CPU_COUNT 4
+
#define SIFIVE_U_PLIC_HART_CONFIG "MS"
#define SIFIVE_U_PLIC_NUM_SOURCES 54
#define SIFIVE_U_PLIC_NUM_PRIORITIES 7
#define SIFIVE_U_PLIC_CONTEXT_BASE 0x200000
#define SIFIVE_U_PLIC_CONTEXT_STRIDE 0x1000
-#if defined(TARGET_RISCV32)
-#define SIFIVE_U_CPU TYPE_RISCV_CPU_SIFIVE_U34
-#elif defined(TARGET_RISCV64)
-#define SIFIVE_U_CPU TYPE_RISCV_CPU_SIFIVE_U54
-#endif
-
#endif
--- /dev/null
+/*
+ * QEMU SiFive U OTP (One-Time Programmable) Memory interface
+ *
+ * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_SIFIVE_U_OTP_H
+#define HW_SIFIVE_U_OTP_H
+
+#define SIFIVE_U_OTP_PA 0x00
+#define SIFIVE_U_OTP_PAIO 0x04
+#define SIFIVE_U_OTP_PAS 0x08
+#define SIFIVE_U_OTP_PCE 0x0C
+#define SIFIVE_U_OTP_PCLK 0x10
+#define SIFIVE_U_OTP_PDIN 0x14
+#define SIFIVE_U_OTP_PDOUT 0x18
+#define SIFIVE_U_OTP_PDSTB 0x1C
+#define SIFIVE_U_OTP_PPROG 0x20
+#define SIFIVE_U_OTP_PTC 0x24
+#define SIFIVE_U_OTP_PTM 0x28
+#define SIFIVE_U_OTP_PTM_REP 0x2C
+#define SIFIVE_U_OTP_PTR 0x30
+#define SIFIVE_U_OTP_PTRIM 0x34
+#define SIFIVE_U_OTP_PWE 0x38
+
+#define SIFIVE_U_OTP_PCE_EN (1 << 0)
+
+#define SIFIVE_U_OTP_PDSTB_EN (1 << 0)
+
+#define SIFIVE_U_OTP_PTRIM_EN (1 << 0)
+
+#define SIFIVE_U_OTP_PA_MASK 0xfff
+#define SIFIVE_U_OTP_NUM_FUSES 0x1000
+#define SIFIVE_U_OTP_SERIAL_ADDR 0xfc
+
+#define SIFIVE_U_OTP_REG_SIZE 0x1000
+
+#define TYPE_SIFIVE_U_OTP "riscv.sifive.u.otp"
+
+#define SIFIVE_U_OTP(obj) \
+ OBJECT_CHECK(SiFiveUOTPState, (obj), TYPE_SIFIVE_U_OTP)
+
+typedef struct SiFiveUOTPState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ MemoryRegion mmio;
+ uint32_t pa;
+ uint32_t paio;
+ uint32_t pas;
+ uint32_t pce;
+ uint32_t pclk;
+ uint32_t pdin;
+ uint32_t pdstb;
+ uint32_t pprog;
+ uint32_t ptc;
+ uint32_t ptm;
+ uint32_t ptm_rep;
+ uint32_t ptr;
+ uint32_t ptrim;
+ uint32_t pwe;
+ uint32_t fuse[SIFIVE_U_OTP_NUM_FUSES];
+ /* config */
+ uint32_t serial;
+} SiFiveUOTPState;
+
+#endif /* HW_SIFIVE_U_OTP_H */
--- /dev/null
+/*
+ * QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt) interface
+ *
+ * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_SIFIVE_U_PRCI_H
+#define HW_SIFIVE_U_PRCI_H
+
+#define SIFIVE_U_PRCI_HFXOSCCFG 0x00
+#define SIFIVE_U_PRCI_COREPLLCFG0 0x04
+#define SIFIVE_U_PRCI_DDRPLLCFG0 0x0C
+#define SIFIVE_U_PRCI_DDRPLLCFG1 0x10
+#define SIFIVE_U_PRCI_GEMGXLPLLCFG0 0x1C
+#define SIFIVE_U_PRCI_GEMGXLPLLCFG1 0x20
+#define SIFIVE_U_PRCI_CORECLKSEL 0x24
+#define SIFIVE_U_PRCI_DEVICESRESET 0x28
+#define SIFIVE_U_PRCI_CLKMUXSTATUS 0x2C
+
+/*
+ * Current FU540-C000 manual says ready bit is at bit 29, but
+ * freedom-u540-c000-bootloader codes (ux00prci.h) says it is at bit 31.
+ * We have to trust the actual code that works.
+ *
+ * see https://github.com/sifive/freedom-u540-c000-bootloader
+ */
+
+#define SIFIVE_U_PRCI_HFXOSCCFG_EN (1 << 30)
+#define SIFIVE_U_PRCI_HFXOSCCFG_RDY (1 << 31)
+
+/* xxxPLLCFG0 register bits */
+#define SIFIVE_U_PRCI_PLLCFG0_DIVR (1 << 0)
+#define SIFIVE_U_PRCI_PLLCFG0_DIVF (31 << 6)
+#define SIFIVE_U_PRCI_PLLCFG0_DIVQ (3 << 15)
+#define SIFIVE_U_PRCI_PLLCFG0_FSE (1 << 25)
+#define SIFIVE_U_PRCI_PLLCFG0_LOCK (1 << 31)
+
+/* xxxPLLCFG1 register bits */
+#define SIFIVE_U_PRCI_PLLCFG1_CKE (1 << 24)
+
+/* coreclksel register bits */
+#define SIFIVE_U_PRCI_CORECLKSEL_HFCLK (1 << 0)
+
+
+#define SIFIVE_U_PRCI_REG_SIZE 0x1000
+
+#define TYPE_SIFIVE_U_PRCI "riscv.sifive.u.prci"
+
+#define SIFIVE_U_PRCI(obj) \
+ OBJECT_CHECK(SiFiveUPRCIState, (obj), TYPE_SIFIVE_U_PRCI)
+
+typedef struct SiFiveUPRCIState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ MemoryRegion mmio;
+ uint32_t hfxosccfg;
+ uint32_t corepllcfg0;
+ uint32_t ddrpllcfg0;
+ uint32_t ddrpllcfg1;
+ uint32_t gemgxlpllcfg0;
+ uint32_t gemgxlpllcfg1;
+ uint32_t coreclksel;
+ uint32_t devicesreset;
+ uint32_t clkmuxstatus;
+} SiFiveUPRCIState;
+
+/*
+ * Clock indexes for use by Device Tree data and the PRCI driver.
+ *
+ * These values are from sifive-fu540-prci.h in the Linux kernel.
+ */
+#define PRCI_CLK_COREPLL 0
+#define PRCI_CLK_DDRPLL 1
+#define PRCI_CLK_GEMGXLPLL 2
+#define PRCI_CLK_TLCLK 3
+
+#endif /* HW_SIFIVE_U_PRCI_H */
int parse_debug_env(const char *name, int max, int initial);
const char *qemu_ether_ntoa(const MACAddr *mac);
-char *size_to_str(uint64_t val);
void page_size_init(void);
/* returns non-zero if dump is in progress, otherwise zero is
int qemu_strtosz_MiB(const char *nptr, const char **end, uint64_t *result);
int qemu_strtosz_metric(const char *nptr, const char **end, uint64_t *result);
+char *size_to_str(uint64_t val);
+
/* used to print char* safely */
#define STR_OR_NULL(str) ((str) ? (str) : "null")
int kvm_device_check_attr(int fd, uint32_t group, uint64_t attr);
/**
- * kvm_device_access - set or get value of a specific vm attribute
+ * kvm_device_access - set or get value of a specific device attribute
* @fd: The device file descriptor
* @group: the group
* @attr: the attribute of that group to set or get
GLuint texture, bool delete);
void egl_fb_setup_new_tex(egl_fb *fb, int width, int height);
void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip);
-void egl_fb_read(void *dst, egl_fb *src);
+void egl_fb_read(DisplaySurface *dst, egl_fb *src);
void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip);
void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip,
nbd_negotiate_new_style_size_flags(uint64_t size, unsigned flags) "advertising size %" PRIu64 " and flags 0x%x"
nbd_negotiate_success(void) "Negotiation succeeded"
nbd_receive_request(uint32_t magic, uint16_t flags, uint16_t type, uint64_t from, uint32_t len) "Got request: { magic = 0x%" PRIx32 ", .flags = 0x%" PRIx16 ", .type = 0x%" PRIx16 ", from = %" PRIu64 ", len = %" PRIu32 " }"
-nbd_blk_aio_attached(const char *name, void *ctx) "Export %s: Attaching clients to AIO context %p\n"
-nbd_blk_aio_detach(const char *name, void *ctx) "Export %s: Detaching clients from AIO context %p\n"
+nbd_blk_aio_attached(const char *name, void *ctx) "Export %s: Attaching clients to AIO context %p"
+nbd_blk_aio_detach(const char *name, void *ctx) "Export %s: Detaching clients from AIO context %p"
nbd_co_send_simple_reply(uint64_t handle, uint32_t error, const char *errname, int len) "Send simple reply: handle = %" PRIu64 ", error = %" PRIu32 " (%s), len = %d"
nbd_co_send_structured_done(uint64_t handle) "Send structured reply done: handle = %" PRIu64
nbd_co_send_structured_read(uint64_t handle, uint64_t offset, void *data, size_t size) "Send structured read data reply: handle = %" PRIu64 ", offset = %" PRIu64 ", data = %p, len = %zu"
colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, const char *stc, const char *std) "ppkt size = %d, ip_src = %s, ip_dst = %s, spkt size = %d, ip_src = %s, ip_dst = %s"
colo_old_packet_check_found(int64_t old_time) "%" PRId64
colo_compare_miscompare(void) ""
-colo_compare_tcp_info(const char *pkt, uint32_t seq, uint32_t ack, int hdlen, int pdlen, int offset, int flags) "%s: seq/ack= %u/%u hdlen= %d pdlen= %d offset= %d flags=%d\n"
+colo_compare_tcp_info(const char *pkt, uint32_t seq, uint32_t ack, int hdlen, int pdlen, int offset, int flags) "%s: seq/ack= %u/%u hdlen= %d pdlen= %d offset= %d flags=%d"
# filter-rewriter.c
colo_filter_rewriter_debug(void) ""
-colo_filter_rewriter_pkt_info(const char *func, const char *src, const char *dst, uint32_t seq, uint32_t ack, uint32_t flag) "%s: src/dst: %s/%s p: seq/ack=%u/%u flags=0x%x\n"
-colo_filter_rewriter_conn_offset(uint32_t offset) ": offset=%u\n"
+colo_filter_rewriter_pkt_info(const char *func, const char *src, const char *dst, uint32_t seq, uint32_t ack, uint32_t flag) "%s: src/dst: %s/%s p: seq/ack=%u/%u flags=0x%x"
+colo_filter_rewriter_conn_offset(uint32_t offset) ": offset=%u"
def _base_args(self):
args = super(QEMUQtestMachine, self)._base_args()
args.extend(['-qtest', 'unix:path=' + self._qtest_path,
- '-machine', 'accel=qtest'])
+ '-accel', 'qtest'])
return args
def _pre_launch(self):
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
+#include "qemu/cutils.h"
#include "qapi/string-output-visitor.h"
#include "qapi/visitor-impl.h"
#include "qemu/host-utils.h"
/* create device */
dev = DEVICE(object_new(driver));
+ /* Check whether the hotplug is allowed by the machine */
+ if (qdev_hotplug && !qdev_hotplug_allowed(dev, &err)) {
+ /* Error must be set in the machine hook */
+ assert(err);
+ goto err_del_dev;
+ }
+
if (bus) {
qdev_set_parent_bus(dev, bus);
} else if (qdev_hotplug && !qdev_get_machine_hotplug_handler(dev)) {
@subsection -no-kvm (since 1.3.0)
-The ``-no-kvm'' argument is now a synonym for setting
-``-machine accel=tcg''.
+The ``-no-kvm'' argument is now a synonym for setting ``-accel tcg''.
@subsection -usbdevice (since 2.10.0)
Enable FIPS 140-2 compliance mode.
ETEXI
-HXCOMM Deprecated by -machine accel=tcg property
+HXCOMM Deprecated by -accel tcg
DEF("no-kvm", 0, QEMU_OPTION_no_kvm, "", QEMU_ARCH_I386)
DEF("msg", HAS_ARG, QEMU_OPTION_msg,
opensbi64-sifive_u:
$(MAKE) -C opensbi \
CROSS_COMPILE=$(riscv64_cross_prefix) \
- PLATFORM="qemu/sifive_u"
- cp opensbi/build/platform/qemu/sifive_u/firmware/fw_jump.bin ../pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin
+ PLATFORM="sifive/fu540"
+ cp opensbi/build/platform/sifive/fu540/firmware/fw_jump.bin ../pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin
clean:
rm -rf seabios/.config seabios/out seabios/builds
if fmt.find("%m") != -1 or fmt_trans.find("%m") != -1:
raise ValueError("Event format '%m' is forbidden, pass the error "
"as an explicit trace argument")
+ if fmt.endswith(r'\n"'):
+ raise ValueError("Event format must not end with a newline "
+ "character")
if len(fmt_trans) > 0:
fmt = [fmt_trans, fmt]
uintptr_t ra);
static uint32_t fmovem_predec(CPUM68KState *env, uint32_t addr, uint32_t mask,
- float_access access)
+ float_access access_fn)
{
uintptr_t ra = GETPC();
int i, size;
for (i = 7; i >= 0; i--, mask <<= 1) {
if (mask & 0x80) {
- size = access(env, addr, &env->fregs[i], ra);
+ size = access_fn(env, addr, &env->fregs[i], ra);
if ((mask & 0xff) != 0x80) {
addr -= size;
}
}
static uint32_t fmovem_postinc(CPUM68KState *env, uint32_t addr, uint32_t mask,
- float_access access)
+ float_access access_fn)
{
uintptr_t ra = GETPC();
int i, size;
for (i = 0; i < 8; i++, mask <<= 1) {
if (mask & 0x80) {
- size = access(env, addr, &env->fregs[i], ra);
+ size = access_fn(env, addr, &env->fregs[i], ra);
addr += size;
}
}
-obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o pmp.o
+obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o
+obj-$(CONFIG_SOFTMMU) += pmp.o
+
+ifeq ($(CONFIG_SOFTMMU),y)
+obj-y += monitor.o
+endif
DECODETREE = $(SRC_PATH)/scripts/decodetree.py
static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG";
const char * const riscv_int_regnames[] = {
- "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
- "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
- "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
- "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
+ "x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1",
+ "x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3",
+ "x14/a4", "x15/a5", "x16/a6", "x17/a7", "x18/s2", "x19/s3", "x20/s4",
+ "x21/s5", "x22/s6", "x23/s7", "x24/s8", "x25/s9", "x26/s10", "x27/s11",
+ "x28/t3", "x29/t4", "x30/t5", "x31/t6"
};
const char * const riscv_fpr_regnames[] = {
- "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
- "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
- "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
- "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
+ "f0/ft0", "f1/ft1", "f2/ft2", "f3/ft3", "f4/ft4", "f5/ft5",
+ "f6/ft6", "f7/ft7", "f8/fs0", "f9/fs1", "f10/fa0", "f11/fa1",
+ "f12/fa2", "f13/fa3", "f14/fa4", "f15/fa5", "f16/fa6", "f17/fa7",
+ "f18/fs2", "f19/fs3", "f20/fs4", "f21/fs5", "f22/fs6", "f23/fs7",
+ "f24/fs8", "f25/fs9", "f26/fs10", "f27/fs11", "f28/ft8", "f29/ft9",
+ "f30/ft10", "f31/ft11"
};
const char * const riscv_excp_names[] = {
int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
+bool riscv_cpu_fp_enabled(CPURISCVState *env);
int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
#ifdef CONFIG_USER_ONLY
*flags = TB_FLAGS_MSTATUS_FS;
#else
- *flags = cpu_mmu_index(env, 0) | (env->mstatus & MSTATUS_FS);
+ *flags = cpu_mmu_index(env, 0);
+ if (riscv_cpu_fp_enabled(env)) {
+ *flags |= TB_FLAGS_MSTATUS_FS;
+ }
#endif
}
#define CSR_SPTBR 0x180
#define CSR_SATP 0x180
+/* Hpervisor CSRs */
+#define CSR_HSTATUS 0x600
+#define CSR_HEDELEG 0x602
+#define CSR_HIDELEG 0x603
+#define CSR_HCOUNTERNEN 0x606
+#define CSR_HGATP 0x680
+
+#if defined(TARGET_RISCV32)
+#define HGATP_MODE SATP32_MODE
+#define HGATP_VMID SATP32_ASID
+#define HGATP_PPN SATP32_PPN
+#endif
+#if defined(TARGET_RISCV64)
+#define HGATP_MODE SATP64_MODE
+#define HGATP_VMID SATP64_ASID
+#define HGATP_PPN SATP64_PPN
+#endif
+
/* Physical Memory Protection */
#define CSR_PMPCFG0 0x3a0
#define CSR_PMPCFG1 0x3a1
#define CSR_DPC 0x7b1
#define CSR_DSCRATCH 0x7b2
-/* Hpervisor CSRs */
-#define CSR_HSTATUS 0xa00
-#define CSR_HEDELEG 0xa02
-#define CSR_HIDELEG 0xa03
-#define CSR_HGATP 0xa80
-
-#if defined(TARGET_RISCV32)
-#define HGATP_MODE SATP32_MODE
-#define HGATP_ASID SATP32_ASID
-#define HGATP_PPN SATP32_PPN
-#endif
-#if defined(TARGET_RISCV64)
-#define HGATP_MODE SATP64_MODE
-#define HGATP_ASID SATP64_ASID
-#define HGATP_PPN SATP64_PPN
-#endif
-
/* Performance Counters */
#define CSR_MHPMCOUNTER3 0xb03
#define CSR_MHPMCOUNTER4 0xb04
#if !defined(CONFIG_USER_ONLY)
+/* Return true is floating point support is currently enabled */
+bool riscv_cpu_fp_enabled(CPURISCVState *env)
+{
+ if (env->mstatus & MSTATUS_FS) {
+ return true;
+ }
+
+ return false;
+}
+
int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
{
CPURISCVState *env = &cpu->env;
*prot = 0;
- target_ulong base;
+ hwaddr base;
int levels, ptidxbits, ptesize, vm, sum;
int mxr = get_field(env->mstatus, MSTATUS_MXR);
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- base = get_field(env->satp, SATP_PPN) << PGSHIFT;
+ base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT;
sum = get_field(env->mstatus, MSTATUS_SUM);
vm = get_field(env->satp, SATP_MODE);
switch (vm) {
g_assert_not_reached();
}
} else {
- base = env->sptbr << PGSHIFT;
+ base = (hwaddr)(env->sptbr) << PGSHIFT;
sum = !get_field(env->mstatus, MSTATUS_PUM);
vm = get_field(env->mstatus, MSTATUS_VM);
switch (vm) {
((1 << ptidxbits) - 1);
/* check that physical address of PTE is legal */
- target_ulong pte_addr = base + idx * ptesize;
+ hwaddr pte_addr = base + idx * ptesize;
if (riscv_feature(env, RISCV_FEATURE_PMP) &&
!pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong),
#elif defined(TARGET_RISCV64)
target_ulong pte = ldq_phys(cs->as, pte_addr);
#endif
- target_ulong ppn = pte >> PTE_PPN_SHIFT;
+ hwaddr ppn = pte >> PTE_PPN_SHIFT;
if (!(pte & PTE_V)) {
/* Invalid PTE */
static int fs(CPURISCVState *env, int csrno)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
#endif
static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
#endif
static int write_fflags(CPURISCVState *env, int csrno, target_ulong val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
env->mstatus |= MSTATUS_FS;
static int read_frm(CPURISCVState *env, int csrno, target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
#endif
static int write_frm(CPURISCVState *env, int csrno, target_ulong val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
env->mstatus |= MSTATUS_FS;
static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
#endif
static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
env->mstatus |= MSTATUS_FS;
{
target_ulong mstatus = env->mstatus;
target_ulong mask = 0;
+ int dirty;
/* flush tlb on mstatus fields that affect VM */
if (env->priv_ver <= PRIV_VERSION_1_09_1) {
* RV32: MPV and MTL are not in mstatus. The current plan is to
* add them to mstatush. For now, we just don't support it.
*/
- mask |= MSTATUS_MPP | MSTATUS_MPV;
+ mask |= MSTATUS_MTL | MSTATUS_MPV;
#endif
}
mstatus = (mstatus & ~mask) | (val & mask);
- int dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) |
- ((mstatus & MSTATUS_XS) == MSTATUS_XS);
+ dirty = (riscv_cpu_fp_enabled(env) &&
+ ((mstatus & MSTATUS_FS) == MSTATUS_FS)) |
+ ((mstatus & MSTATUS_XS) == MSTATUS_XS);
mstatus = set_field(mstatus, MSTATUS_SD, dirty);
env->mstatus = mstatus;
* register 33, so we recalculate the map index.
* This also works for CSR_FRM and CSR_FCSR.
*/
- result = riscv_csrrw_debug(env, n - 33 + 8, &val, 0, 0);
+ result = riscv_csrrw_debug(env, n - 33 + csr_register_map[8], &val,
+ 0, 0);
if (result == 0) {
return gdb_get_regl(mem_buf, val);
}
* register 33, so we recalculate the map index.
* This also works for CSR_FRM and CSR_FCSR.
*/
- result = riscv_csrrw_debug(env, n - 33 + 8, NULL, val, -1);
+ result = riscv_csrrw_debug(env, n - 33 + csr_register_map[8], NULL,
+ val, -1);
if (result == 0) {
return sizeof(target_ulong);
}
--- /dev/null
+/*
+ * QEMU monitor for RISC-V
+ *
+ * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
+ *
+ * RISC-V specific monitor commands implementation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "cpu_bits.h"
+#include "monitor/monitor.h"
+#include "monitor/hmp-target.h"
+
+#ifdef TARGET_RISCV64
+#define PTE_HEADER_FIELDS "vaddr paddr "\
+ "size attr\n"
+#define PTE_HEADER_DELIMITER "---------------- ---------------- "\
+ "---------------- -------\n"
+#else
+#define PTE_HEADER_FIELDS "vaddr paddr size attr\n"
+#define PTE_HEADER_DELIMITER "-------- ---------------- -------- -------\n"
+#endif
+
+/* Perform linear address sign extension */
+static target_ulong addr_canonical(int va_bits, target_ulong addr)
+{
+#ifdef TARGET_RISCV64
+ if (addr & (1UL << (va_bits - 1))) {
+ addr |= (hwaddr)-(1L << va_bits);
+ }
+#endif
+
+ return addr;
+}
+
+static void print_pte_header(Monitor *mon)
+{
+ monitor_printf(mon, PTE_HEADER_FIELDS);
+ monitor_printf(mon, PTE_HEADER_DELIMITER);
+}
+
+static void print_pte(Monitor *mon, int va_bits, target_ulong vaddr,
+ hwaddr paddr, target_ulong size, int attr)
+{
+ /* santity check on vaddr */
+ if (vaddr >= (1UL << va_bits)) {
+ return;
+ }
+
+ if (!size) {
+ return;
+ }
+
+ monitor_printf(mon, TARGET_FMT_lx " " TARGET_FMT_plx " " TARGET_FMT_lx
+ " %c%c%c%c%c%c%c\n",
+ addr_canonical(va_bits, vaddr),
+ paddr, size,
+ attr & PTE_R ? 'r' : '-',
+ attr & PTE_W ? 'w' : '-',
+ attr & PTE_X ? 'x' : '-',
+ attr & PTE_U ? 'u' : '-',
+ attr & PTE_G ? 'g' : '-',
+ attr & PTE_A ? 'a' : '-',
+ attr & PTE_D ? 'd' : '-');
+}
+
+static void walk_pte(Monitor *mon, hwaddr base, target_ulong start,
+ int level, int ptidxbits, int ptesize, int va_bits,
+ target_ulong *vbase, hwaddr *pbase, hwaddr *last_paddr,
+ target_ulong *last_size, int *last_attr)
+{
+ hwaddr pte_addr;
+ hwaddr paddr;
+ target_ulong pgsize;
+ target_ulong pte;
+ int ptshift;
+ int attr;
+ int idx;
+
+ if (level < 0) {
+ return;
+ }
+
+ ptshift = level * ptidxbits;
+ pgsize = 1UL << (PGSHIFT + ptshift);
+
+ for (idx = 0; idx < (1UL << ptidxbits); idx++) {
+ pte_addr = base + idx * ptesize;
+ cpu_physical_memory_read(pte_addr, &pte, ptesize);
+
+ paddr = (hwaddr)(pte >> PTE_PPN_SHIFT) << PGSHIFT;
+ attr = pte & 0xff;
+
+ /* PTE has to be valid */
+ if (attr & PTE_V) {
+ if (attr & (PTE_R | PTE_W | PTE_X)) {
+ /*
+ * A leaf PTE has been found
+ *
+ * If current PTE's permission bits differ from the last one,
+ * or current PTE's ppn does not make a contiguous physical
+ * address block together with the last one, print out the last
+ * contiguous mapped block details.
+ */
+ if ((*last_attr != attr) ||
+ (*last_paddr + *last_size != paddr)) {
+ print_pte(mon, va_bits, *vbase, *pbase,
+ *last_paddr + *last_size - *pbase, *last_attr);
+
+ *vbase = start;
+ *pbase = paddr;
+ *last_attr = attr;
+ }
+
+ *last_paddr = paddr;
+ *last_size = pgsize;
+ } else {
+ /* pointer to the next level of the page table */
+ walk_pte(mon, paddr, start, level - 1, ptidxbits, ptesize,
+ va_bits, vbase, pbase, last_paddr,
+ last_size, last_attr);
+ }
+ }
+
+ start += pgsize;
+ }
+
+}
+
+static void mem_info_svxx(Monitor *mon, CPUArchState *env)
+{
+ int levels, ptidxbits, ptesize, vm, va_bits;
+ hwaddr base;
+ target_ulong vbase;
+ hwaddr pbase;
+ hwaddr last_paddr;
+ target_ulong last_size;
+ int last_attr;
+
+ base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT;
+
+ vm = get_field(env->satp, SATP_MODE);
+ switch (vm) {
+ case VM_1_10_SV32:
+ levels = 2;
+ ptidxbits = 10;
+ ptesize = 4;
+ break;
+ case VM_1_10_SV39:
+ levels = 3;
+ ptidxbits = 9;
+ ptesize = 8;
+ break;
+ case VM_1_10_SV48:
+ levels = 4;
+ ptidxbits = 9;
+ ptesize = 8;
+ break;
+ case VM_1_10_SV57:
+ levels = 5;
+ ptidxbits = 9;
+ ptesize = 8;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+
+ /* calculate virtual address bits */
+ va_bits = PGSHIFT + levels * ptidxbits;
+
+ /* print header */
+ print_pte_header(mon);
+
+ vbase = -1;
+ pbase = -1;
+ last_paddr = -1;
+ last_size = 0;
+ last_attr = 0;
+
+ /* walk page tables, starting from address 0 */
+ walk_pte(mon, base, 0, levels - 1, ptidxbits, ptesize, va_bits,
+ &vbase, &pbase, &last_paddr, &last_size, &last_attr);
+
+ /* don't forget the last one */
+ print_pte(mon, va_bits, vbase, pbase,
+ last_paddr + last_size - pbase, last_attr);
+}
+
+void hmp_info_mem(Monitor *mon, const QDict *qdict)
+{
+ CPUArchState *env;
+
+ env = mon_get_cpu_env();
+ if (!env) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
+
+ if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
+ monitor_printf(mon, "S-mode MMU unavailable\n");
+ return;
+ }
+
+ if (env->priv_ver < PRIV_VERSION_1_10_0) {
+ monitor_printf(mon, "Privileged mode < 1.10 unsupported\n");
+ return;
+ }
+
+ if (!(env->satp & SATP_MODE)) {
+ monitor_printf(mon, "No translation or protection\n");
+ return;
+ }
+
+ mem_info_svxx(mon, env);
+}
#include "qemu/log.h"
#include "qapi/error.h"
#include "cpu.h"
-
-#ifndef CONFIG_USER_ONLY
-
-#define RISCV_DEBUG_PMP 0
-#define PMP_DEBUG(fmt, ...) \
- do { \
- if (RISCV_DEBUG_PMP) { \
- qemu_log_mask(LOG_TRACE, "%s: " fmt "\n", __func__, ##__VA_ARGS__);\
- } \
- } while (0)
+#include "trace.h"
static void pmp_write_cfg(CPURISCVState *env, uint32_t addr_index,
uint8_t val);
int i;
uint8_t cfg_val;
- PMP_DEBUG("hart " TARGET_FMT_ld ": reg%d, val: 0x" TARGET_FMT_lx,
- env->mhartid, reg_index, val);
+ trace_pmpcfg_csr_write(env->mhartid, reg_index, val);
if ((reg_index & 1) && (sizeof(target_ulong) == 8)) {
qemu_log_mask(LOG_GUEST_ERROR,
val = pmp_read_cfg(env, (reg_index * sizeof(target_ulong)) + i);
cfg_val |= (val << (i * 8));
}
-
- PMP_DEBUG("hart " TARGET_FMT_ld ": reg%d, val: 0x" TARGET_FMT_lx,
- env->mhartid, reg_index, cfg_val);
+ trace_pmpcfg_csr_read(env->mhartid, reg_index, cfg_val);
return cfg_val;
}
void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
target_ulong val)
{
- PMP_DEBUG("hart " TARGET_FMT_ld ": addr%d, val: 0x" TARGET_FMT_lx,
- env->mhartid, addr_index, val);
-
+ trace_pmpaddr_csr_write(env->mhartid, addr_index, val);
if (addr_index < MAX_RISCV_PMPS) {
if (!pmp_is_locked(env, addr_index)) {
env->pmp_state.pmp[addr_index].addr_reg = val;
*/
target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index)
{
- PMP_DEBUG("hart " TARGET_FMT_ld ": addr%d, val: 0x" TARGET_FMT_lx,
- env->mhartid, addr_index,
- env->pmp_state.pmp[addr_index].addr_reg);
+ target_ulong val = 0;
+
if (addr_index < MAX_RISCV_PMPS) {
- return env->pmp_state.pmp[addr_index].addr_reg;
+ val = env->pmp_state.pmp[addr_index].addr_reg;
+ trace_pmpaddr_csr_read(env->mhartid, addr_index, val);
} else {
qemu_log_mask(LOG_GUEST_ERROR,
"ignoring pmpaddr read - out of bounds\n");
- return 0;
}
-}
-#endif
+ return val;
+}
# target/riscv/cpu_helper.c
riscv_trap(uint64_t hartid, bool async, uint64_t cause, uint64_t epc, uint64_t tval, const char *desc) "hart:%"PRId64", async:%d, cause:%"PRId64", epc:0x%"PRIx64", tval:0x%"PRIx64", desc=%s"
+
+# pmp.c
+pmpcfg_csr_read(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": read reg%" PRIu32", val: 0x%" PRIx64
+pmpcfg_csr_write(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": write reg%" PRIu32", val: 0x%" PRIx64
+pmpaddr_csr_read(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": read addr%" PRIu32", val: 0x%" PRIx64
+pmpaddr_csr_write(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": write addr%" PRIu32", val: 0x%" PRIx64
"-qtest-log %s "
"-chardev socket,path=%s,id=char0 "
"-mon chardev=char0,mode=control "
- "-machine accel=qtest "
+ "-accel qtest "
"-display none "
"%s", qemu_binary, socket_path,
getenv("QTEST_LOG") ? "/dev/fd/2" : "/dev/null",
cmdline = "'" + cmdline + "'"
argv = [
- "-machine", "accel=kvm",
+ "-accel", "kvm",
"-cpu", "host",
"-kernel", self._kernel,
"-initrd", self._initrd,
done
fi
echo quit
- ) | $QEMU -machine accel=qtest -nographic -monitor stdio -serial none "$@"
+ ) | $QEMU -accel qtest -nographic -monitor stdio -serial none "$@"
echo
}
common-obj-y += keymaps.o console.o cursor.o qemu-pixman.o
common-obj-y += input.o input-keymap.o input-legacy.o kbd-state.o
+common-obj-y += input-barrier.o
common-obj-$(CONFIG_LINUX) += input-linux.o
common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o
common-obj-$(CONFIG_COCOA) += cocoa.o
if (!edpy->guest_fb.texture || !edpy->ds) {
return;
}
- assert(surface_width(edpy->ds) == edpy->guest_fb.width);
- assert(surface_height(edpy->ds) == edpy->guest_fb.height);
assert(surface_format(edpy->ds) == PIXMAN_x8r8g8b8);
if (edpy->cursor_fb.texture) {
egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top);
}
- egl_fb_read(surface_data(edpy->ds), &edpy->blit_fb);
+ egl_fb_read(edpy->ds, &edpy->blit_fb);
dpy_gfx_update(edpy->dcl.con, x, y, w, h);
}
GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
-void egl_fb_read(void *dst, egl_fb *src)
+void egl_fb_read(DisplaySurface *dst, egl_fb *src)
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer);
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
- glReadPixels(0, 0, src->width, src->height,
- GL_BGRA, GL_UNSIGNED_BYTE, dst);
+ glReadPixels(0, 0, surface_width(dst), surface_height(dst),
+ GL_BGRA, GL_UNSIGNED_BYTE, surface_data(dst));
}
void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip)
--- /dev/null
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "sysemu/sysemu.h"
+#include "qemu/main-loop.h"
+#include "qemu/sockets.h"
+#include "qapi/error.h"
+#include "qom/object_interfaces.h"
+#include "io/channel-socket.h"
+#include "ui/input.h"
+#include "ui/vnc_keysym.h" /* use name2keysym from VNC as we use X11 values */
+#include "qemu/cutils.h"
+#include "qapi/qmp/qerror.h"
+#include "input-barrier.h"
+
+#define TYPE_INPUT_BARRIER "input-barrier"
+#define INPUT_BARRIER(obj) \
+ OBJECT_CHECK(InputBarrier, (obj), TYPE_INPUT_BARRIER)
+#define INPUT_BARRIER_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(InputBarrierClass, (obj), TYPE_INPUT_BARRIER)
+#define INPUT_BARRIER_CLASS(klass) \
+ OBJECT_CLASS_CHECK(InputBarrierClass, (klass), TYPE_INPUT_BARRIER)
+
+typedef struct InputBarrier InputBarrier;
+typedef struct InputBarrierClass InputBarrierClass;
+
+#define MAX_HELLO_LENGTH 1024
+
+struct InputBarrier {
+ Object parent;
+
+ QIOChannelSocket *sioc;
+ guint ioc_tag;
+
+ /* display properties */
+ gchar *name;
+ int16_t x_origin, y_origin;
+ int16_t width, height;
+
+ /* keyboard/mouse server */
+
+ SocketAddress saddr;
+
+ char buffer[MAX_HELLO_LENGTH];
+};
+
+struct InputBarrierClass {
+ ObjectClass parent_class;
+};
+
+static const char *cmd_names[] = {
+ [barrierCmdCNoop] = "CNOP",
+ [barrierCmdCClose] = "CBYE",
+ [barrierCmdCEnter] = "CINN",
+ [barrierCmdCLeave] = "COUT",
+ [barrierCmdCClipboard] = "CCLP",
+ [barrierCmdCScreenSaver] = "CSEC",
+ [barrierCmdCResetOptions] = "CROP",
+ [barrierCmdCInfoAck] = "CIAK",
+ [barrierCmdCKeepAlive] = "CALV",
+ [barrierCmdDKeyDown] = "DKDN",
+ [barrierCmdDKeyRepeat] = "DKRP",
+ [barrierCmdDKeyUp] = "DKUP",
+ [barrierCmdDMouseDown] = "DMDN",
+ [barrierCmdDMouseUp] = "DMUP",
+ [barrierCmdDMouseMove] = "DMMV",
+ [barrierCmdDMouseRelMove] = "DMRM",
+ [barrierCmdDMouseWheel] = "DMWM",
+ [barrierCmdDClipboard] = "DCLP",
+ [barrierCmdDInfo] = "DINF",
+ [barrierCmdDSetOptions] = "DSOP",
+ [barrierCmdDFileTransfer] = "DFTR",
+ [barrierCmdDDragInfo] = "DDRG",
+ [barrierCmdQInfo] = "QINF",
+ [barrierCmdEIncompatible] = "EICV",
+ [barrierCmdEBusy] = "EBSY",
+ [barrierCmdEUnknown] = "EUNK",
+ [barrierCmdEBad] = "EBAD",
+ [barrierCmdHello] = "Barrier",
+ [barrierCmdHelloBack] = "Barrier",
+};
+
+static kbd_layout_t *kbd_layout;
+
+static int input_barrier_to_qcode(uint16_t keyid, uint16_t keycode)
+{
+ /* keycode is optional, if it is not provided use keyid */
+ if (keycode && keycode <= qemu_input_map_xorgkbd_to_qcode_len) {
+ return qemu_input_map_xorgkbd_to_qcode[keycode];
+ }
+
+ if (keyid >= 0xE000 && keyid <= 0xEFFF) {
+ keyid += 0x1000;
+ }
+
+ /* keyid is the X11 key id */
+ if (kbd_layout) {
+ keycode = keysym2scancode(kbd_layout, keyid, NULL, false);
+
+ return qemu_input_key_number_to_qcode(keycode);
+ }
+
+ return qemu_input_map_x11_to_qcode[keyid];
+}
+
+static int input_barrier_to_mouse(uint8_t buttonid)
+{
+ switch (buttonid) {
+ case barrierButtonLeft:
+ return INPUT_BUTTON_LEFT;
+ case barrierButtonMiddle:
+ return INPUT_BUTTON_MIDDLE;
+ case barrierButtonRight:
+ return INPUT_BUTTON_RIGHT;
+ case barrierButtonExtra0:
+ return INPUT_BUTTON_SIDE;
+ }
+ return buttonid;
+}
+
+#define read_char(x, p, l) \
+do { \
+ int size = sizeof(char); \
+ if (l < size) { \
+ return G_SOURCE_REMOVE; \
+ } \
+ x = *(char *)p; \
+ p += size; \
+ l -= size; \
+} while (0)
+
+#define read_short(x, p, l) \
+do { \
+ int size = sizeof(short); \
+ if (l < size) { \
+ return G_SOURCE_REMOVE; \
+ } \
+ x = ntohs(*(short *)p); \
+ p += size; \
+ l -= size; \
+} while (0)
+
+#define write_short(p, x, l) \
+do { \
+ int size = sizeof(short); \
+ if (l < size) { \
+ return G_SOURCE_REMOVE; \
+ } \
+ *(short *)p = htons(x); \
+ p += size; \
+ l -= size; \
+} while (0)
+
+#define read_int(x, p, l) \
+do { \
+ int size = sizeof(int); \
+ if (l < size) { \
+ return G_SOURCE_REMOVE; \
+ } \
+ x = ntohl(*(int *)p); \
+ p += size; \
+ l -= size; \
+} while (0)
+
+#define write_int(p, x, l) \
+do { \
+ int size = sizeof(int); \
+ if (l < size) { \
+ return G_SOURCE_REMOVE; \
+ } \
+ *(int *)p = htonl(x); \
+ p += size; \
+ l -= size; \
+} while (0)
+
+#define write_cmd(p, c, l) \
+do { \
+ int size = strlen(cmd_names[c]); \
+ if (l < size) { \
+ return G_SOURCE_REMOVE; \
+ } \
+ memcpy(p, cmd_names[c], size); \
+ p += size; \
+ l -= size; \
+} while (0)
+
+#define write_string(p, s, l) \
+do { \
+ int size = strlen(s); \
+ if (l < size + sizeof(int)) { \
+ return G_SOURCE_REMOVE; \
+ } \
+ *(int *)p = htonl(size); \
+ p += sizeof(size); \
+ l -= sizeof(size); \
+ memcpy(p, s, size); \
+ p += size; \
+ l -= size; \
+} while (0)
+
+static gboolean readcmd(InputBarrier *ib, struct barrierMsg *msg)
+{
+ int ret, len, i;
+ enum barrierCmd cmd;
+ char *p;
+
+ ret = qio_channel_read(QIO_CHANNEL(ib->sioc), (char *)&len, sizeof(len),
+ NULL);
+ if (ret < 0) {
+ return G_SOURCE_REMOVE;
+ }
+
+ len = ntohl(len);
+ if (len > MAX_HELLO_LENGTH) {
+ return G_SOURCE_REMOVE;
+ }
+
+ ret = qio_channel_read(QIO_CHANNEL(ib->sioc), ib->buffer, len, NULL);
+ if (ret < 0) {
+ return G_SOURCE_REMOVE;
+ }
+
+ p = ib->buffer;
+ if (len >= strlen(cmd_names[barrierCmdHello]) &&
+ memcmp(p, cmd_names[barrierCmdHello],
+ strlen(cmd_names[barrierCmdHello])) == 0) {
+ cmd = barrierCmdHello;
+ p += strlen(cmd_names[barrierCmdHello]);
+ len -= strlen(cmd_names[barrierCmdHello]);
+ } else {
+ for (cmd = 0; cmd < barrierCmdHello; cmd++) {
+ if (memcmp(ib->buffer, cmd_names[cmd], 4) == 0) {
+ break;
+ }
+ }
+
+ if (cmd == barrierCmdHello) {
+ return G_SOURCE_REMOVE;
+ }
+ p += 4;
+ len -= 4;
+ }
+
+ msg->cmd = cmd;
+ switch (cmd) {
+ /* connection */
+ case barrierCmdHello:
+ read_short(msg->version.major, p, len);
+ read_short(msg->version.minor, p, len);
+ break;
+ case barrierCmdDSetOptions:
+ read_int(msg->set.nb, p, len);
+ msg->set.nb /= 2;
+ if (msg->set.nb > BARRIER_MAX_OPTIONS) {
+ msg->set.nb = BARRIER_MAX_OPTIONS;
+ }
+ i = 0;
+ while (len && i < msg->set.nb) {
+ read_int(msg->set.option[i].id, p, len);
+ /* it's a string, restore endianness */
+ msg->set.option[i].id = htonl(msg->set.option[i].id);
+ msg->set.option[i].nul = 0;
+ read_int(msg->set.option[i].value, p, len);
+ i++;
+ }
+ break;
+ case barrierCmdQInfo:
+ break;
+
+ /* mouse */
+ case barrierCmdDMouseMove:
+ case barrierCmdDMouseRelMove:
+ read_short(msg->mousepos.x, p, len);
+ read_short(msg->mousepos.y, p, len);
+ break;
+ case barrierCmdDMouseDown:
+ case barrierCmdDMouseUp:
+ read_char(msg->mousebutton.buttonid, p, len);
+ break;
+ case barrierCmdDMouseWheel:
+ read_short(msg->mousepos.y, p, len);
+ msg->mousepos.x = 0;
+ if (len) {
+ msg->mousepos.x = msg->mousepos.y;
+ read_short(msg->mousepos.y, p, len);
+ }
+ break;
+
+ /* keyboard */
+ case barrierCmdDKeyDown:
+ case barrierCmdDKeyUp:
+ read_short(msg->key.keyid, p, len);
+ read_short(msg->key.modifier, p, len);
+ msg->key.button = 0;
+ if (len) {
+ read_short(msg->key.button, p, len);
+ }
+ break;
+ case barrierCmdDKeyRepeat:
+ read_short(msg->repeat.keyid, p, len);
+ read_short(msg->repeat.modifier, p, len);
+ read_short(msg->repeat.repeat, p, len);
+ msg->repeat.button = 0;
+ if (len) {
+ read_short(msg->repeat.button, p, len);
+ }
+ break;
+ case barrierCmdCInfoAck:
+ case barrierCmdCResetOptions:
+ case barrierCmdCEnter:
+ case barrierCmdDClipboard:
+ case barrierCmdCKeepAlive:
+ case barrierCmdCLeave:
+ case barrierCmdCClose:
+ break;
+
+ /* Invalid from the server */
+ case barrierCmdHelloBack:
+ case barrierCmdCNoop:
+ case barrierCmdDInfo:
+ break;
+
+ /* Error codes */
+ case barrierCmdEIncompatible:
+ read_short(msg->version.major, p, len);
+ read_short(msg->version.minor, p, len);
+ break;
+ case barrierCmdEBusy:
+ case barrierCmdEUnknown:
+ case barrierCmdEBad:
+ break;
+ default:
+ return G_SOURCE_REMOVE;
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+static gboolean writecmd(InputBarrier *ib, struct barrierMsg *msg)
+{
+ char *p;
+ int ret, i;
+ int avail, len;
+
+ p = ib->buffer;
+ avail = MAX_HELLO_LENGTH;
+
+ /* reserve space to store the length */
+ p += sizeof(int);
+ avail -= sizeof(int);
+
+ switch (msg->cmd) {
+ case barrierCmdHello:
+ if (msg->version.major < BARRIER_VERSION_MAJOR ||
+ (msg->version.major == BARRIER_VERSION_MAJOR &&
+ msg->version.minor < BARRIER_VERSION_MINOR)) {
+ ib->ioc_tag = 0;
+ return G_SOURCE_REMOVE;
+ }
+ write_cmd(p, barrierCmdHelloBack, avail);
+ write_short(p, BARRIER_VERSION_MAJOR, avail);
+ write_short(p, BARRIER_VERSION_MINOR, avail);
+ write_string(p, ib->name, avail);
+ break;
+ case barrierCmdCClose:
+ ib->ioc_tag = 0;
+ return G_SOURCE_REMOVE;
+ case barrierCmdQInfo:
+ write_cmd(p, barrierCmdDInfo, avail);
+ write_short(p, ib->x_origin, avail);
+ write_short(p, ib->y_origin, avail);
+ write_short(p, ib->width, avail);
+ write_short(p, ib->height, avail);
+ write_short(p, 0, avail); /* warpsize (obsolete) */
+ write_short(p, 0, avail); /* mouse x */
+ write_short(p, 0, avail); /* mouse y */
+ break;
+ case barrierCmdCInfoAck:
+ break;
+ case barrierCmdCResetOptions:
+ /* TODO: reset options */
+ break;
+ case barrierCmdDSetOptions:
+ /* TODO: set options */
+ break;
+ case barrierCmdCEnter:
+ break;
+ case barrierCmdDClipboard:
+ break;
+ case barrierCmdCKeepAlive:
+ write_cmd(p, barrierCmdCKeepAlive, avail);
+ break;
+ case barrierCmdCLeave:
+ break;
+
+ /* mouse */
+ case barrierCmdDMouseMove:
+ qemu_input_queue_abs(NULL, INPUT_AXIS_X, msg->mousepos.x,
+ ib->x_origin, ib->width);
+ qemu_input_queue_abs(NULL, INPUT_AXIS_Y, msg->mousepos.y,
+ ib->y_origin, ib->height);
+ qemu_input_event_sync();
+ break;
+ case barrierCmdDMouseRelMove:
+ qemu_input_queue_rel(NULL, INPUT_AXIS_X, msg->mousepos.x);
+ qemu_input_queue_rel(NULL, INPUT_AXIS_Y, msg->mousepos.y);
+ qemu_input_event_sync();
+ break;
+ case barrierCmdDMouseDown:
+ qemu_input_queue_btn(NULL,
+ input_barrier_to_mouse(msg->mousebutton.buttonid),
+ true);
+ qemu_input_event_sync();
+ break;
+ case barrierCmdDMouseUp:
+ qemu_input_queue_btn(NULL,
+ input_barrier_to_mouse(msg->mousebutton.buttonid),
+ false);
+ qemu_input_event_sync();
+ break;
+ case barrierCmdDMouseWheel:
+ qemu_input_queue_btn(NULL, (msg->mousepos.y > 0) ? INPUT_BUTTON_WHEEL_UP
+ : INPUT_BUTTON_WHEEL_DOWN, true);
+ qemu_input_event_sync();
+ qemu_input_queue_btn(NULL, (msg->mousepos.y > 0) ? INPUT_BUTTON_WHEEL_UP
+ : INPUT_BUTTON_WHEEL_DOWN, false);
+ qemu_input_event_sync();
+ break;
+
+ /* keyboard */
+ case barrierCmdDKeyDown:
+ qemu_input_event_send_key_qcode(NULL,
+ input_barrier_to_qcode(msg->key.keyid, msg->key.button),
+ true);
+ break;
+ case barrierCmdDKeyRepeat:
+ for (i = 0; i < msg->repeat.repeat; i++) {
+ qemu_input_event_send_key_qcode(NULL,
+ input_barrier_to_qcode(msg->repeat.keyid, msg->repeat.button),
+ false);
+ qemu_input_event_send_key_qcode(NULL,
+ input_barrier_to_qcode(msg->repeat.keyid, msg->repeat.button),
+ true);
+ }
+ break;
+ case barrierCmdDKeyUp:
+ qemu_input_event_send_key_qcode(NULL,
+ input_barrier_to_qcode(msg->key.keyid, msg->key.button),
+ false);
+ break;
+ default:
+ write_cmd(p, barrierCmdEUnknown, avail);
+ break;;
+ }
+
+ len = MAX_HELLO_LENGTH - avail - sizeof(int);
+ if (len) {
+ p = ib->buffer;
+ avail = sizeof(len);
+ write_int(p, len, avail);
+ ret = qio_channel_write(QIO_CHANNEL(ib->sioc), ib->buffer,
+ len + sizeof(len), NULL);
+ if (ret < 0) {
+ ib->ioc_tag = 0;
+ return G_SOURCE_REMOVE;
+ }
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+static gboolean input_barrier_event(QIOChannel *ioc G_GNUC_UNUSED,
+ GIOCondition condition, void *opaque)
+{
+ InputBarrier *ib = opaque;
+ int ret;
+ struct barrierMsg msg;
+
+ ret = readcmd(ib, &msg);
+ if (ret == G_SOURCE_REMOVE) {
+ ib->ioc_tag = 0;
+ return G_SOURCE_REMOVE;
+ }
+
+ return writecmd(ib, &msg);
+}
+
+static void input_barrier_complete(UserCreatable *uc, Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(uc);
+ Error *local_err = NULL;
+
+ if (!ib->name) {
+ error_setg(errp, QERR_MISSING_PARAMETER, "name");
+ return;
+ }
+
+ /*
+ * Connect to the primary
+ * Primary is the server where the keyboard and the mouse
+ * are connected and forwarded to the secondary (the client)
+ */
+
+ ib->sioc = qio_channel_socket_new();
+ qio_channel_set_name(QIO_CHANNEL(ib->sioc), "barrier-client");
+
+ qio_channel_socket_connect_sync(ib->sioc, &ib->saddr, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ qio_channel_set_delay(QIO_CHANNEL(ib->sioc), false);
+
+ ib->ioc_tag = qio_channel_add_watch(QIO_CHANNEL(ib->sioc), G_IO_IN,
+ input_barrier_event, ib, NULL);
+}
+
+static void input_barrier_instance_finalize(Object *obj)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+
+ if (ib->ioc_tag) {
+ g_source_remove(ib->ioc_tag);
+ ib->ioc_tag = 0;
+ }
+
+ if (ib->sioc) {
+ qio_channel_close(QIO_CHANNEL(ib->sioc), NULL);
+ object_unref(OBJECT(ib->sioc));
+ }
+ g_free(ib->name);
+ g_free(ib->saddr.u.inet.host);
+ g_free(ib->saddr.u.inet.port);
+}
+
+static char *input_barrier_get_name(Object *obj, Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+
+ return g_strdup(ib->name);
+}
+
+static void input_barrier_set_name(Object *obj, const char *value,
+ Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+
+ if (ib->name) {
+ error_setg(errp, "name property already set");
+ return;
+ }
+ ib->name = g_strdup(value);
+}
+
+static char *input_barrier_get_server(Object *obj, Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+
+ return g_strdup(ib->saddr.u.inet.host);
+}
+
+static void input_barrier_set_server(Object *obj, const char *value,
+ Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+
+ g_free(ib->saddr.u.inet.host);
+ ib->saddr.u.inet.host = g_strdup(value);
+}
+
+static char *input_barrier_get_port(Object *obj, Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+
+ return g_strdup(ib->saddr.u.inet.port);
+}
+
+static void input_barrier_set_port(Object *obj, const char *value,
+ Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+
+ g_free(ib->saddr.u.inet.port);
+ ib->saddr.u.inet.port = g_strdup(value);
+}
+
+static void input_barrier_set_x_origin(Object *obj, const char *value,
+ Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+ int result, err;
+
+ err = qemu_strtoi(value, NULL, 0, &result);
+ if (err < 0 || result < 0 || result > SHRT_MAX) {
+ error_setg(errp,
+ "x-origin property must be in the range [0..%d]", SHRT_MAX);
+ return;
+ }
+ ib->x_origin = result;
+}
+
+static char *input_barrier_get_x_origin(Object *obj, Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+
+ return g_strdup_printf("%d", ib->x_origin);
+}
+
+static void input_barrier_set_y_origin(Object *obj, const char *value,
+ Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+ int result, err;
+
+ err = qemu_strtoi(value, NULL, 0, &result);
+ if (err < 0 || result < 0 || result > SHRT_MAX) {
+ error_setg(errp,
+ "y-origin property must be in the range [0..%d]", SHRT_MAX);
+ return;
+ }
+ ib->y_origin = result;
+}
+
+static char *input_barrier_get_y_origin(Object *obj, Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+
+ return g_strdup_printf("%d", ib->y_origin);
+}
+
+static void input_barrier_set_width(Object *obj, const char *value,
+ Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+ int result, err;
+
+ err = qemu_strtoi(value, NULL, 0, &result);
+ if (err < 0 || result < 0 || result > SHRT_MAX) {
+ error_setg(errp,
+ "width property must be in the range [0..%d]", SHRT_MAX);
+ return;
+ }
+ ib->width = result;
+}
+
+static char *input_barrier_get_width(Object *obj, Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+
+ return g_strdup_printf("%d", ib->width);
+}
+
+static void input_barrier_set_height(Object *obj, const char *value,
+ Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+ int result, err;
+
+ err = qemu_strtoi(value, NULL, 0, &result);
+ if (err < 0 || result < 0 || result > SHRT_MAX) {
+ error_setg(errp,
+ "height property must be in the range [0..%d]", SHRT_MAX);
+ return;
+ }
+ ib->height = result;
+}
+
+static char *input_barrier_get_height(Object *obj, Error **errp)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+
+ return g_strdup_printf("%d", ib->height);
+}
+
+static void input_barrier_instance_init(Object *obj)
+{
+ InputBarrier *ib = INPUT_BARRIER(obj);
+
+ ib->saddr.type = SOCKET_ADDRESS_TYPE_INET;
+ ib->saddr.u.inet.host = g_strdup("localhost");
+ ib->saddr.u.inet.port = g_strdup("24800");
+
+ ib->x_origin = 0;
+ ib->y_origin = 0;
+ ib->width = 1920;
+ ib->height = 1080;
+
+ object_property_add_str(obj, "name",
+ input_barrier_get_name,
+ input_barrier_set_name, NULL);
+ object_property_add_str(obj, "server",
+ input_barrier_get_server,
+ input_barrier_set_server, NULL);
+ object_property_add_str(obj, "port",
+ input_barrier_get_port,
+ input_barrier_set_port, NULL);
+ object_property_add_str(obj, "x-origin",
+ input_barrier_get_x_origin,
+ input_barrier_set_x_origin, NULL);
+ object_property_add_str(obj, "y-origin",
+ input_barrier_get_y_origin,
+ input_barrier_set_y_origin, NULL);
+ object_property_add_str(obj, "width",
+ input_barrier_get_width,
+ input_barrier_set_width, NULL);
+ object_property_add_str(obj, "height",
+ input_barrier_get_height,
+ input_barrier_set_height, NULL);
+}
+
+static void input_barrier_class_init(ObjectClass *oc, void *data)
+{
+ UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
+
+ ucc->complete = input_barrier_complete;
+
+ /* always use generic keymaps */
+ if (keyboard_layout) {
+ /* We use X11 key id, so use VNC name2keysym */
+ kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout,
+ &error_fatal);
+ }
+}
+
+static const TypeInfo input_barrier_info = {
+ .name = TYPE_INPUT_BARRIER,
+ .parent = TYPE_OBJECT,
+ .class_size = sizeof(InputBarrierClass),
+ .class_init = input_barrier_class_init,
+ .instance_size = sizeof(InputBarrier),
+ .instance_init = input_barrier_instance_init,
+ .instance_finalize = input_barrier_instance_finalize,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_USER_CREATABLE },
+ { }
+ }
+};
+
+static void register_types(void)
+{
+ type_register_static(&input_barrier_info);
+}
+
+type_init(register_types);
--- /dev/null
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef UI_INPUT_BARRIER_H
+#define UI_INPUT_BARRIER_H
+
+/* Barrier protocol */
+#define BARRIER_VERSION_MAJOR 1
+#define BARRIER_VERSION_MINOR 6
+
+enum barrierCmd {
+ barrierCmdCNoop,
+ barrierCmdCClose,
+ barrierCmdCEnter,
+ barrierCmdCLeave,
+ barrierCmdCClipboard,
+ barrierCmdCScreenSaver,
+ barrierCmdCResetOptions,
+ barrierCmdCInfoAck,
+ barrierCmdCKeepAlive,
+ barrierCmdDKeyDown,
+ barrierCmdDKeyRepeat,
+ barrierCmdDKeyUp,
+ barrierCmdDMouseDown,
+ barrierCmdDMouseUp,
+ barrierCmdDMouseMove,
+ barrierCmdDMouseRelMove,
+ barrierCmdDMouseWheel,
+ barrierCmdDClipboard,
+ barrierCmdDInfo,
+ barrierCmdDSetOptions,
+ barrierCmdDFileTransfer,
+ barrierCmdDDragInfo,
+ barrierCmdQInfo,
+ barrierCmdEIncompatible,
+ barrierCmdEBusy,
+ barrierCmdEUnknown,
+ barrierCmdEBad,
+ /* connection sequence */
+ barrierCmdHello,
+ barrierCmdHelloBack,
+};
+
+enum {
+ barrierButtonNone,
+ barrierButtonLeft,
+ barrierButtonMiddle,
+ barrierButtonRight,
+ barrierButtonExtra0
+};
+
+struct barrierVersion {
+ int16_t major;
+ int16_t minor;
+};
+
+struct barrierMouseButton {
+ int8_t buttonid;
+};
+
+struct barrierEnter {
+ int16_t x;
+ int16_t y;
+ int32_t seqn;
+ int16_t modifier;
+};
+
+struct barrierMousePos {
+ int16_t x;
+ int16_t y;
+};
+
+struct barrierKey {
+ int16_t keyid;
+ int16_t modifier;
+ int16_t button;
+};
+
+struct barrierRepeat {
+ int16_t keyid;
+ int16_t modifier;
+ int16_t repeat;
+ int16_t button;
+};
+
+#define BARRIER_MAX_OPTIONS 32
+struct barrierSet {
+ int nb;
+ struct {
+ int id;
+ char nul;
+ int value;
+ } option[BARRIER_MAX_OPTIONS];
+};
+
+struct barrierMsg {
+ enum barrierCmd cmd;
+ union {
+ struct barrierVersion version;
+ struct barrierMouseButton mousebutton;
+ struct barrierMousePos mousepos;
+ struct barrierEnter enter;
+ struct barrierKey key;
+ struct barrierRepeat repeat;
+ struct barrierSet set;
+ };
+};
+#endif
static bool tight_can_send_png_rect(VncState *vs, int w, int h)
{
- if (vs->tight.type != VNC_ENCODING_TIGHT_PNG) {
+ if (vs->tight->type != VNC_ENCODING_TIGHT_PNG) {
return false;
}
int pixels = 0;
int pix, left[3];
unsigned int errors;
- unsigned char *buf = vs->tight.tight.buffer;
+ unsigned char *buf = vs->tight->tight.buffer;
/*
* If client is big-endian, color samples begin from the second
int pixels = 0; \
int sample, sum, left[3]; \
unsigned int errors; \
- unsigned char *buf = vs->tight.tight.buffer; \
+ unsigned char *buf = vs->tight->tight.buffer; \
\
endian = 0; /* FIXME */ \
\
tight_detect_smooth_image(VncState *vs, int w, int h)
{
unsigned int errors;
- int compression = vs->tight.compression;
- int quality = vs->tight.quality;
+ int compression = vs->tight->compression;
+ int quality = vs->tight->quality;
if (!vs->vd->lossy) {
return 0;
return 0;
}
- if (vs->tight.quality != (uint8_t)-1) {
+ if (vs->tight->quality != (uint8_t)-1) {
if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) {
return 0;
}
}
if (vs->client_pf.bytes_per_pixel == 4) {
- if (vs->tight.pixel24) {
+ if (vs->tight->pixel24) {
errors = tight_detect_smooth_image24(vs, w, h);
- if (vs->tight.quality != (uint8_t)-1) {
+ if (vs->tight->quality != (uint8_t)-1) {
return (errors < tight_conf[quality].jpeg_threshold24);
}
return (errors < tight_conf[compression].gradient_threshold24);
uint##bpp##_t c0, c1, ci; \
int i, n0, n1; \
\
- data = (uint##bpp##_t *)vs->tight.tight.buffer; \
+ data = (uint##bpp##_t *)vs->tight->tight.buffer; \
\
c0 = data[0]; \
i = 1; \
{
int max;
- max = count / tight_conf[vs->tight.compression].idx_max_colors_divisor;
+ max = count / tight_conf[vs->tight->compression].idx_max_colors_divisor;
if (max < 2 &&
- count >= tight_conf[vs->tight.compression].mono_min_rect_size) {
+ count >= tight_conf[vs->tight->compression].mono_min_rect_size) {
max = 2;
}
if (max >= 256) {
int x, y, c;
buf32 = (uint32_t *)buf;
- memset(vs->tight.gradient.buffer, 0, w * 3 * sizeof(int));
+ memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int));
if (1 /* FIXME */) {
shift[0] = vs->client_pf.rshift;
upper[c] = 0;
here[c] = 0;
}
- prev = (int *)vs->tight.gradient.buffer;
+ prev = (int *)vs->tight->gradient.buffer;
for (x = 0; x < w; x++) {
pix32 = *buf32++;
for (c = 0; c < 3; c++) {
int prediction; \
int x, y, c; \
\
- memset (vs->tight.gradient.buffer, 0, w * 3 * sizeof(int)); \
+ memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int)); \
\
endian = 0; /* FIXME */ \
\
upper[c] = 0; \
here[c] = 0; \
} \
- prev = (int *)vs->tight.gradient.buffer; \
+ prev = (int *)vs->tight->gradient.buffer; \
for (x = 0; x < w; x++) { \
pix = *buf; \
if (endian) { \
static int tight_init_stream(VncState *vs, int stream_id,
int level, int strategy)
{
- z_streamp zstream = &vs->tight.stream[stream_id];
+ z_streamp zstream = &vs->tight->stream[stream_id];
if (zstream->opaque == NULL) {
int err;
return -1;
}
- vs->tight.levels[stream_id] = level;
+ vs->tight->levels[stream_id] = level;
zstream->opaque = vs;
}
- if (vs->tight.levels[stream_id] != level) {
+ if (vs->tight->levels[stream_id] != level) {
if (deflateParams(zstream, level, strategy) != Z_OK) {
return -1;
}
- vs->tight.levels[stream_id] = level;
+ vs->tight->levels[stream_id] = level;
}
return 0;
}
static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
int level, int strategy)
{
- z_streamp zstream = &vs->tight.stream[stream_id];
+ z_streamp zstream = &vs->tight->stream[stream_id];
int previous_out;
if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) {
- vnc_write(vs, vs->tight.tight.buffer, vs->tight.tight.offset);
+ vnc_write(vs, vs->tight->tight.buffer, vs->tight->tight.offset);
return bytes;
}
}
/* reserve memory in output buffer */
- buffer_reserve(&vs->tight.zlib, bytes + 64);
+ buffer_reserve(&vs->tight->zlib, bytes + 64);
/* set pointers */
- zstream->next_in = vs->tight.tight.buffer;
- zstream->avail_in = vs->tight.tight.offset;
- zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset;
- zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset;
+ zstream->next_in = vs->tight->tight.buffer;
+ zstream->avail_in = vs->tight->tight.offset;
+ zstream->next_out = vs->tight->zlib.buffer + vs->tight->zlib.offset;
+ zstream->avail_out = vs->tight->zlib.capacity - vs->tight->zlib.offset;
previous_out = zstream->avail_out;
zstream->data_type = Z_BINARY;
return -1;
}
- vs->tight.zlib.offset = vs->tight.zlib.capacity - zstream->avail_out;
+ vs->tight->zlib.offset = vs->tight->zlib.capacity - zstream->avail_out;
/* ...how much data has actually been produced by deflate() */
bytes = previous_out - zstream->avail_out;
tight_send_compact_size(vs, bytes);
- vnc_write(vs, vs->tight.zlib.buffer, bytes);
+ vnc_write(vs, vs->tight->zlib.buffer, bytes);
- buffer_reset(&vs->tight.zlib);
+ buffer_reset(&vs->tight->zlib);
return bytes;
}
vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
- if (vs->tight.pixel24) {
- tight_pack24(vs, vs->tight.tight.buffer, w * h, &vs->tight.tight.offset);
+ if (vs->tight->pixel24) {
+ tight_pack24(vs, vs->tight->tight.buffer, w * h,
+ &vs->tight->tight.offset);
bytes = 3;
} else {
bytes = vs->client_pf.bytes_per_pixel;
}
bytes = tight_compress_data(vs, stream, w * h * bytes,
- tight_conf[vs->tight.compression].raw_zlib_level,
- Z_DEFAULT_STRATEGY);
+ tight_conf[vs->tight->compression].raw_zlib_level,
+ Z_DEFAULT_STRATEGY);
return (bytes >= 0);
}
vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */
- if (vs->tight.pixel24) {
- tight_pack24(vs, vs->tight.tight.buffer, 1, &vs->tight.tight.offset);
+ if (vs->tight->pixel24) {
+ tight_pack24(vs, vs->tight->tight.buffer, 1, &vs->tight->tight.offset);
bytes = 3;
} else {
bytes = vs->client_pf.bytes_per_pixel;
}
- vnc_write(vs, vs->tight.tight.buffer, bytes);
+ vnc_write(vs, vs->tight->tight.buffer, bytes);
return 1;
}
{
ssize_t bytes;
int stream = 1;
- int level = tight_conf[vs->tight.compression].mono_zlib_level;
+ int level = tight_conf[vs->tight->compression].mono_zlib_level;
#ifdef CONFIG_VNC_PNG
if (tight_can_send_png_rect(vs, w, h)) {
uint32_t buf[2] = {bg, fg};
size_t ret = sizeof (buf);
- if (vs->tight.pixel24) {
+ if (vs->tight->pixel24) {
tight_pack24(vs, (unsigned char*)buf, 2, &ret);
}
vnc_write(vs, buf, ret);
- tight_encode_mono_rect32(vs->tight.tight.buffer, w, h, bg, fg);
+ tight_encode_mono_rect32(vs->tight->tight.buffer, w, h, bg, fg);
break;
}
case 2:
vnc_write(vs, &bg, 2);
vnc_write(vs, &fg, 2);
- tight_encode_mono_rect16(vs->tight.tight.buffer, w, h, bg, fg);
+ tight_encode_mono_rect16(vs->tight->tight.buffer, w, h, bg, fg);
break;
default:
vnc_write_u8(vs, bg);
vnc_write_u8(vs, fg);
- tight_encode_mono_rect8(vs->tight.tight.buffer, w, h, bg, fg);
+ tight_encode_mono_rect8(vs->tight->tight.buffer, w, h, bg, fg);
break;
}
- vs->tight.tight.offset = bytes;
+ vs->tight->tight.offset = bytes;
bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
return (bytes >= 0);
static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
{
int stream = 3;
- int level = tight_conf[vs->tight.compression].gradient_zlib_level;
+ int level = tight_conf[vs->tight->compression].gradient_zlib_level;
ssize_t bytes;
if (vs->client_pf.bytes_per_pixel == 1) {
vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
- buffer_reserve(&vs->tight.gradient, w * 3 * sizeof (int));
+ buffer_reserve(&vs->tight->gradient, w * 3 * sizeof(int));
- if (vs->tight.pixel24) {
- tight_filter_gradient24(vs, vs->tight.tight.buffer, w, h);
+ if (vs->tight->pixel24) {
+ tight_filter_gradient24(vs, vs->tight->tight.buffer, w, h);
bytes = 3;
} else if (vs->client_pf.bytes_per_pixel == 4) {
- tight_filter_gradient32(vs, (uint32_t *)vs->tight.tight.buffer, w, h);
+ tight_filter_gradient32(vs, (uint32_t *)vs->tight->tight.buffer, w, h);
bytes = 4;
} else {
- tight_filter_gradient16(vs, (uint16_t *)vs->tight.tight.buffer, w, h);
+ tight_filter_gradient16(vs, (uint16_t *)vs->tight->tight.buffer, w, h);
bytes = 2;
}
- buffer_reset(&vs->tight.gradient);
+ buffer_reset(&vs->tight->gradient);
bytes = w * h * bytes;
- vs->tight.tight.offset = bytes;
+ vs->tight->tight.offset = bytes;
bytes = tight_compress_data(vs, stream, bytes,
level, Z_FILTERED);
int w, int h, VncPalette *palette)
{
int stream = 2;
- int level = tight_conf[vs->tight.compression].idx_zlib_level;
+ int level = tight_conf[vs->tight->compression].idx_zlib_level;
int colors;
ssize_t bytes;
palette_iter(palette, write_palette, &priv);
vnc_write(vs, header, sizeof(header));
- if (vs->tight.pixel24) {
+ if (vs->tight->pixel24) {
tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset);
vs->output.offset = old_offset + offset;
}
- tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
+ tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h, palette);
break;
}
case 2:
palette_iter(palette, write_palette, &priv);
vnc_write(vs, header, sizeof(header));
- tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
+ tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h, palette);
break;
}
default:
break;
}
bytes = w * h;
- vs->tight.tight.offset = bytes;
+ vs->tight->tight.offset = bytes;
bytes = tight_compress_data(vs, stream, bytes,
level, Z_DEFAULT_STRATEGY);
static void jpeg_init_destination(j_compress_ptr cinfo)
{
VncState *vs = cinfo->client_data;
- Buffer *buffer = &vs->tight.jpeg;
+ Buffer *buffer = &vs->tight->jpeg;
cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset;
cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset);
static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
{
VncState *vs = cinfo->client_data;
- Buffer *buffer = &vs->tight.jpeg;
+ Buffer *buffer = &vs->tight->jpeg;
buffer->offset = buffer->capacity;
buffer_reserve(buffer, 2048);
static void jpeg_term_destination(j_compress_ptr cinfo)
{
VncState *vs = cinfo->client_data;
- Buffer *buffer = &vs->tight.jpeg;
+ Buffer *buffer = &vs->tight->jpeg;
buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer;
}
return send_full_color_rect(vs, x, y, w, h);
}
- buffer_reserve(&vs->tight.jpeg, 2048);
+ buffer_reserve(&vs->tight->jpeg, 2048);
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
vnc_write_u8(vs, VNC_TIGHT_JPEG << 4);
- tight_send_compact_size(vs, vs->tight.jpeg.offset);
- vnc_write(vs, vs->tight.jpeg.buffer, vs->tight.jpeg.offset);
- buffer_reset(&vs->tight.jpeg);
+ tight_send_compact_size(vs, vs->tight->jpeg.offset);
+ vnc_write(vs, vs->tight->jpeg.buffer, vs->tight->jpeg.offset);
+ buffer_reset(&vs->tight->jpeg);
return 1;
}
VncState *vs = priv->vs;
png_colorp color = &priv->png_palette[idx];
- if (vs->tight.pixel24)
+ if (vs->tight->pixel24)
{
color->red = (pix >> vs->client_pf.rshift) & vs->client_pf.rmax;
color->green = (pix >> vs->client_pf.gshift) & vs->client_pf.gmax;
{
VncState *vs = png_get_io_ptr(png_ptr);
- buffer_reserve(&vs->tight.png, vs->tight.png.offset + length);
- memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length);
+ buffer_reserve(&vs->tight->png, vs->tight->png.offset + length);
+ memcpy(vs->tight->png.buffer + vs->tight->png.offset, data, length);
- vs->tight.png.offset += length;
+ vs->tight->png.offset += length;
}
static void png_flush_data(png_structp png_ptr)
png_infop info_ptr;
png_colorp png_palette = NULL;
pixman_image_t *linebuf;
- int level = tight_png_conf[vs->tight.compression].png_zlib_level;
- int filters = tight_png_conf[vs->tight.compression].png_filters;
+ int level = tight_png_conf[vs->tight->compression].png_zlib_level;
+ int filters = tight_png_conf[vs->tight->compression].png_filters;
uint8_t *buf;
int dy;
png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
if (vs->client_pf.bytes_per_pixel == 4) {
- tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
+ tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h,
+ palette);
} else {
- tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
+ tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h,
+ palette);
}
}
png_write_info(png_ptr, info_ptr);
- buffer_reserve(&vs->tight.png, 2048);
+ buffer_reserve(&vs->tight->png, 2048);
linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, w);
buf = (uint8_t *)pixman_image_get_data(linebuf);
for (dy = 0; dy < h; dy++)
{
if (color_type == PNG_COLOR_TYPE_PALETTE) {
- memcpy(buf, vs->tight.tight.buffer + (dy * w), w);
+ memcpy(buf, vs->tight->tight.buffer + (dy * w), w);
} else {
qemu_pixman_linebuf_fill(linebuf, vs->vd->server, w, x, y + dy);
}
vnc_write_u8(vs, VNC_TIGHT_PNG << 4);
- tight_send_compact_size(vs, vs->tight.png.offset);
- vnc_write(vs, vs->tight.png.buffer, vs->tight.png.offset);
- buffer_reset(&vs->tight.png);
+ tight_send_compact_size(vs, vs->tight->png.offset);
+ vnc_write(vs, vs->tight->png.buffer, vs->tight->png.offset);
+ buffer_reset(&vs->tight->png);
return 1;
}
#endif /* CONFIG_VNC_PNG */
static void vnc_tight_start(VncState *vs)
{
- buffer_reset(&vs->tight.tight);
+ buffer_reset(&vs->tight->tight);
// make the output buffer be the zlib buffer, so we can compress it later
- vs->tight.tmp = vs->output;
- vs->output = vs->tight.tight;
+ vs->tight->tmp = vs->output;
+ vs->output = vs->tight->tight;
}
static void vnc_tight_stop(VncState *vs)
{
// switch back to normal output/zlib buffers
- vs->tight.tight = vs->output;
- vs->output = vs->tight.tmp;
+ vs->tight->tight = vs->output;
+ vs->output = vs->tight->tmp;
}
static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h,
int ret;
if (colors == 0) {
- if (force || (tight_jpeg_conf[vs->tight.quality].jpeg_full &&
+ if (force || (tight_jpeg_conf[vs->tight->quality].jpeg_full &&
tight_detect_smooth_image(vs, w, h))) {
- int quality = tight_conf[vs->tight.quality].jpeg_quality;
+ int quality = tight_conf[vs->tight->quality].jpeg_quality;
ret = send_jpeg_rect(vs, x, y, w, h, quality);
} else {
ret = send_mono_rect(vs, x, y, w, h, bg, fg);
} else if (colors <= 256) {
if (force || (colors > 96 &&
- tight_jpeg_conf[vs->tight.quality].jpeg_idx &&
+ tight_jpeg_conf[vs->tight->quality].jpeg_idx &&
tight_detect_smooth_image(vs, w, h))) {
- int quality = tight_conf[vs->tight.quality].jpeg_quality;
+ int quality = tight_conf[vs->tight->quality].jpeg_quality;
ret = send_jpeg_rect(vs, x, y, w, h, quality);
} else {
qemu_thread_atexit_add(&vnc_tight_cleanup_notifier);
}
- vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
+ vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type);
vnc_tight_start(vs);
vnc_raw_send_framebuffer_update(vs, x, y, w, h);
vnc_tight_stop(vs);
#ifdef CONFIG_VNC_JPEG
- if (!vs->vd->non_adaptive && vs->tight.quality != (uint8_t)-1) {
+ if (!vs->vd->non_adaptive && vs->tight->quality != (uint8_t)-1) {
double freq = vnc_update_freq(vs, x, y, w, h);
- if (freq < tight_jpeg_conf[vs->tight.quality].jpeg_freq_min) {
+ if (freq < tight_jpeg_conf[vs->tight->quality].jpeg_freq_min) {
allow_jpeg = false;
}
- if (freq >= tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
+ if (freq >= tight_jpeg_conf[vs->tight->quality].jpeg_freq_threshold) {
force_jpeg = true;
vnc_sent_lossy_rect(vs, x, y, w, h);
}
colors = tight_fill_palette(vs, x, y, w * h, &bg, &fg, color_count_palette);
#ifdef CONFIG_VNC_JPEG
- if (allow_jpeg && vs->tight.quality != (uint8_t)-1) {
+ if (allow_jpeg && vs->tight->quality != (uint8_t)-1) {
ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors,
color_count_palette, force_jpeg);
} else {
static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
{
- vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
+ vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type);
vnc_tight_start(vs);
vnc_raw_send_framebuffer_update(vs, x, y, w, h);
int rw, rh;
int n = 0;
- max_size = tight_conf[vs->tight.compression].max_rect_size;
- max_width = tight_conf[vs->tight.compression].max_rect_width;
+ max_size = tight_conf[vs->tight->compression].max_rect_size;
+ max_width = tight_conf[vs->tight->compression].max_rect_width;
if (split && (w > max_width || w * h > max_size)) {
max_sub_width = (w > max_width) ? max_width : w;
if (vs->client_pf.bytes_per_pixel == 4 && vs->client_pf.rmax == 0xFF &&
vs->client_pf.bmax == 0xFF && vs->client_pf.gmax == 0xFF) {
- vs->tight.pixel24 = true;
+ vs->tight->pixel24 = true;
} else {
- vs->tight.pixel24 = false;
+ vs->tight->pixel24 = false;
}
#ifdef CONFIG_VNC_JPEG
- if (vs->tight.quality != (uint8_t)-1) {
+ if (vs->tight->quality != (uint8_t)-1) {
double freq = vnc_update_freq(vs, x, y, w, h);
- if (freq > tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
+ if (freq > tight_jpeg_conf[vs->tight->quality].jpeg_freq_threshold) {
return send_rect_simple(vs, x, y, w, h, false);
}
}
/* Calculate maximum number of rows in one non-solid rectangle. */
- max_rows = tight_conf[vs->tight.compression].max_rect_size;
- max_rows /= MIN(tight_conf[vs->tight.compression].max_rect_width, w);
+ max_rows = tight_conf[vs->tight->compression].max_rect_size;
+ max_rows /= MIN(tight_conf[vs->tight->compression].max_rect_width, w);
return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
}
int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
int w, int h)
{
- vs->tight.type = VNC_ENCODING_TIGHT;
+ vs->tight->type = VNC_ENCODING_TIGHT;
return tight_send_framebuffer_update(vs, x, y, w, h);
}
int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
int w, int h)
{
- vs->tight.type = VNC_ENCODING_TIGHT_PNG;
+ vs->tight->type = VNC_ENCODING_TIGHT_PNG;
return tight_send_framebuffer_update(vs, x, y, w, h);
}
void vnc_tight_clear(VncState *vs)
{
int i;
- for (i=0; i<ARRAY_SIZE(vs->tight.stream); i++) {
- if (vs->tight.stream[i].opaque) {
- deflateEnd(&vs->tight.stream[i]);
+ for (i = 0; i < ARRAY_SIZE(vs->tight->stream); i++) {
+ if (vs->tight->stream[i].opaque) {
+ deflateEnd(&vs->tight->stream[i]);
}
}
- buffer_free(&vs->tight.tight);
- buffer_free(&vs->tight.zlib);
- buffer_free(&vs->tight.gradient);
+ buffer_free(&vs->tight->tight);
+ buffer_free(&vs->tight->zlib);
+ buffer_free(&vs->tight->gradient);
#ifdef CONFIG_VNC_JPEG
- buffer_free(&vs->tight.jpeg);
+ buffer_free(&vs->tight->jpeg);
#endif
#ifdef CONFIG_VNC_PNG
- buffer_free(&vs->tight.png);
+ buffer_free(&vs->tight->png);
#endif
}
zstream->zalloc = vnc_zlib_zalloc;
zstream->zfree = vnc_zlib_zfree;
- err = deflateInit2(zstream, vs->tight.compression, Z_DEFLATED, MAX_WBITS,
+ err = deflateInit2(zstream, vs->tight->compression, Z_DEFLATED,
+ MAX_WBITS,
MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
if (err != Z_OK) {
return -1;
}
- vs->zlib.level = vs->tight.compression;
+ vs->zlib.level = vs->tight->compression;
zstream->opaque = vs;
}
- if (vs->tight.compression != vs->zlib.level) {
- if (deflateParams(zstream, vs->tight.compression,
+ if (vs->tight->compression != vs->zlib.level) {
+ if (deflateParams(zstream, vs->tight->compression,
Z_DEFAULT_STRATEGY) != Z_OK) {
return -1;
}
- vs->zlib.level = vs->tight.compression;
+ vs->zlib.level = vs->tight->compression;
}
// reserve memory in output buffer
static void vnc_zrle_start(VncState *vs)
{
- buffer_reset(&vs->zrle.zrle);
+ buffer_reset(&vs->zrle->zrle);
/* make the output buffer be the zlib buffer, so we can compress it later */
- vs->zrle.tmp = vs->output;
- vs->output = vs->zrle.zrle;
+ vs->zrle->tmp = vs->output;
+ vs->output = vs->zrle->zrle;
}
static void vnc_zrle_stop(VncState *vs)
{
/* switch back to normal output/zlib buffers */
- vs->zrle.zrle = vs->output;
- vs->output = vs->zrle.tmp;
+ vs->zrle->zrle = vs->output;
+ vs->output = vs->zrle->tmp;
}
static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h,
{
Buffer tmp;
- buffer_reset(&vs->zrle.fb);
- buffer_reserve(&vs->zrle.fb, w * h * bpp + bpp);
+ buffer_reset(&vs->zrle->fb);
+ buffer_reserve(&vs->zrle->fb, w * h * bpp + bpp);
tmp = vs->output;
- vs->output = vs->zrle.fb;
+ vs->output = vs->zrle->fb;
vnc_raw_send_framebuffer_update(vs, x, y, w, h);
- vs->zrle.fb = vs->output;
+ vs->zrle->fb = vs->output;
vs->output = tmp;
- return vs->zrle.fb.buffer;
+ return vs->zrle->fb.buffer;
}
static int zrle_compress_data(VncState *vs, int level)
{
- z_streamp zstream = &vs->zrle.stream;
+ z_streamp zstream = &vs->zrle->stream;
- buffer_reset(&vs->zrle.zlib);
+ buffer_reset(&vs->zrle->zlib);
if (zstream->opaque != vs) {
int err;
}
/* reserve memory in output buffer */
- buffer_reserve(&vs->zrle.zlib, vs->zrle.zrle.offset + 64);
+ buffer_reserve(&vs->zrle->zlib, vs->zrle->zrle.offset + 64);
/* set pointers */
- zstream->next_in = vs->zrle.zrle.buffer;
- zstream->avail_in = vs->zrle.zrle.offset;
- zstream->next_out = vs->zrle.zlib.buffer + vs->zrle.zlib.offset;
- zstream->avail_out = vs->zrle.zlib.capacity - vs->zrle.zlib.offset;
+ zstream->next_in = vs->zrle->zrle.buffer;
+ zstream->avail_in = vs->zrle->zrle.offset;
+ zstream->next_out = vs->zrle->zlib.buffer + vs->zrle->zlib.offset;
+ zstream->avail_out = vs->zrle->zlib.capacity - vs->zrle->zlib.offset;
zstream->data_type = Z_BINARY;
/* start encoding */
return -1;
}
- vs->zrle.zlib.offset = vs->zrle.zlib.capacity - zstream->avail_out;
- return vs->zrle.zlib.offset;
+ vs->zrle->zlib.offset = vs->zrle->zlib.capacity - zstream->avail_out;
+ return vs->zrle->zlib.offset;
}
/* Try to work out whether to use RLE and/or a palette. We do this by
size_t bytes;
int zywrle_level;
- if (vs->zrle.type == VNC_ENCODING_ZYWRLE) {
- if (!vs->vd->lossy || vs->tight.quality == (uint8_t)-1
- || vs->tight.quality == 9) {
+ if (vs->zrle->type == VNC_ENCODING_ZYWRLE) {
+ if (!vs->vd->lossy || vs->tight->quality == (uint8_t)-1
+ || vs->tight->quality == 9) {
zywrle_level = 0;
- vs->zrle.type = VNC_ENCODING_ZRLE;
- } else if (vs->tight.quality < 3) {
+ vs->zrle->type = VNC_ENCODING_ZRLE;
+ } else if (vs->tight->quality < 3) {
zywrle_level = 3;
- } else if (vs->tight.quality < 6) {
+ } else if (vs->tight->quality < 6) {
zywrle_level = 2;
} else {
zywrle_level = 1;
vnc_zrle_stop(vs);
bytes = zrle_compress_data(vs, Z_DEFAULT_COMPRESSION);
- vnc_framebuffer_update(vs, x, y, w, h, vs->zrle.type);
+ vnc_framebuffer_update(vs, x, y, w, h, vs->zrle->type);
vnc_write_u32(vs, bytes);
- vnc_write(vs, vs->zrle.zlib.buffer, vs->zrle.zlib.offset);
+ vnc_write(vs, vs->zrle->zlib.buffer, vs->zrle->zlib.offset);
return 1;
}
int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
{
- vs->zrle.type = VNC_ENCODING_ZRLE;
+ vs->zrle->type = VNC_ENCODING_ZRLE;
return zrle_send_framebuffer_update(vs, x, y, w, h);
}
int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
{
- vs->zrle.type = VNC_ENCODING_ZYWRLE;
+ vs->zrle->type = VNC_ENCODING_ZYWRLE;
return zrle_send_framebuffer_update(vs, x, y, w, h);
}
void vnc_zrle_clear(VncState *vs)
{
- if (vs->zrle.stream.opaque) {
- deflateEnd(&vs->zrle.stream);
+ if (vs->zrle->stream.opaque) {
+ deflateEnd(&vs->zrle->stream);
}
- buffer_free(&vs->zrle.zrle);
- buffer_free(&vs->zrle.fb);
- buffer_free(&vs->zrle.zlib);
+ buffer_free(&vs->zrle->zrle);
+ buffer_free(&vs->zrle->fb);
+ buffer_free(&vs->zrle->zlib);
}
static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
int zywrle_level)
{
- VncPalette *palette = &vs->zrle.palette;
+ VncPalette *palette = &vs->zrle->palette;
int runs = 0;
int single_pixels = 0;
vnc_init_basic_info_from_remote_addr(client->sioc,
qapi_VncClientInfo_base(client->info),
&err);
+ client->info->websocket = client->websocket;
if (err) {
qapi_free_VncClientInfo(client->info);
client->info = NULL;
object_unref(OBJECT(vs->sioc));
vs->sioc = NULL;
vs->magic = 0;
+ g_free(vs->zrle);
+ g_free(vs->tight);
g_free(vs);
}
vs->features = 0;
vs->vnc_encoding = 0;
- vs->tight.compression = 9;
- vs->tight.quality = -1; /* Lossless by default */
+ vs->tight->compression = 9;
+ vs->tight->quality = -1; /* Lossless by default */
vs->absolute = -1;
/*
vs->features |= VNC_FEATURE_LED_STATE_MASK;
break;
case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
- vs->tight.compression = (enc & 0x0F);
+ vs->tight->compression = (enc & 0x0F);
break;
case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
if (vs->vd->lossy) {
- vs->tight.quality = (enc & 0x0F);
+ vs->tight->quality = (enc & 0x0F);
}
break;
default:
int i;
trace_vnc_client_connect(vs, sioc);
+ vs->zrle = g_new0(VncZrle, 1);
+ vs->tight = g_new0(VncTight, 1);
vs->magic = VNC_MAGIC;
vs->sioc = sioc;
object_ref(OBJECT(vs->sioc));
buffer_init(&vs->output, "vnc-output/%p", sioc);
buffer_init(&vs->jobs_buffer, "vnc-jobs_buffer/%p", sioc);
- buffer_init(&vs->tight.tight, "vnc-tight/%p", sioc);
- buffer_init(&vs->tight.zlib, "vnc-tight-zlib/%p", sioc);
- buffer_init(&vs->tight.gradient, "vnc-tight-gradient/%p", sioc);
+ buffer_init(&vs->tight->tight, "vnc-tight/%p", sioc);
+ buffer_init(&vs->tight->zlib, "vnc-tight-zlib/%p", sioc);
+ buffer_init(&vs->tight->gradient, "vnc-tight-gradient/%p", sioc);
#ifdef CONFIG_VNC_JPEG
- buffer_init(&vs->tight.jpeg, "vnc-tight-jpeg/%p", sioc);
+ buffer_init(&vs->tight->jpeg, "vnc-tight-jpeg/%p", sioc);
#endif
#ifdef CONFIG_VNC_PNG
- buffer_init(&vs->tight.png, "vnc-tight-png/%p", sioc);
+ buffer_init(&vs->tight->png, "vnc-tight-png/%p", sioc);
#endif
buffer_init(&vs->zlib.zlib, "vnc-zlib/%p", sioc);
- buffer_init(&vs->zrle.zrle, "vnc-zrle/%p", sioc);
- buffer_init(&vs->zrle.fb, "vnc-zrle-fb/%p", sioc);
- buffer_init(&vs->zrle.zlib, "vnc-zrle-zlib/%p", sioc);
+ buffer_init(&vs->zrle->zrle, "vnc-zrle/%p", sioc);
+ buffer_init(&vs->zrle->fb, "vnc-zrle-fb/%p", sioc);
+ buffer_init(&vs->zrle->zlib, "vnc-zrle-zlib/%p", sioc);
if (skipauth) {
vs->auth = VNC_AUTH_NONE;
/* Encoding specific, if you add something here, don't forget to
* update vnc_async_encoding_start()
*/
- VncTight tight;
+ VncTight *tight;
VncZlib zlib;
VncHextile hextile;
- VncZrle zrle;
+ VncZrle *zrle;
VncZywrle zywrle;
Notifier mouse_mode_notifier;
g_free(buf);
}
-#elif defined(__APPLE__) \
- || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#elif defined(__APPLE__)
# include <sys/sysctl.h>
-# if defined(__APPLE__)
-# define SYSCTL_CACHELINE_NAME "hw.cachelinesize"
-# else
-# define SYSCTL_CACHELINE_NAME "machdep.cacheline_size"
-# endif
-
static void sys_cache_info(int *isize, int *dsize)
{
/* There's only a single sysctl for both I/D cache line sizes. */
long size;
size_t len = sizeof(size);
- if (!sysctlbyname(SYSCTL_CACHELINE_NAME, &size, &len, NULL, 0)) {
+ if (!sysctlbyname("hw.cachelinesize", &size, &len, NULL, 0)) {
+ *isize = *dsize = size;
+ }
+}
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+# include <sys/sysctl.h>
+static void sys_cache_info(int *isize, int *dsize)
+{
+ /* There's only a single sysctl for both I/D cache line sizes. */
+ int size;
+ size_t len = sizeof(size);
+ if (!sysctlbyname("machdep.cacheline_size", &size, &len, NULL, 0)) {
*isize = *dsize = size;
}
}
-
#else
/* POSIX */