|
@@ -1,324 +0,0 @@
|
1
|
|
-/*
|
2
|
|
- * Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
17
|
|
- */
|
18
|
|
-
|
19
|
|
-#include <stdint.h>
|
20
|
|
-#include <stdlib.h>
|
21
|
|
-#include <string.h>
|
22
|
|
-#include <pxe.h>
|
23
|
|
-#include <realmode.h>
|
24
|
|
-#include <bios.h>
|
25
|
|
-#include <pnpbios.h>
|
26
|
|
-
|
27
|
|
-/** @file
|
28
|
|
- *
|
29
|
|
- * PXE drivers
|
30
|
|
- *
|
31
|
|
- */
|
32
|
|
-
|
33
|
|
-static LIST_HEAD ( pxe_drivers );
|
34
|
|
-
|
35
|
|
-/**
|
36
|
|
- * Parse PXE ROM ID structure
|
37
|
|
- *
|
38
|
|
- * @v pxedrv PXE driver
|
39
|
|
- * @v pxeromid Offset within ROM to PXE ROM ID structure
|
40
|
|
- * @ret rc Return status code
|
41
|
|
- */
|
42
|
|
-static int pxedrv_parse_pxeromid ( struct pxe_driver *pxedrv,
|
43
|
|
- unsigned int pxeromid ) {
|
44
|
|
- struct undi_rom_id undi_rom_id;
|
45
|
|
- unsigned int undiloader;
|
46
|
|
-
|
47
|
|
- DBGC ( pxedrv, "PXEDRV %p has PXE ROM ID at %04x:%04x\n", pxedrv,
|
48
|
|
- pxedrv->rom_segment, pxeromid );
|
49
|
|
-
|
50
|
|
- /* Read PXE ROM ID structure and verify */
|
51
|
|
- copy_from_real ( &undi_rom_id, pxedrv->rom_segment, pxeromid,
|
52
|
|
- sizeof ( undi_rom_id ) );
|
53
|
|
- if ( undi_rom_id.Signature != UNDI_ROM_ID_SIGNATURE ) {
|
54
|
|
- DBGC ( pxedrv, "PXEDRV %p has bad PXE ROM ID signature "
|
55
|
|
- "%08lx\n", pxedrv, undi_rom_id.Signature );
|
56
|
|
- return -EINVAL;
|
57
|
|
- }
|
58
|
|
-
|
59
|
|
- /* Check for UNDI loader */
|
60
|
|
- undiloader = undi_rom_id.UNDILoader;
|
61
|
|
- if ( ! undiloader ) {
|
62
|
|
- DBGC ( pxedrv, "PXEDRV %p has no UNDI loader\n", pxedrv );
|
63
|
|
- return -EINVAL;
|
64
|
|
- }
|
65
|
|
-
|
66
|
|
- /* Fill in PXE driver loader fields */
|
67
|
|
- pxedrv->loader_entry.segment = pxedrv->rom_segment;
|
68
|
|
- pxedrv->loader_entry.offset = undiloader;
|
69
|
|
- pxedrv->code_size = undi_rom_id.CodeSize;
|
70
|
|
- pxedrv->data_size = undi_rom_id.DataSize;
|
71
|
|
-
|
72
|
|
- DBGC ( pxedrv, "PXEDRV %p has UNDI loader at %04x:%04x "
|
73
|
|
- "(code %04x data %04x)\n", pxedrv,
|
74
|
|
- pxedrv->loader_entry.segment, pxedrv->loader_entry.offset,
|
75
|
|
- pxedrv->code_size, pxedrv->data_size );
|
76
|
|
- return 0;
|
77
|
|
-}
|
78
|
|
-
|
79
|
|
-/**
|
80
|
|
- * Parse PCI expansion header
|
81
|
|
- *
|
82
|
|
- * @v pxedrv PXE driver
|
83
|
|
- * @v pcirheader Offset within ROM to PCI expansion header
|
84
|
|
- */
|
85
|
|
-static int pxedrv_parse_pcirheader ( struct pxe_driver *pxedrv,
|
86
|
|
- unsigned int pcirheader ) {
|
87
|
|
- struct pcir_header pcir_header;
|
88
|
|
-
|
89
|
|
- DBGC ( pxedrv, "PXEDRV %p has PCI expansion header at %04x:%04x\n",
|
90
|
|
- pxedrv, pxedrv->rom_segment, pcirheader );
|
91
|
|
-
|
92
|
|
- /* Read PCI expansion header and verify */
|
93
|
|
- copy_from_real ( &pcir_header, pxedrv->rom_segment, pcirheader,
|
94
|
|
- sizeof ( pcir_header ) );
|
95
|
|
- if ( pcir_header.signature != PCIR_SIGNATURE ) {
|
96
|
|
- DBGC ( pxedrv, "PXEDRV %p has bad PCI expansion header "
|
97
|
|
- "signature %08lx\n", pxedrv, pcir_header.signature );
|
98
|
|
- return -EINVAL;
|
99
|
|
- }
|
100
|
|
-
|
101
|
|
- /* Fill in PXE driver PCI device fields */
|
102
|
|
- pxedrv->bus_type = PCI_NIC;
|
103
|
|
- pxedrv->bus_id.pci.vendor_id = pcir_header.vendor_id;
|
104
|
|
- pxedrv->bus_id.pci.device_id = pcir_header.device_id;
|
105
|
|
-
|
106
|
|
- DBGC ( pxedrv, "PXEDRV %p is for PCI devices %04x:%04x\n", pxedrv,
|
107
|
|
- pxedrv->bus_id.pci.vendor_id, pxedrv->bus_id.pci.device_id );
|
108
|
|
- return 0;
|
109
|
|
-
|
110
|
|
-}
|
111
|
|
-
|
112
|
|
-/**
|
113
|
|
- * Create PXE driver for expansion ROM
|
114
|
|
- *
|
115
|
|
- * @v rom_segment ROM segment address
|
116
|
|
- * @ret rc Return status code
|
117
|
|
- */
|
118
|
|
-static int pxedrv_probe_rom ( unsigned int rom_segment ) {
|
119
|
|
- struct pxe_driver *pxedrv = NULL;
|
120
|
|
- struct undi_rom rom;
|
121
|
|
- size_t rom_len;
|
122
|
|
- unsigned int pxeromid;
|
123
|
|
- unsigned int pcirheader;
|
124
|
|
- int rc;
|
125
|
|
-
|
126
|
|
- /* Read expansion ROM header and verify */
|
127
|
|
- copy_from_real ( &rom, rom_segment, 0, sizeof ( rom ) );
|
128
|
|
- if ( rom.Signature != ROM_SIGNATURE ) {
|
129
|
|
- rc = -EINVAL;
|
130
|
|
- goto err;
|
131
|
|
- }
|
132
|
|
- rom_len = ( rom.ROMLength * 512 );
|
133
|
|
-
|
134
|
|
- /* Allocate memory for PXE driver */
|
135
|
|
- pxedrv = malloc ( sizeof ( *pxedrv ) );
|
136
|
|
- if ( ! pxedrv ) {
|
137
|
|
- DBG ( "Could not allocate PXE driver structure\n" );
|
138
|
|
- rc = -ENOMEM;
|
139
|
|
- goto err;
|
140
|
|
- }
|
141
|
|
- memset ( pxedrv, 0, sizeof ( *pxedrv ) );
|
142
|
|
- DBGC ( pxedrv, "PXEDRV %p trying expansion ROM at %04x:0000 (%zdkB)\n",
|
143
|
|
- pxedrv, rom_segment, ( rom_len / 1024 ) );
|
144
|
|
- pxedrv->rom_segment = rom_segment;
|
145
|
|
-
|
146
|
|
- /* Check for and parse PXE ROM ID */
|
147
|
|
- pxeromid = rom.PXEROMID;
|
148
|
|
- if ( ! pxeromid ) {
|
149
|
|
- DBGC ( pxedrv, "PXEDRV %p has no PXE ROM ID\n", pxedrv );
|
150
|
|
- rc = -EINVAL;
|
151
|
|
- goto err;
|
152
|
|
- }
|
153
|
|
- if ( pxeromid > rom_len ) {
|
154
|
|
- DBGC ( pxedrv, "PXEDRV %p PXE ROM ID outside ROM\n", pxedrv );
|
155
|
|
- rc = -EINVAL;
|
156
|
|
- goto err;
|
157
|
|
- }
|
158
|
|
- if ( ( rc = pxedrv_parse_pxeromid ( pxedrv, pxeromid ) ) != 0 )
|
159
|
|
- goto err;
|
160
|
|
-
|
161
|
|
- /* Parse PCIR header, if present */
|
162
|
|
- pcirheader = rom.PCIRHeader;
|
163
|
|
- if ( pcirheader )
|
164
|
|
- pxedrv_parse_pcirheader ( pxedrv, pcirheader );
|
165
|
|
-
|
166
|
|
- /* Add to PXE driver list and return */
|
167
|
|
- DBGC ( pxedrv, "PXEDRV %p registered\n", pxedrv );
|
168
|
|
- list_add ( &pxedrv->list, &pxe_drivers );
|
169
|
|
- return 0;
|
170
|
|
-
|
171
|
|
- err:
|
172
|
|
- free ( pxedrv );
|
173
|
|
- return rc;
|
174
|
|
-}
|
175
|
|
-
|
176
|
|
-/**
|
177
|
|
- * Create PXE drivers for all possible expansion ROMs
|
178
|
|
- *
|
179
|
|
- * @ret
|
180
|
|
- */
|
181
|
|
-static void pxedrv_probe_all_roms ( void ) {
|
182
|
|
- static int probed = 0;
|
183
|
|
- unsigned int rom_segment;
|
184
|
|
-
|
185
|
|
- /* Perform probe only once */
|
186
|
|
- if ( probed )
|
187
|
|
- return;
|
188
|
|
-
|
189
|
|
- DBG ( "Scanning for PXE expansion ROMs\n" );
|
190
|
|
-
|
191
|
|
- /* Scan through expansion ROM region at 2kB intervals */
|
192
|
|
- for ( rom_segment = 0xc000 ; rom_segment < 0x10000 ;
|
193
|
|
- rom_segment += 0x80 ) {
|
194
|
|
- pxedrv_probe_rom ( rom_segment );
|
195
|
|
- }
|
196
|
|
-
|
197
|
|
- probed = 1;
|
198
|
|
-}
|
199
|
|
-
|
200
|
|
-/**
|
201
|
|
- * Find PXE driver for PCI device
|
202
|
|
- *
|
203
|
|
- * @v vendor_id PCI vendor ID
|
204
|
|
- * @v device_id PCI device ID
|
205
|
|
- * @v rombase ROM base address, or 0 for any
|
206
|
|
- * @ret pxedrv PXE driver, or NULL
|
207
|
|
- */
|
208
|
|
-struct pxe_driver * pxedrv_find_pci_driver ( unsigned int vendor_id,
|
209
|
|
- unsigned int device_id,
|
210
|
|
- unsigned int rombase ) {
|
211
|
|
- struct pxe_driver *pxedrv;
|
212
|
|
-
|
213
|
|
- pxedrv_probe_all_roms();
|
214
|
|
-
|
215
|
|
- list_for_each_entry ( pxedrv, &pxe_drivers, list ) {
|
216
|
|
- if ( pxedrv->bus_type != PCI_NIC )
|
217
|
|
- continue;
|
218
|
|
- if ( pxedrv->bus_id.pci.vendor_id != vendor_id )
|
219
|
|
- continue;
|
220
|
|
- if ( pxedrv->bus_id.pci.device_id != device_id )
|
221
|
|
- continue;
|
222
|
|
- if ( rombase && ( ( pxedrv->rom_segment << 4 ) != rombase ) )
|
223
|
|
- continue;
|
224
|
|
- DBGC ( pxedrv, "PXEDRV %p matched PCI %04x:%04x (%08x)\n",
|
225
|
|
- pxedrv, vendor_id, device_id, rombase );
|
226
|
|
- return pxedrv;
|
227
|
|
- }
|
228
|
|
-
|
229
|
|
- DBG ( "No PXE driver matched PCI %04x:%04x (%08x)\n",
|
230
|
|
- vendor_id, device_id, rombase );
|
231
|
|
- return NULL;
|
232
|
|
-}
|
233
|
|
-
|
234
|
|
-/** Parameter block for calling UNDI loader */
|
235
|
|
-static struct s_UNDI_LOADER __data16 ( undi_loader );
|
236
|
|
-#define undi_loader __use_data16 ( undi_loader )
|
237
|
|
-
|
238
|
|
-/** UNDI loader entry point */
|
239
|
|
-static SEGOFF16_t __data16 ( undi_loader_entry );
|
240
|
|
-#define undi_loader_entry __use_data16 ( undi_loader_entry )
|
241
|
|
-
|
242
|
|
-/**
|
243
|
|
- * Call UNDI loader to create a pixie
|
244
|
|
- *
|
245
|
|
- * @v pxedrv PXE driver
|
246
|
|
- * @v pxe PXE device to be created
|
247
|
|
- * @v pci_busdevfn PCI bus:dev.fn (PCI devices only), or 0
|
248
|
|
- * @v isapnp_csn ISAPnP Card Select Number, or -1U
|
249
|
|
- * @v isapnp_read_port ISAPnP read port, or -1U
|
250
|
|
- * @ret rc Return status code
|
251
|
|
- */
|
252
|
|
-static int pxedrv_load ( struct pxe_driver *pxedrv, struct pxe_device *pxe,
|
253
|
|
- unsigned int pci_busdevfn, unsigned int isapnp_csn,
|
254
|
|
- unsigned int isapnp_read_port ) {
|
255
|
|
- int pnpbios_offset;
|
256
|
|
- uint16_t fbms;
|
257
|
|
- unsigned int fbms_seg;
|
258
|
|
- int discard;
|
259
|
|
- uint16_t exit;
|
260
|
|
- int rc;
|
261
|
|
-
|
262
|
|
- /* Record device location information */
|
263
|
|
- memset ( &undi_loader, 0, sizeof ( undi_loader ) );
|
264
|
|
- undi_loader.AX = pci_busdevfn;
|
265
|
|
- undi_loader.BX = isapnp_csn;
|
266
|
|
- undi_loader.DX = isapnp_read_port;
|
267
|
|
-
|
268
|
|
- /* Set up PnP BIOS pointer, if PnP BIOS present */
|
269
|
|
- pnpbios_offset = find_pnp_bios();
|
270
|
|
- if ( pnpbios_offset >= 0 ) {
|
271
|
|
- undi_loader.ES = BIOS_SEG;
|
272
|
|
- undi_loader.DI = pnpbios_offset;
|
273
|
|
- }
|
274
|
|
-
|
275
|
|
- /* Allocate base memory for PXE stack */
|
276
|
|
- get_real ( fbms, BDA_SEG, BDA_FBMS );
|
277
|
|
- fbms_seg = ( fbms << 6 );
|
278
|
|
- fbms_seg -= ( ( pxedrv->data_size + 0x0f ) >> 4 );
|
279
|
|
- undi_loader.UNDI_DS = fbms_seg;
|
280
|
|
- fbms_seg -= ( ( pxedrv->code_size + 0x0f ) >> 4 );
|
281
|
|
- undi_loader.UNDI_CS = fbms_seg;
|
282
|
|
- DBGC ( pxedrv, "PXEDRV %p loading to CS %04x and DS %04x\n", pxedrv,
|
283
|
|
- undi_loader.UNDI_CS, undi_loader.UNDI_DS );
|
284
|
|
-
|
285
|
|
- /* Call loader */
|
286
|
|
- undi_loader_entry = pxedrv->loader_entry;
|
287
|
|
- __asm__ __volatile__ ( REAL_CODE ( "pushw %%ds\n\t"
|
288
|
|
- "pushw %w0\n\t"
|
289
|
|
- "lcall *%c3\n\t"
|
290
|
|
- "addw $4, %%sp\n\t" )
|
291
|
|
- : "=a" ( exit ), "=r" ( discard )
|
292
|
|
- : "0" ( & __from_data16 ( undi_loader ) ),
|
293
|
|
- "p" ( & __from_data16 ( undi_loader_entry )));
|
294
|
|
- if ( exit != PXENV_EXIT_SUCCESS ) {
|
295
|
|
- rc = -undi_loader.Status;
|
296
|
|
- if ( rc == 0 ) /* Paranoia */
|
297
|
|
- rc = -EIO;
|
298
|
|
- DBGC ( pxedrv, "PXEDRV %p loader failed: %s\n", pxedrv,
|
299
|
|
- strerror ( rc ) );
|
300
|
|
- return rc;
|
301
|
|
- }
|
302
|
|
-
|
303
|
|
- /* Update free base memory counter */
|
304
|
|
- fbms = ( fbms_seg >> 6 );
|
305
|
|
- put_real ( fbms, BDA_SEG, BDA_FBMS );
|
306
|
|
-
|
307
|
|
- /* Record location of pixie in PXE device structure */
|
308
|
|
- pxe->pxenv = undi_loader.PXENVptr;
|
309
|
|
- pxe->ppxe = undi_loader.PXEptr;
|
310
|
|
- return 0;
|
311
|
|
-}
|
312
|
|
-
|
313
|
|
-/**
|
314
|
|
- * Call UNDI loader to create a pixie
|
315
|
|
- *
|
316
|
|
- * @v pxedrv PXE driver
|
317
|
|
- * @v pxe PXE device to be created
|
318
|
|
- * @v pci_busdevfn PCI bus:dev.fn
|
319
|
|
- * @ret rc Return status code
|
320
|
|
- */
|
321
|
|
-int pxedrv_load_pci ( struct pxe_driver *pxedrv, struct pxe_device *pxe,
|
322
|
|
- unsigned int bus, unsigned int devfn ) {
|
323
|
|
- return pxedrv_load ( pxedrv, pxe, ( ( bus << 8 ) | devfn ), -1U, -1U );
|
324
|
|
-}
|