[3/5] flattened device tree creation
R Sharada
sharada at in.ibm.com
Thu Apr 14 00:14:03 EST 2005
/*
* fs2dt: creates a flattened device-tree
*
* Copyright (C) 2004,2005 Milton D Miller II, IBM Corporation
*
* This program 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 (version 2 of the License).
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#define MAXPATH 1024 /* max path name length */
#define NAMESPACE 16384 /* max bytes for property names */
#define TREEWORDS 65536 /* max 32 bit words for property values */
#define MEMRESERVE 256 /* max number of reserved memory blocks */
enum {
ERR_NONE,
ERR_USAGE,
ERR_OPENDIR,
ERR_READDIR,
ERR_STAT,
ERR_OPEN,
ERR_READ,
ERR_RESERVE,
};
void err(const char *str, int rc)
{
if (errno)
perror(str);
else
fprintf(stderr, "%s: unrecoverable error\n", str);
exit(rc);
}
typedef unsigned dvt;
struct stat statbuf[1];
char pathname[MAXPATH], *pathstart;
char propnames[NAMESPACE];
dvt dtstruct[TREEWORDS], *dt;
unsigned long long mem_rsrv[2*MEMRESERVE];
void reserve(unsigned long long where, unsigned long long length)
{
unsigned long long *mr;
mr = mem_rsrv;
while(mr[1])
mr += 2;
mr[0] = where;
mr[1] = length;
}
/* look for properties we need to reserve memory space for */
void checkprop(char *name, dvt *data)
{
static unsigned long long base, size, end;
if ((data == NULL) && (base || size || end))
err((void *)data, ERR_RESERVE);
else if (!strcmp(name, "linux,rtas-base"))
base = *data;
else if (!strcmp(name, "linux,initrd-start") ||
!strcmp(name, "linux,tce-base"))
base = *(unsigned long long *) data;
else if (!strcmp(name, "rtas-size") ||
!strcmp(name, "linux,tce-size"))
size = *data;
else if (!strcmp(name, "linux,initrd-end"))
end = *(unsigned long long *) data;
if (size && end)
err(name, ERR_RESERVE);
if (base && size) {
reserve(base, size);
base = size = 0;
}
if (base && end) {
reserve(base, end-base);
base = end = 0;
}
}
/*
* return the property index for a property name, creating a new one
* if needed.
*/
dvt propnum(const char *name)
{
dvt offset = 0;
while(propnames[offset])
if (strcmp(name, propnames+offset))
offset += strlen(propnames+offset)+1;
else
return offset;
strcpy(propnames+offset, name);
return offset;
}
/* put all properties (files) in the property structure */
void putprops(char *fn, DIR *dir)
{
struct dirent *dp;
while ((dp = readdir(dir)) != NULL) {
strcpy(fn, dp->d_name);
if (lstat(pathname, statbuf))
err(pathname, ERR_STAT);
if (S_ISREG(statbuf[0].st_mode)) {
int fd, len = statbuf[0].st_size;
*dt++ = 3;
*dt++ = len;
*dt++ = propnum(fn);
if ((len >= 8) && ((unsigned long)dt & 0x4))
dt++;
fd = open(pathname, O_RDONLY);
if (fd == -1)
err(pathname, ERR_OPEN);
if (read(fd, dt, len) != len)
err(pathname, ERR_READ);
close(fd);
checkprop(fn, dt);
dt += (len + 3)/4;
}
}
fn[0] = '\0';
if (errno)
err(pathname, ERR_READDIR);
checkprop(pathname, NULL);
}
/*
* put a node (directory) in the property structure. first properties
* then children.
*/
void putnode(void)
{
DIR *dir;
char *dn;
struct dirent *dp;
*dt++ = 1;
strcpy((void *)dt, *pathstart ? pathstart : "/");
while(*dt)
dt++;
if (dt[-1] & 0xff)
dt++;
dir = opendir(pathname);
if (!dir)
err(pathname, ERR_OPENDIR);
strcat(pathname, "/");
dn = pathname + strlen(pathname);
putprops(dn, dir);
rewinddir(dir);
while ((dp = readdir(dir)) != NULL) {
strcpy(dn, dp->d_name);
if (!strcmp(dn, ".") || !strcmp(dn, ".."))
continue;
if (lstat(pathname, statbuf))
err(pathname, ERR_STAT);
if (S_ISDIR(statbuf[0].st_mode))
putnode();
}
if (errno)
err(pathname, ERR_READDIR);
*dt++ = 2;
closedir(dir);
dn[-1] = '\0';
}
/* boot block version 2 as defined by the linux kernel */
struct bootblock {
unsigned magic,
totalsize,
off_dt_struct,
off_dt_strings,
off_mem_rsvmap,
version,
last_comp_version,
boot_physid;
} bb[1];
main(int argc, char *argv[], char *envp[])
{
unsigned len;
unsigned long long me;
me = 0x01ff8000;
while (1)
switch(getopt(argc, argv, "c:b:")) {
case -1:
goto opt;
case 'c':
bb->boot_physid = strtoul(optarg, NULL, 0);
break;
case 'b':
me = strtoull(optarg, NULL, 0);
break;
default:
fprintf(stderr,
"usage: fs2dt [-c cpu ] [-b base] dir\n");
err(argv[0], ERR_USAGE);
}
opt:
if (optind < argc)
strcpy(pathname, argv[optind]);
else
strcpy(pathname, ".");
pathstart = pathname + strlen(pathname);
dt = dtstruct;
putnode();
*dt++ = 9;
len = sizeof(bb[0]);
len += 7; len &= ~7;
bb->off_mem_rsvmap = len;
for (len = 1; mem_rsrv[len]; len += 2)
;
len+= 3;
len *= sizeof(mem_rsrv[0]);
bb->off_dt_struct = bb->off_mem_rsvmap + len;
len = dt - dtstruct;
len *= sizeof(dvt);
bb->off_dt_strings = bb->off_dt_struct + len;
len = propnum("");
len += 3; len &= ~3;
bb->totalsize = bb->off_dt_strings + len;
bb->magic = 0xd00dfeed;
bb->version = 2;
bb->last_comp_version = 2;
reserve(me, bb->totalsize);
write(1, bb, bb->off_mem_rsvmap);
write(1, mem_rsrv, bb->off_dt_struct - bb->off_mem_rsvmap);
write(1, dtstruct, bb->off_dt_strings - bb->off_dt_struct);
write(1, propnames, bb->totalsize - bb->off_dt_strings);
exit(ERR_NONE);
}
More information about the Linuxppc64-dev
mailing list