Commit 395a8e97 authored by Bernhard Heinloth's avatar Bernhard Heinloth
Browse files

Vorgabe oostubs Aufgabe 1

parent 29fc36a8
# vim: set et ts=4 sw=4:
# -----------------------------------------------------------------------------
#
# M A K E F I L E
#
# Zum Uebungsbetriebssystem OO/MP-StuBS der Lehrveranstaltung Betriebssysteme.
# -----------------------------------------------------------------------------
#
# Durch Eingabe von 'make' werden die Quelltexte des Systems kompiliert.
# Es gibt Targets in mehreren Varianten, <name>, <name>-noopt sowie
# <name>-verbose.
# Targets mit dem Suffix -noopt werden ohne Optimierungen kompiliert. Dies
# kann sich z.B. für das Debugging mit gdb eignen.
# Bei dem Suffix -verbose werden umfangreiche Ausgaben (über den Ausgabestrom
# DBG_VERBOSE) angezeigt, was beim printf-Debugging hilfreich sein kann.
#
# Folgende Targets sind verfügbar (jeweils auch mit -noopt):
# all: Das System wird gebaut und liegt anschließend als ELF-Binary vor.
#
# kvm: KVM wird gestartet und führt euer System in einer
# Hardware-Beschleunigten virtuellen Maschine aus. Dieses Target ruft
# aus Sicherhietsgründen ein CIP-Pool spezifisches Script auf.
#
# netboot: Das System wird in das Netzwerkverzeichnis kopiert und kann auf den
# Testrechner gestartet werden
#
# iso: Erstellt ein bootfähiges Abbild für den Start auf Testrechner
# mittels externe Datenträger
#
# qemu: QEMU wird gestartet und führt euer System aus. Da QEMU langsamer
# ist als KVM treten hier u.U. andere Fehler hervor als in KVM oder
# auf der Hardware.
#
# qemu-iso: QEMU start und führt euer System von der ISO (als CD eingelegt) aus
#
# qemu-gdb: QEMU wird mit aktiviertem GDB-Stub gestartet und eine GDB-Instanz
# angehängt, damit lässt sich euer System Schritt für Schritt
# debuggen
#
# qemu-ddd: Wie qemu-gdb nur dient hier DDD als Frontend.
#
# help: Zeigt eine umfangreiche Hilfe an
#
# -----------------------------------------------------------------------------
# Rewrite 02/2014: gabor
# -----------------------------------------------------------------------------
# --------------------------------------------------------------------------
# Default target
.DEFAULT_GOAL = all
# --------------------------------------------------------------------------
# Zu uebersetzende Quelldateien (Wichtig: vor common.mk definieren!)
CC_SOURCES = $(shell find . -name "*.cc" -and ! -name '.*' -and ! -path './test*' -and ! -path './fs/tool/*')
ASM_SOURCES = $(shell find . -name "*.asm" -and ! -name '.*' -and ! -name "startup.asm")
STARTUP_SOURCE = startup.asm
STARTUP_OBJECT = $(OBJDIR)/_startup.o
# Pfad zum Ordner für Dateien für die initiale Ramdisk (für Aufgabe 7)
INITRD_DIR ?= initrd/
INITRD_TOOL ?= fs/tool/fstool
INITRD_DEP =
# 1MB Freier Speicher
INITRD_FREE ?= 1048576
# --------------------------------------------------------------------------
# Globale Variablen und Standard-Rezepte einbinden
include common.mk
# -----------------------------------------------------------------------------
# Parameter:
KERNEL = $(OBJDIR)/system
ISOFILE = $(OBJDIR)/stubs.iso
ifneq ($(wildcard $(INITRD_DIR)*),)
INITRD = $(OBJDIR)/initrd.img
INITRD_DEP += $(shell find $(INITRD_DIR) -type f )
$(KERNEL): $(INITRD)
endif
all: $(KERNEL)
# Rezept zum Linken des Systemimages
$(KERNEL): $(STARTUP_OBJECT) $(OBJPRE) $(MAKEFILE_LIST)
@echo "LD $@"
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi
$(VERBOSE) $(LD) -e startup -T boot/sections.ld -o $(KERNEL) $(LDFLAGS) $(STARTUP_OBJECT) $(LDHEAD) $(OBJPRE) $(LDTAIL) $(LDLIBS)
# Tool zum Bearbeiten eines Minix-v3 Abbildes (Aufgabe 7)
$(INITRD_TOOL): $(shell test -d $(dir $(INITRD_TOOL)) && find $(dir $(INITRD_TOOL)) -name "*.cc" -or -name '*.h')
@echo "Make $@"
@make -C $(dir $(INITRD_TOOL))
# Ramdisk mit Minix v3 Dateisystem
$(INITRD): $(INITRD_TOOL) $(INITRD_DEP)
@echo "INITRD $@"
@dd if=/dev/zero of=$@ bs=$(shell du -s $(INITRD_DIR) | cut -f1 | xargs expr $(INITRD_FREE) + ) count=1
@/sbin/mkfs.minix -3 $@ # optional --inodes <number>
@./$(INITRD_TOOL) put "$(INITRD_DIR)" $@
/* vim: set et ts=4 sw=4: */
SECTIONS
{
. = 0x1000000; /* Startadresse des Systems */
.text :
{
*(".text")
*(".text$")
*(".init")
*(".fini")
*(".gnu.linkonce.*")
}
/* Liste von Startadressen der globalen Konstruktoren (benoetigt ab gcc 4.7) */
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
}
.data :
{
*(".data")
*(".data$")
*(".rodata")
___CTOR_LIST__ = .;
*(".ctors")
*(".ctor")
___CTOR_LIST_END__ = .;
___DTOR_LIST__ = .;
*(".dtors")
*(".dtor")
___DTOR_LIST_END__ = .;
*(".got")
*(".got.plt")
*(".eh_frame")
*(".eh_fram")
*(".jcr")
}
/* Startcode fuer die APs, wird von SMPSystem::copyStartAPtoLowMem() reloziert */
.setup_ap_seg ALIGN(0x10) :
{
___SETUP_AP_START__ = .;
*(".setup_ap_seg")
*(".setup_ap_seg$")
___SETUP_AP_END__ = .;
}
.vesa_detection ALIGN(0x10):
{
__VESA_DETECTION_CODE_START__ = .;
*(".vesa_detection")
*(".vesa_detection$")
__VESA_DETECTION_CODE_END__ = .;
}
.bss :
{
*(".bss")
*(".bss.*")
*(COMMON)
}
___IMG_END___ = .;
/*
/DISCARD/ :
{
*(".note")
*(".comment")
*(".debug_line")
*(".debug_info")
*(".debug_abbrev")
*(".debug_aranges")
}
*/
}
; 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
// vim: set et ts=4 sw=4:
/*! \file
* \brief Enthält Funktionen für den Systemstart, die nicht mehr in
* Assembler geschrieben werden müssen.
*/
#include "types.h"
#include "machine/apicsystem.h"
#include "machine/cpu.h"
#include "machine/io_port.h"
/*! \brief Die Zeiger auf die Multiboot-Strukturen wird vom Assembler-
* startup zugewiesen.
*/
void *multiboot_addr = 0;
/*! \brief Hilfsfunktion der PIT-Initialisierung, die ein kurzes Delay
* verursacht.
*/
static void delay()
{
asm volatile("nop\n\t":::"memory");
}
/*! \brief Initalisierung der PICs (Programmierbare Interrupt-Controller),
* damit alle 15 Hardware-Interrupts nacheinander in der idt liegen.
*/
static void initialise_pics()
{
IO_Port p20(0x20);
IO_Port p21(0x21);
IO_Port pa0(0xa0);
IO_Port pa1(0xa1);
//ICW1: 8086 Modus mit ICW4
p20.outb(0x11);
delay();
pa0.outb(0x11);
delay();
//ICW2 Master: IRQ # Offset (32)
p21.outb(0x20);
delay();
//ICW2 Slave: IRQ # Offset (40)
pa1.outb(0x28);
delay();
//ICW3 Master: Slaves an IRQs
p21.outb(0x04);
delay();
//ICW3 Slave: Verbunden mit IRQ2 des Masters
pa1.outb(0x02);
delay();
//ICW4: 8086 Modus und automatischer EIO
p21.outb(0x03);
delay();
pa1.outb(0x03);
delay();
//Alle Hardware-Interrupts durch Legacy-PICs ausmaskieren.
pa1.outb(0xff);
delay();
p21.outb(0xff);
}
/*! \brief Ab gcc 4.7 weitere Initialisierung globaler Objekte.
*
*/
static void csu_init()
{
extern void (*__init_array_start []) ();
extern void (*__init_array_end[]) ();
const size_t size = __init_array_end - __init_array_start;
for (size_t i = 0; i < size; i++) {
(*__init_array_start[i])();
}
}
extern "C" void _init();
extern "C" void _fini();
extern "C" int main_ap() __attribute__ ((weak));
extern "C" int main();
static bool bootCPU = true;
extern "C" void kernel_init()
{
if(bootCPU) {
bootCPU = false;
//initialisierung der PICs
initialise_pics();
//Aufruf globaler Konstruktoren
_init();
csu_init();
//weitere Initialisierungen
system.detectSystemType();
system.setupThisProcessor();
//Die main-Funktion
main();
//falls die main-Funktion zurückkehren sollte werden die Destruktoren
//globaler Objekte aufgerufen
_fini();
}
else {
// Initialisiere diesen AP Prozessor
system.setupThisProcessor();
// Springe die Anwendung an.
main_ap();
}
for(;;) {
CPU::die();
}
}
# --------------------------------------------------------------------------
# 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: Verzeichnispräfix, in dem die Objektdateien abgelegt werden
# sollen.
# DEPDIR: Verzeichnispräfix, in dem die Abhaengigkeitsdateien abgelegt
# werden sollen
# ISOIR: Verzeichnispräfix, in dem die Daten für das bootfähige
# Medium angelegt werden sollen
# NOOPTTAG: Endung, welche an die Verzeichnisse für Objekt- und
# Abhängigkeitsdateien bei Debugversionen angehängt wird
# VERBOSETAG: Endung ähnlich NOOPTTAG, nur für Builds mit Verboseausgaben
# ASM: Zu benutzender Assembler
# CC/CXX: Zu benutzender C/C++-Compiler
# AR: Zu benutzender Archivierer
# 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
VERBOSE = @
ASMOBJFORMAT = elf
OBJDIR = ./build
DEPDIR = ./dep
NOOPTTAG = -noopt
VERBOSETAG = -verbose
SOLUTIONDIR = /proj/i4bs/solution
SOLUTIONPREFIX = musterloesung-u
ASM = nasm
CXX = g++
LD = ld
MKISO = grub-mkrescue
QEMU = qemu-system-i386
PROJECT="OOStuBS"
WARNFLAGS = -Wall -Wextra -Werror -Wno-error=unused-parameter
OPTFLAGS = -O3 -fomit-frame-pointer
FLOATINGPOINT = -mno-mmx -mno-sse
STANDALONEFLAGS = -ffreestanding -fno-builtin -nodefaultlibs -nostdlib -nostdinc
ifeq ($(CXX),g++)
STANDALONEFLAGS += -fno-tree-loop-distribute-patterns -nostartfiles
WARNFLAGS += -Wstack-usage=1024 -Wno-error=stack-usage=
else ifeq ($(CXX),clang++)
WARNFLAGS += -Wno-error=unused-private-field -Wno-implicit-exception-spec-mismatch -Wno-error=unused-const-variable
endif
CXXFLAGS = -std=c++11 -m32 -I. $(OPTFLAGS) $(WARNFLAGS) $(STANDALONEFLAGS) $(FLOATINGPOINT) -Wno-non-virtual-dtor -fno-rtti -fno-exceptions -Wno-write-strings -fno-stack-protector -mno-red-zone -g -gdwarf-2
ASMFLAGS = -f $(ASMOBJFORMAT)
LDFLAGS = -melf_i386
LDHEAD = $(shell $(CXX) -m32 --print-file-name=crti.o && $(CXX) -m32 --print-file-name=crtbegin.o)
LDTAIL = $(shell $(CXX) -m32 --print-file-name=crtend.o && $(CXX) -m32 --print-file-name=crtn.o)
AR = ar
QEMUCPUS = 4
QEMUFLAGS = -k en-us -serial pty -d guest_errors
INITRD = /dev/null
ISODIR = ./build-iso
ISOBOOTDIR = /boot
ISOGRUBCFG = $(ISOBOOTDIR)/grub/grub.cfg
ISOKERNEL = $(ISOBOOTDIR)/kernel
GRUBTIMEOUT = 2
GRUBBIN = /usr/lib/grub/i386-pc
DD = dd
XORRISO = xorriso
ifeq (,$(wildcard $(GRUBBIN)))
GRUBBIN = /proj/i4bs/tools/grub-i386-pc
endif
# Namen der Unterverzeichnisse mit den Quelltexten
VPATH = $(sort $(dir $(STARTUP_SOURCE) $(CC_SOURCES) $(ASM_SOURCES)))
# -------------------------------------------------------------------------
# Listen mit den Objektdateien, die beim Kompilieren entstehen:
# (Die Eingabevariablen werden vom eigentlichen Makefile zwar erst spaeter
# definiert, sind aber zum Auswertezeitpunkt *dieser* Variablen schon
# verfuegbar.)
STARTUP_OBJECT = $(addprefix $(OBJDIR)/,$(patsubst %.asm,_%.o, $(notdir $(STARTUP_SOURCE))))
CC_OBJECTS = $(notdir $(CC_SOURCES:.cc=.o))
DEP_FILES = $(patsubst %.o,$(DEPDIR)/%.d,$(CC_OBJECTS))
ASM_OBJECTS = $(patsubst %.asm,_%.o, $(notdir $(ASM_SOURCES)))
OBJPRE = $(addprefix $(OBJDIR)/,$(ASM_OBJECTS) $(CC_OBJECTS))
# --------------------------------------------------------------------------
# Standardrezept zur Erzeugung der Abhaengigkeitsdateien
$(DEPDIR)/%.d : %.cc $(MAKEFILE_LIST)
@echo "DEP $@"
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi
$(VERBOSE) $(CXX) $(CXXFLAGS) -MM -MT $(OBJDIR)/$*.o -MF $@ $<
# --------------------------------------------------------------------------
# Standardrezept zur Erzeugung von Objektdateien
$(OBJDIR)/%.o : %.cc $(MAKEFILE_LIST)
@echo "CXX $@"
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi
$(VERBOSE) $(CXX) -c $(CXXFLAGS) -o $@ $<
$(OBJDIR)/_%.o : %.asm $(MAKEFILE_LIST)
@echo "ASM $@"
@if test \( ! \( -d $(@D) \) \) ;then mkdir -p $(@D);fi
$(VERBOSE) $(ASM) $(ASMFLAGS) -o $@ $<
# --------------------------------------------------------------------------
# Standardrezept 'clean' loescht das generierte System, die Objektdateien und
# die Abhaengigkeitsdateien
clean: