1 /*
2  * Copyright (C) 2017 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/config/kernel_args.h"
18 
19 #include <array>
20 #include <sstream>
21 #include <string>
22 #include <vector>
23 
24 #include "common/libs/utils/environment.h"
25 #include "host/libs/config/cuttlefish_config.h"
26 #include "host/libs/vm_manager/qemu_manager.h"
27 
28 namespace cuttlefish {
29 
30 using vm_manager::QemuManager;
31 
32 namespace {
33 
34 template<typename T>
AppendVector(std::vector<T> * destination,const std::vector<T> & source)35 void AppendVector(std::vector<T>* destination, const std::vector<T>& source) {
36   destination->insert(destination->end(), source.begin(), source.end());
37 }
38 
39 // TODO(schuffelen): Move more of this into host/libs/vm_manager, as a
40 // substitute for the vm_manager comparisons.
VmManagerKernelCmdline(const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance)41 std::vector<std::string> VmManagerKernelCmdline(
42     const CuttlefishConfig& config,
43     const CuttlefishConfig::InstanceSpecific& instance) {
44   std::vector<std::string> vm_manager_cmdline;
45   if (config.vm_manager() == VmmMode::kQemu) {
46     Arch target_arch = instance.target_arch();
47     if (target_arch == Arch::Arm64 || target_arch == Arch::Arm) {
48       if (instance.enable_kernel_log()) {
49         vm_manager_cmdline.push_back("console=hvc0");
50 
51         // To update the pl011 address:
52         // $ qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine dumpdtb=virt.dtb
53         // $ dtc -O dts -o virt.dts -I dtb virt.dtb
54         // In the virt.dts file, look for a uart node
55         vm_manager_cmdline.push_back("earlycon=pl011,mmio32,0x9000000");
56       }
57     } else if (target_arch == Arch::RiscV64) {
58         vm_manager_cmdline.push_back("console=hvc0");
59 
60         // To update the uart8250 address:
61         // $ qemu-system-riscv64 -machine virt -machine dumpdtb=virt.dtb
62         // $ dtc -O dts -o virt.dts -I dtb virt.dtb
63         // In the virt.dts file, look for a uart node
64         // Only 'mmio' mode works; mmio32 does not
65         vm_manager_cmdline.push_back("earlycon=uart8250,mmio,0x10000000");
66 
67         // The kernel defaults to Sv57. Disable 5-level paging to set the mode
68         // to Sv48.
69         vm_manager_cmdline.push_back("no5lvl");
70     } else {
71       if (instance.enable_kernel_log()) {
72         vm_manager_cmdline.push_back("console=hvc0");
73 
74         // To update the uart8250 address:
75         // $ qemu-system-x86_64 -kernel bzImage -serial stdio | grep ttyS0
76         // Only 'io' mode works; mmio and mmio32 do not
77         vm_manager_cmdline.push_back("earlycon=uart8250,io,0x3f8");
78       }
79 
80       // crosvm doesn't support ACPI PNP, but QEMU does. We need to disable
81       // it on QEMU so that the ISA serial ports aren't claimed by ACPI, so
82       // we can use serdev with platform devices instead
83       vm_manager_cmdline.push_back("pnpacpi=off");
84 
85       // crosvm sets up the ramoops.xx= flags for us, but QEMU does not.
86       // See external/crosvm/x86_64/src/lib.rs
87       // this feature is not supported on aarch64
88       // check guest's /proc/iomem when you need to change mem_address or mem_size
89       vm_manager_cmdline.push_back("ramoops.mem_address=0x150000000");
90       vm_manager_cmdline.push_back("ramoops.mem_size=0x200000");
91       vm_manager_cmdline.push_back("ramoops.console_size=0x80000");
92       vm_manager_cmdline.push_back("ramoops.record_size=0x80000");
93       vm_manager_cmdline.push_back("ramoops.dump_oops=1");
94     }
95   }
96 
97   if (instance.console() && instance.kgdb()) {
98     AppendVector(&vm_manager_cmdline, {"kgdboc_earlycon", "kgdbcon",
99                                        "kgdboc=" + instance.console_dev()});
100   }
101   return vm_manager_cmdline;
102 }
103 
104 } // namespace
105 
KernelCommandLineFromConfig(const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance)106 std::vector<std::string> KernelCommandLineFromConfig(
107     const CuttlefishConfig& config,
108     const CuttlefishConfig::InstanceSpecific& instance) {
109   std::vector<std::string> kernel_cmdline;
110   AppendVector(&kernel_cmdline, VmManagerKernelCmdline(config, instance));
111   AppendVector(&kernel_cmdline, config.extra_kernel_cmdline());
112   return kernel_cmdline;
113 }
114 
115 } // namespace cuttlefish
116