mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* core support for MemoryRegionCache from myself * rules.mak speedup and cleanups from myself and Marc-Adnré * multiboot command line fix from Vlad * SCSI fixes from myself * small qemu-timer speedup from myself * x86 debugging improvements from Doug * configurable Q35 devices from Chao * x86 5-level paging support from Kirill * x86 SHA_NI support for KVM from Yi Sun * improved kvmclock migration logic from Marcelo * bugfixes and doc fixes from others # gpg: Signature made Thu 22 Dec 2016 15:01:13 GMT # gpg: using RSA key 0xBFFBD25F78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini/tags/for-upstream: (25 commits) x86: implement la57 paging mode target-i386: Fix eflags.TF/#DB handling of syscall/sysret insns kvmclock: reduce kvmclock difference on migration kvm: sync linux headers scsi-disk: fix VERIFY for scsi-block hw/block/pflash_cfi*.c: fix confusing assert fail message multiboot: copy the cmdline verbatim, unescape module strings x86: Fix x86_64 'g' packet response to gdb from 32-bit mode. pc: make pit configurable pc: make sata configurable pc: make smbus configurable target-i386: Add Intel SHA_NI instruction support. block: drop remaining legacy aio functions in comment main-loop: update comment for qemu_mutex_lock/unlock_iothread timer: fix misleading comment in timer.h qemu-timer: check active_timers outside lock/event virtio-scsi: introduce virtio_scsi_acquire/release build-sys: remove libtool left-over rules.mak: add more rules to avoid chaining rules.mak: speedup save-vars load-vars ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -82,10 +82,6 @@
|
||||
*.d
|
||||
!/scripts/qemu-guest-agent/fsfreeze-hook.d
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
*.pc
|
||||
.libs
|
||||
.sdk
|
||||
*.gcda
|
||||
*.gcno
|
||||
|
||||
@@ -231,12 +231,10 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
|
||||
|
||||
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
|
||||
|
||||
$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h | $(BUILD_DIR)/version.lo
|
||||
$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h
|
||||
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.o")
|
||||
$(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc config-host.h
|
||||
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.lo")
|
||||
|
||||
Makefile: $(version-obj-y) $(version-lobj-y)
|
||||
Makefile: $(version-obj-y)
|
||||
|
||||
######################################################################
|
||||
# Build libraries
|
||||
@@ -358,10 +356,9 @@ clean:
|
||||
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||
rm -f qemu-options.def
|
||||
rm -f *.msi
|
||||
find . \( -name '*.l[oa]' -o -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
|
||||
find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
|
||||
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
|
||||
rm -f fsdev/*.pod
|
||||
rm -rf .libs */.libs
|
||||
rm -f qemu-img-cmds.h
|
||||
rm -f ui/shader/*-vert.h ui/shader/*-frag.h
|
||||
@# May not be present in GENERATED_HEADERS
|
||||
|
||||
@@ -97,7 +97,6 @@ common-obj-y += disas/
|
||||
######################################################################
|
||||
# Resource file for Windows executables
|
||||
version-obj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.o
|
||||
version-lobj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.lo
|
||||
|
||||
######################################################################
|
||||
# tracing
|
||||
|
||||
@@ -76,6 +76,7 @@ $(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all
|
||||
else
|
||||
stap:
|
||||
endif
|
||||
.PHONY: stap
|
||||
|
||||
all: $(PROGS) stap
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ TMPB="qemu-conf"
|
||||
TMPC="${TMPDIR1}/${TMPB}.c"
|
||||
TMPO="${TMPDIR1}/${TMPB}.o"
|
||||
TMPCXX="${TMPDIR1}/${TMPB}.cxx"
|
||||
TMPL="${TMPDIR1}/${TMPB}.lo"
|
||||
TMPA="${TMPDIR1}/lib${TMPB}.la"
|
||||
TMPE="${TMPDIR1}/${TMPB}.exe"
|
||||
TMPMO="${TMPDIR1}/${TMPB}.mo"
|
||||
|
||||
|
||||
@@ -707,6 +707,19 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
|
||||
int num_devices;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (pfl->sector_len == 0) {
|
||||
error_setg(errp, "attribute \"sector-length\" not specified or zero.");
|
||||
return;
|
||||
}
|
||||
if (pfl->nb_blocs == 0) {
|
||||
error_setg(errp, "attribute \"num-blocks\" not specified or zero.");
|
||||
return;
|
||||
}
|
||||
if (pfl->name == NULL) {
|
||||
error_setg(errp, "attribute \"name\" not specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
total_len = pfl->sector_len * pfl->nb_blocs;
|
||||
|
||||
/* These are only used to expose the parameters of each device
|
||||
|
||||
@@ -600,6 +600,19 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (pfl->sector_len == 0) {
|
||||
error_setg(errp, "attribute \"sector-length\" not specified or zero.");
|
||||
return;
|
||||
}
|
||||
if (pfl->nb_blocs == 0) {
|
||||
error_setg(errp, "attribute \"num-blocks\" not specified or zero.");
|
||||
return;
|
||||
}
|
||||
if (pfl->name == NULL) {
|
||||
error_setg(errp, "attribute \"name\" not specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
chip_len = pfl->sector_len * pfl->nb_blocs;
|
||||
/* XXX: to be fixed */
|
||||
#if 0
|
||||
|
||||
+127
-15
@@ -36,6 +36,13 @@ typedef struct KVMClockState {
|
||||
|
||||
uint64_t clock;
|
||||
bool clock_valid;
|
||||
|
||||
/* whether machine type supports reliable KVM_GET_CLOCK */
|
||||
bool mach_use_reliable_get_clock;
|
||||
|
||||
/* whether the 'clock' value was obtained in a host with
|
||||
* reliable KVM_GET_CLOCK */
|
||||
bool clock_is_reliable;
|
||||
} KVMClockState;
|
||||
|
||||
struct pvclock_vcpu_time_info {
|
||||
@@ -81,6 +88,60 @@ static uint64_t kvmclock_current_nsec(KVMClockState *s)
|
||||
return nsec + time.system_time;
|
||||
}
|
||||
|
||||
static void kvm_update_clock(KVMClockState *s)
|
||||
{
|
||||
struct kvm_clock_data data;
|
||||
int ret;
|
||||
|
||||
ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
|
||||
abort();
|
||||
}
|
||||
s->clock = data.clock;
|
||||
|
||||
/* If kvm_has_adjust_clock_stable() is false, KVM_GET_CLOCK returns
|
||||
* essentially CLOCK_MONOTONIC plus a guest-specific adjustment. This
|
||||
* can drift from the TSC-based value that is computed by the guest,
|
||||
* so we need to go through kvmclock_current_nsec(). If
|
||||
* kvm_has_adjust_clock_stable() is true, and the flags contain
|
||||
* KVM_CLOCK_TSC_STABLE, then KVM_GET_CLOCK returns a TSC-based value
|
||||
* and kvmclock_current_nsec() is not necessary.
|
||||
*
|
||||
* Here, however, we need not check KVM_CLOCK_TSC_STABLE. This is because:
|
||||
*
|
||||
* - if the host has disabled the kvmclock master clock, the guest already
|
||||
* has protection against time going backwards. This "safety net" is only
|
||||
* absent when kvmclock is stable;
|
||||
*
|
||||
* - therefore, we can replace a check like
|
||||
*
|
||||
* if last KVM_GET_CLOCK was not reliable then
|
||||
* read from memory
|
||||
*
|
||||
* with
|
||||
*
|
||||
* if last KVM_GET_CLOCK was not reliable && masterclock is enabled
|
||||
* read from memory
|
||||
*
|
||||
* However:
|
||||
*
|
||||
* - if kvm_has_adjust_clock_stable() returns false, the left side is
|
||||
* always true (KVM_GET_CLOCK is never reliable), and the right side is
|
||||
* unknown (because we don't have data.flags). We must assume it's true
|
||||
* and read from memory.
|
||||
*
|
||||
* - if kvm_has_adjust_clock_stable() returns true, the result of the &&
|
||||
* is always false (masterclock is enabled iff KVM_GET_CLOCK is reliable)
|
||||
*
|
||||
* So we can just use this instead:
|
||||
*
|
||||
* if !kvm_has_adjust_clock_stable() then
|
||||
* read from memory
|
||||
*/
|
||||
s->clock_is_reliable = kvm_has_adjust_clock_stable();
|
||||
}
|
||||
|
||||
static void kvmclock_vm_state_change(void *opaque, int running,
|
||||
RunState state)
|
||||
{
|
||||
@@ -91,15 +152,21 @@ static void kvmclock_vm_state_change(void *opaque, int running,
|
||||
|
||||
if (running) {
|
||||
struct kvm_clock_data data = {};
|
||||
uint64_t time_at_migration = kvmclock_current_nsec(s);
|
||||
|
||||
/*
|
||||
* If the host where s->clock was read did not support reliable
|
||||
* KVM_GET_CLOCK, read kvmclock value from memory.
|
||||
*/
|
||||
if (!s->clock_is_reliable) {
|
||||
uint64_t pvclock_via_mem = kvmclock_current_nsec(s);
|
||||
/* We can't rely on the saved clock value, just discard it */
|
||||
if (pvclock_via_mem) {
|
||||
s->clock = pvclock_via_mem;
|
||||
}
|
||||
}
|
||||
|
||||
s->clock_valid = false;
|
||||
|
||||
/* We can't rely on the migrated clock value, just discard it */
|
||||
if (time_at_migration) {
|
||||
s->clock = time_at_migration;
|
||||
}
|
||||
|
||||
data.clock = s->clock;
|
||||
ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
|
||||
if (ret < 0) {
|
||||
@@ -120,8 +187,6 @@ static void kvmclock_vm_state_change(void *opaque, int running,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
struct kvm_clock_data data;
|
||||
int ret;
|
||||
|
||||
if (s->clock_valid) {
|
||||
return;
|
||||
@@ -129,13 +194,7 @@ static void kvmclock_vm_state_change(void *opaque, int running,
|
||||
|
||||
kvm_synchronize_all_tsc();
|
||||
|
||||
ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
|
||||
abort();
|
||||
}
|
||||
s->clock = data.clock;
|
||||
|
||||
kvm_update_clock(s);
|
||||
/*
|
||||
* If the VM is stopped, declare the clock state valid to
|
||||
* avoid re-reading it on next vmsave (which would return
|
||||
@@ -149,25 +208,78 @@ static void kvmclock_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
KVMClockState *s = KVM_CLOCK(dev);
|
||||
|
||||
kvm_update_clock(s);
|
||||
|
||||
qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
|
||||
}
|
||||
|
||||
static bool kvmclock_clock_is_reliable_needed(void *opaque)
|
||||
{
|
||||
KVMClockState *s = opaque;
|
||||
|
||||
return s->mach_use_reliable_get_clock;
|
||||
}
|
||||
|
||||
static const VMStateDescription kvmclock_reliable_get_clock = {
|
||||
.name = "kvmclock/clock_is_reliable",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = kvmclock_clock_is_reliable_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(clock_is_reliable, KVMClockState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* When migrating, read the clock just before migration,
|
||||
* so that the guest clock counts during the events
|
||||
* between:
|
||||
*
|
||||
* * vm_stop()
|
||||
* *
|
||||
* * pre_save()
|
||||
*
|
||||
* This reduces kvmclock difference on migration from 5s
|
||||
* to 0.1s (when max_downtime == 5s), because sending the
|
||||
* final pages of memory (which happens between vm_stop()
|
||||
* and pre_save()) takes max_downtime.
|
||||
*/
|
||||
static void kvmclock_pre_save(void *opaque)
|
||||
{
|
||||
KVMClockState *s = opaque;
|
||||
|
||||
kvm_update_clock(s);
|
||||
}
|
||||
|
||||
static const VMStateDescription kvmclock_vmsd = {
|
||||
.name = "kvmclock",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.pre_save = kvmclock_pre_save,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(clock, KVMClockState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
.subsections = (const VMStateDescription * []) {
|
||||
&kvmclock_reliable_get_clock,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static Property kvmclock_properties[] = {
|
||||
DEFINE_PROP_BOOL("x-mach-use-reliable-get-clock", KVMClockState,
|
||||
mach_use_reliable_get_clock, true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void kvmclock_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = kvmclock_realize;
|
||||
dc->vmsd = &kvmclock_vmsd;
|
||||
dc->props = kvmclock_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo kvmclock_info = {
|
||||
|
||||
+10
-10
@@ -109,7 +109,7 @@ static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
|
||||
hwaddr p = s->offset_cmdlines;
|
||||
char *b = (char *)s->mb_buf + p;
|
||||
|
||||
get_opt_value(b, strlen(cmdline) + 1, cmdline);
|
||||
memcpy(b, cmdline, strlen(cmdline) + 1);
|
||||
s->offset_cmdlines += strlen(b) + 1;
|
||||
return s->mb_buf_phys + p;
|
||||
}
|
||||
@@ -287,7 +287,8 @@ int load_multiboot(FWCfgState *fw_cfg,
|
||||
mbs.offset_bootloader = mbs.offset_cmdlines + cmdline_len;
|
||||
|
||||
if (initrd_filename) {
|
||||
char *next_initrd, not_last;
|
||||
const char *next_initrd;
|
||||
char not_last, tmpbuf[strlen(initrd_filename) + 1];
|
||||
|
||||
mbs.offset_mods = mbs.mb_buf_size;
|
||||
|
||||
@@ -296,25 +297,24 @@ int load_multiboot(FWCfgState *fw_cfg,
|
||||
int mb_mod_length;
|
||||
uint32_t offs = mbs.mb_buf_size;
|
||||
|
||||
next_initrd = (char *)get_opt_value(NULL, 0, initrd_filename);
|
||||
next_initrd = get_opt_value(tmpbuf, sizeof(tmpbuf), initrd_filename);
|
||||
not_last = *next_initrd;
|
||||
*next_initrd = '\0';
|
||||
/* if a space comes after the module filename, treat everything
|
||||
after that as parameters */
|
||||
hwaddr c = mb_add_cmdline(&mbs, initrd_filename);
|
||||
if ((next_space = strchr(initrd_filename, ' ')))
|
||||
hwaddr c = mb_add_cmdline(&mbs, tmpbuf);
|
||||
if ((next_space = strchr(tmpbuf, ' ')))
|
||||
*next_space = '\0';
|
||||
mb_debug("multiboot loading module: %s\n", initrd_filename);
|
||||
mb_mod_length = get_image_size(initrd_filename);
|
||||
mb_debug("multiboot loading module: %s\n", tmpbuf);
|
||||
mb_mod_length = get_image_size(tmpbuf);
|
||||
if (mb_mod_length < 0) {
|
||||
fprintf(stderr, "Failed to open file '%s'\n", initrd_filename);
|
||||
fprintf(stderr, "Failed to open file '%s'\n", tmpbuf);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
|
||||
mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
|
||||
|
||||
load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
|
||||
load_image(tmpbuf, (unsigned char *)mbs.mb_buf + offs);
|
||||
mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
|
||||
mbs.mb_buf_phys + offs + mb_mod_length, c);
|
||||
|
||||
|
||||
+62
-6
@@ -400,13 +400,13 @@ static void pc_cmos_init_late(void *opaque)
|
||||
int i, trans;
|
||||
|
||||
val = 0;
|
||||
if (ide_get_geometry(arg->idebus[0], 0,
|
||||
&cylinders, &heads, §ors) >= 0) {
|
||||
if (arg->idebus[0] && ide_get_geometry(arg->idebus[0], 0,
|
||||
&cylinders, &heads, §ors) >= 0) {
|
||||
cmos_init_hd(s, 0x19, 0x1b, cylinders, heads, sectors);
|
||||
val |= 0xf0;
|
||||
}
|
||||
if (ide_get_geometry(arg->idebus[0], 1,
|
||||
&cylinders, &heads, §ors) >= 0) {
|
||||
if (arg->idebus[0] && ide_get_geometry(arg->idebus[0], 1,
|
||||
&cylinders, &heads, §ors) >= 0) {
|
||||
cmos_init_hd(s, 0x1a, 0x24, cylinders, heads, sectors);
|
||||
val |= 0x0f;
|
||||
}
|
||||
@@ -418,7 +418,8 @@ static void pc_cmos_init_late(void *opaque)
|
||||
geometry. It is always such that: 1 <= sects <= 63, 1
|
||||
<= heads <= 16, 1 <= cylinders <= 16383. The BIOS
|
||||
geometry can be different if a translation is done. */
|
||||
if (ide_get_geometry(arg->idebus[i / 2], i % 2,
|
||||
if (arg->idebus[i / 2] &&
|
||||
ide_get_geometry(arg->idebus[i / 2], i % 2,
|
||||
&cylinders, &heads, §ors) >= 0) {
|
||||
trans = ide_get_bios_chs_trans(arg->idebus[i / 2], i % 2) - 1;
|
||||
assert((trans & ~3) == 0);
|
||||
@@ -1535,6 +1536,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
ISADevice **rtc_state,
|
||||
bool create_fdctrl,
|
||||
bool no_vmport,
|
||||
bool has_pit,
|
||||
uint32_t hpet_irqs)
|
||||
{
|
||||
int i;
|
||||
@@ -1588,7 +1590,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
|
||||
qemu_register_boot_set(pc_boot_set, *rtc_state);
|
||||
|
||||
if (!xen_enabled()) {
|
||||
if (!xen_enabled() && has_pit) {
|
||||
if (kvm_pit_in_kernel()) {
|
||||
pit = kvm_pit_init(isa_bus, 0x40);
|
||||
} else {
|
||||
@@ -2158,6 +2160,48 @@ static void pc_machine_set_nvdimm(Object *obj, bool value, Error **errp)
|
||||
pcms->acpi_nvdimm_state.is_enabled = value;
|
||||
}
|
||||
|
||||
static bool pc_machine_get_smbus(Object *obj, Error **errp)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(obj);
|
||||
|
||||
return pcms->smbus;
|
||||
}
|
||||
|
||||
static void pc_machine_set_smbus(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(obj);
|
||||
|
||||
pcms->smbus = value;
|
||||
}
|
||||
|
||||
static bool pc_machine_get_sata(Object *obj, Error **errp)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(obj);
|
||||
|
||||
return pcms->sata;
|
||||
}
|
||||
|
||||
static void pc_machine_set_sata(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(obj);
|
||||
|
||||
pcms->sata = value;
|
||||
}
|
||||
|
||||
static bool pc_machine_get_pit(Object *obj, Error **errp)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(obj);
|
||||
|
||||
return pcms->pit;
|
||||
}
|
||||
|
||||
static void pc_machine_set_pit(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(obj);
|
||||
|
||||
pcms->pit = value;
|
||||
}
|
||||
|
||||
static void pc_machine_initfn(Object *obj)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(obj);
|
||||
@@ -2169,6 +2213,9 @@ static void pc_machine_initfn(Object *obj)
|
||||
pcms->acpi_nvdimm_state.is_enabled = false;
|
||||
/* acpi build is enabled by default if machine supports it */
|
||||
pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build;
|
||||
pcms->smbus = true;
|
||||
pcms->sata = true;
|
||||
pcms->pit = true;
|
||||
}
|
||||
|
||||
static void pc_machine_reset(void)
|
||||
@@ -2329,6 +2376,15 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
object_class_property_add_bool(oc, PC_MACHINE_NVDIMM,
|
||||
pc_machine_get_nvdimm, pc_machine_set_nvdimm, &error_abort);
|
||||
|
||||
object_class_property_add_bool(oc, PC_MACHINE_SMBUS,
|
||||
pc_machine_get_smbus, pc_machine_set_smbus, &error_abort);
|
||||
|
||||
object_class_property_add_bool(oc, PC_MACHINE_SATA,
|
||||
pc_machine_get_sata, pc_machine_set_sata, &error_abort);
|
||||
|
||||
object_class_property_add_bool(oc, PC_MACHINE_PIT,
|
||||
pc_machine_get_pit, pc_machine_set_pit, &error_abort);
|
||||
}
|
||||
|
||||
static const TypeInfo pc_machine_info = {
|
||||
|
||||
+1
-1
@@ -235,7 +235,7 @@ static void pc_init1(MachineState *machine,
|
||||
|
||||
/* init basic PC hardware */
|
||||
pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, true,
|
||||
(pcms->vmport != ON_OFF_AUTO_ON), 0x4);
|
||||
(pcms->vmport != ON_OFF_AUTO_ON), pcms->pit, 0x4);
|
||||
|
||||
pc_nic_init(isa_bus, pci_bus);
|
||||
|
||||
|
||||
+23
-16
@@ -227,32 +227,39 @@ static void pc_q35_init(MachineState *machine)
|
||||
|
||||
/* init basic PC hardware */
|
||||
pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, !mc->no_floppy,
|
||||
(pcms->vmport != ON_OFF_AUTO_ON), 0xff0104);
|
||||
(pcms->vmport != ON_OFF_AUTO_ON), pcms->pit,
|
||||
0xff0104);
|
||||
|
||||
/* connect pm stuff to lpc */
|
||||
ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms));
|
||||
|
||||
/* ahci and SATA device, for q35 1 ahci controller is built-in */
|
||||
ahci = pci_create_simple_multifunction(host_bus,
|
||||
PCI_DEVFN(ICH9_SATA1_DEV,
|
||||
ICH9_SATA1_FUNC),
|
||||
true, "ich9-ahci");
|
||||
idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0");
|
||||
idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1");
|
||||
g_assert(MAX_SATA_PORTS == ICH_AHCI(ahci)->ahci.ports);
|
||||
ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports);
|
||||
ahci_ide_create_devs(ahci, hd);
|
||||
if (pcms->sata) {
|
||||
/* ahci and SATA device, for q35 1 ahci controller is built-in */
|
||||
ahci = pci_create_simple_multifunction(host_bus,
|
||||
PCI_DEVFN(ICH9_SATA1_DEV,
|
||||
ICH9_SATA1_FUNC),
|
||||
true, "ich9-ahci");
|
||||
idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0");
|
||||
idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1");
|
||||
g_assert(MAX_SATA_PORTS == ICH_AHCI(ahci)->ahci.ports);
|
||||
ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports);
|
||||
ahci_ide_create_devs(ahci, hd);
|
||||
} else {
|
||||
idebus[0] = idebus[1] = NULL;
|
||||
}
|
||||
|
||||
if (machine_usb(machine)) {
|
||||
/* Should we create 6 UHCI according to ich9 spec? */
|
||||
ehci_create_ich9_with_companions(host_bus, 0x1d);
|
||||
}
|
||||
|
||||
/* TODO: Populate SPD eeprom data. */
|
||||
smbus_eeprom_init(ich9_smb_init(host_bus,
|
||||
PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC),
|
||||
0xb100),
|
||||
8, NULL, 0);
|
||||
if (pcms->smbus) {
|
||||
/* TODO: Populate SPD eeprom data. */
|
||||
smbus_eeprom_init(ich9_smb_init(host_bus,
|
||||
PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC),
|
||||
0xb100),
|
||||
8, NULL, 0);
|
||||
}
|
||||
|
||||
pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
|
||||
|
||||
|
||||
+8
-1
@@ -2157,6 +2157,13 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
|
||||
DPRINTF("Write %s(sector %" PRId64 ", count %u)\n",
|
||||
(command & 0xe) == 0xe ? "And Verify " : "",
|
||||
r->req.cmd.lba, len);
|
||||
case VERIFY_10:
|
||||
case VERIFY_12:
|
||||
case VERIFY_16:
|
||||
/* We get here only for BYTCHK == 0x01 and only for scsi-block.
|
||||
* As far as DMA is concerned, we can treat it the same as a write;
|
||||
* scsi_block_do_sgio will send VERIFY commands.
|
||||
*/
|
||||
if (r->req.cmd.buf[1] & 0xe0) {
|
||||
goto illegal_request;
|
||||
}
|
||||
@@ -2712,7 +2719,7 @@ static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf)
|
||||
case WRITE_VERIFY_16:
|
||||
/* MMC writing cannot be done via DMA helpers, because it sometimes
|
||||
* involves writing beyond the maximum LBA or to negative LBA (lead-in).
|
||||
* We might use scsi_disk_dma_reqops as long as no writing commands are
|
||||
* We might use scsi_block_dma_reqops as long as no writing commands are
|
||||
* seen, but performance usually isn't paramount on optical media. So,
|
||||
* just make scsi-block operate the same as scsi-generic for them.
|
||||
*/
|
||||
|
||||
+18
-9
@@ -420,6 +420,20 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void virtio_scsi_acquire(VirtIOSCSI *s)
|
||||
{
|
||||
if (s->ctx) {
|
||||
aio_context_acquire(s->ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void virtio_scsi_release(VirtIOSCSI *s)
|
||||
{
|
||||
if (s->ctx) {
|
||||
aio_context_release(s->ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
|
||||
{
|
||||
VirtIOSCSIReq *req;
|
||||
@@ -691,10 +705,7 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->dataplane_started) {
|
||||
assert(s->ctx);
|
||||
aio_context_acquire(s->ctx);
|
||||
}
|
||||
virtio_scsi_acquire(s);
|
||||
|
||||
req = virtio_scsi_pop_req(s, vs->event_vq);
|
||||
if (!req) {
|
||||
@@ -730,9 +741,7 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
|
||||
}
|
||||
virtio_scsi_complete_req(req);
|
||||
out:
|
||||
if (s->dataplane_started) {
|
||||
aio_context_release(s->ctx);
|
||||
}
|
||||
virtio_scsi_release(s);
|
||||
}
|
||||
|
||||
void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq)
|
||||
@@ -778,9 +787,9 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
|
||||
return;
|
||||
}
|
||||
aio_context_acquire(s->ctx);
|
||||
virtio_scsi_acquire(s);
|
||||
blk_set_aio_context(sd->conf.blk, s->ctx);
|
||||
aio_context_release(s->ctx);
|
||||
virtio_scsi_release(s);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -428,6 +428,14 @@ static void i6300esb_realize(PCIDevice *dev, Error **errp)
|
||||
/* qemu_register_coalesced_mmio (addr, 0x10); ? */
|
||||
}
|
||||
|
||||
static void i6300esb_exit(PCIDevice *dev)
|
||||
{
|
||||
I6300State *d = WATCHDOG_I6300ESB_DEVICE(dev);
|
||||
|
||||
timer_del(d->timer);
|
||||
timer_free(d->timer);
|
||||
}
|
||||
|
||||
static WatchdogTimerModel model = {
|
||||
.wdt_name = "i6300esb",
|
||||
.wdt_description = "Intel 6300ESB",
|
||||
@@ -441,6 +449,7 @@ static void i6300esb_class_init(ObjectClass *klass, void *data)
|
||||
k->config_read = i6300esb_config_read;
|
||||
k->config_write = i6300esb_config_write;
|
||||
k->realize = i6300esb_realize;
|
||||
k->exit = i6300esb_exit;
|
||||
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
||||
k->device_id = PCI_DEVICE_ID_INTEL_ESB_9;
|
||||
k->class_id = PCI_CLASS_SYSTEM_OTHER;
|
||||
|
||||
+2
-2
@@ -195,8 +195,8 @@ QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque);
|
||||
* aio_notify: Force processing of pending events.
|
||||
*
|
||||
* Similar to signaling a condition variable, aio_notify forces
|
||||
* aio_wait to exit, so that the next call will re-examine pending events.
|
||||
* The caller of aio_notify will usually call aio_wait again very soon,
|
||||
* aio_poll to exit, so that the next call will re-examine pending events.
|
||||
* The caller of aio_notify will usually call aio_poll again very soon,
|
||||
* or go through another iteration of the GLib main loop. Hence, aio_notify
|
||||
* also has the side effect of recalculating the sets of file descriptors
|
||||
* that the main loop waits for.
|
||||
|
||||
@@ -186,6 +186,29 @@ void address_space_stl(AddressSpace *as, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
void address_space_stq(AddressSpace *as, hwaddr addr, uint64_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
|
||||
uint32_t lduw_phys_cached(MemoryRegionCache *cache, hwaddr addr);
|
||||
uint32_t ldl_phys_cached(MemoryRegionCache *cache, hwaddr addr);
|
||||
uint64_t ldq_phys_cached(MemoryRegionCache *cache, hwaddr addr);
|
||||
void stl_phys_notdirty_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val);
|
||||
void stw_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val);
|
||||
void stl_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val);
|
||||
void stq_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val);
|
||||
|
||||
uint32_t address_space_lduw_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
uint32_t address_space_ldl_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
uint64_t address_space_ldq_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
void address_space_stl_notdirty_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
uint32_t val, MemTxAttrs attrs, MemTxResult *result);
|
||||
void address_space_stw_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
void address_space_stl_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
void address_space_stq_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
#endif
|
||||
|
||||
/* page related stuff */
|
||||
|
||||
@@ -94,21 +94,6 @@ bool cpu_physical_memory_is_io(hwaddr phys_addr);
|
||||
*/
|
||||
void qemu_flush_coalesced_mmio_buffer(void);
|
||||
|
||||
uint32_t ldub_phys(AddressSpace *as, hwaddr addr);
|
||||
uint32_t lduw_le_phys(AddressSpace *as, hwaddr addr);
|
||||
uint32_t lduw_be_phys(AddressSpace *as, hwaddr addr);
|
||||
uint32_t ldl_le_phys(AddressSpace *as, hwaddr addr);
|
||||
uint32_t ldl_be_phys(AddressSpace *as, hwaddr addr);
|
||||
uint64_t ldq_le_phys(AddressSpace *as, hwaddr addr);
|
||||
uint64_t ldq_be_phys(AddressSpace *as, hwaddr addr);
|
||||
void stb_phys(AddressSpace *as, hwaddr addr, uint32_t val);
|
||||
void stw_le_phys(AddressSpace *as, hwaddr addr, uint32_t val);
|
||||
void stw_be_phys(AddressSpace *as, hwaddr addr, uint32_t val);
|
||||
void stl_le_phys(AddressSpace *as, hwaddr addr, uint32_t val);
|
||||
void stl_be_phys(AddressSpace *as, hwaddr addr, uint32_t val);
|
||||
void stq_le_phys(AddressSpace *as, hwaddr addr, uint64_t val);
|
||||
void stq_be_phys(AddressSpace *as, hwaddr addr, uint64_t val);
|
||||
|
||||
void cpu_physical_memory_write_rom(AddressSpace *as, hwaddr addr,
|
||||
const uint8_t *buf, int len);
|
||||
void cpu_flush_icache_range(hwaddr start, int len);
|
||||
|
||||
@@ -1404,6 +1404,140 @@ void address_space_stq_le(AddressSpace *as, hwaddr addr, uint64_t val,
|
||||
void address_space_stq_be(AddressSpace *as, hwaddr addr, uint64_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
|
||||
uint32_t ldub_phys(AddressSpace *as, hwaddr addr);
|
||||
uint32_t lduw_le_phys(AddressSpace *as, hwaddr addr);
|
||||
uint32_t lduw_be_phys(AddressSpace *as, hwaddr addr);
|
||||
uint32_t ldl_le_phys(AddressSpace *as, hwaddr addr);
|
||||
uint32_t ldl_be_phys(AddressSpace *as, hwaddr addr);
|
||||
uint64_t ldq_le_phys(AddressSpace *as, hwaddr addr);
|
||||
uint64_t ldq_be_phys(AddressSpace *as, hwaddr addr);
|
||||
void stb_phys(AddressSpace *as, hwaddr addr, uint32_t val);
|
||||
void stw_le_phys(AddressSpace *as, hwaddr addr, uint32_t val);
|
||||
void stw_be_phys(AddressSpace *as, hwaddr addr, uint32_t val);
|
||||
void stl_le_phys(AddressSpace *as, hwaddr addr, uint32_t val);
|
||||
void stl_be_phys(AddressSpace *as, hwaddr addr, uint32_t val);
|
||||
void stq_le_phys(AddressSpace *as, hwaddr addr, uint64_t val);
|
||||
void stq_be_phys(AddressSpace *as, hwaddr addr, uint64_t val);
|
||||
|
||||
struct MemoryRegionCache {
|
||||
hwaddr xlat;
|
||||
void *ptr;
|
||||
hwaddr len;
|
||||
MemoryRegion *mr;
|
||||
bool is_write;
|
||||
};
|
||||
|
||||
/* address_space_cache_init: prepare for repeated access to a physical
|
||||
* memory region
|
||||
*
|
||||
* @cache: #MemoryRegionCache to be filled
|
||||
* @as: #AddressSpace to be accessed
|
||||
* @addr: address within that address space
|
||||
* @len: length of buffer
|
||||
* @is_write: indicates the transfer direction
|
||||
*
|
||||
* Will only work with RAM, and may map a subset of the requested range by
|
||||
* returning a value that is less than @len. On failure, return a negative
|
||||
* errno value.
|
||||
*
|
||||
* Because it only works with RAM, this function can be used for
|
||||
* read-modify-write operations. In this case, is_write should be %true.
|
||||
*
|
||||
* Note that addresses passed to the address_space_*_cached functions
|
||||
* are relative to @addr.
|
||||
*/
|
||||
int64_t address_space_cache_init(MemoryRegionCache *cache,
|
||||
AddressSpace *as,
|
||||
hwaddr addr,
|
||||
hwaddr len,
|
||||
bool is_write);
|
||||
|
||||
/**
|
||||
* address_space_cache_invalidate: complete a write to a #MemoryRegionCache
|
||||
*
|
||||
* @cache: The #MemoryRegionCache to operate on.
|
||||
* @addr: The first physical address that was written, relative to the
|
||||
* address that was passed to @address_space_cache_init.
|
||||
* @access_len: The number of bytes that were written starting at @addr.
|
||||
*/
|
||||
void address_space_cache_invalidate(MemoryRegionCache *cache,
|
||||
hwaddr addr,
|
||||
hwaddr access_len);
|
||||
|
||||
/**
|
||||
* address_space_cache_destroy: free a #MemoryRegionCache
|
||||
*
|
||||
* @cache: The #MemoryRegionCache whose memory should be released.
|
||||
*/
|
||||
void address_space_cache_destroy(MemoryRegionCache *cache);
|
||||
|
||||
/* address_space_ld*_cached: load from a cached #MemoryRegion
|
||||
* address_space_st*_cached: store into a cached #MemoryRegion
|
||||
*
|
||||
* These functions perform a load or store of the byte, word,
|
||||
* longword or quad to the specified address. The address is
|
||||
* a physical address in the AddressSpace, but it must lie within
|
||||
* a #MemoryRegion that was mapped with address_space_cache_init.
|
||||
*
|
||||
* The _le suffixed functions treat the data as little endian;
|
||||
* _be indicates big endian; no suffix indicates "same endianness
|
||||
* as guest CPU".
|
||||
*
|
||||
* The "guest CPU endianness" accessors are deprecated for use outside
|
||||
* target-* code; devices should be CPU-agnostic and use either the LE
|
||||
* or the BE accessors.
|
||||
*
|
||||
* @cache: previously initialized #MemoryRegionCache to be accessed
|
||||
* @addr: address within the address space
|
||||
* @val: data value, for stores
|
||||
* @attrs: memory transaction attributes
|
||||
* @result: location to write the success/failure of the transaction;
|
||||
* if NULL, this information is discarded
|
||||
*/
|
||||
uint32_t address_space_ldub_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
uint32_t address_space_lduw_le_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
uint32_t address_space_lduw_be_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
uint32_t address_space_ldl_le_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
uint32_t address_space_ldl_be_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
uint64_t address_space_ldq_le_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
uint64_t address_space_ldq_be_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
void address_space_stb_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
void address_space_stw_le_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
void address_space_stw_be_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
void address_space_stl_le_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
void address_space_stl_be_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
void address_space_stq_le_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
void address_space_stq_be_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val,
|
||||
MemTxAttrs attrs, MemTxResult *result);
|
||||
|
||||
uint32_t ldub_phys_cached(MemoryRegionCache *cache, hwaddr addr);
|
||||
uint32_t lduw_le_phys_cached(MemoryRegionCache *cache, hwaddr addr);
|
||||
uint32_t lduw_be_phys_cached(MemoryRegionCache *cache, hwaddr addr);
|
||||
uint32_t ldl_le_phys_cached(MemoryRegionCache *cache, hwaddr addr);
|
||||
uint32_t ldl_be_phys_cached(MemoryRegionCache *cache, hwaddr addr);
|
||||
uint64_t ldq_le_phys_cached(MemoryRegionCache *cache, hwaddr addr);
|
||||
uint64_t ldq_be_phys_cached(MemoryRegionCache *cache, hwaddr addr);
|
||||
void stb_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val);
|
||||
void stw_le_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val);
|
||||
void stw_be_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val);
|
||||
void stl_le_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val);
|
||||
void stl_be_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val);
|
||||
void stq_le_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val);
|
||||
void stq_be_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val);
|
||||
|
||||
/* address_space_translate: translate an address range into an address space
|
||||
* into a MemoryRegion and an address range into that section. Should be
|
||||
* called from an RCU critical section, to avoid that the last reference
|
||||
@@ -1529,6 +1663,38 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* address_space_read_cached: read from a cached RAM region
|
||||
*
|
||||
* @cache: Cached region to be addressed
|
||||
* @addr: address relative to the base of the RAM region
|
||||
* @buf: buffer with the data transferred
|
||||
* @len: length of the data transferred
|
||||
*/
|
||||
static inline void
|
||||
address_space_read_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
void *buf, int len)
|
||||
{
|
||||
assert(addr < cache->len && len <= cache->len - addr);
|
||||
memcpy(buf, cache->ptr + addr, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* address_space_write_cached: write to a cached RAM region
|
||||
*
|
||||
* @cache: Cached region to be addressed
|
||||
* @addr: address relative to the base of the RAM region
|
||||
* @buf: buffer with the data transferred
|
||||
* @len: length of the data transferred
|
||||
*/
|
||||
static inline void
|
||||
address_space_write_cached(MemoryRegionCache *cache, hwaddr addr,
|
||||
void *buf, int len)
|
||||
{
|
||||
assert(addr < cache->len && len <= cache->len - addr);
|
||||
memcpy(cache->ptr + addr, buf, len);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user