├── .gitignore ├── runscript.sh ├── inittab ├── configs-keystone-fu540 ├── system │ ├── __init__.py │ └── system.py ├── run_untrusted.py └── run_trusted.py ├── configs-keystone-large ├── system │ ├── __init__.py │ └── system.py ├── run_untrusted.py └── run_trusted.py ├── configs-keystone-default ├── system │ ├── __init__.py │ └── system.py ├── run_untrusted.py └── run_trusted.py ├── 0001-arch-riscv-Update-the-way-a-valid-virtual-address-is.patch ├── README.md ├── launch_keystone_experiments.py ├── 0002-arch-riscv-add-pma-pmp-checks-during-page-table-walk.patch └── bootstrap_musl_riscv.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .vscode 3 | results 4 | gem5art-env 5 | gem5 6 | keystone 7 | rv8-bench 8 | musl-riscv-toolchain 9 | -------------------------------------------------------------------------------- /runscript.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright (c) 2020 The Regents of the University of California. 4 | # SPDX-License-Identifier: BSD 3-Clause 5 | 6 | /sbin/m5 readfile > script.sh 7 | if [ -s script.sh ]; then 8 | # if the file is not empty, execute it 9 | chmod +x script.sh 10 | ./script.sh 11 | /sbin/m5 exit 12 | fi 13 | # otherwise, drop to the terminal 14 | -------------------------------------------------------------------------------- /inittab: -------------------------------------------------------------------------------- 1 | # /etc/inittab 2 | # 3 | # Copyright (C) 2001 Erik Andersen 4 | # 5 | # Note: BusyBox init doesn't support runlevels. The runlevels field is 6 | # completely ignored by BusyBox init. If you want runlevels, use 7 | # sysvinit. 8 | # 9 | # Format for each entry: ::: 10 | # 11 | # id == tty to run on, or empty for /dev/console 12 | # runlevels == ignored 13 | # action == one of sysinit, respawn, askfirst, wait, and once 14 | # process == program to run 15 | 16 | # Startup the system 17 | ::sysinit:/bin/mount -t proc proc /proc 18 | ::sysinit:/bin/mount -o remount,rw / 19 | ::sysinit:/bin/mkdir -p /dev/pts /dev/shm 20 | ::sysinit:/bin/mount -a 21 | ::sysinit:/sbin/swapon -a 22 | null::sysinit:/bin/ln -sf /proc/self/fd /dev/fd 23 | null::sysinit:/bin/ln -sf /proc/self/fd/0 /dev/stdin 24 | null::sysinit:/bin/ln -sf /proc/self/fd/1 /dev/stdout 25 | null::sysinit:/bin/ln -sf /proc/self/fd/2 /dev/stderr 26 | ::sysinit:/bin/hostname -F /etc/hostname 27 | # now run any rc scripts 28 | ::sysinit:/etc/init.d/rcS 29 | 30 | # Put a getty on the serial port 31 | ::respawn:-/bin/sh -c "/root/runscript.sh" 32 | #console::respawn:/sbin/getty -L console 0 vt100 # GENERIC_SERIAL 33 | 34 | # Stuff to do for the 3-finger salute 35 | #::ctrlaltdel:/sbin/reboot 36 | 37 | # Stuff to do before rebooting 38 | ::shutdown:/etc/init.d/rcK 39 | ::shutdown:/sbin/swapoff -a 40 | ::shutdown:/bin/umount -a -r 41 | -------------------------------------------------------------------------------- /configs-keystone-fu540/system/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2016 Jason Lowe-Power 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions are 7 | # met: redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer; 9 | # redistributions in binary form must reproduce the above copyright 10 | # notice, this list of conditions and the following disclaimer in the 11 | # documentation and/or other materials provided with the distribution; 12 | # neither the name of the copyright holders nor the names of its 13 | # contributors may be used to endorse or promote products derived from 14 | # this software without specific prior written permission. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | # 28 | # Authors: Jason Lowe-Power 29 | 30 | from .system import RiscvSystem 31 | 32 | -------------------------------------------------------------------------------- /configs-keystone-large/system/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2016 Jason Lowe-Power 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions are 7 | # met: redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer; 9 | # redistributions in binary form must reproduce the above copyright 10 | # notice, this list of conditions and the following disclaimer in the 11 | # documentation and/or other materials provided with the distribution; 12 | # neither the name of the copyright holders nor the names of its 13 | # contributors may be used to endorse or promote products derived from 14 | # this software without specific prior written permission. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | # 28 | # Authors: Jason Lowe-Power 29 | 30 | from .system import RiscvSystem 31 | 32 | -------------------------------------------------------------------------------- /configs-keystone-default/system/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2016 Jason Lowe-Power 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions are 7 | # met: redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer; 9 | # redistributions in binary form must reproduce the above copyright 10 | # notice, this list of conditions and the following disclaimer in the 11 | # documentation and/or other materials provided with the distribution; 12 | # neither the name of the copyright holders nor the names of its 13 | # contributors may be used to endorse or promote products derived from 14 | # this software without specific prior written permission. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | # 28 | # Authors: Jason Lowe-Power 29 | 30 | from .system import RiscvSystem 31 | 32 | -------------------------------------------------------------------------------- /0001-arch-riscv-Update-the-way-a-valid-virtual-address-is.patch: -------------------------------------------------------------------------------- 1 | From ecaca2c214f7c0d45b9a62c048c46572b83c05c3 Mon Sep 17 00:00:00 2001 2 | From: Ayaz Akram 3 | Date: Tue, 25 May 2021 01:58:54 -0700 4 | Subject: [PATCH] arch-riscv: Update the way a valid virtual address is 5 | computed 6 | 7 | According to privileged ISA specs, a valid 64 bit virtual address should 8 | have bit 63-39 same as bit 38 (for Sv39). Without this change, kernel page 9 | fault handler does not seem to work correctly. For example, while running 10 | a program, the kernel was segfaulting complaining that it cannot handle 11 | kernel paging request at some virtual address (which is the faulting 12 | address returned by gem5 currently, with all bits after first 39 cleared). 13 | With this change, that error goes away. 14 | 15 | Change-Id: Iae7c9d0af19e29214e14a0db08d7c0ac122122bc 16 | --- 17 | src/arch/riscv/pagetable_walker.cc | 4 ++-- 18 | src/arch/riscv/tlb.cc | 2 +- 19 | 2 files changed, 3 insertions(+), 3 deletions(-) 20 | 21 | diff --git a/src/arch/riscv/pagetable_walker.cc b/src/arch/riscv/pagetable_walker.cc 22 | index d3c390531..8dadd9676 100644 23 | --- a/src/arch/riscv/pagetable_walker.cc 24 | +++ b/src/arch/riscv/pagetable_walker.cc 25 | @@ -418,7 +418,7 @@ Walker::WalkerState::endWalk() 26 | void 27 | Walker::WalkerState::setupWalk(Addr vaddr) 28 | { 29 | - vaddr &= (static_cast(1) << VADDR_BITS) - 1; 30 | + vaddr = Addr(sext(vaddr)); 31 | 32 | Addr shift = PageShift + LEVEL_BITS * 2; 33 | Addr idx = (vaddr >> shift) & LEVEL_MASK; 34 | @@ -486,7 +486,7 @@ Walker::WalkerState::recvPacket(PacketPtr pkt) 35 | * well. 36 | */ 37 | Addr vaddr = req->getVaddr(); 38 | - vaddr &= (static_cast(1) << VADDR_BITS) - 1; 39 | + vaddr = Addr(sext(vaddr)); 40 | Addr paddr = walker->tlb->translateWithTLB(vaddr, satp.asid, mode); 41 | req->setPaddr(paddr); 42 | walker->pma->check(req); 43 | diff --git a/src/arch/riscv/tlb.cc b/src/arch/riscv/tlb.cc 44 | index 8be783655..7e0cc7474 100644 45 | --- a/src/arch/riscv/tlb.cc 46 | +++ b/src/arch/riscv/tlb.cc 47 | @@ -277,7 +277,7 @@ TLB::doTranslate(const RequestPtr &req, ThreadContext *tc, 48 | { 49 | delayed = false; 50 | 51 | - Addr vaddr = req->getVaddr() & ((static_cast(1) << VADDR_BITS) - 1); 52 | + Addr vaddr = Addr(sext(req->getVaddr())); 53 | SATP satp = tc->readMiscReg(MISCREG_SATP); 54 | 55 | TlbEntry *e = lookup(vaddr, satp.asid, mode, false); 56 | -- 57 | 2.17.1 58 | 59 | -------------------------------------------------------------------------------- /configs-keystone-default/run_untrusted.py: -------------------------------------------------------------------------------- 1 | #Copyright (c) 2021 The Regents of the University of California. 2 | #All Rights Reserved 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are 6 | # met: redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer; 8 | # redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution; 11 | # neither the name of the copyright holders nor the names of its 12 | # contributors may be used to endorse or promote products derived from 13 | # this software without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | # 27 | 28 | """ 29 | This script is supposed to run keystone benchmarks 30 | """ 31 | 32 | import time 33 | import argparse 34 | 35 | import m5 36 | import m5.ticks 37 | from m5.objects import * 38 | 39 | from system import * 40 | 41 | def parse_options(): 42 | parser = argparse.ArgumentParser(description='Runs Linux boot test with' 43 | 'RISCV. Expects the disk image to call the simulator exit' 44 | 'event after boot.') 45 | parser.add_argument("sbi", help='Path to the opensbi' 46 | 'binary with kernel payload') 47 | parser.add_argument("disk", help="Path to the disk image to boot") 48 | parser.add_argument("cpu_type", help="The type of CPU in the system") 49 | parser.add_argument("num_cpus", type=int, help="Number of CPU cores") 50 | parser.add_argument("bench", help="Benchmark to simulate") 51 | 52 | return parser.parse_args() 53 | 54 | def writeBenchScript(dir, bench): 55 | """ 56 | This method creates a script in dir which will be eventually 57 | passed to the simulated system (to run a specific benchmark 58 | at bootup). 59 | """ 60 | file_name = '{}/run_{}'.format(dir, bench) 61 | bench_file = open(file_name,"w+") 62 | bench_file.write('cd /root/ \n') 63 | bench_file.write('/sbin/m5 exit \n') 64 | bench_file.write('riscv64/{} \n'.format(args.bench)) 65 | bench_file.write('/sbin/m5 exit \n') 66 | bench_file.close() 67 | return file_name 68 | 69 | 70 | if __name__ == "__m5_main__": 71 | 72 | args = parse_options() 73 | 74 | # create the system we are going to simulate 75 | 76 | system = RiscvSystem(args.sbi, args.disk, args.cpu_type, args.num_cpus) 77 | 78 | # Exit from guest on workbegin/workend 79 | system.exit_on_work_items = True 80 | 81 | # Create and pass a script to the simulated system to run the reuired 82 | # benchmark 83 | system.readfile = writeBenchScript(m5.options.outdir, args.bench) 84 | 85 | # set up the root SimObject and start the simulation 86 | root = Root(full_system = True, system = system) 87 | 88 | # Required for long-running jobs 89 | #m5.disableAllListeners() 90 | 91 | # instantiate all of the objects we've created above 92 | m5.instantiate() 93 | 94 | globalStart = time.time() 95 | 96 | print("Running the simulation") 97 | exit_event = m5.simulate() 98 | 99 | if exit_event.getCause() == "m5_exit instruction encountered": 100 | # Reached the start of actual benchmark 101 | print("Starting actual workload!") 102 | m5.stats.reset() 103 | start_tick = m5.curTick() 104 | else: 105 | print("Unexpected termination of simulation !") 106 | exit(1) 107 | 108 | exit_event = m5.simulate() 109 | 110 | if exit_event.getCause() == "m5_exit instruction encountered": 111 | # Reached the end of workload of interest 112 | print("Finshed running the workload!") 113 | print("Dumping the stats!") 114 | m5.stats.dump() 115 | end_tick = m5.curTick() 116 | m5.stats.reset() 117 | print("Simulated time: %.2fs" % ((end_tick-start_tick)/1e12)) 118 | exit(0) 119 | else: 120 | print("Unexpected termination of simulation !") 121 | exit(1) 122 | -------------------------------------------------------------------------------- /configs-keystone-fu540/run_untrusted.py: -------------------------------------------------------------------------------- 1 | #Copyright (c) 2021 The Regents of the University of California. 2 | #All Rights Reserved 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are 6 | # met: redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer; 8 | # redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution; 11 | # neither the name of the copyright holders nor the names of its 12 | # contributors may be used to endorse or promote products derived from 13 | # this software without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | # 27 | 28 | """ 29 | This script is supposed to run keystone benchmarks 30 | """ 31 | 32 | import time 33 | import argparse 34 | 35 | import m5 36 | import m5.ticks 37 | from m5.objects import * 38 | 39 | from system import * 40 | 41 | def parse_options(): 42 | parser = argparse.ArgumentParser(description='Runs Linux boot test with' 43 | 'RISCV. Expects the disk image to call the simulator exit' 44 | 'event after boot.') 45 | parser.add_argument("sbi", help='Path to the opensbi' 46 | 'binary with kernel payload') 47 | parser.add_argument("disk", help="Path to the disk image to boot") 48 | parser.add_argument("cpu_type", help="The type of CPU in the system") 49 | parser.add_argument("num_cpus", type=int, help="Number of CPU cores") 50 | parser.add_argument("bench", help="Benchmark to simulate") 51 | 52 | return parser.parse_args() 53 | 54 | def writeBenchScript(dir, bench): 55 | """ 56 | This method creates a script in dir which will be eventually 57 | passed to the simulated system (to run a specific benchmark 58 | at bootup). 59 | """ 60 | file_name = '{}/run_{}'.format(dir, bench) 61 | bench_file = open(file_name,"w+") 62 | bench_file.write('cd /root/ \n') 63 | bench_file.write('/sbin/m5 exit \n') 64 | bench_file.write('riscv64/{} \n'.format(args.bench)) 65 | bench_file.write('/sbin/m5 exit \n') 66 | bench_file.close() 67 | return file_name 68 | 69 | 70 | if __name__ == "__m5_main__": 71 | 72 | args = parse_options() 73 | 74 | # create the system we are going to simulate 75 | 76 | system = RiscvSystem(args.sbi, args.disk, args.cpu_type, args.num_cpus) 77 | 78 | # Exit from guest on workbegin/workend 79 | system.exit_on_work_items = True 80 | 81 | # Create and pass a script to the simulated system to run the reuired 82 | # benchmark 83 | system.readfile = writeBenchScript(m5.options.outdir, args.bench) 84 | 85 | # set up the root SimObject and start the simulation 86 | root = Root(full_system = True, system = system) 87 | 88 | # Required for long-running jobs 89 | #m5.disableAllListeners() 90 | 91 | # instantiate all of the objects we've created above 92 | m5.instantiate() 93 | 94 | globalStart = time.time() 95 | 96 | print("Running the simulation") 97 | exit_event = m5.simulate() 98 | 99 | if exit_event.getCause() == "m5_exit instruction encountered": 100 | # Reached the start of actual benchmark 101 | print("Starting actual workload!") 102 | m5.stats.reset() 103 | start_tick = m5.curTick() 104 | else: 105 | print("Unexpected termination of simulation !") 106 | exit(1) 107 | 108 | exit_event = m5.simulate() 109 | 110 | if exit_event.getCause() == "m5_exit instruction encountered": 111 | # Reached the end of workload of interest 112 | print("Finshed running the workload!") 113 | print("Dumping the stats!") 114 | m5.stats.dump() 115 | end_tick = m5.curTick() 116 | m5.stats.reset() 117 | print("Simulated time: %.2fs" % ((end_tick-start_tick)/1e12)) 118 | exit(0) 119 | else: 120 | print("Unexpected termination of simulation !") 121 | exit(1) 122 | -------------------------------------------------------------------------------- /configs-keystone-large/run_untrusted.py: -------------------------------------------------------------------------------- 1 | #Copyright (c) 2021 The Regents of the University of California. 2 | #All Rights Reserved 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are 6 | # met: redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer; 8 | # redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution; 11 | # neither the name of the copyright holders nor the names of its 12 | # contributors may be used to endorse or promote products derived from 13 | # this software without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | # 27 | 28 | """ 29 | This script is supposed to run keystone benchmarks 30 | """ 31 | 32 | import time 33 | import argparse 34 | 35 | import m5 36 | import m5.ticks 37 | from m5.objects import * 38 | 39 | from system import * 40 | 41 | def parse_options(): 42 | parser = argparse.ArgumentParser(description='Runs Linux boot test with' 43 | 'RISCV. Expects the disk image to call the simulator exit' 44 | 'event after boot.') 45 | parser.add_argument("sbi", help='Path to the opensbi' 46 | 'binary with kernel payload') 47 | parser.add_argument("disk", help="Path to the disk image to boot") 48 | parser.add_argument("cpu_type", help="The type of CPU in the system") 49 | parser.add_argument("num_cpus", type=int, help="Number of CPU cores") 50 | parser.add_argument("bench", help="Benchmark to simulate") 51 | 52 | return parser.parse_args() 53 | 54 | def writeBenchScript(dir, bench): 55 | """ 56 | This method creates a script in dir which will be eventually 57 | passed to the simulated system (to run a specific benchmark 58 | at bootup). 59 | """ 60 | file_name = '{}/run_{}'.format(dir, bench) 61 | bench_file = open(file_name,"w+") 62 | bench_file.write('cd /root/ \n') 63 | bench_file.write('/sbin/m5 exit \n') 64 | bench_file.write('riscv64/{} \n'.format(args.bench)) 65 | bench_file.write('/sbin/m5 exit \n') 66 | bench_file.close() 67 | return file_name 68 | 69 | 70 | if __name__ == "__m5_main__": 71 | 72 | args = parse_options() 73 | 74 | # create the system we are going to simulate 75 | 76 | system = RiscvSystem(args.sbi, args.disk, args.cpu_type, args.num_cpus) 77 | 78 | # Exit from guest on workbegin/workend 79 | system.exit_on_work_items = True 80 | 81 | # Create and pass a script to the simulated system to run the reuired 82 | # benchmark 83 | system.readfile = writeBenchScript(m5.options.outdir, args.bench) 84 | 85 | # set up the root SimObject and start the simulation 86 | root = Root(full_system = True, system = system) 87 | 88 | # Required for long-running jobs 89 | #m5.disableAllListeners() 90 | 91 | # instantiate all of the objects we've created above 92 | m5.instantiate() 93 | 94 | globalStart = time.time() 95 | 96 | print("Running the simulation") 97 | exit_event = m5.simulate() 98 | 99 | if exit_event.getCause() == "m5_exit instruction encountered": 100 | # Reached the start of actual benchmark 101 | print("Starting actual workload!") 102 | m5.stats.reset() 103 | start_tick = m5.curTick() 104 | else: 105 | print("Unexpected termination of simulation !") 106 | exit(1) 107 | 108 | exit_event = m5.simulate() 109 | 110 | if exit_event.getCause() == "m5_exit instruction encountered": 111 | # Reached the end of workload of interest 112 | print("Finshed running the workload!") 113 | print("Dumping the stats!") 114 | m5.stats.dump() 115 | end_tick = m5.curTick() 116 | m5.stats.reset() 117 | print("Simulated time: %.2fs" % ((end_tick-start_tick)/1e12)) 118 | exit(0) 119 | else: 120 | print("Unexpected termination of simulation !") 121 | exit(1) 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Keystone Runs in gem5 2 | 3 | This document explains how to setup all components to run Keystone on gem5. 4 | Some of the instructions (relevant to building Keystone components) are a summarized form of the keystone setup instructions from the Keystone [documentation](http://docs.keystone-enclave.org/). 5 | 6 | 7 | Pre-requisite libraries needed: 8 | 9 | ```sh 10 | sudo apt update 11 | sudo apt install autoconf automake autotools-dev bc \ 12 | bison build-essential curl expat libexpat1-dev libexpat-dev flex gawk gcc git \ 13 | gperf libgmp-dev libmpc-dev libmpfr-dev libtool texinfo tmux \ 14 | patchutils zlib1g-dev wget bzip2 patch vim-common lbzip2 python \ 15 | pkg-config libglib2.0-dev libpixman-1-dev libssl-dev screen \ 16 | device-tree-compiler expect makeself unzip cpio rsync cmake p7zip-full 17 | ``` 18 | 19 | Clone the main keystone repo: 20 | 21 | ```sh 22 | git clone https://github.com/keystone-enclave/keystone.git 23 | ``` 24 | 25 | A quick way to do initial set-up is running `fast-setup.sh` script in `keystone` directory: 26 | 27 | ```sh 28 | cd keystone 29 | # Optionally to checkout the version we tested: 30 | git checkout a1842a1ec959c4e40ffd55091795bb577894c545 31 | ./fast-setup.sh 32 | ``` 33 | 34 | This should build/install needed tool-chain as well: 35 | 36 | Then to set all the environment variables: 37 | 38 | ```sh 39 | source source.sh 40 | ``` 41 | 42 | Then to build all components: 43 | 44 | ```sh 45 | mkdir build 46 | cd build 47 | cmake .. 48 | make 49 | ``` 50 | 51 | This would build all the components needed to run Keystone. 52 | The built disk image (build/buildroot.build/images/rootfs.ext2) will contain test binaries, eyrie runtime and a test runner application all combined into a single package. 53 | 54 | Assuming that you are in the build/ directory, the created disk image can be found in `buildroot.build/images/rootfs.ext2` 55 | 56 | Bootloader compiled with SM and the Linux kernel will be here: 57 | 58 | `sm.build/platform/generic/firmware/fw_payload.elf` 59 | 60 | One change that is still needed in the disk image is to remove a networking related init script: 61 | 62 | ```sh 63 | cd buildroot.build/images/; 64 | mkdir mnt; 65 | mount -o loop rootfs.ext2 mnt/; 66 | rm ../etc/init.d/S40network ; 67 | umount mnt/; 68 | ``` 69 | 70 | Linux would still boot on gem5 with this init script, but it makes the booting process very slow (as a networking device is nor supported yet for RISC-V and this script keeps scanning for it). 71 | 72 | 73 | 74 | ## To compile and run RV8 benchmarks 75 | 76 | First building musl riscv toolchain: 77 | 78 | ```sh 79 | git clone https://github.com/rv8-io/musl-riscv-toolchain.git 80 | cd musl-riscv-toolchain 81 | sh bootstrap.sh riscv64 82 | ``` 83 | 84 | You might need to apply this patch before building the toolchain: 85 | `https://github.com/michaeljclark/musl-riscv-toolchain/pull/5`. 86 | 87 | `RISCV_MUSL` env variable should be set to the path of the built toolchain: 88 | 89 | To build the workloads: 90 | 91 | ```sh 92 | git clone https://github.com/keystone-enclave/rv8-bench.git 93 | cd rv8-bench 94 | git checkout keystone 95 | make 96 | ``` 97 | 98 | We will have to separately compile eyrie runtime, the one that is built by default as in above instructions will not work for unmodified rv8 benchmarks: 99 | 100 | ```sh 101 | cd keystone/build/examples/tests/runtime/src/eyrie-test-eyrie; 102 | /build.sh freemem untrusted_io_syscall env_setup linux_syscall; 103 | ``` 104 | 105 | Add the build runtime to the disk image. 106 | 107 | 108 | ## Using this with gem5 109 | 110 | gem5 scripts are available in [configs-riscv-keystone](configs-riscv-keystone/). 111 | 112 | The command to use: 113 | 114 | ```sh 115 | build/RISCV/gem5.opt configs-riscv-keystone/run_trusted.py [path to fw_payload.elf] [path to rootfs.ext2] [cpu type] [number of cores] [rv8 benchmark name] 116 | ``` 117 | 118 | Note that there are some kernel command line arguments passed in the above scripts that are needed to run keystone on gem5. 119 | 120 | **Note:** You can also look at the instructions to compile/build each individual artifact in `launch_keystone_experiments.py` script in this repo. 121 | 122 | # Keystone Runs in gem5 using gem5art 123 | 124 | 125 | If you want to do run Keystone experiments using `gem5art` run: 126 | 127 | ```sh 128 | GEM5ART_DB="[path to the mongodb database]" python3 launch_keystone_experiments.py 129 | ``` 130 | 131 | `GEM5ART_DB` by default will point to a mongodb database on local system. 132 | 133 | For DArchr: 134 | 135 | ```sh 136 | GEM5ART_DB="mongodb://glacier.cs.ucdavis.edu" python3 launch_keystone_experiments.py 137 | ``` 138 | 139 | ## Citation 140 | 141 | ``` 142 | @inproceedings{akram21carrv, 143 | title={Enabling Design Space Exploration for RISC-V Secure Compute Environments}, 144 | author={Akram, Ayaz and Akella, Venkatesh and Peisert, Sean and Lowe-Power, Jason}, 145 | booktitle={Fifth Workshop on Computer Architecture Research with RISC-V (CARRV 2021)}, 146 | pages={1--7}, 147 | year={2021} 148 | } 149 | ``` -------------------------------------------------------------------------------- /configs-keystone-default/run_trusted.py: -------------------------------------------------------------------------------- 1 | #Copyright (c) 2021 The Regents of the University of California. 2 | #All Rights Reserved 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are 6 | # met: redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer; 8 | # redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution; 11 | # neither the name of the copyright holders nor the names of its 12 | # contributors may be used to endorse or promote products derived from 13 | # this software without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | # 27 | 28 | """ 29 | This script is supposed to run keystone benchmarks 30 | """ 31 | 32 | import time 33 | import argparse 34 | 35 | import m5 36 | import m5.ticks 37 | from m5.objects import * 38 | 39 | from system import * 40 | 41 | def parse_options(): 42 | parser = argparse.ArgumentParser(description='Runs Linux boot test with' 43 | 'RISCV. Expects the disk image to call the simulator exit' 44 | 'event after boot.') 45 | parser.add_argument("sbi", help='Path to the opensbi' 46 | 'binary with kernel payload') 47 | parser.add_argument("disk", help="Path to the disk image to boot") 48 | parser.add_argument("cpu_type", help="The type of CPU in the system") 49 | parser.add_argument("num_cpus", type=int, help="Number of CPU cores") 50 | parser.add_argument("bench", help="Benchmark to simulate") 51 | 52 | return parser.parse_args() 53 | 54 | def writeBenchScript(dir, bench): 55 | """ 56 | This method creates a script in dir which will be eventually 57 | passed to the simulated system (to run a specific benchmark 58 | at bootup). 59 | """ 60 | file_name = '{}/run_{}'.format(dir, bench) 61 | bench_file = open(file_name,"w+") 62 | bench_file.write('cd /root/ \n') 63 | bench_file.write('insmod keystone-driver.ko \n') 64 | bench_file.write('/sbin/m5 exit \n') 65 | bench_file.write('./test-runner ' \ 66 | 'riscv64/{} ' \ 67 | 'eyrie-rt --utm-size 4096 ' \ 68 | '--freemem-size 262144 --time \n'.format(args.bench)) 69 | bench_file.write('/sbin/m5 exit \n') 70 | bench_file.close() 71 | return file_name 72 | 73 | 74 | if __name__ == "__m5_main__": 75 | 76 | args = parse_options() 77 | 78 | # create the system we are going to simulate 79 | 80 | system = RiscvSystem(args.sbi, args.disk, args.cpu_type, args.num_cpus) 81 | 82 | # Exit from guest on workbegin/workend 83 | system.exit_on_work_items = True 84 | 85 | # Create and pass a script to the simulated system to run the reuired 86 | # benchmark 87 | system.readfile = writeBenchScript(m5.options.outdir, args.bench) 88 | 89 | # set up the root SimObject and start the simulation 90 | root = Root(full_system = True, system = system) 91 | 92 | # Required for long-running jobs 93 | m5.disableAllListeners() 94 | 95 | # instantiate all of the objects we've created above 96 | m5.instantiate() 97 | 98 | globalStart = time.time() 99 | 100 | print("Running the simulation") 101 | exit_event = m5.simulate() 102 | 103 | if exit_event.getCause() == "m5_exit instruction encountered": 104 | # Reached the start of actual benchmark 105 | print("Starting actual workload!") 106 | m5.stats.reset() 107 | start_tick = m5.curTick() 108 | else: 109 | print("Unexpected termination of simulation !") 110 | exit(1) 111 | 112 | exit_event = m5.simulate() 113 | 114 | if exit_event.getCause() == "m5_exit instruction encountered": 115 | # Reached the end of workload of interest 116 | print("Finshed running the workload!") 117 | print("Dumping the stats!") 118 | m5.stats.dump() 119 | end_tick = m5.curTick() 120 | m5.stats.reset() 121 | print("Simulated time: %.2fs" % ((end_tick-start_tick)/1e12)) 122 | exit(0) 123 | else: 124 | print("Unexpected termination of simulation !") 125 | exit(1) 126 | -------------------------------------------------------------------------------- /configs-keystone-fu540/run_trusted.py: -------------------------------------------------------------------------------- 1 | #Copyright (c) 2021 The Regents of the University of California. 2 | #All Rights Reserved 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are 6 | # met: redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer; 8 | # redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution; 11 | # neither the name of the copyright holders nor the names of its 12 | # contributors may be used to endorse or promote products derived from 13 | # this software without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | # 27 | 28 | """ 29 | This script is supposed to run keystone benchmarks 30 | """ 31 | 32 | import time 33 | import argparse 34 | 35 | import m5 36 | import m5.ticks 37 | from m5.objects import * 38 | 39 | from system import * 40 | 41 | def parse_options(): 42 | parser = argparse.ArgumentParser(description='Runs Linux boot test with' 43 | 'RISCV. Expects the disk image to call the simulator exit' 44 | 'event after boot.') 45 | parser.add_argument("sbi", help='Path to the opensbi' 46 | 'binary with kernel payload') 47 | parser.add_argument("disk", help="Path to the disk image to boot") 48 | parser.add_argument("cpu_type", help="The type of CPU in the system") 49 | parser.add_argument("num_cpus", type=int, help="Number of CPU cores") 50 | parser.add_argument("bench", help="Benchmark to simulate") 51 | 52 | return parser.parse_args() 53 | 54 | def writeBenchScript(dir, bench): 55 | """ 56 | This method creates a script in dir which will be eventually 57 | passed to the simulated system (to run a specific benchmark 58 | at bootup). 59 | """ 60 | file_name = '{}/run_{}'.format(dir, bench) 61 | bench_file = open(file_name,"w+") 62 | bench_file.write('cd /root/ \n') 63 | bench_file.write('insmod keystone-driver.ko \n') 64 | bench_file.write('/sbin/m5 exit \n') 65 | bench_file.write('./test-runner ' \ 66 | 'riscv64/{} ' \ 67 | 'eyrie-rt --utm-size 4096 ' \ 68 | '--freemem-size 262144 --time \n'.format(args.bench)) 69 | bench_file.write('/sbin/m5 exit \n') 70 | bench_file.close() 71 | return file_name 72 | 73 | 74 | if __name__ == "__m5_main__": 75 | 76 | args = parse_options() 77 | 78 | # create the system we are going to simulate 79 | 80 | system = RiscvSystem(args.sbi, args.disk, args.cpu_type, args.num_cpus) 81 | 82 | # Exit from guest on workbegin/workend 83 | system.exit_on_work_items = True 84 | 85 | # Create and pass a script to the simulated system to run the reuired 86 | # benchmark 87 | system.readfile = writeBenchScript(m5.options.outdir, args.bench) 88 | 89 | # set up the root SimObject and start the simulation 90 | root = Root(full_system = True, system = system) 91 | 92 | # Required for long-running jobs 93 | m5.disableAllListeners() 94 | 95 | # instantiate all of the objects we've created above 96 | m5.instantiate() 97 | 98 | globalStart = time.time() 99 | 100 | print("Running the simulation") 101 | exit_event = m5.simulate() 102 | 103 | if exit_event.getCause() == "m5_exit instruction encountered": 104 | # Reached the start of actual benchmark 105 | print("Starting actual workload!") 106 | m5.stats.reset() 107 | start_tick = m5.curTick() 108 | else: 109 | print("Unexpected termination of simulation !") 110 | exit(1) 111 | 112 | exit_event = m5.simulate() 113 | 114 | if exit_event.getCause() == "m5_exit instruction encountered": 115 | # Reached the end of workload of interest 116 | print("Finshed running the workload!") 117 | print("Dumping the stats!") 118 | m5.stats.dump() 119 | end_tick = m5.curTick() 120 | m5.stats.reset() 121 | print("Simulated time: %.2fs" % ((end_tick-start_tick)/1e12)) 122 | exit(0) 123 | else: 124 | print("Unexpected termination of simulation !") 125 | exit(1) 126 | -------------------------------------------------------------------------------- /configs-keystone-large/run_trusted.py: -------------------------------------------------------------------------------- 1 | #Copyright (c) 2021 The Regents of the University of California. 2 | #All Rights Reserved 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are 6 | # met: redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer; 8 | # redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution; 11 | # neither the name of the copyright holders nor the names of its 12 | # contributors may be used to endorse or promote products derived from 13 | # this software without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | # 27 | 28 | """ 29 | This script is supposed to run keystone benchmarks 30 | """ 31 | 32 | import time 33 | import argparse 34 | 35 | import m5 36 | import m5.ticks 37 | from m5.objects import * 38 | 39 | from system import * 40 | 41 | def parse_options(): 42 | parser = argparse.ArgumentParser(description='Runs Linux boot test with' 43 | 'RISCV. Expects the disk image to call the simulator exit' 44 | 'event after boot.') 45 | parser.add_argument("sbi", help='Path to the opensbi' 46 | 'binary with kernel payload') 47 | parser.add_argument("disk", help="Path to the disk image to boot") 48 | parser.add_argument("cpu_type", help="The type of CPU in the system") 49 | parser.add_argument("num_cpus", type=int, help="Number of CPU cores") 50 | parser.add_argument("bench", help="Benchmark to simulate") 51 | 52 | return parser.parse_args() 53 | 54 | def writeBenchScript(dir, bench): 55 | """ 56 | This method creates a script in dir which will be eventually 57 | passed to the simulated system (to run a specific benchmark 58 | at bootup). 59 | """ 60 | file_name = '{}/run_{}'.format(dir, bench) 61 | bench_file = open(file_name,"w+") 62 | bench_file.write('cd /root/ \n') 63 | bench_file.write('insmod keystone-driver.ko \n') 64 | bench_file.write('/sbin/m5 exit \n') 65 | bench_file.write('./test-runner ' \ 66 | 'riscv64/{} ' \ 67 | 'eyrie-rt --utm-size 4096 ' \ 68 | '--freemem-size 262144 --time \n'.format(args.bench)) 69 | bench_file.write('/sbin/m5 exit \n') 70 | bench_file.close() 71 | return file_name 72 | 73 | 74 | if __name__ == "__m5_main__": 75 | 76 | args = parse_options() 77 | 78 | # create the system we are going to simulate 79 | 80 | system = RiscvSystem(args.sbi, args.disk, args.cpu_type, args.num_cpus) 81 | 82 | # Exit from guest on workbegin/workend 83 | system.exit_on_work_items = True 84 | 85 | # Create and pass a script to the simulated system to run the reuired 86 | # benchmark 87 | system.readfile = writeBenchScript(m5.options.outdir, args.bench) 88 | 89 | # set up the root SimObject and start the simulation 90 | root = Root(full_system = True, system = system) 91 | 92 | # Required for long-running jobs 93 | m5.disableAllListeners() 94 | 95 | # instantiate all of the objects we've created above 96 | m5.instantiate() 97 | 98 | globalStart = time.time() 99 | 100 | print("Running the simulation") 101 | exit_event = m5.simulate() 102 | 103 | if exit_event.getCause() == "m5_exit instruction encountered": 104 | # Reached the start of actual benchmark 105 | print("Starting actual workload!") 106 | m5.stats.reset() 107 | start_tick = m5.curTick() 108 | else: 109 | print("Unexpected termination of simulation !") 110 | exit(1) 111 | 112 | exit_event = m5.simulate() 113 | 114 | if exit_event.getCause() == "m5_exit instruction encountered": 115 | # Reached the end of workload of interest 116 | print("Finshed running the workload!") 117 | print("Dumping the stats!") 118 | m5.stats.dump() 119 | end_tick = m5.curTick() 120 | m5.stats.reset() 121 | print("Simulated time: %.2fs" % ((end_tick-start_tick)/1e12)) 122 | exit(0) 123 | else: 124 | print("Unexpected termination of simulation !") 125 | exit(1) 126 | -------------------------------------------------------------------------------- /launch_keystone_experiments.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This is a job launch script to run experiments 4 | # using RISCV's Keystone TEE on gem5 5 | # Other details of these experiments can also be 6 | # found in the CARRV paper "Enabling Design Space Exploration 7 | # for RISC-V Secure Compute Environments" 8 | 9 | import os 10 | import sys 11 | from uuid import UUID 12 | from itertools import starmap 13 | from itertools import product 14 | 15 | from gem5art.artifact.artifact import Artifact 16 | from gem5art.run import gem5Run 17 | from gem5art.tasks.tasks import run_job_pool 18 | 19 | 20 | experiments_repo = Artifact.registerArtifact( 21 | command = 'https://github.com/darchr/Keystone-experiments.git', 22 | typ = 'git repo', 23 | name = 'Keystone-experiments', 24 | path = './', 25 | cwd = '../', 26 | documentation = 'main experiments repo to run keystone experiments on gem5' 27 | ) 28 | 29 | gem5_repo = Artifact.registerArtifact( 30 | command = 'git clone https://gem5.googlesource.com/public/gem5', 31 | typ = 'git repo', 32 | name = 'gem5', 33 | path = 'gem5/', 34 | cwd = './', 35 | documentation = 'cloned gem5 from googlesource and checked out develop version (as around June 1)' 36 | ) 37 | 38 | gem5_binary = Artifact.registerArtifact( 39 | command = '''cd gem5; 40 | git checkout 62610709df76f4b544769cbbb; 41 | git apply ../0001-arch-riscv-Update-the-way-a-valid-virtual-address-is.patch; 42 | scons build/RISCV/gem5.opt -j8 43 | ''', 44 | typ = 'gem5 binary', 45 | name = 'gem5', 46 | cwd = 'gem5/', 47 | path = 'gem5/build/RISCV/gem5.opt', 48 | inputs = [gem5_repo, experiments_repo], 49 | documentation = 'gem5 binary based on develop version (as around June 1) and applied two patches which are currently under review on gerrit' 50 | ) 51 | 52 | m5_binary = Artifact.registerArtifact( 53 | command = 'scons -C util/m5 build/riscv/out/m5', 54 | typ = 'binary', 55 | name = 'm5', 56 | path = 'gem5/util/m5/build/riscv/out/m5', 57 | cwd = 'gem5/util/m5', 58 | inputs = [gem5_repo,], 59 | documentation = 'm5 utility' 60 | ) 61 | 62 | keystone_repo = Artifact.registerArtifact( 63 | command = 'git clone https://github.com/keystone-enclave/keystone.git', 64 | typ = 'git repo', 65 | name = 'keystone', 66 | cwd = './', 67 | path = 'keystone/', 68 | inputs = [], 69 | documentation = 'Keystone enclave github repo' 70 | ) 71 | 72 | eyrie_runtime = Artifact.registerArtifact( 73 | command = '''cd keystone; 74 | git checkout a1842a1ec959c4e40ffd55091795bb577894c545; 75 | ./fast-setup.sh; 76 | source source.sh; 77 | mkdir build; 78 | cd build; 79 | cmake ..; 80 | make -j64; 81 | cd keystone/build/examples/tests/runtime/src/eyrie-test-eyrie; 82 | ./build.sh freemem untrusted_io_syscall env_setup linux_syscall; 83 | ''', 84 | typ = 'binary', 85 | name = 'eyrie runtime', 86 | path = 'keystone/build/examples/tests/runtime/src/eyrie-test-eyrie/eyrie-rt', 87 | cwd = './', 88 | inputs = [keystone_repo,], 89 | documentation = 'Eyrie runtime with paging enabled to run rv8 benchmarks' 90 | ) 91 | 92 | keystone_driver = Artifact.registerArtifact( 93 | command = '''cd keystone; 94 | git checkout a1842a1ec959c4e40ffd55091795bb577894c545; 95 | ./fast-setup.sh; 96 | source source.sh; 97 | mkdir build; 98 | cd build; 99 | cmake ..; 100 | make -j64; 101 | ''', 102 | typ = 'binary', 103 | name = 'keystone driver', 104 | path = 'keystone/build/linux-keystone-driver.build/keystone-driver.ko', 105 | cwd = './', 106 | inputs = [keystone_repo,], 107 | documentation = 'Keystone linux driver' 108 | ) 109 | 110 | test_runner = Artifact.registerArtifact( 111 | command = '''cd keystone; 112 | git checkout a1842a1ec959c4e40ffd55091795bb577894c545; 113 | ./fast-setup.sh; 114 | source source.sh; 115 | mkdir build; 116 | cd build; 117 | cmake ..; 118 | make -j64; 119 | ''', 120 | typ = 'binary', 121 | name = 'test runner', 122 | path = 'keystone/build/examples/tests/test-runner', 123 | cwd = './', 124 | inputs = [keystone_repo,], 125 | documentation = 'Test (untrusted) runner application' 126 | ) 127 | 128 | musl_tool = Artifact.registerArtifact( 129 | command = '''git clone https://github.com/rv8-io/musl-riscv-toolchain.git; 130 | cd musl-riscv-toolchain; 131 | cp ../bootstrap_musl_riscv.sh bootstrap.sh; 132 | sh bootstrap.sh riscv64; 133 | ''', 134 | typ = 'git repo', 135 | name = 'test runner', 136 | path = 'musl-riscv-toolchain/', 137 | cwd = './', 138 | inputs = [experiments_repo,], 139 | documentation = 'musl riscv toolchain to compile rv8 benchmarks' 140 | ) 141 | 142 | rv8_bench = Artifact.registerArtifact( 143 | command = '''https://github.com/keystone-enclave/rv8-bench.git; 144 | cd rv8-bench; 145 | git checkout keystone; 146 | export PATH=$PATH:/opt/riscv/musl-riscv-toolchain-8.2.0-1/bin/; 147 | make 148 | ''', 149 | typ = 'git repo', 150 | name = 'rv8 source', 151 | path = 'rv8-bench/', 152 | cwd = './', 153 | inputs = [experiments_repo, musl_tool], 154 | documentation = 'rv8 benchmarks' 155 | ) 156 | 157 | disk_image = Artifact.registerArtifact( 158 | command = '''cd keystone; 159 | git checkout a1842a1ec959c4e40ffd55091795bb577894c545; 160 | ./fast-setup.sh; 161 | source source.sh; 162 | mkdir build; 163 | cd build; 164 | cmake ..; 165 | make -j64; 166 | cd buildroot.build/images/; 167 | mkdir mnt; 168 | mount -o loop rootfs.ext2 mnt/; 169 | cd mnt/root/; 170 | cp ../../../../examples/tests/runtime/src/eyrie-test-eyrie/eyrie-rt . ; 171 | cp -r ../../../../../../keystone-bench/rv8-bench/bin/riscv64/ . ; 172 | cp ../../../../../../runscript.sh . ; 173 | cp ../../../../examples/tests/test-runner . ; 174 | cp ../../../../../../inittab ../etc/inittab ; 175 | rm ../etc/init.d/S40network ; 176 | cp ../../../../../../gem5/util/m5/build/riscv/out/m5 /sbin/m5; 177 | cd ../../ ; 178 | umount mnt/; 179 | ''', 180 | typ = 'disk image', 181 | name = 'keystone-disk', 182 | cwd = './', 183 | path = 'keystone/build/buildroot.build/images/rootfs.ext2', 184 | inputs = [experiments_repo, keystone_repo, m5_binary, eyrie_runtime, rv8_bench,], 185 | documentation = 'Keystone disk image with RV8 benchamarks in addition to other needed components/changes to run the experiments' 186 | ) 187 | 188 | linux_repo = Artifact.registerArtifact( 189 | command = '''cd keystone; 190 | git checkout a1842a1ec959c4e40ffd55091795bb577894c545; 191 | ./fast-setup.sh; 192 | ''', 193 | typ = 'git repo', 194 | name = 'linux source', 195 | path = 'keystone/linux', 196 | inputs = [keystone_repo,], 197 | cwd = './', 198 | documentation = 'Linux kernel source (v5.7)' 199 | ) 200 | 201 | linux_binary = Artifact.registerArtifact( 202 | command = '''cd keystone; 203 | git checkout a1842a1ec959c4e40ffd55091795bb577894c545; 204 | ./fast-setup.sh; 205 | source source.sh; 206 | mkdir build; 207 | cd build; 208 | cmake ..; 209 | make -j64; 210 | ''', 211 | typ = 'binary', 212 | name = 'vmlinux', 213 | path = 'keystone/build/linux.build/vmlinux', 214 | inputs = [keystone_repo,linux_repo], 215 | cwd = './', 216 | documentation = 'linux kernel binary which will be embedded into opensbi' 217 | ) 218 | 219 | firmware_binary = Artifact.registerArtifact( 220 | command = '''cd keystone; 221 | git checkout a1842a1ec959c4e40ffd55091795bb577894c545; 222 | ./fast-setup.sh; 223 | source source.sh; 224 | mkdir build; 225 | cd build; 226 | cmake ..; 227 | make -j64; 228 | ''', 229 | typ = 'binary', 230 | name = 'firmware', 231 | path = 'keystone/build/sm.build/platform/generic/firmware/fw_payload.elf', 232 | inputs = [linux_binary, keystone_repo], 233 | cwd = './', 234 | documentation = 'opensbi with keystone security monitor + linux kernel' 235 | ) 236 | 237 | if __name__ == "__main__": 238 | num_cpus = ['1'] 239 | cpu_types = ['timing','minor'] 240 | benchmarks = ['aes.O3', 'bigint.O3', 'dhrystone.O3', 'miniz.O3', 'norx.O3', 'primes.O3', 'qsort.O3', 'sha512.O3'] 241 | configs = ['untrusted', 'trusted'] 242 | # uarchitectures = ['default', 'fu540', 'large'] 243 | # commenting the above line because default has already been run 244 | uarchitectures = ['fu540', 'large'] 245 | 246 | def createRun(uarch, config, cpu, num_cpu, bench): 247 | 248 | return gem5Run.createFSRun( 249 | 'keystone experiments with gem5 for carrv (june 5)', 250 | 'gem5/build/RISCV/gem5.opt', 251 | 'configs-keystone-{}/run_{}.py'.format(uarch,config), 252 | 'results/{}/{}/{}/{}/{}'.format(uarch, config, bench, cpu, num_cpu), 253 | gem5_binary, gem5_repo, experiments_repo, 254 | 'keystone/build/sm.build/platform/generic/firmware/fw_payload.elf', 255 | 'keystone/build/buildroot.build/images/rootfs.ext2', 256 | firmware_binary, disk_image, 257 | cpu, num_cpu, bench, 258 | timeout = 20*60*60 #20 hours 259 | ) 260 | 261 | # For the cross product of tests, create a run object. 262 | runs = starmap(createRun, product(uarchitectures, configs, cpu_types, num_cpus, benchmarks)) 263 | # Run all of these experiments in parallel 264 | run_job_pool(runs) 265 | -------------------------------------------------------------------------------- /0002-arch-riscv-add-pma-pmp-checks-during-page-table-walk.patch: -------------------------------------------------------------------------------- 1 | From f4a0d95e0ab96ef157329c0b5889ba4ab1de3ed3 Mon Sep 17 00:00:00 2001 2 | From: Ayaz Akram 3 | Date: Sat, 29 May 2021 01:51:07 -0700 4 | Subject: [PATCH 1/2] arch-riscv: add pma/pmp checks during page table walks 5 | 6 | This change adds pma/pmp checks when page table entries 7 | are accessed by hardware page table walker. 8 | 9 | Change-Id: I161aad514bb7421e61a8c56af088c73969837704 10 | --- 11 | src/arch/riscv/pagetable_walker.cc | 143 +++++++++++++++++------------ 12 | src/arch/riscv/pmp.cc | 24 ++++- 13 | 2 files changed, 103 insertions(+), 64 deletions(-) 14 | 15 | diff --git a/src/arch/riscv/pagetable_walker.cc b/src/arch/riscv/pagetable_walker.cc 16 | index d3c390531..54725e742 100644 17 | --- a/src/arch/riscv/pagetable_walker.cc 18 | +++ b/src/arch/riscv/pagetable_walker.cc 19 | @@ -295,76 +295,99 @@ Walker::WalkerState::stepWalk(PacketPtr &write) 20 | 21 | DPRINTF(PageTableWalker, "Got level%d PTE: %#x\n", level, pte); 22 | 23 | - // step 2: TODO check PMA and PMP 24 | + // step 2: 25 | + // Performing PMA/PMP checks on physical address of PTE 26 | 27 | - // step 3: 28 | - if (!pte.v || (!pte.r && pte.w)) { 29 | - doEndWalk = true; 30 | - DPRINTF(PageTableWalker, "PTE invalid, raising PF\n"); 31 | - fault = pageFault(pte.v); 32 | - } 33 | - else { 34 | - // step 4: 35 | - if (pte.r || pte.x) { 36 | - // step 5: leaf PTE 37 | - doEndWalk = true; 38 | - fault = walker->tlb->checkPermissions(status, pmode, 39 | - entry.vaddr, mode, pte); 40 | - 41 | - // step 6 42 | - if (fault == NoFault) { 43 | - if (level >= 1 && pte.ppn0 != 0) { 44 | - DPRINTF(PageTableWalker, 45 | - "PTE has misaligned PPN, raising PF\n"); 46 | - fault = pageFault(true); 47 | - } 48 | - else if (level == 2 && pte.ppn1 != 0) { 49 | - DPRINTF(PageTableWalker, 50 | - "PTE has misaligned PPN, raising PF\n"); 51 | - fault = pageFault(true); 52 | - } 53 | - } 54 | + walker->pma->check(read->req); 55 | + fault = walker->pmp->pmpCheck(read->req, mode, pmode, tc); 56 | 57 | - if (fault == NoFault) { 58 | - // step 7 59 | - if (!pte.a) { 60 | - pte.a = 1; 61 | - doWrite = true; 62 | - } 63 | - if (!pte.d && mode == TLB::Write) { 64 | - pte.d = 1; 65 | - doWrite = true; 66 | - } 67 | - // TODO check if this violates a PMA or PMP 68 | - 69 | - // step 8 70 | - entry.logBytes = PageShift + (level * LEVEL_BITS); 71 | - entry.paddr = pte.ppn; 72 | - entry.vaddr &= ~((1 << entry.logBytes) - 1); 73 | - entry.pte = pte; 74 | - // put it non-writable into the TLB to detect writes and redo 75 | - // the page table walk in order to update the dirty flag. 76 | - if (!pte.d && mode != TLB::Write) 77 | - entry.pte.w = 0; 78 | - doTLBInsert = true; 79 | - } 80 | + if (fault == NoFault) { 81 | + // step 3: 82 | + if (!pte.v || (!pte.r && pte.w)) { 83 | + doEndWalk = true; 84 | + DPRINTF(PageTableWalker, "PTE invalid, raising PF\n"); 85 | + fault = pageFault(pte.v); 86 | } 87 | else { 88 | - level--; 89 | - if (level < 0) { 90 | - DPRINTF(PageTableWalker, "No leaf PTE found, raising PF\n"); 91 | + // step 4: 92 | + if (pte.r || pte.x) { 93 | + // step 5: leaf PTE 94 | doEndWalk = true; 95 | - fault = pageFault(true); 96 | + fault = walker->tlb->checkPermissions(status, pmode, 97 | + entry.vaddr, mode, pte); 98 | + 99 | + // step 6 100 | + if (fault == NoFault) { 101 | + if (level >= 1 && pte.ppn0 != 0) { 102 | + DPRINTF(PageTableWalker, 103 | + "PTE has misaligned PPN, raising PF\n"); 104 | + fault = pageFault(true); 105 | + } 106 | + else if (level == 2 && pte.ppn1 != 0) { 107 | + DPRINTF(PageTableWalker, 108 | + "PTE has misaligned PPN, raising PF\n"); 109 | + fault = pageFault(true); 110 | + } 111 | + } 112 | + 113 | + if (fault == NoFault) { 114 | + // step 7 115 | + if (!pte.a) { 116 | + pte.a = 1; 117 | + doWrite = true; 118 | + } 119 | + if (!pte.d && mode == TLB::Write) { 120 | + pte.d = 1; 121 | + doWrite = true; 122 | + } 123 | + // Performing PMA/PMP checks 124 | + 125 | + if (doWrite) { 126 | + 127 | + // this read will eventually become write 128 | + // if doWrite is True 129 | + 130 | + walker->pma->check(read->req); 131 | + 132 | + fault = walker->pmp->pmpCheck(read->req, 133 | + mode, pmode, tc); 134 | + 135 | + } 136 | + // perform step 8 only if pmp checks pass 137 | + if (fault == NoFault) { 138 | + 139 | + // step 8 140 | + entry.logBytes = PageShift + (level * LEVEL_BITS); 141 | + entry.paddr = pte.ppn; 142 | + entry.vaddr &= ~((1 << entry.logBytes) - 1); 143 | + entry.pte = pte; 144 | + // put it non-writable into the TLB to detect writes and redo 145 | + // the page table walk in order to update the dirty flag. 146 | + if (!pte.d && mode != TLB::Write) 147 | + entry.pte.w = 0; 148 | + doTLBInsert = true; 149 | + } 150 | + } 151 | } 152 | else { 153 | - Addr shift = (PageShift + LEVEL_BITS * level); 154 | - Addr idx = (entry.vaddr >> shift) & LEVEL_MASK; 155 | - nextRead = (pte.ppn << PageShift) + (idx * sizeof(pte)); 156 | - nextState = Translate; 157 | + level--; 158 | + if (level < 0) { 159 | + DPRINTF(PageTableWalker, "No leaf PTE found, raising PF\n"); 160 | + doEndWalk = true; 161 | + fault = pageFault(true); 162 | + } 163 | + else { 164 | + Addr shift = (PageShift + LEVEL_BITS * level); 165 | + Addr idx = (entry.vaddr >> shift) & LEVEL_MASK; 166 | + nextRead = (pte.ppn << PageShift) + (idx * sizeof(pte)); 167 | + nextState = Translate; 168 | + } 169 | } 170 | } 171 | } 172 | - 173 | + else { 174 | + doEndWalk = true; 175 | + } 176 | PacketPtr oldRead = read; 177 | Request::Flags flags = oldRead->req->getFlags(); 178 | 179 | diff --git a/src/arch/riscv/pmp.cc b/src/arch/riscv/pmp.cc 180 | index e9fcb7b90..9fe0a2db3 100644 181 | --- a/src/arch/riscv/pmp.cc 182 | +++ b/src/arch/riscv/pmp.cc 183 | @@ -57,8 +57,14 @@ PMP::pmpCheck(const RequestPtr &req, BaseTLB::Mode mode, 184 | if (!shouldCheckPMP(pmode, mode, tc)) 185 | return NoFault; 186 | 187 | - DPRINTF(PMP, "Checking pmp permissions for va: %#x , pa: %#x\n", 188 | - req->getVaddr(), req->getPaddr()); 189 | + if (req->hasVaddr()) { 190 | + DPRINTF(PMP, "Checking pmp permissions for va: %#x , pa: %#x\n", 191 | + req->getVaddr(), req->getPaddr()); 192 | + } 193 | + else { // this access is corresponding to a page table walk 194 | + DPRINTF(PMP, "Checking pmp permissions for pa: %#x\n", 195 | + req->getPaddr()); 196 | + } 197 | 198 | // An access should be successful if there are 199 | // no rules defined yet or we are in M mode (based 200 | @@ -100,12 +106,22 @@ PMP::pmpCheck(const RequestPtr &req, BaseTLB::Mode mode, 201 | (PMP_EXEC & allowed_privs)) { 202 | return NoFault; 203 | } else { 204 | - return createAddrfault(req->getVaddr(), mode); 205 | + if (req->hasVaddr()) { 206 | + return createAddrfault(req->getVaddr(), mode); 207 | + } 208 | + else { 209 | + return createAddrfault(req->getPaddr(), mode); 210 | + } 211 | } 212 | } 213 | } 214 | // if no entry matched and we are not in M mode return fault 215 | - return createAddrfault(req->getVaddr(), mode); 216 | + if (req->hasVaddr()) { 217 | + return createAddrfault(req->getVaddr(), mode); 218 | + } 219 | + else { 220 | + return createAddrfault(req->getPaddr(), mode); 221 | + } 222 | } 223 | 224 | Fault 225 | -- 226 | 2.17.1 227 | 228 | -------------------------------------------------------------------------------- /configs-keystone-default/system/system.py: -------------------------------------------------------------------------------- 1 | #Copyright (c) 2021 The Regents of the University of California. 2 | #All Rights Reserved 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are 6 | # met: redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer; 8 | # redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution; 11 | # neither the name of the copyright holders nor the names of its 12 | # contributors may be used to endorse or promote products derived from 13 | # this software without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | # 27 | 28 | import m5 29 | from m5.objects import * 30 | from m5.util import convert 31 | from os import path 32 | 33 | ''' 34 | This class creates a bare bones RISCV full system. 35 | 36 | The targeted system is based on SiFive FU540-C000. 37 | Reference: 38 | [1] https://sifive.cdn.prismic.io/sifive/b5e7a29c- 39 | d3c2-44ea-85fb-acc1df282e21_FU540-C000-v1p3.pdf 40 | ''' 41 | 42 | # Dtb generation code from configs/example/riscv/fs_linux.py 43 | def generateMemNode(state, mem_range): 44 | node = FdtNode("memory@%x" % int(mem_range.start)) 45 | node.append(FdtPropertyStrings("device_type", ["memory"])) 46 | node.append(FdtPropertyWords("reg", 47 | state.addrCells(mem_range.start) + 48 | state.sizeCells(mem_range.size()) )) 49 | return node 50 | 51 | def generateDtb(system): 52 | """ 53 | Autogenerate DTB. Arguments are the folder where the DTB 54 | will be stored, and the name of the DTB file. 55 | """ 56 | state = FdtState(addr_cells=2, size_cells=2, cpu_cells=1) 57 | root = FdtNode('/') 58 | root.append(state.addrCellsProperty()) 59 | root.append(state.sizeCellsProperty()) 60 | root.appendCompatible(["riscv-virtio"]) 61 | 62 | for mem_range in system.mem_ranges: 63 | root.append(generateMemNode(state, mem_range)) 64 | 65 | sections = [*system.cpu, system.platform] 66 | 67 | for section in sections: 68 | for node in section.generateDeviceTree(state): 69 | if node.get_name() == root.get_name(): 70 | root.merge(node) 71 | else: 72 | root.append(node) 73 | 74 | fdt = Fdt() 75 | fdt.add_rootnode(root) 76 | fdt.writeDtsFile(path.join(m5.options.outdir, 'device.dts')) 77 | fdt.writeDtbFile(path.join(m5.options.outdir, 'device.dtb')) 78 | 79 | class RiscvSystem(System): 80 | 81 | def __init__(self, sbi, disk, cpu_type, num_cpus): 82 | super(RiscvSystem, self).__init__() 83 | 84 | # Set up the clock domain and the voltage domain 85 | self.clk_domain = SrcClockDomain() 86 | self.clk_domain.clock = '3GHz' 87 | self.clk_domain.voltage_domain = VoltageDomain() 88 | self.cpu_clk_domain = SrcClockDomain() 89 | self.cpu_clk_domain.voltage_domain = VoltageDomain() 90 | self.cpu_clk_domain.clock = '3GHz' 91 | 92 | # DDR memory range starts from base address 0x80000000 93 | # based on [1] 94 | self.mem_ranges = [AddrRange(start=0x80000000, size='1024MB')] 95 | 96 | # Create the main memory bus 97 | # This connects to main memory 98 | self.membus = SystemXBar(width = 64) # 64-byte width 99 | 100 | self.membus.badaddr_responder = BadAddr() 101 | self.membus.default = Self.badaddr_responder.pio 102 | 103 | # Set up the system port for functional access from the simulator 104 | self.system_port = self.membus.cpu_side_ports 105 | 106 | # Create the CPUs for our system. 107 | self.createCPU(cpu_type, num_cpus) 108 | 109 | # HiFive platform 110 | # This is based on a HiFive RISCV board and has 111 | # only a limited number of devices so far i.e. 112 | # PLIC, CLINT, UART, VirtIOMMIO 113 | self.platform = HiFive() 114 | 115 | # create and intialize devices currently supported for RISCV 116 | self.initDevices(self.membus, disk) 117 | 118 | # Create the cache heirarchy for the system. 119 | self.createCacheHierarchy() 120 | 121 | # Create the memory controller 122 | self.createMemoryControllerDDR3() 123 | 124 | self.setupInterrupts() 125 | 126 | # using RiscvLinux as the base full system workload 127 | self.workload = RiscvLinux() 128 | 129 | # this is user passed berkeley boot loader binary 130 | # currently the Linux kernel payload is compiled into this 131 | # as well 132 | self.workload.object_file = sbi 133 | 134 | # Generate DTB (from configs/example/riscv/fs_linux.py) 135 | generateDtb(self) 136 | self.workload.dtb_filename = path.join(m5.options.outdir, 'device.dtb') 137 | # Default DTB address if bbl is bulit with --with-dts option 138 | self.workload.dtb_addr = 0x87e00000 139 | 140 | # Linux boot command flags 141 | kernel_cmd = [ 142 | "console=ttyS0", 143 | "root=/dev/vda", 144 | "ro", 145 | "cma=512M@0-4G" 146 | ] 147 | self.workload.command_line = " ".join(kernel_cmd) 148 | 149 | def createCPU(self, cpu_type, num_cpus): 150 | # the default cpu will be atomic cpu 151 | if cpu_type == "atomic": 152 | self.cpu = [AtomicSimpleCPU(cpu_id = i) 153 | for i in range(num_cpus)] 154 | self.mem_mode = 'atomic' 155 | 156 | for cpu in self.cpu: 157 | cpu.createThreads() 158 | 159 | elif cpu_type == "timing": 160 | self.cpu = [TimingSimpleCPU(cpu_id = i) 161 | for i in range(num_cpus)] 162 | self.mem_mode = 'timing' 163 | for cpu in self.cpu: 164 | cpu.createThreads() 165 | 166 | elif cpu_type == "minor": 167 | self.cpu = [MinorCPU(cpu_id = i) 168 | for i in range(num_cpus)] 169 | self.mem_mode = 'timing' 170 | for cpu in self.cpu: 171 | cpu.createThreads() 172 | 173 | elif cpu_type == "o3": 174 | self.cpu = [DerivO3CPU(cpu_id = i) 175 | for i in range(num_cpus)] 176 | self.mem_mode = 'timing' 177 | for cpu in self.cpu: 178 | cpu.createThreads() 179 | else: 180 | m5.fatal("No CPU type {}".format(cpu_type)) 181 | 182 | def switchCpus(self, old, new): 183 | assert(new[0].switchedOut()) 184 | m5.switchCpus(self, list(zip(old, new))) 185 | 186 | def createCacheHierarchy(self): 187 | class L1Cache(Cache): 188 | """Simple L1 Cache with default values""" 189 | 190 | assoc = 8 191 | size = '32kB' 192 | tag_latency = 1 193 | data_latency = 1 194 | response_latency = 1 195 | mshrs = 16 196 | tgts_per_mshr = 20 197 | writeback_clean = True 198 | 199 | def __init__(self): 200 | super(L1Cache, self).__init__() 201 | 202 | for cpu in self.cpu: 203 | # Create a very simple cache hierarchy 204 | 205 | # Create an L1 instruction, data and mmu cache 206 | cpu.icache = L1Cache() 207 | cpu.dcache = L1Cache() 208 | cpu.mmucache = L1Cache() 209 | 210 | # Connecting icache and dcache to memory bus and cpu 211 | cpu.icache.mem_side = self.membus.cpu_side_ports 212 | cpu.dcache.mem_side = self.membus.cpu_side_ports 213 | 214 | cpu.icache.cpu_side = cpu.icache_port 215 | cpu.dcache.cpu_side = cpu.dcache_port 216 | 217 | # Need a new crossbar for mmucache 218 | 219 | cpu.mmucache.mmubus = L2XBar() 220 | 221 | cpu.mmucache.cpu_side = cpu.mmucache.mmubus.mem_side_ports 222 | cpu.mmucache.mem_side = self.membus.cpu_side_ports 223 | 224 | # Connect the itb and dtb to mmucache 225 | cpu.mmu.connectWalkerPorts( 226 | cpu.mmucache.mmubus.cpu_side_ports, cpu.mmucache.mmubus.cpu_side_ports) 227 | 228 | 229 | def setupInterrupts(self): 230 | for cpu in self.cpu: 231 | # create the interrupt controller CPU and connect to the membus 232 | cpu.createInterruptController() 233 | 234 | def createMemoryControllerDDR3(self): 235 | self.mem_cntrls = [ 236 | MemCtrl(dram = DDR3_1600_8x8(range = self.mem_ranges[0]), 237 | port = self.membus.mem_side_ports) 238 | ] 239 | 240 | def initDevices(self, membus, disk): 241 | 242 | self.iobus = IOXBar() 243 | #self.intrctrl = IntrControl() 244 | 245 | # Set the frequency of RTC (real time clock) used by 246 | # CLINT (core level interrupt controller). 247 | # This frequency is 1MHz in SiFive's U54MC. 248 | # Setting it to 100MHz for faster simulation (from riscv/fs_linux.py) 249 | self.platform.rtc = RiscvRTC(frequency=Frequency("100MHz")) 250 | 251 | # RTC sends the clock signal to CLINT via an interrupt pin. 252 | self.platform.clint.int_pin = self.platform.rtc.int_pin 253 | 254 | # VirtIOMMIO 255 | image = CowDiskImage(child=RawDiskImage(read_only=True), read_only=False) 256 | image.child.image_file = disk 257 | # using reserved memory space 258 | self.platform.disk = MmioVirtIO( 259 | vio=VirtIOBlock(image=image), 260 | interrupt_id=0x8, 261 | pio_size = 4096, 262 | pio_addr=0x10008000 263 | ) 264 | 265 | # From riscv/fs_linux.py 266 | uncacheable_range = [ 267 | *self.platform._on_chip_ranges(), 268 | *self.platform._off_chip_ranges() 269 | ] 270 | # PMA (physical memory attribute) checker is a hardware structure 271 | # that ensures that physical addresses follow the memory permissions 272 | 273 | # PMA checker can be defined at system-level (system.pma_checker) 274 | # or MMU-level (system.cpu[0].mmu.pma_checker). It will be resolved 275 | # by RiscvTLB's Parent.any proxy 276 | 277 | for cpu in self.cpu: 278 | cpu.mmu.pma_checker = PMAChecker(uncacheable=uncacheable_range) 279 | 280 | self.bridge = Bridge(delay='50ns') 281 | self.bridge.mem_side_port = self.iobus.cpu_side_ports 282 | self.bridge.cpu_side_port = self.membus.mem_side_ports 283 | self.bridge.ranges = self.platform._off_chip_ranges() 284 | 285 | # Connecting on chip and off chip IO to the mem 286 | # and IO bus 287 | self.platform.attachOnChipIO(self.membus) 288 | self.platform.attachOffChipIO(self.iobus) 289 | 290 | # Attach the PLIC (platform level interrupt controller) 291 | # to the platform. This initializes the PLIC with 292 | # interrupt sources coming from off chip devices 293 | self.platform.attachPlic() 294 | -------------------------------------------------------------------------------- /configs-keystone-large/system/system.py: -------------------------------------------------------------------------------- 1 | #Copyright (c) 2021 The Regents of the University of California. 2 | #All Rights Reserved 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are 6 | # met: redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer; 8 | # redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution; 11 | # neither the name of the copyright holders nor the names of its 12 | # contributors may be used to endorse or promote products derived from 13 | # this software without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | # 27 | 28 | import m5 29 | from m5.objects import * 30 | from m5.util import convert 31 | from os import path 32 | 33 | ''' 34 | This class creates a bare bones RISCV full system. 35 | 36 | The targeted system is based on SiFive FU540-C000. 37 | Reference: 38 | [1] https://sifive.cdn.prismic.io/sifive/b5e7a29c- 39 | d3c2-44ea-85fb-acc1df282e21_FU540-C000-v1p3.pdf 40 | ''' 41 | 42 | # Dtb generation code from configs/example/riscv/fs_linux.py 43 | def generateMemNode(state, mem_range): 44 | node = FdtNode("memory@%x" % int(mem_range.start)) 45 | node.append(FdtPropertyStrings("device_type", ["memory"])) 46 | node.append(FdtPropertyWords("reg", 47 | state.addrCells(mem_range.start) + 48 | state.sizeCells(mem_range.size()) )) 49 | return node 50 | 51 | def generateDtb(system): 52 | """ 53 | Autogenerate DTB. Arguments are the folder where the DTB 54 | will be stored, and the name of the DTB file. 55 | """ 56 | state = FdtState(addr_cells=2, size_cells=2, cpu_cells=1) 57 | root = FdtNode('/') 58 | root.append(state.addrCellsProperty()) 59 | root.append(state.sizeCellsProperty()) 60 | root.appendCompatible(["riscv-virtio"]) 61 | 62 | for mem_range in system.mem_ranges: 63 | root.append(generateMemNode(state, mem_range)) 64 | 65 | sections = [*system.cpu, system.platform] 66 | 67 | for section in sections: 68 | for node in section.generateDeviceTree(state): 69 | if node.get_name() == root.get_name(): 70 | root.merge(node) 71 | else: 72 | root.append(node) 73 | 74 | fdt = Fdt() 75 | fdt.add_rootnode(root) 76 | fdt.writeDtsFile(path.join(m5.options.outdir, 'device.dts')) 77 | fdt.writeDtbFile(path.join(m5.options.outdir, 'device.dtb')) 78 | 79 | class RiscvSystem(System): 80 | 81 | def __init__(self, sbi, disk, cpu_type, num_cpus): 82 | super(RiscvSystem, self).__init__() 83 | 84 | # Set up the clock domain and the voltage domain 85 | self.clk_domain = SrcClockDomain() 86 | self.clk_domain.clock = '3GHz' 87 | self.clk_domain.voltage_domain = VoltageDomain() 88 | self.cpu_clk_domain = SrcClockDomain() 89 | self.cpu_clk_domain.voltage_domain = VoltageDomain() 90 | self.cpu_clk_domain.clock = '3GHz' 91 | 92 | # DDR memory range starts from base address 0x80000000 93 | # based on [1] 94 | self.mem_ranges = [AddrRange(start=0x80000000, size='1024MB')] 95 | 96 | # Create the main memory bus 97 | # This connects to main memory 98 | self.membus = SystemXBar(width = 64) # 64-byte width 99 | 100 | self.membus.badaddr_responder = BadAddr() 101 | self.membus.default = Self.badaddr_responder.pio 102 | 103 | # Set up the system port for functional access from the simulator 104 | self.system_port = self.membus.cpu_side_ports 105 | 106 | # Create the CPUs for our system. 107 | self.createCPU(cpu_type, num_cpus) 108 | 109 | # HiFive platform 110 | # This is based on a HiFive RISCV board and has 111 | # only a limited number of devices so far i.e. 112 | # PLIC, CLINT, UART, VirtIOMMIO 113 | self.platform = HiFive() 114 | 115 | # create and intialize devices currently supported for RISCV 116 | self.initDevices(self.membus, disk) 117 | 118 | # Create the cache heirarchy for the system. 119 | self.createCacheHierarchy() 120 | 121 | # Create the memory controller 122 | self.createMemoryControllerDDR3() 123 | 124 | self.setupInterrupts() 125 | 126 | # using RiscvLinux as the base full system workload 127 | self.workload = RiscvLinux() 128 | 129 | # this is user passed berkeley boot loader binary 130 | # currently the Linux kernel payload is compiled into this 131 | # as well 132 | self.workload.object_file = sbi 133 | 134 | # Generate DTB (from configs/example/riscv/fs_linux.py) 135 | generateDtb(self) 136 | self.workload.dtb_filename = path.join(m5.options.outdir, 'device.dtb') 137 | # Default DTB address if bbl is bulit with --with-dts option 138 | self.workload.dtb_addr = 0x87e00000 139 | 140 | # Linux boot command flags 141 | kernel_cmd = [ 142 | "console=ttyS0", 143 | "root=/dev/vda", 144 | "ro", 145 | "cma=512M@0-4G" 146 | ] 147 | self.workload.command_line = " ".join(kernel_cmd) 148 | 149 | def createCPU(self, cpu_type, num_cpus): 150 | # the default cpu will be atomic cpu 151 | if cpu_type == "atomic": 152 | self.cpu = [AtomicSimpleCPU(cpu_id = i) 153 | for i in range(num_cpus)] 154 | self.mem_mode = 'atomic' 155 | 156 | for cpu in self.cpu: 157 | cpu.createThreads() 158 | 159 | elif cpu_type == "timing": 160 | self.cpu = [TimingSimpleCPU(cpu_id = i) 161 | for i in range(num_cpus)] 162 | self.mem_mode = 'timing' 163 | for cpu in self.cpu: 164 | cpu.createThreads() 165 | 166 | elif cpu_type == "minor": 167 | self.cpu = [MinorCPU(cpu_id = i) 168 | for i in range(num_cpus)] 169 | self.mem_mode = 'timing' 170 | for cpu in self.cpu: 171 | cpu.createThreads() 172 | 173 | elif cpu_type == "o3": 174 | self.cpu = [DerivO3CPU(cpu_id = i) 175 | for i in range(num_cpus)] 176 | self.mem_mode = 'timing' 177 | for cpu in self.cpu: 178 | cpu.createThreads() 179 | else: 180 | m5.fatal("No CPU type {}".format(cpu_type)) 181 | 182 | def switchCpus(self, old, new): 183 | assert(new[0].switchedOut()) 184 | m5.switchCpus(self, list(zip(old, new))) 185 | 186 | def createCacheHierarchy(self): 187 | class L1Cache(Cache): 188 | """Large L1 cache""" 189 | 190 | assoc = 8 191 | size = '512kB' 192 | tag_latency = 1 193 | data_latency = 1 194 | response_latency = 1 195 | mshrs = 16 196 | tgts_per_mshr = 20 197 | writeback_clean = True 198 | 199 | def __init__(self): 200 | super(L1Cache, self).__init__() 201 | 202 | class L2Cache(Cache): 203 | """Large L2 cache""" 204 | 205 | assoc = 32 206 | size = '16MB' 207 | tag_latency = 1 208 | data_latency = 3 209 | response_latency = 3 210 | mshrs = 16 211 | tgts_per_mshr = 20 212 | writeback_clean = True 213 | 214 | def __init__(self): 215 | super(L2Cache, self).__init__() 216 | 217 | for cpu in self.cpu: 218 | # Create a very simple cache hierarchy 219 | 220 | # Create an L1 instruction, data and mmu cache 221 | cpu.icache = L1Cache() 222 | cpu.dcache = L1Cache() 223 | cpu.mmucache = L1Cache() 224 | cpu.l2cache = L2Cache() 225 | 226 | # A cross bar for l2 cache 227 | cpu.l2bus = L2XBar() 228 | 229 | # Connecting icache and dcache to memory bus and cpu 230 | cpu.icache.cpu_side = cpu.icache_port 231 | cpu.dcache.cpu_side = cpu.dcache_port 232 | cpu.icache.mem_side = cpu.l2bus.cpu_side_ports 233 | cpu.dcache.mem_side = cpu.l2bus.cpu_side_ports 234 | cpu.l2cache.cpu_side = cpu.l2bus.mem_side_ports 235 | cpu.l2cache.mem_side = self.membus.cpu_side_ports 236 | 237 | # Need a new crossbar for mmucache 238 | 239 | cpu.mmucache.mmubus = L2XBar() 240 | 241 | cpu.mmucache.cpu_side = cpu.mmucache.mmubus.mem_side_ports 242 | cpu.mmucache.mem_side = self.membus.cpu_side_ports 243 | 244 | # Connect the itb and dtb to mmucache 245 | cpu.mmu.connectWalkerPorts( 246 | cpu.mmucache.mmubus.cpu_side_ports, cpu.mmucache.mmubus.cpu_side_ports) 247 | 248 | # setting the dtb size to a very large value 249 | cpu.mmu.dtb.size = 2048 250 | 251 | def setupInterrupts(self): 252 | for cpu in self.cpu: 253 | # create the interrupt controller CPU and connect to the membus 254 | cpu.createInterruptController() 255 | 256 | def createMemoryControllerDDR3(self): 257 | self.mem_cntrls = [ 258 | MemCtrl(dram = DDR3_1600_8x8(range = self.mem_ranges[0]), 259 | port = self.membus.mem_side_ports) 260 | ] 261 | 262 | def initDevices(self, membus, disk): 263 | 264 | self.iobus = IOXBar() 265 | #self.intrctrl = IntrControl() 266 | 267 | # Set the frequency of RTC (real time clock) used by 268 | # CLINT (core level interrupt controller). 269 | # This frequency is 1MHz in SiFive's U54MC. 270 | # Setting it to 100MHz for faster simulation (from riscv/fs_linux.py) 271 | self.platform.rtc = RiscvRTC(frequency=Frequency("100MHz")) 272 | 273 | # RTC sends the clock signal to CLINT via an interrupt pin. 274 | self.platform.clint.int_pin = self.platform.rtc.int_pin 275 | 276 | # VirtIOMMIO 277 | image = CowDiskImage(child=RawDiskImage(read_only=True), read_only=False) 278 | image.child.image_file = disk 279 | # using reserved memory space 280 | self.platform.disk = MmioVirtIO( 281 | vio=VirtIOBlock(image=image), 282 | interrupt_id=0x8, 283 | pio_size = 4096, 284 | pio_addr=0x10008000 285 | ) 286 | 287 | # From riscv/fs_linux.py 288 | uncacheable_range = [ 289 | *self.platform._on_chip_ranges(), 290 | *self.platform._off_chip_ranges() 291 | ] 292 | # PMA (physical memory attribute) checker is a hardware structure 293 | # that ensures that physical addresses follow the memory permissions 294 | 295 | # PMA checker can be defined at system-level (system.pma_checker) 296 | # or MMU-level (system.cpu[0].mmu.pma_checker). It will be resolved 297 | # by RiscvTLB's Parent.any proxy 298 | 299 | for cpu in self.cpu: 300 | cpu.mmu.pma_checker = PMAChecker(uncacheable=uncacheable_range) 301 | 302 | self.bridge = Bridge(delay='50ns') 303 | self.bridge.mem_side_port = self.iobus.cpu_side_ports 304 | self.bridge.cpu_side_port = self.membus.mem_side_ports 305 | self.bridge.ranges = self.platform._off_chip_ranges() 306 | 307 | # Connecting on chip and off chip IO to the mem 308 | # and IO bus 309 | self.platform.attachOnChipIO(self.membus) 310 | self.platform.attachOffChipIO(self.iobus) 311 | 312 | # Attach the PLIC (platform level interrupt controller) 313 | # to the platform. This initializes the PLIC with 314 | # interrupt sources coming from off chip devices 315 | self.platform.attachPlic() -------------------------------------------------------------------------------- /configs-keystone-fu540/system/system.py: -------------------------------------------------------------------------------- 1 | #Copyright (c) 2021 The Regents of the University of California. 2 | #All Rights Reserved 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are 6 | # met: redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer; 8 | # redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution; 11 | # neither the name of the copyright holders nor the names of its 12 | # contributors may be used to endorse or promote products derived from 13 | # this software without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | # 27 | 28 | import m5 29 | from m5.objects import * 30 | from m5.util import convert 31 | from os import path 32 | 33 | ''' 34 | This class creates a bare bones RISCV full system. 35 | 36 | The targeted system is based on SiFive FU540-C000. 37 | Reference: 38 | [1] https://sifive.cdn.prismic.io/sifive/b5e7a29c- 39 | d3c2-44ea-85fb-acc1df282e21_FU540-C000-v1p3.pdf 40 | ''' 41 | 42 | # Dtb generation code from configs/example/riscv/fs_linux.py 43 | def generateMemNode(state, mem_range): 44 | node = FdtNode("memory@%x" % int(mem_range.start)) 45 | node.append(FdtPropertyStrings("device_type", ["memory"])) 46 | node.append(FdtPropertyWords("reg", 47 | state.addrCells(mem_range.start) + 48 | state.sizeCells(mem_range.size()) )) 49 | return node 50 | 51 | def generateDtb(system): 52 | """ 53 | Autogenerate DTB. Arguments are the folder where the DTB 54 | will be stored, and the name of the DTB file. 55 | """ 56 | state = FdtState(addr_cells=2, size_cells=2, cpu_cells=1) 57 | root = FdtNode('/') 58 | root.append(state.addrCellsProperty()) 59 | root.append(state.sizeCellsProperty()) 60 | root.appendCompatible(["riscv-virtio"]) 61 | 62 | for mem_range in system.mem_ranges: 63 | root.append(generateMemNode(state, mem_range)) 64 | 65 | sections = [*system.cpu, system.platform] 66 | 67 | for section in sections: 68 | for node in section.generateDeviceTree(state): 69 | if node.get_name() == root.get_name(): 70 | root.merge(node) 71 | else: 72 | root.append(node) 73 | 74 | fdt = Fdt() 75 | fdt.add_rootnode(root) 76 | fdt.writeDtsFile(path.join(m5.options.outdir, 'device.dts')) 77 | fdt.writeDtbFile(path.join(m5.options.outdir, 'device.dtb')) 78 | 79 | class RiscvSystem(System): 80 | 81 | def __init__(self, sbi, disk, cpu_type, num_cpus): 82 | super(RiscvSystem, self).__init__() 83 | 84 | # Set up the clock domain and the voltage domain 85 | self.clk_domain = SrcClockDomain() 86 | self.clk_domain.clock = '3GHz' 87 | self.clk_domain.voltage_domain = VoltageDomain() 88 | self.cpu_clk_domain = SrcClockDomain() 89 | self.cpu_clk_domain.voltage_domain = VoltageDomain() 90 | self.cpu_clk_domain.clock = '3GHz' 91 | 92 | # DDR memory range starts from base address 0x80000000 93 | # based on [1] 94 | self.mem_ranges = [AddrRange(start=0x80000000, size='1024MB')] 95 | 96 | # Create the main memory bus 97 | # This connects to main memory 98 | self.membus = SystemXBar(width = 64) # 64-byte width 99 | 100 | self.membus.badaddr_responder = BadAddr() 101 | self.membus.default = Self.badaddr_responder.pio 102 | 103 | # Set up the system port for functional access from the simulator 104 | self.system_port = self.membus.cpu_side_ports 105 | 106 | # Create the CPUs for our system. 107 | self.createCPU(cpu_type, num_cpus) 108 | 109 | # HiFive platform 110 | # This is based on a HiFive RISCV board and has 111 | # only a limited number of devices so far i.e. 112 | # PLIC, CLINT, UART, VirtIOMMIO 113 | self.platform = HiFive() 114 | 115 | # create and intialize devices currently supported for RISCV 116 | self.initDevices(self.membus, disk) 117 | 118 | # Create the cache heirarchy for the system. 119 | self.createCacheHierarchy() 120 | 121 | # Create the memory controller 122 | self.createMemoryControllerDDR3() 123 | 124 | self.setupInterrupts() 125 | 126 | # using RiscvLinux as the base full system workload 127 | self.workload = RiscvLinux() 128 | 129 | # this is user passed berkeley boot loader binary 130 | # currently the Linux kernel payload is compiled into this 131 | # as well 132 | self.workload.object_file = sbi 133 | 134 | # Generate DTB (from configs/example/riscv/fs_linux.py) 135 | generateDtb(self) 136 | self.workload.dtb_filename = path.join(m5.options.outdir, 'device.dtb') 137 | # Default DTB address if bbl is bulit with --with-dts option 138 | self.workload.dtb_addr = 0x87e00000 139 | 140 | # Linux boot command flags 141 | kernel_cmd = [ 142 | "console=ttyS0", 143 | "root=/dev/vda", 144 | "ro", 145 | "cma=512M@0-4G" 146 | ] 147 | self.workload.command_line = " ".join(kernel_cmd) 148 | 149 | def createCPU(self, cpu_type, num_cpus): 150 | # the default cpu will be atomic cpu 151 | if cpu_type == "atomic": 152 | self.cpu = [AtomicSimpleCPU(cpu_id = i) 153 | for i in range(num_cpus)] 154 | self.mem_mode = 'atomic' 155 | 156 | for cpu in self.cpu: 157 | cpu.createThreads() 158 | 159 | elif cpu_type == "timing": 160 | self.cpu = [TimingSimpleCPU(cpu_id = i) 161 | for i in range(num_cpus)] 162 | self.mem_mode = 'timing' 163 | for cpu in self.cpu: 164 | cpu.createThreads() 165 | 166 | elif cpu_type == "minor": 167 | self.cpu = [MinorCPU(cpu_id = i) 168 | for i in range(num_cpus)] 169 | self.mem_mode = 'timing' 170 | for cpu in self.cpu: 171 | cpu.createThreads() 172 | 173 | elif cpu_type == "o3": 174 | self.cpu = [DerivO3CPU(cpu_id = i) 175 | for i in range(num_cpus)] 176 | self.mem_mode = 'timing' 177 | for cpu in self.cpu: 178 | cpu.createThreads() 179 | else: 180 | m5.fatal("No CPU type {}".format(cpu_type)) 181 | 182 | def switchCpus(self, old, new): 183 | assert(new[0].switchedOut()) 184 | m5.switchCpus(self, list(zip(old, new))) 185 | 186 | def createCacheHierarchy(self): 187 | class L1Cache(Cache): 188 | """L1 cache with specs as in FU540""" 189 | 190 | assoc = 8 191 | size = '32kB' 192 | tag_latency = 1 193 | data_latency = 1 194 | response_latency = 1 195 | mshrs = 16 196 | tgts_per_mshr = 20 197 | writeback_clean = True 198 | 199 | def __init__(self): 200 | super(L1Cache, self).__init__() 201 | 202 | class L2Cache(Cache): 203 | """L2 cache with specs as in FU540""" 204 | 205 | assoc = 16 206 | size = '2MB' 207 | tag_latency = 2 208 | data_latency = 6 209 | response_latency = 6 210 | mshrs = 16 211 | tgts_per_mshr = 20 212 | writeback_clean = True 213 | 214 | def __init__(self): 215 | super(L2Cache, self).__init__() 216 | 217 | for cpu in self.cpu: 218 | # Create a very simple cache hierarchy 219 | 220 | # Create an L1 instruction, data and mmu cache 221 | cpu.icache = L1Cache() 222 | cpu.dcache = L1Cache() 223 | cpu.mmucache = L1Cache() 224 | cpu.l2cache = L2Cache() 225 | 226 | # A cross bar for l2 cache 227 | cpu.l2bus = L2XBar() 228 | 229 | # Connecting icache and dcache to memory bus and cpu 230 | cpu.icache.cpu_side = cpu.icache_port 231 | cpu.dcache.cpu_side = cpu.dcache_port 232 | cpu.icache.mem_side = cpu.l2bus.cpu_side_ports 233 | cpu.dcache.mem_side = cpu.l2bus.cpu_side_ports 234 | cpu.l2cache.cpu_side = cpu.l2bus.mem_side_ports 235 | cpu.l2cache.mem_side = self.membus.cpu_side_ports 236 | 237 | # Need a new crossbar for mmucache 238 | 239 | cpu.mmucache.mmubus = L2XBar() 240 | 241 | cpu.mmucache.cpu_side = cpu.mmucache.mmubus.mem_side_ports 242 | cpu.mmucache.mem_side = self.membus.cpu_side_ports 243 | 244 | # Connect the itb and dtb to mmucache 245 | cpu.mmu.connectWalkerPorts( 246 | cpu.mmucache.mmubus.cpu_side_ports, cpu.mmucache.mmubus.cpu_side_ports) 247 | 248 | # fu540 has l1 tlb size 32 and l2 tlb 128 249 | # approximating this with dtb size of 128 250 | cpu.mmu.dtb.size = 128 251 | 252 | def setupInterrupts(self): 253 | for cpu in self.cpu: 254 | # create the interrupt controller CPU and connect to the membus 255 | cpu.createInterruptController() 256 | 257 | def createMemoryControllerDDR3(self): 258 | self.mem_cntrls = [ 259 | MemCtrl(dram = DDR3_1600_8x8(range = self.mem_ranges[0]), 260 | port = self.membus.mem_side_ports) 261 | ] 262 | 263 | def initDevices(self, membus, disk): 264 | 265 | self.iobus = IOXBar() 266 | #self.intrctrl = IntrControl() 267 | 268 | # Set the frequency of RTC (real time clock) used by 269 | # CLINT (core level interrupt controller). 270 | # This frequency is 1MHz in SiFive's U54MC. 271 | # Setting it to 100MHz for faster simulation (from riscv/fs_linux.py) 272 | self.platform.rtc = RiscvRTC(frequency=Frequency("100MHz")) 273 | 274 | # RTC sends the clock signal to CLINT via an interrupt pin. 275 | self.platform.clint.int_pin = self.platform.rtc.int_pin 276 | 277 | # VirtIOMMIO 278 | image = CowDiskImage(child=RawDiskImage(read_only=True), read_only=False) 279 | image.child.image_file = disk 280 | # using reserved memory space 281 | self.platform.disk = MmioVirtIO( 282 | vio=VirtIOBlock(image=image), 283 | interrupt_id=0x8, 284 | pio_size = 4096, 285 | pio_addr=0x10008000 286 | ) 287 | 288 | # From riscv/fs_linux.py 289 | uncacheable_range = [ 290 | *self.platform._on_chip_ranges(), 291 | *self.platform._off_chip_ranges() 292 | ] 293 | # PMA (physical memory attribute) checker is a hardware structure 294 | # that ensures that physical addresses follow the memory permissions 295 | 296 | # PMA checker can be defined at system-level (system.pma_checker) 297 | # or MMU-level (system.cpu[0].mmu.pma_checker). It will be resolved 298 | # by RiscvTLB's Parent.any proxy 299 | 300 | for cpu in self.cpu: 301 | cpu.mmu.pma_checker = PMAChecker(uncacheable=uncacheable_range) 302 | 303 | self.bridge = Bridge(delay='50ns') 304 | self.bridge.mem_side_port = self.iobus.cpu_side_ports 305 | self.bridge.cpu_side_port = self.membus.mem_side_ports 306 | self.bridge.ranges = self.platform._off_chip_ranges() 307 | 308 | # Connecting on chip and off chip IO to the mem 309 | # and IO bus 310 | self.platform.attachOnChipIO(self.membus) 311 | self.platform.attachOffChipIO(self.iobus) 312 | 313 | # Attach the PLIC (platform level interrupt controller) 314 | # to the platform. This initializes the PLIC with 315 | # interrupt sources coming from off chip devices 316 | self.platform.attachPlic() -------------------------------------------------------------------------------- /bootstrap_musl_riscv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # ## musl-riscv-toolchain 4 | # 5 | # musl libc GCC cross compiler toolchain bootstrap script 6 | # 7 | # usage: ./bootstrap.sh [native-cross] 8 | # 9 | # This script by default builds cross compilers for the supported 10 | # target architectures. If the optional "native-cross" option is 11 | # given, then in addition to building a cross compiler for the 12 | # target, the script will use the target cross compiler to build 13 | # a native compiler for the target architecture linked with the 14 | # target architecture's musl C library. The native compiler is 15 | # installed into ${SYSROOT}/usr/bin 16 | # 17 | # ## Supported architectures: 18 | # 19 | # - riscv32 20 | # - riscv64 21 | # - i386 22 | # - x86_64 23 | # - arm 24 | # - aarch64 25 | # 26 | # ## Directory layout 27 | # 28 | # - ${bootstrap_prefix}-${gcc_version}-${bootstrap_version} 29 | # - bin/ 30 | # - {$triple}-{as,ld,gcc,g++,strip,objdump} # host binaries 31 | # - ${triple} # sysroot 32 | # - include # target headers 33 | # - lib # target libraries 34 | # - usr 35 | # - lib -> ../lib 36 | # - bin 37 | # - {as,ld,gcc,g++,strip,objdump} # target binaries 38 | # 39 | 40 | case "$1" in 41 | riscv32) 42 | ARCH=riscv32 43 | LINUX_ARCH=riscv 44 | WITHARCH=--with-arch=rv32imafdc 45 | ;; 46 | riscv64) 47 | ARCH=riscv64 48 | LINUX_ARCH=riscv 49 | WITHARCH=--with-arch=rv64imafdc 50 | ;; 51 | i386) 52 | ARCH=i386 53 | LINUX_ARCH=x86 54 | WITHARCH=--with-arch-32=core2 55 | ;; 56 | x86_64) 57 | ARCH=x86_64 58 | LINUX_ARCH=x86 59 | WITHARCH=--with-arch-64=core2 60 | ;; 61 | arm) 62 | ARCH=arm 63 | LINUX_ARCH=arm 64 | WITHARCH=--with-arch=armv7-a 65 | SUFFIX=eabihf 66 | ;; 67 | aarch64) 68 | ARCH=aarch64 69 | LINUX_ARCH=arm64 70 | WITHARCH=--with-arch=armv8-a 71 | ;; 72 | *) 73 | echo "Usage: $0 {riscv32|riscv64|i386|x86_64|arm|aarch64}" 74 | exit 1 75 | esac 76 | 77 | set -e 78 | 79 | # build dependency versions 80 | gmp_version=6.1.2 81 | mpfr_version=3.1.4 82 | mpc_version=1.0.3 83 | isl_version=0.16.1 84 | cloog_version=0.18.4 85 | binutils_version=2.31.1 86 | gcc_version=8.2.0 87 | musl_version=1.1.18-riscv-a6 88 | linux_version=4.18 89 | 90 | # bootstrap install prefix and version 91 | bootstrap_prefix=/opt/riscv/musl-riscv-toolchain 92 | bootstrap_version=1 93 | 94 | # derived variables 95 | PREFIX=${bootstrap_prefix}-${gcc_version}-${bootstrap_version} 96 | TRIPLE=${ARCH}-linux-musl${SUFFIX} 97 | SYSROOT=${PREFIX}/${TARGET:=$TRIPLE} 98 | TOPDIR=$(pwd) 99 | 100 | make_directories() 101 | { 102 | test -d src || mkdir src 103 | test -d build || mkdir build 104 | test -d stamps || mkdir stamps 105 | test -d archives || mkdir archives 106 | test -d ${PREFIX} || mkdir -p ${PREFIX} 107 | } 108 | 109 | download_prerequisites() 110 | { 111 | test -f archives/gmp-${gmp_version}.tar.bz2 || \ 112 | curl -o archives/gmp-${gmp_version}.tar.bz2 \ 113 | https://gmplib.org/download/gmp-${gmp_version}/gmp-${gmp_version}.tar.bz2 114 | test -f archives/mpfr-${mpfr_version}.tar.bz2 || \ 115 | curl -o archives/mpfr-${mpfr_version}.tar.bz2 \ 116 | https://gcc.gnu.org/pub/gcc/infrastructure/mpfr-${mpfr_version}.tar.bz2 117 | test -f archives/mpc-${mpc_version}.tar.gz || \ 118 | curl -o archives/mpc-${mpc_version}.tar.gz \ 119 | https://gcc.gnu.org/pub/gcc/infrastructure/mpc-${mpc_version}.tar.gz 120 | test -f archives/isl-${isl_version}.tar.bz2 || \ 121 | curl -o archives/isl-${isl_version}.tar.bz2 \ 122 | ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-${isl_version}.tar.bz2 123 | test -f archives/cloog-${cloog_version}.tar.gz || \ 124 | curl -o archives/cloog-${cloog_version}.tar.gz \ 125 | http://www.bastoul.net/cloog/pages/download/cloog-${cloog_version}.tar.gz 126 | test -f archives/binutils-${binutils_version}.tar.bz2 || \ 127 | curl -o archives/binutils-${binutils_version}.tar.bz2 \ 128 | http://ftp.gnu.org/gnu/binutils/binutils-${binutils_version}.tar.bz2 129 | test -f archives/musl-riscv-${musl_version}.tar.gz || \ 130 | curl -o archives/musl-riscv-${musl_version}.tar.gz \ 131 | https://codeload.github.com/rv8-io/musl-riscv/tar.gz/${musl_version} 132 | test -f archives/linux-${linux_version}.tar.xz || \ 133 | curl -L -o archives/linux-${linux_version}.tar.xz \ 134 | https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-${linux_version}.tar.xz 135 | test -f archives/gcc-${gcc_version}.tar.xz || \ 136 | curl -o archives/gcc-${gcc_version}.tar.xz \ 137 | http://ftp.gnu.org/gnu/gcc/gcc-${gcc_version}/gcc-${gcc_version}.tar.xz 138 | } 139 | 140 | extract_archives() 141 | { 142 | test -d src/gmp-${gmp_version} || \ 143 | tar -C src -xjf archives/gmp-${gmp_version}.tar.bz2 144 | test -d src/mpfr-${mpfr_version} || \ 145 | tar -C src -xjf archives/mpfr-${mpfr_version}.tar.bz2 146 | test -d src/mpc-${mpc_version} || \ 147 | tar -C src -xzf archives/mpc-${mpc_version}.tar.gz 148 | test -d src/isl-${isl_version} || \ 149 | tar -C src -xjf archives/isl-${isl_version}.tar.bz2 150 | test -d src/cloog-${cloog_version} || \ 151 | tar -C src -xzf archives/cloog-${cloog_version}.tar.gz 152 | test -d src/binutils-${binutils_version} || \ 153 | tar -C src -xjf archives/binutils-${binutils_version}.tar.bz2 154 | test -d src/musl-riscv-${musl_version} || \ 155 | tar -C src -xzf archives/musl-riscv-${musl_version}.tar.gz 156 | test -d src/linux-${linux_version} || \ 157 | tar -C src -xJf archives/linux-${linux_version}.tar.xz 158 | test -d src/gcc-${gcc_version} || \ 159 | tar -C src -xJf archives/gcc-${gcc_version}.tar.xz 160 | } 161 | 162 | patch_musl() 163 | { 164 | test -f src/musl-riscv-${musl_version}/.patched || ( 165 | set -e 166 | cd src/musl-riscv-${musl_version} 167 | patch -p0 < ../../patches/musl-stdbool-cpluscplus.patch 168 | touch .patched 169 | ) 170 | test "$?" -eq "0" || exit 1 171 | } 172 | 173 | patch_gcc() 174 | { 175 | test -f src/gcc-${gcc_version}/.patched || ( 176 | set -e 177 | cd src/gcc-${gcc_version} 178 | #patch -p0 < ../../patches/gcc-7.1-strict-operands.patch 179 | touch .patched 180 | ) 181 | test "$?" -eq "0" || exit 1 182 | } 183 | 184 | build_gmp() 185 | { 186 | host=$1; shift 187 | test -f stamps/lib-gmp-${host} || ( 188 | set -e 189 | test -d build/gmp-${host} || mkdir build/gmp-${host} 190 | cd build/gmp-${host} 191 | CFLAGS=-fPIE ../../src/gmp-${gmp_version}/configure \ 192 | --disable-shared \ 193 | --prefix=${TOPDIR}/build/install-${host} \ 194 | $* 195 | make -j$(nproc) && make install 196 | ) && touch stamps/lib-gmp-${host} 197 | test "$?" -eq "0" || exit 1 198 | } 199 | 200 | build_mpfr() 201 | { 202 | host=$1; shift 203 | test -f stamps/lib-mpfr-${host} || ( 204 | set -e 205 | test -d build/mpfr-${host} || mkdir build/mpfr-${host} 206 | cd build/mpfr-${host} 207 | CFLAGS=-fPIE ../../src/mpfr-${mpfr_version}/configure \ 208 | --disable-shared \ 209 | --prefix=${TOPDIR}/build/install-${host} \ 210 | --with-gmp=${TOPDIR}/build/install-${host} \ 211 | $* 212 | make -j$(nproc) && make install 213 | ) && touch stamps/lib-mpfr-${host} 214 | test "$?" -eq "0" || exit 1 215 | } 216 | 217 | build_mpc() 218 | { 219 | host=$1; shift 220 | test -f stamps/lib-mpc-${host} || ( 221 | set -e 222 | test -d build/mpc-${host} || mkdir build/mpc-${host} 223 | cd build/mpc-${host} 224 | CFLAGS=-fPIE ../../src/mpc-${mpc_version}/configure \ 225 | --disable-shared \ 226 | --prefix=${TOPDIR}/build/install-${host} \ 227 | --with-gmp=${TOPDIR}/build/install-${host} \ 228 | --with-mpfr=${TOPDIR}/build/install-${host} \ 229 | $* 230 | make -j$(nproc) && make install 231 | ) && touch stamps/lib-mpc-${host} 232 | test "$?" -eq "0" || exit 1 233 | } 234 | 235 | build_isl() 236 | { 237 | host=$1; shift 238 | if [ "${build_graphite}" = "yes" ]; then 239 | test -f stamps/lib-isl-${host} || ( 240 | set -e 241 | test -d build/isl-${host} || mkdir build/isl-${host} 242 | cd build/isl-${host} 243 | CFLAGS=-fPIE ../../src/isl-${isl_version}/configure \ 244 | --disable-shared \ 245 | --prefix=${TOPDIR}/build/install-${host} \ 246 | --with-gmp-prefix=${TOPDIR}/build/install-${host} \ 247 | $* 248 | make -j$(nproc) && make install 249 | ) && touch stamps/lib-isl-${host} 250 | test "$?" -eq "0" || exit 1 251 | fi 252 | } 253 | 254 | build_cloog() 255 | { 256 | host=$1; shift 257 | if [ "${build_graphite}" = "yes" ]; then 258 | test -f stamps/lib-cloog-${host} || ( 259 | set -e 260 | test -d build/cloog-${host} || mkdir build/cloog-${host} 261 | cd build/cloog-${host} 262 | CFLAGS=-fPIE ../../src/cloog-${cloog_version}/configure \ 263 | --disable-shared \ 264 | --prefix=${TOPDIR}/build/install-${host} \ 265 | --with-isl-prefix=${TOPDIR}/build/install-${host} \ 266 | --with-gmp-prefix=${TOPDIR}/build/install-${host} \ 267 | $* 268 | make -j$(nproc) && make install 269 | ) && touch stamps/lib-cloog-${host} 270 | test "$?" -eq "0" || exit 1 271 | fi 272 | } 273 | 274 | build_binutils() 275 | { 276 | host=$1; shift 277 | prefix=$1; shift 278 | destdir=$1; shift 279 | transform=$1; shift 280 | test -f stamps/binutils-${host}-${ARCH} || ( 281 | set -e 282 | test -d build/binutils-${host}-${ARCH} || mkdir build/binutils-${host}-${ARCH} 283 | cd build/binutils-${host}-${ARCH} 284 | CFLAGS=-fPIE ../../src/binutils-${binutils_version}/configure \ 285 | --prefix=${prefix} \ 286 | --target=${TARGET:=$TRIPLE} ${WITHARCH} \ 287 | ${transform:+--program-transform-name='s&^&'${TRIPLE}'-&'} \ 288 | --with-sysroot=${SYSROOT} \ 289 | --disable-nls \ 290 | --disable-libssp \ 291 | --disable-shared \ 292 | --disable-werror \ 293 | --disable-multilib \ 294 | --with-gmp=${TOPDIR}/build/install-${host} \ 295 | --with-mpfr=${TOPDIR}/build/install-${host} \ 296 | --with-mpc=${TOPDIR}/build/install-${host} \ 297 | ${build_graphite:+--disable-isl-version-check} \ 298 | ${build_graphite:+--with-isl=${TOPDIR}/build/install-${host}} \ 299 | ${build_graphite:+--with-cloog=${TOPDIR}/build/install-${host}} \ 300 | $* 301 | make -j$(nproc) && make DESTDIR=${destdir} install 302 | ) && touch stamps/binutils-${host}-${ARCH} 303 | test "$?" -eq "0" || exit 1 304 | } 305 | 306 | configure_musl() 307 | { 308 | test -f stamps/musl-config-${ARCH} || ( 309 | set -e 310 | rsync -a src/musl-riscv-${musl_version}/ build/musl-${ARCH}/ 311 | cd build/musl-${ARCH} 312 | echo prefix= > config.mak 313 | echo exec_prefix= >> config.mak 314 | echo ARCH=${ARCH} >> config.mak 315 | echo CC=${PREFIX}/bin/${TRIPLE}-gcc >> config.mak 316 | echo AS=${PREFIX}/bin/${TRIPLE}-as >> config.mak 317 | echo LD=${PREFIX}/bin/${TRIPLE}-ld >> config.mak 318 | echo AR=${PREFIX}/bin/${TRIPLE}-ar >> config.mak 319 | echo RANLIB=${PREFIX}/bin/${TRIPLE}-ranlib >> config.mak 320 | ) && touch stamps/musl-config-${ARCH} 321 | test "$?" -eq "0" || exit 1 322 | } 323 | 324 | install_musl_headers() 325 | { 326 | test -f stamps/musl-headers-${ARCH} || ( 327 | set -e 328 | cd build/musl-${ARCH} 329 | make DESTDIR=${SYSROOT} install-headers 330 | mkdir -p ${SYSROOT}/usr 331 | test -L ${SYSROOT}/usr/lib || ln -s ../lib ${SYSROOT}/usr/lib 332 | test -L ${SYSROOT}/usr/include || ln -s ../include ${SYSROOT}/usr/include 333 | ) && touch stamps/musl-headers-${ARCH} 334 | test "$?" -eq "0" || exit 1 335 | } 336 | 337 | install_linux_headers() 338 | { 339 | test -f stamps/linux-headers-${ARCH} || ( 340 | set -e 341 | mkdir -p build/linux-headers-${ARCH}/staged 342 | ( cd src/linux-${linux_version} && \ 343 | make ARCH=${LINUX_ARCH} O=../../build/linux-headers-${ARCH} \ 344 | INSTALL_HDR_PATH=../../build/linux-headers-${ARCH}/staged headers_install ) 345 | find build/linux-headers-${ARCH}/staged/include '(' -name .install -o -name ..install.cmd ')' -exec rm {} + 346 | rsync -a build/linux-headers-${ARCH}/staged/include/ ${SYSROOT}/usr/include/ 347 | ) && touch stamps/linux-headers-${ARCH} 348 | test "$?" -eq "0" || exit 1 349 | } 350 | 351 | build_gcc_stage1() 352 | { 353 | # musl compiler 354 | host=$1; shift 355 | prefix=$1; shift 356 | destdir=$1; shift 357 | transform=$1; shift 358 | test -f stamps/gcc-stage1-${host}-${ARCH} || ( 359 | set -e 360 | test -d build/gcc-stage1-${host}-${ARCH} || mkdir build/gcc-stage1-${host}-${ARCH} 361 | cd build/gcc-stage1-${host}-${ARCH} 362 | CFLAGS=-fPIE ../../src/gcc-${gcc_version}/configure \ 363 | --prefix=${prefix} \ 364 | --target=${TARGET:=$TRIPLE} ${WITHARCH} \ 365 | ${transform:+--program-transform-name='s&^&'${TRIPLE}'-&'} \ 366 | --with-sysroot=${SYSROOT} \ 367 | --with-gnu-as \ 368 | --with-gnu-ld \ 369 | --enable-languages=c,c++ \ 370 | --enable-target-optspace \ 371 | --enable-initfini-array \ 372 | --enable-zlib \ 373 | --enable-libgcc \ 374 | --enable-tls \ 375 | --disable-shared \ 376 | --disable-threads \ 377 | --disable-libatomic \ 378 | --disable-libstdc__-v3 \ 379 | --disable-libquadmath \ 380 | --disable-libsanitizer \ 381 | --disable-libvtv \ 382 | --disable-libmpx \ 383 | --disable-multilib \ 384 | --disable-libssp \ 385 | --disable-libmudflap \ 386 | --disable-libgomp \ 387 | --disable-libitm \ 388 | --disable-nls \ 389 | --disable-plugins \ 390 | --disable-sjlj-exceptions \ 391 | --disable-bootstrap \ 392 | --with-gmp=${TOPDIR}/build/install-${host} \ 393 | --with-mpfr=${TOPDIR}/build/install-${host} \ 394 | --with-mpc=${TOPDIR}/build/install-${host} \ 395 | ${build_graphite:+--disable-isl-version-check} \ 396 | ${build_graphite:+--enable-cloog-backend=isl} \ 397 | ${build_graphite:+--with-isl=${TOPDIR}/build/install-${host}} \ 398 | ${build_graphite:+--with-cloog=${TOPDIR}/build/install-${host}} \ 399 | $* 400 | make -j$(nproc) inhibit-libc=true all-gcc all-target-libgcc 401 | make DESTDIR=${destdir} inhibit-libc=true install-gcc install-target-libgcc 402 | ) && touch stamps/gcc-stage1-${host}-${ARCH} 403 | test "$?" -eq "0" || exit 1 404 | } 405 | 406 | build_musl() 407 | { 408 | test -f stamps/musl-dynamic-${ARCH} || ( 409 | set -e 410 | cd build/musl-${ARCH} 411 | make -j$(nproc) 412 | make DESTDIR=${SYSROOT} install-libs 413 | ) && touch stamps/musl-dynamic-${ARCH} 414 | test "$?" -eq "0" || exit 1 415 | } 416 | 417 | build_gcc_stage2() 418 | { 419 | # final compiler 420 | host=$1; shift 421 | prefix=$1; shift 422 | destdir=$1; shift 423 | transform=$1; shift 424 | test -f stamps/gcc-stage2-${host}-${ARCH} || ( 425 | set -e 426 | test -d build/gcc-stage2-${host}-${ARCH} || mkdir build/gcc-stage2-${host}-${ARCH} 427 | cd build/gcc-stage2-${host}-${ARCH} 428 | CFLAGS=-fPIE ../../src/gcc-${gcc_version}/configure \ 429 | --prefix=${prefix} \ 430 | --target=${TARGET:=$TRIPLE} ${WITHARCH} \ 431 | ${transform:+--program-transform-name='s&^&'${TRIPLE}'-&'} \ 432 | --with-sysroot=${SYSROOT} \ 433 | --with-gnu-as \ 434 | --with-gnu-ld \ 435 | --enable-languages=c,c++ \ 436 | --enable-target-optspace \ 437 | --enable-initfini-array \ 438 | --enable-zlib \ 439 | --enable-libgcc \ 440 | --enable-tls \ 441 | --enable-shared \ 442 | --enable-threads \ 443 | --enable-libatomic \ 444 | --enable-libstdc__-v3 \ 445 | --disable-libquadmath \ 446 | --disable-libsanitizer \ 447 | --disable-libvtv \ 448 | --disable-libmpx \ 449 | --disable-multilib \ 450 | --disable-libssp \ 451 | --disable-libmudflap \ 452 | --disable-libgomp \ 453 | --disable-libitm \ 454 | --disable-nls \ 455 | --disable-plugins \ 456 | --disable-sjlj-exceptions \ 457 | --disable-bootstrap \ 458 | --with-gmp=${TOPDIR}/build/install-${host} \ 459 | --with-mpfr=${TOPDIR}/build/install-${host} \ 460 | --with-mpc=${TOPDIR}/build/install-${host} \ 461 | ${build_graphite:+--disable-isl-version-check} \ 462 | ${build_graphite:+--enable-cloog-backend=isl} \ 463 | ${build_graphite:+--with-isl=${TOPDIR}/build/install-${host}} \ 464 | ${build_graphite:+--with-cloog=${TOPDIR}/build/install-${host}} \ 465 | $* 466 | make -j$(nproc) all-gcc all-target-libgcc all-target-libstdc++-v3 467 | make DESTDIR=${destdir} install-gcc install-target-libgcc install-target-libstdc++-v3 468 | ) && touch stamps/gcc-stage2-${host}-${ARCH} 469 | test "$?" -eq "0" || exit 1 470 | } 471 | 472 | 473 | # 474 | # build musl libc toolchain for host 475 | # 476 | 477 | make_directories 478 | download_prerequisites 479 | extract_archives 480 | patch_musl 481 | patch_gcc 482 | 483 | build_gmp host 484 | build_mpfr host 485 | build_mpc host 486 | build_isl host 487 | build_cloog host 488 | build_binutils host ${PREFIX} / transform-name 489 | 490 | configure_musl 491 | install_musl_headers 492 | install_linux_headers 493 | 494 | build_gcc_stage1 host ${PREFIX} / transform-name 495 | build_musl 496 | build_gcc_stage2 host ${PREFIX} / transform-name 497 | 498 | 499 | # 500 | # build musl libc toolchain for target 501 | # 502 | 503 | if [ "$2" = "native-cross" ]; then 504 | 505 | export PATH=${PREFIX}/bin:${PATH} 506 | 507 | build_gmp ${ARCH} --host=${TRIPLE} 508 | build_mpfr ${ARCH} --host=${TRIPLE} 509 | build_mpc ${ARCH} --host=${TRIPLE} 510 | build_isl ${ARCH} --host=${TRIPLE} 511 | build_cloog ${ARCH} --host=${TRIPLE} 512 | build_binutils ${ARCH} /usr ${SYSROOT} '' --host=${TRIPLE} 513 | build_gcc_stage2 ${ARCH} /usr ${SYSROOT} '' --host=${TRIPLE} 514 | 515 | fi 516 | --------------------------------------------------------------------------------