From patchwork Thu Sep 16 13:58:37 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mathias Krause X-Patchwork-Id: 64976 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 809BA1007DC for ; Fri, 17 Sep 2010 00:01:20 +1000 (EST) Received: from localhost ([127.0.0.1]:44971 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OwF1Z-0005Ix-2d for incoming@patchwork.ozlabs.org; Thu, 16 Sep 2010 10:01:17 -0400 Received: from [140.186.70.92] (port=60612 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OwEz3-0004QM-HV for qemu-devel@nongnu.org; Thu, 16 Sep 2010 09:58:51 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OwEz2-0005sF-23 for qemu-devel@nongnu.org; Thu, 16 Sep 2010 09:58:41 -0400 Received: from grimli.r00tworld.net ([83.169.44.195]:56451 helo=mail.r00tworld.net) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OwEz1-0005rt-Od for qemu-devel@nongnu.org; Thu, 16 Sep 2010 09:58:40 -0400 Received: by mail.r00tworld.net (Postfix, from userid 1000) id 18BE6115901EC; Thu, 16 Sep 2010 15:58:37 +0200 (CEST) From: Mathias Krause To: qemu-devel@nongnu.org Date: Thu, 16 Sep 2010 15:58:37 +0200 Message-Id: <1284645517-32743-1-git-send-email-mathias.krause@secunet.com> X-Mailer: git-send-email 1.5.6.5 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) Cc: Mathias Krause Subject: [Qemu-devel] [PATCH] CMOS file support X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org In contrast to the BIOS and Option ROMs the CMOS content cannot be predefined by the user. Also the amount of useable CMOS ARM is pretty limited, even though the amount of CMOS bytes emulated by qemu is already twice as much as of the original MC146818. Nevertheless those limitations are pretty annoying when testing different BIOS replacement implementations like coreboot in combination with FILO that use CMOS values above the basic RTC range for its own purpose to, e.g., control the boot device order using a string containing the boot devices to probe. This patch adds support to specify a file to read the initial CMOS content from. It also increases the CMOS size to 256 bytes and implements access to the extended memory range via I/O ports 0x72 and 0x73. Use it like: `qemu -global mc146818rtc.file=cmos.bin ...' where cmos.bin is a binary file, sized 256 bytes containing the CMOS RAM. Signed-off-by: Mathias Krause --- hw/mc146818rtc.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 56 insertions(+), 6 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 2b91fa8..9f215e0 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -78,12 +78,16 @@ #define REG_C_PF 0x40 #define REG_C_AF 0x20 +#define BASE_PORT 0x70 +#define CMOS_SIZE 256 + typedef struct RTCState { ISADevice dev; - uint8_t cmos_data[128]; + uint8_t cmos_data[CMOS_SIZE]; uint8_t cmos_index; struct tm current_tm; int32_t base_year; + char *file; qemu_irq irq; qemu_irq sqw_irq; int it_shift; @@ -206,7 +210,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) RTCState *s = opaque; if ((addr & 1) == 0) { - s->cmos_index = data & 0x7f; + s->cmos_index = data & (addr == BASE_PORT ? 0x7f : 0xff); } else { CMOS_DPRINTF("cmos: write index=0x%02x val=0x%02x\n", s->cmos_index, data); @@ -581,7 +585,6 @@ static void rtc_reset(void *opaque) static int rtc_initfn(ISADevice *dev) { RTCState *s = DO_UPCAST(RTCState, dev, dev); - int base = 0x70; s->cmos_data[RTC_REG_A] = 0x26; s->cmos_data[RTC_REG_B] = 0x02; @@ -603,14 +606,57 @@ static int rtc_initfn(ISADevice *dev) qemu_get_clock(rtc_clock) + (get_ticks_per_sec() * 99) / 100; qemu_mod_timer(s->second_timer2, s->next_second_time); - register_ioport_write(base, 2, 1, cmos_ioport_write, s); - register_ioport_read(base, 2, 1, cmos_ioport_read, s); + register_ioport_write(BASE_PORT, 4, 1, cmos_ioport_write, s); + register_ioport_read(BASE_PORT, 4, 1, cmos_ioport_read, s); - qdev_set_legacy_instance_id(&dev->qdev, base, 2); + qdev_set_legacy_instance_id(&dev->qdev, BASE_PORT, 2); qemu_register_reset(rtc_reset, s); return 0; } +static long get_file_size(FILE *f) +{ + long where, size; + + /* XXX: on Unix systems, using fstat() probably makes more sense */ + + where = ftell(f); + fseek(f, 0, SEEK_END); + size = ftell(f); + fseek(f, where, SEEK_SET); + + return size; +} + +static void cmos_load_from_file(RTCState *s, const char *file) +{ + const char *err_msg = NULL; + FILE *f; + + if (!(f = fopen(file, "r"))) { + err_msg = strerror(errno); + goto err; + } + + if (get_file_size(f) != CMOS_SIZE) { + err_msg = "invalid file size"; + goto err; + } + + if (fread(s->cmos_data, 1, CMOS_SIZE, f) != CMOS_SIZE) { + err_msg = strerror(errno); + goto err; + } + CMOS_DPRINTF("cmos: initialized from '%s'\n", file); + + fclose(f); + + return; +err: + fprintf(stderr, "qemu: could not load CMOS '%s': %s\n", file, err_msg); + exit(1); +} + ISADevice *rtc_init(int base_year, qemu_irq intercept_irq) { ISADevice *dev; @@ -618,6 +664,9 @@ ISADevice *rtc_init(int base_year, qemu_irq intercept_irq) dev = isa_create("mc146818rtc"); s = DO_UPCAST(RTCState, dev, dev); + if (s->file != NULL) { + cmos_load_from_file(s, s->file); + } qdev_prop_set_int32(&dev->qdev, "base_year", base_year); qdev_init_nofail(&dev->qdev); if (intercept_irq) { @@ -636,6 +685,7 @@ static ISADeviceInfo mc146818rtc_info = { .init = rtc_initfn, .qdev.props = (Property[]) { DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980), + DEFINE_PROP_STRING("file", RTCState, file), DEFINE_PROP_END_OF_LIST(), } };