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*
|
||||||
/build*
|
/build*
|
||||||
/tools/qemu.mk
|
/tools/qemu.mk
|
||||||
|
/tools/remote.mk
|
||||||
|
|||||||
@@ -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){
|
||||||
|
|||||||
@@ -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,8 @@ enum Vector {
|
|||||||
SECURITY_EXCEPTION = 31,
|
SECURITY_EXCEPTION = 31,
|
||||||
|
|
||||||
// Interrupts
|
// Interrupts
|
||||||
|
KEYBOARD=32,
|
||||||
|
PANIC=33
|
||||||
};
|
};
|
||||||
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;
|
||||||
|
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 config(uint8_t slot, Core::Interrupt::Vector vector,
|
void config(uint8_t slot, Core::Interrupt::Vector vector,
|
||||||
TriggerMode trigger_mode, Polarity polarity) {
|
TriggerMode trigger_mode, Polarity polarity) {
|
||||||
(void)slot;
|
assert(slot < slot_max);
|
||||||
(void)vector;
|
RedirectionTableEntry entry = readEntry(slot);
|
||||||
(void)trigger_mode;
|
entry.vector = vector;
|
||||||
(void)polarity;
|
entry.trigger_mode = trigger_mode;
|
||||||
|
entry.polarity = polarity;
|
||||||
|
writeEntry(slot, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void allow(uint8_t slot) { (void)slot; }
|
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) { (void)slot; }
|
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.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -43,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);
|
writeReg(TRANSMIT_BUFFER_REGISTER, out);
|
||||||
return out;
|
return out;
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "textwindow.h"
|
#include "textwindow.h"
|
||||||
#include "cga.h"
|
#include "cga.h"
|
||||||
#include "../utils/string.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) {
|
||||||
@@ -13,12 +14,23 @@ TextWindow::TextWindow(unsigned from_col, unsigned to_col, unsigned from_row,
|
|||||||
setPos(0,0);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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 "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)
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -108,18 +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();
|
uint8_t status_reg = ctrl_port.inb();
|
||||||
if(status_reg & IS_MOUSE || !(status_reg & HAS_OUTPUT) )
|
if(!(status_reg & HAS_OUTPUT) )
|
||||||
return false; // TODO Remove mouse events from buffer
|
return false;
|
||||||
DBG_VERBOSE << "status: " << hex << static_cast<int>(status_reg) << "\n" << flush;
|
DBG_VERBOSE << "status: " << hex << static_cast<int>(status_reg) << "\n" << flush;
|
||||||
|
|
||||||
uint8_t out_buffer = data_port.inb();
|
uint8_t out_buffer = data_port.inb();
|
||||||
DBG_VERBOSE << "scancode: " << hex << static_cast<int>(out_buffer) << "\n" << flush;
|
DBG_VERBOSE << "scancode: " << hex << static_cast<int>(out_buffer) << "\n" << flush;
|
||||||
|
|
||||||
|
if (status_reg & IS_MOUSE)
|
||||||
|
return false;
|
||||||
|
|
||||||
pressed = key_decoder.decode(out_buffer);
|
pressed = key_decoder.decode(out_buffer);
|
||||||
|
|
||||||
if (pressed.alt() || pressed.ctrl() || pressed.shift || !pressed.valid())
|
if (pressed.alt() || pressed.ctrl() || !pressed.valid())
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
@@ -140,6 +143,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) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "textstream.h"
|
#include "textstream.h"
|
||||||
#include "../arch/lapic.h"
|
#include "../arch/core.h"
|
||||||
|
|
||||||
TextStream::TextStream(unsigned from_col,
|
TextStream::TextStream(unsigned from_col,
|
||||||
unsigned to_col,
|
unsigned to_col,
|
||||||
@@ -17,7 +17,7 @@ TextStream::TextStream(unsigned from_col,
|
|||||||
|
|
||||||
|
|
||||||
void TextStream::flush() {
|
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));
|
print(buffer,pos,CGA::Attribute(CGA::LIGHT_GREEN, fg, false));
|
||||||
pos = 0;
|
pos = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
namespace Epilogues {
|
namespace Epilogues {
|
||||||
|
|
||||||
void keyboard(Vault& g) { (void)g; }
|
void keyboard(Vault& g) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void timer(Vault& g) { (void)g; }
|
void timer(Vault& g) { (void)g; }
|
||||||
|
|
||||||
|
|||||||
@@ -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()]
|
||||||
@@ -21,10 +22,45 @@ 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();
|
||||||
|
}
|
||||||
|
|
||||||
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; }
|
const Vault &Guard::unsafeConstAccess() { return global_vault; }
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 ;
|
||||||
|
|||||||
@@ -7,6 +7,12 @@
|
|||||||
#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"
|
||||||
|
|
||||||
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
|
||||||
@@ -65,10 +71,27 @@ enum PAGE_FAULT_ERROR {
|
|||||||
kernelpanic("Page fault!");
|
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) {
|
[[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) {
|
||||||
@@ -97,6 +120,9 @@ void initInterruptHandlers() {
|
|||||||
IDT::InterruptDescriptor::ReturningWithError(handle_page_fault));
|
IDT::InterruptDescriptor::ReturningWithError(handle_page_fault));
|
||||||
|
|
||||||
// TODO: Add more handlers here
|
// TODO: Add more handlers here
|
||||||
|
IDT::set(Core::Interrupt::Vector::KEYBOARD,
|
||||||
|
IDT::InterruptDescriptor::Returning(handle_keyboard_asm));
|
||||||
|
|
||||||
// Load the idt pointer
|
// 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);
|
||||||
|
|
||||||
|
|||||||
77
main.cc
77
main.cc
@@ -1,7 +1,9 @@
|
|||||||
#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/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"
|
||||||
@@ -9,7 +11,13 @@
|
|||||||
#include "device/serialstream.h"
|
#include "device/serialstream.h"
|
||||||
#include "device/textstream.h"
|
#include "device/textstream.h"
|
||||||
#include "device/ps2controller.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);
|
TextStream kout = TextStream(0, 80, 0, 10, true);
|
||||||
|
Ticketlock koutlock;
|
||||||
|
|
||||||
//TextStream dout[8] = {
|
//TextStream dout[8] = {
|
||||||
// TextStream(0 ,20,12,25,false),
|
// 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(0 ,0 ,0, 0,false),
|
// TextStream(0 ,0 ,0, 0,false),
|
||||||
//};
|
//};
|
||||||
|
|
||||||
TextStream dout[Core::MAX] = {
|
TextStream dout[Core::MAX] = {
|
||||||
{0, 40, 10, 14},
|
{0, 40, 10, 14},
|
||||||
{40, 80, 10, 14},
|
{40, 80, 10, 14},
|
||||||
@@ -54,39 +63,16 @@ OutputStream* copyout[Core::MAX]{
|
|||||||
&dout[7]
|
&dout[7]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
unsigned int testx, testy;
|
||||||
|
|
||||||
// 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;
|
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 << "Test <stream result> -> <expected>" << endl;
|
||||||
kout << "bool: " << true << " -> true" << endl;
|
kout << "bool: " << true << " -> true" << endl;
|
||||||
kout << "zero: " << 0 << " -> 0" << endl;
|
kout << "zero: " << 0 << " -> 0" << endl;
|
||||||
@@ -111,12 +97,23 @@ extern "C" int main() {
|
|||||||
ApplicationProcessor::boot();
|
ApplicationProcessor::boot();
|
||||||
|
|
||||||
PS2Controller::init();
|
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){
|
while (true){
|
||||||
if (PS2Controller::fetch(key)) {
|
DBG << "pos: " << testx << ", " << testy << endl << flush;
|
||||||
kout << key.ascii() << flush ;
|
Core::pause();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,24 +121,12 @@ 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;
|
||||||
|
|
||||||
|
//assert(Core::getID() != 1);
|
||||||
//TextWindow dout0 = TextWindow(0,20,13,19, false);
|
Application{}.action();
|
||||||
//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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
};
|
};
|
||||||
|
|||||||
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
|
#pragma once
|
||||||
|
|
||||||
|
#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 +31,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 +49,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,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="y0085044@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,49 @@
|
|||||||
// 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"
|
||||||
|
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
|
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;
|
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
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user