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