iPXE
realmode.h
Go to the documentation of this file.
1 #ifndef REALMODE_H
2 #define REALMODE_H
3 
4 #include <stdint.h>
5 #include <registers.h>
6 #include <ipxe/uaccess.h>
7 
8 /*
9  * Data structures and type definitions
10  *
11  */
12 
13 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
14 
15 /*
16  * Declaration of variables in .data16
17  *
18  * To place a variable in the .data16 segment, declare it using the
19  * pattern:
20  *
21  * int __data16 ( foo );
22  * #define foo __use_data16 ( foo );
23  *
24  * extern uint32_t __data16 ( bar );
25  * #define bar __use_data16 ( bar );
26  *
27  * static long __data16 ( baz ) = 0xff000000UL;
28  * #define baz __use_data16 ( baz );
29  *
30  * i.e. take a normal declaration, add __data16() around the variable
31  * name, and add a line saying "#define <name> __use_data16 ( <name> )
32  *
33  * You can then access them just like any other variable, for example
34  *
35  * int x = foo + bar;
36  *
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.
40  *
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
45  *
46  * static uint16_t __data16 ( foo );
47  * #define foo __use_data16 ( foo )
48  *
49  * int bar ( void ) {
50  * __asm__ __volatile__ ( REAL_CODE ( "int $0xff\n\t"
51  * "movw %ax, foo" )
52  * : : );
53  * return foo;
54  * }
55  *
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.
59  *
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.
65  */
66 
67 /**
68  * Convert segment:offset address to user buffer
69  *
70  * @v segment Real-mode segment
71  * @v offset Real-mode offset
72  * @ret buffer User buffer
73  */
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 ) );
77 }
78 
79 /**
80  * Copy data to base memory
81  *
82  * @v dest_seg Destination segment
83  * @v dest_off Destination offset
84  * @v src Source
85  * @v len Length
86  */
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 );
91 }
92 
93 /**
94  * Copy data to base memory
95  *
96  * @v dest Destination
97  * @v src_seg Source segment
98  * @v src_off Source offset
99  * @v len Length
100  */
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 );
105 }
106 
107 /**
108  * Write a single variable to base memory
109  *
110  * @v var Variable to write
111  * @v dest_seg Destination segment
112  * @v dest_off Destination offset
113  */
114 #define put_real( var, dest_seg, dest_off ) \
115  copy_to_real ( (dest_seg), (dest_off), &(var), sizeof (var) )
116 
117 /**
118  * Read a single variable from base memory
119  *
120  * @v var Variable to read
121  * @v src_seg Source segment
122  * @v src_off Source offset
123  */
124 #define get_real( var, src_seg, src_off ) \
125  copy_from_real ( &(var), (src_seg), (src_off), sizeof (var) )
126 
127 /*
128  * REAL_CODE ( asm_code_str )
129  *
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:
133  *
134  * __asm__ __volatile__ ( REAL_CODE ( "int $0x16" )
135  * : "=a" ( character ) : "a" ( 0x0000 ) );
136  *
137  */
138 
139 #endif /* REALMODE_H */
uint16_t segment
Code segment.
Definition: librm.h:252
static __always_inline void off_t userptr_t off_t src_off
Definition: efi_uaccess.h:66
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
static __always_inline void copy_from_user(void *dest, userptr_t src, off_t src_off, size_t len)
Copy data from user buffer.
Definition: uaccess.h:337
static void const void * src
Definition: crypto.h:244
static __always_inline void off_t dest_off
Definition: efi_uaccess.h:66
i386 registers.
userptr_t phys_to_user(unsigned long phys_addr)
Convert physical address to user pointer.
Access to external ("user") memory.
static userptr_t size_t offset
Offset of the first segment within the content.
Definition: deflate.h:259
static void * dest
Definition: strings.h:176
static __always_inline void copy_to_real(unsigned int dest_seg, unsigned int dest_off, void *src, size_t n)
Copy data to base memory.
Definition: realmode.h:88
#define __always_inline
Declare a function to be always inline.
Definition: compiler.h:611
static __always_inline void copy_to_user(userptr_t dest, off_t dest_off, const void *src, size_t len)
Copy data to user buffer.
Definition: uaccess.h:324
static __always_inline userptr_t real_to_user(unsigned int segment, unsigned int offset)
Convert segment:offset address to user buffer.
Definition: realmode.h:75
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33
static __always_inline void copy_from_real(void *dest, unsigned int src_seg, unsigned int src_off, size_t n)
Copy data to base memory.
Definition: realmode.h:102