| 
				
			 | 
			
			
				
				@@ -20,6 +20,7 @@ 
			 | 
		
		
	
		
			
			| 
				20
			 | 
			
				20
			 | 
			
			
				
				 FILE_LICENCE ( GPL2_OR_LATER ); 
			 | 
		
		
	
		
			
			| 
				21
			 | 
			
				21
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				22
			 | 
			
				22
			 | 
			
			
				
				 #include <ipxe/dhcp.h> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				23
			 | 
			
			
				
				+#include <ipxe/profile.h> 
			 | 
		
		
	
		
			
			| 
				23
			 | 
			
				24
			 | 
			
			
				
				 #include <pxeparent.h> 
			 | 
		
		
	
		
			
			| 
				24
			 | 
			
				25
			 | 
			
			
				
				 #include <pxe_api.h> 
			 | 
		
		
	
		
			
			| 
				25
			 | 
			
				26
			 | 
			
			
				
				 #include <pxe_types.h> 
			 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			
				
				@@ -37,6 +38,59 @@ FILE_LICENCE ( GPL2_OR_LATER ); 
			 | 
		
		
	
		
			
			| 
				37
			 | 
			
				38
			 | 
			
			
				
				 			  "External PXE API error" ) 
			 | 
		
		
	
		
			
			| 
				38
			 | 
			
				39
			 | 
			
			
				
				 #define EPXECALL( status ) EPLATFORM ( EINFO_EPXECALL, status ) 
			 | 
		
		
	
		
			
			| 
				39
			 | 
			
				40
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				41
			 | 
			
			
				
				+/** A parent PXE API call profiler */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				42
			 | 
			
			
				
				+struct pxeparent_profiler { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				43
			 | 
			
			
				
				+	/** Total time spent performing REAL_CALL() */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				44
			 | 
			
			
				
				+	struct profiler total; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				45
			 | 
			
			
				
				+	/** Time spent transitioning to real mode */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				46
			 | 
			
			
				
				+	struct profiler p2r; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				47
			 | 
			
			
				
				+	/** Time spent in external code */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				48
			 | 
			
			
				
				+	struct profiler ext; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				49
			 | 
			
			
				
				+	/** Time spent transitioning back to protected mode */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				50
			 | 
			
			
				
				+	struct profiler r2p; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				51
			 | 
			
			
				
				+}; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				52
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				53
			 | 
			
			
				
				+/** PXENV_UNDI_TRANSMIT profiler */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				54
			 | 
			
			
				
				+static struct pxeparent_profiler pxeparent_tx_profiler __profiler = { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				55
			 | 
			
			
				
				+	{ .name = "pxeparent.tx" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				56
			 | 
			
			
				
				+	{ .name = "pxeparent.tx_p2r" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				57
			 | 
			
			
				
				+	{ .name = "pxeparent.tx_ext" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				58
			 | 
			
			
				
				+	{ .name = "pxeparent.tx_r2p" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				59
			 | 
			
			
				
				+}; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				60
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				61
			 | 
			
			
				
				+/** PXENV_UNDI_ISR profiler 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				62
			 | 
			
			
				
				+ * 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				63
			 | 
			
			
				
				+ * Note that this profiler will not see calls to 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				64
			 | 
			
			
				
				+ * PXENV_UNDI_ISR_IN_START, which are handled by the UNDI ISR and do 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				65
			 | 
			
			
				
				+ * not go via pxeparent_call(). 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				66
			 | 
			
			
				
				+ */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				67
			 | 
			
			
				
				+static struct pxeparent_profiler pxeparent_isr_profiler __profiler = { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				68
			 | 
			
			
				
				+	{ .name = "pxeparent.isr" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				69
			 | 
			
			
				
				+	{ .name = "pxeparent.isr_p2r" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				70
			 | 
			
			
				
				+	{ .name = "pxeparent.isr_ext" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				71
			 | 
			
			
				
				+	{ .name = "pxeparent.isr_r2p" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				72
			 | 
			
			
				
				+}; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				73
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				74
			 | 
			
			
				
				+/** PXE unknown API call profiler 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				75
			 | 
			
			
				
				+ * 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				76
			 | 
			
			
				
				+ * This profiler can be used to measure the overhead of a dummy PXE 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				77
			 | 
			
			
				
				+ * API call. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				78
			 | 
			
			
				
				+ */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				79
			 | 
			
			
				
				+static struct pxeparent_profiler pxeparent_unknown_profiler __profiler = { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				80
			 | 
			
			
				
				+	{ .name = "pxeparent.unknown" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				81
			 | 
			
			
				
				+	{ .name = "pxeparent.unknown_p2r" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				82
			 | 
			
			
				
				+	{ .name = "pxeparent.unknown_ext" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				83
			 | 
			
			
				
				+	{ .name = "pxeparent.unknown_r2p" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				84
			 | 
			
			
				
				+}; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				85
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				86
			 | 
			
			
				
				+/** Miscellaneous PXE API call profiler */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				87
			 | 
			
			
				
				+static struct pxeparent_profiler pxeparent_misc_profiler __profiler = { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				88
			 | 
			
			
				
				+	{ .name = "pxeparent.misc" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				89
			 | 
			
			
				
				+	{ .name = "pxeparent.misc_p2r" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				90
			 | 
			
			
				
				+	{ .name = "pxeparent.misc_ext" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				91
			 | 
			
			
				
				+	{ .name = "pxeparent.misc_r2p" }, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				92
			 | 
			
			
				
				+}; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				93
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				40
			 | 
			
				94
			 | 
			
			
				
				 /** 
			 | 
		
		
	
		
			
			| 
				41
			 | 
			
				95
			 | 
			
			
				
				  * Name PXE API call 
			 | 
		
		
	
		
			
			| 
				42
			 | 
			
				96
			 | 
			
			
				
				  * 
			 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			
				
				@@ -103,11 +157,32 @@ pxeparent_function_name ( unsigned int function ) { 
			 | 
		
		
	
		
			
			| 
				103
			 | 
			
				157
			 | 
			
			
				
				 	} 
			 | 
		
		
	
		
			
			| 
				104
			 | 
			
				158
			 | 
			
			
				
				 } 
			 | 
		
		
	
		
			
			| 
				105
			 | 
			
				159
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				160
			 | 
			
			
				
				+/** 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				161
			 | 
			
			
				
				+ * Determine applicable profiler pair (for debugging) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				162
			 | 
			
			
				
				+ * 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				163
			 | 
			
			
				
				+ * @v function		API call number 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				164
			 | 
			
			
				
				+ * @ret profiler	Profiler 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				165
			 | 
			
			
				
				+ */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				166
			 | 
			
			
				
				+static struct pxeparent_profiler * pxeparent_profiler ( unsigned int function ){ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				167
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				168
			 | 
			
			
				
				+	/* Determine applicable profiler */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				169
			 | 
			
			
				
				+	switch ( function ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				170
			 | 
			
			
				
				+	case PXENV_UNDI_TRANSMIT: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				171
			 | 
			
			
				
				+		return &pxeparent_tx_profiler; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				172
			 | 
			
			
				
				+	case PXENV_UNDI_ISR: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				173
			 | 
			
			
				
				+		return &pxeparent_isr_profiler; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				174
			 | 
			
			
				
				+	case PXENV_UNKNOWN: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				175
			 | 
			
			
				
				+		return &pxeparent_unknown_profiler; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				176
			 | 
			
			
				
				+	default: 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				177
			 | 
			
			
				
				+		return &pxeparent_misc_profiler; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				178
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				179
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				180
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				106
			 | 
			
				181
			 | 
			
			
				
				 /** 
			 | 
		
		
	
		
			
			| 
				107
			 | 
			
				182
			 | 
			
			
				
				  * PXE parent parameter block 
			 | 
		
		
	
		
			
			| 
				108
			 | 
			
				183
			 | 
			
			
				
				  * 
			 | 
		
		
	
		
			
			| 
				109
			 | 
			
				
			 | 
			
			
				
				- * Used as the paramter block for all parent PXE API calls.  Resides in base 
			 | 
		
		
	
		
			
			| 
				110
			 | 
			
				
			 | 
			
			
				
				- * memory. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				184
			 | 
			
			
				
				+ * Used as the parameter block for all parent PXE API calls.  Resides 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				185
			 | 
			
			
				
				+ * in base memory. 
			 | 
		
		
	
		
			
			| 
				111
			 | 
			
				186
			 | 
			
			
				
				  */ 
			 | 
		
		
	
		
			
			| 
				112
			 | 
			
				187
			 | 
			
			
				
				 static union u_PXENV_ANY __bss16 ( pxeparent_params ); 
			 | 
		
		
	
		
			
			| 
				113
			 | 
			
				188
			 | 
			
			
				
				 #define pxeparent_params __use_data16 ( pxeparent_params ) 
			 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			
				
				@@ -131,8 +206,11 @@ SEGOFF16_t __bss16 ( pxeparent_entry_point ); 
			 | 
		
		
	
		
			
			| 
				131
			 | 
			
				206
			 | 
			
			
				
				  */ 
			 | 
		
		
	
		
			
			| 
				132
			 | 
			
				207
			 | 
			
			
				
				 int pxeparent_call ( SEGOFF16_t entry, unsigned int function, 
			 | 
		
		
	
		
			
			| 
				133
			 | 
			
				208
			 | 
			
			
				
				 		     void *params, size_t params_len ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				209
			 | 
			
			
				
				+	struct pxeparent_profiler *profiler = pxeparent_profiler ( function ); 
			 | 
		
		
	
		
			
			| 
				134
			 | 
			
				210
			 | 
			
			
				
				 	PXENV_EXIT_t exit; 
			 | 
		
		
	
		
			
			| 
				135
			 | 
			
				
			 | 
			
			
				
				-	int discard_b, discard_D; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				211
			 | 
			
			
				
				+	unsigned long started; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				212
			 | 
			
			
				
				+	unsigned long stopped; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				213
			 | 
			
			
				
				+	int discard_D; 
			 | 
		
		
	
		
			
			| 
				136
			 | 
			
				214
			 | 
			
			
				
				 	int rc; 
			 | 
		
		
	
		
			
			| 
				137
			 | 
			
				215
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				138
			 | 
			
				216
			 | 
			
			
				
				 	/* Copy parameter block and entry point */ 
			 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			
				
				@@ -143,18 +221,31 @@ int pxeparent_call ( SEGOFF16_t entry, unsigned int function, 
			 | 
		
		
	
		
			
			| 
				143
			 | 
			
				221
			 | 
			
			
				
				 	/* Call real-mode entry point.  This calling convention will 
			 | 
		
		
	
		
			
			| 
				144
			 | 
			
				222
			 | 
			
			
				
				 	 * work with both the !PXE and the PXENV+ entry points. 
			 | 
		
		
	
		
			
			| 
				145
			 | 
			
				223
			 | 
			
			
				
				 	 */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				224
			 | 
			
			
				
				+	profile_start ( &profiler->total ); 
			 | 
		
		
	
		
			
			| 
				146
			 | 
			
				225
			 | 
			
			
				
				 	__asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				226
			 | 
			
			
				
				+					   "rdtsc\n\t" 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				227
			 | 
			
			
				
				+					   "pushl %%eax\n\t" 
			 | 
		
		
	
		
			
			| 
				147
			 | 
			
				228
			 | 
			
			
				
				 					   "pushw %%es\n\t" 
			 | 
		
		
	
		
			
			| 
				148
			 | 
			
				229
			 | 
			
			
				
				 					   "pushw %%di\n\t" 
			 | 
		
		
	
		
			
			| 
				149
			 | 
			
				230
			 | 
			
			
				
				 					   "pushw %%bx\n\t" 
			 | 
		
		
	
		
			
			| 
				150
			 | 
			
				231
			 | 
			
			
				
				 					   "lcall *pxeparent_entry_point\n\t" 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				232
			 | 
			
			
				
				+					   "movw %%ax, %%bx\n\t" 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				233
			 | 
			
			
				
				+					   "rdtsc\n\t" 
			 | 
		
		
	
		
			
			| 
				151
			 | 
			
				234
			 | 
			
			
				
				 					   "addw $6, %%sp\n\t" 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				235
			 | 
			
			
				
				+					   "popl %%edx\n\t" 
			 | 
		
		
	
		
			
			| 
				152
			 | 
			
				236
			 | 
			
			
				
				 					   "popl %%ebp\n\t" /* gcc bug */ ) 
			 | 
		
		
	
		
			
			| 
				153
			 | 
			
				
			 | 
			
			
				
				-			       : "=a" ( exit ), "=b" ( discard_b ), 
			 | 
		
		
	
		
			
			| 
				154
			 | 
			
				
			 | 
			
			
				
				-			         "=D" ( discard_D ) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				237
			 | 
			
			
				
				+			       : "=a" ( stopped ), "=d" ( started ), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				238
			 | 
			
			
				
				+				 "=b" ( exit ), "=D" ( discard_D ) 
			 | 
		
		
	
		
			
			| 
				155
			 | 
			
				239
			 | 
			
			
				
				 			       : "b" ( function ), 
			 | 
		
		
	
		
			
			| 
				156
			 | 
			
				240
			 | 
			
			
				
				 			         "D" ( __from_data16 ( &pxeparent_params ) ) 
			 | 
		
		
	
		
			
			| 
				157
			 | 
			
				
			 | 
			
			
				
				-			       : "ecx", "edx", "esi" ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				241
			 | 
			
			
				
				+			       : "ecx", "esi" ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				242
			 | 
			
			
				
				+	profile_stop ( &profiler->total ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				243
			 | 
			
			
				
				+	profile_start_at ( &profiler->p2r, profiler->total.started ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				244
			 | 
			
			
				
				+	profile_stop_at ( &profiler->p2r, started ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				245
			 | 
			
			
				
				+	profile_start_at ( &profiler->ext, started ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				246
			 | 
			
			
				
				+	profile_stop_at ( &profiler->ext, stopped ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				247
			 | 
			
			
				
				+	profile_start_at ( &profiler->r2p, stopped ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				248
			 | 
			
			
				
				+	profile_stop_at ( &profiler->r2p, profiler->total.stopped ); 
			 | 
		
		
	
		
			
			| 
				158
			 | 
			
				249
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				159
			 | 
			
				250
			 | 
			
			
				
				 	/* Determine return status code based on PXENV_EXIT and 
			 | 
		
		
	
		
			
			| 
				160
			 | 
			
				251
			 | 
			
			
				
				 	 * PXENV_STATUS 
			 |