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