| /* |
| * Copyright (C) 2021 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 "libxbc.h" |
| |
| #define BOOTCONFIG_MAGIC "#BOOTCONFIG\n" |
| #define BOOTCONFIG_MAGIC_SIZE 12 |
| #define BOOTCONFIG_SIZE_SIZE 4 |
| #define BOOTCONFIG_CHECKSUM_SIZE 4 |
| #define BOOTCONFIG_TRAILER_SIZE BOOTCONFIG_MAGIC_SIZE + \ |
| BOOTCONFIG_SIZE_SIZE + \ |
| BOOTCONFIG_CHECKSUM_SIZE |
| /* |
| * Simple checksum for a buffer. |
| * |
| * @param addr pointer to the start of the buffer. |
| * @param size size of the buffer in bytes. |
| * @return check sum result. |
| */ |
| static uint32_t checksum(const unsigned char* const buffer, uint32_t size) { |
| uint32_t sum = 0; |
| for (uint32_t i = 0; i < size; i++) { |
| sum += buffer[i]; |
| } |
| return sum; |
| } |
| |
| /* |
| * Check if the bootconfig trailer is present within the bootconfig section. |
| * |
| * @param bootconfig_end_addr address of the end of the bootconfig section. If |
| * the trailer is present, it will be directly preceding this address. |
| * @return true if the trailer is present, false if not. |
| */ |
| static bool isTrailerPresent(uint64_t bootconfig_end_addr) { |
| return !strncmp((char*)(bootconfig_end_addr - BOOTCONFIG_MAGIC_SIZE), |
| BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_SIZE); |
| } |
| |
| /* |
| * Add a string of boot config parameters to memory appended by the trailer. |
| */ |
| int32_t addBootConfigParameters(const char* params, uint32_t params_size, |
| uint64_t bootconfig_start_addr, uint32_t bootconfig_size) { |
| if (!params || !bootconfig_start_addr) { |
| return -1; |
| } |
| if (params_size == 0) { |
| return 0; |
| } |
| int32_t applied_bytes = 0; |
| int32_t new_size = 0; |
| uint64_t end = bootconfig_start_addr + bootconfig_size; |
| |
| if (isTrailerPresent(end)) { |
| end -= BOOTCONFIG_TRAILER_SIZE; |
| applied_bytes -= BOOTCONFIG_TRAILER_SIZE; |
| memcpy(&new_size, (void *)end, BOOTCONFIG_SIZE_SIZE); |
| } else { |
| new_size = bootconfig_size; |
| } |
| |
| // params |
| memcpy((void*)end, params, params_size); |
| |
| applied_bytes += params_size; |
| applied_bytes += addBootConfigTrailer(bootconfig_start_addr, |
| bootconfig_size + applied_bytes); |
| |
| return applied_bytes; |
| } |
| |
| /* |
| * Add boot config trailer. |
| */ |
| int32_t addBootConfigTrailer(uint64_t bootconfig_start_addr, |
| uint32_t bootconfig_size) { |
| if (!bootconfig_start_addr) { |
| return -1; |
| } |
| if (bootconfig_size == 0) { |
| return 0; |
| } |
| uint64_t end = bootconfig_start_addr + bootconfig_size; |
| |
| if (isTrailerPresent(end)) { |
| // no need to overwrite the current trailers |
| return 0; |
| } |
| |
| // size |
| memcpy((void *)(end), &bootconfig_size, BOOTCONFIG_SIZE_SIZE); |
| |
| // checksum |
| uint32_t sum = |
| checksum((unsigned char*)bootconfig_start_addr, bootconfig_size); |
| memcpy((void *)(end + BOOTCONFIG_SIZE_SIZE), &sum, |
| BOOTCONFIG_CHECKSUM_SIZE); |
| |
| // magic |
| memcpy((void *)(end + BOOTCONFIG_SIZE_SIZE + BOOTCONFIG_CHECKSUM_SIZE), |
| BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_SIZE); |
| |
| return BOOTCONFIG_TRAILER_SIZE; |
| } |