/*
 * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation. Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

#include<stdint.h>

// These datastructures are directly copied from HotSpot vm_version_x86.hpp

// cpuid result register layouts.  These are all unions of a uint32_t
// (in case anyone wants access to the register as a whole) and a bitfield.
typedef union {
  uint32_t value;
  struct {
    uint32_t stepping   : 4,
             model      : 4,
             family     : 4,
             proc_type  : 2,
                        : 2,
             ext_model  : 4,
             ext_family : 8,
                        : 4;
  } bits;
} StdCpuid1Eax ;

typedef union { // example, unused
  uint32_t value;
  struct {
    uint32_t brand_id         : 8,
             clflush_size     : 8,
             threads_per_cpu  : 8,
             apic_id          : 8;
  } bits;
} StdCpuid1Ebx ;

typedef union {
  uint32_t value;
  struct {
    uint32_t sse3     : 1,
             clmul    : 1,
                      : 1,
             monitor  : 1,
                      : 1,
             vmx      : 1,
                      : 1,
             est      : 1,
                      : 1,
             ssse3    : 1,
             cid      : 1,
                      : 1,
             fma      : 1,
             cmpxchg16: 1,
                      : 4,
             dca      : 1,
             sse4_1   : 1,
             sse4_2   : 1,
                      : 2,
             popcnt   : 1,
                      : 1,
             aes      : 1,
                      : 1,
             osxsave  : 1,
             avx      : 1,
             f16c     : 1,
                      : 1,
             hv       : 1;
  } bits;
} StdCpuid1Ecx;

typedef union {
  uint32_t value;
  struct {
    uint32_t          : 4,
             tsc      : 1,
                      : 3,
             cmpxchg8 : 1,
                      : 6,
             cmov     : 1,
                      : 3,
             clflush  : 1,
                      : 3,
             mmx      : 1,
             fxsr     : 1,
             sse      : 1,
             sse2     : 1,
                      : 1,
             ht       : 1,
                      : 3;
  } bits;
} StdCpuid1Edx;

typedef union {
  uint32_t value;
  struct {
    uint32_t cache_type    : 5,
                           : 21,
             cores_per_cpu : 6;
  } bits;
} DcpCpuid4Eax;

typedef union {
  uint32_t value;
  struct {
    uint32_t L1_line_size  : 12,
             partitions    : 10,
             associativity : 10;
  } bits;
} DcpCpuid4Ebx;

typedef union {
  uint32_t value;
  struct {
    uint32_t logical_cpus : 16,
                          : 16;
  } bits;
} TplCpuidBEbx;

typedef union {
  uint32_t value;
  struct {
    uint32_t LahfSahf     : 1,
             CmpLegacy    : 1,
                          : 3,
             lzcnt        : 1,
             sse4a        : 1,
             misalignsse  : 1,
             prefetchw    : 1,
                          : 23;
  } bits;
} ExtCpuid1Ecx;

typedef union {
  uint32_t value;
  struct {
    uint32_t           : 22,
             mmx_amd   : 1,
             mmx       : 1,
             fxsr      : 1,
             fxsr_opt  : 1,
             pdpe1gb   : 1,
             rdtscp    : 1,
                       : 1,
             long_mode : 1,
             tdnow2    : 1,
             tdnow     : 1;
  } bits;
} ExtCpuid1Edx;

typedef union {
  uint32_t value;
  struct {
    uint32_t L1_line_size : 8,
             L1_tag_lines : 8,
             L1_assoc     : 8,
             L1_size      : 8;
  } bits;
} ExtCpuid5Ex;

typedef union {
  uint32_t value;
  struct {
    uint32_t               : 8,
            tsc_invariance : 1,
                           : 23;
  } bits;
} ExtCpuid7Edx;

typedef union {
  uint32_t value;
  struct {
    uint32_t cores_per_cpu : 8,
                           : 24;
  } bits;
} ExtCpuid8Ecx;

typedef union {
  uint32_t value;
} SefCpuid7Eax;

typedef union {
  uint32_t value;
  struct {
    uint32_t fsgsbase : 1,
                      : 2,
                 bmi1 : 1,
                      : 1,
                 avx2 : 1,
                      : 2,
                 bmi2 : 1,
                 erms : 1,
                      : 1,
                  rtm : 1,
                      : 4,
              avx512f : 1,
             avx512dq : 1,
                      : 1,
                  adx : 1,
                      : 1,
           avx512ifma : 1,
                      : 1,
           clflushopt : 1,
                 clwb : 1,
                      : 1,
             avx512pf : 1,
             avx512er : 1,
             avx512cd : 1,
                  sha : 1,
             avx512bw : 1,
             avx512vl : 1;
  } bits;
} SefCpuid7Ebx;

typedef union {
  uint32_t value;
  struct {
    uint32_t prefetchwt1 : 1,
             avx512_vbmi : 1,
                    umip : 1,
                     pku : 1,
                   ospke : 1,
                         : 1,
            avx512_vbmi2 : 1,
                  cet_ss : 1,
                    gfni : 1,
                    vaes : 1,
       avx512_vpclmulqdq : 1,
             avx512_vnni : 1,
           avx512_bitalg : 1,
                         : 1,
        avx512_vpopcntdq : 1,
                         : 1,
                         : 1,
                   mawau : 5,
                   rdpid : 1,
                         : 9;
  } bits;
} SefCpuid7Ecx;

typedef union {
  uint32_t value;
  struct {
    uint32_t             : 2,
           avx512_4vnniw : 1,
           avx512_4fmaps : 1,
      fast_short_rep_mov : 1,
                         : 9,
               serialize : 1,
                         : 5,
                 cet_ibt : 1,
                         : 2,
            avx512_fp16  : 1,
                         : 8;
  } bits;
} SefCpuid7Edx;

typedef union {
  uint32_t value;
  struct {
    uint32_t    sha512   : 1,
                         : 22,
                avx_ifma : 1,
                         : 8;
  } bits;
} SefCpuid7SubLeaf1Eax;

typedef union {
  uint32_t value;
  struct {
    uint32_t             : 19,
                avx10    : 1,
                         : 1,
                apx_f    : 1,
                         : 10;
  } bits;
} SefCpuid7SubLeaf1Edx;

typedef union {
  uint32_t value;
  struct {
    uint32_t sub_leaves_cnt : 31;
  } bits;
} StdCpuid24MainLeafEax;

typedef union StdCpuid24MainLeafEbx {
  uint32_t value;
  struct {
    uint32_t avx10_converged_isa_version : 8,
                                         : 8,
                                         : 2,
             avx10_vlen_512              : 1,
                                         : 13;
  } bits;
} StdCpuid24MainLeafEbx;

typedef union StdCpuidEax29Ecx0 {
  uint32_t value;
  struct {
    uint32_t  apx_nci_ndd_nf  : 1,
                              : 31;
  } bits;
} StdCpuidEax29Ecx0;

typedef union {
  uint32_t value;
  struct {
    uint32_t                  : 8,
             threads_per_core : 8,
                              : 16;
  } bits;
} ExtCpuid1EEbx;

typedef union {
  uint32_t value;
  struct {
    uint32_t x87     : 1,
             sse     : 1,
             ymm     : 1,
             bndregs : 1,
             bndcsr  : 1,
             opmask  : 1,
             zmm512  : 1,
             zmm32   : 1,
                     : 11,
             apx_f   : 1,
                     : 12;
  } bits;
} XemXcr0Eax;

// cpuid information block.  All info derived from executing cpuid with
// various function numbers is stored here.  Intel and AMD info is
// merged in this block: accessor methods disentangle it.
//
// The info block is laid out in subblocks of 4 dwords corresponding to
// eax, ebx, ecx and edx, whether or not they contain anything useful.
typedef struct {
  // cpuid function 0
  uint32_t std_max_function;
  uint32_t std_vendor_name_0;
  uint32_t std_vendor_name_1;
  uint32_t std_vendor_name_2;

  // cpuid function 1
  StdCpuid1Eax std_cpuid1_eax;
  StdCpuid1Ebx std_cpuid1_ebx;
  StdCpuid1Ecx std_cpuid1_ecx;
  StdCpuid1Edx std_cpuid1_edx;

  // cpuid function 4 (deterministic cache parameters)
  DcpCpuid4Eax dcp_cpuid4_eax;
  DcpCpuid4Ebx dcp_cpuid4_ebx;
  uint32_t     dcp_cpuid4_ecx; // unused currently
  uint32_t     dcp_cpuid4_edx; // unused currently

  // cpuid function 7 (structured extended features)
  // eax = 7, ecx = 0
  SefCpuid7Eax sef_cpuid7_eax;
  SefCpuid7Ebx sef_cpuid7_ebx;
  SefCpuid7Ecx sef_cpuid7_ecx;
  SefCpuid7Edx sef_cpuid7_edx;
  // cpuid function 7 (structured extended features enumeration sub-leaf 1)
  // eax = 7, ecx = 1
  SefCpuid7SubLeaf1Eax sefsl1_cpuid7_eax;
  SefCpuid7SubLeaf1Edx sefsl1_cpuid7_edx;

  // cpuid function 24 converged vector ISA main leaf
  // eax = 24, ecx = 0
  StdCpuid24MainLeafEax std_cpuid24_eax;
  StdCpuid24MainLeafEbx std_cpuid24_ebx;

  // cpuid function 0x29 APX Advanced Performance Extensions Leaf
  // eax = 0x29, ecx = 0
  StdCpuidEax29Ecx0 std_cpuid29_ebx;

  // cpuid function 0xB (processor topology)
  // ecx = 0
  uint32_t     tpl_cpuidB0_eax;
  TplCpuidBEbx tpl_cpuidB0_ebx;
  uint32_t     tpl_cpuidB0_ecx; // unused currently
  uint32_t     tpl_cpuidB0_edx; // unused currently

  // ecx = 1
  uint32_t     tpl_cpuidB1_eax;
  TplCpuidBEbx tpl_cpuidB1_ebx;
  uint32_t     tpl_cpuidB1_ecx; // unused currently
  uint32_t     tpl_cpuidB1_edx; // unused currently

  // ecx = 2
  uint32_t     tpl_cpuidB2_eax;
  TplCpuidBEbx tpl_cpuidB2_ebx;
  uint32_t     tpl_cpuidB2_ecx; // unused currently
  uint32_t     tpl_cpuidB2_edx; // unused currently

  // cpuid function 0x80000000 // example, unused
  uint32_t ext_max_function;
  uint32_t ext_vendor_name_0;
  uint32_t ext_vendor_name_1;
  uint32_t ext_vendor_name_2;

  // cpuid function 0x80000001
  uint32_t     ext_cpuid1_eax; // reserved
  uint32_t     ext_cpuid1_ebx; // reserved
  ExtCpuid1Ecx ext_cpuid1_ecx;
  ExtCpuid1Edx ext_cpuid1_edx;

  // cpuid functions 0x80000002 thru 0x80000004: example, unused
  uint32_t proc_name_0, proc_name_1, proc_name_2, proc_name_3;
  uint32_t proc_name_4, proc_name_5, proc_name_6, proc_name_7;
  uint32_t proc_name_8, proc_name_9, proc_name_10,proc_name_11;

  // cpuid function 0x80000005 // AMD L1, Intel reserved
  uint32_t     ext_cpuid5_eax; // unused currently
  uint32_t     ext_cpuid5_ebx; // reserved
  ExtCpuid5Ex  ext_cpuid5_ecx; // L1 data cache info (AMD)
  ExtCpuid5Ex  ext_cpuid5_edx; // L1 instruction cache info (AMD)

  // cpuid function 0x80000007
  uint32_t     ext_cpuid7_eax; // reserved
  uint32_t     ext_cpuid7_ebx; // reserved
  uint32_t     ext_cpuid7_ecx; // reserved
  ExtCpuid7Edx ext_cpuid7_edx; // tscinv

  // cpuid function 0x80000008
  uint32_t     ext_cpuid8_eax; // unused currently
  uint32_t     ext_cpuid8_ebx; // reserved
  ExtCpuid8Ecx ext_cpuid8_ecx;
  uint32_t     ext_cpuid8_edx; // reserved

  // cpuid function 0x8000001E // AMD 17h
  uint32_t      ext_cpuid1E_eax;
  ExtCpuid1EEbx ext_cpuid1E_ebx; // threads per core (AMD17h)
  uint32_t      ext_cpuid1E_ecx;
  uint32_t      ext_cpuid1E_edx; // unused currently

  // extended control register XCR0 (the XFEATURE_ENABLED_MASK register)
  XemXcr0Eax   xem_xcr0_eax;
  uint32_t     xem_xcr0_edx; // reserved

  // Space to save ymm registers after signal handle
  int          ymm_save[8*4]; // Save ymm0, ymm7, ymm8, ymm15

  // Space to save zmm registers after signal handle
  int          zmm_save[16*4]; // Save zmm0, zmm7, zmm8, zmm31
} CpuidInfo;

enum Extended_Family {
  // AMD
  CPU_FAMILY_AMD_11H       = 0x11,
  // ZX
  CPU_FAMILY_ZX_CORE_F6    = 6,
  CPU_FAMILY_ZX_CORE_F7    = 7,
  // Intel
  CPU_FAMILY_INTEL_CORE    = 6,
  CPU_MODEL_NEHALEM        = 0x1e,
  CPU_MODEL_NEHALEM_EP     = 0x1a,
  CPU_MODEL_NEHALEM_EX     = 0x2e,
  CPU_MODEL_WESTMERE       = 0x25,
  CPU_MODEL_WESTMERE_EP    = 0x2c,
  CPU_MODEL_WESTMERE_EX    = 0x2f,
  CPU_MODEL_SANDYBRIDGE    = 0x2a,
  CPU_MODEL_SANDYBRIDGE_EP = 0x2d,
  CPU_MODEL_IVYBRIDGE_EP   = 0x3a,
  CPU_MODEL_HASWELL_E3     = 0x3c,
  CPU_MODEL_HASWELL_E7     = 0x3f,
  CPU_MODEL_BROADWELL      = 0x3d,
  CPU_MODEL_SKYLAKE        = 0x55
};
