                                                                                                                                                                                                                                                               
Delivered-To: blauwirbel@gmail.com
Received: by 10.143.166.2 with SMTP id t2cs70055wfo;
        Thu, 28 Aug 2008 10:21:47 -0700 (PDT)
Received: by 10.150.144.9 with SMTP id r9mr2510735ybd.100.1219944106983;
        Thu, 28 Aug 2008 10:21:46 -0700 (PDT)
Return-Path: <qemu-devel-bounces+blauwirbel=gmail.com@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [199.232.76.165])
        by mx.google.com with ESMTP id v26si1419186ele.2.2008.08.28.10.21.46;
        Thu, 28 Aug 2008 10:21:46 -0700 (PDT)
Received-SPF: pass (google.com: domain of qemu-devel-bounces+blauwirbel=gmail.com@nongnu.org designates 199.232.76.165 as permitted sender) client-ip=199.232.76.165;
Authentication-Results: mx.google.com; spf=pass (google.com: domain of qemu-devel-bounces+blauwirbel=gmail.com@nongnu.org designates 199.232.76.165 as permitted sender) smtp.mail=qemu-devel-bounces+blauwirbel=gmail.com@nongnu.org
Received: from localhost ([127.0.0.1]:34146 helo=lists.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.43)
	id 1KYkv4-0003Aq-GL
	for blauwirbel@gmail.com; Thu, 28 Aug 2008 13:04:26 -0400
Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43)
	id 1KYkk6-0000QQ-CF
	for qemu-devel@nongnu.org; Thu, 28 Aug 2008 12:53:06 -0400
Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43)
	id 1KYkk5-0000PZ-Jt
	for qemu-devel@nongnu.org; Thu, 28 Aug 2008 12:53:05 -0400
Received: from [199.232.76.173] (port=36295 helo=monty-python.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.43) id 1KYkk5-0000PK-D5
	for qemu-devel@nongnu.org; Thu, 28 Aug 2008 12:53:05 -0400
Received: from il.qumranet.com ([212.179.150.194]:48346)
	by monty-python.gnu.org with esmtp (Exim 4.60)
	(envelope-from <gleb@qumranet.com>) id 1KYkk4-0004sq-69
	for qemu-devel@nongnu.org; Thu, 28 Aug 2008 12:53:05 -0400
Received: from gleb-debian.qumranet.com (gleb-debian.qumranet.com.qumranet.com
	[172.16.15.143])
	by il.qumranet.com (Postfix) with ESMTP id BCB61250DB2
	for <qemu-devel@nongnu.org>; Thu, 28 Aug 2008 19:53:02 +0300 (IDT)
Received: from gleb-debian.qumranet.com.qumranet.com (localhost [127.0.0.1])
	by gleb-debian.qumranet.com (Postfix) with ESMTP id BBC0718D48F
	for <qemu-devel@nongnu.org>; Thu, 28 Aug 2008 19:53:02 +0300 (IDT)
From: Gleb Natapov <gleb@qumranet.com>
To: qemu-devel@nongnu.org
Date: Thu, 28 Aug 2008 19:53:02 +0300
Message-ID: <20080828165302.22851.72018.stgit@gleb-debian.qumranet.com.qumranet.com>
In-Reply-To: <20080828165232.22851.77678.stgit@gleb-debian.qumranet.com.qumranet.com>
References: <20080828165232.22851.77678.stgit@gleb-debian.qumranet.com.qumranet.com>
User-Agent: StGIT/0.14.2
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
X-detected-kernel: by monty-python.gnu.org: Linux 2.6 (newer, 1)
Subject: [Qemu-devel] [PATCH v3 6/6] Pass cpu speed into SM BIOS.
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.5
Precedence: list
Reply-To: qemu-devel@nongnu.org
List-Id: qemu-devel.nongnu.org
List-Unsubscribe: <http://lists.nongnu.org/mailman/listinfo/qemu-devel>,
	<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <http://lists.gnu.org/pipermail/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <http://lists.nongnu.org/mailman/listinfo/qemu-devel>,
	<mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Sender: qemu-devel-bounces+blauwirbel=gmail.com@nongnu.org
Errors-To: qemu-devel-bounces+blauwirbel=gmail.com@nongnu.org

Signed-off-by: Gleb Natapov <gleb@qumranet.com>
---

 hw/pc.c |   90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 90 insertions(+), 0 deletions(-)

Index: qemu/hw/pc.c
===================================================================
--- qemu.orig/hw/pc.c	2008-08-31 12:35:25.000000000 +0000
+++ qemu/hw/pc.c	2008-08-31 12:35:42.000000000 +0000
@@ -49,6 +49,8 @@
 
 #define MAX_IDE_BUS 2
 
+#define FW_CFG_PC_CPUSPEED (FW_CFG_ARCH_LOCAL + 0x00)
+
 static fdctrl_t *floppy_controller;
 static RTCState *rtc_state;
 static PITState *pit;
@@ -369,6 +371,89 @@
     return ioport_get_a20() << 1;
 }
 
+#ifdef __linux__
+/* get_freq () function is taken from conky source code */
+#define CPUFREQ_PREFIX "/sys/devices/system/cpu"
+#define CPUFREQ_POSTFIX "cpufreq/scaling_cur_freq"
+
+/* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
+static double get_freq(int divisor, unsigned int cpu)
+{
+	FILE *f;
+	char frequency[32];
+	char s[256];
+	double freq = 0;
+
+	if (divisor <= 0)
+		return 0;
+
+	snprintf(s, 256, "%s/cpu%d/%s", CPUFREQ_PREFIX, cpu - 1, CPUFREQ_POSTFIX);
+	f = fopen(s, "r");
+	if (f) {
+		/* if there's a cpufreq /sys node, read the current frequency from
+		 * this node and divide by 1000 to get Mhz. */
+		if (fgets(s, sizeof(s), f)) {
+			s[strlen(s) - 1] = '\0';
+			freq = strtod(s, NULL);
+		}
+		fclose(f);
+		return (freq / 1000) / divisor;
+	}
+
+	// open the CPU information file
+	f = fopen("/proc/cpuinfo", "r");
+	if (!f) {
+		perror("Failed to access '/proc/cpuinfo' at get_freq()");
+		return 0;
+	}
+
+	// read the file
+	while (fgets(s, sizeof(s), f) != NULL) {
+
+#if defined(__i386) || defined(__x86_64)
+		// and search for the cpu mhz
+		if (strncmp(s, "cpu MHz", 7) == 0 && cpu == 0) {
+#else
+#if defined(__alpha)
+		// different on alpha
+		if (strncmp(s, "cycle frequency [Hz]", 20) == 0 && cpu == 0) {
+#else
+		// this is different on ppc for some reason
+		if (strncmp(s, "clock", 5) == 0 && cpu == 0) {
+#endif // defined(__alpha)
+#endif // defined(__i386) || defined(__x86_64)
+
+			// copy just the number
+			strcpy(frequency, strchr(s, ':') + 2);
+#if defined(__alpha)
+			// strip " est.\n"
+			frequency[strlen(frequency) - 6] = '\0';
+			// kernel reports in Hz
+			freq = strtod(frequency, NULL) / 1000000;
+#else
+			// strip \n
+			frequency[strlen(frequency) - 1] = '\0';
+			freq = strtod(frequency, NULL);
+#endif
+			break;
+		}
+		if (strncmp(s, "processor", 9) == 0) {
+			cpu--;
+			continue;
+		}
+	}
+
+	fclose(f);
+	return freq / divisor;
+}
+#else
+static double get_freq(int divisor, unsigned int cpu)
+{
+    return 0;
+}
+#endif
+
+
 /***********************************************************/
 /* Bochs BIOS debug ports */
 
@@ -418,6 +503,7 @@
 
 static void bochs_bios_init(void)
 {
+    uint16_t cpu_speed;
     void *fw_cfg;
 
     register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL);
@@ -433,6 +519,8 @@
 
     fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, 0);
     fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+    cpu_speed = (uint16_t)get_freq(1, 1);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_PC_CPUSPEED, cpu_speed);
 }
 
 /* Generate an initial boot sector which sets state and jump to
