6 #include <ipxe/uaccess.h>
9 * Data structures and type definitions
13 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
16 * Declaration of variables in .data16
18 * To place a variable in the .data16 segment, declare it using the
21 * int __data16 ( foo );
22 * #define foo __use_data16 ( foo );
24 * extern uint32_t __data16 ( bar );
25 * #define bar __use_data16 ( bar );
27 * static long __data16 ( baz ) = 0xff000000UL;
28 * #define baz __use_data16 ( baz );
30 * i.e. take a normal declaration, add __data16() around the variable
31 * name, and add a line saying "#define <name> __use_data16 ( <name> )
33 * You can then access them just like any other variable, for example
37 * This magic is achieved at a cost of only around 7 extra bytes per
38 * group of accesses to .data16 variables. When using KEEP_IT_REAL,
39 * there is no extra cost.
41 * You should place variables in .data16 when they need to be accessed
42 * by real-mode code. Real-mode assembly (e.g. as created by
43 * REAL_CODE()) can access these variables via the usual data segment.
44 * You can therefore write something like
46 * static uint16_t __data16 ( foo );
47 * #define foo __use_data16 ( foo )
50 * __asm__ __volatile__ ( REAL_CODE ( "int $0xff\n\t"
56 * Variables may also be placed in .text16 using __text16 and
57 * __use_text16. Some variables (e.g. chained interrupt vectors) fit
58 * most naturally in .text16; most should be in .data16.
60 * If you have only a pointer to a magic symbol within .data16 or
61 * .text16, rather than the symbol itself, you can attempt to extract
62 * the underlying symbol name using __from_data16() or
63 * __from_text16(). This is not for the faint-hearted; check the
64 * assembler output to make sure that it's doing the right thing.
68 * Convert segment:offset address to user buffer
70 * @v segment Real-mode segment
71 * @v offset Real-mode offset
72 * @ret buffer User buffer
74 static inline __always_inline userptr_t
75 real_to_user ( unsigned int segment, unsigned int offset ) {
76 return ( phys_to_user ( ( segment << 4 ) + offset ) );
80 * Copy data to base memory
82 * @v dest_seg Destination segment
83 * @v dest_off Destination offset
87 static inline __always_inline void
88 copy_to_real ( unsigned int dest_seg, unsigned int dest_off,
89 void *src, size_t n ) {
90 copy_to_user ( real_to_user ( dest_seg, dest_off ), 0, src, n );
94 * Copy data to base memory
97 * @v src_seg Source segment
98 * @v src_off Source offset
101 static inline __always_inline void
102 copy_from_real ( void *dest, unsigned int src_seg,
103 unsigned int src_off, size_t n ) {
104 copy_from_user ( dest, real_to_user ( src_seg, src_off ), 0, n );
108 * Write a single variable to base memory
110 * @v var Variable to write
111 * @v dest_seg Destination segment
112 * @v dest_off Destination offset
114 #define put_real( var, dest_seg, dest_off ) \
115 copy_to_real ( (dest_seg), (dest_off), &(var), sizeof (var) )
118 * Read a single variable from base memory
120 * @v var Variable to read
121 * @v src_seg Source segment
122 * @v src_off Source offset
124 #define get_real( var, src_seg, src_off ) \
125 copy_from_real ( &(var), (src_seg), (src_off), sizeof (var) )
128 * REAL_CODE ( asm_code_str )
130 * This can be used in inline assembly to create a fragment of code
131 * that will execute in real mode. For example: to write a character
132 * to the BIOS console using INT 10, you would do something like:
134 * __asm__ __volatile__ ( REAL_CODE ( "int $0x16" )
135 * : "=a" ( character ) : "a" ( 0x0000 ) );
139 #endif /* REALMODE_H */