1 /*
2  * Copyright (C) 2023 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/commands/assemble_cvd/disk/disk.h"
18 
19 #include <memory>
20 #include <string>
21 #include <unordered_set>
22 
23 #include <fruit/fruit.h>
24 
25 #include "common/libs/fs/shared_buf.h"
26 #include "common/libs/fs/shared_fd.h"
27 #include "common/libs/utils/files.h"
28 #include "common/libs/utils/result.h"
29 #include "common/libs/utils/size_utils.h"
30 #include "host/commands/assemble_cvd/bootconfig_args.h"
31 #include "host/libs/avb/avb.h"
32 #include "host/libs/config/cuttlefish_config.h"
33 #include "host/libs/config/data_image.h"
34 #include "host/libs/config/feature.h"
35 #include "host/libs/config/known_paths.h"
36 #include "host/libs/vm_manager/gem5_manager.h"
37 
38 namespace cuttlefish {
39 
GeneratePersistentBootconfig(const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance)40 Result<void> GeneratePersistentBootconfig(
41     const CuttlefishConfig& config,
42     const CuttlefishConfig::InstanceSpecific& instance) {
43   if (instance.protected_vm()) {
44     return {};
45   }
46   //  Cuttlefish for the time being won't be able to support OTA from a
47   //  non-bootconfig kernel to a bootconfig-kernel (or vice versa) IF the
48   //  device is stopped (via stop_cvd). This is rarely an issue since OTA
49   //  testing run on cuttlefish is done within one launch cycle of the device.
50   //  If this ever becomes an issue, this code will have to be rewritten.
51   if (!instance.bootconfig_supported()) {
52     return {};
53   }
54   const auto bootconfig_path = instance.persistent_bootconfig_path();
55   if (!FileExists(bootconfig_path)) {
56     CF_EXPECT(CreateBlankImage(bootconfig_path, 1 /* mb */, "none"),
57               "Failed to create image at " << bootconfig_path);
58   }
59 
60   auto bootconfig_fd = SharedFD::Open(bootconfig_path, O_RDWR);
61   CF_EXPECT(bootconfig_fd->IsOpen(),
62             "Unable to open bootconfig file: " << bootconfig_fd->StrError());
63 
64   const auto bootconfig_args =
65       CF_EXPECT(BootconfigArgsFromConfig(config, instance));
66   const auto bootconfig =
67       CF_EXPECT(BootconfigArgsString(bootconfig_args, "\n")) + "\n";
68 
69   LOG(DEBUG) << "bootconfig size is " << bootconfig.size();
70   ssize_t bytesWritten = WriteAll(bootconfig_fd, bootconfig);
71   CF_EXPECT(WriteAll(bootconfig_fd, bootconfig) == bootconfig.size(),
72             "Failed to write bootconfig to \"" << bootconfig_path << "\"");
73   LOG(DEBUG) << "Bootconfig parameters from vendor boot image and config are "
74              << ReadFile(bootconfig_path);
75 
76   CF_EXPECT(bootconfig_fd->Truncate(bootconfig.size()) == 0,
77             "`truncate --size=" << bootconfig.size() << " bytes "
78                                 << bootconfig_path
79                                 << "` failed:" << bootconfig_fd->StrError());
80 
81   if (config.vm_manager() == VmmMode::kGem5) {
82     const off_t bootconfig_size_bytes_gem5 =
83         AlignToPowerOf2(bytesWritten, PARTITION_SIZE_SHIFT);
84     CF_EXPECT(bootconfig_fd->Truncate(bootconfig_size_bytes_gem5) == 0);
85     bootconfig_fd->Close();
86   } else {
87     bootconfig_fd->Close();
88     const off_t bootconfig_size_bytes = AlignToPowerOf2(
89         kMaxAvbMetadataSize + bootconfig.size(), PARTITION_SIZE_SHIFT);
90 
91     std::unique_ptr<Avb> avbtool = GetDefaultAvb();
92     CF_EXPECT(avbtool->AddHashFooter(bootconfig_path, "bootconfig",
93                                      bootconfig_size_bytes));
94   }
95   return {};
96 }
97 
98 }  // namespace cuttlefish
99