|
@@ -1,391 +0,0 @@
|
1
|
|
-/* PXE callback mechanisms. This file contains only the portions
|
2
|
|
- * specific to i386: i.e. the low-level mechanisms for calling in from
|
3
|
|
- * an NBP to the PXE stack and for starting an NBP from the PXE stack.
|
4
|
|
- */
|
5
|
|
-
|
6
|
|
-#warning "pxe_callbacks.c is temporarily broken"
|
7
|
|
-
|
8
|
|
-void xstartpxe ( void ) {
|
9
|
|
-}
|
10
|
|
-
|
11
|
|
-void install_pxe_stack ( void ) {
|
12
|
|
-}
|
13
|
|
-
|
14
|
|
-void remove_pxe_stack ( void ) {
|
15
|
|
-}
|
16
|
|
-
|
17
|
|
-void hook_pxe_stack ( void ) {
|
18
|
|
-}
|
19
|
|
-
|
20
|
|
-void unhook_pxe_stack ( void ) {
|
21
|
|
-}
|
22
|
|
-
|
23
|
|
-void pxe_in_call ( void ) {
|
24
|
|
-}
|
25
|
|
-
|
26
|
|
-void use_undi_ds_for_rm_stack ( void ) {
|
27
|
|
-}
|
28
|
|
-
|
29
|
|
-#if 0
|
30
|
|
-
|
31
|
|
-#ifdef PXE_EXPORT
|
32
|
|
-
|
33
|
|
-#include "etherboot.h"
|
34
|
|
-#include "callbacks.h"
|
35
|
|
-#include "realmode.h"
|
36
|
|
-#include "pxe.h"
|
37
|
|
-#include "pxe_callbacks.h"
|
38
|
|
-#include "pxe_export.h"
|
39
|
|
-#include "hidemem.h"
|
40
|
|
-#include <stdarg.h>
|
41
|
|
-
|
42
|
|
-#define INSTALLED(x) ( (typeof(&x)) ( (void*)(&x) \
|
43
|
|
- - &pxe_callback_interface \
|
44
|
|
- + (void*)&pxe_stack->arch_data ) )
|
45
|
|
-#define pxe_intercept_int1a INSTALLED(_pxe_intercept_int1a)
|
46
|
|
-#define pxe_intercepted_int1a INSTALLED(_pxe_intercepted_int1a)
|
47
|
|
-#define pxe_pxenv_location INSTALLED(_pxe_pxenv_location)
|
48
|
|
-#define INT1A_VECTOR ( (segoff_t*) ( phys_to_virt( 4 * 0x1a ) ) )
|
49
|
|
-
|
50
|
|
-/* The overall size of the PXE stack is ( sizeof(pxe_stack_t) +
|
51
|
|
- * pxe_callback_interface_size + rm_callback_interface_size ).
|
52
|
|
- * Unfortunately, this isn't a compile-time constant, since
|
53
|
|
- * {pxe,rm}_callback_interface_size depend on the length of the
|
54
|
|
- * assembly code in these interfaces.
|
55
|
|
- *
|
56
|
|
- * We used to have a function pxe_stack_size() which returned this
|
57
|
|
- * value. However, it actually needs to be a link-time constant, so
|
58
|
|
- * that it can appear in the UNDIROMID structure in romprefix.S. We
|
59
|
|
- * therefore export the three component sizes as absolute linker
|
60
|
|
- * symbols, get the linker to add them together and generate a new
|
61
|
|
- * absolute symbol _pxe_stack_size. We then import this value into a
|
62
|
|
- * C variable pxe_stack_size, for access from C code.
|
63
|
|
- */
|
64
|
|
-
|
65
|
|
-/* gcc won't let us use extended asm outside a function (compiler
|
66
|
|
- * bug), ao we have to put these asm statements inside a dummy
|
67
|
|
- * function.
|
68
|
|
- */
|
69
|
|
-static void work_around_gcc_bug ( void ) __attribute__ ((used));
|
70
|
|
-static void work_around_gcc_bug ( void ) {
|
71
|
|
- /* Export sizeof(pxe_stack_t) as absolute linker symbol */
|
72
|
|
- __asm__ ( ".globl _pxe_stack_t_size" );
|
73
|
|
- __asm__ ( ".equ _pxe_stack_t_size, %c0"
|
74
|
|
- : : "i" (sizeof(pxe_stack_t)) );
|
75
|
|
-}
|
76
|
|
-/* Import _pxe_stack_size absolute linker symbol into C variable */
|
77
|
|
-extern int pxe_stack_size;
|
78
|
|
-__asm__ ( "pxe_stack_size: .long _pxe_stack_size" );
|
79
|
|
-
|
80
|
|
-/* Utility routine: byte checksum
|
81
|
|
- */
|
82
|
|
-uint8_t byte_checksum ( void *address, size_t size ) {
|
83
|
|
- unsigned int i, sum = 0;
|
84
|
|
-
|
85
|
|
- for ( i = 0; i < size; i++ ) {
|
86
|
|
- sum += ((uint8_t*)address)[i];
|
87
|
|
- }
|
88
|
|
- return (uint8_t)sum;
|
89
|
|
-}
|
90
|
|
-
|
91
|
|
-/* install_pxe_stack(): install PXE stack.
|
92
|
|
- *
|
93
|
|
- * Use base = NULL for auto-allocation of base memory
|
94
|
|
- *
|
95
|
|
- * IMPORTANT: no further allocation of base memory should take place
|
96
|
|
- * before the PXE stack is removed. This is to work around a small
|
97
|
|
- * but important deficiency in the PXE specification.
|
98
|
|
- */
|
99
|
|
-pxe_stack_t * install_pxe_stack ( void *base ) {
|
100
|
|
- pxe_t *pxe;
|
101
|
|
- pxenv_t *pxenv;
|
102
|
|
- void *pxe_callback_code;
|
103
|
|
- void (*pxe_in_call_far)(void);
|
104
|
|
- void (*pxenv_in_call_far)(void);
|
105
|
|
- void *rm_callback_code;
|
106
|
|
- void *e820mangler_code;
|
107
|
|
- void *end;
|
108
|
|
-
|
109
|
|
- /* If already installed, just return */
|
110
|
|
- if ( pxe_stack != NULL ) return pxe_stack;
|
111
|
|
-
|
112
|
|
- /* Allocate base memory if requested to do so
|
113
|
|
- */
|
114
|
|
- if ( base == NULL ) {
|
115
|
|
- base = allot_base_memory ( pxe_stack_size );
|
116
|
|
- if ( base == NULL ) return NULL;
|
117
|
|
- }
|
118
|
|
-
|
119
|
|
- /* Round address up to 16-byte physical alignment */
|
120
|
|
- pxe_stack = (pxe_stack_t *)
|
121
|
|
- ( phys_to_virt ( ( virt_to_phys(base) + 0xf ) & ~0xf ) );
|
122
|
|
- /* Zero out allocated stack */
|
123
|
|
- memset ( pxe_stack, 0, sizeof(*pxe_stack) );
|
124
|
|
-
|
125
|
|
- /* Calculate addresses for portions of the stack */
|
126
|
|
- pxe = &(pxe_stack->pxe);
|
127
|
|
- pxenv = &(pxe_stack->pxenv);
|
128
|
|
- pxe_callback_code = &(pxe_stack->arch_data);
|
129
|
|
- pxe_in_call_far = _pxe_in_call_far +
|
130
|
|
- ( pxe_callback_code - &pxe_callback_interface );
|
131
|
|
- pxenv_in_call_far = _pxenv_in_call_far +
|
132
|
|
- ( pxe_callback_code - &pxe_callback_interface );
|
133
|
|
- rm_callback_code = pxe_callback_code + pxe_callback_interface_size;
|
134
|
|
-
|
135
|
|
- e820mangler_code = (void*)(((int)rm_callback_code +
|
136
|
|
- rm_callback_interface_size + 0xf ) & ~0xf);
|
137
|
|
- end = e820mangler_code + e820mangler_size;
|
138
|
|
-
|
139
|
|
- /* Initialise !PXE data structures */
|
140
|
|
- memcpy ( pxe->Signature, "!PXE", 4 );
|
141
|
|
- pxe->StructLength = sizeof(*pxe);
|
142
|
|
- pxe->StructRev = 0;
|
143
|
|
- pxe->reserved_1 = 0;
|
144
|
|
- /* We don't yet have an UNDI ROM ID structure */
|
145
|
|
- pxe->UNDIROMID.segment = 0;
|
146
|
|
- pxe->UNDIROMID.offset = 0;
|
147
|
|
- /* or a BC ROM ID structure */
|
148
|
|
- pxe->BaseROMID.segment = 0;
|
149
|
|
- pxe->BaseROMID.offset = 0;
|
150
|
|
- pxe->EntryPointSP.segment = SEGMENT(pxe_stack);
|
151
|
|
- pxe->EntryPointSP.offset = (void*)pxe_in_call_far - (void*)pxe_stack;
|
152
|
|
- /* No %esp-compatible entry point yet */
|
153
|
|
- pxe->EntryPointESP.segment = 0;
|
154
|
|
- pxe->EntryPointESP.offset = 0;
|
155
|
|
- pxe->StatusCallout.segment = -1;
|
156
|
|
- pxe->StatusCallout.offset = -1;
|
157
|
|
- pxe->reserved_2 = 0;
|
158
|
|
- pxe->SegDescCn = 7;
|
159
|
|
- pxe->FirstSelector = 0;
|
160
|
|
- /* PXE specification doesn't say anything about when the stack
|
161
|
|
- * space should get freed. We work around this by claiming it
|
162
|
|
- * as our data segment as well.
|
163
|
|
- */
|
164
|
|
- pxe->Stack.Seg_Addr = pxe->UNDIData.Seg_Addr = real_mode_stack >> 4;
|
165
|
|
- pxe->Stack.Phy_Addr = pxe->UNDIData.Phy_Addr = real_mode_stack;
|
166
|
|
- pxe->Stack.Seg_Size = pxe->UNDIData.Seg_Size = real_mode_stack_size;
|
167
|
|
- /* Code segment has to be the one containing the data structures... */
|
168
|
|
- pxe->UNDICode.Seg_Addr = SEGMENT(pxe_stack);
|
169
|
|
- pxe->UNDICode.Phy_Addr = virt_to_phys(pxe_stack);
|
170
|
|
- pxe->UNDICode.Seg_Size = end - (void*)pxe_stack;
|
171
|
|
- /* No base code loaded */
|
172
|
|
- pxe->BC_Data.Seg_Addr = 0;
|
173
|
|
- pxe->BC_Data.Phy_Addr = 0;
|
174
|
|
- pxe->BC_Data.Seg_Size = 0;
|
175
|
|
- pxe->BC_Code.Seg_Addr = 0;
|
176
|
|
- pxe->BC_Code.Phy_Addr = 0;
|
177
|
|
- pxe->BC_Code.Seg_Size = 0;
|
178
|
|
- pxe->BC_CodeWrite.Seg_Addr = 0;
|
179
|
|
- pxe->BC_CodeWrite.Phy_Addr = 0;
|
180
|
|
- pxe->BC_CodeWrite.Seg_Size = 0;
|
181
|
|
- pxe->StructCksum -= byte_checksum ( pxe, sizeof(*pxe) );
|
182
|
|
-
|
183
|
|
- /* Initialise PXENV+ data structures */
|
184
|
|
- memcpy ( pxenv->Signature, "PXENV+", 6 );
|
185
|
|
- pxenv->Version = 0x201;
|
186
|
|
- pxenv->Length = sizeof(*pxenv);
|
187
|
|
- pxenv->RMEntry.segment = SEGMENT(pxe_stack);
|
188
|
|
- pxenv->RMEntry.offset = (void*)pxenv_in_call_far - (void*)pxe_stack;
|
189
|
|
- pxenv->PMOffset = 0; /* "Do not use" says the PXE spec */
|
190
|
|
- pxenv->PMSelector = 0; /* "Do not use" says the PXE spec */
|
191
|
|
- pxenv->StackSeg = pxenv->UNDIDataSeg = real_mode_stack >> 4;
|
192
|
|
- pxenv->StackSize = pxenv->UNDIDataSize = real_mode_stack_size;
|
193
|
|
- pxenv->BC_CodeSeg = 0;
|
194
|
|
- pxenv->BC_CodeSize = 0;
|
195
|
|
- pxenv->BC_DataSeg = 0;
|
196
|
|
- pxenv->BC_DataSize = 0;
|
197
|
|
- /* UNDIData{Seg,Size} set above */
|
198
|
|
- pxenv->UNDICodeSeg = SEGMENT(pxe_stack);
|
199
|
|
- pxenv->UNDICodeSize = end - (void*)pxe_stack;
|
200
|
|
- pxenv->PXEPtr.segment = SEGMENT(pxe);
|
201
|
|
- pxenv->PXEPtr.offset = OFFSET(pxe);
|
202
|
|
- pxenv->Checksum -= byte_checksum ( pxenv, sizeof(*pxenv) );
|
203
|
|
-
|
204
|
|
- /* Mark stack as inactive */
|
205
|
|
- pxe_stack->state = CAN_UNLOAD;
|
206
|
|
-
|
207
|
|
- /* Install PXE and RM callback code and E820 mangler */
|
208
|
|
- memcpy ( pxe_callback_code, &pxe_callback_interface,
|
209
|
|
- pxe_callback_interface_size );
|
210
|
|
- install_rm_callback_interface ( rm_callback_code, 0 );
|
211
|
|
- install_e820mangler ( e820mangler_code );
|
212
|
|
-
|
213
|
|
- return pxe_stack;
|
214
|
|
-}
|
215
|
|
-
|
216
|
|
-/* Use the UNDI data segment as our real-mode stack. This is for when
|
217
|
|
- * we have been loaded via the UNDI loader
|
218
|
|
- */
|
219
|
|
-void use_undi_ds_for_rm_stack ( uint16_t ds ) {
|
220
|
|
- forget_real_mode_stack();
|
221
|
|
- real_mode_stack = virt_to_phys ( VIRTUAL ( ds, 0 ) );
|
222
|
|
- lock_real_mode_stack = 1;
|
223
|
|
-}
|
224
|
|
-
|
225
|
|
-/* Activate PXE stack (i.e. hook interrupt vectors). The PXE stack
|
226
|
|
- * *can* be used before it is activated, but it really shoudln't.
|
227
|
|
- */
|
228
|
|
-int hook_pxe_stack ( void ) {
|
229
|
|
- if ( pxe_stack == NULL ) return 0;
|
230
|
|
- if ( pxe_stack->state >= MIDWAY ) return 1;
|
231
|
|
-
|
232
|
|
- /* Hook INT15 handler */
|
233
|
|
- hide_etherboot();
|
234
|
|
-
|
235
|
|
- /* Hook INT1A handler */
|
236
|
|
- *pxe_intercepted_int1a = *INT1A_VECTOR;
|
237
|
|
- pxe_pxenv_location->segment = SEGMENT(pxe_stack);
|
238
|
|
- pxe_pxenv_location->offset = (void*)&pxe_stack->pxenv
|
239
|
|
- - (void*)pxe_stack;
|
240
|
|
- INT1A_VECTOR->segment = SEGMENT(&pxe_stack->arch_data);
|
241
|
|
- INT1A_VECTOR->offset = (void*)pxe_intercept_int1a
|
242
|
|
- - (void*)&pxe_stack->arch_data;
|
243
|
|
-
|
244
|
|
- /* Mark stack as active */
|
245
|
|
- pxe_stack->state = MIDWAY;
|
246
|
|
- return 1;
|
247
|
|
-}
|
248
|
|
-
|
249
|
|
-/* Deactivate the PXE stack (i.e. unhook interrupt vectors).
|
250
|
|
- */
|
251
|
|
-int unhook_pxe_stack ( void ) {
|
252
|
|
- if ( pxe_stack == NULL ) return 0;
|
253
|
|
- if ( pxe_stack->state <= CAN_UNLOAD ) return 1;
|
254
|
|
-
|
255
|
|
- /* Restore original INT15 and INT1A handlers */
|
256
|
|
- *INT1A_VECTOR = *pxe_intercepted_int1a;
|
257
|
|
- if ( !unhide_etherboot() ) {
|
258
|
|
- /* Cannot unhook INT15. We're up the creek without
|
259
|
|
- * even a suitable log out of which to fashion a
|
260
|
|
- * paddle. There are some very badly behaved NBPs
|
261
|
|
- * that will ignore plaintive pleas such as
|
262
|
|
- * PXENV_KEEP_UNDI and just zero out our code anyway.
|
263
|
|
- * This means they end up vapourising an active INT15
|
264
|
|
- * handler, which is generally not a good thing to do.
|
265
|
|
- */
|
266
|
|
- return 0;
|
267
|
|
- }
|
268
|
|
-
|
269
|
|
- /* Mark stack as inactive */
|
270
|
|
- pxe_stack->state = CAN_UNLOAD;
|
271
|
|
- return 1;
|
272
|
|
-}
|
273
|
|
-
|
274
|
|
-/* remove_pxe_stack(): remove PXE stack installed by install_pxe_stack()
|
275
|
|
- */
|
276
|
|
-void remove_pxe_stack ( void ) {
|
277
|
|
- /* Ensure stack is deactivated, then free up the memory */
|
278
|
|
- if ( ensure_pxe_state ( CAN_UNLOAD ) ) {
|
279
|
|
- forget_base_memory ( pxe_stack, pxe_stack_size );
|
280
|
|
- pxe_stack = NULL;
|
281
|
|
- } else {
|
282
|
|
- printf ( "Cannot remove PXE stack!\n" );
|
283
|
|
- }
|
284
|
|
-}
|
285
|
|
-
|
286
|
|
-/* xstartpxe(): start up a PXE image
|
287
|
|
- */
|
288
|
|
-int xstartpxe ( void ) {
|
289
|
|
- int nbp_exit;
|
290
|
|
- struct {
|
291
|
|
- reg16_t bx;
|
292
|
|
- reg16_t es;
|
293
|
|
- segoff_t pxe;
|
294
|
|
- } PACKED in_stack;
|
295
|
|
-
|
296
|
|
- /* Set up registers and stack parameters to pass to PXE NBP */
|
297
|
|
- in_stack.es.word = SEGMENT(&(pxe_stack->pxenv));
|
298
|
|
- in_stack.bx.word = OFFSET(&(pxe_stack->pxenv));
|
299
|
|
- in_stack.pxe.segment = SEGMENT(&(pxe_stack->pxe));
|
300
|
|
- in_stack.pxe.offset = OFFSET(&(pxe_stack->pxe));
|
301
|
|
-
|
302
|
|
- /* Real-mode trampoline fragment used to jump to PXE NBP
|
303
|
|
- */
|
304
|
|
- RM_FRAGMENT(jump_to_pxe_nbp,
|
305
|
|
- "popw %bx\n\t"
|
306
|
|
- "popw %es\n\t"
|
307
|
|
- "lcall $" RM_STR(PXE_LOAD_SEGMENT) ", $" RM_STR(PXE_LOAD_OFFSET) "\n\t"
|
308
|
|
- );
|
309
|
|
-
|
310
|
|
- /* Call to PXE image */
|
311
|
|
- gateA20_unset();
|
312
|
|
- nbp_exit = real_call ( jump_to_pxe_nbp, &in_stack, NULL );
|
313
|
|
- gateA20_set();
|
314
|
|
-
|
315
|
|
- return nbp_exit;
|
316
|
|
-}
|
317
|
|
-
|
318
|
|
-int pxe_in_call ( in_call_data_t *in_call_data, va_list params ) {
|
319
|
|
- /* i386 calling conventions; the only two defined by Intel's
|
320
|
|
- * PXE spec.
|
321
|
|
- *
|
322
|
|
- * Assembly code must pass a long containing the PXE version
|
323
|
|
- * code (i.e. 0x201 for !PXE, 0x200 for PXENV+) as the first
|
324
|
|
- * parameter after the in_call opcode. This is used to decide
|
325
|
|
- * whether to take parameters from the stack (!PXE) or from
|
326
|
|
- * registers (PXENV+).
|
327
|
|
- */
|
328
|
|
- uint32_t api_version = va_arg ( params, typeof(api_version) );
|
329
|
|
- uint16_t opcode;
|
330
|
|
- segoff_t segoff;
|
331
|
|
- t_PXENV_ANY *structure;
|
332
|
|
-
|
333
|
|
- if ( api_version >= 0x201 ) {
|
334
|
|
- /* !PXE calling convention */
|
335
|
|
- pxe_call_params_t pxe_params
|
336
|
|
- = va_arg ( params, typeof(pxe_params) );
|
337
|
|
- opcode = pxe_params.opcode;
|
338
|
|
- segoff = pxe_params.segoff;
|
339
|
|
- } else {
|
340
|
|
- /* PXENV+ calling convention */
|
341
|
|
- opcode = in_call_data->pm->regs.bx;
|
342
|
|
- segoff.segment = in_call_data->rm->seg_regs.es;
|
343
|
|
- segoff.offset = in_call_data->pm->regs.di;
|
344
|
|
- }
|
345
|
|
- structure = VIRTUAL ( segoff.segment, segoff.offset );
|
346
|
|
- return pxe_api_call ( opcode, structure );
|
347
|
|
-}
|
348
|
|
-
|
349
|
|
-#ifdef TEST_EXCLUDE_ALGORITHM
|
350
|
|
-/* This code retained because it's a difficult algorithm to tweak with
|
351
|
|
- * confidence
|
352
|
|
- */
|
353
|
|
-int ___test_exclude ( int start, int len, int estart, int elen, int fixbase );
|
354
|
|
-void __test_exclude ( int start, int len, int estart, int elen, int fixbase ) {
|
355
|
|
- int newrange = ___test_exclude ( start, len, estart, elen, fixbase );
|
356
|
|
- int newstart = ( newrange >> 16 ) & 0xffff;
|
357
|
|
- int newlen = ( newrange & 0xffff );
|
358
|
|
-
|
359
|
|
- printf ( "[%x,%x): excluding [%x,%x) %s gives [%x,%x)\n",
|
360
|
|
- start, start + len,
|
361
|
|
- estart, estart + elen,
|
362
|
|
- ( fixbase == 0 ) ? " " : "fb",
|
363
|
|
- newstart, newstart + newlen );
|
364
|
|
-}
|
365
|
|
-void _test_exclude ( int start, int len, int estart, int elen ) {
|
366
|
|
- __test_exclude ( start, len, estart, elen, 0 );
|
367
|
|
- __test_exclude ( start, len, estart, elen, 1 );
|
368
|
|
-}
|
369
|
|
-void test_exclude ( void ) {
|
370
|
|
- _test_exclude ( 0x8000, 0x1000, 0x0400, 0x200 ); /* before */
|
371
|
|
- _test_exclude ( 0x8000, 0x1000, 0x9000, 0x200 ); /* after */
|
372
|
|
- _test_exclude ( 0x8000, 0x1000, 0x7f00, 0x200 ); /* before overlap */
|
373
|
|
- _test_exclude ( 0x8000, 0x1000, 0x8f00, 0x200 ); /* after overlap */
|
374
|
|
- _test_exclude ( 0x8000, 0x1000, 0x8000, 0x200 ); /* align start */
|
375
|
|
- _test_exclude ( 0x8000, 0x1000, 0x8e00, 0x200 ); /* align end */
|
376
|
|
- _test_exclude ( 0x8000, 0x1000, 0x8100, 0x200 ); /* early overlap */
|
377
|
|
- _test_exclude ( 0x8000, 0x1000, 0x8d00, 0x200 ); /* late overlap */
|
378
|
|
- _test_exclude ( 0x8000, 0x1000, 0x7000, 0x3000 ); /* total overlap */
|
379
|
|
- _test_exclude ( 0x8000, 0x1000, 0x8000, 0x1000 ); /* exact overlap */
|
380
|
|
-}
|
381
|
|
-#endif /* TEST_EXCLUDE_ALGORITHM */
|
382
|
|
-
|
383
|
|
-#else /* PXE_EXPORT */
|
384
|
|
-
|
385
|
|
-/* Define symbols used by the linker scripts, to prevent link errors */
|
386
|
|
-__asm__ ( ".globl _pxe_stack_t_size" );
|
387
|
|
-__asm__ ( ".equ _pxe_stack_t_size, 0" );
|
388
|
|
-
|
389
|
|
-#endif /* PXE_EXPORT */
|
390
|
|
-
|
391
|
|
-#endif /* 0 */
|