Initial git commit of legacy userland including some extras but excluding others, based on latest version in my fossil repository with the LICENSE clarified.
This commit is contained in:
parent
e25e8d1043
commit
de71bc79e4
25
LICENSE
Normal file
25
LICENSE
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
Files marked NEW CODE can be attributed just to Zak's copyright with the same license, other files will either have their own information or are to be taken under the full license including the xv6 copyright statement:
|
||||||
|
|
||||||
|
Copyright (c) 2024, 2025 Zak Yani Star Fenton
|
||||||
|
Copyright (c) 2006-2024 Frans Kaashoek, Robert Morris, Russ Cox,
|
||||||
|
Massachusetts Institute of Technology
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
43
cat.c
Normal file
43
cat.c
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/fcntl.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
void
|
||||||
|
cat(int fd)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
while((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||||
|
if (write(1, buf, n) != n) {
|
||||||
|
fprintf(2, "cat: write error\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(n < 0){
|
||||||
|
fprintf(2, "cat: read error\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd, i;
|
||||||
|
|
||||||
|
if(argc <= 1){
|
||||||
|
cat(0);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 1; i < argc; i++){
|
||||||
|
if((fd = open(argv[i], O_RDONLY)) < 0){
|
||||||
|
fprintf(2, "cat: cannot open %s\n", argv[i]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
cat(fd);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
81
drives.c
Normal file
81
drives.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// This is NEW CODE to demonstrate the drvinf syscall by printing convenient
|
||||||
|
// information about drives to the console.
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../kernel/syscdefs.h"
|
||||||
|
|
||||||
|
#define DRIVE_SEARCH_MAX 1000
|
||||||
|
|
||||||
|
// Inline definition of the syscall
|
||||||
|
int drvinf(int drivenumber, struct __syscdefs_driveinfo* structure);
|
||||||
|
|
||||||
|
#define SIZEOUTPUTLENGTH 40
|
||||||
|
#define KB 1024ULL
|
||||||
|
#define MB (KB*1024)
|
||||||
|
#define GB (MB*1024)
|
||||||
|
#define TB (GB*1024)
|
||||||
|
|
||||||
|
void formatsizevalue(char* output, long long value) {
|
||||||
|
int ntb = value/TB;
|
||||||
|
value -= ntb*TB;
|
||||||
|
int ngb = value/GB;
|
||||||
|
value -= ngb*GB;
|
||||||
|
int nmb = value/MB;
|
||||||
|
value -= nmb*MB;
|
||||||
|
int nkb = value/KB;
|
||||||
|
value -= nkb*KB;
|
||||||
|
int nb = (int) value; // The remainder is any leftover bytes
|
||||||
|
if (ntb > 0) {
|
||||||
|
if (nb > 0) {
|
||||||
|
snprintf(output, SIZEOUTPUTLENGTH, "%dTB %dGB %dMB %dKB %d bytes", ntb, ngb, nmb, nkb, nb);
|
||||||
|
} else {
|
||||||
|
snprintf(output, SIZEOUTPUTLENGTH, "%dTB %dGB %dMB %dKB", ntb, ngb, nmb, nkb);
|
||||||
|
}
|
||||||
|
} else if (ngb > 0) {
|
||||||
|
if (nb > 0) {
|
||||||
|
snprintf(output, SIZEOUTPUTLENGTH, "%dGB %dMB %dKB %d bytes", ngb, nmb, nkb, nb);
|
||||||
|
} else {
|
||||||
|
snprintf(output, SIZEOUTPUTLENGTH, "%dGB %dMB %dKB", ngb, nmb, nkb);
|
||||||
|
}
|
||||||
|
} else if (nmb > 0) {
|
||||||
|
if (nb > 0) {
|
||||||
|
snprintf(output, SIZEOUTPUTLENGTH, "%dMB %dKB %d bytes", nmb, nkb, nb);
|
||||||
|
} else {
|
||||||
|
snprintf(output, SIZEOUTPUTLENGTH, "%dMB %dKB", nmb, nkb);
|
||||||
|
}
|
||||||
|
} else if (nkb > 0) {
|
||||||
|
if (nb > 0) {
|
||||||
|
snprintf(output, SIZEOUTPUTLENGTH, "%dKB %d bytes", nkb, nb);
|
||||||
|
} else {
|
||||||
|
snprintf(output, SIZEOUTPUTLENGTH, "%dKB", nkb);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
snprintf(output, SIZEOUTPUTLENGTH, "%d bytes", nb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char totalbuf[SIZEOUTPUTLENGTH];
|
||||||
|
char freebuf[SIZEOUTPUTLENGTH];
|
||||||
|
|
||||||
|
void printinfo(struct __syscdefs_driveinfo* info) {
|
||||||
|
//printf("[#%d] %s: %d * %lld, %lld free [%s]\n", info->drivenumber, info->name, info->blocksize, info->totalblocks, info->freedatablocks, info->fsname);
|
||||||
|
|
||||||
|
formatsizevalue(totalbuf, info->blocksize * info->totalblocks);
|
||||||
|
formatsizevalue(freebuf, info->blocksize * info->freedatablocks);
|
||||||
|
printf("[#%d] %s:\t%s total\t%s free\t[%s]\n", info->drivenumber, info->name, totalbuf, freebuf, info->fsname);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
struct __syscdefs_driveinfo info;
|
||||||
|
//int isfirst = 1;
|
||||||
|
for (int i = 0; i < DRIVE_SEARCH_MAX; i++) {
|
||||||
|
int result = drvinf(i, &info);
|
||||||
|
if (result >= 0) {
|
||||||
|
/*if (isfirst) {
|
||||||
|
isfirst = 0;
|
||||||
|
} else {
|
||||||
|
printf("\n");
|
||||||
|
}*/
|
||||||
|
printinfo(&info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
echo.c
Normal file
19
echo.c
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 1; i < argc; i++){
|
||||||
|
write(1, argv[i], strlen(argv[i]));
|
||||||
|
if(i + 1 < argc){
|
||||||
|
write(1, " ", 1);
|
||||||
|
} else {
|
||||||
|
write(1, "\n", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
94
forktest.c
Normal file
94
forktest.c
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// Test that fork fails gracefully.
|
||||||
|
// Tiny executable so that the limit can be filling the proc table.
|
||||||
|
|
||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
|
||||||
|
// N should be set HIGHER than the limit!
|
||||||
|
#define N 10000
|
||||||
|
|
||||||
|
void
|
||||||
|
print(const char *s)
|
||||||
|
{
|
||||||
|
write(1, s, strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
void printdec(unsigned int i) {
|
||||||
|
if (i == 0) {
|
||||||
|
print("0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char foo[11];
|
||||||
|
int idx = 10;
|
||||||
|
while (i > 0) {
|
||||||
|
idx--;
|
||||||
|
foo[idx] = '0' + (i%10);
|
||||||
|
i /= 10;
|
||||||
|
}
|
||||||
|
foo[10] = 0;
|
||||||
|
print(foo+idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
forktest(void)
|
||||||
|
{
|
||||||
|
int n, pid;
|
||||||
|
|
||||||
|
print("fork test\n");
|
||||||
|
|
||||||
|
//print("testing printdec(12345)="); printdec(12345); print("\n");
|
||||||
|
print("attempting to fork up to N="); printdec(N); print(" processes...\n");
|
||||||
|
|
||||||
|
for(n=0; n<N; n++){
|
||||||
|
pid = fork();
|
||||||
|
if(pid < 0)
|
||||||
|
break;
|
||||||
|
if (pid == 0) {
|
||||||
|
int i, j, ch, pr;
|
||||||
|
pr = 7-(getpid() % 4);
|
||||||
|
ch = '0'+pr;
|
||||||
|
prio(getpid(), pr, 4);
|
||||||
|
sleep(1);
|
||||||
|
for (i = 0; i < 100; i++) {
|
||||||
|
for (j = 0; j < 256; j++) {
|
||||||
|
ch++;
|
||||||
|
}
|
||||||
|
char str[2];
|
||||||
|
str[0] = (char)ch;
|
||||||
|
str[1] = 0;
|
||||||
|
print(str);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
print("forked "); printdec(n); print(" processes\n");
|
||||||
|
|
||||||
|
if(n == N){
|
||||||
|
print("fork claimed to work N times! forktest should be updated so N is greater than the kernel's NPROC!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(; n > 0; n--){
|
||||||
|
if(wait(0) < 0){
|
||||||
|
print("wait stopped early\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wait(0) != -1){
|
||||||
|
print("wait got too many\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
print("fork test OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
forktest();
|
||||||
|
exit(0);
|
||||||
|
}
|
107
grep.c
Normal file
107
grep.c
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// Simple grep. Only supports ^ . * $ operators.
|
||||||
|
|
||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "kernel/fcntl.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
|
||||||
|
char buf[1024];
|
||||||
|
int match(char*, char*);
|
||||||
|
|
||||||
|
void
|
||||||
|
grep(char *pattern, int fd)
|
||||||
|
{
|
||||||
|
int n, m;
|
||||||
|
char *p, *q;
|
||||||
|
|
||||||
|
m = 0;
|
||||||
|
while((n = read(fd, buf+m, sizeof(buf)-m-1)) > 0){
|
||||||
|
m += n;
|
||||||
|
buf[m] = '\0';
|
||||||
|
p = buf;
|
||||||
|
while((q = strchr(p, '\n')) != 0){
|
||||||
|
*q = 0;
|
||||||
|
if(match(pattern, p)){
|
||||||
|
*q = '\n';
|
||||||
|
write(1, p, q+1 - p);
|
||||||
|
}
|
||||||
|
p = q+1;
|
||||||
|
}
|
||||||
|
if(m > 0){
|
||||||
|
m -= p - buf;
|
||||||
|
memmove(buf, p, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd, i;
|
||||||
|
char *pattern;
|
||||||
|
|
||||||
|
if(argc <= 1){
|
||||||
|
fprintf(2, "usage: grep pattern [file ...]\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
pattern = argv[1];
|
||||||
|
|
||||||
|
if(argc <= 2){
|
||||||
|
grep(pattern, 0);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 2; i < argc; i++){
|
||||||
|
if((fd = open(argv[i], O_RDONLY)) < 0){
|
||||||
|
printf("grep: cannot open %s\n", argv[i]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
grep(pattern, fd);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regexp matcher from Kernighan & Pike,
|
||||||
|
// The Practice of Programming, Chapter 9, or
|
||||||
|
// https://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html
|
||||||
|
|
||||||
|
int matchhere(char*, char*);
|
||||||
|
int matchstar(int, char*, char*);
|
||||||
|
|
||||||
|
int
|
||||||
|
match(char *re, char *text)
|
||||||
|
{
|
||||||
|
if(re[0] == '^')
|
||||||
|
return matchhere(re+1, text);
|
||||||
|
do{ // must look at empty string
|
||||||
|
if(matchhere(re, text))
|
||||||
|
return 1;
|
||||||
|
}while(*text++ != '\0');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchhere: search for re at beginning of text
|
||||||
|
int matchhere(char *re, char *text)
|
||||||
|
{
|
||||||
|
if(re[0] == '\0')
|
||||||
|
return 1;
|
||||||
|
if(re[1] == '*')
|
||||||
|
return matchstar(re[0], re+2, text);
|
||||||
|
if(re[0] == '$' && re[1] == '\0')
|
||||||
|
return *text == '\0';
|
||||||
|
if(*text!='\0' && (re[0]=='.' || re[0]==*text))
|
||||||
|
return matchhere(re+1, text+1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchstar: search for c*re at beginning of text
|
||||||
|
int matchstar(int c, char *re, char *text)
|
||||||
|
{
|
||||||
|
do{ // a * matches zero or more instances
|
||||||
|
if(matchhere(re, text))
|
||||||
|
return 1;
|
||||||
|
}while(*text!='\0' && (*text++==c || c=='.'));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
351
grind.c
Normal file
351
grind.c
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
//
|
||||||
|
// run random system calls in parallel forever.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "kernel/param.h"
|
||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
#include "kernel/fs.h"
|
||||||
|
#include "kernel/fcntl.h"
|
||||||
|
#include "kernel/syscall.h"
|
||||||
|
#include "kernel/memlayout.h"
|
||||||
|
#include "kernel/riscv.h"
|
||||||
|
|
||||||
|
// from FreeBSD.
|
||||||
|
int
|
||||||
|
do_rand(unsigned long *ctx)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Compute x = (7^5 * x) mod (2^31 - 1)
|
||||||
|
* without overflowing 31 bits:
|
||||||
|
* (2^31 - 1) = 127773 * (7^5) + 2836
|
||||||
|
* From "Random number generators: good ones are hard to find",
|
||||||
|
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
|
||||||
|
* October 1988, p. 1195.
|
||||||
|
*/
|
||||||
|
long hi, lo, x;
|
||||||
|
|
||||||
|
/* Transform to [1, 0x7ffffffe] range. */
|
||||||
|
x = (*ctx % 0x7ffffffe) + 1;
|
||||||
|
hi = x / 127773;
|
||||||
|
lo = x % 127773;
|
||||||
|
x = 16807 * lo - 2836 * hi;
|
||||||
|
if (x < 0)
|
||||||
|
x += 0x7fffffff;
|
||||||
|
/* Transform to [0, 0x7ffffffd] range. */
|
||||||
|
x--;
|
||||||
|
*ctx = x;
|
||||||
|
return (x);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long rand_next = 1;
|
||||||
|
|
||||||
|
int
|
||||||
|
rand(void)
|
||||||
|
{
|
||||||
|
return (do_rand(&rand_next));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
go(int which_child)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
static char buf[999];
|
||||||
|
char *break0 = sbrk(0);
|
||||||
|
uint64 iters = 0;
|
||||||
|
|
||||||
|
mkdir("grindir");
|
||||||
|
if(chdir("grindir") != 0){
|
||||||
|
printf("grind: chdir grindir failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
chdir("/");
|
||||||
|
|
||||||
|
while(1){
|
||||||
|
iters++;
|
||||||
|
if((iters % 500) == 0)
|
||||||
|
write(1, which_child?"B":"A", 1);
|
||||||
|
int what = rand() % 23;
|
||||||
|
if(what == 1){
|
||||||
|
close(open("grindir/../a", O_CREATE|O_RDWR));
|
||||||
|
} else if(what == 2){
|
||||||
|
close(open("grindir/../grindir/../b", O_CREATE|O_RDWR));
|
||||||
|
} else if(what == 3){
|
||||||
|
unlink("grindir/../a");
|
||||||
|
} else if(what == 4){
|
||||||
|
if(chdir("grindir") != 0){
|
||||||
|
printf("grind: chdir grindir failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
unlink("../b");
|
||||||
|
chdir("/");
|
||||||
|
} else if(what == 5){
|
||||||
|
close(fd);
|
||||||
|
fd = open("/grindir/../a", O_CREATE|O_RDWR);
|
||||||
|
} else if(what == 6){
|
||||||
|
close(fd);
|
||||||
|
fd = open("/./grindir/./../b", O_CREATE|O_RDWR);
|
||||||
|
} else if(what == 7){
|
||||||
|
write(fd, buf, sizeof(buf));
|
||||||
|
} else if(what == 8){
|
||||||
|
read(fd, buf, sizeof(buf));
|
||||||
|
} else if(what == 9){
|
||||||
|
mkdir("grindir/../a");
|
||||||
|
close(open("a/../a/./a", O_CREATE|O_RDWR));
|
||||||
|
unlink("a/a");
|
||||||
|
} else if(what == 10){
|
||||||
|
mkdir("/../b");
|
||||||
|
close(open("grindir/../b/b", O_CREATE|O_RDWR));
|
||||||
|
unlink("b/b");
|
||||||
|
} else if(what == 11){
|
||||||
|
unlink("b");
|
||||||
|
link("../grindir/./../a", "../b");
|
||||||
|
} else if(what == 12){
|
||||||
|
unlink("../grindir/../a");
|
||||||
|
link(".././b", "/grindir/../a");
|
||||||
|
} else if(what == 13){
|
||||||
|
int pid = fork();
|
||||||
|
if(pid == 0){
|
||||||
|
exit(0);
|
||||||
|
} else if(pid < 0){
|
||||||
|
printf("grind: fork failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
wait(0);
|
||||||
|
} else if(what == 14){
|
||||||
|
int pid = fork();
|
||||||
|
if(pid == 0){
|
||||||
|
fork();
|
||||||
|
fork();
|
||||||
|
exit(0);
|
||||||
|
} else if(pid < 0){
|
||||||
|
printf("grind: fork failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
wait(0);
|
||||||
|
} else if(what == 15){
|
||||||
|
sbrk(6011);
|
||||||
|
} else if(what == 16){
|
||||||
|
if(sbrk(0) > break0)
|
||||||
|
sbrk(-(sbrk(0) - break0));
|
||||||
|
} else if(what == 17){
|
||||||
|
int pid = fork();
|
||||||
|
if(pid == 0){
|
||||||
|
close(open("a", O_CREATE|O_RDWR));
|
||||||
|
exit(0);
|
||||||
|
} else if(pid < 0){
|
||||||
|
printf("grind: fork failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if(chdir("../grindir/..") != 0){
|
||||||
|
printf("grind: chdir failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
kill(pid);
|
||||||
|
wait(0);
|
||||||
|
} else if(what == 18){
|
||||||
|
int pid = fork();
|
||||||
|
if(pid == 0){
|
||||||
|
kill(getpid());
|
||||||
|
exit(0);
|
||||||
|
} else if(pid < 0){
|
||||||
|
printf("grind: fork failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
wait(0);
|
||||||
|
} else if(what == 19){
|
||||||
|
int fds[2];
|
||||||
|
if(pipe(fds) < 0){
|
||||||
|
printf("grind: pipe failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
int pid = fork();
|
||||||
|
if(pid == 0){
|
||||||
|
fork();
|
||||||
|
fork();
|
||||||
|
if(write(fds[1], "x", 1) != 1)
|
||||||
|
printf("grind: pipe write failed\n");
|
||||||
|
char c;
|
||||||
|
if(read(fds[0], &c, 1) != 1)
|
||||||
|
printf("grind: pipe read failed\n");
|
||||||
|
exit(0);
|
||||||
|
} else if(pid < 0){
|
||||||
|
printf("grind: fork failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
close(fds[0]);
|
||||||
|
close(fds[1]);
|
||||||
|
wait(0);
|
||||||
|
} else if(what == 20){
|
||||||
|
int pid = fork();
|
||||||
|
if(pid == 0){
|
||||||
|
unlink("a");
|
||||||
|
mkdir("a");
|
||||||
|
chdir("a");
|
||||||
|
unlink("../a");
|
||||||
|
fd = open("x", O_CREATE|O_RDWR);
|
||||||
|
unlink("x");
|
||||||
|
exit(0);
|
||||||
|
} else if(pid < 0){
|
||||||
|
printf("grind: fork failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
wait(0);
|
||||||
|
} else if(what == 21){
|
||||||
|
unlink("c");
|
||||||
|
// should always succeed. check that there are free i-nodes,
|
||||||
|
// file descriptors, blocks.
|
||||||
|
int fd1 = open("c", O_CREATE|O_RDWR);
|
||||||
|
if(fd1 < 0){
|
||||||
|
printf("grind: create c failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if(write(fd1, "x", 1) != 1){
|
||||||
|
printf("grind: write c failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
struct stat st;
|
||||||
|
if(fstat(fd1, &st) != 0){
|
||||||
|
printf("grind: fstat failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if(st.size != 1){
|
||||||
|
printf("grind: fstat reports wrong size %d\n", (int)(st.size));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if(st.ino > 200){
|
||||||
|
printf("grind: fstat reports crazy i-number %d\n", st.ino);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
close(fd1);
|
||||||
|
unlink("c");
|
||||||
|
} else if(what == 22){
|
||||||
|
// echo hi | cat
|
||||||
|
int aa[2], bb[2];
|
||||||
|
if(pipe(aa) < 0){
|
||||||
|
fprintf(2, "grind: pipe failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if(pipe(bb) < 0){
|
||||||
|
fprintf(2, "grind: pipe failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
int pid1 = fork();
|
||||||
|
if(pid1 == 0){
|
||||||
|
close(bb[0]);
|
||||||
|
close(bb[1]);
|
||||||
|
close(aa[0]);
|
||||||
|
close(1);
|
||||||
|
if(dup(aa[1]) != 1){
|
||||||
|
fprintf(2, "grind: dup failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
close(aa[1]);
|
||||||
|
char *args[3] = { "echo", "hi", 0 };
|
||||||
|
exec("grindir/../echo", args);
|
||||||
|
fprintf(2, "grind: echo: not found\n");
|
||||||
|
exit(2);
|
||||||
|
} else if(pid1 < 0){
|
||||||
|
fprintf(2, "grind: fork failed\n");
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
int pid2 = fork();
|
||||||
|
if(pid2 == 0){
|
||||||
|
close(aa[1]);
|
||||||
|
close(bb[0]);
|
||||||
|
close(0);
|
||||||
|
if(dup(aa[0]) != 0){
|
||||||
|
fprintf(2, "grind: dup failed\n");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
close(aa[0]);
|
||||||
|
close(1);
|
||||||
|
if(dup(bb[1]) != 1){
|
||||||
|
fprintf(2, "grind: dup failed\n");
|
||||||
|
exit(5);
|
||||||
|
}
|
||||||
|
close(bb[1]);
|
||||||
|
char *args[2] = { "cat", 0 };
|
||||||
|
exec("/cat", args);
|
||||||
|
fprintf(2, "grind: cat: not found\n");
|
||||||
|
exit(6);
|
||||||
|
} else if(pid2 < 0){
|
||||||
|
fprintf(2, "grind: fork failed\n");
|
||||||
|
exit(7);
|
||||||
|
}
|
||||||
|
close(aa[0]);
|
||||||
|
close(aa[1]);
|
||||||
|
close(bb[1]);
|
||||||
|
char buf[4] = { 0, 0, 0, 0 };
|
||||||
|
read(bb[0], buf+0, 1);
|
||||||
|
read(bb[0], buf+1, 1);
|
||||||
|
read(bb[0], buf+2, 1);
|
||||||
|
close(bb[0]);
|
||||||
|
int st1, st2;
|
||||||
|
wait(&st1);
|
||||||
|
wait(&st2);
|
||||||
|
if(st1 != 0 || st2 != 0 || strcmp(buf, "hi\n") != 0){
|
||||||
|
printf("grind: exec pipeline failed %d %d \"%s\"\n", st1, st2, buf);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
iter()
|
||||||
|
{
|
||||||
|
unlink("a");
|
||||||
|
unlink("b");
|
||||||
|
|
||||||
|
int pid1 = fork();
|
||||||
|
if(pid1 < 0){
|
||||||
|
printf("grind: fork failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if(pid1 == 0){
|
||||||
|
rand_next ^= 31;
|
||||||
|
go(0);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pid2 = fork();
|
||||||
|
if(pid2 < 0){
|
||||||
|
printf("grind: fork failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if(pid2 == 0){
|
||||||
|
rand_next ^= 7177;
|
||||||
|
go(1);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int st1 = -1;
|
||||||
|
wait(&st1);
|
||||||
|
if(st1 != 0){
|
||||||
|
kill(pid1);
|
||||||
|
kill(pid2);
|
||||||
|
}
|
||||||
|
int st2 = -1;
|
||||||
|
wait(&st2);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
while(1){
|
||||||
|
int pid = fork();
|
||||||
|
if(pid == 0){
|
||||||
|
iter();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if(pid > 0){
|
||||||
|
wait(0);
|
||||||
|
}
|
||||||
|
sleep(20);
|
||||||
|
rand_next += 1;
|
||||||
|
}
|
||||||
|
}
|
57
init.c
Normal file
57
init.c
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// init: The initial user-level program
|
||||||
|
|
||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "kernel/sched.h"
|
||||||
|
#include "kernel/fs.h"
|
||||||
|
#include "kernel/file.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
#include "kernel/fcntl.h"
|
||||||
|
|
||||||
|
char *argv[2];// = { "sh", 0 };
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
int pid, wpid;
|
||||||
|
|
||||||
|
argv[0] = "sh";
|
||||||
|
argv[1] = (void*) 0UL;
|
||||||
|
|
||||||
|
if(open("console", O_RDWR) < 0){
|
||||||
|
mknod("console", CONSOLE, 0);
|
||||||
|
open("console", O_RDWR);
|
||||||
|
}
|
||||||
|
dup(0); // stdout
|
||||||
|
dup(0); // stderr
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
printf("init: starting sh\n");
|
||||||
|
pid = fork();
|
||||||
|
if(pid < 0){
|
||||||
|
printf("init: fork failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if(pid == 0){
|
||||||
|
prio(getpid(), 4, 0);
|
||||||
|
exec("sh", argv);
|
||||||
|
printf("init: exec sh failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
// this call to wait() returns if the shell exits,
|
||||||
|
// or if a parentless process exits.
|
||||||
|
wpid = wait((int *) 0);
|
||||||
|
if(wpid == pid){
|
||||||
|
// the shell exited; restart it.
|
||||||
|
break;
|
||||||
|
} else if(wpid < 0){
|
||||||
|
printf("init: wait returned an error\n");
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
// it was a parentless process; do nothing.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
initcode.S
Normal file
29
initcode.S
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Initial process that execs /init.
|
||||||
|
// This code runs in user space.
|
||||||
|
|
||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
// exec(init, argv)
|
||||||
|
.globl start
|
||||||
|
start:
|
||||||
|
la a0, init
|
||||||
|
la a1, argv
|
||||||
|
addi a2, a1, 8
|
||||||
|
li a7, SYS_execve
|
||||||
|
ecall
|
||||||
|
|
||||||
|
// for(;;) exit();
|
||||||
|
exit:
|
||||||
|
li a7, SYS_exit
|
||||||
|
ecall
|
||||||
|
jal exit
|
||||||
|
|
||||||
|
// char init[] = "/init\0";
|
||||||
|
init:
|
||||||
|
.string "/init\0"
|
||||||
|
|
||||||
|
// char *argv[] = { init, 0 };
|
||||||
|
.p2align 3
|
||||||
|
argv:
|
||||||
|
.quad init
|
||||||
|
.quad 0
|
17
kill.c
Normal file
17
kill.c
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(argc < 2){
|
||||||
|
fprintf(2, "usage: kill pid...\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
for(i=1; i<argc; i++)
|
||||||
|
kill(atoi(argv[i]));
|
||||||
|
exit(0);
|
||||||
|
}
|
15
ln.c
Normal file
15
ln.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if(argc != 3){
|
||||||
|
fprintf(2, "Usage: ln old new\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if(link(argv[1], argv[2]) < 0)
|
||||||
|
fprintf(2, "link %s %s: failed\n", argv[1], argv[2]);
|
||||||
|
exit(0);
|
||||||
|
}
|
92
ls.c
Normal file
92
ls.c
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
#include "kernel/fs.h"
|
||||||
|
#include "mkfs/fsformat.h"
|
||||||
|
#include "kernel/fcntl.h"
|
||||||
|
|
||||||
|
char buf[FSFORMAT_NAMESIZE_NEW+1];
|
||||||
|
|
||||||
|
char*
|
||||||
|
fmtname(char *path)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
// Find first character after last slash.
|
||||||
|
for(p=path+strlen(path); p >= path && *p != '/'; p--)
|
||||||
|
;
|
||||||
|
p++;
|
||||||
|
|
||||||
|
// Return blank-padded name.
|
||||||
|
if(strlen(p) >= 32)
|
||||||
|
return p;
|
||||||
|
memmove(buf, p, strlen(p));
|
||||||
|
memset(buf+strlen(p), ' ', 32-strlen(p));
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Syscall to get dirents in standardised format
|
||||||
|
int lsdir(int fd, void* buff, int sz);
|
||||||
|
|
||||||
|
void
|
||||||
|
ls(char *path)
|
||||||
|
{
|
||||||
|
char buf[512], *p;
|
||||||
|
int fd;
|
||||||
|
fsformat_dirent_v1_t de;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if((fd = open(path, O_RDONLY)) < 0){
|
||||||
|
fprintf(2, "ls: cannot open %s\n", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fstat(fd, &st) < 0){
|
||||||
|
fprintf(2, "ls: cannot stat %s\n", path);
|
||||||
|
close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(st.type){
|
||||||
|
case T_DEVICE:
|
||||||
|
case T_FILE:
|
||||||
|
printf("%s %d %d %d\n", fmtname(path), st.type, st.ino, (int) (st.size));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_DIR:
|
||||||
|
if(strlen(path) + 1 + FSFORMAT_NAMESIZE_NEW + 1 > 512 /*sizeof buf*/){
|
||||||
|
printf("ls: path too long\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
strcpy(buf, path);
|
||||||
|
p = buf+strlen(buf);
|
||||||
|
*p++ = '/';
|
||||||
|
while(lsdir(fd, &de, sizeof(fsformat_dirent_v1_t /*de*/)) == sizeof(fsformat_dirent_v1_t /*de*/)){
|
||||||
|
if(de.datainode == 0)
|
||||||
|
continue;
|
||||||
|
memmove(p, de.filename, FSFORMAT_NAMESIZE_NEW);
|
||||||
|
p[FSFORMAT_NAMESIZE_NEW] = 0;
|
||||||
|
if(stat(buf, &st) < 0){
|
||||||
|
printf("ls: cannot stat %s\n", buf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
printf("%s %d %d %d\n", fmtname(buf), st.type, st.ino, (int) (st.size));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(argc < 2){
|
||||||
|
ls(".");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
for(i=1; i<argc; i++)
|
||||||
|
ls(argv[i]);
|
||||||
|
exit(0);
|
||||||
|
}
|
23
mkdir.c
Normal file
23
mkdir.c
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(argc < 2){
|
||||||
|
fprintf(2, "Usage: mkdir files...\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 1; i < argc; i++){
|
||||||
|
if(mkdir(argv[i]) < 0){
|
||||||
|
fprintf(2, "mkdir: %s failed to create\n", argv[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
168
printf.c
Normal file
168
printf.c
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
|
||||||
|
#ifdef _ZCC
|
||||||
|
#include "kernel/cc_stdarg.h"
|
||||||
|
#else
|
||||||
|
#include <stdarg.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char digits[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
static void
|
||||||
|
putc(int fd, char c)
|
||||||
|
{
|
||||||
|
write(fd, &c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printint(int fd, int xx, int base, int sgn)
|
||||||
|
{
|
||||||
|
char buf[16];
|
||||||
|
int i, neg;
|
||||||
|
uint x;
|
||||||
|
|
||||||
|
neg = 0;
|
||||||
|
if(sgn && xx < 0){
|
||||||
|
neg = 1;
|
||||||
|
x = -xx;
|
||||||
|
} else {
|
||||||
|
x = xx;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
do{
|
||||||
|
buf[i++] = digits[x % base];
|
||||||
|
}while((x /= base) != 0);
|
||||||
|
if(neg)
|
||||||
|
buf[i++] = '-';
|
||||||
|
|
||||||
|
while(--i >= 0)
|
||||||
|
putc(fd, buf[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printptr(int fd, uint64 x) {
|
||||||
|
int i;
|
||||||
|
putc(fd, '0');
|
||||||
|
putc(fd, 'x');
|
||||||
|
for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4)
|
||||||
|
putc(fd, digits[x >> (sizeof(uint64) * 8 - 4)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print to the given fd. Only understands %d, %x, %p, %s.
|
||||||
|
void
|
||||||
|
vprintf(int fd, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
int c0, c1, c2, i, state;
|
||||||
|
|
||||||
|
state = 0;
|
||||||
|
for(i = 0; fmt[i]; i++){
|
||||||
|
c0 = fmt[i] & 0xff;
|
||||||
|
if(state == 0){
|
||||||
|
if(c0 == '%'){
|
||||||
|
state = '%';
|
||||||
|
} else {
|
||||||
|
putc(fd, c0);
|
||||||
|
}
|
||||||
|
} else if(state == '%'){
|
||||||
|
c1 = c2 = 0;
|
||||||
|
if(c0) c1 = fmt[i+1] & 0xff;
|
||||||
|
if(c1) c2 = fmt[i+2] & 0xff;
|
||||||
|
if(c0 == 'd'){
|
||||||
|
printint(fd, va_arg(ap, int), 10, 1);
|
||||||
|
} else if(c0 == 'l' && c1 == 'd'){
|
||||||
|
printint(fd, va_arg(ap, uint64), 10, 1);
|
||||||
|
i += 1;
|
||||||
|
} else if(c0 == 'l' && c1 == 'l' && c2 == 'd'){
|
||||||
|
printint(fd, va_arg(ap, uint64), 10, 1);
|
||||||
|
i += 2;
|
||||||
|
} else if(c0 == 'u'){
|
||||||
|
printint(fd, va_arg(ap, int), 10, 0);
|
||||||
|
} else if(c0 == 'l' && c1 == 'u'){
|
||||||
|
printint(fd, va_arg(ap, uint64), 10, 0);
|
||||||
|
i += 1;
|
||||||
|
} else if(c0 == 'l' && c1 == 'l' && c2 == 'u'){
|
||||||
|
printint(fd, va_arg(ap, uint64), 10, 0);
|
||||||
|
i += 2;
|
||||||
|
} else if(c0 == 'x'){
|
||||||
|
printint(fd, va_arg(ap, int), 16, 0);
|
||||||
|
} else if(c0 == 'l' && c1 == 'x'){
|
||||||
|
printint(fd, va_arg(ap, uint64), 16, 0);
|
||||||
|
i += 1;
|
||||||
|
} else if(c0 == 'l' && c1 == 'l' && c2 == 'x'){
|
||||||
|
printint(fd, va_arg(ap, uint64), 16, 0);
|
||||||
|
i += 2;
|
||||||
|
} else if(c0 == 'p'){
|
||||||
|
printptr(fd, va_arg(ap, uint64));
|
||||||
|
} else if(c0 == 's'){
|
||||||
|
if((s = va_arg(ap, char*)) == 0)
|
||||||
|
s = "(null)";
|
||||||
|
write(fd, s, strlen(s));
|
||||||
|
//for(; *s; s++)
|
||||||
|
// putc(fd, *s);
|
||||||
|
} else if(c0 == '%'){
|
||||||
|
putc(fd, '%');
|
||||||
|
} else {
|
||||||
|
// Unknown % sequence. Print it to draw attention.
|
||||||
|
putc(fd, '%');
|
||||||
|
putc(fd, c0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if(c == 'd'){
|
||||||
|
printint(fd, va_arg(ap, int), 10, 1);
|
||||||
|
} else if(c == 'l') {
|
||||||
|
printint(fd, va_arg(ap, uint64), 10, 0);
|
||||||
|
} else if(c == 'x') {
|
||||||
|
printint(fd, va_arg(ap, int), 16, 0);
|
||||||
|
} else if(c == 'p') {
|
||||||
|
printptr(fd, va_arg(ap, uint64));
|
||||||
|
} else if(c == 's'){
|
||||||
|
s = va_arg(ap, char*);
|
||||||
|
if(s == 0)
|
||||||
|
s = "(null)";
|
||||||
|
while(*s != 0){
|
||||||
|
putc(fd, *s);
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
} else if(c == 'c'){
|
||||||
|
putc(fd, va_arg(ap, uint));
|
||||||
|
} else if(c == '%'){
|
||||||
|
putc(fd, c);
|
||||||
|
} else {
|
||||||
|
// Unknown % sequence. Print it to draw attention.
|
||||||
|
putc(fd, '%');
|
||||||
|
putc(fd, c);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
state = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
#ifdef _ZCC
|
||||||
|
__classic_call
|
||||||
|
#endif
|
||||||
|
fprintf(int fd, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vprintf(fd, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
#ifdef _ZCC
|
||||||
|
__classic_call
|
||||||
|
#endif
|
||||||
|
printf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vprintf(1, fmt, ap);
|
||||||
|
}
|
23
rm.c
Normal file
23
rm.c
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(argc < 2){
|
||||||
|
fprintf(2, "Usage: rm files...\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 1; i < argc; i++){
|
||||||
|
if(unlink(argv[i]) < 0){
|
||||||
|
fprintf(2, "rm: %s failed to delete\n", argv[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
500
sh.c
Normal file
500
sh.c
Normal file
@ -0,0 +1,500 @@
|
|||||||
|
// Shell.
|
||||||
|
|
||||||
|
#include "kernel/types.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
#include "kernel/fcntl.h"
|
||||||
|
|
||||||
|
// Parsed command representation
|
||||||
|
#define EXEC 1
|
||||||
|
#define REDIR 2
|
||||||
|
#define PIPE 3
|
||||||
|
#define LIST 4
|
||||||
|
#define BACK 5
|
||||||
|
|
||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
||||||
|
int fork1(void); // Fork but panics on failure.
|
||||||
|
void panic(char*);
|
||||||
|
struct cmd *parsecmd(char*);
|
||||||
|
#ifdef _ZCC
|
||||||
|
void runcmd(struct cmd*);
|
||||||
|
#else
|
||||||
|
void runcmd(struct cmd*) __attribute__((noreturn));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Execute cmd. Never returns.
|
||||||
|
void
|
||||||
|
runcmd(struct cmd *cmd)
|
||||||
|
{
|
||||||
|
int p[2];
|
||||||
|
struct backcmd *bcmd;
|
||||||
|
struct execcmd *ecmd;
|
||||||
|
struct listcmd *lcmd;
|
||||||
|
struct pipecmd *pcmd;
|
||||||
|
struct redircmd *rcmd;
|
||||||
|
|
||||||
|
if(cmd == 0)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
|
||||||
|
switch(cmd->type){
|
||||||
|
case EXEC:
|
||||||
|
ecmd = (struct execcmd*)cmd;
|
||||||
|
if(ecmd->argv[0] == 0)
|
||||||
|
exit(1);
|
||||||
|
exec(ecmd->argv[0], ecmd->argv);
|
||||||
|
fprintf(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){
|
||||||
|
fprintf(2, "open %s failed\n", rcmd->file);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
runcmd(rcmd->cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LIST:
|
||||||
|
lcmd = (struct listcmd*)cmd;
|
||||||
|
if(fork1() == 0)
|
||||||
|
runcmd(lcmd->left);
|
||||||
|
wait(0);
|
||||||
|
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(0);
|
||||||
|
wait(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BACK:
|
||||||
|
bcmd = (struct backcmd*)cmd;
|
||||||
|
if(fork1() == 0)
|
||||||
|
runcmd(bcmd->cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("runcmd");
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
getcmd(char *buf, int nbuf)
|
||||||
|
{
|
||||||
|
write(2, "$ ", 2);
|
||||||
|
memset(buf, 0, nbuf);
|
||||||
|
gets(buf, nbuf);
|
||||||
|
if(buf[0] == 0) // EOF
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
/*static*/ char buf[100];
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
// Ensure that three file descriptors are open.
|
||||||
|
while((fd = open("console", O_RDWR)) >= 0){
|
||||||
|
if(fd >= 3){
|
||||||
|
close(fd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and run input commands.
|
||||||
|
while(getcmd(buf, 100 /*sizeof(buf)*/) >= 0){
|
||||||
|
if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
|
||||||
|
// Chdir must be called by the parent, not the child.
|
||||||
|
buf[strlen(buf)-1] = 0; // chop \n
|
||||||
|
if(chdir(buf+3) < 0)
|
||||||
|
fprintf(2, "cannot cd %s\n", buf+3);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(fork1() == 0)
|
||||||
|
runcmd(parsecmd(buf));
|
||||||
|
wait(0);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
panic(char *s)
|
||||||
|
{
|
||||||
|
fprintf(2, "%s\n", s);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(struct execcmd /**cmd*/));
|
||||||
|
memset(cmd, 0, sizeof(struct execcmd /**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(struct redircmd /**cmd*/));
|
||||||
|
memset(cmd, 0, sizeof(struct redircmd /**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(struct pipecmd /**cmd*/));
|
||||||
|
memset(cmd, 0, sizeof(struct pipecmd /**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(struct listcmd /**cmd*/));
|
||||||
|
memset(cmd, 0, sizeof(struct listcmd /**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(struct backcmd /**cmd*/));
|
||||||
|
memset(cmd, 0, sizeof(struct backcmd /**cmd*/));
|
||||||
|
cmd->type = BACK;
|
||||||
|
cmd->cmd = subcmd;
|
||||||
|
return (struct cmd*)cmd;
|
||||||
|
}
|
||||||
|
//PAGEBREAK!
|
||||||
|
// Parsing
|
||||||
|
|
||||||
|
int
|
||||||
|
gettoken(char **ps, char *es, char **q, char **eq)
|
||||||
|
{
|
||||||
|
const char* whitespace = " \t\r\n\v";
|
||||||
|
const char* symbols = "<|>&;()";
|
||||||
|
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;
|
||||||
|
|
||||||
|
while(s < es && strchr(whitespace, *s))
|
||||||
|
s++;
|
||||||
|
*ps = s;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
peek(char **ps, char *es, char *toks)
|
||||||
|
{
|
||||||
|
const char* whitespace = " \t\r\n\v";
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
s = *ps;
|
||||||
|
while(s < es && strchr(whitespace, *s))
|
||||||
|
s++;
|
||||||
|
*ps = s;
|
||||||
|
return *s && strchr(toks, *s);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmd *parseline(char**, char*);
|
||||||
|
struct cmd *parsepipe(char**, char*);
|
||||||
|
struct cmd *parseexec(char**, char*);
|
||||||
|
struct cmd *nulterminate(struct cmd*);
|
||||||
|
|
||||||
|
struct cmd*
|
||||||
|
parsecmd(char *s)
|
||||||
|
{
|
||||||
|
char *es;
|
||||||
|
struct cmd *cmd;
|
||||||
|
|
||||||
|
es = s + strlen(s);
|
||||||
|
cmd = parseline(&s, es);
|
||||||
|
peek(&s, es, "");
|
||||||
|
if(s != es){
|
||||||
|
fprintf(2, "leftovers: %s\n", s);
|
||||||
|
panic("syntax");
|
||||||
|
}
|
||||||
|
nulterminate(cmd);
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmd*
|
||||||
|
parseline(char **ps, char *es)
|
||||||
|
{
|
||||||
|
struct cmd *cmd;
|
||||||
|
|
||||||
|
cmd = parsepipe(ps, es);
|
||||||
|
while(peek(ps, es, "&")){
|
||||||
|
gettoken(ps, es, 0, 0);
|
||||||
|
cmd = backcmd(cmd);
|
||||||
|
}
|
||||||
|
if(peek(ps, es, ";")){
|
||||||
|
gettoken(ps, es, 0, 0);
|
||||||
|
cmd = listcmd(cmd, parseline(ps, es));
|
||||||
|
}
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmd*
|
||||||
|
parsepipe(char **ps, char *es)
|
||||||
|
{
|
||||||
|
struct cmd *cmd;
|
||||||
|
|
||||||
|
cmd = parseexec(ps, es);
|
||||||
|
if(peek(ps, es, "|")){
|
||||||
|
gettoken(ps, es, 0, 0);
|
||||||
|
cmd = pipecmd(cmd, parsepipe(ps, es));
|
||||||
|
}
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmd*
|
||||||
|
parseredirs(struct cmd *cmd, char **ps, char *es)
|
||||||
|
{
|
||||||
|
int tok;
|
||||||
|
char *q, *eq;
|
||||||
|
|
||||||
|
while(peek(ps, es, "<>")){
|
||||||
|
tok = gettoken(ps, es, 0, 0);
|
||||||
|
if(gettoken(ps, es, &q, &eq) != 'a')
|
||||||
|
panic("missing file for redirection");
|
||||||
|
switch(tok){
|
||||||
|
case '<':
|
||||||
|
cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE|O_TRUNC, 1);
|
||||||
|
break;
|
||||||
|
case '+': // >>
|
||||||
|
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmd*
|
||||||
|
parseblock(char **ps, char *es)
|
||||||
|
{
|
||||||
|
struct cmd *cmd;
|
||||||
|
|
||||||
|
if(!peek(ps, es, "("))
|
||||||
|
panic("parseblock");
|
||||||
|
gettoken(ps, es, 0, 0);
|
||||||
|
cmd = parseline(ps, es);
|
||||||
|
if(!peek(ps, es, ")"))
|
||||||
|
panic("syntax - missing )");
|
||||||
|
gettoken(ps, es, 0, 0);
|
||||||
|
cmd = parseredirs(cmd, ps, es);
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmd*
|
||||||
|
parseexec(char **ps, char *es)
|
||||||
|
{
|
||||||
|
char *q, *eq;
|
||||||
|
int tok, argc;
|
||||||
|
struct execcmd *cmd;
|
||||||
|
struct cmd *ret;
|
||||||
|
|
||||||
|
if(peek(ps, es, "("))
|
||||||
|
return parseblock(ps, es);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NUL-terminate all the counted strings.
|
||||||
|
struct cmd*
|
||||||
|
nulterminate(struct cmd *cmd)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct backcmd *bcmd;
|
||||||
|
struct execcmd *ecmd;
|
||||||
|
struct listcmd *lcmd;
|
||||||
|
struct pipecmd *pcmd;
|
||||||
|
struct redircmd *rcmd;
|
||||||
|
|
||||||
|
if(cmd == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
49
stressfs.c
Normal file
49
stressfs.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Demonstrate that moving the "acquire" in iderw after the loop that
|
||||||
|
// appends to the idequeue results in a race.
|
||||||
|
|
||||||
|
// For this to work, you should also add a spin within iderw's
|
||||||
|
// idequeue traversal loop. Adding the following demonstrated a panic
|
||||||
|
// after about 5 runs of stressfs in QEMU on a 2.1GHz CPU:
|
||||||
|
// for (i = 0; i < 40000; i++)
|
||||||
|
// asm volatile("");
|
||||||
|
|
||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
#include "kernel/fs.h"
|
||||||
|
#include "kernel/fcntl.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd, i;
|
||||||
|
char path[] = "stressfs0";
|
||||||
|
char data[512];
|
||||||
|
|
||||||
|
printf("stressfs starting\n");
|
||||||
|
memset(data, 'a', sizeof(data));
|
||||||
|
|
||||||
|
for(i = 0; i < 4; i++)
|
||||||
|
if(fork() > 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
printf("write %d\n", i);
|
||||||
|
|
||||||
|
path[8] += i;
|
||||||
|
fd = open(path, O_CREATE | O_RDWR);
|
||||||
|
for(i = 0; i < 20; i++)
|
||||||
|
// printf(fd, "%d\n", i);
|
||||||
|
write(fd, data, sizeof(data));
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
printf("read\n");
|
||||||
|
|
||||||
|
fd = open(path, O_RDONLY);
|
||||||
|
for (i = 0; i < 20; i++)
|
||||||
|
read(fd, data, sizeof(data));
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
wait(0);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
112
thrdtest.c
Normal file
112
thrdtest.c
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// Test that thrd succeeds or fails gracefully.
|
||||||
|
// This file was modified from the xv6-based forktest.c
|
||||||
|
// Tiny executable so that the limit can be filling the proc table.
|
||||||
|
|
||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
|
||||||
|
// N should be set HIGHER than the limit!
|
||||||
|
#define N 10
|
||||||
|
|
||||||
|
void
|
||||||
|
print(const char *s)
|
||||||
|
{
|
||||||
|
write(1, s, strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
void printdec(unsigned int i) {
|
||||||
|
if (i == 0) {
|
||||||
|
print("0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char foo[11];
|
||||||
|
int idx = 10;
|
||||||
|
while (i > 0) {
|
||||||
|
idx--;
|
||||||
|
foo[idx] = '0' + (i%10);
|
||||||
|
i /= 10;
|
||||||
|
}
|
||||||
|
foo[10] = 0;
|
||||||
|
print(foo+idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void thrdf(uint64 thrdnum) {
|
||||||
|
print("Hello from thread #"); printdec((int)thrdnum); print("\n");
|
||||||
|
int i, j, ch, pr;
|
||||||
|
pr = 7-(getpid() % 4);
|
||||||
|
ch = '0'+pr;
|
||||||
|
prio(getpid(), pr, 4);
|
||||||
|
//sleep(1);
|
||||||
|
for (i = 0; i < 100; i++) {
|
||||||
|
for (j = 0; j < 256; j++) {
|
||||||
|
ch++;
|
||||||
|
}
|
||||||
|
char str[2];
|
||||||
|
str[0] = (char)ch;
|
||||||
|
str[1] = 0;
|
||||||
|
print(str);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
thrdtest(void)
|
||||||
|
{
|
||||||
|
int n, pid;
|
||||||
|
|
||||||
|
print("thrd test\n");
|
||||||
|
|
||||||
|
print("thrdf is at "); printdec((int)(uint64)&thrdf); print("\n");
|
||||||
|
//print("testing printdec(12345)="); printdec(12345); print("\n");
|
||||||
|
print("attempting to launch up to N="); printdec(N); print(" processes in the same address space...\n");
|
||||||
|
|
||||||
|
for(n=0; n<N; n++){
|
||||||
|
char* stack = malloc(1024);
|
||||||
|
print("stack at "); printdec((int)(uint64)stack); print("\n");
|
||||||
|
if (!stack) {
|
||||||
|
print("malloc failed\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int i = 1024;
|
||||||
|
// Align stack, since this probably won't be guaranteed by a simple malloc
|
||||||
|
// And may differ by compiler/settings/etc.!!
|
||||||
|
while (((uint64)(stack+i)) % 16) {
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
pid = thrd(getpid(), &thrdf, stack+i, n);
|
||||||
|
if(pid < 0) {
|
||||||
|
print("thrd() syscall failed\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
print("spawned "); printdec(n); print(n == 1 ? " thread\n" : " threads\n");
|
||||||
|
|
||||||
|
if(n == N){
|
||||||
|
print("thrd() claimed to work N times! thrdtest can be updated so N is greater than the kernel's NPROC!\n");
|
||||||
|
//exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(; n > 0; n--){
|
||||||
|
if(wait(0) < 0){
|
||||||
|
print("wait stopped early\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wait(0) != -1){
|
||||||
|
print("wait got too many\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
print("\nthrd() test OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
thrdtest();
|
||||||
|
exit(0);
|
||||||
|
}
|
162
ulib.c
Normal file
162
ulib.c
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
//#include "kernel/types.h"
|
||||||
|
// Avoid reimplementing optimisations to string routines everywhere
|
||||||
|
#include "kernel/string.c"
|
||||||
|
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "kernel/fcntl.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// wrapper so that it's OK if main() does not call exit().
|
||||||
|
//
|
||||||
|
void
|
||||||
|
start()
|
||||||
|
{
|
||||||
|
extern int main();
|
||||||
|
main();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// exec() now needs to be implemented on top of execve()
|
||||||
|
// but for now we can just pass a single NULL in the env array
|
||||||
|
int exec(const char* name, char** argv) {
|
||||||
|
char* envpointers[1];
|
||||||
|
envpointers[0] = (void*)0ULL;
|
||||||
|
return execve(name, argv, envpointers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
char*
|
||||||
|
strcpy(char *s, const char *t)
|
||||||
|
{
|
||||||
|
char *os;
|
||||||
|
|
||||||
|
os = s;
|
||||||
|
while((*s++ = *t++) != 0)
|
||||||
|
;
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
strcmp(const char *p, const char *q)
|
||||||
|
{
|
||||||
|
while(*p && *p == *q)
|
||||||
|
p++, q++;
|
||||||
|
return (uchar)*p - (uchar)*q;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint
|
||||||
|
strlen(const char *s)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for(n = 0; s[n]; n++)
|
||||||
|
;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
memset(void *dst, int c, uint n)
|
||||||
|
{
|
||||||
|
char *cdst = (char *) dst;
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < n; i++){
|
||||||
|
cdst[i] = c;
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
strchr(const char *s, char c)
|
||||||
|
{
|
||||||
|
for(; *s; s++)
|
||||||
|
if(*s == c)
|
||||||
|
return (char*)s;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
char*
|
||||||
|
gets(char *buf, int max)
|
||||||
|
{
|
||||||
|
int i, cc;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
for(i=0; i+1 < max; ){
|
||||||
|
cc = read(0, &c, 1);
|
||||||
|
if(cc < 1)
|
||||||
|
break;
|
||||||
|
buf[i++] = c;
|
||||||
|
if(c == '\n' || c == '\r')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf[i] = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
stat(const char *n, struct stat *st)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
fd = open(n, O_RDONLY);
|
||||||
|
if(fd < 0)
|
||||||
|
return -1;
|
||||||
|
r = fstat(fd, st);
|
||||||
|
close(fd);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int
|
||||||
|
atoi(const char *s)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
while('0' <= *s && *s <= '9')
|
||||||
|
n = n*10 + *s++ - '0';
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
memmove(void *vdst, const void *vsrc, int n)
|
||||||
|
{
|
||||||
|
char *dst;
|
||||||
|
const char *src;
|
||||||
|
|
||||||
|
dst = vdst;
|
||||||
|
src = vsrc;
|
||||||
|
if (src > dst) {
|
||||||
|
while(n-- > 0)
|
||||||
|
*dst++ = *src++;
|
||||||
|
} else {
|
||||||
|
dst += n;
|
||||||
|
src += n;
|
||||||
|
while(n-- > 0)
|
||||||
|
*--dst = *--src;
|
||||||
|
}
|
||||||
|
return vdst;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
memcmp(const void *s1, const void *s2, uint n)
|
||||||
|
{
|
||||||
|
const char *p1 = s1, *p2 = s2;
|
||||||
|
while (n-- > 0) {
|
||||||
|
if (*p1 != *p2) {
|
||||||
|
return *p1 - *p2;
|
||||||
|
}
|
||||||
|
p1++;
|
||||||
|
p2++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
memcpy(void *dst, const void *src, uint n)
|
||||||
|
{
|
||||||
|
return memmove(dst, src, n);
|
||||||
|
}
|
||||||
|
*/
|
90
umalloc.c
Normal file
90
umalloc.c
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
#include "kernel/param.h"
|
||||||
|
|
||||||
|
// Memory allocator by Kernighan and Ritchie,
|
||||||
|
// The C programming Language, 2nd ed. Section 8.7.
|
||||||
|
|
||||||
|
typedef long Align;
|
||||||
|
|
||||||
|
union header {
|
||||||
|
struct {
|
||||||
|
union header *ptr;
|
||||||
|
uint size;
|
||||||
|
} s;
|
||||||
|
Align x;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef union header Header;
|
||||||
|
|
||||||
|
static Header base;
|
||||||
|
static Header *freep;
|
||||||
|
|
||||||
|
void
|
||||||
|
free(void *ap)
|
||||||
|
{
|
||||||
|
Header *bp, *p;
|
||||||
|
|
||||||
|
bp = (Header*)ap - 1;
|
||||||
|
for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
|
||||||
|
if(p >= p->s.ptr && (bp > p || bp < p->s.ptr))
|
||||||
|
break;
|
||||||
|
if(bp + bp->s.size == p->s.ptr){
|
||||||
|
bp->s.size += p->s.ptr->s.size;
|
||||||
|
bp->s.ptr = p->s.ptr->s.ptr;
|
||||||
|
} else
|
||||||
|
bp->s.ptr = p->s.ptr;
|
||||||
|
if(p + p->s.size == bp){
|
||||||
|
p->s.size += bp->s.size;
|
||||||
|
p->s.ptr = bp->s.ptr;
|
||||||
|
} else
|
||||||
|
p->s.ptr = bp;
|
||||||
|
freep = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Header*
|
||||||
|
morecore(uint nu)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
Header *hp;
|
||||||
|
|
||||||
|
if(nu < 4096)
|
||||||
|
nu = 4096;
|
||||||
|
p = sbrk(nu * sizeof(Header));
|
||||||
|
if(p == (char*)-1)
|
||||||
|
return 0;
|
||||||
|
hp = (Header*)p;
|
||||||
|
hp->s.size = nu;
|
||||||
|
free((void*)(hp + 1));
|
||||||
|
return freep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
malloc(uint nbytes)
|
||||||
|
{
|
||||||
|
Header *p, *prevp;
|
||||||
|
uint nunits;
|
||||||
|
|
||||||
|
nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1;
|
||||||
|
if((prevp = freep) == 0){
|
||||||
|
base.s.ptr = freep = prevp = &base;
|
||||||
|
base.s.size = 0;
|
||||||
|
}
|
||||||
|
for(p = prevp->s.ptr; ; prevp = p, p = p->s.ptr){
|
||||||
|
if(p->s.size >= nunits){
|
||||||
|
if(p->s.size == nunits)
|
||||||
|
prevp->s.ptr = p->s.ptr;
|
||||||
|
else {
|
||||||
|
p->s.size -= nunits;
|
||||||
|
p += p->s.size;
|
||||||
|
p->s.size = nunits;
|
||||||
|
}
|
||||||
|
freep = prevp;
|
||||||
|
return (void*)(p + 1);
|
||||||
|
}
|
||||||
|
if(p == freep)
|
||||||
|
if((p = morecore(nunits)) == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
63
user.h
Normal file
63
user.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
struct stat;
|
||||||
|
|
||||||
|
// system calls
|
||||||
|
int fork(void);
|
||||||
|
#ifdef _ZCC
|
||||||
|
int exit(int);
|
||||||
|
#else
|
||||||
|
int exit(int) __attribute__((noreturn));
|
||||||
|
#endif
|
||||||
|
int wait(int*);
|
||||||
|
int pipe(int*);
|
||||||
|
int write(int, const void*, int);
|
||||||
|
int read(int, void*, int);
|
||||||
|
int close(int);
|
||||||
|
int kill(int);
|
||||||
|
int execve(const char*, char**, char**); // New/modified system call
|
||||||
|
int open(const char*, int);
|
||||||
|
int mknod(const char*, short, short);
|
||||||
|
int unlink(const char*);
|
||||||
|
int fstat(int fd, struct stat*);
|
||||||
|
int link(const char*, const char*);
|
||||||
|
int mkdir(const char*);
|
||||||
|
int chdir(const char*);
|
||||||
|
int dup(int);
|
||||||
|
int getpid(void);
|
||||||
|
char* sbrk(int);
|
||||||
|
int sleep(int);
|
||||||
|
int uptime(void);
|
||||||
|
// New system call, set priority
|
||||||
|
// first implementation only works/worked on current pid
|
||||||
|
int prio(int pid, int newprio, int newlimit);
|
||||||
|
// Set processor affinity, pid must be current pid and range must be 0 for now
|
||||||
|
int affin(int pid, int range, uint64 mask);
|
||||||
|
// New system call, start thread
|
||||||
|
// Typedef for the thread function
|
||||||
|
typedef void (*thrd_fnc_t)(uint64 arg);
|
||||||
|
// Less-typesafe version: int thrd(int pid, uint64 fnc, uint64 stk, uint64 arg);
|
||||||
|
int thrd(int frompid, thrd_fnc_t fnc, void* stk, uint64 arg);
|
||||||
|
|
||||||
|
// ulib.c
|
||||||
|
int exec(const char*, char**); // Now implemented on top of execve
|
||||||
|
int stat(const char*, struct stat*);
|
||||||
|
char* strcpy(char*, const char*);
|
||||||
|
void *memmove(void*, const void*, uint);
|
||||||
|
char* strchr(const char*, int c);
|
||||||
|
int strcmp(const char*, const char*);
|
||||||
|
#ifdef _ZCC
|
||||||
|
void __classic_call fprintf(int, const char*, ...);
|
||||||
|
void __classic_call printf(const char*, ...);
|
||||||
|
#else
|
||||||
|
void fprintf(int, const char*, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
void printf(const char*, ...) __attribute__ ((format (printf, 1, 2)));
|
||||||
|
#endif
|
||||||
|
char* gets(char*, int max);
|
||||||
|
long int strlen(const char*);
|
||||||
|
void* memset(void*, int, long int);
|
||||||
|
int atoi(const char*);
|
||||||
|
int memcmp(const void *, const void *, uint);
|
||||||
|
void *memcpy(void *, const void *, long int);
|
||||||
|
|
||||||
|
// umalloc.c
|
||||||
|
void* malloc(uint);
|
||||||
|
void free(void*);
|
39
user.ld
Normal file
39
user.ld
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
OUTPUT_ARCH( "riscv" )
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x0;
|
||||||
|
|
||||||
|
.text : {
|
||||||
|
*(.text .text.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata : {
|
||||||
|
. = ALIGN(16);
|
||||||
|
*(.srodata .srodata.*) /* do not need to distinguish this from .rodata */
|
||||||
|
. = ALIGN(16);
|
||||||
|
*(.rodata .rodata.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.eh_frame : {
|
||||||
|
*(.eh_frame)
|
||||||
|
*(.eh_frame.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
. = ALIGN(0x1000);
|
||||||
|
.data : {
|
||||||
|
. = ALIGN(16);
|
||||||
|
*(.sdata .sdata.*) /* do not need to distinguish this from .data */
|
||||||
|
. = ALIGN(16);
|
||||||
|
*(.data .data.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss : {
|
||||||
|
. = ALIGN(16);
|
||||||
|
*(.sbss .sbss.*) /* do not need to distinguish this from .bss */
|
||||||
|
. = ALIGN(16);
|
||||||
|
*(.bss .bss.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
PROVIDE(end = .);
|
||||||
|
}
|
3118
usertests.c
Normal file
3118
usertests.c
Normal file
File diff suppressed because it is too large
Load Diff
45
usys.pl
Executable file
45
usys.pl
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
|
# Generate usys.S, the stubs for syscalls.
|
||||||
|
|
||||||
|
print "// generated by usys.pl - do not edit\n";
|
||||||
|
|
||||||
|
print "#include \"kernel/syscall.h\"\n";
|
||||||
|
|
||||||
|
sub entry {
|
||||||
|
my $name = shift;
|
||||||
|
print ".global $name\n";
|
||||||
|
print "${name}:\n";
|
||||||
|
print " li a7, SYS_${name}\n";
|
||||||
|
print " ecall\n";
|
||||||
|
print " ret\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
entry("fork");
|
||||||
|
entry("exit");
|
||||||
|
entry("wait");
|
||||||
|
entry("pipe");
|
||||||
|
entry("read");
|
||||||
|
entry("write");
|
||||||
|
entry("close");
|
||||||
|
entry("kill");
|
||||||
|
entry("execve"); # modified by Zak, replaces exec() which can work on top
|
||||||
|
entry("open");
|
||||||
|
entry("mknod");
|
||||||
|
entry("unlink");
|
||||||
|
entry("fstat");
|
||||||
|
entry("link");
|
||||||
|
entry("mkdir");
|
||||||
|
entry("chdir");
|
||||||
|
entry("dup");
|
||||||
|
entry("getpid");
|
||||||
|
entry("sbrk");
|
||||||
|
entry("sleep");
|
||||||
|
entry("uptime");
|
||||||
|
entry("prio"); # new syscall, set priority and limit
|
||||||
|
entry("affin"); # new syscall, set processor affinity
|
||||||
|
entry("thrd"); # new syscall, launch thread
|
||||||
|
entry("drvinf"); # new syscall, get drive info
|
||||||
|
entry("lsdir"); # new syscall, read directory in standardised form
|
||||||
|
entry("kqueue1"); # new syscall, allocate kqueue
|
||||||
|
entry("kevent"); # new syscall, wait for events or modify a kqueue
|
55
wc.c
Normal file
55
wc.c
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/stat.h"
|
||||||
|
#include "kernel/fcntl.h"
|
||||||
|
#include "user/user.h"
|
||||||
|
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
void
|
||||||
|
wc(int fd, char *name)
|
||||||
|
{
|
||||||
|
int i, n;
|
||||||
|
int l, w, c, inword;
|
||||||
|
|
||||||
|
l = w = c = 0;
|
||||||
|
inword = 0;
|
||||||
|
while((n = read(fd, buf, sizeof(buf))) > 0){
|
||||||
|
for(i=0; i<n; i++){
|
||||||
|
c++;
|
||||||
|
if(buf[i] == '\n')
|
||||||
|
l++;
|
||||||
|
if(strchr(" \r\t\n\v", buf[i]))
|
||||||
|
inword = 0;
|
||||||
|
else if(!inword){
|
||||||
|
w++;
|
||||||
|
inword = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(n < 0){
|
||||||
|
printf("wc: read error\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
printf("%d %d %d %s\n", l, w, c, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd, i;
|
||||||
|
|
||||||
|
if(argc <= 1){
|
||||||
|
wc(0, "");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 1; i < argc; i++){
|
||||||
|
if((fd = open(argv[i], O_RDONLY)) < 0){
|
||||||
|
printf("wc: cannot open %s\n", argv[i]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
wc(fd, argv[i]);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user