[SOLVED] Split addresses on 32 and 64 bit platforms
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
This has to run of 32 and 64 bit kernels.
Anyone know how to get rid of this error on 32 bit platforms
/vd80Drvr.c: In function ‘split_address’:
/vd80Drvr.c:33: warning: right shift count >= width of type
/**
* ===========================================================
* @brief Given a pointer split it into upr and lwr parts
* @param upr address where upper part of arddress will be stored
* @param lwr address where lower part of arddress will be stored
* @param ptr is the given pointer value to be split
*/
If you are writing a Linux driver and need to set up DMA you should use DMA API instead of whatever you seem to be doing. For more information see chapter 15 of LDD3, Documentation/DMA-API.txt and Documentation/DMA-API-HOWTO.txt.
Quote:
Originally Posted by Julian Lewis
On a 32bit platform this is what you get.
I bet any kind of optimisation will get rid of the differences, but it seems that my solution is best if no optimisation is enabled. Still it does not get rid of the warning as I hoped it would. So I guess it's either casting up or preprocessor:
Off: then please tell me why... if for some reason you have to treat a pointer as an integer, [u]intptr_t is the natural choice (or ptrdiff_t)
In Linux kernel, long or unsigned long is usually used if pointer needs to be stored as an integer. It so happens, that on all architectures Linux runs on, long can store a pointer.
ptrdiff_t is supposed to contain the difference between two pointers. It can even have negative values.
Apparently this type has been misused as a place to store pointers, but actually it is not big enough to hold a full 64 bit address.
uintptr_t is defined simply as unsigned long in linux/types.h and there is a load of bullshit declared around it in stdint.h
effectivley uintprt_t can always hold a full 64 bit pointer unlike ptrdiff_t and uintptr_t is the same as unsigned long.
What I like about uintptr_t is that you declare that you intend it to hold pointers when you use it, although the compiler will not complain if you store any other type in it.
Cheers
This is an email I got from someone who should know. In this case I am going to ignore his advice because as mentioned uintptr_t is just unsigned long.
Quote Email:
uintptr_t is never used in the kernel. It's an awful perverse thing.
The rule is that "unsigned long" is the type for addresses that must
not be dereferenced.
On a 32bit platform this is what you get.
I need to program a DMA transfer on a tsi148 VME bridge PCI chip
It has two registers upr and lwr
Do you expect to support 32-bit PAE?
I don't know how you translated whatever virtual address you had to a physical address, but in 32-bit PAE a physical address is 36-bits, and thus could not have been stored in a pointer.
I don't know what kernel support exists to help drivers with DMA (so the driver doesn't need to special case things like PAE), but that seems to be at least mentioned earlier in this thread. In general (though not in detail) I know drivers are not supposed to handle such details themselves, but are supposed to use general purpose constructs.
> ptrdiff_t is supposed to contain the difference between two pointers.
True
> It can even have negative values.
Certainly.
> Apparently this type has been misused as a place to store pointers, but actually it is not big enough to hold a full 64 bit address.
Why do you think so? In 64-bit mode it has to be 64-bit long, to be able to store the difference of any two pointers.
> uintptr_t is defined simply as unsigned long in linux/types.h and there is a load of bullshit declared around it in stdint.h
Those 'pieces of bullshit' might be useful for those who want to write portable C-code. (eg in LLP64 intptr_t is 'long long', not 'long')
> effectively uintprt_t can always hold a full 64 bit pointer unlike ptrdiff_t and uintptr_t is the same as unsigned long.
It isn't the case in 32-bit mode: both ptrdiff_t and inptr_t are 32-bit long.
> What I like about uintptr_t is that you declare that you intend it to hold pointers when you use it, although the compiler will not complain if you store any other type in it.
Very true.
- if (!access_ok(VERIFY_WRITE, u_tmp->rx_buf, u_tmp->len))
+ if (!access_ok(VERIFY_WRITE, (u8 __user *)
+ (ptrdiff_t) u_tmp->rx_buf,
+ u_tmp->len))
is wrong; for one thing, it's a bad C (it's what uintptr_t is for; in general
we are not even promised that ptrdiff_t is large enough to hold a pointer,
just enough to hold a difference between two pointers within the same object).
For another, it confuses the fsck out of sparse.
Use unsigned long or uintptr_t instead. There are several places misusing
ptrdiff_t (one - in a very odd way; WTF did that cast to __user ptrdiff_t
in ntfs expect to happen, anyway?) Fixed...
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.