├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md └── workflows │ ├── pr.yml │ ├── push.yml │ ├── test.yml │ └── trigger.yml ├── .gitignore ├── .licenseignore ├── .stylefilter ├── CMakeLists.txt ├── Findcamkes-arm-vm.cmake ├── Findcamkes-vm.cmake ├── LICENSE.md ├── LICENSES ├── BSD-2-Clause.txt ├── CC-BY-SA-4.0.txt ├── GPL-2.0-only.txt ├── LGPL-2.0-or-later.txt └── MIT.txt ├── README.md ├── arm_vm_helpers.cmake ├── camkes_vm_helpers.cmake ├── camkes_vm_settings.cmake ├── components ├── Echo │ ├── CMakeLists.txt │ ├── Echo.camkes │ └── src │ │ └── echo.c ├── Firewall │ ├── CMakeLists.txt │ ├── Firewall.camkes │ └── src │ │ └── firewall.c ├── Init │ ├── Init.camkes │ ├── include │ │ └── crossvm.h │ ├── src │ │ ├── camkes_vm_interfaces.h │ │ ├── crossvm.c │ │ ├── hpet.c │ │ ├── hpet.h │ │ ├── i8254.c │ │ ├── main.c │ │ ├── mc146818rtc.c │ │ ├── serial.c │ │ ├── timers.h │ │ ├── virtio_blk.c │ │ ├── virtio_blk.h │ │ ├── virtio_con.c │ │ ├── virtio_con.h │ │ ├── virtio_irq.h │ │ ├── virtio_net.c │ │ ├── virtio_net.h │ │ ├── virtio_net_vswitch.c │ │ ├── virtio_net_vswitch.h │ │ ├── virtio_vsock.c │ │ └── virtio_vsock.h │ └── templates │ │ ├── seL4ExcludeGuestPAddr.template.c │ │ ├── seL4ExtraRAM.template.c │ │ ├── seL4GuestMaps.template.c │ │ ├── seL4InitConnection.template.c │ │ ├── seL4VMIOPorts.template.c │ │ ├── seL4VMIRQs.template.c │ │ └── seL4VMPCIDevices.template.c ├── Sataserver │ ├── CMakeLists.txt │ ├── Sataserver.camkes │ ├── include │ │ ├── plat │ │ │ ├── empty │ │ │ │ └── plat │ │ │ │ │ └── sata.h │ │ │ └── pc99 │ │ │ │ ├── optiplex │ │ │ │ └── plat │ │ │ │ │ └── sata.h │ │ │ │ └── supermicro │ │ │ │ └── plat │ │ │ │ └── sata.h │ │ └── sataserver.h │ └── src │ │ └── sataserver.c ├── StringReverse │ ├── CMakeLists.txt │ ├── StringReverse.camkes │ ├── include │ │ └── string_reverse.h │ └── src │ │ └── string_reverse.c ├── UDPServer │ ├── CMakeLists.txt │ ├── UDPServer.camkes │ └── src │ │ └── udpserver.c ├── VM │ ├── PIC.camkes │ ├── configurations │ │ ├── connections.h │ │ ├── sata.h │ │ └── vm.h │ └── vm.camkes └── VM_Arm │ ├── CMakeLists.txt │ ├── VM.camkes │ ├── configurations │ └── vm.h │ ├── docs │ └── vm_memory_configuration.md │ ├── include │ └── vmlinux.h │ ├── plat_include │ ├── exynos5410 │ │ └── plat │ │ │ └── vmlinux.h │ ├── exynos5422 │ │ └── plat │ │ │ └── vmlinux.h │ ├── odroidc2 │ │ └── plat │ │ │ └── vmlinux.h │ ├── qemu-arm-virt │ │ └── plat │ │ │ └── vmlinux.h │ ├── tk1 │ │ └── plat │ │ │ └── vmlinux.h │ ├── tx1 │ │ └── plat │ │ │ └── vmlinux.h │ ├── tx2 │ │ └── plat │ │ │ └── vmlinux.h │ ├── ultra96v2 │ │ └── plat │ │ │ ├── smc.h │ │ │ └── vmlinux.h │ └── zynqmp │ │ └── plat │ │ ├── smc.h │ │ └── vmlinux.h │ ├── src │ ├── crossvm.c │ ├── fdt_manipulation.c │ ├── fdt_manipulation.h │ ├── main.c │ └── modules │ │ ├── init_ram.c │ │ ├── map_frame_hack.c │ │ ├── plat │ │ ├── exynos5410 │ │ │ └── init.c │ │ └── tk1 │ │ │ ├── device_fwd.c │ │ │ └── init.c │ │ ├── virtio_con.c │ │ ├── virtio_net_arping.c │ │ ├── virtio_net_virtqueue.c │ │ └── vuart_init.c │ └── vm_common.camkes ├── interfaces ├── Sataserver.idl4 ├── UDPRecv.idl4 ├── UDPSend.idl4 ├── seL4VMDTBPassthrough.idl4 └── vm-connectors.camkes ├── libs └── libvirtio │ ├── CMakeLists.txt │ ├── include │ └── virtioarm │ │ ├── virtio.h │ │ ├── virtio_console.h │ │ └── virtio_net.h │ ├── plat_include │ ├── exynos5 │ │ └── virtioarm │ │ │ └── virtio_plat.h │ ├── qemu-arm-virt │ │ └── virtioarm │ │ │ └── virtio_plat.h │ ├── tx2 │ │ └── virtioarm │ │ │ └── virtio_plat.h │ └── zynqmp │ │ └── virtioarm │ │ └── virtio_plat.h │ └── src │ ├── virtio_console.c │ └── virtio_net.c ├── templates ├── seL4AllocatorMempool.template.c ├── seL4AllocatorMempool.template.h ├── seL4SMMUV2.template.c ├── seL4Sataserver-from.template.c ├── seL4Sataserver-to.template.c ├── seL4UDPRecv-from.template.c ├── seL4UDPRecv-to.template.c ├── seL4UDPSend-from.template.c ├── seL4UDPSend-to.template.c ├── seL4VMDTBPassthrough-from.template.c ├── seL4VMDTBPassthrough-to.template.c ├── seL4VMParameters.template.c └── seL4VMParameters.template.h └── tools └── elf ├── extract-vmlinux ├── relocs └── relocs.license /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Code of Conduct 8 | 9 | This repository and interactions with it fall under the [seL4 Code of Conduct][1] available from the [seL4 website][2]. 10 | 11 | [1]: https://docs.sel4.systems/processes/conduct.html 12 | [2]: https://sel4.systems 13 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Contributions Welcome 8 | 9 | Please see the [seL4 contributing guidelines][1] on the [seL4 website][2] for 10 | details. 11 | 12 | [1]: https://docs.sel4.systems/processes/contributing.html 13 | [2]: https://sel4.systems 14 | 15 | 16 | ## Contact 17 | 18 | If you have larger changes or additions, it is a good idea to get in contact 19 | with us as , so we can help you get started. 20 | 21 | The people responsible for the technical direction, procedures, and quality 22 | control are the [Technical Steering Committee][3] (TSC) of the seL4 23 | foundation. You can contact them either on the developer mailing list or on 24 | directly via email available from their profile pages. 25 | 26 | [3]: https://sel4.systems/Foundation/TSC 27 | 28 | 29 | ## Developer Certificate of Origin (DCO) 30 | 31 | This repository uses the same sign-off process as the Linux kernel. For every 32 | commit, use 33 | 34 | git commit -s 35 | 36 | to add a sign-off line to your commit message, which will come out as: 37 | 38 | Signed-off-by: name 39 | 40 | By adding this line, you make the declaration that you have the right to make 41 | this contribution under the open source license the files use that you changed 42 | or contributed. 43 | 44 | The full text of the declaration is at . 45 | -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025, Proofcraft Pty Ltd 2 | # 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | 5 | # Actions to run on pull requests 6 | 7 | name: PR 8 | 9 | on: [pull_request, workflow_dispatch] 10 | 11 | jobs: 12 | pr-checks: 13 | name: Checks 14 | uses: seL4/ci-actions/.github/workflows/pr.yml@master 15 | -------------------------------------------------------------------------------- /.github/workflows/push.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 2 | # 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | 5 | # Actions to run on Push and Pull Request 6 | name: CI 7 | 8 | on: 9 | push: 10 | branches: 11 | - master 12 | pull_request: 13 | workflow_dispatch: 14 | 15 | jobs: 16 | checks: 17 | name: Checks 18 | uses: seL4/ci-actions/.github/workflows/push.yml@master 19 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023, Proofcraft Pty Ltd 2 | # 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | 5 | # Actions to run on pull requests 6 | 7 | name: Camkes-VM-Examples-HW 8 | 9 | on: 10 | pull_request_target: 11 | types: [opened, reopened, synchronize, labeled] 12 | 13 | # downgrade permissions to read-only as you would have in a standard PR action 14 | permissions: 15 | contents: read 16 | 17 | # To reduce the load (especiually on the machine queue) we cancel any older runs 18 | # of this workflow for the current PR. Such runs exist, if there were new pushes 19 | # to the PR's branch without waiting for the workflow to finish. As a side 20 | # effect, pushing new commits now becomes a convenient way to cancel all the 21 | # older runs, e.g. if they are stuck and would only be stopped by the timeout 22 | # eventually. 23 | # Note that we could do the concurrency handling at a finer level, and only wrap 24 | # the actual run on the hardware. But there seems not much gain in letting the 25 | # older builds run, as these are usually obsolete with new pushes also. 26 | concurrency: 27 | group: ${{ github.workflow }}-pr-${{ github.event.number }} 28 | cancel-in-progress: true 29 | 30 | jobs: 31 | code: 32 | name: Freeze Code 33 | runs-on: ubuntu-latest 34 | outputs: 35 | xml: ${{ steps.repo.outputs.xml }} 36 | steps: 37 | - id: repo 38 | uses: seL4/ci-actions/repo-checkout@master 39 | with: 40 | manifest_repo: camkes-vm-examples-manifest 41 | manifest: master.xml 42 | sha: ${{ github.event.pull_request.head.sha }} 43 | 44 | build: 45 | name: Build 46 | needs: [code] 47 | runs-on: ubuntu-latest 48 | strategy: 49 | fail-fast: false 50 | matrix: 51 | march: [nehalem, armv7a, armv8a] 52 | steps: 53 | - uses: seL4/ci-actions/camkes-vm@master 54 | with: 55 | xml: ${{ needs.code.outputs.xml }} 56 | march: ${{ matrix.march }} 57 | - name: Upload images 58 | uses: actions/upload-artifact@v4 59 | with: 60 | name: images-${{ matrix.march }} 61 | path: '*-images.tar.gz' 62 | 63 | hw-run: 64 | name: Hardware 65 | runs-on: ubuntu-latest 66 | needs: [build] 67 | if: ${{ github.repository_owner == 'seL4' && 68 | (github.event_name == 'push' || 69 | github.event_name == 'pull_request_target' && 70 | github.event.action != 'labeled' && 71 | contains(github.event.pull_request.labels.*.name, 'hw-test') || 72 | github.event_name == 'pull_request_target' && 73 | github.event.action == 'labeled' && 74 | github.event.label.name == 'hw-test') }} 75 | strategy: 76 | fail-fast: false 77 | matrix: 78 | march: [nehalem, armv7a, armv8a] 79 | steps: 80 | - name: Get machine queue 81 | uses: actions/checkout@v4 82 | with: 83 | repository: seL4/machine_queue 84 | path: machine_queue 85 | - name: Download image 86 | uses: actions/download-artifact@v4 87 | with: 88 | name: images-${{ matrix.march }} 89 | - name: Run 90 | uses: seL4/ci-actions/camkes-vm-hw@master 91 | with: 92 | march: ${{ matrix.march }} 93 | index: $${{ strategy.job-index }} 94 | env: 95 | HW_SSH: ${{ secrets.HW_SSH }} 96 | -------------------------------------------------------------------------------- /.github/workflows/trigger.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021, Proofcraft Pty Ltd 2 | # 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | 5 | # Trigger repository dispatch on main test repos 6 | name: Trigger 7 | 8 | on: 9 | push: 10 | branches: [master] 11 | 12 | jobs: 13 | trigger: 14 | name: Repository Dispatch 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: seL4/ci-actions/trigger@master 18 | with: 19 | token: ${{ secrets.PRIV_REPO_TOKEN }} 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | linux/out 8 | linux/modules/**/*.cmd 9 | linux/modules/**/*.ko 10 | linux/modules/**/.* 11 | linux/modules/**/Module.symvers 12 | linux/modules/**/modules.order 13 | linux/modules/**/*.mod.c 14 | linux/**/*.o 15 | linux/**/*.a 16 | -------------------------------------------------------------------------------- /.licenseignore: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | linux 8 | configs 9 | liblwip/lwip-1.4.1 10 | lwipopts.h 11 | tools/elf/relocs 12 | *bzimage 13 | *.cpio 14 | apps/vm/cma34cr_centos/centos-kernel-config 15 | liblwip/include/arch/perf.h 16 | liblwip/include/lwip/arch/cc.h 17 | components/PicoServer/include/khash.h 18 | .gitignore 19 | -------------------------------------------------------------------------------- /.stylefilter: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | *.template.c 7 | components/Init/src/i8254.c 8 | components/Init/src/mc146818rtc.c 9 | components/Init/src/serial.c 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2018, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.8.2) 8 | 9 | set(configure_string "") 10 | 11 | config_option( 12 | CAmkESVMGuestDMAIommu 13 | CAMKES_VM_GUEST_DMA_IOMMU 14 | "Enable DMA through the IOMMU" 15 | DEFAULT 16 | ON 17 | ) 18 | 19 | # Create VMM configuration library 20 | add_config_library(camkes_vmm "${configure_string}") 21 | 22 | # Common VM build definitions 23 | CAmkESAddImportPath(components) 24 | CAmkESAddImportPath(interfaces) 25 | CAmkESAddTemplatesPath(templates) 26 | CAmkESAddTemplatesPath(components/Init/templates) 27 | 28 | # Add VM Components and Libraries 29 | add_subdirectory(components/Echo) 30 | add_subdirectory(components/Firewall) 31 | add_subdirectory(components/StringReverse) 32 | add_subdirectory(components/UDPServer) 33 | add_subdirectory(components/Sataserver) 34 | add_subdirectory(libs/libvirtio camkes-arm-vm/libs/libvirtio) 35 | 36 | # Declare connectors with templates. 37 | # We can rely on the naming scheme being consistent to allow for easier declaration. 38 | foreach( 39 | connector 40 | IN 41 | ITEMS 42 | seL4UDPSend 43 | seL4UDPRecv 44 | seL4PicoUDPSend 45 | seL4PicoUDPRecv 46 | seL4MultiSharedData 47 | seL4Sataserver 48 | ) 49 | DeclareCAmkESConnector( 50 | ${connector} 51 | FROM 52 | ${connector}-from.template.c 53 | TO 54 | ${connector}-to.template.c 55 | ) 56 | endforeach() 57 | -------------------------------------------------------------------------------- /Findcamkes-arm-vm.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | set(CAMKES_ARM_VM_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE STRING "") 8 | set(CAMKES_ARM_VM_HELPERS_PATH "${CMAKE_CURRENT_LIST_DIR}/arm_vm_helpers.cmake" CACHE STRING "") 9 | mark_as_advanced(CAMKES_ARM_VM_DIR CAMKES_ARM_VM_HELPERS_PATH) 10 | 11 | macro(camkes_arm_vm_import_project) 12 | include(${CAMKES_VM_HELPERS_PATH}) 13 | include(${CAMKES_ARM_VM_HELPERS_PATH}) 14 | # Common build definitions 15 | CAmkESAddImportPath(${CAMKES_ARM_VM_DIR}/components camkes-arm-vm/components) 16 | CAmkESAddImportPath(${CAMKES_ARM_VM_DIR}/interfaces camkes-arm-vm/interfaces) 17 | CAmkESAddTemplatesPath(${CAMKES_ARM_VM_DIR}/templates camkes-arm-vm/templates) 18 | DeclareCAmkESConnector( 19 | seL4VMDTBPassthrough 20 | FROM 21 | seL4VMDTBPassthrough-from.template.c 22 | TO 23 | seL4VMDTBPassthrough-to.template.c 24 | ) 25 | 26 | # Add libraries 27 | add_subdirectory(${CAMKES_ARM_VM_DIR}/libs/libvirtio camkes-arm-vm/libs/libvirtio) 28 | 29 | # VM components 30 | add_subdirectory(${CAMKES_ARM_VM_DIR}/components/VM_Arm camkes-arm-vm/components/VM) 31 | 32 | endmacro() 33 | 34 | macro(camkes_arm_vm_setup_arm_vm_environment) 35 | 36 | find_package(camkes-tool REQUIRED) 37 | find_package(global-components REQUIRED) 38 | find_package(camkes-vm REQUIRED) 39 | find_package(camkes-vm-images REQUIRED) 40 | find_package(sel4_projects_libs REQUIRED) 41 | camkes_tool_setup_camkes_build_environment() 42 | sel4_projects_libs_import_libraries() 43 | global_components_import_project() 44 | 45 | camkes_arm_vm_import_project() 46 | endmacro() 47 | 48 | include(FindPackageHandleStandardArgs) 49 | FIND_PACKAGE_HANDLE_STANDARD_ARGS( 50 | camkes-arm-vm 51 | DEFAULT_MSG 52 | CAMKES_ARM_VM_DIR 53 | CAMKES_ARM_VM_HELPERS_PATH 54 | ) 55 | -------------------------------------------------------------------------------- /Findcamkes-vm.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | set(CAMKES_VM_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE STRING "") 8 | set(CAMKES_VM_HELPERS_PATH "${CMAKE_CURRENT_LIST_DIR}/camkes_vm_helpers.cmake" CACHE STRING "") 9 | set(CAMKES_VM_SETTINGS_PATH "${CMAKE_CURRENT_LIST_DIR}/camkes_vm_settings.cmake" CACHE STRING "") 10 | mark_as_advanced(CAMKES_VM_DIR CAMKES_VM_HELPERS_PATH CAMKES_VM_SETTINGS_PATH) 11 | 12 | macro(camkes_x86_vm_setup_x86_vm_environment) 13 | 14 | find_package(camkes-tool REQUIRED) 15 | find_package(global-components REQUIRED) 16 | find_package(camkes-vm REQUIRED) 17 | find_package(sel4_projects_libs REQUIRED) 18 | camkes_tool_setup_camkes_build_environment() 19 | global_components_import_project() 20 | sel4_projects_libs_import_libraries() 21 | # Add project 22 | add_subdirectory(${CAMKES_VM_DIR} camkes-vm) 23 | 24 | endmacro() 25 | 26 | include(FindPackageHandleStandardArgs) 27 | FIND_PACKAGE_HANDLE_STANDARD_ARGS( 28 | camkes-vm 29 | DEFAULT_MSG 30 | CAMKES_VM_DIR 31 | CAMKES_VM_HELPERS_PATH 32 | CAMKES_VM_SETTINGS_PATH 33 | ) 34 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # License 8 | 9 | The files in this repository are released under standard open source licenses, 10 | identified by [SPDX license tags][1]. See the individual file headers for 11 | details, or use one of the publicly available SPDX tools to generate a bill of 12 | materials. The directory [`LICENSES`][2] contains the text for all licenses 13 | that are mentioned by files in this repository. 14 | 15 | [1]: https://spdx.org 16 | [2]: LICENSES/ 17 | -------------------------------------------------------------------------------- /LICENSES/BSD-2-Clause.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 17 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 22 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /LICENSES/MIT.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is furnished 10 | to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 18 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 19 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 20 | OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 6 | camkes-vm 7 | ========= 8 | 9 | The CAmkES VMM is actively targeted to run on the C162 platform from Aitech. 10 | This repo provides various CAmkES components, templates, interfaces and libraries that can be used to create a CAmkES VMM application. This is short description of how to use and build with this project. 11 | 12 | Build dependencies 13 | ------------------ 14 | 15 | To ensure you have the necessary dependencies for building the CAmkES VM project please refer to the [Host Dependencies page](https://docs.sel4.systems/HostDependencies.html). 16 | 17 | ## CMake 18 | To build an application with this project we use CMake. This repo provides a series of CMake helper functions (found in `camkes_vm_helpers.cmake`) to assit you with defining your CAmkES VM application. Importing this file into your applications CMake configuration gives you access to the following helper functions: 19 | 20 | - `DeclareCAmkESVM(init_component [SOURCES INCLUDES LIBS LD_FLAGS C_FLAGS])`: Function for declaring a CAmkESVM. This is called for each Init component in the defined in the applications `.camkes` file. The user can also pass in extra compilation sources, includes, libs and flags to be compiled with the component through additional arguments (`SOURCES`, `INCLUDES`, `LIBS`, `LD_FLAGS` and `C_FLAGS`) 21 | - `DeclareCAmkESVMRootServer(camkes_config)`: Declares the CAmkESVM root server. This function takes the applications `.camkes` file as an argument (`camkes_config`). 22 | - `AddToFileServer(filename_pref file_dest [DEPENDS])`: Function for adding a file/image to the vm file server. The caller specifies the name of they wish to refer to the image in the FileServer through the `filename_pref` parameter. `file_dest` is the file system location of the image the caller is adding. Additional dependencies to the image can be passed through the optional `DEPENDS` parameter. 23 | - `DecompressLinuxKernel(decompress_target decompressed_kernel_image compressed_kernel_image [DEPENDS])`: Function for decompressing/extracting a vmlinux file from a given kernel image. The caller specifies a target name (`decompress_target`) for decompressing the kernel, the kernel image to decompress (`compressed_kernel_image`) and additional dependencies to the compressed image through the optional `DEPENDS` parameter. The location of the decompressed image is populated in the `decompressed_kernel_image` parameter passed by the caller. 24 | 25 | ## Items 26 | 27 | This repo contains a series of CAmkES components, templates, libraries and images necessary to develop a CAmkES VM application. This project does not contain any CAmkES VM applications to build however. A set of example CAmkES VM applications can be found in the [camkes-vm-examples](https://github.com/seL4/camkes-vm-examples/blob/master/README.md) repo. This is a small description of the various items provided in this repository: 28 | 29 | ### CAmkES Components 30 | This repo provides a series of useful CAmkES components that can be used to develop your VM platform, in addition to some demonstration applications. These components include: 31 | 32 | - `Init` 33 | - `Ethdriver` 34 | - `StringReverse` 35 | - `Echo` 36 | - `Firewall` 37 | - `StringReverse` 38 | - `UDPServer` 39 | 40 | ### Linux Images 41 | This repo provides Guest Linux VM images you can use for your CAmkES VM application, located in the `linux` directory. We provide a ready-to-use Rootfs (`linux/rootfs.cpio`) and Kernel image (`linux/bzimage`) built from the [buildroot](https://buildroot.org/) project. 42 | 43 | Additionally you can develop your own applications and linux kernel modules to add to the Linux `rootfs.cpio` archive. After making changes and adding additional packages and modules you can run the provided `build-rootfs` tool to generate a new rootfs image. 44 | 45 | ### Libraries 46 | 47 | #### libcrossvm 48 | 49 | `libcrossvm` makes it possible connect processes in the guest linux to a regular CAmkES component. This is achieved through making dataports and event interfaces available to the guest VM. To utilise the CAmkES Cross VM connector implementation we provide the crossvm library. 50 | 51 | To enable a guest Linux with crossvm functionality we can link the library to the desired VMs CMake declaration, for example: 52 | ``` 53 | DeclareCAmkESVM(Init0 54 | EXTRA_LIBS crossvm 55 | ) 56 | ``` 57 | 58 | Serial 59 | ------ 60 | 61 | The hardware COM1 is multiplexed to each VM such that output for each guest 62 | and VM appears over COM1, and input can be directed at any of the guests. The 63 | output of each guest and VM is colour coded. 64 | 65 | By default input is sent to vm0, to switch input to a different VM use 66 | @N where N is 0-9 (for VMs 0 to 9) or :,; for VMs 10 and 11 67 | respectively. The escape character, tilde, is only recognized 68 | following a newline. To get a list of all supported escapes, use `@?`. 69 | 70 | It is also possible to send input to multiple VMs at the same time. 71 | This mode is experimental. To set up multi-guest input, use `@m` 72 | followed by one or more numbers or characters (as above), then press 73 | Return to apply. 74 | 75 | Multi-guest input mode also enables output coalescing, in order to 76 | allow convenient use of the shell and other interactive terminal 77 | applications (including text editors, if the editor state is exactly 78 | the same in all guests). Coalesced output is drawn in white. Please 79 | note that coalescing is experimental and best-effort; some 80 | circumstances will result in coalescing failure, which is shown as 81 | multiple colour-coded copies of the same output. In order to 82 | ameliorate this, it is recommended to use a terminal multiplexer such 83 | as `screen` inside the VMs, providing a redraw function. 84 | 85 | Some debug features are also built in (activated via the `@d` escape); 86 | see the online help (`@?`) and [the source code](components/Init/src/serial.c) 87 | for details. 88 | -------------------------------------------------------------------------------- /arm_vm_helpers.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2018, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.8.2) 8 | set(ARM_VM_PROJECT_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "") 9 | 10 | # Function appends a given list of CMake config variables as CAmkES CPP flags 11 | # 'configure_string': The variable to append the CPP flags onto 12 | # 'CONFIG_VARS': followed by the CMake variables to turn into CPP flags. 13 | # Converts the CMake variables to upper case i.e. VmVchan -> VMVCHAN. 14 | # If the CMake variable is a boolean it passes the flag with a 0 or 1 value 15 | # e.g VMVCHAN=0. Intended to be used with CMake variables that contain boolean 16 | # values. 17 | function(AddCamkesCPPFlag configure_string) 18 | cmake_parse_arguments(PARSE_ARGV 1 ADD_CPP "" "" "CONFIG_VARS") 19 | foreach(configure_var IN LISTS ADD_CPP_CONFIG_VARS) 20 | # Convert the configuration variable name into uppercase 21 | string(TOUPPER ${configure_var} config_var_name) 22 | if(${${configure_var}}) 23 | # If ON value, set the flag to "=1" 24 | list(APPEND ${configure_string} "-D${config_var_name}=1") 25 | else() 26 | # If OFF value, set the flag to "=0" 27 | list(APPEND ${configure_string} "-D${config_var_name}=0") 28 | endif() 29 | endforeach() 30 | # Update the configure_string value 31 | set(${configure_string} "${${configure_string}}" PARENT_SCOPE) 32 | endfunction(AddCamkesCPPFlag) 33 | 34 | function(DeclareCAmkESARMVM init_component) 35 | cmake_parse_arguments( 36 | PARSE_ARGV 37 | 1 38 | VM_COMP 39 | "" 40 | "" 41 | "EXTRA_SOURCES;EXTRA_INCLUDES;EXTRA_LIBS;EXTRA_C_FLAGS;EXTRA_LD_FLAGS" 42 | ) 43 | 44 | set( 45 | vm_src 46 | ${ARM_VM_PROJECT_DIR}/components/VM_Arm/src/main.c 47 | ${ARM_VM_PROJECT_DIR}/components/VM_Arm/src/fdt_manipulation.c 48 | ${ARM_VM_PROJECT_DIR}/components/VM_Arm/src/crossvm.c 49 | ${ARM_VM_PROJECT_DIR}/components/VM_Arm/src/modules/map_frame_hack.c 50 | ${ARM_VM_PROJECT_DIR}/components/VM_Arm/src/modules/init_ram.c 51 | ) 52 | 53 | if(VmVirtUart) 54 | list(APPEND vm_src ${ARM_VM_PROJECT_DIR}/components/VM_Arm/src/modules/vuart_init.c) 55 | endif() 56 | 57 | if(Tk1DeviceFwd) 58 | list( 59 | APPEND vm_src ${ARM_VM_PROJECT_DIR}/components/VM_Arm/src/modules/plat/tk1/device_fwd.c 60 | ) 61 | endif() 62 | 63 | # A module that is expected to exist for each platform but not required. 64 | # It should provide basic device intialisation required for every vm configuratoin 65 | set( 66 | platform_module 67 | ${ARM_VM_PROJECT_DIR}/components/VM_Arm/src/modules/plat/${KernelPlatform}/init.c 68 | ) 69 | if(EXISTS ${platform_module}) 70 | list(APPEND vm_src ${platform_module}) 71 | endif() 72 | 73 | # Append virtio net sources if the virtio net config is enabled 74 | if(VmVirtioNetArping) 75 | list(APPEND vm_src ${ARM_VM_PROJECT_DIR}/components/VM_Arm/src/modules/virtio_net_arping.c) 76 | endif() 77 | 78 | if(VmVirtioNetVirtqueue) 79 | list( 80 | APPEND vm_src ${ARM_VM_PROJECT_DIR}/components/VM_Arm/src/modules/virtio_net_virtqueue.c 81 | ) 82 | endif() 83 | 84 | if(VmVirtioConsole) 85 | list(APPEND vm_src ${ARM_VM_PROJECT_DIR}/components/VM_Arm/src/modules/virtio_con.c) 86 | endif() 87 | 88 | if(KernelPlatformExynos5410) 89 | list( 90 | APPEND vm_src ${ARM_VM_PROJECT_DIR}/components/VM_Arm/src/modules/plat/exynos5410/init.c 91 | ) 92 | set(vm_plat_include "${ARM_VM_PROJECT_DIR}/components/VM_Arm/plat_include/exynos5410") 93 | elseif(KernelPlatformExynos5422) 94 | set(vm_plat_include "${ARM_VM_PROJECT_DIR}/components/VM_Arm/plat_include/exynos5422") 95 | elseif(KernelPlatformZynqmpUltra96v2) 96 | set(vm_plat_include "${ARM_VM_PROJECT_DIR}/components/VM_Arm/plat_include/ultra96v2") 97 | else() 98 | set( 99 | vm_plat_include 100 | "${ARM_VM_PROJECT_DIR}/components/VM_Arm/plat_include/${KernelPlatform}" 101 | ) 102 | endif() 103 | # Declare the CAmkES VM component 104 | DeclareCAmkESComponent( 105 | ${init_component} 106 | SOURCES 107 | ${vm_src} 108 | ${VM_COMP_EXTRA_SOURCES} 109 | INCLUDES 110 | ${ARM_VM_PROJECT_DIR}/components/VM_Arm/include 111 | ${vm_plat_include} 112 | ${VM_COMP_EXTRA_INCLUDES} 113 | LIBS 114 | sel4allocman 115 | elf 116 | sel4simple 117 | sel4simple-default 118 | cpio 119 | sel4vm 120 | sel4dma 121 | FileServer-client 122 | sel4vmmplatsupport 123 | arm_vm_Config 124 | sel4_autoconf 125 | sel4muslcsys_Config 126 | fdt 127 | fdtgen 128 | ${VM_COMP_EXTRA_LIBS} 129 | LD_FLAGS 130 | ${VM_COMP_EXTRA_LD_FLAGS} 131 | C_FLAGS 132 | ${VM_COMP_EXTRA_C_FLAGS} 133 | TEMPLATE_SOURCES 134 | seL4AllocatorMempool.template.c 135 | seL4VMParameters.template.c 136 | TEMPLATE_HEADERS 137 | seL4AllocatorMempool.template.h 138 | seL4VMParameters.template.h 139 | ) 140 | 141 | if(VmVirtioNetArping OR VmVirtioNetVirtqueue OR VmVirtioConsole) 142 | DeclareCAmkESComponent(${init_component} LIBS virtioarm vswitch) 143 | endif() 144 | 145 | # Append the USB driver library if building for exynos 146 | if("${KernelARMPlatform}" STREQUAL "exynos5410") 147 | DeclareCAmkESComponent(${init_component} LIBS usbdrivers) 148 | endif() 149 | 150 | if("${KernelArmSMMU}") 151 | DeclareCAmkESComponent(${init_component} TEMPLATE_SOURCES seL4SMMUV2.template.c) 152 | endif() 153 | 154 | endfunction() 155 | -------------------------------------------------------------------------------- /camkes_vm_settings.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2018, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.8.2) 8 | 9 | # Kernel settings 10 | set(KernelArch x86 CACHE STRING "" FORCE) 11 | set(KernelPlatform pc99 CACHE STRING "" FORCE) 12 | set(KernelVTX ON CACHE BOOL "" FORCE) 13 | set(KernelRootCNodeSizeBits 20 CACHE STRING "" FORCE) 14 | set(KernelIRQController IOAPIC CACHE STRING "" FORCE) 15 | if(CAmkESVMGuestDMAIommu) 16 | set(KernelIOMMU ON CACHE BOOL "" FORCE) 17 | endif() 18 | # Release settings 19 | set(RELEASE OFF CACHE BOOL "Performance optimized build") 20 | # capDL settings 21 | set(CapDLLoaderMaxObjects 900000 CACHE STRING "" FORCE) 22 | # Our components will all define their own heaps if needed 23 | # Otherwise we provide enough of a heap to initialise libc 24 | set(CAmkESDefaultHeapSize 4096 CACHE STRING "" FORCE) 25 | # We need to pre-process our specs 26 | set(CAmkESCPP ON CACHE BOOL "" FORCE) 27 | 28 | # Set release/verification configuration 29 | ApplyCommonReleaseVerificationSettings(${RELEASE} FALSE) 30 | -------------------------------------------------------------------------------- /components/Echo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2018, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.8.2) 8 | 9 | project(Echo C) 10 | 11 | DeclareCAmkESComponent(Echo SOURCES src/echo.c LIBS lwip sel4vspace) 12 | -------------------------------------------------------------------------------- /components/Echo/Echo.camkes: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | /* 8 | * Usage: This component contains two echo servers that listen on a recv_port defined in 9 | * the .camkes file, and bound to the ip address of the UDPserver that it is 10 | * connected to. Sending data over UDP will be rebounded to the client immediately. 11 | * 12 | * Note: The reply is sent via a udp port statically defined by send_ports in .camkes 13 | * so the reply may not arrive on the same port as the sender. Multiple netcat clients could be used. 14 | * 15 | * Example usage from external client: 16 | * $ netcat -u #Sender 17 | * $ netcat -lup #Recieve the rebounded echo replies on this port. Echos data from sender. 18 | */ 19 | 20 | import ; 21 | import ; 22 | import ; 23 | import ; 24 | import ; 25 | 26 | component Echo { 27 | control; 28 | uses UDPRecv echo_recv; 29 | uses UDPSend echo_send; 30 | uses UDPRecv echo2_recv; 31 | uses UDPSend echo2_send; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /components/Echo/src/echo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | /* get rid of camkes ERR_IF macro that collides with the lwip one */ 11 | #undef ERR_IF 12 | #include 13 | 14 | extern volatile void *echo_recv_buf; 15 | extern volatile void *echo2_recv_buf; 16 | 17 | void echo_recv_ready_callback() 18 | { 19 | int status = 0; 20 | while (status == 0) { 21 | unsigned int len; 22 | uint16_t port; 23 | uint32_t ip4addr; 24 | status = echo_recv_poll(&len, &port, &ip4addr); 25 | if (status != -1) { 26 | echo_send_send((uintptr_t)echo_recv_buf, len, ip4addr); 27 | } 28 | } 29 | } 30 | 31 | void echo2_recv_ready_callback() 32 | { 33 | int status = 0; 34 | while (status == 0) { 35 | unsigned int len; 36 | uint16_t port; 37 | uint32_t ip4addr; 38 | status = echo2_recv_poll(&len, &port, &ip4addr); 39 | if (status != -1) { 40 | echo2_send_send((uintptr_t)echo2_recv_buf, len, ip4addr); 41 | } 42 | } 43 | } 44 | 45 | 46 | int run(void) 47 | { 48 | 49 | while (1) { 50 | seL4_Word badge; 51 | seL4_Wait(echo2_recv_notification(), &badge); 52 | if (badge & echo_recv_notification_badge()) { 53 | echo_recv_ready_callback(); 54 | } 55 | if (badge & echo2_recv_notification_badge()) { 56 | echo2_recv_ready_callback(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /components/Firewall/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2018, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.8.2) 8 | 9 | project(Firewall C) 10 | 11 | DeclareCAmkESComponent(Firewall SOURCES src/firewall.c) 12 | -------------------------------------------------------------------------------- /components/Firewall/Firewall.camkes: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | import ; 8 | 9 | component Firewall { 10 | uses Ethdriver ethdriver; 11 | provides Ethdriver client; 12 | emits HasData dummy; 13 | consumes HasData ethdriver_has_data; 14 | } 15 | -------------------------------------------------------------------------------- /components/Firewall/src/firewall.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | extern void *ethdriver_buf; 13 | void *client_buf(int); 14 | void client_emit(seL4_Word badge); 15 | 16 | void client_mac(uint8_t *b1, uint8_t *b2, uint8_t *b3, uint8_t *b4, uint8_t *b5, uint8_t *b6) 17 | { 18 | ethdriver_mac(b1, b2, b3, b4, b5, b6); 19 | } 20 | 21 | int client_tx(int len) 22 | { 23 | memcpy(ethdriver_buf, client_buf(1), len); 24 | return ethdriver_tx(len); 25 | } 26 | 27 | int client_rx(int *len) 28 | { 29 | int result = ethdriver_rx(len); 30 | if (result != -1) { 31 | memcpy(client_buf(1), ethdriver_buf, *len); 32 | } 33 | return result; 34 | } 35 | 36 | void ethdriver_has_data_callback(seL4_Word badge) 37 | { 38 | client_emit(1); 39 | } 40 | -------------------------------------------------------------------------------- /components/Init/Init.camkes: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #include 8 | import ; 9 | import ; 10 | import ; 11 | import ; 12 | import ; 13 | import ; 14 | 15 | struct vswitch_mapping { 16 | string mac_addr; 17 | int send_id; 18 | int recv_id; 19 | }; 20 | -------------------------------------------------------------------------------- /components/Init/include/crossvm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | struct camkes_consumes_event { 15 | vm_t *vm; 16 | unsigned int id; 17 | int (*reg_callback)(event_callback_fn, void *arg); 18 | seL4_CPtr irq_notification; 19 | }; 20 | 21 | struct camkes_crossvm_connection { 22 | dataport_caps_handle_t *handle; 23 | emit_fn emit_fn; 24 | struct camkes_consumes_event consume_event; 25 | }; 26 | 27 | /** 28 | * Initialise and register a series of camkes crossvm connections with a given vm 29 | * @param[in] vm A handle to the VM 30 | * @param[in] connection_base_addr The base guest physical address to interface the crossvm connection devices through 31 | * @param[in] connections An array of camkes crossvm connections 32 | * @param[in] num_connection The number of elements in the 'connections' array (parameter) 33 | * @param[in] pci A handle to the virtual pci driver 34 | * @param[in] irq_notification Notification object to signal crossvm irq 35 | * @return -1 for error, otherwise 0 for success 36 | */ 37 | int cross_vm_connections_init(vm_t *vm, uintptr_t connection_base_addr, struct camkes_crossvm_connection *connections, 38 | int num_connections, vmm_pci_space_t *pci, seL4_CPtr irq_notification); 39 | -------------------------------------------------------------------------------- /components/Init/src/camkes_vm_interfaces.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int ram_num_untypeds(void); 14 | int ram_get_untyped(int ut, uintptr_t *paddr, int *size_bits, seL4_CPtr *cap); 15 | 16 | 17 | int exclude_paddr_num_regions(void); 18 | void exclude_paddr_get_region(int region_num, uintptr_t *paddr, size_t *bytes); 19 | 20 | int init_cons_num_connections(void); 21 | uintptr_t init_cons_init_function(int con); 22 | int init_cons_has_interrupt(int con, uintptr_t *badge, uintptr_t *fun); 23 | 24 | 25 | int ioports_num_pci_ioports(void); 26 | int ioports_num_nonpci_ioports(void); 27 | const char *ioports_get_pci_ioport(int num, seL4_CPtr *cap, uint16_t *start, uint16_t *end); 28 | const char *ioports_get_nonpci_ioport(int num, seL4_CPtr *cap, uint16_t *start, uint16_t *end); 29 | seL4_CPtr ioports_get_ioport(uint16_t start, uint16_t end); 30 | 31 | int pci_devices_num_devices(void); 32 | const char *pci_devices_get_device(int pci_dev, uint8_t *bus, uint8_t *dev, uint8_t *fun, seL4_CPtr *iospace_cap); 33 | int pci_devices_num_device_mem(int pci_dev); 34 | const char *pci_devices_get_device_irq(int pci_dev); 35 | int pci_devices_get_device_mem(int pci_dev, int mem, uintptr_t *paddr, size_t *size, int *page_bits); 36 | seL4_CPtr pci_devices_get_device_mem_frame(uintptr_t paddr); 37 | 38 | int guest_mappings_num_guestmaps(); 39 | int guest_mappings_get_guest_map(int num, uint64_t *frame, uint64_t *size); 40 | seL4_CPtr guest_mappings_get_mapping_mem_frame(uintptr_t paddr); 41 | 42 | int irqs_num_irqs(); 43 | const char *irqs_get_irq(int irq, seL4_CPtr *irq_handler, uint8_t *ioapic, uint8_t *source, int *level_trig, 44 | int *active_low, uint8_t *dest); 45 | -------------------------------------------------------------------------------- /components/Init/src/crossvm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | extern int get_crossvm_irq_num(void); 17 | 18 | static void event_camkes_callback(void *arg) 19 | { 20 | struct camkes_crossvm_connection *conn = arg; 21 | consume_connection_event(conn->consume_event.vm, conn->consume_event.id, false); 22 | seL4_Signal(conn->consume_event.irq_notification); 23 | int err = conn->consume_event.reg_callback(event_camkes_callback, conn); 24 | assert(!err); 25 | } 26 | 27 | int cross_vm_connections_init(vm_t *vm, uintptr_t connection_base_addr, struct camkes_crossvm_connection *connections, 28 | int num_connections, vmm_pci_space_t *pci, seL4_CPtr irq_notification) 29 | { 30 | crossvm_handle_t *crossvm_connections = calloc(num_connections, sizeof(crossvm_handle_t)); 31 | if (!crossvm_connections) { 32 | return -1; 33 | } 34 | for (int i = 0; i < num_connections; i++) { 35 | /* Initialise crossvm dataport handle */ 36 | crossvm_dataport_handle_t *dp_handle = calloc(1, sizeof(crossvm_dataport_handle_t)); 37 | if (!dp_handle) { 38 | ZF_LOGE("Failed to initialse cross vm connection dataport %d", i); 39 | return -1; 40 | } 41 | dataport_caps_handle_t *handle = connections[i].handle; 42 | dp_handle->frame_size_bits = handle->get_frame_size_bits(); 43 | dp_handle->num_frames = handle->get_num_frame_caps(); 44 | dp_handle->frames = handle->get_frame_caps(); 45 | 46 | /* Initialise consume event connection callbacks */ 47 | if (connections[i].consume_event.reg_callback) { 48 | connections[i].consume_event.irq_notification = irq_notification; 49 | connections[i].consume_event.reg_callback(event_camkes_callback, &connections[i]); 50 | } 51 | 52 | /* Initialise crossvm connection */ 53 | crossvm_connections[i].dataport = dp_handle; 54 | crossvm_connections[i].emit_fn = connections[i].emit_fn; 55 | crossvm_connections[i].consume_id = (seL4_Word)connections[i].consume_event.id; 56 | } 57 | 58 | int ret = cross_vm_connections_init_common(vm, connection_base_addr, crossvm_connections, num_connections, 59 | pci, get_crossvm_irq_num); 60 | free(crossvm_connections); 61 | return ret; 62 | } 63 | -------------------------------------------------------------------------------- /components/Init/src/hpet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, DornerWorks 3 | * SPDX-License-Identifier: GPL-2.0-only 4 | */ 5 | 6 | #define HPET_BASE 0xfed00000 7 | #define HPET_LEN 0x500 8 | #define HPET_CLK_PERIOD 10 /* 10 ns*/ 9 | 10 | #define FS_PER_NS 1000000 /* 1000000 femtoseconds == 1 ns */ 11 | #define HPET_MIN_TIMERS 3 12 | #define HPET_MAX_TIMERS 3 13 | 14 | #define HPET_NUM_IRQ_ROUTES 32 15 | 16 | #define HPET_LEGACY_PIT_INT 0 17 | #define HPET_LEGACY_RTC_INT 1 18 | 19 | #define HPET_CFG_ENABLE 0x001 20 | #define HPET_CFG_LEGACY 0x002 21 | 22 | #define HPET_ID 0x000 23 | #define HPET_PERIOD 0x004 24 | #define HPET_CFG 0x010 25 | #define HPET_STATUS 0x020 26 | #define HPET_COUNTER 0x0f0 27 | #define HPET_TN_CFG 0x000 28 | #define HPET_TN_CMP 0x008 29 | #define HPET_TN_ROUTE 0x010 30 | #define HPET_CFG_WRITE_MASK 0x3 31 | 32 | #define HPET_ID_NUM_TIM_SHIFT 8 33 | #define HPET_ID_NUM_TIM_MASK 0x1f00 34 | 35 | #define HPET_TN_TYPE_LEVEL 0x002 36 | #define HPET_TN_ENABLE 0x004 37 | #define HPET_TN_PERIODIC 0x008 38 | #define HPET_TN_PERIODIC_CAP 0x010 39 | #define HPET_TN_SIZE_CAP 0x020 40 | #define HPET_TN_SETVAL 0x040 41 | #define HPET_TN_32BIT 0x100 42 | #define HPET_TN_INT_ROUTE_MASK 0x3e00 43 | #define HPET_TN_FSB_ENABLE 0x4000 44 | #define HPET_TN_FSB_CAP 0x8000 45 | #define HPET_TN_CFG_WRITE_MASK 0x7f4e 46 | #define HPET_TN_INT_ROUTE_SHIFT 9 47 | #define HPET_TN_INT_ROUTE_CAP_SHIFT 32 48 | #define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U 49 | 50 | #define RTC_ISA_IRQ 8 51 | 52 | typedef int (*timer_oneshot_callback_fn)(int p_tid, uint64_t p_ns); 53 | typedef int (*timer_stop_callback_fn)(int p_tid); 54 | 55 | void hpet_pre_init(uint64_t initial_tsc_frequency, 56 | seL4_Word hpet_id_base, 57 | timer_oneshot_callback_fn timer_oneshot_callback, 58 | timer_stop_callback_fn timer_stop_callback); 59 | int vm_create_hpet(vm_t *vm); 60 | -------------------------------------------------------------------------------- /components/Init/src/timers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #pragma once 8 | 9 | /* define the different timer ids for the init component. */ 10 | /* TODO: Allocate timers from within the devices so that we are not polluting 11 | * all of the source with nitty gritty details */ 12 | 13 | /* pit timers */ 14 | #define TIMER_PIT 0 15 | 16 | /* rtc timers*/ 17 | #define TIMER_PERIODIC_TIMER 1 18 | #define TIMER_COALESCED_TIMER 2 19 | #define TIMER_SECOND_TIMER 3 20 | #define TIMER_SECOND_TIMER2 4 21 | 22 | /* serial timers */ 23 | #define TIMER_FIFO_TIMEOUT 5 24 | #define TIMER_TRANSMIT_TIMER 6 25 | #define TIMER_MODEM_STATUS_TIMER 7 26 | #define TIMER_MORE_CHARS 8 27 | 28 | /* hpet timer */ 29 | #define TIMER_HPET0 9 30 | #define TIMER_HPET1 10 31 | #define TIMER_HPET2 11 32 | -------------------------------------------------------------------------------- /components/Init/src/virtio_blk.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Dornerworks 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include "vm.h" 35 | #include "virtio_blk.h" 36 | #include "virtio_irq.h" 37 | 38 | #define VIRTIO_VENDOR_ID 0x1af4 39 | #define VIRTIO_DEVICE_ID 0x1001 40 | 41 | #define VIRTIO_BLK_IOBASE 0x8000 42 | #define VIRTIO_QUEUE_SIZE 128 43 | #define VIRTIO_BLK_DISK_BLK_SIZE 512 44 | #define VIRTIO_BLK_SIZE_MAX 4096 45 | #define VIRTIO_BLK_SEG_MAX 1 46 | 47 | #define CACHE_LINE_SIZE 64 48 | #define LATENCY_TIMER 64 49 | #define SUBSYSTEM_ID 2 50 | 51 | /* Global pointer for the virtio_blk interface structure 52 | * Doesn't actually get used, but memory space is filled with proper values */ 53 | static virtio_blk_t *virtio_blk = NULL; 54 | static vm_t *emul_vm = NULL; 55 | 56 | #define SATASERVER_STATUS_GOOD 0 57 | #define SATASERVER_STATUS_NOT_DONE 1 58 | #define SATASERVER_STATUS_INVALID_CONF 2 59 | 60 | /* 61 | * These functions have the WEAK declaration because of the CAmkES protocol 62 | * requirements. Virtio_blk uses the Sataserver component with interface functions (declared as 63 | * "sataserver") so the compiler needs these so the build doesn't fail; however, the "weak" 64 | * attribute means they are overridden by the proper functions (tx, rx, get_capacity) 65 | */ 66 | volatile Buf *sataserver_iface_buf WEAK; 67 | 68 | int WEAK sataserver_iface_tx(unsigned int sector, unsigned int len) 69 | { 70 | assert(!"should not be here"); 71 | return 0; 72 | } 73 | 74 | int WEAK sataserver_iface_rx(unsigned int sector, unsigned int len) 75 | { 76 | assert(!"should not be here"); 77 | return 0; 78 | } 79 | 80 | unsigned int WEAK sataserver_iface_get_capacity(void) 81 | { 82 | assert(!"should not be here"); 83 | return 0; 84 | } 85 | 86 | unsigned int WEAK sataserver_iface_get_status(void) 87 | { 88 | assert(!"should not be here"); 89 | return 0; 90 | } 91 | 92 | /* 93 | * Purpose: Determine the transfer direction (In/Out) and either read/write from the Dataport. 94 | * If the transfer failed, set the return variable accordingly 95 | * 96 | * Inputs: 97 | * - *driver: disk information 98 | * - direction: read/write to the disk 99 | * - sector: sector to manipulate (512 byte offset) 100 | * - len: number of bytes 101 | * - guest_buf_phys: physical buffer to share data with 102 | * 103 | * Returns: TX_COMPLETE or TX_FAILED based on the transfer status 104 | * 105 | */ 106 | static int virtio_blk_emul_transfer(struct disk_driver *driver, uint8_t direction, uint64_t sector, 107 | uint32_t len, uintptr_t guest_buf_phys) 108 | { 109 | int status = 0; /* Variable to ensure transfer succeeded */ 110 | 111 | switch (direction) { 112 | case VIRTIO_BLK_T_IN: 113 | status = sataserver_iface_rx(sector, len); 114 | memcpy((void *)guest_buf_phys, (void *)sataserver_iface_buf, len); 115 | break; 116 | case VIRTIO_BLK_T_OUT: 117 | memcpy((void *)sataserver_iface_buf, (void *)guest_buf_phys, len); 118 | status = sataserver_iface_tx(sector, len); 119 | break; 120 | case VIRTIO_BLK_T_SCSI_CMD: 121 | case VIRTIO_BLK_T_FLUSH: 122 | case VIRTIO_BLK_T_GET_ID: 123 | /* Do nothing */ 124 | break; 125 | default: 126 | ZF_LOGE("virtio_blk: Invalid command (%d)", direction); 127 | break; 128 | } 129 | 130 | return (status != 0 ? VIRTIO_BLK_XFER_COMPLETE : VIRTIO_BLK_XFER_FAILED); 131 | } 132 | 133 | /* 134 | * Purpose: Handle an Interrupt (May not be necessary...) 135 | * 136 | * Inputs: 137 | * - *driver: disk information 138 | * - irq: interrupt to trigger 139 | * 140 | * Returns: void 141 | * 142 | */ 143 | static void emul_raw_handle_irq(struct disk_driver *driver, int irq) 144 | { 145 | vm_inject_irq(emul_vm->vcpus[BOOT_VCPU], VIRTIO_BLK_IRQ); 146 | } 147 | 148 | /* 149 | * Purpose: Configure the virtio blk structure's capacity, max segments, and size. 150 | * 151 | * Inputs: 152 | * - *driver: disk information 153 | * - *cfg: virtio blk configuration structure pointer 154 | * 155 | * Returns: void 156 | * 157 | */ 158 | static void emul_low_level_init(struct disk_driver *driver, struct virtio_blk_config *cfg) 159 | { 160 | cfg->capacity = sataserver_iface_get_capacity(); 161 | cfg->seg_max = VIRTIO_BLK_SEG_MAX; 162 | cfg->size_max = VIRTIO_BLK_SIZE_MAX; 163 | cfg->blk_size = VIRTIO_BLK_DISK_BLK_SIZE; 164 | } 165 | 166 | /* Interrupt Function Handler for Virtual Machine Monitor - Doesn't really do anything since we're polling */ 167 | UNUSED void virtio_blk_notify(vm_t *vm) 168 | { 169 | // This is where handler code would go 170 | } 171 | 172 | /* Initialization Function for Virtio Blk */ 173 | void make_virtio_blk(vm_t *vm, vmm_pci_space_t *pci, vmm_io_port_list_t *io_ports) 174 | { 175 | unsigned int status = sataserver_iface_get_status(); 176 | 177 | while (SATASERVER_STATUS_NOT_DONE == status) { 178 | status = sataserver_iface_get_status(); 179 | } 180 | 181 | if (SATASERVER_STATUS_INVALID_CONF == status) { 182 | ZF_LOGF("Invalid partition configuration"); 183 | return; 184 | } 185 | 186 | raw_diskiface_funcs_t backend = virtio_blk_default_backend(); 187 | backend.raw_xfer = virtio_blk_emul_transfer; 188 | backend.low_level_init = emul_low_level_init; 189 | backend.raw_handleIRQ = emul_raw_handle_irq, 190 | emul_vm = vm; 191 | 192 | ioport_range_t virtio_port_range = {VIRTIO_BLK_IOBASE, VIRTIO_BLK_IOBASE + VIRTIO_IOPORT_SIZE, VIRTIO_IOPORT_SIZE}; 193 | virtio_blk = common_make_virtio_blk(vm, pci, io_ports, virtio_port_range, IOPORT_ADDR, 194 | VIRTIO_BLK_IRQ, VIRTIO_BLK_IRQ, backend); 195 | 196 | assert(virtio_blk); 197 | } 198 | -------------------------------------------------------------------------------- /components/Init/src/virtio_blk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Dornerworks 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | #define VIRTIO_IOPORT_SIZE 0x40 12 | 13 | void make_virtio_blk(vm_t *vm, vmm_pci_space_t *pci, vmm_io_port_list_t *io_ports); 14 | void virtio_blk_notify(vm_t *vm); 15 | -------------------------------------------------------------------------------- /components/Init/src/virtio_con.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022, UNSW (ABN 57 195 873 179) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | /* ioport size, used for ioport emulation of virtio console */ 13 | #define VIRTIO_IOPORT_SIZE 0x400 14 | 15 | /** 16 | * Initialize a virtio console backend. This includes: 17 | * - adding an IO port handler 18 | * - adding a PCI entry 19 | * - initializing the emul layer 20 | * - setting up connections 21 | * 22 | * @param vm The vm handler of the caller 23 | * @param pci Virtual PCI space of the caller 24 | * @param io_ports list of registered ioports of the caller 25 | */ 26 | void make_virtio_con(vm_t *vm, vmm_pci_space_t *pci, vmm_io_port_list_t *io_ports); 27 | -------------------------------------------------------------------------------- /components/Init/src/virtio_irq.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022, UNSW (ABN 57 195 873 179) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | /** 10 | * Hardcoded IRQ numbers for virtual devices. These have to be unique 11 | * for each device. 12 | * Where Linux has a virtual IRQ number assigned (in `/proc/interrupts`) 13 | * we use that, otherwise pick a free one. 14 | * 15 | * @todo: Having hardcoded numbers for virtio devices might become 16 | * an issue as the list of virtual devices grows. Might be worth it 17 | * to have an IRQ number allocator. 18 | */ 19 | #define TIMER_IRQ 0 20 | /* #define CASCADE_IRQ 2 */ 21 | #define TTYS0_IRQ 4 22 | #define VIRTIO_NET_IRQ 6 23 | #define VIRTIO_BLK_IRQ 7 24 | #define RTC_IRQ 8 25 | #define VIRTIO_CON_IRQ 9 26 | #define VIRTIO_SCK_IRQ 10 27 | -------------------------------------------------------------------------------- /components/Init/src/virtio_net.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #include "vm.h" 36 | #include "virtio_net.h" 37 | #include "virtio_irq.h" 38 | 39 | #define VIRTIO_VID 0x1af4 40 | #define VIRTIO_DID_START 0x1000 41 | 42 | #define QUEUE_SIZE 128 43 | 44 | volatile Buf *__attribute__((weak)) ethdriver_buf; 45 | 46 | int __attribute__((weak)) ethdriver_tx(int len) 47 | { 48 | ZF_LOGF("should not be here"); 49 | return 0; 50 | } 51 | 52 | int __attribute__((weak)) ethdriver_rx(int *len) 53 | { 54 | ZF_LOGF("should not be here"); 55 | return 0; 56 | } 57 | 58 | void __attribute__((weak)) ethdriver_mac(uint8_t *b1, uint8_t *b2, uint8_t *b3, uint8_t *b4, uint8_t *b5, uint8_t *b6) 59 | { 60 | ZF_LOGF("should not be here"); 61 | } 62 | 63 | int __attribute__((weak)) eth_rx_ready_reg_callback(void (*proc)(void *), void *blah) 64 | { 65 | ZF_LOGF("should not be here"); 66 | return 0; 67 | } 68 | 69 | 70 | static virtio_net_t *virtio_net = NULL; 71 | static vm_t *emul_vm; 72 | 73 | static int emul_raw_tx(struct eth_driver *driver, unsigned int num, uintptr_t *phys, unsigned int *len, void *cookie) 74 | { 75 | size_t tot_len = 0; 76 | char *p = (char *)ethdriver_buf; 77 | /* copy to the data port */ 78 | for (int i = 0; i < num; i++) { 79 | memcpy(p + tot_len, (void *)phys[i], len[i]); 80 | tot_len += len[i]; 81 | } 82 | ethdriver_tx(tot_len); 83 | return ETHIF_TX_COMPLETE; 84 | } 85 | 86 | static void emul_raw_handle_irq(struct eth_driver *driver, int irq) 87 | { 88 | vm_inject_irq(emul_vm->vcpus[BOOT_VCPU], VIRTIO_NET_IRQ); 89 | } 90 | 91 | static void emul_low_level_init(struct eth_driver *driver, uint8_t *mac, int *mtu) 92 | { 93 | ethdriver_mac(&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); 94 | *mtu = 1500; 95 | } 96 | 97 | 98 | void virtio_net_notify(vm_t *vm) 99 | { 100 | int len; 101 | int status; 102 | status = ethdriver_rx(&len); 103 | while (status != -1) { 104 | void *cookie; 105 | void *emul_buf = (void *)virtio_net->emul_driver->i_cb.allocate_rx_buf(virtio_net->emul_driver->cb_cookie, len, 106 | &cookie); 107 | if (emul_buf) { 108 | memcpy(emul_buf, (void *)ethdriver_buf, len); 109 | virtio_net->emul_driver->i_cb.rx_complete(virtio_net->emul_driver->cb_cookie, 1, &cookie, (unsigned int *)&len); 110 | } 111 | if (status == 1) { 112 | status = ethdriver_rx(&len); 113 | } else { 114 | /* if status is 0 we already saw the last packet */ 115 | assert(status == 0); 116 | status = -1; 117 | } 118 | } 119 | } 120 | 121 | void make_virtio_net(vm_t *vm, vmm_pci_space_t *pci, vmm_io_port_list_t *io_ports) 122 | { 123 | /* drain any existing packets */ 124 | struct raw_iface_funcs backend = virtio_net_default_backend(); 125 | backend.raw_tx = emul_raw_tx; 126 | backend.low_level_init = emul_low_level_init; 127 | backend.raw_handleIRQ = emul_raw_handle_irq; 128 | emul_vm = vm; 129 | 130 | ioport_range_t virtio_port_range = {0, 0, VIRTIO_IOPORT_SIZE}; 131 | virtio_net = common_make_virtio_net(vm, pci, io_ports, virtio_port_range, IOPORT_FREE, VIRTIO_NET_IRQ, VIRTIO_NET_IRQ, 132 | backend); 133 | assert(virtio_net); 134 | int len; 135 | while (ethdriver_rx(&len) != -1); 136 | } 137 | -------------------------------------------------------------------------------- /components/Init/src/virtio_net.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #define FREE_IOPORT_START 0x9000 13 | #define VIRTIO_IOPORT_SIZE 0x400 14 | 15 | void make_virtio_net(vm_t *vm, vmm_pci_space_t *pci, vmm_io_port_list_t *io_ports); 16 | void virtio_net_notify(vm_t *vm); 17 | -------------------------------------------------------------------------------- /components/Init/src/virtio_net_vswitch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | void make_virtio_net_vswitch(vm_t *vm, vmm_pci_space_t *pci, vmm_io_port_list_t *io_ports); 13 | -------------------------------------------------------------------------------- /components/Init/src/virtio_vsock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022, UNSW (ABN 57 195 873 179) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | /* ioport size, used for ioport emulation of virtio vsock */ 13 | #define VIRTIO_IOPORT_SIZE 0x400 14 | 15 | /** 16 | * Initialize a virtio vsock backend. This includes: 17 | * - adding an IO port handler 18 | * - adding a PCI entry 19 | * - initializing the emul layer 20 | * - setting up connections 21 | * 22 | * @param vm 23 | * @param pci 24 | * @param io_ports 25 | */ 26 | void make_virtio_vsock(vm_t *vm, vmm_pci_space_t *pci, vmm_io_port_list_t *io_ports); 27 | -------------------------------------------------------------------------------- /components/Init/templates/seL4ExcludeGuestPAddr.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | /*- set regions = configuration[me.name].get("exclude_paddr") -*/ 14 | static uintptr_t exclude_regions[] = { 15 | /*- if regions is not none -*/ 16 | /*- for paddr, bytes in regions -*/ 17 | /*? paddr ?*/, /*? bytes ?*/, 18 | /*- endfor -*/ 19 | /*- endif -*/ 20 | }; 21 | 22 | int exclude_paddr_num_regions() { 23 | return ARRAY_SIZE(exclude_regions) / 2; 24 | } 25 | 26 | void exclude_paddr_get_region(int region_num, uintptr_t *paddr, size_t *bytes) { 27 | assert(paddr); 28 | assert(bytes); 29 | assert(region_num < exclude_paddr_num_regions()); 30 | *paddr = exclude_regions[region_num * 2]; 31 | *bytes = exclude_regions[(region_num * 2) + 1]; 32 | } 33 | -------------------------------------------------------------------------------- /components/Init/templates/seL4ExtraRAM.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | /*- set config_uts = configuration[me.name].get("ram") -*/ 14 | /*- set uts = [] -*/ 15 | /*- if config_uts is not none -*/ 16 | /*- for paddr, size_bits in config_uts -*/ 17 | /*- set cap = alloc('extra_ram_cap_%d' % paddr, seL4_UntypedObject, read=True, write=True, paddr = paddr, size_bits = size_bits) -*/ 18 | /*- do uts.append( (paddr, size_bits, cap) ) -*/ 19 | /*- endfor -*/ 20 | /*- endif -*/ 21 | 22 | int ram_num_untypeds() { 23 | return /*? len(uts) ?*/; 24 | } 25 | 26 | int ram_get_untyped(int ut, uintptr_t *paddr, int *size_bits, seL4_CPtr *cap) { 27 | /*- if len(uts) == 0 -*/ 28 | return -1; 29 | /*- else -*/ 30 | switch (ut) { 31 | /*- for paddr, size_bits, cap in uts -*/ 32 | case /*? loop.index0 ?*/: 33 | *paddr = /*? paddr ?*/; 34 | *size_bits = /*? size_bits ?*/; 35 | *cap = /*? cap ?*/; 36 | break; 37 | /*- endfor -*/ 38 | default: 39 | return -1; 40 | } 41 | return 0; 42 | /*- endif -*/ 43 | } 44 | -------------------------------------------------------------------------------- /components/Init/templates/seL4GuestMaps.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | /*- set bits_to_frame_type = { 12:seL4_FrameObject, 20:seL4_ARM_SectionObject, 21:seL4_ARM_SectionObject } -*/ 15 | 16 | 17 | /*- set config_guestmaps = configuration[me.name].get("guest_mappings") -*/ 18 | /*- set gmaps = [] -*/ 19 | /*- if config_guestmaps is not none -*/ 20 | /*- for gmap in config_guestmaps -*/ 21 | /*- for frame_offset in range (0, gmap['size'], 2 ** gmap['page_bits']) -*/ 22 | /*- set frame = gmap['paddr'] + frame_offset -*/ 23 | /*- set object = alloc_obj('gmap_frame_%d' % frame, bits_to_frame_type[gmap['page_bits']], paddr=frame) -*/ 24 | /*- set cap = alloc_cap('gmap_frame_%d' % frame, object, read=true, write=true) -*/ 25 | 26 | /*- do gmaps.append( (gmap['paddr'], 2 ** gmap['page_bits'], gmap['page_bits'], frame, cap) ) -*/ 27 | /*- endfor -*/ 28 | /*- endfor -*/ 29 | /*- endif -*/ 30 | 31 | int guest_mappings_num_guestmaps() { 32 | return /*? len(gmaps) ?*/; 33 | } 34 | 35 | int guest_mappings_get_guest_map(int num, uint64_t *frame, uint64_t *size) { 36 | /*- if len(gmaps) == 0 -*/ 37 | return 0; 38 | /*- else -*/ 39 | switch (num) { 40 | /*- for paddr, size, pgbits, frame, cap in gmaps -*/ 41 | case /*? loop.index0 ?*/: 42 | *frame = /*? frame ?*/; 43 | *size = /*? size ?*/; 44 | return 1; 45 | /*- endfor -*/ 46 | default: 47 | return 0; 48 | } 49 | /*- endif -*/ 50 | } 51 | 52 | seL4_CPtr guest_mappings_get_mapping_mem_frame(uintptr_t paddr) { 53 | /*- if len(gmaps) == 0 -*/ 54 | return 0; 55 | /*- else -*/ 56 | switch(paddr) { 57 | /*- for pd, sz, pb, paddr, cap in gmaps -*/ 58 | case /*? paddr ?*/: 59 | return /*? cap ?*/; 60 | /*- endfor -*/ 61 | default: 62 | return 0; 63 | } 64 | /*- endif -*/ 65 | } 66 | -------------------------------------------------------------------------------- /components/Init/templates/seL4InitConnection.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | /*- set cons = configuration[me.name].get("init_cons") -*/ 18 | /*- set cons = lambda('x: [] if x is None else x')(cons) -*/ 19 | 20 | /*- for con in cons -*/ 21 | void /*? con['init'].strip('"') ?*/(vm_t *vm, vmm_pci_space_t *pci, vmm_io_port_list_t *io_ports); 22 | /*- if 'irq' in con -*/ 23 | void /*? con['irq'].strip('"') ?*/(vm_t *vm); 24 | /*- endif -*/ 25 | /*- endfor -*/ 26 | 27 | int init_cons_num_connections() { 28 | return /*? len(cons) ?*/; 29 | } 30 | 31 | uintptr_t init_cons_init_function(int con) { 32 | /*- if len(cons) == 0 -*/ 33 | return -1; 34 | /*- else -*/ 35 | switch(con) { 36 | /*- for con in cons -*/ 37 | case /*? loop.index0 ?*/: 38 | return (uintptr_t)/*? con['init'].strip('"') ?*/; 39 | /*- endfor -*/ 40 | default: 41 | return -1; 42 | } 43 | /*- endif -*/ 44 | } 45 | 46 | int init_cons_has_interrupt(int con, uintptr_t *badge, uintptr_t *fun) { 47 | /*- if len(cons) == 0 -*/ 48 | return -1; 49 | /*- else -*/ 50 | switch (con) { 51 | /*- for con in cons -*/ 52 | case /*? loop.index0 ?*/: 53 | /*- if 'irq' not in con -*/ 54 | return 0; 55 | /*- else -*/ 56 | *badge = /*? con['badge'] ?*/; 57 | *fun = (uintptr_t)/*? con['irq'].strip('"') ?*/; 58 | return 1; 59 | /*- endif -*/ 60 | /*- endfor -*/ 61 | default: 62 | return -1; 63 | } 64 | /*- endif -*/ 65 | } 66 | -------------------------------------------------------------------------------- /components/Init/templates/seL4VMIOPorts.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | /*- set config_ioports = configuration[me.name].get("vm_ioports") -*/ 14 | /*- set pci_ioports = [] -*/ 15 | /*- set nonpci_ioports = [] -*/ 16 | /*- if config_ioports is not none -*/ 17 | /*- for ioport in config_ioports -*/ 18 | /*- set cap = alloc('iport_%d_%d' % (ioport['start'], ioport['end']), seL4_IA32_IOPort, start_port=ioport['start'], end_port=ioport['end']) -*/ 19 | /*- if ioport['pci_device'] is not none -*/ 20 | /*- do pci_ioports.append( (cap, ioport['start'], ioport['end'], ioport['name'].strip('"')) ) -*/ 21 | /*- else -*/ 22 | /*- do nonpci_ioports.append( (cap, ioport['start'], ioport['end'], ioport['name'].strip('"')) ) -*/ 23 | /*- endif -*/ 24 | /*- endfor -*/ 25 | /*- endif -*/ 26 | 27 | int ioports_num_pci_ioports() { 28 | return /*? len(pci_ioports) ?*/; 29 | } 30 | 31 | int ioports_num_nonpci_ioports() { 32 | return /*? len(nonpci_ioports) ?*/; 33 | } 34 | 35 | const char *ioports_get_pci_ioport(int num, seL4_CPtr *cap, uint16_t *start, uint16_t *end) { 36 | /*- if len(pci_ioports) == 0 -*/ 37 | return NULL; 38 | /*- else -*/ 39 | switch (num) { 40 | /*- for cap, start, end, name in pci_ioports -*/ 41 | case /*? loop.index0 ?*/: 42 | *cap = /*? cap ?*/; 43 | *start = /*? start ?*/; 44 | *end = /*? end ?*/; 45 | return "/*? name ?*/"; 46 | /*- endfor -*/ 47 | default: 48 | return NULL; 49 | } 50 | /*- endif -*/ 51 | } 52 | 53 | const char *ioports_get_nonpci_ioport(int num, seL4_CPtr *cap, uint16_t *start, uint16_t *end) { 54 | /*- if len(nonpci_ioports) == 0 -*/ 55 | return NULL; 56 | /*- else -*/ 57 | switch (num) { 58 | /*- for cap, start, end, name in nonpci_ioports -*/ 59 | case /*? loop.index0 ?*/: 60 | *cap = /*? cap ?*/; 61 | *start = /*? start ?*/; 62 | *end = /*? end ?*/; 63 | return "/*? name ?*/"; 64 | /*- endfor -*/ 65 | default: 66 | return NULL; 67 | } 68 | /*- endif -*/ 69 | } 70 | 71 | seL4_CPtr ioports_get_ioport(uint16_t start, uint16_t end) { 72 | /*- set all_ports = pci_ioports + nonpci_ioports -*/ 73 | /*- if len(all_ports) == 0 -*/ 74 | return 0; 75 | /*- else -*/ 76 | /*- for cap, start, end, name in all_ports -*/ 77 | if (start >= /*? start ?*/ && end <= /*? end ?*/) { 78 | return /*? cap ?*/; 79 | } 80 | /*- endfor -*/ 81 | return 0; 82 | /*- endif -*/ 83 | } 84 | -------------------------------------------------------------------------------- /components/Init/templates/seL4VMIRQs.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | /*- set config_irqs = configuration[me.name].get("vm_irqs") -*/ 14 | /*- set irqs = [] -*/ 15 | /*- set irqnotification_object = alloc_obj('irq_notification_obj', seL4_NotificationObject) -*/ 16 | /*- set irqnotification_object_cap = alloc_cap('irq_notification_obj', irqnotification_object, read=True) -*/ 17 | /*- if config_irqs is not none -*/ 18 | /*- for irq in config_irqs -*/ 19 | /*- set cap = alloc('irq_%d_%d' % (irq['ioapic'], irq['source']), seL4_IRQHandler, vector=irq['dest'], ioapic = irq['ioapic'], ioapic_pin = irq['source'], level = irq['level_trig'], polarity = irq['active_low'], notification=my_cnode[irqnotification_object_cap]) -*/ 20 | /*- do irqs.append( (irq['name'].strip('"'), irq['ioapic'], irq['source'], irq['level_trig'], irq['active_low'], irq['dest'], cap) ) -*/ 21 | /*- endfor -*/ 22 | /*- endif -*/ 23 | 24 | int irqs_num_irqs() { 25 | return /*? len(irqs) ?*/; 26 | } 27 | 28 | const char * irqs_get_irq(int irq, seL4_CPtr *irq_handler, uint8_t *ioapic, uint8_t *source, int *level_trig, int *active_low, uint8_t *dest) { 29 | /*- if len(irqs) == 0 -*/ 30 | return NULL; 31 | /*- else -*/ 32 | switch (irq) { 33 | /*- for name, ioapic, source, level_trig, active_low, dest, cap in irqs -*/ 34 | case /*? loop.index0 ?*/: 35 | *irq_handler = /*? cap ?*/; 36 | *ioapic = /*? ioapic ?*/; 37 | *source = /*? source ?*/; 38 | *level_trig = /*? level_trig ?*/; 39 | *active_low = /*? active_low ?*/; 40 | *dest = /*? dest ?*/; 41 | return "/*? name ?*/"; 42 | /*- endfor -*/ 43 | default: 44 | return NULL; 45 | } 46 | /*- endif -*/ 47 | } 48 | -------------------------------------------------------------------------------- /components/Init/templates/seL4VMPCIDevices.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | /*- set iospace_domain = configuration[me.name].get('iospace_domain') -*/ 14 | 15 | /*- set config_pci = configuration[me.name].get("pci_devices") -*/ 16 | /*- set has_iospace = configuration[me.name].get("pci_devices_iospace") -*/ 17 | /*- set devices = [] -*/ 18 | /*- set device_mem = [] -*/ 19 | 20 | /*- set bits_to_frame_type = { 12:seL4_FrameObject, 20:seL4_ARM_SectionObject, 21:seL4_ARM_SectionObject } -*/ 21 | 22 | /*- if config_pci is not none -*/ 23 | /*- for device in config_pci -*/ 24 | /*- set bus = device['bus'] -*/ 25 | /*- set dev = device['dev'] -*/ 26 | /*- set fun = device['fun'] -*/ 27 | /*- set pciid = bus * 256 + dev * 8 + fun -*/ 28 | /*- set devid = iospace_domain * 65536 + pciid -*/ 29 | /*- set iospace_cap = [] -*/ 30 | /*- if has_iospace -*/ 31 | /*- set cap = alloc('iospace_%d' % devid, seL4_IA32_IOSpace, domainID = iospace_domain, bus = bus, dev = dev, fun = fun) -*/ 32 | /*- do iospace_cap.append(cap) -*/ 33 | /*- endif -*/ 34 | /*- set mem_ranges = [] -*/ 35 | /*- for mem in device['memory'] -*/ 36 | /*- for frame_offset in range(0, mem['size'], 2 ** mem['page_bits']) -*/ 37 | /*- set frame = mem['paddr'] + frame_offset -*/ 38 | /*- set object = alloc_obj('mmio_frame_%d' % frame, bits_to_frame_type[mem['page_bits']], paddr=frame) -*/ 39 | /*- set cap = alloc_cap('mmio_frame_%d' % frame, object, read=true, write=true) -*/ 40 | /*- do device_mem.append( (frame, cap) ) -*/ 41 | /*- endfor -*/ 42 | /*- do mem_ranges.append( (mem['paddr'], mem['size'], mem['page_bits']) ) -*/ 43 | /*- endfor -*/ 44 | /*- do devices.append( (device['name'].strip('"'), bus, dev, fun, iospace_cap, device['irq'].strip('"'), mem_ranges) ) -*/ 45 | /*- endfor -*/ 46 | /*- endif -*/ 47 | 48 | int pci_devices_num_devices() { 49 | return /*? len(devices) ?*/; 50 | } 51 | 52 | const char *pci_devices_get_device(int pci_dev, uint8_t *bus, uint8_t *dev, uint8_t *fun, seL4_CPtr *iospace_cap) { 53 | /*- if len(devices) == 0 -*/ 54 | return NULL; 55 | /*- else -*/ 56 | switch(pci_dev) { 57 | /*- for name, bus, dev, fun, iospace_cap, irq, mem in devices -*/ 58 | case /*? loop.index0 ?*/: 59 | *bus = /*? bus ?*/; 60 | *dev = /*? dev ?*/; 61 | *fun = /*? fun ?*/; 62 | /*- if len(iospace_cap) == 0 -*/ 63 | *iospace_cap = 0; 64 | /*- else -*/ 65 | *iospace_cap = /*? iospace_cap[0] ?*/; 66 | /*- endif -*/ 67 | return "/*? name ?*/"; 68 | /*- endfor -*/ 69 | default: 70 | return NULL; 71 | } 72 | /*- endif -*/ 73 | } 74 | 75 | int pci_devices_num_device_mem(int pci_dev) { 76 | /*- if len(devices) == 0 -*/ 77 | return -1; 78 | /*- else -*/ 79 | switch(pci_dev) { 80 | /*- for name, bus, dev, fun, iospace_cap, irq, mem in devices -*/ 81 | case /*? loop.index0 ?*/: 82 | return /*? len(mem) ?*/; 83 | /*- endfor -*/ 84 | default: 85 | return -1; 86 | } 87 | /*- endif -*/ 88 | } 89 | 90 | const char *pci_devices_get_device_irq(int pci_dev) { 91 | /*- if len(devices) == 0 -*/ 92 | return NULL; 93 | /*- else -*/ 94 | switch(pci_dev) { 95 | /*- for name, bus, dev, fun, iospace_cap, irq, mem in devices -*/ 96 | case /*? loop.index0 ?*/: 97 | return "/*? irq ?*/"; 98 | /*- endfor -*/ 99 | default: 100 | return NULL; 101 | } 102 | /*- endif -*/ 103 | } 104 | 105 | int pci_devices_get_device_mem(int pci_dev, int mem, uintptr_t *paddr, size_t *size, int *page_bits) { 106 | /*- if len(devices) == 0 -*/ 107 | return -1; 108 | /*- else -*/ 109 | switch(pci_dev) { 110 | /*- for name, bus, dev, fun, iospace_cap, irq, mem in devices -*/ 111 | case /*? loop.index0 ?*/: 112 | /*- if len(mem) == 0 -*/ 113 | return -1; 114 | /*- else -*/ 115 | switch(mem) { 116 | /*- for paddr, size, page_bits in mem -*/ 117 | case /*? loop.index0 ?*/: 118 | *paddr = /*? paddr ?*/; 119 | *size = /*? size ?*/; 120 | *page_bits = /*? page_bits ?*/; 121 | return 0; 122 | /*- endfor -*/ 123 | default: 124 | return -1; 125 | } 126 | /*- endif -*/ 127 | /*- endfor -*/ 128 | default: 129 | return -1; 130 | } 131 | /*- endif -*/ 132 | } 133 | 134 | seL4_CPtr pci_devices_get_device_mem_frame(uintptr_t paddr) { 135 | /*- if len(device_mem) == 0 -*/ 136 | return 0; 137 | /*- else -*/ 138 | switch(paddr) { 139 | /*- for paddr, cap in device_mem -*/ 140 | case /*? paddr ?*/: 141 | return /*? cap ?*/; 142 | /*- endfor -*/ 143 | default: 144 | return 0; 145 | } 146 | /*- endif -*/ 147 | } 148 | -------------------------------------------------------------------------------- /components/Sataserver/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2021, Data61, CSIRO (ABN 41 687 119 230) 3 | # Copyright 2019, DornerWorks 4 | # 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | cmake_minimum_required(VERSION 3.8.2) 8 | 9 | project(Sataserver C) 10 | 11 | set(configure_string "") 12 | 13 | config_option( 14 | SataserverUseAHCI 15 | SATASERVER_USE_AHCI 16 | "Enables the use of SATA AHCI interface for the Sataserver." 17 | DEFAULT 18 | OFF 19 | ) 20 | 21 | add_config_library(sataserver "${configure_string}") 22 | 23 | if(SataserverUseAHCI STREQUAL "ON") 24 | if(NOT "${CAmkESVMDestHardware}" STREQUAL "") 25 | CAmkESAddCPPInclude( 26 | "${CMAKE_CURRENT_LIST_DIR}/include/plat/${KernelPlatform}/${CAmkESVMDestHardware}" 27 | ) 28 | else() 29 | message( 30 | FATAL_ERROR 31 | "Sataserver is using AHCI but CAmkESVMDestHardware is not set, cannot find hardware details" 32 | ) 33 | endif() 34 | else() 35 | # Add the empty sata definitions file 36 | CAmkESAddCPPInclude("${CMAKE_CURRENT_LIST_DIR}/include/plat/empty") 37 | endif() 38 | 39 | # Find header with hardware details, can find the empty 40 | DeclareCAmkESComponent( 41 | Sataserver 42 | SOURCES 43 | src/sataserver.c 44 | INCLUDES 45 | include 46 | LIBS 47 | sel4allocman 48 | sel4platsupport 49 | satadrivers 50 | sataserver_Config 51 | ) 52 | -------------------------------------------------------------------------------- /components/Sataserver/Sataserver.camkes: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Dornerworks 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | import ; 7 | import ; 8 | 9 | #include 10 | 11 | #ifdef SATADRIVER_AHCI_ENABLE 12 | component HWSata { 13 | hardware; 14 | HARDWARE_SATA_PROVIDES_INTERFACES 15 | }; 16 | #endif 17 | 18 | component Sataserver { 19 | has mutex sataserver_mux; 20 | provides SataserverInterface client; 21 | attribute int iospace_id; 22 | /* format for bdf is "BUS:DEV.fun,BUS:DEV.fun,..." where BUS and DEV are hex and FUN is decimal */ 23 | attribute string pci_bdfs; 24 | /* Some controllers have an odd quirk where they use multiple PCI ports. Should match number of 25 | * ports set in the pci_bdfs string. See https://bugzilla.kernel.org/show_bug.cgi?id=42679 26 | * for description of why this is needed 27 | */ 28 | attribute int num_bdfs; 29 | attribute int drive; 30 | 31 | uses PutChar putchar; 32 | 33 | #ifdef SATADRIVER_AHCI_ENABLE 34 | HARDWARE_SATA_INTERFACES 35 | 36 | /* Connect the hardware Sata to the Sata component */ 37 | composition { 38 | HARDWARE_SATA_COMPOSITION 39 | } 40 | configuration { 41 | HARDWARE_SATA_CONFIG 42 | } 43 | #endif 44 | } 45 | -------------------------------------------------------------------------------- /components/Sataserver/include/plat/empty/plat/sata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | /* 7 | * This file is intentionally empty. 8 | */ 9 | -------------------------------------------------------------------------------- /components/Sataserver/include/plat/pc99/optiplex/plat/sata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Dornerworks 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | #pragma once 7 | 8 | #define SATADRIVER_AHCI_ENABLE 9 | 10 | #define HARDWARE_SATA_PROVIDES_INTERFACES \ 11 | dataport Buf mmio; 12 | 13 | #define HARDWARE_SATA_INTERFACES \ 14 | dataport Buf ahcidriver; 15 | 16 | #define HARDWARE_SATA_COMPOSITION \ 17 | component HWSata HWsata; \ 18 | connection seL4HardwareMMIO satadrivermmio(from ahcidriver, to HWsata.mmio); 19 | 20 | #define HARDWARE_SATA_CONFIG \ 21 | /* In AHCI mode the PCI device has an associated memory space */ \ 22 | HWsata.mmio_paddr = 0xfebd6000; \ 23 | HWsata.mmio_size = 0x1000; 24 | -------------------------------------------------------------------------------- /components/Sataserver/include/plat/pc99/supermicro/plat/sata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Dornerworks 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | #pragma once 7 | 8 | #define SATADRIVER_AHCI_ENABLE 9 | 10 | #define HARDWARE_SATA_PROVIDES_INTERFACES \ 11 | dataport Buf mmio; 12 | 13 | #define HARDWARE_SATA_INTERFACES \ 14 | dataport Buf ahcidriver; 15 | 16 | #define HARDWARE_SATA_COMPOSITION \ 17 | component HWSata HWsata; \ 18 | connection seL4HardwareMMIO satadrivermmio(from ahcidriver, to HWsata.mmio); 19 | 20 | #define HARDWARE_SATA_CONFIG \ 21 | /* In AHCI mode the PCI device has an associated memory space */ \ 22 | HWsata.mmio_paddr = 0xaa180000; \ 23 | HWsata.mmio_size = 0x1000; 24 | -------------------------------------------------------------------------------- /components/Sataserver/include/sataserver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Dornerworks 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | #pragma once 7 | 8 | #define SATASERVER_STATUS_GOOD 0 9 | #define SATASERVER_STATUS_NOT_DONE 1 10 | #define SATASERVER_STATUS_INVALID_CONF 2 11 | -------------------------------------------------------------------------------- /components/StringReverse/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2018, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.8.2) 8 | 9 | project(StringReverse C) 10 | 11 | DeclareCAmkESComponent(StringReverse SOURCES src/string_reverse.c INCLUDES include) 12 | -------------------------------------------------------------------------------- /components/StringReverse/StringReverse.camkes: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | component StringReverse { 8 | control; 9 | consumes Ready ready; 10 | emits Done done; 11 | dataport Buf(8192) src_dp; 12 | dataport Buf(8192) dest_dp; 13 | 14 | maybe uses PutChar putchar; 15 | } 16 | -------------------------------------------------------------------------------- /components/StringReverse/include/string_reverse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #pragma once 8 | 9 | #define STRING_REVERSE_BUFSIZE 8192 10 | -------------------------------------------------------------------------------- /components/StringReverse/src/string_reverse.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | static void reverse_dataport_string(volatile char *src, volatile char *dest, size_t n) 13 | { 14 | 15 | int len = strnlen((char *)src, n - 1); 16 | 17 | for (int i = 0; i < len; i++) { 18 | dest[i] = src[len - i - 1]; 19 | } 20 | 21 | dest[len] = '\0'; 22 | } 23 | 24 | int run(void) 25 | { 26 | 27 | set_putchar(putchar_putchar); 28 | 29 | while (1) { 30 | ready_wait(); 31 | 32 | reverse_dataport_string(src_dp, dest_dp, STRING_REVERSE_BUFSIZE); 33 | 34 | done_emit(); 35 | } 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /components/UDPServer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2018, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.8.2) 8 | 9 | project(UDPServer C) 10 | 11 | DeclareCAmkESComponent(UDPServer SOURCES src/udpserver.c LIBS sel4camkes ethdrivers lwip sel4vspace) 12 | -------------------------------------------------------------------------------- /components/UDPServer/UDPServer.camkes: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | import ; 8 | import ; 9 | import ; 10 | import ; 11 | 12 | component UDPServer { 13 | control; 14 | has mutex lwip; 15 | 16 | uses Ethdriver ethdriver; 17 | attribute string udp_ip_addr; 18 | attribute string multicast_addr; 19 | attribute int num_client_recv_bufs; 20 | 21 | provides UDPRecv client_recv; 22 | provides UDPSend client_send; 23 | } 24 | -------------------------------------------------------------------------------- /components/UDPServer/src/udpserver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | /* get rid of the camkes ERR_IF macro that collides with lwip one */ 12 | #undef ERR_IF 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | static void low_level_init(struct eth_driver *driver, uint8_t *mac, int *mtu) 21 | { 22 | *mtu = 1500; 23 | ethdriver_mac(&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); 24 | } 25 | 26 | extern void *ethdriver_buf; 27 | 28 | static void raw_poll(struct eth_driver *driver) 29 | { 30 | int len; 31 | int status; 32 | status = ethdriver_rx(&len); 33 | while (status != -1) { 34 | void *buf; 35 | void *cookie; 36 | buf = (void *)driver->i_cb.allocate_rx_buf(driver->cb_cookie, len, &cookie); 37 | assert(buf); 38 | memcpy(buf, (void *)ethdriver_buf, len); 39 | driver->i_cb.rx_complete(driver->cb_cookie, 1, &cookie, (unsigned int *)&len); 40 | if (status == 1) { 41 | status = ethdriver_rx(&len); 42 | } else { 43 | /* if status is 0 we already saw the last packet */ 44 | assert(status == 0); 45 | status = -1; 46 | } 47 | } 48 | } 49 | 50 | static int raw_tx(struct eth_driver *driver, unsigned int num, uintptr_t *phys, unsigned int *len, void *cookie) 51 | { 52 | unsigned int total_len = 0; 53 | int i; 54 | void *p = (void *)ethdriver_buf; 55 | int err; 56 | 57 | for (i = 0; i < num; i++) { 58 | memcpy(p + total_len, (void *)phys[i], len[i]); 59 | total_len += len[i]; 60 | } 61 | 62 | /* Retry whilst the link is down */ 63 | while ((err = ethdriver_tx(total_len)) == ETHIF_TX_FAILED) { 64 | err = lwip_unlock(); 65 | err = lwip_lock(); 66 | } 67 | 68 | return ETHIF_TX_COMPLETE; 69 | } 70 | 71 | static void handle_irq(struct eth_driver *driver, int irq) 72 | { 73 | raw_poll(driver); 74 | } 75 | 76 | static struct raw_iface_funcs iface_fns = { 77 | .raw_handleIRQ = handle_irq, 78 | .print_state = NULL, 79 | .low_level_init = low_level_init, 80 | .raw_tx = raw_tx, 81 | .raw_poll = raw_poll 82 | }; 83 | 84 | static int ethdriver_init(struct eth_driver *eth_driver, ps_io_ops_t io_ops, void *config) 85 | { 86 | eth_driver->eth_data = NULL; 87 | eth_driver->dma_alignment = 1; 88 | eth_driver->i_fn = iface_fns; 89 | return 0; 90 | } 91 | 92 | static void *malloc_dma_alloc(void *cookie, size_t size, int align, int cached, ps_mem_flags_t flags) 93 | { 94 | assert(cached); 95 | int error; 96 | void *ret; 97 | error = posix_memalign(&ret, align, size); 98 | if (error) { 99 | return NULL; 100 | } 101 | return ret; 102 | } 103 | 104 | static void malloc_dma_free(void *cookie, void *addr, size_t size) 105 | { 106 | free(addr); 107 | } 108 | 109 | static uintptr_t malloc_dma_pin(void *cookie, void *addr, size_t size) 110 | { 111 | return (uintptr_t)addr; 112 | } 113 | 114 | static void malloc_dma_unpin(void *cookie, void *addr, size_t size) 115 | { 116 | } 117 | 118 | static void malloc_dma_cache_op(void *cookie, void *addr, size_t size, dma_cache_op_t op) 119 | { 120 | } 121 | 122 | static ps_io_ops_t io_ops; 123 | static struct netif _netif; 124 | static lwip_iface_t _lwip_driver; 125 | 126 | void pre_init(void) 127 | { 128 | ip_addr_t netmask, ipaddr, gw, multicast; 129 | struct netif *netif; 130 | int UNUSED error; 131 | lwip_iface_t *lwip_driver; 132 | memset(&io_ops, 0, sizeof(io_ops)); 133 | io_ops.dma_manager = (ps_dma_man_t) { 134 | .cookie = NULL, 135 | .dma_alloc_fn = malloc_dma_alloc, 136 | .dma_free_fn = malloc_dma_free, 137 | .dma_pin_fn = malloc_dma_pin, 138 | .dma_unpin_fn = malloc_dma_unpin, 139 | .dma_cache_op_fn = malloc_dma_cache_op 140 | }; 141 | lwip_driver = ethif_new_lwip_driver_no_malloc(io_ops, &io_ops.dma_manager, ethdriver_init, NULL, &_lwip_driver); 142 | assert(lwip_driver); 143 | ipaddr_aton("0.0.0.0", &gw); 144 | ipaddr_aton(udp_ip_addr, &ipaddr); 145 | ipaddr_aton(multicast_addr, &multicast); 146 | ipaddr_aton("255.255.255.0", &netmask); 147 | 148 | error = lwip_lock(); 149 | 150 | lwip_init(); 151 | netif = netif_add(&_netif, &ipaddr, &netmask, &gw, lwip_driver, ethif_get_ethif_init(lwip_driver), 152 | ethernet_input); 153 | assert(netif); 154 | netif_set_up(netif); 155 | netif_set_default(netif); 156 | 157 | if (ip_addr_ismulticast(&multicast)) { 158 | igmp_joingroup(&ipaddr, &multicast); 159 | } 160 | 161 | error = lwip_unlock(); 162 | } 163 | 164 | /* Provided by the Ethdriver template */ 165 | seL4_CPtr ethdriver_notification(void); 166 | 167 | int run() 168 | { 169 | int UNUSED error; 170 | while (1) { 171 | seL4_Wait(ethdriver_notification(), NULL); 172 | error = lwip_lock(); 173 | ethif_lwip_handle_irq(&_lwip_driver, 0); 174 | error = lwip_unlock(); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /components/VM/PIC.camkes: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | component PIC { 8 | hardware; 9 | emits Irq0 irq0; 10 | emits Irq1 irq1; 11 | emits Irq3 irq3; 12 | emits Irq4 irq4; 13 | emits Irq5 irq5; 14 | emits Irq6 irq6; 15 | emits Irq7 irq7; 16 | emits Irq8 irq8; 17 | emits Irq9 irq9; 18 | emits Irq10 irq10; 19 | emits Irq11 irq11; 20 | emits Irq12 irq12; 21 | emits Irq13 irq13; 22 | emits Irq14 irq14; 23 | emits Irq15 irq15; 24 | } 25 | -------------------------------------------------------------------------------- /components/VM/configurations/connections.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | /* 8 | * This file contains macros to try and hide the boilerplate required to use crossvm connections. 9 | * 10 | * The following macros are private and used to implement the public macros at the end of this file. 11 | * 12 | * See the end of the file for a description of this _macro api_. 13 | */ 14 | 15 | /* 16 | * Calls macro f with each argument e.g. a,b,c,.. 17 | */ 18 | #define __CALL1(f,a) f(a) 19 | #define __CALL2(f,a,b) f(a) f(b) 20 | #define __CALL3(f,a,b,c) f(a) f(b) f(c) 21 | #define __CALL4(f,a,b,c,d) f(a) f(b) f(c) f(d) 22 | 23 | /* 24 | * Calls macro f with p for each argument e.g. a,b,c,.. 25 | */ 26 | #define __CALL_SINGLE1(f,p,a) f(p, a) 27 | #define __CALL_SINGLE2(f,p,a,b) f(p, a) f(p, b) 28 | #define __CALL_SINGLE3(f,p,a,b,c) f(p, a) f(p, b) f(p, c) 29 | #define __CALL_SINGLE4(f,p,a,b,c,d) f(p, a) f(p, b) f(p, c) f(p, d) 30 | 31 | /* 32 | * Calls macro f with p and an index for each argument e.g. a,b,c,.. 33 | */ 34 | #define __CALL_NUM1(f,p,a) f(p, a, 0) 35 | #define __CALL_NUM2(f,p,a,b) f(p, a, 0) f(p, b, 1) 36 | #define __CALL_NUM3(f,p,a,b,c) f(p, a, 0) f(p, b, 1) f(p, c, 2) 37 | #define __CALL_NUM4(f,p,a,b,c,d) f(p, a, 0) f(p, b, 1) f(p, c, 2) f(p, d, 3) 38 | 39 | /* 40 | * Call macro utils 41 | */ 42 | #define __CALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n 43 | #define __CALL_NARGS_FROM0(...) __CALL_NARGS_X(__VA_ARGS__,7,6,5,4,3,2,1,0,) 44 | #define __CALL_NARGS_FROM1(...) __CALL_NARGS_X(__VA_ARGS__,8,7,6,5,4,3,2,1,) 45 | #define __CALL_CONCAT_X(a,b) a##b 46 | #define __CALL_CONCAT(a,b) __CALL_CONCAT_X(a,b) 47 | #define __CALL_DISP_FROM0(f, b,...) __CALL_CONCAT(b,__CALL_NARGS_FROM0(__VA_ARGS__))(f, __VA_ARGS__) 48 | #define __CALL_DISP_FROM1(f, b,...) __CALL_CONCAT(b,__CALL_NARGS_FROM1(__VA_ARGS__))(f, __VA_ARGS__) 49 | 50 | #define __CALL(f, args...) __CALL_DISP_FROM1(f, __CALL, args) 51 | #define __CALL_SINGLE(f, args...) __CALL_DISP_FROM0(f, __CALL_SINGLE, args) 52 | #define __CALL_NUM(f, args...) __CALL_DISP_FROM0(f, __CALL_NUM, args) 53 | 54 | /* 55 | * This defines the send and recv queues for a 56 | * virtio vswitch connection with a given vm ("vm_id") 57 | * Typically called in the Init definition 58 | */ 59 | #define __COMPONENT_DECL_ADD_INTERFACE_END(vm_id) \ 60 | uses VirtQueueDrv ether_##vm_id##_send; \ 61 | uses VirtQueueDev ether_##vm_id##_recv; 62 | 63 | #define __COMPONENT_DECL(base_id, vm_id...) \ 64 | __CALL(__COMPONENT_DECL_ADD_INTERFACE_END, vm_id) 65 | 66 | 67 | /* 68 | * Expands the from ends of a connection between base_id vm and target vm 69 | */ 70 | #define __CONNECTION_ADD_INTERFACE_END(base_id, target_id) \ 71 | from vm##base_id.ether_##target_id##_send, from vm##base_id.ether_##target_id##_recv, 72 | 73 | #define __CONNECTION_PERVM_ADD_INTERFACES(base_id, vm_ids...) \ 74 | __CALL_SINGLE(__CONNECTION_ADD_INTERFACE_END, base_id, vm_ids) 75 | 76 | /** 77 | * Expands the config attributes of a VMs send and recv queue 78 | * Called once per connection per vm 79 | *_id is used for calling buffqueue_register 80 | *_attributes is used for shared memory connector. 81 | * currently each chan gets its own shared memory region, 82 | * keyed by base_id##target_id on send side and target_id##base_id on receive side 83 | *_global_endpoint refers to the notification object of the other vm 84 | *_badge refers to the badge that the other vm will receive on its notification object 85 | */ 86 | #define __CONFIG_PER_CONNECTION(base_id, target_id, idx) \ 87 | vm##base_id.ether_##target_id##_send_id = idx *2; \ 88 | vm##base_id.ether_##target_id##_send_attributes = VAR_STRINGIZE(base_id##target_id); \ 89 | vm##base_id.ether_##target_id##_recv_id = idx *2 + 1; \ 90 | vm##base_id.ether_##target_id##_recv_attributes = VAR_STRINGIZE(target_id##base_id); \ 91 | vm##base_id.ether_##target_id##_send_shmem_size = 32768; \ 92 | vm##base_id.ether_##target_id##_recv_shmem_size = 32768; \ 93 | 94 | // Add macaddress to virtqueue mapping. Called per connection per vm 95 | #define __ADD_MACADDR_MAPPING(base_id, vm_id, idx) \ 96 | {"mac_addr": VM##vm_id##_MACADDRESS, "send_id": idx*2, "recv_id":idx*2+1}, 97 | 98 | // Expand config section, called once per vm 99 | #define __CONFIG_EXPAND_PERVM(base_id, vm_ids...) \ 100 | __CALL_NUM(__CONFIG_PER_CONNECTION, base_id, vm_ids) \ 101 | vm##base_id.vswitch_mac_address = VM##base_id##_MACADDRESS; \ 102 | vm##base_id.vswitch_layout = [__CALL_NUM(__ADD_MACADDR_MAPPING, base_id, vm_ids)]; \ 103 | 104 | 105 | // Create a single virtqueue drv/dev pair. 106 | #define __ADD_TOPOLOGY(base_id, target_id) \ 107 | { "drv" : VAR_STRINGIZE(vm##base_id.ether_##target_id##_send) , "dev" : VAR_STRINGIZE(vm##target_id.ether_##base_id##_recv)}, 108 | 109 | // Connect the virtqueue ends together within the single connection instance. 110 | #define __CONFIG_EXPAND_TOPOLOGY(base_id, vm_ids...) \ 111 | __CALL_SINGLE(__ADD_TOPOLOGY, base_id, vm_ids) 112 | 113 | 114 | 115 | /** PUBLIC FUNCTIONS 116 | * Types: 117 | * vm_id: A unique vm identifier. VMs should be numbered from 0. 118 | * f(base_id, vm_ids...) a varargs macro that is called with vm_id arguments. 119 | * topology(f): A macro that takes a function f, and calls it N times with each VM in the base_id param, 120 | and the vms it connects to in the following parameters. 121 | eg: #define topology_all(f) f(0,1,2) f(1,0,2) f(2,0,1) 122 | describes a topology where 3 vms are each connected to each other. 123 | * VM##vm_id##_##topology(f) A macro that calls f only for vm_id. 124 | eg: #define VM0_topology_all(f) f(0,1,2) 125 | Note it is possible/encouraged to define topology(f) in terms of VM##vm_id##_##topology(f) 126 | eg: #define topology_all(f) VM0_topology_all(f) VM1_topology_all(f) VM2_topology_all(f) 127 | * to_end: A component instance.interface that has been defined as: provides VirtQueue 128 | * VM##vm_id##_##MACADDRESS: The macaddress of vm_id. This will become the macaddress of the created VirtioNet device 129 | * 130 | * Functions: 131 | * VM_CONNECTION_COMPONENT_DEF(vm_id, topology): Defines interfaces for vm_id and topology. 132 | * VM_CONNECTION_CONNECT_VMS(to_end, topology): Creates connection between all instances of the given topology. 133 | * VM_CONNECTION_CONFIG(to_end, topology): Applies configuration for cross vm connection. 134 | * VM_CONNECTION_INIT_HANDLER(to_end, topology): Add init handler to vmm to create the cross_vm virtio_net device 135 | * 136 | */ 137 | #define VM_CONNECTION_COMPONENT_DEF(vm_id, topology) \ 138 | VM##vm_id##_##topology(__COMPONENT_DECL) 139 | 140 | /* 141 | * Defines a vswitch connection 142 | */ 143 | #define VM_CONNECTION_CONNECT_VMS(to_end, topology) \ 144 | connection seL4VirtQueues topology##_conn(to to_end, topology(__CONNECTION_PERVM_ADD_INTERFACES)); 145 | 146 | #define VM_CONNECTION_CONFIG(to_end, topology) \ 147 | topology(__CONFIG_EXPAND_PERVM) \ 148 | to_end##_topology = [topology(__CONFIG_EXPAND_TOPOLOGY)]; 149 | 150 | #define __INIT_ADD_INTERFACE_END(base_id, target_id) \ 151 | {"init":"make_virtio_net_vswitch_driver_dummy", "badge":"ether_" # target_id "_send_notification_badge()", "irq":"virtio_net_notify_vswitch"}, \ 152 | {"init":"make_virtio_net_vswitch_driver_dummy", "badge":"ether_" # target_id "_recv_notification_badge()", "irq":"virtio_net_notify_vswitch"}, 153 | 154 | #define __CONNECTION_PERVM_ADD_INIT(base_id, vm_ids...) \ 155 | __CALL_SINGLE(__INIT_ADD_INTERFACE_END, base_id, vm_ids) 156 | 157 | #define VM_CONNECTION_INIT_HANDLER(vm_id, topology) \ 158 | VM##vm_id##_##topology(__CONNECTION_PERVM_ADD_INIT) \ 159 | {"init":"make_virtio_net_vswitch"} 160 | -------------------------------------------------------------------------------- /components/VM/configurations/sata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Dornerworks 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | #define VM_INIT_SATA() \ 7 | has mutex virtio_blk_mutex; \ 8 | uses SataserverInterface sataserver_iface; 9 | 10 | #define SATA_COMPOSITION_DEF() \ 11 | component Sataserver sataserver; \ 12 | connection seL4RPCCall sata_serial(from sataserver.putchar, to serial.processed_putchar); 13 | 14 | /* Convenience wrapper for connecting VMs to the SataServer component 15 | * num: vm instance number 16 | */ 17 | #define VM_SATA_CONNECTIONS(num) \ 18 | connection seL4Sataserver sataservercon##num(from vm##num.sataserver_iface, to sataserver.client); 19 | 20 | /* Convenience wrapper for configuring the sataserver 21 | */ 22 | #define VM_SATA_CONFIG() \ 23 | sataserver.simple = true; /* Links component to component.simple.c */ \ 24 | sataserver.cnode_size_bits = 16; /* Changes cnode size from default 12 to 16 */ \ 25 | sataserver.simple_untyped23_pool = 2; /* Creates 2 untyped pools of size 2^23 */ \ 26 | sataserver.heap_size = 0x30000; /* RAM allocation available to sataserver component */ \ 27 | sataserver.dma_pool = 0x20000; \ 28 | sataserver.putchar_attributes = 0; 29 | -------------------------------------------------------------------------------- /components/VM/configurations/vm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #define _VAR_STRINGIZE(...) #__VA_ARGS__ 8 | #define VAR_STRINGIZE(...) _VAR_STRINGIZE(__VA_ARGS__) 9 | 10 | #define _CAT(x, y) x ## y 11 | #define CAT(x, y) _CAT(x, y) 12 | 13 | /* For all the async sources on the intready endpoint the high bit 14 | * is set to indicate that an async event occured, and the low bits 15 | * indicate which async events */ 16 | 17 | #define VM_PIC_BADGE_IRQ_0 134217730 /* BIT(27) | BIT(1) */ 18 | #define VM_PIC_BADGE_IRQ_1 134217732 /* BIT(27) | BIT(2) */ 19 | #define VM_PIC_BADGE_IRQ_2 134217736 /* BIT(27) | BIT(3) */ 20 | #define VM_PIC_BADGE_IRQ_3 134217744 /* BIT(27) | BIT(4) */ 21 | #define VM_PIC_BADGE_IRQ_4 134217760 /* BIT(27) | BIT(5) */ 22 | #define VM_PIC_BADGE_IRQ_5 134217792 /* BIT(27) | BIT(6) */ 23 | #define VM_PIC_BADGE_IRQ_6 134217856 /* BIT(27) | BIT(7) */ 24 | #define VM_PIC_BADGE_IRQ_7 134217984 /* BIT(27) | BIT(8) */ 25 | #define VM_PIC_BADGE_IRQ_8 134218240 /* BIT(27) | BIT(9) */ 26 | #define VM_PIC_BADGE_IRQ_9 134218752 /* BIT(27) | BIT(10) */ 27 | #define VM_PIC_BADGE_IRQ_10 134219776 /* BIT(27) | BIT(11) */ 28 | #define VM_PIC_BADGE_IRQ_11 134221824 /* BIT(27) | BIT(12) */ 29 | #define VM_PIC_BADGE_IRQ_12 134225920 /* BIT(27) | BIT(13) */ 30 | #define VM_PIC_BADGE_IRQ_13 134234112 /* BIT(27) | BIT(14) */ 31 | #define VM_PIC_BADGE_IRQ_14 134250496 /* BIT(27) | BIT(15) */ 32 | #define VM_PIC_BADGE_IRQ_15 134283264 /* BIT(27) | BIT(16) */ 33 | 34 | /* Base definition of the Init component. This gets 35 | * extended in the per Vm configuration */ 36 | #define VM_INIT_DEF() \ 37 | control; \ 38 | uses PutChar putchar; \ 39 | uses PutChar guest_putchar; \ 40 | uses PCIConfig pci_config; \ 41 | uses RTC system_rtc; \ 42 | consumes HaveInterrupt intready; \ 43 | emits HaveInterrupt intready_connector; \ 44 | uses Timer init_timer; \ 45 | /* File Server */ \ 46 | uses FileServerInterface fs; \ 47 | uses GetChar serial_getchar; \ 48 | attribute string kernel_cmdline; \ 49 | attribute string kernel_image; \ 50 | attribute string kernel_relocs; \ 51 | attribute string initrd_image; \ 52 | attribute int iospace_domain; \ 53 | attribute int guest_ram_mb; \ 54 | attribute int cnode_size_bits = 21; \ 55 | attribute vswitch_mapping vswitch_layout[] = []; \ 56 | attribute string vswitch_mac_address = ""; \ 57 | attribute { \ 58 | /* virtq ids */ \ 59 | int send_id; \ 60 | int recv_id; \ 61 | } serial_layout[] = []; \ 62 | attribute { \ 63 | /* cid of the VM on the other side of this connection*/ \ 64 | int cid; \ 65 | /* virtq ids */ \ 66 | int send_id; \ 67 | int recv_id; \ 68 | } socket_layout[] = []; \ 69 | /* unique cid that identifies this vm's socket < 256 */ \ 70 | attribute int guest_cid = 0; \ 71 | /**/ 72 | 73 | /* VM and per VM componenents */ 74 | #define VM_PER_VM_COMPONENTS(num) \ 75 | component Init##num vm##num; \ 76 | /**/ 77 | 78 | 79 | #define VM_PER_VM_CONNECTIONS(num) \ 80 | /* Connect the intready to itself to generate a template for retrieving the AEP */ \ 81 | connection seL4GlobalAsynch intreadycon##num(from vm##num.intready_connector, to vm##num.intready); \ 82 | /* Connect all Init components to the fileserver */ \ 83 | connection seL4RPCDataport fs##num(from vm##num.fs, to fserv.fs_ctrl); \ 84 | /* Connect all the components to the serial server */ \ 85 | connection seL4RPCCall serial_vm##num(from vm##num.putchar, to serial.processed_putchar); \ 86 | connection seL4RPCCall serial_guest_vm##num(from vm##num.guest_putchar, to serial.raw_putchar); \ 87 | /* Connect the emulated serial input to the serial server */ \ 88 | connection seL4SerialServer serial_input##num(from vm##num.serial_getchar, to serial.getchar); \ 89 | /* Temporarily connect the VM directly to the RTC */ \ 90 | connection seL4RPCCall rtctest##num(from vm##num.system_rtc, to rtc.rtc); \ 91 | /* Connect the VM to the timer server */ \ 92 | connection seL4TimeServer CAT(pit##num,_timer)(from vm##num.init_timer, to time_server.the_timer); \ 93 | /* Connect config space to main VM */ \ 94 | connection seL4RPCCall pciconfig##num(from vm##num.pci_config, to pci_config.pci_config); \ 95 | /**/ 96 | 97 | #define VM_MAYBE_ZONE_DMA(num) 98 | 99 | #define VM_PER_VM_CONFIG_DEF(num) \ 100 | vm##num.fs_shmem_size = 0x1000; \ 101 | vm##num.serial_getchar_attributes = VAR_STRINGIZE(num); \ 102 | vm##num.serial_getchar_shmem_size = 0x1000; \ 103 | vm##num.simple = true; \ 104 | vm##num.asid_pool = true; \ 105 | vm##num.global_endpoint_mask = 0x1fffffff & ~0x1fffe; \ 106 | vm##num.global_endpoint_base = 1 << 27; \ 107 | VM_MAYBE_ZONE_DMA(num) \ 108 | /**/ 109 | 110 | #define VM_COMPOSITION_DEF() \ 111 | component FileServer fserv; \ 112 | /* Hardware multiplexing components */ \ 113 | component SerialServer serial; \ 114 | component PCIConfigIO pci_config; \ 115 | component TimeServer time_server; \ 116 | component RTC rtc; \ 117 | /* These components don't do much output, but just in case they can pretend to \ 118 | * be vm0 */ \ 119 | connection seL4RPCCall serial_pci_config(from pci_config.putchar, to serial.processed_putchar); \ 120 | connection seL4RPCCall serial_time_server(from time_server.putchar, to serial.processed_putchar); \ 121 | connection seL4RPCCall serial_rtc(from rtc.putchar, to serial.processed_putchar); \ 122 | /* COnnect the serial server to the timer server */ \ 123 | connection seL4TimeServer serialserver_timer(from serial.timeout, to time_server.the_timer); \ 124 | /**/ 125 | 126 | #define VM_PER_VM_COMP_DEF(num) \ 127 | VM_PER_VM_COMPONENTS(num) \ 128 | VM_PER_VM_CONNECTIONS(num) \ 129 | /**/ 130 | 131 | #define VM_CONFIGURATION_DEF() \ 132 | fserv.heap_size = 0x30000; \ 133 | time_server.timers_per_client = 12; \ 134 | /* Put the entire time server at the highest priority */ \ 135 | time_server.priority = 255; \ 136 | /* The timer server runs better if it can get the true tsc frequency from the kernel */ \ 137 | time_server.simple_extra_bootinfo = ["SEL4_BOOTINFO_HEADER_X86_TSC_FREQ"]; \ 138 | time_server.simple = true; \ 139 | /* Put the serial interrupt at 200 \ 140 | * but Leave the rest of the serial at default priority */ \ 141 | serial.serial_irq_priority = 200; \ 142 | /* Now the VMM, guest and everything else should be at \ 143 | * the default priority of 100 */ \ 144 | /**/ 145 | -------------------------------------------------------------------------------- /components/VM/vm.camkes: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #include 8 | 9 | import ; 10 | import ; 11 | 12 | import ; 13 | import ; 14 | import ; 15 | import ; 16 | import ; 17 | 18 | import "PIC.camkes"; 19 | 20 | import ; 21 | import ; 22 | import ; 23 | import ; 24 | import ; 25 | import ; 26 | import ; 27 | import ; 28 | import ; 29 | 30 | import ; 31 | 32 | connector seL4UDPSend { 33 | from Procedure with 0 threads; 34 | to Procedure; 35 | } 36 | 37 | connector seL4UDPRecv { 38 | from Procedure with 0 threads; 39 | to Procedure; 40 | attribute bool from_global_endpoint = True; 41 | } 42 | 43 | connector seL4Sataserver { 44 | from Procedures with 0 threads; 45 | to Procedure; 46 | } 47 | 48 | connector seL4MultiSharedData { 49 | from Dataport; 50 | to Dataport; 51 | } 52 | -------------------------------------------------------------------------------- /components/VM_Arm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2018, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.8.2) 8 | 9 | project(VM C) 10 | 11 | set(configure_string "") 12 | 13 | # ARM VM Configuration Options 14 | config_option( 15 | VmOnDemandDeviceInstall 16 | VM_ONDEMAND_DEVICE_INSTALL 17 | "Allow the VMM to install arbitrary devices into the VM as they are accessed." 18 | DEFAULT 19 | ON 20 | ) 21 | 22 | config_option(VmEmmc2NoDMA VM_EMMC2_NODMA "SD access control to prevent DMA \ 23 | Installs SD card into the VM with read only access. Write access is \ 24 | trapped and emulated to ensure that DMA is not used." DEFAULT OFF) 25 | 26 | config_option(VmVUSB VM_VUSB "Para-virtual USB driver \ 27 | Selects the device tree which enables the para virtual USB driver and \ 28 | installs the device into the VM." DEPENDS "KernelPlatformExynos5410" DEFAULT OFF) 29 | 30 | config_option( 31 | VmPCISupport 32 | VM_PCI_SUPPORT 33 | "Enable virtual pci device support" 34 | DEPENDS 35 | "KernelPlatformExynos5410 OR KernelPlatformExynos5422 OR KernelPlatformTx2 OR KernelPlatformQEMUArmVirt OR KernelPlatformOdroidc2 OR KernelPlatformZynqmp" 36 | DEFAULT 37 | OFF 38 | ) 39 | 40 | config_option( 41 | VmVirtioNetArping 42 | VM_VIRTIO_NET_ARPING 43 | "Enable virtio net arping module" 44 | DEPENDS 45 | "KernelPlatformExynos5410 OR KernelPlatformExynos5422 OR KernelPlatformTx2 OR KernelPlatformQEMUArmVirt OR KernelPlatformZynqmp;VmPCISupport" 46 | DEFAULT 47 | OFF 48 | ) 49 | 50 | config_option( 51 | VmVirtioNetVirtqueue 52 | VM_VIRTIO_NET_VIRTQUEUE 53 | "Enable virtio net virtqueue forwarding module" 54 | DEPENDS 55 | "KernelPlatformExynos5410 OR KernelPlatformExynos5422 OR KernelPlatformTx2 OR KernelPlatformQEMUArmVirt OR KernelPlatformZynqmp;VmPCISupport" 56 | DEFAULT 57 | OFF 58 | ) 59 | 60 | config_option( 61 | VmVirtioConsole 62 | VM_VIRTIO_CON 63 | "Enable virtio console module" 64 | DEPENDS 65 | "KernelPlatformExynos5410 OR KernelPlatformExynos5422 OR KernelPlatformQEMUArmVirt;VmPCISupport" 66 | DEFAULT 67 | OFF 68 | ) 69 | 70 | config_choice( 71 | VmRootfs 72 | VM_ROOTFS 73 | "Root file system selection \ 74 | Selects the root device and partition which should be used for the root filesystem. \ 75 | mmcblk0p2 -> Selects partition 2 of the on board eMMC as the root filesystem. \ 76 | mmcblk1p2 -> Selects partition 2 of the on removable SD card as the root filesystem." 77 | "mmcblk0p2;VmRootfsMmcblk0p2;VM_ROOTFS_MMCBLK0P2" 78 | "mmcblk1p2;VmRootfsMmcblk1p2;VM_ROOTFS_MMCBLK1P2" 79 | ) 80 | 81 | config_choice( 82 | VmTk1Rootfs 83 | VM_TK1_ROOTFS 84 | "TK1 boot mode selection. Selects whether to load root file system off emmc or ramdisk \ 85 | initrd -> Selects initrd as the root filesystem. \ 86 | mmcblk0p2 -> Selects partition 2 of the emmc card as the root filesystem." 87 | "initrd;VmTk1InitrdRootfs;VM_TK1_INITRD_ROOTFS" 88 | "mmcblk0p2;VmTk1EmmcRootfs;VM_TK1_EMMC_ROOTFS" 89 | ) 90 | 91 | config_option( 92 | Tk1DeviceFwd 93 | TK1_DEVICE_FWD 94 | "Forward VM access to UART and Clock and reset controller. \ 95 | When using the VM with other components that need access to the UART and clock and reset controller \ 96 | devices, this option will cause the vm to forward the faults over a RPC connection" 97 | DEPENDS 98 | "KernelPlatformTK1" 99 | DEFAULT 100 | OFF 101 | ) 102 | 103 | config_option( 104 | Tk1Insecure 105 | TK1_INSECURE 106 | "Insecure: Give all devices to VM component \ 107 | The option when disabled only passes through UARTD, USB, EMMC, VGIC and a Clock and reset controller" 108 | DEPENDS 109 | "KernelPlatformTK1" 110 | DEFAULT 111 | OFF 112 | ) 113 | 114 | config_option( 115 | VmInitRdFile 116 | VM_INITRD_FILE 117 | "Enables the option for the VM to open and load a seperate initrd file" 118 | DEFAULT 119 | OFF 120 | ) 121 | 122 | config_option( 123 | VmDtbFile 124 | VM_DTB_FILE 125 | "Enables the option for the VM to open and load a seperate dtb file" 126 | DEFAULT 127 | OFF 128 | ) 129 | 130 | config_option( 131 | VmVirtUart 132 | VM_VIRT_UART 133 | "Option for virtualizing console" 134 | DEFAULT 135 | OFF 136 | DEPENDS 137 | "KernelPlatformExynos5410 OR KernelPlatformExynos5422 OR KernelPlatformZynqmp" 138 | ) 139 | 140 | config_choice( 141 | VmZynqmpPetalinuxVersion 142 | ZYNQMP_PETALINUX_VERSION 143 | "The version of Petalinux to use. Default is 2018.3, which will use images \ 144 | compatible with the seL4 kernel device tree" 145 | "2018_3;VmZynqmpPetalinux2018_3;ZYNQMP_PETALINUX_2018_3;KernelPlatformZynqmp" 146 | "2021_1;VmZynqmpPetalinux2021_1;ZYNQMP_PETALINUX_2021_1;KernelPlatformZynqmp" 147 | "2022_1;VmZynqmpPetalinux2022_1;ZYNQMP_PETALINUX_2022_1;KernelPlatformZynqmp" 148 | ) 149 | 150 | add_config_library(arm_vm "${configure_string}") 151 | 152 | DeclareCAmkESARMVM(VM) 153 | -------------------------------------------------------------------------------- /components/VM_Arm/VM.camkes: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | import ; 8 | import ; 9 | import ; 10 | 11 | import ; 12 | import ; 13 | import ; 14 | import ; 15 | 16 | #if TK1DEVICEFWD 17 | import ; 18 | #endif 19 | 20 | #include 21 | 22 | component VM { 23 | VM_INIT_DEF() 24 | } 25 | -------------------------------------------------------------------------------- /components/VM_Arm/configurations/vm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #define _VAR_STRINGIZE(...) #__VA_ARGS__ 8 | #define VAR_STRINGIZE(...) _VAR_STRINGIZE(__VA_ARGS__) 9 | 10 | /* 11 | * Calls macro f with each argument e.g. a,b,c,.. 12 | */ 13 | #define __CALL1(f,a) f(a) 14 | #define __CALL2(f,a,b) f(a) f(b) 15 | #define __CALL3(f,a,b,c) f(a) f(b) f(c) 16 | #define __CALL4(f,a,b,c,d) f(a) f(b) f(c) f(d) 17 | #define __CALL5(f,a,b,c,d,e) f(a) f(b) f(c) f(d) f(e) 18 | #define __CALL6(f,a,b,c,d,e,g) f(a) f(b) f(c) f(d) f(e) f(g) 19 | #define __CALL7(f,a,b,c,d,e,g,h) f(a) f(b) f(c) f(d) f(e) f(g) f(h) 20 | #define __CALL8(f,a,b,c,d,e,g,h,i) f(a) f(b) f(c) f(d) f(e) f(g) f(h) f(i) 21 | 22 | #define __CALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n 23 | #define __CALL_CONCAT_X(a,b) a##b 24 | #define __CALL_CONCAT(a,b) __CALL_CONCAT_X(a,b) 25 | #define __CALL_NARGS_FROM(...) __CALL_NARGS_X(__VA_ARGS__,8,7,6,5,4,3,2,1,) 26 | #define __CALL_DISP_FROM(f, b,...) __CALL_CONCAT(b,__CALL_NARGS_FROM(__VA_ARGS__))(f, __VA_ARGS__) 27 | #define __CALL(f, args...) __CALL_DISP_FROM(f, __CALL, args) 28 | 29 | #if TK1DEVICEFWD 30 | #define DEF_TK1DEVICEFWD \ 31 | uses gen_fwd_inf uartfwd; \ 32 | uses gen_fwd_inf clkcarfwd; \ 33 | 34 | #else 35 | #define DEF_TK1DEVICEFWD 36 | #endif 37 | 38 | #if KERNELARMPLATFORM_EXYNOS5410 39 | #define DEF_KERNELARMPLATFORM_EXYNOS5410 \ 40 | uses pwm_inf pwm; \ 41 | dataport Buf cmu_cpu; \ 42 | dataport Buf cmu_top; \ 43 | dataport Buf gpio_right; \ 44 | dataport Buf cmu_core; \ 45 | 46 | #else 47 | #define DEF_KERNELARMPLATFORM_EXYNOS5410 48 | #endif 49 | 50 | #define VM_INIT_DEF() \ 51 | control; \ 52 | uses FileServerInterface fs; \ 53 | DEF_TK1DEVICEFWD \ 54 | DEF_KERNELARMPLATFORM_EXYNOS5410 \ 55 | maybe consumes restart restart_event; \ 56 | has semaphore vm_sem; \ 57 | maybe uses Batch batch; \ 58 | maybe uses PutChar guest_putchar; \ 59 | maybe uses GetChar serial_getchar; \ 60 | maybe uses VirtQueueDev recv; \ 61 | maybe uses VirtQueueDrv send; \ 62 | consumes HaveNotification notification_ready; \ 63 | emits HaveNotification notification_ready_connector; \ 64 | maybe uses VMDTBPassthrough dtb_self; \ 65 | provides VMDTBPassthrough dtb; \ 66 | attribute int base_prio; \ 67 | attribute int num_vcpus = 1; \ 68 | attribute int num_extra_frame_caps; \ 69 | attribute int extra_frame_map_address; \ 70 | attribute { \ 71 | string ram_base; \ 72 | string ram_paddr_base; \ 73 | string ram_size; \ 74 | string dtb_addr; \ 75 | string initrd_addr; \ 76 | string kernel_entry_addr = "-1"; \ 77 | } vm_address_config; \ 78 | attribute { \ 79 | string kernel_name = "linux"; \ 80 | string dtb_name = "linux-dtb"; \ 81 | string initrd_name = "linux-initrd"; \ 82 | string kernel_bootcmdline = ""; \ 83 | string kernel_stdout = ""; \ 84 | string dtb_base_name = ""; \ 85 | int provide_dtb = true; \ 86 | int generate_dtb = false; \ 87 | int provide_initrd = true; \ 88 | int clean_cache = false; \ 89 | int map_one_to_one = false; \ 90 | } vm_image_config; \ 91 | attribute { \ 92 | string linux_ram_base; \ 93 | string linux_ram_paddr_base; \ 94 | string linux_ram_size; \ 95 | string linux_ram_offset = "0"; /* obsolete */ \ 96 | string dtb_addr; \ 97 | string initrd_max_size = "-1"; /* obsolete */ \ 98 | string initrd_addr; \ 99 | } linux_address_config; \ 100 | attribute { \ 101 | string linux_name = "linux"; \ 102 | string dtb_name = "linux-dtb"; \ 103 | string initrd_name = "linux-initrd"; \ 104 | string linux_bootcmdline = ""; \ 105 | string linux_stdout = ""; \ 106 | string dtb_base_name = ""; \ 107 | } linux_image_config; \ 108 | attribute { \ 109 | int send_id; \ 110 | int recv_id; \ 111 | } serial_layout[] = []; \ 112 | 113 | 114 | #define VM_COMPONENT_DEF(num) \ 115 | component VM vm##num; \ 116 | 117 | #define VM_COMPONENT_CONNECTIONS_DEF(num) \ 118 | connection seL4RPCDataport fs##num(from vm##num.fs, to fserv.fs_ctrl); \ 119 | connection seL4GlobalAsynch notify_ready_vm##num(from vm##num.notification_ready_connector, to vm##num.notification_ready); \ 120 | 121 | #define VM_GENERAL_COMPOSITION_DEF() \ 122 | component FileServer fserv; \ 123 | 124 | #define VM_COMPOSITION_DEF(num) \ 125 | VM_COMPONENT_DEF(num) \ 126 | VM_COMPONENT_CONNECTIONS_DEF(num) \ 127 | 128 | #define VM_GENERAL_CONFIGURATION_DEF() \ 129 | fserv.heap_size = 0x30000; \ 130 | 131 | #define VM_CONFIGURATION_DEF(num) \ 132 | vm##num.fs_shmem_size = 0x100000; \ 133 | vm##num.global_endpoint_base = 1 << 27; \ 134 | vm##num.asid_pool = true; \ 135 | vm##num.simple = true; \ 136 | vm##num.base_prio = 100; \ 137 | vm##num._priority = 101; \ 138 | vm##num.sem_value = 0; \ 139 | vm##num.heap_size = 0x300000; 140 | 141 | #define VM_DOMAIN_CONFIGURATION_DEF(num, domain) \ 142 | vm##num._domain = domain; \ 143 | vm##num.tcb_pool = 2; \ 144 | vm##num.tcb_pool_domains = [domain, domain]; 145 | 146 | #define VM_VIRTUAL_SERIAL_COMPONENTS_DEF() \ 147 | component SerialServer serial; \ 148 | component TimeServer time_server; \ 149 | connection seL4TimeServer serialserver_timer(from serial.timeout, to time_server.the_timer); \ 150 | 151 | #define PER_VM_VIRTUAL_SERIAL_CONNECTIONS_DEF(num) \ 152 | connection seL4SerialServer serial_vm##num(from vm##num.batch, to serial.processed_batch); \ 153 | connection seL4SerialServer serial_input_vm##num(from vm##num.serial_getchar, to serial.getchar); 154 | 155 | #define VM_VIRTUAL_SERIAL_COMPOSITION_DEF(vm_ids...) \ 156 | VM_VIRTUAL_SERIAL_COMPONENTS_DEF() \ 157 | __CALL(PER_VM_VIRTUAL_SERIAL_CONNECTIONS_DEF, vm_ids) \ 158 | 159 | #define VM_VIRTUAL_SERIAL_GENERAL_CONFIGURATION_DEF() \ 160 | time_server.timers_per_client = 1; \ 161 | time_server.priority = 255; \ 162 | time_server.simple = true; 163 | 164 | #define PER_VM_VIRTUAL_SERIAL_CONFIGURATION_DEF(num) \ 165 | vm##num.serial_getchar_shmem_size = 0x1000; \ 166 | vm##num.batch_shmem_size = 0x1000; \ 167 | 168 | #define VM_VIRTUAL_SERIAL_CONFIGURATION_DEF(vm_ids...) \ 169 | VM_VIRTUAL_SERIAL_GENERAL_CONFIGURATION_DEF() \ 170 | __CALL(PER_VM_VIRTUAL_SERIAL_CONFIGURATION_DEF, vm_ids) \ 171 | 172 | -------------------------------------------------------------------------------- /components/VM_Arm/docs/vm_memory_configuration.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | # VM Memory Configuration 7 | 8 | This document overviews how the seL4 VMM provides guests with the a block of memory. 9 | 10 | ## Basic Configuration 11 | 12 | In the platform specific `devices.camkes` file, there are macros that define the VM's RAM region: 13 | 14 | ``` 15 | #define VM_RAM_BASE 0x40000000 16 | #define VM_RAM_SIZE 0x20000000 17 | 18 | vm0.vm_address_config = { 19 | "ram_base" : VAR_STRINGIZE(VM_RAM_BASE), 20 | "ram_paddr_base" : VAR_STRINGIZE(VM_RAM_BASE), 21 | "ram_size" : VAR_STRINGIZE(VM_RAM_SIZE), 22 | }; 23 | 24 | vm0.simple_untyped24_pool = 33; 25 | 26 | ``` 27 | 28 | This configuration lets VM0 see 512MB at 0x40000000. When running as a hypervisor, seL4 uses stage 2 29 | mappings to map an Intermediate Physical Address (IPA) to a Physical Address (PA). This means that 30 | 0x40000000 is the IPA that the guest sees, and the associated PA could be any available page in the 31 | system. The pages backing the guest mappings are provided by the `simple_untyped24_pool`. In order 32 | to map 512MB, 32 untyped objects of size 24 are required. The additional object is provided for 33 | overhead operations. 34 | 35 | ### What does this mean? 36 | 37 | This default method is the most secure way of configuring the system. You can give two VMs the exact 38 | same `RAM_BASE` and `RAM_SIZE`, and the MMU will protect against the VMs accessing the others 39 | memory. 40 | 41 | The only case where this fails is when you want to give a VM a DMA-backed hardware device. In this 42 | specific case, you must provide the guest with the appropriate SMMU capabilities such that the SMMU 43 | will back the VM's DMA transactions. 44 | 45 | However, there are platforms that don't have a (supported) SMMU. What then? 46 | 47 | ## 1:1 Mapping Configuration 48 | 49 | DMA transactions will still work in the guest if the IPA->PA mappings are 1:1. In the previous 50 | example, a VM at 512MB at 0x40000000. In order for DMA to work, the VMM must use the page 51 | capabilities for the specified address range to back the guests mappings. For example: 52 | 53 | ``` 54 | #define VM_RAM_BASE 0x40000000 55 | #define VM_RAM_SIZE 0x20000000 56 | 57 | vm0.vm_address_config = { 58 | "ram_base" : VAR_STRINGIZE(VM_RAM_BASE), 59 | "ram_paddr_base" : VAR_STRINGIZE(VM_RAM_BASE), 60 | "ram_size" : VAR_STRINGIZE(VM_RAM_SIZE), 61 | }; 62 | 63 | 64 | vm0.vm_image_config = { 65 | "map_one_to_one" : true, 66 | }; 67 | 68 | vm0.untyped_mmios = [ 69 | "0x40000000:29", // Linux kernel memory regions 70 | ]; 71 | 72 | vm0.simple_untyped24_pool = 1; 73 | 74 | ``` 75 | 76 | In this example, the capability to the guest memory region is provided via the `untyped_mmios` 77 | configuration option. The VMM knows to map 1:1 by the 'vm_image_config.map_one_to_one flag'. Also, 78 | the `simple_untyped24_pool` was reduced to 1 because the VMM no longer needs the generic untyped 79 | objects to back the guest's mappings. 80 | 81 | ### How to get the Capability List 82 | 83 | Use the `CapDLLoaderPrintUntypeds` CMake option to have the capDL loader print out the untyped 84 | objects list. Then place the objects associated with the guest memory region into the 85 | `untyped_mmios` pool. 86 | -------------------------------------------------------------------------------- /components/VM_Arm/include/vmlinux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #define MACH_TYPE_SPECIAL ~0 16 | #define MACH_TYPE MACH_TYPE_SPECIAL 17 | 18 | #define FREE_IOPORT_START 0x1000 19 | 20 | extern char gen_dtb_buf[]; 21 | extern void *fdt_ori; 22 | 23 | irq_callback_fn_t get_custom_irq_handler(ps_irq_t irq) WEAK; 24 | 25 | /* Struct type that's passed into the IRQ callback functions for 26 | * this component */ 27 | struct irq_token { 28 | vm_t *vm; 29 | ps_irq_t irq; 30 | int virq; 31 | ps_irq_acknowledge_fn_t acknowledge_fn; 32 | void *ack_data; 33 | }; 34 | typedef struct irq_token *irq_token_t; 35 | 36 | typedef struct vmm_module { 37 | const char *name; 38 | void *cookie; 39 | // Function called for setup. 40 | void (*init_module)(vm_t *vm, void *cookie); 41 | } ALIGN(32) vmm_module_t; 42 | 43 | /** 44 | * Get the crossvm. This being an irq not passed through to the guest 45 | * such that it can be used for emulation purposes 46 | * @return -1 for error, otherwise a positive value (irq number) 47 | */ 48 | int get_crossvm_irq_num(void); 49 | 50 | struct camkes_crossvm_connection { 51 | dataport_caps_handle_t *handle; 52 | emit_fn emit_fn; 53 | seL4_Word consume_badge; 54 | const char *connection_name; 55 | }; 56 | 57 | typedef struct camkes_crossvm_connection camkes_crossvm_connection_t; 58 | 59 | /** 60 | * Initialise and register a series of camkes crossvm connections with a given vm 61 | * @param[in] vm A handle to the VM 62 | * @param[in] connection_base_addr The base guest physical address to interface the crossvm connection devices through 63 | * @param[in] connections An array of camkes crossvm connections 64 | * @param[in] num_connection The number of elements in the 'connections' array (parameter) 65 | * @return -1 for error, otherwise 0 for success 66 | */ 67 | int cross_vm_connections_init(vm_t *vm, uintptr_t connection_base_addr, struct camkes_crossvm_connection *connections, 68 | int num_connections); 69 | 70 | /* Declare a module. 71 | * For now, we put the modules in a separate elf section. */ 72 | #define DEFINE_MODULE(_name, _cookie, _init_module) \ 73 | __attribute__((used)) __attribute__((section("_vmm_module"))) vmm_module_t VMM_MODULE_ ##_name = { \ 74 | .name = #_name, \ 75 | .cookie = _cookie, \ 76 | .init_module = _init_module, \ 77 | }; 78 | 79 | #define CROSS_VM_CONNECTION(connection_name, connection_symbol) \ 80 | __attribute__((used)) __attribute__((section("_vmm_cross_connector_definition"))) \ 81 | camkes_crossvm_connection_t *connection_name##def = &connection_symbol; 82 | 83 | /** 84 | * Callback handler to be called when a certain badged event is received. 85 | * 86 | * @param vm A handle to the VM. 87 | * @param cookie cookie given to registration function 88 | * 89 | * @return Returns 0 on success. 90 | */ 91 | typedef int (*async_event_handler_fn_t)(vm_t *vm, void *cookie); 92 | /** 93 | * @brief Register an async_event_handler to be called when badged events are received. 94 | * 95 | * This method is intended to allow VMM modules to register async_event_handlers for handling 96 | * events generated by other camkes components. A module is expected to know what badge it 97 | * is registering a handler for as this is currently statically defined at build time. 98 | * 99 | * @param badge The badge that the event will have 100 | * @param callback A callback to call by the vm event loop. 101 | * @param cookie Custom cookie for the vm to pass through to the event handler. 102 | * 103 | * @return Returns 0 on successful registration. 104 | */ 105 | int register_async_event_handler(seL4_Word badge, async_event_handler_fn_t callback, void *cookie); 106 | -------------------------------------------------------------------------------- /components/VM_Arm/plat_include/exynos5410/plat/vmlinux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | #pragma once 7 | 8 | #define VUSB_ADDRESS 0x33330000 9 | #define VUSB_IRQ 198 10 | #define VUSB_NINDEX 5 11 | #define VUSB_NBADGE 0x123 12 | #define IRQ_SPI_OFFSET 32 13 | #define GIC_NODE_PATH "/soc/interrupt-controller@10481000" 14 | 15 | static const int linux_pt_irqs[] = { 16 | }; 17 | 18 | static const int free_plat_interrupts[] = { 92 + IRQ_SPI_OFFSET, 19 | 93 + IRQ_SPI_OFFSET, 20 | 101 + IRQ_SPI_OFFSET, 21 | 102 + IRQ_SPI_OFFSET 22 | }; 23 | 24 | void vusb_notify(void); 25 | 26 | static const char *plat_keep_devices[] = { 27 | "/soc/chipid@10000000", 28 | GIC_NODE_PATH, 29 | "/soc/interrupt-controller@10440000", 30 | "/soc/usb@12110000", 31 | "/soc/phy@12130000", 32 | "/soc/serial@12c00000", 33 | "/soc/serial@12c10000", 34 | "/soc/serial@12c20000", 35 | "/xxti", 36 | "/cpus/cpu@0", 37 | "/soc/clock-controller@10010000", 38 | "/soc/syscon@10050000", 39 | "/soc/memory-controller@12250000", 40 | }; 41 | static const char *plat_keep_device_and_disable[] = {}; 42 | static const char *plat_keep_device_and_subtree[] = { 43 | "/soc/mmc@12200000", 44 | "/soc/mmc@12220000", 45 | "/soc/system-controller@10040000", 46 | "/soc/sysram@2020000", 47 | 48 | }; 49 | static const char *plat_keep_device_and_subtree_and_disable[] = {}; 50 | -------------------------------------------------------------------------------- /components/VM_Arm/plat_include/exynos5422/plat/vmlinux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | #pragma once 7 | 8 | #define IRQ_SPI_OFFSET 32 9 | #define GIC_NODE_PATH "/soc/interrupt-controller@10481000" 10 | 11 | static const int linux_pt_irqs[] = { 12 | }; 13 | 14 | static const int free_plat_interrupts[] = { 92 + IRQ_SPI_OFFSET, 15 | 93 + IRQ_SPI_OFFSET, 16 | 101 + IRQ_SPI_OFFSET, 17 | 102 + IRQ_SPI_OFFSET 18 | }; 19 | static const char *plat_keep_devices[] = { 20 | "/fixed-rate-clocks/oscclk", 21 | "/timer", 22 | "/soc/chipid@10000000", 23 | GIC_NODE_PATH 24 | }; 25 | static const char *plat_keep_device_and_disable[] = {}; 26 | static const char *plat_keep_device_and_subtree[] = {}; 27 | static const char *plat_keep_device_and_subtree_and_disable[] = {}; 28 | -------------------------------------------------------------------------------- /components/VM_Arm/plat_include/odroidc2/plat/vmlinux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | #pragma once 7 | 8 | #define IRQ_SPI_OFFSET 32 9 | #define GIC_NODE_PATH "/soc/interrupt-controller@c4301000" 10 | 11 | static const int linux_pt_irqs[] = {}; 12 | 13 | static const int free_plat_interrupts[] = { 50 + IRQ_SPI_OFFSET }; 14 | static const char *plat_keep_devices[] = {}; 15 | static const char *plat_keep_device_and_disable[] = {}; 16 | static const char *plat_keep_device_and_subtree[] = { 17 | GIC_NODE_PATH, 18 | }; 19 | static const char *plat_keep_device_and_subtree_and_disable[] = {}; 20 | -------------------------------------------------------------------------------- /components/VM_Arm/plat_include/qemu-arm-virt/plat/vmlinux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | #pragma once 7 | 8 | #define IRQ_SPI_OFFSET 32 9 | #define GIC_NODE_PATH "/intc@8000000" 10 | 11 | static const int linux_pt_irqs[] = {}; 12 | 13 | static const int free_plat_interrupts[] = { 50 + IRQ_SPI_OFFSET }; 14 | static const char *plat_keep_devices[] = { 15 | "/timer", 16 | "/apb-pclk", 17 | "/platform@c000000", 18 | "/pmu", 19 | "/flash@0", 20 | "/psci", 21 | }; 22 | static const char *plat_keep_device_and_disable[] = {}; 23 | static const char *plat_keep_device_and_subtree[] = { 24 | GIC_NODE_PATH, 25 | }; 26 | static const char *plat_keep_device_and_subtree_and_disable[] = {}; 27 | -------------------------------------------------------------------------------- /components/VM_Arm/plat_include/ultra96v2/plat/smc.h: -------------------------------------------------------------------------------- 1 | ../../zynqmp/plat/smc.h -------------------------------------------------------------------------------- /components/VM_Arm/plat_include/ultra96v2/plat/vmlinux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023, Hensoldt Cyber 3 | * Copyright 2019, DornerWorks 4 | * 5 | * SPDX-License-Identifier: BSD-2-Clause 6 | */ 7 | 8 | #pragma once 9 | 10 | #define GIC_NODE_PATH "/amba_apu@0/interrupt-controller@f9010000" 11 | 12 | static const int linux_pt_irqs[] = {}; 13 | 14 | static const int free_plat_interrupts[] = { -1 }; 15 | 16 | static const char *plat_keep_devices[] = { 17 | "/timer", 18 | }; 19 | static const char *plat_keep_device_and_disable[] = {}; 20 | static const char *plat_keep_device_and_subtree[] = { 21 | GIC_NODE_PATH, 22 | }; 23 | static const char *plat_keep_device_and_subtree_and_disable[] = {}; 24 | static const char *plat_linux_bootcmdline = ""; 25 | static const char *plat_linux_stdout = ""; 26 | -------------------------------------------------------------------------------- /components/VM_Arm/plat_include/zynqmp/plat/smc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022, DornerWorks 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #define SMC_PM_GET_API_VERSION 0xC2000001 10 | #define SMC_PM_SET_CONFIGURATION 0xC2000002 11 | #define SMC_PM_GET_NODE_STATUS 0xC2000003 12 | #define SMC_PM_GET_OPERATING_CHARACTERISTIC 0xC2000004 13 | #define SMC_PM_REGISTER_NOTIFIER 0xC2000005 14 | #define SMC_PM_REQUEST_SUSPEND 0xC2000006 15 | #define SMC_PM_SELF_SUSPEND 0xC2000007 16 | #define SMC_PM_FORCE_POWERDOWN 0xC2000008 17 | #define SMC_PM_ABORT_SUSPEND 0xC2000009 18 | #define SMC_PM_REQUEST_WAKEUP 0xC200000A 19 | #define SMC_PM_SET_WAKEUP_SOURCE 0xC200000B 20 | #define SMC_PM_SYSTEM_SHUTDOWN 0xC200000C 21 | #define SMC_PM_REQUEST_NODE 0xC200000D 22 | #define SMC_PM_RELEASE_NODE 0xC200000E 23 | #define SMC_PM_SET_REQUIREMENT 0xC200000F 24 | #define SMC_PM_SET_MAX_LATENCY 0xC2000010 25 | #define SMC_PM_RESET_ASSERT 0xC2000011 26 | #define SMC_PM_RESET_GET_STATUS 0xC2000012 27 | #define SMC_PM_MMIO_WRITE 0xC2000013 28 | #define SMC_PM_MMIO_READ 0xC2000014 29 | #define SMC_PM_INIT_FINALIZE 0xC2000015 30 | #define SMC_PM_FPGA_LOAD 0xC2000016 31 | #define SMC_PM_FPGA_GET_STATUS 0xC2000017 32 | #define SMC_PM_GET_CHIPID 0xC2000018 33 | #define SMC_PM_SECURE_SHA 0xC200001A 34 | #define SMC_PM_SECURE_RSA 0xC200001B 35 | #define SMC_PM_PINCTRL_REQUEST 0xC200001C 36 | #define SMC_PM_PINCTRL_RELEASE 0xC200001D 37 | #define SMC_PM_PINCTRL_GET_FUNCTION 0xC200001E 38 | #define SMC_PM_PINCTRL_SET_FUNCTION 0xC200001F 39 | #define SMC_PM_PINCTRL_CONFIG_PARAM_GET 0xC2000020 40 | #define SMC_PM_PINCTRL_CONFIG_PARAM_SET 0xC2000021 41 | #define SMC_PM_IOCTL 0xC2000022 42 | #define SMC_PM_QUERY_DATA 0xC2000023 43 | #define SMC_PM_CLOCK_ENABLE 0xC2000024 44 | #define SMC_PM_CLOCK_DISABLE 0xC2000025 45 | #define SMC_PM_CLOCK_GETSTATE 0xC2000026 46 | #define SMC_PM_CLOCK_SETDIVIDER 0xC2000027 47 | #define SMC_PM_CLOCK_GETDIVIDER 0xC2000028 48 | #define SMC_PM_CLOCK_SETRATE 0xC2000029 49 | #define SMC_PM_CLOCK_GETRATE 0xC200002A 50 | #define SMC_PM_CLOCK_SETPARENT 0xC200002B 51 | #define SMC_PM_CLOCK_GETPARENT 0xC200002C 52 | #define SMC_PM_SECURE_IMAGE 0xC200002D 53 | #define SMC_PM_FPGA_READ 0xC200002E 54 | #define SMC_PM_SECURE_AES 0xC200002F 55 | #define SMC_PM_CLOCK_PLL_GETPARAM 0xC2000030 56 | #define SMC_PM_REGISTER_ACCESS 0xC2000034 57 | #define SMC_PM_EFUSE_ACCESS 0xC2000035 58 | #define SMC_PM_ADD_SUBSYSTEM 0xC2000036 59 | #define SMC_PM_FEATURE_CHECK 0xC200003F 60 | #define SMC_PM_API_MAX 0xC2000040 61 | 62 | #define SMC_IPI_MAILBOX_OPEN 0x82001000 63 | #define SMC_IPI_MAILBOX_RELEASE 0x82001001 64 | #define SMC_IPI_MAILBOX_STATUS_ENQUIRY 0x82001002 65 | #define SMC_IPI_MAILBOX_NOTIFY 0x82001003 66 | #define SMC_IPI_MAILBOX_ACK 0x82001004 67 | #define SMC_IPI_MAILBOX_ENABLE_IRQ 0x82001005 68 | #define SMC_IPI_MAILBOX_DISABLE_IRQ 0x82001006 69 | 70 | #define SMC_PM_GET_TRUSTZONE_VERSION 0xC2000A03 71 | -------------------------------------------------------------------------------- /components/VM_Arm/plat_include/zynqmp/plat/vmlinux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023, Hensoldt Cyber 3 | * Copyright 2019, DornerWorks 4 | * 5 | * SPDX-License-Identifier: BSD-2-Clause 6 | * 7 | * 8 | * The "zynqmp" platform target means the zcu102 board. 9 | * 10 | */ 11 | 12 | #pragma once 13 | 14 | #ifdef CONFIG_ZYNQMP_PETALINUX_2018_3 15 | #define GIC_NODE_PATH "/amba_apu@0/interrupt-controller@f9010000" 16 | #else 17 | #define GIC_NODE_PATH "/axi/interrupt-controller@f9010000" 18 | #endif 19 | 20 | static const int linux_pt_irqs[] = {}; 21 | 22 | static const int free_plat_interrupts[] = { -1 }; 23 | 24 | static const char *plat_keep_devices[] = { 25 | "/timer", 26 | }; 27 | static const char *plat_keep_device_and_disable[] = {}; 28 | static const char *plat_keep_device_and_subtree[] = { 29 | GIC_NODE_PATH, 30 | }; 31 | static const char *plat_keep_device_and_subtree_and_disable[] = {}; 32 | static const char *plat_linux_bootcmdline = ""; 33 | static const char *plat_linux_stdout = ""; 34 | -------------------------------------------------------------------------------- /components/VM_Arm/src/crossvm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | extern vmm_pci_space_t *pci; 17 | 18 | /* Force the _vmm_cross_connector_definition section to be created even if no modules are defined. */ 19 | static USED SECTION("_vmm_cross_connector_definition") struct {} dummy_module; 20 | extern camkes_crossvm_connection_t *__start__vmm_cross_connector_definition[]; 21 | extern camkes_crossvm_connection_t *__stop__vmm_cross_connector_definition[]; 22 | 23 | 24 | static int setup_connection(crossvm_handle_t *crossvm_connections, size_t index, 25 | camkes_crossvm_connection_t *connection) 26 | { 27 | crossvm_dataport_handle_t *dp_handle = calloc(1, sizeof(crossvm_dataport_handle_t)); 28 | if (!dp_handle) { 29 | ZF_LOGE("Failed to initialize cross vm connection dataport %zd", index); 30 | return -1; 31 | } 32 | 33 | dataport_caps_handle_t *handle = connection->handle; 34 | dp_handle->frame_size_bits = handle->get_frame_size_bits(); 35 | dp_handle->num_frames = handle->get_num_frame_caps(); 36 | dp_handle->frames = handle->get_frame_caps(); 37 | 38 | crossvm_connections[index].dataport = dp_handle; 39 | crossvm_connections[index].emit_fn = connection->emit_fn; 40 | crossvm_connections[index].consume_id = connection->consume_badge; 41 | crossvm_connections[index].connection_name = connection->connection_name; 42 | return 0; 43 | } 44 | 45 | int cross_vm_connections_init(vm_t *vm, uintptr_t connection_base_addr, camkes_crossvm_connection_t *connections, 46 | int num_connections) 47 | { 48 | 49 | int sectioned_connections = 0; 50 | // Connections can also be declared in linker sections. 51 | for (camkes_crossvm_connection_t **i = __start__vmm_cross_connector_definition; 52 | i < __stop__vmm_cross_connector_definition; i++) { 53 | if (*i != NULL) { 54 | sectioned_connections++; 55 | } 56 | } 57 | 58 | 59 | crossvm_handle_t *crossvm_connections = calloc(num_connections + sectioned_connections, sizeof(crossvm_handle_t)); 60 | if (!crossvm_connections) { 61 | return -1; 62 | } 63 | for (int i = 0; i < num_connections; i++) { 64 | if (setup_connection(crossvm_connections, i, &connections[i])) { 65 | return -1; 66 | } 67 | } 68 | int i = num_connections; 69 | for (camkes_crossvm_connection_t **connection = __start__vmm_cross_connector_definition; 70 | connection < __stop__vmm_cross_connector_definition; connection++, i++) { 71 | if (*connection != NULL) { 72 | if (setup_connection(crossvm_connections, i, *connection)) { 73 | return -1; 74 | } 75 | } 76 | } 77 | 78 | int ret = cross_vm_connections_init_common(vm, connection_base_addr, crossvm_connections, 79 | num_connections + sectioned_connections, 80 | pci, get_crossvm_irq_num); 81 | free(crossvm_connections); 82 | return ret; 83 | } 84 | -------------------------------------------------------------------------------- /components/VM_Arm/src/fdt_manipulation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | int fdt_generate_memory_node(void *fdt, uintptr_t base, size_t size) 11 | { 12 | int root_offset = fdt_path_offset(fdt, "/"); 13 | int address_cells = fdt_address_cells(fdt, root_offset); 14 | int size_cells = fdt_size_cells(fdt, root_offset); 15 | 16 | int this = fdt_add_subnode(fdt, root_offset, "memory"); 17 | if (this < 0) { 18 | return this; 19 | } 20 | int err = fdt_appendprop_string(fdt, this, "device_type", "memory"); 21 | if (err) { 22 | return err; 23 | } 24 | err = fdt_appendprop_uint(fdt, this, "reg", base, address_cells); 25 | if (err) { 26 | return err; 27 | } 28 | err = fdt_appendprop_uint(fdt, this, "reg", size, size_cells); 29 | if (err) { 30 | return err; 31 | } 32 | 33 | return 0; 34 | } 35 | 36 | int fdt_generate_chosen_node(void *fdt, const char *stdout_path, const char *bootargs, const unsigned int maxcpus) 37 | { 38 | int root_offset = fdt_path_offset(fdt, "/"); 39 | int this = fdt_add_subnode(fdt, root_offset, "chosen"); 40 | int err; 41 | 42 | if (stdout_path && strlen(stdout_path) > 0) { 43 | err = fdt_appendprop_string(fdt, this, "stdout-path", stdout_path); 44 | if (err) { 45 | return err; 46 | } 47 | err = fdt_appendprop_string(fdt, this, "linux,stdout-path", stdout_path); 48 | if (err) { 49 | return err; 50 | } 51 | } 52 | 53 | size_t bootargs_len = strlen(bootargs); 54 | /* +3*sizeof(int) is a cheap approximated formula for maximum number of characters in a UINT_MAX 55 | * +1 for null character, +9 for ' maxcpus=' 56 | */ 57 | size_t updated_bootargs_len = bootargs_len + 9 + (3 * sizeof(unsigned int) + 1); 58 | char *updated_bootargs = calloc(1, updated_bootargs_len); 59 | if (!updated_bootargs) { 60 | ZF_LOGE("Failed to generate chosen node: Unable to allocate updated bootargs"); 61 | return err; 62 | } 63 | int res = snprintf(updated_bootargs, updated_bootargs_len, "%s maxcpus=%u", bootargs, maxcpus); 64 | if (res < 0) { 65 | ZF_LOGE("Failed to generate chosen node: Unable to allocate updated bootargs"); 66 | free(updated_bootargs); 67 | return -1; 68 | } 69 | 70 | err = fdt_appendprop_string(fdt, this, "bootargs", updated_bootargs); 71 | if (err) { 72 | ZF_LOGE("Failed to generate chosen node: Unable to create updated bootargs"); 73 | free(updated_bootargs); 74 | return err; 75 | } 76 | free(updated_bootargs); 77 | 78 | return 0; 79 | } 80 | 81 | int fdt_append_chosen_node_with_initrd_info(void *fdt, uintptr_t base, size_t size) 82 | { 83 | int root_offset = fdt_path_offset(fdt, "/"); 84 | int address_cells = fdt_address_cells(fdt, root_offset); 85 | int this = fdt_path_offset(fdt, "/chosen"); 86 | int err = fdt_appendprop_uint(fdt, this, "linux,initrd-start", base, address_cells); 87 | if (err) { 88 | return err; 89 | } 90 | err = fdt_appendprop_uint(fdt, this, "linux,initrd-end", base + size, address_cells); 91 | if (err) { 92 | return err; 93 | } 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /components/VM_Arm/src/fdt_manipulation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | 10 | /** 11 | * generate a "memory" node 12 | * @param fdt 13 | * @param base, the base of the memory region 14 | * @param size, the size of the memory region 15 | * @return -1 on error, 0 otherwise 16 | */ 17 | int fdt_generate_memory_node(void *fdt, uintptr_t base, size_t size); 18 | 19 | /** 20 | * generate a "chosen" node 21 | * @param fdt 22 | * @param stdout_path, the path of the stdout 23 | * @param bootargs 24 | * @param maxcpus 25 | * @return -1 on error, 0 otherwise 26 | */ 27 | int fdt_generate_chosen_node(void *fdt, const char *stdout_path, const char *bootargs, const unsigned int maxcpus); 28 | 29 | /** 30 | * append the chosen node with initrd info 31 | * @param fdt 32 | * @param base, the base of the initrd image 33 | * @param size, the size of the initrd image 34 | * @return -1 on error, 0 otherwise 35 | */ 36 | int fdt_append_chosen_node_with_initrd_info(void *fdt, uintptr_t base, size_t size); 37 | -------------------------------------------------------------------------------- /components/VM_Arm/src/modules/init_ram.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | void WEAK init_ram_module(vm_t *vm, void *cookie) 16 | { 17 | int err = vm_ram_register_at(vm, 18 | vm_config.ram.base, 19 | vm_config.ram.size, 20 | vm->mem.map_one_to_one); 21 | assert(!err); 22 | } 23 | 24 | DEFINE_MODULE(init_ram, NULL, init_ram_module) 25 | -------------------------------------------------------------------------------- /components/VM_Arm/src/modules/map_frame_hack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | extern int start_extra_frame_caps; 14 | 15 | static vm_frame_t map_frame_hack_iterator(uintptr_t addr, void *cookie) 16 | { 17 | int error; 18 | vm_frame_t frame_result = { seL4_CapNull, seL4_NoRights, 0, 0 }; 19 | 20 | int cap_idx = (extra_frame_map_address - addr) / BIT(PAGE_BITS_4K); 21 | frame_result.cptr = start_extra_frame_caps + cap_idx; 22 | frame_result.rights = seL4_AllRights; 23 | frame_result.vaddr = addr; 24 | frame_result.size_bits = PAGE_BITS_4K; 25 | 26 | return frame_result; 27 | } 28 | 29 | static void map_frame_hack_init_module(vm_t *vm, void *cookie) 30 | { 31 | 32 | /* hack to give access to other components 33 | see https://github.com/smaccm/vm_hack/blob/master/details.md for details */ 34 | if (num_extra_frame_caps == 0) { 35 | return; 36 | } 37 | 38 | vm_memory_reservation_t *frame_hack_reservation = vm_reserve_memory_at(vm, extra_frame_map_address, 39 | num_extra_frame_caps * BIT(PAGE_BITS_4K), default_error_fault_callback, NULL); 40 | if (!frame_hack_reservation) { 41 | ZF_LOGE("Failed to reserve frame hack memory"); 42 | return; 43 | } 44 | int err = vm_map_reservation(vm, frame_hack_reservation, map_frame_hack_iterator, NULL); 45 | if (err) { 46 | ZF_LOGE("Failed to map frame hack memory"); 47 | } 48 | } 49 | 50 | DEFINE_MODULE(map_frame_hack, NULL, map_frame_hack_init_module) 51 | -------------------------------------------------------------------------------- /components/VM_Arm/src/modules/plat/tk1/device_fwd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | struct generic_forward_cfg camkes_uart_d = { 16 | .read_fn = uartfwd_read, 17 | .write_fn = uartfwd_write 18 | }; 19 | 20 | struct generic_forward_cfg camkes_clk_car = { 21 | .read_fn = clkcarfwd_read, 22 | .write_fn = clkcarfwd_write 23 | }; 24 | 25 | 26 | static void device_fwd_init_module(vm_t *vm, void *cookie) 27 | { 28 | 29 | /* Configure UART forward device */ 30 | int err = vm_install_generic_forward_device(vm, &dev_vconsole, camkes_uart_d); 31 | assert(!err); 32 | 33 | /* Configure Clock and Reset forward device */ 34 | err = vm_install_generic_forward_device(vm, &dev_clkcar, camkes_clk_car); 35 | assert(!err); 36 | } 37 | 38 | DEFINE_MODULE(device_fwd, NULL, device_fwd_init_module) 39 | -------------------------------------------------------------------------------- /components/VM_Arm/src/modules/plat/tk1/init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | static const struct device *linux_pt_devices[] = { 27 | &dev_usb1, 28 | &dev_usb3, 29 | &dev_sdmmc, 30 | }; 31 | 32 | static const struct device *linux_ram_devices[] = { 33 | #ifndef CONFIG_TK1_INSECURE 34 | &dev_rtc_kbc_pmc, 35 | &dev_exception_vectors, 36 | &dev_system_registers, 37 | &dev_ictlr, 38 | &dev_apb_misc, 39 | &dev_fuse, 40 | &dev_gpios, 41 | #endif /* CONFIG_TK1_INSECURE */ 42 | &dev_data_memory, 43 | }; 44 | 45 | extern reboot_hooks_list_t reboot_hooks_list; 46 | 47 | static void plat_init_module(vm_t *vm, void *cookie) 48 | { 49 | int err; 50 | int i; 51 | 52 | err = vm_install_tk1_usb_passthrough_device(vm, &reboot_hooks_list); 53 | assert(!err); 54 | 55 | /* Install pass through devices */ 56 | /* In insecure mode TK1 passes through all devices at the moment by using on-demand device mapping */ 57 | for (i = 0; i < sizeof(linux_pt_devices) / sizeof(*linux_pt_devices); i++) { 58 | err = vm_install_passthrough_device(vm, linux_pt_devices[i]); 59 | assert(!err); 60 | } 61 | 62 | /* Install ram backed devices */ 63 | /* Devices that are just anonymous memory mappings */ 64 | for (i = 0; i < sizeof(linux_ram_devices) / sizeof(*linux_ram_devices); i++) { 65 | err = vm_install_ram_only_device(vm, linux_ram_devices[i]); 66 | assert(!err); 67 | } 68 | } 69 | 70 | DEFINE_MODULE(plat, NULL, plat_init_module) 71 | -------------------------------------------------------------------------------- /components/VM_Arm/src/modules/virtio_con.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | /** 8 | * @brief virtio console backend layer for ARM 9 | * 10 | * The virtio console backend has two layers, the emul layer and the backend layer. 11 | * This file is part of the backend layer, it's responsible for: 12 | * 13 | * - TX: receiving data from the emul layer and forwarding them to the destination 14 | * port using camkes virtqueue (which is different from the virtqueue that's 15 | * used to communicate between the guest and the emul layer). 16 | * - RX: receiving data from the source port via camkes virtqueue and invoking the 17 | * emul layer to handle the data. 18 | * - virtio console backend initialization 19 | * 20 | * This file relies on the connection topology and camkes virtqueue connection 21 | * being configured correctly in camkes. 22 | * 23 | * @todo Handling the RX and TX is similar between the x86/ARM VMMs, hence this file 24 | * and `components/Init/src/virtio_con.c` share a lot of common code. A refactor for 25 | * the backend layer is needed. 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | #include 44 | 45 | #include 46 | #include 47 | 48 | /* Number of ports is the number of crossvm connections plus hvc0 */ 49 | #define NUM_PORTS (ARRAY_SIZE(serial_layout) + 1) 50 | 51 | static virtio_con_t *virtio_con = NULL; 52 | extern vmm_pci_space_t *pci; 53 | extern vmm_io_port_list_t *io_ports; 54 | 55 | /* 4088 because the serial_shmem_t struct has to be 0x1000 bytes big */ 56 | #define BUFSIZE (0x1000 - 2 * sizeof(uint32_t)) 57 | 58 | /** 59 | * This struct is a ring buffer that occupies exactly one page, it should represent 60 | * the data in the shmem region (that is shared between two nodes of a virtio console 61 | * connection. 62 | * 63 | * Example: 64 | * 65 | * |----------*************------------| 66 | * 0 head tail BUFSIZE 67 | * 68 | * (- available, * used) 69 | 70 | * Invariants of the ring buffer: 71 | * 1. 0 <= head < BUFSIZE, 0 <= tail < BUFSIZE 72 | * 2. used = (tail >= head) ? (tail - head) : (tail + BUFSIZE - head) 73 | * 3. empty = head - tail == 0 74 | * 4. full = (tail + 1) % BUFSIZE == head 75 | * 76 | * For this ring buffer, always add data to the tail and take from the head. The access 77 | * can be lock-free since an instance of this struct can only be either the receive buffer 78 | * or the sent buffer of a virtio console node, which guarantees that only one end of the 79 | * ring buffer struct can be modified in a node. 80 | */ 81 | typedef struct serial_shmem { 82 | uint32_t head; 83 | uint32_t tail; 84 | char buf[BUFSIZE]; 85 | } serial_shmem_t; 86 | compile_time_assert(serial_shmem_4k_size, sizeof(serial_shmem_t) == 0x1000); 87 | 88 | /* 89 | * Represents the virtqueues used in a given link between 90 | * two VMs. 91 | */ 92 | typedef struct serial_conn { 93 | void (*notify)(void); 94 | serial_shmem_t *recv_buf; 95 | serial_shmem_t *send_buf; 96 | } serial_conn_t; 97 | static serial_conn_t connections[NUM_PORTS]; 98 | 99 | /** 100 | * Writes data to the guest console attached to a port, and sets the head of the receive 101 | * ring buffer to the right place. 102 | * 103 | * @param port Port number 104 | */ 105 | static void virtio_con_notify_recv(int port) 106 | { 107 | serial_shmem_t *buffer = connections[port].recv_buf; 108 | uint32_t last_read_tail = buffer->tail; 109 | 110 | virtio_con->emul_driver->emul_cb.emul_putchar(port, virtio_con->emul, buffer->buf, buffer->head, last_read_tail); 111 | buffer->head = last_read_tail; 112 | } 113 | 114 | /** 115 | * Callback function for camkes virtqueue notification. Polls each receive ring buffer 116 | * to see if there are data pending. For some legacy reasons, this callback passes a 117 | * VMM handler and a cookie as parameters, they're unused here. 118 | * 119 | * @see include/vmlinux.h (async_event_handler_fn_t) for usages 120 | * 121 | * @return Returns 0 on success. 122 | */ 123 | static int handle_serial_console(vm_t *vmm, void *cookie UNUSED) 124 | { 125 | /* Poll each ring buffer to see if data was added */ 126 | for (int i = 0; i < NUM_PORTS; i++) { 127 | if (connections[i].recv_buf->head != connections[i].recv_buf->tail) { 128 | virtio_con_notify_recv(i); 129 | } 130 | } 131 | return 0; 132 | } 133 | 134 | /** 135 | * Forwards data to the destination port using camkes virtqueue, and notifies the dest VM. 136 | * 137 | * @param port Port number 138 | * @param c Data to forward 139 | */ 140 | static void tx_virtcon_forward(int port, char c) 141 | { 142 | if (port >= NUM_PORTS) { 143 | return; 144 | } 145 | 146 | serial_shmem_t *buffer = connections[port].send_buf; 147 | buffer->buf[buffer->tail] = c; 148 | __atomic_thread_fence(__ATOMIC_ACQ_REL); 149 | buffer->tail = (buffer->tail + 1) % BUFSIZE; 150 | 151 | /* If newline or staging area full, it's time to send */ 152 | if (c == '\n' || (buffer->tail + 1) % BUFSIZE == buffer->head) { 153 | __atomic_thread_fence(__ATOMIC_ACQ_REL); 154 | connections[port].notify(); 155 | } 156 | } 157 | 158 | /* camkes-generated symbols */ 159 | /* regions shared by the SerialServer and the VMM */ 160 | extern serial_shmem_t *batch_buf; 161 | extern serial_shmem_t *serial_getchar_buf; 162 | 163 | extern seL4_Word serial_getchar_notification_badge(void); 164 | 165 | /** 166 | * Initialize a virtio console backend. This includes: 167 | * - adding an IO port handler 168 | * - adding a PCI entry 169 | * - initializing the emul layer 170 | * - setting up connections (includes hvc0) 171 | * 172 | * @see include/vmlinux.h (vmm_module_t) for usages 173 | * 174 | * @param vm The vm handler of the caller 175 | * @param cookie Unused in this function 176 | */ 177 | void make_virtio_con(vm_t *vm, void *cookie UNUSED) 178 | { 179 | ZF_LOGF_IF((NUM_PORTS > VIRTIO_CON_MAX_PORTS), "Too many ports configured (up the constant)"); 180 | 181 | virtio_con = virtio_console_init(vm, tx_virtcon_forward, pci, io_ports); 182 | ZF_LOGF_IF(!virtio_con, "Failed to initialise virtio console"); 183 | 184 | int err; 185 | for (int i = 0; i < NUM_PORTS; i++) { 186 | if (i == 0) { 187 | /* Port 0 is the existing SerialServer shmem interface */ 188 | connections[0].notify = batch_batch; 189 | connections[0].recv_buf = serial_getchar_buf; 190 | connections[0].send_buf = batch_buf; 191 | err = register_async_event_handler(serial_getchar_notification_badge(), handle_serial_console, NULL); 192 | if (err) { 193 | ZF_LOGE("Failed to register event handler"); 194 | return; 195 | } 196 | continue; 197 | } 198 | 199 | camkes_virtqueue_channel_t *recv_channel = get_virtqueue_channel(VIRTQUEUE_DEVICE, serial_layout[i - 1].recv_id); 200 | camkes_virtqueue_channel_t *send_channel = get_virtqueue_channel(VIRTQUEUE_DRIVER, serial_layout[i - 1].send_id); 201 | 202 | if (!recv_channel || !send_channel) { 203 | ZF_LOGE("Failed to get channel"); 204 | return; 205 | } 206 | 207 | err = register_async_event_handler(recv_channel->recv_badge, handle_serial_console, NULL); 208 | if (err) { 209 | ZF_LOGE("Failed to register event handler"); 210 | return; 211 | } 212 | 213 | connections[i].notify = send_channel->notify; 214 | connections[i].recv_buf = (serial_shmem_t *) recv_channel->channel_buffer; 215 | connections[i].send_buf = (serial_shmem_t *) send_channel->channel_buffer; 216 | } 217 | } 218 | 219 | DEFINE_MODULE(virtio_con, NULL, make_virtio_con) 220 | -------------------------------------------------------------------------------- /components/VM_Arm/src/modules/virtio_net_arping.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #define IPV4_LENGTH 4 29 | #define ARP_REQUEST 0x01 30 | #define ARP_REPLY 0x02 31 | #define HW_TYPE 1 32 | 33 | extern vmm_pci_space_t *pci; 34 | extern vmm_io_port_list_t *io_ports; 35 | 36 | void self_mac(uint8_t *mac) 37 | { 38 | struct ether_addr res; 39 | struct ether_addr *resp; 40 | resp = ether_aton_r(vswitch_mac_address, &res); 41 | if (resp == NULL) { 42 | ZF_LOGF("Failed to get MAC address"); 43 | } 44 | memcpy(mac, res.ether_addr_octet, ETH_ALEN); 45 | } 46 | 47 | static int arping_reply(char *eth_buffer, size_t length, virtio_net_t *virtio_net) 48 | { 49 | int err; 50 | if (eth_buffer == NULL) { 51 | return -1; 52 | } 53 | struct ethhdr *rcv_req = (struct ethhdr *) eth_buffer; 54 | struct ether_arp *arp_req = (struct ether_arp *)(eth_buffer + sizeof(struct ethhdr)); 55 | if (ntohs(rcv_req->h_proto) == ETH_P_ARP) { 56 | unsigned char reply_buffer[1500]; 57 | struct ethhdr *send_reply = (struct ethhdr *) reply_buffer; 58 | struct ether_arp *arp_reply = (struct ether_arp *)(reply_buffer + sizeof(struct ethhdr)); 59 | 60 | memcpy(send_reply->h_dest, arp_req->arp_sha, ETH_ALEN); 61 | send_reply->h_proto = htons(ETH_P_ARP); 62 | 63 | // MAC Address 64 | memcpy(arp_reply->arp_tha, arp_req->arp_sha, ETH_ALEN); 65 | memcpy(arp_reply->arp_sha, arp_req->arp_sha, ETH_ALEN); 66 | arp_reply->arp_sha[5] = arp_reply->arp_sha[5] + 2; 67 | 68 | memcpy(send_reply->h_source, arp_reply->arp_sha, ETH_ALEN); 69 | // IP Addresss 70 | memcpy(arp_reply->arp_spa, (void *)arp_req->arp_tpa, IPV4_LENGTH); 71 | memcpy(arp_reply->arp_tpa, (void *)arp_req->arp_spa, IPV4_LENGTH); 72 | // Misc arp fields 73 | arp_reply->ea_hdr.ar_hrd = htons(HW_TYPE); 74 | arp_reply->ea_hdr.ar_pro = htons(ETH_P_IP); 75 | arp_reply->ea_hdr.ar_op = htons(ARP_REPLY); 76 | arp_reply->ea_hdr.ar_hln = ETH_ALEN; 77 | arp_reply->ea_hdr.ar_pln = IPV4_LENGTH; 78 | 79 | err = virtio_net_rx(reply_buffer, sizeof(struct ethhdr) + sizeof(struct ether_arp), virtio_net); 80 | if (err) { 81 | ZF_LOGE("Unable to perform virtio net rx"); 82 | return -1; 83 | } 84 | } 85 | return 0; 86 | } 87 | 88 | static virtio_net_t *virtio_net = NULL; 89 | 90 | void make_arping_virtio_net(vm_t *vm, void *cookie) 91 | { 92 | virtio_net_callbacks_t callbacks; 93 | callbacks.tx_callback = arping_reply; 94 | callbacks.irq_callback = NULL; 95 | callbacks.get_mac_addr_callback = self_mac; 96 | virtio_net = virtio_net_init(vm, &callbacks, pci, io_ports); 97 | } 98 | 99 | DEFINE_MODULE(virtio_net, NULL, make_arping_virtio_net) 100 | -------------------------------------------------------------------------------- /components/VM_Arm/src/modules/virtio_net_virtqueue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | static virtio_net_t *virtio_net = NULL; 23 | static vswitch_t virtio_vswitch; 24 | 25 | extern vmm_pci_space_t *pci; 26 | extern vmm_io_port_list_t *io_ports; 27 | 28 | void self_mac(uint8_t *mac) 29 | { 30 | struct ether_addr res; 31 | struct ether_addr *resp; 32 | resp = ether_aton_r(vswitch_mac_address, &res); 33 | if (resp == NULL) { 34 | ZF_LOGF("Failed to get MAC address"); 35 | } 36 | memcpy(mac, res.ether_addr_octet, ETH_ALEN); 37 | } 38 | 39 | static int tx_virtqueue_forward(char *eth_buffer, size_t length, virtio_net_t *virtio_net) 40 | { 41 | struct ether_addr *destaddr; 42 | int err, destnode_start_idx, destnode_n_idxs; 43 | 44 | /* The dest MAC addr is the first member of an ethernet frame. */ 45 | destaddr = (struct ether_addr *)eth_buffer; 46 | 47 | destnode_n_idxs = virtio_vswitch.n_connected; 48 | destnode_start_idx = 0; 49 | for (int i = destnode_start_idx; i < destnode_start_idx + destnode_n_idxs; i++) { 50 | vswitch_node_t *destnode; 51 | destnode = vswitch_get_destnode_by_index(&virtio_vswitch, i); 52 | if (destnode == NULL) { 53 | /* This could happen in the broadcast case if there are holes in 54 | * the array, though that would still be odd. 55 | */ 56 | continue; 57 | } 58 | 59 | if (camkes_virtqueue_driver_scatter_send_buffer(destnode->virtqueues.send_queue, (void *)eth_buffer, length) < 0) { 60 | ZF_LOGE("Unknown error while enqueuing available buffer for dest " 61 | PR_MAC802_ADDR ".", 62 | PR_MAC802_ADDR_ARGS(destaddr)); 63 | continue; 64 | } 65 | destnode->virtqueues.send_queue->notify(); 66 | } 67 | return 0; 68 | } 69 | 70 | static void virtio_net_notify_free_send(vswitch_node_t *node) 71 | { 72 | void *buf = NULL; 73 | unsigned int buf_size = 0; 74 | uint32_t wr_len = 0; 75 | vq_flags_t flag; 76 | virtqueue_ring_object_t handle; 77 | while (virtqueue_get_used_buf(node->virtqueues.send_queue, &handle, &wr_len)) { 78 | while (camkes_virtqueue_driver_gather_buffer(node->virtqueues.send_queue, &handle, &buf, &buf_size, &flag) >= 0) { 79 | /* Clean up and free the buffer we allocated */ 80 | camkes_virtqueue_buffer_free(node->virtqueues.send_queue, buf); 81 | } 82 | } 83 | } 84 | 85 | static int virtio_net_notify_recv(vswitch_node_t *node) 86 | { 87 | int err; 88 | struct ether_addr myaddr; 89 | void *buf = NULL; 90 | size_t buf_size = 0; 91 | vq_flags_t flag; 92 | virtqueue_ring_object_t handle; 93 | 94 | while (virtqueue_get_available_buf(node->virtqueues.recv_queue, &handle)) { 95 | char emul_buf[MAX_MTU] = {0}; 96 | size_t len = virtqueue_scattered_available_size(node->virtqueues.recv_queue, &handle); 97 | int enqueue_res = 0; 98 | if (camkes_virtqueue_device_gather_copy_buffer(node->virtqueues.recv_queue, &handle, (void *)emul_buf, len) < 0) { 99 | ZF_LOGW("Dropping frame for " PR_MAC802_ADDR ": Can't gather vq buffer.", 100 | PR_MAC802_ADDR_ARGS(&myaddr)); 101 | continue; 102 | } 103 | 104 | int err = virtio_net_rx(emul_buf, len, virtio_net); 105 | if (err) { 106 | ZF_LOGE("Unable to forward received buffer to the guest"); 107 | } 108 | node->virtqueues.recv_queue->notify(); 109 | } 110 | } 111 | 112 | static int virtio_net_notify(vm_t *vmm, void *cookie) 113 | { 114 | for (int i = 0; i < VSWITCH_NUM_NODES; i++) { 115 | if (virtio_vswitch.nodes[i].virtqueues.recv_queue && VQ_DEV_POLL(virtio_vswitch.nodes[i].virtqueues.recv_queue)) { 116 | virtio_net_notify_recv(&virtio_vswitch.nodes[i]); 117 | } 118 | if (virtio_vswitch.nodes[i].virtqueues.send_queue && VQ_DRV_POLL(virtio_vswitch.nodes[i].virtqueues.send_queue)) { 119 | virtio_net_notify_free_send(&virtio_vswitch.nodes[i]); 120 | } 121 | } 122 | return 0; 123 | } 124 | 125 | void make_virtqueue_virtio_net(vm_t *vm, void *cookie) 126 | { 127 | int err; 128 | virtio_net_callbacks_t callbacks; 129 | callbacks.tx_callback = tx_virtqueue_forward; 130 | callbacks.irq_callback = NULL; 131 | callbacks.get_mac_addr_callback = self_mac; 132 | virtio_net = virtio_net_init(vm, &callbacks, pci, io_ports); 133 | 134 | err = vswitch_init(&virtio_vswitch); 135 | if (err) { 136 | ZF_LOGF("Unable to initialise vswitch library"); 137 | } 138 | 139 | int num_vswitch_entries = ARRAY_SIZE(vswitch_layout); 140 | for (int i = 0; i < num_vswitch_entries; i++) { 141 | struct vswitch_mapping mac_mapping = vswitch_layout[i]; 142 | struct ether_addr guest_macaddr; 143 | struct ether_addr *res = ether_aton_r(mac_mapping.mac_addr, &guest_macaddr); 144 | virtqueue_driver_t *vq_send; 145 | virtqueue_device_t *vq_recv; 146 | seL4_CPtr recv_notif; 147 | seL4_CPtr recv_badge; 148 | vq_recv = malloc(sizeof(*vq_recv)); 149 | if (!vq_recv) { 150 | ZF_LOGF("Unable to initialise recv virtqueue for MAC address: %s", mac_mapping.mac_addr); 151 | } 152 | vq_send = malloc(sizeof(*vq_send)); 153 | if (!vq_send) { 154 | ZF_LOGF("Unable to initialise send virtqueue for MAC address: %s", mac_mapping.mac_addr); 155 | } 156 | 157 | /* Initialise recv virtqueue */ 158 | err = camkes_virtqueue_device_init_with_recv(vq_recv, mac_mapping.recv_id, &recv_notif, &recv_badge); 159 | ZF_LOGF_IF(err, "Unable to initialise recv virtqueue"); 160 | err = register_async_event_handler(recv_badge, virtio_net_notify, NULL); 161 | ZF_LOGF_IF(err, "Failed to register_async_event_handler for recv channel on MAC address: %s", mac_mapping.mac_addr); 162 | 163 | /* Initialise send virtqueue */ 164 | err = camkes_virtqueue_driver_init_with_recv(vq_send, mac_mapping.send_id, &recv_notif, &recv_badge); 165 | ZF_LOGF_IF(err, "Unable to initialise send virtqueue"); 166 | err = register_async_event_handler(recv_badge, virtio_net_notify, NULL); 167 | ZF_LOGF_IF(err, "Failed to register_async_event_handler for send channel on MAC address: %s", mac_mapping.mac_addr); 168 | 169 | err = vswitch_connect(&virtio_vswitch, &guest_macaddr, vq_send, vq_recv); 170 | if (err) { 171 | ZF_LOGF("Unable to initialise vswitch for MAC address: %s", mac_mapping.mac_addr); 172 | } 173 | } 174 | } 175 | 176 | DEFINE_MODULE(virtio_net, NULL, make_virtqueue_virtio_net) 177 | -------------------------------------------------------------------------------- /components/VM_Arm/src/modules/vuart_init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, DornerWorks 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | extern void *serial_getchar_buf; 13 | 14 | //this matches the size of the buffer in serial server 15 | #define BUFSIZE 4088 16 | 17 | static int handle_serial_console(vm_t *vmm, void *cookie UNUSED) 18 | { 19 | struct { 20 | uint32_t head; 21 | uint32_t tail; 22 | char buf[BUFSIZE]; 23 | } volatile *buffer = serial_getchar_buf; 24 | 25 | char c; 26 | while (buffer->head != buffer->tail) { 27 | c = buffer->buf[buffer->head]; 28 | buffer->head = (buffer->head + 1) % sizeof(buffer->buf); 29 | vuart_handle_irq(c); 30 | } 31 | } 32 | 33 | /* Install vuart */ 34 | static void vconsole_init_module(vm_t *vm, void *cookie) 35 | { 36 | int err = register_async_event_handler(serial_getchar_notification_badge(), handle_serial_console, NULL); 37 | ZF_LOGF_IF(err, "Failed to register_async_event_handler for make_virtio_con."); 38 | vm_install_vconsole(vm, guest_putchar_putchar); 39 | } 40 | 41 | DEFINE_MODULE(vconsole, NULL, vconsole_init_module) 42 | -------------------------------------------------------------------------------- /components/VM_Arm/vm_common.camkes: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | import ; 7 | import ; 8 | 9 | import ; 10 | import ; 11 | import ; 12 | import ; 13 | import "VM.camkes"; 14 | 15 | assembly { 16 | composition { 17 | component VM vm; 18 | component FileServer fserv; 19 | 20 | connection seL4RPCDataport fs(from vm.fs, to fserv.fs_ctrl); 21 | connection seL4GlobalAsynch vm_notify_read_conn(from vm.notification_ready_connector, to vm.notification_ready); 22 | } 23 | configuration { 24 | fserv.heap_size = 0x30000; 25 | vm.fs_shmem_size = 0x1000; 26 | 27 | vm.asid_pool = true; 28 | 29 | vm.simple = true; 30 | vm.cnode_size_bits = 23; 31 | vm.simple_untyped24_pool = 12; 32 | 33 | vm.base_prio = 100; 34 | 35 | vm._priority = 101; 36 | vm.sem_value = 0; 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /interfaces/Sataserver.idl4: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Dornerworks 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | procedure SataserverInterface { 7 | int tx(in unsigned int sector, in unsigned int len); 8 | int rx(in unsigned int sector, in unsigned int len); 9 | unsigned int get_capacity(void); 10 | unsigned int get_status(void); 11 | }; 12 | -------------------------------------------------------------------------------- /interfaces/UDPRecv.idl4: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | procedure UDPRecv { 8 | int poll(out unsigned int len, out uint16_t port, out uint32_t ip4addr); 9 | }; 10 | -------------------------------------------------------------------------------- /interfaces/UDPSend.idl4: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-only 5 | */ 6 | 7 | procedure UDPSend { 8 | int send(in uintptr_t data, in unsigned int len, in uint32_t ip4addr); 9 | }; 10 | -------------------------------------------------------------------------------- /interfaces/seL4VMDTBPassthrough.idl4: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | procedure VMDTBPassthrough {} 8 | -------------------------------------------------------------------------------- /interfaces/vm-connectors.camkes: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | /** 8 | * seL4VMDTBPassthrough 9 | */ 10 | connector seL4VMDTBPassthrough { 11 | from Procedure with 0 threads; 12 | to Procedure; 13 | 14 | attribute string isabelle_connector_spec = "\ 15 | connector_type = NativeConnector, 16 | connector_interface = RPCInterface, 17 | connector_access = \ 18 | access_from_to = {}, 19 | access_to_from = {}, 20 | access_from_from = {}, 21 | access_to_to = {}, 22 | access_from_conn = {}, 23 | access_to_conn = {} 24 | \ \"; 25 | } 26 | -------------------------------------------------------------------------------- /libs/libvirtio/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.8.2) 8 | 9 | project(libvirtio C) 10 | 11 | add_compile_options(-std=gnu99) 12 | 13 | set(sources src/virtio_net.c src/virtio_console.c) 14 | 15 | add_library(virtioarm STATIC EXCLUDE_FROM_ALL ${sources}) 16 | 17 | target_include_directories(virtioarm PUBLIC include plat_include/${KernelPlatform}) 18 | 19 | target_link_libraries(virtioarm muslc sel4 sel4camkes sel4vm sel4vmmplatsupport sel4_autoconf) 20 | -------------------------------------------------------------------------------- /libs/libvirtio/include/virtioarm/virtio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #define VIRTIO_IOPORT_SIZE 0x400 12 | #define VIRTIO_INTERRUPT_PIN 1 13 | -------------------------------------------------------------------------------- /libs/libvirtio/include/virtioarm/virtio_console.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | virtio_con_t *virtio_console_init(vm_t *vm, console_putchar_fn_t putchar, 12 | vmm_pci_space_t *pci, vmm_io_port_list_t *io_ports); 13 | 14 | void virtio_console_putchar(virtio_emul_t *con, char *buf, int len); 15 | -------------------------------------------------------------------------------- /libs/libvirtio/include/virtioarm/virtio_net.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | 9 | /* Maximum transmission unit for Ethernet interface */ 10 | #define ETHERNET_HEADER_SIZE 14 11 | #define MAX_MTU_DATA 1500 12 | #define MAX_MTU (MAX_MTU_DATA + ETHERNET_HEADER_SIZE) 13 | 14 | typedef struct virtio_net_callbacks { 15 | int (*tx_callback)(char *data, size_t length, virtio_net_t *virtio_net); 16 | void (*irq_callback)(int irq, virtio_net_t *virtio_net); 17 | void (*get_mac_addr_callback)(uint8_t *mac); 18 | } virtio_net_callbacks_t; 19 | 20 | int virtio_net_rx(char *data, size_t length, virtio_net_t *virtio_net); 21 | 22 | virtio_net_t *virtio_net_init(vm_t *vm, virtio_net_callbacks_t *callbacks, 23 | vmm_pci_space_t *pci, vmm_io_port_list_t *io_ports); 24 | -------------------------------------------------------------------------------- /libs/libvirtio/plat_include/exynos5/virtioarm/virtio_plat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | #pragma once 7 | 8 | #define IRQ_SPI_OFFSET 32 9 | #define VIRTIO_NET_PLAT_INTERRUPT_LINE (92 + IRQ_SPI_OFFSET) 10 | #define VIRTIO_CON_PLAT_INTERRUPT_LINE (92 + IRQ_SPI_OFFSET) 11 | -------------------------------------------------------------------------------- /libs/libvirtio/plat_include/qemu-arm-virt/virtioarm/virtio_plat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | #pragma once 7 | 8 | #define IRQ_SPI_OFFSET 32 9 | #define VIRTIO_NET_PLAT_INTERRUPT_LINE (50 + IRQ_SPI_OFFSET) 10 | #define VIRTIO_CON_PLAT_INTERRUPT_LINE (50 + IRQ_SPI_OFFSET) 11 | -------------------------------------------------------------------------------- /libs/libvirtio/plat_include/tx2/virtioarm/virtio_plat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | #pragma once 7 | 8 | #define IRQ_SPI_OFFSET 32 9 | #define VIRTIO_NET_PLAT_INTERRUPT_LINE (220 + IRQ_SPI_OFFSET) 10 | #define VIRTIO_CON_PLAT_INTERRUPT_LINE (220 + IRQ_SPI_OFFSET) 11 | -------------------------------------------------------------------------------- /libs/libvirtio/plat_include/zynqmp/virtioarm/virtio_plat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, DornerWorks 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #define IRQ_SPI_OFFSET 32 10 | 11 | /* 158 chosen because it doesn't correspond to a physical interrupt */ 12 | #define VIRTIO_NET_PLAT_INTERRUPT_LINE (158 + IRQ_SPI_OFFSET) 13 | #define VIRTIO_CON_PLAT_INTERRUPT_LINE (158 + IRQ_SPI_OFFSET) 14 | -------------------------------------------------------------------------------- /libs/libvirtio/src/virtio_console.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | typedef struct virtio_con_cookie { 24 | virtio_con_t *virtio_con; 25 | vm_t *vm; 26 | } virtio_con_cookie_t; 27 | 28 | static void virtio_console_ack(vm_vcpu_t *vcpu, int irq, void *token) {} 29 | 30 | static void console_handle_irq(void *cookie) 31 | { 32 | virtio_con_cookie_t *virtio_cookie = (virtio_con_cookie_t *)cookie; 33 | if (!virtio_cookie || !virtio_cookie->vm) { 34 | ZF_LOGE("NULL virtio cookie given to raw irq handler"); 35 | return; 36 | } 37 | int err = vm_inject_irq(virtio_cookie->vm->vcpus[BOOT_VCPU], VIRTIO_CON_PLAT_INTERRUPT_LINE); 38 | if (err) { 39 | ZF_LOGE("Failed to inject irq"); 40 | return; 41 | } 42 | } 43 | 44 | virtio_con_t *virtio_console_init(vm_t *vm, console_putchar_fn_t putchar, 45 | vmm_pci_space_t *pci, vmm_io_port_list_t *io_ports) 46 | { 47 | 48 | int err; 49 | struct virtio_console_passthrough backend; 50 | virtio_con_cookie_t *console_cookie; 51 | virtio_con_t *virtio_con; 52 | 53 | backend.handleIRQ = console_handle_irq; 54 | backend.backend_putchar = putchar; 55 | 56 | console_cookie = (virtio_con_cookie_t *)calloc(1, sizeof(struct virtio_con_cookie)); 57 | if (console_cookie == NULL) { 58 | ZF_LOGE("Failed to allocated virtio console cookie"); 59 | return NULL; 60 | } 61 | 62 | backend.console_data = (void *)console_cookie; 63 | ioport_range_t virtio_port_range = {0, 0, VIRTIO_IOPORT_SIZE}; 64 | virtio_con = common_make_virtio_con(vm, pci, io_ports, virtio_port_range, IOPORT_FREE, 65 | VIRTIO_INTERRUPT_PIN, VIRTIO_CON_PLAT_INTERRUPT_LINE, backend); 66 | console_cookie->virtio_con = virtio_con; 67 | console_cookie->vm = vm; 68 | err = vm_register_irq(vm->vcpus[BOOT_VCPU], VIRTIO_CON_PLAT_INTERRUPT_LINE, &virtio_console_ack, NULL); 69 | if (err) { 70 | ZF_LOGE("Failed to register console irq"); 71 | free(console_cookie); 72 | return NULL; 73 | } 74 | return virtio_con; 75 | } 76 | -------------------------------------------------------------------------------- /libs/libvirtio/src/virtio_net.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | typedef struct virtio_net_cookie { 31 | virtio_net_t *virtio_net; 32 | virtio_net_callbacks_t callbacks; 33 | vm_t *vm; 34 | } virtio_net_cookie_t; 35 | 36 | static void (*get_mac_addr_callback)(uint8_t *mac) = NULL; 37 | 38 | static void emul_raw_handle_irq(struct eth_driver *driver, int irq) 39 | { 40 | virtio_net_cookie_t *virtio_cookie = (virtio_net_cookie_t *)driver->eth_data; 41 | if (!virtio_cookie) { 42 | ZF_LOGE("NULL virtio cookie given to raw irq handler"); 43 | return; 44 | } 45 | int err = vm_inject_irq(virtio_cookie->vm->vcpus[BOOT_VCPU], VIRTIO_NET_PLAT_INTERRUPT_LINE); 46 | if (err) { 47 | ZF_LOGE("Failed to inject irq"); 48 | return; 49 | } 50 | if (virtio_cookie->callbacks.irq_callback) { 51 | virtio_cookie->callbacks.irq_callback(irq, virtio_cookie->virtio_net); 52 | } 53 | } 54 | 55 | static int emul_raw_tx(struct eth_driver *driver, unsigned int num, uintptr_t *phys, unsigned int *len, void *cookie) 56 | { 57 | bool complete = true; 58 | int err; 59 | virtio_net_cookie_t *virtio_cookie = (virtio_net_cookie_t *)driver->eth_data; 60 | if (!virtio_cookie) { 61 | ZF_LOGE("NULL virtio cookie given to raw tx"); 62 | return -1; 63 | } 64 | 65 | for (int i = 0; i < num; i++) { 66 | char ethbuffer[MAX_MTU]; 67 | if (len[i] > MAX_MTU) { 68 | ZF_LOGE("TX data exceeds MTU (%d) - truncating remaining data", MAX_MTU); 69 | complete = false; 70 | break; 71 | } 72 | memcpy((void *)ethbuffer, (void *)phys[i], len[i]); 73 | if (virtio_cookie->callbacks.tx_callback) { 74 | err = virtio_cookie->callbacks.tx_callback(ethbuffer, len[i], virtio_cookie->virtio_net); 75 | if (err) { 76 | ZF_LOGE("TX callback failed"); 77 | complete = false; 78 | break; 79 | } 80 | } 81 | } 82 | 83 | return complete ? ETHIF_TX_COMPLETE : ETHIF_TX_FAILED; 84 | } 85 | 86 | int virtio_net_rx(char *data, size_t length, virtio_net_t *virtio_net) 87 | { 88 | unsigned int len[1]; 89 | len[0] = length; 90 | void *cookie; 91 | void *emul_buf = (void *)virtio_net->emul_driver->i_cb.allocate_rx_buf(virtio_net->emul_driver->cb_cookie, len[0], 92 | &cookie); 93 | if (emul_buf) { 94 | memcpy(emul_buf, (void *)data, len[0]); 95 | virtio_net->emul_driver->i_cb.rx_complete(virtio_net->emul_driver->cb_cookie, 1, &cookie, len); 96 | } 97 | return 0; 98 | } 99 | 100 | static void emul_low_level_init(struct eth_driver *driver, uint8_t *mac, int *mtu) 101 | { 102 | get_mac_addr_callback(mac); 103 | *mtu = MAX_MTU_DATA; 104 | } 105 | 106 | static void virtio_net_ack(vm_vcpu_t *vcpu, int irq, void *token) {} 107 | 108 | virtio_net_t *virtio_net_init(vm_t *vm, virtio_net_callbacks_t *callbacks, 109 | vmm_pci_space_t *pci, vmm_io_port_list_t *io_ports) 110 | { 111 | virtio_net_cookie_t *driver_cookie; 112 | virtio_net_t *virtio_net; 113 | 114 | get_mac_addr_callback = callbacks->get_mac_addr_callback; 115 | 116 | struct raw_iface_funcs backend = virtio_net_default_backend(); 117 | backend.raw_tx = emul_raw_tx; 118 | backend.low_level_init = emul_low_level_init; 119 | backend.raw_handleIRQ = emul_raw_handle_irq; 120 | 121 | driver_cookie = (virtio_net_cookie_t *)calloc(1, sizeof(struct virtio_net_cookie)); 122 | if (driver_cookie == NULL) { 123 | ZF_LOGE("Failed to allocated virtio iface cookie"); 124 | return NULL; 125 | } 126 | 127 | ioport_range_t virtio_port_range = {0, 0, VIRTIO_IOPORT_SIZE}; 128 | virtio_net = common_make_virtio_net(vm, pci, io_ports, virtio_port_range, IOPORT_FREE, 129 | VIRTIO_INTERRUPT_PIN, VIRTIO_NET_PLAT_INTERRUPT_LINE, backend); 130 | if (virtio_net == NULL) { 131 | ZF_LOGE("Failed to initialise virtio net driver"); 132 | free(driver_cookie); 133 | return NULL; 134 | } 135 | driver_cookie->virtio_net = virtio_net; 136 | driver_cookie->vm = vm; 137 | int err = vm_register_irq(vm->vcpus[BOOT_VCPU], VIRTIO_NET_PLAT_INTERRUPT_LINE, &virtio_net_ack, NULL); 138 | if (callbacks) { 139 | driver_cookie->callbacks.tx_callback = callbacks->tx_callback; 140 | driver_cookie->callbacks.irq_callback = callbacks->irq_callback; 141 | } 142 | virtio_net->emul_driver->eth_data = (void *)driver_cookie; 143 | return virtio_net; 144 | } 145 | -------------------------------------------------------------------------------- /templates/seL4AllocatorMempool.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022, DornerWorks 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | 9 | /*- set mempool_size = macros.ROUND_UP(configuration[me.name].get('allocator_mempool_size', 80 * 1024 * 1024), macros.PAGE_SIZE) -*/ 10 | 11 | static char allocator_mempool[/*? mempool_size ?*/] ALIGN(PAGE_SIZE_4K) SECTION("align_12bit"); 12 | 13 | char *get_allocator_mempool(void) 14 | { 15 | return (char *)allocator_mempool; 16 | } 17 | 18 | size_t get_allocator_mempool_size(void) 19 | { 20 | return /*? mempool_size ?*/; 21 | } 22 | -------------------------------------------------------------------------------- /templates/seL4AllocatorMempool.template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022, DornerWorks 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | char *get_allocator_mempool(void); 8 | size_t get_allocator_mempool_size(void); 9 | -------------------------------------------------------------------------------- /templates/seL4SMMUV2.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | 9 | /*# ARM smmu v2 cap allocation #*/ 10 | /*- set sid_cap = alloc(name='sid', type=seL4_ARMSID) -*/ 11 | 12 | /*- set cb_cap = alloc(name='cb', type=seL4_ARMCB) -*/ 13 | 14 | seL4_CPtr camkes_get_smmu_sid_cap(){ 15 | return /*? sid_cap ?*/; 16 | } 17 | 18 | seL4_CPtr camkes_get_smmu_cb_cap(){ 19 | return /*? cb_cap ?*/; 20 | } -------------------------------------------------------------------------------- /templates/seL4Sataserver-from.template.c: -------------------------------------------------------------------------------- 1 | /*# 2 | *# Copyright 2019, DornerWorks 3 | *# 4 | *# SPDX-License-Identifier: BSD-2-Clause 5 | #*/ 6 | 7 | /*- include 'seL4RPCDataport-from.template.c' -*/ 8 | -------------------------------------------------------------------------------- /templates/seL4Sataserver-to.template.c: -------------------------------------------------------------------------------- 1 | /*# 2 | *# Copyright 2019, DornerWorks 3 | *# 4 | *# SPDX-License-Identifier: BSD-2-Clause 5 | #*/ 6 | 7 | /*- include 'seL4RPCDataport-to.template.c' -*/ 8 | 9 | /*# Look through the composition and find all '-to' connectors that would be 10 | *# duplicates of this one 11 | #*/ 12 | /*- set badges = [] -*/ 13 | /*- set partitions = [] -*/ 14 | /*- for c in me.parent.from_ends -*/ 15 | /*- set badge = configuration[c.instance.name].get('%s_attributes' % (c.interface.name)).strip('"') -*/ 16 | /*- set partition = configuration[c.instance.name].get('%s_partitions' % (c.interface.name)) -*/ 17 | /*- do badges.append(badge) -*/ 18 | /*- do partitions.append( (badge, partition) ) -*/ 19 | /*- endfor -*/ 20 | 21 | /*- do badges.sort() -*/ 22 | 23 | void /*? me.interface.name ?*/_get_partitions(unsigned int badge, uint8_t *partition_list, uint8_t *num_partitions) { 24 | /*- if partitions -*/ 25 | switch (badge) { 26 | /*- for badge,partition in partitions -*/ 27 | case /*? badge ?*/: { 28 | uint8_t temp[] = { 29 | /*- for num in partition -*/ 30 | /*? num ?*/, 31 | /*- endfor -*/ 32 | }; 33 | memcpy(partition_list, temp, sizeof(temp)); 34 | *num_partitions = sizeof(temp); 35 | break; 36 | } 37 | /*- endfor -*/ 38 | } 39 | /*- endif -*/ 40 | } 41 | -------------------------------------------------------------------------------- /templates/seL4UDPRecv-from.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | /*- set suffix = "_buf" -*/ 8 | /*- include 'seL4MultiSharedData-from.template.c' -*/ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /*- set ep = alloc('ep', seL4_EndpointObject, write=True, grantreply=True) -*/ 16 | 17 | /*- from 'rpc-connector.c' import allocate_badges with context -*/ 18 | 19 | /*- set client_ids = namespace() -*/ 20 | /*- do allocate_badges(client_ids) -*/ 21 | 22 | /*- set badges = client_ids.badges -*/ 23 | 24 | /*- set index = me.parent.from_ends.index(me) -*/ 25 | 26 | /*- set badge = badges[index] -*/ 27 | /*- do cap_space.cnode[ep].set_badge(badge) -*/ 28 | 29 | int /*? me.interface.name ?*/_poll(unsigned int *len, uint16_t *port, ip_addr_t *addr) { 30 | int status; 31 | seL4_MessageInfo_t UNUSED info; 32 | info = seL4_Call(/*? ep ?*/, seL4_MessageInfo_new(0, 0, 0, 0)); 33 | assert(seL4_MessageInfo_get_length(info) > 0); 34 | status = seL4_GetMR(0); 35 | if (status != -1) { 36 | *len = seL4_GetMR(1); 37 | *port = seL4_GetMR(2); 38 | *addr = (ip_addr_t){.addr = seL4_GetMR(3)}; 39 | assert(*len < 4096); 40 | } 41 | return status; 42 | } 43 | 44 | /*- include 'get-notification.template.c' -*/ 45 | -------------------------------------------------------------------------------- /templates/seL4UDPRecv-to.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | /*- include 'seL4MultiSharedData-to.template.c' -*/ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /*- from 'rpc-connector.c' import allocate_badges with context -*/ 16 | /*- from 'global-endpoint.template.c' import allocate_cap with context -*/ 17 | 18 | /*- set client_ids = namespace() -*/ 19 | /*- do allocate_badges(client_ids) -*/ 20 | 21 | /*- set badges = client_ids.badges -*/ 22 | 23 | /*- set ep = alloc('ep', seL4_EndpointObject, read=True, write=True) -*/ 24 | 25 | void lwip_lock(); 26 | void lwip_unlock(); 27 | 28 | /*- set bufs = configuration[me.instance.name].get('num_client_recv_bufs') -*/ 29 | /*- set clients = [] -*/ 30 | 31 | /*- for c in me.parent.from_ends -*/ 32 | 33 | /*- set port = configuration[c.instance.name].get('%s_port' % c.interface.name) -*/ 34 | /*- set client = badges[loop.index0] -*/ 35 | /*- do allocate_cap(c, is_reader=False) -*/ 36 | /*- set notification = pop('notification') -*/ 37 | 38 | /*- do clients.append( (client, port, notification) ) -*/ 39 | /*- endfor -*/ 40 | 41 | typedef struct udp_message { 42 | struct pbuf *pbuf; 43 | ip_addr_t addr; 44 | uint16_t port; 45 | struct udp_message *next; 46 | }udp_message_t; 47 | 48 | typedef struct udp_client { 49 | struct udp_pcb *upcb; 50 | int client_id; 51 | uint16_t port; 52 | int need_signal; 53 | seL4_CPtr notification; 54 | udp_message_t *free_head; 55 | udp_message_t *used_head; 56 | udp_message_t *used_tail; 57 | udp_message_t message_memory[ /*? bufs ?*/]; 58 | } udp_client_t; 59 | 60 | static udp_client_t udp_clients[/*? len(clients) ?*/] = { 61 | /*- for client,port,notification in clients -*/ 62 | {.upcb = NULL, .client_id = /*? client ?*/, .port = /*? port ?*/, .need_signal = 1, .notification = /*? notification ?*/, .used_head = NULL}, 63 | /*- endfor -*/ 64 | }; 65 | 66 | static void udprecv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { 67 | udp_client_t *client = (udp_client_t*)arg; 68 | if (!client->free_head) { 69 | pbuf_free(p); 70 | return; 71 | } 72 | udp_message_t *m = client->free_head; 73 | client->free_head = client->free_head->next; 74 | 75 | m->pbuf = p; 76 | m->addr = *addr; 77 | m->port = port; 78 | m->next = NULL; 79 | 80 | if (client->need_signal) { 81 | seL4_Signal(client->notification); 82 | client->need_signal = 0; 83 | } 84 | 85 | if (!client->used_head) { 86 | client->used_head = client->used_tail = m; 87 | } else { 88 | client->used_tail->next = m; 89 | client->used_tail = m; 90 | } 91 | } 92 | 93 | void /*? me.interface.name ?*/__run(void) { 94 | while (1) { 95 | /*- set cnode = alloc_cap('cnode', my_cnode, write=True) -*/ 96 | /*- set reply_cap_slot = alloc_cap('reply_cap_slot', None) -*/ 97 | int len; 98 | int result UNUSED; 99 | seL4_Word badge; 100 | seL4_Wait(/*? ep ?*/, &badge); 101 | udp_client_t *client = NULL; 102 | for (int i = 0; i < /*? len(clients) ?*/ && !client; i++) { 103 | if (udp_clients[i].client_id == badge) { 104 | client = &udp_clients[i]; 105 | } 106 | } 107 | assert(client); 108 | result = seL4_CNode_SaveCaller(/*? cnode ?*/, /*? reply_cap_slot ?*/, CONFIG_WORD_SIZE); 109 | assert(result == seL4_NoError); 110 | lwip_lock(); 111 | len = 0; 112 | if (!client->used_head) { 113 | seL4_SetMR(0, -1); 114 | len = 1; 115 | client->need_signal = 1; 116 | } else { 117 | unsigned int packet_len = 0; 118 | void *p = /*? me.interface.name ?*/_buf(badge); 119 | udp_message_t *m = client->used_head; 120 | client->used_head = client->used_head->next; 121 | if (!client->used_head) { 122 | client->need_signal = 1; 123 | } 124 | 125 | for (struct pbuf *q = m->pbuf; q; q = q->next) { 126 | memcpy(p + packet_len, q->payload, q->len); 127 | packet_len += q->len; 128 | } 129 | pbuf_free(m->pbuf); 130 | seL4_SetMR(0, client->used_head ? 0 : 1); 131 | seL4_SetMR(1, packet_len); 132 | seL4_SetMR(2, m->port); 133 | seL4_SetMR(3, m->addr.addr); 134 | len = 4; 135 | 136 | m->next = client->free_head; 137 | client->free_head = m; 138 | } 139 | seL4_Send(/*? reply_cap_slot ?*/, seL4_MessageInfo_new(0, 0, 0, len)); 140 | lwip_unlock(); 141 | } 142 | } 143 | 144 | void /*? me.interface.name ?*/__init(void) { 145 | int UNUSED err; 146 | int i, j; 147 | lwip_lock(); 148 | for (i = 0; i < /*? len(clients) ?*/; i++) { 149 | for (j = 0; j < /*? bufs ?*/; j++) { 150 | if (j == 0) { 151 | udp_clients[i].message_memory[j] = 152 | (udp_message_t){.pbuf = NULL, .port = 0, .next = NULL}; 153 | } else { 154 | udp_clients[i].message_memory[j] = 155 | (udp_message_t){.pbuf = NULL, .port = 0, .next = &udp_clients[i].message_memory[j - 1]}; 156 | } 157 | } 158 | udp_clients[i].free_head = &udp_clients[i].message_memory[/*? bufs ?*/ - 1]; 159 | udp_clients[i].upcb = udp_new(); 160 | assert(udp_clients[i].upcb); 161 | udp_recv(udp_clients[i].upcb, udprecv, &udp_clients[i]); 162 | err = udp_bind(udp_clients[i].upcb, NULL, udp_clients[i].port); 163 | assert(!err); 164 | } 165 | lwip_unlock(); 166 | } 167 | -------------------------------------------------------------------------------- /templates/seL4UDPSend-from.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | /*- set suffix = "_buf" -*/ 8 | /*- include 'seL4MultiSharedData-from.template.c' -*/ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | /*? macros.show_includes(me.instance.type.includes) ?*/ 15 | 16 | /*- set ep = alloc('ep', seL4_EndpointObject, write=True, grantreply=True) -*/ 17 | 18 | /*- from 'rpc-connector.c' import allocate_badges with context -*/ 19 | 20 | /*- set client_ids = namespace() -*/ 21 | /*- do allocate_badges(client_ids) -*/ 22 | 23 | /*- set badges = client_ids.badges -*/ 24 | 25 | /*- set index = me.parent.from_ends.index(me) -*/ 26 | 27 | /*- set badge = badges[index] -*/ 28 | /*- do cap_space.cnode[ep].set_badge(badge) -*/ 29 | 30 | int /*? me.interface.name ?*/_send(void *p, unsigned int len, ip_addr_t addr) { 31 | seL4_SetMR(0, len); 32 | seL4_SetMR(1, addr.addr); 33 | if (len > 4096) { 34 | len = 4096; 35 | } 36 | memcpy((void *)/*? me.interface.name?*/_buf, p, len); 37 | seL4_Call(/*? ep ?*/, seL4_MessageInfo_new(0, 0, 0, 2)); 38 | return len; 39 | } 40 | -------------------------------------------------------------------------------- /templates/seL4UDPSend-to.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | /*- include 'seL4MultiSharedData-to.template.c' -*/ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /*- from 'rpc-connector.c' import allocate_badges with context -*/ 16 | 17 | /*- set client_ids = namespace() -*/ 18 | /*- do allocate_badges(client_ids) -*/ 19 | 20 | /*- set badges = client_ids.badges -*/ 21 | 22 | /*- set ep = alloc('ep', seL4_EndpointObject, read=True, write=True) -*/ 23 | 24 | /*- set clients = [] -*/ 25 | 26 | /*- for c in me.parent.from_ends -*/ 27 | 28 | /*- set ports = configuration[c.instance.name].get('%s_ports' % c.interface.name) -*/ 29 | /*- set client = badges[loop.index0] -*/ 30 | /*- do clients.append( (client, ports['source'], ports['dest']) ) -*/ 31 | 32 | /*- endfor -*/ 33 | 34 | void lwip_lock(); 35 | void lwip_unlock(); 36 | 37 | static struct udp_pcb *upcb[/*? len(clients) ?*/]; 38 | 39 | void /*? me.interface.name ?*/__run(void) { 40 | while(1) { 41 | /*- set cnode = alloc_cap('cnode', my_cnode, write=True) -*/ 42 | /*- set reply_cap_slot = alloc_cap('reply_cap_slot', None) -*/ 43 | int result UNUSED; 44 | unsigned int len; 45 | ip_addr_t addr; 46 | struct pbuf *p; 47 | seL4_Word badge; 48 | seL4_Wait(/*? ep ?*/, &badge); 49 | result = seL4_CNode_SaveCaller(/*? cnode ?*/, /*? reply_cap_slot ?*/, CONFIG_WORD_SIZE); 50 | assert(result == seL4_NoError); 51 | 52 | len = seL4_GetMR(0); 53 | if (len < 4096) { 54 | addr.addr = seL4_GetMR(1); 55 | lwip_lock(); 56 | p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); 57 | if (p) { 58 | memcpy(p->payload, /*? me.interface.name?*/_buf(badge), len); 59 | switch (badge) { 60 | /*- for client, source, dest in clients -*/ 61 | case /*? client ?*/: 62 | udp_sendto(upcb[/*? loop.index0 ?*/], p, &addr, /*? dest ?*/); 63 | break; 64 | /*- endfor -*/ 65 | } 66 | pbuf_free(p); 67 | } 68 | lwip_unlock(); 69 | } 70 | seL4_Send(/*? reply_cap_slot ?*/, seL4_MessageInfo_new(0, 0, 0, 0)); 71 | } 72 | } 73 | 74 | void /*? me.interface.name ?*/__init(void) { 75 | lwip_lock(); 76 | /*- for client, source, dest in clients -*/ 77 | upcb[/*? loop.index0 ?*/] = udp_new(); 78 | assert(upcb[/*? loop.index0 ?*/]); 79 | /* we cheat here and set a local port without using the actual lwip bind function. 80 | * this is because we want to persuade lwip to send packets with this as the from 81 | * port, but we don't actually want to receive packets here */ 82 | upcb[/*? loop.index0 ?*/]->local_port = /*? source ?*/; 83 | /*- endfor -*/ 84 | lwip_unlock(); 85 | } 86 | -------------------------------------------------------------------------------- /templates/seL4VMDTBPassthrough-from.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | /* This template is intentionally empty. */ 8 | -------------------------------------------------------------------------------- /templates/seL4VMDTBPassthrough-to.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | /*- import 'dtb-query-common.template.c' as dtb_macros with context -*/ 21 | 22 | /*# Grab the DTB object made from the previous stages of the parsing #*/ 23 | /*- set configuration_name = '%s.%s' % (me.instance.name, me.interface.name) -*/ 24 | /*- set dtb_query = configuration[me.instance.name].get('dtb') -*/ 25 | /*- set dtb = dtb_query.get('query') -*/ 26 | 27 | /*- set untyped_dtb_mmio = [] -*/ 28 | /*- set dtb_irqs_map = {} -*/ 29 | /*- set dtb_irqs = [] -*/ 30 | /*- set dtb_node_paths = [] -*/ 31 | 32 | /*# Extract the relevant fields from the DTB (regs, interrupts, etc) #*/ 33 | /*- for i, node in enumerate(dtb) -*/ 34 | 35 | /*? dtb_macros.parse_dtb_node_reg(node) ?*/ 36 | /*- set reg_set = pop('reg_set') -*/ 37 | 38 | /*- for paddr, size in reg_set -*/ 39 | /*- set paddr = macros.ROUND_DOWN(paddr, 4096) -*/ 40 | /*- set size = macros.ROUND_UP(size, 4096) -*/ 41 | /*- for paddr_alloc, size_bits in macros.get_untypeds_from_range(paddr, size) -*/ 42 | /*- set cap = alloc('dtb_untyped_cap_0x%x' % paddr_alloc, seL4_UntypedObject, paddr = paddr_alloc, size_bits = size_bits) -*/ 43 | /*- do untyped_dtb_mmio.append( (paddr_alloc, size_bits, cap) ) -*/ 44 | /*- endfor -*/ 45 | /*- endfor -*/ 46 | 47 | /*? dtb_macros.parse_dtb_node_interrupts(node, -1, options.architecture) ?*/ 48 | /*- set irq_set = pop('irq_set') -*/ 49 | /*- for irq in irq_set -*/ 50 | /*- if irq['irq'] not in dtb_irqs_map -*/ 51 | /*- if irq['trigger'] -*/ 52 | /*- set irq_cap = alloc('%s_irq_%d' % (me.interface.name, irq['irq']), seL4_IRQHandler, number=irq['irq'], trigger=irq['trigger']) -*/ 53 | /*- else -*/ 54 | /*- set irq_cap = alloc('%s_irq_%d' % (me.interface.name, irq['irq']), seL4_IRQHandler, number=irq['irq']) -*/ 55 | /*- endif -*/ 56 | /*- do dtb_irqs.append( (irq['irq'], irq_cap) ) -*/ 57 | /*- do dtb_irqs_map.update({irq['irq']: irq_cap}) -*/ 58 | /*- endif -*/ 59 | /*- endfor -*/ 60 | 61 | /*- set dtb_path = node.get('this_node_path') -*/ 62 | /*- do dtb_node_paths.append(dtb_path) -*/ 63 | /*- endfor -*/ 64 | 65 | /*- for irq in configuration[me.instance.name].get('dtb_irqs', []) -*/ 66 | /*- if irq not in dtb_irqs_map -*/ 67 | /*- set irq_cap = alloc('%s_irq_%d' % (me.interface.name, irq), seL4_IRQHandler, number=irq) -*/ 68 | /*- do dtb_irqs.append( (irq, irq_cap) ) -*/ 69 | /*- do dtb_irqs_map.update({irq: irq_cap}) -*/ 70 | /*- endif -*/ 71 | /*- endfor -*/ 72 | 73 | /*- set self_cnode = alloc_cap('cnode', my_cnode, write=true) -*/ 74 | 75 | static int camkes_dtb_irqs[] = { 76 | /*- for (irq, cap) in dtb_irqs -*/ 77 | /*? irq ?*/, 78 | /*- endfor -*/ 79 | }; 80 | 81 | static char *camkes_dtb_node_paths[] = { 82 | /*- for path in dtb_node_paths -*/ 83 | /*- if path -*/ 84 | "/*? path ?*/", 85 | /*- endif -*/ 86 | /*- endfor -*/ 87 | }; 88 | 89 | /*- set plat_keep_devices = configuration[me.instance.name].get('plat_keep_devices') -*/ 90 | 91 | static char *camkes_dtb_keep_devices[] = { 92 | /*- if plat_keep_devices -*/ 93 | /*- for path in plat_keep_devices -*/ 94 | "/*? path ?*/", 95 | /*- endfor -*/ 96 | /*- endif -*/ 97 | }; 98 | 99 | /*- set plat_keep_devices_and_subtree = configuration[me.instance.name].get('plat_keep_devices_and_subtree') -*/ 100 | 101 | static char *camkes_dtb_keep_devices_and_subtree[] = { 102 | /*- if plat_keep_devices_and_subtree -*/ 103 | /*- for path in plat_keep_devices_and_subtree -*/ 104 | "/*? path ?*/", 105 | /*- endfor -*/ 106 | /*- endif -*/ 107 | }; 108 | 109 | char **camkes_dtb_get_node_paths(int *num_nodes) { 110 | *num_nodes = ARRAY_SIZE(camkes_dtb_node_paths); 111 | return camkes_dtb_node_paths; 112 | } 113 | 114 | char **camkes_dtb_get_plat_keep_devices(int *num_nodes) { 115 | *num_nodes = ARRAY_SIZE(camkes_dtb_keep_devices); 116 | return camkes_dtb_keep_devices; 117 | } 118 | 119 | char **camkes_dtb_get_plat_keep_devices_and_subtree(int *num_nodes) { 120 | *num_nodes = ARRAY_SIZE(camkes_dtb_keep_devices_and_subtree); 121 | return camkes_dtb_keep_devices_and_subtree; 122 | } 123 | 124 | int *camkes_dtb_get_irqs(int *num_irqs) { 125 | *num_irqs = ARRAY_SIZE(camkes_dtb_irqs); 126 | return camkes_dtb_irqs; 127 | } 128 | 129 | seL4_Error camkes_dtb_get_irq_cap(int irq, seL4_CNode cnode, seL4_Word index, uint8_t depth) { 130 | /*- if len(dtb_irqs) > 0 -*/ 131 | switch(irq) { 132 | /*- for irq,cap in dtb_irqs -*/ 133 | case /*? irq ?*/: 134 | return seL4_CNode_Copy(cnode, index, depth, /*? self_cnode ?*/, /*? cap ?*/, CONFIG_WORD_SIZE, seL4_AllRights); 135 | /*- endfor -*/ 136 | default: 137 | return seL4_FailedLookup; 138 | } 139 | /*- else -*/ 140 | return seL4_FailedLookup; 141 | /*- endif -*/ 142 | } 143 | 144 | int camkes_dtb_untyped_count(void) { 145 | return /*? len(untyped_dtb_mmio) ?*/; 146 | } 147 | 148 | seL4_CPtr camkes_dtb_get_nth_untyped(int n, size_t *size_bits, uintptr_t *paddr) { 149 | switch(n) { 150 | /*- for i in range(0, len(untyped_dtb_mmio)) -*/ 151 | /*- set (paddr,size_bits,cap) = untyped_dtb_mmio[i] -*/ 152 | case /*? i ?*/: 153 | *size_bits = (size_t)/*? size_bits ?*/; 154 | *paddr = /*? paddr ?*/; 155 | return /*? cap ?*/; 156 | /*- endfor -*/ 157 | default: 158 | assert(!"Invalid untyped cap requested"); 159 | } 160 | return 0; 161 | } 162 | -------------------------------------------------------------------------------- /templates/seL4VMParameters.template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023, DornerWorks 3 | * Copyright 2023, Hensoldt Cyber 4 | * 5 | * SPDX-License-Identifier: BSD-2-Clause 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | /*- set config = configuration[me.name] -*/ 12 | /*- if not config -*/ 13 | /*? raise(Exception('Missing VM configuration')) ?*/ 14 | /*- endif -*/ 15 | 16 | /*- set vm_address_config = config.get('vm_address_config') -*/ 17 | /*- set vm_image_config = config.get('vm_image_config') -*/ 18 | /*- set linux_address_config = config.get('linux_address_config') -*/ 19 | /*- set linux_image_config = config.get('linux_image_config') -*/ 20 | 21 | /*# For legacy compatibility, a fall back to the standard Linux entry exists. #*/ 22 | /*- set is_64_bit = (8 == macros.get_word_size(options.architecture)) -*/ 23 | /*- set entry_offset = 0x80000 if is_64_bit else 0x8000 -*/ 24 | 25 | const vm_config_t vm_config = { 26 | 27 | /*- if vm_address_config -*/ 28 | 29 | .ram = { 30 | .phys_base = /*? vm_address_config.get('ram_paddr_base') ?*/, 31 | .base = /*? vm_address_config.get('ram_base') ?*/, 32 | .size = /*? vm_address_config.get('ram_size') ?*/, 33 | }, 34 | 35 | .dtb_addr = /*? vm_address_config.get('dtb_addr') ?*/, 36 | .initrd_addr = /*? vm_address_config.get('initrd_addr') ?*/, 37 | 38 | /*- if vm_address_config.get('kernel_entry_addr') != '-1' -*/ 39 | .entry_addr = /*? vm_address_config.get('kernel_entry_addr') ?*/, 40 | /*- else -*/ 41 | #warning Using standard Linux entry point, please consider setting kernel_entry_addr explicitly. 42 | .entry_addr = /*? vm_address_config.get('ram_base') ?*/ + /*? '0x%x'%entry_offset ?*/, 43 | /*- endif -*/ 44 | 45 | /*- else -*/ 46 | 47 | #warning You are using the deprecated linux_address_config structure. Please use the vm_address_config structure instead 48 | 49 | .ram = { 50 | .phys_base = /*? linux_address_config.get('linux_ram_paddr_base') ?*/, 51 | .base = /*? linux_address_config.get('linux_ram_base') ?*/, 52 | .size = /*? linux_address_config.get('linux_ram_size') ?*/, 53 | }, 54 | 55 | .dtb_addr = /*? linux_address_config.get('dtb_addr') ?*/, 56 | .initrd_addr = /*? linux_address_config.get('initrd_addr') ?*/, 57 | /* Use standard Linux entry point. */ 58 | .entry_addr = /*? linux_address_config.get('linux_ram_base') ?*/ + /*? '0x%x'%entry_offset ?*/, 59 | 60 | /*- endif -*/ 61 | 62 | /*- if vm_image_config -*/ 63 | 64 | .provide_initrd = /*? vm_image_config.get('provide_initrd') ?*/, 65 | .generate_dtb = /*? vm_image_config.get('generate_dtb') ?*/, 66 | .provide_dtb = /*? vm_image_config.get('provide_dtb') ?*/, 67 | .map_one_to_one = /*? vm_image_config.get('map_one_to_one') ?*/, 68 | .clean_cache = /*? vm_image_config.get('clean_cache') ?*/, 69 | 70 | .files = { 71 | .kernel = "/*? vm_image_config.get('kernel_name') ?*/", 72 | .initrd = "/*? vm_image_config.get('initrd_name', "") ?*/", 73 | .dtb = "/*? vm_image_config.get('dtb_name', "") ?*/", 74 | .dtb_base = "/*? vm_image_config.get('dtb_base_name', "") ?*/", 75 | }, 76 | 77 | .kernel_bootcmdline = "/*? vm_image_config.get('kernel_bootcmdline', "") ?*/", 78 | .kernel_stdout = "/*? vm_image_config.get('kernel_stdout', "") ?*/", 79 | 80 | /*- else -*/ 81 | 82 | #warning "You are using the deprecated linux_image_config structure. The provide_initrd, generate_dtb, provide_dtb, \ 83 | map_one_to_one, and clean_cache flags are set to replicate previous behavior, which may cause your configuration to break. \ 84 | Please use the vm_image_config structure instead." 85 | 86 | #ifdef CONFIG_VM_INITRD_FILE 87 | #warning VmInitRdFile is a deprecated setting. Please remove and use vm_image_config.provide_initrd 88 | .provide_initrd = 1, 89 | #else 90 | .provide_initrd = 0, 91 | #endif 92 | 93 | #ifdef CONFIG_VM_DTB_FILE 94 | #warning VmDtbFile is a deprecated setting. Please remove and use vm_image_config.provide_dtb 95 | .provide_dtb = 1, 96 | .generate_dtb = 0, 97 | #else 98 | .provide_dtb = 0, 99 | .generate_dtb = 1, 100 | #endif 101 | 102 | #if defined(CONFIG_PLAT_EXYNOS5) || defined(CONFIG_PLAT_QEMU_ARM_VIRT) || defined(CONFIG_PLAT_TX2) 103 | .map_one_to_one = 1, 104 | #else 105 | .map_one_to_one = 0, 106 | #endif 107 | 108 | #if defined(CONFIG_PLAT_TX1) || defined(CONFIG_PLAT_TX2) 109 | .clean_cache = 1, 110 | #else 111 | .clean_cache = 0, 112 | #endif 113 | 114 | .files = { 115 | .kernel = "/*? linux_image_config.get('linux_name') ?*/", 116 | .initrd = "/*? linux_image_config.get('initrd_name') ?*/", 117 | .dtb = "/*? linux_image_config.get('dtb_name') ?*/", 118 | .dtb_base = "/*? linux_image_config.get('dtb_base_name') ?*/", 119 | }, 120 | 121 | .kernel_bootcmdline = "/*? linux_image_config.get('linux_bootcmdline') ?*/", 122 | .kernel_stdout = "/*? linux_image_config.get('linux_stdout') ?*/", 123 | 124 | /*- endif -*/ 125 | 126 | }; 127 | -------------------------------------------------------------------------------- /templates/seL4VMParameters.template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023, DornerWorks 3 | * Copyright 2023, Hensoldt Cyber 4 | * 5 | * SPDX-License-Identifier: BSD-2-Clause 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | typedef struct { 15 | 16 | struct { 17 | uintptr_t phys_base; 18 | uintptr_t base; 19 | size_t size; 20 | } ram; 21 | 22 | bool provide_initrd; 23 | bool generate_dtb; 24 | bool provide_dtb; 25 | bool map_one_to_one; 26 | bool clean_cache; 27 | 28 | uintptr_t dtb_addr; 29 | uintptr_t initrd_addr; 30 | uintptr_t entry_addr; 31 | 32 | struct { 33 | char const *kernel; 34 | char const *initrd; 35 | char const *dtb; 36 | char const *dtb_base; 37 | } files; 38 | 39 | char const *kernel_bootcmdline; 40 | char const *kernel_stdout; 41 | 42 | } vm_config_t; 43 | 44 | extern const vm_config_t vm_config; 45 | -------------------------------------------------------------------------------- /tools/elf/extract-vmlinux: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # SPDX-FileCopyrightText: (c) 2009,2010 Dick Streefland 3 | # SPDX-FileCopyrightText: (c) 2011 Corentin Chary 4 | 5 | # ---------------------------------------------------------------------- 6 | # extract-vmlinux - Extract uncompressed vmlinux from a kernel image 7 | # 8 | # Inspired from extract-ikconfig 9 | # (c) 2009,2010 Dick Streefland 10 | # 11 | # (c) 2011 Corentin Chary 12 | # 13 | # ---------------------------------------------------------------------- 14 | 15 | check_vmlinux() 16 | { 17 | # Use readelf to check if it's a valid ELF 18 | # TODO: find a better to way to check that it's really vmlinux 19 | # and not just an elf 20 | readelf -h $1 > /dev/null 2>&1 || return 1 21 | 22 | cat $1 23 | exit 0 24 | } 25 | 26 | try_decompress() 27 | { 28 | # The obscure use of the "tr" filter is to work around older versions of 29 | # "grep" that report the byte offset of the line instead of the pattern. 30 | 31 | # Try to find the header ($1) and decompress from here 32 | for pos in `tr "$1\n$2" "\n$2=" < "$img" | grep -abo "^$2"` 33 | do 34 | pos=${pos%%:*} 35 | tail -c+$pos "$img" | $3 > $tmp 2> /dev/null 36 | check_vmlinux $tmp 37 | done 38 | } 39 | 40 | # Check invocation: 41 | me=${0##*/} 42 | img=$1 43 | if [ $# -ne 1 -o ! -s "$img" ] 44 | then 45 | echo "Usage: $me " >&2 46 | exit 2 47 | fi 48 | 49 | # Prepare temp files: 50 | tmp=$(mktemp /tmp/vmlinux-XXX) 51 | trap "rm -f $tmp" 0 52 | 53 | # Initial attempt for uncompressed images or objects: 54 | check_vmlinux $img 55 | 56 | # That didn't work, so retry after decompression. 57 | try_decompress '\037\213\010' xy gunzip 58 | try_decompress '\3757zXZ\000' abcde unxz 59 | try_decompress 'BZh' xy bunzip2 60 | try_decompress '\135\0\0\0' xxx unlzma 61 | try_decompress '\211\114\132' xy 'lzop -d' 62 | 63 | # Bail out: 64 | echo "$me: Cannot find vmlinux." >&2 65 | -------------------------------------------------------------------------------- /tools/elf/relocs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seL4/camkes-vm/3dd34a480ba55e10a684d3c6e06e7bc158226ed7/tools/elf/relocs -------------------------------------------------------------------------------- /tools/elf/relocs.license: -------------------------------------------------------------------------------- 1 | SPDX-License-Identifier: GPL-2.0-only 2 | SPDX-FileCopyrightText: Linux --------------------------------------------------------------------------------