Verified as working
[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         .globl alloc_basemem
83 alloc_basemem:
84         /* FBMS => %ax as segment address */
85         movw    $0x40, %ax
86         movw    %ax, %fs
87         movw    %fs:0x13, %ax
88         shlw    $6, %ax
89
90         /* .data16 segment address */
91         subw    $_data16_size, %ax
92         pushw   %ax
93
94         /* .text16 segment address */
95         subw    $_text16_size, %ax
96         pushw   %ax
97
98         /* Update FBMS */
99         shrw    $6, %ax
100         movw    %ax, %fs:0x13
101
102         /* Return */
103         popw    %ax
104         popw    %bx
105         ret
106         .size alloc_basemem, . - alloc_basemem
107
108 /****************************************************************************
109  * install_basemem (real-mode near call)
110  *
111  * Install .text16 and .data16 into base memory
112  *
113  * Parameters: 
114  *   %ax : .text16 segment address
115  *   %bx : .data16 segment address
116  * Returns:
117  *   none
118  * Corrupts:
119  *   none
120  ****************************************************************************
121  */
122         .section ".prefix.lib"
123         .code16
124         .globl install_basemem
125 install_basemem:
126         /* Preserve registers */
127         pushw   %es
128         pushl   %esi
129         pushl   %edi
130         pushl   %ecx
131
132         /* Install .text16 */
133         movw    %ax, %es
134         xorl    %edi, %edi
135         movl    $_text16_load_offset, %esi
136         movl    $_text16_size, %ecx
137         call    install_block
138
139         /* Install .data16 */
140         movw    %bx, %es
141         xorl    %edi, %edi      
142         movl    $_data16_load_offset, %esi
143         movl    $_data16_progbits_size, %ecx
144         call    install_block
145
146         /* Restore registers */
147         popl    %ecx
148         popl    %edi
149         popl    %esi
150         popw    %es
151         ret
152         .size install_basemem, . - install_basemem
153
154 /****************************************************************************
155  * GDT for flat real mode
156  *
157  * We only ever use this GDT to set segment limits; the bases are
158  * unused.  Also, we only flatten data segments, so we don't need to
159  * worry about the code or stack segments.  This makes everything much
160  * simpler.
161  ****************************************************************************
162  */
163         .section ".prefix.lib"
164         .align 16
165 gdt:
166 gdt_limit:              .word gdt_length - 1
167 gdt_base:               .long 0
168                         .word 0 /* padding */
169
170 real_ds:        /* Genuine real mode data segment */
171         .equ    REAL_DS, real_ds - gdt
172         .word   0xffff, 0
173         .byte   0, 0x93, 0, 0
174
175 flat_ds:        /* Flat real mode data segment */
176         .equ    FLAT_DS, flat_ds - gdt
177         .word   0xffff, 0
178         .byte   0, 0x93, 0xcf, 0
179
180 gdt_end:
181         .equ    gdt_length, gdt_end - gdt
182         .size gdt, . - gdt
183
184 /****************************************************************************
185  * set_segment_limits (real-mode near call)
186  *
187  * Sets limits on the data segments %ds and %es.
188  *
189  * Parameters: 
190  *   %cx : Segment limit ($REAL_DS or $FLAT_DS)
191  ****************************************************************************
192  */
193         .section ".prefix.lib"
194         .code16
195 set_segment_limits:
196         /* Preserve real-mode segment values and temporary registers */
197         pushw   %es
198         pushw   %ds
199         pushl   %eax
200
201         /* Set GDT base and load GDT */
202         xorl    %eax, %eax
203         movw    %cs, %ax
204         shll    $4, %eax
205         addl    $gdt, %eax
206         movl    %eax, %cs:gdt_base
207         lgdt    %cs:gdt
208
209         /* Switch to protected mode, set segment limits, switch back */
210         movl    %cr0, %eax
211         orb     $CR0_PE, %al
212         movl    %eax, %cr0
213         movw    %cx, %ds
214         movw    %cx, %es
215         andb    $0!CR0_PE, %al
216         movl    %eax, %cr0
217
218         /* Restore real-mode segment values and temporary registers */
219         popl    %eax
220         popw    %ds
221         popw    %es
222         ret
223         .size set_segment_limits, . - set_segment_limits
224         
225 /****************************************************************************
226  * install_highmem (real-mode near call)
227  *
228  * Install .text and .data into high memory
229  *
230  * Parameters:
231  *   %edi : physical address in high memory
232  * Returns:
233  *   none
234  * Corrupts:
235  *   none
236  ****************************************************************************
237  */
238         .section ".prefix.lib"
239         .code16
240         .globl install_highmem
241 install_highmem:
242         /* Preserve registers and interrupt status */
243         pushfl
244         pushl   %esi
245         pushl   %edi
246         pushl   %ecx
247                 
248         /* Disable interrupts and flatten real mode */
249         cli
250         movw    $FLAT_DS, %cx
251         call    set_segment_limits
252
253         /* Install .text and .data to specified address */
254         xorw    %cx, %cx
255         movw    %cx, %es
256         movl    $_text_load_offset, %esi
257         movl    $_text_progbits_size, %ecx
258         call    install_block
259
260         /* Unflatten real mode */
261         movw    $REAL_DS, %cx
262         call    set_segment_limits
263
264         /* Restore registers and interrupt status */
265         popl    %ecx
266         popl    %edi
267         popl    %esi
268         popfl
269         ret
270         .size install_highmem, . - install_highmem