Compare commits
88 Commits
9ae9f6fd78
...
main
| 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 | ||
|
|
7c1f380184 | ||
|
|
0a150eb84b | ||
|
|
c46cc8d1a2 | ||
|
|
893fc4bad9 | ||
|
|
83e18391b7 | ||
|
|
c4d7ca3cf0 | ||
|
|
9af6bd4455 | ||
|
|
4ee45e27c2 | ||
|
|
00c6f9c943 | ||
|
|
deac8bfb8c | ||
|
|
901eb0bbf5 | ||
|
|
f1e5f17d1f | ||
|
|
a415260776 | ||
|
|
2421136335 | ||
|
|
b0f129141a | ||
|
|
ae3980cfa2 | ||
|
|
bddcebefae | ||
|
|
7d65db4f45 | ||
|
|
e4e7cb9d0c | ||
|
|
9afe202078 | ||
|
|
4a731be0ca | ||
|
|
a053ac561c | ||
|
|
20f7f50fa9 | ||
|
|
65514ec040 | ||
|
|
b61df61e36 | ||
|
|
220bdd8b77 | ||
|
|
2543dca933 | ||
|
|
58f8cf1815 | ||
|
|
d5dc4935a5 | ||
|
|
2a0f0573db | ||
|
|
ebd3bd3597 | ||
|
|
7214ce8e53 | ||
|
|
383561a4f6 | ||
|
|
e9500c1b40 | ||
|
|
9a311fd38c | ||
|
|
90faf06496 | ||
|
|
b2368b2bc5 | ||
|
|
f8942434df | ||
|
|
1dc52aa6f2 | ||
|
|
24c6311f38 | ||
|
|
ecc3b1011d | ||
|
|
5846351aed | ||
|
|
35765897c4 | ||
|
|
6d5f48e154 | ||
|
|
55c23fb293 | ||
|
|
6534b4660c | ||
|
|
35c2667fbf | ||
|
|
2c60b88849 | ||
|
|
bccd23c0c6 | ||
|
|
35d9c7bd48 | ||
|
|
69c1afa5dc | ||
|
|
a3495dbc72 | ||
|
|
0b8c00ab19 | ||
|
|
92792d9cac | ||
|
|
0666fc30c7 | ||
|
|
6b2d3dc8ed | ||
|
|
4a537711e4 | ||
|
|
7add9c8fca | ||
|
|
563d30f9f2 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
|||||||
.build*
|
.build*
|
||||||
/build*
|
/build*
|
||||||
|
/tools/qemu.mk
|
||||||
|
/tools/remote.mk
|
||||||
|
|||||||
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;
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "cga.h"
|
#include "cga.h"
|
||||||
#include "arch/ioport.h"
|
#include "../debug/output.h"
|
||||||
|
#include "../arch/ioport.h"
|
||||||
|
|
||||||
namespace CGA {
|
namespace CGA {
|
||||||
|
|
||||||
@@ -8,7 +9,7 @@ namespace CGA {
|
|||||||
|
|
||||||
void writeCGAReg(int reg, int data){
|
void writeCGAReg(int reg, int data){
|
||||||
index_port.outb(reg);
|
index_port.outb(reg);
|
||||||
data_port.outw(data);
|
data_port.outb(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t readCGAReg(int reg){
|
uint16_t readCGAReg(int reg){
|
||||||
@@ -17,7 +18,7 @@ namespace CGA {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setCursor(unsigned abs_x, unsigned abs_y) {
|
void setCursor(unsigned abs_x, unsigned abs_y) {
|
||||||
uint16_t pos = abs_y * COLUMNS + abs_x;
|
uint16_t pos = abs_y * COLUMNS + abs_x;
|
||||||
|
|
||||||
writeCGAReg(RegisterIndex::CURSOR_LOW, pos & 0xFF);
|
writeCGAReg(RegisterIndex::CURSOR_LOW, pos & 0xFF);
|
||||||
writeCGAReg(RegisterIndex::CURSOR_HIGH, ((pos >> 8) & 0xFF));
|
writeCGAReg(RegisterIndex::CURSOR_HIGH, ((pos >> 8) & 0xFF));
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ void setCursor(unsigned abs_x, unsigned abs_y);
|
|||||||
|
|
||||||
/*! \brief Retrieve the keyboard hardware cursor position on screen
|
/*! \brief Retrieve the keyboard hardware cursor position on screen
|
||||||
*
|
*
|
||||||
* \todo(11) Implement the method using the \ref IOPort
|
|
||||||
*
|
*
|
||||||
* \param abs_x absolute column of the keyboard hardware cursor
|
* \param abs_x absolute column of the keyboard hardware cursor
|
||||||
* \param abs_y absolute row of the keyboard hardware cursor
|
* \param abs_y absolute row of the keyboard hardware cursor
|
||||||
@@ -118,7 +117,6 @@ void getCursor(unsigned& abs_x, unsigned& abs_y);
|
|||||||
* \param character Character to be displayed
|
* \param character Character to be displayed
|
||||||
* \param attrib Attribute with color settings
|
* \param attrib Attribute with color settings
|
||||||
*
|
*
|
||||||
* \todo(11) Implement the method
|
|
||||||
*/
|
*/
|
||||||
void show(unsigned abs_x, unsigned abs_y, char character,
|
void show(unsigned abs_x, unsigned abs_y, char character,
|
||||||
Attribute attrib = Attribute());
|
Attribute attrib = Attribute());
|
||||||
|
|||||||
@@ -7,14 +7,30 @@
|
|||||||
; and populates the registers from the the next context.
|
; and populates the registers from the the next context.
|
||||||
align 16
|
align 16
|
||||||
context_switch:
|
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.
|
; context_launch populates the register set from the next context structure.
|
||||||
; It does not save the current registers.
|
; It does not save the current registers.
|
||||||
align 16 ; When only one parameter is used for `align`, it will use NOP
|
align 16 ; When only one parameter is used for `align`, it will use NOP
|
||||||
context_launch:
|
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, ...)
|
; 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, ...)
|
; with values from the non-volatile registers saved within the thread context (r15, r14, ...)
|
||||||
align 16
|
align 16
|
||||||
fake_systemv_abi:
|
fake_systemv_abi:
|
||||||
|
mov rdi, r15
|
||||||
|
mov rsi, r14
|
||||||
|
ret
|
||||||
|
|||||||
@@ -1,9 +1,21 @@
|
|||||||
#include "context.h"
|
#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 prepareContext(void* tos, Context& context, void (*kickoff)(void*),
|
||||||
void* param1) {
|
void* param1) {
|
||||||
(void)tos;
|
((uint64_t*)tos)[0] = (uint64_t)panic;
|
||||||
(void)context;
|
((uint64_t*)tos)[-1] = (uint64_t)kickoff;
|
||||||
(void)kickoff;
|
((uint64_t*)tos)[-2] = (uint64_t)fake_systemv_abi;
|
||||||
(void)param1;
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ constexpr uintptr_t FLAG_ENABLE = 1 << 9;
|
|||||||
*
|
*
|
||||||
* \see [ISDMv3, 6.15 Exception and Interrupt
|
* \see [ISDMv3, 6.15 Exception and Interrupt
|
||||||
* Reference](intel_manual_vol3.pdf#page=203)
|
* Reference](intel_manual_vol3.pdf#page=203)
|
||||||
* \todo(12) Add Keyboard and Panic vector numbers
|
* \todo
|
||||||
*/
|
*/
|
||||||
enum Vector {
|
enum Vector {
|
||||||
// Predefined Exceptions
|
// Predefined Exceptions
|
||||||
@@ -67,6 +67,10 @@ enum Vector {
|
|||||||
SECURITY_EXCEPTION = 31,
|
SECURITY_EXCEPTION = 31,
|
||||||
|
|
||||||
// Interrupts
|
// Interrupts
|
||||||
|
KEYBOARD=32,
|
||||||
|
PANIC=33,
|
||||||
|
TIMER=34,
|
||||||
|
ASS=25
|
||||||
};
|
};
|
||||||
constexpr size_t VECTORS = 256;
|
constexpr size_t VECTORS = 256;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
#include "ioapic.h"
|
#include "ioapic.h"
|
||||||
|
#include "apic.h"
|
||||||
|
#include "core.h"
|
||||||
|
#include "../debug/assert.h"
|
||||||
|
|
||||||
namespace IOAPIC {
|
namespace IOAPIC {
|
||||||
/*! \brief IOAPIC registers memory mapped into the CPU's address space.
|
/*! \brief IOAPIC registers memory mapped into the CPU's address space.
|
||||||
@@ -20,22 +23,66 @@ volatile Register *IOWIN_REG =
|
|||||||
// IOAPIC manual, p. 8
|
// IOAPIC manual, p. 8
|
||||||
const Index IOAPICID_IDX = 0x00;
|
const Index IOAPICID_IDX = 0x00;
|
||||||
const Index IOREDTBL_IDX = 0x10;
|
const Index IOREDTBL_IDX = 0x10;
|
||||||
|
const Index IOREDTBL_ENTRY_SIZE = 0x02;
|
||||||
|
|
||||||
const uint8_t slot_max = 24;
|
const uint8_t slot_max = 24;
|
||||||
|
|
||||||
void init() {}
|
RedirectionTableEntry readEntry(Index slot) {
|
||||||
|
*IOREGSEL_REG = IOREDTBL_IDX + slot * IOREDTBL_ENTRY_SIZE;
|
||||||
void config(uint8_t slot, Core::Interrupt::Vector vector,
|
Register low = *IOWIN_REG;
|
||||||
TriggerMode trigger_mode, Polarity polarity) {
|
*IOREGSEL_REG += IOREDTBL_ENTRY_SIZE / 2;
|
||||||
(void)slot;
|
Register high = *IOWIN_REG;
|
||||||
(void)vector;
|
return RedirectionTableEntry{low, high};
|
||||||
(void)trigger_mode;
|
|
||||||
(void)polarity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void allow(uint8_t slot) { (void)slot; }
|
void writeEntry(Index slot, RedirectionTableEntry entry) {
|
||||||
|
*IOREGSEL_REG = IOREDTBL_IDX + slot * IOREDTBL_ENTRY_SIZE;
|
||||||
|
*IOWIN_REG = entry.value_low;
|
||||||
|
*IOREGSEL_REG += IOREDTBL_ENTRY_SIZE / 2;
|
||||||
|
*IOWIN_REG = entry.value_high;
|
||||||
|
}
|
||||||
|
|
||||||
void forbid(uint8_t slot) { (void)slot; }
|
void init() {
|
||||||
|
for (uint8_t slot = 0; slot < slot_max; slot++) {
|
||||||
|
RedirectionTableEntry entry = readEntry(slot);
|
||||||
|
entry.destination = (1 << Core::count()) - 1;
|
||||||
|
entry.interrupt_mask = MASKED;
|
||||||
|
entry.trigger_mode = EDGE;
|
||||||
|
entry.polarity = HIGH;
|
||||||
|
entry.destination_mode = LOGICAL;
|
||||||
|
entry.delivery_mode = LOWEST_PRIORITY;
|
||||||
|
entry.vector = Core::Interrupt::PANIC;
|
||||||
|
writeEntry(slot, entry);
|
||||||
|
}
|
||||||
|
*IOREGSEL_REG = IOAPICID_IDX;
|
||||||
|
Identification IOAPICID{*IOWIN_REG};
|
||||||
|
IOAPICID.id = APIC::getIOAPICID();
|
||||||
|
*IOWIN_REG = IOAPICID.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void config(uint8_t slot, Core::Interrupt::Vector vector,
|
||||||
|
TriggerMode trigger_mode, Polarity polarity) {
|
||||||
|
assert(slot < slot_max);
|
||||||
|
RedirectionTableEntry entry = readEntry(slot);
|
||||||
|
entry.vector = vector;
|
||||||
|
entry.trigger_mode = trigger_mode;
|
||||||
|
entry.polarity = polarity;
|
||||||
|
writeEntry(slot, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void allow(uint8_t slot) {
|
||||||
|
assert(slot < slot_max);
|
||||||
|
RedirectionTableEntry entry = readEntry(slot);
|
||||||
|
entry.interrupt_mask = UNMASKED;
|
||||||
|
writeEntry(slot, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void forbid(uint8_t slot) {
|
||||||
|
assert(slot < slot_max);
|
||||||
|
RedirectionTableEntry entry = readEntry(slot);
|
||||||
|
entry.interrupt_mask = MASKED;
|
||||||
|
writeEntry(slot, entry);
|
||||||
|
}
|
||||||
|
|
||||||
bool status(uint8_t slot) {
|
bool status(uint8_t slot) {
|
||||||
(void)slot;
|
(void)slot;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ void init();
|
|||||||
* \param polarity Polarity of the interrupt signaling (active high or
|
* \param polarity Polarity of the interrupt signaling (active high or
|
||||||
active low)
|
active low)
|
||||||
*
|
*
|
||||||
* \todo(12) Implement Function
|
* \todo Implement Function
|
||||||
*/
|
*/
|
||||||
void config(uint8_t slot, Core::Interrupt::Vector vector,
|
void config(uint8_t slot, Core::Interrupt::Vector vector,
|
||||||
TriggerMode trigger_mode = TriggerMode::EDGE,
|
TriggerMode trigger_mode = TriggerMode::EDGE,
|
||||||
@@ -57,7 +57,7 @@ void config(uint8_t slot, Core::Interrupt::Vector vector,
|
|||||||
* To fully enable interrupt handling, the interrupts must be enabled for every
|
* To fully enable interrupt handling, the interrupts must be enabled for every
|
||||||
* CPU (e.g., by calling
|
* CPU (e.g., by calling
|
||||||
* \ref Core::Interrupt::enable() in main).
|
* \ref Core::Interrupt::enable() in main).
|
||||||
* \todo(12) Do that somewhere appropriate.
|
* \todo Do that somewhere appropriate.
|
||||||
*
|
*
|
||||||
* \param slot Number of the external interrupt that should be enabled.
|
* \param slot Number of the external interrupt that should be enabled.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ void set(uint32_t counter, uint8_t divide, uint8_t vector, bool periodic,
|
|||||||
*
|
*
|
||||||
* Initializes the \ref LAPIC::Timer
|
* Initializes the \ref LAPIC::Timer
|
||||||
* in such a way that regular interrupts are triggered approx. every `us`
|
* 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
|
* For this purpose, a suitable timer divisor is determined
|
||||||
* based on the timer frequency determined with \ref LAPIC::Timer::ticks().
|
* 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
|
* This timer divisor has to be as small as possible, but large enough to
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
#include "lapic.h"
|
#include "lapic.h"
|
||||||
#include "lapic_registers.h"
|
#include "lapic_registers.h"
|
||||||
|
#include "core.h"
|
||||||
|
#include "pit.h"
|
||||||
|
|
||||||
|
#include "../debug/output.h"
|
||||||
|
|
||||||
namespace LAPIC {
|
namespace LAPIC {
|
||||||
namespace Timer {
|
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
|
* \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.
|
* \return Bit mask for LAPIC::setTimer() or `0xff` if `div` is invalid.
|
||||||
*/
|
*/
|
||||||
Register getClockDiv(uint8_t div) {
|
static Register getClockDiv(uint8_t div) {
|
||||||
(void)div;
|
switch (div) {
|
||||||
return 0;
|
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(void) {
|
||||||
uint32_t ticks = 0; // ticks per millisecond
|
static uint32_t ticks = 0; // ticks per millisecond
|
||||||
// Calculation (Assignment 5)
|
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;
|
return ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(uint32_t counter, uint8_t divide, uint8_t vector, bool periodic,
|
void set(uint32_t counter, uint8_t divide, uint8_t vector, bool periodic,
|
||||||
bool masked) {
|
bool masked) {
|
||||||
(void)counter;
|
if (divide == 0 || (divide & (divide - 1)) != 0) {
|
||||||
(void)divide;
|
// Not a power of 2
|
||||||
(void)vector;
|
return;
|
||||||
(void)periodic;
|
}
|
||||||
(void)masked;
|
|
||||||
|
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) {
|
bool setup(uint32_t us) {
|
||||||
(void)us;
|
uint64_t timer_ticks = (static_cast<uint64_t>(ticks()) * us) / 1000ULL;
|
||||||
return false;
|
|
||||||
|
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 Timer
|
||||||
} // namespace LAPIC
|
} // namespace LAPIC
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ Serial::Serial(ComPort port, BaudRate baud_rate, DataBits data_bits,
|
|||||||
// FIFO: Enable & clear buffers
|
// FIFO: Enable & clear buffers
|
||||||
writeReg(FIFO_CONTROL_REGISTER,
|
writeReg(FIFO_CONTROL_REGISTER,
|
||||||
ENABLE_FIFO | CLEAR_RECEIVE_FIFO | CLEAR_TRANSMIT_FIFO);
|
ENABLE_FIFO | CLEAR_RECEIVE_FIFO | CLEAR_TRANSMIT_FIFO);
|
||||||
|
|
||||||
// Modem Control: OUT2 (0000 1000) must be set for interrupt
|
// Modem Control: OUT2 (0000 1000) must be set for interrupt
|
||||||
writeReg(MODEM_CONTROL_REGISTER, OUT_2);
|
writeReg(MODEM_CONTROL_REGISTER, OUT_2);
|
||||||
}
|
}
|
||||||
@@ -44,9 +43,8 @@ int Serial::write(char out) {
|
|||||||
if(out == '\n')
|
if(out == '\n')
|
||||||
write('\r');
|
write('\r');
|
||||||
|
|
||||||
if(readReg(LINE_STATUS_REGISTER) & TRANSMITTER_EMPTY){
|
while(!(readReg(LINE_STATUS_REGISTER) & TRANSMITTER_EMPTY));
|
||||||
writeReg(TRANSMIT_BUFFER_REGISTER, out);
|
|
||||||
return out;
|
writeReg(TRANSMIT_BUFFER_REGISTER, out);
|
||||||
}
|
return out;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,7 +161,6 @@ class Serial {
|
|||||||
|
|
||||||
/*! \brief Read value from register
|
/*! \brief Read value from register
|
||||||
*
|
*
|
||||||
* \todo(11) Implement Method
|
|
||||||
*
|
*
|
||||||
* \param reg Register index
|
* \param reg Register index
|
||||||
* \return The value read from register
|
* \return The value read from register
|
||||||
@@ -170,7 +169,6 @@ class Serial {
|
|||||||
|
|
||||||
/*! \brief Write value to register
|
/*! \brief Write value to register
|
||||||
*
|
*
|
||||||
* \todo(11) Implement Method
|
|
||||||
*
|
*
|
||||||
* \param reg Register index
|
* \param reg Register index
|
||||||
* \param out value to be written
|
* \param out value to be written
|
||||||
@@ -188,7 +186,6 @@ class Serial {
|
|||||||
* parameters used for the serial connection. Default values are `8N1` (8 bit,
|
* parameters used for the serial connection. Default values are `8N1` (8 bit,
|
||||||
* no parity bit, one stop bit) with 115200 Baud using COM1.
|
* no parity bit, one stop bit) with 115200 Baud using COM1.
|
||||||
*
|
*
|
||||||
* \todo(11) - Implement Constructor
|
|
||||||
*/
|
*/
|
||||||
explicit Serial(ComPort port = COM1, BaudRate baud_rate = BAUD_115200,
|
explicit Serial(ComPort port = COM1, BaudRate baud_rate = BAUD_115200,
|
||||||
DataBits data_bits = DATA_8BIT,
|
DataBits data_bits = DATA_8BIT,
|
||||||
@@ -196,7 +193,6 @@ class Serial {
|
|||||||
|
|
||||||
/*! \brief Write one byte to the serial interface
|
/*! \brief Write one byte to the serial interface
|
||||||
*
|
*
|
||||||
* \todo(11) - Implement Method
|
|
||||||
*
|
*
|
||||||
* \param out Byte to be written
|
* \param out Byte to be written
|
||||||
* \return Byte written (or `-1` if writing byte failed)
|
* \return Byte written (or `-1` if writing byte failed)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "textwindow.h"
|
#include "textwindow.h"
|
||||||
#include "cga.h"
|
#include "cga.h"
|
||||||
|
#include "../utils/string.h"
|
||||||
|
#include "../debug/output.h"
|
||||||
|
|
||||||
TextWindow::TextWindow(unsigned from_col, unsigned to_col, unsigned from_row,
|
TextWindow::TextWindow(unsigned from_col, unsigned to_col, unsigned from_row,
|
||||||
unsigned to_row, bool use_cursor) {
|
unsigned to_row, bool use_cursor) {
|
||||||
@@ -8,14 +10,27 @@ TextWindow::TextWindow(unsigned from_col, unsigned to_col, unsigned from_row,
|
|||||||
this->from_row = from_row;
|
this->from_row = from_row;
|
||||||
this->to_row = to_row;
|
this->to_row = to_row;
|
||||||
this->use_cursor = use_cursor;
|
this->use_cursor = use_cursor;
|
||||||
|
|
||||||
|
setPos(0,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern unsigned int testx, testy;
|
||||||
void TextWindow::setPos(unsigned rel_x, unsigned rel_y) {
|
void TextWindow::setPos(unsigned rel_x, unsigned rel_y) {
|
||||||
|
unsigned abs_x = from_col + rel_x;
|
||||||
|
unsigned abs_y = from_row + rel_y;
|
||||||
|
|
||||||
|
if(abs_x >= CGA::COLUMNS)
|
||||||
|
return;
|
||||||
|
if(abs_y >= CGA::ROWS)
|
||||||
|
return;
|
||||||
|
|
||||||
if(use_cursor){
|
if(use_cursor){
|
||||||
CGA::setCursor(from_col + rel_x, from_row + rel_y);
|
testx = abs_x;
|
||||||
|
testy = abs_y;
|
||||||
|
CGA::setCursor(abs_x, abs_y);
|
||||||
}else{
|
}else{
|
||||||
pos_x = from_col + rel_x;
|
pos_x = abs_x;
|
||||||
pos_y = from_row + rel_y;
|
pos_y = abs_y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,6 +62,13 @@ void TextWindow::getPos(int& rel_x, int& rel_y) const {
|
|||||||
rel_y = y;
|
rel_y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextWindow::scrollUp(){
|
||||||
|
for(uint8_t row = from_row; row < to_row-1; row++){
|
||||||
|
memmove(&CGA::TEXT_BUFFER_BASE[row*CGA::COLUMNS + from_col], &CGA::TEXT_BUFFER_BASE[(row+1)*CGA::COLUMNS + from_col], 2*(to_col-from_col));
|
||||||
|
}
|
||||||
|
memset(&CGA::TEXT_BUFFER_BASE[(to_row-1)*CGA::COLUMNS + from_col] , 0, 2*(to_col-from_col));
|
||||||
|
}
|
||||||
|
|
||||||
void TextWindow::print(const char* str, size_t length, CGA::Attribute attrib) {
|
void TextWindow::print(const char* str, size_t length, CGA::Attribute attrib) {
|
||||||
for(unsigned i=0; i<length; i++){
|
for(unsigned i=0; i<length; i++){
|
||||||
unsigned x_now, y_now;
|
unsigned x_now, y_now;
|
||||||
@@ -54,7 +76,7 @@ void TextWindow::print(const char* str, size_t length, CGA::Attribute attrib) {
|
|||||||
if(str[i] == '\n'){
|
if(str[i] == '\n'){
|
||||||
x_now = 0;
|
x_now = 0;
|
||||||
if(from_row + y_now >= to_row-1){
|
if(from_row + y_now >= to_row-1){
|
||||||
//TODO scrollUp()
|
scrollUp();
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
y_now++;
|
y_now++;
|
||||||
@@ -63,11 +85,11 @@ void TextWindow::print(const char* str, size_t length, CGA::Attribute attrib) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGA::show(x_now, y_now, str[i], attrib);
|
CGA::show(from_col + x_now, from_row + y_now, str[i], attrib);
|
||||||
if(from_col+x_now >= to_col-1){
|
if(from_col+x_now >= to_col-1){
|
||||||
x_now = 0;
|
x_now = 0;
|
||||||
if(from_row + y_now >= to_row-1){
|
if(from_row + y_now >= to_row-1){
|
||||||
//TODO scrollUp()
|
scrollUp();
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
y_now++;
|
y_now++;
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ class TextWindow {
|
|||||||
unsigned pos_x;
|
unsigned pos_x;
|
||||||
unsigned pos_y;
|
unsigned pos_y;
|
||||||
|
|
||||||
|
void scrollUp();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*! \brief Constructor of a text window
|
/*! \brief Constructor of a text window
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "boot/multiboot/data.h"
|
#include "./data.h"
|
||||||
|
|
||||||
/*! \brief Multiboot Information Structure according to Specification
|
/*! \brief Multiboot Information Structure according to Specification
|
||||||
* \see [Multiboot Specification]{@ref multiboot}
|
* \see [Multiboot Specification]{@ref multiboot}
|
||||||
|
|||||||
3
compile_flags.txt
Normal file
3
compile_flags.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
-Iarch
|
||||||
|
-xc++
|
||||||
|
-std=gnu++2b
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
#include "output.h"
|
||||||
|
|
||||||
[[noreturn]] void assertion_failed(const char* exp, const char* func,
|
[[noreturn]] void assertion_failed(const char* exp, const char* func,
|
||||||
const char* file, int line) {
|
const char* file, int line) {
|
||||||
@@ -6,6 +7,7 @@
|
|||||||
(void)func;
|
(void)func;
|
||||||
(void)file;
|
(void)file;
|
||||||
(void)line;
|
(void)line;
|
||||||
|
DBG << "Assertion failed: " << exp << "\nin function: " << func << "\nfrom file: \"" << file << "\" in line " << dec << line << flush;
|
||||||
// TODO: Print error message (in debug window)
|
// TODO: Print error message (in debug window)
|
||||||
// TODO: Then stop the current core permanently
|
// TODO: Then stop the current core permanently
|
||||||
// Use appropriate method from class Core to do so.
|
// Use appropriate method from class Core to do so.
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
#define kernelpanic(MSG) \
|
#define kernelpanic(MSG) \
|
||||||
do { \
|
do { \
|
||||||
DBG << "PANIC: '" << (MSG) << "' in " << __func__ << " @ " << __FILE__ \
|
DBG << "PANIC: '" << (MSG) << "' in " << __func__ << " @ " << __FILE__ \
|
||||||
<< ":" << __LINE__ << ") - CPU stopped." << endl; \
|
<< ":" << dec << __LINE__ << ") - CPU stopped." << endl; \
|
||||||
Core::die(); \
|
Core::die(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|||||||
@@ -43,10 +43,10 @@
|
|||||||
* possible that the debug output in a multi core system is displayed
|
* possible that the debug output in a multi core system is displayed
|
||||||
* on the wrong (previous) core.
|
* on the wrong (previous) core.
|
||||||
*/
|
*/
|
||||||
#define DBG nullstream
|
|
||||||
|
|
||||||
#include "../arch/core.h"
|
#include "../arch/core.h"
|
||||||
#include "../device/textstream.h"
|
#include "../device/textstream.h"
|
||||||
|
#define DBG *copyout[Core::getID()]
|
||||||
|
|
||||||
/*! \brief Debug window for the CGA screen
|
/*! \brief Debug window for the CGA screen
|
||||||
*
|
*
|
||||||
@@ -72,7 +72,6 @@
|
|||||||
* without any overlap and should be able to display at least 3 lines.
|
* without any overlap and should be able to display at least 3 lines.
|
||||||
* In \MPStuBS, two windows can be placed side-by-side, having 40 columns each.
|
* In \MPStuBS, two windows can be placed side-by-side, having 40 columns each.
|
||||||
*
|
*
|
||||||
* \todo(11) Define `dout`
|
|
||||||
*/
|
*/
|
||||||
extern TextStream dout[Core::MAX];
|
extern TextStream dout[Core::MAX];
|
||||||
|
|
||||||
@@ -83,11 +82,11 @@ extern TextStream dout[Core::MAX];
|
|||||||
* an array in the multi core case, which consists of three TextStreams and
|
* an array in the multi core case, which consists of three TextStreams and
|
||||||
* one CopyStream.
|
* one CopyStream.
|
||||||
* For that, construction is done like:
|
* For that, construction is done like:
|
||||||
|
* \todo(11) Define `copyout`
|
||||||
*
|
*
|
||||||
* \code{.cpp}
|
* \code{.cpp}
|
||||||
* OutputStream* copyout[Core::MAX]{&dout[0], &dout[1], ...}
|
* OutputStream* copyout[Core::MAX]{&dout[0], &dout[1], ...}
|
||||||
* \endcode
|
* \endcode
|
||||||
*
|
*
|
||||||
* \todo(11) Define `copyout`
|
|
||||||
*/
|
*/
|
||||||
extern OutputStream* copyout[Core::MAX];
|
extern OutputStream* copyout[Core::MAX];
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "ps2controller.h"
|
#include "ps2controller.h"
|
||||||
|
|
||||||
|
#include "../arch/system.h"
|
||||||
#include "../arch/core_interrupt.h"
|
#include "../arch/core_interrupt.h"
|
||||||
#include "../arch/ioport.h"
|
#include "../arch/ioport.h"
|
||||||
#include "../compiler/fix.h"
|
#include "../compiler/fix.h"
|
||||||
@@ -89,8 +90,11 @@ enum ControllerCommand {
|
|||||||
*
|
*
|
||||||
* \param value data to be sent
|
* \param value data to be sent
|
||||||
*/
|
*/
|
||||||
[[maybe_unused]] static void sendData(uint8_t value) {
|
static void sendData(uint8_t value) {
|
||||||
// TODO: You have to implement this method
|
|
||||||
|
if (!(ctrl_port.inb()&HAS_OUTPUT)) {
|
||||||
|
data_port.outb(value);
|
||||||
|
}
|
||||||
(void)value;
|
(void)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,9 +109,20 @@ void init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool fetch(Key &pressed) {
|
bool fetch(Key &pressed) {
|
||||||
// TODO: You have to implement this method
|
uint8_t status_reg = ctrl_port.inb();
|
||||||
(void)pressed;
|
if(!(status_reg & HAS_OUTPUT) )
|
||||||
return false;
|
return false;
|
||||||
|
DBG_VERBOSE << "status: " << hex << static_cast<int>(status_reg) << "\n" << flush;
|
||||||
|
|
||||||
|
uint8_t out_buffer = data_port.inb();
|
||||||
|
DBG_VERBOSE << "scancode: " << hex << static_cast<int>(out_buffer) << "\n" << flush;
|
||||||
|
|
||||||
|
if (status_reg & IS_MOUSE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
pressed = key_decoder.decode(out_buffer);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setRepeatRate(Speed speed, Delay delay) {
|
void setRepeatRate(Speed speed, Delay delay) {
|
||||||
@@ -125,6 +140,8 @@ void setLed(enum LED led, bool on) {
|
|||||||
sendData(leds); // Parameter
|
sendData(leds); // Parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
void drainBuffer() {}
|
void drainBuffer() {
|
||||||
|
while(ctrl_port.inb() & HAS_OUTPUT)
|
||||||
|
data_port.inb();
|
||||||
|
}
|
||||||
} // namespace PS2Controller
|
} // namespace PS2Controller
|
||||||
|
|||||||
@@ -146,7 +146,6 @@ void setLed(enum LED led, bool on);
|
|||||||
* should be emptied once right before allowing keyboard interrupts
|
* should be emptied once right before allowing keyboard interrupts
|
||||||
* (even if keystrokes might be lost).
|
* (even if keystrokes might be lost).
|
||||||
*
|
*
|
||||||
* \todo(12) Implement method
|
|
||||||
*/
|
*/
|
||||||
void drainBuffer();
|
void drainBuffer();
|
||||||
|
|
||||||
|
|||||||
@@ -41,8 +41,6 @@ void SerialStream::reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SerialStream::setPos(int x, int y) {
|
void SerialStream::setPos(int x, int y) {
|
||||||
//char out[] = {0x1b, '[', 0, 0, ';', 0, 0, 'H', 0};
|
|
||||||
//*this << 0x1b;
|
|
||||||
write(0x1b);
|
write(0x1b);
|
||||||
sout << '[';
|
sout << '[';
|
||||||
sout << dec << x;
|
sout << dec << x;
|
||||||
@@ -50,9 +48,6 @@ void SerialStream::setPos(int x, int y) {
|
|||||||
sout << dec << y;
|
sout << dec << y;
|
||||||
sout << 'H';
|
sout << 'H';
|
||||||
flush();
|
flush();
|
||||||
//itoa(x, &out[2], 10);
|
|
||||||
//itoa(y, &out[5], 10);
|
|
||||||
//print( out , strlen(out));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialStream::print(char* str, int length) {
|
void SerialStream::print(char* str, int length) {
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ class SerialStream : public OutputStream, public Serial {
|
|||||||
*
|
*
|
||||||
* Sets up the serial connection as well
|
* Sets up the serial connection as well
|
||||||
*
|
*
|
||||||
* \todo(11) Implement Method
|
|
||||||
*/
|
*/
|
||||||
explicit SerialStream(ComPort port = COM1, BaudRate baud_rate = BAUD_115200,
|
explicit SerialStream(ComPort port = COM1, BaudRate baud_rate = BAUD_115200,
|
||||||
DataBits data_bits = DATA_8BIT,
|
DataBits data_bits = DATA_8BIT,
|
||||||
@@ -74,13 +73,11 @@ class SerialStream : public OutputStream, public Serial {
|
|||||||
* The method is automatically called when the buffer is full,
|
* The method is automatically called when the buffer is full,
|
||||||
* but can also be called explicitly to force output of the current buffer.
|
* but can also be called explicitly to force output of the current buffer.
|
||||||
*
|
*
|
||||||
* \todo(11) Implement Method
|
|
||||||
*/
|
*/
|
||||||
void flush() override;
|
void flush() override;
|
||||||
|
|
||||||
/*! \brief Change foreground color (for subsequent output)
|
/*! \brief Change foreground color (for subsequent output)
|
||||||
*
|
*
|
||||||
* \todo(11) Implement Method
|
|
||||||
*
|
*
|
||||||
* \param c Color
|
* \param c Color
|
||||||
*/
|
*/
|
||||||
@@ -88,7 +85,6 @@ class SerialStream : public OutputStream, public Serial {
|
|||||||
|
|
||||||
/*! \brief Change background color (for subsequent output)
|
/*! \brief Change background color (for subsequent output)
|
||||||
*
|
*
|
||||||
* \todo(11) Implement Method
|
|
||||||
*
|
*
|
||||||
* \param c Color
|
* \param c Color
|
||||||
*/
|
*/
|
||||||
@@ -96,7 +92,6 @@ class SerialStream : public OutputStream, public Serial {
|
|||||||
|
|
||||||
/*! \brief Change text attribute (for subsequent output)
|
/*! \brief Change text attribute (for subsequent output)
|
||||||
*
|
*
|
||||||
* \todo(11) Implement Method
|
|
||||||
*
|
*
|
||||||
* \param a Attribute
|
* \param a Attribute
|
||||||
*/
|
*/
|
||||||
@@ -107,7 +102,6 @@ class SerialStream : public OutputStream, public Serial {
|
|||||||
* Clear screen, place cursor at the beginning and reset colors
|
* Clear screen, place cursor at the beginning and reset colors
|
||||||
* and attributes to the default value.
|
* and attributes to the default value.
|
||||||
*
|
*
|
||||||
* \todo(11) Implement Method
|
|
||||||
*/
|
*/
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
@@ -116,7 +110,6 @@ class SerialStream : public OutputStream, public Serial {
|
|||||||
* \param x Column in window
|
* \param x Column in window
|
||||||
* \param y Row in window
|
* \param y Row in window
|
||||||
*
|
*
|
||||||
* \todo(11) Implement Method
|
|
||||||
*/
|
*/
|
||||||
void setPos(int x, int y);
|
void setPos(int x, int y);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "textstream.h"
|
#include "textstream.h"
|
||||||
|
#include "../arch/core.h"
|
||||||
|
|
||||||
TextStream::TextStream(unsigned from_col,
|
TextStream::TextStream(unsigned from_col,
|
||||||
unsigned to_col,
|
unsigned to_col,
|
||||||
@@ -9,10 +10,14 @@ TextStream::TextStream(unsigned from_col,
|
|||||||
to_col,
|
to_col,
|
||||||
from_row,
|
from_row,
|
||||||
to_row,
|
to_row,
|
||||||
use_cursor){}
|
use_cursor){
|
||||||
|
//CGA::Color fg = static_cast<CGA::Color>((LAPIC::getID() + 1 ));
|
||||||
|
//this->reset(' ', CGA::Attribute(CGA::LIGHT_GREEN, fg, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void TextStream::flush() {
|
void TextStream::flush() {
|
||||||
print(buffer,pos);
|
CGA::Color fg = static_cast<CGA::Color>((Core::getID() + 1 ));
|
||||||
|
print(buffer,pos,CGA::Attribute(CGA::LIGHT_GREEN, fg, false));
|
||||||
pos = 0;
|
pos = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
* \ref TextWindow and only implements the method \ref TextStream::flush().
|
* \ref TextWindow and only implements the method \ref TextStream::flush().
|
||||||
* Further formatting or special effects are implemented in \ref TextWindow.
|
* Further formatting or special effects are implemented in \ref TextWindow.
|
||||||
*/
|
*/
|
||||||
class TextStream: public OutputStream, protected TextWindow {
|
class TextStream: public OutputStream, public TextWindow {
|
||||||
// Prevent copies and assignments
|
// Prevent copies and assignments
|
||||||
TextStream(const TextStream&) = delete;
|
TextStream(const TextStream&) = delete;
|
||||||
TextStream& operator=(const TextStream&) = delete;
|
TextStream& operator=(const TextStream&) = delete;
|
||||||
@@ -36,14 +36,7 @@ class TextStream: public OutputStream, protected TextWindow {
|
|||||||
* but can also be called explicitly to force output of the current buffer.
|
* but can also be called explicitly to force output of the current buffer.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* \todo(11) Implement method
|
|
||||||
*/
|
*/
|
||||||
void flush();
|
void flush();
|
||||||
|
|
||||||
private:
|
|
||||||
unsigned from_col;
|
|
||||||
unsigned to_col;
|
|
||||||
unsigned from_row;
|
|
||||||
unsigned to_row;
|
|
||||||
bool use_cursor;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,35 @@
|
|||||||
#include "epilogues.h"
|
#include "epilogues.h"
|
||||||
|
|
||||||
|
#include "../debug/output.h"
|
||||||
#include "guard.h"
|
#include "guard.h"
|
||||||
|
#include "../thread/scheduler.h"
|
||||||
|
|
||||||
|
extern Key kout_key;
|
||||||
|
|
||||||
namespace Epilogues {
|
namespace Epilogues {
|
||||||
|
|
||||||
void keyboard(Vault& g) { (void)g; }
|
void keyboard(Vault& v) {
|
||||||
|
v.kout.setPos(0,0);
|
||||||
|
v.kout << kout_key.ascii() << flush ;
|
||||||
|
|
||||||
void timer(Vault& g) { (void)g; }
|
}
|
||||||
|
|
||||||
void assassin(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
v.sch.resume(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void assassin(Vault& v) {
|
||||||
|
if (v.sch.active()->kill_flag) {
|
||||||
|
v.sch.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
}; // namespace Epilogues
|
}; // namespace Epilogues
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace Epilogues {
|
|||||||
* \todo(15) Store the key to the keyboard buffer for user threads. Wake user
|
* \todo(15) Store the key to the keyboard buffer for user threads. Wake user
|
||||||
* threads waiting for a key using the key semaphore.
|
* threads waiting for a key using the key semaphore.
|
||||||
*
|
*
|
||||||
* @param g
|
* @param v The vault.
|
||||||
*/
|
*/
|
||||||
void keyboard(Vault& g);
|
void keyboard(Vault& g);
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ void keyboard(Vault& g);
|
|||||||
* \todo(15) Preemptively reschedule threads
|
* \todo(15) Preemptively reschedule threads
|
||||||
* \todo(16) Check the bellringer
|
* \todo(16) Check the bellringer
|
||||||
* \todo(17) Refresh screen with fixed FPS rate
|
* \todo(17) Refresh screen with fixed FPS rate
|
||||||
* @param g
|
* @param v The vault.
|
||||||
*/
|
*/
|
||||||
void timer(Vault& g);
|
void timer(Vault& g);
|
||||||
|
|
||||||
@@ -45,6 +45,7 @@ void timer(Vault& g);
|
|||||||
* it is set.
|
* it is set.
|
||||||
*
|
*
|
||||||
* \todo(15) Implement the rescheduling (in \MPStuBS only)
|
* \todo(15) Implement the rescheduling (in \MPStuBS only)
|
||||||
|
* @param v The vault.
|
||||||
*/
|
*/
|
||||||
void assassin(Vault& g);
|
void assassin(Vault& g);
|
||||||
}; // namespace Epilogues
|
}; // namespace Epilogues
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "../debug/output.h"
|
#include "../debug/output.h"
|
||||||
#include "../object/bbuffer.h"
|
#include "../object/bbuffer.h"
|
||||||
#include "../sync/ticketlock.h"
|
#include "../sync/ticketlock.h"
|
||||||
|
#include "../arch/core_interrupt.h"
|
||||||
#include "epilogues.h"
|
#include "epilogues.h"
|
||||||
|
|
||||||
#define FOR_CURRENT_CORE [Core::getID()]
|
#define FOR_CURRENT_CORE [Core::getID()]
|
||||||
@@ -17,14 +18,57 @@ static BBuffer<Epilogue, 32> epilogue_queue[Core::MAX] = {};
|
|||||||
constinit Ticketlock global_lock;
|
constinit Ticketlock global_lock;
|
||||||
constinit bool epi_flag[Core::MAX] = {false};
|
constinit bool epi_flag[Core::MAX] = {false};
|
||||||
|
|
||||||
Vault::Vault() {}
|
Vault::Vault() {
|
||||||
|
}
|
||||||
|
|
||||||
Guarded::~Guarded() { Guard::leave(); }
|
Guarded::~Guarded() { Guard::leave(); }
|
||||||
|
|
||||||
Guarded Guard::enter() { while (true); }
|
Guarded Guard::enter() {
|
||||||
|
epi_flag FOR_CURRENT_CORE = true;
|
||||||
|
//Core::Interrupt::enable();
|
||||||
|
global_lock.lock();
|
||||||
|
return Guarded(global_vault);
|
||||||
|
}
|
||||||
|
|
||||||
void Guard::leave() {}
|
void Guard::leave() {
|
||||||
|
bool istate = Core::Interrupt::disable();
|
||||||
|
|
||||||
|
Epilogue next;
|
||||||
|
global_lock.unlock();
|
||||||
|
while(epilogue_queue FOR_CURRENT_CORE.consume(next)){
|
||||||
|
Core::Interrupt::enable();
|
||||||
|
global_lock.lock();
|
||||||
|
next(global_vault);
|
||||||
|
global_lock.unlock();
|
||||||
|
Core::Interrupt::disable();
|
||||||
|
}
|
||||||
|
epi_flag FOR_CURRENT_CORE = false;
|
||||||
|
Core::Interrupt::restore(istate);
|
||||||
|
}
|
||||||
|
void Guard::relay(Epilogue handler) {
|
||||||
|
//if(!epilogue_queue FOR_CURRENT_CORE.produce(handler))
|
||||||
|
// return; // enqueue, but dont execute
|
||||||
|
//if(!epi_flag FOR_CURRENT_CORE){
|
||||||
|
// enter();
|
||||||
|
// Core::Interrupt::enable();
|
||||||
|
// handler(global_vault);
|
||||||
|
// leave();
|
||||||
|
//}
|
||||||
|
|
||||||
void Guard::relay(Epilogue handler) { (void)handler; }
|
Core::Interrupt::enable(); // goto level 0.5
|
||||||
|
if(epi_flag FOR_CURRENT_CORE){
|
||||||
|
epilogue_queue->produce(handler);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
epi_flag FOR_CURRENT_CORE = true;
|
||||||
|
global_lock.lock();
|
||||||
|
handler(global_vault);
|
||||||
|
leave();
|
||||||
|
}
|
||||||
|
//epilogue_queue->consume(handler);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const Vault &Guard::unsafeConstAccess() { return global_vault; }
|
const Vault &Guard::unsafeConstAccess() { return global_vault; }
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,19 @@
|
|||||||
* \brief \ref Guard synchronizes access to epilogue level
|
* \brief \ref Guard synchronizes access to epilogue level
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
//#pragma once
|
||||||
#include "../object/bbuffer.h"
|
#include "../object/bbuffer.h"
|
||||||
#include "../object/key.h"
|
#include "../object/key.h"
|
||||||
#include "../types.h"
|
#include "../types.h"
|
||||||
#include "epilogues.h"
|
#include "epilogues.h"
|
||||||
|
#include "../device/textstream.h"
|
||||||
|
#include "../thread/scheduler.h"
|
||||||
//! \brief The epilogue vault contains the protected data for the epilogue level
|
//! \brief The epilogue vault contains the protected data for the epilogue level
|
||||||
|
|
||||||
struct Vault {
|
struct Vault {
|
||||||
Vault();
|
Vault();
|
||||||
|
TextStream kout = TextStream(0, 80, 0, 10, true);
|
||||||
|
Scheduler sch = Scheduler();
|
||||||
// no copy
|
// no copy
|
||||||
Vault(const Vault&) = delete;
|
Vault(const Vault&) = delete;
|
||||||
Vault& operator=(const Vault&) = delete;
|
Vault& operator=(const Vault&) = delete;
|
||||||
|
|||||||
@@ -11,4 +11,26 @@ handle_keyboard_asm:
|
|||||||
; continue. The C++ compiler will only generates code to preserve
|
; continue. The C++ compiler will only generates code to preserve
|
||||||
; non-scratch registers in the high-level interrupt handler -- the scratch
|
; non-scratch registers in the high-level interrupt handler -- the scratch
|
||||||
; registers have to be saved (and restored later) manually!
|
; registers have to be saved (and restored later) manually!
|
||||||
; TODO(12): Implement the context save and restore for the keyboard interrupt
|
; TODO: Implement the context save and restore for the keyboard interrupt
|
||||||
|
;
|
||||||
|
;
|
||||||
|
push rax;
|
||||||
|
push rdi;
|
||||||
|
push rsi;
|
||||||
|
push rdx;
|
||||||
|
push rcx;
|
||||||
|
push r8;
|
||||||
|
push r9;
|
||||||
|
push r10;
|
||||||
|
push r11;
|
||||||
|
call handle_keyboard;
|
||||||
|
pop r11;
|
||||||
|
pop r10;
|
||||||
|
pop r9;
|
||||||
|
pop r8;
|
||||||
|
pop rcx;
|
||||||
|
pop rdx;
|
||||||
|
pop rsi;
|
||||||
|
pop rdi;
|
||||||
|
pop rax;
|
||||||
|
iretq ;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "handlers.h"
|
#include "./handlers.h"
|
||||||
|
|
||||||
#include "../arch/core_cr.h"
|
#include "../arch/core_cr.h"
|
||||||
#include "../arch/idt.h"
|
#include "../arch/idt.h"
|
||||||
@@ -7,6 +7,14 @@
|
|||||||
#include "../debug/kernelpanic.h"
|
#include "../debug/kernelpanic.h"
|
||||||
#include "../debug/output.h"
|
#include "../debug/output.h"
|
||||||
|
|
||||||
|
#include "../device/ps2controller.h"
|
||||||
|
|
||||||
|
#include "../sync/ticketlock.h"
|
||||||
|
#include "epilogues.h"
|
||||||
|
#include "guard.h"
|
||||||
|
|
||||||
|
Key kout_key = Key();
|
||||||
|
|
||||||
void printContext(const InterruptContext *context) {
|
void printContext(const InterruptContext *context) {
|
||||||
DBG << "ip: " << hex << context->cs << ':' << context->ip
|
DBG << "ip: " << hex << context->cs << ':' << context->ip
|
||||||
<< " sp: " << context->ss << ':' << context->sp << " flags" << bin
|
<< " sp: " << context->ss << ':' << context->sp << " flags" << bin
|
||||||
@@ -21,8 +29,7 @@ void printContext(const InterruptContext *context) {
|
|||||||
|
|
||||||
[[gnu::interrupt]] void handle_double_fault(InterruptContext *context,
|
[[gnu::interrupt]] void handle_double_fault(InterruptContext *context,
|
||||||
uint64_t error) {
|
uint64_t error) {
|
||||||
(void)error;
|
DBG << "Double fault encountered. Error code: " << dec << error << endl;
|
||||||
DBG << "Double fault encoutered" << endl;
|
|
||||||
printContext(context);
|
printContext(context);
|
||||||
kernelpanic("Double fault!");
|
kernelpanic("Double fault!");
|
||||||
}
|
}
|
||||||
@@ -53,8 +60,7 @@ enum PAGE_FAULT_ERROR {
|
|||||||
|
|
||||||
[[gnu::interrupt]] void handle_page_fault(InterruptContext *context,
|
[[gnu::interrupt]] void handle_page_fault(InterruptContext *context,
|
||||||
uint64_t error) {
|
uint64_t error) {
|
||||||
(void)error;
|
DBG << "Page fault encountered at linear address " << hex
|
||||||
DBG << "Page fault encoutered at linear address " << hex
|
|
||||||
<< Core::CR<2>::read() << endl
|
<< Core::CR<2>::read() << endl
|
||||||
<< (error & PF_ERR_PRESENT ? "present" : "non-present") << " page|"
|
<< (error & PF_ERR_PRESENT ? "present" : "non-present") << " page|"
|
||||||
<< (error & PF_ERR_WRITE ? "write" : "read") << " access|"
|
<< (error & PF_ERR_WRITE ? "write" : "read") << " access|"
|
||||||
@@ -65,18 +71,34 @@ enum PAGE_FAULT_ERROR {
|
|||||||
kernelpanic("Page fault!");
|
kernelpanic("Page fault!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_keyboard() {}
|
void handle_keyboard() {
|
||||||
|
//Key key = Key();
|
||||||
|
if (PS2Controller::fetch(kout_key)) {
|
||||||
|
LAPIC::endOfInterrupt();
|
||||||
|
if (kout_key.ctrl() && kout_key.alt() && kout_key.scancode == Key::KEY_DEL)
|
||||||
|
System::reboot();
|
||||||
|
Guard::relay(Epilogues::keyboard);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LAPIC::endOfInterrupt();
|
||||||
|
}
|
||||||
|
|
||||||
[[gnu::interrupt]] void handle_panic(InterruptContext *context) {
|
[[gnu::interrupt]] void handle_panic(InterruptContext *context) {
|
||||||
(void)context;
|
DBG << "Generic KernelPanic triggered"<< endl;
|
||||||
|
printContext(context);
|
||||||
|
kernelpanic("Generic Panic Triggerd");
|
||||||
}
|
}
|
||||||
|
|
||||||
[[gnu::interrupt]] void handle_timer(InterruptContext *context) {
|
[[gnu::interrupt]] void handle_timer(InterruptContext *context) {
|
||||||
(void)context;
|
(void)context;
|
||||||
|
LAPIC::endOfInterrupt();
|
||||||
|
Guard::relay(Epilogues::timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[gnu::interrupt]] void handle_assassin(InterruptContext *context) {
|
[[gnu::interrupt]] void handle_assassin(InterruptContext *context) {
|
||||||
(void)context;
|
(void)context;
|
||||||
|
LAPIC::endOfInterrupt();
|
||||||
|
Guard::relay(Epilogues::assassin);
|
||||||
}
|
}
|
||||||
[[gnu::interrupt]] void handle_wakeup(InterruptContext *context) {
|
[[gnu::interrupt]] void handle_wakeup(InterruptContext *context) {
|
||||||
(void)context;
|
(void)context;
|
||||||
@@ -96,7 +118,16 @@ void initInterruptHandlers() {
|
|||||||
IDT::set(Core::Interrupt::Vector::PAGE_FAULT,
|
IDT::set(Core::Interrupt::Vector::PAGE_FAULT,
|
||||||
IDT::InterruptDescriptor::ReturningWithError(handle_page_fault));
|
IDT::InterruptDescriptor::ReturningWithError(handle_page_fault));
|
||||||
|
|
||||||
|
IDT::set(Core::Interrupt::Vector::TIMER,
|
||||||
|
IDT::InterruptDescriptor::Returning(handle_timer));
|
||||||
|
|
||||||
// TODO: Add more handlers here
|
// TODO: Add more handlers here
|
||||||
// Load the idt pointer
|
IDT::set(Core::Interrupt::Vector::KEYBOARD,
|
||||||
|
IDT::InterruptDescriptor::Returning(handle_keyboard_asm));
|
||||||
|
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();
|
IDT::load();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ extern "C" { // disable C++ name mangling for asm function
|
|||||||
* On keyboard interrupt, the register state is saved to and restored from the
|
* On keyboard interrupt, the register state is saved to and restored from the
|
||||||
* stack. This function wraps the handle_keyboard C-function.
|
* stack. This function wraps the handle_keyboard C-function.
|
||||||
*
|
*
|
||||||
* \todo(12) Implement in assembly
|
* \todo Implement in assembly
|
||||||
*/
|
*/
|
||||||
[[gnu::interrupt]] void handle_keyboard_asm(InterruptContext *context);
|
[[gnu::interrupt]] void handle_keyboard_asm(InterruptContext *context);
|
||||||
|
|
||||||
@@ -77,12 +77,12 @@ extern "C" { // disable C++ name mangling for asm function
|
|||||||
* \todo(12) Fetch a single key
|
* \todo(12) Fetch a single key
|
||||||
* \todo(13) Extend to use the Prologue-Epilogue pattern
|
* \todo(13) Extend to use the Prologue-Epilogue pattern
|
||||||
*/
|
*/
|
||||||
void handle_keyboard();
|
void handle_keyboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief handle_panic
|
/*! \brief handle_panic
|
||||||
*
|
*
|
||||||
* \todo(12) Trigger a kernel panic
|
* \todo Trigger a kernel panic
|
||||||
*/
|
*/
|
||||||
[[gnu::interrupt]] void handle_panic(InterruptContext *context);
|
[[gnu::interrupt]] void handle_panic(InterruptContext *context);
|
||||||
|
|
||||||
|
|||||||
204
main.cc
204
main.cc
@@ -1,65 +1,155 @@
|
|||||||
#include "arch/lapic.h"
|
#include "arch/lapic.h"
|
||||||
#include "boot/startup_ap.h"
|
#include "boot/startup_ap.h"
|
||||||
|
#include "arch/core_interrupt.h"
|
||||||
|
#include "debug/copystream.h"
|
||||||
#include "debug/output.h"
|
#include "debug/output.h"
|
||||||
|
#include "debug/assert.h"
|
||||||
|
|
||||||
#include "arch/cga.h"
|
#include "arch/cga.h"
|
||||||
#include "arch/textwindow.h"
|
#include "arch/textwindow.h"
|
||||||
#include "arch/serial.h"
|
#include "arch/serial.h"
|
||||||
#include "device/serialstream.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];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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
|
// Main function
|
||||||
// (the bootstrap processor starts here)}
|
// (the bootstrap processor starts here)}
|
||||||
extern "C" int main() {
|
extern "C" int main() {
|
||||||
|
CGA::setCursor(0, 0);
|
||||||
|
|
||||||
unsigned int numCPUs = Core::count();
|
unsigned int numCPUs = Core::count();
|
||||||
DBG_VERBOSE << "Number of CPUs: " << numCPUs << endl;
|
|
||||||
|
|
||||||
////test cga implemantation
|
|
||||||
// CGA::setCursor(1, 2);
|
|
||||||
// unsigned x,y;
|
|
||||||
// CGA::getCursor(x, y);
|
|
||||||
// CGA::setCursor(x+1, y+1);
|
|
||||||
// for(uint8_t i = 0; i < 10; i++)
|
|
||||||
// CGA::show(i, i, i+0x30, CGA::Attribute());
|
|
||||||
|
|
||||||
////test textwindow implemantation
|
|
||||||
//TextWindow tw_global = TextWindow(0, 80, 0, 25, true);
|
|
||||||
//tw_global.reset(' ', CGA::Attribute(CGA::LIGHT_GREEN, CGA::BLUE, false));
|
|
||||||
|
|
||||||
// test SerialStream
|
|
||||||
SerialStream ss = SerialStream();
|
|
||||||
ss.print("test", 4);
|
|
||||||
ss.setAttribute(SerialStream::UNDERSCORE);
|
|
||||||
ss.print("test", 4);
|
|
||||||
ss.setAttribute(SerialStream::RESET);
|
|
||||||
ss.setForeground(SerialStream::MAGENTA);
|
|
||||||
ss.print("test", 4);
|
|
||||||
ss.setBackground(SerialStream::CYAN);
|
|
||||||
ss.print("test", 4);
|
|
||||||
ss.setPos(10, 10);
|
|
||||||
ss.print("test\n", 5);
|
|
||||||
ss.setBackground(SerialStream::BLACK);
|
|
||||||
|
|
||||||
kout << "Test <stream result> -> <expected>" << endl;
|
|
||||||
kout << "bool: " << true << " -> true" << endl;
|
|
||||||
kout << "zero: " << 0 << " -> 0" << endl;
|
|
||||||
kout << "binary: " << bin << 42 << dec << " -> 0b101010" << endl;
|
|
||||||
kout << "octal: " << oct << 42 << dec << " -> 052" << endl;
|
|
||||||
kout << "hex: " << hex << 42 << dec << " -> 0x2a" << endl;
|
|
||||||
kout << "uint64_t max: " << ~((uint64_t)0) << " -> 18446744073709551615" << endl;
|
|
||||||
kout << "int64_t max: " << ~(1ll<<63) << " -> 9223372036854775807" << endl;
|
|
||||||
kout << "int64_t min: " << (1ll<<63) << " -> -9223372036854775808" << endl;
|
|
||||||
kout << "some int64_t: " << (-1234567890123456789) << " -> -1234567890123456789" << endl;
|
|
||||||
kout << "some int64_t: " << (1234567890123456789) << " -> 1234567890123456789" << endl;
|
|
||||||
kout << "pointer: " << reinterpret_cast<void*>(1994473406541717165ull)
|
|
||||||
<< " -> 0x1badcafefee1dead" << endl;
|
|
||||||
kout << "smiley: " << static_cast<char>(1) << endl;
|
|
||||||
|
|
||||||
/* Start application processors
|
/* Start application processors
|
||||||
* To avoid unexpected behaviour, make sure that interrupts are not
|
* To avoid unexpected behaviour, make sure that interrupts are not
|
||||||
* enabled before the APs are booted. Otherwise it might interfere with the
|
* 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
|
* 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();
|
ApplicationProcessor::boot();
|
||||||
|
|
||||||
|
PS2Controller::init();
|
||||||
|
|
||||||
|
IOAPIC::init();
|
||||||
|
IOAPIC::config(1, Core::Interrupt::KEYBOARD);
|
||||||
|
IOAPIC::allow(1);
|
||||||
|
|
||||||
|
Core::Interrupt::enable();
|
||||||
|
|
||||||
|
LAPIC::Timer::activate();
|
||||||
|
PS2Controller::drainBuffer();
|
||||||
|
|
||||||
|
DBG << "Main CPU " << static_cast<int>(LAPIC::getID()) << endl << flush;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
Guarded g = Guard::enter();
|
||||||
|
g.vault().sch.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Application{}.action();
|
||||||
|
while (true){
|
||||||
|
//DBG << "pos: " << testx << ", " << testy << endl << flush;
|
||||||
|
//Core::pause();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -68,29 +158,17 @@ extern "C" int main() {
|
|||||||
extern "C" int main_ap() {
|
extern "C" int main_ap() {
|
||||||
DBG_VERBOSE << "CPU core " << static_cast<int>(Core::getID()) << " / LAPIC "
|
DBG_VERBOSE << "CPU core " << static_cast<int>(Core::getID()) << " / LAPIC "
|
||||||
<< static_cast<int>(LAPIC::getID()) << " in main_ap()" << endl;
|
<< static_cast<int>(LAPIC::getID()) << " in main_ap()" << endl;
|
||||||
|
Core::Interrupt::enable();
|
||||||
|
|
||||||
|
DBG << "App CPU " << static_cast<int>(Core::getID()) << endl << flush;
|
||||||
|
|
||||||
TextWindow kout = TextWindow(0, 80, 0, 12, true);
|
{
|
||||||
kout.reset();
|
Guarded g = Guard::enter();
|
||||||
kout.setPos(0,0);
|
g.vault().sch.schedule();
|
||||||
kout.print("Corem ipsum dolor sit amit", 26);
|
}
|
||||||
kout.setPos(0,-1);
|
|
||||||
kout.print("test", 4, CGA::Attribute(CGA::BLACK, CGA::BLUE));
|
|
||||||
int x,y;
|
|
||||||
kout.getPos(x,y);
|
|
||||||
kout.setPos(x+1,y);
|
|
||||||
kout.reset(' ', CGA::Attribute(CGA::LIGHT_GREEN, CGA::BLUE, false));
|
|
||||||
|
|
||||||
|
|
||||||
TextWindow dout0 = TextWindow(0,20,13,19, false);
|
|
||||||
dout0.reset();
|
|
||||||
dout0.reset(' ', CGA::Attribute(CGA::LIGHT_GREEN, CGA::RED, false));
|
|
||||||
|
|
||||||
|
|
||||||
////test Serial
|
|
||||||
Serial s = Serial();
|
|
||||||
s.write('a');
|
|
||||||
|
|
||||||
|
//assert(Core::getID() != 1);
|
||||||
|
//Application{}.action();
|
||||||
|
|
||||||
return 0;
|
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.
|
/*! \brief Templated Queue for arbitrary objects.
|
||||||
*
|
*
|
||||||
* Queue is implemented by a head-object (Queue<T>) and next-pointers embedded
|
* 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
|
* in the queued objects. By passing a different get_link function into the
|
||||||
* an index into the constructor identifying the index into the next-pointer
|
* constructor, the member name of the next-pointer can be changed and objects
|
||||||
* array. By passing a different get_link function into the constructor, the
|
* can be contained in different independent queues.
|
||||||
* member name of the next-pointer array can be changed and objects can be
|
|
||||||
* contained in different independent queues.
|
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T>
|
||||||
class Queue {
|
class Queue {
|
||||||
/*! \brief Default get_link implementation returns a pointer to the
|
/// Default get_link implementation returns a pointer to the next-pointer.
|
||||||
* link_index'th element of the next-pointer array.
|
static T** default_get_link(T& obj) { return &obj.queue_link; }
|
||||||
* 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];
|
|
||||||
}
|
|
||||||
/// Type definition for the get_link function
|
/// Type definition for the get_link function
|
||||||
typedef T** (*NextFunc)(T&, unsigned);
|
typedef T** (*NextFunc)(T&);
|
||||||
|
|
||||||
/// 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); }
|
|
||||||
|
|
||||||
/// Function pointer to the get_link function, called whenever the
|
/// Function pointer to the get_link function, called whenever the
|
||||||
/// next pointer array is referenced
|
/// next pointer array is referenced
|
||||||
@@ -106,18 +83,15 @@ class Queue {
|
|||||||
constexpr Queue(Queue&&) = default;
|
constexpr Queue(Queue&&) = default;
|
||||||
|
|
||||||
/*! \brief Constructor
|
/*! \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
|
* \param[in] get_link A function pointer to the get_link, i.e. a function
|
||||||
* which returns a pointer to the
|
* which returns a pointer to the
|
||||||
*next-pointer of an element in the Queue.
|
*next-pointer of an element in the Queue.
|
||||||
*/
|
*/
|
||||||
explicit Queue(unsigned link_index, NextFunc get_link = default_get_link)
|
explicit Queue(NextFunc get_link = default_get_link)
|
||||||
: link_index(link_index),
|
: get_link(get_link), head(nullptr), tail(nullptr) {
|
||||||
get_link(get_link),
|
assert(get_link != nullptr &&
|
||||||
head(nullptr),
|
"get_link function pointer must not be nullptr!");
|
||||||
tail(nullptr) {}
|
};
|
||||||
|
|
||||||
/*! \brief Enqueues the provided item at the end of the queue. If the element
|
/*! \brief Enqueues the provided item at the end of the queue. If the element
|
||||||
* is already contained in the queue, false will be returned
|
* 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)
|
* or not (and it is now enqueued, then true)
|
||||||
*/
|
*/
|
||||||
bool enqueue(T& item) {
|
bool enqueue(T& item) {
|
||||||
T** nextptr = get_link_wrapped(item);
|
T** nextptr = get_link(item);
|
||||||
if (*nextptr != nullptr || (head != nullptr && tail == &item)) {
|
if (*nextptr != nullptr || (head != nullptr && tail == &item)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -136,7 +110,7 @@ class Queue {
|
|||||||
head = tail = &item;
|
head = tail = &item;
|
||||||
} else {
|
} else {
|
||||||
assert(tail != nullptr);
|
assert(tail != nullptr);
|
||||||
*get_link_wrapped(*tail) = &item;
|
*get_link(*tail) = &item;
|
||||||
tail = &item;
|
tail = &item;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -147,7 +121,7 @@ class Queue {
|
|||||||
* \return true if successful, false if item was already in the queue
|
* \return true if successful, false if item was already in the queue
|
||||||
**/
|
**/
|
||||||
bool insertFirst(T& item) {
|
bool insertFirst(T& item) {
|
||||||
T** nextptr = get_link_wrapped(item);
|
T** nextptr = get_link(item);
|
||||||
if (*nextptr != nullptr || (head != nullptr && tail == &item)) {
|
if (*nextptr != nullptr || (head != nullptr && tail == &item)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -177,13 +151,13 @@ class Queue {
|
|||||||
if (&after == tail) {
|
if (&after == tail) {
|
||||||
return enqueue(item);
|
return enqueue(item);
|
||||||
}
|
}
|
||||||
T** nextptr = get_link_wrapped(item);
|
T** nextptr = get_link(item);
|
||||||
// if item is already in the list return false
|
// if item is already in the list return false
|
||||||
if (*nextptr != nullptr || tail == &item) {
|
if (*nextptr != nullptr || tail == &item) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
T** pnextptr = get_link_wrapped(after);
|
T** pnextptr = get_link(after);
|
||||||
// if after is NOT in the list, return false
|
// if after is NOT in the list, return false
|
||||||
if (!(pnextptr != nullptr || tail == &after)) {
|
if (!(pnextptr != nullptr || tail == &after)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -201,8 +175,7 @@ class Queue {
|
|||||||
*not in this list
|
*not in this list
|
||||||
**/
|
**/
|
||||||
T* next(T& item) {
|
T* next(T& item) {
|
||||||
T** nextptr = get_link_wrapped(item);
|
T** nextptr = get_link(item);
|
||||||
// if item is already in the list return nullptr
|
|
||||||
if (head == nullptr || (*nextptr == nullptr && tail != &item)) {
|
if (head == nullptr || (*nextptr == nullptr && tail != &item)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -222,7 +195,7 @@ class Queue {
|
|||||||
T* dequeue() {
|
T* dequeue() {
|
||||||
T* out = head;
|
T* out = head;
|
||||||
if (head != nullptr) {
|
if (head != nullptr) {
|
||||||
T** nextptr = get_link_wrapped(*head);
|
T** nextptr = get_link(*head);
|
||||||
head = *nextptr;
|
head = *nextptr;
|
||||||
*nextptr = nullptr;
|
*nextptr = nullptr;
|
||||||
}
|
}
|
||||||
@@ -239,21 +212,21 @@ class Queue {
|
|||||||
T** next_link;
|
T** next_link;
|
||||||
|
|
||||||
if (head == that) {
|
if (head == that) {
|
||||||
head = *get_link_wrapped(*head);
|
head = *get_link(*head);
|
||||||
|
|
||||||
*get_link_wrapped(*that) = nullptr;
|
*get_link(*that) = nullptr;
|
||||||
return that;
|
return that;
|
||||||
}
|
}
|
||||||
while (cur) {
|
while (cur) {
|
||||||
next_link = get_link_wrapped(*cur);
|
next_link = get_link(*cur);
|
||||||
if (*next_link == that) {
|
if (*next_link == that) {
|
||||||
*next_link = *get_link_wrapped(**next_link);
|
*next_link = *get_link(**next_link);
|
||||||
|
|
||||||
if (that == tail) {
|
if (that == tail) {
|
||||||
tail = cur;
|
tail = cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
*get_link_wrapped(*that) = nullptr;
|
*get_link(*that) = nullptr;
|
||||||
return that;
|
return that;
|
||||||
}
|
}
|
||||||
cur = *next_link;
|
cur = *next_link;
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ class Stringbuffer {
|
|||||||
*
|
*
|
||||||
* \param c Char to be added
|
* \param c Char to be added
|
||||||
*
|
*
|
||||||
* \todo(11) Implement
|
|
||||||
*/
|
*/
|
||||||
void put(char c);
|
void put(char c);
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,6 @@
|
|||||||
#include "bellringer.h"
|
#include "./bellringer.h"
|
||||||
|
|
||||||
#include "../interrupt/guard.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
|
// check: Checks whether bells are running out of time and rings them if
|
||||||
// necessary
|
// necessary
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../object/queue.h"
|
#include "../object/queue.h"
|
||||||
|
#include "../thread/thread.h"
|
||||||
#include "../types.h"
|
#include "../types.h"
|
||||||
|
|
||||||
struct Vault;
|
struct Vault;
|
||||||
struct Bell;
|
|
||||||
|
|
||||||
/*! \brief Manages and activates time-triggered activities.
|
/*! \brief Manages and activates time-triggered activities.
|
||||||
* \ingroup ipc
|
* \ingroup ipc
|
||||||
@@ -24,6 +24,14 @@ class Bellringer {
|
|||||||
Bellringer(const Bellringer&) = delete;
|
Bellringer(const Bellringer&) = delete;
|
||||||
Bellringer& operator=(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.
|
/*! \brief List of bells currently managed.
|
||||||
*
|
*
|
||||||
* This list contains non-expired bells enqueued by job().
|
* This list contains non-expired bells enqueued by job().
|
||||||
@@ -34,26 +42,26 @@ class Bellringer {
|
|||||||
*/
|
*/
|
||||||
Queue<Bell> bells;
|
Queue<Bell> bells;
|
||||||
|
|
||||||
//! Link pointer for bells
|
|
||||||
static Bell** bell_link(Bell& obj, unsigned link_index);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// constructor
|
// constructor
|
||||||
Bellringer() : bells(0, bell_link) {}
|
Bellringer() : bells() {}
|
||||||
|
|
||||||
/*! \brief Checks whether there are bells to be rung.
|
/*! \brief Checks whether there are bells to be rung.
|
||||||
*
|
*
|
||||||
* Every call to check elapses a tick. Once such a tick reduces a bells
|
* Every call to check elapses a tick. Once such a tick reduces a bells
|
||||||
* remaining time to zero, the bell will be rung.
|
* remaining time to zero, the bell will be rung.
|
||||||
*
|
*
|
||||||
|
* \param vault The vault containing the bellringer instance
|
||||||
|
*
|
||||||
* \todo(16) Implement Method
|
* \todo(16) Implement Method
|
||||||
*/
|
*/
|
||||||
void check(Vault& vault);
|
void check(Vault& vault);
|
||||||
|
|
||||||
/*! \brief Passes a `bell` to the bellringer to be rung after `ms`
|
/*! \brief Passes a `bell` to the bellringer to be rung after `ms`
|
||||||
* milliseconds.
|
* 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
|
* ringing the bell
|
||||||
*
|
*
|
||||||
* \todo(16) Implement Method
|
* \todo(16) Implement Method
|
||||||
|
|||||||
@@ -1,16 +1,7 @@
|
|||||||
#include "./semaphore.h"
|
#include "./semaphore.h"
|
||||||
|
|
||||||
#include "../interrupt/guard.h"
|
|
||||||
#include "../thread/thread.h"
|
|
||||||
|
|
||||||
Semaphore::Semaphore(unsigned c) { (void)c; }
|
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::p(Vault &vault) { (void)vault; }
|
||||||
|
|
||||||
void Semaphore::v(Vault &vault) { (void)vault; }
|
void Semaphore::v(Vault &vault) { (void)vault; }
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ class Semaphore {
|
|||||||
Semaphore(const Semaphore&) = delete;
|
Semaphore(const Semaphore&) = delete;
|
||||||
Semaphore& operator=(const Semaphore&) = delete;
|
Semaphore& operator=(const Semaphore&) = delete;
|
||||||
|
|
||||||
static Thread** thread_link(Thread& obj, unsigned link_index);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*! \brief Constructor; initialized the counter with provided value `c`
|
/*! \brief Constructor; initialized the counter with provided value `c`
|
||||||
* \param c Initial counter value
|
* \param c Initial counter value
|
||||||
|
|||||||
@@ -35,14 +35,15 @@ class Spinlock {
|
|||||||
// Prevent copies and assignments
|
// Prevent copies and assignments
|
||||||
Spinlock(const Spinlock& copy) = delete;
|
Spinlock(const Spinlock& copy) = delete;
|
||||||
Spinlock& operator=(const Spinlock&) = delete;
|
Spinlock& operator=(const Spinlock&) = delete;
|
||||||
|
private:
|
||||||
|
volatile uint64_t locked;
|
||||||
public:
|
public:
|
||||||
/*! \brief Constructor; Initializes as unlocked.
|
/*! \brief Constructor; Initializes as unlocked.
|
||||||
*
|
*
|
||||||
* \todo(12) Complete Constructor (for \MPStuBS, or use \ref Ticketlock)
|
* \todo(12) Complete Constructor (for \MPStuBS, or use \ref Ticketlock)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
consteval Spinlock() {}
|
consteval Spinlock() : locked(0) {}
|
||||||
|
|
||||||
/*! \brief Enters the critical area. In case the area is already locked,
|
/*! \brief Enters the critical area. In case the area is already locked,
|
||||||
* \ref lock() will actively wait until the area can be entered.
|
* \ref lock() will actively wait until the area can be entered.
|
||||||
@@ -50,11 +51,11 @@ class Spinlock {
|
|||||||
* \see \ref Core::pause()
|
* \see \ref Core::pause()
|
||||||
* \todo(12) Implement Method (for \MPStuBS, or use \ref Ticketlock)
|
* \todo(12) Implement Method (for \MPStuBS, or use \ref Ticketlock)
|
||||||
*/
|
*/
|
||||||
void lock() {}
|
void lock();
|
||||||
|
|
||||||
/*! \brief Unblocks the critical area.
|
/*! \brief Unblocks the critical area.
|
||||||
*
|
*
|
||||||
* \todo(12) Implement Method (for \MPStuBS, or use \ref Ticketlock)
|
* \todo(12) Implement Method (for \MPStuBS, or use \ref Ticketlock)
|
||||||
*/
|
*/
|
||||||
void unlock() {}
|
void unlock();
|
||||||
};
|
};
|
||||||
|
|||||||
15
sync/ticketlock.cc
Normal file
15
sync/ticketlock.cc
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#include "sync/ticketlock.h"
|
||||||
|
#include "debug/output.h"
|
||||||
|
|
||||||
|
void Ticketlock::lock() {
|
||||||
|
uint64_t ticket = __atomic_fetch_add(&ticket_count, 1, __ATOMIC_RELAXED);
|
||||||
|
while (ticket != __atomic_fetch_add(&ticket_current, 0, __ATOMIC_ACQUIRE)) {
|
||||||
|
Core::pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ticketlock::unlock() {
|
||||||
|
if(ticket_current != ticket_count){
|
||||||
|
__atomic_fetch_add(&ticket_current, 1, __ATOMIC_RELEASE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "../types.h"
|
||||||
|
|
||||||
|
#include "../arch/core.h"
|
||||||
|
#include "../arch/cache.h"
|
||||||
/*! \brief Using Ticketlocks, it is possible to serialize blocks of code
|
/*! \brief Using Ticketlocks, it is possible to serialize blocks of code
|
||||||
* that might otherwise run in parallel on multiple CPU cores,
|
* that might otherwise run in parallel on multiple CPU cores,
|
||||||
* or be interleaved due to interrupts or scheduling.
|
* or be interleaved due to interrupts or scheduling.
|
||||||
@@ -29,12 +32,17 @@ class Ticketlock {
|
|||||||
Ticketlock(const Ticketlock& copy) = delete;
|
Ticketlock(const Ticketlock& copy) = delete;
|
||||||
Ticketlock& operator=(const Ticketlock&) = delete;
|
Ticketlock& operator=(const Ticketlock&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
volatile uint64_t ticket_current;
|
||||||
|
volatile uint64_t ticket_count;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*! \brief Constructor
|
/*! \brief Constructor
|
||||||
*
|
*
|
||||||
* \todo(12) Complete Constructor (for \MPStuBS)
|
* \todo(12) Complete Constructor (for \MPStuBS)
|
||||||
*/
|
*/
|
||||||
consteval Ticketlock() {}
|
consteval Ticketlock() : ticket_current(0), ticket_count(0) {}
|
||||||
|
|
||||||
/*! \brief Enters the critical area. In case the area is already locked,
|
/*! \brief Enters the critical area. In case the area is already locked,
|
||||||
* \ref lock() will actively wait until the area can be entered.
|
* \ref lock() will actively wait until the area can be entered.
|
||||||
@@ -42,11 +50,11 @@ class Ticketlock {
|
|||||||
* \see \ref Core::pause()
|
* \see \ref Core::pause()
|
||||||
* \todo(12) Implement Method (for \MPStuBS)
|
* \todo(12) Implement Method (for \MPStuBS)
|
||||||
*/
|
*/
|
||||||
void lock() {}
|
void lock();
|
||||||
|
|
||||||
/*! \brief Unblocks the critical area.
|
/*! \brief Unblocks the critical area.
|
||||||
*
|
*
|
||||||
* \todo(12) Implement Method (for \MPStuBS)
|
* \todo(12) Implement Method (for \MPStuBS)
|
||||||
*/
|
*/
|
||||||
void unlock() {}
|
void unlock();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,17 +1,32 @@
|
|||||||
// vim: set noet ts=4 sw=4:
|
// vim: set noet ts=4 sw=4:
|
||||||
|
|
||||||
#include "dispatcher.h"
|
#include "dispatcher.h"
|
||||||
|
#include "../arch/core.h"
|
||||||
|
|
||||||
Dispatcher::Dispatcher() {}
|
Dispatcher::Dispatcher() {
|
||||||
|
|
||||||
Thread *Dispatcher::active() { return nullptr; }
|
|
||||||
|
|
||||||
bool Dispatcher::isActive(const Thread *thread, unsigned *cpu) {
|
|
||||||
(void)thread;
|
|
||||||
(void)cpu;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
#pragma once
|
||||||
#include "../thread/thread.h"
|
#include "../thread/thread.h"
|
||||||
#include "../types.h"
|
#include "../types.h"
|
||||||
|
#include "../arch/core.h"
|
||||||
|
|
||||||
/*! \brief The dispatcher dispatches threads and puts the scheduler's
|
/*! \brief The dispatcher dispatches threads and puts the scheduler's
|
||||||
* decisions into action.
|
* decisions into action.
|
||||||
@@ -23,12 +24,14 @@ class Dispatcher {
|
|||||||
*/
|
*/
|
||||||
void setActive(Thread* thread) { (void)thread; }
|
void setActive(Thread* thread) { (void)thread; }
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*! \brief constructor
|
/*! \brief constructor
|
||||||
*
|
*
|
||||||
* \todo(14) Implement Method
|
* \todo(14) Implement Method
|
||||||
*/
|
*/
|
||||||
Dispatcher();
|
Dispatcher();
|
||||||
|
Thread* lifePointer[Core::MAX];
|
||||||
|
|
||||||
/*! \brief Returns the thread currently running on the CPU core calling
|
/*! \brief Returns the thread currently running on the CPU core calling
|
||||||
* this method
|
* this method
|
||||||
|
|||||||
@@ -2,22 +2,47 @@
|
|||||||
|
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
|
|
||||||
Scheduler::Scheduler() {}
|
Queue<Thread> readyList = Queue<Thread>();
|
||||||
|
|
||||||
|
Scheduler::Scheduler() {
|
||||||
|
}
|
||||||
|
|
||||||
Thread* Scheduler::getNext() { return nullptr; }
|
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) {
|
bool Scheduler::isActive(const Thread* thread, unsigned int* cpu) {
|
||||||
(void)that;
|
(void)thread;
|
||||||
(void)cpu;
|
(void)cpu;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,18 +22,20 @@
|
|||||||
* taken from the front of the queue.
|
* taken from the front of the queue.
|
||||||
*/
|
*/
|
||||||
class Scheduler {
|
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
|
/*! \brief a Dispatcher object, providing the low level context switching
|
||||||
* routines.
|
* routines.
|
||||||
*/
|
*/
|
||||||
Dispatcher dispatcher;
|
Dispatcher dispatcher;
|
||||||
|
|
||||||
/*! \brief Helper to retrieve next Thread
|
|
||||||
* \return pointer of next thread
|
|
||||||
*/
|
|
||||||
Thread* getNext();
|
|
||||||
|
|
||||||
public:
|
|
||||||
Scheduler();
|
|
||||||
|
|
||||||
/*! \brief Start scheduling
|
/*! \brief Start scheduling
|
||||||
*
|
*
|
||||||
@@ -103,7 +105,7 @@ class Scheduler {
|
|||||||
Thread* active() { return dispatcher.active(); }
|
Thread* active() { return dispatcher.active(); }
|
||||||
|
|
||||||
/// \copydoc Dispatcher::isActive
|
/// \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.
|
/*! \brief Checks whether the ready queue is empty.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,16 +1,43 @@
|
|||||||
// vim: set noet ts=4 sw=4:
|
// vim: set noet ts=4 sw=4:
|
||||||
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "../debug/output.h"
|
||||||
|
#include "../arch/context.h"
|
||||||
|
#include "interrupt/guard.h"
|
||||||
// Alias to simplify stuff
|
// Alias to simplify stuff
|
||||||
typedef void (*kickoff_t)(void*);
|
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 "../arch/context.h"
|
||||||
#include "../object/queue.h"
|
#include "../object/queue.h"
|
||||||
#include "../types.h"
|
#include "../types.h"
|
||||||
|
|
||||||
/*! \brief The Thread is an object used by the scheduler.
|
/*! \brief The Thread is an object used by the scheduler.
|
||||||
* \ingroup thread
|
* \ingroup thread
|
||||||
*/
|
*/
|
||||||
class Thread {
|
class Thread {
|
||||||
protected:
|
public:
|
||||||
/*! \brief The thread's entry point.
|
/*! \brief The thread's entry point.
|
||||||
*
|
*
|
||||||
* For the first activation of a thread, we need a "return address"
|
* For the first activation of a thread, we need a "return address"
|
||||||
@@ -36,13 +35,15 @@ class Thread {
|
|||||||
*
|
*
|
||||||
* \param object Thread to be started
|
* \param object Thread to be started
|
||||||
*/
|
*/
|
||||||
/// \todo(14) Implement Method
|
|
||||||
static void kickoff(Thread* object);
|
static void kickoff(Thread* object);
|
||||||
|
|
||||||
|
volatile bool kill_flag;
|
||||||
|
Context context;
|
||||||
|
Thread* queue_link;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*! \brief Marker for a dying thread
|
/*! \brief Marker for a dying thread
|
||||||
*/
|
*/
|
||||||
volatile bool kill_flag;
|
|
||||||
|
|
||||||
/*! \brief Constructor
|
/*! \brief Constructor
|
||||||
* Initializes the context using \ref prepareContext with the given stack
|
* Initializes the context using \ref prepareContext with the given stack
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ kvm: all
|
|||||||
|
|
||||||
# Execute Qemu with activated GDB stub and directly connect GDB to the spawned Qemu.
|
# Execute Qemu with activated GDB stub and directly connect GDB to the spawned Qemu.
|
||||||
gdb: all
|
gdb: all
|
||||||
${VERBOSE} cgdb -d $(GDB) "$(DBGKERNEL)" \
|
${VERBOSE} cgdb "$(DBGKERNEL)" \
|
||||||
-ex "set arch $(DBGARCH)" \
|
-ex "set arch $(DBGARCH)" \
|
||||||
-ex "target remote | exec $(QEMU) -gdb stdio $(QEMUKERNEL) -smp $(QEMUCPUS) -S $(QEMUFLAGS) $(DBGFLAGS)"
|
-ex "target remote | exec $(QEMU) -gdb stdio $(QEMUKERNEL) -smp $(QEMUCPUS) -S $(QEMUFLAGS) $(DBGFLAGS)"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Test your system on real hardware
|
# Test your system on real hardware
|
||||||
|
|
||||||
NETBOOT_LOCAL="/ibr/adm/user-boot/"
|
NETBOOT_LOCAL="/ibr/adm/user-boot/"
|
||||||
NETBOOT_HOST="x1.ibr.cs.tu-bs.de"
|
NETBOOT_HOST="y0080589@x1.ibr.cs.tu-bs.de"
|
||||||
|
|
||||||
# The boot menu shows pairs of `vmlinuz-*` + `initrd-*.img` with owning user and timestamp.
|
# The boot menu shows pairs of `vmlinuz-*` + `initrd-*.img` with owning user and timestamp.
|
||||||
# We just need to choose a name that doesn't overlap with another user's.
|
# We just need to choose a name that doesn't overlap with another user's.
|
||||||
|
|||||||
@@ -1,6 +1,62 @@
|
|||||||
// vim: set noet ts=4 sw=4:
|
// vim: set noet ts=4 sw=4:
|
||||||
|
|
||||||
#include "appl.h"
|
#include "appl.h"
|
||||||
|
#include "../../device/ps2controller.h"
|
||||||
|
#include "../../object/outputstream.h"
|
||||||
|
#include "../../device/textstream.h"
|
||||||
|
#include "../../sync/ticketlock.h"
|
||||||
|
#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\
|
||||||
|
Ich bin Großmutterknuddler, Großmutterknuddler\n\
|
||||||
|
Ich bin Großmutterknuddler, ich bin Großmutterknuddler\n\
|
||||||
|
\n\
|
||||||
|
Saftige Pflaumen voller Aroma\n\
|
||||||
|
Ich knuddel jede Oma ins Koma\n\
|
||||||
|
Ich bin Großmutterknuddler, Großmutterknuddler\n\
|
||||||
|
Ich bin Großmuttersniffer\n\
|
||||||
|
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) {
|
||||||
|
counter++; // Simple operation to consume cycles
|
||||||
|
asm("nop");
|
||||||
|
//Core::pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Application::action() { // NOLINT
|
void Application::action() { // NOLINT
|
||||||
|
uint16_t cnt = 0;
|
||||||
|
uint8_t row = appl_cnt++;
|
||||||
|
while (1) {
|
||||||
|
//koutlock.lock();
|
||||||
|
{
|
||||||
|
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(10000000);
|
||||||
|
|
||||||
|
if(cnt >= sizeof(text)-1)
|
||||||
|
cnt=0;
|
||||||
|
//context_switch(test2,test1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,25 +6,26 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../types.h"
|
#include "../../types.h"
|
||||||
|
#include "../../thread/thread.h"
|
||||||
//! \brief Test application
|
//! \brief Test application
|
||||||
//!
|
//!
|
||||||
//! \todo(12) Create a test application
|
//! \todo(12) Create a test application
|
||||||
//! \todo(14) Application should inherit from \ref Thread
|
//! \todo(14) Application should inherit from \ref Thread
|
||||||
//! \todo(16) Make some noise using the \ref PIT::pcspeaker "PC Speaker"
|
//! \todo(16) Make some noise using the \ref PIT::pcspeaker "PC Speaker"
|
||||||
class Application {
|
class Application:public Thread {
|
||||||
// Prevent copies and assignments
|
// Prevent copies and assignments
|
||||||
Application(const Application&) = delete;
|
Application(const Application&) = delete;
|
||||||
Application& operator=(const Application&) = delete;
|
Application& operator=(const Application&) = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Application(Application&&) = default; // XXX: is this used anywhere?
|
Application() = default; // XXX: is this used anywhere?
|
||||||
|
|
||||||
/*! \brief Constructor
|
/*! \brief Constructor
|
||||||
*
|
*
|
||||||
* \todo(14) Implement Constructor
|
* \todo(14) Implement Constructor
|
||||||
*/
|
*/
|
||||||
|
Application(void* tos): Thread(tos){
|
||||||
|
}
|
||||||
/*! \brief Contains the application code.
|
/*! \brief Contains the application code.
|
||||||
*
|
*
|
||||||
* \todo(14) Implement Method
|
* \todo(14) Implement Method
|
||||||
|
|||||||
Reference in New Issue
Block a user