Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //#include <stdio.h>
- //#include <stdlib.h>
- // http://charette.no-ip.com:81/programming/2009-12-30_Virtualization
- // $Id: 2009-12-30_Virtualization.c 13 2010-01-01 15:38:51Z stephane $
- //
- // Code to walk through the CPUs/cores and gcc inline assembly is loosely
- // based on this: http://nibbles.tuxfamily.org/?tag=gdt
- //
- // *** PLEASE NOTE ***
- //
- // 1) This code assumes it is being compiled for AMD64. If compiling for
- // i386 then you'll need to edit the "dt" structure. See documentation.
- //
- // 2) This "C" file has inline assembly written for gcc v4.4.1. If using
- // a different compiler, you'll neeed to modify the source.
- #define _GNU_SOURCE
- // needed for CPU_... macros
- #include <sched.h>
- #include <errno.h>
- #include <stdio.h>
- //*****************************************************************************************************************************
- #define __SLONGWORD_TYPE long int
- #define __ULONGWORD_TYPE unsigned long int
- /* X32 kernel interface is 64-bit. */
- #if defined __x86_64__ && defined __ILP32__
- # define __SYSCALL_SLONG_TYPE __SQUAD_TYPE
- # define __SYSCALL_ULONG_TYPE __UQUAD_TYPE
- #else
- # define __SYSCALL_SLONG_TYPE __SLONGWORD_TYPE
- # define __SYSCALL_ULONG_TYPE __ULONGWORD_TYPE
- #endif
- //cpu-set.h
- /* Size definition for CPU sets. */
- #define __CPU_SETSIZE 1024
- #define __NCPUBITS (8 * sizeof (__cpu_mask))
- #define __CPU_MASK_TYPE __SYSCALL_ULONG_TYPE
- /* Type for array elements in 'cpu_set_t'. */
- typedef __CPU_MASK_TYPE __cpu_mask;
- /* Data structure to describe CPU mask. */
- typedef struct
- {
- __cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS];
- } cpu_set_t;
- //******************************************************************************************************************************
- typedef struct
- {
- // Lots of *really bad* examples on the web where they use char[2]
- // to store the output of SIDT and SGDT. This is wrong!
- //
- // In 32-bit mode, the output is 6 bytes, where the first 2 is
- // the limit and the upper 4 bytes is the 32-bit base address.
- //
- // In 64-bit mode, the output is 10 bytes, where the first 2 is
- // the limit and the upper 8 bytes is the 64-bit base address.
- //
- // This is described on page 299 of AMD64 Architecture Programmer's
- // Manual Volume 3: General-Purpose and System Instructions:
- // http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/24594.pdf
- unsigned long limit : 16;
- unsigned long base : 64;
- } __attribute__((packed)) dt;
- unsigned long getIDT( void )
- {
- // Interrupt Descriptor Table Register
- //
- // This is the original "red pill" and "scoopy_doo" method of determining
- // whether or not we're running in a VM. The check would be against the
- // base address returned by SIDT. If the table was not at the usual
- // location, then it was assumed we were running in a VM. However, this
- // check can return false-positives with multi-core and multi-processor,
- // since the table is per-cpu/core.
- dt idt = {0, 0};
- asm volatile( "sidt %0" : "=m"(idt) );
- printf( "IDT: limit=%04d, base=%016lx\n", idt.limit, idt.base );
- return idt.base;
- }
- unsigned long getGDT( void )
- {
- // Global Descriptor Table Register
- //
- // This is the "no pill" variation on the original "red pill".
- dt gdt = {0, 0};
- asm volatile( "sgdt %0" : "=m"(gdt) );
- printf( "GDT: limit=%04d, base=%016lx\n", gdt.limit, gdt.base );
- return gdt.base;
- }
- unsigned short getLDT( void )
- {
- // Local Descriptor Table Register
- //
- // This one is slightly different than IDT and GDT. It returns to us just
- // the 16-bit segment selector. This is always a 16-bit value, regardless
- // of whether or not we're running in legacy i386 or in AMD64.
- unsigned long ldt = -1;
- // -1 will help us "see" this is a 16-bit value
- asm volatile( "sldt %0" : "=m"(ldt) );
- printf( "LDT: %04lx\n", ldt );
- return ldt;
- }
- unsigned short getSTR( void )
- {
- // Task Register Selector
- //
- // Apparently this can be used to determine if this is within or outside
- // the "Matrix, but I get the same value whether I'm running natively or
- // within VirtualBox.
- // http://www.s21sec.com/descargas/vmware-eng.pdf
- unsigned long str = -1;
- // -1 will help us "see" this is a 16-bit value
- asm volatile( "str %0" : "=m"(str) );
- printf( "STR: %04lx\n", str );
- return str;
- }
- int main(void)
- {
- int result = 0;
- int cpu = 0;
- int cpu2 = 0;
- cpu_set_t cs, cs2;
- if( sched_getaffinity( getpid(), sizeof( cs ), &cs ) != 0 )
- {
- printf( "sched_getaffinity() failed\n" );
- return -1;
- }
- // loop through all of the CPUs
- while( CPU_COUNT( &cs ) != 0 )
- {
- // if we have this CPU...
- if ( CPU_ISSET( cpu, &cs ) )
- {
- printf("\nCPU: %d\n", cpu );
- // set affinity -- schedule us to run on this specific CPU
- CPU_ZERO( &cs2 );
- CPU_SET( cpu, &cs2 );
- if( sched_setaffinity( getpid(), sizeof( cs2 ), &cs2 ) != 0)
- {
- printf( "setaffinity(%d) failed\n", cpu);
- result = -1;
- }
- // determine on which CPU we're running
- cpu2 = sched_getcpu ();
- if (cpu2 == -1 && errno == ENOSYS)
- {
- printf( "getcpu syscall not implemented" );
- return -1;
- }
- // ensure we're running on the CPU we think we should be using
- if (cpu2 != cpu)
- {
- printf( "getcpu result is %d; expected %d\n", cpu2, cpu );
- result = 1;
- }
- // display the results
- getIDT();
- getGDT();
- getLDT();
- getSTR();
- // clear affinity
- CPU_CLR(cpu, &cs);
- }
- // move on to the next CPU
- cpu ++;
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement