18 #include <file/file.h>
19 #include <talloc/talloc.h>
21 static const char *fbdev_name = "fb0";
24 #define ADDRESS_PROP_SIZE 4096
31 struct fb_fix_screeninfo fscreeninfo;
32 struct fb_var_screeninfo vscreeninfo;
35 static int load_dtb(struct offb_ctx *ctx)
41 rc = read_file(ctx, ctx->dtb_name, &buf, &len);
43 warn("error reading %s", ctx->dtb_name);
47 rc = fdt_check_header(buf);
48 if (rc || (int)fdt_totalsize(buf) > len) {
49 warnx("invalid dtb: %s (rc %d)", ctx->dtb_name, rc);
53 len = fdt_totalsize(buf) + ADDRESS_PROP_SIZE;
55 ctx->dtb = talloc_array(ctx, char, len);
57 warn("Failed to allocate space for dtb\n");
60 fdt_open_into(buf, ctx->dtb, len);
65 static int fbdev_sysfs_lookup(struct offb_ctx *ctx)
67 char *path, *linkpath, *nodepath;
69 ssize_t rc __attribute__((unused));
71 path = talloc_asprintf(ctx, "/sys/class/graphics/%s", fbdev_name);
73 warn("Failed to allocate space for sysfs path\n");
77 fd = open(path, O_RDONLY | O_DIRECTORY);
79 warn("Can't open device %s in sysfs", fbdev_name);
83 linkpath = talloc_zero_array(ctx, char, PATH_MAX + 1);
85 warn("Failed to allocate space for link path\n");
89 rc = readlinkat(fd, "device/of_node", linkpath, PATH_MAX);
91 warn("Can't read of_node link for device %s", fbdev_name);
95 /* readlinkat() returns a relative path such as:
97 * ../../../../../../../firmware/devicetree/base/pciex@n/…/vga@0
99 * We only need the path component from the device tree itself; so
100 * strip everything before /firmware/devicetree/base
102 nodepath = strstr(linkpath, "/firmware/devicetree/base/");
104 warnx("Can't resolve device tree link for device %s",
109 nodepath += strlen("/firmware/devicetree/base");
111 node = fdt_path_offset(ctx->dtb, nodepath);
113 warnx("Can't find node %s in device tree: %s",
114 nodepath, fdt_strerror(node));
118 ctx->path = nodepath;
119 ctx->dtb_node = node;
124 static int fbdev_device_query(struct offb_ctx *ctx)
129 path = talloc_asprintf(ctx, "/dev/%s", fbdev_name);
131 warn("Failed to allocate space for device path\n");
135 fd = open(path, O_RDWR);
137 warn("Can't open fb device %s", path);
141 rc = ioctl(fd, FBIOGET_VSCREENINFO, &ctx->vscreeninfo);
143 warn("ioctl(FBIOGET_VSCREENINFO) failed");
147 rc = ioctl(fd, FBIOGET_FSCREENINFO, &ctx->fscreeninfo);
149 warn("ioctl(FBIOGET_FSCREENINFO) failed");
153 fprintf(stderr, "Retrieved framebuffer details:\n");
154 fprintf(stderr, "device %s:\n", fbdev_name);
155 fprintf(stderr, " addr: %lx\n", ctx->fscreeninfo.smem_start);
156 fprintf(stderr, " len: %" PRIu32 "\n", ctx->fscreeninfo.smem_len);
157 fprintf(stderr, " line: %d\n", ctx->fscreeninfo.line_length);
158 fprintf(stderr, " res: %dx%d@%d\n", ctx->vscreeninfo.xres,
159 ctx->vscreeninfo.yres,
160 ctx->vscreeninfo.bits_per_pixel);
169 static char *next_dt_name(struct offb_ctx *ctx, const char **path)
182 c = strchrnul(p, '/');
184 name = talloc_strndup(ctx, p, c - p);
191 static uint64_t of_read_number(const fdt32_t *data, int n)
195 x = fdt32_to_cpu(data[0]);
198 x |= fdt32_to_cpu(data[1]);
203 /* Do a single translation across a PCI bridge. This results in either;
204 * - Translating a 2-cell CPU address into a 3-cell PCI address, or
205 * - Translating a 3-cell PCI address into a 3-cell PCI address with a
208 * To simplify translation we make some assumptions about addresses:
209 * Addresses are either 3 or 2 cells wide
210 * Size is always 2 cells wide
211 * The first cell of a 3 cell address is the PCI memory type
213 static int do_translate(void *fdt, int node,
214 const fdt32_t *ranges, int range_size,
215 uint32_t *addr, uint32_t *size,
216 int *addr_cells, int *size_cells)
218 uint64_t addr_current_base, addr_child_base, addr_size;
219 uint64_t addr_current, offset, new_addr;
220 uint64_t current_pci_flags, child_pci_flags;
221 int i, na, ns, cna, cns, prop_len;
226 type = fdt_getprop(fdt, node, "device_type", NULL);
227 pci = type && (!strcmp(type, "pci") || !strcmp(type, "pciex"));
229 /* We don't translate at vga@0, so we should always see a pci or
230 * pciex device_type */
234 if (range_size == 0) {
235 fprintf(stderr, "Empty ranges property, 1:1 translation\n");
239 /* Number of cells for address and size at current level */
243 /* Number of cells for address and size at child level */
244 prop = fdt_getprop(fdt, node, "#address-cells", &prop_len);
245 cna = prop ? fdt32_to_cpu(*prop) : 2;
246 prop = fdt_getprop(fdt, node, "#size-cells", &prop_len);
247 cns = prop ? fdt32_to_cpu(*prop) : 2;
249 /* We're translating back to a PCI address, so the size should grow */
251 fprintf(stderr, "na > cna, unexpected\n");
255 /* If the current address is a PCI address, its type should match the
256 * type of every subsequent child address */
257 current_pci_flags = na > 2 ? of_read_number(addr, 1) : 0;
258 child_pci_flags = cna > 2 ? of_read_number(ranges, 1) : 0;
259 if (current_pci_flags != 0 && current_pci_flags != child_pci_flags) {
260 fprintf(stderr, "Unexpected change in flags: %" PRIu64 ", %" PRIu64 "\n",
261 current_pci_flags, child_pci_flags);
266 fprintf(stderr, "Unexpected change in #size-cells: %d vs %d\n",
272 * The ranges property is of the form
273 * < upstream addr base > < downstream addr base > < size >
274 * The current address stored in addr is similarly of the form
275 * < current address > < size >
276 * Where either address base and the current address can be a 2-cell
277 * CPU address or a 3-cell PCI address.
279 * For PCI addresses ignore the type flag in the first cell and use the
280 * 64-bit address in the remaining 2 cells.
283 addr_current_base = of_read_number(ranges + cna + 1, na - 1);
284 addr_current = of_read_number(addr + 1, na - 1);
286 addr_current_base = of_read_number(ranges + cna, na);
287 addr_current = of_read_number(addr, na);
290 addr_child_base = of_read_number(ranges + 1, cna - 1);
292 addr_child_base = of_read_number(ranges, cna);
295 * Perform the actual translation. Find the offset of the current
296 * address from the upstream base, and add the offset to the
297 * downstream base to find the new address.
298 * The new address will be cna-cells wide, inheriting child_pci_flags
299 * as the memory type.
301 addr_size = of_read_number(size, ns);
302 offset = addr_current - addr_current_base;
303 new_addr = addr_child_base + offset;
305 memset(addr, 0, *addr_cells);
306 memset(size, 0, *size_cells);
310 /* Update the current address in addr.
311 * It's highly unlikely any translation will leave us with a 2-cell
312 * CPU address, but for completeness only include PCI flags if the
313 * child offset was definitely a PCI address */
315 addr[0] = cpu_to_fdt32(child_pci_flags);
316 for (i = *addr_cells - 1; i >= *addr_cells - 2; i--) {
317 addr[i] = cpu_to_fdt32(new_addr & 0xffffffff);
320 for (i = *size_cells - 1; i >= 0; i--) {
321 size[i] = cpu_to_fdt32(addr_size & 0xffffffff);
325 fprintf(stderr, "New address:\n\t");
326 for (i = 0; i < *addr_cells; i++)
327 fprintf(stderr, " %" PRIu64 " ", of_read_number(&addr[i], 1));
328 fprintf(stderr, "\n");
333 static int create_translated_addresses(struct offb_ctx *ctx,
334 int dev_node, const char *path,
335 uint64_t in_addr, uint64_t in_size,
336 fdt32_t *reg, int reg_cells)
338 uint32_t addr[MAX_N_CELLS], size[MAX_N_CELLS];
339 int addr_cells, size_cells, node, prop_len, ranges_len, rc, i;
340 const fdt32_t *ranges, *prop;
343 prop = fdt_getprop(ctx->dtb, 0, "#address-cells", &prop_len);
344 addr_cells = prop ? fdt32_to_cpu(*prop) : 2;
346 prop = fdt_getprop(ctx->dtb, 0, "#size-cells", &prop_len);
347 size_cells = prop ? fdt32_to_cpu(*prop) : 2;
349 memset(addr, 0, sizeof(uint32_t) * MAX_N_CELLS);
350 for (i = addr_cells - 1; i >= 0; i--) {
351 addr[i] = cpu_to_fdt32(in_addr & 0xffffffff);
354 memset(size, 0, sizeof(uint32_t) * MAX_N_CELLS);
355 for (i = size_cells - 1; i >= 0; i--) {
356 size[i] = cpu_to_fdt32(in_size & 0xffffffff);
362 /* get the name of the next child node to 'node' */
363 name = next_dt_name(ctx, &path);
367 node = fdt_subnode_offset(ctx->dtb, node, name);
370 if (node == dev_node)
373 ranges = fdt_getprop(ctx->dtb, node, "ranges", &ranges_len);
377 rc = do_translate(ctx->dtb, node, ranges, ranges_len,
378 addr, size, &addr_cells, &size_cells);
383 fprintf(stderr, "Final address:\n\t");
384 for (i = 0; i < addr_cells; i++)
385 fprintf(stderr, " %" PRIu64 " ", of_read_number(&addr[i], 1));
386 fprintf(stderr, "\n");
388 if (addr_cells + size_cells > reg_cells) {
389 fprintf(stderr, "Error: na + ns larger than reg\n");
393 memcpy(reg, addr, sizeof(fdt32_t) * addr_cells);
394 memcpy(reg + addr_cells, size, sizeof(fdt32_t) * size_cells);
399 #define fdt_set_check(dtb, node, fn, prop, ...) \
401 int __x = fn(dtb, node, prop, __VA_ARGS__); \
403 warnx("failed to update device tree (%s): %s", \
404 prop, fdt_strerror(__x)); \
409 static int populate_devicetree(struct offb_ctx *ctx)
412 void *dtb = ctx->dtb;
413 int rc, node = ctx->dtb_node;
415 memset(reg, 0, sizeof(reg));
416 rc = create_translated_addresses(ctx, node, ctx->path,
417 ctx->fscreeninfo.smem_start,
418 ctx->fscreeninfo.smem_len,
422 fprintf(stderr, "Failed to translate address\n");
426 fdt_set_check(dtb, node, fdt_setprop_string, "device_type", "display");
428 fdt_set_check(dtb, node, fdt_setprop, "assigned-addresses",
431 fdt_set_check(dtb, node, fdt_setprop_cell,
432 "width", ctx->vscreeninfo.xres);
433 fdt_set_check(dtb, node, fdt_setprop_cell,
434 "height", ctx->vscreeninfo.yres);
435 fdt_set_check(dtb, node, fdt_setprop_cell,
436 "depth", ctx->vscreeninfo.bits_per_pixel);
438 fdt_set_check(dtb, node, fdt_setprop, "little-endian", NULL, 0);
439 fdt_set_check(dtb, node, fdt_setprop, "linux,opened", NULL, 0);
440 fdt_set_check(dtb, node, fdt_setprop, "linux,boot-display", NULL, 0);
446 * Find the device tree path assoicated with a hvc device.
447 * On OPAL all hvc consoles have a 'serial@X' node under ibm,opal/consoles,
448 * so we make a simplifying assumption that a hvcX is associated with a
451 static char *get_hvc_path(struct offb_ctx *ctx, unsigned int termno)
456 serial = talloc_asprintf(ctx, "serial@%u", termno);
460 node = fdt_subnode_offset(ctx->dtb, 0, "ibm,opal");
462 fprintf(stderr, "Couldn't find ibm,opal\n");
465 node = fdt_subnode_offset(ctx->dtb, node, "consoles");
467 fprintf(stderr, "Couldn't find ibm,opal/consoles\n");
471 node = fdt_subnode_offset(ctx->dtb, node, serial);
473 fprintf(stderr, "Could not locate hvc%u\n", termno);
477 return talloc_asprintf(ctx, "/ibm,opal/consoles/%s", serial);
481 * Find the device tree path of the vga device. On OPAL we assume there is only
482 * one of these that represents any 'tty' console.
484 static char *get_vga_path(struct offb_ctx *ctx)
486 char *root, *vga_path;
488 root = strstr(ctx->path, "/pciex@");
490 fprintf(stderr, "Can't find root path for vga device in below:\n");
491 fprintf(stderr, "%s\n", ctx->path);
495 vga_path = talloc_strdup(ctx, root);
496 fprintf(stderr, "VGA target at '%s'\n", vga_path);
501 static int set_stdout(struct offb_ctx *ctx)
503 const char *boot_console, *ptr;
504 long unsigned int termno;
508 boot_console = getenv("boot_console");
510 fprintf(stderr, "boot_console not set, using default stdout for boot\n");
514 if (strncmp(boot_console, "/dev/", strlen("/dev/")) != 0) {
515 /* We already have the full path */
516 stdout_path = talloc_strdup(ctx, boot_console);
517 /* Check for a tty* console but don't accidentally catch
519 } else if (strstr(boot_console, "tty") != NULL &&
520 strstr(boot_console, "ttyS") == NULL) {
521 fprintf(stderr, "TTY recognised: %s\n", boot_console);
522 stdout_path = get_vga_path(ctx);
524 ptr = strstr(boot_console, "hvc");
525 if (!ptr || strlen(ptr) <= strlen("hvc")) {
526 fprintf(stderr, "Unrecognised console: %s\n",
530 ptr += strlen("hvc");
532 termno = strtoul(ptr, NULL, 0);
534 fprintf(stderr, "Couldn't parse termno from %s\n",
538 fprintf(stderr, "HVC recognised: %s\n", boot_console);
539 stdout_path = get_hvc_path(ctx, termno);
543 fprintf(stderr, "Couldn't parse %s into a path\n",
548 fprintf(stderr, "stdout-path: %s\n", stdout_path);
550 node = fdt_subnode_offset(ctx->dtb, 0, "chosen");
552 fprintf(stderr, "Failed to find chosen\n");
557 * linux,stdout-path is deprecated after v3.14 but we don't know
558 * what the next kernel will be, so set both.
560 fdt_set_check(ctx->dtb, node, fdt_setprop_string, "stdout-path",
562 fdt_set_check(ctx->dtb, node, fdt_setprop_string, "linux,stdout-path",
568 static int write_devicetree(struct offb_ctx *ctx)
574 rc = replace_file(ctx->dtb_name, ctx->dtb, fdt_totalsize(ctx->dtb));
576 warn("failed to write file %s", ctx->dtb_name);
581 static int set_offb(struct offb_ctx *ctx)
589 rc = fbdev_sysfs_lookup(ctx);
593 rc = fbdev_device_query(ctx);
597 rc = populate_devicetree(ctx);
607 struct offb_ctx *ctx;
610 ctx = talloc_zero(NULL, struct offb_ctx);
612 ctx->dtb_name = getenv("boot_dtb");
613 if (!ctx->dtb_name) {
619 warn("Failed offb setup step");
623 if (set_stdout(ctx)) {
624 warn("Failed stdout setup step\n");
628 if (write_devicetree(ctx)) {
629 warn("Failed to write back device tree\n");
634 return rc ? EXIT_FAILURE : EXIT_SUCCESS;