Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Sunxi Tools
Commits
6c022244
Unverified
Commit
6c022244
authored
Mar 15, 2021
by
Chen-Yu Tsai
Committed by
GitHub
Mar 15, 2021
Browse files
Merge pull request #152 from apritzel/fit
sunxi-fel FIT image support
parents
7a6a2221
14b3492e
Changes
6
Hide whitespace changes
Inline
Side-by-side
Makefile
View file @
6c022244
...
...
@@ -137,9 +137,9 @@ SOC_INFO := soc_info.c soc_info.h
FEL_LIB
:=
fel_lib.c fel_lib.h
SPI_FLASH
:=
fel-spiflash.c fel-spiflash.h fel-remotefunc-spi-data-transfer.h
sunxi-fel
:
fel.c thunks/fel-to-spl-thunk.h $(PROGRESS) $(SOC_INFO) $(FEL_LIB) $(SPI_FLASH)
sunxi-fel
:
fel.c
fit_image.c
thunks/fel-to-spl-thunk.h $(PROGRESS) $(SOC_INFO) $(FEL_LIB) $(SPI_FLASH)
$(CC)
$(HOST_CFLAGS)
$(LIBUSB_CFLAGS)
$(ZLIB_CFLAGS)
$(LDFLAGS)
-o
$@
\
$(
filter
%.c,
$^
)
$(LIBS)
$(LIBUSB_LIBS)
$(ZLIB_LIBS)
$(
filter
%.c,
$^
)
$(LIBS)
$(LIBUSB_LIBS)
$(ZLIB_LIBS)
-lfdt
sunxi-nand-part
:
nand-part-main.c nand-part.c nand-part-a10.h nand-part-a20.h
$(CC)
$(HOST_CFLAGS)
-c
-o
nand-part-main.o nand-part-main.c
...
...
fel.c
View file @
6c022244
...
...
@@ -19,6 +19,7 @@
#include "portable_endian.h"
#include "fel_lib.h"
#include "fel-spiflash.h"
#include "fit_image.h"
#include <assert.h>
#include <ctype.h>
...
...
@@ -31,9 +32,10 @@
#include <zlib.h>
#include <sys/stat.h>
static
bool
verbose
=
false
;
/* If set, makes the 'fel' tool more talkative */
bool
verbose
=
false
;
/* If set, makes the 'fel' tool more talkative */
static
uint32_t
uboot_entry
=
0
;
/* entry point (address) of U-Boot */
static
uint32_t
uboot_size
=
0
;
/* size of U-Boot binary */
static
bool
enter_in_aarch64
=
false
;
/* printf-style output, but only if "verbose" flag is active */
#define pr_info(...) \
...
...
@@ -45,6 +47,7 @@ static uint32_t uboot_size = 0; /* size of U-Boot binary */
#define IH_TYPE_INVALID 0
/* Invalid Image */
#define IH_TYPE_FIRMWARE 5
/* Firmware Image */
#define IH_TYPE_SCRIPT 6
/* Script file */
#define IH_TYPE_FLATDT 8
/* DTB or FIT image */
#define IH_NMLEN 32
/* Image Name Length */
/* Additional error codes, newly introduced for get_image_type() */
...
...
@@ -90,6 +93,8 @@ int get_image_type(const uint8_t *buf, size_t len)
if
(
len
<=
HEADER_SIZE
)
/* insufficient length/size */
return
IH_TYPE_INVALID
;
if
(
be32toh
(
hdr
->
ih_magic
)
==
0xd00dfeed
)
return
IH_TYPE_FLATDT
;
if
(
be32toh
(
hdr
->
ih_magic
)
!=
IH_MAGIC
)
/* signature mismatch */
return
IH_TYPE_INVALID
;
/* For sunxi, we always expect ARM architecture here */
...
...
@@ -864,7 +869,8 @@ uint32_t aw_fel_write_and_execute_spl(feldev_handle *dev, uint8_t *buf, size_t l
* address stored within the image header; and the function preserves the
* U-Boot entry point (offset) and size values.
*/
void
aw_fel_write_uboot_image
(
feldev_handle
*
dev
,
uint8_t
*
buf
,
size_t
len
)
static
void
aw_fel_write_uboot_image
(
feldev_handle
*
dev
,
uint8_t
*
buf
,
size_t
len
,
const
char
*
dt_name
)
{
if
(
len
<=
HEADER_SIZE
)
return
;
/* Insufficient size (no actual data), just bail out */
...
...
@@ -887,6 +893,13 @@ void aw_fel_write_uboot_image(feldev_handle *dev, uint8_t *buf, size_t len)
}
exit
(
1
);
}
if
(
image_type
==
IH_TYPE_FLATDT
)
{
/* FIT image */
uboot_entry
=
load_fit_images
(
dev
,
buf
,
dt_name
,
&
enter_in_aarch64
);
uboot_size
=
4
;
/* dummy value to pass check below */
return
;
}
if
(
image_type
!=
IH_TYPE_FIRMWARE
)
pr_fatal
(
"U-Boot image type mismatch: "
"expected IH_TYPE_FIRMWARE, got %02X
\n
"
,
image_type
);
...
...
@@ -923,6 +936,28 @@ void aw_fel_write_uboot_image(feldev_handle *dev, uint8_t *buf, size_t len)
uboot_size
=
data_size
;
}
static
const
char
*
spl_get_dtb_name
(
uint8_t
*
spl_buf
)
{
uint32_t
dt_offset
;
if
(
memcmp
(
spl_buf
+
4
,
"eGON.BT0"
,
8
))
return
NULL
;
if
(
memcmp
(
spl_buf
+
0x14
,
"SPL"
,
3
))
return
NULL
;
if
(
spl_buf
[
0x17
]
<
0x2
)
/* only since v0.2 */
return
NULL
;
memcpy
(
&
dt_offset
,
spl_buf
+
0x20
,
4
);
dt_offset
=
le32toh
(
dt_offset
);
if
(
verbose
)
printf
(
"found DT name in SPL header: %s
\n
"
,
spl_buf
+
dt_offset
);
return
(
char
*
)
spl_buf
+
dt_offset
;
}
/*
* This function handles the common part of both "spl" and "uboot" commands.
*/
...
...
@@ -932,15 +967,18 @@ void aw_fel_process_spl_and_uboot(feldev_handle *dev, const char *filename)
uint32_t
offset
;
/* load file into memory buffer */
uint8_t
*
buf
=
load_file
(
filename
,
&
size
);
const
char
*
dt_name
=
spl_get_dtb_name
(
buf
);
/* write and execute the SPL from the buffer */
offset
=
aw_fel_write_and_execute_spl
(
dev
,
buf
,
size
);
/* check for optional main U-Boot binary (and transfer it, if applicable) */
if
(
size
>
offset
)
{
/* U-Boot pads to at least 32KB */
if
(
offset
<
SPL_MIN_OFFSET
)
offset
=
SPL_MIN_OFFSET
;
aw_fel_write_uboot_image
(
dev
,
buf
+
offset
,
size
-
offset
);
aw_fel_write_uboot_image
(
dev
,
buf
+
offset
,
size
-
offset
,
dt_name
);
}
free
(
buf
);
}
...
...
@@ -1405,7 +1443,10 @@ int main(int argc, char **argv)
/* auto-start U-Boot if requested (by the "uboot" command) */
if
(
uboot_autostart
)
{
pr_info
(
"Starting U-Boot (0x%08X).
\n
"
,
uboot_entry
);
aw_fel_execute
(
handle
,
uboot_entry
);
if
(
enter_in_aarch64
)
aw_rmr_request
(
handle
,
uboot_entry
,
true
);
else
aw_fel_execute
(
handle
,
uboot_entry
);
}
feldev_done
(
handle
);
...
...
fel_lib.c
View file @
6c022244
...
...
@@ -214,8 +214,11 @@ void aw_fel_read(feldev_handle *dev, uint32_t offset, void *buf, size_t len)
}
/* AW_FEL_1_WRITE request */
void
aw_fel_write
(
feldev_handle
*
dev
,
void
*
buf
,
uint32_t
offset
,
size_t
len
)
void
aw_fel_write
(
feldev_handle
*
dev
,
const
void
*
buf
,
uint32_t
offset
,
size_t
len
)
{
if
(
len
==
0
)
return
;
aw_send_fel_request
(
dev
,
AW_FEL_1_WRITE
,
offset
,
len
);
aw_usb_write
(
dev
,
buf
,
len
,
false
);
aw_read_fel_status
(
dev
);
...
...
@@ -233,9 +236,12 @@ void aw_fel_execute(feldev_handle *dev, uint32_t offset)
* Unlike aw_fel_write() above - which is reserved for internal use - this
* routine optionally allows progress callbacks.
*/
void
aw_fel_write_buffer
(
feldev_handle
*
dev
,
void
*
buf
,
uint32_t
offset
,
void
aw_fel_write_buffer
(
feldev_handle
*
dev
,
const
void
*
buf
,
uint32_t
offset
,
size_t
len
,
bool
progress
)
{
if
(
len
==
0
)
return
;
aw_send_fel_request
(
dev
,
AW_FEL_1_WRITE
,
offset
,
len
);
aw_usb_write
(
dev
,
buf
,
len
,
progress
);
aw_read_fel_status
(
dev
);
...
...
fel_lib.h
View file @
6c022244
...
...
@@ -59,8 +59,8 @@ feldev_list_entry *list_fel_devices(size_t *count);
/* FEL functions */
void
aw_fel_read
(
feldev_handle
*
dev
,
uint32_t
offset
,
void
*
buf
,
size_t
len
);
void
aw_fel_write
(
feldev_handle
*
dev
,
void
*
buf
,
uint32_t
offset
,
size_t
len
);
void
aw_fel_write_buffer
(
feldev_handle
*
dev
,
void
*
buf
,
uint32_t
offset
,
void
aw_fel_write
(
feldev_handle
*
dev
,
const
void
*
buf
,
uint32_t
offset
,
size_t
len
);
void
aw_fel_write_buffer
(
feldev_handle
*
dev
,
const
void
*
buf
,
uint32_t
offset
,
size_t
len
,
bool
progress
);
void
aw_fel_execute
(
feldev_handle
*
dev
,
uint32_t
offset
);
...
...
fit_image.c
0 → 100644
View file @
6c022244
/*
* Copyright (C) 2018-2020 Andre Przywara <osp@andrep.de>
*
* 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; under 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdint.h>
#include <libfdt.h>
#include "common.h"
#include "fel_lib.h"
#include "fit_image.h"
/* defined in fel.c */
extern
bool
verbose
;
#define IH_ARCH_INVALID 0
#define IH_ARCH_ARM 2
#define IH_ARCH_ARM64 22
#define IH_OS_INVALID 0
#define IH_OS_LINUX 5
#define IH_OS_U_BOOT 17
#define IH_OS_ARM_TRUSTED_FIRMWARE 25
#define IH_OS_EFI 28
struct
fit_image_info
{
const
char
*
description
;
const
char
*
data
;
uint32_t
data_size
;
uint32_t
load_addr
;
uint32_t
entry_point
;
uint8_t
os
;
uint8_t
arch
;
};
static
int
fit_parse_os
(
const
char
*
value
)
{
if
(
!
value
||
!*
value
)
return
IH_OS_INVALID
;
if
(
!
strcmp
(
value
,
"u-boot"
))
return
IH_OS_U_BOOT
;
if
(
!
strcmp
(
value
,
"linux"
))
return
IH_OS_LINUX
;
if
(
!
strcmp
(
value
,
"arm-trusted-firmware"
))
return
IH_OS_ARM_TRUSTED_FIRMWARE
;
if
(
!
strcmp
(
value
,
"efi"
))
return
IH_OS_EFI
;
return
IH_OS_INVALID
;
}
static
int
fit_parse_arch
(
const
char
*
value
)
{
if
(
!
value
||
!*
value
)
return
IH_ARCH_INVALID
;
if
(
!
strcmp
(
value
,
"arm"
))
return
IH_ARCH_ARM
;
if
(
!
strcmp
(
value
,
"arm64"
))
return
IH_ARCH_ARM64
;
return
IH_ARCH_INVALID
;
}
static
uint32_t
fdt_getprop_u32
(
const
void
*
fdt
,
int
node
,
const
char
*
name
)
{
const
struct
fdt_property
*
prop
;
prop
=
fdt_get_property
(
fdt
,
node
,
name
,
NULL
);
if
(
!
prop
)
return
~
0U
;
return
be32toh
(
*
(
uint32_t
*
)
prop
->
data
);
}
static
const
char
*
fdt_getprop_str
(
const
void
*
fdt
,
int
node
,
const
char
*
name
)
{
const
struct
fdt_property
*
prop
;
prop
=
fdt_get_property
(
fdt
,
node
,
name
,
NULL
);
if
(
!
prop
)
return
NULL
;
return
prop
->
data
;
}
/*
* Find the image with the given name under the /images node, and parse
* its information into the fit_image_info struct.
* Returns 0 on success, and a negative error value otherwise.
*/
static
int
fit_get_image_info
(
const
void
*
fit
,
const
char
*
name
,
struct
fit_image_info
*
info
)
{
int
node
;
const
char
*
str
;
uint32_t
data_offset
;
node
=
fdt_path_offset
(
fit
,
"/images"
);
if
(
node
<
0
)
return
-
1
;
node
=
fdt_subnode_offset
(
fit
,
node
,
name
);
if
(
node
<
0
)
return
-
1
;
info
->
load_addr
=
fdt_getprop_u32
(
fit
,
node
,
"load"
);
info
->
entry_point
=
fdt_getprop_u32
(
fit
,
node
,
"entry"
);
info
->
description
=
fdt_getprop_str
(
fit
,
node
,
"description"
);
/* properties used for FIT images with external data */
info
->
data_size
=
fdt_getprop_u32
(
fit
,
node
,
"data-size"
);
data_offset
=
fdt_getprop_u32
(
fit
,
node
,
"data-offset"
);
/* check for embedded data (when invalid external data properties) */
if
(
info
->
data_size
==
~
0U
||
data_offset
==
~
0U
)
{
const
struct
fdt_property
*
prop
;
int
len
;
prop
=
fdt_get_property
(
fit
,
node
,
"data"
,
&
len
);
info
->
data_size
=
len
;
info
->
data
=
prop
->
data
;
}
else
{
/* external data is appended at the end of the FIT DTB blob */
info
->
data
=
(
const
char
*
)
fit
+
((
fdt_totalsize
(
fit
)
+
3
)
&
~
3U
);
info
->
data
+=
data_offset
;
}
info
->
os
=
fit_parse_os
(
fdt_getprop_str
(
fit
,
node
,
"os"
));
info
->
arch
=
fit_parse_arch
(
fdt_getprop_str
(
fit
,
node
,
"arch"
));
str
=
fdt_getprop_str
(
fit
,
node
,
"compression"
);
/* The current SPL does not support compression either. */
if
(
str
&&
strcmp
(
str
,
"none"
))
{
printf
(
"compression
\"
%s
\"
not supported for image
\"
%s
\"\n
"
,
str
,
info
->
description
);
return
-
2
;
}
return
0
;
}
static
int
entry_arch
;
static
uint32_t
dtb_addr
;
/*
* Upload the image described by its fit_image_info struct to the board.
* Detect if an image contains an entry point and return that.
* Set entry_arch to arm or arm64 on the way. Also detect the image
* containing U-Boot and record its end address, so that the DTB can be
* appended later on.
* Returns the entry point if any is specified, or 0 otherwise.
*/
static
uint32_t
fit_load_image
(
feldev_handle
*
dev
,
struct
fit_image_info
*
img
)
{
uint32_t
ret
=
0
;
if
(
verbose
)
printf
(
"loading image
\"
%s
\"
(%d bytes) to 0x%x
\n
"
,
img
->
description
,
img
->
data_size
,
img
->
load_addr
);
aw_fel_write_buffer
(
dev
,
img
->
data
,
img
->
load_addr
,
img
->
data_size
,
true
);
if
(
img
->
entry_point
!=
~
0U
)
{
ret
=
img
->
entry_point
;
entry_arch
=
img
->
arch
;
}
/* either explicitly marked as U-Boot, or the first invalid one */
if
(
img
->
os
==
IH_OS_U_BOOT
||
(
!
dtb_addr
&&
img
->
os
==
IH_OS_INVALID
))
dtb_addr
=
img
->
load_addr
+
img
->
data_size
;
return
ret
;
}
uint32_t
load_fit_images
(
feldev_handle
*
dev
,
const
void
*
fit
,
const
char
*
dt_name
,
bool
*
use_aarch64
)
{
const
struct
fdt_property
*
prop
;
struct
fit_image_info
img
;
const
char
*
str
;
int
node
,
len
;
uint32_t
entry_point
=
0
;
node
=
fdt_path_offset
(
fit
,
"/configurations"
);
if
(
node
<
0
)
{
pr_error
(
"invalid FIT image, no /configurations node
\n
"
);
return
0
;
}
/*
* Find the right configuration node, either by using the provided
* DT name as an identifier, falling back to the node titled "default",
* or by using just the first node.
*/
if
(
dt_name
)
{
for
(
node
=
fdt_first_subnode
(
fit
,
node
);
node
>=
0
;
node
=
fdt_next_subnode
(
fit
,
node
))
{
prop
=
fdt_get_property
(
fit
,
node
,
"description"
,
NULL
);
if
(
prop
&&
!
strcmp
(
prop
->
data
,
dt_name
))
break
;
}
if
(
node
<
0
)
{
pr_error
(
"no matching FIT configuration node for
\"
%s
\"\n
"
,
dt_name
);
return
0
;
}
}
else
{
prop
=
fdt_get_property
(
fit
,
node
,
"default"
,
NULL
);
if
(
!
prop
)
node
=
fdt_first_subnode
(
fit
,
node
);
else
node
=
fdt_subnode_offset
(
fit
,
node
,
prop
->
data
);
if
(
node
<
0
)
{
pr_error
(
"no default FIT configuration node
\n
"
);
return
0
;
}
}
entry_arch
=
IH_ARCH_INVALID
;
dtb_addr
=
0
;
/* Load the image described as "firmware". */
str
=
fdt_getprop_str
(
fit
,
node
,
"firmware"
);
if
(
str
&&
!
fit_get_image_info
(
fit
,
str
,
&
img
))
{
uint32_t
addr
=
fit_load_image
(
dev
,
&
img
);
if
(
addr
!=
0
)
entry_point
=
addr
;
}
else
{
printf
(
"WARNING: no valid
\"
firmware
\"
image entry in FIT
\n
"
);
}
/* load all loadables, at their respective load addresses */
prop
=
fdt_get_property
(
fit
,
node
,
"loadables"
,
&
len
);
for
(
str
=
prop
?
prop
->
data
:
NULL
;
prop
&&
(
str
-
prop
->
data
)
<
len
&&
*
str
;
str
+=
strlen
(
str
)
+
1
)
{
uint32_t
addr
;
if
(
fit_get_image_info
(
fit
,
str
,
&
img
))
{
printf
(
"Can't load loadable
\"
%s
\"
, skipping.
\n
"
,
str
);
continue
;
}
addr
=
fit_load_image
(
dev
,
&
img
);
if
(
addr
!=
0
)
entry_point
=
addr
;
}
if
(
use_aarch64
)
*
use_aarch64
=
(
entry_arch
==
IH_ARCH_ARM64
);
if
(
!
dtb_addr
)
{
printf
(
"Warning: no U-Boot image found, not loading DTB
\n
"
);
return
entry_point
;
}
/* load .dtb right after the U-Boot image (appended DTB) */
str
=
fdt_getprop_str
(
fit
,
node
,
"fdt"
);
if
(
!
str
||
fit_get_image_info
(
fit
,
str
,
&
img
))
{
printf
(
"Warning: no FDT found in FIT image
\n
"
);
return
entry_point
;
}
if
(
verbose
)
printf
(
"loading DTB
\"
%s
\"
(%d bytes)
\n
"
,
img
.
description
,
img
.
data_size
);
aw_fel_write_buffer
(
dev
,
img
.
data
,
dtb_addr
,
img
.
data_size
,
false
);
return
entry_point
;
}
fit_image.h
0 → 100644
View file @
6c022244
/*
* Copyright (C) 2018-2020 Andre Przywara <osp@andrep.de>
*
* 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; under 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FIT_IMAGE_H__
#define __FIT_IMAGE_H__
#include <stdint.h>
#include "fel_lib.h"
/*
* Load all images referenced in the given U-Boot FIT image. @dt_name will
* be used to select one of the configurations. @use_aarch64 contains the
* target architecture of the entry point.
* Returns the entry point address of the image to be started.
*/
uint32_t
load_fit_images
(
feldev_handle
*
dev
,
const
void
*
fit
,
const
char
*
dt_name
,
bool
*
use_aarch64
);
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment