mirror of https://github.com/xemu-project/xemu.git
target-arm queue:
* hw/dma/xlnx-zdma, xlnx_csu_dma: Require 'dma' link property to be set * hw/arm/Kconfig: no need to enable ACPI_MEMORY_HOTPLUG/ACPI_NVDIMM explicitly * target/arm/cpu: Introduce sve_vq_supported bitmap * docs/specs: Convert ACPI spec docs to rST * arch_init: Clean up and refactoring * hw/core/loader: In gunzip(), check index is in range before use, not after * softmmu/physmem.c: Remove unneeded NULL check in qemu_ram_alloc_from_fd() * softmmu/physmem.c: Check return value from realpath() * Zero-initialize sockaddr_in structs * raspi: Use error_fatal for SoC realize errors, not error_abort * target/arm: Avoid assertion trying to use KVM and multiple ASes * target/arm: Implement HSTR.TTEE * target/arm: Implement HSTR.TJDBX * target/arm: Do hflags rebuild in cpsr_write() * hw/arm/xlnx-versal, xlnx-zynqmp: Add unimplemented APU mmio -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmEnyRIZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3v97EACBt9tRBw9I6FOIT61FJKr6 ZTaknJBT2rU7Yg9mTlQa+q/pZjVVtduD9oe7OxGNoCQCF6Bne435IayAXgPdrQtz GEiBrJ8ZSk8KmrbL/SJJra93OMrer3Y7kGwgFEQ5KmezCT70jzY9t+ysQYRGykMd sA10A76CDR3dl7/rYBCoSBXW7o5GNC2C/5MC+ikFJchQMrkd85eGgKOlZvf+zsDC uky+DmDOjv+LHbcky7Xd8Ln0CikgaSLbKBIdFmpemAIQ9KB6yQ2b0KOAIQWGyPbk LDphcUHlnoShhh3BspkX/kvm9rF/GzosnsyH6XfaH8fOCyr+zAdpN6+M96CpP7mw y5EOZxHk50XI2oC6wAnKrUFQd0CKW+fyHeUXtvIzA7y/JVkud1KOmmTNvNYu1ekK GHZCEPXj6bEVcp/Vk1rwdQPOueF2HloYKVs8cV7rrzb2r7JitR+exPvzyYmuifS5 nUZOWT46662vtTaFikJBIeX6x+sqlKAfi1uEcMJ/tSVtsjIyqcFGqjcBKTEyBW93 GX+bk4e6v+UuC9ch03u9VSE6TTA9wEFPladuhFdbKtvpj2qzkVmNtrdfVPO/Wl78 O22rs6hCgl702OkrFDemFK2De0rfsHKxGo3114uL7CHClYbMMN3jUywZEkLGH/jV VabgHZaNkh3WYfQG1AbZ/w== =bYAy -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210826' into staging target-arm queue: * hw/dma/xlnx-zdma, xlnx_csu_dma: Require 'dma' link property to be set * hw/arm/Kconfig: no need to enable ACPI_MEMORY_HOTPLUG/ACPI_NVDIMM explicitly * target/arm/cpu: Introduce sve_vq_supported bitmap * docs/specs: Convert ACPI spec docs to rST * arch_init: Clean up and refactoring * hw/core/loader: In gunzip(), check index is in range before use, not after * softmmu/physmem.c: Remove unneeded NULL check in qemu_ram_alloc_from_fd() * softmmu/physmem.c: Check return value from realpath() * Zero-initialize sockaddr_in structs * raspi: Use error_fatal for SoC realize errors, not error_abort * target/arm: Avoid assertion trying to use KVM and multiple ASes * target/arm: Implement HSTR.TTEE * target/arm: Implement HSTR.TJDBX * target/arm: Do hflags rebuild in cpsr_write() * hw/arm/xlnx-versal, xlnx-zynqmp: Add unimplemented APU mmio # gpg: Signature made Thu 26 Aug 2021 18:02:10 BST # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20210826: (37 commits) hw/arm/xlnx-zynqmp: Add unimplemented APU mmio hw/arm/xlnx-versal: Add unimplemented APU mmio target/arm: Do hflags rebuild in cpsr_write() target/arm: Implement HSTR.TJDBX target/arm: Implement HSTR.TTEE hw/arm/virt: Delete EL3 error checksnow provided in CPU realize target/arm: Avoid assertion trying to use KVM and multiple ASes raspi: Use error_fatal for SoC realize errors, not error_abort tests/tcg/multiarch/linux-test: Zero-initialize sockaddr structs tests/qtest/ipmi-bt-test: Zero-initialize sockaddr struct gdbstub: Zero-initialize sockaddr structs net: Zero sockaddr_in in parse_host_port() softmmu/physmem.c: Check return value from realpath() softmmu/physmem.c: Remove unneeded NULL check in qemu_ram_alloc_from_fd() hw/core/loader: In gunzip(), check index is in range before use, not after stubs: Remove unused arch_type.c stub arch_init.h: Don't include arch_init.h unnecessarily arch_init.h: Move QEMU_ARCH_VIRTIO_* to qdev-monitor.c arch_init.h: Add QEMU_ARCH_HEXAGON meson.build: Define QEMU_ARCH in config-target.h ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
f214d8e015
|
@ -1751,6 +1751,10 @@ F: qapi/acpi.json
|
|||
F: tests/qtest/bios-tables-test*
|
||||
F: tests/qtest/acpi-utils.[hc]
|
||||
F: tests/data/acpi/
|
||||
F: docs/specs/acpi_cpu_hotplug.rst
|
||||
F: docs/specs/acpi_mem_hotplug.rst
|
||||
F: docs/specs/acpi_pci_hotplug.rst
|
||||
F: docs/specs/acpi_hw_reduced_hotplug.rst
|
||||
|
||||
ACPI/HEST/GHES
|
||||
R: Dongjiu Geng <gengdongjiu1@gmail.com>
|
||||
|
@ -2057,6 +2061,7 @@ F: hw/acpi/nvdimm.c
|
|||
F: hw/mem/nvdimm.c
|
||||
F: include/hw/mem/nvdimm.h
|
||||
F: docs/nvdimm.txt
|
||||
F: docs/specs/acpi_nvdimm.rst
|
||||
|
||||
e1000x
|
||||
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
|
||||
|
|
|
@ -56,7 +56,6 @@
|
|||
#include "sysemu/iothread.h"
|
||||
#include "block/block_int.h"
|
||||
#include "block/trace.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
QEMU<->ACPI BIOS CPU hotplug interface
|
||||
======================================
|
||||
|
||||
QEMU supports CPU hotplug via ACPI. This document
|
||||
describes the interface between QEMU and the ACPI BIOS.
|
||||
|
||||
ACPI BIOS GPE.2 handler is dedicated for notifying OS about CPU hot-add
|
||||
and hot-remove events.
|
||||
|
||||
|
||||
Legacy ACPI CPU hotplug interface registers
|
||||
-------------------------------------------
|
||||
|
||||
CPU present bitmap for:
|
||||
|
||||
- ICH9-LPC (IO port 0x0cd8-0xcf7, 1-byte access)
|
||||
- PIIX-PM (IO port 0xaf00-0xaf1f, 1-byte access)
|
||||
- One bit per CPU. Bit position reflects corresponding CPU APIC ID. Read-only.
|
||||
- The first DWORD in bitmap is used in write mode to switch from legacy
|
||||
to modern CPU hotplug interface, write 0 into it to do switch.
|
||||
|
||||
QEMU sets corresponding CPU bit on hot-add event and issues SCI
|
||||
with GPE.2 event set. CPU present map is read by ACPI BIOS GPE.2 handler
|
||||
to notify OS about CPU hot-add events. CPU hot-remove isn't supported.
|
||||
|
||||
|
||||
Modern ACPI CPU hotplug interface registers
|
||||
-------------------------------------------
|
||||
|
||||
Register block base address:
|
||||
|
||||
- ICH9-LPC IO port 0x0cd8
|
||||
- PIIX-PM IO port 0xaf00
|
||||
|
||||
Register block size:
|
||||
|
||||
- ACPI_CPU_HOTPLUG_REG_LEN = 12
|
||||
|
||||
All accesses to registers described below, imply little-endian byte order.
|
||||
|
||||
Reserved registers behavior:
|
||||
|
||||
- write accesses are ignored
|
||||
- read accesses return all bits set to 0.
|
||||
|
||||
The last stored value in 'CPU selector' must refer to a possible CPU, otherwise
|
||||
|
||||
- reads from any register return 0
|
||||
- writes to any other register are ignored until valid value is stored into it
|
||||
|
||||
On QEMU start, 'CPU selector' is initialized to a valid value, on reset it
|
||||
keeps the current value.
|
||||
|
||||
Read access behavior
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
offset [0x0-0x3]
|
||||
Command data 2: (DWORD access)
|
||||
|
||||
If value last stored in 'Command field' is:
|
||||
|
||||
0:
|
||||
reads as 0x0
|
||||
3:
|
||||
upper 32 bits of architecture specific CPU ID value
|
||||
other values:
|
||||
reserved
|
||||
|
||||
offset [0x4]
|
||||
CPU device status fields: (1 byte access)
|
||||
|
||||
bits:
|
||||
|
||||
0:
|
||||
Device is enabled and may be used by guest
|
||||
1:
|
||||
Device insert event, used to distinguish device for which
|
||||
no device check event to OSPM was issued.
|
||||
It's valid only when bit 0 is set.
|
||||
2:
|
||||
Device remove event, used to distinguish device for which
|
||||
no device eject request to OSPM was issued. Firmware must
|
||||
ignore this bit.
|
||||
3:
|
||||
reserved and should be ignored by OSPM
|
||||
4:
|
||||
if set to 1, OSPM requests firmware to perform device eject.
|
||||
5-7:
|
||||
reserved and should be ignored by OSPM
|
||||
|
||||
offset [0x5-0x7]
|
||||
reserved
|
||||
|
||||
offset [0x8]
|
||||
Command data: (DWORD access)
|
||||
|
||||
If value last stored in 'Command field' is one of:
|
||||
|
||||
0:
|
||||
contains 'CPU selector' value of a CPU with pending event[s]
|
||||
3:
|
||||
lower 32 bits of architecture specific CPU ID value
|
||||
(in x86 case: APIC ID)
|
||||
otherwise:
|
||||
contains 0
|
||||
|
||||
Write access behavior
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
offset [0x0-0x3]
|
||||
CPU selector: (DWORD access)
|
||||
|
||||
Selects active CPU device. All following accesses to other
|
||||
registers will read/store data from/to selected CPU.
|
||||
Valid values: [0 .. max_cpus)
|
||||
|
||||
offset [0x4]
|
||||
CPU device control fields: (1 byte access)
|
||||
|
||||
bits:
|
||||
|
||||
0:
|
||||
reserved, OSPM must clear it before writing to register.
|
||||
1:
|
||||
if set to 1 clears device insert event, set by OSPM
|
||||
after it has emitted device check event for the
|
||||
selected CPU device
|
||||
2:
|
||||
if set to 1 clears device remove event, set by OSPM
|
||||
after it has emitted device eject request for the
|
||||
selected CPU device.
|
||||
3:
|
||||
if set to 1 initiates device eject, set by OSPM when it
|
||||
triggers CPU device removal and calls _EJ0 method or by firmware
|
||||
when bit #4 is set. In case bit #4 were set, it's cleared as
|
||||
part of device eject.
|
||||
4:
|
||||
if set to 1, OSPM hands over device eject to firmware.
|
||||
Firmware shall issue device eject request as described above
|
||||
(bit #3) and OSPM should not touch device eject bit (#3) in case
|
||||
it's asked firmware to perform CPU device eject.
|
||||
5-7:
|
||||
reserved, OSPM must clear them before writing to register
|
||||
|
||||
offset[0x5]
|
||||
Command field: (1 byte access)
|
||||
|
||||
value:
|
||||
|
||||
0:
|
||||
selects a CPU device with inserting/removing events and
|
||||
following reads from 'Command data' register return
|
||||
selected CPU ('CPU selector' value).
|
||||
If no CPU with events found, the current 'CPU selector' doesn't
|
||||
change and corresponding insert/remove event flags are not modified.
|
||||
|
||||
1:
|
||||
following writes to 'Command data' register set OST event
|
||||
register in QEMU
|
||||
2:
|
||||
following writes to 'Command data' register set OST status
|
||||
register in QEMU
|
||||
3:
|
||||
following reads from 'Command data' and 'Command data 2' return
|
||||
architecture specific CPU ID value for currently selected CPU.
|
||||
other values:
|
||||
reserved
|
||||
|
||||
offset [0x6-0x7]
|
||||
reserved
|
||||
|
||||
offset [0x8]
|
||||
Command data: (DWORD access)
|
||||
|
||||
If last stored 'Command field' value is:
|
||||
|
||||
1:
|
||||
stores value into OST event register
|
||||
2:
|
||||
stores value into OST status register, triggers
|
||||
ACPI_DEVICE_OST QMP event from QEMU to external applications
|
||||
with current values of OST event and status registers.
|
||||
other values:
|
||||
reserved
|
||||
|
||||
Typical usecases
|
||||
----------------
|
||||
|
||||
(x86) Detecting and enabling modern CPU hotplug interface
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
QEMU starts with legacy CPU hotplug interface enabled. Detecting and
|
||||
switching to modern interface is based on the 2 legacy CPU hotplug features:
|
||||
|
||||
#. Writes into CPU bitmap are ignored.
|
||||
#. CPU bitmap always has bit #0 set, corresponding to boot CPU.
|
||||
|
||||
Use following steps to detect and enable modern CPU hotplug interface:
|
||||
|
||||
#. Store 0x0 to the 'CPU selector' register, attempting to switch to modern mode
|
||||
#. Store 0x0 to the 'CPU selector' register, to ensure valid selector value
|
||||
#. Store 0x0 to the 'Command field' register
|
||||
#. Read the 'Command data 2' register.
|
||||
If read value is 0x0, the modern interface is enabled.
|
||||
Otherwise legacy or no CPU hotplug interface available
|
||||
|
||||
Get a cpu with pending event
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
#. Store 0x0 to the 'CPU selector' register.
|
||||
#. Store 0x0 to the 'Command field' register.
|
||||
#. Read the 'CPU device status fields' register.
|
||||
#. If both bit #1 and bit #2 are clear in the value read, there is no CPU
|
||||
with a pending event and selected CPU remains unchanged.
|
||||
#. Otherwise, read the 'Command data' register. The value read is the
|
||||
selector of the CPU with the pending event (which is already selected).
|
||||
|
||||
Enumerate CPUs present/non present CPUs
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
#. Set the present CPU count to 0.
|
||||
#. Set the iterator to 0.
|
||||
#. Store 0x0 to the 'CPU selector' register, to ensure that it's in
|
||||
a valid state and that access to other registers won't be ignored.
|
||||
#. Store 0x0 to the 'Command field' register to make 'Command data'
|
||||
register return 'CPU selector' value of selected CPU
|
||||
#. Read the 'CPU device status fields' register.
|
||||
#. If bit #0 is set, increment the present CPU count.
|
||||
#. Increment the iterator.
|
||||
#. Store the iterator to the 'CPU selector' register.
|
||||
#. Read the 'Command data' register.
|
||||
#. If the value read is not zero, goto 05.
|
||||
#. Otherwise store 0x0 to the 'CPU selector' register, to put it
|
||||
into a valid state and exit.
|
||||
The iterator at this point equals "max_cpus".
|
|
@ -1,160 +0,0 @@
|
|||
QEMU<->ACPI BIOS CPU hotplug interface
|
||||
--------------------------------------
|
||||
|
||||
QEMU supports CPU hotplug via ACPI. This document
|
||||
describes the interface between QEMU and the ACPI BIOS.
|
||||
|
||||
ACPI BIOS GPE.2 handler is dedicated for notifying OS about CPU hot-add
|
||||
and hot-remove events.
|
||||
|
||||
============================================
|
||||
Legacy ACPI CPU hotplug interface registers:
|
||||
--------------------------------------------
|
||||
CPU present bitmap for:
|
||||
ICH9-LPC (IO port 0x0cd8-0xcf7, 1-byte access)
|
||||
PIIX-PM (IO port 0xaf00-0xaf1f, 1-byte access)
|
||||
One bit per CPU. Bit position reflects corresponding CPU APIC ID. Read-only.
|
||||
The first DWORD in bitmap is used in write mode to switch from legacy
|
||||
to modern CPU hotplug interface, write 0 into it to do switch.
|
||||
---------------------------------------------------------------
|
||||
QEMU sets corresponding CPU bit on hot-add event and issues SCI
|
||||
with GPE.2 event set. CPU present map is read by ACPI BIOS GPE.2 handler
|
||||
to notify OS about CPU hot-add events. CPU hot-remove isn't supported.
|
||||
|
||||
=====================================
|
||||
Modern ACPI CPU hotplug interface registers:
|
||||
-------------------------------------
|
||||
Register block base address:
|
||||
ICH9-LPC IO port 0x0cd8
|
||||
PIIX-PM IO port 0xaf00
|
||||
Register block size:
|
||||
ACPI_CPU_HOTPLUG_REG_LEN = 12
|
||||
|
||||
All accesses to registers described below, imply little-endian byte order.
|
||||
|
||||
Reserved resisters behavior:
|
||||
- write accesses are ignored
|
||||
- read accesses return all bits set to 0.
|
||||
|
||||
The last stored value in 'CPU selector' must refer to a possible CPU, otherwise
|
||||
- reads from any register return 0
|
||||
- writes to any other register are ignored until valid value is stored into it
|
||||
On QEMU start, 'CPU selector' is initialized to a valid value, on reset it
|
||||
keeps the current value.
|
||||
|
||||
read access:
|
||||
offset:
|
||||
[0x0-0x3] Command data 2: (DWORD access)
|
||||
if value last stored in 'Command field':
|
||||
0: reads as 0x0
|
||||
3: upper 32 bits of architecture specific CPU ID value
|
||||
other values: reserved
|
||||
[0x4] CPU device status fields: (1 byte access)
|
||||
bits:
|
||||
0: Device is enabled and may be used by guest
|
||||
1: Device insert event, used to distinguish device for which
|
||||
no device check event to OSPM was issued.
|
||||
It's valid only when bit 0 is set.
|
||||
2: Device remove event, used to distinguish device for which
|
||||
no device eject request to OSPM was issued. Firmware must
|
||||
ignore this bit.
|
||||
3: reserved and should be ignored by OSPM
|
||||
4: if set to 1, OSPM requests firmware to perform device eject.
|
||||
5-7: reserved and should be ignored by OSPM
|
||||
[0x5-0x7] reserved
|
||||
[0x8] Command data: (DWORD access)
|
||||
contains 0 unless value last stored in 'Command field' is one of:
|
||||
0: contains 'CPU selector' value of a CPU with pending event[s]
|
||||
3: lower 32 bits of architecture specific CPU ID value
|
||||
(in x86 case: APIC ID)
|
||||
|
||||
write access:
|
||||
offset:
|
||||
[0x0-0x3] CPU selector: (DWORD access)
|
||||
selects active CPU device. All following accesses to other
|
||||
registers will read/store data from/to selected CPU.
|
||||
Valid values: [0 .. max_cpus)
|
||||
[0x4] CPU device control fields: (1 byte access)
|
||||
bits:
|
||||
0: reserved, OSPM must clear it before writing to register.
|
||||
1: if set to 1 clears device insert event, set by OSPM
|
||||
after it has emitted device check event for the
|
||||
selected CPU device
|
||||
2: if set to 1 clears device remove event, set by OSPM
|
||||
after it has emitted device eject request for the
|
||||
selected CPU device.
|
||||
3: if set to 1 initiates device eject, set by OSPM when it
|
||||
triggers CPU device removal and calls _EJ0 method or by firmware
|
||||
when bit #4 is set. In case bit #4 were set, it's cleared as
|
||||
part of device eject.
|
||||
4: if set to 1, OSPM hands over device eject to firmware.
|
||||
Firmware shall issue device eject request as described above
|
||||
(bit #3) and OSPM should not touch device eject bit (#3) in case
|
||||
it's asked firmware to perform CPU device eject.
|
||||
5-7: reserved, OSPM must clear them before writing to register
|
||||
[0x5] Command field: (1 byte access)
|
||||
value:
|
||||
0: selects a CPU device with inserting/removing events and
|
||||
following reads from 'Command data' register return
|
||||
selected CPU ('CPU selector' value).
|
||||
If no CPU with events found, the current 'CPU selector' doesn't
|
||||
change and corresponding insert/remove event flags are not modified.
|
||||
1: following writes to 'Command data' register set OST event
|
||||
register in QEMU
|
||||
2: following writes to 'Command data' register set OST status
|
||||
register in QEMU
|
||||
3: following reads from 'Command data' and 'Command data 2' return
|
||||
architecture specific CPU ID value for currently selected CPU.
|
||||
other values: reserved
|
||||
[0x6-0x7] reserved
|
||||
[0x8] Command data: (DWORD access)
|
||||
if last stored 'Command field' value:
|
||||
1: stores value into OST event register
|
||||
2: stores value into OST status register, triggers
|
||||
ACPI_DEVICE_OST QMP event from QEMU to external applications
|
||||
with current values of OST event and status registers.
|
||||
other values: reserved
|
||||
|
||||
Typical usecases:
|
||||
- (x86) Detecting and enabling modern CPU hotplug interface.
|
||||
QEMU starts with legacy CPU hotplug interface enabled. Detecting and
|
||||
switching to modern interface is based on the 2 legacy CPU hotplug features:
|
||||
1. Writes into CPU bitmap are ignored.
|
||||
2. CPU bitmap always has bit#0 set, corresponding to boot CPU.
|
||||
|
||||
Use following steps to detect and enable modern CPU hotplug interface:
|
||||
1. Store 0x0 to the 'CPU selector' register,
|
||||
attempting to switch to modern mode
|
||||
2. Store 0x0 to the 'CPU selector' register,
|
||||
to ensure valid selector value
|
||||
3. Store 0x0 to the 'Command field' register,
|
||||
4. Read the 'Command data 2' register.
|
||||
If read value is 0x0, the modern interface is enabled.
|
||||
Otherwise legacy or no CPU hotplug interface available
|
||||
|
||||
- Get a cpu with pending event
|
||||
1. Store 0x0 to the 'CPU selector' register.
|
||||
2. Store 0x0 to the 'Command field' register.
|
||||
3. Read the 'CPU device status fields' register.
|
||||
4. If both bit#1 and bit#2 are clear in the value read, there is no CPU
|
||||
with a pending event and selected CPU remains unchanged.
|
||||
5. Otherwise, read the 'Command data' register. The value read is the
|
||||
selector of the CPU with the pending event (which is already
|
||||
selected).
|
||||
|
||||
- Enumerate CPUs present/non present CPUs
|
||||
01. Set the present CPU count to 0.
|
||||
02. Set the iterator to 0.
|
||||
03. Store 0x0 to the 'CPU selector' register, to ensure that it's in
|
||||
a valid state and that access to other registers won't be ignored.
|
||||
04. Store 0x0 to the 'Command field' register to make 'Command data'
|
||||
register return 'CPU selector' value of selected CPU
|
||||
05. Read the 'CPU device status fields' register.
|
||||
06. If bit#0 is set, increment the present CPU count.
|
||||
07. Increment the iterator.
|
||||
08. Store the iterator to the 'CPU selector' register.
|
||||
09. Read the 'Command data' register.
|
||||
10. If the value read is not zero, goto 05.
|
||||
11. Otherwise store 0x0 to the 'CPU selector' register, to put it
|
||||
into a valid state and exit.
|
||||
The iterator at this point equals "max_cpus".
|
|
@ -0,0 +1,128 @@
|
|||
QEMU<->ACPI BIOS memory hotplug interface
|
||||
=========================================
|
||||
|
||||
ACPI BIOS GPE.3 handler is dedicated for notifying OS about memory hot-add
|
||||
and hot-remove events.
|
||||
|
||||
Memory hot-plug interface (IO port 0xa00-0xa17, 1-4 byte access)
|
||||
----------------------------------------------------------------
|
||||
|
||||
Read access behavior
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
[0x0-0x3]
|
||||
Lo part of memory device phys address
|
||||
[0x4-0x7]
|
||||
Hi part of memory device phys address
|
||||
[0x8-0xb]
|
||||
Lo part of memory device size in bytes
|
||||
[0xc-0xf]
|
||||
Hi part of memory device size in bytes
|
||||
[0x10-0x13]
|
||||
Memory device proximity domain
|
||||
[0x14]
|
||||
Memory device status fields
|
||||
|
||||
bits:
|
||||
|
||||
0:
|
||||
Device is enabled and may be used by guest
|
||||
1:
|
||||
Device insert event, used to distinguish device for which
|
||||
no device check event to OSPM was issued.
|
||||
It's valid only when bit 1 is set.
|
||||
2:
|
||||
Device remove event, used to distinguish device for which
|
||||
no device eject request to OSPM was issued.
|
||||
3-7:
|
||||
reserved and should be ignored by OSPM
|
||||
|
||||
[0x15-0x17]
|
||||
reserved
|
||||
|
||||
Write access behavior
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
[0x0-0x3]
|
||||
Memory device slot selector, selects active memory device.
|
||||
All following accesses to other registers in 0xa00-0xa17
|
||||
region will read/store data from/to selected memory device.
|
||||
[0x4-0x7]
|
||||
OST event code reported by OSPM
|
||||
[0x8-0xb]
|
||||
OST status code reported by OSPM
|
||||
[0xc-0x13]
|
||||
reserved, writes into it are ignored
|
||||
[0x14]
|
||||
Memory device control fields
|
||||
|
||||
bits:
|
||||
|
||||
0:
|
||||
reserved, OSPM must clear it before writing to register.
|
||||
Due to BUG in versions prior 2.4 that field isn't cleared
|
||||
when other fields are written. Keep it reserved and don't
|
||||
try to reuse it.
|
||||
1:
|
||||
if set to 1 clears device insert event, set by OSPM
|
||||
after it has emitted device check event for the
|
||||
selected memory device
|
||||
2:
|
||||
if set to 1 clears device remove event, set by OSPM
|
||||
after it has emitted device eject request for the
|
||||
selected memory device
|
||||
3:
|
||||
if set to 1 initiates device eject, set by OSPM when it
|
||||
triggers memory device removal and calls _EJ0 method
|
||||
4-7:
|
||||
reserved, OSPM must clear them before writing to register
|
||||
|
||||
Selecting memory device slot beyond present range has no effect on platform:
|
||||
|
||||
- write accesses to memory hot-plug registers not documented above are ignored
|
||||
- read accesses to memory hot-plug registers not documented above return
|
||||
all bits set to 1.
|
||||
|
||||
Memory hot remove process diagram
|
||||
---------------------------------
|
||||
|
||||
::
|
||||
|
||||
+-------------+ +-----------------------+ +------------------+
|
||||
| 1. QEMU | | 2. QEMU | |3. QEMU |
|
||||
| device_del +---->+ device unplug request +----->+Send SCI to guest,|
|
||||
| | | cb | |return control to |
|
||||
| | | | |management |
|
||||
+-------------+ +-----------------------+ +------------------+
|
||||
|
||||
+---------------------------------------------------------------------+
|
||||
|
||||
+---------------------+ +-------------------------+
|
||||
| OSPM: | remove event | OSPM: |
|
||||
| send Eject Request, | | Scan memory devices |
|
||||
| clear remove event +<-------------+ for event flags |
|
||||
| | | |
|
||||
+---------------------+ +-------------------------+
|
||||
|
|
||||
|
|
||||
+---------v--------+ +-----------------------+
|
||||
| Guest OS: | success | OSPM: |
|
||||
| process Ejection +----------->+ Execute _EJ0 method, |
|
||||
| request | | set eject bit in flags|
|
||||
+------------------+ +-----------------------+
|
||||
|failure |
|
||||
v v
|
||||
+------------------------+ +-----------------------+
|
||||
| OSPM: | | QEMU: |
|
||||
| set OST event & status | | call device unplug cb |
|
||||
| fields | | |
|
||||
+------------------------+ +-----------------------+
|
||||
| |
|
||||
v v
|
||||
+------------------+ +-------------------+
|
||||
|QEMU: | |QEMU: |
|
||||
|Send OST QMP event| |Send device deleted|
|
||||
| | |QMP event |
|
||||
+------------------+ | |
|
||||
+-------------------+
|
|
@ -1,94 +0,0 @@
|
|||
QEMU<->ACPI BIOS memory hotplug interface
|
||||
--------------------------------------
|
||||
|
||||
ACPI BIOS GPE.3 handler is dedicated for notifying OS about memory hot-add
|
||||
and hot-remove events.
|
||||
|
||||
Memory hot-plug interface (IO port 0xa00-0xa17, 1-4 byte access):
|
||||
---------------------------------------------------------------
|
||||
0xa00:
|
||||
read access:
|
||||
[0x0-0x3] Lo part of memory device phys address
|
||||
[0x4-0x7] Hi part of memory device phys address
|
||||
[0x8-0xb] Lo part of memory device size in bytes
|
||||
[0xc-0xf] Hi part of memory device size in bytes
|
||||
[0x10-0x13] Memory device proximity domain
|
||||
[0x14] Memory device status fields
|
||||
bits:
|
||||
0: Device is enabled and may be used by guest
|
||||
1: Device insert event, used to distinguish device for which
|
||||
no device check event to OSPM was issued.
|
||||
It's valid only when bit 1 is set.
|
||||
2: Device remove event, used to distinguish device for which
|
||||
no device eject request to OSPM was issued.
|
||||
3-7: reserved and should be ignored by OSPM
|
||||
[0x15-0x17] reserved
|
||||
|
||||
write access:
|
||||
[0x0-0x3] Memory device slot selector, selects active memory device.
|
||||
All following accesses to other registers in 0xa00-0xa17
|
||||
region will read/store data from/to selected memory device.
|
||||
[0x4-0x7] OST event code reported by OSPM
|
||||
[0x8-0xb] OST status code reported by OSPM
|
||||
[0xc-0x13] reserved, writes into it are ignored
|
||||
[0x14] Memory device control fields
|
||||
bits:
|
||||
0: reserved, OSPM must clear it before writing to register.
|
||||
Due to BUG in versions prior 2.4 that field isn't cleared
|
||||
when other fields are written. Keep it reserved and don't
|
||||
try to reuse it.
|
||||
1: if set to 1 clears device insert event, set by OSPM
|
||||
after it has emitted device check event for the
|
||||
selected memory device
|
||||
2: if set to 1 clears device remove event, set by OSPM
|
||||
after it has emitted device eject request for the
|
||||
selected memory device
|
||||
3: if set to 1 initiates device eject, set by OSPM when it
|
||||
triggers memory device removal and calls _EJ0 method
|
||||
4-7: reserved, OSPM must clear them before writing to register
|
||||
|
||||
Selecting memory device slot beyond present range has no effect on platform:
|
||||
- write accesses to memory hot-plug registers not documented above are
|
||||
ignored
|
||||
- read accesses to memory hot-plug registers not documented above return
|
||||
all bits set to 1.
|
||||
|
||||
Memory hot remove process diagram:
|
||||
----------------------------------
|
||||
+-------------+ +-----------------------+ +------------------+
|
||||
| 1. QEMU | | 2. QEMU | |3. QEMU |
|
||||
| device_del +---->+ device unplug request +----->+Send SCI to guest,|
|
||||
| | | cb | |return control to |
|
||||
+-------------+ +-----------------------+ |management |
|
||||
+------------------+
|
||||
|
||||
+---------------------------------------------------------------------+
|
||||
|
||||
+---------------------+ +-------------------------+
|
||||
| OSPM: | remove event | OSPM: |
|
||||
| send Eject Request, | | Scan memory devices |
|
||||
| clear remove event +<-------------+ for event flags |
|
||||
| | | |
|
||||
+---------------------+ +-------------------------+
|
||||
|
|
||||
|
|
||||
+---------v--------+ +-----------------------+
|
||||
| Guest OS: | success | OSPM: |
|
||||
| process Ejection +----------->+ Execute _EJ0 method, |
|
||||
| request | | set eject bit in flags|
|
||||
+------------------+ +-----------------------+
|
||||
|failure |
|
||||
v v
|
||||
+------------------------+ +-----------------------+
|
||||
| OSPM: | | QEMU: |
|
||||
| set OST event & status | | call device unplug cb |
|
||||
| fields | | |
|
||||
+------------------------+ +-----------------------+
|
||||
| |
|
||||
v v
|
||||
+------------------+ +-------------------+
|
||||
|QEMU: | |QEMU: |
|
||||
|Send OST QMP event| |Send device deleted|
|
||||
| | |QMP event |
|
||||
+------------------+ | |
|
||||
+-------------------+
|
|
@ -0,0 +1,228 @@
|
|||
QEMU<->ACPI BIOS NVDIMM interface
|
||||
=================================
|
||||
|
||||
QEMU supports NVDIMM via ACPI. This document describes the basic concepts of
|
||||
NVDIMM ACPI and the interface between QEMU and the ACPI BIOS.
|
||||
|
||||
NVDIMM ACPI Background
|
||||
----------------------
|
||||
|
||||
NVDIMM is introduced in ACPI 6.0 which defines an NVDIMM root device under
|
||||
_SB scope with a _HID of "ACPI0012". For each NVDIMM present or intended
|
||||
to be supported by platform, platform firmware also exposes an ACPI
|
||||
Namespace Device under the root device.
|
||||
|
||||
The NVDIMM child devices under the NVDIMM root device are defined with _ADR
|
||||
corresponding to the NFIT device handle. The NVDIMM root device and the
|
||||
NVDIMM devices can have device specific methods (_DSM) to provide additional
|
||||
functions specific to a particular NVDIMM implementation.
|
||||
|
||||
This is an example from ACPI 6.0, a platform contains one NVDIMM::
|
||||
|
||||
Scope (\_SB){
|
||||
Device (NVDR) // Root device
|
||||
{
|
||||
Name (_HID, "ACPI0012")
|
||||
Method (_STA) {...}
|
||||
Method (_FIT) {...}
|
||||
Method (_DSM, ...) {...}
|
||||
Device (NVD)
|
||||
{
|
||||
Name(_ADR, h) //where h is NFIT Device Handle for this NVDIMM
|
||||
Method (_DSM, ...) {...}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Methods supported on both NVDIMM root device and NVDIMM device
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
_DSM (Device Specific Method)
|
||||
It is a control method that enables devices to provide device specific
|
||||
control functions that are consumed by the device driver.
|
||||
The NVDIMM DSM specification can be found at
|
||||
http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
|
||||
|
||||
Arguments:
|
||||
|
||||
Arg0
|
||||
A Buffer containing a UUID (16 Bytes)
|
||||
Arg1
|
||||
An Integer containing the Revision ID (4 Bytes)
|
||||
Arg2
|
||||
An Integer containing the Function Index (4 Bytes)
|
||||
Arg3
|
||||
A package containing parameters for the function specified by the
|
||||
UUID, Revision ID, and Function Index
|
||||
|
||||
Return Value:
|
||||
|
||||
If Function Index = 0, a Buffer containing a function index bitfield.
|
||||
Otherwise, the return value and type depends on the UUID, revision ID
|
||||
and function index which are described in the DSM specification.
|
||||
|
||||
Methods on NVDIMM ROOT Device
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
_FIT(Firmware Interface Table)
|
||||
It evaluates to a buffer returning data in the format of a series of NFIT
|
||||
Type Structure.
|
||||
|
||||
Arguments: None
|
||||
|
||||
Return Value:
|
||||
A Buffer containing a list of NFIT Type structure entries.
|
||||
|
||||
The detailed definition of the structure can be found at ACPI 6.0: 5.2.25
|
||||
NVDIMM Firmware Interface Table (NFIT).
|
||||
|
||||
QEMU NVDIMM Implementation
|
||||
--------------------------
|
||||
|
||||
QEMU uses 4 bytes IO Port starting from 0x0a18 and a RAM-based memory page
|
||||
for NVDIMM ACPI.
|
||||
|
||||
Memory:
|
||||
QEMU uses BIOS Linker/loader feature to ask BIOS to allocate a memory
|
||||
page and dynamically patch its address into an int32 object named "MEMA"
|
||||
in ACPI.
|
||||
|
||||
This page is RAM-based and it is used to transfer data between _DSM
|
||||
method and QEMU. If ACPI has control, this pages is owned by ACPI which
|
||||
writes _DSM input data to it, otherwise, it is owned by QEMU which
|
||||
emulates _DSM access and writes the output data to it.
|
||||
|
||||
ACPI writes _DSM Input Data (based on the offset in the page):
|
||||
|
||||
[0x0 - 0x3]
|
||||
4 bytes, NVDIMM Device Handle.
|
||||
|
||||
The handle is completely QEMU internal thing, the values in
|
||||
range [1, 0xFFFF] indicate nvdimm device. Other values are
|
||||
reserved for other purposes.
|
||||
|
||||
Reserved handles:
|
||||
|
||||
- 0 is reserved for nvdimm root device named NVDR.
|
||||
- 0x10000 is reserved for QEMU internal DSM function called on
|
||||
the root device.
|
||||
|
||||
[0x4 - 0x7]
|
||||
4 bytes, Revision ID, that is the Arg1 of _DSM method.
|
||||
|
||||
[0x8 - 0xB]
|
||||
4 bytes. Function Index, that is the Arg2 of _DSM method.
|
||||
|
||||
[0xC - 0xFFF]
|
||||
4084 bytes, the Arg3 of _DSM method.
|
||||
|
||||
QEMU writes Output Data (based on the offset in the page):
|
||||
|
||||
[0x0 - 0x3]
|
||||
4 bytes, the length of result
|
||||
|
||||
[0x4 - 0xFFF]
|
||||
4092 bytes, the DSM result filled by QEMU
|
||||
|
||||
IO Port 0x0a18 - 0xa1b:
|
||||
ACPI writes the address of the memory page allocated by BIOS to this
|
||||
port then QEMU gets the control and fills the result in the memory page.
|
||||
|
||||
Write Access:
|
||||
|
||||
[0x0a18 - 0xa1b]
|
||||
4 bytes, the address of the memory page allocated by BIOS.
|
||||
|
||||
_DSM process diagram
|
||||
--------------------
|
||||
|
||||
"MEMA" indicates the address of memory page allocated by BIOS.
|
||||
|
||||
::
|
||||
|
||||
+----------------------+ +-----------------------+
|
||||
| 1. OSPM | | 2. OSPM |
|
||||
| save _DSM input data | | write "MEMA" to | Exit to QEMU
|
||||
| to the page +----->| IO port 0x0a18 +------------+
|
||||
| indicated by "MEMA" | | | |
|
||||
+----------------------+ +-----------------------+ |
|
||||
|
|
||||
v
|
||||
+--------------------+ +-----------+ +------------------+--------+
|
||||
| 5 QEMU | | 4 QEMU | | 3. QEMU |
|
||||
| write _DSM result | | emulate | | get _DSM input data from |
|
||||
| to the page +<------+ _DSM +<-----+ the page indicated by the |
|
||||
| | | | | value from the IO port |
|
||||
+--------+-----------+ +-----------+ +---------------------------+
|
||||
|
|
||||
| Enter Guest
|
||||
|
|
||||
v
|
||||
+--------------------------+ +--------------+
|
||||
| 6 OSPM | | 7 OSPM |
|
||||
| result size is returned | | _DSM return |
|
||||
| by reading DSM +----->+ |
|
||||
| result from the page | | |
|
||||
+--------------------------+ +--------------+
|
||||
|
||||
NVDIMM hotplug
|
||||
--------------
|
||||
|
||||
ACPI BIOS GPE.4 handler is dedicated for notifying OS about nvdimm device
|
||||
hot-add event.
|
||||
|
||||
QEMU internal use only _DSM functions
|
||||
-------------------------------------
|
||||
|
||||
Read FIT
|
||||
^^^^^^^^
|
||||
|
||||
_FIT method uses _DSM method to fetch NFIT structures blob from QEMU
|
||||
in 1 page sized increments which are then concatenated and returned
|
||||
as _FIT method result.
|
||||
|
||||
Input parameters:
|
||||
|
||||
Arg0
|
||||
UUID {set to 648B9CF2-CDA1-4312-8AD9-49C4AF32BD62}
|
||||
Arg1
|
||||
Revision ID (set to 1)
|
||||
Arg2
|
||||
Function Index, 0x1
|
||||
Arg3
|
||||
A package containing a buffer whose layout is as follows:
|
||||
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
| Field | Length | Offset | Description |
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
| offset | 4 | 0 | offset in QEMU's NFIT structures blob to |
|
||||
| | | | read from |
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
|
||||
Output layout in the dsm memory page:
|
||||
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
| Field | Length | Offset | Description |
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
| length | 4 | 0 | length of entire returned data |
|
||||
| | | | (including this header) |
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
| | | | return status codes |
|
||||
| | | | |
|
||||
| | | | - 0x0 - success |
|
||||
| | | | - 0x100 - error caused by NFIT update |
|
||||
| status | 4 | 4 | while read by _FIT wasn't completed |
|
||||
| | | | - other codes follow Chapter 3 in |
|
||||
| | | | DSM Spec Rev1 |
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
| fit data | Varies | 8 | contains FIT data. This field is present |
|
||||
| | | | if status field is 0. |
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
|
||||
The FIT offset is maintained by the OSPM itself, current offset plus
|
||||
the size of the fit data returned by the function is the next offset
|
||||
OSPM should read. When all FIT data has been read out, zero fit data
|
||||
size is returned.
|
||||
|
||||
If it returns status code 0x100, OSPM should restart to read FIT (read
|
||||
from offset 0 again).
|
|
@ -1,188 +0,0 @@
|
|||
QEMU<->ACPI BIOS NVDIMM interface
|
||||
---------------------------------
|
||||
|
||||
QEMU supports NVDIMM via ACPI. This document describes the basic concepts of
|
||||
NVDIMM ACPI and the interface between QEMU and the ACPI BIOS.
|
||||
|
||||
NVDIMM ACPI Background
|
||||
----------------------
|
||||
NVDIMM is introduced in ACPI 6.0 which defines an NVDIMM root device under
|
||||
_SB scope with a _HID of “ACPI0012”. For each NVDIMM present or intended
|
||||
to be supported by platform, platform firmware also exposes an ACPI
|
||||
Namespace Device under the root device.
|
||||
|
||||
The NVDIMM child devices under the NVDIMM root device are defined with _ADR
|
||||
corresponding to the NFIT device handle. The NVDIMM root device and the
|
||||
NVDIMM devices can have device specific methods (_DSM) to provide additional
|
||||
functions specific to a particular NVDIMM implementation.
|
||||
|
||||
This is an example from ACPI 6.0, a platform contains one NVDIMM:
|
||||
|
||||
Scope (\_SB){
|
||||
Device (NVDR) // Root device
|
||||
{
|
||||
Name (_HID, “ACPI0012”)
|
||||
Method (_STA) {...}
|
||||
Method (_FIT) {...}
|
||||
Method (_DSM, ...) {...}
|
||||
Device (NVD)
|
||||
{
|
||||
Name(_ADR, h) //where h is NFIT Device Handle for this NVDIMM
|
||||
Method (_DSM, ...) {...}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Method supported on both NVDIMM root device and NVDIMM device
|
||||
_DSM (Device Specific Method)
|
||||
It is a control method that enables devices to provide device specific
|
||||
control functions that are consumed by the device driver.
|
||||
The NVDIMM DSM specification can be found at:
|
||||
http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
|
||||
|
||||
Arguments:
|
||||
Arg0 – A Buffer containing a UUID (16 Bytes)
|
||||
Arg1 – An Integer containing the Revision ID (4 Bytes)
|
||||
Arg2 – An Integer containing the Function Index (4 Bytes)
|
||||
Arg3 – A package containing parameters for the function specified by the
|
||||
UUID, Revision ID, and Function Index
|
||||
|
||||
Return Value:
|
||||
If Function Index = 0, a Buffer containing a function index bitfield.
|
||||
Otherwise, the return value and type depends on the UUID, revision ID
|
||||
and function index which are described in the DSM specification.
|
||||
|
||||
Methods on NVDIMM ROOT Device
|
||||
_FIT(Firmware Interface Table)
|
||||
It evaluates to a buffer returning data in the format of a series of NFIT
|
||||
Type Structure.
|
||||
|
||||
Arguments: None
|
||||
|
||||
Return Value:
|
||||
A Buffer containing a list of NFIT Type structure entries.
|
||||
|
||||
The detailed definition of the structure can be found at ACPI 6.0: 5.2.25
|
||||
NVDIMM Firmware Interface Table (NFIT).
|
||||
|
||||
QEMU NVDIMM Implementation
|
||||
==========================
|
||||
QEMU uses 4 bytes IO Port starting from 0x0a18 and a RAM-based memory page
|
||||
for NVDIMM ACPI.
|
||||
|
||||
Memory:
|
||||
QEMU uses BIOS Linker/loader feature to ask BIOS to allocate a memory
|
||||
page and dynamically patch its address into an int32 object named "MEMA"
|
||||
in ACPI.
|
||||
|
||||
This page is RAM-based and it is used to transfer data between _DSM
|
||||
method and QEMU. If ACPI has control, this pages is owned by ACPI which
|
||||
writes _DSM input data to it, otherwise, it is owned by QEMU which
|
||||
emulates _DSM access and writes the output data to it.
|
||||
|
||||
ACPI writes _DSM Input Data (based on the offset in the page):
|
||||
[0x0 - 0x3]: 4 bytes, NVDIMM Device Handle.
|
||||
|
||||
The handle is completely QEMU internal thing, the values in
|
||||
range [1, 0xFFFF] indicate nvdimm device. Other values are
|
||||
reserved for other purposes.
|
||||
|
||||
Reserved handles:
|
||||
0 is reserved for nvdimm root device named NVDR.
|
||||
0x10000 is reserved for QEMU internal DSM function called on
|
||||
the root device.
|
||||
|
||||
[0x4 - 0x7]: 4 bytes, Revision ID, that is the Arg1 of _DSM method.
|
||||
[0x8 - 0xB]: 4 bytes. Function Index, that is the Arg2 of _DSM method.
|
||||
[0xC - 0xFFF]: 4084 bytes, the Arg3 of _DSM method.
|
||||
|
||||
QEMU Writes Output Data (based on the offset in the page):
|
||||
[0x0 - 0x3]: 4 bytes, the length of result
|
||||
[0x4 - 0xFFF]: 4092 bytes, the DSM result filled by QEMU
|
||||
|
||||
IO Port 0x0a18 - 0xa1b:
|
||||
ACPI writes the address of the memory page allocated by BIOS to this
|
||||
port then QEMU gets the control and fills the result in the memory page.
|
||||
|
||||
write Access:
|
||||
[0x0a18 - 0xa1b]: 4 bytes, the address of the memory page allocated
|
||||
by BIOS.
|
||||
|
||||
_DSM process diagram:
|
||||
---------------------
|
||||
"MEMA" indicates the address of memory page allocated by BIOS.
|
||||
|
||||
+----------------------+ +-----------------------+
|
||||
| 1. OSPM | | 2. OSPM |
|
||||
| save _DSM input data | | write "MEMA" to | Exit to QEMU
|
||||
| to the page +----->| IO port 0x0a18 +------------+
|
||||
| indicated by "MEMA" | | | |
|
||||
+----------------------+ +-----------------------+ |
|
||||
|
|
||||
v
|
||||
+------------- ----+ +-----------+ +------------------+--------+
|
||||
| 5 QEMU | | 4 QEMU | | 3. QEMU |
|
||||
| write _DSM result | | emulate | | get _DSM input data from |
|
||||
| to the page +<------+ _DSM +<-----+ the page indicated by the |
|
||||
| | | | | value from the IO port |
|
||||
+--------+-----------+ +-----------+ +---------------------------+
|
||||
|
|
||||
| Enter Guest
|
||||
|
|
||||
v
|
||||
+--------------------------+ +--------------+
|
||||
| 6 OSPM | | 7 OSPM |
|
||||
| result size is returned | | _DSM return |
|
||||
| by reading DSM +----->+ |
|
||||
| result from the page | | |
|
||||
+--------------------------+ +--------------+
|
||||
|
||||
NVDIMM hotplug
|
||||
--------------
|
||||
ACPI BIOS GPE.4 handler is dedicated for notifying OS about nvdimm device
|
||||
hot-add event.
|
||||
|
||||
QEMU internal use only _DSM function
|
||||
------------------------------------
|
||||
1) Read FIT
|
||||
_FIT method uses _DSM method to fetch NFIT structures blob from QEMU
|
||||
in 1 page sized increments which are then concatenated and returned
|
||||
as _FIT method result.
|
||||
|
||||
Input parameters:
|
||||
Arg0 – UUID {set to 648B9CF2-CDA1-4312-8AD9-49C4AF32BD62}
|
||||
Arg1 – Revision ID (set to 1)
|
||||
Arg2 - Function Index, 0x1
|
||||
Arg3 - A package containing a buffer whose layout is as follows:
|
||||
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
| Field | Length | Offset | Description |
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
| offset | 4 | 0 | offset in QEMU's NFIT structures blob to |
|
||||
| | | | read from |
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
|
||||
Output layout in the dsm memory page:
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
| Field | Length | Offset | Description |
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
| length | 4 | 0 | length of entire returned data |
|
||||
| | | | (including this header) |
|
||||
+----------+-----------------+-------------------------------------------+
|
||||
| | | | return status codes |
|
||||
| | | | 0x0 - success |
|
||||
| | | | 0x100 - error caused by NFIT update while |
|
||||
| status | 4 | 4 | read by _FIT wasn't completed, other |
|
||||
| | | | codes follow Chapter 3 in DSM Spec Rev1 |
|
||||
+----------+-----------------+-------------------------------------------+
|
||||
| fit data | Varies | 8 | contains FIT data, this field is present |
|
||||
| | | | if status field is 0; |
|
||||
+----------+--------+--------+-------------------------------------------+
|
||||
|
||||
The FIT offset is maintained by the OSPM itself, current offset plus
|
||||
the size of the fit data returned by the function is the next offset
|
||||
OSPM should read. When all FIT data has been read out, zero fit data
|
||||
size is returned.
|
||||
|
||||
If it returns status code 0x100, OSPM should restart to read FIT (read
|
||||
from offset 0 again).
|
|
@ -1,45 +1,48 @@
|
|||
QEMU<->ACPI BIOS PCI hotplug interface
|
||||
--------------------------------------
|
||||
======================================
|
||||
|
||||
QEMU supports PCI hotplug via ACPI, for PCI bus 0. This document
|
||||
describes the interface between QEMU and the ACPI BIOS.
|
||||
|
||||
ACPI GPE block (IO ports 0xafe0-0xafe3, byte access):
|
||||
-----------------------------------------
|
||||
ACPI GPE block (IO ports 0xafe0-0xafe3, byte access)
|
||||
----------------------------------------------------
|
||||
|
||||
Generic ACPI GPE block. Bit 1 (GPE.1) used to notify PCI hotplug/eject
|
||||
event to ACPI BIOS, via SCI interrupt.
|
||||
|
||||
PCI slot injection notification pending (IO port 0xae00-0xae03, 4-byte access):
|
||||
---------------------------------------------------------------
|
||||
PCI slot injection notification pending (IO port 0xae00-0xae03, 4-byte access)
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Slot injection notification pending. One bit per slot.
|
||||
|
||||
Read by ACPI BIOS GPE.1 handler to notify OS of injection
|
||||
events. Read-only.
|
||||
|
||||
PCI slot removal notification (IO port 0xae04-0xae07, 4-byte access):
|
||||
-----------------------------------------------------
|
||||
PCI slot removal notification (IO port 0xae04-0xae07, 4-byte access)
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Slot removal notification pending. One bit per slot.
|
||||
|
||||
Read by ACPI BIOS GPE.1 handler to notify OS of removal
|
||||
events. Read-only.
|
||||
|
||||
PCI device eject (IO port 0xae08-0xae0b, 4-byte access):
|
||||
----------------------------------------
|
||||
PCI device eject (IO port 0xae08-0xae0b, 4-byte access)
|
||||
-------------------------------------------------------
|
||||
|
||||
Write: Used by ACPI BIOS _EJ0 method to request device removal.
|
||||
One bit per slot.
|
||||
|
||||
Read: Hotplug features register. Used by platform to identify features
|
||||
available. Current base feature set (no bits set):
|
||||
- Read-only "up" register @0xae00, 4-byte access, bit per slot
|
||||
- Read-only "down" register @0xae04, 4-byte access, bit per slot
|
||||
- Read/write "eject" register @0xae08, 4-byte access,
|
||||
write: bit per slot eject, read: hotplug feature set
|
||||
- Read-only hotplug capable register @0xae0c, 4-byte access, bit per slot
|
||||
|
||||
PCI removability status (IO port 0xae0c-0xae0f, 4-byte access):
|
||||
-----------------------------------------------
|
||||
- Read-only "up" register @0xae00, 4-byte access, bit per slot
|
||||
- Read-only "down" register @0xae04, 4-byte access, bit per slot
|
||||
- Read/write "eject" register @0xae08, 4-byte access,
|
||||
write: bit per slot eject, read: hotplug feature set
|
||||
- Read-only hotplug capable register @0xae0c, 4-byte access, bit per slot
|
||||
|
||||
PCI removability status (IO port 0xae0c-0xae0f, 4-byte access)
|
||||
--------------------------------------------------------------
|
||||
|
||||
Used by ACPI BIOS _RMV method to indicate removability status to OS. One
|
||||
bit per slot. Read-only
|
||||
bit per slot. Read-only.
|
|
@ -13,3 +13,7 @@ guest hardware that is specific to QEMU.
|
|||
acpi_hw_reduced_hotplug
|
||||
tpm
|
||||
acpi_hest_ghes
|
||||
acpi_cpu_hotplug
|
||||
acpi_mem_hotplug
|
||||
acpi_pci_hotplug
|
||||
acpi_nvdimm
|
||||
|
|
|
@ -3218,7 +3218,7 @@ static bool gdb_accept_socket(int gdb_fd)
|
|||
|
||||
static int gdbserver_open_socket(const char *path)
|
||||
{
|
||||
struct sockaddr_un sockaddr;
|
||||
struct sockaddr_un sockaddr = {};
|
||||
int fd, ret;
|
||||
|
||||
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
@ -3247,7 +3247,7 @@ static int gdbserver_open_socket(const char *path)
|
|||
|
||||
static bool gdb_accept_tcp(int gdb_fd)
|
||||
{
|
||||
struct sockaddr_in sockaddr;
|
||||
struct sockaddr_in sockaddr = {};
|
||||
socklen_t len;
|
||||
int fd;
|
||||
|
||||
|
|
|
@ -25,9 +25,7 @@ config ARM_VIRT
|
|||
select ACPI_PCI
|
||||
select MEM_DEVICE
|
||||
select DIMM
|
||||
select ACPI_MEMORY_HOTPLUG
|
||||
select ACPI_HW_REDUCED
|
||||
select ACPI_NVDIMM
|
||||
select ACPI_APEI
|
||||
|
||||
config CHEETAH
|
||||
|
|
|
@ -281,7 +281,7 @@ static void raspi_machine_init(MachineState *machine)
|
|||
object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(machine->ram));
|
||||
object_property_set_int(OBJECT(&s->soc), "board-rev", board_rev,
|
||||
&error_abort);
|
||||
qdev_realize(DEVICE(&s->soc), NULL, &error_abort);
|
||||
qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
|
||||
|
||||
/* Create and plug in the SD cards */
|
||||
di = drive_get_next(IF_SD);
|
||||
|
|
|
@ -1852,11 +1852,6 @@ static void machvirt_init(MachineState *machine)
|
|||
}
|
||||
|
||||
if (vms->secure) {
|
||||
if (kvm_enabled()) {
|
||||
error_report("mach-virt: KVM does not support Security extensions");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The Secure view of the world is the same as the NonSecure,
|
||||
* but with a few extra devices. Create it as a container region
|
||||
|
|
|
@ -218,6 +218,8 @@ static void versal_create_admas(Versal *s, qemu_irq *pic)
|
|||
TYPE_XLNX_ZDMA);
|
||||
dev = DEVICE(&s->lpd.iou.adma[i]);
|
||||
object_property_set_int(OBJECT(dev), "bus-width", 128, &error_abort);
|
||||
object_property_set_link(OBJECT(dev), "dma",
|
||||
OBJECT(get_system_memory()), &error_fatal);
|
||||
sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
|
||||
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
|
||||
|
@ -376,6 +378,8 @@ static void versal_unimp(Versal *s)
|
|||
MM_CRL, MM_CRL_SIZE);
|
||||
versal_unimp_area(s, "crf", &s->mr_ps,
|
||||
MM_FPD_CRF, MM_FPD_CRF_SIZE);
|
||||
versal_unimp_area(s, "apu", &s->mr_ps,
|
||||
MM_FPD_FPD_APU, MM_FPD_FPD_APU_SIZE);
|
||||
versal_unimp_area(s, "crp", &s->mr_ps,
|
||||
MM_PMC_CRP, MM_PMC_CRP_SIZE);
|
||||
versal_unimp_area(s, "iou-scntr", &s->mr_ps,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "qemu/module.h"
|
||||
#include "hw/arm/xlnx-zynqmp.h"
|
||||
#include "hw/intc/arm_gic_common.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
@ -56,6 +57,9 @@
|
|||
#define DPDMA_ADDR 0xfd4c0000
|
||||
#define DPDMA_IRQ 116
|
||||
|
||||
#define APU_ADDR 0xfd5c0000
|
||||
#define APU_SIZE 0x100
|
||||
|
||||
#define IPI_ADDR 0xFF300000
|
||||
#define IPI_IRQ 64
|
||||
|
||||
|
@ -222,6 +226,32 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s,
|
|||
qdev_realize(DEVICE(&s->rpu_cluster), NULL, &error_fatal);
|
||||
}
|
||||
|
||||
static void xlnx_zynqmp_create_unimp_mmio(XlnxZynqMPState *s)
|
||||
{
|
||||
static const struct UnimpInfo {
|
||||
const char *name;
|
||||
hwaddr base;
|
||||
hwaddr size;
|
||||
} unimp_areas[ARRAY_SIZE(s->mr_unimp)] = {
|
||||
{ .name = "apu", APU_ADDR, APU_SIZE },
|
||||
};
|
||||
unsigned int nr;
|
||||
|
||||
for (nr = 0; nr < ARRAY_SIZE(unimp_areas); nr++) {
|
||||
const struct UnimpInfo *info = &unimp_areas[nr];
|
||||
DeviceState *dev = qdev_new(TYPE_UNIMPLEMENTED_DEVICE);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
assert(info->name && info->base && info->size > 0);
|
||||
qdev_prop_set_string(dev, "name", info->name);
|
||||
qdev_prop_set_uint64(dev, "size", info->size);
|
||||
object_property_add_child(OBJECT(s), info->name, OBJECT(dev));
|
||||
|
||||
sysbus_realize_and_unref(sbd, &error_fatal);
|
||||
sysbus_mmio_map(sbd, 0, info->base);
|
||||
}
|
||||
}
|
||||
|
||||
static void xlnx_zynqmp_init(Object *obj)
|
||||
{
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
|
@ -570,26 +600,6 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
|||
g_free(bus_name);
|
||||
}
|
||||
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->qspi), errp)) {
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 0, QSPI_ADDR);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 1, LQSPI_ADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->qspi), 0, gic_spi[QSPI_IRQ]);
|
||||
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_QSPI_BUS; i++) {
|
||||
gchar *bus_name;
|
||||
gchar *target_bus;
|
||||
|
||||
/* Alias controller SPI bus to the SoC itself */
|
||||
bus_name = g_strdup_printf("qspi%d", i);
|
||||
target_bus = g_strdup_printf("spi%d", i);
|
||||
object_property_add_alias(OBJECT(s), bus_name,
|
||||
OBJECT(&s->qspi), target_bus);
|
||||
g_free(bus_name);
|
||||
g_free(target_bus);
|
||||
}
|
||||
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->dp), errp)) {
|
||||
return;
|
||||
}
|
||||
|
@ -616,11 +626,17 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
|||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, RTC_ADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0, gic_spi[RTC_IRQ]);
|
||||
|
||||
xlnx_zynqmp_create_unimp_mmio(s);
|
||||
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_GDMA_CH; i++) {
|
||||
if (!object_property_set_uint(OBJECT(&s->gdma[i]), "bus-width", 128,
|
||||
errp)) {
|
||||
return;
|
||||
}
|
||||
if (!object_property_set_link(OBJECT(&s->gdma[i]), "dma",
|
||||
OBJECT(system_memory), errp)) {
|
||||
return;
|
||||
}
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gdma[i]), errp)) {
|
||||
return;
|
||||
}
|
||||
|
@ -631,6 +647,10 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
|||
}
|
||||
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_ADMA_CH; i++) {
|
||||
if (!object_property_set_link(OBJECT(&s->adma[i]), "dma",
|
||||
OBJECT(system_memory), errp)) {
|
||||
return;
|
||||
}
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->adma[i]), errp)) {
|
||||
return;
|
||||
}
|
||||
|
@ -640,14 +660,36 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
|||
gic_spi[adma_ch_intr[i]]);
|
||||
}
|
||||
|
||||
if (!object_property_set_link(OBJECT(&s->qspi_dma), "dma",
|
||||
OBJECT(system_memory), errp)) {
|
||||
return;
|
||||
}
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->qspi_dma), errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi_dma), 0, QSPI_DMA_ADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->qspi_dma), 0, gic_spi[QSPI_IRQ]);
|
||||
object_property_set_link(OBJECT(&s->qspi), "stream-connected-dma",
|
||||
OBJECT(&s->qspi_dma), errp);
|
||||
|
||||
if (!object_property_set_link(OBJECT(&s->qspi), "stream-connected-dma",
|
||||
OBJECT(&s->qspi_dma), errp)) {
|
||||
return;
|
||||
}
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->qspi), errp)) {
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 0, QSPI_ADDR);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 1, LQSPI_ADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->qspi), 0, gic_spi[QSPI_IRQ]);
|
||||
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_QSPI_BUS; i++) {
|
||||
g_autofree gchar *bus_name = g_strdup_printf("qspi%d", i);
|
||||
g_autofree gchar *target_bus = g_strdup_printf("spi%d", i);
|
||||
|
||||
/* Alias controller SPI bus to the SoC itself */
|
||||
object_property_add_alias(OBJECT(s), bus_name,
|
||||
OBJECT(&s->qspi), target_bus);
|
||||
}
|
||||
}
|
||||
|
||||
static Property xlnx_zynqmp_props[] = {
|
||||
|
|
|
@ -555,24 +555,35 @@ ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, size_t srclen)
|
|||
|
||||
/* skip header */
|
||||
i = 10;
|
||||
if (srclen < 4) {
|
||||
goto toosmall;
|
||||
}
|
||||
flags = src[3];
|
||||
if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
|
||||
puts ("Error: Bad gzipped data\n");
|
||||
return -1;
|
||||
}
|
||||
if ((flags & EXTRA_FIELD) != 0)
|
||||
if ((flags & EXTRA_FIELD) != 0) {
|
||||
if (srclen < 12) {
|
||||
goto toosmall;
|
||||
}
|
||||
i = 12 + src[10] + (src[11] << 8);
|
||||
if ((flags & ORIG_NAME) != 0)
|
||||
while (src[i++] != 0)
|
||||
;
|
||||
if ((flags & COMMENT) != 0)
|
||||
while (src[i++] != 0)
|
||||
;
|
||||
if ((flags & HEAD_CRC) != 0)
|
||||
}
|
||||
if ((flags & ORIG_NAME) != 0) {
|
||||
while (i < srclen && src[i++] != 0) {
|
||||
/* do nothing */
|
||||
}
|
||||
}
|
||||
if ((flags & COMMENT) != 0) {
|
||||
while (i < srclen && src[i++] != 0) {
|
||||
/* do nothing */
|
||||
}
|
||||
}
|
||||
if ((flags & HEAD_CRC) != 0) {
|
||||
i += 2;
|
||||
}
|
||||
if (i >= srclen) {
|
||||
puts ("Error: gunzip out of data in header\n");
|
||||
return -1;
|
||||
goto toosmall;
|
||||
}
|
||||
|
||||
s.zalloc = zalloc;
|
||||
|
@ -596,6 +607,10 @@ ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, size_t srclen)
|
|||
inflateEnd(&s);
|
||||
|
||||
return dstbytes;
|
||||
|
||||
toosmall:
|
||||
puts("Error: gunzip out of data in header\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Load a U-Boot image. */
|
||||
|
|
|
@ -320,9 +320,9 @@ static bool zdma_load_descriptor(XlnxZDMA *s, uint64_t addr,
|
|||
return false;
|
||||
}
|
||||
|
||||
descr->addr = address_space_ldq_le(s->dma_as, addr, s->attr, NULL);
|
||||
descr->size = address_space_ldl_le(s->dma_as, addr + 8, s->attr, NULL);
|
||||
descr->attr = address_space_ldl_le(s->dma_as, addr + 12, s->attr, NULL);
|
||||
descr->addr = address_space_ldq_le(&s->dma_as, addr, s->attr, NULL);
|
||||
descr->size = address_space_ldl_le(&s->dma_as, addr + 8, s->attr, NULL);
|
||||
descr->attr = address_space_ldl_le(&s->dma_as, addr + 12, s->attr, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -354,7 +354,7 @@ static void zdma_update_descr_addr(XlnxZDMA *s, bool type,
|
|||
} else {
|
||||
addr = zdma_get_regaddr64(s, basereg);
|
||||
addr += sizeof(s->dsc_dst);
|
||||
next = address_space_ldq_le(s->dma_as, addr, s->attr, NULL);
|
||||
next = address_space_ldq_le(&s->dma_as, addr, s->attr, NULL);
|
||||
}
|
||||
|
||||
zdma_put_regaddr64(s, basereg, next);
|
||||
|
@ -421,7 +421,7 @@ static void zdma_write_dst(XlnxZDMA *s, uint8_t *buf, uint32_t len)
|
|||
}
|
||||
}
|
||||
|
||||
address_space_write(s->dma_as, s->dsc_dst.addr, s->attr, buf, dlen);
|
||||
address_space_write(&s->dma_as, s->dsc_dst.addr, s->attr, buf, dlen);
|
||||
if (burst_type == AXI_BURST_INCR) {
|
||||
s->dsc_dst.addr += dlen;
|
||||
}
|
||||
|
@ -497,7 +497,7 @@ static void zdma_process_descr(XlnxZDMA *s)
|
|||
len = s->cfg.bus_width / 8;
|
||||
}
|
||||
} else {
|
||||
address_space_read(s->dma_as, src_addr, s->attr, s->buf, len);
|
||||
address_space_read(&s->dma_as, src_addr, s->attr, s->buf, len);
|
||||
if (burst_type == AXI_BURST_INCR) {
|
||||
src_addr += len;
|
||||
}
|
||||
|
@ -765,6 +765,12 @@ static void zdma_realize(DeviceState *dev, Error **errp)
|
|||
XlnxZDMA *s = XLNX_ZDMA(dev);
|
||||
unsigned int i;
|
||||
|
||||
if (!s->dma_mr) {
|
||||
error_setg(errp, TYPE_XLNX_ZDMA " 'dma' link not set");
|
||||
return;
|
||||
}
|
||||
address_space_init(&s->dma_as, s->dma_mr, "zdma-dma");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(zdma_regs_info); ++i) {
|
||||
RegisterInfo *r = &s->regs_info[zdma_regs_info[i].addr / 4];
|
||||
|
||||
|
@ -777,12 +783,6 @@ static void zdma_realize(DeviceState *dev, Error **errp)
|
|||
};
|
||||
}
|
||||
|
||||
if (s->dma_mr) {
|
||||
s->dma_as = g_malloc0(sizeof(AddressSpace));
|
||||
address_space_init(s->dma_as, s->dma_mr, NULL);
|
||||
} else {
|
||||
s->dma_as = &address_space_memory;
|
||||
}
|
||||
s->attr = MEMTXATTRS_UNSPECIFIED;
|
||||
}
|
||||
|
||||
|
|
|
@ -201,11 +201,11 @@ static uint32_t xlnx_csu_dma_read(XlnxCSUDMA *s, uint8_t *buf, uint32_t len)
|
|||
for (i = 0; i < len && (result == MEMTX_OK); i += s->width) {
|
||||
uint32_t mlen = MIN(len - i, s->width);
|
||||
|
||||
result = address_space_rw(s->dma_as, addr, s->attr,
|
||||
result = address_space_rw(&s->dma_as, addr, s->attr,
|
||||
buf + i, mlen, false);
|
||||
}
|
||||
} else {
|
||||
result = address_space_rw(s->dma_as, addr, s->attr, buf, len, false);
|
||||
result = address_space_rw(&s->dma_as, addr, s->attr, buf, len, false);
|
||||
}
|
||||
|
||||
if (result == MEMTX_OK) {
|
||||
|
@ -232,12 +232,12 @@ static uint32_t xlnx_csu_dma_write(XlnxCSUDMA *s, uint8_t *buf, uint32_t len)
|
|||
for (i = 0; i < len && (result == MEMTX_OK); i += s->width) {
|
||||
uint32_t mlen = MIN(len - i, s->width);
|
||||
|
||||
result = address_space_rw(s->dma_as, addr, s->attr,
|
||||
result = address_space_rw(&s->dma_as, addr, s->attr,
|
||||
buf, mlen, true);
|
||||
buf += mlen;
|
||||
}
|
||||
} else {
|
||||
result = address_space_rw(s->dma_as, addr, s->attr, buf, len, true);
|
||||
result = address_space_rw(&s->dma_as, addr, s->attr, buf, len, true);
|
||||
}
|
||||
|
||||
if (result != MEMTX_OK) {
|
||||
|
@ -626,6 +626,17 @@ static void xlnx_csu_dma_realize(DeviceState *dev, Error **errp)
|
|||
XlnxCSUDMA *s = XLNX_CSU_DMA(dev);
|
||||
RegisterInfoArray *reg_array;
|
||||
|
||||
if (!s->is_dst && !s->tx_dev) {
|
||||
error_setg(errp, "zynqmp.csu-dma: Stream not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->dma_mr) {
|
||||
error_setg(errp, TYPE_XLNX_CSU_DMA " 'dma' link not set");
|
||||
return;
|
||||
}
|
||||
address_space_init(&s->dma_as, s->dma_mr, "csu-dma");
|
||||
|
||||
reg_array =
|
||||
register_init_block32(dev, xlnx_csu_dma_regs_info[!!s->is_dst],
|
||||
XLNX_CSU_DMA_R_MAX,
|
||||
|
@ -640,21 +651,9 @@ static void xlnx_csu_dma_realize(DeviceState *dev, Error **errp)
|
|||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
|
||||
|
||||
if (!s->is_dst && !s->tx_dev) {
|
||||
error_setg(errp, "zynqmp.csu-dma: Stream not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
s->src_timer = ptimer_init(xlnx_csu_dma_src_timeout_hit,
|
||||
s, PTIMER_POLICY_DEFAULT);
|
||||
|
||||
if (s->dma_mr) {
|
||||
s->dma_as = g_malloc0(sizeof(AddressSpace));
|
||||
address_space_init(s->dma_as, s->dma_mr, NULL);
|
||||
} else {
|
||||
s->dma_as = &address_space_memory;
|
||||
}
|
||||
|
||||
s->attr = MEMTXATTRS_UNSPECIFIED;
|
||||
|
||||
s->r_size_last_word = 0;
|
||||
|
|
|
@ -65,7 +65,6 @@
|
|||
#include "hw/xen/start_info.h"
|
||||
#include "ui/qemu-spice.h"
|
||||
#include "exec/memory.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "qemu/bitmap.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
#include "sysemu/kvm.h"
|
||||
#include "hw/kvm/clock.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "hw/i2c/smbus_eeprom.h"
|
||||
#include "hw/xen/xen-x86.h"
|
||||
#include "exec/memory.h"
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "hw/loader.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "hw/i2c/smbus_eeprom.h"
|
||||
#include "hw/rtc/mc146818rtc.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "hw/isa/isa.h"
|
||||
#include "hw/block/fdc.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "hw/boards.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/scsi/esp.h"
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include "hw/mips/mips.h"
|
||||
#include "hw/mips/cpudevs.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/mips/bios.h"
|
||||
#include "hw/ide.h"
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
#include "hw/rtc/mc146818rtc.h"
|
||||
#include "hw/isa/pc87312.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "trace.h"
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "hw/intc/sifive_plic.h"
|
||||
#include "hw/misc/sifive_e_prci.h"
|
||||
#include "chardev/char.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
static const MemMapEntry sifive_e_memmap[] = {
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
#include "hw/intc/sifive_plic.h"
|
||||
#include "chardev/char.h"
|
||||
#include "net/eth.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "hw/char/riscv_htif.h"
|
||||
#include "hw/intc/sifive_clint.h"
|
||||
#include "chardev/char.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#include "hw/intc/sifive_plic.h"
|
||||
#include "hw/misc/sifive_test.h"
|
||||
#include "chardev/char.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/pci/pci.h"
|
||||
|
|
|
@ -167,6 +167,8 @@ struct Versal {
|
|||
#define MM_IOU_SCNTRS_SIZE 0x10000
|
||||
#define MM_FPD_CRF 0xfd1a0000U
|
||||
#define MM_FPD_CRF_SIZE 0x140000
|
||||
#define MM_FPD_FPD_APU 0xfd5c0000
|
||||
#define MM_FPD_FPD_APU_SIZE 0x100
|
||||
|
||||
#define MM_PMC_SD0 0xf1040000U
|
||||
#define MM_PMC_SD0_SIZE 0x10000
|
||||
|
|
|
@ -79,6 +79,11 @@ OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPState, XLNX_ZYNQMP)
|
|||
#define XLNX_ZYNQMP_MAX_RAM_SIZE (XLNX_ZYNQMP_MAX_LOW_RAM_SIZE + \
|
||||
XLNX_ZYNQMP_MAX_HIGH_RAM_SIZE)
|
||||
|
||||
/*
|
||||
* Unimplemented mmio regions needed to boot some images.
|
||||
*/
|
||||
#define XLNX_ZYNQMP_NUM_UNIMP_AREAS 1
|
||||
|
||||
struct XlnxZynqMPState {
|
||||
/*< private >*/
|
||||
DeviceState parent_obj;
|
||||
|
@ -96,6 +101,8 @@ struct XlnxZynqMPState {
|
|||
MemoryRegion *ddr_ram;
|
||||
MemoryRegion ddr_ram_low, ddr_ram_high;
|
||||
|
||||
MemoryRegion mr_unimp[XLNX_ZYNQMP_NUM_UNIMP_AREAS];
|
||||
|
||||
CadenceGEMState gem[XLNX_ZYNQMP_NUM_GEMS];
|
||||
CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS];
|
||||
XlnxZynqMPCANState can[XLNX_ZYNQMP_NUM_CAN];
|
||||
|
|
|
@ -56,7 +56,7 @@ struct XlnxZDMA {
|
|||
MemoryRegion iomem;
|
||||
MemTxAttrs attr;
|
||||
MemoryRegion *dma_mr;
|
||||
AddressSpace *dma_as;
|
||||
AddressSpace dma_as;
|
||||
qemu_irq irq_zdma_ch_imr;
|
||||
|
||||
struct {
|
||||
|
|
|
@ -30,7 +30,7 @@ typedef struct XlnxCSUDMA {
|
|||
MemoryRegion iomem;
|
||||
MemTxAttrs attr;
|
||||
MemoryRegion *dma_mr;
|
||||
AddressSpace *dma_as;
|
||||
AddressSpace dma_as;
|
||||
qemu_irq irq;
|
||||
StreamSink *tx_dev; /* Used as generic StreamSink */
|
||||
ptimer_state *src_timer;
|
||||
|
|
|
@ -23,22 +23,9 @@ enum {
|
|||
QEMU_ARCH_RISCV = (1 << 19),
|
||||
QEMU_ARCH_RX = (1 << 20),
|
||||
QEMU_ARCH_AVR = (1 << 21),
|
||||
|
||||
QEMU_ARCH_NONE = (1 << 31),
|
||||
QEMU_ARCH_HEXAGON = (1 << 22),
|
||||
};
|
||||
|
||||
extern const uint32_t arch_type;
|
||||
|
||||
int kvm_available(void);
|
||||
int xen_available(void);
|
||||
|
||||
/* default virtio transport per architecture */
|
||||
#define QEMU_ARCH_VIRTIO_PCI (QEMU_ARCH_ALPHA | QEMU_ARCH_ARM | \
|
||||
QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
|
||||
QEMU_ARCH_MIPS | QEMU_ARCH_PPC | \
|
||||
QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
|
||||
QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
|
||||
#define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
|
||||
#define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -289,7 +289,6 @@ setup_return(CPUARMState *env, struct target_sigaction *ka,
|
|||
env->regs[14] = retcode;
|
||||
env->regs[15] = handler & (thumb ? ~1 : ~3);
|
||||
cpsr_write(env, cpsr, CPSR_IT | CPSR_T | CPSR_E, CPSRWriteByInstr);
|
||||
arm_rebuild_hflags(env);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -547,7 +546,6 @@ restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
|
|||
__get_user(env->regs[15], &sc->arm_pc);
|
||||
__get_user(cpsr, &sc->arm_cpsr);
|
||||
cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
|
||||
arm_rebuild_hflags(env);
|
||||
|
||||
err |= !valid_user_regs(env);
|
||||
|
||||
|
|
|
@ -1625,6 +1625,8 @@ foreach target : target_dirs
|
|||
config_target_data.set(k, v)
|
||||
endif
|
||||
endforeach
|
||||
config_target_data.set('QEMU_ARCH',
|
||||
'QEMU_ARCH_' + config_target['TARGET_BASE_ARCH'].to_upper())
|
||||
config_target_h += {target: configure_file(output: target + '-config-target.h',
|
||||
configuration: config_target_data)}
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "sysemu/runstate-action.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qapi/error.h"
|
||||
|
@ -58,7 +57,7 @@ KvmInfo *qmp_query_kvm(Error **errp)
|
|||
KvmInfo *info = g_malloc0(sizeof(*info));
|
||||
|
||||
info->enabled = kvm_enabled();
|
||||
info->present = kvm_available();
|
||||
info->present = accel_find("kvm");
|
||||
|
||||
return info;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,8 @@ int parse_host_port(struct sockaddr_in *saddr, const char *str,
|
|||
const char *addr, *p, *r;
|
||||
int port, ret = 0;
|
||||
|
||||
memset(saddr, 0, sizeof(*saddr));
|
||||
|
||||
substrings = g_strsplit(str, ":", 2);
|
||||
if (!substrings || !substrings[0] || !substrings[1]) {
|
||||
error_setg(errp, "host address '%s' doesn't contain ':' "
|
||||
|
|
|
@ -23,13 +23,6 @@
|
|||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/audio/soundhw.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "qemu/help_option.h"
|
||||
|
||||
#ifdef TARGET_SPARC
|
||||
int graphic_width = 1024;
|
||||
|
@ -45,63 +38,4 @@ int graphic_height = 600;
|
|||
int graphic_depth = 32;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(TARGET_ALPHA)
|
||||
#define QEMU_ARCH QEMU_ARCH_ALPHA
|
||||
#elif defined(TARGET_ARM)
|
||||
#define QEMU_ARCH QEMU_ARCH_ARM
|
||||
#elif defined(TARGET_CRIS)
|
||||
#define QEMU_ARCH QEMU_ARCH_CRIS
|
||||
#elif defined(TARGET_HPPA)
|
||||
#define QEMU_ARCH QEMU_ARCH_HPPA
|
||||
#elif defined(TARGET_I386)
|
||||
#define QEMU_ARCH QEMU_ARCH_I386
|
||||
#elif defined(TARGET_M68K)
|
||||
#define QEMU_ARCH QEMU_ARCH_M68K
|
||||
#elif defined(TARGET_MICROBLAZE)
|
||||
#define QEMU_ARCH QEMU_ARCH_MICROBLAZE
|
||||
#elif defined(TARGET_MIPS)
|
||||
#define QEMU_ARCH QEMU_ARCH_MIPS
|
||||
#elif defined(TARGET_NIOS2)
|
||||
#define QEMU_ARCH QEMU_ARCH_NIOS2
|
||||
#elif defined(TARGET_OPENRISC)
|
||||
#define QEMU_ARCH QEMU_ARCH_OPENRISC
|
||||
#elif defined(TARGET_PPC)
|
||||
#define QEMU_ARCH QEMU_ARCH_PPC
|
||||
#elif defined(TARGET_RISCV)
|
||||
#define QEMU_ARCH QEMU_ARCH_RISCV
|
||||
#elif defined(TARGET_RX)
|
||||
#define QEMU_ARCH QEMU_ARCH_RX
|
||||
#elif defined(TARGET_S390X)
|
||||
#define QEMU_ARCH QEMU_ARCH_S390X
|
||||
#elif defined(TARGET_SH4)
|
||||
#define QEMU_ARCH QEMU_ARCH_SH4
|
||||
#elif defined(TARGET_SPARC)
|
||||
#define QEMU_ARCH QEMU_ARCH_SPARC
|
||||
#elif defined(TARGET_TRICORE)
|
||||
#define QEMU_ARCH QEMU_ARCH_TRICORE
|
||||
#elif defined(TARGET_XTENSA)
|
||||
#define QEMU_ARCH QEMU_ARCH_XTENSA
|
||||
#elif defined(TARGET_AVR)
|
||||
#define QEMU_ARCH QEMU_ARCH_AVR
|
||||
#endif
|
||||
|
||||
const uint32_t arch_type = QEMU_ARCH;
|
||||
|
||||
int kvm_available(void)
|
||||
{
|
||||
#ifdef CONFIG_KVM
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int xen_available(void)
|
||||
{
|
||||
#ifdef CONFIG_XEN
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1451,6 +1451,9 @@ static int64_t get_file_align(int fd)
|
|||
path = g_strdup_printf("/sys/dev/char/%d:%d",
|
||||
major(st.st_rdev), minor(st.st_rdev));
|
||||
rpath = realpath(path, NULL);
|
||||
if (!rpath) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
rc = daxctl_new(&ctx);
|
||||
if (rc) {
|
||||
|
@ -2075,7 +2078,7 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
|
|||
}
|
||||
|
||||
file_align = get_file_align(fd);
|
||||
if (file_align > 0 && mr && file_align > mr->align) {
|
||||
if (file_align > 0 && file_align > mr->align) {
|
||||
error_setg(errp, "backing store align 0x%" PRIx64
|
||||
" is larger than 'align' option 0x%" PRIx64,
|
||||
file_align, mr->align);
|
||||
|
|
|
@ -52,6 +52,15 @@ typedef struct QDevAlias
|
|||
uint32_t arch_mask;
|
||||
} QDevAlias;
|
||||
|
||||
/* default virtio transport per architecture */
|
||||
#define QEMU_ARCH_VIRTIO_PCI (QEMU_ARCH_ALPHA | QEMU_ARCH_ARM | \
|
||||
QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
|
||||
QEMU_ARCH_MIPS | QEMU_ARCH_PPC | \
|
||||
QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
|
||||
QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
|
||||
#define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
|
||||
#define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
|
||||
|
||||
/* Please keep this table sorted by typename. */
|
||||
static const QDevAlias qdev_alias_table[] = {
|
||||
{ "AC97", "ac97" }, /* -soundhw name */
|
||||
|
|
|
@ -3448,21 +3448,21 @@ void qemu_init(int argc, char **argv, char **envp)
|
|||
has_defaults = 0;
|
||||
break;
|
||||
case QEMU_OPTION_xen_domid:
|
||||
if (!(xen_available())) {
|
||||
if (!(accel_find("xen"))) {
|
||||
error_report("Option not supported for this target");
|
||||
exit(1);
|
||||
}
|
||||
xen_domid = atoi(optarg);
|
||||
break;
|
||||
case QEMU_OPTION_xen_attach:
|
||||
if (!(xen_available())) {
|
||||
if (!(accel_find("xen"))) {
|
||||
error_report("Option not supported for this target");
|
||||
exit(1);
|
||||
}
|
||||
xen_mode = XEN_ATTACH;
|
||||
break;
|
||||
case QEMU_OPTION_xen_domid_restrict:
|
||||
if (!(xen_available())) {
|
||||
if (!(accel_find("xen"))) {
|
||||
error_report("Option not supported for this target");
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
|
||||
const uint32_t arch_type = QEMU_ARCH_NONE;
|
|
@ -1,4 +1,3 @@
|
|||
stub_ss.add(files('arch_type.c'))
|
||||
stub_ss.add(files('bdrv-next-monitor-owned.c'))
|
||||
stub_ss.add(files('blk-commit-all.c'))
|
||||
stub_ss.add(files('blk-exp-close-all.c'))
|
||||
|
|
|
@ -1422,6 +1422,29 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
if (kvm_enabled()) {
|
||||
/*
|
||||
* Catch all the cases which might cause us to create more than one
|
||||
* address space for the CPU (otherwise we will assert() later in
|
||||
* cpu_address_space_init()).
|
||||
*/
|
||||
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||
error_setg(errp,
|
||||
"Cannot enable KVM when using an M-profile guest CPU");
|
||||
return;
|
||||
}
|
||||
if (cpu->has_el3) {
|
||||
error_setg(errp,
|
||||
"Cannot enable KVM when guest CPU has EL3 enabled");
|
||||
return;
|
||||
}
|
||||
if (cpu->tag_memory) {
|
||||
error_setg(errp,
|
||||
"Cannot enable KVM when guest CPUs has MTE enabled");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
uint64_t scale;
|
||||
|
||||
|
|
|
@ -1020,9 +1020,13 @@ struct ARMCPU {
|
|||
* While processing properties during initialization, corresponding
|
||||
* sve_vq_init bits are set for bits in sve_vq_map that have been
|
||||
* set by properties.
|
||||
*
|
||||
* Bits set in sve_vq_supported represent valid vector lengths for
|
||||
* the CPU type.
|
||||
*/
|
||||
DECLARE_BITMAP(sve_vq_map, ARM_MAX_VQ);
|
||||
DECLARE_BITMAP(sve_vq_init, ARM_MAX_VQ);
|
||||
DECLARE_BITMAP(sve_vq_supported, ARM_MAX_VQ);
|
||||
|
||||
/* Generic timer counter frequency, in Hz */
|
||||
uint64_t gt_cntfrq_hz;
|
||||
|
@ -1394,11 +1398,17 @@ uint32_t cpsr_read(CPUARMState *env);
|
|||
typedef enum CPSRWriteType {
|
||||
CPSRWriteByInstr = 0, /* from guest MSR or CPS */
|
||||
CPSRWriteExceptionReturn = 1, /* from guest exception return insn */
|
||||
CPSRWriteRaw = 2, /* trust values, do not switch reg banks */
|
||||
CPSRWriteRaw = 2,
|
||||
/* trust values, no reg bank switch, no hflags rebuild */
|
||||
CPSRWriteByGDBStub = 3, /* from the GDB stub */
|
||||
} CPSRWriteType;
|
||||
|
||||
/* Set the CPSR. Note that some bits of mask must be all-set or all-clear.*/
|
||||
/*
|
||||
* Set the CPSR. Note that some bits of mask must be all-set or all-clear.
|
||||
* This will do an arm_rebuild_hflags() if any of the bits in @mask
|
||||
* correspond to TB flags bits cached in the hflags, unless @write_type
|
||||
* is CPSRWriteRaw.
|
||||
*/
|
||||
void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask,
|
||||
CPSRWriteType write_type);
|
||||
|
||||
|
@ -1537,6 +1547,9 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
|
|||
#define SCR_ENSCXT (1U << 25)
|
||||
#define SCR_ATA (1U << 26)
|
||||
|
||||
#define HSTR_TTEE (1 << 16)
|
||||
#define HSTR_TJDBX (1 << 17)
|
||||
|
||||
/* Return the current FPSCR value. */
|
||||
uint32_t vfp_get_fpscr(CPUARMState *env);
|
||||
void vfp_set_fpscr(CPUARMState *env, uint32_t val);
|
||||
|
|
|
@ -265,14 +265,17 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
|||
* any of the above. Finally, if SVE is not disabled, then at least one
|
||||
* vector length must be enabled.
|
||||
*/
|
||||
DECLARE_BITMAP(kvm_supported, ARM_MAX_VQ);
|
||||
DECLARE_BITMAP(tmp, ARM_MAX_VQ);
|
||||
uint32_t vq, max_vq = 0;
|
||||
|
||||
/* Collect the set of vector lengths supported by KVM. */
|
||||
bitmap_zero(kvm_supported, ARM_MAX_VQ);
|
||||
/*
|
||||
* CPU models specify a set of supported vector lengths which are
|
||||
* enabled by default. Attempting to enable any vector length not set
|
||||
* in the supported bitmap results in an error. When KVM is enabled we
|
||||
* fetch the supported bitmap from the host.
|
||||
*/
|
||||
if (kvm_enabled() && kvm_arm_sve_supported()) {
|
||||
kvm_arm_sve_get_vls(CPU(cpu), kvm_supported);
|
||||
kvm_arm_sve_get_vls(CPU(cpu), cpu->sve_vq_supported);
|
||||
} else if (kvm_enabled()) {
|
||||
assert(!cpu_isar_feature(aa64_sve, cpu));
|
||||
}
|
||||
|
@ -299,7 +302,7 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
|||
* For KVM we have to automatically enable all supported unitialized
|
||||
* lengths, even when the smaller lengths are not all powers-of-two.
|
||||
*/
|
||||
bitmap_andnot(tmp, kvm_supported, cpu->sve_vq_init, max_vq);
|
||||
bitmap_andnot(tmp, cpu->sve_vq_supported, cpu->sve_vq_init, max_vq);
|
||||
bitmap_or(cpu->sve_vq_map, cpu->sve_vq_map, tmp, max_vq);
|
||||
} else {
|
||||
/* Propagate enabled bits down through required powers-of-two. */
|
||||
|
@ -322,39 +325,30 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
|||
/* Disabling a supported length disables all larger lengths. */
|
||||
for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
|
||||
if (test_bit(vq - 1, cpu->sve_vq_init) &&
|
||||
test_bit(vq - 1, kvm_supported)) {
|
||||
test_bit(vq - 1, cpu->sve_vq_supported)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
|
||||
bitmap_andnot(cpu->sve_vq_map, kvm_supported,
|
||||
cpu->sve_vq_init, max_vq);
|
||||
if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) {
|
||||
error_setg(errp, "cannot disable sve%d", vq * 128);
|
||||
error_append_hint(errp, "Disabling sve%d results in all "
|
||||
"vector lengths being disabled.\n",
|
||||
vq * 128);
|
||||
error_append_hint(errp, "With SVE enabled, at least one "
|
||||
"vector length must be enabled.\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* Disabling a power-of-two disables all larger lengths. */
|
||||
if (test_bit(0, cpu->sve_vq_init)) {
|
||||
error_setg(errp, "cannot disable sve128");
|
||||
error_append_hint(errp, "Disabling sve128 results in all "
|
||||
"vector lengths being disabled.\n");
|
||||
error_append_hint(errp, "With SVE enabled, at least one "
|
||||
"vector length must be enabled.\n");
|
||||
return;
|
||||
}
|
||||
for (vq = 2; vq <= ARM_MAX_VQ; vq <<= 1) {
|
||||
for (vq = 1; vq <= ARM_MAX_VQ; vq <<= 1) {
|
||||
if (test_bit(vq - 1, cpu->sve_vq_init)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
|
||||
bitmap_complement(cpu->sve_vq_map, cpu->sve_vq_init, max_vq);
|
||||
}
|
||||
|
||||
max_vq = vq <= ARM_MAX_VQ ? vq - 1 : ARM_MAX_VQ;
|
||||
bitmap_andnot(cpu->sve_vq_map, cpu->sve_vq_supported,
|
||||
cpu->sve_vq_init, max_vq);
|
||||
if (max_vq == 0 || bitmap_empty(cpu->sve_vq_map, max_vq)) {
|
||||
error_setg(errp, "cannot disable sve%d", vq * 128);
|
||||
error_append_hint(errp, "Disabling sve%d results in all "
|
||||
"vector lengths being disabled.\n",
|
||||
vq * 128);
|
||||
error_append_hint(errp, "With SVE enabled, at least one "
|
||||
"vector length must be enabled.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
max_vq = find_last_bit(cpu->sve_vq_map, max_vq) + 1;
|
||||
|
@ -390,46 +384,44 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
|
|||
assert(max_vq != 0);
|
||||
bitmap_clear(cpu->sve_vq_map, max_vq, ARM_MAX_VQ - max_vq);
|
||||
|
||||
if (kvm_enabled()) {
|
||||
/* Ensure the set of lengths matches what KVM supports. */
|
||||
bitmap_xor(tmp, cpu->sve_vq_map, kvm_supported, max_vq);
|
||||
if (!bitmap_empty(tmp, max_vq)) {
|
||||
vq = find_last_bit(tmp, max_vq) + 1;
|
||||
if (test_bit(vq - 1, cpu->sve_vq_map)) {
|
||||
if (cpu->sve_max_vq) {
|
||||
error_setg(errp, "cannot set sve-max-vq=%d",
|
||||
cpu->sve_max_vq);
|
||||
error_append_hint(errp, "This KVM host does not support "
|
||||
"the vector length %d-bits.\n",
|
||||
vq * 128);
|
||||
error_append_hint(errp, "It may not be possible to use "
|
||||
"sve-max-vq with this KVM host. Try "
|
||||
"using only sve<N> properties.\n");
|
||||
} else {
|
||||
error_setg(errp, "cannot enable sve%d", vq * 128);
|
||||
error_append_hint(errp, "This KVM host does not support "
|
||||
"the vector length %d-bits.\n",
|
||||
vq * 128);
|
||||
}
|
||||
/* Ensure the set of lengths matches what is supported. */
|
||||
bitmap_xor(tmp, cpu->sve_vq_map, cpu->sve_vq_supported, max_vq);
|
||||
if (!bitmap_empty(tmp, max_vq)) {
|
||||
vq = find_last_bit(tmp, max_vq) + 1;
|
||||
if (test_bit(vq - 1, cpu->sve_vq_map)) {
|
||||
if (cpu->sve_max_vq) {
|
||||
error_setg(errp, "cannot set sve-max-vq=%d", cpu->sve_max_vq);
|
||||
error_append_hint(errp, "This CPU does not support "
|
||||
"the vector length %d-bits.\n", vq * 128);
|
||||
error_append_hint(errp, "It may not be possible to use "
|
||||
"sve-max-vq with this CPU. Try "
|
||||
"using only sve<N> properties.\n");
|
||||
} else {
|
||||
error_setg(errp, "cannot enable sve%d", vq * 128);
|
||||
error_append_hint(errp, "This CPU does not support "
|
||||
"the vector length %d-bits.\n", vq * 128);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (kvm_enabled()) {
|
||||
error_setg(errp, "cannot disable sve%d", vq * 128);
|
||||
error_append_hint(errp, "The KVM host requires all "
|
||||
"supported vector lengths smaller "
|
||||
"than %d bits to also be enabled.\n",
|
||||
max_vq * 128);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* Ensure all required powers-of-two are enabled. */
|
||||
for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
|
||||
if (!test_bit(vq - 1, cpu->sve_vq_map)) {
|
||||
error_setg(errp, "cannot disable sve%d", vq * 128);
|
||||
error_append_hint(errp, "sve%d is required as it "
|
||||
"is a power-of-two length smaller than "
|
||||
"the maximum, sve%d\n",
|
||||
vq * 128, max_vq * 128);
|
||||
return;
|
||||
} else {
|
||||
/* Ensure all required powers-of-two are enabled. */
|
||||
for (vq = pow2floor(max_vq); vq >= 1; vq >>= 1) {
|
||||
if (!test_bit(vq - 1, cpu->sve_vq_map)) {
|
||||
error_setg(errp, "cannot disable sve%d", vq * 128);
|
||||
error_append_hint(errp, "sve%d is required as it "
|
||||
"is a power-of-two length smaller "
|
||||
"than the maximum, sve%d\n",
|
||||
vq * 128, max_vq * 128);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -840,6 +832,8 @@ static void aarch64_max_initfn(Object *obj)
|
|||
/* Default to PAUTH on, with the architected algorithm. */
|
||||
qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_property);
|
||||
qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_impdef_property);
|
||||
|
||||
bitmap_fill(cpu->sve_vq_supported, ARM_MAX_VQ);
|
||||
}
|
||||
|
||||
aarch64_add_sve_properties(obj);
|
||||
|
|
|
@ -2446,20 +2446,34 @@ static void teecr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
env->teecr = value;
|
||||
}
|
||||
|
||||
static CPAccessResult teecr_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/*
|
||||
* HSTR.TTEE only exists in v7A, not v8A, but v8A doesn't have T2EE
|
||||
* at all, so we don't need to check whether we're v8A.
|
||||
*/
|
||||
if (arm_current_el(env) < 2 && !arm_is_secure_below_el3(env) &&
|
||||
(env->cp15.hstr_el2 & HSTR_TTEE)) {
|
||||
return CP_ACCESS_TRAP_EL2;
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
static CPAccessResult teehbr_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (arm_current_el(env) == 0 && (env->teecr & 1)) {
|
||||
return CP_ACCESS_TRAP;
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
return teecr_access(env, ri, isread);
|
||||
}
|
||||
|
||||
static const ARMCPRegInfo t2ee_cp_reginfo[] = {
|
||||
{ .name = "TEECR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 6, .opc2 = 0,
|
||||
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, teecr),
|
||||
.resetvalue = 0,
|
||||
.writefn = teecr_write },
|
||||
.writefn = teecr_write, .accessfn = teecr_access },
|
||||
{ .name = "TEEHBR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 6, .opc2 = 0,
|
||||
.access = PL0_RW, .fieldoffset = offsetof(CPUARMState, teehbr),
|
||||
.accessfn = teehbr_access, .resetvalue = 0 },
|
||||
|
@ -7588,6 +7602,21 @@ static CPAccessResult access_jazelle(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
static CPAccessResult access_joscr_jmcr(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri, bool isread)
|
||||
{
|
||||
/*
|
||||
* HSTR.TJDBX traps JOSCR and JMCR accesses, but it exists only
|
||||
* in v7A, not in v8A.
|
||||
*/
|
||||
if (!arm_feature(env, ARM_FEATURE_V8) &&
|
||||
arm_current_el(env) < 2 && !arm_is_secure_below_el3(env) &&
|
||||
(env->cp15.hstr_el2 & HSTR_TJDBX)) {
|
||||
return CP_ACCESS_TRAP_EL2;
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
static const ARMCPRegInfo jazelle_regs[] = {
|
||||
{ .name = "JIDR",
|
||||
.cp = 14, .crn = 0, .crm = 0, .opc1 = 7, .opc2 = 0,
|
||||
|
@ -7595,9 +7624,11 @@ static const ARMCPRegInfo jazelle_regs[] = {
|
|||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "JOSCR",
|
||||
.cp = 14, .crn = 1, .crm = 0, .opc1 = 7, .opc2 = 0,
|
||||
.accessfn = access_joscr_jmcr,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "JMCR",
|
||||
.cp = 14, .crn = 2, .crm = 0, .opc1 = 7, .opc2 = 0,
|
||||
.accessfn = access_joscr_jmcr,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
@ -9215,6 +9246,8 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask,
|
|||
CPSRWriteType write_type)
|
||||
{
|
||||
uint32_t changed_daif;
|
||||
bool rebuild_hflags = (write_type != CPSRWriteRaw) &&
|
||||
(mask & (CPSR_M | CPSR_E | CPSR_IL));
|
||||
|
||||
if (mask & CPSR_NZCV) {
|
||||
env->ZF = (~val) & CPSR_Z;
|
||||
|
@ -9334,6 +9367,9 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask,
|
|||
}
|
||||
mask &= ~CACHED_CPSR_BITS;
|
||||
env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask);
|
||||
if (rebuild_hflags) {
|
||||
arm_rebuild_hflags(env);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sign/zero extend */
|
||||
|
|
|
@ -73,6 +73,8 @@ DEF_HELPER_2(v7m_vlldm, void, env, i32)
|
|||
|
||||
DEF_HELPER_2(v8m_stackcheck, void, env, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_2(check_bxj_trap, TCG_CALL_NO_WG, void, env, i32)
|
||||
|
||||
DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32)
|
||||
DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
|
||||
DEF_HELPER_2(get_cp_reg, i32, env, ptr)
|
||||
|
|
|
@ -740,7 +740,7 @@ void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map)
|
|||
uint32_t vq = 0;
|
||||
int i, j;
|
||||
|
||||
bitmap_clear(map, 0, ARM_MAX_VQ);
|
||||
bitmap_zero(map, ARM_MAX_VQ);
|
||||
|
||||
/*
|
||||
* KVM ensures all host CPUs support the same set of vector lengths.
|
||||
|
|
|
@ -224,6 +224,22 @@ void HELPER(setend)(CPUARMState *env)
|
|||
arm_rebuild_hflags(env);
|
||||
}
|
||||
|
||||
void HELPER(check_bxj_trap)(CPUARMState *env, uint32_t rm)
|
||||
{
|
||||
/*
|
||||
* Only called if in NS EL0 or EL1 for a BXJ for a v7A CPU;
|
||||
* check if HSTR.TJDBX means we need to trap to EL2.
|
||||
*/
|
||||
if (env->cp15.hstr_el2 & HSTR_TJDBX) {
|
||||
/*
|
||||
* We know the condition code check passed, so take the IMPDEF
|
||||
* choice to always report CV=1 COND 0xe
|
||||
*/
|
||||
uint32_t syn = syn_bxjtrap(1, 0xe, rm);
|
||||
raise_exception_ra(env, EXCP_HYP_TRAP, syn, 2, GETPC());
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* Function checks whether WFx (WFI/WFE) instructions are set up to be trapped.
|
||||
* The function returns the target EL (1-3) if the instruction is to be trapped;
|
||||
|
|
|
@ -36,6 +36,7 @@ enum arm_exception_class {
|
|||
EC_ADVSIMDFPACCESSTRAP = 0x07,
|
||||
EC_FPIDTRAP = 0x08,
|
||||
EC_PACTRAP = 0x09,
|
||||
EC_BXJTRAP = 0x0a,
|
||||
EC_CP14RRTTRAP = 0x0c,
|
||||
EC_BTITRAP = 0x0d,
|
||||
EC_ILLEGALSTATE = 0x0e,
|
||||
|
@ -215,6 +216,12 @@ static inline uint32_t syn_btitrap(int btype)
|
|||
return (EC_BTITRAP << ARM_EL_EC_SHIFT) | btype;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_bxjtrap(int cv, int cond, int rm)
|
||||
{
|
||||
return (EC_BXJTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL |
|
||||
(cv << 24) | (cond << 20) | rm;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
|
||||
{
|
||||
return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
|
||||
|
|
|
@ -6440,6 +6440,18 @@ static bool trans_BXJ(DisasContext *s, arg_BXJ *a)
|
|||
if (!ENABLE_ARCH_5J || arm_dc_feature(s, ARM_FEATURE_M)) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* v7A allows BXJ to be trapped via HSTR.TJDBX. We don't waste a
|
||||
* TBFLAGS bit on a basically-never-happens case, so call a helper
|
||||
* function to check for the trap and raise the exception if needed
|
||||
* (passing it the register number for the syndrome value).
|
||||
* v8A doesn't have this HSTR bit.
|
||||
*/
|
||||
if (!arm_dc_feature(s, ARM_FEATURE_V8) &&
|
||||
arm_dc_feature(s, ARM_FEATURE_EL2) &&
|
||||
s->current_el < 2 && s->ns) {
|
||||
gen_helper_check_bxj_trap(cpu_env, tcg_constant_i32(a->rm));
|
||||
}
|
||||
/* Trivial implementation equivalent to bx. */
|
||||
gen_bx(s, load_reg(s, a->rm));
|
||||
return true;
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "disas/dis-asm.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "kvm_ppc.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "sysemu/tcg.h"
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
|
||||
#include "hw/s390x/pv.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/tcg.h"
|
||||
#include "hw/core/sysemu-cpu-ops.h"
|
||||
|
|
|
@ -378,7 +378,7 @@ static void test_enable_irq(void)
|
|||
*/
|
||||
static void open_socket(void)
|
||||
{
|
||||
struct sockaddr_in myaddr;
|
||||
struct sockaddr_in myaddr = {};
|
||||
socklen_t addrlen;
|
||||
|
||||
myaddr.sin_family = AF_INET;
|
||||
|
|
|
@ -251,7 +251,7 @@ static void test_time(void)
|
|||
static int server_socket(void)
|
||||
{
|
||||
int val, fd;
|
||||
struct sockaddr_in sockaddr;
|
||||
struct sockaddr_in sockaddr = {};
|
||||
|
||||
/* server socket */
|
||||
fd = chk_error(socket(PF_INET, SOCK_STREAM, 0));
|
||||
|
@ -271,7 +271,7 @@ static int server_socket(void)
|
|||
static int client_socket(uint16_t port)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in sockaddr;
|
||||
struct sockaddr_in sockaddr = {};
|
||||
|
||||
/* server socket */
|
||||
fd = chk_error(socket(PF_INET, SOCK_STREAM, 0));
|
||||
|
|
Loading…
Reference in New Issue