Compare commits
40 Commits
35c2667fbf
...
9af6bd4455
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.build*
|
||||
/build*
|
||||
/tools/qemu.mk
|
||||
/tools/remote.mk
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
2
compile_flags.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
-Iarch
|
||||
-xc++
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
namespace Epilogues {
|
||||
|
||||
void keyboard(Vault& g) { (void)g; }
|
||||
void keyboard(Vault& g) {
|
||||
|
||||
}
|
||||
|
||||
void timer(Vault& g) { (void)g; }
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
77
main.cc
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
12
sync/ticketlock.cc
Normal 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);
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user