Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swap endian-ness in tools on big endian hosts #329

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from

Conversation

zeldin
Copy link

@zeldin zeldin commented Apr 10, 2021

When the host running the SDK is not little endian, all data that is exchanged with the Pico must be converted to/from little endian byte order.

Instead of sprinking explicit swaps around the code, I used available mechanisms for doing the swaps implicitly. Unfortunately, there is no such mechanism that works with both C and C++, so because the code base mixes C and C++ double mechanisms need to be employed...

The C++ fix also suffers from the fact that some structures are declared as __attribute__((packed)), which requires the contents to be POD. Because of this, the little_endian template is not allowed to have a constructor. This is not a problem in the SDK itself, but in picotool it would have been convenient to be able to create std::vector<little_endian<uint32_t>> program with an initializer.

@lurch
Copy link
Contributor

lurch commented Apr 10, 2021

@kilograham may feel differently (and his opinion matters much more than mine), but I think it might be simpler to keep everything on the Pico little-endian, and rely on the host-side tools (elf2uf2, picotool, etc.) to do any necessary conversion if the host itself isn't little-endian?
Otherwise you might have some Picos presenting a little-endian host interface, and other Picos presenting a big-endian host interface, depending only on what firmware has been flashed to them, and that might get a bit confusing?

(Of course, that's assuming that I'm correctly understanding what this PR is trying to do, which I might not be? 🤷 )

@zeldin
Copy link
Author

zeldin commented Apr 10, 2021

@lurch I think there may be a misunderstanding here. What the code does it make the data being accessed as little endian, regardless of the systems actual endianness. On a system which is already little endian, such as the Pico itself, this is a no-operation (and in fact the macros will expand to nothing). There is nothing here that will make anything big endian on the Pico. All conversions happen on the host side (and only if the host is big endian).

@lurch
Copy link
Contributor

lurch commented Apr 10, 2021

All conversions happen on the host side (and only if the host is big endian).

Cool, please accept my apologies for my misunderstanding (I'm more of a Python guy than a low-level C guy). Is a similar patch needed for https://github.com/raspberrypi/picotool or does this PR already encompass that?

@zeldin
Copy link
Author

zeldin commented Apr 10, 2021

@lurch Yes, I have a patch for picotool too. It depends on this patch though, so I wanted to test the waters here first before submitting it. 😄

@lurch
Copy link
Contributor

lurch commented Apr 10, 2021

Just out of curiosity, what big-endian host machine / OS / environment are you using?

@zeldin
Copy link
Author

zeldin commented Apr 10, 2021

@lurch RCS Talos II (POWER9) with Gentoo Linux is my main host. I also have a big endian Raspberry Pi 3. 😸

@aallan
Copy link
Contributor

aallan commented Apr 10, 2021

@lurch RCS Talos II (POWER9) with Gentoo Linux is my main host. I also have a big endian Raspberry Pi 3. 😸

I'd presumed you were on a Dec Alpha or a VAX or some such. Huh. I hadn't quite grokked that the Pi was Bi-endian.

@zeldin
Copy link
Author

zeldin commented Apr 10, 2021

@aallan All ARM-v8 cores from ARM are bi-endian. VAX is little-endian only, though, having been designed in the 1970:s, just like x86. 😆

@aallan
Copy link
Contributor

aallan commented Apr 10, 2021

All ARM-v8 cores from ARM are bi-endian. VAX is little-endian only, though, having been designed in the 1970:s, just like x86. 😆

Having used a VAX a lot during my undergrad I have total false memories of it being big endian at that point. Huh. Guess I was brain washed by my many years on Dec Alphas during my postgrad years. 🤷‍♂️

@kilograham kilograham changed the title Properly account for Pico being little endian Swap endian-ness in tools on big endian hosts Apr 11, 2021
@kilograham
Copy link
Contributor

can you rebase this on develop

@zeldin
Copy link
Author

zeldin commented Apr 16, 2021

@kilograham Sure thing!

@zeldin zeldin changed the base branch from master to develop April 16, 2021 16:58
@kilograham
Copy link
Contributor

I'm a bit torn over this; scalar_storage_order isn't supported on clang (even gcc mode). I don't believe we have any non target device which touches this which isn't C++ anyway.

I'd be tempted perhaps to do (i will keep trying to think of a nice way to do this with typedefs - I guess we can guard with an #ifdef)

#ifndef le_uint32_t
#define le_uint32_t uint32_t
#endif

in the headers (or in a common one if we have one which works across elf2uf2, picotool, regular build etc)

And that way we defer everything to the user.

C code, can continue to have to reverse byte orders manually (or wrap the structure with another one which reverses the byte order using scalar_storage_order - if that's what they choose to do)

In our C++ we can define le_uint32_t to be stored_little_endian<uint32_t> before including the header

@zeldin
Copy link
Author

zeldin commented Apr 19, 2021

I'm a bit torn over this; scalar_storage_order isn't supported on clang (even gcc mode).

Ah, ok. In that case at the very least there should be a conditional #error to catch the case where you use clang on a big-endian host. But not using it at all might be preferable.

I don't believe we have any non target device which touches this which isn't C++ anyway.

Maybe I mistunderstand your point here, but C code compiled for the host using the relevant structs exist in the file picoboot_connection.c (which is in picotool, but the header file picoboot.h that it gets the structs from is in pico-sdk).
Of course, changing this file to C++ could be an option.

In our C++ we can define le_uint32_t to be stored_little_endian<uint32_t> before including the header

Right, but wouldn't it make sense for platform.h to make that define and provide the appropriate template? If you don't like e.g. uf2.h getting an added #include "pico/platform.h", the C++ source code could be required to include it from the top level instead. Or I guess a new header file with a different name. It just doesn't seem like this wheel should have to be reinvented by each client. 😸

@zeldin
Copy link
Author

zeldin commented May 1, 2021

@kilograham I reworked the patch to work along the lines you described. The SDK patch wasn't affected that much. The picotool patch became a bit more messy when picoboot_connection.c can't rely on __attribute__((scalar_storage_order)) anymore, but it's not too bad. I'll open a PR for that repo to so you can take a look.

Copy link
Contributor

@kilograham kilograham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a few thoughts; will look at the picotool patch too

@@ -135,5 +135,21 @@ static inline void __compiler_memory_barrier(void) {
}
#ifdef __cplusplus
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note we should only need this for big endian systems... either omit, or make it a no-op on little endian host

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. A modern compiler will in fact already turn this code into a no-op on little endian, but I can put an explicitly no-op version inside an #ifdef.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Here's what I mean about the compiler fixing this for you, btw: https://godbolt.org/z/3cTdTYGzY)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I figured, I didn't know they all did so so uniformly... still it is clearer, and some maniacs may use -O0.

#include <algorithm>
#include "pico/platform.h"
#define le_uint16_t stored_little_endian<uint16_t>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be in platform.h

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I guess if you want an alternate implementation you could make your #defines before including pico/platform.h instead of after.

@kilograham kilograham added this to the 1.2.1 milestone May 31, 2021
@kilograham
Copy link
Contributor

Moved to 1.2.1 as I think i want to put the stuff in platform.h after all

@josch
Copy link

josch commented Jun 5, 2024

We are now carrying this as a patch to the Debian package of pico-sdk so that it works on s390x:

https://salsa.debian.org/debian/pico-sdk/-/blob/master/debian/patches/329.patch?ref_type=heads

This closes raspberrypi/picotool#104

@josch
Copy link

josch commented Jun 6, 2024

FYI, the pico-sdk autopkgtest failed on (big endian) s390x before but with the (rebased) patch from this pull request it passes now: https://ci.debian.net/packages/p/pico-sdk/testing/s390x/47384722/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants