gta4xl-common: Support updating firmware
Change-Id: Iff87746b6e3efd5ed0af207e689fd068ad965212
diff --git a/BoardConfigCommon.mk b/BoardConfigCommon.mk
index 4dabd01..eb05bdb 100644
--- a/BoardConfigCommon.mk
+++ b/BoardConfigCommon.mk
@@ -149,6 +149,7 @@
BOARD_INCLUDE_RECOVERY_DTBO := true
TARGET_RECOVERY_FSTAB := $(COMMON_PATH)/configs/init/fstab.exynos9611
TARGET_RECOVERY_PIXEL_FORMAT := "ABGR_8888"
+TARGET_RECOVERY_UPDATER_LIBS := librecovery_updater_exynos9611
## Releasetools
TARGET_RELEASETOOLS_EXTENSIONS := $(COMMON_PATH)/releasetools
diff --git a/recovery/Android.bp b/recovery/Android.bp
new file mode 100644
index 0000000..fb4bebe
--- /dev/null
+++ b/recovery/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2022 The LineageOS Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+ name: "librecovery_updater_exynos9611",
+ srcs: [
+ "recovery_updater.cpp",
+ ],
+ header_libs: ["libbase_headers"],
+ include_dirs: [
+ "bootable/recovery",
+ "bootable/recovery/edify/include",
+ "bootable/recovery/otautil/include",
+ "system/libziparchive/include"
+ ],
+}
diff --git a/recovery/recovery_updater.cpp b/recovery/recovery_updater.cpp
new file mode 100644
index 0000000..eff2c0f
--- /dev/null
+++ b/recovery/recovery_updater.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2022 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <libgen.h>
+#include <unistd.h>
+
+#include <android-base/properties.h>
+#include <edify/expr.h>
+#include <otautil/error_code.h>
+#include <ziparchive/zip_archive.h>
+
+Value *VerifyNoDowngradeFn(const char* name, State *state,
+ const std::vector<std::unique_ptr<Expr>>& argv) {
+ int ret = 1;
+ std::vector<std::string> args;
+
+ if (argv.size() != 1 || !ReadArgs(state, argv, &args))
+ return ErrorAbort(state, kArgsParsingFailure,
+ "%s() error parsing arguments", name);
+
+ std::string blModel = android::base::GetProperty("ro.boot.em.model", "");
+ std::string shortModel = blModel.substr(blModel.find("-") + 1, std::string::npos);
+ std::string blVer = android::base::GetProperty("ro.boot.bootloader", "");
+ if (blVer.length() >= shortModel.length() + 4
+ && args[0].length() >= shortModel.length() + 4) { // <model>XXU<binary>
+ std::string curBinary = blVer.substr(shortModel.length() + 3, 1);
+ std::string newBinary = args[0].substr(shortModel.length() + 3, 1);
+ if (newBinary.at(0) >= curBinary.at(0)) {
+ ret = 0;
+ }
+ }
+
+ return StringValue(std::to_string(ret));
+}
+
+Value *MarkHeaderBtFn(const char* name, State *state,
+ const std::vector<std::unique_ptr<Expr>>& argv) {
+ int ret = 0;
+ std::vector<std::string> args;
+ const char* partition;
+ uint32_t magicOffset;
+ uint32_t numImages;
+ uint32_t magic1;
+
+ if(argv.size() < 4 || argv.size() > 4 || !ReadArgs(state, argv, &args))
+ return ErrorAbort(state, kArgsParsingFailure,
+ "%s() error parsing arguments", name);
+
+ partition = args[0].c_str();
+ magicOffset = std::atoi(args[1].c_str());
+ numImages = std::atoi(args[2].c_str());
+ magic1 = std::atoi(args[3].c_str());
+
+ int fd = open(partition, O_RDWR);
+ if (fd < 0)
+ return ErrorAbort(state, kFileOpenFailure,
+ "%s() failed to open %s", name, partition);
+
+ magic1 = magic1 << (magicOffset * 8);
+ numImages = numImages << (magicOffset * 8);
+ write(fd, (char*)&magic1, sizeof(uint32_t));
+ write(fd, (char*)&numImages, sizeof(uint32_t));
+ close(fd);
+
+ return StringValue(std::to_string(ret));
+}
+
+#define FILENAME_MAX_LEN 32
+
+Value *WriteDataBtFn(const char* name, State *state,
+ const std::vector<std::unique_ptr<Expr>>& argv) {
+ int ret = 0;
+ std::vector<std::string> args;
+ const char* file;
+ const char* filename;
+ const char* partition;
+ uint32_t offset;
+ uint32_t filesize;
+
+ if(argv.size() < 4 || argv.size() > 4 || !ReadArgs(state, argv, &args))
+ return ErrorAbort(state, kArgsParsingFailure,
+ "%s() error parsing arguments", name);
+
+ file = args[0].c_str();
+ filename = basename(file);
+ partition = args[1].c_str();
+ offset = std::atoi(args[2].c_str());
+ filesize = std::atoi(args[3].c_str());
+
+ int fd = open(partition, O_RDWR);
+ if (fd < 0)
+ return ErrorAbort(state, kFileOpenFailure,
+ "%s() failed to open %s", name, partition);
+
+ char filename_padded[FILENAME_MAX_LEN] = { 0 };
+ strcpy(&filename_padded[0], filename);
+
+ lseek(fd, offset, SEEK_SET);
+ write(fd, &filename_padded[0], FILENAME_MAX_LEN);
+ write(fd, (char*)&filesize, sizeof(uint32_t));
+
+ // write data
+ ZipArchiveHandle za = state->updater->GetPackageHandle();
+ ZipEntry64 entry;
+ if (FindEntry(za, file, &entry) != 0) {
+ return ErrorAbort(state, kPackageExtractFileFailure,
+ "%s() %s not found in package", name, file);
+ }
+
+ if (ExtractEntryToFile(za, &entry, fd))
+ return ErrorAbort(state, kPackageExtractFileFailure,
+ "%s() failed to extract %s from package", name, file);
+
+ close(fd);
+
+ return StringValue(std::to_string(ret));
+}
+
+void Register_librecovery_updater_exynos9611() {
+ RegisterFunction("exynos9611.verify_no_downgrade", VerifyNoDowngradeFn);
+ RegisterFunction("exynos9611.mark_header_bt", MarkHeaderBtFn);
+ RegisterFunction("exynos9611.write_data_bt", WriteDataBtFn);
+}
diff --git a/releasetools/releasetools.py b/releasetools/releasetools.py
index 3e59bc6..584791b 100644
--- a/releasetools/releasetools.py
+++ b/releasetools/releasetools.py
@@ -1,6 +1,6 @@
#!/bin/env python3
#
-# Copyright (C) 2020 The LineageOS Project
+# Copyright (C) 2020-2022 The LineageOS Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -34,9 +34,53 @@
def PrintInfo(info, dest):
info.script.Print("Patching {} image unconditionally...".format(dest.split('/')[-1]))
+def AddFirmwareImage(info, model, basename, dest, simple=False, offset=8):
+ if ("RADIO/%s_%s" % (basename, model)) in info.input_zip.namelist():
+ data = info.input_zip.read("RADIO/%s_%s" % (basename, model))
+ common.ZipWriteStr(info.output_zip, "firmware/%s/%s" % (model, basename), data);
+ info.script.Print("Patching {} image unconditionally...".format(basename.split('.')[0]));
+ if simple:
+ info.script.AppendExtra('package_extract_file("firmware/%s/%s", "%s");' % (model, basename, dest))
+ else:
+ size = info.input_zip.getinfo("RADIO/%s_%s" % (basename, model)).file_size
+ info.script.AppendExtra('assert(exynos9611.write_data_bt("firmware/%s/%s", "%s", %d, %d));' % (model, basename, dest, offset, size))
+ return size
+ return 0
+
def OTA_InstallEnd(info):
PrintInfo(info, "/dev/block/by-name/dtbo")
AddImage(info, "dtbo.img", "/dev/block/by-name/dtbo")
PrintInfo(info, "/dev/block/by-name/vbmeta")
AddImage(info, "vbmeta.img", "/dev/block/by-name/vbmeta")
+
+ if "RADIO/models" in info.input_zip.namelist():
+ modelsIncluded = []
+ for model in info.input_zip.read("RADIO/models").decode('utf-8').splitlines():
+ if "RADIO/version_%s" % model in info.input_zip.namelist():
+ modelsIncluded.append(model)
+ version = info.input_zip.read("RADIO/version_%s" % model).decode('utf-8').splitlines()[0]
+ offset = 8
+ numImages = 0
+ info.script.AppendExtra('# Firmware update to %s for %s' % (version, model))
+ info.script.AppendExtra('ifelse (getprop("ro.boot.em.model") == "%s" &&' % model)
+ info.script.AppendExtra('exynos9611.verify_no_downgrade("%s") == "0" &&' % version)
+ info.script.AppendExtra('getprop("ro.boot.bootloader") != "%s",' % version)
+ info.script.AppendExtra('assert(exynos9611.mark_header_bt("/dev/block/by-name/bota", 0, 0, 0));')
+ for image in 'cm.bin', 'keystorage.bin', 'sboot.bin', 'uh.bin', 'up_param.bin':
+ size = AddFirmwareImage(info, model, image, "/dev/block/by-name/bota", False, offset)
+ if size > 0:
+ numImages += 1
+ offset += size + 36 # header size
+ info.script.AppendExtra('assert(exynos9611.mark_header_bt("/dev/block/by-name/bota", 0, %d, 3142939818));' % numImages)
+ AddFirmwareImage(info, model, "modem.bin", "/dev/block/by-name/radio", True)
+ AddFirmwareImage(info, model, "modem_debug.bin", "/dev/block/by-name/cp_debug", True)
+ info.script.AppendExtra(',"");')
+
+ modelCheck = ""
+ for model in modelsIncluded:
+ if len(modelCheck) > 0:
+ modelCheck += ' || '
+ modelCheck += 'getprop("ro.boot.em.model") == "%s"' % model
+ if len(modelCheck) > 0:
+ info.script.AppendExtra('%s || abort("Unsupported model, not updating firmware!");' % modelCheck)
return