1 | // This module defines the `ComponentName1` type and marks it deprecated. That |
2 | // causes warnings for uses within this module (e.g. the `impl ComponentName1` |
3 | // block), so turn off deprecated warnings. It's not yet possible to make this |
4 | // allow more fine-grained, see https://github.com/rust-lang/rust/issues/62398. |
5 | #![allow (deprecated)] |
6 | |
7 | use crate::proto::unsafe_protocol ; |
8 | use crate::table::boot::{BootServices, ScopedProtocol}; |
9 | use crate::{CStr16, Error, Handle, Result, Status}; |
10 | use core::{ptr, slice}; |
11 | |
12 | /// Protocol that provides human-readable names for a driver and for each of the |
13 | /// controllers that the driver is managing. |
14 | /// |
15 | /// This protocol was deprecated in UEFI 2.1 in favor of the new |
16 | /// [`ComponentName2`] protocol. The two protocols are identical except the |
17 | /// encoding of supported languages changed from [ISO 639-2] to [RFC 4646]. The |
18 | /// [`ComponentName`] wrapper can be used to automatically select |
19 | /// [`ComponentName2`] if available, and otherwise fall back to |
20 | /// [`ComponentName1`]. |
21 | /// |
22 | /// The corresponding C type is `EFI_COMPONENT_NAME_PROTOCOL`. |
23 | /// |
24 | /// [ISO 639-2]: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes |
25 | /// [RFC 4646]: https://www.rfc-editor.org/rfc/rfc4646 |
26 | #[deprecated = "deprecated in UEFI 2.1; use ComponentName2 where possible" ] |
27 | #[unsafe_protocol ("107a772c-d5e1-11d4-9a46-0090273fc14d" )] |
28 | #[repr (C)] |
29 | pub struct ComponentName1 { |
30 | get_driver_name: unsafe extern "efiapi" fn( |
31 | this: *const Self, |
32 | language: *const u8, |
33 | driver_name: *mut *const u16, |
34 | ) -> Status, |
35 | get_controller_name: unsafe extern "efiapi" fn( |
36 | this: *const Self, |
37 | controller_handle: Handle, |
38 | child_handle: Option<Handle>, |
39 | language: *const u8, |
40 | controller_name: *mut *const u16, |
41 | ) -> Status, |
42 | supported_languages: *const u8, |
43 | } |
44 | |
45 | impl ComponentName1 { |
46 | /// Get an iterator over supported languages. Each language is identified by |
47 | /// a three-letter ASCII string specified in [ISO 639-2]. For example, |
48 | /// English is encoded as "eng". |
49 | /// |
50 | /// [ISO 639-2]: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes |
51 | pub fn supported_languages(&self) -> core::result::Result<LanguageIter, LanguageError> { |
52 | LanguageIter::new(self.supported_languages, LanguageIterKind::V1) |
53 | } |
54 | |
55 | /// Get the human-readable name of the driver in the given language. |
56 | /// |
57 | /// `language` must be one of the languages returned by [`supported_languages`]. |
58 | /// |
59 | /// [`supported_languages`]: Self::supported_languages |
60 | pub fn driver_name(&self, language: &str) -> Result<&CStr16> { |
61 | let language = language_to_cstr(language)?; |
62 | let mut driver_name = ptr::null(); |
63 | unsafe { (self.get_driver_name)(self, language.as_ptr(), &mut driver_name) } |
64 | .into_with_val(|| unsafe { CStr16::from_ptr(driver_name.cast()) }) |
65 | } |
66 | |
67 | /// Get the human-readable name of a controller in the given language. |
68 | /// |
69 | /// `language` must be one of the languages returned by [`supported_languages`]. |
70 | /// |
71 | /// [`supported_languages`]: Self::supported_languages |
72 | pub fn controller_name( |
73 | &self, |
74 | controller_handle: Handle, |
75 | child_handle: Option<Handle>, |
76 | language: &str, |
77 | ) -> Result<&CStr16> { |
78 | let language = language_to_cstr(language)?; |
79 | let mut driver_name = ptr::null(); |
80 | unsafe { |
81 | (self.get_controller_name)( |
82 | self, |
83 | controller_handle, |
84 | child_handle, |
85 | language.as_ptr(), |
86 | &mut driver_name, |
87 | ) |
88 | } |
89 | .into_with_val(|| unsafe { CStr16::from_ptr(driver_name.cast()) }) |
90 | } |
91 | } |
92 | |
93 | /// Protocol that provides human-readable names for a driver and for each of the |
94 | /// controllers that the driver is managing. |
95 | /// |
96 | /// This protocol was introduced in UEFI 2.1 to replace the now-deprecated |
97 | /// [`ComponentName1`] protocol. The two protocols are identical except the |
98 | /// encoding of supported languages changed from [ISO 639-2] to [RFC 4646]. The |
99 | /// [`ComponentName`] wrapper can be used to automatically select |
100 | /// [`ComponentName2`] if available, and otherwise fall back to |
101 | /// [`ComponentName1`]. |
102 | /// |
103 | /// The corresponding C type is `EFI_COMPONENT_NAME2_PROTOCOL`. |
104 | /// |
105 | /// [ISO 639-2]: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes |
106 | /// [RFC 4646]: https://www.rfc-editor.org/rfc/rfc4646 |
107 | #[unsafe_protocol ("6a7a5cff-e8d9-4f70-bada-75ab3025ce14" )] |
108 | #[repr (C)] |
109 | pub struct ComponentName2 { |
110 | get_driver_name: unsafe extern "efiapi" fn( |
111 | this: *const Self, |
112 | language: *const u8, |
113 | driver_name: *mut *const u16, |
114 | ) -> Status, |
115 | get_controller_name: unsafe extern "efiapi" fn( |
116 | this: *const Self, |
117 | controller_handle: Handle, |
118 | child_handle: Option<Handle>, |
119 | language: *const u8, |
120 | controller_name: *mut *const u16, |
121 | ) -> Status, |
122 | supported_languages: *const u8, |
123 | } |
124 | |
125 | impl ComponentName2 { |
126 | /// Get an iterator over supported languages. Each language is identified by |
127 | /// an ASCII string specified in [RFC 4646]. For example, English is encoded |
128 | /// as "en". |
129 | /// |
130 | /// [RFC 4646]: https://www.rfc-editor.org/rfc/rfc4646 |
131 | pub fn supported_languages(&self) -> core::result::Result<LanguageIter, LanguageError> { |
132 | LanguageIter::new(self.supported_languages, LanguageIterKind::V2) |
133 | } |
134 | |
135 | /// Get the human-readable name of the driver in the given language. |
136 | /// |
137 | /// `language` must be one of the languages returned by [`supported_languages`]. |
138 | /// |
139 | /// [`supported_languages`]: Self::supported_languages |
140 | pub fn driver_name(&self, language: &str) -> Result<&CStr16> { |
141 | let language = language_to_cstr(language)?; |
142 | let mut driver_name = ptr::null(); |
143 | unsafe { (self.get_driver_name)(self, language.as_ptr(), &mut driver_name) } |
144 | .into_with_val(|| unsafe { CStr16::from_ptr(driver_name.cast()) }) |
145 | } |
146 | |
147 | /// Get the human-readable name of a controller in the given language. |
148 | /// |
149 | /// `language` must be one of the languages returned by [`supported_languages`]. |
150 | /// |
151 | /// [`supported_languages`]: Self::supported_languages |
152 | pub fn controller_name( |
153 | &self, |
154 | controller_handle: Handle, |
155 | child_handle: Option<Handle>, |
156 | language: &str, |
157 | ) -> Result<&CStr16> { |
158 | let language = language_to_cstr(language)?; |
159 | let mut driver_name = ptr::null(); |
160 | unsafe { |
161 | (self.get_controller_name)( |
162 | self, |
163 | controller_handle, |
164 | child_handle, |
165 | language.as_ptr(), |
166 | &mut driver_name, |
167 | ) |
168 | } |
169 | .into_with_val(|| unsafe { CStr16::from_ptr(driver_name.cast()) }) |
170 | } |
171 | } |
172 | |
173 | /// Wrapper around [`ComponentName1`] and [`ComponentName2`]. This will use |
174 | /// [`ComponentName2`] if available, otherwise it will back to |
175 | /// [`ComponentName1`]. |
176 | pub enum ComponentName<'a> { |
177 | /// Opened [`ComponentName1`] protocol. |
178 | V1(ScopedProtocol<'a, ComponentName1>), |
179 | |
180 | /// Opened [`ComponentName2`] protocol. |
181 | V2(ScopedProtocol<'a, ComponentName2>), |
182 | } |
183 | |
184 | impl<'a> ComponentName<'a> { |
185 | /// Open the [`ComponentName2`] protocol if available, otherwise fall back to |
186 | /// [`ComponentName1`]. |
187 | pub fn open(boot_services: &'a BootServices, handle: Handle) -> Result<Self> { |
188 | if let Ok(cn2) = boot_services.open_protocol_exclusive::<ComponentName2>(handle) { |
189 | Ok(Self::V2(cn2)) |
190 | } else { |
191 | Ok(Self::V1( |
192 | boot_services.open_protocol_exclusive::<ComponentName1>(handle)?, |
193 | )) |
194 | } |
195 | } |
196 | |
197 | /// Get an iterator over supported languages. Each language is identified by |
198 | /// an ASCII string. If the opened protocol is [`ComponentName1`] this will |
199 | /// be an [ISO 639-2] string. If the opened protocol is [`ComponentName2`] |
200 | /// it will be an [RFC 4646] string. For example, English is encoded as |
201 | /// "eng" in ISO 639-2, and "en" in RFC 4646. |
202 | /// |
203 | /// [ISO 639-2]: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes |
204 | /// [RFC 4646]: https://www.rfc-editor.org/rfc/rfc4646 |
205 | pub fn supported_languages(&self) -> core::result::Result<LanguageIter, LanguageError> { |
206 | match self { |
207 | Self::V1(cn1) => cn1.supported_languages(), |
208 | Self::V2(cn2) => cn2.supported_languages(), |
209 | } |
210 | } |
211 | |
212 | /// Get the human-readable name of the driver in the given language. |
213 | /// |
214 | /// `language` must be one of the languages returned by [`supported_languages`]. |
215 | /// |
216 | /// [`supported_languages`]: Self::supported_languages |
217 | pub fn driver_name(&self, language: &str) -> Result<&CStr16> { |
218 | match self { |
219 | Self::V1(cn1) => cn1.driver_name(language), |
220 | Self::V2(cn2) => cn2.driver_name(language), |
221 | } |
222 | } |
223 | |
224 | /// Get the human-readable name of a controller in the given language. |
225 | /// |
226 | /// `language` must be one of the languages returned by [`supported_languages`]. |
227 | /// |
228 | /// [`supported_languages`]: Self::supported_languages |
229 | pub fn controller_name( |
230 | &self, |
231 | controller_handle: Handle, |
232 | child_handle: Option<Handle>, |
233 | language: &str, |
234 | ) -> Result<&CStr16> { |
235 | match self { |
236 | Self::V1(cn1) => cn1.controller_name(controller_handle, child_handle, language), |
237 | Self::V2(cn2) => cn2.controller_name(controller_handle, child_handle, language), |
238 | } |
239 | } |
240 | } |
241 | |
242 | /// Error returned by [`ComponentName1::supported_languages`] and |
243 | /// [`ComponentName2::supported_languages`]. |
244 | #[derive (Debug, Eq, PartialEq)] |
245 | pub enum LanguageError { |
246 | /// The supported languages list contains a non-ASCII character at the |
247 | /// specified index. |
248 | Ascii { |
249 | /// Index of the invalid character. |
250 | index: usize, |
251 | }, |
252 | } |
253 | |
254 | #[derive (PartialEq)] |
255 | enum LanguageIterKind { |
256 | V1, |
257 | V2, |
258 | } |
259 | |
260 | /// Iterator returned by [`ComponentName1::supported_languages`] and |
261 | /// [`ComponentName2::supported_languages`]. |
262 | pub struct LanguageIter<'a> { |
263 | languages: &'a [u8], |
264 | kind: LanguageIterKind, |
265 | } |
266 | |
267 | impl<'a> LanguageIter<'a> { |
268 | fn new( |
269 | languages: *const u8, |
270 | kind: LanguageIterKind, |
271 | ) -> core::result::Result<Self, LanguageError> { |
272 | let mut index: usize = 0; |
273 | loop { |
274 | let c: u8 = unsafe { languages.add(count:index).read() }; |
275 | if c == 0 { |
276 | break; |
277 | } else if !c.is_ascii() { |
278 | return Err(LanguageError::Ascii { index }); |
279 | } else { |
280 | index += 1; |
281 | } |
282 | } |
283 | |
284 | Ok(Self { |
285 | languages: unsafe { slice::from_raw_parts(data:languages, len:index) }, |
286 | kind, |
287 | }) |
288 | } |
289 | } |
290 | |
291 | impl<'a> Iterator for LanguageIter<'a> { |
292 | type Item = &'a str; |
293 | |
294 | fn next(&mut self) -> Option<Self::Item> { |
295 | if self.languages.is_empty() { |
296 | return None; |
297 | } |
298 | |
299 | let lang; |
300 | match self.kind { |
301 | LanguageIterKind::V1 => { |
302 | if self.languages.len() <= 3 { |
303 | lang = self.languages; |
304 | self.languages = &[]; |
305 | } else { |
306 | lang = &self.languages[..3]; |
307 | self.languages = &self.languages[3..]; |
308 | } |
309 | } |
310 | LanguageIterKind::V2 => { |
311 | if let Some(index) = self.languages.iter().position(|c| *c == b';' ) { |
312 | lang = &self.languages[..index]; |
313 | self.languages = &self.languages[index + 1..]; |
314 | } else { |
315 | lang = self.languages; |
316 | self.languages = &[]; |
317 | } |
318 | } |
319 | } |
320 | |
321 | // OK to unwrap because we already checked the string is ASCII. |
322 | Some(core::str::from_utf8(lang).unwrap()) |
323 | } |
324 | } |
325 | |
326 | /// Statically-sized buffer used to convert a `str` to a null-terminated C |
327 | /// string. The buffer should be at least 42 characters per |
328 | /// <https://www.rfc-editor.org/rfc/rfc4646#section-4.3.1>, plus one for the |
329 | /// null terminator. Round up to 64 bytes just for aesthetics. |
330 | type LanguageCStr = [u8; 64]; |
331 | |
332 | fn language_to_cstr(language: &str) -> Result<LanguageCStr> { |
333 | let mut lang_cstr: LanguageCStr = [0; 64]; |
334 | // Ensure there's room for a null-terminator. |
335 | if language.len() >= lang_cstr.len() - 1 { |
336 | return Err(Error::from(Status::BUFFER_TOO_SMALL)); |
337 | } |
338 | lang_cstr[..language.len()].copy_from_slice(src:language.as_bytes()); |
339 | // Assert that it's null-terminated. |
340 | assert_eq!(*lang_cstr.last().unwrap(), 0); |
341 | Ok(lang_cstr) |
342 | } |
343 | |
344 | #[cfg (test)] |
345 | mod tests { |
346 | use super::*; |
347 | use alloc::vec::Vec; |
348 | use LanguageIterKind::{V1, V2}; |
349 | |
350 | #[test ] |
351 | fn test_language_iter_v1() { |
352 | // Empty string. |
353 | let data = " \0" ; |
354 | assert!(LanguageIter::new(data.as_ptr(), V1) |
355 | .unwrap() |
356 | .next() |
357 | .is_none()); |
358 | |
359 | // Two languages. |
360 | let data = "engfra \0" ; |
361 | assert_eq!( |
362 | LanguageIter::new(data.as_ptr(), V1) |
363 | .unwrap() |
364 | .collect::<Vec<_>>(), |
365 | ["eng" , "fra" ] |
366 | ); |
367 | |
368 | // Truncated data. |
369 | let data = "en \0" ; |
370 | assert_eq!( |
371 | LanguageIter::new(data.as_ptr(), V1) |
372 | .unwrap() |
373 | .collect::<Vec<_>>(), |
374 | ["en" ] |
375 | ); |
376 | |
377 | // Non-ASCII. |
378 | let data = "engæ \0" ; |
379 | assert_eq!( |
380 | LanguageIter::new(data.as_ptr(), V1).err().unwrap(), |
381 | LanguageError::Ascii { index: 3 }, |
382 | ); |
383 | } |
384 | |
385 | #[test ] |
386 | fn test_language_iter_v2() { |
387 | // Empty string. |
388 | let data = " \0" ; |
389 | assert!(LanguageIter::new(data.as_ptr(), V2) |
390 | .unwrap() |
391 | .next() |
392 | .is_none()); |
393 | |
394 | // Two languages. |
395 | let data = "en;fr \0" ; |
396 | assert_eq!( |
397 | LanguageIter::new(data.as_ptr(), V2) |
398 | .unwrap() |
399 | .collect::<Vec<_>>(), |
400 | ["en" , "fr" ] |
401 | ); |
402 | |
403 | // Non-ASCII. |
404 | let data = "engæ \0" ; |
405 | assert_eq!( |
406 | LanguageIter::new(data.as_ptr(), V2).err().unwrap(), |
407 | LanguageError::Ascii { index: 3 }, |
408 | ); |
409 | } |
410 | |
411 | #[test ] |
412 | fn test_language_to_cstr() { |
413 | let mut expected = [0; 64]; |
414 | expected[0] = b'e' ; |
415 | expected[1] = b'n' ; |
416 | assert_eq!(language_to_cstr("en" ), Ok(expected)); |
417 | |
418 | assert_eq!( |
419 | language_to_cstr( |
420 | "0123456789012345678901234567890123456789012345678901234567890123456789" |
421 | ) |
422 | .err() |
423 | .unwrap() |
424 | .status(), |
425 | Status::BUFFER_TOO_SMALL |
426 | ); |
427 | } |
428 | } |
429 | |