[kernel][arch] Add <lib/arch/x86/msr.h> API
This provides access to x86 Model-Specific Registers in the
lib/arch API. For now, only a few trivial ones are defined.
This also generates the <lib/arch/x86/msr-asm.h> header that
can be used by assembly code.
Along the way, clean up uses of lib/arch in host code by
separating the host case from the specific target machine cases.
A new "host" sublibrary fills in stubs for the machine-dependent
headers so that machine-independent headers can be used on host.
Test: mostly refactor, still builds; new assembly constants used by later change
Change-Id: I36d21d86beee19d2064f109fe1f7f945c219c559
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/403058
Commit-Queue: Joshua Seaton <joshuaseaton@google.com>
Reviewed-by: Tess Eisenberger <teisenbe@google.com>
Testability-Review: Tess Eisenberger <teisenbe@google.com>
diff --git a/zircon/kernel/lib/arch/BUILD.zircon.gn b/zircon/kernel/lib/arch/BUILD.zircon.gn
index 6cabdaa..9fa58df5 100644
--- a/zircon/kernel/lib/arch/BUILD.zircon.gn
+++ b/zircon/kernel/lib/arch/BUILD.zircon.gn
@@ -4,21 +4,40 @@
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/MIT
-library("arch") {
- kernel = true
- static = true
+import("$zx/system/ulib/hwreg/hwreg_asm_header.gni")
- # Not much is actually usable on host, but hwreg definitions and such are.
- host = true
+if (current_toolchain != default_toolchain) {
+ library("arch") {
+ kernel = true
+ static = true
- sdk = "source"
- sdk_headers = [ "lib/arch/asm.h" ]
+ # Not much is actually usable on host, but hwreg definitions and such are.
+ host = true
- sources = []
+ sdk = "source"
+ sdk_headers = [ "lib/arch/asm.h" ]
- # The per-CPU subdirectory is a separate library() target but it shares
- # (and overrides) the <lib/arch/...> header name space and users of this
- # library need never realize it's distinct.
- deps = [ zircon_cpu ]
- public_deps = [ "$zircon_cpu:headers" ]
+ sources = []
+
+ if (is_host) {
+ deps = [ "host" ]
+ public_deps = [ "host:headers" ]
+ } else {
+ # The per-CPU subdirectory is a separate library() target but it shares
+ # (and overrides) the <lib/arch/...> header name space and users of this
+ # library need never realize it's distinct.
+ deps = [ zircon_cpu ]
+ public_deps = [
+ ":gen-x86-msr-asm",
+ "$zircon_cpu:headers",
+ ]
+ }
+ }
+}
+
+hwreg_asm_header("gen-x86-msr-asm") {
+ visibility = [ ":*" ]
+ output_name = "lib/arch/x86/msr-asm.h"
+ sources = [ "gen-x86-msr-asm.cc" ]
+ deps = [ ":arch" ]
}
diff --git a/zircon/kernel/lib/arch/README.md b/zircon/kernel/lib/arch/README.md
index 5c76e9a..f700188 100644
--- a/zircon/kernel/lib/arch/README.md
+++ b/zircon/kernel/lib/arch/README.md
@@ -173,6 +173,11 @@
Such declarations may also be useful in unit test code that can sometimes be
built and tested on a different machine and/or operating system.
+There is also a `host` subdirectory akin to the machine subdirectories. This
+is used in lieu of a particular machine when compiling for host environments.
+This makes it possible to write code using the machine-independent lib/arch API
+that can be built on host for purposes lock mock testing.
+
### C++
Only C++ 17 with modern style is supported.
diff --git a/zircon/kernel/lib/arch/gen-x86-msr-asm.cc b/zircon/kernel/lib/arch/gen-x86-msr-asm.cc
new file mode 100644
index 0000000..e1f2799
--- /dev/null
+++ b/zircon/kernel/lib/arch/gen-x86-msr-asm.cc
@@ -0,0 +1,17 @@
+// Copyright 2020 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 <lib/arch/x86/msr.h>
+
+#include <hwreg/asm.h>
+
+int main(int argc, char** argv) {
+ return hwreg::AsmHeader()
+ .Macro("MSR_IA32_FS_BASE", static_cast<uint32_t>(X86Msr::IA32_FS_BASE))
+ .Macro("MSR_IA32_GS_BASE", static_cast<uint32_t>(X86Msr::IA32_GS_BASE))
+ .Macro("MSR_IA32_KERNEL_GS_BASE", static_cast<uint32_t>(X86Msr::IA32_KERNEL_GS_BASE))
+ .Main(argc, argv);
+}
diff --git a/zircon/kernel/lib/arch/host/BUILD.zircon.gn b/zircon/kernel/lib/arch/host/BUILD.zircon.gn
new file mode 100644
index 0000000..41f22a3
--- /dev/null
+++ b/zircon/kernel/lib/arch/host/BUILD.zircon.gn
@@ -0,0 +1,13 @@
+# Copyright 2020 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
+
+zx_library("host") {
+ host = true
+ sources = []
+
+ sdk = "source"
+ sdk_headers = [ "lib/arch/intrin.h" ]
+}
diff --git a/zircon/kernel/lib/arch/host/include/lib/arch/intrin.h b/zircon/kernel/lib/arch/host/include/lib/arch/intrin.h
new file mode 100644
index 0000000..32d1ce6
--- /dev/null
+++ b/zircon/kernel/lib/arch/host/include/lib/arch/intrin.h
@@ -0,0 +1,34 @@
+// Copyright 2020 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
+
+#ifndef ZIRCON_KERNEL_LIB_ARCH_HOST_INCLUDE_LIB_ARCH_INTRIN_H_
+#define ZIRCON_KERNEL_LIB_ARCH_HOST_INCLUDE_LIB_ARCH_INTRIN_H_
+
+#ifdef __cplusplus
+
+// Provide the machine-independent <lib/arch/intrin.h> API. This file defines
+// dummy versions that are sufficient to compile code using the generic API
+// in host contexts, e.g. for unit tests and generator programs.
+
+namespace arch {
+
+/// Yield the processor momentarily. This should be used in busy waits.
+inline void Yield() {}
+
+/// Synchronize all memory accesses of all kinds.
+inline void DeviceMemoryBarrier() {}
+
+/// Synchronize the ordering of all memory accesses wrt other CPUs.
+inline void ThreadMemoryBarrier() {}
+
+/// Return the current CPU cycle count.
+inline uint64_t Cycles() { return 0; }
+
+} // namespace arch
+
+#endif // __cplusplus
+
+#endif // ZIRCON_KERNEL_LIB_ARCH_HOST_INCLUDE_LIB_ARCH_INTRIN_H_
diff --git a/zircon/kernel/lib/arch/include/lib/arch/x86/msr.h b/zircon/kernel/lib/arch/include/lib/arch/x86/msr.h
new file mode 100644
index 0000000..b107b225
--- /dev/null
+++ b/zircon/kernel/lib/arch/include/lib/arch/x86/msr.h
@@ -0,0 +1,58 @@
+// Copyright 2020 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
+
+#ifndef ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_X86_MSR_H_
+#define ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_X86_MSR_H_
+
+// This provides access to x86 Model-Specific Registers (MSRs).
+// It defines the constants for the MSR identifiers and it defines
+// hwreg types to represent the bit layouts.
+
+#ifdef __ASSEMBLER__ // clang-format off
+
+#ifdef __x86_64__
+// Writes %rax to the given MSR, which should be the bare constant.
+// Clobbers %rcx and %rdx.
+.macro wrmsr64 msr
+ mov $\msr, %ecx
+ mov %rax, %rdx
+ shr $32, %rdx
+ wrmsr
+.endm
+#endif // __x86_64__
+
+#if defined(__x86_64__) || defined(__i386__)
+// Writes %eax to the given MSR, which should be the bare constant.
+// Clobbers %ecx and %edx.
+.macro wrmsr32 msr
+ mov $\msr, %ecx
+ xor %edx, %edx
+ wrmsr
+.endm
+#endif // __x86_64__ || __i386__
+
+// This generated header provides `#define MSR_NAME ...` constants for
+// the X86Msr::NAME values below.
+#include <lib/arch/x86/msr-asm.h>
+
+#else // clang-format on
+
+#include <stdint.h>
+
+// MSR identifiers. These use the ALL_CAPS name style to be consistent with
+// the Intel manuals. The generated header <lib/arch/x86/msr-asm.h> contains
+// macros for `MSR_<name>` so these constants can be used in assembly code.
+enum class X86Msr : uint32_t {
+ IA32_FS_BASE = 0xc000'0100, // Current %fs.base value.
+ IA32_GS_BASE = 0xc000'0101, // Current %gs.base value.
+ IA32_KERNEL_GS_BASE = 0xc000'0102, // %gs.base value after `swapgs`.
+};
+
+// TODO: add more MSRs, add hwreg types for C++ access
+
+#endif // __ASSEMBLER__
+
+#endif // ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_X86_MSR_H_
diff --git a/zircon/kernel/lib/arch/x86/include/lib/arch/ticks.h b/zircon/kernel/lib/arch/x86/include/lib/arch/ticks.h
index 8a494be..1b71e80 100644
--- a/zircon/kernel/lib/arch/x86/include/lib/arch/ticks.h
+++ b/zircon/kernel/lib/arch/x86/include/lib/arch/ticks.h
@@ -32,7 +32,7 @@
.macro sample_ticks
rdtsc
#ifdef __x86_64__
- lsh $32, %rdx
+ shl $32, %rdx
or %rdx, %rax
#endif
.endm
diff --git a/zircon/system/ulib/BUILD.zircon.gn b/zircon/system/ulib/BUILD.zircon.gn
index 504cc5e..09b95ea 100644
--- a/zircon/system/ulib/BUILD.zircon.gn
+++ b/zircon/system/ulib/BUILD.zircon.gn
@@ -76,7 +76,7 @@
testonly = true
deps = [
"$zx/kernel/lib/arch",
- "$zx/kernel/lib/arch/$zircon_cpu",
+ "$zx/kernel/lib/arch/host",
"$zx/kernel/lib/heap/cmpctmalloc",
"$zx/third_party/ulib/boringssl",
"$zx/third_party/ulib/cksum",