f87ba3305679f1732899f20036fd2c498dcdc913
[people/xl0/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 #define CR0_PE 1
21
22         .arch i386
23         .section ".prefix.lib", "awx", @progbits
24
25 /****************************************************************************
26  * install_block (real-mode near call)
27  *
28  * Install block to specified address
29  *
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
34  * Returns:
35  *   none
36  * Corrupts:
37  *   %esi, %edi, %ecx
38  ****************************************************************************
39  */
40         .section ".prefix.lib"
41         .code16
42 install_block:
43         /* Preserve registers */
44         pushw   %ds
45         pushw   %ax
46         
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 */
84         movw    $40, %ax
85         movw    %ax, %fs
86         movw    %fs:0x13, %ax
87         shlw    $6, %ax
88
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 */
102         popw    %ax
103         popw    %bx
104         ret
105         .size alloc_basemem, . - alloc_basemem
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
136
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"
162         .align 16
163 gdt:
164 gdt_limit:              .word gdt_length - 1
165 gdt_base:               .long 0
166                         .word 0 /* padding */
167
168 real_ds:        /* Genuine real mode data segment */
169         .equ    REAL_DS, real_ds - gdt
170         .word   0xffff, 0
171         .byte   0, 0x93, 0, 0
172
173 flat_ds:        /* Flat real mode data segment */
174         .equ    FLAT_DS, flat_ds - gdt
175         .word   0xffff, 0
176         .byte   0, 0x93, 0xcf, 0
177
178 gdt_end:
179         .equ    gdt_length, gdt_end - gdt
180         .size gdt, . - gdt
181
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"
192         .code16
193 set_segment_limits:
194         /* Preserve real-mode segment values and temporary registers */
195         pushw   %es
196         pushw   %ds
197         pushl   %eax
198
199         /* Set GDT base and load GDT */
200         xorl    %eax, %eax
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 */
208         movl    %cr0, %eax
209         orb     $CR0_PE, %al
210         movl    %eax, %cr0
211         movw    %cx, %ds
212         movw    %cx, %es
213         andb    $0!CR0_PE, %al
214         movl    %eax, %cr0
215
216         /* Restore real-mode segment values and temporary registers */
217         popl    %eax
218         popw    %ds
219         popw    %es
220         ret
221         .size set_segment_limits, . - set_segment_limits
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
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