iPXE
pxe_file.c
Go to the documentation of this file.
1 /** @file
2  *
3  * PXE FILE API
4  *
5  */
6 
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <errno.h>
10 #include <byteswap.h>
11 #include <ipxe/uaccess.h>
12 #include <ipxe/posix_io.h>
13 #include <ipxe/features.h>
14 #include <pxe.h>
15 #include <realmode.h>
16 
17 /*
18  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
19  *
20  * This program is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU General Public License as
22  * published by the Free Software Foundation; either version 2 of the
23  * License, or any later version.
24  *
25  * This program is distributed in the hope that it will be useful, but
26  * WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28  * General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, write to the Free Software
32  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
33  * 02110-1301, USA.
34  *
35  * You can also choose to distribute this program under the terms of
36  * the Unmodified Binary Distribution Licence (as given in the file
37  * COPYING.UBDL), provided that you have satisfied its requirements.
38  */
39 
40 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
41 
43 
44 /**
45  * FILE OPEN
46  *
47  * @v file_open Pointer to a struct s_PXENV_FILE_OPEN
48  * @v s_PXENV_FILE_OPEN::FileName URL of file to open
49  * @ret #PXENV_EXIT_SUCCESS File was opened
50  * @ret #PXENV_EXIT_FAILURE File was not opened
51  * @ret s_PXENV_FILE_OPEN::Status PXE status code
52  * @ret s_PXENV_FILE_OPEN::FileHandle Handle of opened file
53  *
54  */
56  userptr_t filename;
57  size_t filename_len;
58  int fd;
59 
60  DBG ( "PXENV_FILE_OPEN" );
61 
62  /* Copy name from external program, and open it */
63  filename = real_to_user ( file_open->FileName.segment,
64  file_open->FileName.offset );
65  filename_len = strlen_user ( filename, 0 );
66  {
67  char uri_string[ filename_len + 1 ];
68 
69  copy_from_user ( uri_string, filename, 0,
70  sizeof ( uri_string ) );
71  DBG ( " %s", uri_string );
72  fd = open ( uri_string );
73  }
74 
75  if ( fd < 0 ) {
76  file_open->Status = PXENV_STATUS ( fd );
77  return PXENV_EXIT_FAILURE;
78  }
79 
80  DBG ( " as file %d", fd );
81 
82  file_open->FileHandle = fd;
84  return PXENV_EXIT_SUCCESS;
85 }
86 
87 /**
88  * FILE CLOSE
89  *
90  * @v file_close Pointer to a struct s_PXENV_FILE_CLOSE
91  * @v s_PXENV_FILE_CLOSE::FileHandle File handle
92  * @ret #PXENV_EXIT_SUCCESS File was closed
93  * @ret #PXENV_EXIT_FAILURE File was not closed
94  * @ret s_PXENV_FILE_CLOSE::Status PXE status code
95  *
96  */
97 static PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE *file_close ) {
98 
99  DBG ( "PXENV_FILE_CLOSE %d", file_close->FileHandle );
100 
101  close ( file_close->FileHandle );
102  file_close->Status = PXENV_STATUS_SUCCESS;
103  return PXENV_EXIT_SUCCESS;
104 }
105 
106 /**
107  * FILE SELECT
108  *
109  * @v file_select Pointer to a struct s_PXENV_FILE_SELECT
110  * @v s_PXENV_FILE_SELECT::FileHandle File handle
111  * @ret #PXENV_EXIT_SUCCESS File has been checked for readiness
112  * @ret #PXENV_EXIT_FAILURE File has not been checked for readiness
113  * @ret s_PXENV_FILE_SELECT::Status PXE status code
114  * @ret s_PXENV_FILE_SELECT::Ready Indication of readiness
115  *
116  */
117 static PXENV_EXIT_t
118 pxenv_file_select ( struct s_PXENV_FILE_SELECT *file_select ) {
119  fd_set fdset;
120  int ready;
121 
122  DBG ( "PXENV_FILE_SELECT %d", file_select->FileHandle );
123 
124  FD_ZERO ( &fdset );
125  FD_SET ( file_select->FileHandle, &fdset );
126  if ( ( ready = select ( &fdset, 0 ) ) < 0 ) {
127  file_select->Status = PXENV_STATUS ( ready );
128  return PXENV_EXIT_FAILURE;
129  }
130 
131  file_select->Ready = ( ready ? RDY_READ : 0 );
132  file_select->Status = PXENV_STATUS_SUCCESS;
133  return PXENV_EXIT_SUCCESS;
134 }
135 
136 /**
137  * FILE READ
138  *
139  * @v file_read Pointer to a struct s_PXENV_FILE_READ
140  * @v s_PXENV_FILE_READ::FileHandle File handle
141  * @v s_PXENV_FILE_READ::BufferSize Size of data buffer
142  * @v s_PXENV_FILE_READ::Buffer Data buffer
143  * @ret #PXENV_EXIT_SUCCESS Data has been read from file
144  * @ret #PXENV_EXIT_FAILURE Data has not been read from file
145  * @ret s_PXENV_FILE_READ::Status PXE status code
146  * @ret s_PXENV_FILE_READ::Ready Indication of readiness
147  * @ret s_PXENV_FILE_READ::BufferSize Length of data read
148  *
149  */
152  ssize_t len;
153 
154  DBG ( "PXENV_FILE_READ %d to %04x:%04x+%04x", file_read->FileHandle,
155  file_read->Buffer.segment, file_read->Buffer.offset,
156  file_read->BufferSize );
157 
158  buffer = real_to_user ( file_read->Buffer.segment,
159  file_read->Buffer.offset );
160  if ( ( len = read_user ( file_read->FileHandle, buffer, 0,
161  file_read->BufferSize ) ) < 0 ) {
162  file_read->Status = PXENV_STATUS ( len );
163  return PXENV_EXIT_FAILURE;
164  }
165 
166  DBG ( " read %04zx", ( ( size_t ) len ) );
167 
168  file_read->BufferSize = len;
170  return PXENV_EXIT_SUCCESS;
171 }
172 
173 /**
174  * GET FILE SIZE
175  *
176  * @v get_file_size Pointer to a struct s_PXENV_GET_FILE_SIZE
177  * @v s_PXENV_GET_FILE_SIZE::FileHandle File handle
178  * @ret #PXENV_EXIT_SUCCESS File size has been determined
179  * @ret #PXENV_EXIT_FAILURE File size has not been determined
180  * @ret s_PXENV_GET_FILE_SIZE::Status PXE status code
181  * @ret s_PXENV_GET_FILE_SIZE::FileSize Size of file
182  */
183 static PXENV_EXIT_t
184 pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE *get_file_size ) {
185  ssize_t filesize;
186 
187  DBG ( "PXENV_GET_FILE_SIZE %d", get_file_size->FileHandle );
188 
189  filesize = fsize ( get_file_size->FileHandle );
190  if ( filesize < 0 ) {
191  get_file_size->Status = PXENV_STATUS ( filesize );
192  return PXENV_EXIT_FAILURE;
193  }
194 
195  DBG ( " is %zd", ( ( size_t ) filesize ) );
196 
197  get_file_size->FileSize = filesize;
198  get_file_size->Status = PXENV_STATUS_SUCCESS;
199  return PXENV_EXIT_SUCCESS;
200 }
201 
202 /**
203  * FILE EXEC
204  *
205  * @v file_exec Pointer to a struct s_PXENV_FILE_EXEC
206  * @v s_PXENV_FILE_EXEC::Command Command to execute
207  * @ret #PXENV_EXIT_SUCCESS Command was executed successfully
208  * @ret #PXENV_EXIT_FAILURE Command was not executed successfully
209  * @ret s_PXENV_FILE_EXEC::Status PXE status code
210  *
211  */
212 static PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ) {
214  size_t command_len;
215  int rc;
216 
217  DBG ( "PXENV_FILE_EXEC" );
218 
219  /* Copy name from external program, and exec it */
220  command = real_to_user ( file_exec->Command.segment,
221  file_exec->Command.offset );
223  {
224  char command_string[ command_len + 1 ];
225 
226  copy_from_user ( command_string, command, 0,
227  sizeof ( command_string ) );
228  DBG ( " %s", command_string );
229 
230  if ( ( rc = system ( command_string ) ) != 0 ) {
231  file_exec->Status = PXENV_STATUS ( rc );
232  return PXENV_EXIT_FAILURE;
233  }
234  }
235 
236  file_exec->Status = PXENV_STATUS_SUCCESS;
237  return PXENV_EXIT_SUCCESS;
238 }
239 
240 /**
241  * FILE CMDLINE
242  *
243  * @v file_cmdline Pointer to a struct s_PXENV_FILE_CMDLINE
244  * @v s_PXENV_FILE_CMDLINE::Buffer Buffer to contain command line
245  * @v s_PXENV_FILE_CMDLINE::BufferSize Size of buffer
246  * @ret #PXENV_EXIT_SUCCESS Command was executed successfully
247  * @ret #PXENV_EXIT_FAILURE Command was not executed successfully
248  * @ret s_PXENV_FILE_EXEC::Status PXE status code
249  * @ret s_PXENV_FILE_EXEC::BufferSize Length of command line (including NUL)
250  *
251  */
252 static PXENV_EXIT_t
253 pxenv_file_cmdline ( struct s_PXENV_FILE_CMDLINE *file_cmdline ) {
255  size_t max_len;
256  size_t len;
257 
258  DBG ( "PXENV_FILE_CMDLINE to %04x:%04x+%04x \"%s\"\n",
259  file_cmdline->Buffer.segment, file_cmdline->Buffer.offset,
260  file_cmdline->BufferSize, pxe_cmdline );
261 
262  buffer = real_to_user ( file_cmdline->Buffer.segment,
263  file_cmdline->Buffer.offset );
264  len = file_cmdline->BufferSize;
265  max_len = ( pxe_cmdline ?
266  ( strlen ( pxe_cmdline ) + 1 /* NUL */ ) : 0 );
267  if ( len > max_len )
268  len = max_len;
270  file_cmdline->BufferSize = max_len;
271 
272  file_cmdline->Status = PXENV_STATUS_SUCCESS;
273  return PXENV_EXIT_SUCCESS;
274 }
275 
276 /**
277  * FILE API CHECK
278  *
279  * @v file_exec Pointer to a struct s_PXENV_FILE_API_CHECK
280  * @v s_PXENV_FILE_API_CHECK::Magic Inbound magic number (0x91d447b2)
281  * @ret #PXENV_EXIT_SUCCESS Command was executed successfully
282  * @ret #PXENV_EXIT_FAILURE Command was not executed successfully
283  * @ret s_PXENV_FILE_API_CHECK::Status PXE status code
284  * @ret s_PXENV_FILE_API_CHECK::Magic Outbound magic number (0xe9c17b20)
285  * @ret s_PXENV_FILE_API_CHECK::Provider "iPXE" (0x45585067)
286  * @ret s_PXENV_FILE_API_CHECK::APIMask API function bitmask
287  * @ret s_PXENV_FILE_API_CHECK::Flags Reserved
288  *
289  */
290 static PXENV_EXIT_t
291 pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check ) {
292  struct pxe_api_call *call;
293  unsigned int mask = 0;
294  unsigned int offset;
295 
296  DBG ( "PXENV_FILE_API_CHECK" );
297 
298  /* Check for magic value */
299  if ( file_api_check->Magic != 0x91d447b2 ) {
300  file_api_check->Status = PXENV_STATUS_BAD_FUNC;
301  return PXENV_EXIT_FAILURE;
302  }
303 
304  /* Check for required parameter size */
305  if ( file_api_check->Size < sizeof ( *file_api_check ) ) {
306  file_api_check->Status = PXENV_STATUS_OUT_OF_RESOURCES;
307  return PXENV_EXIT_FAILURE;
308  }
309 
310  /* Determine supported calls */
312  offset = ( call->opcode - PXENV_FILE_MIN );
313  if ( offset <= ( PXENV_FILE_MAX - PXENV_FILE_MIN ) )
314  mask |= ( 1 << offset );
315  }
316 
317  /* Fill in parameters */
318  file_api_check->Size = sizeof ( *file_api_check );
319  file_api_check->Magic = 0xe9c17b20;
320  file_api_check->Provider = 0x45585067; /* "iPXE" */
321  file_api_check->APIMask = mask;
322  file_api_check->Flags = 0; /* None defined */
323 
324  file_api_check->Status = PXENV_STATUS_SUCCESS;
325  return PXENV_EXIT_SUCCESS;
326 }
327 
328 /** PXE file API */
329 struct pxe_api_call pxe_file_api[] __pxe_api_call = {
331  struct s_PXENV_FILE_OPEN ),
333  struct s_PXENV_FILE_CLOSE ),
335  struct s_PXENV_FILE_SELECT ),
337  struct s_PXENV_FILE_READ ),
339  struct s_PXENV_GET_FILE_SIZE ),
341  struct s_PXENV_FILE_EXEC ),
343  struct s_PXENV_FILE_CMDLINE ),
345  struct s_PXENV_FILE_API_CHECK ),
346 };
#define PXENV_FILE_CMDLINE
PXE API function code for pxenv_file_cmdline()
Definition: pxe_api.h:1706
#define PXENV_STATUS_OUT_OF_RESOURCES
Definition: pxe_error.h:25
#define PXENV_FILE_SELECT
PXE API function code for pxenv_file_select()
Definition: pxe_api.h:1575
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define RDY_READ
File is ready for reading.
Definition: pxe_api.h:1578
device command_len
Definition: threewire.h:59
#define PXENV_EXIT_FAILURE
An error occurred.
Definition: pxe_types.h:46
UINT32_t Provider
Implementation identifier.
Definition: pxe_api.h:1669
SEGOFF16_t Buffer
Data buffer.
Definition: pxe_api.h:1712
UINT16_t BufferSize
Data buffer size.
Definition: pxe_api.h:1711
UINT16_t FileHandle
File handle.
Definition: pxe_api.h:1626
#define DHCP_EB_FEATURE_PXE_EXT
PXE API extensions.
Definition: features.h:36
#define PXENV_FILE_READ
PXE API function code for pxenv_file_read()
Definition: pxe_api.h:1599
static PXENV_EXIT_t pxenv_file_api_check(struct s_PXENV_FILE_API_CHECK *file_api_check)
FILE API CHECK.
Definition: pxe_file.c:291
Error codes.
static PXENV_EXIT_t pxenv_file_open(struct s_PXENV_FILE_OPEN *file_open)
FILE OPEN.
Definition: pxe_file.c:55
static PXENV_EXIT_t pxenv_file_select(struct s_PXENV_FILE_SELECT *file_select)
FILE SELECT.
Definition: pxe_file.c:118
A command-line command.
Definition: command.h:9
#define PXENV_FILE_CLOSE
PXE API function code for pxenv_file_close()
Definition: pxe_api.h:1555
uint16_t max_len
Maximum length (in bytes)
Definition: ntlm.h:18
ssize_t read_user(int fd, userptr_t buffer, off_t offset, size_t max_len)
Read data from file.
Definition: posix_io.c:265
static __always_inline void copy_from_user(void *dest, userptr_t src, off_t src_off, size_t len)
Copy data from user buffer.
Definition: uaccess.h:337
Parameter block for pxenv_file_close()
Definition: pxe_api.h:1558
#define PXENV_GET_FILE_SIZE
PXE API function code for pxenv_get_file_size()
Definition: pxe_api.h:1621
#define PXENV_STATUS_BAD_FUNC
Definition: pxe_error.h:21
int file_open(const char *filename)
PXENV_STATUS_t Status
PXE status code.
Definition: pxe_api.h:1710
uint32_t buffer
Buffer index (or NETVSC_RNDIS_NO_BUFFER)
Definition: netvsc.h:16
#define PXENV_FILE_API_CHECK
PXE API function code for pxenv_file_api_check()
Definition: pxe_api.h:1662
PXENV_STATUS_t Status
PXE status code.
Definition: pxe_api.h:1666
Access to external ("user") memory.
UINT16_t FileHandle
File handle.
Definition: pxe_api.h:1560
PXENV_STATUS_t Status
PXE status code.
Definition: pxe_api.h:1582
#define PXE_API_CALL(_opcode, _entry, _params_type)
Define a PXE API call.
Definition: pxe.h:108
Parameter block for pxenv_file_api_check()
Definition: pxe_api.h:1665
static PXENV_EXIT_t pxenv_file_close(struct s_PXENV_FILE_CLOSE *file_close)
FILE CLOSE.
Definition: pxe_file.c:97
ssize_t fsize(int fd)
Determine file size.
Definition: posix_io.c:311
Parameter block for pxenv_file_select()
Definition: pxe_api.h:1581
UINT16_t PXENV_EXIT_t
A PXE exit code.
Definition: pxe_types.h:44
UINT32_t Flags
Reserved for the future.
Definition: pxe_api.h:1671
#define PXENV_FILE_EXEC
PXE API function code for pxenv_file_exec()
Definition: pxe_api.h:1642
#define PXE_API_CALLS
PXE API call table.
Definition: pxe.h:95
struct pxe_api_call pxe_file_api [] __pxe_api_call
PXE file API.
Definition: pxe_file.c:329
const char * pxe_cmdline
PXE command line.
Definition: pxe_image.c:48
Parameter block for pxenv_get_file_size()
Definition: pxe_api.h:1624
UINT16_t Ready
Indication of readiness.
Definition: pxe_api.h:1584
static userptr_t size_t offset
Offset of the first segment within the content.
Definition: deflate.h:259
Parameter block for pxenv_file_exec()
Definition: pxe_api.h:1645
Feature list.
UINT16_t FileHandle
File handle.
Definition: pxe_api.h:1583
UINT32_t Magic
Magic number.
Definition: pxe_api.h:1668
PXENV_STATUS_t Status
PXE status code.
Definition: pxe_api.h:1625
uint32_t fd_set
File descriptor set as used for select()
Definition: posix_io.h:22
#define FEATURE_MISC
Miscellaneous.
Definition: features.h:23
SEGOFF16_t Command
Command to execute.
Definition: pxe_api.h:1647
FEATURE(FEATURE_MISC, "PXEXT", DHCP_EB_FEATURE_PXE_EXT, 2)
int file_read(void *buf, unsigned long len)
static PXENV_EXIT_t pxenv_file_exec(struct s_PXENV_FILE_EXEC *file_exec)
FILE EXEC.
Definition: pxe_file.c:212
static __always_inline void copy_to_user(userptr_t dest, off_t dest_off, const void *src, size_t len)
Copy data to user buffer.
Definition: uaccess.h:324
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:385
size_t strlen(const char *src)
Get length of string.
Definition: string.c:243
int select(fd_set *readfds, int wait)
Check file descriptors for readiness.
Definition: posix_io.c:229
Parameter block for pxenv_file_cmdline()
Definition: pxe_api.h:1709
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
static int command
Definition: epic100.c:68
uint16_t opcode
Opcode.
Definition: pxe.h:91
#define PXENV_EXIT_SUCCESS
No error occurred.
Definition: pxe_types.h:45
UINT32_t APIMask
Supported API functions.
Definition: pxe_api.h:1670
size_t strlen_user(userptr_t userptr, off_t offset)
Find length of NUL-terminated string in user buffer.
static PXENV_EXIT_t pxenv_file_read(struct s_PXENV_FILE_READ *file_read)
FILE READ.
Definition: pxe_file.c:150
Parameter block for pxenv_file_open()
Definition: pxe_api.h:1536
uint32_t len
Length.
Definition: ena.h:14
A PXE API call.
Definition: pxe.h:81
UINT16_t Size
Size of structure.
Definition: pxe_api.h:1667
#define PXENV_FILE_MAX
Minimum possible opcode used within PXE FILE API.
Definition: pxe_api.h:1523
#define PXENV_FILE_OPEN
PXE API function code for pxenv_file_open()
Definition: pxe_api.h:1533
UINT32_t FileSize
File size.
Definition: pxe_api.h:1627
#define PXENV_FILE_MIN
Minimum possible opcode used within PXE FILE API.
Definition: pxe_api.h:1520
int open(const char *uri_string)
Open file.
Definition: posix_io.c:176
PXENV_STATUS_t Status
PXE status code.
Definition: pxe_api.h:1559
PXENV_STATUS_t Status
PXE status code.
Definition: pxe_api.h:1646
static __always_inline userptr_t real_to_user(unsigned int segment, unsigned int offset)
Convert segment:offset address to user buffer.
Definition: realmode.h:75
Parameter block for pxenv_file_read()
Definition: pxe_api.h:1602
signed long ssize_t
Definition: stdint.h:7
static struct evtchn_close * close
Definition: xenevent.h:23
#define PXENV_STATUS_SUCCESS
Definition: pxe_error.h:19
POSIX-like I/O.
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
static PXENV_EXIT_t pxenv_get_file_size(struct s_PXENV_GET_FILE_SIZE *get_file_size)
GET FILE SIZE.
Definition: pxe_file.c:184
#define PXENV_STATUS(rc)
Derive PXENV_STATUS code from iPXE error number.
Definition: pxe_error.h:121
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33
uint8_t system[ETH_ALEN]
System identifier.
Definition: eth_slow.h:24
static PXENV_EXIT_t pxenv_file_cmdline(struct s_PXENV_FILE_CMDLINE *file_cmdline)
FILE CMDLINE.
Definition: pxe_file.c:253