qemu_rv32_virt_tutorial/
main.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 2022.
4
5//! Board file for qemu-system-riscv32 "virt" machine type
6
7#![no_std]
8#![no_main]
9
10use kernel::capabilities;
11use kernel::component::Component;
12use kernel::deferred_call::DeferredCallClient;
13use kernel::platform::KernelResources;
14use kernel::platform::SyscallDriverLookup;
15use kernel::{create_capability, debug, static_init};
16
17mod checker_credentials_not_required;
18
19//------------------------------------------------------------------------------
20// BOARD CONSTANTS
21//------------------------------------------------------------------------------
22
23pub const NUM_PROCS: usize = 4;
24
25// How should the kernel respond when a process faults.
26const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
27    capsules_system::process_policies::PanicFaultPolicy {};
28
29// How many credential verifying keys the kernel supports.
30const NUM_CREDENTIAL_KEYS: usize = 1;
31// Length of the key used for the ECDSA-P256 signature.
32const SIGNATURE_KEY_LEN: usize = 64;
33// Length of the hash used for the signature (SHA-256).
34const SIGNATURE_HASH_LEN: usize = 32;
35// Length of the ECDSA-P256 signature.
36const SIGNATURE_SIG_LEN: usize = 64;
37
38//------------------------------------------------------------------------------
39// TYPE DEFINITIONS
40//------------------------------------------------------------------------------
41
42type ScreenDriver = capsules_extra::screen::screen::Screen<'static>;
43type ScreenAdapter = capsules_extra::screen::screen_adapters::ScreenARGB8888ToMono8BitPage<
44    'static,
45    qemu_rv32_virt_lib::ScreenHw,
46>;
47type ScreenSplitUser = components::screen::ScreenSplitUserComponentType<ScreenAdapter>;
48type ScreenOnLed = components::screen_on::ScreenOnLedComponentType<ScreenSplitUser, 4, 128, 64>;
49type ScreenOnLedSingle =
50    capsules_extra::screen::screen_on_led::ScreenOnLedSingle<'static, ScreenOnLed>;
51
52type LedDriver = capsules_core::led::LedDriver<'static, ScreenOnLedSingle, 4>;
53
54type ButtonDriver = capsules_extra::button_keyboard::ButtonKeyboard<'static>;
55
56type Verifier = ecdsa_sw::p256_verifier::EcdsaP256SignatureVerifier<'static>;
57type SignatureVerifyInMemoryKeys =
58    components::signature_verify_in_memory_keys::SignatureVerifyInMemoryKeysComponentType<
59        Verifier,
60        NUM_CREDENTIAL_KEYS,
61        SIGNATURE_KEY_LEN,
62        SIGNATURE_HASH_LEN,
63        SIGNATURE_SIG_LEN,
64    >;
65type SignatureChecker = components::appid::checker_signature::AppCheckerSignatureComponentType<
66    SignatureVerifyInMemoryKeys,
67    capsules_extra::sha256::Sha256Software<'static>,
68    SIGNATURE_HASH_LEN,
69    SIGNATURE_SIG_LEN,
70>;
71
72//------------------------------------------------------------------------------
73// PLATFORM AND SYSCALL HANDLING
74//------------------------------------------------------------------------------
75
76struct Platform {
77    base: qemu_rv32_virt_lib::QemuRv32VirtPlatform,
78    screen: Option<&'static ScreenDriver>,
79    led: Option<&'static LedDriver>,
80    buttons: Option<&'static ButtonDriver>,
81}
82
83impl SyscallDriverLookup for Platform {
84    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
85    where
86        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
87    {
88        match driver_num {
89            capsules_extra::screen::screen::DRIVER_NUM => {
90                if let Some(screen_driver) = self.screen {
91                    f(Some(screen_driver))
92                } else {
93                    f(None)
94                }
95            }
96            capsules_core::led::DRIVER_NUM => {
97                if let Some(led_driver) = self.led {
98                    f(Some(led_driver))
99                } else {
100                    f(None)
101                }
102            }
103            capsules_core::button::DRIVER_NUM => {
104                if let Some(button_driver) = self.buttons {
105                    f(Some(button_driver))
106                } else {
107                    f(None)
108                }
109            }
110
111            _ => self.base.with_driver(driver_num, f),
112        }
113    }
114}
115
116impl KernelResources<qemu_rv32_virt_lib::Chip> for Platform {
117    type SyscallDriverLookup = Self;
118    type SyscallFilter = <qemu_rv32_virt_lib::QemuRv32VirtPlatform as KernelResources<
119        qemu_rv32_virt_lib::Chip,
120    >>::SyscallFilter;
121    type ProcessFault = <qemu_rv32_virt_lib::QemuRv32VirtPlatform as KernelResources<
122        qemu_rv32_virt_lib::Chip,
123    >>::ProcessFault;
124    type Scheduler = <qemu_rv32_virt_lib::QemuRv32VirtPlatform as KernelResources<
125        qemu_rv32_virt_lib::Chip,
126    >>::Scheduler;
127    type SchedulerTimer = <qemu_rv32_virt_lib::QemuRv32VirtPlatform as KernelResources<
128        qemu_rv32_virt_lib::Chip,
129    >>::SchedulerTimer;
130    type WatchDog = <qemu_rv32_virt_lib::QemuRv32VirtPlatform as KernelResources<
131        qemu_rv32_virt_lib::Chip,
132    >>::WatchDog;
133    type ContextSwitchCallback = <qemu_rv32_virt_lib::QemuRv32VirtPlatform as KernelResources<
134        qemu_rv32_virt_lib::Chip,
135    >>::ContextSwitchCallback;
136
137    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
138        self
139    }
140    fn syscall_filter(&self) -> &Self::SyscallFilter {
141        self.base.syscall_filter()
142    }
143    fn process_fault(&self) -> &Self::ProcessFault {
144        self.base.process_fault()
145    }
146    fn scheduler(&self) -> &Self::Scheduler {
147        self.base.scheduler()
148    }
149    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
150        self.base.scheduler_timer()
151    }
152    fn watchdog(&self) -> &Self::WatchDog {
153        self.base.watchdog()
154    }
155    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
156        self.base.context_switch_callback()
157    }
158}
159
160/// Main function called after RAM initialized.
161#[no_mangle]
162pub unsafe fn main() {
163    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
164
165    let (board_kernel, base_platform, chip) = qemu_rv32_virt_lib::start();
166
167    //--------------------------------------------------------------------------
168    // SCREEN
169    //--------------------------------------------------------------------------
170
171    let (screen, led) = base_platform
172        .virtio_gpu_screen
173        .map_or((None, None), |screen| {
174            let screen_split = components::screen::ScreenSplitMuxComponent::new(screen).finalize(
175                components::screen_split_mux_component_static!(ScreenAdapter),
176            );
177
178            let screen_split_userspace =
179                components::screen::ScreenSplitUserComponent::new(screen_split, 0, 0, 128, 64)
180                    .finalize(components::screen_split_user_component_static!(
181                        ScreenAdapter
182                    ));
183
184            let screen_split_kernel =
185                components::screen::ScreenSplitUserComponent::new(screen_split, 0, 64, 128, 64)
186                    .finalize(components::screen_split_user_component_static!(
187                        ScreenAdapter
188                    ));
189
190            let screen = components::screen::ScreenComponent::new(
191                board_kernel,
192                capsules_extra::screen::screen::DRIVER_NUM,
193                screen_split_userspace,
194                None,
195            )
196            .finalize(components::screen_component_static!(1032));
197
198            let screen_on_leds =
199                components::screen_on::ScreenOnLedComponent::new(screen_split_kernel).finalize(
200                    components::screen_on_led_component_static!(ScreenSplitUser, 4, 128, 64),
201                );
202
203            let led =
204                components::led::LedsComponent::new().finalize(components::led_component_static!(
205                    ScreenOnLedSingle,
206                    capsules_extra::screen::screen_on_led::ScreenOnLedSingle::new(
207                        screen_on_leds,
208                        0
209                    ),
210                    capsules_extra::screen::screen_on_led::ScreenOnLedSingle::new(
211                        screen_on_leds,
212                        1
213                    ),
214                    capsules_extra::screen::screen_on_led::ScreenOnLedSingle::new(
215                        screen_on_leds,
216                        2
217                    ),
218                    capsules_extra::screen::screen_on_led::ScreenOnLedSingle::new(
219                        screen_on_leds,
220                        3
221                    ),
222                ));
223
224            (Some(screen), Some(led))
225        });
226
227    //--------------------------------------------------------------------------
228    // SIMULATED BUTTONS USING KEYBOARD
229    //--------------------------------------------------------------------------
230
231    let buttons = base_platform.virtio_input_keyboard.map(|keyboard| {
232        let key_mappings = static_init!(
233            [u16; 4],
234            [
235                103, // UP
236                14,  // BACKSPACE
237                108, // DOWN
238                28,  // ENTER
239            ]
240        );
241
242        components::button_keyboard::KeyboardButtonComponent::new(
243            board_kernel,
244            capsules_extra::button_keyboard::DRIVER_NUM,
245            keyboard,
246            key_mappings,
247        )
248        .finalize(components::keyboard_button_component_static!())
249    });
250
251    let platform = Platform {
252        base: base_platform,
253        screen,
254        led,
255        buttons,
256    };
257
258    // Start the process console:
259    let _ = platform.base.pconsole.start();
260
261    //--------------------------------------------------------------------------
262    // CREDENTIAL CHECKING
263    //--------------------------------------------------------------------------
264
265    // Create the software-based SHA engine.
266    let sha = components::sha::ShaSoftware256Component::new()
267        .finalize(components::sha_software_256_component_static!());
268
269    // Create the credential checker.
270    //
271    // Setup an example key.
272    //
273    // - `ec-secp256r1-priv-key.pem`:
274    //   ```
275    //   -----BEGIN EC PRIVATE KEY-----
276    //   MHcCAQEEIGU0zCXHLqxDmrHHAWEQP5zNfWRQrAiIpH9YwxHlqysmoAoGCCqGSM49
277    //   AwEHoUQDQgAE4BM6kKdKNWFRjuFECfFpwc9q239+Uvi3QXniTVdBI1IuthIDs4UQ
278    //   5fMlB2KPVJWCV0VQvaPiF+g0MIkmTCNisQ==
279    //   -----END EC PRIVATE KEY-----
280    //   ```
281    //
282    // - `ec-secp256r1-pub-key.pem`:
283    //   ```
284    //   -----BEGIN PUBLIC KEY-----
285    //   MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4BM6kKdKNWFRjuFECfFpwc9q239+
286    //   Uvi3QXniTVdBI1IuthIDs4UQ5fMlB2KPVJWCV0VQvaPiF+g0MIkmTCNisQ==
287    //   -----END PUBLIC KEY-----
288    //   ```
289    //
290    // You can add the correct signature to a TBF by saving the private key to
291    // a file and then running:
292    //
293    //     tockloader tbf credential add ecdsap256 --private-key ec-secp256r1-priv-key.pem
294    //
295    let verifying_key0 = kernel::static_init!(
296        [u8; SIGNATURE_KEY_LEN],
297        [
298            0xe0, 0x13, 0x3a, 0x90, 0xa7, 0x4a, 0x35, 0x61, 0x51, 0x8e, 0xe1, 0x44, 0x09, 0xf1,
299            0x69, 0xc1, 0xcf, 0x6a, 0xdb, 0x7f, 0x7e, 0x52, 0xf8, 0xb7, 0x41, 0x79, 0xe2, 0x4d,
300            0x57, 0x41, 0x23, 0x52, 0x2e, 0xb6, 0x12, 0x03, 0xb3, 0x85, 0x10, 0xe5, 0xf3, 0x25,
301            0x07, 0x62, 0x8f, 0x54, 0x95, 0x82, 0x57, 0x45, 0x50, 0xbd, 0xa3, 0xe2, 0x17, 0xe8,
302            0x34, 0x30, 0x89, 0x26, 0x4c, 0x23, 0x62, 0xb1
303        ]
304    );
305    let verifying_keys = kernel::static_init!(
306        [&'static mut [u8; SIGNATURE_KEY_LEN]; NUM_CREDENTIAL_KEYS],
307        [verifying_key0]
308    );
309    // Setup the ECDSA-P256 verifier.
310    let ecdsa_p256_verifying_key =
311        kernel::static_init!([u8; SIGNATURE_KEY_LEN], [0; SIGNATURE_KEY_LEN]);
312    let ecdsa_p256_verifier = kernel::static_init!(
313        ecdsa_sw::p256_verifier::EcdsaP256SignatureVerifier<'static>,
314        ecdsa_sw::p256_verifier::EcdsaP256SignatureVerifier::new(ecdsa_p256_verifying_key)
315    );
316    ecdsa_p256_verifier.register();
317
318    // Setup the in-memory key selector.
319    let verifier_multiple_keys =
320        components::signature_verify_in_memory_keys::SignatureVerifyInMemoryKeysComponent::new(
321            ecdsa_p256_verifier,
322            verifying_keys,
323        )
324        .finalize(
325            components::signature_verify_in_memory_keys_component_static!(
326                Verifier,
327                NUM_CREDENTIAL_KEYS,
328                SIGNATURE_KEY_LEN,
329                SIGNATURE_HASH_LEN,
330                SIGNATURE_SIG_LEN,
331            ),
332        );
333
334    // Policy checks for a valid EcdsaNistP256 signature.
335    let checking_policy_signature =
336        components::appid::checker_signature::AppCheckerSignatureComponent::new(
337            sha,
338            verifier_multiple_keys,
339            tock_tbf::types::TbfFooterV2CredentialsType::EcdsaNistP256,
340        )
341        .finalize(components::app_checker_signature_component_static!(
342            SignatureVerifyInMemoryKeys,
343            capsules_extra::sha256::Sha256Software<'static>,
344            SIGNATURE_HASH_LEN,
345            SIGNATURE_SIG_LEN,
346        ));
347
348    // Wrap the policy checker with a custom version that does not require valid
349    // credentials to load the app. We are ok with this for this tutorial
350    // because the verifying key (or lack thereof) is encoded in the AppId so
351    // we can still check if an app is signed or not.
352    let checking_policy = static_init!(
353        checker_credentials_not_required::AppCheckerCredentialsNotRequired<
354            SignatureChecker,
355        >,
356        checker_credentials_not_required::AppCheckerCredentialsNotRequired::new(
357            checking_policy_signature
358        ),
359    );
360
361    // Create the AppID assigner.
362    let assigner = components::appid::assigner_name::AppIdAssignerNamesComponent::new()
363        .finalize(components::appid_assigner_names_component_static!());
364
365    // Create the process checking machine.
366    let checker = components::appid::checker::ProcessCheckerMachineComponent::new(checking_policy)
367        .finalize(components::process_checker_machine_component_static!());
368
369    //--------------------------------------------------------------------------
370    // STORAGE PERMISSIONS
371    //--------------------------------------------------------------------------
372
373    let storage_permissions_policy =
374        components::storage_permissions::null::StoragePermissionsNullComponent::new().finalize(
375            components::storage_permissions_null_component_static!(
376                qemu_rv32_virt_lib::Chip,
377                kernel::process::ProcessStandardDebugFull,
378            ),
379        );
380
381    //--------------------------------------------------------------------------
382    // PROCESS LOADING
383    //--------------------------------------------------------------------------
384
385    // These symbols are defined in the standard Tock linker script.
386    extern "C" {
387        /// Beginning of the ROM region containing app images.
388        static _sapps: u8;
389        /// End of the ROM region containing app images.
390        static _eapps: u8;
391        /// Beginning of the RAM region for app memory.
392        static mut _sappmem: u8;
393        /// End of the RAM region for app memory.
394        static _eappmem: u8;
395    }
396
397    let app_flash = core::slice::from_raw_parts(
398        core::ptr::addr_of!(_sapps),
399        core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
400    );
401    let app_memory = core::slice::from_raw_parts_mut(
402        core::ptr::addr_of_mut!(_sappmem),
403        core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
404    );
405
406    // Create and start the asynchronous process loader.
407    let _loader = components::loader::sequential::ProcessLoaderSequentialComponent::new(
408        checker,
409        board_kernel,
410        chip,
411        &FAULT_RESPONSE,
412        assigner,
413        storage_permissions_policy,
414        app_flash,
415        app_memory,
416    )
417    .finalize(components::process_loader_sequential_component_static!(
418        qemu_rv32_virt_lib::Chip,
419        kernel::process::ProcessStandardDebugFull,
420        NUM_PROCS
421    ));
422
423    debug!("Starting main kernel loop.");
424
425    board_kernel.kernel_loop(
426        &platform,
427        chip,
428        Some(&platform.base.ipc),
429        &main_loop_capability,
430    );
431}