• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "host/libs/vm_manager/gem5_manager.h"
18 
19 #include <string.h>
20 #include <sys/socket.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <sys/un.h>
24 #include <sys/wait.h>
25 #include <unistd.h>
26 
27 #include <cstdlib>
28 #include <fstream>
29 #include <sstream>
30 #include <string>
31 #include <thread>
32 #include <vector>
33 
34 #include <android-base/strings.h>
35 #include <android-base/logging.h>
36 #include <vulkan/vulkan.h>
37 
38 #include "common/libs/fs/shared_select.h"
39 #include "common/libs/utils/files.h"
40 #include "common/libs/utils/subprocess.h"
41 #include "common/libs/utils/users.h"
42 #include "host/libs/config/cuttlefish_config.h"
43 #include "host/libs/config/known_paths.h"
44 
45 namespace cuttlefish {
46 namespace vm_manager {
47 namespace {
48 
LogAndSetEnv(const char * key,const std::string & value)49 void LogAndSetEnv(const char* key, const std::string& value) {
50   setenv(key, value.c_str(), 1);
51   LOG(INFO) << key << "=" << value;
52 }
53 
GenerateGem5File(const CuttlefishConfig & config)54 void GenerateGem5File(const CuttlefishConfig& config) {
55   // Gem5 specific config, currently users have to change these config locally (without throug launch_cvd input flag) to meet their design
56   // TODO: Add these config into launch_cvd input flag or parse from one json file
57   std::string cpu_class = "AtomicSimpleCPU";
58   std::string l1_icache_class = "None";
59   std::string l1_dcache_class = "None";
60   std::string walk_cache_class = "None";
61   std::string l2_Cache_class = "None";
62   std::string cpu_freq = "4GHz";
63   int num_cores = 1;
64   std::string mem_type = "DDR3_1600_8x8";
65   int mem_channels = 1;
66   std::string mem_ranks = "None";
67 
68   // start generating starter_fs.py
69   std::string fs_path = config.gem5_binary_dir() + "/configs/example/arm/starter_fs.py";
70   std::ofstream starter_fs_ofstream(fs_path.c_str());
71   starter_fs_ofstream << fs_header << "\n";
72 
73   // global vars in python
74   starter_fs_ofstream << "default_disk = 'linaro-minimal-aarch64.img'\n";
75 
76   // main function
77   starter_fs_ofstream << "def main():\n";
78 
79   // args
80   auto instance = config.ForDefaultInstance();
81   starter_fs_ofstream << "  parser = argparse.ArgumentParser(epilog=__doc__)\n";
82   starter_fs_ofstream << "  parser.add_argument(\"--disk-image\", action=\"append\", type=str, default=[])\n";
83   starter_fs_ofstream << "  parser.add_argument(\"--mem-type\", default=\"" << mem_type << "\", choices=ObjectList.mem_list.get_names())\n";
84   starter_fs_ofstream << "  parser.add_argument(\"--mem-channels\", type=int, default=" << mem_channels << ")\n";
85   starter_fs_ofstream << "  parser.add_argument(\"--mem-ranks\", type=int, default=" << mem_ranks << ")\n";
86   starter_fs_ofstream << "  parser.add_argument(\"--mem-size\", action=\"store\", type=str, default=\"" << config.memory_mb() << "MB\")\n";
87   starter_fs_ofstream << "  args = parser.parse_args()\n";
88 
89   // instantiate system
90   starter_fs_ofstream << "  root = Root(full_system=True)\n";
91   starter_fs_ofstream << "  mem_mode = " << cpu_class << ".memory_mode()\n";
92   starter_fs_ofstream << "  has_caches = True if mem_mode == \"timing\" else False\n";
93   starter_fs_ofstream << "  root.system = devices.SimpleSystem(has_caches, args.mem_size, mem_mode=mem_mode, workload=ArmFsLinux(object_file=SysPaths.binary(\"" << config.assembly_dir() << "/kernel\")))\n";
94 
95   // mem config and pci instantiate
96   starter_fs_ofstream << fs_mem_pci;
97 
98   // system settings
99   starter_fs_ofstream << "  root.system.cpu_cluster = [devices.CpuCluster(root.system, " << num_cores << ", \"" << cpu_freq << "\", \"1.0V\", " << cpu_class << ", " << l1_icache_class << ", " << l1_dcache_class << ", " << walk_cache_class << ", " << l2_Cache_class << ")]\n";
100   starter_fs_ofstream << "  root.system.addCaches(has_caches, last_cache_level=2)\n";
101   starter_fs_ofstream << "  root.system.realview.setupBootLoader(root.system, SysPaths.binary)\n";
102   starter_fs_ofstream << "  root.system.workload.dtb_filename = os.path.join(m5.options.outdir, 'system.dtb')\n";
103   starter_fs_ofstream << "  root.system.generateDtb(root.system.workload.dtb_filename)\n";
104   starter_fs_ofstream << "  root.system.workload.initrd_filename = \"" << instance.PerInstancePath("initrd.img") << "\"\n";
105 
106   //kernel cmd
107   starter_fs_ofstream << fs_kernel_cmd << "\n";
108 
109   // execute main
110   starter_fs_ofstream << fs_exe_main << "\n";
111 }
112 
113 }  // namespace
114 
Gem5Manager(Arch arch)115 Gem5Manager::Gem5Manager(Arch arch) : arch_(arch) {}
116 
IsSupported()117 bool Gem5Manager::IsSupported() {
118   return HostSupportsQemuCli();
119 }
120 
ConfigureGraphics(const CuttlefishConfig & config)121 std::vector<std::string> Gem5Manager::ConfigureGraphics(
122     const CuttlefishConfig& config) {
123   // TODO: Add support for the gem5 gpu models
124 
125   // Override the default HAL search paths in all cases. We do this because
126   // the HAL search path allows for fallbacks, and fallbacks in conjunction
127   // with properities lead to non-deterministic behavior while loading the
128   // HALs.
129   return {
130       "androidboot.cpuvulkan.version=" + std::to_string(VK_API_VERSION_1_1),
131       "androidboot.hardware.gralloc=minigbm",
132       "androidboot.hardware.hwcomposer=" + config.hwcomposer(),
133       "androidboot.hardware.hwcomposer.mode=noop",
134       "androidboot.hardware.egl=angle",
135       "androidboot.hardware.vulkan=pastel",
136   };
137 }
138 
ConfigureBootDevices(int)139 std::string Gem5Manager::ConfigureBootDevices(int /*num_disks*/) {
140   switch (arch_) {
141     case Arch::Arm:
142     case Arch::Arm64:
143       return "androidboot.boot_devices=30000000.pci";
144     // TODO: Add x86 support
145     default:
146       return "";
147   }
148 }
149 
StartCommands(const CuttlefishConfig & config)150 std::vector<Command> Gem5Manager::StartCommands(
151     const CuttlefishConfig& config) {
152   auto instance = config.ForDefaultInstance();
153 
154   auto stop = [](Subprocess* proc) {
155     return KillSubprocess(proc) == StopperResult::kStopSuccess
156                ? StopperResult::kStopCrash
157                : StopperResult::kStopFailure;
158   };
159   std::string gem5_binary = config.gem5_binary_dir();
160   switch (arch_) {
161     case Arch::Arm:
162     case Arch::Arm64:
163       gem5_binary += "/build/ARM/gem5.opt";
164       break;
165     case Arch::X86:
166     case Arch::X86_64:
167       gem5_binary += "/build/X86/gem5.opt";
168       break;
169   }
170   // generate Gem5 starter_fs.py before we execute it
171   GenerateGem5File(config);
172 
173   Command gem5_cmd(gem5_binary, stop);
174   gem5_cmd.AddParameter(config.gem5_binary_dir(), "/configs/example/arm/starter_fs.py");
175   gem5_cmd.AddParameter("--mem-size=", config.memory_mb() * 1024ULL * 1024ULL);
176   for (const auto& disk : instance.virtual_disk_paths()) {
177     gem5_cmd.AddParameter("--disk-image=", disk);
178   }
179 
180   LogAndSetEnv("M5_PATH", config.assembly_dir());
181 
182   std::vector<Command> ret;
183   ret.push_back(std::move(gem5_cmd));
184   return ret;
185 }
186 
187 } // namespace vm_manager
188 } // namespace cuttlefish
189