add setup/boot code
This commit is contained in:
254
Makefile
Executable file
254
Makefile
Executable file
@ -0,0 +1,254 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# M A K E F I L E
|
||||
#
|
||||
# zum HHUos der Lehrveranstaltung 'Betriebssystem-Entwicklung'.
|
||||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# Compilieren: ‘make'
|
||||
# Ausfuehren mit Qemu: ‘make qemu’
|
||||
# GDB mit Qemu: ‘make qemu-gdb &’ und danach ‘make gdb’
|
||||
# DDD mit Qemu: ‘make qemu-gdb &’ und danach ‘make ddd’
|
||||
#
|
||||
# Aufraeumen mit: ‘make clean’
|
||||
#
|
||||
# Achtung: Erzeugen von bootfaehigen Medien erfordert das Anpassen folgender
|
||||
# Variablen: DRIVE_FD und DRIVE_HD. Aufpassen, ansonsten wir evt.
|
||||
# die System-Disk zerstoert.
|
||||
#
|
||||
# Erzeugen einer bootfaehigen Diskette mit: ‘make bootdisk’
|
||||
# Erzeugen eines bootfaehigen USB-Sticks mit: ‘make bootdisk-usb’
|
||||
# Erzeugen eines bootfaehigen Festplatte mit: ‘make bootdisk-hd’
|
||||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
# Autor: Olaf Spinzcyk, TU Dortmund
|
||||
#
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Liste der Quelltexte:
|
||||
|
||||
STARTUP_SOURCE = ./startup.asm
|
||||
CC_SOURCES = $(shell find . -name "*.cc")
|
||||
C_SOURCES = $(shell find . -name "*.c")
|
||||
ASM_SOURCES = $(shell find ./kernel -name "*.asm")
|
||||
|
||||
# Einstellungen in Abhaengigkeit vom Generierungssystem:
|
||||
#
|
||||
# ASMOBJFORMAT: Ausgabeformat fuer den Assembler. Das Format muss dem
|
||||
# jeweiligen Format des verwendeten C++ Compilers angepasst
|
||||
# werde, damit gemischte Objektdateien gelinkt werden koennen.
|
||||
# OBJDIR: Verzeichnis, in dem die Objektdateien abgelegt werden
|
||||
# sollen.
|
||||
# DEPDIR: Verzeichnis, in dem die Abhaengigkeitsdateien abgelegt werden
|
||||
# sollen
|
||||
# DRIVE_FD: Diskettenlaufwerk, auf das das System-Image geschrieben wird
|
||||
# (Target: bootdisk)
|
||||
# DRIVE_HD: Festplatten-/USB-Device, auf das das System-Image
|
||||
# geschrieben wird (Target: bootdisk-hd)
|
||||
# DELETE: Name des Kommandos zum Loeschen von Dateien
|
||||
# ASM: Zu benutzender Assembler
|
||||
# CC/CXX: Zu benutzender C/C++-Compiler
|
||||
# CFLAGS: Flags fuer den C-Compileraufruf
|
||||
# CXXFLAGS: Flags fuer den C++-Compileraufruf
|
||||
# LD: Zu benutzender Linker
|
||||
# LDFLAGS: Flags fuer den Linkeraufruf
|
||||
# LDLIBS: Dazuzulinkende Bibliotheken
|
||||
# LDHEAD: Am Anfang zu linkende Dateien
|
||||
# LDTAIL: Am Ende zu linkende Dateien
|
||||
# BOOT: Das Verzeichnis zu Bootsektor und Setup-Code
|
||||
# TOOLS: Das Verzeichnis mit dem Build-Tool
|
||||
|
||||
VERBOSE = @
|
||||
ASMOBJFORMAT = elf
|
||||
OBJDIR = ./build
|
||||
DEPDIR = ./dep
|
||||
DRIVE_FD = /dev/sdb
|
||||
# ACHTUNG: ein falsch angegebenes Laufwerk kann dazu fuehren, dass Daten auf dem
|
||||
# spezifizierten Laufwerk verloren gehen! Nicht mit root-Rechten ausfuehren!
|
||||
DRIVE_HD = /dev/sdb
|
||||
DELETE = rm
|
||||
ASM = nasm
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
CFLAGS := $(CFLAGS) -m32 -march=i486 -Wall -fno-stack-protector -nostdlib -I. -g -ffreestanding -fno-pie -fno-pic -mpreferred-stack-boundary=2 -Wno-write-strings -mno-sse -mno-sse2 -mmanual-endbr
|
||||
CXXFLAGS := $(CFLAGS) -Wno-non-virtual-dtor -fno-threadsafe-statics -fno-use-cxa-atexit -fno-rtti -fno-exceptions
|
||||
|
||||
BOOT = ../c_boot
|
||||
TOOLS = ../c_tools
|
||||
# BIOS-dev.code:total-tracks:-heads:-sectors:start-track:-head:-sector
|
||||
# Default-Werte fuer Boot von Floppy (USB/HD erkennt bootsect.asm selbst):
|
||||
BOOTDEVICE = 0:80:2:18:0:0:1
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Namen der Unterverzeichnisse mit den Quelltexten
|
||||
|
||||
VPATH = $(sort $(dir $(STARTUP_SOURCE) $(CC_SOURCES) $(C_SOURCES) $(ASM_SOURCES)))
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Listen mit den Objektdateien, die beim Kompilieren entstehen:
|
||||
|
||||
FIRST_OBJECT = $(addprefix $(OBJDIR)/,$(patsubst %.asm,_%.o, $(notdir $(STARTUP_SOURCE))))
|
||||
C_OBJECTS = $(notdir $(C_SOURCES:.c=.o))
|
||||
CC_OBJECTS = $(notdir $(CC_SOURCES:.cc=.o))
|
||||
|
||||
DEP_FILES = $(patsubst %.o,$(DEPDIR)/%.d,$(C_OBJECTS))
|
||||
DEP_FILES += $(patsubst %.o,$(DEPDIR)/%.d,$(CC_OBJECTS))
|
||||
|
||||
ASM_OBJECTS = $(patsubst %.asm,_%.o, $(notdir $(ASM_SOURCES)))
|
||||
OBJPRE = $(addprefix $(OBJDIR)/,$(ASM_OBJECTS) $(C_OBJECTS) $(CC_OBJECTS))
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Default targets (einfaches Image, Image fuer USB Sticks, Image fuer VMWare
|
||||
# und Boot CDs)
|
||||
|
||||
all: $(OBJDIR)/bootdisk.img $(OBJDIR)/bootdisk.vmi $(OBJDIR)/bootdisk-hd.vmi
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Regeln zur Erzeugung der Abhaengigkeitsdateien
|
||||
|
||||
$(DEPDIR)/%.d : %.c
|
||||
@echo "DEP $@"
|
||||
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi
|
||||
$(VERBOSE) $(CC) $(CFLAGS) -MM -MT $(OBJDIR)/$*.o -MF $@ $<
|
||||
|
||||
$(DEPDIR)/%.d : %.cc
|
||||
@echo "DEP $@"
|
||||
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi
|
||||
$(VERBOSE) $(CXX) $(CXXFLAGS) -MM -MT $(OBJDIR)/$*.o -MF $@ $<
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Regeln zur Erzeugung der Objektdateien
|
||||
|
||||
$(OBJDIR)/%.o : %.c
|
||||
@echo "CC $@"
|
||||
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi
|
||||
$(VERBOSE) $(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.o : %.cc
|
||||
@echo "CXX $@"
|
||||
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi
|
||||
$(VERBOSE) $(CXX) -c $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(OBJDIR)/_%.o : %.asm
|
||||
@echo "ASM $@"
|
||||
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi
|
||||
$(VERBOSE) $(ASM) -f $(ASMOBJFORMAT) -o $@ $<
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Gelinktes System
|
||||
|
||||
$(OBJDIR)/system: $(FIRST_OBJECT) $(OBJPRE)
|
||||
@echo "LD $@"
|
||||
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi
|
||||
$(VERBOSE) $(CXX) $(CXXFLAGS) -static -e startup -T sections -o $(OBJDIR)/system $(FIRST_OBJECT) $(OBJPRE)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 'system.img' enthaelt die zu ladenden Sections des eigentlichen Systems
|
||||
|
||||
$(OBJDIR)/system.img : $(OBJDIR)/system
|
||||
@echo "OBJCOPY $@"
|
||||
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi
|
||||
$(VERBOSE) objcopy -O binary $< $@
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 'bootdisk.img' besteht aus dem 'system.img', das um den (parametrisierten)
|
||||
# Bootblock und den Setup-Code erweitert wurde.
|
||||
|
||||
$(OBJDIR)/bootdisk.img : $(OBJDIR)/system.img $(TOOLS)/build $(BOOT)/bootsect $(BOOT)/setup
|
||||
@echo "BUILD $@"
|
||||
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi
|
||||
$(VERBOSE) $(TOOLS)/build $(BOOT)/bootsect $(BOOT)/setup $< $(BOOTDEVICE) $@
|
||||
|
||||
# 'bootdisk.vmi' ist eine bootdisk, die auf 1.44 MB mit 0 aufgefuellt ist,
|
||||
# damit VMware damit klarkommt. Des weiteren wird dieses Image benoetigt, um
|
||||
# bootfaehige CDs zu erstellen.
|
||||
# bootdisk-hd.img wird auf etwa 1M mit 0 aufgefuellt, da qemu diese Groesse
|
||||
# auf eine Festplatten-Laufwerkscharakteristik zurueckrechnen kann.
|
||||
|
||||
$(OBJDIR)/bootdisk.vmi: $(OBJDIR)/bootdisk.img
|
||||
dd if=$< of=$@ bs=1474560 conv=sync
|
||||
|
||||
$(OBJDIR)/bootdisk-hd.vmi: $(OBJDIR)/bootdisk.img
|
||||
dd if=$< of=$@ bs=$$((2016*512)) conv=sync
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 'clean' loescht das generierte System, die Objektdateien und die
|
||||
# Abhaengigkeitsdateien
|
||||
|
||||
clean:
|
||||
@echo "RM $(OBJDIR)"
|
||||
$(VERBOSE) rm -rf $(OBJDIR)
|
||||
@echo "RM $(DEPDIR)"
|
||||
$(VERBOSE) rm -rf $(DEPDIR)
|
||||
$(MAKE) -C $(BOOT) clean
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 'bootdisk' erzeugt zunaechst das System, falls das noch nicht geschehen ist.
|
||||
# Danach wird eine Bootdiskette mit dem System erzeugt.
|
||||
|
||||
bootdisk: $(OBJDIR)/bootdisk.img
|
||||
@echo "CP $<"
|
||||
$(VERBOSE) cp $< $(DRIVE_FD)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 'bootdisk-hd' erzeugt zunaechst das System, falls das noch nicht geschehen
|
||||
# ist. Danach wird das System auf das spezifizierte Laufwerk geschrieben,
|
||||
# welches sowohl eine Festplatte, als auch ein USB-Stick sein kann.
|
||||
# ACHTUNG: ein falsch angegebenes Laufwerk kann dazu fuehren, dass Daten auf dem
|
||||
# spezifizierten Laufwerk verloren gehen! Nicht mit root-Rechten ausfuehren!
|
||||
|
||||
bootdisk-usb: bootdisk-hd
|
||||
bootdisk-hd: $(OBJDIR)/bootdisk.img
|
||||
@echo "CP $<"
|
||||
$(VERBOSE) cp $< $(DRIVE_HD)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 'qemu' ruft den qemu-Emulator mit dem System auf.
|
||||
|
||||
qemu: $(OBJDIR)/bootdisk.vmi
|
||||
qemu-system-i386 -fda $(OBJDIR)/bootdisk.vmi -boot a -k en-us -soundhw pcspk -vga std -cpu 486
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 'qemu-gdb' ruft den qemu-Emulator mit aktiviertem GDB-Stub mit dem System
|
||||
# auf, sodass es per GDB oder DDD inspiziert werden kann.
|
||||
|
||||
qemu-gdb: $(OBJDIR)/bootdisk.vmi
|
||||
$(VERBOSE) echo "break main" > /tmp/gdbcommands.$(shell id -u)
|
||||
$(VERBOSE) echo "target remote 127.0.0.1:1234" >> /tmp/gdbcommands.$(shell id -u)
|
||||
$(VERBOSE) echo "continue" >> /tmp/gdbcommands.$(shell id -u)
|
||||
qemu-system-i386 -fda $(OBJDIR)/bootdisk.vmi -boot a -k en-us -s -S -soundhw pcspk -vga std -cpu 486
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 'gdb' startet den GDB-Debugger und verbindet sich mit dem GDB-Stub des vorher
|
||||
# gestarteten Qemu.
|
||||
|
||||
gdb:
|
||||
gdb -x /tmp/gdbcommands.$(shell id -u) $(OBJDIR)/system
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 'ddd' startet den DDD-Debugger und verbindet sich mit dem GDB-Stub des vorher
|
||||
# gestarteten Qemu.
|
||||
|
||||
ddd:
|
||||
ddd --gdb -x /tmp/gdbcommands.$(shell id -u) $(OBJDIR)/system
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 'build'-Tool kompilieren.
|
||||
|
||||
$(TOOLS)/build: $(TOOLS)/build.c
|
||||
cd $(TOOLS) && $(CC) -o $@ $<
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Bootsektor und Protected-Mode-Setup-Code kompilieren.
|
||||
|
||||
$(BOOT)/bootsect $(BOOT)/setup: $(BOOT)/bootsect.asm $(BOOT)/setup.asm
|
||||
$(MAKE) -C $(BOOT)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Einbindung der Abhaengigkeitsdateien
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(DEP_FILES)
|
||||
endif
|
||||
|
||||
.PHONY: clean bootdisk bootdisk-hd bootdisk-usb gdb ddd
|
9
c_boot/Makefile
Executable file
9
c_boot/Makefile
Executable file
@ -0,0 +1,9 @@
|
||||
# $Id: Makefile 956 2008-10-19 22:24:23Z hsc $
|
||||
|
||||
all: bootsect setup
|
||||
|
||||
% : %.asm
|
||||
nasm -f bin $<
|
||||
|
||||
clean:
|
||||
rm -f *~ bootsect setup
|
BIN
c_boot/bootsect
Normal file
BIN
c_boot/bootsect
Normal file
Binary file not shown.
324
c_boot/bootsect.asm
Executable file
324
c_boot/bootsect.asm
Executable file
@ -0,0 +1,324 @@
|
||||
; $Id: bootsect.asm 5001 2012-10-12 11:34:05Z os $
|
||||
|
||||
;******************************************************************************
|
||||
;* Betriebssysteme *
|
||||
;*----------------------------------------------------------------------------*
|
||||
;* *
|
||||
;* B O O T S E C T *
|
||||
;* *
|
||||
;*----------------------------------------------------------------------------*
|
||||
;* Code fuer den Disketten-Bootblock des System-Images. Das BIOS laedt den *
|
||||
;* ersten Block einer Diskette (den Bootblock) beim Starten des Rechner in *
|
||||
;* den Hauptspeicher und fuehrt ihn aus. Der Programmcode des Bootblocks *
|
||||
;* laedt nun das restliche System und fuehrt es aus. *
|
||||
;******************************************************************************
|
||||
|
||||
;
|
||||
; Konstanten
|
||||
;
|
||||
BIOSSEG equ 0x07c0 ; Hierher wird der Bootsector
|
||||
; vom BIOS geladen
|
||||
BOOTSEG equ 0x0060 ; Hierher verschiebt sich der
|
||||
; Boot-Code
|
||||
SETUPSEG equ 0x9000 ; Hierher laedt der Boot-Code den
|
||||
; Setup-Code (max. 64K inkl. Stack)
|
||||
SYSTEMSEG equ 0x1000 ; System-Code (max. 512K)
|
||||
SECTORSZ equ 512 ; Groesse eines Sektors in Bytes
|
||||
|
||||
[SECTION .text]
|
||||
|
||||
;
|
||||
; Boot-Code
|
||||
;
|
||||
bootsector:
|
||||
jmp skip_data
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
;
|
||||
; Datenbereich, der von 'build' beim Erzeugen der Boot-Diskette
|
||||
; gefuellt wird.
|
||||
;
|
||||
pad:
|
||||
times 4+bootsector-$ db 0 ; Bytes zum Auffuellen, damit 'total_tracks' an einer
|
||||
; geraden und tools/build.c bekannten Adresse liegt
|
||||
total_tracks:
|
||||
dw 0 ; Anzahl der Tracks der Diskette
|
||||
total_heads:
|
||||
dw 0 ; Anzahl der Seiten der Diskette
|
||||
total_sectors:
|
||||
dw 0 ; Anzahl der Sektoren pro Track
|
||||
setup_sectors:
|
||||
dw 0 ; Anzahl der Sektoren, die der Setup-Code einnimmt
|
||||
system_sectors:
|
||||
dw 0 ; Anzahl der Sektoren, die das System einnimmt
|
||||
bootdevice:
|
||||
db 0 ; BIOS Geraetecode: 00: Disk A, 01: Disk B, ..., 0x80 HD0, ...
|
||||
curr_track:
|
||||
db 0 ; Track, bei dem die Diskette/Partition beginnt
|
||||
curr_head:
|
||||
db 0 ; Head, bei dem die Diskette/Partition beginnt
|
||||
curr_sector:
|
||||
db 0 ; Sector, bei dem die Diskette/Partition beginnt
|
||||
|
||||
;-----------------------------------------------------------------------
|
||||
|
||||
;
|
||||
; Kopieren des Bootsectors
|
||||
;
|
||||
skip_data:
|
||||
mov bl,dl ; vom BIOS uebergebenes Boot-Device sichern
|
||||
|
||||
mov ax,BIOSSEG
|
||||
mov ds,ax
|
||||
xor si,si
|
||||
mov ax,BOOTSEG
|
||||
mov es,ax
|
||||
xor di,di
|
||||
mov cx,SECTORSZ/2
|
||||
rep movsw
|
||||
;
|
||||
; Ausfuehrung durch die Kopie fortsetzen
|
||||
;
|
||||
jmp BOOTSEG:start
|
||||
;
|
||||
; Segmentregister initialisieren und Platz fuer den Stack schaffen
|
||||
;
|
||||
start:
|
||||
mov ax,cs ; Daten-, Stack- und Codesegment sollen
|
||||
mov ds,ax ; hierher zeigen.
|
||||
mov ss,ax
|
||||
mov sp,4*SECTORSZ ; Drei Sektoren als Stack freilassen
|
||||
|
||||
mov [bootdevice],bl ; zuvor gesichertes Boot-Device permanent ablegen
|
||||
|
||||
;
|
||||
; Ausgabe einer Meldung mit Hilfe eines BIOS-Aufrufs
|
||||
;
|
||||
mov ah,0x03 ; Feststellen der Cursor-Position
|
||||
xor bh,bh
|
||||
int 0x10
|
||||
|
||||
mov cx,13
|
||||
mov bx,0x0007 ; page 0, attribute 7 (normal)
|
||||
mov ax,ds
|
||||
mov es,ax
|
||||
mov bp,bootmessage
|
||||
mov ax,0x1301 ; Ausgabe des Textes, Cursor bewegen
|
||||
int 0x10
|
||||
;
|
||||
; Nachladen des Setup-Codes und des Systems selbst.
|
||||
;
|
||||
xor ah,ah ; Reset des Disketten-/Plattencontrollers
|
||||
mov dl,[bootdevice]
|
||||
int 0x13
|
||||
;
|
||||
; Informationen ueber die Laufwerksgeometrie holen
|
||||
;
|
||||
hdd_probe:
|
||||
mov dl,[bootdevice]
|
||||
test dl,0x80
|
||||
jz load_setup ; Floppy mit den Standardparametern laden
|
||||
mov ah,0x8
|
||||
int 0x13
|
||||
jc load_setup ; CF bei Fehler gesetzt
|
||||
mov [total_heads],dh
|
||||
mov ax,cx ; CX sichern
|
||||
and ax,0x3f
|
||||
mov [total_sectors],ax
|
||||
mov ax,cx
|
||||
shr ax,6
|
||||
mov [total_tracks],ax
|
||||
|
||||
;
|
||||
; Weiterstellen der Disketten-/Plattenposition um 1 (Bootblock)
|
||||
;
|
||||
load_setup:
|
||||
call step_disk
|
||||
|
||||
;
|
||||
; Laden des Setup-Codes
|
||||
;
|
||||
mov word [curr_segment],SETUPSEG
|
||||
mov word [curr_offset],0
|
||||
mov ax,[setup_sectors]
|
||||
call load
|
||||
;
|
||||
; Laden des Kernels
|
||||
;
|
||||
mov word [curr_segment],SYSTEMSEG
|
||||
mov word [curr_offset],0
|
||||
mov ax,[system_sectors]
|
||||
call load
|
||||
;
|
||||
; Floppy wieder abschalten
|
||||
;
|
||||
call stop_floppy_motor
|
||||
;
|
||||
; Start des Setup-Codes
|
||||
;
|
||||
mov ax, [system_sectors] ; Speichere Anzahl an System-Sektoren in AX.
|
||||
jmp SETUPSEG:0
|
||||
|
||||
;
|
||||
; load
|
||||
;
|
||||
; Die 'ax' Sektoren von der Diskette in den Hauptspeicher. Die Position auf
|
||||
; der Diskette muss vorher in curr_head/curr_track/curr_sector und die
|
||||
; Position im Hauptspeicher in curr_segment/curr_offset stehen. Die Positionen
|
||||
; werden entsprechend der geladenen Sektoren weitergestellt.
|
||||
;
|
||||
load:
|
||||
mov [to_load],ax
|
||||
l_next_part:
|
||||
mov al,[curr_head]
|
||||
mov [last_head],al
|
||||
mov al,[curr_track]
|
||||
mov [last_track],al
|
||||
mov al,[curr_sector]
|
||||
mov [last_sector],al
|
||||
mov ax,[curr_segment]
|
||||
mov [last_segment],ax
|
||||
mov ax,[curr_offset]
|
||||
mov [last_offset],ax
|
||||
|
||||
mov al,0
|
||||
|
||||
l_loop: call step
|
||||
|
||||
cmp byte [curr_sector],0x01
|
||||
je l_now
|
||||
cmp word [curr_offset],0x0000
|
||||
je l_now
|
||||
cmp al,[to_load]
|
||||
jne l_loop
|
||||
|
||||
l_now:
|
||||
push ax
|
||||
mov dl,[bootdevice]
|
||||
mov dh,[last_head]
|
||||
mov ch,[last_track]
|
||||
mov cl,[last_sector]
|
||||
mov bx,[last_segment]
|
||||
mov es,bx
|
||||
mov bx,[last_offset]
|
||||
mov ah,0x02 ; Funktionscode fuer 'Lesen'
|
||||
int 0x13
|
||||
pop ax
|
||||
|
||||
push ax
|
||||
call print_dot
|
||||
pop ax
|
||||
|
||||
mov ah,0
|
||||
sub [to_load],ax
|
||||
jne l_next_part
|
||||
ret
|
||||
|
||||
;
|
||||
; step
|
||||
;
|
||||
; Stellt die aktuelle Position im Hauptspeicher und auf der Diskette
|
||||
; um einen Sektor (512 Byte) weiter.
|
||||
;
|
||||
step: add al,1
|
||||
call step_disk
|
||||
call step_memory
|
||||
ret
|
||||
|
||||
step_disk:
|
||||
mov bl,[curr_sector]
|
||||
add bl,1
|
||||
mov [curr_sector],bl
|
||||
cmp bl,[total_sectors]
|
||||
jle l_1
|
||||
mov byte [curr_sector],1
|
||||
|
||||
mov bl,[curr_head]
|
||||
add bl,1
|
||||
mov [curr_head],bl
|
||||
cmp bl,[total_heads]
|
||||
jne l_1
|
||||
mov byte [curr_head],0
|
||||
|
||||
mov bl,[curr_track]
|
||||
add bl,1
|
||||
mov [curr_track],bl
|
||||
|
||||
l_1: ret
|
||||
|
||||
step_memory:
|
||||
mov bx,[curr_offset]
|
||||
add bx,SECTORSZ
|
||||
mov [curr_offset],bx
|
||||
test bx,0xffff
|
||||
jne l_2
|
||||
mov bx,[curr_segment]
|
||||
add bx,0x1000 ; 64 KByte weiterstellen
|
||||
mov [curr_segment],bx
|
||||
|
||||
l_2 ret
|
||||
|
||||
;
|
||||
; Ausgabe eines Stern ('*') mit Hilfe eines BIOS-Aufrufs
|
||||
;
|
||||
print_dot:
|
||||
mov ah,0x03 ; Feststellen der Cursor-Position
|
||||
xor bh,bh
|
||||
int 0x10
|
||||
|
||||
mov cx,1
|
||||
mov bx,0x0007 ; page 0, attribute 7 (normal)
|
||||
mov ax,ds
|
||||
mov es,ax
|
||||
mov bp,dot
|
||||
mov ax,0x1301 ; Ausgabe des Textes, Cursor bewegen
|
||||
int 0x10
|
||||
|
||||
ret
|
||||
|
||||
;
|
||||
; stop_floppy_motor
|
||||
;
|
||||
; Stopt den Motor der Floppy, da das BIOS dazu in Kuerze nicht mehr in
|
||||
; der Lage sein wird. Egal, ob von Floppy oder Platte gebootet wurde.
|
||||
;
|
||||
stop_floppy_motor:
|
||||
mov dx,0x3f2
|
||||
xor al,al
|
||||
out dx,al
|
||||
ret
|
||||
|
||||
;
|
||||
; Datenbereich
|
||||
;
|
||||
|
||||
bootmessage:
|
||||
db 13,10
|
||||
db 'booting ... '
|
||||
|
||||
dot:
|
||||
db '*'
|
||||
|
||||
to_load:
|
||||
dw 0
|
||||
curr_segment:
|
||||
dw 0
|
||||
curr_offset:
|
||||
dw 0
|
||||
|
||||
last_head:
|
||||
db 0
|
||||
last_track:
|
||||
db 0
|
||||
last_sector:
|
||||
db 0
|
||||
last_segment:
|
||||
dw 0
|
||||
last_offset:
|
||||
dw 0
|
||||
|
||||
unused:
|
||||
times bootsector+510-$ db 0
|
||||
|
||||
mark:
|
||||
dw 0xaa55
|
BIN
c_boot/setup
Normal file
BIN
c_boot/setup
Normal file
Binary file not shown.
195
c_boot/setup.asm
Executable file
195
c_boot/setup.asm
Executable file
@ -0,0 +1,195 @@
|
||||
; $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)
|
||||
|
||||
idt_48:
|
||||
dw 0 ; idt limit=0
|
||||
dw 0,0 ; idt base=0L
|
||||
|
||||
gdt_48:
|
||||
dw 0x18 ; GDT Limit=24, 3 GDT Eintraege
|
||||
dd SETUPSEG*0x10+gdt; Physikalische Adresse der GDT
|
BIN
c_tools/build
Executable file
BIN
c_tools/build
Executable file
Binary file not shown.
153
c_tools/build.c
Executable file
153
c_tools/build.c
Executable file
@ -0,0 +1,153 @@
|
||||
#include <stdio.h> /* fprintf */
|
||||
#include <string.h>
|
||||
#include <stdlib.h> /* contains exit */
|
||||
#include <unistd.h> /* contains read/write */
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if !defined(DOS) && !defined(Win32)
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#define SECTOR 512
|
||||
|
||||
void die (const char* str)
|
||||
{
|
||||
fprintf(stderr,"%s\n",str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
int fd, fd_out;
|
||||
char bootsector[SECTOR];
|
||||
char setupsector[SECTOR];
|
||||
struct stat info;
|
||||
unsigned short setup_size;
|
||||
int bytes_read, to_read;
|
||||
unsigned int dc, st, sh, ss, tt, th, ts;
|
||||
unsigned char bios_device_code, start_track, start_head, start_sector;
|
||||
unsigned short total_tracks, total_heads, total_sectors;
|
||||
unsigned short system_sectors;
|
||||
|
||||
if (argc != 6)
|
||||
die ("usage: build bootsector setup-code system-image dev.info bootdisk-image\n\n"
|
||||
"dev.info: BIOS-dev.code:total-tracks:-heads:-sectors:start-track:-head:-sector\n"
|
||||
"BIOS-devicecode: 0=fd0, 1=fd1, ..., 128=hd0, 129=hd1, ...\n"
|
||||
"Example: to boot from a 3.5\" floppy disk use \"0:80:2:18:0:0:1\"\n");
|
||||
|
||||
sscanf (argv[4], "%u:%u:%u:%u:%u:%u:%u", &dc, &tt, &th, &ts, &st, &sh, &ss);
|
||||
bios_device_code = (unsigned char)dc;
|
||||
total_tracks = (unsigned short)tt;
|
||||
total_sectors = (unsigned short)ts;
|
||||
total_heads = (unsigned short)th;
|
||||
start_track = (unsigned char)st;
|
||||
start_head = (unsigned char)sh;
|
||||
start_sector = (unsigned char)ss;
|
||||
|
||||
printf ("BIOS-devicecode: 0x%x\n", bios_device_code);
|
||||
printf ("Total T/H/S: (%d/%d/%d)\n", total_tracks, total_heads,
|
||||
total_sectors);
|
||||
printf ("Start T/H/S: (%d/%d/%d)\n\n", start_track, start_head,
|
||||
start_sector);
|
||||
|
||||
if ((fd_out = open (argv[5], O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) < 0)
|
||||
die ("Unable to open output file.");
|
||||
|
||||
if ((fd = open (argv[1], O_RDONLY|O_BINARY, 0)) < 0)
|
||||
die ("Unable to open input file.");
|
||||
|
||||
if (read (fd, bootsector, SECTOR) < 0)
|
||||
die ("Unable to read bootsector.");
|
||||
|
||||
close (fd);
|
||||
|
||||
if (stat (argv[2], &info) != 0)
|
||||
die ("Can't stat setup file.");
|
||||
|
||||
setup_size = (unsigned short)
|
||||
((info.st_size + SECTOR - 1) / SECTOR);
|
||||
printf ("Setup size is %d sectors.\n", (int)setup_size);
|
||||
|
||||
if (stat (argv[3], &info) != 0)
|
||||
die ("Can't stat system file.");
|
||||
to_read = info.st_size;
|
||||
printf ("System size is %d bytes.\n", to_read);
|
||||
|
||||
system_sectors = (to_read + SECTOR - 1) / SECTOR;
|
||||
printf ("# System sectors is %d.\n", system_sectors);
|
||||
|
||||
#if 0
|
||||
*(unsigned short*)(bootsector+4) = total_tracks;
|
||||
*(unsigned short*)(bootsector+6) = total_heads;
|
||||
*(unsigned short*)(bootsector+8) = total_sectors;
|
||||
|
||||
*(unsigned short*)(bootsector+10) = setup_size;
|
||||
*(unsigned short*)(bootsector+12) =
|
||||
(unsigned short)((to_read + SECTOR - 1) / SECTOR);
|
||||
*(unsigned char*)(bootsector+14) = bios_device_code;
|
||||
*(unsigned char*)(bootsector+15) = start_track;
|
||||
*(unsigned char*)(bootsector+16) = start_head;
|
||||
*(unsigned char*)(bootsector+17) = start_sector;
|
||||
#else
|
||||
*(unsigned char*)(bootsector+4) = (total_tracks) & 0xff;
|
||||
*(unsigned char*)(bootsector+5) = (total_tracks >> 8) & 0xff;
|
||||
*(unsigned char*)(bootsector+6) = (total_heads) & 0xff;
|
||||
*(unsigned char*)(bootsector+7) = (total_heads >> 8) & 0xff;
|
||||
*(unsigned char*)(bootsector+8) = (total_sectors) & 0xff;
|
||||
*(unsigned char*)(bootsector+9) = (total_sectors >> 8) & 0xff;
|
||||
|
||||
*(unsigned char*)(bootsector+10) = (setup_size) & 0xff;
|
||||
*(unsigned char*)(bootsector+11) = (setup_size >> 8) & 0xff;
|
||||
*(unsigned char*)(bootsector+12) = system_sectors & 0xff;
|
||||
*(unsigned char*)(bootsector+13) = (system_sectors >> 8) & 0xff;
|
||||
*(unsigned char*)(bootsector+14) = bios_device_code;
|
||||
*(unsigned char*)(bootsector+15) = start_track;
|
||||
*(unsigned char*)(bootsector+16) = start_head;
|
||||
*(unsigned char*)(bootsector+17) = start_sector;
|
||||
#endif
|
||||
|
||||
write (fd_out, bootsector, SECTOR);
|
||||
|
||||
if ((fd = open (argv[2], O_RDONLY|O_BINARY, 0)) < 0)
|
||||
die ("Unable to open setup file.");
|
||||
|
||||
do
|
||||
{
|
||||
if ((bytes_read = read (fd, setupsector, SECTOR)) < 0)
|
||||
die ("Unable to read setup.");
|
||||
|
||||
if (bytes_read > 0)
|
||||
write (fd_out, setupsector, SECTOR);
|
||||
|
||||
} while (bytes_read > 0);
|
||||
|
||||
|
||||
close (fd);
|
||||
|
||||
if ((fd = open (argv[3], O_RDONLY|O_BINARY, 0)) < 0)
|
||||
die ("Unable to open system file.");
|
||||
|
||||
while (to_read > 0)
|
||||
{
|
||||
int l;
|
||||
|
||||
l = (to_read < SECTOR)?to_read:SECTOR;
|
||||
|
||||
if ((bytes_read = read (fd, setupsector, l)) != l)
|
||||
die ("Unable to read system.");
|
||||
|
||||
write (fd_out, setupsector, l);
|
||||
|
||||
to_read -= l;
|
||||
}
|
||||
|
||||
close (fd);
|
||||
close (fd_out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
70
sections
Executable file
70
sections
Executable file
@ -0,0 +1,70 @@
|
||||
/* $Id: sections 5834 2013-10-08 17:04:08Z os $ */
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x100000; /* Startadresse des Systems */
|
||||
|
||||
.text :
|
||||
{
|
||||
*(".text")
|
||||
*(".text.*")
|
||||
*(".text$")
|
||||
*(".init")
|
||||
*(".fini")
|
||||
*(".gnu.linkonce.*")
|
||||
}
|
||||
|
||||
.init_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
KEEP (*(".ctors"))
|
||||
KEEP (*(".ctor"))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
}
|
||||
|
||||
.fini_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(".dtors"))
|
||||
KEEP (*(".dtor"))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
}
|
||||
|
||||
.data :
|
||||
{
|
||||
*(".data")
|
||||
*(".data$")
|
||||
*(".rodata")
|
||||
*(".rodata.*")
|
||||
*(".got")
|
||||
*(".got.plt")
|
||||
*(".eh_frame")
|
||||
*(".eh_fram")
|
||||
*(".jcr")
|
||||
*(".note.*")
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
___BSS_START__ = .;
|
||||
*(".bss")
|
||||
*(".bss.*")
|
||||
___BSS_END__ = .;
|
||||
}
|
||||
|
||||
/*
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(".note")
|
||||
*(".comment")
|
||||
*(".debug_line")
|
||||
*(".debug_info")
|
||||
*(".debug_abbrev")
|
||||
*(".debug_aranges")
|
||||
}
|
||||
*/
|
||||
}
|
284
startup.asm
Executable file
284
startup.asm
Executable file
@ -0,0 +1,284 @@
|
||||
;******************************************************************************
|
||||
;* *
|
||||
;* S T A R T U P . A S M *
|
||||
;* *
|
||||
;*----------------------------------------------------------------------------*
|
||||
;* Beschreibung: '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-Code erfolgen kann. *
|
||||
;* *
|
||||
;* Autor: Olaf Spinczyk, TU Dortmund *
|
||||
;******************************************************************************
|
||||
|
||||
; Multiboot-Konstanten
|
||||
MULTIBOOT_PAGE_ALIGN equ 1<<0
|
||||
MULTIBOOT_MEMORY_INFO equ 1<<1
|
||||
|
||||
; Magic-Number fuer Multiboot
|
||||
MULTIBOOT_HEADER_MAGIC equ 0x1badb002
|
||||
; Multiboot-Flags (ELF-spezifisch!)
|
||||
MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
|
||||
MULTIBOOT_HEADER_CHKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
|
||||
MULTIBOOT_EAX_MAGIC equ 0x2badb002
|
||||
|
||||
;
|
||||
; System
|
||||
;
|
||||
|
||||
[GLOBAL startup]
|
||||
[GLOBAL idt]
|
||||
[GLOBAL __cxa_pure_virtual]
|
||||
[GLOBAL _ZdlPv]
|
||||
|
||||
[EXTERN main]
|
||||
[EXTERN int_disp]
|
||||
|
||||
[EXTERN ___BSS_START__]
|
||||
[EXTERN ___BSS_END__]
|
||||
[EXTERN __init_array_start]
|
||||
[EXTERN __init_array_end]
|
||||
[EXTERN __fini_array_start]
|
||||
[EXTERN __fini_array_end]
|
||||
|
||||
[SECTION .text]
|
||||
|
||||
startup:
|
||||
jmp skip_multiboot_hdr
|
||||
|
||||
multiboot_header:
|
||||
align 4
|
||||
dd MULTIBOOT_HEADER_MAGIC
|
||||
dd MULTIBOOT_HEADER_FLAGS
|
||||
dd MULTIBOOT_HEADER_CHKSUM
|
||||
|
||||
skip_multiboot_hdr:
|
||||
; GCC-kompilierter Code erwartet das so.
|
||||
|
||||
cld
|
||||
|
||||
cmp eax,MULTIBOOT_EAX_MAGIC
|
||||
jne floppy_boot
|
||||
;
|
||||
; GDT setzen (notwendig, falls wir durch GRUB geladen wurden)
|
||||
;
|
||||
lgdt [gdt_48]
|
||||
|
||||
floppy_boot:
|
||||
|
||||
; Globales Datensegment
|
||||
|
||||
mov ax,0x10
|
||||
mov ds,ax
|
||||
mov es,ax
|
||||
mov fs,ax
|
||||
mov gs,ax
|
||||
|
||||
; Stack festlegen
|
||||
|
||||
mov ss,ax
|
||||
mov esp,init_stack+4096
|
||||
|
||||
; Unterbrechungsbehandlung sicherstellen
|
||||
|
||||
call setup_idt
|
||||
call reprogram_pics
|
||||
|
||||
; BSS loeschen
|
||||
mov edi, ___BSS_START__
|
||||
clear_bss:
|
||||
mov byte [edi], 0
|
||||
inc edi
|
||||
cmp edi, ___BSS_END__
|
||||
jne clear_bss
|
||||
|
||||
; Aufruf des C-Codes
|
||||
|
||||
call _init ; Konstruktoren globaler Objekte ausfuehren
|
||||
call main ; C/C++ Level System
|
||||
call _fini ; Destruktoren
|
||||
hlt
|
||||
|
||||
;; Ausfuehrung der Konstruktoren globaler Objekte
|
||||
_init:
|
||||
mov edi, __init_array_start
|
||||
_init_loop:
|
||||
cmp edi, __init_array_end
|
||||
je _init_done
|
||||
mov eax, [edi]
|
||||
call eax
|
||||
add edi, 4
|
||||
ja _init_loop
|
||||
_init_done:
|
||||
ret
|
||||
|
||||
;; Ausfuehrung der Destruktoren globaler Objekte
|
||||
_fini:
|
||||
mov edi, __fini_array_start
|
||||
_fini_loop:
|
||||
cmp edi, __fini_array_end
|
||||
je _fini_done
|
||||
mov eax, [edi]
|
||||
call eax
|
||||
add edi, 4
|
||||
ja _fini_loop
|
||||
_fini_done:
|
||||
ret
|
||||
|
||||
; Default Interrupt Behandlung
|
||||
|
||||
; Spezifischer Kopf der Unterbrechungsbehandlungsroutinen
|
||||
|
||||
%macro wrapper 1
|
||||
wrapper_%1:
|
||||
push eax
|
||||
mov al,%1
|
||||
jmp wrapper_body
|
||||
%endmacro
|
||||
|
||||
; ... wird automatisch erzeugt.
|
||||
%assign i 0
|
||||
%rep 256
|
||||
wrapper i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
; Gemeinsamer Rumpf
|
||||
wrapper_body:
|
||||
cld ; das erwartet der gcc so.
|
||||
push ecx ; Sichern der fluechtigen Register
|
||||
push edx
|
||||
and eax,0xff ; Der generierte Wrapper liefert nur 8 Bits
|
||||
push eax ; Nummer der Unterbrechung uebergeben
|
||||
call int_disp
|
||||
add esp,4 ; Parameter vom Stack entfernen
|
||||
pop edx ; fluechtige Register wieder herstellen
|
||||
pop ecx
|
||||
pop eax
|
||||
iret ; fertig!
|
||||
|
||||
;
|
||||
; setup_idt
|
||||
;
|
||||
; Relokation der Eintraege in der IDT und Setzen des IDTR
|
||||
|
||||
setup_idt:
|
||||
mov eax,wrapper_0 ; ax: niederwertige 16 Bit
|
||||
mov ebx,eax
|
||||
shr ebx,16 ; bx: hoeherwertige 16 Bit
|
||||
mov ecx,255 ; Zaehler
|
||||
.loop: add [idt+8*ecx+0],ax
|
||||
adc [idt+8*ecx+6],bx
|
||||
dec ecx
|
||||
jge .loop
|
||||
|
||||
lidt [idt_descr]
|
||||
ret
|
||||
|
||||
;
|
||||
; reprogram_pics
|
||||
;
|
||||
; Neuprogrammierung der PICs (Programmierbare Interrupt-Controller), damit
|
||||
; alle 15 Hardware-Interrupts nacheinander in der idt liegen.
|
||||
|
||||
reprogram_pics:
|
||||
mov al,0x11 ; ICW1: 8086 Modus mit ICW4
|
||||
out 0x20,al
|
||||
call delay
|
||||
out 0xa0,al
|
||||
call delay
|
||||
mov al,0x20 ; ICW2 Master: IRQ # Offset (32)
|
||||
out 0x21,al
|
||||
call delay
|
||||
mov al,0x28 ; ICW2 Slave: IRQ # Offset (40)
|
||||
out 0xa1,al
|
||||
call delay
|
||||
mov al,0x04 ; ICW3 Master: Slaves an IRQs
|
||||
out 0x21,al
|
||||
call delay
|
||||
mov al,0x02 ; ICW3 Slave: Verbunden mit IRQ2 des Masters
|
||||
out 0xa1,al
|
||||
call delay
|
||||
mov al,0x03 ; ICW4: 8086 Modus und automatischer EIO
|
||||
out 0x21,al
|
||||
call delay
|
||||
out 0xa1,al
|
||||
call delay
|
||||
|
||||
mov al,0xff ; Hardware-Interrupts durch PICs
|
||||
out 0xa1,al ; ausmaskieren. Nur der Interrupt 2,
|
||||
call delay ; der der Kaskadierung der beiden
|
||||
mov al,0xfb ; PICs dient, ist erlaubt.
|
||||
out 0x21,al
|
||||
|
||||
ret
|
||||
|
||||
; delay
|
||||
;
|
||||
; Kurze Verzoegerung fuer in/out Befehle.
|
||||
|
||||
delay:
|
||||
jmp .L2
|
||||
.L2: ret
|
||||
|
||||
; Die Funktion wird beim abarbeiten der globalen Konstruktoren aufgerufen
|
||||
; (unter Linux). Das Label muss definiert sein (fuer den Linker). Die
|
||||
; Funktion selbst kann aber leer sein, da bei StuBs keine Freigabe des
|
||||
; Speichers erfolgen muss.
|
||||
|
||||
__cxa_pure_virtual:
|
||||
_ZdlPv:
|
||||
ret
|
||||
|
||||
[SECTION .data]
|
||||
|
||||
; 'interrupt descriptor table' mit 256 Eintraegen.
|
||||
|
||||
idt:
|
||||
|
||||
%macro idt_entry 1
|
||||
dw (wrapper_%1 - wrapper_0) & 0xffff
|
||||
dw 0x0008
|
||||
dw 0x8e00
|
||||
dw ((wrapper_%1 - wrapper_0) & 0xffff0000) >> 16
|
||||
%endmacro
|
||||
|
||||
; ... wird automatisch erzeugt.
|
||||
|
||||
%assign i 0
|
||||
%rep 256
|
||||
idt_entry i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
idt_descr:
|
||||
dw 256*8-1 ; idt enthaelt 256 Eintraege
|
||||
dd idt
|
||||
|
||||
; Stack und interrupt descriptor table im BSS Bereich
|
||||
|
||||
[SECTION .bss]
|
||||
|
||||
init_stack:
|
||||
resb 4096
|
||||
|
||||
[SECTION .data]
|
||||
;
|
||||
; 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)
|
||||
|
||||
gdt_48:
|
||||
dw 0x18 ; GDT Limit=24, 3 GDT Eintraege
|
||||
dd gdt ; Physikalische Adresse der GDT
|
Reference in New Issue
Block a user