|
@@ -1,178 +1,267 @@
|
|
1
|
+/*
|
|
2
|
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
|
|
3
|
+ *
|
|
4
|
+ * This program is free software; you can redistribute it and/or
|
|
5
|
+ * modify it under the terms of the GNU General Public License as
|
|
6
|
+ * published by the Free Software Foundation; either version 2 of the
|
|
7
|
+ * License, or any later version.
|
|
8
|
+ *
|
|
9
|
+ * This program is distributed in the hope that it will be useful, but
|
|
10
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
12
|
+ * General Public License for more details.
|
|
13
|
+ *
|
|
14
|
+ * You should have received a copy of the GNU General Public License
|
|
15
|
+ * along with this program; if not, write to the Free Software
|
|
16
|
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
17
|
+ *
|
|
18
|
+ */
|
1
|
19
|
|
2
|
20
|
#define CR0_PE 1
|
3
|
|
-
|
4
|
|
-
|
|
21
|
+
|
5
|
22
|
.arch i386
|
6
|
|
- .section ".prefix", "awx", @progbits
|
|
23
|
+ .section ".prefix.lib", "awx", @progbits
|
7
|
24
|
|
8
|
25
|
/****************************************************************************
|
9
|
|
- * alloc_basemem (real-mode near call)
|
|
26
|
+ * install_block (real-mode near call)
|
10
|
27
|
*
|
11
|
|
- * Allocate space from base memory via the BIOS free base memory
|
12
|
|
- * counter at 40: 13
|
|
28
|
+ * Install block to specified address
|
13
|
29
|
*
|
14
|
|
- * Parameters:
|
15
|
|
- * %cx : Number of bytes to allocate
|
|
30
|
+ * Parameters:
|
|
31
|
+ * %esi : byte offset within loaded image (must be a multiple of 16)
|
|
32
|
+ * %es:edi : destination address
|
|
33
|
+ * %ecx : length to install
|
16
|
34
|
* Returns:
|
17
|
|
- * %es : Segment address of newly allocated memory
|
|
35
|
+ * none
|
|
36
|
+ * Corrupts:
|
|
37
|
+ * %esi, %edi, %ecx
|
18
|
38
|
****************************************************************************
|
19
|
39
|
*/
|
20
|
|
- .section ".prefix"
|
|
40
|
+ .section ".prefix.lib"
|
21
|
41
|
.code16
|
22
|
|
-alloc_basemem:
|
|
42
|
+install_block:
|
23
|
43
|
/* Preserve registers */
|
24
|
|
- pushw %cx
|
|
44
|
+ pushw %ds
|
25
|
45
|
pushw %ax
|
26
|
46
|
|
27
|
|
- /* %fs = 0x40, %ax = fbms */
|
|
47
|
+ /* Starting segment => %ds */
|
|
48
|
+ movw %cs, %ax
|
|
49
|
+ shrl $4, %esi
|
|
50
|
+ addw %si, %ax
|
|
51
|
+ movw %ax, %ds
|
|
52
|
+ xorl %esi, %esi
|
|
53
|
+
|
|
54
|
+ /* Do the copy */
|
|
55
|
+ cld
|
|
56
|
+ addr32 rep movsb /* or "call decompress16" */
|
|
57
|
+
|
|
58
|
+ /* Restore registers */
|
|
59
|
+ popw %ax
|
|
60
|
+ popw %ds
|
|
61
|
+ ret
|
|
62
|
+ .size install_block, . - install_block
|
|
63
|
+
|
|
64
|
+/****************************************************************************
|
|
65
|
+ * alloc_basemem (real-mode near call)
|
|
66
|
+ *
|
|
67
|
+ * Allocate space for .text16 and .data16 from top of base memory.
|
|
68
|
+ * Memory is allocated using the BIOS free base memory counter at
|
|
69
|
+ * 0x40:13.
|
|
70
|
+ *
|
|
71
|
+ * Parameters:
|
|
72
|
+ * none
|
|
73
|
+ * Returns:
|
|
74
|
+ * %ax : .text16 segment address
|
|
75
|
+ * %bx : .data16 segment address
|
|
76
|
+ * Corrupts:
|
|
77
|
+ * none
|
|
78
|
+ ****************************************************************************
|
|
79
|
+ */
|
|
80
|
+ .section ".prefix.lib"
|
|
81
|
+ .code16
|
|
82
|
+alloc_basemem:
|
|
83
|
+ /* FBMS => %ax as segment address */
|
28
|
84
|
movw $40, %ax
|
29
|
85
|
movw %ax, %fs
|
30
|
|
-
|
31
|
|
- /* Round up %cx to nearest kB, subtract from FBMS */
|
32
|
|
- addw $0x03ff, %cx
|
33
|
|
- andw $0xfc00, %cx
|
34
|
|
- shrw $10, %cx
|
35
|
86
|
movw %fs:0x13, %ax
|
36
|
|
- subw %cx, %ax
|
37
|
|
- movw %ax, %fs:0x13
|
38
|
|
-
|
39
|
|
- /* Convert to segment address in %es */
|
40
|
87
|
shlw $6, %ax
|
41
|
|
- movw %ax, %es
|
42
|
88
|
|
43
|
|
- /* Restore registers and return */
|
|
89
|
+ /* .data16 segment address */
|
|
90
|
+ subw $_data16_size, %ax
|
|
91
|
+ pushw %ax
|
|
92
|
+
|
|
93
|
+ /* .text16 segment address */
|
|
94
|
+ subw $_text16_size, %ax
|
|
95
|
+ pushw %ax
|
|
96
|
+
|
|
97
|
+ /* Update FBMS */
|
|
98
|
+ shrw $6, %ax
|
|
99
|
+ movw %ax, %fs:0x13
|
|
100
|
+
|
|
101
|
+ /* Return */
|
44
|
102
|
popw %ax
|
45
|
|
- popw %cx
|
|
103
|
+ popw %bx
|
46
|
104
|
ret
|
|
105
|
+ .size alloc_basemem, . - alloc_basemem
|
47
|
106
|
|
|
107
|
+/****************************************************************************
|
|
108
|
+ * install_basemem (real-mode near call)
|
|
109
|
+ *
|
|
110
|
+ * Install .text16 and .data16 into base memory
|
|
111
|
+ *
|
|
112
|
+ * Parameters:
|
|
113
|
+ * %ax : .text16 segment address
|
|
114
|
+ * %bx : .data16 segment address
|
|
115
|
+ * Returns:
|
|
116
|
+ * none
|
|
117
|
+ * Corrupts:
|
|
118
|
+ * none
|
|
119
|
+ ****************************************************************************
|
|
120
|
+ */
|
|
121
|
+ .section ".prefix.lib"
|
|
122
|
+ .code16
|
|
123
|
+install_basemem:
|
|
124
|
+ /* Preserve registers */
|
|
125
|
+ pushw %es
|
|
126
|
+ pushl %esi
|
|
127
|
+ pushl %edi
|
|
128
|
+ pushl %ecx
|
|
129
|
+
|
|
130
|
+ /* Install .text16 */
|
|
131
|
+ movw %ax, %es
|
|
132
|
+ xorl %edi, %edi
|
|
133
|
+ movl $_text16_load_offset, %esi
|
|
134
|
+ movl $_text16_size, %ecx
|
|
135
|
+ call install_block
|
48
|
136
|
|
49
|
|
- .section ".prefix"
|
|
137
|
+ /* Install .data16 */
|
|
138
|
+ movw %bx, %es
|
|
139
|
+ xorl %edi, %edi
|
|
140
|
+ movl $_data16_load_offset_pgh, %esi
|
|
141
|
+ movl $_data16_progbits_size, %ecx
|
|
142
|
+ call install_block
|
|
143
|
+
|
|
144
|
+ /* Restore registers */
|
|
145
|
+ popl %ecx
|
|
146
|
+ popl %edi
|
|
147
|
+ popl %esi
|
|
148
|
+ popw %es
|
|
149
|
+ ret
|
|
150
|
+ .size install_basemem, . - install_basemem
|
|
151
|
+
|
|
152
|
+/****************************************************************************
|
|
153
|
+ * GDT for flat real mode
|
|
154
|
+ *
|
|
155
|
+ * We only ever use this GDT to set segment limits; the bases are
|
|
156
|
+ * unused. Also, we only flatten data segments, so we don't need to
|
|
157
|
+ * worry about the code or stack segments. This makes everything much
|
|
158
|
+ * simpler.
|
|
159
|
+ ****************************************************************************
|
|
160
|
+ */
|
|
161
|
+ .section ".prefix.lib"
|
50
|
162
|
.align 16
|
51
|
163
|
gdt:
|
52
|
164
|
gdt_limit: .word gdt_length - 1
|
53
|
|
-gdt_base: .long gdt
|
|
165
|
+gdt_base: .long 0
|
54
|
166
|
.word 0 /* padding */
|
55
|
167
|
|
56
|
|
-cs16: /* 16 bit code segment, base at real-mode %cs:0000 */
|
57
|
|
- .equ CS16, cs16 - gdt
|
58
|
|
- .word 0xffff, 0
|
59
|
|
- .byte 0, 0x9b, 0, 0
|
60
|
|
-
|
61
|
|
-ss16: /* 16 bit stack segment, base at real-mode %ss:0000 */
|
62
|
|
- .equ SS16, ss16 - gdt
|
|
168
|
+real_ds: /* Genuine real mode data segment */
|
|
169
|
+ .equ REAL_DS, real_ds - gdt
|
63
|
170
|
.word 0xffff, 0
|
64
|
171
|
.byte 0, 0x93, 0, 0
|
65
|
172
|
|
66
|
|
-flat_ds: /* 16 bit data segment, zero base, 4GB limit */
|
|
173
|
+flat_ds: /* Flat real mode data segment */
|
67
|
174
|
.equ FLAT_DS, flat_ds - gdt
|
68
|
175
|
.word 0xffff, 0
|
69
|
|
- .byte 0, 0x9f, 0xcf, 0
|
70
|
|
-
|
|
176
|
+ .byte 0, 0x93, 0xcf, 0
|
|
177
|
+
|
71
|
178
|
gdt_end:
|
72
|
179
|
.equ gdt_length, gdt_end - gdt
|
|
180
|
+ .size gdt, . - gdt
|
73
|
181
|
|
74
|
|
-
|
75
|
|
-
|
76
|
|
-
|
77
|
|
- .section ".prefix"
|
|
182
|
+/****************************************************************************
|
|
183
|
+ * set_segment_limits (real-mode near call)
|
|
184
|
+ *
|
|
185
|
+ * Sets limits on the data segments %ds and %es.
|
|
186
|
+ *
|
|
187
|
+ * Parameters:
|
|
188
|
+ * %cx : Segment limit ($REAL_DS or $FLAT_DS)
|
|
189
|
+ ****************************************************************************
|
|
190
|
+ */
|
|
191
|
+ .section ".prefix.lib"
|
78
|
192
|
.code16
|
79
|
|
-prot16_call:
|
80
|
|
-
|
|
193
|
+set_segment_limits:
|
|
194
|
+ /* Preserve real-mode segment values and temporary registers */
|
|
195
|
+ pushw %es
|
|
196
|
+ pushw %ds
|
|
197
|
+ pushl %eax
|
81
|
198
|
|
82
|
|
- /* Install .data16 to top of base memory */
|
83
|
|
- movw %cs, %ax
|
84
|
|
- addw $_data16_load_offset_pgh, %ax
|
85
|
|
- movw %ax, %ds
|
86
|
|
- movw $_data16_size, %cx
|
87
|
|
- call alloc_basemem
|
88
|
|
- xorw %si, %si
|
89
|
|
- xorw %di, %di
|
90
|
|
- movw $_data16_progbits_size, %cx
|
91
|
|
- rep movsb /* or "call decompress16" */
|
92
|
|
-
|
93
|
|
- /* Install .code16 to top of base memory */
|
94
|
|
- movw %cs, %ax
|
95
|
|
- addw $_code16_load_offset_pgh, %ax
|
96
|
|
- movw %ax, %ds
|
97
|
|
- movw $_code16_size, %cx
|
98
|
|
- call alloc_basemem
|
99
|
|
- xorw %si, %si
|
100
|
|
- xorw %di, %di
|
101
|
|
- rep movsb /* or "call decompress16" */
|
102
|
|
-
|
103
|
|
- /* Push flags and real-mode segment registers */
|
104
|
|
- pushfl
|
105
|
|
- push %gs
|
106
|
|
- push %fs
|
107
|
|
- push %es
|
108
|
|
- push %ds
|
109
|
|
- push %ss
|
110
|
|
- push %cs
|
111
|
|
-
|
112
|
|
- /* Physical address of %cs:0000 to %ebx, of %ss:0000 to %eax */
|
113
|
|
- xorl %ebx, %ebx
|
114
|
|
- movw %cs, %bx
|
115
|
|
- shll $4, %ebx
|
|
199
|
+ /* Set GDT base and load GDT */
|
116
|
200
|
xorl %eax, %eax
|
117
|
|
- movw %ss, %ax
|
118
|
|
- shll $4, %eax
|
119
|
|
-
|
120
|
|
- /* Set up GDT and switch to protected mode */
|
121
|
|
- addl %ebx, %cs:gdt_base
|
122
|
|
- orl %ebx, %cs:(cs16+2)
|
123
|
|
- orl %eax, %cs:(ss16+2)
|
124
|
|
- cli
|
125
|
|
- data32 lgdt %cs:gdt
|
|
201
|
+ movw %cs, %ax
|
|
202
|
+ shrl $4, %eax
|
|
203
|
+ addl $gdt, %eax
|
|
204
|
+ movl %eax, %cs:gdt_base
|
|
205
|
+ lgdt %cs:gdt
|
|
206
|
+
|
|
207
|
+ /* Switch to protected mode, set segment limits, switch back */
|
126
|
208
|
movl %cr0, %eax
|
127
|
209
|
orb $CR0_PE, %al
|
128
|
210
|
movl %eax, %cr0
|
129
|
|
- data32 ljmp $CS16, $1f
|
130
|
|
-1: movw $SS16, %ax
|
131
|
|
- movw %ax, %ss
|
132
|
|
- movw $FLAT_DS, %ax
|
133
|
|
- movw %ax, %ds
|
134
|
|
- movw %ax, %es
|
135
|
|
- movw %ax, %fs
|
136
|
|
- movw %ax, %gs
|
137
|
|
-
|
138
|
|
- /* Install .text and .data to 2MB mark. Use 2MB to avoid
|
139
|
|
- * having to deal with A20.
|
140
|
|
- */
|
141
|
|
- leal _text_load_offset(%ebx), %esi
|
142
|
|
- movl $( 2 * 1024 * 1024 ), %edi
|
143
|
|
- movl $_text_and_data_progbits_size, %ecx
|
144
|
|
- addr32 rep movsb /* or "call decompress16" */
|
145
|
|
-
|
146
|
|
- /* Restore real-mode segment limits */
|
147
|
|
- movw %ss, %ax
|
148
|
|
- movw %ax, %ds
|
149
|
|
- movw %ax, %es
|
150
|
|
- movw %ax, %fs
|
151
|
|
- movw %ax, %gs
|
152
|
|
-
|
153
|
|
- /* Return to real mode, restore segment registers and flags */
|
154
|
|
- pushw $1f
|
155
|
|
- movl %cr0, %eax
|
|
211
|
+ movw %cx, %ds
|
|
212
|
+ movw %cx, %es
|
156
|
213
|
andb $0!CR0_PE, %al
|
157
|
214
|
movl %eax, %cr0
|
158
|
|
- lret /* used as equivalent of pop %cs */
|
159
|
|
-1: pop %ss
|
160
|
|
- pop %ds
|
161
|
|
- pop %es
|
162
|
|
- pop %fs
|
163
|
|
- pop %gs
|
164
|
|
- popfl
|
165
|
215
|
|
166
|
|
- /* Call init_gdt */
|
167
|
|
- pushw %cs
|
168
|
|
- pushw $1f
|
169
|
|
- pushw %es
|
170
|
|
- pushw $init_gdt
|
171
|
|
- lret /* lcall %es:init_gdt */
|
172
|
|
-1:
|
173
|
|
-
|
174
|
|
-
|
175
|
|
-
|
|
216
|
+ /* Restore real-mode segment values and temporary registers */
|
|
217
|
+ popl %eax
|
|
218
|
+ popw %ds
|
|
219
|
+ popw %es
|
176
|
220
|
ret
|
|
221
|
+ .size set_segment_limits, . - set_segment_limits
|
177
|
222
|
|
|
223
|
+/****************************************************************************
|
|
224
|
+ * install_highmem (real-mode near call)
|
|
225
|
+ *
|
|
226
|
+ * Install .text and .data into high memory
|
|
227
|
+ *
|
|
228
|
+ * Parameters:
|
|
229
|
+ * %edi : physical address in high memory
|
|
230
|
+ * Returns:
|
|
231
|
+ * none
|
|
232
|
+ * Corrupts:
|
|
233
|
+ * none
|
|
234
|
+ ****************************************************************************
|
|
235
|
+ */
|
|
236
|
+ .section ".prefix.lib"
|
|
237
|
+ .code16
|
|
238
|
+install_highmem:
|
|
239
|
+ /* Preserve registers and interrupt status */
|
|
240
|
+ pushfl
|
|
241
|
+ pushl %esi
|
|
242
|
+ pushl %edi
|
|
243
|
+ pushl %ecx
|
|
244
|
+
|
|
245
|
+ /* Disable interrupts and flatten real mode */
|
|
246
|
+ cli
|
|
247
|
+ movw $FLAT_DS, %cx
|
|
248
|
+ call set_segment_limits
|
|
249
|
+
|
|
250
|
+ /* Install .text and .data to specified address */
|
|
251
|
+ xorw %ax, %ax
|
|
252
|
+ movw %ax, %es
|
|
253
|
+ movl $_text_load_offset, %esi
|
|
254
|
+ movl $_text_and_data_progbits_size, %ecx
|
|
255
|
+ call install_block
|
178
|
256
|
|
|
257
|
+ /* Unflatten real mode */
|
|
258
|
+ movw $REAL_DS, %cx
|
|
259
|
+ call set_segment_limits
|
|
260
|
+
|
|
261
|
+ /* Restore registers and interrupt status */
|
|
262
|
+ popl %ecx
|
|
263
|
+ popl %edi
|
|
264
|
+ popl %esi
|
|
265
|
+ popfl
|
|
266
|
+ ret
|
|
267
|
+ .size install_highmem, . - install_highmem
|