├── VERSION ├── .stylefilter ├── python-capdl-tool ├── tests │ ├── resources │ │ ├── stripped.bin │ │ ├── arm-hello.bin │ │ ├── ia32-hello.bin │ │ └── unstripped.bin │ ├── __init__.py │ ├── testmerge.py │ ├── testelf.py │ ├── runall.py │ └── allocator.py ├── .gitignore ├── requirements.txt ├── examples │ ├── to-capdl.py │ ├── construct-address-space.py │ ├── allocation.py │ └── capdl-manipulation.py ├── README.md └── capdl │ ├── __init__.py │ ├── Spec.py │ ├── Cap.py │ ├── PageCollection.py │ └── ELF.py ├── .gitignore ├── .linkcheck-ignore.yml ├── capDL-tool ├── doc │ ├── tex │ │ ├── imgs │ │ │ └── logos │ │ │ │ ├── seL4-Foundation-logo.pdf │ │ │ │ └── seL4-Foundation-logo.pdf.license │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── capDL.tex │ │ └── sel4.sty │ └── README.md ├── stack.yaml ├── .gitignore ├── camkes-adder-arm.object_sizes.yaml ├── cap-dist-elf-simpleserver.right ├── cap-dist-elf-simpleserver.cdl ├── capdl.dtd ├── tools │ └── capdl.vim ├── example.cdl ├── README.md ├── example-aarch64.right ├── example-arm.right ├── capDL-tool.cabal ├── example-ia32.right ├── Makefile ├── example-aarch64.cdl ├── example-arm.cdl ├── example-ia32.cdl ├── CapDL │ ├── Parser.hs │ ├── Matrix.hs │ ├── AST.hs │ ├── PrintModel.hs │ ├── DumpParser.hs │ ├── PrintXml.hs │ └── PrintDot.hs ├── capDL-tool.cmake ├── hello-dump.right └── Main.hs ├── CMakeLists.txt ├── capdl-loader-app ├── include │ └── capdl_spec.h ├── README.md ├── CMakeLists.txt └── helpers.cmake ├── .github └── workflows │ ├── pr.yml │ ├── push.yml │ ├── trigger.yml │ └── build.yml ├── LICENSES ├── LicenseRef-Trademark.txt └── BSD-2-Clause.txt ├── CODE_OF_CONDUCT.md ├── .licenseignore ├── object_sizes ├── README.md ├── CMakeLists.txt └── object_sizes.yaml ├── README.md ├── .reuse └── dep5 ├── cdl_utils ├── templates │ └── cspace.template.c ├── README.md ├── capdl_linker.py └── untyped_gen.py ├── Findcapdl.cmake └── CHANGES.md /VERSION: -------------------------------------------------------------------------------- 1 | 0.4.0-dev -------------------------------------------------------------------------------- /.stylefilter: -------------------------------------------------------------------------------- 1 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 2 | # 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | 5 | *.template.c -------------------------------------------------------------------------------- /python-capdl-tool/tests/resources/stripped.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seL4/capdl/HEAD/python-capdl-tool/tests/resources/stripped.bin -------------------------------------------------------------------------------- /python-capdl-tool/tests/resources/arm-hello.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seL4/capdl/HEAD/python-capdl-tool/tests/resources/arm-hello.bin -------------------------------------------------------------------------------- /python-capdl-tool/tests/resources/ia32-hello.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seL4/capdl/HEAD/python-capdl-tool/tests/resources/ia32-hello.bin -------------------------------------------------------------------------------- /python-capdl-tool/tests/resources/unstripped.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seL4/capdl/HEAD/python-capdl-tool/tests/resources/unstripped.bin -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 2 | # 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | 5 | capDL-tool/.stack-work 6 | -------------------------------------------------------------------------------- /python-capdl-tool/.gitignore: -------------------------------------------------------------------------------- 1 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 2 | # 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | 5 | *.pyc 6 | -------------------------------------------------------------------------------- /.linkcheck-ignore.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025, Proofcraft Pty Ltd 2 | # 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | 5 | urls: 6 | - ".*haskellstack.org.*" 7 | -------------------------------------------------------------------------------- /capDL-tool/doc/tex/imgs/logos/seL4-Foundation-logo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seL4/capdl/HEAD/capDL-tool/doc/tex/imgs/logos/seL4-Foundation-logo.pdf -------------------------------------------------------------------------------- /capDL-tool/doc/tex/imgs/logos/seL4-Foundation-logo.pdf.license: -------------------------------------------------------------------------------- 1 | Copyright seL4 Project a Series of LF Projects, LLC 2 | SPDX-License-Identifier: LicenseRef-Trademark 3 | -------------------------------------------------------------------------------- /capDL-tool/doc/tex/.gitignore: -------------------------------------------------------------------------------- 1 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 2 | # 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | 5 | *.aux 6 | *.log 7 | *.out 8 | capDL_generated.tex 9 | 10 | capDL.pdf -------------------------------------------------------------------------------- /capDL-tool/stack.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | # Stackage LTS Haskell 20.25 (ghc-9.2.8) 8 | resolver: lts-20.25 9 | 10 | local-bin-path: . 11 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.16.0) 8 | 9 | add_subdirectory(capdl-loader-app) 10 | add_subdirectory(object_sizes) 11 | -------------------------------------------------------------------------------- /python-capdl-tool/requirements.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 4 | # 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | aenum 8 | ordered-set 9 | pyelftools 10 | six 11 | sortedcontainers 12 | concurrencytest 13 | hypothesis 14 | future 15 | -------------------------------------------------------------------------------- /capDL-tool/.gitignore: -------------------------------------------------------------------------------- 1 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 2 | # 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | 5 | /*.parse 6 | /*.parse.x 7 | /*.dot 8 | /*.png 9 | /*.xml 10 | /*.thy 11 | /*-OK 12 | 13 | .cabal-sandbox 14 | cabal.sandbox.config 15 | dist 16 | parse-capDL 17 | stack.yaml.lock -------------------------------------------------------------------------------- /capdl-loader-app/include/capdl_spec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "capdl.h" 10 | 11 | /* This global is generated by the CapDL tools from the .cdl spec. */ 12 | extern CDL_Model capdl_spec; 13 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /LICENSES/LicenseRef-Trademark.txt: -------------------------------------------------------------------------------- 1 | The files in directory `imgs/logos/` are trademarks of their respective 2 | owners. 3 | 4 | For license and usage guidelines on the seL4 trademark and logo, including 5 | the seL4 Foundation logo, see https://sel4.systems/Foundation/Trademark/ 6 | 7 | No further license is granted from use in this repository. 8 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /capDL-tool/doc/tex/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | all: capDL.pdf 8 | 9 | GEN=capDL_generated.tex 10 | 11 | capDL.pdf: capDL.tex $(GEN) 12 | pdflatex capDL 13 | pdflatex capDL 14 | 15 | $(GEN): ../capDL.md 16 | pandoc $< -o $@ 17 | 18 | clean: 19 | rm -f *.log 20 | rm -f *.aux 21 | rm -f *.out 22 | rm -f $(GEN) 23 | 24 | realclean: clean 25 | rm -f capDL.pdf 26 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /capDL-tool/doc/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # capDL Language Specification 8 | 9 | This directory contains the capDL text language specification in 10 | [`capDL.md`](capDL.md). 11 | 12 | For building a PDF from this, run `make` in the directory 13 | [`tex/`](tex/). 14 | 15 | The build relies on the following packages: 16 | - `pandoc` `texlive-latex-extra` `texlive-fonts-extra` 17 | -------------------------------------------------------------------------------- /.licenseignore: -------------------------------------------------------------------------------- 1 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 2 | # 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | 5 | capDL-tool/.stack-work/* 6 | .git* 7 | VERSION 8 | CHANGES 9 | *LICENSE_*.txt 10 | .licenseignore 11 | .reuse/dep5 12 | *.pyc 13 | *.gitignore 14 | *.bin 15 | capDL-tool/parse-capDL 16 | capDL-tool/*.right 17 | capDL-tool/*.parse 18 | capDL-tool/*.xml 19 | capDL-tool/*.test-OK 20 | capDL-tool/doc/tex/imgs/* 21 | capDL-tool/camkes-adder-arm.* 22 | python-capdl-tool/.hypothesis 23 | object_sizes/object_sizes.yaml 24 | -------------------------------------------------------------------------------- /python-capdl-tool/examples/to-capdl.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | from __future__ import absolute_import, division, print_function, \ 8 | unicode_literals 9 | 10 | # Add the root directory of this repository to your PYTHONPATH environment 11 | # variable to enable the following import. 12 | import capdl 13 | 14 | # Load an ELF file. 15 | elf = capdl.ELF('../tests/arm-elf/hello.bin') 16 | 17 | # Generate CapDL. 18 | print(elf.get_spec()) 19 | -------------------------------------------------------------------------------- /python-capdl-tool/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Python CapDL module 8 | 9 | A Python module for providing CapDL support. 10 | 11 | Note: to use the ELF file functionality you will need pyelftools installed. If 12 | you don't have this and don't need this functionality just don't import 13 | anything that imports ELF.py. 14 | 15 | * capdl/ — The source code of the module 16 | * examples/ — Some examples of how to use this module 17 | * tests/ — Some basic tests of the functionality 18 | -------------------------------------------------------------------------------- /object_sizes/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Object Sizes 8 | 9 | This directory provides a cmake target runs which runs the preprocessor over a 10 | yaml file to extract the preprocessed values from of specific object size 11 | constants from libsel4 to be passed to other tools which require knowledge of 12 | object sizes. This allows sizes to be evaluated with respect to the kernel 13 | configuration. 14 | 15 | The location of the preprocessed file in the build directory is then set in the 16 | FILE_PATH property of the object_sizes target. 17 | 18 | -------------------------------------------------------------------------------- /capDL-tool/camkes-adder-arm.object_sizes.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 2 | # 3 | # SPDX-License-Identifier: BSD-2-Clause 4 | 5 | seL4_TCBObject: 10 6 | seL4_EndpointObject: 4 7 | seL4_NotificationObject: 4 8 | seL4_SmallPageObject: 12 9 | seL4_LargePageObject: 16 10 | seL4_ASID_Pool: 12 11 | seL4_ASID_Table: 10 12 | seL4_Slot: 4 13 | seL4_Value_MinUntypedBits: 4 14 | seL4_Value_MaxUntypedBits: 29 15 | seL4_PageTableObject: 10 16 | seL4_PageDirectoryObject: 14 17 | seL4_ARM_SectionObject: 20 18 | seL4_ARM_SuperSectionObject: 24 19 | seL4_IOPageTableObject: 12 20 | seL4_IOPorts: 0 21 | seL4_IODevice: 0 22 | seL4_ARMIODevice: 0 23 | seL4_IRQ: 0 24 | seL4_IOAPICIRQ: 0 25 | seL4_MSIIRQ: 0 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Capability Distribution Language 8 | 9 | Collection of tools for generating, parsing and loading capdl specifications of systems: 10 | 11 | * capDL-tool - A tool to assist working with capDL textual specifications 12 | * python-capdl-tool - A Python module for providing CapDL support 13 | * capdl-loader-app - The capDL initialiser for seL4 14 | 15 | ## Reporting security vulnerabilities 16 | 17 | If you believe you have found a security vulnerability in this code, we ask you 18 | to follow the seL4 [vulnerability disclosure policy][VDP]. 19 | 20 | [VDP]: https://github.com/seL4/seL4/blob/master/SECURITY.md 21 | -------------------------------------------------------------------------------- /python-capdl-tool/examples/construct-address-space.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | from __future__ import absolute_import, division, print_function, \ 8 | unicode_literals 9 | 10 | # Add the root directory of this repository to your PYTHONPATH environment 11 | # variable to enable the following import. 12 | import capdl 13 | 14 | # Create an address space with two regions, one R and one RW. 15 | pc = capdl.create_address_space([ 16 | {'start': 0x00010000, 'end': 0x00015000, 'read': True}, 17 | {'start': 0x00017000, 'end': 0x00020000, 'read': True, 'write': True}, 18 | ]) 19 | 20 | # Print a CapDL spec for all the virtual address space objects. 21 | print(pc.get_spec()) 22 | -------------------------------------------------------------------------------- /object_sizes/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.16.0) 8 | 9 | project(object_sizes C) 10 | 11 | set(objsz_file object_sizes.yaml) 12 | add_custom_command( 13 | OUTPUT ${objsz_file} 14 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${objsz_file} 15 | COMMAND ${CMAKE_C_COMPILER} -E -P "-I$,;-I>" - 16 | > ${objsz_file} < ${CMAKE_CURRENT_SOURCE_DIR}/${objsz_file} 17 | COMMAND_EXPAND_LISTS 18 | DEPENDS sel4 19 | ) 20 | 21 | add_custom_target(object_sizes DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${objsz_file} sel4) 22 | set_property(TARGET object_sizes PROPERTY FILE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${objsz_file}") 23 | -------------------------------------------------------------------------------- /.reuse/dep5: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: capDL 3 | Upstream-Contact: 4 | Source: https://github.com/seL4/capDL/ 5 | 6 | Files: 7 | VERSION 8 | capDL-tool/camkes-adder-arm.right 9 | capDL-tool/camkes-adder-arm.thy.right 10 | capDL-tool/cap-dist-elf-simpleserver.right 11 | capDL-tool/example-arm.right 12 | capDL-tool/example-aarch64.right 13 | capDL-tool/example-ia32.right 14 | capDL-tool/hello-dump.right 15 | python-capdl-tool/tests/resources/arm-hello.bin 16 | python-capdl-tool/tests/resources/ia32-hello.bin 17 | python-capdl-tool/tests/resources/stripped.bin 18 | python-capdl-tool/tests/resources/unstripped.bin 19 | object_sizes/object_sizes.yaml 20 | Copyright: 2020, Data61, CSIRO (ABN 41 687 119 230) 21 | License: BSD-2-Clause 22 | -------------------------------------------------------------------------------- /capDL-tool/cap-dist-elf-simpleserver.right: -------------------------------------------------------------------------------- 1 | arch ia32 2 | 3 | objects { 4 | 5 | ap = asid_pool (asid_high: 0x1) 6 | cnode = cnode (4 bits) 7 | cnode2 = cnode (4 bits) 8 | ep = notification 9 | frame[6] = frame (4k) 10 | pd1 = pd 11 | pt1 = pt 12 | tcb = tcb (addr: 86016, ip: 65536, sp: 77824, prio: 42, max_prio: 254, affinity: 0, fault_ep: 1, dom: 0, init: [10, 15]) 13 | 14 | 15 | } caps { 16 | 17 | ap {0: pd1} 18 | 19 | cnode { 20 | 0: tcb 21 | 1: ep (RWG) 22 | 2: cnode (guard_size: 28) 23 | 3: frame[5] (RWX) 24 | } 25 | 26 | cnode2 {5: cnode (guard: 1, guard_size: 28)} 27 | 28 | pd1 {0: pt1} 29 | 30 | pt1 {16: frame[0..5] (RWX)} 31 | 32 | tcb { 33 | 0: cnode2 (guard_size: 28) 34 | 1: pd1 35 | 4: frame[5] (RWX) 36 | } 37 | 38 | } cdt { 39 | 40 | } irq maps { 41 | 42 | } -------------------------------------------------------------------------------- /cdl_utils/templates/cspace.template.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 | {% raw %} 11 | #define DECLARE_IPCBUFFER_SYMBOL(symbol) \ 12 | extern char symbol[]; \ 13 | void CONSTRUCTOR(199) setIPCBuffer(void) { \ 14 | __sel4_ipc_buffer = (seL4_IPCBuffer *) symbol;\ 15 | } 16 | {% endraw %} 17 | 18 | DECLARE_IPCBUFFER_SYMBOL({{ipc_buffer_symbol}}) 19 | 20 | #define SIZED_SYMBOL(symbol, size, section) \ 21 | char symbol[size] VISIBLE ALIGN(4096) SECTION(section); 22 | 23 | {% for (symbol, slot) in slots -%} 24 | seL4_CPtr {{symbol}} = {{slot}}; 25 | {% endfor %} 26 | 27 | {% for (symbol, size, section) in symbols -%} 28 | SIZED_SYMBOL({{symbol}}, {{size}}, "{{section}}") 29 | {% endfor %} 30 | 31 | 32 | char progname[] = "{{progname}}"; 33 | -------------------------------------------------------------------------------- /capDL-tool/doc/tex/capDL.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | % 4 | % SPDX-License-Identifier: BSD-2-Clause 5 | % 6 | 7 | \documentclass[english,a4paper,11pt]{article} 8 | \usepackage{sel4} 9 | 10 | \usepackage{url,verbatim,datetime,microtype} 11 | 12 | \usepackage[pdftex,pagebackref,hyperindex,bookmarks]{hyperref} 13 | % default no frames around links, dark versions so it prints Ok. 14 | \hypersetup{colorlinks, 15 | allcolors=neutral, 16 | anchorcolor=black, 17 | citecolor=greenDark, 18 | linkcolor=greenDark, 19 | pdftitle={capDL Language Specification}, 20 | pdfauthor={Gerwin Klein}} 21 | 22 | 23 | \begin{document} 24 | 25 | \title{capDL Language Specification} 26 | \subtitle{Revision 1.0} 27 | \author{Gerwin Klein} 28 | \date{} 29 | 30 | \maketitle 31 | 32 | \input{capDL_generated} 33 | 34 | \end{document} 35 | -------------------------------------------------------------------------------- /capDL-tool/cap-dist-elf-simpleserver.cdl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | arch ia32 8 | 9 | objects { 10 | 11 | cnode = cnode (4 bits) 12 | tcb = tcb (addr: 0x15000, ip: 0x00010000, sp: 0x00013000, prio: 42, max_prio: 254, affinity: 0, init:[10,15], fault_ep: 1) 13 | pd1 = pd 14 | ap = asid_pool (asid_high: 0x1) 15 | pt1 = pt 16 | frame[6] = frame (4k) 17 | ep = notification 18 | cnode2 = cnode (4 bits) 19 | } 20 | 21 | caps { 22 | 23 | cnode { 24 | tcb 25 | ep (RWG) 26 | cnode (guard: 0, guard_size: 28) 27 | frame[5] (RWG) 28 | } 29 | 30 | ap { pd1 } 31 | 32 | pd1 { 0: pt1 } 33 | 34 | pt1 { 35 | 0x10: frame[] (RWG) 36 | } 37 | 38 | cnode2 { 5: cnode (guard: 1, guard_size: 28) } 39 | 40 | tcb { 41 | cspace: cnode2 (guard: 0, guard_size: 28) 42 | vspace: pd1 43 | ipc_buffer_slot: frame[5] (RWG) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /python-capdl-tool/tests/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 4 | # 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | from __future__ import absolute_import, division, print_function, \ 9 | unicode_literals 10 | 11 | import unittest 12 | 13 | from capdl import register_object_sizes 14 | 15 | test_object_sizes = { 16 | 'seL4_TCBObject': 9, 17 | 'seL4_EndpointObject': 4, 18 | 'seL4_NotificationObject': 4, 19 | 'seL4_SmallPageObject': 12, 20 | 'seL4_LargePageObject': 16, 21 | 'seL4_ASID_Pool': 12, 22 | 'seL4_Slot': 4, 23 | 'seL4_PageTableObject': 10, 24 | 'seL4_PageDirectoryObject': 14, 25 | 'seL4_ARM_SectionObject': 20, 26 | 'seL4_ARM_SuperSectionObject': 24, 27 | 'seL4_IOPageTableObject': 12 28 | } 29 | 30 | 31 | class CapdlTestCase(unittest.TestCase): 32 | 33 | def setUp(self): 34 | register_object_sizes(test_object_sizes) 35 | -------------------------------------------------------------------------------- /Findcapdl.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | set(CAPDL_DIR 8 | "${CMAKE_CURRENT_LIST_DIR}" 9 | CACHE STRING "" 10 | ) 11 | set(PYTHON_CAPDL_PATH 12 | "${CAPDL_DIR}/python-capdl-tool" 13 | CACHE STRING "" 14 | ) 15 | set(CAPDL_TOOL_HELPERS 16 | "${CAPDL_DIR}/capDL-tool/capDL-tool.cmake" 17 | CACHE STRING "" 18 | ) 19 | set(CAPDL_LINKER_TOOL 20 | "${CAPDL_DIR}/cdl_utils/capdl_linker.py" 21 | CACHE STRING "" 22 | ) 23 | mark_as_advanced(CAPDL_DIR PYTHON_CAPDL_PATH CAPDL_TOOL_HELPERS CAPDL_LINKER_TOOL) 24 | 25 | macro(capdl_import_project) 26 | add_subdirectory(${CAPDL_DIR} capdl) 27 | endmacro() 28 | 29 | include(${CAPDL_DIR}/capdl-loader-app/helpers.cmake) 30 | include(${CAPDL_DIR}/capDL-tool/capDL-tool.cmake) 31 | 32 | include(FindPackageHandleStandardArgs) 33 | FIND_PACKAGE_HANDLE_STANDARD_ARGS( 34 | capdl DEFAULT_MSG CAPDL_DIR PYTHON_CAPDL_PATH CAPDL_TOOL_HELPERS CAPDL_LINKER_TOOL 35 | ) 36 | -------------------------------------------------------------------------------- /python-capdl-tool/capdl/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | from __future__ import absolute_import, division, print_function, \ 8 | unicode_literals 9 | 10 | from .Cap import Cap 11 | from .ELF import ELF 12 | from .Object import Frame, PageTable, PageDirectory, ASIDPool, CNode, Endpoint, \ 13 | Notification, TCB, Untyped, IOPorts, IODevice, IOPageTable, \ 14 | IRQ, SC, RTReply, calculate_cnode_size, \ 15 | Object, ContainerObject, ObjectType, ObjectRights, IRQControl, register_object_sizes, \ 16 | SchedControl, ARMIRQMode, ContextBank, StreamID 17 | from .Spec import Spec 18 | from .Allocator import ObjectAllocator, CSpaceAllocator, AddressSpaceAllocator, AllocatorState 19 | from .PageCollection import PageCollection, create_address_space 20 | from .util import page_index, page_sizes, page_table_coverage, \ 21 | page_table_index, page_table_vaddr, page_vaddr, lookup_architecture, valid_architectures 22 | -------------------------------------------------------------------------------- /python-capdl-tool/tests/testmerge.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 4 | # 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | from __future__ import absolute_import, division, print_function, \ 9 | unicode_literals 10 | 11 | import capdl 12 | from tests import CapdlTestCase 13 | 14 | 15 | class TestSpec(CapdlTestCase): 16 | 17 | def test_merge(self): 18 | a = capdl.TCB('foo') 19 | b = capdl.TCB('bar') 20 | 21 | spec1 = capdl.Spec() 22 | spec2 = capdl.Spec() 23 | spec1.merge(spec2) 24 | assert len(spec1.objs) == 0 25 | 26 | spec1 = capdl.Spec() 27 | spec1.add_object(a) 28 | spec2 = capdl.Spec() 29 | spec1.merge(spec2) 30 | assert spec1.objs == set([a]) 31 | 32 | spec1 = capdl.Spec() 33 | spec1.add_object(a) 34 | spec2 = capdl.Spec() 35 | spec2.add_object(b) 36 | spec1.merge(spec2) 37 | assert spec1.objs == set([a, b]) 38 | -------------------------------------------------------------------------------- /cdl_utils/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # cdl_utils 8 | 9 | This directory provides a collection of utility scripts relating to capDL. 10 | 11 | ## capdl_linker.py 12 | 13 | The capdl_linker.py generates a final capDL spec from a input list of ELF files, 14 | and a record of which resources via objects and capabilities that the ELF file 15 | applications require. This then produces a capDL file (.cdl) that can be given 16 | to the translator tool for translating into different formats. 17 | 18 | ## untyped_gen.py 19 | 20 | This takes a description of the memory layout in a system from a seL4 build system 21 | artifact and generates the list of untyped objects that the kernel is expected to 22 | create. This relies on knowledge of which policies that the kernel will use for 23 | generating the initial untyped objects. The output of this script is typically 24 | used for performing more exact allocation of objects in a capDL specification. 25 | -------------------------------------------------------------------------------- /python-capdl-tool/examples/allocation.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | # The module Allocator.py contains an object and CSpace allocator. This example 8 | # shows how these can be used for convenience. 9 | 10 | from __future__ import absolute_import, division, print_function, \ 11 | unicode_literals 12 | 13 | # Add the root directory of this repository to your PYTHONPATH environment 14 | # variable to enable the following import. 15 | import capdl 16 | 17 | # Create an allocator for kernel objects. 18 | obj_allocator = capdl.ObjectAllocator() 19 | 20 | # Let's create a CNode. Note that the allocation type constants are named to 21 | # match the enums in the kernel. 22 | my_cnode = obj_allocator.alloc(capdl.ObjectType.seL4_CapTableObject, size_bits=28) 23 | 24 | # Now let's allocate some objects and caps to them in this CNode using a CSpace 25 | # allocator. 26 | cap_allocator = capdl.CSpaceAllocator(my_cnode) 27 | my_tcb = obj_allocator.alloc(capdl.ObjectType.seL4_TCBObject) 28 | tcb_slot = cap_allocator.alloc(my_tcb) 29 | cnode_slot = cap_allocator.alloc(my_cnode) 30 | 31 | # Now create a spec and print it out to show what we did. 32 | spec = capdl.Spec() 33 | spec.add_object(my_cnode) 34 | spec.add_object(my_tcb) 35 | print(str(spec)) 36 | -------------------------------------------------------------------------------- /python-capdl-tool/examples/capdl-manipulation.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | from __future__ import absolute_import, division, print_function, \ 8 | unicode_literals 9 | 10 | # Add the root directory of this repository to your PYTHONPATH environment 11 | # variable to enable the following import. 12 | import capdl 13 | 14 | # Let's make a TCB: 15 | tcb = capdl.TCB('my_tcb') 16 | 17 | # Set some relevant properties of it: 18 | tcb.ip = 0x8000 19 | tcb.sp = 0xdeadbeef 20 | tcb.init += [0xcafe, 0xdeaf] 21 | 22 | # Create an endpoint: 23 | ep = capdl.Endpoint('my_ep') 24 | 25 | # Let's set that endpoint as the TCB's fault EP: 26 | ep_cap = capdl.Cap(ep) 27 | tcb['fault_ep'] = ep_cap 28 | 29 | # Let's setup a CSpace and VSpace for the TCB: 30 | cspace = capdl.CNode('my_cnode', 28) # <-- size in bits 31 | vspace = capdl.PageDirectory('my_pd') 32 | tcb['cspace'] = capdl.Cap(cspace) 33 | tcb['vspace'] = capdl.Cap(vspace) 34 | 35 | # Throw in an untyped and give the thread a cap to it: 36 | ut = capdl.Untyped('my_ut', 10) # <-- size in bits 37 | cspace[1] = capdl.Cap(ut) 38 | 39 | # Let's create a spec from all this and output it: 40 | spec = capdl.Spec() 41 | for obj in [tcb, ep, cspace, vspace, ut]: 42 | spec.add_object(obj) 43 | print(spec) 44 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /capDL-tool/capdl.dtd: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /python-capdl-tool/tests/testelf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 4 | # 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | from __future__ import absolute_import, division, print_function, \ 9 | unicode_literals 10 | 11 | import unittest 12 | 13 | from capdl import ELF 14 | from tests import CapdlTestCase 15 | 16 | 17 | class TestElf(CapdlTestCase): 18 | 19 | def test_elf(self): 20 | elf = ELF('resources/arm-hello.bin') 21 | assert elf.get_arch() in [40, 'EM_ARM', 'ARM'] 22 | elf.get_spec() 23 | 24 | def test_ia32_elf(self): 25 | elf = ELF('resources/ia32-hello.bin') 26 | assert elf.get_arch() == 'x86' 27 | 28 | elf.get_spec() 29 | 30 | def test_symbol_lookup(self): 31 | elf = ELF('resources/unstripped.bin') 32 | assert elf.get_arch() == 'x86' 33 | 34 | # Confirm that the address concurs with the one we get from objdump. 35 | assert elf.get_symbol_vaddr('_start') == 0x08048d48 36 | 37 | elf = ELF('resources/stripped.bin') 38 | assert elf.get_arch() == 'x86' 39 | 40 | # We shouldn't be able to get the symbol from the stripped binary. 41 | try: 42 | vaddr = elf.get_symbol_vaddr('_start') 43 | assert not ('Symbol lookup on a stripped binary returned _start == 0x%0.8x' % vaddr) 44 | except: 45 | # Expected 46 | pass 47 | 48 | 49 | if __name__ == '__main__': 50 | unittest.main() 51 | -------------------------------------------------------------------------------- /python-capdl-tool/tests/runall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 5 | # 6 | # SPDX-License-Identifier: BSD-2-Clause 7 | # 8 | 9 | """ 10 | This script is a quick way to execute the tests for all capdl-python modules. 11 | """ 12 | 13 | from __future__ import absolute_import, division, print_function, \ 14 | unicode_literals 15 | from concurrencytest import ConcurrentTestSuite, fork_for_tests 16 | 17 | import argparse 18 | import multiprocessing 19 | import os 20 | import sys 21 | import unittest 22 | 23 | ME = os.path.abspath(__file__) 24 | 25 | 26 | def main(argv): 27 | parser = argparse.ArgumentParser(prog=argv[0], 28 | description='Run capdl tests') 29 | parser.add_argument('--verbosity', '-v', default=1, type=int, 30 | help="Verbosity to run tests. 0 = quiet. 1 = default. 2 = verbose") 31 | options = parser.parse_args(argv[1:]) 32 | 33 | # load the tests we want to run 34 | loader = unittest.TestLoader() 35 | test_suite = unittest.TestSuite() 36 | print("Looking for tests in {0}".format(os.path.dirname(ME))) 37 | test_suite.addTests(loader.discover(os.path.dirname(ME), pattern="*.py")) 38 | 39 | concurrent_suite = ConcurrentTestSuite(test_suite, fork_for_tests(multiprocessing.cpu_count())) 40 | runner = unittest.TextTestRunner(verbosity=options.verbosity) 41 | result = runner.run(concurrent_suite) 42 | if result.wasSuccessful(): 43 | return 0 44 | return 1 45 | 46 | 47 | if __name__ == '__main__': 48 | sys.exit(main(sys.argv)) 49 | -------------------------------------------------------------------------------- /capdl-loader-app/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # CapDL initialiser for seL4 8 | 9 | This repository contains the capDL initialiser for seL4. 10 | 11 | The capDL initialiser is the root task for a seL4 system that takes a 12 | description of the state to be initialised using [capDL][Kuz_KLW_10], 13 | and starts the system in conformance with the specification. 14 | 15 | The code is an implementation of the formal algorithm specified 16 | in Isabelle/HOL. 17 | 18 | [Kuz_KLW_10]: https://trustworthy.systems/publications/nicta_full_text/3679.pdf "capDL: A language for describing capability-based systems" 19 | 20 | ## Repository overview 21 | 22 | * [`src/main.c`](src/main.c): The implementation of the initialiser 23 | * [`include/capdl.h`](include/capdl.h): The data structure for capDL. 24 | 25 | ## Dependencies 26 | 27 | The capDL loader uses `capDL-tool` to generate a data structure 28 | containing the capDL specification to be initialised. 29 | 30 | ## Related papers 31 | 32 | The formal model for the capDL initialiser is documented in a 33 | [ICFEM '13 paper][Boyton_13] and Andrew Boyton's [PhD thesis][Boyton_14]. 34 | 35 | [Boyton_13]: https://trustworthy.systems/publications/nicta_full_text/7047.pdf "Formally Verified System Initialisation" 36 | [Boyton_14]: https://trustworthy.systems/publications/nicta_full_text/9141.pdf "Secure architectures on a verified microkernel" 37 | 38 | ## License 39 | 40 | The files in this repository are release under standard open source licenses. 41 | Please see individual file headers and the `LICENSE_BSD2`.txt file for details. 42 | -------------------------------------------------------------------------------- /capDL-tool/tools/capdl.vim: -------------------------------------------------------------------------------- 1 | " 2 | " Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 | " 4 | " SPDX-License-Identifier: BSD-2-Clause 5 | " 6 | " 7 | " CapDL syntax highlighting for vim. 8 | " 9 | " To use this, copy to ~/.vim/syntax/ and put the following in 10 | " ~/.vim/filetype.vim: 11 | " 12 | " augroup filetypedetect 13 | " au BufRead,BufNewFile *.cdl setfiletype capdl 14 | " augroup END 15 | " 16 | " Note that this supports CPP commands in your CapDL as well. 17 | " 18 | 19 | syn keyword CapDLKeyword arch caps objects arm11 ia32 20 | syn match CapDLIRQMap "\" 21 | syn match CapDLIRQ "\\( maps\)\@!" 22 | syn keyword CapDLObject notification asid_pool cnode ep frame io_device io_ports io_pt pd pt tcb ut 23 | syn keyword CapDLAttribute addr affinity badge dom fault_ep G guard guard_size init ip max_prio prio sp R RG RX RW RWG RWX W WG WX paddr cached uncached 24 | syn match CapDLCPP "[ \t]*#.*$" 25 | syn match CapDLLiteral "\<\(0x\)\?[0-9]\+\(k\|M\)\?\( bits\)\?\>" 26 | syn match CapDLLiteral "\<0x[0-f]\+\>" 27 | syn keyword CapDLSymbolicSlot cspace vspace reply_slot caller_slot ipc_buffer_slot fault_ep_slot sc_slot temp_fault_ep_slot bound_notification bound_vcpu 28 | 29 | syn region Foldable start="{" end="}" fold transparent 30 | 31 | syn match CapDLMultiLineComment "\/\*\_.\{-}\*\/" 32 | syn match CapDLSingleLineComment "\(\/\/\|--\).*$" 33 | 34 | hi def link CapDLMultiLineComment Comment 35 | hi def link CapDLSingleLineComment Comment 36 | hi def link CapDLIRQMap Statement 37 | hi def link CapDLKeyword Statement 38 | hi def link CapDLObject Type 39 | hi def link CapDLIRQ Type 40 | hi def link CapDLAttribute Type 41 | hi def link CapDLCPP PreProc 42 | hi def link CapDLLiteral Constant 43 | hi def link CapDLSymbolicSlot Constant 44 | -------------------------------------------------------------------------------- /.github/workflows/build.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: Build 7 | 8 | on: 9 | push: 10 | branches: 11 | - master 12 | pull_request: 13 | 14 | jobs: 15 | pdf: 16 | name: Language Spec PDF 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Install texlive and pandoc 21 | run: | 22 | sudo apt-get update 23 | sudo apt-get install pandoc texlive-latex-extra texlive-fonts-extra 24 | - name: Build PDF 25 | run: | 26 | cd capDL-tool/doc/tex 27 | make 28 | 29 | python-capdl-tool: 30 | name: Python build 31 | runs-on: ubuntu-latest 32 | strategy: 33 | matrix: 34 | python-version: [ '3.9', '3.x' ] 35 | fail-fast: false 36 | steps: 37 | - uses: actions/checkout@v4 38 | - uses: actions/setup-python@v5 39 | with: 40 | python-version: ${{ matrix.python-version }} 41 | - name: Install python packages 42 | run: | 43 | cd python-capdl-tool 44 | pip3 install -r requirements.txt 45 | - name: Run tests 46 | run: | 47 | cd python-capdl-tool/tests 48 | PYTHONPATH=../ ./runall.py 49 | 50 | capDL-tool: 51 | name: capDL-tool (ghc) 52 | runs-on: ubuntu-latest 53 | steps: 54 | - uses: actions/checkout@v4 55 | - run: | 56 | sudo apt-get update 57 | sudo apt-get install libxml2-utils 58 | - uses: haskell-actions/setup@v2 59 | with: 60 | enable-stack: true 61 | stack-setup-ghc: true 62 | ghc-version: 9.2.8 63 | - name: Build and test 64 | run: | 65 | cd capDL-tool 66 | make clean sandbox all 67 | make tests 68 | -------------------------------------------------------------------------------- /capDL-tool/example.cdl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | arch ia32 8 | 9 | objects 10 | 11 | -- following 2 could be implicit 12 | ioport = ioport 13 | irqtable = cnode (8 bits) 14 | 15 | rm_ut = ut { 16 | rm_tcb = tcb 17 | name2 = ut { 18 | rm_cn = cnode (10 bits) 19 | } 20 | rm_pd = page_directory [ 10 -> frame_name_x, .. ] 21 | rm_ap = asid_pool (asid_high: 0x0) 22 | 23 | linux_pd = page_directory 24 | 25 | rm_ut_small[50] = untyped (12 bits) 26 | rm_ut_big[101] = untyped (20 bits) 27 | 28 | frame_nic1[64] = frame (4k) 29 | -- io space?? 30 | 31 | frame_nic2[64] = frame (4k) 32 | -- io space?? 33 | 34 | frame_nic3[4] = frame (4k) 35 | -- io space?? 36 | 37 | timer = notification 38 | control = ep 39 | } 40 | 41 | name: ut { x, y, z } 42 | 43 | name: ut 44 | name/name2/name3/x = tcb .. 45 | name/y = 46 | name/z = 47 | 48 | caps 49 | 50 | name { 51 | opt num: obj_name parameters 52 | } 53 | 54 | rm_cn { 55 | 001: rm_tcb; 56 | 002: rm_cn (0, 0, mask: R, rights: W); 57 | 003: rm_pd; 58 | 006: rm_ap; 59 | 007: ioport; 60 | 00b: linux_pd; 61 | 00c: rm_ut_small[3..7]; 62 | 00x: rm_ut_small[7..200, 232, 237..]; 63 | 03e: rm_ut_big[]; 64 | 65 | 0a3: IRQHandler nic1; 66 | 0a4: name = frame_nic1[]; 67 | 0e4: iospace; 68 | 69 | 0e5: IRQHandler nic2 70 | 0e6: frame_nic2[] 71 | 126: iospace 72 | 73 | 127: IRQHandler nic3 74 | 128: frame_nic3[] 75 | 12c: iospace 76 | 77 | 12d: timer 78 | 12e: control 79 | 12f: name2 = name (masked: R) 80 | } 81 | 82 | rm_tcb { 83 | vspace: rm_pd 84 | cspace: rm_cn 85 | } 86 | 87 | cap_name = (rm_tcb, cspace) 88 | cap_name2 = (irqtable, 0) 89 | 90 | irqtable { 0: notification_cap nic1 } 91 | 92 | cnode_booter { 93 | 001: rm_ut 94 | } 95 | 96 | CDT: { 97 | rm_ut parent_of timer 98 | } 99 | -------------------------------------------------------------------------------- /python-capdl-tool/capdl/Spec.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | from __future__ import absolute_import, division, print_function, \ 8 | unicode_literals 9 | 10 | from .Object import IRQ, Object, PageTable 11 | from .util import lookup_architecture 12 | 13 | 14 | class Spec(object): 15 | """ 16 | A CapDL specification. 17 | """ 18 | 19 | def __init__(self, arch='arm11'): 20 | self.arch = arch 21 | self.objs = set() 22 | 23 | @property 24 | def arch(self): 25 | return self._arch 26 | 27 | @arch.setter 28 | def arch(self, value): 29 | if value is None: 30 | self._arch = None 31 | else: 32 | self._arch = lookup_architecture(value) 33 | 34 | def add_object(self, obj): 35 | assert isinstance(obj, Object) 36 | self.objs.add(obj) 37 | 38 | def merge(self, other): 39 | assert isinstance(other, Spec) 40 | self.objs.update(other) 41 | 42 | def __iter__(self): 43 | return self.objs.__iter__() 44 | 45 | def __repr__(self): 46 | return 'arch %(arch)s\n\n' \ 47 | 'objects {\n%(objs)s\n}\n\n' \ 48 | 'caps {\n%(caps)s\n}\n\n' \ 49 | 'irq maps {\n%(irqs)s\n}' % { 50 | 51 | # Architecture; arm11 or ia32 52 | 'arch': self.arch.capdl_name(), 53 | 54 | # Kernel objects 55 | 'objs': '\n'.join(sorted(str(x) for x in self.objs)), 56 | 57 | # Capabilities to kernel objects 58 | 'caps': '\n'.join(sorted( 59 | x.print_contents() for x in self.objs if x.is_container())), 60 | 61 | # Mapping from interrupt numbers to IRQ objects 62 | 'irqs': '\n'.join(sorted( 63 | '%d: %s' % (x.number, x.name) for x in self.objs 64 | if isinstance(x, IRQ) and x.number is not None)), 65 | } 66 | -------------------------------------------------------------------------------- /object_sizes/object_sizes.yaml: -------------------------------------------------------------------------------- 1 | /* We preprocess this file to extract the sizes of objects for use in camkes/capdl */ 2 | #define __ASSEMBLER__ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | seL4_TCBObject: seL4_TCBBits 9 | seL4_EndpointObject: seL4_EndpointBits 10 | seL4_NotificationObject: seL4_NotificationBits 11 | seL4_SmallPageObject: seL4_PageBits 12 | seL4_LargePageObject: seL4_LargePageBits 13 | seL4_ASID_Pool: seL4_ASIDPoolBits 14 | seL4_ASID_Table: seL4_ASIDPoolIndexBits 15 | seL4_Slot: seL4_SlotBits 16 | seL4_Value_MinUntypedBits: seL4_MinUntypedBits 17 | seL4_Value_MaxUntypedBits: seL4_MaxUntypedBits 18 | seL4_Value_BadgeBits: seL4_BadgeBits 19 | #ifdef seL4_ReplyBits 20 | seL4_RTReplyObject: seL4_ReplyBits 21 | #endif 22 | #ifdef seL4_VCPUBits 23 | seL4_VCPU: seL4_VCPUBits 24 | #endif 25 | #ifdef seL4_PageTableBits 26 | seL4_PageTableObject: seL4_PageTableBits 27 | #endif 28 | #ifdef seL4_PageDirBits 29 | seL4_PageDirectoryObject: seL4_PageDirBits 30 | #endif 31 | #ifdef seL4_SectionBits 32 | seL4_ARM_SectionObject: seL4_SectionBits 33 | #endif 34 | #ifdef seL4_SuperSectionBits 35 | seL4_ARM_SuperSectionObject: seL4_SuperSectionBits 36 | #endif 37 | #ifdef seL4_HugePageBits 38 | seL4_HugePageObject: seL4_HugePageBits 39 | #endif 40 | #ifdef seL4_PGDBits 41 | seL4_AARCH64_PGD: seL4_PGDBits 42 | #endif 43 | #ifdef seL4_PUDBits 44 | seL4_AARCH64_PUD: seL4_PUDBits 45 | #endif 46 | #ifdef seL4_IOPageTableBits 47 | seL4_IOPageTableObject: seL4_IOPageTableBits 48 | #endif 49 | #ifdef seL4_PDPTBits 50 | seL4_X64_PDPT: seL4_PDPTBits 51 | #endif 52 | #ifdef seL4_PML4Bits 53 | seL4_X64_PML4: seL4_PML4Bits 54 | #endif 55 | #ifdef seL4_MinSchedContextBits 56 | seL4_SchedContextObject: seL4_MinSchedContextBits 57 | #endif 58 | 59 | /* These need not, and should not, be allocated */ 60 | seL4_IOPorts: 0 61 | seL4_IODevice: 0 62 | seL4_ARMIODevice: 0 63 | seL4_IRQ: 0 64 | seL4_IOAPICIRQ: 0 65 | seL4_MSIIRQ: 0 66 | seL4_ARMIRQ: 0 67 | seL4_ARMSID: 0 68 | seL4_ARMCB: 0 69 | seL4_ARMSMC: 0 70 | seL4_ARMSGI_Signal: 0 71 | -------------------------------------------------------------------------------- /capDL-tool/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # capDL-tool 8 | 9 | This tool is intended to be used with capDL textual specifications. In 10 | particular, it can parse input files into a variety of different output 11 | formats, including Isabelle theory files and C source files that can be given 12 | to the capDL initialiser. 13 | 14 | For usage instructions run 'make' and then './parse-capDL'. 15 | 16 | For details of the Capability Distribution Language, see the specification in 17 | the 'doc/' directory. Run 'make' in that directory to generate 'capDL.pdf'. 18 | 19 | ## Repository overview 20 | 21 | * 'CapDL': Haskell source code of the tool 22 | * '*.cdl': Toy examples used as test files 23 | * '*.right': Canonical representations of the examples used in testing 24 | * 'doc': Latex source of the capDL Specification 25 | 26 | ## Dependencies 27 | 28 | [Stack][1] should automatically retrieve all necessary Haskell dependencies to 29 | build this tool, but if you need exact dependency information it is available 30 | in [`capDL-tool.cabal`](capDL-tool.cabal) and [`stack.yaml`](stack.yaml). 31 | 32 | [1]: https://haskellstack.org 33 | 34 | To install all dependencies of this tool (including the haskell compiler if an 35 | appropriate version of GHC isn't found), run 36 | 37 | make sandbox 38 | 39 | This will install GHC in "~/.stack" (if it isn't already installed there), and 40 | install all libraries in the local directory ".stack-work". 41 | 42 | To build this tool, run 43 | 44 | make 45 | 46 | To place the capdl binary in the top level directory of this project, run 47 | 48 | make install 49 | 50 | ## Related papers 51 | 52 | The Capability Distribution Language is also documented in 53 | 54 | Ihor Kuz, Gerwin Klein, Corey Lewis and Adam Christopher Walker 55 | [_"capDL: A language for describing capability-based systems"_][CapDL] 56 | Proceedings of the 1st Asia-Pacific Workshop on Systems (APSys), pp. 31–36, 57 | New Delhi, India, August, 2010 58 | 59 | [CapDL]: https://trustworthy.systems/publications/papers/Kuz_KLW_10.pdf 60 | 61 | ## License 62 | 63 | The files in this repository are released under standard open source licenses. 64 | Please see individual file headers and the `LICENSE_BSD2`.txt file for details. 65 | -------------------------------------------------------------------------------- /capDL-tool/example-aarch64.right: -------------------------------------------------------------------------------- 1 | arch aarch64 2 | 3 | objects { 4 | 5 | cnode_booter = cnode (8 bits) 6 | control = ep 7 | frame_nic1[64] = frame (4k) 8 | frame_nic2[64] = frame (4k) 9 | frame_nic3[4] = frame (4k) 10 | g = tcb (dom: 0) 11 | irq_handler[3] = irq 12 | linux_pd = pt 13 | nic1_notification = notification 14 | rm_ap = asid_pool (asid_high: 0x1) 15 | rm_cn = cnode (10 bits) 16 | rm_pd = pgd 17 | rm_tcb = tcb (fault_ep: 15, dom: 5, init: [10]) 18 | sgi2 = arm_sgi_signal (irq: 1, target: 0) 19 | test[5] = cnode (8 bits) 20 | timer = notification 21 | x = tcb (dom: 0) 22 | y[5] = ep 23 | z = ep 24 | 25 | name = ut (8 bits) {y[0..2], z, name2} 26 | name2 = ut {name3} 27 | name3 = ut {x} 28 | name_b = ut (10 bits) {name} 29 | rm_ut = ut {rm_tcb, something, rm_pd, rm_ap, linux_pd, 30 | rm_ut_small[0..49], rm_ut_big[0..99], frame_nic1[0..63], 31 | frame_nic2[0..63], frame_nic3[0..3], timer, control, test[0..4]} 32 | rm_ut_big[100] = ut (20 bits) 33 | rm_ut_small[50] = ut (12 bits) 34 | rm_ut_small[0] = ut (12 bits) {name_b, g} 35 | something = ut (8 bits) {rm_cn} 36 | 37 | } caps { 38 | 39 | cnode_booter { 40 | 1: rm_ut 41 | 2: sched_control (core: 0) 42 | } 43 | 44 | rm_ap {1: rm_pd} 45 | 46 | rm_cn { 47 | 1: rm_tcb 48 | 2: rm_cn 49 | 3: rm_pd 50 | 6: rm_ap 51 | 11: linux_pd 52 | 12: rm_ut_small[3..5, 7..20, 23, 27..49] 53 | 62: rm_ut_big[0..99] 54 | 163: irq_handler[0] 55 | 164: frame_nic1[0..63] 56 | 229: irq_handler[1] 57 | 230: frame_nic2[0..63] (RW, asid: (0x1, 0x1)) 58 | 294: sgi2 59 | 295: irq_handler[2] 60 | 296: frame_nic3[0..3] 61 | 301: timer (G) 62 | 302: control (badge: 10) 63 | 303: rm_cn 64 | 304: test[0..1, 1..2] 65 | 308: name_b 66 | 512: rm_cn 67 | 513: rm_cn 68 | 514: frame_nic1[0..63] 69 | } 70 | 71 | rm_tcb { 72 | 0: rm_cn 73 | 1: rm_pd 74 | } 75 | 76 | test[0] {1: rm_cn} 77 | 78 | test[1] { 79 | 1: name_b 80 | 2: g (reply) 81 | 512: rm_cn 82 | } 83 | 84 | test[2..4] { 85 | 1: name_b 86 | 512: rm_cn 87 | } 88 | 89 | } cdt { 90 | 91 | (cnode_booter, 1) {(rm_cn, 301)} 92 | 93 | (test[1], 512) {(rm_cn, 302)} 94 | 95 | (rm_cn, 303) { 96 | (rm_cn, 512) 97 | (rm_cn, 513) 98 | } 99 | 100 | } irq maps { 101 | 102 | 0: irq_handler[0..2] 103 | 104 | } -------------------------------------------------------------------------------- /capDL-tool/example-arm.right: -------------------------------------------------------------------------------- 1 | arch arm11 2 | 3 | objects { 4 | 5 | a = tcb (dom: 0) 6 | b = tcb (dom: 0) 7 | cnode_booter = cnode (8 bits) 8 | control = ep 9 | frame_nic1[64] = frame (4k) 10 | frame_nic2[64] = frame (4k) 11 | frame_nic3[4] = frame (4k) 12 | g = tcb (dom: 0) 13 | irq_handler[3] = irq 14 | linux_pd = pd 15 | nic1_notification = notification 16 | rm_ap = asid_pool (asid_high: 0x1) 17 | rm_cn = cnode (10 bits) 18 | rm_pd = pd 19 | rm_tcb = tcb (fault_ep: 15, dom: 5, init: [10]) 20 | sgi1 = arm_sgi_signal (irq: 10, target: 2) 21 | test[5] = cnode (8 bits) 22 | timer = notification 23 | x = tcb (dom: 0) 24 | y[5] = ep 25 | z = ep 26 | 27 | name = ut (8 bits) {y[0..2], z, a, b, name2} 28 | name2 = ut {name3} 29 | name3 = ut {x} 30 | name_b = ut (10 bits) {name} 31 | rm_ut = ut {rm_tcb, something, rm_pd, rm_ap, linux_pd, 32 | rm_ut_small[0..49], rm_ut_big[0..99], frame_nic1[0..63], 33 | frame_nic2[0..63], frame_nic3[0..3], timer, control, test[0..4]} 34 | rm_ut_big[100] = ut (20 bits) 35 | rm_ut_small[50] = ut (12 bits) 36 | rm_ut_small[0] = ut (12 bits) {name_b, g} 37 | something = ut (8 bits) {rm_cn} 38 | 39 | } caps { 40 | 41 | cnode_booter { 42 | 1: rm_ut 43 | 2: sched_control (core: 0) 44 | } 45 | 46 | rm_ap {1: rm_pd} 47 | 48 | rm_cn { 49 | 1: rm_tcb 50 | 2: rm_cn 51 | 3: rm_pd (asid: (0x1, 0x1)) 52 | 6: rm_ap 53 | 11: linux_pd 54 | 12: rm_ut_small[3..5, 7..20, 23, 27..49] 55 | 62: rm_ut_big[0..99] 56 | 163: irq_handler[0] 57 | 164: frame_nic1[0..63] 58 | 229: irq_handler[1] 59 | 230: frame_nic2[0..63] (RW, asid: (0x1, 0x1)) 60 | 294: sgi1 61 | 295: irq_handler[2] 62 | 296: frame_nic3[0..3] 63 | 301: timer (G) 64 | 302: control (badge: 10) 65 | 303: rm_cn 66 | 304: test[0..1, 1..2] 67 | 308: name_b 68 | 512: rm_cn 69 | 513: rm_cn 70 | 514: frame_nic1[0..63] 71 | } 72 | 73 | rm_tcb { 74 | 0: rm_cn 75 | 1: rm_pd 76 | } 77 | 78 | test[0] {1: rm_cn} 79 | 80 | test[1] { 81 | 1: name_b 82 | 2: g (reply) 83 | 512: rm_cn 84 | } 85 | 86 | test[2..4] { 87 | 1: name_b 88 | 512: rm_cn 89 | } 90 | 91 | } cdt { 92 | 93 | (cnode_booter, 1) {(rm_cn, 301)} 94 | 95 | (test[1], 512) {(rm_cn, 302)} 96 | 97 | (rm_cn, 303) { 98 | (rm_cn, 512) 99 | (rm_cn, 513) 100 | } 101 | 102 | } irq maps { 103 | 104 | 0: irq_handler[0..2] 105 | 106 | } -------------------------------------------------------------------------------- /capDL-tool/capDL-tool.cabal: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | -- 4 | -- SPDX-License-Identifier: BSD-2-Clause 5 | -- 6 | 7 | name: capDL-tool 8 | version: 1.0.0.1 9 | synopsis: A tool for processing seL4 capDL specifications. 10 | license: BSD2 11 | author: Gerwin Klein (Proofcraft), Corey Lewis (Proofcraft), Matthew Fernandez (Data61), Japheth Lim (Data61) 12 | maintainer: corey.lewis@proofcraft.systems 13 | homepage: https://github.com/seL4/capdl 14 | copyright: Data61, CSIRO 15 | UNSW 16 | Proofcraft 17 | category: Development 18 | build-type: Simple 19 | extra-source-files: README.md 20 | cabal-version: 1.18 21 | tested-with: GHC == 9.2.8 22 | 23 | executable parse-capDL 24 | main-is: Main.hs 25 | 26 | other-extensions: DeriveDataTypeable, 27 | FlexibleContexts, 28 | FlexibleInstances, 29 | TypeSynonymInstances, 30 | TemplateHaskell 31 | 32 | build-depends: 33 | -- Included libraries 34 | array >=0.5 && <0.6, 35 | base >= 4.16, 36 | containers >=0.6 && <0.7, 37 | filepath >=1.4 && <1.5, 38 | mtl >=2.2 && <2.3, 39 | parsec >=3.1 && <3.2, 40 | unix >=2.7 && <3, 41 | 42 | -- Other libraries 43 | base-compat == 0.12.*, 44 | lens >= 4.15, 45 | MissingH >=1.4 && <1.6, 46 | pretty >=1.1 && <1.2, 47 | regex-compat >= 0.90, 48 | split >=0.2 && <0.3, 49 | yaml >=0.8 && <0.12 50 | 51 | other-modules: CapDL.AST, CapDL.DumpParser, CapDL.MakeModel, 52 | CapDL.Matrix, CapDL.Model, CapDL.Parser, 53 | CapDL.ParserUtils, CapDL.PrintC, CapDL.PrintDot, 54 | CapDL.PrintIsabelle, CapDL.PrintModel, 55 | CapDL.PrintUtils, CapDL.PrintXml, CapDL.STCC, 56 | CapDL.State 57 | 58 | default-language: Haskell2010 59 | 60 | ghc-options: -O2 -Werror -Wall -fno-warn-name-shadowing 61 | -fno-warn-missing-signatures -fno-warn-type-defaults 62 | -fno-warn-incomplete-uni-patterns 63 | -fno-warn-incomplete-record-updates 64 | -------------------------------------------------------------------------------- /capDL-tool/example-ia32.right: -------------------------------------------------------------------------------- 1 | arch ia32 2 | 3 | objects { 4 | 5 | a = tcb (dom: 0) 6 | b = tcb (dom: 0) 7 | cnode_booter = cnode (8 bits) 8 | control = ep 9 | frame_name = frame (4k) 10 | frame_nic1[64] = frame (4k) 11 | frame_nic2[64] = frame (4k) 12 | frame_nic3[4] = frame (4k) 13 | io_ports = io_ports (ports: [4096..45894]) 14 | io_pt1 = io_pt (level: 1) 15 | io_pt2 = io_pt (level: 2) 16 | io_pt3 = io_pt (level: 3) 17 | iospace = io_device (domainID: 50, 15:10.3) 18 | irq_handler[3] = irq 19 | linux_pd = pd 20 | nic1 = io_device (domainID: 0, 0:0.0) 21 | nic1_notification = notification 22 | nic2 = io_device (domainID: 0, 0:0.0) 23 | nic3 = io_device (domainID: 50, 15:10.3) 24 | rm_ap = asid_pool (asid_high: 0x0) 25 | rm_cn = cnode (10 bits) 26 | rm_pd = pd 27 | rm_tcb = tcb (dom: 0) 28 | some_pt = pt 29 | timer = notification 30 | x = tcb (dom: 0) 31 | y = ep 32 | z = ep 33 | 34 | name = ut (8 bits) {y, z, name3, a, b} 35 | name2 = ut (8 bits) {rm_cn} 36 | name3 = ut {x} 37 | name_b = ut (10 bits) 38 | rm_ut = ut {rm_tcb, name2, rm_pd, rm_ap, linux_pd, 39 | rm_ut_small[0..49], rm_ut_big[0..99], frame_nic1[0..63], nic1, 40 | frame_nic2[0..63], nic2, frame_nic3[0..3], nic3, timer, control, 41 | io_pt1, io_pt2, io_pt3} 42 | rm_ut_big[100] = ut (20 bits) 43 | rm_ut_small[50] = ut (12 bits) 44 | 45 | } caps { 46 | 47 | cnode_booter {1: rm_ut} 48 | 49 | io_pt1 {0: io_pt2} 50 | 51 | io_pt2 {0: io_pt3} 52 | 53 | io_pt3 {0: frame_nic3[0]} 54 | 55 | linux_pd { 56 | 10: frame_name 57 | 255: some_pt 58 | 256: frame_nic1[0..30] 59 | 304: frame_nic1[31..63] 60 | 352: frame_nic2[10] 61 | 384: frame_nic2[11..17, 0..2, 10, 10..63] 62 | } 63 | 64 | nic1 {0: io_pt1} 65 | 66 | rm_cn { 67 | 1: rm_tcb 68 | 2: rm_cn 69 | 3: rm_pd 70 | 6: rm_ap 71 | 7: io_ports 72 | 11: linux_pd 73 | 12: rm_ut_small[3..5, 7..20, 23, 27..49] 74 | 62: rm_ut_big[0..99] 75 | 163: irq_handler[0] 76 | 164: frame_nic1[0..63] 77 | 228: iospace 78 | 229: irq_handler[1] 79 | 230: frame_nic2[0..63] 80 | 295: irq_handler[2] 81 | 296: frame_nic3[0..3] 82 | 301: timer (G) 83 | 302: control (badge: 10) 84 | 303: frame_nic1[0] 85 | 320: io_space_master 86 | 325: nic2 87 | 327: io_pt1 88 | 328: io_ports 89 | 528: x 90 | } 91 | 92 | rm_tcb { 93 | 0: rm_cn 94 | 1: rm_pd 95 | } 96 | 97 | some_pt {37: frame_nic3[0..2]} 98 | 99 | } cdt { 100 | 101 | } irq maps { 102 | 103 | 0: irq_handler[0..2] 104 | 105 | } -------------------------------------------------------------------------------- /capDL-tool/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | TARGET=parse-capDL 8 | 9 | .PHONY: all 10 | all: $(TARGET) 11 | 12 | .PHONY: tests 13 | tests: example-arm.test-OK example-ia32.test-OK example-aarch64.test-OK \ 14 | hello-dump.test-OK cap-dist-elf-simpleserver.test-OK camkes-adder-arm.test-OK \ 15 | camkes-adder-arm.test-thy-OK 16 | 17 | %.parse %.dot %.xml: %.cdl $(TARGET) 18 | stack exec $(TARGET) -- -t $*.parse -x $*.xml -d $*.dot $< || rm -f $*.parse $*.dot $*.xml 19 | 20 | %.test-OK: %.parse %.dot %.xml %.right 21 | @diff -b $*.parse $*.right 22 | @stack exec $(TARGET) -- -t $*.parse.x $*.parse > /dev/null 23 | @diff $*.parse $*.parse.x || (echo "Self parse failed"; exit 1) 24 | which xmllint && xmllint --noout --dtdvalid ./capdl.dtd $*.xml 25 | dot -Tpng $*.dot -o $*.png || true # don't fail the test if graph layout is too hard 26 | echo placeholder for Makefile >$*.test-OK 27 | 28 | camkes-adder-arm.test-thy-OK: $(TARGET) camkes-adder-arm.cdl camkes-adder-arm.thy.right 29 | @stack exec $(TARGET) -- -i camkes-adder-arm.thy --object-sizes=camkes-adder-arm.object_sizes.yaml camkes-adder-arm.cdl 30 | @diff -b camkes-adder-arm.thy camkes-adder-arm.thy.right || (echo "Isabelle output differs"; exit 1) 31 | echo placeholder for Makefile >camkes-adder-arm.test-thy-OK 32 | 33 | # This tells GNU Make that *.parse files should not be considered as intermediate files 34 | # for the *.test-OK targets, so that Make won't delete them. 35 | # We can't use a wildcard here because it's not implemented in Make; see 36 | # https://stackoverflow.com/questions/27090032 37 | .SECONDARY: example-arm.parse example-arm.dot example-arm.xml \ 38 | example-ia32.parse example-ia32.dot example-ia32.xml \ 39 | hello-dump.parse hello-dump.dot hello-dump.xml \ 40 | cap-dist-elf-simpleserver.parse cap-dist-elf-simpleserver.dot cap-dist-elf-simpleserver.xml \ 41 | camkes-adder-arm.parse camkes-adder-arm.dot camkes-adder-arm.xml camkes-adder-arm.thy 42 | 43 | .PHONY: sandbox 44 | sandbox: 45 | stack setup 46 | stack build --only-dependencies 47 | 48 | # `stack install` copies the binary out of the build dir 49 | # --fast compiles with out any optimisations and should be more appropriate 50 | # for current capDL-tool usage behavior. 51 | .PHONY: $(TARGET) 52 | $(TARGET): 53 | stack build --fast 54 | stack install 55 | 56 | .PHONY: install 57 | # Deprecated. This used to be `stack install` but did not install 58 | # to any meaningful PATH location 59 | install: 60 | echo >&2 'capDL-tool/Makefile: install target no longer exists' 61 | false 62 | 63 | .PHONY: clean 64 | clean: 65 | rm -f $(TARGET) 66 | 67 | .PHONY: testclean 68 | testclean: 69 | rm -f *.parse *.parse.x *.dot *.xml *.thy *.png *.out *-OK 70 | -------------------------------------------------------------------------------- /capDL-tool/example-aarch64.cdl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | arch aarch64 8 | 9 | objects { 10 | 11 | rm_ut = ut { 12 | rm_tcb = tcb (init: [10], dom: 5, fault_ep: 0xF) 13 | something = ut (8 bits) { 14 | rm_cn = cnode (10 bits) 15 | } 16 | rm_pd = pgd 17 | rm_ap = asid_pool (asid_high: 0x1) 18 | 19 | linux_pd = pt 20 | 21 | rm_ut_small[50] = ut (12 bits) 22 | rm_ut_big[100] = ut (20 bits) 23 | 24 | frame_nic1[64] = frame (4k) 25 | -- io space?? 26 | 27 | frame_nic2[64] = frame (4k) 28 | -- io space?? 29 | 30 | frame_nic3[4] = frame (4k) 31 | -- io space?? 32 | 33 | timer = notification 34 | control = ep 35 | test[5] = cnode (8 bits) 36 | } 37 | 38 | rm_ut_small[0] = ut { 39 | name_b 40 | } 41 | 42 | rm_ut_small[0]/g = tcb 43 | 44 | irq_handler[3] = irq 45 | nic1_notification = notification 46 | 47 | cnode_booter = cnode (8 bits) 48 | 49 | name_b/name = ut (8 bits) { y[..2], z } 50 | 51 | name_b = ut (10 bits) 52 | name/name2/name3/x = tcb 53 | y[5] = ep 54 | z = ep 55 | 56 | sgi2 = arm_sgi_signal (target: 0, irq: 1) 57 | 58 | } 59 | 60 | caps { 61 | 62 | rm_cn { 63 | 001: rm_tcb 64 | 002: rm_cn (guard: 0, guard_size: 0) 65 | 003: rm_pd (asid: (0x1, 0x1)) 66 | 006: rm_ap 67 | 0x00b: linux_pd; 68 | 0x00c: rm_ut_small[3..5]; 69 | 0x00f: rm_ut_small[7..20, 23, 27..]; 70 | 0x03e: rm_ut_big[]; 71 | 72 | 0x0a3: irq_handler[0]; 73 | 0x0a4: name[] = frame_nic1[]; 74 | 75 | 0x0e5: irq_handler[1]; 76 | 0x0e6: frame_nic2[] (RW, asid: (0x1, 0x1)); 77 | -- 126: iospace 78 | 79 | 0x126: sgi2 80 | 81 | 0x127: irq_handler[2]; 82 | 0x128: frame_nic3[]; 83 | -- 12c: iospace 84 | 85 | 0x12d: timer (G) 86 | 0x12e: control (badge: 10) 87 | 88 | 0x12f: name2 = (masked: R); 89 | 304: test[0] 90 | 305: test[1] 91 | 306: test[1,2] 92 | 308: 93 | 0x200: - child_of name2 94 | 0x201: - child_of (rm_cn, 0x12f) 95 | 0x202: 96 | } 97 | 98 | rm_tcb { 99 | vspace: rm_pd 100 | cspace: rm_cn 101 | } 102 | 103 | cap_name = (rm_tcb, cspace) 104 | cap_name2 = (irq_table, 0) 105 | 106 | cnode_booter { 107 | 001: rm_ut 108 | sched_control (core: 0) 109 | } 110 | 111 | test[2..] { 112 | 001: name3 = name_b 113 | 0x200: rm_cn 114 | } 115 | 116 | test[1] { 117 | 001: name_b 118 | 2: g (reply) 119 | 0x200: rm_cn 120 | } 121 | 122 | cap_test = (test[1],0x200) 123 | 124 | test[0] { 125 | 1: 126 | } 127 | 128 | rm_ap { 129 | 1: rm_pd 130 | } 131 | 132 | } irq maps { 133 | 134 | irq_handler[] 135 | 136 | } cdt { 137 | 138 | (cnode_booter, 1) { 139 | (rm_cn, 0x12d) 140 | } 141 | 142 | cap_test { 143 | (rm_cn, 0x12e) 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /capDL-tool/example-arm.cdl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | arch arm11 8 | 9 | objects { 10 | 11 | rm_ut = ut { 12 | rm_tcb = tcb (init: [10], dom: 5, fault_ep: 0xF) 13 | something = ut (8 bits) { 14 | rm_cn = cnode (10 bits) 15 | } 16 | rm_pd = pd 17 | rm_ap = asid_pool (asid_high: 0x1) 18 | 19 | linux_pd = pd 20 | 21 | rm_ut_small[50] = ut (12 bits) 22 | rm_ut_big[100] = ut (20 bits) 23 | 24 | frame_nic1[64] = frame (4k) 25 | -- io space?? 26 | 27 | frame_nic2[64] = frame (4k) 28 | -- io space?? 29 | 30 | frame_nic3[4] = frame (4k) 31 | -- io space?? 32 | 33 | timer = notification 34 | control = ep 35 | test[5] = cnode (8 bits) 36 | } 37 | rm_ut_small[0] = ut { 38 | name_b 39 | } 40 | rm_ut_small[0]/g = tcb 41 | 42 | irq_handler[3] = irq 43 | nic1_notification = notification 44 | 45 | cnode_booter = cnode (8 bits) 46 | 47 | name_b/name = ut (8 bits) { y[..2], z, a, b } 48 | 49 | name_b = ut (10 bits) 50 | name/name2/name3/x = tcb 51 | name/a = tcb 52 | name/b = tcb 53 | y[5] = ep 54 | z = ep 55 | 56 | sgi1 = arm_sgi_signal(irq: 10, target: 2) 57 | 58 | } caps { 59 | 60 | rm_cn { 61 | 001: rm_tcb 62 | 002: rm_cn (guard: 0, guard_size: 0) 63 | 003: rm_pd (asid: (0x1, 0x1)) 64 | 006: rm_ap 65 | 0x00b: linux_pd; 66 | 0x00c: rm_ut_small[3..5]; 67 | 0x00f: rm_ut_small[7..20, 23, 27..]; 68 | 0x03e: rm_ut_big[]; 69 | 70 | 0x0a3: irq_handler[0]; 71 | 0x0a4: name[] = frame_nic1[]; 72 | 73 | 0x0e5: irq_handler[1]; 74 | 0x0e6: frame_nic2[] (RW, asid: (0x1, 0x1)); 75 | -- 126: iospace 76 | 77 | 0x126: sgi1; 78 | 79 | 0x127: irq_handler[2]; 80 | 0x128: frame_nic3[]; 81 | -- 12c: iospace 82 | 83 | 0x12d: timer (G) 84 | 0x12e: control (badge: 10) 85 | 86 | 0x12f: name2 = (masked: R); 87 | 304: test[0] 88 | 305: test[1] 89 | 306: test[1,2] 90 | 308: 91 | 0x200: - child_of name2 92 | 0x201: - child_of (rm_cn, 0x12f) 93 | 0x202: 94 | } 95 | 96 | rm_tcb { 97 | vspace: rm_pd 98 | cspace: rm_cn 99 | } 100 | 101 | cap_name = (rm_tcb, cspace) 102 | cap_name2 = (irq_table, 0) 103 | 104 | cnode_booter { 105 | 001: rm_ut 106 | sched_control (core: 0) 107 | } 108 | 109 | test[2..] { 110 | 001: name3 = name_b 111 | 0x200: rm_cn 112 | } 113 | 114 | test[1] { 115 | 001: name_b 116 | 2: g (reply) 117 | 0x200: rm_cn 118 | } 119 | 120 | cap_test = (test[1],0x200) 121 | 122 | test[0] { 123 | 1: 124 | } 125 | 126 | rm_ap { 127 | 1: rm_pd 128 | } 129 | 130 | } irq maps { 131 | 132 | irq_handler[] 133 | 134 | } cdt { 135 | 136 | (cnode_booter, 1) { 137 | (rm_cn, 0x12d) 138 | } 139 | 140 | cap_test { 141 | (rm_cn, 0x12e) 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /capDL-tool/example-ia32.cdl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | arch ia32 8 | 9 | objects { 10 | 11 | rm_ut = ut { 12 | rm_tcb = tcb 13 | name2 = ut (8 bits) { 14 | rm_cn = cnode (10 bits) 15 | } 16 | rm_pd = pd 17 | rm_ap = asid_pool (asid_high: 0x0) 18 | 19 | linux_pd = pd 20 | 21 | rm_ut_small[50] = ut (12 bits) 22 | rm_ut_big[100] = ut (20 bits) 23 | 24 | frame_nic1[64] = frame (4k) 25 | nic1 = io_device (domainID: 0, 0:0.0) 26 | 27 | frame_nic2[64] = frame (4k) 28 | nic2 = io_device (domainID: 0, 0:0.0) 29 | 30 | frame_nic3[4] = frame (4k) 31 | nic3 = io_device (0xf:10.3, domainID: 50) 32 | 33 | timer = notification 34 | control = ep 35 | 36 | io_pt1 = io_pt (level: 1) 37 | io_pt2 = io_pt (level: 2) 38 | io_pt3 = io_pt (level: 3) 39 | } 40 | 41 | some_pt = pt 42 | frame_name = frame (4k) 43 | 44 | io_ports = io_ports (ports:[0x1000..45894]) 45 | 46 | irq_handler[3] = irq 47 | 48 | nic1_notification = notification 49 | 50 | iospace = io_device (0xf:10.3, domainID: 50) 51 | 52 | cnode_booter = cnode (8 bits) 53 | 54 | name = ut (8 bits) { y, z } 55 | 56 | name_b = ut (10 bits) 57 | name/name3/x = tcb 58 | name/a = tcb 59 | name/b = tcb 60 | 61 | y = ep 62 | z = ep 63 | 64 | } caps { 65 | 66 | rm_cn { 67 | 001: rm_tcb 68 | 002: rm_cn ( guard: 0, guard_size: 0) 69 | 003: rm_pd 70 | 006: rm_ap 71 | 007: io_ports 72 | 0x00b: linux_pd; 73 | 0x00c: rm_ut_small[3..5]; 74 | 0x00f: rm_ut_small[7..20, 23, 27..]; 75 | 0x03e: rm_ut_big[]; 76 | 77 | 0x0a3: irq_handler[0]; 78 | 0x0a4: name[] = frame_nic1[]; 79 | 0x0e4: iospace; 80 | 81 | 0x0e5: irq_handler[1]; 82 | 0x0e6: frame_nic2[]; 83 | -- 126: iospace 84 | 85 | 0x127: irq_handler[2]; 86 | 0x128: frame_nic3[]; 87 | -- 12c: iospace 88 | 89 | 0x12d: timer (G) 90 | 0x12e: control (badge: 10) 91 | 92 | 0x140: io_space_master 93 | 94 | 0x145: nic2 95 | 96 | 0x147: io_pt1 97 | 98 | 0x148: io_ports 99 | 100 | 0x210: x 101 | 102 | 0x12f: name2[] = (masked: R); 103 | } 104 | 105 | rm_tcb { 106 | vspace: rm_pd 107 | cspace: rm_cn 108 | } 109 | 110 | cap_name = (rm_tcb, cspace) 111 | cap_name2 = (irq_table, 0) 112 | 113 | cnode_booter { 114 | 001: rm_ut 115 | } 116 | 117 | -- some pd and pt mappings: 118 | 119 | linux_pd { 120 | 10: frame_name 121 | 0xFF: some_pt 122 | 0x100: frame_nic1[..030] 123 | 0x130: frame_nic1[31..] 124 | 0x160: frame_nic2[10] 125 | 0x180: frame_nic2[11..17, ..2, 10, 10..] 126 | } 127 | 128 | some_pt { 129 | 37: frame_nic3[..2] 130 | } 131 | 132 | nic1 { 0: io_pt1 } 133 | 134 | io_pt1 { 0: io_pt2 } 135 | io_pt2 { 0: io_pt3 } 136 | io_pt3 { 0: frame_nic3[0] } 137 | 138 | } irq maps { 139 | irq_handler[] 140 | } 141 | 142 | /* not supported yet 143 | CDT: { 144 | rm_ut parent_of timer 145 | } 146 | */ 147 | -------------------------------------------------------------------------------- /capDL-tool/CapDL/Parser.hs: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | -- 4 | -- SPDX-License-Identifier: BSD-2-Clause 5 | -- 6 | 7 | {-# OPTIONS_GHC -fno-warn-unused-do-bind #-} 8 | 9 | module CapDL.Parser where 10 | 11 | import Prelude () 12 | import Prelude.Compat 13 | import CapDL.AST 14 | import CapDL.ParserUtils 15 | 16 | import Text.ParserCombinators.Parsec 17 | 18 | obj_decl_or_ref :: MapParser (Either KODecl NameRef) 19 | obj_decl_or_ref = 20 | (try $ do 21 | d <- obj_decl 22 | comma <|> return "" 23 | return $ Left d) 24 | <|> (do n <- name_ref 25 | comma <|> return "" 26 | return $ Right n) 27 | 28 | opt_obj_decls :: MapParser [Either KODecl NameRef] 29 | opt_obj_decls = braces (many obj_decl_or_ref) <|> return [] 30 | 31 | object :: MapParser KO 32 | object = do 33 | typ <- object_type 34 | params <- object_params 35 | decls <- opt_obj_decls 36 | return (Obj typ params decls) 37 | 38 | obj_decl :: MapParser KODecl 39 | obj_decl = do 40 | qname <- qname 41 | symbol "=" 42 | obj <- CapDL.Parser.object 43 | return (KODecl qname obj) 44 | 45 | obj_decls :: MapParser [Decl] 46 | obj_decls = do 47 | reserved "objects" 48 | decls <- braces $ many obj_decl 49 | return $ map ObjDecl decls 50 | 51 | cap_mapping :: Maybe Word -> Maybe NameRef -> MapParser CapMapping 52 | cap_mapping sl nm = do 53 | obj <- name_ref 54 | params <- cap_params 55 | parent <- maybe_parent 56 | return $ CapMapping sl nm obj params parent 57 | 58 | cap_name_ref :: Maybe Word -> Maybe NameRef -> MapParser CapMapping 59 | cap_name_ref sl nm = do 60 | symbol "<" 61 | name <- name_ref 62 | symbol ">" 63 | params <- cap_params 64 | parent <- maybe_parent 65 | return $ CopyOf sl nm name params parent 66 | 67 | maybe_name :: MapParser (Maybe NameRef) 68 | maybe_name = 69 | optionMaybe $ try $ do 70 | n <- name_ref 71 | symbol "=" 72 | return n 73 | 74 | cap_mapping_or_ref :: MapParser CapMapping 75 | cap_mapping_or_ref = do 76 | sl <- maybe_slot 77 | nm <- maybe_name 78 | cap_mapping sl nm <|> cap_name_ref sl nm 79 | 80 | cap_decl :: MapParser Decl 81 | cap_decl = do 82 | n <- name_ref 83 | ms <- braces (sepEndBy cap_mapping_or_ref opt_semi) 84 | return $ CapDecl n ms 85 | 86 | cap_name_decl :: MapParser Decl 87 | cap_name_decl = do 88 | n <- name 89 | symbol "=" 90 | symbol "(" 91 | ref <- name_ref 92 | symbol "," 93 | slot <- parse_slot 94 | symbol ")" 95 | return $ CapNameDecl n ref slot 96 | 97 | cap_decls :: MapParser [Decl] 98 | cap_decls = do 99 | reserved "caps" 100 | braces $ many (try cap_name_decl <|> try cap_decl) 101 | 102 | decl_section :: MapParser [Decl] 103 | decl_section = 104 | obj_decls <|> cap_decls <|> irq_decls <|> cdt_decls 105 | 106 | capDLModule :: MapParser Module 107 | capDLModule = do 108 | whiteSpace 109 | arch <- parse_arch 110 | decls <- many1 decl_section 111 | eof 112 | return (Module arch (concat decls)) 113 | -------------------------------------------------------------------------------- /capdl-loader-app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.16.0) 8 | 9 | set(configure_string "") 10 | 11 | config_choice( 12 | CapDLLoaderCallingConvention 13 | CAPDL_LOADER_CALLING_CONVENTION 14 | "Select the calling convention that loaded processes are expecting. If 15 | you select the register convention you will be limited to passing four 16 | arguments to processes and their stack frames will not need to be 17 | mapped in during thread configuration." 18 | "standard;CapDLLoaderCallingConventionStandard;CAPDL_LOADER_CC_STANDARD" 19 | "registers;CapDLLoaderCallingConventionRegisters;CAPDL_LOADER_CC_REGISTERS" 20 | ) 21 | 22 | config_string( 23 | CapDLLoaderMaxObjects 24 | CAPDL_LOADER_MAX_OBJECTS 25 | "Maximum number of objects that can be handled by the loader. Note that 26 | there is an upper limit on this based on the size of the initialiser's 27 | CNode." 28 | DEFAULT 29 | 4096 30 | UNQUOTE 31 | ) 32 | 33 | config_string( 34 | CapDLLoaderFillsPerFrame CAPDL_LOADER_FILLS_PER_FRAME 35 | "Maximum number of fill commands per frame." DEFAULT 1 UNQUOTE 36 | ) 37 | 38 | config_option( 39 | CapDLLoaderWriteablePages 40 | CAPDL_LOADER_WRITEABLE_PAGES 41 | "CapDL Loader will map all pages as writeable if the cap has grant permissions. 42 | This is currently used to enable instruction and data rewriting by an external debugger such as GDB." 43 | DEFAULT 44 | OFF 45 | ) 46 | 47 | config_option( 48 | CapDLLoaderPrintDeviceInfo 49 | CAPDL_LOADER_PRINT_DEVICE_INFO 50 | "Dump device frame information on startup for the purposes of debugging." 51 | DEFAULT 52 | OFF 53 | DEPENDS 54 | "NOT CapDLLoaderVerified" 55 | ) 56 | 57 | config_option( 58 | CapDLLoaderPrintUntypeds 59 | CAPDL_LOADER_PRINT_UNTYPEDS 60 | "Dump untyped object information on startup for the purposes of debugging." 61 | DEFAULT 62 | OFF 63 | DEPENDS 64 | "NOT CapDLLoaderVerified" 65 | ) 66 | 67 | config_option( 68 | CapDLLoaderPrintCapDLObjects 69 | CAPDL_LOAD_PRINT_CAPDL_OBJECTS 70 | "Display verbose capDL objects as they are created. Could help with debugging, 71 | but for large specs with lots of objects, this could slow things down significantly." 72 | DEFAULT 73 | OFF 74 | DEPENDS 75 | "NOT CapDLLoaderVerified" 76 | ) 77 | 78 | config_option( 79 | CapDLLoaderStaticAlloc CAPDL_LOADER_STATIC_ALLOC 80 | "Build the loader to expect a statically allocated capDL spec." DEFAULT OFF 81 | ) 82 | 83 | add_config_library(capdl_loader_app "${configure_string}") 84 | 85 | # The capdl-loader-app requires outside configuration in order to build. To achieve this 86 | # we just declare a target here with custom properties for describing the source and headers. 87 | # This is done here as at this point we know the source directory and can construct these things. 88 | # Later on the user will construct a rule for actually generating the capdl executable from a 89 | # different project directory 90 | add_custom_target(capdl_app_properties) 91 | set_property(TARGET capdl_app_properties PROPERTY C_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/main.c") 92 | set_property( 93 | TARGET capdl_app_properties PROPERTY INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include" 94 | ) 95 | 96 | RequireFile(CAPDL_LOADER_BUILD_HELPERS helpers.cmake) 97 | -------------------------------------------------------------------------------- /capDL-tool/capDL-tool.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | set(CapDLToolDirectory ${CMAKE_CURRENT_LIST_DIR}) 8 | 9 | include(make) 10 | include(debug) 11 | # Build and install capDL-tool 12 | # Path of installed tool will be returned in program_path 13 | # This assumes that there are no other dependencies. 14 | function(CapDLToolInstall target program_path) 15 | # Require the parse-capDL tool 16 | create_depfile_by_find( 17 | depfile_commands "${CMAKE_CURRENT_BINARY_DIR}/capDL-tool/parse-capDL" 18 | "${CMAKE_CURRENT_BINARY_DIR}/capDL-tool/parse-capDL.d" "${CapDLToolDirectory}/" 19 | ) 20 | 21 | include(memoize) 22 | # memoize this installation rule which will save the resulting artifact in a cache and reuse it across builds. 23 | # This will rebuild from source if the git directory has changes or has a changed commit hash. 24 | memoize_add_custom_command( 25 | capDL-tool 26 | "${CMAKE_CURRENT_BINARY_DIR}/capDL-tool/" 27 | "${CapDLToolDirectory}" 28 | "" 29 | "parse-capDL" 30 | OUTPUT 31 | "${CMAKE_CURRENT_BINARY_DIR}/capDL-tool/parse-capDL" 32 | WORKING_DIRECTORY 33 | ${CMAKE_CURRENT_BINARY_DIR}/capDL-tool/ 34 | ${depfile_commands} 35 | COMMAND 36 | cp 37 | -a 38 | ${CapDLToolDirectory}/* 39 | . 40 | COMMAND 41 | ${CMAKE_COMMAND} 42 | -E 43 | env 44 | make 45 | ${USES_TERMINAL_DEBUG} 46 | ) 47 | add_custom_target(${target} DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/capDL-tool/parse-capDL") 48 | set(${program_path} 49 | "${CMAKE_CURRENT_BINARY_DIR}/capDL-tool/parse-capDL" 50 | PARENT_SCOPE 51 | ) 52 | endfunction() 53 | 54 | # Create target for creating capdl C file from cdl spec 55 | # target: Name of target to Create 56 | # output: Output name of C file 57 | # static_alloc: whether the spec has been statically allocated 58 | # object_sizes: object_sizes file 59 | # input: Input name of capdl spec 60 | # capdl_tool: Path to capdl parse tool 61 | # MAX_IRQS: Named argument for size of IRQ array (Deprecated) 62 | # DEPENDS: Any target or file dependencies that the parse command depends on 63 | function( 64 | CapDLToolCFileGen 65 | target 66 | output 67 | static_alloc 68 | object_sizes 69 | input 70 | capdl_tool 71 | ) 72 | cmake_parse_arguments(PARSE_ARGV 6 CAPDL "" "MAX_IRQS" "DEPENDS") 73 | if(NOT "${CAPDL_UNPARSED_ARGUMENTS}" STREQUAL "") 74 | message(FATAL_ERROR "Unknown arguments to CapDLToolCFileGen") 75 | endif() 76 | if(static_alloc) 77 | set(alloc_type_opt "--code-static-alloc") 78 | set(object_sizes_opt "") 79 | else() 80 | set(alloc_type_opt "--code-dynamic-alloc") 81 | set(object_sizes_opt "--object-sizes=${object_sizes}") 82 | endif() 83 | if(NOT "${CAPDL_MAX_IRQS}" STREQUAL "") 84 | message(WARNING "MAX_IRQS option to CapDLToolCFileGen is no longer used by the tool") 85 | endif() 86 | # Invoke the parse-capDL tool to turn the CDL spec into a C spec 87 | add_custom_command( 88 | OUTPUT ${output} 89 | COMMAND ${capdl_tool} --code ${output} ${alloc_type_opt} ${object_sizes_opt} "${input}" 90 | DEPENDS "${input}" "${object_sizes}" ${CAPDL_DEPENDS} 91 | ) 92 | add_custom_target(${target} DEPENDS ${output} ${object_sizes}) 93 | endfunction() 94 | -------------------------------------------------------------------------------- /capdl-loader-app/helpers.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | cmake_minimum_required(VERSION 3.16.0) 8 | 9 | function(BuildCapDLApplication) 10 | cmake_parse_arguments(PARSE_ARGV 0 CAPDL_BUILD_APP "" "C_SPEC;OUTPUT" "ELF;DEPENDS") 11 | if(NOT "${CAPDL_BUILD_APP_UNPARSED_ARGUMENTS}" STREQUAL "") 12 | message(FATAL_ERROR "Unknown arguments to BuildCapDLApplication") 13 | endif() 14 | # Require a cspec and an output 15 | if("${CAPDL_BUILD_APP_C_SPEC}" STREQUAL "") 16 | message(FATAL_ERROR "C_SPEC is required argument to BuildCapDLApplication") 17 | endif() 18 | if("${CAPDL_BUILD_APP_OUTPUT}" STREQUAL "") 19 | message(FATAL_ERROR "OUTPUT is required argument to BuildCapDLApplication") 20 | endif() 21 | # Build a CPIO archive out of the provided ELF files 22 | include(cpio) 23 | MakeCPIO(${CAPDL_BUILD_APP_OUTPUT}_archive.o "${CAPDL_BUILD_APP_ELF}" CPIO_SYMBOL 24 | _capdl_archive 25 | ) 26 | 27 | if(DEFINED platform_yaml) 28 | 29 | find_file( 30 | PLATFORM_SIFT platform_sift.py 31 | PATHS ${CMAKE_MODULE_PATH} 32 | NO_CMAKE_FIND_ROOT_PATH 33 | ) 34 | mark_as_advanced(FORCE PLATFORM_SIFT) 35 | if("${PLATFORM_SIFT}" STREQUAL "PLATFORM_SIFT-NOTFOUND") 36 | message( 37 | FATAL_ERROR 38 | "Failed to find platform_sift.py. Consider using -DPLATFORM_SIFT=/path/to/file" 39 | ) 40 | endif() 41 | 42 | set(MEMORY_REGIONS 43 | "${CMAKE_BINARY_DIR}/capdl/capdl-loader-app/gen_config/capdl_loader_app/platform_info.h" 44 | ) 45 | add_custom_command( 46 | COMMAND ${PLATFORM_SIFT} --emit-c-syntax ${platform_yaml} > ${MEMORY_REGIONS} 47 | OUTPUT ${MEMORY_REGIONS} 48 | ) 49 | add_custom_target(mem_regions DEPENDS ${platform_yaml} ${PLATFORM_SIFT} ${MEMORY_REGIONS}) 50 | set_property( 51 | SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/capdl/capdl-loader-app/src/main.c 52 | PROPERTY OBJECT_DEPENDS mem_regions 53 | ) 54 | endif() 55 | 56 | # Build the application 57 | add_executable( 58 | "${CAPDL_BUILD_APP_OUTPUT}" EXCLUDE_FROM_ALL 59 | $ ${CAPDL_LOADER_APP_C_FILES} 60 | ${CAPDL_BUILD_APP_OUTPUT}_archive.o ${CAPDL_BUILD_APP_C_SPEC} 61 | ) 62 | 63 | if(DEFINED platform_yaml) 64 | add_dependencies("${CAPDL_BUILD_APP_OUTPUT}" mem_regions) 65 | endif() 66 | 67 | add_dependencies("${CAPDL_BUILD_APP_OUTPUT}" ${CAPDL_BUILD_APP_DEPENDS}) 68 | target_include_directories( 69 | "${CAPDL_BUILD_APP_OUTPUT}" PRIVATE $ 70 | ) 71 | target_link_libraries( 72 | "${CAPDL_BUILD_APP_OUTPUT}" 73 | sel4runtime 74 | sel4 75 | cpio 76 | sel4platsupport 77 | sel4utils 78 | capdl_loader_app_Config 79 | sel4_autoconf 80 | ) 81 | if(KernelDebugBuild) 82 | target_link_libraries("${CAPDL_BUILD_APP_OUTPUT}" sel4muslcsys) 83 | endif() 84 | endfunction(BuildCapDLApplication) 85 | 86 | # Hook for CAmkES build system. This allows CAmkES projects to 87 | # propagate the capDL allocation setting into the loader. 88 | function(SetCapDLLoaderStaticAlloc) 89 | set(CapDLLoaderStaticAlloc 90 | ON 91 | CACHE BOOL "" FORCE 92 | ) 93 | endfunction() 94 | -------------------------------------------------------------------------------- /capDL-tool/CapDL/Matrix.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleContexts #-} 2 | -- 3 | -- Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 4 | -- 5 | -- SPDX-License-Identifier: BSD-2-Clause 6 | -- 7 | 8 | module CapDL.Matrix( 9 | Matrix 10 | ,isConnected 11 | ,connect 12 | ,newEmptyMatrix 13 | ,printMatrix 14 | ,printDotMatrix 15 | ,showDotMatrix 16 | ,getSize 17 | ,disconnect 18 | ) where 19 | 20 | import Data.Array.IO 21 | 22 | import Prelude () 23 | import Prelude.Compat 24 | import Data.Map (Map) 25 | import qualified Data.Map as Map 26 | 27 | import Control.Monad 28 | 29 | import Data.Char 30 | 31 | newtype Matrix = Matrix (IOUArray (Int,Int) Bool) 32 | 33 | {- This function takes a matrix and prints a literal table representation 34 | with 0 for False and 1 for True, should be for debugging only -} 35 | printMatrix :: Matrix -> IO() 36 | printMatrix (Matrix m) = 37 | do ((minx, miny), (maxx, maxy)) <- getBounds m 38 | forM_ [minx .. maxx] $ \i -> 39 | forM_ [miny .. maxy] $ \j -> 40 | do elt <- readArray m (i,j) 41 | putStr $ (if elt then "1" else "0") 42 | ++ if j == maxy then "\n" else " " 43 | 44 | {- This function takes a matrix and a map of labels for 45 | the nodes being represented by the matrix and prints 46 | a .dot file representation of the graph. 47 | 48 | This is hacky and only works for the specific 'names' used 49 | in the -} 50 | 51 | printDotMatrix :: Matrix -> Map Int (String, Maybe Word) -> IO () 52 | printDotMatrix (Matrix m) nameMap = 53 | do putStrLn "digraph {" 54 | ((min, _), (_, max)) <- getBounds m 55 | forM_ [min .. max] $ \i -> 56 | do let iobjID = Map.findWithDefault (e i) i nameMap 57 | putStrLn $ cf $ fst iobjID 58 | forM_ [i .. max] $ \j -> 59 | do outb <- readArray m (i,j) 60 | inb <- readArray m (j,i) 61 | let iname = fst (iobjID) ++ maybe "" show (snd (iobjID)) 62 | jobjID = Map.findWithDefault (e j) j nameMap 63 | jname = fst (jobjID) ++ maybe "" show (snd (jobjID)) 64 | case (inb,outb) of 65 | (False, False) -> return () 66 | (False, True) -> putStrLn $ cf iname ++ " -> " ++ cf jname ++ ";" 67 | (True, False) -> putStrLn $ cf jname ++ " -> " ++ cf iname ++ ";" 68 | (True, True) -> putStrLn $ cf iname ++ " -> " ++ cf jname ++ "[dir=both];" 69 | putStrLn "}" 70 | where 71 | e x = error ("Can't find name for object " ++ show x) 72 | cf = filter (\c -> isDigit c || isAlpha c) 73 | 74 | showDotMatrix :: Matrix -> Map Int (String, Maybe Word) -> IO String 75 | showDotMatrix (Matrix m) nameMap = 76 | do 77 | ((min, _), (_, max)) <- getBounds m 78 | rows <- forM [min .. max] $ \i -> 79 | do let iobjID = Map.findWithDefault (e i) i nameMap 80 | cells <- forM [i .. max] $ \j -> 81 | do outb <- readArray m (i,j) 82 | inb <- readArray m (j,i) 83 | let iname = fst (iobjID) ++ maybe "" show (snd (iobjID)) 84 | jobjID = Map.findWithDefault (e j) j nameMap 85 | jname = fst (jobjID) ++ maybe "" show (snd (jobjID)) 86 | return $ case (inb,outb) of 87 | (False, False) -> "" 88 | (False, True) -> cf iname ++ " -> " ++ cf jname ++ ";\n" 89 | (True, False) -> cf jname ++ " -> " ++ cf iname ++ ";\n" 90 | (True, True) -> cf iname ++ " -> " ++ cf jname ++ "[dir=both];\n" 91 | return $ (cf (fst iobjID)) ++ "\n" ++ (concat cells) 92 | return $ "digraph {\n" ++ (concat rows) ++ "}\n" 93 | where 94 | e x = error ("Can't find name for object " ++ show x) 95 | cf = filter (\c -> isDigit c || isAlpha c) 96 | 97 | isConnected :: Matrix -> Int -> Int -> IO Bool 98 | isConnected (Matrix m) x y = readArray m (x,y) 99 | 100 | {- Sets (x,y) to True -} 101 | connect :: Matrix -> Int -> Int -> IO () 102 | connect (Matrix m) x y = writeArray m (x,y) True 103 | 104 | {- Sets (x,y) to False -} 105 | disconnect :: Matrix -> Int -> Int -> IO () 106 | disconnect (Matrix m) x y = writeArray m (x,y) False 107 | 108 | {- Returns a new empty matrix -} 109 | newEmptyMatrix :: Int -> IO Matrix 110 | newEmptyMatrix n = liftM Matrix $ newArray ((0,0),(n-1,n-1)) False 111 | 112 | {- Returns the dimensions of the matrix -} 113 | getSize (Matrix m) = getBounds m 114 | -------------------------------------------------------------------------------- /python-capdl-tool/capdl/Cap.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | from __future__ import absolute_import, division, print_function, \ 8 | unicode_literals 9 | 10 | from capdl.Object import Object, Frame, CNode, Endpoint, Notification, \ 11 | SchedControl, SMC 12 | 13 | 14 | class Cap(object): 15 | """ 16 | A capability to a kernel object. 17 | """ 18 | 19 | def __init__(self, referent, **kwargs): 20 | assert isinstance(referent, Object) 21 | self.referent = referent 22 | self.read = False 23 | self.write = False 24 | self.grant = False 25 | self.grantreply = False 26 | self.guard = 0 27 | self.guard_size = 0 28 | self.badge = None 29 | self.cached = True 30 | self.ports = None 31 | self.mapping_container = None 32 | self.mapping_slot = None 33 | self.mapping_deferred = False 34 | for (k, v) in kwargs.items(): 35 | if hasattr(self, k): 36 | setattr(self, k, v) 37 | 38 | def set_guard(self, guard): 39 | assert isinstance(self.referent, CNode) 40 | assert isinstance(guard, int) 41 | assert guard % 2**18 == guard, 'guards can be a maximum of 18 bits' 42 | self.guard = guard 43 | 44 | def set_guard_size(self, guard_size): 45 | assert isinstance(self.referent, CNode) 46 | assert isinstance(guard_size, int) 47 | self.guard_size = guard_size 48 | 49 | def set_badge(self, badge): 50 | # Only endpoint caps can be badged. 51 | assert isinstance(self.referent, Endpoint) or \ 52 | isinstance(self.referent, Notification) or \ 53 | isinstance(self.referent, SMC) 54 | assert badge % 2**28 == badge, 'badges can be a maximum of 28 bits' 55 | self.badge = badge 56 | 57 | def set_cached(self, cached): 58 | assert isinstance(self.referent, Frame) 59 | self.cached = cached 60 | 61 | def set_mapping(self, container, slot): 62 | """ 63 | @brief For a frame cap in a cspace, ensure that this is the 64 | cap used for a mapping into a mapping object specified by 65 | container and slot. 66 | 67 | @param self A frame cap that is inside a CNode. 68 | @param container The mapping object the frame is mapped into. 69 | @param slot The index of the mapping object 70 | """ 71 | assert isinstance(self.referent, Frame) 72 | self.mapping_container = container 73 | self.mapping_slot = slot 74 | 75 | def set_mapping_deferred(self): 76 | """ 77 | @brief Indicate that this cap is a mapping cap, but the container 78 | and slot values are to be set later. 79 | """ 80 | assert isinstance(self.referent, Frame) 81 | self.mapping_deferred = True 82 | 83 | def __repr__(self): 84 | extra = [] 85 | 86 | if isinstance(self.referent, SchedControl): 87 | return "sched_control (core: %d)" % self.referent.core 88 | 89 | if isinstance(self.referent, 90 | (Frame, Endpoint, Notification, SMC)): 91 | is_frame = isinstance(self.referent, Frame) 92 | rights = [sym for sym, flag in 93 | [('R', self.read), 94 | ('W', self.write), 95 | ('X', is_frame and self.grant), 96 | ('G', not is_frame and self.grant), 97 | ('P', self.grantreply)] 98 | if flag] 99 | extra.append(''.join(rights)) 100 | 101 | if isinstance(self.referent, Frame) and not self.cached: 102 | extra.append('uncached') 103 | if isinstance(self.referent, Frame) and \ 104 | self.mapping_container is not None: 105 | extra.append('mapping: (%s, %d)' % (self.mapping_container.name, self.mapping_slot)) 106 | if isinstance(self.referent, (Endpoint, Notification, SMC)) and \ 107 | self.badge is not None: 108 | extra.append('badge: %d' % self.badge) 109 | if isinstance(self.referent, CNode): 110 | extra.append('guard: %s' % self.guard) 111 | extra.append('guard_size: %s' % self.guard_size) 112 | 113 | extra = [x for x in extra if x != ''] 114 | 115 | return '%s%s' % (self.referent.name, 116 | (' (%s)' % ', '.join(extra)) if extra else '') 117 | -------------------------------------------------------------------------------- /capDL-tool/CapDL/AST.hs: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | -- 4 | -- SPDX-License-Identifier: BSD-2-Clause 5 | -- 6 | 7 | {-# LANGUAGE DeriveDataTypeable #-} 8 | module CapDL.AST where 9 | 10 | import CapDL.Model 11 | 12 | import Prelude () 13 | import Prelude.Compat 14 | import Data.Data 15 | import Data.Word 16 | 17 | -- AST 18 | 19 | type Name = String 20 | type QName = [NameRef] 21 | 22 | data Range = Only Word 23 | | FromTo Word Word 24 | | From Word 25 | | To Word 26 | | All 27 | deriving (Show, Eq, Ord, Typeable, Data) 28 | 29 | type NameRef = (Name, [Range]) 30 | 31 | data TCBExtraParam = 32 | Addr { 33 | addr :: Word } 34 | | IP { 35 | ip :: Word } 36 | | SP { 37 | sp :: Word } 38 | | Prio { 39 | prio :: Integer } 40 | | MaxPrio { 41 | max_prio :: Integer } 42 | | Affinity { 43 | affinity :: Integer } 44 | | Resume { 45 | resume :: Bool } 46 | | FPUDisabled { 47 | fpuDisabled :: Bool } 48 | deriving (Show, Eq, Ord, Typeable, Data) 49 | 50 | data FrameExtraParam = 51 | Fill { fill :: [[String]] } 52 | deriving (Show, Eq, Ord, Typeable, Data) 53 | 54 | data SCExtraParam = 55 | Period { 56 | period :: Word64 } 57 | | Budget { 58 | budget :: Word64 } 59 | | SCData { 60 | scData :: Word } 61 | deriving (Show, Eq, Ord, Typeable, Data) 62 | 63 | data CBExtraParam = 64 | CBNumber { 65 | cbNumber :: Word } 66 | deriving (Eq, Show, Ord, Typeable, Data) 67 | 68 | data IOAPICIRQExtraParam = 69 | IOAPIC { 70 | ioapic :: Word } 71 | | Pin { 72 | pin :: Word } 73 | | Level { 74 | ioapic_level :: Word } 75 | | Polarity { 76 | polarity :: Word } 77 | deriving (Show, Eq, Ord, Typeable, Data) 78 | 79 | data MSIIRQExtraParam = 80 | MSIHandle { 81 | handle :: Word } 82 | | MSIPCIBus { 83 | bus :: Word } 84 | | MSIPCIDev { 85 | dev :: Word } 86 | | MSIPCIFun { 87 | fun :: Word } 88 | deriving (Show, Eq, Ord, Typeable, Data) 89 | 90 | data ARMIRQExtraParam = 91 | ARMIRQTrigger { 92 | trigger :: Word } 93 | | ARMIRQTarget { 94 | target_core :: Word } 95 | deriving (Show, Eq, Ord, Typeable, Data) 96 | 97 | data ObjParam = 98 | BitSize { 99 | bits :: Word } 100 | | VMSize { 101 | vmSize :: Word } 102 | | IOPTLevel { 103 | level :: Word } 104 | | Paddr { 105 | paddr :: Word } 106 | | TCBExtraParam { 107 | extraParam :: TCBExtraParam } 108 | | FrameExtraParam { 109 | frameExtraParam :: FrameExtraParam} 110 | | SCExtraParam { 111 | sc_extraParam :: SCExtraParam } 112 | | CBExtraParam { 113 | cb_extraParam :: CBExtraParam } 114 | | IOAPICIRQExtraParam { 115 | ioapic_irq_extraParam :: IOAPICIRQExtraParam } 116 | | MSIIRQExtraParam { 117 | msi_irq_extraParam :: MSIIRQExtraParam } 118 | | ARMIRQExtraParam { 119 | arm_irq_extraParam :: ARMIRQExtraParam } 120 | | ARMSGISignalIrq { 121 | sgi_irq :: Word } 122 | | InitArguments { 123 | arguments :: [Word] } 124 | | DomainID { 125 | domainID :: Word } 126 | | ARMIOSpace { 127 | armiospace :: Word } 128 | | PCIDevice { 129 | pciDevice :: (Word, Word, Word) } 130 | | Dom { 131 | dom :: Integer } 132 | | FaultEP { 133 | faulEP :: Word } 134 | | Ports { 135 | theRange :: (Word, Word) } 136 | | AsidHigh { 137 | asidHigh :: Word } 138 | deriving (Show, Eq, Ord, Typeable, Data) 139 | 140 | data KO = Obj { 141 | koType :: KOType, 142 | params :: [ObjParam], 143 | objDecls :: [Either KODecl NameRef] 144 | } deriving (Show, Eq) 145 | 146 | -- obj and slot or declared name 147 | type SlotRef = Either (NameRef, Word) NameRef 148 | 149 | data CapParam 150 | = Rights { 151 | rights :: CapRights } 152 | | Masked { 153 | rights :: CapRights } 154 | | Guard { 155 | guard :: Word } 156 | | GuardSize { 157 | guardSize :: Word } 158 | | IRQRef 159 | | Badge { 160 | theBadge :: Word } 161 | | Core { 162 | theCore :: Word } 163 | | Reply 164 | | MasterReply 165 | | Asid { 166 | asid :: Asid } 167 | | Cached { 168 | cached :: Bool } 169 | | FrameMapping { 170 | container :: NameRef, 171 | slotIndex :: Word } 172 | deriving (Show, Eq, Ord, Typeable, Data) 173 | 174 | data CapMapping 175 | = CapMapping { 176 | slot :: Maybe Word, 177 | capName :: Maybe NameRef, 178 | objRef :: NameRef, 179 | capParams :: [CapParam], 180 | maybeParent :: Maybe SlotRef 181 | } 182 | | CopyOf { 183 | slot :: Maybe Word, 184 | capName :: Maybe NameRef, 185 | target :: NameRef, 186 | copyParams :: [CapParam], 187 | maybeParent :: Maybe SlotRef 188 | } 189 | | IRQMapping { 190 | slot :: Maybe Word, 191 | objRef :: NameRef 192 | } 193 | | ASIDMapping { 194 | slot :: Maybe Word, 195 | objRef :: NameRef 196 | } 197 | deriving Show 198 | 199 | data KODecl = KODecl { 200 | objName :: QName, 201 | object :: KO 202 | } deriving (Show, Eq) 203 | 204 | data Decl 205 | = ObjDecl { 206 | theKODecl :: KODecl } 207 | | CapDecl { 208 | nameRef :: NameRef, 209 | mappings :: [CapMapping] } 210 | | CapNameDecl { 211 | declCapName :: Name, 212 | declObjRef :: NameRef, 213 | declSlot :: Word } 214 | | IRQDecl { 215 | irqs :: [CapMapping] } 216 | | ASIDDecl { 217 | asids :: [CapMapping] } 218 | | CDTDecl { 219 | parentRef :: SlotRef, 220 | children :: [Either Decl SlotRef] } 221 | deriving Show 222 | 223 | data Module = Module { 224 | theArch :: Arch, 225 | decls :: [Decl] 226 | } deriving Show 227 | -------------------------------------------------------------------------------- /capDL-tool/hello-dump.right: -------------------------------------------------------------------------------- 1 | arch arm11 2 | 3 | objects { 4 | 5 | asid_pool@0xf0306000 = asid_pool (asid_high: 0x0) 6 | cnode@0xf7ff0000 = cnode (12 bits) 7 | frame@0x10000000[64] = frame (1M) 8 | frame@0x18000000[32] = frame (1M) 9 | frame@0x26000000 = frame (4k) 10 | frame@0x30000000[32] = frame (1M) 11 | frame@0xb3f80000 = frame (4k) 12 | frame@0xb3f84000 = frame (4k) 13 | frame@0xb3f88000 = frame (4k) 14 | frame@0xb3f8c000 = frame (4k) 15 | frame@0xb3f94000 = frame (4k) 16 | frame@0xb3f98000 = frame (4k) 17 | frame@0xb3f9c000 = frame (4k) 18 | frame@0xb3fa0000 = frame (4k) 19 | frame@0xb3fa4000 = frame (4k) 20 | frame@0xb3fa8000 = frame (4k) 21 | frame@0xb3fac000 = frame (4k) 22 | frame@0xb3fb0000 = frame (4k) 23 | frame@0xb3fb4000 = frame (4k) 24 | frame@0xc0004000 = frame (4k) 25 | frame@0xc0008000 = frame (4k) 26 | frame@0xc000c000 = frame (4k) 27 | frame@0xc0010000 = frame (4k) 28 | frame@0xc0014000 = frame (4k) 29 | frame@0xc0018000 = frame (4k) 30 | frame@0xc001c000 = frame (4k) 31 | frame@0xc0020000 = frame (4k) 32 | frame@0xc0024000 = frame (4k) 33 | frame@0xc0028000 = frame (4k) 34 | frame@0xc003c000 = frame (4k) 35 | frame@0xc3f80000 = frame (4k) 36 | frame@0xc3f84000 = frame (4k) 37 | frame@0xc3f8c000 = frame (4k) 38 | frame@0xc3f90000 = frame (4k) 39 | frame@0xc3f98000 = frame (4k) 40 | frame@0xc3fa4000 = frame (4k) 41 | frame@0xc3fb0000 = frame (4k) 42 | frame@0xc3fc4000 = frame (4k) 43 | frame@0xc3fcc000 = frame (4k) 44 | frame@0xc3fd0000 = frame (4k) 45 | frame@0xc3fd8000 = frame (4k) 46 | frame@0xc3fe0000 = frame (4k) 47 | frame@0xc3fec000 = frame (4k) 48 | frame@0xf002f000[2] = frame (4k) 49 | frame@0xf0307000[16] = frame (4k) 50 | pd@0xf7fec000 = pd 51 | pt@0xf0031000 = pt 52 | tcb@0xf0031700 = tcb (dom: 0) 53 | 54 | untyped@0xf0000000@12[16] = ut (12 bits) 55 | untyped@0xf0031800@11 = ut (11 bits) 56 | untyped@0xf0032000@13 = ut (13 bits) 57 | untyped@0xf0034000@14 = ut (14 bits) 58 | untyped@0xf0038000@15 = ut (15 bits) 59 | untyped@0xf0040000@18 = ut (18 bits) 60 | untyped@0xf0080000@19 = ut (19 bits) 61 | untyped@0xf0100000@20[2] = ut (20 bits) 62 | untyped@0xf0300000@14 = ut (14 bits) 63 | untyped@0xf0304000@13 = ut (13 bits) 64 | untyped@0xf0317000@12 = ut (12 bits) 65 | untyped@0xf0318000@15 = ut (15 bits) 66 | untyped@0xf0320000@17 = ut (17 bits) 67 | untyped@0xf0340000@18 = ut (18 bits) 68 | untyped@0xf0380000@19 = ut (19 bits) 69 | untyped@0xf0400000@22 = ut (22 bits) 70 | untyped@0xf0800000@23 = ut (23 bits) 71 | untyped@0xf1000000@24 = ut (24 bits) 72 | untyped@0xf2000000@25[2] = ut (25 bits) 73 | untyped@0xf6000000@24 = ut (24 bits) 74 | untyped@0xf7000000@23 = ut (23 bits) 75 | untyped@0xf7800000@22 = ut (22 bits) 76 | untyped@0xf7c00000@21 = ut (21 bits) 77 | untyped@0xf7e00000@20 = ut (20 bits) 78 | untyped@0xf7f00000@19 = ut (19 bits) 79 | untyped@0xf7f80000@18 = ut (18 bits) 80 | untyped@0xf7fc0000@17 = ut (17 bits) 81 | untyped@0xf7fe0000@15 = ut (15 bits) 82 | untyped@0xf7fe8000@14 = ut (14 bits) 83 | 84 | } caps { 85 | 86 | asid_pool@0xf0306000 {1: pd@0xf7fec000} 87 | 88 | cnode@0xf7ff0000 { 89 | 1: tcb@0xf0031700 90 | 2: cnode@0xf7ff0000 (guard_size: 20) 91 | 3: pd@0xf7fec000 (asid: (0x0, 0x1)) 92 | 4: irq_control 93 | 5: asid_control 94 | 6: asid_pool@0xf0306000 95 | 9: frame@0xf002f000[1..0] (RW, asid: (0x0, 0x1)) 96 | 11: frame@0xf0307000[0..15] (RW, asid: (0x0, 0x1)) 97 | 27: pt@0xf0031000 (asid: (0x0, 0x1)) 98 | 28: untyped@0xf0000000@12[0..15] 99 | 44: untyped@0xf0031800@11 100 | 45: untyped@0xf0032000@13 101 | 46: untyped@0xf0304000@13 102 | 47: untyped@0xf0034000@14 103 | 48: untyped@0xf0300000@14 104 | 49: untyped@0xf0038000@15 105 | 50: untyped@0xf0040000@18 106 | 51: untyped@0xf0080000@19 107 | 52: untyped@0xf0100000@20[0..1] 108 | 54: untyped@0xf0317000@12 109 | 55: untyped@0xf7fe8000@14 110 | 56: untyped@0xf0318000@15 111 | 57: untyped@0xf7fe0000@15 112 | 58: untyped@0xf0320000@17 113 | 59: untyped@0xf7fc0000@17 114 | 60: untyped@0xf0340000@18 115 | 61: untyped@0xf7f80000@18 116 | 62: untyped@0xf0380000@19 117 | 63: untyped@0xf7f00000@19 118 | 64: untyped@0xf7e00000@20 119 | 65: untyped@0xf7c00000@21 120 | 66: untyped@0xf0400000@22 121 | 67: untyped@0xf7800000@22 122 | 68: untyped@0xf0800000@23 123 | 69: untyped@0xf7000000@23 124 | 70: untyped@0xf1000000@24 125 | 71: untyped@0xf6000000@24 126 | 72: untyped@0xf2000000@25[0..1] 127 | 74: frame@0xb3f80000 (RW) 128 | 75: frame@0xb3f84000 (RW) 129 | 76: frame@0xb3f88000 (RW) 130 | 77: frame@0xb3f8c000 (RW) 131 | 78: frame@0xb3f94000 (RW) 132 | 79: frame@0xb3f98000 (RW) 133 | 80: frame@0xb3f9c000 (RW) 134 | 81: frame@0xb3fa0000 (RW) 135 | 82: frame@0xb3fa4000 (RW) 136 | 83: frame@0xb3fa8000 (RW) 137 | 84: frame@0xb3fac000 (RW) 138 | 85: frame@0xb3fb0000 (RW) 139 | 86: frame@0xb3fb4000 (RW) 140 | 87: frame@0xc0004000 (RW) 141 | 88: frame@0xc0008000 (RW) 142 | 89: frame@0xc000c000 (RW) 143 | 90: frame@0xc0010000 (RW) 144 | 91: frame@0xc0014000 (RW) 145 | 92: frame@0xc0018000 (RW) 146 | 93: frame@0xc001c000 (RW) 147 | 94: frame@0xc0020000 (RW) 148 | 95: frame@0xc0024000 (RW) 149 | 96: frame@0xc0028000 (RW) 150 | 97: frame@0xc003c000 (RW) 151 | 98: frame@0xc3f80000 (RW) 152 | 99: frame@0xc3f84000 (RW) 153 | 100: frame@0xc3f8c000 (RW) 154 | 101: frame@0xc3f90000 (RW) 155 | 102: frame@0xc3f98000 (RW) 156 | 103: frame@0xc3fa4000 (RW) 157 | 104: frame@0xc3fb0000 (RW) 158 | 105: frame@0xc3fc4000 (RW) 159 | 106: frame@0xc3fcc000 (RW) 160 | 107: frame@0xc3fd0000 (RW) 161 | 108: frame@0xc3fd8000 (RW) 162 | 109: frame@0xc3fe0000 (RW) 163 | 110: frame@0xc3fec000 (RW) 164 | 111: frame@0x10000000[0..63] (RW) 165 | 175: frame@0x18000000[0..31] (RW) 166 | 207: frame@0x26000000 (RW) 167 | 208: frame@0x30000000[0..31] (RW) 168 | } 169 | 170 | pd@0xf7fec000 {0: pt@0xf0031000} 171 | 172 | pt@0xf0031000 { 173 | 7: frame@0xf0307000[0..15] (RW) 174 | 23: frame@0xf002f000[0..1] (RW) 175 | } 176 | 177 | tcb@0xf0031700 { 178 | 0: cnode@0xf7ff0000 (guard_size: 20) 179 | 1: pd@0xf7fec000 (asid: (0x0, 0x1)) 180 | 2: tcb@0xf0031700 (master_reply) 181 | 4: frame@0xf002f000[0] (RW, asid: (0x0, 0x1)) 182 | } 183 | 184 | } cdt { 185 | 186 | (cnode@0xf7ff0000, 2) {(tcb@0xf0031700, 0)} 187 | 188 | (cnode@0xf7ff0000, 3) {(tcb@0xf0031700, 1)} 189 | 190 | (cnode@0xf7ff0000, 10) {(tcb@0xf0031700, 4)} 191 | 192 | } irq maps { 193 | 194 | } -------------------------------------------------------------------------------- /python-capdl-tool/capdl/PageCollection.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | ''' 8 | Wrapper around a dict of pages for some extra functionality. Only intended to 9 | be used internally. 10 | ''' 11 | 12 | from __future__ import absolute_import, division, print_function, \ 13 | unicode_literals 14 | 15 | from .Cap import Cap 16 | from .Object import ASIDPool, Frame 17 | from .Spec import Spec 18 | from .util import round_down, PAGE_SIZE, lookup_architecture 19 | import collections 20 | 21 | 22 | def consume(iterator): 23 | '''Take a generator and exhaust it. Useful for discarding the unused result 24 | of something that would otherwise accumulate in memory. Clagged from 25 | https://docs.python.org/2/library/itertools.html''' 26 | # feed the entire iterator into a zero-length deque 27 | collections.deque(iterator, maxlen=0) 28 | 29 | 30 | class PageCollection(object): 31 | def __init__(self, name='', arch='arm11', infer_asid=True, vspace_root=None): 32 | self.name = name 33 | self.arch = arch 34 | self._pages = {} 35 | self._vspace_root = vspace_root 36 | self._asid = None 37 | self.infer_asid = infer_asid 38 | self._spec = None 39 | 40 | def add_page(self, vaddr, read=False, write=False, execute=False, size=PAGE_SIZE, elffill=[]): 41 | if vaddr not in self._pages: 42 | # Only create this page if we don't already have it. 43 | self._pages[vaddr] = { 44 | 'read': False, 45 | 'write': False, 46 | 'execute': False, 47 | 'size': PAGE_SIZE, 48 | 'elffill': [], 49 | } 50 | # Now upgrade this page's permissions to meet our current requirements. 51 | self._pages[vaddr]['read'] |= read 52 | self._pages[vaddr]['write'] |= write 53 | self._pages[vaddr]['execute'] |= execute 54 | self._pages[vaddr]['size'] = size 55 | self._pages[vaddr]['elffill'].extend(elffill) 56 | 57 | def __getitem__(self, key): 58 | return self._pages[key] 59 | 60 | def __iter__(self): 61 | return self._pages.__iter__() 62 | 63 | def get_vspace_root(self): 64 | if not self._vspace_root: 65 | vspace = lookup_architecture(self.arch).vspace() 66 | self._vspace_root = vspace.make_object('%s_%s' % (vspace.type_name, self.name)) 67 | return self._vspace_root, Cap(self._vspace_root) 68 | 69 | def get_asid(self): 70 | if not self._asid and self.infer_asid: 71 | self._asid = ASIDPool('asid_%s' % self.name) 72 | self._asid[0] = self.get_vspace_root()[1] 73 | return self._asid 74 | 75 | def _get_page_cap(self, existing_frames, page, page_vaddr, page_counter, spec): 76 | ''' 77 | Get a mapping cap from somewhere. First check if the existing_frames we 78 | were given contain a cap already. Otherwise create a Frame and Cap from 79 | the mapping information we have. 80 | ''' 81 | if page_vaddr in existing_frames: 82 | (size, cap) = existing_frames[page_vaddr] 83 | assert size == page['size'] 84 | return cap 85 | frame = Frame('frame_%s_%04d' % (self.name, page_counter), 86 | page['size']) 87 | spec.add_object(frame) 88 | return Cap(frame, read=page['read'], write=page['write'], 89 | grant=page['execute']) 90 | 91 | def get_spec(self, existing_frames={}): 92 | if self._spec is not None: 93 | return self._spec 94 | 95 | spec = Spec(self.arch) 96 | 97 | # Page directory and ASID. 98 | vspace_root, vspace_root_cap = self.get_vspace_root() 99 | spec.add_object(vspace_root) 100 | asid = self.get_asid() 101 | if asid is not None: 102 | spec.add_object(asid) 103 | 104 | # Construct frames and infer page objects from the pages. 105 | vspace = spec.arch.vspace() 106 | object_counter = 0 107 | objects = {} 108 | for page_counter, (page_vaddr, page) in enumerate(self._pages.items()): 109 | page_cap = self._get_page_cap(existing_frames, page, page_vaddr, page_counter, spec) 110 | # Walk the hierarchy, creating missing objects until we can 111 | # insert the frame 112 | level = vspace 113 | parent = vspace_root 114 | while level.child is not None and page['size'] < level.child.coverage: 115 | level = level.child 116 | object_vaddr = level.base_vaddr(page_vaddr) 117 | object_index = level.parent_index(object_vaddr) 118 | if (level, object_vaddr) not in objects: 119 | object = level.make_object('%s_%s_%04d' % ( 120 | level.type_name, self.name, object_counter)) 121 | object_counter += 1 122 | spec.add_object(object) 123 | object_cap = Cap(object) 124 | parent[object_index] = object_cap 125 | objects[(level, object_vaddr)] = object 126 | parent = parent[object_index].referent 127 | object_counter += 1 128 | if page_cap and page_cap.mapping_deferred: 129 | # This cap requires set_mapping to be called on it to provide a reference 130 | # to the mapping container and index. This is so the loader can use the same 131 | # cap for mapping and then copy it into the target cspace. Otherwise the cap 132 | # would be copied and therefore be an unmapped cap. 133 | page_cap.set_mapping(parent, level.child_index(page_vaddr)) 134 | page_cap = Cap(page_cap.referent, read=page_cap.read, 135 | write=page_cap.write, grant=page_cap.grant, cached=page_cap.cached) 136 | parent[level.child_index(page_vaddr)] = page_cap 137 | if page_cap: 138 | page["elffill"].extend(page_cap.referent.fill) 139 | page_cap.referent.fill = page["elffill"] 140 | 141 | # Cache the result for next time. 142 | assert self._spec is None 143 | self._spec = spec 144 | 145 | return spec 146 | 147 | 148 | def create_address_space(regions, name='', arch='arm11'): 149 | assert isinstance(regions, list) 150 | 151 | pages = PageCollection(name, arch) 152 | for r in regions: 153 | assert 'start' in r 154 | assert 'end' in r 155 | v = round_down(r['start']) 156 | while round_down(v) < r['end']: 157 | pages.add_page(v, r.get('read', False), r.get('write', False), 158 | r.get('execute', False)) 159 | v += PAGE_SIZE 160 | 161 | return pages 162 | -------------------------------------------------------------------------------- /cdl_utils/capdl_linker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 4 | # 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | from capdl.Object import register_object_sizes, Untyped 9 | from capdl.Allocator import ASIDTableAllocator, BestFitAllocator 10 | from capdl import ELF, lookup_architecture, TCB, valid_architectures 11 | from importlib.metadata import version 12 | from jinja2 import Environment, BaseLoader, FileSystemLoader 13 | import sys 14 | import argparse 15 | import pickle 16 | import logging 17 | import os 18 | import tempfile 19 | import yaml 20 | import six 21 | 22 | 23 | CSPACE_TEMPLATE_FILE = os.path.join(os.path.dirname(__file__), "templates/cspace.template.c") 24 | 25 | 26 | def manifest(cap_symbols, region_symbols, architecture, targets): 27 | """ 28 | Generates a c file from CSPACE_TEMPLATE_FILE with some runtime information 29 | about CSpace slots and special address ranges 30 | """ 31 | jinja2_version = version("jinja2") 32 | if jinja2_version < "2.10": 33 | raise Warning("Jinja2 should be >= 2.10") 34 | 35 | temp_file = open(CSPACE_TEMPLATE_FILE, 'r').read() 36 | template = Environment(loader=BaseLoader).from_string(temp_file) 37 | 38 | for (e, ccspace) in targets: 39 | name = os.path.basename(e) 40 | if ccspace: 41 | data = template.render( 42 | {'slots': cap_symbols[name], 'symbols': region_symbols[name], 'progname': name, 'ipc_buffer_symbol': "mainIpcBuffer"}) 43 | ccspace.write(data) 44 | 45 | 46 | def final_spec(args, obj_space, cspaces, addr_spaces, targets, architecture): 47 | """ 48 | Generates a final CapDL spec file that can be given to a capdl loader application 49 | """ 50 | arch = lookup_architecture(architecture) 51 | 52 | for e, key in targets: 53 | name = os.path.basename(e) 54 | elf = ELF(e, name, architecture) 55 | cspace = cspaces[key] 56 | 57 | # Avoid inferring a TCB as we've already created our own. 58 | elf_spec = elf.get_spec(infer_tcb=False, infer_asid=False, 59 | pd=addr_spaces[key].vspace_root, addr_space=addr_spaces[key]) 60 | obj_space.merge(elf_spec, label=key) 61 | for slot, v in cspace.cnode.slots.items(): 62 | if v is not None and isinstance(v.referent, TCB): 63 | tcb = v.referent 64 | if 'cspace' in tcb and tcb['cspace'] and tcb['cspace'].referent is not cspace.cnode: 65 | # We exclude TCBs that refer to a different CSpace 66 | continue 67 | funcs = {"get_vaddr": lambda x: elf.get_symbol_vaddr(x)} 68 | tcb.ip = eval(str(tcb.ip), {"__builtins__": None}, funcs) 69 | tcb.sp = eval(str(tcb.sp), {"__builtins__": None}, funcs) 70 | tcb.addr = eval(str(tcb.addr), {"__builtins__": None}, funcs) 71 | tcb.init = eval(str(tcb.init), {"__builtins__": None}, funcs) 72 | if not args.fprovide_tcb_caps: 73 | del cspace.cnode[slot] 74 | cspace.cnode.finalise_size(arch=arch) 75 | return obj_space 76 | 77 | 78 | def main(): 79 | parser = argparse.ArgumentParser( 80 | description="") 81 | parser.add_argument('--architecture', '--arch', default='aarch32', 82 | type=lambda x: type('')(x).lower(), choices=valid_architectures(), 83 | help='Target architecture.') 84 | parser.add_argument('--object-sizes', required=True, type=argparse.FileType('r')) 85 | subparsers = parser.add_subparsers() 86 | parser_a = subparsers.add_parser('build_cnode') 87 | parser_a.add_argument('--ccspace', nargs='+', type=argparse.FileType('w'), action='append') 88 | parser_a.set_defaults(which="build_cnode") 89 | parser_a.add_argument('--manifest-in', type=argparse.FileType('rb')) 90 | parser_a.add_argument('--elffile', nargs='+', action='append') 91 | parser_b = subparsers.add_parser('gen_cdl') 92 | parser_b.add_argument('--outfile', type=argparse.FileType('w')) 93 | parser_b.set_defaults(which="gen_cdl") 94 | parser_b.add_argument('--manifest-in', type=argparse.FileType('rb')) 95 | parser_b.add_argument('--elffile', nargs='+', action='append') 96 | parser_b.add_argument('--keys', nargs='+', action='append') 97 | parser_b.add_argument('--fprovide-tcb-caps', action='store_true', 98 | default=True, help='Hand out TCB caps to components, allowing them to ' 99 | 'exit cleanly.') 100 | parser_b.add_argument('--fno-provide-tcb-caps', action='store_false', 101 | dest='fprovide_tcb_caps', help='Do not hand out TCB caps, causing ' 102 | 'components to fault on exiting.') 103 | parser_b.add_argument('--save-object-state', type=argparse.FileType('wb')) 104 | parser_b.add_argument('--static-alloc', action='store_true', 105 | help='Perform static object allocation (requires --untyped)') 106 | parser_b.add_argument('--dynamic-alloc', action='store_false', dest='static_alloc', 107 | help='Cancel --static-alloc') 108 | parser_b.add_argument('--untyped', type=argparse.FileType('r'), 109 | help="YAML file with available seL4 bootinfo untypeds") 110 | 111 | args = parser.parse_args() 112 | register_object_sizes(yaml.load(args.object_sizes, Loader=yaml.FullLoader)) 113 | 114 | if args.which == "build_cnode": 115 | data = yaml.load(args.manifest_in, Loader=yaml.FullLoader) 116 | assert 'cap_symbols' in data and 'region_symbols' in data, "Invalid file format" 117 | elfs = [item for sublist in args.elffile for item in sublist] 118 | cspaces = [item for sublist in args.ccspace for item in sublist] 119 | targets = zip(elfs, cspaces) 120 | manifest(data['cap_symbols'], data['region_symbols'], args.architecture, targets) 121 | return 0 122 | 123 | if args.which == "gen_cdl": 124 | if args.static_alloc and not args.untyped: 125 | parser.error('--static-alloc requires --untyped') 126 | 127 | allocator_state = pickle.load(args.manifest_in) 128 | elfs = [item for sublist in args.elffile for item in sublist] 129 | keys = [item for sublist in args.keys for item in sublist] 130 | targets = zip(elfs, keys) 131 | obj_space = final_spec(args, allocator_state.obj_space, allocator_state.cspaces, 132 | allocator_state.addr_spaces, targets, args.architecture) 133 | 134 | # Calculate final layout for objects and ASID slots... 135 | ASIDTableAllocator().allocate(obj_space.spec) 136 | if args.static_alloc: 137 | alloc = BestFitAllocator() 138 | for ut in yaml.load(args.untyped, Loader=yaml.FullLoader): 139 | if len(ut): 140 | is_device, paddr, size_bits = ut['device'], ut['paddr'], ut['size_bits'] 141 | alloc.add_untyped(Untyped("root_untyped_0x%x" % paddr, 142 | size_bits=size_bits, paddr=paddr), is_device) 143 | alloc.allocate(obj_space.spec) 144 | 145 | args.outfile.write(repr(obj_space.spec)) 146 | if args.save_object_state: 147 | pickle.dump(allocator_state, args.save_object_state) 148 | 149 | return 0 150 | 151 | 152 | if __name__ == '__main__': 153 | sys.exit(main()) 154 | -------------------------------------------------------------------------------- /capDL-tool/CapDL/PrintModel.hs: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | -- 4 | -- SPDX-License-Identifier: BSD-2-Clause 5 | -- 6 | 7 | module CapDL.PrintModel where 8 | 9 | import CapDL.Model 10 | import CapDL.PrintUtils 11 | 12 | import Prelude () 13 | import Prelude.Compat hiding ((<>)) 14 | import Text.PrettyPrint 15 | import Data.List.Compat 16 | import qualified Data.Map as Map 17 | 18 | indent = 2 19 | 20 | prettyMapping :: (Show a, Show b) => (a,b) -> Doc 21 | prettyMapping (a,b) = text (show a) <> text " -> " <> text (show b) 22 | 23 | prettyBigList f xs = lbrack $+$ nest indent (vcat (map f xs)) $+$ rbrack 24 | 25 | prettyMap m = prettyBigList prettyMapping (Map.toList m) 26 | 27 | prettyNum :: Int -> Doc 28 | prettyNum num = brackets $ int num 29 | 30 | prettyNameDecl :: ObjID -> Int-> Doc 31 | prettyNameDecl (n, Nothing) _ = text n <+> equals 32 | prettyNameDecl (n, _) num = text n <> prettyNum num <+> equals 33 | 34 | prettyNameRefr :: [ObjID]-> Doc 35 | prettyNameRefr objs = (text.fst.head) objs <> (prettyBrackets $ map snd objs) 36 | 37 | prettyObject :: ObjID -> Int -> KernelObject a -> Doc 38 | prettyObject _ _ Untyped {} = empty 39 | prettyObject n num obj = prettyNameDecl n num <+> prettyObjParams obj 40 | 41 | prettyObjectsList :: [(ObjID, KernelObject a)] -> [Doc] 42 | prettyObjectsList [] = [] 43 | prettyObjectsList list@((id, obj):_) = 44 | prettyObject id len obj:prettyObjectsList (drop len list) 45 | where len = length (takeWhile (sameName id) (map fst list)) 46 | 47 | prettyObjects :: ObjMap a -> Doc 48 | prettyObjects m = vcat (prettyObjectsList (Map.toList m)) 49 | 50 | prettyCovered :: [ObjID] -> [Doc] 51 | prettyCovered [] = [] 52 | prettyCovered list@(id:_) = 53 | prettyNameRefr same:prettyCovered (drop (length same) list) 54 | where same = takeWhile (sameName id) list 55 | 56 | prettyIndexedUntyped :: CoverMap -> [(ObjID, KernelObject a)] -> Doc 57 | prettyIndexedUntyped _ [] = empty 58 | prettyIndexedUntyped covers ((name, obj@(Untyped _ _)):xs) = 59 | if null cover 60 | then prettyIndexedUntyped covers xs 61 | else prettyNameRefr [name] <+> equals <+> prettyObjParams obj <+> 62 | braces (fsep $ punctuate comma $ prettyCovered cover) $+$ 63 | prettyIndexedUntyped covers xs 64 | where cover = getUTCover name covers 65 | prettyIndexedUntyped _ _ = error "Untyped only" 66 | 67 | prettyUntyped :: CoverMap -> [(ObjID, KernelObject a)] -> Doc 68 | prettyUntyped covers list@((name, obj@(Untyped _ _)):_) = 69 | if snd name == Nothing 70 | then prettyNameDecl name len <+> prettyObjParams obj <+> 71 | if null cover 72 | then empty 73 | else braces (fsep $ punctuate comma $ prettyCovered cover) 74 | else prettyNameDecl name len <+> prettyObjParams obj $+$ 75 | prettyIndexedUntyped covers list 76 | where len = length list 77 | cover = getUTCover name covers 78 | prettyUntyped _ _ = empty 79 | 80 | prettyUntypedsList :: CoverMap -> [(ObjID, KernelObject a)] -> [Doc] 81 | prettyUntypedsList _ [] = [empty] 82 | prettyUntypedsList covers list@((name, _):_) = 83 | prettyUntyped covers (take len list) : 84 | prettyUntypedsList covers (drop len list) 85 | where len = length $ takeWhile (sameName name) (map fst list) 86 | 87 | prettyUntypeds :: ObjMap a -> CoverMap -> Doc 88 | prettyUntypeds m covers = vcat (prettyUntypedsList covers (Map.toList m)) 89 | 90 | prettyCap :: Cap -> [Maybe Word] -> Doc 91 | prettyCap cap range = printCap cap <> prettyBrackets range <+> maybeCapParams cap 92 | 93 | prettySlot :: Printing a => (a, Cap) -> [Maybe Word] -> Doc 94 | prettySlot (n, cap) range = num n <> colon <+> prettyCap cap range 95 | 96 | prettySlotsRange :: Printing a => [(a, Cap)] -> Doc 97 | prettySlotsRange [] = error "empty" 98 | prettySlotsRange list@(x:_) = 99 | prettySlot x (map (snd.objID.snd) list) 100 | 101 | prettySlotsList :: Printing a => [(a, Cap)] -> [Doc] 102 | prettySlotsList [] = [] 103 | prettySlotsList list@(first@(_, cap):xs) = 104 | if hasObjID cap 105 | then prettySlotsRange sameGroup : prettySlotsList (drop (length sameGroup) list) 106 | else prettySlot first [Nothing] : prettySlotsList xs 107 | where sameGroup = sameArray list 108 | 109 | capHead :: ObjID -> [Maybe Word] -> Doc 110 | capHead (name, _) range = text name <> prettyBrackets range 111 | 112 | prettySlots :: Printing a => (ObjID, KernelObject a) -> [Maybe Word] -> Doc 113 | prettySlots (n, obj) range = 114 | let xs = prettySlotsList $ Map.toList $ slots obj 115 | in case xs of 116 | [] -> empty 117 | [slot] -> capHead n range <+> braces slot $+$ text "" 118 | xs -> hang (capHead n range <+> lbrace) indent (vcat xs) 119 | $+$ rbrace $+$ text "" 120 | 121 | prettyCapsGroup :: Printing a => [(ObjID, KernelObject a)] -> Doc 122 | prettyCapsGroup list = prettySlots (head list) (map (snd.fst) list) 123 | 124 | prettyCapsList :: Printing a => [(ObjID, KernelObject a)] -> [Doc] 125 | prettyCapsList [] = [] 126 | prettyCapsList list@(first:xs) 127 | | hasSlots (snd first) = 128 | prettyCapsGroup sameCaps : prettyCapsList otherCaps 129 | | otherwise = prettyCapsList xs 130 | where (sameCaps, otherCaps) = partition (same first) list 131 | 132 | prettyCaps :: Printing a => ObjMap a -> Doc 133 | prettyCaps ms = vcat $ prettyCapsList $ Map.toList ms 134 | 135 | prettyCapRef :: CapRef -> Doc 136 | prettyCapRef (obj, slot) = parens $ text (showID obj) <> comma <+> num slot 137 | 138 | prettyCDTDecl :: CapRef -> [CapRef] -> Doc 139 | prettyCDTDecl parent children = 140 | let parent' = prettyCapRef parent 141 | children' = map prettyCapRef children 142 | in case children' of 143 | [child] -> parent' <+> braces child $+$ text "" 144 | children -> hang (parent' <+> lbrace) indent (vcat children) 145 | $+$ rbrace $+$ text "" 146 | 147 | prettyCDTGroup :: [(CapRef, CapRef)] -> Doc 148 | prettyCDTGroup list = prettyCDTDecl (snd (head list)) (map fst list) 149 | 150 | prettyCDTList :: [(CapRef, CapRef)] -> [Doc] 151 | prettyCDTList [] = [] 152 | prettyCDTList list = 153 | prettyCDTGroup sameParents : prettyCDTList otherParents 154 | where 155 | (sameParents, otherParents) = 156 | partition ((== firstParent) . snd) list 157 | firstParent = snd $ head list 158 | 159 | prettyCDT :: CDT -> Doc 160 | prettyCDT cdt = vcat $ prettyCDTList $ Map.toList cdt 161 | 162 | prettyIRQ :: ObjID -> [Maybe Word] -> Doc 163 | prettyIRQ irq range = text (fst irq) <> prettyBrackets range 164 | 165 | prettyIRQSlot :: (Word, ObjID) -> [Maybe Word] -> Doc 166 | prettyIRQSlot (n, irq) range = num n <> colon <+> prettyIRQ irq range 167 | 168 | prettyIRQSlotsRange :: [(Word, ObjID)] -> Doc 169 | prettyIRQSlotsRange [] = error "empty" 170 | prettyIRQSlotsRange list@(x:_) = 171 | prettyIRQSlot x (map (snd.snd) list) 172 | 173 | prettyIRQSlotsList :: [(Word, ObjID)] -> [Doc] 174 | prettyIRQSlotsList [] = [] 175 | prettyIRQSlotsList list = 176 | prettyIRQSlotsRange sameGroup : prettyIRQSlotsList (drop (length sameGroup) list) 177 | where sameGroup = sameArray list 178 | 179 | prettyIRQNode :: IRQMap -> Doc 180 | prettyIRQNode irqNode = 181 | let irqs = prettyIRQSlotsList (Map.toList irqNode) 182 | in case irqs of 183 | [] -> empty 184 | [irq] -> irq $+$ text "" 185 | irqs -> vcat irqs $+$ text "" 186 | 187 | prettyMappings :: Printing a => Model a -> Doc 188 | prettyMappings (Model _ ms irqNode cdt untypedCovers) = 189 | text "objects {" $+$ 190 | text "" $+$ 191 | nest indent (prettyObjects ms) $+$ 192 | text "" $+$ 193 | nest indent (prettyUntypeds ms untypedCovers) $+$ 194 | text "" $+$ 195 | text "} caps {" $+$ 196 | text "" $+$ 197 | nest indent (prettyCaps ms) $+$ 198 | text "} cdt {" $+$ 199 | text "" $+$ 200 | nest indent (prettyCDT cdt) $+$ 201 | text "} irq maps {" $+$ 202 | text "" $+$ 203 | nest indent (prettyIRQNode irqNode) $+$ 204 | text "}" 205 | 206 | prettyHeader arch = 207 | text "arch" <+> prettyArch arch $+$ 208 | text "" 209 | 210 | pretty model = 211 | prettyHeader (arch model) $+$ 212 | prettyMappings model 213 | -------------------------------------------------------------------------------- /cdl_utils/untyped_gen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 4 | # 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | """ 8 | Generate an initial list of untyped objects based on the available physical 9 | memory regions, the kernel image size, user image size, and devices on a platform 10 | """ 11 | 12 | import argparse 13 | import logging 14 | from collections import namedtuple, deque, defaultdict 15 | 16 | from elftools.elf.elffile import ELFFile 17 | import yaml 18 | from sortedcontainers import SortedList 19 | 20 | from capdl import register_object_sizes 21 | from capdl.ELF import ELF 22 | from capdl.Object import get_object_size_bits, ObjectType 23 | from capdl.util import ctz, valid_architectures, lookup_architecture, round_down, round_up, PAGE_SIZE 24 | 25 | Region = namedtuple('Region', ['start', 'end']) 26 | 27 | 28 | def create_untypeds_for_region(object_sizes, region, arch, device): 29 | untyped = [] 30 | start = region.start 31 | end = region.end 32 | while start != end: 33 | assert (start <= end) 34 | size_bits = (end - start).bit_length() - 1 if start < end else arch.word_size_bits() 35 | align_bits = ctz(start) if start > 0 else size_bits 36 | size_bits = min(size_bits, 37 | align_bits, 38 | object_sizes['seL4_Value_MaxUntypedBits']) 39 | if size_bits > object_sizes['seL4_Value_MinUntypedBits']: 40 | untyped.append({'device': device, 'size_bits': size_bits, 'paddr': start}) 41 | start += 1 << size_bits 42 | return untyped 43 | 44 | 45 | def init_freemem(available, reserved): 46 | """ 47 | Remove any reserved regions from available and return a new list of 48 | available regions that does not contain any reserved regions 49 | 50 | This method mirrors init_freemem in the kernel. 51 | """ 52 | 53 | freemem = [] 54 | available = deque(available) 55 | reserved = deque(reserved) 56 | while len(available) and len(reserved): 57 | if reserved[0].start == reserved[0].end: 58 | # reserved region is empty - skip it 59 | reserved.popleft() 60 | if available[0].start >= available[0].end: 61 | # skip the entire region - it's empty now after trimming 62 | available.popleft() 63 | elif reserved[0].end <= available[0].start: 64 | # the reserved region is below the available region - skip it 65 | reserved.popleft() 66 | elif reserved[0].start >= available[0].end: 67 | # the reserved region is above the available region - take the whole thing 68 | freemem.append(available[0]) 69 | available.popleft() 70 | else: 71 | # the reserved region overlaps with the available region 72 | if reserved[0].start <= available[0].start: 73 | # the region overlaps with the start of the available region. 74 | # trim start of the available region 75 | available[0] = Region(min(available[0].end, reserved[0].end), 76 | available[0].end) 77 | reserved.popleft() 78 | else: 79 | assert reserved[0].start < available[0].end 80 | # take the first chunk of the available region and move 81 | # the start to the end of the reserved region 82 | freemem.append(Region(available[0].start, reserved[0].start)) 83 | if available[0].end > reserved[0].end: 84 | available[0] = Region(reserved[0].end, available[0].end) 85 | reserved.popleft() 86 | else: 87 | available.popleft() 88 | 89 | # no more reserved regions - add the rest 90 | freemem += list(available) 91 | return freemem 92 | 93 | 94 | def get_load_bounds(elf): 95 | end = 0 96 | start = 0xFFFFFFFFFFFFFFFF 97 | for s in elf.iter_segments(): 98 | if s['p_type'] == 'PT_LOAD': 99 | paddr = s['p_paddr'] 100 | memsz = s['p_memsz'] 101 | start = min(paddr, start) 102 | end = max(paddr + memsz, end) 103 | print("ELF image: {0}<-->{1}".format(hex(start), hex(end))) 104 | return Region(start, end) 105 | 106 | 107 | def get_symbol_size(elf, name): 108 | symbol_table = elf.get_section_by_name('.symtab') 109 | symbol = symbol_table.get_symbol_by_name(name) 110 | if not symbol: 111 | logging.fatal("No symbol {0}".format(name)) 112 | return symbol['st_size'] 113 | 114 | 115 | def main(args): 116 | arch = lookup_architecture(args.architecture) 117 | addresses = yaml.load(args.input, Loader=yaml.FullLoader) 118 | object_sizes = yaml.load(args.object_sizes, Loader=yaml.FullLoader) 119 | register_object_sizes(object_sizes) 120 | 121 | # create the list of reserved regions. This duplicates the load_images part of the elf loader. Ultimately 122 | # we should feed this info to the elf loader rather than doing it dynamically 123 | reserved = SortedList() 124 | # first the kernel image 125 | kernel_elf = ELFFile(args.kernel_elf) 126 | kernel_region = get_load_bounds(kernel_elf) 127 | # elfloader currently rounds end to page boundary 128 | kernel_region = Region(kernel_region.start, round_up(kernel_region.end, PAGE_SIZE)) 129 | reserved.add(kernel_region) 130 | 131 | # now the DTB 132 | next_paddr = kernel_region.end 133 | if args.dtb_size: 134 | dtb_region = Region(next_paddr, round_up(next_paddr + args.dtb_size, PAGE_SIZE)) 135 | reserved.add(dtb_region) 136 | print("DTB: {0}<-->{1}".format(hex(dtb_region.start), hex(dtb_region.end))) 137 | 138 | available = SortedList() 139 | for a in addresses['memory']: 140 | # trim to paddr-top 141 | start, end = a['start'], a['end'] 142 | if args.paddr_top is not None: 143 | start = min(start, args.paddr_top) 144 | end = min(end, args.paddr_top) 145 | if start != end: 146 | available.add(Region(start, end)) 147 | 148 | # calculate free regions based on available + reserved regions 149 | freemem = init_freemem(available, reserved) 150 | 151 | # create untyped for each region 152 | untypeds = [] 153 | for f in freemem: 154 | untypeds += create_untypeds_for_region(object_sizes, f, arch, False) 155 | 156 | # create untyped for each device untyped 157 | for d in addresses['devices']: 158 | untypeds += create_untypeds_for_region(object_sizes, 159 | Region(d['start'], d['end']), arch, True) 160 | 161 | # finally output the file 162 | yaml.dump(untypeds, args.output) 163 | 164 | 165 | if __name__ == '__main__': 166 | def int_or_hex(s): 167 | if s.strip().startswith('0x'): 168 | return int(s, 0) 169 | else: 170 | return int(s) 171 | 172 | parser = argparse.ArgumentParser() 173 | parser.add_argument('--input', required=True, type=argparse.FileType('r'), 174 | help='input yaml describing physical and device memory') 175 | parser.add_argument('--output', required=True, type=argparse.FileType('w'), 176 | help='output file for generated untyped yaml') 177 | parser.add_argument('--linker', type=argparse.FileType('w'), help="Output file for linker") 178 | parser.add_argument('--object-sizes', required=True, type=argparse.FileType('r'), 179 | help='Yaml file with kernel object sizes') 180 | parser.add_argument('--extra-bi-size-bits', default=0, type=int, 181 | help='Size_bits of extra bootinfo frame (0 if none)') 182 | parser.add_argument('--kernel-elf', type=argparse.FileType('rb'), 183 | help='Kernel elf file', required=False) 184 | parser.add_argument('--paddr-top', type=int_or_hex, 185 | help='Kernel\'s PADDR_TOP (highest usable physical memory addr)') 186 | parser.add_argument('--architecture', choices=valid_architectures()) 187 | parser.add_argument('--dtb-size', type=int_or_hex, default=0, 188 | help='DTB (device tree binary) blob size') 189 | parser.add_argument('--elffile', nargs='+', action='append') 190 | 191 | main(parser.parse_args()) 192 | -------------------------------------------------------------------------------- /capDL-tool/CapDL/DumpParser.hs: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | -- 4 | -- SPDX-License-Identifier: BSD-2-Clause 5 | -- 6 | 7 | module CapDL.DumpParser where 8 | 9 | import CapDL.AST 10 | import CapDL.Model 11 | import CapDL.ParserUtils 12 | 13 | import Text.ParserCombinators.Parsec 14 | 15 | import Prelude () 16 | import Prelude.Compat 17 | import Control.Monad (when) 18 | import qualified Data.Set as Set 19 | import qualified Data.Map as Map 20 | import Data.List.Compat 21 | import Data.List.Split 22 | import Data.Ord 23 | import Numeric 24 | import Data.Maybe 25 | 26 | --Assumes that untypeds come before anything with an address 27 | 28 | insertCov :: ObjID -> ObjID -> MapParser () 29 | insertCov cov untyp = do 30 | maps <- getState 31 | let covM = covMap maps 32 | covSet = Map.findWithDefault Set.empty untyp covM 33 | covSet' = Set.insert cov covSet 34 | setState $ maps { covMap = Map.insert untyp covSet' covM } 35 | 36 | getCovs :: MapParser [(ObjID, Set.Set ObjID)] 37 | getCovs = do 38 | maps <- getState 39 | return $ Map.toList $ covMap maps 40 | 41 | insertAddrs :: (Word, Word) -> ObjID -> MapParser () 42 | insertAddrs addrs objID = do 43 | maps <- getState 44 | let addrM = addrMap maps 45 | setState $ maps { addrMap = Map.insert objID addrs addrM } 46 | 47 | included :: Word -> (Word, Word) -> Bool 48 | included n (st, end) = n >= st && n < end 49 | 50 | getUntypSize :: String -> Int 51 | getUntypSize string = read $ splitOn "@" string !! 2 52 | 53 | lookupAddr :: Word -> MapParser (Maybe ObjID) 54 | lookupAddr addr = do 55 | maps <- getState 56 | let ids = map fst $ filter (included addr . snd) $ Map.toList $ addrMap maps 57 | id = minimumBy (comparing (getUntypSize . fst)) ids 58 | return $ case ids of 59 | [] -> Nothing 60 | _ -> Just id 61 | 62 | insertRef :: Name -> ObjID -> MapParser () 63 | insertRef dumpID objID = do 64 | maps <- getState 65 | let refM = refMap maps 66 | setState $ maps { refMap = Map.insert dumpID objID refM } 67 | 68 | lookupRef :: Name -> MapParser ObjID 69 | lookupRef dumpID = do 70 | maps <- getState 71 | let id = Map.lookup dumpID $ refMap maps 72 | case id of 73 | Just id -> return id 74 | Nothing -> return (dumpID, Nothing) 75 | 76 | getAddr :: String -> Maybe Word 77 | getAddr string = 78 | if '@' `elem` string 79 | then Just $ fst.head.readHex $ splitOn "@0x" string !! 1 80 | else Nothing 81 | 82 | getObjTyp :: String -> Maybe String 83 | getObjTyp string = 84 | if '@' `elem` string 85 | then Just $ splitOn "@" string !! 0 86 | else Nothing 87 | 88 | maybeInsertIRQ :: Name -> MapParser () 89 | maybeInsertIRQ obj = 90 | when (getObjTyp obj == Just "irqhandler") $ do 91 | maps <- getState 92 | let irqM = irqMap maps 93 | slot = fromJust $ getAddr obj 94 | setState $ maps { irqMap = Map.insert slot obj irqM } 95 | 96 | object :: MapParser KO 97 | object = do 98 | typ <- object_type 99 | params <- object_params 100 | return (Obj typ params []) 101 | 102 | maybe_object :: MapParser (Maybe (Name, KO)) 103 | maybe_object = 104 | do name <- name 105 | _ <- symbol "=" 106 | obj <- CapDL.DumpParser.object 107 | return $ Just (name, obj) 108 | <|> return Nothing 109 | 110 | sizeOf :: Arch -> KO -> Word 111 | sizeOf _ (Obj Frame_T [VMSize vmSz] _) = vmSz 112 | sizeOf _ (Obj Untyped_T [BitSize bSz] _) = 2 ^ bSz 113 | sizeOf _ (Obj CNode_T [BitSize bSz] _) = 16 * 2 ^ bSz 114 | sizeOf _ (Obj IrqSlot_T _ _) = 1 115 | sizeOf _ (Obj Endpoint_T _ _) = 16 116 | sizeOf _ (Obj Notification_T _ _) = 16 117 | sizeOf _ (Obj ASIDPool_T _ _) = 4 * 2^10 118 | sizeOf _ (Obj IOPT_T _ _) = 4 * 2^10 119 | sizeOf _ (Obj IODevice_T _ _) = 1 120 | sizeOf _ (Obj ARMIODevice_T _ _) = 1 121 | sizeOf IA32 (Obj TCB_T _ _) = 2^10 122 | sizeOf IA32 (Obj PD_T _ _) = 4 * 2^10 123 | sizeOf IA32 (Obj PT_T _ _) = 4 * 2^10 124 | sizeOf ARM11 (Obj TCB_T _ _) = 512 125 | sizeOf ARM11 (Obj PD_T _ _) = 16 * 2^10 126 | sizeOf ARM11 (Obj PT_T _ _) = 2^10 127 | sizeOf _ _ = 0 128 | 129 | consecutive :: Arch -> (Name, KO) -> Maybe (Name, KO) -> Word -> Bool 130 | consecutive _ _ Nothing _ = False 131 | consecutive arch (name1, obj1) (Just (name2, obj2)) num = 132 | let addr1 = getAddr name1 133 | addr2 = getAddr name2 134 | in case (addr1, addr2) of 135 | (Just addr1, Just addr2) -> 136 | obj1 == obj2 && addr1 + num * sizeOf arch obj1 == addr2 137 | _ -> False 138 | 139 | considerUntypeds :: Arch -> ObjID -> Maybe Word -> KO -> MapParser () 140 | considerUntypeds arch refr addr obj = 141 | case (addr, obj) of 142 | (Just addr, Obj Untyped_T _ _ ) -> do 143 | covUn <- lookupAddr addr 144 | insertAddrs (addr, addr + sizeOf arch obj - 1) refr 145 | case covUn of 146 | Just covUn -> insertCov refr covUn 147 | Nothing -> return () 148 | (Just addr, _) -> do covUn <- lookupAddr addr 149 | case covUn of 150 | Just covUn -> insertCov refr covUn 151 | Nothing -> return () 152 | (Nothing, _) -> return () 153 | 154 | maybe_obj_decl :: Arch -> (Name, KO) -> Word -> MapParser Word 155 | maybe_obj_decl arch pre num = do 156 | next <- lookAhead maybe_object 157 | if consecutive arch pre next num 158 | then do let (name, obj) = fromJust next 159 | refr = (fst pre, Just num) 160 | addr = getAddr name 161 | _ <- maybe_object 162 | maybeInsertIRQ name 163 | insertRef name refr 164 | considerUntypeds arch refr addr obj 165 | total <- maybe_obj_decl arch pre (num + 1) 166 | return total 167 | else return num 168 | 169 | obj_decl :: Arch -> MapParser KODecl 170 | obj_decl arch = do 171 | name <- name 172 | _ <- symbol "=" 173 | obj <- CapDL.DumpParser.object 174 | total <- maybe_obj_decl arch (name, obj) 1 175 | let (decl, refr) = if total == 1 176 | then ((name, []), (name, Nothing)) 177 | else ((name, [Only total]), (name, Just 0)) 178 | addr = getAddr name 179 | maybeInsertIRQ name 180 | insertRef name refr 181 | considerUntypeds arch refr addr obj 182 | return (KODecl [decl] obj) 183 | 184 | obj_decls :: Arch -> MapParser [Decl] 185 | obj_decls arch = do 186 | reserved "objects" 187 | decls <- braces $ many (obj_decl arch) 188 | return $ map ObjDecl decls 189 | 190 | id_to_ref :: ObjID -> NameRef 191 | id_to_ref (name, Nothing) = (name, []) 192 | id_to_ref (name, Just n) = (name, [Only n]) 193 | 194 | make_obj :: Set.Set ObjID -> KO 195 | make_obj covs = Obj Untyped_T [] $ map (Right . id_to_ref) $ Set.toList covs 196 | 197 | cov_decl :: (ObjID, Set.Set ObjID) -> KODecl 198 | cov_decl (refr, covs) = 199 | let obj = make_obj covs 200 | in KODecl [id_to_ref refr] obj 201 | 202 | cov_decls :: MapParser [Decl] 203 | cov_decls = do 204 | covs <- getCovs 205 | return $ map (ObjDecl . cov_decl) covs 206 | 207 | cap_mapping :: MapParser CapMapping 208 | cap_mapping = do 209 | sl <- maybe_slot 210 | obj <- name 211 | (n,num) <- lookupRef obj 212 | let obj' = case num of 213 | Just num -> (n, [Only num]) 214 | Nothing -> (n, []) 215 | params <- cap_params 216 | parent <- maybe_parent 217 | return $ CapMapping sl Nothing obj' params parent 218 | 219 | refToNameRef :: ObjID -> NameRef 220 | refToNameRef (id, num) = 221 | case num of 222 | Just num -> (id, [Only num]) 223 | Nothing -> (id, []) 224 | 225 | cap_decl :: MapParser Decl 226 | cap_decl = do 227 | n <- name 228 | ref <- lookupRef n 229 | let n' = refToNameRef ref 230 | ms <- braces (sepEndBy cap_mapping opt_semi) 231 | return $ CapDecl n' ms 232 | 233 | cap_decls :: MapParser [Decl] 234 | cap_decls = do 235 | reserved "caps" 236 | braces $ many (try cap_decl) 237 | 238 | make_irq_mapping :: (Word, Name) -> MapParser CapMapping 239 | make_irq_mapping (slot, irq) = do 240 | ref <- lookupRef irq 241 | let irq' = refToNameRef ref 242 | return $ IRQMapping (Just slot) irq' 243 | 244 | make_irq_decl :: MapParser [Decl] 245 | make_irq_decl = do 246 | maps <- getState 247 | let irqs = Map.toList $ irqMap maps 248 | irq_decls <- mapM make_irq_mapping irqs 249 | return [IRQDecl irq_decls] 250 | 251 | all_decls :: Arch -> MapParser [Decl] 252 | all_decls arch = do 253 | objs <- obj_decls arch 254 | cov <- cov_decls 255 | caps <- cap_decls 256 | cdt <- cdt_decls 257 | irq <- make_irq_decl 258 | return $ objs ++ cov ++ caps ++ cdt ++ irq 259 | 260 | capDLDumpModule :: MapParser Module 261 | capDLDumpModule = do 262 | whiteSpace 263 | arch <- parse_arch 264 | decls <- all_decls arch 265 | eof 266 | return (Module arch decls) 267 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Version history for capDL 8 | 9 | 10 | 11 | --- 12 | 13 | ## Upcoming release 14 | 15 | ### Changes 16 | 17 | 18 | ### Upgrade Notes 19 | --- 20 | 21 | ## 0.4.0 2025-11-25 22 | Using seL4 version 14.0.0 23 | 24 | ### Changes 25 | 26 | * Add support for fpu_disabled flag on TCBs for platforms with CONFIG_HAVE_FPU. 27 | * Add support for SGISignal capability. SGISignal capabilities in capDL point 28 | to an `arm_sgi_signal` object with `(irg: , target: )` properties 29 | that define the destination of the SGI. 30 | * Remove `pyaml` python dependency and use `pyyaml` (import `yaml`) directly. 31 | 32 | ### Upgrade Notes 33 | 34 | * existing capDL specs should continue to work without change 35 | 36 | --- 37 | 38 | ## 0.3 2024-07-01 39 | 40 | Using seL4 version 13.0.0 41 | 42 | ### Changes 43 | 44 | * add support for SMC capability 45 | * add support for binding notifications to TCBs 46 | * enable MCS build; use `seL4_TCB_SetAffinity` only for non-MCS kernels 47 | * allow `SchedControlCap` to refer to a secondary core 48 | * minimal update for seL4 AArch64 VSpace API change, removing `seL4_ARM_PageGlobalDirectoryObject` 49 | * `object_sizes`: add include for deprecated constants, because some definitions 50 | that `object_sizes` depends on are now found in a `deprecated.h` header file. 51 | * Clean up and clarify `arm11` usage in capDL despite ARMv6 removal 52 | * `cdl_utils`: remove `simpleeval` python dependency 53 | * Run GitHub tests with python 3.9 54 | * added vulnerability reporting policy 55 | 56 | #### capdl-loader 57 | 58 | * use `seL4_BootInfoFrameSize` instead of hard-coded page size 59 | * python + loader: Add support for generating fault handler caps with specific 60 | rights. Behaviour is unchanged (`seL4_AllRights`) if no rights are provided. 61 | * ensure heap is aligned 62 | 63 | #### capDL-tool 64 | 65 | * update to LTS Haskell 20.25, ghc-9.2.8 66 | * fix several cases in `validObjPars`: `Period`, `IOAPIC`, `MSIHandle`, `CBNumber` 67 | 68 | ### Upgrade Notes 69 | 70 | * existing capDL specs should continue to work 71 | * AArch64 VSpace changes may allow simplification of some capDL specs 72 | 73 | --- 74 | 75 | ## 0.2.1 2021-06-10 76 | 77 | Using seL4 version 12.1.0 78 | 79 | ### Changes 80 | 81 | * Added page-upper-directory caps to the valid TCB check for platforms like QEMU arm-virt as they use different paging 82 | structures. 83 | * Added const qualifiers to the capdl-loader-app to avoid compiler warnings against other libraries. 84 | * Improved the README for the capdl-loader-app. 85 | 86 | ### Upgrade Notes 87 | 88 | * None to be aware of. This is not a source-breaking or binary-breaking release. 89 | 90 | --- 91 | 92 | ## capdl-0.2.0 2020-10-27 93 | 94 | Using seL4 version 12.0.0 95 | 96 | ### Changes 97 | 98 | * Convert to SPDX license tags. This includes marking all documentation files CC-BY-SA-4.0. 99 | 100 | * Build system: 101 | - Support `CMakeForegroundComplexCommands`. This enables long-running build steps like Haskell installation to 102 | directly print to the console. 103 | - Make PLATFORM_SIFT agnostic of the build system directory layout 104 | - Save the binary artifacts for the capDL-tool in an out-of-build-tree directory, this will not rebuild in future if 105 | it can find a previously built artifact. 106 | - Migrate scripts to python3 107 | * Add `seL4_BadgeBits` constant and update python-capdl-tool to directly query the object_sizes dictionary. This allows 108 | for templates to use badge sizes. 109 | * Add support for Arm smmu v2. 110 | * Add support for Arm GetTrigger and GetTriggerCore seL4 invocations. This enables specs to correctly specify interrupt 111 | trigger mode and core affinities on Arm. 112 | * Add TCB Resume field to capDL object and support raw TCB object creation. 113 | * Add GitHub actions scripts. These scripts replicate internal CI checks directly on GitHub 114 | 115 | #### capDL-tool 116 | 117 | * rework validObjCap and check TCB slots, which allows vcpus for all architectures. 118 | * convert CapDL language specification to Markdown. 119 | 120 | #### Capdl-loader-app 121 | 122 | * Improve log output. 123 | * Initialise libc in debug builds. 124 | * Add check to only flush and invalidate kernel memory regions in capdl loader on Arm. Add platform_info header with 125 | memory window. 126 | * Add vcpu support for aarch64. 127 | * Handle IRQ binding to badged notifications properly: If an irq is bound to a notification with a non-zero badge, a 128 | badged capability is minted and used. Previously, the IRQ was bound to the unbadged notification. 129 | * Track number of used untypeds during object allocation and fail more gracefully if they run out. 130 | * Improve debugging printouts. 131 | * Fix issue where large DTB images inside BootInfo would overlap reserved memory address used to initialise frames. 132 | * Remove CONFIG_CAPDL_LOADER_ALLOW_NO_CSPACE config option as it has been unused for a while. 133 | 134 | #### Capdl-linker 135 | 136 | * Optimize spec generation performance: 137 | - Sort elf symbols by their vaddr. 138 | - Replace linear search with binary when looking for virtual addresses. 139 | * Fix Python syntax warnings when `capdl_linker.py` is invoked. 140 | 141 | --- 142 | 143 | ## 0.1.0 2019-11-19 144 | 145 | Using seL4 version 11.0.0 146 | 147 | ### Changes 148 | 149 | * Add GrantReply access right for endpoint capabilities. 150 | - This is a new right available on seL4 Endpoint object capabilities. 151 | - A capDL spec can now describe an endpoint capability with the 'P' GrantReply access right. 152 | - The capdl-loader-app will create capabilities with these rights based on the translated spec. 153 | - python-capdl-tool supports creating endpoint caps with GrantReply rights. 154 | * Add object_sizes target. 155 | - This target generates a YAML file describing the object size of each seL4 object. 156 | - It is based on the current build configuration of the kernel. 157 | - This file can be used as an input to tools performing allocation of seL4 objects from untypeds. 158 | * Add untyped_gen.py in cdl_utils. 159 | - This is only supported on Arm architectures currently. 160 | - This tool generates a predicted list of untypeds that the kernel will provide to userlevel 161 | - This list is calculated from an input of memory regions for the platform and sizes of the kernel image and device 162 | tree binary. 163 | - The list is intended to be used as an input for an allocator to perform allocation of initial system resources. 164 | * capDL untyped allocation 165 | - Add support for generating a capDL spec that specifies which untyped object each object and capability is allocated 166 | from. This is intended to be used when implementing trustworthy system initialisers as it removes online allocation 167 | decisions and results in a simpler init program. 168 | - This is only supported on Arm. 169 | * Static allocator 170 | - Updates capdl-loader-app to load static specs with all objects allocated from a predicted list of untypeds. 171 | - This simpler version of the loader app will act as a reference implementation for a more trustworthy implementation 172 | that is in development. 173 | - This is only supported on Arm. 174 | * RISC-V support added 175 | - Support for generating, translating and loading RISC-V applications. 176 | * seL4runtime updates 177 | - Port capdl-loader-app to sel4runtime 178 | * cdl-refine 179 | - This support is closely tied to CAmkES and L4V. 180 | - The capDL-tool can translate specs into Isabelle .thy file formats. These are then used to calculate which access 181 | rights different parts of the system have to each other. 182 | - It is used to check that the capDL system spec implements certain access policies as specified by an external 183 | source. 184 | - See cdl-refine in the context of CAmkES for more information. 185 | * 40-bit PA for aarch64 hyp 186 | - When seL4 is running in EL2 on aarch64, VSpace objects are an abstraction of stage 2 translations. 187 | These translations have different input address restrictions based on the physical address range the CPU supports. 188 | 40-bit PA support supports platforms that have 40-bit stage 2 input address ranges when in hyp-mode. 189 | * Remove --code-max-irqs from capDL tool 190 | - The capDL-tool that translates capDL formats no longer requires --code-max-irqs as an option for generating C specs. 191 | It now infers the total IRQs from the input spec and specifies this value in the generated C spec. 192 | * Add FrameFill mechanism for files and use this to implement ELF loading 193 | - The FrameFill mechanism allows Frame objects to be annotated with an attribute describing a way to initialise 194 | their contents by a loader. 195 | - The new file FrameFill mechanism allows frames to be initialised from the contents of a file provided to the loader 196 | in a cpio archive. 197 | - This mechanism is used to remove ELF loader support from the initialiser. Instead a spec describes how frames are 198 | initialised via copies from offsets into a provided ELF file. 199 | - This allows a loader to load program data from different file formats also. 200 | 201 | --- 202 | -------------------------------------------------------------------------------- /capDL-tool/doc/tex/sel4.sty: -------------------------------------------------------------------------------- 1 | % Copyright seL4 Project a Series of LF Projects, LLC 2 | % SPDX-License-Identifier: CC-BY-SA-4.0 3 | 4 | \NeedsTeXFormat{LaTeX2e} 5 | \ProvidesPackage{sel4}[2020/04/01 v0.5 seL4 Foundation letterhead and title page] 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % Letterhead and title page for the seL4 Foundation 9 | % 10 | % Written 2020-03-23 by Gernot Heiser 11 | % 12 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 | % 14 | % OPTIONS: 15 | % noBanner: no black banner underneath the logo 16 | % 17 | % 18 | % COMMANDS: 19 | % - INPUTS: 20 | % \title Document title in header, default: none 21 | % \author Document author, ignored if title is empty 22 | % \date Date of document, default \today, ignored if title is empty 23 | % \header Organisation/originator to go in TRHS of header, multiple lines 24 | % default: seL4 Foundation 25 | % \url Org URL, default: seL4 Foundation URL 26 | % \copyYear Year of copyright (default: this year) 27 | % - OUTPUTS: 28 | % \doCopyright Produces the copyright notice 29 | % 30 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 31 | 32 | % To Do: 33 | % - test \header, \url 34 | % - proper stacking of header 35 | 36 | \newif\ifb@nner\b@nnertrue 37 | 38 | %% options section 39 | \DeclareOption{noBanner}{\b@nnerfalse} 40 | 41 | \ProcessOptions\relax 42 | 43 | %% package section 44 | \RequirePackage[margin=25mm]{geometry} 45 | \RequirePackage{fancyhdr} 46 | \RequirePackage{enumitem} 47 | \RequirePackage{parskip} 48 | \RequirePackage{sfmath} 49 | \RequirePackage{graphicx} 50 | \usepackage[T1]{fontenc} 51 | \usepackage[sfdefault]{roboto} 52 | \RequirePackage{xcolor} 53 | % \RequirePackage[datesep=-,style=iso]{datetime2} 54 | \RequirePackage[iso]{isodate} 55 | 56 | \if@titlepage 57 | \typeout{have titlepage} 58 | \else 59 | \typeout{no titlepage} 60 | \fi 61 | 62 | %% Foundation colour scheme: 63 | \definecolor{greenLight}{HTML}{C0DF9A} 64 | \definecolor{greenLogo}{HTML}{96CA50} 65 | \definecolor{greenDark}{HTML}{668B37} 66 | \definecolor{accentLight}{HTML}{D5AEAA} 67 | \definecolor{accent}{HTML}{AC5D55} 68 | \definecolor{accentDark}{HTML}{820C00} 69 | \definecolor{emphasisLight}{HTML}{FFE0A2} 70 | \definecolor{emphasis}{HTML}{FFCA5F} 71 | \definecolor{emphasisDark}{HTML}{B78B41} 72 | % white (already defined) 73 | \definecolor{neutralLighter}{HTML}{D6DBE4} 74 | \definecolor{neutralLight}{HTML}{8897AE} 75 | \definecolor{neutral}{HTML}{385378} 76 | \definecolor{neutralDark}{HTML}{263852} 77 | % black (already defined) 78 | 79 | \colorlet{logoGreen}{greenLogo} 80 | \colorlet{seL4Green}{greenLogo} 81 | 82 | 83 | %% definitions 84 | \renewcommand{\familydefault}{\sfdefault} 85 | \def\h@eader{The seL4 Foundation\\\\} 86 | \def\u@rl{https://sel4.systems/Foundation} 87 | \def\@title{} 88 | \def\@subtitle{} 89 | \def\@author{} 90 | \def\@authortitle{} 91 | \def\@email{} 92 | \def\@docversion{} 93 | \def\@date{\today} 94 | \def\header#1{\def\h@eader{#1}} 95 | \def\title#1{\def\@title{#1}} 96 | \def\author#1{\def\@author{#1}} 97 | \def\authortitle#1{\def\@authortitle{#1}} 98 | \def\email#1{\def\@email{#1}} 99 | \def\docversion#1{\def\@docversion{#1}} 100 | \def\thedocversion{\@docversion} 101 | \def\date#1{\def\@date{#1}} 102 | \def\thedate{\value\@date} 103 | \def\thanks{\undefined} 104 | \newcommand{\subtitle}[1]{\def\@subtitle{#1}} 105 | \newcommand{\Logo@FileName}{imgs/logos/seL4-Foundation-logo.pdf} 106 | \newcommand{\Triang@FileName}{imgs/blacktriangle.pdf} 107 | \newcommand{\Key@FileName}{imgs/seL4-key.pdf} 108 | \newcommand{\L@ogo}{\includegraphics[keepaspectratio=true,height=23mm]{\Logo@FileName}} 109 | \newcommand{\K@ey}{\includegraphics[keepaspectratio=true,width=1.04\paperwidth]{\Key@FileName}} 110 | 111 | \newcommand{\doCopyright}[1][\the\year]{ 112 | Copyright \copyright~#1 seL4 Project a Series of LF Projects, LLC.\\ 113 | Distributed under the 114 | \href{https://creativecommons.org/licenses/by-sa/4.0/legalcode}{Creative 115 | Commons Attribution-ShareAlike 4.0 International (CC~BY-SA~4.0) License.}\\ 116 | seL4 is a trademark of LF Projects, LLC. 117 | } 118 | 119 | 120 | %% the main thing: \maketitle produces the letterhead 121 | 122 | \if@titlepage 123 | \renewcommand\maketitle{% 124 | \typeout{Starting \protect\maketitle} 125 | \noindent% 126 | \begin{titlepage}% 127 | \urlstyle{sf} 128 | % to suppress Overfull \hbox warnings 129 | \newlength{\saveHfuzz} 130 | \setlength{\saveHfuzz}{\hfuzz} 131 | \setlength{\hfuzz}{\paperwidth} 132 | % 133 | \let\footnotesize\small 134 | \let\footnoterule\relax 135 | \let \footnote \thanks 136 | % laying out the background 137 | \newlength{\img@raise} 138 | % the black triangle 139 | \setlength{\img@raise}{-\paperheight}% 140 | \addtolength{\img@raise}{\Gm@tmargin}% 141 | \addtolength{\img@raise}{4mm}% don't ask me why! 142 | % \typeout{paperheight=\the\paperheight, 143 | % paperwidth=\the\paperwidth, 144 | % Gm@lmargin=\Gm@lmargin, 145 | % Gm@tmargin=\Gm@tmargin, 146 | % img@raise=\the\img@raise, 147 | % hfuzz=\the\hfuzz} 148 | \raisebox{\img@raise}[0pt][0pt]{\hspace*{-\Gm@lmargin}% 149 | \makebox[0pt][l]{% 150 | \includegraphics[keepaspectratio=false,width=\paperwidth,height=\paperheight]{\Triang@FileName}% 151 | }% 152 | } 153 | % header 154 | \raisebox{4mm}[0pt][0pt]{\hspace*{-\Gm@tmargin}% 155 | \begin{minipage}[b]{\paperwidth}% 156 | \hspace*{22mm}% 157 | \raisebox{2.5mm}[38mm][0mm]{\L@ogo}% 158 | \hfill 159 | \raisebox{4mm}{% 160 | \footnotesize% 161 | \textcolor{greenLogo}{ 162 | \begin{tabular}[b]{r}\bf 163 | \h@eader\\ 164 | % force URL colour to be green or black, irrespective of hyperref setup 165 | \bf\href{\u@rl}{\textcolor{\ifb@nner greenLogo\else black\fi}\u@rl} 166 | \end{tabular} 167 | } 168 | }\hspace*{5mm} 169 | % key 170 | \setlength{\img@raise}{-\paperheight}% 171 | \addtolength{\img@raise}{\Gm@tmargin}% 172 | \addtolength{\img@raise}{-4mm}% don't ask me why! 173 | \raisebox{\img@raise}[0pt][0pt]{% 174 | \makebox[0pt][r]{% 175 | \K@ey% 176 | }% 177 | }% 178 | \end{minipage}% 179 | }% 180 | % 181 | \null%\vfil 182 | % \vskip 60\p@ 183 | \raggedright% to prevent stuff shifting 184 | \vskip 50mm% 185 | ~\hfill% 186 | \makebox[0pt][r]{ 187 | \raisebox{0pt}[0pt][0pt]{ 188 | \begin{minipage}{150mm} 189 | \raggedleft 190 | \fontsize{36}{42}\selectfont \textcolor{greenLogo}{\@title}\\% 191 | \if\@subtitle\empty 192 | ~ 193 | \else 194 | \fontsize{36}{42}\selectfont \textcolor{emphasis}{\@subtitle} 195 | \fi% 196 | \end{minipage} 197 | \hspace*{-10mm} 198 | } 199 | } 200 | \vskip 70mm 201 | \makebox[0pt][l]{ 202 | \hspace*{-13mm} 203 | \raisebox{0pt}[0pt][0pt]{ 204 | \begin{minipage}{70mm}% 205 | \raggedright% 206 | \color{neutral} 207 | \fontsize{20}{26}\selectfont% 208 | \@author\par 209 | \fontsize{14}{22}\selectfont% 210 | \ifx\@authortitle\empty\else\@authortitle\par\fi 211 | \ifx\@email\empty\else\@email\par\fi 212 | \ifx\@docversion\empty\else\@docversion\par\fi 213 | \ifx\@date\empty\else\@date\par\fi 214 | \end{minipage} 215 | } 216 | } 217 | \setcounter{page}{0} 218 | \end{titlepage}% 219 | \thispagestyle{fancyplain} 220 | \setlength{\hfuzz}{\saveHfuzz}% 221 | \setcounter{footnote}{0}% 222 | \global\let\thanks\relax 223 | \global\let\maketitle\relax 224 | \global\let\@thanks\@empty 225 | \global\let\@author\@empty 226 | \global\let\@date\@empty 227 | \global\let\@title\@empty 228 | \global\let\title\relax 229 | \global\let\author\relax 230 | \global\let\date\relax 231 | \global\let\and\relax 232 | \setcounter{page}{0} 233 | \typeout{Finish \protect\maketitle} 234 | } 235 | \else% no titlepage 236 | \def\maketitle{\urlstyle{sf} 237 | % to suppress overfull bars in ``draft'' mode: 238 | \newlength{\saveOverfullRule} 239 | \setlength{\saveOverfullRule}{\overfullrule} 240 | \setlength\overfullrule{0pt} 241 | % 242 | \noindent% 243 | \raisebox{0mm}[0pt][0pt]{\hspace*{-25mm}% 244 | \ifb@nner\makebox[0pt][l]{\rule{\paperwidth}{40mm}}\fi% black banner 245 | \begin{minipage}[b]{\paperwidth}% 246 | \hspace*{16mm}% 247 | \raisebox{2.5mm}[38mm][0mm]{\L@ogo}% 248 | \hfill 249 | \raisebox{4mm}{% 250 | \footnotesize% 251 | \textcolor{\ifb@nner greenLogo\else black\fi}{ 252 | \begin{tabular}[b]{r}\bf 253 | \h@eader\\ 254 | % force URL colour to be green or black, irrespective of hyperref setup 255 | \bf\href{\u@rl}{\textcolor{\ifb@nner greenLogo\else black\fi}\u@rl} 256 | \end{tabular} 257 | } 258 | }\hspace*{5mm} 259 | \end{minipage}% 260 | }% 261 | % reset overfull rule 262 | \setlength{\overfullrule}{\saveOverfullRule}% 263 | % \@maketitle 264 | \vspace*{12mm}% 265 | \ifx\@title\empty \else% 266 | \begin{center} 267 | {\LARGE\bf\@title\\[1ex]} 268 | \ifx\@subtitle\empty \else{\Large\@subtitle} \\[1ex]\fi% 269 | \ifx\@author\empty \else{\Large\@author\\[2ex]} \fi% 270 | \ifx\@date\empty \else\@date \\\fi% 271 | \vspace{5ex}% 272 | \end{center}% 273 | \fi% 274 | }%\maketitle 275 | \fi% no titlepage 276 | -------------------------------------------------------------------------------- /capDL-tool/CapDL/PrintXml.hs: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | -- 4 | -- SPDX-License-Identifier: BSD-2-Clause 5 | -- 6 | module CapDL.PrintXml (printXml) where 7 | 8 | import CapDL.Model 9 | import CapDL.PrintUtils 10 | 11 | import Prelude () 12 | import Prelude.Compat 13 | import Text.PrettyPrint 14 | import Data.Maybe (fromMaybe) 15 | import qualified Data.Map as Map 16 | import qualified Data.Set as Set 17 | 18 | indent = 4 19 | 20 | -- XML header 21 | xml_header = "" 22 | 23 | -- 24 | -- Convert a list of key/value pairs into an XML tag attribute string. 25 | -- 26 | -- > showXmlAttrsString [("name", "rover"), ("colour", "red")] 27 | -- 'name="rover" colour="red"' 28 | -- 29 | showXmlAttrsString :: [(String, String)] -> String 30 | showXmlAttrsString attrs = foldl (\a b -> a ++ " " ++ b) "" joinedAttrs 31 | where 32 | joinedAttrs = (map (\(a, b) -> a ++ "=\"" ++ b ++ "\"") attrs) 33 | 34 | -- 35 | -- Create an XML opening tag, filled with the given attributes. 36 | -- 37 | openTag :: String -> [(String, String)] -> String 38 | openTag x [] = "<" ++ x ++ ">" 39 | openTag x attrs = "<" ++ x ++ attrsString ++ ">" 40 | where 41 | attrsString = showXmlAttrsString attrs 42 | 43 | -- 44 | -- Create an XML closing tag. 45 | -- 46 | closeTag :: String -> String 47 | closeTag x = "" 48 | 49 | -- 50 | -- Create an empty XML tag. 51 | -- 52 | emptyTag :: String -> [(String, String)] -> String 53 | emptyTag x [] = "<" ++ x ++ " />" 54 | emptyTag x attrs = "<" ++ x ++ attrsString ++ " />" 55 | where 56 | attrsString = showXmlAttrsString attrs 57 | 58 | -- 59 | -- Surround the given document with the given tag. 60 | -- 61 | xmlSurround :: String -> [(String, String)] -> Doc -> Doc 62 | xmlSurround tag attrs details = 63 | (text (openTag tag attrs)) $+$ (nest indent details) $+$ (text (closeTag tag)) 64 | 65 | showCapRef :: CapRef -> String 66 | showCapRef (obj, slot) = "(" ++ showID obj ++ ", " ++ show slot ++ ")" 67 | 68 | -- 69 | -- Convert CapRights into a string. 70 | -- 71 | showRights :: CapRights -> String 72 | showRights rights = readRight ++ writeRight ++ grantRight ++ grantReplyRight 73 | where 74 | readRight = if Read `Set.member` rights then "r" else "" 75 | writeRight = if Write `Set.member` rights then "w" else "" 76 | grantRight = if Grant `Set.member` rights then "g" else "" 77 | grantReplyRight = if GrantReply `Set.member` rights then "p" else "" 78 | 79 | -- 80 | -- Get an object's attributes. 81 | -- 82 | showObjectAttrs :: KernelObject a -> [(String, String)] 83 | showObjectAttrs (TCB _ _ _ domain _) = [("domain", show domain)] 84 | showObjectAttrs (CNode _ sz) = [("size", show sz)] 85 | showObjectAttrs (Untyped (Just sz) paddr) = [("size", show sz), ("paddr", show $ fromMaybe 0 paddr)] 86 | showObjectAttrs (Frame sz paddr _) = [("size", show sz), ("paddr", show $ fromMaybe 0 paddr)] 87 | showObjectAttrs (IOPorts sz) = [("size", show sz)] 88 | showObjectAttrs (IODevice _ dom pci) = [("domain", show dom), ("device", show pci)] 89 | showObjectAttrs (ARMIODevice _ iospace) = [("iospace", show iospace)] 90 | showObjectAttrs (IOPT _ level) = [("level", show level)] 91 | showObjectAttrs (ARMSGISignal irq target) = [("irq", show irq), ("target", show target)] 92 | showObjectAttrs _ = [] 93 | 94 | -- 95 | -- Get an object's name. 96 | -- 97 | showObjectName :: KernelObject a -> String 98 | showObjectName Endpoint = "Endpoint" 99 | showObjectName Notification = "Notification" 100 | showObjectName TCB {} = "TCB" 101 | showObjectName CNode {} = "CNode" 102 | showObjectName Untyped {} = "Untyped" 103 | showObjectName ASIDPool {} = "ASIDPool" 104 | showObjectName PT {} = "PT" 105 | showObjectName PD {} = "PD" 106 | showObjectName PDPT {} = "PDPT" 107 | showObjectName PML4 {} = "PML4" 108 | showObjectName PUD {} = "PUD" 109 | showObjectName PGD {} = "PGD" 110 | showObjectName Frame {} = "Frame" 111 | showObjectName IOPorts {} = "IOPorts" 112 | showObjectName IODevice {} = "IODevice" 113 | showObjectName ARMIODevice {} = "ARMIODevice" 114 | showObjectName IOPT {} = "IOPT" 115 | showObjectName VCPU {} = "VCPU" 116 | showObjectName SC {} = "SC" 117 | showObjectName RTReply {} = "RTReply" 118 | showObjectName IOAPICIrq {} = "IOAPICIrq" 119 | showObjectName MSIIrq {} = "MSIIrq" 120 | showObjectName ARMIrq {} = "ARMIrq" 121 | showObjectName ARMSID {} = "ARMSID" 122 | showObjectName ARMCB {} = "ARMCB" 123 | showObjectName ARMSMC = "ARMSMC" 124 | showObjectName ARMSGISignal {} = "ARMSGISignal" 125 | 126 | -- 127 | -- Get a cap's name. 128 | -- 129 | showCapName :: Cap -> String 130 | showCapName NullCap = "NullCap" 131 | showCapName UntypedCap {} = "UntypedCap" 132 | showCapName EndpointCap {} = "EndpointCap" 133 | showCapName NotificationCap {} = "NotificationCap" 134 | showCapName ReplyCap {} = "ReplyCap" 135 | showCapName MasterReplyCap {} = "MasterReplyCap" 136 | showCapName CNodeCap {} = "CNodeCap" 137 | showCapName TCBCap {} = "TCBCap" 138 | showCapName IRQControlCap = "IRQControlCap" 139 | showCapName IRQHandlerCap {} = "IRQHandlerCap" 140 | showCapName IRQIOAPICHandlerCap {} = "IRQIOAPICHandlerCap" 141 | showCapName IRQMSIHandlerCap {} = "IRQMSIHandlerCap" 142 | showCapName ARMIRQHandlerCap {} = "ARMIRQHandlerCap" 143 | showCapName DomainCap = "DomainCap" 144 | showCapName FrameCap {} = "FrameCap" 145 | showCapName PTCap {} = "PTCap" 146 | showCapName PDCap {} = "PDCap" 147 | showCapName PDPTCap {} = "PDPTCap" 148 | showCapName PML4Cap {} = "PML4Cap" 149 | showCapName PUDCap {} = "PUDCap" 150 | showCapName PGDCap {} = "PGDCap" 151 | showCapName ASIDControlCap = "ASIDControlCap" 152 | showCapName ASIDPoolCap {} = "ASIDPoolCap" 153 | showCapName IOPortsCap {} = "IOPortsCap" 154 | showCapName IOSpaceMasterCap = "IOSpaceMasterCap" 155 | showCapName IOSpaceCap {} = "IOSpaceCap" 156 | showCapName ARMIOSpaceCap {} = "ARMIOSpaceCap" 157 | showCapName IOPTCap {} = "IOPTCap" 158 | showCapName VCPUCap {} = "VCPUCap" 159 | showCapName SCCap {} = "SCCap" 160 | showCapName RTReplyCap {} = "RTReplyCap" 161 | showCapName SchedControlCap {} = "SchedControlCap" 162 | showCapName ARMSIDCap {} = "ARMSIDCap" 163 | showCapName ARMCBCap {} = "ARMCBCap" 164 | showCapName ARMSMCCap {} = "ARMSMCCap" 165 | showCapName ARMSGISignalCap {} = "ARMSGISignalCap" 166 | 167 | showExtraCapAttributes :: Cap -> [(String, String)] 168 | showExtraCapAttributes (EndpointCap _ capBadge _) = [("badge", show capBadge)] 169 | showExtraCapAttributes (NotificationCap _ capBadge _) = [("badge", show capBadge)] 170 | showExtraCapAttributes (ARMSMCCap _ capBadge) = [("badge", show capBadge)] 171 | showExtraCapAttributes (CNodeCap _ guard guardSize) = 172 | [("guard", show guard), ("guardSize", show guardSize)] 173 | showExtraCapAttributes (FrameCap _ _ _ False _) = [("cached", "False")] 174 | showExtraCapAttributes _ = [] 175 | 176 | -- 177 | -- Print the XML for the given cap. 178 | -- 179 | printCapXml :: (Word, Cap) -> Doc 180 | printCapXml (location, cap) = 181 | text (emptyTag "cap" (captype ++ slot ++ target ++ rights ++ attrs)) 182 | where 183 | slot = [("slot", show location)] 184 | captype = [("type", showCapName cap)] 185 | target = if hasObjID cap then [("id", showID (objID cap))] else [("id", "global" ++ showCapName cap)] 186 | rights = if hasRights cap then [("rights", showRights (capRights cap))] else [] 187 | attrs = showExtraCapAttributes cap 188 | 189 | -- 190 | -- Print the XML for a CapMap 191 | -- 192 | printCapMap :: CapMap Word -> Doc 193 | printCapMap x = 194 | vcat (map printCapXml (Map.toList x)) 195 | 196 | -- 197 | -- Print an object that just has a name and some simple attributes. 198 | -- 199 | printSimpleObject :: KernelObject Word -> ObjID -> [(String, String)] -> Doc 200 | printSimpleObject object objId attrs = 201 | if hasSlots object then 202 | (xmlSurround "object" all_attrs $ printCapMap (slots object)) 203 | else 204 | text (emptyTag "object" all_attrs) 205 | where 206 | all_attrs = [("id", showID objId), ("type", showObjectName object)] ++ attrs 207 | 208 | -- 209 | -- Print the given object. 210 | -- 211 | printObject :: (ObjID, KernelObject Word) -> Doc 212 | printObject (objId, object) = 213 | printSimpleObject object objId (showObjectAttrs object) 214 | 215 | -- Print the contents of all objects in the given heap. 216 | printObjects :: ObjMap Word -> Doc 217 | printObjects x = 218 | xmlSurround "objects" [] $ vcat (map printObject (Map.toList x)) 219 | 220 | printCovered :: [ObjID] -> Doc 221 | printCovered objs = 222 | xmlSurround "covered" [] ids 223 | where ids = vcat $ map text $ map (\obj -> emptyTag "id" [("id", showID obj)]) objs 224 | 225 | printCover :: (ObjID, [ObjID]) -> Doc 226 | printCover (untyped, cover) = 227 | xmlSurround "cover" [("untyped", showID untyped)] $ printCovered cover 228 | 229 | printUntypedCovers :: CoverMap -> Doc 230 | printUntypedCovers untypedCovers = 231 | xmlSurround "untypedCovers" [] $ vcat (map printCover (Map.toList untypedCovers)) 232 | 233 | printCDTRelation :: (CapRef, CapRef) -> Doc 234 | printCDTRelation (child, parent) = 235 | text $ emptyTag "cdtRelation" [("child", showCapRef child), ("parent", showCapRef parent)] 236 | 237 | printCDT :: CDT -> Doc 238 | printCDT cdt = 239 | xmlSurround "cdt" [] $ vcat (map printCDTRelation (Map.toList cdt)) 240 | 241 | -- Print the contents of a model in XML format. 242 | printXml :: String -> Model Word -> Doc 243 | printXml _ (Model arch ms _ cdt untypedCovers) = 244 | text xml_header 245 | $+$ (xmlSurround "model" [("arch", show arch)] $ printObjects ms $+$ printUntypedCovers untypedCovers $+$ printCDT cdt) 246 | $+$ text "\n" 247 | -------------------------------------------------------------------------------- /capDL-tool/CapDL/PrintDot.hs: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | -- 4 | -- SPDX-License-Identifier: BSD-2-Clause 5 | -- 6 | 7 | {-# LANGUAGE FlexibleInstances #-} 8 | 9 | module CapDL.PrintDot where 10 | 11 | import CapDL.Model 12 | import CapDL.PrintUtils 13 | import Prelude () 14 | import Prelude.Compat hiding ((<>)) 15 | import Text.PrettyPrint 16 | import Data.List.Compat 17 | import qualified Data.Map as Map 18 | 19 | indent = 2 20 | 21 | type NodeMap = Map.Map ObjID String 22 | 23 | class (Printing a) => DotPrinting a where 24 | dotRange :: a -> Int -> Doc 25 | 26 | instance DotPrinting Word where 27 | dotRange n 1 = num n 28 | dotRange n len = num n <> text " - " <> num (n + fromIntegral len - 1) 29 | 30 | instance DotPrinting [Word] where 31 | dotRange ns 1 = num ns 32 | dotRange [n] len = dotRange n len 33 | dotRange ns len = 34 | let n = last ns 35 | in num (init ns) <> comma <+> dotRange n len 36 | 37 | angles :: String -> Doc 38 | angles st = text ("<" ++ st ++ ">") 39 | 40 | getName :: ObjID -> NodeMap -> String 41 | getName id names = 42 | case Map.lookup id names of 43 | Just name -> name 44 | Nothing -> error $ "Something weird happened when printing: " ++ showID id 45 | 46 | getObject :: ObjMap a -> ObjID -> KernelObject a 47 | getObject ms id = 48 | let Just obj = Map.lookup id ms 49 | in obj 50 | 51 | sameNode :: NodeMap -> ObjID -> ObjID -> Bool 52 | sameNode names first second = getName first names == getName second names 53 | 54 | dotObjParams :: KernelObject a -> Doc 55 | dotObjParams obj = text " \\n " <> prettyObjParams obj 56 | 57 | hasCover :: ObjID -> CoverMap -> Bool 58 | hasCover ut covers = 59 | case Map.lookup ut covers of 60 | Nothing -> False 61 | Just cover -> not $ null cover 62 | 63 | dotCovered :: NodeMap -> ObjMap a -> CoverMap -> [ObjID] -> [Doc] 64 | dotCovered _ _ _ [] = [] 65 | dotCovered names ms covers list@(id:_) 66 | | hasCover id covers = 67 | dotUntyped names ms covers [] id [Nothing] obj: 68 | dotCovered names ms covers (drop (length same) list) 69 | | otherwise = 70 | (doubleQuotes.text) (getName id names) <> semi: 71 | dotCovered names ms covers (drop (length same) list) 72 | where 73 | same = takeWhile (sameNode names id) list 74 | obj = getObject ms id 75 | 76 | -- Minor problem if a covered object has a cap to the untyped 77 | dotCluster :: NodeMap -> ObjMap a -> CoverMap -> ObjID -> [Maybe Word] -> 78 | [ObjID] -> Doc 79 | dotCluster names ms covers n _ cover = 80 | text "subgraph" <+> (doubleQuotes.text) ("cluster_" ++ getName n names) <+> 81 | braces (braces (text "rank = source;" <+> (doubleQuotes.text) (getName n names) 82 | <+> text "[style = filled];") <> semi <+> 83 | hsep (dotCovered names ms covers cover)) <> semi 84 | 85 | getCover :: ObjID -> CoverMap -> [ObjID] 86 | getCover ut covers = 87 | case Map.lookup ut covers of 88 | Nothing -> [] 89 | Just cover -> cover 90 | 91 | dotUntyped :: NodeMap -> ObjMap a -> CoverMap -> [ObjID] -> ObjID -> 92 | [Maybe Word] -> KernelObject a -> Doc 93 | dotUntyped names ms covers cov id@(n, _) range obj@(Untyped {}) = 94 | if id `notElem` cov 95 | then if null cover 96 | then (doubleQuotes.text) (getName id names) <+> brackets (text "label =" 97 | <+> doubleQuotes (braces (angles "name" <+> text n 98 | <> prettyBrackets range <> dotObjParams obj))) <> semi 99 | else dotCluster names ms covers id range cover 100 | else empty 101 | where cover = getCover id covers 102 | dotUntyped _ _ _ _ _ _ _ = empty 103 | 104 | --Do we want the port to be s 105 | dotEdge :: DotPrinting a => NodeMap -> a -> Cap -> ObjID -> Doc 106 | dotEdge names slot cap n = 107 | (doubleQuotes.text) (getName n names) <> text (":\"t" ++ show slot ++ "\"") 108 | <> text ":s ->" <+> (doubleQuotes.text) (getName (objID cap) names) 109 | <> text ":Object" <> semi 110 | 111 | sameHeadNode :: NodeMap -> (a, Cap) -> (a, Cap) -> Bool 112 | sameHeadNode names (_, first) (_, second) = 113 | sameNode names (objID first) (objID second) 114 | 115 | dotEdges :: DotPrinting a => NodeMap -> [(a, Cap)] -> a -> ObjID -> Doc 116 | dotEdges _ [] _ _ = empty 117 | dotEdges names list@(first@(_, cap):_) slot n = 118 | dotEdge names slot cap n $+$ dotEdges names others slot n 119 | where (_,others) = partition (sameHeadNode names first) list 120 | 121 | dotEdgesList :: DotPrinting a => NodeMap -> [(a, Cap)] -> ObjID -> [Doc] 122 | dotEdgesList _ [] _ = [] 123 | dotEdgesList names list@((slot, cap):xs) name = 124 | if hasObjID cap 125 | then dotEdges names sameGroup slot name: 126 | dotEdgesList names (drop (length sameGroup) list) name 127 | else dotEdgesList names xs name 128 | where sameGroup = sameArray list 129 | 130 | dotTop :: DotPrinting a => a -> Int -> Doc 131 | dotTop n len = angles ("a" ++ show n) <+> dotRange n len 132 | 133 | dotBot :: DotPrinting a => a -> Cap -> [Maybe Word] -> Doc 134 | dotBot n cap range = angles ("t" ++ show n) <+> 135 | prettyBrackets range <+> maybeCapParams cap 136 | 137 | dotSlot :: DotPrinting a => (a, Cap) -> [Maybe Word] -> Doc 138 | dotSlot (n, cap) range = text "|" <> 139 | braces (dotTop n (length range) <+> text "|" <+> dotBot n cap range) 140 | 141 | dotSlotsRange :: DotPrinting a => [(a, Cap)] -> Doc 142 | dotSlotsRange [] = error "dotSlotsRange: empty" 143 | dotSlotsRange list@(x:_) = 144 | dotSlot x (map (snd.objID.snd) list) 145 | 146 | dotSlotsList :: DotPrinting a => [(a, Cap)] -> [Doc] 147 | dotSlotsList [] = [] 148 | dotSlotsList list@(first@(_, cap):xs) = 149 | if hasObjID cap 150 | then dotSlotsRange sameGroup:dotSlotsList (drop (length sameGroup) list) 151 | else (dotSlot first [Nothing]):(dotSlotsList xs) 152 | where sameGroup = sameArray list 153 | 154 | dotNodeHead :: ObjID -> KernelObject a -> [Maybe Word] -> Doc 155 | dotNodeHead (name, _) obj range = 156 | text "label" <+> equals <+> text "\"" <> 157 | braces (angles "Object" <+> text name <> prettyBrackets range 158 | <> dotObjParams obj) 159 | 160 | dotNode :: DotPrinting a => NodeMap -> ObjMap a -> CoverMap -> [ObjID] 161 | -> (ObjID, KernelObject a) -> [Maybe Word] -> Doc 162 | dotNode names ms covers cov (n, obj) range = 163 | let xs = (if hasSlots obj then Map.toList $ slots obj else []) 164 | in nest indent ((doubleQuotes.text) (getName n names) <+> 165 | brackets (dotNodeHead n obj range <> hcat (dotSlotsList xs) 166 | <> text "\"") <> semi $+$ nest indent (vcat (dotEdgesList names xs n) 167 | $+$ if hasCover n covers 168 | then dotUntyped names ms covers cov n range obj 169 | else empty)) 170 | 171 | dotNodesGroup :: DotPrinting a => NodeMap -> ObjMap a -> CoverMap -> [ObjID] 172 | -> [(ObjID, KernelObject a)] -> Doc 173 | dotNodesGroup names ms covers cov list = 174 | dotNode names ms covers cov (head list) (map (snd.fst) list) 175 | 176 | dotNodesList :: DotPrinting a => NodeMap -> ObjMap a -> CoverMap -> [ObjID] 177 | -> [(ObjID, KernelObject a)] -> [Doc] 178 | dotNodesList _ _ _ _ [] = [] 179 | dotNodesList names ms covers cov list@(first:_) = 180 | dotNodesGroup names ms covers cov sameCaps: 181 | dotNodesList names ms covers cov otherCaps 182 | where (sameCaps, otherCaps) = 183 | partition (\tuple -> sameNode names (fst first) (fst tuple)) list 184 | 185 | dotNodes :: DotPrinting a => NodeMap -> ObjMap a -> CoverMap -> [ObjID] 186 | -> [(ObjID, KernelObject a)] -> Doc 187 | dotNodes names ms covers covered list = 188 | (vcat (dotNodesList names ms covers covered list)) $+$ text "" 189 | 190 | getCovered :: ObjMap a -> CoverMap -> [ObjID] -> [ObjID] 191 | getCovered _ _ [] = [] 192 | getCovered ms covers (x:xs) 193 | | hasCover x covers = x : getCovered ms covers xs 194 | | otherwise = getCovered ms covers xs 195 | 196 | getCovUntyped :: ObjMap a -> CoverMap -> [ObjID] 197 | getCovUntyped ms covers = 198 | concat $ Map.elems $ 199 | Map.map (\cover -> getCovered ms covers cover) covers 200 | 201 | initCovNamesGroup :: NodeMap -> [ObjID] -> NodeMap 202 | initCovNamesGroup names list = 203 | foldl (\map id -> Map.insert id ("cov_" ++ showID (head list)) map) 204 | names list 205 | 206 | initCovNamesCovered :: NodeMap -> [ObjID] -> NodeMap 207 | initCovNamesCovered names cover = 208 | foldl initCovNamesGroup names $ groupBy (sameNode names) cover 209 | 210 | initCovNames :: NodeMap -> CoverMap -> NodeMap 211 | initCovNames names covers = 212 | foldl initCovNamesCovered names 213 | (map snd (Map.toList covers)) 214 | 215 | initNamesGroup :: NodeMap -> [ObjID] -> NodeMap 216 | initNamesGroup names list = 217 | foldl (\map id -> Map.insert id (showID (head list)) map) names list 218 | 219 | initNamesList :: DotPrinting a => NodeMap -> [(ObjID, KernelObject a)] -> NodeMap 220 | initNamesList _ [] = Map.empty 221 | initNamesList names list@(first:_) = 222 | Map.union (initNamesGroup names (map fst sameCaps)) 223 | (initNamesList names otherCaps) 224 | where (sameCaps, otherCaps) = partition (same first) list 225 | 226 | initNames :: DotPrinting a => [(ObjID, KernelObject a)] -> NodeMap 227 | initNames = initNamesList Map.empty 228 | 229 | dotLabel :: Arch -> Doc 230 | dotLabel arch = text "fontsize = 30; labelloc = top; label = \"arch" 231 | <+> prettyArch arch <> text "\";" 232 | 233 | -- nodesep? ranksep? page? concentrate? minlen? fontsize? 234 | dotAttributes :: Doc 235 | dotAttributes = text "nodesep = 0.5; ranksep = 3;" 236 | $+$ text "node [shape = record]; edge [minlen = 2];" $+$ text "" 237 | 238 | dotHeader :: String -> Doc 239 | dotHeader name = text "digraph" <+> doubleQuotes (text name) 240 | <+> lbrace $+$ dotAttributes 241 | 242 | printDot' :: DotPrinting a => String -> Arch -> ObjMap a -> CoverMap -> Doc 243 | printDot' name arch ms covers = 244 | let list = (Map.toList ms) 245 | names = initNames list 246 | names' = initCovNames names covers 247 | covered = getCovUntyped ms covers 248 | in dotHeader name $+$ 249 | dotNodes names' ms covers covered list $+$ 250 | dotLabel arch $+$ 251 | rbrace 252 | 253 | printDot :: DotPrinting a => String -> Model a -> Doc 254 | printDot name (Model arch ms _ _ untypedCovers) = 255 | printDot' name arch ms untypedCovers 256 | -------------------------------------------------------------------------------- /python-capdl-tool/capdl/ELF.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | # 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | """ 8 | Functionality related to handling ELF file input. This is the only section of 9 | this module that relies on elftools, so it is possible to use this module 10 | without elftools installed by not importing this particular file. 11 | """ 12 | from __future__ import absolute_import, division, print_function, \ 13 | unicode_literals 14 | from future.utils import iteritems 15 | 16 | from elftools.elf.elffile import ELFFile 17 | from elftools.elf.constants import P_FLAGS 18 | from .Object import TCB 19 | from .util import PAGE_SIZE, round_down, page_sizes 20 | from .PageCollection import PageCollection 21 | import os 22 | import re 23 | import six 24 | 25 | 26 | def _decode(data): 27 | ''' 28 | Decode ambiguous data retrieved from an ELF file. 29 | 30 | Depending on the version of Python we are running, we may wind up with 31 | ascii strings, UTF-8 or byte arrays. Only ASCII data can appear in ELF 32 | files in places we are expecting text (this is not strictly true, but 33 | `pyelftools` makes this assumption internally, so we may as well stick to 34 | that) so we decode any byte array as ASCII. 35 | ''' 36 | if isinstance(data, bytes): 37 | return data.decode('ascii') 38 | return data 39 | 40 | 41 | class ELF(object): 42 | def __init__(self, elf, name='', arch=None): 43 | """ 44 | This constructor is overloaded and can accept either a string as the 45 | parameter 'elf', or a stream to ELF data. 'name' is only used when 46 | generating CapDL from the ELF file. 47 | """ 48 | if isinstance(elf, six.string_types): 49 | f = open(elf, 'rb') 50 | else: 51 | f = elf 52 | self._elf = ELFFile(f) 53 | self.name = name 54 | self._symtab = None 55 | self.arch = arch or self.get_arch() 56 | 57 | def get_entry_point(self): 58 | return self._elf['e_entry'] 59 | 60 | def _get_symbol(self, symbol): 61 | 62 | # If possible, let elftools do all the work. 63 | if hasattr(self._elf, 'get_symbol_by_name'): 64 | # From 46ae4bd this functionality is in elftools. 65 | sym = self._elf.get_symbol_by_name(symbol) 66 | if isinstance(sym, list): 67 | # From 9da4c45 get_symbol_by_name returns a list. 68 | return sym[0] 69 | return sym 70 | 71 | if self._symtab is None: 72 | table = self._elf.get_section_by_name('.symtab') 73 | if not table: 74 | # This ELF file has been stripped. 75 | raise Exception('No symbol table available') 76 | self._symtab = dict([(s.name, s) for s in table.iter_symbols()]) 77 | 78 | return self._symtab.get(symbol) 79 | 80 | def get_symbol_vaddr(self, symbol): 81 | sym = self._get_symbol(symbol) 82 | if sym: 83 | return sym['st_value'] 84 | return None 85 | 86 | def get_symbol_size(self, symbol): 87 | sym = self._get_symbol(symbol) 88 | if sym: 89 | return sym['st_size'] 90 | return None 91 | 92 | def _safe_name(self): 93 | """ 94 | Replace characters that the CapDL tools parse differently. 95 | """ 96 | return re.sub(r'[^A-Za-z0-9]', '_', self.name) 97 | 98 | def get_arch(self): 99 | return self._elf.get_machine_arch() 100 | 101 | def check_alignment(self, regions): 102 | for (vaddr, sizes, caps) in regions: 103 | for size in sizes: 104 | assert vaddr % size == 0, "vaddr: 0x%x is not aligned to frame_size: 0x%x" % ( 105 | vaddr, size) 106 | vaddr += size 107 | 108 | def regions_in_segment(self, segment, regions): 109 | seg_start = segment['p_vaddr'] 110 | seg_size = segment['p_memsz'] 111 | seg_end = seg_start + seg_size 112 | regions_return = [] 113 | for (vaddr, sizes, caps) in regions: 114 | for size in sizes: 115 | if vaddr >= (seg_end) or (vaddr+size) < seg_start: 116 | pass 117 | else: 118 | assert vaddr >= seg_start and ( 119 | vaddr + size) <= seg_end, "Regions overlap segments which is not allowed" 120 | regions_return.append((vaddr, size)) 121 | vaddr += size 122 | return regions_return 123 | 124 | def compute_elf_fill_frame(self, vaddr, size, seg_p_vaddr, seg_p_filesz, seg_p_offset): 125 | dest_offset = 0 if vaddr >= seg_p_vaddr else seg_p_vaddr - vaddr 126 | assert dest_offset < size, "There is no section in this frame: %p" % vaddr 127 | 128 | target_vaddr_start = vaddr + dest_offset 129 | section_offset = target_vaddr_start - seg_p_vaddr 130 | if section_offset >= seg_p_filesz: 131 | # Past the end of the data to load 132 | return [] 133 | # length to copy 134 | length = min(size-dest_offset, seg_p_filesz-section_offset) 135 | src_offset = seg_p_offset + section_offset 136 | 137 | return ["%d %d CDL_FrameFill_FileData \"%s\" %d" % (dest_offset, length, self.name, src_offset)] 138 | 139 | def get_pages(self, infer_asid=True, pd=None, use_large_frames=True, addr_space=None): 140 | """ 141 | Returns a dictionary of pages keyed on base virtual address, that are 142 | required to ELF load this file. Each dictionary entry is a dictionary 143 | containing booleans 'read', 'write' and 'execute' for the permissions 144 | of the page. 145 | """ 146 | pages = PageCollection(self._safe_name(), self.arch, infer_asid, pd) 147 | 148 | # We assume that this array contains aligned vaddrs and sizes that are frame sizes 149 | existing_pages = [] 150 | if addr_space: 151 | # Update symbols with their vaddrs in the AddressSpaceAllocator if we were given one 152 | for (symbol, (sizes, caps)) in iteritems(addr_space.get_symbols_and_clear()): 153 | assert self.get_symbol_size(symbol) >= sum(sizes), \ 154 | "Symbol (%s:%d) must have same or greater size than supplied cap range (%d)" % ( 155 | symbol, self.get_symbol_size(symbol), sum(sizes)) 156 | existing_pages.append((self.get_symbol_vaddr(symbol), sizes, caps)) 157 | 158 | existing_pages.sort(key=lambda phys_addr: phys_addr[0]) 159 | self.check_alignment(existing_pages) 160 | for (vaddr, sizes, caps) in existing_pages: 161 | addr_space.add_region_with_caps(vaddr, sizes, caps) 162 | 163 | for seg in self._elf.iter_segments(): 164 | if not seg['p_type'] == 'PT_LOAD': 165 | continue 166 | if seg['p_memsz'] == 0: 167 | continue 168 | 169 | seg_p_vaddr = seg['p_vaddr'] 170 | seg_p_filesz = seg['p_filesz'] 171 | seg_p_offset = seg['p_offset'] 172 | regions = [{'addr': seg_p_vaddr, 173 | 'size': seg['p_memsz'], 174 | 'type': 0}] 175 | relevant_regions = self.regions_in_segment(seg, existing_pages) 176 | 177 | for reg_vaddr, reg_size in relevant_regions: 178 | region = None 179 | # Use binary search to find the correct region 180 | s, e = 0, len(regions)-1 181 | while s <= e: 182 | m = s + (e - s) // 2 183 | lower = regions[m]['addr'] 184 | upper = regions[m]['addr'] + regions[m]['size'] 185 | if lower <= reg_vaddr and reg_vaddr < upper: 186 | region = regions[m] 187 | break 188 | elif reg_vaddr >= upper: 189 | s = m+1 190 | elif reg_vaddr < lower: 191 | e = m-1 192 | 193 | assert region != None, "section is overlapping which is not allowed" 194 | orig_size = region['size'] 195 | 196 | # Shrink the region to the range preceding this section. 197 | region['size'] = reg_vaddr - region['addr'] 198 | # Append a region for this section itself and that following 199 | # this section. 200 | 201 | # only add if they are not empty 202 | if reg_size != 0: 203 | regions += [{'addr': reg_vaddr, 204 | 'size': reg_size, 205 | 'type': 1}] 206 | if orig_size - region['size'] - reg_size != 0: 207 | regions += [{'addr': reg_vaddr + reg_size, 208 | 'size': orig_size - region['size'] - reg_size, 209 | 'type': 0}] 210 | 211 | r = (seg['p_flags'] & P_FLAGS.PF_R) > 0 212 | w = (seg['p_flags'] & P_FLAGS.PF_W) > 0 213 | x = (seg['p_flags'] & P_FLAGS.PF_X) > 0 214 | 215 | # Allocate pages 216 | for reg in regions: 217 | if reg['type']: 218 | vaddr = reg['addr'] 219 | pages.add_page(vaddr, r, w, x, reg['size'], self.compute_elf_fill_frame( 220 | vaddr, reg['size'], seg_p_vaddr, seg_p_filesz, seg_p_offset)) 221 | else: 222 | # A range that is eligible for promotion. 223 | possible_pages = list(reversed(page_sizes(self.arch))) 224 | vaddr = round_down(reg['addr']) 225 | remain = reg['addr'] + reg['size'] - vaddr 226 | while vaddr < reg['addr'] + reg['size']: 227 | size = PAGE_SIZE 228 | if use_large_frames: 229 | for p in possible_pages: 230 | if remain >= p and vaddr % p == 0: 231 | size = p 232 | break 233 | pages.add_page(vaddr, r, w, x, size, self.compute_elf_fill_frame( 234 | vaddr, size, seg_p_vaddr, seg_p_filesz, seg_p_offset)) 235 | vaddr += size 236 | remain -= size 237 | 238 | return pages 239 | 240 | def get_spec(self, infer_tcb=True, infer_asid=True, pd=None, 241 | use_large_frames=True, addr_space=None): 242 | """ 243 | Return a CapDL spec with as much information as can be derived from the 244 | ELF file in isolation. 245 | """ 246 | pages = self.get_pages(infer_asid, pd, use_large_frames, addr_space=addr_space) 247 | spec = pages.get_spec(addr_space.get_regions_and_clear() if addr_space else {}) 248 | 249 | if infer_tcb: 250 | # Create a single TCB. 251 | tcb = TCB('tcb_%s' % self._safe_name(), ip=self.get_entry_point()) 252 | spec.add_object(tcb) 253 | tcb['vspace'] = pages.get_vspace_root()[1] 254 | 255 | return spec 256 | 257 | def __repr__(self): 258 | return str(self._elf) 259 | -------------------------------------------------------------------------------- /python-capdl-tool/tests/allocator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 4 | # 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | from __future__ import absolute_import, division, print_function, \ 9 | unicode_literals 10 | 11 | import unittest 12 | 13 | import hypothesis.strategies as st 14 | from hypothesis import given 15 | 16 | from capdl import Spec, Untyped, Endpoint, IRQControl, Frame 17 | from capdl.Allocator import BestFitAllocator, AllocatorException 18 | from capdl.util import round_up 19 | from tests import CapdlTestCase 20 | 21 | 22 | class TestAllocator(CapdlTestCase): 23 | 24 | def assertValidSpec(self, allocator, spec, ut_size, child_size, children, uts): 25 | if ut_size >= child_size: 26 | allocator.allocate(spec) 27 | # now check if all the children got allocated 28 | for c in children: 29 | if not any(c in ut.children for ut in uts): 30 | self.fail("Child {0} not allocated!".format(c)) 31 | else: 32 | with self.assertRaises(AllocatorException): 33 | allocator.allocate(spec) 34 | 35 | @given(st.integers(min_value=4, max_value=64), st.integers(min_value=4, max_value=64)) 36 | def test_alloc_single_fun_obj(self, child_size_bits, ut_size_bits): 37 | """ 38 | Test allocating a single object from a single untyped. Vary the untyped size and object size, 39 | and make sure it either succeeds (should always succeed if the untyped size is big enough) or fails 40 | by throwing an AllocatorException 41 | """ 42 | allocator = BestFitAllocator() 43 | spec = Spec() 44 | 45 | ut = Untyped(name="test_ut", size_bits=ut_size_bits, paddr=1 << ut_size_bits) 46 | allocator.add_untyped(ut) 47 | 48 | child = Untyped(name="child_ut", size_bits=child_size_bits) 49 | spec.add_object(child) 50 | 51 | self.assertValidSpec(allocator, spec, ut_size_bits, child_size_bits, [child], [ut]) 52 | 53 | @staticmethod 54 | def alloc_children(spec, object_sizes): 55 | sum = 0 56 | children = [] 57 | for i, size_bits in enumerate(object_sizes): 58 | sum += (1 << size_bits) 59 | child = Untyped(name="child ut {0}".format(i), size_bits=size_bits) 60 | spec.add_object(child) 61 | children.append(child) 62 | return sum, children 63 | 64 | @given(st.lists(st.integers(min_value=4, max_value=64), max_size=100, min_size=10), st.integers(min_value=4, max_value=64)) 65 | def test_alloc_multiple_fun_obj(self, object_sizes, ut_size_bits): 66 | """Test allocating multiple child objects from a single untyped""" 67 | allocator = BestFitAllocator() 68 | spec = Spec() 69 | (total_child_size, children) = TestAllocator.alloc_children(spec, object_sizes) 70 | 71 | ut = Untyped(name="test_ut", size_bits=ut_size_bits, paddr=1 << ut_size_bits) 72 | allocator.add_untyped(ut) 73 | 74 | self.assertValidSpec(allocator, spec, 1 << ut_size_bits, total_child_size, children, [ut]) 75 | 76 | @given(st.lists(st.integers(min_value=4, max_value=32), max_size=100, min_size=10), 77 | st.lists(st.integers(min_value=32, max_value=64), max_size=20, min_size=2)) 78 | def test_alloc_multiple_fun_multiple_untyped(self, object_sizes, ut_sizes): 79 | """Test allocating multiple children from multiple untyped""" 80 | allocator = BestFitAllocator() 81 | spec = Spec() 82 | (total_child_size, children) = TestAllocator.alloc_children(spec, object_sizes) 83 | untyped = [] 84 | paddr = 0x1 85 | ut_size = 0 86 | 87 | for i in range(0, len(ut_sizes)): 88 | size_bits = ut_sizes[i] 89 | paddr = round_up(paddr, 1 << size_bits) 90 | ut = Untyped("untyped_{0}".format(i), size_bits=size_bits, paddr=paddr) 91 | untyped.append(ut) 92 | allocator.add_untyped(ut) 93 | paddr += 1 << size_bits 94 | ut_size += 1 << size_bits 95 | 96 | self.assertValidSpec(allocator, spec, ut_size, total_child_size, children, untyped) 97 | 98 | def test_alloc_no_spec_no_untyped(self): 99 | """ 100 | Test allocating nothing from nothing works. 101 | """ 102 | BestFitAllocator().allocate(Spec()) 103 | 104 | def test_alloc_no_spec(self): 105 | """ 106 | Test allocating nothing from something works 107 | """ 108 | allocator = BestFitAllocator() 109 | allocator.add_untyped(Untyped(name="test_ut", size_bits=16, paddr=0)) 110 | allocator.allocate(Spec()) 111 | 112 | def test_alloc_no_untyped(self): 113 | """ 114 | Test allocating something from nothing fails elegantly 115 | """ 116 | ep = Endpoint(name="test_ep") 117 | spec = Spec() 118 | spec.add_object(ep) 119 | 120 | with self.assertRaises(AllocatorException): 121 | BestFitAllocator().allocate(spec) 122 | 123 | def test_alloc_unsized(self): 124 | """Test allocating an object with no size""" 125 | irq_ctrl = IRQControl("irq_control") 126 | spec = Spec() 127 | spec.add_object(irq_ctrl) 128 | allocator = BestFitAllocator() 129 | allocator.add_untyped(Untyped(name="test_ut", size_bits=16, paddr=0x10000)) 130 | allocator.allocate(spec) 131 | self.assertTrue(irq_ctrl in spec.objs) 132 | 133 | @given(st.integers(min_value=0xA0, max_value=0xD0), st.integers(min_value=0xB0, max_value=0xC0)) 134 | def test_alloc_paddr(self, unfun_paddr, ut_paddr): 135 | """ 136 | Test allocating a single unfun untyped in and out of bounds of an untyped 137 | """ 138 | 139 | allocator = BestFitAllocator() 140 | size_bits = 12 141 | 142 | unfun_paddr = unfun_paddr << size_bits 143 | ut_paddr = ut_paddr << size_bits 144 | unfun_end = unfun_paddr + (1 << size_bits) 145 | ut_end = ut_paddr + (1 << size_bits) 146 | 147 | parent = Untyped("parent_ut", size_bits=size_bits, paddr=ut_paddr) 148 | allocator.add_untyped(parent) 149 | spec = Spec() 150 | child = Untyped("child_ut", size_bits=size_bits, paddr=unfun_paddr) 151 | spec.add_object(child) 152 | 153 | if unfun_paddr >= ut_paddr and unfun_end <= ut_end: 154 | self.assertValidSpec(allocator, spec, size_bits, size_bits, [child], [parent]) 155 | else: 156 | with self.assertRaises(AllocatorException): 157 | allocator.allocate(spec) 158 | 159 | @given(st.lists(st.integers(min_value=4, max_value=64), min_size=1), st.lists(st.integers(min_value=4, max_value=64), min_size=1)) 160 | def test_device_ut_only(self, ut_sizes, obj_sizes): 161 | """ 162 | Test allocating fun objects from only device untypeds 163 | """ 164 | allocator = BestFitAllocator() 165 | paddr = 0x1 166 | for i in range(0, len(ut_sizes)): 167 | paddr = round_up(paddr, 1 << ut_sizes[i]) 168 | allocator.add_device_untyped( 169 | Untyped("device_untyped_{0}".format(i), size_bits=ut_sizes[i], paddr=paddr)) 170 | paddr += 1 << ut_sizes[i] 171 | 172 | spec = Spec() 173 | for i in range(0, len(obj_sizes)): 174 | spec.add_object(Untyped("obj_untyped_{0}".format(i), size_bits=obj_sizes[i])) 175 | 176 | with self.assertRaises(AllocatorException): 177 | allocator.allocate(spec) 178 | 179 | @given(st.integers(min_value=0, max_value=3)) 180 | def test_overlapping_paddr_smaller(self, offset): 181 | """Test allocating unfun objects with overlapping paddrs, where the overlapping paddr is from a smaller 182 | object """ 183 | 184 | paddr = 0xAAAA0000 185 | size_bits = 16 186 | overlap_paddr = paddr + offset * (1 << (size_bits-2)) 187 | 188 | allocator = BestFitAllocator() 189 | allocator.add_untyped(Untyped("parent", paddr=paddr, size_bits=size_bits)) 190 | 191 | spec = Spec() 192 | spec.add_object(Untyped("child", paddr=paddr, size_bits=size_bits)) 193 | spec.add_object(Untyped("overlap_child", paddr=overlap_paddr, size_bits=size_bits-2)) 194 | 195 | with self.assertRaises(AllocatorException): 196 | allocator.allocate(spec) 197 | 198 | def test_overlapping_paddr_larger(self): 199 | """Test allocating unfun objects with overlapping paddrs, where the overlapping paddr is from a larger object""" 200 | allocator = BestFitAllocator() 201 | 202 | paddr = 0xAAAA0000 203 | allocator.add_untyped(Untyped("deadbeef", size_bits=16, paddr=paddr)) 204 | 205 | spec = Spec() 206 | spec.add_object(Untyped("obj_untyped_1", size_bits=14, paddr=paddr + 2 * (1 << 15))) 207 | spec.add_object(Untyped("obj_untyped_2", size_bits=15, paddr=paddr)) 208 | 209 | with self.assertRaises(AllocatorException): 210 | allocator.allocate(spec) 211 | 212 | @given(st.lists(st.integers(min_value=4, max_value=16), min_size=1, max_size=1000)) 213 | def test_placeholder_uts(self, sizes): 214 | """ 215 | Test allocating a collection of unfun objects that do not align and have placeholder uts between them 216 | """ 217 | allocator = BestFitAllocator() 218 | start_paddr = 1 << (max(sizes) + len(sizes).bit_length()) 219 | paddr = start_paddr 220 | ut_size = 0 221 | 222 | children = [] 223 | spec = Spec() 224 | for i in range(0, len(sizes)): 225 | paddr = round_up(paddr, 1 << sizes[i]) 226 | ut = Untyped("ut_{0}".format(i), size_bits=sizes[i], paddr=paddr) 227 | spec.add_object(ut) 228 | paddr += 1 << sizes[i] 229 | ut_size += 1 << sizes[i] 230 | children.append(ut) 231 | 232 | ut_size_bits = (paddr - start_paddr).bit_length() 233 | ut = Untyped("ut_parent", size_bits=ut_size_bits, paddr=start_paddr) 234 | allocator.add_untyped(ut) 235 | self.assertValidSpec(allocator, spec, 1 << ut_size_bits, ut_size, children, [ut]) 236 | 237 | def test_regression_unfun_at_end(self): 238 | """ 239 | Ensure that if an unfun object is the last to get allocated, 240 | its root ut is included in the spec. 241 | """ 242 | allocator = BestFitAllocator() 243 | root_ut_A = Untyped("root_ut_A", size_bits=16, paddr=0x10000) 244 | root_ut_B = Untyped("root_ut_B", size_bits=16, paddr=0x20000) 245 | allocator.add_untyped(root_ut_A) 246 | allocator.add_untyped(root_ut_B) 247 | 248 | spec = Spec() 249 | my_frame_A0 = Frame("my_frame_A0") 250 | my_frame_A1 = Frame("my_frame_A1") 251 | my_pinned_frame_B = Frame("my_pinned_frame_B", paddr=0x20000) 252 | spec.add_object(my_frame_A0) 253 | spec.add_object(my_frame_A1) 254 | spec.add_object(my_pinned_frame_B) 255 | 256 | allocator.allocate(spec) 257 | self.assertIn(root_ut_B, spec.objs) # main test 258 | # other tests: 259 | for obj in (root_ut_A, root_ut_B, my_frame_A0, my_frame_A1, my_pinned_frame_B): 260 | self.assertIn(obj, spec.objs) 261 | for obj in (my_frame_A0, my_frame_A1): 262 | self.assertIn(obj, root_ut_A.children) 263 | for obj in (my_pinned_frame_B,): 264 | self.assertIn(obj, root_ut_B.children) 265 | 266 | 267 | if __name__ == '__main__': 268 | unittest.main() 269 | -------------------------------------------------------------------------------- /capDL-tool/Main.hs: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 | -- 4 | -- SPDX-License-Identifier: BSD-2-Clause 5 | -- 6 | 7 | module Main where 8 | 9 | import CapDL.Parser 10 | import CapDL.DumpParser 11 | import CapDL.PrintUtils 12 | import CapDL.ParserUtils (emptyMaps) 13 | import CapDL.Model 14 | import CapDL.MakeModel 15 | import CapDL.PrintModel 16 | import CapDL.State 17 | import CapDL.PrintDot 18 | import CapDL.PrintXml 19 | import CapDL.PrintIsabelle 20 | import CapDL.PrintC 21 | import CapDL.STCC 22 | 23 | import System.Environment 24 | import System.Exit (exitFailure) 25 | import System.FilePath 26 | import System.IO 27 | import System.Posix (rename, removeLink) 28 | import Text.ParserCombinators.Parsec 29 | import Control.Exception (bracketOnError) 30 | import Control.Monad 31 | import Control.Monad.Writer 32 | import Data.Maybe 33 | import System.Console.GetOpt 34 | import Data.String.Utils 35 | import qualified Data.Map as Map 36 | import qualified Data.Yaml as Yaml 37 | import qualified Text.PrettyPrint as PP 38 | 39 | data Options = Options { 40 | optOutputIsabelle :: Maybe String, 41 | optOutputXml :: Maybe String, 42 | optOutputDot :: Maybe String, 43 | optOutputCSpec :: Maybe String, 44 | optDynamicAllocCSpec :: Bool, 45 | optOutputText :: Maybe String, 46 | optOutputAnalysis :: Maybe String, 47 | optDumpAST :: Maybe String, 48 | optObjectSizeFile :: Maybe String 49 | } 50 | 51 | -- Default options. 52 | defaultOptions :: Options 53 | defaultOptions = Options { 54 | optOutputIsabelle = Nothing, 55 | optOutputXml = Nothing, 56 | optOutputDot = Nothing, 57 | optOutputCSpec = Nothing, 58 | optDynamicAllocCSpec = True, 59 | optOutputText = Nothing, 60 | optOutputAnalysis = Nothing, 61 | optDumpAST = Nothing, 62 | optObjectSizeFile = Nothing 63 | } 64 | 65 | -- 66 | -- Options our program supports. 67 | -- 68 | options = [ 69 | Option ['i'] ["isabelle"] 70 | (ReqArg (\arg -> \o -> o {optOutputIsabelle = Just arg }) "FILE") 71 | "output isabelle to FILE", 72 | 73 | Option ['d'] ["dot"] 74 | (ReqArg (\arg -> \o -> o {optOutputDot = Just arg }) "FILE") 75 | "output dot to FILE", 76 | 77 | Option ['c'] ["code"] 78 | (ReqArg (\arg -> \o -> o {optOutputCSpec = Just arg}) "FILE") 79 | "output C initialiser source to FILE", 80 | 81 | Option [] ["code-dynamic-alloc"] 82 | (NoArg (\o -> o {optDynamicAllocCSpec = True})) 83 | "assume dynamic allocation for C initialiser (default)", 84 | 85 | Option [] ["code-static-alloc"] 86 | (NoArg (\o -> o {optDynamicAllocCSpec = False})) 87 | "assume static allocation for C initialiser (must have untyped covers)", 88 | 89 | Option ['x'] ["xml"] 90 | (ReqArg (\arg -> \o -> o {optOutputXml = Just arg }) "FILE") 91 | "output XML to FILE", 92 | 93 | Option ['t'] ["text"] 94 | (ReqArg (\arg -> \o -> o {optOutputText = Just arg }) "FILE") 95 | "output text to FILE", 96 | 97 | Option ['a'] ["analysis"] 98 | (ReqArg (\arg o -> o {optOutputAnalysis = Just arg }) "FILE") 99 | "perform analysis and output cap leak and info flow .dot files and capDL text", 100 | 101 | Option [] ["dump-ast"] 102 | (ReqArg (\arg o -> o {optDumpAST = Just arg}) "FILE") 103 | "dump internal AST", 104 | 105 | Option [] ["object-sizes"] 106 | (ReqArg (\arg o -> o {optObjectSizeFile = Just arg}) "FILE") 107 | "YAML file containing kernel object sizes. Required for --code-dynamic-alloc and --isabelle" 108 | ] 109 | 110 | -- 111 | -- Usage information 112 | -- 113 | usageHeader = "usage: parse-capDL [options] " 114 | 115 | -- 116 | -- The result of "getOpt" returns a list of functions that transforms 117 | -- a "Options", returning a new "Options" object with the option applied. This 118 | -- fucnction applies all these generated option functions together. 119 | -- 120 | processOpts :: [Options -> Options] -> Options 121 | processOpts [] = defaultOptions 122 | processOpts (action:actions) = action (processOpts actions) 123 | 124 | genparseFromFile :: GenParser Char s a -> s -> String -> IO (Either ParseError a) 125 | genparseFromFile p st fname = do 126 | input <- readFile fname 127 | return $ runParser p st fname input 128 | 129 | isDump :: String -> IO Bool 130 | isDump fname = do 131 | input <- openFile fname ReadMode 132 | first <- hGetLine input 133 | hClose input 134 | if strip first == "-- Dump" 135 | then return True 136 | else return False 137 | 138 | genObjectSizeMap :: Map.Map String Word -> ObjectSizeMap 139 | genObjectSizeMap m = 140 | Map.fromList [ (koType, sz) 141 | | (n, sz) <- Map.toList m, Just koType <- [Map.lookup n names] ] 142 | where names = Map.fromList 143 | [ ("seL4_Slot", CNode_T) 144 | , ("seL4_TCBObject", TCB_T) 145 | , ("seL4_EndpointObject", Endpoint_T) 146 | , ("seL4_NotificationObject", Notification_T) 147 | , ("seL4_ASID_Pool", ASIDPool_T) 148 | , ("seL4_RTReplyObject", RTReply_T) 149 | , ("seL4_VCPU", VCPU_T) 150 | , ("seL4_PageTableObject", PT_T) 151 | , ("seL4_PageDirectoryObject", PD_T) 152 | , ("seL4_AARCH64_PGD", PGD_T) 153 | , ("seL4_AARCH64_PUD", PUD_T) 154 | , ("seL4_IOPageTableObject", IOPT_T) 155 | , ("seL4_X64_PDPT", PDPT_T) 156 | , ("seL4_X64_PML4", PML4_T) 157 | , ("seL4_SchedContextObject", SC_T) 158 | , ("seL4_IOPorts", IOPorts_T) 159 | , ("seL4_IODevice", IODevice_T) 160 | , ("seL4_ARMIODevice", ARMIODevice_T) 161 | , ("seL4_IRQ", IrqSlot_T) 162 | , ("seL4_IOAPICIRQ", IOAPICIrqSlot_T) 163 | , ("seL4_MSIIRQ", MSIIrqSlot_T) 164 | , ("seL4_ARMIRQ", ARMIrqSlot_T) 165 | , ("seL4_ARMSID", ARMSID_T) 166 | , ("seL4_ARMCB", ARMCB_T) 167 | , ("seL4_ARMSMC", ARMSMC_T) 168 | , ("seL4_ARMSGI_Signal", ARMSGISignal_T) 169 | ] 170 | 171 | -- Abort with an error message if 'isFullyAllocated' fails. 172 | assertIsFullyAllocated :: (PP.Doc -> PP.Doc) -> ObjectSizeMap -> ObjMap Word -> CoverMap -> IO () 173 | assertIsFullyAllocated wrapMessage sizeMap objs untypedCovers = 174 | case isFullyAllocated sizeMap objs untypedCovers of 175 | Right () -> return () 176 | Left (msg, badObjs) -> do 177 | hPutStrLn stderr . PP.render . wrapMessage $ 178 | PP.text (msg ++ ":") PP.$+$ 179 | -- TODO: maybe limit number of badObjs printed 180 | PP.nest 2 (PP.vcat $ PP.text . CapDL.PrintUtils.showID <$> badObjs) 181 | exitFailure 182 | 183 | main = do 184 | -- Parse command line arguments. 185 | args <- getArgs 186 | let (actions, nonOpts, msgs) = getOpt RequireOrder options args 187 | when (length msgs > 0) $ 188 | error (concat msgs ++ usageInfo usageHeader options) 189 | when (length nonOpts < 1) $ 190 | error ("input file not specified\n" ++ usageInfo usageHeader options) 191 | when (length nonOpts > 1) $ 192 | error ("unrecognised arguments: " ++ unwords nonOpts ++ "\n" ++ usageInfo usageHeader options) 193 | let opt = foldr ($) defaultOptions actions 194 | 195 | -- Print option names that satisfy a condition 196 | let gatherOptions = Data.String.Utils.join " and " . map snd . filter fst 197 | 198 | let whyNeedObjectSizes = gatherOptions 199 | [ (isJust (optOutputIsabelle opt), "--isabelle") 200 | , (isJust (optOutputCSpec opt) && optDynamicAllocCSpec opt, "--code-dynamic-alloc") ] 201 | when (not (null whyNeedObjectSizes) && isNothing (optObjectSizeFile opt)) $ 202 | error $ "--object-sizes file is required for " ++ whyNeedObjectSizes 203 | 204 | -- Parse the file. 205 | let inputFile = nonOpts !! 0 206 | dump <- isDump inputFile 207 | res <- if dump 208 | then genparseFromFile capDLDumpModule emptyMaps inputFile 209 | else genparseFromFile capDLModule emptyMaps inputFile 210 | 211 | -- Parse object sizes file, if available. 212 | objSizeMap <- case optObjectSizeFile opt of 213 | Nothing -> return Map.empty 214 | Just f -> do yParse <- Yaml.decodeFileEither f 215 | case yParse of 216 | Left err -> error $ "failed to parse object sizes file " ++ show f ++ "\n" 217 | ++ show err 218 | Right m -> return $ genObjectSizeMap m 219 | 220 | -- Get the parse result (or show an error if it failed). 221 | res <- case res of 222 | Left e -> error (show e) 223 | Right t -> return t 224 | let ((m, i, c), mmLog) = runWriter (makeModel res) 225 | when (not (PP.isEmpty mmLog)) $ hPrint stderr mmLog 226 | 227 | -- `--isabelle` requires a statically allocated spec, so check this now. 228 | -- NB: we don't check this for `--code-static-alloc`, because we might not 229 | -- have objSizeMap for that mode. 230 | let whyNeedStaticAlloc = gatherOptions 231 | [ (isJust (optOutputIsabelle opt), "--isabelle") ] 232 | prefix = "A statically allocated spec is required for " ++ whyNeedStaticAlloc 233 | when (not (null whyNeedStaticAlloc)) $ 234 | assertIsFullyAllocated (PP.text prefix PP.$+$) objSizeMap (objects m) (untypedCovers m) 235 | 236 | let writeFile' "-" s = putStr s 237 | writeFile' f s = bracketOnError 238 | (do (tempF, handle) <- uncurry openTempFile (splitFileName f) 239 | hClose handle -- ignore for now 240 | return tempF) 241 | removeLink 242 | (\tempF -> do writeFile tempF s 243 | rename tempF f) 244 | 245 | let (valid, log) = runWriter (checkModel m) 246 | if valid 247 | then do 248 | -- Output model in any requested format. 249 | let optActions = [(optOutputIsabelle, \f -> writeFile' f $ show $ printIsabelle f objSizeMap m), 250 | (optOutputXml, \f -> writeFile' f $ show $ printXml inputFile m), 251 | (optOutputDot, \f -> writeFile' f $ show $ printDot inputFile m), 252 | (optOutputCSpec, \f -> let allocType 253 | | optDynamicAllocCSpec opt = DynamicAlloc objSizeMap 254 | | otherwise = StaticAlloc 255 | in writeFile' f $ show $ 256 | printC allocType m i c), 257 | (optOutputText, \f -> writeFile' f $ show $ pretty m), 258 | (optOutputAnalysis, \f -> do (leakDot, flowDot, newM) <- leakMatrix m 259 | writeFile (f ++ "-leak.dot") leakDot 260 | writeFile (f ++ "-flow.dot") flowDot 261 | writeFile (f ++ "-saturation.txt") $ show $ pretty newM), 262 | 263 | (optDumpAST, \f -> writeFile' f $ show m)] 264 | condDoOpt (projection, action) = maybe (return ()) action (projection opt) 265 | mapM_ condDoOpt optActions 266 | else do 267 | putStr $ show log 268 | error("Failed to check model") 269 | --------------------------------------------------------------------------------