When reading from the SID device using the normal memory access method,
we upload our "readl" routine (via fel_readl_n()), which expects a number
of *words* to read. However length is given in *bytes*, so we read four
times as much, and overflow our key buffer, clobbering the return address.
This is typically fatal:
===============
$ ./sunxi-fel sid
02c05200:12345678:34567890:76543210
Segmentation fault (core dumped)
$
===============
Fix this by giving the number of (32-bit) words instead. We already
checked that length is a multiple of 4, so we can just divide.
Signed-off-by: Andre Przywara <osp@andrep.de>
At the moment we have two functions reading the SID eFuses:
fel_get_sid_root_key() to read the "root key" (the first 128 bits), and
fel_get_sid() to read an arbitrary range. The latter does not use the
MMIO register workaround on affected SoCs, while the former only reads
that specific range of bits.
Unify the two functions into one that combines the advantanges of both:
we can read any range of eFuses, and it uses the MMIO register access
method, if needed. Switch the users to use the new function.
Signed-off-by: Andre Przywara <osp@andrep.de>
To workaround a hardware erratum on the H3 SoC, we use an MMIO register
based assembly routine to dump the SID registers, if needed. This is
hard-coded to read the first four 32-bit words of the SID fuses.
For the sid-dump command we need to access any arbitrary regions of the
fuses, so extend the routine to take a start and an end address to dump.
This changes the assembly source in the thunks/ directory:
- We load the start address into r1, instead of zeroing it. The start
address is put right after the SIO MMIO base address, at the end of
the code.
- When storing the read value into the result buffer, we automatically
increase the pointer register (r3), instead of adding the offset
address, since this is now no longer zero based.
- To check for the end, we read the end pointer (stored at the end of
the code, right after the offset), and compare against that instead of
the hardcoded value of 16.
This assembly file was put through the thunks Makefile, and the resulting
content was copied from thunks/sid_read_root.h into fel_lib.c.
For now we are still putting the constant values of 0 and 16 in, but
this time from the C code.
Signed-off-by: Andre Przywara <osp@andrep.de>
On some new Allwinner SoCs, I-Cache is enabled by BROM but FEL write
command cannot correctly invalidate I-Cache, so thunks will not get
properly executed.
Implement a hack that tries to disable I-Cache each time trying to write
data via FEL, to prevent stall thunks in I-Cache.
Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Some functions are only used internally in fel_lib.c, consequently their
prototypes are not exported in fel_lib.h.
Mark those functions as "static", to make this clear to the reader and
improve the generated code.
Signed-off-by: Andre Przywara <osp@andrep.de>
The aw_usb_read() function is meant to *fill* the buffer given to it, so
marking the pointer as "const" in the parameters list is wrong.
Some compilers (for instance GCC 11) spot this and issue a warning:
----------------------------------
fel_lib.c: In function ‘aw_read_fel_status’:
fel_lib.c:190:9: warning: ‘buf’ may be used uninitialized [-Wmaybe-uninitialize]
190 | aw_usb_read(dev, buf, sizeof(buf));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fel_lib.c:168:13: note: by argument 2 of type ‘const void *’ to ‘aw_usb_read’ declared here
168 | static void aw_usb_read(feldev_handle *dev, const void *data, size_t len)
| ^~~~~~~~~~~
fel_lib.c:189:14: note: ‘buf’ declared here
189 | char buf[8];
| ^~~
----------------------------------
Drop the 'const' specifier, and use the right USB bulk transfer wrapper
to make this work. The usb_bulk_send() function just happened to work
before because the actual libusb bulk transfer function is bidirectional.
Signed-off-by: Andre Przywara <osp@andrep.de>
Our FEL code does not deal very well with the upload size being 0.
Check for that before calling any USB routines, and skip the call
entirely. Mark the buffer as "const" on the way, since we have no
business other than reading from it.
That helps to properly skip dummy images later.
Signed-off-by: Andre Przywara <osp@andrep.de>
This function provides bitwise clear/set operations on 32-bit words
via FEL. It may help with implementing future functionality, where
ARM register manipulations often involve such bit level access.
Signed-off-by: Bernhard Nortmann <bernhard.nortmann@web.de>
The functions represent ARM "thunk" code that can be invoked via
FEL to execute arbitrary memory copy operations on the target
device, i.e. they deal with overlap and unaligned access. Where
possible, the copy operation will use (32-bit) word transfers,
otherwise it falls back to bytewise copying.
Signed-off-by: Bernhard Nortmann <bernhard.nortmann@web.de>
The patch also introduces a "sid-register" command for diagnostic
purposes. It allows to use/enforce the workaround method for other
SoCs, to check if there are any inconsistencies with the values
read from memory.
Signed-off-by: Bernhard Nortmann <bernhard.nortmann@web.de>
The new function fel_get_sid_registers() uses ARM code for register
access to the SID root key. This is necessary to retrieve correct
values for certain SoCs, e.g. when not using this approach the H3
has been observed to return 'mangled' values (when reading SID from
memory).
See https://groups.google.com/forum/#!topic/linux-sunxi/ynyIP8c61Qs
The FEL library provides a uniform fel_get_sid_root_key() wrapper
that will automatically use the workaround method for SoCs that
are tagged accordingly - so the application program does not have
to bother with selecting memory vs. register-based access.
Signed-off-by: Bernhard Nortmann <bernhard.nortmann@web.de>
This is a preparatory step. Instead of using memory-based access,
we might want to retrieve SID keys (e-fuses) via SID registers.
For this, it's convenient if the plain base address is available.
Signed-off-by: Bernhard Nortmann <bernhard.nortmann@web.de>
open_fel_device() will automatically provide this member field,
based on the SoC ID from FEL/BROM version data. The field will
either receive a human-readable identifier, or the ID in 4-digit
hexadecimal representation (for unknown SoCs).
Signed-off-by: Bernhard Nortmann <bernhard.nortmann@web.de>
The feldev_handle struct returned by feldev_open() will now contain
this additional data, so the main application no longer needs to care
about retrieving that.
aw_fel_get_version() has thus become a static (= 'private') function.
Signed-off-by: Bernhard Nortmann <bernhard.nortmann@web.de>
The FEL utility had accumulated enough (mostly USB-related)
"low-level" code to justify moving that to a separate code unit.
This will allow us to keep better focus on the higher level
functionality in fel.c.
Signed-off-by: Bernhard Nortmann <bernhard.nortmann@web.de>