| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Permission is hereby granted, free of charge, to any person |
| * obtaining a copy of this software and associated documentation |
| * files (the "Software"), to deal in the Software without |
| * restriction, including without limitation the rights to use, copy, |
| * modify, merge, publish, distribute, sublicense, and/or sell copies |
| * of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| */ |
| |
| #include <efi.h> |
| #include <efilib.h> |
| |
| #include <libavb_ab/libavb_ab.h> |
| |
| #include "uefi_avb_boot.h" |
| #include "uefi_avb_ops.h" |
| |
| EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, |
| EFI_SYSTEM_TABLE* SystemTable) { |
| AvbOps* ops; |
| AvbABFlowResult ab_result; |
| AvbSlotVerifyData* slot_data; |
| UEFIAvbBootKernelResult boot_result; |
| const char* requested_partitions[] = {"boot", NULL}; |
| bool unlocked = true; |
| char* additional_cmdline = NULL; |
| |
| InitializeLib(ImageHandle, SystemTable); |
| |
| avb_printv("UEFI AVB-based bootloader using libavb version ", |
| avb_version_string(), |
| "\n", |
| NULL); |
| |
| ops = uefi_avb_ops_new(ImageHandle); |
| if (ops == NULL) { |
| avb_fatal("Error allocating AvbOps.\n"); |
| } |
| |
| if (ops->read_is_device_unlocked(ops, &unlocked) != AVB_IO_RESULT_OK) { |
| avb_fatal("Error determining whether device is unlocked.\n"); |
| } |
| avb_printv("read_is_device_unlocked() ops returned that device is ", |
| unlocked ? "UNLOCKED" : "LOCKED", |
| "\n", |
| NULL); |
| |
| ab_result = avb_ab_flow(ops->ab_ops, |
| requested_partitions, |
| unlocked /* allow_verification_error */, |
| &slot_data); |
| avb_printv("avb_ab_flow() returned ", |
| avb_ab_flow_result_to_string(ab_result), |
| "\n", |
| NULL); |
| switch (ab_result) { |
| case AVB_AB_FLOW_RESULT_OK: |
| case AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR: |
| avb_printv("slot_suffix: ", slot_data->ab_suffix, "\n", NULL); |
| avb_printv("cmdline: ", slot_data->cmdline, "\n", NULL); |
| avb_printv( |
| "release string: ", |
| (const char*)((((AvbVBMetaImageHeader*)(slot_data->vbmeta_images[0] |
| .vbmeta_data))) |
| ->release_string), |
| "\n", |
| NULL); |
| /* Pass 'skip_initramfs' since we're not booting into recovery |
| * mode. Also pass the selected slot in androidboot.slot_suffix. |
| */ |
| additional_cmdline = avb_strdupv("skip_initramfs ", |
| "androidboot.slot_suffix=", |
| slot_data->ab_suffix, |
| NULL); |
| if (additional_cmdline == NULL) { |
| avb_fatal("Error allocating additional_cmdline.\n"); |
| } |
| boot_result = |
| uefi_avb_boot_kernel(ImageHandle, slot_data, additional_cmdline); |
| avb_fatalv("uefi_avb_boot_kernel() failed with error ", |
| uefi_avb_boot_kernel_result_to_string(boot_result), |
| "\n", |
| NULL); |
| avb_slot_verify_data_free(slot_data); |
| avb_free(additional_cmdline); |
| break; |
| case AVB_AB_FLOW_RESULT_ERROR_OOM: |
| avb_fatal("OOM error while doing A/B select flow.\n"); |
| break; |
| case AVB_AB_FLOW_RESULT_ERROR_IO: |
| avb_fatal("I/O error while doing A/B select flow.\n"); |
| break; |
| case AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS: |
| avb_fatal("No bootable slots - enter repair mode\n"); |
| break; |
| } |
| uefi_avb_ops_free(ops); |
| |
| return EFI_SUCCESS; |
| } |