• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Rust types related to the libfdt C integer results.
16 
17 use core::error;
18 use core::ffi::{c_int, c_uint};
19 use core::fmt;
20 use core::result;
21 
22 /// Error type corresponding to libfdt error codes.
23 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
24 pub enum FdtError {
25     /// FDT_ERR_NOTFOUND
26     NotFound,
27     /// FDT_ERR_EXISTS
28     Exists,
29     /// FDT_ERR_NOSPACE
30     NoSpace,
31     /// FDT_ERR_BADOFFSET
32     BadOffset,
33     /// FDT_ERR_BADPATH
34     BadPath,
35     /// FDT_ERR_BADPHANDLE
36     BadPhandle,
37     /// FDT_ERR_BADSTATE
38     BadState,
39     /// FDT_ERR_TRUNCATED
40     Truncated,
41     /// FDT_ERR_BADMAGIC
42     BadMagic,
43     /// FDT_ERR_BADVERSION
44     BadVersion,
45     /// FDT_ERR_BADSTRUCTURE
46     BadStructure,
47     /// FDT_ERR_BADLAYOUT
48     BadLayout,
49     /// FDT_ERR_INTERNAL
50     Internal,
51     /// FDT_ERR_BADNCELLS
52     BadNCells,
53     /// FDT_ERR_BADVALUE
54     BadValue,
55     /// FDT_ERR_BADOVERLAY
56     BadOverlay,
57     /// FDT_ERR_NOPHANDLES
58     NoPhandles,
59     /// FDT_ERR_BADFLAGS
60     BadFlags,
61     /// FDT_ERR_ALIGNMENT
62     Alignment,
63     /// Unexpected error code
64     Unknown(i32),
65 }
66 
67 impl fmt::Display for FdtError {
68     /// Prints error messages from libfdt.h documentation.
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result69     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70         match self {
71             Self::NotFound => write!(f, "The requested node or property does not exist"),
72             Self::Exists => write!(f, "Attempted to create an existing node or property"),
73             Self::NoSpace => write!(f, "Insufficient buffer space to contain the expanded tree"),
74             Self::BadOffset => write!(f, "Structure block offset is out-of-bounds or invalid"),
75             Self::BadPath => write!(f, "Badly formatted path"),
76             Self::BadPhandle => write!(f, "Invalid phandle length or value"),
77             Self::BadState => write!(f, "Received incomplete device tree"),
78             Self::Truncated => write!(f, "Device tree or sub-block is improperly terminated"),
79             Self::BadMagic => write!(f, "Device tree header missing its magic number"),
80             Self::BadVersion => write!(f, "Device tree has a version which can't be handled"),
81             Self::BadStructure => write!(f, "Device tree has a corrupt structure block"),
82             Self::BadLayout => write!(f, "Device tree sub-blocks in unsupported order"),
83             Self::Internal => write!(f, "libfdt has failed an internal assertion"),
84             Self::BadNCells => write!(f, "Bad format or value of #address-cells or #size-cells"),
85             Self::BadValue => write!(f, "Unexpected property value"),
86             Self::BadOverlay => write!(f, "Overlay cannot be applied"),
87             Self::NoPhandles => write!(f, "Device tree doesn't have any phandle available anymore"),
88             Self::BadFlags => write!(f, "Invalid flag or invalid combination of flags"),
89             Self::Alignment => write!(f, "Device tree base address is not 8-byte aligned"),
90             Self::Unknown(e) => write!(f, "Unknown libfdt error '{e}'"),
91         }
92     }
93 }
94 
95 impl error::Error for FdtError {}
96 
97 /// Result type with FdtError enum.
98 pub type Result<T> = result::Result<T, FdtError>;
99 
100 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
101 pub(crate) struct FdtRawResult(c_int);
102 
103 impl From<c_int> for FdtRawResult {
from(value: c_int) -> Self104     fn from(value: c_int) -> Self {
105         Self(value)
106     }
107 }
108 
109 impl TryFrom<FdtRawResult> for c_int {
110     type Error = FdtError;
111 
try_from(res: FdtRawResult) -> Result<Self>112     fn try_from(res: FdtRawResult) -> Result<Self> {
113         use libfdt_bindgen::{
114             FDT_ERR_ALIGNMENT, FDT_ERR_BADFLAGS, FDT_ERR_BADLAYOUT, FDT_ERR_BADMAGIC,
115             FDT_ERR_BADNCELLS, FDT_ERR_BADOFFSET, FDT_ERR_BADOVERLAY, FDT_ERR_BADPATH,
116             FDT_ERR_BADPHANDLE, FDT_ERR_BADSTATE, FDT_ERR_BADSTRUCTURE, FDT_ERR_BADVALUE,
117             FDT_ERR_BADVERSION, FDT_ERR_EXISTS, FDT_ERR_INTERNAL, FDT_ERR_NOPHANDLES,
118             FDT_ERR_NOSPACE, FDT_ERR_NOTFOUND, FDT_ERR_TRUNCATED,
119         };
120         match res.0 {
121             x if x >= 0 => Ok(x),
122             x if x == -(FDT_ERR_NOTFOUND as c_int) => Err(FdtError::NotFound),
123             x if x == -(FDT_ERR_EXISTS as c_int) => Err(FdtError::Exists),
124             x if x == -(FDT_ERR_NOSPACE as c_int) => Err(FdtError::NoSpace),
125             x if x == -(FDT_ERR_BADOFFSET as c_int) => Err(FdtError::BadOffset),
126             x if x == -(FDT_ERR_BADPATH as c_int) => Err(FdtError::BadPath),
127             x if x == -(FDT_ERR_BADPHANDLE as c_int) => Err(FdtError::BadPhandle),
128             x if x == -(FDT_ERR_BADSTATE as c_int) => Err(FdtError::BadState),
129             x if x == -(FDT_ERR_TRUNCATED as c_int) => Err(FdtError::Truncated),
130             x if x == -(FDT_ERR_BADMAGIC as c_int) => Err(FdtError::BadMagic),
131             x if x == -(FDT_ERR_BADVERSION as c_int) => Err(FdtError::BadVersion),
132             x if x == -(FDT_ERR_BADSTRUCTURE as c_int) => Err(FdtError::BadStructure),
133             x if x == -(FDT_ERR_BADLAYOUT as c_int) => Err(FdtError::BadLayout),
134             x if x == -(FDT_ERR_INTERNAL as c_int) => Err(FdtError::Internal),
135             x if x == -(FDT_ERR_BADNCELLS as c_int) => Err(FdtError::BadNCells),
136             x if x == -(FDT_ERR_BADVALUE as c_int) => Err(FdtError::BadValue),
137             x if x == -(FDT_ERR_BADOVERLAY as c_int) => Err(FdtError::BadOverlay),
138             x if x == -(FDT_ERR_NOPHANDLES as c_int) => Err(FdtError::NoPhandles),
139             x if x == -(FDT_ERR_BADFLAGS as c_int) => Err(FdtError::BadFlags),
140             x if x == -(FDT_ERR_ALIGNMENT as c_int) => Err(FdtError::Alignment),
141             x => Err(FdtError::Unknown(x)),
142         }
143     }
144 }
145 
146 impl TryFrom<FdtRawResult> for Option<c_int> {
147     type Error = FdtError;
148 
try_from(res: FdtRawResult) -> Result<Self>149     fn try_from(res: FdtRawResult) -> Result<Self> {
150         match res.try_into() {
151             Ok(n) => Ok(Some(n)),
152             Err(FdtError::NotFound) => Ok(None),
153             Err(e) => Err(e),
154         }
155     }
156 }
157 
158 impl TryFrom<FdtRawResult> for c_uint {
159     type Error = FdtError;
160 
try_from(res: FdtRawResult) -> Result<Self>161     fn try_from(res: FdtRawResult) -> Result<Self> {
162         Ok(c_int::try_from(res)?.try_into().unwrap())
163     }
164 }
165 
166 impl TryFrom<FdtRawResult> for usize {
167     type Error = FdtError;
168 
try_from(res: FdtRawResult) -> Result<Self>169     fn try_from(res: FdtRawResult) -> Result<Self> {
170         Ok(c_int::try_from(res)?.try_into().unwrap())
171     }
172 }
173 
174 impl TryFrom<FdtRawResult> for Option<usize> {
175     type Error = FdtError;
176 
try_from(res: FdtRawResult) -> Result<Self>177     fn try_from(res: FdtRawResult) -> Result<Self> {
178         match res.try_into() {
179             Ok(n) => Ok(Some(n)),
180             Err(FdtError::NotFound) => Ok(None),
181             Err(e) => Err(e),
182         }
183     }
184 }
185 
186 impl TryFrom<FdtRawResult> for () {
187     type Error = FdtError;
188 
try_from(res: FdtRawResult) -> Result<Self>189     fn try_from(res: FdtRawResult) -> Result<Self> {
190         match res.try_into()? {
191             0 => Ok(()),
192             n => Err(FdtError::Unknown(n)),
193         }
194     }
195 }
196