diff --git a/configs/example/gem5_library/arm-ubuntu-run-with-kvm.py b/configs/example/gem5_library/arm-ubuntu-run-with-kvm.py new file mode 100644 index 0000000000..f6c9164396 --- /dev/null +++ b/configs/example/gem5_library/arm-ubuntu-run-with-kvm.py @@ -0,0 +1,139 @@ +# Copyright (c) 2022-23 The Regents of the University of California +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" +This script further shows an example of booting an ARM based full system Ubuntu +disk image. This simulation boots the disk image using 2 TIMING CPU cores. The +simulation ends when the startup is completed successfully (i.e. when an +`m5_exit instruction is reached on successful boot). + +Usage +----- + +``` +scons build/ARM/gem5.opt -j +./build/ARM/gem5.opt configs/example/gem5_library/arm-ubuntu-run-with-kvm.py +``` + +""" + +from m5.objects import ( + ArmDefaultRelease, + VExpress_GEM5_V1, +) + +from gem5.coherence_protocol import CoherenceProtocol +from gem5.components.boards.arm_board import ArmBoard +from gem5.components.memory import DualChannelDDR4_2400 +from gem5.components.processors.cpu_types import CPUTypes +from gem5.components.processors.simple_switchable_processor import ( + SimpleSwitchableProcessor, +) +from gem5.isas import ISA +from gem5.resources.resource import obtain_resource +from gem5.simulate.exit_event import ExitEvent +from gem5.simulate.simulator import Simulator +from gem5.utils.requires import requires + +# This runs a check to ensure the gem5 binary is compiled for ARM. +requires(isa_required=ISA.ARM) + +from gem5.components.cachehierarchies.classic.private_l1_private_l2_cache_hierarchy import ( + PrivateL1PrivateL2CacheHierarchy, +) + +# Here we setup the parameters of the l1 and l2 caches. +cache_hierarchy = PrivateL1PrivateL2CacheHierarchy( + l1d_size="16kB", l1i_size="16kB", l2_size="256kB" +) + +# Memory: Dual Channel DDR4 2400 DRAM device. +memory = DualChannelDDR4_2400(size="2GB") + +# Here we setup the processor. This is a special switchable processor in which +# a starting core type and a switch core type must be specified. Once a +# configuration is instantiated a user may call `processor.switch()` to switch +# from the starting core types to the switch core types. In this simulation +# we start with KVM cores to simulate the OS boot, then switch to the Timing +# cores for the command we wish to run after boot. +processor = SimpleSwitchableProcessor( + starting_core_type=CPUTypes.KVM, + switch_core_type=CPUTypes.TIMING, + isa=ISA.ARM, + num_cores=2, +) + +# The ArmBoard requires a `release` to be specified. This adds all the +# extensions or features to the system. We are setting this to Armv8 +# (ArmDefaultRelease) in this example config script. +release = ArmDefaultRelease() + +# The platform sets up the memory ranges of all the on-chip and off-chip +# devices present on the ARM system. ARM KVM only works with VExpress_GEM5_V1 +# on the ArmBoard at the moment. +platform = VExpress_GEM5_V1() + +# Here we setup the board. The ArmBoard allows for Full-System ARM simulations. +board = ArmBoard( + clk_freq="3GHz", + processor=processor, + memory=memory, + cache_hierarchy=cache_hierarchy, + release=release, + platform=platform, +) +# This is the command to run after the system has booted. The first `m5 exit` +# will stop the simulation so we can switch the CPU cores from KVM to timing +# and continue the simulation to run the echo command, sleep for a second, +# then, again, call `m5 exit` to terminate the simulation. After simulation +# has ended you may inspect `m5out/system.pc.com_1.device` to see the echo +# output. +command = ( + "m5 --addr=0x10010000 exit;" + + "echo 'This is running on Timing CPU cores.';" + + "m5 exit;" +) + +# Here we set a full system workload. The "arm64-ubuntu-20.04-boot" boots +# Ubuntu 20.04. We use arm64-bootloader (boot.arm64) as the bootloader to use +# ARM KVM. +board.set_kernel_disk_workload( + kernel=obtain_resource("arm64-linux-kernel-5.4.49"), + disk_image=obtain_resource("arm64-ubuntu-20.04-img"), + bootloader=obtain_resource("arm64-bootloader"), + readfile_contents=command, +) +# We define the system with the aforementioned system defined. +simulator = Simulator( + board=board, + on_exit_event={ExitEvent.EXIT: (func() for func in [processor.switch])}, +) + +# Once the system successfully boots, it encounters an +# `m5_exit instruction encountered`. We stop the simulation then. When the +# simulation has ended you may inspect `m5out/board.terminal` to see +# the stdout. +simulator.run() diff --git a/src/python/gem5/components/boards/arm_board.py b/src/python/gem5/components/boards/arm_board.py index c60761c16d..d4028e4d71 100644 --- a/src/python/gem5/components/boards/arm_board.py +++ b/src/python/gem5/components/boards/arm_board.py @@ -42,6 +42,7 @@ from m5.objects import ( BadAddr, Bridge, CowDiskImage, + GenericTimer, IOXBar, PciVirtIO, Port, @@ -51,6 +52,7 @@ from m5.objects import ( Terminal, VExpress_GEM5_Base, VExpress_GEM5_Foundation, + VExpress_GEM5_V1, VirtIOBlock, VncServer, VoltageDomain, @@ -80,6 +82,7 @@ class ArmBoard(ArmSystem, AbstractBoard, KernelDiskWorkload): **Limitations** * stage2 walker ports are ignored. + * KVM cores only work with VExpress_GEM5_V1 """ __metaclass__ = ABCMeta @@ -110,8 +113,13 @@ class ArmBoard(ArmSystem, AbstractBoard, KernelDiskWorkload): requires(isa_required=ISA.ARM) # Setting up ARM release here. We use the ARM default release, which - # corresponds to an ARMv8 system. + # corresponds to an ARMv8 system. The default release is updated if + # the user is using any KVM cores. self.release = release + if any(core.is_kvm_core() for core in processor.get_cores()): + # KVM cores only work with VExpress_GEM5_V1() + if isinstance(platform, VExpress_GEM5_V1): + self.release = ArmDefaultRelease.for_kvm() # Setting multi_proc of ArmSystem by counting the number of processors. if processor.get_num_cores() == 1: @@ -211,6 +219,17 @@ class ArmBoard(ArmSystem, AbstractBoard, KernelDiskWorkload): if hasattr(self.realview.gic, "cpu_addr"): self.gic_cpu_addr = self.realview.gic.cpu_addr + # For KVM cpus, we need to simulate the GIC. + if any(core.is_kvm_core() for core in self.processor.get_cores()): + # The following is taken from + # `tests/fs/linux/arm/configs/arm_generic.py`: + # Arm KVM regressions will use a simulated GIC. This means that in + # order to work we need to remove the system interface of the + # generic timer from the DTB and we need to inform the MuxingKvmGic + # class to use the gem5 GIC instead of relying on the host one + GenericTimer.generateDeviceTree = SimObject.generateDeviceTree + self.realview.gic.simulate_gic = True + # IO devices has to setup before incorporating the caches in the case # of ruby caches. Otherwise the DMA controllers are incorrectly # created. The IO device has to be attached first. This is done in the