0% found this document useful (0 votes)
87 views

Fork Assingnment

The document contains code for the kernel of an operating system. It includes function definitions for kernel initialization, process setup, exception handling, and system calls. Key functions include kernel_start() to initialize hardware and processes, process_setup() to load processes into memory, and syscall handlers like syscall_read() and syscall_write() for I/O.

Uploaded by

khadija
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
87 views

Fork Assingnment

The document contains code for the kernel of an operating system. It includes function definitions for kernel initialization, process setup, exception handling, and system calls. Key functions include kernel_start() to initialize hardware and processes, process_setup() to load processes into memory, and syscall handlers like syscall_read() and syscall_write() for I/O.

Uploaded by

khadija
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODT, PDF, TXT or read online on Scribd
You are on page 1/ 15

Problem set 1

khadija 023-17-0042
sumra 051-18-0009

Coding
#include "kernel.hh"
#include "k-ahci.hh"
#include "k-apic.hh"
#include "k-chkfs.hh"
#include "k-chkfsiter.hh"
#include "k-devices.hh"
#include "k-vmiter.hh"

#ifndef CHICKADEE_FIRST_PROCESS
#define CHICKADEE_FIRST_PROCESS "allocator"
#endif

// kernel.cc
//
// This is the kernel.

volatile unsigned long ticks; // # timer interrupts so far on CPU 0


int kdisplay; // type of display; initially
KDISPLAY_CONSOLE

static void kdisplay_ontick();


static void process_setup(pid_t pid, const char* program_name =
nullptr);

// kernel_start(command)
// Initialize the hardware and processes and start running. The
`command`
// string is an optional string passed from the boot loader.

void kernel_start(const char* command) {


init_hardware();
console_clear();

// Set up process descriptors


for (pid_t i = 0; i < NPROC; i++) {
ptable[i] = nullptr;
}

auto irqs = ptable_lock.lock();


process_setup(1, CHICKADEE_FIRST_PROCESS);
ptable_lock.unlock(irqs);

// Switch to the first process


cpus[0].schedule(nullptr);
}

// process_setup(pid, name)
// Load application program `name` as process number `pid`.
// This loads the application's code and data into memory, sets its
// %rip and %rsp, gives it a stack page, and marks it as runnable.

void process_setup(pid_t pid, const char* name) {


memfile_loader ld(memfile::initfs_lookup(name),
kalloc_pagetable());
assert(ld.memfile_ && ld.pagetable_);
int r = proc::load(ld);
assert(r >= 0);

assert(!ptable[pid]);
proc* p = ptable[pid] = knew<proc>();
p->init_user(pid, ld.pagetable_);
p->regs_->reg_rip = ld.entry_rip_;

void* stkpg = kalloc(PAGESIZE);


assert(stkpg);
r = vmiter(p, MEMSIZE_VIRTUAL -
PAGESIZE).map(ka2pa(stkpg));
assert(r >= 0);
p->regs_->reg_rsp = MEMSIZE_VIRTUAL;

int cpu = pid % ncpu;


cpus[cpu].runq_lock_.lock_noirq();
cpus[cpu].enqueue(p);
cpus[cpu].runq_lock_.unlock_noirq();
}

// proc::exception(reg)
// Exception handler (for interrupts, traps, and faults).
//
// The register values from exception time are stored in `reg`.
// The processor responds to an exception by saving application
state on
// the current CPU stack, then jumping to kernel assembly code
(in
// k-exception.S). That code transfers the state to the current
kernel
// task's stack, then calls proc::exception().

void proc::exception(regstate* regs) {


// It can be useful to log events using `log_printf`.
// Events logged this way are stored in the host's `log.txt` file.
/*log_printf("proc %d: exception %d\n", this->id_, regs-
>reg_intno);*/

// Show the current cursor location.


console_show_cursor(cursorpos);

// Actually handle the exception.


switch (regs->reg_intno) {

case INT_IRQ + IRQ_TIMER: {


cpustate* cpu = this_cpu();
if (cpu->index_ == 0) {
++ticks;
kdisplay_ontick();
}
lapicstate::get().ack();
this->regs_ = regs;
this->yield_noreturn();
break; /* will not be reached */
}

case INT_PF: { // pagefault exception


// Analyze faulting address and access type.
uintptr_t addr = rdcr2();
const char* operation = regs->reg_errcode &
PFERR_WRITE
? "write" : "read";
const char* problem = regs->reg_errcode &
PFERR_PRESENT
? "protection problem" : "missing page";

if ((regs->reg_cs & 5) == 0) {
panic("Kernel page fault for %p (%s %s, rip=%p)!\n",
addr, operation, problem, regs->reg_rip);
}
error_printf(CPOS(24, 0), 0x0C00,
"Process %d page fault for %p (%s %s, rip=%p)!\n",
id_, addr, operation, problem, regs->reg_rip);
this->state_ = proc::broken;
this->yield();
break;
}

case INT_IRQ + IRQ_KEYBOARD:


keyboardstate::get().handle_interrupt();
break;

default:
if (sata_disk && regs->reg_intno == INT_IRQ + sata_disk-
>irq_) {
sata_disk->handle_interrupt();
} else {
panic("Unexpected exception %d!\n", regs->reg_intno);
}
break; /* will not be reached */

// Return to the current process.


// If exception arrived in user mode, the process must be
runnable.
assert((regs->reg_cs & 3) == 0 || this->state_ ==
proc::runnable);
}

// proc::syscall(regs)
// System call handler.
//
// The register values from system call time are stored in `regs`.
// The return value from `proc::syscall()` is returned to the user
// process in `%rax`.
uintptr_t proc::syscall(regstate* regs) {
switch (regs->reg_rax) {

case SYSCALL_KDISPLAY:
if (kdisplay != (int) regs->reg_rdi) {
console_clear();
}
kdisplay = regs->reg_rdi;
return 0;

case SYSCALL_PANIC:
panic(nullptr);
break; // will not be reached

case SYSCALL_GETPID:
return id_;

case SYSCALL_YIELD:
this->yield();
return 0;

case SYSCALL_PAGE_ALLOC: {
uintptr_t addr = regs->reg_rdi;
if (addr >= VA_LOWEND || addr & 0xFFF) {
return -1;
}
void* pg = kalloc(PAGESIZE);
if (!pg || vmiter(this, addr).map(ka2pa(pg)) < 0) {
return -1;
}
return 0;
}

case SYSCALL_PAUSE: {
sti();
for (uintptr_t delay = 0; delay < 1000000; ++delay) {
pause();
}
cli();
return 0;
}

case SYSCALL_FORK:

return syscall_fork(regs);

case SYSCALL_READ:
return syscall_read(regs);

case SYSCALL_WRITE:
return syscall_write(regs);

case SYSCALL_READDISKFILE:
return syscall_readdiskfile(regs);

case SYSCALL_SYNC: {
int drop = regs->reg_rdi;
// `drop > 1` asserts that no data blocks are referenced (except
// possibly superblock and FBB blocks). This can only be
ensured on
// tests that run as the first process.
if (drop > 1 && strncmp(CHICKADEE_FIRST_PROCESS,
"test", 4) != 0) {
drop = 1;
}
return bufcache::get().sync(drop);
}

default:
// no such system call
log_printf("%d: no such system call %u\n", id_, regs-
>reg_rax);
return E_NOSYS;

}
}

// proc::syscall_read(regs), proc::syscall_write(regs)
// Handle read and write system calls.

uintptr_t proc::syscall_read(regstate* regs) {


int fd = regs->reg_rdi;
uintptr_t addr = regs->reg_rsi;
size_t sz = regs->reg_rdx;

auto& kbd = keyboardstate::get();


auto irqs = kbd.lock_.lock();

// mark that we are now reading from the keyboard


// (so `q` should not power off)
if (kbd.state_ == kbd.boot) {
kbd.state_ = kbd.input;
}

// yield until a line is available


// (special case: do not block if the user wants to read 0 bytes)
while (sz != 0 && kbd.eol_ == 0) {
kbd.lock_.unlock(irqs);
yield();
irqs = kbd.lock_.lock();
}

// read that line or lines


size_t n = 0;
while (kbd.eol_ != 0 && n < sz) {
if (kbd.buf_[kbd.pos_] == 0x04) {
// Ctrl-D means EOF
if (n == 0) {
kbd.consume(1);
}
break;
} else {
*reinterpret_cast<char*>(addr) = kbd.buf_[kbd.pos_];
++addr;
++n;
kbd.consume(1);
}
}

kbd.lock_.unlock(irqs);
return n;
}

uintptr_t proc::syscall_write(regstate* regs){


int fd = regs->reg_rdi;
uintptr_t addr = regs->reg_rsi;
size_t sz = regs->reg_rdx;
auto& csl = consolestate::get();
auto irqs = csl.lock_.lock();
size_t n = 0;
while (n < sz) {
int ch = *reinterpret_cast<const char*>(addr);
++addr;
++n;
console_printf(0x0F00, "%c", ch);
}
csl.lock_.unlock(irqs);
return n;
}
uintptr_t proc::syscall_fork(regstate* regs){
// auto irqs=ptable_lock.lock();
pid_t cp = SYSCALL_GETPID;
proc* par = current();

pid_t pid = 1;
for(;pid<NPROC;pid++){
if(ptable[pid] == nullptr){
break;
}
else if(pid == 15)
return -1;
}

// Set up process descriptors

auto irqs = ptable_lock.lock();


pid_t i = 0;
for (; i < NPROC; i++) {
if(ptable[i] = nullptr)
{
break;
}
}

process_setup(i, CHICKADEE_FIRST_PROCESS);
ptable_lock.unlock(irqs);

proc* p = knew<proc>();
ptable[pid] = p;
ptable[pid]->pagetable_ = kalloc_pagetable();
memfile_loader ld(pid, p->pagetable_);
p->init_user(pid,ld.pagetable_);
memcpy(p->regs_,par->regs_,sizeof(regs_));
p->regs_->reg_rax=0;

ptable[pid]->regs_->reg_rip = regs->reg_rip;
//p->regs_->reg_rip =regs->entry_rip_;
memcpy(&p->regs_->reg_rcx,&ptable[cp]->regs_-
>reg_rcx,sizeof(regs));
void* stkpg = kalloc(PAGESIZE);
assert(stkpg);
int r = proc::load(ld);
r = vmiter(p, MEMSIZE_VIRTUAL -
PAGESIZE).map(ka2pa(stkpg));
assert(r >= 0);
p->regs_->reg_rsp = MEMSIZE_VIRTUAL;

//scehdualling
int cpu = pid % ncpu;
cpus[cpu].runq_lock_.lock_noirq();
cpus[cpu].enqueue(ptable[pid]);
cpus[cpu].runq_lock_.unlock_noirq();
ptable_lock.unlock(irqs);

return pid++;

uintptr_t proc::syscall_readdiskfile(regstate* regs){


const char* filename = reinterpret_cast<const char*>(regs-
>reg_rdi);
unsigned char* buf = reinterpret_cast<unsigned char*>(regs-
>reg_rsi);
uintptr_t sz = regs->reg_rdx;
uintptr_t off = regs->reg_r10;
if (!sata_disk) {
return E_IO;
}

// read root directory to find file inode number


auto ino = chkfsstate::get().lookup_inode(filename);
if (!ino) {
return 0;//E_NOENT;
}

// read file inode


ino->lock_read();
chkfs_fileiter it(ino);

size_t nread = 0;
while (nread < sz) {
// copy data from current block
if (bcentry* e = it.find(off).get_disk_entry()) {
unsigned b = it.block_relative_offset();
size_t ncopy = min(
size_t(ino->size - it.offset()), // bytes left in file
chkfs::blocksize - b, // bytes left in block
sz - nread // bytes left in request
);
memcpy(buf + nread, e->buf_ + b, ncopy);
e->put();

nread += ncopy;
off += ncopy;
if (ncopy == 0) {
break;
}
} else {
break;
}
}

ino->unlock_read();
ino->put();
return 0;//nread;
}
// memshow()
// Draw a picture of memory (physical and virtual) on the CGA
console.
// Switches to a new process's virtual memory map every 0.25
sec.
// Uses `console_memviewer()`, a function defined in `k-
memviewer.cc`.

static void memshow() {


static unsigned last_ticks = 0;
static int showing = 1;

// switch to a new process every 0.25 sec


if (last_ticks == 0 || ticks - last_ticks >= HZ / 2) {
last_ticks = ticks;
showing = (showing + 1) % NPROC;
}

auto irqs = ptable_lock.lock();

int search = 0;
while ((!ptable[showing]
|| !ptable[showing]->pagetable_
|| ptable[showing]->pagetable_ == early_pagetable)
&& search < NPROC) {
showing = (showing + 1) % NPROC;
++search;
}
extern void console_memviewer(proc* vmp);
console_memviewer(ptable[showing]);

ptable_lock.unlock(irqs);
}

// kdisplay_ontick()
// Shows the currently-configured kdisplay. Called once every
tick
// (every 0.01 sec) by CPU 0.

void kdisplay_ontick() {
if (kdisplay == KDISPLAY_MEMVIEWER) {
memshow();
}
}
Result:

You might also like