ReactOS 0.4.16-dev-1946-g52006dd
pxe.c
Go to the documentation of this file.
1/*
2 * FreeLoader
3 * Copyright (C) 2011 Hervé Poussineau
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20#include <freeldr.h>
21
22#include <debug.h>
24
25#define TAG_PXE_FILE 'FexP'
26#define NO_FILE ((ULONG)-1)
27
28static IP4 _ServerIP = { 0, };
30static CHAR _OpenFileName[128];
31static ULONG _FileSize = 0;
34static UCHAR _Packet[1024]; // Should be a value which can be transferred well in one packet over the network
36
37static PPXE
39{
40 PPXE Ptr;
41 UCHAR Checksum;
42 UCHAR i;
43
44 /* Find the '!PXE' structure */
45 Ptr = (PPXE)0xA0000;
46 while ((ULONG_PTR)Ptr > 0x10000)
47 {
48 Ptr = (PPXE)((ULONG_PTR)Ptr - 0x10);
49
50 /* Look for signature */
51 if (memcmp(Ptr, "!PXE", 4) != 0)
52 continue;
53
54 /* Check size */
55 if (Ptr->StructLength != sizeof(PXE))
56 continue;
57
58 /* Check checksum */
59 Checksum = 0;
60 for (i = 0; i < Ptr->StructLength; i++)
61 Checksum += *((PUCHAR)Ptr + i);
62 if (Checksum != 0)
63 continue;
64
65 TRACE("!PXE structure found at %p\n", Ptr);
66 return Ptr;
67 }
68
69 return NULL;
70}
71
73{
74 static PPXE pPxe = NULL;
75 static BOOLEAN bPxeSearched = FALSE;
76 if (!bPxeSearched)
77 {
78 pPxe = FindPxeStructure();
79 bPxeSearched = TRUE;
80 }
81 return pPxe;
82}
83
86{
87 PPXE pxe;
89
90 pxe = GetPxeStructure();
91 if (!pxe)
92 return FALSE;
93
95 {
96 // HACK: this delay shouldn't be necessary
97 StallExecutionProcessor(100 * 1000); // 100 ms
98 TRACE("PxeCall(0x%x, %p)\n", Service, Parameter);
99 }
100
103 {
104 ERR("PxeCall(0x%x, %p) failed with exit=%d status=0x%x\n",
106 return FALSE;
107 }
109 {
110 ERR("PxeCall(0x%x, %p) succeeded, but returned error status 0x%x\n",
112 return FALSE;
113 }
114 return TRUE;
115}
116
118{
119 t_PXENV_TFTP_CLOSE closeData;
120
121 if (_OpenFile == NO_FILE || FileId != _OpenFile)
122 return EBADF;
123
124 RtlZeroMemory(&closeData, sizeof(closeData));
125 if (!CallPxe(PXENV_TFTP_CLOSE, &closeData))
126 return EIO;
127
129 return ESUCCESS;
130}
131
133{
135
136 if (_OpenFile == NO_FILE || FileId != _OpenFile)
137 return EBADF;
138
140 Information->EndingAddress.LowPart = _FileSize;
141 Information->CurrentAddress.LowPart = _FilePosition;
142
144
145 /* Set the ARC file attributes */
146 Information->Attributes = ReadOnlyFile;
147
148 /* Search for the last path separator. Slashes are used as separators,
149 * for supporting TFTP servers on POSIX systems (see PxeOpen()) */
151 if (FileName)
152 ++FileName; // Go past it.
153 else
154 FileName = _OpenFileName; // No separator: file name without directory.
155
156 /* Copy the file name, perhaps truncated, and NUL-terminated */
157 Information->FileNameLength = (ULONG)strlen(FileName);
158 Information->FileNameLength = min(Information->FileNameLength, sizeof(Information->FileName) - 1);
159 RtlCopyMemory(Information->FileName, FileName, Information->FileNameLength);
160 Information->FileName[Information->FileNameLength] = ANSI_NULL;
161
162 TRACE("PxeGetFileInformation(%lu) -> FileSize = %lu, FilePointer = 0x%lx\n",
163 FileId, Information->EndingAddress.LowPart, Information->CurrentAddress.LowPart);
164
165 return ESUCCESS;
166}
167
168static ARC_STATUS PxeOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
169{
170 t_PXENV_TFTP_GET_FSIZE sizeData;
171 t_PXENV_TFTP_OPEN openData;
172 SIZE_T PathLen, i;
173
174 if (_OpenFile != NO_FILE)
175 return EIO;
176 if (OpenMode != OpenReadOnly)
177 return EACCES;
178
179 /* Skip leading path separator, if any, so as to ensure that
180 * we always lookup the file at the root of the TFTP server's
181 * file space ("virtual root"), even if the server doesn't
182 * support this, and NOT from the root of the file system. */
183 if (*Path == '\\' || *Path == '/')
184 ++Path;
185
186 /* Retrieve the path length without NULL terminator */
187 PathLen = strlen(Path);
188 PathLen = min(PathLen, sizeof(_OpenFileName) - 1);
189
190 /* Lowercase the path and always use slashes as separators,
191 * for supporting TFTP servers on POSIX systems */
192 for (i = 0; i < PathLen; i++)
193 {
194 if (Path[i] == '\\')
195 _OpenFileName[i] = '/';
196 else
198 }
199
200 /* Zero out rest of the file name */
201 RtlZeroMemory(_OpenFileName + PathLen, sizeof(_OpenFileName) - PathLen);
202
203 RtlZeroMemory(&sizeData, sizeof(sizeData));
204 sizeData.ServerIPAddress = _ServerIP;
206 if (!CallPxe(PXENV_TFTP_GET_FSIZE, &sizeData))
207 {
208 ERR("Failed to get '%s' size\n", Path);
209 return EIO;
210 }
211
212 _FileSize = sizeData.FileSize;
213 _CachedLength = 0;
214
215 RtlZeroMemory(&openData, sizeof(openData));
216 openData.ServerIPAddress = _ServerIP;
218 openData.PacketSize = sizeof(_Packet);
219
220 if (!CallPxe(PXENV_TFTP_OPEN, &openData))
221 return ENOENT;
222
223 _FilePosition = 0;
224 _PacketPosition = 0;
225
226 _OpenFile = *FileId;
227 return ESUCCESS;
228}
229
231{
232 t_PXENV_TFTP_READ readData;
233 ULONG i;
234
235 *Count = 0;
236
237 if (_OpenFile == NO_FILE || FileId != _OpenFile)
238 return EBADF;
239
240 RtlZeroMemory(&readData, sizeof(readData));
241 readData.Buffer.segment = ((ULONG_PTR)_Packet & 0xf0000) / 16;
242 readData.Buffer.offset = (ULONG_PTR)_Packet & 0xffff;
243
244 // Get new packets as required
245 while (N > 0)
246 {
248 i = N;
249 else
252 _FilePosition += i;
253 Buffer = (UCHAR*)Buffer + i;
254 *Count += i;
255 N -= i;
256 if (N == 0)
257 break;
258
259 if (!CallPxe(PXENV_TFTP_READ, &readData))
260 return EIO;
262 _CachedLength += readData.BufferSize;
263 }
264
265 return ESUCCESS;
266}
267
269{
270 t_PXENV_TFTP_READ readData;
271
272 if (_OpenFile == NO_FILE || FileId != _OpenFile)
273 return EBADF;
274
275 if (Position->HighPart != 0 || SeekMode != SeekAbsolute)
276 return EINVAL;
277
278 if (Position->LowPart < _FilePosition)
279 {
280 // Close and reopen the file to go to position 0
281 if (PxeClose(FileId) != ESUCCESS)
282 return EIO;
283 if (PxeOpen(_OpenFileName, OpenReadOnly, &FileId) != ESUCCESS)
284 return EIO;
285 }
286
287 RtlZeroMemory(&readData, sizeof(readData));
288 readData.Buffer.segment = ((ULONG_PTR)_Packet & 0xf0000) / 16;
289 readData.Buffer.offset = (ULONG_PTR)_Packet & 0xffff;
290
291 // Get new packets as required
292 while (Position->LowPart > _CachedLength)
293 {
294 if (!CallPxe(PXENV_TFTP_READ, &readData))
295 return EIO;
297 _CachedLength += readData.BufferSize;
298 }
299
300 _FilePosition = Position->LowPart;
301 return ESUCCESS;
302}
303
304static const DEVVTBL PxeVtbl = {
305 PxeClose,
307 PxeOpen,
308 PxeRead,
309 PxeSeek,
310};
311
312const DEVVTBL* PxeMount(ULONG DeviceId)
313{
314 if (GetPxeStructure() == NULL)
315 return NULL;
316 return &PxeVtbl;
317}
318
320{
321 // Nothing to do
322 return ESUCCESS;
323}
324
326{
327 // No disk access in PXE mode
328 return EINVAL;
329}
330
331static ARC_STATUS PxeDiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
332{
333 // Nothing to do
334 return ESUCCESS;
335}
336
338{
339 // No disk access in PXE mode
340 return EINVAL;
341}
342
344{
345 // No disk access in PXE mode
346 return EINVAL;
347}
348
349static const DEVVTBL PxeDiskVtbl = {
355};
356
358{
360 BOOLEAN res;
361 UCHAR* Packet;
362
363 RtlZeroMemory(&Data, sizeof(Data));
365
367 if (!res)
368 return FALSE;
369 if (Data.BufferSize < 36)
370 return FALSE;
371 Packet = (UCHAR*)((ULONG_PTR)(Data.Buffer.segment << 4) + Data.Buffer.offset);
372 RtlCopyMemory(&_ServerIP, Packet + 20, sizeof(IP4));
373 return TRUE;
374}
375
377{
378 static BOOLEAN Initialized = FALSE;
379 static BOOLEAN Success = FALSE;
380
381 // Do initialization only once
382 if (Initialized)
383 return Success;
385
386 // Check if PXE is available
388 {
389 FsRegisterDevice("net(0)", &PxeDiskVtbl);
390 Success = TRUE;
391 }
392
393 return Success;
394}
395
#define N
Definition: crc32.c:57
unsigned short UINT16
unsigned char BOOLEAN
PRTL_UNICODE_STRING_BUFFER Path
#define ENOENT
Definition: acclib.h:79
#define EINVAL
Definition: acclib.h:90
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define EIO
Definition: acclib.h:81
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define EACCES
Definition: acclib.h:85
#define EBADF
Definition: acclib.h:82
int tolower(int c)
Definition: utclib.c:902
#define __cdecl
Definition: accygwin.h:79
UINT16 PXENV_STATUS
Definition: pxe.h:8
#define PXENV_TFTP_READ
Definition: pxe.h:589
#define PXENV_TFTP_CLOSE
Definition: pxe.h:588
#define PXENV_EXIT_SUCCESS
Definition: pxe.h:457
#define PXENV_TFTP_GET_FSIZE
Definition: pxe.h:591
struct s_PXE * PPXE
#define PXENV_PACKET_TYPE_CACHED_REPLY
Definition: pxe.h:403
UINT16 PXENV_EXIT
Definition: pxe.h:7
#define PXENV_TFTP_OPEN
Definition: pxe.h:587
#define PXENV_STATUS_SUCCESS
Definition: pxe.h:461
#define PXENV_GET_CACHED_INFO
Definition: pxe.h:597
#define ERR(fmt,...)
Definition: precomp.h:57
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:106
VOID FsRegisterDevice(_In_ PCSTR DeviceName, _In_ const DEVVTBL *FuncTable)
Definition: fs.c:673
Definition: bufpool.h:45
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ULONG_PTR
Definition: config.h:101
@ Success
Definition: eventcreate.c:712
struct _FileName FileName
Definition: fatprocs.h:897
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
GLuint res
Definition: glext.h:9613
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define min(a, b)
Definition: monoChain.cc:55
_In_ NDIS_HANDLE _In_ PNDIS_PACKET Packet
Definition: ndis.h:1549
@ Initialized
Definition: ketypes.h:388
int Count
Definition: noreturn.cpp:7
#define ANSI_NULL
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
@ Service
Definition: ntsecapi.h:292
VOID StallExecutionProcessor(ULONG Microseconds)
Definition: pchw.c:60
static ULONG _CachedLength
Definition: pxe.c:35
static const DEVVTBL PxeVtbl
Definition: pxe.c:304
const DEVVTBL * PxeMount(ULONG DeviceId)
Definition: pxe.c:312
static ARC_STATUS PxeDiskOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: pxe.c:331
static const DEVVTBL PxeDiskVtbl
Definition: pxe.c:349
static BOOLEAN GetCachedInfo(VOID)
Definition: pxe.c:357
static ARC_STATUS PxeOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: pxe.c:168
static ULONG _FileSize
Definition: pxe.c:31
static ARC_STATUS PxeDiskRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: pxe.c:337
static ARC_STATUS PxeRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: pxe.c:230
static ARC_STATUS PxeDiskSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: pxe.c:343
BOOLEAN CallPxe(UINT16 Service, PVOID Parameter)
Definition: pxe.c:85
static PPXE FindPxeStructure(VOID)
Definition: pxe.c:38
static ARC_STATUS PxeDiskClose(ULONG FileId)
Definition: pxe.c:319
PXENV_EXIT __cdecl PxeCallApi(UINT16 Segment, UINT16 Offset, UINT16 Service, VOID *Parameter)
BOOLEAN PxeInit(VOID)
Definition: pxe.c:376
#define NO_FILE
Definition: pxe.c:26
static ULONG _PacketPosition
Definition: pxe.c:33
static ARC_STATUS PxeGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: pxe.c:132
static ULONG _OpenFile
Definition: pxe.c:29
static ULONG _FilePosition
Definition: pxe.c:32
static CHAR _OpenFileName[128]
Definition: pxe.c:30
static ARC_STATUS PxeSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: pxe.c:268
static ARC_STATUS PxeClose(ULONG FileId)
Definition: pxe.c:117
static UCHAR _Packet[1024]
Definition: pxe.c:34
static IP4 _ServerIP
Definition: pxe.c:28
static ARC_STATUS PxeDiskGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: pxe.c:325
static PPXE GetPxeStructure(VOID)
Definition: pxe.c:72
_CRT_RESTORE_GCC_WARNINGS _CRT_DISABLE_GCC_WARNINGS _Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
@ ESUCCESS
Definition: arc.h:32
ULONG ARC_STATUS
Definition: arc.h:4
@ NetworkPeripheral
Definition: arc.h:149
@ SeekAbsolute
Definition: arc.h:59
enum _OPENMODE OPENMODE
@ ReadOnlyFile
Definition: arc.h:78
enum _SEEKMODE SEEKMODE
@ OpenReadOnly
Definition: arc.h:65
#define exit(n)
Definition: config.h:202
#define TRACE(s)
Definition: solgame.cpp:4
UINT8 FileName[128]
Definition: pxe.h:354
IP4 ServerIPAddress
Definition: pxe.h:314
UINT16 PacketSize
Definition: pxe.h:318
UINT8 FileName[128]
Definition: pxe.h:316
SEGOFF16 Buffer
Definition: pxe.h:331
UINT16 BufferSize
Definition: pxe.h:330
Definition: pxe.h:39
SEGOFF16 EntryPointSP
Definition: pxe.h:47
SEGSEL segment
Definition: pxe.h:35
OFF16 offset
Definition: pxe.h:34
Definition: fs.h:25
static COORD Position
Definition: mouse.c:34
ULONG_PTR SIZE_T
Definition: typedefs.h:80
const char * PCSTR
Definition: typedefs.h:52
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
Definition: pxe.h:17
_In_ WDFREQUEST _In_ NTSTATUS _In_ ULONG_PTR Information
Definition: wdfrequest.h:1049
_Inout_ PVOID Segment
Definition: exfuncs.h:1101
_Inout_opt_ PVOID Parameter
Definition: rtltypes.h:336
unsigned char UCHAR
Definition: xmlstorage.h:181
char CHAR
Definition: xmlstorage.h:175