Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add device tree blob to Linux x86 kernel boot?

My custom development board is based on x86 and one of the electronic component which is connected to it (through SPI mainly) cannot be controlled easily without using the vendor kernel driver (and the vendor won't help if I don't use it). This module requires some configuration parameters that it gets from the device tree. I believe this module is mostly used on ARM platforms where device trees are common.

On x86, the device tree is generally not needed so it is disabled by default during Linux kernel compilation. I changed the configuration in order to enable it, but I cannot find the way to put the device tree BLOB into the boot image. There is only one DTS file for the x86 architecture in the kernel sources but it doesn't seem to be used at all so it doesn't help.

From the kernel documentation, I understand I need to put it in the setup_data field of the x86 real-mode kernel header, but I don't understand how to do that and when (at kernel build time? when building the bootloader?). Am I supposed to hack the arch/x86/boot/header.S file directly?

Right now, I've replaced the module configuration by hard-coded values, but using the device tree would be better.

like image 241
Tey' Avatar asked Feb 15 '16 21:02

Tey'


1 Answers

On x86, the boot loader adds the Device Tree binary data (DTB) to the linked list of setup_data structures before calling the kernel entry point. The DTB can be loaded from a storage device or embedded into the boot loader image.

The following code shows how it's implemented in U-Boot.

http://git.denx.de/?p=u-boot.git;a=blob;f=arch/x86/lib/zimage.c:

static int setup_device_tree(struct setup_header *hdr, const void *fdt_blob)
{
        int bootproto = get_boot_protocol(hdr);
        struct setup_data *sd;
        int size;

        if (bootproto < 0x0209)
                return -ENOTSUPP;

        if (!fdt_blob)
                return 0;

        size = fdt_totalsize(fdt_blob);
        if (size < 0)
                return -EINVAL;

        size += sizeof(struct setup_data);
        sd = (struct setup_data *)malloc(size);
        if (!sd) {
                printf("Not enough memory for DTB setup data\n");
                return -ENOMEM;
        }

        sd->next = hdr->setup_data;
        sd->type = SETUP_DTB;
        sd->len = fdt_totalsize(fdt_blob);
        memcpy(sd->data, fdt_blob, sd->len);
        hdr->setup_data = (unsigned long)sd;

        return 0;
}
like image 167
igorinov Avatar answered Sep 27 '22 19:09

igorinov