kernel/
memop.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//! Implementation of the MEMOP family of syscalls.
6
7use crate::process::Process;
8use crate::syscall::SyscallReturn;
9use crate::utilities::capability_ptr::{CapabilityPtr, CapabilityPtrPermissions};
10use crate::ErrorCode;
11
12/// Handle the `memop` syscall.
13///
14/// ### `memop_num`
15///
16/// - `0`: BRK. Change the location of the program break and return a
17///   SyscallReturn.
18/// - `1`: SBRK. Change the location of the program break and return the
19///   previous break address.
20/// - `2`: Get the address of the start of the application's RAM allocation.
21/// - `3`: Get the address pointing to the first address after the end of the
22///   application's RAM allocation.
23/// - `4`: Get the address of the start of the application's flash region. This
24///   is where the TBF header is located.
25/// - `5`: Get the address pointing to the first address after the end of the
26///   application's flash region.
27/// - `6`: Get the address of the lowest address of the grant region for the
28///   app.
29/// - `7`: Get the number of writeable flash regions defined in the header of
30///   this app.
31/// - `8`: Get the start address of the writeable region indexed from 0 by r1.
32///   Returns (void*) -1 on failure, meaning the selected writeable region
33///   does not exist.
34/// - `9`: Get the end address of the writeable region indexed by r1. Returns
35///   (void*) -1 on failure, meaning the selected writeable region does not
36///   exist.
37/// - `10`: Specify where the start of the app stack is. This tells the kernel
38///   where the app has put the start of its stack. This is not strictly
39///   necessary for correct operation, but allows for better debugging if the
40///   app crashes.
41/// - `11`: Specify where the start of the app heap is. This tells the kernel
42///   where the app has put the start of its heap. This is not strictly
43///   necessary for correct operation, but allows for better debugging if the
44///   app crashes.
45pub(crate) fn memop(process: &dyn Process, op_type: usize, r1: usize) -> SyscallReturn {
46    match op_type {
47        // Op Type 0: BRK
48        0 => process
49            .brk(r1 as *const u8)
50            .map(|_| SyscallReturn::Success)
51            .unwrap_or(SyscallReturn::Failure(ErrorCode::NOMEM)),
52
53        // Op Type 1: SBRK
54        1 => process
55            .sbrk(r1 as isize)
56            .map(|addr| SyscallReturn::SuccessPtr(addr))
57            .unwrap_or(SyscallReturn::Failure(ErrorCode::NOMEM)),
58
59        // Op Type 2: Process memory start
60        2 => SyscallReturn::SuccessPtr(unsafe {
61            let addresses = process.get_addresses();
62            CapabilityPtr::new_with_authority(
63                addresses.sram_start as *const _,
64                addresses.sram_start,
65                addresses.sram_app_brk - addresses.sram_start,
66                CapabilityPtrPermissions::ReadWrite,
67            )
68        }),
69
70        // Op Type 3: Process memory end
71        3 => SyscallReturn::SuccessPtr(unsafe {
72            let addresses = process.get_addresses();
73            CapabilityPtr::new_with_authority(
74                addresses.sram_end as *const _,
75                addresses.sram_start,
76                addresses.sram_end - addresses.sram_start,
77                CapabilityPtrPermissions::ReadWrite,
78            )
79        }),
80
81        // Op Type 4: Process flash start
82        4 => SyscallReturn::SuccessPtr(unsafe {
83            let addresses = process.get_addresses();
84            CapabilityPtr::new_with_authority(
85                addresses.flash_start as *const _,
86                addresses.flash_start,
87                addresses.flash_end - addresses.flash_start,
88                CapabilityPtrPermissions::Execute,
89            )
90        }),
91
92        // Op Type 5: Process flash end
93        5 => SyscallReturn::SuccessPtr(unsafe {
94            let addresses = process.get_addresses();
95            CapabilityPtr::new_with_authority(
96                addresses.flash_end as *const _,
97                addresses.flash_start,
98                addresses.flash_end - addresses.flash_start,
99                CapabilityPtrPermissions::Execute,
100            )
101        }),
102
103        // Op Type 6: Grant region begin
104        6 => SyscallReturn::SuccessAddr(process.get_addresses().sram_grant_start),
105
106        // Op Type 7: Number of defined writeable regions in the TBF header.
107        7 => SyscallReturn::SuccessU32(process.number_writeable_flash_regions() as u32),
108
109        // Op Type 8: The start address of the writeable region indexed by r1.
110        8 => {
111            let flash_start = process.get_addresses().flash_start;
112            let (offset, size) = process.get_writeable_flash_region(r1);
113            if size == 0 {
114                SyscallReturn::Failure(ErrorCode::FAIL)
115            } else {
116                SyscallReturn::SuccessPtr(unsafe {
117                    CapabilityPtr::new_with_authority(
118                        (flash_start + offset) as *const _,
119                        flash_start + offset,
120                        size,
121                        CapabilityPtrPermissions::ReadWrite,
122                    )
123                })
124            }
125        }
126
127        // Op Type 9: The end address of the writeable region indexed by r1.
128        // Returns (void*) -1 on failure, meaning the selected writeable region
129        // does not exist.
130        9 => {
131            let flash_start = process.get_addresses().flash_start;
132            let (offset, size) = process.get_writeable_flash_region(r1);
133            if size == 0 {
134                SyscallReturn::Failure(ErrorCode::FAIL)
135            } else {
136                SyscallReturn::SuccessPtr(unsafe {
137                    CapabilityPtr::new_with_authority(
138                        (flash_start + offset + size) as *const _,
139                        flash_start + offset,
140                        size,
141                        CapabilityPtrPermissions::ReadWrite,
142                    )
143                })
144            }
145        }
146
147        // Op Type 10: Specify where the start of the app stack is.
148        10 => {
149            process.update_stack_start_pointer(r1 as *const u8);
150            SyscallReturn::Success
151        }
152
153        // Op Type 11: Specify where the start of the app heap is.
154        11 => {
155            process.update_heap_start_pointer(r1 as *const u8);
156            SyscallReturn::Success
157        }
158
159        _ => SyscallReturn::Failure(ErrorCode::NOSUPPORT),
160    }
161}