XV6 Project
XV6 Project
XV6 Project
BACHELOR OF TECHNOLOGY
Branch: Computer Science and Engineering
NOVEMBER 2020
1 What is XV6?
2 SRS
3 Data Flow Diagrams
4 Modules Description
5 Codes with output
6 Conclusion
WHAT IS XV6?
Xv6 is a re-implementation of the Unix sixth edition in order to use as a learning tool.
xv6 was developed by MIT as a teaching operating system for their “6.828” course. A
vital fact about xv6 is that it contains all the core Unix concepts and has a similar
structure to Unix even though it lacks some functionality that you would expect from
a modern operating system. This is a lightweight operating system where the time to
compile is very low and it also allow remote debugging. The source code of xv6 can
be cloned to your machine as follows :
1 Introduction
1.1 Purpose
1.2 Scope
With the decrease in the number of people actually learning to work with the base
OS like XV6 due to its lack of functionality even for educational purposes. We took it
upon ourselves to create a Shell in XV6 with all the functionalities which we think is
absolutely necessary for us someone to use it properly without any problem.
The system focuses on improving the already existing open source XV6-public OS
distribution by MIT on GitHub and use create the basic shell functionalities like
Copying, Moving and Editing files and also to display all running process. This
means we create a basic working Editor and add extra functionalities into it while
at the same time implementing all missing common Linux commands.
2 General Requirements
Basic XV6 – use the MIT XV6 as a base code and make it run
Copy – Implement a copy function to copy files from one location to
another
Move – enable moving a file from one location to another using the
function
Head – display first 10 lines of any file
Tail – Display last 10 lines of any file
Editor – Create a basic editor to create and modify files
Process Display – display all running process
3 Functional Requirements
6 Performance Requirements
7 References
TABLE DESCRIPTIONS
Main Memory
The RAM and HDD/SSD parts of an OS where all data is finally stored. It
does not lose any data even when the OS enters a panic state or is shut down. It
has a logical memory address or physical memory address. The RAM houses all
files which are for immediate access while the HDD/SSD houses the rest.
Buffers
The buffers are streams or intermediate storages that house all data for
display or modification. The stream 2 is connected straight to the output terminal
and is used for displaying in the Terminal. The other streams are used to carry
around information and commands from all devices and the CPU.
Structures
This Data Store stores all necessary structures required for functioning of a
CPU. This table has predefined structures and cannot be modified unless the
change is done directly to the source code. This data store houses the structures
of Process Statistics or File Structures and is used for initiation of all core
functionalities of a system.
Level 1 DFD
Level 2 DFD
MODULES DESCRIPTION
Editor
Syntax: editor file1 or bedit file1 mode
Mandatory Parameters: file1
This module is used to open a basic editor that can be used to create a new file or
view and modify an existing file. The editor can be used to insert, modify or delete
a particular line. It can also be used to insert a huge block of text. The editor can
also be used to add lines at end of the file. The editor displays the number of lines
at each line and that can be used to specify after which line you need to insert or
modify. When invoked, the editor goes to fetch the filename and if its non-
existent, it then goes on to create a file of the given name. It then prints the
whole text along with line numbers and then shows all possible options to choose
from and execute. At the end, you can choose to exit with or without saving all
changes.
Shell
A Shell provides you with an interface to the Unix system. It gathers input from
you and executes programs based on that input. When a program finishes
executing, it displays that program's output. Shell is an environment in which we
can run our commands, programs, and shell scripts. There are different flavors of
a shell, just as there are different flavors of operating systems. Each flavor of shell
has its own set of recognized commands and functions.
Shell Prompt
The prompt, $, which is called the command prompt, is
issued by the shell. While the prompt is displayed, you can type a command. Shell
reads your input after you press Enter. It determines the command you want
executed by looking at the first word of your input. A word is an unbroken set of
characters. Spaces and tabs separate words.
Change Directory (CD)
Syntax: cd [OPTIONS] directory
Code :
// Shell.
#include "types.h"
#include "user.h"
#include "fcntl.h"
#define MAXARGS 10
struct cmd {
int type;
};
struct execcmd {
int type;
char *argv[MAXARGS];
char *eargv[MAXARGS];
};
struct redircmd {
int type;
struct cmd *cmd;
char *file;
char *efile;
int mode;
int fd;
};
struct pipecmd {
int type;
struct cmd *left;
struct cmd *right;
};
struct listcmd {
int type;
struct cmd *left;
struct cmd *right;
};
struct backcmd {
int type;
struct cmd *cmd;
};
if(cmd == 0)
exit();
switch(cmd->type){
default:
panic("runcmd");
case EXEC:
ecmd = (struct execcmd*)cmd;
if(ecmd->argv[0] == 0)
exit();
exec(ecmd->argv[0], ecmd->argv);
printf(2, "exec %s failed\n", ecmd->argv[0]);
break;
case REDIR:
rcmd = (struct redircmd*)cmd;
close(rcmd->fd);
if(open(rcmd->file, rcmd->mode) < 0){
printf(2, "open %s failed\n", rcmd->file);
exit();
}
runcmd(rcmd->cmd);
break;
case LIST:
lcmd = (struct listcmd*)cmd;
if(fork1() == 0)
runcmd(lcmd->left);
wait();
runcmd(lcmd->right);
break;
case PIPE:
pcmd = (struct pipecmd*)cmd;
if(pipe(p) < 0)
panic("pipe");
if(fork1() == 0){
close(1);
dup(p[1]);
close(p[0]);
close(p[1]);
runcmd(pcmd->left);
}
if(fork1() == 0){
close(0);
dup(p[0]);
close(p[0]);
close(p[1]);
runcmd(pcmd->right);
}
close(p[0]);
close(p[1]);
wait();
wait();
break;
case BACK:
bcmd = (struct backcmd*)cmd;
if(fork1() == 0)
runcmd(bcmd->cmd);
break;
}
exit();
}
int
getcmd(char *buf, int nbuf)
{
printf(2, "$ ");
memset(buf, 0, nbuf);
gets(buf, nbuf);
if(buf[0] == 0) // EOF
return -1;
return 0;
}
int
main(void)
{
static char buf[100],bufx[100];
int fd;
int
fork1(void)
{
int pid;
pid = fork();
if(pid == -1)
panic("fork");
return pid;
}
//PAGEBREAK!
// Constructors
struct cmd*
execcmd(void)
{
struct execcmd *cmd;
cmd = malloc(sizeof(*cmd));
memset(cmd, 0, sizeof(*cmd));
cmd->type = EXEC;
return (struct cmd*)cmd;
}
struct cmd*
redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
{
struct redircmd *cmd;
cmd = malloc(sizeof(*cmd));
memset(cmd, 0, sizeof(*cmd));
cmd->type = REDIR;
cmd->cmd = subcmd;
cmd->file = file;
cmd->efile = efile;
cmd->mode = mode;
cmd->fd = fd;
return (struct cmd*)cmd;
}
struct cmd*
pipecmd(struct cmd *left, struct cmd *right)
{
struct pipecmd *cmd;
cmd = malloc(sizeof(*cmd));
memset(cmd, 0, sizeof(*cmd));
cmd->type = PIPE;
cmd->left = left;
cmd->right = right;
return (struct cmd*)cmd;
}
struct cmd*
listcmd(struct cmd *left, struct cmd *right)
{
struct listcmd *cmd;
cmd = malloc(sizeof(*cmd));
memset(cmd, 0, sizeof(*cmd));
cmd->type = LIST;
cmd->left = left;
cmd->right = right;
return (struct cmd*)cmd;
}
struct cmd*
backcmd(struct cmd *subcmd)
{
struct backcmd *cmd;
cmd = malloc(sizeof(*cmd));
memset(cmd, 0, sizeof(*cmd));
cmd->type = BACK;
cmd->cmd = subcmd;
return (struct cmd*)cmd;
}
//PAGEBREAK!
// Parsing
int
gettoken(char **ps, char *es, char **q, char **eq)
{
char *s;
int ret;
s = *ps;
while(s < es && strchr(whitespace, *s))
s++;
if(q)
*q = s;
ret = *s;
switch(*s){
case 0:
break;
case '|':
case '(':
case ')':
case ';':
case '&':
case '<':
s++;
break;
case '>':
s++;
if(*s == '>'){
ret = '+';
s++;
}
break;
default:
ret = 'a';
while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
s++;
break;
}
if(eq)
*eq = s;
int
peek(char **ps, char *es, char *toks)
{
char *s;
s = *ps;
while(s < es && strchr(whitespace, *s))
s++;
*ps = s;
return *s && strchr(toks, *s);
}
struct cmd*
parsecmd(char *s)
{
char *es;
struct cmd *cmd;
es = s + strlen(s);
cmd = parseline(&s, es);
peek(&s, es, "");
if(s != es){
printf(2, "leftovers: %s\n", s);
panic("syntax");
}
nulterminate(cmd);
return cmd;
}
struct cmd*
parseline(char **ps, char *es)
{
struct cmd *cmd;
struct cmd*
parsepipe(char **ps, char *es)
{
struct cmd *cmd;
struct cmd*
parseredirs(struct cmd *cmd, char **ps, char *es)
{
int tok;
char *q, *eq;
struct cmd*
parseblock(char **ps, char *es)
{
struct cmd *cmd;
struct cmd*
parseexec(char **ps, char *es)
{
char *q, *eq;
int tok, argc;
struct execcmd *cmd;
struct cmd *ret;
ret = execcmd();
cmd = (struct execcmd*)ret;
argc = 0;
ret = parseredirs(ret, ps, es);
while(!peek(ps, es, "|)&;")){
if((tok=gettoken(ps, es, &q, &eq)) == 0)
break;
if(tok != 'a')
panic("syntax");
cmd->argv[argc] = q;
cmd->eargv[argc] = eq;
argc++;
if(argc >= MAXARGS)
panic("too many args");
ret = parseredirs(ret, ps, es);
}
cmd->argv[argc] = 0;
cmd->eargv[argc] = 0;
return ret;
}
switch(cmd->type){
case EXEC:
ecmd = (struct execcmd*)cmd;
for(i=0; ecmd->argv[i]; i++)
*ecmd->eargv[i] = 0;
break;
case REDIR:
rcmd = (struct redircmd*)cmd;
nulterminate(rcmd->cmd);
*rcmd->efile = 0;
break;
case PIPE:
pcmd = (struct pipecmd*)cmd;
nulterminate(pcmd->left);
nulterminate(pcmd->right);
break;
case LIST:
lcmd = (struct listcmd*)cmd;
nulterminate(lcmd->left);
nulterminate(lcmd->right);
break;
case BACK:
bcmd = (struct backcmd*)cmd;
nulterminate(bcmd->cmd);
break;
}
return cmd;
}
Output :
Editor.c
Code :
#include "types.h"
#include "stat.h"
#include "user.h"
#include "fcntl.h"
#include "fs.h"
#define BUF_SIZE 256
#define MAX_LINE_NUMBER 256
#define MAX_LINE_LENGTH 256
#define NULL 0
char* strcat_n(char* dest, char* src, int len);
int get_line_number(char *text[]);
void show_text(char *text[]);
void com_ins(char *text[], int n, char *extra);
void com_mod(char *text[], int n, char *extra);
void com_del(char *text[], int n);
void com_help(char *text[]);
void com_save(char *text[], char *path);
void com_exit(char *text[], char *path);
int stringtonumber(char* src);
//???????
int changed = 0;
int auto_show = 1;
int main(int argc, char *argv[])
{
//setProgramStatus(EDITOR);
if (argc == 1)
{
printf(1, "please input the command as [editor file_name]\n");
//setProgramStatus(SHELL);
exit();
}
//??????
char *text[MAX_LINE_NUMBER] = {};
text[0] = malloc(MAX_LINE_LENGTH);
memset(text[0], 0, MAX_LINE_LENGTH);
//?????????,?0?????line_number == x,??text[0]?text[x]??
int line_number = 0;
//??????
int fd = open(argv[1], O_RDONLY);
//??????,???????????
if (fd != -1)
{
printf(1, "file exist\n");
char buf[BUF_SIZE] = {};
int len = 0;
while ((len = read(fd, buf, BUF_SIZE)) > 0)
{
int i = 0;
int next = 0;
int is_full = 0;
while (i < len)
{
//??"\n"?????
for (i = next; i < len && buf[i] != '\n'; i++)
;
strcat_n(text[line_number], buf+next, i-next);
//???????
if (i < len && buf[i] == '\n')
{
if (line_number >= MAX_LINE_NUMBER - 1)
is_full = 1;
else
{
line_number++;
text[line_number] = malloc(MAX_LINE_LENGTH);
memset(text[line_number], 0, MAX_LINE_LENGTH);
}
}
if (is_full == 1 || i >= len - 1)
break;
else
next = i + 1;
}
if (is_full == 1)
break;
}
close(fd);
} else{
printf(1,"File do not exist\n");
exit();
}
//??????
show_text(text);
//????
com_help(text);
//????
char input[MAX_LINE_LENGTH] = {};
while (1)
{
printf(1, "\nplease input command:\n");
memset(input, 0, MAX_LINE_LENGTH);
gets(input, MAX_LINE_LENGTH);
int len = strlen(input);
input[len-1] = '\0';
len --;
//??????????
int pos = MAX_LINE_LENGTH - 1;
int j = 0;
for (; j < 8; j++)
{
if (input[j] == ' ')
{
pos = j + 1;
break;
}
}
//ins
if (input[0] == 'i' && input[1] == 'n' && input[2] == 's')
{
if (input[3] == '-'&&stringtonumber(&input[4])>=0)
{
com_ins(text, stringtonumber(&input[4]), &input[pos]);
//??????????
line_number = get_line_number(text);
}
else if(input[3] == ' '||input[3] == '\0')
{
com_ins(text, line_number+1, &input[pos]);
line_number = get_line_number(text);
}
else
{
printf(1, "invalid command.\n");
com_help(text);
}
}
//mod
else if (input[0] == 'm' && input[1] == 'o' && input[2] == 'd')
{
if (input[3] == '-'&&stringtonumber(&input[4])>=0)
com_mod(text, atoi(&input[4]), &input[pos]);
else if(input[3] == ' '||input[3] == '\0')
com_mod(text, line_number + 1, &input[pos]);
else
{
printf(1, "invalid command.\n");
com_help(text);
}
}
//del
else if (input[0] == 'd' && input[1] == 'e' && input[2] == 'l')
{
if (input[3] == '-'&&stringtonumber(&input[4])>=0)
{
com_del(text, atoi(&input[4]));
//??????????
line_number = get_line_number(text);
}
else if(input[3]=='\0')
{
com_del(text, line_number + 1);
line_number = get_line_number(text);
}
else
{
printf(1, "invalid command.\n");
com_help(text);
}
}
else if (strcmp(input, "show") == 0)
{
auto_show = 1;
printf(1, "enable show current contents after text changed.\n");
}
else if (strcmp(input, "hide") == 0)
{
auto_show = 0;
printf(1, "disable show current contents after text changed.\n");
}
else if (strcmp(input, "help") == 0)
com_help(text);
else if (strcmp(input, "save") == 0 || strcmp(input, "CTRL+S\n") == 0)
com_save(text, argv[1]);
else if (strcmp(input, "exit") == 0)
com_exit(text, argv[1]);
else
{
printf(1, "invalid command.\n");
com_help(text);
}
}
//setProgramStatus(SHELL);
exit();
}
//??src??n????dest
char* strcat_n(char* dest, char* src, int len)
{
if (len <= 0)
return dest;
int pos = strlen(dest);
if (len + pos >= MAX_LINE_LENGTH)
return dest;
int i = 0;
for (; i < len; i++)
dest[i+pos] = src[i];
dest[len+pos] = '\0';
return dest;
}
void show_text(char *text[])
{
printf(1, "****************************************\n");
printf(1, "the contents of the file are:\n");
int j = 0;
for (; text[j] != NULL; j++)
printf(1, "%d%d%d:%s\n", (j+1)/100, ((j+1)%100)/10, (j+1)%10, text[j]);
}
//?????????,?0??,?return x??text[0]?text[x]??
int get_line_number(char *text[])
{
int i = 0;
for (; i < MAX_LINE_NUMBER; i++)
if (text[i] == NULL)
return i - 1;
return i - 1;
}
int stringtonumber(char* src)
{
int number = 0;
int i=0;
int pos = strlen(src);
for(;i<pos;i++)
{
if(src[i]==' ') break;
if(src[i]>57||src[i]<48) return -1;
number=10*number+(src[i]-48);
}
return number;
}
//????,n????????,?1??
//extra:??????????,????????
void com_ins(char *text[], int n, char *extra)
{
if (n < 0 || n > get_line_number(text) + 1)
{
printf(1, "invalid line number\n");
return;
}
char input[MAX_LINE_LENGTH] = {};
if (*extra == '\0')
{
printf(1, "please input content:\n");
gets(input, MAX_LINE_LENGTH);
input[strlen(input)-1] = '\0';
}
else
strcpy(input, extra);
int i = MAX_LINE_NUMBER - 1;
for (; i > n; i--)
{
if (text[i-1] == NULL)
continue;
else if (text[i] == NULL && text[i-1] != NULL)
{
text[i] = malloc(MAX_LINE_LENGTH);
memset(text[i], 0, MAX_LINE_LENGTH);
strcpy(text[i], text[i-1]);
}
else if (text[i] != NULL && text[i-1] != NULL)
{
memset(text[i], 0, MAX_LINE_LENGTH);
strcpy(text[i], text[i-1]);
}
}
if (text[n] == NULL)
{
text[n] = malloc(MAX_LINE_LENGTH);
if (text[n-1][0] == '\0')
{
memset(text[n], 0, MAX_LINE_LENGTH);
strcpy(text[n-1], input);
changed = 1;
if (auto_show == 1)
show_text(text);
return;
}
}
memset(text[n], 0, MAX_LINE_LENGTH);
strcpy(text[n], input);
changed = 1;
if (auto_show == 1)
show_text(text);
}
//????,n????????,?1??
//extra:??????????,?????????
void com_mod(char *text[], int n, char *extra)
{
if (n <= 0 || n > get_line_number(text) + 1)
{
printf(1, "invalid line number\n");
return;
}
char input[MAX_LINE_LENGTH] = {};
if (*extra == '\0')
{
printf(1, "please input content:\n");
gets(input, MAX_LINE_LENGTH);
input[strlen(input)-1] = '\0';
}
else
strcpy(input, extra);
memset(text[n-1], 0, MAX_LINE_LENGTH);
strcpy(text[n-1], input);
changed = 1;
if (auto_show == 1)
show_text(text);
}
//????,n????????,?1??
void com_del(char *text[], int n)
{
if (n <= 0 || n > get_line_number(text) + 1)
{
printf(1, "invalid line number\n");
return;
}
memset(text[n-1], 0, MAX_LINE_LENGTH);
int i = n - 1;
for (; text[i+1] != NULL; i++)
{
strcpy(text[i], text[i+1]);
memset(text[i+1], 0, MAX_LINE_LENGTH);
}
if (i != 0)
{
free(text[i]);
text[i] = 0;
}
changed = 1;
if (auto_show == 1)
show_text(text);
}
void com_help(char *text[])
{
printf(1, "****************************************\n");
printf(1, "instructions for use:\n");
printf(1, "ins-n, insert a line after line n\n");
printf(1, "mod-n, modify line n\n");
printf(1, "del-n, delete line n\n");
printf(1, "ins, insert a line after the last line\n");
printf(1, "mod, modify the last line\n");
printf(1, "del, delete the last line\n");
printf(1, "show, enable show current contents after executing a command.\n");
printf(1, "hide, disable show current contents after executing a command.\n");
printf(1, "save, save the file\n");
printf(1, "exit, exit editor\n");
}
void com_save(char *text[], char *path)
{
//??????
unlink(path);
//???????
int fd = open(path, O_WRONLY|O_CREATE);
if (fd == -1)
{
printf(1, "save failed, file can't open:\n");
//setProgramStatus(SHELL);
exit();
}
if (text[0] == NULL)
{
close(fd);
return;
}
//???
write(fd, text[0], strlen(text[0]));
int i = 1;
for (; text[i] != NULL; i++)
{
printf(fd, "\n");
write(fd, text[i], strlen(text[i]));
}
close(fd);
printf(1, "saved successfully\n");
changed = 0;
return;
}
void com_exit(char *text[], char *path)
{
//??????
while (changed == 1)
{
printf(1, "save the file? y/n\n");
char input[MAX_LINE_LENGTH] = {};
gets(input, MAX_LINE_LENGTH);
input[strlen(input)-1] = '\0';
if (strcmp(input, "y") == 0)
com_save(text, path);
else if(strcmp(input, "n") == 0)
break;
else
printf(2, "wrong answer?\n");
}
//????
int i = 0;
for (; text[i] != NULL; i++)
{
free(text[i]);
text[i] = 0;
}
//??
//setProgramStatus(SHELL);
exit();
}
Output:
cd
code:
#include "types.h"
#include "stat.h"
#include "user.h"
Output :
chpr
Code :
Adding Chpr into system calls like syscall.c, syscall.h, user.h, usys.S, defs.h, proc.c,
sysproc.c and adding ps, dpro, nice codes
Output:
IN NEXT PAGE
VM.C
Code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define PSIZE 4096
int main(int argc, char *argv[])
{
int addressFile,backingStore;
char *file= argv[1];
char ch,ct, input[1000], output;
int logicalAddress, physicalAddress;
int i=0, j=0;
int p,d;
int f;
char frames[PSIZE*16];
int frametable[16];
int start, current;
int offset, pagefault=0;
int freeFrame=-1;
int pagetable[16];
for (j=0;j<16;j++)
{
pagetable[j] = -1;
}
pagetable[0]=0x2;
pagetable[1]=0x1;
pagetable[2]=0x6;
pagetable[3]=0x0;
pagetable[4]=0x4;
pagetable[5]=0x3;
pagetable[9]=0x5;
pagetable[11]=0x7;
for (j=0;j<16;j++)
{
frametable[j] = -1;
}
frametable[0] = 1;
frametable[1] = 1;
frametable[2] = 1;
frametable[3] = 1;
frametable[4] = 1;
frametable[5] = 1;
frametable[9] = 1;
frametable[11] = 1;
addressFile = open("address.txt",O_RDONLY);
backingStore = open("BACKING_STORE.bin",O_RDONLY);
if(addressFile != -1)
{
while(read(addressFile, &ch, sizeof(char)) != 0)
{
if(ch != '\n')
{
input[i] = ch;
i++;
}
else
{
logicalAddress =atoi(input);
p = (logicalAddress & 0x000000000000f000UL) >> 12;
d = (logicalAddress & 0x0000000000000fffUL);
f = pagetable[p];
physicalAddress = (f * PSIZE) + d;
printf("\nphysicalAddress: %d, f: %d",
physicalAddress,f);
}
// pagetable-miss, page-fault
else
{
pagefault++;
// locate free frame (-1) in physical memory
for (j=0;j<8;j++)
{
if(frametable[j]==-1)
{
freeFrame = j;
break;
}
}
if(backingStore != -1)
{
offset=0;
start = PSIZE * p;
current=lseek(backingStore, start,
SEEK_SET);
while((offset < PSIZE)&&(current))
{
current = read(backingStore, &ct,
sizeof(char));
frames[freeFrame*offset] = ct;
offset++;
}
}
else
{
printf("Backing-Store Does not exist!");
close(backingStore);
close(addressFile);
return 0;
}
// update pagetable, frametable
pagetable[p] = freeFrame;
frametable[freeFrame] = 0;
output = frames[physicalAddress];
printf("\nByte value stored at physicalAddress %d: %c\
n",physicalAddress, output);
memset(input,0,sizeof(input));
i=0;
}
}
printf("\nTotal Page Faults: %d",pagefault);
}
else
printf("Addresses File Does not exist!");
close(backingStore);
close(addressFile);
return 0;
}
Output:
CONCLUSION
We successfully created a basic XV6 shell with what our team believes to be
necessary for a common usage. We learnt a lot from working with a basic
Operating System and would like to thank everyone for this opportunity. The
journey to modifying the XV6 and implementing our own shell was a very
interesting and eventful one and even though sometimes, our code was like a
shot in the dark, we believe that we achieved what we wanted to in the end.