Initial commit

This commit is contained in:
Yatis 2020-09-17 19:27:01 +02:00
commit 8fac0c2272
71 changed files with 6439 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
build

178
configure vendored Executable file
View file

@ -0,0 +1,178 @@
#! /bin/bash
# output file
confile='fxlibc.cfg'
# Build options
toolchain=sh-elf
prefix=
cflags=
# wanted Makefile
makefile='Makefile.default'
# configuration
declare -A config
config[__SUPPORT_VHEX_KERNEL]=false
config[__DEBUG]=false
config[__ENABLE_VALGRIND]=false
config[__SUPPORT_CASIO_ABI_FX9860]=false
config[__SUPPORT_CASIO_ABI_FXCG50]=false
#
# Help screen
#
help()
{
cat << EOF
Configuration script for the fx calculator libc.
Usage: $0 [OPTION]...
You should build out-of-tree by creating a build directory and configuring from
there.
Debug the fxlibc
--debug enable valgrind flags (-g3)
--unit-test check C-functoon validity with Criterion
Build options:
--toolchain=TRIPLET Build with a different toolchain
[sh-elf-gcc] (or [gcc] when the '--unit_test' flag is set)
--cflags=FLAGS Additional compiler flags at end of command
ABI support:
--vhex-support Enable the Vhex kernel support
--casio-support=fx9860|fxcg50
enable the support of the Casio' ABI (used by malloc, free, ...)
fx9860 covers all fx-9860G II-like monochromes models that support add-ins
or can be flashed with an OS that does. This includes SH3 and SH4 machines.
fxcg50 covers just the fx-CG 50; there is some unofficial compatibility with
fx-CG 10/20. All of these are SH4-only.
The 'ABI support' is used to allow some part of the code, in particular the 'unistd'
part, I/O management and additionnal feature (process, fs, ...).
Format:
--dyn-lib generate dynamic librairies (Vhex kernel dependant)
Little note for the generation of dynamic libraries.
The superH toolchain currently used (GCC) does not support the '--shared' flags
when the archive is build. So we need to create manually an archive that can be
used like a shared librairy.
To do this we need to do several steps:
1) build the sources with the PIE mode as if it were a executable without entry point.
2) manually extract symbols defined as 'global' from the generated ELF.
3) we create "stubs": functions that will have the same name than the wanted
shared librairies and will call internal VHEX loader primitives with the
librairies name, function address and size, etc....Then the loader will
load the shared function and override the "user function (stub)" to force
it to jump into the "real" function (trampoline)
4) all generated stubs will be compiled and linked throught a static lib that
SHOULD be used in the user program which use the "dynamic librairy"
EOF
exit 0
}
#
# Check mandatory build location
# @note:
# * You should build out-of-tree by creating a build directory and configuring
# from there.
#
if [ -f 'make/Makefile.default' ]; then
echo "error: you should configure from a build directory, like this:" >&2
echo " mkdir build && cd build && ../configure [options..]" >&2
exit 1
fi
#
# Parsing arguments
#
for arg; do case "$arg" in
--help | -h)
help;;
--debug)
config[__DEBUG]=true;;
--unit-test)
makefile='Malefile.unitest';;
--toolchain=*)
toolchain=${arg#*=};;
--prefix=*)
prefix=${arg#*=};;
--cflags=*)
cflags=${arg#*=};;
--vhex-support)
config[__SUPPORT_VHEX_KERNEL]=true;;
--casio-abi=*)
case ${arg#*=} in
"fx9860g")
config[__SUPPORT_CASIO_ABI_FX9860]=true;;
"fcg50")
config[__SUPPORT_CASIO_ABI_FXCG50]=true;;
*)
echo -e "\033[1;33merror\033[0m unreconized target '$arg'"
exit 1
esac;;
--dyn-lib)
makefile='Makefile.dynlib';;
*)
echo -e "\033[1;33merror\033[0m unreconized argument '$arg'"
exit 1
esac; done
#
# Check error
#
if [ ${config[__SUPPORT_CASIO_ABI_FX9860]} = true ] && [ ${config[__SUPPORT_CASIO_ABI_FXCG50]} = true ]; then
echo -e "\033[1;33merror\033[0m too many target"
exit 1
fi
#
# Dump appropriate Makefile
# @note:
# * We have 3 makefile: normal, dynlib, unit_test
#
dst='Makefile'
src="../make/$makefile"
if ! test $src; then
echo -e "\033[1;33merror\033[0m target makefile ($src) does not exist !"
exit 1
fi
[ -L $src ] && [ "$(readlink $src)" == $dst ] && rm $dst
ln -s $src $dst
#
# Generate the configuration file
#
function generate_config()
{
echo "CONFIG.TOOLCHAIN = $toolchain"
[ "$prefix" ] && echo "PREFIX = $prefix"
[ "$cflags" ] && echo "CONFIG.CFLAGS = $cflags"
[ ${config[__DEBUG]} = true ] && echo -n '-g3'
[ ${config[__SUPPORT_VHEX_KERNEL]} = true ] && echo -n ' -D __SUPPORT_VHEX_KERNEL'
[ ${config[__SUPPORT_CASIO_ABI_FX9860]} = true ] && echo -n ' -D ___SUPPORT_CASIO_ABI_FX9860'
[ ${config[__SUPPORT_CASIO_ABI_FXCG50]} = true ] && echo -n ' -D ___SUPPORT_CASIO_ABI_FXCG50'
echo ''
}
generate_config > $confile
echo "Configuration saved in $confile, ready to make!"
exit 0

45
include/asm/unistd_32.h Normal file
View file

@ -0,0 +1,45 @@
#ifndef __ASM_UNISTD_32_H__
# define __ASM_UNISTD_32_H__
// Define the number of syscall
#define __NR_MAX 21
// Kernel Test
#define __NR_test_syscall 0
// Process
#define __NR_exit 1
#define __NR_fork_execve 2 // (custom)
#define __NR_waitpid 3
#define __NR_wait 4
#define __NR_getpid 5
#define __NR_getppid 6
#define __NR_getpgid 7
#define __NR_setpgid 8
// Signal
#define __NR_signal 9
#define __NR_sigreturn 10
#define __NR_sigaction 11
#define __NR_kill 12
#define __NR_sigprogmask 13
#define __NR_sigpending 14
#define __NR_sigaltstack 15
// VFS
#define __NR_read 16
#define __NR_write 17
#define __NR_open 18
#define __NR_close 19
#define __NR_lseek 20
#define __NR_pread 21
#define __NR_pwrite 22
// Memory
#define __NR_mmap 23
#define __NR_munmap 24
#define __NR_proc_heap_alloc 25 // (custom)
#define __NR_proc_heap_free 26 // (custom)
#define __NR_proc_heap_realloc 27 // (custom)
#endif /*__ASM_UNISTD_32_H__*/

50
include/bits/signum.h Normal file
View file

@ -0,0 +1,50 @@
#ifndef __LIB_BITS_SIGNUM_H__
# define __LIB_BITS_SIGNUM_H__
// Define the number of signals
#define NSIG 32
// Vhex kernel internal define used to indicate
// if the signal is implemented or not
#define __SIGUNDEF ((__sighandler_t) -2) /* Not implemented */
/* Fake signal functions. */
#define SIG_ERR ((__sighandler_t) -1) /* Error return. */
#define SIG_DFL ((__sighandler_t) 0) /* Default action. */
#define SIG_IGN ((__sighandler_t) 1) /* Ignore signal. */
/* ISO C99 signals. */
#define SIGINT 2 /* Interactive attention signal. */
#define SIGILL 4 /* Illegal instruction. */
#define SIGABRT 6 /* Abnormal termination. */
#define SIGFPE 8 /* Erroneous arithmetic operation. */
#define SIGSEGV 11 /* Invalid access to storage. */
#define SIGTERM 15 /* Termination request. */
/* Historical signals specified by POSIX. */
#define SIGHUP 1 /* Hangup. */
#define SIGQUIT 3 /* Quit. */
#define SIGTRAP 5 /* Trace/breakpoint trap. */
#define SIGKILL 9 /* Killed. */
#define SIGBUS 10 /* Bus error. */
#define SIGSYS 12 /* Bad system call. */
#define SIGPIPE 13 /* Broken pipe. */
#define SIGALRM 14 /* Alarm clock. */
/* New(er) POSIX signals (1003.1-2008, 1003.1-2013). */
#define SIGURG 16 /* Urgent data is available at a socket. */
#define SIGSTOP 17 /* Stop, unblockable. */
#define SIGTSTP 18 /* Keyboard stop. */
#define SIGCONT 19 /* Continue. */
#define SIGCHLD 20 /* Child terminated or stopped. */
#define SIGTTIN 21 /* Background read from control terminal. */
#define SIGTTOU 22 /* Background write to control terminal. */
#define SIGPOLL 23 /* Pollable event occurred (System V). */
#define SIGXCPU 24 /* CPU time limit exceeded. */
#define SIGXFSZ 25 /* File size limit exceeded. */
#define SIGVTALRM 26 /* Virtual timer expired. */
#define SIGPROF 27 /* Profiling timer expired. */
#define SIGUSR1 30 /* User-defined signal 1. */
#define SIGUSR2 31 /* User-defined signal 2. */
#endif /*__LIB_BITS_SIGNUM_H__*/

View file

@ -0,0 +1,9 @@
#ifndef __LIB_BITS_TYPES_FILE_H__
# define __LIB_BITS_TYPES_FILE_H__
struct _IO_FILE;
/* The opaque type of streams. This is the definition used elsewhere. */
typedef struct _IO_FILE FILE;
#endif /*__LIB_BITS_TYPES_FILE_H__*/

View file

@ -0,0 +1,7 @@
#ifndef __LIB_BITS_TYPES___FILE_H__
# define __LIB_BITS_TYPES___FILE_H__
struct _IO_FILE;
typedef struct _IO_FILE __FILE;
#endif /*__LIB_BITS_TYPES___FILE_H__*/

View file

@ -0,0 +1,23 @@
#ifndef __FILE_H__
# define __FILE_H__
#include <stdint.h>
#include <stddef.h>
#include <sys/types.h>
//TODO: remove me !!!
#include <kernel/bits/filesystem.h>
// Define _IO_FILE
// TODO: add open flags
// TODO: add file descriptor ?
// TODO: update me !
struct _IO_FILE
{
off_t cursor;
int permission;
struct file_operations *file_op;
void *private;
};
#endif /*__FILE_H__*/

9
include/bits/waitflags.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef __LIB_BITS_WAITFLAGS_H__
# define __LIB_BITS_WAITFLAGS_H__
/* Bits in the third argument to `waitpid'. */
#define WNOHANG 1 /* Don't block waiting. */
#define WUNTRACED 2 /* Report status of stopped child. */
#define WCONTINUED 3 /* Report continued child. */
#endif /*__LIB_BITS_WAITFLAGS_H__*/

35
include/bits/waitstatus.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef __LIB_BITS_WAITSTATUS_H__
# define __LIB_BITS_WAITSTATUS_H__
/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */
#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)
/* If WIFSIGNALED(STATUS), the terminating signal. */
#define __WTERMSIG(status) ((status) & 0x7f)
/* If WIFSTOPPED(STATUS), the signal that stopped the child. */
#define __WSTOPSIG(status) __WEXITSTATUS(status)
/* Nonzero if STATUS indicates normal termination. */
#define __WIFEXITED(status) (__WTERMSIG(status) == 0)
/* Nonzero if STATUS indicates termination by a signal. */
#define __WIFSIGNALED(status) \
(((signed char) (((status) & 0x7f) + 1) >> 1) > 0)
/* Nonzero if STATUS indicates the child is stopped. */
#define __WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
/* Nonzero if STATUS indicates the child continued after a stop. */
# define __WIFCONTINUED(status) ((status) == __W_CONTINUED)
/* Nonzero if STATUS indicates the child dumped core. */
#define __WCOREDUMP(status) ((status) & __WCOREFLAG)
/* Macros for constructing status values. */
#define __W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
#define __W_STOPCODE(sig) ((sig) << 8 | 0x7f)
#define __W_CONTINUED 0xffff
#define __WCOREFLAG 0x80
#endif /*__LIB_BITS_WAITSTATUS_H__*/

65
include/display.h Normal file
View file

@ -0,0 +1,65 @@
#ifndef __LIB_DISPLAY_H__
# define __LIB_DISPLAY_H__
#include <stddef.h>
#include <stdint.h>
// Internal struct used in each draw function
typedef struct display_s
{
uint32_t vram[256];
struct font_s *font;
struct {
size_t width;
size_t height;
} display;
// Internal pre-calculated value
int nb_char_width;
} display_t;
// Internal struct used to define font structure object.
// TODO: move me ?
struct font_s
{
// Bitmap informations
struct {
uint8_t width;
uint8_t height;
uint8_t cwidth;
uint8_t cheight;
uint8_t *raw;
} bitmap;
// Character information
struct {
uint8_t width;
uint8_t height;
} font;
};
// Internal struct used to draw
// the ASCII character.
struct font_block_s
{
int16_t height;
int16_t width;
struct {
uint16_t x;
uint16_t y;
} bitmap;
int16_t x;
int16_t y;
};
// Draw primitives
extern int dopen(display_t *disp, const char *fontname);
extern void dclear(display_t *disp);
extern void dascii(display_t *disp, int row, int colomn, char const c, int mode);
extern size_t dprint(display_t *disp, int x, int y, char const *str, ...);
extern void dscroll(display_t *disp, int line);
extern void dreverse(display_t *disp, int x, int y, int width, int height);
extern void drect(display_t *disp, int x, int y, int width, int height);
extern void dupdate(display_t *disp);
#endif /*__LIB_DISPLAY_H__*/

4026
include/elf.h Normal file

File diff suppressed because it is too large Load diff

156
include/errno.h Normal file
View file

@ -0,0 +1,156 @@
#ifndef __KERNEL_ERRNO_H__
# define __KERNEL_ERRNO_H__ 1
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
/*
* This error code is special: arch syscall entry code will return
* -ENOSYS if users try to call a syscall that doesn't exist. To keep
* failures of syscalls that really do exist distinguishable from
* failures due to attempts to use a nonexistent syscall, syscall
* implementations should refrain from returning -ENOSYS.
*/
#define ENOSYS 38 /* Invalid system call number */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define ENOTSUP EOPNOTSUPP /* Not supported (may be the same value as [EOPNOTSUPP]) */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ECANCELED 125 /* Operation Canceled */
#define ENOKEY 126 /* Required key not available */
#define EKEYEXPIRED 127 /* Key has expired */
#define EKEYREVOKED 128 /* Key has been revoked */
#define EKEYREJECTED 129 /* Key was rejected by service */
/* for robust mutexes */
#define EOWNERDEAD 130 /* Owner died */
#define ENOTRECOVERABLE 131 /* State not recoverable */
#define ERFKILL 132 /* Operation not possible due to RF-kill */
#define EHWPOISON 133 /* Memory page has hardware error */
#endif /* __KERNEL_ERRNO_H__ */

20
include/fcntl.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef __LIB_FCNTL_H__
# define __LIB_FCNTL_H__
#include <stddef.h>
#include <stdint.h>
//TODO: update me !!
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2
//TODO: define also in <stdio.h>
#define SEEK_SET 0 /* Seek from beginning of file. */
#define SEEK_CUR 1 /* Seek from current position. */
#define SEEK_END 2 /* Seek from end of file. */
// Functions
extern int open(const char *pathname, int flags, ...);
#endif /*__LIB_FCNTL_H__*/

30
include/setjmp.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef __LIB_SETJMP_H__
# define __LIB_SETJMP_H__
#include <stddef.h>
#include <stdint.h>
// Real jmp_buf struct
// @note: save only r8 ~ r15 and SR / PC registers
// The SR register is saved first because the longjump can be involved with
// differentregister bank. So to avoid this it's more simple to restore the
// saved SR first then restore all register (see <lib/libc/setjmp/longjmp.S>)
struct __jmp_buf
{
uint32_t sr;
uint32_t reg[8];
uint32_t gbr;
uint32_t macl;
uint32_t mach;
uint32_t pr;
};
// User jmp_buf alias
typedef struct __jmp_buf jmp_buf[1];
// Functions
extern int setjmp(jmp_buf env);
extern void longjmp(jmp_buf env, int val);
#endif /*__LIB_SETJMP_H__*/

26
include/signal.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef __LIB_SIGNAL_H__
# define __LIB_SIGNAL_H__
#include <stddef.h>
#include <stdint.h>
#include <bits/signum.h>
// Type of a signal handler
typedef void (*__sighandler_t)(int);
typedef __sighandler_t sighandler_t;
// Type of signal set
typedef uint32_t sigset_t;
typedef uint32_t kernel_sigset_t;
// Define sigprocmask() value for "how" argument
#define SIG_BLOCK 0
#define SIG_UNBLOCK 1
#define SIG_SETMASK 2
// Prototype
// TODO: doc
extern int kill(pid_t pid, int sig);
extern void (*signal(int signum, void (*handler)(int)))(int);
#endif /*__LIB_SIGNAL_H__*/

78
include/stdio.h Normal file
View file

@ -0,0 +1,78 @@
#ifndef __LIB_STDIO_H__
# define __LIB_STDIO_H__
#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>
/* *printf() familly - formatted output conversion. */
extern int printf(const char *restrict format, ...);
extern int dprintf(int fd, const char *restrict format, ...);
extern int sprintf(char *restrict str, const char *restrict format, ...);
extern int snprintf(char *restrict str, size_t size, const char *restrict format, ...);
extern int vdprintf(int fd, const char *restrict format, va_list ap);
extern int vsprintf(char *restrict str, const char *restrict format, va_list ap);
extern int vsnprintf(char *restrict str, size_t size, const char *restrict format, va_list ap);
/* putx() - display char / string */
extern int putchar(int c);
extern int puts(const char *s);
//---
// Internal part
// TODO: move me ?
//---
#define PRINTF_INTERNAL_BUFFER_SIZE 32
struct printf_opt
{
// Internal buffer to avoid syscall flux
char buffer[PRINTF_INTERNAL_BUFFER_SIZE];
size_t buffer_cursor;
// Common part
int counter;
va_list ap;
// *dprintf part
int fd;
// *sprintf part
char *str;
size_t str_size;
// For string / fd common support
void (*disp_char)(struct printf_opt *opt, char n);
void (*disp_fflush)(struct printf_opt *opt);
// Printf-options
struct {
uint8_t diez : 1;
uint8_t zero : 1;
uint8_t minus : 1;
uint8_t space : 1;
uint8_t plus : 1;
uint8_t const : 3;
} flags;
int width;
int precision;
int uppercase;
int lenght;
// Internal format management.
char sign;
char base[2];
char format[32];
int digits;
};
// Internal symbols used to define all actions possibility
extern void (*action[26])(struct printf_opt *opt, char n);
#endif /*__LIB_STDIO_H__*/

30
include/stdlib.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef __LIB_STDLIB_H__
# define __LIB_STDLIB_H__
#include <stddef.h>
#include <stdint.h>
#define HEAP_BLOCK_MIN (16)
struct heap_block
{
uint16_t status; /* status of the block (1=used,0=free) */
uint16_t size; /* size of the block (without block header) */
} __attribute__((packed, aligned(2)));
struct heap_page
{
void *brk; /* break (address of the limit area) */
size_t size; /* Page size (without header) */
struct heap_page *next; /* Next heap page */
struct heap_block heap; /* Start of block informations */
} __attribute__((packed, aligned(4)));
// Functions
extern void *malloc(size_t size);
extern void *calloc(size_t nmemb, size_t size);
extern void *realloc(void *ptr, size_t size);
extern void *reallocarray(void *ptr, size_t nmemb, size_t size);
extern void free(void *ptr);
#endif /*__LIB_STDLIB_H__*/

32
include/string.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef __STRING_H__
# define __STRING_H__
#include <stdint.h>
#include <stddef.h>
/* memset() - fill memory with a constant byte. */
extern void *memset(void *s, int c, size_t n);
extern void *memcpy(void *dest, const void *src, size_t n);
/* strcat() - concatenate two string */
extern char *strcat(char *dest, char const *src);
/* strcmp() - compare two strings */
extern int strcmp(const char *s1, const char *s2);
extern int strncmp(const char *s1, const char *s2, size_t n);
/* strcpy(), strncpy() - copy a string. */
extern char *strncpy(char *dest, char const *str, size_t size);
extern char *strcpy(char *dest, char const *src);
/* strlen - calculate the lenght of a string. */
extern size_t strnlen(char const *str, size_t maxlen);
extern size_t strlen(char const *str);
/* strrchr() - find the last occurent of a byte */
extern char *strrchr(const char *s, int c);
/* strdup() - dump string */
extern char *strdup(const char *s);
#endif /*__STRING_H__*/

44
include/sys/mman.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef __LIB_SYS_MMAN_H__
# define __LIB_SYS_MMAN_H__
#include <stddef.h>
#include <stdint.h>
#ifndef __KERNEL_MEMORY_H__
// mapping flags
// Protection (unused)
#define PROT_READ 0x1 /* Page can be read. */
#define PROT_WRITE 0x2 /* Page can be written. */
#define PROT_EXEC 0x4 /* Page can be executed. */
#define PROT_NONE 0x0 /* Page can not be accessed. */
// Mapping flags
#define MAP_SHARED 0x01 /* Share changes. */
#define MAP_PRIVATE 0x02 /* Changes are private. */
#define MAP_ANONYMOUS 0x20 /* Don't use a file. */
#define MAP_ANON MAP_ANONYMOUS /* Don't use a file. */
#define MAP_FILE 0 /* Ignored. */
#define MAP_GROWSDOWN 0x00100 /* Stack-like segment. */
#define MAP_DENYWRITE 0x00800 /* ETXTBSY. */
#define MAP_EXECUTABLE 0x01000 /* Mark it as an executable. */
#define MAP_LOCKED 0x02000 /* Lock the mapping. */
#define MAP_NORESERVE 0x04000 /* Don't check for reservations. */
#define MAP_POPULATE 0x08000 /* Populate (prefault) pagetables. */
#define MAP_NONBLOCK 0x10000 /* Do not block on IO. */
#define MAP_STACK 0x20000 /* Allocation is for a stack. */
#define MAP_HUGETLB 0x40000 /* Create huge page mapping. */
#define MAP_SYNC 0x80000 /* Perform synchronous page
faults for the mapping. */
#define MAP_FIXED_NOREPLACE 0x100000 /* MAP_FIXED but do not unmap
underlying mapping. */
#define MAP_UNINITIALIZED 0x200000 /* Don't clear anonymous page */
// Value returned when mmap value
#define MAP_FAILED ((void*) -1)
#endif
// Prototype
extern void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
extern int munmap(void *addr, size_t length);
#endif /*__LIB_SYS_MMAN_H__*/

1
include/sys/signal.h Normal file
View file

@ -0,0 +1 @@
#include <signal.h>

41
include/sys/stat.h Normal file
View file

@ -0,0 +1,41 @@
#ifndef __KERNEL_FS_STAT_H__
# define __KERNEL_FS_STAT_H__
/* File types. */
#define __S_IFMT 0170000 /* These bits determine file type. */
#define __S_IFDIR 0040000 /* Directory. */
#define __S_IFCHR 0020000 /* Character device. */
#define __S_IFBLK 0060000 /* Block device. */
#define __S_IFREG 0100000 /* Regular file. */
#define __S_IFIFO 0010000 /* FIFO. */
#define __S_IFLNK 0120000 /* Symbolic link. */
#define __S_IFSOCK 0140000 /* Socket. */
/* Protection bits. */
#define __S_ISUID 0004000 /* Set user ID on execution. */
#define __S_ISGID 0002000 /* Set group ID on execution. */
#define __S_ISVTX 0001000 /* Save swapped text after use (sticky). */
#define __S_IREAD 0000400 /* Read by owner. */
#define __S_IWRITE 0000200 /* Write by owner. */
#define __S_IEXEC 0000100 /* Execute by owner. */
#define S_IRUSR __S_IREAD /* Read by owner. */
#define S_IWUSR __S_IWRITE /* Write by owner. */
#define S_IXUSR __S_IEXEC /* Execute by owner. */
/* Read, write, and execute by owner. */
#define S_IRWXU (__S_IREAD|__S_IWRITE|__S_IEXEC)
#define S_IRGRP (S_IRUSR >> 3) /* Read by group. */
#define S_IWGRP (S_IWUSR >> 3) /* Write by group. */
#define S_IXGRP (S_IXUSR >> 3) /* Execute by group. */
/* Read, write, and execute by group. */
#define S_IRWXG (S_IRWXU >> 3)
#define S_IROTH (S_IRGRP >> 3) /* Read by others. */
#define S_IWOTH (S_IWGRP >> 3) /* Write by others. */
#define S_IXOTH (S_IXGRP >> 3) /* Execute by others. */
/* Read, write, and execute by others. */
#define S_IRWXO (S_IRWXG >> 3)
#endif /*__KERNEL_FS_STAT_H__*/

12
include/sys/syscall.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef __LIB_SYS_SYSCALL_H__
# define __LIB_SYS_SYSCALL_H__
#include <stddef.h>
#include <stdint.h>
// include Vhex kernel real syscall
#include <asm/unistd_32.h>
//TODO include Casio's syscall !!
#endif /*__LIB_SYS_SYSCALL_H__*/

25
include/sys/types.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef __TYPES_H__
# define __TYPES_H__
#include <stddef.h>
#include <stdint.h>
// Define properly off_t type.
# ifndef __off_t_defined
typedef uint32_t off_t;
# define __off_t_defined
# endif
// Define properly ssize_t type.
#ifndef __ssize_t_defined
typedef int32_t ssize_t;
# define __ssize_t_defined
#endif
// Define alias
typedef int32_t pid_t;
typedef int16_t mode_t;
typedef uint16_t dev_t;
typedef uint16_t umode_t;
#endif /*__TYPES_H__*/

24
include/sys/wait.h Normal file
View file

@ -0,0 +1,24 @@
#ifndef __LIB_SYS_WAIT_H__
# define __LIB_SYS_WAIT_H__
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#include <bits/waitflags.h>
#include <bits/waitstatus.h>
/* Macros for the `waitpid`'s wstatus argument. */
#define WEXITSTATUS(status) __WEXITSTATUS(status)
#define WTERMSIG(status) __WTERMSIG(status)
#define WSTOPSIG(status) __WSTOPSIG(status)
#define WIFEXITED(status) __WIFEXITED(status)
#define WIFSIGNALED(status) __WIFSIGNALED(status)
#define WIFSTOPPED(status) __WIFSTOPPED(status)
#define WIFCONTINUED(status) __WIFCONTINUED(status)
#define WCOREDUMP(status) __WCOREDUMP(status)
// Wait process
extern pid_t waitpid(pid_t pid, int *wstatus, int options);
extern pid_t wait(int *wstatus);
#endif /*__LIB_SYS_WAIT_H__*/

1
include/syscall.h Normal file
View file

@ -0,0 +1 @@
#include <sys/syscall.h>

62
include/threads.h Normal file
View file

@ -0,0 +1,62 @@
#ifndef __LIB_PTHREAD_H__
# define __LIB_PTHREAD_H__
#include <stddef.h>
#include <stdint.h>
// Define Mutex type
enum
{
mtx_plain = 0,
mtx_recursive = 1,
mtx_timed = 2
};
// Define mutex structure
#define MTX_WATERMARK (0xdeadbeef)
struct __mtx_s
{
uint32_t __watermark;
uint16_t lock;
uint8_t type;
} __attribute__((packed, aligned(4)));
typedef struct __mtx_s mtx_t;
//
// Mutex functions
//
// Creates a new mutex object with type __TYPE.
// @note: If successful the new object is pointed by __MUTEX.
extern int mtx_init(mtx_t *__mutex, int __type);
// Block the current thread until the mutex pointed to by __MUTEX is unlocked.
// In that case current thread will not be blocked.
extern int mtx_lock(mtx_t *__mutex);
// Try to lock the mutex pointed by __MUTEX without blocking.
// @note: If the mutex is free the current threads takes control of it,
// otherwise it returns immediately.
extern int mtx_trylock(mtx_t *__mutex);
// Unlock the mutex pointed by __MUTEX.
// @note: It may potentially awake other threads waiting on this mutex.
extern int mtx_unlock (mtx_t *__mutex);
// Destroy the mutex object pointed by __MUTEX.
extern void mtx_destroy(mtx_t *__mutex);
//
// Atomic operations
//
// Save the current SR register and set the SR.BIT bit up (start atomic operations)
// @note: return the saved SR register (if has been saved), 0xffffffff otherwise.
extern uint32_t __thread_atomic_start(void);
// Restore the saved SR register
// @note: return the restored SR register or -1 otherwise.
extern uint32_t __thread_atomic_stop(void);
#endif /*__LIB_PTHREAD_H__*/

36
include/unistd.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef __LIB_UNISTD_H__
# define __LIB_UNISTD_H__
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
// TODO: move me
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
//TODO: move me
#define _SC_PAGE_SIZE 0
#define _SC_PAGESIZE _SC_PAGE_SIZE
// Process part
extern pid_t getpid(void);
extern pid_t getpgid(void);
extern pid_t getppid(void);
extern int setpgid(pid_t pid, pid_t pgid);
// CUSTOM function (fork() + exeve()) !
extern pid_t fork_execve(const char *pathname, char **argv, char **envp);
// File part
extern ssize_t write(int fd, const void *buf, size_t count);
extern ssize_t read(int fd, void *buf, size_t count);
extern off_t lseek(int fd, off_t offset, int whence);
extern int close(int fd);
// System part
extern long sysconf(int name);
#endif /*__LIB_UNISTD_H__*/

168
make/Makefile.default Normal file
View file

@ -0,0 +1,168 @@
#! /usr/bin/make -f
#---
#
# fxlibc project Makefile
#
# This makefile is grandly inspired by the Gint unikernel
# projet, many thanks to Lephenixnoir !
#
# Build architecture:
# build/
# |-- objects/
# | |-- string_strlen.o
# | |-- string_strcmp.o
# | ...
# | `-- signal_kill.o
# |-- debug/
# | |-- fxlibc.map (ELF link map informations)
# | ...
# | `-- otherinfo.txt
# |-- Makefile
# |-- fxlibc.cfg
# `-- bin/
# |-- fxlibc_stubs.a (workaround for the shared librairie, see documentation note)
# |-- fxlibc.so (shared librairy)
# `-- fxlibc.a (static librairy)
#---
#---
# Build configuration
#---
# Require configuration file (if you want to clean up and lost the file, you
# can either reconfigure or just delete the build directory)
CONFIG := fxlibc.cfg
ifeq "$(wildcard $(CONFIG))" ""
$(error "config file $(CONFIG) does not exist (reconfigure or wipe directory)")
endif
include $(CONFIG)
# Compiler flags, assembler flags, dependency generation, archiving
header := -I ../include
cflags := $(machine) -ffreestanding -nostdlib -Wall -Wextra -std=c11 -Os \
-fstrict-volatile-bitfields $(header) $(CONFIG.CFLAGS)
# color definition
red := \033[1;31m
green := \033[1;32m
blue := \033[1;34m
white := \033[1;37m
nocolor := \033[1;0m
# This is a workaround to force a newline when the "eval" keyword is involved
define n
# Force newline character
endef
# Define all directory used to stored informations
dir_objects := objects
dir_bin := bin
# Output configurations
name := fxlibc
target := $(dir_bin)/$(name).a
# automated variable
src :=
directory := $(shell find ../src/ -not -path "*/\.*" -type d)
$(foreach path,$(directory),$(eval \
src += $(wildcard $(path)/*.c) $n\
src += $(wildcard $(path)/*.S) $n\
src += $(wildcard $(path)/*.s) $n\
))
obj := $(patsubst .._src_%,$(dir_objects)/%.o,$(subst /,_,$(basename $(src))))
# check if any file have been found
ifeq ($(obj),)
$(error "source file does not exist (reconfigure or wipe directory)")
endif
#---
# Toolchain
#---
gcc = $(CONFIG.TOOLCHAIN)-gcc
as = $(CONFIG.TOOLCHAIN)-as
ld = $(CONFIG.TOOLCHAIN)-ld
ar = $(CONFIG.TOOLCHAIN)-ar
objcopy = $(CONFIG.TOOLCHAIN)-objcopy
#---
# Version management
#---
# TODO
#---
# Build rules
#---
all: $(target)
# linker part
$(target): $(obj) | $(dir_bin)
$(ar) crs $@ $^
# Directory management
$(dir_bin) $(dir_objects):
@ printf "Create $(blue)$@$(nocolor) directory\n"
@ mkdir -p $@
.PHONY: all
#---
# Automated rules
#---
define rule-src
$(patsubst .._src_%,$(dir_objects)/%.o,$(subst /,_,$(basename $1))): $1 | $(dir_objects)
@ printf "compiling $(white)$$<$(nocolor)..."
@ $(gcc) $(cflags) -o $$@ -c $$< -lgcc
@ printf "$(green)[ok]$(nocolor)\n"
endef
$(foreach source,$(src),$(eval \
$(call rule-src,$(source))) \
)
#---
# Debugging rules
#---
help:
@ echo 'make [options]...'
@ echo ''
@ echo 'Options:'
@ echo ' * disasm use objdump to display the content of the archive'
@ echo ' * debug display source files name and objects name'
@ echo ' * elf_sec display ELF section of the archive'
__debug:
@ echo 'src: $(src)'
@ echo ''
@ echo 'obj: $(obj)'
@ echo ''
@ echo 'directory: $(dir_bin) $(dir_output) $(dir_objects)'
disasm:
@ $(objdump) -D $(target) | less
elf_sec:
@ $(objdump) -h $(target) | less
.PHONY: help __debug disasm elf_sec
#---
# clean rules
#---
clean:
rm -rf $(dir_objects)
fclean: clean
rm -rf $(dir_bin)
re: fclean clean
.PHONY: clean fclean re

54
src/setjmp/longjmp.S Normal file
View file

@ -0,0 +1,54 @@
.text
.global _longjmp
.type _longjmp, @function
.align 2
/*
** void longjmp(jmp_buf env, int val)
** @note: TODO
*/
_longjmp:
! save the context into unbankable register
mov r4, r8
! check the returned value validity
tst r5, r5
bf/s int_block
mov r5, r9
mov #1, r9
! block interrupt
int_block:
stc sr, r1
mov #0x10, r2
shll8 r2
shll16 r2
or r2, r1
ldc r1, sr
context_switch:
! load the old SR regsiter first to force register bank switch
! (if needed) then move the context and the returned value into
! non-saved (by the setjmp context) registers.
ldc.l @r8+, sr
mov r8, r4
mov r9, r0
! restore all old registers
mov.l @r4+, r8
mov.l @r4+, r9
mov.l @r4+, r10
mov.l @r4+, r11
mov.l @r4+, r12
mov.l @r4+, r13
mov.l @r4+, r14
mov.l @r4+, r15
ldc.l @r4+, gbr
lds.l @r4+, macl
lds.l @r4+, mach
lds.l @r4+, pr
! return to the old place
rts
nop

43
src/setjmp/setjmp.S Normal file
View file

@ -0,0 +1,43 @@
.text
.global _setjmp
.type _setjmp, @function
.align 2
/*
** int setjmp(jmp_buf env)
** @note: TODO
*/
_setjmp:
! block interrupt
stc sr, r1
mov r1, r3
mov #0x10, r2
shll8 r2
shll16 r2
or r2, r1
ldc r1, sr
! save current context
! @note: r3 is the saved SR regsiter
add #52, r4
sts.l pr, @-r4
sts.l mach, @-r4
sts.l macl, @-r4
stc.l gbr, @-r4
mov.l r15, @-r4
mov.l r14, @-r4
mov.l r13, @-r4
mov.l r12, @-r4
mov.l r11, @-r4
mov.l r10, @-r4
mov.l r9, @-r4
mov.l r8, @-r4
mov.l r3, @-r4
! restore sr
ldc r3, sr
! return
rts
mov #0, r0

15
src/signal/kill.S Normal file
View file

@ -0,0 +1,15 @@
#include <asm/unistd_32.h>
.text
.global _kill
.type _kill, @function
.align 2
/*
** TODO: doc
*/
_kill:
trapa #__NR_kill
rts
nop
.end

15
src/signal/signal.S Normal file
View file

@ -0,0 +1,15 @@
#include <asm/unistd_32.h>
.text
.global _signal
.type _signal, @function
.align 2
/*
** TODO: doc
*/
_signal:
trapa #__NR_signal
rts
nop
.end

12
src/stdio/dprintf.c Normal file
View file

@ -0,0 +1,12 @@
#include <stdio.h>
int dprintf(int fd, const char *restrict format, ...)
{
va_list ap;
int ret;
va_start(ap, format);
ret = vdprintf(fd, format, ap);
va_end(ap);
return (ret);
}

View file

@ -0,0 +1,188 @@
#include <stdio.h>
// Define all actions
static void action_str(struct printf_opt *op, char n);
static void action_ptr(struct printf_opt *op, char n);
static void action_int(struct printf_opt *op, char n);
static void action_uint(struct printf_opt *op, char n);
static void action_char(struct printf_opt *op, char n);
// Define all actions which can be used
void (*action[26])(struct printf_opt *opt, char n) = {
NULL, NULL, action_char, action_int,
NULL, NULL, NULL, NULL,
action_int, NULL, NULL, NULL,
NULL, NULL, action_uint, action_ptr,
NULL, NULL, action_str, NULL,
action_uint, NULL, NULL, action_uint,
NULL, NULL,
};
//---
// Disp part
//---
static void base_to_str(struct printf_opt *opt, uint32_t num, int base, int digits)
{
char *hexa = (opt->uppercase == 1) ? "0123456789ABCDEF" : "0123456789abcdef";
opt->digits = 0;
while (num != 0 || opt->digits < digits)
{
opt->format[opt->digits++] = hexa[num % base];
num = num / base;
}
}
static void disp_format(struct printf_opt *opt)
{
// display pre symbols
if (opt->sign != '\0')
(*opt->disp_char)(opt, opt->sign);
if (opt->base[0] != '\0')
(*opt->disp_char)(opt, opt->base[0]);
if (opt->base[1] != '\0')
(*opt->disp_char)(opt, opt->base[1]);
// padding
if (opt->flags.minus == 1 && opt->width > opt->digits)
{
int total = opt->digits + (opt->sign != '\0') +
(opt->base[0] != '\0') + (opt->base[1] != '\0');
total = opt->width - total;
while (--total >= 0)
(*opt->disp_char)(opt, (opt->flags.zero == 1) ? '0' : ' ');
}
// Display number
int saved_digits = opt->digits;
while (--opt->digits >= 0)
(*opt->disp_char)(opt, opt->format[opt->digits]);
// padding
if (opt->flags.minus == 0 && opt->width > saved_digits)
{
int total = saved_digits + (opt->sign != '\0') +
(opt->base[0] != '\0') + (opt->base[1] != '\0');
total = opt->width - total;
while (--total >= 0)
(*opt->disp_char)(opt, ' ');
}
}
//---
// Args part
//---
static uint32_t get_arg_i(struct printf_opt *opt)
{
switch (opt->lenght)
{
case 0: return ((signed char)va_arg(opt->ap, int));
case 1: return ((short int)va_arg(opt->ap, int));
case 2: return (va_arg(opt->ap, long int));
case 3: return (va_arg(opt->ap, long long int));
case 4: return (va_arg(opt->ap, intmax_t));
case 5: return (va_arg(opt->ap, size_t));
case 6: return (va_arg(opt->ap, ptrdiff_t));
}
return (va_arg(opt->ap, int));
}
static uint32_t get_arg_u(struct printf_opt *opt)
{
switch (opt->lenght)
{
case 0: return ((unsigned char)va_arg(opt->ap, int));
case 1: return ((unsigned short int)va_arg(opt->ap, int));
case 2: return (va_arg(opt->ap, unsigned long int));
case 3: return (va_arg(opt->ap, unsigned long long int));
case 4: return (va_arg(opt->ap, intmax_t));
case 5: return (va_arg(opt->ap, size_t));
case 6: return (va_arg(opt->ap, ptrdiff_t));
}
return (va_arg(opt->ap, unsigned int));
}
//---
// Actions part.
//---
static void action_str(struct printf_opt *opt, char n)
{
const char *str;
(void)n;
str = va_arg(opt->ap, const char *);
while (*str != '\0')
(*opt->disp_char)(opt, *(str++));
}
static void action_char(struct printf_opt *opt, char n)
{
n = (char)va_arg(opt->ap, int);
(*opt->disp_char)(opt, n);
}
static void action_ptr(struct printf_opt *opt, char n)
{
(void)n;
opt->sign = '@';
opt->base[0] = '0';
opt->base[1] = 'x';
base_to_str(opt, (uint32_t)va_arg(opt->ap, void*), 16, 8);
disp_format(opt);
}
static void action_int(struct printf_opt *opt, char n)
{
int64_t num;
// Get data and check negative value
// FIXME: max negative value can not be reversed
(void)n;
num = get_arg_i(opt);
if (num < 0) {
opt->sign = '-';
num = -num;
} else if (opt->flags.space == 1 || opt->flags.plus == 1) {
opt->sign = (opt->flags.plus == 1) ? '+' : ' ';
}
// Generate / display number
base_to_str(opt, num, 10, 1);
disp_format(opt);
}
static void action_uint(struct printf_opt *opt, char n)
{
uint32_t num;
int base;
// Get appropriate base
switch (n)
{
case 'o': base = 8; break;
case 'x': base = 16; break;
default: base = 10; break;
}
// Display extra symbols if needed
if (opt->flags.diez == 1)
{
if (n == 'o') {
opt->base[0] = '0';
} else if (n == 'x') {
opt->base[0] = '0';
opt->base[1] = (opt->uppercase == 1) ? 'X' : 'x';
}
}
// Get number
num = get_arg_u(opt);
// Generate / display number
base_to_str(opt, num, base, 1);
disp_format(opt);
}

View file

@ -0,0 +1,40 @@
#include <stdio.h>
//TODO: precision handling
int printf_common(struct printf_opt *opt, const char *restrict format)
{
extern int printf_get_options(struct printf_opt *opt, const char *restrict format);
int saved_p;
int p;
p = -1;
opt->counter = 0;
opt->buffer_cursor = 0;
while (format[++p] != '\0')
{
// Check printable char
if (format[p] != '%' || format[p + 1] == '%') {
(*opt->disp_char)(opt, (format[p] != '%') ? format[p] : format[++p]);
continue;
}
// Get options
saved_p = p;
p = p + printf_get_options(opt, &format[p + 1]);
// Check arg validity
if (((format[p + 1] >= 'a' && format[p + 1] <= 'z') ||
(format[p + 1] >= 'A' && format[p + 1] <= 'Z')) &&
action[(format[p + 1] | 0x20) - 'a'] != NULL) {
(*action[(format[p + 1] | 0x20) - 'a'])(opt, format[p + 1] | 0x20);
p = p + 1;
continue;
}
// Default, print the %
(*opt->disp_char)(opt, '%');
p = saved_p;
}
(*opt->disp_fflush)(opt);
return (opt->counter);
}

View file

@ -0,0 +1,105 @@
#include <stdio.h>
static int get_flags(struct printf_opt *opt, const char *restrict format)
{
int i;
i = -1;
opt->flags.diez = 0;
opt->flags.zero = 0;
opt->flags.minus = 0;
opt->flags.space = 0;
opt->flags.plus = 0;
while (format[++i] != '\0')
{
switch (format[i])
{
case '#': opt->flags.diez = 1; break;
case '0': opt->flags.zero = 1; break;
case '-': opt->flags.minus = 1; break;
case ' ': opt->flags.space = 1; break;
case '+': opt->flags.plus = 1; break;
default: return (i);
}
}
return (i);
}
static int get_width(struct printf_opt *opt, const char *restrict format)
{
// Check dynamic width
if (format[0] == '*') {
opt->width = va_arg(opt->ap, int);
return (1);
}
// Check error
int i = -1;
opt->width = 0;
if (format[0] == '0')
return (0);
// Get static width
while (format[++i] >= '0' && format[i] <= '9')
opt->width = (opt->width * 10) + (format[i] - '0');
return (i);
}
static int get_precision(struct printf_opt *opt, const char *restrict format)
{
// Check if precision is specified
if (format[0] != '.')
return (0);
// Check dynamic precision
if (format[1] == '*') {
opt->precision = va_arg(opt->ap, int);
return (2);
}
// Get static precision
int i = 0;
opt->precision = 0;
while (format[++i] >= '0' && format[i] <= '9')
opt->precision = (opt->precision * 10) + (format[i] - '0');
// Check default precision
if (i == 0)
opt->precision = 1;
return (i);
}
static int get_lenght(struct printf_opt *opt, const char *restrict format)
{
opt->lenght = -1;
switch (format[0])
{
case 'h': opt->lenght = (format[1] == 'h') ? 1 : 0; break;
case 'l': opt->lenght = (format[1] == 'l') ? 3 : 2; break;
case 'j': opt->lenght = 4; break;
case 'z': opt->lenght = 5; break;
case 't': opt->lenght = 6; break;
default: return (0);
}
return ((opt->lenght == 1 || opt->lenght == 3) ? 2 : 1);
}
int printf_get_options(struct printf_opt *opt, const char *restrict format)
{
int i;
// Wipe internal format infos
opt->sign = '\0';
opt->base[0] = '\0';
opt->base[1] = '\0';
// Get generals opetions
i = get_flags(opt, &format[0]);
i += get_width(opt, &format[i]);
i += get_precision(opt, &format[i]);
i += get_lenght(opt, &format[i]);
// Check upper case actions
opt->uppercase = (format[i] == 'X') ? 1 : 0;
return (i);
}

13
src/stdio/printf.c Normal file
View file

@ -0,0 +1,13 @@
#include <stdio.h>
#include <unistd.h>
int printf(const char *restrict format, ...)
{
va_list ap;
int ret;
va_start(ap, format);
ret = vdprintf(STDOUT_FILENO, format, ap);
va_end(ap);
return (ret);
}

11
src/stdio/putc.c Normal file
View file

@ -0,0 +1,11 @@
#include <stdio.h>
#include <unistd.h>
int putc(int c)
{
char n;
n = (char)c;
write(STDOUT_FILENO, &n, 1);
return (n);
}

13
src/stdio/puts.c Normal file
View file

@ -0,0 +1,13 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int puts(const char *s)
{
size_t size;
size_t n;
size = strlen(s);
n = write(STDOUT_FILENO, s, size);
return (-(n == size));
}

11
src/stdio/snprintf.c Normal file
View file

@ -0,0 +1,11 @@
#include <stdio.h>
int snprintf(char *restrict str, size_t size, const char *restrict format, ...)
{
va_list ap;
va_start(ap, format);
size = vsnprintf(str, size, format, ap);
va_end(ap);
return (size);
}

12
src/stdio/sprintf.c Normal file
View file

@ -0,0 +1,12 @@
#include <stdio.h>
int sprintf(char *restrict str, const char *restrict format, ...)
{
va_list ap;
int size;
va_start(ap, format);
size = vsnprintf(str, 65535, format, ap);
va_end(ap);
return (size);
}

35
src/stdio/vdprintf.c Normal file
View file

@ -0,0 +1,35 @@
#include <stdio.h>
#include <unistd.h>
// FIXME:
// if the writte syscall do not return the same
// number of bytes that requested, stop the function !
static void disp_fflush(struct printf_opt *opt)
{
if (opt->buffer_cursor != 0) {
opt->counter += write(opt->fd, opt->buffer, opt->buffer_cursor);
opt->buffer_cursor = 0;
}
}
static void disp_char(struct printf_opt *opt, char n)
{
// Check if we should force flush the internal buffer
if (opt->buffer_cursor >= PRINTF_INTERNAL_BUFFER_SIZE)
disp_fflush(opt);
// Save char
opt->buffer[opt->buffer_cursor++] = n;
}
int vdprintf(int fd, const char *restrict format, va_list ap)
{
extern int printf_common(struct printf_opt *opt, const char *restrict format);
struct printf_opt opt;
opt.fd = fd;
opt.disp_char = &disp_char;
opt.disp_fflush = &disp_fflush;
va_copy(opt.ap, ap);
return (printf_common(&opt, format));
}

29
src/stdio/vsnprintf.c Normal file
View file

@ -0,0 +1,29 @@
#include <stdio.h>
static void disp_char(struct printf_opt *opt, char n)
{
// Check write possibility
if (opt->buffer_cursor < opt->str_size - 1) {
opt->str[opt->buffer_cursor] = n;
opt->buffer_cursor = opt->buffer_cursor + 1;
}
}
static void disp_fflush(struct printf_opt *opt)
{
opt->str[opt->buffer_cursor] = '\0';
}
int vsnprintf(char *restrict str, size_t size, const char *restrict format, va_list ap)
{
extern int printf_common(struct printf_opt *opt, const char *restrict format);
struct printf_opt opt;
opt.str = str;
opt.str_size = size;
opt.disp_char = &disp_char;
opt.disp_fflush = &disp_fflush;
va_copy(opt.ap, ap);
return (printf_common(&opt, format) + 1);
}

6
src/stdio/vsprintf.c Normal file
View file

@ -0,0 +1,6 @@
#include <stdio.h>
int vsprintf(char *restrict str, const char *restrict format, va_list ap)
{
return (vsnprintf(str, 65535, format, ap));
}

16
src/stdlib/calloc.c Normal file
View file

@ -0,0 +1,16 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void *calloc(size_t nmemb, size_t size)
{
if (size == 0 || nmemb == 0)
return (NULL);
void *ret = malloc(nmemb * size);
if (ret == NULL)
return (NULL);
memset(ret, 0x00, size);
return (ret);
}

17
src/stdlib/free.S Normal file
View file

@ -0,0 +1,17 @@
#include <asm/unistd_32.h>
.text
.global _free
.type _free, @function
.align 2
/*
** @note: the MMU is used by Casio so we
** can not implement brk or skr because
** of non continuous heap.
*/
_free:
trapa #__NR_proc_heap_free
rts
nop
.end

16
src/stdlib/malloc.S Normal file
View file

@ -0,0 +1,16 @@
#include <asm/unistd_32.h>
.text
.global _malloc
.type _malloc, @function
.align 2
/*
** @note: We can not implement brk or skr
** because the MMU is used by Casio.
*/
_malloc:
trapa #__NR_proc_heap_alloc
rts
nop
.end

46
src/stdlib/realloc.S Normal file
View file

@ -0,0 +1,46 @@
#include <asm/unistd_32.h>
.text
.global _realloc
.type _realloc, @function
.extern _malloc
.extern _free
.align 2
/*
** void *realloc(void ptr, size_t size)
**
** @note: the MMU is used by Casio so we
** can not implement brk or skr because
** of non continuous heap.
*/
_realloc:
! Check malloc part
tst r4, r4 ! if ptr == NULL...
bf.s check_free ! ...if not, jump at <check_free>
mov.l .malloc, r0 ! get malloc() address
jmp @r0 ! call malloc(size)
mov r5, r4 ! (db) send size
! Check free
check_free:
tst r5, r5 ! if size == 0...
bf.s call_realloc ! ...if not, jump at <call_realloc>
mov.l .free, r0 ! get free() address
sts.l pr, @-r15 ! save pr register
jmp @r0 ! call free(ptr)
nop ! (db) nop
rts ! return...
xor r0, r0 ! (db) ...NULL
! Call realloc
call_realloc:
trapa #__NR_proc_heap_realloc
rts
nop
.align 4
.malloc: .long _malloc
.free: .long _free
.end

View file

@ -0,0 +1,8 @@
#include <stdlib.h>
//FIXME: check safe !!!!
//FIXME: Check underflow !!
void *reallocarray(void *ptr, size_t nmemb, size_t size)
{
return (realloc(ptr, nmemb * size));
}

8
src/string/memcpy.c Normal file
View file

@ -0,0 +1,8 @@
#include <string.h>
void *memcpy(void *dest, const void *src, size_t count)
{
for (size_t i = 0 ; i < count ; i = i + 1)
((uint8_t*)dest)[i] = ((uint8_t*)src)[i];
return (dest);
}

9
src/string/memset.c Normal file
View file

@ -0,0 +1,9 @@
#include <string.h>
//TODO: update me :(
void *memset(void *s, int c, size_t n)
{
while ((int)--n >= 0)
((uint8_t*)s)[n] = c;
return (s);
}

17
src/string/strcat.c Normal file
View file

@ -0,0 +1,17 @@
#include <string.h>
char *strcat(char *dest, char const *src)
{
size_t i;
size_t start;
if (src == NULL || dest == NULL)
return (0);
i = -1;
start = -1;
while (dest[++start] != '\0');
while (src[++i] != '\0')
dest[start + i] = src[i];
dest[i + start] = '\0';
return (dest);
}

31
src/string/strchr.c Normal file
View file

@ -0,0 +1,31 @@
#include <string.h>
//TODO: asm ?
char *strchr(const char *s1, int c)
{
int i = -1;
while (s1[++i] != '\0' && s1[i] != c);
return ((s1[i] == '\0') ? NULL : (void*)&s1[i]);
}
//TODO: asm ?
char *strchrnul(const char *s1, int c)
{
int i = -1;
while (s1[++i] != '\0' && s1[i] != c);
return ((void*)&s1[i]);
}
//TODO asm ?
char *strrchr(const char *s1, int c)
{
void *saved;
saved = NULL;
for (int i = 0 ; s1[i] != '\0' ; i++)
{
if (s1[i] == c)
saved = (void *)&s1[i];
}
return (saved);
}

22
src/string/strcmp.c Normal file
View file

@ -0,0 +1,22 @@
#include <string.h>
int strcmp(const char *s1, const char *s2)
{
if (s1 == NULL || s2 == NULL)
return (0);
while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
{
s1 += 1;
s2 += 1;
}
return (*s1 - *s2);
}
int strncmp(const char *s1, const char *s2, size_t n)
{
if (s1 == NULL || s2 == NULL || n == 0)
return (0);
size_t i = -1;
while (++i < n - 1 && s1[i] != '\0' && s2[i] != '\0' && s1[i] == s2[i]);
return (s1[i] - s2[i]);
}

27
src/string/strcpy.c Normal file
View file

@ -0,0 +1,27 @@
#include <string.h>
char *strcpy(char *dest, char const *src)
{
size_t i;
if (src == NULL || dest == NULL)
return (0);
i = -1;
while (src[++i] != '\0')
dest[i] = src[i];
dest[i] = '\0';
return (dest);
}
char *strncpy(char *dest, char const *str, size_t size)
{
size_t i;
if (str == NULL || dest == NULL)
return (0);
i = -1;
while (++i < size && str[i] != '\0')
dest[i] = str[i];
dest[i] = '\0';
return (dest);
}

22
src/string/strdup.c Normal file
View file

@ -0,0 +1,22 @@
#include <string.h>
#include <stdlib.h>
char *strdup(const char *s)
{
size_t len;
void *dump;
// Check error
if (s == NULL)
return (NULL);
// Check len
len = strlen(s);
if (len == 0)
return (NULL);
// Dump string and return
dump = malloc(len);
memcpy(dump, s, len);
return (dump);
}

23
src/string/strlen.c Normal file
View file

@ -0,0 +1,23 @@
#include <string.h>
size_t strlen(char const *str)
{
size_t i;
if (str == NULL)
return (0);
i = -1;
while (str[++i] != '\0');
return (i);
}
size_t strnlen(char const *str, size_t maxlen)
{
size_t i;
if (str == NULL)
return (0);
i = -1;
while (str[++i] != '\0' && (size_t)i < maxlen);
return (i);
}

88
src/threads/atomic.S Normal file
View file

@ -0,0 +1,88 @@
.text
.global ___thread_atomic_start
.global ___thread_atomic_stop
.type ___thread_atomic_start, @function
.type ___thread_atomic_stop, @function
.align 2
// Save the current SR register and set the SR.BIT bit up (start atomic operations)
// @note: return the saved SR register (if has been saved), 0xffffffff otherwise.
___thread_atomic_start:
! Check if the calculator is currently
! into an atomic operation and update
! atomic counter.
mov.l atomic_counter, r1 ! r1 = atomic counter address
mov.l @r1, r2 ! r2 = atomic counter data
tst r2, r2 ! if atomic counter == 0...
add #1, r2 ! update atomic counter data
mov.l r2, @r1 ! update atomic counter.
bf.s atomic_start_exit ! ...if not, jump <atomic_start_exit>
mov #-1, r0 ! (db) return 0xffffffff
! Block interrupt if needed.
stc sr, r1 ! get SR register.
mov r1, r0 ! save current SR register.
mov.l bl_mask, r2 ! get SR.BL mask.
or r2, r1 ! set SR.BL = 1 and SR.IMASK = 0b1111.
ldc r1, sr ! update SR register.
! Save "old" SR register.
mov.l sr_save, r1 ! r1 = sr_save address
mov.l r0, @r1 ! save "old" SR register data.
atomic_start_exit:
rts ! exit.
nop ! (db) nop.
// Restore the saved SR register
// @note: return the restored SR register or -1 otherwise.
___thread_atomic_stop:
! Check if the calculator is currently
! into an atomic operation and update
! atomic counter if pssible.
mov.l atomic_counter, r1 ! r1 = atomic counter address
mov.l @r1, r0 ! r0 = atomic counter data
tst r0, r0 ! if atomic counter == 0...
bt atomic_end_error ! ...if yes, jump at <atomic_end_error>
cmp/eq #1, r0 ! if atomic counter == 1...
add #-1, r0 ! update atomic counter data
mov.l r0, @r1 ! update atomic counter
bf atomic_end_error ! ...if not, jump at <atomic_end_error>
! Restore saved SR register data.
mov.l sr_save, r1 ! get sr_save address
mov.l @r1, r0 ! r0 = "old" SR register data
ldc r0, sr ! restore SR register.
bra atomic_end_exit ! return the resotred SR register.
nop ! (db) nop
atomic_end_error:
mov #-1, r0 ! return 0xffffffff
atomic_end_exit:
rts ! exit.
nop ! (db) nop.
.align 4
bl_mask: .long 0x100000f0
sr_save: .long ___thread_atomic_sr_save
atomic_counter: .long ___thread_atomic_counter
##---
## Global part.
##---
.data
.global ___thread_atomic_sr_save
.global ___thread_atomic_counter
.type ___thread_atomic_sr_save, @object
.type ___thread_atomic_counter, @object
.align 4
___thread_atomic_sr_save: .long 0x00000000
___thread_atomic_counter: .long 0x00000000

109
src/threads/mutex.c Normal file
View file

@ -0,0 +1,109 @@
#include <threads.h>
#include <unistd.h>
// Creates a new mutex object with type __TYPE.
// @note: If successful the new object is pointed by __MUTEX.
int mtx_init (mtx_t *__mutex, int __type)
{
// Check if the mutext is already initialized
if (__mutex->__watermark == MTX_WATERMARK)
return (-1);
// Initialize mutex
__mutex->__watermark = MTX_WATERMARK;
__mutex->type = __type;
__mutex->lock = 0;
return (0);
}
// Block the current thread until the mutex pointed to by __MUTEX is unlocked.
// In that case current thread will not be blocked.
int mtx_lock(mtx_t *__mutex)
{
// Check mutex validity
if (__mutex->__watermark != MTX_WATERMARK)
return (-1);
// Wait util the mutex is unlocked
while (1)
{
// Check if the mutex is unlock
__thread_atomic_start();
if (__mutex->lock == 0)
break;
__thread_atomic_stop();
// TODO: force kernel schedule
__asm__ volatile ("sleep");
}
//TODO: handle mutex type !!
(void)__mutex->type;
// Lock the mutex
__mutex->lock = 1;
// Stop atomic operations
__thread_atomic_stop();
return (0);
}
// Try to lock the mutex pointed by __MUTEX without blocking.
// @note: If the mutex is free the current threads takes control of it,
// otherwise it returns immediately.
int mtx_trylock(mtx_t *__mutex)
{
// Check mutex validity
if (__mutex->__watermark != MTX_WATERMARK)
return (-1);
// Start atomic operations
__thread_atomic_start();
// Check if the mutex is already free
int ret = -1;
if (__mutex->lock == 0)
{
//TODO: handle mutex type !!
(void)__mutex->type;
// lock the mutex and change the return value
__mutex->lock = 1;
ret = 0;
}
// Stop atomic operation and return
__thread_atomic_stop();
return (ret);
}
// Unlock the mutex pointed by __MUTEX.
// @note: It may potentially awake other threads waiting on this mutex.
int mtx_unlock(mtx_t *__mutex)
{
// Check mutex validity
if (__mutex->__watermark != MTX_WATERMARK)
return (-1);
// Start atomic operation
__thread_atomic_start();
// Check if the mutex is realy used and unluck if needed
int ret = -1;
if (__mutex->lock != 0) {
__mutex->lock = 0;
ret = 0;
}
// Stop atomic operation and return
__thread_atomic_stop();
return (ret);
}
// Destroy the mutex object pointed by __MUTEX.
// TODO: check if the mutex is in use ?
void mtx_destroy(mtx_t *__mutex)
{
__mutex->__watermark = 0x00000000;
__mutex->type = -1;
}

12
src/unistd/close.S Normal file
View file

@ -0,0 +1,12 @@
#include <asm/unistd_32.h>
.text
.global _close
.type _close, @function
.align 2
_close:
trapa #__NR_close
rts
nop
.end

12
src/unistd/fork_execve.S Normal file
View file

@ -0,0 +1,12 @@
#include <asm/unistd_32.h>
.text
.global _fork_execve
.type _fork_execve, @function
.align 2
_fork_execve:
trapa #__NR_fork_execve
rts
nop
.end

12
src/unistd/getpgid.S Normal file
View file

@ -0,0 +1,12 @@
#include <asm/unistd_32.h>
.text
.global _getpgid
.type _getpgid, @function
.align 2
_getpgid:
trapa #__NR_getpgid
rts
nop
.end

12
src/unistd/getpid.S Normal file
View file

@ -0,0 +1,12 @@
#include <asm/unistd_32.h>
.text
.global _getpid
.type _getpid, @function
.align 2
_getpid:
trapa #__NR_getpid
rts
nop
.end

12
src/unistd/getppid.S Normal file
View file

@ -0,0 +1,12 @@
#include <asm/unistd_32.h>
.text
.global _getppid
.type _getppid, @function
.align 2
_getppid:
trapa #__NR_getppid
rts
nop
.end

12
src/unistd/lseek.S Normal file
View file

@ -0,0 +1,12 @@
#include <asm/unistd_32.h>
.text
.global _lseek
.type _lseek, @function
.align 2
_lseek:
trapa #__NR_lseek
rts
nop
.end

12
src/unistd/open.S Normal file
View file

@ -0,0 +1,12 @@
#include <asm/unistd_32.h>
.text
.global _open
.type _open, @function
.align 2
_open:
trapa #__NR_open
rts
nop
.end

12
src/unistd/read.S Normal file
View file

@ -0,0 +1,12 @@
#include <asm/unistd_32.h>
.text
.global _read
.type _read, @function
.align 2
_read:
trapa #__NR_read
rts
nop
.end

12
src/unistd/setpgid.S Normal file
View file

@ -0,0 +1,12 @@
#include <asm/unistd_32.h>
.text
.global _setpgid
.type _setpgid, @function
.align 2
_setpgid:
trapa #__NR_setpgid
rts
nop
.end

12
src/unistd/wait.S Normal file
View file

@ -0,0 +1,12 @@
#include <asm/unistd_32.h>
.text
.global _wait
.type _wait, @function
.align 2
_wait:
trapa #__NR_wait
rts
nop
.end

12
src/unistd/waitpid.S Normal file
View file

@ -0,0 +1,12 @@
#include <asm/unistd_32.h>
.text
.global _waitpid
.type _waitpid, @function
.align 2
_waitpid:
trapa #__NR_waitpid
rts
nop
.end

12
src/unistd/write.S Normal file
View file

@ -0,0 +1,12 @@
#include <asm/unistd_32.h>
.text
.global _write
.type _write, @function
.align 2
_write:
trapa #__NR_write
rts
nop
.end