1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "libxbc.h"
18
19 #define BOOTCONFIG_MAGIC "#BOOTCONFIG\n"
20 #define BOOTCONFIG_MAGIC_SIZE 12
21 #define BOOTCONFIG_SIZE_SIZE 4
22 #define BOOTCONFIG_CHECKSUM_SIZE 4
23 #define BOOTCONFIG_TRAILER_SIZE BOOTCONFIG_MAGIC_SIZE + \
24 BOOTCONFIG_SIZE_SIZE + \
25 BOOTCONFIG_CHECKSUM_SIZE
26 /*
27 * Simple checksum for a buffer.
28 *
29 * @param addr pointer to the start of the buffer.
30 * @param size size of the buffer in bytes.
31 * @return check sum result.
32 */
checksum(const unsigned char * const buffer,uint32_t size)33 static uint32_t checksum(const unsigned char* const buffer, uint32_t size) {
34 uint32_t sum = 0;
35 for (uint32_t i = 0; i < size; i++) {
36 sum += buffer[i];
37 }
38 return sum;
39 }
40
41 /*
42 * Check if the bootconfig trailer is present within the bootconfig section.
43 *
44 * @param bootconfig_end_addr address of the end of the bootconfig section. If
45 * the trailer is present, it will be directly preceding this address.
46 * @return true if the trailer is present, false if not.
47 */
isTrailerPresent(uint64_t bootconfig_end_addr)48 static bool isTrailerPresent(uint64_t bootconfig_end_addr) {
49 return !strncmp((char*)(bootconfig_end_addr - BOOTCONFIG_MAGIC_SIZE),
50 BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_SIZE);
51 }
52
53 /*
54 * Add a string of boot config parameters to memory appended by the trailer.
55 */
addBootConfigParameters(char * params,uint32_t params_size,uint64_t bootconfig_start_addr,uint32_t bootconfig_size)56 int32_t addBootConfigParameters(char* params, uint32_t params_size,
57 uint64_t bootconfig_start_addr, uint32_t bootconfig_size) {
58 if (!params || !bootconfig_start_addr) {
59 return -1;
60 }
61 if (params_size == 0) {
62 return 0;
63 }
64 int32_t applied_bytes = 0;
65 int32_t new_size = 0;
66 uint64_t end = bootconfig_start_addr + bootconfig_size;
67
68 if (isTrailerPresent(end)) {
69 end -= BOOTCONFIG_TRAILER_SIZE;
70 applied_bytes -= BOOTCONFIG_TRAILER_SIZE;
71 memcpy(&new_size, (void *)end, BOOTCONFIG_SIZE_SIZE);
72 } else {
73 new_size = bootconfig_size;
74 }
75
76 // params
77 memcpy((void*)end, params, params_size);
78
79 applied_bytes += params_size;
80 applied_bytes += addBootConfigTrailer(bootconfig_start_addr,
81 bootconfig_size + applied_bytes);
82
83 return applied_bytes;
84 }
85
86 /*
87 * Add boot config trailer.
88 */
addBootConfigTrailer(uint64_t bootconfig_start_addr,uint32_t bootconfig_size)89 int32_t addBootConfigTrailer(uint64_t bootconfig_start_addr,
90 uint32_t bootconfig_size) {
91 if (!bootconfig_start_addr) {
92 return -1;
93 }
94 if (bootconfig_size == 0) {
95 return 0;
96 }
97 uint64_t end = bootconfig_start_addr + bootconfig_size;
98
99 if (isTrailerPresent(end)) {
100 // no need to overwrite the current trailers
101 return 0;
102 }
103
104 // size
105 memcpy((void *)(end), &bootconfig_size, BOOTCONFIG_SIZE_SIZE);
106
107 // checksum
108 uint32_t sum =
109 checksum((unsigned char*)bootconfig_start_addr, bootconfig_size);
110 memcpy((void *)(end + BOOTCONFIG_SIZE_SIZE), &sum,
111 BOOTCONFIG_CHECKSUM_SIZE);
112
113 // magic
114 memcpy((void *)(end + BOOTCONFIG_SIZE_SIZE + BOOTCONFIG_CHECKSUM_SIZE),
115 BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_SIZE);
116
117 return BOOTCONFIG_TRAILER_SIZE;
118 }
119