Compare commits

...

40 Commits

Author SHA1 Message Date
Eggert Jung
9af6bd4455 Merge branch 'main' of gitlab.ibr.cs.tu-bs.de:vss/teaching/ss25/v_bsb1/Gruppe_018 2025-05-20 23:21:40 +02:00
Eggert Jung
4ee45e27c2 wip aufg 3 2025-05-20 23:21:25 +02:00
Simon
00c6f9c943 removed interrupt enable/disable from critical app section 2025-05-20 20:33:21 +02:00
Eggert Jung
deac8bfb8c fix ) 2025-05-20 20:21:41 +02:00
Eggert Jung
901eb0bbf5 zack fertig 2025-05-13 17:44:58 +02:00
Eggert Jung
f1e5f17d1f move reboot call to handlerscc 2025-05-13 17:36:34 +02:00
Eggert Jung
a415260776 rename lock 2025-05-13 16:49:28 +02:00
Eggert Jung
2421136335 foo 2025-05-13 16:24:44 +02:00
Eggert Jung
b0f129141a fix hw issue 2025-05-13 16:05:28 +02:00
Eggert Jung
ae3980cfa2 check cga pos bounds and debug print 2025-05-13 15:35:47 +02:00
Eggert Jung
bddcebefae Merge branch 'main' of gitlab.ibr.cs.tu-bs.de:vss/teaching/ss25/v_bsb1/Gruppe_018 2025-05-13 15:35:03 +02:00
Eggert Jung
7d65db4f45 cleanup code 2025-05-13 15:34:51 +02:00
Simon
e4e7cb9d0c added spinlock 2025-05-13 15:10:03 +02:00
Simon
9afe202078 ticketlock foo 2025-05-13 14:35:58 +02:00
Simon
4a731be0ca removed double lines 2025-05-12 21:44:42 +02:00
Simon
a053ac561c censored 2025-05-12 21:44:13 +02:00
Eggert Jung
20f7f50fa9 start app on appcpu 2025-05-12 21:41:46 +02:00
Eggert Jung
65514ec040 add app 2025-05-11 02:20:07 +02:00
Eggert Jung
b61df61e36 fix endof interrupt 2025-05-11 01:18:41 +02:00
Eggert Jung
220bdd8b77 Merge branch 'main' of gitlab.ibr.cs.tu-bs.de:vss/teaching/ss25/v_bsb1/Gruppe_018 2025-05-11 01:02:22 +02:00
Eggert Jung
2543dca933 cleanup 2025-05-11 01:01:47 +02:00
Eggert Jung
58f8cf1815 execute fetch in isr 2025-05-10 23:22:36 +02:00
Simon
d5dc4935a5 fixed iret 2025-05-10 22:16:22 +02:00
Eggert Jung
2a0f0573db set IDT 2025-05-10 21:17:52 +02:00
Eggert Jung
ebd3bd3597 remove unneccessary bullshit 2025-05-10 20:03:04 +02:00
Eggert Jung
7214ce8e53 foo 2025-05-10 19:42:48 +02:00
Eggert Jung
383561a4f6 add ctrl alt del 2025-05-10 16:53:17 +02:00
Simon
e9500c1b40 capitalization 2025-05-10 15:37:56 +02:00
Simon
9a311fd38c ich hab das ganz sicher nicht die letzten 5 min gefixed was ich am dienstag vergeigt habe 2025-05-10 15:01:13 +02:00
Eggert Jung
90faf06496 Merge branch 'main' of gitlab.ibr.cs.tu-bs.de:vss/teaching/ss25/v_bsb1/Gruppe_018 2025-05-06 19:51:13 +02:00
Eggert Jung
b2368b2bc5 implement init 2025-05-06 19:50:56 +02:00
Simon
f8942434df enable interrupts for each core 2025-05-06 19:09:42 +02:00
Simon
1dc52aa6f2 checkmark to done todo 2025-05-06 18:57:25 +02:00
Eggert Jung
24c6311f38 drain 2025-05-06 18:54:09 +02:00
Eggert Jung
ecc3b1011d Merge branch 'main' of gitlab.ibr.cs.tu-bs.de:vss/teaching/ss25/v_bsb1/Gruppe_018 2025-05-06 18:09:56 +02:00
Eggert Jung
5846351aed feedback 2025-05-06 18:07:37 +02:00
Simon
35765897c4 handler asm code for saving the volatile registers created 2025-05-06 17:53:45 +02:00
Simon
6d5f48e154 handle panic now triggers a panic 2025-05-06 17:27:51 +02:00
Simon
55c23fb293 added the user defined interrupt 2025-05-06 17:04:11 +02:00
Simon
6534b4660c mini changes 2025-05-06 16:32:32 +02:00
26 changed files with 304 additions and 105 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.build*
/build*
/tools/qemu.mk
/tools/remote.mk

View File

@@ -1,5 +1,6 @@
#include "cga.h"
#include "arch/ioport.h"
#include "../debug/output.h"
#include "../arch/ioport.h"
namespace CGA {
@@ -8,7 +9,7 @@ namespace CGA {
void writeCGAReg(int reg, int data){
index_port.outb(reg);
data_port.outw(data);
data_port.outb(data);
}
uint16_t readCGAReg(int reg){
@@ -17,7 +18,7 @@ namespace CGA {
}
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_HIGH, ((pos >> 8) & 0xFF));

View File

@@ -28,7 +28,7 @@ constexpr uintptr_t FLAG_ENABLE = 1 << 9;
*
* \see [ISDMv3, 6.15 Exception and Interrupt
* Reference](intel_manual_vol3.pdf#page=203)
* \todo(12) Add Keyboard and Panic vector numbers
* \todo
*/
enum Vector {
// Predefined Exceptions
@@ -67,6 +67,8 @@ enum Vector {
SECURITY_EXCEPTION = 31,
// Interrupts
KEYBOARD=32,
PANIC=33
};
constexpr size_t VECTORS = 256;

View File

@@ -1,4 +1,7 @@
#include "ioapic.h"
#include "apic.h"
#include "core.h"
#include "../debug/assert.h"
namespace IOAPIC {
/*! \brief IOAPIC registers memory mapped into the CPU's address space.
@@ -20,22 +23,66 @@ volatile Register *IOWIN_REG =
// IOAPIC manual, p. 8
const Index IOAPICID_IDX = 0x00;
const Index IOREDTBL_IDX = 0x10;
const Index IOREDTBL_ENTRY_SIZE = 0x02;
const uint8_t slot_max = 24;
void init() {}
void config(uint8_t slot, Core::Interrupt::Vector vector,
TriggerMode trigger_mode, Polarity polarity) {
(void)slot;
(void)vector;
(void)trigger_mode;
(void)polarity;
RedirectionTableEntry readEntry(Index slot) {
*IOREGSEL_REG = IOREDTBL_IDX + slot * IOREDTBL_ENTRY_SIZE;
Register low = *IOWIN_REG;
*IOREGSEL_REG += IOREDTBL_ENTRY_SIZE / 2;
Register high = *IOWIN_REG;
return RedirectionTableEntry{low, high};
}
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) {
(void)slot;

View File

@@ -45,7 +45,7 @@ void init();
* \param polarity Polarity of the interrupt signaling (active high or
active low)
*
* \todo(12) Implement Function
* \todo Implement Function
*/
void config(uint8_t slot, Core::Interrupt::Vector vector,
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
* CPU (e.g., by calling
* \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.
*

View File

@@ -43,9 +43,8 @@ int Serial::write(char out) {
if(out == '\n')
write('\r');
if(readReg(LINE_STATUS_REGISTER) & TRANSMITTER_EMPTY){
writeReg(TRANSMIT_BUFFER_REGISTER, out);
return out;
}
return -1;
while(!(readReg(LINE_STATUS_REGISTER) & TRANSMITTER_EMPTY));
writeReg(TRANSMIT_BUFFER_REGISTER, out);
return out;
}

View File

@@ -1,6 +1,7 @@
#include "textwindow.h"
#include "cga.h"
#include "../utils/string.h"
#include "../debug/output.h"
TextWindow::TextWindow(unsigned from_col, unsigned to_col, unsigned from_row,
unsigned to_row, bool use_cursor) {
@@ -13,12 +14,23 @@ TextWindow::TextWindow(unsigned from_col, unsigned to_col, unsigned from_row,
setPos(0,0);
}
extern unsigned int testx, testy;
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){
CGA::setCursor(from_col + rel_x, from_row + rel_y);
testx = abs_x;
testy = abs_y;
CGA::setCursor(abs_x, abs_y);
}else{
pos_x = from_col + rel_x;
pos_y = from_row + rel_y;
pos_x = abs_x;
pos_y = abs_y;
}
}

2
compile_flags.txt Normal file
View File

@@ -0,0 +1,2 @@
-Iarch
-xc++

View File

@@ -1,4 +1,5 @@
#include "assert.h"
#include "output.h"
[[noreturn]] void assertion_failed(const char* exp, const char* func,
const char* file, int line) {
@@ -6,6 +7,7 @@
(void)func;
(void)file;
(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: Then stop the current core permanently
// Use appropriate method from class Core to do so.

View File

@@ -17,7 +17,7 @@
#define kernelpanic(MSG) \
do { \
DBG << "PANIC: '" << (MSG) << "' in " << __func__ << " @ " << __FILE__ \
<< ":" << __LINE__ << ") - CPU stopped." << endl; \
<< ":" << dec << __LINE__ << ") - CPU stopped." << endl; \
Core::die(); \
} while (0)

View File

@@ -1,5 +1,6 @@
#include "ps2controller.h"
#include "../arch/system.h"
#include "../arch/core_interrupt.h"
#include "../arch/ioport.h"
#include "../compiler/fix.h"
@@ -108,18 +109,20 @@ void init() {
}
bool fetch(Key &pressed) {
// TODO: You have to implement this method
uint8_t status_reg = ctrl_port.inb();
if(status_reg & IS_MOUSE || !(status_reg & HAS_OUTPUT) )
return false; // TODO Remove mouse events from buffer
if(!(status_reg & HAS_OUTPUT) )
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);
if (pressed.alt() || pressed.ctrl() || pressed.shift || !pressed.valid())
if (pressed.alt() || pressed.ctrl() || !pressed.valid())
return false;
else
return true;
@@ -140,6 +143,8 @@ void setLed(enum LED led, bool on) {
sendData(leds); // Parameter
}
void drainBuffer() {}
void drainBuffer() {
while(ctrl_port.inb() & HAS_OUTPUT)
data_port.inb();
}
} // namespace PS2Controller

View File

@@ -146,7 +146,6 @@ void setLed(enum LED led, bool on);
* should be emptied once right before allowing keyboard interrupts
* (even if keystrokes might be lost).
*
* \todo(12) Implement method
*/
void drainBuffer();

View File

@@ -41,8 +41,6 @@ void SerialStream::reset() {
}
void SerialStream::setPos(int x, int y) {
//char out[] = {0x1b, '[', 0, 0, ';', 0, 0, 'H', 0};
//*this << 0x1b;
write(0x1b);
sout << '[';
sout << dec << x;
@@ -50,9 +48,6 @@ void SerialStream::setPos(int x, int y) {
sout << dec << y;
sout << 'H';
flush();
//itoa(x, &out[2], 10);
//itoa(y, &out[5], 10);
//print( out , strlen(out));
}
void SerialStream::print(char* str, int length) {

View File

@@ -1,5 +1,5 @@
#include "textstream.h"
#include "../arch/lapic.h"
#include "../arch/core.h"
TextStream::TextStream(unsigned from_col,
unsigned to_col,
@@ -17,7 +17,7 @@ TextStream::TextStream(unsigned from_col,
void TextStream::flush() {
CGA::Color fg = static_cast<CGA::Color>((LAPIC::getID() + 1 ));
CGA::Color fg = static_cast<CGA::Color>((Core::getID() + 1 ));
print(buffer,pos,CGA::Attribute(CGA::LIGHT_GREEN, fg, false));
pos = 0;
}

View File

@@ -4,7 +4,9 @@
namespace Epilogues {
void keyboard(Vault& g) { (void)g; }
void keyboard(Vault& g) {
}
void timer(Vault& g) { (void)g; }

View File

@@ -4,6 +4,7 @@
#include "../debug/output.h"
#include "../object/bbuffer.h"
#include "../sync/ticketlock.h"
#include "../arch/core_interrupt.h"
#include "epilogues.h"
#define FOR_CURRENT_CORE [Core::getID()]
@@ -21,10 +22,45 @@ Vault::Vault() {}
Guarded::~Guarded() { Guard::leave(); }
Guarded Guard::enter() { while (true); }
Guarded Guard::enter() {
epi_flag FOR_CURRENT_CORE = true;
Core::Interrupt::enable();
global_lock.lock();
}
void Guard::leave() {}
void Guard::leave() {
bool istate = Core::Interrupt::disable();
void Guard::relay(Epilogue handler) { (void)handler; }
Epilogue next;
while(epilogue_queue FOR_CURRENT_CORE.consume(next)){
Core::Interrupt::enable();
next(global_vault);
Core::Interrupt::disable();
}
epi_flag FOR_CURRENT_CORE = false;
global_lock.unlock();
Core::Interrupt::restore(istate);
}
void Guard::relay(Epilogue handler) {
if(!epilogue_queue FOR_CURRENT_CORE.consume(handler))
return; // enqueue, but dont execute
if(epi_flag FOR_CURRENT_CORE){
enter();
Core::Interrupt::disable();
leave();
}
//Core::Interrupt::enable(); // goto level 0.5
//if(epi_flag FOR_CURRENT_CORE){
// epilogue_queue->produce(handler);
//}
//else{
// epi_flag FOR_CURRENT_CORE = true;
// handler(global_vault);
// leave(); // maybe not needed since destructor also calls leave
//}
}
const Vault &Guard::unsafeConstAccess() { return global_vault; }

View File

@@ -11,4 +11,26 @@ handle_keyboard_asm:
; continue. The C++ compiler will only generates code to preserve
; non-scratch registers in the high-level interrupt handler -- the scratch
; 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 ;

View File

@@ -7,6 +7,12 @@
#include "../debug/kernelpanic.h"
#include "../debug/output.h"
#include "../device/ps2controller.h"
#include "../sync/ticketlock.h"
#include "epilogues.h"
#include "guard.h"
void printContext(const InterruptContext *context) {
DBG << "ip: " << hex << context->cs << ':' << context->ip
<< " sp: " << context->ss << ':' << context->sp << " flags" << bin
@@ -65,10 +71,27 @@ enum PAGE_FAULT_ERROR {
kernelpanic("Page fault!");
}
void handle_keyboard() {}
extern TextStream kout;
extern Ticketlock koutlock;
extern Vault keyboard_vault;
void handle_keyboard() {
Key key = Key();
if (PS2Controller::fetch(key)) {
Guard::relay(Epilogues::keyboard);
//koutlock.lock();
//kout << key.ascii() << endl << flush ;
//koutlock.unlock();
}
else if (key.ctrl() && key.alt() && key.scancode == Key::KEY_DEL)
System::reboot();
LAPIC::endOfInterrupt();
}
[[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) {
@@ -97,6 +120,9 @@ void initInterruptHandlers() {
IDT::InterruptDescriptor::ReturningWithError(handle_page_fault));
// TODO: Add more handlers here
IDT::set(Core::Interrupt::Vector::KEYBOARD,
IDT::InterruptDescriptor::Returning(handle_keyboard_asm));
// Load the idt pointer
IDT::load();
}

View File

@@ -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
* 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);
@@ -77,12 +77,12 @@ extern "C" { // disable C++ name mangling for asm function
* \todo(12) Fetch a single key
* \todo(13) Extend to use the Prologue-Epilogue pattern
*/
void handle_keyboard();
void handle_keyboard();
}
/*! \brief handle_panic
*
* \todo(12) Trigger a kernel panic
* \todo Trigger a kernel panic
*/
[[gnu::interrupt]] void handle_panic(InterruptContext *context);

77
main.cc
View File

@@ -1,7 +1,9 @@
#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"
@@ -9,7 +11,13 @@
#include "device/serialstream.h"
#include "device/textstream.h"
#include "device/ps2controller.h"
#include "arch/ioapic.h"
#include "user/app1/appl.h"
#include "sync/ticketlock.h"
#include "interrupt/guard.h"
TextStream kout = TextStream(0, 80, 0, 10, true);
Ticketlock koutlock;
//TextStream dout[8] = {
// TextStream(0 ,20,12,25,false),
@@ -21,6 +29,7 @@ TextStream kout = TextStream(0, 80, 0, 10, true);
// TextStream(0 ,0 ,0, 0,false),
// TextStream(0 ,0 ,0, 0,false),
//};
TextStream dout[Core::MAX] = {
{0, 40, 10, 14},
{40, 80, 10, 14},
@@ -54,39 +63,16 @@ OutputStream* copyout[Core::MAX]{
&dout[7]
};
unsigned int testx, testy;
// Main function
// (the bootstrap processor starts here)}
extern "C" int main() {
CGA::setCursor(0, 0);
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;
@@ -111,12 +97,23 @@ extern "C" int main() {
ApplicationProcessor::boot();
PS2Controller::init();
Key key = Key();
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;
Application{}.action();
while (true){
if (PS2Controller::fetch(key)) {
kout << key.ascii() << flush ;
}
DBG << "pos: " << testx << ", " << testy << endl << flush;
Core::pause();
}
return 0;
}
@@ -124,24 +121,12 @@ extern "C" int main() {
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;
//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');
//uint8_t from = static_cast<int>(LAPIC::getID()) * 20;
//uint8_t to = from+20;
//dout[LAPIC::getID()] = TextStream(from, to, 0, 6, false);
DBG << "test\n" << flush;
DBG << static_cast<int>(LAPIC::getID()) << flush;
//assert(Core::getID() != 1);
Application{}.action();
return 0;
}

View File

@@ -35,14 +35,15 @@ class Spinlock {
// Prevent copies and assignments
Spinlock(const Spinlock& copy) = delete;
Spinlock& operator=(const Spinlock&) = delete;
private:
volatile uint64_t locked;
public:
/*! \brief Constructor; Initializes as unlocked.
*
* \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,
* \ref lock() will actively wait until the area can be entered.
@@ -50,11 +51,11 @@ class Spinlock {
* \see \ref Core::pause()
* \todo(12) Implement Method (for \MPStuBS, or use \ref Ticketlock)
*/
void lock() {}
void lock();
/*! \brief Unblocks the critical area.
*
* \todo(12) Implement Method (for \MPStuBS, or use \ref Ticketlock)
*/
void unlock() {}
void unlock();
};

12
sync/ticketlock.cc Normal file
View File

@@ -0,0 +1,12 @@
#include "sync/ticketlock.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() {
__atomic_fetch_add(&ticket_current, 1, __ATOMIC_RELEASE);
}

View File

@@ -4,6 +4,8 @@
#pragma once
#include "../arch/core.h"
#include "../arch/cache.h"
/*! \brief Using Ticketlocks, it is possible to serialize blocks of code
* that might otherwise run in parallel on multiple CPU cores,
* or be interleaved due to interrupts or scheduling.
@@ -29,12 +31,17 @@ class Ticketlock {
Ticketlock(const Ticketlock& copy) = delete;
Ticketlock& operator=(const Ticketlock&) = delete;
private:
volatile uint64_t ticket_current;
volatile uint64_t ticket_count;
public:
/*! \brief Constructor
*
* \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,
* \ref lock() will actively wait until the area can be entered.
@@ -42,11 +49,11 @@ class Ticketlock {
* \see \ref Core::pause()
* \todo(12) Implement Method (for \MPStuBS)
*/
void lock() {}
void lock();
/*! \brief Unblocks the critical area.
*
* \todo(12) Implement Method (for \MPStuBS)
*/
void unlock() {}
void unlock();
};

View File

@@ -1,7 +1,7 @@
# Test your system on real hardware
NETBOOT_LOCAL="/ibr/adm/user-boot/"
NETBOOT_HOST="x1.ibr.cs.tu-bs.de"
NETBOOT_HOST="y0085044@x1.ibr.cs.tu-bs.de"
# 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.

View File

@@ -1,6 +1,49 @@
// vim: set noet ts=4 sw=4:
#include "appl.h"
#include "../../device/ps2controller.h"
#include "../../object/outputstream.h"
#include "../../device/textstream.h"
#include "../../sync/ticketlock.h"
#include "../../arch/core.h"
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 TextStream kout;
extern Ticketlock koutlock;
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
uint16_t cnt = 0;
while (1) {
koutlock.lock();
while(text[cnt++] != '\n'){
kout << text[cnt-1];
}
kout << endl << flush;
koutlock.unlock();
activeWaitDelay(1000000000);
if(cnt >= sizeof(text)-1)
cnt=0;
}
}

View File

@@ -18,7 +18,7 @@ class Application {
Application& operator=(const Application&) = delete;
public:
Application(Application&&) = default; // XXX: is this used anywhere?
Application() = default; // XXX: is this used anywhere?
/*! \brief Constructor
*