[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",