x86: Allow getting/setting p/c-states via devarch

We don't offer any support here.  The user needs to know by other means
what values to set, such as by reading MSR_TURBO_LIMIT, Intel docs, etc.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/arch/x86/devarch.c b/kern/arch/x86/devarch.c
index 8986f20..b23d169 100644
--- a/kern/arch/x86/devarch.c
+++ b/kern/arch/x86/devarch.c
@@ -66,6 +66,8 @@
 	Qrealmem,
 	Qmsr,
 	Qperf,
+	Qcstate,
+	Qpstate,
 
 	Qmax,
 };
@@ -85,6 +87,8 @@
 	{"realmem", {Qrealmem, 0}, 0, 0444},
 	{"msr", {Qmsr, 0}, 0, 0666},
 	{"perf", {Qperf, 0}, 0, 0666},
+	{"c-state", {Qcstate, 0}, 0, 0666},
+	{"p-state", {Qpstate, 0}, 0, 0666},
 };
 /* White list entries needs to be ordered by start address, and never overlap.
  */
@@ -588,6 +592,10 @@
 			qunlock(&pc->resp_lock);
 
 			return n;
+		case Qcstate:
+			return readnum_hex(offset, a, n, get_cstate(), NUMSIZE32);
+		case Qpstate:
+			return readnum_hex(offset, a, n, get_pstate(), NUMSIZE32);
 		}
 		default:
 			error(EINVAL, ERROR_FIXME);
@@ -621,6 +629,32 @@
 	return n;
 }
 
+static ssize_t cstate_write(void *ubuf, size_t len, off64_t off)
+{
+	set_cstate(strtoul_from_ubuf(ubuf, len, off));
+	/* Poke the other cores so they use the new C-state. */
+	send_broadcast_ipi(I_POKE_CORE);
+	return len;
+}
+
+static void __smp_set_pstate(void *arg)
+{
+	unsigned int val = (unsigned int)(unsigned long)arg;
+
+	set_pstate(val);
+}
+
+static ssize_t pstate_write(void *ubuf, size_t len, off64_t off)
+{
+	struct core_set all_cores;
+
+	core_set_init(&all_cores);
+	core_set_fill_available(&all_cores);
+	smp_do_in_cores(&all_cores, __smp_set_pstate,
+	                (void*)strtoul_from_ubuf(ubuf, len, off));
+	return len;
+}
+
 static long archwrite(struct chan *c, void *a, long n, int64_t offset)
 {
 	char *p;
@@ -698,6 +732,10 @@
 
 			return arch_perf_write(pc, a, n);
 		}
+		case Qcstate:
+			return cstate_write(a, n, 0);
+		case Qpstate:
+			return pstate_write(a, n, 0);
 		default:
 			error(EINVAL, ERROR_FIXME);
 	}