[U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions

Rob Clark robdclark at gmail.com
Sun Aug 6 14:17:51 UTC 2017


On Sun, Aug 6, 2017 at 9:16 AM, Mark Kettenis <mark.kettenis at xs4all.nl> wrote:
>> From: Rob Clark <robdclark at gmail.com>
>> Date: Sat, 5 Aug 2017 11:36:25 -0400
>>
>> On Sat, Aug 5, 2017 at 11:24 AM, Rob Clark <robdclark at gmail.com> wrote:
>> > On Sat, Aug 5, 2017 at 11:10 AM, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
>> >> On 08/05/2017 04:35 PM, Rob Clark wrote:
>> >>> On Sat, Aug 5, 2017 at 10:28 AM, Mark Kettenis <mark.kettenis at xs4all.nl> wrote:
>> >>>>> Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
>> >>>>> From: Mark Kettenis <mark.kettenis at xs4all.nl>
>> >>>>>
>> >>>>> Unfortunately something in this patch series breaks things for me on a
>> >>>>> Banana Pi:
>> >>>>
>> >>>> And according to git bisect:
>> >>>>
>> >>>> 4e3e748a50fc3f43e20c7ff407184596d7c9a589 is the first bad commit
>> >>>> commit 4e3e748a50fc3f43e20c7ff407184596d7c9a589
>> >>>> Author: Peter Jones <pjones at redhat.com>
>> >>>> Date:   Wed Jun 21 16:39:02 2017 -0400
>> >>>>
>> >>>>     efi: add some more device path structures
>> >>>>
>> >>>>     Signed-off-by: Peter Jones <pjones at redhat.com>
>> >>>>     Signed-off-by: Rob Clark <robdclark at gmail.com>
>> >>>
>> >>>
>> >>> hmm, odd.. it is only adding some #define's and structs that are not
>> >>> used until a later commit..
>> >>>
>> >>> although it does also make 'struct efi_device_path_mac_addr' __packed,
>> >>> which it should have been before.  Is this an armv7?  I wonder if we
>> >>> have some troubles with unaligned accesses on armv7 that we don't have
>> >>> on aarch64 (or maybe compiler isn't turning access to device-path
>> >>> nodes into byte accesses if it can't do unaligned accesses.  (The node
>> >>> in the device-path structure are byte-packed.)
>> >>
>> >> http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
>> >>
>> >> <cite>On older processors, such as ARM9 family based processors, an
>> >> unaligned load had to be synthesised in software.  Typically by doing a
>> >> series of small accesses, and combining the results. ... Unaligned
>> >> access support must be enabled by setting the SCTLR.A bit in the system
>> >> control coprocessor</cite>
>> >>
>> >> Generally packing structures is not a good idea performance-wise. The
>> >> sequence of fields should be carefully chosen to fill up to powers of
>> >> two (2, 4 , 8).
>> >
>> > Yeah, it was clearly a dumb idea for UEFI to not make device-path
>> > nodes word aligned.  But when implementing a standard, we don't have a
>> > choice but to implement it properly, warts and all :-/
>> >
>>
>> btw, just for reference (if anyone is curious), see sect 10.3.1 in
>> UEFI spec v2.7.  If you don't want to bother looking it up, here is
>> the exact wording:
>>
>>    A Device Path is a series of generic Device Path nodes. The first
>>    Device Path node starts at byte offset zero of the Device Path.
>>    The next Device Path node starts at the end of the previous Device
>>    Path node. Therefore all nodes are byte-packed data structures that
>>    may appear on any byte boundary. All code references to device path
>>    notes must assume all fields are unaligned. Since every Device Path
>>    node contains a length field in a known place, it is possible to
>>    traverse Device Path nodes that are of an unknown type. There is
>>    no limit to the number, type, or sequence of nodes in a Device Path.
>>
>> So clearly what we were doing before was incorrect.. but cheating w/
>> extra padding bytes on arch's that cannot handle unaligned accesses
>> will avoid having to go fix grub, bootaa64/shim/fallback (and anything
>> else that uses gnu-efi), and apparently openbsd's bootaa64.efi.  It is
>> kinda weird to be using efi on these arch's in the first place, so I
>> guess I don't feel as badly about the padding bytes hack on those
>> arch's.  (But we should not use the hack on aarch64.)
>
> Looking a bit more closely at the OpenBSD efiboot code, I'm pretty
> sure we handle the parsing of device path nodes correctly.  We use an
> incarnation of the Intel EFI header files which have:
>
> typedef struct _EFI_DEVICE_PATH {
>         UINT8                           Type;
>         UINT8                           SubType;
>         UINT8                           Length[2];
> } EFI_DEVICE_PATH;
>
> #define DevicePathNodeLength(a)     ( ((a)->Length[0]) | ((a)->Length[1] << 8) )
>
> so this is all done using byte access.

Hmm, I assume the OpenBSD efiboot code does look at the payload of
device-path nodes, like HARDDRIVE_DEVICE_PATH.. which does use u32 and
u64 fields (which would be unaligned).  Although that might not be the
problem here.

> Going back to the original crash report:
>
> data abort
> pc : [<7ef8d878>]          lr : [<7ef8d874>]
> reloc pc : [<4a039878>]    lr : [<4a039874>]
> sp : 7af29660  ip : 00000000     fp : 7af29774
> r10: 7efec230  r9 : 7af33ee0     r8 : 00000000
> r7 : 00000009  r6 : 7ef9e8b8     r5 : 7af296a0  r4 : 7efa4495
> r3 : 7af296a0  r2 : 0000008c     r1 : 7af29658  r0 : 00000004
> Flags: nzCV  IRQs off  FIQs off  Mode SVC_32
>
> I think it is actually "reloc pc" instead of "pc" that we need to look
> at:
>
> $ addr2line -e u-boot 0x4a039874
> /home/kettenis/tmp/rclark/u-boot/include/efi_loader.h:272
>
> which points at the guidstr() function.  That code certainly looks
> suspicious.  It will defenitely trigger alignment faults if the guid
> isn't 32-bit aligned.

hmm, interesting.  At least gnu-efi's EFI_GUID uses the same
u32+u16+u16+u8[8] layout.  And iirc so did linux kernel and grub, so
it seemed like u-boot was the odd one out for using u8[16].  Although
maybe we are printing one of our own guid's or openbsd efiboot is also
using u8[16].

Either way I've dropped this patch and instead added %pG support to
vsprintf, using uuid_bin_to_str() which only does byte accesses.

The latest can be found here:

  https://github.com/robclark/u-boot/commits/enough-uefi-for-shim

  https://github.com/robclark/u-boot.git enough-uefi-for-shim


> The relevant instruction is a 16-bit load:
>
>   4a039878:       e1d430b4        ldrh    r3, [r4, #4]
>
> and with r4 = 7efa4495 that will defenitely trap.
>
> Looking at the defenition efi_guid_t in u-boot:
>
>   typedef struct {
>           u8 b[16];
>   } efi_guid_t;
>
> there is no guarantee that GUIDs are properly aligned, so you'll need
> to fix the guidstr function introduced in commit
> b6d913c6101ba891eb2bcb08a4ee9fc8fb57367.
>
> Things are already broken before that commit though, so there is
> another problem.  I'll see if I can figure out what it is...

Thanks

BR,
-R


More information about the U-Boot mailing list