smbus: Add generic storage device

This commit is contained in:
Mike 2020-10-29 15:59:51 -05:00 committed by mborgerson
parent 5cc4568dfe
commit 7c8a7d1d16
6 changed files with 258 additions and 175 deletions

View File

@ -1,7 +1,7 @@
obj-y += xbox.o
obj-y += chihiro.o
obj-y += xbox_pci.o acpi_xbox.o
obj-y += amd_smbus.o smbus_xbox_smc.o smbus_cx25871.o smbus_adm1032.o
obj-y += amd_smbus.o smbus_xbox_smc.o smbus_cx25871.o smbus_adm1032.o smbus_storage.o
obj-y += nvnet.o
obj-y += mcpx_apu.o mcpx_aci.o
obj-y += lpc47m157.o

View File

@ -274,48 +274,6 @@ static void chihiro_ide_interface_init(const char *rom_file,
#endif
}
/* Placeholder blank eeprom for chihiro:
* Serial number 000000000000
* Mac address 00:00:00:00:00:00
* ...etc.
*/
/* FIXME: This should be passed in via machine args,
* please fix when xbox is fixed */
static const uint8_t eeprom[] = {
0xA7, 0x65, 0x60, 0x76, 0xB7, 0x2F, 0xFE, 0xD8,
0x20, 0xBC, 0x8B, 0x15, 0x13, 0xBF, 0x73, 0x9C,
0x8C, 0x3F, 0xD8, 0x07, 0x75, 0x55, 0x5F, 0x8B,
0x09, 0xD1, 0x25, 0xD1, 0x1A, 0xA2, 0xD5, 0xB7,
0x01, 0x7D, 0x9A, 0x31, 0xCD, 0x9C, 0x83, 0x6B,
0x2C, 0xAB, 0xAD, 0x6F, 0xAC, 0x36, 0xDE, 0xEF,
0x6F, 0x6E, 0x2F, 0x6F, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static void chihiro_init(MachineState *machine)
{
const char *mediaboard_rom_file = object_property_get_str(
@ -326,7 +284,7 @@ static void chihiro_init(MachineState *machine)
mediaboard_filesystem_file);
ISABus *isa_bus;
xbox_init_common(machine, eeprom, NULL, &isa_bus);
xbox_init_common(machine, NULL, &isa_bus);
isa_create_simple(isa_bus, "chihiro-lpc");
}

224
hw/xbox/smbus_storage.c Normal file
View File

@ -0,0 +1,224 @@
/*
* QEMU SMBus Generic Storage Device
*
* Copyright (c) 2020 Mike Davis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/qdev-properties.h"
#include "hw/i2c/i2c.h"
#include "hw/i2c/smbus_slave.h"
#include "smbus.h"
#include "qapi/error.h"
#include "hw/loader.h"
#include "migration/vmstate.h"
#define TYPE_SMBUS_STORAGE "smbus-storage"
#define SMBUS_STORAGE(obj) OBJECT_CHECK(SMBusStorageDevice, (obj), \
TYPE_SMBUS_STORAGE)
//#define DEBUG
#ifdef DEBUG
# define DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
#else
# define DPRINTF(format, ...) do { } while (0)
#endif
typedef struct SMBusStorageDevice {
SMBusDevice smbusdev;
char* file;
uint8_t *data;
uint32_t size;
uint8_t addr;
uint32_t offset;
bool persist;
} SMBusStorageDevice;
// FIXME: remove, file should be generated upstream if unspecified
const uint8_t default_eeprom[] = {
0xe3, 0x1c, 0x5c, 0x23, 0x6a, 0x58, 0x68, 0x37,
0xb7, 0x12, 0x26, 0x6c, 0x99, 0x11, 0x30, 0xd1,
0xe2, 0x3e, 0x4d, 0x56, 0xf7, 0x73, 0x2b, 0x73,
0x85, 0xfe, 0x7f, 0x0a, 0x08, 0xef, 0x15, 0x3c,
0x77, 0xee, 0x6d, 0x4e, 0x93, 0x2f, 0x28, 0xee,
0xf8, 0x61, 0xf7, 0x94, 0x17, 0x1f, 0xfc, 0x11,
0x0b, 0x84, 0x44, 0xed, 0x31, 0x30, 0x35, 0x35,
0x38, 0x31, 0x31, 0x31, 0x34, 0x30, 0x30, 0x33,
0x00, 0x50, 0xf2, 0x4f, 0x65, 0x52, 0x00, 0x00,
0x0a, 0x1e, 0x35, 0x33, 0x71, 0x85, 0x31, 0x4d,
0x59, 0x12, 0x38, 0x48, 0x1c, 0x91, 0x53, 0x60,
0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x75, 0x61, 0x57, 0xfb, 0x2c, 0x01, 0x00, 0x00,
0x45, 0x53, 0x54, 0x00, 0x45, 0x44, 0x54, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0a, 0x05, 0x00, 0x02, 0x04, 0x01, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc4, 0xff, 0xff, 0xff,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static void smbus_storage_realize(DeviceState *dev, Error **errp)
{
SMBusStorageDevice *s = SMBUS_STORAGE(dev);
qdev_prop_set_uint8(dev, "address", s->addr);
s->data = g_malloc0(s->size);
s->offset = 0;
if (s->file) {
int size = get_image_size(s->file);
if (size != s->size) {
error_setg(errp, "%s: file '%s' size of %d, expected %d\n",
__func__, s->file, size, s->size);
return;
}
int fd = open(s->file, O_RDONLY | O_BINARY);
if (fd < 0) {
error_setg(errp, "%s: file '%s' could not be opened\n",
__func__, s->file);
return;
}
int rc = read(fd, s->data, s->size);
if (rc != s->size) {
error_setg(errp, "%s: file '%s' read failure\n", __func__, s->file);
close(fd);
return;
}
close(fd);
} else {
// FIXME: remove, file should be generated upstream if unspecified
memcpy(s->data, default_eeprom, MIN(s->size, sizeof(default_eeprom)));
}
}
static int smbus_storage_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len)
{
SMBusStorageDevice *s = SMBUS_STORAGE(dev);
DPRINTF("%s: addr=0x%02x cmd=0x%02x val=0x%02x\n",
__func__, s->addr, buf[0], buf[1]);
/* len is guaranteed to be > 0 */
s->offset = buf[0];
buf++;
len--;
bool changed = false;
for (; len > 0; len--) {
changed = true;
s->data[s->offset] = *buf++;
DPRINTF("%s: addr=0x%02x off=0x%02x, data=0x%02x\n",
__func__, s->addr, s->offset, s->data[s->offset]);
s->offset = (s->offset + 1) % s->size;
}
if (changed && s->file && s->persist) {
int fd = open(s->file, O_WRONLY | O_BINARY);
if (fd < 0) {
DPRINTF("%s: file '%s' could not be opened\n", __func__, s->file);
return -1;
}
int wc = write(fd, s->data, s->size);
if (wc != s->size) {
DPRINTF( "%s: file '%s' write failure\n", __func__, s->file);
close(fd);
return -1;
}
close(fd);
}
return 0;
}
static uint8_t smbus_storage_receive_byte(SMBusDevice *dev)
{
SMBusStorageDevice *s = SMBUS_STORAGE(dev);
uint8_t val = s->data[s->offset];
DPRINTF("%s: addr=0x%02x off=0x%02x val=0x%02x\n",
__func__, s->addr, s->offset, val);
s->offset = (s->offset + 1) % s->size;
return val;
}
static const VMStateDescription vmstate_smbus_storage = {
.name = "smbus-storage",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_SMBUS_DEVICE(smbusdev, SMBusStorageDevice),
VMSTATE_VBUFFER_UINT32(data, SMBusStorageDevice, 1, NULL, size),
VMSTATE_UINT32(offset, SMBusStorageDevice),
VMSTATE_END_OF_LIST()
}
};
// default xbox eeprom with persistence
static Property smbus_storage_props[] = {
DEFINE_PROP_UINT8("addr", SMBusStorageDevice, addr, 0x54),
DEFINE_PROP_UINT32("size", SMBusStorageDevice, size, 256),
DEFINE_PROP_BOOL("persist", SMBusStorageDevice, persist, true),
DEFINE_PROP_STRING("file", SMBusStorageDevice, file),
DEFINE_PROP_END_OF_LIST()
};
static void smbus_storage_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
dc->vmsd = &vmstate_smbus_storage;
dc->realize = smbus_storage_realize;
sc->receive_byte = smbus_storage_receive_byte;
sc->write_data = smbus_storage_write_data;
device_class_set_props(dc, smbus_storage_props);
}
static TypeInfo smbus_storage_info = {
.name = TYPE_SMBUS_STORAGE,
.parent = TYPE_SMBUS_DEVICE,
.instance_size = sizeof(SMBusStorageDevice),
.class_init = smbus_storage_class_initfn
};
static void smbus_storage_register_devices(void)
{
type_register_static(&smbus_storage_info);
}
type_init(smbus_storage_register_devices)

View File

@ -59,43 +59,6 @@
#define MAX_IDE_BUS 2
// XBOX_TODO: Should be passed in through configuration
/* bunnie's eeprom */
const uint8_t default_eeprom[] = {
0xe3, 0x1c, 0x5c, 0x23, 0x6a, 0x58, 0x68, 0x37,
0xb7, 0x12, 0x26, 0x6c, 0x99, 0x11, 0x30, 0xd1,
0xe2, 0x3e, 0x4d, 0x56, 0xf7, 0x73, 0x2b, 0x73,
0x85, 0xfe, 0x7f, 0x0a, 0x08, 0xef, 0x15, 0x3c,
0x77, 0xee, 0x6d, 0x4e, 0x93, 0x2f, 0x28, 0xee,
0xf8, 0x61, 0xf7, 0x94, 0x17, 0x1f, 0xfc, 0x11,
0x0b, 0x84, 0x44, 0xed, 0x31, 0x30, 0x35, 0x35,
0x38, 0x31, 0x31, 0x31, 0x34, 0x30, 0x30, 0x33,
0x00, 0x50, 0xf2, 0x4f, 0x65, 0x52, 0x00, 0x00,
0x0a, 0x1e, 0x35, 0x33, 0x71, 0x85, 0x31, 0x4d,
0x59, 0x12, 0x38, 0x48, 0x1c, 0x91, 0x53, 0x60,
0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x75, 0x61, 0x57, 0xfb, 0x2c, 0x01, 0x00, 0x00,
0x45, 0x53, 0x54, 0x00, 0x45, 0x44, 0x54, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0a, 0x05, 0x00, 0x02, 0x04, 0x01, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc4, 0xff, 0xff, 0xff,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* FIXME: Clean this up and propagate errors to UI */
static void xbox_flash_init(MemoryRegion *rom_memory)
{
@ -233,66 +196,13 @@ static void xbox_memory_init(PCMachineState *pcms,
pc_system_flash_cleanup_unused(pcms);
}
uint8_t *load_eeprom(void)
{
char *filename;
int fd;
int rc;
int eeprom_file_size;
const int eeprom_size = 256;
uint8_t *eeprom_data = g_malloc(eeprom_size);
const char *eeprom_file = object_property_get_str(qdev_get_machine(),
"eeprom", NULL);
if ((eeprom_file != NULL) && *eeprom_file) {
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, eeprom_file);
assert(filename);
eeprom_file_size = get_image_size(filename);
if (eeprom_size != eeprom_file_size) {
fprintf(stderr,
"qemu: EEPROM file size != %d bytes. (Is %d bytes)\n",
eeprom_size, eeprom_file_size);
g_free(filename);
exit(1);
return NULL;
}
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0) {
fprintf(stderr, "qemu: EEPROM file '%s' could not be opened.\n", filename);
g_free(filename);
exit(1);
return NULL;
}
rc = read(fd, eeprom_data, eeprom_size);
if (rc != eeprom_size) {
fprintf(stderr, "qemu: Could not read the full EEPROM file.\n");
close(fd);
g_free(filename);
exit(1);
return NULL;
}
close(fd);
g_free(filename);
} else {
memcpy(eeprom_data, default_eeprom, eeprom_size);
}
return eeprom_data;
}
/* PC hardware initialisation */
static void xbox_init(MachineState *machine)
{
uint8_t *eeprom_data = load_eeprom();
xbox_init_common(machine, eeprom_data, NULL, NULL);
xbox_init_common(machine, NULL, NULL);
}
void xbox_init_common(MachineState *machine,
const uint8_t *eeprom,
PCIBus **pci_bus_out,
ISABus **isa_bus_out)
{
@ -394,10 +304,6 @@ void xbox_init_common(MachineState *machine,
}
/* smbus devices */
uint8_t *eeprom_buf = g_malloc0(256);
memcpy(eeprom_buf, eeprom, 256);
smbus_eeprom_init_one(smbus, 0x54, eeprom_buf);
smbus_xbox_smc_init(smbus, 0x10);
smbus_cx25871_init(smbus, 0x45);
smbus_adm1032_init(smbus, 0x4c);
@ -475,22 +381,6 @@ static void machine_set_bootrom(Object *obj, const char *value,
ms->bootrom = g_strdup(value);
}
static char *machine_get_eeprom(Object *obj, Error **errp)
{
XboxMachineState *ms = XBOX_MACHINE(obj);
return g_strdup(ms->eeprom);
}
static void machine_set_eeprom(Object *obj, const char *value,
Error **errp)
{
XboxMachineState *ms = XBOX_MACHINE(obj);
g_free(ms->eeprom);
ms->eeprom = g_strdup(value);
}
static char *machine_get_avpack(Object *obj, Error **errp)
{
XboxMachineState *ms = XBOX_MACHINE(obj);
@ -534,11 +424,6 @@ static inline void xbox_machine_initfn(Object *obj)
object_property_set_description(obj, "bootrom",
"Xbox bootrom file");
object_property_add_str(obj, "eeprom", machine_get_eeprom,
machine_set_eeprom);
object_property_set_description(obj, "eeprom",
"Xbox EEPROM file");
object_property_add_str(obj, "avpack", machine_get_avpack,
machine_set_avpack);
object_property_set_description(obj, "avpack",

View File

@ -25,10 +25,7 @@
#define MAX_IDE_BUS 2
uint8_t *load_eeprom(void);
void xbox_init_common(MachineState *machine,
const uint8_t *eeprom,
PCIBus **pci_bus_out,
ISABus **isa_bus_out);
@ -46,7 +43,6 @@ typedef struct XboxMachineState {
/*< public >*/
char *bootrom;
char *eeprom;
char *avpack;
bool short_animation;
} XboxMachineState;

View File

@ -2917,25 +2917,45 @@ void qemu_init(int argc, char **argv, char **envp)
bootrom_path = "";
}
const char *eeprom_path;
xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_EEPROM_PATH, &eeprom_path);
if (strlen(eeprom_path) > 0 && xemu_check_file(eeprom_path)) {
char *msg = g_strdup_printf("Failed to open EEPROM file '%s'. Please check machine settings.", eeprom_path);
xemu_queue_error_message(msg);
g_free(msg);
eeprom_path = "";
}
int short_animation;
xemu_settings_get_bool(XEMU_SETTINGS_SYSTEM_SHORTANIM, &short_animation);
fake_argv[fake_argc++] = g_strdup_printf("xbox%s%s%s%s",
fake_argv[fake_argc++] = g_strdup_printf("xbox%s%s%s",
strlen(bootrom_path) > 0 ? g_strdup_printf(",bootrom=%s", bootrom_path) : "", // Leak
strlen(eeprom_path) > 0 ? g_strdup_printf(",eeprom=%s", eeprom_path) : "", // Leak
short_animation ? ",short-animation" : "",
",kernel-irqchip=off"
);
const char *eeprom_path;
xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_EEPROM_PATH, &eeprom_path);
// Sanity check EEPROM file
if (strlen(eeprom_path) > 0) {
int eeprom_size = get_image_size(eeprom_path);
if (eeprom_size < 0) {
char *msg = g_strdup_printf("Failed to open EEPROM file '%s'. "
"Please check machine settings.", eeprom_path);
xemu_queue_error_message(msg);
g_free(msg);
eeprom_path = "";
} else if (eeprom_size != 256) {
char *msg = g_strdup_printf(
"Invalid EEPROM file '%s' size of %d; should be 256 bytes. "
"Please check machine settings.", eeprom_path, eeprom_size);
xemu_queue_error_message(msg);
g_free(msg);
eeprom_path = "";
}
}
fake_argv[fake_argc++] = strdup("-device");
if (strlen(eeprom_path) > 0) {
fake_argv[fake_argc++] = g_strdup_printf("smbus-storage,file=%s",
eeprom_path);
} else {
fake_argv[fake_argc++] = strdup("smbus-storage");
}
const char *flash_path;
xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_FLASH_PATH, &flash_path);
autostart = 0; // Do not auto-start the machine without a valid BIOS file