On Tue, Mar 13, 2012 at 06:44:19PM +0900, Daniel Castro wrote:
Hello,
Sorry to bring this again, but I am still struggling with 16 bit disk operation.
This time I have a simpler question.
When I do container_of(...) I get pointer to 0xd630. The address when I created the drive struct is 0x000fd630. What do I need to do to be able to use the return of container_of in 16bit code?
When in "segmented" mode (both 16bit mode and 32bit segmented mode) the processor does not have a uniform view of memory. This is quite complex and painful to work with, so basically no modern systems use it anymore. For compatibility, seabios must still support 16bit mode though. This means that when it is in segmented mode it has a different view of memory than the init code (which runs in regular 32bit flat mode).
So, the following code:
u8 myglobal VAR16VISIBLE; ... dprintf(1, "myglobal addr = %p\n", &myglobal);
Will show two different results - it prints 0xf1234 in 32bit flat mode (it's a variable in the f-segment). In 16bit mode it shows up as 0x1234 - the build arranges for this in order to keep the address within a 16bit range. To access the variable in 16bit mode, one must use GET_GLOBAL(myglobal) - this will arrange for the proper segment accessor (in this case %cs) to be used in conjunction with the variable address (eg, 0x1234) to load the proper value.
However, the following code:
int *myptr VAR16VISIBLE; ... myptr = malloc_fseg(16); ... dprintf(1, "myptr = %p\n", GET_GLOBAL(myptr));
The dprintf will show 0xf4567 regardless of the mode it is in. That is because the pointer is loaded up at runtime with a 32 bit flat address, and the build has no way of "fixing" that up. To access the content of the pointer, one would use the GET_GLOBALFLAT() macro.
To make things slightly more complex, a *drive_g pointer returned from block.c:getDrive() makes the conversion from GLOBALFLAT to GLOBAL (via the GLOBALFLAT2GLOBAL macro. So, if you're working with drive_g pointers, you should just use GET_GLOBAL. This, BTW, is the reason for the "_g" and "_gf" sufixes found in places through the code - they're identifiers for pointers that are global vs globalflat.
Also, be aware that *every* pointer access (that isn't pointing to a variable on the stack) must be wrapped in a macro. Failure to do this will result in random data being read. As an example of this, to read the integer pointed to by the global variable "myptr" above, one would need to run GET_GLOBALFLAT(*GET_GLOBAL(myptr)) - one macro to extract the global variable and the other macro to extract the data pointed to by the global variable.
So, basically, pointers have to be accessed the correct way in order for the system to work. I know this is complex, but it's just the reality of programming in segmented mode. This complexity has nothing to do with container_of - that macro works the same way regardless of the mode.
-Kevin