cbfs_module.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #include "coreinfo.h" 4 #include "endian.h" 5 6 #if CONFIG(MODULE_CBFS) 7 8 #define FILES_VISIBLE 19 9 10 #define HEADER_MAGIC 0x4F524243 11 #define HEADER_ADDR 0xfffffffc 12 #define LARCHIVE_MAGIC 0x455649484352414cLL /* "LARCHIVE" */ 13 14 #define COMPONENT_DELETED 0x00 15 #define COMPONENT_BOOTBLOCK 0x01 16 #define COMPONENT_CBFSHEADER 0x02 17 #define COMPONENT_STAGE 0x10 18 #define COMPONENT_SELF 0x20 19 #define COMPONENT_FIT 0x21 20 #define COMPONENT_OPTIONROM 0x30 21 #define COMPONENT_RAW 0x50 22 #define COMPONENT_MICROCODE 0x53 23 #define COMPONENT_CMOS_LAYOUT 0x1aa 24 #define COMPONENT_NULL 0xffffffff 25 26 struct cbheader { 27 u32 magic; 28 u32 version; 29 u32 romsize; 30 u32 bootblocksize; 31 u32 align; 32 u32 offset; 33 u32 architecture; 34 u32 pad[]; 35 } __packed; 36 37 struct cbfile { 38 u64 magic; 39 u32 len; 40 u32 type; 41 u32 checksum; 42 u32 offset; 43 char filename[]; 44 } __packed; 45 46 static int filecount = 0, selected = 0, start_row = 0; 47 static char **filenames; 48 static struct cbheader *header = NULL; 49 50 static struct cbfile *getfile(struct cbfile *f) 51 { 52 while (1) { 53 if (f < (struct cbfile *)(0xffffffff - ntohl(header->romsize))) 54 return NULL; 55 if (f->magic == 0) 56 return NULL; 57 if (f->magic == LARCHIVE_MAGIC) 58 return f; 59 f = (struct cbfile *)((u8 *)f + ntohl(header->align)); 60 } 61 } 62 63 static struct cbfile *firstfile(void) 64 { 65 return getfile((void *)(0 - ntohl(header->romsize) + 66 ntohl(header->offset))); 67 } 68 69 static struct cbfile *nextfile(struct cbfile *f) 70 { 71 f = (struct cbfile *)((u8 *)f + ALIGN_UP(ntohl(f->len) + ntohl(f->offset), 72 ntohl(header->align))); 73 return getfile(f); 74 } 75 76 static struct cbfile *findfile(const char *filename) 77 { 78 struct cbfile *f; 79 for (f = firstfile(); f; f = nextfile(f)) { 80 if (strcmp(filename, f->filename) == 0) 81 return f; 82 } 83 return NULL; 84 } 85 86 static int cbfs_module_init(void) 87 { 88 struct cbfile *f; 89 int index = 0; 90 91 header = *(void **)HEADER_ADDR; 92 if (header->magic != ntohl(HEADER_MAGIC)) { 93 header = NULL; 94 return 0; 95 } 96 97 for (f = firstfile(); f; f = nextfile(f)) 98 filecount++; 99 100 filenames = malloc(filecount * sizeof(char *)); 101 if (filenames == NULL) 102 return 0; 103 104 for (f = firstfile(); f; f = nextfile(f)) 105 filenames[index++] = strdup((const char *)f->filename); 106 107 return 0; 108 } 109 110 static int cbfs_module_redraw(WINDOW * win) 111 { 112 struct cbfile *f; 113 int i, row, frow; 114 115 print_module_title(win, "CBFS Listing"); 116 117 if (!header) { 118 mvwprintw(win, 11, 61 / 2, "Bad or missing CBFS header"); 119 return 0; 120 } 121 122 /* Draw a line down the middle. */ 123 for (i = 2; i < 21; i++) 124 mvwaddch(win, i, 30, ACS_VLINE); 125 126 /* Draw the names down the left side. */ 127 for (frow = 0; frow < FILES_VISIBLE; frow++) { 128 row = 2 + frow; 129 i = start_row + frow; 130 if (i >= filecount) 131 break; 132 if (i == selected) 133 wattrset(win, COLOR_PAIR(3) | A_BOLD); 134 else 135 wattrset(win, COLOR_PAIR(2)); 136 137 if (strlen(filenames[i]) == 0) { 138 if (findfile(filenames[i])->type == COMPONENT_NULL) 139 mvwprintw(win, row, 1, "<free space>"); 140 else 141 mvwprintw(win, row, 1, "<unnamed>"); 142 } else { 143 mvwprintw(win, row, 1, "%.25s", filenames[i]); 144 } 145 /* show scroll arrows */ 146 if (frow == 0 && start_row > 0) { 147 wattrset(win, COLOR_PAIR(2)); 148 mvwaddch(win, row, 28, ACS_UARROW); 149 } 150 if (frow == FILES_VISIBLE - 1 && i != filecount - 1) { 151 wattrset(win, COLOR_PAIR(2)); 152 mvwaddch(win, row, 28, ACS_DARROW); 153 } 154 } 155 156 f = findfile(filenames[selected]); 157 if (!f) { 158 mvwprintw(win, 11, 32, "ERROR: CBFS component not found"); 159 return 0; 160 } 161 162 wattrset(win, COLOR_PAIR(2)); 163 164 /* Draw the file information */ 165 row = 2; 166 /* mvwprintw(win, row++, 32, "Offset: 0x%x", f->offset); *//* FIXME */ 167 mvwprintw(win, row, 32, "Type: "); 168 switch (ntohl(f->type)) { 169 case COMPONENT_BOOTBLOCK: 170 mvwprintw(win, row++, 38, "bootblock"); 171 break; 172 case COMPONENT_CBFSHEADER: 173 mvwprintw(win, row++, 38, "CBFS header"); 174 break; 175 case COMPONENT_STAGE: 176 mvwprintw(win, row++, 38, "stage"); 177 break; 178 case COMPONENT_SELF: 179 mvwprintw(win, row++, 38, "simple ELF"); 180 break; 181 case COMPONENT_FIT: 182 mvwprintw(win, row++, 38, "FIT"); 183 break; 184 case COMPONENT_OPTIONROM: 185 mvwprintw(win, row++, 38, "optionrom"); 186 break; 187 case COMPONENT_RAW: 188 mvwprintw(win, row++, 38, "raw"); 189 break; 190 case COMPONENT_MICROCODE: 191 mvwprintw(win, row++, 38, "microcode"); 192 break; 193 case COMPONENT_CMOS_LAYOUT: 194 mvwprintw(win, row++, 38, "cmos layout"); 195 break; 196 case COMPONENT_NULL: 197 mvwprintw(win, row++, 38, "free"); 198 break; 199 case COMPONENT_DELETED: 200 mvwprintw(win, row++, 38, "deleted"); 201 break; 202 default: 203 mvwprintw(win, row++, 38, "Unknown (0x%x)", ntohl(f->type)); 204 break; 205 } 206 mvwprintw(win, row++, 32, "Size: %d", ntohl(f->len)); 207 mvwprintw(win, row++, 32, "Checksum: 0x%x", ntohl(f->checksum)); 208 209 return 0; 210 } 211 212 static int cbfs_module_handle(int key) 213 { 214 int ret = 0; 215 216 if (filecount == 0) 217 return 0; 218 219 switch (key) { 220 case KEY_DOWN: 221 if (selected + 1 < filecount) { 222 selected++; 223 if (selected >= start_row + FILES_VISIBLE - 1) 224 start_row = selected - (FILES_VISIBLE - 1); 225 ret = 1; 226 } 227 break; 228 case KEY_UP: 229 if (selected > 0) { 230 selected--; 231 if (selected < start_row) 232 start_row = selected; 233 ret = 1; 234 } 235 break; 236 } 237 238 return ret; 239 } 240 241 struct coreinfo_module cbfs_module = { 242 .name = "CBFS", 243 .init = cbfs_module_init, 244 .redraw = cbfs_module_redraw, 245 .handle = cbfs_module_handle 246 }; 247 248 #else 249 250 struct coreinfo_module cbfs_module = { 251 }; 252 253 #endif