Checking in because I don't want to lose this rather neat code for
[people/xl0/gpxe.git] / src / arch / i386 / prefix / libprefix.S
1
2 #define CR0_PE 1
3         
4         
5         .arch i386
6         .section ".prefix", "awx", @progbits
7
8 /****************************************************************************
9  * alloc_basemem (real-mode near call)
10  *
11  * Allocate space from base memory via the BIOS free base memory
12  * counter at 40: 13
13  *
14  * Parameters: 
15  *   %cx : Number of bytes to allocate
16  * Returns:
17  *   %es : Segment address of newly allocated memory
18  ****************************************************************************
19  */
20         .section ".prefix"
21         .code16
22 alloc_basemem:
23         /* Preserve registers */
24         pushw   %cx
25         pushw   %ax
26         
27         /* %fs = 0x40, %ax = fbms */
28         movw    $40, %ax
29         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         movw    %fs:0x13, %ax
36         subw    %cx, %ax
37         movw    %ax, %fs:0x13
38
39         /* Convert to segment address in %es */
40         shlw    $6, %ax
41         movw    %ax, %es
42
43         /* Restore registers and return */
44         popw    %ax
45         popw    %cx
46         ret
47
48
49         .section ".prefix"
50         .align 16
51 gdt:
52 gdt_limit:              .word gdt_length - 1
53 gdt_base:               .long gdt
54                         .word 0 /* padding */
55
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
63         .word   0xffff, 0
64         .byte   0, 0x93, 0, 0
65
66 flat_ds:        /* 16 bit data segment, zero base, 4GB limit */
67         .equ    FLAT_DS, flat_ds - gdt
68         .word   0xffff, 0
69         .byte   0, 0x9f, 0xcf, 0
70         
71 gdt_end:
72         .equ    gdt_length, gdt_end - gdt
73
74
75
76         
77         .section ".prefix"
78         .code16
79 prot16_call:
80
81
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
116         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
126         movl    %cr0, %eax
127         orb     $CR0_PE, %al
128         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
156         andb    $0!CR0_PE, %al
157         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
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         
176         ret
177         
178