class: center, middle # Tock Development Environment .title[.center[]] .left[ Alexandru Radovici, ilustrations by [Mieuneli](http://miau.laura.ro) ] --- # Overview 1. Tock Development Environment 2. Renode Emulator 3. Tock --- # Development Environment You will have to install: - [Visual Studio Code](https://code.visualstudio.com/) - a powerfull source code editor - [RLS](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust) - the Rust extension - [Remote SSH](https://code.visualstudio.com/docs/remote/ssh-tutorial) - the connection to the virtual machine - [VirtualBox](https://www.virtualbox.org/) - a Linux environment¹ with the Tock setup - [Extension Pack](https://download.virtualbox.org/virtualbox/6.1.12/Oracle_VM_VirtualBox_Extension_Pack-6.1.12.vbox-extpack) - you will be able to see you USB devices in guest virtual machine - [Tock Virtual Machine](https://wyliodrinstudio.s3.eu-central-1.amazonaws.com/images/Tock-SAIoT.ova) - Import Appliance - [Modified](https://github.com/UPBIoT/renode-iot)² version of [Renode](https://renode.io/) - [Modified](https://github.com/UPBIoT/tock/tree/saiot)² version of Tock to run in [Renode](https://renode.io/) - Windows: Make sure you select __Allow__ when you get a question from the Firewall ¹If you are running Linux, this step is recommended, not necessary.
²You do need these for simulating Tock --- ## Virtual Box 1. Install the [Extension Pack](https://download.virtualbox.org/virtualbox/6.1.12/Oracle_VM_VirtualBox_Extension_Pack-6.1.12.vbox-extpack) 2. Import Appliance [Tock-SAIoT](https://wyliodrinstudio.s3.eu-central-1.amazonaws.com/images/Tock-SAIoT.ova) --- ## Visual Studio Code Setup the Extensions: - [RLS](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust) - the Rust extension - [Remote SSH](https://code.visualstudio.com/docs/remote/ssh-tutorial) - the connection to the virtual machine .center[.title[]] --- ### SSH connect 1. Start the Virtual Machine with Tock 2. Connect to host: `tock@localhost:2000`¹ (password: `tock`) .center[.title[]] ¹ Due to an issue with the Remote SSH Extension, you will always have to write `tock@localhost:2000`, it will not be remebered. --- # Renode SoC Emulator - Very simple emulation of Cortex-M and STM32F4Discovery - Patches required for Tock (`stm32f4xx` chip) and Renode (pending interrupts) Use our patched [Renode](https://github.com/UPBIoT/renode-iot) Included in the [Tock Virtual Machine](https://wyliodrinstudio.s3.eu-central-1.amazonaws.com/images/Tock-SAIoT.ova) --- ## Using Renode - Use the [Tock Virtual Machine](https://wyliodrinstudio.s3.eu-central-1.amazonaws.com/images/Tock-SAIoT.ova) - Import Appliance - Windows: Make sure you select __Allow__ when you get a question from the Firewall - Use the `stm32f4discovery` board from `/home/tock/tock-saiot/tock/boards/stm32f4discovery`. --- # Tock - A
preemptive
embedded OS (runs on MCUs) - Cortex-M - RISC-V - Uses memory protection (MPU required) - Has separate
kernel and user space
- most embedded OS have the one piece software philosophy - Runs untrusted apps in user space -
Microkernel
architecture - Kernel (and drivers) written in Rust - Apps written in C/C++ or Rust (any language that can be compiled) .right[] --- # Tock Stack .splash[.center[]] Image from https://github.com/tock/tock/tree/master/doc. --- # Let's write some code for Tock In `/wyliodrin` you have: ```bash +-- tock # original Tock repositories | +-- tock # kernel | +-- libtock-c # C userspace | +-- libtock-rs # Rust userspace | +-- /tock-saiot # our Tock version (with POSIX emulation and emulator modification) | +-- tock # kernel | +-- libtock-c # C userspace ``` .card[.small[.center[]]] --- class: split-50 # A few words about how ARM-Cortex M boots .column[ ### Exceptions - Reset - Supervisor - SysTick - Pending SV - Faults ### Interrupts - Events from hardware ] .column[ .card[.large_vertical[.center[]]] ] --- # A few words about how Tock boots In `/home/tock-posix/tock` you have: ```bash +-- tock # kernel | +-- arch # code specific to MCUs (ARM, RISC-V) | +-- boards # code specific to boards (STM32F412G Discovery Kit) | +-- capsules # drivers | +-- chips # code specific to MCUs (STM32F412G, E310, ) | +-- doc # documentation | +-- kernel # actual kernel (scheduler, ipc, memory) | +-- libraries # libraries used by all the source code | +-- tools # scripts for testing on other tools | +-- vagrant # VM setup (different from ours) ``` .small[] --- # Workpoint 1 .top_image[] Use the VS Code shell and the `tree` command to list the Tock folders. Hint: Install `tree` uysing the apt-get command. --- class: split-50 # Interrupt vector and Reset Handler .center[.card[.large_vertical[]] .card[.large_vertical[]]] --- # Build kernel Use the `tock-saiot` folder. The kernel folder is called 'tock', the apps folder is called `libtock-c`. In `boards/stm32f4discovery` run: ```bash tock@tock-dev:~/tock-saiot/tock/boards/stm32f4discovery$ make flash Compiling tock-cells v0.1.0 (/home/tock/tock-saiot/tock/libraries/tock-cells) Compiling tock-registers v0.5.0 (/home/tock/tock-saiot/tock/libraries/tock-register-interface) Compiling enum_primitive v0.1.0 (/home/tock/tock-saiot/tock/libraries/enum_primitive) Compiling tock-rt0 v0.1.0 (/home/tock/tock-saiot/tock/libraries/tock-rt0) Compiling stm32f4discovery v0.1.0 (/home/tock/tock-saiot/tock/boards/stm32f4discovery) Compiling kernel v0.1.0 (/home/tock/tock-saiot/tock/kernel) Compiling cortexm v0.1.0 (/home/tock/tock-saiot/tock/arch/cortex-m) Compiling capsules v0.1.0 (/home/tock/tock-saiot/tock/capsules) Compiling cortexm4 v0.1.0 (/home/tock/tock-saiot/tock/arch/cortex-m4) Compiling components v0.1.0 (/home/tock/tock-saiot/tock/boards/components) Compiling stm32f4xx v0.1.0 (/home/tock/tock-saiot/tock/chips/stm32f4xx) Compiling stm32f407zg v0.1.0 (/home/tock/tock-saiot/tock/chips/stm32f407zg) Finished release [optimized + debuginfo] target(s) in 30.61s text data bss dec hex filename 64929 2072 14312 81313 13da1 /home/tock/tock-saiot/tock/target/thumbv7em-none-eabi/release/stm32f4discovery /home/tock/renode-saiot/renode -e "s @/home/tock/tock-saiot/tock/boards/stm32f4discovery/stm32f4_discovery.resc" 13:31:41.3966 [WARNING] Couldn't start UI - falling back to telnet mode 13:31:41.8170 [INFO] Loaded monitor commands from: /home/tock/renode-saiot/./scripts/monitor.py 13:31:41.8507 [INFO] Monitor available in telnet mode on port 1234 13:31:42.1205 [INFO] Including script: /home/tock/tock-saiot/tock/boards/stm32f4discovery/stm32f4_discovery.resc 13:31:42.1366 [INFO] System bus created. 13:31:43.2308 [INFO] sysbus: Loaded SVD: /tmp/renode-2868/35141cbd-dcd5-4773-9f1d-676bce7619b5.tmp. Name: STM32F40x. Description: STM32F40x. 13:31:43.5522 [INFO] cpu: Guessing VectorTableOffset value to be 0x8000000. 13:31:43.5552 [INFO] cpu: Setting initial values: PC = 0x8007571, SP = 0x20001000. 13:31:43.6870 [INFO] uart2: [+0.27s host +0s virt 0s virt from start] Initialization complete. Entering main loop ``` Now you have a running Tock kernel --- # Workpoint 2 .top_image[] In `main.rs`, find the line that prints the start message, and write a message of your own. ```bash Initialization complete. Entering main loop ``` Example ```bash Welcome from Tock ``` .center[.card[.small_vertical[]]] --- # Processes One process is running at a time - __Running__ - the process is schedulable - __Yielded__ - the process is waiting - __Faulted__ - the process had a fault - Stop process - Restart process - Report fault .right[.card[.small[]]] --- # Build an application Use the `tock-saiot` folder. The kernel folder is called 'tock', the apps folder is called `libtock-c`. In `examples/cc_hello` run: ```bash tock@tock-dev:~/tock-saiot/libtock-c/examples/c_hello$ make DIR ../../libtock/build/cortex-m0 CC ../../libtock/internal/alarm_internal.c CC ../../libtock/internal/nonvolatile_storage_internal.c CC ../../libtock/ieee802154.c CC ../../libtock/alarm_timer.c CC ../../libtock/i2c_master_slave.c CC ../../libtock/max17205.c CC ../../libtock/nrf51_serialization.c CC ../../libtock/aes.c CC ../../libtock/crt0.c CC ../../libtock/unit_test.c CC ../../libtock/gpio_async.c CC ../../libtock/crc.c CC ../../libtock/lps25hb.c CC ../../libtock/button.c CC ../../libtock/rng.c CC ../../libtock/l3gd20.c CC ../../libtock/ninedof.c CC ../../libtock/screen.c CC ../../libtock/ble.c CC ../../libtock/humidity.c CC ../../libtock/tock.c CC ../../libtock/usb.c CC ../../libtock/spi.c CC ../../libtock/app_state.c CC ../../libtock/console.c CC ../../libtock/tmp006.c CC ../../libtock/lsm303dlhc.c CC ../../libtock/gpio.c CC ../../libtock/ipc.c CC ../../libtock/ltc294x.c CC ../../libtock/pca9544a.c CC ../../libtock/analog_comparator.c CC ../../libtock/led.c CC ../../libtock/sys.c CC ../../libtock/st7735.c CC ../../libtock/temperature.c CC ../../libtock/spi_slave.c CC ../../libtock/tsl2561.c CC ../../libtock/udp.c CC ../../libtock/sdcard.c CC ../../libtock/hd44780.c CC ../../libtock/ambient_light.c CC ../../libtock/dac.c CC ../../libtock/adc.c AR ../../libtock/build/cortex-m0/libtock.a DIR ../../libtock/build/cortex-m3 CC ../../libtock/internal/alarm_internal.c CC ../../libtock/internal/nonvolatile_storage_internal.c CC ../../libtock/ieee802154.c CC ../../libtock/alarm_timer.c CC ../../libtock/i2c_master_slave.c CC ../../libtock/max17205.c CC ../../libtock/nrf51_serialization.c CC ../../libtock/aes.c CC ../../libtock/crt0.c CC ../../libtock/unit_test.c CC ../../libtock/gpio_async.c CC ../../libtock/crc.c CC ../../libtock/lps25hb.c CC ../../libtock/button.c CC ../../libtock/rng.c CC ../../libtock/l3gd20.c CC ../../libtock/ninedof.c CC ../../libtock/screen.c CC ../../libtock/ble.c CC ../../libtock/humidity.c CC ../../libtock/tock.c CC ../../libtock/usb.c CC ../../libtock/spi.c CC ../../libtock/app_state.c CC ../../libtock/console.c CC ../../libtock/tmp006.c CC ../../libtock/lsm303dlhc.c CC ../../libtock/gpio.c CC ../../libtock/ipc.c CC ../../libtock/ltc294x.c CC ../../libtock/pca9544a.c CC ../../libtock/analog_comparator.c CC ../../libtock/led.c CC ../../libtock/sys.c CC ../../libtock/st7735.c CC ../../libtock/temperature.c CC ../../libtock/spi_slave.c CC ../../libtock/tsl2561.c CC ../../libtock/udp.c CC ../../libtock/sdcard.c CC ../../libtock/hd44780.c CC ../../libtock/ambient_light.c CC ../../libtock/dac.c CC ../../libtock/adc.c AR ../../libtock/build/cortex-m3/libtock.a DIR ../../libtock/build/cortex-m4 CC ../../libtock/internal/alarm_internal.c CC ../../libtock/internal/nonvolatile_storage_internal.c CC ../../libtock/ieee802154.c CC ../../libtock/alarm_timer.c CC ../../libtock/i2c_master_slave.c CC ../../libtock/max17205.c CC ../../libtock/nrf51_serialization.c CC ../../libtock/aes.c CC ../../libtock/crt0.c CC ../../libtock/unit_test.c CC ../../libtock/gpio_async.c CC ../../libtock/crc.c CC ../../libtock/lps25hb.c CC ../../libtock/button.c CC ../../libtock/rng.c CC ../../libtock/l3gd20.c CC ../../libtock/ninedof.c CC ../../libtock/screen.c CC ../../libtock/ble.c CC ../../libtock/humidity.c CC ../../libtock/tock.c CC ../../libtock/usb.c CC ../../libtock/spi.c CC ../../libtock/app_state.c CC ../../libtock/console.c CC ../../libtock/tmp006.c CC ../../libtock/lsm303dlhc.c CC ../../libtock/gpio.c CC ../../libtock/ipc.c CC ../../libtock/ltc294x.c CC ../../libtock/pca9544a.c CC ../../libtock/analog_comparator.c CC ../../libtock/led.c CC ../../libtock/sys.c CC ../../libtock/st7735.c CC ../../libtock/temperature.c CC ../../libtock/spi_slave.c CC ../../libtock/tsl2561.c CC ../../libtock/udp.c CC ../../libtock/sdcard.c CC ../../libtock/hd44780.c CC ../../libtock/ambient_light.c CC ../../libtock/dac.c CC ../../libtock/adc.c AR ../../libtock/build/cortex-m4/libtock.a DIR build/cortex-m0 CC main.c LD build/cortex-m0/cortex-m0.elf DIR build/cortex-m3 CC main.c LD build/cortex-m3/cortex-m3.elf DIR build/cortex-m4 CC main.c LD build/cortex-m4/cortex-m4.elf Creating "build/cortex-m0/cortex-m0.tbf" Min RAM size from segments in ELF: 508 bytes Number of writeable flash regions: 0 Adding .crt0_header section. Offset: 44 (0x2c). Length: 40 (0x28) bytes. Entry point is in .text section Adding .text section. Offset: 84 (0x54). Length: 732 (0x2dc) bytes. Adding .got section. Offset: 816 (0x330). Length: 32 (0x20) bytes. Adding .data section. Offset: 848 (0x350). Length: 128 (0x80) bytes. Searching for .rel.X sections to add. Adding .rel.data section. Offset: 1020 (0x3fc). Length: 40 (0x28) bytes. TBF Header: version: 2 0x2 header_size: 44 0x2C total_size: 1024 0x400 flags: 1 0x1 init_fn_offset: 41 0x29 protected_size: 0 0x0 minimum_ram_size: 4604 0x11FC Creating "build/cortex-m3/cortex-m3.tbf" Min RAM size from segments in ELF: 508 bytes Number of writeable flash regions: 0 Adding .crt0_header section. Offset: 44 (0x2c). Length: 40 (0x28) bytes. Entry point is in .text section Adding .text section. Offset: 84 (0x54). Length: 520 (0x208) bytes. Adding .got section. Offset: 604 (0x25c). Length: 32 (0x20) bytes. Adding .data section. Offset: 636 (0x27c). Length: 128 (0x80) bytes. Searching for .rel.X sections to add. Adding .rel.data section. Offset: 808 (0x328). Length: 40 (0x28) bytes. TBF Header: version: 2 0x2 header_size: 44 0x2C total_size: 1024 0x400 flags: 1 0x1 init_fn_offset: 41 0x29 protected_size: 0 0x0 minimum_ram_size: 4604 0x11FC Creating "build/cortex-m4/cortex-m4.tbf" Min RAM size from segments in ELF: 508 bytes Number of writeable flash regions: 0 Adding .crt0_header section. Offset: 44 (0x2c). Length: 40 (0x28) bytes. Entry point is in .text section Adding .text section. Offset: 84 (0x54). Length: 520 (0x208) bytes. Adding .got section. Offset: 604 (0x25c). Length: 32 (0x20) bytes. Adding .data section. Offset: 636 (0x27c). Length: 128 (0x80) bytes. Searching for .rel.X sections to add. Adding .rel.data section. Offset: 808 (0x328). Length: 40 (0x28) bytes. TBF Header: version: 2 0x2 header_size: 44 0x2C total_size: 1024 0x400 flags: 1 0x1 init_fn_offset: 41 0x29 protected_size: 0 0x0 minimum_ram_size: 4604 0x11FC Application size report for target cortex-m0: text data bss dec hex filename 732 200 2396 3328 d00 build/cortex-m0/cortex-m0.elf Application size report for target cortex-m3: text data bss dec hex filename 520 200 2396 3116 c2c build/cortex-m3/cortex-m3.elf Application size report for target cortex-m4: text data bss dec hex filename 520 200 2396 3116 c2c build/cortex-m4/cortex-m4.elf ``` Now you have built the `c_hello` application. --- ## Compile the kernel with the app Use the `tock-saiot` folder. The kernel folder is called 'tock', the apps folder is called `libtock-c`. In `boards/stm32f4discovery` edit the application name in the `Makefile` ```bash APP=../../../libtock-c/examples/blink/build/cortex-m4/cortex-m4.tbf # blink id the app name here KERNEL=$(TOCK_ROOT_DIRECTORY)/target/$(TARGET)/debug/$(PLATFORM).elf KERNEL_WITH_APP=$(TOCK_ROOT_DIRECTORY)/target/$(TARGET)/debug/$(PLATFORM)-app.elf ``` ```bash make program ``` Now you should have a Tock kernal and application running. Hint: 1. The application name here is `blink`, change it with another application to run something different. 2. To run several applications, use `cat app1.tbf app2.tbf > app.bundle` and use the `app.bundle` for the `APP` variable --- ## Workpoint 3 .top_image[] Upload the `blink` app. --- ## Scheduler & Handle Process .center[.title[]] --- ## Scheduler The `Scheduler` trait - Round Robun - Cooperative - Priority Queue ```rust /// Trait which any scheduler must implement. pub trait Scheduler
{ /// Decide which process to run next. /// /// The scheduler must decide whether to run a process, and if so, which one. /// If the scheduler chooses not to run a process, it can request that the chip /// enter sleep mode. fn next(&self, kernel: &Kernel) -> SchedulingDecision; /// Inform the scheduler of why the last process stopped executing, and how /// long it executed for. Notably, `execution_time_us` will be `None` /// if the the scheduler requested this process be run cooperatively. fn result(&self, result: StoppedExecutingReason, execution_time_us: Option
); /// Tell the scheduler to execute kernel work such as interrupt bottom halves /// and dynamic deferred calls. Most schedulers will use this default /// implementation, but schedulers which at times wish to defer interrupt /// handling will reimplement it. /// /// Providing this interface allows schedulers to fully manage how /// the main kernel loop executes. For example, a more advanced /// scheduler that attempts to help processes meet their deadlines may /// need to defer bottom half interrupt handling or to selectively service /// certain interrupts. Or, a power aware scheduler may want to selectively /// choose what work to complete at any time to meet power requirements. /// /// Custom implementations of this function must be very careful, however, /// as this function is called in the core kernel loop. unsafe fn execute_kernel_work(&self, chip: &C) { chip.service_pending_interrupts(); DynamicDeferredCall::call_global_instance_while(|| !chip.has_pending_interrupts()); } /// Ask the scheduler whether to take a break from executing userspace /// processes to handle kernel tasks. Most schedulers will use this /// default implementation, which always prioritizes kernel work, but /// schedulers that wish to defer interrupt handling may reimplement it. unsafe fn do_kernel_work_now(&self, chip: &C) -> bool { chip.has_pending_interrupts() || DynamicDeferredCall::global_instance_calls_pending().unwrap_or(false) } /// Ask the scheduler whether to continue trying to execute a process. /// /// Once a process is scheduled the kernel will try to execute it until it has no more /// work to do or exhausts its timeslice. The kernel will call this function before /// every loop to check with the scheduler if it wants to continue trying to execute /// this process. /// /// Most /// schedulers will use this default implementation, which causes the `do_process()` /// loop to return if there are interrupts or deferred calls that need to be serviced. /// However, schedulers which wish to defer interrupt handling may change this, or /// priority schedulers which wish to check if the execution of the current process /// has caused a higher priority process to become ready (such as in the case of IPC). /// If this returns `false`, then `do_process` will exit with a `KernelPreemption`. /// /// `id` is the identifier of the currently active process. unsafe fn continue_process(&self, _id: AppId, chip: &C) -> bool { !(chip.has_pending_interrupts() || DynamicDeferredCall::global_instance_calls_pending().unwrap_or(false)) } } pub enum SchedulingDecision { /// Tell the kernel to run the specified process with the passed timeslice. /// If `None` is passed as a timeslice, the process will be run cooperatively. RunProcess((AppId, Option
)), /// Tell the kernel to go to sleep. Notably, if the scheduler asks the kernel /// to sleep when kernel tasks are ready, the kernel will not sleep, and will /// instead restart the main loop and call `next()` again. TrySleep, } pub enum StoppedExecutingReason { /// The process returned because it is no longer ready to run. NoWorkLeft, /// The process faulted, and the board restart policy was configured such that /// it was not restarted and there was not a kernel panic. StoppedFaulted, /// The kernel stopped the process. Stopped, /// The process was preempted because its timeslice expired. TimesliceExpired, /// The process returned because it was preempted by the kernel. /// This can mean that kernel work became ready (most likely because an interrupt fired /// and the kernel thread needs to execute the bottom half of the /// interrupt), or because the scheduler no longer wants to execute that /// process. KernelPreemption, } ``` --- class: split-50 ## System Call .column[ API provided by the OS - ABI (Application Binary Interface) - uses the `svc` (or similar) instruction Applications request an action from the OS .card[.small_vertical[]] ] .column[ .center[.splash_vertical[]] ] --- ## Tock System Calls 0. Yield 1. Subscribe 2. Command 3. Allow 4. Memop .right[ .card[.small[]] .card[.small[]] .card[.small[]] .card[.small[]] .card[.small[]] .card[.small[]] ] --- ### 0: Yield Yield transitions the current process from the Running to the Yielded state, and the process will not execute again until another callback re-schedules the process. If a process has enqueued callbacks waiting to execute when Yield is called, the process immediately re-enters the Running state and the first callback runs. ```rust yield() ``` ##### Arguments None. ##### Return None. --- ### 1: Subscribe Subscribe assigns callback functions to be executed in response to various events. - a callback function has a *callback ID* (`driver`,`subscribe_number`), - null pointer disables the callback ```rust subscribe(driver: u32, subscribe_number: u32, callback: u32, userdata: u32) -> ReturnCode as u32 ``` ##### Arguments - `driver`: An integer specifying which driver to call. - `subscribe_number`: An integer index for which function is being subscribed. - `callback`: A pointer to a callback function to be executed when this event occurs. `void callback(int arg1, int arg2, int arg3, void* data)`. - `userdata`: A pointer to a value of any type that will be passed back ##### Return - `ENODEVICE` if `driver` does not refer to a valid kernel driver. - `ENOSUPPORT` if the driver exists but doesn't support the `subscribe_number`. - Other return codes based on the specific driver. --- ### 2: Command Command instructs the driver to perform a specific action. ```rust command(driver: u32, command_number: u32, argument1: u32, argument2: u32) -> ReturnCode as u32 ``` #### Arguments - `driver`: An integer specifying which driver to call. - `command_number`: An integer specifying the requested command. - `argument1`: A command-specific argument. - `argument2`: A command-specific argument. - One Tock convention with the Command syscall is that command number 0 will always return a value of 0 or greater if the driver is supported. #### Return - `ENODEVICE` if `driver` does not refer to a valid kernel driver. - `ENOSUPPORT` if the driver exists but doesn't support the `command_number`. - Other return codes based on the specific driver. --- ### 3: Allow Allow shares memory buffers between the kernel and application. - null pointer revokes sharing a region. ```rust allow(driver: u32, allow_number: u32, pointer: usize, size: u32) -> ReturnCode as u32 ``` #### Arguments - `driver`: An integer specifying which driver should be granted access. - `allow_number`: A driver-specific integer specifying the purpose of this buffer. - `pointer`: A pointer to the start of the buffer in the process memory space. - `size`: An integer number of bytes specifying the length of the buffer. #### Return - `ENODEVICE` if `driver` does not refer to a valid kernel driver. - `ENOSUPPORT` if the driver exists but doesn't support the `allow_number`. - `EINVAL` the buffer referred to by `pointer` and `size` lies completely or partially outside of the processes addressable RAM. - Other return codes based on the specific driver. --- ### 4: Memop Memop expands the memory segment available to the process, allows the process to retrieve pointers to its allocated memory space, provides a mechanism for the process to tell the kernel where its stack and heap start, and other operations involving process memory. ```rust memop(op_type: u32, argument: u32) -> [[ VARIES ]] as u32 ``` #### Arguments - `op_type`: An integer indicating whether this is a `brk` (0), a `sbrk` (1), or another memop call. - `argument`: The argument to `brk`, `sbrk`, or other call. Each memop operation is specific and details of each call can be found in the [memop syscall documentation](syscalls/memop.md). #### Return - Dependent on the particular memop call. --- ## Workpoint 4 .top_image[] Enable the system calls trace in `kernel/src/config.rs`. 1. Upload an app that prints a text on the shell using `printf`. - How many system calls is printf using? - What is the driver number of the driver used for printing? 2. Upload the blink app and look at the system calls trace. - What is led's driver number? --- ## Faults The kernal and the processes can fault .pre[ ````terminal ---| Fault Status |--- Data Access Violation: true Forced Hard Fault: true Faulting Memory Address: 0x00000000 Fault Status Register (CFSR): 0x00000082 Hard Fault Status Register (HFSR): 0x40000000 ---| App Status |--- App: crash_dummy - [Fault] Events Queued: 0 Syscall Count: 0 Dropped Callback Count: 0 Restart Count: 0 Last Syscall: None ╔═══════════╤══════════════════════════════════════════╗ ║ Address │ Region Name Used | Allocated (bytes) ║ ╚0x20006000═╪══════════════════════════════════════════╝ │ ▼ Grant 948 | 948 0x20005C4C ┼─────────────────────────────────────────── │ Unused 0x200049F0 ┼─────────────────────────────────────────── │ ▲ Heap 0 | 4700 S 0x200049F0 ┼─────────────────────────────────────────── R │ Data 496 | 496 A 0x20004800 ┼─────────────────────────────────────────── M │ ▼ Stack 72 | 2048 0x200047B8 ┼─────────────────────────────────────────── │ Unused 0x20004000 ┴─────────────────────────────────────────── ..... 0x00030400 ┬─────────────────────────────────────────── F │ App Flash 976 L 0x00030030 ┼─────────────────────────────────────────── A │ Protected 48 S 0x00030000 ┴─────────────────────────────────────────── H R0 : 0x00000000 R6 : 0x20004894 R1 : 0x00000001 R7 : 0x20004000 R2 : 0x00000000 R8 : 0x00000000 R3 : 0x00000000 R10: 0x00000000 R4 : 0x00000000 R11: 0x00000000 R5 : 0x20004800 R12: 0x12E36C82 R9 : 0x20004800 (Static Base Register) SP : 0x200047B8 (Process Stack Pointer) LR : 0x000301B7 PC : 0x000300AA YPC : 0x000301B6 APSR: N 0 Z 1 C 1 V 0 Q 0 GE 0 0 0 0 EPSR: ICI.IT 0x00 ThumbBit true Cortex-M MPU Region 0: base: 0x20004000, length: 8192 bytes; ReadWrite (0x3) Region 1: base: 0x30000, length: 1024 bytes; ReadOnly (0x6) Region 2: Unused Region 3: Unused Region 4: Unused Region 5: Unused Region 6: Unused Region 7: Unused To debug, run `make debug RAM_START=0x20004000 FLASH_INIT=0x30059` in the app's folder and open the .lst file. ````] --- ## Workpoint 5 .top_image[] 1. Write and upload and app that faults. ```c int main(void) { int *s = NULL; *s = 0; return 0; } ``` 2. Modify the app fault policy so that it does not panic when an app faults - hint: `main.rs` serach for `FAULT_RESPONSE`.