[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.
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.
Introduction to Linux - A Hands on Guide
This guide was created as an overview of the Linux Operating System, geared toward new users as an exploration tour and getting started guide, with exercises at the end of each chapter.
For more advanced trainees it can be a desktop reference, and a collection of the base knowledge needed to proceed with system and network administration. This book contains many real life examples derived from the author's experience as a Linux system and network administrator, trainer and consultant. They hope these examples will help you to get a better understanding of the Linux system and that you feel encouraged to try out things on your own.
Click Here to receive this Complete Guide absolutely free.
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.
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:
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.
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.
> 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.
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.
- 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,
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...