Merge branch 'ytshih/hw2' into 'main'

Ytshih/hw2

See merge request cs_os_group_20/cs_os_project_20_hw!2
This commit is contained in:
Yi-Ting Shih
2024-11-02 07:58:12 +08:00
24 changed files with 752 additions and 4283 deletions

1
.gitignore vendored
View File

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

View File

@@ -6,8 +6,11 @@ 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 ["bash"]
CMD ["fish"]

View File

@@ -3,12 +3,15 @@
all:
make -C build.linux depend
make -C build.linux
make -C test
make -C build.linux -j 16
make -C test -j 16
clean:
make -C build.linux 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
# you need to call some inline functions from the debugger.
CFLAGS = -g -Wall $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32
LDFLAGS = -m32
CFLAGS = -g -fsanitize=address,undefined -Wall -Wextra $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32
LDFLAGS = -fsanitize=address,undefined -m32
CPP_AS_FLAGS= -m32
#####################################################################

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

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

View File

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

View File

@@ -40,7 +40,8 @@ const int NumPhysPages = 128;
const int MemorySize = (NumPhysPages * PageSize);
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.
PageFaultException, // No valid translation found
ReadOnlyException, // Write attempted to page marked
@@ -52,6 +53,7 @@ enum ExceptionType { NoException, // Everything ok!
// address space
OverflowException, // Integer overflow in add or sub.
IllegalInstrException, // Unimplemented or reserved instr.
MemoryLimitException, // Bad allocation
NumExceptionTypes
};

View File

@@ -208,6 +208,7 @@ Machine::Translate(int virtAddr, int* physAddr, int size, bool writing)
if (tlb == NULL) { // => page table => vpn is index into table
if (vpn >= pageTableSize) {
DEBUG(dbgAddr, "Illegal virtual page # " << virtAddr);
DEBUG(dbgAddr, "vpn, pageTableSize, NumPhysPages: " << vpn << ' ' << pageTableSize << ' ' << NumPhysPages);
return AddressErrorException;
} else if (!pageTable[vpn].valid) {
DEBUG(dbgAddr, "Invalid virtual page # " << virtAddr);
@@ -233,6 +234,13 @@ Machine::Translate(int virtAddr, int* physAddr, int size, bool writing)
return ReadOnlyException;
}
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!
// An invalid translation was loaded into the page table or TLB.

View File

@@ -113,7 +113,7 @@ ifeq ($(hosttype),unknown)
PROGRAMS = unknownhost
else
# 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
endif
@@ -189,6 +189,11 @@ fileIO_test3: fileIO_test3.o start.o
$(LD) $(LDFLAGS) start.o fileIO_test3.o -o fileIO_test3.coff
$(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:
$(RM) -f *.o *.ii
@@ -198,10 +203,11 @@ distclean: clean
$(RM) -f $(PROGRAMS)
run: $(PROGRAMS)
for i in $(PROGRAMS); do \
echo ===== $$i =====; \
$(NACHOS) -e $$i; \
done
timeout 1 $(NACHOS) -e consoleIO_test1 -e consoleIO_test2
echo 'done'
debug: $(PROGRAMS)
timeout 1 $(NACHOS) -e consoleIO_test1 -e consoleIO_test2 -d +
unknownhost:

View File

@@ -4,6 +4,6 @@ int main() {
int n;
for (n = 9; n > 5; n--)
PrintInt(n);
Halt();
return 0;
}

View File

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

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

View File

@@ -63,6 +63,7 @@ class Kernel {
FileSystem *fileSystem;
PostOfficeInput *postOfficeIn;
PostOfficeOutput *postOfficeOut;
FrameTable *frameTable;
int hostName; // machine identifier

View File

@@ -57,6 +57,71 @@ SwapHeader (NoffHeader *noffH)
#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
// Create an address space to run a user program.
@@ -66,20 +131,7 @@ SwapHeader (NoffHeader *noffH)
//----------------------------------------------------------------------
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
@@ -88,7 +140,10 @@ 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
AddrSpace::Load(char *fileName)
{
//cerr << "AddrSpace::Load" << endl;
OpenFile *executable = kernel->fileSystem->Open(fileName);
NoffHeader noffH;
unsigned int size;
@@ -124,6 +180,11 @@ AddrSpace::Load(char *fileName)
// how big is address space?
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
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
// to leave room for the stack
#else
@@ -131,6 +192,10 @@ AddrSpace::Load(char *fileName)
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
+ UserStackSize; // we need to increase the size
// to leave room for the stack
//cerr << noffH.code.size << ' '
// << noffH.initData.size << ' '
// << noffH.uninitData.size << ' '
// << UserStackSize << endl;
#endif
numPages = divRoundUp(size, PageSize);
size = numPages * PageSize;
@@ -140,32 +205,60 @@ AddrSpace::Load(char *fileName)
// at least until we have
// 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);
// then, copy in the code and data segments into memory
// Note: this code assumes that virtual address = physical address
if (noffH.code.size > 0) {
DEBUG(dbgAddr, "Initializing code segment.");
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(
&(kernel->machine->mainMemory[noffH.code.virtualAddr]),
noffH.code.size, noffH.code.inFileAddr);
&(kernel->machine->mainMemory[physAddr]), size,
noffH.code.inFileAddr + cur);
}
}
if (noffH.initData.size > 0) {
DEBUG(dbgAddr, "Initializing data segment.");
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(
&(kernel->machine->mainMemory[noffH.initData.virtualAddr]),
noffH.initData.size, noffH.initData.inFileAddr);
&(kernel->machine->mainMemory[physAddr]), size,
noffH.initData.inFileAddr + cur);
}
}
#ifdef RDATA
if (noffH.readonlyData.size > 0) {
DEBUG(dbgAddr, "Initializing read only data segment.");
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(
&(kernel->machine->mainMemory[noffH.readonlyData.virtualAddr]),
noffH.readonlyData.size, noffH.readonlyData.inFileAddr);
&(kernel->machine->mainMemory[physAddr]),
size, noffH.readonlyData.inFileAddr + cur);
}
}
#endif
@@ -185,7 +278,7 @@ AddrSpace::Load(char *fileName)
void
AddrSpace::Execute(char* fileName)
{
//cerr << "AddrSpace::Execute" << endl;
kernel->currentThread->space = this;
this->InitRegisters(); // set the initial register values
@@ -288,6 +381,13 @@ AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
}
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!
// An invalid translation was loaded into the page table or TLB.
@@ -310,7 +410,3 @@ AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
return NoException;
}

View File

@@ -18,6 +18,28 @@
#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 {
public:
AddrSpace(); // Create an address space.
@@ -40,8 +62,7 @@ class AddrSpace {
ExceptionType Translate(unsigned int vaddr, unsigned int *paddr, int mode);
private:
TranslationEntry *pageTable; // Assume linear page table translation
// for now!
TranslationEntry *pageTable;
unsigned int numPages; // Number of pages in the virtual
// address space