1

add vorgabe09

This commit is contained in:
2022-07-04 16:17:39 +02:00
parent 586fe3bb80
commit da6c5ab0b5
13 changed files with 231 additions and 40 deletions

View File

@ -84,28 +84,6 @@ inline void PCSPK::delay(int time) {
/* Hier muess Code eingefuegt werden */
// 1.19 MHz => 1s for full countdown
unsigned short cntStart = 1193180 / 1000; // 1s / 1000 = 1ms countdown
// 00110000 => 0x30: Counter0, LoByte/HiByte, Mode0, Binary
// 00110010 => 0x32: Counter0, LoByte/HiByte, Mode1, Binary
// 00110100 => 0x34: Counter0, LoByte/HiByte, Mode2, Binary
// 00110110 => 0x36: Counter0, LoByte/HiByte, Mode3, Binary
control.outb(0x34); // Zaehler-0 konfigurieren
data0.outb(cntStart & 0xFF); // Zaehler-0 laden (Lobyte)
data0.outb(cntStart >> 8); // Zaehler-0 laden (Hibyte)
int initial_count, current_count;
for (int i = 0; i < time; ++i) {
initial_count = readCounter();
while (1) {
current_count = readCounter();
if (current_count > initial_count) break; // The counter has already been reset
initial_count = current_count;
}
}
}
/*****************************************************************************

68
c_os/devices/PIT.cc Executable file
View File

@ -0,0 +1,68 @@
/*****************************************************************************
* *
* P I T *
* *
*---------------------------------------------------------------------------*
* Beschreibung: Programmable Interval Timer. *
* *
* Autor: Michael Schoettner, 3.7.2022 *
*****************************************************************************/
#include "devices/PIT.h"
#include "kernel/IOport.h"
#include "kernel/Globals.h"
/*****************************************************************************
* Methode: PIT::interval *
*---------------------------------------------------------------------------*
* Beschreibung: Zeitinervall programmieren. *
* *
* Parameter: *
* us: Zeitintervall in Mikrosekunden, nachdem periodisch ein *
* Interrupt erzeugt werden soll. *
*****************************************************************************/
void PIT::interval (int us) {
/* hier muss Code eingefuegt werden */
}
/*****************************************************************************
* Methode: PIT::plugin *
*---------------------------------------------------------------------------*
* Beschreibung: Unterbrechungen fuer den Zeitgeber erlauben. Ab sofort *
* wird bei Ablauf des definierten Zeitintervalls die *
* Methode 'trigger' aufgerufen. *
*****************************************************************************/
void PIT::plugin () {
/* hier muss Code eingefuegt werden */
}
/*****************************************************************************
* Methode: PIT::trigger *
*---------------------------------------------------------------------------*
* Beschreibung: ISR fuer den Zeitgeber. Wird aufgerufen, wenn der *
* Zeitgeber eine Unterbrechung ausloest. Anzeige der Uhr *
* aktualisieren und Thread wechseln durch Setzen der *
* Variable 'forceSwitch', wird in 'int_disp' behandelt. *
*****************************************************************************/
void PIT::trigger () {
/* hier muss Code eingefuegt werden */
// alle 10ms, Systemzeit weitersetzen
systime++;
// Bei jedem Tick einen Threadwechsel ausloesen.
// Aber nur wenn der Scheduler bereits fertig intialisiert wurde
// und ein weiterer Thread rechnen moechte
/* hier muss Code eingefuegt werden */
}

47
c_os/devices/PIT.h Executable file
View File

@ -0,0 +1,47 @@
/*****************************************************************************
* *
* P I T *
* *
*---------------------------------------------------------------------------*
* Beschreibung: Programmable Interval Timer. *
* *
* Autor: Michael Schoettner, 23.8.2016 *
*****************************************************************************/
#ifndef __PIT_include__
#define __PIT_include__
#include "kernel/interrupts/ISR.h"
class PIT : public ISR {
private:
PIT(const PIT &copy); // Verhindere Kopieren
private:
enum { time_base = 838 }; /* ns */
int timer_interval;
public:
// Zeitgeber initialisieren.
PIT (int us) {
interval (us);
}
// Konfiguriertes Zeitintervall auslesen.
int interval () {
return timer_interval;
}
// Zeitintervall in Mikrosekunden, nachdem periodisch ein Interrupt
//erzeugt werden soll.
void interval (int us);
// Aktivierung der Unterbrechungen fuer den Zeitgeber
void plugin ();
// Unterbrechnungsroutine des Zeitgebers.
void trigger ();
};
#endif

View File

@ -17,9 +17,11 @@ Keyboard kb; // Tastatur
IntDispatcher intdis; // Unterbrechungsverteilung
PIC pic; // Interrupt-Controller
unsigned int total_mem; // RAM total
unsigned long systime = 0;
// BumpAllocator allocator;
// LinkedListAllocator allocator;
TreeAllocator allocator;
Scheduler scheduler;
BIOS bios; // Schnittstelle zum 16-Bit BIOS
VESA vesa; // VESA-Treiber
PIT pit(10000);

View File

@ -22,6 +22,7 @@
#include "kernel/interrupts/IntDispatcher.h"
#include "kernel/interrupts/PIC.h"
#include "kernel/threads/Scheduler.h"
#include "devices/PIT.h"
extern CPU cpu; // CPU-spezifische Funktionen
extern PCSPK pcspk; // PC-Lautsprecher
@ -29,7 +30,9 @@ extern CGA_Stream kout; // Ausgabe-Strom fuer Kernel
extern Keyboard kb; // Tastatur
extern IntDispatcher intdis; // Unterbrechungsverteilung
extern PIC pic; // Interrupt-Controller
extern PIT pit; // Zeitgeber
extern unsigned int total_mem; // RAM total
extern unsigned long systime; // wird all 10ms hochgezaehlt
// extern BumpAllocator allocator;
// extern LinkedListAllocator allocator;
extern TreeAllocator allocator;

View File

@ -22,6 +22,9 @@ public:
IdleThread() {}
void run() override {
// Idle-Thread läuft, ab jetzt ist der Scheduler fertig initialisiert
scheduler.setInitialized();
while (true) {
scheduler.yield();
// kout << "Idle!" << endl;

View File

@ -22,7 +22,8 @@ void Scheduler::schedule() {
/* hier muss Code eingefuegt werden */
Thread* idle = new IdleThread();
this->readyQueue.enqueue(idle);
// this->readyQueue.enqueue(idle);
this->ready(idle);
/* Bevor diese Methode anufgerufen wird, muss zumindest der Idle-Thread
* in der Queue eingefuegt worden sein.
@ -44,7 +45,13 @@ void Scheduler::ready(Thread* that) {
/* hier muss Code eingefuegt werden */
// Thread-Wechsel durch PIT verhindern
cpu.disable_int ();
this->readyQueue.enqueue(that);
// Thread-Wechsel durch PIT jetzt wieder erlauben
cpu.enable_int ();
}
/*****************************************************************************
@ -59,8 +66,14 @@ void Scheduler::exit() {
/* hier muss Code eingefuegt werden */
// Thread-Wechsel durch PIT verhindern
cpu.disable_int ();
Thread& next = *(Thread*)this->readyQueue.dequeue();
this->dispatch(next);
// Interrupts werden in Thread_switch in Thread.asm wieder zugelassen
// dispatch kehr nicht zurueck
}
/*****************************************************************************
@ -78,7 +91,13 @@ void Scheduler::kill(Thread* that) {
/* hier muss Code eingefuegt werden */
// Thread-Wechsel durch PIT verhindern
cpu.disable_int ();
this->readyQueue.remove(that);
// Thread-Wechsel durch PIT jetzt wieder erlauben
cpu.enable_int ();
}
/*****************************************************************************
@ -96,6 +115,9 @@ void Scheduler::yield() {
/* hier muss Code eingefuegt werden */
// Thread-Wechsel durch PIT verhindern
cpu.disable_int ();
// When only one thread exists (IdleThread) it can't yield as the readyqueue becomes empty
// and this is not handled anywhere else
if (this->readyQueue.isEmpty()) {
@ -106,4 +128,20 @@ void Scheduler::yield() {
Thread& next = *(Thread*)this->readyQueue.dequeue();
this->readyQueue.enqueue(this->get_active());
this->dispatch(next);
// Thread-Wechsel durch PIT jetzt wieder erlauben
cpu.enable_int ();
}
/*****************************************************************************
* Methode: Scheduler::preempt *
*---------------------------------------------------------------------------*
* Beschreibung: Diese Funktion wird aus der ISR des PITs aufgerufen und *
* schaltet auf den naechsten Thread um, sofern einer vor- *
* handen ist. *
*****************************************************************************/
void Scheduler::preempt () {
/* Hier muss Code eingefuegt werden */
}

View File

@ -22,8 +22,20 @@ private:
Queue readyQueue; // auf die CPU wartende Threads
// Scheduler wird evt. von einer Unterbrechung vom Zeitgeber gerufen,
// bevor er initialisiert wurde
bool initialized;
public:
Scheduler() {}
Scheduler() : initialized(false) {}
// Scheduler initialisiert?
// Zeitgeber-Unterbrechung kommt evt. bevor der Scheduler fertig
// intiialisiert wurde!
bool isInitialized() { return initialized; }
// ruft nur der Idle-Thread (erster Thread der vom Scheduler gestartet wird)
void setInitialized() { initialized = true; }
// Scheduler starten
void schedule();
@ -39,6 +51,10 @@ public:
// CPU freiwillig abgeben und Auswahl des naechsten Threads
void yield();
// Thread umschalten; wird aus der ISR des PITs gerufen
void preempt ();
};
#endif

View File

@ -70,6 +70,15 @@ void Thread_init(struct ThreadState* regs, unsigned int* stack, void (*kickoff)(
regs->edi = 0;
regs->ebp = 0;
regs->esp = sp; // esp now points to the location of the address of kickoff
// nachfolgend die fluechtige Register
// wichtig fuer preemptives Multitasking
regs->eax = 0;
regs->ecx = 0;
regs->edx = 0;
// flags initialisieren
regs->efl = (void*)0x200; // Interrupt-Enable
}
/*****************************************************************************

View File

@ -15,6 +15,13 @@
* ThreadState, in dem die Werte der nicht-fluechtigen *
* Register gesichert werden koennen. *
* *
* Zusaetzlich zum vorhandenen freiwilligen Umschalten der *
* CPU mit 'Thread_switch' gibt es nun ein forciertes Um- *
* durch den Zeitgeber-Interrupt ausgeloest wird und in *
* Assembler in startup.asm implementiert ist. Fuer das *
* Zusammenspiel mit dem Scheduler ist die Methode *
* 'prepare_preemption' in Scheduler.cc wichtig. *
* *
* Autor: Michael, Schoettner, HHU, 16.12.2016 *
*****************************************************************************/

View File

@ -24,3 +24,7 @@ esi_offset: resd 1
edi_offset: resd 1
ebp_offset: resd 1
esp_offset: resd 1
eax_offset: resd 1
ecx_offset: resd 1
edx_offset: resd 1
efl_offset: resd 1

View File

@ -34,6 +34,12 @@ struct ThreadState {
void* edi;
void* ebp;
void* esp;
// nachfolgend die fluechtige Register
// wichtig fuer preemptives Multitasking
void *eax;
void *ecx;
void *edx;
void *efl;
};
#endif

View File

@ -8,10 +8,18 @@
;* Es wird alles vorbereitet, damit so schnell wie moeglich *
;* die weitere Ausfuehrung durch C-Code erfolgen kann. *
;* *
;* Hier erweitert, um BIOS callund Paging-Aktivierung, *
;* Unterstuetzung des Bluescreens und preemptives *
;* Thread-Switching. *
;* *
;* Autor: Olaf Spinczyk, TU Dortmund *
;* Michael Schoettner, HHU, 15.12.2018 *
;* Michael Schoettner, HHU, 3.7.2022 *
;******************************************************************************
; fuer preemptives Umschalten zwischen Threads
%include "kernel/threads/Thread.inc"
; Multiboot-Konstanten
MULTIBOOT_PAGE_ALIGN equ 1<<0
MULTIBOOT_MEMORY_INFO equ 1<<1
@ -36,6 +44,7 @@ MULTIBOOT_EAX_MAGIC equ 0x2badb002
[GLOBAL get_page_fault_address]
[GLOBAL get_int_esp]
; Michael Schoettner:
; Nachfolgender label steht fuer das 'delete', welches jetzt implementiert
; wird. Damit der Linker nicht wegen doppelter Definition "meckert"
@ -158,17 +167,17 @@ wrapper i
; 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
popad ; alle Register wiederherstellen
iret ; fertig!
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; Interrupt-Dispatcher aufrufen
add esp,4 ; Parameter vom Stack entfernen
pop edx ; fluechtige Register wieder herstellen
pop ecx
popad ; alle Register wiederherstellen
iret ; fertig!
;
; setup_idt
@ -371,7 +380,7 @@ idt16_descr:
; (genauerer Stack-Aufbau siehe Bluescreen.cc)
;
; |-------------|
; |  EFLAGS |
; | EFLAGS |
; |-------------|
; | CS |
; |-------------|
@ -379,8 +388,9 @@ idt16_descr:
; |-------------|
; | [ErrorCode] |
; |-------------|
; | alle Regs. |
; | (PUSHAD) |
; | alle Regs. |
; | (PUSHAD) |
; |-------------| <-- int_esp
int_esp:
db 0,0,0,0
db 0,0,0,0