Merge tag 'android-11.0.0_r16' into android-10.0
Android 11.0.0 release 16 - twrp bringup patch
diff --git a/.clang-format b/.clang-format
index 4a3bd2f..6fa717c 100644
--- a/.clang-format
+++ b/.clang-format
@@ -36,6 +36,7 @@
ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
+IncludeBlocks: Preserve
IndentWidth: 2
PointerAlignment: Left
TabWidth: 2
diff --git a/Android.bp b/Android.bp
index c9f92b6..250ef9d 100755
--- a/Android.bp
+++ b/Android.bp
@@ -1,10 +1,5 @@
subdirs = [
-// "applypatch",
"bootloader_message",
-// "edify",
-// "otafault",
-// "otautil",
-// "uncrypt",
]
cc_defaults {
@@ -18,3 +13,78 @@
],
cpp_std: "c++17",
}
+
+bootstrap_go_package {
+ name: "soong-libaosprecovery_defaults",
+ pkgPath: "bootable/recovery/libaosprecovery",
+ deps: [
+ "soong",
+ "soong-android",
+ "soong-cc"
+ ],
+ srcs: [
+ "libaosprecovery_defaults.go"
+ ],
+ pluginFor: ["soong_build"]
+}
+
+libaosprecovery_defaults {
+ name: "libaosprecovery_defaults"
+}
+
+cc_library_shared {
+ name: "libaosprecovery",
+ defaults: ["libaosprecovery_defaults"],
+ cflags: [
+ "-std=gnu++2a",
+ "-DRECOVERY_API_VERSION=3"
+ ],
+ include_dirs: [
+ "bootable/recovery/install/include",
+ "bootable/recovery/recovery_ui/include",
+ "bootable/recovery/recovery_utils/include",
+ "bootable/recovery/otautil/include",
+ "bootable/recovery/minadbd",
+ "bootable/recovery/minadbd/include",
+ "bootable/recovery/minzip",
+ "bootable/recovery/twrpinstall/include",
+ "system/libvintf/include"
+ ],
+ srcs: [
+ "install/adb_install.cpp",
+ "install/asn1_decoder.cpp",
+ "install/get_args.cpp",
+ "install/install.cpp",
+ "install/package.cpp",
+ "install/verifier.cpp",
+ "install/wipe_data.cpp",
+ "install/set_metadata.cpp",
+ "install/ZipUtil.cpp"
+ ],
+ shared_libs: [
+ "libbase",
+ "libbootloader_message",
+ "libcrypto",
+ "libext4_utils",
+ "libfs_mgr",
+ "libfusesideload",
+ "libhidl-gen-utils",
+ "libhidlbase",
+ "liblog",
+ "libselinux",
+ "libtinyxml2",
+ "libutils",
+ "libz",
+ "libziparchive",
+ "libcutils",
+ "libc++"
+ ],
+ static_libs: [
+ "libotautil",
+ "libvintf",
+ "libhidl-gen-utils",
+ "librecovery_utils",
+ "libc++fs"
+ ]
+}
+
diff --git a/Android.mk b/Android.mk
index efcf1b6..f81d023 100755
--- a/Android.mk
+++ b/Android.mk
@@ -77,8 +77,8 @@
twrpApex.cpp \
twrpRepacker.cpp
-LOCAL_STATIC_LIBRARIES += libavb libtwrpinstall
-LOCAL_SHARED_LIBRARIES += libfs_mgr libinit
+LOCAL_STATIC_LIBRARIES += libavb libtwrpinstall libminadbd_services libinit
+LOCAL_SHARED_LIBRARIES += libfs_mgr
LOCAL_C_INCLUDES += \
system/core/fs_mgr/libfs_avb/include/ \
system/core/fs_mgr/include_fstab/ \
@@ -120,11 +120,13 @@
$(LOCAL_PATH)/install/include \
$(LOCAL_PATH)/fuse_sideload/include \
$(LOCAL_PATH)/install/include \
- $(LOCAL_PATH)/twrpinstall/include
+ $(LOCAL_PATH)/twrpinstall/include \
+ $(LOCAL_PATH)/recovery_utils/include
LOCAL_STATIC_LIBRARIES += libguitwrp
-LOCAL_SHARED_LIBRARIES += libz libc libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libtwadbbu libbootloader_message
-LOCAL_SHARED_LIBRARIES += libcrecovery libtwrpdigest libc++ libaosprecovery libinit libcrypto libbase libziparchive libselinux
+LOCAL_SHARED_LIBRARIES += libz libc libcutils libstdc++ libtar libblkid libminuitwrp libmtdutils libtwadbbu
+LOCAL_SHARED_LIBRARIES += libbootloader_message libcrecovery libtwrpdigest libc++ libaosprecovery libcrypto libbase
+LOCAL_SHARED_LIBRARIES += libziparchive libselinux
ifneq ($(wildcard system/core/libsparse/Android.mk),)
LOCAL_SHARED_LIBRARIES += libsparse
@@ -288,7 +290,8 @@
endif
ifeq ($(TW_INCLUDE_CRYPTO), true)
LOCAL_CFLAGS += -DTW_INCLUDE_CRYPTO -DUSE_FSCRYPT -Wno-macro-redefined
- LOCAL_SHARED_LIBRARIES += libcryptfsfde libgpt_twrp
+ # LOCAL_SHARED_LIBRARIES += libcryptfsfde
+ LOCAL_SHARED_LIBRARIES += libgpt_twrp
LOCAL_C_INCLUDES += external/boringssl/src/include bootable/recovery/crypto/fscrypt \
bootable/recovery/crypto
TW_INCLUDE_CRYPTO_FBE := true
@@ -510,11 +513,11 @@
LOCAL_SRC_FILES := \
recovery-persist.cpp
LOCAL_MODULE := recovery-persist
-LOCAL_SHARED_LIBRARIES := liblog libbase libmetricslogger
-LOCAL_STATIC_LIBRARIES := libotautil
+LOCAL_SHARED_LIBRARIES := liblog libbase
+LOCAL_STATIC_LIBRARIES := libotautil librecovery_utils
LOCAL_C_INCLUDES += $(LOCAL_PATH)/otautil/include
-LOCAL_C_INCLUDES += system/core/libmetricslogger/include \
- system/core/libstats/include
+LOCAL_C_INCLUDES += system/core/libstats/include
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/recovery_utils/include
LOCAL_CFLAGS := -Werror
LOCAL_INIT_RC := recovery-persist.rc
include $(BUILD_EXECUTABLE)
@@ -526,8 +529,9 @@
recovery-refresh.cpp
LOCAL_MODULE := recovery-refresh
LOCAL_SHARED_LIBRARIES := liblog libbase
-LOCAL_STATIC_LIBRARIES := libotautil
+LOCAL_STATIC_LIBRARIES := libotautil librecovery_utils
LOCAL_C_INCLUDES += $(LOCAL_PATH)/otautil/include
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/recovery_utils/include
LOCAL_CFLAGS := -Werror
LOCAL_INIT_RC := recovery-refresh.rc
include $(BUILD_EXECUTABLE)
@@ -567,53 +571,17 @@
include $(BUILD_STATIC_LIBRARY)
-# shared libaosprecovery for Apache code
-# ===============================
-include $(CLEAR_VARS)
-
-
-LOCAL_MODULE := libaosprecovery
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := install/adb_install.cpp install/asn1_decoder.cpp install/fuse_sdcard_install.cpp \
- install/get_args.cpp install/install.cpp install/legacy_property_service.cpp \
- install/package.cpp install/verifier.cpp install/wipe_data.cpp \
- install/set_metadata.cpp install/zipwrap.cpp install/ZipUtil.cpp
-LOCAL_SHARED_LIBRARIES += libbase libbootloader_message libcrypto libext4_utils \
- libfs_mgr libfusesideload libhidl-gen-utils libhidlbase \
- liblog libselinux libtinyxml2 libutils libz libziparchive libcutils
-LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
-LOCAL_SHARED_LIBRARIES += libc++
-LOCAL_CFLAGS := -std=gnu++2a
-LOCAL_C_INCLUDES += $(commands_TWRP_local_path)/install/include \
- $(commands_TWRP_local_path)/recovery_ui/include \
- $(commands_TWRP_local_path)/otautil/include \
- $(commands_TWRP_local_path)/minadbd \
- $(commands_TWRP_local_path)/minzip \
- $(commands_TWRP_local_path)/twrpinstall/include \
- system/libvintf/include
-LOCAL_STATIC_LIBRARIES += libotautil libvintf_recovery libvintf libhidl-gen-utils
-LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
-
-ifeq ($(AB_OTA_UPDATER),true)
- LOCAL_CFLAGS += -DAB_OTA_UPDATER=1
-endif
-
-include $(BUILD_SHARED_LIBRARY)
-
commands_recovery_local_path := $(LOCAL_PATH)
include \
$(commands_TWRP_local_path)/updater/Android.mk
include $(commands_TWRP_local_path)/mtp/ffs/Android.mk \
- $(commands_TWRP_local_path)/minadbd/Android.mk \
$(commands_TWRP_local_path)/minui/Android.mk
#includes for TWRP
include $(commands_TWRP_local_path)/injecttwrp/Android.mk \
$(commands_TWRP_local_path)/htcdumlock/Android.mk \
- $(commands_TWRP_local_path)/gui/Android.mk \
$(commands_TWRP_local_path)/mmcutils/Android.mk \
$(commands_TWRP_local_path)/bmlutils/Android.mk \
$(commands_TWRP_local_path)/prebuilt/Android.mk \
@@ -623,7 +591,6 @@
$(commands_TWRP_local_path)/libtar/Android.mk \
$(commands_TWRP_local_path)/libcrecovery/Android.mk \
$(commands_TWRP_local_path)/libblkid/Android.mk \
- $(commands_TWRP_local_path)/minuitwrp/Android.mk \
$(commands_TWRP_local_path)/openaes/Android.mk \
$(commands_TWRP_local_path)/twrpTarMain/Android.mk \
$(commands_TWRP_local_path)/minzip/Android.mk \
@@ -631,7 +598,6 @@
$(commands_TWRP_local_path)/etc/Android.mk \
$(commands_TWRP_local_path)/simg2img/Android.mk \
$(commands_TWRP_local_path)/adbbu/Android.mk \
- $(commands_TWRP_local_path)/libpixelflinger/Android.mk \
$(commands_TWRP_local_path)/twrpDigest/Android.mk \
$(commands_TWRP_local_path)/attr/Android.mk
@@ -641,7 +607,7 @@
endif
ifeq ($(TW_INCLUDE_CRYPTO), true)
- include $(commands_TWRP_local_path)/crypto/fde/Android.mk
+ # include $(commands_TWRP_local_path)/crypto/fde/Android.mk
include $(commands_TWRP_local_path)/crypto/scrypt/Android.mk
ifeq ($(TW_INCLUDE_CRYPTO_FBE), true)
include $(commands_TWRP_local_path)/crypto/fscrypt/Android.mk
diff --git a/CleanSpec.mk b/CleanSpec.mk
index a7ab0d9..d4e9e43 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -51,6 +51,24 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libinstall.recovery_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/system/lib64/libinstall.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/nativetest/recovery_component_test)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/nativetest64/recovery_component_test)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/testcases/recovery_component_test)
+
+$(call add-clean-step, find $(OUT_DIR) -type f -name "SystemUpdaterSample*" -print0 | xargs -0 rm -f)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/SystemUpdaterSample)
+
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib*/libbrotli.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib*/libbz.so)
+
+# Move recovery resources from /system to /vendor.
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/bin/applypatch)
+$(call add-clean-step, rm -r $(PRODUCT_OUT)/symbols/system/bin/applypatch)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/PACKAGING/target_files_intermediates/*-target_files-*/SYSTEM/bin/applypatch)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/PACKAGING/target_files_intermediates/*-target_files-*/SYSTEM/bin/install-recovery.sh)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/PACKAGING/target_files_intermediates/*-target_files-*/SYSTEM/etc/recovery-resource.dat)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/PACKAGING/target_files_intermediates/*-target_files-*/SYSTEM/recovery-from-boot.p)
+
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
diff --git a/OWNERS b/OWNERS
index b3f11dc..79dd9f7 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,5 @@
+elsk@google.com
enh@google.com
-tbao@google.com
+nhdo@google.com
xunchang@google.com
+zhaojiac@google.com
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..a304582
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,14 @@
+{
+ "presubmit": [
+ {
+ "name": "minadbd_test"
+ },
+ {
+ "name": "recovery_unit_test"
+ },
+ {
+ "name": "recovery_host_test",
+ "host": true
+ }
+ ]
+}
diff --git a/applypatch/Android.bp b/applypatch/Android.bp
index 620ca6c..13a9625 100644
--- a/applypatch/Android.bp
+++ b/applypatch/Android.bp
@@ -31,6 +31,7 @@
name: "libapplypatch",
host_supported: true,
+ vendor_available: true,
defaults: [
"applypatch_defaults",
@@ -51,12 +52,15 @@
"libbase",
"libbspatch",
"libbz",
- "libcrypto",
"libedify",
"libotautil",
"libz",
],
+ shared_libs: [
+ "libcrypto",
+ ],
+
target: {
darwin: {
enabled: false,
@@ -66,6 +70,7 @@
cc_library_static {
name: "libapplypatch_modes",
+ vendor_available: true,
defaults: [
"applypatch_defaults",
@@ -78,14 +83,18 @@
static_libs: [
"libapplypatch",
"libbase",
- "libcrypto",
"libedify",
"libotautil",
],
+
+ shared_libs: [
+ "libcrypto",
+ ],
}
cc_binary {
name: "applypatch",
+ vendor: true,
defaults: [
"applypatch_defaults",
@@ -100,25 +109,29 @@
"libapplypatch",
"libedify",
"libotautil",
+
+ // External dependencies.
"libbspatch",
+ "libbrotli",
+ "libbz",
],
shared_libs: [
"libbase",
- "libbrotli",
- "libbz",
"libcrypto",
"liblog",
"libz",
"libziparchive",
],
+
+ init_rc: [
+ "vendor_flash_recovery.rc",
+ ],
}
-cc_library_static {
+cc_library_host_static {
name: "libimgdiff",
- host_supported: true,
-
defaults: [
"applypatch_defaults",
],
@@ -170,35 +183,3 @@
"libz",
],
}
-
-cc_library_static {
- name: "libimgpatch",
-
- // The host module is for recovery_host_test (Linux only).
- host_supported: true,
-
- defaults: [
- "applypatch_defaults",
- ],
-
- srcs: [
- "bspatch.cpp",
- "imgpatch.cpp",
- ],
-
- static_libs: [
- "libbase",
- "libbspatch",
- "libbz",
- "libcrypto",
- "libedify",
- "libotautil",
- "libz",
- ],
-
- target: {
- darwin: {
- enabled: false,
- },
- },
-}
diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp
index 0106582..206a3a3 100755
--- a/applypatch/applypatch.cpp
+++ b/applypatch/applypatch.cpp
@@ -50,7 +50,7 @@
using namespace std::string_literals;
static bool GenerateTarget(const Partition& target, const FileContents& source_file,
- const Value& patch, const Value* bonus_data);
+ const Value& patch, const Value* bonus_data, bool backup_source);
bool LoadFileContents(const std::string& filename, FileContents* file) {
// No longer allow loading contents from eMMC partitions.
@@ -262,7 +262,7 @@
}
bool PatchPartition(const Partition& target, const Partition& source, const Value& patch,
- const Value* bonus) {
+ const Value* bonus, bool backup_source) {
LOG(INFO) << "Patching " << target.name;
// We try to load and check against the target hash first.
@@ -275,8 +275,8 @@
}
FileContents source_file;
- if (ReadPartitionToBuffer(source, &source_file, true)) {
- return GenerateTarget(target, source_file, patch, bonus);
+ if (ReadPartitionToBuffer(source, &source_file, backup_source)) {
+ return GenerateTarget(target, source_file, patch, bonus, backup_source);
}
LOG(ERROR) << "Failed to find any match";
@@ -322,7 +322,7 @@
}
static bool GenerateTarget(const Partition& target, const FileContents& source_file,
- const Value& patch, const Value* bonus_data) {
+ const Value& patch, const Value* bonus_data, bool backup_source) {
uint8_t expected_sha1[SHA_DIGEST_LENGTH];
if (ParseSha1(target.hash, expected_sha1) != 0) {
LOG(ERROR) << "Failed to parse target hash \"" << target.hash << "\"";
@@ -347,11 +347,11 @@
}
// We write the original source to cache, in case the partition write is interrupted.
- if (!CheckAndFreeSpaceOnCache(source_file.data.size())) {
+ if (backup_source && !CheckAndFreeSpaceOnCache(source_file.data.size())) {
LOG(ERROR) << "Not enough free space on /cache";
return false;
}
- if (!SaveFileContents(Paths::Get().cache_temp_source(), &source_file)) {
+ if (backup_source && !SaveFileContents(Paths::Get().cache_temp_source(), &source_file)) {
LOG(ERROR) << "Failed to back up source file";
return false;
}
@@ -405,6 +405,42 @@
LOG(INFO) << " now " << short_sha1(expected_sha1);
// Write back the temp file to the partition.
+ if (!WriteBufferToPartition(patched, target)) {
+ LOG(ERROR) << "Failed to write patched data to " << target.name;
+ return false;
+ }
+
+ // Delete the backup copy of the source.
+ if (backup_source) {
+ unlink(Paths::Get().cache_temp_source().c_str());
+ }
+
+ // Success!
+ return true;
+}
+
+bool CheckPartition(const Partition& partition) {
+ FileContents target_file;
+ return ReadPartitionToBuffer(partition, &target_file, false);
+}
+
+Partition Partition::Parse(const std::string& input_str, std::string* err) {
+ std::vector<std::string> pieces = android::base::Split(input_str, ":");
+ if (pieces.size() != 4 || pieces[0] != "EMMC") {
+ *err = "Invalid number of tokens or non-eMMC target";
+ return {};
+ }
+
+ size_t size;
+ if (!android::base::ParseUint(pieces[2], &size) || size == 0) {
+ *err = "Failed to parse \"" + pieces[2] + "\" as byte count";
+ return {};
+ }
+
+ return Partition(pieces[1], size, pieces[3]);
+}
+
+std::string Partition::ToString() const {
if (*this) {
return "EMMC:"s + name + ":" + std::to_string(size) + ":" + hash;
}
diff --git a/applypatch/applypatch_modes.cpp b/applypatch/applypatch_modes.cpp
index b466598..bb5eeae 100644
--- a/applypatch/applypatch_modes.cpp
+++ b/applypatch/applypatch_modes.cpp
@@ -87,7 +87,7 @@
bonus = std::make_unique<Value>(Value::Type::BLOB, std::move(bonus_contents));
}
- return PatchPartition(target, source, patch, bonus.get()) ? 0 : 1;
+ return PatchPartition(target, source, patch, bonus.get(), false) ? 0 : 1;
}
static void Usage() {
diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp
index 415d95f..6ad4a61 100644
--- a/applypatch/imgdiff.cpp
+++ b/applypatch/imgdiff.cpp
@@ -675,7 +675,7 @@
// Iterate the zip entries and compose the image chunks accordingly.
bool ZipModeImage::InitializeChunks(const std::string& filename, ZipArchiveHandle handle) {
void* cookie;
- int ret = StartIteration(handle, &cookie, nullptr, nullptr);
+ int ret = StartIteration(handle, &cookie);
if (ret != 0) {
LOG(ERROR) << "Failed to iterate over entries in " << filename << ": " << ErrorCodeString(ret);
return false;
@@ -683,12 +683,11 @@
// Create a list of deflated zip entries, sorted by offset.
std::vector<std::pair<std::string, ZipEntry>> temp_entries;
- ZipString name;
+ std::string name;
ZipEntry entry;
while ((ret = Next(cookie, &entry, &name)) == 0) {
if (entry.method == kCompressDeflated || limit_ > 0) {
- std::string entry_name(name.name, name.name + name.name_length);
- temp_entries.emplace_back(entry_name, entry);
+ temp_entries.emplace_back(name, entry);
}
}
diff --git a/applypatch/include/applypatch/applypatch.h b/applypatch/include/applypatch/applypatch.h
index 6fc6f0f..799f4b2 100644
--- a/applypatch/include/applypatch/applypatch.h
+++ b/applypatch/include/applypatch/applypatch.h
@@ -73,10 +73,11 @@
// the 'target' Partition. While patching, it will backup the data on the source partition to
// /cache, so that the patching could be resumed on interruption even if both of the source and
// target partitions refer to the same device. The function is idempotent if called multiple times.
-// An optional arg 'bonus' can be provided, if the patch was generated with a bonus output.
-// Returns the patching result.
+// 'bonus' can be provided if the patch was generated with a bonus output, or nullptr.
+// 'backup_source' indicates whether the source partition should be backed up prior to the update
+// (e.g. when doing in-place update). Returns the patching result.
bool PatchPartition(const Partition& target, const Partition& source, const Value& patch,
- const Value* bonus);
+ const Value* bonus, bool backup_source);
// Returns whether the contents of the eMMC target or the cached file match the embedded hash.
// It will look for the backup on /cache if the given partition doesn't match the checksum.
diff --git a/applypatch/vendor_flash_recovery.rc b/applypatch/vendor_flash_recovery.rc
new file mode 100644
index 0000000..37a7c2b
--- /dev/null
+++ b/applypatch/vendor_flash_recovery.rc
@@ -0,0 +1,3 @@
+service vendor_flash_recovery /vendor/bin/install-recovery.sh
+ class main
+ oneshot
diff --git a/boot_control/Android.bp b/boot_control/Android.bp
deleted file mode 100644
index 7720ead..0000000
--- a/boot_control/Android.bp
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-// Copyright (C) 2018 The Android Open Source 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_shared {
- name: "bootctrl.default",
- recovery_available: true,
- relative_install_path: "hw",
-
- srcs: ["boot_control.cpp"],
-
- cflags: [
- "-D_FILE_OFFSET_BITS=64",
- "-Werror",
- "-Wall",
- "-Wextra",
- ],
-
- shared_libs: [
- "libbase",
- "libbootloader_message",
- "libfs_mgr",
- "liblog",
- ],
-}
diff --git a/boot_control/boot_control.cpp b/boot_control/boot_control.cpp
deleted file mode 100644
index ec97b6c..0000000
--- a/boot_control/boot_control.cpp
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source 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 <endian.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <hardware/boot_control.h>
-#include <hardware/hardware.h>
-
-#include <bootloader_message/bootloader_message.h>
-
-struct boot_control_private_t {
- // The base struct needs to be first in the list.
- boot_control_module_t base;
-
- // Whether this struct was initialized with data from the bootloader message
- // that doesn't change until next reboot.
- bool initialized;
-
- // The path to the misc_device as reported in the fstab.
- const char* misc_device;
-
- // The number of slots present on the device.
- unsigned int num_slots;
-
- // The slot where we are running from.
- unsigned int current_slot;
-};
-
-namespace {
-
-// The number of boot attempts that should be made from a new slot before
-// rolling back to the previous slot.
-constexpr unsigned int kDefaultBootAttempts = 7;
-static_assert(kDefaultBootAttempts < 8, "tries_remaining field only has 3 bits");
-
-constexpr unsigned int kMaxNumSlots =
- sizeof(bootloader_control::slot_info) / sizeof(bootloader_control::slot_info[0]);
-constexpr const char* kSlotSuffixes[kMaxNumSlots] = { "_a", "_b", "_c", "_d" };
-constexpr off_t kBootloaderControlOffset = offsetof(bootloader_message_ab, slot_suffix);
-
-static uint32_t CRC32(const uint8_t* buf, size_t size) {
- static uint32_t crc_table[256];
-
- // Compute the CRC-32 table only once.
- if (!crc_table[1]) {
- for (uint32_t i = 0; i < 256; ++i) {
- uint32_t crc = i;
- for (uint32_t j = 0; j < 8; ++j) {
- uint32_t mask = -(crc & 1);
- crc = (crc >> 1) ^ (0xEDB88320 & mask);
- }
- crc_table[i] = crc;
- }
- }
-
- uint32_t ret = -1;
- for (size_t i = 0; i < size; ++i) {
- ret = (ret >> 8) ^ crc_table[(ret ^ buf[i]) & 0xFF];
- }
-
- return ~ret;
-}
-
-// Return the little-endian representation of the CRC-32 of the first fields
-// in |boot_ctrl| up to the crc32_le field.
-uint32_t BootloaderControlLECRC(const bootloader_control* boot_ctrl) {
- return htole32(
- CRC32(reinterpret_cast<const uint8_t*>(boot_ctrl), offsetof(bootloader_control, crc32_le)));
-}
-
-bool LoadBootloaderControl(const char* misc_device, bootloader_control* buffer) {
- android::base::unique_fd fd(open(misc_device, O_RDONLY));
- if (fd.get() == -1) {
- PLOG(ERROR) << "failed to open " << misc_device;
- return false;
- }
- if (lseek(fd, kBootloaderControlOffset, SEEK_SET) != kBootloaderControlOffset) {
- PLOG(ERROR) << "failed to lseek " << misc_device;
- return false;
- }
- if (!android::base::ReadFully(fd.get(), buffer, sizeof(bootloader_control))) {
- PLOG(ERROR) << "failed to read " << misc_device;
- return false;
- }
- return true;
-}
-
-bool UpdateAndSaveBootloaderControl(const char* misc_device, bootloader_control* buffer) {
- buffer->crc32_le = BootloaderControlLECRC(buffer);
- android::base::unique_fd fd(open(misc_device, O_WRONLY | O_SYNC));
- if (fd.get() == -1) {
- PLOG(ERROR) << "failed to open " << misc_device;
- return false;
- }
- if (lseek(fd.get(), kBootloaderControlOffset, SEEK_SET) != kBootloaderControlOffset) {
- PLOG(ERROR) << "failed to lseek " << misc_device;
- return false;
- }
- if (!android::base::WriteFully(fd.get(), buffer, sizeof(bootloader_control))) {
- PLOG(ERROR) << "failed to write " << misc_device;
- return false;
- }
- return true;
-}
-
-void InitDefaultBootloaderControl(const boot_control_private_t* module,
- bootloader_control* boot_ctrl) {
- memset(boot_ctrl, 0, sizeof(*boot_ctrl));
-
- if (module->current_slot < kMaxNumSlots) {
- strlcpy(boot_ctrl->slot_suffix, kSlotSuffixes[module->current_slot],
- sizeof(boot_ctrl->slot_suffix));
- }
- boot_ctrl->magic = BOOT_CTRL_MAGIC;
- boot_ctrl->version = BOOT_CTRL_VERSION;
-
- // Figure out the number of slots by checking if the partitions exist,
- // otherwise assume the maximum supported by the header.
- boot_ctrl->nb_slot = kMaxNumSlots;
- std::string base_path = module->misc_device;
- size_t last_path_sep = base_path.rfind('/');
- if (last_path_sep != std::string::npos) {
- // We test the existence of the "boot" partition on each possible slot,
- // which is a partition required by Android Bootloader Requirements.
- base_path = base_path.substr(0, last_path_sep + 1) + "boot";
- int last_existing_slot = -1;
- int first_missing_slot = -1;
- for (unsigned int slot = 0; slot < kMaxNumSlots; ++slot) {
- std::string partition_path = base_path + kSlotSuffixes[slot];
- struct stat part_stat;
- int err = stat(partition_path.c_str(), &part_stat);
- if (!err) {
- last_existing_slot = slot;
- LOG(INFO) << "Found slot: " << kSlotSuffixes[slot];
- } else if (err < 0 && errno == ENOENT && first_missing_slot == -1) {
- first_missing_slot = slot;
- }
- }
- // We only declare that we found the actual number of slots if we found all
- // the boot partitions up to the number of slots, and no boot partition
- // after that. Not finding any of the boot partitions implies a problem so
- // we just leave the number of slots in the maximum value.
- if ((last_existing_slot != -1 && last_existing_slot + 1 == first_missing_slot) ||
- (first_missing_slot == -1 && last_existing_slot + 1 == kMaxNumSlots)) {
- boot_ctrl->nb_slot = last_existing_slot + 1;
- LOG(INFO) << "Found a system with " << last_existing_slot + 1 << " slots.";
- }
- }
-
- for (unsigned int slot = 0; slot < kMaxNumSlots; ++slot) {
- slot_metadata entry = {};
-
- if (slot < boot_ctrl->nb_slot) {
- entry.priority = 7;
- entry.tries_remaining = kDefaultBootAttempts;
- entry.successful_boot = 0;
- } else {
- entry.priority = 0; // Unbootable
- }
-
- // When the boot_control stored on disk is invalid, we assume that the
- // current slot is successful. The bootloader should repair this situation
- // before booting and write a valid boot_control slot, so if we reach this
- // stage it means that the misc partition was corrupted since boot.
- if (module->current_slot == slot) {
- entry.successful_boot = 1;
- }
-
- boot_ctrl->slot_info[slot] = entry;
- }
- boot_ctrl->recovery_tries_remaining = 0;
-
- boot_ctrl->crc32_le = BootloaderControlLECRC(boot_ctrl);
-}
-
-// Return the index of the slot suffix passed or -1 if not a valid slot suffix.
-int SlotSuffixToIndex(const char* suffix) {
- for (unsigned int slot = 0; slot < kMaxNumSlots; ++slot) {
- if (!strcmp(kSlotSuffixes[slot], suffix)) return slot;
- }
- return -1;
-}
-
-// Initialize the boot_control_private struct with the information from
-// the bootloader_message buffer stored in |boot_ctrl|. Returns whether the
-// initialization succeeded.
-bool BootControl_lazyInitialization(boot_control_private_t* module) {
- if (module->initialized) return true;
-
- // Initialize the current_slot from the read-only property. If the property
- // was not set (from either the command line or the device tree), we can later
- // initialize it from the bootloader_control struct.
- std::string suffix_prop = android::base::GetProperty("ro.boot.slot_suffix", "");
- module->current_slot = SlotSuffixToIndex(suffix_prop.c_str());
-
- std::string err;
- std::string device = get_bootloader_message_blk_device(&err);
- if (device.empty()) return false;
-
- bootloader_control boot_ctrl;
- if (!LoadBootloaderControl(device.c_str(), &boot_ctrl)) return false;
-
- // Note that since there isn't a module unload function this memory is leaked.
- module->misc_device = strdup(device.c_str());
- module->initialized = true;
-
- // Validate the loaded data, otherwise we will destroy it and re-initialize it
- // with the current information.
- uint32_t computed_crc32 = BootloaderControlLECRC(&boot_ctrl);
- if (boot_ctrl.crc32_le != computed_crc32) {
- LOG(WARNING) << "Invalid boot control found, expected CRC-32 0x" << std::hex << computed_crc32
- << " but found 0x" << std::hex << boot_ctrl.crc32_le << ". Re-initializing.";
- InitDefaultBootloaderControl(module, &boot_ctrl);
- UpdateAndSaveBootloaderControl(device.c_str(), &boot_ctrl);
- }
-
- module->num_slots = boot_ctrl.nb_slot;
- return true;
-}
-
-void BootControl_init(boot_control_module_t* module) {
- BootControl_lazyInitialization(reinterpret_cast<boot_control_private_t*>(module));
-}
-
-unsigned int BootControl_getNumberSlots(boot_control_module_t* module) {
- return reinterpret_cast<boot_control_private_t*>(module)->num_slots;
-}
-
-unsigned int BootControl_getCurrentSlot(boot_control_module_t* module) {
- return reinterpret_cast<boot_control_private_t*>(module)->current_slot;
-}
-
-int BootControl_markBootSuccessful(boot_control_module_t* module) {
- boot_control_private_t* const bootctrl_module = reinterpret_cast<boot_control_private_t*>(module);
-
- bootloader_control bootctrl;
- if (!LoadBootloaderControl(bootctrl_module->misc_device, &bootctrl)) return -1;
-
- bootctrl.slot_info[bootctrl_module->current_slot].successful_boot = 1;
- // tries_remaining == 0 means that the slot is not bootable anymore, make
- // sure we mark the current slot as bootable if it succeeds in the last
- // attempt.
- bootctrl.slot_info[bootctrl_module->current_slot].tries_remaining = 1;
- if (!UpdateAndSaveBootloaderControl(bootctrl_module->misc_device, &bootctrl)) return -1;
- return 0;
-}
-
-int BootControl_setActiveBootSlot(boot_control_module_t* module, unsigned int slot) {
- boot_control_private_t* const bootctrl_module = reinterpret_cast<boot_control_private_t*>(module);
-
- if (slot >= kMaxNumSlots || slot >= bootctrl_module->num_slots) {
- // Invalid slot number.
- return -1;
- }
-
- bootloader_control bootctrl;
- if (!LoadBootloaderControl(bootctrl_module->misc_device, &bootctrl)) return -1;
-
- // Set every other slot with a lower priority than the new "active" slot.
- const unsigned int kActivePriority = 15;
- const unsigned int kActiveTries = 6;
- for (unsigned int i = 0; i < bootctrl_module->num_slots; ++i) {
- if (i != slot) {
- if (bootctrl.slot_info[i].priority >= kActivePriority)
- bootctrl.slot_info[i].priority = kActivePriority - 1;
- }
- }
-
- // Note that setting a slot as active doesn't change the successful bit.
- // The successful bit will only be changed by setSlotAsUnbootable().
- bootctrl.slot_info[slot].priority = kActivePriority;
- bootctrl.slot_info[slot].tries_remaining = kActiveTries;
-
- // Setting the current slot as active is a way to revert the operation that
- // set *another* slot as active at the end of an updater. This is commonly
- // used to cancel the pending update. We should only reset the verity_corrpted
- // bit when attempting a new slot, otherwise the verity bit on the current
- // slot would be flip.
- if (slot != bootctrl_module->current_slot) bootctrl.slot_info[slot].verity_corrupted = 0;
-
- if (!UpdateAndSaveBootloaderControl(bootctrl_module->misc_device, &bootctrl)) return -1;
- return 0;
-}
-
-int BootControl_setSlotAsUnbootable(struct boot_control_module* module, unsigned int slot) {
- boot_control_private_t* const bootctrl_module = reinterpret_cast<boot_control_private_t*>(module);
-
- if (slot >= kMaxNumSlots || slot >= bootctrl_module->num_slots) {
- // Invalid slot number.
- return -1;
- }
-
- bootloader_control bootctrl;
- if (!LoadBootloaderControl(bootctrl_module->misc_device, &bootctrl)) return -1;
-
- // The only way to mark a slot as unbootable, regardless of the priority is to
- // set the tries_remaining to 0.
- bootctrl.slot_info[slot].successful_boot = 0;
- bootctrl.slot_info[slot].tries_remaining = 0;
- if (!UpdateAndSaveBootloaderControl(bootctrl_module->misc_device, &bootctrl)) return -1;
- return 0;
-}
-
-int BootControl_isSlotBootable(struct boot_control_module* module, unsigned int slot) {
- boot_control_private_t* const bootctrl_module = reinterpret_cast<boot_control_private_t*>(module);
-
- if (slot >= kMaxNumSlots || slot >= bootctrl_module->num_slots) {
- // Invalid slot number.
- return -1;
- }
-
- bootloader_control bootctrl;
- if (!LoadBootloaderControl(bootctrl_module->misc_device, &bootctrl)) return -1;
-
- return bootctrl.slot_info[slot].tries_remaining;
-}
-
-int BootControl_isSlotMarkedSuccessful(struct boot_control_module* module, unsigned int slot) {
- boot_control_private_t* const bootctrl_module = reinterpret_cast<boot_control_private_t*>(module);
-
- if (slot >= kMaxNumSlots || slot >= bootctrl_module->num_slots) {
- // Invalid slot number.
- return -1;
- }
-
- bootloader_control bootctrl;
- if (!LoadBootloaderControl(bootctrl_module->misc_device, &bootctrl)) return -1;
-
- return bootctrl.slot_info[slot].successful_boot && bootctrl.slot_info[slot].tries_remaining;
-}
-
-const char* BootControl_getSuffix(boot_control_module_t* module, unsigned int slot) {
- if (slot >= kMaxNumSlots || slot >= reinterpret_cast<boot_control_private_t*>(module)->num_slots) {
- return NULL;
- }
- return kSlotSuffixes[slot];
-}
-
-static int BootControl_open(const hw_module_t* module __unused, const char* id __unused,
- hw_device_t** device __unused) {
- /* Nothing to do currently. */
- return 0;
-}
-
-struct hw_module_methods_t BootControl_methods = {
- .open = BootControl_open,
-};
-
-} // namespace
-
-boot_control_private_t HAL_MODULE_INFO_SYM = {
- .base =
- {
- .common =
- {
- .tag = HARDWARE_MODULE_TAG,
- .module_api_version = BOOT_CONTROL_MODULE_API_VERSION_0_1,
- .hal_api_version = HARDWARE_HAL_API_VERSION,
- .id = BOOT_CONTROL_HARDWARE_MODULE_ID,
- .name = "AOSP reference bootctrl HAL",
- .author = "The Android Open Source Project",
- .methods = &BootControl_methods,
- },
- .init = BootControl_init,
- .getNumberSlots = BootControl_getNumberSlots,
- .getCurrentSlot = BootControl_getCurrentSlot,
- .markBootSuccessful = BootControl_markBootSuccessful,
- .setActiveBootSlot = BootControl_setActiveBootSlot,
- .setSlotAsUnbootable = BootControl_setSlotAsUnbootable,
- .isSlotBootable = BootControl_isSlotBootable,
- .getSuffix = BootControl_getSuffix,
- .isSlotMarkedSuccessful = BootControl_isSlotMarkedSuccessful,
- },
- .initialized = false,
- .misc_device = nullptr,
- .num_slots = 0,
- .current_slot = 0,
-};
diff --git a/bootloader_message/Android.bp b/bootloader_message/Android.bp
index 450dad0..6443a07 100644
--- a/bootloader_message/Android.bp
+++ b/bootloader_message/Android.bp
@@ -36,6 +36,18 @@
"libbootloader_message_defaults",
],
recovery_available: true,
+ host_supported: true,
+
+ target: {
+ host: {
+ shared_libs: [
+ "libcutils", // for strlcpy
+ ],
+ },
+ darwin: {
+ enabled: false,
+ },
+ }
}
cc_library_static {
@@ -44,4 +56,5 @@
"libbootloader_message_defaults",
],
vendor: true,
+ recovery_available: true,
}
diff --git a/bootloader_message/bootloader_message.cpp b/bootloader_message/bootloader_message.cpp
index c1ebeaa..b70d54e 100755
--- a/bootloader_message/bootloader_message.cpp
+++ b/bootloader_message/bootloader_message.cpp
@@ -20,6 +20,7 @@
#include <fcntl.h>
#include <string.h>
+#include <optional>
#include <string>
#include <string_view>
#include <vector>
@@ -30,19 +31,23 @@
#include <android-base/unique_fd.h>
#include <fstab/fstab.h>
+#ifndef __ANDROID__
+#include <cutils/memory.h> // for strlcpy
+#endif
+
using android::fs_mgr::Fstab;
using android::fs_mgr::ReadDefaultFstab;
-static std::string g_misc_device_for_test;
+static std::optional<std::string> g_misc_device_for_test;
// Exposed for test purpose.
void SetMiscBlockDeviceForTest(std::string_view misc_device) {
g_misc_device_for_test = misc_device;
}
-static std::string get_misc_blk_device(std::string* err) {
- if (!g_misc_device_for_test.empty()) {
- return g_misc_device_for_test;
+std::string get_misc_blk_device(std::string* err) {
+ if (g_misc_device_for_test.has_value() && !g_misc_device_for_test->empty()) {
+ return *g_misc_device_for_test;
}
Fstab fstab;
if (!ReadDefaultFstab(&fstab)) {
@@ -106,8 +111,8 @@
return true;
}
-static bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
- size_t offset, std::string* err) {
+bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
+ size_t offset, std::string* err) {
android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY));
if (fd == -1) {
*err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
@@ -179,6 +184,14 @@
return write_bootloader_message(boot, err);
}
+bool write_bootloader_message_to(const std::vector<std::string>& options,
+ const std::string& misc_blk_device, std::string* err) {
+ bootloader_message boot = {};
+ update_bootloader_message_in_struct(&boot, options);
+
+ return write_bootloader_message_to(boot, misc_blk_device, err);
+}
+
bool update_bootloader_message(const std::vector<std::string>& options, std::string* err) {
bootloader_message boot;
if (!read_bootloader_message(&boot, err)) {
@@ -197,13 +210,15 @@
memset(boot->recovery, 0, sizeof(boot->recovery));
strlcpy(boot->command, "boot-recovery", sizeof(boot->command));
- strlcpy(boot->recovery, "recovery\n", sizeof(boot->recovery));
+
+ std::string recovery = "recovery\n";
for (const auto& s : options) {
- strlcat(boot->recovery, s.c_str(), sizeof(boot->recovery));
+ recovery += s;
if (s.back() != '\n') {
- strlcat(boot->recovery, "\n", sizeof(boot->recovery));
+ recovery += '\n';
}
}
+ strlcpy(boot->recovery, recovery.c_str(), sizeof(boot->recovery));
return true;
}
@@ -235,41 +250,60 @@
if (misc_blk_device.empty()) {
return false;
}
+ static constexpr size_t kMaximumWipePackageSize =
+ SYSTEM_SPACE_OFFSET_IN_MISC - WIPE_PACKAGE_OFFSET_IN_MISC;
+ if (package_data.size() > kMaximumWipePackageSize) {
+ *err = "Wipe package size " + std::to_string(package_data.size()) + " exceeds " +
+ std::to_string(kMaximumWipePackageSize) + " bytes";
+ return false;
+ }
return write_misc_partition(package_data.data(), package_data.size(), misc_blk_device,
WIPE_PACKAGE_OFFSET_IN_MISC, err);
}
-static bool OffsetAndSizeInVendorSpace(size_t offset, size_t size) {
- auto total_size = WIPE_PACKAGE_OFFSET_IN_MISC - VENDOR_SPACE_OFFSET_IN_MISC;
- return size <= total_size && offset <= total_size - size;
+static bool ValidateSystemSpaceRegion(size_t offset, size_t size, std::string* err) {
+ if (size <= SYSTEM_SPACE_SIZE_IN_MISC && offset <= (SYSTEM_SPACE_SIZE_IN_MISC - size)) {
+ return true;
+ }
+ *err = android::base::StringPrintf("Out of bound access (offset %zu size %zu)", offset, size);
+ return false;
}
-bool ReadMiscPartitionVendorSpace(void* data, size_t size, size_t offset, std::string* err) {
- if (!OffsetAndSizeInVendorSpace(offset, size)) {
- *err = android::base::StringPrintf("Out of bound read (offset %zu size %zu)", offset, size);
+static bool ReadMiscPartitionSystemSpace(void* data, size_t size, size_t offset, std::string* err) {
+ if (!ValidateSystemSpaceRegion(offset, size, err)) {
return false;
}
auto misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
return false;
}
- return read_misc_partition(data, size, misc_blk_device, VENDOR_SPACE_OFFSET_IN_MISC + offset,
+ return read_misc_partition(data, size, misc_blk_device, SYSTEM_SPACE_OFFSET_IN_MISC + offset,
err);
}
-bool WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset, std::string* err) {
- if (!OffsetAndSizeInVendorSpace(offset, size)) {
- *err = android::base::StringPrintf("Out of bound write (offset %zu size %zu)", offset, size);
+static bool WriteMiscPartitionSystemSpace(const void* data, size_t size, size_t offset,
+ std::string* err) {
+ if (!ValidateSystemSpaceRegion(offset, size, err)) {
return false;
}
auto misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
return false;
}
- return write_misc_partition(data, size, misc_blk_device, VENDOR_SPACE_OFFSET_IN_MISC + offset,
+ return write_misc_partition(data, size, misc_blk_device, SYSTEM_SPACE_OFFSET_IN_MISC + offset,
err);
}
+bool ReadMiscVirtualAbMessage(misc_virtual_ab_message* message, std::string* err) {
+ return ReadMiscPartitionSystemSpace(message, sizeof(*message),
+ offsetof(misc_system_space_layout, virtual_ab_message), err);
+}
+
+bool WriteMiscVirtualAbMessage(const misc_virtual_ab_message& message, std::string* err) {
+ return WriteMiscPartitionSystemSpace(&message, sizeof(message),
+ offsetof(misc_system_space_layout, virtual_ab_message), err);
+}
+
extern "C" bool write_reboot_bootloader(void) {
std::string err;
return write_reboot_bootloader(&err);
diff --git a/bootloader_message/include/bootloader_message/bootloader_message.h b/bootloader_message/include/bootloader_message/bootloader_message.h
index 95dd8f4..e4cf09b 100644
--- a/bootloader_message/include/bootloader_message/bootloader_message.h
+++ b/bootloader_message/include/bootloader_message/bootloader_message.h
@@ -25,12 +25,15 @@
// 0 - 2K For bootloader_message
// 2K - 16K Used by Vendor's bootloader (the 2K - 4K range may be optionally used
// as bootloader_message_ab struct)
-// 16K - 64K Used by uncrypt and recovery to store wipe_package for A/B devices
+// 16K - 32K Used by uncrypt and recovery to store wipe_package for A/B devices
+// 32K - 64K System space, used for miscellanious AOSP features. See below.
// Note that these offsets are admitted by bootloader,recovery and uncrypt, so they
// are not configurable without changing all of them.
constexpr size_t BOOTLOADER_MESSAGE_OFFSET_IN_MISC = 0;
constexpr size_t VENDOR_SPACE_OFFSET_IN_MISC = 2 * 1024;
constexpr size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024;
+constexpr size_t SYSTEM_SPACE_OFFSET_IN_MISC = 32 * 1024;
+constexpr size_t SYSTEM_SPACE_SIZE_IN_MISC = 32 * 1024;
/* Bootloader Message (2-KiB)
*
@@ -80,116 +83,47 @@
char reserved[1184];
};
-/**
- * We must be cautious when changing the bootloader_message struct size,
- * because A/B-specific fields may end up with different offsets.
- */
-#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
-static_assert(sizeof(struct bootloader_message) == 2048,
- "struct bootloader_message size changes, which may break A/B devices");
-#endif
-
-/**
- * The A/B-specific bootloader message structure (4-KiB).
- *
- * We separate A/B boot control metadata from the regular bootloader
- * message struct and keep it here. Everything that's A/B-specific
- * stays after struct bootloader_message, which should be managed by
- * the A/B-bootloader or boot control HAL.
- *
- * The slot_suffix field is used for A/B implementations where the
- * bootloader does not set the androidboot.ro.boot.slot_suffix kernel
- * commandline parameter. This is used by fs_mgr to mount /system and
- * other partitions with the slotselect flag set in fstab. A/B
- * implementations are free to use all 32 bytes and may store private
- * data past the first NUL-byte in this field. It is encouraged, but
- * not mandatory, to use 'struct bootloader_control' described below.
- *
- * The update_channel field is used to store the Omaha update channel
- * if update_engine is compiled with Omaha support.
- */
-struct bootloader_message_ab {
- struct bootloader_message message;
- char slot_suffix[32];
- char update_channel[128];
-
- // Round up the entire struct to 4096-byte.
- char reserved[1888];
-};
-
-/**
- * Be cautious about the struct size change, in case we put anything post
- * bootloader_message_ab struct (b/29159185).
- */
-#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
-static_assert(sizeof(struct bootloader_message_ab) == 4096,
- "struct bootloader_message_ab size changes");
-#endif
-
-#define BOOT_CTRL_MAGIC 0x42414342 /* Bootloader Control AB */
-#define BOOT_CTRL_VERSION 1
-
-struct slot_metadata {
- // Slot priority with 15 meaning highest priority, 1 lowest
- // priority and 0 the slot is unbootable.
- uint8_t priority : 4;
- // Number of times left attempting to boot this slot.
- uint8_t tries_remaining : 3;
- // 1 if this slot has booted successfully, 0 otherwise.
- uint8_t successful_boot : 1;
- // 1 if this slot is corrupted from a dm-verity corruption, 0
- // otherwise.
- uint8_t verity_corrupted : 1;
- // Reserved for further use.
- uint8_t reserved : 7;
+// Holds Virtual A/B merge status information. Current version is 1. New fields
+// must be added to the end.
+struct misc_virtual_ab_message {
+ uint8_t version;
+ uint32_t magic;
+ uint8_t merge_status; // IBootControl 1.1, MergeStatus enum.
+ uint8_t source_slot; // Slot number when merge_status was written.
+ uint8_t reserved[57];
} __attribute__((packed));
-/* Bootloader Control AB
- *
- * This struct can be used to manage A/B metadata. It is designed to
- * be put in the 'slot_suffix' field of the 'bootloader_message'
- * structure described above. It is encouraged to use the
- * 'bootloader_control' structure to store the A/B metadata, but not
- * mandatory.
- */
-struct bootloader_control {
- // NUL terminated active slot suffix.
- char slot_suffix[4];
- // Bootloader Control AB magic number (see BOOT_CTRL_MAGIC).
- uint32_t magic;
- // Version of struct being used (see BOOT_CTRL_VERSION).
- uint8_t version;
- // Number of slots being managed.
- uint8_t nb_slot : 3;
- // Number of times left attempting to boot recovery.
- uint8_t recovery_tries_remaining : 3;
- // Ensure 4-bytes alignment for slot_info field.
- uint8_t reserved0[2];
- // Per-slot information. Up to 4 slots.
- struct slot_metadata slot_info[4];
- // Reserved for further use.
- uint8_t reserved1[8];
- // CRC32 of all 28 bytes preceding this field (little endian
- // format).
- uint32_t crc32_le;
-} __attribute__((packed));
+#define MISC_VIRTUAL_AB_MESSAGE_VERSION 2
+#define MISC_VIRTUAL_AB_MAGIC_HEADER 0x56740AB0
#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
-static_assert(sizeof(struct bootloader_control) ==
- sizeof(((struct bootloader_message_ab *)0)->slot_suffix),
- "struct bootloader_control has wrong size");
+static_assert(sizeof(struct misc_virtual_ab_message) == 64,
+ "struct misc_virtual_ab_message has wrong size");
#endif
+// This struct is not meant to be used directly, rather, it is to make
+// computation of offsets easier. New fields must be added to the end.
+struct misc_system_space_layout {
+ misc_virtual_ab_message virtual_ab_message;
+} __attribute__((packed));
+
#ifdef __cplusplus
#include <string>
#include <vector>
+// Gets the block device name of /misc partition.
+std::string get_misc_blk_device(std::string* err);
// Return the block device name for the bootloader message partition and waits
// for the device for up to 10 seconds. In case of error returns the empty
// string.
std::string get_bootloader_message_blk_device(std::string* err);
+// Writes |size| bytes of data from buffer |p| to |misc_blk_device| at |offset|. If the write fails,
+// sets the error message in |err|.
+bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
+ size_t offset, std::string* err);
+
// Read bootloader message into boot. Error message will be set in err.
bool read_bootloader_message(bootloader_message* boot, std::string* err);
@@ -208,6 +142,11 @@
// set the command and recovery fields, and reset the rest.
bool write_bootloader_message(const std::vector<std::string>& options, std::string* err);
+// Write bootloader message (boots into recovery with the options) to the specific BCB device. Will
+// set the command and recovery fields, and reset the rest.
+bool write_bootloader_message_to(const std::vector<std::string>& options,
+ const std::string& misc_blk_device, std::string* err);
+
// Update bootloader message (boots into recovery with the options) to BCB. Will
// only update the command and recovery fields.
bool update_bootloader_message(const std::vector<std::string>& options, std::string* err);
@@ -229,13 +168,9 @@
// Write the wipe package into BCB (to offset WIPE_PACKAGE_OFFSET_IN_MISC).
bool write_wipe_package(const std::string& package_data, std::string* err);
-// Reads data from the vendor space in /misc partition, with the given offset and size. Note that
-// offset is in relative to the start of vendor space.
-bool ReadMiscPartitionVendorSpace(void* data, size_t size, size_t offset, std::string* err);
-
-// Writes the given data to the vendor space in /misc partition, at the given offset. Note that
-// offset is in relative to the start of the vendor space.
-bool WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset, std::string* err);
+// Read or write the Virtual A/B message from system space in /misc.
+bool ReadMiscVirtualAbMessage(misc_virtual_ab_message* message, std::string* err);
+bool WriteMiscVirtualAbMessage(const misc_virtual_ab_message& message, std::string* err);
#else
diff --git a/crypto/fscrypt/Decrypt.cpp b/crypto/fscrypt/Decrypt.cpp
index 1e62ce2..ef46535 100755
--- a/crypto/fscrypt/Decrypt.cpp
+++ b/crypto/fscrypt/Decrypt.cpp
@@ -68,7 +68,7 @@
#include <keystore/keystore_promises.h>
#include <keystore/keystore_return_types.h>
#include <keystore/keymaster_types.h>
-#include <keymasterV4_0/Keymaster.h>
+#include <keymasterV4_1/Keymaster.h>
#include <keystore/OperationResult.h>
#include "keystore_client.pb.h"
@@ -87,6 +87,7 @@
using keystore::KeystoreResponsePromise;
using keystore::OperationResultPromise;
using android::security::keymaster::OperationResult;
+using android::hardware::keymaster::V4_0::support::blob2hidlVec;
// Store main DE raw ref / policy
extern std::string de_raw_ref;
@@ -716,8 +717,11 @@
future = {};
promise = new OperationResultPromise();
future = promise->get_future();
+ std::tie(rc, keyBlob, charBlob, lockedEntry) = mKeyStore->getKeyForName(name8, callingUid, TYPE_KEYMASTER_10);
+
+ auto hidlInput = blob2hidlVec(input_data);
::keystore::hidl_vec<uint8_t> signature;
- binder_result = service->finish(promise, handle, empty_params, signature, entropy, &error_code);
+ binder_result = service->finish(promise, handle, empty_params, hidlInput, signature, entropy, &error_code);
if (!binder_result.isOk()) {
printf("communication error while calling keystore\n");
free(keystore_result);
diff --git a/crypto/fscrypt/Keymaster.h b/crypto/fscrypt/Keymaster.h
index 7d4d9c9..429a0a6 100644
--- a/crypto/fscrypt/Keymaster.h
+++ b/crypto/fscrypt/Keymaster.h
@@ -24,13 +24,13 @@
#include <utility>
#include <android-base/macros.h>
-#include <keymasterV4_0/Keymaster.h>
+#include <keymasterV4_1/Keymaster.h>
#include <keymasterV4_0/authorization_set.h>
namespace android {
namespace vold {
-namespace km = ::android::hardware::keymaster::V4_0;
+namespace km = ::android::hardware::keymaster::V4_1;
using KmDevice = km::support::Keymaster;
// C++ wrappers to the Keymaster hidl interface.
diff --git a/crypto/fscrypt/fscryptpolicyget.cpp b/crypto/fscrypt/fscryptpolicyget.cpp
index 5add616..fae06f8 100755
--- a/crypto/fscrypt/fscryptpolicyget.cpp
+++ b/crypto/fscrypt/fscryptpolicyget.cpp
@@ -19,8 +19,6 @@
#include <string.h>
#include "fscrypt_policy.h"
-#define FS_KEY_DESCRIPTOR_SIZE 8
-
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Must specify a path\n");
diff --git a/crypto/scrypt/Android.bp b/crypto/scrypt/Android.bp
new file mode 100755
index 0000000..2a3f025
--- /dev/null
+++ b/crypto/scrypt/Android.bp
@@ -0,0 +1,6 @@
+build = ["sources.bp"]
+
+cc_library_static {
+ name: "libscrypttwrp_static",
+ include_dirs: ["bootable/recovery/crypto/scrypt/lib/util"]
+}
\ No newline at end of file
diff --git a/crypto/scrypt/Scrypt.mk b/crypto/scrypt/Scrypt.mk
index 67e73c8..bf50cc0 100644
--- a/crypto/scrypt/Scrypt.mk
+++ b/crypto/scrypt/Scrypt.mk
@@ -5,50 +5,3 @@
local_additional_dependencies := $(LOCAL_PATH)/android-config.mk $(LOCAL_PATH)/Scrypt.mk
include $(LOCAL_PATH)/Scrypt-config.mk
-
-#######################################
-# target static library
-include $(CLEAR_VARS)
-include $(LOCAL_PATH)/android-config.mk
-
-LOCAL_SHARED_LIBRARIES := $(log_shared_libraries)
-
-# If we're building an unbundled build, don't try to use clang since it's not
-# in the NDK yet. This can be removed when a clang version that is fast enough
-# in the NDK.
-ifeq (,$(TARGET_BUILD_APPS))
-LOCAL_CLANG := true
-else
-LOCAL_SDK_VERSION := 9
-endif
-
-LOCAL_SRC_FILES += $(target_src_files)
-LOCAL_CFLAGS += $(target_c_flags)
-LOCAL_C_INCLUDES += $(target_c_includes) $(commands_recovery_local_path)/crypto/scrypt/lib/util
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE:= libscrypttwrp_static
-ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 28; echo $$?),0)
- LOCAL_REQUIRED_MODULES := $(local_additional_dependencies)
-else
- LOCAL_ADDITIONAL_DEPENDENCIES := $(local_additional_dependencies)
-endif
-include $(BUILD_STATIC_LIBRARY)
-
-########################################
-# host static library
-
-include $(CLEAR_VARS)
-include $(LOCAL_PATH)/android-config.mk
-LOCAL_SHARED_LIBRARIES := $(log_shared_libraries)
-LOCAL_SRC_FILES += $(host_src_files)
-LOCAL_CFLAGS += $(host_c_flags)
-LOCAL_C_INCLUDES += $(host_c_includes) $(commands_recovery_local_path)/crypto/scrypt/lib/util
-LOCAL_LDLIBS += -ldl
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE:= libscrypttwrp_static
-ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 28; echo $$?),0)
- LOCAL_REQUIRED_MODULES := $(local_additional_dependencies)
-else
- LOCAL_ADDITIONAL_DEPENDENCIES := $(local_additional_dependencies)
-endif
-include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/crypto/scrypt/sources.bp b/crypto/scrypt/sources.bp
new file mode 100644
index 0000000..d21344f
--- /dev/null
+++ b/crypto/scrypt/sources.bp
@@ -0,0 +1,82 @@
+// Auto-generated - DO NOT EDIT!
+// To regenerate, edit scrypt.config, then run:
+// ./import_scrypt.sh import /path/to/scrypt-1.1.6.tar.gz
+//
+
+//
+// Copyright (C) 2017 The Android Open Source 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_defaults {
+ name: "libscrypttwrp_sources",
+
+ cflags: [
+ "-DHAVE_CONFIG_H",
+ "-DUSE_OPENSSL_PBKDF2",
+ "-Wall",
+ "-Werror",
+ "-Wno-implicit-function-declaration",
+ "-Wno-unused-variable",
+ ],
+
+ export_include_dirs: [
+ "lib/crypto",
+ ],
+
+ local_include_dirs: [
+ "lib/util",
+ ],
+
+ srcs: [
+ "lib/crypto/crypto_scrypt-ref.c",
+ ],
+
+ arch: {
+ arm: {
+ neon: {
+ srcs: [
+ "lib/crypto/crypto_scrypt-neon.c",
+ ],
+ exclude_srcs: [
+ "lib/crypto/crypto_scrypt-ref.c",
+ ],
+ },
+ },
+ arm64: {
+ srcs: [
+ "lib/crypto/crypto_scrypt-neon.c",
+ ],
+ exclude_srcs: [
+ "lib/crypto/crypto_scrypt-ref.c",
+ ],
+ },
+ x86: {
+ srcs: [
+ "lib/crypto/crypto_scrypt-sse.c",
+ ],
+ exclude_srcs: [
+ "lib/crypto/crypto_scrypt-ref.c",
+ ],
+ },
+ x86_64: {
+ srcs: [
+ "lib/crypto/crypto_scrypt-sse.c",
+ ],
+ exclude_srcs: [
+ "lib/crypto/crypto_scrypt-ref.c",
+ ],
+ },
+ },
+}
diff --git a/edify/Android.bp b/edify/Android.bp
index 42947eb..0ab53d6 100644
--- a/edify/Android.bp
+++ b/edify/Android.bp
@@ -16,6 +16,8 @@
name: "libedify",
host_supported: true,
+ vendor_available: true,
+ recovery_available: true,
srcs: [
"expr.cpp",
diff --git a/edify/expr.cpp b/edify/expr.cpp
index c090eb2..e5e0e24 100644
--- a/edify/expr.cpp
+++ b/edify/expr.cpp
@@ -421,5 +421,5 @@
return nullptr;
}
-State::State(const std::string& script, void* cookie)
- : script(script), cookie(cookie), error_code(kNoError), cause_code(kNoCause) {}
+State::State(const std::string& script, UpdaterInterface* interface)
+ : script(script), updater(interface), error_code(kNoError), cause_code(kNoCause) {}
diff --git a/edify/include/edify/expr.h b/edify/include/edify/expr.h
index 5cbd5e1..cd9c701 100644
--- a/edify/include/edify/expr.h
+++ b/edify/include/edify/expr.h
@@ -23,19 +23,20 @@
#include <string>
#include <vector>
+#include "edify/updater_interface.h"
+
// Forward declaration to avoid including "otautil/error_code.h".
enum ErrorCode : int;
enum CauseCode : int;
struct State {
- State(const std::string& script, void* cookie);
+ State(const std::string& script, UpdaterInterface* cookie);
// The source of the original script.
const std::string& script;
- // Optional pointer to app-specific data; the core of edify never
- // uses this value.
- void* cookie;
+ // A pointer to app-specific data; the libedify doesn't use this value.
+ UpdaterInterface* updater;
// The error message (if any) returned if the evaluation aborts.
// Should be empty initially, will be either empty or a string that
diff --git a/edify/include/edify/updater_interface.h b/edify/include/edify/updater_interface.h
new file mode 100644
index 0000000..aa977e3
--- /dev/null
+++ b/edify/include/edify/updater_interface.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <string>
+#include <string_view>
+
+struct ZipArchive;
+typedef ZipArchive* ZipArchiveHandle;
+
+class UpdaterRuntimeInterface;
+
+class UpdaterInterface {
+ public:
+ virtual ~UpdaterInterface() = default;
+
+ // Writes the message to command pipe, adds a new line in the end.
+ virtual void WriteToCommandPipe(const std::string_view message, bool flush = false) const = 0;
+
+ // Sends over the message to recovery to print it on the screen.
+ virtual void UiPrint(const std::string_view message) const = 0;
+
+ // Given the name of the block device, returns |name| for updates on the device; or the file path
+ // to the fake block device for simulations.
+ virtual std::string FindBlockDeviceName(const std::string_view name) const = 0;
+
+ virtual UpdaterRuntimeInterface* GetRuntime() const = 0;
+ virtual ZipArchiveHandle GetPackageHandle() const = 0;
+ virtual std::string GetResult() const = 0;
+ virtual uint8_t* GetMappedPackageAddress() const = 0;
+ virtual size_t GetMappedPackageLength() const = 0;
+};
diff --git a/edify/include/edify/updater_runtime_interface.h b/edify/include/edify/updater_runtime_interface.h
new file mode 100644
index 0000000..bdd6aec
--- /dev/null
+++ b/edify/include/edify/updater_runtime_interface.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 The Android Open Source 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.
+ */
+
+#pragma once
+
+#include <string>
+#include <string_view>
+#include <vector>
+
+// This class serves as the base to updater runtime. It wraps the runtime dependent functions; and
+// updates on device and host simulations can have different implementations. e.g. block devices
+// during host simulation merely a temporary file. With this class, the caller side in registered
+// updater's functions will stay the same for both update and simulation.
+class UpdaterRuntimeInterface {
+ public:
+ virtual ~UpdaterRuntimeInterface() = default;
+
+ // Returns true if it's a runtime instance for simulation.
+ virtual bool IsSimulator() const = 0;
+
+ // Returns the value of system property |key|. If the property doesn't exist, returns
+ // |default_value|.
+ virtual std::string GetProperty(const std::string_view key,
+ const std::string_view default_value) const = 0;
+
+ // Given the name of the block device, returns |name| for updates on the device; or the file path
+ // to the fake block device for simulations.
+ virtual std::string FindBlockDeviceName(const std::string_view name) const = 0;
+
+ // Mounts the |location| on |mount_point|. Returns 0 on success.
+ virtual int Mount(const std::string_view location, const std::string_view mount_point,
+ const std::string_view fs_type, const std::string_view mount_options) = 0;
+
+ // Returns true if |mount_point| is mounted.
+ virtual bool IsMounted(const std::string_view mount_point) const = 0;
+
+ // Unmounts the |mount_point|. Returns a pair of results with the first value indicating
+ // if the |mount_point| is mounted, and the second value indicating the result of umount(2).
+ virtual std::pair<bool, int> Unmount(const std::string_view mount_point) = 0;
+
+ // Reads |filename| and puts its value to |content|.
+ virtual bool ReadFileToString(const std::string_view filename, std::string* content) const = 0;
+
+ // Updates the content of |filename| with |content|.
+ virtual bool WriteStringToFile(const std::string_view content,
+ const std::string_view filename) const = 0;
+
+ // Wipes the first |len| bytes of block device in |filename|.
+ virtual int WipeBlockDevice(const std::string_view filename, size_t len) const = 0;
+
+ // Starts a child process and runs the program with |args|. Uses vfork(2) if |is_vfork| is true.
+ virtual int RunProgram(const std::vector<std::string>& args, bool is_vfork) const = 0;
+
+ // Runs tune2fs with arguments |args|.
+ virtual int Tune2Fs(const std::vector<std::string>& args) const = 0;
+
+ // Dynamic partition related functions.
+ virtual bool MapPartitionOnDeviceMapper(const std::string& partition_name, std::string* path) = 0;
+ virtual bool UnmapPartitionOnDeviceMapper(const std::string& partition_name) = 0;
+ virtual bool UpdateDynamicPartitions(const std::string_view op_list_value) = 0;
+
+ // On devices supports A/B, add current slot suffix to arg. Otherwise, return |arg| as is.
+ virtual std::string AddSlotSuffix(const std::string_view arg) const = 0;
+};
diff --git a/edify/parser.yy b/edify/parser.yy
index 3a63c37..37bcdd0 100644
--- a/edify/parser.yy
+++ b/edify/parser.yy
@@ -72,7 +72,7 @@
%parse-param {std::unique_ptr<Expr>* root}
%parse-param {int* error_count}
-%error-verbose
+%define parse.error verbose
/* declarations in increasing order of precedence */
%left ';'
diff --git a/etc/Android.mk b/etc/Android.mk
index 26d86d6..58b45ad 100755
--- a/etc/Android.mk
+++ b/etc/Android.mk
@@ -19,7 +19,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := init.recovery.usb.rc
LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_CLASS := EXECUTABLES
# Cannot send to TARGET_RECOVERY_ROOT_OUT since build system wipes init*.rc
# during ramdisk creation and only allows init.recovery.*.rc files to be copied
@@ -34,7 +34,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := init.recovery.service.rc
LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
LOCAL_SRC_FILES := init.recovery.service22.rc
@@ -43,7 +43,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := init.recovery.hlthchrg.rc
LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
LOCAL_SRC_FILES := init.recovery.hlthchrg26.rc
@@ -52,7 +52,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := init.recovery.ldconfig.rc
LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
LOCAL_SRC_FILES := init.recovery.ldconfig.rc
@@ -62,7 +62,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := android.hardware.boot@1.0-service.rc
LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+ LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/etc/init
LOCAL_SRC_FILES := init/$(LOCAL_MODULE)
@@ -73,7 +73,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := android.hardware.health@2.0-service.rc
LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+ LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/etc/init
LOCAL_SRC_FILES := init/$(LOCAL_MODULE)
@@ -84,7 +84,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := hwservicemanager.rc
LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+ LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/etc/init
LOCAL_SRC_FILES := init/$(LOCAL_MODULE)
@@ -93,7 +93,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := vndservicemanager.rc
LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+ LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/etc/init
LOCAL_SRC_FILES := init/$(LOCAL_MODULE)
@@ -103,7 +103,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := servicemanager.rc
LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+ LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/etc/init
LOCAL_SRC_FILES := init/$(LOCAL_MODULE)
@@ -117,7 +117,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := init.recovery.logd.rc
LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+ LOCAL_MODULE_CLASS := EXECUTABLES
# Cannot send to TARGET_RECOVERY_ROOT_OUT since build system wipes init*.rc
# during ramdisk creation and only allows init.recovery.*.rc files to be copied
@@ -133,7 +133,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := init.recovery.mksh.rc
LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+ LOCAL_MODULE_CLASS := EXECUTABLES
# Cannot send to TARGET_RECOVERY_ROOT_OUT since build system wipes init*.rc
# during ramdisk creation and only allows init.recovery.*.rc files to be copied
diff --git a/etc/init.rc b/etc/init.rc
index 8542196..e63c74c 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -13,6 +13,10 @@
# ueventd wants to write to /acct
mount cgroup none /acct cpuacct
mkdir /acct/uid
+ # Copy prebuilt ld.config.txt into linkerconfig directory
+ copy /system/etc/ld.config.txt /linkerconfig/ld.config.txt
+ chmod 444 /linkerconfig/ld.config.txt
+
start ueventd
on init
@@ -53,18 +57,6 @@
class_start default
-# Load properties, pre-Android 6.0
-on load_all_props_action
- load_all_props
-
-# Load properties, Android 6.0+
-on load_system_props_action
- load_system_props
-
-# Load properties, Android 6.0+, vendor init lives here
-on load_persist_props_action
- load_persist_props
-
on firmware_mounts_complete
rm /dev/.booting
@@ -75,17 +67,6 @@
trigger post-fs
trigger post-fs-data
- # Load properties, pre-Android 6.0
- trigger load_all_props_action
-
- # Load properties from /system/ + /factory after fs mount. Place
- # this in another action so that the load will be scheduled after the prior
- # issued fs triggers have completed.
- trigger load_system_props_action
-
- # Load properties, Android 6.0+, vendor init lives here
- trigger load_persist_props_action
-
# Remove a file to wake up anything waiting for firmware
trigger firmware_mounts_complete
@@ -119,10 +100,6 @@
on property:service.adb.root=1
restart adbd
-# Always start adbd on userdebug and eng builds
-on fs && property:ro.debuggable=1
- setprop sys.usb.config adb
-
on fs && property:sys.usb.configfs=1
mount configfs none /config
mkdir /config/usb_gadget/g1 0770 shell shell
@@ -159,7 +136,7 @@
on property:sys.usb.config=none && property:sys.usb.configfs=0
stop adbd
- stop fastboot
+ stop fastbootd
write /sys/class/android_usb/android0/enable 0
setprop sys.usb.state ${sys.usb.config}
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 14f5e4b..a093008 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -30,10 +30,10 @@
#include "recovery_ui/ui.h"
static const std::vector<std::pair<std::string, Device::BuiltinAction>> kFastbootMenuActions{
- { "Reboot system now", Device::REBOOT },
+ { "Reboot system now", Device::REBOOT_FROM_FASTBOOT },
{ "Enter recovery", Device::ENTER_RECOVERY },
{ "Reboot to bootloader", Device::REBOOT_BOOTLOADER },
- { "Power off", Device::SHUTDOWN },
+ { "Power off", Device::SHUTDOWN_FROM_FASTBOOT },
};
Device::BuiltinAction StartFastboot(Device* device, const std::vector<std::string>& /* args */) {
@@ -52,6 +52,7 @@
ui->ResetKeyInterruptStatus();
ui->SetTitle(title_lines);
ui->ShowText(true);
+ device->StartFastboot();
// Reset to normal system boot so recovery won't cycle indefinitely.
// TODO(b/112277594) Clear only if 'recovery' field of BCB is empty. If not,
diff --git a/fsck_unshare_blocks.cpp b/fsck_unshare_blocks.cpp
deleted file mode 100644
index e74f8ba..0000000
--- a/fsck_unshare_blocks.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source 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 "fsck_unshare_blocks.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <spawn.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/unique_fd.h>
-#include <fstab/fstab.h>
-
-#include "otautil/roots.h"
-
-static constexpr const char* SYSTEM_E2FSCK_BIN = "/system/bin/e2fsck_static";
-static constexpr const char* TMP_E2FSCK_BIN = "/tmp/e2fsck.bin";
-
-static bool copy_file(const char* source, const char* dest) {
- android::base::unique_fd source_fd(open(source, O_RDONLY));
- if (source_fd < 0) {
- PLOG(ERROR) << "open %s failed" << source;
- return false;
- }
-
- android::base::unique_fd dest_fd(open(dest, O_CREAT | O_WRONLY, S_IRWXU));
- if (dest_fd < 0) {
- PLOG(ERROR) << "open %s failed" << dest;
- return false;
- }
-
- for (;;) {
- char buf[4096];
- ssize_t rv = read(source_fd, buf, sizeof(buf));
- if (rv < 0) {
- PLOG(ERROR) << "read failed";
- return false;
- }
- if (rv == 0) {
- break;
- }
- if (write(dest_fd, buf, rv) != rv) {
- PLOG(ERROR) << "write failed";
- return false;
- }
- }
- return true;
-}
-
-static bool run_e2fsck(const std::string& partition) {
- Volume* volume = volume_for_mount_point(partition);
- if (!volume) {
- LOG(INFO) << "No fstab entry for " << partition << ", skipping.";
- return true;
- }
-
- LOG(INFO) << "Running e2fsck on device " << volume->blk_device;
-
- std::vector<std::string> args = { TMP_E2FSCK_BIN, "-p", "-E", "unshare_blocks",
- volume->blk_device };
- std::vector<char*> argv(args.size());
- std::transform(args.cbegin(), args.cend(), argv.begin(),
- [](const std::string& arg) { return const_cast<char*>(arg.c_str()); });
- argv.push_back(nullptr);
-
- pid_t child;
- char* env[] = { nullptr };
- if (posix_spawn(&child, argv[0], nullptr, nullptr, argv.data(), env)) {
- PLOG(ERROR) << "posix_spawn failed";
- return false;
- }
-
- int status = 0;
- int ret = TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
- if (ret < 0) {
- PLOG(ERROR) << "waitpid failed";
- return false;
- }
- if (!WIFEXITED(status)) {
- LOG(ERROR) << "e2fsck exited abnormally: " << status;
- return false;
- }
- int return_code = WEXITSTATUS(status);
- if (return_code >= 8) {
- LOG(ERROR) << "e2fsck could not unshare blocks: " << return_code;
- return false;
- }
-
- LOG(INFO) << "Successfully unshared blocks on " << partition;
- return true;
-}
-
-bool do_fsck_unshare_blocks() {
- // List of partitions we will try to e2fsck -E unshare_blocks.
- std::vector<std::string> partitions = { "/odm", "/oem", "/product", "/vendor" };
-
- // Temporarily mount system so we can copy e2fsck_static.
- std::string system_root = get_system_root();
- bool mounted = ensure_path_mounted_at(system_root, "/mnt/system") != -1;
- partitions.push_back(system_root);
-
- if (!mounted) {
- LOG(ERROR) << "Failed to mount system image.";
- return false;
- }
- if (!copy_file(SYSTEM_E2FSCK_BIN, TMP_E2FSCK_BIN)) {
- LOG(ERROR) << "Could not copy e2fsck to /tmp.";
- return false;
- }
- if (umount("/mnt/system") < 0) {
- PLOG(ERROR) << "umount failed";
- return false;
- }
-
- bool ok = true;
- for (const auto& partition : partitions) {
- ok &= run_e2fsck(partition);
- }
-
- if (ok) {
- LOG(INFO) << "Finished running e2fsck.";
- } else {
- LOG(ERROR) << "Finished running e2fsck, but not all partitions succceeded.";
- }
- return ok;
-}
diff --git a/fsck_unshare_blocks.h b/fsck_unshare_blocks.h
deleted file mode 100644
index 9de8ef9..0000000
--- a/fsck_unshare_blocks.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source 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.
- */
-
-#ifndef _FILESYSTEM_CMDS_H
-#define _FILESYSTEM_CMDS_H
-
-bool do_fsck_unshare_blocks();
-
-#endif // _FILESYSTEM_CMDS_H
diff --git a/fuse_sideload/Android.bp b/fuse_sideload/Android.bp
index 8548548..9bf19eb 100644
--- a/fuse_sideload/Android.bp
+++ b/fuse_sideload/Android.bp
@@ -34,6 +34,10 @@
"include",
],
+ static_libs: [
+ "libotautil",
+ ],
+
shared_libs: [
"libbase",
"libcrypto",
diff --git a/fuse_sideload/fuse_provider.cpp b/fuse_sideload/fuse_provider.cpp
index 58786f5..8fa1b5c 100644
--- a/fuse_sideload/fuse_provider.cpp
+++ b/fuse_sideload/fuse_provider.cpp
@@ -27,8 +27,11 @@
#include <functional>
#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
#include "fuse_sideload.h"
+#include "otautil/sysutil.h"
FuseFileDataProvider::FuseFileDataProvider(const std::string& path, uint32_t block_size) {
struct stat sb;
@@ -46,6 +49,11 @@
fuse_block_size_ = block_size;
}
+std::unique_ptr<FuseDataProvider> FuseFileDataProvider::CreateFromFile(const std::string& path,
+ uint32_t block_size) {
+ return std::make_unique<FuseFileDataProvider>(path, block_size);
+}
+
bool FuseFileDataProvider::ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size,
uint32_t start_block) const {
uint64_t offset = static_cast<uint64_t>(start_block) * fuse_block_size_;
@@ -69,3 +77,79 @@
void FuseFileDataProvider::Close() {
fd_.reset();
}
+
+FuseBlockDataProvider::FuseBlockDataProvider(uint64_t file_size, uint32_t fuse_block_size,
+ android::base::unique_fd&& fd,
+ uint32_t source_block_size, RangeSet ranges)
+ : FuseDataProvider(file_size, fuse_block_size),
+ fd_(std::move(fd)),
+ source_block_size_(source_block_size),
+ ranges_(std::move(ranges)) {
+ // Make sure the offset is also aligned with the blocks on the block device when we call
+ // ReadBlockAlignedData().
+ CHECK_EQ(0, fuse_block_size_ % source_block_size_);
+}
+
+bool FuseBlockDataProvider::ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size,
+ uint32_t start_block) const {
+ uint64_t offset = static_cast<uint64_t>(start_block) * fuse_block_size_;
+ if (fetch_size > file_size_ || offset > file_size_ - fetch_size) {
+ LOG(ERROR) << "Out of bound read, offset: " << offset << ", fetch size: " << fetch_size
+ << ", file size " << file_size_;
+ return false;
+ }
+
+ auto read_ranges =
+ ranges_.GetSubRanges(offset / source_block_size_, fetch_size / source_block_size_);
+ if (!read_ranges) {
+ return false;
+ }
+
+ uint8_t* next_out = buffer;
+ for (const auto& [range_start, range_end] : read_ranges.value()) {
+ uint64_t bytes_start = static_cast<uint64_t>(range_start) * source_block_size_;
+ uint64_t bytes_to_read = static_cast<uint64_t>(range_end - range_start) * source_block_size_;
+ if (!android::base::ReadFullyAtOffset(fd_, next_out, bytes_to_read, bytes_start)) {
+ PLOG(ERROR) << "Failed to read " << bytes_to_read << " bytes at offset " << bytes_start;
+ return false;
+ }
+
+ next_out += bytes_to_read;
+ }
+
+ if (uint64_t tailing_bytes = fetch_size % source_block_size_; tailing_bytes != 0) {
+ // Calculate the offset to last partial block.
+ uint64_t tailing_offset =
+ read_ranges.value()
+ ? static_cast<uint64_t>((read_ranges->cend() - 1)->second) * source_block_size_
+ : static_cast<uint64_t>(start_block) * source_block_size_;
+ if (!android::base::ReadFullyAtOffset(fd_, next_out, tailing_bytes, tailing_offset)) {
+ PLOG(ERROR) << "Failed to read tailing " << tailing_bytes << " bytes at offset "
+ << tailing_offset;
+ return false;
+ }
+ }
+ return true;
+}
+
+std::unique_ptr<FuseDataProvider> FuseBlockDataProvider::CreateFromBlockMap(
+ const std::string& block_map_path, uint32_t fuse_block_size) {
+ auto block_map = BlockMapData::ParseBlockMapFile(block_map_path);
+ if (!block_map) {
+ return nullptr;
+ }
+
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(block_map.path().c_str(), O_RDONLY)));
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open " << block_map.path();
+ return nullptr;
+ }
+
+ return std::unique_ptr<FuseBlockDataProvider>(
+ new FuseBlockDataProvider(block_map.file_size(), fuse_block_size, std::move(fd),
+ block_map.block_size(), block_map.block_ranges()));
+}
+
+void FuseBlockDataProvider::Close() {
+ fd_.reset();
+}
diff --git a/fuse_sideload/include/fuse_provider.h b/fuse_sideload/include/fuse_provider.h
index 59059cf..3cdaef3 100644
--- a/fuse_sideload/include/fuse_provider.h
+++ b/fuse_sideload/include/fuse_provider.h
@@ -18,10 +18,13 @@
#include <stdint.h>
+#include <memory>
#include <string>
#include <android-base/unique_fd.h>
+#include "otautil/rangeset.h"
+
// This is the base class to read data from source and provide the data to FUSE.
class FuseDataProvider {
public:
@@ -41,6 +44,8 @@
virtual bool ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size,
uint32_t start_block) const = 0;
+ virtual bool Valid() const = 0;
+
virtual void Close() {}
protected:
@@ -57,10 +62,13 @@
public:
FuseFileDataProvider(const std::string& path, uint32_t block_size);
+ static std::unique_ptr<FuseDataProvider> CreateFromFile(const std::string& path,
+ uint32_t block_size);
+
bool ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size,
uint32_t start_block) const override;
- bool Valid() const {
+ bool Valid() const override {
return fd_ != -1;
}
@@ -70,3 +78,34 @@
// The underlying source to read data from.
android::base::unique_fd fd_;
};
+
+// This class parses a block map and reads data from the underlying block device.
+class FuseBlockDataProvider : public FuseDataProvider {
+ public:
+ // Constructs the fuse provider from the block map.
+ static std::unique_ptr<FuseDataProvider> CreateFromBlockMap(const std::string& block_map_path,
+ uint32_t fuse_block_size);
+
+ RangeSet ranges() const {
+ return ranges_;
+ }
+
+ bool ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size,
+ uint32_t start_block) const override;
+
+ bool Valid() const override {
+ return fd_ != -1;
+ }
+
+ void Close() override;
+
+ private:
+ FuseBlockDataProvider(uint64_t file_size, uint32_t fuse_block_size, android::base::unique_fd&& fd,
+ uint32_t source_block_size, RangeSet ranges);
+ // The underlying block device to read data from.
+ android::base::unique_fd fd_;
+ // The block size of the source block device.
+ uint32_t source_block_size_;
+ // The block ranges from the source block device that consist of the file
+ RangeSet ranges_;
+};
diff --git a/gui/Android.bp b/gui/Android.bp
new file mode 100644
index 0000000..94d429b
--- /dev/null
+++ b/gui/Android.bp
@@ -0,0 +1,83 @@
+bootstrap_go_package {
+ name: "soong-libguitwrp_defaults",
+ pkgPath: "bootable/recovery/gui",
+ deps: [
+ "soong",
+ "soong-android",
+ "soong-cc"
+ ],
+ srcs: [
+ "libguitwrp_defaults.go"
+ ],
+ pluginFor: ["soong_build"]
+}
+
+libguitwrp_defaults {
+ name: "libguitwrp_defaults"
+}
+
+cc_library_static {
+ name: "libguitwrp",
+ defaults: ["libguitwrp_defaults"],
+ cflags: [
+ "-fno-strict-aliasing",
+ "-Wno-implicit-fallthrough",
+ "-D_USE_SYSTEM_ZIPARCHIVE"
+ ],
+ include_dirs: [
+ "bootable/recovery/crypto/scrypt/lib/util",
+ "bootable/recovery/otautil/include",
+ "bootable/recovery/install/include",
+ "system/core/libziparchive/include",
+ "bootable/recovery/recovery_ui/include",
+ "bootable/recovery/fuse_sideload/include",
+ "bootable/recovery/twrpinstall",
+ "bootable/recovery/twrpinstall/include",
+ "bionic",
+ "system/core/base/include",
+ "system/core/include",
+ "system/core/libpixelflinger/include",
+ "external/freetype/include"
+
+ ],
+ srcs: [
+ "gui.cpp",
+ "resources.cpp",
+ "pages.cpp",
+ "text.cpp",
+ "image.cpp",
+ "action.cpp",
+ "console.cpp",
+ "fill.cpp",
+ "button.cpp",
+ "checkbox.cpp",
+ "fileselector.cpp",
+ "progressbar.cpp",
+ "animation.cpp",
+ "object.cpp",
+ "slider.cpp",
+ "slidervalue.cpp",
+ "listbox.cpp",
+ "keyboard.cpp",
+ "input.cpp",
+ "blanktimer.cpp",
+ "partitionlist.cpp",
+ "mousecursor.cpp",
+ "scrolllist.cpp",
+ "patternpassword.cpp",
+ "textbox.cpp",
+ "terminal.cpp",
+ "twmsg.cpp"
+ ],
+ shared_libs: [
+ "libminuitwrp",
+ "libc",
+ "libstdc++",
+ "libaosprecovery",
+ "libselinux",
+ "libziparchive"
+ ],
+ static_libs: [
+ "libotautil"
+ ]
+}
\ No newline at end of file
diff --git a/gui/Android.mk b/gui/Android.mk
index b49b94d..450748d 100755
--- a/gui/Android.mk
+++ b/gui/Android.mk
@@ -1,140 +1,10 @@
LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CFLAGS := -fno-strict-aliasing -Wno-implicit-fallthrough
-
-LOCAL_SRC_FILES := \
- gui.cpp \
- resources.cpp \
- pages.cpp \
- text.cpp \
- image.cpp \
- action.cpp \
- console.cpp \
- fill.cpp \
- button.cpp \
- checkbox.cpp \
- fileselector.cpp \
- progressbar.cpp \
- animation.cpp \
- object.cpp \
- slider.cpp \
- slidervalue.cpp \
- listbox.cpp \
- keyboard.cpp \
- input.cpp \
- blanktimer.cpp \
- partitionlist.cpp \
- mousecursor.cpp \
- scrolllist.cpp \
- patternpassword.cpp \
- textbox.cpp \
- terminal.cpp \
- twmsg.cpp
-
-ifneq ($(TW_DELAY_TOUCH_INIT_MS),)
- LOCAL_CFLAGS += -DTW_DELAY_TOUCH_INIT_MS=$(TW_DELAY_TOUCH_INIT_MS)
-endif
-
-ifneq ($(TWRP_CUSTOM_KEYBOARD),)
- LOCAL_SRC_FILES += $(TWRP_CUSTOM_KEYBOARD)
-else
- LOCAL_SRC_FILES += hardwarekeyboard.cpp
-endif
-
-LOCAL_SHARED_LIBRARIES += libminuitwrp libc libstdc++ libaosprecovery libselinux
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/../otautil/include
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/../twrpinstall/include
-ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0)
- LOCAL_SHARED_LIBRARIES += libziparchive
- LOCAL_STATIC_LIBRARIES += libotautil libtwrpinstall
- ifneq ($(TW_INCLUDE_CRYPTO),)
- LOCAL_C_INCLUDES += bootable/recovery/crypto/fscrypt
- endif
- ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 28; echo $$?),0)
- LOCAL_C_INCLUDES += $(LOCAL_PATH)/../install/include \
- system/core/libziparchive/include/ \
- $(LOCAL_PATH)/../recovery_ui/include \
- $(LOCAL_PATH)/../fuse_sideload/include
- LOCAL_CFLAGS += -D_USE_SYSTEM_ZIPARCHIVE
- else
- LOCAL_C_INCLUDES += $(LOCAL_PATH)/../install28/ \
- $(LOCAL_PATH)/../fuse_sideload28/
- LOCAL_CFLAGS += -DUSE_28_INSTALL -DUSE_OTAUTIL_ZIPARCHIVE
- endif
-else
- LOCAL_SHARED_LIBRARIES += libminzip
- LOCAL_CFLAGS += -DUSE_MINZIP
-endif
-ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
- ifeq ($(shell test $(PLATFORM_SDK_VERSION) -le 28; echo $$?),0)
- LOCAL_C_INCLUDES += system/extras/ext4_utils \
- system/extras/ext4_utils/include \
- $(LOCAL_PATH)/../crypto/ext4crypt
- LOCAL_SHARED_LIBRARIES += libext4_utils
- endif
-endif
-
-LOCAL_MODULE := libguitwrp
-
-#TWRP_EVENT_LOGGING := true
-ifeq ($(TWRP_EVENT_LOGGING), true)
- LOCAL_CFLAGS += -D_EVENT_LOGGING
-endif
-ifneq ($(TW_USE_KEY_CODE_TOUCH_SYNC),)
- LOCAL_CFLAGS += -DTW_USE_KEY_CODE_TOUCH_SYNC=$(TW_USE_KEY_CODE_TOUCH_SYNC)
-endif
-ifneq ($(TW_OZIP_DECRYPT_KEY),)
- LOCAL_CFLAGS += -DTW_OZIP_DECRYPT_KEY=\"$(TW_OZIP_DECRYPT_KEY)\"
-else
- LOCAL_CFLAGS += -DTW_OZIP_DECRYPT_KEY=0
-endif
-ifneq ($(TW_NO_SCREEN_BLANK),)
- LOCAL_CFLAGS += -DTW_NO_SCREEN_BLANK
-endif
-ifneq ($(TW_NO_SCREEN_TIMEOUT),)
- LOCAL_CFLAGS += -DTW_NO_SCREEN_TIMEOUT
-endif
-ifeq ($(TW_OEM_BUILD), true)
- LOCAL_CFLAGS += -DTW_OEM_BUILD
-endif
-ifneq ($(TW_X_OFFSET),)
- LOCAL_CFLAGS += -DTW_X_OFFSET=$(TW_X_OFFSET)
-endif
-ifneq ($(TW_Y_OFFSET),)
- LOCAL_CFLAGS += -DTW_Y_OFFSET=$(TW_Y_OFFSET)
-endif
-ifneq ($(TW_W_OFFSET),)
- LOCAL_CFLAGS += -DTW_W_OFFSET=$(TW_W_OFFSET)
-endif
-ifneq ($(TW_H_OFFSET),)
- LOCAL_CFLAGS += -DTW_H_OFFSET=$(TW_H_OFFSET)
-endif
-ifeq ($(TW_ROUND_SCREEN), true)
- LOCAL_CFLAGS += -DTW_ROUND_SCREEN
-endif
-
-LOCAL_C_INCLUDES += \
- bionic \
- system/core/base/include \
- system/core/include \
- system/core/libpixelflinger/include \
- external/freetype/include
-
-ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
- LOCAL_C_INCLUDES += external/stlport/stlport
- LOCAL_CFLAGS += -DUSE_FUSE_SIDELOAD22
-endif
-
-LOCAL_CFLAGS += -DTWRES=\"$(TWRES_PATH)\"
-
-include $(BUILD_STATIC_LIBRARY)
# Transfer in the resources for the device
include $(CLEAR_VARS)
LOCAL_MODULE := twrp
LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_CLASS := DATA
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)$(TWRES_PATH)
# The extra blank line before *** is intentional to ensure it ends up on its own line
@@ -228,5 +98,7 @@
cp -fr $(TWRP_THEME_LOC)/* $(TARGET_RECOVERY_ROOT_OUT)$(TWRES_PATH)
LOCAL_GENERATED_SOURCES := $(TWRP_RES_GEN)
-LOCAL_SRC_FILES := twrp $(TWRP_RES_GEN)
+#LOCAL_SRC_FILES := twrp
+LOCAL_SRC_FILES := $(TWRP_RES_GEN)
+$(warning LOCAL_SRC_FILES: $(LOCAL_SRC_FILES))
include $(BUILD_PREBUILT)
diff --git a/gui/action.cpp b/gui/action.cpp
index b0f0027..597bb61 100755
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -52,7 +52,7 @@
#include "../twcommon.h"
#include "../variables.h"
#include "cutils/properties.h"
-#include "install/adb_install.h"
+#include "twinstall/adb_install.h"
};
#include "set_metadata.h"
#include "../minuitwrp/minui.h"
diff --git a/gui/libguitwrp_defaults.go b/gui/libguitwrp_defaults.go
new file mode 100644
index 0000000..8abec95
--- /dev/null
+++ b/gui/libguitwrp_defaults.go
@@ -0,0 +1,118 @@
+package libgui_defaults
+
+import (
+ "android/soong/android"
+ "android/soong/cc"
+)
+
+func globalFlags(ctx android.BaseContext) []string {
+ var cflags []string
+
+ if ctx.AConfig().Getenv("TW_DELAY_TOUCH_INIT_MS") != "" {
+ cflags = append(cflags, "-DTW_DELAY_TOUCH_INIT_MS="+ctx.AConfig().Getenv("TW_DELAY_TOUCH_INIT_MS"))
+ }
+
+ if ctx.AConfig().Getenv("TW_EVENT_LOGGING") == "true" {
+ cflags = append(cflags, "-D_EVENT_LOGGING")
+ }
+
+ if ctx.AConfig().Getenv("TW_USE_KEY_CODE_TOUCH_SYNC") != "" {
+ cflags = append(cflags, "DTW_USE_KEY_CODE_TOUCH_SYNC="+ctx.AConfig().Getenv("TW_USE_KEY_CODE_TOUCH_SYNC"))
+ }
+
+ if ctx.AConfig().Getenv("TW_OZIP_DECRYPT_KEY") != "" {
+ cflags = append(cflags, "-DTW_OZIP_DECRYPT_KEY=\""+ctx.AConfig().Getenv("TW_OZIP_DECRYPT_KEY")+"\"")
+ } else {
+ cflags = append(cflags, "-DTW_OZIP_DECRYPT_KEY=0")
+ }
+
+ if ctx.AConfig().Getenv("TW_NO_SCREEN_BLANK") != "" {
+ cflags = append(cflags, "-DTW_NO_SCREEN_BLANK")
+ }
+
+ if ctx.AConfig().Getenv("TW_NO_SCREEN_TIMEOUT") != "" {
+ cflags = append(cflags, "-DTW_NO_SCREEN_TIMEOUT")
+ }
+
+ if ctx.AConfig().Getenv("TW_OEM_BUILD") != "" {
+ cflags = append(cflags, "-DTW_OEM_BUILD")
+ }
+
+ if ctx.AConfig().Getenv("TW_X_OFFSET") != "" {
+ cflags = append(cflags, "-DTW_X_OFFSET="+ctx.AConfig().Getenv("TW_X_OFFSET"))
+ }
+
+ if ctx.AConfig().Getenv("TW_Y_OFFSET") != "" {
+ cflags = append(cflags, "-DTW_Y_OFFSET="+ctx.AConfig().Getenv("TW_Y_OFFSET"))
+ }
+
+ if ctx.AConfig().Getenv("TW_W_OFFSET") != "" {
+ cflags = append(cflags, "-DTW_W_OFFSET="+ctx.AConfig().Getenv("TW_W_OFFSET"))
+ }
+
+ if ctx.AConfig().Getenv("TW_H_OFFSET") != "" {
+ cflags = append(cflags, "-DTW_H_OFFSET="+ctx.AConfig().Getenv("TW_H_OFFSET"))
+ }
+
+ if ctx.AConfig().Getenv("TW_ROUND_SCREEN") == "true" {
+ cflags = append(cflags, "-DTW_ROUND_SCREEN")
+ }
+
+ cflags = append(cflags, "-DTWRES=\""+ctx.AConfig().Getenv("TWRES_PATH")+"\"")
+
+ return cflags
+}
+
+func globalSrcs(ctx android.BaseContext) []string {
+ var srcs []string
+
+ if ctx.AConfig().Getenv("TWRP_CUSTOM_KEYBOARD") != "" {
+ srcs = append(srcs, ctx.AConfig().Getenv("TWRP_CUSTOM_KEYBOARD"))
+ } else {
+ srcs = append(srcs, "hardwarekeyboard.cpp")
+ }
+ return srcs
+}
+
+func globalIncludes(ctx android.BaseContext) []string {
+ var includes []string
+
+ if ctx.AConfig().Getenv("TW_INCLUDE_CRYPTO") != "" {
+ includes = append(includes, "bootable/recovery/crypto/fscrypt")
+ }
+
+ return includes
+}
+
+func libGuiDefaults(ctx android.LoadHookContext) {
+ type props struct {
+ Target struct {
+ Android struct {
+ Cflags []string
+ Enabled *bool
+ }
+ }
+ Cflags []string
+ Srcs []string
+ Include_dirs []string
+ }
+
+ p := &props{}
+ p.Cflags = globalFlags(ctx)
+ s := globalSrcs(ctx)
+ p.Srcs = s
+ i := globalIncludes(ctx)
+ p.Include_dirs = i
+ ctx.AppendProperties(p)
+}
+
+func init() {
+ android.RegisterModuleType("libguitwrp_defaults", libGuiDefaultsFactory)
+}
+
+func libGuiDefaultsFactory() android.Module {
+ module := cc.DefaultsFactory()
+ android.AddLoadHook(module, libGuiDefaults)
+
+ return module
+}
diff --git a/gui/pages.cpp b/gui/pages.cpp
index a3047bb..c274c4b 100755
--- a/gui/pages.cpp
+++ b/gui/pages.cpp
@@ -39,21 +39,14 @@
#include <string>
#include <algorithm>
-#ifdef USE_MINZIP
-#include "../minzip/SysUtil.h"
-#else
-#ifdef USE_OTAUTIL_ZIPARCHIVE
-#include <otautil/SysUtil.h>
-#else
+
#include <ziparchive/zip_archive.h>
-#endif
-#endif
+#include "ZipUtil.h"
extern "C" {
#include "../twcommon.h"
#include "gui.h"
}
-#include "zipwrap.hpp"
#include "../minuitwrp/minui.h"
#include "rapidxml.hpp"
@@ -674,7 +667,7 @@
// transient data for loading themes
struct LoadingContext
{
- ZipWrap* zip; // zip to load theme from, or NULL for the stock theme
+ ZipArchiveHandle zip; // zip to load theme from, or NULL for the stock theme
std::set<std::string> filenames; // to detect cyclic includes
std::string basepath; // if zip is NULL, base path to load includes from with trailing slash, otherwise empty
std::vector<xml_document<>*> xmldocs; // all loaded xml docs
@@ -816,7 +809,7 @@
}
}
-int PageSet::LoadLanguage(char* languageFile, ZipWrap* package)
+int PageSet::LoadLanguage(char* languageFile, ZipArchiveHandle package)
{
xml_document<> lang;
xml_node<>* parent;
@@ -1192,11 +1185,11 @@
mResources->AddStringResource(resource_source, resource_name, value);
}
-char* PageManager::LoadFileToBuffer(std::string filename, ZipWrap* package) {
+char* PageManager::LoadFileToBuffer(std::string filename, ZipArchiveHandle package) {
size_t len;
char* buffer = NULL;
- if (!package) {
+ if (package) {
// We can try to load the XML directly...
LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' directly\n", filename.c_str());
struct stat st;
@@ -1229,18 +1222,24 @@
close(fd);
} else {
LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' from zip\n", filename.c_str());
- if (!package->EntryExists(filename)) {
+ ZipEntry binary_entry;
+ if (FindEntry(package, filename, &binary_entry) == 0) {
+ // if (!package->EntryExists(filename)) {
LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
return NULL;
}
// Allocate the buffer for the file
- len = package->GetUncompressedSize(filename);
+ len = binary_entry.uncompressed_length;
+ // len = package->GetUncompressedSize(filename);
buffer = (char*) malloc(len + 1);
if (!buffer)
return NULL;
- if (!package->ExtractToBuffer(filename, (unsigned char*) buffer)) {
+ int32_t err =
+ ExtractToMemory(package, &binary_entry, reinterpret_cast<uint8_t*>(buffer), len);
+ if (err != 0) {
+ // if (!package->ExtractToBuffer(filename, (unsigned char*) buffer)) {
LOGERR("Unable to extract '%s'\n", filename.c_str());
free(buffer);
return NULL;
@@ -1304,13 +1303,15 @@
closedir(d);
}
-void PageManager::LoadLanguageList(ZipWrap* package) {
+void PageManager::LoadLanguageList(ZipArchiveHandle package) {
Language_List.clear();
if (TWFunc::Path_Exists(TWRES "customlanguages"))
TWFunc::removeDir(TWRES "customlanguages", true);
if (package) {
TWFunc::Recursive_Mkdir(TWRES "customlanguages");
- package->ExtractRecursive("languages", TWRES "customlanguages/");
+ ExtractPackageRecursive(package, "", TWRES "customlanguages", nullptr, nullptr);
+
+ // package->ExtractRecursive("languages", TWRES "customlanguages/");
LoadLanguageListDir(TWRES "customlanguages/");
} else {
LoadLanguageListDir(TWRES "languages/");
@@ -1338,12 +1339,10 @@
int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
{
std::string mainxmlfilename = package;
- ZipWrap zip;
char* languageFile = NULL;
char* baseLanguageFile = NULL;
PageSet* pageSet = NULL;
int ret;
- MemMapping map;
mReloadTheme = false;
mStartPage = startpage;
@@ -1375,22 +1374,14 @@
tw_h_offset = 0;
if (!TWFunc::Path_Exists(package))
return -1;
-#ifdef USE_MINZIP
- if (sysMapFile(package.c_str(), &map) != 0) {
-#else
- if (!map.MapFile(package)) {
-#endif
- LOGERR("Failed to map '%s'\n", package.c_str());
- goto error;
- }
- if (!zip.Open(package.c_str(), &map)) {
- LOGERR("Unable to open zip archive '%s'\n", package.c_str());
-#ifdef USE_MINZIP
- sysReleaseMap(&map);
-#endif
- goto error;
- }
- ctx.zip = &zip;
+
+ ZipArchiveHandle Zip;
+ int err = OpenArchive(package.c_str(), &Zip);
+
+ if (err != 0)
+ return -1;
+
+ ctx.zip = Zip;
mainxmlfilename = "ui.xml";
LoadLanguageList(ctx.zip);
languageFile = LoadFileToBuffer("languages/en.xml", ctx.zip);
@@ -1428,22 +1419,9 @@
mCurrentSet = pageSet;
if (ctx.zip) {
- ctx.zip->Close();
-#ifdef USE_MINZIP
- sysReleaseMap(&map);
-#endif
+ CloseArchive(ctx.zip);
}
return ret;
-
-error:
- // Sometimes we get here without a real error
- if (ctx.zip) {
- ctx.zip->Close();
-#ifdef USE_MINZIP
- sysReleaseMap(&map);
-#endif
- }
- return -1;
}
PageSet* PageManager::FindPackage(std::string name)
diff --git a/gui/pages.hpp b/gui/pages.hpp
index 8c5edaf..7688604 100755
--- a/gui/pages.hpp
+++ b/gui/pages.hpp
@@ -21,10 +21,10 @@
#ifndef _PAGES_HEADER_HPP
#define _PAGES_HEADER_HPP
-#include "zipwrap.hpp"
#include <vector>
#include <map>
#include <string>
+#include "ziparchive/zip_archive.h"
#include "rapidxml.hpp"
#include "gui.hpp"
using namespace rapidxml;
@@ -116,7 +116,7 @@
public:
int Load(LoadingContext& ctx, const std::string& filename);
- int LoadLanguage(char* languageFile, ZipWrap* package);
+ int LoadLanguage(char* languageFile, ZipArchiveHandle package);
void MakeEmergencyConsoleIfNeeded();
Page* FindPage(std::string name);
@@ -155,8 +155,8 @@
{
public:
// Used by GUI
- static char* LoadFileToBuffer(std::string filename, ZipWrap* package);
- static void LoadLanguageList(ZipWrap* package);
+ static char* LoadFileToBuffer(std::string filename, ZipArchiveHandle package);
+ static void LoadLanguageList(ZipArchiveHandle package);
static void LoadLanguage(std::string filename);
static int LoadPackage(std::string name, std::string package, std::string startpage);
static PageSet* SelectPackage(std::string name);
diff --git a/gui/resources.cpp b/gui/resources.cpp
index 5efa093..9c4eec1 100755
--- a/gui/resources.cpp
+++ b/gui/resources.cpp
@@ -29,8 +29,9 @@
#include <iostream>
#include <iomanip>
#include <fcntl.h>
+#include <ziparchive/zip_archive.h>
+#include <android-base/unique_fd.h>
-#include "zipwrap.hpp"
extern "C" {
#include "../twcommon.h"
#include "gui.h"
@@ -44,24 +45,36 @@
#define TMP_RESOURCE_NAME "/tmp/extract.bin"
-Resource::Resource(xml_node<>* node, ZipWrap* pZip __unused)
+Resource::Resource(xml_node<>* node, ZipArchiveHandle pZip __unused)
{
if (node && node->first_attribute("name"))
mName = node->first_attribute("name")->value();
}
-int Resource::ExtractResource(ZipWrap* pZip, std::string folderName, std::string fileName, std::string fileExtn, std::string destFile)
+int Resource::ExtractResource(ZipArchiveHandle pZip, std::string folderName, std::string fileName, std::string fileExtn, std::string destFile)
{
if (!pZip)
return -1;
std::string src = folderName + "/" + fileName + fileExtn;
- if (!pZip->ExtractEntry(src, destFile, 0666))
+ ZipEntry binary_entry;
+ if (FindEntry(pZip, src, &binary_entry) != 0) {
+ android::base::unique_fd fd(
+ open(destFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0666));
+ if (fd == -1) {
+ return -1;
+ }
+ // if (!pZip->ExtractEntry(src, destFile, 0666))
+ int32_t err = ExtractEntryToFile(pZip, &binary_entry, fd);
+ if (err != 0)
+ return -1;
+ } else {
return -1;
+ }
return 0;
}
-void Resource::LoadImage(ZipWrap* pZip, std::string file, gr_surface* surface)
+void Resource::LoadImage(ZipArchiveHandle pZip, std::string file, gr_surface* surface)
{
int rc = 0;
if (ExtractResource(pZip, "images", file, ".png", TMP_RESOURCE_NAME) == 0)
@@ -107,7 +120,7 @@
}
}
-FontResource::FontResource(xml_node<>* node, ZipWrap* pZip)
+FontResource::FontResource(xml_node<>* node, ZipArchiveHandle pZip)
: Resource(node, pZip)
{
origFontSize = 0;
@@ -115,7 +128,7 @@
LoadFont(node, pZip);
}
-void FontResource::LoadFont(xml_node<>* node, ZipWrap* pZip)
+void FontResource::LoadFont(xml_node<>* node, ZipArchiveHandle pZip)
{
std::string file;
xml_attribute<>* attr;
@@ -182,7 +195,7 @@
origFont = NULL;
}
-void FontResource::Override(xml_node<>* node, ZipWrap* pZip) {
+void FontResource::Override(xml_node<>* node, ZipArchiveHandle pZip) {
if (!origFont) {
origFont = mFont;
} else if (mFont) {
@@ -197,7 +210,7 @@
DeleteFont();
}
-ImageResource::ImageResource(xml_node<>* node, ZipWrap* pZip)
+ImageResource::ImageResource(xml_node<>* node, ZipArchiveHandle pZip)
: Resource(node, pZip)
{
std::string file;
@@ -228,7 +241,7 @@
res_free_surface(mSurface);
}
-AnimationResource::AnimationResource(xml_node<>* node, ZipWrap* pZip)
+AnimationResource::AnimationResource(xml_node<>* node, ZipArchiveHandle pZip)
: Resource(node, pZip)
{
std::string file;
@@ -349,7 +362,7 @@
mStrings[resource_name] = res;
}
-void ResourceManager::LoadResources(xml_node<>* resList, ZipWrap* pZip, std::string resource_source)
+void ResourceManager::LoadResources(xml_node<>* resList, ZipArchiveHandle pZip, std::string resource_source)
{
if (!resList)
return;
diff --git a/gui/resources.hpp b/gui/resources.hpp
index e709e33..aeacd19 100755
--- a/gui/resources.hpp
+++ b/gui/resources.hpp
@@ -25,7 +25,7 @@
#include <vector>
#include <map>
#include "rapidxml.hpp"
-#include "zipwrap.hpp"
+#include "ziparchive/zip_archive.h"
#include "../minuitwrp/truetype.hpp"
extern "C" {
@@ -36,7 +36,7 @@
class Resource
{
public:
- Resource(xml_node<>* node, ZipWrap* pZip);
+ Resource(xml_node<>* node, ZipArchiveHandle pZip);
virtual ~Resource() {}
public:
@@ -46,27 +46,27 @@
std::string mName;
protected:
- static int ExtractResource(ZipWrap* pZip, std::string folderName, std::string fileName, std::string fileExtn, std::string destFile);
- static void LoadImage(ZipWrap* pZip, std::string file, gr_surface* surface);
+ static int ExtractResource(ZipArchiveHandle pZip, std::string folderName, std::string fileName, std::string fileExtn, std::string destFile);
+ static void LoadImage(ZipArchiveHandle pZip, std::string file, gr_surface* surface);
static void CheckAndScaleImage(gr_surface source, gr_surface* destination, int retain_aspect);
};
class FontResource : public Resource
{
public:
- FontResource(xml_node<>* node, ZipWrap* pZip);
+ FontResource(xml_node<>* node, ZipArchiveHandle pZip);
virtual ~FontResource();
public:
void* GetResource() { return mFont; }
int GetHeight() { return twrpTruetype::gr_ttf_getMaxFontHeight(mFont); }
- void Override(xml_node<>* node, ZipWrap* pZip);
+ void Override(xml_node<>* node, ZipArchiveHandle pZip);
protected:
void* mFont;
private:
- void LoadFont(xml_node<>* node, ZipWrap* pZip);
+ void LoadFont(xml_node<>* node, ZipArchiveHandle pZip);
void DeleteFont();
private:
@@ -77,7 +77,7 @@
class ImageResource : public Resource
{
public:
- ImageResource(xml_node<>* node, ZipWrap* pZip);
+ ImageResource(xml_node<>* node, ZipArchiveHandle pZip);
virtual ~ImageResource();
public:
@@ -92,7 +92,7 @@
class AnimationResource : public Resource
{
public:
- AnimationResource(xml_node<>* node, ZipWrap* pZip);
+ AnimationResource(xml_node<>* node, ZipArchiveHandle pZip);
virtual ~AnimationResource();
public:
@@ -112,7 +112,7 @@
ResourceManager();
virtual ~ResourceManager();
void AddStringResource(std::string resource_source, std::string resource_name, std::string value);
- void LoadResources(xml_node<>* resList, ZipWrap* pZip, std::string resource_source);
+ void LoadResources(xml_node<>* resList, ZipArchiveHandle pZip, std::string resource_source);
public:
FontResource* FindFont(const std::string& name) const;
diff --git a/install/Android.bp b/install/Android.bp
index ea893a0..aa14475 100644
--- a/install/Android.bp
+++ b/install/Android.bp
@@ -19,8 +19,8 @@
"recovery_defaults",
],
- header_libs: [
- "libminadbd_headers",
+ cflags: [
+ //"-DRECOVERY_API_VERSION=3"
],
shared_libs: [
@@ -32,7 +32,6 @@
"libfusesideload",
"libhidl-gen-utils",
"libhidlbase",
- "libhidltransport",
"liblog",
"libselinux",
"libtinyxml2",
@@ -42,12 +41,12 @@
],
static_libs: [
+ "librecovery_utils",
"libotautil",
+ "libsnapshot_nobinder",
// external dependencies
- "libvintf_recovery",
"libvintf",
- "libfstab",
],
}
@@ -62,11 +61,17 @@
srcs: [
"adb_install.cpp",
"asn1_decoder.cpp",
- "fuse_sdcard_install.cpp",
+ "fuse_install.cpp",
"install.cpp",
"package.cpp",
+ "snapshot_utils.cpp",
"verifier.cpp",
"wipe_data.cpp",
+ "wipe_device.cpp",
+ ],
+
+ header_libs: [
+ "libminadbd_headers",
],
shared_libs: [
diff --git a/install/ZipUtil.cpp b/install/ZipUtil.cpp
index f8134bc..c7b6b3d 100755
--- a/install/ZipUtil.cpp
+++ b/install/ZipUtil.cpp
@@ -54,9 +54,9 @@
if (!zip_path.empty() && zip_path.back() != '/') {
prefix_path += '/';
}
- const ZipString zip_prefix(prefix_path.c_str());
+ const std::string zip_prefix(prefix_path.c_str());
- int ret = StartIteration(zip, &cookie, &zip_prefix, nullptr);
+ int ret = StartIteration(zip, &cookie, zip_prefix, nullptr);
if (ret != 0) {
LOG(ERROR) << "failed to start iterating zip entries.";
return false;
@@ -64,10 +64,10 @@
std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
ZipEntry entry;
- ZipString name;
+ std::string name;
int extractCount = 0;
while (Next(cookie, &entry, &name) == 0) {
- std::string entry_name(name.name, name.name + name.name_length);
+ std::string entry_name(name.c_str(), name.c_str() + name.size());
CHECK_LE(prefix_path.size(), entry_name.size());
std::string path = target_dir + entry_name.substr(prefix_path.size());
// Skip dir.
diff --git a/install/adb_install.cpp b/install/adb_install.cpp
index 0db4a27..feebaee 100755
--- a/install/adb_install.cpp
+++ b/install/adb_install.cpp
@@ -44,7 +44,7 @@
#include "fuse_sideload.h"
#include "install/install.h"
#include "install/wipe_data.h"
-#include "minadbd_types.h"
+#include "minadbd/types.h"
#include "otautil/sysutil.h"
#include "recovery_ui/device.h"
#include "recovery_ui/ui.h"
@@ -90,7 +90,7 @@
// Installs the package from FUSE. Returns the installation result and whether it should continue
// waiting for new commands.
-static auto AdbInstallPackageHandler(int* result) {
+static auto AdbInstallPackageHandler(InstallResult* result) {
// How long (in seconds) we wait for the package path to be ready. It doesn't need to be too long
// because the minadbd service has already issued an install command. FUSE_SIDELOAD_HOST_PATHNAME
// will start to exist once the host connects and starts serving a package. Poll for its
@@ -110,7 +110,10 @@
break;
}
}
- *result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0);
+
+ auto package =
+ Package::CreateFilePackage(FUSE_SIDELOAD_HOST_PATHNAME, nullptr);
+ *result = InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0);
break;
}
@@ -120,7 +123,7 @@
return std::make_pair(*result == INSTALL_SUCCESS, should_continue);
}
-static auto AdbRebootHandler(MinadbdCommand command, int* result,
+static auto AdbRebootHandler(MinadbdCommand command, InstallResult* result,
Device::BuiltinAction* reboot_action) {
// Use Device::REBOOT_{FASTBOOT,RECOVERY,RESCUE}, instead of the ones with ENTER_. This allows
// rebooting back into fastboot/recovery/rescue mode through bootloader, which may use a newly
@@ -333,7 +336,6 @@
signal(SIGPIPE, SIG_DFL);
}
-// int ApplyFromAdb(Device* device, bool rescue_mode, Device::BuiltinAction* reboot_action) {
int ApplyFromAdb(const char* install_file, Device::BuiltinAction* reboot_action) {
// Save the usb state to restore after the sideload operation.
@@ -346,7 +348,7 @@
// RecoveryUI* ui = device->GetUI();
- int install_result = INSTALL_ERROR;
+ InstallResult install_result = INSTALL_ERROR;
std::map<MinadbdCommand, CommandFunction> command_map{
{ MinadbdCommand::kInstall, std::bind(&AdbInstallPackageHandler, &install_result) },
{ MinadbdCommand::kRebootAndroid, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootAndroid,
diff --git a/install/fuse_sdcard_install.cpp b/install/fuse_install.cpp
similarity index 74%
rename from install/fuse_sdcard_install.cpp
rename to install/fuse_install.cpp
index 011847b..61e1d74 100755
--- a/install/fuse_sdcard_install.cpp
+++ b/install/fuse_install.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "install/fuse_sdcard_install.h"
+#include "install/fuse_install.h"
#include <dirent.h>
#include <signal.h>
@@ -27,6 +27,7 @@
#include <algorithm>
#include <functional>
#include <memory>
+#include <string>
#include <vector>
#include <android-base/logging.h>
@@ -36,7 +37,7 @@
#include "fuse_provider.h"
#include "fuse_sideload.h"
#include "install/install.h"
-#include "otautil/roots.h"
+#include "recovery_utils/roots.h"
static constexpr const char* SDCARD_ROOT = "/sdcard";
// How long (in seconds) we wait for the fuse-provided package file to
@@ -74,7 +75,8 @@
// Skip "." and ".." entries.
if (name == "." || name == "..") continue;
dirs.push_back(name + "/");
- } else if (de->d_type == DT_REG && android::base::EndsWithIgnoreCase(name, ".zip")) {
+ } else if (de->d_type == DT_REG && (android::base::EndsWithIgnoreCase(name, ".zip") ||
+ android::base::EndsWithIgnoreCase(name, ".map"))) {
entries.push_back(name);
}
}
@@ -119,49 +121,44 @@
// Unreachable.
}
-static bool StartSdcardFuse(const std::string& path) {
- auto file_data_reader = std::make_unique<FuseFileDataProvider>(path, 65536);
-
- if (!file_data_reader->Valid()) {
+static bool StartInstallPackageFuse(std::string_view path) {
+ if (path.empty()) {
return false;
}
- // The installation process expects to find the sdcard unmounted. Unmount it with MNT_DETACH so
- // that our open file continues to work but new references see it as unmounted.
- umount2("/sdcard", MNT_DETACH);
+ constexpr auto FUSE_BLOCK_SIZE = 65536;
+ bool is_block_map = android::base::ConsumePrefix(&path, "@");
+ auto fuse_data_provider =
+ is_block_map ? FuseBlockDataProvider::CreateFromBlockMap(std::string(path), FUSE_BLOCK_SIZE)
+ : FuseFileDataProvider::CreateFromFile(std::string(path), FUSE_BLOCK_SIZE);
- return run_fuse_sideload(std::move(file_data_reader)) == 0;
+ if (!fuse_data_provider || !fuse_data_provider->Valid()) {
+ LOG(ERROR) << "Failed to create fuse data provider.";
+ return false;
+ }
+
+ if (android::base::StartsWith(path, SDCARD_ROOT)) {
+ // The installation process expects to find the sdcard unmounted. Unmount it with MNT_DETACH so
+ // that our open file continues to work but new references see it as unmounted.
+ umount2(SDCARD_ROOT, MNT_DETACH);
+ }
+
+ return run_fuse_sideload(std::move(fuse_data_provider)) == 0;
}
-int ApplyFromSdcard(Device* device, RecoveryUI* ui) {
- if (ensure_path_mounted(SDCARD_ROOT) != 0) {
- LOG(ERROR) << "\n-- Couldn't mount " << SDCARD_ROOT << ".\n";
- return INSTALL_ERROR;
- }
-
- std::string path = BrowseDirectory(SDCARD_ROOT, device, ui);
- if (path.empty()) {
- LOG(ERROR) << "\n-- No package file selected.\n";
- ensure_path_unmounted(SDCARD_ROOT);
- return INSTALL_ERROR;
- }
-
- ui->Print("\n-- Install %s ...\n", path.c_str());
- SetSdcardUpdateBootloaderMessage();
-
+InstallResult InstallWithFuseFromPath(std::string_view path, __attribute__((unused)) RecoveryUI* ui) {
// We used to use fuse in a thread as opposed to a process. Since accessing
// through fuse involves going from kernel to userspace to kernel, it leads
// to deadlock when a page fault occurs. (Bug: 26313124)
pid_t child;
if ((child = fork()) == 0) {
- bool status = StartSdcardFuse(path);
+ bool status = StartInstallPackageFuse(path);
_exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
}
- // FUSE_SIDELOAD_HOST_PATHNAME will start to exist once the fuse in child
- // process is ready.
- int result = INSTALL_ERROR;
+ // FUSE_SIDELOAD_HOST_PATHNAME will start to exist once the fuse in child process is ready.
+ InstallResult result = INSTALL_ERROR;
int status;
bool waited = false;
for (int i = 0; i < SDCARD_INSTALL_TIMEOUT; ++i) {
@@ -183,8 +180,10 @@
break;
}
}
-
- result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0 /*retry_count*/);
+ auto package =
+ Package::CreateFilePackage(FUSE_SIDELOAD_HOST_PATHNAME, nullptr);
+ result =
+ InstallPackage(package.get(), FUSE_SIDELOAD_HOST_PATHNAME, false, 0 /* retry_count */);
break;
}
@@ -201,6 +200,32 @@
LOG(ERROR) << "Error exit from the fuse process: " << WEXITSTATUS(status);
}
+ return result;
+}
+
+InstallResult ApplyFromSdcard(Device* device) {
+ auto ui = device->GetUI();
+ if (ensure_path_mounted(SDCARD_ROOT) != 0) {
+ LOG(ERROR) << "\n-- Couldn't mount " << SDCARD_ROOT << ".\n";
+ return INSTALL_ERROR;
+ }
+
+ std::string path = BrowseDirectory(SDCARD_ROOT, device, ui);
+ if (path.empty()) {
+ LOG(ERROR) << "\n-- No package file selected.\n";
+ ensure_path_unmounted(SDCARD_ROOT);
+ return INSTALL_ERROR;
+ }
+
+ // Hint the install function to read from a block map file.
+ if (android::base::EndsWithIgnoreCase(path, ".map")) {
+ path = "@" + path;
+ }
+
+ ui->Print("\n-- Install %s ...\n", path.c_str());
+ SetSdcardUpdateBootloaderMessage();
+
+ auto result = InstallWithFuseFromPath(path, ui);
ensure_path_unmounted(SDCARD_ROOT);
return result;
}
diff --git a/install/include/install/adb_install.h b/install/include/install/adb_install.h
index f7b15b2..8800223 100755
--- a/install/include/install/adb_install.h
+++ b/install/include/install/adb_install.h
@@ -16,9 +16,10 @@
#pragma once
-#include <recovery_ui/device.h>
+#include "install/install.h"
+#include "recovery_ui/device.h"
-// Applies a package via `adb sideload` or `adb rescue`. Returns the install result (in `enum
-// InstallResult`). When a reboot has been requested, INSTALL_REBOOT will be the return value, with
-// the reboot target set in reboot_action.
-int ApplyFromAdb(const char* install_file, Device::BuiltinAction* reboot_action);
+// Applies a package via `adb sideload` or `adb rescue`. Returns the install result. When a reboot
+// has been requested, INSTALL_REBOOT will be the return value, with the reboot target set in
+// reboot_action.
+InstallResult ApplyFromAdb(Device* device, bool rescue_mode, Device::BuiltinAction* reboot_action);
diff --git a/install/include/install/fuse_sdcard_install.h b/install/include/install/fuse_install.h
old mode 100755
new mode 100644
similarity index 60%
copy from install/include/install/fuse_sdcard_install.h
copy to install/include/install/fuse_install.h
index d9214ca..63b116a
--- a/install/include/install/fuse_sdcard_install.h
+++ b/install/include/install/fuse_install.h
@@ -16,7 +16,15 @@
#pragma once
+#include <string_view>
+
+#include "install/install.h"
#include "recovery_ui/device.h"
#include "recovery_ui/ui.h"
-int ApplyFromSdcard(Device* device, RecoveryUI* ui);
+// Starts FUSE with the package from |path| as the data source. And installs the package from
+// |FUSE_SIDELOAD_HOST_PATHNAME|. The |path| can point to the location of a package zip file or a
+// block map file with the prefix '@'; e.g. /sdcard/package.zip, @/cache/recovery/block.map.
+InstallResult InstallWithFuseFromPath(std::string_view path, RecoveryUI* ui);
+
+InstallResult ApplyFromSdcard(Device* device);
diff --git a/install/include/install/install.h b/install/include/install/install.h
index fcbfc99..eb91974 100755
--- a/install/include/install/install.h
+++ b/install/include/install/install.h
@@ -44,14 +44,12 @@
BRICK,
};
-static constexpr const char* UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary";
-static constexpr float VERIFICATION_PROGRESS_FRACTION = 0.25;
-
-// Installs the given update package. This function should also wipe the cache partition after a
-// successful installation if |should_wipe_cache| is true or an updater command asks to wipe the
-// cache.
-int install_package(const std::string& package, bool should_wipe_cache, bool needs_mount,
- int retry_count);
+// Installs the given update package. The package_id is a string provided by the caller (e.g. the
+// package path) to identify the package and log to last_install. This function should also wipe the
+// cache partition after a successful installation if |should_wipe_cache| is true or an updater
+// command asks to wipe the cache.
+InstallResult InstallPackage(Package* package, const std::string_view package_id,
+ bool should_wipe_cache, int retry_count);
// Verifies the package by ota keys. Returns true if the package is verified successfully,
// otherwise returns false.
@@ -61,14 +59,11 @@
// result to |metadata|. Return true if succeed, otherwise return false.
bool ReadMetadataFromPackage(ZipArchiveHandle zip, std::map<std::string, std::string>* metadata);
-// Reads the "recovery.wipe" entry in the zip archive returns a list of partitions to wipe.
-std::vector<std::string> GetWipePartitionList(Package* wipe_package);
+// Checks if the metadata in the OTA package has expected values. Mandatory checks: ota-type,
+// pre-device and serial number (if presents). A/B OTA specific checks: pre-build version,
+// fingerprint, timestamp.
+bool CheckPackageMetadata(const std::map<std::string, std::string>& metadata, OtaType ota_type);
-// Verifies the compatibility info in a Treble-compatible package. Returns true directly if the
-// entry doesn't exist.
-bool verify_package_compatibility(ZipArchiveHandle package_zip);
-
-// Checks if the the metadata in the OTA package has expected values. Returns 0 on success.
-// Mandatory checks: ota-type, pre-device and serial number(if presents)
-// AB OTA specific checks: pre-build version, fingerprint, timestamp.
-int CheckPackageMetadata(const std::map<std::string, std::string>& metadata, OtaType ota_type);
+// Ensures the path to the update package is mounted. Also set the |should_use_fuse| to true if the
+// package stays on a removable media.
+bool SetupPackageMount(const std::string& package_path, bool* should_use_fuse);
diff --git a/install/include/install/package.h b/install/include/install/package.h
index 50a4ffa..3699752 100755
--- a/install/include/install/package.h
+++ b/install/include/install/package.h
@@ -28,6 +28,11 @@
#include "verifier.h"
+enum class PackageType {
+ kMemory,
+ kFile,
+};
+
// This class serves as a wrapper for an OTA update package. It aims to provide the common
// interface for both packages loaded in memory and packages read from fd.
class Package : public VerifierInterface {
@@ -41,6 +46,10 @@
virtual ~Package() = default;
+ virtual PackageType GetType() const = 0;
+
+ virtual std::string GetPath() const = 0;
+
// Opens the package as a zip file and returns the ZipArchiveHandle.
virtual ZipArchiveHandle GetZipArchiveHandle() = 0;
diff --git a/install/include/install/fuse_sdcard_install.h b/install/include/install/snapshot_utils.h
old mode 100755
new mode 100644
similarity index 62%
copy from install/include/install/fuse_sdcard_install.h
copy to install/include/install/snapshot_utils.h
index d9214ca..f4b978d
--- a/install/include/install/fuse_sdcard_install.h
+++ b/install/include/install/snapshot_utils.h
@@ -17,6 +17,14 @@
#pragma once
#include "recovery_ui/device.h"
-#include "recovery_ui/ui.h"
-int ApplyFromSdcard(Device* device, RecoveryUI* ui);
+bool FinishPendingSnapshotMerges(Device* device);
+
+/*
+ * This function tries to create the snapshotted devices in the case a Virtual
+ * A/B device is updating.
+ * The function returns false in case of critical failure that would prevent
+ * the further mountings of devices, or true in case of success, if either the
+ * devices were created or there was no need to.
+ */
+bool CreateSnapshotPartitions();
diff --git a/install/include/install/fuse_sdcard_install.h b/install/include/install/wipe_device.h
similarity index 63%
rename from install/include/install/fuse_sdcard_install.h
rename to install/include/install/wipe_device.h
index d9214ca..c60b999 100755
--- a/install/include/install/fuse_sdcard_install.h
+++ b/install/include/install/wipe_device.h
@@ -16,7 +16,14 @@
#pragma once
-#include "recovery_ui/device.h"
-#include "recovery_ui/ui.h"
+#include <string>
+#include <vector>
-int ApplyFromSdcard(Device* device, RecoveryUI* ui);
+#include "install/package.h"
+#include "recovery_ui/device.h"
+
+// Wipes the current A/B device, with a secure wipe of all the partitions in RECOVERY_WIPE.
+bool WipeAbDevice(Device* device, size_t wipe_package_size);
+
+// Reads the "recovery.wipe" entry in the zip archive returns a list of partitions to wipe.
+std::vector<std::string> GetWipePartitionList(Package* wipe_package);
diff --git a/install/include/legacy_property_service.h b/install/include/legacy_property_service.h
deleted file mode 100644
index d20bdef..0000000
--- a/install/include/legacy_property_service.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source 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.
- */
-
-#ifndef _LEGACY_PROPERTY_H
-#define _LEGACY_PROPERTY_H
-
-#include <stdbool.h>
-
-void legacy_get_property_workspace(int *fd, int *sz);
-int legacy_properties_init();
-
-#endif /* _LEGACY_PROPERTY_H */
diff --git a/install/include/private/setup_commands.h b/install/include/private/setup_commands.h
index 7fdc741..dcff761 100644
--- a/install/include/private/setup_commands.h
+++ b/install/include/private/setup_commands.h
@@ -27,13 +27,13 @@
// |zip| located at |package|. Stores the command line that should be called into |cmd|. The
// |status_fd| is the file descriptor the child process should use to report back the progress of
// the update.
-int SetUpNonAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int retry_count,
- int status_fd, std::vector<std::string>* cmd);
+bool SetUpNonAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int retry_count,
+ int status_fd, std::vector<std::string>* cmd);
// Sets up the commands for an A/B update. Extracts the needed entries from the open zip archive
// |zip| located at |package|. Stores the command line that should be called into |cmd|. The
// |status_fd| is the file descriptor the child process should use to report back the progress of
// the update. Note that since this applies to the sideloading flow only, it takes one less
// parameter |retry_count| than the non-A/B version.
-int SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd,
- std::vector<std::string>* cmd);
+bool SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd,
+ std::vector<std::string>* cmd);
diff --git a/install/include/zipwrap.hpp b/install/include/zipwrap.hpp
deleted file mode 100755
index 7102116..0000000
--- a/install/include/zipwrap.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) TeamWin
- * This file is part of TWRP/TeamWin Recovery 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.
- */
-
-#ifndef __ZIPWRAP_HPP
-#define __ZIPWRAP_HPP
-
-#include <string>
-#ifdef USE_MINZIP
-#include "minzip/Zip.h"
-#include "minzip/SysUtil.h"
-#else
-#include <ziparchive/zip_archive.h>
-#include "otautil/sysutil.h"
-#endif
-
-using namespace std;
-
-class ZipWrap {
- public:
- ZipWrap();
- ~ZipWrap();
-
- bool Open(const char* file, MemMapping* map);
- void Close();
- bool EntryExists(const string& filename);
- bool ExtractEntry(const string& source_file, const string& target_file, mode_t mode);
-
- long GetUncompressedSize(const string& filename);
- bool ExtractToBuffer(const string& filename, uint8_t* begin);
- bool ExtractRecursive(const string& source_dir, const string& target_dir);
-#ifdef USE_MINZIP
- loff_t GetEntryOffset(const string& filename);
-#else
- off64_t GetEntryOffset(const string& filename);
- ZipArchiveHandle GetZipArchiveHandle();
-#endif
-
- private:
-#ifdef USE_MINZIP
- ZipArchive Zip;
-#else
- ZipArchiveHandle Zip;
-#endif
- string zip_file;
- bool zip_open;
-};
-
-#endif //__ZIPWRAP_HPP
diff --git a/install/install.cpp b/install/install.cpp
index 55d51fc..80c4bdf 100755
--- a/install/install.cpp
+++ b/install/install.cpp
@@ -30,6 +30,7 @@
#include <atomic>
#include <chrono>
#include <condition_variable>
+#include <filesystem>
#include <functional>
#include <limits>
#include <mutex>
@@ -44,23 +45,23 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-#include <vintf/VintfObjectRecovery.h>
#include "install/package.h"
#include "install/verifier.h"
#include "install/wipe_data.h"
#include "otautil/error_code.h"
#include "otautil/paths.h"
-#include "otautil/roots.h"
#include "otautil/sysutil.h"
-#include "otautil/thermalutil.h"
#include "private/setup_commands.h"
#include "recovery_ui/ui.h"
+#include "recovery_utils/roots.h"
+#include "recovery_utils/thermalutil.h"
using namespace std::chrono_literals;
static constexpr int kRecoveryApiVersion = 3;
-// Assert the version defined in code and in Android.mk are consistent.
+// We define RECOVERY_API_VERSION in Android.mk, which will be picked up by build system and packed
+// into target_files.zip. Assert the version defined in code and in Android.mk are consistent.
static_assert(kRecoveryApiVersion == RECOVERY_API_VERSION, "Mismatching recovery API versions.");
// Default allocation of progress bar segments to operations
@@ -73,9 +74,8 @@
CHECK(metadata != nullptr);
static constexpr const char* METADATA_PATH = "META-INF/com/android/metadata";
- ZipString path(METADATA_PATH);
ZipEntry entry;
- if (FindEntry(zip, path, &entry) != 0) {
+ if (FindEntry(zip, METADATA_PATH, &entry) != 0) {
LOG(ERROR) << "Failed to find " << METADATA_PATH;
return false;
}
@@ -139,14 +139,14 @@
// Checks the build version, fingerprint and timestamp in the metadata of the A/B package.
// Downgrading is not allowed unless explicitly enabled in the package and only for
// incremental packages.
-static int CheckAbSpecificMetadata(const std::map<std::string, std::string>& metadata) {
+static bool CheckAbSpecificMetadata(const std::map<std::string, std::string>& metadata) {
// Incremental updates should match the current build.
auto device_pre_build = android::base::GetProperty("ro.build.version.incremental", "");
auto pkg_pre_build = get_value(metadata, "pre-build-incremental");
if (!pkg_pre_build.empty() && pkg_pre_build != device_pre_build) {
LOG(ERROR) << "Package is for source build " << pkg_pre_build << " but expected "
<< device_pre_build;
- return INSTALL_ERROR;
+ return false;
}
auto device_fingerprint = android::base::GetProperty("ro.build.fingerprint", "");
@@ -154,7 +154,7 @@
if (!pkg_pre_build_fingerprint.empty() && pkg_pre_build_fingerprint != device_fingerprint) {
LOG(ERROR) << "Package is for source build " << pkg_pre_build_fingerprint << " but expected "
<< device_fingerprint;
- return INSTALL_ERROR;
+ return false;
}
// Check for downgrade version.
@@ -172,36 +172,36 @@
"newer than timestamp "
<< build_timestamp << " but package has timestamp " << pkg_post_timestamp
<< " and downgrade not allowed.";
- return INSTALL_ERROR;
+ return false;
}
if (pkg_pre_build_fingerprint.empty()) {
LOG(ERROR) << "Downgrade package must have a pre-build version set, not allowed.";
- return INSTALL_ERROR;
+ return false;
}
}
- return 0;
+ return true;
}
-int CheckPackageMetadata(const std::map<std::string, std::string>& metadata, OtaType ota_type) {
+bool CheckPackageMetadata(const std::map<std::string, std::string>& metadata, OtaType ota_type) {
auto package_ota_type = get_value(metadata, "ota-type");
auto expected_ota_type = OtaTypeToString(ota_type);
if (ota_type != OtaType::AB && ota_type != OtaType::BRICK) {
LOG(INFO) << "Skip package metadata check for ota type " << expected_ota_type;
- return 0;
+ return true;
}
if (package_ota_type != expected_ota_type) {
LOG(ERROR) << "Unexpected ota package type, expects " << expected_ota_type << ", actual "
<< package_ota_type;
- return INSTALL_ERROR;
+ return false;
}
auto device = android::base::GetProperty("ro.product.device", "");
auto pkg_device = get_value(metadata, "pre-device");
if (pkg_device != device || pkg_device.empty()) {
LOG(ERROR) << "Package is for product " << pkg_device << " but expected " << device;
- return INSTALL_ERROR;
+ return false;
}
// We allow the package to not have any serialno; and we also allow it to carry multiple serial
@@ -218,7 +218,7 @@
}
if (!serial_number_match) {
LOG(ERROR) << "Package is for serial " << pkg_serial_no;
- return INSTALL_ERROR;
+ return false;
}
}
@@ -226,21 +226,20 @@
return CheckAbSpecificMetadata(metadata);
}
- return 0;
+ return true;
}
-int SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd,
- std::vector<std::string>* cmd) {
+bool SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd,
+ std::vector<std::string>* cmd) {
CHECK(cmd != nullptr);
// For A/B updates we extract the payload properties to a buffer and obtain the RAW payload offset
// in the zip file.
static constexpr const char* AB_OTA_PAYLOAD_PROPERTIES = "payload_properties.txt";
- ZipString property_name(AB_OTA_PAYLOAD_PROPERTIES);
ZipEntry properties_entry;
- if (FindEntry(zip, property_name, &properties_entry) != 0) {
+ if (FindEntry(zip, AB_OTA_PAYLOAD_PROPERTIES, &properties_entry) != 0) {
LOG(ERROR) << "Failed to find " << AB_OTA_PAYLOAD_PROPERTIES;
- return INSTALL_CORRUPT;
+ return false;
}
uint32_t properties_entry_length = properties_entry.uncompressed_length;
std::vector<uint8_t> payload_properties(properties_entry_length);
@@ -248,15 +247,14 @@
ExtractToMemory(zip, &properties_entry, payload_properties.data(), properties_entry_length);
if (err != 0) {
LOG(ERROR) << "Failed to extract " << AB_OTA_PAYLOAD_PROPERTIES << ": " << ErrorCodeString(err);
- return INSTALL_CORRUPT;
+ return false;
}
static constexpr const char* AB_OTA_PAYLOAD = "payload.bin";
- ZipString payload_name(AB_OTA_PAYLOAD);
ZipEntry payload_entry;
- if (FindEntry(zip, payload_name, &payload_entry) != 0) {
+ if (FindEntry(zip, AB_OTA_PAYLOAD, &payload_entry) != 0) {
LOG(ERROR) << "Failed to find " << AB_OTA_PAYLOAD;
- return INSTALL_CORRUPT;
+ return false;
}
long payload_offset = payload_entry.offset;
*cmd = {
@@ -266,20 +264,19 @@
"--headers=" + std::string(payload_properties.begin(), payload_properties.end()),
android::base::StringPrintf("--status_fd=%d", status_fd),
};
- return 0;
+ return true;
}
-int SetUpNonAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int retry_count,
- int status_fd, std::vector<std::string>* cmd) {
+bool SetUpNonAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int retry_count,
+ int status_fd, std::vector<std::string>* cmd) {
CHECK(cmd != nullptr);
// In non-A/B updates we extract the update binary from the package.
static constexpr const char* UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary";
- ZipString binary_name(UPDATE_BINARY_NAME);
ZipEntry binary_entry;
- if (FindEntry(zip, binary_name, &binary_entry) != 0) {
+ if (FindEntry(zip, UPDATE_BINARY_NAME, &binary_entry) != 0) {
LOG(ERROR) << "Failed to find update binary " << UPDATE_BINARY_NAME;
- return INSTALL_CORRUPT;
+ return false;
}
const std::string binary_path = Paths::Get().temporary_update_binary();
@@ -288,13 +285,12 @@
open(binary_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0755));
if (fd == -1) {
PLOG(ERROR) << "Failed to create " << binary_path;
- return INSTALL_ERROR;
+ return false;
}
- int32_t error = ExtractEntryToFile(zip, &binary_entry, fd);
- if (error != 0) {
+ if (auto error = ExtractEntryToFile(zip, &binary_entry, fd); error != 0) {
LOG(ERROR) << "Failed to extract " << UPDATE_BINARY_NAME << ": " << ErrorCodeString(error);
- return INSTALL_ERROR;
+ return false;
}
// When executing the update binary contained in the package, the arguments passed are:
@@ -311,7 +307,7 @@
if (retry_count > 0) {
cmd->push_back("retry");
}
- return 0;
+ return true;
}
static void log_max_temperature(int* max_temperature, const std::atomic<bool>& logger_finished) {
@@ -325,21 +321,35 @@
}
// If the package contains an update binary, extract it and run it.
-static int try_update_binary(const std::string& package, ZipArchiveHandle zip, bool* wipe_cache,
- std::vector<std::string>* log_buffer, int retry_count,
- int* max_temperature) {
+static InstallResult TryUpdateBinary(Package* package, bool* wipe_cache,
+ std::vector<std::string>* log_buffer, int retry_count,
+ int* max_temperature) {
std::map<std::string, std::string> metadata;
+ auto zip = package->GetZipArchiveHandle();
if (!ReadMetadataFromPackage(zip, &metadata)) {
LOG(ERROR) << "Failed to parse metadata in the zip file";
return INSTALL_CORRUPT;
}
- bool is_ab = android::base::GetBoolProperty("ro.build.ab_update", false);
- // Verifies against the metadata in the package first.
- if (int check_status = is_ab ? CheckPackageMetadata(metadata, OtaType::AB) : 0;
- check_status != 0) {
- log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure));
- return check_status;
+ bool package_is_ab = get_value(metadata, "ota-type") == OtaTypeToString(OtaType::AB);
+ bool device_supports_ab = android::base::GetBoolProperty("ro.build.ab_update", false);
+ bool ab_device_supports_nonab =
+ android::base::GetBoolProperty("ro.virtual_ab.allow_non_ab", false);
+ bool device_only_supports_ab = device_supports_ab && !ab_device_supports_nonab;
+
+ if (package_is_ab) {
+ CHECK(package->GetType() == PackageType::kFile);
+ }
+
+ // Verify against the metadata in the package first. Expects A/B metadata if:
+ // Package declares itself as an A/B package
+ // Package does not declare itself as an A/B package, but device only supports A/B;
+ // still calls CheckPackageMetadata to get a meaningful error message.
+ if (package_is_ab || device_only_supports_ab) {
+ if (!CheckPackageMetadata(metadata, OtaType::AB)) {
+ log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure));
+ return INSTALL_ERROR;
+ }
}
ReadSourceTargetBuild(metadata, log_buffer);
@@ -385,13 +395,16 @@
// updater requests logging the string (e.g. cause of the failure).
//
+ std::string package_path = package->GetPath();
+
std::vector<std::string> args;
- if (int update_status =
- is_ab ? SetUpAbUpdateCommands(package, zip, pipe_write.get(), &args)
- : SetUpNonAbUpdateCommands(package, zip, retry_count, pipe_write.get(), &args);
- update_status != 0) {
+ if (auto setup_result =
+ package_is_ab
+ ? SetUpAbUpdateCommands(package_path, zip, pipe_write.get(), &args)
+ : SetUpNonAbUpdateCommands(package_path, zip, retry_count, pipe_write.get(), &args);
+ !setup_result) {
log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure));
- return update_status;
+ return INSTALL_CORRUPT;
}
pid_t pid = fork();
@@ -490,11 +503,11 @@
}
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != EXIT_SUCCESS) {
- LOG(ERROR) << "Error in " << package << " (status " << WEXITSTATUS(status) << ")";
+ LOG(ERROR) << "Error in " << package_path << " (status " << WEXITSTATUS(status) << ")";
return INSTALL_ERROR;
}
} else if (WIFSIGNALED(status)) {
- LOG(ERROR) << "Error in " << package << " (killed by signal " << WTERMSIG(status) << ")";
+ LOG(ERROR) << "Error in " << package_path << " (killed by signal " << WTERMSIG(status) << ")";
return INSTALL_ERROR;
} else {
LOG(FATAL) << "Invalid status code " << status;
@@ -503,153 +516,57 @@
return INSTALL_SUCCESS;
}
-// Verifes the compatibility info in a Treble-compatible package. Returns true directly if the
-// entry doesn't exist. Note that the compatibility info is packed in a zip file inside the OTA
-// package.
-bool verify_package_compatibility(ZipArchiveHandle package_zip) {
- LOG(INFO) << "Verifying package compatibility...";
-
- static constexpr const char* COMPATIBILITY_ZIP_ENTRY = "compatibility.zip";
- ZipString compatibility_entry_name(COMPATIBILITY_ZIP_ENTRY);
- ZipEntry compatibility_entry;
- if (FindEntry(package_zip, compatibility_entry_name, &compatibility_entry) != 0) {
- LOG(INFO) << "Package doesn't contain " << COMPATIBILITY_ZIP_ENTRY << " entry";
- return true;
- }
-
- std::string zip_content(compatibility_entry.uncompressed_length, '\0');
- int32_t ret;
- if ((ret = ExtractToMemory(package_zip, &compatibility_entry,
- reinterpret_cast<uint8_t*>(&zip_content[0]),
- compatibility_entry.uncompressed_length)) != 0) {
- LOG(ERROR) << "Failed to read " << COMPATIBILITY_ZIP_ENTRY << ": " << ErrorCodeString(ret);
- return false;
- }
-
- ZipArchiveHandle zip_handle;
- ret = OpenArchiveFromMemory(static_cast<void*>(const_cast<char*>(zip_content.data())),
- zip_content.size(), COMPATIBILITY_ZIP_ENTRY, &zip_handle);
- if (ret != 0) {
- LOG(ERROR) << "Failed to OpenArchiveFromMemory: " << ErrorCodeString(ret);
- return false;
- }
-
- // Iterate all the entries inside COMPATIBILITY_ZIP_ENTRY and read the contents.
- void* cookie;
- ret = StartIteration(zip_handle, &cookie, nullptr, nullptr);
- if (ret != 0) {
- LOG(ERROR) << "Failed to start iterating zip entries: " << ErrorCodeString(ret);
- CloseArchive(zip_handle);
- return false;
- }
- std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
-
- std::vector<std::string> compatibility_info;
- ZipEntry info_entry;
- ZipString info_name;
- while (Next(cookie, &info_entry, &info_name) == 0) {
- std::string content(info_entry.uncompressed_length, '\0');
- int32_t ret = ExtractToMemory(zip_handle, &info_entry, reinterpret_cast<uint8_t*>(&content[0]),
- info_entry.uncompressed_length);
- if (ret != 0) {
- LOG(ERROR) << "Failed to read " << info_name.name << ": " << ErrorCodeString(ret);
- CloseArchive(zip_handle);
- return false;
- }
- compatibility_info.emplace_back(std::move(content));
- }
- CloseArchive(zip_handle);
-
- // VintfObjectRecovery::CheckCompatibility returns zero on success.
- std::string err;
- int result = android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err);
- if (result == 0) {
- return true;
- }
-
- LOG(ERROR) << "Failed to verify package compatibility (result " << result << "): " << err;
- return false;
-}
-
-static int really_install_package(const std::string& path, bool* wipe_cache, bool needs_mount,
- std::vector<std::string>* log_buffer, int retry_count,
- int* max_temperature) {
+static InstallResult VerifyAndInstallPackage(Package* package, bool* wipe_cache,
+ std::vector<std::string>* log_buffer, int retry_count,
+ int* max_temperature) {
// ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
- // ui->Print("Finding update package...\n");
// Give verification half the progress bar...
// ui->SetProgressType(RecoveryUI::DETERMINATE);
// ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);
- LOG(INFO) << "Update location: " << path;
-
- // Map the update package into memory.
- // ui->Print("Opening update package...\n");
-
- if (needs_mount) {
- if (path[0] == '@') {
- ensure_path_mounted(path.substr(1));
- } else {
- ensure_path_mounted(path);
- }
- }
-
- auto package = Package::CreateMemoryPackage(
- path);
- if (!package) {
- log_buffer->push_back(android::base::StringPrintf("error: %d", kMapFileFailure));
- return INSTALL_CORRUPT;
- }
// Verify package.
- if (!verify_package(package.get())) {
+ if (!verify_package(package)) {
log_buffer->push_back(android::base::StringPrintf("error: %d", kZipVerificationFailure));
return INSTALL_CORRUPT;
}
- // Try to open the package.
- ZipArchiveHandle zip = package->GetZipArchiveHandle();
- if (!zip) {
- log_buffer->push_back(android::base::StringPrintf("error: %d", kZipOpenFailure));
- return INSTALL_CORRUPT;
- }
-
- // Additionally verify the compatibility of the package if it's a fresh install.
- if (retry_count == 0 && !verify_package_compatibility(zip)) {
- log_buffer->push_back(android::base::StringPrintf("error: %d", kPackageCompatibilityFailure));
- return INSTALL_CORRUPT;
- }
-
// Verify and install the contents of the package.
// ui->Print("Installing update...\n");
// if (retry_count > 0) {
// ui->Print("Retry attempt: %d\n", retry_count);
// }
// ui->SetEnableReboot(false);
- int result =
- try_update_binary(path, zip, wipe_cache, log_buffer, retry_count, max_temperature);
+ auto result = TryUpdateBinary(package, wipe_cache, log_buffer, retry_count, max_temperature);
// ui->SetEnableReboot(true);
// ui->Print("\n");
return result;
}
-int install_package(const std::string& path, bool should_wipe_cache, bool needs_mount,
- int retry_count) {
- CHECK(!path.empty());
-
+InstallResult InstallPackage(Package* package, const std::string_view package_id,
+ bool should_wipe_cache, int retry_count) {
auto start = std::chrono::system_clock::now();
int start_temperature = GetMaxValueFromThermalZone();
int max_temperature = start_temperature;
- int result;
+ InstallResult result;
std::vector<std::string> log_buffer;
- if (setup_install_mounts() != 0) {
+
+ // ui->Print("Supported API: %d\n", kRecoveryApiVersion);
+
+ // ui->Print("Finding update package...\n");
+ LOG(INFO) << "Update package id: " << package_id;
+ if (!package) {
+ log_buffer.push_back(android::base::StringPrintf("error: %d", kMapFileFailure));
+ result = INSTALL_CORRUPT;
+ } else if (setup_install_mounts() != 0) {
LOG(ERROR) << "failed to set up expected mounts for install; aborting";
result = INSTALL_ERROR;
} else {
bool updater_wipe_cache = false;
- result = really_install_package(path, &updater_wipe_cache, needs_mount, &log_buffer,
- retry_count, &max_temperature);
+ result = VerifyAndInstallPackage(package, &updater_wipe_cache, &log_buffer, retry_count,
+ &max_temperature);
should_wipe_cache = should_wipe_cache || updater_wipe_cache;
}
@@ -677,7 +594,7 @@
// The first two lines need to be the package name and install result.
std::vector<std::string> log_header = {
- path,
+ std::string(package_id),
result == INSTALL_SUCCESS ? "1" : "0",
"time_total: " + std::to_string(time_total),
"retry: " + std::to_string(retry_count),
@@ -736,3 +653,49 @@
}
return true;
}
+
+bool SetupPackageMount(const std::string& package_path, bool* should_use_fuse) {
+ CHECK(should_use_fuse != nullptr);
+
+ if (package_path.empty()) {
+ return false;
+ }
+
+ *should_use_fuse = true;
+ if (package_path[0] == '@') {
+ auto block_map_path = package_path.substr(1);
+ if (ensure_path_mounted(block_map_path) != 0) {
+ LOG(ERROR) << "Failed to mount " << block_map_path;
+ return false;
+ }
+ // uncrypt only produces block map only if the package stays on /data.
+ *should_use_fuse = false;
+ return true;
+ }
+
+ // Package is not a block map file.
+ if (ensure_path_mounted(package_path) != 0) {
+ LOG(ERROR) << "Failed to mount " << package_path;
+ return false;
+ }
+
+ // Reject the package if the input path doesn't equal the canonicalized path.
+ // e.g. /cache/../sdcard/update_package.
+ std::error_code ec;
+ auto canonical_path = std::filesystem::canonical(package_path, ec);
+ if (ec) {
+ LOG(ERROR) << "Failed to get canonical of " << package_path << ", " << ec.message();
+ return false;
+ }
+ if (canonical_path.string() != package_path) {
+ LOG(ERROR) << "Installation aborts. The canonical path " << canonical_path.string()
+ << " doesn't equal the original path " << package_path;
+ return false;
+ }
+
+ constexpr const char* CACHE_ROOT = "/cache";
+ if (android::base::StartsWith(package_path, CACHE_ROOT)) {
+ *should_use_fuse = false;
+ }
+ return true;
+}
diff --git a/install/legacy_property_service.cpp b/install/legacy_property_service.cpp
deleted file mode 100644
index c3990f7..0000000
--- a/install/legacy_property_service.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source 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 <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <dirent.h>
-#include <limits.h>
-#include <errno.h>
-
-#include "../../bionic/libc/private/bionic_futex.h"
-
-#include <cutils/properties.h>
-
-#include "legacy_properties.h"
-
-#include <sys/mman.h>
-// Not available in 5.0
-//#include <sys/atomics.h>
-#include "legacy_property_service.h"
-
-#ifndef INT32_MAX
-#define INT32_MAX (2147483647)
-#endif
-
-static int property_area_inited = 0;
-
-typedef struct {
- void *data;
- size_t size;
- int fd;
-} workspace;
-
-static int init_workspace(workspace *w, size_t size)
-{
- void *data;
- int fd;
-
- /* dev is a tmpfs that we can use to carve a shared workspace
- * out of, so let's do that...
- */
- fd = open("/dev/__legacy_properties__", O_RDWR | O_CREAT, 0600);
- if (fd < 0)
- return -1;
-
- if (ftruncate(fd, size) < 0)
- goto out;
-
- data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if(data == MAP_FAILED)
- goto out;
-
- close(fd);
-
- fd = open("/dev/__legacy_properties__", O_RDONLY);
- if (fd < 0)
- return -1;
-
- unlink("/dev/__legacy_properties__");
-
- w->data = data;
- w->size = size;
- w->fd = fd;
- return 0;
-
-out:
- close(fd);
- return -1;
-}
-
-/* (8 header words + 247 toc words) = 1020 bytes */
-/* 1024 bytes header and toc + 247 prop_infos @ 128 bytes = 32640 bytes */
-
-#define PA_COUNT_MAX 247
-#define PA_INFO_START 1024
-#define PA_SIZE 32768
-
-static workspace pa_workspace;
-static prop_info *pa_info_array;
-
-prop_area *__legacy_property_area__;
-
-static int init_property_area(void)
-{
- prop_area *pa;
-
- if(pa_info_array)
- return -1;
-
- if(init_workspace(&pa_workspace, PA_SIZE))
- return -1;
-
- fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
-
- pa_info_array = (prop_info*) (((char*) pa_workspace.data) + PA_INFO_START);
-
- pa = (prop_area*)(pa_workspace.data);
- memset(pa, 0, PA_SIZE);
- pa->magic = PROP_AREA_MAGIC;
- pa->version = PROP_AREA_VERSION;
-
- /* plug into the lib property services */
- __legacy_property_area__ = pa;
- property_area_inited = 1;
- return 0;
-}
-
-static void update_prop_info(prop_info *pi, const char *value, unsigned len)
-{
- pi->serial = pi->serial | 1;
- memcpy(pi->value, value, len + 1);
- pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
- __futex_wake(&pi->serial, INT32_MAX);
-}
-
-static const prop_info *__legacy_property_find(const char *name)
-{
- prop_area *pa = __legacy_property_area__;
- unsigned count = pa->count;
- unsigned *toc = pa->toc;
- unsigned len = strlen(name);
- prop_info *pi;
-
- while(count--) {
- unsigned entry = *toc++;
- if(TOC_NAME_LEN(entry) != len) continue;
-
- pi = TOC_TO_INFO(pa, entry);
- if(memcmp(name, pi->name, len)) continue;
-
- return pi;
- }
-
- return 0;
-}
-
-static int legacy_property_set(const char *name, const char *value)
-{
- prop_area *pa;
- prop_info *pi;
-
- int namelen = strlen(name);
- int valuelen = strlen(value);
-
- if(namelen >= PROP_NAME_MAX) return -1;
- if(valuelen >= PROP_VALUE_MAX) return -1;
- if(namelen < 1) return -1;
-
- pi = (prop_info*) __legacy_property_find(name);
-
-
- if(pi != 0) {
- /* ro.* properties may NEVER be modified once set */
- if(!strncmp(name, "ro.", 3)) return -1;
-
- pa = __legacy_property_area__;
- update_prop_info(pi, value, valuelen);
- pa->serial++;
- __futex_wake(&pa->serial, INT32_MAX);
- } else {
- pa = __legacy_property_area__;
- if(pa->count == PA_COUNT_MAX) return -1;
-
- pi = pa_info_array + pa->count;
- pi->serial = (valuelen << 24);
- memcpy(pi->name, name, namelen + 1);
- memcpy(pi->value, value, valuelen + 1);
-
- pa->toc[pa->count] =
- (namelen << 24) | (((unsigned long) pi) - ((unsigned long) pa));
-
- pa->count++;
- pa->serial++;
- __futex_wake(&pa->serial, INT32_MAX);
- }
-
- return 0;
-}
-
-void legacy_get_property_workspace(int *fd, int *sz)
-{
- *fd = pa_workspace.fd;
- *sz = pa_workspace.size;
-}
-
-static void copy_property_to_legacy(const char *key, const char *value, void *cookie __unused)
-{
- legacy_property_set(key, value);
-}
-
-int legacy_properties_init()
-{
- if(init_property_area() != 0)
- return -1;
-
- if(property_list(copy_property_to_legacy, 0) != 0)
- return -1;
-
- return 0;
-}
diff --git a/install/package.cpp b/install/package.cpp
index 22673cf..d3470bc 100755
--- a/install/package.cpp
+++ b/install/package.cpp
@@ -39,12 +39,20 @@
~MemoryPackage() override;
+ PackageType GetType() const override {
+ return PackageType::kMemory;
+ }
+
// Memory maps the package file if necessary. Initializes the start address and size of the
// package.
uint64_t GetPackageSize() const override {
return package_size_;
}
+ std::string GetPath() const override {
+ return path_;
+ }
+
bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override;
ZipArchiveHandle GetZipArchiveHandle() override;
@@ -81,10 +89,18 @@
~FilePackage() override;
+ PackageType GetType() const override {
+ return PackageType::kFile;
+ }
+
uint64_t GetPackageSize() const override {
return package_size_;
}
+ std::string GetPath() const override {
+ return path_;
+ }
+
bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override;
ZipArchiveHandle GetZipArchiveHandle() override;
@@ -248,7 +264,7 @@
return zip_handle_;
}
- if (auto err = OpenArchiveFd(fd_.get(), path_.c_str(), &zip_handle_); err != 0) {
+ if (auto err = OpenArchiveFd(fd_.get(), path_.c_str(), &zip_handle_, false); err != 0) {
LOG(ERROR) << "Can't open package" << path_ << " : " << ErrorCodeString(err);
return nullptr;
}
diff --git a/install/snapshot_utils.cpp b/install/snapshot_utils.cpp
new file mode 100644
index 0000000..7235e67
--- /dev/null
+++ b/install/snapshot_utils.cpp
@@ -0,0 +1,74 @@
+
+/*
+ * Copyright (C) 2019 The Android Open Source 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 <android-base/logging.h>
+#include <android-base/properties.h>
+#include <libsnapshot/snapshot.h>
+
+#include "recovery_ui/device.h"
+#include "recovery_ui/ui.h"
+#include "recovery_utils/roots.h"
+
+using android::snapshot::CreateResult;
+using android::snapshot::SnapshotManager;
+
+bool FinishPendingSnapshotMerges(Device* device) {
+ if (!android::base::GetBoolProperty("ro.virtual_ab.enabled", false)) {
+ return true;
+ }
+
+ RecoveryUI* ui = device->GetUI();
+ auto sm = SnapshotManager::NewForFirstStageMount();
+ if (!sm) {
+ ui->Print("Could not create SnapshotManager.\n");
+ return false;
+ }
+
+ auto callback = [&]() -> void {
+ double progress;
+ sm->GetUpdateState(&progress);
+ ui->Print("Waiting for merge to complete: %.2f\n", progress);
+ };
+ if (!sm->HandleImminentDataWipe(callback)) {
+ ui->Print("Unable to check merge status and/or complete update merge.\n");
+ return false;
+ }
+ return true;
+}
+
+bool CreateSnapshotPartitions() {
+ if (!android::base::GetBoolProperty("ro.virtual_ab.enabled", false)) {
+ // If the device does not support Virtual A/B, there's no need to create
+ // snapshot devices.
+ return true;
+ }
+
+ auto sm = SnapshotManager::NewForFirstStageMount();
+ if (!sm) {
+ // SnapshotManager could not be created. The device is still in a
+ // consistent state and can continue with the mounting of the existing
+ // devices, but cannot initialize snapshot devices.
+ LOG(WARNING) << "Could not create SnapshotManager";
+ return true;
+ }
+
+ auto ret = sm->RecoveryCreateSnapshotDevices();
+ if (ret == CreateResult::ERROR) {
+ return false;
+ }
+ return true;
+}
diff --git a/install/verifier.cpp b/install/verifier.cpp
index 6ba1d77..ab75044 100644
--- a/install/verifier.cpp
+++ b/install/verifier.cpp
@@ -311,8 +311,7 @@
static std::vector<Certificate> IterateZipEntriesAndSearchForKeys(const ZipArchiveHandle& handle) {
void* cookie;
- ZipString suffix("x509.pem");
- int32_t iter_status = StartIteration(handle, &cookie, nullptr, &suffix);
+ int32_t iter_status = StartIteration(handle, &cookie, "", "x509.pem");
if (iter_status != 0) {
LOG(ERROR) << "Failed to iterate over entries in the certificate zipfile: "
<< ErrorCodeString(iter_status);
@@ -321,22 +320,21 @@
std::vector<Certificate> result;
- ZipString name;
+ std::string_view name;
ZipEntry entry;
while ((iter_status = Next(cookie, &entry, &name)) == 0) {
std::vector<uint8_t> pem_content(entry.uncompressed_length);
if (int32_t extract_status =
ExtractToMemory(handle, &entry, pem_content.data(), pem_content.size());
extract_status != 0) {
- LOG(ERROR) << "Failed to extract " << std::string(name.name, name.name + name.name_length);
+ LOG(ERROR) << "Failed to extract " << name;
return {};
}
Certificate cert(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr);
// Aborts the parsing if we fail to load one of the key file.
if (!LoadCertificateFromBuffer(pem_content, &cert)) {
- LOG(ERROR) << "Failed to load keys from "
- << std::string(name.name, name.name + name.name_length);
+ LOG(ERROR) << "Failed to load keys from " << name;
return {};
}
diff --git a/install/wipe_data.cpp b/install/wipe_data.cpp
index b0e44c7..b2da76b 100755
--- a/install/wipe_data.cpp
+++ b/install/wipe_data.cpp
@@ -27,10 +27,11 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include "install/snapshot_utils.h"
#include "otautil/dirutil.h"
-#include "otautil/logging.h"
-#include "otautil/roots.h"
#include "recovery_ui/ui.h"
+#include "recovery_utils/logging.h"
+#include "recovery_utils/roots.h"
constexpr const char* CACHE_ROOT = "/cache";
constexpr const char* DATA_ROOT = "/data";
@@ -104,6 +105,12 @@
bool WipeData(Device* device, bool convert_fbe) {
// RecoveryUI* ui = device->GetUI();
// ui->Print("\n-- Wiping data...\n");
+
+ // if (!FinishPendingSnapshotMerges(device)) {
+ // ui->Print("Unable to check update status or complete merge, cannot wipe partitions.\n");
+ // return false;
+ // }
+
bool success = device->PreWipeData();
if (success) {
success &= EraseVolume(DATA_ROOT, convert_fbe);
@@ -120,4 +127,4 @@
}
// ui->Print("Data wipe %s.\n", success ? "complete" : "failed");
return success;
-}
\ No newline at end of file
+}
diff --git a/install/wipe_device.cpp b/install/wipe_device.cpp
new file mode 100644
index 0000000..d1cf89f
--- /dev/null
+++ b/install/wipe_device.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2019 The Android Open Source 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 "install/wipe_device.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/fs.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <ziparchive/zip_archive.h>
+
+#include "bootloader_message/bootloader_message.h"
+#include "install/install.h"
+#include "install/package.h"
+#include "recovery_ui/device.h"
+#include "recovery_ui/ui.h"
+
+std::vector<std::string> GetWipePartitionList(Package* wipe_package) {
+ ZipArchiveHandle zip = wipe_package->GetZipArchiveHandle();
+ if (!zip) {
+ LOG(ERROR) << "Failed to get ZipArchiveHandle";
+ return {};
+ }
+
+ constexpr char RECOVERY_WIPE_ENTRY_NAME[] = "recovery.wipe";
+
+ std::string partition_list_content;
+ ZipEntry entry;
+ if (FindEntry(zip, RECOVERY_WIPE_ENTRY_NAME, &entry) == 0) {
+ uint32_t length = entry.uncompressed_length;
+ partition_list_content = std::string(length, '\0');
+ if (auto err = ExtractToMemory(
+ zip, &entry, reinterpret_cast<uint8_t*>(partition_list_content.data()), length);
+ err != 0) {
+ LOG(ERROR) << "Failed to extract " << RECOVERY_WIPE_ENTRY_NAME << ": "
+ << ErrorCodeString(err);
+ return {};
+ }
+ } else {
+ LOG(INFO) << "Failed to find " << RECOVERY_WIPE_ENTRY_NAME
+ << ", falling back to use the partition list on device.";
+
+ constexpr char RECOVERY_WIPE_ON_DEVICE[] = "/etc/recovery.wipe";
+ if (!android::base::ReadFileToString(RECOVERY_WIPE_ON_DEVICE, &partition_list_content)) {
+ PLOG(ERROR) << "failed to read \"" << RECOVERY_WIPE_ON_DEVICE << "\"";
+ return {};
+ }
+ }
+
+ std::vector<std::string> result;
+ auto lines = android::base::Split(partition_list_content, "\n");
+ for (const auto& line : lines) {
+ auto partition = android::base::Trim(line);
+ // Ignore '#' comment or empty lines.
+ if (android::base::StartsWith(partition, "#") || partition.empty()) {
+ continue;
+ }
+ result.push_back(line);
+ }
+
+ return result;
+}
+
+// Secure-wipes a given partition. It uses BLKSECDISCARD, if supported. Otherwise, it goes with
+// BLKDISCARD (if device supports BLKDISCARDZEROES) or BLKZEROOUT.
+static bool SecureWipePartition(const std::string& partition) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(partition.c_str(), O_WRONLY)));
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open \"" << partition << "\"";
+ return false;
+ }
+
+ uint64_t range[2] = { 0, 0 };
+ if (ioctl(fd, BLKGETSIZE64, &range[1]) == -1 || range[1] == 0) {
+ PLOG(ERROR) << "Failed to get partition size";
+ return false;
+ }
+ LOG(INFO) << "Secure-wiping \"" << partition << "\" from " << range[0] << " to " << range[1];
+
+ LOG(INFO) << " Trying BLKSECDISCARD...";
+ if (ioctl(fd, BLKSECDISCARD, &range) == -1) {
+ PLOG(WARNING) << " Failed";
+
+ // Use BLKDISCARD if it zeroes out blocks, otherwise use BLKZEROOUT.
+ unsigned int zeroes;
+ if (ioctl(fd, BLKDISCARDZEROES, &zeroes) == 0 && zeroes != 0) {
+ LOG(INFO) << " Trying BLKDISCARD...";
+ if (ioctl(fd, BLKDISCARD, &range) == -1) {
+ PLOG(ERROR) << " Failed";
+ return false;
+ }
+ } else {
+ LOG(INFO) << " Trying BLKZEROOUT...";
+ if (ioctl(fd, BLKZEROOUT, &range) == -1) {
+ PLOG(ERROR) << " Failed";
+ return false;
+ }
+ }
+ }
+
+ LOG(INFO) << " Done";
+ return true;
+}
+
+static std::unique_ptr<Package> ReadWipePackage(size_t wipe_package_size) {
+ if (wipe_package_size == 0) {
+ LOG(ERROR) << "wipe_package_size is zero";
+ return nullptr;
+ }
+
+ std::string wipe_package;
+ if (std::string err_str; !read_wipe_package(&wipe_package, wipe_package_size, &err_str)) {
+ PLOG(ERROR) << "Failed to read wipe package" << err_str;
+ return nullptr;
+ }
+
+ return Package::CreateMemoryPackage(
+ std::vector<uint8_t>(wipe_package.begin(), wipe_package.end()));
+}
+
+// Checks if the wipe package matches expectation. If the check passes, reads the list of
+// partitions to wipe from the package. Checks include
+// 1. verify the package.
+// 2. check metadata (ota-type, pre-device and serial number if having one).
+static bool CheckWipePackage(Package* wipe_package, __attribute__((unused)) RecoveryUI* ui) {
+ if (!verify_package(wipe_package)) {
+ LOG(ERROR) << "Failed to verify package";
+ return false;
+ }
+
+ ZipArchiveHandle zip = wipe_package->GetZipArchiveHandle();
+ if (!zip) {
+ LOG(ERROR) << "Failed to get ZipArchiveHandle";
+ return false;
+ }
+
+ std::map<std::string, std::string> metadata;
+ if (!ReadMetadataFromPackage(zip, &metadata)) {
+ LOG(ERROR) << "Failed to parse metadata in the zip file";
+ return false;
+ }
+
+ return CheckPackageMetadata(metadata, OtaType::BRICK);
+}
+
+bool WipeAbDevice(Device* device, size_t wipe_package_size) {
+ auto ui = device->GetUI();
+ ui->SetBackground(RecoveryUI::ERASING);
+ ui->SetProgressType(RecoveryUI::INDETERMINATE);
+
+ auto wipe_package = ReadWipePackage(wipe_package_size);
+ if (!wipe_package) {
+ LOG(ERROR) << "Failed to open wipe package";
+ return false;
+ }
+
+ if (!CheckWipePackage(wipe_package.get(), ui)) {
+ LOG(ERROR) << "Failed to verify wipe package";
+ return false;
+ }
+
+ auto partition_list = GetWipePartitionList(wipe_package.get());
+ if (partition_list.empty()) {
+ LOG(ERROR) << "Empty wipe ab partition list";
+ return false;
+ }
+
+ for (const auto& partition : partition_list) {
+ // Proceed anyway even if it fails to wipe some partition.
+ SecureWipePartition(partition);
+ }
+ return true;
+}
diff --git a/install/zipwrap.cpp b/install/zipwrap.cpp
deleted file mode 100755
index ddd13de..0000000
--- a/install/zipwrap.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) TeamWin
- * This file is part of TWRP/TeamWin Recovery 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 "zipwrap.hpp"
-#include <string>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#ifdef USE_MINZIP
-#include "minzip/Zip.h"
-#include "minzip/SysUtil.h"
-#else
-#include <ziparchive/zip_archive.h>
-#include "ZipUtil.h"
-#include "otautil/sysutil.h"
-#endif
-
-ZipWrap::ZipWrap() {
- zip_open = false;
-}
-
-ZipWrap::~ZipWrap() {
- if (zip_open)
- Close();
-}
-
-bool ZipWrap::Open(const char* file, MemMapping* map) {
- if (zip_open) {
- printf("ZipWrap '%s' is already open\n", zip_file.c_str());
- return true;
- }
- zip_file = file;
-#ifdef USE_MINZIP
- if (mzOpenZipArchive(map->addr, map->length, &Zip) != 0)
- return false;
-#else
- if (OpenArchiveFromMemory(map->addr, map->length, file, &Zip) != 0)
- return false;
-#endif
- zip_open = true;
- return true;
-}
-
-void ZipWrap::Close() {
- if (zip_open)
-#ifdef USE_MINZIP
- mzCloseZipArchive(&Zip);
-#else
- CloseArchive(Zip);
-#endif
- zip_open = false;
-}
-
-bool ZipWrap::EntryExists(const string& filename) {
-#ifdef USE_MINZIP
- const ZipEntry* file_location = mzFindZipEntry(&Zip, filename.c_str());
- if (file_location != NULL)
- return true;
- return false;
-#else
- ZipString zip_string(filename.c_str());
- ZipEntry file_entry;
-
- if (FindEntry(Zip, zip_string, &file_entry) != 0)
- return false;
- return true;
-#endif
-}
-
-bool ZipWrap::ExtractEntry(const string& source_file, const string& target_file, mode_t mode) {
- if (access(target_file.c_str(), F_OK) == 0 && unlink(target_file.c_str()) != 0)
- printf("Unable to unlink '%s': %s\n", target_file.c_str(), strerror(errno));
-
- int fd = creat(target_file.c_str(), mode);
- if (fd < 0) {
- printf("Failed to create '%s'\n", target_file.c_str());
- return false;
- }
-
-#ifdef USE_MINZIP
- const ZipEntry* file_entry = mzFindZipEntry(&Zip, source_file.c_str());
- if (file_entry == NULL) {
- printf("'%s' does not exist in zip '%s'\n", source_file.c_str(), zip_file.c_str());
- return false;
- }
- int ret_val = mzExtractZipEntryToFile(&Zip, file_entry, fd);
- close(fd);
-
- if (!ret_val) {
- printf("Could not extract '%s'\n", target_file.c_str());
- return false;
- }
-#else
- ZipString zip_string(source_file.c_str());
- ZipEntry file_entry;
-
- if (FindEntry(Zip, zip_string, &file_entry) != 0)
- return false;
- int32_t ret_val = ExtractEntryToFile(Zip, &file_entry, fd);
- close(fd);
-
- if (ret_val != 0) {
- printf("Could not extract '%s'\n", target_file.c_str());
- return false;
- }
-#endif
- return true;
-}
-
-bool ZipWrap::ExtractRecursive(const string& source_dir, const string& target_dir) {
- struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
-#ifdef USE_MINZIP
- return mzExtractRecursive(&Zip, source_dir.c_str(), target_dir.c_str(), ×tamp, NULL, NULL, NULL);
-#else
- return ExtractPackageRecursive(Zip, source_dir, target_dir, ×tamp, NULL);
-#endif
-}
-
-long ZipWrap::GetUncompressedSize(const string& filename) {
-#ifdef USE_MINZIP
- const ZipEntry* file_entry = mzFindZipEntry(&Zip, filename.c_str());
- if (file_entry == NULL) {
- printf("'%s' does not exist in zip '%s'\n", filename.c_str(), zip_file.c_str());
- return 0;
- }
- return file_entry->uncompLen;
-#else
- ZipString zip_string(filename.c_str());
- ZipEntry file_entry;
-
- if (FindEntry(Zip, zip_string, &file_entry) != 0)
- return 0;
- return file_entry.uncompressed_length;
-#endif
-}
-
-bool ZipWrap::ExtractToBuffer(const string& filename, uint8_t* buffer) {
-#ifdef USE_MINZIP
- const ZipEntry* file_entry = mzFindZipEntry(&Zip, filename.c_str());
- if (file_entry == NULL) {
- printf("'%s' does not exist in zip '%s'\n", filename.c_str(), zip_file.c_str());
- return false;
- }
- if (!mzExtractZipEntryToBuffer(&Zip, file_entry, buffer)) {
- printf("Failed to read '%s'\n", filename.c_str());
- return false;
- }
-#else
- ZipString zip_string(filename.c_str());
- ZipEntry file_entry;
-
- if (FindEntry(Zip, zip_string, &file_entry) != 0)
- return false;
- if (ExtractToMemory(Zip, &file_entry, buffer, file_entry.uncompressed_length) != 0) {
- printf("Failed to read '%s'\n", filename.c_str());
- return false;
- }
-#endif
- return true;
-}
-
-#ifdef USE_MINZIP
-loff_t ZipWrap::GetEntryOffset(const string& filename) {
- const ZipEntry* file_entry = mzFindZipEntry(&Zip, filename.c_str());
- if (file_entry == NULL) {
- printf("'%s' does not exist in zip '%s'\n", filename.c_str(), zip_file.c_str());
- return 0;
- }
- return mzGetZipEntryOffset(file_entry);
-}
-#else
-off64_t ZipWrap::GetEntryOffset(const string& filename) {
- ZipString zip_string(filename.c_str());
- ZipEntry file_entry;
-
- if (FindEntry(Zip, zip_string, &file_entry) != 0) {
- printf("'%s' does not exist in zip '%s'\n", filename.c_str(), zip_file.c_str());
- return 0;
- }
- return file_entry.offset;
-}
-
-ZipArchiveHandle ZipWrap::GetZipArchiveHandle() {
- return Zip;
-}
-#endif
diff --git a/libaosprecovery_defaults.go b/libaosprecovery_defaults.go
new file mode 100644
index 0000000..608942b
--- /dev/null
+++ b/libaosprecovery_defaults.go
@@ -0,0 +1,68 @@
+package liba_defaults
+
+import (
+ "android/soong/android"
+ "android/soong/cc"
+)
+
+func globalFlags(ctx android.BaseContext) []string {
+ var cflags []string
+
+ if ctx.AConfig().Getenv("AB_OTA_UPDATER") == "true" {
+ cflags = append(cflags, "-DAB_OTA_UPDATER=1")
+ }
+ return cflags
+}
+
+func globalSrcs(ctx android.BaseContext) []string {
+ var srcs []string
+
+ if ctx.AConfig().Getenv("TWRP_CUSTOM_KEYBOARD") != "" {
+ srcs = append(srcs, ctx.AConfig().Getenv("TWRP_CUSTOM_KEYBOARD"))
+ }
+
+ return srcs
+}
+
+func globalIncludes(ctx android.BaseContext) []string {
+ var includes []string
+
+ if ctx.AConfig().Getenv("TW_INCLUDE_CRYPTO") != "" {
+ includes = append(includes, "bootable/recovery/crypto/fscrypt")
+ }
+
+ return includes
+}
+
+func libAospRecoveryDefaults(ctx android.LoadHookContext) {
+ type props struct {
+ Target struct {
+ Android struct {
+ Cflags []string
+ Enabled *bool
+ }
+ }
+ Cflags []string
+ Srcs []string
+ Include_dirs []string
+ }
+
+ p := &props{}
+ p.Cflags = globalFlags(ctx)
+ s := globalSrcs(ctx)
+ p.Srcs = s
+ i := globalIncludes(ctx)
+ p.Include_dirs = i
+ ctx.AppendProperties(p)
+}
+
+func init() {
+ android.RegisterModuleType("libaosprecovery_defaults", libAospRecoveryDefaultsFactory)
+}
+
+func libAospRecoveryDefaultsFactory() android.Module {
+ module := cc.DefaultsFactory()
+ android.AddLoadHook(module, libAospRecoveryDefaults)
+
+ return module
+}
diff --git a/libpixelflinger/Android.bp b/libpixelflinger/Android.bp
new file mode 100644
index 0000000..5721394
--- /dev/null
+++ b/libpixelflinger/Android.bp
@@ -0,0 +1,105 @@
+//bootstrap_go_package {
+// name: "soong-libpixelflingertwrp_defaults",
+// pkgPath: "bootable/recovery/libpixelflinger",
+// deps: [
+// "soong",
+// "soong-android",
+// "soong-cc"
+// ],
+// srcs: [
+// "libpixelflingertwrp_defaults.go"
+// ],
+// pluginFor: ["soong_build"]
+//}
+
+//libpixelflingertwrp_defaults {
+// name: "libpixelflingertwrp_defaults"
+//}
+
+cc_defaults {
+ name: "libpixelflingertwrp_defaults",
+
+ cflags: [
+ "-fstrict-aliasing",
+ "-fomit-frame-pointer",
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-function",
+ ],
+ export_include_dirs: ["include"],
+ header_libs: ["libbase_headers"],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+
+ arch: {
+ arm: {
+ neon: {
+ cflags: ["-D__ARM_HAVE_NEON"],
+ },
+ },
+ },
+}
+
+cc_library_static {
+ name: "libpixelflinger_twrp",
+ defaults: ["libpixelflingertwrp_defaults"],
+
+ srcs: [
+ "codeflinger/ARMAssemblerInterface.cpp",
+ "codeflinger/ARMAssemblerProxy.cpp",
+ "codeflinger/CodeCache.cpp",
+ "codeflinger/GGLAssembler.cpp",
+ "codeflinger/load_store.cpp",
+ "codeflinger/blending.cpp",
+ "codeflinger/texturing.cpp",
+ "format.cpp",
+ "clear.cpp",
+ "raster.cpp",
+ "buffer.cpp",
+ ],
+ whole_static_libs: ["libpixelflinger-arm"],
+
+ arch: {
+ arm: {
+ srcs: [
+ "codeflinger/ARMAssembler.cpp",
+ "codeflinger/disassem.c",
+ "col32cb16blend.S",
+ "t32cb16blend.S",
+ ],
+
+ neon: {
+ srcs: ["col32cb16blend_neon.S"],
+ },
+ },
+ arm64: {
+ srcs: [
+ "codeflinger/Arm64Assembler.cpp",
+ "codeflinger/Arm64Disassembler.cpp",
+ "arch-arm64/col32cb16blend.S",
+ "arch-arm64/t32cb16blend.S",
+ ],
+ },
+ mips: {
+ mips32r6: {
+ srcs: [
+ "codeflinger/MIPSAssembler.cpp",
+ "codeflinger/mips_disassem.c",
+ "arch-mips/t32cb16blend.S",
+ ],
+ },
+ },
+ mips64: {
+ srcs: [
+ "codeflinger/MIPSAssembler.cpp",
+ "codeflinger/MIPS64Assembler.cpp",
+ "codeflinger/mips64_disassem.c",
+ "arch-mips64/col32cb16blend.S",
+ "arch-mips64/t32cb16blend.S",
+ ],
+ },
+ },
+}
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk.orig
similarity index 94%
rename from libpixelflinger/Android.mk
rename to libpixelflinger/Android.mk.orig
index 439c835..5a0bc79 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk.orig
@@ -76,14 +76,6 @@
arch-arm64/col32cb16blend.S \
arch-arm64/t32cb16blend.S \
-ifndef ARCH_MIPS_REV6
-PIXELFLINGER_SRC_FILES_mips := \
- codeflinger/MIPSAssembler.cpp \
- codeflinger/mips_disassem.c \
- arch-mips/t32cb16blend.S \
-
-endif
-
#
# Static library version
#
diff --git a/libpixelflinger/MODULE_LICENSE_APACHE2 b/libpixelflinger/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libpixelflinger/MODULE_LICENSE_APACHE2
diff --git a/libpixelflinger/NOTICE b/libpixelflinger/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libpixelflinger/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/libpixelflinger/arch-arm64/col32cb16blend.S b/libpixelflinger/arch-arm64/col32cb16blend.S
new file mode 100644
index 0000000..84596f9
--- /dev/null
+++ b/libpixelflinger/arch-arm64/col32cb16blend.S
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * 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.
+ *
+ * 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.
+ */
+ .text
+ .balign 0
+
+ .global scanline_col32cb16blend_arm64
+
+//
+// This function alpha blends a fixed color into a destination scanline, using
+// the formula:
+//
+// d = s + (((a + (a >> 7)) * d) >> 8)
+//
+// where d is the destination pixel,
+// s is the source color,
+// a is the alpha channel of the source color.
+//
+
+// x0 = destination buffer pointer
+// w1 = color value
+// w2 = count
+
+
+scanline_col32cb16blend_arm64:
+
+ lsr w5, w1, #24 // shift down alpha
+ mov w9, #0xff // create mask
+ add w5, w5, w5, lsr #7 // add in top bit
+ mov w4, #256 // create #0x100
+ sub w5, w4, w5 // invert alpha
+ and w10, w1, #0xff // extract red
+ and w12, w9, w1, lsr #8 // extract green
+ and w4, w9, w1, lsr #16 // extract blue
+ lsl w10, w10, #5 // prescale red
+ lsl w12, w12, #6 // prescale green
+ lsl w4, w4, #5 // prescale blue
+ lsr w9, w9, #2 // create dest green mask
+
+1:
+ ldrh w8, [x0] // load dest pixel
+ subs w2, w2, #1 // decrement loop counter
+ lsr w6, w8, #11 // extract dest red
+ and w7, w9, w8, lsr #5 // extract dest green
+ and w8, w8, #0x1f // extract dest blue
+
+ madd w6, w6, w5, w10 // dest red * alpha + src red
+ madd w7, w7, w5, w12 // dest green * alpha + src green
+ madd w8, w8, w5, w4 // dest blue * alpha + src blue
+
+ lsr w6, w6, #8 // shift down red
+ lsr w7, w7, #8 // shift down green
+ lsl w6, w6, #11 // shift red into 565
+ orr w6, w6, w7, lsl #5 // shift green into 565
+ orr w6, w6, w8, lsr #8 // shift blue into 565
+
+ strh w6, [x0], #2 // store pixel to dest, update ptr
+ b.ne 1b // if count != 0, loop
+
+ ret
+
+
+
diff --git a/libpixelflinger/arch-arm64/t32cb16blend.S b/libpixelflinger/arch-arm64/t32cb16blend.S
new file mode 100644
index 0000000..a9733c0
--- /dev/null
+++ b/libpixelflinger/arch-arm64/t32cb16blend.S
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * 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.
+ *
+ * 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.
+ */
+ .text
+ .balign 0
+
+ .global scanline_t32cb16blend_arm64
+
+/*
+ * .macro pixel
+ *
+ * This macro alpha blends RGB565 original pixel located in either
+ * top or bottom 16 bits of DREG register with SRC 32 bit pixel value
+ * and writes the result to FB register
+ *
+ * \DREG is a 32-bit register containing *two* original destination RGB565
+ * pixels, with the even one in the low-16 bits, and the odd one in the
+ * high 16 bits.
+ *
+ * \SRC is a 32-bit 0xAABBGGRR pixel value, with pre-multiplied colors.
+ *
+ * \FB is a target register that will contain the blended pixel values.
+ *
+ * \ODD is either 0 or 1 and indicates if we're blending the lower or
+ * upper 16-bit pixels in DREG into FB
+ *
+ *
+ * clobbered: w6, w7, w15, w16, w17
+ *
+ */
+
+.macro pixel, DREG, SRC, FB, ODD
+
+ // SRC = 0xAABBGGRR
+ lsr w7, \SRC, #24 // sA
+ add w7, w7, w7, lsr #7 // sA + (sA >> 7)
+ mov w6, #0x100
+ sub w7, w6, w7 // sA = 0x100 - (sA+(sA>>7))
+
+1:
+
+.if \ODD //Blending odd pixel present in top 16 bits of DREG register
+
+ // red
+ lsr w16, \DREG, #(16 + 11)
+ mul w16, w7, w16
+ lsr w6, \SRC, #3
+ and w6, w6, #0x1F
+ add w16, w6, w16, lsr #8
+ cmp w16, #0x1F
+ orr w17, \FB, #(0x1F<<(16 + 11))
+ orr w15, \FB, w16, lsl #(16 + 11)
+ csel \FB, w17, w15, hi
+ // green
+ and w6, \DREG, #(0x3F<<(16 + 5))
+ lsr w17,w6,#(16+5)
+ mul w6, w7, w17
+ lsr w16, \SRC, #(8+2)
+ and w16, w16, #0x3F
+ add w6, w16, w6, lsr #8
+ cmp w6, #0x3F
+ orr w17, \FB, #(0x3F<<(16 + 5))
+ orr w15, \FB, w6, lsl #(16 + 5)
+ csel \FB, w17, w15, hi
+ // blue
+ and w16, \DREG, #(0x1F << 16)
+ lsr w17,w16,#16
+ mul w16, w7, w17
+ lsr w6, \SRC, #(8+8+3)
+ and w6, w6, #0x1F
+ add w16, w6, w16, lsr #8
+ cmp w16, #0x1F
+ orr w17, \FB, #(0x1F << 16)
+ orr w15, \FB, w16, lsl #16
+ csel \FB, w17, w15, hi
+
+.else //Blending even pixel present in bottom 16 bits of DREG register
+
+ // red
+ lsr w16, \DREG, #11
+ and w16, w16, #0x1F
+ mul w16, w7, w16
+ lsr w6, \SRC, #3
+ and w6, w6, #0x1F
+ add w16, w6, w16, lsr #8
+ cmp w16, #0x1F
+ mov w17, #(0x1F<<11)
+ lsl w15, w16, #11
+ csel \FB, w17, w15, hi
+
+
+ // green
+ and w6, \DREG, #(0x3F<<5)
+ mul w6, w7, w6
+ lsr w16, \SRC, #(8+2)
+ and w16, w16, #0x3F
+ add w6, w16, w6, lsr #(5+8)
+ cmp w6, #0x3F
+ orr w17, \FB, #(0x3F<<5)
+ orr w15, \FB, w6, lsl #5
+ csel \FB, w17, w15, hi
+
+ // blue
+ and w16, \DREG, #0x1F
+ mul w16, w7, w16
+ lsr w6, \SRC, #(8+8+3)
+ and w6, w6, #0x1F
+ add w16, w6, w16, lsr #8
+ cmp w16, #0x1F
+ orr w17, \FB, #0x1F
+ orr w15, \FB, w16
+ csel \FB, w17, w15, hi
+
+.endif // End of blending even pixel
+
+.endm // End of pixel macro
+
+
+// x0: dst ptr
+// x1: src ptr
+// w2: count
+// w3: d
+// w4: s0
+// w5: s1
+// w6: pixel
+// w7: pixel
+// w8: free
+// w9: free
+// w10: free
+// w11: free
+// w12: scratch
+// w14: pixel
+
+scanline_t32cb16blend_arm64:
+
+ // align DST to 32 bits
+ tst x0, #0x3
+ b.eq aligned
+ subs w2, w2, #1
+ b.lo return
+
+last:
+ ldr w4, [x1], #4
+ ldrh w3, [x0]
+ pixel w3, w4, w12, 0
+ strh w12, [x0], #2
+
+aligned:
+ subs w2, w2, #2
+ b.lo 9f
+
+ // The main loop is unrolled twice and processes 4 pixels
+8:
+ ldp w4,w5, [x1], #8
+ add x0, x0, #4
+ // it's all zero, skip this pixel
+ orr w3, w4, w5
+ cbz w3, 7f
+
+ // load the destination
+ ldr w3, [x0, #-4]
+ // stream the destination
+ pixel w3, w4, w12, 0
+ pixel w3, w5, w12, 1
+ str w12, [x0, #-4]
+
+ // 2nd iteration of the loop, don't stream anything
+ subs w2, w2, #2
+ csel w4, w5, w4, lt
+ blt 9f
+ ldp w4,w5, [x1], #8
+ add x0, x0, #4
+ orr w3, w4, w5
+ cbz w3, 7f
+ ldr w3, [x0, #-4]
+ pixel w3, w4, w12, 0
+ pixel w3, w5, w12, 1
+ str w12, [x0, #-4]
+
+7: subs w2, w2, #2
+ bhs 8b
+ mov w4, w5
+
+9: adds w2, w2, #1
+ b.lo return
+ b last
+
+return:
+ ret
diff --git a/libpixelflinger/arch-mips/col32cb16blend.S b/libpixelflinger/arch-mips/col32cb16blend.S
new file mode 100644
index 0000000..810294c
--- /dev/null
+++ b/libpixelflinger/arch-mips/col32cb16blend.S
@@ -0,0 +1,134 @@
+/*
+** Copyright 2015, The Android Open Source 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.
+*/
+
+ .macro pixel dreg src f sR sG sB shift
+
+#if __mips==32 && __mips_isa_rev>=2
+ /* extract red */
+ ext $t4,\src,\shift+11,5
+ mul $t4,$t4,\f
+
+ /* extract green */
+ ext $t5,\src,\shift+5,6
+ mul $t5,$t5,\f
+
+ /* extract blue */
+ ext $t6,\src,\shift,5
+ mul $t6,$t6,\f
+#else
+ /* extract red */
+ srl $t4,\src,\shift+11
+ andi $t4, 0x1f
+ mul $t4,$t4,\f
+
+ /* extract green */
+ srl $t5,\src,\shift+5
+ andi $t5, 0x3f
+ mul $t5,$t5,\f
+
+ /* extract blue */
+ srl $t6,\src,\shift
+ andi $t6, 0x1f
+ mul $t6,$t6,\f
+#endif
+
+ srl $t4,$t4,8
+ srl $t5,$t5,8
+ srl $t6,$t6,8
+ addu $t4,$t4,\sR
+ addu $t5,$t5,\sG
+ addu \dreg,$t6,\sB
+ sll $t4,$t4,11
+ sll $t5,$t5,5
+ or \dreg,\dreg,$t4
+ or \dreg,\dreg,$t5
+ andi \dreg, 0xffff
+ .endm
+
+ .text
+ .balign 4
+
+ .global scanline_col32cb16blend_mips
+ .ent scanline_col32cb16blend_mips
+scanline_col32cb16blend_mips:
+
+ /* check if count is zero */
+ srl $v0,$a1,24 /* sA */
+ beqz $a2,done
+ li $t4, 0x100
+ srl $v1,$v0,7
+ addu $v0,$v1,$v0
+ subu $v0,$t4,$v0 /* f */
+#if __mips==32 && __mips_isa_rev>=2
+ ext $a3,$a1,3,5 /* sR */
+ ext $t0,$a1,10,6 /* sG */
+ ext $t1,$a1,19,5 /* sB */
+#else
+ srl $a3, $a1, 3
+ andi $a3, 0x1f /* sR */
+ srl $t0, $a1, 10
+ andi $t0, 0x3f /* sG */
+ srl $t1, $a1, 19
+ andi $t1, 0x1f /* sB */
+#endif
+
+ /* check if cnt is at least 4 */
+ addiu $a2,$a2,-4
+ bltz $a2,tail
+
+loop_4pixels:
+ lw $t7,0($a0)
+ lw $t8,4($a0)
+ addiu $a0,$a0,8
+ addiu $a2,$a2,-4
+ pixel $t2 $t7 $v0 $a3 $t0 $t1 0
+ pixel $t3 $t7 $v0 $a3 $t0 $t1 16
+#if __mips==32 && __mips_isa_rev>=2
+ ins $t2,$t3,16,16
+#else
+ sll $t3, 16
+ or $t2, $t2, $t3
+#endif
+ pixel $t7 $t8 $v0 $a3 $t0 $t1 0
+ pixel $t3 $t8 $v0 $a3 $t0 $t1 16
+#if __mips==32 && __mips_isa_rev>=2
+ ins $t7,$t3,16,16
+#else
+ sll $t3, 16
+ or $t7, $t7, $t3
+#endif
+ sw $t2,-8($a0)
+ sw $t7,-4($a0)
+ bgez $a2, loop_4pixels
+
+tail:
+ /* the pixel count underran, restore it now */
+ addiu $a2,$a2,4
+
+ /* handle the last 0..3 pixels */
+ beqz $a2,done
+
+loop_1pixel:
+ lhu $t7,0($a0)
+ addiu $a0,$a0,2
+ addiu $a2,$a2,-1
+ pixel $t2 $t7 $v0 $a3 $t0 $t1 0
+ sh $t2, -2($a0)
+ bnez $a2,loop_1pixel
+
+done:
+ j $ra
+ .end scanline_col32cb16blend_mips
diff --git a/libpixelflinger/arch-mips/t32cb16blend.S b/libpixelflinger/arch-mips/t32cb16blend.S
new file mode 100644
index 0000000..1d2fb8f
--- /dev/null
+++ b/libpixelflinger/arch-mips/t32cb16blend.S
@@ -0,0 +1,273 @@
+/* libs/pixelflinger/t32cb16blend.S
+**
+** Copyright 2010, The Android Open Source 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.
+*/
+
+#ifdef DEBUG
+#define DBG
+#else
+#define DBG #
+#endif
+
+/*
+ * blend one of 2 16bpp RGB pixels held in dreg selected by shift
+ * with the 32bpp ABGR pixel held in src and store the result in fb
+ *
+ * Assumes that the dreg data is little endian and that
+ * the the second pixel (shift==16) will be merged into
+ * the fb result
+ *
+ * Uses $t0,$t6,$t7,$t8
+ */
+
+#if __mips==32 && __mips_isa_rev>=2
+ .macro pixel dreg src fb shift
+ /*
+ * sA = s >> 24
+ * f = 0x100 - (sA + (sA>>7))
+ */
+DBG .set noat
+DBG rdhwr $at,$2
+DBG .set at
+
+ srl $t7,\src,24
+ srl $t6,$t7,7
+ addu $t7,$t6
+ li $t6,0x100
+ subu $t7,$t6,$t7
+
+ /* red */
+ ext $t8,\dreg,\shift+6+5,5 # dst[\shift:15..11]
+ mul $t6,$t8,$t7
+ ext $t0,\dreg,\shift+5,6 # start green extraction dst[\shift:10..5]
+ ext $t8,\src,3,5 # src[7..3]
+ srl $t6,8
+ addu $t8,$t6
+.if \shift!=0
+ sll $t8,\shift+11
+ or \fb,$t8
+.else
+ sll \fb,$t8,11
+.endif
+
+ /* green */
+ mul $t8,$t0,$t7
+ ext $t0,\dreg,\shift,5 # start blue extraction dst[\shift:4..0]
+ ext $t6,\src,2+8,6 # src[15..10]
+ srl $t8,8
+ addu $t8,$t6
+
+ /* blue */
+ mul $t0,$t0,$t7
+ sll $t8, $t8, \shift+5
+ or \fb, \fb, $t8
+ ext $t6,\src,(3+8+8),5
+ srl $t8,$t0,8
+ addu $t8,$t6
+ sll $t8, $t8, \shift
+ or \fb, \fb, $t8
+
+DBG .set noat
+DBG rdhwr $t8,$2
+DBG subu $t8,$at
+DBG sltu $at,$t8,$v0
+DBG movn $v0,$t8,$at
+DBG sgtu $at,$t8,$v1
+DBG movn $v1,$t8,$at
+DBG .set at
+ .endm
+
+#else
+
+ .macro pixel dreg src fb shift
+ /*
+ * sA = s >> 24
+ * f = 0x100 - (sA + (sA>>7))
+ */
+DBG .set push
+DBG .set noat
+DBG .set mips32r2
+DBG rdhwr $at,$2
+DBG .set pop
+
+ srl $t7,\src,24
+ srl $t6,$t7,7
+ addu $t7,$t6
+ li $t6,0x100
+ subu $t7,$t6,$t7
+
+ /*
+ * red
+ * dR = (d >> (6 + 5)) & 0x1f;
+ * dR = (f*dR)>>8
+ * sR = (s >> ( 3)) & 0x1f;
+ * sR += dR
+ * fb |= sR << 11
+ */
+ srl $t8,\dreg,\shift+6+5
+.if \shift==0
+ and $t8,0x1f
+.endif
+ mul $t8,$t8,$t7
+ srl $t6,\src,3
+ and $t6,0x1f
+ srl $t8,8
+ addu $t8,$t6
+.if \shift!=0
+ sll $t8,\shift+11
+ or \fb,$t8
+.else
+ sll \fb,$t8,11
+.endif
+
+ /*
+ * green
+ * dG = (d >> 5) & 0x3f
+ * dG = (f*dG) >> 8
+ * sG = (s >> ( 8+2))&0x3F;
+ */
+ srl $t8,\dreg,\shift+5
+ and $t8,0x3f
+ mul $t8,$t8,$t7
+ srl $t6,\src,8+2
+ and $t6,0x3f
+ srl $t8,8
+ addu $t8,$t6
+ sll $t8,\shift + 5
+ or \fb,$t8
+
+ /* blue */
+.if \shift!=0
+ srl $t8,\dreg,\shift
+ and $t8,0x1f
+.else
+ and $t8,\dreg,0x1f
+.endif
+ mul $t8,$t8,$t7
+ srl $t6,\src,(8+8+3)
+ and $t6,0x1f
+ srl $t8,8
+ addu $t8,$t6
+.if \shift!=0
+ sll $t8,\shift
+.endif
+ or \fb,$t8
+DBG .set push
+DBG .set noat
+DBG .set mips32r2
+DBG rdhwr $t8,$2
+DBG subu $t8,$at
+DBG sltu $at,$t8,$v0
+DBG movn $v0,$t8,$at
+DBG sgtu $at,$t8,$v1
+DBG movn $v1,$t8,$at
+DBG .set pop
+ .endm
+#endif
+
+ .text
+ .balign 4
+
+ .global scanline_t32cb16blend_mips
+ .ent scanline_t32cb16blend_mips
+scanline_t32cb16blend_mips:
+DBG li $v0,0xffffffff
+DBG li $v1,0
+ /* Align the destination if necessary */
+ and $t0,$a0,3
+ beqz $t0,aligned
+
+ /* as long as there is at least one pixel */
+ beqz $a2,done
+
+ lw $t4,($a1)
+ addu $a0,2
+ addu $a1,4
+ beqz $t4,1f
+ lhu $t3,-2($a0)
+ pixel $t3,$t4,$t1,0
+ sh $t1,-2($a0)
+1: subu $a2,1
+
+aligned:
+ /* Check to see if its worth unrolling the loop */
+ subu $a2,4
+ bltz $a2,tail
+
+ /* Process 4 pixels at a time */
+fourpixels:
+ /* 1st pair of pixels */
+ lw $t4,0($a1)
+ lw $t5,4($a1)
+ addu $a0,8
+ addu $a1,16
+
+ /* both are zero, skip this pair */
+ or $t3,$t4,$t5
+ beqz $t3,1f
+
+ /* load the destination */
+ lw $t3,-8($a0)
+
+ pixel $t3,$t4,$t1,0
+ andi $t1, 0xFFFF
+ pixel $t3,$t5,$t1,16
+ sw $t1,-8($a0)
+
+1:
+ /* 2nd pair of pixels */
+ lw $t4,-8($a1)
+ lw $t5,-4($a1)
+
+ /* both are zero, skip this pair */
+ or $t3,$t4,$t5
+ beqz $t3,1f
+
+ /* load the destination */
+ lw $t3,-4($a0)
+
+ pixel $t3,$t4,$t1,0
+ andi $t1, 0xFFFF
+ pixel $t3,$t5,$t1,16
+ sw $t1,-4($a0)
+
+1: subu $a2,4
+ bgtz $a2,fourpixels
+
+tail:
+ /* the pixel count underran, restore it now */
+ addu $a2,4
+
+ /* handle the last 0..3 pixels */
+ beqz $a2,done
+onepixel:
+ lw $t4,($a1)
+ addu $a0,2
+ addu $a1,4
+ beqz $t4,1f
+ lhu $t3,-2($a0)
+ pixel $t3,$t4,$t1,0
+ sh $t1,-2($a0)
+1: subu $a2,1
+ bnez $a2,onepixel
+done:
+DBG .set push
+DBG .set mips32r2
+DBG rdhwr $a0,$3
+DBG mul $v0,$a0
+DBG mul $v1,$a0
+DBG .set pop
+ j $ra
+ .end scanline_t32cb16blend_mips
diff --git a/libpixelflinger/arch-mips64/col32cb16blend.S b/libpixelflinger/arch-mips64/col32cb16blend.S
new file mode 100644
index 0000000..5baffb1
--- /dev/null
+++ b/libpixelflinger/arch-mips64/col32cb16blend.S
@@ -0,0 +1,108 @@
+/*
+** Copyright 2015, The Android Open Source 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.
+*/
+
+ .macro pixel dreg src f sR sG sB shift
+
+ /* extract red */
+.if \shift < 32
+ dext $t0,\src,\shift+11,5
+.else
+ dextu $t0,\src,\shift+11,5
+.endif
+ mul $t0,$t0,\f
+
+ /* extract green */
+.if \shift < 32
+ dext $t1,\src,\shift+5,6
+.else
+ dextu $t1,\src,\shift+5,6
+.endif
+ mul $t1,$t1,\f
+
+ /* extract blue */
+.if \shift < 32
+ dext $t2,\src,\shift,5
+.else
+ dextu $t2,\src,\shift,5
+.endif
+ mul $t2,$t2,\f
+
+ srl $t0,$t0,8
+ srl $t1,$t1,8
+ srl $t2,$t2,8
+ addu $t0,$t0,\sR
+ addu $t1,$t1,\sG
+ addu \dreg,$t2,\sB
+ sll $t0,$t0,11
+ sll $t1,$t1,5
+ or \dreg,\dreg,$t0
+ or \dreg,\dreg,$t1
+ .endm
+
+ .text
+ .balign 4
+
+ .global scanline_col32cb16blend_mips64
+ .ent scanline_col32cb16blend_mips64
+scanline_col32cb16blend_mips64:
+
+ /* check if count is zero */
+ srl $v0,$a1,24 /* sA */
+ beqz $a2,done
+ li $t0, 0x100
+ srl $v1,$v0,7
+ addu $v0,$v1,$v0
+ subu $v0,$t0,$v0 /* f */
+ ext $a3,$a1,3,5 /* sR */
+ ext $a4,$a1,10,6 /* sG */
+ ext $a5,$a1,19,5 /* sB */
+
+ /* check if cnt is at least 4 */
+ addiu $a2,$a2,-4
+ bltz $a2,tail
+
+loop_4pixels:
+ ld $t3,0($a0)
+ daddiu $a0,$a0,8
+ addiu $a2,$a2,-4
+ pixel $a6 $t3 $v0 $a3 $a4 $a5 0
+ pixel $a7 $t3 $v0 $a3 $a4 $a5 16
+ pixel $t8 $t3 $v0 $a3 $a4 $a5 32
+ pixel $t9 $t3 $v0 $a3 $a4 $a5 48
+ dins $a6,$a7,16,16
+ dinsu $a6,$t8,32,16
+ dinsu $a6,$t9,48,16
+ sd $a6,-8($a0)
+ bgez $a2, loop_4pixels
+
+tail:
+ /* the pixel count underran, restore it now */
+ addiu $a2,$a2,4
+
+ /* handle the last 0..3 pixels */
+ beqz $a2,done
+
+loop_1pixel:
+ lhu $t3,0($a0)
+ daddiu $a0,$a0,2
+ addiu $a2,$a2,-1
+ pixel $a6 $t3 $v0 $a3 $a4 $a5 0
+ sh $a6, -2($a0)
+ bnez $a2,loop_1pixel
+
+done:
+ j $ra
+ .end scanline_col32cb16blend_mips64
diff --git a/libpixelflinger/arch-mips64/t32cb16blend.S b/libpixelflinger/arch-mips64/t32cb16blend.S
new file mode 100644
index 0000000..3cb5f93
--- /dev/null
+++ b/libpixelflinger/arch-mips64/t32cb16blend.S
@@ -0,0 +1,172 @@
+/*
+** Copyright 2015, The Android Open Source 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.
+*/
+
+#ifdef DEBUG
+#define DBG
+#else
+#define DBG #
+#endif
+
+/*
+ * blend one of 2 16bpp RGB pixels held in dreg selected by shift
+ * with the 32bpp ABGR pixel held in src and store the result in fb
+ *
+ * Assumes that the dreg data is little endian and that
+ * the the second pixel (shift==16) will be merged into
+ * the fb result
+ *
+ * Uses $a4,$t2,$t3,$t8
+ */
+
+ .macro pixel dreg src fb shift
+ /*
+ * sA = s >> 24
+ * f = 0x100 - (sA + (sA>>7))
+ */
+ srl $t3,\src,24
+ srl $t2,$t3,7
+ addu $t3,$t2
+ li $t2,0x100
+ subu $t3,$t2,$t3
+
+ /* red */
+ ext $t8,\dreg,\shift+6+5,5 # dst[\shift:15..11]
+ mul $t2,$t8,$t3
+ ext $a4,\dreg,\shift+5,6 # start green extraction dst[\shift:10..5]
+ ext $t8,\src,3,5 # src[7..3]
+ srl $t2,8
+ addu $t8,$t2
+.if \shift!=0
+ sll $t8,\shift+11 # dst[\shift:15..11]
+ or \fb,$t8
+.else
+ sll \fb,$t8,11
+.endif
+
+ /* green */
+ mul $t8,$a4,$t3
+ ext $a4,\dreg,\shift,5 # start blue extraction dst[\shift:4..0]
+ ext $t2,\src,2+8,6 # src[15..10]
+ srl $t8,8
+ addu $t8,$t2
+
+ /* blue */
+ mul $a4,$a4,$t3
+ sll $t8, $t8, \shift+5 # finish green insertion dst[\shift:10..5]
+ or \fb, \fb, $t8
+ ext $t2,\src,(3+8+8),5
+ srl $t8,$a4,8
+ addu $t8,$t2
+ sll $t8, $t8, \shift
+ or \fb, \fb, $t8
+ .endm
+
+ .text
+ .balign 4
+
+ .global scanline_t32cb16blend_mips64
+ .ent scanline_t32cb16blend_mips64
+scanline_t32cb16blend_mips64:
+ daddiu $sp, $sp, -40
+DBG li $v0,0xffffffff
+DBG li $v1,0
+ /* Align the destination if necessary */
+ and $a4,$a0,3
+ beqz $a4,aligned
+
+ /* as long as there is at least one pixel */
+ beqz $a2,done
+
+ lw $t0,($a1)
+ daddu $a0,2
+ daddu $a1,4
+ beqz $t0,1f
+ lhu $a7,-2($a0)
+ pixel $a7,$t0,$a5,0
+ sh $a5,-2($a0)
+1: subu $a2,1
+
+aligned:
+ /* Check to see if its worth unrolling the loop */
+ subu $a2,4
+ bltz $a2,tail
+
+ /* Process 4 pixels at a time */
+fourpixels:
+ /* 1st pair of pixels */
+ lw $t0,0($a1)
+ lw $t1,4($a1)
+ daddu $a0,8
+ daddu $a1,16
+
+ /* both are zero, skip this pair */
+ or $a7,$t0,$t1
+ beqz $a7,1f
+
+ /* load the destination */
+ lw $a7,-8($a0)
+
+ pixel $a7,$t0,$a5,0
+ andi $a5, 0xFFFF
+ pixel $a7,$t1,$a5,16
+ sw $a5,-8($a0)
+
+1:
+ /* 2nd pair of pixels */
+ lw $t0,-8($a1)
+ lw $t1,-4($a1)
+
+ /* both are zero, skip this pair */
+ or $a7,$t0,$t1
+ beqz $a7,1f
+
+ /* load the destination */
+ lw $a7,-4($a0)
+
+ pixel $a7,$t0,$a5,0
+ andi $a5, 0xFFFF
+ pixel $a7,$t1,$a5,16
+ sw $a5,-4($a0)
+
+1: subu $a2,4
+ bgtz $a2,fourpixels
+
+tail:
+ /* the pixel count underran, restore it now */
+ addu $a2,4
+
+ /* handle the last 0..3 pixels */
+ beqz $a2,done
+onepixel:
+ lw $t0,($a1)
+ daddu $a0,2
+ daddu $a1,4
+ beqz $t0,1f
+ lhu $a7,-2($a0)
+ pixel $a7,$t0,$a5,0
+ sh $a5,-2($a0)
+1: subu $a2,1
+ bnez $a2,onepixel
+done:
+DBG .set push
+DBG .set mips32r2
+DBG rdhwr $a0,$3
+DBG mul $v0,$a0
+DBG mul $v1,$a0
+DBG .set pop
+ daddiu $sp, $sp, 40
+ j $ra
+ .end scanline_t32cb16blend_mips64
diff --git a/libpixelflinger/buffer.cpp b/libpixelflinger/buffer.cpp
new file mode 100644
index 0000000..ea9514c
--- /dev/null
+++ b/libpixelflinger/buffer.cpp
@@ -0,0 +1,389 @@
+/* libs/pixelflinger/buffer.cpp
+**
+** Copyright 2006, The Android Open Source 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 <assert.h>
+
+#include <android-base/macros.h>
+
+#include "buffer.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+static void read_pixel(const surface_t* s, context_t* c,
+ uint32_t x, uint32_t y, pixel_t* pixel);
+static void write_pixel(const surface_t* s, context_t* c,
+ uint32_t x, uint32_t y, const pixel_t* pixel);
+static void readRGB565(const surface_t* s, context_t* c,
+ uint32_t x, uint32_t y, pixel_t* pixel);
+static void readABGR8888(const surface_t* s, context_t* c,
+ uint32_t x, uint32_t y, pixel_t* pixel);
+
+static uint32_t logic_op(int op, uint32_t s, uint32_t d);
+static uint32_t extract(uint32_t v, int h, int l, int bits);
+static uint32_t expand(uint32_t v, int sbits, int dbits);
+static uint32_t downshift_component(uint32_t in, uint32_t v,
+ int sh, int sl, int dh, int dl, int ch, int cl, int dither);
+
+// ----------------------------------------------------------------------------
+
+void ggl_init_texture(context_t* c)
+{
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ texture_t& t = c->state.texture[i];
+ t.s_coord = GGL_ONE_TO_ONE;
+ t.t_coord = GGL_ONE_TO_ONE;
+ t.s_wrap = GGL_REPEAT;
+ t.t_wrap = GGL_REPEAT;
+ t.min_filter = GGL_NEAREST;
+ t.mag_filter = GGL_NEAREST;
+ t.env = GGL_MODULATE;
+ }
+ c->activeTMU = &(c->state.texture[0]);
+}
+
+void ggl_set_surface(context_t* c, surface_t* dst, const GGLSurface* src)
+{
+ dst->width = src->width;
+ dst->height = src->height;
+ dst->stride = src->stride;
+ dst->data = src->data;
+ dst->format = src->format;
+ dst->dirty = 1;
+ if (__builtin_expect(dst->stride < 0, false)) {
+ const GGLFormat& pixelFormat(c->formats[dst->format]);
+ const int32_t bpr = -dst->stride * pixelFormat.size;
+ dst->data += bpr * (dst->height-1);
+ }
+}
+
+static void pick_read_write(surface_t* s)
+{
+ // Choose best reader/writers.
+ switch (s->format) {
+ case GGL_PIXEL_FORMAT_RGBA_8888: s->read = readABGR8888; break;
+ case GGL_PIXEL_FORMAT_RGB_565: s->read = readRGB565; break;
+ default: s->read = read_pixel; break;
+ }
+ s->write = write_pixel;
+}
+
+void ggl_pick_texture(context_t* c)
+{
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
+ surface_t& s = c->state.texture[i].surface;
+ if ((!c->state.texture[i].enable) || (!s.dirty))
+ continue;
+ s.dirty = 0;
+ pick_read_write(&s);
+ generated_tex_vars_t& gen = c->generated_vars.texture[i];
+ gen.width = s.width;
+ gen.height = s.height;
+ gen.stride = s.stride;
+ gen.data = uintptr_t(s.data);
+ }
+}
+
+void ggl_pick_cb(context_t* c)
+{
+ surface_t& s = c->state.buffers.color;
+ if (s.dirty) {
+ s.dirty = 0;
+ pick_read_write(&s);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void read_pixel(const surface_t* s, context_t* c,
+ uint32_t x, uint32_t y, pixel_t* pixel)
+{
+ assert((x < s->width) && (y < s->height));
+
+ const GGLFormat* f = &(c->formats[s->format]);
+ int32_t index = x + (s->stride * y);
+ uint8_t* const data = s->data + index * f->size;
+ uint32_t v = 0;
+ switch (f->size) {
+ case 1: v = *data; break;
+ case 2: v = *(uint16_t*)data; break;
+ case 3: v = (data[2]<<16)|(data[1]<<8)|data[0]; break;
+ case 4: v = GGL_RGBA_TO_HOST(*(uint32_t*)data); break;
+ }
+ for (int i=0 ; i<4 ; i++) {
+ pixel->s[i] = f->c[i].h - f->c[i].l;
+ if (pixel->s[i])
+ pixel->c[i] = extract(v, f->c[i].h, f->c[i].l, f->size*8);
+ }
+}
+
+void readRGB565(const surface_t* s, context_t* /*c*/,
+ uint32_t x, uint32_t y, pixel_t* pixel)
+{
+ uint16_t v = *(reinterpret_cast<uint16_t*>(s->data) + (x + (s->stride * y)));
+ pixel->c[0] = 0;
+ pixel->c[1] = v>>11;
+ pixel->c[2] = (v>>5)&0x3F;
+ pixel->c[3] = v&0x1F;
+ pixel->s[0] = 0;
+ pixel->s[1] = 5;
+ pixel->s[2] = 6;
+ pixel->s[3] = 5;
+}
+
+void readABGR8888(const surface_t* s, context_t* /*c*/,
+ uint32_t x, uint32_t y, pixel_t* pixel)
+{
+ uint32_t v = *(reinterpret_cast<uint32_t*>(s->data) + (x + (s->stride * y)));
+ v = GGL_RGBA_TO_HOST(v);
+ pixel->c[0] = v>>24; // A
+ pixel->c[1] = v&0xFF; // R
+ pixel->c[2] = (v>>8)&0xFF; // G
+ pixel->c[3] = (v>>16)&0xFF; // B
+ pixel->s[0] =
+ pixel->s[1] =
+ pixel->s[2] =
+ pixel->s[3] = 8;
+}
+
+void write_pixel(const surface_t* s, context_t* c,
+ uint32_t x, uint32_t y, const pixel_t* pixel)
+{
+ assert((x < s->width) && (y < s->height));
+
+ int dither = -1;
+ if (c->state.enables & GGL_ENABLE_DITHER) {
+ dither = c->ditherMatrix[ (x & GGL_DITHER_MASK) +
+ ((y & GGL_DITHER_MASK)<<GGL_DITHER_ORDER_SHIFT) ];
+ }
+
+ const GGLFormat* f = &(c->formats[s->format]);
+ int32_t index = x + (s->stride * y);
+ uint8_t* const data = s->data + index * f->size;
+
+ uint32_t mask = 0;
+ uint32_t v = 0;
+ for (int i=0 ; i<4 ; i++) {
+ const int component_mask = 1 << i;
+ if (f->components>=GGL_LUMINANCE &&
+ (i==GGLFormat::GREEN || i==GGLFormat::BLUE)) {
+ // destinations L formats don't have G or B
+ continue;
+ }
+ const int l = f->c[i].l;
+ const int h = f->c[i].h;
+ if (h && (c->state.mask.color & component_mask)) {
+ mask |= (((1<<(h-l))-1)<<l);
+ uint32_t u = pixel->c[i];
+ int32_t pixelSize = pixel->s[i];
+ if (pixelSize < (h-l)) {
+ u = expand(u, pixelSize, h-l);
+ pixelSize = h-l;
+ }
+ v = downshift_component(v, u, pixelSize, 0, h, l, 0, 0, dither);
+ }
+ }
+
+ if ((c->state.mask.color != 0xF) ||
+ (c->state.enables & GGL_ENABLE_LOGIC_OP)) {
+ uint32_t d = 0;
+ switch (f->size) {
+ case 1: d = *data; break;
+ case 2: d = *(uint16_t*)data; break;
+ case 3: d = (data[2]<<16)|(data[1]<<8)|data[0]; break;
+ case 4: d = GGL_RGBA_TO_HOST(*(uint32_t*)data); break;
+ }
+ if (c->state.enables & GGL_ENABLE_LOGIC_OP) {
+ v = logic_op(c->state.logic_op.opcode, v, d);
+ v &= mask;
+ }
+ v |= (d & ~mask);
+ }
+
+ switch (f->size) {
+ case 1: *data = v; break;
+ case 2: *(uint16_t*)data = v; break;
+ case 3:
+ data[0] = v;
+ data[1] = v>>8;
+ data[2] = v>>16;
+ break;
+ case 4: *(uint32_t*)data = GGL_HOST_TO_RGBA(v); break;
+ }
+}
+
+static uint32_t logic_op(int op, uint32_t s, uint32_t d)
+{
+ switch(op) {
+ case GGL_CLEAR: return 0;
+ case GGL_AND: return s & d;
+ case GGL_AND_REVERSE: return s & ~d;
+ case GGL_COPY: return s;
+ case GGL_AND_INVERTED: return ~s & d;
+ case GGL_NOOP: return d;
+ case GGL_XOR: return s ^ d;
+ case GGL_OR: return s | d;
+ case GGL_NOR: return ~(s | d);
+ case GGL_EQUIV: return ~(s ^ d);
+ case GGL_INVERT: return ~d;
+ case GGL_OR_REVERSE: return s | ~d;
+ case GGL_COPY_INVERTED: return ~s;
+ case GGL_OR_INVERTED: return ~s | d;
+ case GGL_NAND: return ~(s & d);
+ case GGL_SET: return ~0;
+ };
+ return s;
+}
+
+
+uint32_t ggl_expand(uint32_t v, int sbits, int dbits)
+{
+ return expand(v, sbits, dbits);
+}
+
+uint32_t ggl_pack_color(context_t* c, int32_t format,
+ GGLcolor r, GGLcolor g, GGLcolor b, GGLcolor a)
+{
+ const GGLFormat* f = &(c->formats[format]);
+ uint32_t p = 0;
+ const int32_t hbits = GGL_COLOR_BITS;
+ const int32_t lbits = GGL_COLOR_BITS - 8;
+ p = downshift_component(p, r, hbits, lbits, f->rh, f->rl, 0, 1, -1);
+ p = downshift_component(p, g, hbits, lbits, f->gh, f->gl, 0, 1, -1);
+ p = downshift_component(p, b, hbits, lbits, f->bh, f->bl, 0, 1, -1);
+ p = downshift_component(p, a, hbits, lbits, f->ah, f->al, 0, 1, -1);
+ switch (f->size) {
+ case 1:
+ p |= p << 8;
+ FALLTHROUGH_INTENDED;
+ case 2:
+ p |= p << 16;
+ }
+ return p;
+}
+
+// ----------------------------------------------------------------------------
+
+// extract a component from a word
+uint32_t extract(uint32_t v, int h, int l, int bits)
+{
+ assert(h);
+ if (l) {
+ v >>= l;
+ }
+ if (h != bits) {
+ v &= (1<<(h-l))-1;
+ }
+ return v;
+}
+
+// expand a component from sbits to dbits
+uint32_t expand(uint32_t v, int sbits, int dbits)
+{
+ if (dbits > sbits) {
+ assert(sbits);
+ if (sbits==1) {
+ v = (v<<dbits) - v;
+ } else {
+ if (dbits % sbits) {
+ v <<= (dbits-sbits);
+ dbits -= sbits;
+ do {
+ v |= v>>sbits;
+ dbits -= sbits;
+ sbits *= 2;
+ } while (dbits>0);
+ } else {
+ dbits -= sbits;
+ do {
+ v |= v<<sbits;
+ dbits -= sbits;
+ if (sbits*2 < dbits) {
+ sbits *= 2;
+ }
+ } while (dbits > 0);
+ }
+ }
+ }
+ return v;
+}
+
+// downsample a component from sbits to dbits
+// and shift / construct the pixel
+uint32_t downshift_component( uint32_t in, uint32_t v,
+ int sh, int sl, // src
+ int dh, int dl, // dst
+ int ch, int cl, // clear
+ int dither)
+{
+ const int sbits = sh-sl;
+ const int dbits = dh-dl;
+
+ assert(sbits>=dbits);
+
+
+ if (sbits>dbits) {
+ if (dither>=0) {
+ v -= (v>>dbits); // fix up
+ const int shift = (GGL_DITHER_BITS - (sbits-dbits));
+ if (shift >= 0) v += (dither >> shift) << sl;
+ else v += (dither << (-shift)) << sl;
+ } else {
+ // don't do that right now, so we can reproduce the same
+ // artifacts we get on ARM (Where we don't do this)
+ // -> this is not really needed if we don't dither
+ //if (dBits > 1) { // result already OK if dBits==1
+ // v -= (v>>dbits); // fix up
+ // v += 1 << ((sbits-dbits)-1); // rounding
+ //}
+ }
+ }
+
+
+ // we need to clear the high bits of the source
+ if (ch) {
+ v <<= 32-sh;
+ sl += 32-sh;
+ sh = 32;
+ }
+
+ if (dl) {
+ if (cl || (sbits>dbits)) {
+ v >>= sh-dbits;
+ sl = 0;
+ sh = dbits;
+ in |= v<<dl;
+ } else {
+ // sbits==dbits and we don't need to clean the lower bits
+ // so we just have to shift the component to the right location
+ int shift = dh-sh;
+ in |= v<<shift;
+ }
+ } else {
+ // destination starts at bit 0
+ // ie: sh-dh == sh-dbits
+ int shift = sh-dh;
+ if (shift > 0) in |= v>>shift;
+ else if (shift < 0) in |= v<<shift;
+ else in |= v;
+ }
+ return in;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/libpixelflinger/buffer.h b/libpixelflinger/buffer.h
new file mode 100644
index 0000000..9c9e4bc
--- /dev/null
+++ b/libpixelflinger/buffer.h
@@ -0,0 +1,39 @@
+/* libs/pixelflinger/buffer.h
+**
+** Copyright 2006, The Android Open Source 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.
+*/
+
+
+#ifndef ANDROID_GGL_TEXTURE_H
+#define ANDROID_GGL_TEXTURE_H
+
+#include <private/pixelflinger/ggl_context.h>
+
+namespace android {
+
+void ggl_init_texture(context_t* c);
+
+void ggl_set_surface(context_t* c, surface_t* dst, const GGLSurface* src);
+
+void ggl_pick_texture(context_t* c);
+void ggl_pick_cb(context_t* c);
+
+uint32_t ggl_expand(uint32_t v, int sbits, int dbits);
+uint32_t ggl_pack_color(context_t* c, int32_t format,
+ GGLcolor r, GGLcolor g, GGLcolor b, GGLcolor a);
+
+}; // namespace android
+
+#endif // ANDROID_GGL_TEXTURE_H
diff --git a/libpixelflinger/clear.cpp b/libpixelflinger/clear.cpp
new file mode 100644
index 0000000..b962456
--- /dev/null
+++ b/libpixelflinger/clear.cpp
@@ -0,0 +1,171 @@
+/* libs/pixelflinger/clear.cpp
+**
+** Copyright 2006, The Android Open Source 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 <cutils/memory.h>
+
+#include "clear.h"
+#include "buffer.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static void ggl_clear(void* c, GGLbitfield mask);
+static void ggl_clearColorx(void* c,
+ GGLclampx r, GGLclampx g, GGLclampx b, GGLclampx a);
+static void ggl_clearDepthx(void* c, GGLclampx depth);
+static void ggl_clearStencil(void* c, GGLint s);
+
+// ----------------------------------------------------------------------------
+
+void ggl_init_clear(context_t* c)
+{
+ GGLContext& procs = *(GGLContext*)c;
+ GGL_INIT_PROC(procs, clear);
+ GGL_INIT_PROC(procs, clearColorx);
+ GGL_INIT_PROC(procs, clearDepthx);
+ GGL_INIT_PROC(procs, clearStencil);
+ c->state.clear.dirty = GGL_STENCIL_BUFFER_BIT |
+ GGL_COLOR_BUFFER_BIT |
+ GGL_DEPTH_BUFFER_BIT;
+ c->state.clear.depth = FIXED_ONE;
+}
+
+// ----------------------------------------------------------------------------
+
+static void memset2d(context_t* c, const surface_t& s, uint32_t packed,
+ uint32_t l, uint32_t t, uint32_t w, uint32_t h)
+{
+ const uint32_t size = c->formats[s.format].size;
+ const int32_t stride = s.stride * size;
+ uint8_t* dst = (uint8_t*)s.data + (l + t*s.stride)*size;
+ w *= size;
+
+ if (ggl_likely(int32_t(w) == stride)) {
+ // clear the whole thing in one call
+ w *= h;
+ h = 1;
+ }
+
+ switch (size) {
+ case 1:
+ do {
+ memset(dst, packed, w);
+ dst += stride;
+ } while(--h);
+ break;
+ case 2:
+ do {
+ android_memset16((uint16_t*)dst, packed, w);
+ dst += stride;
+ } while(--h);
+ break;
+ case 3: // XXX: 24-bit clear.
+ break;
+ case 4:
+ do {
+ android_memset32((uint32_t*)dst, packed, w);
+ dst += stride;
+ } while(--h);
+ break;
+ }
+}
+
+static inline GGLfixed fixedToZ(GGLfixed z) {
+ return GGLfixed(((int64_t(z) << 16) - z) >> 16);
+}
+
+static void ggl_clear(void* con, GGLbitfield mask)
+{
+ GGL_CONTEXT(c, con);
+
+ // XXX: rgba-dithering, rgba-masking
+ // XXX: handle all formats of Z and S
+
+ const uint32_t l = c->state.scissor.left;
+ const uint32_t t = c->state.scissor.top;
+ uint32_t w = c->state.scissor.right - l;
+ uint32_t h = c->state.scissor.bottom - t;
+
+ if (!w || !h)
+ return;
+
+ // unexsiting buffers have no effect...
+ if (c->state.buffers.color.format == 0)
+ mask &= ~GGL_COLOR_BUFFER_BIT;
+
+ if (c->state.buffers.depth.format == 0)
+ mask &= ~GGL_DEPTH_BUFFER_BIT;
+
+ if (c->state.buffers.stencil.format == 0)
+ mask &= ~GGL_STENCIL_BUFFER_BIT;
+
+ if (mask & GGL_COLOR_BUFFER_BIT) {
+ if (c->state.clear.dirty & GGL_COLOR_BUFFER_BIT) {
+ c->state.clear.dirty &= ~GGL_COLOR_BUFFER_BIT;
+
+ uint32_t colorPacked = ggl_pack_color(c,
+ c->state.buffers.color.format,
+ gglFixedToIteratedColor(c->state.clear.r),
+ gglFixedToIteratedColor(c->state.clear.g),
+ gglFixedToIteratedColor(c->state.clear.b),
+ gglFixedToIteratedColor(c->state.clear.a));
+
+ c->state.clear.colorPacked = GGL_HOST_TO_RGBA(colorPacked);
+ }
+ const uint32_t packed = c->state.clear.colorPacked;
+ memset2d(c, c->state.buffers.color, packed, l, t, w, h);
+ }
+ if (mask & GGL_DEPTH_BUFFER_BIT) {
+ if (c->state.clear.dirty & GGL_DEPTH_BUFFER_BIT) {
+ c->state.clear.dirty &= ~GGL_DEPTH_BUFFER_BIT;
+ uint32_t depth = fixedToZ(c->state.clear.depth);
+ c->state.clear.depthPacked = (depth<<16)|depth;
+ }
+ const uint32_t packed = c->state.clear.depthPacked;
+ memset2d(c, c->state.buffers.depth, packed, l, t, w, h);
+ }
+
+ // XXX: do stencil buffer
+}
+
+static void ggl_clearColorx(void* con,
+ GGLclampx r, GGLclampx g, GGLclampx b, GGLclampx a)
+{
+ GGL_CONTEXT(c, con);
+ c->state.clear.r = gglClampx(r);
+ c->state.clear.g = gglClampx(g);
+ c->state.clear.b = gglClampx(b);
+ c->state.clear.a = gglClampx(a);
+ c->state.clear.dirty |= GGL_COLOR_BUFFER_BIT;
+}
+
+static void ggl_clearDepthx(void* con, GGLclampx depth)
+{
+ GGL_CONTEXT(c, con);
+ c->state.clear.depth = gglClampx(depth);
+ c->state.clear.dirty |= GGL_DEPTH_BUFFER_BIT;
+}
+
+static void ggl_clearStencil(void* con, GGLint s)
+{
+ GGL_CONTEXT(c, con);
+ c->state.clear.stencil = s;
+ c->state.clear.dirty |= GGL_STENCIL_BUFFER_BIT;
+}
+
+}; // namespace android
diff --git a/libpixelflinger/clear.h b/libpixelflinger/clear.h
new file mode 100644
index 0000000..b071df0
--- /dev/null
+++ b/libpixelflinger/clear.h
@@ -0,0 +1,30 @@
+/* libs/pixelflinger/clear.h
+**
+** Copyright 2006, The Android Open Source 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.
+*/
+
+#ifndef ANDROID_GGL_CLEAR_H
+#define ANDROID_GGL_CLEAR_H
+
+#include <pixelflinger/pixelflinger.h>
+#include <private/pixelflinger/ggl_context.h>
+
+namespace android {
+
+void ggl_init_clear(context_t* c);
+
+}; // namespace android
+
+#endif // ANDROID_GGL_CLEAR_H
diff --git a/libpixelflinger/codeflinger/ARMAssembler.cpp b/libpixelflinger/codeflinger/ARMAssembler.cpp
new file mode 100644
index 0000000..f47b6e4
--- /dev/null
+++ b/libpixelflinger/codeflinger/ARMAssembler.cpp
@@ -0,0 +1,579 @@
+/* libs/pixelflinger/codeflinger/ARMAssembler.cpp
+**
+** Copyright 2006, The Android Open Source 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.
+*/
+
+#define LOG_TAG "ARMAssembler"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cutils/properties.h>
+#include <log/log.h>
+#include <private/pixelflinger/ggl_context.h>
+
+#include "ARMAssembler.h"
+#include "CodeCache.h"
+#include "disassem.h"
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark ARMAssembler...
+#endif
+
+ARMAssembler::ARMAssembler(const sp<Assembly>& assembly)
+ : ARMAssemblerInterface(),
+ mAssembly(assembly)
+{
+ mBase = mPC = (uint32_t *)assembly->base();
+ mDuration = ggl_system_time();
+}
+
+ARMAssembler::~ARMAssembler()
+{
+}
+
+uint32_t* ARMAssembler::pc() const
+{
+ return mPC;
+}
+
+uint32_t* ARMAssembler::base() const
+{
+ return mBase;
+}
+
+void ARMAssembler::reset()
+{
+ mBase = mPC = (uint32_t *)mAssembly->base();
+ mBranchTargets.clear();
+ mLabels.clear();
+ mLabelsInverseMapping.clear();
+ mComments.clear();
+}
+
+int ARMAssembler::getCodegenArch()
+{
+ return CODEGEN_ARCH_ARM;
+}
+
+// ----------------------------------------------------------------------------
+
+void ARMAssembler::disassemble(const char* name)
+{
+ if (name) {
+ printf("%s:\n", name);
+ }
+ size_t count = pc()-base();
+ uint32_t* i = base();
+ while (count--) {
+ ssize_t label = mLabelsInverseMapping.indexOfKey(i);
+ if (label >= 0) {
+ printf("%s:\n", mLabelsInverseMapping.valueAt(label));
+ }
+ ssize_t comment = mComments.indexOfKey(i);
+ if (comment >= 0) {
+ printf("; %s\n", mComments.valueAt(comment));
+ }
+ printf("%08x: %08x ", uintptr_t(i), int(i[0]));
+ ::disassemble((uintptr_t)i);
+ i++;
+ }
+}
+
+void ARMAssembler::comment(const char* string)
+{
+ mComments.add(mPC, string);
+}
+
+void ARMAssembler::label(const char* theLabel)
+{
+ mLabels.add(theLabel, mPC);
+ mLabelsInverseMapping.add(mPC, theLabel);
+}
+
+void ARMAssembler::B(int cc, const char* label)
+{
+ mBranchTargets.add(branch_target_t(label, mPC));
+ *mPC++ = (cc<<28) | (0xA<<24) | 0;
+}
+
+void ARMAssembler::BL(int cc, const char* label)
+{
+ mBranchTargets.add(branch_target_t(label, mPC));
+ *mPC++ = (cc<<28) | (0xB<<24) | 0;
+}
+
+#if 0
+#pragma mark -
+#pragma mark Prolog/Epilog & Generate...
+#endif
+
+
+void ARMAssembler::prolog()
+{
+ // write dummy prolog code
+ mPrologPC = mPC;
+ STM(AL, FD, SP, 1, LSAVED);
+}
+
+void ARMAssembler::epilog(uint32_t touched)
+{
+ touched &= LSAVED;
+ if (touched) {
+ // write prolog code
+ uint32_t* pc = mPC;
+ mPC = mPrologPC;
+ STM(AL, FD, SP, 1, touched | LLR);
+ mPC = pc;
+ // write epilog code
+ LDM(AL, FD, SP, 1, touched | LLR);
+ BX(AL, LR);
+ } else { // heh, no registers to save!
+ // write prolog code
+ uint32_t* pc = mPC;
+ mPC = mPrologPC;
+ MOV(AL, 0, R0, R0); // NOP
+ mPC = pc;
+ // write epilog code
+ BX(AL, LR);
+ }
+}
+
+int ARMAssembler::generate(const char* name)
+{
+ // fixup all the branches
+ size_t count = mBranchTargets.size();
+ while (count--) {
+ const branch_target_t& bt = mBranchTargets[count];
+ uint32_t* target_pc = mLabels.valueFor(bt.label);
+ LOG_ALWAYS_FATAL_IF(!target_pc,
+ "error resolving branch targets, target_pc is null");
+ int32_t offset = int32_t(target_pc - (bt.pc+2));
+ *bt.pc |= offset & 0xFFFFFF;
+ }
+
+ mAssembly->resize( int(pc()-base())*4 );
+
+ // the instruction cache is flushed by CodeCache
+ const int64_t duration = ggl_system_time() - mDuration;
+ const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
+ ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.pf.disasm", value, "0");
+ if (atoi(value) != 0) {
+ printf(format, name, int(pc()-base()), base(), pc(), duration);
+ disassemble(name);
+ }
+
+ return OK;
+}
+
+uint32_t* ARMAssembler::pcForLabel(const char* label)
+{
+ return mLabels.valueFor(label);
+}
+
+// ----------------------------------------------------------------------------
+
+#if 0
+#pragma mark -
+#pragma mark Data Processing...
+#endif
+
+void ARMAssembler::dataProcessing(int opcode, int cc,
+ int s, int Rd, int Rn, uint32_t Op2)
+{
+ *mPC++ = (cc<<28) | (opcode<<21) | (s<<20) | (Rn<<16) | (Rd<<12) | Op2;
+}
+
+#if 0
+#pragma mark -
+#pragma mark Multiply...
+#endif
+
+// multiply...
+void ARMAssembler::MLA(int cc, int s,
+ int Rd, int Rm, int Rs, int Rn) {
+ if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
+ LOG_FATAL_IF(Rd==Rm, "MLA(r%u,r%u,r%u,r%u)", Rd,Rm,Rs,Rn);
+ *mPC++ = (cc<<28) | (1<<21) | (s<<20) |
+ (Rd<<16) | (Rn<<12) | (Rs<<8) | 0x90 | Rm;
+}
+void ARMAssembler::MUL(int cc, int s,
+ int Rd, int Rm, int Rs) {
+ if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
+ LOG_FATAL_IF(Rd==Rm, "MUL(r%u,r%u,r%u)", Rd,Rm,Rs);
+ *mPC++ = (cc<<28) | (s<<20) | (Rd<<16) | (Rs<<8) | 0x90 | Rm;
+}
+void ARMAssembler::UMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs) {
+ LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
+ "UMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
+ *mPC++ = (cc<<28) | (1<<23) | (s<<20) |
+ (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
+}
+void ARMAssembler::UMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs) {
+ LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
+ "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
+ *mPC++ = (cc<<28) | (1<<23) | (1<<21) | (s<<20) |
+ (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
+}
+void ARMAssembler::SMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs) {
+ LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
+ "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
+ *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (s<<20) |
+ (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
+}
+void ARMAssembler::SMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs) {
+ LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
+ "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
+ *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) |
+ (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
+}
+
+#if 0
+#pragma mark -
+#pragma mark Branches...
+#endif
+
+// branches...
+void ARMAssembler::B(int cc, uint32_t* pc)
+{
+ int32_t offset = int32_t(pc - (mPC+2));
+ *mPC++ = (cc<<28) | (0xA<<24) | (offset & 0xFFFFFF);
+}
+
+void ARMAssembler::BL(int cc, uint32_t* pc)
+{
+ int32_t offset = int32_t(pc - (mPC+2));
+ *mPC++ = (cc<<28) | (0xB<<24) | (offset & 0xFFFFFF);
+}
+
+void ARMAssembler::BX(int cc, int Rn)
+{
+ *mPC++ = (cc<<28) | 0x12FFF10 | Rn;
+}
+
+#if 0
+#pragma mark -
+#pragma mark Data Transfer...
+#endif
+
+// data transfert...
+void ARMAssembler::LDR(int cc, int Rd, int Rn, uint32_t offset) {
+ *mPC++ = (cc<<28) | (1<<26) | (1<<20) | (Rn<<16) | (Rd<<12) | offset;
+}
+void ARMAssembler::LDRB(int cc, int Rd, int Rn, uint32_t offset) {
+ *mPC++ = (cc<<28) | (1<<26) | (1<<22) | (1<<20) | (Rn<<16) | (Rd<<12) | offset;
+}
+void ARMAssembler::STR(int cc, int Rd, int Rn, uint32_t offset) {
+ *mPC++ = (cc<<28) | (1<<26) | (Rn<<16) | (Rd<<12) | offset;
+}
+void ARMAssembler::STRB(int cc, int Rd, int Rn, uint32_t offset) {
+ *mPC++ = (cc<<28) | (1<<26) | (1<<22) | (Rn<<16) | (Rd<<12) | offset;
+}
+
+void ARMAssembler::LDRH(int cc, int Rd, int Rn, uint32_t offset) {
+ *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xB0 | offset;
+}
+void ARMAssembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset) {
+ *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xD0 | offset;
+}
+void ARMAssembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset) {
+ *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xF0 | offset;
+}
+void ARMAssembler::STRH(int cc, int Rd, int Rn, uint32_t offset) {
+ *mPC++ = (cc<<28) | (Rn<<16) | (Rd<<12) | 0xB0 | offset;
+}
+
+#if 0
+#pragma mark -
+#pragma mark Block Data Transfer...
+#endif
+
+// block data transfer...
+void ARMAssembler::LDM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list)
+{ // ED FD EA FA IB IA DB DA
+ const uint8_t P[8] = { 1, 0, 1, 0, 1, 0, 1, 0 };
+ const uint8_t U[8] = { 1, 1, 0, 0, 1, 1, 0, 0 };
+ *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
+ (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list;
+}
+
+void ARMAssembler::STM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list)
+{ // ED FD EA FA IB IA DB DA
+ const uint8_t P[8] = { 0, 1, 0, 1, 1, 0, 1, 0 };
+ const uint8_t U[8] = { 0, 0, 1, 1, 1, 1, 0, 0 };
+ *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
+ (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list;
+}
+
+#if 0
+#pragma mark -
+#pragma mark Special...
+#endif
+
+// special...
+void ARMAssembler::SWP(int cc, int Rn, int Rd, int Rm) {
+ *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
+}
+void ARMAssembler::SWPB(int cc, int Rn, int Rd, int Rm) {
+ *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
+}
+void ARMAssembler::SWI(int cc, uint32_t comment) {
+ *mPC++ = (cc<<28) | (0xF<<24) | comment;
+}
+
+#if 0
+#pragma mark -
+#pragma mark DSP instructions...
+#endif
+
+// DSP instructions...
+void ARMAssembler::PLD(int Rn, uint32_t offset) {
+ LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))),
+ "PLD only P=1, W=0");
+ *mPC++ = 0xF550F000 | (Rn<<16) | offset;
+}
+
+void ARMAssembler::CLZ(int cc, int Rd, int Rm)
+{
+ *mPC++ = (cc<<28) | 0x16F0F10| (Rd<<12) | Rm;
+}
+
+void ARMAssembler::QADD(int cc, int Rd, int Rm, int Rn)
+{
+ *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm;
+}
+
+void ARMAssembler::QDADD(int cc, int Rd, int Rm, int Rn)
+{
+ *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm;
+}
+
+void ARMAssembler::QSUB(int cc, int Rd, int Rm, int Rn)
+{
+ *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm;
+}
+
+void ARMAssembler::QDSUB(int cc, int Rd, int Rm, int Rn)
+{
+ *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm;
+}
+
+void ARMAssembler::SMUL(int cc, int xy,
+ int Rd, int Rm, int Rs)
+{
+ *mPC++ = (cc<<28) | 0x1600080 | (Rd<<16) | (Rs<<8) | (xy<<4) | Rm;
+}
+
+void ARMAssembler::SMULW(int cc, int y,
+ int Rd, int Rm, int Rs)
+{
+ *mPC++ = (cc<<28) | 0x12000A0 | (Rd<<16) | (Rs<<8) | (y<<4) | Rm;
+}
+
+void ARMAssembler::SMLA(int cc, int xy,
+ int Rd, int Rm, int Rs, int Rn)
+{
+ *mPC++ = (cc<<28) | 0x1000080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (xy<<4) | Rm;
+}
+
+void ARMAssembler::SMLAL(int cc, int xy,
+ int RdHi, int RdLo, int Rs, int Rm)
+{
+ *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm;
+}
+
+void ARMAssembler::SMLAW(int cc, int y,
+ int Rd, int Rm, int Rs, int Rn)
+{
+ *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm;
+}
+
+#if 0
+#pragma mark -
+#pragma mark Byte/half word extract and extend (ARMv6+ only)...
+#endif
+
+void ARMAssembler::UXTB16(int cc, int Rd, int Rm, int rotate)
+{
+ *mPC++ = (cc<<28) | 0x6CF0070 | (Rd<<12) | ((rotate >> 3) << 10) | Rm;
+}
+#if 0
+#pragma mark -
+#pragma mark Bit manipulation (ARMv7+ only)...
+#endif
+
+// Bit manipulation (ARMv7+ only)...
+void ARMAssembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
+{
+ *mPC++ = (cc<<28) | 0x7E00000 | ((width-1)<<16) | (Rd<<12) | (lsb<<7) | 0x50 | Rn;
+}
+
+#if 0
+#pragma mark -
+#pragma mark Addressing modes...
+#endif
+
+int ARMAssembler::buildImmediate(
+ uint32_t immediate, uint32_t& rot, uint32_t& imm)
+{
+ rot = 0;
+ imm = immediate;
+ if (imm > 0x7F) { // skip the easy cases
+ while (!(imm&3) || (imm&0xFC000000)) {
+ uint32_t newval;
+ newval = imm >> 2;
+ newval |= (imm&3) << 30;
+ imm = newval;
+ rot += 2;
+ if (rot == 32) {
+ rot = 0;
+ break;
+ }
+ }
+ }
+ rot = (16 - (rot>>1)) & 0xF;
+
+ if (imm>=0x100)
+ return -EINVAL;
+
+ if (((imm>>(rot<<1)) | (imm<<(32-(rot<<1)))) != immediate)
+ return -1;
+
+ return 0;
+}
+
+// shifters...
+
+bool ARMAssembler::isValidImmediate(uint32_t immediate)
+{
+ uint32_t rot, imm;
+ return buildImmediate(immediate, rot, imm) == 0;
+}
+
+uint32_t ARMAssembler::imm(uint32_t immediate)
+{
+ uint32_t rot, imm;
+ int err = buildImmediate(immediate, rot, imm);
+
+ LOG_ALWAYS_FATAL_IF(err==-EINVAL,
+ "immediate %08x cannot be encoded",
+ immediate);
+
+ LOG_ALWAYS_FATAL_IF(err,
+ "immediate (%08x) encoding bogus!",
+ immediate);
+
+ return (1<<25) | (rot<<8) | imm;
+}
+
+uint32_t ARMAssembler::reg_imm(int Rm, int type, uint32_t shift)
+{
+ return ((shift&0x1F)<<7) | ((type&0x3)<<5) | (Rm&0xF);
+}
+
+uint32_t ARMAssembler::reg_rrx(int Rm)
+{
+ return (ROR<<5) | (Rm&0xF);
+}
+
+uint32_t ARMAssembler::reg_reg(int Rm, int type, int Rs)
+{
+ return ((Rs&0xF)<<8) | ((type&0x3)<<5) | (1<<4) | (Rm&0xF);
+}
+
+// addressing modes...
+// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
+uint32_t ARMAssembler::immed12_pre(int32_t immed12, int W)
+{
+ LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
+ "LDR(B)/STR(B)/PLD immediate too big (%08x)",
+ immed12);
+ return (1<<24) | (((uint32_t(immed12)>>31)^1)<<23) |
+ ((W&1)<<21) | (abs(immed12)&0x7FF);
+}
+
+uint32_t ARMAssembler::immed12_post(int32_t immed12)
+{
+ LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
+ "LDR(B)/STR(B)/PLD immediate too big (%08x)",
+ immed12);
+
+ return (((uint32_t(immed12)>>31)^1)<<23) | (abs(immed12)&0x7FF);
+}
+
+uint32_t ARMAssembler::reg_scale_pre(int Rm, int type,
+ uint32_t shift, int W)
+{
+ return (1<<25) | (1<<24) |
+ (((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) |
+ reg_imm(abs(Rm), type, shift);
+}
+
+uint32_t ARMAssembler::reg_scale_post(int Rm, int type, uint32_t shift)
+{
+ return (1<<25) | (((uint32_t(Rm)>>31)^1)<<23) | reg_imm(abs(Rm), type, shift);
+}
+
+// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0)
+uint32_t ARMAssembler::immed8_pre(int32_t immed8, int W)
+{
+ uint32_t offset = abs(immed8);
+
+ LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
+ "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
+ immed8);
+
+ return (1<<24) | (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
+ ((W&1)<<21) | (((offset&0xF0)<<4)|(offset&0xF));
+}
+
+uint32_t ARMAssembler::immed8_post(int32_t immed8)
+{
+ uint32_t offset = abs(immed8);
+
+ LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
+ "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
+ immed8);
+
+ return (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
+ (((offset&0xF0)<<4) | (offset&0xF));
+}
+
+uint32_t ARMAssembler::reg_pre(int Rm, int W)
+{
+ return (1<<24) | (((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) | (abs(Rm)&0xF);
+}
+
+uint32_t ARMAssembler::reg_post(int Rm)
+{
+ return (((uint32_t(Rm)>>31)^1)<<23) | (abs(Rm)&0xF);
+}
+
+}; // namespace android
diff --git a/libpixelflinger/codeflinger/ARMAssembler.h b/libpixelflinger/codeflinger/ARMAssembler.h
new file mode 100644
index 0000000..76acf7e
--- /dev/null
+++ b/libpixelflinger/codeflinger/ARMAssembler.h
@@ -0,0 +1,187 @@
+/* libs/pixelflinger/codeflinger/ARMAssembler.h
+**
+** Copyright 2006, The Android Open Source 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.
+*/
+
+#ifndef ANDROID_ARMASSEMBLER_H
+#define ANDROID_ARMASSEMBLER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "tinyutils/smartpointer.h"
+#include "utils/Vector.h"
+#include "utils/KeyedVector.h"
+
+#include "ARMAssemblerInterface.h"
+#include "CodeCache.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class ARMAssembler : public ARMAssemblerInterface
+{
+public:
+ explicit ARMAssembler(const sp<Assembly>& assembly);
+ virtual ~ARMAssembler();
+
+ uint32_t* base() const;
+ uint32_t* pc() const;
+
+
+ void disassemble(const char* name);
+
+ // ------------------------------------------------------------------------
+ // ARMAssemblerInterface...
+ // ------------------------------------------------------------------------
+
+ virtual void reset();
+
+ virtual int generate(const char* name);
+ virtual int getCodegenArch();
+
+ virtual void prolog();
+ virtual void epilog(uint32_t touched);
+ virtual void comment(const char* string);
+
+
+ // -----------------------------------------------------------------------
+ // shifters and addressing modes
+ // -----------------------------------------------------------------------
+
+ // shifters...
+ virtual bool isValidImmediate(uint32_t immed);
+ virtual int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm);
+
+ virtual uint32_t imm(uint32_t immediate);
+ virtual uint32_t reg_imm(int Rm, int type, uint32_t shift);
+ virtual uint32_t reg_rrx(int Rm);
+ virtual uint32_t reg_reg(int Rm, int type, int Rs);
+
+ // addressing modes...
+ // LDR(B)/STR(B)/PLD
+ // (immediate and Rm can be negative, which indicates U=0)
+ virtual uint32_t immed12_pre(int32_t immed12, int W=0);
+ virtual uint32_t immed12_post(int32_t immed12);
+ virtual uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0);
+ virtual uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0);
+
+ // LDRH/LDRSB/LDRSH/STRH
+ // (immediate and Rm can be negative, which indicates U=0)
+ virtual uint32_t immed8_pre(int32_t immed8, int W=0);
+ virtual uint32_t immed8_post(int32_t immed8);
+ virtual uint32_t reg_pre(int Rm, int W=0);
+ virtual uint32_t reg_post(int Rm);
+
+
+ virtual void dataProcessing(int opcode, int cc, int s,
+ int Rd, int Rn,
+ uint32_t Op2);
+ virtual void MLA(int cc, int s,
+ int Rd, int Rm, int Rs, int Rn);
+ virtual void MUL(int cc, int s,
+ int Rd, int Rm, int Rs);
+ virtual void UMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+ virtual void UMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+ virtual void SMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+ virtual void SMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+
+ virtual void B(int cc, uint32_t* pc);
+ virtual void BL(int cc, uint32_t* pc);
+ virtual void BX(int cc, int Rn);
+ virtual void label(const char* theLabel);
+ virtual void B(int cc, const char* label);
+ virtual void BL(int cc, const char* label);
+
+ virtual uint32_t* pcForLabel(const char* label);
+
+ virtual void LDR (int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void LDRB(int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void STR (int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void STRB(int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void LDRH (int cc, int Rd,
+ int Rn, uint32_t offset = __immed8_pre(0));
+ virtual void LDRSB(int cc, int Rd,
+ int Rn, uint32_t offset = __immed8_pre(0));
+ virtual void LDRSH(int cc, int Rd,
+ int Rn, uint32_t offset = __immed8_pre(0));
+ virtual void STRH (int cc, int Rd,
+ int Rn, uint32_t offset = __immed8_pre(0));
+
+
+ virtual void LDM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list);
+ virtual void STM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list);
+
+ virtual void SWP(int cc, int Rn, int Rd, int Rm);
+ virtual void SWPB(int cc, int Rn, int Rd, int Rm);
+ virtual void SWI(int cc, uint32_t comment);
+
+ virtual void PLD(int Rn, uint32_t offset);
+ virtual void CLZ(int cc, int Rd, int Rm);
+ virtual void QADD(int cc, int Rd, int Rm, int Rn);
+ virtual void QDADD(int cc, int Rd, int Rm, int Rn);
+ virtual void QSUB(int cc, int Rd, int Rm, int Rn);
+ virtual void QDSUB(int cc, int Rd, int Rm, int Rn);
+ virtual void SMUL(int cc, int xy,
+ int Rd, int Rm, int Rs);
+ virtual void SMULW(int cc, int y,
+ int Rd, int Rm, int Rs);
+ virtual void SMLA(int cc, int xy,
+ int Rd, int Rm, int Rs, int Rn);
+ virtual void SMLAL(int cc, int xy,
+ int RdHi, int RdLo, int Rs, int Rm);
+ virtual void SMLAW(int cc, int y,
+ int Rd, int Rm, int Rs, int Rn);
+ virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
+ virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
+
+private:
+ ARMAssembler(const ARMAssembler& rhs);
+ ARMAssembler& operator = (const ARMAssembler& rhs);
+
+ sp<Assembly> mAssembly;
+ uint32_t* mBase;
+ uint32_t* mPC;
+ uint32_t* mPrologPC;
+ int64_t mDuration;
+
+ struct branch_target_t {
+ inline branch_target_t() : label(0), pc(0) { }
+ inline branch_target_t(const char* l, uint32_t* p)
+ : label(l), pc(p) { }
+ const char* label;
+ uint32_t* pc;
+ };
+
+ Vector<branch_target_t> mBranchTargets;
+ KeyedVector< const char*, uint32_t* > mLabels;
+ KeyedVector< uint32_t*, const char* > mLabelsInverseMapping;
+ KeyedVector< uint32_t*, const char* > mComments;
+};
+
+}; // namespace android
+
+#endif //ANDROID_ARMASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
new file mode 100644
index 0000000..c96cf4b
--- /dev/null
+++ b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
@@ -0,0 +1,90 @@
+/* libs/pixelflinger/codeflinger/ARMAssemblerInterface.cpp
+**
+** Copyright 2006, The Android Open Source 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.
+*/
+#define LOG_TAG "pixelflinger-code"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <log/log.h>
+
+#include "ARMAssemblerInterface.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+ARMAssemblerInterface::~ARMAssemblerInterface()
+{
+}
+
+// --------------------------------------------------------------------
+
+// The following two functions are static and used for initializers
+// in the original ARM code. The above versions (without __), are now
+// virtual, and can be overridden in the MIPS code. But since these are
+// needed at initialization time, they must be static. Not thrilled with
+// this implementation, but it works...
+
+uint32_t ARMAssemblerInterface::__immed12_pre(int32_t immed12, int W)
+{
+ LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
+ "LDR(B)/STR(B)/PLD immediate too big (%08x)",
+ immed12);
+ return (1<<24) | (((uint32_t(immed12)>>31)^1)<<23) |
+ ((W&1)<<21) | (abs(immed12)&0x7FF);
+}
+
+uint32_t ARMAssemblerInterface::__immed8_pre(int32_t immed8, int W)
+{
+ uint32_t offset = abs(immed8);
+
+ LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
+ "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
+ immed8);
+
+ return (1<<24) | (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
+ ((W&1)<<21) | (((offset&0xF0)<<4)|(offset&0xF));
+}
+
+// The following four functions are required for address manipulation
+// These are virtual functions, which can be overridden by architectures
+// that need special handling of address values (e.g. 64-bit arch)
+
+void ARMAssemblerInterface::ADDR_LDR(int cc, int Rd,
+ int Rn, uint32_t offset)
+{
+ LDR(cc, Rd, Rn, offset);
+}
+void ARMAssemblerInterface::ADDR_STR(int cc, int Rd,
+ int Rn, uint32_t offset)
+{
+ STR(cc, Rd, Rn, offset);
+}
+void ARMAssemblerInterface::ADDR_ADD(int cc, int s,
+ int Rd, int Rn, uint32_t Op2)
+{
+ dataProcessing(opADD, cc, s, Rd, Rn, Op2);
+}
+void ARMAssemblerInterface::ADDR_SUB(int cc, int s,
+ int Rd, int Rn, uint32_t Op2)
+{
+ dataProcessing(opSUB, cc, s, Rd, Rn, Op2);
+}
+}; // namespace android
+
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.h b/libpixelflinger/codeflinger/ARMAssemblerInterface.h
new file mode 100644
index 0000000..72935ac
--- /dev/null
+++ b/libpixelflinger/codeflinger/ARMAssemblerInterface.h
@@ -0,0 +1,349 @@
+/* libs/pixelflinger/codeflinger/ARMAssemblerInterface.h
+**
+** Copyright 2006, The Android Open Source 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.
+*/
+
+
+#ifndef ANDROID_ARMASSEMBLER_INTERFACE_H
+#define ANDROID_ARMASSEMBLER_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class ARMAssemblerInterface
+{
+public:
+ virtual ~ARMAssemblerInterface();
+
+ enum {
+ EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV,
+ HS = CS,
+ LO = CC
+ };
+ enum {
+ S = 1
+ };
+ enum {
+ LSL, LSR, ASR, ROR
+ };
+ enum {
+ ED, FD, EA, FA,
+ IB, IA, DB, DA
+ };
+ enum {
+ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15,
+ SP = R13,
+ LR = R14,
+ PC = R15
+ };
+ enum {
+ #define LIST(rr) L##rr=1<<rr
+ LIST(R0), LIST(R1), LIST(R2), LIST(R3), LIST(R4), LIST(R5), LIST(R6),
+ LIST(R7), LIST(R8), LIST(R9), LIST(R10), LIST(R11), LIST(R12),
+ LIST(R13), LIST(R14), LIST(R15),
+ LIST(SP), LIST(LR), LIST(PC),
+ #undef LIST
+ LSAVED = LR4|LR5|LR6|LR7|LR8|LR9|LR10|LR11 | LLR
+ };
+
+ enum {
+ CODEGEN_ARCH_ARM = 1, CODEGEN_ARCH_MIPS, CODEGEN_ARCH_ARM64, CODEGEN_ARCH_MIPS64
+ };
+
+ // -----------------------------------------------------------------------
+ // shifters and addressing modes
+ // -----------------------------------------------------------------------
+
+ // these static versions are used for initializers on LDxx/STxx below
+ static uint32_t __immed12_pre(int32_t immed12, int W=0);
+ static uint32_t __immed8_pre(int32_t immed12, int W=0);
+
+ virtual bool isValidImmediate(uint32_t immed) = 0;
+ virtual int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm) = 0;
+
+ virtual uint32_t imm(uint32_t immediate) = 0;
+ virtual uint32_t reg_imm(int Rm, int type, uint32_t shift) = 0;
+ virtual uint32_t reg_rrx(int Rm) = 0;
+ virtual uint32_t reg_reg(int Rm, int type, int Rs) = 0;
+
+ // addressing modes...
+ // LDR(B)/STR(B)/PLD
+ // (immediate and Rm can be negative, which indicates U=0)
+ virtual uint32_t immed12_pre(int32_t immed12, int W=0) = 0;
+ virtual uint32_t immed12_post(int32_t immed12) = 0;
+ virtual uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0) = 0;
+ virtual uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0) = 0;
+
+ // LDRH/LDRSB/LDRSH/STRH
+ // (immediate and Rm can be negative, which indicates U=0)
+ virtual uint32_t immed8_pre(int32_t immed8, int W=0) = 0;
+ virtual uint32_t immed8_post(int32_t immed8) = 0;
+ virtual uint32_t reg_pre(int Rm, int W=0) = 0;
+ virtual uint32_t reg_post(int Rm) = 0;
+
+ // -----------------------------------------------------------------------
+ // basic instructions & code generation
+ // -----------------------------------------------------------------------
+
+ // generate the code
+ virtual void reset() = 0;
+ virtual int generate(const char* name) = 0;
+ virtual void disassemble(const char* name) = 0;
+ virtual int getCodegenArch() = 0;
+
+ // construct prolog and epilog
+ virtual void prolog() = 0;
+ virtual void epilog(uint32_t touched) = 0;
+ virtual void comment(const char* string) = 0;
+
+ // data processing...
+ enum {
+ opAND, opEOR, opSUB, opRSB, opADD, opADC, opSBC, opRSC,
+ opTST, opTEQ, opCMP, opCMN, opORR, opMOV, opBIC, opMVN,
+ opADD64, opSUB64
+ };
+
+ virtual void
+ dataProcessing( int opcode, int cc, int s,
+ int Rd, int Rn,
+ uint32_t Op2) = 0;
+
+ // multiply...
+ virtual void MLA(int cc, int s,
+ int Rd, int Rm, int Rs, int Rn) = 0;
+ virtual void MUL(int cc, int s,
+ int Rd, int Rm, int Rs) = 0;
+ virtual void UMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs) = 0;
+ virtual void UMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs) = 0;
+ virtual void SMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs) = 0;
+ virtual void SMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs) = 0;
+
+ // branches...
+ virtual void B(int cc, uint32_t* pc) = 0;
+ virtual void BL(int cc, uint32_t* pc) = 0;
+ virtual void BX(int cc, int Rn) = 0;
+
+ virtual void label(const char* theLabel) = 0;
+ virtual void B(int cc, const char* label) = 0;
+ virtual void BL(int cc, const char* label) = 0;
+
+ // valid only after generate() has been called
+ virtual uint32_t* pcForLabel(const char* label) = 0;
+
+ // data transfer...
+ virtual void LDR (int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0)) = 0;
+ virtual void LDRB(int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0)) = 0;
+ virtual void STR (int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0)) = 0;
+ virtual void STRB(int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0)) = 0;
+
+ virtual void LDRH (int cc, int Rd,
+ int Rn, uint32_t offset = __immed8_pre(0)) = 0;
+ virtual void LDRSB(int cc, int Rd,
+ int Rn, uint32_t offset = __immed8_pre(0)) = 0;
+ virtual void LDRSH(int cc, int Rd,
+ int Rn, uint32_t offset = __immed8_pre(0)) = 0;
+ virtual void STRH (int cc, int Rd,
+ int Rn, uint32_t offset = __immed8_pre(0)) = 0;
+
+ // block data transfer...
+ virtual void LDM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list) = 0;
+ virtual void STM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list) = 0;
+
+ // special...
+ virtual void SWP(int cc, int Rn, int Rd, int Rm) = 0;
+ virtual void SWPB(int cc, int Rn, int Rd, int Rm) = 0;
+ virtual void SWI(int cc, uint32_t comment) = 0;
+
+ // DSP instructions...
+ enum {
+ // B=0, T=1
+ // yx
+ xyBB = 0, // 0000,
+ xyTB = 2, // 0010,
+ xyBT = 4, // 0100,
+ xyTT = 6, // 0110,
+ yB = 0, // 0000,
+ yT = 4, // 0100
+ };
+
+ virtual void PLD(int Rn, uint32_t offset) = 0;
+
+ virtual void CLZ(int cc, int Rd, int Rm) = 0;
+
+ virtual void QADD(int cc, int Rd, int Rm, int Rn) = 0;
+ virtual void QDADD(int cc, int Rd, int Rm, int Rn) = 0;
+ virtual void QSUB(int cc, int Rd, int Rm, int Rn) = 0;
+ virtual void QDSUB(int cc, int Rd, int Rm, int Rn) = 0;
+
+ virtual void SMUL(int cc, int xy,
+ int Rd, int Rm, int Rs) = 0;
+ virtual void SMULW(int cc, int y,
+ int Rd, int Rm, int Rs) = 0;
+ virtual void SMLA(int cc, int xy,
+ int Rd, int Rm, int Rs, int Rn) = 0;
+ virtual void SMLAL(int cc, int xy,
+ int RdHi, int RdLo, int Rs, int Rm) = 0;
+ virtual void SMLAW(int cc, int y,
+ int Rd, int Rm, int Rs, int Rn) = 0;
+
+ // byte/half word extract...
+ virtual void UXTB16(int cc, int Rd, int Rm, int rotate) = 0;
+
+ // bit manipulation...
+ virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width) = 0;
+
+ // -----------------------------------------------------------------------
+ // convenience...
+ // -----------------------------------------------------------------------
+ inline void
+ ADC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
+ dataProcessing(opADC, cc, s, Rd, Rn, Op2);
+ }
+ inline void
+ ADD(int cc, int s, int Rd, int Rn, uint32_t Op2) {
+ dataProcessing(opADD, cc, s, Rd, Rn, Op2);
+ }
+ inline void
+ AND(int cc, int s, int Rd, int Rn, uint32_t Op2) {
+ dataProcessing(opAND, cc, s, Rd, Rn, Op2);
+ }
+ inline void
+ BIC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
+ dataProcessing(opBIC, cc, s, Rd, Rn, Op2);
+ }
+ inline void
+ EOR(int cc, int s, int Rd, int Rn, uint32_t Op2) {
+ dataProcessing(opEOR, cc, s, Rd, Rn, Op2);
+ }
+ inline void
+ MOV(int cc, int s, int Rd, uint32_t Op2) {
+ dataProcessing(opMOV, cc, s, Rd, 0, Op2);
+ }
+ inline void
+ MVN(int cc, int s, int Rd, uint32_t Op2) {
+ dataProcessing(opMVN, cc, s, Rd, 0, Op2);
+ }
+ inline void
+ ORR(int cc, int s, int Rd, int Rn, uint32_t Op2) {
+ dataProcessing(opORR, cc, s, Rd, Rn, Op2);
+ }
+ inline void
+ RSB(int cc, int s, int Rd, int Rn, uint32_t Op2) {
+ dataProcessing(opRSB, cc, s, Rd, Rn, Op2);
+ }
+ inline void
+ RSC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
+ dataProcessing(opRSC, cc, s, Rd, Rn, Op2);
+ }
+ inline void
+ SBC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
+ dataProcessing(opSBC, cc, s, Rd, Rn, Op2);
+ }
+ inline void
+ SUB(int cc, int s, int Rd, int Rn, uint32_t Op2) {
+ dataProcessing(opSUB, cc, s, Rd, Rn, Op2);
+ }
+ inline void
+ TEQ(int cc, int Rn, uint32_t Op2) {
+ dataProcessing(opTEQ, cc, 1, 0, Rn, Op2);
+ }
+ inline void
+ TST(int cc, int Rn, uint32_t Op2) {
+ dataProcessing(opTST, cc, 1, 0, Rn, Op2);
+ }
+ inline void
+ CMP(int cc, int Rn, uint32_t Op2) {
+ dataProcessing(opCMP, cc, 1, 0, Rn, Op2);
+ }
+ inline void
+ CMN(int cc, int Rn, uint32_t Op2) {
+ dataProcessing(opCMN, cc, 1, 0, Rn, Op2);
+ }
+
+ inline void SMULBB(int cc, int Rd, int Rm, int Rs) {
+ SMUL(cc, xyBB, Rd, Rm, Rs); }
+ inline void SMULTB(int cc, int Rd, int Rm, int Rs) {
+ SMUL(cc, xyTB, Rd, Rm, Rs); }
+ inline void SMULBT(int cc, int Rd, int Rm, int Rs) {
+ SMUL(cc, xyBT, Rd, Rm, Rs); }
+ inline void SMULTT(int cc, int Rd, int Rm, int Rs) {
+ SMUL(cc, xyTT, Rd, Rm, Rs); }
+
+ inline void SMULWB(int cc, int Rd, int Rm, int Rs) {
+ SMULW(cc, yB, Rd, Rm, Rs); }
+ inline void SMULWT(int cc, int Rd, int Rm, int Rs) {
+ SMULW(cc, yT, Rd, Rm, Rs); }
+
+ inline void
+ SMLABB(int cc, int Rd, int Rm, int Rs, int Rn) {
+ SMLA(cc, xyBB, Rd, Rm, Rs, Rn); }
+ inline void
+ SMLATB(int cc, int Rd, int Rm, int Rs, int Rn) {
+ SMLA(cc, xyTB, Rd, Rm, Rs, Rn); }
+ inline void
+ SMLABT(int cc, int Rd, int Rm, int Rs, int Rn) {
+ SMLA(cc, xyBT, Rd, Rm, Rs, Rn); }
+ inline void
+ SMLATT(int cc, int Rd, int Rm, int Rs, int Rn) {
+ SMLA(cc, xyTT, Rd, Rm, Rs, Rn); }
+
+ inline void
+ SMLALBB(int cc, int RdHi, int RdLo, int Rs, int Rm) {
+ SMLAL(cc, xyBB, RdHi, RdLo, Rs, Rm); }
+ inline void
+ SMLALTB(int cc, int RdHi, int RdLo, int Rs, int Rm) {
+ SMLAL(cc, xyTB, RdHi, RdLo, Rs, Rm); }
+ inline void
+ SMLALBT(int cc, int RdHi, int RdLo, int Rs, int Rm) {
+ SMLAL(cc, xyBT, RdHi, RdLo, Rs, Rm); }
+ inline void
+ SMLALTT(int cc, int RdHi, int RdLo, int Rs, int Rm) {
+ SMLAL(cc, xyTT, RdHi, RdLo, Rs, Rm); }
+
+ inline void
+ SMLAWB(int cc, int Rd, int Rm, int Rs, int Rn) {
+ SMLAW(cc, yB, Rd, Rm, Rs, Rn); }
+ inline void
+ SMLAWT(int cc, int Rd, int Rm, int Rs, int Rn) {
+ SMLAW(cc, yT, Rd, Rm, Rs, Rn); }
+
+ // Address loading/storing/manipulation
+ virtual void ADDR_LDR(int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void ADDR_STR (int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void ADDR_ADD(int cc, int s, int Rd,
+ int Rn, uint32_t Op2);
+ virtual void ADDR_SUB(int cc, int s, int Rd,
+ int Rn, uint32_t Op2);
+};
+
+}; // namespace android
+
+#endif //ANDROID_ARMASSEMBLER_INTERFACE_H
diff --git a/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp b/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
new file mode 100644
index 0000000..816de48
--- /dev/null
+++ b/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
@@ -0,0 +1,311 @@
+/* libs/pixelflinger/codeflinger/ARMAssemblerProxy.cpp
+**
+** Copyright 2006, The Android Open Source 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 <stdint.h>
+#include <sys/types.h>
+
+#include "ARMAssemblerProxy.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+ARMAssemblerProxy::ARMAssemblerProxy()
+ : mTarget(0)
+{
+}
+
+ARMAssemblerProxy::ARMAssemblerProxy(ARMAssemblerInterface* target)
+ : mTarget(target)
+{
+}
+
+ARMAssemblerProxy::~ARMAssemblerProxy()
+{
+ delete mTarget;
+}
+
+void ARMAssemblerProxy::setTarget(ARMAssemblerInterface* target)
+{
+ delete mTarget;
+ mTarget = target;
+}
+
+void ARMAssemblerProxy::reset() {
+ mTarget->reset();
+}
+int ARMAssemblerProxy::generate(const char* name) {
+ return mTarget->generate(name);
+}
+void ARMAssemblerProxy::disassemble(const char* name) {
+ return mTarget->disassemble(name);
+}
+int ARMAssemblerProxy::getCodegenArch()
+{
+ return mTarget->getCodegenArch();
+}
+void ARMAssemblerProxy::prolog() {
+ mTarget->prolog();
+}
+void ARMAssemblerProxy::epilog(uint32_t touched) {
+ mTarget->epilog(touched);
+}
+void ARMAssemblerProxy::comment(const char* string) {
+ mTarget->comment(string);
+}
+
+
+
+// addressing modes
+
+bool ARMAssemblerProxy::isValidImmediate(uint32_t immed)
+{
+ return mTarget->isValidImmediate(immed);
+}
+
+int ARMAssemblerProxy::buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm)
+{
+ return mTarget->buildImmediate(i, rot, imm);
+}
+
+
+
+uint32_t ARMAssemblerProxy::imm(uint32_t immediate)
+{
+ return mTarget->imm(immediate);
+}
+
+uint32_t ARMAssemblerProxy::reg_imm(int Rm, int type, uint32_t shift)
+{
+ return mTarget->reg_imm(Rm, type, shift);
+}
+
+uint32_t ARMAssemblerProxy::reg_rrx(int Rm)
+{
+ return mTarget->reg_rrx(Rm);
+}
+
+uint32_t ARMAssemblerProxy::reg_reg(int Rm, int type, int Rs)
+{
+ return mTarget->reg_reg(Rm, type, Rs);
+}
+
+
+// addressing modes...
+// LDR(B)/STR(B)/PLD
+// (immediate and Rm can be negative, which indicates U=0)
+uint32_t ARMAssemblerProxy::immed12_pre(int32_t immed12, int W)
+{
+ return mTarget->immed12_pre(immed12, W);
+}
+
+uint32_t ARMAssemblerProxy::immed12_post(int32_t immed12)
+{
+ return mTarget->immed12_post(immed12);
+}
+
+uint32_t ARMAssemblerProxy::reg_scale_pre(int Rm, int type, uint32_t shift, int W)
+{
+ return mTarget->reg_scale_pre(Rm, type, shift, W);
+}
+
+uint32_t ARMAssemblerProxy::reg_scale_post(int Rm, int type, uint32_t shift)
+{
+ return mTarget->reg_scale_post(Rm, type, shift);
+}
+
+
+// LDRH/LDRSB/LDRSH/STRH
+// (immediate and Rm can be negative, which indicates U=0)
+uint32_t ARMAssemblerProxy::immed8_pre(int32_t immed8, int W)
+{
+ return mTarget->immed8_pre(immed8, W);
+}
+
+uint32_t ARMAssemblerProxy::immed8_post(int32_t immed8)
+{
+ return mTarget->immed8_post(immed8);
+}
+
+uint32_t ARMAssemblerProxy::reg_pre(int Rm, int W)
+{
+ return mTarget->reg_pre(Rm, W);
+}
+
+uint32_t ARMAssemblerProxy::reg_post(int Rm)
+{
+ return mTarget->reg_post(Rm);
+}
+
+
+//------------------------------------------------------------------------
+
+
+
+void ARMAssemblerProxy::dataProcessing( int opcode, int cc, int s,
+ int Rd, int Rn, uint32_t Op2)
+{
+ mTarget->dataProcessing(opcode, cc, s, Rd, Rn, Op2);
+}
+
+void ARMAssemblerProxy::MLA(int cc, int s, int Rd, int Rm, int Rs, int Rn) {
+ mTarget->MLA(cc, s, Rd, Rm, Rs, Rn);
+}
+void ARMAssemblerProxy::MUL(int cc, int s, int Rd, int Rm, int Rs) {
+ mTarget->MUL(cc, s, Rd, Rm, Rs);
+}
+void ARMAssemblerProxy::UMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs) {
+ mTarget->UMULL(cc, s, RdLo, RdHi, Rm, Rs);
+}
+void ARMAssemblerProxy::UMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs) {
+ mTarget->UMUAL(cc, s, RdLo, RdHi, Rm, Rs);
+}
+void ARMAssemblerProxy::SMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs) {
+ mTarget->SMULL(cc, s, RdLo, RdHi, Rm, Rs);
+}
+void ARMAssemblerProxy::SMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs) {
+ mTarget->SMUAL(cc, s, RdLo, RdHi, Rm, Rs);
+}
+
+void ARMAssemblerProxy::B(int cc, uint32_t* pc) {
+ mTarget->B(cc, pc);
+}
+void ARMAssemblerProxy::BL(int cc, uint32_t* pc) {
+ mTarget->BL(cc, pc);
+}
+void ARMAssemblerProxy::BX(int cc, int Rn) {
+ mTarget->BX(cc, Rn);
+}
+void ARMAssemblerProxy::label(const char* theLabel) {
+ mTarget->label(theLabel);
+}
+void ARMAssemblerProxy::B(int cc, const char* label) {
+ mTarget->B(cc, label);
+}
+void ARMAssemblerProxy::BL(int cc, const char* label) {
+ mTarget->BL(cc, label);
+}
+
+uint32_t* ARMAssemblerProxy::pcForLabel(const char* label) {
+ return mTarget->pcForLabel(label);
+}
+
+void ARMAssemblerProxy::LDR(int cc, int Rd, int Rn, uint32_t offset) {
+ mTarget->LDR(cc, Rd, Rn, offset);
+}
+void ARMAssemblerProxy::LDRB(int cc, int Rd, int Rn, uint32_t offset) {
+ mTarget->LDRB(cc, Rd, Rn, offset);
+}
+void ARMAssemblerProxy::STR(int cc, int Rd, int Rn, uint32_t offset) {
+ mTarget->STR(cc, Rd, Rn, offset);
+}
+void ARMAssemblerProxy::STRB(int cc, int Rd, int Rn, uint32_t offset) {
+ mTarget->STRB(cc, Rd, Rn, offset);
+}
+void ARMAssemblerProxy::LDRH(int cc, int Rd, int Rn, uint32_t offset) {
+ mTarget->LDRH(cc, Rd, Rn, offset);
+}
+void ARMAssemblerProxy::LDRSB(int cc, int Rd, int Rn, uint32_t offset) {
+ mTarget->LDRSB(cc, Rd, Rn, offset);
+}
+void ARMAssemblerProxy::LDRSH(int cc, int Rd, int Rn, uint32_t offset) {
+ mTarget->LDRSH(cc, Rd, Rn, offset);
+}
+void ARMAssemblerProxy::STRH(int cc, int Rd, int Rn, uint32_t offset) {
+ mTarget->STRH(cc, Rd, Rn, offset);
+}
+void ARMAssemblerProxy::LDM(int cc, int dir, int Rn, int W, uint32_t reg_list) {
+ mTarget->LDM(cc, dir, Rn, W, reg_list);
+}
+void ARMAssemblerProxy::STM(int cc, int dir, int Rn, int W, uint32_t reg_list) {
+ mTarget->STM(cc, dir, Rn, W, reg_list);
+}
+
+void ARMAssemblerProxy::SWP(int cc, int Rn, int Rd, int Rm) {
+ mTarget->SWP(cc, Rn, Rd, Rm);
+}
+void ARMAssemblerProxy::SWPB(int cc, int Rn, int Rd, int Rm) {
+ mTarget->SWPB(cc, Rn, Rd, Rm);
+}
+void ARMAssemblerProxy::SWI(int cc, uint32_t comment) {
+ mTarget->SWI(cc, comment);
+}
+
+
+void ARMAssemblerProxy::PLD(int Rn, uint32_t offset) {
+ mTarget->PLD(Rn, offset);
+}
+void ARMAssemblerProxy::CLZ(int cc, int Rd, int Rm) {
+ mTarget->CLZ(cc, Rd, Rm);
+}
+void ARMAssemblerProxy::QADD(int cc, int Rd, int Rm, int Rn) {
+ mTarget->QADD(cc, Rd, Rm, Rn);
+}
+void ARMAssemblerProxy::QDADD(int cc, int Rd, int Rm, int Rn) {
+ mTarget->QDADD(cc, Rd, Rm, Rn);
+}
+void ARMAssemblerProxy::QSUB(int cc, int Rd, int Rm, int Rn) {
+ mTarget->QSUB(cc, Rd, Rm, Rn);
+}
+void ARMAssemblerProxy::QDSUB(int cc, int Rd, int Rm, int Rn) {
+ mTarget->QDSUB(cc, Rd, Rm, Rn);
+}
+void ARMAssemblerProxy::SMUL(int cc, int xy, int Rd, int Rm, int Rs) {
+ mTarget->SMUL(cc, xy, Rd, Rm, Rs);
+}
+void ARMAssemblerProxy::SMULW(int cc, int y, int Rd, int Rm, int Rs) {
+ mTarget->SMULW(cc, y, Rd, Rm, Rs);
+}
+void ARMAssemblerProxy::SMLA(int cc, int xy, int Rd, int Rm, int Rs, int Rn) {
+ mTarget->SMLA(cc, xy, Rd, Rm, Rs, Rn);
+}
+void ARMAssemblerProxy::SMLAL( int cc, int xy,
+ int RdHi, int RdLo, int Rs, int Rm) {
+ mTarget->SMLAL(cc, xy, RdHi, RdLo, Rs, Rm);
+}
+void ARMAssemblerProxy::SMLAW(int cc, int y, int Rd, int Rm, int Rs, int Rn) {
+ mTarget->SMLAW(cc, y, Rd, Rm, Rs, Rn);
+}
+
+void ARMAssemblerProxy::UXTB16(int cc, int Rd, int Rm, int rotate) {
+ mTarget->UXTB16(cc, Rd, Rm, rotate);
+}
+
+void ARMAssemblerProxy::UBFX(int cc, int Rd, int Rn, int lsb, int width) {
+ mTarget->UBFX(cc, Rd, Rn, lsb, width);
+}
+
+void ARMAssemblerProxy::ADDR_LDR(int cc, int Rd, int Rn, uint32_t offset) {
+ mTarget->ADDR_LDR(cc, Rd, Rn, offset);
+}
+void ARMAssemblerProxy::ADDR_STR(int cc, int Rd, int Rn, uint32_t offset) {
+ mTarget->ADDR_STR(cc, Rd, Rn, offset);
+}
+void ARMAssemblerProxy::ADDR_ADD(int cc, int s, int Rd, int Rn, uint32_t Op2){
+ mTarget->ADDR_ADD(cc, s, Rd, Rn, Op2);
+}
+void ARMAssemblerProxy::ADDR_SUB(int cc, int s, int Rd, int Rn, uint32_t Op2){
+ mTarget->ADDR_SUB(cc, s, Rd, Rn, Op2);
+}
+
+}; // namespace android
+
diff --git a/libpixelflinger/codeflinger/ARMAssemblerProxy.h b/libpixelflinger/codeflinger/ARMAssemblerProxy.h
new file mode 100644
index 0000000..10d0390
--- /dev/null
+++ b/libpixelflinger/codeflinger/ARMAssemblerProxy.h
@@ -0,0 +1,164 @@
+/* libs/pixelflinger/codeflinger/ARMAssemblerProxy.h
+**
+** Copyright 2006, The Android Open Source 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.
+*/
+
+
+#ifndef ANDROID_ARMASSEMBLER_PROXY_H
+#define ANDROID_ARMASSEMBLER_PROXY_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "ARMAssemblerInterface.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class ARMAssemblerProxy : public ARMAssemblerInterface
+{
+public:
+ // ARMAssemblerProxy take ownership of the target
+
+ ARMAssemblerProxy();
+ explicit ARMAssemblerProxy(ARMAssemblerInterface* target);
+ virtual ~ARMAssemblerProxy();
+
+ void setTarget(ARMAssemblerInterface* target);
+
+ virtual void reset();
+ virtual int generate(const char* name);
+ virtual void disassemble(const char* name);
+ virtual int getCodegenArch();
+
+ virtual void prolog();
+ virtual void epilog(uint32_t touched);
+ virtual void comment(const char* string);
+
+ // -----------------------------------------------------------------------
+ // shifters and addressing modes
+ // -----------------------------------------------------------------------
+
+ virtual bool isValidImmediate(uint32_t immed);
+ virtual int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm);
+
+ virtual uint32_t imm(uint32_t immediate);
+ virtual uint32_t reg_imm(int Rm, int type, uint32_t shift);
+ virtual uint32_t reg_rrx(int Rm);
+ virtual uint32_t reg_reg(int Rm, int type, int Rs);
+
+ // addressing modes...
+ // LDR(B)/STR(B)/PLD
+ // (immediate and Rm can be negative, which indicates U=0)
+ virtual uint32_t immed12_pre(int32_t immed12, int W=0);
+ virtual uint32_t immed12_post(int32_t immed12);
+ virtual uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0);
+ virtual uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0);
+
+ // LDRH/LDRSB/LDRSH/STRH
+ // (immediate and Rm can be negative, which indicates U=0)
+ virtual uint32_t immed8_pre(int32_t immed8, int W=0);
+ virtual uint32_t immed8_post(int32_t immed8);
+ virtual uint32_t reg_pre(int Rm, int W=0);
+ virtual uint32_t reg_post(int Rm);
+
+
+ virtual void dataProcessing(int opcode, int cc, int s,
+ int Rd, int Rn,
+ uint32_t Op2);
+ virtual void MLA(int cc, int s,
+ int Rd, int Rm, int Rs, int Rn);
+ virtual void MUL(int cc, int s,
+ int Rd, int Rm, int Rs);
+ virtual void UMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+ virtual void UMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+ virtual void SMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+ virtual void SMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+
+ virtual void B(int cc, uint32_t* pc);
+ virtual void BL(int cc, uint32_t* pc);
+ virtual void BX(int cc, int Rn);
+ virtual void label(const char* theLabel);
+ virtual void B(int cc, const char* label);
+ virtual void BL(int cc, const char* label);
+
+ uint32_t* pcForLabel(const char* label);
+
+ virtual void LDR (int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void LDRB(int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void STR (int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void STRB(int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void LDRH (int cc, int Rd,
+ int Rn, uint32_t offset = __immed8_pre(0));
+ virtual void LDRSB(int cc, int Rd,
+ int Rn, uint32_t offset = __immed8_pre(0));
+ virtual void LDRSH(int cc, int Rd,
+ int Rn, uint32_t offset = __immed8_pre(0));
+ virtual void STRH (int cc, int Rd,
+ int Rn, uint32_t offset = __immed8_pre(0));
+ virtual void LDM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list);
+ virtual void STM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list);
+
+ virtual void SWP(int cc, int Rn, int Rd, int Rm);
+ virtual void SWPB(int cc, int Rn, int Rd, int Rm);
+ virtual void SWI(int cc, uint32_t comment);
+
+ virtual void PLD(int Rn, uint32_t offset);
+ virtual void CLZ(int cc, int Rd, int Rm);
+ virtual void QADD(int cc, int Rd, int Rm, int Rn);
+ virtual void QDADD(int cc, int Rd, int Rm, int Rn);
+ virtual void QSUB(int cc, int Rd, int Rm, int Rn);
+ virtual void QDSUB(int cc, int Rd, int Rm, int Rn);
+ virtual void SMUL(int cc, int xy,
+ int Rd, int Rm, int Rs);
+ virtual void SMULW(int cc, int y,
+ int Rd, int Rm, int Rs);
+ virtual void SMLA(int cc, int xy,
+ int Rd, int Rm, int Rs, int Rn);
+ virtual void SMLAL(int cc, int xy,
+ int RdHi, int RdLo, int Rs, int Rm);
+ virtual void SMLAW(int cc, int y,
+ int Rd, int Rm, int Rs, int Rn);
+
+ virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
+ virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
+
+ virtual void ADDR_LDR(int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void ADDR_STR (int cc, int Rd,
+ int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void ADDR_ADD(int cc, int s, int Rd,
+ int Rn, uint32_t Op2);
+ virtual void ADDR_SUB(int cc, int s, int Rd,
+ int Rn, uint32_t Op2);
+
+private:
+ ARMAssemblerInterface* mTarget;
+};
+
+}; // namespace android
+
+#endif //ANDROID_ARMASSEMBLER_PROXY_H
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.cpp b/libpixelflinger/codeflinger/Arm64Assembler.cpp
new file mode 100644
index 0000000..271a9b9
--- /dev/null
+++ b/libpixelflinger/codeflinger/Arm64Assembler.cpp
@@ -0,0 +1,1240 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * 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.
+ *
+ * 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.
+ */
+
+#define LOG_TAG "ArmToArm64Assembler"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cutils/properties.h>
+#include <log/log.h>
+#include <private/pixelflinger/ggl_context.h>
+
+#include "codeflinger/Arm64Assembler.h"
+#include "codeflinger/Arm64Disassembler.h"
+#include "codeflinger/CodeCache.h"
+
+/*
+** --------------------------------------------
+** Support for Arm64 in GGLAssembler JIT
+** --------------------------------------------
+**
+** Approach
+** - GGLAssembler and associated files are largely un-changed.
+** - A translator class maps ArmAssemblerInterface calls to
+** generate Arm64 instructions.
+**
+** ----------------------
+** ArmToArm64Assembler
+** ----------------------
+**
+** - Subclassed from ArmAssemblerInterface
+**
+** - Translates each ArmAssemblerInterface call to generate
+** one or more Arm64 instructions as necessary.
+**
+** - Does not implement ArmAssemblerInterface portions unused by GGLAssembler
+** It calls NOT_IMPLEMENTED() for such cases, which in turn logs
+** a fatal message.
+**
+** - Uses A64_.. series of functions to generate instruction machine code
+** for Arm64 instructions. These functions also log the instruction
+** to LOG, if ARM64_ASM_DEBUG define is set to 1
+**
+** - Dumps machine code and eqvt assembly if "debug.pf.disasm" option is set
+** It uses arm64_disassemble to perform disassembly
+**
+** - Uses register 13 (SP in ARM), 15 (PC in ARM), 16, 17 for storing
+** intermediate results. GGLAssembler does not use SP and PC as these
+** registers are marked as reserved. The temporary registers are not
+** saved/restored on stack as these are caller-saved registers in Arm64
+**
+** - Uses CSEL instruction to support conditional execution. The result is
+** stored in a temporary register and then copied to the target register
+** if the condition is true.
+**
+** - In the case of conditional data transfer instructions, conditional
+** branch is used to skip over instruction, if the condition is false
+**
+** - Wherever possible, immediate values are transferred to temporary
+** register prior to processing. This simplifies overall implementation
+** as instructions requiring immediate values are converted to
+** move immediate instructions followed by register-register instruction.
+**
+** --------------------------------------------
+** ArmToArm64Assembler unit test bench
+** --------------------------------------------
+**
+** - Tests ArmToArm64Assembler interface for all the possible
+** ways in which GGLAssembler uses ArmAssemblerInterface interface.
+**
+** - Uses test jacket (written in assembly) to set the registers,
+** condition flags prior to calling generated instruction. It also
+** copies registers and flags at the end of execution. Caller then
+** checks if generated code performed correct operation based on
+** output registers and flags.
+**
+** - Broadly contains three type of tests, (i) data operation tests
+** (ii) data transfer tests and (iii) LDM/STM tests.
+**
+** ----------------------
+** Arm64 disassembler
+** ----------------------
+** - This disassembler disassembles only those machine codes which can be
+** generated by ArmToArm64Assembler. It has a unit testbench which
+** tests all the instructions supported by the disassembler.
+**
+** ------------------------------------------------------------------
+** ARMAssembler/ARMAssemblerInterface/ARMAssemblerProxy changes
+** ------------------------------------------------------------------
+**
+** - In existing code, addresses were being handled as 32 bit values at
+** certain places.
+**
+** - Added a new set of functions for address load/store/manipulation.
+** These are ADDR_LDR, ADDR_STR, ADDR_ADD, ADDR_SUB and they map to
+** default 32 bit implementations in ARMAssemblerInterface.
+**
+** - ArmToArm64Assembler maps these functions to appropriate 64 bit
+** functions.
+**
+** ----------------------
+** GGLAssembler changes
+** ----------------------
+** - Since ArmToArm64Assembler can generate 4 Arm64 instructions for
+** each call in worst case, the memory required is set to 4 times
+** ARM memory
+**
+** - Address load/store/manipulation were changed to use new functions
+** added in the ARMAssemblerInterface.
+**
+*/
+
+
+#define NOT_IMPLEMENTED() LOG_FATAL("Arm instruction %s not yet implemented\n", __func__)
+
+#define ARM64_ASM_DEBUG 0
+
+#if ARM64_ASM_DEBUG
+ #define LOG_INSTR(...) ALOGD("\t" __VA_ARGS__)
+ #define LOG_LABEL(...) ALOGD(__VA_ARGS__)
+#else
+ #define LOG_INSTR(...) ((void)0)
+ #define LOG_LABEL(...) ((void)0)
+#endif
+
+namespace android {
+
+static __unused const char* shift_codes[] =
+{
+ "LSL", "LSR", "ASR", "ROR"
+};
+static __unused const char *cc_codes[] =
+{
+ "EQ", "NE", "CS", "CC", "MI",
+ "PL", "VS", "VC", "HI", "LS",
+ "GE", "LT", "GT", "LE", "AL", "NV"
+};
+
+ArmToArm64Assembler::ArmToArm64Assembler(const sp<Assembly>& assembly)
+ : ARMAssemblerInterface(),
+ mAssembly(assembly)
+{
+ mBase = mPC = (uint32_t *)assembly->base();
+ mDuration = ggl_system_time();
+ mZeroReg = 13;
+ mTmpReg1 = 15;
+ mTmpReg2 = 16;
+ mTmpReg3 = 17;
+}
+
+ArmToArm64Assembler::ArmToArm64Assembler(void *base)
+ : ARMAssemblerInterface(), mAssembly(NULL)
+{
+ mBase = mPC = (uint32_t *)base;
+ mDuration = ggl_system_time();
+ // Regs 13, 15, 16, 17 are used as temporary registers
+ mZeroReg = 13;
+ mTmpReg1 = 15;
+ mTmpReg2 = 16;
+ mTmpReg3 = 17;
+}
+
+ArmToArm64Assembler::~ArmToArm64Assembler()
+{
+}
+
+uint32_t* ArmToArm64Assembler::pc() const
+{
+ return mPC;
+}
+
+uint32_t* ArmToArm64Assembler::base() const
+{
+ return mBase;
+}
+
+void ArmToArm64Assembler::reset()
+{
+ if(mAssembly == NULL)
+ mPC = mBase;
+ else
+ mBase = mPC = (uint32_t *)mAssembly->base();
+ mBranchTargets.clear();
+ mLabels.clear();
+ mLabelsInverseMapping.clear();
+ mComments.clear();
+#if ARM64_ASM_DEBUG
+ ALOGI("RESET\n");
+#endif
+}
+
+int ArmToArm64Assembler::getCodegenArch()
+{
+ return CODEGEN_ARCH_ARM64;
+}
+
+// ----------------------------------------------------------------------------
+
+void ArmToArm64Assembler::disassemble(const char* name)
+{
+ if(name)
+ {
+ printf("%s:\n", name);
+ }
+ size_t count = pc()-base();
+ uint32_t* i = base();
+ while (count--)
+ {
+ ssize_t label = mLabelsInverseMapping.indexOfKey(i);
+ if (label >= 0)
+ {
+ printf("%s:\n", mLabelsInverseMapping.valueAt(label));
+ }
+ ssize_t comment = mComments.indexOfKey(i);
+ if (comment >= 0)
+ {
+ printf("; %s\n", mComments.valueAt(comment));
+ }
+ printf("%p: %08x ", i, uint32_t(i[0]));
+ {
+ char instr[256];
+ ::arm64_disassemble(*i, instr);
+ printf("%s\n", instr);
+ }
+ i++;
+ }
+}
+
+void ArmToArm64Assembler::comment(const char* string)
+{
+ mComments.add(mPC, string);
+ LOG_INSTR("//%s\n", string);
+}
+
+void ArmToArm64Assembler::label(const char* theLabel)
+{
+ mLabels.add(theLabel, mPC);
+ mLabelsInverseMapping.add(mPC, theLabel);
+ LOG_LABEL("%s:\n", theLabel);
+}
+
+void ArmToArm64Assembler::B(int cc, const char* label)
+{
+ mBranchTargets.add(branch_target_t(label, mPC));
+ LOG_INSTR("B%s %s\n", cc_codes[cc], label );
+ *mPC++ = (0x54 << 24) | cc;
+}
+
+void ArmToArm64Assembler::BL(int /*cc*/, const char* /*label*/)
+{
+ NOT_IMPLEMENTED(); //Not Required
+}
+
+// ----------------------------------------------------------------------------
+//Prolog/Epilog & Generate...
+// ----------------------------------------------------------------------------
+
+void ArmToArm64Assembler::prolog()
+{
+ // write prolog code
+ mPrologPC = mPC;
+ *mPC++ = A64_MOVZ_X(mZeroReg,0,0);
+}
+
+void ArmToArm64Assembler::epilog(uint32_t /*touched*/)
+{
+ // write epilog code
+ static const int XLR = 30;
+ *mPC++ = A64_RET(XLR);
+}
+
+int ArmToArm64Assembler::generate(const char* name)
+{
+ // fixup all the branches
+ size_t count = mBranchTargets.size();
+ while (count--)
+ {
+ const branch_target_t& bt = mBranchTargets[count];
+ uint32_t* target_pc = mLabels.valueFor(bt.label);
+ LOG_ALWAYS_FATAL_IF(!target_pc,
+ "error resolving branch targets, target_pc is null");
+ int32_t offset = int32_t(target_pc - bt.pc);
+ *bt.pc |= (offset & 0x7FFFF) << 5;
+ }
+
+ if(mAssembly != NULL)
+ mAssembly->resize( int(pc()-base())*4 );
+
+ // the instruction cache is flushed by CodeCache
+ const int64_t duration = ggl_system_time() - mDuration;
+ const char * const format = "generated %s (%d ins) at [%p:%p] in %" PRId64 "ns\n";
+ ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
+
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.pf.disasm", value, "0");
+ if (atoi(value) != 0)
+ {
+ printf(format, name, int(pc()-base()), base(), pc(), duration);
+ disassemble(name);
+ }
+ return OK;
+}
+
+uint32_t* ArmToArm64Assembler::pcForLabel(const char* label)
+{
+ return mLabels.valueFor(label);
+}
+
+// ----------------------------------------------------------------------------
+// Data Processing...
+// ----------------------------------------------------------------------------
+void ArmToArm64Assembler::dataProcessingCommon(int opcode,
+ int s, int Rd, int Rn, uint32_t Op2)
+{
+ if(opcode != opSUB && s == 1)
+ {
+ NOT_IMPLEMENTED(); //Not required
+ return;
+ }
+
+ if(opcode != opSUB && opcode != opADD && opcode != opAND &&
+ opcode != opORR && opcode != opMVN)
+ {
+ NOT_IMPLEMENTED(); //Not required
+ return;
+ }
+
+ if(Op2 == OPERAND_REG_IMM && mAddrMode.reg_imm_shift > 31)
+ {
+ NOT_IMPLEMENTED();
+ return;
+ }
+
+ //Store immediate in temporary register and convert
+ //immediate operation into register operation
+ if(Op2 == OPERAND_IMM)
+ {
+ int imm = mAddrMode.immediate;
+ *mPC++ = A64_MOVZ_W(mTmpReg2, imm & 0x0000FFFF, 0);
+ *mPC++ = A64_MOVK_W(mTmpReg2, (imm >> 16) & 0x0000FFFF, 16);
+ Op2 = mTmpReg2;
+ }
+
+
+ {
+ uint32_t shift;
+ uint32_t amount;
+ uint32_t Rm;
+
+ if(Op2 == OPERAND_REG_IMM)
+ {
+ shift = mAddrMode.reg_imm_type;
+ amount = mAddrMode.reg_imm_shift;
+ Rm = mAddrMode.reg_imm_Rm;
+ }
+ else if(Op2 < OPERAND_REG)
+ {
+ shift = 0;
+ amount = 0;
+ Rm = Op2;
+ }
+ else
+ {
+ NOT_IMPLEMENTED(); //Not required
+ return;
+ }
+
+ switch(opcode)
+ {
+ case opADD: *mPC++ = A64_ADD_W(Rd, Rn, Rm, shift, amount); break;
+ case opAND: *mPC++ = A64_AND_W(Rd, Rn, Rm, shift, amount); break;
+ case opORR: *mPC++ = A64_ORR_W(Rd, Rn, Rm, shift, amount); break;
+ case opMVN: *mPC++ = A64_ORN_W(Rd, Rn, Rm, shift, amount); break;
+ case opSUB: *mPC++ = A64_SUB_W(Rd, Rn, Rm, shift, amount, s);break;
+ };
+
+ }
+}
+
+void ArmToArm64Assembler::dataProcessing(int opcode, int cc,
+ int s, int Rd, int Rn, uint32_t Op2)
+{
+ uint32_t Wd;
+
+ if(cc != AL)
+ Wd = mTmpReg1;
+ else
+ Wd = Rd;
+
+ if(opcode == opADD || opcode == opAND || opcode == opORR ||opcode == opSUB)
+ {
+ dataProcessingCommon(opcode, s, Wd, Rn, Op2);
+ }
+ else if(opcode == opCMP)
+ {
+ dataProcessingCommon(opSUB, 1, mTmpReg3, Rn, Op2);
+ }
+ else if(opcode == opRSB)
+ {
+ dataProcessingCommon(opSUB, s, Wd, Rn, Op2);
+ dataProcessingCommon(opSUB, s, Wd, mZeroReg, Wd);
+ }
+ else if(opcode == opMOV)
+ {
+ dataProcessingCommon(opORR, 0, Wd, mZeroReg, Op2);
+ if(s == 1)
+ {
+ dataProcessingCommon(opSUB, 1, mTmpReg3, Wd, mZeroReg);
+ }
+ }
+ else if(opcode == opMVN)
+ {
+ dataProcessingCommon(opMVN, s, Wd, mZeroReg, Op2);
+ }
+ else if(opcode == opBIC)
+ {
+ dataProcessingCommon(opMVN, s, mTmpReg3, mZeroReg, Op2);
+ dataProcessingCommon(opAND, s, Wd, Rn, mTmpReg3);
+ }
+ else
+ {
+ NOT_IMPLEMENTED();
+ return;
+ }
+
+ if(cc != AL)
+ {
+ *mPC++ = A64_CSEL_W(Rd, mTmpReg1, Rd, cc);
+ }
+}
+// ----------------------------------------------------------------------------
+// Address Processing...
+// ----------------------------------------------------------------------------
+
+void ArmToArm64Assembler::ADDR_ADD(int cc,
+ int s, int Rd, int Rn, uint32_t Op2)
+{
+ if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+ if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
+
+
+ if(Op2 == OPERAND_REG_IMM && mAddrMode.reg_imm_type == LSL)
+ {
+ int Rm = mAddrMode.reg_imm_Rm;
+ int amount = mAddrMode.reg_imm_shift;
+ *mPC++ = A64_ADD_X_Wm_SXTW(Rd, Rn, Rm, amount);
+ }
+ else if(Op2 < OPERAND_REG)
+ {
+ int Rm = Op2;
+ int amount = 0;
+ *mPC++ = A64_ADD_X_Wm_SXTW(Rd, Rn, Rm, amount);
+ }
+ else if(Op2 == OPERAND_IMM)
+ {
+ int imm = mAddrMode.immediate;
+ *mPC++ = A64_MOVZ_W(mTmpReg1, imm & 0x0000FFFF, 0);
+ *mPC++ = A64_MOVK_W(mTmpReg1, (imm >> 16) & 0x0000FFFF, 16);
+
+ int Rm = mTmpReg1;
+ int amount = 0;
+ *mPC++ = A64_ADD_X_Wm_SXTW(Rd, Rn, Rm, amount);
+ }
+ else
+ {
+ NOT_IMPLEMENTED(); //Not required
+ }
+}
+
+void ArmToArm64Assembler::ADDR_SUB(int cc,
+ int s, int Rd, int Rn, uint32_t Op2)
+{
+ if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+ if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
+
+ if(Op2 == OPERAND_REG_IMM && mAddrMode.reg_imm_type == LSR)
+ {
+ *mPC++ = A64_ADD_W(mTmpReg1, mZeroReg, mAddrMode.reg_imm_Rm,
+ LSR, mAddrMode.reg_imm_shift);
+ *mPC++ = A64_SUB_X_Wm_SXTW(Rd, Rn, mTmpReg1, 0);
+ }
+ else
+ {
+ NOT_IMPLEMENTED(); //Not required
+ }
+}
+
+// ----------------------------------------------------------------------------
+// multiply...
+// ----------------------------------------------------------------------------
+void ArmToArm64Assembler::MLA(int cc, int s,int Rd, int Rm, int Rs, int Rn)
+{
+ if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+
+ *mPC++ = A64_MADD_W(Rd, Rm, Rs, Rn);
+ if(s == 1)
+ dataProcessingCommon(opSUB, 1, mTmpReg1, Rd, mZeroReg);
+}
+void ArmToArm64Assembler::MUL(int cc, int s, int Rd, int Rm, int Rs)
+{
+ if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+ if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
+ *mPC++ = A64_MADD_W(Rd, Rm, Rs, mZeroReg);
+}
+void ArmToArm64Assembler::UMULL(int /*cc*/, int /*s*/,
+ int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+void ArmToArm64Assembler::UMUAL(int /*cc*/, int /*s*/,
+ int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+void ArmToArm64Assembler::SMULL(int /*cc*/, int /*s*/,
+ int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+void ArmToArm64Assembler::SMUAL(int /*cc*/, int /*s*/,
+ int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+
+// ----------------------------------------------------------------------------
+// branches relative to PC...
+// ----------------------------------------------------------------------------
+void ArmToArm64Assembler::B(int /*cc*/, uint32_t* /*pc*/){
+ NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToArm64Assembler::BL(int /*cc*/, uint32_t* /*pc*/){
+ NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToArm64Assembler::BX(int /*cc*/, int /*Rn*/){
+ NOT_IMPLEMENTED(); //Not required
+}
+
+// ----------------------------------------------------------------------------
+// data transfer...
+// ----------------------------------------------------------------------------
+enum dataTransferOp
+{
+ opLDR,opLDRB,opLDRH,opSTR,opSTRB,opSTRH
+};
+
+void ArmToArm64Assembler::dataTransfer(int op, int cc,
+ int Rd, int Rn, uint32_t op_type, uint32_t size)
+{
+ const int XSP = 31;
+ if(Rn == SP)
+ Rn = XSP;
+
+ if(op_type == OPERAND_IMM)
+ {
+ int addrReg;
+ int imm = mAddrMode.immediate;
+ if(imm >= 0 && imm < (1<<12))
+ *mPC++ = A64_ADD_IMM_X(mTmpReg1, mZeroReg, imm, 0);
+ else if(imm < 0 && -imm < (1<<12))
+ *mPC++ = A64_SUB_IMM_X(mTmpReg1, mZeroReg, -imm, 0);
+ else
+ {
+ NOT_IMPLEMENTED();
+ return;
+ }
+
+ addrReg = Rn;
+ if(mAddrMode.preindex == true || mAddrMode.postindex == true)
+ {
+ *mPC++ = A64_ADD_X(mTmpReg2, addrReg, mTmpReg1);
+ if(mAddrMode.preindex == true)
+ addrReg = mTmpReg2;
+ }
+
+ if(cc != AL)
+ *mPC++ = A64_B_COND(cc^1, 8);
+
+ *mPC++ = A64_LDRSTR_Wm_SXTW_0(op, size, Rd, addrReg, mZeroReg);
+
+ if(mAddrMode.writeback == true)
+ *mPC++ = A64_CSEL_X(Rn, mTmpReg2, Rn, cc);
+ }
+ else if(op_type == OPERAND_REG_OFFSET)
+ {
+ if(cc != AL)
+ *mPC++ = A64_B_COND(cc^1, 8);
+ *mPC++ = A64_LDRSTR_Wm_SXTW_0(op, size, Rd, Rn, mAddrMode.reg_offset);
+
+ }
+ else if(op_type > OPERAND_UNSUPPORTED)
+ {
+ if(cc != AL)
+ *mPC++ = A64_B_COND(cc^1, 8);
+ *mPC++ = A64_LDRSTR_Wm_SXTW_0(op, size, Rd, Rn, mZeroReg);
+ }
+ else
+ {
+ NOT_IMPLEMENTED(); // Not required
+ }
+ return;
+
+}
+void ArmToArm64Assembler::ADDR_LDR(int cc, int Rd, int Rn, uint32_t op_type)
+{
+ return dataTransfer(opLDR, cc, Rd, Rn, op_type, 64);
+}
+void ArmToArm64Assembler::ADDR_STR(int cc, int Rd, int Rn, uint32_t op_type)
+{
+ return dataTransfer(opSTR, cc, Rd, Rn, op_type, 64);
+}
+void ArmToArm64Assembler::LDR(int cc, int Rd, int Rn, uint32_t op_type)
+{
+ return dataTransfer(opLDR, cc, Rd, Rn, op_type);
+}
+void ArmToArm64Assembler::LDRB(int cc, int Rd, int Rn, uint32_t op_type)
+{
+ return dataTransfer(opLDRB, cc, Rd, Rn, op_type);
+}
+void ArmToArm64Assembler::STR(int cc, int Rd, int Rn, uint32_t op_type)
+{
+ return dataTransfer(opSTR, cc, Rd, Rn, op_type);
+}
+
+void ArmToArm64Assembler::STRB(int cc, int Rd, int Rn, uint32_t op_type)
+{
+ return dataTransfer(opSTRB, cc, Rd, Rn, op_type);
+}
+
+void ArmToArm64Assembler::LDRH(int cc, int Rd, int Rn, uint32_t op_type)
+{
+ return dataTransfer(opLDRH, cc, Rd, Rn, op_type);
+}
+void ArmToArm64Assembler::LDRSB(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+void ArmToArm64Assembler::LDRSH(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToArm64Assembler::STRH(int cc, int Rd, int Rn, uint32_t op_type)
+{
+ return dataTransfer(opSTRH, cc, Rd, Rn, op_type);
+}
+
+// ----------------------------------------------------------------------------
+// block data transfer...
+// ----------------------------------------------------------------------------
+void ArmToArm64Assembler::LDM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list)
+{
+ const int XSP = 31;
+ if(cc != AL || dir != IA || W == 0 || Rn != SP)
+ {
+ NOT_IMPLEMENTED();
+ return;
+ }
+
+ for(int i = 0; i < 32; ++i)
+ {
+ if((reg_list & (1 << i)))
+ {
+ int reg = i;
+ int size = 16;
+ *mPC++ = A64_LDR_IMM_PostIndex(reg, XSP, size);
+ }
+ }
+}
+
+void ArmToArm64Assembler::STM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list)
+{
+ const int XSP = 31;
+ if(cc != AL || dir != DB || W == 0 || Rn != SP)
+ {
+ NOT_IMPLEMENTED();
+ return;
+ }
+
+ for(int i = 31; i >= 0; --i)
+ {
+ if((reg_list & (1 << i)))
+ {
+ int size = -16;
+ int reg = i;
+ *mPC++ = A64_STR_IMM_PreIndex(reg, XSP, size);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// special...
+// ----------------------------------------------------------------------------
+void ArmToArm64Assembler::SWP(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+void ArmToArm64Assembler::SWPB(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+void ArmToArm64Assembler::SWI(int /*cc*/, uint32_t /*comment*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+
+// ----------------------------------------------------------------------------
+// DSP instructions...
+// ----------------------------------------------------------------------------
+void ArmToArm64Assembler::PLD(int /*Rn*/, uint32_t /*offset*/) {
+ NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToArm64Assembler::CLZ(int /*cc*/, int /*Rd*/, int /*Rm*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToArm64Assembler::QADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToArm64Assembler::QDADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToArm64Assembler::QSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToArm64Assembler::QDSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+}
+
+// ----------------------------------------------------------------------------
+// 16 x 16 multiplication
+// ----------------------------------------------------------------------------
+void ArmToArm64Assembler::SMUL(int cc, int xy,
+ int Rd, int Rm, int Rs)
+{
+ if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+
+ if (xy & xyTB)
+ *mPC++ = A64_SBFM_W(mTmpReg1, Rm, 16, 31);
+ else
+ *mPC++ = A64_SBFM_W(mTmpReg1, Rm, 0, 15);
+
+ if (xy & xyBT)
+ *mPC++ = A64_SBFM_W(mTmpReg2, Rs, 16, 31);
+ else
+ *mPC++ = A64_SBFM_W(mTmpReg2, Rs, 0, 15);
+
+ *mPC++ = A64_MADD_W(Rd,mTmpReg1,mTmpReg2, mZeroReg);
+}
+// ----------------------------------------------------------------------------
+// 32 x 16 multiplication
+// ----------------------------------------------------------------------------
+void ArmToArm64Assembler::SMULW(int cc, int y, int Rd, int Rm, int Rs)
+{
+ if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+
+ if (y & yT)
+ *mPC++ = A64_SBFM_W(mTmpReg1, Rs, 16, 31);
+ else
+ *mPC++ = A64_SBFM_W(mTmpReg1, Rs, 0, 15);
+
+ *mPC++ = A64_SBFM_W(mTmpReg2, Rm, 0, 31);
+ *mPC++ = A64_SMADDL(mTmpReg3,mTmpReg1,mTmpReg2, mZeroReg);
+ *mPC++ = A64_UBFM_X(Rd,mTmpReg3, 16, 47);
+}
+// ----------------------------------------------------------------------------
+// 16 x 16 multiplication and accumulate
+// ----------------------------------------------------------------------------
+void ArmToArm64Assembler::SMLA(int cc, int xy, int Rd, int Rm, int Rs, int Rn)
+{
+ if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+ if(xy != xyBB) { NOT_IMPLEMENTED(); return;} //Not required
+
+ *mPC++ = A64_SBFM_W(mTmpReg1, Rm, 0, 15);
+ *mPC++ = A64_SBFM_W(mTmpReg2, Rs, 0, 15);
+ *mPC++ = A64_MADD_W(Rd, mTmpReg1, mTmpReg2, Rn);
+}
+
+void ArmToArm64Assembler::SMLAL(int /*cc*/, int /*xy*/,
+ int /*RdHi*/, int /*RdLo*/, int /*Rs*/, int /*Rm*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+ return;
+}
+
+void ArmToArm64Assembler::SMLAW(int /*cc*/, int /*y*/,
+ int /*Rd*/, int /*Rm*/, int /*Rs*/, int /*Rn*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+ return;
+}
+
+// ----------------------------------------------------------------------------
+// Byte/half word extract and extend
+// ----------------------------------------------------------------------------
+void ArmToArm64Assembler::UXTB16(int cc, int Rd, int Rm, int rotate)
+{
+ if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+
+ *mPC++ = A64_EXTR_W(mTmpReg1, Rm, Rm, rotate * 8);
+
+ uint32_t imm = 0x00FF00FF;
+ *mPC++ = A64_MOVZ_W(mTmpReg2, imm & 0xFFFF, 0);
+ *mPC++ = A64_MOVK_W(mTmpReg2, (imm >> 16) & 0x0000FFFF, 16);
+ *mPC++ = A64_AND_W(Rd,mTmpReg1, mTmpReg2);
+}
+
+// ----------------------------------------------------------------------------
+// Bit manipulation
+// ----------------------------------------------------------------------------
+void ArmToArm64Assembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
+{
+ if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+ *mPC++ = A64_UBFM_W(Rd, Rn, lsb, lsb + width - 1);
+}
+// ----------------------------------------------------------------------------
+// Shifters...
+// ----------------------------------------------------------------------------
+int ArmToArm64Assembler::buildImmediate(
+ uint32_t immediate, uint32_t& rot, uint32_t& imm)
+{
+ rot = 0;
+ imm = immediate;
+ return 0; // Always true
+}
+
+
+bool ArmToArm64Assembler::isValidImmediate(uint32_t immediate)
+{
+ uint32_t rot, imm;
+ return buildImmediate(immediate, rot, imm) == 0;
+}
+
+uint32_t ArmToArm64Assembler::imm(uint32_t immediate)
+{
+ mAddrMode.immediate = immediate;
+ mAddrMode.writeback = false;
+ mAddrMode.preindex = false;
+ mAddrMode.postindex = false;
+ return OPERAND_IMM;
+
+}
+
+uint32_t ArmToArm64Assembler::reg_imm(int Rm, int type, uint32_t shift)
+{
+ mAddrMode.reg_imm_Rm = Rm;
+ mAddrMode.reg_imm_type = type;
+ mAddrMode.reg_imm_shift = shift;
+ return OPERAND_REG_IMM;
+}
+
+uint32_t ArmToArm64Assembler::reg_rrx(int /*Rm*/)
+{
+ NOT_IMPLEMENTED();
+ return OPERAND_UNSUPPORTED;
+}
+
+uint32_t ArmToArm64Assembler::reg_reg(int /*Rm*/, int /*type*/, int /*Rs*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+ return OPERAND_UNSUPPORTED;
+}
+// ----------------------------------------------------------------------------
+// Addressing modes...
+// ----------------------------------------------------------------------------
+uint32_t ArmToArm64Assembler::immed12_pre(int32_t immed12, int W)
+{
+ mAddrMode.immediate = immed12;
+ mAddrMode.writeback = W;
+ mAddrMode.preindex = true;
+ mAddrMode.postindex = false;
+ return OPERAND_IMM;
+}
+
+uint32_t ArmToArm64Assembler::immed12_post(int32_t immed12)
+{
+ mAddrMode.immediate = immed12;
+ mAddrMode.writeback = true;
+ mAddrMode.preindex = false;
+ mAddrMode.postindex = true;
+ return OPERAND_IMM;
+}
+
+uint32_t ArmToArm64Assembler::reg_scale_pre(int Rm, int type,
+ uint32_t shift, int W)
+{
+ if(type != 0 || shift != 0 || W != 0)
+ {
+ NOT_IMPLEMENTED(); //Not required
+ return OPERAND_UNSUPPORTED;
+ }
+ else
+ {
+ mAddrMode.reg_offset = Rm;
+ return OPERAND_REG_OFFSET;
+ }
+}
+
+uint32_t ArmToArm64Assembler::reg_scale_post(int /*Rm*/, int /*type*/, uint32_t /*shift*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+ return OPERAND_UNSUPPORTED;
+}
+
+uint32_t ArmToArm64Assembler::immed8_pre(int32_t immed8, int W)
+{
+ mAddrMode.immediate = immed8;
+ mAddrMode.writeback = W;
+ mAddrMode.preindex = true;
+ mAddrMode.postindex = false;
+ return OPERAND_IMM;
+}
+
+uint32_t ArmToArm64Assembler::immed8_post(int32_t immed8)
+{
+ mAddrMode.immediate = immed8;
+ mAddrMode.writeback = true;
+ mAddrMode.preindex = false;
+ mAddrMode.postindex = true;
+ return OPERAND_IMM;
+}
+
+uint32_t ArmToArm64Assembler::reg_pre(int Rm, int W)
+{
+ if(W != 0)
+ {
+ NOT_IMPLEMENTED(); //Not required
+ return OPERAND_UNSUPPORTED;
+ }
+ else
+ {
+ mAddrMode.reg_offset = Rm;
+ return OPERAND_REG_OFFSET;
+ }
+}
+
+uint32_t ArmToArm64Assembler::reg_post(int /*Rm*/)
+{
+ NOT_IMPLEMENTED(); //Not required
+ return OPERAND_UNSUPPORTED;
+}
+
+// ----------------------------------------------------------------------------
+// A64 instructions
+// ----------------------------------------------------------------------------
+
+static __unused const char * dataTransferOpName[] =
+{
+ "LDR","LDRB","LDRH","STR","STRB","STRH"
+};
+
+static const uint32_t dataTransferOpCode [] =
+{
+ ((0xB8u << 24) | (0x3 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11)),
+ ((0x38u << 24) | (0x3 << 21) | (0x6 << 13) | (0x1 << 12) |(0x1 << 11)),
+ ((0x78u << 24) | (0x3 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11)),
+ ((0xB8u << 24) | (0x1 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11)),
+ ((0x38u << 24) | (0x1 << 21) | (0x6 << 13) | (0x1 << 12) |(0x1 << 11)),
+ ((0x78u << 24) | (0x1 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11))
+};
+uint32_t ArmToArm64Assembler::A64_LDRSTR_Wm_SXTW_0(uint32_t op,
+ uint32_t size, uint32_t Rt,
+ uint32_t Rn, uint32_t Rm)
+{
+ if(size == 32)
+ {
+ LOG_INSTR("%s W%d, [X%d, W%d, SXTW #0]\n",
+ dataTransferOpName[op], Rt, Rn, Rm);
+ return(dataTransferOpCode[op] | (Rm << 16) | (Rn << 5) | Rt);
+ }
+ else
+ {
+ LOG_INSTR("%s X%d, [X%d, W%d, SXTW #0]\n",
+ dataTransferOpName[op], Rt, Rn, Rm);
+ return(dataTransferOpCode[op] | (0x1<<30) | (Rm<<16) | (Rn<<5)|Rt);
+ }
+}
+
+uint32_t ArmToArm64Assembler::A64_STR_IMM_PreIndex(uint32_t Rt,
+ uint32_t Rn, int32_t simm)
+{
+ if(Rn == 31)
+ LOG_INSTR("STR W%d, [SP, #%d]!\n", Rt, simm);
+ else
+ LOG_INSTR("STR W%d, [X%d, #%d]!\n", Rt, Rn, simm);
+
+ uint32_t imm9 = (unsigned)(simm) & 0x01FF;
+ return (0xB8 << 24) | (imm9 << 12) | (0x3 << 10) | (Rn << 5) | Rt;
+}
+
+uint32_t ArmToArm64Assembler::A64_LDR_IMM_PostIndex(uint32_t Rt,
+ uint32_t Rn, int32_t simm)
+{
+ if(Rn == 31)
+ LOG_INSTR("LDR W%d, [SP], #%d\n",Rt,simm);
+ else
+ LOG_INSTR("LDR W%d, [X%d], #%d\n",Rt, Rn, simm);
+
+ uint32_t imm9 = (unsigned)(simm) & 0x01FF;
+ return (0xB8 << 24) | (0x1 << 22) |
+ (imm9 << 12) | (0x1 << 10) | (Rn << 5) | Rt;
+
+}
+uint32_t ArmToArm64Assembler::A64_ADD_X_Wm_SXTW(uint32_t Rd,
+ uint32_t Rn,
+ uint32_t Rm,
+ uint32_t amount)
+{
+ LOG_INSTR("ADD X%d, X%d, W%d, SXTW #%d\n", Rd, Rn, Rm, amount);
+ return ((0x8B << 24) | (0x1 << 21) |(Rm << 16) |
+ (0x6 << 13) | (amount << 10) | (Rn << 5) | Rd);
+
+}
+
+uint32_t ArmToArm64Assembler::A64_SUB_X_Wm_SXTW(uint32_t Rd,
+ uint32_t Rn,
+ uint32_t Rm,
+ uint32_t amount)
+{
+ LOG_INSTR("SUB X%d, X%d, W%d, SXTW #%d\n", Rd, Rn, Rm, amount);
+ return ((0xCB << 24) | (0x1 << 21) |(Rm << 16) |
+ (0x6 << 13) | (amount << 10) | (Rn << 5) | Rd);
+
+}
+
+uint32_t ArmToArm64Assembler::A64_B_COND(uint32_t cc, uint32_t offset)
+{
+ LOG_INSTR("B.%s #.+%d\n", cc_codes[cc], offset);
+ return (0x54 << 24) | ((offset/4) << 5) | (cc);
+
+}
+uint32_t ArmToArm64Assembler::A64_ADD_X(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t shift,
+ uint32_t amount)
+{
+ LOG_INSTR("ADD X%d, X%d, X%d, %s #%d\n",
+ Rd, Rn, Rm, shift_codes[shift], amount);
+ return ((0x8B << 24) | (shift << 22) | ( Rm << 16) |
+ (amount << 10) |(Rn << 5) | Rd);
+}
+uint32_t ArmToArm64Assembler::A64_ADD_IMM_X(uint32_t Rd, uint32_t Rn,
+ uint32_t imm, uint32_t shift)
+{
+ LOG_INSTR("ADD X%d, X%d, #%d, LSL #%d\n", Rd, Rn, imm, shift);
+ return (0x91 << 24) | ((shift/12) << 22) | (imm << 10) | (Rn << 5) | Rd;
+}
+
+uint32_t ArmToArm64Assembler::A64_SUB_IMM_X(uint32_t Rd, uint32_t Rn,
+ uint32_t imm, uint32_t shift)
+{
+ LOG_INSTR("SUB X%d, X%d, #%d, LSL #%d\n", Rd, Rn, imm, shift);
+ return (0xD1 << 24) | ((shift/12) << 22) | (imm << 10) | (Rn << 5) | Rd;
+}
+
+uint32_t ArmToArm64Assembler::A64_ADD_W(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t shift,
+ uint32_t amount)
+{
+ LOG_INSTR("ADD W%d, W%d, W%d, %s #%d\n",
+ Rd, Rn, Rm, shift_codes[shift], amount);
+ return ((0x0B << 24) | (shift << 22) | ( Rm << 16) |
+ (amount << 10) |(Rn << 5) | Rd);
+}
+
+uint32_t ArmToArm64Assembler::A64_SUB_W(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t shift,
+ uint32_t amount,
+ uint32_t setflag)
+{
+ if(setflag == 0)
+ {
+ LOG_INSTR("SUB W%d, W%d, W%d, %s #%d\n",
+ Rd, Rn, Rm, shift_codes[shift], amount);
+ return ((0x4B << 24) | (shift << 22) | ( Rm << 16) |
+ (amount << 10) |(Rn << 5) | Rd);
+ }
+ else
+ {
+ LOG_INSTR("SUBS W%d, W%d, W%d, %s #%d\n",
+ Rd, Rn, Rm, shift_codes[shift], amount);
+ return ((0x6B << 24) | (shift << 22) | ( Rm << 16) |
+ (amount << 10) |(Rn << 5) | Rd);
+ }
+}
+
+uint32_t ArmToArm64Assembler::A64_AND_W(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t shift,
+ uint32_t amount)
+{
+ LOG_INSTR("AND W%d, W%d, W%d, %s #%d\n",
+ Rd, Rn, Rm, shift_codes[shift], amount);
+ return ((0x0A << 24) | (shift << 22) | ( Rm << 16) |
+ (amount << 10) |(Rn << 5) | Rd);
+}
+
+uint32_t ArmToArm64Assembler::A64_ORR_W(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t shift,
+ uint32_t amount)
+{
+ LOG_INSTR("ORR W%d, W%d, W%d, %s #%d\n",
+ Rd, Rn, Rm, shift_codes[shift], amount);
+ return ((0x2A << 24) | (shift << 22) | ( Rm << 16) |
+ (amount << 10) |(Rn << 5) | Rd);
+}
+
+uint32_t ArmToArm64Assembler::A64_ORN_W(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t shift,
+ uint32_t amount)
+{
+ LOG_INSTR("ORN W%d, W%d, W%d, %s #%d\n",
+ Rd, Rn, Rm, shift_codes[shift], amount);
+ return ((0x2A << 24) | (shift << 22) | (0x1 << 21) | ( Rm << 16) |
+ (amount << 10) |(Rn << 5) | Rd);
+}
+
+uint32_t ArmToArm64Assembler::A64_CSEL_X(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t cond)
+{
+ LOG_INSTR("CSEL X%d, X%d, X%d, %s\n", Rd, Rn, Rm, cc_codes[cond]);
+ return ((0x9A << 24)|(0x1 << 23)|(Rm << 16) |(cond << 12)| (Rn << 5) | Rd);
+}
+
+uint32_t ArmToArm64Assembler::A64_CSEL_W(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t cond)
+{
+ LOG_INSTR("CSEL W%d, W%d, W%d, %s\n", Rd, Rn, Rm, cc_codes[cond]);
+ return ((0x1A << 24)|(0x1 << 23)|(Rm << 16) |(cond << 12)| (Rn << 5) | Rd);
+}
+
+uint32_t ArmToArm64Assembler::A64_RET(uint32_t Rn)
+{
+ LOG_INSTR("RET X%d\n", Rn);
+ return ((0xD6 << 24) | (0x1 << 22) | (0x1F << 16) | (Rn << 5));
+}
+
+uint32_t ArmToArm64Assembler::A64_MOVZ_X(uint32_t Rd, uint32_t imm,
+ uint32_t shift)
+{
+ LOG_INSTR("MOVZ X%d, #0x%x, LSL #%d\n", Rd, imm, shift);
+ return(0xD2 << 24) | (0x1 << 23) | ((shift/16) << 21) | (imm << 5) | Rd;
+}
+
+uint32_t ArmToArm64Assembler::A64_MOVK_W(uint32_t Rd, uint32_t imm,
+ uint32_t shift)
+{
+ LOG_INSTR("MOVK W%d, #0x%x, LSL #%d\n", Rd, imm, shift);
+ return (0x72 << 24) | (0x1 << 23) | ((shift/16) << 21) | (imm << 5) | Rd;
+}
+
+uint32_t ArmToArm64Assembler::A64_MOVZ_W(uint32_t Rd, uint32_t imm,
+ uint32_t shift)
+{
+ LOG_INSTR("MOVZ W%d, #0x%x, LSL #%d\n", Rd, imm, shift);
+ return(0x52 << 24) | (0x1 << 23) | ((shift/16) << 21) | (imm << 5) | Rd;
+}
+
+uint32_t ArmToArm64Assembler::A64_SMADDL(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t Ra)
+{
+ LOG_INSTR("SMADDL X%d, W%d, W%d, X%d\n",Rd, Rn, Rm, Ra);
+ return ((0x9B << 24) | (0x1 << 21) | (Rm << 16)|(Ra << 10)|(Rn << 5) | Rd);
+}
+
+uint32_t ArmToArm64Assembler::A64_MADD_W(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t Ra)
+{
+ LOG_INSTR("MADD W%d, W%d, W%d, W%d\n",Rd, Rn, Rm, Ra);
+ return ((0x1B << 24) | (Rm << 16) | (Ra << 10) |(Rn << 5) | Rd);
+}
+
+uint32_t ArmToArm64Assembler::A64_SBFM_W(uint32_t Rd, uint32_t Rn,
+ uint32_t immr, uint32_t imms)
+{
+ LOG_INSTR("SBFM W%d, W%d, #%d, #%d\n", Rd, Rn, immr, imms);
+ return ((0x13 << 24) | (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
+
+}
+uint32_t ArmToArm64Assembler::A64_UBFM_W(uint32_t Rd, uint32_t Rn,
+ uint32_t immr, uint32_t imms)
+{
+ LOG_INSTR("UBFM W%d, W%d, #%d, #%d\n", Rd, Rn, immr, imms);
+ return ((0x53 << 24) | (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
+
+}
+uint32_t ArmToArm64Assembler::A64_UBFM_X(uint32_t Rd, uint32_t Rn,
+ uint32_t immr, uint32_t imms)
+{
+ LOG_INSTR("UBFM X%d, X%d, #%d, #%d\n", Rd, Rn, immr, imms);
+ return ((0xD3 << 24) | (0x1 << 22) |
+ (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
+
+}
+uint32_t ArmToArm64Assembler::A64_EXTR_W(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t lsb)
+{
+ LOG_INSTR("EXTR W%d, W%d, W%d, #%d\n", Rd, Rn, Rm, lsb);
+ return (0x13 << 24)|(0x1 << 23) | (Rm << 16) | (lsb << 10)|(Rn << 5) | Rd;
+}
+
+}; // namespace android
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.h b/libpixelflinger/codeflinger/Arm64Assembler.h
new file mode 100644
index 0000000..527c757
--- /dev/null
+++ b/libpixelflinger/codeflinger/Arm64Assembler.h
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef ANDROID_ARMTOARM64ASSEMBLER_H
+#define ANDROID_ARMTOARM64ASSEMBLER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "tinyutils/smartpointer.h"
+#include "utils/Vector.h"
+#include "utils/KeyedVector.h"
+
+#include "tinyutils/smartpointer.h"
+#include "codeflinger/ARMAssemblerInterface.h"
+#include "codeflinger/CodeCache.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class ArmToArm64Assembler : public ARMAssemblerInterface
+{
+public:
+ explicit ArmToArm64Assembler(const sp<Assembly>& assembly);
+ explicit ArmToArm64Assembler(void *base);
+ virtual ~ArmToArm64Assembler();
+
+ uint32_t* base() const;
+ uint32_t* pc() const;
+
+
+ void disassemble(const char* name);
+
+ // ------------------------------------------------------------------------
+ // ARMAssemblerInterface...
+ // ------------------------------------------------------------------------
+
+ virtual void reset();
+
+ virtual int generate(const char* name);
+ virtual int getCodegenArch();
+
+ virtual void prolog();
+ virtual void epilog(uint32_t touched);
+ virtual void comment(const char* string);
+
+
+ // -----------------------------------------------------------------------
+ // shifters and addressing modes
+ // -----------------------------------------------------------------------
+
+ // shifters...
+ virtual bool isValidImmediate(uint32_t immed);
+ virtual int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm);
+
+ virtual uint32_t imm(uint32_t immediate);
+ virtual uint32_t reg_imm(int Rm, int type, uint32_t shift);
+ virtual uint32_t reg_rrx(int Rm);
+ virtual uint32_t reg_reg(int Rm, int type, int Rs);
+
+ // addressing modes...
+ virtual uint32_t immed12_pre(int32_t immed12, int W=0);
+ virtual uint32_t immed12_post(int32_t immed12);
+ virtual uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0);
+ virtual uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0);
+ virtual uint32_t immed8_pre(int32_t immed8, int W=0);
+ virtual uint32_t immed8_post(int32_t immed8);
+ virtual uint32_t reg_pre(int Rm, int W=0);
+ virtual uint32_t reg_post(int Rm);
+
+
+ virtual void dataProcessing(int opcode, int cc, int s,
+ int Rd, int Rn,
+ uint32_t Op2);
+ virtual void MLA(int cc, int s,
+ int Rd, int Rm, int Rs, int Rn);
+ virtual void MUL(int cc, int s,
+ int Rd, int Rm, int Rs);
+ virtual void UMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+ virtual void UMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+ virtual void SMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+ virtual void SMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+
+ virtual void B(int cc, uint32_t* pc);
+ virtual void BL(int cc, uint32_t* pc);
+ virtual void BX(int cc, int Rn);
+ virtual void label(const char* theLabel);
+ virtual void B(int cc, const char* label);
+ virtual void BL(int cc, const char* label);
+
+ virtual uint32_t* pcForLabel(const char* label);
+
+ virtual void ADDR_LDR(int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void ADDR_ADD(int cc, int s, int Rd,
+ int Rn, uint32_t Op2);
+ virtual void ADDR_SUB(int cc, int s, int Rd,
+ int Rn, uint32_t Op2);
+ virtual void ADDR_STR (int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+
+ virtual void LDR (int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void LDRB(int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void STR (int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void STRB(int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void LDRH (int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void LDRSB(int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void LDRSH(int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void STRH (int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+
+
+ virtual void LDM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list);
+ virtual void STM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list);
+
+ virtual void SWP(int cc, int Rn, int Rd, int Rm);
+ virtual void SWPB(int cc, int Rn, int Rd, int Rm);
+ virtual void SWI(int cc, uint32_t comment);
+
+ virtual void PLD(int Rn, uint32_t offset);
+ virtual void CLZ(int cc, int Rd, int Rm);
+ virtual void QADD(int cc, int Rd, int Rm, int Rn);
+ virtual void QDADD(int cc, int Rd, int Rm, int Rn);
+ virtual void QSUB(int cc, int Rd, int Rm, int Rn);
+ virtual void QDSUB(int cc, int Rd, int Rm, int Rn);
+ virtual void SMUL(int cc, int xy,
+ int Rd, int Rm, int Rs);
+ virtual void SMULW(int cc, int y,
+ int Rd, int Rm, int Rs);
+ virtual void SMLA(int cc, int xy,
+ int Rd, int Rm, int Rs, int Rn);
+ virtual void SMLAL(int cc, int xy,
+ int RdHi, int RdLo, int Rs, int Rm);
+ virtual void SMLAW(int cc, int y,
+ int Rd, int Rm, int Rs, int Rn);
+ virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
+ virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
+
+private:
+ ArmToArm64Assembler(const ArmToArm64Assembler& rhs);
+ ArmToArm64Assembler& operator = (const ArmToArm64Assembler& rhs);
+
+ // -----------------------------------------------------------------------
+ // helper functions
+ // -----------------------------------------------------------------------
+
+ void dataTransfer(int operation, int cc, int Rd, int Rn,
+ uint32_t operand_type, uint32_t size = 32);
+ void dataProcessingCommon(int opcode, int s,
+ int Rd, int Rn, uint32_t Op2);
+
+ // -----------------------------------------------------------------------
+ // Arm64 instructions
+ // -----------------------------------------------------------------------
+ uint32_t A64_B_COND(uint32_t cc, uint32_t offset);
+ uint32_t A64_RET(uint32_t Rn);
+
+ uint32_t A64_LDRSTR_Wm_SXTW_0(uint32_t operation,
+ uint32_t size, uint32_t Rt,
+ uint32_t Rn, uint32_t Rm);
+
+ uint32_t A64_STR_IMM_PreIndex(uint32_t Rt, uint32_t Rn, int32_t simm);
+ uint32_t A64_LDR_IMM_PostIndex(uint32_t Rt,uint32_t Rn, int32_t simm);
+
+ uint32_t A64_ADD_X_Wm_SXTW(uint32_t Rd, uint32_t Rn, uint32_t Rm,
+ uint32_t amount);
+ uint32_t A64_SUB_X_Wm_SXTW(uint32_t Rd, uint32_t Rn, uint32_t Rm,
+ uint32_t amount);
+
+ uint32_t A64_ADD_IMM_X(uint32_t Rd, uint32_t Rn,
+ uint32_t imm, uint32_t shift = 0);
+ uint32_t A64_SUB_IMM_X(uint32_t Rd, uint32_t Rn,
+ uint32_t imm, uint32_t shift = 0);
+
+ uint32_t A64_ADD_X(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t shift = 0, uint32_t amount = 0);
+ uint32_t A64_ADD_W(uint32_t Rd, uint32_t Rn, uint32_t Rm,
+ uint32_t shift = 0, uint32_t amount = 0);
+ uint32_t A64_SUB_W(uint32_t Rd, uint32_t Rn, uint32_t Rm,
+ uint32_t shift = 0, uint32_t amount = 0,
+ uint32_t setflag = 0);
+ uint32_t A64_AND_W(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t shift = 0, uint32_t amount = 0);
+ uint32_t A64_ORR_W(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t shift = 0, uint32_t amount = 0);
+ uint32_t A64_ORN_W(uint32_t Rd, uint32_t Rn,
+ uint32_t Rm, uint32_t shift = 0, uint32_t amount = 0);
+
+ uint32_t A64_MOVZ_W(uint32_t Rd, uint32_t imm, uint32_t shift);
+ uint32_t A64_MOVZ_X(uint32_t Rd, uint32_t imm, uint32_t shift);
+ uint32_t A64_MOVK_W(uint32_t Rd, uint32_t imm, uint32_t shift);
+
+ uint32_t A64_SMADDL(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t Ra);
+ uint32_t A64_MADD_W(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t Ra);
+
+ uint32_t A64_SBFM_W(uint32_t Rd, uint32_t Rn,
+ uint32_t immr, uint32_t imms);
+ uint32_t A64_UBFM_W(uint32_t Rd, uint32_t Rn,
+ uint32_t immr, uint32_t imms);
+ uint32_t A64_UBFM_X(uint32_t Rd, uint32_t Rn,
+ uint32_t immr, uint32_t imms);
+
+ uint32_t A64_EXTR_W(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t lsb);
+ uint32_t A64_CSEL_X(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t cond);
+ uint32_t A64_CSEL_W(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t cond);
+
+ uint32_t* mBase;
+ uint32_t* mPC;
+ uint32_t* mPrologPC;
+ int64_t mDuration;
+ uint32_t mTmpReg1, mTmpReg2, mTmpReg3, mZeroReg;
+
+ struct branch_target_t {
+ inline branch_target_t() : label(0), pc(0) { }
+ inline branch_target_t(const char* l, uint32_t* p)
+ : label(l), pc(p) { }
+ const char* label;
+ uint32_t* pc;
+ };
+
+ sp<Assembly> mAssembly;
+ Vector<branch_target_t> mBranchTargets;
+ KeyedVector< const char*, uint32_t* > mLabels;
+ KeyedVector< uint32_t*, const char* > mLabelsInverseMapping;
+ KeyedVector< uint32_t*, const char* > mComments;
+
+ enum operand_type_t
+ {
+ OPERAND_REG = 0x20,
+ OPERAND_IMM,
+ OPERAND_REG_IMM,
+ OPERAND_REG_OFFSET,
+ OPERAND_UNSUPPORTED
+ };
+
+ struct addr_mode_t {
+ int32_t immediate;
+ bool writeback;
+ bool preindex;
+ bool postindex;
+ int32_t reg_imm_Rm;
+ int32_t reg_imm_type;
+ uint32_t reg_imm_shift;
+ int32_t reg_offset;
+ } mAddrMode;
+
+};
+
+}; // namespace android
+
+#endif //ANDROID_ARM64ASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/Arm64Disassembler.cpp b/libpixelflinger/codeflinger/Arm64Disassembler.cpp
new file mode 100644
index 0000000..70f1ff1
--- /dev/null
+++ b/libpixelflinger/codeflinger/Arm64Disassembler.cpp
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * 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.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+
+struct disasm_table_entry_t
+{
+ uint32_t mask;
+ uint32_t value;
+ const char* instr_template;
+};
+
+
+static disasm_table_entry_t disasm_table[] =
+{
+ {0xff000000, 0x91000000, "add <xd|sp>, <xn|sp>, #<imm1>, <shift1>"},
+ {0xff000000, 0xd1000000, "sub <xd|sp>, <xn|sp>, #<imm1>, <shift1>"},
+ {0xff200000, 0x8b000000, "add <xd>, <xn>, <xm>, <shift2> #<amt1>"},
+ {0xff200000, 0x0b000000, "add <wd>, <wn>, <wm>, <shift2> #<amt1>"},
+ {0xff200000, 0x4b000000, "sub <wd>, <wn>, <wm>, <shift2> #<amt1>"},
+ {0xff200000, 0x6b000000, "subs <wd>, <wn>, <wm>, <shift2> #<amt1>"},
+ {0xff200000, 0x0a000000, "and <wd>, <wn>, <wm>, <shift2> #<amt1>"},
+ {0xff200000, 0x2a000000, "orr <wd>, <wn>, <wm>, <shift2> #<amt1>"},
+ {0xff200000, 0x2a200000, "orn <wd>, <wn>, <wm>, <shift2> #<amt1>"},
+ {0xff800000, 0x72800000, "movk <wd>, #<imm2>, lsl #<shift3>"},
+ {0xff800000, 0x52800000, "movz <wd>, #<imm2>, lsl #<shift3>"},
+ {0xff800000, 0xd2800000, "movz <xd>, #<imm2>, lsl #<shift3>"},
+ {0xffe00c00, 0x1a800000, "csel <wd>, <wn>, <wm>, <cond1>"},
+ {0xffe00c00, 0x9a800000, "csel <xd>, <xn>, <xm>, <cond1>"},
+ {0xffe00c00, 0x5a800000, "csinv <wd>, <wn>, <wm>, <cond1>"},
+ {0xffe08000, 0x1b000000, "madd <wd>, <wn>, <wm>, <wa>"},
+ {0xffe08000, 0x9b200000, "smaddl <xd>, <wn>, <wm>, <xa>"},
+ {0xffe04c00, 0xb8604800, "ldr <wt>, [<xn|sp>, <r1><m1>, <ext1> #<amt2>]"},
+ {0xffe04c00, 0xb8204800, "str <wt>, [<xn|sp>, <r1><m1>, <ext1> #<amt2>]"},
+ {0xffe04c00, 0xf8604800, "ldr <xt>, [<xn|sp>, <r1><m1>, <ext1> #<amt3>]"},
+ {0xffe04c00, 0xf8204800, "str <xt>, [<xn|sp>, <r1><m1>, <ext1> #<amt3>]"},
+ {0xffe04c00, 0x38604800, "ldrb <wt>, [<xn|sp>, <r1><m1>, <ext1> <amt5>]"},
+ {0xffe04c00, 0x38204800, "strb <wt>, [<xn|sp>, <r1><m1>, <ext1> <amt5>]"},
+ {0xffe04c00, 0x78604800, "ldrh <wt>, [<xn|sp>, <r1><m1>, <ext1> #<amt6>]"},
+ {0xffe04c00, 0x78204800, "strh <wt>, [<xn|sp>, <r1><m1>, <ext1> #<amt6>]"},
+ {0xffe00c00, 0xb8400400, "ldr <wt>, [<xn|sp>], #<simm1>"},
+ {0xffe00c00, 0xb8000c00, "str <wt>, [<xn|sp>, #<simm1>]!"},
+ {0xffc00000, 0x13000000, "sbfm <wd>, <wn>, #<immr1>, #<imms1>"},
+ {0xffc00000, 0x53000000, "ubfm <wd>, <wn>, #<immr1>, #<imms1>"},
+ {0xffc00000, 0xd3400000, "ubfm <xd>, <xn>, #<immr1>, #<imms1>"},
+ {0xffe00000, 0x13800000, "extr <wd>, <wn>, <wm>, #<lsb1>"},
+ {0xff000000, 0x54000000, "b.<cond2> <label1>"},
+ {0xfffffc1f, 0xd65f0000, "ret <xn>"},
+ {0xffe00000, 0x8b200000, "add <xd|sp>, <xn|sp>, <r2><m1>, <ext2> #<amt4>"},
+ {0xffe00000, 0xcb200000, "sub <xd|sp>, <xn|sp>, <r2><m1>, <ext2> #<amt4>"}
+};
+
+static int32_t bits_signed(uint32_t instr, uint32_t msb, uint32_t lsb)
+{
+ int32_t value;
+ value = ((int32_t)instr) << (31 - msb);
+ value >>= (31 - msb);
+ value >>= lsb;
+ return value;
+}
+static uint32_t bits_unsigned(uint32_t instr, uint32_t msb, uint32_t lsb)
+{
+ uint32_t width = msb - lsb + 1;
+ uint32_t mask = (1 << width) - 1;
+ return ((instr >> lsb) & mask);
+}
+
+static void get_token(const char *instr, uint32_t index, char *token)
+{
+ uint32_t i, j;
+ for(i = index, j = 0; i < strlen(instr); ++i)
+ {
+ if(instr[index] == '<' && instr[i] == '>')
+ {
+ token[j++] = instr[i];
+ break;
+ }
+ else if(instr[index] != '<' && instr[i] == '<')
+ {
+ break;
+ }
+ else
+ {
+ token[j++] = instr[i];
+ }
+ }
+ token[j] = '\0';
+ return;
+}
+
+
+static const char * token_cc_table[] =
+{
+ "eq", "ne", "cs", "cc", "mi",
+ "pl", "vs", "vc", "hi", "ls",
+ "ge", "lt", "gt", "le", "al", "nv"
+};
+
+static void decode_rx_zr_token(uint32_t reg, const char *prefix, char *instr_part)
+{
+ if(reg == 31)
+ sprintf(instr_part, "%s%s", prefix, "zr");
+ else
+ sprintf(instr_part, "%s%d", prefix, reg);
+}
+
+static void decode_token(uint32_t code, char *token, char *instr_part)
+{
+ if(strcmp(token, "<imm1>") == 0)
+ sprintf(instr_part, "0x%x", bits_unsigned(code, 21,10));
+ else if(strcmp(token, "<imm2>") == 0)
+ sprintf(instr_part, "0x%x", bits_unsigned(code, 20,5));
+ else if(strcmp(token, "<shift1>") == 0)
+ sprintf(instr_part, "lsl #%d", bits_unsigned(code, 23,22) * 12);
+ else if(strcmp(token, "<shift2>") == 0)
+ {
+ static const char * shift2_table[] = { "lsl", "lsr", "asr", "ror"};
+ sprintf(instr_part, "%s", shift2_table[bits_unsigned(code, 23,22)]);
+ }
+ else if(strcmp(token, "<shift3>") == 0)
+ sprintf(instr_part, "%d", bits_unsigned(code, 22,21) * 16);
+ else if(strcmp(token, "<amt1>") == 0)
+ sprintf(instr_part, "%d", bits_unsigned(code, 15,10));
+ else if(strcmp(token, "<amt2>") == 0)
+ sprintf(instr_part, "%d", bits_unsigned(code, 12,12) * 2);
+ else if(strcmp(token, "<amt3>") == 0)
+ sprintf(instr_part, "%d", bits_unsigned(code, 12,12) * 3);
+ else if(strcmp(token, "<amt4>") == 0)
+ sprintf(instr_part, "%d", bits_unsigned(code, 12,10));
+ else if(strcmp(token, "<amt5>") == 0)
+ {
+ static const char * amt5_table[] = {"", "#0"};
+ sprintf(instr_part, "%s", amt5_table[bits_unsigned(code, 12,12)]);
+ }
+ else if(strcmp(token, "<amt6>") == 0)
+ sprintf(instr_part, "%d", bits_unsigned(code, 12,12));
+ else if(strcmp(token, "<simm1>") == 0)
+ sprintf(instr_part, "%d", bits_signed(code, 20,12));
+ else if(strcmp(token, "<immr1>") == 0)
+ sprintf(instr_part, "%d", bits_unsigned(code, 21,16));
+ else if(strcmp(token, "<imms1>") == 0)
+ sprintf(instr_part, "%d", bits_unsigned(code, 15,10));
+ else if(strcmp(token, "<lsb1>") == 0)
+ sprintf(instr_part, "%d", bits_unsigned(code, 15,10));
+ else if(strcmp(token, "<cond1>") == 0)
+ sprintf(instr_part, "%s", token_cc_table[bits_unsigned(code, 15,12)]);
+ else if(strcmp(token, "<cond2>") == 0)
+ sprintf(instr_part, "%s", token_cc_table[bits_unsigned(code, 4,0)]);
+ else if(strcmp(token, "<r1>") == 0)
+ {
+ const char * token_r1_table[] =
+ {
+ "reserved", "reserved", "w", "x",
+ "reserved", "reserved", "w", "x"
+ };
+ sprintf(instr_part, "%s", token_r1_table[bits_unsigned(code, 15,13)]);
+ }
+ else if(strcmp(token, "<r2>") == 0)
+ {
+ static const char * token_r2_table[] =
+ {
+ "w","w","w", "x", "w", "w", "w", "x"
+ };
+ sprintf(instr_part, "%s", token_r2_table[bits_unsigned(code, 15,13)]);
+ }
+ else if(strcmp(token, "<m1>") == 0)
+ {
+ uint32_t reg = bits_unsigned(code, 20,16);
+ if(reg == 31)
+ sprintf(instr_part, "%s", "zr");
+ else
+ sprintf(instr_part, "%d", reg);
+ }
+ else if(strcmp(token, "<ext1>") == 0)
+ {
+ static const char * token_ext1_table[] =
+ {
+ "reserved","reserved","uxtw", "lsl",
+ "reserved","reserved", "sxtw", "sxtx"
+ };
+ sprintf(instr_part, "%s", token_ext1_table[bits_unsigned(code, 15,13)]);
+ }
+ else if(strcmp(token, "<ext2>") == 0)
+ {
+ static const char * token_ext2_table[] =
+ {
+ "uxtb","uxth","uxtw","uxtx",
+ "sxtb","sxth","sxtw","sxtx"
+ };
+ sprintf(instr_part, "%s", token_ext2_table[bits_unsigned(code, 15,13)]);
+ }
+ else if (strcmp(token, "<label1>") == 0)
+ {
+ int32_t offset = bits_signed(code, 23,5) * 4;
+ if(offset > 0)
+ sprintf(instr_part, "#.+%d", offset);
+ else
+ sprintf(instr_part, "#.-%d", -offset);
+ }
+ else if (strcmp(token, "<xn|sp>") == 0)
+ {
+ uint32_t reg = bits_unsigned(code, 9, 5);
+ if(reg == 31)
+ sprintf(instr_part, "%s", "sp");
+ else
+ sprintf(instr_part, "x%d", reg);
+ }
+ else if (strcmp(token, "<xd|sp>") == 0)
+ {
+ uint32_t reg = bits_unsigned(code, 4, 0);
+ if(reg == 31)
+ sprintf(instr_part, "%s", "sp");
+ else
+ sprintf(instr_part, "x%d", reg);
+ }
+ else if (strcmp(token, "<xn>") == 0)
+ decode_rx_zr_token(bits_unsigned(code, 9, 5), "x", instr_part);
+ else if (strcmp(token, "<xd>") == 0)
+ decode_rx_zr_token(bits_unsigned(code, 4, 0), "x", instr_part);
+ else if (strcmp(token, "<xm>") == 0)
+ decode_rx_zr_token(bits_unsigned(code, 20, 16), "x", instr_part);
+ else if (strcmp(token, "<xa>") == 0)
+ decode_rx_zr_token(bits_unsigned(code, 14, 10), "x", instr_part);
+ else if (strcmp(token, "<xt>") == 0)
+ decode_rx_zr_token(bits_unsigned(code, 4, 0), "x", instr_part);
+ else if (strcmp(token, "<wn>") == 0)
+ decode_rx_zr_token(bits_unsigned(code, 9, 5), "w", instr_part);
+ else if (strcmp(token, "<wd>") == 0)
+ decode_rx_zr_token(bits_unsigned(code, 4, 0), "w", instr_part);
+ else if (strcmp(token, "<wm>") == 0)
+ decode_rx_zr_token(bits_unsigned(code, 20, 16), "w", instr_part);
+ else if (strcmp(token, "<wa>") == 0)
+ decode_rx_zr_token(bits_unsigned(code, 14, 10), "w", instr_part);
+ else if (strcmp(token, "<wt>") == 0)
+ decode_rx_zr_token(bits_unsigned(code, 4, 0), "w", instr_part);
+ else
+ {
+ sprintf(instr_part, "error");
+ }
+ return;
+}
+
+int arm64_disassemble(uint32_t code, char* instr)
+{
+ uint32_t i;
+ char token[256];
+ char instr_part[256];
+
+ if(instr == NULL)
+ return -1;
+
+ bool matched = false;
+ disasm_table_entry_t *entry = NULL;
+ for(i = 0; i < sizeof(disasm_table)/sizeof(disasm_table_entry_t); ++i)
+ {
+ entry = &disasm_table[i];
+ if((code & entry->mask) == entry->value)
+ {
+ matched = true;
+ break;
+ }
+ }
+ if(matched == false)
+ {
+ strcpy(instr, "Unknown Instruction");
+ return -1;
+ }
+ else
+ {
+ uint32_t index = 0;
+ uint32_t length = strlen(entry->instr_template);
+ instr[0] = '\0';
+ do
+ {
+ get_token(entry->instr_template, index, token);
+ if(token[0] == '<')
+ {
+ decode_token(code, token, instr_part);
+ strcat(instr, instr_part);
+ }
+ else
+ {
+ strcat(instr, token);
+ }
+ index += strlen(token);
+ }while(index < length);
+ return 0;
+ }
+}
diff --git a/libpixelflinger/codeflinger/Arm64Disassembler.h b/libpixelflinger/codeflinger/Arm64Disassembler.h
new file mode 100644
index 0000000..86f3aba
--- /dev/null
+++ b/libpixelflinger/codeflinger/Arm64Disassembler.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef ANDROID_ARM64DISASSEMBLER_H
+#define ANDROID_ARM64DISASSEMBLER_H
+
+#include <inttypes.h>
+int arm64_disassemble(uint32_t code, char* instr);
+
+#endif //ANDROID_ARM64ASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
new file mode 100644
index 0000000..32691a3
--- /dev/null
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -0,0 +1,217 @@
+/* libs/pixelflinger/codeflinger/CodeCache.cpp
+**
+** Copyright 2006, The Android Open Source 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.
+*/
+
+#define LOG_TAG "CodeCache"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <cutils/ashmem.h>
+#include <log/log.h>
+
+#include "CodeCache.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+#if defined(__arm__) || defined(__aarch64__)
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#if defined(__mips__)
+#include <asm/cachectl.h>
+#include <errno.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+
+// A dlmalloc mspace is used to manage the code cache over a mmaped region.
+#define HAVE_MMAP 0
+#define HAVE_MREMAP 0
+#define HAVE_MORECORE 0
+#define MALLOC_ALIGNMENT 16
+#define MSPACES 1
+#define NO_MALLINFO 1
+#define ONLY_MSPACES 1
+// Custom heap error handling.
+#define PROCEED_ON_ERROR 0
+static void heap_error(const char* msg, const char* function, void* p);
+#define CORRUPTION_ERROR_ACTION(m) \
+ heap_error("HEAP MEMORY CORRUPTION", __FUNCTION__, NULL)
+#define USAGE_ERROR_ACTION(m,p) \
+ heap_error("ARGUMENT IS INVALID HEAP ADDRESS", __FUNCTION__, p)
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wexpansion-to-defined"
+#pragma GCC diagnostic ignored "-Wnull-pointer-arithmetic"
+#include "../../../../external/dlmalloc/malloc.c"
+#pragma GCC diagnostic pop
+
+static void heap_error(const char* msg, const char* function, void* p) {
+ ALOG(LOG_FATAL, LOG_TAG, "@@@ ABORTING: CODE FLINGER: %s IN %s addr=%p",
+ msg, function, p);
+ /* So that we can get a memory dump around p */
+ *((int **) 0xdeadbaad) = (int *) p;
+}
+
+// ----------------------------------------------------------------------------
+
+static void* gExecutableStore = NULL;
+static mspace gMspace = NULL;
+const size_t kMaxCodeCacheCapacity = 1024 * 1024;
+
+static mspace getMspace()
+{
+ if (gExecutableStore == NULL) {
+ int fd = ashmem_create_region("CodeFlinger code cache",
+ kMaxCodeCacheCapacity);
+ LOG_ALWAYS_FATAL_IF(fd < 0,
+ "Creating code cache, ashmem_create_region "
+ "failed with error '%s'", strerror(errno));
+ gExecutableStore = mmap(NULL, kMaxCodeCacheCapacity,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE, fd, 0);
+ LOG_ALWAYS_FATAL_IF(gExecutableStore == MAP_FAILED,
+ "Creating code cache, mmap failed with error "
+ "'%s'", strerror(errno));
+ close(fd);
+ gMspace = create_mspace_with_base(gExecutableStore, kMaxCodeCacheCapacity,
+ /*locked=*/ false);
+ mspace_set_footprint_limit(gMspace, kMaxCodeCacheCapacity);
+ }
+ return gMspace;
+}
+
+Assembly::Assembly(size_t size)
+ : mCount(0), mSize(0)
+{
+ mBase = (uint32_t*)mspace_malloc(getMspace(), size);
+ LOG_ALWAYS_FATAL_IF(mBase == NULL,
+ "Failed to create Assembly of size %zd in executable "
+ "store of size %zd", size, kMaxCodeCacheCapacity);
+ mSize = size;
+}
+
+Assembly::~Assembly()
+{
+ mspace_free(getMspace(), mBase);
+}
+
+void Assembly::incStrong(const void*) const
+{
+ mCount.fetch_add(1, std::memory_order_relaxed);
+}
+
+void Assembly::decStrong(const void*) const
+{
+ if (mCount.fetch_sub(1, std::memory_order_acq_rel) == 1) {
+ delete this;
+ }
+}
+
+ssize_t Assembly::size() const
+{
+ if (!mBase) return NO_MEMORY;
+ return mSize;
+}
+
+uint32_t* Assembly::base() const
+{
+ return mBase;
+}
+
+ssize_t Assembly::resize(size_t newSize)
+{
+ mBase = (uint32_t*)mspace_realloc(getMspace(), mBase, newSize);
+ LOG_ALWAYS_FATAL_IF(mBase == NULL,
+ "Failed to resize Assembly to %zd in code cache "
+ "of size %zd", newSize, kMaxCodeCacheCapacity);
+ mSize = newSize;
+ return size();
+}
+
+// ----------------------------------------------------------------------------
+
+CodeCache::CodeCache(size_t size)
+ : mCacheSize(size), mCacheInUse(0)
+{
+ pthread_mutex_init(&mLock, 0);
+}
+
+CodeCache::~CodeCache()
+{
+ pthread_mutex_destroy(&mLock);
+}
+
+sp<Assembly> CodeCache::lookup(const AssemblyKeyBase& keyBase) const
+{
+ pthread_mutex_lock(&mLock);
+ sp<Assembly> r;
+ ssize_t index = mCacheData.indexOfKey(key_t(keyBase));
+ if (index >= 0) {
+ const cache_entry_t& e = mCacheData.valueAt(index);
+ e.when = mWhen++;
+ r = e.entry;
+ }
+ pthread_mutex_unlock(&mLock);
+ return r;
+}
+
+int CodeCache::cache( const AssemblyKeyBase& keyBase,
+ const sp<Assembly>& assembly)
+{
+ pthread_mutex_lock(&mLock);
+
+ const ssize_t assemblySize = assembly->size();
+ while (mCacheInUse + assemblySize > mCacheSize) {
+ // evict the LRU
+ size_t lru = 0;
+ size_t count = mCacheData.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const cache_entry_t& e = mCacheData.valueAt(i);
+ if (e.when < mCacheData.valueAt(lru).when) {
+ lru = i;
+ }
+ }
+ const cache_entry_t& e = mCacheData.valueAt(lru);
+ mCacheInUse -= e.entry->size();
+ mCacheData.removeItemsAt(lru);
+ }
+
+ ssize_t err = mCacheData.add(key_t(keyBase), cache_entry_t(assembly, mWhen));
+ if (err >= 0) {
+ mCacheInUse += assemblySize;
+ mWhen++;
+ // synchronize caches...
+ char* base = reinterpret_cast<char*>(assembly->base());
+ char* curr = reinterpret_cast<char*>(base + assembly->size());
+ __builtin___clear_cache(base, curr);
+ }
+
+ pthread_mutex_unlock(&mLock);
+ return err;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libpixelflinger/codeflinger/CodeCache.h b/libpixelflinger/codeflinger/CodeCache.h
new file mode 100644
index 0000000..9326453
--- /dev/null
+++ b/libpixelflinger/codeflinger/CodeCache.h
@@ -0,0 +1,136 @@
+/* libs/pixelflinger/codeflinger/CodeCache.h
+**
+** Copyright 2006, The Android Open Source 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.
+*/
+
+
+#ifndef ANDROID_CODECACHE_H
+#define ANDROID_CODECACHE_H
+
+#include <atomic>
+#include <stdint.h>
+#include <pthread.h>
+#include <sys/types.h>
+
+#include "utils/KeyedVector.h"
+#include "tinyutils/smartpointer.h"
+
+namespace android {
+
+using namespace tinyutils;
+
+// ----------------------------------------------------------------------------
+
+class AssemblyKeyBase {
+public:
+ virtual ~AssemblyKeyBase() { }
+ virtual int compare_type(const AssemblyKeyBase& key) const = 0;
+};
+
+template <typename T>
+class AssemblyKey : public AssemblyKeyBase
+{
+public:
+ explicit AssemblyKey(const T& rhs) : mKey(rhs) { }
+ virtual int compare_type(const AssemblyKeyBase& key) const {
+ const T& rhs = static_cast<const AssemblyKey&>(key).mKey;
+ return android::compare_type(mKey, rhs);
+ }
+private:
+ T mKey;
+};
+
+// ----------------------------------------------------------------------------
+
+class Assembly
+{
+public:
+ explicit Assembly(size_t size);
+ virtual ~Assembly();
+
+ ssize_t size() const;
+ uint32_t* base() const;
+ ssize_t resize(size_t size);
+
+ // protocol for sp<>
+ void incStrong(const void* id) const;
+ void decStrong(const void* id) const;
+ typedef void weakref_type;
+
+private:
+ mutable std::atomic<int32_t> mCount;
+ uint32_t* mBase;
+ size_t mSize;
+};
+
+// ----------------------------------------------------------------------------
+
+class CodeCache
+{
+public:
+// pretty simple cache API...
+ explicit CodeCache(size_t size);
+ ~CodeCache();
+
+ sp<Assembly> lookup(const AssemblyKeyBase& key) const;
+
+ int cache(const AssemblyKeyBase& key,
+ const sp<Assembly>& assembly);
+
+private:
+ // nothing to see here...
+ struct cache_entry_t {
+ inline cache_entry_t() { }
+ inline cache_entry_t(const sp<Assembly>& a, int64_t w)
+ : entry(a), when(w) { }
+ sp<Assembly> entry;
+ mutable int64_t when;
+ };
+
+ class key_t {
+ friend int compare_type(
+ const key_value_pair_t<key_t, cache_entry_t>&,
+ const key_value_pair_t<key_t, cache_entry_t>&);
+ const AssemblyKeyBase* mKey;
+ public:
+ key_t() { };
+ explicit key_t(const AssemblyKeyBase& k) : mKey(&k) { }
+ };
+
+ mutable pthread_mutex_t mLock;
+ mutable int64_t mWhen;
+ size_t mCacheSize;
+ size_t mCacheInUse;
+ KeyedVector<key_t, cache_entry_t> mCacheData;
+
+ friend int compare_type(
+ const key_value_pair_t<key_t, cache_entry_t>&,
+ const key_value_pair_t<key_t, cache_entry_t>&);
+};
+
+// KeyedVector uses compare_type(), which is more efficient, than
+// just using operator < ()
+inline int compare_type(
+ const key_value_pair_t<CodeCache::key_t, CodeCache::cache_entry_t>& lhs,
+ const key_value_pair_t<CodeCache::key_t, CodeCache::cache_entry_t>& rhs)
+{
+ return lhs.key.mKey->compare_type(*(rhs.key.mKey));
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif //ANDROID_CODECACHE_H
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
new file mode 100644
index 0000000..04e285d
--- /dev/null
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -0,0 +1,1195 @@
+/* libs/pixelflinger/codeflinger/GGLAssembler.cpp
+**
+** Copyright 2006, The Android Open Source 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.
+*/
+
+#define LOG_TAG "GGLAssembler"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <log/log.h>
+
+#include "GGLAssembler.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+GGLAssembler::GGLAssembler(ARMAssemblerInterface* target)
+ : ARMAssemblerProxy(target),
+ RegisterAllocator(ARMAssemblerProxy::getCodegenArch()), mOptLevel(7)
+{
+}
+
+GGLAssembler::~GGLAssembler()
+{
+}
+
+void GGLAssembler::prolog()
+{
+ ARMAssemblerProxy::prolog();
+}
+
+void GGLAssembler::epilog(uint32_t touched)
+{
+ ARMAssemblerProxy::epilog(touched);
+}
+
+void GGLAssembler::reset(int opt_level)
+{
+ ARMAssemblerProxy::reset();
+ RegisterAllocator::reset();
+ mOptLevel = opt_level;
+}
+
+// ---------------------------------------------------------------------------
+
+int GGLAssembler::scanline(const needs_t& needs, context_t const* c)
+{
+ int err = 0;
+ int opt_level = mOptLevel;
+ while (opt_level >= 0) {
+ reset(opt_level);
+ err = scanline_core(needs, c);
+ if (err == 0)
+ break;
+ opt_level--;
+ }
+
+ // XXX: in theory, pcForLabel is not valid before generate()
+ uint32_t* fragment_start_pc = pcForLabel("fragment_loop");
+ uint32_t* fragment_end_pc = pcForLabel("epilog");
+ const int per_fragment_ops = int(fragment_end_pc - fragment_start_pc);
+
+ // build a name for our pipeline
+ char name[64];
+ sprintf(name,
+ "scanline__%08X:%08X_%08X_%08X [%3d ipp]",
+ needs.p, needs.n, needs.t[0], needs.t[1], per_fragment_ops);
+
+ if (err) {
+ ALOGE("Error while generating ""%s""\n", name);
+ disassemble(name);
+ return -1;
+ }
+
+ return generate(name);
+}
+
+int GGLAssembler::scanline_core(const needs_t& needs, context_t const* c)
+{
+ mBlendFactorCached = 0;
+ mBlending = 0;
+ mMasking = 0;
+ mAA = GGL_READ_NEEDS(P_AA, needs.p);
+ mDithering = GGL_READ_NEEDS(P_DITHER, needs.p);
+ mAlphaTest = GGL_READ_NEEDS(P_ALPHA_TEST, needs.p) + GGL_NEVER;
+ mDepthTest = GGL_READ_NEEDS(P_DEPTH_TEST, needs.p) + GGL_NEVER;
+ mFog = GGL_READ_NEEDS(P_FOG, needs.p) != 0;
+ mSmooth = GGL_READ_NEEDS(SHADE, needs.n) != 0;
+ mBuilderContext.needs = needs;
+ mBuilderContext.c = c;
+ mBuilderContext.Rctx = reserveReg(R0); // context always in R0
+ mCbFormat = c->formats[ GGL_READ_NEEDS(CB_FORMAT, needs.n) ];
+
+ // ------------------------------------------------------------------------
+
+ decodeLogicOpNeeds(needs);
+
+ decodeTMUNeeds(needs, c);
+
+ mBlendSrc = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_SRC, needs.n));
+ mBlendDst = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_DST, needs.n));
+ mBlendSrcA = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_SRCA, needs.n));
+ mBlendDstA = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_DSTA, needs.n));
+
+ if (!mCbFormat.c[GGLFormat::ALPHA].h) {
+ if ((mBlendSrc == GGL_ONE_MINUS_DST_ALPHA) ||
+ (mBlendSrc == GGL_DST_ALPHA)) {
+ mBlendSrc = GGL_ONE;
+ }
+ if ((mBlendSrcA == GGL_ONE_MINUS_DST_ALPHA) ||
+ (mBlendSrcA == GGL_DST_ALPHA)) {
+ mBlendSrcA = GGL_ONE;
+ }
+ if ((mBlendDst == GGL_ONE_MINUS_DST_ALPHA) ||
+ (mBlendDst == GGL_DST_ALPHA)) {
+ mBlendDst = GGL_ONE;
+ }
+ if ((mBlendDstA == GGL_ONE_MINUS_DST_ALPHA) ||
+ (mBlendDstA == GGL_DST_ALPHA)) {
+ mBlendDstA = GGL_ONE;
+ }
+ }
+
+ // if we need the framebuffer, read it now
+ const int blending = blending_codes(mBlendSrc, mBlendDst) |
+ blending_codes(mBlendSrcA, mBlendDstA);
+
+ // XXX: handle special cases, destination not modified...
+ if ((mBlendSrc==GGL_ZERO) && (mBlendSrcA==GGL_ZERO) &&
+ (mBlendDst==GGL_ONE) && (mBlendDstA==GGL_ONE)) {
+ // Destination unmodified (beware of logic ops)
+ } else if ((mBlendSrc==GGL_ZERO) && (mBlendSrcA==GGL_ZERO) &&
+ (mBlendDst==GGL_ZERO) && (mBlendDstA==GGL_ZERO)) {
+ // Destination is zero (beware of logic ops)
+ }
+
+ int fbComponents = 0;
+ const int masking = GGL_READ_NEEDS(MASK_ARGB, needs.n);
+ for (int i=0 ; i<4 ; i++) {
+ const int mask = 1<<i;
+ component_info_t& info = mInfo[i];
+ int fs = i==GGLFormat::ALPHA ? mBlendSrcA : mBlendSrc;
+ int fd = i==GGLFormat::ALPHA ? mBlendDstA : mBlendDst;
+ if (fs==GGL_SRC_ALPHA_SATURATE && i==GGLFormat::ALPHA)
+ fs = GGL_ONE;
+ info.masked = !!(masking & mask);
+ info.inDest = !info.masked && mCbFormat.c[i].h &&
+ ((mLogicOp & LOGIC_OP_SRC) || (!mLogicOp));
+ if (mCbFormat.components >= GGL_LUMINANCE &&
+ (i==GGLFormat::GREEN || i==GGLFormat::BLUE)) {
+ info.inDest = false;
+ }
+ info.needed = (i==GGLFormat::ALPHA) &&
+ (isAlphaSourceNeeded() || mAlphaTest != GGL_ALWAYS);
+ info.replaced = !!(mTextureMachine.replaced & mask);
+ info.iterated = (!info.replaced && (info.inDest || info.needed));
+ info.smooth = mSmooth && info.iterated;
+ info.fog = mFog && info.inDest && (i != GGLFormat::ALPHA);
+ info.blend = (fs != int(GGL_ONE)) || (fd > int(GGL_ZERO));
+
+ mBlending |= (info.blend ? mask : 0);
+ mMasking |= (mCbFormat.c[i].h && info.masked) ? mask : 0;
+ fbComponents |= mCbFormat.c[i].h ? mask : 0;
+ }
+
+ mAllMasked = (mMasking == fbComponents);
+ if (mAllMasked) {
+ mDithering = 0;
+ }
+
+ fragment_parts_t parts;
+
+ // ------------------------------------------------------------------------
+ prolog();
+ // ------------------------------------------------------------------------
+
+ build_scanline_prolog(parts, needs);
+
+ if (registerFile().status())
+ return registerFile().status();
+
+ // ------------------------------------------------------------------------
+ label("fragment_loop");
+ // ------------------------------------------------------------------------
+ {
+ Scratch regs(registerFile());
+
+ if (mDithering) {
+ // update the dither index.
+ MOV(AL, 0, parts.count.reg,
+ reg_imm(parts.count.reg, ROR, GGL_DITHER_ORDER_SHIFT));
+ ADD(AL, 0, parts.count.reg, parts.count.reg,
+ imm( 1 << (32 - GGL_DITHER_ORDER_SHIFT)));
+ MOV(AL, 0, parts.count.reg,
+ reg_imm(parts.count.reg, ROR, 32 - GGL_DITHER_ORDER_SHIFT));
+ }
+
+ // XXX: could we do an early alpha-test here in some cases?
+ // It would probaly be used only with smooth-alpha and no texture
+ // (or no alpha component in the texture).
+
+ // Early z-test
+ if (mAlphaTest==GGL_ALWAYS) {
+ build_depth_test(parts, Z_TEST|Z_WRITE);
+ } else {
+ // we cannot do the z-write here, because
+ // it might be killed by the alpha-test later
+ build_depth_test(parts, Z_TEST);
+ }
+
+ { // texture coordinates
+ Scratch scratches(registerFile());
+
+ // texel generation
+ build_textures(parts, regs);
+ if (registerFile().status())
+ return registerFile().status();
+ }
+
+ if ((blending & (FACTOR_DST|BLEND_DST)) ||
+ (mMasking && !mAllMasked) ||
+ (mLogicOp & LOGIC_OP_DST))
+ {
+ // blending / logic_op / masking need the framebuffer
+ mDstPixel.setTo(regs.obtain(), &mCbFormat);
+
+ // load the framebuffer pixel
+ comment("fetch color-buffer");
+ load(parts.cbPtr, mDstPixel);
+ }
+
+ if (registerFile().status())
+ return registerFile().status();
+
+ pixel_t pixel;
+ int directTex = mTextureMachine.directTexture;
+ if (directTex | parts.packed) {
+ // note: we can't have both here
+ // iterated color or direct texture
+ pixel = directTex ? parts.texel[directTex-1] : parts.iterated;
+ pixel.flags &= ~CORRUPTIBLE;
+ } else {
+ if (mDithering) {
+ const int ctxtReg = mBuilderContext.Rctx;
+ const int mask = GGL_DITHER_SIZE-1;
+ parts.dither = reg_t(regs.obtain());
+ AND(AL, 0, parts.dither.reg, parts.count.reg, imm(mask));
+ ADDR_ADD(AL, 0, parts.dither.reg, ctxtReg, parts.dither.reg);
+ LDRB(AL, parts.dither.reg, parts.dither.reg,
+ immed12_pre(GGL_OFFSETOF(ditherMatrix)));
+ }
+
+ // allocate a register for the resulting pixel
+ pixel.setTo(regs.obtain(), &mCbFormat, FIRST);
+
+ build_component(pixel, parts, GGLFormat::ALPHA, regs);
+
+ if (mAlphaTest!=GGL_ALWAYS) {
+ // only handle the z-write part here. We know z-test
+ // was successful, as well as alpha-test.
+ build_depth_test(parts, Z_WRITE);
+ }
+
+ build_component(pixel, parts, GGLFormat::RED, regs);
+ build_component(pixel, parts, GGLFormat::GREEN, regs);
+ build_component(pixel, parts, GGLFormat::BLUE, regs);
+
+ pixel.flags |= CORRUPTIBLE;
+ }
+
+ if (registerFile().status())
+ return registerFile().status();
+
+ if (pixel.reg == -1) {
+ // be defensive here. if we're here it's probably
+ // that this whole fragment is a no-op.
+ pixel = mDstPixel;
+ }
+
+ if (!mAllMasked) {
+ // logic operation
+ build_logic_op(pixel, regs);
+
+ // masking
+ build_masking(pixel, regs);
+
+ comment("store");
+ store(parts.cbPtr, pixel, WRITE_BACK);
+ }
+ }
+
+ if (registerFile().status())
+ return registerFile().status();
+
+ // update the iterated color...
+ if (parts.reload != 3) {
+ build_smooth_shade(parts);
+ }
+
+ // update iterated z
+ build_iterate_z(parts);
+
+ // update iterated fog
+ build_iterate_f(parts);
+
+ SUB(AL, S, parts.count.reg, parts.count.reg, imm(1<<16));
+ B(PL, "fragment_loop");
+ label("epilog");
+ epilog(registerFile().touched());
+
+ if ((mAlphaTest!=GGL_ALWAYS) || (mDepthTest!=GGL_ALWAYS)) {
+ if (mDepthTest!=GGL_ALWAYS) {
+ label("discard_before_textures");
+ build_iterate_texture_coordinates(parts);
+ }
+ label("discard_after_textures");
+ build_smooth_shade(parts);
+ build_iterate_z(parts);
+ build_iterate_f(parts);
+ if (!mAllMasked) {
+ ADDR_ADD(AL, 0, parts.cbPtr.reg, parts.cbPtr.reg, imm(parts.cbPtr.size>>3));
+ }
+ SUB(AL, S, parts.count.reg, parts.count.reg, imm(1<<16));
+ B(PL, "fragment_loop");
+ epilog(registerFile().touched());
+ }
+
+ return registerFile().status();
+}
+
+// ---------------------------------------------------------------------------
+
+void GGLAssembler::build_scanline_prolog(
+ fragment_parts_t& parts, const needs_t& needs)
+{
+ Scratch scratches(registerFile());
+
+ // compute count
+ comment("compute ct (# of pixels to process)");
+ parts.count.setTo(obtainReg());
+ int Rx = scratches.obtain();
+ int Ry = scratches.obtain();
+ CONTEXT_LOAD(Rx, iterators.xl);
+ CONTEXT_LOAD(parts.count.reg, iterators.xr);
+ CONTEXT_LOAD(Ry, iterators.y);
+
+ // parts.count = iterators.xr - Rx
+ SUB(AL, 0, parts.count.reg, parts.count.reg, Rx);
+ SUB(AL, 0, parts.count.reg, parts.count.reg, imm(1));
+
+ if (mDithering) {
+ // parts.count.reg = 0xNNNNXXDD
+ // NNNN = count-1
+ // DD = dither offset
+ // XX = 0xxxxxxx (x = garbage)
+ Scratch scratches(registerFile());
+ int tx = scratches.obtain();
+ int ty = scratches.obtain();
+ AND(AL, 0, tx, Rx, imm(GGL_DITHER_MASK));
+ AND(AL, 0, ty, Ry, imm(GGL_DITHER_MASK));
+ ADD(AL, 0, tx, tx, reg_imm(ty, LSL, GGL_DITHER_ORDER_SHIFT));
+ ORR(AL, 0, parts.count.reg, tx, reg_imm(parts.count.reg, LSL, 16));
+ } else {
+ // parts.count.reg = 0xNNNN0000
+ // NNNN = count-1
+ MOV(AL, 0, parts.count.reg, reg_imm(parts.count.reg, LSL, 16));
+ }
+
+ if (!mAllMasked) {
+ // compute dst ptr
+ comment("compute color-buffer pointer");
+ const int cb_bits = mCbFormat.size*8;
+ int Rs = scratches.obtain();
+ parts.cbPtr.setTo(obtainReg(), cb_bits);
+ CONTEXT_LOAD(Rs, state.buffers.color.stride);
+ CONTEXT_ADDR_LOAD(parts.cbPtr.reg, state.buffers.color.data);
+ SMLABB(AL, Rs, Ry, Rs, Rx); // Rs = Rx + Ry*Rs
+ base_offset(parts.cbPtr, parts.cbPtr, Rs);
+ scratches.recycle(Rs);
+ }
+
+ // init fog
+ const int need_fog = GGL_READ_NEEDS(P_FOG, needs.p);
+ if (need_fog) {
+ comment("compute initial fog coordinate");
+ Scratch scratches(registerFile());
+ int dfdx = scratches.obtain();
+ int ydfdy = scratches.obtain();
+ int f = ydfdy;
+ CONTEXT_LOAD(dfdx, generated_vars.dfdx);
+ CONTEXT_LOAD(ydfdy, iterators.ydfdy);
+ MLA(AL, 0, f, Rx, dfdx, ydfdy);
+ CONTEXT_STORE(f, generated_vars.f);
+ }
+
+ // init Z coordinate
+ if ((mDepthTest != GGL_ALWAYS) || GGL_READ_NEEDS(P_MASK_Z, needs.p)) {
+ parts.z = reg_t(obtainReg());
+ comment("compute initial Z coordinate");
+ Scratch scratches(registerFile());
+ int dzdx = scratches.obtain();
+ int ydzdy = parts.z.reg;
+ CONTEXT_LOAD(dzdx, generated_vars.dzdx); // 1.31 fixed-point
+ CONTEXT_LOAD(ydzdy, iterators.ydzdy); // 1.31 fixed-point
+ MLA(AL, 0, parts.z.reg, Rx, dzdx, ydzdy);
+
+ // we're going to index zbase of parts.count
+ // zbase = base + (xl-count + stride*y)*2
+ int Rs = dzdx;
+ int zbase = scratches.obtain();
+ CONTEXT_LOAD(Rs, state.buffers.depth.stride);
+ CONTEXT_ADDR_LOAD(zbase, state.buffers.depth.data);
+ SMLABB(AL, Rs, Ry, Rs, Rx);
+ ADD(AL, 0, Rs, Rs, reg_imm(parts.count.reg, LSR, 16));
+ ADDR_ADD(AL, 0, zbase, zbase, reg_imm(Rs, LSL, 1));
+ CONTEXT_ADDR_STORE(zbase, generated_vars.zbase);
+ }
+
+ // init texture coordinates
+ init_textures(parts.coords, reg_t(Rx), reg_t(Ry));
+ scratches.recycle(Ry);
+
+ // iterated color
+ init_iterated_color(parts, reg_t(Rx));
+
+ // init coverage factor application (anti-aliasing)
+ if (mAA) {
+ parts.covPtr.setTo(obtainReg(), 16);
+ CONTEXT_ADDR_LOAD(parts.covPtr.reg, state.buffers.coverage);
+ ADDR_ADD(AL, 0, parts.covPtr.reg, parts.covPtr.reg, reg_imm(Rx, LSL, 1));
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void GGLAssembler::build_component( pixel_t& pixel,
+ const fragment_parts_t& parts,
+ int component,
+ Scratch& regs)
+{
+ static char const * comments[] = {"alpha", "red", "green", "blue"};
+ comment(comments[component]);
+
+ // local register file
+ Scratch scratches(registerFile());
+ const int dst_component_size = pixel.component_size(component);
+
+ component_t temp(-1);
+ build_incoming_component( temp, dst_component_size,
+ parts, component, scratches, regs);
+
+ if (mInfo[component].inDest) {
+
+ // blending...
+ build_blending( temp, mDstPixel, component, scratches );
+
+ // downshift component and rebuild pixel...
+ downshift(pixel, component, temp, parts.dither);
+ }
+}
+
+void GGLAssembler::build_incoming_component(
+ component_t& temp,
+ int dst_size,
+ const fragment_parts_t& parts,
+ int component,
+ Scratch& scratches,
+ Scratch& global_regs)
+{
+ const uint32_t component_mask = 1<<component;
+
+ // Figure out what we need for the blending stage...
+ int fs = component==GGLFormat::ALPHA ? mBlendSrcA : mBlendSrc;
+ int fd = component==GGLFormat::ALPHA ? mBlendDstA : mBlendDst;
+ if (fs==GGL_SRC_ALPHA_SATURATE && component==GGLFormat::ALPHA) {
+ fs = GGL_ONE;
+ }
+
+ // Figure out what we need to extract and for what reason
+ const int blending = blending_codes(fs, fd);
+
+ // Are we actually going to blend?
+ const int need_blending = (fs != int(GGL_ONE)) || (fd > int(GGL_ZERO));
+
+ // expand the source if the destination has more bits
+ int need_expander = false;
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT-1 ; i++) {
+ texture_unit_t& tmu = mTextureMachine.tmu[i];
+ if ((tmu.format_idx) &&
+ (parts.texel[i].component_size(component) < dst_size)) {
+ need_expander = true;
+ }
+ }
+
+ // do we need to extract this component?
+ const bool multiTexture = mTextureMachine.activeUnits > 1;
+ const int blend_needs_alpha_source = (component==GGLFormat::ALPHA) &&
+ (isAlphaSourceNeeded());
+ int need_extract = mInfo[component].needed;
+ if (mInfo[component].inDest)
+ {
+ need_extract |= ((need_blending ?
+ (blending & (BLEND_SRC|FACTOR_SRC)) : need_expander));
+ need_extract |= (mTextureMachine.mask != mTextureMachine.replaced);
+ need_extract |= mInfo[component].smooth;
+ need_extract |= mInfo[component].fog;
+ need_extract |= mDithering;
+ need_extract |= multiTexture;
+ }
+
+ if (need_extract) {
+ Scratch& regs = blend_needs_alpha_source ? global_regs : scratches;
+ component_t fragment;
+
+ // iterated color
+ build_iterated_color(fragment, parts, component, regs);
+
+ // texture environement (decal, modulate, replace)
+ build_texture_environment(fragment, parts, component, regs);
+
+ // expand the source if the destination has more bits
+ if (need_expander && (fragment.size() < dst_size)) {
+ // we're here only if we fetched a texel
+ // (so we know for sure fragment is CORRUPTIBLE)
+ expand(fragment, fragment, dst_size);
+ }
+
+ // We have a few specific things to do for the alpha-channel
+ if ((component==GGLFormat::ALPHA) &&
+ (mInfo[component].needed || fragment.size()<dst_size))
+ {
+ // convert to integer_t first and make sure
+ // we don't corrupt a needed register
+ if (fragment.l) {
+ component_t incoming(fragment);
+ modify(fragment, regs);
+ MOV(AL, 0, fragment.reg, reg_imm(incoming.reg, LSR, incoming.l));
+ fragment.h -= fragment.l;
+ fragment.l = 0;
+ }
+
+ // coverage factor application
+ build_coverage_application(fragment, parts, regs);
+
+ // alpha-test
+ build_alpha_test(fragment, parts);
+
+ if (blend_needs_alpha_source) {
+ // We keep only 8 bits for the blending stage
+ const int shift = fragment.h <= 8 ? 0 : fragment.h-8;
+ if (fragment.flags & CORRUPTIBLE) {
+ fragment.flags &= ~CORRUPTIBLE;
+ mAlphaSource.setTo(fragment.reg,
+ fragment.size(), fragment.flags);
+ if (shift) {
+ MOV(AL, 0, mAlphaSource.reg,
+ reg_imm(mAlphaSource.reg, LSR, shift));
+ }
+ } else {
+ // XXX: it would better to do this in build_blend_factor()
+ // so we can avoid the extra MOV below.
+ mAlphaSource.setTo(regs.obtain(),
+ fragment.size(), CORRUPTIBLE);
+ if (shift) {
+ MOV(AL, 0, mAlphaSource.reg,
+ reg_imm(fragment.reg, LSR, shift));
+ } else {
+ MOV(AL, 0, mAlphaSource.reg, fragment.reg);
+ }
+ }
+ mAlphaSource.s -= shift;
+ }
+ }
+
+ // fog...
+ build_fog( fragment, component, regs );
+
+ temp = fragment;
+ } else {
+ if (mInfo[component].inDest) {
+ // extraction not needed and replace
+ // we just select the right component
+ if ((mTextureMachine.replaced & component_mask) == 0) {
+ // component wasn't replaced, so use it!
+ temp = component_t(parts.iterated, component);
+ }
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ const texture_unit_t& tmu = mTextureMachine.tmu[i];
+ if ((tmu.mask & component_mask) &&
+ ((tmu.replaced & component_mask) == 0)) {
+ temp = component_t(parts.texel[i], component);
+ }
+ }
+ }
+ }
+}
+
+bool GGLAssembler::isAlphaSourceNeeded() const
+{
+ // XXX: also needed for alpha-test
+ const int bs = mBlendSrc;
+ const int bd = mBlendDst;
+ return bs==GGL_SRC_ALPHA_SATURATE ||
+ bs==GGL_SRC_ALPHA || bs==GGL_ONE_MINUS_SRC_ALPHA ||
+ bd==GGL_SRC_ALPHA || bd==GGL_ONE_MINUS_SRC_ALPHA ;
+}
+
+// ---------------------------------------------------------------------------
+
+void GGLAssembler::build_smooth_shade(const fragment_parts_t& parts)
+{
+ if (mSmooth && !parts.iterated_packed) {
+ // update the iterated color in a pipelined way...
+ comment("update iterated color");
+ Scratch scratches(registerFile());
+
+ const int reload = parts.reload;
+ for (int i=0 ; i<4 ; i++) {
+ if (!mInfo[i].iterated)
+ continue;
+
+ int c = parts.argb[i].reg;
+ int dx = parts.argb_dx[i].reg;
+
+ if (reload & 1) {
+ c = scratches.obtain();
+ CONTEXT_LOAD(c, generated_vars.argb[i].c);
+ }
+ if (reload & 2) {
+ dx = scratches.obtain();
+ CONTEXT_LOAD(dx, generated_vars.argb[i].dx);
+ }
+
+ if (mSmooth) {
+ ADD(AL, 0, c, c, dx);
+ }
+
+ if (reload & 1) {
+ CONTEXT_STORE(c, generated_vars.argb[i].c);
+ scratches.recycle(c);
+ }
+ if (reload & 2) {
+ scratches.recycle(dx);
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void GGLAssembler::build_coverage_application(component_t& fragment,
+ const fragment_parts_t& parts, Scratch& regs)
+{
+ // here fragment.l is guarenteed to be 0
+ if (mAA) {
+ // coverages are 1.15 fixed-point numbers
+ comment("coverage application");
+
+ component_t incoming(fragment);
+ modify(fragment, regs);
+
+ Scratch scratches(registerFile());
+ int cf = scratches.obtain();
+ LDRH(AL, cf, parts.covPtr.reg, immed8_post(2));
+ if (fragment.h > 31) {
+ fragment.h--;
+ SMULWB(AL, fragment.reg, incoming.reg, cf);
+ } else {
+ MOV(AL, 0, fragment.reg, reg_imm(incoming.reg, LSL, 1));
+ SMULWB(AL, fragment.reg, fragment.reg, cf);
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void GGLAssembler::build_alpha_test(component_t& fragment,
+ const fragment_parts_t& /*parts*/)
+{
+ if (mAlphaTest != GGL_ALWAYS) {
+ comment("Alpha Test");
+ Scratch scratches(registerFile());
+ int ref = scratches.obtain();
+ const int shift = GGL_COLOR_BITS-fragment.size();
+ CONTEXT_LOAD(ref, state.alpha_test.ref);
+ if (shift) CMP(AL, fragment.reg, reg_imm(ref, LSR, shift));
+ else CMP(AL, fragment.reg, ref);
+ int cc = NV;
+ switch (mAlphaTest) {
+ case GGL_NEVER: cc = NV; break;
+ case GGL_LESS: cc = LT; break;
+ case GGL_EQUAL: cc = EQ; break;
+ case GGL_LEQUAL: cc = LS; break;
+ case GGL_GREATER: cc = HI; break;
+ case GGL_NOTEQUAL: cc = NE; break;
+ case GGL_GEQUAL: cc = HS; break;
+ }
+ B(cc^1, "discard_after_textures");
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void GGLAssembler::build_depth_test(
+ const fragment_parts_t& parts, uint32_t mask)
+{
+ mask &= Z_TEST|Z_WRITE;
+ const needs_t& needs = mBuilderContext.needs;
+ const int zmask = GGL_READ_NEEDS(P_MASK_Z, needs.p);
+ Scratch scratches(registerFile());
+
+ if (mDepthTest != GGL_ALWAYS || zmask) {
+ int cc=AL, ic=AL;
+ switch (mDepthTest) {
+ case GGL_LESS: ic = HI; break;
+ case GGL_EQUAL: ic = EQ; break;
+ case GGL_LEQUAL: ic = HS; break;
+ case GGL_GREATER: ic = LT; break;
+ case GGL_NOTEQUAL: ic = NE; break;
+ case GGL_GEQUAL: ic = LS; break;
+ case GGL_NEVER:
+ // this never happens, because it's taken care of when
+ // computing the needs. but we keep it for completness.
+ comment("Depth Test (NEVER)");
+ B(AL, "discard_before_textures");
+ return;
+ case GGL_ALWAYS:
+ // we're here because zmask is enabled
+ mask &= ~Z_TEST; // test always passes.
+ break;
+ }
+
+ // inverse the condition
+ cc = ic^1;
+
+ if ((mask & Z_WRITE) && !zmask) {
+ mask &= ~Z_WRITE;
+ }
+
+ if (!mask)
+ return;
+
+ comment("Depth Test");
+
+ int zbase = scratches.obtain();
+ int depth = scratches.obtain();
+ int z = parts.z.reg;
+
+ CONTEXT_ADDR_LOAD(zbase, generated_vars.zbase); // stall
+ ADDR_SUB(AL, 0, zbase, zbase, reg_imm(parts.count.reg, LSR, 15));
+ // above does zbase = zbase + ((count >> 16) << 1)
+
+ if (mask & Z_TEST) {
+ LDRH(AL, depth, zbase); // stall
+ CMP(AL, depth, reg_imm(z, LSR, 16));
+ B(cc, "discard_before_textures");
+ }
+ if (mask & Z_WRITE) {
+ if (mask == Z_WRITE) {
+ // only z-write asked, cc is meaningless
+ ic = AL;
+ }
+ MOV(AL, 0, depth, reg_imm(z, LSR, 16));
+ STRH(ic, depth, zbase);
+ }
+ }
+}
+
+void GGLAssembler::build_iterate_z(const fragment_parts_t& parts)
+{
+ const needs_t& needs = mBuilderContext.needs;
+ if ((mDepthTest != GGL_ALWAYS) || GGL_READ_NEEDS(P_MASK_Z, needs.p)) {
+ Scratch scratches(registerFile());
+ int dzdx = scratches.obtain();
+ CONTEXT_LOAD(dzdx, generated_vars.dzdx); // stall
+ ADD(AL, 0, parts.z.reg, parts.z.reg, dzdx);
+ }
+}
+
+void GGLAssembler::build_iterate_f(const fragment_parts_t& /*parts*/)
+{
+ const needs_t& needs = mBuilderContext.needs;
+ if (GGL_READ_NEEDS(P_FOG, needs.p)) {
+ Scratch scratches(registerFile());
+ int dfdx = scratches.obtain();
+ int f = scratches.obtain();
+ CONTEXT_LOAD(f, generated_vars.f);
+ CONTEXT_LOAD(dfdx, generated_vars.dfdx); // stall
+ ADD(AL, 0, f, f, dfdx);
+ CONTEXT_STORE(f, generated_vars.f);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void GGLAssembler::build_logic_op(pixel_t& pixel, Scratch& regs)
+{
+ const needs_t& needs = mBuilderContext.needs;
+ const int opcode = GGL_READ_NEEDS(LOGIC_OP, needs.n) | GGL_CLEAR;
+ if (opcode == GGL_COPY)
+ return;
+
+ comment("logic operation");
+
+ pixel_t s(pixel);
+ if (!(pixel.flags & CORRUPTIBLE)) {
+ pixel.reg = regs.obtain();
+ pixel.flags |= CORRUPTIBLE;
+ }
+
+ pixel_t d(mDstPixel);
+ switch(opcode) {
+ case GGL_CLEAR: MOV(AL, 0, pixel.reg, imm(0)); break;
+ case GGL_AND: AND(AL, 0, pixel.reg, s.reg, d.reg); break;
+ case GGL_AND_REVERSE: BIC(AL, 0, pixel.reg, s.reg, d.reg); break;
+ case GGL_COPY: break;
+ case GGL_AND_INVERTED: BIC(AL, 0, pixel.reg, d.reg, s.reg); break;
+ case GGL_NOOP: MOV(AL, 0, pixel.reg, d.reg); break;
+ case GGL_XOR: EOR(AL, 0, pixel.reg, s.reg, d.reg); break;
+ case GGL_OR: ORR(AL, 0, pixel.reg, s.reg, d.reg); break;
+ case GGL_NOR: ORR(AL, 0, pixel.reg, s.reg, d.reg);
+ MVN(AL, 0, pixel.reg, pixel.reg); break;
+ case GGL_EQUIV: EOR(AL, 0, pixel.reg, s.reg, d.reg);
+ MVN(AL, 0, pixel.reg, pixel.reg); break;
+ case GGL_INVERT: MVN(AL, 0, pixel.reg, d.reg); break;
+ case GGL_OR_REVERSE: // s | ~d == ~(~s & d)
+ BIC(AL, 0, pixel.reg, d.reg, s.reg);
+ MVN(AL, 0, pixel.reg, pixel.reg); break;
+ case GGL_COPY_INVERTED: MVN(AL, 0, pixel.reg, s.reg); break;
+ case GGL_OR_INVERTED: // ~s | d == ~(s & ~d)
+ BIC(AL, 0, pixel.reg, s.reg, d.reg);
+ MVN(AL, 0, pixel.reg, pixel.reg); break;
+ case GGL_NAND: AND(AL, 0, pixel.reg, s.reg, d.reg);
+ MVN(AL, 0, pixel.reg, pixel.reg); break;
+ case GGL_SET: MVN(AL, 0, pixel.reg, imm(0)); break;
+ };
+}
+
+// ---------------------------------------------------------------------------
+
+static uint32_t find_bottom(uint32_t val)
+{
+ uint32_t i = 0;
+ while (!(val & (3<<i)))
+ i+= 2;
+ return i;
+}
+
+static void normalize(uint32_t& val, uint32_t& rot)
+{
+ rot = 0;
+ while (!(val&3) || (val & 0xFC000000)) {
+ uint32_t newval;
+ newval = val >> 2;
+ newval |= (val&3) << 30;
+ val = newval;
+ rot += 2;
+ if (rot == 32) {
+ rot = 0;
+ break;
+ }
+ }
+}
+
+void GGLAssembler::build_and_immediate(int d, int s, uint32_t mask, int bits)
+{
+ uint32_t rot;
+ uint32_t size = ((bits>=32) ? 0 : (1LU << bits)) - 1;
+ mask &= size;
+
+ if (mask == size) {
+ if (d != s)
+ MOV( AL, 0, d, s);
+ return;
+ }
+
+ if ((getCodegenArch() == CODEGEN_ARCH_MIPS) ||
+ (getCodegenArch() == CODEGEN_ARCH_MIPS64)) {
+ // MIPS can do 16-bit imm in 1 instr, 32-bit in 3 instr
+ // the below ' while (mask)' code is buggy on mips
+ // since mips returns true on isValidImmediate()
+ // then we get multiple AND instr (positive logic)
+ AND( AL, 0, d, s, imm(mask) );
+ return;
+ }
+ else if (getCodegenArch() == CODEGEN_ARCH_ARM64) {
+ AND( AL, 0, d, s, imm(mask) );
+ return;
+ }
+
+ int negative_logic = !isValidImmediate(mask);
+ if (negative_logic) {
+ mask = ~mask & size;
+ }
+ normalize(mask, rot);
+
+ if (mask) {
+ while (mask) {
+ uint32_t bitpos = find_bottom(mask);
+ int shift = rot + bitpos;
+ uint32_t m = mask & (0xff << bitpos);
+ mask &= ~m;
+ m >>= bitpos;
+ int32_t newMask = (m<<shift) | (m>>(32-shift));
+ if (!negative_logic) {
+ AND( AL, 0, d, s, imm(newMask) );
+ } else {
+ BIC( AL, 0, d, s, imm(newMask) );
+ }
+ s = d;
+ }
+ } else {
+ MOV( AL, 0, d, imm(0));
+ }
+}
+
+void GGLAssembler::build_masking(pixel_t& pixel, Scratch& regs)
+{
+ if (!mMasking || mAllMasked) {
+ return;
+ }
+
+ comment("color mask");
+
+ pixel_t fb(mDstPixel);
+ pixel_t s(pixel);
+ if (!(pixel.flags & CORRUPTIBLE)) {
+ pixel.reg = regs.obtain();
+ pixel.flags |= CORRUPTIBLE;
+ }
+
+ int mask = 0;
+ for (int i=0 ; i<4 ; i++) {
+ const int component_mask = 1<<i;
+ const int h = fb.format.c[i].h;
+ const int l = fb.format.c[i].l;
+ if (h && (!(mMasking & component_mask))) {
+ mask |= ((1<<(h-l))-1) << l;
+ }
+ }
+
+ // There is no need to clear the masked components of the source
+ // (unless we applied a logic op), because they're already zeroed
+ // by construction (masked components are not computed)
+
+ if (mLogicOp) {
+ const needs_t& needs = mBuilderContext.needs;
+ const int opcode = GGL_READ_NEEDS(LOGIC_OP, needs.n) | GGL_CLEAR;
+ if (opcode != GGL_CLEAR) {
+ // clear masked component of source
+ build_and_immediate(pixel.reg, s.reg, mask, fb.size());
+ s = pixel;
+ }
+ }
+
+ // clear non masked components of destination
+ build_and_immediate(fb.reg, fb.reg, ~mask, fb.size());
+
+ // or back the channels that were masked
+ if (s.reg == fb.reg) {
+ // this is in fact a MOV
+ if (s.reg == pixel.reg) {
+ // ugh. this in in fact a nop
+ } else {
+ MOV(AL, 0, pixel.reg, fb.reg);
+ }
+ } else {
+ ORR(AL, 0, pixel.reg, s.reg, fb.reg);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void GGLAssembler::base_offset(
+ const pointer_t& d, const pointer_t& b, const reg_t& o)
+{
+ switch (b.size) {
+ case 32:
+ ADDR_ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 2));
+ break;
+ case 24:
+ if (d.reg == b.reg) {
+ ADDR_ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 1));
+ ADDR_ADD(AL, 0, d.reg, d.reg, o.reg);
+ } else {
+ ADDR_ADD(AL, 0, d.reg, o.reg, reg_imm(o.reg, LSL, 1));
+ ADDR_ADD(AL, 0, d.reg, d.reg, b.reg);
+ }
+ break;
+ case 16:
+ ADDR_ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 1));
+ break;
+ case 8:
+ ADDR_ADD(AL, 0, d.reg, b.reg, o.reg);
+ break;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// cheezy register allocator...
+// ----------------------------------------------------------------------------
+
+// Modified to support MIPS processors, in a very simple way. We retain the
+// (Arm) limit of 16 total registers, but shift the mapping of those registers
+// from 0-15, to 2-17. Register 0 on Mips cannot be used as GP registers, and
+// register 1 has a traditional use as a temp).
+
+RegisterAllocator::RegisterAllocator(int arch) : mRegs(arch)
+{
+}
+
+void RegisterAllocator::reset()
+{
+ mRegs.reset();
+}
+
+int RegisterAllocator::reserveReg(int reg)
+{
+ return mRegs.reserve(reg);
+}
+
+int RegisterAllocator::obtainReg()
+{
+ return mRegs.obtain();
+}
+
+void RegisterAllocator::recycleReg(int reg)
+{
+ mRegs.recycle(reg);
+}
+
+RegisterAllocator::RegisterFile& RegisterAllocator::registerFile()
+{
+ return mRegs;
+}
+
+// ----------------------------------------------------------------------------
+
+RegisterAllocator::RegisterFile::RegisterFile(int codegen_arch)
+ : mRegs(0), mTouched(0), mStatus(0), mArch(codegen_arch), mRegisterOffset(0)
+{
+ if ((mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) ||
+ (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS64)) {
+ mRegisterOffset = 2; // ARM has regs 0..15, MIPS offset to 2..17
+ }
+ reserve(ARMAssemblerInterface::SP);
+ reserve(ARMAssemblerInterface::PC);
+}
+
+RegisterAllocator::RegisterFile::RegisterFile(const RegisterFile& rhs, int codegen_arch)
+ : mRegs(rhs.mRegs), mTouched(rhs.mTouched), mArch(codegen_arch), mRegisterOffset(0)
+{
+ if ((mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) ||
+ (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS64)) {
+ mRegisterOffset = 2; // ARM has regs 0..15, MIPS offset to 2..17
+ }
+}
+
+RegisterAllocator::RegisterFile::~RegisterFile()
+{
+}
+
+bool RegisterAllocator::RegisterFile::operator == (const RegisterFile& rhs) const
+{
+ return (mRegs == rhs.mRegs);
+}
+
+void RegisterAllocator::RegisterFile::reset()
+{
+ mRegs = mTouched = mStatus = 0;
+ reserve(ARMAssemblerInterface::SP);
+ reserve(ARMAssemblerInterface::PC);
+}
+
+// RegisterFile::reserve() take a register parameter in the
+// range 0-15 (Arm compatible), but on a Mips processor, will
+// return the actual allocated register in the range 2-17.
+int RegisterAllocator::RegisterFile::reserve(int reg)
+{
+ reg += mRegisterOffset;
+ LOG_ALWAYS_FATAL_IF(isUsed(reg),
+ "reserving register %d, but already in use",
+ reg);
+ mRegs |= (1<<reg);
+ mTouched |= mRegs;
+ return reg;
+}
+
+// This interface uses regMask in range 2-17 on MIPS, no translation.
+void RegisterAllocator::RegisterFile::reserveSeveral(uint32_t regMask)
+{
+ mRegs |= regMask;
+ mTouched |= regMask;
+}
+
+int RegisterAllocator::RegisterFile::isUsed(int reg) const
+{
+ LOG_ALWAYS_FATAL_IF(reg>=16+(int)mRegisterOffset, "invalid register %d", reg);
+ return mRegs & (1<<reg);
+}
+
+int RegisterAllocator::RegisterFile::obtain()
+{
+ const char priorityList[14] = { 0, 1, 2, 3,
+ 12, 14, 4, 5,
+ 6, 7, 8, 9,
+ 10, 11 };
+ const int nbreg = sizeof(priorityList);
+ int i, r, reg;
+ for (i=0 ; i<nbreg ; i++) {
+ r = priorityList[i];
+ if (!isUsed(r + mRegisterOffset)) {
+ break;
+ }
+ }
+ // this is not an error anymore because, we'll try again with
+ // a lower optimization level.
+ //ALOGE_IF(i >= nbreg, "pixelflinger ran out of registers\n");
+ if (i >= nbreg) {
+ mStatus |= OUT_OF_REGISTERS;
+ // we return SP so we can more easily debug things
+ // the code will never be run anyway.
+ return ARMAssemblerInterface::SP;
+ }
+ reg = reserve(r); // Param in Arm range 0-15, returns range 2-17 on Mips.
+ return reg;
+}
+
+bool RegisterAllocator::RegisterFile::hasFreeRegs() const
+{
+ uint32_t regs = mRegs >> mRegisterOffset; // MIPS fix.
+ return ((regs & 0xFFFF) == 0xFFFF) ? false : true;
+}
+
+int RegisterAllocator::RegisterFile::countFreeRegs() const
+{
+ uint32_t regs = mRegs >> mRegisterOffset; // MIPS fix.
+ int f = ~regs & 0xFFFF;
+ // now count number of 1
+ f = (f & 0x5555) + ((f>>1) & 0x5555);
+ f = (f & 0x3333) + ((f>>2) & 0x3333);
+ f = (f & 0x0F0F) + ((f>>4) & 0x0F0F);
+ f = (f & 0x00FF) + ((f>>8) & 0x00FF);
+ return f;
+}
+
+void RegisterAllocator::RegisterFile::recycle(int reg)
+{
+ // commented out, since common failure of running out of regs
+ // triggers this assertion. Since the code is not execectued
+ // in that case, it does not matter. No reason to FATAL err.
+ // LOG_FATAL_IF(!isUsed(reg),
+ // "recycling unallocated register %d",
+ // reg);
+ mRegs &= ~(1<<reg);
+}
+
+void RegisterAllocator::RegisterFile::recycleSeveral(uint32_t regMask)
+{
+ // commented out, since common failure of running out of regs
+ // triggers this assertion. Since the code is not execectued
+ // in that case, it does not matter. No reason to FATAL err.
+ // LOG_FATAL_IF((mRegs & regMask)!=regMask,
+ // "recycling unallocated registers "
+ // "(recycle=%08x, allocated=%08x, unallocated=%08x)",
+ // regMask, mRegs, mRegs®Mask);
+ mRegs &= ~regMask;
+}
+
+uint32_t RegisterAllocator::RegisterFile::touched() const
+{
+ return mTouched;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/libpixelflinger/codeflinger/GGLAssembler.h b/libpixelflinger/codeflinger/GGLAssembler.h
new file mode 100644
index 0000000..47dbf3a
--- /dev/null
+++ b/libpixelflinger/codeflinger/GGLAssembler.h
@@ -0,0 +1,572 @@
+/* libs/pixelflinger/codeflinger/GGLAssembler.h
+**
+** Copyright 2006, The Android Open Source 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.
+*/
+
+
+#ifndef ANDROID_GGLASSEMBLER_H
+#define ANDROID_GGLASSEMBLER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include "ARMAssemblerProxy.h"
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+#define CONTEXT_ADDR_LOAD(REG, FIELD) \
+ ADDR_LDR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
+
+#define CONTEXT_ADDR_STORE(REG, FIELD) \
+ ADDR_STR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
+
+#define CONTEXT_LOAD(REG, FIELD) \
+ LDR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
+
+#define CONTEXT_STORE(REG, FIELD) \
+ STR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
+
+
+class RegisterAllocator
+{
+public:
+ class RegisterFile;
+
+ RegisterAllocator(int arch); // NOLINT, implicit
+ RegisterFile& registerFile();
+ int reserveReg(int reg);
+ int obtainReg();
+ void recycleReg(int reg);
+ void reset();
+
+ class RegisterFile
+ {
+ public:
+ RegisterFile(int arch); // NOLINT, implicit
+ RegisterFile(const RegisterFile& rhs, int arch);
+ ~RegisterFile();
+
+ void reset();
+
+ bool operator == (const RegisterFile& rhs) const;
+ bool operator != (const RegisterFile& rhs) const {
+ return !operator == (rhs);
+ }
+
+ int reserve(int reg);
+ void reserveSeveral(uint32_t regMask);
+
+ void recycle(int reg);
+ void recycleSeveral(uint32_t regMask);
+
+ int obtain();
+ inline int isUsed(int reg) const;
+
+ bool hasFreeRegs() const;
+ int countFreeRegs() const;
+
+ uint32_t touched() const;
+ inline uint32_t status() const { return mStatus; }
+
+ enum {
+ OUT_OF_REGISTERS = 0x1
+ };
+
+ private:
+ uint32_t mRegs;
+ uint32_t mTouched;
+ uint32_t mStatus;
+ int mArch;
+ uint32_t mRegisterOffset; // lets reg alloc use 2..17 for mips
+ // while arm uses 0..15
+ };
+
+ class Scratch
+ {
+ public:
+ explicit Scratch(RegisterFile& regFile)
+ : mRegFile(regFile), mScratch(0) {
+ }
+ ~Scratch() {
+ mRegFile.recycleSeveral(mScratch);
+ }
+ int obtain() {
+ int reg = mRegFile.obtain();
+ mScratch |= 1<<reg;
+ return reg;
+ }
+ void recycle(int reg) {
+ mRegFile.recycle(reg);
+ mScratch &= ~(1<<reg);
+ }
+ bool isUsed(int reg) {
+ return (mScratch & (1<<reg));
+ }
+ int countFreeRegs() {
+ return mRegFile.countFreeRegs();
+ }
+ private:
+ RegisterFile& mRegFile;
+ uint32_t mScratch;
+ };
+
+ class Spill
+ {
+ public:
+ Spill(RegisterFile& regFile, ARMAssemblerInterface& gen, uint32_t reglist)
+ : mRegFile(regFile), mGen(gen), mRegList(reglist), mCount(0)
+ {
+ if (reglist) {
+ int count = 0;
+ while (reglist) {
+ count++;
+ reglist &= ~(1 << (31 - __builtin_clz(reglist)));
+ }
+ if (count == 1) {
+ int reg = 31 - __builtin_clz(mRegList);
+ mGen.STR(mGen.AL, reg, mGen.SP, mGen.immed12_pre(-4, 1));
+ } else {
+ mGen.STM(mGen.AL, mGen.DB, mGen.SP, 1, mRegList);
+ }
+ mRegFile.recycleSeveral(mRegList);
+ mCount = count;
+ }
+ }
+ ~Spill() {
+ if (mRegList) {
+ if (mCount == 1) {
+ int reg = 31 - __builtin_clz(mRegList);
+ mGen.LDR(mGen.AL, reg, mGen.SP, mGen.immed12_post(4));
+ } else {
+ mGen.LDM(mGen.AL, mGen.IA, mGen.SP, 1, mRegList);
+ }
+ mRegFile.reserveSeveral(mRegList);
+ }
+ }
+ private:
+ RegisterFile& mRegFile;
+ ARMAssemblerInterface& mGen;
+ uint32_t mRegList;
+ int mCount;
+ };
+
+private:
+ RegisterFile mRegs;
+};
+
+// ----------------------------------------------------------------------------
+
+class GGLAssembler : public ARMAssemblerProxy, public RegisterAllocator
+{
+public:
+
+ explicit GGLAssembler(ARMAssemblerInterface* target);
+ virtual ~GGLAssembler();
+
+ uint32_t* base() const { return 0; } // XXX
+ uint32_t* pc() const { return 0; } // XXX
+
+ void reset(int opt_level);
+
+ virtual void prolog();
+ virtual void epilog(uint32_t touched);
+
+ // generate scanline code for given needs
+ int scanline(const needs_t& needs, context_t const* c);
+ int scanline_core(const needs_t& needs, context_t const* c);
+
+ enum {
+ CLEAR_LO = 0x0001,
+ CLEAR_HI = 0x0002,
+ CORRUPTIBLE = 0x0004,
+ FIRST = 0x0008
+ };
+
+ enum { //load/store flags
+ WRITE_BACK = 0x0001
+ };
+
+ struct reg_t {
+ reg_t() : reg(-1), flags(0) {
+ }
+ reg_t(int r, int f=0) // NOLINT, implicit
+ : reg(r), flags(f) {
+ }
+ void setTo(int r, int f=0) {
+ reg=r; flags=f;
+ }
+ int reg;
+ uint16_t flags;
+ };
+
+ struct integer_t : public reg_t {
+ integer_t() : reg_t(), s(0) {
+ }
+ integer_t(int r, int sz=32, int f=0) // NOLINT, implicit
+ : reg_t(r, f), s(sz) {
+ }
+ void setTo(int r, int sz=32, int f=0) {
+ reg_t::setTo(r, f); s=sz;
+ }
+ int8_t s;
+ inline int size() const { return s; }
+ };
+
+ struct pixel_t : public reg_t {
+ pixel_t() : reg_t() {
+ memset(&format, 0, sizeof(GGLFormat));
+ }
+ pixel_t(int r, const GGLFormat* fmt, int f=0)
+ : reg_t(r, f), format(*fmt) {
+ }
+ void setTo(int r, const GGLFormat* fmt, int f=0) {
+ reg_t::setTo(r, f); format = *fmt;
+ }
+ GGLFormat format;
+ inline int hi(int c) const { return format.c[c].h; }
+ inline int low(int c) const { return format.c[c].l; }
+ inline int mask(int c) const { return ((1<<size(c))-1) << low(c); }
+ inline int size() const { return format.size*8; }
+ inline int size(int c) const { return component_size(c); }
+ inline int component_size(int c) const { return hi(c) - low(c); }
+ };
+
+ struct component_t : public reg_t {
+ component_t() : reg_t(), h(0), l(0) {
+ }
+ component_t(int r, int f=0) // NOLINT, implicit
+ : reg_t(r, f), h(0), l(0) {
+ }
+ component_t(int r, int lo, int hi, int f=0)
+ : reg_t(r, f), h(hi), l(lo) {
+ }
+ explicit component_t(const integer_t& rhs)
+ : reg_t(rhs.reg, rhs.flags), h(rhs.s), l(0) {
+ }
+ explicit component_t(const pixel_t& rhs, int component) {
+ setTo( rhs.reg,
+ rhs.format.c[component].l,
+ rhs.format.c[component].h,
+ rhs.flags|CLEAR_LO|CLEAR_HI);
+ }
+ void setTo(int r, int lo=0, int hi=0, int f=0) {
+ reg_t::setTo(r, f); h=hi; l=lo;
+ }
+ int8_t h;
+ int8_t l;
+ inline int size() const { return h-l; }
+ };
+
+ struct pointer_t : public reg_t {
+ pointer_t() : reg_t(), size(0) {
+ }
+ pointer_t(int r, int s, int f=0)
+ : reg_t(r, f), size(s) {
+ }
+ void setTo(int r, int s, int f=0) {
+ reg_t::setTo(r, f); size=s;
+ }
+ int8_t size;
+ };
+
+
+private:
+ // GGLAssembler hides RegisterAllocator's and ARMAssemblerProxy's reset
+ // methods by providing a reset method with a different parameter set. The
+ // intent of GGLAssembler's reset method is to wrap the inherited reset
+ // methods, so make these methods private in order to prevent direct calls
+ // to these methods from clients.
+ using RegisterAllocator::reset;
+ using ARMAssemblerProxy::reset;
+
+ struct tex_coord_t {
+ reg_t s;
+ reg_t t;
+ pointer_t ptr;
+ };
+
+ struct fragment_parts_t {
+ uint32_t packed : 1;
+ uint32_t reload : 2;
+ uint32_t iterated_packed : 1;
+ pixel_t iterated;
+ pointer_t cbPtr;
+ pointer_t covPtr;
+ reg_t count;
+ reg_t argb[4];
+ reg_t argb_dx[4];
+ reg_t z;
+ reg_t dither;
+ pixel_t texel[GGL_TEXTURE_UNIT_COUNT];
+ tex_coord_t coords[GGL_TEXTURE_UNIT_COUNT];
+ };
+
+ struct texture_unit_t {
+ int format_idx;
+ GGLFormat format;
+ int bits;
+ int swrap;
+ int twrap;
+ int env;
+ int pot;
+ int linear;
+ uint8_t mask;
+ uint8_t replaced;
+ };
+
+ struct texture_machine_t {
+ texture_unit_t tmu[GGL_TEXTURE_UNIT_COUNT];
+ uint8_t mask;
+ uint8_t replaced;
+ uint8_t directTexture;
+ uint8_t activeUnits;
+ };
+
+ struct component_info_t {
+ bool masked : 1;
+ bool inDest : 1;
+ bool needed : 1;
+ bool replaced : 1;
+ bool iterated : 1;
+ bool smooth : 1;
+ bool blend : 1;
+ bool fog : 1;
+ };
+
+ struct builder_context_t {
+ context_t const* c;
+ needs_t needs;
+ int Rctx;
+ };
+
+ template <typename T>
+ void modify(T& r, Scratch& regs)
+ {
+ if (!(r.flags & CORRUPTIBLE)) {
+ r.reg = regs.obtain();
+ r.flags |= CORRUPTIBLE;
+ }
+ }
+
+ // helpers
+ void base_offset(const pointer_t& d, const pointer_t& b, const reg_t& o);
+
+ // texture environement
+ void modulate( component_t& dest,
+ const component_t& incoming,
+ const pixel_t& texel, int component);
+
+ void decal( component_t& dest,
+ const component_t& incoming,
+ const pixel_t& texel, int component);
+
+ void blend( component_t& dest,
+ const component_t& incoming,
+ const pixel_t& texel, int component, int tmu);
+
+ void add( component_t& dest,
+ const component_t& incoming,
+ const pixel_t& texel, int component);
+
+ // load/store stuff
+ void store(const pointer_t& addr, const pixel_t& src, uint32_t flags=0);
+ void load(const pointer_t& addr, const pixel_t& dest, uint32_t flags=0);
+ void extract(integer_t& d, const pixel_t& s, int component);
+ void extract(component_t& d, const pixel_t& s, int component);
+ void extract(integer_t& d, int s, int h, int l, int bits=32);
+ void expand(integer_t& d, const integer_t& s, int dbits);
+ void expand(integer_t& d, const component_t& s, int dbits);
+ void expand(component_t& d, const component_t& s, int dbits);
+ void downshift(pixel_t& d, int component, component_t s, const reg_t& dither);
+
+
+ void mul_factor( component_t& d,
+ const integer_t& v,
+ const integer_t& f);
+
+ void mul_factor_add( component_t& d,
+ const integer_t& v,
+ const integer_t& f,
+ const component_t& a);
+
+ void component_add( component_t& d,
+ const integer_t& dst,
+ const integer_t& src);
+
+ void component_sat( const component_t& v);
+
+
+ void build_scanline_prolog( fragment_parts_t& parts,
+ const needs_t& needs);
+
+ void build_smooth_shade(const fragment_parts_t& parts);
+
+ void build_component( pixel_t& pixel,
+ const fragment_parts_t& parts,
+ int component,
+ Scratch& global_scratches);
+
+ void build_incoming_component(
+ component_t& temp,
+ int dst_size,
+ const fragment_parts_t& parts,
+ int component,
+ Scratch& scratches,
+ Scratch& global_scratches);
+
+ void init_iterated_color(fragment_parts_t& parts, const reg_t& x);
+
+ void build_iterated_color( component_t& fragment,
+ const fragment_parts_t& parts,
+ int component,
+ Scratch& regs);
+
+ void decodeLogicOpNeeds(const needs_t& needs);
+
+ void decodeTMUNeeds(const needs_t& needs, context_t const* c);
+
+ void init_textures( tex_coord_t* coords,
+ const reg_t& x,
+ const reg_t& y);
+
+ void build_textures( fragment_parts_t& parts,
+ Scratch& regs);
+
+ void filter8( const fragment_parts_t& parts,
+ pixel_t& texel, const texture_unit_t& tmu,
+ int U, int V, pointer_t& txPtr,
+ int FRAC_BITS);
+
+ void filter16( const fragment_parts_t& parts,
+ pixel_t& texel, const texture_unit_t& tmu,
+ int U, int V, pointer_t& txPtr,
+ int FRAC_BITS);
+
+ void filter24( const fragment_parts_t& parts,
+ pixel_t& texel, const texture_unit_t& tmu,
+ int U, int V, pointer_t& txPtr,
+ int FRAC_BITS);
+
+ void filter32( const fragment_parts_t& parts,
+ pixel_t& texel, const texture_unit_t& tmu,
+ int U, int V, pointer_t& txPtr,
+ int FRAC_BITS);
+
+ void build_texture_environment( component_t& fragment,
+ const fragment_parts_t& parts,
+ int component,
+ Scratch& regs);
+
+ void wrapping( int d,
+ int coord, int size,
+ int tx_wrap, int tx_linear);
+
+ void build_fog( component_t& temp,
+ int component,
+ Scratch& parent_scratches);
+
+ void build_blending( component_t& in_out,
+ const pixel_t& pixel,
+ int component,
+ Scratch& parent_scratches);
+
+ void build_blend_factor(
+ integer_t& factor, int f, int component,
+ const pixel_t& dst_pixel,
+ integer_t& fragment,
+ integer_t& fb,
+ Scratch& scratches);
+
+ void build_blendFOneMinusF( component_t& temp,
+ const integer_t& factor,
+ const integer_t& fragment,
+ const integer_t& fb);
+
+ void build_blendOneMinusFF( component_t& temp,
+ const integer_t& factor,
+ const integer_t& fragment,
+ const integer_t& fb);
+
+ void build_coverage_application(component_t& fragment,
+ const fragment_parts_t& parts,
+ Scratch& regs);
+
+ void build_alpha_test(component_t& fragment, const fragment_parts_t& parts);
+
+ enum { Z_TEST=1, Z_WRITE=2 };
+ void build_depth_test(const fragment_parts_t& parts, uint32_t mask);
+ void build_iterate_z(const fragment_parts_t& parts);
+ void build_iterate_f(const fragment_parts_t& parts);
+ void build_iterate_texture_coordinates(const fragment_parts_t& parts);
+
+ void build_logic_op(pixel_t& pixel, Scratch& regs);
+
+ void build_masking(pixel_t& pixel, Scratch& regs);
+
+ void build_and_immediate(int d, int s, uint32_t mask, int bits);
+
+ bool isAlphaSourceNeeded() const;
+
+ enum {
+ FACTOR_SRC=1, FACTOR_DST=2, BLEND_SRC=4, BLEND_DST=8
+ };
+
+ enum {
+ LOGIC_OP=1, LOGIC_OP_SRC=2, LOGIC_OP_DST=4
+ };
+
+ static int blending_codes(int fs, int fd);
+
+ builder_context_t mBuilderContext;
+ texture_machine_t mTextureMachine;
+ component_info_t mInfo[4];
+ int mBlending;
+ int mMasking;
+ int mAllMasked;
+ int mLogicOp;
+ int mAlphaTest;
+ int mAA;
+ int mDithering;
+ int mDepthTest;
+
+ int mSmooth;
+ int mFog;
+ pixel_t mDstPixel;
+
+ GGLFormat mCbFormat;
+
+ int mBlendFactorCached;
+ integer_t mAlphaSource;
+
+ int mBaseRegister;
+
+ int mBlendSrc;
+ int mBlendDst;
+ int mBlendSrcA;
+ int mBlendDstA;
+
+ int mOptLevel;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_GGLASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.cpp b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
new file mode 100644
index 0000000..d6d2156
--- /dev/null
+++ b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
@@ -0,0 +1,1447 @@
+/* libs/pixelflinger/codeflinger/MIPS64Assembler.cpp
+**
+** Copyright 2015, The Android Open Source 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.
+*/
+
+
+/* MIPS64 assembler and ARM->MIPS64 assembly translator
+**
+** The approach is utilize MIPSAssembler generator, using inherited MIPS64Assembler
+** that overrides just the specific MIPS64r6 instructions.
+** For now ArmToMips64Assembler is copied over from ArmToMipsAssembler class,
+** changing some MIPS64r6 related stuff.
+**
+*/
+
+#define LOG_TAG "MIPS64Assembler"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cutils/properties.h>
+#include <log/log.h>
+#include <private/pixelflinger/ggl_context.h>
+
+#include "MIPS64Assembler.h"
+#include "CodeCache.h"
+#include "mips64_disassem.h"
+
+#define NOT_IMPLEMENTED() LOG_ALWAYS_FATAL("Arm instruction %s not yet implemented\n", __func__)
+#define __unused __attribute__((__unused__))
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark ArmToMips64Assembler...
+#endif
+
+ArmToMips64Assembler::ArmToMips64Assembler(const sp<Assembly>& assembly,
+ char *abuf, int linesz, int instr_count)
+ : ARMAssemblerInterface(),
+ mArmDisassemblyBuffer(abuf),
+ mArmLineLength(linesz),
+ mArmInstrCount(instr_count),
+ mInum(0),
+ mAssembly(assembly)
+{
+ mMips = new MIPS64Assembler(assembly, this);
+ mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *));
+ init_conditional_labels();
+}
+
+ArmToMips64Assembler::ArmToMips64Assembler(void* assembly)
+ : ARMAssemblerInterface(),
+ mArmDisassemblyBuffer(NULL),
+ mInum(0),
+ mAssembly(NULL)
+{
+ mMips = new MIPS64Assembler(assembly, this);
+ mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *));
+ init_conditional_labels();
+}
+
+ArmToMips64Assembler::~ArmToMips64Assembler()
+{
+ delete mMips;
+ free((void *) mArmPC);
+}
+
+uint32_t* ArmToMips64Assembler::pc() const
+{
+ return mMips->pc();
+}
+
+uint32_t* ArmToMips64Assembler::base() const
+{
+ return mMips->base();
+}
+
+void ArmToMips64Assembler::reset()
+{
+ cond.labelnum = 0;
+ mInum = 0;
+ mMips->reset();
+}
+
+int ArmToMips64Assembler::getCodegenArch()
+{
+ return CODEGEN_ARCH_MIPS64;
+}
+
+void ArmToMips64Assembler::comment(const char* string)
+{
+ mMips->comment(string);
+}
+
+void ArmToMips64Assembler::label(const char* theLabel)
+{
+ mMips->label(theLabel);
+}
+
+void ArmToMips64Assembler::disassemble(const char* name)
+{
+ mMips->disassemble(name);
+}
+
+void ArmToMips64Assembler::init_conditional_labels()
+{
+ int i;
+ for (i=0;i<99; ++i) {
+ sprintf(cond.label[i], "cond_%d", i);
+ }
+}
+
+
+
+#if 0
+#pragma mark -
+#pragma mark Prolog/Epilog & Generate...
+#endif
+
+void ArmToMips64Assembler::prolog()
+{
+ mArmPC[mInum++] = pc(); // save starting PC for this instr
+
+ mMips->DADDIU(R_sp, R_sp, -(5 * 8));
+ mMips->SD(R_s0, R_sp, 0);
+ mMips->SD(R_s1, R_sp, 8);
+ mMips->SD(R_s2, R_sp, 16);
+ mMips->SD(R_s3, R_sp, 24);
+ mMips->SD(R_s4, R_sp, 32);
+ mMips->MOVE(R_v0, R_a0); // move context * passed in a0 to v0 (arm r0)
+}
+
+void ArmToMips64Assembler::epilog(uint32_t touched __unused)
+{
+ mArmPC[mInum++] = pc(); // save starting PC for this instr
+
+ mMips->LD(R_s0, R_sp, 0);
+ mMips->LD(R_s1, R_sp, 8);
+ mMips->LD(R_s2, R_sp, 16);
+ mMips->LD(R_s3, R_sp, 24);
+ mMips->LD(R_s4, R_sp, 32);
+ mMips->DADDIU(R_sp, R_sp, (5 * 8));
+ mMips->JR(R_ra);
+
+}
+
+int ArmToMips64Assembler::generate(const char* name)
+{
+ return mMips->generate(name);
+}
+
+void ArmToMips64Assembler::fix_branches()
+{
+ mMips->fix_branches();
+}
+
+uint32_t* ArmToMips64Assembler::pcForLabel(const char* label)
+{
+ return mMips->pcForLabel(label);
+}
+
+void ArmToMips64Assembler::set_condition(int mode, int R1, int R2) {
+ if (mode == 2) {
+ cond.type = SBIT_COND;
+ } else {
+ cond.type = CMP_COND;
+ }
+ cond.r1 = R1;
+ cond.r2 = R2;
+}
+
+//----------------------------------------------------------
+
+#if 0
+#pragma mark -
+#pragma mark Addressing modes & shifters...
+#endif
+
+
+// do not need this for MIPS, but it is in the Interface (virtual)
+int ArmToMips64Assembler::buildImmediate(
+ uint32_t immediate, uint32_t& rot, uint32_t& imm)
+{
+ // for MIPS, any 32-bit immediate is OK
+ rot = 0;
+ imm = immediate;
+ return 0;
+}
+
+// shifters...
+
+bool ArmToMips64Assembler::isValidImmediate(uint32_t immediate __unused)
+{
+ // for MIPS, any 32-bit immediate is OK
+ return true;
+}
+
+uint32_t ArmToMips64Assembler::imm(uint32_t immediate)
+{
+ amode.value = immediate;
+ return AMODE_IMM;
+}
+
+uint32_t ArmToMips64Assembler::reg_imm(int Rm, int type, uint32_t shift)
+{
+ amode.reg = Rm;
+ amode.stype = type;
+ amode.value = shift;
+ return AMODE_REG_IMM;
+}
+
+uint32_t ArmToMips64Assembler::reg_rrx(int Rm __unused)
+{
+ // reg_rrx mode is not used in the GLLAssember code at this time
+ return AMODE_UNSUPPORTED;
+}
+
+uint32_t ArmToMips64Assembler::reg_reg(int Rm __unused, int type __unused,
+ int Rs __unused)
+{
+ // reg_reg mode is not used in the GLLAssember code at this time
+ return AMODE_UNSUPPORTED;
+}
+
+
+// addressing modes...
+// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
+uint32_t ArmToMips64Assembler::immed12_pre(int32_t immed12, int W)
+{
+ LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
+ "LDR(B)/STR(B)/PLD immediate too big (%08x)",
+ immed12);
+ amode.value = immed12;
+ amode.writeback = W;
+ return AMODE_IMM_12_PRE;
+}
+
+uint32_t ArmToMips64Assembler::immed12_post(int32_t immed12)
+{
+ LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
+ "LDR(B)/STR(B)/PLD immediate too big (%08x)",
+ immed12);
+
+ amode.value = immed12;
+ return AMODE_IMM_12_POST;
+}
+
+uint32_t ArmToMips64Assembler::reg_scale_pre(int Rm, int type,
+ uint32_t shift, int W)
+{
+ LOG_ALWAYS_FATAL_IF(W | type | shift, "reg_scale_pre adv modes not yet implemented");
+
+ amode.reg = Rm;
+ // amode.stype = type; // more advanced modes not used in GGLAssembler yet
+ // amode.value = shift;
+ // amode.writeback = W;
+ return AMODE_REG_SCALE_PRE;
+}
+
+uint32_t ArmToMips64Assembler::reg_scale_post(int Rm __unused, int type __unused,
+ uint32_t shift __unused)
+{
+ LOG_ALWAYS_FATAL("adr mode reg_scale_post not yet implemented\n");
+ return AMODE_UNSUPPORTED;
+}
+
+// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0)
+uint32_t ArmToMips64Assembler::immed8_pre(int32_t immed8, int W __unused)
+{
+ LOG_ALWAYS_FATAL("adr mode immed8_pre not yet implemented\n");
+
+ LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
+ "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
+ immed8);
+ return AMODE_IMM_8_PRE;
+}
+
+uint32_t ArmToMips64Assembler::immed8_post(int32_t immed8)
+{
+ LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
+ "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
+ immed8);
+ amode.value = immed8;
+ return AMODE_IMM_8_POST;
+}
+
+uint32_t ArmToMips64Assembler::reg_pre(int Rm, int W)
+{
+ LOG_ALWAYS_FATAL_IF(W, "reg_pre writeback not yet implemented");
+ amode.reg = Rm;
+ return AMODE_REG_PRE;
+}
+
+uint32_t ArmToMips64Assembler::reg_post(int Rm __unused)
+{
+ LOG_ALWAYS_FATAL("adr mode reg_post not yet implemented\n");
+ return AMODE_UNSUPPORTED;
+}
+
+
+
+// ----------------------------------------------------------------------------
+
+#if 0
+#pragma mark -
+#pragma mark Data Processing...
+#endif
+
+// check if the operand registers from a previous CMP or S-bit instruction
+// would be overwritten by this instruction. If so, move the value to a
+// safe register.
+// Note that we cannot tell at _this_ instruction time if a future (conditional)
+// instruction will _also_ use this value (a defect of the simple 1-pass, one-
+// instruction-at-a-time translation). Therefore we must be conservative and
+// save the value before it is overwritten. This costs an extra MOVE instr.
+
+void ArmToMips64Assembler::protectConditionalOperands(int Rd)
+{
+ if (Rd == cond.r1) {
+ mMips->MOVE(R_cmp, cond.r1);
+ cond.r1 = R_cmp;
+ }
+ if (cond.type == CMP_COND && Rd == cond.r2) {
+ mMips->MOVE(R_cmp2, cond.r2);
+ cond.r2 = R_cmp2;
+ }
+}
+
+
+// interprets the addressing mode, and generates the common code
+// used by the majority of data-processing ops. Many MIPS instructions
+// have a register-based form and a different immediate form. See
+// opAND below for an example. (this could be inlined)
+//
+// this works with the imm(), reg_imm() methods above, which are directly
+// called by the GLLAssembler.
+// note: _signed parameter defaults to false (un-signed)
+// note: tmpReg parameter defaults to 1, MIPS register AT
+int ArmToMips64Assembler::dataProcAdrModes(int op, int& source, bool _signed, int tmpReg)
+{
+ if (op < AMODE_REG) {
+ source = op;
+ return SRC_REG;
+ } else if (op == AMODE_IMM) {
+ if ((!_signed && amode.value > 0xffff)
+ || (_signed && ((int)amode.value < -32768 || (int)amode.value > 32767) )) {
+ mMips->LUI(tmpReg, (amode.value >> 16));
+ if (amode.value & 0x0000ffff) {
+ mMips->ORI(tmpReg, tmpReg, (amode.value & 0x0000ffff));
+ }
+ source = tmpReg;
+ return SRC_REG;
+ } else {
+ source = amode.value;
+ return SRC_IMM;
+ }
+ } else if (op == AMODE_REG_IMM) {
+ switch (amode.stype) {
+ case LSL: mMips->SLL(tmpReg, amode.reg, amode.value); break;
+ case LSR: mMips->SRL(tmpReg, amode.reg, amode.value); break;
+ case ASR: mMips->SRA(tmpReg, amode.reg, amode.value); break;
+ case ROR: mMips->ROTR(tmpReg, amode.reg, amode.value); break;
+ }
+ source = tmpReg;
+ return SRC_REG;
+ } else { // adr mode RRX is not used in GGL Assembler at this time
+ // we are screwed, this should be exception, assert-fail or something
+ LOG_ALWAYS_FATAL("adr mode reg_rrx not yet implemented\n");
+ return SRC_ERROR;
+ }
+}
+
+
+void ArmToMips64Assembler::dataProcessing(int opcode, int cc,
+ int s, int Rd, int Rn, uint32_t Op2)
+{
+ int src; // src is modified by dataProcAdrModes() - passed as int&
+
+ if (cc != AL) {
+ protectConditionalOperands(Rd);
+ // the branch tests register(s) set by prev CMP or instr with 'S' bit set
+ // inverse the condition to jump past this conditional instruction
+ ArmToMips64Assembler::B(cc^1, cond.label[++cond.labelnum]);
+ } else {
+ mArmPC[mInum++] = pc(); // save starting PC for this instr
+ }
+
+ switch (opcode) {
+ case opAND:
+ if (dataProcAdrModes(Op2, src) == SRC_REG) {
+ mMips->AND(Rd, Rn, src);
+ } else { // adr mode was SRC_IMM
+ mMips->ANDI(Rd, Rn, src);
+ }
+ break;
+
+ case opADD:
+ // set "signed" to true for adr modes
+ if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
+ mMips->ADDU(Rd, Rn, src);
+ } else { // adr mode was SRC_IMM
+ mMips->ADDIU(Rd, Rn, src);
+ }
+ break;
+
+ case opSUB:
+ // set "signed" to true for adr modes
+ if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
+ mMips->SUBU(Rd, Rn, src);
+ } else { // adr mode was SRC_IMM
+ mMips->SUBIU(Rd, Rn, src);
+ }
+ break;
+
+ case opADD64:
+ // set "signed" to true for adr modes
+ if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
+ mMips->DADDU(Rd, Rn, src);
+ } else { // adr mode was SRC_IMM
+ mMips->DADDIU(Rd, Rn, src);
+ }
+ break;
+
+ case opSUB64:
+ // set "signed" to true for adr modes
+ if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
+ mMips->DSUBU(Rd, Rn, src);
+ } else { // adr mode was SRC_IMM
+ mMips->DSUBIU(Rd, Rn, src);
+ }
+ break;
+
+ case opEOR:
+ if (dataProcAdrModes(Op2, src) == SRC_REG) {
+ mMips->XOR(Rd, Rn, src);
+ } else { // adr mode was SRC_IMM
+ mMips->XORI(Rd, Rn, src);
+ }
+ break;
+
+ case opORR:
+ if (dataProcAdrModes(Op2, src) == SRC_REG) {
+ mMips->OR(Rd, Rn, src);
+ } else { // adr mode was SRC_IMM
+ mMips->ORI(Rd, Rn, src);
+ }
+ break;
+
+ case opBIC:
+ if (dataProcAdrModes(Op2, src) == SRC_IMM) {
+ // if we are 16-bit imnmediate, load to AT reg
+ mMips->ORI(R_at, 0, src);
+ src = R_at;
+ }
+ mMips->NOT(R_at, src);
+ mMips->AND(Rd, Rn, R_at);
+ break;
+
+ case opRSB:
+ if (dataProcAdrModes(Op2, src) == SRC_IMM) {
+ // if we are 16-bit imnmediate, load to AT reg
+ mMips->ORI(R_at, 0, src);
+ src = R_at;
+ }
+ mMips->SUBU(Rd, src, Rn); // subu with the parameters reversed
+ break;
+
+ case opMOV:
+ if (Op2 < AMODE_REG) { // op2 is reg # in this case
+ mMips->MOVE(Rd, Op2);
+ } else if (Op2 == AMODE_IMM) {
+ if (amode.value > 0xffff) {
+ mMips->LUI(Rd, (amode.value >> 16));
+ if (amode.value & 0x0000ffff) {
+ mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
+ }
+ } else {
+ mMips->ORI(Rd, 0, amode.value);
+ }
+ } else if (Op2 == AMODE_REG_IMM) {
+ switch (amode.stype) {
+ case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
+ case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
+ case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
+ case ROR: mMips->ROTR(Rd, amode.reg, amode.value); break;
+ }
+ }
+ else {
+ // adr mode RRX is not used in GGL Assembler at this time
+ mMips->UNIMPL();
+ }
+ break;
+
+ case opMVN: // this is a 1's complement: NOT
+ if (Op2 < AMODE_REG) { // op2 is reg # in this case
+ mMips->NOR(Rd, Op2, 0); // NOT is NOR with 0
+ break;
+ } else if (Op2 == AMODE_IMM) {
+ if (amode.value > 0xffff) {
+ mMips->LUI(Rd, (amode.value >> 16));
+ if (amode.value & 0x0000ffff) {
+ mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
+ }
+ } else {
+ mMips->ORI(Rd, 0, amode.value);
+ }
+ } else if (Op2 == AMODE_REG_IMM) {
+ switch (amode.stype) {
+ case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
+ case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
+ case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
+ case ROR: mMips->ROTR(Rd, amode.reg, amode.value); break;
+ }
+ }
+ else {
+ // adr mode RRX is not used in GGL Assembler at this time
+ mMips->UNIMPL();
+ }
+ mMips->NOR(Rd, Rd, 0); // NOT is NOR with 0
+ break;
+
+ case opCMP:
+ // Either operand of a CMP instr could get overwritten by a subsequent
+ // conditional instruction, which is ok, _UNLESS_ there is a _second_
+ // conditional instruction. Under MIPS, this requires doing the comparison
+ // again (SLT), and the original operands must be available. (and this
+ // pattern of multiple conditional instructions from same CMP _is_ used
+ // in GGL-Assembler)
+ //
+ // For now, if a conditional instr overwrites the operands, we will
+ // move them to dedicated temp regs. This is ugly, and inefficient,
+ // and should be optimized.
+ //
+ // WARNING: making an _Assumption_ that CMP operand regs will NOT be
+ // trashed by intervening NON-conditional instructions. In the general
+ // case this is legal, but it is NOT currently done in GGL-Assembler.
+
+ cond.type = CMP_COND;
+ cond.r1 = Rn;
+ if (dataProcAdrModes(Op2, src, false, R_cmp2) == SRC_REG) {
+ cond.r2 = src;
+ } else { // adr mode was SRC_IMM
+ mMips->ORI(R_cmp2, R_zero, src);
+ cond.r2 = R_cmp2;
+ }
+
+ break;
+
+
+ case opTST:
+ case opTEQ:
+ case opCMN:
+ case opADC:
+ case opSBC:
+ case opRSC:
+ mMips->UNIMPL(); // currently unused in GGL Assembler code
+ break;
+ }
+
+ if (cc != AL) {
+ mMips->label(cond.label[cond.labelnum]);
+ }
+ if (s && opcode != opCMP) {
+ cond.type = SBIT_COND;
+ cond.r1 = Rd;
+ }
+}
+
+
+
+#if 0
+#pragma mark -
+#pragma mark Multiply...
+#endif
+
+// multiply, accumulate
+void ArmToMips64Assembler::MLA(int cc __unused, int s,
+ int Rd, int Rm, int Rs, int Rn) {
+
+ //ALOGW("MLA");
+ mArmPC[mInum++] = pc(); // save starting PC for this instr
+
+ mMips->MUL(R_at, Rm, Rs);
+ mMips->ADDU(Rd, R_at, Rn);
+ if (s) {
+ cond.type = SBIT_COND;
+ cond.r1 = Rd;
+ }
+}
+
+void ArmToMips64Assembler::MUL(int cc __unused, int s,
+ int Rd, int Rm, int Rs) {
+ mArmPC[mInum++] = pc();
+ mMips->MUL(Rd, Rm, Rs);
+ if (s) {
+ cond.type = SBIT_COND;
+ cond.r1 = Rd;
+ }
+}
+
+void ArmToMips64Assembler::UMULL(int cc __unused, int s,
+ int RdLo, int RdHi, int Rm, int Rs) {
+ mArmPC[mInum++] = pc();
+ mMips->MUH(RdHi, Rm, Rs);
+ mMips->MUL(RdLo, Rm, Rs);
+
+ if (s) {
+ cond.type = SBIT_COND;
+ cond.r1 = RdHi; // BUG...
+ LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
+ }
+}
+
+void ArmToMips64Assembler::UMUAL(int cc __unused, int s,
+ int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
+ LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
+ "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
+ // *mPC++ = (cc<<28) | (1<<23) | (1<<21) | (s<<20) |
+ // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+ if (s) {
+ cond.type = SBIT_COND;
+ cond.r1 = RdHi; // BUG...
+ LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
+ }
+}
+
+void ArmToMips64Assembler::SMULL(int cc __unused, int s,
+ int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
+ LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
+ "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
+ // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (s<<20) |
+ // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+ if (s) {
+ cond.type = SBIT_COND;
+ cond.r1 = RdHi; // BUG...
+ LOG_ALWAYS_FATAL("Condition on SMULL must be on 64-bit result\n");
+ }
+}
+void ArmToMips64Assembler::SMUAL(int cc __unused, int s,
+ int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
+ LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
+ "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
+ // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) |
+ // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+ if (s) {
+ cond.type = SBIT_COND;
+ cond.r1 = RdHi; // BUG...
+ LOG_ALWAYS_FATAL("Condition on SMUAL must be on 64-bit result\n");
+ }
+}
+
+
+
+#if 0
+#pragma mark -
+#pragma mark Branches...
+#endif
+
+// branches...
+
+void ArmToMips64Assembler::B(int cc, const char* label)
+{
+ mArmPC[mInum++] = pc();
+ if (cond.type == SBIT_COND) { cond.r2 = R_zero; }
+
+ switch(cc) {
+ case EQ: mMips->BEQ(cond.r1, cond.r2, label); break;
+ case NE: mMips->BNE(cond.r1, cond.r2, label); break;
+ case HS: mMips->BGEU(cond.r1, cond.r2, label); break;
+ case LO: mMips->BLTU(cond.r1, cond.r2, label); break;
+ case MI: mMips->BLT(cond.r1, cond.r2, label); break;
+ case PL: mMips->BGE(cond.r1, cond.r2, label); break;
+
+ case HI: mMips->BGTU(cond.r1, cond.r2, label); break;
+ case LS: mMips->BLEU(cond.r1, cond.r2, label); break;
+ case GE: mMips->BGE(cond.r1, cond.r2, label); break;
+ case LT: mMips->BLT(cond.r1, cond.r2, label); break;
+ case GT: mMips->BGT(cond.r1, cond.r2, label); break;
+ case LE: mMips->BLE(cond.r1, cond.r2, label); break;
+ case AL: mMips->B(label); break;
+ case NV: /* B Never - no instruction */ break;
+
+ case VS:
+ case VC:
+ default:
+ LOG_ALWAYS_FATAL("Unsupported cc: %02x\n", cc);
+ break;
+ }
+}
+
+void ArmToMips64Assembler::BL(int cc __unused, const char* label __unused)
+{
+ LOG_ALWAYS_FATAL("branch-and-link not supported yet\n");
+ mArmPC[mInum++] = pc();
+}
+
+// no use for Branches with integer PC, but they're in the Interface class ....
+void ArmToMips64Assembler::B(int cc __unused, uint32_t* to_pc __unused)
+{
+ LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
+ mArmPC[mInum++] = pc();
+}
+
+void ArmToMips64Assembler::BL(int cc __unused, uint32_t* to_pc __unused)
+{
+ LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
+ mArmPC[mInum++] = pc();
+}
+
+void ArmToMips64Assembler::BX(int cc __unused, int Rn __unused)
+{
+ LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
+ mArmPC[mInum++] = pc();
+}
+
+
+
+#if 0
+#pragma mark -
+#pragma mark Data Transfer...
+#endif
+
+// data transfer...
+void ArmToMips64Assembler::LDR(int cc __unused, int Rd, int Rn, uint32_t offset)
+{
+ mArmPC[mInum++] = pc();
+ // work-around for ARM default address mode of immed12_pre(0)
+ if (offset > AMODE_UNSUPPORTED) offset = 0;
+ switch (offset) {
+ case 0:
+ amode.value = 0;
+ amode.writeback = 0;
+ // fall thru to next case ....
+ case AMODE_IMM_12_PRE:
+ if (Rn == ARMAssemblerInterface::SP) {
+ Rn = R_sp; // convert LDR via Arm SP to LW via Mips SP
+ }
+ mMips->LW(Rd, Rn, amode.value);
+ if (amode.writeback) { // OPTIONAL writeback on pre-index mode
+ mMips->DADDIU(Rn, Rn, amode.value);
+ }
+ break;
+ case AMODE_IMM_12_POST:
+ if (Rn == ARMAssemblerInterface::SP) {
+ Rn = R_sp; // convert STR thru Arm SP to STR thru Mips SP
+ }
+ mMips->LW(Rd, Rn, 0);
+ mMips->DADDIU(Rn, Rn, amode.value);
+ break;
+ case AMODE_REG_SCALE_PRE:
+ // we only support simple base + index, no advanced modes for this one yet
+ mMips->DADDU(R_at, Rn, amode.reg);
+ mMips->LW(Rd, R_at, 0);
+ break;
+ }
+}
+
+void ArmToMips64Assembler::LDRB(int cc __unused, int Rd, int Rn, uint32_t offset)
+{
+ mArmPC[mInum++] = pc();
+ // work-around for ARM default address mode of immed12_pre(0)
+ if (offset > AMODE_UNSUPPORTED) offset = 0;
+ switch (offset) {
+ case 0:
+ amode.value = 0;
+ amode.writeback = 0;
+ // fall thru to next case ....
+ case AMODE_IMM_12_PRE:
+ mMips->LBU(Rd, Rn, amode.value);
+ if (amode.writeback) { // OPTIONAL writeback on pre-index mode
+ mMips->DADDIU(Rn, Rn, amode.value);
+ }
+ break;
+ case AMODE_IMM_12_POST:
+ mMips->LBU(Rd, Rn, 0);
+ mMips->DADDIU(Rn, Rn, amode.value);
+ break;
+ case AMODE_REG_SCALE_PRE:
+ // we only support simple base + index, no advanced modes for this one yet
+ mMips->DADDU(R_at, Rn, amode.reg);
+ mMips->LBU(Rd, R_at, 0);
+ break;
+ }
+
+}
+
+void ArmToMips64Assembler::STR(int cc __unused, int Rd, int Rn, uint32_t offset)
+{
+ mArmPC[mInum++] = pc();
+ // work-around for ARM default address mode of immed12_pre(0)
+ if (offset > AMODE_UNSUPPORTED) offset = 0;
+ switch (offset) {
+ case 0:
+ amode.value = 0;
+ amode.writeback = 0;
+ // fall thru to next case ....
+ case AMODE_IMM_12_PRE:
+ if (Rn == ARMAssemblerInterface::SP) {
+ Rn = R_sp; // convert STR thru Arm SP to SW thru Mips SP
+ }
+ if (amode.writeback) { // OPTIONAL writeback on pre-index mode
+ // If we will writeback, then update the index reg, then store.
+ // This correctly handles stack-push case.
+ mMips->DADDIU(Rn, Rn, amode.value);
+ mMips->SW(Rd, Rn, 0);
+ } else {
+ // No writeback so store offset by value
+ mMips->SW(Rd, Rn, amode.value);
+ }
+ break;
+ case AMODE_IMM_12_POST:
+ mMips->SW(Rd, Rn, 0);
+ mMips->DADDIU(Rn, Rn, amode.value); // post index always writes back
+ break;
+ case AMODE_REG_SCALE_PRE:
+ // we only support simple base + index, no advanced modes for this one yet
+ mMips->DADDU(R_at, Rn, amode.reg);
+ mMips->SW(Rd, R_at, 0);
+ break;
+ }
+}
+
+void ArmToMips64Assembler::STRB(int cc __unused, int Rd, int Rn, uint32_t offset)
+{
+ mArmPC[mInum++] = pc();
+ // work-around for ARM default address mode of immed12_pre(0)
+ if (offset > AMODE_UNSUPPORTED) offset = 0;
+ switch (offset) {
+ case 0:
+ amode.value = 0;
+ amode.writeback = 0;
+ // fall thru to next case ....
+ case AMODE_IMM_12_PRE:
+ mMips->SB(Rd, Rn, amode.value);
+ if (amode.writeback) { // OPTIONAL writeback on pre-index mode
+ mMips->DADDIU(Rn, Rn, amode.value);
+ }
+ break;
+ case AMODE_IMM_12_POST:
+ mMips->SB(Rd, Rn, 0);
+ mMips->DADDIU(Rn, Rn, amode.value);
+ break;
+ case AMODE_REG_SCALE_PRE:
+ // we only support simple base + index, no advanced modes for this one yet
+ mMips->DADDU(R_at, Rn, amode.reg);
+ mMips->SB(Rd, R_at, 0);
+ break;
+ }
+}
+
+void ArmToMips64Assembler::LDRH(int cc __unused, int Rd, int Rn, uint32_t offset)
+{
+ mArmPC[mInum++] = pc();
+ // work-around for ARM default address mode of immed8_pre(0)
+ if (offset > AMODE_UNSUPPORTED) offset = 0;
+ switch (offset) {
+ case 0:
+ amode.value = 0;
+ // fall thru to next case ....
+ case AMODE_IMM_8_PRE: // no support yet for writeback
+ mMips->LHU(Rd, Rn, amode.value);
+ break;
+ case AMODE_IMM_8_POST:
+ mMips->LHU(Rd, Rn, 0);
+ mMips->DADDIU(Rn, Rn, amode.value);
+ break;
+ case AMODE_REG_PRE:
+ // we only support simple base +/- index
+ if (amode.reg >= 0) {
+ mMips->DADDU(R_at, Rn, amode.reg);
+ } else {
+ mMips->DSUBU(R_at, Rn, abs(amode.reg));
+ }
+ mMips->LHU(Rd, R_at, 0);
+ break;
+ }
+}
+
+void ArmToMips64Assembler::LDRSB(int cc __unused, int Rd __unused,
+ int Rn __unused, uint32_t offset __unused)
+{
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+void ArmToMips64Assembler::LDRSH(int cc __unused, int Rd __unused,
+ int Rn __unused, uint32_t offset __unused)
+{
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+void ArmToMips64Assembler::STRH(int cc __unused, int Rd, int Rn, uint32_t offset)
+{
+ mArmPC[mInum++] = pc();
+ // work-around for ARM default address mode of immed8_pre(0)
+ if (offset > AMODE_UNSUPPORTED) offset = 0;
+ switch (offset) {
+ case 0:
+ amode.value = 0;
+ // fall thru to next case ....
+ case AMODE_IMM_8_PRE: // no support yet for writeback
+ mMips->SH(Rd, Rn, amode.value);
+ break;
+ case AMODE_IMM_8_POST:
+ mMips->SH(Rd, Rn, 0);
+ mMips->DADDIU(Rn, Rn, amode.value);
+ break;
+ case AMODE_REG_PRE:
+ // we only support simple base +/- index
+ if (amode.reg >= 0) {
+ mMips->DADDU(R_at, Rn, amode.reg);
+ } else {
+ mMips->DSUBU(R_at, Rn, abs(amode.reg));
+ }
+ mMips->SH(Rd, R_at, 0);
+ break;
+ }
+}
+
+
+
+#if 0
+#pragma mark -
+#pragma mark Block Data Transfer...
+#endif
+
+// block data transfer...
+void ArmToMips64Assembler::LDM(int cc __unused, int dir __unused,
+ int Rn __unused, int W __unused, uint32_t reg_list __unused)
+{ // ED FD EA FA IB IA DB DA
+ // const uint8_t P[8] = { 1, 0, 1, 0, 1, 0, 1, 0 };
+ // const uint8_t U[8] = { 1, 1, 0, 0, 1, 1, 0, 0 };
+ // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
+ // (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+void ArmToMips64Assembler::STM(int cc __unused, int dir __unused,
+ int Rn __unused, int W __unused, uint32_t reg_list __unused)
+{ // FA EA FD ED IB IA DB DA
+ // const uint8_t P[8] = { 0, 1, 0, 1, 1, 0, 1, 0 };
+ // const uint8_t U[8] = { 0, 0, 1, 1, 1, 1, 0, 0 };
+ // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
+ // (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+
+
+#if 0
+#pragma mark -
+#pragma mark Special...
+#endif
+
+// special...
+void ArmToMips64Assembler::SWP(int cc __unused, int Rn __unused,
+ int Rd __unused, int Rm __unused) {
+ // *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+void ArmToMips64Assembler::SWPB(int cc __unused, int Rn __unused,
+ int Rd __unused, int Rm __unused) {
+ // *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+void ArmToMips64Assembler::SWI(int cc __unused, uint32_t comment __unused) {
+ // *mPC++ = (cc<<28) | (0xF<<24) | comment;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+
+#if 0
+#pragma mark -
+#pragma mark DSP instructions...
+#endif
+
+// DSP instructions...
+void ArmToMips64Assembler::PLD(int Rn __unused, uint32_t offset) {
+ LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))),
+ "PLD only P=1, W=0");
+ // *mPC++ = 0xF550F000 | (Rn<<16) | offset;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+void ArmToMips64Assembler::CLZ(int cc __unused, int Rd, int Rm)
+{
+ mArmPC[mInum++] = pc();
+ mMips->CLZ(Rd, Rm);
+}
+
+void ArmToMips64Assembler::QADD(int cc __unused, int Rd __unused,
+ int Rm __unused, int Rn __unused)
+{
+ // *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+void ArmToMips64Assembler::QDADD(int cc __unused, int Rd __unused,
+ int Rm __unused, int Rn __unused)
+{
+ // *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+void ArmToMips64Assembler::QSUB(int cc __unused, int Rd __unused,
+ int Rm __unused, int Rn __unused)
+{
+ // *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+void ArmToMips64Assembler::QDSUB(int cc __unused, int Rd __unused,
+ int Rm __unused, int Rn __unused)
+{
+ // *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+// 16 x 16 signed multiply (like SMLAxx without the accumulate)
+void ArmToMips64Assembler::SMUL(int cc __unused, int xy,
+ int Rd, int Rm, int Rs)
+{
+ mArmPC[mInum++] = pc();
+
+ // the 16 bits may be in the top or bottom half of 32-bit source reg,
+ // as defined by the codes BB, BT, TB, TT (compressed param xy)
+ // where x corresponds to Rm and y to Rs
+
+ // select half-reg for Rm
+ if (xy & xyTB) {
+ // use top 16-bits
+ mMips->SRA(R_at, Rm, 16);
+ } else {
+ // use bottom 16, but sign-extend to 32
+ mMips->SEH(R_at, Rm);
+ }
+ // select half-reg for Rs
+ if (xy & xyBT) {
+ // use top 16-bits
+ mMips->SRA(R_at2, Rs, 16);
+ } else {
+ // use bottom 16, but sign-extend to 32
+ mMips->SEH(R_at2, Rs);
+ }
+ mMips->MUL(Rd, R_at, R_at2);
+}
+
+// signed 32b x 16b multiple, save top 32-bits of 48-bit result
+void ArmToMips64Assembler::SMULW(int cc __unused, int y,
+ int Rd, int Rm, int Rs)
+{
+ mArmPC[mInum++] = pc();
+
+ // the selector yT or yB refers to reg Rs
+ if (y & yT) {
+ // zero the bottom 16-bits, with 2 shifts, it can affect result
+ mMips->SRL(R_at, Rs, 16);
+ mMips->SLL(R_at, R_at, 16);
+
+ } else {
+ // move low 16-bit half, to high half
+ mMips->SLL(R_at, Rs, 16);
+ }
+ mMips->MUH(Rd, Rm, R_at);
+}
+
+// 16 x 16 signed multiply, accumulate: Rd = Rm{16} * Rs{16} + Rn
+void ArmToMips64Assembler::SMLA(int cc __unused, int xy,
+ int Rd, int Rm, int Rs, int Rn)
+{
+ mArmPC[mInum++] = pc();
+
+ // the 16 bits may be in the top or bottom half of 32-bit source reg,
+ // as defined by the codes BB, BT, TB, TT (compressed param xy)
+ // where x corresponds to Rm and y to Rs
+
+ // select half-reg for Rm
+ if (xy & xyTB) {
+ // use top 16-bits
+ mMips->SRA(R_at, Rm, 16);
+ } else {
+ // use bottom 16, but sign-extend to 32
+ mMips->SEH(R_at, Rm);
+ }
+ // select half-reg for Rs
+ if (xy & xyBT) {
+ // use top 16-bits
+ mMips->SRA(R_at2, Rs, 16);
+ } else {
+ // use bottom 16, but sign-extend to 32
+ mMips->SEH(R_at2, Rs);
+ }
+
+ mMips->MUL(R_at, R_at, R_at2);
+ mMips->ADDU(Rd, R_at, Rn);
+}
+
+void ArmToMips64Assembler::SMLAL(int cc __unused, int xy __unused,
+ int RdHi __unused, int RdLo __unused,
+ int Rs __unused, int Rm __unused)
+{
+ // *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+void ArmToMips64Assembler::SMLAW(int cc __unused, int y __unused,
+ int Rd __unused, int Rm __unused,
+ int Rs __unused, int Rn __unused)
+{
+ // *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm;
+ mArmPC[mInum++] = pc();
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+// used by ARMv6 version of GGLAssembler::filter32
+void ArmToMips64Assembler::UXTB16(int cc __unused, int Rd, int Rm, int rotate)
+{
+ mArmPC[mInum++] = pc();
+
+ //Rd[31:16] := ZeroExtend((Rm ROR (8 * sh))[23:16]),
+ //Rd[15:0] := ZeroExtend((Rm ROR (8 * sh))[7:0]). sh 0-3.
+
+ mMips->ROTR(R_at2, Rm, rotate * 8);
+ mMips->LUI(R_at, 0xFF);
+ mMips->ORI(R_at, R_at, 0xFF);
+ mMips->AND(Rd, R_at2, R_at);
+}
+
+void ArmToMips64Assembler::UBFX(int cc __unused, int Rd __unused, int Rn __unused,
+ int lsb __unused, int width __unused)
+{
+ /* Placeholder for UBFX */
+ mArmPC[mInum++] = pc();
+
+ mMips->NOP2();
+ NOT_IMPLEMENTED();
+}
+
+// ----------------------------------------------------------------------------
+// Address Processing...
+// ----------------------------------------------------------------------------
+
+void ArmToMips64Assembler::ADDR_ADD(int cc,
+ int s, int Rd, int Rn, uint32_t Op2)
+{
+// if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+// if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
+ dataProcessing(opADD64, cc, s, Rd, Rn, Op2);
+}
+
+void ArmToMips64Assembler::ADDR_SUB(int cc,
+ int s, int Rd, int Rn, uint32_t Op2)
+{
+// if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+// if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
+ dataProcessing(opSUB64, cc, s, Rd, Rn, Op2);
+}
+
+void ArmToMips64Assembler::ADDR_LDR(int cc __unused, int Rd,
+ int Rn, uint32_t offset) {
+ mArmPC[mInum++] = pc();
+ // work-around for ARM default address mode of immed12_pre(0)
+ if (offset > AMODE_UNSUPPORTED) offset = 0;
+ switch (offset) {
+ case 0:
+ amode.value = 0;
+ amode.writeback = 0;
+ // fall thru to next case ....
+ case AMODE_IMM_12_PRE:
+ if (Rn == ARMAssemblerInterface::SP) {
+ Rn = R_sp; // convert LDR via Arm SP to LW via Mips SP
+ }
+ mMips->LD(Rd, Rn, amode.value);
+ if (amode.writeback) { // OPTIONAL writeback on pre-index mode
+ mMips->DADDIU(Rn, Rn, amode.value);
+ }
+ break;
+ case AMODE_IMM_12_POST:
+ if (Rn == ARMAssemblerInterface::SP) {
+ Rn = R_sp; // convert STR thru Arm SP to STR thru Mips SP
+ }
+ mMips->LD(Rd, Rn, 0);
+ mMips->DADDIU(Rn, Rn, amode.value);
+ break;
+ case AMODE_REG_SCALE_PRE:
+ // we only support simple base + index, no advanced modes for this one yet
+ mMips->DADDU(R_at, Rn, amode.reg);
+ mMips->LD(Rd, R_at, 0);
+ break;
+ }
+}
+
+void ArmToMips64Assembler::ADDR_STR(int cc __unused, int Rd,
+ int Rn, uint32_t offset) {
+ mArmPC[mInum++] = pc();
+ // work-around for ARM default address mode of immed12_pre(0)
+ if (offset > AMODE_UNSUPPORTED) offset = 0;
+ switch (offset) {
+ case 0:
+ amode.value = 0;
+ amode.writeback = 0;
+ // fall thru to next case ....
+ case AMODE_IMM_12_PRE:
+ if (Rn == ARMAssemblerInterface::SP) {
+ Rn = R_sp; // convert STR thru Arm SP to SW thru Mips SP
+ }
+ if (amode.writeback) { // OPTIONAL writeback on pre-index mode
+ // If we will writeback, then update the index reg, then store.
+ // This correctly handles stack-push case.
+ mMips->DADDIU(Rn, Rn, amode.value);
+ mMips->SD(Rd, Rn, 0);
+ } else {
+ // No writeback so store offset by value
+ mMips->SD(Rd, Rn, amode.value);
+ }
+ break;
+ case AMODE_IMM_12_POST:
+ mMips->SD(Rd, Rn, 0);
+ mMips->DADDIU(Rn, Rn, amode.value); // post index always writes back
+ break;
+ case AMODE_REG_SCALE_PRE:
+ // we only support simple base + index, no advanced modes for this one yet
+ mMips->DADDU(R_at, Rn, amode.reg);
+ mMips->SD(Rd, R_at, 0);
+ break;
+ }
+}
+
+#if 0
+#pragma mark -
+#pragma mark MIPS Assembler...
+#endif
+
+
+//**************************************************************************
+//**************************************************************************
+//**************************************************************************
+
+
+/* MIPS64 assembler
+** this is a subset of mips64r6, targeted specifically at ARM instruction
+** replacement in the pixelflinger/codeflinger code.
+**
+** This class is extended from MIPSAssembler class and overrides only
+** MIPS64r6 specific stuff.
+*/
+
+MIPS64Assembler::MIPS64Assembler(const sp<Assembly>& assembly, ArmToMips64Assembler *parent)
+ : MIPSAssembler::MIPSAssembler(assembly, NULL), mParent(parent)
+{
+}
+
+MIPS64Assembler::MIPS64Assembler(void* assembly, ArmToMips64Assembler *parent)
+ : MIPSAssembler::MIPSAssembler(assembly), mParent(parent)
+{
+}
+
+MIPS64Assembler::~MIPS64Assembler()
+{
+}
+
+void MIPS64Assembler::reset()
+{
+ if (mAssembly != NULL) {
+ mBase = mPC = (uint32_t *)mAssembly->base();
+ } else {
+ mPC = mBase = base();
+ }
+ mBranchTargets.clear();
+ mLabels.clear();
+ mLabelsInverseMapping.clear();
+ mComments.clear();
+}
+
+
+void MIPS64Assembler::disassemble(const char* name __unused)
+{
+ char di_buf[140];
+
+ bool arm_disasm_fmt = (mParent->mArmDisassemblyBuffer == NULL) ? false : true;
+
+ typedef char dstr[40];
+ dstr *lines = (dstr *)mParent->mArmDisassemblyBuffer;
+
+ if (mParent->mArmDisassemblyBuffer != NULL) {
+ for (int i=0; i<mParent->mArmInstrCount; ++i) {
+ string_detab(lines[i]);
+ }
+ }
+
+ size_t count = pc()-base();
+ uint32_t* mipsPC = base();
+
+ while (count--) {
+ ssize_t label = mLabelsInverseMapping.indexOfKey(mipsPC);
+ if (label >= 0) {
+ ALOGW("%s:\n", mLabelsInverseMapping.valueAt(label));
+ }
+ ssize_t comment = mComments.indexOfKey(mipsPC);
+ if (comment >= 0) {
+ ALOGW("; %s\n", mComments.valueAt(comment));
+ }
+ ::mips_disassem(mipsPC, di_buf, arm_disasm_fmt);
+ string_detab(di_buf);
+ string_pad(di_buf, 30);
+ ALOGW("%08lx: %08x %s", uintptr_t(mipsPC), uint32_t(*mipsPC), di_buf);
+ mipsPC++;
+ }
+}
+
+void MIPS64Assembler::fix_branches()
+{
+ // fixup all the branches
+ size_t count = mBranchTargets.size();
+ while (count--) {
+ const branch_target_t& bt = mBranchTargets[count];
+ uint32_t* target_pc = mLabels.valueFor(bt.label);
+ LOG_ALWAYS_FATAL_IF(!target_pc,
+ "error resolving branch targets, target_pc is null");
+ int32_t offset = int32_t(target_pc - (bt.pc+1));
+ *bt.pc |= offset & 0x00FFFF;
+ }
+}
+
+void MIPS64Assembler::DADDU(int Rd, int Rs, int Rt)
+{
+ *mPC++ = (spec_op<<OP_SHF) | (daddu_fn<<FUNC_SHF)
+ | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF);
+}
+
+void MIPS64Assembler::DADDIU(int Rt, int Rs, int16_t imm)
+{
+ *mPC++ = (daddiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
+}
+
+void MIPS64Assembler::DSUBU(int Rd, int Rs, int Rt)
+{
+ *mPC++ = (spec_op<<OP_SHF) | (dsubu_fn<<FUNC_SHF) |
+ (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
+}
+
+void MIPS64Assembler::DSUBIU(int Rt, int Rs, int16_t imm) // really addiu(d, s, -j)
+{
+ *mPC++ = (daddiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | ((-imm) & MSK_16);
+}
+
+void MIPS64Assembler::MUL(int Rd, int Rs, int Rt)
+{
+ *mPC++ = (spec_op<<OP_SHF) | (mul_fn<<RE_SHF) | (sop30_fn<<FUNC_SHF) |
+ (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
+}
+
+void MIPS64Assembler::MUH(int Rd, int Rs, int Rt)
+{
+ *mPC++ = (spec_op<<OP_SHF) | (muh_fn<<RE_SHF) | (sop30_fn<<FUNC_SHF) |
+ (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
+}
+
+void MIPS64Assembler::CLO(int Rd, int Rs)
+{
+ *mPC++ = (spec_op<<OP_SHF) | (17<<FUNC_SHF) |
+ (Rd<<RD_SHF) | (Rs<<RS_SHF) | (1<<RE_SHF);
+}
+
+void MIPS64Assembler::CLZ(int Rd, int Rs)
+{
+ *mPC++ = (spec_op<<OP_SHF) | (16<<FUNC_SHF) |
+ (Rd<<RD_SHF) | (Rs<<RS_SHF) | (1<<RE_SHF);
+}
+
+void MIPS64Assembler::LD(int Rt, int Rbase, int16_t offset)
+{
+ *mPC++ = (ld_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
+}
+
+void MIPS64Assembler::SD(int Rt, int Rbase, int16_t offset)
+{
+ *mPC++ = (sd_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
+}
+
+void MIPS64Assembler::LUI(int Rt, int16_t offset)
+{
+ *mPC++ = (aui_op<<OP_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
+}
+
+
+void MIPS64Assembler::JR(int Rs)
+{
+ *mPC++ = (spec_op<<OP_SHF) | (Rs<<RS_SHF) | (jalr_fn << FUNC_SHF);
+ MIPS64Assembler::NOP();
+}
+
+}; // namespace android:
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.h b/libpixelflinger/codeflinger/MIPS64Assembler.h
new file mode 100644
index 0000000..b43e5da
--- /dev/null
+++ b/libpixelflinger/codeflinger/MIPS64Assembler.h
@@ -0,0 +1,404 @@
+/* libs/pixelflinger/codeflinger/MIPS64Assembler.h
+**
+** Copyright 2015, The Android Open Source 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.
+*/
+
+#ifndef ANDROID_MIPS64ASSEMBLER_H
+#define ANDROID_MIPS64ASSEMBLER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "utils/KeyedVector.h"
+#include "utils/Vector.h"
+#include "tinyutils/smartpointer.h"
+
+#include "ARMAssemblerInterface.h"
+#include "MIPSAssembler.h"
+#include "CodeCache.h"
+
+namespace android {
+
+class MIPS64Assembler; // forward reference
+
+// this class mimics ARMAssembler interface
+// intent is to translate each ARM instruction to 1 or more MIPS instr
+// implementation calls MIPS64Assembler class to generate mips code
+class ArmToMips64Assembler : public ARMAssemblerInterface
+{
+public:
+ ArmToMips64Assembler(const sp<Assembly>& assembly,
+ char *abuf = 0, int linesz = 0, int instr_count = 0);
+ ArmToMips64Assembler(void* assembly);
+ virtual ~ArmToMips64Assembler();
+
+ uint32_t* base() const;
+ uint32_t* pc() const;
+ void disassemble(const char* name);
+
+ virtual void reset();
+
+ virtual int generate(const char* name);
+ virtual int getCodegenArch();
+
+ virtual void prolog();
+ virtual void epilog(uint32_t touched);
+ virtual void comment(const char* string);
+ // for testing purposes
+ void fix_branches();
+ void set_condition(int mode, int R1, int R2);
+
+
+ // -----------------------------------------------------------------------
+ // shifters and addressing modes
+ // -----------------------------------------------------------------------
+
+ // shifters...
+ virtual bool isValidImmediate(uint32_t immed);
+ virtual int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm);
+
+ virtual uint32_t imm(uint32_t immediate);
+ virtual uint32_t reg_imm(int Rm, int type, uint32_t shift);
+ virtual uint32_t reg_rrx(int Rm);
+ virtual uint32_t reg_reg(int Rm, int type, int Rs);
+
+ // addressing modes...
+ // LDR(B)/STR(B)/PLD
+ // (immediate and Rm can be negative, which indicates U=0)
+ virtual uint32_t immed12_pre(int32_t immed12, int W=0);
+ virtual uint32_t immed12_post(int32_t immed12);
+ virtual uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0);
+ virtual uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0);
+
+ // LDRH/LDRSB/LDRSH/STRH
+ // (immediate and Rm can be negative, which indicates U=0)
+ virtual uint32_t immed8_pre(int32_t immed8, int W=0);
+ virtual uint32_t immed8_post(int32_t immed8);
+ virtual uint32_t reg_pre(int Rm, int W=0);
+ virtual uint32_t reg_post(int Rm);
+
+
+
+
+ virtual void dataProcessing(int opcode, int cc, int s,
+ int Rd, int Rn,
+ uint32_t Op2);
+ virtual void MLA(int cc, int s,
+ int Rd, int Rm, int Rs, int Rn);
+ virtual void MUL(int cc, int s,
+ int Rd, int Rm, int Rs);
+ virtual void UMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+ virtual void UMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+ virtual void SMULL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+ virtual void SMUAL(int cc, int s,
+ int RdLo, int RdHi, int Rm, int Rs);
+
+ virtual void B(int cc, uint32_t* pc);
+ virtual void BL(int cc, uint32_t* pc);
+ virtual void BX(int cc, int Rn);
+ virtual void label(const char* theLabel);
+ virtual void B(int cc, const char* label);
+ virtual void BL(int cc, const char* label);
+
+ virtual uint32_t* pcForLabel(const char* label);
+
+ virtual void LDR (int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void LDRB(int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void STR (int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void STRB(int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void LDRH (int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void LDRSB(int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void LDRSH(int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+ virtual void STRH (int cc, int Rd,
+ int Rn, uint32_t offset = 0);
+
+ virtual void LDM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list);
+ virtual void STM(int cc, int dir,
+ int Rn, int W, uint32_t reg_list);
+
+ virtual void SWP(int cc, int Rn, int Rd, int Rm);
+ virtual void SWPB(int cc, int Rn, int Rd, int Rm);
+ virtual void SWI(int cc, uint32_t comment);
+
+ virtual void PLD(int Rn, uint32_t offset);
+ virtual void CLZ(int cc, int Rd, int Rm);
+ virtual void QADD(int cc, int Rd, int Rm, int Rn);
+ virtual void QDADD(int cc, int Rd, int Rm, int Rn);
+ virtual void QSUB(int cc, int Rd, int Rm, int Rn);
+ virtual void QDSUB(int cc, int Rd, int Rm, int Rn);
+ virtual void SMUL(int cc, int xy,
+ int Rd, int Rm, int Rs);
+ virtual void SMULW(int cc, int y,
+ int Rd, int Rm, int Rs);
+ virtual void SMLA(int cc, int xy,
+ int Rd, int Rm, int Rs, int Rn);
+ virtual void SMLAL(int cc, int xy,
+ int RdHi, int RdLo, int Rs, int Rm);
+ virtual void SMLAW(int cc, int y,
+ int Rd, int Rm, int Rs, int Rn);
+
+ // byte/half word extract...
+ virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
+
+ // bit manipulation...
+ virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
+
+ // Address loading/storing/manipulation
+ virtual void ADDR_LDR(int cc, int Rd, int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void ADDR_STR(int cc, int Rd, int Rn, uint32_t offset = __immed12_pre(0));
+ virtual void ADDR_ADD(int cc, int s, int Rd, int Rn, uint32_t Op2);
+ virtual void ADDR_SUB(int cc, int s, int Rd, int Rn, uint32_t Op2);
+
+ // this is some crap to share is MIPS64Assembler class for debug
+ char * mArmDisassemblyBuffer;
+ int mArmLineLength;
+ int mArmInstrCount;
+
+ int mInum; // current arm instuction number (0..n)
+ uint32_t** mArmPC; // array: PC for 1st mips instr of
+ // each translated ARM instr
+
+
+private:
+ ArmToMips64Assembler(const ArmToMips64Assembler& rhs);
+ ArmToMips64Assembler& operator = (const ArmToMips64Assembler& rhs);
+
+ void init_conditional_labels(void);
+
+ void protectConditionalOperands(int Rd);
+
+ // reg__tmp set to MIPS AT, reg 1
+ int dataProcAdrModes(int op, int& source, bool sign = false, int reg_tmp = 1);
+
+ sp<Assembly> mAssembly;
+ MIPS64Assembler* mMips;
+
+
+ enum misc_constants_t {
+ ARM_MAX_INSTUCTIONS = 512 // based on ASSEMBLY_SCRATCH_SIZE
+ };
+
+ enum {
+ SRC_REG = 0,
+ SRC_IMM,
+ SRC_ERROR = -1
+ };
+
+ enum addr_modes {
+ // start above the range of legal mips reg #'s (0-31)
+ AMODE_REG = 0x20,
+ AMODE_IMM, AMODE_REG_IMM, // for data processing
+ AMODE_IMM_12_PRE, AMODE_IMM_12_POST, // for load/store
+ AMODE_REG_SCALE_PRE, AMODE_IMM_8_PRE,
+ AMODE_IMM_8_POST, AMODE_REG_PRE,
+ AMODE_UNSUPPORTED
+ };
+
+ struct addr_mode_t { // address modes for current ARM instruction
+ int reg;
+ int stype;
+ uint32_t value;
+ bool writeback; // writeback the adr reg after modification
+ } amode;
+
+ enum cond_types {
+ CMP_COND = 1,
+ SBIT_COND
+ };
+
+ struct cond_mode_t { // conditional-execution info for current ARM instruction
+ cond_types type;
+ int r1;
+ int r2;
+ int labelnum;
+ char label[100][10];
+ } cond;
+};
+
+
+
+
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+
+// This is the basic MIPS64 assembler, which just creates the opcodes in memory.
+// All the more complicated work is done in ArmToMips64Assember above.
+// Inherits MIPSAssembler class, and overrides only MIPS64r6 specific stuff
+
+class MIPS64Assembler : public MIPSAssembler
+{
+public:
+ MIPS64Assembler(const sp<Assembly>& assembly, ArmToMips64Assembler *parent);
+ MIPS64Assembler(void* assembly, ArmToMips64Assembler *parent);
+ virtual ~MIPS64Assembler();
+
+ virtual void reset();
+ virtual void disassemble(const char* name);
+
+ void fix_branches();
+
+ // ------------------------------------------------------------------------
+ // MIPS64AssemblerInterface...
+ // ------------------------------------------------------------------------
+
+#if 0
+#pragma mark -
+#pragma mark Arithmetic...
+#endif
+
+ void DADDU(int Rd, int Rs, int Rt);
+ void DADDIU(int Rt, int Rs, int16_t imm);
+ void DSUBU(int Rd, int Rs, int Rt);
+ void DSUBIU(int Rt, int Rs, int16_t imm);
+ virtual void MUL(int Rd, int Rs, int Rt);
+ void MUH(int Rd, int Rs, int Rt);
+
+#if 0
+#pragma mark -
+#pragma mark Logical...
+#endif
+
+ virtual void CLO(int Rd, int Rs);
+ virtual void CLZ(int Rd, int Rs);
+
+#if 0
+#pragma mark -
+#pragma mark Load/store...
+#endif
+
+ void LD(int Rt, int Rbase, int16_t offset);
+ void SD(int Rt, int Rbase, int16_t offset);
+ virtual void LUI(int Rt, int16_t offset);
+
+#if 0
+#pragma mark -
+#pragma mark Branch...
+#endif
+
+ void JR(int Rs);
+
+
+protected:
+ ArmToMips64Assembler *mParent;
+
+ // opcode field of all instructions
+ enum opcode_field {
+ spec_op, regimm_op, j_op, jal_op, // 0x00 - 0x03
+ beq_op, bne_op, pop06_op, pop07_op, // 0x04 - 0x07
+ pop10_op, addiu_op, slti_op, sltiu_op, // 0x08 - 0x0b
+ andi_op, ori_op, xori_op, aui_op, // 0x0c - 0x0f
+ cop0_op, cop1_op, cop2_op, rsrv_opc_0, // 0x10 - 0x13
+ rsrv_opc_1, rsrv_opc_2, pop26_op, pop27_op, // 0x14 - 0x17
+ pop30_op, daddiu_op, rsrv_opc_3, rsrv_opc_4, // 0x18 - 0x1b
+ rsrv_opc_5, daui_op, msa_op, spec3_op, // 0x1c - 0x1f
+ lb_op, lh_op, rsrv_opc_6, lw_op, // 0x20 - 0x23
+ lbu_op, lhu_op, rsrv_opc_7, lwu_op, // 0x24 - 0x27
+ sb_op, sh_op, rsrv_opc_8, sw_op, // 0x28 - 0x2b
+ rsrv_opc_9, rsrv_opc_10, rsrv_opc_11, rsrv_opc_12, // 0x2c - 0x2f
+ rsrv_opc_13, lwc1_op, bc_op, rsrv_opc_14, // 0x2c - 0x2f
+ rsrv_opc_15, ldc1_op, pop66_op, ld_op, // 0x30 - 0x33
+ rsrv_opc_16, swc1_op, balc_op, pcrel_op, // 0x34 - 0x37
+ rsrv_opc_17, sdc1_op, pop76_op, sd_op // 0x38 - 0x3b
+ };
+
+
+ // func field for special opcode
+ enum func_spec_op {
+ sll_fn, rsrv_spec_0, srl_fn, sra_fn,
+ sllv_fn, lsa_fn, srlv_fn, srav_fn,
+ rsrv_spec_1, jalr_fn, rsrv_spec_2, rsrv_spec_3,
+ syscall_fn, break_fn, sdbbp_fn, sync_fn,
+ clz_fn, clo_fn, dclz_fn, dclo_fn,
+ dsllv_fn, dlsa_fn, dsrlv_fn, dsrav_fn,
+ sop30_fn, sop31_fn, sop32_fn, sop33_fn,
+ sop34_fn, sop35_fn, sop36_fn, sop37_fn,
+ add_fn, addu_fn, sub_fn, subu_fn,
+ and_fn, or_fn, xor_fn, nor_fn,
+ rsrv_spec_4, rsrv_spec_5, slt_fn, sltu_fn,
+ dadd_fn, daddu_fn, dsub_fn, dsubu_fn,
+ tge_fn, tgeu_fn, tlt_fn, tltu_fn,
+ teq_fn, seleqz_fn, tne_fn, selnez_fn,
+ dsll_fn, rsrv_spec_6, dsrl_fn, dsra_fn,
+ dsll32_fn, rsrv_spec_7, dsrl32_fn, dsra32_fn
+ };
+
+ // func field for spec3 opcode
+ enum func_spec3_op {
+ ext_fn, dextm_fn, dextu_fn, dext_fn,
+ ins_fn, dinsm_fn, dinsu_fn, dins_fn,
+ cachee_fn = 0x1b, sbe_fn, she_fn, sce_fn, swe_fn,
+ bshfl_fn, prefe_fn = 0x23, dbshfl_fn, cache_fn, sc_fn, scd_fn,
+ lbue_fn, lhue_fn, lbe_fn = 0x2c, lhe_fn, lle_fn, lwe_fn,
+ pref_fn = 0x35, ll_fn, lld_fn, rdhwr_fn = 0x3b
+ };
+
+ // sa field for spec3 opcodes, with BSHFL function
+ enum func_spec3_bshfl {
+ bitswap_fn,
+ wsbh_fn = 0x02,
+ dshd_fn = 0x05,
+ seb_fn = 0x10,
+ seh_fn = 0x18
+ };
+
+ // rt field of regimm opcodes.
+ enum regimm_fn {
+ bltz_fn, bgez_fn,
+ dahi_fn = 0x6,
+ nal_fn = 0x10, bal_fn, bltzall_fn, bgezall_fn,
+ sigrie_fn = 0x17,
+ dati_fn = 0x1e, synci_fn
+ };
+
+ enum muldiv_fn {
+ mul_fn = 0x02, muh_fn
+ };
+
+ enum mips_inst_shifts {
+ OP_SHF = 26,
+ JTARGET_SHF = 0,
+ RS_SHF = 21,
+ RT_SHF = 16,
+ RD_SHF = 11,
+ RE_SHF = 6,
+ SA_SHF = RE_SHF, // synonym
+ IMM_SHF = 0,
+ FUNC_SHF = 0,
+
+ // mask values
+ MSK_16 = 0xffff,
+
+
+ CACHEOP_SHF = 18,
+ CACHESEL_SHF = 16,
+ };
+};
+
+
+}; // namespace android
+
+#endif //ANDROID_MIPS64ASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp
new file mode 100644
index 0000000..7de8cc1
--- /dev/null
+++ b/libpixelflinger/codeflinger/MIPSAssembler.cpp
@@ -0,0 +1,1955 @@
+/* libs/pixelflinger/codeflinger/MIPSAssembler.cpp
+**
+** Copyright 2012, The Android Open Source 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.
+*/
+
+
+/* MIPS assembler and ARM->MIPS assembly translator
+**
+** The approach is to leave the GGLAssembler and associated files largely
+** un-changed, still utilizing all Arm instruction generation. Via the
+** ArmToMipsAssembler (subclassed from ArmAssemblerInterface) each Arm
+** instruction is translated to one or more Mips instructions as necessary. This
+** is clearly less efficient than a direct implementation within the
+** GGLAssembler, but is far cleaner, more maintainable, and has yielded very
+** significant performance gains on Mips compared to the generic pixel pipeline.
+**
+**
+** GGLAssembler changes
+**
+** - The register allocator has been modified to re-map Arm registers 0-15 to mips
+** registers 2-17. Mips register 0 cannot be used as general-purpose register,
+** and register 1 has traditional uses as a short-term temporary.
+**
+** - Added some early bailouts for OUT_OF_REGISTERS in texturing.cpp and
+** GGLAssembler.cpp, since this is not fatal, and can be retried at lower
+** optimization level.
+**
+**
+** ARMAssembler and ARMAssemblerInterface changes
+**
+** Refactored ARM address-mode static functions (imm(), reg_imm(), imm12_pre(), etc.)
+** to virtual, so they can be overridden in MIPSAssembler. The implementation of these
+** functions on ARM is moved from ARMAssemblerInterface.cpp to ARMAssembler.cpp, and
+** is unchanged from the original. (This required duplicating 2 of these as static
+** functions in ARMAssemblerInterface.cpp so they could be used as static initializers).
+*/
+
+#define LOG_TAG "MIPSAssembler"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <cutils/properties.h>
+#include <log/log.h>
+#include <private/pixelflinger/ggl_context.h>
+
+#include "CodeCache.h"
+#include "MIPSAssembler.h"
+#include "mips_disassem.h"
+
+#define __unused __attribute__((__unused__))
+
+// Choose MIPS arch variant following gcc flags
+#if defined(__mips__) && __mips==32 && __mips_isa_rev>=2
+#define mips32r2 1
+#else
+#define mips32r2 0
+#endif
+
+
+#define NOT_IMPLEMENTED() LOG_ALWAYS_FATAL("Arm instruction %s not yet implemented\n", __func__)
+
+
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark ArmToMipsAssembler...
+#endif
+
+ArmToMipsAssembler::ArmToMipsAssembler(const sp<Assembly>& assembly,
+ char *abuf, int linesz, int instr_count)
+ : ARMAssemblerInterface(),
+ mArmDisassemblyBuffer(abuf),
+ mArmLineLength(linesz),
+ mArmInstrCount(instr_count),
+ mInum(0),
+ mAssembly(assembly)
+{
+ mMips = new MIPSAssembler(assembly, this);
+ mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *));
+ init_conditional_labels();
+}
+
+ArmToMipsAssembler::~ArmToMipsAssembler()
+{
+ delete mMips;
+ free((void *) mArmPC);
+}
+
+uint32_t* ArmToMipsAssembler::pc() const
+{
+ return mMips->pc();
+}
+
+uint32_t* ArmToMipsAssembler::base() const
+{
+ return mMips->base();
+}
+
+void ArmToMipsAssembler::reset()
+{
+ cond.labelnum = 0;
+ mInum = 0;
+ mMips->reset();
+}
+
+int ArmToMipsAssembler::getCodegenArch()
+{
+ return CODEGEN_ARCH_MIPS;
+}
+
+void ArmToMipsAssembler::comment(const char* string)
+{
+ mMips->comment(string);
+}
+
+void ArmToMipsAssembler::label(const char* theLabel)
+{
+ mMips->label(theLabel);
+}
+
+void ArmToMipsAssembler::disassemble(const char* name)
+{
+ mMips->disassemble(name);
+}
+
+void ArmToMipsAssembler::init_conditional_labels()
+{
+ int i;
+ for (i=0;i<99; ++i) {
+ sprintf(cond.label[i], "cond_%d", i);
+ }
+}
+
+
+
+#if 0
+#pragma mark -
+#pragma mark Prolog/Epilog & Generate...
+#endif
+
+void ArmToMipsAssembler::prolog()
+{
+ mArmPC[mInum++] = pc(); // save starting PC for this instr
+
+ mMips->ADDIU(R_sp, R_sp, -(5 * 4));
+ mMips->SW(R_s0, R_sp, 0);
+ mMips->SW(R_s1, R_sp, 4);
+ mMips->SW(R_s2, R_sp, 8);
+ mMips->SW(R_s3, R_sp, 12);
+ mMips->SW(R_s4, R_sp, 16);
+ mMips->MOVE(R_v0, R_a0); // move context * passed in a0 to v0 (arm r0)
+}
+
+void ArmToMipsAssembler::epi