@@ -2,14 +2,14 @@ use super::{
2
2
common:: { self , status_to_io_error} ,
3
3
unsupported,
4
4
} ;
5
- use crate :: error:: Error as StdError ;
6
5
use crate :: ffi:: { OsStr , OsString } ;
7
6
use crate :: fmt;
8
7
use crate :: io;
9
8
use crate :: marker:: PhantomData ;
10
9
use crate :: os:: uefi;
11
10
use crate :: os:: uefi:: ffi:: OsStrExt ;
12
11
use crate :: path:: { self , PathBuf } ;
12
+ use crate :: { error:: Error as StdError , os:: uefi:: ffi:: OsStringExt } ;
13
13
14
14
// Return EFI_ABORTED as Status
15
15
pub fn errno ( ) -> i32 {
@@ -84,31 +84,65 @@ pub fn current_exe() -> io::Result<PathBuf> {
84
84
}
85
85
86
86
// FIXME: Implement using Variable Services
87
- pub struct Env ( !) ;
87
+ pub struct Env {
88
+ last_var_name : Vec < u16 > ,
89
+ last_var_guid : r_efi:: efi:: Guid ,
90
+ }
88
91
89
92
impl Iterator for Env {
90
93
type Item = ( OsString , OsString ) ;
91
94
fn next ( & mut self ) -> Option < ( OsString , OsString ) > {
92
- self . 0
95
+ let mut key = self . last_var_name . clone ( ) ;
96
+ // Only Read Shell and Rust variables. UEFI variables can be random bytes of data and so
97
+ // not much point in reading anything else in Env context.
98
+ let val = match self . last_var_guid {
99
+ uefi_vars:: RUST_VARIABLE_GUID => {
100
+ uefi_vars:: get_variable_utf8 ( & mut key, uefi_vars:: RUST_VARIABLE_GUID )
101
+ }
102
+ uefi_vars:: SHELL_VARIABLE_GUID => {
103
+ uefi_vars:: get_variable_ucs2 ( & mut key, self . last_var_guid )
104
+ }
105
+ _ => None ,
106
+ } ;
107
+ let ( k, g) =
108
+ uefi_vars:: get_next_variable_name ( & self . last_var_name , & self . last_var_guid ) . ok ( ) ?;
109
+ self . last_var_guid = g;
110
+ self . last_var_name = k;
111
+ match val {
112
+ None => self . next ( ) ,
113
+ Some ( x) => Some ( ( OsString :: from_ucs2_lossy ( & key) , x) ) ,
114
+ }
93
115
}
94
116
}
95
117
96
118
pub fn env ( ) -> Env {
97
- panic ! ( "not supported on this platform" )
119
+ // The Guid should be ignored, so just passing anything
120
+ let ( key, guid) =
121
+ uefi_vars:: get_next_variable_name ( & [ 0 ] , & uefi_vars:: RUST_VARIABLE_GUID ) . unwrap ( ) ;
122
+ Env { last_var_name : key, last_var_guid : guid }
98
123
}
99
124
125
+ // Tries to get variable from bot RUST_VARIABLE_GUID and SHELL_VARIABLE_GUID. Precedence:
126
+ // RUST_VARIABLE_GUID > SHELL_VARIABLE_GUID
100
127
pub fn getenv ( key : & OsStr ) -> Option < OsString > {
101
- uefi_vars:: get_variable ( key)
128
+ let mut k = key. to_ffi_string ( ) ;
129
+ if let Some ( x) = uefi_vars:: get_variable_utf8 ( & mut k, uefi_vars:: RUST_VARIABLE_GUID ) {
130
+ Some ( x)
131
+ } else {
132
+ uefi_vars:: get_variable_ucs2 ( & mut k, uefi_vars:: SHELL_VARIABLE_GUID )
133
+ }
102
134
}
103
135
136
+ // Only possible to set variable to RUST_VARIABLE_GUID
104
137
pub fn setenv ( key : & OsStr , val : & OsStr ) -> io:: Result < ( ) > {
105
138
// Setting a variable with null value is same as unsetting it in UEFI
106
139
if val. is_empty ( ) {
107
140
unsetenv ( key)
108
141
} else {
109
142
unsafe {
110
- uefi_vars:: set_variable (
143
+ uefi_vars:: set_variable_raw (
111
144
key. to_ffi_string ( ) . as_mut_ptr ( ) ,
145
+ uefi_vars:: RUST_VARIABLE_GUID ,
112
146
val. len ( ) ,
113
147
val. bytes ( ) . as_ptr ( ) as * mut crate :: ffi:: c_void ,
114
148
)
@@ -118,7 +152,12 @@ pub fn setenv(key: &OsStr, val: &OsStr) -> io::Result<()> {
118
152
119
153
pub fn unsetenv ( key : & OsStr ) -> io:: Result < ( ) > {
120
154
match unsafe {
121
- uefi_vars:: set_variable ( key. to_ffi_string ( ) . as_mut_ptr ( ) , 0 , crate :: ptr:: null_mut ( ) )
155
+ uefi_vars:: set_variable_raw (
156
+ key. to_ffi_string ( ) . as_mut_ptr ( ) ,
157
+ uefi_vars:: RUST_VARIABLE_GUID ,
158
+ 0 ,
159
+ crate :: ptr:: null_mut ( ) ,
160
+ )
122
161
} {
123
162
Ok ( _) => Ok ( ( ) ) ,
124
163
Err ( e) => match e. kind ( ) {
@@ -163,13 +202,14 @@ pub fn getpid() -> u32 {
163
202
pub ( crate ) mod uefi_vars {
164
203
// It is possible to directly store and use UTF-8 data. So no need to convert to and from UCS-2
165
204
use super :: super :: common:: { self , status_to_io_error} ;
166
- use crate :: ffi:: { OsStr , OsString } ;
205
+ use crate :: ffi:: OsString ;
167
206
use crate :: io;
207
+ use crate :: mem:: size_of;
168
208
use crate :: os:: uefi;
169
- use crate :: os:: uefi:: ffi:: OsStrExt ;
209
+ use crate :: os:: uefi:: ffi:: OsStringExt ;
170
210
171
211
// Using Shell Variable Guid from edk2/ShellPkg
172
- const SHELL_VARIABLE_GUID : r_efi:: efi:: Guid = r_efi:: efi:: Guid :: from_fields (
212
+ pub const SHELL_VARIABLE_GUID : r_efi:: efi:: Guid = r_efi:: efi:: Guid :: from_fields (
173
213
0x158def5a ,
174
214
0xf656 ,
175
215
0x419c ,
@@ -178,14 +218,91 @@ pub(crate) mod uefi_vars {
178
218
& [ 0x7a , 0x31 , 0x92 , 0xc0 , 0x79 , 0xd2 ] ,
179
219
) ;
180
220
181
- pub ( crate ) unsafe fn set_variable (
221
+ pub const RUST_VARIABLE_GUID : r_efi:: efi:: Guid = r_efi:: efi:: Guid :: from_fields (
222
+ 0x49bb4029 ,
223
+ 0x7d2b ,
224
+ 0x4bf7 ,
225
+ 0xa1 ,
226
+ 0x95 ,
227
+ & [ 0x0f , 0x18 , 0xa1 , 0xa8 , 0x85 , 0xc9 ] ,
228
+ ) ;
229
+
230
+ pub fn get_variable_utf8 ( key : & mut [ u16 ] , guid : r_efi:: efi:: Guid ) -> Option < OsString > {
231
+ let mut buf_size = 0 ;
232
+
233
+ if let Err ( e) = unsafe {
234
+ get_vaiable_raw ( key. as_mut_ptr ( ) , guid, & mut buf_size, crate :: ptr:: null_mut ( ) )
235
+ } {
236
+ if e. kind ( ) != io:: ErrorKind :: FileTooLarge {
237
+ return None ;
238
+ }
239
+ }
240
+
241
+ let mut buf: Vec < u8 > = Vec :: with_capacity ( buf_size) ;
242
+ unsafe {
243
+ get_vaiable_raw ( key. as_mut_ptr ( ) , guid, & mut buf_size, buf. as_mut_ptr ( ) . cast ( ) ) . ok ( )
244
+ } ?;
245
+
246
+ unsafe { buf. set_len ( buf_size) } ;
247
+ Some ( OsString :: from ( String :: from_utf8 ( buf) . ok ( ) ?) )
248
+ }
249
+
250
+ pub fn get_variable_ucs2 ( key : & mut [ u16 ] , guid : r_efi:: efi:: Guid ) -> Option < OsString > {
251
+ let mut buf_size = 0 ;
252
+
253
+ if let Err ( e) = unsafe {
254
+ get_vaiable_raw ( key. as_mut_ptr ( ) , guid, & mut buf_size, crate :: ptr:: null_mut ( ) )
255
+ } {
256
+ if e. kind ( ) != io:: ErrorKind :: FileTooLarge {
257
+ return None ;
258
+ }
259
+ }
260
+
261
+ let mut buf: Vec < u16 > = Vec :: with_capacity ( buf_size / size_of :: < u16 > ( ) ) ;
262
+ unsafe {
263
+ get_vaiable_raw ( key. as_mut_ptr ( ) , guid, & mut buf_size, buf. as_mut_ptr ( ) . cast ( ) ) . ok ( )
264
+ } ?;
265
+
266
+ unsafe { buf. set_len ( buf_size / size_of :: < u16 > ( ) ) } ;
267
+ Some ( OsString :: from_ucs2_lossy ( & buf) )
268
+ }
269
+
270
+ pub fn get_next_variable_name (
271
+ last_var_name : & [ u16 ] ,
272
+ last_guid : & r_efi:: efi:: Guid ,
273
+ ) -> io:: Result < ( Vec < u16 > , r_efi:: efi:: Guid ) > {
274
+ let mut var_name = Vec :: from ( last_var_name) ;
275
+ let mut var_size = var_name. capacity ( ) * size_of :: < u16 > ( ) ;
276
+ let mut guid: r_efi:: efi:: Guid = * last_guid;
277
+ match unsafe { get_next_variable_raw ( & mut var_size, var_name. as_mut_ptr ( ) , & mut guid) } {
278
+ Ok ( _) => {
279
+ unsafe { var_name. set_len ( var_size / size_of :: < u16 > ( ) ) } ;
280
+ return Ok ( ( var_name, guid) ) ;
281
+ }
282
+ Err ( e) => {
283
+ if e. kind ( ) != io:: ErrorKind :: FileTooLarge {
284
+ return Err ( e) ;
285
+ }
286
+ }
287
+ }
288
+
289
+ var_name. reserve ( var_size - ( var_name. capacity ( ) * size_of :: < u16 > ( ) ) ) ;
290
+ var_size = var_name. capacity ( ) * size_of :: < u16 > ( ) ;
291
+
292
+ unsafe { get_next_variable_raw ( & mut var_size, var_name. as_mut_ptr ( ) , & mut guid) } ?;
293
+
294
+ unsafe { var_name. set_len ( var_size / size_of :: < u16 > ( ) ) } ;
295
+ Ok ( ( var_name, guid) )
296
+ }
297
+
298
+ pub unsafe fn set_variable_raw (
182
299
variable_name : * mut u16 ,
300
+ mut guid : r_efi:: efi:: Guid ,
183
301
data_size : usize ,
184
302
data : * mut crate :: ffi:: c_void ,
185
303
) -> io:: Result < ( ) > {
186
304
let runtime_services =
187
305
uefi:: env:: get_runtime_services ( ) . ok_or ( common:: RUNTIME_SERVICES_ERROR ) ?;
188
- let mut guid = SHELL_VARIABLE_GUID ;
189
306
let r = unsafe {
190
307
( ( * runtime_services. as_ptr ( ) ) . set_variable ) (
191
308
variable_name,
@@ -198,34 +315,14 @@ pub(crate) mod uefi_vars {
198
315
if r. is_error ( ) { Err ( status_to_io_error ( r) ) } else { Ok ( ( ) ) }
199
316
}
200
317
201
- pub ( crate ) fn get_variable ( key : & OsStr ) -> Option < OsString > {
202
- let mut buf_size = 0 ;
203
- let mut key_buf = key. to_ffi_string ( ) ;
204
-
205
- if let Err ( e) =
206
- unsafe { get_vaiable_raw ( key_buf. as_mut_ptr ( ) , & mut buf_size, crate :: ptr:: null_mut ( ) ) }
207
- {
208
- if e. kind ( ) != io:: ErrorKind :: FileTooLarge {
209
- return None ;
210
- }
211
- }
212
-
213
- let mut buf: Vec < u8 > = Vec :: with_capacity ( buf_size) ;
214
- unsafe { get_vaiable_raw ( key_buf. as_mut_ptr ( ) , & mut buf_size, buf. as_mut_ptr ( ) . cast ( ) ) }
215
- . ok ( ) ?;
216
-
217
- unsafe { buf. set_len ( buf_size) } ;
218
- Some ( OsString :: from ( String :: from_utf8 ( buf) . ok ( ) ?) )
219
- }
220
-
221
318
unsafe fn get_vaiable_raw (
222
319
key : * mut u16 ,
320
+ mut guid : r_efi:: efi:: Guid ,
223
321
data_size : & mut usize ,
224
322
data : * mut crate :: ffi:: c_void ,
225
323
) -> io:: Result < ( ) > {
226
324
let runtime_services =
227
325
uefi:: env:: get_runtime_services ( ) . ok_or ( common:: RUNTIME_SERVICES_ERROR ) ?;
228
- let mut guid = SHELL_VARIABLE_GUID ;
229
326
let r = unsafe {
230
327
( ( * runtime_services. as_ptr ( ) ) . get_variable ) (
231
328
key,
@@ -237,4 +334,21 @@ pub(crate) mod uefi_vars {
237
334
} ;
238
335
if r. is_error ( ) { Err ( status_to_io_error ( r) ) } else { Ok ( ( ) ) }
239
336
}
337
+
338
+ unsafe fn get_next_variable_raw (
339
+ variable_name_size : * mut usize ,
340
+ variable_name : * mut u16 ,
341
+ vendor_guid : * mut r_efi:: efi:: Guid ,
342
+ ) -> io:: Result < ( ) > {
343
+ let runtime_services =
344
+ uefi:: env:: get_runtime_services ( ) . ok_or ( common:: RUNTIME_SERVICES_ERROR ) ?;
345
+ let r = unsafe {
346
+ ( ( * runtime_services. as_ptr ( ) ) . get_next_variable_name ) (
347
+ variable_name_size,
348
+ variable_name,
349
+ vendor_guid,
350
+ )
351
+ } ;
352
+ if r. is_error ( ) { Err ( status_to_io_error ( r) ) } else { Ok ( ( ) ) }
353
+ }
240
354
}
0 commit comments