Commit c7bc4028 authored by Antônio Augusto Fröhlich's avatar Antônio Augusto Fröhlich
Browse files

Solution to P3 without the elements left out for P4.

parent ee55840a
// EPOS Semaphore Component Test Program
#include <machine/display.h>
#include <time.h>
#include <synchronizer.h>
#include <process.h>
......@@ -21,8 +20,6 @@ int philosopher(int n, int l, int c);
int main()
{
table.lock();
Display::clear();
Display::position(0, 0);
cout << "The Philosopher's Dinner:" << endl;
for(int i = 0; i < 5; i++)
......@@ -36,25 +33,12 @@ int main()
cout << "Philosophers are alive and hungry!" << endl;
Display::position(7, 44);
cout << '/';
Display::position(13, 44);
cout << '\\';
Display::position(16, 35);
cout << '|';
Display::position(13, 27);
cout << '/';
Display::position(7, 27);
cout << '\\';
Display::position(19, 0);
cout << "The dinner is served ..." << endl;
table.unlock();
for(int i = 0; i < 5; i++) {
int ret = phil[i]->join();
table.lock();
Display::position(20 + i, 0);
cout << "Philosopher " << i << " ate " << ret << " times " << endl;
table.unlock();
}
......@@ -77,14 +61,12 @@ int philosopher(int n, int l, int c)
for(int i = iterations; i > 0; i--) {
table.lock();
Display::position(l, c);
cout << "thinking";
table.unlock();
Delay thinking(1000000);
table.lock();
Display::position(l, c);
cout << " hungry ";
table.unlock();
......@@ -92,14 +74,12 @@ int philosopher(int n, int l, int c)
chopstick[second]->p(); // get second chopstick
table.lock();
Display::position(l, c);
cout << " eating ";
table.unlock();
Delay eating(500000);
table.lock();
Display::position(l, c);
cout << " sate ";
table.unlock();
......@@ -108,7 +88,6 @@ int philosopher(int n, int l, int c)
}
table.lock();
Display::position(l, c);
cout << " done ";
table.unlock();
......
......@@ -9,7 +9,7 @@ __BEGIN_SYS
template<> struct Traits<Build>: public Traits_Tokens
{
// Basic configuration
static const unsigned int MODE = BUILTIN;
static const unsigned int MODE = KERNEL;
static const unsigned int ARCHITECTURE = RV32;
static const unsigned int MACHINE = RISCV;
static const unsigned int MODEL = SiFive_E;
......
......@@ -9,7 +9,7 @@ __BEGIN_SYS
template<> struct Traits<Build>: public Traits_Tokens
{
// Basic configuration
static const unsigned int MODE = BUILTIN;
static const unsigned int MODE = KERNEL;
static const unsigned int ARCHITECTURE = RV32;
static const unsigned int MACHINE = RISCV;
static const unsigned int MODEL = SiFive_E;
......
......@@ -30,29 +30,46 @@ public:
// Status Register (mstatus)
typedef Reg32 Flags;
enum {
MIE = 1 << 3, // Machine Interrupts Enabled
SIE = 1 << 1, // Supervisor Interrupts Enabled
SPIE = 1 << 5, // Supervisor Previous Interrupts Enabled
MPIE = 1 << 7, // Machine Previous Interrupts Enabled
MPP = 3 << 11, // Machine Previous Privilege
MPP_M = 3 << 11, // Machine Previous Privilege = Machine
MPP_S = 1 << 11, // Machine Previous Privilege = Supervisor
MPP_U = 0 << 11, // Machine Previous Privilege = User
SPP = 1 << 8, // Supervisor Previous Privilege
SPP_S = 1 << 8, // Supervisor Previous Privilege = Supervisor
SPP_U = 0 << 8, // Supervisor Previous Privilege = User
MPRV = 1 << 17, // Memory Priviledge
TVM = 1 << 20 // Trap Virtual Memory //not allow MMU
UIE = 1 << 0, // User Interrupts Enabled
SIE = 1 << 1, // Supervisor Interrupts Enabled
MIE = 1 << 3, // Machine Interrupts Enabled
UPIE = 1 << 4, // User Previous Interrupts Enabled
SPIE = 1 << 5, // Supervisor Previous Interrupts Enabled
MPIE = 1 << 7, // Machine Previous Interrupts Enabled
SPP = 1 << 8, // Supervisor Previous Privilege
SPP_U = 0 << 8, // Supervisor Previous Privilege = user
SPP_S = 1 << 8, // Supervisor Previous Privilege = supervisor
MPP = 3 << 11, // Machine Previous Privilege
MPP_U = 0 << 11, // Machine Previous Privilege = user
MPP_S = 1 << 11, // Machine Previous Privilege = supervisor
MPP_M = 3 << 11, // Machine Previous Privilege = machine
FS = 3 << 13, // FPU Status
FS_OFF = 0 << 13, // FPU off
FS_INIT = 1 << 13, // FPU on
FS_CLEAN = 2 << 13, // FPU registers clean
FS_DIRTY = 3 << 13, // FPU registers dirty (and must be saved on context switch)
XS = 3 << 15, // Extension Status
XS_OFF = 0 << 15, // Extension off
XS_INIT = 1 << 15, // Extension on
XS_CLEAN = 2 << 15, // Extension registers clean
XS_DIRTY = 3 << 15, // Extension registers dirty (and must be saved on context switch)
MPRV = 1 << 17, // Memory PRiVilege (when set, enables MMU also in machine mode)
SUM = 1 << 18, // Supervisor User Memory access allowed
MXR = 1 << 19, // Make eXecutable Readable
TVM = 1 << 20, // Trap Virtual Memory makes SATP inaccessible in supervisor mode
TW = 1 << 21, // Timeout Wait for WFI outside machine mode
TSR = 1 << 22, // Trap SRet in supervisor mode
SD = 1 << 31, // Status Dirty = (FS | XS)
};
// Interrupt-Enable, Interrupt-Pending and Machine Cause Registers (mie, mip, and mcause when interrupt bit is set)
enum {
SSI = 1 << 1, // Supervisor Software Interrupt
MSI = 1 << 3, // Machine Software Interrupt
STI = 1 << 5, // Supervisor Timer Interrupt
MTI = 1 << 7, // Machine Timer Interrupt
SEI = 1 << 9, // Supervisor External Interrupt
MEI = 1 << 11 // Machine External Interrupt
SSI = 1 << 1, // Supervisor Software Interrupt
MSI = 1 << 3, // Machine Software Interrupt
STI = 1 << 5, // Supervisor Timer Interrupt
MTI = 1 << 7, // Machine Timer Interrupt
SEI = 1 << 9, // Supervisor External Interrupt
MEI = 1 << 11 // Machine External Interrupt
};
// Exceptions (mcause with interrupt = 0)
......@@ -76,7 +93,7 @@ public:
class Context
{
public:
// Contexts are loaded with mret, which gets pc from mepc and updates some bits of mstatus, that's why _st is initialized with MPIE and MPP
// Contexts are loaded with [m|s]ret, which gets pc from [m|s]epc and updates some bits of [m|s]status, that's why _st is initialized with [M|S]PIE and [M|S]PP
Context(const Log_Addr & entry, const Log_Addr & exit): _st(sup ? (SPIE | SPP_S) : (MPIE | MPP_M)), _pc(entry), _x1(exit) {
if(Traits<Build>::hysterically_debugged || Traits<Thread>::trace_idle) {
_x5 = 5; _x6 = 6; _x7 = 7; _x8 = 8; _x9 = 9;
......@@ -127,7 +144,7 @@ public:
}
public:
Reg32 _st; // mstatus
Reg32 _st; // [m|s]status
Reg32 _pc; // pc
// Reg32 _x0; // zero
Reg32 _x1; // ra, ABI Link Register
......@@ -205,6 +222,9 @@ public:
static void fpu_restore();
static void switch_context(Context ** o, Context * n) __attribute__ ((naked));
static void syscall(void * message);
static void syscalled(unsigned int int_id);
template<typename T>
static T tsl(volatile T & lock) {
register T old;
......@@ -268,19 +288,16 @@ public:
using CPU_Common::ntohs;
template<typename ... Tn>
static Context * init_stack(const Log_Addr & usp, Log_Addr sp, void (* exit)(), int (* entry)(Tn ...), Tn ... an) {
static Context * init_stack(Log_Addr usp, Log_Addr sp, void (* exit)(), int (* entry)(Tn ...), Tn ... an) {
sp -= sizeof(Context);
Context * ctx = new(sp) Context(entry, exit);
init_stack_helper(&ctx->_x10, an ...); // x10 is a0
return ctx;
}
// In RISC-V, the main thread of each task gets parameters over registers, not the stack, and they are initialized by init_stack.
template<typename ... Tn>
static Log_Addr init_user_stack(Log_Addr sp, void (* exit)(), Tn ... an) {
sp -= sizeof(Context);
Context * ctx = new(sp) Context(0, exit);
init_stack_helper(&ctx->_x10, an ...); // x10 is a0
return sp;
}
static Log_Addr init_user_stack(Log_Addr sp, void (* exit)(), Tn ... an) { return sp; }
public:
// RISC-V 32 specifics
......
......@@ -53,7 +53,7 @@ public:
Page_Flags(unsigned int f) : _flags(f) {}
Page_Flags(Flags f) : _flags(V | R | X |
((f & Flags::RW) ? W : 0) |
// ((f & Flags::USR) ? U : 0) |
((f & Flags::USR) ? U : 0) |
((f & Flags::CWT) ? 0 : 0) |
((f & Flags::CD) ? 0 : 0) |
((f & Flags::CT) ? CT : 0) |
......
// EPOS Component Authentication Aspect Program
#ifndef __authenticated_h
#define __authenticated_h
#include <system/config.h>
__BEGIN_SYS
template<typename Component>
class Authenticated
{
protected:
Authenticated() {}
public:
void enter() { db<Aspect>(TRC) << "Authenticated::enter()" << endl; }
void leave() { db<Aspect>(TRC) << "Authenticated::leave()" << endl; }
static void static_enter() { db<Aspect>(TRC) << "Authenticated::static_enter()" << endl; }
static void static_leave() { db<Aspect>(TRC) << "Authenticated::static_leave()" << endl; }
};
__END_SYS
#endif
// EPOS Energy-aware Component Management Aspect Program
#ifndef __energy_aware_h
#define __energy_aware_h
#include <framework/id.h>
#include <utility/hash.h>
__BEGIN_SYS
class Energized
{
public:
static const unsigned int TYPES = LAST_MEDIATOR_ID - FIRST_MEDIATOR_ID;
typedef Hash<Energized, TYPES, Type_Id> _Hash;
typedef _Hash::Element Element;
public:
Energized(const Type_Id & id): _id(id), _mode(OFF), _link(this, id) {
db<Aspect>(WRN) << "Energized()" << endl;
_devices.insert(&_link);
}
~Energized() {
db<Aspect>(WRN) << "~Energized()" << endl;
_devices.remove(&_link);
}
const Power_Mode & mode() { return _mode; }
Power_Mode mode(const Power_Mode & mode) {
db<Aspect>(WRN) << "Energized::mode()" << endl;
Power_Mode old = _mode;
switch(mode) {
case ENROLL:
// _threaads.insert(Thread::self());
break;
case DISMISS:
// _threaads.remove(Thread::self());
break;
default: // Contest current mode
_mode = mode;
}
return _mode == old ? SAME : _mode;
}
private:
Type_Id _id;
Power_Mode _mode;
// List<void *> _threads;
Element _link;
static _Hash _devices;
};
template<typename Component>
class Energy_Aware
{
protected:
Energy_Aware() {}
public:
static const Power_Mode & power() { return _energized.mode(); }
static Power_Mode power(const Power_Mode & mode) { return _energized.mode(mode); }
private:
static Energized _energized;
};
template<typename Component>
Energized Energy_Aware<Component>::_energized(Type<Component>::ID);
__END_SYS
#endif
// EPOS Component Sharing Control Aspect Program
#ifndef __shared_h
#define __shared_h
#include <system/config.h>
__BEGIN_SYS
template<typename Component>
class Shared
{
protected:
Shared() {}
public:
void enter() { db<Aspect>(TRC) << "Shared::enter()" << endl; }
void leave() { db<Aspect>(TRC) << "Shared::leave()" << endl; }
static void static_enter() { db<Aspect>(TRC) << "Shared::static_enter()" << endl; }
static void static_leave() { db<Aspect>(TRC) << "Shared::static_leave()" << endl; }
};
__END_SYS
#endif
// EPOS Component Framework - Scenario Adapter
// Scenario adapters are the heart of EPOS component framework.
// They collect component-specific Aspect programs to build a scenario for it to run.
// Scenario features are enforced by wrapping all and any method invocation (event creation and destruction)
// within the enter() and leave() methods.
#ifndef __adapter_h
#define __adapter_h
#include "scenario.h"
__BEGIN_SYS
template<typename Component>
class Adapter: public Component, public Scenario<Component>
{
using Scenario<Component>::enter;
using Scenario<Component>::leave;
using Scenario<Component>::static_enter;
using Scenario<Component>::static_leave;
public:
typedef Component _Component; // used by Message
public:
template<typename ... Tn>
Adapter(const Tn & ... an): Component(an ...) { static_leave(); }
~Adapter() { static_enter(); }
void * operator new(size_t bytes) {
static_enter();
return Scenario<Component>::operator new(bytes);
}
void operator delete(void * adapter) {
Scenario<Component>::operator delete(adapter);
static_leave();
}
static const Adapter<Component> * self() { static_enter(); const Adapter<Component> * res = reinterpret_cast<const Adapter<Component> *>(Component::self()); return res; }
// Process management
void suspend() { enter(); Component::suspend(); leave(); }
void resume() { enter(); Component::resume(); leave(); }
int join() { enter(); int res = Component::join(); leave(); return res; }
void pass() { enter(); Component::pass(); leave(); }
static void yield() { static_enter(); Component::yield(); static_leave(); }
static void exit(int status) { static_enter(); Component::exit(status); static_leave(); }
Address_Space * address_space() { enter(); Address_Space * res = Component::address_space(); leave(); return res; }
Segment * code_segment() { enter(); Segment * res = Component::code_segment(); leave(); return res; }
Segment * data_segment() { enter(); Segment * res = Component::data_segment(); leave(); return res; }
CPU::Log_Addr code() { enter(); CPU::Log_Addr res = Component::code(); leave(); return res; }
CPU::Log_Addr data() { enter(); CPU::Log_Addr res = Component::data(); leave(); return res; }
Thread * main() { enter(); Thread * res = Component::main(); leave(); return res; }
// Memory management
CPU::Phy_Addr pd() { enter(); CPU::Phy_Addr res = Component::pd(); leave(); return res; }
CPU::Log_Addr attach(Segment * seg) { enter(); CPU::Log_Addr res = Component::attach(seg); leave(); return res; }
CPU::Log_Addr attach(Segment * seg, const CPU::Log_Addr & addr) { enter(); CPU::Log_Addr res = Component::attach(seg, addr); leave(); return res; }
void detach(Segment * seg) { enter(); Component::detach(seg); leave(); }
void detach(Segment * seg, const CPU::Log_Addr & addr) { enter(); Component::detach(seg, addr); leave(); }
CPU::Phy_Addr physical(const CPU::Log_Addr & addr) { enter(); CPU::Phy_Addr res = Component::physical(addr); leave(); return res; }
unsigned int size() { enter(); unsigned int res = Component::size(); leave(); return res; }
CPU::Phy_Addr phy_address() { enter(); CPU::Phy_Addr res = Component::phy_address(); leave(); return res; }
int resize(int amount) { enter(); int res = Component::resize(amount); leave(); return res; }
// Synchronization
void lock() { enter(); Component::lock(); leave(); }
void unlock() { enter(); Component::unlock(); leave(); }
void p() { enter(); Component::p(); leave(); }
void v() { enter(); Component::v(); leave(); }
void wait() { enter(); Component::wait(); leave(); }
void signal() { enter(); Component::signal(); leave(); }
void broadcast() { enter(); Component::broadcast(); leave(); }
// Timing
static void delay(const Microsecond & time) { static_enter(); Component::delay(time); static_leave(); }
void reset() { enter(); Component::reset(); leave(); }
void start() { enter(); Component::start(); leave(); }
void lap() { enter(); Component::lap(); leave(); }
void stop() { enter(); Component::stop(); leave(); }
int frequency() { enter(); int res = Component::frequency(); leave(); return res; }
int ticks() { enter(); int res = Component::ticks(); leave(); return res; }
int read() { enter(); int res = Component::read(); leave(); return res; }
const Microsecond period() { enter(); Microsecond res = Component::period(); leave(); return res; }
void period(const Microsecond p) { enter(); Component::period(p); leave(); }
static Hertz alarm_frequency() { static_enter(); Hertz res = Component::frequency(); static_leave(); return res; }
// Communication
template<typename ... Tn>
int send(Tn ... an) {
enter();
int res = Component::send(an ...);
leave();
return res;
}
template<typename ... Tn>
int receive(Tn ... an) {
enter();
int res = Component::receive(an ...);
leave();
return res;
}
template<typename ... Tn>
int read(Tn ... an) { return receive(an ...);}
template<typename ... Tn>
int write(Tn ... an) { return send(an ...);}
};
__END_SYS
#endif
// EPOS Component Framework - Component Agent
#ifndef __agent_h
#define __agent_h
#include <process.h>
#include <memory.h>
#include <time.h>
#include <synchronizer.h>
#include "message.h"
__BEGIN_SYS
class Agent: public Message
{
private:
typedef void (Agent:: * Member)();
public:
void exec() {
if(id().type() != UTILITY_ID)
db<Framework>(TRC) << ":=>" << *reinterpret_cast<Message *>(this) << endl;
if(id().type() < LAST_TYPE_ID) // in-kernel services
(this->*_handlers[id().type()])();
// else { // out-of-kernel (i.e. Dom0 or server) services
// db<Framework>(TRC) << "P3" << endl;
// Message msg(*this); // copy message from user space to kernel
// msg.id(Id(IPC_COMMUNICATOR_ID, id().unit()));
// if(IPC::send(&msg)) { // 0 => no one listening
// Port<IPC> * comm = reinterpret_cast<Port<IPC> *>(IPC::observer(id().type())); // recall the Port<IPC> that got us here
// comm->receive(this); // copy from kernel to user
// } else
// result(UNDEFINED);
// }
if(id().type() != UTILITY_ID)
db<Framework>(TRC) << "<=:" << *reinterpret_cast<Message *>(this) << endl;
if(result() == UNDEFINED)
db<Framework>(WRN) << "<=:" << *reinterpret_cast<Message *>(this) << endl;
}
private:
void handle_thread();
void handle_task();
void handle_active();
void handle_address_space();
void handle_segment();
void handle_mutex();
void handle_semaphore();
void handle_condition();
void handle_clock();
void handle_alarm();
void handle_chronometer();
void handle_utility();
private:
static Member _handlers[LAST_TYPE_ID];
};
void Agent::handle_thread()
{
Adapter<Thread> * thread = reinterpret_cast<Adapter<Thread> *>(id().unit());
Result res = 0;
switch(method()) {
case CREATE1:
case CREATE2:
case CREATE3:
case CREATE4:
case CREATE5:
case CREATE6:
case CREATE7:
case CREATE8:
case CREATE9: {
int (*entry)();
in(entry);
id(Id(THREAD_ID, reinterpret_cast<Id::Unit_Id>(new Adapter<Thread>(Thread::Configuration(Thread::READY, Thread::NORMAL, 0, 0), entry))));
} break;
case DESTROY:
delete thread;
break;
case SELF:
id(Id(THREAD_ID, reinterpret_cast<Id::Unit_Id>(Adapter<Thread>::self())));
break;
case THREAD_PRIORITY:
res = thread->priority();
break;
case THREAD_PRIORITY1: {
int p;
in(p);
thread->priority(Thread::Criterion(p));
} break;
case THREAD_JOIN:
res = thread->join();
break;
case THREAD_PASS:
thread->pass();
break;
case THREAD_SUSPEND:
thread->suspend();
break;
case THREAD_RESUME:
thread->resume();
break;
case THREAD_YIELD:
Thread::yield();
break;
case THREAD_WAIT_NEXT:
// Periodic_Thread::wait_next();
break;
case THREAD_EXIT: {
int r;
in(r);
Thread::exit(r);
} break;
default:
res = UNDEFINED;
}
result(res);
};