1
+ //! Read-only initial RAM Disk
2
+ //!
3
+ //! A rather crude format, and very hacky code to run it
4
+ use core:: convert:: TryInto ;
5
+ use kernel:: lib:: mem:: Box ;
6
+ use kernel:: metadevs:: storage:: { IoError , VolumeHandle } ;
7
+ use core:: mem:: size_of;
8
+
9
+ const BLOCK_SIZE : usize = 0x1000 ;
10
+ mod repr {
11
+ pub const MAGIC_NUMBER : u32 = 0x0 ;
12
+
13
+ #[ repr( C ) ]
14
+ pub struct Header {
15
+ pub magic : u32 ,
16
+ pub total_length : u32 ,
17
+ pub node_count : u32 ,
18
+ pub root_length : u32 ,
19
+ }
20
+ #[ repr( C ) ]
21
+ pub struct Inode {
22
+ pub length : u32 ,
23
+ pub ofs : u32 ,
24
+ pub ty : u8 ,
25
+ _reserved : [ u8 ; 3 ]
26
+ // TODO: Anything else?
27
+ }
28
+
29
+ pub const NODE_TY_REGULAR : u8 = 0 ;
30
+ pub const NODE_TY_DIRECTORY : u8 = 1 ;
31
+ //pub const NODE_TY_SYMLINK: u8 = 2;
32
+
33
+ #[ repr( C ) ]
34
+ pub struct DirEntry {
35
+ pub node : u32 ,
36
+ pub filename : [ u8 ; 64 -4 ] ,
37
+ }
38
+ impl DirEntry {
39
+ pub fn name ( & self ) -> & super :: ByteStr {
40
+ let l = self . filename . iter ( ) . position ( |v| * v == 0 ) . unwrap_or ( self . filename . len ( ) ) ;
41
+ super :: ByteStr :: new ( & self . filename [ ..l] )
42
+ }
43
+ }
44
+ }
45
+
46
+ /// The underlying "storage device" for an initrd
47
+ ///
48
+ /// Acts like a normal device, except that if you read from block -1 it returns a magic number
49
+ /// and the slice (pointer and len) to the raw data.
50
+ pub struct InitrdVol {
51
+ handle : :: kernel:: memory:: virt:: AllocHandle ,
52
+ ofs : u32 ,
53
+ len : u32 ,
54
+ }
55
+ impl InitrdVol {
56
+ /// UNSAFE: Takes raw physical memory locations, and thus can read from any memory
57
+ pub unsafe fn new ( base : u64 , length : usize ) -> Result < Self , ( ) > {
58
+ let handle = match :: kernel:: memory:: virt:: map_hw_ro (
59
+ base, ( length + :: kernel:: PAGE_SIZE -1 ) / :: kernel:: PAGE_SIZE ,
60
+ "initrd"
61
+ )
62
+ {
63
+ Ok ( v) => v,
64
+ Err ( _e) => return Err ( ( ) ) ,
65
+ } ;
66
+ let ofs = ( base % ( :: kernel:: PAGE_SIZE as u64 ) ) as usize ;
67
+
68
+ Ok ( Self { handle, ofs : ofs as u32 , len : length as u32 } )
69
+ }
70
+ }
71
+ impl :: kernel:: metadevs:: storage:: PhysicalVolume for InitrdVol {
72
+ fn name ( & self ) -> & str {
73
+ "initrd"
74
+ }
75
+
76
+ fn blocksize ( & self ) -> usize {
77
+ BLOCK_SIZE
78
+ }
79
+
80
+ fn capacity ( & self ) -> Option < u64 > {
81
+ Some ( self . len as u64 / BLOCK_SIZE as u64 )
82
+ }
83
+
84
+ fn read < ' a > ( & ' a self , _: u8 , blockidx : u64 , count : usize , dst : & ' a mut [ u8 ] ) -> kernel:: metadevs:: storage:: AsyncIoResult < ' a , usize > {
85
+ // Handle the magic protocol
86
+ if blockidx == !0 && count == 1 {
87
+ dst[ 0 ..] [ ..8 ] . copy_from_slice ( & ( repr:: MAGIC_NUMBER as u64 ) . to_le_bytes ( ) ) ;
88
+ dst[ 8 ..] [ ..8 ] . copy_from_slice ( & ( self . handle . as_slice :: < u8 > ( self . ofs as usize , 0 ) . as_ptr ( ) as usize as u64 ) . to_le_bytes ( ) ) ;
89
+ dst[ 16 ..] [ ..8 ] . copy_from_slice ( & ( self . len as u64 ) . to_le_bytes ( ) ) ;
90
+ return Box :: pin ( async move { Ok ( 1 ) } ) ;
91
+ }
92
+ if blockidx as usize > ( self . len as usize ) / BLOCK_SIZE {
93
+ return Box :: pin ( async move { Err ( IoError :: BadBlock ) } ) ;
94
+ }
95
+ let count = count. min ( self . len as usize / BLOCK_SIZE - blockidx as usize ) ;
96
+ assert ! ( dst. len( ) >= count * BLOCK_SIZE ) ;
97
+ let ofs = self . ofs as usize + blockidx as usize * BLOCK_SIZE ;
98
+ let src = self . handle . as_slice ( ofs, dst. len ( ) ) ;
99
+ dst. copy_from_slice ( src) ;
100
+
101
+ Box :: pin ( async move { Ok ( count) } )
102
+ }
103
+
104
+ fn write < ' a > ( & ' a self , _: u8 , _: u64 , _: usize , _: & ' a [ u8 ] ) -> kernel:: metadevs:: storage:: AsyncIoResult < ' a , usize > {
105
+ Box :: pin ( async move { Err ( IoError :: ReadOnly ) } )
106
+ }
107
+
108
+ fn wipe < ' a > ( & ' a self , _: u64 , _: usize ) -> kernel:: metadevs:: storage:: AsyncIoResult < ' a , ( ) > {
109
+ Box :: pin ( async move { Err ( IoError :: ReadOnly ) } )
110
+ }
111
+ }
112
+
113
+ pub struct InitrdDriver ;
114
+ impl super :: mount:: Driver for InitrdDriver {
115
+ fn detect ( & self , vol : & VolumeHandle ) -> crate :: Result < usize > {
116
+ let mut tmp = [ 0 ; 4096 ] ;
117
+ :: kernel:: futures:: block_on ( vol. read_blocks ( !0 , & mut tmp) ) ?;
118
+ if tmp[ ..4 ] == repr:: MAGIC_NUMBER . to_le_bytes ( ) {
119
+ Ok ( 3 )
120
+ }
121
+ else {
122
+ Ok ( 0 )
123
+ }
124
+ }
125
+
126
+ fn mount ( & self , vol : VolumeHandle , _self_handle : crate :: mount:: SelfHandle ) -> crate :: Result < Box < dyn crate :: mount:: Filesystem > > {
127
+ let mut tmp = [ 0 ; 4096 ] ;
128
+ :: kernel:: futures:: block_on ( vol. read_blocks ( !0 , & mut tmp) ) ?;
129
+ if tmp[ ..4 ] != repr:: MAGIC_NUMBER . to_le_bytes ( ) {
130
+ return Err ( crate :: Error :: InconsistentFilesystem )
131
+ }
132
+ let ptr = u64:: from_le_bytes ( tmp[ 8 ..] [ ..8 ] . try_into ( ) . unwrap ( ) ) ;
133
+ let len = u64:: from_le_bytes ( tmp[ 16 ..] [ ..8 ] . try_into ( ) . unwrap ( ) ) ;
134
+ // SAFE: Since the magic passed, assume that the encoded slice is also valid
135
+ let data = unsafe { :: core:: slice:: from_raw_parts ( ptr as usize as * const u8 , len as usize ) } ;
136
+ if data. as_ptr ( ) as usize % :: core:: mem:: align_of :: < repr:: Header > ( ) != 0 {
137
+ return Err ( crate :: Error :: InconsistentFilesystem )
138
+ }
139
+ if data. len ( ) < size_of :: < repr:: Header > ( ) {
140
+ return Err ( crate :: Error :: InconsistentFilesystem )
141
+ }
142
+
143
+ let instance = Inner {
144
+ _vol_handle : vol,
145
+ //self_handle,
146
+ data
147
+ } ;
148
+ if data. len ( ) < size_of :: < repr:: Header > ( ) + instance. header ( ) . node_count as usize * size_of :: < repr:: Inode > ( ) {
149
+ return Err ( crate :: Error :: InconsistentFilesystem )
150
+ }
151
+
152
+ // SAFE: The ArefInner is going right in a box, and won't move until the box is dropped
153
+ Ok ( Box :: new ( InitrdInstance ( unsafe { :: kernel:: lib:: mem:: aref:: ArefInner :: new ( instance) } ) ) )
154
+ }
155
+ }
156
+ struct Inner {
157
+ _vol_handle : VolumeHandle ,
158
+ //self_handle: super::mount::SelfHandle,
159
+ data : & ' static [ u8 ] ,
160
+ }
161
+ impl Inner {
162
+ fn header ( & self ) -> & repr:: Header {
163
+ // SAFE: Data alignment cheked by the original mount, and is valid for this type
164
+ unsafe { & * ( self . data . as_ptr ( ) as * const repr:: Header ) }
165
+ }
166
+ fn inodes ( & self ) -> & [ repr:: Inode ] {
167
+ unsafe {
168
+ :: core:: slice:: from_raw_parts (
169
+ self . data . as_ptr ( ) . offset ( size_of :: < repr:: Header > ( ) as isize ) as * const repr:: Inode ,
170
+ self . header ( ) . node_count as usize
171
+ )
172
+ }
173
+ }
174
+ fn get_data ( & self , ofs : u32 , len : u32 ) -> crate :: Result < & [ u8 ] > {
175
+ if ofs as usize > self . data . len ( ) {
176
+ return Err ( crate :: Error :: InconsistentFilesystem ) ;
177
+ }
178
+ if ofs as usize + len as usize > self . data . len ( ) {
179
+ return Err ( crate :: Error :: InconsistentFilesystem ) ;
180
+ }
181
+ Ok ( & self . data [ ofs as usize ..] [ ..len as usize ] )
182
+ }
183
+ }
184
+ struct InitrdInstance ( :: kernel:: lib:: mem:: aref:: ArefInner < Inner > ) ;
185
+ impl crate :: mount:: Filesystem for InitrdInstance {
186
+ fn root_inode ( & self ) -> crate :: node:: InodeId {
187
+ 0
188
+ }
189
+
190
+ fn get_node_by_inode ( & self , i : crate :: node:: InodeId ) -> Option < crate :: node:: Node > {
191
+ use :: core:: convert:: TryFrom ;
192
+ let inodes = self . 0 . inodes ( ) ;
193
+ let inode = inodes. get ( usize:: try_from ( i) . ok ( ) ?) ?;
194
+ Some ( match inode. ty {
195
+ repr:: NODE_TY_REGULAR => crate :: node:: Node :: File ( Box :: new ( NodeFile {
196
+ parent : self . 0 . borrow ( ) ,
197
+ node_id : i as u32 ,
198
+ ofs : inode. ofs ,
199
+ size : inode. length ,
200
+ } ) ) ,
201
+ repr:: NODE_TY_DIRECTORY => crate :: node:: Node :: Dir ( Box :: new ( NodeDir {
202
+ parent : self . 0 . borrow ( ) ,
203
+ node_id : i as u32 ,
204
+ ofs : inode. ofs ,
205
+ size : inode. length ,
206
+ } ) ) ,
207
+ _ => return None ,
208
+ } )
209
+ }
210
+ }
211
+
212
+ struct NodeFile {
213
+ parent : :: kernel:: lib:: mem:: aref:: ArefBorrow < Inner > ,
214
+ node_id : u32 ,
215
+ ofs : u32 ,
216
+ size : u32 ,
217
+ }
218
+ impl crate :: node:: NodeBase for NodeFile {
219
+ fn get_id ( & self ) -> crate :: node:: InodeId {
220
+ self . node_id as _
221
+ }
222
+
223
+ fn get_any ( & self ) -> & dyn core:: any:: Any {
224
+ self
225
+ }
226
+ }
227
+ impl crate :: node:: File for NodeFile {
228
+ fn size ( & self ) -> u64 {
229
+ self . size as u64
230
+ }
231
+
232
+ fn truncate ( & self , _newsize : u64 ) -> crate :: node:: Result < u64 > {
233
+ Err ( crate :: Error :: ReadOnlyFilesystem )
234
+ }
235
+
236
+ fn clear ( & self , _ofs : u64 , _size : u64 ) -> crate :: node:: Result < ( ) > {
237
+ Err ( crate :: Error :: ReadOnlyFilesystem )
238
+ }
239
+
240
+ fn read ( & self , ofs : u64 , buf : & mut [ u8 ] ) -> crate :: node:: Result < usize > {
241
+ let src = self . parent . get_data ( self . ofs , self . size ) ?;
242
+ if ofs > src. len ( ) as u64 {
243
+ return Err ( crate :: Error :: InvalidParameter ) ;
244
+ }
245
+ let src = & src[ ofs as usize ..] ;
246
+ let rv = buf. len ( ) . min ( src. len ( ) ) ;
247
+ buf[ ..rv] . copy_from_slice ( & src[ ..rv] ) ;
248
+ Ok ( rv)
249
+ }
250
+
251
+ fn write ( & self , _ofs : u64 , _buf : & [ u8 ] ) -> crate :: node:: Result < usize > {
252
+ Err ( crate :: Error :: ReadOnlyFilesystem )
253
+ }
254
+ }
255
+
256
+ struct NodeDir {
257
+ parent : :: kernel:: lib:: mem:: aref:: ArefBorrow < Inner > ,
258
+ node_id : u32 ,
259
+ ofs : u32 ,
260
+ size : u32 ,
261
+ }
262
+ impl NodeDir {
263
+ fn entries ( & self ) -> Result < & [ repr:: DirEntry ] , super :: Error > {
264
+ let d = self . parent . get_data ( self . ofs , self . size ) ?;
265
+ if d. as_ptr ( ) as usize % align_of :: < repr:: DirEntry > ( ) != 0 {
266
+ return Err ( crate :: Error :: InconsistentFilesystem ) ;
267
+ }
268
+ if d. len ( ) as usize % size_of :: < repr:: DirEntry > ( ) != 0 {
269
+ return Err ( crate :: Error :: InconsistentFilesystem ) ;
270
+ }
271
+ // SAFE: Alignment and size checked above, data is functionally POD
272
+ Ok ( unsafe { :: core:: slice:: from_raw_parts ( d. as_ptr ( ) as * const _ , d. len ( ) / size_of :: < repr:: DirEntry > ( ) ) } )
273
+ }
274
+ }
275
+ impl crate :: node:: NodeBase for NodeDir {
276
+ fn get_id ( & self ) -> crate :: node:: InodeId {
277
+ self . node_id as _
278
+ }
279
+
280
+ fn get_any ( & self ) -> & dyn core:: any:: Any {
281
+ self
282
+ }
283
+ }
284
+ use kernel:: lib:: byte_str:: ByteStr ;
285
+ impl crate :: node:: Dir for NodeDir {
286
+ fn lookup ( & self , name : & ByteStr ) -> crate :: node:: Result < crate :: node:: InodeId > {
287
+ for e in self . entries ( ) ? {
288
+ if e. name ( ) == name {
289
+ return Ok ( e. node as _ ) ;
290
+ }
291
+ }
292
+ Err ( super :: Error :: NotFound )
293
+ }
294
+
295
+ fn read ( & self , start_ofs : usize , callback : & mut crate :: node:: ReadDirCallback ) -> crate :: node:: Result < usize > {
296
+ let ents = self . entries ( ) ?;
297
+ if start_ofs >= ents. len ( ) {
298
+ return Ok ( ents. len ( ) ) ;
299
+ }
300
+ let ents_to_visit = ents. get ( start_ofs..) . unwrap_or ( & [ ] ) ;
301
+ for ( i, e) in ents_to_visit. iter ( ) . enumerate ( ) {
302
+ if callback ( e. node as u64 , & mut e. name ( ) . as_bytes ( ) . iter ( ) . copied ( ) ) == false {
303
+ return Ok ( start_ofs + i + 1 ) ;
304
+ }
305
+ }
306
+ Ok ( start_ofs + ents_to_visit. len ( ) )
307
+ }
308
+
309
+ fn create ( & self , _name : & ByteStr , _nodetype : crate :: node:: NodeType ) -> crate :: node:: Result < crate :: node:: InodeId > {
310
+ Err ( super :: Error :: ReadOnlyFilesystem )
311
+ }
312
+
313
+ fn link ( & self , _name : & ByteStr , _inode : & dyn crate :: node:: NodeBase ) -> crate :: node:: Result < ( ) > {
314
+ Err ( super :: Error :: ReadOnlyFilesystem )
315
+ }
316
+
317
+ fn unlink ( & self , _name : & ByteStr ) -> crate :: node:: Result < ( ) > {
318
+ Err ( super :: Error :: ReadOnlyFilesystem )
319
+ }
320
+ }
0 commit comments