Compare commits
29 Commits
7c1f380184
...
e8135e9ff9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8135e9ff9 | ||
|
|
c38000e503 | ||
|
|
9ffd22e941 | ||
|
|
698d0c155b | ||
|
|
68f0381c01 | ||
|
|
bc0a94b705 | ||
|
|
2a7d1bdedc | ||
|
|
689c77f19e | ||
|
|
38a10f2010 | ||
|
|
f5c42a8e77 | ||
|
|
638aa9b636 | ||
|
|
7322a9ed70 | ||
|
|
e6d6e7521c | ||
|
|
da34f7cada | ||
|
|
94249eda37 | ||
|
|
d9978ddc37 | ||
|
|
68e11c9793 | ||
|
|
5b664840d8 | ||
|
|
944d4991cb | ||
|
|
76eb2420bd | ||
|
|
b422ee176a | ||
|
|
c1145d28f8 | ||
|
|
ab76afa30a | ||
|
|
3d659e0eab | ||
|
|
e8ec76112b | ||
|
|
a0e2a59f96 | ||
|
|
24a0888760 | ||
|
|
f90eaa3fcd | ||
|
|
a38b6cbdb2 |
195
1
Normal file
195
1
Normal file
@@ -0,0 +1,195 @@
|
||||
#include "arch/lapic.h"
|
||||
#include "boot/startup_ap.h"
|
||||
#include "arch/core_interrupt.h"
|
||||
#include "debug/copystream.h"
|
||||
#include "debug/output.h"
|
||||
#include "debug/assert.h"
|
||||
|
||||
#include "arch/cga.h"
|
||||
#include "arch/textwindow.h"
|
||||
#include "arch/serial.h"
|
||||
#include "device/serialstream.h"
|
||||
#include "device/textstream.h"
|
||||
#include "device/ps2controller.h"
|
||||
#include "arch/ioapic.h"
|
||||
#include "thread/scheduler.h"
|
||||
#include "user/app1/appl.h"
|
||||
#include "sync/ticketlock.h"
|
||||
#include "interrupt/guard.h"
|
||||
|
||||
#include "arch/context.h"
|
||||
#include "thread/thread.h"
|
||||
|
||||
///TextStream kout = TextStream(0, 80, 0, 10, true);
|
||||
Ticketlock koutlock;
|
||||
Scheduler sch;
|
||||
|
||||
//TextStream dout[8] = {
|
||||
// TextStream(0 ,20,12,25,false),
|
||||
// TextStream(20,40,12,25,false),
|
||||
// TextStream(40,60,12,25,false),
|
||||
// TextStream(60,80,12,25,false),
|
||||
// TextStream(0 ,0 ,0, 0,false),
|
||||
// TextStream(0 ,0 ,0, 0,false),
|
||||
// TextStream(0 ,0 ,0, 0,false),
|
||||
// TextStream(0 ,0 ,0, 0,false),
|
||||
//};
|
||||
|
||||
|
||||
TextStream dout[Core::MAX] = {
|
||||
{0, 40, 10, 14},
|
||||
{40, 80, 10, 14},
|
||||
{0, 40, 14, 18},
|
||||
{40, 80, 14, 18},
|
||||
{0, 40, 18, 22},
|
||||
{40, 80, 18, 22},
|
||||
{0, 40, 22, 25},
|
||||
{40, 80, 22, 25},
|
||||
};
|
||||
|
||||
CopyStream copystream[Core::MAX]{
|
||||
{&dout[0], &sout},
|
||||
{&dout[1], &sout},
|
||||
{&dout[2], &sout},
|
||||
{&dout[3], &sout},
|
||||
{&dout[4], &sout},
|
||||
{&dout[5], &sout},
|
||||
{&dout[6], &sout},
|
||||
{&dout[7], &sout},
|
||||
};
|
||||
|
||||
OutputStream* copyout[Core::MAX]{
|
||||
&dout[0],
|
||||
©stream[1],
|
||||
&dout[2],
|
||||
&dout[3],
|
||||
&dout[4],
|
||||
&dout[5],
|
||||
&dout[6],
|
||||
&dout[7]
|
||||
};
|
||||
|
||||
unsigned int testx, testy;
|
||||
|
||||
uint8_t test1_stack[1024];
|
||||
uint8_t test2_stack[1024];
|
||||
uint8_t test3_stack[1024];
|
||||
uint8_t test4_stack[1024];
|
||||
uint8_t test5_stack[1024];
|
||||
uint8_t test6_stack[1024];
|
||||
uint8_t test7_stack[1024];
|
||||
uint8_t test8_stack[1024];
|
||||
uint8_t test9_stack[1024];
|
||||
|
||||
|
||||
|
||||
//Thread test1_thread = Thread(&test1_stack[sizeof(test1_stack)-1]);
|
||||
Application application1 = Application(&test1_stack[sizeof(test1_stack)-1]);
|
||||
Application application2 = Application(&test2_stack[sizeof(test2_stack)-1]);
|
||||
Application application3 = Application(&test3_stack[sizeof(test3_stack)-1]);
|
||||
Application application4 = Application(&test4_stack[sizeof(test4_stack)-1]);
|
||||
Application application5 = Application(&test5_stack[sizeof(test5_stack)-1]);
|
||||
Application application6 = Application(&test6_stack[sizeof(test5_stack)-1]);
|
||||
Application application7 = Application(&test7_stack[sizeof(test5_stack)-1]);
|
||||
Application application8 = Application(&test8_stack[sizeof(test5_stack)-1]);
|
||||
Application application9 = Application(&test9_stack[sizeof(test5_stack)-1]);
|
||||
|
||||
//Context test2;
|
||||
//uint8_t test2_stack[256];
|
||||
//Thread test2_thread = Thread(&test2_stack[sizeof(test2_stack)-1]);
|
||||
|
||||
//void test_func1(){
|
||||
// while(1){
|
||||
// {
|
||||
// Guarded g = Guard::enter();
|
||||
// g.vault().kout << "test 1\n" << flush;
|
||||
// }
|
||||
// context_switch(&test2, &test1);
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void test_func2(){
|
||||
// while(1){
|
||||
// {
|
||||
// Guarded g = Guard::enter();
|
||||
// g.vault().kout << "test 2\n" << flush;
|
||||
// }
|
||||
// context_switch(&test1, &test2);
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
// Main function
|
||||
// (the bootstrap processor starts here)}
|
||||
extern "C" int main() {
|
||||
CGA::setCursor(0, 0);
|
||||
|
||||
unsigned int numCPUs = Core::count();
|
||||
/* Start application processors
|
||||
* To avoid unexpected behaviour, make sure that interrupts are not
|
||||
* enabled before the APs are booted. Otherwise it might interfere with the
|
||||
* Startup IPIs or even block devices like keyboard because of a missing EOI
|
||||
*/
|
||||
|
||||
{
|
||||
Guarded g = Guard::enter();
|
||||
sch.ready(&application1);
|
||||
sch.ready(&application2);
|
||||
sch.ready(&application3);
|
||||
sch.ready(&application4);
|
||||
sch.ready(&application5);
|
||||
sch.ready(&application6);
|
||||
sch.ready(&application7);
|
||||
sch.ready(&application8);
|
||||
sch.ready(&application9);
|
||||
}
|
||||
|
||||
ApplicationProcessor::boot();
|
||||
|
||||
PS2Controller::init();
|
||||
|
||||
IOAPIC::init();
|
||||
IOAPIC::config(1, Core::Interrupt::KEYBOARD);
|
||||
IOAPIC::allow(1);
|
||||
|
||||
Core::Interrupt::enable();
|
||||
|
||||
PS2Controller::drainBuffer();
|
||||
|
||||
DBG << "Main CPU " << static_cast<int>(LAPIC::getID()) << endl << flush;
|
||||
|
||||
|
||||
|
||||
{
|
||||
Guarded g = Guard::enter();
|
||||
sch.schedule();
|
||||
}
|
||||
|
||||
|
||||
//Application{}.action();
|
||||
while (true){
|
||||
//DBG << "pos: " << testx << ", " << testy << endl << flush;
|
||||
//Core::pause();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Main function for application processors
|
||||
extern "C" int main_ap() {
|
||||
DBG_VERBOSE << "CPU core " << static_cast<int>(Core::getID()) << " / LAPIC "
|
||||
<< static_cast<int>(LAPIC::getID()) << " in main_ap()" << endl;
|
||||
Core::Interrupt::enable();
|
||||
|
||||
DBG << "App CPU " << static_cast<int>(Core::getID()) << endl << flush;
|
||||
|
||||
{
|
||||
Guarded g = Guard::enter();
|
||||
sch.schedule();
|
||||
}
|
||||
|
||||
//assert(Core::getID() != 1);
|
||||
//Application{}.action();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -7,14 +7,30 @@
|
||||
; and populates the registers from the the next context.
|
||||
align 16
|
||||
context_switch:
|
||||
mov [rsi + 0], rbx
|
||||
mov [rsi + 8], rbp
|
||||
mov [rsi + 16], r12
|
||||
mov [rsi + 24], r13
|
||||
mov [rsi + 32], r14
|
||||
mov [rsi + 40], r15
|
||||
mov [rsi + 48], rsp
|
||||
|
||||
; context_launch populates the register set from the next context structure.
|
||||
; It does not save the current registers.
|
||||
align 16 ; When only one parameter is used for `align`, it will use NOP
|
||||
context_launch:
|
||||
|
||||
mov rbx, [rdi + 0]
|
||||
mov rbp, [rdi + 8]
|
||||
mov r12, [rdi + 16]
|
||||
mov r13, [rdi + 24]
|
||||
mov r14, [rdi + 32]
|
||||
mov r15, [rdi + 40]
|
||||
mov rsp, [rdi + 48]
|
||||
ret
|
||||
; fake_systemv_abi is used to populate the volatile argument registers used by the systemv abi (rdi, rsi, ...)
|
||||
; with values from the non-volatile registers saved within the thread context (r15, r14, ...)
|
||||
align 16
|
||||
fake_systemv_abi:
|
||||
|
||||
mov rdi, r15
|
||||
mov rsi, r14
|
||||
ret
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
#include "context.h"
|
||||
#include "../debug/output.h"
|
||||
|
||||
void panic(){
|
||||
DBG << "panic!\n" << flush;
|
||||
while(1);
|
||||
}
|
||||
|
||||
void prepareContext(void* tos, Context& context, void (*kickoff)(void*),
|
||||
void* param1) {
|
||||
(void)tos;
|
||||
(void)context;
|
||||
(void)kickoff;
|
||||
(void)param1;
|
||||
((uint64_t*)tos)[0] = (uint64_t)panic;
|
||||
((uint64_t*)tos)[-1] = (uint64_t)kickoff;
|
||||
((uint64_t*)tos)[-2] = (uint64_t)fake_systemv_abi;
|
||||
context.rsp = (void*)(((uint64_t) tos)-16);
|
||||
context.rbx = 0;
|
||||
context.rbp = 0;
|
||||
context.r12 = 0;
|
||||
context.r13 = 0;
|
||||
context.r14 = 0;
|
||||
context.r15 = (uint64_t)param1;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,9 @@ enum Vector {
|
||||
|
||||
// Interrupts
|
||||
KEYBOARD=32,
|
||||
PANIC=33
|
||||
PANIC=33,
|
||||
TIMER=34,
|
||||
ASS=25
|
||||
};
|
||||
constexpr size_t VECTORS = 256;
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ void set(uint32_t counter, uint8_t divide, uint8_t vector, bool periodic,
|
||||
*
|
||||
* Initializes the \ref LAPIC::Timer
|
||||
* in such a way that regular interrupts are triggered approx. every `us`
|
||||
* microseconds when \ref LAPIC::Timer:::activate() is called.
|
||||
* microseconds when \ref LAPIC::Timer::activate() is called.
|
||||
* For this purpose, a suitable timer divisor is determined
|
||||
* based on the timer frequency determined with \ref LAPIC::Timer::ticks().
|
||||
* This timer divisor has to be as small as possible, but large enough to
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include "lapic.h"
|
||||
#include "lapic_registers.h"
|
||||
#include "core.h"
|
||||
#include "pit.h"
|
||||
|
||||
#include "../debug/output.h"
|
||||
|
||||
namespace LAPIC {
|
||||
namespace Timer {
|
||||
@@ -56,36 +60,118 @@ static const Register div_masks[] = {
|
||||
* \param div Divider, must be power of two: 1, 2, 4, 8, 16, 32, 64, 128
|
||||
* \return Bit mask for LAPIC::setTimer() or `0xff` if `div` is invalid.
|
||||
*/
|
||||
Register getClockDiv(uint8_t div) {
|
||||
(void)div;
|
||||
return 0;
|
||||
static Register getClockDiv(uint8_t div) {
|
||||
switch (div) {
|
||||
case 1: return div_masks[0];
|
||||
case 2: return div_masks[1];
|
||||
case 4: return div_masks[2];
|
||||
case 8: return div_masks[3];
|
||||
case 16: return div_masks[4];
|
||||
case 32: return div_masks[5];
|
||||
case 64: return div_masks[6];
|
||||
case 128: return div_masks[7];
|
||||
default : return 0xff;
|
||||
}
|
||||
}
|
||||
/*! \brief Calculate the LAPIC-timer divider for the bit mask.
|
||||
* \param div_mask The bit mask, must be one of: 0xb, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xa
|
||||
* \return LAPIC-timer divider or `0xff` if `div_mask` is invalid.
|
||||
*/
|
||||
static uint8_t fromClockDiv(Register div_mask) {
|
||||
if (div_mask == div_masks[0]) return 1;
|
||||
if (div_mask == div_masks[1]) return 2;
|
||||
if (div_mask == div_masks[2]) return 4;
|
||||
if (div_mask == div_masks[3]) return 8;
|
||||
if (div_mask == div_masks[4]) return 16;
|
||||
if (div_mask == div_masks[5]) return 32;
|
||||
if (div_mask == div_masks[6]) return 64;
|
||||
if (div_mask == div_masks[7]) return 128;
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ticks(void) {
|
||||
uint32_t ticks = 0; // ticks per millisecond
|
||||
// Calculation (Assignment 5)
|
||||
static uint32_t ticks = 0; // ticks per millisecond
|
||||
if (ticks != 0) return ticks;
|
||||
|
||||
// Prepare Counter
|
||||
LAPIC::Timer::set(0, 1, 0, false, true);
|
||||
|
||||
// Set timer for 10ms
|
||||
PIT::set(10 * 1000);
|
||||
// Start LAPIC-Timer
|
||||
LAPIC::write(TIMER_INITIAL_COUNTER, UINT32_MAX);
|
||||
PIT::waitForTimeout();
|
||||
// Get final Count
|
||||
uint32_t counter = LAPIC::read(TIMER_CURRENT_COUNTER);
|
||||
// Disable LAPIC-Timer
|
||||
LAPIC::write(TIMER_INITIAL_COUNTER, 0);
|
||||
// Calculate tick count.
|
||||
ticks = (UINT32_MAX - counter) / 10;
|
||||
|
||||
DBG << "LAPIC-Timer calibration using PIT" << endl;
|
||||
return ticks;
|
||||
}
|
||||
|
||||
void set(uint32_t counter, uint8_t divide, uint8_t vector, bool periodic,
|
||||
bool masked) {
|
||||
(void)counter;
|
||||
(void)divide;
|
||||
(void)vector;
|
||||
(void)periodic;
|
||||
(void)masked;
|
||||
if (divide == 0 || (divide & (divide - 1)) != 0) {
|
||||
// Not a power of 2
|
||||
return;
|
||||
}
|
||||
|
||||
ControlRegister tcr;
|
||||
tcr.vector = Core::Interrupt::Vector::TIMER;
|
||||
tcr.timer_mode = periodic ? PERIODIC : ONE_SHOT;
|
||||
tcr.masked = masked ? MASKED : NOT_MASKED;
|
||||
LAPIC::write(TIMER_CONTROL, tcr.value);
|
||||
|
||||
LAPIC::write(TIMER_DIVIDE_CONFIGURATION, getClockDiv(divide));
|
||||
LAPIC::write(TIMER_INITIAL_COUNTER, counter);
|
||||
}
|
||||
|
||||
bool setup(uint32_t us) {
|
||||
(void)us;
|
||||
return false;
|
||||
uint64_t timer_ticks = (static_cast<uint64_t>(ticks()) * us) / 1000ULL;
|
||||
|
||||
uint8_t divisor = 1;
|
||||
while (timer_ticks > UINT32_MAX) {
|
||||
// While timer_ticks is to large to fit in 32bits.
|
||||
timer_ticks >>= 1;
|
||||
divisor <<= 1;
|
||||
}
|
||||
if (divisor > 128)
|
||||
return false; // Timer interval is to large.
|
||||
|
||||
// Setup Masked interrupts to effectively disable the timer.
|
||||
set(static_cast<uint32_t>(timer_ticks), divisor, Core::Interrupt::TIMER, true, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t interval() { return 0; }
|
||||
uint32_t interval() {
|
||||
uint32_t timer_ticks = LAPIC::read(TIMER_INITIAL_COUNTER);
|
||||
uint32_t divisor = fromClockDiv(LAPIC::read(TIMER_DIVIDE_CONFIGURATION));
|
||||
|
||||
void activate() {}
|
||||
uint64_t us = (static_cast<uint64_t>(timer_ticks) * divisor * 1000ULL) / static_cast<uint64_t>(ticks());
|
||||
return static_cast<uint32_t>(us);
|
||||
}
|
||||
|
||||
void setMasked(bool masked) { (void)masked; }
|
||||
void activate() {
|
||||
uint32_t timer_ticks = LAPIC::read(TIMER_INITIAL_COUNTER);
|
||||
// Disable Counter to avoid spouriose interrupts.
|
||||
LAPIC::write(TIMER_INITIAL_COUNTER, 0);
|
||||
|
||||
// Activate Timer interrupts.
|
||||
setMasked(false);
|
||||
|
||||
// enable counter with correct value.
|
||||
LAPIC::write(TIMER_INITIAL_COUNTER, timer_ticks);
|
||||
}
|
||||
|
||||
void setMasked(bool masked) {
|
||||
ControlRegister tcr;
|
||||
tcr.value = LAPIC::read(TIMER_CONTROL);
|
||||
tcr.masked = masked ? MASKED : NOT_MASKED;
|
||||
LAPIC::write(TIMER_CONTROL, tcr.value);
|
||||
}
|
||||
} // namespace Timer
|
||||
} // namespace LAPIC
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "boot/multiboot/data.h"
|
||||
#include "./data.h"
|
||||
|
||||
/*! \brief Multiboot Information Structure according to Specification
|
||||
* \see [Multiboot Specification]{@ref multiboot}
|
||||
|
||||
@@ -2,18 +2,34 @@
|
||||
|
||||
#include "../debug/output.h"
|
||||
#include "guard.h"
|
||||
#include "../thread/scheduler.h"
|
||||
|
||||
extern Key kout_key;
|
||||
|
||||
namespace Epilogues {
|
||||
|
||||
void keyboard(Vault& g) {
|
||||
g.kout.setPos(0,0);
|
||||
g.kout << kout_key.ascii() << flush ;
|
||||
void keyboard(Vault& v) {
|
||||
v.kout.setPos(0,0);
|
||||
v.kout << kout_key.ascii() << flush ;
|
||||
|
||||
}
|
||||
|
||||
void timer(Vault& g) { (void)g; }
|
||||
void timer(Vault& v) {
|
||||
static int counter = 0;
|
||||
int x, y;
|
||||
if(Core::getID() == 0) {
|
||||
v.kout.getPos(x, y);
|
||||
v.kout.setPos(65U, 0U);
|
||||
v.kout << counter++ << " " << flush;
|
||||
v.kout.setPos(x, y);
|
||||
}
|
||||
|
||||
void assassin(Vault& g) { (void)g; }
|
||||
v.sch.resume(true);
|
||||
}
|
||||
|
||||
void assassin(Vault& v) {
|
||||
if (v.sch.active()->kill_flag) {
|
||||
v.sch.exit();
|
||||
}
|
||||
}
|
||||
}; // namespace Epilogues
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Epilogues {
|
||||
* \todo(15) Store the key to the keyboard buffer for user threads. Wake user
|
||||
* threads waiting for a key using the key semaphore.
|
||||
*
|
||||
* @param g
|
||||
* @param v The vault.
|
||||
*/
|
||||
void keyboard(Vault& g);
|
||||
|
||||
@@ -37,7 +37,7 @@ void keyboard(Vault& g);
|
||||
* \todo(15) Preemptively reschedule threads
|
||||
* \todo(16) Check the bellringer
|
||||
* \todo(17) Refresh screen with fixed FPS rate
|
||||
* @param g
|
||||
* @param v The vault.
|
||||
*/
|
||||
void timer(Vault& g);
|
||||
|
||||
@@ -45,6 +45,7 @@ void timer(Vault& g);
|
||||
* it is set.
|
||||
*
|
||||
* \todo(15) Implement the rescheduling (in \MPStuBS only)
|
||||
* @param v The vault.
|
||||
*/
|
||||
void assassin(Vault& g);
|
||||
}; // namespace Epilogues
|
||||
|
||||
@@ -2,18 +2,19 @@
|
||||
* \brief \ref Guard synchronizes access to epilogue level
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
//#pragma once
|
||||
#include "../object/bbuffer.h"
|
||||
#include "../object/key.h"
|
||||
#include "../types.h"
|
||||
#include "epilogues.h"
|
||||
#include "../device/textstream.h"
|
||||
|
||||
#include "../thread/scheduler.h"
|
||||
//! \brief The epilogue vault contains the protected data for the epilogue level
|
||||
|
||||
struct Vault {
|
||||
Vault();
|
||||
TextStream kout = TextStream(0, 80, 0, 10, true);
|
||||
|
||||
Scheduler sch = Scheduler();
|
||||
// no copy
|
||||
Vault(const Vault&) = delete;
|
||||
Vault& operator=(const Vault&) = delete;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "handlers.h"
|
||||
#include "./handlers.h"
|
||||
|
||||
#include "../arch/core_cr.h"
|
||||
#include "../arch/idt.h"
|
||||
@@ -29,8 +29,7 @@ void printContext(const InterruptContext *context) {
|
||||
|
||||
[[gnu::interrupt]] void handle_double_fault(InterruptContext *context,
|
||||
uint64_t error) {
|
||||
(void)error;
|
||||
DBG << "Double fault encoutered" << endl;
|
||||
DBG << "Double fault encountered. Error code: " << dec << error << endl;
|
||||
printContext(context);
|
||||
kernelpanic("Double fault!");
|
||||
}
|
||||
@@ -61,8 +60,7 @@ enum PAGE_FAULT_ERROR {
|
||||
|
||||
[[gnu::interrupt]] void handle_page_fault(InterruptContext *context,
|
||||
uint64_t error) {
|
||||
(void)error;
|
||||
DBG << "Page fault encoutered at linear address " << hex
|
||||
DBG << "Page fault encountered at linear address " << hex
|
||||
<< Core::CR<2>::read() << endl
|
||||
<< (error & PF_ERR_PRESENT ? "present" : "non-present") << " page|"
|
||||
<< (error & PF_ERR_WRITE ? "write" : "read") << " access|"
|
||||
@@ -73,9 +71,6 @@ enum PAGE_FAULT_ERROR {
|
||||
kernelpanic("Page fault!");
|
||||
}
|
||||
|
||||
extern Ticketlock koutlock;
|
||||
extern Vault keyboard_vault;
|
||||
|
||||
void handle_keyboard() {
|
||||
//Key key = Key();
|
||||
if (PS2Controller::fetch(kout_key)) {
|
||||
@@ -83,9 +78,6 @@ void handle_keyboard() {
|
||||
if (kout_key.ctrl() && kout_key.alt() && kout_key.scancode == Key::KEY_DEL)
|
||||
System::reboot();
|
||||
Guard::relay(Epilogues::keyboard);
|
||||
//koutlock.lock();
|
||||
//kout << key.ascii() << endl << flush ;
|
||||
//koutlock.unlock();
|
||||
}
|
||||
else
|
||||
LAPIC::endOfInterrupt();
|
||||
@@ -99,10 +91,14 @@ void handle_keyboard() {
|
||||
|
||||
[[gnu::interrupt]] void handle_timer(InterruptContext *context) {
|
||||
(void)context;
|
||||
LAPIC::endOfInterrupt();
|
||||
Guard::relay(Epilogues::timer);
|
||||
}
|
||||
|
||||
[[gnu::interrupt]] void handle_assassin(InterruptContext *context) {
|
||||
(void)context;
|
||||
LAPIC::endOfInterrupt();
|
||||
Guard::relay(Epilogues::assassin);
|
||||
}
|
||||
[[gnu::interrupt]] void handle_wakeup(InterruptContext *context) {
|
||||
(void)context;
|
||||
@@ -122,10 +118,16 @@ void initInterruptHandlers() {
|
||||
IDT::set(Core::Interrupt::Vector::PAGE_FAULT,
|
||||
IDT::InterruptDescriptor::ReturningWithError(handle_page_fault));
|
||||
|
||||
IDT::set(Core::Interrupt::Vector::TIMER,
|
||||
IDT::InterruptDescriptor::Returning(handle_timer));
|
||||
|
||||
// TODO: Add more handlers here
|
||||
IDT::set(Core::Interrupt::Vector::KEYBOARD,
|
||||
IDT::InterruptDescriptor::Returning(handle_keyboard_asm));
|
||||
|
||||
// Load the idt pointer
|
||||
IDT::set(Core::Interrupt::Vector::TIMER,
|
||||
IDT::InterruptDescriptor::Returning(handle_timer));
|
||||
IDT::set(Core::Interrupt::Vector::ASS,
|
||||
IDT::InterruptDescriptor::Returning(handle_assassin));
|
||||
// Load the idt pointer
|
||||
IDT::load();
|
||||
}
|
||||
|
||||
63
main.cc
63
main.cc
@@ -12,12 +12,17 @@
|
||||
#include "device/textstream.h"
|
||||
#include "device/ps2controller.h"
|
||||
#include "arch/ioapic.h"
|
||||
#include "thread/scheduler.h"
|
||||
#include "user/app1/appl.h"
|
||||
#include "sync/ticketlock.h"
|
||||
#include "interrupt/guard.h"
|
||||
|
||||
#include "arch/context.h"
|
||||
#include "thread/thread.h"
|
||||
|
||||
///TextStream kout = TextStream(0, 80, 0, 10, true);
|
||||
Ticketlock koutlock;
|
||||
//Scheduler sch;
|
||||
|
||||
//TextStream dout[8] = {
|
||||
// TextStream(0 ,20,12,25,false),
|
||||
@@ -30,6 +35,7 @@ Ticketlock koutlock;
|
||||
// TextStream(0 ,0 ,0, 0,false),
|
||||
//};
|
||||
|
||||
|
||||
TextStream dout[Core::MAX] = {
|
||||
{0, 40, 10, 14},
|
||||
{40, 80, 10, 14},
|
||||
@@ -65,6 +71,29 @@ OutputStream* copyout[Core::MAX]{
|
||||
|
||||
unsigned int testx, testy;
|
||||
|
||||
uint8_t test1_stack[1024];
|
||||
uint8_t test2_stack[1024];
|
||||
uint8_t test3_stack[1024];
|
||||
uint8_t test4_stack[1024];
|
||||
uint8_t test5_stack[1024];
|
||||
uint8_t test6_stack[1024];
|
||||
uint8_t test7_stack[1024];
|
||||
uint8_t test8_stack[1024];
|
||||
uint8_t test9_stack[1024];
|
||||
|
||||
|
||||
|
||||
Application application1 = Application(&test1_stack[sizeof(test1_stack)-1]);
|
||||
Application application2 = Application(&test2_stack[sizeof(test2_stack)-1]);
|
||||
Application application3 = Application(&test3_stack[sizeof(test3_stack)-1]);
|
||||
Application application4 = Application(&test4_stack[sizeof(test4_stack)-1]);
|
||||
Application application5 = Application(&test5_stack[sizeof(test5_stack)-1]);
|
||||
Application application6 = Application(&test6_stack[sizeof(test5_stack)-1]);
|
||||
Application application7 = Application(&test7_stack[sizeof(test5_stack)-1]);
|
||||
Application application8 = Application(&test8_stack[sizeof(test5_stack)-1]);
|
||||
Application application9 = Application(&test9_stack[sizeof(test5_stack)-1]);
|
||||
|
||||
|
||||
// Main function
|
||||
// (the bootstrap processor starts here)}
|
||||
extern "C" int main() {
|
||||
@@ -77,6 +106,22 @@ extern "C" int main() {
|
||||
* Startup IPIs or even block devices like keyboard because of a missing EOI
|
||||
*/
|
||||
|
||||
{
|
||||
Guarded g = Guard::enter();
|
||||
Scheduler &sch =g.vault().sch;
|
||||
sch.ready(&application1);
|
||||
sch.ready(&application2);
|
||||
sch.ready(&application3);
|
||||
sch.ready(&application4);
|
||||
sch.ready(&application5);
|
||||
sch.ready(&application6);
|
||||
sch.ready(&application7);
|
||||
sch.ready(&application8);
|
||||
sch.ready(&application9);
|
||||
}
|
||||
|
||||
LAPIC::Timer::setup(1000000);
|
||||
|
||||
ApplicationProcessor::boot();
|
||||
|
||||
PS2Controller::init();
|
||||
@@ -87,11 +132,20 @@ extern "C" int main() {
|
||||
|
||||
Core::Interrupt::enable();
|
||||
|
||||
LAPIC::Timer::activate();
|
||||
PS2Controller::drainBuffer();
|
||||
|
||||
DBG << "Main CPU " << static_cast<int>(LAPIC::getID()) << endl << flush;
|
||||
|
||||
Application{}.action();
|
||||
|
||||
|
||||
{
|
||||
Guarded g = Guard::enter();
|
||||
g.vault().sch.schedule();
|
||||
}
|
||||
|
||||
|
||||
//Application{}.action();
|
||||
while (true){
|
||||
//DBG << "pos: " << testx << ", " << testy << endl << flush;
|
||||
//Core::pause();
|
||||
@@ -108,8 +162,13 @@ extern "C" int main_ap() {
|
||||
|
||||
DBG << "App CPU " << static_cast<int>(Core::getID()) << endl << flush;
|
||||
|
||||
{
|
||||
Guarded g = Guard::enter();
|
||||
g.vault().sch.schedule();
|
||||
}
|
||||
|
||||
//assert(Core::getID() != 1);
|
||||
Application{}.action();
|
||||
//Application{}.action();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
4
notes
Normal file
4
notes
Normal file
@@ -0,0 +1,4 @@
|
||||
scheduler in vault
|
||||
next implementieren
|
||||
thread kill nicht in die liste enqueuen, scheduler.cc zeile 26
|
||||
setzen von epi flags interrupt vermutlich disablen.
|
||||
@@ -11,39 +11,16 @@
|
||||
/*! \brief Templated Queue for arbitrary objects.
|
||||
*
|
||||
* Queue is implemented by a head-object (Queue<T>) and next-pointers embedded
|
||||
* in the queued objects. This Queue supports arrays of next-pointers by passing
|
||||
* an index into the constructor identifying the index into the next-pointer
|
||||
* array. By passing a different get_link function into the constructor, the
|
||||
* member name of the next-pointer array can be changed and objects can be
|
||||
* contained in different independent queues.
|
||||
* in the queued objects. By passing a different get_link function into the
|
||||
* constructor, the member name of the next-pointer can be changed and objects
|
||||
* can be contained in different independent queues.
|
||||
*/
|
||||
template <class T>
|
||||
class Queue {
|
||||
/*! \brief Default get_link implementation returns a pointer to the
|
||||
* link_index'th element of the next-pointer array.
|
||||
* The function assumes a member named "queue_link" that stores the
|
||||
* next-pointer.
|
||||
*
|
||||
* If your object contains a queue_link member you can just ignore this
|
||||
* function and the get_link keyword argument of the constructor.
|
||||
*
|
||||
* \param[in] obj the object whose link should be accessed.
|
||||
* \param[in] link_index the index within the array.
|
||||
*
|
||||
* \return A pointer to the next-object pointer.
|
||||
*/
|
||||
static T** default_get_link(T& obj, unsigned link_index) {
|
||||
assert(link_index < sizeof(T::queue_link) / sizeof(void*));
|
||||
return &obj.queue_link[link_index];
|
||||
}
|
||||
/// Default get_link implementation returns a pointer to the next-pointer.
|
||||
static T** default_get_link(T& obj) { return &obj.queue_link; }
|
||||
/// Type definition for the get_link function
|
||||
typedef T** (*NextFunc)(T&, unsigned);
|
||||
|
||||
/// Queue-local index into the next-pointer array
|
||||
unsigned link_index;
|
||||
|
||||
/// Provides the same signature for single- and multi-core Queue
|
||||
T** get_link_wrapped(T& obj) { return get_link(obj, link_index); }
|
||||
typedef T** (*NextFunc)(T&);
|
||||
|
||||
/// Function pointer to the get_link function, called whenever the
|
||||
/// next pointer array is referenced
|
||||
@@ -106,18 +83,15 @@ class Queue {
|
||||
constexpr Queue(Queue&&) = default;
|
||||
|
||||
/*! \brief Constructor
|
||||
* \param[in] link_index denotes the index into the next-pointer array
|
||||
* to be used by this
|
||||
*queue-object
|
||||
* \param[in] get_link A function pointer to the get_link, i.e. a function
|
||||
* which returns a pointer to the
|
||||
*next-pointer of an element in the Queue.
|
||||
*/
|
||||
explicit Queue(unsigned link_index, NextFunc get_link = default_get_link)
|
||||
: link_index(link_index),
|
||||
get_link(get_link),
|
||||
head(nullptr),
|
||||
tail(nullptr) {}
|
||||
explicit Queue(NextFunc get_link = default_get_link)
|
||||
: get_link(get_link), head(nullptr), tail(nullptr) {
|
||||
assert(get_link != nullptr &&
|
||||
"get_link function pointer must not be nullptr!");
|
||||
};
|
||||
|
||||
/*! \brief Enqueues the provided item at the end of the queue. If the element
|
||||
* is already contained in the queue, false will be returned
|
||||
@@ -126,7 +100,7 @@ class Queue {
|
||||
* or not (and it is now enqueued, then true)
|
||||
*/
|
||||
bool enqueue(T& item) {
|
||||
T** nextptr = get_link_wrapped(item);
|
||||
T** nextptr = get_link(item);
|
||||
if (*nextptr != nullptr || (head != nullptr && tail == &item)) {
|
||||
return false;
|
||||
}
|
||||
@@ -136,7 +110,7 @@ class Queue {
|
||||
head = tail = &item;
|
||||
} else {
|
||||
assert(tail != nullptr);
|
||||
*get_link_wrapped(*tail) = &item;
|
||||
*get_link(*tail) = &item;
|
||||
tail = &item;
|
||||
}
|
||||
return true;
|
||||
@@ -147,7 +121,7 @@ class Queue {
|
||||
* \return true if successful, false if item was already in the queue
|
||||
**/
|
||||
bool insertFirst(T& item) {
|
||||
T** nextptr = get_link_wrapped(item);
|
||||
T** nextptr = get_link(item);
|
||||
if (*nextptr != nullptr || (head != nullptr && tail == &item)) {
|
||||
return false;
|
||||
}
|
||||
@@ -177,13 +151,13 @@ class Queue {
|
||||
if (&after == tail) {
|
||||
return enqueue(item);
|
||||
}
|
||||
T** nextptr = get_link_wrapped(item);
|
||||
T** nextptr = get_link(item);
|
||||
// if item is already in the list return false
|
||||
if (*nextptr != nullptr || tail == &item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
T** pnextptr = get_link_wrapped(after);
|
||||
T** pnextptr = get_link(after);
|
||||
// if after is NOT in the list, return false
|
||||
if (!(pnextptr != nullptr || tail == &after)) {
|
||||
return false;
|
||||
@@ -201,8 +175,7 @@ class Queue {
|
||||
*not in this list
|
||||
**/
|
||||
T* next(T& item) {
|
||||
T** nextptr = get_link_wrapped(item);
|
||||
// if item is already in the list return nullptr
|
||||
T** nextptr = get_link(item);
|
||||
if (head == nullptr || (*nextptr == nullptr && tail != &item)) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -222,7 +195,7 @@ class Queue {
|
||||
T* dequeue() {
|
||||
T* out = head;
|
||||
if (head != nullptr) {
|
||||
T** nextptr = get_link_wrapped(*head);
|
||||
T** nextptr = get_link(*head);
|
||||
head = *nextptr;
|
||||
*nextptr = nullptr;
|
||||
}
|
||||
@@ -239,21 +212,21 @@ class Queue {
|
||||
T** next_link;
|
||||
|
||||
if (head == that) {
|
||||
head = *get_link_wrapped(*head);
|
||||
head = *get_link(*head);
|
||||
|
||||
*get_link_wrapped(*that) = nullptr;
|
||||
*get_link(*that) = nullptr;
|
||||
return that;
|
||||
}
|
||||
while (cur) {
|
||||
next_link = get_link_wrapped(*cur);
|
||||
next_link = get_link(*cur);
|
||||
if (*next_link == that) {
|
||||
*next_link = *get_link_wrapped(**next_link);
|
||||
*next_link = *get_link(**next_link);
|
||||
|
||||
if (that == tail) {
|
||||
tail = cur;
|
||||
}
|
||||
|
||||
*get_link_wrapped(*that) = nullptr;
|
||||
*get_link(*that) = nullptr;
|
||||
return that;
|
||||
}
|
||||
cur = *next_link;
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
#include "bellringer.h"
|
||||
#include "./bellringer.h"
|
||||
|
||||
#include "../interrupt/guard.h"
|
||||
#include "../thread/thread.h"
|
||||
|
||||
struct Bell {
|
||||
// link pointer to the next bell in the bellringers bell list
|
||||
Bell *queue_link[1] = {nullptr};
|
||||
|
||||
Thread *thread;
|
||||
size_t counter;
|
||||
};
|
||||
|
||||
Bell **Bellringer::bell_link(Bell &obj, unsigned link_index) {
|
||||
return &obj.queue_link[link_index];
|
||||
}
|
||||
|
||||
// check: Checks whether bells are running out of time and rings them if
|
||||
// necessary
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
#include "../object/queue.h"
|
||||
#include "../thread/thread.h"
|
||||
#include "../types.h"
|
||||
|
||||
struct Vault;
|
||||
struct Bell;
|
||||
|
||||
/*! \brief Manages and activates time-triggered activities.
|
||||
* \ingroup ipc
|
||||
@@ -24,6 +24,14 @@ class Bellringer {
|
||||
Bellringer(const Bellringer&) = delete;
|
||||
Bellringer& operator=(const Bellringer&) = delete;
|
||||
|
||||
struct Bell {
|
||||
// link pointer to the next bell in the bellringers bell list
|
||||
Bell* queue_link = nullptr;
|
||||
|
||||
Thread* thread;
|
||||
size_t counter;
|
||||
};
|
||||
|
||||
/*! \brief List of bells currently managed.
|
||||
*
|
||||
* This list contains non-expired bells enqueued by job().
|
||||
@@ -34,26 +42,26 @@ class Bellringer {
|
||||
*/
|
||||
Queue<Bell> bells;
|
||||
|
||||
//! Link pointer for bells
|
||||
static Bell** bell_link(Bell& obj, unsigned link_index);
|
||||
|
||||
public:
|
||||
// constructor
|
||||
Bellringer() : bells(0, bell_link) {}
|
||||
Bellringer() : bells() {}
|
||||
|
||||
/*! \brief Checks whether there are bells to be rung.
|
||||
*
|
||||
* Every call to check elapses a tick. Once such a tick reduces a bells
|
||||
* remaining time to zero, the bell will be rung.
|
||||
*
|
||||
* \param vault The vault containing the bellringer instance
|
||||
*
|
||||
* \todo(16) Implement Method
|
||||
*/
|
||||
void check(Vault& vault);
|
||||
|
||||
/*! \brief Passes a `bell` to the bellringer to be rung after `ms`
|
||||
* milliseconds.
|
||||
* \param bell Bell that should be rung after `ms` milliseconds
|
||||
* \param ms number of milliseconds that should be waited before
|
||||
*
|
||||
* \param vault The vault containing the bellringer instance
|
||||
* \param ms Number of milliseconds that should be waited before
|
||||
* ringing the bell
|
||||
*
|
||||
* \todo(16) Implement Method
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
#include "./semaphore.h"
|
||||
|
||||
#include "../interrupt/guard.h"
|
||||
#include "../thread/thread.h"
|
||||
|
||||
Semaphore::Semaphore(unsigned c) { (void)c; }
|
||||
|
||||
Thread **Semaphore::thread_link(Thread &obj, unsigned link_index) {
|
||||
(void)obj;
|
||||
(void)link_index;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Semaphore::p(Vault &vault) { (void)vault; }
|
||||
|
||||
void Semaphore::v(Vault &vault) { (void)vault; }
|
||||
|
||||
@@ -26,8 +26,6 @@ class Semaphore {
|
||||
Semaphore(const Semaphore&) = delete;
|
||||
Semaphore& operator=(const Semaphore&) = delete;
|
||||
|
||||
static Thread** thread_link(Thread& obj, unsigned link_index);
|
||||
|
||||
public:
|
||||
/*! \brief Constructor; initialized the counter with provided value `c`
|
||||
* \param c Initial counter value
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
|
||||
#include "../arch/core.h"
|
||||
#include "../arch/cache.h"
|
||||
|
||||
@@ -1,17 +1,32 @@
|
||||
// vim: set noet ts=4 sw=4:
|
||||
|
||||
#include "dispatcher.h"
|
||||
#include "../arch/core.h"
|
||||
|
||||
Dispatcher::Dispatcher() {}
|
||||
|
||||
Thread *Dispatcher::active() { return nullptr; }
|
||||
|
||||
bool Dispatcher::isActive(const Thread *thread, unsigned *cpu) {
|
||||
(void)thread;
|
||||
(void)cpu;
|
||||
return false;
|
||||
Dispatcher::Dispatcher() {
|
||||
}
|
||||
|
||||
void Dispatcher::go(Thread *first) { (void)first; }
|
||||
Thread *Dispatcher::active() {
|
||||
return lifePointer[Core::getID()];
|
||||
}
|
||||
|
||||
void Dispatcher::dispatch(Thread *next) { (void)next; }
|
||||
bool Dispatcher::isActive(const Thread *thread, unsigned *cpu) {
|
||||
for(uint8_t i=0; i<Core::MAX; i++){
|
||||
if(thread == lifePointer[i]){
|
||||
*cpu = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
cpu = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Dispatcher::go(Thread *first) {
|
||||
lifePointer[Core::getID()] = first;
|
||||
first->go();
|
||||
}
|
||||
|
||||
void Dispatcher::dispatch(Thread *next) {
|
||||
lifePointer[Core::getID()] = next;
|
||||
lifePointer[Core::getID()]->resume(next);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#pragma once
|
||||
#include "../thread/thread.h"
|
||||
#include "../types.h"
|
||||
#include "../arch/core.h"
|
||||
|
||||
/*! \brief The dispatcher dispatches threads and puts the scheduler's
|
||||
* decisions into action.
|
||||
@@ -23,12 +24,14 @@ class Dispatcher {
|
||||
*/
|
||||
void setActive(Thread* thread) { (void)thread; }
|
||||
|
||||
|
||||
public:
|
||||
/*! \brief constructor
|
||||
*
|
||||
* \todo(14) Implement Method
|
||||
*/
|
||||
Dispatcher();
|
||||
Thread* lifePointer[Core::MAX];
|
||||
|
||||
/*! \brief Returns the thread currently running on the CPU core calling
|
||||
* this method
|
||||
|
||||
@@ -2,22 +2,47 @@
|
||||
|
||||
#include "scheduler.h"
|
||||
|
||||
Scheduler::Scheduler() {}
|
||||
Queue<Thread> readyList = Queue<Thread>();
|
||||
|
||||
Scheduler::Scheduler() {
|
||||
}
|
||||
|
||||
Thread* Scheduler::getNext() { return nullptr; }
|
||||
|
||||
void Scheduler::schedule() {}
|
||||
void Scheduler::schedule() {
|
||||
// TODO maybe guard?
|
||||
Thread* next = readyList.dequeue();
|
||||
assert(next != nullptr);
|
||||
dispatcher.go(next);
|
||||
}
|
||||
|
||||
void Scheduler::ready(Thread* that) { (void)that; }
|
||||
void Scheduler::ready(Thread* that) {
|
||||
assert(that != nullptr);
|
||||
readyList.enqueue(*that);
|
||||
}
|
||||
|
||||
void Scheduler::resume(bool ready) { (void)ready; }
|
||||
void Scheduler::resume(bool ready) {
|
||||
//if (!active()->kill_flag)
|
||||
if (ready)
|
||||
readyList.enqueue(*active());
|
||||
Thread* thread = readyList.dequeue();
|
||||
assert(thread != nullptr);
|
||||
dispatcher.dispatch(thread);
|
||||
}
|
||||
|
||||
void Scheduler::exit() {}
|
||||
void Scheduler::exit() {
|
||||
Thread* thread = readyList.dequeue();
|
||||
assert(thread != nullptr);
|
||||
dispatcher.dispatch(thread);
|
||||
}
|
||||
|
||||
void Scheduler::kill(Thread* that) { (void)that; }
|
||||
void Scheduler::kill(Thread* that) {
|
||||
readyList.remove(that);
|
||||
that->kill_flag = true;
|
||||
}
|
||||
|
||||
bool Scheduler::isActive(const Thread* that, unsigned int* cpu) {
|
||||
(void)that;
|
||||
bool Scheduler::isActive(const Thread* thread, unsigned int* cpu) {
|
||||
(void)thread;
|
||||
(void)cpu;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -22,18 +22,20 @@
|
||||
* taken from the front of the queue.
|
||||
*/
|
||||
class Scheduler {
|
||||
/*! \brief Helper to retrieve next Thread
|
||||
* \return pointer of next thread
|
||||
*/
|
||||
Thread* getNext();
|
||||
|
||||
|
||||
public:
|
||||
Scheduler();
|
||||
|
||||
/*! \brief a Dispatcher object, providing the low level context switching
|
||||
* routines.
|
||||
*/
|
||||
Dispatcher dispatcher;
|
||||
|
||||
/*! \brief Helper to retrieve next Thread
|
||||
* \return pointer of next thread
|
||||
*/
|
||||
Thread* getNext();
|
||||
|
||||
public:
|
||||
Scheduler();
|
||||
|
||||
/*! \brief Start scheduling
|
||||
*
|
||||
@@ -103,7 +105,7 @@ class Scheduler {
|
||||
Thread* active() { return dispatcher.active(); }
|
||||
|
||||
/// \copydoc Dispatcher::isActive
|
||||
bool isActive(const Thread* that, unsigned int* cpu = nullptr);
|
||||
bool isActive(const Thread* thread, unsigned int* cpu = nullptr);
|
||||
|
||||
/*! \brief Checks whether the ready queue is empty.
|
||||
*
|
||||
|
||||
@@ -1,16 +1,43 @@
|
||||
// vim: set noet ts=4 sw=4:
|
||||
|
||||
#include "thread.h"
|
||||
|
||||
#include "../debug/output.h"
|
||||
#include "../arch/context.h"
|
||||
#include "interrupt/guard.h"
|
||||
// Alias to simplify stuff
|
||||
typedef void (*kickoff_t)(void*);
|
||||
|
||||
void Thread::kickoff(Thread* object) { (void)object; }
|
||||
void Thread::kickoff(Thread* object) {
|
||||
Guard::leave();
|
||||
object->action();
|
||||
}
|
||||
|
||||
Thread::Thread(void* tos) { (void)tos; }
|
||||
Thread::Thread(void* tos) {
|
||||
prepareContext(tos, context, (void(*)(void*)) &(kickoff), this);
|
||||
}
|
||||
|
||||
void Thread::resume(Thread* next) { (void)next; }
|
||||
#include "../thread/scheduler.h"
|
||||
void Thread::resume(Thread* next) {
|
||||
Context *from;
|
||||
Context *to;
|
||||
|
||||
|
||||
void Thread::go() {}
|
||||
|
||||
from = &this->context;
|
||||
to = &next->context;
|
||||
|
||||
void Thread::action() {}
|
||||
//dispatcher.lifePointer[Core::getID()] = next;
|
||||
DBG << "from: " << hex << from << endl;
|
||||
DBG << "to : " << hex << to << endl << flush;
|
||||
|
||||
context_switch(to, from);
|
||||
|
||||
}
|
||||
|
||||
void Thread::go() {
|
||||
context_launch(&context);
|
||||
}
|
||||
|
||||
void Thread::action() {
|
||||
while(1);
|
||||
}
|
||||
|
||||
@@ -16,12 +16,11 @@
|
||||
#include "../arch/context.h"
|
||||
#include "../object/queue.h"
|
||||
#include "../types.h"
|
||||
|
||||
/*! \brief The Thread is an object used by the scheduler.
|
||||
* \ingroup thread
|
||||
*/
|
||||
class Thread {
|
||||
protected:
|
||||
public:
|
||||
/*! \brief The thread's entry point.
|
||||
*
|
||||
* For the first activation of a thread, we need a "return address"
|
||||
@@ -36,13 +35,15 @@ class Thread {
|
||||
*
|
||||
* \param object Thread to be started
|
||||
*/
|
||||
/// \todo(14) Implement Method
|
||||
static void kickoff(Thread* object);
|
||||
|
||||
volatile bool kill_flag;
|
||||
Context context;
|
||||
Thread* queue_link;
|
||||
|
||||
public:
|
||||
/*! \brief Marker for a dying thread
|
||||
*/
|
||||
volatile bool kill_flag;
|
||||
|
||||
/*! \brief Constructor
|
||||
* Initializes the context using \ref prepareContext with the given stack
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
#include "../../arch/core.h"
|
||||
#include "../../interrupt/guard.h"
|
||||
#include "../../debug/output.h"
|
||||
#include "../../arch/context.h"
|
||||
|
||||
static uint8_t appl_cnt = 0;
|
||||
|
||||
char text[] = "Ich mag\n\
|
||||
Saftige Pflaumen voller Aroma\n\
|
||||
Ich knuddel jede Oma ins Koma\n\
|
||||
@@ -22,7 +26,8 @@ Und wacht sie aus'm Koma auf, kriegt sie von mir 'n Sticker\n\
|
||||
\n";
|
||||
|
||||
extern Ticketlock koutlock;
|
||||
|
||||
extern Context* test2; extern Context* test1;
|
||||
extern uint8_t test1_stack[], test2_stack[];
|
||||
void activeWaitDelay(uint64_t cycles) {
|
||||
uint64_t counter = 0; // Use volatile to prevent optimization
|
||||
for (uint64_t i = 0; i < cycles; ++i) {
|
||||
@@ -34,23 +39,24 @@ void activeWaitDelay(uint64_t cycles) {
|
||||
|
||||
void Application::action() { // NOLINT
|
||||
uint16_t cnt = 0;
|
||||
uint8_t row = appl_cnt++;
|
||||
while (1) {
|
||||
//koutlock.lock();
|
||||
//koutlock.lock();
|
||||
{
|
||||
Guarded g = Guard::enter();
|
||||
//g.vault();
|
||||
g.vault().kout.setPos((unsigned)0,(unsigned)Core::getID()*2+1);
|
||||
|
||||
g.vault().kout << cnt++ << flush;
|
||||
|
||||
//g.vault().kout << endl << flush;
|
||||
//Guard::leave();
|
||||
//koutlock.unlock();
|
||||
Guarded g = Guard::enter();
|
||||
//g.vault();
|
||||
g.vault().kout.setPos((unsigned)10*row,(unsigned)/*Core::getID()*2+*/1);
|
||||
g.vault().kout << cnt++ << flush;
|
||||
|
||||
//g.vault().kout << endl << flush;
|
||||
//Guard::leave();
|
||||
//koutlock.unlock();
|
||||
}
|
||||
Core::pause();
|
||||
//activeWaitDelay(1000000000);
|
||||
//Core::pause();
|
||||
//activeWaitDelay(10000000);
|
||||
|
||||
if(cnt >= sizeof(text)-1)
|
||||
cnt=0;
|
||||
|
||||
//context_switch(test2,test1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
|
||||
#pragma once
|
||||
#include "../../types.h"
|
||||
|
||||
#include "../../thread/thread.h"
|
||||
//! \brief Test application
|
||||
//!
|
||||
//! \todo(12) Create a test application
|
||||
//! \todo(14) Application should inherit from \ref Thread
|
||||
//! \todo(16) Make some noise using the \ref PIT::pcspeaker "PC Speaker"
|
||||
class Application {
|
||||
class Application:public Thread {
|
||||
// Prevent copies and assignments
|
||||
Application(const Application&) = delete;
|
||||
Application& operator=(const Application&) = delete;
|
||||
@@ -24,7 +24,8 @@ class Application {
|
||||
*
|
||||
* \todo(14) Implement Constructor
|
||||
*/
|
||||
|
||||
Application(void* tos): Thread(tos){
|
||||
}
|
||||
/*! \brief Contains the application code.
|
||||
*
|
||||
* \todo(14) Implement Method
|
||||
|
||||
Reference in New Issue
Block a user