-
Notifications
You must be signed in to change notification settings - Fork 6
/
setup.S
162 lines (137 loc) · 3.57 KB
/
setup.S
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
* setup.s is responsible for getting the system data from the BIOS,
* and putting them into the appropriate places in system memory.
* both setup.s and system has been loaded by the bootblock.
*
* 1-Jan-96 Modified by Chris Brady for use as a boot/loader for memtest-86.
*/
#define __ASSEMBLY__
#include "defs.h"
.code16
.section ".setup", "ax", @progbits
.globl start
start:
# ok, the read went well
# now we want to move to protected mode ...
cli # no interrupts allowed #
movb $0x80, %al # disable NMI for the bootup sequence
outb %al, $0x70
# The system will move itself to its rightful place.
# reload the segment registers and the stack since the
# APs also execute this code
#ljmp $INITSEG, $(reload - start + 0x200)
reload:
movw $INITSEG, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %ss # reset the stack to INITSEG:0x4000-12.
movw %dx, %sp
push %cs
pop %ds
xorl %eax, %eax
movw %cs, %ax
shll $4, %eax
addl %eax, gdt_48 - start + 2
lidt idt_48 - start # load idt with 0,0
lgdt gdt_48 - start # load gdt with whatever appropriate
# that was painless, now we enable A20
# start from grub-a20.patch
/*
* try to switch gateA20 using PORT92, the "Fast A20 and Init"
* register
*/
mov $0x92, %dx
inb %dx, %al
/* skip the port92 code if it's unimplemented (read returns 0xff) */
cmpb $0xff, %al
jz alt_a20_done
/* set or clear bit1, the ALT_A20_GATE bit */
movb 4(%esp), %ah
testb %ah, %ah
jz alt_a20_cont1
orb $2, %al
jmp alt_a20_cont2
alt_a20_cont1:
and $0xfd, %al
/* clear the INIT_NOW bit; don't accidently reset the machine */
alt_a20_cont2:
and $0xfe, %al
outb %al, %dx
alt_a20_done:
# end from grub-a20.patch
call empty_8042
movb $0xD1, %al # command write
outb %al, $0x64
call empty_8042
movb $0xDF, %al # A20 on
outb %al, $0x60
call empty_8042
/*
* Note that the short jump isn't strictly needed, althought there are
* reasons why it might be a good idea. It won't hurt in any case.
*/
xorl %ebx, %ebx
movw %ss, %bx
shll $4, %ebx
movw $0x0001, %ax # protected mode (PE) bit
lmsw %ax # This is it#
jmp flush_instr
flush_instr:
movw $KERNEL_DS, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
addl %ebx, %esp
movw %ax, %fs
movw %ax, %gs
data32 ljmp $KERNEL_CS, $(TSTLOAD <<4) # jmp offset 2000 of segment 0x10 (cs)
/*
* This routine checks that the keyboard command queue is empty
* (after emptying the output buffers)
*
* No timeout is used - if this hangs there is something wrong with
* the machine, and we probably couldn't proceed anyway.
*/
empty_8042:
call delay
inb $0x64, %al # 8042 status port
cmpb $0xff, %al # from grub-a20-patch, skip if not impl
jz empty_8042_ret
testb $1, %al # output buffer?
jz no_output
call delay
inb $0x60, %al # read it
jmp empty_8042
no_output:
testb $2, %al # is input buffer full?
jnz empty_8042 # yes - loop
empty_8042_ret:
ret
#
# Delay is needed after doing i/o
#
delay:
.word 0x00eb # jmp $+2
ret
gdt:
.word 0,0,0,0 # dummy
.word 0,0,0,0 # unused
.word 0x7FFF # limit 128mb
.word 0x0000 # base address=0
.word 0x9A00 # code read/exec
.word 0x00C0 # granularity=4096, 386
.word 0x7FFF # limit 128mb
.word 0x0000 # base address=0
.word 0x9200 # data read/write
.word 0x00C0 # granularity=4096, 386
idt_48:
.word 0 # idt limit=0
.long 0 # idt base=0L
gdt_48:
.word 0x800 # gdt limit=2048, 256 GDT entries
.word gdt - start,0 # gdt base
msg1:
.asciz "Setup.S\r\n"
/* Pad setup to the proper size */
.org (SETUPSECS*512)