iPXE
librm_test.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 /** @file
27  *
28  * Real mode transition self-tests
29  *
30  * This file allows for easy measurement of the time taken to perform
31  * real mode transitions, which may have a substantial overhead when
32  * running under a hypervisor.
33  *
34  */
35 
36 /* Forcibly enable assertions */
37 #undef NDEBUG
38 
39 #include <ipxe/test.h>
40 #include <ipxe/profile.h>
41 #include <realmode.h>
42 
43 /** Number of sample iterations for profiling */
44 #define PROFILE_COUNT 4096
45 
46 /** Protected-to-real mode transition profiler */
47 static struct profiler p2r_profiler __profiler = { .name = "p2r" };
48 
49 /** Real-to-protected mode transition profiler */
50 static struct profiler r2p_profiler __profiler = { .name = "r2p" };
51 
52 /** Real-mode call profiler */
53 static struct profiler real_call_profiler __profiler = { .name = "real_call" };
54 
55 /** Virtual call profiler */
56 static struct profiler virt_call_profiler __profiler = { .name = "virt_call" };
57 
58 /**
59  * Dummy function for profiling tests
60  */
61 static __asmcall __used void
63  /* Do nothing */
64 }
65 
66 /**
67  * Perform real mode transition self-tests
68  *
69  */
70 static void librm_test_exec ( void ) {
71  unsigned int i;
72  unsigned long timestamp;
73  uint32_t timestamp_lo;
74  uint32_t timestamp_hi;
77  uint32_t discard_d;
78 
79  /* Profile mode transitions. We want to profile each
80  * direction of the transition separately, so perform an RDTSC
81  * while in real mode and tweak the profilers' start/stop
82  * times appropriately.
83  */
84  for ( i = 0 ; i < PROFILE_COUNT ; i++ ) {
85  profile_start ( &p2r_profiler );
86  __asm__ __volatile__ ( REAL_CODE ( "rdtsc\n\t" )
87  : "=a" ( timestamp_lo ),
88  "=d" ( timestamp_hi )
89  : );
90  timestamp = timestamp_lo;
91  if ( sizeof ( timestamp ) > sizeof ( timestamp_lo ) )
92  timestamp |= ( ( ( uint64_t ) timestamp_hi ) << 32 );
93  profile_start_at ( &r2p_profiler, timestamp );
94  profile_stop ( &r2p_profiler );
95  profile_stop_at ( &p2r_profiler, timestamp );
96  }
97 
98  /* Profile complete real-mode call cycle */
99  for ( i = 0 ; i < PROFILE_COUNT ; i++ ) {
100  profile_start ( &real_call_profiler );
101  __asm__ __volatile__ ( REAL_CODE ( "" ) : );
102  profile_stop ( &real_call_profiler );
103  }
104 
105  /* Profile complete virtual call cycle */
106  for ( i = 0 ; i < PROFILE_COUNT ; i++ ) {
107  __asm__ __volatile__ ( REAL_CODE ( "rdtsc\n\t"
108  "movl %k0, %k2\n\t"
110  "rdtsc\n\t" )
111  : "=a" ( stopped ), "=d" ( discard_d ),
112  "=R" ( started ) : );
113  profile_start_at ( &virt_call_profiler, started );
114  profile_stop_at ( &virt_call_profiler, stopped );
115  }
116 }
117 
118 /** Real mode transition self-test */
119 struct self_test librm_test __self_test = {
120  .name = "librm",
121  .exec = librm_test_exec,
122 };
123 
124 REQUIRING_SYMBOL ( librm_test );
125 REQUIRE_OBJECT ( test );
#define VIRT_CALL(function)
Call C function from real-mode code.
Definition: librm.h:78
unsigned long long uint64_t
Definition: stdint.h:13
Self-test infrastructure.
const char * name
Test set name.
Definition: test.h:17
A data structure for storing profiling information.
Definition: profile.h:26
static void profile_stop(struct profiler *profiler)
Stop profiling.
Definition: profile.h:173
A self-test set.
Definition: test.h:15
A full register dump.
Definition: registers.h:174
static struct profiler p2r_profiler __profiler
Protected-to-real mode transition profiler.
Definition: librm_test.c:47
static void profile_stop_at(struct profiler *profiler, unsigned long stopped)
Stop profiling.
Definition: profile.h:145
static int started
"startup() has been called" flag
Definition: init.c:37
const char * name
Name.
Definition: profile.h:28
#define __asmcall
Declare a function with standard calling conventions.
Definition: compiler.h:15
struct self_test librm_test __self_test
Real mode transition self-test.
Definition: librm_test.c:119
#define __used
Declare a function as used.
Definition: compiler.h:605
static __asmcall __used void librm_test_call(struct i386_all_regs *ix86 __unused)
Dummy function for profiling tests.
Definition: librm_test.c:62
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define PROFILE_COUNT
Number of sample iterations for profiling.
Definition: librm_test.c:44
uint64_t timestamp
Timestamp.
Definition: ena.h:20
static void profile_start(struct profiler *profiler)
Start profiling.
Definition: profile.h:160
Profiling.
REQUIRING_SYMBOL(librm_test)
__asm__ __volatile__("call *%9" :"=a"(result), "=c"(discard_ecx), "=d"(discard_edx) :"d"(0), "a"(code), "b"(0), "c"(in_phys), "D"(0), "S"(out_phys), "m"(hypercall))
unsigned int uint32_t
Definition: stdint.h:12
REQUIRE_OBJECT(test)
static void profile_start_at(struct profiler *profiler, unsigned long started)
Start profiling.
Definition: profile.h:131
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
static void librm_test_exec(void)
Perform real mode transition self-tests.
Definition: librm_test.c:70
#define REAL_CODE(asm_code_str)
Definition: libkir.h:226
static int test
Definition: epic100.c:73
unsigned long stopped
Stop timestamp.
Definition: profile.h:32