diff options
author | Freya Murphy <freya@freyacat.org> | 2025-03-25 17:36:52 -0400 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2025-03-25 17:38:22 -0400 |
commit | 6af21e6a4f2251e71353562d5df7f376fdffc270 (patch) | |
tree | de20c7afc9878422c81e34f30c6b010075e9e69a /lib | |
download | comus-6af21e6a4f2251e71353562d5df7f376fdffc270.tar.gz comus-6af21e6a4f2251e71353562d5df7f376fdffc270.tar.bz2 comus-6af21e6a4f2251e71353562d5df7f376fdffc270.zip |
initial checkout from wrc
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Make.mk | 73 | ||||
-rw-r--r-- | lib/bound.c | 37 | ||||
-rw-r--r-- | lib/cvtdec.c | 43 | ||||
-rw-r--r-- | lib/cvtdec0.c | 44 | ||||
-rw-r--r-- | lib/cvthex.c | 49 | ||||
-rw-r--r-- | lib/cvtoct.c | 54 | ||||
-rw-r--r-- | lib/cvtuns.c | 37 | ||||
-rw-r--r-- | lib/cvtuns0.c | 39 | ||||
-rw-r--r-- | lib/entry.S | 25 | ||||
-rw-r--r-- | lib/klibc.c | 112 | ||||
-rw-r--r-- | lib/memclr.c | 37 | ||||
-rw-r--r-- | lib/memcpy.c | 41 | ||||
-rw-r--r-- | lib/memset.c | 38 | ||||
-rw-r--r-- | lib/pad.c | 35 | ||||
-rw-r--r-- | lib/padstr.c | 61 | ||||
-rw-r--r-- | lib/sprint.c | 133 | ||||
-rw-r--r-- | lib/str2int.c | 51 | ||||
-rw-r--r-- | lib/strcat.c | 38 | ||||
-rw-r--r-- | lib/strcmp.c | 32 | ||||
-rw-r--r-- | lib/strcpy.c | 35 | ||||
-rw-r--r-- | lib/strlen.c | 32 | ||||
-rw-r--r-- | lib/ulibc.c | 162 | ||||
-rw-r--r-- | lib/ulibs.S | 93 |
23 files changed, 1301 insertions, 0 deletions
diff --git a/lib/Make.mk b/lib/Make.mk new file mode 100644 index 0000000..2f8de2c --- /dev/null +++ b/lib/Make.mk @@ -0,0 +1,73 @@ +# +# Makefile fragment for the library components of the system. +# +# THIS IS NOT A COMPLETE Makefile - run GNU make in the top-level +# directory, and this will be pulled in automatically. +# + +SUBDIRS += lib + +################### +# FILES SECTION # +################### + +# +# library file lists +# + +# "common" library functions, used by kernel and users +CLIB_SRC := lib/bound.c lib/cvtdec.c lib/cvtdec0.c \ + lib/cvthex.c lib/cvtoct.c lib/cvtuns.c \ + lib/cvtuns0.c lib/memclr.c lib/memcpy.c \ + lib/memset.c lib/pad.c lib/padstr.c \ + lib/sprint.c lib/str2int.c lib/strcat.c \ + lib/strcmp.c lib/strcpy.c lib/strlen.c + +# user-only library functions +ULIB_SRC := lib/ulibc.c lib/ulibs.S lib/entry.S + +# kernel-only library functions +KLIB_SRC := lib/klibc.c + +# lists of object files +CLIB_OBJ:= $(patsubst lib/%.c, $(BUILDDIR)/lib/%.o, $(CLIB_SRC)) + +ULIB_OBJ:= $(patsubst lib/%.c, $(BUILDDIR)/lib/%.o, $(ULIB_SRC)) +ULIB_OBJ:= $(patsubst lib/%.S, $(BUILDDIR)/lib/%.o, $(ULIB_OBJ)) + +KLIB_OBJ := $(patsubst lib/%.c, $(BUILDDIR)/lib/%.o, $(KLIB_SRC)) +KLIB_OBJ := $(patsubst lib/%.S, $(BUILDDIR)/lib/%.o, $(KLIB_OBJ)) + +# library file names +CLIB_NAME := libcommon.a +ULIB_NAME := libuser.a +KLIB_NAME := libkernel.a + +################### +# RULES SECTION # +################### + +# how to make everything +lib: $(BUILDDIR)/lib/$(CLIB_NAME) \ + $(BUILDDIR)/lib/$(KLIB_NAME) \ + $(BUILDDIR)/lib/$(ULIB_NAME) + +$(BUILDDIR)/lib/%.o: lib/%.c $(BUILDDIR)/.vars.CFLAGS + @mkdir -p $(@D) + $(CC) $(CFLAGS) -c -o $@ $< + +$(BUILDDIR)/lib/%.o: lib/%.S $(BUILDDIR)/.vars.CFLAGS + @mkdir -p $(@D) + $(CPP) $(CPPFLAGS) -o $(@D)/$*.s $< + $(AS) $(ASFLAGS) -o $@ $(@D)/$*.s -a=$(@D)/$*.lst + $(RM) -f $(@D)/$*.s + $(NM) -n $@ > $(@D)/$*.sym + +$(BUILDDIR)/lib/$(CLIB_NAME): $(CLIB_OBJ) + $(AR) $(ARFLAGS) $@ $(CLIB_OBJ) + +$(BUILDDIR)/lib/$(ULIB_NAME): $(ULIB_OBJ) + $(AR) $(ARFLAGS) $@ $(ULIB_OBJ) + +$(BUILDDIR)/lib/$(KLIB_NAME): $(KLIB_OBJ) + $(AR) $(ARFLAGS) $@ $(KLIB_OBJ) diff --git a/lib/bound.c b/lib/bound.c new file mode 100644 index 0000000..f086473 --- /dev/null +++ b/lib/bound.c @@ -0,0 +1,37 @@ +/** +** @file bound.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef BOUND_SRC_INC +#define BOUND_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** bound(min,value,max) +** +** This function confines an argument within specified bounds. +** +** @param min Lower bound +** @param value Value to be constrained +** @param max Upper bound +** +** @return The constrained value +*/ +uint32_t bound( uint32_t min, uint32_t value, uint32_t max ) { + if( value < min ){ + value = min; + } + if( value > max ){ + value = max; + } + return value; +} + +#endif diff --git a/lib/cvtdec.c b/lib/cvtdec.c new file mode 100644 index 0000000..216f147 --- /dev/null +++ b/lib/cvtdec.c @@ -0,0 +1,43 @@ +/** +** @file cvtdec.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef CVTDEC_SRC_INC +#define CVTDEC_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** cvtdec(buf,value) +** +** convert a 32-bit signed value into a NUL-terminated character string +** +** @param buf Destination buffer +** @param value Value to convert +** +** @return The number of characters placed into the buffer +** (not including the NUL) +** +** NOTE: assumes buf is large enough to hold the resulting string +*/ +int cvtdec( char *buf, int32_t value ) { + char *bp = buf; + + if( value < 0 ) { + *bp++ = '-'; + value = -value; + } + + bp = cvtdec0( bp, value ); + *bp = '\0'; + + return( bp - buf ); +} + +#endif diff --git a/lib/cvtdec0.c b/lib/cvtdec0.c new file mode 100644 index 0000000..87792e0 --- /dev/null +++ b/lib/cvtdec0.c @@ -0,0 +1,44 @@ +/** +** @file cvtdec0.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef CVTDEC0_SRC_INC +#define CVTDEC0_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** cvtdec0(buf,value) - local support routine for cvtdec() +** +** convert a 32-bit unsigned integer into a NUL-terminated character string +** +** @param buf Destination buffer +** @param value Value to convert +** +** @return The number of characters placed into the buffer +** (not including the NUL) +** +** NOTE: assumes buf is large enough to hold the resulting string +*/ +char *cvtdec0( char *buf, int value ) { + int quotient; + + quotient = value / 10; + if( quotient < 0 ) { + quotient = 214748364; + value = 8; + } + if( quotient != 0 ) { + buf = cvtdec0( buf, quotient ); + } + *buf++ = value % 10 + '0'; + return buf; +} + +#endif diff --git a/lib/cvthex.c b/lib/cvthex.c new file mode 100644 index 0000000..5f3da19 --- /dev/null +++ b/lib/cvthex.c @@ -0,0 +1,49 @@ +/** +** @file cvthex.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef CVTHEX_SRC_INC +#define CVTHEX_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** cvthex(buf,value) +** +** convert a 32-bit unsigned value into a minimal-length (up to +** 8-character) NUL-terminated character string +** +** @param buf Destination buffer +** @param value Value to convert +** +** @return The number of characters placed into the buffer +** (not including the NUL) +** +** NOTE: assumes buf is large enough to hold the resulting string +*/ +int cvthex( char *buf, uint32_t value ) { + const char hexdigits[] = "0123456789ABCDEF"; + int chars_stored = 0; + + for( int i = 0; i < 8; i += 1 ) { + uint32_t val = value & 0xf0000000; + if( chars_stored || val != 0 || i == 7 ) { + ++chars_stored; + val = (val >> 28) & 0xf; + *buf++ = hexdigits[val]; + } + value <<= 4; + } + + *buf = '\0'; + + return( chars_stored ); +} + +#endif diff --git a/lib/cvtoct.c b/lib/cvtoct.c new file mode 100644 index 0000000..dafd8ff --- /dev/null +++ b/lib/cvtoct.c @@ -0,0 +1,54 @@ +/** +** @file cvtoct.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef CVTOCT_SRC_INC +#define CVTOCT_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** cvtoct(buf,value) +** +** convert a 32-bit unsigned value into a mininal-length (up to +** 11-character) NUL-terminated character string +** +** @param buf Destination buffer +** @param value Value to convert +** +** @return The number of characters placed into the buffer +** (not including the NUL) +** +** NOTE: assumes buf is large enough to hold the resulting string +*/ +int cvtoct( char *buf, uint32_t value ) { + int i; + int chars_stored = 0; + char *bp = buf; + uint32_t val; + + val = ( value & 0xc0000000 ); + val >>= 30; + for( i = 0; i < 11; i += 1 ){ + + if( i == 10 || val != 0 || chars_stored ) { + chars_stored = 1; + val &= 0x7; + *bp++ = val + '0'; + } + value <<= 3; + val = ( value & 0xe0000000 ); + val >>= 29; + } + *bp = '\0'; + + return bp - buf; +} + +#endif diff --git a/lib/cvtuns.c b/lib/cvtuns.c new file mode 100644 index 0000000..a0a686a --- /dev/null +++ b/lib/cvtuns.c @@ -0,0 +1,37 @@ +/** +** @file cvtuns.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef CVTUNS_SRC_INC +#define CVTUNS_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** cvtuns(buf,value) +** +** Convert a 32-bit unsigned value into a NUL-terminated character string +** +** @param buf Result buffer +** @param value Value to be converted +** +** @return Length of the resulting buffer +** +** NOTE: assumes buf is large enough to hold the resulting string +*/ +int cvtuns( char *buf, uint32_t value ) { + char *bp = buf; + + bp = cvtuns0( bp, value ); + *bp = '\0'; + + return bp - buf; +} + +#endif diff --git a/lib/cvtuns0.c b/lib/cvtuns0.c new file mode 100644 index 0000000..6a63573 --- /dev/null +++ b/lib/cvtuns0.c @@ -0,0 +1,39 @@ +/** +** @file cvtuns0.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef CVTUNS0_SRC_INC +#define CVTUNS0_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** cvtuns0(buf,value) - local support routine for cvtuns() +** +** Convert a 32-bit unsigned value into a NUL-terminated character string +** +** @param buf Result buffer +** @param value Value to be converted +** +** @return Pointer to the first unused byte in the buffer +** +** NOTE: assumes buf is large enough to hold the resulting string +*/ +char *cvtuns0( char *buf, uint32_t value ) { + uint32_t quotient; + + quotient = value / 10; + if( quotient != 0 ){ + buf = cvtdec0( buf, quotient ); + } + *buf++ = value % 10 + '0'; + return buf; +} + +#endif diff --git a/lib/entry.S b/lib/entry.S new file mode 100644 index 0000000..87ad9c7 --- /dev/null +++ b/lib/entry.S @@ -0,0 +1,25 @@ +// +// user-level startup routine +// + .text + .globl _start + .globl main + .globl exit + +// entry point - this is where the kernel starts us running +_start: + // we immediately call main() + call main + + // if we come back from that, it means the user + // program didn't call exit(), in which case the + // value returned from main() is the exit status + + // push that value onto the stack and call exit() + subl $12, %esp + pushl %eax + call exit + + // if we come back from that, something bad has + // happened, so we just lock up +1: jmp 1b diff --git a/lib/klibc.c b/lib/klibc.c new file mode 100644 index 0000000..ded0c78 --- /dev/null +++ b/lib/klibc.c @@ -0,0 +1,112 @@ +/* +** @file klibc.c +** +** @author Warren R. Carithers +** +** Additional support functions for the kernel. +** +*/ + +#define KERNEL_SRC + +#include <klib.h> +#include <cio.h> +#include <procs.h> +#include <support.h> + +/** +** Name: put_char_or_code( ch ) +** +** Description: Prints a character on the console, unless it +** is a non-printing character, in which case its hex code +** is printed +** +** @param ch The character to be printed +*/ +void put_char_or_code( int ch ) { + + if( ch >= ' ' && ch < 0x7f ) { + cio_putchar( ch ); + } else { + cio_printf( "\\x%02x", ch ); + } +} + +/** +** Name: backtrace +** +** Perform a stack backtrace +** +** @param ebp Initial EBP to use +** @param args Number of function argument values to print +*/ +void backtrace( uint32_t *ebp, uint_t args ) { + + cio_puts( "Trace: " ); + if( ebp == NULL ) { + cio_puts( "NULL ebp, no trace possible\n" ); + return; + } else { + cio_putchar( '\n' ); + } + + while( ebp != NULL ){ + + // get return address and report it and EBP + uint32_t ret = ebp[1]; + cio_printf( " ebp %08x ret %08x args", (uint32_t) ebp, ret ); + + // print the requested number of function arguments + for( uint_t i = 0; i < args; ++i ) { + cio_printf( " [%u] %08x", i+1, ebp[2+i] ); + } + cio_putchar( '\n' ); + + // follow the chain + ebp = (uint32_t *) *ebp; + } +} + +/** +** kpanic - kernel-level panic routine +** +** usage: kpanic( msg ) +** +** Prefix routine for panic() - can be expanded to do other things +** (e.g., printing a stack traceback) +** +** @param msg[in] String containing a relevant message to be printed, +** or NULL +*/ +void kpanic( const char *msg ) { + + cio_puts( "\n\n***** KERNEL PANIC *****\n\n" ); + + if( msg ) { + cio_printf( "%s\n", msg ); + } + + delay( DELAY_5_SEC ); // approximately + + // dump a bunch of potentially useful information + + // dump the contents of the current PCB + pcb_dump( "Current", current, true ); + + // dump the basic info about what's in the process table + ptable_dump_counts(); + + // dump information about the queues + pcb_queue_dump( "R", ready, true ); + pcb_queue_dump( "W", waiting, true ); + pcb_queue_dump( "S", sleeping, true ); + pcb_queue_dump( "Z", zombie, true ); + pcb_queue_dump( "I", sioread, true ); + + // perform a stack backtrace + backtrace( (uint32_t *) r_ebp(), 3 ); + + // could dump other stuff here, too + + panic( "KERNEL PANIC" ); +} diff --git a/lib/memclr.c b/lib/memclr.c new file mode 100644 index 0000000..490fc6d --- /dev/null +++ b/lib/memclr.c @@ -0,0 +1,37 @@ +/** +** @file memclr.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef MEMCLR_SRC_INC +#define MEMCLR_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** memclr(buf,len) +** +** Initialize all bytes of a block of memory to zero +** +** @param buf The buffer to initialize +** @param len Buffer size (in bytes) +*/ +void memclr( void *buf, register uint32_t len ) { + register uint8_t *dest = buf; + + /* + ** We could speed this up by unrolling it and clearing + ** words at a time (instead of bytes). + */ + + while( len-- ) { + *dest++ = 0; + } +} + +#endif diff --git a/lib/memcpy.c b/lib/memcpy.c new file mode 100644 index 0000000..e5add26 --- /dev/null +++ b/lib/memcpy.c @@ -0,0 +1,41 @@ +/** +** @file memcpy.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef MEMCPY_SRC_INC +#define MEMCPY_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** memcpy(dst,src,len) +** +** Copy a block from one place to another +** +** May not correctly deal with overlapping buffers +** +** @param dst Destination buffer +** @param src Source buffer +** @param len Buffer size (in bytes) +*/ +void memcpy( void *dst, register const void *src, register uint32_t len ) { + register uint8_t *dest = dst; + register const uint8_t *source = src; + + /* + ** We could speed this up by unrolling it and copying + ** words at a time (instead of bytes). + */ + + while( len-- ) { + *dest++ = *source++; + } +} + +#endif diff --git a/lib/memset.c b/lib/memset.c new file mode 100644 index 0000000..a93815c --- /dev/null +++ b/lib/memset.c @@ -0,0 +1,38 @@ +/** +** @file memset.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef MEMSET_SRC_INC +#define MEMSET_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** memset(buf,len,value) +** +** initialize all bytes of a block of memory to a specific value +** +** @param buf The buffer to initialize +** @param len Buffer size (in bytes) +** @param value Initialization value +*/ +void memset( void *buf, register uint32_t len, register uint32_t value ) { + register uint8_t *bp = buf; + + /* + ** We could speed this up by unrolling it and copying + ** words at a time (instead of bytes). + */ + + while( len-- ) { + *bp++ = value; + } +} + +#endif diff --git a/lib/pad.c b/lib/pad.c new file mode 100644 index 0000000..5220c99 --- /dev/null +++ b/lib/pad.c @@ -0,0 +1,35 @@ +/** +** @file pad.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef PAD_SRC_INC +#define PAD_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** pad(dst,extra,padchar) - generate a padding string +** +** @param dst Pointer to where the padding should begin +** @param extra How many padding bytes to add +** @param padchar What character to pad with +** +** @return Pointer to the first byte after the padding +** +** NOTE: does NOT NUL-terminate the buffer +*/ +char *pad( char *dst, int extra, int padchar ) { + while( extra > 0 ){ + *dst++ = (char) padchar; + extra -= 1; + } + return dst; +} + +#endif diff --git a/lib/padstr.c b/lib/padstr.c new file mode 100644 index 0000000..b83229f --- /dev/null +++ b/lib/padstr.c @@ -0,0 +1,61 @@ +/** +** @file padstr.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef PADSTR_SRC_INC +#define PADSTR_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** padstr(dst,str,len,width,leftadjust,padchar - add padding characters +** to a string +** +** @param dst The destination buffer +** @param str The string to be padded +** @param len The string length, or -1 +** @param width The desired final length of the string +** @param leftadjust Should the string be left-justified? +** @param padchar What character to pad with +** +** @return Pointer to the first byte after the padded string +** +** NOTE: does NOT NUL-terminate the buffer +*/ +char *padstr( char *dst, char *str, int len, int width, + int leftadjust, int padchar ) { + int extra; + + // determine the length of the string if we need to + if( len < 0 ){ + len = strlen( str ); + } + + // how much filler must we add? + extra = width - len; + + // add filler on the left if we're not left-justifying + if( extra > 0 && !leftadjust ){ + dst = pad( dst, extra, padchar ); + } + + // copy the string itself + for( int i = 0; i < len; ++i ) { + *dst++ = str[i]; + } + + // add filler on the right if we are left-justifying + if( extra > 0 && leftadjust ){ + dst = pad( dst, extra, padchar ); + } + + return dst; +} + +#endif diff --git a/lib/sprint.c b/lib/sprint.c new file mode 100644 index 0000000..d2e0a7e --- /dev/null +++ b/lib/sprint.c @@ -0,0 +1,133 @@ +/** +** @file sprint.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef SPRINT_SRC_INC +#define SPRINT_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** sprint(dst,fmt,...) - formatted output into a string buffer +** +** @param dst The string buffer +** @param fmt Format string +** +** The format string parameter is followed by zero or more additional +** parameters which are interpreted according to the format string. +** +** NOTE: assumes the buffer is large enough to hold the result string +** +** NOTE: relies heavily on the x86 parameter passing convention +** (parameters are pushed onto the stack in reverse order as +** 32-bit values). +*/ +void sprint( char *dst, char *fmt, ... ) { + int32_t *ap; + char buf[ 12 ]; + char ch; + char *str; + int leftadjust; + int width; + int len; + int padchar; + + /* + ** Get characters from the format string and process them + ** + ** We use the "old-school" method of handling variable numbers + ** of parameters. We assume that parameters are passed on the + ** runtime stack in consecutive longwords; thus, if the first + ** parameter is at location 'x', the second is at 'x+4', the + ** third at 'x+8', etc. We use a pointer to a 32-bit thing + ** to point to the next "thing", and interpret it according + ** to the format string. + */ + + // get the pointer to the first "value" parameter + ap = (int *)(&fmt) + 1; + + // iterate through the format string + while( (ch = *fmt++) != '\0' ){ + /* + ** Is it the start of a format code? + */ + if( ch == '%' ){ + /* + ** Yes, get the padding and width options (if there). + ** Alignment must come at the beginning, then fill, + ** then width. + */ + leftadjust = 0; + padchar = ' '; + width = 0; + ch = *fmt++; + if( ch == '-' ){ + leftadjust = 1; + ch = *fmt++; + } + if( ch == '0' ){ + padchar = '0'; + ch = *fmt++; + } + while( ch >= '0' && ch <= '9' ){ + width *= 10; + width += ch - '0'; + ch = *fmt++; + } + + /* + ** What data type do we have? + */ + switch( ch ) { + + case 'c': // characters are passed as 32-bit values + ch = *ap++; + buf[ 0 ] = ch; + buf[ 1 ] = '\0'; + dst = padstr( dst, buf, 1, width, leftadjust, padchar ); + break; + + case 'd': + len = cvtdec( buf, *ap++ ); + dst = padstr( dst, buf, len, width, leftadjust, padchar ); + break; + + case 's': + str = (char *) (*ap++); + dst = padstr( dst, str, -1, width, leftadjust, padchar ); + break; + + case 'x': + len = cvthex( buf, *ap++ ); + dst = padstr( dst, buf, len, width, leftadjust, padchar ); + break; + + case 'o': + len = cvtoct( buf, *ap++ ); + dst = padstr( dst, buf, len, width, leftadjust, padchar ); + break; + + case 'u': + len = cvtuns( buf, *ap++ ); + dst = padstr( dst, buf, len, width, leftadjust, padchar ); + break; + + } + } else { + // no, it's just an ordinary character + *dst++ = ch; + } + } + + // NUL-terminate the result + *dst = '\0'; +} + +#endif diff --git a/lib/str2int.c b/lib/str2int.c new file mode 100644 index 0000000..c0f777d --- /dev/null +++ b/lib/str2int.c @@ -0,0 +1,51 @@ +/** +** @file str2int.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef STR2INT_SRC_INC +#define STR2INT_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** str2int(str,base) - convert a string to a number in the specified base +** +** @param str The string to examine +** @param base The radix to use in the conversion +** +** @return The converted integer +*/ +int str2int( register const char *str, register int base ) { + register int num = 0; + register char bchar = '9'; + int sign = 1; + + // check for leading '-' + if( *str == '-' ) { + sign = -1; + ++str; + } + + if( base != 10 ) { + bchar = '0' + base - 1; + } + + // iterate through the characters + while( *str ) { + if( *str < '0' || *str > bchar ) + break; + num = num * base + *str - '0'; + ++str; + } + + // return the converted value + return( num * sign ); +} + +#endif diff --git a/lib/strcat.c b/lib/strcat.c new file mode 100644 index 0000000..b0a8726 --- /dev/null +++ b/lib/strcat.c @@ -0,0 +1,38 @@ +/** +** @file strcat.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef STRCAT_SRC_INC +#define STRCAT_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** strcat(dst,src) - append one string to another +** +** @param dst The destination buffer +** @param src The source buffer +** +** @return The dst parameter +** +** NOTE: assumes dst is large enough to hold the resulting string +*/ +char *strcat( register char *dst, register const char *src ) { + register char *tmp = dst; + + while( *dst ) // find the NUL + ++dst; + + while( (*dst++ = *src++) ) // append the src string + ; + + return( tmp ); +} + +#endif diff --git a/lib/strcmp.c b/lib/strcmp.c new file mode 100644 index 0000000..c59f4f7 --- /dev/null +++ b/lib/strcmp.c @@ -0,0 +1,32 @@ +/** +** @file strcmp.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef STRCMP_SRC_INC +#define STRCMP_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** strcmp(s1,s2) - compare two NUL-terminated strings +** +** @param s1 The first source string +** @param s2 The second source string +** +** @return negative if s1 < s2, zero if equal, and positive if s1 > s2 +*/ +int strcmp( register const char *s1, register const char *s2 ) { + + while( *s1 != 0 && (*s1 == *s2) ) + ++s1, ++s2; + + return( *s1 - *s2 ); +} + +#endif diff --git a/lib/strcpy.c b/lib/strcpy.c new file mode 100644 index 0000000..036e4be --- /dev/null +++ b/lib/strcpy.c @@ -0,0 +1,35 @@ +/** +** @file strcpy.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef STRCPY_SRC_INC +#define STRCPY_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** strcpy(dst,src) - copy a NUL-terminated string +** +** @param dst The destination buffer +** @param src The source buffer +** +** @return The dst parameter +** +** NOTE: assumes dst is large enough to hold the copied string +*/ +char *strcpy( register char *dst, register const char *src ) { + register char *tmp = dst; + + while( (*dst++ = *src++) ) + ; + + return( tmp ); +} + +#endif diff --git a/lib/strlen.c b/lib/strlen.c new file mode 100644 index 0000000..b41fe69 --- /dev/null +++ b/lib/strlen.c @@ -0,0 +1,32 @@ +/** +** @file strlen.c +** +** @author Numerous CSCI-452 classes +** +** @brief C implementations of common library functions +*/ + +#ifndef STRLEN_SRC_INC +#define STRLEN_SRC_INC + +#include <common.h> + +#include <lib.h> + +/** +** strlen(str) - return length of a NUL-terminated string +** +** @param str The string to examine +** +** @return The length of the string, or 0 +*/ +uint32_t strlen( register const char *str ) { + register uint32_t len = 0; + + while( *str++ ) { + ++len; + } + + return( len ); +} +#endif diff --git a/lib/ulibc.c b/lib/ulibc.c new file mode 100644 index 0000000..f3783a4 --- /dev/null +++ b/lib/ulibc.c @@ -0,0 +1,162 @@ +/** +** @file ulibc.c +** +** @author CSCI-452 class of 20245 +** +** @brief C implementations of user-level library functions +*/ + +#include <common.h> + +/* +** PRIVATE DEFINITIONS +*/ + +/* +** PRIVATE DATA TYPES +*/ + +/* +** PRIVATE GLOBAL VARIABLES +*/ + +/* +** PUBLIC GLOBAL VARIABLES +*/ + +/* +** PRIVATE FUNCTIONS +*/ + +/* +** PUBLIC FUNCTIONS +*/ + +/* +********************************************** +** CONVENIENT "SHORTHAND" VERSIONS OF SYSCALLS +********************************************** +*/ + +/** +** wait - wait for any child to exit +** +** usage: pid = wait(&status) +** +** Calls waitpid(0,status) +** +** @param status Pointer to int32_t into which the child's status is placed, +** or NULL +** +** @returns The PID of the terminated child, or an error code +*/ +int wait( int32_t *status ) { + return( waitpid(0,status) ); +} + +/** +** spawn - create a new process running a different program +** +** usage: pid = spawn(what,args); +** +** Creates a new process and then execs 'what' +** +** @param what The program table index of the program to spawn +** @param args The command-line argument vector for the new process +** +** @returns PID of the new process, or an error code +*/ +int32_t spawn( uint_t what, char **args ) { + int32_t pid; + char buf[256]; + + pid = fork(); + if( pid != 0 ) { + // failure, or we are the parent + return( pid ); + } + + // we are the child + pid = getpid(); + + // child inherits parent's priority level + + exec( what, args ); + + // uh-oh.... + + sprint( buf, "Child %d exec() #%u failed\n", pid, what ); + cwrites( buf ); + + exit( EXIT_FAILURE ); + return( 0 ); // shut the compiler up +} + +/** +** cwritech(ch) - write a single character to the console +** +** @param ch The character to write +** +** @returns The return value from calling write() +*/ +int cwritech( char ch ) { + return( write(CHAN_CIO,&ch,1) ); +} + +/** +** cwrites(str) - write a NUL-terminated string to the console +** +** @param str The string to write +** +*/ +int cwrites( const char *str ) { + int len = strlen(str); + return( write(CHAN_CIO,str,len) ); +} + +/** +** cwrite(buf,size) - write a sized buffer to the console +** +** @param buf The buffer to write +** @param size The number of bytes to write +** +** @returns The return value from calling write() +*/ +int cwrite( const char *buf, uint32_t size ) { + return( write(CHAN_CIO,buf,size) ); +} + +/** +** swritech(ch) - write a single character to the SIO +** +** @param ch The character to write +** +** @returns The return value from calling write() +*/ +int swritech( char ch ) { + return( write(CHAN_SIO,&ch,1) ); +} + +/** +** swrites(str) - write a NUL-terminated string to the SIO +** +** @param str The string to write +** +** @returns The return value from calling write() +*/ +int swrites( const char *str ) { + int len = strlen(str); + return( write(CHAN_SIO,str,len) ); +} + +/** +** swrite(buf,size) - write a sized buffer to the SIO +** +** @param buf The buffer to write +** @param size The number of bytes to write +** +** @returns The return value from calling write() +*/ +int swrite( const char *buf, uint32_t size ) { + return( write(CHAN_SIO,buf,size) ); +} diff --git a/lib/ulibs.S b/lib/ulibs.S new file mode 100644 index 0000000..46fcb89 --- /dev/null +++ b/lib/ulibs.S @@ -0,0 +1,93 @@ +/** +** @file ulibs.S +** +** @author CSCI-452 class of 20245 +** +** @brief assembly-language user-level library functions +*/ + +#define ASM_SRC + +// get the system call codes + +#include <syscalls.h> + +/** +** System call stubs +** +** All have the same structure: +** +** move a code into EAX +** generate the interrupt +** return to the caller +** +** As these are simple "leaf" routines, we don't use +** the standard enter/leave method to set up a stack +** frame - that takes time, and we don't really need it. +** +** Could be modified to use the UNIX/Linux convention of +** having the syscall code set the 'C' flag to indicate that +** the value being returned in %EAX is an error code: +** +** ... +** int $VEC_SYSCALL +** jc set_errno +** ret +** ... +** +** .globl errno +** set_errno: +** movl %eax, errno +** movl $-1, %eax +** ret +*/ + +#define SYSCALL(name) \ + .globl name ; \ +name: ; \ + movl $SYS_##name, %eax ; \ + int $VEC_SYSCALL ; \ + ret + +/* +** "real" system calls +*/ + +SYSCALL(exit) +SYSCALL(waitpid) +SYSCALL(fork) +SYSCALL(exec) +SYSCALL(read) +SYSCALL(write) +SYSCALL(getpid) +SYSCALL(getppid) +SYSCALL(gettime) +SYSCALL(getprio) +SYSCALL(setprio) +SYSCALL(kill) +SYSCALL(sleep) + +/* +** This is a bogus system call; it's here so that we can test +** our handling of out-of-range syscall codes in the syscall ISR. +*/ +SYSCALL(bogus) + +/* +** Other library functions +*/ + +/** +** fake_exit() +** +** Dummy "startup" function +** +** calls exit(%eax) - serves as the "return to" code for +** main() functions, in case they don't call exit() themselves +*/ + + .globl fake_exit +fake_exit: + // alternate: could push a "fake exit" status + pushl %eax // termination status returned by main() + call exit // terminate this process |