Own fdt parsing implementation
This commit is contained in:
parent
470038745c
commit
c6a8472baf
4 changed files with 587 additions and 104 deletions
|
@ -1536,11 +1536,10 @@ module = {
|
||||||
sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c;
|
sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c;
|
||||||
ia64_efi = loader/ia64/efi/linux.c;
|
ia64_efi = loader/ia64/efi/linux.c;
|
||||||
arm = loader/arm/linux.c;
|
arm = loader/arm/linux.c;
|
||||||
|
arm = lib/fdt.c;
|
||||||
common = loader/linux.c;
|
common = loader/linux.c;
|
||||||
common = lib/cmdline.c;
|
common = lib/cmdline.c;
|
||||||
enable = noemu;
|
enable = noemu;
|
||||||
|
|
||||||
fdt_cppflags = '$(CPPFLAGS_LIBFDT)';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module = {
|
module = {
|
||||||
|
|
389
grub-core/lib/fdt.c
Normal file
389
grub-core/lib/fdt.c
Normal file
|
@ -0,0 +1,389 @@
|
||||||
|
/*
|
||||||
|
* GRUB -- GRand Unified Bootloader
|
||||||
|
* Copyright (C) 2013 Free Software Foundation, Inc.
|
||||||
|
*
|
||||||
|
* GRUB is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* GRUB is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <grub/fdt.h>
|
||||||
|
#include <grub/misc.h>
|
||||||
|
#include <grub/mm.h>
|
||||||
|
|
||||||
|
#define FDT_SUPPORTED_VERSION 17
|
||||||
|
|
||||||
|
#define FDT_BEGIN_NODE 0x00000001
|
||||||
|
#define FDT_END_NODE 0x00000002
|
||||||
|
#define FDT_PROP 0x00000003
|
||||||
|
#define FDT_NOP 0x00000004
|
||||||
|
#define FDT_END 0x00000009
|
||||||
|
|
||||||
|
#define struct_end(fdt) \
|
||||||
|
((grub_addr_t) fdt + grub_fdt_get_off_dt_struct(fdt) \
|
||||||
|
+ grub_fdt_get_size_dt_struct(fdt))
|
||||||
|
|
||||||
|
/* Size needed by a node entry: 2 tokens (FDT_BEGIN_NODE and FDT_END_NODE), plus
|
||||||
|
the NULL-terminated string containing the name, plus padding if needed. */
|
||||||
|
#define node_entry_size(node_name) \
|
||||||
|
(2 * sizeof(grub_uint32_t) \
|
||||||
|
+ ALIGN_UP (grub_strlen (name) + 1, sizeof(grub_uint32_t)))
|
||||||
|
|
||||||
|
/* Size needed by a property entry: 1 token (FDT_PROPERTY), plus len and nameoff
|
||||||
|
fields, plus the property value, plus padding if needed. */
|
||||||
|
#define prop_entry_size(prop_len) \
|
||||||
|
(3 * sizeof(grub_uint32_t) + ALIGN_UP(prop_len, sizeof(grub_uint32_t)))
|
||||||
|
|
||||||
|
static grub_uint32_t *get_next_node (const void *fdt, char *node_name)
|
||||||
|
{
|
||||||
|
grub_uint32_t *end = (void *) struct_end (fdt);
|
||||||
|
grub_uint32_t *token;
|
||||||
|
|
||||||
|
if (node_name >= (char *) end)
|
||||||
|
return NULL;
|
||||||
|
while (*node_name)
|
||||||
|
{
|
||||||
|
if (++node_name >= (char *) end)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
token = (grub_uint32_t *) ALIGN_UP ((grub_addr_t) node_name, 4);
|
||||||
|
while (token < end)
|
||||||
|
{
|
||||||
|
switch (grub_be_to_cpu32(*token))
|
||||||
|
{
|
||||||
|
case FDT_BEGIN_NODE:
|
||||||
|
token = get_next_node (fdt, (char *) (token + 1));
|
||||||
|
if (!token)
|
||||||
|
return NULL;
|
||||||
|
break;
|
||||||
|
case FDT_END_NODE:
|
||||||
|
token++;
|
||||||
|
if (token >= end)
|
||||||
|
return NULL;
|
||||||
|
return token;
|
||||||
|
case FDT_PROP:
|
||||||
|
/* Skip property token and following data (len, nameoff and property
|
||||||
|
value). */
|
||||||
|
token += 3 + grub_be_to_cpu32 (*(token + 1));
|
||||||
|
break;
|
||||||
|
case FDT_NOP:
|
||||||
|
token++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_mem_rsvmap_size (const void *fdt)
|
||||||
|
{
|
||||||
|
int size = 0;
|
||||||
|
grub_uint64_t *ptr = (void *) ((grub_addr_t) fdt
|
||||||
|
+ grub_fdt_get_off_mem_rsvmap (fdt));
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
size += 2 * sizeof(*ptr);
|
||||||
|
if (!*ptr && !*(ptr + 1))
|
||||||
|
return size;
|
||||||
|
ptr += 2;
|
||||||
|
} while ((grub_addr_t) ptr <= (grub_addr_t) fdt + grub_fdt_get_totalsize (fdt)
|
||||||
|
- 2 * sizeof(grub_uint64_t));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static grub_uint32_t get_free_space (void *fdt)
|
||||||
|
{
|
||||||
|
int mem_rsvmap_size = get_mem_rsvmap_size (fdt);
|
||||||
|
|
||||||
|
if (mem_rsvmap_size < 0)
|
||||||
|
/* invalid memory reservation block */
|
||||||
|
return 0;
|
||||||
|
return (grub_fdt_get_totalsize (fdt) - sizeof(grub_fdt_header_t)
|
||||||
|
- mem_rsvmap_size - grub_fdt_get_size_dt_strings (fdt)
|
||||||
|
- grub_fdt_get_size_dt_struct (fdt));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_subnode (void *fdt, int parentoffset, const char *name)
|
||||||
|
{
|
||||||
|
grub_uint32_t *begin = (void *) ((grub_addr_t) fdt
|
||||||
|
+ grub_fdt_get_off_dt_struct(fdt)
|
||||||
|
+ parentoffset);
|
||||||
|
grub_uint32_t *end = (void *) struct_end (fdt);
|
||||||
|
unsigned int entry_size = node_entry_size (name);
|
||||||
|
grub_uint32_t *token = begin;
|
||||||
|
|
||||||
|
/* Insert the new subnode just after the properties of the parent node (if
|
||||||
|
any).*/
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (token >= end)
|
||||||
|
return -1;
|
||||||
|
switch (grub_be_to_cpu32(*token))
|
||||||
|
{
|
||||||
|
case FDT_PROP:
|
||||||
|
/* Skip len and nameoff. */
|
||||||
|
token += 2;
|
||||||
|
break;
|
||||||
|
case FDT_BEGIN_NODE:
|
||||||
|
case FDT_END_NODE:
|
||||||
|
goto insert;
|
||||||
|
case FDT_NOP:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* invalid token */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
token++;
|
||||||
|
}
|
||||||
|
insert:
|
||||||
|
grub_memmove (token + entry_size, token,
|
||||||
|
(grub_addr_t) end - (grub_addr_t) token);
|
||||||
|
*token = grub_cpu_to_be32(FDT_BEGIN_NODE);
|
||||||
|
token[entry_size / sizeof(*token) - 2] = 0; /* padding bytes */
|
||||||
|
grub_strcpy((char *) (token + 1), name);
|
||||||
|
token += entry_size / sizeof(*token) - 1;
|
||||||
|
*token = grub_cpu_to_be32(FDT_END_NODE);
|
||||||
|
return ((grub_addr_t) token - (grub_addr_t) fdt
|
||||||
|
- grub_fdt_get_off_dt_struct(fdt));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Rearrange FDT blocks in the canonical order: first the memory reservation
|
||||||
|
block (just after the FDT header), then the structure block and finally the
|
||||||
|
strings block. No free space is left between the first and the second block,
|
||||||
|
while the space between the second and the third block is given by the
|
||||||
|
clearance argument. */
|
||||||
|
static int rearrange_blocks (void *fdt, unsigned int clearance)
|
||||||
|
{
|
||||||
|
grub_uint32_t off_mem_rsvmap = ALIGN_UP(sizeof(grub_fdt_header_t), 8);
|
||||||
|
grub_uint32_t off_dt_struct = off_mem_rsvmap + get_mem_rsvmap_size (fdt);
|
||||||
|
grub_uint32_t off_dt_strings = off_dt_struct
|
||||||
|
+ grub_fdt_get_size_dt_struct (fdt)
|
||||||
|
+ clearance;
|
||||||
|
grub_uint8_t *fdt_ptr = fdt;
|
||||||
|
grub_uint8_t *tmp_fdt;
|
||||||
|
|
||||||
|
if ((grub_fdt_get_off_mem_rsvmap (fdt) == off_mem_rsvmap)
|
||||||
|
&& (grub_fdt_get_off_dt_struct (fdt) == off_dt_struct))
|
||||||
|
{
|
||||||
|
/* No need to allocate memory for a temporary FDT, just move the strings
|
||||||
|
block if needed. */
|
||||||
|
if (grub_fdt_get_off_dt_strings (fdt) != off_dt_strings)
|
||||||
|
grub_memmove(fdt_ptr + off_dt_strings,
|
||||||
|
fdt_ptr + grub_fdt_get_off_dt_strings (fdt),
|
||||||
|
grub_fdt_get_size_dt_strings (fdt));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
tmp_fdt = grub_malloc (grub_fdt_get_totalsize (fdt));
|
||||||
|
if (!tmp_fdt)
|
||||||
|
return -1;
|
||||||
|
grub_memcpy (tmp_fdt + off_mem_rsvmap,
|
||||||
|
fdt_ptr + grub_fdt_get_off_mem_rsvmap (fdt),
|
||||||
|
get_mem_rsvmap_size (fdt));
|
||||||
|
grub_fdt_set_off_mem_rsvmap (fdt, off_mem_rsvmap);
|
||||||
|
grub_memcpy (tmp_fdt + off_dt_struct,
|
||||||
|
fdt_ptr + grub_fdt_get_off_dt_struct (fdt),
|
||||||
|
grub_fdt_get_size_dt_struct (fdt));
|
||||||
|
grub_fdt_set_off_dt_struct (fdt, off_dt_struct);
|
||||||
|
grub_memcpy (tmp_fdt + off_dt_strings,
|
||||||
|
fdt_ptr + grub_fdt_get_off_dt_strings (fdt),
|
||||||
|
grub_fdt_get_size_dt_strings (fdt));
|
||||||
|
grub_fdt_set_off_dt_strings (fdt, off_dt_strings);
|
||||||
|
|
||||||
|
/* Copy reordered blocks back to fdt. */
|
||||||
|
memcpy (fdt_ptr + off_mem_rsvmap, tmp_fdt + off_mem_rsvmap,
|
||||||
|
grub_fdt_get_totalsize (fdt) - off_mem_rsvmap);
|
||||||
|
|
||||||
|
grub_free(tmp_fdt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static grub_uint32_t *find_prop (void *fdt, unsigned int nodeoffset,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
grub_uint32_t *prop = (void *) ((grub_addr_t) fdt
|
||||||
|
+ grub_fdt_get_off_dt_struct (fdt)
|
||||||
|
+ nodeoffset);
|
||||||
|
grub_uint32_t nameoff;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (grub_be_to_cpu32(*prop) == FDT_PROP)
|
||||||
|
{
|
||||||
|
nameoff = grub_be_to_cpu32(*(prop + 2));
|
||||||
|
if ((nameoff + grub_strlen (name) < grub_fdt_get_size_dt_strings (fdt))
|
||||||
|
&& !grub_strcmp (name, (char *) fdt +
|
||||||
|
grub_fdt_get_off_dt_strings (fdt) + nameoff))
|
||||||
|
return prop;
|
||||||
|
prop += prop_entry_size(grub_be_to_cpu32(*prop + 1)) / sizeof (*prop);
|
||||||
|
}
|
||||||
|
else if (grub_be_to_cpu32(*prop) != FDT_NOP)
|
||||||
|
return NULL;
|
||||||
|
prop++;
|
||||||
|
} while ((grub_addr_t) prop < ((grub_addr_t) fdt
|
||||||
|
+ grub_fdt_get_off_dt_struct (fdt)
|
||||||
|
+ grub_fdt_get_size_dt_struct (fdt)));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the FDT header for consistency and adjust the totalsize field to match
|
||||||
|
the size allocated for the FDT; if this function is called before the other
|
||||||
|
functions in this file and returns success, the other functions are
|
||||||
|
guaranteed not to access memory locations outside the allocated memory. */
|
||||||
|
int grub_fdt_check_header (void *fdt, unsigned int size)
|
||||||
|
{
|
||||||
|
if (((grub_addr_t) fdt & 0x7) || (grub_fdt_get_magic (fdt) != FDT_MAGIC)
|
||||||
|
|| (grub_fdt_get_totalsize (fdt) > size)
|
||||||
|
|| (grub_fdt_get_version (fdt) < FDT_SUPPORTED_VERSION)
|
||||||
|
|| (grub_fdt_get_last_comp_version (fdt) > FDT_SUPPORTED_VERSION)
|
||||||
|
|| (grub_fdt_get_off_dt_struct (fdt) & 0x00000003)
|
||||||
|
|| (grub_fdt_get_size_dt_struct (fdt) & 0x00000003)
|
||||||
|
|| (grub_fdt_get_off_dt_struct (fdt) + grub_fdt_get_size_dt_struct (fdt)
|
||||||
|
> grub_fdt_get_totalsize (fdt))
|
||||||
|
|| (grub_fdt_get_off_dt_strings (fdt) + grub_fdt_get_size_dt_strings (fdt)
|
||||||
|
> grub_fdt_get_totalsize (fdt))
|
||||||
|
|| (grub_fdt_get_off_mem_rsvmap (fdt) & 0x00000007)
|
||||||
|
|| (grub_fdt_get_off_mem_rsvmap (fdt)
|
||||||
|
> grub_fdt_get_totalsize (fdt) - 2 * sizeof(grub_uint64_t)))
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find a direct sub-node of a given parent node. */
|
||||||
|
int grub_fdt_find_subnode (const void *fdt, unsigned int parentoffset,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
grub_uint32_t *token, *end;
|
||||||
|
char *node_name;
|
||||||
|
|
||||||
|
if (parentoffset & 0x3)
|
||||||
|
return -1;
|
||||||
|
token = (void *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct(fdt)
|
||||||
|
+ parentoffset);
|
||||||
|
end = (void *) struct_end (fdt);
|
||||||
|
while (token < end)
|
||||||
|
{
|
||||||
|
switch (grub_be_to_cpu32(*token))
|
||||||
|
{
|
||||||
|
case FDT_BEGIN_NODE:
|
||||||
|
node_name = (char *) (token + 1);
|
||||||
|
if (node_name + grub_strlen (name) >= (char *) end)
|
||||||
|
return -1;
|
||||||
|
if (!grub_strcmp (node_name, name))
|
||||||
|
return (int) ((grub_addr_t) token
|
||||||
|
+ ALIGN_UP(grub_strlen (name) + 1, 4)
|
||||||
|
- grub_fdt_get_off_dt_struct (fdt));
|
||||||
|
token = get_next_node (fdt, node_name);
|
||||||
|
if (!token)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case FDT_END_NODE:
|
||||||
|
return -1;
|
||||||
|
case FDT_PROP:
|
||||||
|
/* Skip property token and following data (len, nameoff and property
|
||||||
|
value). */
|
||||||
|
token += 3 + grub_be_to_cpu32 (*(token + 1));
|
||||||
|
break;
|
||||||
|
case FDT_NOP:
|
||||||
|
token++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int grub_fdt_add_subnode (void *fdt, unsigned int parentoffset,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
unsigned int entry_size = node_entry_size(name);
|
||||||
|
|
||||||
|
if ((parentoffset & 0x3) || (get_free_space (fdt) < entry_size))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* The new node entry will increase the size of the structure block: rearrange
|
||||||
|
blocks such that there is sufficient free space between the structure and
|
||||||
|
the strings block, then add the new node entry. */
|
||||||
|
if (rearrange_blocks (fdt, entry_size) < 0)
|
||||||
|
return -1;
|
||||||
|
return add_subnode (fdt, parentoffset, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name,
|
||||||
|
const void *val, grub_uint32_t len)
|
||||||
|
{
|
||||||
|
grub_uint32_t *prop;
|
||||||
|
int prop_name_present = 0;
|
||||||
|
grub_uint32_t nameoff = 0;
|
||||||
|
|
||||||
|
if ((nodeoffset >= grub_fdt_get_size_dt_struct (fdt)) || (nodeoffset & 0x3))
|
||||||
|
return -1;
|
||||||
|
prop = find_prop (fdt, nodeoffset, name);
|
||||||
|
if (prop)
|
||||||
|
{
|
||||||
|
grub_uint32_t prop_len = ALIGN_UP(grub_be_to_cpu32 (*(prop + 1)),
|
||||||
|
sizeof(grub_uint32_t));
|
||||||
|
grub_uint32_t i;
|
||||||
|
|
||||||
|
prop_name_present = 1;
|
||||||
|
for (i = 0; i < prop_len / sizeof(grub_uint32_t); i++)
|
||||||
|
*(prop + 3 + i) = grub_cpu_to_be32 (FDT_NOP);
|
||||||
|
if (len > prop_len)
|
||||||
|
{
|
||||||
|
/* Length of new property value is greater than the space allocated
|
||||||
|
for the current value: a new entry needs to be created, so save the
|
||||||
|
nameoff field of the current entry and replace the current entry
|
||||||
|
with NOP tokens. */
|
||||||
|
nameoff = grub_be_to_cpu32 (*(prop + 2));
|
||||||
|
*prop = *(prop + 1) = *(prop + 2) = grub_cpu_to_be32 (FDT_NOP);
|
||||||
|
prop = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!prop || !prop_name_present) {
|
||||||
|
unsigned int needed_space = 0;
|
||||||
|
|
||||||
|
if (!prop)
|
||||||
|
needed_space = prop_entry_size(len);
|
||||||
|
if (!prop_name_present)
|
||||||
|
needed_space += grub_strlen (name) + 1;
|
||||||
|
if (needed_space > get_free_space (fdt))
|
||||||
|
return -1;
|
||||||
|
if (rearrange_blocks (fdt, !prop ? prop_entry_size(len) : 0) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!prop_name_present) {
|
||||||
|
/* Append the property name at the end of the strings block. */
|
||||||
|
nameoff = grub_fdt_get_size_dt_strings (fdt);
|
||||||
|
grub_strcpy ((char *) fdt + grub_fdt_get_off_dt_strings (fdt) + nameoff,
|
||||||
|
name);
|
||||||
|
grub_fdt_set_size_dt_strings (fdt, grub_fdt_get_size_dt_strings (fdt)
|
||||||
|
+ grub_strlen (name) + 1);
|
||||||
|
}
|
||||||
|
if (!prop) {
|
||||||
|
prop = (void *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct (fdt)
|
||||||
|
+ nodeoffset);
|
||||||
|
grub_memmove (prop + prop_entry_size(len), prop,
|
||||||
|
grub_fdt_get_size_dt_struct (fdt) - nodeoffset);
|
||||||
|
*prop = grub_cpu_to_be32 (FDT_PROP);
|
||||||
|
*(prop + 1) = grub_cpu_to_be32 (len);
|
||||||
|
*(prop + 2) = grub_cpu_to_be32 (nameoff);
|
||||||
|
|
||||||
|
/* Insert padding bytes at the end of the value; if they are not needed,
|
||||||
|
they will be overwritten by the follozing memcpy. */
|
||||||
|
*(prop + prop_entry_size(len) / sizeof(grub_uint32_t) - 1) = 0;
|
||||||
|
|
||||||
|
grub_memcpy (prop + 3, val, len);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <grub/dl.h>
|
#include <grub/dl.h>
|
||||||
|
#include <grub/fdt.h>
|
||||||
#include <grub/file.h>
|
#include <grub/file.h>
|
||||||
#include <grub/loader.h>
|
#include <grub/loader.h>
|
||||||
#include <grub/mm.h>
|
#include <grub/mm.h>
|
||||||
|
@ -27,23 +28,29 @@
|
||||||
#include <grub/cpu/linux.h>
|
#include <grub/cpu/linux.h>
|
||||||
#include <grub/lib/cmdline.h>
|
#include <grub/lib/cmdline.h>
|
||||||
|
|
||||||
#include <libfdt.h>
|
|
||||||
|
|
||||||
GRUB_MOD_LICENSE ("GPLv3+");
|
GRUB_MOD_LICENSE ("GPLv3+");
|
||||||
|
|
||||||
static grub_dl_t my_mod;
|
static grub_dl_t my_mod;
|
||||||
|
|
||||||
static grub_addr_t initrd_start;
|
static grub_addr_t initrd_start;
|
||||||
static grub_size_t initrd_end;
|
static grub_addr_t initrd_end;
|
||||||
|
|
||||||
static grub_addr_t linux_addr;
|
static grub_addr_t linux_addr;
|
||||||
static grub_size_t linux_size;
|
static grub_size_t linux_size;
|
||||||
|
|
||||||
static char *linux_args;
|
static char *linux_args;
|
||||||
|
|
||||||
static grub_addr_t firmware_boot_data;
|
|
||||||
static grub_addr_t boot_data;
|
|
||||||
static grub_uint32_t machine_type;
|
static grub_uint32_t machine_type;
|
||||||
|
static void *fdt_addr;
|
||||||
|
|
||||||
|
#define LINUX_ZIMAGE_OFFSET 0x24
|
||||||
|
#define LINUX_ZIMAGE_MAGIC 0x016f2818
|
||||||
|
|
||||||
|
#define ARM_FDT_MACHINE_TYPE 0xFFFFFFFF
|
||||||
|
|
||||||
|
#define LINUX_PHYS_OFFSET (0x00008000)
|
||||||
|
#define LINUX_INITRD_PHYS_OFFSET (LINUX_PHYS_OFFSET + 0x02000000)
|
||||||
|
#define LINUX_FDT_PHYS_OFFSET (LINUX_INITRD_PHYS_OFFSET - 0x10000)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* linux_prepare_fdt():
|
* linux_prepare_fdt():
|
||||||
|
@ -58,19 +65,20 @@ linux_prepare_fdt (void)
|
||||||
int tmp_size;
|
int tmp_size;
|
||||||
void *tmp_fdt;
|
void *tmp_fdt;
|
||||||
|
|
||||||
tmp_size = fdt_totalsize ((void *) boot_data) + FDT_ADDITIONAL_ENTRIES_SIZE;
|
tmp_size = grub_fdt_get_totalsize (fdt_addr) + 0x100 + grub_strlen (linux_args);
|
||||||
tmp_fdt = grub_malloc (tmp_size);
|
tmp_fdt = grub_malloc (tmp_size);
|
||||||
if (!tmp_fdt)
|
if (!tmp_fdt)
|
||||||
return GRUB_ERR_OUT_OF_MEMORY;
|
return grub_errno;
|
||||||
|
|
||||||
fdt_open_into ((void *) boot_data, tmp_fdt, tmp_size);
|
grub_memcpy (tmp_fdt, fdt_addr, grub_fdt_get_totalsize (fdt_addr));
|
||||||
|
grub_fdt_set_totalsize (tmp_fdt, tmp_size);
|
||||||
|
|
||||||
/* Find or create '/chosen' node */
|
/* Find or create '/chosen' node */
|
||||||
node = fdt_subnode_offset (tmp_fdt, 0, "chosen");
|
node = grub_fdt_find_subnode (tmp_fdt, 0, "chosen");
|
||||||
if (node < 0)
|
if (node < 0)
|
||||||
{
|
{
|
||||||
grub_printf ("No 'chosen' node in FDT - creating.\n");
|
grub_printf ("No 'chosen' node in FDT - creating.\n");
|
||||||
node = fdt_add_subnode (tmp_fdt, 0, "chosen");
|
node = grub_fdt_add_subnode (tmp_fdt, 0, "chosen");
|
||||||
if (node < 0)
|
if (node < 0)
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
@ -78,8 +86,8 @@ linux_prepare_fdt (void)
|
||||||
grub_printf ("linux_args: '%s'\n", linux_args);
|
grub_printf ("linux_args: '%s'\n", linux_args);
|
||||||
|
|
||||||
/* Generate and set command line */
|
/* Generate and set command line */
|
||||||
retval = fdt_setprop (tmp_fdt, node, "bootargs", linux_args,
|
retval = grub_fdt_set_prop (tmp_fdt, node, "bootargs", linux_args,
|
||||||
grub_strlen (linux_args) + 1);
|
grub_strlen (linux_args) + 1);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
|
@ -89,26 +97,22 @@ linux_prepare_fdt (void)
|
||||||
* We're using physical addresses, so even if we have LPAE, we're
|
* We're using physical addresses, so even if we have LPAE, we're
|
||||||
* restricted to a 32-bit address space.
|
* restricted to a 32-bit address space.
|
||||||
*/
|
*/
|
||||||
grub_uint32_t fdt_initrd_start = cpu_to_fdt32 (initrd_start);
|
|
||||||
grub_uint32_t fdt_initrd_end = cpu_to_fdt32 (initrd_end);
|
|
||||||
|
|
||||||
grub_dprintf ("loader", "Initrd @ 0x%08x-0x%08x\n",
|
grub_dprintf ("loader", "Initrd @ 0x%08x-0x%08x\n",
|
||||||
initrd_start, initrd_end);
|
initrd_start, initrd_end);
|
||||||
|
|
||||||
retval = fdt_setprop (tmp_fdt, node, "linux,initrd-start",
|
retval = grub_fdt_set_prop32 (tmp_fdt, node, "linux,initrd-start",
|
||||||
&fdt_initrd_start, sizeof (fdt_initrd_start));
|
initrd_start);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto failure;
|
goto failure;
|
||||||
retval = fdt_setprop (tmp_fdt, node, "linux,initrd-end",
|
retval = grub_fdt_set_prop32 (tmp_fdt, node, "linux,initrd-end",
|
||||||
&fdt_initrd_end, sizeof (fdt_initrd_end));
|
initrd_end);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy updated FDT to its launch location */
|
/* Copy updated FDT to its launch location */
|
||||||
fdt_move (tmp_fdt, (void *) boot_data, fdt_totalsize (tmp_fdt));
|
grub_memcpy (fdt_addr, tmp_fdt, tmp_size);
|
||||||
grub_free (tmp_fdt);
|
grub_free (tmp_fdt);
|
||||||
fdt_pack ((void *) boot_data);
|
|
||||||
|
|
||||||
grub_dprintf ("loader", "FDT updated for Linux boot\n");
|
grub_dprintf ("loader", "FDT updated for Linux boot\n");
|
||||||
|
|
||||||
|
@ -116,52 +120,35 @@ linux_prepare_fdt (void)
|
||||||
|
|
||||||
failure:
|
failure:
|
||||||
grub_free (tmp_fdt);
|
grub_free (tmp_fdt);
|
||||||
return GRUB_ERR_BAD_ARGUMENT;
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unable to prepare FDT");
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
linux_boot (void)
|
linux_boot (void)
|
||||||
{
|
{
|
||||||
kernel_entry_t linuxmain;
|
kernel_entry_t linuxmain;
|
||||||
grub_err_t err = GRUB_ERR_NONE;
|
grub_err_t err;
|
||||||
|
|
||||||
|
if (!fdt_addr && machine_type == ARM_FDT_MACHINE_TYPE)
|
||||||
|
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
|
||||||
|
N_("device tree must be supplied"));
|
||||||
|
|
||||||
grub_arch_sync_caches ((void *) linux_addr, linux_size);
|
grub_arch_sync_caches ((void *) linux_addr, linux_size);
|
||||||
|
|
||||||
grub_dprintf ("loader", "Kernel at: 0x%x\n", linux_addr);
|
grub_dprintf ("loader", "Kernel at: 0x%x\n", linux_addr);
|
||||||
|
|
||||||
if (!boot_data)
|
err = linux_prepare_fdt ();
|
||||||
{
|
if (err)
|
||||||
if (firmware_boot_data)
|
return err;
|
||||||
{
|
grub_dprintf ("loader", "FDT @ 0x%p\n", fdt_addr);
|
||||||
grub_printf ("Using firmware-supplied boot data @ 0x%08x\n",
|
|
||||||
firmware_boot_data);
|
|
||||||
boot_data = firmware_boot_data;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return GRUB_ERR_FILE_NOT_FOUND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
grub_dprintf ("loader", "Boot data at: 0x%x\n", boot_data);
|
|
||||||
|
|
||||||
if (fdt32_to_cpu (*(grub_uint32_t *) (boot_data)) == FDT_MAGIC)
|
|
||||||
{
|
|
||||||
grub_dprintf ("loader", "FDT @ 0x%08x\n", (grub_addr_t) boot_data);
|
|
||||||
if (linux_prepare_fdt () != GRUB_ERR_NONE)
|
|
||||||
{
|
|
||||||
grub_dprintf ("loader", "linux_prepare_fdt() failed\n");
|
|
||||||
return GRUB_ERR_FILE_NOT_FOUND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
grub_dprintf ("loader", "Jumping to Linux...\n");
|
grub_dprintf ("loader", "Jumping to Linux...\n");
|
||||||
|
|
||||||
/* Boot the kernel.
|
/* Boot the kernel.
|
||||||
* Arguments to kernel:
|
* Arguments to kernel:
|
||||||
* r0 - 0
|
* r0 - 0
|
||||||
* r1 - machine type (possibly passed from firmware)
|
* r1 - machine type
|
||||||
* r2 - address of DTB or ATAG list
|
* r2 - address of DTB
|
||||||
*/
|
*/
|
||||||
linuxmain = (kernel_entry_t) linux_addr;
|
linuxmain = (kernel_entry_t) linux_addr;
|
||||||
|
|
||||||
|
@ -171,7 +158,7 @@ linux_boot (void)
|
||||||
return err;
|
return err;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
linuxmain (0, machine_type, (void *) boot_data);
|
linuxmain (0, machine_type, fdt_addr);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -180,21 +167,18 @@ linux_boot (void)
|
||||||
* Only support zImage, so no relocations necessary
|
* Only support zImage, so no relocations necessary
|
||||||
*/
|
*/
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
linux_load (const char *filename)
|
linux_load (const char *filename, grub_file_t file)
|
||||||
{
|
{
|
||||||
grub_file_t file;
|
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
file = grub_file_open (filename);
|
|
||||||
if (!file)
|
|
||||||
return GRUB_ERR_FILE_NOT_FOUND;
|
|
||||||
|
|
||||||
size = grub_file_size (file);
|
size = grub_file_size (file);
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return GRUB_ERR_FILE_READ_ERROR;
|
return grub_error (GRUB_ERR_BAD_OS, "empty kernel");
|
||||||
|
|
||||||
#ifdef GRUB_MACHINE_EFI
|
#ifdef GRUB_MACHINE_EFI
|
||||||
linux_addr = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_PHYS_OFFSET, size);
|
linux_addr = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_PHYS_OFFSET, size);
|
||||||
|
if (!linux_addr)
|
||||||
|
return grub_errno;
|
||||||
#else
|
#else
|
||||||
linux_addr = LINUX_ADDRESS;
|
linux_addr = LINUX_ADDRESS;
|
||||||
#endif
|
#endif
|
||||||
|
@ -203,8 +187,10 @@ linux_load (const char *filename)
|
||||||
|
|
||||||
if (grub_file_read (file, (void *) linux_addr, size) != size)
|
if (grub_file_read (file, (void *) linux_addr, size) != size)
|
||||||
{
|
{
|
||||||
grub_printf ("Kernel read failed!\n");
|
if (!grub_errno)
|
||||||
return GRUB_ERR_FILE_READ_ERROR;
|
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
||||||
|
filename);
|
||||||
|
return grub_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*(grub_uint32_t *) (linux_addr + LINUX_ZIMAGE_OFFSET)
|
if (*(grub_uint32_t *) (linux_addr + LINUX_ZIMAGE_OFFSET)
|
||||||
|
@ -235,7 +221,8 @@ static grub_err_t
|
||||||
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
||||||
int argc, char *argv[])
|
int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int size, retval;
|
int size;
|
||||||
|
grub_err_t err;
|
||||||
grub_file_t file;
|
grub_file_t file;
|
||||||
grub_dl_ref (my_mod);
|
grub_dl_ref (my_mod);
|
||||||
|
|
||||||
|
@ -246,17 +233,20 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
||||||
if (!file)
|
if (!file)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
retval = linux_load (argv[0]);
|
err = linux_load (argv[0], file);
|
||||||
grub_file_close (file);
|
grub_file_close (file);
|
||||||
if (retval != GRUB_ERR_NONE)
|
if (err)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
grub_loader_set (linux_boot, linux_unload, 1);
|
grub_loader_set (linux_boot, linux_unload, 0);
|
||||||
|
|
||||||
size = grub_loader_cmdline_size (argc, argv);
|
size = grub_loader_cmdline_size (argc, argv);
|
||||||
linux_args = grub_malloc (size + sizeof (LINUX_IMAGE));
|
linux_args = grub_malloc (size + sizeof (LINUX_IMAGE));
|
||||||
if (!linux_args)
|
if (!linux_args)
|
||||||
goto fail;
|
{
|
||||||
|
grub_loader_unset();
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create kernel command line. */
|
/* Create kernel command line. */
|
||||||
grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
|
grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
|
||||||
|
@ -288,16 +278,31 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
if (initrd_start)
|
||||||
|
grub_free ((void *) initrd_start);
|
||||||
#ifdef GRUB_MACHINE_EFI
|
#ifdef GRUB_MACHINE_EFI
|
||||||
initrd_start = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_INITRD_PHYS_OFFSET, size);
|
initrd_start = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_INITRD_PHYS_OFFSET, size);
|
||||||
|
|
||||||
|
if (!initrd_start)
|
||||||
|
{
|
||||||
|
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("memory allocation failed"));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
initrd_start = LINUX_INITRD_ADDRESS;
|
initrd_start = LINUX_INITRD_ADDRESS;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
grub_dprintf ("loader", "Loading initrd to 0x%08x\n",
|
grub_dprintf ("loader", "Loading initrd to 0x%08x\n",
|
||||||
(grub_addr_t) initrd_start);
|
(grub_addr_t) initrd_start);
|
||||||
|
|
||||||
if (grub_file_read (file, (void *) initrd_start, size) != size)
|
if (grub_file_read (file, (void *) initrd_start, size) != size)
|
||||||
goto fail;
|
{
|
||||||
|
initrd_start = 0;
|
||||||
|
if (!grub_errno)
|
||||||
|
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
||||||
|
argv[0]);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
initrd_end = initrd_start + size;
|
initrd_end = initrd_start + size;
|
||||||
|
|
||||||
|
@ -309,28 +314,15 @@ fail:
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static grub_err_t
|
||||||
load_dtb (grub_file_t dtb, int size)
|
load_dtb (grub_file_t dtb, int size)
|
||||||
{
|
{
|
||||||
void *fdt;
|
if ((grub_file_read (dtb, fdt_addr, size) != size)
|
||||||
|
|| (grub_fdt_check_header (fdt_addr, size) != 0))
|
||||||
|
return grub_error (GRUB_ERR_BAD_OS, N_("invalid device tree"));
|
||||||
|
|
||||||
fdt = grub_malloc (size);
|
grub_fdt_set_totalsize (fdt_addr, size);
|
||||||
if (!fdt)
|
return GRUB_ERR_NONE;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (grub_file_read (dtb, fdt, size) != size)
|
|
||||||
{
|
|
||||||
grub_free (fdt);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fdt_check_header (fdt) != 0)
|
|
||||||
{
|
|
||||||
grub_free (fdt);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fdt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
|
@ -338,7 +330,6 @@ grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
|
||||||
int argc, char *argv[])
|
int argc, char *argv[])
|
||||||
{
|
{
|
||||||
grub_file_t dtb;
|
grub_file_t dtb;
|
||||||
void *blob;
|
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
if (argc != 1)
|
if (argc != 1)
|
||||||
|
@ -346,25 +337,34 @@ grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
|
||||||
|
|
||||||
dtb = grub_file_open (argv[0]);
|
dtb = grub_file_open (argv[0]);
|
||||||
if (!dtb)
|
if (!dtb)
|
||||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("failed to open file"));
|
goto out;
|
||||||
|
|
||||||
size = grub_file_size (dtb);
|
size = grub_file_size (dtb);
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
goto out;
|
{
|
||||||
|
grub_error (GRUB_ERR_BAD_OS, "empty file");
|
||||||
blob = load_dtb (dtb, size);
|
goto out;
|
||||||
if (!blob)
|
}
|
||||||
return GRUB_ERR_FILE_NOT_FOUND;
|
|
||||||
|
|
||||||
#ifdef GRUB_MACHINE_EFI
|
#ifdef GRUB_MACHINE_EFI
|
||||||
boot_data = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_FDT_PHYS_OFFSET, size);
|
fdt_addr = grub_efi_allocate_loader_memory (LINUX_FDT_PHYS_OFFSET, size);
|
||||||
|
if (!fdt_addr)
|
||||||
|
{
|
||||||
|
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("memory allocation failed"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
boot_data = LINUX_FDT_ADDRESS;
|
fdt_addr = (void *) LINUX_FDT_ADDRESS;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
grub_dprintf ("loader", "Loading device tree to 0x%08x\n",
|
grub_dprintf ("loader", "Loading device tree to 0x%08x\n",
|
||||||
(grub_addr_t) boot_data);
|
(grub_addr_t) fdt_addr);
|
||||||
fdt_move (blob, (void *) boot_data, fdt_totalsize (blob));
|
load_dtb (dtb, size);
|
||||||
grub_free (blob);
|
if (grub_errno != GRUB_ERR_NONE)
|
||||||
|
{
|
||||||
|
fdt_addr = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We've successfully loaded an FDT, so any machine type passed
|
* We've successfully loaded an FDT, so any machine type passed
|
||||||
|
@ -372,8 +372,6 @@ grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
|
||||||
*/
|
*/
|
||||||
machine_type = ARM_FDT_MACHINE_TYPE;
|
machine_type = ARM_FDT_MACHINE_TYPE;
|
||||||
|
|
||||||
return GRUB_ERR_NONE;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
grub_file_close (dtb);
|
grub_file_close (dtb);
|
||||||
|
|
||||||
|
@ -391,9 +389,7 @@ GRUB_MOD_INIT (linux)
|
||||||
cmd_devicetree = grub_register_command ("devicetree", grub_cmd_devicetree,
|
cmd_devicetree = grub_register_command ("devicetree", grub_cmd_devicetree,
|
||||||
0, N_("Load DTB file."));
|
0, N_("Load DTB file."));
|
||||||
my_mod = mod;
|
my_mod = mod;
|
||||||
firmware_boot_data = firmware_get_boot_data ();
|
fdt_addr = (void *) firmware_get_boot_data ();
|
||||||
|
|
||||||
boot_data = (grub_addr_t) NULL;
|
|
||||||
machine_type = firmware_get_machine_type ();
|
machine_type = firmware_get_machine_type ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
99
include/grub/fdt.h
Normal file
99
include/grub/fdt.h
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* GRUB -- GRand Unified Bootloader
|
||||||
|
* Copyright (C) 2013 Free Software Foundation, Inc.
|
||||||
|
*
|
||||||
|
* GRUB is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* GRUB is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GRUB_FDT_HEADER
|
||||||
|
#define GRUB_FDT_HEADER 1
|
||||||
|
|
||||||
|
#include <grub/types.h>
|
||||||
|
|
||||||
|
#define FDT_MAGIC 0xD00DFEED
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
grub_uint32_t magic;
|
||||||
|
grub_uint32_t totalsize;
|
||||||
|
grub_uint32_t off_dt_struct;
|
||||||
|
grub_uint32_t off_dt_strings;
|
||||||
|
grub_uint32_t off_mem_rsvmap;
|
||||||
|
grub_uint32_t version;
|
||||||
|
grub_uint32_t last_comp_version;
|
||||||
|
grub_uint32_t boot_cpuid_phys;
|
||||||
|
grub_uint32_t size_dt_strings;
|
||||||
|
grub_uint32_t size_dt_struct;
|
||||||
|
} grub_fdt_header_t;
|
||||||
|
|
||||||
|
#define grub_fdt_get_header(fdt, field) \
|
||||||
|
grub_be_to_cpu32(((const grub_fdt_header_t *)(fdt))->field)
|
||||||
|
#define grub_fdt_set_header(fdt, field, value) \
|
||||||
|
((grub_fdt_header_t *)(fdt))->field = grub_cpu_to_be32(value)
|
||||||
|
|
||||||
|
#define grub_fdt_get_magic(fdt) \
|
||||||
|
grub_fdt_get_header(fdt, magic)
|
||||||
|
#define grub_fdt_set_magic(fdt, value) \
|
||||||
|
grub_fdt_set_header(fdt, magic, value)
|
||||||
|
#define grub_fdt_get_totalsize(fdt) \
|
||||||
|
grub_fdt_get_header(fdt, totalsize)
|
||||||
|
#define grub_fdt_set_totalsize(fdt, value) \
|
||||||
|
grub_fdt_set_header(fdt, totalsize, value)
|
||||||
|
#define grub_fdt_get_off_dt_struct(fdt) \
|
||||||
|
grub_fdt_get_header(fdt, off_dt_struct)
|
||||||
|
#define grub_fdt_set_off_dt_struct(fdt, value) \
|
||||||
|
grub_fdt_set_header(fdt, off_dt_struct, value)
|
||||||
|
#define grub_fdt_get_off_dt_strings(fdt) \
|
||||||
|
grub_fdt_get_header(fdt, off_dt_strings)
|
||||||
|
#define grub_fdt_set_off_dt_strings(fdt, value) \
|
||||||
|
grub_fdt_set_header(fdt, off_dt_strings, value)
|
||||||
|
#define grub_fdt_get_off_mem_rsvmap(fdt) \
|
||||||
|
grub_fdt_get_header(fdt, off_mem_rsvmap)
|
||||||
|
#define grub_fdt_set_off_mem_rsvmap(fdt, value) \
|
||||||
|
grub_fdt_set_header(fdt, off_mem_rsvmap, value)
|
||||||
|
#define grub_fdt_get_version(fdt) \
|
||||||
|
grub_fdt_get_header(fdt, version)
|
||||||
|
#define grub_fdt_set_version(fdt, value) \
|
||||||
|
grub_fdt_set_header(fdt, version, value)
|
||||||
|
#define grub_fdt_get_last_comp_version(fdt) \
|
||||||
|
grub_fdt_get_header(fdt, last_comp_version)
|
||||||
|
#define grub_fdt_set_last_comp_version(fdt, value) \
|
||||||
|
grub_fdt_set_header(fdt, last_comp_version, value)
|
||||||
|
#define grub_fdt_get_boot_cpuid_phys(fdt) \
|
||||||
|
grub_fdt_get_header(fdt, boot_cpuid_phys)
|
||||||
|
#define grub_fdt_set_boot_cpuid_phys(fdt, value) \
|
||||||
|
grub_fdt_set_header(fdt, boot_cpuid_phys, value)
|
||||||
|
#define grub_fdt_get_size_dt_strings(fdt) \
|
||||||
|
grub_fdt_get_header(fdt, size_dt_strings)
|
||||||
|
#define grub_fdt_set_size_dt_strings(fdt, value) \
|
||||||
|
grub_fdt_set_header(fdt, size_dt_strings, value)
|
||||||
|
#define grub_fdt_get_size_dt_struct(fdt) \
|
||||||
|
grub_fdt_get_header(fdt, size_dt_struct)
|
||||||
|
#define grub_fdt_set_size_dt_struct(fdt, value) \
|
||||||
|
grub_fdt_set_header(fdt, size_dt_struct, value)
|
||||||
|
|
||||||
|
int grub_fdt_check_header (void *fdt, unsigned int size);
|
||||||
|
int grub_fdt_find_subnode (const void *fdt, unsigned int parentoffset,
|
||||||
|
const char *name);
|
||||||
|
int grub_fdt_add_subnode (void *fdt, unsigned int parentoffset,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
|
int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name,
|
||||||
|
const void *val, grub_uint32_t len);
|
||||||
|
#define grub_fdt_set_prop32(fdt, nodeoffset, name, val) \
|
||||||
|
({ \
|
||||||
|
grub_uint32_t _val = grub_cpu_to_be32(val); \
|
||||||
|
grub_fdt_set_prop ((fdt), (nodeoffset), (name), &_val, 4); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif /* ! GRUB_FDT_HEADER */
|
Loading…
Reference in a new issue