1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
|
/*
* Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/**
* High memory temporary load address
*
* Temporary buffer into which to copy (or decompress) our runtime
* image, prior to calling get_memmap() and relocate(). We don't
* actually leave anything here once install() has returned.
*
* We use the start of an even megabyte so that we don't have to worry
* about the current state of the A20 line.
*
* We use 4MB rather than 2MB because there is at least one commercial
* PXE ROM ("Broadcom UNDI, PXE-2.1 (build 082) v2.0.4") which stores
* data required by the UNDI ROM loader (yes, the ROM loader; that's
* the component which should be impossible to damage short of
* screwing with the MMU) around the 2MB mark. Sadly, this is not a
* joke.
*
*/
#define HIGHMEM_LOADPOINT ( 4 << 20 )
#define CR0_PE 1
.arch i386
.section ".prefix.lib", "awx", @progbits
.section ".data16", "aw", @progbits
/****************************************************************************
* install_block (real-mode near call)
*
* Install block to specified address
*
* Parameters:
* %esi : start offset within loaded image (must be a multiple of 16)
* %es:edi : destination address
* %ecx : length of (decompressed) data
* %edx : total length of block (including any uninitialised data portion)
* Returns:
* %esi : end offset within image (rounded up to next multiple of 16)
* Corrupts:
* %edi, %ecx, %edx
****************************************************************************
*/
.section ".prefix.lib"
.code16
install_block:
/* Preserve registers */
pushw %ds
pushl %eax
pushl %ebx
movl %esi, %ebx
/* Starting segment => %ds */
movw %cs, %ax
shrl $4, %esi
addw %si, %ax
movw %ax, %ds
xorl %esi, %esi
/* Calculate start and length of uninitialised data portion */
addr32 leal (%edi,%ecx), %eax
subl %ecx, %edx
/* Do the copy */
cld
rep addr32 movsb /* or "call decompress16" */
/* Zero remaining space */
movl %eax, %edi
movl %edx, %ecx
xorb %al, %al
rep addr32 stosb
/* Adjust %esi */
addl %ebx, %esi
addl $0xf, %esi
andl $~0xf, %esi
/* Restore registers */
popl %ebx
popl %eax
popw %ds
ret
.size install_block, . - install_block
/****************************************************************************
* alloc_basemem (real-mode near call)
*
* Allocate space for .text16 and .data16 from top of base memory.
* Memory is allocated using the BIOS free base memory counter at
* 0x40:13.
*
* Parameters:
* none
* Returns:
* %ax : .text16 segment address
* %bx : .data16 segment address
* Corrupts:
* none
****************************************************************************
*/
.section ".prefix.lib"
.code16
alloc_basemem:
/* FBMS => %ax as segment address */
movw $0x40, %ax
movw %ax, %fs
movw %fs:0x13, %ax
shlw $6, %ax
/* .data16 segment address */
subw $_data16_size_pgh, %ax
pushw %ax
/* .text16 segment address */
subw $_text16_size_pgh, %ax
pushw %ax
/* Update FBMS */
shrw $6, %ax
movw %ax, %fs:0x13
/* Return */
popw %ax
popw %bx
ret
.size alloc_basemem, . - alloc_basemem
/****************************************************************************
* install_basemem (real-mode near call)
*
* Install .text16 and .data16 into base memory
*
* Parameters:
* %ax : .text16 segment address
* %bx : .data16 segment address
* %esi : start offset within loaded image (must be a multiple of 16)
* Returns:
* %esi : end offset within image (rounded up to next multiple of 16)
* Corrupts:
* none
****************************************************************************
*/
.section ".prefix.lib"
.code16
install_basemem:
/* Preserve registers */
pushw %es
pushl %edi
pushl %ecx
pushl %edx
/* Install .text16 */
movw %ax, %es
xorl %edi, %edi
movl $_text16_size, %ecx
movl %ecx, %edx
call install_block
/* Install .data16 */
movw %bx, %es
xorl %edi, %edi
movl $_data16_progbits_size, %ecx
movl $_data16_size, %edx
call install_block
/* Restore registers */
popl %edx
popl %ecx
popl %edi
popw %es
ret
.size install_basemem, . - install_basemem
/****************************************************************************
* install_highmem (flat real-mode near call)
*
* Install .text and .data into high memory
*
* Parameters:
* %esi : start offset within loaded image (must be a multiple of 16)
* %es:edi : address in high memory
* Returns:
* %esi : end offset within image (rounded up to next multiple of 16)
* Corrupts:
* none
****************************************************************************
*/
#ifndef KEEP_IT_REAL
.section ".prefix.lib"
.code16
install_highmem:
/* Preserve registers */
pushl %edi
pushl %ecx
pushl %edx
/* Install .text and .data to specified address */
movl $_textdata_progbits_size, %ecx
movl $_textdata_size, %edx
call install_block
/* Restore registers and interrupt status */
popl %edx
popl %ecx
popl %edi
ret
.size install_highmem, . - install_highmem
#endif /* KEEP_IT_REAL */
/****************************************************************************
* GDT for flat real mode
*
* We only ever use this GDT to set segment limits; the bases are
* unused. Also, we only change data segments, so we don't need to
* worry about the code or stack segments. This makes everything much
* simpler.
****************************************************************************
*/
#ifndef KEEP_IT_REAL
.section ".prefix.lib"
.align 16
gdt:
gdt_limit: .word gdt_length - 1
gdt_base: .long 0
.word 0 /* padding */
flat_ds: /* Flat real mode data segment */
.equ FLAT_DS, flat_ds - gdt
.word 0xffff, 0
.byte 0, 0x93, 0xcf, 0
real_ds: /* Normal real mode data segment */
.equ REAL_DS, real_ds - gdt
.word 0xffff, 0
.byte 0, 0x93, 0x00, 0
gdt_end:
.equ gdt_length, gdt_end - gdt
.size gdt, . - gdt
#endif /* KEEP_IT_REAL */
/****************************************************************************
* set_real_mode_limits (real-mode near call)
*
* Sets limits on the data segments %ds and %es.
*
* Parameters:
* %cx : segment type (FLAT_DS for 4GB or REAL_DS for 64kB)
****************************************************************************
*/
#ifndef KEEP_IT_REAL
.section ".prefix.lib"
.code16
set_real_mode_limits:
/* Preserve real-mode segment values and temporary registers */
pushw %es
pushw %ds
pushw %bp
pushl %eax
/* Set GDT base and load GDT */
xorl %eax, %eax
movw %cs, %ax
shll $4, %eax
addl $gdt, %eax
pushl %eax
pushw %cs:gdt_limit
movw %sp, %bp
lgdt (%bp)
addw $6, %sp
/* Switch to protected mode */
movl %cr0, %eax
orb $CR0_PE, %al
movl %eax, %cr0
/* Set flat segment limits */
movw %cx, %ds
movw %cx, %es
/* Switch back to real mode */
movl %cr0, %eax
andb $0!CR0_PE, %al
movl %eax, %cr0
/* Restore real-mode segment values and temporary registers */
popl %eax
popw %bp
popw %ds
popw %es
ret
.size set_real_mode_limits, . - set_real_mode_limits
#endif /* KEEP_IT_REAL */
/****************************************************************************
* install (real-mode near call)
* install_prealloc (real-mode near call)
*
* Install all text and data segments.
*
* Parameters:
* %ax : .text16 segment address (install_prealloc only)
* %bx : .data16 segment address (install_prealloc only)
* Returns:
* %ax : .text16 segment address
* %bx : .data16 segment address
* %edi : .text physical address (if applicable)
* Corrupts:
* none
****************************************************************************
*/
.section ".prefix.lib"
.code16
.globl install
install:
/* Allocate space for .text16 and .data16 */
call alloc_basemem
.size install, . - install
.globl install_prealloc
install_prealloc:
/* Save registers */
pushl %esi
/* Install .text16 and .data16 */
movl $_payload_offset, %esi
call install_basemem
#ifdef KEEP_IT_REAL
/* Preserve %ds, call init_libkir, restore registers */
pushw %ds
movw %bx, %ds
movw %ax, (init_libkir_vector+2)
lcall *init_libkir_vector
popw %ds
#else
/* Preserve registers and interrupt status, and disable interrupts */
pushfw
pushw %ds
pushw %es
pushl %ecx
cli
/* Load up %ds and %es, and set up vectors for far calls to .text16 */
movw %bx, %ds
xorw %cx, %cx
movw %cx, %es
movw %ax, (init_librm_vector+2)
movw %ax, (prot_call_vector+2)
/* Install .text and .data to temporary area in high memory,
* prior to reading the E820 memory map and relocating
* properly.
*/
movw $FLAT_DS, %cx
call set_real_mode_limits
movl $HIGHMEM_LOADPOINT, %edi
call install_highmem
/* Set up initial protected-mode GDT, call relocate().
* relocate() will return with %esi, %edi and %ecx set up
* ready for the copy to the new location.
*/
lcall *init_librm_vector
pushl $relocate
lcall *prot_call_vector
addw $4, %sp
/* Move code to new location, set up new protected-mode GDT */
movw $FLAT_DS, %cx
call set_real_mode_limits
pushl %edi
es rep addr32 movsb
popl %edi
lcall *init_librm_vector
/* Restore real-mode segment limits */
movw $REAL_DS, %cx
call set_real_mode_limits
/* Restore registers and interrupt status */
popl %ecx
popw %es
popw %ds
popfw
#endif
popl %esi
ret
.size install_prealloc, . - install_prealloc
/* Vectors for far calls to .text16 functions */
.section ".data16"
#ifdef KEEP_IT_REAL
init_libkir_vector:
.word init_libkir
.word 0
.size init_libkir_vector, . - init_libkir_vector
#else
init_librm_vector:
.word init_librm
.word 0
.size init_librm_vector, . - init_librm_vector
prot_call_vector:
.word prot_call
.word 0
.size prot_call_vector, . - prot_call_vector
#endif
|