|
|
1.1 root 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 );
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: * Copy data to base memory
69: *
70: * @v dest_seg Destination segment
71: * @v dest_off Destination offset
72: * @v src Source
73: * @v len Length
74: */
75: static inline __always_inline void
76: copy_to_real ( unsigned int dest_seg, unsigned int dest_off,
77: void *src, size_t n ) {
78: copy_to_user ( real_to_user ( dest_seg, dest_off ), 0, src, n );
79: }
80:
81: /**
82: * Copy data to base memory
83: *
84: * @v dest Destination
85: * @v src_seg Source segment
86: * @v src_off Source offset
87: * @v len Length
88: */
89: static inline __always_inline void
90: copy_from_real ( void *dest, unsigned int src_seg,
91: unsigned int src_off, size_t n ) {
92: copy_from_user ( dest, real_to_user ( src_seg, src_off ), 0, n );
93: }
94:
95: /**
96: * Write a single variable to base memory
97: *
98: * @v var Variable to write
99: * @v dest_seg Destination segment
100: * @v dest_off Destination offset
101: */
102: #define put_real( var, dest_seg, dest_off ) \
103: copy_to_real ( (dest_seg), (dest_off), &(var), sizeof (var) )
104:
105: /**
106: * Read a single variable from base memory
107: *
108: * @v var Variable to read
109: * @v src_seg Source segment
110: * @v src_off Source offset
111: */
112: #define get_real( var, src_seg, src_off ) \
113: copy_from_real ( &(var), (src_seg), (src_off), sizeof (var) )
114:
115: /*
116: * REAL_CODE ( asm_code_str )
117: *
118: * This can be used in inline assembly to create a fragment of code
119: * that will execute in real mode. For example: to write a character
120: * to the BIOS console using INT 10, you would do something like:
121: *
122: * __asm__ __volatile__ ( REAL_CODE ( "int $0x16" )
123: * : "=a" ( character ) : "a" ( 0x0000 ) );
124: *
125: */
126:
127: #endif /* REALMODE_H */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.