add vorgabe09
This commit is contained in:
@ -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
68
c_os/devices/PIT.cc
Executable 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
47
c_os/devices/PIT.h
Executable 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 ©); // 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
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 */
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
@ -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 *
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user