Compare commits

..

No commits in common. '9af6bd4455418cd2fcc8ec6d12cad8df4c03bc8b' and '35c2667fbfb57ccde005f826800993d3db2890e3' have entirely different histories.

1
.gitignore vendored

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

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

@ -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
* \todo(12) Add Keyboard and Panic vector numbers
*/
enum Vector {
// Predefined Exceptions
@ -67,8 +67,6 @@ enum Vector {
SECURITY_EXCEPTION = 31,
// Interrupts
KEYBOARD=32,
PANIC=33
};
constexpr size_t VECTORS = 256;

@ -1,7 +1,4 @@
#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.
@ -23,66 +20,22 @@ 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;
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 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 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 init() {}
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);
TriggerMode trigger_mode, Polarity polarity) {
(void)slot;
(void)vector;
(void)trigger_mode;
(void)polarity;
}
void allow(uint8_t slot) {
assert(slot < slot_max);
RedirectionTableEntry entry = readEntry(slot);
entry.interrupt_mask = UNMASKED;
writeEntry(slot, entry);
}
void allow(uint8_t slot) { (void)slot; }
void forbid(uint8_t slot) {
assert(slot < slot_max);
RedirectionTableEntry entry = readEntry(slot);
entry.interrupt_mask = MASKED;
writeEntry(slot, entry);
}
void forbid(uint8_t slot) { (void)slot; }
bool status(uint8_t slot) {
(void)slot;

@ -45,7 +45,7 @@ void init();
* \param polarity Polarity of the interrupt signaling (active high or
active low)
*
* \todo Implement Function
* \todo(12) 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 Do that somewhere appropriate.
* \todo(12) Do that somewhere appropriate.
*
* \param slot Number of the external interrupt that should be enabled.
*

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

@ -1,7 +1,6 @@
#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) {
@ -14,23 +13,12 @@ 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){
testx = abs_x;
testy = abs_y;
CGA::setCursor(abs_x, abs_y);
CGA::setCursor(from_col + rel_x, from_row + rel_y);
}else{
pos_x = abs_x;
pos_y = abs_y;
pos_x = from_col + rel_x;
pos_y = from_row + rel_y;
}
}

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

@ -1,5 +1,4 @@
#include "assert.h"
#include "output.h"
[[noreturn]] void assertion_failed(const char* exp, const char* func,
const char* file, int line) {
@ -7,7 +6,6 @@
(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.

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

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

@ -146,6 +146,7 @@ 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();

@ -41,6 +41,8 @@ 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;
@ -48,6 +50,9 @@ 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) {

@ -1,5 +1,5 @@
#include "textstream.h"
#include "../arch/core.h"
#include "../arch/lapic.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>((Core::getID() + 1 ));
CGA::Color fg = static_cast<CGA::Color>((LAPIC::getID() + 1 ));
print(buffer,pos,CGA::Attribute(CGA::LIGHT_GREEN, fg, false));
pos = 0;
}

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

@ -4,7 +4,6 @@
#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()]
@ -22,45 +21,10 @@ Vault::Vault() {}
Guarded::~Guarded() { Guard::leave(); }
Guarded Guard::enter() {
epi_flag FOR_CURRENT_CORE = true;
Core::Interrupt::enable();
global_lock.lock();
}
Guarded Guard::enter() { while (true); }
void Guard::leave() {
bool istate = Core::Interrupt::disable();
void Guard::leave() {}
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
//}
}
void Guard::relay(Epilogue handler) { (void)handler; }
const Vault &Guard::unsafeConstAccess() { return global_vault; }

@ -11,26 +11,4 @@ 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: 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 ;
; TODO(12): Implement the context save and restore for the keyboard interrupt

@ -7,12 +7,6 @@
#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
@ -71,27 +65,10 @@ enum PAGE_FAULT_ERROR {
kernelpanic("Page fault!");
}
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();
}
void handle_keyboard() {}
[[gnu::interrupt]] void handle_panic(InterruptContext *context) {
DBG << "Generic KernelPanic triggered"<< endl;
printContext(context);
kernelpanic("Generic Panic Triggerd");
(void)context;
}
[[gnu::interrupt]] void handle_timer(InterruptContext *context) {
@ -120,9 +97,6 @@ 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();
}

@ -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 Implement in assembly
* \todo(12) 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 Trigger a kernel panic
* \todo(12) Trigger a kernel panic
*/
[[gnu::interrupt]] void handle_panic(InterruptContext *context);

@ -1,9 +1,7 @@
#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"
@ -11,13 +9,7 @@
#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),
@ -29,7 +21,6 @@ Ticketlock koutlock;
// TextStream(0 ,0 ,0, 0,false),
// TextStream(0 ,0 ,0, 0,false),
//};
TextStream dout[Core::MAX] = {
{0, 40, 10, 14},
{40, 80, 10, 14},
@ -63,16 +54,39 @@ 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;
@ -97,23 +111,12 @@ extern "C" int main() {
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;
Application{}.action();
Key key = Key();
while (true){
DBG << "pos: " << testx << ", " << testy << endl << flush;
Core::pause();
if (PS2Controller::fetch(key)) {
kout << key.ascii() << flush ;
}
}
return 0;
}
@ -121,12 +124,24 @@ 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;
//assert(Core::getID() != 1);
Application{}.action();
//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;
return 0;
}

@ -35,15 +35,14 @@ 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() : locked(0) {}
consteval Spinlock() {}
/*! \brief Enters the critical area. In case the area is already locked,
* \ref lock() will actively wait until the area can be entered.
@ -51,11 +50,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() {}
};

@ -1,12 +0,0 @@
#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);
}

@ -4,8 +4,6 @@
#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.
@ -31,17 +29,12 @@ 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() : ticket_current(0), ticket_count(0) {}
consteval Ticketlock() {}
/*! \brief Enters the critical area. In case the area is already locked,
* \ref lock() will actively wait until the area can be entered.
@ -49,11 +42,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() {}
};

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

@ -1,49 +1,6 @@
// 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;
}
}

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

Loading…
Cancel
Save