startup.asm 5.44 KB
Newer Older
Bernhard Heinloth's avatar
Bernhard Heinloth committed
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
; vim: set et ts=4 sw=4:

;******************************************************************************
;* Betriebssysteme                                                            *
;*----------------------------------------------------------------------------*
;*                                                                            *
;*                        S T A R T U P . A S M                               *
;*                                                                            *
;*----------------------------------------------------------------------------*
;* 'startup' ist der Eintrittspunkt des eigentlichen Systems. Die Umschaltung *
;* in den 'Protected Mode' ist bereits erfolgt. Es wird alles vorbereitet,    *
;* damit so schnell wie moeglich die weitere Ausfuehrung durch C/C++-Code     *
;* erfolgen kann.                                                             *
;******************************************************************************

; Multiboot-Konstanten
MULTIBOOT_PAGE_ALIGN equ 1<<0
MULTIBOOT_MEMORY_INFO equ 1<<1
MULTIBOOT_HEADER_MAGIC equ 0x1badb002
MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
MULTIBOOT_HEADER_CHKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
MULTIBOOT_START_ADDRESS equ 0x1000000
INIT_STACK_SIZE equ (1024*4)

; Deskriptoren global machen für realmode.asm
[GLOBAL idt_desc_global]

; Globaler Einsprungspunkt für das System
[GLOBAL startup]

; externe Funktionen und Variablen, die hier benötigt werden
[EXTERN multiboot_addr] ; Adresse der Multiboot Strukturen
[EXTERN guardian] ; Wird zur Interruptbehandlung aufgerufen
[EXTERN ap_stack] ; hier liegt die Adresse des Stacks für den gerade gebooteten AP
[EXTERN kernel_init] ; Wird zur Interruptbehandlung aufgerufen
[EXTERN gdt_desc_global]        ; Der "Pointer" zur globalen Deskriptortabelle (machine/gdt.cc)

[SECTION .text]

startup:
    jmp skip_multiboot_hdr

; multiboot header, auch der Zugriff über das Symbol ist aligned
align 4
multiboot_header:
    dd MULTIBOOT_HEADER_MAGIC
    dd MULTIBOOT_HEADER_FLAGS
    dd MULTIBOOT_HEADER_CHKSUM

skip_multiboot_hdr:
; Adresse der Multiboot-Strukturen speichern
    mov [multiboot_addr], ebx

; Unterbrechungen sperren
    cli
; NMI verbieten
    mov al, 0x80
    out 0x70, al

    mov dword [ap_stack], init_stack + INIT_STACK_SIZE

segment_init:
; GDT setzen
    lgdt [gdt_desc_global]
; Unterbrechungsbehandlung sicherstellen
    lidt [idt_desc_global]

; Datensegmentregister initialisieren
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax

; cs Segment Register neu laden
    jmp 0x8:load_cs

load_cs:

; Stackpointer initialisieren
    mov esp, [ap_stack]
; Richtung für String-Operationen festlegen
    cld

; Wechsel in C/C++
    call kernel_init

; Startup-Code fuer die APs
startup_ap:
; Alle Segmentselektoren neu laden, die zeigen noch auf die ap_gdt
; Nach Intel Manual Kapitel 9.9.1 ist das nötig
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax

; jetzt ist die CPU im protected mode

    jmp segment_init

;Unterbrechungsbehandlungen

; Die Interruptbehandlung muss in Assembler gestartet werden, um die
;; IRQ <irq-num> <error-code?>
%macro IRQ 2
align 8
irq_entry_%1:
    ;;  Den CPU Kontext Sichern
    push edx
    push ecx
    push eax
    ;; Einen Pointer auf den CPU Kontext als zweites Argument pushen
    push esp
    ;; Die Interrupt-Nummer ist das erste Argument
    push %1
    call guardian
    add esp, 8                 ; CPU Kontext und IRQ-Nummer vom Stack nehmen
    pop eax
    pop ecx
    pop edx
    iret
%endmacro

IRQ 0, 0
IRQ 1, 0
IRQ 2, 0
IRQ 3, 0
IRQ 4, 0
IRQ 5, 0
IRQ 6, 0
IRQ 7, 0
IRQ 8, 1
IRQ 9, 0
IRQ 10, 1
IRQ 11, 1
IRQ 12, 1
IRQ 13, 1
IRQ 14, 1
IRQ 15, 0
IRQ 16, 0
IRQ 17, 1

%assign i 18
%rep 238
IRQ i, 0
%assign i i+1
%endrep

[SECTION .data]
;  'interrupt descriptor table' mit 256 Eintraegen.
align 4
idt:
%macro idt_entry 1
    dw (irq_entry_%1 - startup + MULTIBOOT_START_ADDRESS) & 0xffff
    dw 0x0008
    dw 0x8e00
    dw ((irq_entry_%1 - startup + MULTIBOOT_START_ADDRESS) & 0xffff0000) >> 16
%endmacro

%assign i 0
%rep 256
idt_entry i
%assign i i+1
%endrep

idt_desc_global:
    dw 256*8-1  ; idt enthaelt 256 Eintraege
    dd idt

[SECTION .bss]

init_stack:
    resb INIT_STACK_SIZE

; setup_ap, Start der restlichen Prozessoren
; Umschaltung in den 'Protected-Mode'
; Dieser Code wird von APICSystem::copySetupAPtoLowMem() reloziert!
[SECTION .setup_ap_seg]

USE16

setup_ap:
; Segmentregister initialisieren
    mov ax,cs ; Daten- und Codesegment sollen
    mov ds,ax ; hierher zeigen. Stack brauchen wir hier nicht.

; Unterbrechungen sperren
    cli
; NMI verbieten
    mov al, 0x80
    out 0x70, al

; vorrübergehende GDT setzen
    lgdt [ap_gdtd - setup_ap]

; Umschalten in den Protected Mode
    mov eax,cr0 ; Setze PM bit im Kontrollregister 1
    or  eax,1
    mov cr0,eax
    jmp dword 0x08:startup_ap

align 4
ap_gdt:
    dw 0,0,0,0   ; NULL Deskriptor
; Codesegment von 0-4GB
    dw 0xFFFF    ; 4Gb - (0x100000*0x1000 = 4Gb)
    dw 0x0000    ; base address=0
    dw 0x9A00    ; code read/exec
    dw 0x00CF    ; granularity=4096, 386 (+5th nibble of limit)
; Datensegment von 0-4GB
    dw 0xFFFF    ; 4Gb - (0x100000*0x1000 = 4Gb)
    dw 0x0000    ; base address=0
    dw 0x9200    ; data read/write
    dw 0x00CF    ; granularity=4096, 386 (+5th nibble of limit)

ap_gdtd:
    dw $ - ap_gdt - 1 ; Limit
    dd 0x40000 + ap_gdt - setup_ap ; Physikalische Adresse der ap_gdt