- Many fixes from the floor as usual
- New "edu" device (v1->v2: fix 32-bit compilation) - Disabling HLE and RTM on Haswell & Broadwell - kvm_stat updates - Added --enable-modules to Travis, in preparation for switching the default -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQEcBAABAgAGBQJUxiioAAoJEL/70l94x66D+zQIAKVq9DPm4RNJ2/c2nt6phAVr 6Z5yB+TMf4BKFORwVkionvIOEqOC0pdm3oo93/XH7DTsN7pFg7rdwJl+ADESgvl6 +tpUbrgjZuCuNQNXy/mjx0EJQUmTk8/x+a054hSo6XNvs2ZM9HjaKNX3ojS6pG1J mhIH4cjGPMCwu2hgm2mho/1zdIs4Qk3xT8Uzfq8i5gES14YX0Fmt93idUn3DRs7m zHdzHWr0JmXfZweNDdPgsfGO6g+NnwgGUOqeGY4Ucmurkepk9ViCaaJP7lOnuRhT 52isayOrfrZsSLm5xxwtSUjmgbxzlOEit1b8jLzpHb5b9b+LJiCtuJnN7vwHb34= =jgup -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging - Many fixes from the floor as usual - New "edu" device (v1->v2: fix 32-bit compilation) - Disabling HLE and RTM on Haswell & Broadwell - kvm_stat updates - Added --enable-modules to Travis, in preparation for switching the default # gpg: Signature made Mon 26 Jan 2015 11:44:40 GMT using RSA key ID 78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # 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: kvm_stat: Add RESET support for perf event ioctl target-i386: Disable HLE and RTM on Haswell & Broadwell sparse: Fix build with sparse on .S files exec: fix madvise of NULL pointer .travis.yml: Add "--enable-modules" apic: do not dereference pointer before it is checked for NULL kvm_stat: Print errno when syscall to perf_event_open() fails kvm_stat: Update exit reasons to the latest defintion kvm_stat: Add aarch64 support hw: misc, add educational driver vmstate: accept QEMUTimer in VMSTATE_TIMER*, add VMSTATE_TIMER_PTR* qemu-timer: introduce timer_deinit qemu-timer: add timer_init and timer_init_ns/us/ms target-i386: make xmm_regs 512-bit wide target-i386: use vmstate_offset_sub_array for AVX registers tests/multiboot: Add test for modules multiboot: Fix offset of bootloader name tests/multiboot: Update reference output pc: fix KVM features in pc-1.3 and earlier machine types Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
0c28d0d07f
@ -98,3 +98,6 @@ matrix:
|
||||
EXTRA_PKGS="liblttng-ust-dev liburcu-dev"
|
||||
EXTRA_CONFIG="--enable-trace-backends=ust"
|
||||
compiler: gcc
|
||||
- env: TARGETS=i386-softmmu,x86_64-softmmu
|
||||
EXTRA_CONFIG="--enable-modules"
|
||||
compiler: gcc
|
||||
|
@ -599,6 +599,11 @@ F: hw/net/opencores_eth.c
|
||||
|
||||
Devices
|
||||
-------
|
||||
EDU
|
||||
M: Jiri Slaby <jslaby@suse.cz>
|
||||
S: Maintained
|
||||
F: hw/misc/edu.c
|
||||
|
||||
IDE
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
|
1
configure
vendored
1
configure
vendored
@ -4938,6 +4938,7 @@ echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak
|
||||
echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak
|
||||
if test "$sparse" = "yes" ; then
|
||||
echo "CC := REAL_CC=\"\$(CC)\" cgcc" >> $config_host_mak
|
||||
echo "CPP := REAL_CC=\"\$(CPP)\" cgcc" >> $config_host_mak
|
||||
echo "CXX := REAL_CC=\"\$(CXX)\" cgcc" >> $config_host_mak
|
||||
echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_host_mak
|
||||
echo "QEMU_CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak
|
||||
|
@ -32,3 +32,4 @@ CONFIG_PCI_TESTDEV=y
|
||||
CONFIG_NVME_PCI=y
|
||||
CONFIG_SD=y
|
||||
CONFIG_SDHCI=y
|
||||
CONFIG_EDU=y
|
||||
|
110
docs/specs/edu.txt
Normal file
110
docs/specs/edu.txt
Normal file
@ -0,0 +1,110 @@
|
||||
|
||||
EDU device
|
||||
==========
|
||||
|
||||
Copyright (c) 2014-2015 Jiri Slaby
|
||||
|
||||
This document is licensed under the GPLv2 (or later).
|
||||
|
||||
This is an educational device for writing (kernel) drivers. Its original
|
||||
intention was to support the Linux kernel lectures taught at the Masaryk
|
||||
University. Students are given this virtual device and are expected to write a
|
||||
driver with I/Os, IRQs, DMAs and such.
|
||||
|
||||
The devices behaves very similar to the PCI bridge present in the COMBO6 cards
|
||||
developed under the Liberouter wings. Both PCI device ID and PCI space is
|
||||
inherited from that device.
|
||||
|
||||
Command line switches:
|
||||
-device edu[,dma_mask=mask]
|
||||
|
||||
dma_mask makes the virtual device work with DMA addresses with the given
|
||||
mask. For educational purposes, the device supports only 28 bits (256 MiB)
|
||||
by default. Students shall set dma_mask for the device in the OS driver
|
||||
properly.
|
||||
|
||||
PCI specs
|
||||
---------
|
||||
|
||||
PCI ID: 1234:11e8
|
||||
|
||||
PCI Region 0:
|
||||
I/O memory, 1 MB in size. Users are supposed to communicate with the card
|
||||
through this memory.
|
||||
|
||||
MMIO area spec
|
||||
--------------
|
||||
|
||||
Only size == 4 accesses are allowed for addresses < 0x80. size == 4 or
|
||||
size == 8 for the rest.
|
||||
|
||||
0x00 (RO) : identification (0xRRrr00edu)
|
||||
RR -- major version
|
||||
rr -- minor version
|
||||
|
||||
0x04 (RW) : card liveness check
|
||||
It is a simple value inversion (~ C operator).
|
||||
|
||||
0x08 (RW) : factorial computation
|
||||
The stored value is taken and factorial of it is put back here.
|
||||
This happens only after factorial bit in the status register (0x20
|
||||
below) is cleared.
|
||||
|
||||
0x20 (RW) : status register, bitwise OR
|
||||
0x01 -- computing factorial (RO)
|
||||
0x80 -- raise interrupt 0x01 after finishing factorial computation
|
||||
|
||||
0x24 (RO) : interrupt status register
|
||||
It contains values which raised the interrupt (see interrupt raise
|
||||
register below).
|
||||
|
||||
0x60 (WO) : interrupt raise register
|
||||
Raise an interrupt. The value will be put to the interrupt status
|
||||
register (using bitwise OR).
|
||||
|
||||
0x64 (WO) : interrupt acknowledge register
|
||||
Clear an interrupt. The value will be cleared from the interrupt
|
||||
status register. This needs to be done from the ISR to stop
|
||||
generating interrupts.
|
||||
|
||||
0x80 (RW) : DMA source address
|
||||
Where to perform the DMA from.
|
||||
|
||||
0x88 (RW) : DMA destination address
|
||||
Where to perform the DMA to.
|
||||
|
||||
0x90 (RW) : DMA transfer count
|
||||
The size of the area to perform the DMA on.
|
||||
|
||||
0x98 (RW) : DMA command register, bitwise OR
|
||||
0x01 -- start transfer
|
||||
0x02 -- direction (0: from RAM to EDU, 1: from EDU to RAM)
|
||||
0x04 -- raise interrupt 0x100 after finishing the DMA
|
||||
|
||||
IRQ controller
|
||||
--------------
|
||||
An IRQ is generated when written to the interrupt raise register. The value
|
||||
appears in interrupt status register when the interrupt is raised and has to
|
||||
be written to the interrupt acknowledge register to lower it.
|
||||
|
||||
DMA controller
|
||||
--------------
|
||||
One has to specify, source, destination, size, and start the transfer. One
|
||||
4096 bytes long buffer at offset 0x40000 is available in the EDU device. I.e.
|
||||
one can perform DMA to/from this space when programmed properly.
|
||||
|
||||
Example of transferring a 100 byte block to and from the buffer using a given
|
||||
PCI address 'addr':
|
||||
addr -> DMA source address
|
||||
0x40000 -> DMA destination address
|
||||
100 -> DMA transfer count
|
||||
1 -> DMA command register
|
||||
while (DMA command register & 1)
|
||||
;
|
||||
|
||||
0x40000 -> DMA source address
|
||||
addr+100 -> DMA destination address
|
||||
100 -> DMA transfer count
|
||||
3 -> DMA command register
|
||||
while (DMA command register & 1)
|
||||
;
|
13
exec.c
13
exec.c
@ -1386,12 +1386,13 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
|
||||
cpu_physical_memory_set_dirty_range(new_block->offset,
|
||||
new_block->used_length);
|
||||
|
||||
qemu_ram_setup_dump(new_block->host, new_block->max_length);
|
||||
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE);
|
||||
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK);
|
||||
|
||||
if (kvm_enabled()) {
|
||||
kvm_setup_guest_memory(new_block->host, new_block->max_length);
|
||||
if (new_block->host) {
|
||||
qemu_ram_setup_dump(new_block->host, new_block->max_length);
|
||||
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE);
|
||||
qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK);
|
||||
if (kvm_enabled()) {
|
||||
kvm_setup_guest_memory(new_block->host, new_block->max_length);
|
||||
}
|
||||
}
|
||||
|
||||
return new_block->offset;
|
||||
|
@ -166,7 +166,7 @@ const VMStateDescription vmstate_ich9_pm = {
|
||||
VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs),
|
||||
VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs),
|
||||
VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs),
|
||||
VMSTATE_TIMER(acpi_regs.tmr.timer, ICH9LPCPMRegs),
|
||||
VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, ICH9LPCPMRegs),
|
||||
VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs),
|
||||
VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs),
|
||||
VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs),
|
||||
|
@ -285,7 +285,7 @@ static const VMStateDescription vmstate_acpi = {
|
||||
VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState),
|
||||
VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState),
|
||||
VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
|
||||
VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState),
|
||||
VMSTATE_TIMER_PTR(ar.tmr.timer, PIIX4PMState),
|
||||
VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
|
||||
VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
|
||||
VMSTATE_STRUCT_TEST(
|
||||
|
@ -306,7 +306,7 @@ static const VMStateDescription vmstate_stellaris_gptm = {
|
||||
VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2),
|
||||
VMSTATE_UINT32(rtc, gptm_state),
|
||||
VMSTATE_INT64_ARRAY(tick, gptm_state, 2),
|
||||
VMSTATE_TIMER_ARRAY(timer, gptm_state, 2),
|
||||
VMSTATE_TIMER_PTR_ARRAY(timer, gptm_state, 2),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -791,7 +791,7 @@ static const VMStateDescription vmstate_fdc_result_timer = {
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_TIMER(result_timer, FDCtrl),
|
||||
VMSTATE_TIMER_PTR(result_timer, FDCtrl),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -520,7 +520,7 @@ static const VMStateDescription vmstate_cadence_uart = {
|
||||
VMSTATE_UINT32(rx_count, UartState),
|
||||
VMSTATE_UINT32(tx_count, UartState),
|
||||
VMSTATE_UINT32(rx_wpos, UartState),
|
||||
VMSTATE_TIMER(fifo_trigger_handle, UartState),
|
||||
VMSTATE_TIMER_PTR(fifo_trigger_handle, UartState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -730,7 +730,7 @@ const VMStateDescription vmstate_serial_fifo_timeout_timer = {
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_TIMER(fifo_timeout_timer, SerialState),
|
||||
VMSTATE_TIMER_PTR(fifo_timeout_timer, SerialState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
@ -763,7 +763,7 @@ const VMStateDescription vmstate_serial_poll = {
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(poll_msl, SerialState),
|
||||
VMSTATE_TIMER(modem_status_poll, SerialState),
|
||||
VMSTATE_TIMER_PTR(modem_status_poll, SerialState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -214,7 +214,7 @@ const VMStateDescription vmstate_ptimer = {
|
||||
VMSTATE_INT64(period, ptimer_state),
|
||||
VMSTATE_INT64(last_event, ptimer_state),
|
||||
VMSTATE_INT64(next_event, ptimer_state),
|
||||
VMSTATE_TIMER(timer, ptimer_state),
|
||||
VMSTATE_TIMER_PTR(timer, ptimer_state),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -286,7 +286,7 @@ static const VMStateDescription vmstate_pl330 = {
|
||||
PL330Queue),
|
||||
VMSTATE_STRUCT(write_queue, PL330State, 0, vmstate_pl330_queue,
|
||||
PL330Queue),
|
||||
VMSTATE_TIMER(timer, PL330State),
|
||||
VMSTATE_TIMER_PTR(timer, PL330State),
|
||||
VMSTATE_UINT32(inten, PL330State),
|
||||
VMSTATE_UINT32(int_status, PL330State),
|
||||
VMSTATE_UINT32(ev_status, PL330State),
|
||||
|
@ -156,6 +156,7 @@ int load_multiboot(FWCfgState *fw_cfg,
|
||||
MultibootState mbs;
|
||||
uint8_t bootinfo[MBI_SIZE];
|
||||
uint8_t *mb_bootinfo_data;
|
||||
uint32_t cmdline_len;
|
||||
|
||||
/* Ok, let's see if it is a multiboot image.
|
||||
The header is 12x32bit long, so the latest entry may be 8192 - 48. */
|
||||
@ -258,27 +259,28 @@ int load_multiboot(FWCfgState *fw_cfg,
|
||||
mbs.offset_mbinfo = mbs.mb_buf_size;
|
||||
|
||||
/* Calculate space for cmdlines, bootloader name, and mb_mods */
|
||||
mbs.mb_buf_size += strlen(kernel_filename) + 1;
|
||||
mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
|
||||
mbs.mb_buf_size += strlen(bootloader_name) + 1;
|
||||
cmdline_len = strlen(kernel_filename) + 1;
|
||||
cmdline_len += strlen(kernel_cmdline) + 1;
|
||||
if (initrd_filename) {
|
||||
const char *r = initrd_filename;
|
||||
mbs.mb_buf_size += strlen(r) + 1;
|
||||
cmdline_len += strlen(r) + 1;
|
||||
mbs.mb_mods_avail = 1;
|
||||
while (*(r = get_opt_value(NULL, 0, r))) {
|
||||
mbs.mb_mods_avail++;
|
||||
r++;
|
||||
}
|
||||
mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
|
||||
}
|
||||
|
||||
mbs.mb_buf_size += cmdline_len;
|
||||
mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
|
||||
mbs.mb_buf_size += strlen(bootloader_name) + 1;
|
||||
|
||||
mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
|
||||
|
||||
/* enlarge mb_buf to hold cmdlines, bootloader, mb-info structs */
|
||||
mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
|
||||
mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
|
||||
mbs.offset_bootloader = mbs.offset_cmdlines + strlen(kernel_filename) + 1
|
||||
+ strlen(kernel_cmdline) + 1;
|
||||
mbs.offset_bootloader = mbs.offset_cmdlines + cmdline_len;
|
||||
|
||||
if (initrd_filename) {
|
||||
char *next_initrd, not_last;
|
||||
|
@ -328,6 +328,10 @@ static void pc_compat_2_2(MachineState *machine)
|
||||
x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND);
|
||||
x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_F16C);
|
||||
x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND);
|
||||
x86_cpu_compat_set_features("Haswell", FEAT_7_0_EBX,
|
||||
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, 0);
|
||||
x86_cpu_compat_set_features("Broadwell", FEAT_7_0_EBX,
|
||||
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, 0);
|
||||
}
|
||||
|
||||
static void pc_compat_2_1(MachineState *machine)
|
||||
@ -406,7 +410,7 @@ static void pc_compat_1_3(MachineState *machine)
|
||||
static void pc_compat_1_2(MachineState *machine)
|
||||
{
|
||||
pc_compat_1_3(machine);
|
||||
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, KVM_FEATURE_PV_EOI);
|
||||
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
|
||||
}
|
||||
|
||||
static void pc_init_pci_2_2(MachineState *machine)
|
||||
@ -483,7 +487,7 @@ static void pc_init_isa(MachineState *machine)
|
||||
if (!machine->cpu_model) {
|
||||
machine->cpu_model = "486";
|
||||
}
|
||||
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, KVM_FEATURE_PV_EOI);
|
||||
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
|
||||
enable_compat_apic_id_mode();
|
||||
pc_init1(machine, 0, 1);
|
||||
}
|
||||
|
@ -307,6 +307,10 @@ static void pc_compat_2_2(MachineState *machine)
|
||||
x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND);
|
||||
x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_F16C);
|
||||
x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND);
|
||||
x86_cpu_compat_set_features("Haswell", FEAT_7_0_EBX,
|
||||
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, 0);
|
||||
x86_cpu_compat_set_features("Broadwell", FEAT_7_0_EBX,
|
||||
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM, 0);
|
||||
}
|
||||
|
||||
static void pc_compat_2_1(MachineState *machine)
|
||||
|
@ -455,7 +455,7 @@ static const VMStateDescription vmstate_lm_kbd = {
|
||||
VMSTATE_UINT16_ARRAY(pwm.file, LM823KbdState, 256),
|
||||
VMSTATE_UINT8(pwm.faddr, LM823KbdState),
|
||||
VMSTATE_BUFFER(pwm.addr, LM823KbdState),
|
||||
VMSTATE_TIMER_ARRAY(pwm.tm, LM823KbdState, 3),
|
||||
VMSTATE_TIMER_PTR_ARRAY(pwm.tm, LM823KbdState, 3),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -177,13 +177,14 @@ bool apic_next_timer(APICCommonState *s, int64_t current_time)
|
||||
|
||||
void apic_init_reset(DeviceState *dev)
|
||||
{
|
||||
APICCommonState *s = APIC_COMMON(dev);
|
||||
APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
|
||||
APICCommonState *s;
|
||||
APICCommonClass *info;
|
||||
int i;
|
||||
|
||||
if (!s) {
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
s = APIC_COMMON(dev);
|
||||
s->tpr = 0;
|
||||
s->spurious_vec = 0xff;
|
||||
s->log_dest = 0;
|
||||
@ -208,6 +209,7 @@ void apic_init_reset(DeviceState *dev)
|
||||
}
|
||||
s->timer_expiry = -1;
|
||||
|
||||
info = APIC_COMMON_GET_CLASS(s);
|
||||
if (info->reset) {
|
||||
info->reset(s);
|
||||
}
|
||||
|
@ -450,7 +450,7 @@ static const VMStateDescription vmstate_nvic = {
|
||||
VMSTATE_UINT32(systick.control, nvic_state),
|
||||
VMSTATE_UINT32(systick.reload, nvic_state),
|
||||
VMSTATE_INT64(systick.tick, nvic_state),
|
||||
VMSTATE_TIMER(systick.timer, nvic_state),
|
||||
VMSTATE_TIMER_PTR(systick.timer, nvic_state),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -234,7 +234,7 @@ static const VMStateDescription vmstate_acpi = {
|
||||
VMSTATE_UINT16(ar.pm1.evt.en, VT686PMState),
|
||||
VMSTATE_UINT16(ar.pm1.cnt.cnt, VT686PMState),
|
||||
VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState),
|
||||
VMSTATE_TIMER(ar.tmr.timer, VT686PMState),
|
||||
VMSTATE_TIMER_PTR(ar.tmr.timer, VT686PMState),
|
||||
VMSTATE_INT64(ar.tmr.overflow_time, VT686PMState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
|
@ -40,3 +40,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o
|
||||
obj-$(CONFIG_ZYNQ) += zynq_slcr.o
|
||||
|
||||
obj-$(CONFIG_PVPANIC) += pvpanic.o
|
||||
obj-$(CONFIG_EDU) += edu.o
|
||||
|
408
hw/misc/edu.c
Normal file
408
hw/misc/edu.c
Normal file
@ -0,0 +1,408 @@
|
||||
/*
|
||||
* QEMU educational PCI device
|
||||
*
|
||||
* Copyright (c) 2012-2015 Jiri Slaby
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "hw/pci/pci.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/main-loop.h" /* iothread mutex */
|
||||
#include "qapi/visitor.h"
|
||||
|
||||
#define EDU(obj) OBJECT_CHECK(EduState, obj, "edu")
|
||||
|
||||
#define FACT_IRQ 0x00000001
|
||||
#define DMA_IRQ 0x00000100
|
||||
|
||||
#define DMA_START 0x40000
|
||||
#define DMA_SIZE 4096
|
||||
|
||||
typedef struct {
|
||||
PCIDevice pdev;
|
||||
MemoryRegion mmio;
|
||||
|
||||
QemuThread thread;
|
||||
QemuMutex thr_mutex;
|
||||
QemuCond thr_cond;
|
||||
bool stopping;
|
||||
|
||||
uint32_t addr4;
|
||||
uint32_t fact;
|
||||
#define EDU_STATUS_COMPUTING 0x01
|
||||
#define EDU_STATUS_IRQFACT 0x80
|
||||
uint32_t status;
|
||||
|
||||
uint32_t irq_status;
|
||||
|
||||
#define EDU_DMA_RUN 0x1
|
||||
#define EDU_DMA_DIR(cmd) (((cmd) & 0x2) >> 1)
|
||||
# define EDU_DMA_FROM_PCI 0
|
||||
# define EDU_DMA_TO_PCI 1
|
||||
#define EDU_DMA_IRQ 0x4
|
||||
struct dma_state {
|
||||
dma_addr_t src;
|
||||
dma_addr_t dst;
|
||||
dma_addr_t cnt;
|
||||
dma_addr_t cmd;
|
||||
} dma;
|
||||
QEMUTimer dma_timer;
|
||||
char dma_buf[DMA_SIZE];
|
||||
uint64_t dma_mask;
|
||||
} EduState;
|
||||
|
||||
static void edu_raise_irq(EduState *edu, uint32_t val)
|
||||
{
|
||||
edu->irq_status |= val;
|
||||
if (edu->irq_status) {
|
||||
pci_set_irq(&edu->pdev, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void edu_lower_irq(EduState *edu, uint32_t val)
|
||||
{
|
||||
edu->irq_status &= ~val;
|
||||
|
||||
if (!edu->irq_status) {
|
||||
pci_set_irq(&edu->pdev, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static bool within(uint32_t addr, uint32_t start, uint32_t end)
|
||||
{
|
||||
return start <= addr && addr < end;
|
||||
}
|
||||
|
||||
static void edu_check_range(uint32_t addr, uint32_t size1, uint32_t start,
|
||||
uint32_t size2)
|
||||
{
|
||||
uint32_t end1 = addr + size1;
|
||||
uint32_t end2 = start + size2;
|
||||
|
||||
if (within(addr, start, end2) &&
|
||||
end1 > addr && within(end1, start, end2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hw_error("EDU: DMA range 0x%.8x-0x%.8x out of bounds (0x%.8x-0x%.8x)!",
|
||||
addr, end1 - 1, start, end2 - 1);
|
||||
}
|
||||
|
||||
static dma_addr_t edu_clamp_addr(const EduState *edu, dma_addr_t addr)
|
||||
{
|
||||
dma_addr_t res = addr & edu->dma_mask;
|
||||
|
||||
if (addr != res) {
|
||||
printf("EDU: clamping DMA %#.16"PRIx64" to %#.16"PRIx64"!\n", addr, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void edu_dma_timer(void *opaque)
|
||||
{
|
||||
EduState *edu = opaque;
|
||||
bool raise_irq = false;
|
||||
|
||||
if (!(edu->dma.cmd & EDU_DMA_RUN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (EDU_DMA_DIR(edu->dma.cmd) == EDU_DMA_FROM_PCI) {
|
||||
uint32_t dst = edu->dma.dst;
|
||||
edu_check_range(dst, edu->dma.cnt, DMA_START, DMA_SIZE);
|
||||
dst -= DMA_START;
|
||||
pci_dma_read(&edu->pdev, edu_clamp_addr(edu, edu->dma.src),
|
||||
edu->dma_buf + dst, edu->dma.cnt);
|
||||
} else {
|
||||
uint32_t src = edu->dma.src;
|
||||
edu_check_range(src, edu->dma.cnt, DMA_START, DMA_SIZE);
|
||||
src -= DMA_START;
|
||||
pci_dma_write(&edu->pdev, edu_clamp_addr(edu, edu->dma.dst),
|
||||
edu->dma_buf + src, edu->dma.cnt);
|
||||
}
|
||||
|
||||
edu->dma.cmd &= ~EDU_DMA_RUN;
|
||||
if (edu->dma.cmd & EDU_DMA_IRQ) {
|
||||
raise_irq = true;
|
||||
}
|
||||
|
||||
if (raise_irq) {
|
||||
edu_raise_irq(edu, DMA_IRQ);
|
||||
}
|
||||
}
|
||||
|
||||
static void dma_rw(EduState *edu, bool write, dma_addr_t *val, dma_addr_t *dma,
|
||||
bool timer)
|
||||
{
|
||||
if (write && (edu->dma.cmd & EDU_DMA_RUN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (write) {
|
||||
*dma = *val;
|
||||
} else {
|
||||
*val = *dma;
|
||||
}
|
||||
|
||||
if (timer) {
|
||||
timer_mod(&edu->dma_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 100);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t edu_mmio_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
EduState *edu = opaque;
|
||||
uint64_t val = ~0ULL;
|
||||
|
||||
if (size != 4) {
|
||||
return val;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x00:
|
||||
val = 0x010000edu;
|
||||
break;
|
||||
case 0x04:
|
||||
val = edu->addr4;
|
||||
break;
|
||||
case 0x08:
|
||||
qemu_mutex_lock(&edu->thr_mutex);
|
||||
val = edu->fact;
|
||||
qemu_mutex_unlock(&edu->thr_mutex);
|
||||
break;
|
||||
case 0x20:
|
||||
val = atomic_read(&edu->status);
|
||||
break;
|
||||
case 0x24:
|
||||
val = edu->irq_status;
|
||||
break;
|
||||
case 0x80:
|
||||
dma_rw(edu, false, &val, &edu->dma.src, false);
|
||||
break;
|
||||
case 0x88:
|
||||
dma_rw(edu, false, &val, &edu->dma.dst, false);
|
||||
break;
|
||||
case 0x90:
|
||||
dma_rw(edu, false, &val, &edu->dma.cnt, false);
|
||||
break;
|
||||
case 0x98:
|
||||
dma_rw(edu, false, &val, &edu->dma.cmd, false);
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void edu_mmio_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned size)
|
||||
{
|
||||
EduState *edu = opaque;
|
||||
|
||||
if (addr < 0x80 && size != 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr >= 0x80 && size != 4 && size != 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x04:
|
||||
edu->addr4 = ~val;
|
||||
break;
|
||||
case 0x08:
|
||||
if (atomic_read(&edu->status) & EDU_STATUS_COMPUTING) {
|
||||
break;
|
||||
}
|
||||
/* EDU_STATUS_COMPUTING cannot go 0->1 concurrently, because it is only
|
||||
* set in this function and it is under the iothread mutex.
|
||||
*/
|
||||
qemu_mutex_lock(&edu->thr_mutex);
|
||||
edu->fact = val;
|
||||
atomic_or(&edu->status, EDU_STATUS_COMPUTING);
|
||||
qemu_cond_signal(&edu->thr_cond);
|
||||
qemu_mutex_unlock(&edu->thr_mutex);
|
||||
break;
|
||||
case 0x20:
|
||||
if (val & EDU_STATUS_IRQFACT) {
|
||||
atomic_or(&edu->status, EDU_STATUS_IRQFACT);
|
||||
} else {
|
||||
atomic_and(&edu->status, ~EDU_STATUS_IRQFACT);
|
||||
}
|
||||
break;
|
||||
case 0x60:
|
||||
edu_raise_irq(edu, val);
|
||||
break;
|
||||
case 0x64:
|
||||
edu_lower_irq(edu, val);
|
||||
break;
|
||||
case 0x80:
|
||||
dma_rw(edu, true, &val, &edu->dma.src, false);
|
||||
break;
|
||||
case 0x88:
|
||||
dma_rw(edu, true, &val, &edu->dma.dst, false);
|
||||
break;
|
||||
case 0x90:
|
||||
dma_rw(edu, true, &val, &edu->dma.cnt, false);
|
||||
break;
|
||||
case 0x98:
|
||||
if (!(val & EDU_DMA_RUN)) {
|
||||
break;
|
||||
}
|
||||
dma_rw(edu, true, &val, &edu->dma.cmd, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps edu_mmio_ops = {
|
||||
.read = edu_mmio_read,
|
||||
.write = edu_mmio_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
/*
|
||||
* We purposedly use a thread, so that users are forced to wait for the status
|
||||
* register.
|
||||
*/
|
||||
static void *edu_fact_thread(void *opaque)
|
||||
{
|
||||
EduState *edu = opaque;
|
||||
|
||||
while (1) {
|
||||
uint32_t val, ret = 1;
|
||||
|
||||
qemu_mutex_lock(&edu->thr_mutex);
|
||||
while ((atomic_read(&edu->status) & EDU_STATUS_COMPUTING) == 0 &&
|
||||
!edu->stopping) {
|
||||
qemu_cond_wait(&edu->thr_cond, &edu->thr_mutex);
|
||||
}
|
||||
|
||||
if (edu->stopping) {
|
||||
qemu_mutex_unlock(&edu->thr_mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
val = edu->fact;
|
||||
qemu_mutex_unlock(&edu->thr_mutex);
|
||||
|
||||
while (val > 0) {
|
||||
ret *= val--;
|
||||
}
|
||||
|
||||
/*
|
||||
* We should sleep for a random period here, so that students are
|
||||
* forced to check the status properly.
|
||||
*/
|
||||
|
||||
qemu_mutex_lock(&edu->thr_mutex);
|
||||
edu->fact = ret;
|
||||
qemu_mutex_unlock(&edu->thr_mutex);
|
||||
atomic_and(&edu->status, ~EDU_STATUS_COMPUTING);
|
||||
|
||||
if (atomic_read(&edu->status) & EDU_STATUS_IRQFACT) {
|
||||
qemu_mutex_lock_iothread();
|
||||
edu_raise_irq(edu, FACT_IRQ);
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int pci_edu_init(PCIDevice *pdev)
|
||||
{
|
||||
EduState *edu = DO_UPCAST(EduState, pdev, pdev);
|
||||
uint8_t *pci_conf = pdev->config;
|
||||
|
||||
timer_init_ms(&edu->dma_timer, QEMU_CLOCK_VIRTUAL, edu_dma_timer, edu);
|
||||
|
||||
qemu_mutex_init(&edu->thr_mutex);
|
||||
qemu_cond_init(&edu->thr_cond);
|
||||
qemu_thread_create(&edu->thread, "edu", edu_fact_thread,
|
||||
edu, QEMU_THREAD_JOINABLE);
|
||||
|
||||
pci_config_set_interrupt_pin(pci_conf, 1);
|
||||
|
||||
memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu,
|
||||
"edu-mmio", 1 << 20);
|
||||
pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pci_edu_uninit(PCIDevice *pdev)
|
||||
{
|
||||
EduState *edu = DO_UPCAST(EduState, pdev, pdev);
|
||||
|
||||
qemu_mutex_lock(&edu->thr_mutex);
|
||||
edu->stopping = true;
|
||||
qemu_mutex_unlock(&edu->thr_mutex);
|
||||
qemu_cond_signal(&edu->thr_cond);
|
||||
qemu_thread_join(&edu->thread);
|
||||
|
||||
qemu_cond_destroy(&edu->thr_cond);
|
||||
qemu_mutex_destroy(&edu->thr_mutex);
|
||||
|
||||
timer_del(&edu->dma_timer);
|
||||
}
|
||||
|
||||
static void edu_obj_uint64(Object *obj, struct Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
uint64_t *val = opaque;
|
||||
|
||||
visit_type_uint64(v, val, name, errp);
|
||||
}
|
||||
|
||||
static void edu_instance_init(Object *obj)
|
||||
{
|
||||
EduState *edu = EDU(obj);
|
||||
|
||||
edu->dma_mask = (1UL << 28) - 1;
|
||||
object_property_add(obj, "dma_mask", "uint64", edu_obj_uint64,
|
||||
edu_obj_uint64, NULL, &edu->dma_mask, NULL);
|
||||
}
|
||||
|
||||
static void edu_class_init(ObjectClass *class, void *data)
|
||||
{
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(class);
|
||||
|
||||
k->init = pci_edu_init;
|
||||
k->exit = pci_edu_uninit;
|
||||
k->vendor_id = PCI_VENDOR_ID_QEMU;
|
||||
k->device_id = 0x11e8;
|
||||
k->revision = 0x10;
|
||||
k->class_id = PCI_CLASS_OTHERS;
|
||||
}
|
||||
|
||||
static void pci_edu_register_types(void)
|
||||
{
|
||||
static const TypeInfo edu_info = {
|
||||
.name = "edu",
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(EduState),
|
||||
.instance_init = edu_instance_init,
|
||||
.class_init = edu_class_init,
|
||||
};
|
||||
|
||||
type_register_static(&edu_info);
|
||||
}
|
||||
type_init(pci_edu_register_types)
|
@ -631,7 +631,7 @@ static const VMStateDescription vmstate_cuda_timer = {
|
||||
VMSTATE_UINT16(counter_value, CUDATimer),
|
||||
VMSTATE_INT64(load_time, CUDATimer),
|
||||
VMSTATE_INT64(next_irq_time, CUDATimer),
|
||||
VMSTATE_TIMER_TEST(timer, CUDATimer, cuda_timer_exist),
|
||||
VMSTATE_TIMER_PTR_TEST(timer, CUDATimer, cuda_timer_exist),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -1719,7 +1719,7 @@ const VMStateDescription vmstate_pcnet = {
|
||||
VMSTATE_BUFFER(buffer, PCNetState),
|
||||
VMSTATE_UNUSED_TEST(is_version_2, 4),
|
||||
VMSTATE_INT32(tx_busy, PCNetState),
|
||||
VMSTATE_TIMER(poll_timer, PCNetState),
|
||||
VMSTATE_TIMER_PTR(poll_timer, PCNetState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -1205,8 +1205,8 @@ const VMStateDescription sdhci_vmstate = {
|
||||
VMSTATE_UINT64(admasysaddr, SDHCIState),
|
||||
VMSTATE_UINT8(stopped_state, SDHCIState),
|
||||
VMSTATE_VBUFFER_UINT32(fifo_buffer, SDHCIState, 1, NULL, 0, buf_maxsz),
|
||||
VMSTATE_TIMER(insert_timer, SDHCIState),
|
||||
VMSTATE_TIMER(transfer_timer, SDHCIState),
|
||||
VMSTATE_TIMER_PTR(insert_timer, SDHCIState),
|
||||
VMSTATE_TIMER_PTR(transfer_timer, SDHCIState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -328,7 +328,7 @@ static const VMStateDescription vmstate_a9_gtimer = {
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_TIMER(timer, A9GTimerState),
|
||||
VMSTATE_TIMER_PTR(timer, A9GTimerState),
|
||||
VMSTATE_UINT64(counter, A9GTimerState),
|
||||
VMSTATE_UINT64(ref_counter, A9GTimerState),
|
||||
VMSTATE_UINT64(cpu_ref_time, A9GTimerState),
|
||||
|
@ -246,7 +246,7 @@ static const VMStateDescription vmstate_timerblock = {
|
||||
VMSTATE_UINT32(control, TimerBlock),
|
||||
VMSTATE_UINT32(status, TimerBlock),
|
||||
VMSTATE_INT64(tick, TimerBlock),
|
||||
VMSTATE_TIMER(timer, TimerBlock),
|
||||
VMSTATE_TIMER_PTR(timer, TimerBlock),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -299,7 +299,7 @@ static const VMStateDescription vmstate_hpet_timer = {
|
||||
VMSTATE_UINT64(fsb, HPETTimer),
|
||||
VMSTATE_UINT64(period, HPETTimer),
|
||||
VMSTATE_UINT8(wrap_flag, HPETTimer),
|
||||
VMSTATE_TIMER(qemu_timer, HPETTimer),
|
||||
VMSTATE_TIMER_PTR(qemu_timer, HPETTimer),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -758,7 +758,7 @@ static const VMStateDescription vmstate_rtc = {
|
||||
VMSTATE_BUFFER(cmos_data, RTCState),
|
||||
VMSTATE_UINT8(cmos_index, RTCState),
|
||||
VMSTATE_UNUSED(7*4),
|
||||
VMSTATE_TIMER(periodic_timer, RTCState),
|
||||
VMSTATE_TIMER_PTR(periodic_timer, RTCState),
|
||||
VMSTATE_INT64(next_periodic_time, RTCState),
|
||||
VMSTATE_UNUSED(3*8),
|
||||
VMSTATE_UINT32_V(irq_coalesced, RTCState, 2),
|
||||
@ -766,7 +766,7 @@ static const VMStateDescription vmstate_rtc = {
|
||||
VMSTATE_UINT64_V(base_rtc, RTCState, 3),
|
||||
VMSTATE_UINT64_V(last_update, RTCState, 3),
|
||||
VMSTATE_INT64_V(offset, RTCState, 3),
|
||||
VMSTATE_TIMER_V(update_timer, RTCState, 3),
|
||||
VMSTATE_TIMER_PTR_V(update_timer, RTCState, 3),
|
||||
VMSTATE_UINT64_V(next_alarm_time, RTCState, 3),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
|
@ -2437,7 +2437,7 @@ const VMStateDescription vmstate_ehci = {
|
||||
VMSTATE_UINT32(portsc[4], EHCIState),
|
||||
VMSTATE_UINT32(portsc[5], EHCIState),
|
||||
/* frame timer */
|
||||
VMSTATE_TIMER(frame_timer, EHCIState),
|
||||
VMSTATE_TIMER_PTR(frame_timer, EHCIState),
|
||||
VMSTATE_UINT64(last_run_ns, EHCIState),
|
||||
VMSTATE_UINT32(async_stepdown, EHCIState),
|
||||
/* schedule state */
|
||||
|
@ -2015,7 +2015,7 @@ static const VMStateDescription vmstate_ohci_eof_timer = {
|
||||
.minimum_version_id = 1,
|
||||
.pre_load = ohci_eof_timer_pre_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_TIMER(eof_timer, OHCIState),
|
||||
VMSTATE_TIMER_PTR(eof_timer, OHCIState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
@ -419,7 +419,7 @@ static const VMStateDescription vmstate_uhci = {
|
||||
VMSTATE_UINT32(fl_base_addr, UHCIState),
|
||||
VMSTATE_UINT8(sof_timing, UHCIState),
|
||||
VMSTATE_UINT8(status2, UHCIState),
|
||||
VMSTATE_TIMER(frame_timer, UHCIState),
|
||||
VMSTATE_TIMER_PTR(frame_timer, UHCIState),
|
||||
VMSTATE_INT64_V(expire_time, UHCIState, 2),
|
||||
VMSTATE_UINT32_V(pending_int_mask, UHCIState, 3),
|
||||
VMSTATE_END_OF_LIST()
|
||||
|
@ -3855,7 +3855,7 @@ static const VMStateDescription vmstate_xhci = {
|
||||
|
||||
/* Runtime Registers & state */
|
||||
VMSTATE_INT64(mfindex_start, XHCIState),
|
||||
VMSTATE_TIMER(mfwrap_timer, XHCIState),
|
||||
VMSTATE_TIMER_PTR(mfwrap_timer, XHCIState),
|
||||
VMSTATE_STRUCT(cmd_ring, XHCIState, 1, vmstate_xhci_ring, XHCIRing),
|
||||
|
||||
VMSTATE_END_OF_LIST()
|
||||
|
@ -2438,7 +2438,7 @@ static const VMStateDescription usbredir_vmstate = {
|
||||
.post_load = usbredir_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_USB_DEVICE(dev, USBRedirDevice),
|
||||
VMSTATE_TIMER(attach_timer, USBRedirDevice),
|
||||
VMSTATE_TIMER_PTR(attach_timer, USBRedirDevice),
|
||||
{
|
||||
.name = "parser",
|
||||
.version_id = 0,
|
||||
|
@ -398,7 +398,7 @@ static const VMStateDescription vmstate_i6300esb = {
|
||||
VMSTATE_INT32(free_run, I6300State),
|
||||
VMSTATE_INT32(locked, I6300State),
|
||||
VMSTATE_INT32(enabled, I6300State),
|
||||
VMSTATE_TIMER(timer, I6300State),
|
||||
VMSTATE_TIMER_PTR(timer, I6300State),
|
||||
VMSTATE_UINT32(timer1_preload, I6300State),
|
||||
VMSTATE_UINT32(timer2_preload, I6300State),
|
||||
VMSTATE_INT32(stage, I6300State),
|
||||
|
@ -93,7 +93,7 @@ static const VMStateDescription vmstate_ib700 = {
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_TIMER(timer, IB700State),
|
||||
VMSTATE_TIMER_PTR(timer, IB700State),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -359,6 +359,16 @@ extern const VMStateInfo vmstate_info_bitmap;
|
||||
.offset = vmstate_offset_array(_s, _f, _type*, _n), \
|
||||
}
|
||||
|
||||
#define VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, _num, _version, _vmsd, _type) { \
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = (_version), \
|
||||
.num = (_num), \
|
||||
.vmsd = &(_vmsd), \
|
||||
.size = sizeof(_type), \
|
||||
.flags = VMS_STRUCT|VMS_ARRAY, \
|
||||
.offset = vmstate_offset_sub_array(_state, _field, _type, _start), \
|
||||
}
|
||||
|
||||
#define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, _vmsd, _type) { \
|
||||
.name = (stringify(_field)), \
|
||||
.num = (_num), \
|
||||
@ -642,17 +652,29 @@ extern const VMStateInfo vmstate_info_bitmap;
|
||||
#define VMSTATE_FLOAT64(_f, _s) \
|
||||
VMSTATE_FLOAT64_V(_f, _s, 0)
|
||||
|
||||
#define VMSTATE_TIMER_TEST(_f, _s, _test) \
|
||||
#define VMSTATE_TIMER_PTR_TEST(_f, _s, _test) \
|
||||
VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *)
|
||||
|
||||
#define VMSTATE_TIMER_V(_f, _s, _v) \
|
||||
#define VMSTATE_TIMER_PTR_V(_f, _s, _v) \
|
||||
VMSTATE_POINTER(_f, _s, _v, vmstate_info_timer, QEMUTimer *)
|
||||
|
||||
#define VMSTATE_TIMER_PTR(_f, _s) \
|
||||
VMSTATE_TIMER_PTR_V(_f, _s, 0)
|
||||
|
||||
#define VMSTATE_TIMER_PTR_ARRAY(_f, _s, _n) \
|
||||
VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *)
|
||||
|
||||
#define VMSTATE_TIMER_TEST(_f, _s, _test) \
|
||||
VMSTATE_SINGLE_TEST(_f, _s, _test, 0, vmstate_info_timer, QEMUTimer)
|
||||
|
||||
#define VMSTATE_TIMER_V(_f, _s, _v) \
|
||||
VMSTATE_SINGLE(_f, _s, _v, vmstate_info_timer, QEMUTimer)
|
||||
|
||||
#define VMSTATE_TIMER(_f, _s) \
|
||||
VMSTATE_TIMER_V(_f, _s, 0)
|
||||
|
||||
#define VMSTATE_TIMER_ARRAY(_f, _s, _n) \
|
||||
VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *)
|
||||
VMSTATE_ARRAY(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer)
|
||||
|
||||
#define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v) \
|
||||
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool)
|
||||
|
@ -427,6 +427,79 @@ void timer_init_tl(QEMUTimer *ts,
|
||||
QEMUTimerList *timer_list, int scale,
|
||||
QEMUTimerCB *cb, void *opaque);
|
||||
|
||||
/**
|
||||
* timer_init:
|
||||
* @type: the clock to associate with the timer
|
||||
* @scale: the scale value for the timer
|
||||
* @cb: the callback to call when the timer expires
|
||||
* @opaque: the opaque pointer to pass to the callback
|
||||
*
|
||||
* Initialize a timer with the given scale on the default timer list
|
||||
* associated with the clock.
|
||||
*
|
||||
* You need not call an explicit deinit call. Simply make
|
||||
* sure it is not on a list with timer_del.
|
||||
*/
|
||||
static inline void timer_init(QEMUTimer *ts, QEMUClockType type, int scale,
|
||||
QEMUTimerCB *cb, void *opaque)
|
||||
{
|
||||
timer_init_tl(ts, main_loop_tlg.tl[type], scale, cb, opaque);
|
||||
}
|
||||
|
||||
/**
|
||||
* timer_init_ns:
|
||||
* @type: the clock to associate with the timer
|
||||
* @cb: the callback to call when the timer expires
|
||||
* @opaque: the opaque pointer to pass to the callback
|
||||
*
|
||||
* Initialize a timer with nanosecond scale on the default timer list
|
||||
* associated with the clock.
|
||||
*
|
||||
* You need not call an explicit deinit call. Simply make
|
||||
* sure it is not on a list with timer_del.
|
||||
*/
|
||||
static inline void timer_init_ns(QEMUTimer *ts, QEMUClockType type,
|
||||
QEMUTimerCB *cb, void *opaque)
|
||||
{
|
||||
timer_init(ts, type, SCALE_NS, cb, opaque);
|
||||
}
|
||||
|
||||
/**
|
||||
* timer_init_us:
|
||||
* @type: the clock to associate with the timer
|
||||
* @cb: the callback to call when the timer expires
|
||||
* @opaque: the opaque pointer to pass to the callback
|
||||
*
|
||||
* Initialize a timer with microsecond scale on the default timer list
|
||||
* associated with the clock.
|
||||
*
|
||||
* You need not call an explicit deinit call. Simply make
|
||||
* sure it is not on a list with timer_del.
|
||||
*/
|
||||
static inline void timer_init_us(QEMUTimer *ts, QEMUClockType type,
|
||||
QEMUTimerCB *cb, void *opaque)
|
||||
{
|
||||
timer_init(ts, type, SCALE_US, cb, opaque);
|
||||
}
|
||||
|
||||
/**
|
||||
* timer_init_ms:
|
||||
* @type: the clock to associate with the timer
|
||||
* @cb: the callback to call when the timer expires
|
||||
* @opaque: the opaque pointer to pass to the callback
|
||||
*
|
||||
* Initialize a timer with millisecond scale on the default timer list
|
||||
* associated with the clock.
|
||||
*
|
||||
* You need not call an explicit deinit call. Simply make
|
||||
* sure it is not on a list with timer_del.
|
||||
*/
|
||||
static inline void timer_init_ms(QEMUTimer *ts, QEMUClockType type,
|
||||
QEMUTimerCB *cb, void *opaque)
|
||||
{
|
||||
timer_init(ts, type, SCALE_MS, cb, opaque);
|
||||
}
|
||||
|
||||
/**
|
||||
* timer_new_tl:
|
||||
* @timer_list: the timer list to attach the timer to
|
||||
@ -521,6 +594,17 @@ static inline QEMUTimer *timer_new_ms(QEMUClockType type, QEMUTimerCB *cb,
|
||||
return timer_new(type, SCALE_MS, cb, opaque);
|
||||
}
|
||||
|
||||
/**
|
||||
* timer_deinit:
|
||||
* @ts: the timer to be de-initialised
|
||||
*
|
||||
* Deassociate the timer from any timerlist. You should
|
||||
* call timer_del before. After this call, any further
|
||||
* timer_del call cannot cause dangling pointer accesses
|
||||
* even if the previously used timerlist is freed.
|
||||
*/
|
||||
void timer_deinit(QEMUTimer *ts);
|
||||
|
||||
/**
|
||||
* timer_free:
|
||||
* @ts: the timer
|
||||
|
14
qemu-timer.c
14
qemu-timer.c
@ -342,6 +342,12 @@ void timer_init_tl(QEMUTimer *ts,
|
||||
ts->expire_time = -1;
|
||||
}
|
||||
|
||||
void timer_deinit(QEMUTimer *ts)
|
||||
{
|
||||
assert(ts->expire_time == -1);
|
||||
ts->timer_list = NULL;
|
||||
}
|
||||
|
||||
void timer_free(QEMUTimer *ts)
|
||||
{
|
||||
g_free(ts);
|
||||
@ -398,9 +404,11 @@ void timer_del(QEMUTimer *ts)
|
||||
{
|
||||
QEMUTimerList *timer_list = ts->timer_list;
|
||||
|
||||
qemu_mutex_lock(&timer_list->active_timers_lock);
|
||||
timer_del_locked(timer_list, ts);
|
||||
qemu_mutex_unlock(&timer_list->active_timers_lock);
|
||||
if (timer_list) {
|
||||
qemu_mutex_lock(&timer_list->active_timers_lock);
|
||||
timer_del_locked(timer_list, ts);
|
||||
qemu_mutex_unlock(&timer_list->active_timers_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/* modify the current timer so that it will be fired when current_time
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
import curses
|
||||
import sys, os, time, optparse, ctypes
|
||||
from ctypes import *
|
||||
|
||||
class DebugfsProvider(object):
|
||||
def __init__(self):
|
||||
@ -65,6 +66,8 @@ vmx_exit_reasons = {
|
||||
49: 'EPT_MISCONFIG',
|
||||
54: 'WBINVD',
|
||||
55: 'XSETBV',
|
||||
56: 'APIC_WRITE',
|
||||
58: 'INVPCID',
|
||||
}
|
||||
|
||||
svm_exit_reasons = {
|
||||
@ -138,6 +141,7 @@ svm_exit_reasons = {
|
||||
0x08a: 'MONITOR',
|
||||
0x08b: 'MWAIT',
|
||||
0x08c: 'MWAIT_COND',
|
||||
0x08d: 'XSETBV',
|
||||
0x400: 'NPF',
|
||||
}
|
||||
|
||||
@ -167,6 +171,7 @@ userspace_exit_reasons = {
|
||||
21: 'WATCHDOG',
|
||||
22: 'S390_TSCH',
|
||||
23: 'EPR',
|
||||
24: 'SYSTEM_EVENT',
|
||||
}
|
||||
|
||||
x86_exit_reasons = {
|
||||
@ -181,6 +186,7 @@ ioctl_numbers = {
|
||||
'SET_FILTER' : 0x40082406,
|
||||
'ENABLE' : 0x00002400,
|
||||
'DISABLE' : 0x00002401,
|
||||
'RESET' : 0x00002403,
|
||||
}
|
||||
|
||||
def x86_init(flag):
|
||||
@ -204,10 +210,18 @@ def ppc_init():
|
||||
}
|
||||
})
|
||||
|
||||
def aarch64_init():
|
||||
globals().update({
|
||||
'sc_perf_evt_open' : 241
|
||||
})
|
||||
|
||||
def detect_platform():
|
||||
if os.uname()[4].startswith('ppc'):
|
||||
ppc_init()
|
||||
return
|
||||
elif os.uname()[4].startswith('aarch64'):
|
||||
aarch64_init()
|
||||
return
|
||||
|
||||
for line in file('/proc/cpuinfo').readlines():
|
||||
if line.startswith('flags'):
|
||||
@ -235,6 +249,9 @@ import struct, array
|
||||
|
||||
libc = ctypes.CDLL('libc.so.6')
|
||||
syscall = libc.syscall
|
||||
get_errno = libc.__errno_location
|
||||
get_errno.restype = POINTER(c_int)
|
||||
|
||||
class perf_event_attr(ctypes.Structure):
|
||||
_fields_ = [('type', ctypes.c_uint32),
|
||||
('size', ctypes.c_uint32),
|
||||
@ -318,7 +335,8 @@ class Event(object):
|
||||
group_leader = group.events[0].fd
|
||||
fd = _perf_event_open(attr, -1, group.cpu, group_leader, 0)
|
||||
if fd == -1:
|
||||
raise Exception('perf_event_open failed')
|
||||
err = get_errno()[0]
|
||||
raise Exception('perf_event_open failed, errno = ' + err.__str__())
|
||||
if filter:
|
||||
import fcntl
|
||||
fcntl.ioctl(fd, ioctl_numbers['SET_FILTER'], filter)
|
||||
@ -329,6 +347,9 @@ class Event(object):
|
||||
def disable(self):
|
||||
import fcntl
|
||||
fcntl.ioctl(self.fd, ioctl_numbers['DISABLE'], 0)
|
||||
def reset(self):
|
||||
import fcntl
|
||||
fcntl.ioctl(self.fd, ioctl_numbers['RESET'], 0)
|
||||
|
||||
class TracepointProvider(object):
|
||||
def __init__(self):
|
||||
@ -388,6 +409,7 @@ class TracepointProvider(object):
|
||||
for group in self.group_leaders:
|
||||
for event in group.events:
|
||||
if event.name in fields:
|
||||
event.reset()
|
||||
event.enable()
|
||||
else:
|
||||
event.disable()
|
||||
|
@ -277,8 +277,8 @@ const VMStateDescription vmstate_arm_cpu = {
|
||||
VMSTATE_UINT32(env.exception.syndrome, ARMCPU),
|
||||
VMSTATE_UINT32(env.exception.fsr, ARMCPU),
|
||||
VMSTATE_UINT64(env.exception.vaddress, ARMCPU),
|
||||
VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU),
|
||||
VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU),
|
||||
VMSTATE_TIMER_PTR(gt_timer[GTIMER_PHYS], ARMCPU),
|
||||
VMSTATE_TIMER_PTR(gt_timer[GTIMER_VIRT], ARMCPU),
|
||||
VMSTATE_BOOL(powered_off, ARMCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
|
@ -1100,9 +1100,8 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
CPUID_EXT3_LAHF_LM,
|
||||
.features[FEAT_7_0_EBX] =
|
||||
CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
||||
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
|
||||
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
|
||||
CPUID_7_0_EBX_RTM,
|
||||
CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
|
||||
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID,
|
||||
.features[FEAT_XSAVE] =
|
||||
CPUID_XSAVE_XSAVEOPT,
|
||||
.xlevel = 0x8000000A,
|
||||
@ -1135,9 +1134,9 @@ static X86CPUDefinition builtin_x86_defs[] = {
|
||||
CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
|
||||
.features[FEAT_7_0_EBX] =
|
||||
CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
|
||||
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
|
||||
CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
|
||||
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
|
||||
CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
|
||||
CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
|
||||
CPUID_7_0_EBX_SMAP,
|
||||
.features[FEAT_XSAVE] =
|
||||
CPUID_XSAVE_XSAVEOPT,
|
||||
|
@ -712,24 +712,6 @@ typedef struct SegmentCache {
|
||||
uint32_t flags;
|
||||
} SegmentCache;
|
||||
|
||||
typedef union {
|
||||
uint8_t _b[16];
|
||||
uint16_t _w[8];
|
||||
uint32_t _l[4];
|
||||
uint64_t _q[2];
|
||||
float32 _s[4];
|
||||
float64 _d[2];
|
||||
} XMMReg;
|
||||
|
||||
typedef union {
|
||||
uint8_t _b[32];
|
||||
uint16_t _w[16];
|
||||
uint32_t _l[8];
|
||||
uint64_t _q[4];
|
||||
float32 _s[8];
|
||||
float64 _d[4];
|
||||
} YMMReg;
|
||||
|
||||
typedef union {
|
||||
uint8_t _b[64];
|
||||
uint16_t _w[32];
|
||||
@ -737,7 +719,7 @@ typedef union {
|
||||
uint64_t _q[8];
|
||||
float32 _s[16];
|
||||
float64 _d[8];
|
||||
} ZMMReg;
|
||||
} XMMReg; /* really zmm */
|
||||
|
||||
typedef union {
|
||||
uint8_t _b[8];
|
||||
@ -758,46 +740,18 @@ typedef struct BNDCSReg {
|
||||
} BNDCSReg;
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
#define ZMM_B(n) _b[63 - (n)]
|
||||
#define ZMM_W(n) _w[31 - (n)]
|
||||
#define ZMM_L(n) _l[15 - (n)]
|
||||
#define ZMM_S(n) _s[15 - (n)]
|
||||
#define ZMM_Q(n) _q[7 - (n)]
|
||||
#define ZMM_D(n) _d[7 - (n)]
|
||||
|
||||
#define YMM_B(n) _b[31 - (n)]
|
||||
#define YMM_W(n) _w[15 - (n)]
|
||||
#define YMM_L(n) _l[7 - (n)]
|
||||
#define YMM_S(n) _s[7 - (n)]
|
||||
#define YMM_Q(n) _q[3 - (n)]
|
||||
#define YMM_D(n) _d[3 - (n)]
|
||||
|
||||
#define XMM_B(n) _b[15 - (n)]
|
||||
#define XMM_W(n) _w[7 - (n)]
|
||||
#define XMM_L(n) _l[3 - (n)]
|
||||
#define XMM_S(n) _s[3 - (n)]
|
||||
#define XMM_Q(n) _q[1 - (n)]
|
||||
#define XMM_D(n) _d[1 - (n)]
|
||||
#define XMM_B(n) _b[63 - (n)]
|
||||
#define XMM_W(n) _w[31 - (n)]
|
||||
#define XMM_L(n) _l[15 - (n)]
|
||||
#define XMM_S(n) _s[15 - (n)]
|
||||
#define XMM_Q(n) _q[7 - (n)]
|
||||
#define XMM_D(n) _d[7 - (n)]
|
||||
|
||||
#define MMX_B(n) _b[7 - (n)]
|
||||
#define MMX_W(n) _w[3 - (n)]
|
||||
#define MMX_L(n) _l[1 - (n)]
|
||||
#define MMX_S(n) _s[1 - (n)]
|
||||
#else
|
||||
#define ZMM_B(n) _b[n]
|
||||
#define ZMM_W(n) _w[n]
|
||||
#define ZMM_L(n) _l[n]
|
||||
#define ZMM_S(n) _s[n]
|
||||
#define ZMM_Q(n) _q[n]
|
||||
#define ZMM_D(n) _d[n]
|
||||
|
||||
#define YMM_B(n) _b[n]
|
||||
#define YMM_W(n) _w[n]
|
||||
#define YMM_L(n) _l[n]
|
||||
#define YMM_S(n) _s[n]
|
||||
#define YMM_Q(n) _q[n]
|
||||
#define YMM_D(n) _d[n]
|
||||
|
||||
#define XMM_B(n) _b[n]
|
||||
#define XMM_W(n) _w[n]
|
||||
#define XMM_L(n) _l[n]
|
||||
@ -896,17 +850,11 @@ typedef struct CPUX86State {
|
||||
float_status mmx_status; /* for 3DNow! float ops */
|
||||
float_status sse_status;
|
||||
uint32_t mxcsr;
|
||||
XMMReg xmm_regs[CPU_NB_REGS];
|
||||
XMMReg xmm_regs[CPU_NB_REGS == 8 ? 8 : 32];
|
||||
XMMReg xmm_t0;
|
||||
MMXReg mmx_t0;
|
||||
|
||||
XMMReg ymmh_regs[CPU_NB_REGS];
|
||||
|
||||
uint64_t opmask_regs[NB_OPMASK_REGS];
|
||||
YMMReg zmmh_regs[CPU_NB_REGS];
|
||||
#ifdef TARGET_X86_64
|
||||
ZMMReg hi16_zmm_regs[CPU_NB_REGS];
|
||||
#endif
|
||||
|
||||
/* sysenter registers */
|
||||
uint32_t sysenter_cs;
|
||||
|
@ -1048,7 +1048,7 @@ static int kvm_put_xsave(X86CPU *cpu)
|
||||
CPUX86State *env = &cpu->env;
|
||||
struct kvm_xsave* xsave = env->kvm_xsave_buf;
|
||||
uint16_t cwd, swd, twd;
|
||||
uint8_t *xmm;
|
||||
uint8_t *xmm, *ymmh, *zmmh;
|
||||
int i, r;
|
||||
|
||||
if (!kvm_has_xsave()) {
|
||||
@ -1071,26 +1071,30 @@ static int kvm_put_xsave(X86CPU *cpu)
|
||||
sizeof env->fpregs);
|
||||
xsave->region[XSAVE_MXCSR] = env->mxcsr;
|
||||
*(uint64_t *)&xsave->region[XSAVE_XSTATE_BV] = env->xstate_bv;
|
||||
memcpy(&xsave->region[XSAVE_YMMH_SPACE], env->ymmh_regs,
|
||||
sizeof env->ymmh_regs);
|
||||
memcpy(&xsave->region[XSAVE_BNDREGS], env->bnd_regs,
|
||||
sizeof env->bnd_regs);
|
||||
memcpy(&xsave->region[XSAVE_BNDCSR], &env->bndcs_regs,
|
||||
sizeof(env->bndcs_regs));
|
||||
memcpy(&xsave->region[XSAVE_OPMASK], env->opmask_regs,
|
||||
sizeof env->opmask_regs);
|
||||
memcpy(&xsave->region[XSAVE_ZMM_Hi256], env->zmmh_regs,
|
||||
sizeof env->zmmh_regs);
|
||||
|
||||
xmm = (uint8_t *)&xsave->region[XSAVE_XMM_SPACE];
|
||||
for (i = 0; i < CPU_NB_REGS; i++, xmm += 16) {
|
||||
ymmh = (uint8_t *)&xsave->region[XSAVE_YMMH_SPACE];
|
||||
zmmh = (uint8_t *)&xsave->region[XSAVE_ZMM_Hi256];
|
||||
for (i = 0; i < CPU_NB_REGS; i++, xmm += 16, ymmh += 16, zmmh += 32) {
|
||||
stq_p(xmm, env->xmm_regs[i].XMM_Q(0));
|
||||
stq_p(xmm+8, env->xmm_regs[i].XMM_Q(1));
|
||||
stq_p(ymmh, env->xmm_regs[i].XMM_Q(2));
|
||||
stq_p(ymmh+8, env->xmm_regs[i].XMM_Q(3));
|
||||
stq_p(zmmh, env->xmm_regs[i].XMM_Q(4));
|
||||
stq_p(zmmh+8, env->xmm_regs[i].XMM_Q(5));
|
||||
stq_p(zmmh+16, env->xmm_regs[i].XMM_Q(6));
|
||||
stq_p(zmmh+24, env->xmm_regs[i].XMM_Q(7));
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
memcpy(&xsave->region[XSAVE_Hi16_ZMM], env->hi16_zmm_regs,
|
||||
sizeof env->hi16_zmm_regs);
|
||||
memcpy(&xsave->region[XSAVE_Hi16_ZMM], &env->xmm_regs[16],
|
||||
16 * sizeof env->xmm_regs[16]);
|
||||
#endif
|
||||
r = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_XSAVE, xsave);
|
||||
return r;
|
||||
@ -1407,7 +1411,7 @@ static int kvm_get_xsave(X86CPU *cpu)
|
||||
CPUX86State *env = &cpu->env;
|
||||
struct kvm_xsave* xsave = env->kvm_xsave_buf;
|
||||
int ret, i;
|
||||
const uint8_t *xmm;
|
||||
const uint8_t *xmm, *ymmh, *zmmh;
|
||||
uint16_t cwd, swd, twd;
|
||||
|
||||
if (!kvm_has_xsave()) {
|
||||
@ -1435,26 +1439,30 @@ static int kvm_get_xsave(X86CPU *cpu)
|
||||
memcpy(env->fpregs, &xsave->region[XSAVE_ST_SPACE],
|
||||
sizeof env->fpregs);
|
||||
env->xstate_bv = *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV];
|
||||
memcpy(env->ymmh_regs, &xsave->region[XSAVE_YMMH_SPACE],
|
||||
sizeof env->ymmh_regs);
|
||||
memcpy(env->bnd_regs, &xsave->region[XSAVE_BNDREGS],
|
||||
sizeof env->bnd_regs);
|
||||
memcpy(&env->bndcs_regs, &xsave->region[XSAVE_BNDCSR],
|
||||
sizeof(env->bndcs_regs));
|
||||
memcpy(env->opmask_regs, &xsave->region[XSAVE_OPMASK],
|
||||
sizeof env->opmask_regs);
|
||||
memcpy(env->zmmh_regs, &xsave->region[XSAVE_ZMM_Hi256],
|
||||
sizeof env->zmmh_regs);
|
||||
|
||||
xmm = (const uint8_t *)&xsave->region[XSAVE_XMM_SPACE];
|
||||
for (i = 0; i < CPU_NB_REGS; i++, xmm += 16) {
|
||||
ymmh = (const uint8_t *)&xsave->region[XSAVE_YMMH_SPACE];
|
||||
zmmh = (const uint8_t *)&xsave->region[XSAVE_ZMM_Hi256];
|
||||
for (i = 0; i < CPU_NB_REGS; i++, xmm += 16, ymmh += 16, zmmh += 32) {
|
||||
env->xmm_regs[i].XMM_Q(0) = ldq_p(xmm);
|
||||
env->xmm_regs[i].XMM_Q(1) = ldq_p(xmm+8);
|
||||
env->xmm_regs[i].XMM_Q(2) = ldq_p(ymmh);
|
||||
env->xmm_regs[i].XMM_Q(3) = ldq_p(ymmh+8);
|
||||
env->xmm_regs[i].XMM_Q(4) = ldq_p(zmmh);
|
||||
env->xmm_regs[i].XMM_Q(5) = ldq_p(zmmh+8);
|
||||
env->xmm_regs[i].XMM_Q(6) = ldq_p(zmmh+16);
|
||||
env->xmm_regs[i].XMM_Q(7) = ldq_p(zmmh+24);
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
memcpy(env->hi16_zmm_regs, &xsave->region[XSAVE_Hi16_ZMM],
|
||||
sizeof env->hi16_zmm_regs);
|
||||
memcpy(&env->xmm_regs[16], &xsave->region[XSAVE_Hi16_ZMM],
|
||||
16 * sizeof env->xmm_regs[16]);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -42,39 +42,42 @@ static const VMStateDescription vmstate_xmm_reg = {
|
||||
}
|
||||
};
|
||||
|
||||
#define VMSTATE_XMM_REGS(_field, _state, _n) \
|
||||
VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_xmm_reg, XMMReg)
|
||||
#define VMSTATE_XMM_REGS(_field, _state, _start) \
|
||||
VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, 0, \
|
||||
vmstate_xmm_reg, XMMReg)
|
||||
|
||||
/* YMMH format is the same as XMM */
|
||||
/* YMMH format is the same as XMM, but for bits 128-255 */
|
||||
static const VMStateDescription vmstate_ymmh_reg = {
|
||||
.name = "ymmh_reg",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(XMM_Q(0), XMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(1), XMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(2), XMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(3), XMMReg),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
#define VMSTATE_YMMH_REGS_VARS(_field, _state, _n, _v) \
|
||||
VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_ymmh_reg, XMMReg)
|
||||
#define VMSTATE_YMMH_REGS_VARS(_field, _state, _start, _v) \
|
||||
VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, _v, \
|
||||
vmstate_ymmh_reg, XMMReg)
|
||||
|
||||
static const VMStateDescription vmstate_zmmh_reg = {
|
||||
.name = "zmmh_reg",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(YMM_Q(0), YMMReg),
|
||||
VMSTATE_UINT64(YMM_Q(1), YMMReg),
|
||||
VMSTATE_UINT64(YMM_Q(2), YMMReg),
|
||||
VMSTATE_UINT64(YMM_Q(3), YMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(4), XMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(5), XMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(6), XMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(7), XMMReg),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
#define VMSTATE_ZMMH_REGS_VARS(_field, _state, _n) \
|
||||
VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_zmmh_reg, YMMReg)
|
||||
#define VMSTATE_ZMMH_REGS_VARS(_field, _state, _start) \
|
||||
VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, 0, \
|
||||
vmstate_zmmh_reg, XMMReg)
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
static const VMStateDescription vmstate_hi16_zmm_reg = {
|
||||
@ -82,20 +85,21 @@ static const VMStateDescription vmstate_hi16_zmm_reg = {
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(ZMM_Q(0), ZMMReg),
|
||||
VMSTATE_UINT64(ZMM_Q(1), ZMMReg),
|
||||
VMSTATE_UINT64(ZMM_Q(2), ZMMReg),
|
||||
VMSTATE_UINT64(ZMM_Q(3), ZMMReg),
|
||||
VMSTATE_UINT64(ZMM_Q(4), ZMMReg),
|
||||
VMSTATE_UINT64(ZMM_Q(5), ZMMReg),
|
||||
VMSTATE_UINT64(ZMM_Q(6), ZMMReg),
|
||||
VMSTATE_UINT64(ZMM_Q(7), ZMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(0), XMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(1), XMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(2), XMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(3), XMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(4), XMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(5), XMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(6), XMMReg),
|
||||
VMSTATE_UINT64(XMM_Q(7), XMMReg),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
#define VMSTATE_Hi16_ZMM_REGS_VARS(_field, _state, _n) \
|
||||
VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_hi16_zmm_reg, ZMMReg)
|
||||
#define VMSTATE_Hi16_ZMM_REGS_VARS(_field, _state, _start) \
|
||||
VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, CPU_NB_REGS, 0, \
|
||||
vmstate_hi16_zmm_reg, XMMReg)
|
||||
#endif
|
||||
|
||||
static const VMStateDescription vmstate_bnd_regs = {
|
||||
@ -654,17 +658,16 @@ static bool avx512_needed(void *opaque)
|
||||
}
|
||||
|
||||
for (i = 0; i < CPU_NB_REGS; i++) {
|
||||
#define ENV_ZMMH(reg, field) (env->zmmh_regs[reg].YMM_Q(field))
|
||||
if (ENV_ZMMH(i, 0) || ENV_ZMMH(i, 1) ||
|
||||
ENV_ZMMH(i, 2) || ENV_ZMMH(i, 3)) {
|
||||
#define ENV_XMM(reg, field) (env->xmm_regs[reg].XMM_Q(field))
|
||||
if (ENV_XMM(i, 4) || ENV_XMM(i, 6) ||
|
||||
ENV_XMM(i, 5) || ENV_XMM(i, 7)) {
|
||||
return true;
|
||||
}
|
||||
#ifdef TARGET_X86_64
|
||||
#define ENV_Hi16_ZMM(reg, field) (env->hi16_zmm_regs[reg].ZMM_Q(field))
|
||||
if (ENV_Hi16_ZMM(i, 0) || ENV_Hi16_ZMM(i, 1) ||
|
||||
ENV_Hi16_ZMM(i, 2) || ENV_Hi16_ZMM(i, 3) ||
|
||||
ENV_Hi16_ZMM(i, 4) || ENV_Hi16_ZMM(i, 5) ||
|
||||
ENV_Hi16_ZMM(i, 6) || ENV_Hi16_ZMM(i, 7)) {
|
||||
if (ENV_XMM(i+16, 0) || ENV_XMM(i+16, 1) ||
|
||||
ENV_XMM(i+16, 2) || ENV_XMM(i+16, 3) ||
|
||||
ENV_XMM(i+16, 4) || ENV_XMM(i+16, 5) ||
|
||||
ENV_XMM(i+16, 6) || ENV_XMM(i+16, 7)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@ -679,9 +682,9 @@ static const VMStateDescription vmstate_avx512 = {
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64_ARRAY(env.opmask_regs, X86CPU, NB_OPMASK_REGS),
|
||||
VMSTATE_ZMMH_REGS_VARS(env.zmmh_regs, X86CPU, CPU_NB_REGS),
|
||||
VMSTATE_ZMMH_REGS_VARS(env.xmm_regs, X86CPU, 0),
|
||||
#ifdef TARGET_X86_64
|
||||
VMSTATE_Hi16_ZMM_REGS_VARS(env.hi16_zmm_regs, X86CPU, CPU_NB_REGS),
|
||||
VMSTATE_Hi16_ZMM_REGS_VARS(env.xmm_regs, X86CPU, 16),
|
||||
#endif
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
@ -750,7 +753,7 @@ VMStateDescription vmstate_x86_cpu = {
|
||||
VMSTATE_INT32(env.a20_mask, X86CPU),
|
||||
/* XMM */
|
||||
VMSTATE_UINT32(env.mxcsr, X86CPU),
|
||||
VMSTATE_XMM_REGS(env.xmm_regs, X86CPU, CPU_NB_REGS),
|
||||
VMSTATE_XMM_REGS(env.xmm_regs, X86CPU, 0),
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
VMSTATE_UINT64(env.efer, X86CPU),
|
||||
@ -803,7 +806,7 @@ VMStateDescription vmstate_x86_cpu = {
|
||||
/* XSAVE related fields */
|
||||
VMSTATE_UINT64_V(env.xcr0, X86CPU, 12),
|
||||
VMSTATE_UINT64_V(env.xstate_bv, X86CPU, 12),
|
||||
VMSTATE_YMMH_REGS_VARS(env.ymmh_regs, X86CPU, CPU_NB_REGS, 12),
|
||||
VMSTATE_YMMH_REGS_VARS(env.xmm_regs, X86CPU, 0, 12),
|
||||
VMSTATE_END_OF_LIST()
|
||||
/* The above list is not sorted /wrt version numbers, watch out! */
|
||||
},
|
||||
|
@ -6,11 +6,14 @@ LD=ld
|
||||
LDFLAGS=-melf_i386 -T link.ld
|
||||
LIBS=$(shell $(CC) $(CCFLAGS) -print-libgcc-file-name)
|
||||
|
||||
all: mmap.elf
|
||||
all: mmap.elf modules.elf
|
||||
|
||||
mmap.elf: start.o mmap.o libc.o
|
||||
$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
modules.elf: start.o modules.o libc.o
|
||||
$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CCFLAGS) -c -o $@ $^
|
||||
|
||||
|
@ -22,6 +22,18 @@
|
||||
|
||||
#include "libc.h"
|
||||
|
||||
void* memcpy(void *dest, const void *src, int n)
|
||||
{
|
||||
char *d = dest;
|
||||
const char *s = src;
|
||||
|
||||
while (n--) {
|
||||
*d++ = *s++;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
static void print_char(char c)
|
||||
{
|
||||
outb(0xe9, c);
|
||||
|
@ -57,5 +57,6 @@ static inline void outb(uint16_t port, uint8_t data)
|
||||
/* Misc functions */
|
||||
|
||||
void printf(const char *fmt, ...);
|
||||
void* memcpy(void *dest, const void *src, int n);
|
||||
|
||||
#endif
|
||||
|
@ -4,14 +4,14 @@
|
||||
=== Running test case: mmap.elf ===
|
||||
|
||||
Lower memory: 639k
|
||||
Upper memory: 130040k
|
||||
Upper memory: 129920k
|
||||
|
||||
e820 memory map:
|
||||
0x0 - 0x9fc00: type 1 [entry size: 20]
|
||||
0x9fc00 - 0xa0000: type 2 [entry size: 20]
|
||||
0xf0000 - 0x100000: type 2 [entry size: 20]
|
||||
0x100000 - 0x7ffe000: type 1 [entry size: 20]
|
||||
0x7ffe000 - 0x8000000: type 2 [entry size: 20]
|
||||
0x100000 - 0x7fe0000: type 1 [entry size: 20]
|
||||
0x7fe0000 - 0x8000000: type 2 [entry size: 20]
|
||||
0xfffc0000 - 0x100000000: type 2 [entry size: 20]
|
||||
|
||||
mmap start: 0x9000
|
||||
@ -22,32 +22,31 @@ real mmap end: 0x9090
|
||||
=== Running test case: mmap.elf -m 1.1M ===
|
||||
|
||||
Lower memory: 639k
|
||||
Upper memory: 96k
|
||||
Upper memory: 104k
|
||||
|
||||
e820 memory map:
|
||||
0x0 - 0x9fc00: type 1 [entry size: 20]
|
||||
0x9fc00 - 0xa0000: type 2 [entry size: 20]
|
||||
0xf0000 - 0x100000: type 2 [entry size: 20]
|
||||
0x100000 - 0x118000: type 1 [entry size: 20]
|
||||
0x118000 - 0x11a000: type 2 [entry size: 20]
|
||||
0x100000 - 0x11a000: type 1 [entry size: 20]
|
||||
0xfffc0000 - 0x100000000: type 2 [entry size: 20]
|
||||
|
||||
mmap start: 0x9000
|
||||
mmap end: 0x9090
|
||||
real mmap end: 0x9090
|
||||
mmap end: 0x9078
|
||||
real mmap end: 0x9078
|
||||
|
||||
|
||||
=== Running test case: mmap.elf -m 2G ===
|
||||
|
||||
Lower memory: 639k
|
||||
Upper memory: 2096120k
|
||||
Upper memory: 2096000k
|
||||
|
||||
e820 memory map:
|
||||
0x0 - 0x9fc00: type 1 [entry size: 20]
|
||||
0x9fc00 - 0xa0000: type 2 [entry size: 20]
|
||||
0xf0000 - 0x100000: type 2 [entry size: 20]
|
||||
0x100000 - 0x7fffe000: type 1 [entry size: 20]
|
||||
0x7fffe000 - 0x80000000: type 2 [entry size: 20]
|
||||
0x100000 - 0x7ffe0000: type 1 [entry size: 20]
|
||||
0x7ffe0000 - 0x80000000: type 2 [entry size: 20]
|
||||
0xfffc0000 - 0x100000000: type 2 [entry size: 20]
|
||||
|
||||
mmap start: 0x9000
|
||||
@ -58,16 +57,16 @@ real mmap end: 0x9090
|
||||
=== Running test case: mmap.elf -m 4G ===
|
||||
|
||||
Lower memory: 639k
|
||||
Upper memory: 3668984k
|
||||
Upper memory: 3144576k
|
||||
|
||||
e820 memory map:
|
||||
0x0 - 0x9fc00: type 1 [entry size: 20]
|
||||
0x9fc00 - 0xa0000: type 2 [entry size: 20]
|
||||
0xf0000 - 0x100000: type 2 [entry size: 20]
|
||||
0x100000 - 0xdfffe000: type 1 [entry size: 20]
|
||||
0xdfffe000 - 0xe0000000: type 2 [entry size: 20]
|
||||
0x100000 - 0xbffe0000: type 1 [entry size: 20]
|
||||
0xbffe0000 - 0xc0000000: type 2 [entry size: 20]
|
||||
0xfffc0000 - 0x100000000: type 2 [entry size: 20]
|
||||
0x100000000 - 0x120000000: type 1 [entry size: 20]
|
||||
0x100000000 - 0x140000000: type 1 [entry size: 20]
|
||||
|
||||
mmap start: 0x9000
|
||||
mmap end: 0x90a8
|
||||
@ -77,16 +76,16 @@ real mmap end: 0x90a8
|
||||
=== Running test case: mmap.elf -m 8G ===
|
||||
|
||||
Lower memory: 639k
|
||||
Upper memory: 3668984k
|
||||
Upper memory: 3144576k
|
||||
|
||||
e820 memory map:
|
||||
0x0 - 0x9fc00: type 1 [entry size: 20]
|
||||
0x9fc00 - 0xa0000: type 2 [entry size: 20]
|
||||
0xf0000 - 0x100000: type 2 [entry size: 20]
|
||||
0x100000 - 0xdfffe000: type 1 [entry size: 20]
|
||||
0xdfffe000 - 0xe0000000: type 2 [entry size: 20]
|
||||
0x100000 - 0xbffe0000: type 1 [entry size: 20]
|
||||
0xbffe0000 - 0xc0000000: type 2 [entry size: 20]
|
||||
0xfffc0000 - 0x100000000: type 2 [entry size: 20]
|
||||
0x100000000 - 0x220000000: type 1 [entry size: 20]
|
||||
0x100000000 - 0x240000000: type 1 [entry size: 20]
|
||||
|
||||
mmap start: 0x9000
|
||||
mmap end: 0x90a8
|
||||
|
1
tests/multiboot/module.txt
Normal file
1
tests/multiboot/module.txt
Normal file
@ -0,0 +1 @@
|
||||
This is a test file that is used as a multiboot module.
|
55
tests/multiboot/modules.c
Normal file
55
tests/multiboot/modules.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Kevin Wolf <kwolf@redhat.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "libc.h"
|
||||
#include "multiboot.h"
|
||||
|
||||
int test_main(uint32_t magic, struct mb_info *mbi)
|
||||
{
|
||||
struct mb_module *mod;
|
||||
unsigned int i;
|
||||
|
||||
(void) magic;
|
||||
|
||||
printf("Module list with %d entries at %x\n",
|
||||
mbi->mods_count, mbi->mods_addr);
|
||||
|
||||
for (i = 0, mod = (struct mb_module*) mbi->mods_addr;
|
||||
i < mbi->mods_count;
|
||||
i++, mod++)
|
||||
{
|
||||
char buf[1024];
|
||||
unsigned int size = mod->mod_end - mod->mod_start;
|
||||
|
||||
printf("[%p] Module: %x - %x (%d bytes) '%s'\n",
|
||||
mod, mod->mod_start, mod->mod_end, size, mod->string);
|
||||
|
||||
/* Print test file, but remove the newline at the end */
|
||||
if (size < sizeof(buf)) {
|
||||
memcpy(buf, (void*) mod->mod_start, size);
|
||||
buf[size - 1] = '\0';
|
||||
printf(" Content: '%s'\n", buf);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
38
tests/multiboot/modules.out
Normal file
38
tests/multiboot/modules.out
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
|
||||
|
||||
=== Running test case: modules.elf ===
|
||||
|
||||
Module list with 0 entries at 102000
|
||||
|
||||
|
||||
=== Running test case: modules.elf -initrd module.txt ===
|
||||
|
||||
Module list with 1 entries at 102000
|
||||
[102000] Module: 103000 - 103038 (56 bytes) 'module.txt'
|
||||
Content: 'This is a test file that is used as a multiboot module.'
|
||||
|
||||
|
||||
=== Running test case: modules.elf -initrd module.txt argument ===
|
||||
|
||||
Module list with 1 entries at 102000
|
||||
[102000] Module: 103000 - 103038 (56 bytes) 'module.txt argument'
|
||||
Content: 'This is a test file that is used as a multiboot module.'
|
||||
|
||||
|
||||
=== Running test case: modules.elf -initrd module.txt argument,,with,,commas ===
|
||||
|
||||
Module list with 1 entries at 102000
|
||||
[102000] Module: 103000 - 103038 (56 bytes) 'module.txt argument,with,commas'
|
||||
Content: 'This is a test file that is used as a multiboot module.'
|
||||
|
||||
|
||||
=== Running test case: modules.elf -initrd module.txt,module.txt argument,module.txt ===
|
||||
|
||||
Module list with 3 entries at 102000
|
||||
[102000] Module: 103000 - 103038 (56 bytes) 'module.txt'
|
||||
Content: 'This is a test file that is used as a multiboot module.'
|
||||
[102010] Module: 104000 - 104038 (56 bytes) 'module.txt argument'
|
||||
Content: 'This is a test file that is used as a multiboot module.'
|
||||
[102020] Module: 105000 - 105038 (56 bytes) 'module.txt'
|
||||
Content: 'This is a test file that is used as a multiboot module.'
|
@ -48,10 +48,17 @@ mmap() {
|
||||
run_qemu mmap.elf -m 8G
|
||||
}
|
||||
|
||||
modules() {
|
||||
run_qemu modules.elf
|
||||
run_qemu modules.elf -initrd module.txt
|
||||
run_qemu modules.elf -initrd "module.txt argument"
|
||||
run_qemu modules.elf -initrd "module.txt argument,,with,,commas"
|
||||
run_qemu modules.elf -initrd "module.txt,module.txt argument,module.txt"
|
||||
}
|
||||
|
||||
make all
|
||||
|
||||
for t in mmap; do
|
||||
for t in mmap modules; do
|
||||
|
||||
echo > test.log
|
||||
$t
|
||||
|
Loading…
Reference in New Issue
Block a user