moel@1: /*
moel@1:   
moel@1:   Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@1: 
moel@1:   The contents of this file are subject to the Mozilla Public License Version
moel@1:   1.1 (the "License"); you may not use this file except in compliance with
moel@1:   the License. You may obtain a copy of the License at
moel@1:  
moel@1:   http://www.mozilla.org/MPL/
moel@1: 
moel@1:   Software distributed under the License is distributed on an "AS IS" basis,
moel@1:   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@1:   for the specific language governing rights and limitations under the License.
moel@1: 
moel@1:   The Original Code is the Open Hardware Monitor code.
moel@1: 
moel@1:   The Initial Developer of the Original Code is 
moel@1:   Michael Möller <m.moeller@gmx.ch>.
moel@1:   Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@1:   the Initial Developer. All Rights Reserved.
moel@1: 
moel@1:   Contributor(s):
moel@1: 
moel@1:   Alternatively, the contents of this file may be used under the terms of
moel@1:   either the GNU General Public License Version 2 or later (the "GPL"), or
moel@1:   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@1:   in which case the provisions of the GPL or the LGPL are applicable instead
moel@1:   of those above. If you wish to allow use of your version of this file only
moel@1:   under the terms of either the GPL or the LGPL, and not to allow others to
moel@1:   use your version of this file under the terms of the MPL, indicate your
moel@1:   decision by deleting the provisions above and replace them with the notice
moel@1:   and other provisions required by the GPL or the LGPL. If you do not delete
moel@1:   the provisions above, a recipient may use your version of this file under
moel@1:   the terms of any one of the MPL, the GPL or the LGPL.
moel@1:  
moel@1: */
moel@1: 
moel@1: using System;
moel@1: using System.Collections.Generic;
moel@1: using System.Text;
moel@1: 
moel@1: namespace OpenHardwareMonitor.Hardware.CPU {
moel@1: 
moel@1:   public class CPUGroup : IGroup { 
moel@1:     private List<IHardware> hardware = new List<IHardware>();
moel@1: 
moel@1:     private string cpuBrandString;
moel@1:     private string cpuVendor;
moel@1:     private uint[,] cpuidData;
moel@1:     private uint[,] cpuidExtData;
moel@1: 
moel@1:     private uint family;
moel@1:     private uint model;
moel@1:     private uint stepping;
moel@1: 
moel@1:     private static uint CPUID = 0;
moel@1:     private static uint CPUID_EXT = 0x80000000;
moel@1: 
moel@1:     public static void AppendRegister(StringBuilder b, uint value) {
moel@1:       b.Append((char)((value) & 0xff));
moel@1:       b.Append((char)((value >> 8) & 0xff));
moel@1:       b.Append((char)((value >> 16) & 0xff));
moel@1:       b.Append((char)((value >> 24) & 0xff));
moel@1:     }
moel@1: 
moel@1:     public CPUGroup() {
moel@1: 
moel@1:       if (!WinRing0.IsAvailable) 
moel@1:         return;
moel@1: 
moel@1:       if (WinRing0.IsCpuid()) {
moel@1:         uint maxCPUID = 0;
moel@1:         uint maxCPUID_EXT = 0;
moel@1:         uint eax, ebx, ecx, edx;
moel@1: 
moel@1:         
moel@1:         if (WinRing0.Cpuid(CPUID, out eax, out ebx, out ecx, out edx)) {
moel@1:           maxCPUID = eax;
moel@1:           StringBuilder vendorBuilder = new StringBuilder();
moel@1:           AppendRegister(vendorBuilder, ebx);
moel@1:           AppendRegister(vendorBuilder, edx);
moel@1:           AppendRegister(vendorBuilder, ecx);
moel@1:           cpuVendor = vendorBuilder.ToString();
moel@1: 
moel@1:           eax = ebx = ecx = edx = 0;
moel@1:           if (WinRing0.Cpuid(CPUID_EXT, out eax, out ebx, out ecx, out edx)) {
moel@1:             maxCPUID_EXT = eax - CPUID_EXT;
moel@1:           }
moel@1:         }
moel@1:         if (maxCPUID == 0 || maxCPUID_EXT == 0)
moel@1:           return;        
moel@1: 
moel@1:         cpuidData = new uint[maxCPUID + 1, 4];
moel@1:         for (uint i = 0; i < (maxCPUID + 1); i++)
moel@1:           WinRing0.Cpuid(CPUID + i, out cpuidData[i, 0], out cpuidData[i, 1],
moel@1:             out cpuidData[i, 2], out cpuidData[i, 3]);
moel@1: 
moel@1:         cpuidExtData = new uint[maxCPUID_EXT + 1, 4];
moel@1:         for (uint i = 0; i < (maxCPUID_EXT + 1); i++)
moel@1:           WinRing0.Cpuid(CPUID_EXT + i, out cpuidExtData[i, 0],
moel@1:             out cpuidExtData[i, 1], out cpuidExtData[i, 2],
moel@1:             out cpuidExtData[i, 3]);
moel@1: 
moel@1:         StringBuilder nameBuilder = new StringBuilder();
moel@1:         for (uint i = 2; i <= 4; i++) {
moel@1:           if (WinRing0.Cpuid(CPUID_EXT + i, out eax, out ebx, out ecx, out edx)) 
moel@1:           {
moel@1:             AppendRegister(nameBuilder, eax);
moel@1:             AppendRegister(nameBuilder, ebx);
moel@1:             AppendRegister(nameBuilder, ecx);
moel@1:             AppendRegister(nameBuilder, edx);
moel@1:           }
moel@1:         }
moel@36:         nameBuilder.Replace('\0', ' ');
moel@36:         cpuBrandString = nameBuilder.ToString().Trim();
moel@1:         nameBuilder.Replace("(R)", " ");
moel@1:         nameBuilder.Replace("(TM)", " ");
moel@1:         nameBuilder.Replace("(tm)", " ");
moel@1:         nameBuilder.Replace("CPU", "");
moel@1:         for (int i = 0; i < 10; i++) nameBuilder.Replace("  ", " ");
moel@1:         string name = nameBuilder.ToString();
moel@1:         if (name.Contains("@"))
moel@1:           name = name.Remove(name.LastIndexOf('@')); 
moel@1:         name = name.Trim();
moel@1: 
moel@1:         this.family = ((cpuidData[1, 0] & 0x0FF00000) >> 20) +
moel@1:           ((cpuidData[1, 0] & 0x0F00) >> 8);
moel@1:         this.model = ((cpuidData[1, 0] & 0x0F0000) >> 12) +
moel@1:           ((cpuidData[1, 0] & 0xF0) >> 4);
moel@1:         this.stepping = (cpuidData[1, 0] & 0x0F);
moel@1: 
moel@1:         switch (cpuVendor) {
moel@1:           case "GenuineIntel":
moel@44:             hardware.Add(new IntelCPU(name, family, model, stepping, 
moel@44:               cpuidData, cpuidExtData));
moel@1:             break;
moel@1:           case "AuthenticAMD":                       
moel@1:             // check if processor supports a digital thermal sensor            
moel@1:             if (maxCPUID_EXT >= 7 && (cpuidExtData[7, 3] & 1) != 0) {
moel@1:               switch (family) {
moel@14:                 case 0x0F:
moel@14:                   hardware.Add(new AMD0FCPU(name, family, model, stepping,
moel@14:                     cpuidData, cpuidExtData));
moel@14:                   break;
moel@1:                 case 0x10:
moel@1:                   hardware.Add(new AMD10CPU(name, family, model, stepping,
moel@1:                     cpuidData, cpuidExtData));
moel@1:                   break;
moel@1:                 default:
moel@1:                   break;
moel@1:               }
moel@1:             }
moel@1:             break;
moel@1:           default:
moel@1:             break;
moel@1:         }
moel@1:       }
moel@1:     }
moel@1: 
moel@1:     public IHardware[] Hardware {
moel@1:       get {
moel@1:         return hardware.ToArray();
moel@1:       }
moel@1:     }
moel@1: 
moel@1:     private void AppendCpuidData(StringBuilder r, uint[,] data, uint offset) {
moel@1:       for (int i = 0; i < data.GetLength(0); i++) {
moel@1:         r.Append(" ");
moel@1:         r.Append((i + offset).ToString("X8"));
moel@1:         for (int j = 0; j < 4; j++) {
moel@1:           r.Append("  ");
moel@1:           r.Append(data[i, j].ToString("X8"));
moel@1:         }
moel@1:         r.AppendLine();
moel@1:       }
moel@1:     }
moel@1: 
moel@1:     public string GetReport() {
moel@1: 
moel@1:       StringBuilder r = new StringBuilder();
moel@1: 
moel@1:       r.AppendLine("CPUID");
moel@1:       r.AppendLine();
moel@1:       r.AppendFormat("Processor Vendor: {0}{1}", cpuVendor, 
moel@1:         Environment.NewLine);
moel@1:       r.AppendFormat("Processor Brand: {0}{1}", cpuBrandString, 
moel@1:         Environment.NewLine);
moel@1:       r.AppendFormat("Family: 0x{0}{1}", family.ToString("X"),
moel@1:         Environment.NewLine);
moel@1:       r.AppendFormat("Model: 0x{0}{1}", model.ToString("X"),
moel@1:         Environment.NewLine);
moel@1:       r.AppendFormat("Stepping: 0x{0}{1}", stepping.ToString("X"),
moel@1:         Environment.NewLine);
moel@1:       r.AppendLine();
moel@1: 
moel@1:       r.AppendLine("CPUID Return Values");
moel@1:       r.AppendLine();
moel@1: 
moel@18:       if (cpuidData != null) {
moel@18:         r.AppendLine(" Function  EAX       EBX       ECX       EDX");
moel@18:         AppendCpuidData(r, cpuidData, CPUID);
moel@18:         AppendCpuidData(r, cpuidExtData, CPUID_EXT);
moel@18:         r.AppendLine();
moel@18:       }
moel@1: 
moel@1:       return r.ToString();
moel@1:     }
moel@1: 
moel@1:     public void Close() { }
moel@1:   }
moel@1: }