⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ft_build.c

📁 嵌入式试验箱S3C2410的bootloader源代码
💻 C
字号:
/* * OF flat tree builder * Written by: Pantelis Antoniou <pantelis.antoniou@gmail.com> * Updated by: Matthew McClintock <msm@freescale.com> * * 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; either version 2 of * the License, or (at your option) any later version. * * 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., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */#include <common.h>#include <malloc.h>#include <environment.h>#ifdef CONFIG_OF_FLAT_TREE#include <asm/errno.h>#include <stddef.h>#include <ft_build.h>#undef DEBUG/* align addr on a size boundary - adjust address up if needed -- Cort */#define _ALIGN(addr,size)       (((addr)+(size)-1)&(~((size)-1)))#ifndef CONFIG_OF_BOOT_CPU#define CONFIG_OF_BOOT_CPU 0#endif#define SIZE_OF_RSVMAP_ENTRY (2*sizeof(u64))static void ft_put_word(struct ft_cxt *cxt, u32 v){	memmove(cxt->p + sizeof(u32), cxt->p, cxt->p_end - cxt->p);	*(u32 *) cxt->p = cpu_to_be32(v);	cxt->p += sizeof(u32);	cxt->p_end += sizeof(u32);}static inline void ft_put_bin(struct ft_cxt *cxt, const void *data, int sz){	int aligned_size = ((u8 *)_ALIGN((unsigned long)cxt->p + sz,					sizeof(u32))) - cxt->p;	memmove(cxt->p + aligned_size, cxt->p, cxt->p_end - cxt->p);	/* make sure the last bytes are zeroed */	memset(cxt->p + aligned_size - (aligned_size % sizeof(u32)), 0,			(aligned_size % sizeof(u32)));	memcpy(cxt->p, data, sz);	cxt->p += aligned_size;	cxt->p_end += aligned_size;}void ft_begin_node(struct ft_cxt *cxt, const char *name){	ft_put_word(cxt, OF_DT_BEGIN_NODE);	ft_put_bin(cxt, name, strlen(name) + 1);}void ft_end_node(struct ft_cxt *cxt){	ft_put_word(cxt, OF_DT_END_NODE);}void ft_nop(struct ft_cxt *cxt){	ft_put_word(cxt, OF_DT_NOP);}static int lookup_string(struct ft_cxt *cxt, const char *name){	u8 *p;	p = cxt->p;	while (p < cxt->p_end) {		if (strcmp((char *)p, name) == 0)			return p - cxt->p;		p += strlen((char *)p) + 1;	}	return -1;}void ft_prop(struct ft_cxt *cxt, const char *name, const void *data, int sz){	int off = 0;	off = lookup_string(cxt, name);	if (off == -1) {		memcpy(cxt->p_end, name, strlen(name) + 1);		off = cxt->p_end - cxt->p;		cxt->p_end += strlen(name) + 1;	}	/* now put offset from beginning of *STRUCTURE* */	/* will be fixed up at the end */	ft_put_word(cxt, OF_DT_PROP);	ft_put_word(cxt, sz);	ft_put_word(cxt, off);	ft_put_bin(cxt, data, sz);}void ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str){	ft_prop(cxt, name, str, strlen(str) + 1);}void ft_prop_int(struct ft_cxt *cxt, const char *name, int val){	u32 v = cpu_to_be32((u32) val);	ft_prop(cxt, name, &v, sizeof(u32));}/* pick up and start working on a tree in place */void ft_init_cxt(struct ft_cxt *cxt, void *blob){	struct boot_param_header *bph = blob;	memset(cxt, 0, sizeof(*cxt));	cxt->bph = bph;	bph->boot_cpuid_phys = CONFIG_OF_BOOT_CPU;	/* find beginning and end of reserve map table (zeros in last entry) */	cxt->p_rsvmap = (u8 *)bph + bph->off_mem_rsvmap;	while ( ((uint64_t *)cxt->p_rsvmap)[0] != 0 &&		     ((uint64_t *)cxt->p_rsvmap)[1] != 0 ) {	cxt->p_rsvmap += SIZE_OF_RSVMAP_ENTRY;	}	cxt->p_start = (u8 *)bph + bph->off_dt_struct;	cxt->p_end = (u8 *)bph + bph->totalsize;	cxt->p = (u8 *)bph + bph->off_dt_strings;}/* add a reserver physical area to the rsvmap */void ft_add_rsvmap(struct ft_cxt *cxt, u64 physstart, u64 physend){	memmove(cxt->p_rsvmap + SIZE_OF_RSVMAP_ENTRY, cxt->p_rsvmap,				 cxt->p_end - cxt->p_rsvmap);	((u64 *)cxt->p_rsvmap)[0] = cpu_to_be64(physstart);	((u64 *)cxt->p_rsvmap)[1] = cpu_to_be64(physend);	((u64 *)cxt->p_rsvmap)[2] = 0;	((u64 *)cxt->p_rsvmap)[3] = 0;	cxt->p_rsvmap += SIZE_OF_RSVMAP_ENTRY;	cxt->p_start += SIZE_OF_RSVMAP_ENTRY;	cxt->p += SIZE_OF_RSVMAP_ENTRY;	cxt->p_end += SIZE_OF_RSVMAP_ENTRY;}void ft_end_tree(struct ft_cxt *cxt){	ft_put_word(cxt, OF_DT_END);}/* update the boot param header with correct values */void ft_finalize_tree(struct ft_cxt *cxt) {	struct boot_param_header *bph = cxt->bph;	bph->totalsize = cxt->p_end - (u8 *)bph;	bph->off_dt_struct = cxt->p_start - (u8 *)bph;	bph->off_dt_strings = cxt->p - (u8 *)bph;	bph->dt_strings_size = cxt->p_end - cxt->p;}static inline int isprint(int c){	return c >= 0x20 && c <= 0x7e;}static int is_printable_string(const void *data, int len){	const char *s = data;	const char *ss;	/* zero length is not */	if (len == 0)		return 0;	/* must terminate with zero */	if (s[len - 1] != '\0')		return 0;	ss = s;	while (*s && isprint(*s))		s++;	/* not zero, or not done yet */	if (*s != '\0' || (s + 1 - ss) < len)		return 0;	return 1;}static void print_data(const void *data, int len){	int i;	const u8 *s;	/* no data, don't print */	if (len == 0)		return;	if (is_printable_string(data, len)) {		puts(" = \"");		puts(data);		puts("\"");		return;	}	switch (len) {	case 1:		/* byte */		printf(" = <%02x>", (*(u8 *) data) & 0xff);		break;	case 2:		/* half-word */		printf(" = <%04x>", be16_to_cpu(*(u16 *) data) & 0xffff);		break;	case 4:		/* word */		printf(" = <%x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU);		break;	case 8:		/* double-word */		printf(" = <%qx>", be64_to_cpu(*(uint64_t *) data));		break;	default:		/* anything else... hexdump */		printf(" = [");		for (i = 0, s = data; i < len; i++)			printf("%02x%s", s[i], i < len - 1 ? " " : "");		printf("]");		break;	}}void ft_dump_blob(const void *bphp){	const struct boot_param_header *bph = bphp;	const uint64_t *p_rsvmap = (const uint64_t *)		((const char *)bph + be32_to_cpu(bph->off_mem_rsvmap));	const u32 *p_struct = (const u32 *)		((const char *)bph + be32_to_cpu(bph->off_dt_struct));	const u32 *p_strings = (const u32 *)		((const char *)bph + be32_to_cpu(bph->off_dt_strings));	u32 tag;	const u32 *p;	const char *s, *t;	int depth, sz, shift;	int i;	uint64_t addr, size;	if (be32_to_cpu(bph->magic) != OF_DT_HEADER) {		/* not valid tree */		return;	}	depth = 0;	shift = 4;	for (i = 0;; i++) {		addr = be64_to_cpu(p_rsvmap[i * 2]);		size = be64_to_cpu(p_rsvmap[i * 2 + 1]);		if (addr == 0 && size == 0)			break;		printf("/memreserve/ %qx %qx;\n", addr, size);	}	p = p_struct;	while ((tag = be32_to_cpu(*p++)) != OF_DT_END) {		/* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */		if (tag == OF_DT_BEGIN_NODE) {			s = (const char *)p;			p = (u32 *) _ALIGN((unsigned long)p + strlen(s) + 1, 4);			printf("%*s%s {\n", depth * shift, "", s);			depth++;			continue;		}		if (tag == OF_DT_END_NODE) {			depth--;			printf("%*s};\n", depth * shift, "");			continue;		}		if (tag == OF_DT_NOP) {			printf("%*s[NOP]\n", depth * shift, "");			continue;		}		if (tag != OF_DT_PROP) {			fprintf(stderr, "%*s ** Unknown tag 0x%08x at 0x%x\n",				depth * shift, "", tag, --p);			break;		}		sz = be32_to_cpu(*p++);		s = (const char *)p_strings + be32_to_cpu(*p++);		t = (const char *)p;		p = (const u32 *)_ALIGN((unsigned long)p + sz, 4);		printf("%*s%s", depth * shift, "", s);		print_data(t, sz);		printf(";\n");	}}void ft_backtrack_node(struct ft_cxt *cxt){	int i = 4;	while (be32_to_cpu(*(u32 *) (cxt->p - i)) != OF_DT_END_NODE)		i += 4;	memmove (cxt->p - i, cxt->p, cxt->p_end - cxt->p);	cxt->p_end -= i;	cxt->p -= i;}void *ft_get_prop(void *bphp, const char *propname, int *szp){	struct boot_param_header *bph = bphp;	uint32_t *p_struct =	    (uint32_t *) ((char *)bph + be32_to_cpu(bph->off_dt_struct));	uint32_t *p_strings =	    (uint32_t *) ((char *)bph + be32_to_cpu(bph->off_dt_strings));	uint32_t version = be32_to_cpu(bph->version);	uint32_t tag;	uint32_t *p;	char *s, *t;	char *ss;	int sz;	static char path[256], prop[256];	path[0] = '\0';	p = p_struct;	while ((tag = be32_to_cpu(*p++)) != OF_DT_END) {		if (tag == OF_DT_BEGIN_NODE) {			s = (char *)p;			p = (uint32_t *) _ALIGN((unsigned long)p + strlen(s) +						1, 4);			strcat(path, s);			strcat(path, "/");			continue;		}		if (tag == OF_DT_END_NODE) {			path[strlen(path) - 1] = '\0';			ss = strrchr(path, '/');			if (ss != NULL)				ss[1] = '\0';			continue;		}		if (tag == OF_DT_NOP)			continue;		if (tag != OF_DT_PROP)			break;		sz = be32_to_cpu(*p++);		s = (char *)p_strings + be32_to_cpu(*p++);		if (version < 0x10 && sz >= 8)			p = (uint32_t *) _ALIGN((unsigned long)p, 8);		t = (char *)p;		p = (uint32_t *) _ALIGN((unsigned long)p + sz, 4);		strcpy(prop, path);		strcat(prop, s);		if (strcmp(prop, propname) == 0) {			*szp = sz;			return t;		}	}	return NULL;}/********************************************************************//* Function that returns a character from the environment */extern uchar(*env_get_char) (int);#define BDM(x)	{	.name = #x, .offset = offsetof(bd_t, bi_ ##x ) }#ifdef CONFIG_OF_HAS_BD_Tstatic const struct {	const char *name;	int offset;} bd_map[] = {	BDM(memstart),	BDM(memsize),	BDM(flashstart),	BDM(flashsize),	BDM(flashoffset),	BDM(sramstart),	BDM(sramsize),#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \	|| defined(CONFIG_E500)	BDM(immr_base),#endif#if defined(CONFIG_MPC5xxx)	BDM(mbar_base),#endif#if defined(CONFIG_MPC83XX)	BDM(immrbar),#endif#if defined(CONFIG_MPC8220)	BDM(mbar_base),	BDM(inpfreq),	BDM(pcifreq),	BDM(pevfreq),	BDM(flbfreq),	BDM(vcofreq),#endif	BDM(bootflags),	BDM(ip_addr),	BDM(intfreq),	BDM(busfreq),#ifdef CONFIG_CPM2	BDM(cpmfreq),	BDM(brgfreq),	BDM(sccfreq),	BDM(vco),#endif#if defined(CONFIG_MPC5xxx)	BDM(ipbfreq),	BDM(pcifreq),#endif	BDM(baudrate),};#endifvoid ft_setup(void *blob, bd_t * bd, ulong initrd_start, ulong initrd_end){	u32 *p;	int len;	struct ft_cxt cxt;	ulong clock;#if defined(CONFIG_OF_HAS_UBOOT_ENV)	int k, nxt;#endif#if defined(CONFIG_OF_HAS_BD_T)	u8 *end;#endif#if defined(CONFIG_OF_HAS_UBOOT_ENV) || defined(CONFIG_OF_HAS_BD_T)	int i;	static char tmpenv[256];#endif	/* disable OF tree; booting old kernel */	if (getenv("disable_of") != NULL) {		memcpy(blob, bd, sizeof(*bd));		return;	}#ifdef DEBUG	printf ("recieved oftree\n");	ft_dump_blob(blob);#endif	ft_init_cxt(&cxt, blob);	if (initrd_start && initrd_end)		ft_add_rsvmap(&cxt, initrd_start, initrd_end - initrd_start + 1);	/* back into root */	ft_backtrack_node(&cxt);#ifdef CONFIG_OF_HAS_UBOOT_ENV	ft_begin_node(&cxt, "u-boot-env");	for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) {		char *s, *lval, *rval;		for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) ;		s = tmpenv;		for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k)			*s++ = env_get_char(k);		*s++ = '\0';		lval = tmpenv;		s = strchr(tmpenv, '=');		if (s != NULL) {			*s++ = '\0';			rval = s;		} else			continue;		ft_prop_str(&cxt, lval, rval);	}	ft_end_node(&cxt);#endif	ft_begin_node(&cxt, "chosen");	ft_prop_str(&cxt, "name", "chosen");	ft_prop_str(&cxt, "bootargs", getenv("bootargs"));	ft_prop_int(&cxt, "linux,platform", 0x600);	/* what is this? */	if (initrd_start && initrd_end) {		ft_prop_int(&cxt, "linux,initrd-start", initrd_start);		ft_prop_int(&cxt, "linux,initrd-end", initrd_end);	}#ifdef OF_STDOUT_PATH	ft_prop_str(&cxt, "linux,stdout-path", OF_STDOUT_PATH);#endif	ft_end_node(&cxt);	ft_end_node(&cxt);	/* end root */	ft_end_tree(&cxt);	ft_finalize_tree(&cxt);#ifdef CONFIG_OF_HAS_BD_T	/* paste the bd_t at the end of the flat tree */	end = (char *)blob +	    be32_to_cpu(((struct boot_param_header *)blob)->totalsize);	memcpy(end, bd, sizeof(*bd));#endif#ifdef CONFIG_PPC#ifdef CONFIG_OF_HAS_BD_T	for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) {		uint32_t v;		sprintf(tmpenv, "/bd_t/%s", bd_map[i].name);		v = *(uint32_t *)((char *)bd + bd_map[i].offset);		p = ft_get_prop(blob, tmpenv, &len);		if (p != NULL)			*p = cpu_to_be32(v);	}	p = ft_get_prop(blob, "/bd_t/enetaddr", &len);	if (p != NULL)		memcpy(p, bd->bi_enetaddr, 6);	p = ft_get_prop(blob, "/bd_t/ethspeed", &len);	if (p != NULL)		*p = cpu_to_be32((uint32_t) bd->bi_ethspeed);#endif	clock = bd->bi_intfreq;	p = ft_get_prop(blob, "/cpus/" OF_CPU "/clock-frequency", &len);	if (p != NULL)		*p = cpu_to_be32(clock);#ifdef OF_TBCLK	clock = OF_TBCLK;	p = ft_get_prop(blob, "/cpus/" OF_CPU "/timebase-frequency", &len);	if (p != NULL)		*p = cpu_to_be32(clock);#endif#endif				/* __powerpc__ */#ifdef CONFIG_OF_BOARD_SETUP	ft_board_setup(blob, bd);#endif	/* in case the size changed in the platform code */	ft_finalize_tree(&cxt);#ifdef DEBUG	printf("final OF-tree\n");	ft_dump_blob(blob);#endif}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -