Changeset View
Changeset View
Standalone View
Standalone View
sys/contrib/libfdt/fdt_sw.c
Show First 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
#include "libfdt_env.h" | #include "libfdt_env.h" | ||||
#include <fdt.h> | #include <fdt.h> | ||||
#include <libfdt.h> | #include <libfdt.h> | ||||
#include "libfdt_internal.h" | #include "libfdt_internal.h" | ||||
static int fdt_sw_check_header_(void *fdt) | static int fdt_sw_probe_(void *fdt) | ||||
{ | { | ||||
if (fdt_magic(fdt) != FDT_SW_MAGIC) | if (fdt_magic(fdt) == FDT_MAGIC) | ||||
return -FDT_ERR_BADSTATE; | |||||
else if (fdt_magic(fdt) != FDT_SW_MAGIC) | |||||
return -FDT_ERR_BADMAGIC; | return -FDT_ERR_BADMAGIC; | ||||
/* FIXME: should check more details about the header state */ | |||||
return 0; | return 0; | ||||
} | } | ||||
#define FDT_SW_CHECK_HEADER(fdt) \ | #define FDT_SW_PROBE(fdt) \ | ||||
{ \ | { \ | ||||
int err; \ | int err; \ | ||||
if ((err = fdt_sw_check_header_(fdt)) != 0) \ | if ((err = fdt_sw_probe_(fdt)) != 0) \ | ||||
return err; \ | return err; \ | ||||
} | } | ||||
/* 'memrsv' state: Initial state after fdt_create() | |||||
* | |||||
* Allowed functions: | |||||
* fdt_add_reservmap_entry() | |||||
* fdt_finish_reservemap() [moves to 'struct' state] | |||||
*/ | |||||
static int fdt_sw_probe_memrsv_(void *fdt) | |||||
{ | |||||
int err = fdt_sw_probe_(fdt); | |||||
if (err) | |||||
return err; | |||||
if (fdt_off_dt_strings(fdt) != 0) | |||||
return -FDT_ERR_BADSTATE; | |||||
return 0; | |||||
} | |||||
#define FDT_SW_PROBE_MEMRSV(fdt) \ | |||||
{ \ | |||||
int err; \ | |||||
if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \ | |||||
return err; \ | |||||
} | |||||
/* 'struct' state: Enter this state after fdt_finish_reservemap() | |||||
* | |||||
* Allowed functions: | |||||
* fdt_begin_node() | |||||
* fdt_end_node() | |||||
* fdt_property*() | |||||
* fdt_finish() [moves to 'complete' state] | |||||
*/ | |||||
static int fdt_sw_probe_struct_(void *fdt) | |||||
{ | |||||
int err = fdt_sw_probe_(fdt); | |||||
if (err) | |||||
return err; | |||||
if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) | |||||
return -FDT_ERR_BADSTATE; | |||||
return 0; | |||||
} | |||||
#define FDT_SW_PROBE_STRUCT(fdt) \ | |||||
{ \ | |||||
int err; \ | |||||
if ((err = fdt_sw_probe_struct_(fdt)) != 0) \ | |||||
return err; \ | |||||
} | |||||
/* 'complete' state: Enter this state after fdt_finish() | |||||
* | |||||
* Allowed functions: none | |||||
*/ | |||||
static void *fdt_grab_space_(void *fdt, size_t len) | static void *fdt_grab_space_(void *fdt, size_t len) | ||||
{ | { | ||||
int offset = fdt_size_dt_struct(fdt); | int offset = fdt_size_dt_struct(fdt); | ||||
int spaceleft; | int spaceleft; | ||||
spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) | spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) | ||||
- fdt_size_dt_strings(fdt); | - fdt_size_dt_strings(fdt); | ||||
if ((offset + len < offset) || (offset + len > spaceleft)) | if ((offset + len < offset) || (offset + len > spaceleft)) | ||||
return NULL; | return NULL; | ||||
fdt_set_size_dt_struct(fdt, offset + len); | fdt_set_size_dt_struct(fdt, offset + len); | ||||
return fdt_offset_ptr_w_(fdt, offset); | return fdt_offset_ptr_w_(fdt, offset); | ||||
} | } | ||||
int fdt_create(void *buf, int bufsize) | int fdt_create(void *buf, int bufsize) | ||||
{ | { | ||||
const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header), | |||||
sizeof(struct fdt_reserve_entry)); | |||||
void *fdt = buf; | void *fdt = buf; | ||||
if (bufsize < sizeof(struct fdt_header)) | if (bufsize < hdrsize) | ||||
return -FDT_ERR_NOSPACE; | return -FDT_ERR_NOSPACE; | ||||
memset(buf, 0, bufsize); | memset(buf, 0, bufsize); | ||||
fdt_set_magic(fdt, FDT_SW_MAGIC); | fdt_set_magic(fdt, FDT_SW_MAGIC); | ||||
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); | fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); | ||||
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); | fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); | ||||
fdt_set_totalsize(fdt, bufsize); | fdt_set_totalsize(fdt, bufsize); | ||||
fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), | fdt_set_off_mem_rsvmap(fdt, hdrsize); | ||||
sizeof(struct fdt_reserve_entry))); | |||||
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); | fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); | ||||
fdt_set_off_dt_strings(fdt, bufsize); | fdt_set_off_dt_strings(fdt, 0); | ||||
return 0; | return 0; | ||||
} | } | ||||
int fdt_resize(void *fdt, void *buf, int bufsize) | int fdt_resize(void *fdt, void *buf, int bufsize) | ||||
{ | { | ||||
size_t headsize, tailsize; | size_t headsize, tailsize; | ||||
char *oldtail, *newtail; | char *oldtail, *newtail; | ||||
FDT_SW_CHECK_HEADER(fdt); | FDT_SW_PROBE(fdt); | ||||
headsize = fdt_off_dt_struct(fdt); | headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); | ||||
tailsize = fdt_size_dt_strings(fdt); | tailsize = fdt_size_dt_strings(fdt); | ||||
if ((headsize + tailsize) > fdt_totalsize(fdt)) | |||||
return -FDT_ERR_INTERNAL; | |||||
if ((headsize + tailsize) > bufsize) | if ((headsize + tailsize) > bufsize) | ||||
return -FDT_ERR_NOSPACE; | return -FDT_ERR_NOSPACE; | ||||
oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; | oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; | ||||
newtail = (char *)buf + bufsize - tailsize; | newtail = (char *)buf + bufsize - tailsize; | ||||
/* Two cases to avoid clobbering data if the old and new | /* Two cases to avoid clobbering data if the old and new | ||||
* buffers partially overlap */ | * buffers partially overlap */ | ||||
if (buf <= fdt) { | if (buf <= fdt) { | ||||
memmove(buf, fdt, headsize); | memmove(buf, fdt, headsize); | ||||
memmove(newtail, oldtail, tailsize); | memmove(newtail, oldtail, tailsize); | ||||
} else { | } else { | ||||
memmove(newtail, oldtail, tailsize); | memmove(newtail, oldtail, tailsize); | ||||
memmove(buf, fdt, headsize); | memmove(buf, fdt, headsize); | ||||
} | } | ||||
fdt_set_off_dt_strings(buf, bufsize); | |||||
fdt_set_totalsize(buf, bufsize); | fdt_set_totalsize(buf, bufsize); | ||||
if (fdt_off_dt_strings(buf)) | |||||
fdt_set_off_dt_strings(buf, bufsize); | |||||
return 0; | return 0; | ||||
} | } | ||||
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) | int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) | ||||
{ | { | ||||
struct fdt_reserve_entry *re; | struct fdt_reserve_entry *re; | ||||
int offset; | int offset; | ||||
FDT_SW_CHECK_HEADER(fdt); | FDT_SW_PROBE_MEMRSV(fdt); | ||||
if (fdt_size_dt_struct(fdt)) | |||||
return -FDT_ERR_BADSTATE; | |||||
offset = fdt_off_dt_struct(fdt); | offset = fdt_off_dt_struct(fdt); | ||||
if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) | if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) | ||||
return -FDT_ERR_NOSPACE; | return -FDT_ERR_NOSPACE; | ||||
re = (struct fdt_reserve_entry *)((char *)fdt + offset); | re = (struct fdt_reserve_entry *)((char *)fdt + offset); | ||||
re->address = cpu_to_fdt64(addr); | re->address = cpu_to_fdt64(addr); | ||||
re->size = cpu_to_fdt64(size); | re->size = cpu_to_fdt64(size); | ||||
fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); | fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); | ||||
return 0; | return 0; | ||||
} | } | ||||
int fdt_finish_reservemap(void *fdt) | int fdt_finish_reservemap(void *fdt) | ||||
{ | { | ||||
return fdt_add_reservemap_entry(fdt, 0, 0); | int err = fdt_add_reservemap_entry(fdt, 0, 0); | ||||
if (err) | |||||
return err; | |||||
fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt)); | |||||
return 0; | |||||
} | } | ||||
int fdt_begin_node(void *fdt, const char *name) | int fdt_begin_node(void *fdt, const char *name) | ||||
{ | { | ||||
struct fdt_node_header *nh; | struct fdt_node_header *nh; | ||||
int namelen = strlen(name) + 1; | int namelen; | ||||
FDT_SW_CHECK_HEADER(fdt); | FDT_SW_PROBE_STRUCT(fdt); | ||||
namelen = strlen(name) + 1; | |||||
nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); | nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); | ||||
if (! nh) | if (! nh) | ||||
return -FDT_ERR_NOSPACE; | return -FDT_ERR_NOSPACE; | ||||
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); | nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); | ||||
memcpy(nh->name, name, namelen); | memcpy(nh->name, name, namelen); | ||||
return 0; | return 0; | ||||
} | } | ||||
int fdt_end_node(void *fdt) | int fdt_end_node(void *fdt) | ||||
{ | { | ||||
fdt32_t *en; | fdt32_t *en; | ||||
FDT_SW_CHECK_HEADER(fdt); | FDT_SW_PROBE_STRUCT(fdt); | ||||
en = fdt_grab_space_(fdt, FDT_TAGSIZE); | en = fdt_grab_space_(fdt, FDT_TAGSIZE); | ||||
if (! en) | if (! en) | ||||
return -FDT_ERR_NOSPACE; | return -FDT_ERR_NOSPACE; | ||||
*en = cpu_to_fdt32(FDT_END_NODE); | *en = cpu_to_fdt32(FDT_END_NODE); | ||||
return 0; | return 0; | ||||
} | } | ||||
Show All 21 Lines | static int fdt_find_add_string_(void *fdt, const char *s) | ||||
return offset; | return offset; | ||||
} | } | ||||
int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) | int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) | ||||
{ | { | ||||
struct fdt_property *prop; | struct fdt_property *prop; | ||||
int nameoff; | int nameoff; | ||||
FDT_SW_CHECK_HEADER(fdt); | FDT_SW_PROBE_STRUCT(fdt); | ||||
nameoff = fdt_find_add_string_(fdt, name); | nameoff = fdt_find_add_string_(fdt, name); | ||||
if (nameoff == 0) | if (nameoff == 0) | ||||
return -FDT_ERR_NOSPACE; | return -FDT_ERR_NOSPACE; | ||||
prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); | prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); | ||||
if (! prop) | if (! prop) | ||||
return -FDT_ERR_NOSPACE; | return -FDT_ERR_NOSPACE; | ||||
Show All 20 Lines | |||||
int fdt_finish(void *fdt) | int fdt_finish(void *fdt) | ||||
{ | { | ||||
char *p = (char *)fdt; | char *p = (char *)fdt; | ||||
fdt32_t *end; | fdt32_t *end; | ||||
int oldstroffset, newstroffset; | int oldstroffset, newstroffset; | ||||
uint32_t tag; | uint32_t tag; | ||||
int offset, nextoffset; | int offset, nextoffset; | ||||
FDT_SW_CHECK_HEADER(fdt); | FDT_SW_PROBE_STRUCT(fdt); | ||||
/* Add terminator */ | /* Add terminator */ | ||||
end = fdt_grab_space_(fdt, sizeof(*end)); | end = fdt_grab_space_(fdt, sizeof(*end)); | ||||
if (! end) | if (! end) | ||||
return -FDT_ERR_NOSPACE; | return -FDT_ERR_NOSPACE; | ||||
*end = cpu_to_fdt32(FDT_END); | *end = cpu_to_fdt32(FDT_END); | ||||
/* Relocate the string table */ | /* Relocate the string table */ | ||||
Show All 27 Lines |