• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <gpxe/uaccess.h>
12 #include <gpxe/posix_io.h>
13 #include <gpxe/features.h>
14 #include <pxe.h>
15 #include <realmode.h>
16 
17 /*
18  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
19  * Portions (C) 2010 Shao Miller <shao.miller@yrdsb.edu.on.ca>.
20  *              [PXE exit hook logic]
21  *
22  * This program is free software; you can redistribute it and/or
23  * modify it under the terms of the GNU General Public License as
24  * published by the Free Software Foundation; either version 2 of the
25  * License, or any later version.
26  *
27  * This program is distributed in the hope that it will be useful, but
28  * WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
30  * General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License
33  * along with this program; if not, write to the Free Software
34  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35  */
36 
37 FILE_LICENCE ( GPL2_OR_LATER );
38 
39 FEATURE ( FEATURE_MISC, "PXEXT", DHCP_EB_FEATURE_PXE_EXT, 2 );
40 
41 /**
42  * FILE OPEN
43  *
44  * @v file_open				Pointer to a struct s_PXENV_FILE_OPEN
45  * @v s_PXENV_FILE_OPEN::FileName	URL of file to open
46  * @ret #PXENV_EXIT_SUCCESS		File was opened
47  * @ret #PXENV_EXIT_FAILURE		File was not opened
48  * @ret s_PXENV_FILE_OPEN::Status	PXE status code
49  * @ret s_PXENV_FILE_OPEN::FileHandle	Handle of opened file
50  *
51  */
pxenv_file_open(struct s_PXENV_FILE_OPEN * file_open)52 PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ) {
53 	userptr_t filename;
54 	size_t filename_len;
55 	int fd;
56 
57 	DBG ( "PXENV_FILE_OPEN" );
58 
59 	/* Copy name from external program, and open it */
60 	filename = real_to_user ( file_open->FileName.segment,
61 			      file_open->FileName.offset );
62 	filename_len = strlen_user ( filename, 0 );
63 	{
64 		char uri_string[ filename_len + 1 ];
65 
66 		copy_from_user ( uri_string, filename, 0,
67 				 sizeof ( uri_string ) );
68 		DBG ( " %s", uri_string );
69 		fd = open ( uri_string );
70 	}
71 
72 	if ( fd < 0 ) {
73 		file_open->Status = PXENV_STATUS ( fd );
74 		return PXENV_EXIT_FAILURE;
75 	}
76 
77 	DBG ( " as file %d", fd );
78 
79 	file_open->FileHandle = fd;
80 	file_open->Status = PXENV_STATUS_SUCCESS;
81 	return PXENV_EXIT_SUCCESS;
82 }
83 
84 /**
85  * FILE CLOSE
86  *
87  * @v file_close			Pointer to a struct s_PXENV_FILE_CLOSE
88  * @v s_PXENV_FILE_CLOSE::FileHandle	File handle
89  * @ret #PXENV_EXIT_SUCCESS		File was closed
90  * @ret #PXENV_EXIT_FAILURE		File was not closed
91  * @ret s_PXENV_FILE_CLOSE::Status	PXE status code
92  *
93  */
pxenv_file_close(struct s_PXENV_FILE_CLOSE * file_close)94 PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE *file_close ) {
95 
96 	DBG ( "PXENV_FILE_CLOSE %d", file_close->FileHandle );
97 
98 	close ( file_close->FileHandle );
99 	file_close->Status = PXENV_STATUS_SUCCESS;
100 	return PXENV_EXIT_SUCCESS;
101 }
102 
103 /**
104  * FILE SELECT
105  *
106  * @v file_select			Pointer to a struct s_PXENV_FILE_SELECT
107  * @v s_PXENV_FILE_SELECT::FileHandle	File handle
108  * @ret #PXENV_EXIT_SUCCESS		File has been checked for readiness
109  * @ret #PXENV_EXIT_FAILURE		File has not been checked for readiness
110  * @ret s_PXENV_FILE_SELECT::Status	PXE status code
111  * @ret s_PXENV_FILE_SELECT::Ready	Indication of readiness
112  *
113  */
pxenv_file_select(struct s_PXENV_FILE_SELECT * file_select)114 PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT *file_select ) {
115 	fd_set fdset;
116 	int ready;
117 
118 	DBG ( "PXENV_FILE_SELECT %d", file_select->FileHandle );
119 
120 	FD_ZERO ( &fdset );
121 	FD_SET ( file_select->FileHandle, &fdset );
122 	if ( ( ready = select ( &fdset, 0 ) ) < 0 ) {
123 		file_select->Status = PXENV_STATUS ( ready );
124 		return PXENV_EXIT_FAILURE;
125 	}
126 
127 	file_select->Ready = ( ready ? RDY_READ : 0 );
128 	file_select->Status = PXENV_STATUS_SUCCESS;
129 	return PXENV_EXIT_SUCCESS;
130 }
131 
132 /**
133  * FILE READ
134  *
135  * @v file_read				Pointer to a struct s_PXENV_FILE_READ
136  * @v s_PXENV_FILE_READ::FileHandle	File handle
137  * @v s_PXENV_FILE_READ::BufferSize	Size of data buffer
138  * @v s_PXENV_FILE_READ::Buffer		Data buffer
139  * @ret #PXENV_EXIT_SUCCESS		Data has been read from file
140  * @ret #PXENV_EXIT_FAILURE		Data has not been read from file
141  * @ret s_PXENV_FILE_READ::Status	PXE status code
142  * @ret s_PXENV_FILE_READ::Ready	Indication of readiness
143  * @ret s_PXENV_FILE_READ::BufferSize	Length of data read
144  *
145  */
pxenv_file_read(struct s_PXENV_FILE_READ * file_read)146 PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read ) {
147 	userptr_t buffer;
148 	ssize_t len;
149 
150 	DBG ( "PXENV_FILE_READ %d to %04x:%04x+%04x", file_read->FileHandle,
151 	      file_read->Buffer.segment, file_read->Buffer.offset,
152 	      file_read->BufferSize );
153 
154 	buffer = real_to_user ( file_read->Buffer.segment,
155 				file_read->Buffer.offset );
156 	if ( ( len = read_user ( file_read->FileHandle, buffer, 0,
157 				file_read->BufferSize ) ) < 0 ) {
158 		file_read->Status = PXENV_STATUS ( len );
159 		return PXENV_EXIT_FAILURE;
160 	}
161 
162 	DBG ( " read %04zx", ( ( size_t ) len ) );
163 
164 	file_read->BufferSize = len;
165 	file_read->Status = PXENV_STATUS_SUCCESS;
166 	return PXENV_EXIT_SUCCESS;
167 }
168 
169 /**
170  * GET FILE SIZE
171  *
172  * @v get_file_size			Pointer to a struct s_PXENV_GET_FILE_SIZE
173  * @v s_PXENV_GET_FILE_SIZE::FileHandle	File handle
174  * @ret #PXENV_EXIT_SUCCESS		File size has been determined
175  * @ret #PXENV_EXIT_FAILURE		File size has not been determined
176  * @ret s_PXENV_GET_FILE_SIZE::Status	PXE status code
177  * @ret s_PXENV_GET_FILE_SIZE::FileSize	Size of file
178  */
pxenv_get_file_size(struct s_PXENV_GET_FILE_SIZE * get_file_size)179 PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE
180 				   *get_file_size ) {
181 	ssize_t filesize;
182 
183 	DBG ( "PXENV_GET_FILE_SIZE %d", get_file_size->FileHandle );
184 
185 	filesize = fsize ( get_file_size->FileHandle );
186 	if ( filesize < 0 ) {
187 		get_file_size->Status = PXENV_STATUS ( filesize );
188 		return PXENV_EXIT_FAILURE;
189 	}
190 
191 	DBG ( " is %zd", ( ( size_t ) filesize ) );
192 
193 	get_file_size->FileSize = filesize;
194 	get_file_size->Status = PXENV_STATUS_SUCCESS;
195 	return PXENV_EXIT_SUCCESS;
196 }
197 
198 /**
199  * FILE EXEC
200  *
201  * @v file_exec				Pointer to a struct s_PXENV_FILE_EXEC
202  * @v s_PXENV_FILE_EXEC::Command	Command to execute
203  * @ret #PXENV_EXIT_SUCCESS		Command was executed successfully
204  * @ret #PXENV_EXIT_FAILURE		Command was not executed successfully
205  * @ret s_PXENV_FILE_EXEC::Status	PXE status code
206  *
207  */
pxenv_file_exec(struct s_PXENV_FILE_EXEC * file_exec)208 PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ) {
209 	userptr_t command;
210 	size_t command_len;
211 	int rc;
212 
213 	DBG ( "PXENV_FILE_EXEC" );
214 
215 	/* Copy name from external program, and exec it */
216 	command = real_to_user ( file_exec->Command.segment,
217 				 file_exec->Command.offset );
218 	command_len = strlen_user ( command, 0 );
219 	{
220 		char command_string[ command_len + 1 ];
221 
222 		copy_from_user ( command_string, command, 0,
223 				 sizeof ( command_string ) );
224 		DBG ( " %s", command_string );
225 
226 		if ( ( rc = system ( command_string ) ) != 0 ) {
227 			file_exec->Status = PXENV_STATUS ( rc );
228 			return PXENV_EXIT_FAILURE;
229 		}
230 	}
231 
232 	file_exec->Status = PXENV_STATUS_SUCCESS;
233 	return PXENV_EXIT_SUCCESS;
234 }
235 
236 segoff_t __data16 ( pxe_exit_hook ) = { 0, 0 };
237 #define pxe_exit_hook __use_data16 ( pxe_exit_hook )
238 
239 /**
240  * FILE API CHECK
241  *
242  * @v file_exec				Pointer to a struct s_PXENV_FILE_API_CHECK
243  * @v s_PXENV_FILE_API_CHECK::Magic     Inbound magic number (0x91d447b2)
244  * @ret #PXENV_EXIT_SUCCESS		Command was executed successfully
245  * @ret #PXENV_EXIT_FAILURE		Command was not executed successfully
246  * @ret s_PXENV_FILE_API_CHECK::Status	PXE status code
247  * @ret s_PXENV_FILE_API_CHECK::Magic	Outbound magic number (0xe9c17b20)
248  * @ret s_PXENV_FILE_API_CHECK::Provider "gPXE" (0x45585067)
249  * @ret s_PXENV_FILE_API_CHECK::APIMask API function bitmask
250  * @ret s_PXENV_FILE_API_CHECK::Flags	Reserved
251  *
252  */
pxenv_file_api_check(struct s_PXENV_FILE_API_CHECK * file_api_check)253 PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check ) {
254 	DBG ( "PXENV_FILE_API_CHECK" );
255 
256 	if ( file_api_check->Magic != 0x91d447b2 ) {
257 		file_api_check->Status = PXENV_STATUS_BAD_FUNC;
258 		return PXENV_EXIT_FAILURE;
259 	} else if ( file_api_check->Size <
260 		    sizeof(struct s_PXENV_FILE_API_CHECK) ) {
261 		file_api_check->Status = PXENV_STATUS_OUT_OF_RESOURCES;
262 		return PXENV_EXIT_FAILURE;
263 	} else {
264 		file_api_check->Status   = PXENV_STATUS_SUCCESS;
265 		file_api_check->Size     = sizeof(struct s_PXENV_FILE_API_CHECK);
266 		file_api_check->Magic    = 0xe9c17b20;
267 		file_api_check->Provider = 0x45585067; /* "gPXE" */
268 		file_api_check->APIMask  = 0x0000007f; /* Functions e0-e6 */
269 		/* Check to see if we have a PXE exit hook */
270 		if ( pxe_exit_hook.segment | pxe_exit_hook.offset )
271 			/* Function e7, also */
272 			file_api_check->APIMask |= 0x00000080;
273 		file_api_check->Flags    = 0;	       /* None defined */
274 		return PXENV_EXIT_SUCCESS;
275 	}
276 }
277 
278 /**
279  * FILE EXIT HOOK
280  *
281  * @v file_exit_hook			Pointer to a struct
282  *					s_PXENV_FILE_EXIT_HOOK
283  * @v s_PXENV_FILE_EXIT_HOOK::Hook	SEG16:OFF16 to jump to
284  * @ret #PXENV_EXIT_SUCCESS		Successfully set hook
285  * @ret #PXENV_EXIT_FAILURE		We're not an NBP build
286  * @ret s_PXENV_FILE_EXIT_HOOK::Status	PXE status code
287  *
288  */
pxenv_file_exit_hook(struct s_PXENV_FILE_EXIT_HOOK * file_exit_hook)289 PXENV_EXIT_t pxenv_file_exit_hook ( struct s_PXENV_FILE_EXIT_HOOK
290 					*file_exit_hook ) {
291 	DBG ( "PXENV_FILE_EXIT_HOOK" );
292 
293 	/* Check to see if we have a PXE exit hook */
294 	if ( pxe_exit_hook.segment | pxe_exit_hook.offset ) {
295 		/* We'll jump to the specified SEG16:OFF16 during exit */
296 		pxe_exit_hook.segment = file_exit_hook->Hook.segment;
297 		pxe_exit_hook.offset = file_exit_hook->Hook.offset;
298 		file_exit_hook->Status = PXENV_STATUS_SUCCESS;
299 		return PXENV_EXIT_SUCCESS;
300 	}
301 
302 	DBG ( " not NBP" );
303 	file_exit_hook->Status = PXENV_STATUS_UNSUPPORTED;
304 	return PXENV_EXIT_FAILURE;
305 }
306 
307