Start to allow platforms other than U-Boot to use the FDT code in loader by

moving U-Boot specific code from libfdt.a to a new libuboot_fdt.a. This
needs to be a new library for linking to work correctly.

Differential Revision:	https://reviews.freebsd.org/D1054
Reviewed by:	ian, rpaulo (earlier version)
MFC after:	1 week
This commit is contained in:
Andrew Turner 2014-11-01 17:12:44 +00:00
parent b6fbc510be
commit 8c81befd0b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=273934
8 changed files with 270 additions and 144 deletions

View File

@ -72,6 +72,7 @@ CFLAGS+= -DLOADER_TFTP_SUPPORT
CFLAGS+= -I${.CURDIR}/../../fdt
CFLAGS+= -I${.OBJDIR}/../../fdt
CFLAGS+= -DLOADER_FDT_SUPPORT
LIBUBOOT_FDT= ${.OBJDIR}/../../uboot/fdt/libuboot_fdt.a
LIBFDT= ${.OBJDIR}/../../fdt/libfdt.a
.endif
@ -112,8 +113,8 @@ CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/
# clang doesn't understand %D as a specifier to printf
NO_WERROR.clang=
DPADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBSTAND}
LDADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} -lstand
DPADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} ${LIBSTAND}
LDADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} -lstand
vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version
sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}

View File

@ -11,8 +11,7 @@ SRCS+= fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
# Loader's fdt commands extension sources.
SRCS+= fdt_loader_cmd.c
CFLAGS+= -I${.CURDIR}/../../contrib/libfdt/ -I${.CURDIR}/../common/ \
-I${.CURDIR}/../uboot/lib
CFLAGS+= -I${.CURDIR}/../../contrib/libfdt/ -I${.CURDIR}/../common/
CFLAGS+= -ffreestanding

View File

@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$");
#include "bootstrap.h"
#include "fdt_platform.h"
#include "glue.h"
#ifdef DEBUG
#define debugf(fmt, args...) do { printf("%s(): ", __func__); \
@ -53,9 +52,6 @@ __FBSDID("$FreeBSD$");
#define FDT_PROP_SEP " = "
#define STR(number) #number
#define STRINGIFY(number) STR(number)
#define COPYOUT(s,d,l) archsw.arch_copyout(s, d, l)
#define COPYIN(s,d,l) archsw.arch_copyin(s, d, l)
@ -229,7 +225,7 @@ fdt_load_dtb(vm_offset_t va)
return (0);
}
static int
int
fdt_load_dtb_addr(struct fdt_header *header)
{
int err;
@ -254,7 +250,7 @@ fdt_load_dtb_addr(struct fdt_header *header)
return (0);
}
static int
int
fdt_load_dtb_file(const char * filename)
{
struct preloaded_file *bfp, *oldbfp;
@ -284,9 +280,6 @@ int
fdt_setup_fdtp()
{
struct preloaded_file *bfp;
struct fdt_header *hdr;
const char *s;
char *p;
vm_offset_t va;
debugf("fdt_setup_fdtp()\n");
@ -309,41 +302,8 @@ fdt_setup_fdtp()
}
}
/*
* If the U-boot environment contains a variable giving the address of a
* valid blob in memory, use it. The U-boot README says the right
* variable for fdt data loaded into ram is fdt_addr_r, so try that
* first. Board vendors also use both fdtaddr and fdt_addr names.
*/
s = ub_env_get("fdt_addr_r");
if (s == NULL)
s = ub_env_get("fdtaddr");
if (s == NULL)
s = ub_env_get("fdt_addr");
if (s != NULL && *s != '\0') {
hdr = (struct fdt_header *)strtoul(s, &p, 16);
if (*p == '\0') {
if (fdt_load_dtb_addr(hdr) == 0) {
printf("Using DTB provided by U-Boot at "
"address %p.\n", hdr);
return (0);
}
}
}
/*
* If the U-boot environment contains a variable giving the name of a
* file, use it if we can load and validate it.
*/
s = ub_env_get("fdtfile");
if (s == NULL)
s = ub_env_get("fdt_file");
if (s != NULL && *s != '\0') {
if (fdt_load_dtb_file(s) == 0) {
printf("Loaded DTB from file '%s'.\n", s);
return (0);
}
}
if (fdt_platform_load_dtb() == 0)
return (0);
/* If there is a dtb compiled into the kernel, use it. */
if ((va = fdt_find_static_dtb()) != 0) {
@ -407,48 +367,20 @@ _fdt_strtovect(const char *str, void *cellbuf, int lim, unsigned char cellsize,
return (cnt);
}
#define TMP_MAX_ETH 8
static void
fixup_ethernet(const char *env, char *ethstr, int *eth_no, int len)
void
fdt_fixup_ethernet(const char *str, char *ethstr, int len)
{
const char *str;
char *end;
uint8_t tmp_addr[6];
int i, n;
/* Extract interface number */
i = strtol(env + 3, &end, 10);
if (end == (env + 3))
/* 'ethaddr' means interface 0 address */
n = 0;
else
n = i;
if (n > TMP_MAX_ETH)
return;
str = ub_env_get(env);
/* Convert macaddr string into a vector of uints */
fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t));
if (n != 0) {
i = strlen(env) - 7;
strncpy(ethstr + 8, env + 3, i);
}
/* Set actual property to a value from vect */
fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr),
"local-mac-address", &tmp_addr, 6 * sizeof(uint8_t));
/* Clear ethernet..XXXX.. string */
bzero(ethstr + 8, len - 8);
if (n + 1 > *eth_no)
*eth_no = n + 1;
}
static void
fixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq)
void
fdt_fixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq)
{
int lo, o = 0, o2, maxo = 0, depth;
const uint32_t zero = 0;
@ -527,13 +459,14 @@ fdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells)
return (0);
}
static void
fixup_memory(struct sys_info *si)
void
fdt_fixup_memory(struct fdt_mem_region *region, size_t num)
{
struct mem_region *curmr;
struct fdt_mem_region *curmr;
uint32_t addr_cells, size_cells;
uint32_t *addr_cellsp, *reg, *size_cellsp;
int err, i, len, memory, realmrno, root;
int err, i, len, memory, root;
size_t realmrno;
uint8_t *buf, *sb;
uint64_t rstart, rsize;
int reserved;
@ -591,7 +524,6 @@ fixup_memory(struct sys_info *si)
bzero(buf, len);
for (i = 0; i < reserved; i++) {
curmr = &si->mr[i];
if (fdt_get_mem_rsv(fdtp, i, &rstart, &rsize))
break;
if (rsize) {
@ -623,9 +555,9 @@ fixup_memory(struct sys_info *si)
}
/* Count valid memory regions entries in sysinfo. */
realmrno = si->mr_no;
for (i = 0; i < si->mr_no; i++)
if (si->mr[i].start == 0 && si->mr[i].size == 0)
realmrno = num;
for (i = 0; i < num; i++)
if (region[i].start == 0 && region[i].size == 0)
realmrno--;
if (realmrno == 0) {
@ -652,8 +584,8 @@ fixup_memory(struct sys_info *si)
bzero(buf, len);
for (i = 0; i < si->mr_no; i++) {
curmr = &si->mr[i];
for (i = 0; i < num; i++) {
curmr = &region[i];
if (curmr->size != 0) {
/* Ensure endianess, and put cells into a buffer */
if (addr_cells == 2)
@ -682,17 +614,15 @@ fixup_memory(struct sys_info *si)
free(sb);
}
static void
fixup_stdout(const char *env)
void
fdt_fixup_stdout(const char *str)
{
const char *str;
char *ptr;
int serialno;
int len, no, sero;
const struct fdt_property *prop;
char *tmp[10];
str = ub_env_get(env);
ptr = (char *)str + strlen(str) - 1;
while (ptr > str && isdigit(*(str - 1)))
str--;
@ -738,14 +668,8 @@ fixup_stdout(const char *env)
static int
fdt_fixup(void)
{
const char *env;
char *ethstr;
int chosen, eth_no, len;
struct sys_info *si;
int chosen, len;
env = NULL;
eth_no = 0;
ethstr = NULL;
len = 0;
debugf("fdt_fixup()\n");
@ -762,45 +686,7 @@ fdt_fixup(void)
if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL))
return (1);
/* Acquire sys_info */
si = ub_get_sys_info();
while ((env = ub_env_enum(env)) != NULL) {
if (strncmp(env, "eth", 3) == 0 &&
strncmp(env + (strlen(env) - 4), "addr", 4) == 0) {
/*
* Handle Ethernet addrs: parse uboot env eth%daddr
*/
if (!eth_no) {
/*
* Check how many chars we will need to store
* maximal eth iface number.
*/
len = strlen(STRINGIFY(TMP_MAX_ETH)) +
strlen("ethernet");
/*
* Reserve mem for string "ethernet" and len
* chars for iface no.
*/
ethstr = (char *)malloc(len * sizeof(char));
bzero(ethstr, len * sizeof(char));
strcpy(ethstr, "ethernet0");
}
/* Modify blob */
fixup_ethernet(env, ethstr, &eth_no, len);
} else if (strcmp(env, "consoledev") == 0)
fixup_stdout(env);
}
/* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */
fixup_cpubusfreqs(si->clk_cpu, si->clk_bus);
/* Fixup memory regions */
fixup_memory(si);
fdt_platform_fixups();
fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0);
return (1);

View File

@ -29,7 +29,26 @@
#ifndef FDT_PLATFORM_H
#define FDT_PLATFORM_H
extern int fdt_copy(vm_offset_t);
extern int fdt_setup_fdtp(void);
struct fdt_header;
struct fdt_mem_region {
unsigned long start;
unsigned long size;
};
#define TMP_MAX_ETH 8
int fdt_copy(vm_offset_t);
void fdt_fixup_cpubusfreqs(unsigned long, unsigned long);
void fdt_fixup_ethernet(const char *, char *, int);
void fdt_fixup_memory(struct fdt_mem_region *, size_t);
void fdt_fixup_stdout(const char *);
int fdt_load_dtb_addr(struct fdt_header *);
int fdt_load_dtb_file(const char *);
int fdt_setup_fdtp(void);
/* The platform library needs to implement these functions */
int fdt_platform_load_dtb(void);
void fdt_platform_fixups(void);
#endif /* FDT_PLATFORM_H */

View File

@ -62,6 +62,7 @@ CFLAGS+= -DLOADER_TFTP_SUPPORT
CFLAGS+= -I${.CURDIR}/../../fdt
CFLAGS+= -I${.OBJDIR}/../../fdt
CFLAGS+= -DLOADER_FDT_SUPPORT
LIBUBOOT_FDT= ${.OBJDIR}/../../uboot/fdt/libuboot_fdt.a
LIBFDT= ${.OBJDIR}/../../fdt/libfdt.a
.endif
@ -98,8 +99,8 @@ CFLAGS+= -I${.OBJDIR}/../../uboot/lib
LIBSTAND= ${.OBJDIR}/../../libstand32/libstand.a
CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/
DPADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBSTAND}
LDADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBSTAND}
DPADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} ${LIBSTAND}
LDADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} ${LIBSTAND}
vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version
sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}

View File

@ -1,5 +1,11 @@
# $FreeBSD$
.include <src.opts.mk>
SUBDIR= lib
.if ${MK_FDT} != "no"
SUBDIR+=fdt
.endif
.include <bsd.subdir.mk>

View File

@ -0,0 +1,33 @@
# $FreeBSD$
.include <src.opts.mk>
.PATH: ${.CURDIR}/../../common
LIB= uboot_fdt
INTERNALLIB=
WARNS?= 2
SRCS= uboot_fdt.c
CFLAGS+= -ffreestanding -msoft-float
CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/
# U-Boot library headers
CFLAGS+= -I${.CURDIR}/../lib
# libfdt headers
CFLAGS+= -I${.CURDIR}/../../fdt
# Pick up the bootstrap header for some interface items
CFLAGS+= -I${.CURDIR}/../../common -I${.CURDIR}/../../.. -I.
machine:
ln -sf ${.CURDIR}/../../../${MACHINE_CPUARCH}/include machine
CLEANFILES+= machine
.include <bsd.lib.mk>
beforedepend ${OBJS}: machine

View File

@ -0,0 +1,181 @@
/*-
* Copyright (c) 2009-2010 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Semihalf under sponsorship from
* the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <stand.h>
#include <fdt_platform.h>
#include "glue.h"
#define STR(number) #number
#define STRINGIFY(number) STR(number)
int
fdt_platform_load_dtb(void)
{
struct fdt_header *hdr;
const char *s;
char *p;
/*
* If the U-boot environment contains a variable giving the address of a
* valid blob in memory, use it. The U-boot README says the right
* variable for fdt data loaded into ram is fdt_addr_r, so try that
* first. Board vendors also use both fdtaddr and fdt_addr names.
*/
s = ub_env_get("fdt_addr_r");
if (s == NULL)
s = ub_env_get("fdtaddr");
if (s == NULL)
s = ub_env_get("fdt_addr");
if (s != NULL && *s != '\0') {
hdr = (struct fdt_header *)strtoul(s, &p, 16);
if (*p == '\0') {
if (fdt_load_dtb_addr(hdr) == 0) {
printf("Using DTB provided by U-Boot at "
"address %p.\n", hdr);
return (0);
}
}
}
/*
* If the U-boot environment contains a variable giving the name of a
* file, use it if we can load and validate it.
*/
s = ub_env_get("fdtfile");
if (s == NULL)
s = ub_env_get("fdt_file");
if (s != NULL && *s != '\0') {
if (fdt_load_dtb_file(s) == 0) {
printf("Loaded DTB from file '%s'.\n", s);
return (0);
}
}
return (1);
}
void
fdt_platform_fixups(void)
{
struct fdt_mem_region regions[3];
const char *env, *str;
char *end, *ethstr;
int eth_no, i, len, n;
struct sys_info *si;
env = NULL;
eth_no = 0;
ethstr = NULL;
/* Acquire sys_info */
si = ub_get_sys_info();
while ((env = ub_env_enum(env)) != NULL) {
if (strncmp(env, "eth", 3) == 0 &&
strncmp(env + (strlen(env) - 4), "addr", 4) == 0) {
/*
* Handle Ethernet addrs: parse uboot env eth%daddr
*/
if (!eth_no) {
/*
* Check how many chars we will need to store
* maximal eth iface number.
*/
len = strlen(STRINGIFY(TMP_MAX_ETH)) +
strlen("ethernet") + 1;
/*
* Reserve mem for string "ethernet" and len
* chars for iface no.
*/
ethstr = (char *)malloc(len * sizeof(char));
bzero(ethstr, len * sizeof(char));
strcpy(ethstr, "ethernet0");
}
/* Extract interface number */
i = strtol(env + 3, &end, 10);
if (end == (env + 3))
/* 'ethaddr' means interface 0 address */
n = 0;
else
n = i;
if (n > TMP_MAX_ETH)
continue;
str = ub_env_get(env);
if (n != 0) {
/*
* Find the lenght of the interface id by
* taking in to account the first 3 and
* last 4 characters.
*/
i = strlen(env) - 7;
strncpy(ethstr + 8, env + 3, i);
}
/* Modify blob */
fdt_fixup_ethernet(str, ethstr, len);
/* Clear ethernet..XXXX.. string */
bzero(ethstr + 8, len - 8);
if (n + 1 > eth_no)
eth_no = n + 1;
} else if (strcmp(env, "consoledev") == 0) {
str = ub_env_get(env);
fdt_fixup_stdout(str);
}
}
/* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */
fdt_fixup_cpubusfreqs(si->clk_cpu, si->clk_bus);
/* Copy the data into a useful form */
for (i = 0; i < si->mr_no; i++) {
if (i > nitems(regions)) {
i = nitems(regions);
break;
}
regions[i].start = si->mr[i].start;
regions[i].size = si->mr[i].size;
}
/* Fixup memory regions */
fdt_fixup_memory(regions, i);
}