From bdd2d1c29798384a8ea08ae98f94d2b177497ac6 Mon Sep 17 00:00:00 2001
From: Venkatesh Srinivas <venkateshs@google.com>
Date: Sat, 27 Apr 2019 17:24:18 +0000
Subject: [PATCH] [kernel][x86] Introduce read_msr_on_cpu

read_msr_on_cpu reads an MSR on a single target CPU. The MSR needs to be
readable without causing a #GP; the read happens in IPI function handler.

ZX-3359

Tested: See 4th patch in patch stack; k cpu rdmsr/wrmsr are added to
exercise these.

Change-Id: I42e6162ba8c2f19872b4d058532b454367e19879
---
 zircon/kernel/arch/x86/BUILD.gn           |  1 +
 zircon/kernel/arch/x86/include/arch/x86.h |  4 ++
 zircon/kernel/arch/x86/msr.cpp            | 55 +++++++++++++++++++++++
 3 files changed, 60 insertions(+)
 create mode 100644 zircon/kernel/arch/x86/msr.cpp

diff --git a/zircon/kernel/arch/x86/BUILD.gn b/zircon/kernel/arch/x86/BUILD.gn
index 5378932bb28..855a184a0c4 100644
--- a/zircon/kernel/arch/x86/BUILD.gn
+++ b/zircon/kernel/arch/x86/BUILD.gn
@@ -91,6 +91,7 @@ library("x86") {
     "mmu.cpp",
     "mmu_mem_types.cpp",
     "mp.cpp",
+    "msr.cpp",
     "ops.S",
     "perf_mon.cpp",
     "proc_trace.cpp",
diff --git a/zircon/kernel/arch/x86/include/arch/x86.h b/zircon/kernel/arch/x86/include/arch/x86.h
index 4b6f5549531..2bb61c0ae0c 100644
--- a/zircon/kernel/arch/x86/include/arch/x86.h
+++ b/zircon/kernel/arch/x86/include/arch/x86.h
@@ -10,6 +10,7 @@
 #pragma once
 
 #include <cpuid.h>
+#include <kernel/cpu.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <sys/types.h>
@@ -326,6 +327,9 @@ static inline uint32_t read_msr32(uint32_t msr_id) {
 
 zx_status_t read_msr_safe(uint32_t msr_id, uint64_t* val);
 
+// Read msr |msr_id| on CPU |cpu| and return the 64-bit value.
+uint64_t read_msr_on_cpu(cpu_num_t cpu, uint32_t msr_id);
+
 static inline void write_msr(uint32_t msr_id, uint64_t msr_write_val) {
     __asm__ __volatile__(
         "wrmsr \n\t"
diff --git a/zircon/kernel/arch/x86/msr.cpp b/zircon/kernel/arch/x86/msr.cpp
new file mode 100644
index 00000000000..1ef338a2734
--- /dev/null
+++ b/zircon/kernel/arch/x86/msr.cpp
@@ -0,0 +1,55 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/MIT
+
+#include <assert.h>
+#include <debug.h>
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <trace.h>
+#include <zircon/compiler.h>
+
+#include <arch/mp.h>
+#include <arch/ops.h>
+#include <arch/x86.h>
+#include <arch/x86/apic.h>
+#include <arch/x86/descriptor.h>
+#include <arch/x86/feature.h>
+#include <arch/x86/interrupts.h>
+#include <arch/x86/mp.h>
+#include <arch/x86/tsc.h>
+#include <dev/hw_rng.h>
+#include <dev/interrupt.h>
+#include <kernel/event.h>
+#include <kernel/timer.h>
+#include <platform.h>
+#include <zircon/types.h>
+
+
+struct read_msr_context {
+    uint32_t msr;
+    uint64_t val;
+};
+
+static void read_msr_on_cpu_task(void* raw_context) {
+    auto* const context = reinterpret_cast<struct read_msr_context*>(raw_context);
+    context->val = read_msr(context->msr);
+}
+
+uint64_t read_msr_on_cpu(cpu_num_t cpu, uint32_t msr_id) {
+    struct read_msr_context context = {};
+    cpu_mask_t mask = {};
+
+    if (!mp_is_cpu_online(cpu)) {
+        return -1;
+    }
+
+    context.msr = msr_id;
+    mask |= cpu_num_to_mask(cpu);
+    mp_sync_exec(MP_IPI_TARGET_MASK, mask, read_msr_on_cpu_task,
+                 reinterpret_cast<void*>(&context));
+    return context.val;
+}
-- 
GitLab