201 lines
5.0 KiB
NASM
201 lines
5.0 KiB
NASM
; $Id: setup.asm 1484 2009-02-11 21:03:19Z hsc $
|
|
|
|
;******************************************************************************
|
|
;* Betriebssysteme *
|
|
;*----------------------------------------------------------------------------*
|
|
;* *
|
|
;* S E T U P *
|
|
;* *
|
|
;*----------------------------------------------------------------------------*
|
|
;* Der Setup-Code liegt im System-Image direkt hinter dem Bootsektor und wird *
|
|
;* von diesem direkt nach dem Laden aktiviert. Der Code wird noch im *
|
|
;* 'Real-Mode' gestartet, so dass zu Beginn auch noch BIOS-Aufrufe erlaubt *
|
|
;* sind. Dann werden jedoch alle Interrupts verboten, die Adressleitung A20 *
|
|
;* aktiviert und die Umschaltung in den 'Protected-Mode' vorgenommen. Alles *
|
|
;* weitere uebernimmt der Startup-Code des Systems. *
|
|
;******************************************************************************
|
|
|
|
;
|
|
; Konstanten
|
|
;
|
|
SETUPSEG equ 0x9000 ; Setup-Code (max. 64K inkl. Stack)
|
|
SYSTEMSEG equ 0x1000 ; System-Code (max. 512K)
|
|
SECTORSZ equ 512 ; Groesse eines Sektors in Bytes
|
|
SYSTEMSTART equ 0x100000 ; Hierhin wird das System nach Umschalten in den
|
|
; Protected Mode kopiert, da GRUB das auch tut
|
|
; (und GRUB kann nur an Adressen >1M laden).
|
|
|
|
[SECTION .text]
|
|
[BITS 16]
|
|
;
|
|
; Segmentregister initialisieren
|
|
;
|
|
start:
|
|
mov dx, ax ; Anzahl Systemsektoren in DX sichern.
|
|
|
|
mov ax,cs ; Daten-, Code- und Stacksegment sollen
|
|
mov ds,ax ; hierher zeigen.
|
|
mov ss,ax ; Alle drei Segment duerfen nicht mehr
|
|
mov sp,0xfffe ; als 64 KByte einnehmen (zusammen).
|
|
|
|
mov [system_sectors], dx ; Anzahl der Systemsektoren im Speicher ablegen
|
|
|
|
;
|
|
; Ausgabe einer Meldung mit Hilfe eines BIOS-Aufrufs
|
|
;
|
|
mov ah,0x03 ; Feststellen der Cursor-Position
|
|
xor bh,bh
|
|
int 0x10
|
|
|
|
mov cx,14
|
|
mov bx,0x0007 ; page 0, attribute 7 (normal)
|
|
mov ax,ds
|
|
mov es,ax
|
|
mov bp,setupmessage
|
|
mov ax,0x1301 ; Ausgabe des Textes, Cursor bewegen
|
|
int 0x10
|
|
;
|
|
; So, jetzt werden die Interrupts abgeschaltet
|
|
;
|
|
cli ; Maskierbare Interrupts verbieten
|
|
mov al,0x80 ; NMI verbieten
|
|
out 0x70,al
|
|
;
|
|
; IDT und GDT setzen
|
|
;
|
|
lidt [idt_48]
|
|
lgdt [gdt_48]
|
|
;
|
|
; Aktivieren der Adressleitung A20
|
|
;
|
|
call empty_8042
|
|
mov al,0xd1
|
|
out 0x64,al
|
|
call empty_8042
|
|
mov al,0xdf
|
|
out 0x60,al
|
|
call empty_8042
|
|
mov al,0xff
|
|
out 0x64,al
|
|
call empty_8042
|
|
;
|
|
; Moeglichen Koprozessor zuruecksetzen
|
|
;
|
|
xor ax,ax
|
|
out 0xf0,al
|
|
call delay
|
|
out 0xf1,al
|
|
call delay
|
|
;
|
|
; Umschalten in den Protected Mode
|
|
;
|
|
mov eax,cr0 ; Setze PM-Bit im Kontrollregister 1
|
|
or eax,1
|
|
mov cr0,eax
|
|
|
|
jmp dword 0x08:SETUPSEG*0x10+copy_system ; Far-Jump, um
|
|
; a) fetch Pipeline zu leeren
|
|
; b) CS Register sinnvoll zu belegen
|
|
[BITS 32]
|
|
; Arbeite jetzt im Protected Mode
|
|
copy_system:
|
|
;
|
|
; Systemcode von 0x10000 nach 0x100000 kopieren.
|
|
;
|
|
|
|
mov ax, 0x10 ; 0x10 entspricht dem Data-Eintrag in der GDT.
|
|
mov ds, ax ; DS und ES werden von movsd benoetigt.
|
|
mov es, ax
|
|
|
|
xor ecx, ecx ; Anzahl Systemsektoren laden
|
|
mov cx, [SETUPSEG*0x10+system_sectors]
|
|
|
|
imul ecx, SECTORSZ/4
|
|
|
|
mov esi, SYSTEMSEG*0x10 ; Hier liegt der Systemcode noch ...
|
|
mov edi, SYSTEMSTART ; ... und hierhin moechten wir ihn verschieben
|
|
|
|
cld ; Nach jedem movsb ESI,EDI inkrementieren
|
|
rep movsd ; Kopiere 4 Byte von [ESI] nach [EDI] ecx male
|
|
|
|
|
|
;
|
|
; Sprung in den Startup-Code des Systems
|
|
;
|
|
|
|
jmp dword 0x08:SYSTEMSTART
|
|
|
|
error:
|
|
hlt
|
|
[BITS 16]
|
|
; Ab hier wieder Real-Mode Code fuer die Codeteile
|
|
; vor der Umschaltung in den Protected Mode
|
|
|
|
;
|
|
; empty_8042
|
|
;
|
|
; Ein- und Ausgabepuffer des Tastaturcontrollers leeren
|
|
;
|
|
empty_8042:
|
|
call delay
|
|
in al,0x64 ; 8042 Status Port
|
|
test al,1 ; Ausgabepuffer voll?
|
|
jz no_output
|
|
call delay
|
|
in al,0x60 ; wenn ja: ueberlesen
|
|
jmp empty_8042
|
|
no_output:
|
|
test al,2 ; Eingabepuffer voll?
|
|
jnz empty_8042 ; wenn ja, noch mal testen, irgendwann
|
|
ret ; muss es weg sein.
|
|
;
|
|
; delay:
|
|
;
|
|
; Kurze Verzoegerung fuer in/out-Befehle
|
|
;
|
|
delay:
|
|
out 0x80,al
|
|
ret
|
|
|
|
;
|
|
; Datenbereich
|
|
;
|
|
[SECTION .data]
|
|
|
|
; Meldung
|
|
|
|
system_sectors:
|
|
dw 0
|
|
|
|
setupmessage:
|
|
db 13,10
|
|
db 'setup active'
|
|
;
|
|
; Descriptor-Tabellen
|
|
;
|
|
gdt:
|
|
dw 0,0,0,0 ; NULL Deskriptor
|
|
|
|
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)
|
|
|
|
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)
|
|
|
|
dw 0xFFFF ; 4Gb - (0x100000*0x1000 = 4Gb)
|
|
dw 0x4000 ; 0x4000 -> base address=0x24000 (siehe BIOS.cc)
|
|
dw 09A02h ; 0x2 -> base address =0x24000 (siehe BIOS.cc) und code read/exec;
|
|
dw 0008Fh ; granularity=4096, 16-bit code
|
|
|
|
idt_48:
|
|
dw 0 ; idt limit=0
|
|
dw 0,0 ; idt base=0L
|
|
|
|
gdt_48:
|
|
dw 0x20 ; GDT Limit=24, 3 GDT Eintraege
|
|
dd SETUPSEG*0x10+gdt; Physikalische Adresse der GDT
|