blob: 9e337215a115b23320e09349e2f05a901b6c9f05 [file] [log] [blame]
Martin Roth9b1b3352016-02-24 12:27:06 -08001/*
2 * linux/boot/head.S
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 */
5
6/*
7 * head.S contains the 32-bit startup code.
8 *
9 * 1-Jan-96 Modified by Chris Brady for use as a boot/loader for MemTest-86.
10 * Setup the memory management for flat non-paged linear addressing.
11 * 17 May 2004 : Added X86_PWRCAP for AMD64 (Memtest86+ - Samuel D.)
12 */
13
14.text
15#define __ASSEMBLY__
Martin Roth8cc1aeb2016-02-24 13:03:52 -080016#define ASM_FILE
Martin Roth9b1b3352016-02-24 12:27:06 -080017#include "defs.h"
18#include "config.h"
19#include "test.h"
Martin Roth8cc1aeb2016-02-24 13:03:52 -080020#include "multiboot.h"
Martin Roth9b1b3352016-02-24 12:27:06 -080021
22 .code32
23 .globl startup_32
24startup_32:
25 cld
26 cli
27
Martin Roth8cc1aeb2016-02-24 13:03:52 -080028 /* Store MBI pointer */
29 xorl %ecx, %ecx
30 cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
31 jne 0f
32 movl %ebx, %ecx
330:
34
Martin Roth9b1b3352016-02-24 12:27:06 -080035 /* Ensure I have a boot_stack pointer */
36 testl %esp, %esp
37 jnz 0f
38 movl $(LOW_TEST_ADR + _GLOBAL_OFFSET_TABLE_), %esp
39 leal boot_stack_top@GOTOFF(%esp), %esp
400:
41
42 /* Load the GOT pointer */
43 call 0f
440: popl %ebx
45 addl $_GLOBAL_OFFSET_TABLE_+[.-0b], %ebx
46
Martin Roth8cc1aeb2016-02-24 13:03:52 -080047 /* Move MBI pointer to a safe place */
48 testl %ecx, %ecx
49 je 0f
50 movl %ecx, mbiptr@GOTOFF(%ebx)
510:
52
53 jmp 0f
54 /* Multiboot header */
55.align 4
56 .long MULTIBOOT_HEADER_MAGIC
57 .long 0
58 .long -MULTIBOOT_HEADER_MAGIC
590:
60
61 /* Pick the appropriate stack address */
Martin Roth9b1b3352016-02-24 12:27:06 -080062 leal boot_stack_top@GOTOFF(%ebx), %esp
63
64 /* Reload all of the segment registers */
65 leal gdt@GOTOFF(%ebx), %eax
66 movl %eax, 2 + gdt_descr@GOTOFF(%ebx)
67 lgdt gdt_descr@GOTOFF(%ebx)
68 leal flush@GOTOFF(%ebx), %eax
69 pushl $KERNEL_CS
70 pushl %eax
71 lret
72flush: movl $KERNEL_DS, %eax
73 movw %ax, %ds
74 movw %ax, %es
75 movw %ax, %fs
76 movw %ax, %gs
77 movw %ax, %ss
78
79/*
80 * Zero BSS
81 */
82 cmpl $1, zerobss@GOTOFF(%ebx)
83 jnz zerobss_done
84 xorl %eax, %eax
85 leal _bss@GOTOFF(%ebx), %edi
86 leal _end@GOTOFF(%ebx), %ecx
87 subl %edi, %ecx
881: movl %eax, (%edi)
89 addl $4, %edi
90 subl $4, %ecx
91 jnz 1b
92 movl $0, zerobss@GOTOFF(%ebx)
93zerobss_done:
94
95/*
96 * Setup an exception handler
97 */
98 leal idt@GOTOFF(%ebx), %edi
99
100 leal vec0@GOTOFF(%ebx), %edx
101 movl $(KERNEL_CS << 16),%eax
102 movw %dx, %ax /* selector = 0x0010 = cs */
103 movw $0x8E00, %dx /* interrupt gate - dpl=0, present */
104 movl %eax, (%edi)
105 movl %edx, 4(%edi)
106 addl $8, %edi
107
108 leal vec1@GOTOFF(%ebx),%edx
109 movl $(KERNEL_CS << 16),%eax
110 movw %dx,%ax /* selector = 0x0010 = cs */
111 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
112 movl %eax,(%edi)
113 movl %edx,4(%edi)
114 addl $8,%edi
115
116 leal vec2@GOTOFF(%ebx),%edx
117 movl $(KERNEL_CS << 16),%eax
118 movw %dx,%ax /* selector = 0x0010 = cs */
119 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
120 movl %eax,(%edi)
121 movl %edx,4(%edi)
122 addl $8,%edi
123
124 leal vec3@GOTOFF(%ebx),%edx
125 movl $(KERNEL_CS << 16),%eax
126 movw %dx,%ax /* selector = 0x0010 = cs */
127 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
128 movl %eax,(%edi)
129 movl %edx,4(%edi)
130 addl $8,%edi
131
132 leal vec4@GOTOFF(%ebx),%edx
133 movl $(KERNEL_CS << 16),%eax
134 movw %dx,%ax /* selector = 0x0010 = cs */
135 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
136 movl %eax,(%edi)
137 movl %edx,4(%edi)
138 addl $8,%edi
139
140 leal vec5@GOTOFF(%ebx),%edx
141 movl $(KERNEL_CS << 16),%eax
142 movw %dx,%ax /* selector = 0x0010 = cs */
143 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
144 movl %eax,(%edi)
145 movl %edx,4(%edi)
146 addl $8,%edi
147
148 leal vec6@GOTOFF(%ebx),%edx
149 movl $(KERNEL_CS << 16),%eax
150 movw %dx,%ax /* selector = 0x0010 = cs */
151 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
152 movl %eax,(%edi)
153 movl %edx,4(%edi)
154 addl $8,%edi
155
156 leal vec7@GOTOFF(%ebx),%edx
157 movl $(KERNEL_CS << 16),%eax
158 movw %dx,%ax /* selector = 0x0010 = cs */
159 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
160 movl %eax,(%edi)
161 movl %edx,4(%edi)
162 addl $8,%edi
163
164 leal vec8@GOTOFF(%ebx),%edx
165 movl $(KERNEL_CS << 16),%eax
166 movw %dx,%ax /* selector = 0x0010 = cs */
167 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
168 movl %eax,(%edi)
169 movl %edx,4(%edi)
170 addl $8,%edi
171
172 leal vec9@GOTOFF(%ebx),%edx
173 movl $(KERNEL_CS << 16),%eax
174 movw %dx,%ax /* selector = 0x0010 = cs */
175 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
176 movl %eax,(%edi)
177 movl %edx,4(%edi)
178 addl $8,%edi
179
180 leal vec10@GOTOFF(%ebx),%edx
181 movl $(KERNEL_CS << 16),%eax
182 movw %dx,%ax /* selector = 0x0010 = cs */
183 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
184 movl %eax,(%edi)
185 movl %edx,4(%edi)
186 addl $8,%edi
187
188 leal vec11@GOTOFF(%ebx),%edx
189 movl $(KERNEL_CS << 16),%eax
190 movw %dx,%ax /* selector = 0x0010 = cs */
191 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
192 movl %eax,(%edi)
193 movl %edx,4(%edi)
194 addl $8,%edi
195
196 leal vec12@GOTOFF(%ebx),%edx
197 movl $(KERNEL_CS << 16),%eax
198 movw %dx,%ax /* selector = 0x0010 = cs */
199 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
200 movl %eax,(%edi)
201 movl %edx,4(%edi)
202 addl $8,%edi
203
204 leal vec13@GOTOFF(%ebx),%edx
205 movl $(KERNEL_CS << 16),%eax
206 movw %dx,%ax /* selector = 0x0010 = cs */
207 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
208 movl %eax,(%edi)
209 movl %edx,4(%edi)
210 addl $8,%edi
211
212 leal vec14@GOTOFF(%ebx),%edx
213 movl $(KERNEL_CS << 16),%eax
214 movw %dx,%ax /* selector = 0x0010 = cs */
215 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
216 movl %eax,(%edi)
217 movl %edx,4(%edi)
218 addl $8,%edi
219
220 leal vec15@GOTOFF(%ebx),%edx
221 movl $(KERNEL_CS << 16),%eax
222 movw %dx,%ax /* selector = 0x0010 = cs */
223 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
224 movl %eax,(%edi)
225 movl %edx,4(%edi)
226 addl $8,%edi
227
228 leal vec16@GOTOFF(%ebx),%edx
229 movl $(KERNEL_CS << 16),%eax
230 movw %dx,%ax /* selector = 0x0010 = cs */
231 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
232 movl %eax,(%edi)
233 movl %edx,4(%edi)
234 addl $8,%edi
235
236 leal vec17@GOTOFF(%ebx),%edx
237 movl $(KERNEL_CS << 16),%eax
238 movw %dx,%ax /* selector = 0x0010 = cs */
239 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
240 movl %eax,(%edi)
241 movl %edx,4(%edi)
242 addl $8,%edi
243
244 leal vec18@GOTOFF(%ebx),%edx
245 movl $(KERNEL_CS << 16),%eax
246 movw %dx,%ax /* selector = 0x0010 = cs */
247 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
248 movl %eax,(%edi)
249 movl %edx,4(%edi)
250 addl $8,%edi
251
252 leal vec19@GOTOFF(%ebx),%edx
253 movl $(KERNEL_CS << 16),%eax
254 movw %dx,%ax /* selector = 0x0010 = cs */
255 movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
256 movl %eax,(%edi)
257 movl %edx,4(%edi)
258 addl $8,%edi
259
260 /* Now that it is initialized load the interrupt descriptor table */
261 leal idt@GOTOFF(%ebx), %eax
262 movl %eax, 2 + idt_descr@GOTOFF(%ebx)
263 lidt idt_descr@GOTOFF(%ebx)
264
265 leal _dl_start@GOTOFF(%ebx), %eax
266 call *%eax
267
Martin Roth4dcd13d2016-02-24 13:53:07 -0800268 /* Never forget to initialize the FPU ... Never ! */
Martin Roth9b1b3352016-02-24 12:27:06 -0800269 finit
270
271 call test_start
272
273 /* In case we return simulate an exception */
274 pushfl
275 pushl %cs
276 call 0f
2770: pushl $0 /* error code */
278 pushl $257 /* vector */
279 jmp int_hand
280
281vec0:
282 pushl $0 /* error code */
283 pushl $0 /* vector */
284 jmp int_hand
285vec1:
286 pushl $0 /* error code */
287 pushl $1 /* vector */
288 jmp int_hand
289
290vec2:
291 pushl $0 /* error code */
292 pushl $2 /* vector */
293 jmp int_hand
294
295vec3:
296 pushl $0 /* error code */
297 pushl $3 /* vector */
298 jmp int_hand
299
300vec4:
301 pushl $0 /* error code */
302 pushl $4 /* vector */
303 jmp int_hand
304
305vec5:
306 pushl $0 /* error code */
307 pushl $5 /* vector */
308 jmp int_hand
309
310vec6:
311 pushl $0 /* error code */
312 pushl $6 /* vector */
313 jmp int_hand
314
315vec7:
316 pushl $0 /* error code */
317 pushl $7 /* vector */
318 jmp int_hand
319
320vec8:
321 /* error code */
322 pushl $8 /* vector */
323 jmp int_hand
324
325vec9:
326 pushl $0 /* error code */
327 pushl $9 /* vector */
328 jmp int_hand
329
330vec10:
331 /* error code */
332 pushl $10 /* vector */
333 jmp int_hand
334
335vec11:
336 /* error code */
337 pushl $11 /* vector */
338 jmp int_hand
339
340vec12:
341 /* error code */
342 pushl $12 /* vector */
343 jmp int_hand
344
345vec13:
346 /* error code */
347 pushl $13 /* vector */
348 jmp int_hand
349
350vec14:
351 /* error code */
352 pushl $14 /* vector */
353 jmp int_hand
354
355vec15:
356 pushl $0 /* error code */
357 pushl $15 /* vector */
358 jmp int_hand
359
360vec16:
361 pushl $0 /* error code */
362 pushl $16 /* vector */
363 jmp int_hand
364
365vec17:
366 /* error code */
367 pushl $17 /* vector */
368 jmp int_hand
369
370vec18:
371 pushl $0 /* error code */
372 pushl $18 /* vector */
373 jmp int_hand
374
375vec19:
376 pushl $0 /* error code */
377 pushl $19 /* vector */
378 jmp int_hand
379
380int_hand:
381 pushl %eax
382 pushl %ebx
383 pushl %ecx
384 pushl %edx
385 pushl %edi
386 pushl %esi
387 pushl %ebp
388
389 /* original boot_stack pointer */
390 leal 48(%esp), %eax
391 pushl %eax
Martin Roth4dcd13d2016-02-24 13:53:07 -0800392 pushl %ds
393 pushl %ss
Martin Roth9b1b3352016-02-24 12:27:06 -0800394 pushl %esp /* pointer to trap regs struct on the boot_stack */
395 call inter
396 addl $8, %esp
397
398 popl %ebp
399 popl %esi
400 popl %edi
401 popl %edx
402 popl %ecx
403 popl %ebx
404 popl %eax
405 iret
406
407/*
408 * The interrupt descriptor table has room for 32 idt's
409 */
410.align 4
411.word 0
412idt_descr:
413 .word 20*8-1 # idt contains 32 entries
414 .long 0
415
416idt:
417 .fill 20,8,0 # idt is uninitialized
418
419gdt_descr:
420 .word gdt_end - gdt - 1
421 .long 0
422
423.align 4
424.globl gdt, gdt_end
425gdt:
426 .quad 0x0000000000000000 /* NULL descriptor */
427 .quad 0x0000000000000000 /* not used */
428 .quad 0x00cf9b000000ffff /* 0x10 main 4gb code at 0x000000 */
429 .quad 0x00cf93000000ffff /* 0x18 main 4gb data at 0x000000 */
430
431 .word 0xFFFF # 16bit 64KB - (0x10000*1 = 64KB)
432 .word 0 # base address = SETUPSEG
433 .byte 0x00, 0x9b # code read/exec/accessed
434 .byte 0x00, 0x00 # granularity = bytes
435
436
437 .word 0xFFFF # 16bit 64KB - (0x10000*1 = 64KB)
438 .word 0 # base address = SETUPSEG
439 .byte 0x00, 0x93 # data read/write/accessed
440 .byte 0x00, 0x00 # granularity = bytes
441
442gdt_end:
443
444.data
445
446.macro ptes64 start, count=64
447.quad \start + 0x0000000 + 0xE3
448.quad \start + 0x0200000 + 0xE3
449.quad \start + 0x0400000 + 0xE3
450.quad \start + 0x0600000 + 0xE3
451.quad \start + 0x0800000 + 0xE3
452.quad \start + 0x0A00000 + 0xE3
453.quad \start + 0x0C00000 + 0xE3
454.quad \start + 0x0E00000 + 0xE3
455.if \count-1
456ptes64 "(\start+0x01000000)",\count-1
457.endif
458.endm
459
460.macro maxdepth depth=1
461.if \depth-1
462maxdepth \depth-1
463.endif
464.endm
465
466maxdepth
467
468# Page Directory Tables:
469# There are 4 tables, the first two map the first 2 GB of memory. The last two are used with # PAE to map
470# the rest of memory in 2 GB segments. The last two tables are changed in vmem.c to map each segment.
Martin Roth4dcd13d2016-02-24 13:53:07 -0800471# We use 2 MB pages so only the Page Directory Table is used (no page tables).
Martin Roth9b1b3352016-02-24 12:27:06 -0800472.balign 4096
473.globl pd0
474pd0:
475 ptes64 0x0000000000000000
476
477.balign 4096
478.globl pd1
479pd1:
480 ptes64 0x0000000040000000
481
482.balign 4096
483.globl pd2
484pd2:
485 ptes64 0x0000000080000000
486
487.balign 4096
488.globl pd3
489pd3:
490 ptes64 0x00000000C0000000
491
492# Legacy Mode Page Directory Pointer Table:
493# 4 Entries, pointing to the Page Directory Tables
494.balign 4096
495.globl pdp
496pdp:
497 .long pd0 + 1
498 .long 0
499 .long pd1 + 1
500 .long 0
501 .long pd2 + 1
502 .long 0
503 .long pd3 + 1
504 .long 0
505
506# Long Mode Page Directory Pointer Table:
507# 4 Entries, pointing to the Page Directory Tables
508.balign 4096
509lpdp:
510 .long pd0 + 3
511 .long 0
512 .long pd1 + 3
513 .long 0
514 .long pd2 + 3
515 .long 0
516 .long pd3 + 3
517 .long 0
518
519
520# The long mode level 4 page map table
521.balign 4096
522.globl pml4
523pml4:
524 .long lpdp + 3
525 .long 0
526.previous
527
528#define RSTART startup_32
529
530 .globl query_pcbios
531query_pcbios:
532 /* Save the caller save registers */
533 pushl %ebx
534 pushl %esi
535 pushl %edi
536 pushl %ebp
537 call 1f
5381: popl %ebx
539 addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
540
541 /* Compute the reloc address */
542 leal RSTART@GOTOFF(%ebx), %esi
543
544 /* Fixup real code pointer */
545 movl %esi, %eax
546 shrl $4, %eax
547 movw %ax, 2 + realptr@GOTOFF(%ebx)
548
549 /* Fixup protected code pointer */
550 leal prot@GOTOFF(%ebx), %eax
551 movl %eax, protptr@GOTOFF(%ebx)
552
553 /* Compute the gdt fixup */
554 movl %esi, %eax
555 shll $16, %eax # Base low
556
557 movl %esi, %ecx
558 shrl $16, %ecx
559 andl $0xff, %ecx
560
561 movl %esi, %edx
562 andl $0xff000000, %edx
563 orl %edx, %ecx
564
565 /* Fixup the gdt */
566 andl $0x0000ffff, REAL_CS + 0 + gdt@GOTOFF(%ebx)
567 orl %eax, REAL_CS + 0 + gdt@GOTOFF(%ebx)
568 andl $0x00ffff00, REAL_CS + 4 + gdt@GOTOFF(%ebx)
569 orl %ecx, REAL_CS + 4 + gdt@GOTOFF(%ebx)
570 andl $0x0000ffff, REAL_DS + 0 + gdt@GOTOFF(%ebx)
571 orl %eax, REAL_DS + 0 + gdt@GOTOFF(%ebx)
572 andl $0x00ffff00, REAL_DS + 4 + gdt@GOTOFF(%ebx)
573 orl %ecx, REAL_DS + 4 + gdt@GOTOFF(%ebx)
574
575 /* Fixup the gdt_descr */
576 leal gdt@GOTOFF(%ebx), %eax
577 movl %eax, 2 + gdt_descr@GOTOFF(%ebx)
578
579 lidt idt_real@GOTOFF(%ebx)
580
581 /* Don't disable the a20 line */
582
583 /* Load 16bit data segments, to ensure the segment limits are set */
584 movl $REAL_DS, %eax
585 movl %eax, %ds
586 movl %eax, %es
587 movl %eax, %ss
588 movl %eax, %fs
589 movl %eax, %gs
590
591 /* Compute the boot_stack base */
592 leal boot_stack@GOTOFF(%ebx), %ecx
593 /* Compute the address of meminfo */
594 leal mem_info@GOTOFF(%ebx), %edi
595
596 /* switch to 16bit mode */
597 ljmp $REAL_CS, $1f - RSTART
5981:
599 .code16
600 /* Disable Paging and protected mode */
601 /* clear the PG & PE bits of CR0 */
602 movl %cr0,%eax
603 andl $~((1 << 31)|(1<<0)),%eax
604 movl %eax,%cr0
605
606 /* make intersegment jmp to flush the processor pipeline
607 * and reload %cs:%eip (to clear upper 16 bits of %eip).
608 */
609 ljmp *(realptr - RSTART)
610real:
611 /* we are in real mode now
612 * set up the real mode segment registers : %ds, %ss, %es, %gs, %fs
613 */
614 movw %cs, %ax
615 movw %ax, %ds
616 movw %ax, %es
617 movw %ax, %fs
618 movw %ax, %gs
619 movw %ax, %ss
620
621 /* Adjust the boot_stack pointer */
622 movl %ecx, %eax
623 shrl $4, %eax
624 movw %ax, %ss
625 subl %ecx, %esp
626
627 /* Save my base pointer */
628 pushl %ebx
629
630 /* Setup %ds to point to my data area */
631 shrl $4, %edi
632 movl %edi, %ds
633
634 /* Enable interrupts or BIOS's go crazy */
635 sti
636
637# Get memory size (extended mem, kB)
638
639#define SMAP 0x534d4150
640
641 xorl %eax, %eax
642 movl %eax, (E88)
643 movl %eax, (E801)
644 movl %eax, (E820NR)
645
646# Try three different memory detection schemes. First, try
647# e820h, which lets us assemble a memory map, then try e801h,
648# which returns a 32-bit memory size, and finally 88h, which
649# returns 0-64m
650
651# method E820H:
652# the memory map from hell. e820h returns memory classified into
653# a whole bunch of different types, and allows memory holes and
654# everything. We scan through this memory map and build a list
655# of the first 32 memory areas, which we return at [E820MAP].
656# This is documented at http://www.teleport.com/~acpi/acpihtml/topic245.htm
657
658meme820:
659 xorl %ebx, %ebx # continuation counter
660 movw $E820MAP, %di # point into the whitelist
661 # so we can have the bios
662 # directly write into it.
663
664jmpe820:
665 movl $0x0000e820, %eax # e820, upper word zeroed
666 movl $SMAP, %edx # ascii 'SMAP'
667 movl $20, %ecx # size of the e820rec
668 pushw %ds # data record.
669 popw %es
670 int $0x15 # make the call
671 jc bail820 # fall to e801 if it fails
672
673 cmpl $SMAP, %eax # check the return is `SMAP'
674 jne bail820 # fall to e801 if it fails
675
676# cmpl $1, 16(%di) # is this usable memory?
677# jne again820
678
679 # If this is usable memory, we save it by simply advancing %di by
680 # sizeof(e820rec).
681 #
682good820:
683 movb (E820NR), %al # up to 32 entries
684 cmpb $E820MAX, %al
685 jnl bail820
686
687 incb (E820NR)
688 movw %di, %ax
689 addw $E820ENTRY_SIZE, %ax
690 movw %ax, %di
691again820:
692 cmpl $0, %ebx # check to see if
693 jne jmpe820 # %ebx is set to EOF
694bail820:
695
696
697# method E801H:
698# memory size is in 1k chunksizes, to avoid confusing loadlin.
699# we store the 0xe801 memory size in a completely different place,
700# because it will most likely be longer than 16 bits.
701
702meme801:
703 stc # fix to work around buggy
704 xorw %cx,%cx # BIOSes which dont clear/set
705 xorw %dx,%dx # carry on pass/error of
706 # e801h memory size call
707 # or merely pass cx,dx though
708 # without changing them.
709 movw $0xe801, %ax
710 int $0x15
711 jc mem88
712
713 cmpw $0x0, %cx # Kludge to handle BIOSes
714 jne e801usecxdx # which report their extended
715 cmpw $0x0, %dx # memory in AX/BX rather than
716 jne e801usecxdx # CX/DX. The spec I have read
717 movw %ax, %cx # seems to indicate AX/BX
718 movw %bx, %dx # are more reasonable anyway...
719
720e801usecxdx:
721 andl $0xffff, %edx # clear sign extend
722 shll $6, %edx # and go from 64k to 1k chunks
723 movl %edx, (E801) # store extended memory size
724 andl $0xffff, %ecx # clear sign extend
725 addl %ecx, (E801) # and add lower memory into
726 # total size.
727
728# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or
729# 64mb, depending on the bios) in ax.
730mem88:
731
732 movb $0x88, %ah
733 int $0x15
734 movw %ax, (E88)
735
736#ifdef APM_OFF
737# check for APM BIOS
738 movw $0x5300, %ax # APM BIOS installation check
739 xorw %bx, %bx
740 int $0x15
741 jc done_apm_bios # error -> no APM BIOS
742
743 cmpw $0x504d, %bx # check for "PM" signature
744 jne done_apm_bios # no signature -> no APM BIOS
745
746 movw $0x5304, %ax # Disconnect first just in case
747 xorw %bx, %bx
748 int $0x15 # ignore return code
749
750 movw $0x5301, %ax # Real Mode connect
751 xorw %bx, %bx
752 int $0x15
753 jc done_apm_bios # error
754
755 movw $0x5308, %ax # Disable APM
756 mov $0xffff, %bx
757 xorw %cx, %cx
758 int $0x15
759
760done_apm_bios:
761#endif
762
763 /* O.k. the BIOS query is done switch back to protected mode */
764 cli
765
766 /* Restore my saved variables */
767 popl %ebx
768
769 /* Get an convinient %ds */
770 movw %cs, %ax
771 movw %ax, %ds
772
773 /* Load the global descriptor table */
774 addr32 lgdt gdt_descr - RSTART
775
776 /* Turn on protected mode */
777 /* Set the PE bit in CR0 */
778 movl %cr0,%eax
779 orl $(1<<0),%eax
780 movl %eax,%cr0
781
782 /* flush the prefetch queue, and relaod %cs:%eip */
783 data32 ljmp *(protptr - RSTART)
784prot:
785 .code32
786 /* Reload other segment registers */
787 movl $KERNEL_DS, %eax
788 movl %eax, %ds
789 movl %eax, %es
790 movl %eax, %fs
791 movl %eax, %gs
792 movl %eax, %ss
793
794 /* Adjust the boot_stack pointer */
795 leal boot_stack@GOTOFF(%ebx), %eax
796 addl %eax, %esp
797
798 /* Restore the caller saved registers */
799 popl %ebp
800 popl %edi
801 popl %esi
802 popl %ebx
803 movl $1, %eax
804 ret
805
Martin Roth8cc1aeb2016-02-24 13:03:52 -0800806.globl mbiptr
807mbiptr:
808 .long 0
Martin Roth9b1b3352016-02-24 12:27:06 -0800809realptr:
810 .word real - RSTART
811 .word 0x0000
812protptr:
813 .long 0
814 .long KERNEL_CS
815
816idt_real:
817 .word 0x400 - 1 # idt limit ( 256 entries)
818 .word 0, 0 # idt base = 0L
819
820/* _ap_trampoline_start is the entry point for cpus other than the
821 * bootstrap cpu. The code between _ap_trampoline_start to
822 * _ap_trampoline_protmode is copied to BootCodeStart(0x9000).
823 * The ljmp after turning on CR0.PE will jump to the
824 * relocatable code which usually resides at 0x10000 + _ap_trampoline_protmode.
825 *
826 * The trampoline code uses a temporary GDT. The entries of this temporary
827 * GDT must match the first few entries of the GDT used by the relocatble
828 * memtest code(see 'gdt' sybmol in this file).
829 *
830 */
831 .globl _ap_trampoline_start
832 .globl _ap_trampoline_protmode
833 .code16
834_ap_trampoline_start:
835 lgdt 0x0 /* will be fixed up later, see smp.c:BootAP()*/
836 movl %cr0, %eax
837 orl $1, %eax
838 movl %eax, %cr0
839 data32 ljmp $KERNEL_CS, $_ap_trampoline_protmode
840_ap_trampoline_protmode:
841 .code32
842 movw $KERNEL_DS, %ax
843 movw %ax, %ds
844 movw %ax, %es
845 movw %ax, %fs
846 movw %ax, %gs
847 movw %ax, %ss
848 movl $(LOW_TEST_ADR + _GLOBAL_OFFSET_TABLE_), %esp
849 leal boot_stack_top@GOTOFF(%esp), %esp
850 pushl $0
851 popf
852 call startup_32
853 /* if we ever return, we'll just loop forever */
854 cli
8552: hlt
Martin Roth4dcd13d2016-02-24 13:53:07 -0800856 jmp 2b
Martin Roth9b1b3352016-02-24 12:27:06 -0800857.data
858zerobss: .long 1
859.previous
860.data
861.balign 16
862 .globl mem_info
863mem_info:
864 . = . + MEMINFO_SIZE
865.previous
866.bss
867.balign 16
868boot_stack:
869 .globl boot_stack
870 . = . + 4096
871boot_stack_top:
872 .globl boot_stack_top
873.previous