Misc HW patches

- Set correct values for MPC8569E's eSDHC (Zoltan)
 - Emulate Ricoh RS5C372 RTC device (Bernhard)
 - Array overflow fixes in SMSC91C111 netdev (Peter)
 - Fix typo in Xen HVM (Philippe)
 - Move graphic height/width/depth globals to their own file (Philippe)
 - Introduce qemu_arch_available() helper (Philippe)
 - Check fw_cfg's ACPI availability at runtime (Philippe)
 - Remove virtio-mem dependency on CONFIG_DEVICES (Philippe)
 - Sort HyperV SYNDBG API definitions (Pierrick)
 - Remove need for SDHCI_VENDOR_FSL definition (Philippe)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmfRXiMACgkQ4+MsLN6t
 wN5zFhAAzSW/hZneD8hycKtr9nBlvZSD72cEt+b656OCbTyyucUi1sG4rMPMvHeW
 h6HP6xt2SfQxXbec6Y0pWxWUkBOQzk72s0zpttOED3oEspkrId2D+VSsSH1E+QLh
 WoG7/hVgz0bDHexWYIDdGufO4no/icwewAKmC5Kp2HbaNxIIHyWlK1+RO69/lCLN
 s3qkNesMsQyEWN28ogEMRqyCIG3oJVP76U4TVcdxIiE51WI8sP8/7V2um0AXN68m
 IV3INrfVJjGDp501elrUbD3qsYopRdxoMAvwiVojrLXin6xtS+SQjEe/hcNxzM70
 0IQPp9WWwLjNkeFlAJF4wpwGJttFNHj+5gtH7/YRrP75jt9kAxPXkFw/OFfpVd30
 NYbeFlWDhRL1QPBs+WPBZTrfD7fRmpfMJRLF3/w61+WvnVrshlyDaoCWbR+L329F
 uOQFsBdAD7m/lkZ0mHtskS2vkZx7Itn1av4gql7T7/6cE1R7ItKy1HY9UUCtY6Gp
 7V6XrsAE3khg2HY8IcJ73+sPLQn/GxqZFE7PqmAhgcl6RZEFQv8PNrEgFxCEYyuK
 KJjx0hRMLoigp0CEclLfOqz2d3knsI8SJbgD4iTYQc02E69lx8a4XS4N8JXoLEdh
 3i/ndwKEFmzwNuqbU0nYsSJDiAO9ejra8O2BXZS/a4pkxC2jtdw=
 =VVr6
 -----END PGP SIGNATURE-----

Merge tag 'hw-misc-20250312' of https://github.com/philmd/qemu into staging

Misc HW patches

- Set correct values for MPC8569E's eSDHC (Zoltan)
- Emulate Ricoh RS5C372 RTC device (Bernhard)
- Array overflow fixes in SMSC91C111 netdev (Peter)
- Fix typo in Xen HVM (Philippe)
- Move graphic height/width/depth globals to their own file (Philippe)
- Introduce qemu_arch_available() helper (Philippe)
- Check fw_cfg's ACPI availability at runtime (Philippe)
- Remove virtio-mem dependency on CONFIG_DEVICES (Philippe)
- Sort HyperV SYNDBG API definitions (Pierrick)
- Remove need for SDHCI_VENDOR_FSL definition (Philippe)

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmfRXiMACgkQ4+MsLN6t
# wN5zFhAAzSW/hZneD8hycKtr9nBlvZSD72cEt+b656OCbTyyucUi1sG4rMPMvHeW
# h6HP6xt2SfQxXbec6Y0pWxWUkBOQzk72s0zpttOED3oEspkrId2D+VSsSH1E+QLh
# WoG7/hVgz0bDHexWYIDdGufO4no/icwewAKmC5Kp2HbaNxIIHyWlK1+RO69/lCLN
# s3qkNesMsQyEWN28ogEMRqyCIG3oJVP76U4TVcdxIiE51WI8sP8/7V2um0AXN68m
# IV3INrfVJjGDp501elrUbD3qsYopRdxoMAvwiVojrLXin6xtS+SQjEe/hcNxzM70
# 0IQPp9WWwLjNkeFlAJF4wpwGJttFNHj+5gtH7/YRrP75jt9kAxPXkFw/OFfpVd30
# NYbeFlWDhRL1QPBs+WPBZTrfD7fRmpfMJRLF3/w61+WvnVrshlyDaoCWbR+L329F
# uOQFsBdAD7m/lkZ0mHtskS2vkZx7Itn1av4gql7T7/6cE1R7ItKy1HY9UUCtY6Gp
# 7V6XrsAE3khg2HY8IcJ73+sPLQn/GxqZFE7PqmAhgcl6RZEFQv8PNrEgFxCEYyuK
# KJjx0hRMLoigp0CEclLfOqz2d3knsI8SJbgD4iTYQc02E69lx8a4XS4N8JXoLEdh
# 3i/ndwKEFmzwNuqbU0nYsSJDiAO9ejra8O2BXZS/a4pkxC2jtdw=
# =VVr6
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 12 Mar 2025 18:12:51 HKT
# gpg:                using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE
# gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full]
# Primary key fingerprint: FAAB E75E 1291 7221 DCFD  6BB2 E3E3 2C2C DEAD C0DE

* tag 'hw-misc-20250312' of https://github.com/philmd/qemu:
  hw/sd/sdhci: Remove need for SDHCI_VENDOR_IMX definition
  hw/hyperv/hyperv-proto: Move SYNDBG definitions from target/i386
  hw/virtio/virtio-mem: Remove CONFIG_DEVICES include
  hw/i386/fw_cfg: Check ACPI availability with acpi_builtin()
  hw/acpi: Introduce acpi_builtin() helper
  system: Replace arch_type global by qemu_arch_available() helper
  system: Extract target-specific globals to their own compilation unit
  hw/xen/hvm: Fix Aarch64 typo
  hw/net/smc91c111: Don't allow data register access to overrun buffer
  hw/net/smc91c111: Use MAX_PACKET_SIZE instead of magic numbers
  hw/net/smc91c111: Sanitize packet length on tx
  hw/net/smc91c111: Sanitize packet numbers
  hw/rtc: Add Ricoh RS5C372 RTC emulation
  hw/sd/sdhci: Set reset value of interrupt registers

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2025-03-13 10:35:25 +08:00
commit 4c33c097f3
31 changed files with 503 additions and 82 deletions

View file

@ -827,10 +827,12 @@ F: hw/arm/imx8mp-evk.c
F: hw/arm/fsl-imx8mp.c
F: hw/misc/imx8mp_*.c
F: hw/pci-host/fsl_imx8m_phy.c
F: hw/rtc/rs5c372.c
F: include/hw/arm/fsl-imx8mp.h
F: include/hw/misc/imx8mp_*.h
F: include/hw/pci-host/fsl_imx8m_phy.h
F: docs/system/arm/imx8mp-evk.rst
F: tests/qtest/rs5c372-test.c
MPS2 / MPS3
M: Peter Maydell <peter.maydell@linaro.org>

View file

@ -21,7 +21,15 @@
#include "qemu/osdep.h"
#include "hw/acpi/acpi.h"
char unsigned *acpi_tables;
size_t acpi_tables_len;
void acpi_table_add(const QemuOpts *opts, Error **errp)
{
g_assert_not_reached();
}
bool acpi_builtin(void)
{
return false;
}

View file

@ -78,6 +78,11 @@ static void acpi_register_config(void)
opts_init(acpi_register_config);
bool acpi_builtin(void)
{
return true;
}
static int acpi_checksum(const uint8_t *data, int len)
{
int sum, i;

View file

@ -243,8 +243,6 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
&error_abort);
object_property_set_uint(OBJECT(&s->esdhc[i]), "capareg",
IMX25_ESDHC_CAPABILITIES, &error_abort);
object_property_set_uint(OBJECT(&s->esdhc[i]), "vendor",
SDHCI_VENDOR_IMX, &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), errp)) {
return;
}

View file

@ -327,8 +327,6 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
&error_abort);
object_property_set_uint(OBJECT(&s->esdhc[i]), "capareg",
IMX6_ESDHC_CAPABILITIES, &error_abort);
object_property_set_uint(OBJECT(&s->esdhc[i]), "vendor",
SDHCI_VENDOR_IMX, &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->esdhc[i]), errp)) {
return;
}

View file

@ -531,8 +531,6 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
FSL_IMX6UL_USDHC2_IRQ,
};
object_property_set_uint(OBJECT(&s->usdhc[i]), "vendor",
SDHCI_VENDOR_IMX, &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0,

View file

@ -471,8 +471,6 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
FSL_IMX7_USDHC3_IRQ,
};
object_property_set_uint(OBJECT(&s->usdhc[i]), "vendor",
SDHCI_VENDOR_IMX, &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0,

View file

@ -524,8 +524,6 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
{ fsl_imx8mp_memmap[FSL_IMX8MP_USDHC3].addr, FSL_IMX8MP_USDHC3_IRQ },
};
object_property_set_uint(OBJECT(&s->usdhc[i]), "vendor",
SDHCI_VENDOR_IMX, &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), errp)) {
return;
}

View file

@ -145,10 +145,10 @@ FWCfgState *fw_cfg_arch_create(MachineState *ms,
*/
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, apic_id_limit);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, ms->ram_size);
#ifdef CONFIG_ACPI
fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES,
acpi_tables, acpi_tables_len);
#endif
if (acpi_builtin()) {
fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES,
acpi_tables, acpi_tables_len);
}
fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, 1);
fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, &hpet_fw_cfg, sizeof(hpet_fw_cfg));

View file

@ -13,6 +13,7 @@
#include "net/net.h"
#include "hw/irq.h"
#include "hw/net/smc91c111.h"
#include "hw/registerfields.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/log.h"
@ -22,6 +23,13 @@
/* Number of 2k memory pages available. */
#define NUM_PACKETS 4
/*
* Maximum size of a data frame, including the leading status word
* and byte count fields and the trailing CRC, last data byte
* and control byte (per figure 8-1 in the Microchip Technology
* LAN91C111 datasheet).
*/
#define MAX_PACKET_SIZE 2048
#define TYPE_SMC91C111 "smc91c111"
OBJECT_DECLARE_SIMPLE_TYPE(smc91c111_state, SMC91C111)
@ -51,7 +59,7 @@ struct smc91c111_state {
int tx_fifo_done_len;
int tx_fifo_done[NUM_PACKETS];
/* Packet buffer memory. */
uint8_t data[NUM_PACKETS][2048];
uint8_t data[NUM_PACKETS][MAX_PACKET_SIZE];
uint8_t int_level;
uint8_t int_mask;
MemoryRegion mmio;
@ -79,7 +87,8 @@ static const VMStateDescription vmstate_smc91c111 = {
VMSTATE_INT32_ARRAY(rx_fifo, smc91c111_state, NUM_PACKETS),
VMSTATE_INT32(tx_fifo_done_len, smc91c111_state),
VMSTATE_INT32_ARRAY(tx_fifo_done, smc91c111_state, NUM_PACKETS),
VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048),
VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0,
NUM_PACKETS * MAX_PACKET_SIZE),
VMSTATE_UINT8(int_level, smc91c111_state),
VMSTATE_UINT8(int_mask, smc91c111_state),
VMSTATE_END_OF_LIST()
@ -118,6 +127,18 @@ static const VMStateDescription vmstate_smc91c111 = {
#define RS_TOOSHORT 0x0400
#define RS_MULTICAST 0x0001
FIELD(PTR, PTR, 0, 11)
FIELD(PTR, NOT_EMPTY, 11, 1)
FIELD(PTR, RESERVED, 12, 1)
FIELD(PTR, READ, 13, 1)
FIELD(PTR, AUTOINCR, 14, 1)
FIELD(PTR, RCV, 15, 1)
static inline bool packetnum_valid(int packet_num)
{
return packet_num >= 0 && packet_num < NUM_PACKETS;
}
/* Update interrupt status. */
static void smc91c111_update(smc91c111_state *s)
{
@ -218,12 +239,33 @@ static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
/* Release the memory allocated to a packet. */
static void smc91c111_release_packet(smc91c111_state *s, int packet)
{
if (!packetnum_valid(packet)) {
/*
* Data sheet doesn't document behaviour in this guest error
* case, and there is no error status register to report it.
* Log and ignore the attempt.
*/
qemu_log_mask(LOG_GUEST_ERROR,
"smc91c111: attempt to release invalid packet %d\n",
packet);
return;
}
s->allocated &= ~(1 << packet);
if (s->tx_alloc == 0x80)
smc91c111_tx_alloc(s);
smc91c111_flush_queued_packets(s);
}
static void smc91c111_complete_tx_packet(smc91c111_state *s, int packetnum)
{
if (s->ctr & CTR_AUTO_RELEASE) {
/* Race? */
smc91c111_release_packet(s, packetnum);
} else if (s->tx_fifo_done_len < NUM_PACKETS) {
s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
}
}
/* Flush the TX FIFO. */
static void smc91c111_do_tx(smc91c111_state *s)
{
@ -239,12 +281,25 @@ static void smc91c111_do_tx(smc91c111_state *s)
return;
for (i = 0; i < s->tx_fifo_len; i++) {
packetnum = s->tx_fifo[i];
/* queue_tx checked the packet number was valid */
assert(packetnum_valid(packetnum));
p = &s->data[packetnum][0];
/* Set status word. */
*(p++) = 0x01;
*(p++) = 0x40;
len = *(p++);
len |= ((int)*(p++)) << 8;
if (len > MAX_PACKET_SIZE) {
/*
* Datasheet doesn't say what to do here, and there is no
* relevant tx error condition listed. Log, and drop the packet.
*/
qemu_log_mask(LOG_GUEST_ERROR,
"smc91c111: tx packet with bad length %d, dropping\n",
len);
smc91c111_complete_tx_packet(s, packetnum);
continue;
}
len -= 6;
control = p[len + 1];
if (control & 0x20)
@ -273,11 +328,7 @@ static void smc91c111_do_tx(smc91c111_state *s)
}
}
#endif
if (s->ctr & CTR_AUTO_RELEASE)
/* Race? */
smc91c111_release_packet(s, packetnum);
else if (s->tx_fifo_done_len < NUM_PACKETS)
s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
smc91c111_complete_tx_packet(s, packetnum);
qemu_send_packet(qemu_get_queue(s->nic), p, len);
}
s->tx_fifo_len = 0;
@ -287,6 +338,17 @@ static void smc91c111_do_tx(smc91c111_state *s)
/* Add a packet to the TX FIFO. */
static void smc91c111_queue_tx(smc91c111_state *s, int packet)
{
if (!packetnum_valid(packet)) {
/*
* Datasheet doesn't document behaviour in this error case, and
* there's no error status register we could report it in.
* Log and ignore.
*/
qemu_log_mask(LOG_GUEST_ERROR,
"smc91c111: attempt to queue invalid packet %d\n",
packet);
return;
}
if (s->tx_fifo_len == NUM_PACKETS)
return;
s->tx_fifo[s->tx_fifo_len++] = packet;
@ -318,6 +380,49 @@ static void smc91c111_reset(DeviceState *dev)
#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
/*
* The pointer register's pointer is an 11 bit value (so it exactly
* indexes a 2048-byte data frame). Add the specified offset to it,
* wrapping around at the 2048 byte mark, and return the resulting
* wrapped value. There are flag bits in the top part of the register,
* but we can ignore them here as the mask will mask them out.
*/
static int ptr_reg_add(smc91c111_state *s, int offset)
{
return (s->ptr + offset) & R_PTR_PTR_MASK;
}
/*
* For an access to the Data Register at @offset, return the
* required offset into the packet's data frame. This will
* perform the pointer register autoincrement if required, and
* guarantees to return an in-bounds offset.
*/
static int data_reg_ptr(smc91c111_state *s, int offset)
{
int p;
if (s->ptr & R_PTR_AUTOINCR_MASK) {
/*
* Autoincrement: use the current pointer value, and
* increment the pointer register's pointer field.
*/
p = FIELD_EX32(s->ptr, PTR, PTR);
s->ptr = FIELD_DP32(s->ptr, PTR, PTR, ptr_reg_add(s, 1));
} else {
/*
* No autoincrement: register offset determines which
* byte we're addressing. Setting the pointer to the top
* of the data buffer and then using the pointer wrapping
* to read the bottom byte of the buffer is not something
* sensible guest software will do, but the datasheet
* doesn't say what the behaviour is, so we don't forbid it.
*/
p = ptr_reg_add(s, offset & 3);
}
return p;
}
static void smc91c111_writeb(void *opaque, hwaddr offset,
uint32_t value)
{
@ -457,12 +562,14 @@ static void smc91c111_writeb(void *opaque, hwaddr offset,
n = s->rx_fifo[0];
else
n = s->packet_num;
p = s->ptr & 0x07ff;
if (s->ptr & 0x4000) {
s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
} else {
p += (offset & 3);
if (!packetnum_valid(n)) {
/* Datasheet doesn't document what to do here */
qemu_log_mask(LOG_GUEST_ERROR,
"smc91c111: attempt to write data to invalid packet %d\n",
n);
return;
}
p = data_reg_ptr(s, offset);
s->data[n][p] = value;
}
return;
@ -605,12 +712,14 @@ static uint32_t smc91c111_readb(void *opaque, hwaddr offset)
n = s->rx_fifo[0];
else
n = s->packet_num;
p = s->ptr & 0x07ff;
if (s->ptr & 0x4000) {
s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
} else {
p += (offset & 3);
if (!packetnum_valid(n)) {
/* Datasheet doesn't document what to do here */
qemu_log_mask(LOG_GUEST_ERROR,
"smc91c111: attempt to read data from invalid packet %d\n",
n);
return 0;
}
p = data_reg_ptr(s, offset);
return s->data[n][p];
}
case 12: /* Interrupt status. */
@ -706,13 +815,16 @@ static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, size_t
if (crc)
packetsize += 4;
/* TODO: Flag overrun and receive errors. */
if (packetsize > 2048)
if (packetsize > MAX_PACKET_SIZE) {
return -1;
}
packetnum = smc91c111_allocate_packet(s);
if (packetnum == 0x80)
return -1;
s->rx_fifo[s->rx_fifo_len++] = packetnum;
/* allocate_packet() will not hand us back an invalid packet number */
assert(packetnum_valid(packetnum));
p = &s->data[packetnum][0];
/* ??? Multicast packets? */
status = 0;

View file

@ -1043,6 +1043,7 @@ void ppce500_init(MachineState *machine)
dev = qdev_new(TYPE_SYSBUS_SDHCI);
qdev_prop_set_uint8(dev, "sd-spec-version", 2);
qdev_prop_set_uint8(dev, "endianness", DEVICE_BIG_ENDIAN);
qdev_prop_set_uint8(dev, "vendor", SDHCI_VENDOR_FSL);
s = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(s, &error_fatal);
sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC85XX_ESDHC_IRQ));

View file

@ -26,3 +26,8 @@ config GOLDFISH_RTC
config LS7A_RTC
bool
config RS5C372_RTC
bool
depends on I2C
default y if I2C_DEVICES

View file

@ -13,3 +13,4 @@ system_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c'))
system_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c'))
system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c'))
system_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c'))
system_ss.add(when: 'CONFIG_RS5C372_RTC', if_true: files('rs5c372.c'))

236
hw/rtc/rs5c372.c Normal file
View file

@ -0,0 +1,236 @@
/*
* Ricoh RS5C372, R222x I2C RTC
*
* Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
*
* Based on hw/rtc/ds1338.c
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "hw/i2c/i2c.h"
#include "hw/qdev-properties.h"
#include "hw/resettable.h"
#include "migration/vmstate.h"
#include "qemu/bcd.h"
#include "qom/object.h"
#include "system/rtc.h"
#include "trace.h"
#define NVRAM_SIZE 0x10
/* Flags definitions */
#define SECONDS_CH 0x80
#define HOURS_PM 0x20
#define CTRL2_24 0x20
#define TYPE_RS5C372 "rs5c372"
OBJECT_DECLARE_SIMPLE_TYPE(RS5C372State, RS5C372)
struct RS5C372State {
I2CSlave parent_obj;
int64_t offset;
uint8_t wday_offset;
uint8_t nvram[NVRAM_SIZE];
uint8_t ptr;
uint8_t tx_format;
bool addr_byte;
};
static void capture_current_time(RS5C372State *s)
{
/*
* Capture the current time into the secondary registers which will be
* actually read by the data transfer operation.
*/
struct tm now;
qemu_get_timedate(&now, s->offset);
s->nvram[0] = to_bcd(now.tm_sec);
s->nvram[1] = to_bcd(now.tm_min);
if (s->nvram[0xf] & CTRL2_24) {
s->nvram[2] = to_bcd(now.tm_hour);
} else {
int tmp = now.tm_hour;
if (tmp % 12 == 0) {
tmp += 12;
}
if (tmp <= 12) {
s->nvram[2] = to_bcd(tmp);
} else {
s->nvram[2] = HOURS_PM | to_bcd(tmp - 12);
}
}
s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
s->nvram[4] = to_bcd(now.tm_mday);
s->nvram[5] = to_bcd(now.tm_mon + 1);
s->nvram[6] = to_bcd(now.tm_year - 100);
}
static void inc_regptr(RS5C372State *s)
{
s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
}
static int rs5c372_event(I2CSlave *i2c, enum i2c_event event)
{
RS5C372State *s = RS5C372(i2c);
switch (event) {
case I2C_START_RECV:
/*
* In h/w, capture happens on any START condition, not just a
* START_RECV, but there is no need to actually capture on
* START_SEND, because the guest can't get at that data
* without going through a START_RECV which would overwrite it.
*/
capture_current_time(s);
s->ptr = 0xf;
break;
case I2C_START_SEND:
s->addr_byte = true;
break;
default:
break;
}
return 0;
}
static uint8_t rs5c372_recv(I2CSlave *i2c)
{
RS5C372State *s = RS5C372(i2c);
uint8_t res;
res = s->nvram[s->ptr];
trace_rs5c372_recv(s->ptr, res);
inc_regptr(s);
return res;
}
static int rs5c372_send(I2CSlave *i2c, uint8_t data)
{
RS5C372State *s = RS5C372(i2c);
if (s->addr_byte) {
s->ptr = data >> 4;
s->tx_format = data & 0xf;
s->addr_byte = false;
return 0;
}
trace_rs5c372_send(s->ptr, data);
if (s->ptr < 7) {
/* Time register. */
struct tm now;
qemu_get_timedate(&now, s->offset);
switch (s->ptr) {
case 0:
now.tm_sec = from_bcd(data & 0x7f);
break;
case 1:
now.tm_min = from_bcd(data & 0x7f);
break;
case 2:
if (s->nvram[0xf] & CTRL2_24) {
now.tm_hour = from_bcd(data & 0x3f);
} else {
int tmp = from_bcd(data & (HOURS_PM - 1));
if (data & HOURS_PM) {
tmp += 12;
}
if (tmp % 12 == 0) {
tmp -= 12;
}
now.tm_hour = tmp;
}
break;
case 3:
{
/*
* The day field is supposed to contain a value in the range
* 1-7. Otherwise behavior is undefined.
*/
int user_wday = (data & 7) - 1;
s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
}
break;
case 4:
now.tm_mday = from_bcd(data & 0x3f);
break;
case 5:
now.tm_mon = from_bcd(data & 0x1f) - 1;
break;
case 6:
now.tm_year = from_bcd(data) + 100;
break;
}
s->offset = qemu_timedate_diff(&now);
} else {
s->nvram[s->ptr] = data;
}
inc_regptr(s);
return 0;
}
static void rs5c372_reset_hold(Object *obj, ResetType type)
{
RS5C372State *s = RS5C372(obj);
/* The clock is running and synchronized with the host */
s->offset = 0;
s->wday_offset = 0;
memset(s->nvram, 0, NVRAM_SIZE);
s->ptr = 0;
s->addr_byte = false;
}
static const VMStateDescription rs5c372_vmstate = {
.name = "rs5c372",
.version_id = 1,
.minimum_version_id = 1,
.fields = (const VMStateField[]) {
VMSTATE_I2C_SLAVE(parent_obj, RS5C372State),
VMSTATE_INT64(offset, RS5C372State),
VMSTATE_UINT8_V(wday_offset, RS5C372State, 2),
VMSTATE_UINT8_ARRAY(nvram, RS5C372State, NVRAM_SIZE),
VMSTATE_UINT8(ptr, RS5C372State),
VMSTATE_UINT8(tx_format, RS5C372State),
VMSTATE_BOOL(addr_byte, RS5C372State),
VMSTATE_END_OF_LIST()
}
};
static void rs5c372_init(Object *obj)
{
qdev_prop_set_uint8(DEVICE(obj), "address", 0x32);
}
static void rs5c372_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
k->event = rs5c372_event;
k->recv = rs5c372_recv;
k->send = rs5c372_send;
dc->vmsd = &rs5c372_vmstate;
rc->phases.hold = rs5c372_reset_hold;
}
static const TypeInfo rs5c372_types[] = {
{
.name = TYPE_RS5C372,
.parent = TYPE_I2C_SLAVE,
.instance_size = sizeof(RS5C372State),
.instance_init = rs5c372_init,
.class_init = rs5c372_class_init,
},
};
DEFINE_TYPES(rs5c372_types)

View file

@ -35,3 +35,7 @@ m48txx_nvram_mem_write(uint32_t addr, uint32_t value) "mem write addr:0x%04x val
# goldfish_rtc.c
goldfish_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
goldfish_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
# rs5c372.c
rs5c372_recv(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] -> 0x%02" PRIx8
rs5c372_send(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] <- 0x%02" PRIx8

View file

@ -3165,7 +3165,7 @@ static void scsi_property_add_specifics(DeviceClass *dc)
ObjectClass *oc = OBJECT_CLASS(dc);
/* The loadparm property is only supported on s390x */
if (arch_type & QEMU_ARCH_S390X) {
if (qemu_arch_available(QEMU_ARCH_S390X)) {
object_class_property_add_str(oc, "loadparm",
scsi_property_get_loadparm,
scsi_property_set_loadparm);

View file

@ -307,6 +307,10 @@ static void sdhci_reset(SDHCIState *s)
s->data_count = 0;
s->stopped_state = sdhc_not_stopped;
s->pending_insert_state = false;
if (s->vendor == SDHCI_VENDOR_FSL) {
s->norintstsen = 0x013f;
s->errintstsen = 0x117f;
}
}
static void sdhci_poweron_reset(DeviceState *dev)
@ -1731,16 +1735,10 @@ usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
case USDHC_VENDOR_SPEC:
s->vendor_spec = value;
switch (s->vendor) {
case SDHCI_VENDOR_IMX:
if (value & USDHC_IMX_FRC_SDCLK_ON) {
s->prnsts &= ~SDHC_IMX_CLOCK_GATE_OFF;
} else {
s->prnsts |= SDHC_IMX_CLOCK_GATE_OFF;
}
break;
default:
break;
if (value & USDHC_IMX_FRC_SDCLK_ON) {
s->prnsts &= ~SDHC_IMX_CLOCK_GATE_OFF;
} else {
s->prnsts |= SDHC_IMX_CLOCK_GATE_OFF;
}
break;

View file

@ -28,7 +28,7 @@
#include "migration/misc.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include CONFIG_DEVICES
#include "hw/acpi/acpi.h"
#include "trace.h"
static const VMStateDescription vmstate_virtio_mem_device_early;
@ -883,10 +883,8 @@ static uint64_t virtio_mem_get_features(VirtIODevice *vdev, uint64_t features,
MachineState *ms = MACHINE(qdev_get_machine());
VirtIOMEM *vmem = VIRTIO_MEM(vdev);
if (ms->numa_state) {
#if defined(CONFIG_ACPI)
if (ms->numa_state && acpi_builtin()) {
virtio_add_feature(&features, VIRTIO_MEM_F_ACPI_PXM);
#endif
}
assert(vmem->unplugged_inaccessible != ON_OFF_AUTO_AUTO);
if (vmem->unplugged_inaccessible == ON_OFF_AUTO_ON) {

View file

@ -150,6 +150,9 @@ struct ACPIREGS {
Notifier wakeup;
};
/* Return whether ACPI subsystem is built in */
bool acpi_builtin(void);
/* PM_TMR */
void acpi_pm_tmr_update(ACPIREGS *ar, bool enable);
void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar);

View file

@ -61,6 +61,18 @@
#define HV_MESSAGE_X64_APIC_EOI 0x80010004
#define HV_MESSAGE_X64_LEGACY_FP_ERROR 0x80010005
/*
* Hyper-V Synthetic debug options MSR
*/
#define HV_X64_MSR_SYNDBG_CONTROL 0x400000F1
#define HV_X64_MSR_SYNDBG_STATUS 0x400000F2
#define HV_X64_MSR_SYNDBG_SEND_BUFFER 0x400000F3
#define HV_X64_MSR_SYNDBG_RECV_BUFFER 0x400000F4
#define HV_X64_MSR_SYNDBG_PENDING_BUFFER 0x400000F5
#define HV_X64_MSR_SYNDBG_OPTIONS 0x400000FF
#define HV_X64_SYNDBG_OPTION_USE_HCALLS BIT(2)
/*
* Message flags
*/

View file

@ -109,7 +109,7 @@ struct SDHCIState {
typedef struct SDHCIState SDHCIState;
#define SDHCI_VENDOR_NONE 0
#define SDHCI_VENDOR_IMX 1
#define SDHCI_VENDOR_FSL 2
/*
* Controller does not provide transfer-complete interrupt when not

View file

@ -1,5 +1,5 @@
#if defined(TARGET_I386) || defined(TARGET_X86_64)
#include "hw/i386/xen_arch_hvm.h"
#elif defined(TARGET_ARM) || defined(TARGET_ARM_64)
#elif defined(TARGET_ARM) || defined(TARGET_AARCH64)
#include "hw/arm/xen_arch_hvm.h"
#endif

View file

@ -25,6 +25,6 @@ enum {
QEMU_ARCH_LOONGARCH = (1 << 23),
};
extern const uint32_t arch_type;
bool qemu_arch_available(unsigned qemu_arch_mask);
#endif

View file

@ -24,18 +24,7 @@
#include "qemu/osdep.h"
#include "system/arch_init.h"
#ifdef TARGET_SPARC
int graphic_width = 1024;
int graphic_height = 768;
int graphic_depth = 8;
#elif defined(TARGET_M68K)
int graphic_width = 800;
int graphic_height = 600;
int graphic_depth = 8;
#else
int graphic_width = 800;
int graphic_height = 600;
int graphic_depth = 32;
#endif
const uint32_t arch_type = QEMU_ARCH;
bool qemu_arch_available(unsigned qemu_arch_mask)
{
return qemu_arch_mask & QEMU_ARCH;
}

24
system/globals-target.c Normal file
View file

@ -0,0 +1,24 @@
/*
* Global variables that should not exist (target specific)
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* SPDX-License-Identifier: MIT
*/
#include "qemu/osdep.h"
#include "system/system.h"
#ifdef TARGET_SPARC
int graphic_width = 1024;
int graphic_height = 768;
int graphic_depth = 8;
#elif defined(TARGET_M68K)
int graphic_width = 800;
int graphic_height = 600;
int graphic_depth = 8;
#else
int graphic_width = 800;
int graphic_height = 600;
int graphic_depth = 32;
#endif

View file

@ -1,6 +1,7 @@
specific_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_true: [files(
'arch_init.c',
'ioport.c',
'globals-target.c',
'memory.c',
'physmem.c',
)])

View file

@ -132,7 +132,7 @@ static const char *qdev_class_get_alias(DeviceClass *dc)
for (i = 0; qdev_alias_table[i].typename; i++) {
if (qdev_alias_table[i].arch_mask &&
!(qdev_alias_table[i].arch_mask & arch_type)) {
!qemu_arch_available(qdev_alias_table[i].arch_mask)) {
continue;
}
@ -218,7 +218,7 @@ static const char *find_typename_by_alias(const char *alias)
for (i = 0; qdev_alias_table[i].alias; i++) {
if (qdev_alias_table[i].arch_mask &&
!(qdev_alias_table[i].arch_mask & arch_type)) {
!qemu_arch_available(qdev_alias_table[i].arch_mask)) {
continue;
}

View file

@ -878,11 +878,11 @@ static void help(int exitcode)
g_get_prgname());
#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \
if ((arch_mask) & arch_type) \
if (qemu_arch_available(arch_mask)) \
fputs(opt_help, stdout);
#define ARCHHEADING(text, arch_mask) \
if ((arch_mask) & arch_type) \
if (qemu_arch_available(arch_mask)) \
puts(stringify(text));
#define DEFHEADING(text) ARCHHEADING(text, QEMU_ARCH_ALL)
@ -2929,7 +2929,7 @@ void qemu_init(int argc, char **argv)
const QEMUOption *popt;
popt = lookup_opt(argc, argv, &optarg, &optind);
if (!(popt->arch_mask & arch_type)) {
if (!qemu_arch_available(popt->arch_mask)) {
error_report("Option not supported for this target");
exit(1);
}

View file

@ -151,18 +151,6 @@
#define HV_X64_MSR_STIMER3_CONFIG 0x400000B6
#define HV_X64_MSR_STIMER3_COUNT 0x400000B7
/*
* Hyper-V Synthetic debug options MSR
*/
#define HV_X64_MSR_SYNDBG_CONTROL 0x400000F1
#define HV_X64_MSR_SYNDBG_STATUS 0x400000F2
#define HV_X64_MSR_SYNDBG_SEND_BUFFER 0x400000F3
#define HV_X64_MSR_SYNDBG_RECV_BUFFER 0x400000F4
#define HV_X64_MSR_SYNDBG_PENDING_BUFFER 0x400000F5
#define HV_X64_MSR_SYNDBG_OPTIONS 0x400000FF
#define HV_X64_SYNDBG_OPTION_USE_HCALLS BIT(2)
/*
* Guest crash notification MSRs
*/

View file

@ -297,6 +297,7 @@ qos_test_ss.add(
'pca9552-test.c',
'pci-test.c',
'pcnet-test.c',
'rs5c372-test.c',
'sdhci-test.c',
'spapr-phb-test.c',
'tmp105-test.c',

View file

@ -0,0 +1,43 @@
/*
* QTest testcase for the RS5C372 RTC
*
* Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
*
* Based on ds1338-test.c
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/bcd.h"
#include "libqos/i2c.h"
#define RS5C372_ADDR 0x32
static void rs5c372_read_date(void *obj, void *data, QGuestAllocator *alloc)
{
QI2CDevice *i2cdev = obj;
uint8_t resp[0x10];
time_t now = time(NULL);
struct tm *utc = gmtime(&now);
i2c_read_block(i2cdev, 0, resp, sizeof(resp));
/* check retrieved time against local time */
g_assert_cmpuint(from_bcd(resp[5]), == , utc->tm_mday);
g_assert_cmpuint(from_bcd(resp[6]), == , 1 + utc->tm_mon);
g_assert_cmpuint(2000 + from_bcd(resp[7]), == , 1900 + utc->tm_year);
}
static void rs5c372_register_nodes(void)
{
QOSGraphEdgeOptions opts = { };
add_qi2c_address(&opts, &(QI2CAddress) { RS5C372_ADDR });
qos_node_create_driver("rs5c372", i2c_device_create);
qos_node_consumes("rs5c372", "i2c-bus", &opts);
qos_add_test("read_date", "rs5c372", rs5c372_read_date, NULL);
}
libqos_init(rs5c372_register_nodes);