iPXE
realmode.h
Go to the documentation of this file.
00001 #ifndef REALMODE_H
00002 #define REALMODE_H
00003 
00004 #include <stdint.h>
00005 #include <registers.h>
00006 #include <ipxe/uaccess.h>
00007 
00008 /*
00009  * Data structures and type definitions
00010  *
00011  */
00012 
00013 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00014 
00015 /*
00016  * Declaration of variables in .data16
00017  *
00018  * To place a variable in the .data16 segment, declare it using the
00019  * pattern:
00020  *
00021  *   int __data16 ( foo );
00022  *   #define foo __use_data16 ( foo );
00023  *
00024  *   extern uint32_t __data16 ( bar );
00025  *   #define bar __use_data16 ( bar );
00026  *
00027  *   static long __data16 ( baz ) = 0xff000000UL;
00028  *   #define baz __use_data16 ( baz );
00029  *
00030  * i.e. take a normal declaration, add __data16() around the variable
00031  * name, and add a line saying "#define <name> __use_data16 ( <name> )
00032  *
00033  * You can then access them just like any other variable, for example
00034  *
00035  *   int x = foo + bar;
00036  *
00037  * This magic is achieved at a cost of only around 7 extra bytes per
00038  * group of accesses to .data16 variables.  When using KEEP_IT_REAL,
00039  * there is no extra cost.
00040  *
00041  * You should place variables in .data16 when they need to be accessed
00042  * by real-mode code.  Real-mode assembly (e.g. as created by
00043  * REAL_CODE()) can access these variables via the usual data segment.
00044  * You can therefore write something like
00045  *
00046  *   static uint16_t __data16 ( foo );
00047  *   #define foo __use_data16 ( foo )
00048  *
00049  *   int bar ( void ) {
00050  *     __asm__ __volatile__ ( REAL_CODE ( "int $0xff\n\t"
00051  *                                        "movw %ax, foo" )
00052  *                            : : );
00053  *     return foo;
00054  *   }
00055  *
00056  * Variables may also be placed in .text16 using __text16 and
00057  * __use_text16.  Some variables (e.g. chained interrupt vectors) fit
00058  * most naturally in .text16; most should be in .data16.
00059  *
00060  * If you have only a pointer to a magic symbol within .data16 or
00061  * .text16, rather than the symbol itself, you can attempt to extract
00062  * the underlying symbol name using __from_data16() or
00063  * __from_text16().  This is not for the faint-hearted; check the
00064  * assembler output to make sure that it's doing the right thing.
00065  */
00066 
00067 /**
00068  * Convert segment:offset address to user buffer
00069  *
00070  * @v segment           Real-mode segment
00071  * @v offset            Real-mode offset
00072  * @ret buffer          User buffer
00073  */
00074 static inline __always_inline userptr_t
00075 real_to_user ( unsigned int segment, unsigned int offset ) {
00076         return ( phys_to_user ( ( segment << 4 ) + offset ) );
00077 }
00078 
00079 /**
00080  * Copy data to base memory
00081  *
00082  * @v dest_seg          Destination segment
00083  * @v dest_off          Destination offset
00084  * @v src               Source
00085  * @v len               Length
00086  */
00087 static inline __always_inline void
00088 copy_to_real ( unsigned int dest_seg, unsigned int dest_off,
00089                void *src, size_t n ) {
00090         copy_to_user ( real_to_user ( dest_seg, dest_off ), 0, src, n );
00091 }
00092 
00093 /**
00094  * Copy data to base memory
00095  *
00096  * @v dest              Destination
00097  * @v src_seg           Source segment
00098  * @v src_off           Source offset
00099  * @v len               Length
00100  */
00101 static inline __always_inline void
00102 copy_from_real ( void *dest, unsigned int src_seg,
00103                  unsigned int src_off, size_t n ) {
00104         copy_from_user ( dest, real_to_user ( src_seg, src_off ), 0, n );
00105 }
00106 
00107 /**
00108  * Write a single variable to base memory
00109  *
00110  * @v var               Variable to write
00111  * @v dest_seg          Destination segment
00112  * @v dest_off          Destination offset
00113  */
00114 #define put_real( var, dest_seg, dest_off ) \
00115         copy_to_real ( (dest_seg), (dest_off), &(var), sizeof (var) )
00116 
00117 /**
00118  * Read a single variable from base memory
00119  *
00120  * @v var               Variable to read
00121  * @v src_seg           Source segment
00122  * @v src_off           Source offset
00123  */
00124 #define get_real( var, src_seg, src_off ) \
00125         copy_from_real ( &(var), (src_seg), (src_off), sizeof (var) )
00126 
00127 /*
00128  * REAL_CODE ( asm_code_str )
00129  *
00130  * This can be used in inline assembly to create a fragment of code
00131  * that will execute in real mode.  For example: to write a character
00132  * to the BIOS console using INT 10, you would do something like:
00133  *
00134  *     __asm__ __volatile__ ( REAL_CODE ( "int $0x16" )
00135  *                            : "=a" ( character ) : "a" ( 0x0000 ) );
00136  *
00137  */
00138 
00139 #endif /* REALMODE_H */