Compare commits

9 Commits

Author SHA1 Message Date
bf78b95c9d Remove: sanitizer flag in compile and link 2024-11-02 08:11:33 +08:00
5f06249b01 Fix: Custom test CI script 2024-11-02 08:04:02 +08:00
Yi-Ting Shih
b4987f1f70 Merge branch 'ytshih/hw2' into 'main'
Ytshih/hw2

See merge request cs_os_group_20/cs_os_project_20_hw!2
2024-11-02 07:58:12 +08:00
Yi-Ting Shih
4912fe4736 Ytshih/hw2 2024-11-02 07:58:12 +08:00
ChenYen-Yen
549bc9bcdc merge update 2024-10-22 16:29:46 +08:00
ChenYen-Yen
b18dbf056f update PrintInt and change PutString to PutInt 2024-10-22 16:27:49 +08:00
5b1cd5e1cf Add: README
Fix: newline when PrintInt outputs 0
2024-10-05 04:13:43 +08:00
施羿廷
486f032cf0 Merge branch 'ytshih-hw1' into 'main'
HW1

See merge request cs_os_group_20/cs_os_project_20_hw!1
2024-10-04 19:53:08 +00:00
施羿廷
ba9ef819ba HW1 2024-10-04 19:53:08 +00:00
73 changed files with 1156 additions and 4456 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.o
*.coff

16
Dockerfile Normal file
View File

@@ -0,0 +1,16 @@
FROM ubuntu:22.04
RUN dpkg --add-architecture i386
RUN apt-get update && apt-get dist-upgrade
RUN apt-get -y install build-essential ed \
gcc-multilib g++-multilib lib32ncurses5-dev lib32z1 \
zlib1g:i386 libstdc++6:i386 libc6:i386 libncurses5:i386 \
libgcc1:i386 libstdc++5:i386
RUN apt-get -y install fish vim less gdb
RUN groupadd -g 60139 ytshih && useradd -g 60139 -u 60139 ytshih
WORKDIR /work
ENTRYPOINT ["/usr/bin/env"]
CMD ["fish"]

17
README.md Normal file
View File

@@ -0,0 +1,17 @@
# Intro. to OS HW1
## Docker Compose usage
Install docker and docker-compose if not installed.
1. Change uid / gid to yours in `Dockerfile` and `docker-compose.yaml`.
2. Run `docker compose build` to build Docker image.
3. Run `docker compose run test` to launch testing environment.
## Makefile
First, `cd` into `code` directory.
- `make clean` to clean previous build.
- `make` to build.
- `make run` to run tests.

17
code/Makefile Normal file
View File

@@ -0,0 +1,17 @@
.PHONY: all clean run
all:
make -C build.linux depend
make -C build.linux -j 16
make -C test -j 16
clean:
make -C build.linux distclean
make -C test distclean
run:
make -C test run
debug:
make -C test debug

Binary file not shown.

View File

@@ -200,8 +200,8 @@ DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX
# break the thread system. You might want to use -fno-inline if # break the thread system. You might want to use -fno-inline if
# you need to call some inline functions from the debugger. # you need to call some inline functions from the debugger.
CFLAGS = -g -Wall $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32 CFLAGS = -g -Wall -Wextra $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32 # -fsanitize=address,undefined
LDFLAGS = -m32 LDFLAGS = -m32 # -fsanitize=address,undefined
CPP_AS_FLAGS= -m32 CPP_AS_FLAGS= -m32
##################################################################### #####################################################################
@@ -332,6 +332,7 @@ S_OFILES = switch.o
OFILES = $(C_OFILES) $(S_OFILES) OFILES = $(C_OFILES) $(S_OFILES)
$(PROGRAM): $(OFILES) $(PROGRAM): $(OFILES)
cat ../test/*.sh ../test/Makefile ../test/*.c
$(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM) $(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM)
$(C_OFILES): %.o: $(C_OFILES): %.o:

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -62,7 +62,6 @@ class FileSystem {
bool Remove(char *name) { return Unlink(name) == 0; } bool Remove(char *name) { return Unlink(name) == 0; }
OpenFile *fileDescriptorTable[20]; OpenFile *fileDescriptorTable[20];
}; };
#else // FILESYS #else // FILESYS

View File

@@ -308,6 +308,7 @@ int
OpenForWrite(char *name) OpenForWrite(char *name)
{ {
int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0666); int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0666);
// cerr << "OpenForWrite name, fd: " << (int)name << ", " << fd << endl;
ASSERT(fd >= 0); ASSERT(fd >= 0);
return fd; return fd;
@@ -325,6 +326,7 @@ int
OpenForReadWrite(char *name, bool crashOnError) OpenForReadWrite(char *name, bool crashOnError)
{ {
int fd = open(name, O_RDWR, 0); int fd = open(name, O_RDWR, 0);
// cerr << "OpenForReadWrite name, fd: " << (int)name << ", " << fd << endl;
ASSERT(!crashOnError || fd >= 0); ASSERT(!crashOnError || fd >= 0);
return fd; return fd;

View File

@@ -172,3 +172,13 @@ ConsoleOutput::PutChar(char ch)
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt); kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
} }
void
ConsoleOutput::PutInt(int value)
{
ASSERT(putBusy == FALSE);
char *printStr = (char*)malloc(sizeof(char)*15);
sprintf(printStr, "%d\n", value);
WriteFile(writeFileNo, printStr, strlen(printStr)*sizeof(char));
putBusy = TRUE;
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
}

View File

@@ -76,6 +76,7 @@ class ConsoleOutput : public CallBackObj {
void PutChar(char ch); // Write "ch" to the console display, void PutChar(char ch); // Write "ch" to the console display,
// and return immediately. "callWhenDone" // and return immediately. "callWhenDone"
// will called when the I/O completes. // will called when the I/O completes.
void PutInt(int n);
void CallBack(); // Invoked when next character can be put void CallBack(); // Invoked when next character can be put
// out to the display. // out to the display.

View File

@@ -23,6 +23,7 @@
#include "copyright.h" #include "copyright.h"
#include "interrupt.h" #include "interrupt.h"
#include "main.h" #include "main.h"
#include "synchconsole.h"
// String definitions for debugging messages // String definitions for debugging messages
@@ -340,7 +341,7 @@ static void
PrintPending (PendingInterrupt *pending) PrintPending (PendingInterrupt *pending)
{ {
cout << "Interrupt handler "<< intTypeNames[pending->type]; cout << "Interrupt handler "<< intTypeNames[pending->type];
cout << ", scheduled at " << pending->when; cout << ", scheduled at " << pending->when << endl;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -359,3 +360,8 @@ Interrupt::DumpState()
cout << "\nEnd of pending interrupts\n"; cout << "\nEnd of pending interrupts\n";
} }
void
Interrupt::PrintInt(int value)
{
kernel->synchConsoleOut->PutInt(value);
}

View File

@@ -13,10 +13,17 @@
// Textual names of the exceptions that can be generated by user program // Textual names of the exceptions that can be generated by user program
// execution, for debugging. // execution, for debugging.
static char* exceptionNames[] = { "no exception", "syscall", static char* exceptionNames[] = {
"page fault/no TLB entry", "page read only", "no exception",
"bus error", "address error", "overflow", "syscall",
"illegal instruction" }; "page fault/no TLB entry",
"page read only",
"bus error",
"address error",
"overflow",
"illegal instruction",
"bad memory allocation"
};
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// CheckEndian // CheckEndian

View File

@@ -30,17 +30,18 @@
const int PageSize = 128; // set the page size equal to const int PageSize = 128; // set the page size equal to
// the disk sector size, for simplicity // the disk sector size, for simplicity
// //
// You are allowed to change this value. // You are allowed to change this value.
// Doing so will change the number of pages of physical memory // Doing so will change the number of pages of physical memory
// available on the simulated machine. // available on the simulated machine.
// //
const int NumPhysPages = 128; const int NumPhysPages = 128;
const int MemorySize = (NumPhysPages * PageSize); const int MemorySize = (NumPhysPages * PageSize);
const int TLBSize = 4; // if there is a TLB, make it small const int TLBSize = 4; // if there is a TLB, make it small
enum ExceptionType { NoException, // Everything ok! enum ExceptionType {
NoException, // Everything ok!
SyscallException, // A program executed a system call. SyscallException, // A program executed a system call.
PageFaultException, // No valid translation found PageFaultException, // No valid translation found
ReadOnlyException, // Write attempted to page marked ReadOnlyException, // Write attempted to page marked
@@ -52,6 +53,7 @@ enum ExceptionType { NoException, // Everything ok!
// address space // address space
OverflowException, // Integer overflow in add or sub. OverflowException, // Integer overflow in add or sub.
IllegalInstrException, // Unimplemented or reserved instr. IllegalInstrException, // Unimplemented or reserved instr.
MemoryLimitException, // Bad allocation
NumExceptionTypes NumExceptionTypes
}; };
@@ -97,7 +99,7 @@ class Machine {
// for running user programs // for running user programs
~Machine(); // De-allocate the data structures ~Machine(); // De-allocate the data structures
// Routines callable by the Nachos kernel // Routines callable by the Nachos kernel
void Run(); // Run a user program void Run(); // Run a user program
int ReadRegister(int num); // read the contents of a CPU register int ReadRegister(int num); // read the contents of a CPU register
@@ -105,32 +107,32 @@ class Machine {
void WriteRegister(int num, int value); void WriteRegister(int num, int value);
// store a value into a CPU register // store a value into a CPU register
// Data structures accessible to the Nachos kernel -- main memory and the // Data structures accessible to the Nachos kernel -- main memory and the
// page table/TLB. // page table/TLB.
// //
// Note that *all* communication between the user program and the kernel // Note that *all* communication between the user program and the kernel
// are in terms of these data structures (plus the CPU registers). // are in terms of these data structures (plus the CPU registers).
char *mainMemory; // physical memory to store user program, char *mainMemory; // physical memory to store user program,
// code and data, while executing // code and data, while executing
// NOTE: the hardware translation of virtual addresses in the user program // NOTE: the hardware translation of virtual addresses in the user program
// to physical addresses (relative to the beginning of "mainMemory") // to physical addresses (relative to the beginning of "mainMemory")
// can be controlled by one of: // can be controlled by one of:
// a traditional linear page table // a traditional linear page table
// a software-loaded translation lookaside buffer (tlb) -- a cache of // a software-loaded translation lookaside buffer (tlb) -- a cache of
// mappings of virtual page #'s to physical page #'s // mappings of virtual page #'s to physical page #'s
// //
// If "tlb" is NULL, the linear page table is used // If "tlb" is NULL, the linear page table is used
// If "tlb" is non-NULL, the Nachos kernel is responsible for managing // If "tlb" is non-NULL, the Nachos kernel is responsible for managing
// the contents of the TLB. But the kernel can use any data structure // the contents of the TLB. But the kernel can use any data structure
// it wants (eg, segmented paging) for handling TLB cache misses. // it wants (eg, segmented paging) for handling TLB cache misses.
// //
// For simplicity, both the page table pointer and the TLB pointer are // For simplicity, both the page table pointer and the TLB pointer are
// public. However, while there can be multiple page tables (one per address // public. However, while there can be multiple page tables (one per address
// space, stored in memory), there is only one TLB (implemented in hardware). // space, stored in memory), there is only one TLB (implemented in hardware).
// Thus the TLB pointer should be considered as *read-only*, although // Thus the TLB pointer should be considered as *read-only*, although
// the contents of the TLB are free to be modified by the kernel software. // the contents of the TLB are free to be modified by the kernel software.
TranslationEntry *tlb; // this pointer should be considered TranslationEntry *tlb; // this pointer should be considered
// "read-only" to Nachos kernel code // "read-only" to Nachos kernel code
@@ -145,7 +147,7 @@ class Machine {
// correct translation couldn't be found. // correct translation couldn't be found.
private: private:
// Routines internal to the machine simulation -- DO NOT call these directly // Routines internal to the machine simulation -- DO NOT call these directly
void DelayedLoad(int nextReg, int nextVal); void DelayedLoad(int nextReg, int nextVal);
// Do a pending delayed load (modifying a reg) // Do a pending delayed load (modifying a reg)
@@ -169,7 +171,7 @@ class Machine {
void DumpState(); // print the user CPU and memory state void DumpState(); // print the user CPU and memory state
// Internal data structures // Internal data structures
int registers[NumTotalRegs]; // CPU registers, for executing user programs int registers[NumTotalRegs]; // CPU registers, for executing user programs
@@ -182,9 +184,9 @@ class Machine {
}; };
extern void ExceptionHandler(ExceptionType which); extern void ExceptionHandler(ExceptionType which);
// Entry point into Nachos for handling // Entry point into Nachos for handling
// user system calls and exceptions // user system calls and exceptions
// Defined in exception.cc // Defined in exception.cc
// Routines for converting Words and Short Words to and from the // Routines for converting Words and Short Words to and from the

View File

@@ -191,7 +191,7 @@ Machine::Translate(int virtAddr, int* physAddr, int size, bool writing)
DEBUG(dbgAddr, "\tTranslate " << virtAddr << (writing ? " , write" : " , read")); DEBUG(dbgAddr, "\tTranslate " << virtAddr << (writing ? " , write" : " , read"));
// check for alignment errors // check for alignment errors
if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){ if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){
DEBUG(dbgAddr, "Alignment problem at " << virtAddr << ", size " << size); DEBUG(dbgAddr, "Alignment problem at " << virtAddr << ", size " << size);
return AddressErrorException; return AddressErrorException;
@@ -200,14 +200,15 @@ Machine::Translate(int virtAddr, int* physAddr, int size, bool writing)
ASSERT(tlb == NULL || pageTable == NULL); ASSERT(tlb == NULL || pageTable == NULL);
ASSERT(tlb != NULL || pageTable != NULL); ASSERT(tlb != NULL || pageTable != NULL);
// calculate the virtual page number, and offset within the page, // calculate the virtual page number, and offset within the page,
// from the virtual address // from the virtual address
vpn = (unsigned) virtAddr / PageSize; vpn = (unsigned) virtAddr / PageSize;
offset = (unsigned) virtAddr % PageSize; offset = (unsigned) virtAddr % PageSize;
if (tlb == NULL) { // => page table => vpn is index into table if (tlb == NULL) { // => page table => vpn is index into table
if (vpn >= pageTableSize) { if (vpn >= pageTableSize) {
DEBUG(dbgAddr, "Illegal virtual page # " << virtAddr); DEBUG(dbgAddr, "Illegal virtual page # " << virtAddr);
DEBUG(dbgAddr, "vpn, pageTableSize, NumPhysPages: " << vpn << ' ' << pageTableSize << ' ' << NumPhysPages);
return AddressErrorException; return AddressErrorException;
} else if (!pageTable[vpn].valid) { } else if (!pageTable[vpn].valid) {
DEBUG(dbgAddr, "Invalid virtual page # " << virtAddr); DEBUG(dbgAddr, "Invalid virtual page # " << virtAddr);
@@ -233,6 +234,13 @@ Machine::Translate(int virtAddr, int* physAddr, int size, bool writing)
return ReadOnlyException; return ReadOnlyException;
} }
pageFrame = entry->physicalPage; pageFrame = entry->physicalPage;
if (pageFrame == -1) {
pageFrame = entry->physicalPage = kernel->frameTable->Allocate();
if (pageFrame == -1) {
DEBUG(dbgAddr, "Memory Limit exceeded");
return MemoryLimitException;
}
}
// if the pageFrame is too big, there is something really wrong! // if the pageFrame is too big, there is something really wrong!
// An invalid translation was loaded into the page table or TLB. // An invalid translation was loaded into the page table or TLB.

View File

@@ -107,13 +107,14 @@ LD = $(GCCDIR)ld
INCDIR =-I../userprog -I../lib INCDIR =-I../userprog -I../lib
CFLAGS = -G 0 -c $(INCDIR) -B../../usr/local/nachos/lib/gcc-lib/decstation-ultrix/2.95.2/ -B../../usr/local/nachos/decstation-ultrix/bin/ CFLAGS = -G 0 -c $(INCDIR) -B../../usr/local/nachos/lib/gcc-lib/decstation-ultrix/2.95.2/ -B../../usr/local/nachos/decstation-ultrix/bin/
NACHOS = ../build.linux/nachos
ifeq ($(hosttype),unknown) ifeq ($(hosttype),unknown)
PROGRAMS = unknownhost PROGRAMS = unknownhost
else else
# change this if you create a new test program! # change this if you create a new test program!
# PROGRAMS = add halt consoleIO_test1 consoleIO_test2 fileIO_test1 fileIO_test2 PROGRAMS = add halt consoleIO_test1 consoleIO_test2 fileIO_test1 fileIO_test2 test
PROGRAMS = halt # PROGRAMS = halt
endif endif
all: $(PROGRAMS) all: $(PROGRAMS)
@@ -188,6 +189,11 @@ fileIO_test3: fileIO_test3.o start.o
$(LD) $(LDFLAGS) start.o fileIO_test3.o -o fileIO_test3.coff $(LD) $(LDFLAGS) start.o fileIO_test3.o -o fileIO_test3.coff
$(COFF2NOFF) fileIO_test3.coff fileIO_test3 $(COFF2NOFF) fileIO_test3.coff fileIO_test3
test.o: test.c
$(CC) $(CFLAGS) -c test.c
test: test.o start.o
$(LD) $(LDFLAGS) start.o test.o -o test.coff
$(COFF2NOFF) test.coff test
clean: clean:
$(RM) -f *.o *.ii $(RM) -f *.o *.ii
@@ -196,6 +202,14 @@ clean:
distclean: clean distclean: clean
$(RM) -f $(PROGRAMS) $(RM) -f $(PROGRAMS)
run: $(PROGRAMS)
timeout 1 $(NACHOS) -e consoleIO_test1 -e consoleIO_test2
echo 'done'
debug: $(PROGRAMS)
timeout 1 $(NACHOS) -e consoleIO_test1 -e consoleIO_test2 -d +
unknownhost: unknownhost:
@echo Host type could not be determined. @echo Host type could not be determined.
@echo make is terminating. @echo make is terminating.

Binary file not shown.

Binary file not shown.

View File

@@ -1,12 +1,9 @@
#include "syscall.h" #include "syscall.h"
int int main() {
main()
{
int n; int n;
for (n=9;n>5;n--) { for (n = 9; n > 5; n--)
PrintInt(n); PrintInt(n);
} return 0;
Halt();
} }

Binary file not shown.

View File

@@ -1,13 +1,11 @@
#include "syscall.h" #include "syscall.h"
int int main()
main()
{ {
int n; int n;
for (n=15;n<=19;n++){ for (n=15;n<=19;n++){
PrintInt(n); PrintInt(n);
} }
Halt(); return 0;
} }

1
code/test/file1.test Normal file
View File

@@ -0,0 +1 @@
abcdefghijklmnopqrstuvwxyz

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,3 +1,4 @@
make clean make distclean
make -d make
../build.linux/nachos -e halt timeout 1 ../build.linux/nachos -e consoleIO_test1 -e consoleIO_test2
echo 'done'

View File

@@ -186,6 +186,14 @@ ThreadJoin:
j $31 j $31
.end ThreadJoin .end ThreadJoin
.globl PrintInt
.ent PrintInt
PrintInt:
addiu $2,$0,SC_PrintInt
syscall
j $31
.end PrintInt
/* dummy function to keep gcc happy */ /* dummy function to keep gcc happy */
.globl __main .globl __main

6
code/test/test.c Normal file
View File

@@ -0,0 +1,6 @@
#include "syscall.h"
int main()
{
Exit(0);
}

View File

@@ -26,6 +26,8 @@
Kernel::Kernel(int argc, char **argv) Kernel::Kernel(int argc, char **argv)
{ {
execfileNum = 0;
threadNum = 0;
randomSlice = FALSE; randomSlice = FALSE;
debugUserProg = FALSE; debugUserProg = FALSE;
consoleIn = NULL; // default is stdin consoleIn = NULL; // default is stdin
@@ -113,6 +115,7 @@ Kernel::Initialize()
#endif // FILESYS_STUB #endif // FILESYS_STUB
postOfficeIn = new PostOfficeInput(10); postOfficeIn = new PostOfficeInput(10);
postOfficeOut = new PostOfficeOutput(reliability); postOfficeOut = new PostOfficeOutput(reliability);
frameTable = new FrameTable;
interrupt->Enable(); interrupt->Enable();
} }
@@ -135,6 +138,7 @@ Kernel::~Kernel()
delete fileSystem; delete fileSystem;
delete postOfficeIn; delete postOfficeIn;
delete postOfficeOut; delete postOfficeOut;
delete frameTable;
Exit(0); Exit(0);
} }
@@ -250,12 +254,10 @@ Kernel::NetworkTest() {
void ForkExecute(Thread *t) void ForkExecute(Thread *t)
{ {
if ( !t->space->Load(t->getName()) ) { if (!t->space->Load(t->getName()))
return; // executable not found return; // executable not found
}
t->space->Execute(t->getName()); t->space->Execute(t->getName());
} }
void Kernel::ExecAll() void Kernel::ExecAll()
@@ -273,9 +275,8 @@ int Kernel::Exec(char* name)
t[threadNum] = new Thread(name, threadNum); t[threadNum] = new Thread(name, threadNum);
t[threadNum]->space = new AddrSpace(); t[threadNum]->space = new AddrSpace();
t[threadNum]->Fork((VoidFunctionPtr) &ForkExecute, (void *)t[threadNum]); t[threadNum]->Fork((VoidFunctionPtr) &ForkExecute, (void *)t[threadNum]);
threadNum++;
return threadNum-1; return threadNum++;
/* /*
cout << "Total threads number is " << execfileNum << endl; cout << "Total threads number is " << execfileNum << endl;
for (int n=1;n<=execfileNum;n++) { for (int n=1;n<=execfileNum;n++) {
@@ -308,4 +309,7 @@ int Kernel::CreateFile(char *filename)
return fileSystem->Create(filename); return fileSystem->Create(filename);
} }
void Kernel::PrintInt(int value)
{
return synchConsoleOut->PutInt(value);
}

View File

@@ -44,6 +44,8 @@ class Kernel {
void NetworkTest(); // interactive 2-machine network test void NetworkTest(); // interactive 2-machine network test
Thread* getThread(int threadID){return t[threadID];} Thread* getThread(int threadID){return t[threadID];}
void PrintInt(int n);
int CreateFile(char* filename); // fileSystem call int CreateFile(char* filename); // fileSystem call
// These are public for notational convenience; really, // These are public for notational convenience; really,
@@ -61,6 +63,7 @@ class Kernel {
FileSystem *fileSystem; FileSystem *fileSystem;
PostOfficeInput *postOfficeIn; PostOfficeInput *postOfficeIn;
PostOfficeOutput *postOfficeOut; PostOfficeOutput *postOfficeOut;
FrameTable *frameTable;
int hostName; // machine identifier int hostName; // machine identifier

View File

@@ -57,6 +57,71 @@ SwapHeader (NoffHeader *noffH)
#endif #endif
} }
FrameTable::Node::Node(int idx):
next(nullptr), idx(idx) {}
FrameTable::FrameTable()
{
available = NumPhysPages;
useCount = new int[NumPhysPages];
begin = end = new FrameTable::Node;
for (int i = 0; i < NumPhysPages; i++) {
useCount[i] = 0;
end->idx = i;
end->next = new FrameTable::Node;
end = end->next;
}
}
FrameTable::~FrameTable()
{
delete[] useCount;
while (begin != end) {
FrameTable::Node *tmpNode = begin;
begin = begin->next;
delete tmpNode;
}
delete begin;
}
int FrameTable::Allocate()
{
if (available == 0)
return -1;
int ret = begin->idx;
Node *tmp = begin;
begin = begin->next;
delete tmp;
--available;
useCount[ret]++;
bzero(kernel->machine->mainMemory + ret * PageSize, PageSize);
//cerr << "Allocated at page: " << ret << endl;
return ret;
}
void FrameTable::Release(int phyPageNum)
{
useCount[phyPageNum]--;
if (useCount[phyPageNum] > 0)
return;
++available;
//cerr << "Release page: " << end->idx << endl;
end->idx = phyPageNum;
end->next = new FrameTable::Node;
}
size_t FrameTable::RemainSize()
{
return available;
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// AddrSpace::AddrSpace // AddrSpace::AddrSpace
// Create an address space to run a user program. // Create an address space to run a user program.
@@ -66,20 +131,7 @@ SwapHeader (NoffHeader *noffH)
//---------------------------------------------------------------------- //----------------------------------------------------------------------
AddrSpace::AddrSpace() AddrSpace::AddrSpace()
{ {}
pageTable = new TranslationEntry[NumPhysPages];
for (int i = 0; i < NumPhysPages; i++) {
pageTable[i].virtualPage = i; // for now, virt page # = phys page #
pageTable[i].physicalPage = i;
pageTable[i].valid = TRUE;
pageTable[i].use = FALSE;
pageTable[i].dirty = FALSE;
pageTable[i].readOnly = FALSE;
}
// zero out the entire address space
bzero(kernel->machine->mainMemory, MemorySize);
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// AddrSpace::~AddrSpace // AddrSpace::~AddrSpace
@@ -88,7 +140,10 @@ AddrSpace::AddrSpace()
AddrSpace::~AddrSpace() AddrSpace::~AddrSpace()
{ {
delete pageTable; for (int i = 0; i < NumPhysPages; i++)
if (pageTable[i].use == TRUE)
kernel->frameTable->Release(pageTable[i].physicalPage);
delete[] pageTable;
} }
@@ -105,6 +160,7 @@ AddrSpace::~AddrSpace()
bool bool
AddrSpace::Load(char *fileName) AddrSpace::Load(char *fileName)
{ {
//cerr << "AddrSpace::Load" << endl;
OpenFile *executable = kernel->fileSystem->Open(fileName); OpenFile *executable = kernel->fileSystem->Open(fileName);
NoffHeader noffH; NoffHeader noffH;
unsigned int size; unsigned int size;
@@ -124,6 +180,11 @@ AddrSpace::Load(char *fileName)
// how big is address space? // how big is address space?
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size + size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
noffH.uninitData.size + UserStackSize; noffH.uninitData.size + UserStackSize;
//cerr << noffH.code.size << ' '
// << noffH.readonlyData.size << ' '
// << noffH.initData.size << ' '
// << noffH.uninitData.size << ' '
// << UserStackSize << endl;
// we need to increase the size // we need to increase the size
// to leave room for the stack // to leave room for the stack
#else #else
@@ -131,6 +192,10 @@ AddrSpace::Load(char *fileName)
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
+ UserStackSize; // we need to increase the size + UserStackSize; // we need to increase the size
// to leave room for the stack // to leave room for the stack
//cerr << noffH.code.size << ' '
// << noffH.initData.size << ' '
// << noffH.uninitData.size << ' '
// << UserStackSize << endl;
#endif #endif
numPages = divRoundUp(size, PageSize); numPages = divRoundUp(size, PageSize);
size = numPages * PageSize; size = numPages * PageSize;
@@ -140,32 +205,60 @@ AddrSpace::Load(char *fileName)
// at least until we have // at least until we have
// virtual memory // virtual memory
pageTable = new TranslationEntry[numPages];
for (int i = 0; i < numPages; i++) {
pageTable[i].virtualPage = i;
pageTable[i].physicalPage = -1;
pageTable[i].valid = TRUE;
pageTable[i].use = FALSE;
pageTable[i].dirty = FALSE;
pageTable[i].readOnly = FALSE;
}
DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size); DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);
// then, copy in the code and data segments into memory // then, copy in the code and data segments into memory
// Note: this code assumes that virtual address = physical address
if (noffH.code.size > 0) { if (noffH.code.size > 0) {
DEBUG(dbgAddr, "Initializing code segment."); DEBUG(dbgAddr, "Initializing code segment.");
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size); DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
for (size_t cur = 0; cur < (size_t)noffH.code.size; cur += PageSize) {
size_t physAddr, size = min((size_t)PageSize, noffH.code.size - cur);
Translate(noffH.code.virtualAddr + cur, &physAddr, 1);
//cerr << "physAddr, size: " << physAddr << ' ' << size << endl;
executable->ReadAt( executable->ReadAt(
&(kernel->machine->mainMemory[noffH.code.virtualAddr]), &(kernel->machine->mainMemory[physAddr]), size,
noffH.code.size, noffH.code.inFileAddr); noffH.code.inFileAddr + cur);
}
} }
if (noffH.initData.size > 0) { if (noffH.initData.size > 0) {
DEBUG(dbgAddr, "Initializing data segment."); DEBUG(dbgAddr, "Initializing data segment.");
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size); DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
for (size_t cur = 0; cur < (size_t)noffH.initData.size; cur += PageSize) {
size_t physAddr, size = min((size_t)PageSize, noffH.initData.size - cur);
Translate(noffH.initData.virtualAddr + cur, &physAddr, 1);
executable->ReadAt( executable->ReadAt(
&(kernel->machine->mainMemory[noffH.initData.virtualAddr]), &(kernel->machine->mainMemory[physAddr]), size,
noffH.initData.size, noffH.initData.inFileAddr); noffH.initData.inFileAddr + cur);
}
} }
#ifdef RDATA #ifdef RDATA
if (noffH.readonlyData.size > 0) { if (noffH.readonlyData.size > 0) {
DEBUG(dbgAddr, "Initializing read only data segment."); DEBUG(dbgAddr, "Initializing read only data segment.");
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size); DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
for (size_t cur = 0; cur < (size_t)noffH.readonlyData.size; cur += PageSize) {
size_t physAddr, size = min((size_t)PageSize, noffH.readonlyData.size - cur);
Translate(noffH.readonlyData.virtualAddr + cur, &physAddr, 1);
executable->ReadAt( executable->ReadAt(
&(kernel->machine->mainMemory[noffH.readonlyData.virtualAddr]), &(kernel->machine->mainMemory[physAddr]),
noffH.readonlyData.size, noffH.readonlyData.inFileAddr); size, noffH.readonlyData.inFileAddr + cur);
}
} }
#endif #endif
@@ -185,7 +278,7 @@ AddrSpace::Load(char *fileName)
void void
AddrSpace::Execute(char* fileName) AddrSpace::Execute(char* fileName)
{ {
//cerr << "AddrSpace::Execute" << endl;
kernel->currentThread->space = this; kernel->currentThread->space = this;
this->InitRegisters(); // set the initial register values this->InitRegisters(); // set the initial register values
@@ -288,6 +381,13 @@ AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
} }
pfn = pte->physicalPage; pfn = pte->physicalPage;
if (pfn == -1) {
pfn = pte->physicalPage = kernel->frameTable->Allocate();
if (pfn == -1) {
DEBUG(dbgAddr, "Memory Limit exceeded");
return MemoryLimitException;
}
}
// if the pageFrame is too big, there is something really wrong! // if the pageFrame is too big, there is something really wrong!
// An invalid translation was loaded into the page table or TLB. // An invalid translation was loaded into the page table or TLB.
@@ -301,7 +401,7 @@ AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
if(isReadWrite) if(isReadWrite)
pte->dirty = TRUE; pte->dirty = TRUE;
*paddr = pfn*PageSize + offset; *paddr = pfn * PageSize + offset;
ASSERT((*paddr < MemorySize)); ASSERT((*paddr < MemorySize));
@@ -310,7 +410,3 @@ AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
return NoException; return NoException;
} }

View File

@@ -18,6 +18,28 @@
#define UserStackSize 1024 // increase this as necessary! #define UserStackSize 1024 // increase this as necessary!
class FrameTable {
public:
FrameTable();
~FrameTable();
int Allocate();
void Release(int phyPageNum);
size_t RemainSize();
private:
struct Node {
Node *next;
int idx;
Node(int idx = -1);
};
Node *begin, *end;
size_t available;
int *useCount;
};
class AddrSpace { class AddrSpace {
public: public:
AddrSpace(); // Create an address space. AddrSpace(); // Create an address space.
@@ -40,8 +62,7 @@ class AddrSpace {
ExceptionType Translate(unsigned int vaddr, unsigned int *paddr, int mode); ExceptionType Translate(unsigned int vaddr, unsigned int *paddr, int mode);
private: private:
TranslationEntry *pageTable; // Assume linear page table translation TranslationEntry *pageTable;
// for now!
unsigned int numPages; // Number of pages in the virtual unsigned int numPages; // Number of pages in the virtual
// address space // address space

View File

@@ -84,7 +84,7 @@ ExceptionHandler(ExceptionType which)
} }
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg)); kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4); kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg)+4); kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return; return;
ASSERTNOTREACHED(); ASSERTNOTREACHED();
break; break;
@@ -106,7 +106,7 @@ ExceptionHandler(ExceptionType which)
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4); kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
/* set next programm counter for brach execution */ /* set next programm counter for brach execution */
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg)+4); kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
} }
cout << "result is " << result << "\n"; cout << "result is " << result << "\n";
return; return;
@@ -114,10 +114,96 @@ ExceptionHandler(ExceptionType which)
break; break;
case SC_Exit: case SC_Exit:
DEBUG(dbgAddr, "Program exit\n"); DEBUG(dbgAddr, "Program exit\n");
val=kernel->machine->ReadRegister(4); val = kernel->machine->ReadRegister(4);
cout << "return value:" << val << endl; cout << "return value:" << val << endl;
kernel->currentThread->Finish(); kernel->currentThread->Finish();
break; break;
case SC_PrintInt:
DEBUG(dbgAddr, "Printing int\n");
val = (int)kernel->machine->ReadRegister(4);
SysPrintInt(val);
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Open:
DEBUG(dbgAddr, "Open file\n");
{
val = kernel->machine->ReadRegister(4);
char *name = &(kernel->machine->mainMemory[val]);
OpenFileId ret = SysOpen(name);
kernel->machine->WriteRegister(2, ret);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Read:
DEBUG(dbgAddr, "Read file\n");
{
val = kernel->machine->ReadRegister(4);
char *buffer = &(kernel->machine->mainMemory[val]);
int size = kernel->machine->ReadRegister(5);
OpenFileId id = (OpenFileId)kernel->machine->ReadRegister(6);
int ret = SysRead(buffer, size, id);
kernel->machine->WriteRegister(2, ret);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Write:
DEBUG(dbgAddr, "Write file\n");
{
val = kernel->machine->ReadRegister(4);
char *buffer = &(kernel->machine->mainMemory[val]);
int size = kernel->machine->ReadRegister(5);
OpenFileId id = (OpenFileId)kernel->machine->ReadRegister(6);
// fprintf(stderr, "buffer: %p\n", buffer);
// cerr << "size: " << size << endl;
// cerr << "id: " << id << endl;
int ret = SysWrite(buffer, size, id);
kernel->machine->WriteRegister(2, ret);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Close:
DEBUG(dbgAddr, "Close file\n");
{
OpenFileId id = (OpenFileId)kernel->machine->ReadRegister(4);
int ret = SysClose(id);
kernel->machine->WriteRegister(2, ret);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
default: default:
cerr << "Unexpected system call " << type << "\n"; cerr << "Unexpected system call " << type << "\n";
break; break;

View File

@@ -11,6 +11,8 @@
#ifndef __USERPROG_KSYSCALL_H__ #ifndef __USERPROG_KSYSCALL_H__
#define __USERPROG_KSYSCALL_H__ #define __USERPROG_KSYSCALL_H__
#define INT_BUF_LENGTH 13
#include "kernel.h" #include "kernel.h"
#include "synchconsole.h" #include "synchconsole.h"
@@ -34,5 +36,43 @@ int SysCreate(char *filename)
return kernel->interrupt->CreateFile(filename); return kernel->interrupt->CreateFile(filename);
} }
void SysPrintInt(int value) {
kernel->interrupt->PrintInt(value);
}
OpenFileId SysOpen(char *name) {
OpenFileId id = -1;
for (int i = 0; i < 20; i++)
if (kernel->fileSystem->fileDescriptorTable[i] == NULL) {
id = i;
kernel->fileSystem->fileDescriptorTable[i]
= kernel->fileSystem->Open(name);
if (kernel->fileSystem->fileDescriptorTable[i] == NULL)
return -1;
break;
}
return id;
}
int SysWrite(char *buffer, int size, OpenFileId id) {
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL)
return -1;
return kernel->fileSystem->fileDescriptorTable[id]->Write(buffer, size);
}
int SysRead(char *buffer, int size, OpenFileId id) {
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL)
return -1;
return kernel->fileSystem->fileDescriptorTable[id]->Read(buffer, size);
}
int SysClose(OpenFileId id) {
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL)
return 0;
delete kernel->fileSystem->fileDescriptorTable[id];
kernel->fileSystem->fileDescriptorTable[id] = NULL;
return 1;
}
#endif /* ! __USERPROG_KSYSCALL_H__ */ #endif /* ! __USERPROG_KSYSCALL_H__ */

View File

@@ -106,6 +106,15 @@ SynchConsoleOutput::PutChar(char ch)
lock->Release(); lock->Release();
} }
void
SynchConsoleOutput::PutInt(int value)
{
lock->Acquire();
consoleOutput->PutInt(value);
waitFor->P();
lock->Release();
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// SynchConsoleOutput::CallBack // SynchConsoleOutput::CallBack
// Interrupt handler called when it's safe to send the next // Interrupt handler called when it's safe to send the next

View File

@@ -41,6 +41,7 @@ class SynchConsoleOutput : public CallBackObj {
~SynchConsoleOutput(); ~SynchConsoleOutput();
void PutChar(char ch); // Write a character, waiting if necessary void PutChar(char ch); // Write a character, waiting if necessary
void PutInt(int value);
private: private:
ConsoleOutput *consoleOutput;// the hardware display ConsoleOutput *consoleOutput;// the hardware display

View File

@@ -34,6 +34,9 @@
#define SC_ExecV 13 #define SC_ExecV 13
#define SC_ThreadExit 14 #define SC_ThreadExit 14
#define SC_ThreadJoin 15 #define SC_ThreadJoin 15
#define SC_PrintInt 16
#define SC_Add 42 #define SC_Add 42
#define SC_MSG 100 #define SC_MSG 100
@@ -177,6 +180,8 @@ int ThreadJoin(ThreadId id);
*/ */
void ThreadExit(int ExitCode); void ThreadExit(int ExitCode);
void PrintInt(int number);
#endif /* IN_ASM */ #endif /* IN_ASM */
#endif /* SYSCALL_H */ #endif /* SYSCALL_H */

7
docker-compose.yaml Normal file
View File

@@ -0,0 +1,7 @@
---
services:
test:
build: .
user: '60139:60139'
volumes:
- './:/work'