Upgrade cpu_features to v0.4.0

Test: None
Change-Id: I35bdb7ab9438c8de0b3c78d6207f89a0fd8400c9
diff --git a/Android.bp b/Android.bp
index 0fef460..804c931 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11,6 +11,7 @@
     cflags: [
         // Reserve 1024 bytes on the stack when reading from `/proc/cpuinfo`.
         "-DSTACK_LINE_READER_BUFFER_SIZE=1024",
+        "-Wno-gnu-designator",
     ],
 }
 
@@ -70,16 +71,25 @@
             whole_static_libs: [
                 "libcpu_features-unix_based_hardware_detection",
             ],
+            cflags: [
+                "-Wno-gnu-designator",
+            ],
         },
         x86: {
             srcs: [
                 "src/cpuinfo_x86.c",
             ],
+            cflags: [
+                "-Wno-unused-variable",
+            ],
         },
         x86_64: {
             srcs: [
                 "src/cpuinfo_x86.c",
             ],
+            cflags: [
+                "-Wno-unused-variable",
+            ],
         },
     },
 }
@@ -279,6 +289,7 @@
     },
     cflags: [
         "-DCPU_FEATURES_MOCK_CPUID_X86",
+        "-Wno-unused-variable",
     ],
     srcs: [
         "test/cpuinfo_x86_test.cc",
@@ -314,6 +325,9 @@
             enabled: true,
         },
     },
+    cflags: [
+        "-Wno-gnu-designator",
+    ],
     srcs: [
         "test/cpuinfo_aarch64_test.cc",
         "src/cpuinfo_aarch64.c",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c8ab9ec..4954805 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,6 +2,8 @@
 
 project(CpuFeatures VERSION 0.1.0)
 
+set(CMAKE_C_STANDARD 99)
+
 # Default Build Type to be Release
 if(NOT CMAKE_BUILD_TYPE)
   set(CMAKE_BUILD_TYPE "Release" CACHE STRING
diff --git a/METADATA b/METADATA
index bdad823..13983a6 100644
--- a/METADATA
+++ b/METADATA
@@ -1,7 +1,5 @@
 name: "cpu_features"
-description:
-    "A cross platform C99 library to get CPU features at runtime."
-
+description: "A cross platform C99 library to get CPU features at runtime."
 third_party {
   url {
     type: HOMEPAGE
@@ -11,10 +9,10 @@
     type: GIT
     value: "https://github.com/google/cpu_features.git"
   }
-  version: "v0.3.0"
+  version: "v0.4.0"
   last_upgrade_date {
     year: 2019
     month: 7
-    day: 11
+    day: 12
   }
 }
diff --git a/include/cpu_features_cache_info.h b/include/cpu_features_cache_info.h
new file mode 100644
index 0000000..b7cc046
--- /dev/null
+++ b/include/cpu_features_cache_info.h
@@ -0,0 +1,54 @@
+// Copyright 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
+#define CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
+
+#include "cpu_features_macros.h"
+
+CPU_FEATURES_START_CPP_NAMESPACE
+
+typedef enum {
+  CPU_FEATURE_CACHE_NULL = 0,
+  CPU_FEATURE_CACHE_DATA = 1,
+  CPU_FEATURE_CACHE_INSTRUCTION = 2,
+  CPU_FEATURE_CACHE_UNIFIED = 3,
+  CPU_FEATURE_CACHE_TLB = 4,
+  CPU_FEATURE_CACHE_DTLB = 5,
+  CPU_FEATURE_CACHE_STLB = 6,
+  CPU_FEATURE_CACHE_PREFETCH = 7
+} CacheType;
+
+typedef struct {
+  int level;
+  CacheType cache_type;
+  int cache_size;    // Cache size in bytes
+  int ways;          // Associativity, 0 undefined, 0xFF fully associative
+  int line_size;     // Cache line size in bytes
+  int tlb_entries;   // number of entries for TLB
+  int partitioning;  // number of lines per sector
+} CacheLevelInfo;
+
+// Increase this value if more cache levels are needed.
+#ifndef CPU_FEATURES_MAX_CACHE_LEVEL
+#define CPU_FEATURES_MAX_CACHE_LEVEL 10
+#endif
+typedef struct {
+  int size;
+  CacheLevelInfo levels[CPU_FEATURES_MAX_CACHE_LEVEL];
+} CacheInfo;
+
+CPU_FEATURES_END_CPP_NAMESPACE
+
+#endif  // CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
diff --git a/include/cpuinfo_aarch64.h b/include/cpuinfo_aarch64.h
index a7d2201..cd3a676 100644
--- a/include/cpuinfo_aarch64.h
+++ b/include/cpuinfo_aarch64.h
@@ -16,6 +16,7 @@
 #define CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
 
 #include "cpu_features_macros.h"
+#include "cpu_features_cache_info.h"
 
 CPU_FEATURES_START_CPP_NAMESPACE
 
diff --git a/include/cpuinfo_arm.h b/include/cpuinfo_arm.h
index 76a49ef..d15471f 100644
--- a/include/cpuinfo_arm.h
+++ b/include/cpuinfo_arm.h
@@ -17,18 +17,33 @@
 
 #include <stdint.h>  // uint32_t
 #include "cpu_features_macros.h"
+#include "cpu_features_cache_info.h"
 
 CPU_FEATURES_START_CPP_NAMESPACE
 
 typedef struct {
+  int swp : 1;       // SWP instruction (atomic read-modify-write)
+  int half : 1;      // Half-word loads and stores
+  int thumb : 1;     // Thumb (16-bit instruction set)
+  int _26bit : 1;    // "26 Bit" Model (Processor status register folded into program counter)
+  int fastmult : 1;  // 32x32->64-bit multiplication
+  int fpa : 1;       // Floating point accelerator
   int vfp : 1;       // Vector Floating Point.
+  int edsp : 1;      // DSP extensions (the 'e' variant of the ARM9 CPUs, and all others above)
+  int java : 1;      // Jazelle (Java bytecode accelerator)
   int iwmmxt : 1;    // Intel Wireless MMX Technology.
+  int crunch : 1;    // MaverickCrunch coprocessor
+  int thumbee : 1;   // ThumbEE
   int neon : 1;      // Advanced SIMD.
   int vfpv3 : 1;     // VFP version 3
   int vfpv3d16 : 1;  // VFP version 3 with 16 D-registers
+  int tls : 1;       // TLS register
   int vfpv4 : 1;     // VFP version 4 with fast context switching
   int idiva : 1;     // SDIV and UDIV hardware division in ARM mode.
   int idivt : 1;     // SDIV and UDIV hardware division in Thumb mode.
+  int vfpd32 : 1;    // VFP with 32 D-registers
+  int lpae : 1;      // Large Physical Address Extension (>4GB physical memory on 32-bit architecture)
+  int evtstrm : 1;   // kernel event stream using generic architected timer
   int aes : 1;       // Hardware-accelerated Advanced Encryption Standard.
   int pmull : 1;     // Polynomial multiply long.
   int sha1 : 1;      // Hardware-accelerated SHA1.
@@ -59,14 +74,28 @@
 // Introspection functions
 
 typedef enum {
+  ARM_SWP,
+  ARM_HALF,
+  ARM_THUMB,
+  ARM_26BIT,
+  ARM_FASTMULT,
+  ARM_FPA,
   ARM_VFP,
+  ARM_EDSP,
+  ARM_JAVA,
   ARM_IWMMXT,
+  ARM_CRUNCH,
+  ARM_THUMBEE,
   ARM_NEON,
   ARM_VFPV3,
   ARM_VFPV3D16,
+  ARM_TLS,
   ARM_VFPV4,
   ARM_IDIVA,
   ARM_IDIVT,
+  ARM_VFPD32,
+  ARM_LPAE,
+  ARM_EVTSTRM,
   ARM_AES,
   ARM_PMULL,
   ARM_SHA1,
diff --git a/include/cpuinfo_mips.h b/include/cpuinfo_mips.h
index fd65a23..d82ae85 100644
--- a/include/cpuinfo_mips.h
+++ b/include/cpuinfo_mips.h
@@ -16,6 +16,7 @@
 #define CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
 
 #include "cpu_features_macros.h"
+#include "cpu_features_cache_info.h"
 
 CPU_FEATURES_START_CPP_NAMESPACE
 
diff --git a/include/cpuinfo_ppc.h b/include/cpuinfo_ppc.h
index 53d1cb6..eaac7da 100644
--- a/include/cpuinfo_ppc.h
+++ b/include/cpuinfo_ppc.h
@@ -16,6 +16,7 @@
 #define CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
 
 #include "cpu_features_macros.h"
+#include "cpu_features_cache_info.h"
 #include "internal/hwcaps.h"
 
 CPU_FEATURES_START_CPP_NAMESPACE
diff --git a/include/cpuinfo_x86.h b/include/cpuinfo_x86.h
index bb61293..4d51b60 100644
--- a/include/cpuinfo_x86.h
+++ b/include/cpuinfo_x86.h
@@ -15,6 +15,7 @@
 #ifndef CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
 #define CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
 
+#include "cpu_features_cache_info.h"
 #include "cpu_features_macros.h"
 
 CPU_FEATURES_START_CPP_NAMESPACE
@@ -22,14 +23,28 @@
 // See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features.
 // The field names are based on the short name provided in the wikipedia tables.
 typedef struct {
+  int fpu : 1;
+  int tsc : 1;
+  int cx8 : 1;
+  int clfsh : 1;
+  int mmx : 1;
   int aes : 1;
   int erms : 1;
   int f16c : 1;
   int fma3 : 1;
+  int vaes : 1;
   int vpclmulqdq : 1;
   int bmi1 : 1;
+  int hle : 1;
   int bmi2 : 1;
+  int rtm : 1;
+  int rdseed : 1;
+  int clflushopt : 1;
+  int clwb : 1;
 
+  int sse : 1;
+  int sse2 : 1;
+  int sse3 : 1;
   int ssse3 : 1;
   int sse4_1 : 1;
   int sse4_2 : 1;
@@ -53,6 +68,7 @@
   int avx512_4vnniw : 1;
   int avx512_4vbmi2 : 1;
 
+  int pclmulqdq : 1;
   int smx : 1;
   int sgx : 1;
   int cx16 : 1;  // aka. CMPXCHG16B
@@ -61,6 +77,8 @@
   int movbe : 1;
   int rdrnd : 1;
 
+  int dca : 1;
+  int ss : 1;
   // Make sure to update X86FeaturesEnum below if you add a field here.
 } X86Features;
 
@@ -76,6 +94,12 @@
 // This function is guaranteed to be malloc, memset and memcpy free.
 X86Info GetX86Info(void);
 
+// Returns cache hierarchy informations.
+// Can call cpuid multiple times.
+// Only works on Intel CPU at the moment.
+// This function is guaranteed to be malloc, memset and memcpy free.
+CacheInfo GetX86CacheInfo(void);
+
 typedef enum {
   X86_UNKNOWN,
   INTEL_CORE,      // CORE
@@ -115,13 +139,27 @@
 // Introspection functions
 
 typedef enum {
+  X86_FPU,
+  X86_TSC,
+  X86_CX8,
+  X86_CLFSH,
+  X86_MMX,
   X86_AES,
   X86_ERMS,
   X86_F16C,
   X86_FMA3,
+  X86_VAES,
   X86_VPCLMULQDQ,
   X86_BMI1,
+  X86_HLE,
   X86_BMI2,
+  X86_RTM,
+  X86_RDSEED,
+  X86_CLFLUSHOPT,
+  X86_CLWB,
+  X86_SSE,
+  X86_SSE2,
+  X86_SSE3,
   X86_SSSE3,
   X86_SSE4_1,
   X86_SSE4_2,
@@ -142,6 +180,7 @@
   X86_AVX512VPOPCNTDQ,
   X86_AVX512_4VNNIW,
   X86_AVX512_4VBMI2,
+  X86_PCLMULQDQ,
   X86_SMX,
   X86_SGX,
   X86_CX16,
@@ -149,6 +188,8 @@
   X86_POPCNT,
   X86_MOVBE,
   X86_RDRND,
+  X86_DCA,
+  X86_SS,
   X86_LAST_,
 } X86FeaturesEnum;
 
diff --git a/include/internal/cpuid_x86.h b/include/internal/cpuid_x86.h
index 9dcee0d..754ca38 100644
--- a/include/internal/cpuid_x86.h
+++ b/include/internal/cpuid_x86.h
@@ -26,8 +26,7 @@
   uint32_t eax, ebx, ecx, edx;
 } Leaf;
 
-// Retrieves the leaf for a particular cpuid.
-Leaf CpuId(uint32_t leaf_id);
+Leaf CpuIdEx(uint32_t leaf_id, int ecx);
 
 // Returns the eax value of the XCR0 register.
 uint32_t GetXCR0Eax(void);
diff --git a/include/internal/hwcaps.h b/include/internal/hwcaps.h
index cb38e29..06a0f60 100644
--- a/include/internal/hwcaps.h
+++ b/include/internal/hwcaps.h
@@ -35,14 +35,28 @@
 #define AARCH64_HWCAP_CRC32 (1UL << 7)
 
 // http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
+#define ARM_HWCAP_SWP (1UL << 0)
+#define ARM_HWCAP_HALF (1UL << 1)
+#define ARM_HWCAP_THUMB (1UL << 2)
+#define ARM_HWCAP_26BIT (1UL << 3)
+#define ARM_HWCAP_FAST_MULT (1UL << 4)
+#define ARM_HWCAP_FPA (1UL << 5)
 #define ARM_HWCAP_VFP (1UL << 6)
+#define ARM_HWCAP_EDSP (1UL << 7)
+#define ARM_HWCAP_JAVA (1UL << 8)
 #define ARM_HWCAP_IWMMXT (1UL << 9)
+#define ARM_HWCAP_CRUNCH (1UL << 10)
+#define ARM_HWCAP_THUMBEE (1UL << 11)
 #define ARM_HWCAP_NEON (1UL << 12)
 #define ARM_HWCAP_VFPV3 (1UL << 13)
 #define ARM_HWCAP_VFPV3D16 (1UL << 14)
+#define ARM_HWCAP_TLS (1UL << 15)
 #define ARM_HWCAP_VFPV4 (1UL << 16)
 #define ARM_HWCAP_IDIVA (1UL << 17)
 #define ARM_HWCAP_IDIVT (1UL << 18)
+#define ARM_HWCAP_VFPD32 (1UL << 19)
+#define ARM_HWCAP_LPAE (1UL << 20)
+#define ARM_HWCAP_EVTSTRM (1UL << 21)
 #define ARM_HWCAP2_AES (1UL << 0)
 #define ARM_HWCAP2_PMULL (1UL << 1)
 #define ARM_HWCAP2_SHA1 (1UL << 2)
diff --git a/src/cpuinfo_aarch64.c b/src/cpuinfo_aarch64.c
index 57e9c8d..26a07d3 100644
--- a/src/cpuinfo_aarch64.c
+++ b/src/cpuinfo_aarch64.c
@@ -20,6 +20,7 @@
 #include "internal/string_view.h"
 #include "internal/unix_features_aggregator.h"
 
+#include <assert.h>
 #include <ctype.h>
 
 DECLARE_SETTER(Aarch64Features, fp)
@@ -31,13 +32,13 @@
 DECLARE_SETTER(Aarch64Features, crc32)
 
 static const CapabilityConfig kConfigs[] = {
-    {{AARCH64_HWCAP_FP, 0}, "fp", &set_fp},           //
-    {{AARCH64_HWCAP_ASIMD, 0}, "asimd", &set_asimd},  //
-    {{AARCH64_HWCAP_AES, 0}, "aes", &set_aes},        //
-    {{AARCH64_HWCAP_PMULL, 0}, "pmull", &set_pmull},  //
-    {{AARCH64_HWCAP_SHA1, 0}, "sha1", &set_sha1},     //
-    {{AARCH64_HWCAP_SHA2, 0}, "sha2", &set_sha2},     //
-    {{AARCH64_HWCAP_CRC32, 0}, "crc32", &set_crc32},  //
+  [AARCH64_FP] = {{AARCH64_HWCAP_FP, 0}, "fp", &set_fp},              //
+  [AARCH64_ASIMD] = {{AARCH64_HWCAP_ASIMD, 0}, "asimd", &set_asimd},  //
+  [AARCH64_AES] = {{AARCH64_HWCAP_AES, 0}, "aes", &set_aes},          //
+  [AARCH64_PMULL] = {{AARCH64_HWCAP_PMULL, 0}, "pmull", &set_pmull},  //
+  [AARCH64_SHA1] = {{AARCH64_HWCAP_SHA1, 0}, "sha1", &set_sha1},      //
+  [AARCH64_SHA2] = {{AARCH64_HWCAP_SHA2, 0}, "sha2", &set_sha2},      //
+  [AARCH64_CRC32] {{AARCH64_HWCAP_CRC32, 0}, "crc32", &set_crc32},    //
 };
 
 static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
@@ -79,6 +80,8 @@
 static const Aarch64Info kEmptyAarch64Info;
 
 Aarch64Info GetAarch64Info(void) {
+  assert(kConfigsSize == AARCH64_LAST_);
+
   // capabilities are fetched from both getauxval and /proc/cpuinfo so we can
   // have some information if the executable is sandboxed (aka no access to
   // /proc/cpuinfo).
@@ -119,23 +122,7 @@
 }
 
 const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum value) {
-  switch (value) {
-    case AARCH64_FP:
-      return "fp";
-    case AARCH64_ASIMD:
-      return "asimd";
-    case AARCH64_AES:
-      return "aes";
-    case AARCH64_PMULL:
-      return "pmull";
-    case AARCH64_SHA1:
-      return "sha1";
-    case AARCH64_SHA2:
-      return "sha2";
-    case AARCH64_CRC32:
-      return "crc32";
-    case AARCH64_LAST_:
-      break;
-  }
-  return "unknown feature";
+  if(value >= kConfigsSize)
+    return "unknown feature";
+  return kConfigs[value].proc_cpuinfo_flag;
 }
diff --git a/src/cpuinfo_arm.c b/src/cpuinfo_arm.c
index afbb9f1..66c6d91 100644
--- a/src/cpuinfo_arm.c
+++ b/src/cpuinfo_arm.c
@@ -21,16 +21,31 @@
 #include "internal/string_view.h"
 #include "internal/unix_features_aggregator.h"
 
+#include <assert.h>
 #include <ctype.h>
 
+DECLARE_SETTER(ArmFeatures, swp)
+DECLARE_SETTER(ArmFeatures, half)
+DECLARE_SETTER(ArmFeatures, thumb)
+DECLARE_SETTER(ArmFeatures, _26bit)
+DECLARE_SETTER(ArmFeatures, fastmult)
+DECLARE_SETTER(ArmFeatures, fpa)
 DECLARE_SETTER(ArmFeatures, vfp)
+DECLARE_SETTER(ArmFeatures, edsp)
+DECLARE_SETTER(ArmFeatures, java)
 DECLARE_SETTER(ArmFeatures, iwmmxt)
+DECLARE_SETTER(ArmFeatures, crunch)
+DECLARE_SETTER(ArmFeatures, thumbee)
 DECLARE_SETTER(ArmFeatures, neon)
 DECLARE_SETTER(ArmFeatures, vfpv3)
 DECLARE_SETTER(ArmFeatures, vfpv3d16)
+DECLARE_SETTER(ArmFeatures, tls)
 DECLARE_SETTER(ArmFeatures, vfpv4)
 DECLARE_SETTER(ArmFeatures, idiva)
 DECLARE_SETTER(ArmFeatures, idivt)
+DECLARE_SETTER(ArmFeatures, vfpd32)
+DECLARE_SETTER(ArmFeatures, lpae)
+DECLARE_SETTER(ArmFeatures, evtstrm)
 DECLARE_SETTER(ArmFeatures, aes)
 DECLARE_SETTER(ArmFeatures, pmull)
 DECLARE_SETTER(ArmFeatures, sha1)
@@ -38,19 +53,33 @@
 DECLARE_SETTER(ArmFeatures, crc32)
 
 static const CapabilityConfig kConfigs[] = {
-    {{ARM_HWCAP_VFP, 0}, "vfp", &set_vfp},                 //
-    {{ARM_HWCAP_IWMMXT, 0}, "iwmmxt", &set_iwmmxt},        //
-    {{ARM_HWCAP_NEON, 0}, "neon", &set_neon},              //
-    {{ARM_HWCAP_VFPV3, 0}, "vfpv3", &set_vfpv3},           //
-    {{ARM_HWCAP_VFPV3D16, 0}, "vfpv3d16", &set_vfpv3d16},  //
-    {{ARM_HWCAP_VFPV4, 0}, "vfpv4", &set_vfpv4},           //
-    {{ARM_HWCAP_IDIVA, 0}, "idiva", &set_idiva},           //
-    {{ARM_HWCAP_IDIVT, 0}, "idivt", &set_idivt},           //
-    {{0, ARM_HWCAP2_AES}, "aes", &set_aes},                //
-    {{0, ARM_HWCAP2_PMULL}, "pmull", &set_pmull},          //
-    {{0, ARM_HWCAP2_SHA1}, "sha1", &set_sha1},             //
-    {{0, ARM_HWCAP2_SHA2}, "sha2", &set_sha2},             //
-    {{0, ARM_HWCAP2_CRC32}, "crc32", &set_crc32},          //
+  [ARM_SWP] = {{ARM_HWCAP_SWP, 0}, "swp", &set_swp},                      //
+  [ARM_HALF] = {{ARM_HWCAP_HALF, 0}, "half", &set_half},                  //
+  [ARM_THUMB] = {{ARM_HWCAP_THUMB, 0}, "thumb", &set_thumb},              //
+  [ARM_26BIT] = {{ARM_HWCAP_26BIT, 0}, "26bit", &set__26bit},             //
+  [ARM_FASTMULT] = {{ARM_HWCAP_FAST_MULT, 0}, "fastmult", &set_fastmult}, //
+  [ARM_FPA] = {{ARM_HWCAP_FPA, 0}, "fpa", &set_fpa},                      //
+  [ARM_VFP] = {{ARM_HWCAP_VFP, 0}, "vfp", &set_vfp},                      //
+  [ARM_EDSP] = {{ARM_HWCAP_EDSP, 0}, "edsp", &set_edsp},                  //
+  [ARM_JAVA] = {{ARM_HWCAP_JAVA, 0}, "java", &set_java},                  //
+  [ARM_IWMMXT] = {{ARM_HWCAP_IWMMXT, 0}, "iwmmxt", &set_iwmmxt},          //
+  [ARM_CRUNCH] = {{ARM_HWCAP_CRUNCH, 0}, "crunch", &set_crunch},          //
+  [ARM_THUMBEE] = {{ARM_HWCAP_THUMBEE, 0}, "thumbee", &set_thumbee},      //
+  [ARM_NEON] = {{ARM_HWCAP_NEON, 0}, "neon", &set_neon},                  //
+  [ARM_VFPV3] = {{ARM_HWCAP_VFPV3, 0}, "vfpv3", &set_vfpv3},              //
+  [ARM_VFPV3D16] = {{ARM_HWCAP_VFPV3D16, 0}, "vfpv3d16", &set_vfpv3d16},  //
+  [ARM_TLS] = {{ARM_HWCAP_TLS, 0}, "tls", &set_tls},                      //
+  [ARM_VFPV4] = {{ARM_HWCAP_VFPV4, 0}, "vfpv4", &set_vfpv4},              //
+  [ARM_IDIVA] = {{ARM_HWCAP_IDIVA, 0}, "idiva", &set_idiva},              //
+  [ARM_IDIVT] = {{ARM_HWCAP_IDIVT, 0}, "idivt", &set_idivt},              //
+  [ARM_VFPD32] = {{ARM_HWCAP_VFPD32, 0}, "vfpd32", &set_vfpd32},          //
+  [ARM_LPAE] = {{ARM_HWCAP_LPAE, 0}, "lpae", &set_lpae},                  //
+  [ARM_EVTSTRM] = {{ARM_HWCAP_EVTSTRM, 0}, "evtstrm", &set_evtstrm},      //
+  [ARM_AES] = {{0, ARM_HWCAP2_AES}, "aes", &set_aes},                     //
+  [ARM_PMULL] = {{0, ARM_HWCAP2_PMULL}, "pmull", &set_pmull},             //
+  [ARM_SHA1] = {{0, ARM_HWCAP2_SHA1}, "sha1", &set_sha1},                 //
+  [ARM_SHA2] = {{0, ARM_HWCAP2_SHA2}, "sha2", &set_sha2},                 //
+  [ARM_CRC32] = {{0, ARM_HWCAP2_CRC32}, "crc32", &set_crc32},             //
 };
 
 static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
@@ -90,7 +119,11 @@
       const StringView digits =
           CpuFeatures_StringView_KeepFront(value, IndexOfNonDigit(value));
       info->architecture = CpuFeatures_StringView_ParsePositiveNumber(digits);
-    } else if (CpuFeatures_StringView_IsEquals(key, str("Processor"))) {
+    } else if (CpuFeatures_StringView_IsEquals(key, str("Processor"))
+               || CpuFeatures_StringView_IsEquals(key, str("model name")) ) {
+      // Android reports this in a non-Linux standard "Processor" but sometimes
+      // also in "model name", Linux reports it only in "model name"
+      // see RaspberryPiZero (Linux) vs InvalidArmv7 (Android) test-cases
       proc_info->processor_reports_armv6 =
           CpuFeatures_StringView_IndexOf(value, str("(v6l)")) >= 0;
     } else if (CpuFeatures_StringView_IsEquals(key, str("Hardware"))) {
@@ -192,22 +225,50 @@
 int GetArmFeaturesEnumValue(const ArmFeatures* features,
                             ArmFeaturesEnum value) {
   switch (value) {
+    case ARM_SWP:
+      return features->swp;
+    case ARM_HALF:
+      return features->half;
+    case ARM_THUMB:
+      return features->thumb;
+    case ARM_26BIT:
+      return features->_26bit;
+    case ARM_FASTMULT:
+      return features->fastmult;
+    case ARM_FPA:
+      return features->fpa;
     case ARM_VFP:
       return features->vfp;
+    case ARM_EDSP:
+      return features->edsp;
+    case ARM_JAVA:
+      return features->java;
     case ARM_IWMMXT:
       return features->iwmmxt;
+    case ARM_CRUNCH:
+      return features->crunch;
+    case ARM_THUMBEE:
+      return features->thumbee;
     case ARM_NEON:
       return features->neon;
     case ARM_VFPV3:
       return features->vfpv3;
     case ARM_VFPV3D16:
       return features->vfpv3d16;
+    case ARM_TLS:
+      return features->tls;
     case ARM_VFPV4:
       return features->vfpv4;
     case ARM_IDIVA:
       return features->idiva;
     case ARM_IDIVT:
       return features->idivt;
+    case ARM_VFPD32:
+      return features->vfpd32;
+    case ARM_LPAE:
+      return features->lpae;
+    case ARM_EVTSTRM:
+      return features->evtstrm;
     case ARM_AES:
       return features->aes;
     case ARM_PMULL:
@@ -225,35 +286,7 @@
 }
 
 const char* GetArmFeaturesEnumName(ArmFeaturesEnum value) {
-  switch (value) {
-    case ARM_VFP:
-      return "vfp";
-    case ARM_IWMMXT:
-      return "iwmmxt";
-    case ARM_NEON:
-      return "neon";
-    case ARM_VFPV3:
-      return "vfpv3";
-    case ARM_VFPV3D16:
-      return "vfpv3d16";
-    case ARM_VFPV4:
-      return "vfpv4";
-    case ARM_IDIVA:
-      return "idiva";
-    case ARM_IDIVT:
-      return "idivt";
-    case ARM_AES:
-      return "aes";
-    case ARM_PMULL:
-      return "pmull";
-    case ARM_SHA1:
-      return "sha1";
-    case ARM_SHA2:
-      return "sha2";
-    case ARM_CRC32:
-      return "crc32";
-    case ARM_LAST_:
-      break;
-  }
-  return "unknown feature";
+  if(value >= kConfigsSize)
+    return "unknown feature";
+  return kConfigs[value].proc_cpuinfo_flag;
 }
diff --git a/src/cpuinfo_mips.c b/src/cpuinfo_mips.c
index 706d555..8769211 100644
--- a/src/cpuinfo_mips.c
+++ b/src/cpuinfo_mips.c
@@ -19,14 +19,16 @@
 #include "internal/string_view.h"
 #include "internal/unix_features_aggregator.h"
 
+#include <assert.h>
+
 DECLARE_SETTER(MipsFeatures, msa)
 DECLARE_SETTER(MipsFeatures, eva)
 DECLARE_SETTER(MipsFeatures, r6)
 
 static const CapabilityConfig kConfigs[] = {
-    {{MIPS_HWCAP_MSA, 0}, "msa", &set_msa},  //
-    {{0, 0}, "eva", &set_eva},               //
-    {{MIPS_HWCAP_R6, 0}, "r6", &set_r6},     //
+  [MIPS_MSA] = {{MIPS_HWCAP_MSA, 0}, "msa", &set_msa},  //
+  [MIPS_EVA] = {{0, 0}, "eva", &set_eva},               //
+  [MIPS_R6] = {{MIPS_HWCAP_R6, 0}, "r6", &set_r6},      //
 };
 static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
 
@@ -59,6 +61,8 @@
 static const MipsInfo kEmptyMipsInfo;
 
 MipsInfo GetMipsInfo(void) {
+  assert(kConfigsSize == MIPS_LAST_);
+
   // capabilities are fetched from both getauxval and /proc/cpuinfo so we can
   // have some information if the executable is sandboxed (aka no access to
   // /proc/cpuinfo).
@@ -90,15 +94,7 @@
 }
 
 const char* GetMipsFeaturesEnumName(MipsFeaturesEnum value) {
-  switch (value) {
-    case MIPS_MSA:
-      return "msa";
-    case MIPS_EVA:
-      return "eva";
-    case MIPS_R6:
-      return "r6";
-    case MIPS_LAST_:
-      break;
-  }
-  return "unknown feature";
+  if(value >= kConfigsSize)
+    return "unknown feature";
+  return kConfigs[value].proc_cpuinfo_flag;
 }
diff --git a/src/cpuinfo_ppc.c b/src/cpuinfo_ppc.c
index 53d2059..d6c49f8 100644
--- a/src/cpuinfo_ppc.c
+++ b/src/cpuinfo_ppc.c
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <assert.h>
 #include <stdbool.h>
 #include <string.h>
 
@@ -65,49 +66,49 @@
 DECLARE_SETTER(PPCFeatures, htm_no_suspend)
 
 static const CapabilityConfig kConfigs[] = {
-    {{PPC_FEATURE_32, 0}, "ppc32", &set_ppc32},
-    {{PPC_FEATURE_64, 0}, "ppc64", &set_ppc64},
-    {{PPC_FEATURE_601_INSTR, 0}, "ppc601", &set_ppc601},
-    {{PPC_FEATURE_HAS_ALTIVEC, 0}, "altivec", &set_altivec},
-    {{PPC_FEATURE_HAS_FPU, 0}, "fpu", &set_fpu},
-    {{PPC_FEATURE_HAS_MMU, 0}, "mmu", &set_mmu},
-    {{PPC_FEATURE_HAS_4xxMAC, 0}, "4xxmac", &set_mac_4xx},
-    {{PPC_FEATURE_UNIFIED_CACHE, 0}, "ucache", &set_unifiedcache},
-    {{PPC_FEATURE_HAS_SPE, 0}, "spe", &set_spe},
-    {{PPC_FEATURE_HAS_EFP_SINGLE, 0}, "efpsingle", &set_efpsingle},
-    {{PPC_FEATURE_HAS_EFP_DOUBLE, 0}, "efpdouble", &set_efpdouble},
-    {{PPC_FEATURE_NO_TB, 0}, "notb", &set_no_tb},
-    {{PPC_FEATURE_POWER4, 0}, "power4", &set_power4},
-    {{PPC_FEATURE_POWER5, 0}, "power5", &set_power5},
-    {{PPC_FEATURE_POWER5_PLUS, 0}, "power5+", &set_power5plus},
-    {{PPC_FEATURE_CELL, 0}, "cellbe", &set_cell},
-    {{PPC_FEATURE_BOOKE, 0}, "booke", &set_booke},
-    {{PPC_FEATURE_SMT, 0}, "smt", &set_smt},
-    {{PPC_FEATURE_ICACHE_SNOOP, 0}, "ic_snoop", &set_icachesnoop},
-    {{PPC_FEATURE_ARCH_2_05, 0}, "arch_2_05", &set_arch205},
-    {{PPC_FEATURE_PA6T, 0}, "pa6t", &set_pa6t},
-    {{PPC_FEATURE_HAS_DFP, 0}, "dfp", &set_dfp},
-    {{PPC_FEATURE_POWER6_EXT, 0}, "power6x", &set_power6ext},
-    {{PPC_FEATURE_ARCH_2_06, 0}, "arch_2_06", &set_arch206},
-    {{PPC_FEATURE_HAS_VSX, 0}, "vsx", &set_vsx},
-    {{PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0},
+  [PPC_32] = {{PPC_FEATURE_32, 0}, "ppc32", &set_ppc32},
+  [PPC_64] = {{PPC_FEATURE_64, 0}, "ppc64", &set_ppc64},
+  [PPC_601_INSTR] = {{PPC_FEATURE_601_INSTR, 0}, "ppc601", &set_ppc601},
+  [PPC_HAS_ALTIVEC] = {{PPC_FEATURE_HAS_ALTIVEC, 0}, "altivec", &set_altivec},
+  [PPC_HAS_FPU] = {{PPC_FEATURE_HAS_FPU, 0}, "fpu", &set_fpu},
+  [PPC_HAS_MMU] = {{PPC_FEATURE_HAS_MMU, 0}, "mmu", &set_mmu},
+  [PPC_HAS_4xxMAC] = {{PPC_FEATURE_HAS_4xxMAC, 0}, "4xxmac", &set_mac_4xx},
+  [PPC_UNIFIED_CACHE] = {{PPC_FEATURE_UNIFIED_CACHE, 0}, "ucache", &set_unifiedcache},
+  [PPC_HAS_SPE] = {{PPC_FEATURE_HAS_SPE, 0}, "spe", &set_spe},
+  [PPC_HAS_EFP_SINGLE] = {{PPC_FEATURE_HAS_EFP_SINGLE, 0}, "efpsingle", &set_efpsingle},
+  [PPC_HAS_EFP_DOUBLE] = {{PPC_FEATURE_HAS_EFP_DOUBLE, 0}, "efpdouble", &set_efpdouble},
+  [PPC_NO_TB] = {{PPC_FEATURE_NO_TB, 0}, "notb", &set_no_tb},
+  [PPC_POWER4] = {{PPC_FEATURE_POWER4, 0}, "power4", &set_power4},
+  [PPC_POWER5] = {{PPC_FEATURE_POWER5, 0}, "power5", &set_power5},
+  [PPC_POWER5_PLUS] = {{PPC_FEATURE_POWER5_PLUS, 0}, "power5+", &set_power5plus},
+  [PPC_CELL] = {{PPC_FEATURE_CELL, 0}, "cellbe", &set_cell},
+  [PPC_BOOKE] = {{PPC_FEATURE_BOOKE, 0}, "booke", &set_booke},
+  [PPC_SMT] = {{PPC_FEATURE_SMT, 0}, "smt", &set_smt},
+  [PPC_ICACHE_SNOOP] = {{PPC_FEATURE_ICACHE_SNOOP, 0}, "ic_snoop", &set_icachesnoop},
+  [PPC_ARCH_2_05] = {{PPC_FEATURE_ARCH_2_05, 0}, "arch_2_05", &set_arch205},
+  [PPC_PA6T] = {{PPC_FEATURE_PA6T, 0}, "pa6t", &set_pa6t},
+  [PPC_HAS_DFP] = {{PPC_FEATURE_HAS_DFP, 0}, "dfp", &set_dfp},
+  [PPC_POWER6_EXT] = {{PPC_FEATURE_POWER6_EXT, 0}, "power6x", &set_power6ext},
+  [PPC_ARCH_2_06] = {{PPC_FEATURE_ARCH_2_06, 0}, "arch_2_06", &set_arch206},
+  [PPC_HAS_VSX] = {{PPC_FEATURE_HAS_VSX, 0}, "vsx", &set_vsx},
+  [PPC_PSERIES_PERFMON_COMPAT] = {{PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0},
      "archpmu",
      &set_pseries_perfmon_compat},
-    {{PPC_FEATURE_TRUE_LE, 0}, "true_le", &set_truele},
-    {{PPC_FEATURE_PPC_LE, 0}, "ppcle", &set_ppcle},
-    {{0, PPC_FEATURE2_ARCH_2_07}, "arch_2_07", &set_arch207},
-    {{0, PPC_FEATURE2_HTM}, "htm", &set_htm},
-    {{0, PPC_FEATURE2_DSCR}, "dscr", &set_dscr},
-    {{0, PPC_FEATURE2_EBB}, "ebb", &set_ebb},
-    {{0, PPC_FEATURE2_ISEL}, "isel", &set_isel},
-    {{0, PPC_FEATURE2_TAR}, "tar", &set_tar},
-    {{0, PPC_FEATURE2_VEC_CRYPTO}, "vcrypto", &set_vcrypto},
-    {{0, PPC_FEATURE2_HTM_NOSC}, "htm-nosc", &set_htm_nosc},
-    {{0, PPC_FEATURE2_ARCH_3_00}, "arch_3_00", &set_arch300},
-    {{0, PPC_FEATURE2_HAS_IEEE128}, "ieee128", &set_ieee128},
-    {{0, PPC_FEATURE2_DARN}, "darn", &set_darn},
-    {{0, PPC_FEATURE2_SCV}, "scv", &set_scv},
-    {{0, PPC_FEATURE2_HTM_NO_SUSPEND}, "htm-no-suspend", &set_htm_no_suspend},
+  [PPC_TRUE_LE] = {{PPC_FEATURE_TRUE_LE, 0}, "true_le", &set_truele},
+  [PPC_PPC_LE] = {{PPC_FEATURE_PPC_LE, 0}, "ppcle", &set_ppcle},
+  [PPC_ARCH_2_07] = {{0, PPC_FEATURE2_ARCH_2_07}, "arch_2_07", &set_arch207},
+  [PPC_HTM] = {{0, PPC_FEATURE2_HTM}, "htm", &set_htm},
+  [PPC_DSCR] = {{0, PPC_FEATURE2_DSCR}, "dscr", &set_dscr},
+  [PPC_EBB] = {{0, PPC_FEATURE2_EBB}, "ebb", &set_ebb},
+  [PPC_ISEL] = {{0, PPC_FEATURE2_ISEL}, "isel", &set_isel},
+  [PPC_TAR] = {{0, PPC_FEATURE2_TAR}, "tar", &set_tar},
+  [PPC_VEC_CRYPTO] = {{0, PPC_FEATURE2_VEC_CRYPTO}, "vcrypto", &set_vcrypto},
+  [PPC_HTM_NOSC] = {{0, PPC_FEATURE2_HTM_NOSC}, "htm-nosc", &set_htm_nosc},
+  [PPC_ARCH_3_00] = {{0, PPC_FEATURE2_ARCH_3_00}, "arch_3_00", &set_arch300},
+  [PPC_HAS_IEEE128] = {{0, PPC_FEATURE2_HAS_IEEE128}, "ieee128", &set_ieee128},
+  [PPC_DARN] = {{0, PPC_FEATURE2_DARN}, "darn", &set_darn},
+  [PPC_SCV] = {{0, PPC_FEATURE2_SCV}, "scv", &set_scv},
+  [PPC_HTM_NO_SUSPEND] = {{0, PPC_FEATURE2_HTM_NO_SUSPEND}, "htm-no-suspend", &set_htm_no_suspend},
 };
 static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
 
@@ -268,91 +269,7 @@
 
 /* Have used the same names as glibc  */
 const char* GetPPCFeaturesEnumName(PPCFeaturesEnum value) {
-  switch (value) {
-    case PPC_32:
-      return "ppc32";
-    case PPC_64:
-      return "ppc64";
-    case PPC_601_INSTR:
-      return "ppc601";
-    case PPC_HAS_ALTIVEC:
-      return "altivec";
-    case PPC_HAS_FPU:
-      return "fpu";
-    case PPC_HAS_MMU:
-      return "mmu";
-    case PPC_HAS_4xxMAC:
-      return "4xxmac";
-    case PPC_UNIFIED_CACHE:
-      return "ucache";
-    case PPC_HAS_SPE:
-      return "spe";
-    case PPC_HAS_EFP_SINGLE:
-      return "efpsingle";
-    case PPC_HAS_EFP_DOUBLE:
-      return "efpdouble";
-    case PPC_NO_TB:
-      return "notb";
-    case PPC_POWER4:
-      return "power4";
-    case PPC_POWER5:
-      return "power5";
-    case PPC_POWER5_PLUS:
-      return "power5+";
-    case PPC_CELL:
-      return "cellbe";
-    case PPC_BOOKE:
-      return "booke";
-    case PPC_SMT:
-      return "smt";
-    case PPC_ICACHE_SNOOP:
-      return "ic_snoop";
-    case PPC_ARCH_2_05:
-      return "arch_2_05";
-    case PPC_PA6T:
-      return "pa6t";
-    case PPC_HAS_DFP:
-      return "dfp";
-    case PPC_POWER6_EXT:
-      return "power6x";
-    case PPC_ARCH_2_06:
-      return "arch_2_06";
-    case PPC_HAS_VSX:
-      return "vsx";
-    case PPC_PSERIES_PERFMON_COMPAT:
-      return "archpmu";
-    case PPC_TRUE_LE:
-      return "true_le";
-    case PPC_PPC_LE:
-      return "ppcle";
-    case PPC_ARCH_2_07:
-      return "arch_2_07";
-    case PPC_HTM:
-      return "htm";
-    case PPC_DSCR:
-      return "dscr";
-    case PPC_EBB:
-      return "ebb";
-    case PPC_ISEL:
-      return "isel";
-    case PPC_TAR:
-      return "tar";
-    case PPC_VEC_CRYPTO:
-      return "vcrypto";
-    case PPC_HTM_NOSC:
-      return "htm-nosc";
-    case PPC_ARCH_3_00:
-      return "arch_3_00";
-    case PPC_HAS_IEEE128:
-      return "ieee128";
-    case PPC_DARN:
-      return "darn";
-    case PPC_SCV:
-      return "scv";
-    case PPC_HTM_NO_SUSPEND:
-      return "htm-no-suspend";
-    case PPC_LAST_:
-      break;
-  }
-  return "unknown_feature";
+  if(value >= kConfigsSize)
+    return "unknown feature";
+  return kConfigs[value].proc_cpuinfo_flag;
 }
diff --git a/src/cpuinfo_x86.c b/src/cpuinfo_x86.c
index 52f178f..c997b7b 100644
--- a/src/cpuinfo_x86.c
+++ b/src/cpuinfo_x86.c
@@ -33,9 +33,9 @@
 
 #include <cpuid.h>
 
-Leaf CpuId(uint32_t leaf_id) {
+Leaf CpuIdEx(uint32_t leaf_id, int ecx) {
   Leaf leaf;
-  __cpuid_count(leaf_id, 0, leaf.eax, leaf.ebx, leaf.ecx, leaf.edx);
+  __cpuid_count(leaf_id, ecx, leaf.eax, leaf.ebx, leaf.ecx, leaf.edx);
   return leaf;
 }
 
@@ -53,10 +53,10 @@
 #include <immintrin.h>
 #include <intrin.h>  // For __cpuidex()
 
-Leaf CpuId(uint32_t leaf_id) {
+Leaf CpuIdEx(uint32_t leaf_id, int ecx) {
   Leaf leaf;
   int data[4];
-  __cpuid(data, leaf_id);
+  __cpuidex(data, leaf_id, ecx);
   leaf.eax = data[0];
   leaf.ebx = data[1];
   leaf.ecx = data[2];
@@ -64,22 +64,28 @@
   return leaf;
 }
 
-uint32_t GetXCR0Eax(void) { return _xgetbv(0); }
+uint32_t GetXCR0Eax(void) { return (uint32_t)_xgetbv(0); }
 
 #else
 #error "Unsupported compiler, x86 cpuid requires either GCC, Clang or MSVC."
 #endif
 
+static Leaf CpuId(uint32_t leaf_id) { return CpuIdEx(leaf_id, 0); }
+
 static const Leaf kEmptyLeaf;
 
-static Leaf SafeCpuId(uint32_t max_cpuid_leaf, uint32_t leaf_id) {
+static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx) {
   if (leaf_id <= max_cpuid_leaf) {
-    return CpuId(leaf_id);
+    return CpuIdEx(leaf_id, ecx);
   } else {
     return kEmptyLeaf;
   }
 }
 
+static Leaf SafeCpuId(uint32_t max_cpuid_leaf, uint32_t leaf_id) {
+  return SafeCpuIdEx(max_cpuid_leaf, leaf_id, 0);
+}
+
 #define MASK_XMM 0x2
 #define MASK_YMM 0x4
 #define MASK_MASKREG 0x20
@@ -123,6 +129,397 @@
   return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx;
 }
 
+static const CacheLevelInfo kEmptyCacheLevelInfo;
+
+static CacheLevelInfo MakeX86CacheLevelInfo(int level, CacheType cache_type,
+                                            int cache_size, int ways,
+                                            int line_size, int entries,
+                                            int partitioning) {
+  CacheLevelInfo info;
+  info.level = level;
+  info.cache_type = cache_type;
+  info.cache_size = cache_size;
+  info.ways = ways;
+  info.line_size = line_size;
+  info.tlb_entries = entries;
+  info.partitioning = partitioning;
+  return info;
+}
+
+static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg) {
+  const int UNDEF = -1;
+  const int KiB = 1024;
+  const int MiB = 1024 * KiB;
+  const int GiB = 1024 * MiB;
+  switch (reg) {
+    case 0x01:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, 4,
+                                   UNDEF, 32, 0);
+    case 0x02:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * MiB, 0xFF,
+                                   UNDEF, 2, 0);
+    case 0x03:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, 4,
+                                   UNDEF, 64, 0);
+    case 0x04:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * MiB, 4,
+                                   UNDEF, 8, 0);
+    case 0x05:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * MiB, 4,
+                                   UNDEF, 32, 0);
+    case 0x06:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_INSTRUCTION, 8 * KiB, 4,
+                                   32, UNDEF, 0);
+    case 0x08:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_INSTRUCTION, 16 * KiB,
+                                   4, 32, UNDEF, 0);
+    case 0x09:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_INSTRUCTION, 32 * KiB,
+                                   4, 64, UNDEF, 0);
+    case 0x0A:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_DATA, 8 * KiB, 2, 32,
+                                   UNDEF, 0);
+    case 0x0B:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * MiB, 4,
+                                   UNDEF, 4, 0);
+    case 0x0C:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_DATA, 16 * KiB, 4, 32,
+                                   UNDEF, 0);
+    case 0x0D:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_DATA, 16 * KiB, 4, 64,
+                                   UNDEF, 0);
+    case 0x0E:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_DATA, 24 * KiB, 6, 64,
+                                   UNDEF, 0);
+    case 0x1D:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 128 * KiB, 2, 64,
+                                   UNDEF, 0);
+    case 0x21:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 256 * KiB, 8, 64,
+                                   UNDEF, 0);
+    case 0x22:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 512 * KiB, 4, 64,
+                                   UNDEF, 2);
+    case 0x23:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 1 * MiB, 8, 64,
+                                   UNDEF, 2);
+    case 0x24:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 1 * MiB, 16, 64,
+                                   UNDEF, 0);
+    case 0x25:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 2 * MiB, 8, 64,
+                                   UNDEF, 2);
+    case 0x29:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 4 * MiB, 8, 64,
+                                   UNDEF, 2);
+    case 0x2C:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_DATA, 32 * KiB, 8, 64,
+                                   UNDEF, 0);
+    case 0x30:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_INSTRUCTION, 32 * KiB,
+                                   8, 64, UNDEF, 0);
+    case 0x40:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_DATA, UNDEF, UNDEF,
+                                   UNDEF, UNDEF, 0);
+    case 0x41:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 128 * KiB, 4, 32,
+                                   UNDEF, 0);
+    case 0x42:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 256 * KiB, 4, 32,
+                                   UNDEF, 0);
+    case 0x43:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 512 * KiB, 4, 32,
+                                   UNDEF, 0);
+    case 0x44:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 1 * MiB, 4, 32,
+                                   UNDEF, 0);
+    case 0x45:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 2 * MiB, 4, 32,
+                                   UNDEF, 0);
+    case 0x46:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 4 * MiB, 4, 64,
+                                   UNDEF, 0);
+    case 0x47:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 8 * MiB, 8, 64,
+                                   UNDEF, 0);
+    case 0x48:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 3 * MiB, 12, 64,
+                                   UNDEF, 0);
+    case 0x49:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 4 * MiB, 16, 64,
+                                   UNDEF, 0);
+    case (0x49 | (1 << 8)):
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 4 * MiB, 16, 64,
+                                   UNDEF, 0);
+    case 0x4A:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 6 * MiB, 12, 64,
+                                   UNDEF, 0);
+    case 0x4B:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 8 * MiB, 16, 64,
+                                   UNDEF, 0);
+    case 0x4C:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 12 * MiB, 12, 64,
+                                   UNDEF, 0);
+    case 0x4D:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 16 * MiB, 16, 64,
+                                   UNDEF, 0);
+    case 0x4E:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 6 * MiB, 24, 64,
+                                   UNDEF, 0);
+    case 0x4F:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, UNDEF,
+                                   UNDEF, 32, 0);
+    case 0x50:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, UNDEF,
+                                   UNDEF, 64, 0);
+    case 0x51:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, UNDEF,
+                                   UNDEF, 128, 0);
+    case 0x52:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, UNDEF,
+                                   UNDEF, 256, 0);
+    case 0x55:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 2 * MiB, 0xFF,
+                                   UNDEF, 7, 0);
+    case 0x56:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * MiB, 4,
+                                   UNDEF, 16, 0);
+    case 0x57:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, 4,
+                                   UNDEF, 16, 0);
+    case 0x59:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, 0xFF,
+                                   UNDEF, 16, 0);
+    case 0x5A:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 2 * MiB, 4,
+                                   UNDEF, 32, 0);
+    case 0x5B:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, UNDEF,
+                                   UNDEF, 64, 0);
+    case 0x5C:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, UNDEF,
+                                   UNDEF, 128, 0);
+    case 0x5D:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4, UNDEF,
+                                   UNDEF, 256, 0);
+    case 0x60:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_DATA, 16 * KiB, 8, 64,
+                                   UNDEF, 0);
+    case 0x61:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, 0xFF,
+                                   UNDEF, 48, 0);
+    case 0x63:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 2 * MiB, 4,
+                                   UNDEF, 4, 0);
+    case 0x66:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_DATA, 8 * KiB, 4, 64,
+                                   UNDEF, 0);
+    case 0x67:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_DATA, 16 * KiB, 4, 64,
+                                   UNDEF, 0);
+    case 0x68:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_DATA, 32 * KiB, 4, 64,
+                                   UNDEF, 0);
+    case 0x70:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_INSTRUCTION, 12 * KiB,
+                                   8, UNDEF, UNDEF, 0);
+    case 0x71:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_INSTRUCTION, 16 * KiB,
+                                   8, UNDEF, UNDEF, 0);
+    case 0x72:
+      return MakeX86CacheLevelInfo(1, CPU_FEATURE_CACHE_INSTRUCTION, 32 * KiB,
+                                   8, UNDEF, UNDEF, 0);
+    case 0x76:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 2 * MiB, 0xFF,
+                                   UNDEF, 8, 0);
+    case 0x78:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 1 * MiB, 4, 64,
+                                   UNDEF, 0);
+    case 0x79:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 128 * KiB, 8, 64,
+                                   UNDEF, 2);
+    case 0x7A:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 256 * KiB, 8, 64,
+                                   UNDEF, 2);
+    case 0x7B:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 512 * KiB, 8, 64,
+                                   UNDEF, 2);
+    case 0x7C:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 1 * MiB, 8, 64,
+                                   UNDEF, 2);
+    case 0x7D:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 2 * MiB, 8, 64,
+                                   UNDEF, 0);
+    case 0x7F:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 512 * KiB, 2, 64,
+                                   UNDEF, 0);
+    case 0x80:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 512 * KiB, 8, 64,
+                                   UNDEF, 0);
+    case 0x82:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 256 * KiB, 8, 32,
+                                   UNDEF, 0);
+    case 0x83:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 512 * KiB, 8, 32,
+                                   UNDEF, 0);
+    case 0x84:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 1 * MiB, 8, 32,
+                                   UNDEF, 0);
+    case 0x85:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 2 * MiB, 8, 32,
+                                   UNDEF, 0);
+    case 0x86:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 512 * KiB, 4, 32,
+                                   UNDEF, 0);
+    case 0x87:
+      return MakeX86CacheLevelInfo(2, CPU_FEATURE_CACHE_DATA, 1 * MiB, 8, 64,
+                                   UNDEF, 0);
+    case 0xA0:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_DTLB, 4 * KiB, 0xFF,
+                                   UNDEF, 32, 0);
+    case 0xB0:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, 4,
+                                   UNDEF, 128, 0);
+    case 0xB1:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 2 * MiB, 4,
+                                   UNDEF, 8, 0);
+    case 0xB2:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, 4,
+                                   UNDEF, 64, 0);
+    case 0xB3:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, 4,
+                                   UNDEF, 128, 0);
+    case 0xB4:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, 4,
+                                   UNDEF, 256, 0);
+    case 0xB5:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, 8,
+                                   UNDEF, 64, 0);
+    case 0xB6:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, 8,
+                                   UNDEF, 128, 0);
+    case 0xBA:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, 4,
+                                   UNDEF, 64, 0);
+    case 0xC0:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_TLB, 4 * KiB, 4,
+                                   UNDEF, 8, 0);
+    case 0xC1:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_STLB, 4 * KiB, 8,
+                                   UNDEF, 1024, 0);
+    case 0xC2:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_DTLB, 4 * KiB, 4,
+                                   UNDEF, 16, 0);
+    case 0xC3:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_STLB, 4 * KiB, 6,
+                                   UNDEF, 1536, 0);
+    case 0xCA:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_STLB, 4 * KiB, 4,
+                                   UNDEF, 512, 0);
+    case 0xD0:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 512 * KiB, 4, 64,
+                                   UNDEF, 0);
+    case 0xD1:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 1 * MiB, 4, 64,
+                                   UNDEF, 0);
+    case 0xD2:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 2 * MiB, 4, 64,
+                                   UNDEF, 0);
+    case 0xD6:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 1 * MiB, 8, 64,
+                                   UNDEF, 0);
+    case 0xD7:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 2 * MiB, 8, 64,
+                                   UNDEF, 0);
+    case 0xD8:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 4 * MiB, 8, 64,
+                                   UNDEF, 0);
+    case 0xDC:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 1 * 1536 * KiB,
+                                   12, 64, UNDEF, 0);
+    case 0xDD:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 3 * MiB, 12, 64,
+                                   UNDEF, 0);
+    case 0xDE:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 6 * MiB, 12, 64,
+                                   UNDEF, 0);
+    case 0xE2:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 2 * MiB, 16, 64,
+                                   UNDEF, 0);
+    case 0xE3:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 4 * MiB, 16, 64,
+                                   UNDEF, 0);
+    case 0xE4:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 8 * MiB, 16, 64,
+                                   UNDEF, 0);
+    case 0xEA:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 12 * MiB, 24, 64,
+                                   UNDEF, 0);
+    case 0xEB:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 18 * MiB, 24, 64,
+                                   UNDEF, 0);
+    case 0xEC:
+      return MakeX86CacheLevelInfo(3, CPU_FEATURE_CACHE_DATA, 24 * MiB, 24, 64,
+                                   UNDEF, 0);
+    case 0xF0:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_PREFETCH, 64 * KiB,
+                                   UNDEF, UNDEF, UNDEF, 0);
+    case 0xF1:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_PREFETCH, 128 * KiB,
+                                   UNDEF, UNDEF, UNDEF, 0);
+    case 0xFF:
+      return MakeX86CacheLevelInfo(UNDEF, CPU_FEATURE_CACHE_NULL, UNDEF, UNDEF,
+                                   UNDEF, UNDEF, 0);
+    default:
+      return kEmptyCacheLevelInfo;
+  }
+}
+
+static void GetByteArrayFromRegister(uint32_t result[4], const uint32_t reg) {
+  for (int i = 0; i < 4; ++i) {
+    result[i] = ExtractBitRange(reg, (i + 1) * 8, i * 8);
+  }
+}
+
+static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info) {
+  Leaf leaf = SafeCpuId(max_cpuid_leaf, 2);
+  uint32_t registers[] = {leaf.eax, leaf.ebx, leaf.ecx, leaf.edx};
+  for (int i = 0; i < 4; ++i) {
+    if (registers[i] & (1 << 31)) {
+      continue;  // register does not contains valid information
+    }
+    uint32_t bytes[4];
+    GetByteArrayFromRegister(bytes, registers[i]);
+    for (int i = 0; i < 4; ++i) {
+      if (bytes[i] == 0xFF)
+        break;  // leaf 4 should be used to fetch cache information
+      info->levels[info->size] = GetCacheLevelInfo(bytes[i]);
+    }
+    info->size++;
+  }
+}
+
+static void ParseLeaf4(const int max_cpuid_leaf, CacheInfo* info) {
+  info->size = 0;
+  for (int cache_id = 0; cache_id < CPU_FEATURES_MAX_CACHE_LEVEL; cache_id++) {
+    const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, 4, cache_id);
+    CacheType cache_type = ExtractBitRange(leaf.eax, 4, 0);
+    if (cache_type == CPU_FEATURE_CACHE_NULL) {
+      info->levels[cache_id] = kEmptyCacheLevelInfo;
+      continue;
+    }
+    int level = ExtractBitRange(leaf.eax, 7, 5);
+    int line_size = ExtractBitRange(leaf.ebx, 11, 0) + 1;
+    int partitioning = ExtractBitRange(leaf.ebx, 21, 12) + 1;
+    int ways = ExtractBitRange(leaf.ebx, 31, 22) + 1;
+    int entries = leaf.ecx + 1;
+    int cache_size = (ways * partitioning * line_size * (entries));
+    info->levels[cache_id] = MakeX86CacheLevelInfo(
+        level, cache_type, cache_size, ways, line_size, entries, partitioning);
+    info->size++;
+  }
+}
+
 // Reference https://en.wikipedia.org/wiki/CPUID.
 static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info) {
   const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
@@ -146,8 +543,16 @@
   info->model = (extended_model << 4) + model;
   info->stepping = ExtractBitRange(leaf_1.eax, 3, 0);
 
+  features->fpu = IsBitSet(leaf_1.edx, 0);
+  features->tsc = IsBitSet(leaf_1.edx, 4);
+  features->cx8 = IsBitSet(leaf_1.edx, 8);
+  features->clfsh = IsBitSet(leaf_1.edx, 19);
+  features->mmx = IsBitSet(leaf_1.edx, 23);
+  features->ss = IsBitSet(leaf_1.edx, 27);
+  features->pclmulqdq = IsBitSet(leaf_1.ecx, 1);
   features->smx = IsBitSet(leaf_1.ecx, 6);
   features->cx16 = IsBitSet(leaf_1.ecx, 13);
+  features->dca = IsBitSet(leaf_1.ecx, 18);
   features->movbe = IsBitSet(leaf_1.ecx, 22);
   features->popcnt = IsBitSet(leaf_1.ecx, 23);
   features->aes = IsBitSet(leaf_1.ecx, 25);
@@ -155,12 +560,21 @@
   features->rdrnd = IsBitSet(leaf_1.ecx, 30);
   features->sgx = IsBitSet(leaf_7.ebx, 2);
   features->bmi1 = IsBitSet(leaf_7.ebx, 3);
+  features->hle = IsBitSet(leaf_7.ebx, 4);
   features->bmi2 = IsBitSet(leaf_7.ebx, 8);
   features->erms = IsBitSet(leaf_7.ebx, 9);
+  features->rtm = IsBitSet(leaf_7.ebx, 11);
+  features->rdseed = IsBitSet(leaf_7.ebx, 18);
+  features->clflushopt = IsBitSet(leaf_7.ebx, 23);
+  features->clwb = IsBitSet(leaf_7.ebx, 24);
   features->sha = IsBitSet(leaf_7.ebx, 29);
+  features->vaes = IsBitSet(leaf_7.ecx, 9);
   features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10);
 
   if (have_sse_os_support) {
+    features->sse = IsBitSet(leaf_1.edx, 25);
+    features->sse2 = IsBitSet(leaf_1.edx, 26);
+    features->sse3 = IsBitSet(leaf_1.ecx, 0);
     features->ssse3 = IsBitSet(leaf_1.ecx, 9);
     features->sse4_1 = IsBitSet(leaf_1.ecx, 19);
     features->sse4_2 = IsBitSet(leaf_1.ecx, 20);
@@ -192,6 +606,7 @@
 }
 
 static const X86Info kEmptyX86Info;
+static const CacheInfo kEmptyCacheInfo;
 
 X86Info GetX86Info(void) {
   X86Info info = kEmptyX86Info;
@@ -204,6 +619,17 @@
   return info;
 }
 
+CacheInfo GetX86CacheInfo(void) {
+  CacheInfo info = kEmptyCacheInfo;
+  const Leaf leaf_0 = CpuId(0);
+  const uint32_t max_cpuid_leaf = leaf_0.eax;
+  if (IsVendor(leaf_0, "GenuineIntel")) {
+    ParseLeaf2(max_cpuid_leaf, &info);
+    ParseLeaf4(max_cpuid_leaf, &info);
+  }
+  return info;
+}
+
 #define CPUID(FAMILY, MODEL) ((((FAMILY)&0xFF) << 8) | ((MODEL)&0xFF))
 
 X86Microarchitecture GetX86Microarchitecture(const X86Info* info) {
@@ -317,6 +743,16 @@
 int GetX86FeaturesEnumValue(const X86Features* features,
                             X86FeaturesEnum value) {
   switch (value) {
+    case X86_FPU:
+      return features->fpu;
+    case X86_TSC:
+      return features->tsc;
+    case X86_CX8:
+      return features->cx8;
+    case X86_CLFSH:
+      return features->clfsh;
+    case X86_MMX:
+      return features->mmx;
     case X86_AES:
       return features->aes;
     case X86_ERMS:
@@ -325,12 +761,30 @@
       return features->f16c;
     case X86_FMA3:
       return features->fma3;
+    case X86_VAES:
+      return features->vaes;
     case X86_VPCLMULQDQ:
       return features->vpclmulqdq;
     case X86_BMI1:
       return features->bmi1;
+    case X86_HLE:
+      return features->hle;
     case X86_BMI2:
       return features->bmi2;
+    case X86_RTM:
+      return features->rtm;
+    case X86_RDSEED:
+      return features->rdseed;
+    case X86_CLFLUSHOPT:
+      return features->clflushopt;
+    case X86_CLWB:
+      return features->clwb;
+    case X86_SSE:
+      return features->sse;
+    case X86_SSE2:
+      return features->sse2;
+    case X86_SSE3:
+      return features->sse3;
     case X86_SSSE3:
       return features->ssse3;
     case X86_SSE4_1:
@@ -371,6 +825,8 @@
       return features->avx512_4vnniw;
     case X86_AVX512_4VBMI2:
       return features->avx512_4vbmi2;
+    case X86_PCLMULQDQ:
+      return features->pclmulqdq;
     case X86_SMX:
       return features->smx;
     case X86_SGX:
@@ -385,6 +841,10 @@
       return features->movbe;
     case X86_RDRND:
       return features->rdrnd;
+    case X86_DCA:
+      return features->dca;
+    case X86_SS:
+      return features->ss;
     case X86_LAST_:
       break;
   }
@@ -393,6 +853,16 @@
 
 const char* GetX86FeaturesEnumName(X86FeaturesEnum value) {
   switch (value) {
+    case X86_FPU:
+      return "fpu";
+    case X86_TSC:
+      return "tsc";
+    case X86_CX8:
+      return "cx8";
+    case X86_CLFSH:
+      return "clfsh";
+    case X86_MMX:
+      return "mmx";
     case X86_AES:
       return "aes";
     case X86_ERMS:
@@ -401,12 +871,30 @@
       return "f16c";
     case X86_FMA3:
       return "fma3";
+    case X86_VAES:
+      return "vaes";
     case X86_VPCLMULQDQ:
       return "vpclmulqdq";
     case X86_BMI1:
       return "bmi1";
+    case X86_HLE:
+      return "hle";
     case X86_BMI2:
       return "bmi2";
+    case X86_RTM:
+      return "rtm";
+    case X86_RDSEED:
+      return "rdseed";
+    case X86_CLFLUSHOPT:
+      return "clflushopt";
+    case X86_CLWB:
+      return "clwb";
+    case X86_SSE:
+      return "sse";
+    case X86_SSE2:
+      return "sse2";
+    case X86_SSE3:
+      return "sse3";
     case X86_SSSE3:
       return "ssse3";
     case X86_SSE4_1:
@@ -447,6 +935,8 @@
       return "avx512_4vnniw";
     case X86_AVX512_4VBMI2:
       return "avx512_4vbmi2";
+    case X86_PCLMULQDQ:
+      return "pclmulqdq";
     case X86_SMX:
       return "smx";
     case X86_SGX:
@@ -461,6 +951,10 @@
       return "movbe";
     case X86_RDRND:
       return "rdrnd";
+    case X86_DCA:
+      return "dca";
+    case X86_SS:
+      return "ss";
     case X86_LAST_:
       break;
   }
diff --git a/src/filesystem.c b/src/filesystem.c
index 25444da..2f7083b 100644
--- a/src/filesystem.c
+++ b/src/filesystem.c
@@ -16,6 +16,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <stdlib.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -24,14 +25,16 @@
 #elif defined(_MSC_VER)
 #include <io.h>
 int CpuFeatures_OpenFile(const char* filename) {
-  return _open(filename, _O_RDONLY);
+  int fd = -1;
+  _sopen_s(&fd, filename, _O_RDONLY, _SH_DENYWR, _S_IREAD);
+  return fd;
 }
 
 void CpuFeatures_CloseFile(int file_descriptor) { _close(file_descriptor); }
 
 int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
                          size_t buffer_size) {
-  return _read(file_descriptor, buffer, buffer_size);
+  return _read(file_descriptor, buffer, (unsigned int)buffer_size);
 }
 
 #else
diff --git a/src/string_view.c b/src/string_view.c
index 4f27cbd..856731c 100644
--- a/src/string_view.c
+++ b/src/string_view.c
@@ -22,7 +22,7 @@
   if (view.ptr && view.size) {
     const char* const found = (const char*)memchr(view.ptr, c, view.size);
     if (found) {
-      return found - view.ptr;
+      return (int)(found - view.ptr);
     }
   }
   return -1;
@@ -38,7 +38,7 @@
       if (found_index < 0) break;
       remainder = CpuFeatures_StringView_PopFront(remainder, found_index);
       if (CpuFeatures_StringView_StartsWith(remainder, sub_view)) {
-        return remainder.ptr - view.ptr;
+        return (int)(remainder.ptr - view.ptr);
       }
       remainder = CpuFeatures_StringView_PopFront(remainder, 1);
     }
diff --git a/src/utils/list_cpu_features.c b/src/utils/list_cpu_features.c
index a9ff829..acda5e7 100644
--- a/src/utils/list_cpu_features.c
+++ b/src/utils/list_cpu_features.c
@@ -136,7 +136,7 @@
         ++count;                                                           \
       }                                                                    \
     }                                                                      \
-    qsort(ptrs, count, sizeof(char*), cmp);                                \
+    qsort((void*)ptrs, count, sizeof(char*), cmp);                         \
     p.StartField("flags");                                                 \
     p.ArrayStart();                                                        \
     for (i = 0; i < count; ++i) {                                          \
diff --git a/test/bit_utils_test.cc b/test/bit_utils_test.cc
index 8937cbc..9c8c1bb 100644
--- a/test/bit_utils_test.cc
+++ b/test/bit_utils_test.cc
@@ -22,18 +22,18 @@
 TEST(UtilsTest, IsBitSet) {
   for (size_t bit_set = 0; bit_set < 32; ++bit_set) {
     const uint32_t value = 1UL << bit_set;
-    for (size_t i = 0; i < 32; ++i) {
+    for (uint32_t i = 0; i < 32; ++i) {
       EXPECT_EQ(IsBitSet(value, i), i == bit_set);
     }
   }
 
   // testing 0, all bits should be 0.
-  for (size_t i = 0; i < 32; ++i) {
+  for (uint32_t i = 0; i < 32; ++i) {
     EXPECT_FALSE(IsBitSet(0, i));
   }
 
   // testing ~0, all bits should be 1.
-  for (size_t i = 0; i < 32; ++i) {
+  for (uint32_t i = 0; i < 32; ++i) {
     EXPECT_TRUE(IsBitSet(-1, i));
   }
 }
diff --git a/test/cpuinfo_arm_test.cc b/test/cpuinfo_arm_test.cc
index 34c7551..9ddf90f 100644
--- a/test/cpuinfo_arm_test.cc
+++ b/test/cpuinfo_arm_test.cc
@@ -35,6 +35,8 @@
 
   EXPECT_FALSE(info.features.vfpv4);
   EXPECT_FALSE(info.features.iwmmxt);
+  EXPECT_FALSE(info.features.crunch);
+  EXPECT_FALSE(info.features.thumbee);
   EXPECT_FALSE(info.features.vfpv3d16);
   EXPECT_FALSE(info.features.idiva);
   EXPECT_FALSE(info.features.idivt);
@@ -62,14 +64,28 @@
   EXPECT_EQ(info.revision, 3);
   EXPECT_EQ(info.architecture, 7);
 
+  EXPECT_FALSE(info.features.swp);
+  EXPECT_TRUE(info.features.half);
+  EXPECT_TRUE(info.features.thumb);
+  EXPECT_FALSE(info.features._26bit);
+  EXPECT_TRUE(info.features.fastmult);
+  EXPECT_FALSE(info.features.fpa);
   EXPECT_TRUE(info.features.vfp);
+  EXPECT_TRUE(info.features.edsp);
+  EXPECT_FALSE(info.features.java);
   EXPECT_FALSE(info.features.iwmmxt);
+  EXPECT_FALSE(info.features.crunch);
+  EXPECT_FALSE(info.features.thumbee);
   EXPECT_TRUE(info.features.neon);
   EXPECT_TRUE(info.features.vfpv3);
   EXPECT_FALSE(info.features.vfpv3d16);
+  EXPECT_TRUE(info.features.tls);
   EXPECT_TRUE(info.features.vfpv4);
   EXPECT_TRUE(info.features.idiva);
   EXPECT_TRUE(info.features.idivt);
+  EXPECT_TRUE(info.features.vfpd32);
+  EXPECT_TRUE(info.features.lpae);
+  EXPECT_FALSE(info.features.evtstrm);
   EXPECT_FALSE(info.features.aes);
   EXPECT_FALSE(info.features.pmull);
   EXPECT_FALSE(info.features.sha1);
@@ -77,6 +93,122 @@
   EXPECT_FALSE(info.features.crc32);
 }
 
+// Linux test-case
+TEST(CpuinfoArmTest, RaspberryPiZeroFromCpuInfo) {
+  DisableHardwareCapabilities();
+  auto& fs = GetEmptyFilesystem();
+  fs.CreateFile("/proc/cpuinfo", R"(processor       : 0
+model name      : ARMv6-compatible processor rev 7 (v6l)
+BogoMIPS        : 697.95
+Features        : half thumb fastmult vfp edsp java tls
+CPU implementer : 0x41
+CPU architecture: 7
+CPU variant     : 0x0
+CPU part        : 0xb76
+CPU revision    : 7
+
+Hardware        : BCM2835
+Revision        : 9000c1
+Serial          : 000000006cd946f3)");
+  const auto info = GetArmInfo();
+  EXPECT_EQ(info.implementer, 0x41);
+  EXPECT_EQ(info.variant, 0x0);
+  EXPECT_EQ(info.part, 0xb76);
+  EXPECT_EQ(info.revision, 7);
+  EXPECT_EQ(info.architecture, 6);
+
+  EXPECT_FALSE(info.features.swp);
+  EXPECT_TRUE(info.features.half);
+  EXPECT_TRUE(info.features.thumb);
+  EXPECT_FALSE(info.features._26bit);
+  EXPECT_TRUE(info.features.fastmult);
+  EXPECT_FALSE(info.features.fpa);
+  EXPECT_TRUE(info.features.vfp);
+  EXPECT_TRUE(info.features.edsp);
+  EXPECT_TRUE(info.features.java);
+  EXPECT_FALSE(info.features.iwmmxt);
+  EXPECT_FALSE(info.features.crunch);
+  EXPECT_FALSE(info.features.thumbee);
+  EXPECT_FALSE(info.features.neon);
+  EXPECT_FALSE(info.features.vfpv3);
+  EXPECT_FALSE(info.features.vfpv3d16);
+  EXPECT_TRUE(info.features.tls);
+  EXPECT_FALSE(info.features.vfpv4);
+  EXPECT_FALSE(info.features.idiva);
+  EXPECT_FALSE(info.features.idivt);
+  EXPECT_FALSE(info.features.vfpd32);
+  EXPECT_FALSE(info.features.lpae);
+  EXPECT_FALSE(info.features.evtstrm);
+  EXPECT_FALSE(info.features.aes);
+  EXPECT_FALSE(info.features.pmull);
+  EXPECT_FALSE(info.features.sha1);
+  EXPECT_FALSE(info.features.sha2);
+  EXPECT_FALSE(info.features.crc32);
+}
+
+TEST(CpuinfoArmTest, MarvellArmadaFromCpuInfo) {
+  DisableHardwareCapabilities();
+  auto& fs = GetEmptyFilesystem();
+  fs.CreateFile("/proc/cpuinfo", R"(processor       : 0
+model name      : ARMv7 Processor rev 1 (v7l)
+BogoMIPS        : 50.00
+Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpd32
+CPU implementer : 0x41
+CPU architecture: 7
+CPU variant     : 0x4
+CPU part        : 0xc09
+CPU revision    : 1
+
+processor       : 1
+model name      : ARMv7 Processor rev 1 (v7l)
+BogoMIPS        : 50.00
+Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpd32
+CPU implementer : 0x41
+CPU architecture: 7
+CPU variant     : 0x4
+CPU part        : 0xc09
+CPU revision    : 1
+
+Hardware        : Marvell Armada 380/385 (Device Tree)
+Revision        : 0000
+Serial          : 0000000000000000)");
+  const auto info = GetArmInfo();
+  EXPECT_EQ(info.implementer, 0x41);
+  EXPECT_EQ(info.variant, 0x4);
+  EXPECT_EQ(info.part, 0xc09);
+  EXPECT_EQ(info.revision, 1);
+  EXPECT_EQ(info.architecture, 7);
+
+  EXPECT_FALSE(info.features.swp);
+  EXPECT_TRUE(info.features.half);
+  EXPECT_TRUE(info.features.thumb);
+  EXPECT_FALSE(info.features._26bit);
+  EXPECT_TRUE(info.features.fastmult);
+  EXPECT_FALSE(info.features.fpa);
+  EXPECT_TRUE(info.features.vfp);
+  EXPECT_TRUE(info.features.edsp);
+  EXPECT_FALSE(info.features.java);
+  EXPECT_FALSE(info.features.iwmmxt);
+  EXPECT_FALSE(info.features.crunch);
+  EXPECT_FALSE(info.features.thumbee);
+  EXPECT_TRUE(info.features.neon);
+  EXPECT_TRUE(info.features.vfpv3);
+  EXPECT_FALSE(info.features.vfpv3d16);
+  EXPECT_TRUE(info.features.tls);
+  EXPECT_FALSE(info.features.vfpv4);
+  EXPECT_FALSE(info.features.idiva);
+  EXPECT_FALSE(info.features.idivt);
+  EXPECT_TRUE(info.features.vfpd32);
+  EXPECT_FALSE(info.features.lpae);
+  EXPECT_FALSE(info.features.evtstrm);
+  EXPECT_FALSE(info.features.aes);
+  EXPECT_FALSE(info.features.pmull);
+  EXPECT_FALSE(info.features.sha1);
+  EXPECT_FALSE(info.features.sha2);
+  EXPECT_FALSE(info.features.crc32);
+}
+
+// Android test-case
 // http://code.google.com/p/android/issues/detail?id=10812
 TEST(CpuinfoArmTest, InvalidArmv7) {
   DisableHardwareCapabilities();
@@ -96,8 +228,37 @@
 Serial          : 33323613546d00ec )");
   const auto info = GetArmInfo();
   EXPECT_EQ(info.architecture, 6);
+
+  EXPECT_TRUE(info.features.swp);
+  EXPECT_TRUE(info.features.half);
+  EXPECT_TRUE(info.features.thumb);
+  EXPECT_FALSE(info.features._26bit);
+  EXPECT_TRUE(info.features.fastmult);
+  EXPECT_FALSE(info.features.fpa);
+  EXPECT_TRUE(info.features.vfp);
+  EXPECT_TRUE(info.features.edsp);
+  EXPECT_TRUE(info.features.java);
+  EXPECT_FALSE(info.features.iwmmxt);
+  EXPECT_FALSE(info.features.crunch);
+  EXPECT_FALSE(info.features.thumbee);
+  EXPECT_FALSE(info.features.neon);
+  EXPECT_FALSE(info.features.vfpv3);
+  EXPECT_FALSE(info.features.vfpv3d16);
+  EXPECT_FALSE(info.features.tls);
+  EXPECT_FALSE(info.features.vfpv4);
+  EXPECT_FALSE(info.features.idiva);
+  EXPECT_FALSE(info.features.idivt);
+  EXPECT_FALSE(info.features.vfpd32);
+  EXPECT_FALSE(info.features.lpae);
+  EXPECT_FALSE(info.features.evtstrm);
+  EXPECT_FALSE(info.features.aes);
+  EXPECT_FALSE(info.features.pmull);
+  EXPECT_FALSE(info.features.sha1);
+  EXPECT_FALSE(info.features.sha2);
+  EXPECT_FALSE(info.features.crc32);
 }
 
+// Android test-case
 // https://crbug.com/341598.
 TEST(CpuinfoArmTest, InvalidNeon) {
   auto& fs = GetEmptyFilesystem();
@@ -120,6 +281,7 @@
 Revision: 0010
 Serial: 00001e030000354e)");
   const auto info = GetArmInfo();
+  EXPECT_TRUE(info.features.swp);
   EXPECT_FALSE(info.features.neon);
 }
 
diff --git a/test/cpuinfo_x86_test.cc b/test/cpuinfo_x86_test.cc
index 2389de9..10b9624 100644
--- a/test/cpuinfo_x86_test.cc
+++ b/test/cpuinfo_x86_test.cc
@@ -25,15 +25,17 @@
 
 class FakeCpu {
  public:
-  Leaf CpuId(uint32_t leaf_id) const {
-    const auto itr = cpuid_leaves_.find(leaf_id);
-    EXPECT_TRUE(itr != cpuid_leaves_.end()) << "Missing leaf " << leaf_id;
-    return itr->second;
+  Leaf CpuIdEx(uint32_t leaf_id, int ecx) const {
+    const auto itr = cpuid_leaves_.find(std::make_pair(leaf_id, ecx));
+    if (itr != cpuid_leaves_.end()) {
+      return itr->second;
+    }
+    return {0, 0, 0, 0};
   }
 
   uint32_t GetXCR0Eax() const { return xcr0_eax_; }
 
-  void SetLeaves(std::map<uint32_t, Leaf> configuration) {
+  void SetLeaves(std::map<std::pair<uint32_t, int>, Leaf> configuration) {
     cpuid_leaves_ = std::move(configuration);
   }
 
@@ -42,13 +44,16 @@
   }
 
  private:
-  std::map<uint32_t, Leaf> cpuid_leaves_;
+  std::map<std::pair<uint32_t, int>, Leaf> cpuid_leaves_;
   uint32_t xcr0_eax_;
 };
 
 auto* g_fake_cpu = new FakeCpu();
 
-extern "C" Leaf CpuId(uint32_t leaf_id) { return g_fake_cpu->CpuId(leaf_id); }
+extern "C" Leaf CpuIdEx(uint32_t leaf_id, int ecx) {
+  return g_fake_cpu->CpuIdEx(leaf_id, ecx);
+}
+
 extern "C" uint32_t GetXCR0Eax(void) { return g_fake_cpu->GetXCR0Eax(); }
 
 namespace {
@@ -56,9 +61,9 @@
 TEST(CpuidX86Test, SandyBridge) {
   g_fake_cpu->SetOsBackupsExtendedRegisters(true);
   g_fake_cpu->SetLeaves({
-      {0x00000000, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
-      {0x00000001, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
-      {0x00000007, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+      {{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
+      {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
   });
   const auto info = GetX86Info();
   EXPECT_STREQ(info.vendor, "GenuineIntel");
@@ -96,11 +101,14 @@
   EXPECT_FALSE(features.rdrnd);
 }
 
+const int KiB = 1024;
+const int MiB = 1024 * KiB;
+
 TEST(CpuidX86Test, SandyBridgeTestOsSupport) {
   g_fake_cpu->SetLeaves({
-      {0x00000000, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
-      {0x00000001, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
-      {0x00000007, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+      {{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
+      {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
   });
   // avx is disabled if os does not support backing up ymm registers.
   g_fake_cpu->SetOsBackupsExtendedRegisters(false);
@@ -113,9 +121,9 @@
 TEST(CpuidX86Test, SkyLake) {
   g_fake_cpu->SetOsBackupsExtendedRegisters(true);
   g_fake_cpu->SetLeaves({
-      {0x00000000, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
-      {0x00000001, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
-      {0x00000007, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
+      {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
+      {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
   });
   const auto info = GetX86Info();
   EXPECT_STREQ(info.vendor, "GenuineIntel");
@@ -127,32 +135,129 @@
 
 TEST(CpuidX86Test, Branding) {
   g_fake_cpu->SetLeaves({
-      {0x00000000, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
-      {0x00000001, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
-      {0x00000007, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
-      {0x80000000, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
-      {0x80000001, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
-      {0x80000002, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
-      {0x80000003, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
-      {0x80000004, Leaf{0x352E3220, 0x7A484730, 0x00000000, 0x00000000}},
+      {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
+      {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
+      {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
+      {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
+      {{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
+      {{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
+      {{0x80000004, 0}, Leaf{0x352E3220, 0x7A484730, 0x00000000, 0x00000000}},
   });
   char brand_string[49];
   FillX86BrandString(brand_string);
   EXPECT_STREQ(brand_string, "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz");
 }
 
+TEST(CpuidX86Test, KabyLakeCache) {
+  g_fake_cpu->SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
+      {{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
+      {{0x00000004, 1}, Leaf{0x1C004122, 0x01C0003F, 0x0000003F, 0x00000000}},
+      {{0x00000004, 2}, Leaf{0x1C004143, 0x00C0003F, 0x000003FF, 0x00000000}},
+      {{0x00000004, 3}, Leaf{0x1C03C163, 0x02C0003F, 0x00001FFF, 0x00000002}},
+      {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
+      {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
+      {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
+      {{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
+      {{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
+  });
+  const auto info = GetX86CacheInfo();
+  EXPECT_EQ(info.size, 4);
+  EXPECT_EQ(info.levels[0].level, 1);
+  EXPECT_EQ(info.levels[0].cache_type, 1);
+  EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
+  EXPECT_EQ(info.levels[0].ways, 8);
+  EXPECT_EQ(info.levels[0].line_size, 64);
+  EXPECT_EQ(info.levels[0].tlb_entries, 64);
+  EXPECT_EQ(info.levels[0].partitioning, 1);
+
+  EXPECT_EQ(info.levels[1].level, 1);
+  EXPECT_EQ(info.levels[1].cache_type, 2);
+  EXPECT_EQ(info.levels[1].cache_size, 32 * KiB);
+  EXPECT_EQ(info.levels[1].ways, 8);
+  EXPECT_EQ(info.levels[1].line_size, 64);
+  EXPECT_EQ(info.levels[1].tlb_entries, 64);
+  EXPECT_EQ(info.levels[1].partitioning, 1);
+
+  EXPECT_EQ(info.levels[2].level, 2);
+  EXPECT_EQ(info.levels[2].cache_type, 3);
+  EXPECT_EQ(info.levels[2].cache_size, 256 * KiB);
+  EXPECT_EQ(info.levels[2].ways, 4);
+  EXPECT_EQ(info.levels[2].line_size, 64);
+  EXPECT_EQ(info.levels[2].tlb_entries, 1024);
+  EXPECT_EQ(info.levels[2].partitioning, 1);
+
+  EXPECT_EQ(info.levels[3].level, 3);
+  EXPECT_EQ(info.levels[3].cache_type, 3);
+  EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
+  EXPECT_EQ(info.levels[3].ways, 12);
+  EXPECT_EQ(info.levels[3].line_size, 64);
+  EXPECT_EQ(info.levels[3].tlb_entries, 8192);
+  EXPECT_EQ(info.levels[3].partitioning, 1);
+}
+
+TEST(CpuidX86Test, HSWCache) {
+  g_fake_cpu->SetLeaves({
+      {{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
+      {{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
+      {{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
+      {{0x00000004, 1}, Leaf{0x1C004122, 0x01C0003F, 0x0000003F, 0x00000000}},
+      {{0x00000004, 2}, Leaf{0x1C004143, 0x01C0003F, 0x000001FF, 0x00000000}},
+      {{0x00000004, 3}, Leaf{0x1C03C163, 0x02C0003F, 0x00001FFF, 0x00000006}},
+      {{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
+      {{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
+      {{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
+      {{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
+      {{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
+  });
+  const auto info = GetX86CacheInfo();
+  EXPECT_EQ(info.size, 4);
+  EXPECT_EQ(info.levels[0].level, 1);
+  EXPECT_EQ(info.levels[0].cache_type, 1);
+  EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
+  EXPECT_EQ(info.levels[0].ways, 8);
+  EXPECT_EQ(info.levels[0].line_size, 64);
+  EXPECT_EQ(info.levels[0].tlb_entries, 64);
+  EXPECT_EQ(info.levels[0].partitioning, 1);
+
+  EXPECT_EQ(info.levels[1].level, 1);
+  EXPECT_EQ(info.levels[1].cache_type, 2);
+  EXPECT_EQ(info.levels[1].cache_size, 32 * KiB);
+  EXPECT_EQ(info.levels[1].ways, 8);
+  EXPECT_EQ(info.levels[1].line_size, 64);
+  EXPECT_EQ(info.levels[1].tlb_entries, 64);
+  EXPECT_EQ(info.levels[1].partitioning, 1);
+
+  EXPECT_EQ(info.levels[2].level, 2);
+  EXPECT_EQ(info.levels[2].cache_type, 3);
+  EXPECT_EQ(info.levels[2].cache_size, 256 * KiB);
+  EXPECT_EQ(info.levels[2].ways, 8);
+  EXPECT_EQ(info.levels[2].line_size, 64);
+  EXPECT_EQ(info.levels[2].tlb_entries, 512);
+  EXPECT_EQ(info.levels[2].partitioning, 1);
+
+  EXPECT_EQ(info.levels[3].level, 3);
+  EXPECT_EQ(info.levels[3].cache_type, 3);
+  EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
+  EXPECT_EQ(info.levels[3].ways, 12);
+  EXPECT_EQ(info.levels[3].line_size, 64);
+  EXPECT_EQ(info.levels[3].tlb_entries, 8192);
+  EXPECT_EQ(info.levels[3].partitioning, 1);
+}
 // http://users.atw.hu/instlatx64/AuthenticAMD0630F81_K15_Godavari_CPUID.txt
 TEST(CpuidX86Test, AMD_K15) {
   g_fake_cpu->SetLeaves({
-      {0x00000000, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
-      {0x00000001, Leaf{0x00630F81, 0x00040800, 0x3E98320B, 0x178BFBFF}},
-      {0x00000007, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
-      {0x80000000, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
-      {0x80000001, Leaf{0x00630F81, 0x10000000, 0x0FEBBFFF, 0x2FD3FBFF}},
-      {0x80000002, Leaf{0x20444D41, 0x372D3841, 0x4B303736, 0x64615220}},
-      {0x80000003, Leaf{0x206E6F65, 0x202C3752, 0x43203031, 0x75706D6F}},
-      {0x80000004, Leaf{0x43206574, 0x7365726F, 0x2B433420, 0x00204736}},
-      {0x80000005, Leaf{0xFF40FF18, 0xFF40FF30, 0x10040140, 0x60030140}},
+      {{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x00000001, 0}, Leaf{0x00630F81, 0x00040800, 0x3E98320B, 0x178BFBFF}},
+      {{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+      {{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
+      {{0x80000001, 0}, Leaf{0x00630F81, 0x10000000, 0x0FEBBFFF, 0x2FD3FBFF}},
+      {{0x80000002, 0}, Leaf{0x20444D41, 0x372D3841, 0x4B303736, 0x64615220}},
+      {{0x80000003, 0}, Leaf{0x206E6F65, 0x202C3752, 0x43203031, 0x75706D6F}},
+      {{0x80000004, 0}, Leaf{0x43206574, 0x7365726F, 0x2B433420, 0x00204736}},
+      {{0x80000005, 0}, Leaf{0xFF40FF18, 0xFF40FF30, 0x10040140, 0x60030140}},
   });
   const auto info = GetX86Info();
 
diff --git a/test/filesystem_for_testing.cc b/test/filesystem_for_testing.cc
index 4554c1f..0a11416 100644
--- a/test/filesystem_for_testing.cc
+++ b/test/filesystem_for_testing.cc
@@ -45,7 +45,7 @@
   memcpy(buf, content_.data() + head_index_, read);
   head_index_ += read;
   assert(read < INT_MAX);
-  return read;
+  return (int)read;
 }
 
 void FakeFilesystem::Reset() { files_.clear(); }
diff --git a/test/filesystem_for_testing.h b/test/filesystem_for_testing.h
index ca269e5..7474b5f 100644
--- a/test/filesystem_for_testing.h
+++ b/test/filesystem_for_testing.h
@@ -50,7 +50,7 @@
   FakeFile* FindFileOrNull(const std::string& filename) const;
 
  private:
-  size_t next_file_descriptor_ = 0;
+  int next_file_descriptor_ = 0;
   std::unordered_map<std::string, std::unique_ptr<FakeFile>> files_;
 };