kernel/
dynamic_binary_storage.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2024.
4
5//! Dynamic Binary Flasher for application loading and updating at runtime.
6//!
7//! These functions facilitate dynamic application flashing and process creation
8//! during runtime without requiring the user to restart the device.
9
10use core::cell::Cell;
11
12use crate::config;
13use crate::debug;
14use crate::deferred_call::{DeferredCall, DeferredCallClient};
15use crate::hil::nonvolatile_storage::{NonvolatileStorage, NonvolatileStorageClient};
16use crate::platform::chip::Chip;
17use crate::process::ProcessLoadingAsyncClient;
18use crate::process_loading::{
19    PaddingRequirement, ProcessLoadError, SequentialProcessLoaderMachine,
20};
21use crate::process_standard::ProcessStandardDebug;
22use crate::utilities::cells::{OptionalCell, TakeCell};
23use crate::utilities::leasable_buffer::SubSliceMut;
24use crate::ErrorCode;
25
26/// Expected buffer length for storing application binaries.
27pub const BUF_LEN: usize = 512;
28
29/// The number of bytes in the TBF header for a padding app.
30const PADDING_TBF_HEADER_LENGTH: usize = 16;
31
32#[derive(Clone, Copy, PartialEq)]
33pub enum State {
34    Idle,
35    Setup,
36    AppWrite,
37    Load,
38    Abort,
39    PaddingWrite,
40    Fail,
41}
42
43/// Addresses of where the new process will be stored.
44#[derive(Clone, Copy, Default)]
45struct ProcessLoadMetadata {
46    new_app_start_addr: usize,
47    new_app_length: usize,
48    previous_app_end_addr: usize,
49    next_app_start_addr: usize,
50    padding_requirement: PaddingRequirement,
51    setup_padding: bool,
52}
53
54/// This interface supports flashing binaries at runtime.
55pub trait DynamicBinaryStore {
56    /// Call to request flashing a new binary.
57    ///
58    /// This informs the kernel we want to load a process, and the size of the
59    /// entire process binary. The kernel will try to find a suitable location
60    /// in flash to store said process.
61    ///
62    /// Return value:
63    /// - `Ok(length)`: If there is a place to load the
64    ///   process, the function will return `Ok()` with the size of the region
65    ///   to store the process.
66    /// - `Err(ErrorCode)`: If there is nowhere to store the process a suitable
67    ///   `ErrorCode` will be returned.
68    fn setup(&self, app_length: usize) -> Result<usize, ErrorCode>;
69
70    /// Instruct the kernel to write data to the flash.
71    ///
72    /// `offset` is where to start writing within the region allocated
73    /// for the new process binary from the `setup()` call.
74    ///
75    /// The caller must write the first 8 bytes of the process with valid header
76    /// data. Writes must either be after the first 8 bytes or include the
77    /// entire first 8 bytes.
78    ///
79    /// Returns an error if the write is outside of the permitted region or is
80    /// writing an invalid header.
81    fn write(&self, buffer: SubSliceMut<'static, u8>, offset: usize) -> Result<(), ErrorCode>;
82
83    /// Signal to the kernel that the requesting process is done writing the new
84    /// binary.
85    fn finalize(&self) -> Result<(), ErrorCode>;
86
87    /// Call to abort the setup/writing process.
88    fn abort(&self) -> Result<(), ErrorCode>;
89
90    /// Sets a client for the SequentialDynamicBinaryStore Object
91    ///
92    /// When the client operation is done, it calls the `setup_done()`,
93    /// `write_done()` and `abort_done()` functions.
94    fn set_storage_client(&self, client: &'static dyn DynamicBinaryStoreClient);
95}
96
97/// The callback for dynamic binary flashing.
98pub trait DynamicBinaryStoreClient {
99    /// Any setup work is done and we are ready to write the process binary.
100    fn setup_done(&self, result: Result<(), ErrorCode>);
101
102    /// The provided app binary buffer has been stored.
103    fn write_done(&self, result: Result<(), ErrorCode>, buffer: &'static mut [u8], length: usize);
104
105    /// The kernel has successfully finished finalizing the new app and is ready
106    /// to move to the `load()` phase.
107    fn finalize_done(&self, result: Result<(), ErrorCode>);
108
109    /// Canceled any setup or writing operation and freed up reserved space.
110    fn abort_done(&self, result: Result<(), ErrorCode>);
111}
112
113/// This interface supports loading processes at runtime.
114pub trait DynamicProcessLoad {
115    /// Call to request kernel to load a new process.
116    fn load(&self) -> Result<(), ErrorCode>;
117
118    /// Sets a client for the SequentialDynamicProcessLoading Object
119    ///
120    /// When the client operation is done, it calls the `load_done()`
121    /// function.
122    fn set_load_client(&self, client: &'static dyn DynamicProcessLoadClient);
123}
124
125/// The callback for dynamic binary flashing.
126pub trait DynamicProcessLoadClient {
127    /// The new app has been loaded.
128    fn load_done(&self, result: Result<(), ProcessLoadError>);
129}
130
131/// Dynamic process loading machine.
132pub struct SequentialDynamicBinaryStorage<
133    'a,
134    'b,
135    C: Chip + 'static,
136    D: ProcessStandardDebug + 'static,
137    F: NonvolatileStorage<'b>,
138> {
139    flash_driver: &'b F,
140    loader_driver: &'a SequentialProcessLoaderMachine<'a, C, D>,
141    buffer: TakeCell<'static, [u8]>,
142    storage_client: OptionalCell<&'static dyn DynamicBinaryStoreClient>,
143    load_client: OptionalCell<&'static dyn DynamicProcessLoadClient>,
144    process_metadata: OptionalCell<ProcessLoadMetadata>,
145    state: Cell<State>,
146    deferred_call: DeferredCall,
147}
148
149impl<'a, 'b, C: Chip + 'static, D: ProcessStandardDebug + 'static, F: NonvolatileStorage<'b>>
150    SequentialDynamicBinaryStorage<'a, 'b, C, D, F>
151{
152    pub fn new(
153        flash_driver: &'b F,
154        loader_driver: &'a SequentialProcessLoaderMachine<'a, C, D>,
155        buffer: &'static mut [u8],
156    ) -> Self {
157        Self {
158            flash_driver,
159            loader_driver,
160            buffer: TakeCell::new(buffer),
161            storage_client: OptionalCell::empty(),
162            load_client: OptionalCell::empty(),
163            process_metadata: OptionalCell::empty(),
164            state: Cell::new(State::Idle),
165            deferred_call: DeferredCall::new(),
166        }
167    }
168
169    /// Function to reset variables and states.
170    fn reset_process_loading_metadata(&self) {
171        self.state.set(State::Idle);
172        self.process_metadata.take();
173    }
174
175    /// This function checks whether the new app will fit in the bounds dictated
176    /// by the start address and length provided during the setup phase. This
177    /// function then also computes where in flash the data should be written
178    /// based on whether the call is coming during the app writing phase, or the
179    /// padding phase.
180    ///
181    /// This function returns the physical address in flash where the write is
182    /// supposed to happen.
183    fn compute_address(&self, offset: usize, length: usize) -> Result<usize, ErrorCode> {
184        let mut new_app_len: usize = 0;
185        let mut new_app_addr: usize = 0;
186        if let Some(metadata) = self.process_metadata.get() {
187            new_app_addr = metadata.new_app_start_addr;
188            new_app_len = metadata.new_app_length;
189        }
190
191        match self.state.get() {
192            State::AppWrite => {
193                // Check if there is an overflow while adding length and offset.
194                match offset.checked_add(length) {
195                    Some(result) => {
196                        // Check if the new app is trying to write beyond
197                        // the bounds of the flash region allocated to it.
198                        if result > new_app_len {
199                            // This means the app is out of bounds.
200                            Err(ErrorCode::INVAL)
201                        } else {
202                            // We compute the new address to write the app
203                            // binary segment.
204                            Ok(offset + new_app_addr)
205                        }
206                    }
207                    None => Err(ErrorCode::INVAL),
208                }
209            }
210            // If we are going to write the padding header, we already know
211            // where to write in flash, so we don't have to add the start
212            // address
213            State::Setup | State::Load | State::PaddingWrite | State::Abort => Ok(offset),
214            // We aren't supposed to be able to write unless we are in one of
215            // the first two write states
216            _ => Err(ErrorCode::FAIL),
217        }
218    }
219
220    /// Compute the physical address where we should write the data and then
221    /// write it.
222    fn write_buffer(
223        &self,
224        user_buffer: SubSliceMut<'static, u8>,
225        offset: usize,
226    ) -> Result<(), ErrorCode> {
227        let length = user_buffer.len();
228        // Take the buffer to perform tbf header validation and write with.
229        let buffer = user_buffer.take();
230
231        let physical_address = self.compute_address(offset, length)?;
232
233        // The kernel needs to check if the app is trying to write/overwrite the
234        // header. So the app can only write to the first 8 bytes if the app is
235        // writing all 8 bytes. Else, the kernel must raise an error. The app is
236        // not allowed to write from say, offset 4 because we have to ensure the
237        // validity of the header.
238        //
239        // This means the app is trying to manipulate the space where the TBF
240        // header should go. Ideally, we want the app to only write the complete
241        // set of 8 bytes which is used to determine if the header is valid. We
242        // don't want apps to do this, so we return an error.
243        if (offset == 0 && length < 8) || (offset != 0 && offset < 8) {
244            return Err(ErrorCode::INVAL);
245        }
246
247        // Check if we are writing the start of the TBF header.
248        //
249        // The app is not allowed to manipulate parts of the TBF header, so if
250        // it is trying to write at the very beginning of the promised flash
251        // region, we require the app writes the entire 8 bytes of the header.
252        // This header is then checked for validity.
253        if offset == 0 {
254            // Pass the first eight bytes of the tbf header to parse out the
255            // length of the header and app. We then use those values to see if
256            // the app is going to be valid.
257            let test_header_slice = buffer.get(0..8).ok_or(ErrorCode::INVAL)?;
258            let header = test_header_slice.try_into().or(Err(ErrorCode::FAIL))?;
259            let (_version, _header_length, entry_length) =
260                match tock_tbf::parse::parse_tbf_header_lengths(header) {
261                    Ok((v, hl, el)) => (v, hl, el),
262                    Err(tock_tbf::types::InitialTbfParseError::InvalidHeader(_entry_length)) => {
263                        // If we have an invalid header, so we return an error
264                        return Err(ErrorCode::INVAL);
265                    }
266                    Err(tock_tbf::types::InitialTbfParseError::UnableToParse) => {
267                        // If we could not parse the header, then that's an
268                        // issue. We return an Error.
269                        return Err(ErrorCode::INVAL);
270                    }
271                };
272
273            // Check if the length in the header is matching what the app
274            // requested during the setup phase also check if the kernel
275            // version matches the version indicated in the new application.
276            let mut new_app_len = 0;
277            if let Some(metadata) = self.process_metadata.get() {
278                new_app_len = metadata.new_app_length;
279            }
280            if entry_length as usize != new_app_len {
281                return Err(ErrorCode::INVAL);
282            }
283        }
284        self.flash_driver.write(buffer, physical_address, length)
285    }
286
287    /// Function to generate the padding header to append after the new app.
288    /// This header is created and written to ensure the integrity of the
289    /// processes linked list
290    fn write_padding_app(&self, padding_app_length: usize, offset: usize) -> Result<(), ErrorCode> {
291        // Write the header into the array
292        self.buffer.map(|buffer| {
293            // First two bytes are the TBF version (2).
294            buffer[0] = 2;
295            buffer[1] = 0;
296
297            // The next two bytes are the header length (fixed to 16 bytes for
298            // padding).
299            buffer[2] = (PADDING_TBF_HEADER_LENGTH & 0xff) as u8;
300            buffer[3] = ((PADDING_TBF_HEADER_LENGTH >> 8) & 0xff) as u8;
301
302            // The next 4 bytes are the total app length including the header.
303            buffer[4] = (padding_app_length & 0xff) as u8;
304            buffer[5] = ((padding_app_length >> 8) & 0xff) as u8;
305            buffer[6] = ((padding_app_length >> 16) & 0xff) as u8;
306            buffer[7] = ((padding_app_length >> 24) & 0xff) as u8;
307
308            // We set the flags to 0.
309            for i in 8..12 {
310                buffer[i] = 0x00_u8;
311            }
312
313            // xor of the previous values
314            buffer[12] = buffer[0] ^ buffer[4] ^ buffer[8];
315            buffer[13] = buffer[1] ^ buffer[5] ^ buffer[9];
316            buffer[14] = buffer[2] ^ buffer[6] ^ buffer[10];
317            buffer[15] = buffer[3] ^ buffer[7] ^ buffer[11];
318        });
319
320        self.buffer.take().map_or(Err(ErrorCode::BUSY), |buffer| {
321            match self
322                .loader_driver
323                .check_if_within_flash_bounds(offset, PADDING_TBF_HEADER_LENGTH)
324            {
325                true => {
326                    // Write the header only if there are more than 16 bytes.
327                    // available in the flash.
328                    let mut padding_slice = SubSliceMut::new(buffer);
329                    padding_slice.slice(..PADDING_TBF_HEADER_LENGTH);
330                    // We are only writing the header, so 16 bytes is enough.
331                    self.write_buffer(padding_slice, offset)
332                }
333                false => Err(ErrorCode::NOMEM),
334            }
335        })
336    }
337}
338
339impl<'b, C: Chip, D: ProcessStandardDebug, F: NonvolatileStorage<'b>> DeferredCallClient
340    for SequentialDynamicBinaryStorage<'_, 'b, C, D, F>
341{
342    fn handle_deferred_call(&self) {
343        // We use deferred call to signal the completion of finalize
344        self.storage_client.map(|client| {
345            client.finalize_done(Ok(()));
346        });
347    }
348
349    fn register(&'static self) {
350        self.deferred_call.register(self);
351    }
352}
353
354/// This is the callback client for the underlying physical storage driver.
355impl<'b, C: Chip + 'static, D: ProcessStandardDebug + 'static, F: NonvolatileStorage<'b>>
356    NonvolatileStorageClient for SequentialDynamicBinaryStorage<'_, 'b, C, D, F>
357{
358    fn read_done(&self, _buffer: &'static mut [u8], _length: usize) {
359        // We will never use this, but we need to implement this anyway.
360        unimplemented!();
361    }
362
363    fn write_done(&self, buffer: &'static mut [u8], length: usize) {
364        match self.state.get() {
365            State::AppWrite => {
366                self.state.set(State::AppWrite);
367                // Switch on which user generated this callback and trigger
368                // client callback.
369                self.storage_client.map(|client| {
370                    client.write_done(Ok(()), buffer, length);
371                });
372            }
373            State::PaddingWrite => {
374                // Replace the buffer after the padding is written.
375                self.reset_process_loading_metadata();
376                self.buffer.replace(buffer);
377            }
378            State::Fail => {
379                // If we failed at any of writing, we want to set the state to
380                // PaddingWrite so that the callback after writing the padding
381                // app will get triggererd.
382                self.buffer.replace(buffer);
383                if let Some(metadata) = self.process_metadata.get() {
384                    let _ = self
385                        .write_padding_app(metadata.new_app_length, metadata.new_app_start_addr);
386                }
387                // Clear all metadata specific to this load.
388                self.reset_process_loading_metadata();
389            }
390            State::Setup => {
391                // We have finished writing the post app padding.
392                self.buffer.replace(buffer);
393
394                if let Some(mut metadata) = self.process_metadata.get() {
395                    if !metadata.setup_padding {
396                        // Write padding header to the beginning of the new app address.
397                        // This ensures that the linked list is not broken in the event of a
398                        // powercycle before the app is fully written and loaded.
399                        metadata.setup_padding = true;
400                        let _ = self.write_padding_app(
401                            metadata.new_app_length,
402                            metadata.new_app_start_addr,
403                        );
404                        self.process_metadata.set(metadata);
405                    } else {
406                        self.state.set(State::AppWrite);
407                        // Let the client know we are done setting up.
408                        self.storage_client.map(|client| {
409                            client.setup_done(Ok(()));
410                        });
411                    }
412                }
413            }
414            State::Load => {
415                // We finished writing pre-padding and we need to Load the app.
416                self.buffer.replace(buffer);
417                self.storage_client.map(|client| {
418                    client.finalize_done(Ok(()));
419                });
420            }
421            State::Abort => {
422                self.buffer.replace(buffer);
423                // Reset metadata and let client know we are done aborting.
424                self.reset_process_loading_metadata();
425                self.storage_client.map(|client| {
426                    client.abort_done(Ok(()));
427                });
428            }
429            State::Idle => {
430                self.buffer.replace(buffer);
431            }
432        }
433    }
434}
435
436/// Callback client for the async process loader
437impl<'b, C: Chip + 'static, D: ProcessStandardDebug + 'static, F: NonvolatileStorage<'b>>
438    ProcessLoadingAsyncClient for SequentialDynamicBinaryStorage<'_, 'b, C, D, F>
439{
440    fn process_loaded(&self, result: Result<(), ProcessLoadError>) {
441        self.load_client.map(|client| {
442            client.load_done(result);
443        });
444    }
445
446    fn process_loading_finished(&self) {
447        self.load_client.map(|client| {
448            client.load_done(Ok(()));
449        });
450    }
451}
452
453/// Storage interface exposed to the app_loader capsule
454impl<'b, C: Chip + 'static, D: ProcessStandardDebug + 'static, F: NonvolatileStorage<'b>>
455    DynamicBinaryStore for SequentialDynamicBinaryStorage<'_, 'b, C, D, F>
456{
457    fn set_storage_client(&self, client: &'static dyn DynamicBinaryStoreClient) {
458        self.storage_client.set(client);
459    }
460
461    fn setup(&self, app_length: usize) -> Result<usize, ErrorCode> {
462        self.process_metadata.set(ProcessLoadMetadata::default());
463
464        if self.state.get() == State::Idle {
465            self.state.set(State::Setup);
466            match self.loader_driver.check_flash_for_new_address(app_length) {
467                Ok((
468                    new_app_start_address,
469                    padding_requirement,
470                    previous_app_end_addr,
471                    next_app_start_addr,
472                )) => {
473                    if let Some(mut metadata) = self.process_metadata.get() {
474                        metadata.new_app_start_addr = new_app_start_address;
475                        metadata.new_app_length = app_length;
476                        metadata.previous_app_end_addr = previous_app_end_addr;
477                        metadata.next_app_start_addr = next_app_start_addr;
478                        metadata.padding_requirement = padding_requirement;
479                        self.process_metadata.set(metadata);
480                    }
481
482                    match padding_requirement {
483                        // If we decided we need to write a padding app after
484                        // the new app, we go ahead and do it.
485                        PaddingRequirement::PostPad | PaddingRequirement::PreAndPostPad => {
486                            // Calculating the distance between our app and
487                            // either the next app.
488                            let new_app_end_address = new_app_start_address + app_length;
489                            let post_pad_length = next_app_start_addr - new_app_end_address;
490
491                            let padding_result =
492                                self.write_padding_app(post_pad_length, new_app_end_address);
493                            let _ = match padding_result {
494                                Ok(()) => Ok(()),
495                                Err(e) => {
496                                    // This means we were unable to write the
497                                    // padding app.
498                                    self.reset_process_loading_metadata();
499                                    Err(e)
500                                }
501                            };
502                        }
503                        // Otherwise we let the client know we are done with the
504                        // setup, and we are ready to write the app to flash.
505                        PaddingRequirement::None | PaddingRequirement::PrePad => {
506                            if let Some(mut metadata) = self.process_metadata.get() {
507                                if !metadata.setup_padding {
508                                    // Write padding header to the beginning of the new app address.
509                                    // This ensures that the linked list is not broken in the event of a
510                                    // powercycle before the app is fully written and loaded.
511
512                                    metadata.setup_padding = true;
513                                    let _ = self.write_padding_app(
514                                        metadata.new_app_length,
515                                        metadata.new_app_start_addr,
516                                    );
517                                    self.process_metadata.set(metadata);
518                                }
519                            }
520                        }
521                    }
522                    Ok(app_length)
523                }
524                Err(_err) => {
525                    // Reset the state to None because we did not find any
526                    // available address for this app.
527                    self.reset_process_loading_metadata();
528                    Err(ErrorCode::FAIL)
529                }
530            }
531        } else {
532            // We are in the wrong mode of operation. Ideally we should never reach
533            // here, but this error exists as a failsafe. The capsule should send
534            // a busy error out to the userland app.
535            Err(ErrorCode::INVAL)
536        }
537    }
538
539    fn write(&self, buffer: SubSliceMut<'static, u8>, offset: usize) -> Result<(), ErrorCode> {
540        match self.state.get() {
541            State::AppWrite => {
542                let res = self.write_buffer(buffer, offset);
543                match res {
544                    Ok(()) => Ok(()),
545                    Err(e) => {
546                        // If we fail here, let us erase the app we just wrote.
547                        self.state.set(State::Fail);
548                        Err(e)
549                    }
550                }
551            }
552            _ => {
553                // We are in the wrong mode of operation. Ideally we should never reach
554                // here, but this error exists as a failsafe. The capsule should send
555                // a busy error out to the userland app.
556                Err(ErrorCode::INVAL)
557            }
558        }
559    }
560
561    fn finalize(&self) -> Result<(), ErrorCode> {
562        match self.state.get() {
563            State::AppWrite => {
564                if let Some(metadata) = self.process_metadata.get() {
565                    match metadata.padding_requirement {
566                        // If we decided we need to write a padding app before the new
567                        // app, we go ahead and do it.
568                        PaddingRequirement::PrePad | PaddingRequirement::PreAndPostPad => {
569                            // Calculate the distance between our app and the previous
570                            // app.
571                            let previous_app_end_addr = metadata.previous_app_end_addr;
572                            let pre_pad_length =
573                                metadata.new_app_start_addr - previous_app_end_addr;
574                            self.state.set(State::Load);
575                            let padding_result =
576                                self.write_padding_app(pre_pad_length, previous_app_end_addr);
577                            match padding_result {
578                                Ok(()) => {
579                                    if config::CONFIG.debug_load_processes {
580                                        debug!("Successfully writing prepadding app");
581                                    }
582                                    Ok(())
583                                }
584                                Err(_e) => {
585                                    // This means we were unable to write the padding
586                                    // app.
587                                    self.reset_process_loading_metadata();
588                                    Err(ErrorCode::FAIL)
589                                }
590                            }
591                        }
592                        // We should never reach here if we are not writing a prepad
593                        // app.
594                        PaddingRequirement::None | PaddingRequirement::PostPad => {
595                            if config::CONFIG.debug_load_processes {
596                                debug!("No PrePad app to write.");
597                            }
598                            self.state.set(State::Load);
599                            self.deferred_call.set();
600                            Ok(())
601                        }
602                    }
603                } else {
604                    Err(ErrorCode::INVAL)
605                }
606            }
607            _ => Err(ErrorCode::INVAL),
608        }
609    }
610
611    fn abort(&self) -> Result<(), ErrorCode> {
612        match self.state.get() {
613            State::Setup | State::AppWrite => {
614                self.state.set(State::Abort);
615                if let Some(metadata) = self.process_metadata.get() {
616                    // Write padding header to the beginning of the new app address.
617                    // This ensures that the flash space is reclaimed for future use.
618                    match self
619                        .write_padding_app(metadata.new_app_length, metadata.new_app_start_addr)
620                    {
621                        Ok(()) => Ok(()),
622                        // If abort() returns ErrorCode::BUSY,
623                        // the userland app is expected to retry abort.
624                        Err(_) => Err(ErrorCode::BUSY),
625                    }
626                } else {
627                    Err(ErrorCode::FAIL)
628                }
629            }
630            _ => {
631                // We are in the wrong mode of operation. Ideally we should never reach
632                // here, but this error exists as a failsafe. The capsule should send
633                // a busy error out to the userland app.
634                Err(ErrorCode::INVAL)
635            }
636        }
637    }
638}
639
640/// Loading interface exposed to the app_loader capsule
641impl<'b, C: Chip + 'static, D: ProcessStandardDebug + 'static, F: NonvolatileStorage<'b>>
642    DynamicProcessLoad for SequentialDynamicBinaryStorage<'_, 'b, C, D, F>
643{
644    fn set_load_client(&self, client: &'static dyn DynamicProcessLoadClient) {
645        self.load_client.set(client);
646    }
647
648    fn load(&self) -> Result<(), ErrorCode> {
649        // We have finished writing the last user data segment, next step is to
650        // load the process.
651        match self.state.get() {
652            State::Load => {
653                if let Some(metadata) = self.process_metadata.get() {
654                    let _ = match self.loader_driver.load_new_process_binary(
655                        metadata.new_app_start_addr,
656                        metadata.new_app_length,
657                    ) {
658                        Ok(()) => Ok::<(), ProcessLoadError>(()),
659                        Err(_e) => {
660                            self.reset_process_loading_metadata();
661                            return Err(ErrorCode::FAIL);
662                        }
663                    };
664                } else {
665                    self.reset_process_loading_metadata();
666                    return Err(ErrorCode::FAIL);
667                }
668                self.reset_process_loading_metadata();
669                Ok(())
670            }
671            _ => Err(ErrorCode::INVAL),
672        }
673    }
674}