Merge remote-tracking branch 'origin/decode_print' into decode_print

This commit is contained in:
Rémi Rativel 2023-03-08 13:04:12 +01:00
commit ddc86f6f0a
14 changed files with 1485 additions and 10 deletions

View File

@ -1,4 +1,4 @@
# Ignoring dump files # Ignoring dump files
*.dump *.dump
*.o *.o
./target target

View File

@ -6,8 +6,16 @@ include $(TOPDIR)/Makefile.config
# #
dumps: dumps:
$(MAKE) dumps -C riscv_instructions/ $(MAKE) dumps -C riscv_instructions/
mkdir -p ${TOPDIR}/target mkdir -p ${TOPDIR}/target/dumps/
find . -name '*.dump' -exec mv {} ${TOPDIR}/target \; find . -name '*.dump' -exec mv {} ${TOPDIR}/target/dumps/ \;
user_lib:
$(MAKE) -C userlib/
tests: user_lib
$(MAKE) tests -C riscv_instructions/
mkdir -p ${TOPDIR}/target/guac/
find . -name '*.guac' -exec mv {} ${TOPDIR}/target/guac/ \;
clean: clean:
rm -rf $(TOPDIR)/target rm -rf $(TOPDIR)/target

View File

@ -0,0 +1,38 @@
include $(TOPDIR)/Makefile.config
USERLIB = $(TOPDIR)/userlib
INCPATH += -I$(TOPDIR) -I$(USERLIB)
LDFLAGS = $(RISCV_LDFLAGS) -T $(USERLIB)/ldscript.lds
ASFLAGS = $(RISCV_ASFLAGS) $(INCPATH)
CFLAGS = $(RISCV_CFLAGS) $(INCPATH)
# Rules
%.o: %.s
$(RISCV_AS) $(ASFLAGS) -c $<
%.o: %.c
$(RISCV_GCC) $(CFLAGS) -c $<
%.dump: %.o
$(RISCV_OBJCOPY) -j .text -O $(DUMP_FORMAT) $< $@
%.guac: %.o
$(RISCV_LD) $(LDFLAGS) $+ -o $@
# Dependencies
.%.d: %.s
@echo Generating dependencies for $<
@$(SHELL) -ec '$(GCC) -x assembler-with-cpp -M $(ASFLAGS) $< \
| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
[ -s $@ ] || rm -f $@'
.%.d: %.c
@echo Generating dependencies for $<
@$(SHELL) -ec '$(GCC) -M $(CFLAGS) $< \
| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
[ -s $@ ] || rm -f $@'
# Targets
#clean:
# rm -rf *.o 2> /dev/null
# rm -rf *.dump 2> /dev/null
# rm -rf *.guac 2> /dev/null

View File

@ -2,3 +2,8 @@ dumps:
make dumps -C boolean_logic/ make dumps -C boolean_logic/
make dumps -C jump_instructions/ make dumps -C jump_instructions/
make dumps -C simple_arithmetics/ make dumps -C simple_arithmetics/
tests:
make tests -C boolean_logic/
make tests -C jump_instructions/
make tests -C simple_arithmetics/

View File

@ -1,4 +1,9 @@
TOPDIR = ../.. TOPDIR = ../..
include $(TOPDIR)/Makefile.dumps include $(TOPDIR)/Makefile.tests
dumps: comparisons.dump if.dump switch.dump dumps: comparisons.dump if.dump switch.dump
tests: comparisons.guac if.guac switch.guac
# Dependances
$(PROGRAMS): % : $(USERLIB)/sys.o $(USERLIB)/libnachos.o %.o

View File

@ -1,4 +1,6 @@
TOPDIR = ../.. TOPDIR = ../..
include $(TOPDIR)/Makefile.dumps include $(TOPDIR)/Makefile.tests
dumps: jump.dump ret.dump dumps: jump.dump ret.dump
tests: jump.guac ret.guac

View File

@ -1,4 +1,6 @@
TOPDIR = ../.. TOPDIR = ../..
include $(TOPDIR)/Makefile.dumps include $(TOPDIR)/Makefile.tests
dumps: unsigned_addition.dump unsigned_division.dump unsigned_multiplication.dump unsigned_substraction.dump dumps: unsigned_addition.dump unsigned_division.dump unsigned_multiplication.dump unsigned_substraction.dump
tests: unsigned_addition.guac unsigned_division.guac unsigned_multiplication.guac unsigned_substraction.guac

View File

@ -1,3 +1,6 @@
#include "userlib/syscall.h"
#include "userlib/libnachos.h"
// EXPECTS TWO VARIABLES WITH A VALUE OF UNSIGNED 1 // EXPECTS TWO VARIABLES WITH A VALUE OF UNSIGNED 1
int main() { int main() {
unsigned int x = 0; unsigned int x = 0;

View File

@ -0,0 +1,4 @@
TOPDIR = ../
include $(TOPDIR)/Makefile.tests
default: sys.o libnachos.o

View File

@ -0,0 +1,61 @@
/*
ldscript for running user programs under Nachos
Sections should be aligned on page boundaries. Here an alignement of
at least 0x2000 is selected, thus supporting pages up to 8KB
large. See addrspace.cc for details.
*/
ENTRY(__start)
SECTIONS
{
/* Skip an area of about 8k, so that NULL pointer dereferences can
be detected */
. += 0x2000;
.sys ALIGN(0x4000) : {
*(.init)
*(.sys)
}
/* Code is aligned on a 16k boundary
Due to the size of the .sys section, the code start address will
presumably be at address 0x4000 */
.text ALIGN(0x400000) : {
_ftext = .;
eprol = .;
*(.text)
*(.fini)
}
etext = .;
_etext = .;
/* Initialized data is aligned on a 16k boundary */
.data ALIGN(0x4000) : {
_fdata = .;
*(.data)
*(.sdata)
}
.rodata ALIGN(0x4000) :
{
*(.rdata)
*(.srodata)
*(.rodata)
}
edata = .;
_edata = .;
/* Non-initialized data is aligned on a 16k boundary */
/* Bss = Block Started by Symbol */
.bss ALIGN(0x4000) : {
*(.bss)
*(.sbss)
*(.scommon)
*(COMMON)
}
end = .;
_end = .;
}

View File

@ -0,0 +1,630 @@
/*! \file libnachos.c
* \brief Functions of our library, for user programs.
*
* This library only provides some usefull functions for
* programming.
*
* -----------------------------------------------------
* This file is part of the Nachos-RiscV distribution
* Copyright (c) 2022 University of Rennes 1.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details
* (see see <http://www.gnu.org/licenses/>).
* -----------------------------------------------------
*/
#include "libnachos.h"
#include <stdarg.h>
#include <stdint.h>
//----------------------------------------------------------------------
// threadStart()
/*! Makes a thread execute a function or program. This function
// is static, it is called internally by library function threadCreate
// and should not be called directly by user programs. The interest
// of this function is to be able to terminate threads correctly,
// even when the thread to be terminated does not explicitly call
// Exit. threadStart provides the mechanism by which Exit
// is called automatically
//
// \param func is the identificator of the function to execute.
*/
//----------------------------------------------------------------------
static void threadStart(uint64_t func)
{
VoidNoArgFunctionPtr func2;
func2=(VoidNoArgFunctionPtr)func;
// Call the function that actually contains the thread code
(*func2)();
// Call exit, such that there is no return using an empty stack
Exit(0);
}
//----------------------------------------------------------------------
// threadCreate()
/*! Creates a thread and makes it execute a function.
//
// NB : instead of directly executing the required function,
// function threadStart is called so as to ensure
// that the thread will properly exit
// This function must be called instead of calling directly
// the system call newThread
//
// \param name the name of the thread (for debugging purpose)
// \param func is the address of the function to execute.
*/
//----------------------------------------------------------------------
ThreadId threadCreate(char *debug_name, VoidNoArgFunctionPtr func)
{
return newThread(debug_name, (uint64_t)threadStart,(uint64_t)func);
}
//----------------------------------------------------------------------
// n_strcmp()
/*! String comparison
//
// \param s1 is the first string,
// \param s2 is the second one.
// \return an integer greater than, equal to, or less than 0,
// if the first string is greater than, equal to, or less than
// the the second string.
*/
//----------------------------------------------------------------------
int n_strcmp(const char *s1, const char *s2)
{
int comparaison;
int fini=0;
int i=0;
while(!fini) {
if ((s1[i]==0)&&(s2[i]==0)) {
fini=1;
comparaison=0;
}
if (s1[i]<s2[i]) {
fini=1;
comparaison=-1;
}
if(s1[i]>s2[i]) {
fini=1;
comparaison=1;
}
i++;
}
return comparaison;
}
//----------------------------------------------------------------------
// n_strcpy()
/*! String copy
//
// \param dst is where the string is to be copied,
// \param src is where the string to copy is.
// \return dst, if the copy successes, 0 otherwise
*/
//----------------------------------------------------------------------
char *n_strcpy(char *dst, const char *src)
{
int i=0;
int fini=0;
if ((dst!=0)&&(src!=0)) {
while(fini==0) {
if(src[i]=='\0') fini=1;
dst[i]=src[i];
i++;
}
return dst;
}
else return 0;
}
//----------------------------------------------------------------------
// n_strlen()
/*! Gives the number of bytes in a string, not including the
// terminating null character.
//
// \param c is a pointer onto a string.
// \return the length of the string.
*/
//----------------------------------------------------------------------
size_t n_strlen(const char *s)
{
size_t i=0;
while (s[i] != 0) i++;
return i;
}
//----------------------------------------------------------------------
// n_strcat()
/*! Appends a copy of a string, including null character, to the end
// of another string. Enough memory has to be available in the
// destination string.
//
// \param dst is a pointer onto the string where the other string
// will be appended.
// \param src is the string to append.
// \return the pointer string dst.
*/
//----------------------------------------------------------------------
char *n_strcat(char *dst, const char *src)
{
int i,j,k;
i=(int)n_strlen(dst);
j=(int)n_strlen(src);
for(k=i;k<=j+i;k++) {
dst[k]=src[k-i];
}
return dst;
}
//----------------------------------------------------------------------
// n_toupper()
/*! Gives the upper-case letter corresponding to the lower-case
// letter passed as parameter.
//
// \param c is the ASCII code of the letter to transform.
// \return the corresponding upper-case letter
*/
//----------------------------------------------------------------------
int n_toupper(int c)
{
if((c>='a')&&(c<='z'))
return c+('A'-'a');
else return c;
}
//----------------------------------------------------------------------
// n_tolower()
/*! Gives the lower-case letter corresponding to the upper-case
// letter passed as parameter
//
// \param c is the ASCII code of the letter to transform.
// \return the corresponding lower-case letter
*/
//----------------------------------------------------------------------
int n_tolower(int c)
{
if((c<='Z')&&(c>='A'))
return c+('a'-'A');
else return c;
}
//----------------------------------------------------------------------
// n_atoi()
/*! String to integer conversion.
//
// \param c is a pointer onto a string.
// \return the corresponding value
*/
//----------------------------------------------------------------------
int n_atoi(const char *str)
{
int i=0;
int fini=0;
int val=0;
int negative = 0;
if (str[i] == '-') {
negative = 1; i=1;
}
while(!fini)
{
if(str[i]==0 || str[i]<'0' || str[i]>'9')
fini=1;
else
{
val*=10;
val+=str[i]-'0';
i++;
}
}
if (negative) return(-val); else return val;
}
//----------------------------------------------------------------------
// n_memcmp()
/*! Memory comparison.
//
// \param s1 is the first memory area,
// \param s2 is the second memory area.
// \param n size in bytes of the area to be compared.
// \return an integer less than, equal to, or greater than 0,
// according as s1 is lexicographically less than, equal to,
// or greater than s2 when taken to be unsigned characters.
//
*/
//----------------------------------------------------------------------
int n_memcmp(const void *s1, const void *s2, size_t n)
{
unsigned char* c1=(unsigned char*)s1;
unsigned char* c2=(unsigned char*)s2;
int comparaison=0;
int fini=0;
int i=0;
while ((!fini)&&(i<n)) {
if (c1[i]<c2[i]) {
fini=1;
comparaison=-1;
}
if (c1[i]>c2[i]) {
fini=1;
comparaison=1;
}
i++;
}
return comparaison;
}
//----------------------------------------------------------------------
// n_memcpy()
/*! Memory copy.
//
// \param s1 is where the elements are to be copied,
// \param s2 is the memory area to copy.
// \param n size in bytes of the area to be copied.
// \return the memory area where the copy has been done.
*/
//----------------------------------------------------------------------
void *n_memcpy(void *s1, const void *s2, size_t n)
{
unsigned char* c1=(unsigned char*)s1;
unsigned char* c2=(unsigned char*)s2;
int i=0;
if ((c1!=0)&&(c2!=0)) {
while(i<n) {
c1[i]=c2[i];
i++;
}
return (void *)c1;
}
else return 0;
}
//----------------------------------------------------------------------
// n_memset()
/*! Sets the first n bytes of a memory area to a value (converted to
// an unsigned char).
//
// \param s is the memory area to transform,
// \param c is the value wanted,
// \param n is the number of bytes to put at c.
// \return s.
*/
//----------------------------------------------------------------------
void *n_memset(void *s, int c, size_t n)
{
unsigned char* c1=(unsigned char*)s;
int i;
for (i=0;i<n;i++) {
c1[i]=c;
}
return (void *)c1;
}
//----------------------------------------------------------------------
// n_dumpmem()
/*! Dumps on the string the n first bytes of a memory area
// (used for debugging)
//
// \param addr address of the memory area
// \param len number of bytes to be dumped
*/
//----------------------------------------------------------------------
void n_dumpmem(char *addr, int len)
{
#define TOHEX(x) \
({ char __x = (x); if(__x < 10) __x+='0'; else __x='a'+(__x-10) ; __x; })
int i;
for (i = 0 ; i < len ; i++) {
char s[3];
if ((i%16) == 0)
n_printf("%x\t", (unsigned long)&addr[i]);
else if ((i%8) == 0)
n_printf(" ");
s[0] = TOHEX((addr[i] >> 4) & 0xf);
s[1] = TOHEX(addr[i] & 0xf);
s[2] = '\0';
n_printf("%s ", s);
if ((((i+1)%16) == 0) || (i == len-1))
n_printf("\n");
}
}
#define PUTCHAR(carac) \
do { \
if (result < len-1) *buff++ = carac;\
result++; \
} while (0)
//----------------------------------------------------------------------
// n_vsnprintf()
/*! Build a string according to a specified format (internal function)
//
// Nachos vsnprintf accepts:
// %c to print a character,
// %s, to print a string,
// %d, to print an integer,
// %x, to print an integer in hexa
// %lx %ld same for 64-bit values
// %f, to print a floating point value
//
// \param buff the destination buffer to generate the string to
// \param len the size of buff, determines the number max of
// characters copied to buff (taking the final \0 into account)
// \param format the string to parse
// \param ap parameters to print
//
// \return the number of characters formatted (NOT including \0),
// that is, the number of characters that would have been written
// to the buffer if it were large enough. -1 on error.
*/
//----------------------------------------------------------------------
static int n_vsnprintf(char *buff, int len, const char *format, va_list ap)
{
int i, result;
if (!buff || !format || (len < 0)) {
return -1;
}
result = 0;
for (i=0 ; format[i] != '\0' ; i++) {
switch (format[i]) {
case '%':
i++;
switch(format[i]) {
case '%': {
PUTCHAR('%');
break;
}
case 'i':
case'd': {
int integer = (int) va_arg(ap,int);
int cpt2 = 0;
char buff_int[11];
if (integer<0) {PUTCHAR('-');
}
do {
int m10 = integer%10;
m10 = (m10 < 0)? -m10:m10;
buff_int[cpt2++]=(char)('0'+ m10);
integer=integer/10;
} while(integer!=0);
for (cpt2 = cpt2 - 1 ; cpt2 >= 0 ; cpt2--) {
PUTCHAR(buff_int[cpt2]);
}
break;
}
case 'l': {
i++;
switch(format[i]) {
case 'd': {
long longer = va_arg(ap,long);
int cpt2 = 0;
char buff_long[20];
if (longer<0) {
PUTCHAR('-');
}
do {
int m10 = longer%10;
m10 = (m10 < 0)? -m10:m10;
buff_long[cpt2++]=(char)('0'+ m10);
longer=longer/10;
} while(longer!=0);
for (cpt2 = cpt2 - 1 ; cpt2 >= 0 ; cpt2--) {
PUTCHAR(buff_long[cpt2]);
}
break;
}
case 'x': {
uint64_t hexa = va_arg(ap,long);
uint64_t nb;
uint32_t i, had_nonzero = 0;
for (i=0 ; i < 16 ; i++) {
nb = (hexa << (i*4));
nb = (nb >> 60);
nb = nb & 0x000000000000000f;
// Skip the leading zeros
if (nb == 0) {
if (had_nonzero) {
PUTCHAR((uint8_t)'0');
}
}
else {
had_nonzero = 1;
if (nb < 10)
PUTCHAR((uint8_t)'0'+(uint8_t)nb);
else
PUTCHAR((uint8_t)'a'+(uint8_t)(nb-10));
}
}
if (! had_nonzero)
PUTCHAR((uint8_t)'0');
break;
}
default: {
PUTCHAR('%');
PUTCHAR('l');
PUTCHAR(format[i]);
break;
}
}
break;
}
case 'c': {
int value = va_arg(ap,int);
PUTCHAR((char)value);
break;
}
case 's': {
char *string = va_arg(ap,char *);
if (! string)
string = "(null)";
for( ; *string != '\0' ; string++)
PUTCHAR(*string);
break;
}
case 'x': {
uint32_t hexa = va_arg(ap,int);
uint32_t nb;
uint32_t i, had_nonzero = 0;
for (i=0 ; i < 8 ; i++) {
nb = (hexa << (i*4));
nb = (nb >> 28);
nb = nb & 0x0000000f;
// Skip the leading zeros
if (nb == 0) {
if (had_nonzero)
PUTCHAR((uint8_t)'0');
}
else {
had_nonzero = 1;
if (nb < 10)
PUTCHAR((uint8_t)'0'+(uint8_t)nb);
else
PUTCHAR((uint8_t)'a'+(uint8_t)(nb-10));
}
}
if (! had_nonzero)
PUTCHAR((uint8_t)'0');
break;
}
/*case 'f': {
// Very simple routine to print floats as xxxx.yyyyy
// Not very good (unable to print large numbers)
// If anyone wants to re-write it, feel free ...
double f = (double) va_arg(ap,double);
int cpt2, j;
char buff_float[200];
long ient,idec;
if (f<0) {
PUTCHAR('-');
f = -f;
}
ient = (int)f;
// 100000 = print 5 digits max
idec = (int)((f - ((double)ient))*100000);
// Round up
if ( f - ((double)ient) - ((double)idec)/100000.0 >= 0.5E-5)
idec ++;
cpt2 = 0;
// Print digits after the '.'
for (j=0 ; j<5 ; j++) {
buff_float[cpt2++]=(char)('0'+(idec%10));
idec=idec/10;
}
buff_float[cpt2++] = '.';
// Print digits before the '.'
do {
buff_float[cpt2++]=(char)('0'+ (ient%10));
ient=ient/10;
} while (ient!=0);
for(j = cpt2 - 1 ; j >= 0 ; j--)
PUTCHAR(buff_float[j]);
break;
}
*/
default:
PUTCHAR('%');
PUTCHAR(format[i]);
}
break;
default:
PUTCHAR(format[i]);
}
}
*buff = '\0';
return result;
}
//----------------------------------------------------------------------
// n_snprintf()
/*! Build a string according to a specified format
//
// Nachos snprintf accepts:
// %c to print a character,
// %s, to print a string,
// %d, to print an integer,
// %x, to print a string in hexa
// %f, to print a floating point value
//
// \param buff the destination buffer to generate the string to
// \param len the size of buff, determines the number max of
// characters copied to buff (taking the final \0 into account)
// \param format the string to parse
// \param ... the (variable number of) arguments
//
// \return the number of characters formatted (NOT including \0),
// that is, the number of characters that would have been written
// to the buffer if it were large enough. -1 on error.
*/
//----------------------------------------------------------------------
int n_snprintf(char * buff, int len, const char *format, ...){
va_list ap;
va_start(ap, format);
len = n_vsnprintf(buff, len, format, ap);
va_end(ap);
return len;
}
//----------------------------------------------------------------------
// n_printf()
/*! Print to the standard output parameters.
//
// Nachos printf accepts:
// %c to print a character,
// %s, to print a string,
// %d, to print an integer,
// %x, to print a string in hexa
// %ld, %lx, same for 64-bit values
// %f, to print a floating point value
//
// \param parameters to print,
// \param type of print.
*/
//----------------------------------------------------------------------
void n_printf(const char *format, ...){
va_list ap;
char buff[200];
int len;
va_start(ap, format);
len = n_vsnprintf(buff, sizeof(buff), format, ap);
va_end(ap);
if (len >= sizeof(buff)) {
len = sizeof(buff) - 1;
}
if (len > 0) {
Write(buff,len,CONSOLE_OUTPUT);
}
}
//----------------------------------------------------------------------
// n_read_int()
/*!
// Very basic minimalist read integer function, no error
// checking...
*/
//----------------------------------------------------------------------
int n_read_int(void) {
char buff[200];
Read(buff,200,CONSOLE_INPUT);
return n_atoi(buff);
}

View File

@ -0,0 +1,87 @@
/*! \file libnachos.h
\brief Function structures for programs
Libnachos proposes several 'libc-like' functions
for:
Input-Output operations,
String operations,
Memory operations,
System calls are defined in kernel/syscalls.h
Nachos-libc functions are prefixed by 'n' to avoid
any confusion with standard libc functions.
* -----------------------------------------------------
* This file is part of the Nachos-RiscV distribution
* Copyright (c) 2022 University of Rennes 1.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details
* (see see <http://www.gnu.org/licenses/>).
* -----------------------------------------------------
*/
#include "userlib/syscall.h"
typedef void (*VoidNoArgFunctionPtr)();
typedef unsigned int size_t;
// Thread management
// ----------------------------
ThreadId threadCreate(char * debug_name, VoidNoArgFunctionPtr func);
// Input/Output operations :
// ------------------------------------
// Print on the standard output specified parameters.
void n_printf(const char *format, ...);
// Format <buff> (of max length <len>) according to the format <format>
int n_snprintf(char * buff, int len, const char *format, ...);
// Read an integer on the standard input
int n_read_int(void);
// String operations :
// -------------------
// Compare two strings byte by byte.
int n_strcmp(const char *s1, const char *s2);
// Copy a string.
char* n_strcpy(char *dst, const char *src);
// Return the number of bytes in a string.
size_t n_strlen(const char *s);
// appends a copy of a string, to the end of another string.
char* n_strcat(char *dst, const char *src);
// Return a upper-case letter,
// equivalent to the lower-case letter given.
int n_toupper(int c);
// Return a lower-case letter,
// equivalent to the upper-case letter given.
int n_tolower(int c);
// Convert a string in integer.
int n_atoi(const char *str);
// Concerning memory area operations :
// -----------------------------------
// Compare two memory area, looking at the first n bytes .
int n_memcmp(const void *s1, const void *s2, size_t n);
// Copy n byte from an memory area to another.
void* n_memcpy(void *s1, const void *s2, size_t n);
// Set the first n bytes in a memory area to a specified value.
void* n_memset(void *s, int c, size_t n);

343
test_programs/userlib/sys.s Normal file
View File

@ -0,0 +1,343 @@
/* Start.s
* Assembly language assist for user programs running on top of Nachos.
*
* Since we don't want to pull in the entire C library, we define
* what we need for a user program here, namely Start and the system
* calls.
*
* -----------------------------------------------------
* This file is part of the BurritOS distribution
* Copyright (c) 2022 University of Rennes 1.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details
* (see see <http://www.gnu.org/licenses/>).
* -----------------------------------------------------
*/
#define IN_ASM
#include "userlib/syscall.h"
// Equivalent to ".text", but with a different name, in order
// to be correctly handled by the ldscript
.section .sys,"ax",@progbits
.align 2
/* -------------------------------------------------------------
* __start
* Initialize running a C program, by calling "main".
*
* NOTE: This has to be first, so that it gets loaded at location 0.
* The Nachos kernel always starts a program by jumping to location 0.
* -------------------------------------------------------------
*/
.globl __start
.type __start, @function
__start:
/* Call the program entry point */
call main
li a0, 0
call Exit
jr ra /* if we return from main, exit(0) */
/* -------------------------------------------------------------
* System call stubs:
* Assembly language assist to make system calls to the Nachos kernel.
* There is one stub per system call, that places the code for the
* system call into register r10, and leaves the arguments to the
* system call alone (in other words, arg1 is in r12, arg2 is
* in r13, arg3 is in r14, arg4 is in r15)
*
* The return value is in r10. This follows the standard C calling
* convention on the RISC-V.
* -------------------------------------------------------------
*/
.globl Halt
.type __Halt, @function
Halt:
addi a7,zero,SC_HALT
ecall
jr ra
.globl Exit
.type __Exit, @function
Exit:
addi a7,zero,SC_EXIT
ecall
jr ra
.globl Exec
.type __Exec, @function
Exec:
addi a7,zero,SC_EXEC
ecall
jr ra
.globl Join
.type __Join, @function
Join:
addi a7,zero,SC_JOIN
ecall
jr ra
.globl Create
.type __Create, @function
Create:
addi a7,zero,SC_CREATE
ecall
jr ra
.globl Open
.type __Open, @function
Open:
addi a7,zero,SC_OPEN
ecall
jr ra
.globl Read
.type __Read, @function
Read:
addi a7,zero,SC_READ
ecall
jr ra
.globl Write
.type __Write, @function
Write:
addi a7,zero,SC_WRITE
ecall
jr ra
.globl Seek
.type __Seek, @function
Seek:
addi a7,zero,SC_SEEK
ecall
jr ra
.globl Close
.type __Close, @function
Close:
addi a7,zero,SC_CLOSE
ecall
jr ra
.globl FSList
.type __FSList, @function
FSList:
addi a7,zero,SC_FSLIST
ecall
jr ra
.globl newThread
.type __newThread, @function
newThread:
addi a7,zero,SC_NEW_THREAD
ecall
jr ra
.globl Remove
.type __Remove, @function
Remove:
addi a7,zero,SC_REMOVE
ecall
jr ra
.globl Yield
.type __Yield, @function
Yield:
addi a7,zero,SC_YIELD
ecall
jr ra
.globl PError
.type __PError, @function
PError:
addi a7,zero,SC_PERROR
ecall
jr ra
.globl P
.type __P, @function
P:
addi a7,zero,SC_P
ecall
jr ra
.globl V
.type __V, @function
V:
addi a7,zero,SC_V
ecall
jr ra
.globl SemCreate
.type __SemCreate, @function
SemCreate:
addi a7,zero,SC_SEM_CREATE
ecall
jr ra
.globl SemDestroy
.type __SemDestroy, @function
SemDestroy:
addi a7,zero,SC_SEM_DESTROY
ecall
jr ra
.globl SysTime
.type __SysTime, @function
SysTime:
addi a7,zero,SC_SYS_TIME
ecall
jr ra
.globl LockCreate
.type __LockCreate, @function
LockCreate:
addi a7,zero,SC_LOCK_CREATE
ecall
jr ra
.globl LockDestroy
.type __LockDestroy, @function
LockDestroy:
addi a7,zero,SC_LOCK_DESTROY
ecall
jr ra
.globl LockAcquire
.type __LockAquire, @function
LockAcquire:
addi a7,zero,SC_LOCK_ACQUIRE
ecall
jr ra
.globl LockRelease
.type __LockRelease, @function
LockRelease:
addi a7,zero,SC_LOCK_RELEASE
ecall
jr ra
.globl CondCreate
.type __CondCreate, @function
CondCreate:
addi a7,zero,SC_COND_CREATE
ecall
jr ra
.globl CondDestroy
.type __CondDestroy, @function
CondDestroy:
addi a7,zero,SC_COND_DESTROY
ecall
jr ra
.globl CondWait
.type __CondWait, @function
CondWait:
addi a7,zero,SC_COND_WAIT
ecall
jr ra
.globl CondSignal
.type __CondSignal, @function
CondSignal:
addi a7,zero,SC_COND_SIGNAL
ecall
jr ra
.globl CondBroadcast
.type __CondBroadcast, @function
CondBroadcast:
addi a7,zero,SC_COND_BROADCAST
ecall
jr ra
.globl TtySend
.type __TtySend, @function
TtySend:
addi a7,zero,SC_TTY_SEND
ecall
jr ra
.globl TtyReceive
.type __TtyReceive, @function
TtyReceive:
addi a7,zero,SC_TTY_RECEIVE
ecall
jr ra
.globl Mkdir
.type __Mkdir, @function
Mkdir:
addi a7,zero,SC_MKDIR
ecall
jr ra
.globl Rmdir
.type __Rmdir, @function
Rmdir:
addi a7,zero,SC_RMDIR
ecall
jr ra
.globl Mmap
.type __Mmap, @function
Mmap:
addi a7,zero,SC_MMAP
ecall
jr ra
.globl Debug
.type __Debug, @function
Debug:
addi a7,zero,SC_DEBUG
ecall
jr ra

View File

@ -0,0 +1,287 @@
/*! \file syscall.h
\brief Nachos system call interface.
These are Nachos kernel operations
that can be invoked from user programs, by trapping to the kernel
via the "syscall" instruction.
This file is included by user programs and by the Nachos kernel.
Each of these is invoked by a user program by simply calling the
procedure; an assembly language stub stuffs the system call code
into a register, and traps to the kernel. The kernel procedures
are then invoked in the Nachos kernel, after appropriate error checking,
from the system call entry point in exception.cc.
* -----------------------------------------------------
* This file is part of the Nachos-RiscV distribution
* Copyright (c) 2022 University of Rennes 1.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details
* (see see <http://www.gnu.org/licenses/>).
* -----------------------------------------------------
*/
#ifndef SYSCALLS_H
#define SYSCALLS_H
//#include "kernel/copyright.h"
/* system call codes -- used by the stubs to tell the kernel which system call
* is being asked for
*/
#define SC_HALT 0
#define SC_EXIT 1
#define SC_EXEC 2
#define SC_JOIN 3
#define SC_CREATE 4
#define SC_OPEN 5
#define SC_READ 6
#define SC_WRITE 7
#define SC_SEEK 8
#define SC_CLOSE 9
#define SC_NEW_THREAD 10
#define SC_YIELD 11
#define SC_PERROR 12
#define SC_P 13
#define SC_V 14
#define SC_SEM_CREATE 15
#define SC_SEM_DESTROY 16
#define SC_LOCK_CREATE 17
#define SC_LOCK_DESTROY 18
#define SC_LOCK_ACQUIRE 19
#define SC_LOCK_RELEASE 20
#define SC_COND_CREATE 21
#define SC_COND_DESTROY 22
#define SC_COND_WAIT 23
#define SC_COND_SIGNAL 24
#define SC_COND_BROADCAST 25
#define SC_TTY_SEND 26
#define SC_TTY_RECEIVE 27
#define SC_MKDIR 28
#define SC_RMDIR 29
#define SC_REMOVE 30
#define SC_FSLIST 31
#define SC_SYS_TIME 32
#define SC_MMAP 33
#define SC_DEBUG 34
#ifndef IN_ASM
/* The system call interface. These are the operations the Nachos
* kernel needs to support, to be able to run user programs.
*
*/
typedef int t_error;
/* Stop Nachos, and print out performance stats */
void Halt();
/* Return the time spent running Nachos */
/*! \brief Defines the Nachos basic time unit */
typedef struct {
long seconds;
long nanos;
} Nachos_Time;
void SysTime(Nachos_Time *t);
/* Address space control operations: Exit, Exec, and Join */
/* This user program is done (status = 0 means exited normally). */
void Exit(int status);
/* A unique identifier for a thread executed within a user program */
typedef unsigned long ThreadId;
/* Run the executable, stored in the Nachos file "name", and return the
* master thread identifier
*/
ThreadId Exec(char *name);
/* Create a new thread in the current process
* Return thread identifier
*/
ThreadId newThread(char * debug_name, int func, int arg);
/* Only return once the the thread "id" has finished.
*/
t_error Join(ThreadId id);
/* Yield the CPU to another runnable thread, whether in this address space
* or not.
*/
void Yield();
/*! Print the last error message with the personalized one "mess" */
void PError(char *mess);
/* File system operations: Create, Open, Read, Write, Seek, Close
* These functions are patterned after UNIX -- files represent
* both files *and* hardware I/O devices.
*
* If this assignment is done before doing the file system assignment,
* note that the Nachos file system has a stub implementation, which
* will work for the purposes of testing out these routines.
*/
/* A unique identifier for an open Nachos file. */
typedef unsigned long OpenFileId;
/* when an address space starts up, it has two open files, representing
* keyboard input and display output (in UNIX terms, stdin and stdout).
* Read and Write can be used directly on these, without first opening
* the console device.
*/
#define CONSOLE_INPUT 0
#define CONSOLE_OUTPUT 1
/* Create a Nachos file, with "name" */
t_error Create(char *name,int size);
/* Open the Nachos file "name", and return an "OpenFileId" that can
* be used to read and write to the file.
*/
OpenFileId Open(char *name);
/* Write "size" bytes from "buffer" to the open file. */
t_error Write(char *buffer, int size, OpenFileId id);
/* Read "size" bytes from the open file into "buffer".
* Return the number of bytes actually read -- if the open file isn't
* long enough, or if it is an I/O device, and there aren't enough
* characters to read, return whatever is available (for I/O devices,
* you should always wait until you can return at least one character).
*/
t_error Read(char *buffer, int size, OpenFileId id);
/* Seek to a specified offset into an opened file */
t_error Seek(int offset, OpenFileId id);
#ifndef SYSDEP_H
/* Close the file, we're done reading and writing to it. */
t_error Close(OpenFileId id);
#endif // SYSDEP_H
/* Remove the file */
t_error Remove(char* name);
/******************************************************************/
/* system calls concerning directory management */
/* Create a new repertory
Return a negative number if an error ocurred.
*/
t_error Mkdir(char* name);
/* Destroy a repertory, which must be empty.
Return a negative number if an error ocurred.
*/
t_error Rmdir(char* name);
/* List the content of NachOS FileSystem */
t_error FSList();
/******************************************************************/
/* User-level synchronization operations : */
/* System calls concerning semaphores management */
typedef unsigned long SemId;
/* Create a semaphore, initialising it at count.
Return a Semid, which will enable to do operations on this
semaphore */
SemId SemCreate(char * debug_name, int count);
/* Destroy a semaphore identified by sema.
Return a negative number if an error occured during the destruction */
t_error SemDestroy(SemId sema);
/* Do the operation P() on the semaphore sema */
t_error P(SemId sema);
/* Do the operation V() on the semaphore sema */
t_error V(SemId sema);
/* System calls concerning locks management */
typedef unsigned long LockId;
/* Create a lock.
Return an identifier */
LockId LockCreate(char * debug_name);
/* Destroy a lock.
Return a negative number if an error ocurred
during the destruction. */
t_error LockDestroy(LockId id);
/* Do the operation Acquire on the lock id.
Return a negative number if an error ocurred. */
t_error LockAcquire(LockId id);
/* Do the operation Release on the lock id.
Return a negative number if an error ocurred.
*/
t_error LockRelease(LockId id);
/* System calls concerning conditions variables. */
typedef unsigned long CondId;
/* Create a new condition variable */
CondId CondCreate(char * debug_name);
/* Destroy a condition variable.
Return a negative number if an error ocurred.
*/
t_error CondDestroy(CondId id);
/* Do the operation Wait on a condition variable.
Returns a negative number if an error ocurred.
*/
t_error CondWait(CondId cond);
/* Do the operation Signal on a condition variable (wake up only one thread).
Return a negative number if an error ocurred.
*/
t_error CondSignal(CondId cond);
/* Do the operation Signal on a condition variable (wake up all threads).
Return a negative number if an error ocurred.
*/
t_error CondBroadcast(CondId cond);
/******************************************************************/
/* System calls concerning serial port and console */
/* Send the message on the serial communication link.
Returns the number of bytes successfully sent.
*/
int TtySend(char *mess);
/* Wait for a message comming from the serial communication link.
The length of the buffer where the bytes will be copied is given as a parameter.
Returns the number of characters actually received.
*/
int TtyReceive(char *mess,int length);
/* Map an opened file in memory. Size is the size to be mapped in bytes.
*/
void *Mmap(OpenFileId f, int size);
/* For debug purpose
*/
void Debug(int param);
#endif // IN_ASM
#endif // SYSCALL_H