LCOV - code coverage report
Current view: top level - source/lib/sysdep/arch/x86_x64 - apic.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 0 57 0.0 %
Date: 2021-09-24 14:46:47 Functions: 0 11 0.0 %

          Line data    Source code
       1             : /* Copyright (C) 2020 Wildfire Games.
       2             :  *
       3             :  * Permission is hereby granted, free of charge, to any person obtaining
       4             :  * a copy of this software and associated documentation files (the
       5             :  * "Software"), to deal in the Software without restriction, including
       6             :  * without limitation the rights to use, copy, modify, merge, publish,
       7             :  * distribute, sublicense, and/or sell copies of the Software, and to
       8             :  * permit persons to whom the Software is furnished to do so, subject to
       9             :  * the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included
      12             :  * in all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      15             :  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      16             :  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      17             :  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
      18             :  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
      19             :  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      20             :  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      21             :  */
      22             : 
      23             : #include "precompiled.h"
      24             : #include "lib/sysdep/arch/x86_x64/apic.h"
      25             : 
      26             : #include "lib/bits.h"
      27             : #include "lib/module_init.h"
      28             : #include "lib/sysdep/cpu.h"   // ERR::CPU_FEATURE_MISSING
      29             : #include "lib/sysdep/os_cpu.h"
      30             : #include "lib/sysdep/arch/x86_x64/x86_x64.h"
      31             : 
      32             : #include <algorithm>
      33             : 
      34           0 : ApicId GetApicId()
      35             : {
      36           0 :     x86_x64::CpuidRegs regs = { 0 };
      37           0 :     regs.eax = 1;
      38             :     // note: CPUID function 1 is always supported, but only processors with
      39             :     // an xAPIC (e.g. P4/Athlon XP) will return a nonzero ID.
      40           0 :     bool ok = x86_x64::cpuid(&regs);
      41           0 :     ASSERT(ok); UNUSED2(ok);
      42           0 :     const u8 apicId = (u8)bits(regs.ebx, 24, 31);
      43           0 :     return apicId;
      44             : }
      45             : 
      46             : 
      47             : static size_t numIds;
      48             : static ApicId processorApicIds[os_cpu_MaxProcessors];
      49             : static ApicId sortedApicIds[os_cpu_MaxProcessors];
      50             : 
      51           0 : static Status GetAndValidateApicIds()
      52             : {
      53           0 :     numIds = os_cpu_NumProcessors();
      54           0 :     struct StoreEachProcessorsApicId
      55             :     {
      56           0 :         static void Callback(size_t processor, uintptr_t UNUSED(data))
      57             :         {
      58           0 :             processorApicIds[processor] = GetApicId();
      59           0 :         }
      60             :     };
      61             :     // (can fail due to restrictions on our process affinity or lack of
      62             :     // support for affinity masks in OS X.)
      63           0 :     RETURN_STATUS_IF_ERR(os_cpu_CallByEachCPU(StoreEachProcessorsApicId::Callback, 0));
      64             : 
      65           0 :     std::copy(processorApicIds, processorApicIds+numIds, sortedApicIds);
      66           0 :     std::sort(sortedApicIds, sortedApicIds+numIds);
      67           0 :     ApicId* const end = std::unique(sortedApicIds, sortedApicIds+numIds);
      68           0 :     const size_t numUnique = end-sortedApicIds;
      69             : 
      70             :     // all IDs are zero - system lacks an xAPIC.
      71             :     // (NB: we exclude single-processor systems in this test -
      72             :     // having one zero-valued ID is legitimate)
      73           0 :     if(numUnique == 1 && sortedApicIds[0] == 0 && numIds != 1)
      74             :     {
      75           0 :         debug_printf("APIC: all zero\n");
      76           0 :         return ERR::CPU_FEATURE_MISSING;    // NOWARN
      77             :     }
      78             : 
      79             :     // not all unique - probably running in a VM whose emulation is
      80             :     // imperfect or doesn't allow access to all processors.
      81           0 :     if(numUnique != numIds)
      82             :     {
      83           0 :         debug_printf("APIC: not unique\n");
      84           0 :         return ERR::FAIL;   // NOWARN
      85             :     }
      86             : 
      87             :     return INFO::OK;
      88             : }
      89             : 
      90           0 : static Status InitApicIds()
      91             : {
      92           0 :     const Status status = GetAndValidateApicIds();
      93           0 :     if(status < 0)   // failed
      94             :     {
      95             :         // generate fake but legitimate APIC IDs
      96           0 :         for(size_t processor = 0; processor < numIds; processor++)
      97           0 :             processorApicIds[processor] = sortedApicIds[processor] = (ApicId)processor;
      98             :     }
      99             : 
     100           0 :     return status;
     101             : }
     102             : 
     103             : static ModuleInitState apicInitState;
     104             : 
     105             : 
     106           0 : bool AreApicIdsReliable()
     107             : {
     108           0 :     ModuleInit(&apicInitState, InitApicIds);
     109           0 :     if(apicInitState < 0)
     110           0 :         return false;
     111             :     return true;
     112             : }
     113             : 
     114           0 : bool IsProcessorKnown(ApicId apicId)
     115             : {
     116           0 :     ModuleInit(&apicInitState, InitApicIds);
     117             : 
     118           0 :     const ApicId* pos = std::find(processorApicIds, processorApicIds+numIds, apicId);
     119           0 :     return pos != processorApicIds+numIds;
     120             : }
     121             : 
     122           0 : static size_t IndexFromApicId(const ApicId* apicIds, ApicId apicId)
     123             : {
     124           0 :     ModuleInit(&apicInitState, InitApicIds);
     125             : 
     126           0 :     const ApicId* pos = std::find(apicIds, apicIds+numIds, apicId);
     127           0 :     if(pos == apicIds+numIds)
     128             :     {
     129           0 :         DEBUG_WARN_ERR(ERR::LOGIC);
     130           0 :         return 0;
     131             :     }
     132             : 
     133           0 :     const size_t index = pos - apicIds;
     134           0 :     return index;
     135             : }
     136             : 
     137           0 : size_t ProcessorFromApicId(ApicId apicId)
     138             : {
     139           0 :     return IndexFromApicId(processorApicIds, apicId);
     140             : }
     141             : 
     142           0 : size_t ContiguousIdFromApicId(ApicId apicId)
     143             : {
     144           0 :     return IndexFromApicId(sortedApicIds, apicId);
     145             : }
     146             : 
     147             : 
     148             : static ApicId ApicIdFromIndex(const ApicId* apicIds, size_t index)
     149             : {
     150           0 :     ModuleInit(&apicInitState, InitApicIds);
     151           0 :     ASSERT(index < numIds);
     152           0 :     return apicIds[index];
     153             : }
     154             : 
     155           0 : ApicId ApicIdFromProcessor(size_t processor)
     156             : {
     157           0 :     return ApicIdFromIndex(processorApicIds, processor);
     158             : }
     159             : 
     160           0 : ApicId ApicIdFromContiguousId(size_t contiguousId)
     161             : {
     162           0 :     return ApicIdFromIndex(sortedApicIds, contiguousId);
     163             : }

Generated by: LCOV version 1.13