diff --git a/.gitignore b/.gitignore index 7ed9ebec100052cf4ced1bc16a6993df01e65523..365eb6c6c9d11cf0c010b9b06923629f13015e03 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ serial.txt *.gz *.img *.vmdk +*.iso SrcDoc/ APIDoc/ Usermode/*/*/UTEST/stage diff --git a/.travis.yml b/.travis.yml index d39dc5d2a1d77978cfe601b75985cdba389c5d2a..52dc0327297c08d4d44e918c17245fd0c1434e3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,4 +6,6 @@ compiler: clang #env: # - ARCH=host HOST_ARCH=x86 USE_ACPICA=0 # - ARCH=host HOST_ARCH=x86_64 CC="$CC -m64" -script: "make utest mtest" +script: + - "make utest-build mtest-build" + - "make -k utest-run mtest-run" diff --git a/AcessNative/Makefile b/AcessNative/Makefile index 7448f4fd9f87e85e506b4d5d1fc560d9475dcd4e..8d5d6c4caef0f24d66d28b5b036d56f101fea3e5 100644 --- a/AcessNative/Makefile +++ b/AcessNative/Makefile @@ -1,6 +1,10 @@ .PHONY: all clean +V ?= @ + all clean: @$(MAKE) -C acesskernel_src $@ @$(MAKE) -C ld-acess_src $@ + @$(MAKE) -C libacess-native.so_src $@ + @$(MAKE) -C .. $@-user ARCH=native V=$(V) diff --git a/AcessNative/RunNative b/AcessNative/RunNative new file mode 100755 index 0000000000000000000000000000000000000000..406573db0d20b68b544347d7071819907ad69e60 --- /dev/null +++ b/AcessNative/RunNative @@ -0,0 +1,42 @@ +#!/bin/bash +# +# Execute the specified root application using the ARCH=native build +# +_=$PWD; cd $(dirname $0); DIR=$PWD; cd $_ +DISTROOT=$(dirname $DIR)/Usermode/Output/native/ +VTERM=/Devices/pts/vt0 +echo $DISTROOT + +KERNEL_PID=$$ +function cleanup { + trap '' SIGINT + echo Cleaning up $KERNEL_PID + kill -INT $KERNEL_PID +} + +trap cleanup SIGINT + +# 1. Start up AcessKernel +# - Set DISTROOT to the output directory of ARCH=native +# - Don't start a root application +${DIR}/AcessKernel --distroot $DISTROOT > ${DIR}/log/native_AcessKernel.log 2>&1 & +KERNEL_PID=$! +echo Kernel is $KERNEL_PID +sleep 1 + +APP=gui4 + +case $APP in +gui4) + LD_LIBRARY_PATH=${DIR}:${DISTROOT}Libs AN_PREOPEN=$VTERM:$VTERM:$VTERM ${DBG} ${DISTROOT}Apps/AxWin/4.0/AxWinServer + ;; +gui3) + LD_LIBRARY_PATH=${DIR}:${DISTROOT}Libs AN_PREOPEN=$VTERM:$VTERM:$VTERM ${DBG} ${DISTROOT}Apps/AxWin/3.0/AxWinWM + ;; +*) + echo "Unknown application '$APP'" +esac + +trap '' SIGINT +cleanup + diff --git a/AcessNative/RunRootApp b/AcessNative/RunRootApp index 39a30fac5638011843c422867c2ded7ed82a9fd7..a3d31abc16482475bb4625e7e6c0e236a45ffa20 100755 --- a/AcessNative/RunRootApp +++ b/AcessNative/RunRootApp @@ -1,3 +1,7 @@ #!/bin/sh +# +# Spin up an application bound to VTerm 0 using ./ld-acess +# + $DBG ./ld-acess --open /Devices/VTerm/0 --open /Devices/VTerm/0 --open /Devices/VTerm/0 $* diff --git a/AcessNative/RunTest b/AcessNative/RunTest index 6ea88b673b2410b57d20c7247da2cde18394a643..069ea14f066b7ec6434dc3fe4c112df84df2bce9 100755 --- a/AcessNative/RunTest +++ b/AcessNative/RunTest @@ -1,4 +1,7 @@ #!/bin/sh +# +# Runs the AcessNative kernel and spawns a native executable using ./ld-acess +# trap '' 2 #$1 ./AcessKernel --rootapp /Acess/SBin/login $1 ./AcessKernel --rootapp /Acess/Apps/AxWin/3.0/AxWinWM diff --git a/AcessNative/acesskernel_src/Makefile b/AcessNative/acesskernel_src/Makefile index 9e8ce35fd33ffb7c7d5397eec74e054ee6c59e58..11976045622715104c0af6c222de12ebcbb09751 100644 --- a/AcessNative/acesskernel_src/Makefile +++ b/AcessNative/acesskernel_src/Makefile @@ -15,7 +15,7 @@ KERNEL_SRC = ../../KernelLand/Kernel/ LDACESS_SRC = ../../Usermode/Libraries/ld-acess.so_src/ # - Kernel objects (from KernelLand/Kernel) -KERNEL_OBJ := logging.o adt.o lib.o debug.o messages.o drvutil_disk.o drvutil_video.o +KERNEL_OBJ := logging.o adt.o lib.o debug.o messages.o drvutil_disk.o drvutil_video.o memfs_helpers.o KERNEL_OBJ += mutex.o semaphore.o rwlock.o workqueue.o events.o #KERNEL_OBJ += libc.o KERNEL_OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/io.o vfs/dir.o @@ -30,6 +30,7 @@ N_OBJ := main.o net_wrap.o # - Local objects (use the kernel includes) OBJ := helpers.o threads.o threads_glue.o server.o syscalls.o time.o OBJ += video.o keyboard.o mouse.o nativefs.o vfs_handle.o ui_sdl.o +#OBJ += shm.o OBJ += net.o syscall_getpath.o BUILDINFO_OBJ := obj-$(PLATFORM)/buildinfo.o @@ -46,6 +47,7 @@ KCPPFLAGS = -I include/ -I $(KERNEL_SRC)include/ -I$(LDACESS_SRC)include_exp/ -D CFLAGS += -Wall -g -std=gnu99 CPPFLAGS += $(shell sdl-config --cflags) -I /usr/include/ LDFLAGS += $(shell sdl-config --libs) -g -Wl,--defsym,__buildnum=$(BUILD_NUM) +LDFLAGS += -Wl,-Map,obj-$(PLATFORM)/Map.txt ifeq ($(PLATFORM),win) BIN := ../AcessKernel.exe diff --git a/AcessNative/acesskernel_src/include/arch.h b/AcessNative/acesskernel_src/include/arch.h index ab27de1f1ea0996448d468b0de7a75b123186e23..868a0569c424934ea761926eff33e6211291c17e 100644 --- a/AcessNative/acesskernel_src/include/arch.h +++ b/AcessNative/acesskernel_src/include/arch.h @@ -28,6 +28,7 @@ typedef intptr_t tPAddr; typedef int BOOL; +extern void exit(int status) __attribute__((noreturn)); #define HALT_CPU() exit(1) #include <stddef.h> diff --git a/AcessNative/acesskernel_src/main.c b/AcessNative/acesskernel_src/main.c index ead4f33d9901c866db962c79b0f4f91d06f013b0..4f5de2399d7f501d8c61218224b251253ec25a28 100644 --- a/AcessNative/acesskernel_src/main.c +++ b/AcessNative/acesskernel_src/main.c @@ -13,6 +13,7 @@ #endif #include <unistd.h> #include <string.h> +#include <stdbool.h> #include "../../KernelLand/Kernel/include/logdebug.h" #define VALGRIND_CLIENT 0 @@ -115,7 +116,7 @@ int main(int argc, char *argv[]) VFS_MkDir("/Acess"); VFS_Mount(gsAcessDir, "/Acess", "nativefs", ""); - Debug_SetKTerminal("/Devices/pts/vt7c"); + Debug_SetKTerminal("/Devices/pts/vt7"); // Start syscall server SyscallServer(); diff --git a/AcessNative/acesskernel_src/net_wrap.c b/AcessNative/acesskernel_src/net_wrap.c index 730eda0232f4e72d19c88cbf4419d5da0c13eee9..33a5cf91d410a89885e8719152c9ff4afb62f9b5 100644 --- a/AcessNative/acesskernel_src/net_wrap.c +++ b/AcessNative/acesskernel_src/net_wrap.c @@ -8,6 +8,7 @@ #define DEBUG 1 #include <stdlib.h> #include <unistd.h> +#include <stdbool.h> #include "../../KernelLand/Kernel/include/logdebug.h" #include "net_wrap.h" #include <string.h> diff --git a/AcessNative/acesskernel_src/server.c b/AcessNative/acesskernel_src/server.c index f3826db79f0425cda62c3e85d0aea51d83893c19..4dd964ca155166adc9483aedbce8f00be2ce7aa2 100644 --- a/AcessNative/acesskernel_src/server.c +++ b/AcessNative/acesskernel_src/server.c @@ -6,6 +6,7 @@ */ #include <stdio.h> #include <stdlib.h> +#include <stdbool.h> #include <string.h> #include <SDL/SDL.h> #ifdef __WIN32__ @@ -227,6 +228,13 @@ int SyscallServer(void) server.sin_port = htons(SERVER_PORT); server.sin_addr.s_addr = htonl(INADDR_ANY); + #if USE_TCP + { + int val = 1; + setsockopt(gSocket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val); + } + #endif + // Bind if( bind(gSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1 ) { diff --git a/AcessNative/acesskernel_src/threads.c b/AcessNative/acesskernel_src/threads.c index 86b8a892780f2cfc5102542ed658e45e8c4635e6..74d85fc60c078c54bfdc59fae473d26be74fd0f5 100644 --- a/AcessNative/acesskernel_src/threads.c +++ b/AcessNative/acesskernel_src/threads.c @@ -199,9 +199,10 @@ int Threads_SetGID(tGID NewGID) } int *Threads_GetErrno(void) { return &gpCurrentThread->_errno; } -char **Threads_GetCWD(void) { return &gpCurrentThread->Process->CWD; } -char **Threads_GetChroot(void) { return &gpCurrentThread->Process->Chroot; } -int *Threads_GetMaxFD(void) { return &gpCurrentThread->Process->MaxFD; }; +static tProcess *proc(tProcess *Proc) { return Proc ? Proc : gpCurrentThread->Process; } +char **Threads_GetCWD (tProcess *Proc) { return &proc(Proc)->CWD; } +char **Threads_GetChroot(tProcess *Proc) { return &proc(Proc)->Chroot; } +int *Threads_GetMaxFD (tProcess *Proc) { return &proc(Proc)->MaxFD; }; tTID Threads_WaitTID(int TID, int *Status) { diff --git a/AcessNative/acesskernel_src/threads_glue.c b/AcessNative/acesskernel_src/threads_glue.c index fa83980e38890f8f707b83f73b87c1ba30384a67..7c1378040763fd0565ae7a3d0decf4c15456175a 100644 --- a/AcessNative/acesskernel_src/threads_glue.c +++ b/AcessNative/acesskernel_src/threads_glue.c @@ -20,6 +20,7 @@ typedef void **tShortSpinlock; #include <pthread.h> #define NORETURN __attribute__((noreturn)) +#include <stdbool.h> #include <logdebug.h> // Kernel land, but uses standards #include <errno.h> diff --git a/AcessNative/acesskernel_src/vfs_handle.c b/AcessNative/acesskernel_src/vfs_handle.c index 6c3992f8cb39e2ff898a1bc17b011cfae1d64a2b..93b6a9d674d7354fbb65b8cce57566f1fa7eda6c 100644 --- a/AcessNative/acesskernel_src/vfs_handle.c +++ b/AcessNative/acesskernel_src/vfs_handle.c @@ -79,7 +79,7 @@ void VFS_CloneHandleList(int PID) ent = VFS_int_GetUserHandles(PID, 1); - maxhandles = *Threads_GetMaxFD(); + maxhandles = *Threads_GetMaxFD(NULL); memcpy(ent->Handles, cur->Handles, maxhandles*sizeof(tVFS_Handle)); // Reference all @@ -105,7 +105,7 @@ void VFS_CloneHandlesFromList(int PID, int nFD, int FDs[]) LOG("Copying %i FDs from %i", nFD, PID); - maxhandles = *Threads_GetMaxFD(); + maxhandles = *Threads_GetMaxFD(NULL); if( nFD > maxhandles ) nFD = maxhandles; for( int i = 0; i < nFD; i ++ ) @@ -156,7 +156,7 @@ tVFS_Handle *VFS_GetHandle(int FD) else { int pid = Threads_GetPID(); - int maxhandles = *Threads_GetMaxFD(); + int maxhandles = *Threads_GetMaxFD(NULL); tUserHandles *ent = VFS_int_GetUserHandles(pid, 0); if(!ent) { @@ -193,7 +193,7 @@ int VFS_SetHandle(int FD, tVFS_Node *Node, int Mode) else { tUserHandles *ent; int pid = Threads_GetPID(); - int maxhandles = *Threads_GetMaxFD(); + int maxhandles = *Threads_GetMaxFD(NULL); ent = VFS_int_GetUserHandles(pid, 0); if(!ent) { @@ -219,7 +219,7 @@ int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode) if(bIsUser) { tUserHandles *ent; - int maxhandles = *Threads_GetMaxFD(); + int maxhandles = *Threads_GetMaxFD(NULL); // Find the PID's handle list ent = VFS_int_GetUserHandles(Threads_GetPID(), 1); // Get a handle @@ -254,7 +254,7 @@ void VFS_ClearHandles(int PID) tUserHandles *ent = VFS_int_GetUserHandles(PID, 0); if( !ent ) return; // Get a handle - int maxhandles = *Threads_GetMaxFD(); + int maxhandles = *Threads_GetMaxFD(NULL); for( int i = 0; i < maxhandles; i ++ ) { if(ent->Handles[i].Node) continue; diff --git a/AcessNative/acesskernel_src/video.c b/AcessNative/acesskernel_src/video.c index b1b65b01e6fdc90ce99cdd98c78f0be5459ef2fa..d78f6dadbf3ce7aceb309d1f9d48130cb8f8742f 100644 --- a/AcessNative/acesskernel_src/video.c +++ b/AcessNative/acesskernel_src/video.c @@ -30,7 +30,9 @@ tVFS_NodeType gVideo_NodeType = { }; tDevFS_Driver gVideo_DriverStruct = { NULL, "NativeVideo", - {.Type = &gVideo_NodeType} + { + .Type = &gVideo_NodeType + } }; int giVideo_DriverID; int giVideo_CurrentFormat; @@ -255,6 +257,8 @@ int Video_IOCtl(tVFS_Node *Node, int ID, void *Data) // Video mode control // - We cheat, and only have one mode case VIDEO_IOCTL_GETSETMODE: + // - Abuse GETSETMODE to update size + Node->Size = giUI_Pitch * giUI_Height; return 0; case VIDEO_IOCTL_FINDMODE: case VIDEO_IOCTL_MODEINFO: diff --git a/AcessNative/ld-acess_src/binary.c b/AcessNative/ld-acess_src/binary.c index 59be8295b63de629475a262683053247629ccb20..738c6e819c77966fd36e33647af012883c3ab399 100644 --- a/AcessNative/ld-acess_src/binary.c +++ b/AcessNative/ld-acess_src/binary.c @@ -6,6 +6,7 @@ * - Provides binary loading and type abstraction */ #define DEBUG 0 +#define _POSIX_C_SOURCE 200809L // needed for strdup #include "common.h" #include <stdint.h> #include <stdio.h> @@ -228,7 +229,7 @@ void Binary_SetReadyToUse(void *Base) } } -int Binary_GetSymbol(const char *SymbolName, uintptr_t *Value, size_t *Size) +int Binary_GetSymbol(const char *SymbolName, uintptr_t *Value, size_t *Size, void *IgnoreBase) { int i; tBinary *bin; @@ -251,6 +252,7 @@ int Binary_GetSymbol(const char *SymbolName, uintptr_t *Value, size_t *Size) // Search list of loaded binaries for(bin = gLoadedBinaries; bin; bin = bin->Next) { + if( bin->Base == IgnoreBase ) continue ; if( !bin->Ready ) continue; //printf(" Binary_GetSymbol: bin = %p{%p, %s}\n", bin, bin->Base, bin->Path); if( bin->Format->GetSymbol(bin->Base, (char*)SymbolName, Value, Size) ) diff --git a/AcessNative/ld-acess_src/common.h b/AcessNative/ld-acess_src/common.h index 9f67e9c63d67e3df582612ab9f363073f957109b..0bdc40f247af7cd30556986bda41fff22f2481d1 100644 --- a/AcessNative/ld-acess_src/common.h +++ b/AcessNative/ld-acess_src/common.h @@ -8,16 +8,16 @@ #include <stdint.h> #include <string.h> -extern int Binary_GetSymbol(const char *SymbolName, uintptr_t *Value, size_t *Size); +extern int Binary_GetSymbol(const char *SymbolName, uintptr_t *Value, size_t *Size, void *IgnoreBase); extern void *Binary_LoadLibrary(const char *Path); extern void *Binary_Load(const char *Path, uintptr_t *EntryPoint); extern void Binary_SetReadyToUse(void *Base); // HACKS - So this can share the usermode elf.c -static inline int GetSymbol(const char *sym, void **val, size_t *sz) +static inline int GetSymbol(const char *sym, void **val, size_t *sz, void *IgnoreBase) { uintptr_t rv; - if( !Binary_GetSymbol(sym, &rv, sz) ) + if( !Binary_GetSymbol(sym, &rv, sz, IgnoreBase) ) return 0; *val = (void*)rv; return 1; diff --git a/AcessNative/ld-acess_src/elf_load.c b/AcessNative/ld-acess_src/elf_load.c index 19a8c13fc945255552d3afdc5e93308fd666dbb7..76d92519a8b5ddf2f631d5228838e8c3c43fa718 100644 --- a/AcessNative/ld-acess_src/elf_load.c +++ b/AcessNative/ld-acess_src/elf_load.c @@ -64,17 +64,10 @@ void *Elf_Load(int FD) void *Elf32Load(int FD, Elf32_Ehdr *hdr) { - Elf32_Phdr *phtab; - int i; - int iPageCount; - uint32_t max, base; - uint32_t addr; - uint32_t baseDiff = 0; - ENTER("iFD", FD); // Check for a program header - if(hdr->phoff == 0) { + if(hdr->e_phoff == 0) { #if DEBUG_WARN Warning("ELF File does not contain a program header\n"); #endif @@ -83,25 +76,25 @@ void *Elf32Load(int FD, Elf32_Ehdr *hdr) } // Read Program Header Table - phtab = malloc( sizeof(Elf32_Phdr) * hdr->phentcount ); + Elf32_Phdr* phtab = malloc( sizeof(Elf32_Phdr) * hdr->e_phnum ); if( !phtab ) { LEAVE('n'); return NULL; } - LOG("hdr.phoff = 0x%08x\n", hdr->phoff); - acess__SysSeek(FD, hdr->phoff, ACESS_SEEK_SET); - acess__SysRead(FD, phtab, sizeof(Elf32_Phdr) * hdr->phentcount); + LOG("hdr.e_phoff = 0x%08x\n", hdr->e_phoff); + acess__SysSeek(FD, hdr->e_phoff, ACESS_SEEK_SET); + acess__SysRead(FD, phtab, sizeof(Elf32_Phdr) * hdr->e_phnum); // Count Pages - iPageCount = 0; - LOG("hdr.phentcount = %i\n", hdr->phentcount); - for( i = 0; i < hdr->phentcount; i++ ) + unsigned int iPageCount = 0; + LOG("hdr.e_phnum = %i\n", hdr->e_phnum); + for( unsigned int i = 0; i < hdr->e_phnum; i++ ) { // Ignore Non-LOAD types - if(phtab[i].Type != PT_LOAD) + if(phtab[i].p_type != PT_LOAD) continue; - iPageCount += ((phtab[i].VAddr&0xFFF) + phtab[i].MemSize + 0xFFF) >> 12; - LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}\n", i, phtab[i].VAddr, phtab[i].MemSize); + iPageCount += ((phtab[i].p_vaddr&0xFFF) + phtab[i].p_memsz + 0xFFF) >> 12; + LOG("phtab[%i] = {p_vaddr:0x%x, p_memsz:0x%x}\n", i, phtab[i].p_vaddr, phtab[i].MemSize); } LOG("iPageCount = %i\n", iPageCount); @@ -115,20 +108,21 @@ void *Elf32Load(int FD, Elf32_Ehdr *hdr) //ret->Interpreter = NULL; // Prescan for base and size - max = 0; - base = 0xFFFFFFFF; - for( i = 0; i < hdr->phentcount; i ++) + uint32_t max = 0; + uint32_t base = UINT32_MAX; + for( unsigned int i = 0; i < hdr->e_phnum; i ++) { - if( phtab[i].Type != PT_LOAD ) + if( phtab[i].p_type != PT_LOAD ) continue; - if( phtab[i].VAddr < base ) - base = phtab[i].VAddr; - if( phtab[i].VAddr + phtab[i].MemSize > max ) - max = phtab[i].VAddr + phtab[i].MemSize; + if( phtab[i].p_vaddr < base ) + base = phtab[i].p_vaddr; + if( phtab[i].p_vaddr + phtab[i].p_memsz > max ) + max = phtab[i].p_vaddr + phtab[i].p_memsz; } LOG("base = %08x, max = %08x\n", base, max); + uint32_t baseDiff = 0; if( base == 0 ) { // Find a nice space (47 address bits allowed) base = FindFreeRange( max, 47 ); @@ -138,39 +132,39 @@ void *Elf32Load(int FD, Elf32_Ehdr *hdr) } // Load Pages - for( i = 0; i < hdr->phentcount; i++ ) + for( unsigned int i = 0; i < hdr->e_phnum; i++ ) { // Get Interpreter Name - if( phtab[i].Type == PT_INTERP ) + if( phtab[i].p_type == PT_INTERP ) { char *tmp; //if(ret->Interpreter) continue; - tmp = malloc(phtab[i].FileSize); - acess__SysSeek(FD, phtab[i].Offset, ACESS_SEEK_SET); - acess__SysRead(FD, tmp, phtab[i].FileSize); + tmp = malloc(phtab[i].p_filesz); + acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET); + acess__SysRead(FD, tmp, phtab[i].p_filesz); //ret->Interpreter = Binary_RegInterp(tmp); LOG("Interpreter '%s'\n", tmp); free(tmp); continue; } // Ignore non-LOAD types - if(phtab[i].Type != PT_LOAD) continue; + if(phtab[i].p_type != PT_LOAD) continue; - LOG("phtab[%i] = PT_LOAD {Adj VAddr:0x%x, Offset:0x%x, FileSize:0x%x, MemSize:0x%x}\n", - i, phtab[i].VAddr+baseDiff, phtab[i].Offset, phtab[i].FileSize, phtab[i].MemSize); + LOG("phtab[%i] = PT_LOAD {Adj p_vaddr:0x%x, p_offset:0x%x, p_filesz:0x%x, p_memsz:0x%x}\n", + i, phtab[i].p_vaddr+baseDiff, phtab[i].p_offset, phtab[i].p_filesz, phtab[i].p_memsz); - addr = phtab[i].VAddr + baseDiff; + uint64_t addr = phtab[i].p_vaddr + baseDiff; - if( AllocateMemory( addr, phtab[i].MemSize ) ) { - fprintf(stderr, "Elf_Load: Unable to map memory at %x (0x%x bytes)\n", - addr, phtab[i].MemSize); + if( AllocateMemory( addr, phtab[i].p_memsz ) ) { + fprintf(stderr, "Elf_Load: Unable to map memory at 0x%"PRIx64" (0x%x bytes)\n", + addr, phtab[i].p_memsz); free( phtab ); return NULL; } - acess__SysSeek(FD, phtab[i].Offset, ACESS_SEEK_SET); - acess__SysRead(FD, PTRMK(void, addr), phtab[i].FileSize); - memset( PTRMK(char, addr) + phtab[i].FileSize, 0, phtab[i].MemSize - phtab[i].FileSize ); + acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET); + acess__SysRead(FD, PTRMK(void, addr), phtab[i].p_filesz); + memset( PTRMK(char, addr) + phtab[i].p_filesz, 0, phtab[i].p_memsz - phtab[i].p_filesz ); } // Clean Up @@ -182,13 +176,6 @@ void *Elf32Load(int FD, Elf32_Ehdr *hdr) void *Elf64Load(int FD, Elf64_Ehdr *hdr) { - Elf64_Phdr *phtab; - int i; - int iPageCount; - uint64_t max, base; - uint64_t addr; - uint64_t baseDiff = 0; - ENTER("iFD", FD); if( sizeof(void*) == 4) { @@ -205,25 +192,25 @@ void *Elf64Load(int FD, Elf64_Ehdr *hdr) } // Read Program Header Table - phtab = malloc( sizeof(Elf64_Phdr) * hdr->e_phnum ); + Elf64_Phdr* phtab = malloc( sizeof(Elf64_Phdr) * hdr->e_phnum ); if( !phtab ) { LEAVE('n'); return NULL; } - LOG("hdr.phoff = 0x%08llx\n", (long long)hdr->e_phoff); + LOG("hdr.e_phoff = 0x%08llx\n", (long long)hdr->e_phoff); acess__SysSeek(FD, hdr->e_phoff, ACESS_SEEK_SET); acess__SysRead(FD, phtab, sizeof(Elf64_Phdr) * hdr->e_phnum); // Count Pages - iPageCount = 0; - LOG("hdr.phentcount = %i\n", hdr->e_phnum); - for( i = 0; i < hdr->e_phnum; i++ ) + unsigned int iPageCount = 0; + LOG("hdr.e_phnum = %i\n", hdr->e_phnum); + for( unsigned int i = 0; i < hdr->e_phnum; i++ ) { // Ignore Non-LOAD types if(phtab[i].p_type != PT_LOAD) continue; iPageCount += ((phtab[i].p_vaddr&0xFFF) + phtab[i].p_memsz + 0xFFF) >> 12; - LOG("phtab[%i] = {VAddr:0x%llx, MemSize:0x%llx}\n", + LOG("phtab[%i] = {p_vaddr:0x%llx, p_memsz:0x%llx}\n", i, (long long)phtab[i].p_vaddr, (long long)phtab[i].p_memsz); } @@ -238,9 +225,9 @@ void *Elf64Load(int FD, Elf64_Ehdr *hdr) //ret->Interpreter = NULL; // Prescan for base and size - max = 0; - base = 0xFFFFFFFF; - for( i = 0; i < hdr->e_phnum; i ++) + uint64_t max = 0; + uint64_t base = UINT64_MAX; + for( unsigned int i = 0; i < hdr->e_phnum; i ++) { if( phtab[i].p_type != PT_LOAD ) continue; @@ -252,16 +239,18 @@ void *Elf64Load(int FD, Elf64_Ehdr *hdr) LOG("base = %08lx, max = %08lx\n", base, max); + uint64_t baseDiff = 0; if( base == 0 ) { // Find a nice space (31 address bits allowed) base = FindFreeRange( max, 31 ); LOG("new base = %08lx\n", base); - if( base == 0 ) return NULL; + if( base == 0 ) + goto _err; baseDiff = base; } // Load Pages - for( i = 0; i < hdr->e_phnum; i++ ) + for( unsigned int i = 0; i < hdr->e_phnum; i++ ) { // Get Interpreter Name if( phtab[i].p_type == PT_INTERP ) @@ -280,19 +269,18 @@ void *Elf64Load(int FD, Elf64_Ehdr *hdr) // Ignore non-LOAD types if(phtab[i].p_type != PT_LOAD) continue; - LOG("phtab[%i] = PT_LOAD {Adj VAddr:0x%llx, Offset:0x%llx, FileSize:0x%llx, MemSize:0x%llx}\n", + LOG("phtab[%i] = PT_LOAD {Adj p_vaddr:0x%llx, p_offset:0x%llx, p_filesz:0x%llx, p_memsz:0x%llx}\n", i, (long long)phtab[i].p_vaddr+baseDiff, (long long)phtab[i].p_offset, (long long)phtab[i].p_filesz, (long long)phtab[i].p_memsz ); - addr = phtab[i].p_vaddr + baseDiff; + uint64_t addr = phtab[i].p_vaddr + baseDiff; if( AllocateMemory( addr, phtab[i].p_memsz ) ) { fprintf(stderr, "Elf_Load: Unable to map memory at %"PRIx64" (0x%"PRIx64" bytes)\n", (uint64_t)addr, (uint64_t)phtab[i].p_memsz); - free( phtab ); - return NULL; + goto _err; } acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET); @@ -305,5 +293,9 @@ void *Elf64Load(int FD, Elf64_Ehdr *hdr) // Return LEAVE('p', base); return PTRMK(void, base); +_err: + free(phtab); + LEAVE('n'); + return NULL; } diff --git a/AcessNative/ld-acess_src/exports.c b/AcessNative/ld-acess_src/exports.c index a898b5a3e24f9d06d32358585abfecad9a193143..8064bb8bb1f54ab13c33fed52ccd4ac1ef504a12 100644 --- a/AcessNative/ld-acess_src/exports.c +++ b/AcessNative/ld-acess_src/exports.c @@ -53,7 +53,13 @@ int acess__SysOpen(const char *Path, unsigned int Flags) { if( strncmp(Path, "$$$$", 4) == 0 ) { - return native_open(Path, Flags) | NATIVE_FILE_MASK; + return native_open(Path+4, Flags) | NATIVE_FILE_MASK; + } + if( strncmp(Path, "/Devices/shm/", 13) == 0 ) + { + const char* tag = Path + 13; + Warning("TODO: Handle open SHM \"%s\"", tag); + return native_shm(tag, Flags) | NATIVE_FILE_MASK; } SYSTRACE("open(\"%s\", 0x%x)", Path, Flags); return _Syscall(SYS_OPEN, ">s >i", Path, Flags); @@ -95,6 +101,10 @@ size_t acess__SysWrite(int FD, const void *Src, size_t Bytes) { SYSTRACE("_SysWrite(0x%x, 0x%x, %p\"%.*s\")", FD, Bytes, Src, Bytes, (char*)Src); return _Syscall(SYS_WRITE, ">i >i >d", FD, Bytes, Bytes, Src); } +uint64_t acess__SysTruncate(int fd, uint64_t size) { + TODO(); + return 0; +} int acess__SysSeek(int FD, int64_t Ofs, int Dir) { @@ -156,6 +166,26 @@ int acess__SysUnlink(const char *pathname) TODO(); return 0; } +void* acess__SysMMap(void *addr, size_t length, unsigned int _flags, int fd, uint64_t offset) +{ + TODO(); + return NULL; +} +int acess__SysMUnMap(void *addr, size_t length) +{ + TODO(); + return 0; +} +uint64_t acess__SysMarshalFD(int FD) +{ + TODO(); + return 0; +} +int acess__SysUnMarshalFD(uint64_t Handle) +{ + TODO(); + return -1; +} int acess__SysOpenChild(int fd, char *name, int flags) { SYSTRACE("_SysOpenChild(0x%x, '%s', 0x%x)", fd, name, flags); @@ -224,10 +254,7 @@ int acess__SysLoadModule(const char *Path) // --- Timekeeping --- int64_t acess__SysTimestamp(void) { - // TODO: Better impl - TODO(); -// return now()*1000; - return 0; + return native_timestamp(); } // --- Memory Management --- @@ -418,19 +445,69 @@ int acess__SysWaitEvent(int Mask) } // --- Logging +static void int_dbgheader(void ) +{ + printf("[_SysDebug %i] ", giSyscall_ClientID); +} void acess__SysDebug(const char *Format, ...) { va_list args; va_start(args, Format); - - printf("[_SysDebug %i] ", giSyscall_ClientID); + int_dbgheader(); vprintf(Format, args); printf("\n"); va_end(args); } +void acess__SysDebugHex(const char *tag, const void *data, size_t size) +{ + int_dbgheader(); + printf("%s (Hexdump of %p+%zi)\r\n", tag, data, size); + + #define CH(n) ((' '<=cdat[(n)]&&cdat[(n)]<0x7F) ? cdat[(n)] : '.') + + const uint8_t *cdat = data; + unsigned int pos = 0; + + while(size >= 16) + { + int_dbgheader(); + printf("%04x:" + " %02x %02x %02x %02x %02x %02x %02x %02x " + " %02x %02x %02x %02x %02x %02x %02x %02x " + " %c%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c\r\n", + pos, + cdat[ 0], cdat[ 1], cdat[ 2], cdat[ 3], cdat[ 4], cdat[ 5], cdat[ 6], cdat[ 7], + cdat[ 8], cdat[ 9], cdat[10], cdat[11], cdat[12], cdat[13], cdat[14], cdat[15], + CH(0), CH(1), CH(2), CH(3), CH(4), CH(5), CH(6), CH(7), + CH(8), CH(9), CH(10), CH(11), CH(12), CH(13), CH(14), CH(15) + ); + size -= 16; + cdat += 16; + pos += 16; + } + + { + int_dbgheader(); + printf("%04x: ", pos); + for(int i = 0; i < size; i ++) + printf("%02x ", cdat[i]); + for(int i = size; i < 16; i ++) + printf(" "); + printf(" "); + for(int i = 0; i < size; i ++) + { + if( i == 8 ) + printf(" "); + printf("%c", CH(i)); + } + + printf("\n"); + } +} + void acess__exit(int Status) { DEBUG("_exit(%i)", Status); @@ -489,6 +566,9 @@ const tSym caBuiltinSymbols[] = { DEFSYM(_SysAllocate), DEFSYM(_SysSetMemFlags), DEFSYM(_SysDebug), + {"_ZN4_sys5debugEPKcz", &acess__SysDebug}, + DEFSYM(_SysDebugHex), + {"_ZN4_sys7hexdumpEPKcPKvj", &acess__SysDebugHex}, DEFSYM(_SysSetFaultHandler), DEFSYM(_SysWaitEvent), diff --git a/AcessNative/ld-acess_src/exports.h b/AcessNative/ld-acess_src/exports.h index e8f2e4c8a71425890cb607ab7d989d19ba614b18..94987d0b49e4eaa3791ba7679ff240f02cebe310 100644 --- a/AcessNative/ld-acess_src/exports.h +++ b/AcessNative/ld-acess_src/exports.h @@ -17,6 +17,7 @@ extern uint64_t _Syscall(int SyscallID, const char *ArgTypes, ...); extern int acess__errno; extern int native_open(const char *Path, int Flags); +extern int native_shm(const char *Tag, int Flags); extern void native_close(int FD); extern size_t native_read(int FD, void *Dest, size_t Bytes); extern size_t native_write(int FD, const void *Src, size_t Bytes); @@ -26,6 +27,8 @@ extern uint64_t native_tell(int FD); extern int native_execve(const char *filename, const char *const argv[], const char *const envp[]); extern int native_spawn(const char *filename, const char *const argv[], const char *const envp[]); +extern int64_t native_timestamp(void); + // Syscalls used by the linker extern int acess__SysOpen(const char *Path, unsigned int Flags); extern void acess__SysClose(int FD); diff --git a/AcessNative/ld-acess_src/memory.c b/AcessNative/ld-acess_src/memory.c index c8166af4fb9bc2bf7f5da71f3e8d88000960f759..99238a5222719485605347661dd33333820780da 100644 --- a/AcessNative/ld-acess_src/memory.c +++ b/AcessNative/ld-acess_src/memory.c @@ -1,5 +1,6 @@ /* */ +#define _GNU_SOURCE // needed for MAP_ANONYMOUS to be avaliable #include "common.h" #include <stdio.h> #include <stdlib.h> diff --git a/AcessNative/ld-acess_src/request.c b/AcessNative/ld-acess_src/request.c index fdf57485e860e61e02aa3fe0a1d87a459245bc56..690c7f7ff35221542b3a1b8e5c4064d8adc9b6ce 100644 --- a/AcessNative/ld-acess_src/request.c +++ b/AcessNative/ld-acess_src/request.c @@ -25,6 +25,7 @@ # include <unistd.h> # include <sys/socket.h> # include <netinet/in.h> +# include <sys/select.h> #endif #include "request.h" #include "../syscalls.h" @@ -228,12 +229,12 @@ int SendRequest(tRequestHeader *Request, int RequestSize, int ResponseSize) // Send it off SendData(Request, RequestSize); - if( Request->CallID == SYS_EXIT ) return 0; - // Wait for a response (no timeout) ReadData(Request, sizeof(*Request), 0); + + size_t recvbytes = sizeof(*Request); // TODO: Sanity - size_t recvbytes = sizeof(*Request), expbytes = Request->MessageLength; + size_t expbytes = Request->MessageLength; char *ptr = (void*)Request->Params; while( recvbytes < expbytes ) { diff --git a/AcessNative/ld-acess_src/syscalls.c b/AcessNative/ld-acess_src/syscalls.c index 60b7d952ed53fbae526efe418de13dc321017166..3341a9568f32745f49b4273ba6f0f79f39ca36fb 100644 --- a/AcessNative/ld-acess_src/syscalls.c +++ b/AcessNative/ld-acess_src/syscalls.c @@ -13,6 +13,7 @@ # include <spawn.h> // posix_spawn #endif #include "request.h" +#include <sys/time.h> #define assert(cnd) do{ \ if( !(cnd) ) { \ @@ -171,7 +172,6 @@ uint64_t _Syscall(int SyscallID, const char *ArgTypes, ...) tRequestHeader *req; void *dataPtr; uint64_t retValue; - int i; // DEBUG! // printf("&tRequestHeader->Params = %i\n", offsetof(tRequestHeader, Params)); @@ -244,8 +244,11 @@ uint64_t _Syscall(int SyscallID, const char *ArgTypes, ...) exit(127); } + if( !(req->NParams >= 2) ) { + fprintf(stderr, "syscalls.c: Too few return params (%i)", req->NParams); + exit(127); + } dataPtr = (void*)&req->Params[req->NParams]; - assert(req->NParams >= 2); // return assert(req->Params[0].Type == ARG_TYPE_INT64); assert(req->Params[0].Length == sizeof(uint64_t)); @@ -264,7 +267,7 @@ uint64_t _Syscall(int SyscallID, const char *ArgTypes, ...) exit(127); } retCount = 0; - for( i = 2; i < req->NParams; i ++ ) + for( unsigned int i = 2; i < req->NParams; i ++ ) { #if 0 int j; @@ -288,18 +291,40 @@ uint64_t _Syscall(int SyscallID, const char *ArgTypes, ...) return retValue; } +int native_int_getfd(void) +{ + for(int ret = 0; ret < MAX_FPS; ret ++ ) + if( gaSyscall_LocalFPs[ret] == NULL ) + return ret; + return -1; +} int native_open(const char *Path, int Flags) { - int ret; - for(ret = 0; ret < MAX_FPS && gaSyscall_LocalFPs[ret]; ret ++ ) ; - if(ret == MAX_FPS) return -1; + int ret = native_int_getfd(); + if(ret == -1) return -1; // TODO: Handle directories - gaSyscall_LocalFPs[ret] = fopen(&Path[4], "r+"); + gaSyscall_LocalFPs[ret] = fopen(Path, "r+"); if(!gaSyscall_LocalFPs[ret]) return -1; return ret; } +int native_shm(const char *Tag, int Flags) +{ + // int ret = native_int_getfd(); + //if(ret == -1) return -1; + //if( strcmp(Tag, "anon") == 0 ) + // path = "/AcessNative/anon/RAND"; + // FD = shm_open(path, O_RDWD); + //shm_unlink(path); + //else + // path = "/Acessnative/named/<TAG>"; + // int FD = shm_open(path, O_RDWD); + //shm_unlink(path); + //gaSyscall_LocalFPs[ret] = + return -1; +} + void native_close(int FD) { fclose( gaSyscall_LocalFPs[FD] ); @@ -357,3 +382,10 @@ int native_spawn(const char *filename, const char *const argv[], const char *con return rv; } + +int64_t native_timestamp(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec*1000 + tv.tv_usec / 1000; +} diff --git a/AcessNative/libacess-native.so_src/Makefile b/AcessNative/libacess-native.so_src/Makefile index 927831146e09a1b5da461e95e02d5d9464c84bd8..2a0f0c4c46079beb4a3cfa1c6c53ee7d210d0c01 100644 --- a/AcessNative/libacess-native.so_src/Makefile +++ b/AcessNative/libacess-native.so_src/Makefile @@ -20,7 +20,7 @@ $(warning $(BINLINK)) CFLAGS += -Wall CFLAGS += -Werror -CFLAGS += -g -shared -fPIC +CFLAGS += -g -shared -fPIC -std=c99 CPPFLAGS += -DARCHDIR_is_x86_64=1 LDFLAGS += -g -shared -Wl,--no-undefined -lc diff --git a/AcessNative/libacess-native.so_src/exports.c b/AcessNative/libacess-native.so_src/exports.c index 2f960c4fefae34f152502fbfe7f5b3164684a259..ad5aac4911b39a9316d86461efc4ee35ae758627 100644 --- a/AcessNative/libacess-native.so_src/exports.c +++ b/AcessNative/libacess-native.so_src/exports.c @@ -10,6 +10,9 @@ int *libc_geterrno(void) return &acess__errno; } +void _ZN4_sys5debugEPKcz(const char *fmt, ...) __attribute__((alias("acess__SysDebug"))); +void _ZN4_sys7hexdumpEPKcPKvj(const char *tag, const void *ptr, size_t size) __attribute__((alias("acess__SysDebugHex"))); + #undef acess__SysSpawn int acess__SysSpawn(const char *binary, const char **argv, const char **envp, int nfd, int fds[], struct s_sys_spawninfo *info) diff --git a/AcessNative/libacess-native.so_src/main.c b/AcessNative/libacess-native.so_src/main.c index 74d9d3c62d9baa7a62da054e7cb8dd67e08d5ecd..b5f066f70809e5bc4868aec4c2affc7413b8e7bc 100644 --- a/AcessNative/libacess-native.so_src/main.c +++ b/AcessNative/libacess-native.so_src/main.c @@ -10,6 +10,8 @@ #include <stdint.h> #include "../ld-acess_src/exports.h" +extern int gbSyscallDebugEnabled; + #ifdef __WINDOWS__ int DllMain(void) { @@ -40,10 +42,13 @@ int libacessnative_init(int argc, char *argv[], char **envp) { Request_Preinit(); + //gbSyscallDebugEnabled = 1; + const char *preopens = getenv_p(envp, ENV_VAR_PREOPENS); printf("preopens = %s\n", preopens); if( preopens ) { + int exp_fd = 0; while( *preopens ) { const char *splitter = strchr(preopens, ':'); @@ -59,8 +64,16 @@ int libacessnative_init(int argc, char *argv[], char **envp) path[len] = 0; int fd = acess__SysOpen(path, 6); // WRITE,READ,no EXEC if( fd == -1 ) { - fprintf(stderr, "Unable to preopen '%s'\n", path); + fprintf(stderr, "Unable to preopen '%s' errno=%i\n", path, acess__errno); + exit(1); + } + if( fd != exp_fd ) { + // Oh... this is bad + fprintf(stderr, "Pre-opening '%s' resulted in an incorrect FD (expected %i, got %i)", + path, exp_fd, fd); + exit(1); } + exp_fd += 1; if( !splitter ) break; @@ -77,7 +90,7 @@ int libacessnative_init(int argc, char *argv[], char **envp) int acessnative_spawn(const char *Binary, int SyscallID, const char * const * argv, const char * const * envp) { int envc = 0; - while( envp[envc++] ) + while( envp && envp[envc++] ) envc ++; // Set environment variables for libacess-native @@ -89,7 +102,7 @@ int acessnative_spawn(const char *Binary, int SyscallID, const char * const * ar const char *newenv[envc+2+1]; int i = 0; - for( ; envp[i]; i ++ ) + for( ; envp && envp[i]; i ++ ) { const char *ev = envp[i]; if( strncmp(ev, ENV_VAR_KEY"=", sizeof(ENV_VAR_KEY"=")) == 0 ) { @@ -100,7 +113,7 @@ int acessnative_spawn(const char *Binary, int SyscallID, const char * const * ar } if( !bKeyHit ) newenv[i++] = keystr; - newenv[i++] = "LD_LIBRARY_PATH=Libs/"; // HACK + newenv[i++] = getenv("LD_LIBRARY_PATH") - (sizeof("LD_LIBRARY_PATH=")-1); // VERY hacky newenv[i] = NULL; // TODO: Detect native_spawn failing @@ -127,17 +140,3 @@ void Warning(const char *format, ...) printf("\n"); } -void __libc_csu_fini() -{ -} - -void __libc_csu_init() -{ -} - -void __stack_chk_fail(void) -{ - fprintf(stderr, "__stack_chk_fail"); - exit(1); -} - diff --git a/BuildConf/armv7/Makefile.cfg b/BuildConf/armv7/Makefile.cfg index d2f0a0f74371b1ff84668f71076dcd384c3d3374..3180234a859e2f9cbc78b2252dd8261ca3d1e68d 100644 --- a/BuildConf/armv7/Makefile.cfg +++ b/BuildConf/armv7/Makefile.cfg @@ -1,12 +1,9 @@ +TRIPLET = arm-pc-acess2 ARM_CPUNAME = gerneric-armv7 -CC = arm-eabi-gcc -mcpu=$(ARM_CPUNAME) -AS = arm-eabi-gcc -mcpu=$(ARM_CPUNAME) -c -LD = arm-eabi-ld -OBJDUMP = arm-eabi-objdump +#AS = $(TRIPLET)-gcc -mcpu=$(ARM_CPUNAME) -c DISASM := $(OBJDUMP) -d -S ARCHDIR = armv7 -STRIP = arm-eabi-strip ASSUFFIX = S diff --git a/BuildConf/x86/Makefile.cfg b/BuildConf/x86/Makefile.cfg index 6559146ec7483570f69b5bfecb22300c08b1cff9..271059c88b5a48e5d4c948f01f31ccf7a4cb67ff 100644 --- a/BuildConf/x86/Makefile.cfg +++ b/BuildConf/x86/Makefile.cfg @@ -2,15 +2,8 @@ # Acess2 Build Configuration # -CC = i586-elf-gcc -CXX = i586-elf-g++ -#CC = clang -m32 -LD = i586-elf-ld -#CC = gcc -#LD = ld +TRIPLET = i686-pc-acess2 AS = nasm -#OBJDUMP = i586-elf-objdump -OBJDUMP = objdump RM = @rm -f STRIP = strip diff --git a/BuildConf/x86_64/Makefile.cfg b/BuildConf/x86_64/Makefile.cfg index cc252bc57426e1bec38c3532b8f586ea7ff88833..20dcbb2025032c96110b8e5d8e928b923d41de61 100644 --- a/BuildConf/x86_64/Makefile.cfg +++ b/BuildConf/x86_64/Makefile.cfg @@ -1,10 +1,6 @@ -#PREFIX := x86_64-pc-elf -PREFIX := x86_64-none-elf - -CC := $(PREFIX)-gcc -LD := $(PREFIX)-ld -DISASM = $(PREFIX)-objdump -d -M x86-64 -S +TRIPLET = x86_64-pc-acess2 +AS = nasm KERNEL_CFLAGS := -mcmodel=kernel -nostdlib -mno-red-zone -Wall -mno-sse DYNMOD_CFLAGS := -mcmodel=small -fPIC -mno-red-zone -mno-sse diff --git a/Externals/common_automake.mk b/Externals/common_automake.mk index 70b1978eb7e619b033b6179f5b66e2e4f6b0cbe4..c7e67c3cec50a43190ef5ca4e3040052f86155ca 100644 --- a/Externals/common_automake.mk +++ b/Externals/common_automake.mk @@ -24,9 +24,9 @@ endif $(BDIR)/Makefile: _patch $(CONFIGSCRIPT) ../common_automake.mk Makefile mkdir -p $(BDIR) - cd $(BDIR) && $(CONFIGURE_ENV) PATH=$(PATH) $(CONFIGURE_LINE) + cd $(BDIR) && $(CONFIGURE_ENV) PATH="$(PATH)" $(CONFIGURE_LINE) _build: $(BDIR)/Makefile - PATH=$(PATH) make $(BTARGETS) -C $(BDIR) - PATH=$(PATH) make DESTDIR=$(OUTDIR) $(ITARGETS) -C $(BDIR) + PATH="$(PATH)" make $(BTARGETS) -C $(BDIR) + PATH="$(PATH)" make DESTDIR=$(OUTDIR) $(ITARGETS) -C $(BDIR) diff --git a/Externals/config.mk b/Externals/config.mk index 3d7913b5f00d70f927d9a35ec56c743f50d4ab9f..9db8f0dedfec4c3d3773ed9258b91ce25e094163 100644 --- a/Externals/config.mk +++ b/Externals/config.mk @@ -4,9 +4,11 @@ -include ../../Makefile.cfg ifeq ($(ARCH),x86) - BFD := i586 + BFD := i686 else ifeq ($(ARCH),x86_64) BFD := x86_64 +else ifeq ($(ARCH),armv7) + BFD := arm else $(error No BFD translation for $(ARCH) in Externals/config.mk) endif diff --git a/Externals/core.mk b/Externals/core.mk index bc7a5b80184cb3f17389129e5379c86b8f781ac9..6c23a33ba520f59eafe1aa0c09d9b88dba87feef 100644 --- a/Externals/core.mk +++ b/Externals/core.mk @@ -73,7 +73,14 @@ $(DIR)/%: patches/% PATCHED_FILES := $(addprefix $(DIR)/,$(PATCHES)) -_patch: $(DIR) $(PATCHED_FILES) $(wildcard patches/UNIFIED.patch) ifneq ($(wildcard patches/UNIFIED.patch),) +$(DIR)/_unified_applied: $(wildcard patches/UNIFIED.patch) cd $(DIR) && patch -p1 < ../patches/UNIFIED.patch + touch $@ +UNIFIED_TARGET=$(DIR)/_unified_applied +else +UNIFIED_TARGET= endif + +_patch: $(DIR) $(PATCHED_FILES) $(UNIFIED_TARGET) + diff --git a/Externals/cross-compiler/Makefile b/Externals/cross-compiler/Makefile index 9dde5d8859c50bfd438b82f239a6204ca30fbe98..ae2df5ae1c5cd6819319a0e9dc2452d213df7e0d 100644 --- a/Externals/cross-compiler/Makefile +++ b/Externals/cross-compiler/Makefile @@ -1,67 +1,28 @@ +# +# +# +include Makefile.common.mk +GCC_TARGETS := gcc --include ../config.mk +PREFIX := $(OUTDIR) +BDIR := build-n-$(ARCH)/ +BDIR_GCC := $(BDIR)gcc +BDIR_BINUTILS := $(BDIR)binutils -GCC_ARCHIVE:=$(lastword $(sort $(wildcard gcc-*.tar.bz2))) -GCC_DIR:=$(GCC_ARCHIVE:%.tar.bz2=%) -BINUTILS_ARCHIVE:=$(lastword $(sort $(wildcard binutils-*.tar.bz2))) -BINUTILS_DIR:=$(BINUTILS_ARCHIVE:%.tar.bz2=%) +ENVVARS := PATH=$(OUTDIR)-BUILD/bin:$$PATH -BINUTILS_CHANGES := config.sub bfd/config.bfd gas/configure.tgt ld/configure.tgt ld/emulparams/acess2_i386.sh ld/emulparams/acess2_amd64.sh ld/Makefile.in -GCC_CHANGES := config.sub gcc/config.gcc gcc/config/acess2.h libgcc/config.host -# libstdc++-v3/crossconfig.m4 config/override.m4 - -TARGET=$(HOST) -GCC_TARGETS := gcc target-libgcc -# target-libstdc++-v3 - -PREFIX := $(OUTDIR)-BUILD -BDIR_GCC := build-$(ARCH)/gcc -BDIR_BINUTILS := build-$(ARCH)/binutils - -.PHONY: all clean binutils gcc include - -all: include binutils gcc +include Makefile.rules.mk include: mkdir -p $(PREFIX) - mkdir -p $(SYSROOT)/usr - ln -sf $(ACESSDIR)/Usermode/include $(SYSROOT)/usr/include - ln -sf $(ACESSDIR)/Usermode/Output/$(ARCH)/Libs $(SYSROOT)/usr/lib - -gcc: $(GCC_DIR) $(PREFIX)/bin/$(TARGET)-gcc - -binutils: $(BINUTILS_DIR) $(PREFIX)/bin/$(TARGET)-ld - -clean: - $(RM) -rf $(BINUTILS_DIR) $(GCC_DIR) build-$(ARCH) - -$(BINUTILS_DIR) $(GCC_DIR): %: %.tar.bz2 - tar -xf $< -$(warning $(BINUTILS_DIR) $(GCC_DIR)) - -$(GCC_DIR)/%: patches/gcc/%.patch - @echo [PATCH] $@ - #@tar -xf $(GCC_ARCHIVE) $@ - @patch $@ $< -$(GCC_DIR)/%: patches/gcc/% - @echo [CP] $@ - @cp $< $@ - -$(BINUTILS_DIR)/%: patches/binutils/%.patch - @echo [PATCH] $@ - #@tar -xf $(BINUTILS_ARCHIVE) $@ - @patch $@ $< -$(BINUTILS_DIR)/%: patches/binutils/% - @echo [CP] $@ - @cp $< $@ $(GCC_DIR)/libstdc++-v3/configure: $(GCC_DIR)/libstdc++-v3/crossconfig.m4 cd $(GCC_DIR)/libstdc++-v3/ && autoconf $(BDIR_BINUTILS)/Makefile: $(addprefix $(BINUTILS_DIR)/,$(BINUTILS_CHANGES)) @mkdir -p $(BDIR_BINUTILS) - @cd $(BDIR_BINUTILS) && ../../$(BINUTILS_DIR)/configure --target=$(TARGET) --prefix=$(PREFIX) --disable-nls "--with-sysroot=$(SYSROOT)" --enable-shared + @cd $(BDIR_BINUTILS) && ../../$(BINUTILS_DIR)/configure --target=$(TARGET) --prefix=$(PREFIX) --disable-nls --enable-shared --without-docdir $(PREFIX)/bin/$(TARGET)-ld: $(BDIR_BINUTILS)/Makefile @make -C $(BDIR_BINUTILS) all -j $(PARLEVEL) @@ -69,10 +30,12 @@ $(PREFIX)/bin/$(TARGET)-ld: $(BDIR_BINUTILS)/Makefile $(BDIR_GCC)/Makefile: Makefile $(addprefix $(GCC_DIR)/,$(GCC_CHANGES)) $(GCC_DIR)/libstdc++-v3/configure @mkdir -p $(BDIR_GCC) - @cd $(BDIR_GCC) && PATH=$(PREFIX)/bin:$$PATH ../../$(GCC_DIR)/configure --target=$(TARGET) --prefix=$(PREFIX) --disable-nls --enable-langs=c,c++ --includedir=$(ACESSDIR)/Usermode/include "--with-sysroot=$(SYSROOT)" + @cd $(BDIR_GCC) && $(ENVVARS) ../../$(GCC_DIR)/configure --target=$(TARGET) --prefix=$(PREFIX) --disable-nls --enable-langs=c,c++ --includedir=$(ACESSDIR)/Usermode/include --without-docdir --enable-threads=posix + @echo "MAKEINFO = :" >> $(BDIR_GCC)/Makefile $(PREFIX)/bin/$(TARGET)-gcc: $(BDIR_GCC)/Makefile - @PATH=$(PREFIX)/bin:$$PATH make -C $(BDIR_GCC) $(GCC_TARGETS:%=all-%) -j $(PARLEVEL) - @PATH=$(PREFIX)/bin:$$PATH make -C $(BDIR_GCC) $(GCC_TARGETS:%=install-%) + @$(ENVVARS) make -C $(BDIR_GCC) $(GCC_TARGETS:%=all-%) -j $(PARLEVEL) + @$(ENVVARS) make -C $(BDIR_GCC)libstdc++-v3/ all-target-libsupc++ -j $(PARLEVEL) + @$(ENVVARS) make -C $(BDIR_GCC) $(GCC_TARGETS:%=install-%) diff --git a/Externals/cross-compiler/Makefile.common.mk b/Externals/cross-compiler/Makefile.common.mk new file mode 100644 index 0000000000000000000000000000000000000000..b986044d2ac6e45580b0cc0af8cd89f1e765a64b --- /dev/null +++ b/Externals/cross-compiler/Makefile.common.mk @@ -0,0 +1,26 @@ +# +# +# +-include ../config.mk + +GCC_ARCHIVE:=$(lastword $(sort $(wildcard gcc-*.tar.bz2))) +GCC_DIR:=$(GCC_ARCHIVE:%.tar.bz2=%) +BINUTILS_ARCHIVE:=$(lastword $(sort $(wildcard binutils-*.tar.bz2))) +BINUTILS_DIR:=$(BINUTILS_ARCHIVE:%.tar.bz2=%) + +ifeq ($(GCC_ARCHIVE),) + $(warning Unable to find a GCC archive matching gcc-*.tar.bz2) + $(error No archive found) +endif +ifeq ($(BINUTILS_ARCHIVE),) + $(warning Unable to find a binutils archive matching binutils-*.tar.bz2) + $(error No archive found) +endif + +BINUTILS_CHANGES := config.sub bfd/config.bfd gas/configure.tgt ld/configure.tgt ld/emulparams/acess2_i386.sh ld/emulparams/acess2_amd64.sh ld/emulparams/acess2_arm.sh ld/Makefile.in +GCC_CHANGES := config.sub gcc/config.gcc gcc/config/acess2.h libgcc/config.host gcc/config/acess2.opt +# libstdc++-v3/crossconfig.m4 config/override.m4 + +TARGET=$(HOST) +GCC_TARGETS := gcc target-libgcc +# target-libstdc++-v3 diff --git a/Externals/cross-compiler/Makefile.cross b/Externals/cross-compiler/Makefile.cross new file mode 100644 index 0000000000000000000000000000000000000000..c6a4edd258ebeb7488c43cd2a3893d55de226271 --- /dev/null +++ b/Externals/cross-compiler/Makefile.cross @@ -0,0 +1,39 @@ +# +# +# +include Makefile.common.mk + +PREFIX := $(OUTDIR)-BUILD +BDIR := build-$(ARCH)/ +BDIR_GCC := $(BDIR)gcc +BDIR_BINUTILS := $(BDIR)binutils + +include Makefile.rules.mk + +include: + mkdir -p $(PREFIX) + mkdir -p $(SYSROOT)/usr + ln -sf $(ACESSDIR)/Usermode/include $(SYSROOT)/usr/include + ln -sf $(ACESSDIR)/Usermode/Output/$(ARCH)/Libs $(SYSROOT)/usr/lib + +$(GCC_DIR)/libstdc++-v3/configure: $(GCC_DIR)/libstdc++-v3/crossconfig.m4 + cd $(GCC_DIR)/libstdc++-v3/ && autoconf + +$(BDIR_BINUTILS)/Makefile: $(addprefix $(BINUTILS_DIR)/,$(BINUTILS_CHANGES)) + @mkdir -p $(BDIR_BINUTILS) + @cd $(BDIR_BINUTILS) && ../../$(BINUTILS_DIR)/configure --target=$(TARGET) --prefix=$(PREFIX) --disable-nls "--with-sysroot=$(SYSROOT)" --enable-shared --without-docdir + +$(PREFIX)/bin/$(TARGET)-ld: $(BDIR_BINUTILS)/Makefile + @make -C $(BDIR_BINUTILS) all -j $(PARLEVEL) + @make -C $(BDIR_BINUTILS) install + +$(BDIR_GCC)/Makefile: Makefile $(addprefix $(GCC_DIR)/,$(GCC_CHANGES)) $(GCC_DIR)/libstdc++-v3/configure + @mkdir -p $(BDIR_GCC) + @cd $(BDIR_GCC) && PATH=$(PREFIX)/bin:$$PATH ../../$(GCC_DIR)/configure --target=$(TARGET) --prefix=$(PREFIX) --disable-nls --enable-langs=c,c++ --includedir=$(ACESSDIR)/Usermode/include "--with-sysroot=$(SYSROOT)" --without-docdir --enable-threads=posix + @echo "MAKEINFO = :" >> $(BDIR_GCC)/Makefile + +$(PREFIX)/bin/$(TARGET)-gcc: $(BDIR_GCC)/Makefile + @PATH=$(PREFIX)/bin:$$PATH make -C $(BDIR_GCC) $(GCC_TARGETS:%=all-%) -j $(PARLEVEL) + @PATH=$(PREFIX)/bin:$$PATH make -C $(BDIR_GCC) $(GCC_TARGETS:%=install-%) + + diff --git a/Externals/cross-compiler/Makefile.rules.mk b/Externals/cross-compiler/Makefile.rules.mk new file mode 100644 index 0000000000000000000000000000000000000000..48bf43de144f91a544ca715dd3041db3bd9cd808 --- /dev/null +++ b/Externals/cross-compiler/Makefile.rules.mk @@ -0,0 +1,32 @@ + +.PHONY: all clean binutils gcc include + +all: include binutils gcc + +clean: + $(RM) -rf $(BINUTILS_DIR) $(GCC_DIR) build-$(ARCH) + +gcc: $(GCC_DIR) $(PREFIX)/bin/$(TARGET)-gcc + +binutils: $(BINUTILS_DIR) $(PREFIX)/bin/$(TARGET)-ld + +$(BINUTILS_DIR) $(GCC_DIR): %: %.tar.bz2 + tar -xf $< + +$(GCC_DIR)/%: patches/gcc/%.patch + @echo [PATCH] $@ + @tar -xf $(GCC_ARCHIVE) $@ + @patch $@ $< +$(GCC_DIR)/%: patches/gcc/% + @echo [CP] $@ + @cp $< $@ + +$(BINUTILS_DIR)/%: patches/binutils/%.patch + @echo [PATCH] $@ + @tar -xf $(BINUTILS_ARCHIVE) $@ + @patch $@ $< +$(BINUTILS_DIR)/%: patches/binutils/% + @echo [CP] $@ + @cp $< $@ + + diff --git a/Externals/cross-compiler/patches/binutils/bfd/config.bfd.patch b/Externals/cross-compiler/patches/binutils/bfd/config.bfd.patch index 6b61642485013e25d47e91d24fb2aebcea3e0126..0c0183101e6135c310aadfd2fba0b4b92a73e4b1 100644 --- a/Externals/cross-compiler/patches/binutils/bfd/config.bfd.patch +++ b/Externals/cross-compiler/patches/binutils/bfd/config.bfd.patch @@ -12,7 +12,7 @@ + want64=true + ;; + arm-*-acess2) -+ targ_defvec=bfd_elf32_arm_vec -+ targ_selvecs="bfd_elf32_arm_vec" ++ targ_defvec=bfd_elf32_littlearm_vec ++ targ_selvecs="bfd_elf32_bigarm_vec" + ;; # END OF targmatch.h diff --git a/Externals/cross-compiler/patches/binutils/gas/configure.tgt.patch b/Externals/cross-compiler/patches/binutils/gas/configure.tgt.patch index a024c0805ee535b43e4b73821eb0bf87cf03e301..6148df197182ced812f85879b7742cbf63b80073 100644 --- a/Externals/cross-compiler/patches/binutils/gas/configure.tgt.patch +++ b/Externals/cross-compiler/patches/binutils/gas/configure.tgt.patch @@ -1,6 +1,7 @@ --- gas/configure.tgt 2011-07-29 00:00:00.000000 +0000 +++ gas/configure.tgt 2013-03-01 10:45:00.000000 +0800 -@@ -173,2 +173,3 @@ +@@ -173,2 +173,4 @@ i386-sequent-bsd*) fmt=aout em=dynix ;; + i386-*-acess2*) fmt=elf ;; ++ arm-*-acess2*) fmt=elf ;; i386-*-beospe*) fmt=coff em=pe ;; diff --git a/Externals/cross-compiler/patches/binutils/ld/Makefile.in.patch b/Externals/cross-compiler/patches/binutils/ld/Makefile.in.patch index 76439619c5cbf79f0515b40ad4ef22a2681cbfb5..becadff7eca3e7385d676604ed1db05ce320ab3b 100644 --- a/Externals/cross-compiler/patches/binutils/ld/Makefile.in.patch +++ b/Externals/cross-compiler/patches/binutils/ld/Makefile.in.patch @@ -1,9 +1,11 @@ --- ld/Makefile.in +++ ld/Makefile.in -@@ -2627,2 +2627,6 @@ +@@ -2627,2 +2627,8 @@ ${GENSCRIPTS} elf32xtensa "$(tdir_elf32xtensa)" +eacess2_i386.c: $(srcdir)/emulparams/acess2_i386.sh $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + ${GENSCRIPTS} acess2_i386 "$(tdir_acess2_i386)" +eacess2_amd64.c: $(srcdir)/emulparams/acess2_amd64.sh $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} + ${GENSCRIPTS} acess2_amd64 "$(tdir_acess2_amd64)" ++eacess2_arm.c: $(srcdir)/emulparams/acess2_arm.sh $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ++ ${GENSCRIPTS} acess2_arm "$(tdir_acess2_arm)" eelf_i386.c: $(srcdir)/emulparams/elf_i386.sh \ diff --git a/Externals/cross-compiler/patches/binutils/ld/configure.tgt.patch b/Externals/cross-compiler/patches/binutils/ld/configure.tgt.patch index 8d6a302ac928710d510aa86becc1ec861d4eb353..1d5a4853b67268c5735114e26be6d3a61db1bd86 100644 --- a/Externals/cross-compiler/patches/binutils/ld/configure.tgt.patch +++ b/Externals/cross-compiler/patches/binutils/ld/configure.tgt.patch @@ -1,7 +1,8 @@ --- ld/configure.tgt +++ ld/configure.tgt -@@ -167,1 +167,3 @@ +@@ -167,1 +167,4 @@ i[3-7]86-*-nto-qnx*) targ_emul=i386nto ;; +i[3-7]86-*-acess2*) targ_emul=acess2_i386 ;; -+x86_64-*-acess2*) targ_emul=acess2_amd64 ;; ++x86_64-*-acess2*) targ_emul=acess2_amd64 ;; ++arm-*-acess2*) targ_emul=acess2_arm ;; diff --git a/Externals/cross-compiler/patches/binutils/ld/emulparams/acess2_amd64.sh b/Externals/cross-compiler/patches/binutils/ld/emulparams/acess2_amd64.sh index d31dae98e1cc72466b11a52a065411b701ade2df..3d027850897961e4960b3aac4a2fd9d84dff0b36 100644 --- a/Externals/cross-compiler/patches/binutils/ld/emulparams/acess2_amd64.sh +++ b/Externals/cross-compiler/patches/binutils/ld/emulparams/acess2_amd64.sh @@ -1,11 +1,12 @@ SCRIPT_NAME=elf -OUTPUT_FORMAT=elf64-x86_64 +OUTPUT_FORMAT=elf64-x86-64 TEXT_START_ADDR=0x00400000 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)" -TEMPLATE_NAME=elf64 +ELFSIZE=64 +TEMPLATE_NAME=elf32 -ARCH=x86_64 +ARCH="i386:x86-64" MACHINE= NOP=0x90909090 GENERATE_SHLIB_SCRIPT=yes diff --git a/Externals/cross-compiler/patches/binutils/ld/emulparams/acess2_arm.sh b/Externals/cross-compiler/patches/binutils/ld/emulparams/acess2_arm.sh new file mode 100644 index 0000000000000000000000000000000000000000..87ef5df09814887fca8e978f2833f2c3251d402d --- /dev/null +++ b/Externals/cross-compiler/patches/binutils/ld/emulparams/acess2_arm.sh @@ -0,0 +1,19 @@ +SCRIPT_NAME=elf +OUTPUT_FORMAT="elf32-littlearm" +BIG_OUTPUT_FORMAT="elf32-bigarm" +LITTLE_OUTPUT_FORMAT="elf32-littlearm" +TEXT_START_ADDR=0x8000 +MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" +COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)" +TEMPLATE_NAME=elf32 + +ARCH=arm +MACHINE= +GENERATE_SHLIB_SCRIPT=yes +GENERATE_PIE_SCRIPT=yes + +NO_SMALL_DATA=yes +SEPARATE_GOTPLT=12 + +ELF_INTERPRETER_NAME=\"/Acess/Libs/ld-acess.so\" + diff --git a/Externals/cross-compiler/patches/gcc/gcc/config.gcc.patch b/Externals/cross-compiler/patches/gcc/gcc/config.gcc.patch index 4a1525f215329f185899fa278708858e9fcb703e..c6f085ec7e81ef700e0e12bad4a7e227ab738ac7 100644 --- a/Externals/cross-compiler/patches/gcc/gcc/config.gcc.patch +++ b/Externals/cross-compiler/patches/gcc/gcc/config.gcc.patch @@ -1,22 +1,34 @@ --- gcc/config.gcc +++ gcc/config.gcc -@@ -519,3 +519,10 @@ +@@ -519,3 +519,12 @@ # Common parts for widely ported systems. case ${target} in +*-*-acess2*) -+ extra_parts="crtbegin.o crtend.o" ++ extra_options="${extra_options} acess2.opt" ++ extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o crtendT.o" + gas=yes + gnu_ld=yes + default_use_cxa_atexit=yes + use_gcc_stdint=provide ++ thread_file=posix + ;; *-*-darwin*) -@@ -1192,2 +1196,7 @@ +@@ -1192,2 +1196,17 @@ ;; +i[3-7]86-*-acess2*) + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h i386/i386elf.h newlib-stdint.h acess2.h" -+ tmake_file="i386/t-i386elf t-svr4" ++ tmake_file="i386/t-i386elf i386/t-crtstuff t-svr4" ++ use_fixproto=yes ++ ;; ++x86_64-*-acess2*) ++ tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h acess2.h" ++ tmake_file="i386/t-i386elf i386/t-crtstuff t-svr4" ++ use_fixproto=yes ++ ;; ++arm-*-acess2*) ++ tm_file="dbxelf.h elfos.h arm/unknown-elf.h arm/elf.h arm/bpabi.h newlib-stdint.h acess2.h arm/aout.h arm/arm.h" ++ tmake_file="arm/t-arm arm/t-arm-elf arm/t-bpabi" + use_fixproto=yes + ;; i[34567]86-*-elf*) diff --git a/Externals/cross-compiler/patches/gcc/gcc/config/acess2.h b/Externals/cross-compiler/patches/gcc/gcc/config/acess2.h index ec3c1131d48f4c8cc9e5bc118718fd997381ba26..a22c5356bd5bf1d4817367e1a4ad605e10dbc068 100644 --- a/Externals/cross-compiler/patches/gcc/gcc/config/acess2.h +++ b/Externals/cross-compiler/patches/gcc/gcc/config/acess2.h @@ -5,10 +5,17 @@ builtin_define_std ("unix"); \ builtin_assert ("system=acess2"); \ builtin_assert ("system=unix"); \ + builtin_assert ("system=posix"); \ } while(0); -#define LIB_SPEC "-lc -lld-acess -lposix" +#define LIB_SPEC "-lc -lld-acess -lposix %{pthread:-lpthread}" #define LIBSTDCXX "c++" +#undef STARTFILE_SPEC +#undef ENDFILE_SPEC +#define STARTFILE_SPEC "crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s} %{shared:crt0S.o%s;:crt0.o%s}" +#define ENDFILE_SPEC "%{static:crtendT.o%s;shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s" +#undef LINK_SPEC +#define LINK_SPEC "%{shared:-shared} %{!shared:%{!static:%{rdynamic:-export-dynamic}%{!dynamic-linker:-dynamic-linker /Acess/Libs/ld-acess.so}}}" /* #undef TARGET_VERSION // note that adding these two lines cause an error in gcc-4.7.0 diff --git a/Externals/cross-compiler/patches/gcc/gcc/config/acess2.opt b/Externals/cross-compiler/patches/gcc/gcc/config/acess2.opt new file mode 100644 index 0000000000000000000000000000000000000000..e9db7e5ce596163ca54bd74ef5aaf58e0c016fb7 --- /dev/null +++ b/Externals/cross-compiler/patches/gcc/gcc/config/acess2.opt @@ -0,0 +1,6 @@ +; Options for acess2 + +pthread +Driver + +; diff --git a/Externals/cross-compiler/patches/gcc/libgcc/config.host.patch b/Externals/cross-compiler/patches/gcc/libgcc/config.host.patch index bcf7a4af560caed25ada6ac3a546a984f65c48ef..52725e33b9bb35504dca5efc53707263bc1ffbfb 100644 --- a/Externals/cross-compiler/patches/gcc/libgcc/config.host.patch +++ b/Externals/cross-compiler/patches/gcc/libgcc/config.host.patch @@ -1,16 +1,22 @@ --- libgcc/config.host +++ libgcc/config.host -@@ -523,4 +523,12 @@ +@@ -523,4 +523,18 @@ x86_64-*-elf*) tmake_file="$tmake_file i386/t-crtstuff t-crtstuff-pic t-libgcc-pic" ;; +i[3-7]86-*-acess2*) -+ extra_parts="crtbegin.o crtend.o" ++ extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o crtendT.o" + tmake_file="$tmake_file i386/t-crtstuff" + ;; +x86_64-*-acess2*) -+ extra_parts="crtbegin.o crtend.o" ++ extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o crtendT.o" + tmake_file="$tmake_file i386/t-crtstuff t-crtstuff-pic t-libgcc-pic" ++ ;; ++arm-*-acess2*) ++ extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o crtendT.o" ++ tmake_file="${tmake_file} arm/t-arm arm/t-elf t-fixedpoint-gnu-prefix arm/t-bpabi t-softfp-sfdf t-softfp-excl arm/t-softfp t-softfp" ++ tm_file="$tm_file arm/bpabi-lib.h" ++ unwind_header=config/arm/unwind-arm.h + ;; i[34567]86-*-freebsd*) diff --git a/Externals/curl/Makefile b/Externals/curl/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e0c5eefac9aa27f2969b7e14888c2d964ac76e3a --- /dev/null +++ b/Externals/curl/Makefile @@ -0,0 +1,14 @@ +# +# Acess2 External: libcurl +# - Makefile and patches by John Hodge (thePowersGang) +# + +DEPS := +TARBALL_PATTERN := curl-*.tar.bz2 +TARBALL_TO_DIR_L := %.tar.bz2 +TARBALL_TO_DIR_R := % +PATCHES := config.sub +CONFIGURE_ARGS = LIBS=-lpsocket + +include ../common_automake.mk + diff --git a/Externals/curl/patches/config.sub.patch b/Externals/curl/patches/config.sub.patch new file mode 100644 index 0000000000000000000000000000000000000000..8380154724151d1a9523055512b4e3acfad1bce4 --- /dev/null +++ b/Externals/curl/patches/config.sub.patch @@ -0,0 +1,7 @@ +--- bochs-2.6.2_orig/config.sub 2013-06-17 11:39:39.670720710 +0800 ++++ bochs-2.6.2/config.sub 2013-06-17 11:48:09.149384231 +0800 +@@ -1356,2 +1356,3 @@ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ ++ | -acess2 \ + | -aos* | -aros* \ + diff --git a/Externals/glib/Makefile b/Externals/glib/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..953ef038da4bdd37888d3de358d15a7feb798e8d --- /dev/null +++ b/Externals/glib/Makefile @@ -0,0 +1,17 @@ +# +# Acess2 Externals - glib +# - Patches and Makefile by John Hodge (thePowersGang) +# + +DEPS := libffi +_NAME := glib +TARBALL_PATTERN := $(_NAME)-*.tar.xz +TARBALL_TO_DIR_L := $(_NAME)-%.tar.xz +TARBALL_TO_DIR_R := $(_NAME)-% +PATCHES := config.sub +CONFIGURE_ARGS := glib_cv_stack_grows=no ac_cv_func_posix_getpwuid_r=no ac_cv_func_posix_getgrgid_r=no +CONFIGURE_ARGS += LDFLAGS=-lpsocket + +include ../common_automake.mk + + diff --git a/Externals/glib/patches/config.sub.patch b/Externals/glib/patches/config.sub.patch new file mode 100644 index 0000000000000000000000000000000000000000..f600ad4b374acc30a81e55937316788e8affe64d --- /dev/null +++ b/Externals/glib/patches/config.sub.patch @@ -0,0 +1,8 @@ +--- glib/config.sub ++++ glib/config.sub +@@ -1335,2 +1335,5 @@ + ;; ++ -acess2) ++ os=-acess2 ++ ;; + -solaris) diff --git a/Externals/libspiderscript/source b/Externals/libspiderscript/source index a5d190a89ca3f3a78c8b44a855b044ff4e713bb3..9f2d7faf34c16ceaee2f1bffe3d5558c41382523 160000 --- a/Externals/libspiderscript/source +++ b/Externals/libspiderscript/source @@ -1 +1 @@ -Subproject commit a5d190a89ca3f3a78c8b44a855b044ff4e713bb3 +Subproject commit 9f2d7faf34c16ceaee2f1bffe3d5558c41382523 diff --git a/Externals/netsurf/Makefile b/Externals/netsurf/Makefile index d4140c3f3efe5426a202da1c868f674fb69b4a9a..5b69f5d8ae1d7ec92ba183b79cad4179bd8ec042 100644 --- a/Externals/netsurf/Makefile +++ b/Externals/netsurf/Makefile @@ -12,7 +12,12 @@ NOBDIR = yes include ../core.mk -_build: - cd $(BDIR) && CC=$(HOST)-gcc TARGET=sdl make +.PHONY: _check_local_deps + +_build: _check_local_deps + cd $(BDIR) && CC=$(HOST)-gcc TARGET=framebuffer make + +_check_local_deps: + @gperf --help >/dev/null || (echo "ERROR: netsurf's build system requires gperf"; false) diff --git a/Externals/netsurf/patches/UNIFIED.patch b/Externals/netsurf/patches/UNIFIED.patch index e94563138732104d4b498334fd83aba584bd50dd..f59d7c172da4d8d8dc499d047af334cf6ab945a7 100644 --- a/Externals/netsurf/patches/UNIFIED.patch +++ b/Externals/netsurf/patches/UNIFIED.patch @@ -108,3 +108,15 @@ diff -ru .orig/netsurf-full-3.0//src/libparserutils-0.1.2/src/utils/vector.c net { if (vector == NULL || vector->current_item < 0) return NULL; +diff -ru .orig/netsurf-full-3.0//src/libnsfb-0.1.2/Makefile netsurf-full-3.0//src/libnsfb-0.1.0/Makefile +--- .orig/netsurf-full-3.0//src/libnsfb-0.1.0/Makefile 2013-04-20 02:06:57.000000000 +0800 ++++ netsurf-full-3.0//src/libnsfb-0.1.0/Makefile 2013-07-01 22:22:45.246689992 +0800 +@@ -31,5 +31,5 @@ + # surfaces not detectable via pkg-config + NSFB_ABLE_AVAILABLE := no +-NSFB_LINUX_AVAILABLE := yes ++NSFB_LINUX_AVAILABLE := no + + # Flags and setup for each support library + NSFB_ABLE_AVAILABLE := no + diff --git a/Externals/pkgconfig/Makefile b/Externals/pkgconfig/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bcd63052eaa9e21ac5d7aae09f906e557989b035 --- /dev/null +++ b/Externals/pkgconfig/Makefile @@ -0,0 +1,17 @@ +# +# Acess2 Externals - pkgconfig +# - Patches and Makefile by John Hodge (thePowersGang) +# + +DEPS := +TARBALL_PATTERN := pkg-config-*.tar.gz +TARBALL_TO_DIR_L := pkg-config-%.tar.gz +TARBALL_TO_DIR_R := pkg-config-% +PATCHES := +CONFIGURE_LINE = $(SDIR)/configure --prefix=$(BUILD_OUTDIR) --with-internal-glib + +include ../common_automake.mk + + + + diff --git a/Externals/pkgconfig/patches/config.sub.patch b/Externals/pkgconfig/patches/config.sub.patch new file mode 100644 index 0000000000000000000000000000000000000000..b2d73891f75db2ec5941170f972abc91da6ce25f --- /dev/null +++ b/Externals/pkgconfig/patches/config.sub.patch @@ -0,0 +1,7 @@ +--- bochs-2.6.2_orig/config.sub 2013-06-17 11:39:39.670720710 +0800 ++++ bochs-2.6.2/config.sub 2013-06-17 11:48:09.149384231 +0800 +@@ -1344,2 +1344,3 @@ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ ++ | -acess2 \ + | -aos* | -aros* \ + diff --git a/Externals/pkgconfig/patches/glib/config.sub.patch b/Externals/pkgconfig/patches/glib/config.sub.patch new file mode 100644 index 0000000000000000000000000000000000000000..f600ad4b374acc30a81e55937316788e8affe64d --- /dev/null +++ b/Externals/pkgconfig/patches/glib/config.sub.patch @@ -0,0 +1,8 @@ +--- glib/config.sub ++++ glib/config.sub +@@ -1335,2 +1335,5 @@ + ;; ++ -acess2) ++ os=-acess2 ++ ;; + -solaris) diff --git a/KernelLand/Kernel/GenSyscalls.pl b/KernelLand/Kernel/GenSyscalls.pl index fdf33e91611b074e3cd252abc09fc516a97d2584..e7e3cbe14ed95e7818ef978d90410431b708de9d 100755 --- a/KernelLand/Kernel/GenSyscalls.pl +++ b/KernelLand/Kernel/GenSyscalls.pl @@ -46,7 +46,9 @@ foreach my $call (@calls) } print HEADER " #define NUM_SYSCALLS ",$i," -#define SYS_DEBUG 0x100 +#define SYS_DEBUGS 0x100 +#define SYS_DEBUGF 0x101 +#define SYS_DEBUGHEX 0x102 #if !defined(__ASSEMBLER__) && !defined(NO_SYSCALL_STRS) static const char *cSYSCALL_NAMES[] = { diff --git a/KernelLand/Kernel/Makefile b/KernelLand/Kernel/Makefile index cc4f230524b8f28ff7b7968ff3798e5ce52d74e3..895d90f9878e99f141b739b8e3ca368551e94e55 100644 --- a/KernelLand/Kernel/Makefile +++ b/KernelLand/Kernel/Makefile @@ -56,13 +56,13 @@ BUILDINFO_SRC := $(OBJDIR)buildinfo.c$(OBJSUFFIX) OBJ := $(addprefix arch/$(ARCHDIR)/,$(A_OBJ)) OBJ += pmemmap.o OBJ += heap.o logging.o debug.o lib.o libc.o adt.o time.o utf16.o debug_hooks.o -OBJ += drvutil_video.o drvutil_disk.o -OBJ += messages.o modules.o syscalls.o system.o +OBJ += drvutil_video.o drvutil_disk.o memfs_helpers.o +OBJ += messages.o modules.o syscalls.o system.o emergency_console.o OBJ += threads.o mutex.o semaphore.o workqueue.o events.o rwlock.o OBJ += drv/zero-one.o drv/proc.o drv/fifo.o drv/dgram_pipe.o drv/iocache.o drv/pci.o drv/vpci.o OBJ += drv/vterm.o drv/vterm_font.o drv/vterm_vt100.o drv/vterm_output.o drv/vterm_input.o drv/vterm_termbuf.o OBJ += drv/vterm_2d.o -OBJ += drv/pty.o drv/serial.o +OBJ += drv/pty.o drv/serial.o drv/shm.o OBJ += binary.o bin/elf.o bin/pe.o OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/dir.o vfs/io.o vfs/mount.o OBJ += vfs/memfile.o vfs/nodecache.o vfs/handle.o vfs/select.o vfs/mmap.o @@ -153,7 +153,7 @@ $(BUILDINFO_SRC): $(filter-out $(BUILDINFO_OBJ), $(OBJ)) $(MODS) arch/$(ARCHDIR) @echo "const char gsGitHash[] = \"$(_GITHASH)\";" >> $@ @echo "const int giBuildNumber = $(BUILD_NUM);" >> $@ @echo "const char gsBuildInfo[] = \"Acess2 v$(KERNEL_VERSION) $(ARCH)-$(PLATFORM)\\\\r\\\\n\"" >> $@ - @echo " \"Build $(shell hostname --fqdn):$(BUILD_NUM) Git $(_GITHASH) - $(_GITCHANGED) modified\";" >> $@ + @echo " \"Build $(shell hostname --fqdn):$(BUILD_NUM) $(shell date +%FT%T%z) Git $(_GITHASH) - $(_GITCHANGED) modified\";" >> $@ # Compile rule for buildinfo (needs a special one because it's not a general source file) $(BUILDINFO_OBJ): $(BUILDINFO_SRC) @echo --- CC -o $@ diff --git a/KernelLand/Kernel/arch/helpers.h b/KernelLand/Kernel/arch/helpers.h index 4d85fcb4d5f31aeaae7df3f1b9e89143c910bd94..b478031003456503481e7d860da45e2d4dc6cb65 100644 --- a/KernelLand/Kernel/arch/helpers.h +++ b/KernelLand/Kernel/arch/helpers.h @@ -14,10 +14,10 @@ // > If the `N` value is greater than `D`, we can set this bit #define DEF_DIVMOD(s) Uint##s __divmod##s(Uint##s N, Uint##s D, Uint##s*Rem){\ Uint##s ret=0,add=1;\ - while(N>=D&&add) {D<<=1;add<<=1;}\ - while(add>1){\ - add>>=1;D>>=1;\ + while(N/2>=D&&add) {D<<=1;add<<=1;}\ + while(add>0){\ if(N>=D){ret+=add;N-=D;}\ + add>>=1;D>>=1;\ }\ if(Rem)*Rem = N;\ return ret;\ diff --git a/KernelLand/Kernel/arch/x86/common.inc.asm b/KernelLand/Kernel/arch/x86/common.inc.asm new file mode 100644 index 0000000000000000000000000000000000000000..ec7f8441028186cf503ae8e8447d495d0dee3971 --- /dev/null +++ b/KernelLand/Kernel/arch/x86/common.inc.asm @@ -0,0 +1,24 @@ +%macro PUSH_CC 0 + ; Don't bother being too picky, just take the time + pusha +%endmacro +%macro PUSH_SEG 0 + push ds + push es + push fs + push gs + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax +%endmacro +%macro POP_CC 0 + popa +%endmacro +%macro POP_SEG 0 + pop gs + pop fs + pop es + pop ds +%endmacro diff --git a/KernelLand/Kernel/arch/x86/desctab.asm b/KernelLand/Kernel/arch/x86/desctab.asm index 354a001eb375b3a1e747d7930aa3f18694f3a02c..338253474392d1efa09152c76122b9b3a017cf6e 100644 --- a/KernelLand/Kernel/arch/x86/desctab.asm +++ b/KernelLand/Kernel/arch/x86/desctab.asm @@ -1,6 +1,7 @@ ; AcessOS Microkernel Version ; ; desctab.asm +%include "arch/x86/common.inc.asm" [BITS 32] @@ -182,14 +183,14 @@ Isr0xED: jmp .jmp [global Isr0xEE] -[extern SchedulerBase] +[extern Proc_EventTimer_LAPIC] ; AP's Timer Interrupt Isr0xEE: push eax ; Line up with interrupt number mov eax, dr1 ; CPU Number push eax mov eax, [esp+4] ; Load EAX back - jmp SchedulerBase + jmp Proc_EventTimer_LAPIC ; Spurious Interrupt [global Isr0xEF] Isr0xEF: @@ -201,7 +202,7 @@ Isr0xEF: ; - Timer [global Isr240] [global Isr240.jmp] -[extern SchedulerBase] +[extern Proc_EventTimer_PIT] [extern SetAPICTimerCount] Isr240: push 0 ; Line up with Argument in errors @@ -211,7 +212,7 @@ Isr240.jmp: %if USE_MP jmp SetAPICTimerCount ; This is reset once the bus speed has been calculated %else - jmp SchedulerBase + jmp Proc_EventTimer_PIT %endif ; - Assignable %assign i 0xF1 @@ -254,11 +255,8 @@ ErrorCommon: ; -------------------------- [extern SyscallHandler] SyscallCommon: - pusha - push ds - push es - push fs - push gs + PUSH_CC ; Actually a pusha + PUSH_SEG push esp call SyscallHandler @@ -286,17 +284,8 @@ SyscallCommon: [global IRQCommon_handled] IRQCommon_handled equ IRQCommon.handled IRQCommon: - pusha - push ds - push es - push fs - push gs - - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax + PUSH_CC + PUSH_SEG push esp call IRQ_Handler diff --git a/KernelLand/Kernel/arch/x86/mm_virt.c b/KernelLand/Kernel/arch/x86/mm_virt.c index aec6c60651bc7fb913358cbebb50b2c2eafba339..80875185405089d833980c6d6623d0a5b2b68907 100644 --- a/KernelLand/Kernel/arch/x86/mm_virt.c +++ b/KernelLand/Kernel/arch/x86/mm_virt.c @@ -74,6 +74,7 @@ void MM_InstallVirtual(void); void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs); void MM_DumpTables_Print(tVAddr Start, Uint32 Orig, size_t Size, void *Node); //void MM_DumpTables(tVAddr Start, tVAddr End); +tPAddr MM_GetPageFromAS(tProcess *Process, volatile const void *Addr); //void MM_ClearUser(void); tPAddr MM_DuplicatePage(tVAddr VAddr); @@ -538,6 +539,23 @@ tPAddr MM_GetPhysAddr(volatile const void *Addr) return (gaPageTable[addr >> 12] & ~0xFFF) | (addr & 0xFFF); } +/** + * \brief Get the address of a page from another addres space + * \return Refenced physical address (or 0 on error) + */ +tPAddr MM_GetPageFromAS(tProcess *Process, volatile const void *Addr) +{ + tPAddr ret = 0; + GET_TEMP_MAPPING(Process->MemState.CR3); + tVAddr addr = (tVAddr)Addr; + if( (gaTmpDir[addr >> 22] & 1) && (gaTmpTable[addr >> 12] & 1) ) { + ret = (gaTmpTable[addr >> 12] & ~0xFFF) | (addr & 0xFFF); + MM_RefPhys( ret ); + } + REL_TEMP_MAPPING(); + return ret; +} + /** * \fn void MM_SetCR3(Uint CR3) * \brief Sets the current process space @@ -552,18 +570,17 @@ void MM_SetCR3(Uint CR3) */ void MM_ClearUser(void) { - Uint i, j; - - for( i = 0; i < (MM_USER_MAX>>22); i ++ ) + ASSERTC(MM_PPD_MIN, ==, MM_USER_MAX); + for( unsigned int i = 0; i < (MM_USER_MAX>>22); i ++ ) { // Check if directory is not allocated if( !(gaPageDir[i] & PF_PRESENT) ) { gaPageDir[i] = 0; continue; } - + // Deallocate tables - for( j = 0; j < 1024; j ++ ) + for( unsigned int j = 0; j < 1024; j ++ ) { if( gaPageTable[i*1024+j] & 1 ) MM_DerefPhys( gaPageTable[i*1024+j] & ~0xFFF ); @@ -583,8 +600,6 @@ void MM_ClearUser(void) */ void MM_ClearSpace(Uint32 CR3) { - int i, j; - if(CR3 == (*gpPageCR3 & ~0xFFF)) { Log_Error("MMVirt", "Can't clear current address space"); return ; @@ -601,7 +616,7 @@ void MM_ClearSpace(Uint32 CR3) GET_TEMP_MAPPING(CR3); INVLPG( gaTmpDir ); - for( i = 0; i < 1024; i ++ ) + for( int i = 0; i < 1024; i ++ ) { Uint32 *table = &gaTmpTable[i*1024]; if( !(gaTmpDir[i] & PF_PRESENT) ) @@ -611,7 +626,7 @@ void MM_ClearSpace(Uint32 CR3) if( i < 768 || (i > MM_KERNEL_STACKS >> 22 && i < MM_KERNEL_STACKS_END >> 22) ) { - for( j = 0; j < 1024; j ++ ) + for( int j = 0; j < 1024; j ++ ) { if( !(table[j] & 1) ) continue; @@ -1052,6 +1067,8 @@ void *MM_MapTemp(tPAddr PAddr) LOG("%i: %x", i, *pte); // Check if page used if(*pte & 1) continue; + MM_RefPhys( PAddr ); + // Mark as used *pte = PAddr | 3; INVLPG( TEMP_MAP_ADDR + (i << 12) ); @@ -1064,6 +1081,15 @@ void *MM_MapTemp(tPAddr PAddr) return NULL; } +void *MM_MapTempFromProc(tProcess *Process, const void *VAddr) +{ + // Get paddr + tPAddr paddr = MM_GetPageFromAS(Process, VAddr); + if( paddr == 0 ) + return NULL; + return MM_MapTemp(paddr); +} + /** * \fn void MM_FreeTemp(tVAddr PAddr) * \brief Free's a temp mapping @@ -1073,7 +1099,9 @@ void MM_FreeTemp(void *VAddr) int i = (tVAddr)VAddr >> 12; //ENTER("xVAddr", VAddr); - if(i >= (TEMP_MAP_ADDR >> 12)) { + if(i >= (TEMP_MAP_ADDR >> 12)) + { + MM_DerefPhys( gaPageTable[i] & ~0xFFF ); gaPageTable[ i ] = 0; Semaphore_Signal(&gTempMappingsSem, 1); } diff --git a/KernelLand/Kernel/arch/x86/proc.asm b/KernelLand/Kernel/arch/x86/proc.asm index b8c01bcf451fe4e520a3b81ddd145e6530627cfa..1987166d6c2ff1d6e5a8a120eaea6b62c7e89288 100644 --- a/KernelLand/Kernel/arch/x86/proc.asm +++ b/KernelLand/Kernel/arch/x86/proc.asm @@ -1,5 +1,6 @@ ; AcessOS Microkernel Version ; Start.asm +%include "arch/x86/common.inc.asm" [bits 32] @@ -11,19 +12,6 @@ KSTACK_USERSTATE_SIZE equ (4+8+1+5)*4 ; SRegs, GPRegs, CPU, IRET [section .text] -[global NewTaskHeader] -NewTaskHeader: - mov eax, [esp] - mov dr0, eax - - mov eax, [esp+4] - add esp, 12 ; Thread, Function, Arg Count - call eax - - push eax ; Ret val - push 0 ; 0 = This Thread - call Threads_Exit - [extern MM_Clone] [global Proc_CloneInt] Proc_CloneInt: @@ -38,7 +26,7 @@ Proc_CloneInt: mov esi, [esp+0x20+8] mov [esi], eax ; Undo the pusha - add esp, 0x20 + popa mov eax, .newTask ret .newTask: @@ -53,7 +41,7 @@ Proc_CloneInt: ; +16 = Old RIP save loc ; +20 = CR3 SwitchTasks: - pusha + PUSH_CC ; Old IP mov eax, [esp+0x20+16] @@ -78,7 +66,7 @@ SwitchTasks: jmp ecx .restore: - popa + POP_CC xor eax, eax ret @@ -122,17 +110,8 @@ Proc_RestoreSSE: [extern Isr240.jmp] [global SetAPICTimerCount] SetAPICTimerCount: - pusha - push ds - push es - push fs - push gs - - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax + PUSH_CC + PUSH_SEG mov eax, [gpMP_LocalAPIC] mov ecx, [eax+0x320] @@ -152,7 +131,7 @@ SetAPICTimerCount: mov DWORD [eax+0x380], 0 ; Update Timer IRQ to the IRQ code - mov eax, SchedulerBase + mov eax, Proc_EventTimer_PIT sub eax, Isr240.jmp+5 mov DWORD [Isr240.jmp+1], eax @@ -160,72 +139,55 @@ SetAPICTimerCount: .ret: mov dx, 0x20 mov al, 0x20 - out dx, al ; ACK IRQ - pop gs - pop fs - pop es - pop ds - popa + out 0x20, al ; ACK IRQ + POP_SEG + POP_CC add esp, 8 ; CPU ID / Error Code iret %endif -; -------------- -; Task Scheduler -; -------------- -[extern Proc_Scheduler] -[global SchedulerBase] -SchedulerBase: - pusha - push ds - push es - push fs - push gs + +%if USE_MP +[global Proc_EventTimer_LAPIC] +Proc_EventTimer_LAPIC: + push eax + mov eax, SS:[gpMP_LocalAPIC] + mov DWORD SS:[eax + 0xB0], 0 + pop eax + jmp Proc_EventTimer_Common +%endif +[global Proc_EventTimer_PIT] +Proc_EventTimer_PIT: + push eax + mov al, 0x20 + out 0x20, al ; ACK IRQ + pop eax + jmp Proc_EventTimer_Common +[extern Proc_HandleEventTimer] +[global Proc_EventTimer_Common] +Proc_EventTimer_Common: + PUSH_CC + PUSH_SEG + ; Clear the Trace/Trap flag pushf and BYTE [esp+1], 0xFE ; Clear Trap Flag popf - - mov eax, dr0 - push eax ; Debug Register 0, Current Thread - - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax + ; Re-enable interrupts + ; - TODO: This is quite likely racy, if we get an interrupt flood + sti %if USE_MP call GetCPUNum - mov ebx, eax push eax ; Push as argument %else push 0 %endif - call Proc_Scheduler + call Proc_HandleEventTimer [global scheduler_return] scheduler_return: ; Used by some hackery in Proc_DumpThreadCPUState - add esp, 4 ; Remove CPU Number (thread is poped later) - %if USE_MP - test ebx, ebx - jnz .sendEOI - %endif - - mov al, 0x20 - out 0x20, al ; ACK IRQ - - %if USE_MP - jmp .ret -.sendEOI: - mov eax, DWORD [gpMP_LocalAPIC] - mov DWORD [eax+0x0B0], 0 - %endif -.ret: - pop eax ; Debug Register 0, Current Thread - mov dr0, eax - jmp ReturnFromInterrupt ; diff --git a/KernelLand/Kernel/arch/x86/proc.c b/KernelLand/Kernel/arch/x86/proc.c index 5637985fbbfb318638a021eb40c876c1c199ba60..b1dcb99dc1180ae1f993d2d438c92452d9ca0458 100644 --- a/KernelLand/Kernel/arch/x86/proc.c +++ b/KernelLand/Kernel/arch/x86/proc.c @@ -44,7 +44,6 @@ extern tGDT gGDT[]; extern tIDT gIDT[]; extern void APWait(void); // 16-bit AP pause code extern void APStartup(void); // 16-bit AP startup code -extern void NewTaskHeader(tThread *Thread, void *Fcn, int nArgs, ...); // Actually takes cdecl args extern Uint Proc_CloneInt(Uint *ESP, Uint32 *CR3, int bNoUserClone); extern Uint32 gaInitPageDir[1024]; // start.asm extern char Kernel_Stack_Top[]; @@ -71,6 +70,7 @@ void Proc_IdleThread(void *Ptr); //tThread *Proc_GetCurThread(void); void Proc_ChangeStack(void); // int Proc_NewKThread(void (*Fcn)(void*), void *Data); +void NewTaskHeader(tThread *Thread, void (*Fcn)(void*), void *Data); // Actually takes cdecl args // int Proc_Clone(Uint *Err, Uint Flags); Uint Proc_MakeUserStack(void); //void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize); @@ -78,7 +78,7 @@ void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP) NO void Proc_CallUser(Uint32 UserIP, Uint32 UserSP, const void *StackData, size_t StackDataLen); //void Proc_CallFaultHandler(tThread *Thread); //void Proc_DumpThreadCPUState(tThread *Thread); -void Proc_Scheduler(int CPU); +void Proc_HandleEventTimer(int CPU); // === GLOBALS === // --- Multiprocessing --- @@ -307,10 +307,12 @@ void Proc_IdleThread(void *Ptr) cpu->Current->ThreadName = strdup("Idle Thread"); Threads_SetPriority( cpu->Current, -1 ); // Never called randomly cpu->Current->Quantum = 1; // 1 slice quantum - for(;;) { + LOG("Idle thread for CPU %i ready", GetCPUNum()); + for(;;) + { __asm__ __volatile__ ("sti"); // Make sure interrupts are enabled - __asm__ __volatile__ ("hlt"); - Proc_Reschedule(); + Proc_Reschedule(); // Reshedule + __asm__ __volatile__ ("hlt"); // And wait for an interrupt if we get scheduled again } } @@ -432,10 +434,7 @@ void Proc_ClearThread(tThread *Thread) tTID Proc_NewKThread(void (*Fcn)(void*), void *Data) { - Uint esp; - tThread *newThread; - - newThread = Threads_CloneTCB(0); + tThread *newThread = Threads_CloneTCB(0); if(!newThread) return -1; // Create new KStack @@ -445,12 +444,14 @@ tTID Proc_NewKThread(void (*Fcn)(void*), void *Data) free(newThread); return -1; } + + LOG("%p(%i %s) SP=%p", newThread, newThread->TID, newThread->ThreadName, newThread->KernelStack); - esp = newThread->KernelStack; + Uint esp = newThread->KernelStack; *(Uint*)(esp-=4) = (Uint)Data; // Data (shadowed) - *(Uint*)(esp-=4) = 1; // Number of params *(Uint*)(esp-=4) = (Uint)Fcn; // Function to call *(Uint*)(esp-=4) = (Uint)newThread; // Thread ID + *(Uint*)(esp-=4) = (Uint)0; // Empty return address newThread->SavedState.ESP = esp; newThread->SavedState.EIP = (Uint)&NewTaskHeader; @@ -463,15 +464,24 @@ tTID Proc_NewKThread(void (*Fcn)(void*), void *Data) return newThread->TID; } +void NewTaskHeader(tThread *NewThread, void (*Fcn)(void*), void *Data) +{ + LOG("NewThread=%p, Fcn=%p, Data=%p", NewThread, Fcn, Data); + __asm__ __volatile__ ("mov %0, %%dr0" : : "r"(NewThread)); + SHORTREL(&glThreadListLock); + Fcn(Data); + + Threads_Exit(0, 0); + for(;;); +} + /** * \fn int Proc_Clone(Uint *Err, Uint Flags) * \brief Clone the current process */ tPID Proc_Clone(Uint Flags) { - tThread *newThread; tThread *cur = Proc_GetCurThread(); - Uint eip; // Sanity, please if( !(Flags & CLONE_VM) ) { @@ -480,16 +490,22 @@ tPID Proc_Clone(Uint Flags) } // New thread - newThread = Threads_CloneTCB(Flags); + tThread *newThread = Threads_CloneTCB(Flags); if(!newThread) return -1; + ASSERT(newThread->Process); newThread->KernelStack = cur->KernelStack; // Clone state - eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER); + Uint eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER); if( eip == 0 ) { + SHORTREL( &glThreadListLock ); + LOG("In new thread"); return 0; } + //ASSERT(newThread->Process); + //ASSERT(CheckMem(newThread->Process, sizeof(tProcess))); + //LOG("newThread->Process = %p", newThread->Process); newThread->SavedState.EIP = eip; newThread->SavedState.SSE = NULL; newThread->SavedState.bSSEModified = 0; @@ -522,12 +538,13 @@ tThread *Proc_SpawnWorker(void (*Fcn)(void*), void *Data) Warning("Proc_SpawnWorker - Out of heap space!\n"); return NULL; } + LOG("new = (%i %s)", new->TID, new->ThreadName); // Create the stack contents stack_contents[3] = (Uint)Data; - stack_contents[2] = 1; - stack_contents[1] = (Uint)Fcn; - stack_contents[0] = (Uint)new; + stack_contents[2] = (Uint)Fcn; + stack_contents[1] = (Uint)new; + stack_contents[0] = 0; // Create a new worker stack (in PID0's address space) new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents)); @@ -760,82 +777,82 @@ void Proc_DumpThreadCPUState(tThread *Thread) void Proc_Reschedule(void) { - tThread *nextthread, *curthread; int cpu = GetCPUNum(); // TODO: Wait for the lock? - if(IS_LOCKED(&glThreadListLock)) return; + if(IS_LOCKED(&glThreadListLock)) { + LOG("Thread list locked, not rescheduling"); + return; + } - curthread = Proc_GetCurThread(); - - nextthread = Threads_GetNextToRun(cpu, curthread); - - if(!nextthread || nextthread == curthread) - return ; - - #if DEBUG_TRACE_SWITCH - // HACK: Ignores switches to the idle threads - if( nextthread->TID == 0 || nextthread->TID > giNumCPUs ) + SHORTLOCK(&glThreadListLock); + + tThread *curthread = Proc_GetCurThread(); + tThread *nextthread = Threads_GetNextToRun(cpu, curthread); + + if(nextthread && nextthread != curthread) { - LogF("\nSwitching CPU %i to %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n", - GetCPUNum(), - nextthread, nextthread->TID, nextthread->ThreadName, - nextthread->Process->MemState.CR3, - nextthread->SavedState.EIP, - nextthread->SavedState.ESP - ); - LogF("OldCR3 = %P\n", curthread->Process->MemState.CR3); - } - #endif + #if DEBUG_TRACE_SWITCH + // HACK: Ignores switches to the idle threads + //if( nextthread->TID == 0 || nextthread->TID > giNumCPUs ) + { + LogF("\nSwitching CPU %i to %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n", + GetCPUNum(), + nextthread, nextthread->TID, nextthread->ThreadName, + nextthread->Process->MemState.CR3, + nextthread->SavedState.EIP, + nextthread->SavedState.ESP + ); + LogF(" from %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n", + curthread, curthread->TID, curthread->ThreadName, + curthread->Process->MemState.CR3, + curthread->SavedState.EIP, + curthread->SavedState.ESP + ); + } + #endif - // Update CPU state - gaCPUs[cpu].Current = nextthread; - gaCPUs[cpu].LastTimerThread = NULL; - gTSSs[cpu].ESP0 = nextthread->KernelStack-4; - __asm__ __volatile__("mov %0, %%db0\n\t" : : "r"(nextthread) ); + // Update CPU state + gaCPUs[cpu].Current = nextthread; + gaCPUs[cpu].LastTimerThread = NULL; + gTSSs[cpu].ESP0 = nextthread->KernelStack-4; + __asm__ __volatile__("mov %0, %%db0\n\t" : : "r"(nextthread) ); - // Save FPU/MMX/XMM/SSE state - if( curthread && curthread->SavedState.SSE ) - { - Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF ); - curthread->SavedState.bSSEModified = 0; - Proc_DisableSSE(); - } + // Save FPU/MMX/XMM/SSE state + if( curthread && curthread->SavedState.SSE ) + { + Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF ); + curthread->SavedState.bSSEModified = 0; + Proc_DisableSSE(); + } - if( curthread ) - { - SwitchTasks( - nextthread->SavedState.ESP, &curthread->SavedState.ESP, - nextthread->SavedState.EIP, &curthread->SavedState.EIP, - nextthread->Process->MemState.CR3 - ); - } - else - { - SwitchTasks( - nextthread->SavedState.ESP, 0, - nextthread->SavedState.EIP, 0, - nextthread->Process->MemState.CR3 - ); + if( curthread ) + { + SwitchTasks( + nextthread->SavedState.ESP, &curthread->SavedState.ESP, + nextthread->SavedState.EIP, &curthread->SavedState.EIP, + nextthread->Process->MemState.CR3 + ); + } + else + { + SwitchTasks( + nextthread->SavedState.ESP, 0, + nextthread->SavedState.EIP, 0, + nextthread->Process->MemState.CR3 + ); + } } - - return ; + + SHORTREL(&glThreadListLock); } /** - * \fn void Proc_Scheduler(int CPU) - * \brief Swap current thread and clears dead threads + * \brief Handle the per-CPU timer ticking + */ -void Proc_Scheduler(int CPU) +void Proc_HandleEventTimer(int CPU) { - #if USE_MP - if( GetCPUNum() ) - gpMP_LocalAPIC->EOI.Val = 0; - else - #endif - outb(0x20, 0x20); - __asm__ __volatile__ ("sti"); - // Call the timer update code Timer_CallTimers(); @@ -843,6 +860,8 @@ void Proc_Scheduler(int CPU) // If two ticks happen within the same task, and it's not an idle task, swap if( gaCPUs[CPU].Current->TID > giNumCPUs && gaCPUs[CPU].Current == gaCPUs[CPU].LastTimerThread ) { + const tThread* const t = gaCPUs[CPU].Current; + LOG("Preempting thread %p(%i %s)", t, t->TID, t->ThreadName); Proc_Reschedule(); } diff --git a/KernelLand/Kernel/arch/x86/time.c b/KernelLand/Kernel/arch/x86/time.c index 54e59a5d2d9ac520ebaa8dedbddda239304db8ae..b367c50ae2facdd8851ca09e6fb080fa642800ff 100644 --- a/KernelLand/Kernel/arch/x86/time.c +++ b/KernelLand/Kernel/arch/x86/time.c @@ -103,6 +103,7 @@ void Time_Interrupt(int IRQ, void *Ptr) if( giTime_TSCAtLastTick ) { giTime_TSCPerTick = curTSC - giTime_TSCAtLastTick; + //Debug("TSC Frequency is %llu-%llu = %llu Hz", curTSC, giTime_TSCAtLastTick, giTime_TSCPerTick*2); } giTime_TSCAtLastTick = curTSC; diff --git a/KernelLand/Kernel/arch/x86/vm8086.c b/KernelLand/Kernel/arch/x86/vm8086.c index 93ea63ae5b6022fdb6feff0a31d489fc6439b61b..f1b50059989a0590d0871a35b296d512f5912be1 100644 --- a/KernelLand/Kernel/arch/x86/vm8086.c +++ b/KernelLand/Kernel/arch/x86/vm8086.c @@ -68,16 +68,14 @@ Uint32 gaVM8086_MemBitmap[VM8086_BLOCKCOUNT/32]; // === FUNCTIONS === int VM8086_Install(char **Arguments) { - tPID pid; - Semaphore_Init(&gVM8086_TasksToDo, 0, 10, "VM8086", "TasksToDo"); // Lock to avoid race conditions Mutex_Acquire( &glVM8086_Process ); // Create BIOS Call process - pid = Proc_Clone(CLONE_VM); - //Log_Debug("VM8086", "pid = %i", pid); + tPID pid = Proc_Clone(CLONE_VM); + LOG("pid = %i", pid); if(pid == -1) { Log_Error("VM8086", "Unable to clone kernel into VM8086 worker"); @@ -87,15 +85,14 @@ int VM8086_Install(char **Arguments) { Uint * volatile stacksetup; // Initialising Stack Uint16 * volatile rmstack; // Real Mode Stack - int i; - //Log_Debug("VM8086", "Initialising worker"); + LOG("Initialising worker"); // Set Image Name Threads_SetName("VM8086"); // Map ROM Area - for(i=0xA0;i<0x100;i++) { + for(unsigned int i = 0xA0;i<0x100;i++) { MM_RefPhys(i * 0x1000); MM_Map( (void*)(i * 0x1000), i * 0x1000 ); } @@ -150,6 +147,7 @@ int VM8086_Install(char **Arguments) stacksetup--; *stacksetup = 0x20|3; // ES - Kernel stacksetup--; *stacksetup = 0x20|3; // FS stacksetup--; *stacksetup = 0x20|3; // GS + LOG("stacksetup = %p, entering vm8086"); __asm__ __volatile__ ( "mov %%eax,%%esp;\n\t" // Set stack pointer "pop %%gs;\n\t" @@ -164,6 +162,7 @@ int VM8086_Install(char **Arguments) gVM8086_WorkerPID = pid; // It's released when the GPF fires + LOG("Waiting for worker %i to start", gVM8086_WorkerPID); Mutex_Acquire( &glVM8086_Process ); Mutex_Release( &glVM8086_Process ); diff --git a/KernelLand/Kernel/arch/x86_64/desctab.asm b/KernelLand/Kernel/arch/x86_64/desctab.asm index e83317353d6c4ed4d2595282e03e43d3ad6d3364..e5e3f24797c126c102755618f931c1efbd9b2806 100644 --- a/KernelLand/Kernel/arch/x86_64/desctab.asm +++ b/KernelLand/Kernel/arch/x86_64/desctab.asm @@ -404,7 +404,7 @@ SyscallStub: mov [rsp+0x10], rdi ; Arg1 mov [rsp+0x18], rsi ; Arg2 mov [rsp+0x20], rdx ; Arg3 - mov [rsp+0x28], r10 ; Arg4 + mov [rsp+0x28], r10 ; Arg4 (r10 used in place of rcx) mov [rsp+0x30], r8 ; Arg5 mov [rsp+0x38], r9 ; Arg6 diff --git a/KernelLand/Kernel/arch/x86_64/include/arch.h b/KernelLand/Kernel/arch/x86_64/include/arch.h index ec7444c7a2143885487a61eaf653ac22cbe5d272..1360b19243c392228740763ca6879c74dac29e4d 100644 --- a/KernelLand/Kernel/arch/x86_64/include/arch.h +++ b/KernelLand/Kernel/arch/x86_64/include/arch.h @@ -105,5 +105,7 @@ extern void SHORTREL(struct sShortSpinlock *Lock); extern void Debug_PutCharDebug(char ch); extern void Debug_PutStringDebug(const char *Str); +extern void __AtomicTestSetLoop(Uint *Ptr, Uint Value); + #endif diff --git a/KernelLand/Kernel/arch/x86_64/include/mm_virt.h b/KernelLand/Kernel/arch/x86_64/include/mm_virt.h index 120afb3f024a8705e5c496c931d6c45795cd5b46..b03875fbbf4bd815861a05b57e917fa300d2b6ee 100644 --- a/KernelLand/Kernel/arch/x86_64/include/mm_virt.h +++ b/KernelLand/Kernel/arch/x86_64/include/mm_virt.h @@ -48,6 +48,7 @@ #define MM_USER_MIN 0x00000000##00010000 #define USER_LIB_MAX 0x00007000##00000000 +#define MM_USER_MAX USER_LIB_MAX #define USER_STACK_PREALLOC 0x00000000##00002000 // 8 KiB #define USER_STACK_SZ 0x00000000##00020000 // 64 KiB #define USER_STACK_TOP 0x00008000##00000000 diff --git a/KernelLand/Kernel/arch/x86_64/lib.c b/KernelLand/Kernel/arch/x86_64/lib.c index b35db69cdc707681b838bfda15eccdf6ad343397..60770f63679495e9b3d991330cd221d309ea7765 100644 --- a/KernelLand/Kernel/arch/x86_64/lib.c +++ b/KernelLand/Kernel/arch/x86_64/lib.c @@ -88,6 +88,8 @@ void SHORTLOCK(struct sShortSpinlock *Lock) Lock->Depth ++; return ; } + #else + ASSERT( !CPU_HAS_LOCK(Lock) ); #endif // Wait for another CPU to release @@ -146,6 +148,18 @@ void SHORTREL(struct sShortSpinlock *Lock) #endif } +void __AtomicTestSetLoop(Uint *Ptr, Uint Value) +{ + __ASM__( + "1:\n\t" + "xor %%eax, %%eax;\n\t" + "lock cmpxchg %0, (%1);\n\t" // if( Ptr==0 ) { ZF=1; Ptr=Value } else { ZF=0; _=Ptr } + "jnz 1b;\n\t" + :: "r"(Value), "r"(Ptr) + : "eax" // EAX clobbered + ); +} + // === DEBUG IO === #if USE_GDB_STUB void initGdbSerial(void) @@ -358,11 +372,11 @@ void *memset(void *__dest, int __val, size_t __count) __asm__ __volatile__ ("rep stosb" : : "D"(__dest),"a"(__val),"c"(__count)); else { Uint8 *dst = __dest; + size_t qwords = __count / 8; + size_t trail_bytes = __count % 8; - __asm__ __volatile__ ("rep stosq" : : "D"(dst),"a"(0),"c"(__count/8)); - dst += __count & ~7; - __count = __count & 7; - while( __count-- ) + __asm__ __volatile__ ("rep stosq" : "=D"(dst) : "D"(dst),"a"(0),"c"(qwords)); + while( trail_bytes-- ) *dst++ = 0; } return __dest; diff --git a/KernelLand/Kernel/arch/x86_64/mm_virt.c b/KernelLand/Kernel/arch/x86_64/mm_virt.c index 4e2968fd80e70e99e9a3beb5b7a48b79fbd53a4f..23f04ac2c5b2e73aa9f6fc19232f4e9e532307ec 100644 --- a/KernelLand/Kernel/arch/x86_64/mm_virt.c +++ b/KernelLand/Kernel/arch/x86_64/mm_virt.c @@ -53,6 +53,17 @@ #define INVLPG_ALL() __asm__ __volatile__ ("mov %cr3,%rax;\n\tmov %rax,%cr3;") #define INVLPG_GLOBAL() __asm__ __volatile__ ("mov %cr4,%rax;\n\txorl $0x80, %eax;\n\tmov %rax,%cr4;\n\txorl $0x80, %eax;\n\tmov %rax,%cr4") +// TODO: INVLPG_ALL is expensive +#define GET_TEMP_MAPPING(cr3) do { \ + __ASM__("cli"); \ + __AtomicTestSetLoop( (Uint *)&TMPCR3(), (cr3) | 3 ); \ + INVLPG_ALL(); \ +} while(0) +#define REL_TEMP_MAPPING() do { \ + TMPCR3() = 0; \ + __ASM__("sti"); \ +} while(0) + // === CONSTS === //tPAddr * const gaPageTable = MM_FRACTAL_BASE; @@ -70,6 +81,7 @@ void MM_int_ClonePageEnt( Uint64 *Ent, void *NextLevel, tVAddr Addr, int bTable void MM_int_DumpTablesEnt(tVAddr RangeStart, size_t Length, tPAddr Expected); //void MM_DumpTables(tVAddr Start, tVAddr End); int MM_GetPageEntryPtr(tVAddr Addr, BOOL bTemp, BOOL bAllocate, BOOL bLargePage, tPAddr **Pointer); +tPAddr MM_GetPageFromAS(tProcess *Process, volatile const void *Addr); int MM_MapEx(volatile void *VAddr, tPAddr PAddr, BOOL bTemp, BOOL bLarge); // int MM_Map(tVAddr VAddr, tPAddr PAddr); void MM_Unmap(tVAddr VAddr); @@ -78,7 +90,6 @@ void MM_int_ClearTableLevel(tVAddr VAddr, int LevelBits, int MaxEnts); int MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags); // === GLOBALS === -tMutex glMM_TempFractalLock; tShortSpinlock glMM_ZeroPage; tPAddr gMM_ZeroPage; @@ -260,7 +271,7 @@ int MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs) // Print Stack Backtrace Error_Backtrace(Regs->RIP, Regs->RBP); - MM_DumpTables(0, -1); + //MM_DumpTables(0, -1); return 1; } @@ -301,8 +312,6 @@ void MM_DumpTables(tVAddr Start, tVAddr End) const tPAddr MASK = ~CHANGEABLE_BITS; // Physical address and access bits tVAddr rangeStart = 0; tPAddr expected = CHANGEABLE_BITS; // CHANGEABLE_BITS is used because it's not a vaild value - tVAddr curPos; - Uint page; tPAddr expected_pml4 = PF_WRITE|PF_USER; tPAddr expected_pdp = PF_WRITE|PF_USER; tPAddr expected_pd = PF_WRITE|PF_USER; @@ -311,11 +320,12 @@ void MM_DumpTables(tVAddr Start, tVAddr End) End &= (1L << 48) - 1; - Start >>= 12; End >>= 12; + Start >>= 12; + End >>= 12; - for(page = Start, curPos = Start<<12; - page < End; - curPos += 0x1000, page++) + // `page` will not overflow, End is 48-12 bits + tVAddr curPos = Start << 12; + for(Uint page = Start; page <= End; curPos += 0x1000, page++) { //Debug("&PAGEMAPLVL4(%i page>>27) = %p", page>>27, &PAGEMAPLVL4(page>>27)); //Debug("&PAGEDIRPTR(%i page>>18) = %p", page>>18, &PAGEDIRPTR(page>>18)); @@ -486,7 +496,7 @@ int MM_MapEx(volatile void *VAddr, tPAddr PAddr, BOOL bTemp, BOOL bLarge) *ent = PAddr | 3; - if( (tVAddr)VAddr < USER_MAX ) + if( (tVAddr)VAddr <= USER_MAX ) *ent |= PF_USER; INVLPG( VAddr ); @@ -626,6 +636,27 @@ tPAddr MM_GetPhysAddr(volatile const void *Ptr) return (*ptr & PADDR_MASK) | (Addr & 0xFFF); } +/** + * \brief Get the address of a page from another addres space + * \return Refenced physical address (or 0 on error) + */ +tPAddr MM_GetPageFromAS(tProcess *Process, volatile const void *Addr) +{ + GET_TEMP_MAPPING(Process->MemState.CR3); + tPAddr ret = 0; + tPAddr *ptr; + if(MM_GetPageEntryPtr((tVAddr)Addr, 1,0,0, &ptr) == 0) // Temp, NoAlloc, NotLarge + { + if( *ptr & 1 ) + { + ret = (*ptr & ~0xFFF) | ((tVAddr)Addr & 0xFFF); + MM_RefPhys( ret ); + } + } + REL_TEMP_MAPPING(); + return ret; +} + /** * \brief Sets the flags on a page */ @@ -862,15 +893,16 @@ void *MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr) void *ret; // Sanity Check - if(MaxBits < 12 || !PhysAddr) return 0; + ASSERTCR(MaxBits, >=, 12, NULL); // Fast Allocate if(Pages == 1 && MaxBits >= PHYS_BITS) { phys = MM_AllocPhys(); - *PhysAddr = phys; ret = MM_MapHWPages(phys, 1); MM_DerefPhys(phys); + if(PhysAddr) + *PhysAddr = phys; return ret; } @@ -881,7 +913,8 @@ void *MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr) // Allocated successfully, now map ret = MM_MapHWPages(phys, Pages); - *PhysAddr = phys; + if(PhysAddr) + *PhysAddr = phys; // MapHWPages references the pages, so deref them back down to 1 for(;Pages--;phys+=0x1000) MM_DerefPhys(phys); @@ -898,9 +931,8 @@ void *MM_MapTemp(tPAddr PAddr) { const int max_slots = (MM_TMPMAP_END - MM_TMPMAP_BASE) / PAGE_SIZE; tVAddr ret = MM_TMPMAP_BASE; - int i; - for( i = 0; i < max_slots; i ++, ret += PAGE_SIZE ) + for( int i = 0; i < max_slots; i ++, ret += PAGE_SIZE ) { tPAddr *ent; if( MM_GetPageEntryPtr( ret, 0, 1, 0, &ent) < 0 ) { @@ -918,6 +950,15 @@ void *MM_MapTemp(tPAddr PAddr) return 0; } +void *MM_MapTempFromProc(tProcess *Process, const void *VAddr) +{ + // Get paddr + tPAddr paddr = MM_GetPageFromAS(Process, VAddr); + if( paddr == 0 ) + return NULL; + return MM_MapTemp(paddr); +} + void MM_FreeTemp(void *Ptr) { MM_Deallocate(Ptr); @@ -935,9 +976,7 @@ tPAddr MM_Clone(int bNoUserCopy) if(!ret) return 0; // #2 Alter the fractal pointer - Mutex_Acquire(&glMM_TempFractalLock); - TMPCR3() = ret | 3; - INVLPG_ALL(); + GET_TEMP_MAPPING(ret); // #3 Set Copy-On-Write to all user pages if( Threads_GetPID() != 0 && !bNoUserCopy ) @@ -1015,9 +1054,7 @@ tPAddr MM_Clone(int bNoUserCopy) // MAGIC_BREAK(); // #7 Return - TMPCR3() = 0; - INVLPG_ALL(); - Mutex_Release(&glMM_TempFractalLock); + REL_TEMP_MAPPING(); // Log("MM_Clone: RETURN %P", ret); return ret; } @@ -1061,9 +1098,7 @@ tVAddr MM_NewWorkerStack(void *StackData, size_t StackSize) int i; // #1 Set temp fractal to PID0 - Mutex_Acquire(&glMM_TempFractalLock); - TMPCR3() = ((tPAddr)gInitialPML4 - KERNEL_BASE) | 3; - INVLPG_ALL(); + GET_TEMP_MAPPING( ((tPAddr)gInitialPML4 - KERNEL_BASE) ); // #2 Scan for a free stack addresss < 2^47 for(ret = 0x100000; ret < (1ULL << 47); ret += KERNEL_STACK_SIZE) @@ -1073,7 +1108,7 @@ tVAddr MM_NewWorkerStack(void *StackData, size_t StackSize) if( !(*ptr & 1) ) break; } if( ret >= (1ULL << 47) ) { - Mutex_Release(&glMM_TempFractalLock); + REL_TEMP_MAPPING(); return 0; } @@ -1105,8 +1140,7 @@ tVAddr MM_NewWorkerStack(void *StackData, size_t StackSize) MM_FreeTemp(tmp_addr); } - TMPCR3() = 0; - Mutex_Release(&glMM_TempFractalLock); + REL_TEMP_MAPPING(); return ret + i*0x1000; } diff --git a/KernelLand/Kernel/arch/x86_64/proc.asm b/KernelLand/Kernel/arch/x86_64/proc.asm index aff670aca173c7ac61d6d37b935c26784c6849bd..afde3544dc9c821848cb51ea9e68332f9c926dc3 100644 --- a/KernelLand/Kernel/arch/x86_64/proc.asm +++ b/KernelLand/Kernel/arch/x86_64/proc.asm @@ -6,6 +6,8 @@ [section .text] [extern Threads_Exit] +[extern glThreadListLock] +[extern SHORTREL] [global GetRIP] GetRIP: @@ -18,6 +20,9 @@ NewTaskHeader: ; [rsp+0x08]: Function ; [rsp+0x10]: Argument + mov rdi, glThreadListLock + call SHORTREL + mov rdi, [rsp+0x10] mov rax, [rsp+0x8] add rsp, 0x10 ; Reclaim stack space (thread/fcn) diff --git a/KernelLand/Kernel/arch/x86_64/proc.c b/KernelLand/Kernel/arch/x86_64/proc.c index 50b5054894d8987eab5d9f46bbba4143b5d1ced6..7c73bf9f6ac6ad274d8d2d9ef2acd1409d6d18e7 100644 --- a/KernelLand/Kernel/arch/x86_64/proc.c +++ b/KernelLand/Kernel/arch/x86_64/proc.c @@ -508,7 +508,10 @@ tTID Proc_Clone(Uint Flags) // Save core machine state rip = Proc_CloneInt(&newThread->SavedState.RSP, &newThread->Process->MemState.CR3, !!(Flags & CLONE_NOUSER)); - if(rip == 0) return 0; // Child + if(rip == 0) { + SHORTREL(&glThreadListLock); + return 0; // Child + } newThread->KernelStack = cur->KernelStack; newThread->SavedState.RIP = rip; newThread->SavedState.SSE = NULL; @@ -735,62 +738,61 @@ void Proc_DumpThreadCPUState(tThread *Thread) void Proc_Reschedule(void) { - tThread *nextthread, *curthread; int cpu = GetCPUNum(); - // TODO: Wait for it? - if(IS_LOCKED(&glThreadListLock)) return; - - curthread = gaCPUs[cpu].Current; - - nextthread = Threads_GetNextToRun(cpu, curthread); + if(CPU_HAS_LOCK(&glThreadListLock)) + return; + SHORTLOCK(&glThreadListLock); - if(nextthread == curthread) return ; + tThread *curthread = gaCPUs[cpu].Current; + tThread *nextthread = Threads_GetNextToRun(cpu, curthread); + if(!nextthread) nextthread = gaCPUs[cpu].IdleThread; - if(!nextthread) - return ; - - #if DEBUG_TRACE_SWITCH - LogF("\nSwitching to task CR3 = 0x%x, RIP = %p, RSP = %p - %i (%s)\n", - nextthread->Process->MemState.CR3, - nextthread->SavedState.RIP, - nextthread->SavedState.RSP, - nextthread->TID, - nextthread->ThreadName - ); - #endif - - // Update CPU state - gaCPUs[cpu].Current = nextthread; - gTSSs[cpu].RSP0 = nextthread->KernelStack-sizeof(void*); - __asm__ __volatile__ ("mov %0, %%db0" : : "r" (nextthread)); - if( curthread ) + if(nextthread && nextthread != curthread) { - // Save FPU/MMX/XMM/SSE state - if( curthread->SavedState.SSE ) + #if DEBUG_TRACE_SWITCH + LogF("\nSwitching to task CR3 = 0x%x, RIP = %p, RSP = %p - %i (%s)\n", + nextthread->Process->MemState.CR3, + nextthread->SavedState.RIP, + nextthread->SavedState.RSP, + nextthread->TID, + nextthread->ThreadName + ); + #endif + + // Update CPU state + gaCPUs[cpu].Current = nextthread; + gTSSs[cpu].RSP0 = nextthread->KernelStack-sizeof(void*); + __asm__ __volatile__ ("mov %0, %%db0" : : "r" (nextthread)); + + if( curthread ) { - Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF ); - curthread->SavedState.bSSEModified = 0; - Proc_DisableSSE(); + // Save FPU/MMX/XMM/SSE state + if( curthread->SavedState.SSE ) + { + Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF ); + curthread->SavedState.bSSEModified = 0; + Proc_DisableSSE(); + } + SwitchTasks( + nextthread->SavedState.RSP, &curthread->SavedState.RSP, + nextthread->SavedState.RIP, &curthread->SavedState.RIP, + nextthread->Process->MemState.CR3 + ); + } + else + { + Uint tmp; + SwitchTasks( + nextthread->SavedState.RSP, &tmp, + nextthread->SavedState.RIP, &tmp, + nextthread->Process->MemState.CR3 + ); } - SwitchTasks( - nextthread->SavedState.RSP, &curthread->SavedState.RSP, - nextthread->SavedState.RIP, &curthread->SavedState.RIP, - nextthread->Process->MemState.CR3 - ); - } - else - { - Uint tmp; - SwitchTasks( - nextthread->SavedState.RSP, &tmp, - nextthread->SavedState.RIP, &tmp, - nextthread->Process->MemState.CR3 - ); } - return ; + SHORTREL(&glThreadListLock); } /** diff --git a/KernelLand/Kernel/bin/elf.c b/KernelLand/Kernel/bin/elf.c index 7f65d89d1df6bf37771a7c674855b3a39c071d4e..37172cf920c198b4eb626eac3930f8178dfd2155 100644 --- a/KernelLand/Kernel/bin/elf.c +++ b/KernelLand/Kernel/bin/elf.c @@ -15,8 +15,8 @@ #if BITS <= 32 # define DISABLE_ELF64 #endif -static int GetSymbol(const char *Name, void **Value, size_t *Size); -static int GetSymbol(const char *Name, void **Value, size_t *Size) { +static int GetSymbol(const char *Name, void **Value, size_t *Size, void *IgnoreBase); +static int GetSymbol(const char *Name, void **Value, size_t *Size, void *IgnoreBase) { Uint val; if(!Binary_GetSymbol(Name, &val)) { Log_Notice("ELF", "Lookup of '%s' failed", Name); @@ -205,15 +205,14 @@ tBinary *Elf_Load32(int FD, Elf32_Ehdr *Header) { tBinary *ret; Elf32_Phdr *phtab; - int i, j; - int iLoadCount; + int j; ENTER("xFD", FD); // Check architecture with current CPU // - TODO: Support kernel level emulation #if ARCH_IS_x86 - if( Header->machine != EM_386 ) + if( Header->e_machine != EM_386 ) { Log_Warning("ELF", "Unknown architecure on ELF-32"); LEAVE_RET('n'); @@ -222,7 +221,7 @@ tBinary *Elf_Load32(int FD, Elf32_Ehdr *Header) #endif // Check for a program header - if(Header->phoff == 0) { + if(Header->e_phoff == 0) { #if DEBUG_WARN Log_Warning("ELF", "File does not contain a program header (phoff == 0)"); #endif @@ -231,25 +230,25 @@ tBinary *Elf_Load32(int FD, Elf32_Ehdr *Header) } // Read Program Header Table - phtab = malloc( sizeof(Elf32_Phdr) * Header->phentcount ); + phtab = malloc( sizeof(Elf32_Phdr) * Header->e_phnum ); if( !phtab ) { LEAVE('n'); return NULL; } - LOG("hdr.phoff = 0x%08x", Header->phoff); - VFS_Seek(FD, Header->phoff, SEEK_SET); - VFS_Read(FD, sizeof(Elf32_Phdr)*Header->phentcount, phtab); + LOG("hdr.phoff = 0x%08x", Header->e_phoff); + VFS_Seek(FD, Header->e_phoff, SEEK_SET); + VFS_Read(FD, sizeof(Elf32_Phdr)*Header->e_phnum, phtab); // Count Pages - iLoadCount = 0; - LOG("Header->phentcount = %i", Header->phentcount); - for( i = 0; i < Header->phentcount; i++ ) + unsigned iLoadCount = 0; + LOG("Header->phentcount = %i", Header->e_phnum); + for( int i = 0; i < Header->e_phnum; i++ ) { // Ignore Non-LOAD types - if(phtab[i].Type != PT_LOAD) + if(phtab[i].p_type != PT_LOAD) continue; iLoadCount ++; - LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].VAddr, phtab[i].MemSize); + LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].p_vaddr, phtab[i].p_memsz); } LOG("iLoadCount = %i", iLoadCount); @@ -257,56 +256,55 @@ tBinary *Elf_Load32(int FD, Elf32_Ehdr *Header) // Allocate Information Structure ret = malloc( sizeof(tBinary) + sizeof(tBinarySection)*iLoadCount ); // Fill Info Struct - ret->Entry = Header->entrypoint; + ret->Entry = Header->e_entry; ret->Base = -1; // Set Base to maximum value ret->NumSections = iLoadCount; ret->Interpreter = NULL; // Load Pages j = 0; - for( i = 0; i < Header->phentcount; i++ ) + for( int i = 0; i < Header->e_phnum; i++ ) { //LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type); LOG("phtab[%i] = {", i); - LOG(" .Type = 0x%08x", phtab[i].Type); - LOG(" .Offset = 0x%08x", phtab[i].Offset); - LOG(" .VAddr = 0x%08x", phtab[i].VAddr); - LOG(" .PAddr = 0x%08x", phtab[i].PAddr); - LOG(" .FileSize = 0x%08x", phtab[i].FileSize); - LOG(" .MemSize = 0x%08x", phtab[i].MemSize); - LOG(" .Flags = 0x%08x", phtab[i].Flags); - LOG(" .Align = 0x%08x", phtab[i].Align); + LOG(" .Type = 0x%08x", phtab[i].p_type); + LOG(" .Offset = 0x%08x", phtab[i].p_offset); + LOG(" .VAddr = 0x%08x", phtab[i].p_vaddr); + LOG(" .PAddr = 0x%08x", phtab[i].p_paddr); + LOG(" .FileSize = 0x%08x", phtab[i].p_filesz); + LOG(" .MemSize = 0x%08x", phtab[i].p_memsz); + LOG(" .Flags = 0x%08x", phtab[i].p_flags); + LOG(" .Align = 0x%08x", phtab[i].p_align); LOG(" }"); // Get Interpreter Name - if( phtab[i].Type == PT_INTERP ) + if( phtab[i].p_type == PT_INTERP ) { - char *tmp; if(ret->Interpreter) continue; - tmp = malloc(phtab[i].FileSize); - VFS_Seek(FD, phtab[i].Offset, 1); - VFS_Read(FD, phtab[i].FileSize, tmp); + char* tmp = malloc(phtab[i].p_filesz); + VFS_Seek(FD, phtab[i].p_offset, 1); + VFS_Read(FD, phtab[i].p_filesz, tmp); ret->Interpreter = Binary_RegInterp(tmp); LOG("Interpreter '%s'", tmp); free(tmp); continue; } // Ignore non-LOAD types - if(phtab[i].Type != PT_LOAD) continue; + if(phtab[i].p_type != PT_LOAD) continue; // Find Base - if(phtab[i].VAddr < ret->Base) ret->Base = phtab[i].VAddr; + if(phtab[i].p_vaddr < ret->Base) ret->Base = phtab[i].p_vaddr; LOG("phtab[%i] = {VAddr:0x%x,Offset:0x%x,FileSize:0x%x}", - i, phtab[i].VAddr, phtab[i].Offset, phtab[i].FileSize); + i, phtab[i].p_vaddr, phtab[i].p_offset, phtab[i].p_filesz); - ret->LoadSections[j].Offset = phtab[i].Offset; - ret->LoadSections[j].FileSize = phtab[i].FileSize; - ret->LoadSections[j].Virtual = phtab[i].VAddr; - ret->LoadSections[j].MemSize = phtab[i].MemSize; + ret->LoadSections[j].Offset = phtab[i].p_offset; + ret->LoadSections[j].FileSize = phtab[i].p_filesz; + ret->LoadSections[j].Virtual = phtab[i].p_vaddr; + ret->LoadSections[j].MemSize = phtab[i].p_memsz; ret->LoadSections[j].Flags = 0; - if( !(phtab[i].Flags & PF_W) ) + if( !(phtab[i].p_flags & PF_W) ) ret->LoadSections[j].Flags |= BIN_SECTFLAG_RO; - if( phtab[i].Flags & PF_X ) + if( phtab[i].p_flags & PF_X ) ret->LoadSections[j].Flags |= BIN_SECTFLAG_EXEC; j ++; } diff --git a/KernelLand/Kernel/binary.c b/KernelLand/Kernel/binary.c index 3dab6a9210ca8fc9ef26f7c41710dff3cebc9c49..5170dac06ccda9de159b0f49ac54f3795d31781c 100644 --- a/KernelLand/Kernel/binary.c +++ b/KernelLand/Kernel/binary.c @@ -231,23 +231,19 @@ int Proc_int_Execve(const char *File, const char **ArgV, const char **EnvP, int } // --- Get argc - for( argc = 0; ArgV && ArgV[argc]; argc ++ ); + for( argc = 0; ArgV && ArgV[argc]; argc ++ ) + ; // --- Set Process Name Threads_SetName(File); // --- Clear User Address space - // NOTE: This is a little roundabout, maybe telling ClearUser to not touch the - // PPD area would be a better idea. if( bClearUser ) { - int nfd = *Threads_GetMaxFD(); - void *handles; - handles = VFS_SaveHandles(nfd, NULL); - VFS_CloseAllUserHandles(); + // MM_ClearUser should preserve handles MM_ClearUser(); - VFS_RestoreHandles(nfd, handles); - VFS_FreeSavedHandles(nfd, handles); + // - NOTE: Not a reliable test, but helps for now + ASSERTC( VFS_IOCtl(0, 0, NULL), !=, -1 ); } // --- Load new binary @@ -334,6 +330,8 @@ tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint) if(pBinary->Interpreter) { tVAddr start; if( Binary_Load(pBinary->Interpreter, &start) == 0 ) { + Log_Error("Binary", "Can't load interpeter '%s' for '%s'", + pBinary->Interpreter, Path); LEAVE('x', 0); return 0; } diff --git a/KernelLand/Kernel/debug.c b/KernelLand/Kernel/debug.c index d0de25abc389255c4ab9378bd57321d4d57b6a4f..eed38de5f6161a4250607df8ecfbdd6faca3cfcc 100644 --- a/KernelLand/Kernel/debug.c +++ b/KernelLand/Kernel/debug.c @@ -7,7 +7,7 @@ #include <debug_hooks.h> #define DEBUG_MAX_LINE_LEN 256 -#define LOCK_DEBUG_OUTPUT 1 // Avoid interleaving of output lines? +#define LOCK_DEBUG_OUTPUT 0 // Avoid interleaving of output lines? #define TRACE_TO_KTERM 0 // Send ENTER/DEBUG/LEAVE to debug? // === IMPORTS === @@ -21,7 +21,7 @@ static void Debug_Putchar(char ch); static void Debug_Puts(int bUseKTerm, const char *Str); void Debug_DbgOnlyFmt(const char *format, va_list args); void Debug_FmtS(int bUseKTerm, const char *format, ...); -void Debug_Fmt(int bUseKTerm, const char *format, va_list args); +bool Debug_Fmt(int bUseKTerm, const char *format, va_list args); void Debug_SetKTerminal(const char *File); // === GLOBALS === @@ -77,9 +77,8 @@ static void Debug_Puts(int UseKTerm, const char *Str) IPStack_SendDebugText(Str); // Output to the kernel terminal - if( UseKTerm && gbDebug_IsKPanic < 2 && giDebug_KTerm != -1) + if( UseKTerm && gbDebug_IsKPanic < 2 && giDebug_KTerm != -1 && gbInPutChar == 0) { - if(gbInPutChar) return ; gbInPutChar = 1; VFS_Write(giDebug_KTerm, len, Str); gbInPutChar = 0; @@ -91,17 +90,18 @@ void Debug_DbgOnlyFmt(const char *format, va_list args) Debug_Fmt(0, format, args); } -void Debug_Fmt(int bUseKTerm, const char *format, va_list args) +bool Debug_Fmt(int bUseKTerm, const char *format, va_list args) { char buf[DEBUG_MAX_LINE_LEN]; buf[DEBUG_MAX_LINE_LEN-1] = 0; - int len = vsnprintf(buf, DEBUG_MAX_LINE_LEN-1, format, args); + size_t len = vsnprintf(buf, DEBUG_MAX_LINE_LEN-1, format, args); Debug_Puts(bUseKTerm, buf); if( len > DEBUG_MAX_LINE_LEN-1 ) { // do something Debug_Puts(bUseKTerm, "[...]"); + return false; } - return ; + return true; } void Debug_FmtS(int bUseKTerm, const char *format, ...) @@ -131,25 +131,27 @@ void Debug_KernelPanic(void) /** * \fn void LogF(const char *Msg, ...) * \brief Raw debug log (no new line, no prefix) + * \return True if all of the provided text was printed */ -void LogF(const char *Fmt, ...) +bool LogF(const char *Fmt, ...) { - va_list args; - #if LOCK_DEBUG_OUTPUT - if(CPU_HAS_LOCK(&glDebug_Lock)) return ; + if(CPU_HAS_LOCK(&glDebug_Lock)) { + Debug_Puts("[#]"); + return true; + } SHORTLOCK(&glDebug_Lock); #endif + va_list args; va_start(args, Fmt); - - Debug_Fmt(1, Fmt, args); - + bool rv = Debug_Fmt(1, Fmt, args); va_end(args); #if LOCK_DEBUG_OUTPUT SHORTREL(&glDebug_Lock); #endif + return rv; } /** * \fn void Debug(const char *Msg, ...) @@ -249,12 +251,12 @@ void Panic(const char *Fmt, ...) Debug_KernelPanic(); + Debug_Puts(1, "\x1b[31m"); Debug_Puts(1, "Panic: "); va_start(args, Fmt); Debug_Fmt(1, Fmt, args); va_end(args); - Debug_Putchar('\r'); - Debug_Putchar('\n'); + Debug_Puts(1, "\x1b[0m\r\n"); Proc_PrintBacktrace(); //Threads_Dump(); @@ -265,16 +267,13 @@ void Panic(const char *Fmt, ...) void Debug_SetKTerminal(const char *File) { - int tmp; if(giDebug_KTerm != -1) { - tmp = giDebug_KTerm; + // Clear FD to -1 before closing (prevents writes to closed FD) + int oldfd = giDebug_KTerm; giDebug_KTerm = -1; - VFS_Close(tmp); + VFS_Close(oldfd); } - tmp = VFS_Open(File, VFS_OPENFLAG_WRITE); -// Log_Log("Debug", "Opened '%s' as 0x%x", File, tmp); - giDebug_KTerm = tmp; -// Log_Log("Debug", "Returning to %p", __builtin_return_address(0)); + giDebug_KTerm = VFS_Open(File, VFS_OPENFLAG_WRITE); } void Debug_Enter(const char *FuncName, const char *ArgTypes, ...) @@ -431,16 +430,16 @@ void Debug_HexDump(const char *Header, const void *Data, size_t Length) Uint pos = 0; LogF("%014lli ", now()); Debug_Puts(1, Header); - LogF(" (Hexdump of %p)\r\n", Data); + LogF(" (Hexdump of %p+%i)\r\n", Data, Length); #define CH(n) ((' '<=cdat[(n)]&&cdat[(n)]<0x7F) ? cdat[(n)] : '.') while(Length >= 16) { LogF("%014lli Log: %04x:" - " %02x %02x %02x %02x %02x %02x %02x %02x" - " %02x %02x %02x %02x %02x %02x %02x %02x" - " %c%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c\r\n", + " %02x %02x %02x %02x %02x %02x %02x %02x " + " %02x %02x %02x %02x %02x %02x %02x %02x " + " %c%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c\r\n", now(), pos, cdat[ 0], cdat[ 1], cdat[ 2], cdat[ 3], cdat[ 4], cdat[ 5], cdat[ 6], cdat[ 7], diff --git a/KernelLand/Kernel/drv/dgram_pipe.c b/KernelLand/Kernel/drv/dgram_pipe.c index c13ca2a71cb41cf1a472cdfcdd0bbeb7bf4ac0c8..667190eb0ad8b3cdc3f88e7f18866d46883f2f10 100644 --- a/KernelLand/Kernel/drv/dgram_pipe.c +++ b/KernelLand/Kernel/drv/dgram_pipe.c @@ -34,6 +34,7 @@ struct sIPCPipe_Endpoint tMutex lList; tIPCPipe_Packet *OutHead; tIPCPipe_Packet *OutTail; + size_t ByteCount; tVFS_Node Node; }; struct sIPCPipe_Channel @@ -50,8 +51,8 @@ struct sIPCPipe_Server tIPCPipe_Server *Prev; char *Name; size_t MaxBlockSize; // Max size of a 'packet' - size_t QueueByteLimit; // Maximum number of bytes held in kernel for this server - size_t CurrentByteCount; + // NOTE: Not strictly enforced, can go MaxBlockSize-1 over + size_t QueueByteLimit; // Maximum number of bytes held in kernel for each endpoint tVFS_Node ServerNode; tRWLock lChannelList; tIPCPipe_Channel *FirstClient; @@ -85,6 +86,7 @@ tVFS_NodeType gIPCPipe_ServerNodeType = { }; tVFS_NodeType gIPCPipe_ChannelNodeType = { .TypeName = "IPC Pipe - Channel", + .Flags = VFS_NODETYPEFLAG_STREAM, .Read = IPCPipe_Client_Read, .Write = IPCPipe_Client_Write, .Close = IPCPipe_Client_Close @@ -210,8 +212,10 @@ tVFS_Node *IPCPipe_Root_FindDir(tVFS_Node *Node, const char *Name, Uint Flags) new_client->Server = srv; new_client->ClientEP.Node.Type = &gIPCPipe_ChannelNodeType; new_client->ClientEP.Node.ImplPtr = new_client; + new_client->ClientEP.Node.Size = -1; new_client->ServerEP.Node.Type = &gIPCPipe_ChannelNodeType; new_client->ServerEP.Node.ImplPtr = new_client; + new_client->ServerEP.Node.Size = -1; // Append to server list RWLock_AcquireWrite(&srv->lChannelList); @@ -324,13 +328,13 @@ size_t IPCPipe_Client_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *D // Wait for a packet to be ready tTime timeout_z = 0, *timeout = ((Flags & VFS_IOFLAG_NOBLOCK) ? &timeout_z : NULL); - int rv = VFS_SelectNode(Node, VFS_SELECT_READ, timeout, "IPCPipe Endpoint"); + int rv = VFS_SelectNode(Node, VFS_SELECT_READ|VFS_SELECT_ERROR, timeout, "IPCPipe Endpoint"); if( !rv ) { errno = (Flags & VFS_IOFLAG_NOBLOCK) ? EWOULDBLOCK : EINTR; LEAVE('i', -1); return -1; } - if( channel->Server == NULL ) { + if( (rv & VFS_SELECT_ERROR) || channel->Server == NULL ) { //errno = EIO; LEAVE('i', -1); return -1; @@ -351,6 +355,7 @@ size_t IPCPipe_Client_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *D if(!rep->OutHead) rep->OutTail = NULL; VFS_MarkAvaliable(Node, !!rep->OutHead); + VFS_MarkFull(&rep->Node, 0); // Just read a packet, remote shouldn't be full Mutex_Release(&rep->lList); // Return @@ -363,7 +368,7 @@ size_t IPCPipe_Client_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *D } else { - Log_Warning("IPCPipe", "No packet ready but semaphore returned"); + Log_Warning("IPCPipe", "No packet ready but select returned"); } LEAVE('i', ret); @@ -387,8 +392,21 @@ size_t IPCPipe_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const LEAVE('i', 0); return 0; } - - // TODO: Ensure that no more than DEF_MAX_BYTE_LIMIT bytes are in flight at one time + + // Wait for a packet to be ready + tTime timeout_z = 0, *timeout = ((Flags & VFS_IOFLAG_NOBLOCK) ? &timeout_z : NULL); + int rv = VFS_SelectNode(Node, VFS_SELECT_WRITE|VFS_SELECT_ERROR, timeout, "IPCPipe Endpoint"); + ASSERTC(rv, >=, 0); + if( !rv ) { + errno = (Flags & VFS_IOFLAG_NOBLOCK) ? EWOULDBLOCK : EINTR; + LEAVE('i', -1); + return -1; + } + if( (rv & VFS_SELECT_ERROR) || channel->Server == NULL ) { + //errno = EIO; + LEAVE('i', -1); + return -1; + } // Create packet structure tIPCPipe_Packet *pkt = malloc(sizeof(tIPCPipe_Packet)+Length); @@ -413,6 +431,12 @@ size_t IPCPipe_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const else lep->OutHead = pkt; lep->OutTail = pkt; + + lep->ByteCount += Length; + if( lep->ByteCount >= channel->Server->QueueByteLimit ) { + VFS_MarkFull(Node, 1); + } + Mutex_Release(&lep->lList); // Signal other end diff --git a/KernelLand/Kernel/drv/fifo.c b/KernelLand/Kernel/drv/fifo.c index de3192ab004aae0f4945c73f1aa193522fec9c1e..6d5d4835b7bbfe812c6929680750d98afb5f0271 100644 --- a/KernelLand/Kernel/drv/fifo.c +++ b/KernelLand/Kernel/drv/fifo.c @@ -10,15 +10,16 @@ #include <modules.h> #include <fs_devfs.h> #include <semaphore.h> +#include <memfs_helpers.h> // === CONSTANTS === #define DEFAULT_RING_SIZE 2048 #define PF_BLOCKING 1 // === TYPES === -typedef struct sPipe { - struct sPipe *Next; - char *Name; +typedef struct sPipe +{ + tMemFS_FileHdr FileHdr; tVFS_Node Node; Uint Flags; int ReadPos; @@ -42,6 +43,9 @@ tPipe *FIFO_Int_NewPipe(int Size, const char *Name); // === GLOBALS === MODULE_DEFINE(0, 0x0032, FIFO, FIFO_Install, NULL, NULL); +tMemFS_DirHdr gFIFO_RootDir = { + .FileHdr = { .Name = "FIFO" }, +}; tVFS_NodeType gFIFO_DirNodeType = { .TypeName = "FIFO Dir Node", .ReadDir = FIFO_ReadDir, @@ -71,7 +75,6 @@ tVFS_Node gFIFO_AnonNode = { .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRW, }; -tPipe *gFIFO_NamedPipes = NULL; // === CODE === /** @@ -80,6 +83,7 @@ tPipe *gFIFO_NamedPipes = NULL; */ int FIFO_Install(char **Options) { + MemFS_InitDir( &gFIFO_RootDir ); DevFS_AddDevice( &gFIFO_DriverInfo ); return MODULE_ERR_OK; } @@ -98,22 +102,14 @@ int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data) */ int FIFO_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]) { - tPipe *tmp = gFIFO_NamedPipes; - // Entry 0 is Anon Pipes - if(Id == 0) { + if(Id == 0) + { strcpy(Dest, "anon"); return 0; } - // Find the id'th node - while(--Id && tmp) tmp = tmp->Next; - // If the list ended, error return - if(!tmp) - return -EINVAL; - // Return good - strncpy(Dest, tmp->Name, FILENAME_MAX); - return 0; + return MemFS_ReadDir(&gFIFO_RootDir, Id-1, Dest); } /** @@ -123,11 +119,8 @@ int FIFO_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]) */ tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags) { - tPipe *tmp; - if(!Filename) return NULL; - - // NULL String Check - if(Filename[0] == '\0') return NULL; + ASSERTR(Filename, NULL); + ASSERTR(Filename[0], NULL); // Anon Pipe if( strcmp(Filename, "anon") == 0 ) @@ -135,19 +128,15 @@ tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags) if( Flags & VFS_FDIRFLAG_STAT ) { //return &gFIFI_TemplateAnonNode; } - tmp = FIFO_Int_NewPipe(DEFAULT_RING_SIZE, "anon"); - return &tmp->Node; + tPipe *ret = FIFO_Int_NewPipe(DEFAULT_RING_SIZE, "anon"); + return &ret->Node; } // Check Named List - tmp = gFIFO_NamedPipes; - while(tmp) - { - if(strcmp(tmp->Name, Filename) == 0) - return &tmp->Node; - tmp = tmp->Next; - } - return NULL; + tPipe *ret = (tPipe*)MemFS_FindDir(&gFIFO_RootDir, Filename); + if(!ret) + return NULL; + return &ret->Node; } /** @@ -155,6 +144,25 @@ tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags) */ tVFS_Node *FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags) { + UNIMPLEMENTED(); + return NULL; +} + +/** + * \brief Delete a pipe + */ +int FIFO_Unlink(tVFS_Node *Node, const char *OldName) +{ + if(Node != &gFIFO_DriverInfo.RootNode) return 0; + + // Can't relink anon + if(strcmp(OldName, "anon")) return 0; + + // Find node + tPipe* pipe = (tPipe*)MemFS_Remove(&gFIFO_RootDir, OldName); + if(!pipe) return 0; + + free(pipe); return 0; } @@ -171,54 +179,23 @@ void FIFO_Reference(tVFS_Node *Node) */ void FIFO_Close(tVFS_Node *Node) { - tPipe *pipe; if(!Node->ImplPtr) return ; Node->ReferenceCount --; if(Node->ReferenceCount) return ; - pipe = Node->ImplPtr; + tPipe *pipe = Node->ImplPtr; - if(strcmp(pipe->Name, "anon") == 0) { - Log_Debug("FIFO", "Pipe %p closed", Node->ImplPtr); - free(Node->ImplPtr); + if(strcmp(pipe->FileHdr.Name, "anon") == 0) + { + Log_Debug("FIFO", "Pipe %p closed", pipe); + free(pipe); return ; } return ; } -/** - * \brief Delete a pipe - */ -int FIFO_Unlink(tVFS_Node *Node, const char *OldName) -{ - tPipe *pipe; - - if(Node != &gFIFO_DriverInfo.RootNode) return 0; - - // Can't relink anon - if(strcmp(OldName, "anon")) return 0; - - // Find node - for(pipe = gFIFO_NamedPipes; - pipe; - pipe = pipe->Next) - { - if(strcmp(pipe->Name, OldName) == 0) - break; - } - if(!pipe) return 0; - - // Unlink the pipe - if(Node->ImplPtr) { - free(Node->ImplPtr); - return 1; - } - - return 0; -} - /** * \brief Read from a fifo pipe */ @@ -412,10 +389,8 @@ tPipe *FIFO_Int_NewPipe(int Size, const char *Name) ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) ); // Set name (and FIFO name) - ret->Name = ret->Buffer + Size; - strcpy(ret->Name, Name); - // - Start empty, max of `Size` - //Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name ); + ret->FileHdr.Name = ret->Buffer + Size; + strcpy((char*)ret->FileHdr.Name, Name); // Set Node ret->Node.ReferenceCount = 1; diff --git a/KernelLand/Kernel/drv/proc.c b/KernelLand/Kernel/drv/proc.c index 03288aeaa475e81b4a53778fff118fe8baa38e7b..60bf4dd8f11ec7127888f8f3636de96e05b8d2fd 100644 --- a/KernelLand/Kernel/drv/proc.c +++ b/KernelLand/Kernel/drv/proc.c @@ -50,9 +50,8 @@ tVFS_NodeType gSysFS_DirNodeType = { .FindDir = SysFS_Comm_FindDir }; tSysFS_Ent gSysFS_Version_Kernel = { - NULL, NULL, // Nexts - &gSysFS_Version, // Parent - { + .Parent = &gSysFS_Version, // Parent + .Node = { .Inode = 1, // File #1 .ImplPtr = NULL, .ImplInt = (Uint)&gSysFS_Version_Kernel, // Self-Link @@ -61,12 +60,11 @@ tSysFS_Ent gSysFS_Version_Kernel = { .ACLs = &gVFS_ACL_EveryoneRO, .Type = &gSysFS_FileNodeType }, - "Kernel" + .Name = {"Kernel"} }; tSysFS_Ent gSysFS_Version = { - NULL, NULL, - &gSysFS_Root, - { + .Parent = &gSysFS_Root, + .Node = { .Size = 1, .ImplPtr = &gSysFS_Version_Kernel, .ImplInt = (Uint)&gSysFS_Version, // Self-Link @@ -75,7 +73,7 @@ tSysFS_Ent gSysFS_Version = { .Flags = VFS_FFLAG_DIRECTORY, .Type = &gSysFS_DirNodeType }, - "Version" + .Name = {"Version"} }; // Root of the SysFS tree (just used to keep the code clean) tSysFS_Ent gSysFS_Root = { @@ -86,7 +84,7 @@ tSysFS_Ent gSysFS_Root = { .ImplPtr = &gSysFS_Version, .ImplInt = (Uint)&gSysFS_Root // Self-Link }, - "/" + {"/"} }; tDevFS_Driver gSysFS_DriverInfo = { NULL, "system", diff --git a/KernelLand/Kernel/drv/pty.c b/KernelLand/Kernel/drv/pty.c index 3b30b996e4aba0035584b2cb810124be3a9a5c80..d1f74c58d8fe47eab82114efa7c951b6f58119fe 100644 --- a/KernelLand/Kernel/drv/pty.c +++ b/KernelLand/Kernel/drv/pty.c @@ -85,6 +85,7 @@ tVFS_NodeType gPTY_NodeType_Root = { }; tVFS_NodeType gPTY_NodeType_Client = { .TypeName = "PTY-Client", + .Flags = VFS_NODETYPEFLAG_STREAM, .Read = PTY_ReadClient, .Write = PTY_WriteClient, .IOCtl = PTY_IOCtl, @@ -93,6 +94,7 @@ tVFS_NodeType gPTY_NodeType_Client = { }; tVFS_NodeType gPTY_NodeType_Server = { .TypeName = "PTY-Server", + .Flags = VFS_NODETYPEFLAG_STREAM, .Read = PTY_ReadServer, .Write = PTY_WriteServer, .IOCtl = PTY_IOCtl, @@ -235,6 +237,7 @@ tPTY *PTY_Create(const char *Name, void *Handle, tPTY_OutputFcn Output, tPTY_Req if( InitialMode ) ret->Mode = *InitialMode; // - Client node + ret->ClientNode.Size = -1; ret->ClientNode.ImplPtr = ret; ret->ClientNode.Type = &gPTY_NodeType_Client; ret->ClientNode.UID = Threads_GetUID(); @@ -624,12 +627,14 @@ size_t PTY_WriteClient(tVFS_Node *Node, off_t Offset, size_t Length, const void // If the server has terminated, send SIGPIPE if( pty->ServerNode && pty->ServerNode->ReferenceCount == 0 ) { + LOG("SIGPIPE, server has terminated"); Threads_PostSignal(SIGPIPE); errno = EIO; return -1; } // Write to either FIFO or directly to output function + LOG("pty->OutputFcn = %p", pty->OutputFcn); if( pty->OutputFcn ) { pty->OutputFcn(pty->OutputHandle, Length, Buffer); return Length; @@ -810,6 +815,8 @@ int PTY_IOCtl(tVFS_Node *Node, int ID, void *Data) int is_server = !pty || Node == pty->ServerNode; + LOG("(%i,%p) %s", ID, Data, (is_server?"Server":"Client")); + switch(ID) { case DRV_IOCTL_TYPE: return DRV_TYPE_TERMINAL; diff --git a/KernelLand/Kernel/drv/serial.c b/KernelLand/Kernel/drv/serial.c index bc7597e4bdb0b6b3b9858c1ccdcf66a3cc24e7cc..df13fc73e11b6f3e25572fa0d49df9f459922437 100644 --- a/KernelLand/Kernel/drv/serial.c +++ b/KernelLand/Kernel/drv/serial.c @@ -5,6 +5,7 @@ * drv/serial.c * - Common serial port code */ +#define DEBUG 0 #include <acess.h> #include <modules.h> #include <fs_devfs.h> @@ -65,6 +66,7 @@ tSerialPort *Serial_CreatePort(tSerial_OutFcn output, void *handle) void Serial_ByteReceived(tSerialPort *Port, char Ch) { + LOG("Port=%p,Ch=%i", Port, Ch); if( !Port ) return ; if( Port == gSerial_KernelDebugPort ) @@ -109,6 +111,7 @@ void Serial_ByteReceived(tSerialPort *Port, char Ch) } if( Ch == '\r' ) Ch = '\n'; + LOG("Dispatch to PTY"); PTY_SendInput(Port->PTY, &Ch, 1); } diff --git a/KernelLand/Kernel/drv/shm.c b/KernelLand/Kernel/drv/shm.c new file mode 100644 index 0000000000000000000000000000000000000000..da3214132c4490c795afb3e4941a1cb6f660b24b --- /dev/null +++ b/KernelLand/Kernel/drv/shm.c @@ -0,0 +1,302 @@ +/* + * Acess2 Kernel + * - By John Hodge (thePowersGang) + * + * drv/shm.c + * - Shared memory "device" + */ +#define DEBUG 0 +#include <acess.h> +#include <modules.h> +#include <fs_devfs.h> +#include <memfs_helpers.h> +#include <semaphore.h> + +#define PAGE_COUNT(v) (((v)+(PAGE_SIZE-1))/PAGE_SIZE) + +// === TYPES === +#define PAGES_PER_BLOCK 1024 +typedef struct sSHM_BufferBlock +{ + struct sSHM_BufferBlock *Next; + tPAddr Pages[PAGES_PER_BLOCK]; +} tSHM_BufferBlock; +typedef struct +{ + tMemFS_FileHdr FileHdr; + tVFS_Node Node; + size_t nPages; + tSHM_BufferBlock FirstBlock; +} tSHM_Buffer; + +// === PROTOTYPES === + int SHM_Install(char **Arguments); + int SHM_Uninstall(void); +tSHM_Buffer *SHM_CreateBuffer(const char *Name); +bool SHM_AddPages(tSHM_Buffer *Buffer, size_t num); +void SHM_DeleteBuffer(tSHM_Buffer *Buffer); +// - Root directory + int SHM_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]); +tVFS_Node *SHM_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags); +tVFS_Node *SHM_MkNod(tVFS_Node *Node, const char *Name, Uint Flags); + int SHM_Unlink(tVFS_Node *Node, const char *OldName); +// - Buffers +void SHM_Reference(tVFS_Node *Node); +void SHM_Close(tVFS_Node *Node); +off_t SHM_Truncate(tVFS_Node *Node, off_t NewSize); +size_t SHM_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags); +size_t SHM_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags); + int SHM_MMap(struct sVFS_Node *Node, off_t Offset, size_t Length, void *Dest); + +// === GLOBALS === +MODULE_DEFINE(0, 0x0100, SHM, SHM_Install, SHM_Uninstall, NULL); +tMemFS_DirHdr gSHM_RootDir = { + .FileHdr = {.Name = "SHMRoot"} +}; +tVFS_NodeType gSHM_DirNodeType = { + .TypeName = "SHM Root", + .ReadDir = SHM_ReadDir, + .FindDir = SHM_FindDir, + .MkNod = SHM_MkNod, + .Unlink = SHM_Unlink, +}; +tVFS_NodeType gSHM_FileNodeType = { + .TypeName = "SHM Buffer", + .Read = SHM_Read, + .Write = SHM_Write, + .Close = SHM_Close, + .MMap = SHM_MMap, + .Truncate = SHM_Truncate, + .Reference = SHM_Reference, +}; +tDevFS_Driver gSHM_DriverInfo = { + .Name = "shm", + .RootNode = { + .Size = 0, + .NumACLs = 1, + .ACLs = &gVFS_ACL_EveryoneRW, + .Flags = VFS_FFLAG_DIRECTORY, + .Type = &gSHM_DirNodeType + } +}; + +// === CODE === +int SHM_Install(char **Arguments) +{ + MemFS_InitDir(&gSHM_RootDir); + DevFS_AddDevice( &gSHM_DriverInfo ); + return MODULE_ERR_OK; +} +int SHM_Uninstall(void) +{ + return MODULE_ERR_OK; +} +tSHM_Buffer *SHM_CreateBuffer(const char *Name) +{ + tSHM_Buffer *ret = calloc(1, sizeof(tSHM_Buffer) + strlen(Name) + 1); + MemFS_InitFile(&ret->FileHdr); + ret->FileHdr.Name = (const char*)(ret+1); + strcpy((char*)ret->FileHdr.Name, Name); + ret->Node.ImplPtr = ret; + ret->Node.Type = &gSHM_FileNodeType; + ret->Node.ReferenceCount = 1; + return ret; +} +bool SHM_AddPages(tSHM_Buffer *Buffer, size_t num) +{ + tSHM_BufferBlock *block = &Buffer->FirstBlock; + // Search for final block + size_t idx = Buffer->nPages; + while( block->Next ) { + block = block->Next; + idx -= PAGES_PER_BLOCK; + } + ASSERTC(idx, <=, PAGES_PER_BLOCK); + + for( size_t i = 0; i < num; i ++ ) + { + if( idx == PAGES_PER_BLOCK ) + { + block->Next = calloc(1, sizeof(tSHM_BufferBlock)); + if(!block->Next) { + Log_Warning("SHM", "Out of memory, allocating new buffer block"); + return false; + } + block = block->Next; + idx = 0; + } + ASSERT(block->Pages[idx] == 0); + block->Pages[idx] = MM_AllocPhys(); + if( !block->Pages[idx] ) { + Log_Warning("SHM", "Out of memory, allocating page"); + return false; + } + Buffer->nPages += 1; + idx ++; + } + return true; +} +void SHM_DeleteBuffer(tSHM_Buffer *Buffer) +{ + ASSERTCR(Buffer->Node.ReferenceCount,==,0,); + + // TODO: Destroy multi-block nodes + ASSERT(Buffer->FirstBlock.Next == NULL); + + free(Buffer); +} +// - Root directory +int SHM_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]) +{ + return MemFS_ReadDir(&gSHM_RootDir, Id, Dest); +} + +/** + * \brief Open a shared memory buffer + * + * \note Opening 'anon' will always succeed, and will create an anonymous mapping + */ +tVFS_Node *SHM_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags) +{ + if( strcmp(Filename, "anon") == 0 ) + { + tSHM_Buffer *ret = SHM_CreateBuffer(""); + return &ret->Node; + } + + tMemFS_FileHdr *file = MemFS_FindDir(&gSHM_RootDir, Filename); + if( !file ) + return NULL; + + return &((tSHM_Buffer*)file)->Node; +} + + +/** + * \brief Create a named shared memory file + */ +tVFS_Node *SHM_MkNod(tVFS_Node *Node, const char *Name, Uint Flags) +{ + if( MemFS_FindDir(&gSHM_RootDir, Name) ) + return NULL; + + tSHM_Buffer *ret = SHM_CreateBuffer(Name); + if( !MemFS_Insert(&gSHM_RootDir, &ret->FileHdr) ) + { + ret->Node.ReferenceCount = 0; + SHM_DeleteBuffer(ret); + return NULL; + } + + return &ret->Node; +} + +/** + * \breif Remove a named shared memory buffer (will be deleted when all references drop) + */ +int SHM_Unlink(tVFS_Node *Node, const char *OldName) +{ + tMemFS_FileHdr *file = MemFS_Remove(&gSHM_RootDir, OldName); + if( !file ) + return 1; + + tSHM_Buffer *buf = (tSHM_Buffer*)file; + if( buf->Node.ReferenceCount == 0 ) + { + SHM_DeleteBuffer(buf); + } + else + { + // dangling references, let them clean themselves up later + } + return 0; +} +// - Buffers +void SHM_Reference(tVFS_Node *Node) +{ + Node->ReferenceCount ++; +} +void SHM_Close(tVFS_Node *Node) +{ + Node->ReferenceCount --; + if( Node->ReferenceCount == 0 ) + { + // TODO: How to tell if a buffer should be deleted here? + UNIMPLEMENTED(); + } +} +off_t SHM_Truncate(tVFS_Node *Node, off_t NewSize) +{ + ENTER("pNode XNewSize", Node, NewSize); + tSHM_Buffer *buffer = Node->ImplPtr; + LOG("Node->Size = 0x%llx", Node->Size); + if( PAGE_COUNT(NewSize) != PAGE_COUNT(Node->Size) ) + { + int page_difference = PAGE_COUNT(NewSize) - PAGE_COUNT(Node->Size); + LOG("page_difference = %i", page_difference); + if( page_difference < 0 ) + { + // Truncate down + // TODO: What if underlying pages are mapped?... should it matter? + UNIMPLEMENTED(); + } + else + { + // Truncate up + SHM_AddPages(buffer, page_difference); + } + } + else + { + LOG("Page count hasn't changed"); + } + Node->Size = NewSize; + LEAVE('X', NewSize); + return NewSize; +} +size_t SHM_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags) +{ + UNIMPLEMENTED(); + return -1; +} +size_t SHM_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags) +{ + // TODO: Should first write determine the fixed size of the buffer? + UNIMPLEMENTED(); + return -1; +} +int SHM_MMap(struct sVFS_Node *Node, off_t Offset, size_t Length, void *Dest) +{ + tSHM_Buffer *buf = Node->ImplPtr; + if( Offset > Node->Size ) return 1; + if( Offset + Length > Node->Size ) return 1; + + const int pagecount = (Length + Offset % PAGE_SIZE) / PAGE_SIZE; + int pagenum = Offset / PAGE_SIZE; + + tSHM_BufferBlock *block = &buf->FirstBlock; + while( pagenum > PAGES_PER_BLOCK ) { + block = block->Next; + ASSERT(block); + pagenum -= PAGES_PER_BLOCK; + } + + tPage *dst = Dest; + for( int i = 0; i < pagecount; i ++ ) + { + if( pagenum == PAGES_PER_BLOCK ) { + block = block->Next; + ASSERT(block); + pagenum = 0; + } + + ASSERT(block->Pages[pagenum]); + LOG("%p => %i:%P", dst, pagenum, block->Pages[pagenum]); + MM_Map(dst, block->Pages[pagenum]); + + pagenum ++; + dst ++; + } + return 0; +} + diff --git a/KernelLand/Kernel/drv/vterm.c b/KernelLand/Kernel/drv/vterm.c index 2c6a0d2f8a79ce34cda825b1f8fc3a21250ed2be..217557058c0376ae5507092f951d9e037ebd7d07 100644 --- a/KernelLand/Kernel/drv/vterm.c +++ b/KernelLand/Kernel/drv/vterm.c @@ -5,7 +5,7 @@ * drv/vterm.c * - Virtual Terminal - Initialisation and VFS Interface */ -#define DEBUG 1 +#define DEBUG 0 #include "vterm.h" #include <fs_devfs.h> #include <modules.h> @@ -34,7 +34,6 @@ extern void Debug_SetKTerminal(const char *File); // === PROTOTYPES === int VT_Install(char **Arguments); int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data); -void VT_int_PutFBData(tVTerm *Term, size_t Offset, size_t Length, const void *Data); void VT_PTYOutput(void *Handle, size_t Length, const void *Data); int VT_PTYResize(void *Handle, const struct ptydims *Dims); int VT_PTYModeset(void *Handle, const struct ptymode *Mode); @@ -369,15 +368,16 @@ void VT_PTYOutput(void *Handle, size_t Length, const void *Data) VT_int_PutString(term, Data, Length); break; case PTYBUFFMT_FB: - // TODO: How do offset? + // TODO: How can the offset be done cleanly? (Ask the PTY for its offset?) + Warning("TODO: Offsets for VT_PTYOutput FBData"); VT_int_PutFBData(term, 0, Length, Data); break; case PTYBUFFMT_2DCMD: - // TODO: Impliment 2D commands VT_int_Handle2DCmd(term, Length, Data); break; case PTYBUFFMT_3DCMD: - // TODO: Impliment 3D commands + // TODO: Implement 3D commands + Warning("TODO: VTerm 3D commands"); break; } } diff --git a/KernelLand/Kernel/drv/vterm.h b/KernelLand/Kernel/drv/vterm.h index 05aad87a458ccb0376805c9be956e61816a48f42..75128ba5968760376a3b39f9684aba14c8e62425 100644 --- a/KernelLand/Kernel/drv/vterm.h +++ b/KernelLand/Kernel/drv/vterm.h @@ -94,6 +94,11 @@ struct sVTerm int CachePos; char Cache[32]; size_t PreEat; + union { + struct { + size_t Offset; + } Push; + } CmdInfo; } Cmd2D; tPTY *PTY; @@ -134,6 +139,7 @@ extern void VT_int_ClearLine(tVTerm *Term, int Num); extern void VT_int_ClearInLine(tVTerm *Term, int Row, int FirstCol, int LastCol); extern void VT_int_Resize(tVTerm *Term, int NewWidth, int NewHeight); extern void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled); +extern void VT_int_PutFBData(tVTerm *Term, size_t Offset, size_t Length, const void *Buffer); extern tVT_Pos *VT_int_GetWritePosPtr(tVTerm *Term); extern size_t VT_int_GetBufferRows(tVTerm *Term); diff --git a/KernelLand/Kernel/drv/vterm_2d.c b/KernelLand/Kernel/drv/vterm_2d.c index 4b750ab77e23a31eb0620b1c7911410d58085fe8..086c2b4f37190aa9e4e4e450b1bbcf7f105c3d02 100644 --- a/KernelLand/Kernel/drv/vterm_2d.c +++ b/KernelLand/Kernel/drv/vterm_2d.c @@ -14,6 +14,7 @@ void VT_int_SetCursorBitmap(tVTerm *Term, int W, int H); size_t VT_int_FillCursorBitmap(tVTerm *Term, size_t DataOfs, size_t Length, const void *Data); int VT_int_2DCmd_SetCursorPos(void *Handle, size_t Offset, size_t Length, const void *Data); int VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, const void *Data); + int VT_int_2DCmd_SendData(void *Handle, size_t Offset, size_t Length, const void *Data); // === CODE === void VT_int_SetCursorPos(tVTerm *Term, int X, int Y) @@ -102,18 +103,15 @@ int VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, con Length -= ret; Data = (const char*)Data + ret; Offset += ret; - if( Length == 0 ) - return -ret; } + + ASSERTC(Offset, >=, sizeof(cmd)); - - if( Offset < sizeof(cmd) ) { - // oops? - return ret; + if( Length > 0 ) + { + ret += VT_int_FillCursorBitmap(Handle, Offset - sizeof(cmd), Length, Data); } - ret += VT_int_FillCursorBitmap(Handle, Offset - sizeof(cmd), Length, Data); - LOG("%i + %i ==? %i", ret, Offset, term->Cmd2D.CurrentSize); if( ret + Offset >= term->Cmd2D.CurrentSize ) return ret; @@ -121,6 +119,46 @@ int VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, con return -ret; } +int VT_int_2DCmd_SendData(void *Handle, size_t Offset, size_t Length, const void *Data) +{ + tVTerm *term = Handle; + struct ptycmd_senddata cmd; + size_t ret = 0; + + if( Offset == 0 ) + { + if( Length < sizeof(cmd) ) + return 0; + memcpy(&cmd, Data, sizeof(cmd)); + + ret = sizeof(cmd); + Offset += ret; + Length -= ret; + Data = (const char*)Data + ret; + + term->Cmd2D.CmdInfo.Push.Offset = cmd.ofs*4; + } + + ASSERTC(Offset, >=, sizeof(cmd)); + + if( Length > 0 ) + { + size_t bytes = MIN(term->Width*term->Height*4 - term->Cmd2D.CmdInfo.Push.Offset, Length); + LOG("bytes = %i (0x%x), Length = %i", bytes, bytes, Length); + + VT_int_PutFBData(term, term->Cmd2D.CmdInfo.Push.Offset, bytes, Data ); + term->Cmd2D.CmdInfo.Push.Offset += bytes; + ret += bytes; + + LOG("bytes(%i) ==? 0 || ret(%i) + Offset(%i) ==? %i", + bytes, ret, Offset, term->Cmd2D.CurrentSize); + if( bytes == 0 || ret + Offset >= term->Cmd2D.CurrentSize ) + return ret; + } + + return -ret; +} + // > 0: Command complete // = 0: Not enough data to start // < 0: Ate -n bytes, still need more @@ -128,6 +166,7 @@ typedef int (*tVT_2DCmdHandler)(void *Handle, size_t Offset, size_t Length, cons tVT_2DCmdHandler gVT_2DCmdHandlers[] = { [PTY2D_CMD_SETCURSORPOS] = VT_int_2DCmd_SetCursorPos, [PTY2D_CMD_SETCURSORBMP] = VT_int_2DCmd_SetCursorBitmap, + [PTY2D_CMD_SEND] = VT_int_2DCmd_SendData, }; const int ciVT_Num2DCmdHandlers = sizeof(gVT_2DCmdHandlers)/sizeof(gVT_2DCmdHandlers[0]); @@ -137,7 +176,7 @@ void VT_int_Handle2DCmd(void *Handle, size_t Length, const void *Data) tVTerm *term = Handle; LOG("Length = 0x%x", Length); - // If a command terminated early, we have to clean up its data + // If a command didn't consume all the data it said it would, we have to clean up _eat: if( term->Cmd2D.PreEat ) { @@ -164,7 +203,10 @@ _eat: } // else begin a new command else - { + { + // If the new data would fit in the cache, or the cache is already populated + // use the cache + // - The cache should fit the header for every command, so all good if( Length < cachesize || term->Cmd2D.CachePos != 0 ) { adjust = term->Cmd2D.CachePos; @@ -174,25 +216,33 @@ _eat: dataptr = (void*)term->Cmd2D.Cache; len = term->Cmd2D.CachePos; } - else { + else + { dataptr = (void*)bdata; len = Length; adjust = 0; } const struct ptycmd_header *hdr = dataptr; - if( len < sizeof(*hdr) ) { + // If there's not enough for the common header, wait for more + if( len < sizeof(*hdr) ) + { return ; } + // Parse header term->Cmd2D.Offset = 0; term->Cmd2D.Current = hdr->cmd; term->Cmd2D.CurrentSize = (hdr->len_low | (hdr->len_hi << 8)) * 4; - if( term->Cmd2D.CurrentSize == 0 ) + if( term->Cmd2D.CurrentSize == 0 ) { + Log_Warning("VTerm", "Command size too small (==0)"); term->Cmd2D.CurrentSize = 2; + } LOG("Started %i with %s data", term->Cmd2D.Current, (dataptr == bdata ? "direct" : "cache")); } + + // Sanity check if( term->Cmd2D.Current >= ciVT_Num2DCmdHandlers || !gVT_2DCmdHandlers[term->Cmd2D.Current] ) { Log_Notice("VTerm", "2D Comand %i not handled", term->Cmd2D.Current); @@ -203,42 +253,60 @@ _eat: term->Cmd2D.PreEat = term->Cmd2D.CurrentSize; goto _eat; } - else + + const tVT_2DCmdHandler* handler = &gVT_2DCmdHandlers[term->Cmd2D.Current]; + #if 0 + if( term->Cmd2D.Offset == 0 ) { - int rv = gVT_2DCmdHandlers[term->Cmd2D.Current](Handle, term->Cmd2D.Offset, len, dataptr); - LOG("2DCmd %i: rv=%i", term->Cmd2D.Current, rv); - if( rv == 0 && term->Cmd2D.Offset == 0 ) { - // 0: Not enough data for header - ASSERT( term->Cmd2D.CachePos != cachesize ); - // Clear current command because this command hasn't started yet - term->Cmd2D.Current = 0; - // Return, restart happens once all data is ready + if( len < handler->HeaderLength ) { return ; } - size_t used_bytes = (rv < 0 ? -rv : rv) - adjust; - Length -= used_bytes; - bdata += used_bytes; - term->Cmd2D.CachePos = 0; - if( rv < 0 ) { - ASSERT( -rv <= len ); - LOG(" Incomplete"); - term->Cmd2D.Offset += -rv; - continue ; - } - ASSERT(rv <= len); + rv = handler->Header(Handle, len, dataptr); + } + else + { + rv = hander->Body(Handle, term->Cmd2D.Offset, len, dataptr); + } + #endif + + // Call Handler + int rv = (*handler)(Handle, term->Cmd2D.Offset, len, dataptr); + LOG("2DCmd %i: rv=%i", term->Cmd2D.Current, rv); + + // If it returned 0 on the first call, it lacks space for the header + if( rv == 0 && term->Cmd2D.Offset == 0 ) + { + ASSERT( term->Cmd2D.CachePos != cachesize ); + // Clear current command because this command hasn't started yet term->Cmd2D.Current = 0; + // Return, restart happens once all data is ready + return ; + } - // Eat up any uneaten data - // - TODO: Need to eat across writes - ASSERT( term->Cmd2D.Offset + rv <= term->Cmd2D.CurrentSize ); - if( term->Cmd2D.Offset + rv < term->Cmd2D.CurrentSize ) - { - size_t diff = term->Cmd2D.CurrentSize - (term->Cmd2D.Offset + rv); - LOG("Left %i bytes", diff); - term->Cmd2D.PreEat = diff; - goto _eat; - } - LOG("Done (%i bytes left)", Length); + // Consume the byte count returned (adjust is the number of bytes that were already cached) + size_t used_bytes = (rv < 0 ? -rv : rv) - adjust; + Length -= used_bytes; + bdata += used_bytes; + term->Cmd2D.CachePos = 0; + // If a negative count was returned, more data is expected + if( rv < 0 ) { + ASSERT( -rv <= len ); + LOG(" Incomplete"); + term->Cmd2D.Offset += -rv; + continue ; + } + ASSERT(rv <= len); + term->Cmd2D.Current = 0; + + // Eat up any uneaten data + ASSERT( term->Cmd2D.Offset + rv <= term->Cmd2D.CurrentSize ); + if( term->Cmd2D.Offset + rv < term->Cmd2D.CurrentSize ) + { + size_t diff = term->Cmd2D.CurrentSize - (term->Cmd2D.Offset + rv); + LOG("Left %i bytes", diff); + term->Cmd2D.PreEat = diff; + goto _eat; } + LOG("Done (%i bytes left)", Length); } } diff --git a/KernelLand/Kernel/drv/vterm_input.c b/KernelLand/Kernel/drv/vterm_input.c index 6c25cc81974a888863f4b653a9630f6d8abd8500..aa517d9df69758af9832d6a905124c955f655d9f 100644 --- a/KernelLand/Kernel/drv/vterm_input.c +++ b/KernelLand/Kernel/drv/vterm_input.c @@ -95,20 +95,30 @@ void VT_KBCallBack(Uint32 Codepoint) // Log_Debug("VTerm", "Magic Ctrl-Alt-0x%x", term->RawScancode); + const unsigned int scroll_step = term->TextHeight / 2; + // Note the lack of giVT_Scrollback+1, view top can't go above size-onescreen + const unsigned int scroll_max = term->TextHeight * giVT_Scrollback; switch(term->RawScancode) { - // Scrolling + // VTerm scrolling + // - Scrolls half a screen at a time + // - View up (text goes down) case KEYSYM_PGUP: if( term->Flags & VT_FLAG_ALTBUF ) return ; - term->ViewTopRow = MAX(0, term->ViewTopRow - 1); + Log_Debug("VTerm", "ScrollUp - Old=%i, step=%i", term->ViewTopRow, scroll_step); + term->ViewTopRow = (term->ViewTopRow > scroll_step ? term->ViewTopRow - scroll_step : 0); + Log_Debug("VTerm", "ScrollUp - New=%i", term->ViewTopRow); VT_int_UpdateScreen(term, 1); return; + // - View down (text goes up) case KEYSYM_PGDN: if( term->Flags & VT_FLAG_ALTBUF ) return ; - // Note the lack of giVT_Scrollback+1, view top can't go above size-onescreen - term->ViewTopRow = MIN(term->ViewTopRow + 1, term->Height * giVT_Scrollback); + + Log_Debug("VTerm", "ScrollDown - Old=%i, max=%i", term->ViewTopRow, scroll_max); + term->ViewTopRow = MIN(term->ViewTopRow + scroll_step, scroll_max); + Log_Debug("VTerm", "ScrollDown - New=%i", term->ViewTopRow); VT_int_UpdateScreen(term, 1); return; } diff --git a/KernelLand/Kernel/drv/vterm_output.c b/KernelLand/Kernel/drv/vterm_output.c index 532d2686376cbcd04f9072ffa47390f3259cd941..95c552f5f898417fc41db9a8edf3f8766ffb2834 100644 --- a/KernelLand/Kernel/drv/vterm_output.c +++ b/KernelLand/Kernel/drv/vterm_output.c @@ -5,9 +5,9 @@ * drv/vterm_input.c * - Virtual Terminal - Input code */ +#define DEBUG 0 #include "vterm.h" #include <api_drv_video.h> -#define DEBUG 0 // === CODE === /** @@ -52,8 +52,12 @@ void VT_int_ScrollFramebuffer( tVTerm *Term, int Count ) // Only update if this is the current terminal if( Term != gpVT_CurTerm ) return; + ENTER("pTerm iCount", + Term, Count); + if( Count > Term->ScrollHeight ) Count = Term->ScrollHeight; if( Count < -Term->ScrollHeight ) Count = -Term->ScrollHeight; + LOG("Count = %i", Count); // Switch to 2D Command Stream tmp = VIDEO_BUFFMT_2DSTREAM; @@ -81,6 +85,7 @@ void VT_int_ScrollFramebuffer( tVTerm *Term, int Count ) // Restore old mode (this function is only called during text mode) tmp = VIDEO_BUFFMT_TEXT; VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp); + LEAVE('-'); } void VT_int_UpdateCursor( tVTerm *Term, int bShow ) @@ -88,6 +93,8 @@ void VT_int_UpdateCursor( tVTerm *Term, int bShow ) tVideo_IOCtl_Pos csr_pos; if( Term != gpVT_CurTerm ) return ; + + ENTER("pTerm bShow", Term, bShow); if( !bShow ) { @@ -119,6 +126,7 @@ void VT_int_UpdateCursor( tVTerm *Term, int bShow ) csr_pos.y = Term->VideoCursorY; } VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &csr_pos); + LEAVE('-'); } /** @@ -127,15 +135,21 @@ void VT_int_UpdateCursor( tVTerm *Term, int bShow ) */ void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) { + ENTER("pTerm iUpdateAll", Term, UpdateAll); // Only update if this is the current terminal - if( Term != gpVT_CurTerm ) return; - + if( Term != gpVT_CurTerm ) { + LOG("Term != gpVT_CurTerm (%p)", gpVT_CurTerm); + LEAVE('-'); + return; + } + switch( Term->Mode ) { case TERM_MODE_TEXT: { size_t view_pos = (Term->Flags & VT_FLAG_ALTBUF) ? 0 : Term->ViewTopRow*Term->TextWidth; const tVT_Pos *wrpos = VT_int_GetWritePosPtr(Term); const tVT_Char *buffer = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text; + LOG("view_pos = %i, wrpos = %p (R%i,C%i), buffer=%p", view_pos, wrpos, wrpos->Row, wrpos->Col, buffer); // Re copy the entire screen? if(UpdateAll) { VFS_WriteAt( @@ -148,6 +162,7 @@ void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) // Only copy the current line else { size_t ofs = wrpos->Row * Term->TextWidth; + LOG("ofs = %i", ofs); VFS_WriteAt( giVT_OutputDevHandle, (ofs - view_pos)*sizeof(tVT_Char), @@ -161,5 +176,6 @@ void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) } VT_int_UpdateCursor(Term, 1); + LEAVE('-'); } diff --git a/KernelLand/Kernel/drv/vterm_termbuf.c b/KernelLand/Kernel/drv/vterm_termbuf.c index 50787228063fb0910894b358c3dca53610f05050..1a14f8252ab8481f45c3c477e36df1f4336ab7eb 100644 --- a/KernelLand/Kernel/drv/vterm_termbuf.c +++ b/KernelLand/Kernel/drv/vterm_termbuf.c @@ -25,6 +25,7 @@ extern int Term_HandleVT100(tVTerm *Term, int Len, const char *Buf); */ void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count) { + ENTER("pTerm pBuffer iCount", Term, Buffer, Count); // Iterate for( int ofs = 0; ofs < Count; ) { @@ -43,7 +44,9 @@ void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count) ofs += esc_len; } // Update Screen - VT_int_UpdateScreen( Term, 1 ); + LOG("Update"); + VT_int_UpdateScreen( Term, 0 ); + LEAVE('-'); } void VT_int_PutRawString(tVTerm *Term, const Uint8 *String, size_t Bytes) @@ -76,7 +79,7 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) { ASSERTC(wrpos->Col, <=, Term->TextWidth); VT_int_UpdateScreen( Term, 0 ); - //wrpos->Row ++; + wrpos->Row ++; wrpos->Col = 0; } @@ -121,6 +124,7 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) case '\0': // Ignore NULL byte return; case '\n': + LOG("Newline, update @ %i", write_pos); VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining wrpos->Row ++; // TODO: Force scroll? @@ -165,10 +169,13 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) buffer[ write_pos ].Ch = Ch; buffer[ write_pos ].Colour = Term->CurColour; // Update the line before wrapping - if( (write_pos + 1) % Term->TextWidth == 0 ) + if( (write_pos + 1) % Term->TextWidth == 0 ) { + LOG("Line wrap, update @ %i", write_pos); VT_int_UpdateScreen( Term, 0 ); - write_pos ++; + // NOTE: Code at the top of PutChar handles the actual wrapping + } wrpos->Col ++; + write_pos ++; break; } @@ -176,11 +183,12 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) HEAP_VALIDATE(); - //LEAVE('-'); + // TODO: Schedule a delayed screen update } void VT_int_ScrollText(tVTerm *Term, int Count) { + ENTER("pTerm iCount", Term, Count); tVT_Char *buf; int scroll_top, scroll_height; @@ -274,6 +282,7 @@ void VT_int_ScrollText(tVTerm *Term, int Count) *wrpos = init_wrpos; HEAP_VALIDATE(); + LEAVE('-'); } /** diff --git a/KernelLand/Kernel/drv/vterm_vt100.c b/KernelLand/Kernel/drv/vterm_vt100.c index 4428b64ee4fc215d6299c26eaa5b60b090316e5f..0d59a666fc7f6158968087cceb55352a17571a1b 100644 --- a/KernelLand/Kernel/drv/vterm_vt100.c +++ b/KernelLand/Kernel/drv/vterm_vt100.c @@ -44,7 +44,7 @@ void Display_ScrollDown(tTerminal *Term, int CountDown) LOG("(%i)", CountDown); VT_int_UpdateScreen(Term, 0); if( Term->Flags & VT_FLAG_ALTBUF ) - VT_int_ScrollText(Term, CountDown); + VT_int_ScrollText(Term, -CountDown); else { if(Term->ViewTopRow + CountDown < 0) diff --git a/KernelLand/Kernel/drv/zero-one.c b/KernelLand/Kernel/drv/zero-one.c index fa2b502f3059a61feafc748311c2d1b7a82f1d39..b21d1eff8d31622797c949b5ac9dc9a624ab17c0 100644 --- a/KernelLand/Kernel/drv/zero-one.c +++ b/KernelLand/Kernel/drv/zero-one.c @@ -23,33 +23,38 @@ size_t CoreDevs_Read_GRandom(tVFS_Node *Node, off_t Offset, size_t Length, void MODULE_DEFINE(0, 0x0100, CoreDevs, CoreDevs_Install, NULL, NULL); tVFS_NodeType gCoreDevs_NT_Null = { .TypeName = "CoreDevs-null", + .Flags = VFS_NODETYPEFLAG_STREAM, .Read = CoreDevs_Read_Null, .Write = CoreDevs_Write }; tVFS_NodeType gCoreDevs_NT_Zero = { .TypeName = "CoreDevs-zero", + .Flags = VFS_NODETYPEFLAG_STREAM, .Read = CoreDevs_Read_Zero, .Write = CoreDevs_Write }; tVFS_NodeType gCoreDevs_NT_One = { .TypeName = "CoreDevs-one", + .Flags = VFS_NODETYPEFLAG_STREAM, .Read = CoreDevs_Read_One, .Write = CoreDevs_Write }; tVFS_NodeType gCoreDevs_NT_FRandom = { .TypeName = "CoreDevs-frandom", + .Flags = VFS_NODETYPEFLAG_STREAM, .Read = CoreDevs_Read_FRandom, .Write = CoreDevs_Write }; tVFS_NodeType gCoreDevs_NT_GRandom = { .TypeName = "CoreDevs-grandom", + .Flags = VFS_NODETYPEFLAG_STREAM, .Read = CoreDevs_Read_GRandom, .Write = CoreDevs_Write }; tDevFS_Driver gCoreDevs_Null = { NULL, "null", { - .Size = 0, .NumACLs = 1, + .Size = -1, .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRW, .Type = &gCoreDevs_NT_Null } @@ -57,7 +62,7 @@ tDevFS_Driver gCoreDevs_Null = { tDevFS_Driver gCoreDevs_Zero = { NULL, "zero", { - .Size = 0, .NumACLs = 1, + .Size = -1, .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRW, .Type = &gCoreDevs_NT_Zero } @@ -65,7 +70,7 @@ tDevFS_Driver gCoreDevs_Zero = { tDevFS_Driver gCoreDevs_One = { NULL, "one", { - .Size = 0, .NumACLs = 1, + .Size = -1, .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRW, .Type = &gCoreDevs_NT_One } @@ -73,7 +78,7 @@ tDevFS_Driver gCoreDevs_One = { tDevFS_Driver gCoreDevs_FRandom = { NULL, "frandom", { - .Size = 0, .NumACLs = 1, + .Size = -1, .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRW, .Type = &gCoreDevs_NT_FRandom, .DataAvaliable = 1 @@ -82,7 +87,7 @@ tDevFS_Driver gCoreDevs_FRandom = { tDevFS_Driver gCoreDevs_GRandom = { NULL, "grandom", { - .Size = 0, .NumACLs = 1, + .Size = -1, .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRW, .Type = &gCoreDevs_NT_GRandom, .DataAvaliable = 1 diff --git a/KernelLand/Kernel/drvutil_video.c b/KernelLand/Kernel/drvutil_video.c index 4343ab6f181f51dc77e37375b3822651c0224bde..2bffb1ae92f0b932eccaf4bda790c02964c55db3 100644 --- a/KernelLand/Kernel/drvutil_video.c +++ b/KernelLand/Kernel/drvutil_video.c @@ -536,8 +536,6 @@ void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf) void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf) { int bytes_per_px = (Buf->Depth + 7) / 8; - int y, save_pitch; - Uint8 *dest, *src; // Just a little sanity if( !Buf->CursorBitmap || Buf->CursorX == -1 ) return ; @@ -546,16 +544,21 @@ void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf) // Debug("DrvUtil_Video_RemoveCursor: (Buf=%p) dest_x=%i, dest_y=%i", Buf, Buf->CursorDestX, Buf->CursorDestY); // Set up - save_pitch = Buf->CursorBitmap->W * bytes_per_px; - dest = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px; - src = Buf->CursorSaveBuf; - + size_t save_pitch = Buf->CursorBitmap->W * bytes_per_px; + Uint8 *dst = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px; + const Uint8 *src = Buf->CursorSaveBuf; + + ASSERT(Buf->Framebuffer); + ASSERT(src); + ASSERT(CheckMem(dst, Buf->CursorRenderH*Buf->Pitch)); + ASSERT(CheckMem(src, Buf->CursorRenderH*save_pitch)); + // Copy each line back - for( y = 0; y < Buf->CursorRenderH; y ++ ) + for( int y = 0; y < Buf->CursorRenderH; y ++ ) { - memcpy( dest, src, Buf->CursorRenderW * bytes_per_px ); + memcpy( dst, src, Buf->CursorRenderW * bytes_per_px ); src += save_pitch; - dest += Buf->Pitch; + dst += Buf->Pitch; } // Set the cursor as removed diff --git a/KernelLand/Kernel/emergency_console.c b/KernelLand/Kernel/emergency_console.c new file mode 100644 index 0000000000000000000000000000000000000000..dd6d708b31c2c22fbea3c808167af3ce41733dfd --- /dev/null +++ b/KernelLand/Kernel/emergency_console.c @@ -0,0 +1,226 @@ +/* + * Acess 2 Kernel + * - By John Hodge (thePowersGang) + * + * emergency_console.c + * - Kernel-land emergency console/shell + */ +#include <acess.h> +#include <stdarg.h> + +#define STDIN 0 +#define STDOUT 1 +#define STDERR 2 + +// === PROTOTYPES === +void EmergencyConsole(void); +// -- Commands +void Command_ls(const char* path); +void Command_hd(const char* path); +void Command_mount(const char *fs, const char *dev, const char *point); +// -- +static char **split_args(char *line); +static char *read_line(int fd); +static int dprintf(int fd, const char *fmt, ...);// __attribute__((printf(2,3))); + +// === CODE === +void EmergencyConsole(void) +{ + for(;;) + { + dprintf(STDOUT, "(kernel)$ "); + char *line = read_line(STDIN); + + // Explode line into args + char **args = split_args(line); + // Get command from first arg + ASSERT(args); + ASSERT(args[0]); + if( strcmp(args[0], "help") == 0 ) { + dprintf(STDOUT, + "Commands:\n" + "ls <path> - List the contents of a directory\n" + "hd <path> - Dump a file in a 16 bytes/line hex format\n" + "mount <fs> <device> <point> - Mount a filesystem\n" + ); + } + else if( strcmp(args[0], "ls") == 0 ) { + Command_ls(args[1]); + } + else if( strcmp(args[0], "hd") == 0 ) { + Command_hd(args[1]); + } + else if( strcmp(args[0], "mount") == 0 ) { + Command_mount(args[1], args[2], args[3]); + } + else + { + dprintf(STDERR, "Unknown command '%s'\n", args[0]); + } + // Free args + free(args); + free(line); + } +} + +void Command_ls(const char* path) +{ + dprintf(STDERR, "ls: TODO - Implement\n"); +} +void Command_hd(const char* path) +{ + dprintf(STDERR, "hd: TODO - Implement\n"); +} +void Command_mount(const char *fs, const char *dev, const char *point) +{ + dprintf(STDERR, "mount: TODO - Implement\n"); +} + +// Allocates return array (NUL terminated), but mangles input string +static int split_args_imp(char *line, char **buf) +{ + int argc = 0; + int pos = 0; + enum { + MODE_SPACE, + MODE_NORM, + MODE_SQUOTE, + MODE_DQUOTE, + } mode = MODE_SPACE; + for( char *chp = line; *chp; chp ++ ) + { + if( *chp == ' ' ) { + if( mode != MODE_SPACE ) { + if(buf) buf[argc][pos] = '\0'; + argc ++; + } + mode = MODE_SPACE; + continue ; + } + + switch( mode ) + { + case MODE_SPACE: + if( buf ) + buf[argc] = chp; + pos = 0; + case MODE_NORM: + switch( *chp ) + { + case '"': + mode = MODE_DQUOTE; + break; + case '\'': + mode = MODE_SQUOTE; + break; + case '\\': + chp ++; + switch( *chp ) + { + case '\0': + dprintf(STDERR, "err: Trailing '\\'\n"); + break; + case '\\': + case '\'': + case '"': + if(buf) buf[argc][pos++] = *chp; + break; + default: + dprintf(STDERR, "err: Unkown escape '%c'\n", *chp); + break; + } + break; + default: + if(buf) buf[argc][pos++] = *chp; + break; + } + break; + case MODE_SQUOTE: + switch( *chp ) + { + case '\'': + mode = MODE_NORM; + break; + case '\0': + dprintf(STDERR, "err: Unterminated \' string\n"); + break; + default: + if(buf) buf[argc][pos++] = *chp; + break; + } + break; + case MODE_DQUOTE: + switch( *chp ) + { + case '\"': + mode = MODE_NORM; + break; + case '\\': + chp ++; + switch(*chp) + { + case '\0': + dprintf(STDERR, "err: Trailing '\\' in \" string\n"); + break; + case '\\': + case '"': + if(buf) buf[argc][pos++] = *chp; + break; + default: + dprintf(STDERR, "err: Unkown escape '%c'\n", *chp); + break; + } + break; + case '\0': + dprintf(STDERR, "err: Unterminated \" string\n"); + break; + default: + if(buf) buf[argc][pos++] = *chp; + break; + } + break; + } + } + + if(buf) buf[argc][pos++] = '\0'; + argc ++; + return argc; +} +static char **split_args(char *line) +{ + // 1. Count + int count = split_args_imp(line, NULL); + char **ret = malloc( (count + 1) * sizeof(char*) ); + + split_args_imp(line, ret); + ret[count] = NULL; + return ret; +} + +static char *read_line(int fd) +{ + // Read line (or up to ~128 bytes) + // - This assumes a default PTY state (i.e. line buffered, echo on) + char *ret = malloc(128); + size_t len = VFS_Read(STDIN, 128, ret); + ret[len] = 0; + return ret; +} + +static int dprintf(int fd, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + size_t len = vsnprintf(NULL, 0, fmt, args); + va_end(args); + + char buf[len+1]; + va_start(args, fmt); + vsnprintf(buf, len+1, fmt, args); + va_end(args); + + VFS_Write(fd, len, buf); + + return len; +} + diff --git a/KernelLand/Kernel/events.c b/KernelLand/Kernel/events.c index b0225efe2750eccae269209618b19871a761145a..a572d43362d1e66628a7cd258a7bdfee581892fa 100644 --- a/KernelLand/Kernel/events.c +++ b/KernelLand/Kernel/events.c @@ -7,8 +7,8 @@ */ #define DEBUG 0 #include <acess.h> -#include <threads_int.h> #include <events.h> +#include <threads_int.h> // === CODE === void Threads_PostEvent(tThread *Thread, Uint32 EventMask) @@ -87,7 +87,7 @@ Uint32 Threads_WaitEvents(Uint32 EventMask) { Threads_int_Sleep(THREAD_STAT_EVENTSLEEP, NULL, EventMask, &us, NULL, &us->IsLocked); - // Woken when lock is acquired + // Woken when an event fires SHORTLOCK( &us->IsLocked ); } diff --git a/KernelLand/Kernel/heap.c b/KernelLand/Kernel/heap.c index f7054ea4375684ed981eb729d26ce875c183f606..ba4c9adbdd9add234a3bd0c7649056f33f920bb6 100755 --- a/KernelLand/Kernel/heap.c +++ b/KernelLand/Kernel/heap.c @@ -353,6 +353,8 @@ void Heap_Deallocate(const char *File, int Line, void *Ptr) // INVLPTR is returned from Heap_Allocate when the allocation // size is zero. if( Ptr == INVLPTR ) return; + // free(NULL) is a no-op + if( Ptr == NULL ) return; // Alignment Check if( (tVAddr)Ptr % sizeof(void*) != 0 ) { diff --git a/KernelLand/Kernel/include/acess.h b/KernelLand/Kernel/include/acess.h index fe1a0f972cd56acfdb754b50a5e8148dd4ee420d..83611bb6851b31fc2d9aaa9e29f88d75d98e378d 100644 --- a/KernelLand/Kernel/include/acess.h +++ b/KernelLand/Kernel/include/acess.h @@ -27,7 +27,7 @@ #define DEPRECATED __attribute__((deprecated)) //! Mark a parameter as unused #define UNUSED(x) UNUSED_##x __attribute__((unused)) -//! +//! Apply alignment to a variable #define ALIGN(x) __attribute__((aligned(x))) /** @@ -85,11 +85,11 @@ extern const char gsBuildInfo[]; * \{ * \todo Move to mm_virt.h */ -#define MM_PFLAG_RO 0x01 // Writes disallowed -#define MM_PFLAG_EXEC 0x02 // Allow execution -#define MM_PFLAG_NOPAGE 0x04 // Prevent from being paged out -#define MM_PFLAG_COW 0x08 // Copy-On-Write -#define MM_PFLAG_KERNEL 0x10 // Kernel-Only (Ring0) +#define MM_PFLAG_RO 0x01 //!< Writes disallowed +#define MM_PFLAG_EXEC 0x02 //!< Allow execution +#define MM_PFLAG_NOPAGE 0x04 //!< Prevent from being paged out +#define MM_PFLAG_COW 0x08 //!< Copy-On-Write +#define MM_PFLAG_KERNEL 0x10 //!< Kernel-Only (Ring0) /** * \} */ @@ -143,7 +143,9 @@ typedef struct sKernelSymbol { * \name IRQ hander registration * \{ */ +//! Register a callback for when an IRQ is raised extern int IRQ_AddHandler(int Num, void (*Callback)(int, void*), void *Ptr); +//! Remove a previously registered IRQ handler extern void IRQ_RemHandler(int Handle); /** * \} @@ -240,6 +242,15 @@ extern Uint MM_GetFlags(volatile const void *VAddr); * \note There is only a limited ammount of slots avaliable */ extern void *MM_MapTemp(tPAddr PAddr); +/** + * \brief Peform a temporary map of a page from another process + * \param Process Source process + * \param Address Source virtual address + * \return Virtual address of page in memory + * \note Limited slots + */ +struct sProcess; +extern void *MM_MapTempFromProc(struct sProcess *Process, const void *Address); /** * \brief Free a temporarily mapped page * \param Ptr Pointer to page base diff --git a/KernelLand/Kernel/include/acess_string.h b/KernelLand/Kernel/include/acess_string.h index 12e9ba47e8698cae2f32a82cdbb8d7869ed7e30d..b6407932c2c29fce19ea6d79a894f7db5d2072d9 100644 --- a/KernelLand/Kernel/include/acess_string.h +++ b/KernelLand/Kernel/include/acess_string.h @@ -10,7 +10,7 @@ #include <stdarg.h> /** - * \name Strings + * \name String Manipulation * \{ */ // - stdio.h in userland @@ -38,6 +38,7 @@ extern unsigned long strtoul(const char *str, char **end, int base); extern signed long long strtoll(const char *str, char **end, int base); extern signed long strtol(const char *str, char **end, int base); +//! \brief String comparison (case-insensitive) extern int strucmp(const char *Str1, const char *Str2); extern int strpos(const char *Str, char Ch); extern int strpos8(const char *str, Uint32 search); diff --git a/KernelLand/Kernel/include/apidoc_mainpage.h b/KernelLand/Kernel/include/apidoc_mainpage.h index 8b5b85fb35f1e396806ed7678c6d85b917909249..7a5e427dff4fa1b32ad3dfa2aaecdcb461bf39b7 100644 --- a/KernelLand/Kernel/include/apidoc_mainpage.h +++ b/KernelLand/Kernel/include/apidoc_mainpage.h @@ -23,6 +23,8 @@ * user. * - Drivers for specific types of hardware must behave in the specific * way described here. + * - \ref library "Library Functions" + * - Kernel's version of libc and other helper functions * * \page drivers Device Drivers * diff --git a/KernelLand/Kernel/include/drv_pci.h b/KernelLand/Kernel/include/drv_pci.h index 1032814fc121e00fa2d8bba77cde1904e9f2e169..bdc8c850073222ddb4474799b2800bc3bb1a786a 100644 --- a/KernelLand/Kernel/include/drv_pci.h +++ b/KernelLand/Kernel/include/drv_pci.h @@ -82,5 +82,6 @@ extern Uint8 PCI_GetIRQ(tPCIDev id); extern Uint32 PCI_GetBAR(tPCIDev id, int BAR); extern Uint64 PCI_GetValidBAR(tPCIDev id, int BAR, tPCI_BARType BARType); //extern Uint16 PCI_AssignPort(tPCIDev id, int bar, int count); +//extern void* PCI_MapMemBAR(tPCIDev id, int BAR, tPCI_BARType BARType, size_t* Size, tPAddr* PAddr); #endif diff --git a/KernelLand/Kernel/include/logdebug.h b/KernelLand/Kernel/include/logdebug.h index 0710c6bc2cae9d901bb36f79e4940e224761840f..f13187e67f5ff065b41940b63dba530c8d88c100 100644 --- a/KernelLand/Kernel/include/logdebug.h +++ b/KernelLand/Kernel/include/logdebug.h @@ -38,7 +38,7 @@ extern void Log_Debug(const char *Ident, const char *Message, ...); extern void Debug_KernelPanic(void); //!< Initiate a kernel panic extern void Panic(const char *Msg, ...) NORETURN; //!< Print a panic message (initiates a kernel panic) extern void Warning(const char *Msg, ...); //!< Print a warning message -extern void LogF(const char *Fmt, ...); //!< Print a log message without a trailing newline +extern bool LogF(const char *Fmt, ...); //!< Print a log message without a trailing newline extern void LogFV(const char *Fmt, va_list Args); //!< va_list non-newline log message extern void Log(const char *Fmt, ...); //!< Print a log message extern void Debug(const char *Fmt, ...); //!< Print a debug message (doesn't go to KTerm) @@ -49,6 +49,7 @@ extern void Debug_Leave(const char *FuncName, char RetType, ...); extern void Debug_HexDump(const char *Header, const void *Data, size_t Length); #define UNIMPLEMENTED() Warning("'%s' unimplemented", __func__) +#define TODO(fmt, ...) Panic("TODO: ", fmt ,## __VA_ARGS__) #if DEBUG # define ENTER(_types...) Debug_Enter((char*)__func__, _types) # define LOG(_fmt...) Debug_Log((char*)__func__, _fmt) @@ -72,8 +73,8 @@ extern void Debug_HexDump(const char *Header, const void *Data, size_t Length); #define assert(expr) ASSERTV(expr, "") #define ASSERT(expr) ASSERTV(expr, "") #define ASSERTR(expr,rv) ASSERTRV(expr, rv, "") -#define ASSERTC(l,rel,r) ASSERTV(l rel r, ": 0x%x"#rel"0x%x", l, r) -#define ASSERTCR(l,rel,r,rv) ASSERTRV(l rel r, rv, ": 0x%x"#rel"0x%x", l, r) +#define ASSERTC(l,rel,r) ASSERTV ((l) rel (r), ": 0x%x"#rel"0x%x", (Uint)l, (Uint)r) +#define ASSERTCR(l,rel,r,rv) ASSERTRV((l) rel (r), rv, ": 0x%x"#rel"0x%x", (Uint)l, (Uint)r) /** * \} */ diff --git a/KernelLand/Kernel/include/memfs_helpers.h b/KernelLand/Kernel/include/memfs_helpers.h new file mode 100644 index 0000000000000000000000000000000000000000..c20e1704bae3504e55482097dea9418d4000b308 --- /dev/null +++ b/KernelLand/Kernel/include/memfs_helpers.h @@ -0,0 +1,56 @@ +/* + * Acess2 Kernel + * - By John Hodge (thePowersGang) + * + * memfs_helpers.h + * - Helpers for in-memory filesystems + * + * Provides name lookup, iteration, and node insertion + */ +#ifndef _MEMFS_HELPERS_H_ +#define _MEMFS_HELPERS_H_ + +#include <vfs.h> + +typedef struct sMemFS_FileHdr tMemFS_FileHdr; +typedef struct sMemFS_DirHdr tMemFS_DirHdr; + +extern void MemFS_InitDir (tMemFS_DirHdr *Dir); +extern void MemFS_InitFile(tMemFS_FileHdr *File); + +/* + * \brief Fetch the name of the file at the specified position + * \return standard tVFS_NodeType.ReadDir return values + */ +extern int MemFS_ReadDir(tMemFS_DirHdr *Dir, int Pos, char Name[FILENAME_MAX]); +/* + * \brief Look up a file in a directory + */ +extern tMemFS_FileHdr *MemFS_FindDir(tMemFS_DirHdr *Dir, const char *Name); +/** + * \brief Remove a named file from a directory + * \return File header for \a Name, or NULL if not found + */ +extern tMemFS_FileHdr *MemFS_Remove(tMemFS_DirHdr *Dir, const char *Name); +/** + * \brief Insert a pre-constructed file header into the directory + * \param Dir Directory + * \return false if name already exists + */ +extern bool MemFS_Insert(tMemFS_DirHdr *Dir, tMemFS_FileHdr *File); + +struct sMemFS_FileHdr +{ + tMemFS_FileHdr *Next; + const char *Name; +}; + +struct sMemFS_DirHdr +{ + tMemFS_FileHdr FileHdr; + //tRWLock Lock; + tMemFS_FileHdr *FirstChild; +}; + +#endif + diff --git a/KernelLand/Kernel/include/syscalls.h b/KernelLand/Kernel/include/syscalls.h index 9916458f0ba72f0d73646b3efd178ed0a1d1d1d7..9c68195df814e473467dd24bf5725179b7c7fea2 100644 --- a/KernelLand/Kernel/include/syscalls.h +++ b/KernelLand/Kernel/include/syscalls.h @@ -53,25 +53,34 @@ #define SYS_COPYFD 69 // Create a copy of a file handle #define SYS_FDCTL 70 // Modify flags of a file descriptor #define SYS_READ 71 // Read from an open file -#define SYS_WRITE 72 // Write to an open file -#define SYS_IOCTL 73 // Perform an IOCtl Call -#define SYS_SEEK 74 // Seek to a new position in the file -#define SYS_READDIR 75 // Read from an open directory -#define SYS_GETACL 76 // Get an ACL Value -#define SYS_SETACL 77 // Set an ACL Value -#define SYS_FINFO 78 // Get file information -#define SYS_MKDIR 79 // Create a new directory -#define SYS_LINK 80 // Create a new link to a file -#define SYS_SYMLINK 81 // Create a symbolic link -#define SYS_UNLINK 82 // Delete a file -#define SYS_TELL 83 // Return the current file position -#define SYS_CHDIR 84 // Change current directory -#define SYS_GETCWD 85 // Get current directory -#define SYS_MOUNT 86 // Mount a filesystem -#define SYS_SELECT 87 // Wait for file handles +#define SYS_READAT 72 // Read from an open file (with offset) +#define SYS_WRITE 73 // Write to an open file +#define SYS_WRITEAT 74 // Write to an open file (with offset) +#define SYS_TRUNCATE 75 // Change the size of an open file +#define SYS_IOCTL 76 // Perform an IOCtl Call +#define SYS_SEEK 77 // Seek to a new position in the file +#define SYS_READDIR 78 // Read from an open directory +#define SYS_GETACL 79 // Get an ACL Value +#define SYS_SETACL 80 // Set an ACL Value +#define SYS_FINFO 81 // Get file information +#define SYS_MKDIR 82 // Create a new directory +#define SYS_LINK 83 // Create a new link to a file +#define SYS_SYMLINK 84 // Create a symbolic link +#define SYS_UNLINK 85 // Delete a file +#define SYS_TELL 86 // Return the current file position +#define SYS_CHDIR 87 // Change current directory +#define SYS_GETCWD 88 // Get current directory +#define SYS_MOUNT 89 // Mount a filesystem +#define SYS_SELECT 90 // Wait for file handles +#define SYS_MMAP 91 // Map a file into this address space +#define SYS_MUNMAP 92 // Unmap a file +#define SYS_MARSHALFD 93 // Create a reference to a FD suitable for handing to another process +#define SYS_UNMARSHALFD 94 // Accept a marshaled FD -#define NUM_SYSCALLS 88 -#define SYS_DEBUG 0x100 +#define NUM_SYSCALLS 95 +#define SYS_DEBUGS 0x100 +#define SYS_DEBUGF 0x101 +#define SYS_DEBUGHEX 0x102 #if !defined(__ASSEMBLER__) && !defined(NO_SYSCALL_STRS) static const char *cSYSCALL_NAMES[] = { @@ -147,7 +156,10 @@ static const char *cSYSCALL_NAMES[] = { "SYS_COPYFD", "SYS_FDCTL", "SYS_READ", + "SYS_READAT", "SYS_WRITE", + "SYS_WRITEAT", + "SYS_TRUNCATE", "SYS_IOCTL", "SYS_SEEK", "SYS_READDIR", @@ -163,6 +175,10 @@ static const char *cSYSCALL_NAMES[] = { "SYS_GETCWD", "SYS_MOUNT", "SYS_SELECT", + "SYS_MMAP", + "SYS_MUNMAP", + "SYS_MARSHALFD", + "SYS_UNMARSHALFD", "" }; diff --git a/KernelLand/Kernel/include/syscalls.inc.asm b/KernelLand/Kernel/include/syscalls.inc.asm index ee3c8870b21eca0007ed511222b599e23174cd0d..35743b10681ce9d0a9a0ed0a6621abfd0392e15c 100644 --- a/KernelLand/Kernel/include/syscalls.inc.asm +++ b/KernelLand/Kernel/include/syscalls.inc.asm @@ -45,19 +45,26 @@ %define SYS_COPYFD 69 ;Create a copy of a file handle %define SYS_FDCTL 70 ;Modify flags of a file descriptor %define SYS_READ 71 ;Read from an open file -%define SYS_WRITE 72 ;Write to an open file -%define SYS_IOCTL 73 ;Perform an IOCtl Call -%define SYS_SEEK 74 ;Seek to a new position in the file -%define SYS_READDIR 75 ;Read from an open directory -%define SYS_GETACL 76 ;Get an ACL Value -%define SYS_SETACL 77 ;Set an ACL Value -%define SYS_FINFO 78 ;Get file information -%define SYS_MKDIR 79 ;Create a new directory -%define SYS_LINK 80 ;Create a new link to a file -%define SYS_SYMLINK 81 ;Create a symbolic link -%define SYS_UNLINK 82 ;Delete a file -%define SYS_TELL 83 ;Return the current file position -%define SYS_CHDIR 84 ;Change current directory -%define SYS_GETCWD 85 ;Get current directory -%define SYS_MOUNT 86 ;Mount a filesystem -%define SYS_SELECT 87 ;Wait for file handles +%define SYS_READAT 72 ;Read from an open file (with offset) +%define SYS_WRITE 73 ;Write to an open file +%define SYS_WRITEAT 74 ;Write to an open file (with offset) +%define SYS_TRUNCATE 75 ;Change the size of an open file +%define SYS_IOCTL 76 ;Perform an IOCtl Call +%define SYS_SEEK 77 ;Seek to a new position in the file +%define SYS_READDIR 78 ;Read from an open directory +%define SYS_GETACL 79 ;Get an ACL Value +%define SYS_SETACL 80 ;Set an ACL Value +%define SYS_FINFO 81 ;Get file information +%define SYS_MKDIR 82 ;Create a new directory +%define SYS_LINK 83 ;Create a new link to a file +%define SYS_SYMLINK 84 ;Create a symbolic link +%define SYS_UNLINK 85 ;Delete a file +%define SYS_TELL 86 ;Return the current file position +%define SYS_CHDIR 87 ;Change current directory +%define SYS_GETCWD 88 ;Get current directory +%define SYS_MOUNT 89 ;Mount a filesystem +%define SYS_SELECT 90 ;Wait for file handles +%define SYS_MMAP 91 ;Map a file into this address space +%define SYS_MUNMAP 92 ;Unmap a file +%define SYS_MARSHALFD 93 ;Create a reference to a FD suitable for handing to another process +%define SYS_UNMARSHALFD 94 ;Accept a marshaled FD diff --git a/KernelLand/Kernel/include/threads.h b/KernelLand/Kernel/include/threads.h index ed90d0bb81ad7e11f06f0ba381d69dd93e331863..02039329f828ab76e5311b66670b5bf77f3cc21a 100644 --- a/KernelLand/Kernel/include/threads.h +++ b/KernelLand/Kernel/include/threads.h @@ -21,6 +21,7 @@ enum eFaultNumbers #define GETMSG_IGNORE ((void*)-1) typedef struct sThread tThread; +typedef struct sProcess tProcess; // === FUNCTIONS === extern tThread *Proc_GetCurThread(void); @@ -32,9 +33,9 @@ extern int Threads_SetGID(tUID ID); extern tTID Threads_WaitTID(int TID, int *Status); -extern int *Threads_GetMaxFD(void); -extern char **Threads_GetCWD(void); -extern char **Threads_GetChroot(void); +extern int *Threads_GetMaxFD(tProcess *Process); +extern char **Threads_GetCWD(tProcess *Process); +extern char **Threads_GetChroot(tProcess *Process); extern int Proc_SendMessage(Uint Dest, int Length, void *Data); extern int Proc_GetMessage(Uint *Source, Uint BufSize, void *Buffer); diff --git a/KernelLand/Kernel/include/vfs.h b/KernelLand/Kernel/include/vfs.h index f7666137bbdb21db53ed485bcd64423d0f9226b1..b030627e0c983d2dc6661d72546fd6b0fb20704c 100644 --- a/KernelLand/Kernel/include/vfs.h +++ b/KernelLand/Kernel/include/vfs.h @@ -216,6 +216,21 @@ typedef struct sVFS_Node * \} */ +/** + * \name tVFS_NodeType.Type flags + * \brief Flags for node types + * \{ + */ +//\! Calls to VFS_Write should not generate calls to .Trunctate +//\! +//\! If this flag is set, writing over the end of the file will not call .Truncate automatically +#define VFS_NODETYPEFLAG_NOAUTOEXPAND 0x001 +//\! Node type describes a stream (offset ignored, seeking disallowed) +#define VFS_NODETYPEFLAG_STREAM 0x002 +/** + * \} + */ + /** * \brief Functions for a specific node type */ @@ -226,6 +241,11 @@ struct sVFS_NodeType */ const char *TypeName; + /** + * \brief Flags describing operational quirks + */ + unsigned int Flags; + /** * \name Common Functions * \brief Functions that are used no matter the value of .Flags @@ -293,7 +313,18 @@ struct sVFS_NodeType * \return Boolean Failure * \note If NULL, the VFS implements it using .Read */ - int (*MMap)(struct sVFS_Node *Node, off_t Offset, int Length, void *Dest); + int (*MMap)(struct sVFS_Node *Node, off_t Offset, size_t Length, void *Dest); + + /** + * \brief Resize a file + * \param Node Pointer to this node + * \param NewSize New file size + * \return Actual new file size + * \note If NULL, \a Write may be called with Offset + Length > Size + * + * Called to increase/decrease the size of a file. If the + */ + off_t (*Truncate)(struct sVFS_Node *Node, off_t NewSize); /** * \} @@ -469,7 +500,7 @@ extern tVFS_ACL *VFS_UnixToAcessACL(Uint Mode, Uint Owner, Uint Group); * \param Type Type of wait * \param Timeout Time to wait (NULL for infinite wait) * \param Name Name to show in debug output - * \return Number of nodes that actioned (0 or 1) + * \return Bitset of Type flags that applied */ extern int VFS_SelectNode(tVFS_Node *Node, int Type, tTime *Timeout, const char *Name); diff --git a/KernelLand/Kernel/include/vfs_ext.h b/KernelLand/Kernel/include/vfs_ext.h index 65a81624d1df05a5a23ee9609b253cc1edf9f26b..42d986549cdc50e7dada4118350a700c5bbbe717 100644 --- a/KernelLand/Kernel/include/vfs_ext.h +++ b/KernelLand/Kernel/include/vfs_ext.h @@ -226,6 +226,20 @@ extern int VFS_DuplicateFD(int SrcFD, int DstFD); */ extern int VFS_SetFDFlags(int FD, int Mask, int Value); +/** + * \brief Save specified file handle such that it can be passed between processes + * \param FD File descriptor to save + * \return Marshalled handle, or (uint64_t)-1 on error + */ +extern Uint64 VFS_MarshalHandle(int FD); + +/** + * \brief Restore a marshalled handle into the current process + * \param Handle returned by VFS_MarshalHandle + * \return File descriptor, or -1 on error + */ +extern int VFS_UnmarshalHandle(Uint64 Handle); + /** * \brief Get file information from an open file * \param FD File handle returned by ::VFS_Open @@ -314,6 +328,16 @@ extern size_t VFS_ReadAt(int FD, Uint64 Offset, size_t Length, void *Buffer); */ extern size_t VFS_WriteAt(int FD, Uint64 Offset, size_t Length, const void *Buffer); +/** + * \brief Set the valid size of a file + * \param FD File descriptor + * \param Size New file size + * \return Actual new file size (-1 if error occurred) + * + * \note Not all files support this call (will return ENOTIMPL) + */ +extern off_t VFS_Truncate(int FD, off_t Size); + /** * \brief Sends an IOCtl request to the driver * \param FD File handle returned by ::VFS_Open diff --git a/KernelLand/Kernel/include/vfs_threads.h b/KernelLand/Kernel/include/vfs_threads.h index 95ec2278b69891a5ba06eb7a42b2d33c6eb88beb..a9829def6cf130d17f734171a357b1d5fe9abe3a 100644 --- a/KernelLand/Kernel/include/vfs_threads.h +++ b/KernelLand/Kernel/include/vfs_threads.h @@ -10,7 +10,7 @@ // === FUNCTIONS === extern void VFS_ReferenceUserHandles(void); -extern void VFS_CloseAllUserHandles(void); +extern void VFS_CloseAllUserHandles(struct sProcess *Process); extern void *VFS_SaveHandles(int NumFDs, int *FDs); extern void VFS_RestoreHandles(int NumFDs, void *Handles); diff --git a/KernelLand/Kernel/libc.c b/KernelLand/Kernel/libc.c index 2e08a17c807993f3609089d65c83d22f4115fc2d..572184d9bd5a94a05342526ce4f84f763e03861d 100644 --- a/KernelLand/Kernel/libc.c +++ b/KernelLand/Kernel/libc.c @@ -74,6 +74,7 @@ EXPORT(CheckMem); // === CODE === // - Import userland stroi.c file #define _LIB_H_ +#define _SysDebug(f,v...) Log_Debug("libc", f ,## v) #include "../../Usermode/Libraries/libc.so_src/strtoi.c" int ParseInt(const char *string, int *Val) @@ -380,7 +381,7 @@ int vsnprintf(char *__s, const size_t __maxlen, const char *__format, va_list ar break; } p = va_arg(args, char*); // Get Argument - if( !p || !CheckString(p) ) p = "(inval)"; // Avoid #PFs + if( p && !CheckString(p) ) goto invalString; // Avoid #PFs printString: if(!p) p = "(null)"; len = strlen(p); @@ -388,6 +389,20 @@ int vsnprintf(char *__s, const size_t __maxlen, const char *__format, va_list ar while(*p && precision--) { PUTCH(*p); p++;} if( bPadLeft ) while(len++ < minSize) PUTCH(pad); break; + invalString: + PUTCH('(');PUTCH('i');PUTCH('n');PUTCH('v');PUTCH('a'); PUTCH('l');PUTCH(':'); + PUTCH('*');PUTCH('0');PUTCH('x'); + val = (tVAddr)p; + for( len = BITS/4; len -- && ((val>>(len*4))&15) == 0; ) + ; + len ++; + if( len == 0 ) + PUTCH( '0' ); + else + while( len -- ) + PUTCH( cUCDIGITS[ (val>>(len*4))&15 ] ); + PUTCH(')'); + break; case 'C': // Non-Null Terminated Character Array p = va_arg(args, char*); diff --git a/KernelLand/Kernel/logging.c b/KernelLand/Kernel/logging.c index 46d4c0494c9f3336ca4eb9671bd21faaade7a3fa..3ccfef2b03159d61cb72f25e27f437bfbe5eef01 100644 --- a/KernelLand/Kernel/logging.c +++ b/KernelLand/Kernel/logging.c @@ -158,18 +158,18 @@ void Log_Int_PrintMessage(tLogEntry *Entry) if( CPU_HAS_LOCK(&glLogOutput) ) return ; // TODO: Error? SHORTLOCK( &glLogOutput ); - LogF("%s%014lli", + bool completed = LogF( + "%s%014lli%s [%-8s] %i - %.*s\x1B[0m\r\n", csaLevelColours[Entry->Level], - Entry->Time - ); - LogF("%s [%-8s] %i - %.*s", + Entry->Time, csaLevelCodes[Entry->Level], Entry->Ident, Threads_GetTID(), Entry->Length, Entry->Data ); - LogF("\x1B[0m\r\n"); // Separate in case Entry->Data is too long + if( !completed ) + LogF("\x1B[0m\r\n"); // Separate in case Entry->Data is too long SHORTREL( &glLogOutput ); } diff --git a/KernelLand/Kernel/memfs_helpers.c b/KernelLand/Kernel/memfs_helpers.c new file mode 100644 index 0000000000000000000000000000000000000000..a7e5fc4a45fae6539a658657e06795b357cc2690 --- /dev/null +++ b/KernelLand/Kernel/memfs_helpers.c @@ -0,0 +1,54 @@ +/* + * Acess2 Kernel + * - By John Hodge (thePowersGang) + * + * memfs_helpers.c + * - Helpers for in-memory filesystems + */ +#include <memfs_helpers.h> + +// === CODE === +void MemFS_InitDir(tMemFS_DirHdr *Dir) +{ + MemFS_InitFile(&Dir->FileHdr); +} +void MemFS_InitFile(tMemFS_FileHdr *File) +{ + File->Next = NULL; +} + +int MemFS_ReadDir(tMemFS_DirHdr *Dir, int Pos, char Name[FILENAME_MAX]) +{ + int i = 0; + // TODO: Lock + for( tMemFS_FileHdr *file = Dir->FirstChild; file; file = file->Next, i ++ ) + { + if( i == Pos ) + { + strncpy(Name, file->Name, FILENAME_MAX); + return 0; + } + } + return -EINVAL; +} +tMemFS_FileHdr *MemFS_FindDir(tMemFS_DirHdr *Dir, const char *Name) +{ + // TODO: Lock + for( tMemFS_FileHdr *file = Dir->FirstChild; file; file = file->Next ) + { + if( strcmp(file->Name, Name) == 0 ) + return file; + } + return NULL; +} +tMemFS_FileHdr *MemFS_Remove(tMemFS_DirHdr *Dir, const char *Name) +{ + UNIMPLEMENTED(); + return NULL; +} +bool MemFS_Insert(tMemFS_DirHdr *Dir, tMemFS_FileHdr *File) +{ + UNIMPLEMENTED(); + return false; +} + diff --git a/KernelLand/Kernel/rwlock.c b/KernelLand/Kernel/rwlock.c index c39ce10abcef7037a1e40daf7b1bb6d2d78d1977..1fd64592325ee191dd2f54eb69a1ba792d121306 100644 --- a/KernelLand/Kernel/rwlock.c +++ b/KernelLand/Kernel/rwlock.c @@ -21,7 +21,8 @@ int RWLock_AcquireRead(tRWLock *Lock) SHORTLOCK( &Lock->Protector ); // Check if the lock is already held by a writer - if( Lock->Owner ) + // - OR, there's a writer waiting to write + if( Lock->Owner || Lock->WriterWaiting ) { LOG("Waiting"); Threads_int_Sleep(THREAD_STAT_RWLOCKSLEEP, Lock, 0, diff --git a/KernelLand/Kernel/syscalls.c b/KernelLand/Kernel/syscalls.c index d2f91858a6d2f91c02491f6af2ef6c49e9d7108f..7b4855ce5e2c6d8b852c714235fe1e2adf54a11e 100644 --- a/KernelLand/Kernel/syscalls.c +++ b/KernelLand/Kernel/syscalls.c @@ -37,6 +37,12 @@ if(tmp[i]) break;\ } while(0) +#if BITS==64 +#define ARG64(idx1,idx2) ***ARG64 not used on 64-bit*** +#else +#define ARG64(idx1, idx2) (Regs->Arg##idx1|(((Uint64)Regs->Arg##idx2)<<32)) +#endif + // === IMPORTS === extern Uint Binary_Load(const char *file, Uint *entryPoint); @@ -250,7 +256,7 @@ void SyscallHandler(tSyscallRegs *Regs) #if BITS == 64 ret = VFS_Seek( Regs->Arg1, Regs->Arg2, Regs->Arg3 ); #else - ret = VFS_Seek( Regs->Arg1, Regs->Arg2|(((Uint64)Regs->Arg3)<<32), Regs->Arg4 ); + ret = VFS_Seek( Regs->Arg1, ARG64(2, 3), Regs->Arg4 ); #endif break; @@ -262,11 +268,41 @@ void SyscallHandler(tSyscallRegs *Regs) CHECK_NUM_NONULL( (void*)Regs->Arg2, Regs->Arg3 ); ret = VFS_Write( Regs->Arg1, Regs->Arg3, (void*)Regs->Arg2 ); break; + case SYS_WRITEAT: + #if BITS == 64 + CHECK_NUM_NONULL( (void*)Regs->Arg5, Regs->Arg3 ); + ret = VFS_WriteAt( Regs->Arg1, Regs->Arg2, Regs->Arg3, (void*)Regs->Arg4 ); + #else + CHECK_NUM_NONULL( (void*)Regs->Arg5, Regs->Arg4 ); + Debug("VFS_WriteAt(%i, %lli, %i, %p)", + Regs->Arg1, ARG64(2, 3), Regs->Arg4, (void*)Regs->Arg5); + ret = VFS_WriteAt( Regs->Arg1, ARG64(2, 3), Regs->Arg4, (void*)Regs->Arg5 ); + #endif + break; case SYS_READ: CHECK_NUM_NONULL( (void*)Regs->Arg2, Regs->Arg3 ); ret = VFS_Read( Regs->Arg1, Regs->Arg3, (void*)Regs->Arg2 ); break; + case SYS_READAT: + CHECK_NUM_NONULL( (void*)Regs->Arg5, Regs->Arg2 ); + #if BITS == 64 + ret = VFS_ReadAt( Regs->Arg1, Regs->Arg2, Regs->Arg3, (void*)Regs->Arg4 ); + #else + ret = VFS_ReadAt( Regs->Arg1, Regs->Arg2, ARG64(3, 4), (void*)Regs->Arg5 ); + #endif + break; + + case SYS_TRUNCATE: + ret = VFS_Truncate( + Regs->Arg1, + #if BITS == 32 + ARG64(2,3) + #else + Regs->Arg2 + #endif + ); + break; case SYS_FINFO: CHECK_NUM_NONULL( (void*)Regs->Arg2, sizeof(tFInfo) + Regs->Arg3*sizeof(tVFS_ACL) ); @@ -369,6 +405,21 @@ void SyscallHandler(tSyscallRegs *Regs) ); break; + case SYS_MMAP: + ret = (tVAddr)VFS_MMap( + (void*)Regs->Arg1, Regs->Arg2, + Regs->Arg3&0xFFFF, Regs->Arg3>>16, + Regs->Arg4, + #if BITS == 32 + ARG64(5,6) + #else + Regs->Arg5 + #endif + ); + break; + case SYS_MUNMAP: + ret = VFS_MUnmap( (void*)Regs->Arg1, Regs->Arg2 ); + break; // Create a directory case SYS_MKDIR: @@ -378,16 +429,37 @@ void SyscallHandler(tSyscallRegs *Regs) case SYS_UNLINK: Log_Error("Syscalls", "TODO: Impliment SYS_UNLINK"); - // Fall + break; + + case SYS_MARSHALFD: + ret = VFS_MarshalHandle(Regs->Arg1); + break; + case SYS_UNMARSHALFD: + #if BITS == 64 + ret = VFS_UnmarshalHandle( Regs->Arg1 ); + #else + ret = VFS_UnmarshalHandle( ARG64(1,2) ); + #endif + break; + // -- Debug //#if DEBUG_BUILD - case SYS_DEBUG: + case SYS_DEBUGS: + CHECK_STR_NONULL( (char*)Regs->Arg1 ); + Log("Log: %08lli [%i] %s", now(), Threads_GetTID(), (const char*)Regs->Arg1); + break; + case SYS_DEBUGF: CHECK_STR_NONULL( (char*)Regs->Arg1 ); LogF("Log: %08lli [%i] ", now(), Threads_GetTID()); LogF((const char*)Regs->Arg1, Regs->Arg2, Regs->Arg3, Regs->Arg4, Regs->Arg5, Regs->Arg6); LogF("\r\n"); break; + case SYS_DEBUGHEX: + CHECK_STR_NONULL( (char*)Regs->Arg1 ); + CHECK_NUM_NONULL( (void*)Regs->Arg2, Regs->Arg3 ); + Debug_HexDump( (const char*)Regs->Arg1, (void*)Regs->Arg2, Regs->Arg3 ); + break; //#endif // -- Default (Return Error) diff --git a/KernelLand/Kernel/syscalls.lst b/KernelLand/Kernel/syscalls.lst index 42ae03c312a063c1a685bde4c4b99d7501e388ef..bea821b5392a15d4931eaaba23cbe425e1008b28 100644 --- a/KernelLand/Kernel/syscalls.lst +++ b/KernelLand/Kernel/syscalls.lst @@ -53,7 +53,10 @@ SYS_CLOSE Close a file SYS_COPYFD Create a copy of a file handle SYS_FDCTL Modify flags of a file descriptor SYS_READ Read from an open file +SYS_READAT Read from an open file (with offset) SYS_WRITE Write to an open file +SYS_WRITEAT Write to an open file (with offset) +SYS_TRUNCATE Change the size of an open file SYS_IOCTL Perform an IOCtl Call SYS_SEEK Seek to a new position in the file SYS_READDIR Read from an open directory @@ -69,3 +72,8 @@ SYS_CHDIR Change current directory SYS_GETCWD Get current directory SYS_MOUNT Mount a filesystem SYS_SELECT Wait for file handles +SYS_MMAP Map a file into this address space +SYS_MUNMAP Unmap a file +SYS_MARSHALFD Create a reference to a FD suitable for handing to another process +SYS_UNMARSHALFD Accept a marshaled FD + diff --git a/KernelLand/Kernel/system.c b/KernelLand/Kernel/system.c index 0c701c33cff61b57a5221bc2ed19d49b8ffac2b2..9892af3725deb6c964be7f1ea30e2f8a602101f5 100644 --- a/KernelLand/Kernel/system.c +++ b/KernelLand/Kernel/system.c @@ -14,6 +14,7 @@ extern int Modules_LoadBuiltins(void); extern void Modules_SetBuiltinParams(char *Name, char *ArgString); extern void Debug_SetKTerminal(const char *File); extern void Timer_CallbackThread(void *); +extern void EmergencyConsole(void); // === PROTOTYPES === void System_Init(char *Commandline); @@ -22,6 +23,7 @@ void System_ExecuteCommandLine(void); void System_ParseVFS(char *Arg); void System_ParseModuleArgs(char *Arg); void System_ParseSetting(char *Arg); +void System_EmergencyConsole(void); // === GLOBALS === const char *gsInitBinary = "/Acess/SBin/init"; @@ -41,6 +43,7 @@ void System_Init(char *CommandLine) Modules_LoadBuiltins(); Arch_LoadBootModules(); + Log_Log("Config", "Running command line '%s", CommandLine); System_ExecuteCommandLine(); // - Execute the Config Script @@ -52,12 +55,24 @@ void System_Init(char *CommandLine) VFS_Open("/Devices/pts/vt0", VFS_OPENFLAG_WRITE|VFS_OPENFLAG_USER); // 1: stdout VFS_DuplicateFD(1, 2); // 2: stderr Proc_Execve(gsInitBinary, args, &args[1], 0); + + System_EmergencyConsole(); + Log_KernelPanic("System", "Unable to spawn init '%s'", gsInitBinary); } // Set the debug to be echoed to the terminal Log_Log("Config", "Kernel now echoes to VT7 (Ctrl-Alt-F8)"); Debug_SetKTerminal("/Devices/pts/vt7"); + + // Run a thread to reap unowned threads + for( ;; ) + { + int status; + // TODO: Inform init when a thread dies + int tid = Threads_WaitTID(-1, &status); + Log_Debug("Thread0", "Thread %i exited with status %i", tid, status); + } } /** @@ -265,3 +280,8 @@ void System_ParseSetting(char *Arg) } } +void System_EmergencyConsole(void) +{ + // TODO: Support an emergency kernel-land console (with FS viewing support) + EmergencyConsole(); +} diff --git a/KernelLand/Kernel/threads.c b/KernelLand/Kernel/threads.c index 545896c4435b77b78a1ede666420fdd2ea3d5a28..469c5ec18dd3beae6afe01d71d9f4c14a1a67009 100644 --- a/KernelLand/Kernel/threads.c +++ b/KernelLand/Kernel/threads.c @@ -4,6 +4,7 @@ * threads.c * - Common Thread Control */ +#define DEBUG 0 #include <acess.h> #include <threads.h> #include <threads_int.h> @@ -198,7 +199,7 @@ void Threads_Delete(tThread *Thread) proc->Next->Prev = proc->Prev; // VFS Cleanup - VFS_CloseAllUserHandles(); + VFS_CloseAllUserHandles( proc ); // Architecture cleanup Proc_ClearProcess( proc ); // VFS Configuration strings @@ -329,11 +330,10 @@ void Threads_SetPriority(tThread *Thread, int Pri) */ tThread *Threads_CloneTCB(Uint Flags) { - tThread *cur, *new; - cur = Proc_GetCurThread(); + tThread *cur = Proc_GetCurThread(); // Allocate and duplicate - new = malloc(sizeof(tThread)); + tThread *new = malloc(sizeof(tThread)); if(new == NULL) { errno = -ENOMEM; return NULL; } memcpy(new, cur, sizeof(tThread)); @@ -480,18 +480,26 @@ tTID Threads_WaitTID(int TID, int *Status) tTID ret = -1; if( ev & THREAD_EVENT_DEADCHILD ) { + tThread * const us = Proc_GetCurThread(); // A child died, get the TID - tThread *us = Proc_GetCurThread(); ASSERT(us->LastDeadChild); - ret = us->LastDeadChild->TID; + tThread *dead_thread = us->LastDeadChild; + us->LastDeadChild = dead_thread->Next; + if( us->LastDeadChild ) + Threads_PostEvent( us, THREAD_EVENT_DEADCHILD ); + else + Threads_ClearEvent( THREAD_EVENT_DEADCHILD ); + Mutex_Release(&us->DeadChildLock); + + ret = dead_thread->TID; // - Mark as dead (as opposed to undead) - ASSERT(us->LastDeadChild->Status == THREAD_STAT_ZOMBIE); - us->LastDeadChild->Status = THREAD_STAT_DEAD; + ASSERTC(dead_thread->Status, ==, THREAD_STAT_ZOMBIE); + dead_thread->Status = THREAD_STAT_DEAD; // - Set return status if(Status) - *Status = us->LastDeadChild->RetStatus; - us->LastDeadChild = NULL; - Mutex_Release(&us->DeadChildLock); + *Status = dead_thread->RetStatus; + + Threads_Delete( dead_thread ); } else { @@ -722,9 +730,11 @@ void Threads_Kill(tThread *Thread, int Status) SHORTREL( &glThreadListLock ); // TODO: It's possible that we could be timer-preempted here, should disable that... somehow Mutex_Acquire( &Thread->Parent->DeadChildLock ); // released by parent + Thread->Next = Thread->Parent->LastDeadChild; Thread->Parent->LastDeadChild = Thread; Threads_PostEvent( Thread->Parent, THREAD_EVENT_DEADCHILD ); + // Process cleanup happens on reaping Log("Thread %i went *hurk* (%i)", Thread->TID, Status); // And, reschedule @@ -750,6 +760,7 @@ void Threads_Yield(void) void Threads_int_WaitForStatusEnd(enum eThreadStatus Status) { tThread *us = Proc_GetCurThread(); + LOG("us = %p(%i %s), status=%i", us, us->TID, us->ThreadName, Status); ASSERT(Status != THREAD_STAT_ACTIVE); ASSERT(Status != THREAD_STAT_DEAD); while( us->Status == Status ) @@ -1246,17 +1257,20 @@ int *Threads_GetErrno(void) } // --- Configuration --- -int *Threads_GetMaxFD(void) +int *Threads_GetMaxFD(tProcess *Process) { - return &Proc_GetCurThread()->Process->MaxFD; + if(!Process) Process = Proc_GetCurThread()->Process; + return &Process->MaxFD; } -char **Threads_GetChroot(void) +char **Threads_GetChroot(tProcess *Process) { - return &Proc_GetCurThread()->Process->RootDir; + if(!Process) Process = Proc_GetCurThread()->Process; + return &Process->RootDir; } -char **Threads_GetCWD(void) +char **Threads_GetCWD(tProcess *Process) { - return &Proc_GetCurThread()->Process->CurrentWorkingDir; + if(!Process) Process = Proc_GetCurThread()->Process; + return &Process->CurrentWorkingDir; } // --- @@ -1314,22 +1328,16 @@ void Threads_int_DumpThread(tThread *thread) */ void Threads_DumpActive(void) { - tThread *thread; - tThreadList *list; - #if SCHEDULER_TYPE == SCHED_RR_PRI - int i; - #endif - Log("Active Threads: (%i reported)", giNumActiveThreads); #if SCHEDULER_TYPE == SCHED_RR_PRI - for( i = 0; i < MIN_PRIORITY+1; i++ ) + for( int i = 0; i < MIN_PRIORITY+1; i++ ) { - list = &gaActiveThreads[i]; + tThreadList *list = &gaActiveThreads[i]; #else - list = &gActiveThreads; + tThreadList *list = &gActiveThreads; #endif - for(thread=list->Head;thread;thread=thread->Next) + for(tThread *thread = list->Head; thread; thread = thread->Next) { Threads_int_DumpThread(thread); if(thread->Status != THREAD_STAT_ACTIVE) @@ -1465,6 +1473,7 @@ tThread *Threads_int_GetRunnable(void) // Single-list round-robin // ----------------------------------- tThread *thread = gActiveThreads.Head; + LOG("thread = %p", thread); if( thread ) { gActiveThreads.Head = thread->Next; @@ -1486,23 +1495,20 @@ tThread *Threads_int_GetRunnable(void) */ tThread *Threads_GetNextToRun(int CPU, tThread *Last) { - // If this CPU has the lock, we must let it complete - if( CPU_HAS_LOCK( &glThreadListLock ) ) - return Last; + ASSERT( CPU_HAS_LOCK(&glThreadListLock) ); // Don't change threads if the current CPU has switches disabled - if( gaThreads_NoTaskSwitch[CPU] ) + if( gaThreads_NoTaskSwitch[CPU] ) { + LOG("- Denied"); return Last; - - // Lock thread list - SHORTLOCK( &glThreadListLock ); + } // Make sure the current (well, old) thread is marked as de-scheduled if(Last) Last->CurCPU = -1; // No active threads, just take a nap if(giNumActiveThreads == 0) { - SHORTREL( &glThreadListLock ); + LOG("- No active"); #if DEBUG_TRACE_TICKETS Log("No active threads"); #endif @@ -1545,7 +1551,7 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) // Call actual scheduler tThread *thread = Threads_int_GetRunnable(); - + // Anything to do? if( thread ) { @@ -1571,8 +1577,6 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) Warning("No runnable thread for CPU%i", CPU); } - SHORTREL( &glThreadListLock ); - return thread; } diff --git a/KernelLand/Kernel/time.c b/KernelLand/Kernel/time.c index 15b61907216536d3af5b50b178c8ace8866f431d..478c41f3d1410070e3bea1ddd922f1fd5eab70e1 100644 --- a/KernelLand/Kernel/time.c +++ b/KernelLand/Kernel/time.c @@ -76,8 +76,9 @@ void Timer_CallTimers() { // Tick the random number generator every time timers are checked rand(); - + SHORTLOCK(&gTimers_ListLock); + LOG("gTimers = %p (%lli ms)", gTimers, (gTimers ? gTimers->FiresAfter : 0)); while( gTimers && gTimers->FiresAfter < now() ) { ASSERT( gTimers != gTimers->Next ); diff --git a/KernelLand/Kernel/vfs/handle.c b/KernelLand/Kernel/vfs/handle.c index 661ced8124adf7df94b85f09bd7600a6a81ad2fc..d500aa91b775d5edddab8515cd12fc7233d7caea 100644 --- a/KernelLand/Kernel/vfs/handle.c +++ b/KernelLand/Kernel/vfs/handle.c @@ -39,7 +39,7 @@ tVFS_Handle *VFS_GetHandle(int FD) if(FD >= MAX_KERNEL_FILES) return NULL; h = &gaKernelHandles[ FD ]; } else { - if(FD >= *Threads_GetMaxFD()) return NULL; + if(FD >= *Threads_GetMaxFD(NULL)) return NULL; h = &gaUserHandles[ FD ]; } @@ -59,7 +59,7 @@ int VFS_SetHandle(int FD, tVFS_Node *Node, int Mode) h = &gaKernelHandles[FD]; } else { - if( FD >= *Threads_GetMaxFD()) return -1; + if( FD >= *Threads_GetMaxFD(NULL)) return -1; h = &gaUserHandles[FD]; } h->Node = Node; @@ -72,7 +72,7 @@ int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode) // Check for a user open if(bIsUser) { - int max_handles = *Threads_GetMaxFD(); + int max_handles = *Threads_GetMaxFD(NULL); // Allocate Buffer if( MM_GetPhysAddr( gaUserHandles ) == 0 ) { @@ -132,14 +132,13 @@ int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode) void VFS_ReferenceUserHandles(void) { - int i; - int max_handles = *Threads_GetMaxFD(); + const int max_handles = *Threads_GetMaxFD(NULL); // Check if this process has any handles if( MM_GetPhysAddr( gaUserHandles ) == 0 ) return ; - for( i = 0; i < max_handles; i ++ ) + for( int i = 0; i < max_handles; i ++ ) { tVFS_Handle *h; h = &gaUserHandles[i]; @@ -150,22 +149,34 @@ void VFS_ReferenceUserHandles(void) } } -void VFS_CloseAllUserHandles(void) +void VFS_CloseAllUserHandles(struct sProcess *Process) { - int max_handles = *Threads_GetMaxFD(); + const int max_handles = *Threads_GetMaxFD(Process); + ENTER("pProcess", Process); + if( max_handles >= PAGE_SIZE / sizeof(tVFS_Handle) ) + TODO("More than a page of handles"); + + tVFS_Handle *handles = MM_MapTempFromProc(Process, gaUserHandles); + LOG("handles=%p", handles); // Check if this process has any handles - if( MM_GetPhysAddr( gaUserHandles ) == 0 ) + if( !handles ) { + LEAVE('-'); return ; + } for( int i = 0; i < max_handles; i ++ ) { - tVFS_Handle *h; - h = &gaUserHandles[i]; + tVFS_Handle *h = &handles[i]; + LOG("handles[%i].Node = %p", i, h->Node); if( !h->Node ) continue ; _CloseNode(h->Node); + h->Node = NULL; } + + MM_FreeTemp(handles); + LEAVE('-'); } /** @@ -174,7 +185,7 @@ void VFS_CloseAllUserHandles(void) void *VFS_SaveHandles(int NumFDs, int *FDs) { tVFS_Handle *ret; - int max_handles = *Threads_GetMaxFD(); + const int max_handles = *Threads_GetMaxFD(NULL); // Check if this process has any handles if( MM_GetPhysAddr( gaUserHandles ) == 0 ) @@ -235,11 +246,16 @@ void *VFS_SaveHandles(int NumFDs, int *FDs) void VFS_RestoreHandles(int NumFDs, void *Handles) { tVFS_Handle *handles = Handles; - int max_handles = *Threads_GetMaxFD(); + const int max_handles = *Threads_GetMaxFD(NULL); // NULL = nothing to do if( !Handles ) - return ; + return ; + + if( NumFDs > max_handles ) { + Log_Notice("VFS", "RestoreHandles: Capping from %i FDs to %i", NumFDs, max_handles); + NumFDs = max_handles; + } // Allocate user handle area (and dereference existing handles) for( int i = 0; i < NumFDs; i ++ ) diff --git a/KernelLand/Kernel/vfs/io.c b/KernelLand/Kernel/vfs/io.c index 271e920de7919d49ab8b6964aa597e6799d9a20f..35c1ebf88bec10504cd8fc974da690c3e75f5e4c 100644 --- a/KernelLand/Kernel/vfs/io.c +++ b/KernelLand/Kernel/vfs/io.c @@ -100,16 +100,32 @@ size_t VFS_ReadAt(int FD, Uint64 Offset, size_t Length, void *Buffer) */ size_t VFS_Write(int FD, size_t Length, const void *Buffer) { - tVFS_Handle *h; - size_t ret; - - h = VFS_GetHandle(FD); + tVFS_Handle *h = VFS_GetHandle(FD); if(!h) { LOG("FD%i is not open", FD); errno = EBADF; return -1; } + size_t ret = VFS_WriteAt(FD, h->Position, Length, Buffer); + if(ret == (size_t)-1) return -1; + + if( !(h->Node->Type->Flags & VFS_NODETYPEFLAG_STREAM) ) + h->Position += ret; + return ret; +} + +/** + * \fn Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer) + * \brief Write data to a file at a given offset + */ +size_t VFS_WriteAt(int FD, Uint64 Offset, size_t Length, const void *Buffer) +{ + LOG("FD=%i,Offset=%lli,Length=%i,Buffer=%p", + FD, Offset, Length, Buffer); + tVFS_Handle *h = VFS_GetHandle(FD); + if(!h) return -1; + if( !(h->Mode & VFS_OPENFLAG_WRITE) ) { LOG("FD%i not opened for writing", FD); errno = EBADF; @@ -121,57 +137,63 @@ size_t VFS_Write(int FD, size_t Length, const void *Buffer) return -1; } - if( !h->Node->Type || !h->Node->Type->Write ) { + const tVFS_NodeType* nodetype = h->Node->Type; + if(!nodetype || !nodetype->Write) { LOG("FD%i has no write method", FD); errno = EINTERNAL; return 0; } - - if( !MM_GetPhysAddr(h->Node->Type->Write) ) { + + if( !MM_GetPhysAddr(nodetype->Write) ) { Log_Error("VFS", "Node type %p(%s) write method is junk %p", - h->Node->Type, h->Node->Type->TypeName, - h->Node->Type->Write); + nodetype, nodetype->TypeName, nodetype->Write); errno = EINTERNAL; return -1; } - Uint flags = 0; - flags |= (h->Mode & VFS_OPENFLAG_NONBLOCK) ? VFS_IOFLAG_NOBLOCK : 0; - ret = h->Node->Type->Write(h->Node, h->Position, Length, Buffer, flags); - if(ret != Length) LOG("%i/%i written", ret, Length); - if(ret == (size_t)-1) return -1; - - h->Position += ret; - return ret; -} - -/** - * \fn Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer) - * \brief Write data to a file at a given offset - */ -size_t VFS_WriteAt(int FD, Uint64 Offset, size_t Length, const void *Buffer) -{ - tVFS_Handle *h; - size_t ret; - - h = VFS_GetHandle(FD); - if(!h) return -1; - - if( !(h->Mode & VFS_OPENFLAG_WRITE) ) return -1; - if( h->Node->Flags & VFS_FFLAG_DIRECTORY ) return -1; - - if(!h->Node->Type || !h->Node->Type->Write) return 0; - - if( !MM_GetPhysAddr(h->Node->Type->Write) ) { - Log_Error("VFS", "Node type %p(%s) write method is junk %p", - h->Node->Type, h->Node->Type->TypeName, - h->Node->Type->Write); - return -1; + // Bounds checks + if( h->Node->Size != (Uint64)-1 && Offset > h->Node->Size ) { + Log_Notice("VFS", "Write starting past EOF of FD%x (%lli > %lli)", + FD, Offset, h->Node->Size); + //errno = ESPIPE; + return 0; + } + if( Offset + Length > h->Node->Size ) + { + // Going OOB + if( !nodetype->Truncate ) + { + LOG("No .Truncate method, emiting write past EOF"); + } + else if( nodetype->Flags & VFS_NODETYPEFLAG_NOAUTOEXPAND ) + { + LOG("NOAUTOEXPAND set, truncating length from %i to %i", + Length, h->Node->Size - Offset); + Length = h->Node->Size - Offset; + } + else if( nodetype->Truncate(h->Node, Offset + Length) != Offset + Length ) + { + // oh... fail? Truncate to current size + LOG(".Truncate failed, truncating length from %i to %i", + Length, h->Node->Size - Offset); + Length = h->Node->Size - Offset; + } + else + { + // Expansion, node size should now fit + LOG("Expanded file"); + } } + + // Create flag set Uint flags = 0; flags |= (h->Mode & VFS_OPENFLAG_NONBLOCK) ? VFS_IOFLAG_NOBLOCK : 0; - ret = h->Node->Type->Write(h->Node, Offset, Length, Buffer, flags); + + // Dispatch the read! + size_t ret = nodetype->Write(h->Node, Offset, Length, Buffer, flags); if(ret == (size_t)-1) return -1; + if(ret != Length) LOG("%i/%i written", ret, Length); + return ret; } @@ -198,11 +220,14 @@ Uint64 VFS_Tell(int FD) */ int VFS_Seek(int FD, Sint64 Offset, int Whence) { - tVFS_Handle *h; - - h = VFS_GetHandle(FD); + tVFS_Handle *h = VFS_GetHandle(FD); if(!h) return -1; + if( (h->Node->Type->Flags & VFS_NODETYPEFLAG_STREAM) ) { + LOG("Seeking in stream"); + return -1; + } + // Set relative to current position if(Whence == 0) { LOG("(FD%x)->Position += %lli", FD, Offset); @@ -225,15 +250,34 @@ int VFS_Seek(int FD, Sint64 Offset, int Whence) return 0; } +/* + * Truncate/Expand a file's allocation + */ +off_t VFS_Truncate(int FD, off_t Size) +{ + tVFS_Handle *h = VFS_GetHandle(FD); + if(!h) { + errno = EBADF; + return -1; + } + + if( !h->Node->Type->Truncate) + { + Log_Notice("VFS", "Nodetype '%s' doesn't have a Truncate method", h->Node->Type->TypeName); + errno = ENOTIMPL; + return -1; + } + + return h->Node->Type->Truncate(h->Node, Size); +} + /** * \fn int VFS_IOCtl(int FD, int ID, void *Buffer) * \brief Call an IO Control on a file */ int VFS_IOCtl(int FD, int ID, void *Buffer) { - tVFS_Handle *h; - - h = VFS_GetHandle(FD); + tVFS_Handle *h = VFS_GetHandle(FD); if(!h) { LOG("FD%i is invalid", FD); errno = EINVAL; diff --git a/KernelLand/Kernel/vfs/main.c b/KernelLand/Kernel/vfs/main.c index 0261eca3b9c3598ec913c6c1329a602a085934af..4ed782982d9a401cda595ba43da47f4fa71fd12a 100644 --- a/KernelLand/Kernel/vfs/main.c +++ b/KernelLand/Kernel/vfs/main.c @@ -59,9 +59,10 @@ int VFS_Init(void) VFS_MkDir("/Devices"); VFS_MkDir("/Mount"); VFS_Mount("dev", "/Devices", "devfs", ""); - - Log_Debug("VFS", "Setting max files"); - *Threads_GetMaxFD() = 32; + + // Set default max user file count + // - Applies to PID0, but propagated to all children + *Threads_GetMaxFD(NULL) = 32; return 0; } diff --git a/KernelLand/Kernel/vfs/mmap.c b/KernelLand/Kernel/vfs/mmap.c index b6d5c2d91921425bb8864cb04dd797e91776526a..9016d564bd921f7c3d13090c35e9aaac8d65e349 100644 --- a/KernelLand/Kernel/vfs/mmap.c +++ b/KernelLand/Kernel/vfs/mmap.c @@ -10,6 +10,7 @@ #include <vfs.h> #include <vfs_ext.h> #include <vfs_int.h> +#include <mm_virt.h> // MM_USER_MAX #define MMAP_PAGES_PER_BLOCK 16 @@ -25,31 +26,63 @@ struct sVFS_MMapPageBlock // === PROTOTYPES === //void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, Uint64 Offset); void *VFS_MMap_Anon(void *Destination, size_t Length, Uint FlagsSet, Uint FlagsMask); +int VFS_MMap_MapPage(tVFS_Node *Node, unsigned int PageNum, tVFS_MMapPageBlock *pb, void *mapping_dest, unsigned int Protection); //int VFS_MUnmap(void *Addr, size_t Length); +bool _range_free(const tPage *Base, Uint NumPages); // === CODE === void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, Uint64 Offset) { - tVAddr mapping_base; - int npages, pagenum; - tVFS_MMapPageBlock *pb, *prev; - - ENTER("pDestHint iLength xProtection xFlags xFD XOffset", DestHint, Length, Protection, Flags, FD, Offset); + ENTER("pDestHint xLength xProtection xFlags xFD XOffset", DestHint, Length, Protection, Flags, FD, Offset); if( Flags & MMAP_MAP_ANONYMOUS ) Offset = (tVAddr)DestHint & 0xFFF; - npages = ((Offset & (PAGE_SIZE-1)) + Length + (PAGE_SIZE - 1)) / PAGE_SIZE; - pagenum = Offset / PAGE_SIZE; + unsigned int npages = ((Offset & (PAGE_SIZE-1)) + Length + (PAGE_SIZE - 1)) / PAGE_SIZE; + unsigned int pagenum = Offset / PAGE_SIZE; + LOG("npages=%u,pagenum=%u", npages, pagenum); + + tVAddr mapping_base = (tVAddr)DestHint; - mapping_base = (tVAddr)DestHint; + if( Flags & MMAP_MAP_FIXED ) + { + ASSERT( (Flags & MMAP_MAP_FIXED) && DestHint != NULL ); + // Keep and use the hint + // - TODO: Validate that the region pointed to by the hint is correct + } + else + { + Log_Warning("VFS", "MMap: TODO Handle non-fixed mappings"); + + // Locate a free location in the address space (between brk and MM_USER_MAX) + // TODO: Prefer first location after DestHint, but can go below + + // Search downwards from the top of user memory + mapping_base = 0; + for( tPage *dst = (tPage*)MM_USER_MAX - npages; dst > (tPage*)PAGE_SIZE; dst -- ) + { + if( _range_free(dst, npages) ) { + mapping_base = (tVAddr)dst; + break; + } + } + if( mapping_base == 0 ) + { + Log_Warning("VFS", "MMap: Out of address space"); + errno = ENOMEM; + LEAVE('n'); + return NULL; + } + } tPage *mapping_dest = (void*)(mapping_base & ~(PAGE_SIZE-1)); - if( DestHint == NULL ) + if( !_range_free(mapping_dest, npages) ) { - // TODO: Locate space for the allocation - LEAVE('n'); - return NULL; + LOG("Specified range is not free"); + //errno = EINVAL; + //LEAVE('n'); + //return NULL; + Log_Warning("VFS", "MMap: Overwriting/replacing maps at %p+%x", mapping_base, Length); } // Handle anonymous mappings @@ -67,14 +100,14 @@ void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, Mutex_Acquire( &h->Node->Lock ); + tVFS_MMapPageBlock *pb, **pb_pnp = (tVFS_MMapPageBlock**)&h->Node->MMapInfo; // Search for existing mapping for each page // - Sorted list of 16 page blocks - for( - pb = h->Node->MMapInfo, prev = NULL; - pb && pb->BaseOffset + MMAP_PAGES_PER_BLOCK <= pagenum; - prev = pb, pb = pb->Next - ) - ; + for( pb = h->Node->MMapInfo; pb; pb_pnp = &pb->Next, pb = pb->Next ) + { + if( pb->BaseOffset + MMAP_PAGES_PER_BLOCK > pagenum ) + break; + } LOG("pb = %p, pb->BaseOffset = %X", pb, pb ? pb->BaseOffset : 0); @@ -89,74 +122,22 @@ void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, } pb->Next = old_pb; pb->BaseOffset = pagenum - pagenum % MMAP_PAGES_PER_BLOCK; - if(prev) - prev->Next = pb; - else - h->Node->MMapInfo = pb; + *pb_pnp = pb; } // - Map (and allocate) pages while( npages -- ) { - assert( pagenum >= pb->BaseOffset ); - assert( pagenum - pb->BaseOffset < MMAP_PAGES_PER_BLOCK ); + ASSERTC( pagenum, >=, pb->BaseOffset ); + ASSERTC( pagenum - pb->BaseOffset, <, MMAP_PAGES_PER_BLOCK ); if( MM_GetPhysAddr( mapping_dest ) == 0 ) { - if( pb->PhysAddrs[pagenum - pb->BaseOffset] == 0 ) - { - tVFS_NodeType *nt = h->Node->Type; - if( !nt ) - { - // TODO: error - } - else if( nt->MMap ) - nt->MMap(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, mapping_dest); - else - { - int read_len; - // Allocate pages and read data - if( MM_Allocate(mapping_dest) == 0 ) { - // TODO: Unwrap - Mutex_Release( &h->Node->Lock ); - LEAVE('n'); - return NULL; - } - // TODO: Clip read length - read_len = nt->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, - mapping_dest, 0); - // TODO: This was commented out, why? - if( read_len != PAGE_SIZE ) { - memset( (char*)mapping_dest + read_len, 0, PAGE_SIZE-read_len ); - } - } - pb->PhysAddrs[pagenum - pb->BaseOffset] = MM_GetPhysAddr( mapping_dest ); - MM_SetPageNode( pb->PhysAddrs[pagenum - pb->BaseOffset], h->Node ); - MM_RefPhys( pb->PhysAddrs[pagenum - pb->BaseOffset] ); - LOG("Read and map %X to %p (%P)", pagenum*PAGE_SIZE, mapping_dest, - pb->PhysAddrs[pagenum - pb->BaseOffset]); - } - else + LOG("Map page to %p", mapping_dest); + if( VFS_MMap_MapPage(h->Node, pagenum, pb, mapping_dest, Protection) ) { - MM_Map( mapping_dest, pb->PhysAddrs[pagenum - pb->BaseOffset] ); - MM_RefPhys( pb->PhysAddrs[pagenum - pb->BaseOffset] ); - LOG("Cached map %X to %p (%P)", pagenum*PAGE_SIZE, mapping_dest, - pb->PhysAddrs[pagenum - pb->BaseOffset]); - } - h->Node->ReferenceCount ++; - - // Set flags - if( !(Protection & MMAP_PROT_WRITE) ) { - MM_SetFlags(mapping_dest, MM_PFLAG_RO, MM_PFLAG_RO); - } - else { - MM_SetFlags(mapping_dest, 0, MM_PFLAG_RO); - } - - if( Protection & MMAP_PROT_EXEC ) { - MM_SetFlags(mapping_dest, MM_PFLAG_EXEC, MM_PFLAG_EXEC); - } - else { - MM_SetFlags(mapping_dest, 0, MM_PFLAG_EXEC); + Mutex_Release( &h->Node->Lock ); + LEAVE('n'); + return NULL; } } else @@ -167,25 +148,27 @@ void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, MM_SetFlags(mapping_dest, 0, MM_PFLAG_RO); } } - if( Flags & MMAP_MAP_PRIVATE ) + if( Flags & MMAP_MAP_PRIVATE ) { + // TODO: Don't allow the page to change underneath either MM_SetFlags(mapping_dest, MM_PFLAG_COW, MM_PFLAG_COW); + } pagenum ++; mapping_dest ++; // Roll on to next block if needed if(pagenum - pb->BaseOffset == MMAP_PAGES_PER_BLOCK) { - if( pb->Next && pb->Next->BaseOffset == pagenum ) - pb = pb->Next; - else + if( !pb->Next || pb->Next->BaseOffset != pagenum ) { - tVFS_MMapPageBlock *oldpb = pb; - pb = malloc( sizeof(tVFS_MMapPageBlock) ); - pb->Next = oldpb->Next; - pb->BaseOffset = pagenum; - memset(pb->PhysAddrs, 0, sizeof(pb->PhysAddrs)); - oldpb->Next = pb; + if( pb->Next ) ASSERTC(pb->Next->BaseOffset % MMAP_PAGES_PER_BLOCK, ==, 0); + tVFS_MMapPageBlock *newpb = malloc( sizeof(tVFS_MMapPageBlock) ); + newpb->Next = pb->Next; + newpb->BaseOffset = pagenum; + memset(newpb->PhysAddrs, 0, sizeof(newpb->PhysAddrs)); + pb->Next = newpb; } + + pb = pb->Next; } } @@ -263,7 +246,81 @@ void *VFS_MMap_Anon(void *Destination, size_t Length, Uint FlagsSet, Uint FlagsM return Destination; } +int VFS_MMap_MapPage(tVFS_Node *Node, unsigned int pagenum, tVFS_MMapPageBlock *pb, void *mapping_dest, unsigned int Protection) +{ + if( pb->PhysAddrs[pagenum - pb->BaseOffset] != 0 ) + { + MM_Map( mapping_dest, pb->PhysAddrs[pagenum - pb->BaseOffset] ); + MM_RefPhys( pb->PhysAddrs[pagenum - pb->BaseOffset] ); + LOG("Cached map %X to %p (%P)", pagenum*PAGE_SIZE, mapping_dest, + pb->PhysAddrs[pagenum - pb->BaseOffset]); + } + else + { + tVFS_NodeType *nt = Node->Type; + if( !nt ) + { + // TODO: error + } + else if( nt->MMap ) + nt->MMap(Node, pagenum*PAGE_SIZE, PAGE_SIZE, mapping_dest); + else + { + int read_len; + // Allocate pages and read data + if( MM_Allocate(mapping_dest) == 0 ) { + // TODO: Unwrap + return 1; + } + // TODO: Clip read length + read_len = nt->Read(Node, pagenum*PAGE_SIZE, PAGE_SIZE, mapping_dest, 0); + // TODO: This was commented out, why? + if( read_len != PAGE_SIZE ) { + memset( (char*)mapping_dest + read_len, 0, PAGE_SIZE-read_len ); + } + } + pb->PhysAddrs[pagenum - pb->BaseOffset] = MM_GetPhysAddr( mapping_dest ); + MM_SetPageNode( pb->PhysAddrs[pagenum - pb->BaseOffset], Node ); + MM_RefPhys( pb->PhysAddrs[pagenum - pb->BaseOffset] ); + LOG("Read and map %X to %p (%P)", pagenum*PAGE_SIZE, mapping_dest, + pb->PhysAddrs[pagenum - pb->BaseOffset]); + } + // TODO: Huh? + Node->ReferenceCount ++; + + // Set flags + if( !(Protection & MMAP_PROT_WRITE) ) { + MM_SetFlags(mapping_dest, MM_PFLAG_RO, MM_PFLAG_RO); + } + else { + MM_SetFlags(mapping_dest, 0, MM_PFLAG_RO); + } + + if( Protection & MMAP_PROT_EXEC ) { + MM_SetFlags(mapping_dest, MM_PFLAG_EXEC, MM_PFLAG_EXEC); + } + else { + MM_SetFlags(mapping_dest, 0, MM_PFLAG_EXEC); + } + + return 0; +} + int VFS_MUnmap(void *Addr, size_t Length) { + UNIMPLEMENTED(); return 0; } + +bool _range_free(const tPage *Base, Uint NumPages) +{ + for( int i = 0; i < NumPages; i ++ ) + { + if( MM_GetPhysAddr(Base + i) ) + { + // Oh. + return false; + } + } + return true; +} diff --git a/KernelLand/Kernel/vfs/open.c b/KernelLand/Kernel/vfs/open.c index f0b5734a4ec13696d5e590b64314c0842e090fd8..e5a206fbe3a6376dcc8bb00500cd0c7c8dcf2232 100644 --- a/KernelLand/Kernel/vfs/open.c +++ b/KernelLand/Kernel/vfs/open.c @@ -15,16 +15,29 @@ #define MAX_PATH_SLASHES 256 #define MAX_NESTED_LINKS 4 #define MAX_PATH_LEN 255 +#define MAX_MARSHALLED_HANDLES 16 // Max outstanding // === IMPORTS === extern tVFS_Mount *gVFS_RootMount; extern tVFS_Node *VFS_MemFile_Create(const char *Path); +// === TYPES === +typedef struct sVFS_MarshaledHandle +{ + Uint32 Magic; + tTime AllocTime; + tVFS_Handle Handle; +} tVFS_MarshalledHandle; + // === PROTOTYPES === void _ReferenceMount(tVFS_Mount *Mount, const char *DebugTag); void _DereferenceMount(tVFS_Mount *Mount, const char *DebugTag); int VFS_int_CreateHandle(tVFS_Node *Node, tVFS_Mount *Mount, int Mode); +// === GLOBALS === +tMutex glVFS_MarshalledHandles; +tVFS_MarshalledHandle gaVFS_MarshalledHandles[MAX_MARSHALLED_HANDLES]; + // === CODE === void _ReferenceMount(tVFS_Mount *Mount, const char *DebugTag) { @@ -49,9 +62,9 @@ char *VFS_GetAbsPath(const char *Path) char *tmpStr; int iPos = 0; int iPos2 = 0; - const char *chroot = *Threads_GetChroot(); + const char *chroot = *Threads_GetChroot(NULL); int chrootLen; - const char *cwd = *Threads_GetCWD(); + const char *cwd = *Threads_GetCWD(NULL); int cwdLen; ENTER("sPath", Path); @@ -343,7 +356,7 @@ restart_parse: } if(iNestedLinks > MAX_NESTED_LINKS) { - Log_Notice("VFS", "VFS_ParsePath - Nested link limit exceeded"); + Log_Notice("VFS", "VFS_ParsePath - Nested link limit exceeded on '%.*s'", ofs, Path); errno = ENOENT; goto _error; } @@ -378,7 +391,8 @@ restart_parse: // Handle Non-Directories if( !(curNode->Flags & VFS_FFLAG_DIRECTORY) ) { - Log_Warning("VFS", "VFS_ParsePath - Path segment is not a directory"); + Log_Warning("VFS", "VFS_ParsePath - Path segment '%.*s' is not a directory (curNode{%p}->Flags = 0x%x)", + ofs+nextSlash, Path, curNode, curNode->Flags); errno = ENOTDIR; goto _error; } @@ -407,7 +421,7 @@ restart_parse: // Check final finddir call if( !curNode->Type || !curNode->Type->FindDir ) { - Log_Warning("VFS", "VFS_ParsePath - FindDir doesn't exist for element of '%s'", Path); + Log_Warning("VFS", "VFS_ParsePath - FindDir doesn't exist for leaf of '%s' (dir '%.*s')", Path, ofs, Path); errno = ENOENT; goto _error; } @@ -733,6 +747,7 @@ int VFS_Reopen(int FD, const char *Path, int Flags) int newf = VFS_Open(Path, Flags); if( newf == -1 ) { + // errno = set by VFS_Open return -1; } @@ -759,11 +774,13 @@ void VFS_Close(int FD) h = VFS_GetHandle(FD); if(h == NULL) { Log_Warning("VFS", "Invalid file handle passed to VFS_Close, 0x%x", FD); + errno = EINVAL; return; } if( h->Node == NULL ) { Log_Warning("VFS", "Non-open handle passed to VFS_Close, 0x%x", FD); + errno = EINVAL; return ; } @@ -771,6 +788,7 @@ void VFS_Close(int FD) if(h->Node->Close && !MM_GetPhysAddr(h->Node->Close)) { Log_Warning("VFS", "Node %p's ->Close method is invalid (%p)", h->Node, h->Node->Close); + errno = EINTERNAL; return ; } #endif @@ -858,7 +876,7 @@ int VFS_ChDir(const char *Dest) VFS_Close(fd); { - char **cwdptr = Threads_GetCWD(); + char **cwdptr = Threads_GetCWD(NULL); // Free old working directory if( *cwdptr ) free( *cwdptr ); // Set new @@ -910,7 +928,7 @@ int VFS_ChRoot(const char *New) // Update { - char **chroot_ptr = Threads_GetChroot(); + char **chroot_ptr = Threads_GetChroot(NULL); if( *chroot_ptr ) free( *chroot_ptr ); *chroot_ptr = buf; } @@ -920,6 +938,96 @@ int VFS_ChRoot(const char *New) return 1; } +/* + * Marshal a handle so that it can be transferred between processes + */ +Uint64 VFS_MarshalHandle(int FD) +{ + tVFS_Handle *h = VFS_GetHandle(FD); + if(!h || !h->Node) { + errno = EBADF; + return -1; + } + + // Allocate marshal location + int ret = -1; + Mutex_Acquire(&glVFS_MarshalledHandles); + for( int i = 0; i < MAX_MARSHALLED_HANDLES; i ++ ) + { + tVFS_MarshalledHandle* mh = &gaVFS_MarshalledHandles[i]; + if( mh->Handle.Node == NULL ) { + mh->Handle.Node = h->Node; + mh->AllocTime = now(); + ret = i; + } + if( now() - mh->AllocTime > 2000 ) { + Log_Notice("VFS", "TODO: Expire marshalled handle"); + } + } + Mutex_Release(&glVFS_MarshalledHandles); + if( ret < 0 ) { + // TODO: Need to clean up lost handles to avoid DOS + Log_Warning("VFS", "Out of marshaled handle slots"); + errno = EAGAIN; + return -1; + } + + // Populate + tVFS_MarshalledHandle* mh = &gaVFS_MarshalledHandles[ret]; + mh->Handle = *h; + _ReferenceMount(h->Mount, "MarshalHandle"); + _ReferenceNode(h->Node); + mh->Magic = rand(); + + return (Uint64)mh->Magic << 32 | ret; +} + +/* + * Un-marshal a handle into the current process + * NOTE: Does not support unmarshalling into kernel handle list + */ +int VFS_UnmarshalHandle(Uint64 Handle) +{ + Uint32 magic = Handle >> 32; + int id = Handle & 0xFFFFFFFF; + + // Range check + if( id >= MAX_MARSHALLED_HANDLES ) { + LOG("ID too high (%i > %i)", id, MAX_MARSHALLED_HANDLES); + errno = EINVAL; + return -1; + } + + + // Check validity + tVFS_MarshalledHandle *mh = &gaVFS_MarshalledHandles[id]; + if( mh->Handle.Node == NULL ) { + LOG("Target node is NULL"); + errno = EINVAL; + return -1; + } + if( mh->Magic != magic ) { + LOG("Magic mismatch (0x%08x != 0x%08x)", magic, mh->Magic); + errno = EACCES; + return -1; + } + + Mutex_Acquire(&glVFS_MarshalledHandles); + // - Create destination handle + int ret = VFS_AllocHandle(true, mh->Handle.Node, mh->Handle.Mode); + // - Clear allocation + mh->Handle.Node = NULL; + Mutex_Release(&glVFS_MarshalledHandles); + if( ret == -1 ) { + errno = ENFILE; + return -1; + } + + // No need to reference node/mount, new handle takes marshalled reference + + return ret; +} + // === EXPORTS === EXPORT(VFS_Open); EXPORT(VFS_Close); diff --git a/KernelLand/Kernel/vfs/select.c b/KernelLand/Kernel/vfs/select.c index 660bca89611731009e210aa53f59500b4d80efa4..a18b91c58dce0fe1a65d7b376f969ca201426403 100644 --- a/KernelLand/Kernel/vfs/select.c +++ b/KernelLand/Kernel/vfs/select.c @@ -55,13 +55,14 @@ void VFS_int_Select_SignalAll(tVFS_SelectList *List); // === FUNCTIONS === int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *Name) { - tThread *thisthread = Proc_GetCurThread(); - int ret, type; + tThread * const thisthread = Proc_GetCurThread(); + int ret; ENTER("pNode iTypeFlags pTimeout sName", Node, TypeFlags, Timeout, Name); // Initialise - for( type = 0; type < 3; type ++ ) + ret = 0; + for( int type = 0; type < 3; type ++ ) { tVFS_SelectList **list; int *flag, wanted, maxAllowed; @@ -77,17 +78,19 @@ int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *N VFS_int_Select_AddThread(*list, thisthread, maxAllowed); if( *flag == wanted ) { - VFS_int_Select_RemThread(*list, thisthread); - LEAVE('i', 1); - return 1; + ret |= (1 << type); } } // Wait for things - if( !Timeout ) + if( ret ) + { + // Skip wait, conditions already met + LOG("ret = %i, skipping wait", ret); + } + else if( !Timeout ) { LOG("Semaphore_Wait()"); - // TODO: Actual timeout Threads_WaitEvents( THREAD_EVENT_VFS|THREAD_EVENT_SIGNAL ); } else if( *Timeout > 0 ) @@ -95,7 +98,6 @@ int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *N tTimer *t = Time_AllocateTimer(NULL, NULL); // Clear timer event Threads_ClearEvent( THREAD_EVENT_TIMER ); - // TODO: Convert *Timeout? LOG("Timeout %lli ms", *Timeout); Time_ScheduleTimer( t, *Timeout ); // Wait for the timer or a VFS event @@ -105,13 +107,13 @@ int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *N // Get return value ret = 0; - for( type = 0; type < 3; type ++ ) + for( int type = 0; type < 3; type ++ ) { tVFS_SelectList **list; int *flag, wanted, maxAllowed; if( !(TypeFlags & (1 << type)) ) continue; VFS_int_Select_GetType(type, Node, &list, &flag, &wanted, &maxAllowed); - LOG("VFS_int_Select_RemThread()"); + LOG("VFS_int_Select_RemThread() for %i", type); ASSERT(*list); VFS_int_Select_RemThread(*list, thisthread); ret = ret || *flag == wanted; diff --git a/KernelLand/Modules/Display/BochsGA/bochsvbe.c b/KernelLand/Modules/Display/BochsGA/bochsvbe.c index a6338ae10f9ec03ecc72c81185e465e3a91d4247..7674ed9559dd4026d1eb83f437ffaa3a93a16f4c 100644 --- a/KernelLand/Modules/Display/BochsGA/bochsvbe.c +++ b/KernelLand/Modules/Display/BochsGA/bochsvbe.c @@ -118,8 +118,15 @@ int BGA_Install(char **Arguments) dev = PCI_GetDevice(0x1234, 0x1111, 0); if(dev == -1) base = VBE_DISPI_LFB_PHYSICAL_ADDRESS; - else - base = PCI_GetBAR(dev, 0); + else { + Log_Debug("BGA", "BARs %x,%x,%x,%x,%x,%x", + PCI_GetBAR(dev, 0), PCI_GetBAR(dev, 1), PCI_GetBAR(dev, 2), + PCI_GetBAR(dev, 3), PCI_GetBAR(dev, 4), PCI_GetBAR(dev, 5)); + base = PCI_GetValidBAR(dev, 0, PCI_BARTYPE_MEM); + // TODO: Qemu/bochs have MMIO versions of the registers in BAR2 + // - This range is non-indexed + //mmio_base = PCI_GetValidBAR(dev, 2, PCI_BARTYPE_MEM); + } // Map Framebuffer to hardware address gBGA_Framebuffer = (void *) MM_MapHWPages(base, 768); // 768 pages (3Mb) diff --git a/KernelLand/Modules/Display/Tegra2Vid/main.c b/KernelLand/Modules/Display/Tegra2Vid/main.c index 9ca70984cd031a401558f457b244eda592e84146..a249fd8dc51f683a9ecb9bf171e993a5155ea269 100644 --- a/KernelLand/Modules/Display/Tegra2Vid/main.c +++ b/KernelLand/Modules/Display/Tegra2Vid/main.c @@ -196,7 +196,7 @@ int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data) switch(ID) { - BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls); + BASE_IOCTLS(DRV_TYPE_VIDEO, "Tegra2", VERSION, csaTegra2Vid_IOCtls); case VIDEO_IOCTL_SETBUFFORMAT: DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo ); diff --git a/KernelLand/Modules/Display/VESA/main.c b/KernelLand/Modules/Display/VESA/main.c index 32022efa6b7caaaea79ebda5218c33b9ddfb0877..62fb25a2ea82438f428d8b159b251f674b00602b 100644 --- a/KernelLand/Modules/Display/VESA/main.c +++ b/KernelLand/Modules/Display/VESA/main.c @@ -16,7 +16,11 @@ #include <limits.h> // === CONSTANTS === -#define USE_BIOS 1 +#ifdef ARCHDIR_is_x86 +# define USE_BIOS 1 +#else +# define USE_BIOS 0 +#endif #define VESA_DEFAULT_FRAMEBUFFER (KERNEL_BASE|0xA0000) #define BLINKING_CURSOR 0 #if BLINKING_CURSOR @@ -33,6 +37,7 @@ size_t Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buff int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data); void Vesa_int_HideCursor(void); void Vesa_int_ShowCursor(void); + int Vesa_int_SetCursor(tVideo_IOCtl_Bitmap *Cursor); void Vesa_FlipCursor(void *Arg); Uint16 VBE_int_GetWord(const tVT_Char *Char); void VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour); @@ -124,6 +129,10 @@ int VBE_int_GetModeList(void) // Allocate Info Block info = VM8086_Allocate(gpVesa_BiosState, 512, &infoPtr.seg, &infoPtr.ofs); + if( info == NULL ) { + Log_Warning("VBE", "VM8086 allocation error"); + return MODULE_ERR_NOTNEEDED; + } // Set Requested Version memcpy(info->signature, "VBE2", 4); // Set Registers @@ -361,13 +370,16 @@ int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data) case VIDEO_IOCTL_SETBUFFORMAT: Vesa_int_HideCursor(); ret = gVesa_BufInfo.BufferFormat; - if(Data) gVesa_BufInfo.BufferFormat = *(int*)Data; + if(Data) + gVesa_BufInfo.BufferFormat = *(int*)Data; if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT) - DrvUtil_Video_SetCursor( &gVesa_BufInfo, &gDrvUtil_TextModeCursor ); + Vesa_int_SetCursor(&gDrvUtil_TextModeCursor); Vesa_int_ShowCursor(); return ret; case VIDEO_IOCTL_SETCURSOR: // Set cursor position + if( !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) ) + return -EINVAL; Vesa_int_HideCursor(); giVesaCursorX = ((tVideo_IOCtl_Pos*)Data)->x; giVesaCursorY = ((tVideo_IOCtl_Pos*)Data)->y; @@ -375,9 +387,7 @@ int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data) return 0; case VIDEO_IOCTL_SETCURSORBITMAP: - if( gpVesaCurMode->flags & FLAG_LFB ) - DrvUtil_Video_SetCursor( &gVesa_BufInfo, Data ); - return 0; + return Vesa_int_SetCursor(Data); } return 0; } @@ -451,9 +461,9 @@ int Vesa_Int_SetMode(int mode) Mutex_Release( &glVesa_Lock ); - // TODO: Disableable backbuffer - gVesa_BufInfo.BackBuffer = realloc(gVesa_BufInfo.BackBuffer, - modeptr->height * modeptr->pitch); + // TODO: Allow disabling of back-buffer + gVesa_DriverStruct.RootNode.Size = modeptr->height * modeptr->pitch; + gVesa_BufInfo.BackBuffer = realloc(gVesa_BufInfo.BackBuffer, modeptr->height * modeptr->pitch); gVesa_BufInfo.Framebuffer = gpVesa_Framebuffer; gVesa_BufInfo.Pitch = modeptr->pitch; gVesa_BufInfo.Width = modeptr->width; @@ -607,6 +617,21 @@ void Vesa_int_ShowCursor(void) } } +int Vesa_int_SetCursor(tVideo_IOCtl_Bitmap *Cursor) +{ + if( !CheckMem(Cursor, sizeof(tVideo_IOCtl_Bitmap)) ) + return -EINVAL; + + if( gpVesaCurMode && gpVesaCurMode->flags & FLAG_LFB ) + { + DrvUtil_Video_SetCursor( &gVesa_BufInfo, Cursor ); + } + else + { + } + return 0; +} + /** * \brief Swaps the text cursor on/off */ diff --git a/KernelLand/Modules/Display/VGA/vgaregs.c b/KernelLand/Modules/Display/VGA/vgaregs.c new file mode 100644 index 0000000000000000000000000000000000000000..fa1bc8401192236369617e18c7467b67fe3a8c88 --- /dev/null +++ b/KernelLand/Modules/Display/VGA/vgaregs.c @@ -0,0 +1,81 @@ +/* + * Acess2 VGA Driver + * - By John Hodge (thePowersGang) + */ + +#define VGA_CRTC_IDX 0x3B4 +#define VGA_CRTC_DATA 0x3B5 +#define VGA_FEAT_IS1 0x3BA // Features / Input Status 1 (B/W Chips) +#define VGA_ATTR_WRITE 0x3C0 +#define VGA_ATTR_READ 0x3C1 +#define VGA_MISC_IS0 0x3C2 // Misc Output / Input Status 0 +#define VGA_MBSLEEP 0x3C3 // "Motherboard Sleep" +#define VGA_SEQ_IDX 0x3C4 +#define VGA_SEQ_DATA 0x3C5 +#define VGA_DACMASK 0x3C6 +#define VGA_PADR_DACST 0x3C7 +#define VGA_PIXWRMODE 0x3C8 +#define VGA_PIXDATA 0x3C9 +#define VGA_FEATRD 0x3CA +// 0x3CB +#define VGA_MISCOUT 0x3CC +// 0x3CD +#define VGA_GRAPH_IDX 0x3CE +#define VGA_GRAPH_DATA 0x3CF +// 0x3D0 -- 0x3D3 +#define VGA_CRTC_IDX 0x3D4 +#define VGA_CRTC_DATA 0x3D5 +// 0x3D6 -- 0x3D9 +#define VGA_FEAT_IS1_C 0x3DA // Features / Input Status 1 (Colour Chips) + +// === CODE === +void VGA_WriteAttr(Uint8 Index, Uint8 Data) +{ + Index &= 0x1F; + SHORTLOCK(&glVGA_Attr); + inb(0x3DA); + outb(VGA_ATTR_WRITE, Index); + outb(VGA_ATTR_WRITE, Data); + SHORTREL(&glVGA_Attr); +} + +Uint8 VGA_ReadAttr(Uint8 Index) +{ + Uint8 ret; + SHORTLOCK(&glVGA_Attr); + inb(0x3DA); + outb(VGA_ATTR_WRITE, Index); + ret = inb(VGA_ATTR_READ); + SHORTREL(&glVGA_Attr); + return ret; +} + +void VGA_WriteSeq(Uint8 Index, Uint8 Data) +{ + outb(VGA_SEQ_IDX, Index); + outb(VGA_SEQ_DATA, Data); +} +Uint8 VGA_ReadSeq(Uint8 Index) +{ + outb(VGA_SEQ_IDX, Index); + return inb(VGA_SEQ_DATA); +} +void VGA_WriteGraph(Uint8 Index, Uint8 Data) +{ + outb(VGA_GRAPH_IDX, Index); + outb(VGA_GRAPH_DATA, Data); +} +Uint8 VGA_ReadGraph(Uint8 Index) +{ + outb(VGA_GRAPH_IDX, Index); + return inb(VGA_GRAPH_DATA); +} + +void VGA_WriteMiscOut(Uint8 Data) +{ + outb(VGA_MISC_IS0, Data); +} +Uint8 VGA_ReadMiscOut(void) +{ + return inb(VGA_MISCOUT); +} diff --git a/KernelLand/Modules/Filesystems/InitRD/GenerateInitRD.php b/KernelLand/Modules/Filesystems/InitRD/GenerateInitRD.php index 5034b4bafabaf7f6cb984d6420f071e3d0a87aad..52377e6fed5179eec5558f67ce8f3e45e61e4fef 100644 --- a/KernelLand/Modules/Filesystems/InitRD/GenerateInitRD.php +++ b/KernelLand/Modules/Filesystems/InitRD/GenerateInitRD.php @@ -12,6 +12,8 @@ $gOutput = <<<EOF EOF; +define("DEBUG_ENABLED", false); + $ACESSDIR = getenv("ACESSDIR"); $ARCH = getenv("ARCH"); @@ -143,7 +145,8 @@ EOF; { $path = $item[1]; - echo $path,"\n"; + if( DEBUG_ENABLED ) + echo $path,"\n"; $size = filesize($path); $_sym = "_binary_".str_replace(array("/","-",".","+"), "_", $path)."_start"; diff --git a/KernelLand/Modules/Filesystems/InitRD/files.lst b/KernelLand/Modules/Filesystems/InitRD/files.lst index efae3be159293d84abdead8e2f801fd4aa318a3b..bac8284079a8ccdfd2ced0c87165ee1d2fc99fad 100644 --- a/KernelLand/Modules/Filesystems/InitRD/files.lst +++ b/KernelLand/Modules/Filesystems/InitRD/files.lst @@ -35,6 +35,7 @@ Dir "Libs" { File "__BIN__/Libs/liburi.so" File "__BIN__/Libs/libimage_sif.so" File "__BIN__/Libs/libaxwin3.so" + File "__BIN__/Libs/libaxwin4.so" File "__BIN__/Libs/libposix.so" File "__BIN__/Libs/libpsocket.so" File "__BIN__/Libs/libunicode.so" @@ -61,6 +62,10 @@ Dir "Apps" { File "toolbar_open.sif" "__SRC__/Usermode/Applications/axwin3_src/WM/resources/.toolbar_open.sif" File "toolbar_save.sif" "__SRC__/Usermode/Applications/axwin3_src/WM/resources/.toolbar_save.sif" } + Dir "4.0" { + File "__BIN__/Apps/AxWin/4.0/AxWinServer" + File "__BIN__/Apps/AxWin/4.0/AxWinUI" + } } } #Dir "Keen5" { diff --git a/KernelLand/Modules/IPStack/icmp.c b/KernelLand/Modules/IPStack/icmp.c index fa9927ee1adba1af8de758e15bb3df32d2335c4a..f34d790fd01751a1616f91c11857ba203de07298 100644 --- a/KernelLand/Modules/IPStack/icmp.c +++ b/KernelLand/Modules/IPStack/icmp.c @@ -26,7 +26,7 @@ struct { */ void ICMP_Initialise() { - IPv4_RegisterCallback(IP4PROT_ICMP, ICMP_GetPacket); + IPv4_RegisterCallback(IP4PROT_ICMP, ICMP_GetPacket, NULL); } /** @@ -64,12 +64,15 @@ void ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buff { case 3: // Port Unreachable Log_Debug("ICMPv4", "Destination Unreachable (Port Unreachable)"); + IPv4_HandleError( Interface, IPERR_PORT_UNREACHABLE, + htons(Length)-sizeof(tICMPHeader), hdr->Data ); break; default: Log_Debug("ICMPv4", "Destination Unreachable (Code %i)", hdr->Code); + IPv4_HandleError( Interface, IPERR_MISC, + htons(Length)-sizeof(tICMPHeader), hdr->Data ); break; } -// IPv4_Unreachable( Interface, hdr->Code, htons(hdr->Length)-sizeof(tICMPHeader), hdr->Data ); break; // -- 8: Echo Request diff --git a/KernelLand/Modules/IPStack/icmpv6.h b/KernelLand/Modules/IPStack/icmpv6.h index bda70b13003c00a77c93ff2bc506423fe64d8750..66f61341f175773cd25255822cfe346a430881b7 100644 --- a/KernelLand/Modules/IPStack/icmpv6.h +++ b/KernelLand/Modules/IPStack/icmpv6.h @@ -26,32 +26,32 @@ typedef struct { Uint16 RouterLifetime; // Seconds, life time as a default router (wtf does that mean?) Uint32 ReachableTime; Uint32 RetransTimer; // Miliseconds, time between transmissions of RAs from this router - Uint8 Options[]; + Uint8 Options[0]; } PACKED tICMPv6_RA; typedef struct { Uint32 Reserved; tIPv6 TargetAddress; - Uint8 Options[]; + Uint8 Options[0]; } PACKED tICMPv6_NS; typedef struct { Uint32 Flags; tIPv6 TargetAddress; - Uint8 Options[]; + Uint8 Options[0]; } PACKED tICMPv6_NA; typedef struct { Uint32 Reserved; tIPv6 TargetAddress; tIPv6 DestinationAddress; - Uint8 Options[]; + Uint8 Options[0]; } PACKED tICMPv6_Redirect; typedef struct { Uint8 Type; // 1,2 Uint8 Length; // Length of field in units of 8 bytes (incl header), typically 1 - Uint8 Address[]; + Uint8 Address[0]; } PACKED tICMPv6_Opt_LinkAddr; typedef struct { @@ -62,7 +62,7 @@ typedef struct { Uint32 ValidLifetime; Uint32 PreferredLifetime; Uint32 _reserved2; - tIPv6 Prefix[]; + tIPv6 Prefix[0]; } PACKED tICMPv6_Opt_Prefix; typedef struct { @@ -70,7 +70,7 @@ typedef struct { Uint8 Length; Uint16 _rsvd1; Uint32 _rsvd2; - Uint8 Data[]; // All or part of the redirected message (not exceeding MTU) + Uint8 Data[0]; // All or part of the redirected message (not exceeding MTU) } PACKED tICMPv6_Opt_Redirect; typedef struct { diff --git a/KernelLand/Modules/IPStack/ipstack.h b/KernelLand/Modules/IPStack/ipstack.h index ddcdde9649ea22810e8a2a273809fc32281c5ddf..3833ce7b0d6c2ed345765f511a6678f2d6529383 100644 --- a/KernelLand/Modules/IPStack/ipstack.h +++ b/KernelLand/Modules/IPStack/ipstack.h @@ -15,7 +15,16 @@ typedef struct sAdapter tAdapter; typedef struct sInterface tInterface; typedef struct sSocketFile tSocketFile; -typedef void (*tIPCallback)(tInterface *Interface, void *Address, int Length, void *Buffer); +typedef enum eIPErrorMode +{ + IPERR_MISC, + IPERR_HOST_UNREACHABLE, + IPERR_PORT_UNREACHABLE, +} tIPErrorMode; + +// NOTE: Non-const to allow reuse of Rx buffer for prepping Tx +typedef void tIPRxCallback(tInterface *Interface, void *Address, int Length, void *Buffer); +typedef void tIPErrorCallback(tInterface *Interface, tIPErrorMode mode, const void *Address, int Length, const void *Buffer); enum eInterfaceTypes { AF_NULL, diff --git a/KernelLand/Modules/IPStack/ipv4.c b/KernelLand/Modules/IPStack/ipv4.c index 000fe3966381c15393074d029408a5326ce31e30..371fe4026f224502521daa03df9bc91e388c42bc 100644 --- a/KernelLand/Modules/IPStack/ipv4.c +++ b/KernelLand/Modules/IPStack/ipv4.c @@ -20,7 +20,7 @@ extern int ICMP_Ping(tInterface *Interface, tIPv4 Addr); // === PROTOTYPES === int IPv4_Initialise(); - int IPv4_RegisterCallback(int ID, tIPCallback Callback); +// int IPv4_RegisterCallback(int ID, tIPRxCallback Callback, ); void IPv4_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer); tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast); Uint32 IPv4_Netmask(int FixedBits); @@ -28,7 +28,10 @@ Uint16 IPv4_Checksum(const void *Buf, size_t Length); int IPv4_Ping(tInterface *Iface, tIPv4 Addr); // === GLOBALS === -tIPCallback gaIPv4_Callbacks[256]; +struct { + tIPRxCallback* rx_cb; + tIPErrorCallback* err_cb; +} gaIPv4_Callbacks[256]; // === CODE === /** @@ -46,11 +49,12 @@ int IPv4_Initialise() * \param ID 8-bit packet type ID * \param Callback Callback function */ -int IPv4_RegisterCallback(int ID, tIPCallback Callback) +int IPv4_RegisterCallback(int ID, tIPRxCallback *RxCallback, tIPErrorCallback *ErrCallback) { if( ID < 0 || ID > 255 ) return 0; - if( gaIPv4_Callbacks[ID] ) return 0; - gaIPv4_Callbacks[ID] = Callback; + if( gaIPv4_Callbacks[ID].rx_cb ) return 0; + gaIPv4_Callbacks[ID].rx_cb = RxCallback; + gaIPv4_Callbacks[ID].err_cb = ErrCallback; return 1; } @@ -66,14 +70,12 @@ int IPv4_RegisterCallback(int ID, tIPCallback Callback) */ int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, tIPStackBuffer *Buffer) { - tMacAddr to; tIPv4Header hdr; - int length; - length = IPStack_Buffer_GetLength(Buffer); + int length = IPStack_Buffer_GetLength(Buffer); // --- Resolve destination MAC address - to = HWCache_Resolve(Iface, &Address); + tMacAddr to = HWCache_Resolve(Iface, &Address); if( MAC_EQU(to, cMAC_ZERO) ) { // No route to host Log_Notice("IPv4", "No route to host %i.%i.%i.%i", @@ -134,7 +136,6 @@ int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, tIPS void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer) { tIPv4Header *hdr = Buffer; - tInterface *iface; Uint8 *data; int dataLength; int ret; @@ -197,7 +198,7 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff data = &hdr->Options[0]; // Get Interface (allowing broadcasts) - iface = IPv4_GetInterface(Adapter, hdr->Destination, 1); + tInterface *iface = IPv4_GetInterface(Adapter, hdr->Destination, 1); // Firewall rules if( iface ) { @@ -255,12 +256,29 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff } // Send it on - if( !gaIPv4_Callbacks[hdr->Protocol] ) { + if( !gaIPv4_Callbacks[hdr->Protocol].rx_cb ) { Log_Log("IPv4", "Unknown Protocol %i", hdr->Protocol); return ; } - gaIPv4_Callbacks[hdr->Protocol]( iface, &hdr->Source, dataLength, data ); + gaIPv4_Callbacks[hdr->Protocol].rx_cb( iface, &hdr->Source, dataLength, data ); +} + +/* + * Handles an error from the ICMPv4 code, 'Buf' contains part of an IPv4 packet + */ +void IPv4_HandleError(tInterface *Iface, tIPErrorMode Mode, size_t Length, const void *Buf) +{ + if(Length < sizeof(tIPv4Header)) return; + const tIPv4Header* hdr = Buf; + if(hdr->Version != 4) return; + + // Get Data and Data Length + size_t dataLength = MIN(Length, ntohs(hdr->TotalLength)) - sizeof(tIPv4Header); + const void *data = &hdr->Options[0]; + + if( gaIPv4_Callbacks[hdr->Protocol].err_cb ) + gaIPv4_Callbacks[hdr->Protocol].err_cb(Iface, Mode, &hdr->Source, dataLength, data); } /** @@ -272,16 +290,14 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff */ tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast) { - tInterface *iface = NULL, *zero_iface = NULL; - Uint32 netmask; - Uint32 addr, this; + tInterface *zero_iface = NULL; ENTER("pAdapter xAddress bBroadcast", Adapter, Address, Broadcast); - addr = ntohl( Address.L ); + Uint32 addr = ntohl( Address.L ); LOG("addr = 0x%x", addr); - for( iface = gIP_Interfaces; iface; iface = iface->Next) + for( tInterface *iface = gIP_Interfaces; iface; iface = iface->Next) { if( iface->Adapter != Adapter ) continue; if( iface->Type != 4 ) continue; @@ -307,8 +323,8 @@ tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast) if( !Broadcast ) continue; // Check for broadcast - this = ntohl( ((tIPv4*)iface->Address)->L ); - netmask = IPv4_Netmask(iface->SubnetBits); + Uint32 this = ntohl( ((tIPv4*)iface->Address)->L ); + Uint32 netmask = IPv4_Netmask(iface->SubnetBits); LOG("iface addr = 0x%x, netmask = 0x%x (bits = %i)", this, netmask, iface->SubnetBits); if( (addr & netmask) == (this & netmask) && (addr & ~netmask) == (0xFFFFFFFF & ~netmask) ) diff --git a/KernelLand/Modules/IPStack/ipv4.h b/KernelLand/Modules/IPStack/ipv4.h index dd78788f94f76e1f951245cce8fa7a33b13e5ec6..c31b751296f968649e34e47106eb765ef30aee07 100644 --- a/KernelLand/Modules/IPStack/ipv4.h +++ b/KernelLand/Modules/IPStack/ipv4.h @@ -47,9 +47,11 @@ struct sIPv4Header #define IPV4_ETHERNET_ID 0x0800 // === FUNCTIONS === -extern int IPv4_RegisterCallback(int ID, tIPCallback Callback); +extern int IPv4_RegisterCallback(int ID, tIPRxCallback *RxCallback, tIPErrorCallback *ErrCallback); extern Uint16 IPv4_Checksum(const void *Buf, size_t Length); extern Uint32 IPv4_Netmask(int FixedBits); extern int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, tIPStackBuffer *Buffer); +extern void IPv4_HandleError(tInterface *Iface, tIPErrorMode Mode, size_t Length, const void *Buf); + #endif diff --git a/KernelLand/Modules/IPStack/ipv6.c b/KernelLand/Modules/IPStack/ipv6.c index 2ac05747aa4f967ab21216917b7a2ed080667b63..0e6df538d51f89c0a9435698a6e90d5aeff9c3fe 100644 --- a/KernelLand/Modules/IPStack/ipv6.c +++ b/KernelLand/Modules/IPStack/ipv6.c @@ -14,12 +14,12 @@ extern Uint32 IPv4_Netmask(int FixedBits); // === PROTOTYPES === int IPv6_Initialise(); - int IPv6_RegisterCallback(int ID, tIPCallback Callback); +// int IPv6_RegisterCallback(int ID, tIPCallback Callback); void IPv6_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer); tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast); // === GLOBALS === -tIPCallback gaIPv6_Callbacks[256]; +tIPRxCallback* gaIPv6_Callbacks[256]; // === CODE === /** @@ -36,7 +36,7 @@ int IPv6_Initialise() * \param ID 8-bit packet type ID * \param Callback Callback function */ -int IPv6_RegisterCallback(int ID, tIPCallback Callback) +int IPv6_RegisterCallback(int ID, tIPRxCallback* Callback) { if( ID < 0 || ID > 255 ) return 0; if( gaIPv6_Callbacks[ID] ) return 0; diff --git a/KernelLand/Modules/IPStack/ipv6.h b/KernelLand/Modules/IPStack/ipv6.h index 35cd74227007370244f3c8d314d260c230809b41..086dfbb5398914838fbb24585d3e4ef8adc667f1 100644 --- a/KernelLand/Modules/IPStack/ipv6.h +++ b/KernelLand/Modules/IPStack/ipv6.h @@ -32,12 +32,12 @@ struct sIPv6Header Uint8 HopLimit; tIPv6 Source; tIPv6 Destination; - char Data[]; + char Data[0]; }; #define IPV6_ETHERNET_ID 0x86DD -extern int IPv6_RegisterCallback(int ID, tIPCallback Callback); +extern int IPv6_RegisterCallback(int ID, tIPRxCallback* Callback); extern int IPv6_SendPacket(tInterface *Iface, tIPv6 Destination, int Protocol, tIPStackBuffer *Buffer); #endif diff --git a/KernelLand/Modules/IPStack/tcp.c b/KernelLand/Modules/IPStack/tcp.c index bbf7951730d2d846922414730752680ca7f28818..2854f30a0ee853858f05648b85be6e9537e371a1 100644 --- a/KernelLand/Modules/IPStack/tcp.c +++ b/KernelLand/Modules/IPStack/tcp.c @@ -2,7 +2,7 @@ * Acess2 IP Stack * - TCP Handling */ -#define DEBUG 1 +#define DEBUG 0 #include "ipstack.h" #include "ipv4.h" #include "ipv6.h" @@ -18,7 +18,7 @@ #define TCP_WINDOW_SIZE 0x2000 #define TCP_RECIEVE_BUFFER_SIZE 0x8000 #define TCP_DACK_THRESHOLD 4096 -#define TCP_DACK_TIMEOUT 500 +#define TCP_DACK_TIMEOUT 100 #define TCP_DEBUG 0 // Set to non-0 to enable TCP packet logging @@ -28,7 +28,9 @@ void TCP_StartConnection(tTCPConnection *Conn); void TCP_SendPacket(tTCPConnection *Conn, tTCPHeader *Header, size_t DataLen, const void *Data); void TCP_int_SendPacket(tInterface *Interface, const void *Dest, tTCPHeader *Header, size_t Length, const void *Data); void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer); -void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length); +void TCP_IPError(tInterface *Interface, tIPErrorMode Mode, const void *Address, int Length, const void *Buffer); + int TCP_INT_HandleServerPacket(tInterface *Interface, tTCPListener *Server, const void *Address, tTCPHeader *Header, size_t Length); + int TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length); int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length); void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection); void TCP_int_SendDelayedACK(void *ConnPtr); @@ -66,6 +68,7 @@ tVFS_NodeType gTCP_ServerNodeType = { }; tVFS_NodeType gTCP_ClientNodeType = { .TypeName = "TCP Client/Connection", + .Flags = VFS_NODETYPEFLAG_STREAM, .Read = TCP_Client_Read, .Write = TCP_Client_Write, .IOCtl = TCP_Client_IOCtl, @@ -92,7 +95,7 @@ void TCP_Initialise(void) giTCP_NextOutPort += rand()%128; IPStack_AddFile(&gTCP_ServerFile); IPStack_AddFile(&gTCP_ClientFile); - IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket); + IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket, TCP_IPError); IPv6_RegisterCallback(IP4PROT_TCP, TCP_GetPacket); } @@ -146,10 +149,22 @@ void TCP_int_SendPacket(tInterface *Interface, const void *Dest, tTCPHeader *Hea IPStack_Buffer_AppendSubBuffer(buffer, Length, 0, Data, NULL, NULL); IPStack_Buffer_AppendSubBuffer(buffer, sizeof(*Header), 0, Header, NULL, NULL); - LOG("Sending %i+%i to %s:%i", sizeof(*Header), Length, + #if TCP_DEBUG + Log_Log("TCP", "TCP_int_SendPacket: <Local>:%i to [%s]:%i (%i data), Flags = %s%s%s%s%s%s%s%s", + ntohs(Header->SourcePort), IPStack_PrintAddress(Interface->Type, Dest), - ntohs(Header->DestPort) + ntohs(Header->DestPort), + Length, + (Header->Flags & TCP_FLAG_CWR) ? "CWR " : "", + (Header->Flags & TCP_FLAG_ECE) ? "ECE " : "", + (Header->Flags & TCP_FLAG_URG) ? "URG " : "", + (Header->Flags & TCP_FLAG_ACK) ? "ACK " : "", + (Header->Flags & TCP_FLAG_PSH) ? "PSH " : "", + (Header->Flags & TCP_FLAG_RST) ? "RST " : "", + (Header->Flags & TCP_FLAG_SYN) ? "SYN " : "", + (Header->Flags & TCP_FLAG_FIN) ? "FIN " : "" ); + #endif Header->Checksum = 0; Header->Checksum = TCP_int_CalculateChecksum(Interface->Type, Interface->Address, Dest, @@ -168,7 +183,7 @@ void TCP_int_SendPacket(tInterface *Interface, const void *Dest, tTCPHeader *Hea } } -void TCP_int_SendRSTTo(tInterface *Interface, void *Address, size_t Length, const tTCPHeader *Header) +void TCP_int_SendRSTTo(tInterface *Interface, const void *Address, size_t Length, const tTCPHeader *Header) { tTCPHeader out_hdr = {0}; @@ -244,96 +259,20 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe { // Check that it is coming in on the same interface if(conn->Interface != Interface) continue; - // Check Source Port - Log_Log("TCP", "TCP_GetPacket: conn->RemotePort(%i) == hdr->SourcePort(%i)", - conn->RemotePort, ntohs(hdr->SourcePort)); if(conn->RemotePort != ntohs(hdr->SourcePort)) continue; - // Check Source IP - Log_Debug("TCP", "TCP_GetPacket: conn->RemoteIP(%s)", - IPStack_PrintAddress(conn->Interface->Type, &conn->RemoteIP)); - Log_Debug("TCP", " == Address(%s)", - IPStack_PrintAddress(conn->Interface->Type, Address)); if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 ) continue ; Log_Log("TCP", "TCP_GetPacket: Matches connection %p", conn); // We have a response! - TCP_INT_HandleConnectionPacket(conn, hdr, Length); - - return; + if( TCP_INT_HandleConnectionPacket(conn, hdr, Length) == 0 ) + return; + break ; } - - if( hdr->Flags & TCP_FLAG_RST ) { - LOG("RST, ignore"); - return ; - } - else if( hdr->Flags & TCP_FLAG_ACK ) { - LOG("ACK, send RST"); - TCP_int_SendRSTTo(Interface, Address, Length, hdr); - return ; - } - else if( !(hdr->Flags & TCP_FLAG_SYN) ) { - LOG("Other, ignore"); - return ; - } - Log_Log("TCP", "TCP_GetPacket: Opening Connection"); - - // TODO: Check for halfopen max - - tTCPConnection *conn = TCP_int_CreateConnection(Interface, TCP_ST_SYN_RCVD); - conn->LocalPort = srv->Port; - conn->RemotePort = ntohs(hdr->SourcePort); - - switch(Interface->Type) - { - case 4: conn->RemoteIP.v4 = *(tIPv4*)Address; break; - case 6: conn->RemoteIP.v6 = *(tIPv6*)Address; break; - default: ASSERTC(Interface->Type,==,4); return; - } - - conn->NextSequenceRcv = ntohl( hdr->SequenceNumber ) + 1; - conn->HighestSequenceRcvd = conn->NextSequenceRcv; - conn->NextSequenceSend = rand(); - conn->LastACKSequence = ntohl( hdr->SequenceNumber ); - - conn->Node.ImplInt = srv->NextID ++; - - // Hmm... Theoretically, this lock will never have to wait, - // as the interface is locked to the watching thread, and this - // runs in the watching thread. But, it's a good idea to have - // it, just in case - // Oh, wait, there is a case where a wildcard can be used - // (srv->Interface == NULL) so having the lock is a good idea - SHORTLOCK(&srv->lConnections); - conn->Server = srv; - conn->Prev = srv->ConnectionsTail; - if(srv->Connections) { - ASSERT(srv->ConnectionsTail); - srv->ConnectionsTail->Next = conn; - } - else { - ASSERT(!srv->ConnectionsTail); - srv->Connections = conn; - } - srv->ConnectionsTail = conn; - if(!srv->NewConnections) - srv->NewConnections = conn; - VFS_MarkAvaliable( &srv->Node, 1 ); - SHORTREL(&srv->lConnections); - Semaphore_Signal(&srv->WaitingConnections, 1); - - // Send the SYN ACK - hdr->Flags |= TCP_FLAG_ACK; - hdr->AcknowlegementNumber = htonl(conn->NextSequenceRcv); - hdr->SequenceNumber = htonl(conn->NextSequenceSend); - hdr->DestPort = hdr->SourcePort; - hdr->SourcePort = htons(srv->Port); - hdr->DataOffset = (sizeof(tTCPHeader)/4) << 4; - TCP_SendPacket( conn, hdr, 0, NULL ); - conn->NextSequenceSend ++; + TCP_INT_HandleServerPacket(Interface, srv, Address, hdr, Length); return ; } @@ -348,13 +287,13 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe if(conn->RemotePort != ntohs(hdr->SourcePort)) continue; // Check Source IP - if(conn->Interface->Type == 6 && !IP6_EQU(conn->RemoteIP.v6, *(tIPv6*)Address)) - continue; - if(conn->Interface->Type == 4 && !IP4_EQU(conn->RemoteIP.v4, *(tIPv4*)Address)) - continue; + if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 ) + continue ; - TCP_INT_HandleConnectionPacket(conn, hdr, Length); - return ; + // Handle or fall through + if( TCP_INT_HandleConnectionPacket(conn, hdr, Length) == 0 ) + return ; + break; } } @@ -366,13 +305,116 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe } } +void TCP_IPError(tInterface *Interface, tIPErrorMode Mode, const void *Address, int Length, const void *Buffer) +{ + if( Length < sizeof(tTCPHeader) ) return ; + + const tTCPHeader *hdr = Buffer; + + // TODO: Handle errors for server connections + + for( tTCPConnection *conn = gTCP_OutbountCons; conn; conn = conn->Next ) + { + if(conn->Interface != Interface) + continue; + if(conn->RemotePort != ntohs(hdr->SourcePort)) + continue; + if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 ) + continue ; + + // Mark an error on the interface + VFS_MarkError(&conn->Node, 1); + return ; + } +} + +/* + * Handle packets in LISTEN state + */ +int TCP_INT_HandleServerPacket(tInterface *Interface, tTCPListener *Server, const void *Address, tTCPHeader *Header, size_t Length) +{ + if( Header->Flags & TCP_FLAG_RST ) { + LOG("RST, ignore"); + return 0; + } + else if( Header->Flags & TCP_FLAG_ACK ) { + LOG("ACK, send RST"); + TCP_int_SendRSTTo(Interface, Address, Length, Header); + return 0; + } + else if( !(Header->Flags & TCP_FLAG_SYN) ) { + LOG("Other, ignore"); + return 0; + } + + Log_Log("TCP", "TCP_GetPacket: Opening Connection"); + + // TODO: Check security (a TCP Option) + // TODO: Check SEG.PRC + // TODO: Check for halfopen max + + tTCPConnection *conn = TCP_int_CreateConnection(Interface, TCP_ST_SYN_RCVD); + conn->LocalPort = Server->Port; + conn->RemotePort = ntohs(Header->SourcePort); + + switch(Interface->Type) + { + case 4: conn->RemoteIP.v4 = *(tIPv4*)Address; break; + case 6: conn->RemoteIP.v6 = *(tIPv6*)Address; break; + default: ASSERTC(Interface->Type,==,4); return 0; + } + + conn->NextSequenceRcv = ntohl( Header->SequenceNumber ) + 1; + conn->HighestSequenceRcvd = conn->NextSequenceRcv; + conn->NextSequenceSend = rand(); + conn->LastACKSequence = ntohl( Header->SequenceNumber ); + + conn->Node.ImplInt = Server->NextID ++; + conn->Node.Size = -1; + + // Hmm... Theoretically, this lock will never have to wait, + // as the interface is locked to the watching thread, and this + // runs in the watching thread. But, it's a good idea to have + // it, just in case + // Oh, wait, there is a case where a wildcard can be used + // (Server->Interface == NULL) so having the lock is a good idea + SHORTLOCK(&Server->lConnections); + conn->Server = Server; + conn->Prev = Server->ConnectionsTail; + if(Server->Connections) { + ASSERT(Server->ConnectionsTail); + Server->ConnectionsTail->Next = conn; + } + else { + ASSERT(!Server->ConnectionsTail); + Server->Connections = conn; + } + Server->ConnectionsTail = conn; + if(!Server->NewConnections) + Server->NewConnections = conn; + VFS_MarkAvaliable( &Server->Node, 1 ); + SHORTREL(&Server->lConnections); + Semaphore_Signal(&Server->WaitingConnections, 1); + + // Send the SYN ACK + Header->Flags = TCP_FLAG_ACK|TCP_FLAG_SYN; + Header->AcknowlegementNumber = htonl(conn->NextSequenceRcv); + Header->SequenceNumber = htonl(conn->NextSequenceSend); + Header->DestPort = Header->SourcePort; + Header->SourcePort = htons(Server->Port); + Header->DataOffset = (sizeof(tTCPHeader)/4) << 4; + TCP_SendPacket( conn, Header, 0, NULL ); + conn->NextSequenceSend ++; + return 0; +} + /** * \brief Handles a packet sent to a specific connection * \param Connection TCP Connection pointer * \param Header TCP Packet pointer * \param Length Length of the packet */ -void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length) +int TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length) { int dataLen; Uint32 sequence_num; @@ -381,7 +423,11 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // TODO: Check if this needs to be here if( Connection->State == TCP_ST_FINISHED ) { Log_Log("TCP", "Packet ignored - connection finnished"); - return ; + return 1; + } + if( Connection->State == TCP_ST_FORCE_CLOSE ) { + Log_Log("TCP", "Packet ignored - connection reset"); + return 1; } // Syncronise sequence values @@ -432,7 +478,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head if( Header->Flags & TCP_FLAG_ACK ) { Log_Log("TCP", "ACKing SYN-ACK"); - Connection->State = TCP_ST_OPEN; + Connection->State = TCP_ST_ESTABLISHED; VFS_MarkFull(&Connection->Node, 0); TCP_INT_SendACK(Connection, "SYN-ACK"); } @@ -447,19 +493,34 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // SYN-ACK sent, expecting ACK case TCP_ST_SYN_RCVD: + if( Header->Flags & TCP_FLAG_RST ) + { + Log_Log("TCP", "RST Received, closing"); + Connection->State = TCP_ST_FORCE_CLOSE; + VFS_MarkError(&Connection->Node, 1); + return 0; + } if( Header->Flags & TCP_FLAG_ACK ) { // TODO: Handle max half-open limit Log_Log("TCP", "Connection fully opened"); - Connection->State = TCP_ST_OPEN; + Connection->State = TCP_ST_ESTABLISHED; VFS_MarkFull(&Connection->Node, 0); } break; // --- Established State --- - case TCP_ST_OPEN: + case TCP_ST_ESTABLISHED: // - Handle State changes // + if( Header->Flags & TCP_FLAG_RST ) + { + Log_Log("TCP", "Conn %p closed, received RST"); + // Error outstanding transactions + Connection->State = TCP_ST_FORCE_CLOSE; + VFS_MarkError(&Connection->Node, 1); + return 0; + } if( Header->Flags & TCP_FLAG_FIN ) { Log_Log("TCP", "Conn %p closed, recieved FIN", Connection); VFS_MarkError(&Connection->Node, 1); @@ -467,7 +528,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head TCP_INT_SendACK(Connection, "FIN Received"); Connection->State = TCP_ST_CLOSE_WAIT; // CLOSE WAIT requires the client to close - return ; + return 0; } // Check for an empty packet @@ -475,7 +536,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head if( Header->Flags == TCP_FLAG_ACK ) { Log_Log("TCP", "ACK only packet"); - return ; + return 0; } // TODO: Is this right? (empty packet counts as one byte) if( Connection->HighestSequenceRcvd == Connection->NextSequenceRcv ) @@ -483,7 +544,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head Connection->NextSequenceRcv ++; Log_Log("TCP", "Empty Packet, inc and ACK the current sequence number"); TCP_INT_SendACK(Connection, "Empty"); - return ; + return 0; } // NOTES: @@ -610,7 +671,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head Connection->State = TCP_ST_FIN_WAIT2; Log_Debug("TCP", "Conn %p closed, sent FIN ACKed", Connection); VFS_MarkError(&Connection->Node, 1); - return ; + return 0; } break; @@ -630,7 +691,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head Connection->State = TCP_ST_TIME_WAIT; Log_Debug("TCP", "Conn %p CLOSING -> TIME WAIT", Connection); VFS_MarkError(&Connection->Node, 1); - return ; + return 0; } break; @@ -642,12 +703,17 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head case TCP_ST_FINISHED: Log_Log("TCP", "Packets when CLOSED, ignoring"); break; + case TCP_ST_FORCE_CLOSE: + Log_Log("TCP", "Packets when force CLOSED, ignoring"); + return 1; //default: // Log_Warning("TCP", "Unhandled TCP state %i", Connection->State); // break; } + return 0; + } /** @@ -690,10 +756,15 @@ int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection) { // Calculate length of contiguous bytes - const int length = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv; + const size_t length = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv; Uint32 index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE; size_t runlength = length; - LOG("length=%i, index=0x%x", length, index); + LOG("HSR=0x%x,NSR=0x%x", Connection->HighestSequenceRcvd, Connection->NextSequenceRcv); + if( Connection->HighestSequenceRcvd == Connection->NextSequenceRcv ) + { + return ; + } + LOG("length=%u, index=0x%x", length, index); for( int i = 0; i < length; i ++ ) { int bit = index % 8; @@ -854,6 +925,7 @@ tTCPConnection *TCP_int_CreateConnection(tInterface *Interface, enum eTCPConnect conn->LocalPort = -1; conn->RemotePort = -1; + conn->Node.Size = -1; conn->Node.ReferenceCount = 1; conn->Node.ImplPtr = conn; conn->Node.NumACLs = 1; @@ -867,6 +939,7 @@ tTCPConnection *TCP_int_CreateConnection(tInterface *Interface, enum eTCPConnect Semaphore_Init(conn->SentBufferSpace, 0, TCP_SEND_BUFFER_SIZE, "TCP SentBuffer", conn->Name); #endif + conn->HighestSequenceRcvd = 0; #if CACHE_FUTURE_PACKETS_IN_BYTES // Future recieved data (ahead of the expected sequence number) conn->FuturePacketData = (Uint8*)conn + sizeof(tTCPConnection); @@ -1116,7 +1189,8 @@ tVFS_Node *TCP_Client_Init(tInterface *Interface) conn->Server = NULL; conn->Prev = NULL; conn->Next = gTCP_OutbountCons; - gTCP_OutbountCons->Prev = conn; + if(gTCP_OutbountCons) + gTCP_OutbountCons->Prev = conn; gTCP_OutbountCons = conn; SHORTREL(&glTCP_OutbountCons); @@ -1133,13 +1207,14 @@ size_t TCP_Client_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffe tTCPConnection *conn = Node->ImplPtr; size_t len; - ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); + ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer); LOG("conn = %p {State:%i}", conn, conn->State); // If the connection has been closed (state > ST_OPEN) then clear // any stale data in the buffer (until it is empty (until it is empty)) - if( conn->State > TCP_ST_OPEN ) + if( conn->State > TCP_ST_ESTABLISHED ) { + LOG("Connection closed"); Mutex_Acquire( &conn->lRecievedPackets ); len = RingBuffer_Read( Buffer, conn->RecievedBuffer, Length ); Mutex_Release( &conn->lRecievedPackets ); @@ -1216,6 +1291,8 @@ void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, const voi TCP_SendPacket( Connection, packet, Length, Data ); + // TODO: Start a retransmit time (if data is not ACKed in x seconds, send again) + Connection->NextSequenceSend += Length; } @@ -1235,7 +1312,7 @@ size_t TCP_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void // #endif // Don't allow a write to a closed connection - if( conn->State > TCP_ST_OPEN ) { + if( conn->State > TCP_ST_ESTABLISHED ) { VFS_MarkError(Node, 1); errno = 0; LEAVE('i', -1); @@ -1394,7 +1471,7 @@ void TCP_Client_Close(tVFS_Node *Node) } Node->ReferenceCount --; - if( conn->State == TCP_ST_CLOSE_WAIT || conn->State == TCP_ST_OPEN ) + if( conn->State == TCP_ST_CLOSE_WAIT || conn->State == TCP_ST_ESTABLISHED ) { packet.SourcePort = htons(conn->LocalPort); packet.DestPort = htons(conn->RemotePort); @@ -1416,10 +1493,14 @@ void TCP_Client_Close(tVFS_Node *Node) Log_Warning("TCP", "Closing connection that was never opened"); TCP_int_FreeTCB(conn); break; + case TCP_ST_FORCE_CLOSE: + conn->State = TCP_ST_FINISHED; + TCP_int_FreeTCB(conn); + break; case TCP_ST_CLOSE_WAIT: conn->State = TCP_ST_LAST_ACK; break; - case TCP_ST_OPEN: + case TCP_ST_ESTABLISHED: conn->State = TCP_ST_FIN_WAIT1; while( conn->State == TCP_ST_FIN_WAIT1 ) Threads_Yield(); diff --git a/KernelLand/Modules/IPStack/tcp.h b/KernelLand/Modules/IPStack/tcp.h index 43828f185231e125b7b45904835333030243c0fa..0e260fcf9b42bc468cfad19305788275f9f8b9ff 100644 --- a/KernelLand/Modules/IPStack/tcp.h +++ b/KernelLand/Modules/IPStack/tcp.h @@ -94,7 +94,7 @@ enum eTCPConnectionState TCP_ST_SYN_SENT, // 1 - SYN sent by local, waiting for SYN-ACK TCP_ST_SYN_RCVD, // 2 - SYN recieved, SYN-ACK sent - TCP_ST_OPEN, // 3 - Connection open + TCP_ST_ESTABLISHED, // 3 - Connection open // Local Close TCP_ST_FIN_WAIT1, // 4 - FIN sent, waiting for reply (ACK or FIN) @@ -102,9 +102,10 @@ enum eTCPConnectionState TCP_ST_CLOSING, // 6 - Waiting for ACK of FIN (FIN sent and recieved) TCP_ST_TIME_WAIT, // 7 - Waiting for timeout after local close // Remote close - TCP_ST_CLOSE_WAIT, // 8 - FIN recieved, waiting for user to close (error set, wait for node close) - TCP_ST_LAST_ACK, // 9 - FIN sent and recieved, waiting for ACK - TCP_ST_FINISHED // 10 - Essentially closed, all packets are invalid + TCP_ST_FORCE_CLOSE, // 8 - RST recieved, waiting for user close + TCP_ST_CLOSE_WAIT, // 9 - FIN recieved, waiting for user to close (error set, wait for node close) + TCP_ST_LAST_ACK, // 10 - FIN sent and recieved, waiting for ACK + TCP_ST_FINISHED // 11 - Essentially closed, all packets are invalid }; struct sTCPConnection diff --git a/KernelLand/Modules/IPStack/udp.c b/KernelLand/Modules/IPStack/udp.c index 325a09e86c6d5a3ad82a241583d3b90a82ddd438..9037439cf80023b273974d12ae2c5a512ee9fa51 100644 --- a/KernelLand/Modules/IPStack/udp.c +++ b/KernelLand/Modules/IPStack/udp.c @@ -15,7 +15,7 @@ // === PROTOTYPES === void UDP_Initialise(); void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer); -void UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer); +void UDP_IPError(tInterface *Interface, tIPErrorMode Code, const void *Address, int Length, const void *Buffer); void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length); // --- Client Channels tVFS_Node *UDP_Channel_Init(tInterface *Interface); @@ -33,6 +33,8 @@ Uint16 UDP_int_FinaliseChecksum(Uint16 Value); // === GLOBALS === tVFS_NodeType gUDP_NodeType = { + .TypeName = "UDP", + .Flags = VFS_NODETYPEFLAG_STREAM, .Read = UDP_Channel_Read, .Write = UDP_Channel_Write, .IOCtl = UDP_Channel_IOCtl, @@ -54,8 +56,7 @@ tSocketFile gUDP_SocketFile = {NULL, "udp", UDP_Channel_Init}; void UDP_Initialise() { IPStack_AddFile(&gUDP_SocketFile); - //IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket, UDP_Unreachable); - IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket); + IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket, UDP_IPError); } /** @@ -65,13 +66,15 @@ void UDP_Initialise() int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, int Length, void *Buffer) { tUDPHeader *hdr = Buffer; - tUDPChannel *chan; - tUDPPacket *pack; - int len; - for(chan = List; chan; chan = chan->Next) + for(tUDPChannel *chan = List; chan; chan = chan->Next) { // Match local endpoint + LOG("(%p):%i - %s/%i:%i", + chan->Interface, chan->LocalPort, + IPStack_PrintAddress(chan->Remote.AddrType, &chan->Remote.Addr), chan->RemoteMask, + chan->Remote.Port + ); if(chan->Interface && chan->Interface != Interface) continue; if(chan->LocalPort != ntohs(hdr->DestPort)) continue; @@ -91,8 +94,8 @@ int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, in Log_Log("UDP", "Recieved packet for %p", chan); // Create the cached packet - len = ntohs(hdr->Length); - pack = malloc(sizeof(tUDPPacket) + len); + int len = ntohs(hdr->Length); + tUDPPacket *pack = malloc(sizeof(tUDPPacket) + len); pack->Next = NULL; memcpy(&pack->Remote.Addr, Address, IPStack_GetAddressSize(Interface->Type)); pack->Remote.Port = ntohs(hdr->SourcePort); @@ -142,7 +145,7 @@ void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe /** * \brief Handle an ICMP Unrechable Error */ -void UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer) +void UDP_IPError(tInterface *Interface, tIPErrorMode Code, const void *Address, int Length, const void *Buffer) { } @@ -157,7 +160,11 @@ void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, U { tUDPHeader hdr; - if(Channel->Interface && Channel->Interface->Type != AddrType) return ; + if(Channel->Interface && Channel->Interface->Type != AddrType) { + LOG("Bad interface type for channel packet, IF is %i, but packet is %i", + Channel->Interface->Type, AddrType); + return ; + } // Create the packet hdr.SourcePort = htons( Channel->LocalPort ); @@ -175,6 +182,7 @@ void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, U IPStack_Buffer_AppendSubBuffer(buffer, Length, 0, Data, NULL, NULL); IPStack_Buffer_AppendSubBuffer(buffer, sizeof(hdr), 0, &hdr, NULL, NULL); // TODO: What if Channel->Interface is NULL here? + ASSERT(Channel->Interface); IPv4_SendPacket(Channel->Interface, *(tIPv4*)Address, IP4PROT_UDP, 0, buffer); break; default: @@ -189,6 +197,7 @@ tVFS_Node *UDP_Channel_Init(tInterface *Interface) tUDPChannel *new; new = calloc( sizeof(tUDPChannel), 1 ); new->Interface = Interface; + new->Node.Size = -1; new->Node.ImplPtr = new; new->Node.NumACLs = 1; new->Node.ACLs = &gVFS_ACL_EveryoneRW; @@ -202,49 +211,59 @@ tVFS_Node *UDP_Channel_Init(tInterface *Interface) return &new->Node; } -/** - * \brief Read from the channel file (wait for a packet) - */ -size_t UDP_Channel_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags) +tUDPPacket *UDP_Channel_WaitForPacket(tUDPChannel *chan, Uint VFSFlags) { - tUDPChannel *chan = Node->ImplPtr; - tUDPPacket *pack; - tUDPEndpoint *ep; - int ofs, addrlen; - - if(chan->LocalPort == 0) { - Log_Notice("UDP", "Channel %p sent with no local port", chan); - return 0; - } - - while(chan->Queue == NULL) Threads_Yield(); + // EVIL - Yield until queue is created (avoids races) + while(chan->Queue == NULL) + Threads_Yield(); for(;;) { - tTime timeout_z = 0, *timeout = (Flags & VFS_IOFLAG_NOBLOCK) ? &timeout_z : NULL; - int rv = VFS_SelectNode(Node, VFS_SELECT_READ, timeout, "UDP_Channel_Read"); - if( rv ) { - errno = (Flags & VFS_IOFLAG_NOBLOCK) ? EWOULDBLOCK : EINTR; + tTime timeout_z = 0, *timeout = (VFSFlags & VFS_IOFLAG_NOBLOCK) ? &timeout_z : NULL; + int rv = VFS_SelectNode(&chan->Node, VFS_SELECT_READ, timeout, "UDP_Channel_Read"); + if( rv == 0 ) { + errno = (VFSFlags & VFS_IOFLAG_NOBLOCK) ? EWOULDBLOCK : EINTR; + return NULL; } SHORTLOCK(&chan->lQueue); if(chan->Queue == NULL) { SHORTREL(&chan->lQueue); continue; } - pack = chan->Queue; + tUDPPacket *pack = chan->Queue; chan->Queue = pack->Next; if(!chan->Queue) { chan->QueueEnd = NULL; - VFS_MarkAvaliable(Node, 0); // Nothing left + VFS_MarkAvaliable(&chan->Node, 0); // Nothing left } SHORTREL(&chan->lQueue); - break; + return pack; + } + // Unreachable +} + +/** + * \brief Read from the channel file (wait for a packet) + */ +size_t UDP_Channel_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags) +{ + tUDPChannel *chan = Node->ImplPtr; + + if(chan->LocalPort == 0) { + Log_Notice("UDP", "Channel %p sent with no local port", chan); + return 0; + } + + tUDPPacket *pack = UDP_Channel_WaitForPacket(chan, Flags); + if( !pack ) { + return 0; } + size_t addrlen = IPStack_GetAddressSize(pack->Remote.AddrType); + tUDPEndpoint *ep = Buffer; + size_t ofs = 4 + addrlen; + // Check that the header fits - addrlen = IPStack_GetAddressSize(pack->Remote.AddrType); - ep = Buffer; - ofs = 4 + addrlen; if(Length < ofs) { free(pack); Log_Notice("UDP", "Insuficient space for header in buffer (%i < %i)", (int)Length, ofs); @@ -300,6 +319,8 @@ static const char *casIOCtls_Channel[] = { "getset_remoteport", "getset_remotemask", "set_remoteaddr", + "sendto", + "recvfrom", NULL }; /** @@ -351,14 +372,21 @@ int UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data) case 6: // getset_remotemask (returns bool success) if(!Data) LEAVE_RET('i', chan->RemoteMask); - if(!CheckMem(Data, sizeof(int))) LEAVE_RET('i', -1); + if(!CheckMem(Data, sizeof(int))) { + LOG("Data pointer invalid"); + LEAVE_RET('i', -1); + } if( !chan->Interface ) { LOG("Can't set remote mask on NULL interface"); LEAVE_RET('i', -1); } - if( *(int*)Data > IPStack_GetAddressSize(chan->Interface->Type) ) + int mask = *(int*)Data; + int addr_bits = IPStack_GetAddressSize(chan->Interface->Type) * 8; + if( mask > addr_bits ) { + LOG("Mask too large (%i > max %i)", mask, addr_bits); LEAVE_RET('i', -1); - chan->RemoteMask = *(int*)Data; + } + chan->RemoteMask = mask; LEAVE('i', chan->RemoteMask); return chan->RemoteMask; @@ -371,9 +399,73 @@ int UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data) LOG("Invalid pointer"); LEAVE_RET('i', -1); } + LOG("Set remote addr %s", IPStack_PrintAddress(chan->Interface->Type, Data)); + chan->Remote.AddrType = chan->Interface->Type; memcpy(&chan->Remote.Addr, Data, IPStack_GetAddressSize(chan->Interface->Type)); LEAVE('i', 0); return 0; + case 8: { // sendto + if(!CheckMem(Data, 2*sizeof(void*)+2)) { + LOG("Data pointer invalid"); + LEAVE_RET('i', -1); + } + const struct sSendToArgs { + const tUDPEndpoint* ep; + const void* buf; + const Uint16 buflen; + } info = *(const struct sSendToArgs*)Data; + LOG("sendto(buf=%p + %u, ep=%p)", info.buf, info.buflen, info.ep); + if(!CheckMem(info.ep, 2+2) || !CheckMem(info.ep, 2+2+IPStack_GetAddressSize(info.ep->AddrType)) ) { + LEAVE_RET('i', -1); + } + if(!CheckMem(info.buf, info.buflen)) { + LEAVE_RET('i', -1); + } + + UDP_SendPacketTo(chan, info.ep->AddrType, &info.ep->Addr, info.ep->Port, + info.buf, (size_t)info.buflen); + + LEAVE_RET('i', info.buflen); } + case 9: { // recvfrom + if(!CheckMem(Data, 2*sizeof(void*)+2)) { + LOG("Data pointer invalid"); + LEAVE_RET('i', -1); + } + const struct sRecvFromArgs { + tUDPEndpoint* ep; + void* buf; + Uint16 buflen; + } info = *(const struct sRecvFromArgs*)Data; + LOG("recvfrom(buf=%p + %u, ep=%p)", info.buf, info.buflen, info.ep); + if(!CheckMem(info.ep, 2+2)) { + LEAVE_RET('i', -1); + } + if(!CheckMem(info.buf, info.buflen)) { + LEAVE_RET('i', -1); + } + + tUDPPacket *pack = UDP_Channel_WaitForPacket(chan, 0); + if( pack == NULL ) { + LOG("No packet"); + LEAVE_RET('i', 0); + } + + size_t addrsize = IPStack_GetAddressSize(pack->Remote.AddrType); + if( !CheckMem(info.ep, 2+2+addrsize) ) { + LOG("Insufficient space for source address"); + free(pack); + LEAVE_RET('i', -1); + } + info.ep->Port = pack->Remote.Port; + info.ep->AddrType = pack->Remote.AddrType; + memcpy(&info.ep->Addr, &pack->Remote.Addr, addrsize); + + size_t retlen = (info.buflen < pack->Length ? info.buflen : pack->Length); + memcpy(info.buf, pack->Data, retlen); + + free(pack); + + LEAVE_RET('i', retlen); } } LEAVE_RET('i', 0); } diff --git a/KernelLand/Modules/Input/Keyboard/main.c b/KernelLand/Modules/Input/Keyboard/main.c index 377ae309402c209f76b3f2a5a0c293eb7959caec..32688df28cc4a082c57017e7cf1a3c7777b54304 100644 --- a/KernelLand/Modules/Input/Keyboard/main.c +++ b/KernelLand/Modules/Input/Keyboard/main.c @@ -117,19 +117,16 @@ int Keyboard_IOCtl(tVFS_Node *Node, int Id, void *Data) */ tKeyboard *Keyboard_CreateInstance(int MaxSym, const char *Name) { - tKeyboard *ret; - int sym_bitmap_size = (MaxSym + 7)/8; - int string_size = strlen(Name) + 1; + size_t sym_bitmap_size = (MaxSym + 7)/8; + size_t string_size = strlen(Name) + 1; - ret = malloc( sizeof(tKeyboard) + sym_bitmap_size + string_size ); + tKeyboard *ret = calloc( 1, sizeof(tKeyboard) + sym_bitmap_size + string_size ); if( !ret ) { return NULL; } - // Clear - memset(ret, 0, sizeof(tKeyboard) + sym_bitmap_size ); // Set name - ret->Name = (char*)ret + sizeof(tKeyboard) + sym_bitmap_size; - memcpy(ret->Name, Name, string_size); + ret->Name = (char*)( &ret->KeyStates[sym_bitmap_size] ); + strcpy(ret->Name, Name); // Set node and default keymap ret->Node = &gKB_DevInfo.RootNode; ret->Keymap = &gKeymap_KBDUS; diff --git a/KernelLand/Modules/Input/PS2KbMouse/8042.c b/KernelLand/Modules/Input/PS2KbMouse/8042.c index f71fff7ffe263041a322f7266908aa5247bcd881..d76322cbbc81b8b239e7c8bf68cbba8d62d5fe5a 100644 --- a/KernelLand/Modules/Input/PS2KbMouse/8042.c +++ b/KernelLand/Modules/Input/PS2KbMouse/8042.c @@ -24,10 +24,9 @@ void KBC8042_Init(void) IRQ_AddHandler(12, KBC8042_MouseHandler, NULL); // Set IRQ { - Uint8 temp; // Attempt to get around a strange bug in Bochs/Qemu by toggling // the controller on and off - temp = inb(0x61); + Uint8 temp = inb(0x61); outb(0x61, temp | 0x80); outb(0x61, temp & 0x7F); inb(0x60); // Clear keyboard buffer diff --git a/KernelLand/Modules/Interfaces/EDI/Makefile b/KernelLand/Modules/Interfaces/EDI/Makefile deleted file mode 100644 index a93a8b7c2a78ce84f0ab01bb683ba0156894b2bb..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# EDI - Extensible Driver Interface -# -# Acess Interface - - -OBJ = main.o edi.o -NAME = EDI - --include ../Makefile.tpl diff --git a/KernelLand/Modules/Interfaces/EDI/edi/acess-edi.h b/KernelLand/Modules/Interfaces/EDI/edi/acess-edi.h deleted file mode 100644 index 4071388642a58ac1656435cd4e70467ef32debbf..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/edi/acess-edi.h +++ /dev/null @@ -1,41 +0,0 @@ -/*! \file acess-edi.h - * \brief Acess Specific EDI Objects - * - * Contains documentation and information for - * - Timers - */ - -/* Copyright (c) 2006 John Hodge - * Permission is granted to copy, distribute and/or modify this document - * under the terms of the GNU Free Documentation License, Version 1.2 - * or any later version published by the Free Software Foundation; - * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover - * Texts. A copy of the license is included in the file entitled "COPYING". */ - -#ifndef ACESS_EDI_H -#define ACESS_EDI_H - -#include "edi_objects.h" - -/// \brief Name of Acess EDI Time Class -#define ACESS_TIMER_CLASS "ACESSEDI-TIMER" - -#ifndef IMPLEMENTING_EDI -/*! \brief int32_t ACESSEDI-TIMER.init_timer(uint32_t Delay, void (*Callback)(int), int Arg); - * - * Takes a timer pointer and intialises the timer object to fire after \a Delay ms - * When the timer fires, \a Callback is called with \a Arg passed to it. - */ -EDI_DEFVAR int32_t (*init_timer)(object_pointer port_object, uint32_t Delay, void (*fcn)(int), int arg); - -/*! \brief void ACESSEDI-TIMER.disable_timer(); - * - * Disables the timer and prevents it from firing - * After this has been called, the timer can then be initialised again. - */ -EDI_DEFVAR void (*disable_timer)(object_pointer port_object); - - -#endif // defined(IMPLEMENTING_EDI) - -#endif diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi.h b/KernelLand/Modules/Interfaces/EDI/edi/edi.h deleted file mode 100644 index 273f7a3dc35e88166c7ee070322a88f95c1c9779..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/edi/edi.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef EDI_H - -/* Copyright (c) 2006 Eli Gottlieb. - * Permission is granted to copy, distribute and/or modify this document - * under the terms of the GNU Free Documentation License, Version 1.2 - * or any later version published by the Free Software Foundation; - * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover - * Texts. A copy of the license is included in the file entitled "COPYING". */ - -#define EDI_H -/*! \file edi.h - * \brief The unitive EDI header to include others, start EDI, and stop EDI. - * - * Data structures and algorithms this header represents: - * DATA STRUCTURE: CLASS QUOTAS - The runtime and the driver have the right to set a quota on how many objects of a given class - * owned by that party the other may construct. These quotas are kept internally by the driver or runtime, are optional and are - * exposed to the other party via the quota() function (for quotas of runtime-owned classes) and the k_quota() function pointer given - * to the runtime by the driver. - * - * ALGORITHMS: INITIALIZATION AND SHUTDOWN - On initialization of the runtime's EDI environment for this driver it calls the - * driver's driver_init() routine (which must match driver_init_t) to initialize the driver with a list of EDI objects the runtime - * thinks the driver should run with. The driver then initializes. This can include calling edi_negotiate_resources() to try and - * obtain more or different objects. Eventually driver_init() returns an edi_initialization_t structure containing its quota - * function and the list of classes belonging to the driver which the runtime can construct. Either the driver or the runtime can - * shut down EDI by calling edi_shutdown(), which in turn calls the driver's driver_finish() routine. On shutdown all objects, of - * classes belonging to both the runtime and driver, are destroyed. */ - -#include "edi_objects.h" -#include "edi_dma_streams.h" -#include "edi_pthreads.h" -#include "edi_port_io.h" -#include "edi_memory_mapping.h" -#include "edi_devices.h" -#include "edi_interrupts.h" - -/*! \brief A pointer to a function the runtime can call if it fails to construct one of the driver's classes to find out what the - * runtime's quota is for that class. - * - * A pointer to a function which takes an edi_string_t as a parameter and returns in int32_t. This function follows the same - * semantics as the quota() function, returning the number of objects of the given class that can be constructed, -1 for infinity or - * -2 for an erroneous class name. It is used to tell the runtime the location of such a function in the driver so that the runtime - * can check quotas on driver-owned classes. */ -typedef int32_t (*k_quota_t)(edi_string_t resource_class); -/*!\struct edi_initialization_t - * \brief Structure containing driver classes available to the runtime and the driver's quota function after the driver has initialized. - * - * Structure containing driver classes available to runtime, the driver's quota function and the driver's name provided to the runtime - * after the driver has initialized. driver_bus, vendor_id, and device_id are all optional fields which coders should consider - * supplementary information. Kernels can require these fields if they so please, but doing so for devices which don't run on a Vendor - * ID/Product ID supporting bus is rather unwise. */ -typedef struct { - /*!\brief The number of driver classes in the driver_classes array. */ - int32_t num_driver_classes; - /*!\brief An array of declarations of driver classes available to the runtime. - * - * This array should not necessarily contain the entire list of EDI classes implemented by the driver. Instead, it should - * contain a list of those classes which the driver has correctly initialized itself to provide instances of with full - * functionality. */ - edi_class_declaration_t *driver_classes; - /*!\brief The driver's quota function. */ - k_quota_t k_quota; - /*!\brief The driver's name. */ - edi_string_t driver_name; - /*!\brief The bus of the device this driver wants to drive, if applicable. - * - * The driver does not have to supply this field, and can also supply "MULTIPLE BUSES" here to indicate that it drives devices - * on multiple buses. */ - edi_string_t driver_bus; - /*!\brief The driver's vendor ID, if applicable. - * - * The driver does not need to supply this field, and should supply -1 to indicate that it does not wish to. */ - int16_t vendor_id; - /*!\brief The driver's device ID, if applicable. - * - * The driver does not need to supply this field, but can supply it along with vendor_id. If either vendor_id or this field are - * set to -1 the runtime should consider this field not supplied. */ - int16_t driver_id; -} edi_initialization_t; -/*!\brief A pointer to a driver's initialization function. - * - * The protocol for the driver's initialization function. The runtime gives the driver a set of EDI objects representing the - * resources it thinks the driver should run with. This function returns an edi_initialization_t structure containing declarations - * of the EDI classes the driver can make available to the runtime after initialization. If any member of that structure contains 0 - * or NULL, it is considered invalid and the runtime should destroy the driver without calling its driver_finish() routine. */ -typedef edi_initialization_t (*driver_init_t)(int32_t num_resources,edi_object_metadata_t *resources); -/*!\brief Requests more resources from the runtime. Can be called during driver initialization. - * - * Called to negotiate with the runtime for the right to create further EDI objects/obtain further resources owned by the runtime. - * When the driver calls this routine, the runtime decides whether to grant more resources. If yes, this call returns true, and the - * driver can proceed to try and create the objects it desires, in addition to destroying EDI objects it doesn't want. Otherwise, - * it returns false. - * The driver must deal with whatever value this routine returns. */ -bool edi_negotiate_resources(); - -/*! \brief Returns the driver's quota of objects for a given runtime-owned class. - * - * This function takes an edi_string_t with the name of a runtime-owned class in it and returns the number of objects of that class - * which drivers can construct, -1 for infinity, or -2 for an erroneous class name. */ -int32_t quota(edi_string_t resource_class); -/*! \brief Sends a string to the operating systems debug output or logging facilities. */ -void edi_debug_write(uint32_t debug_string_length, char *debug_string); -/*! \brief This call destroys all objects and shuts down the entire EDI environment of the driver. - * - * This function shuts down EDI as described in INITIALIZATION AND SHUTDOWN above. All objects are destroyed, EDI functions can no - * longer be successfully called, etc. This function only succeeds when EDI has already been initialized, so it returns -1 when EDI - * hasn't been, 1 on success, or 0 for all other errors. */ -int32_t shutdown_edi(void); - -/*!\brief A pointer to the driver's finishing/shutdown function. - * - * The protocol for the driver's shutting down. This function should do anything the driver wants done before it dies. */ -typedef void (*driver_finish_t)(); - -#endif diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_devices.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_devices.h deleted file mode 100644 index 245e01f3ba4bbb16526d532936a1aa62ed7254b7..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/edi/edi_devices.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef EDI_DEVICES_H - -/* Copyright (c) 2006 Eli Gottlieb. - * Permission is granted to copy, distribute and/or modify this document - * under the terms of the GNU Free Documentation License, Version 1.2 - * or any later version published by the Free Software Foundation; - * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover - * Texts. A copy of the license is included in the file entitled "COPYING". */ - -/* Edited by thePowersGang (John Hodge) June 2009 - * - Add #ifdef EDI_MAIN_FILE - */ - -#define EDI_DEVICES_H - -/*! \file edi_devices.h - * \brief Declaration and description of simple classes for implementation by EDI drivers to represent hardware devices. - * - * Data structures and algorithms this header represents: - * - * DATA STRUCTURE AND ALGORITHM: BASIC DEVICES - There are two functions, select() for waiting on devices and ioctl() for - * controlling them, common to many POSIX devices. Implementations of EDI-CHARACTER-DEVICE or EDI-BLOCK-DEVICE may implement either of - * these or both, and users of such objects much query for the methods to see if they're supported. Obviously, runtime or driver - * developers don't *need* to support these. - * - * DATA STRUCTURE AND ALGORITHM: CHARACTER DEVICES - The class EDI-CHARACTER-DEVICE provides a very basic interface to character - * devices, which read and write streams of characters. As such, this class only provides read() and write(). The calls attempt a - * likeness to POSIX. - * - * DATA STRUCTURE AND ALGORITHM: BLOCK DEVICES - The class EDI-BLOCK-DEVICE provides a very basic interface to block devices, which - * can read(), write() and seek() to blocks of a specific size in an array of blocks with a specific size. Its declarations and - * semantics should behave like those of most POSIX operating systems. - * - * Note that EDI runtimes should not implement these classes. Their declarations are provided for drivers to implement. */ - -#include "edi_objects.h" - -/* Methods common to all EDI device classes specified in this header. */ - -/*!\brief EAGAIN returned by functions for block and character devices. - * - * Means that the amount of data the device has ready is less than count. */ -#define EAGAIN -1 -/*!\brief EBADOBJ returned by functions for block and character devices. - * - * Means that the object passed as the method's this point was not a valid object of the needed class. */ -#define EBADOBJ -2 -/*!\brief EINVAL returned by functions for block and character devices. - * - * Means that the method got passed invalid parameters. */ -#ifdef EINVAL -# undef EINVAL -#endif -#define EINVAL -3 - -/*!\brief select() type to wait until device is writable. */ -#define EDI_SELECT_WRITABLE 0 -/*!\brief select() type to wait until device is readable. */ -#define EDI_SELECT_READABLE 1 - -/*!\brief Argument to seek(). Sets the block offset (ie: the "current block" index) to the given whence value. */ -#define EDI_SEEK_SET 0 -/*!\brief Argument to seek(). Sets the block offset (ie: the "current block" index) to its current value + whence. */ -#define EDI_SEEK_CURRENT 1 - -#ifdef EDI_MAIN_FILE -/*!\brief Arguments to EDI's basic select() function. */ -edi_variable_declaration_t select_arguments[2] = {{"pointer void","device",1}, - {"unsigned int32_t","select_type",1}}; -/*!\brief Declaration of EDI's basic select() function. - * - * Contrary to the POSIX version, this select() puts its error codes in its return value. */ -edi_function_declaration_t select_declaration = {"int32_t","edi_device_select",0,2,select_arguments,NULL}; -#else -extern edi_function_declaration_t select_declaration; // Declare for non main files -#endif - -#ifdef EDI_MAIN_FILE -/*!\brief Arguments to EDI's basic ioctl() function. */ -edi_variable_declaration_t ioctl_arguments[3] = {{"pointer void","device",1},{"int32_t","request",1},{"pointer void","argp",1}}; -/*!\brief Declaration of EDI's basic ioctl() function. - * - * Contrary to the POSIX version, this ioctl() puts its error codes in its return value. */ -edi_function_declaration_t ioctl_declaration = {"int32_t","edi_device_ioctl",0,3,ioctl_arguments,NULL}; -#else -extern edi_class_declaration_t ioctl_declaration; // Declare for non main files -#endif - -#ifdef EDI_MAIN_FILE -/*!\brief Declaration of the arguments EDI-CHARACTER-DEVICE's read() and write() methods. */ -edi_variable_declaration_t chardev_read_write_arguments[3] = {{"pointer void","chardev",1}, - {"pointer void","buffer",1}, - {"unsigned int32_t","char_count",1}}; -/*!\brief Declarations of the methods of EDI-CHARACTER-DEVICE, read() and write(). - * - * The code pointers of these function declarations are all given as NULL. Driver developers implementing EDI-CHARACTER-DEVICE should - * fill in these entries with pointers to their own functions. */ -EDI_DEFVAR edi_function_declaration_t chardev_methods[2]= {{"int32_t","edi_chardev_read",0,3,chardev_read_write_arguments,NULL}, - {"int32_t","edi_chardev_write",0,3,chardev_read_write_arguments,NULL}}; -/*!\brief Declaration of the EDI-CHARACTER-DEVICE class. - * - * Driver developers implementing this class should fill in their own values for constructor, destructor, and possibly even parent - * before passing the filled-in structure to the EDI runtime. */ -EDI_DEFVAR edi_class_declaration_t chardev_class = {"EDI-CHARACTER-DEVICE",0,2,chardev_methods,NULL,NULL,NULL}; -#else -extern edi_class_declaration_t chardev_class; // Declare for non main files -#endif - -#ifdef EDI_MAIN_FILE -/*!\brief Arguments to EDI-BLOCK-DEVICE's read() and write() methods. */ -edi_variable_declaration_t blockdev_read_write_arguments[3] = {{"pointer void","blockdev",1}, - {"pointer void","buffer",1}, - {"unsigned int32_t","blocks",1}}; -/*!\brief Arguments to EDI-BLOCK-DEVICE's seek() method. */ -edi_variable_declaration_t blockdev_seek_arguments[3] = {{"pointer void","blockdev",1}, - {"int32_t","offset",1}, - {"int32_t","whence",1}}; -/*!\brief Declaration of the methods of EDI-BLOCK-DEVICE, read(), write(), seek(), and get_block_size(). - * - * The code pointers of these function declarations are all given as NULL. Driver developers implementing EDI-BLOCK-DEVICE should fill - * these entries in with pointers to their own functions. */ -edi_function_declaration_t blockdev_methods[4] = {{"int32_t","edi_blockdev_read",0,3,blockdev_read_write_arguments,NULL}, - {"int32_t","edi_blockdev_write",0,3,blockdev_read_write_arguments,NULL}, - {"int32_t","edi_blockdev_seek",0,3,blockdev_seek_arguments,NULL}, - {"unsigned int32_t","edi_blockdev_get_block_size",0,0,NULL,NULL}}; -/*!\brief Declaration of the EDI-BLOCK-DEVICE class. - * - * Driver developers implementing this class should fill in their own values for constructor, destructor, and possibly even parent - * before passing the filled-in structure to the EDI runtime. */ -edi_class_declaration_t blockdev_class = {"EDI-BLOCK-DEVICE",0,4,blockdev_methods,NULL,NULL,NULL}; -#else -extern edi_class_declaration_t blockdev_class; // Declare for non main files -#endif - -#endif diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_dma_streams.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_dma_streams.h deleted file mode 100644 index 8ab80ccbff472552c5c7de2b6f4efdf7aaa9e074..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/edi/edi_dma_streams.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef EDI_DMA_STREAMS_H - -/* Copyright (c) 2006 Eli Gottlieb. - * Permission is granted to copy, distribute and/or modify this document - * under the terms of the GNU Free Documentation License, Version 1.2 - * or any later version published by the Free Software Foundation; - * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover - * Texts. A copy of the license is included in the file entitled "COPYING". */ - -#define EDI_DMA_STREAMS_H - -/*! \file edi_dma_streams.h - * \brief EDI's stream subclass for handling Direct Memory Access hardware. - * - * Data structures and algorithms this header represents: - * - * DATA STRUCTURE: DMA STREAMS - DMA streams are objects of the class EDI-STREAM-DMA used to pass data between a buffer of - * memory and the computer's DMA hardware. It is the responsibility of the object to allocate memory for its stream memory buffer - * which can be used with DMA hardware and to program the DMA hardware for transmissions. DMA streams can be bidirectional if the - * correct DMA mode is used. */ - -#include "edi_objects.h" - -#define DMA_STREAM_CLASS "EDI-STREAM-DMA" - -/*! \brief The name of the EDI DMA stream class. - * - * An edi_string_t with the class name "EDI-STREAM-DMA" in it. */ -#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI) -const edi_string_t dma_stream_class = DMA_STREAM_CLASS; -#else -extern const edi_string_t dma_stream_class; -#endif - -#ifndef IMPLEMENTING_EDI -/*! \brief int32_t EDI-STREAM-DMA.init_dma_stream(unsigned int32_t channel,unsigned int32_t mode,unsigned int32_t buffer_pages); - * - * Pointer to the init_dma_stream() method of class EDI-STREAM-DMA, which initializes a DMA stream with a DMA channel, DMA mode, and - * the number of DMA-accessible memory pages to keep as a buffer. It will only work once per stream object. It's possible return - * values are 1 for sucess, -1 for invalid DMA channel, -2 for invalid DMA mode, -3 for inability to allocate enough buffer pages and - * 0 for all other errors. */ -EDI_DEFVAR int32_t (*init_dma_stream)(object_pointer stream, uint32_t channel, uint32_t mode, uint32_t buffer_pages); -/*! \brief int32_t EDI-STREAM-DMA.transmit(data_pointer *anchor,unsigned int32 num_bytes,bool sending); - * - * Pointer to the dma_stream_transmit() method of class EDI-STREAM-DMA, which transmits the given number of bytes of data through - * the DMA stream to/from the given anchor (either source or destination), in the given direction. It returns 1 on success, -1 on - * an uninitialized or invalid DMA stream object, -2 when the anchor was NULL or otherwise invalid, -3 if the DMA stream can't - * transmit in the given direction, and 0 for all other errors. */ -EDI_DEFVAR int32_t (*dma_stream_transmit)(object_pointer stream, data_pointer anchor, uint32_t num_bytes, bool sending); -#endif - -#endif diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_interrupts.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_interrupts.h deleted file mode 100644 index ef2ffc9f0887e5eb627658acede34fac9776e3fb..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/edi/edi_interrupts.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef EDI_INTERRUPTS_H - -/* Copyright (c) 2006 Eli Gottlieb. - * Permission is granted to copy, distribute and/or modify this document - * under the terms of the GNU Free Documentation License, Version 1.2 - * or any later version published by the Free Software Foundation; - * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover - * Texts. A copy of the license is included in the file entitled "COPYING". */ - -#define EDI_INTERRUPTS_H - -/*! \file edi_interrupts.h - * \brief Declaration and description of EDI's interrupt handling class. - * - * Data structures and algorithms this header represents: - * DATA STRUCTURE AND ALGORITHM: INTERRUPT OBJECTS - The class EDI-INTERRUPT encapsulates the handling of machine interrupts. - * It is initialized with an interrupt number to handle and a handler routine to call when that interrupt occurs. Only a couple of - * guarantees are made to the driver regarding the runtime's implementation of interrupt handling: 1) That the driver's handler is - * called for every time the interrupt associated with a valid and initialized interrupt object occurs, in the order of the - * occurences, 2) That the runtime handle the architecture-specific (general to the entire machine, not just this device) - * end-of-interrupt code when the driver is called without first returning from the machine interrupt. Note that the runtime hands - * out interrupt numbers at its own discretion and policy. */ - -#include "edi_objects.h" - -/*! \brief Macro constant containing the name of the interrupt class - */ -#define INTERRUPTS_CLASS "EDI-INTERRUPT" -/*! \brief The name of EDI's interrupt-handling class. - * - * An edi_string_t holding the name of the runtime-implemented interrupt object class. It's value is "EDI-INTERRUPT". */ -#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI) -const edi_string_t interrupts_class = INTERRUPTS_CLASS; -#else -extern const edi_string_t interrupts_class; -#endif - -/*! \brief A pointer to an interrupt handling function. - * - * A pointer to a function called to handle interrupts. Its unsigned int32_t parameter is the interrupt number that is being - * handled. */ -typedef void (*interrupt_handler_t)(uint32_t interrupt_number); - -#ifndef IMPLEMENTING_EDI -/*! \brief Initializes an interrupt object with an interrupt number and a pointer to a handler function. - * - * A pointer to the init_interrupt() method of class EDI-INTERRUPT. This method initializes a newly-created interrupt object with an - * interrupt number and a pointer to the driver's handler of type interrupt_handler_t. It can only be called once per object, and - * returns 1 on success, fails with -1 when the interrupt number is invalid or unacceptable to the runtime, fails with -2 when the - * pointer to the driver's interrupt handler is invalid, and fails with -3 for all other errors. */ -EDI_DEFVAR int32_t (*init_interrupt)(object_pointer interrupt, uint32_t interrupt_number, interrupt_handler_t handler); -/*! \brief Get this interrupt object's interrupt number. */ -EDI_DEFVAR uint32_t (*interrupt_get_irq)(object_pointer interrupt); -/*! \brief Set a new handler for this interrupt object. */ -EDI_DEFVAR void (*interrupt_set_handler)(object_pointer interrupt, interrupt_handler_t handler); -/*! \brief Return from this interrupt, letting the runtime run any necessary End-Of-Interrupt code. - * - * A pointer to the interrupt_return() method of class EDI-INTERRUPT. This method returns from the interrupt designated by the - * calling interrupt object. If there is a machine-wide end-of-interrupt procedure and the driver was called during the handling of - * the machine interrupt (as opposed to delaying the handling and letting the runtime EOI), the runtime runs it during this method. - * This method has no return value, since once it's called control leaves the calling thread. */ -EDI_DEFVAR void (*interrupt_return)(object_pointer interrupt); -#endif - -#endif diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_memory_mapping.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_memory_mapping.h deleted file mode 100644 index ba8dff357b424ac9fc40b60342af4046ec65dcb9..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/edi/edi_memory_mapping.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef EDI_MEMORY_MAPPING_H - -/* Copyright (c) 2006 Eli Gottlieb. - * Permission is granted to copy, distribute and/or modify this document - * under the terms of the GNU Free Documentation License, Version 1.2 - * or any later version published by the Free Software Foundation; - * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover - * Texts. A copy of the license is included in the file entitled "COPYING". */ - -#define EDI_MEMORY_MAPPING_H - -/*! \file edi_memory_mapping.h - * \brief Declaration and description of EDI's class for mapping physical pages into the driver's address space. - * - * Data structures and algorithms this header represents: - * ALGORITHM: MEMORY MAPPINGS - Memory mapping objects of the class EDI-MEMORY-MAPPING are used to give virtual (driver-visible) - * addresses to sections of physical memory. These can either be memory mappings belonging to hardware devices or plain RAM which - * the driver wants page-aligned. A memory mapping object is initialized with the physical address for the memory mapping and the - * number of pages the mapping takes up, or simply the desired length of the a physically contiguous buffer in pages. The class's - * two methods map the section of memory into and out of the driver's virtual address space. */ - -#include "edi_objects.h" - -/*! \brief The name of EDI's memory mapping class. - * - * An edi_string_t with the name of the memory mapping class, "EDI-MEMORY-MAPPING". */ -#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI) -const edi_string_t memory_mapping_class = "EDI-MEMORY-MAPPING"; -#else -extern const edi_string_t memory_mapping_class; -#endif - -/*! \brief Flag representing Strong Uncacheable caching method. */ -#define CACHING_STRONG_UNCACHEABLE 0 -/*! \brief Flag representing Uncacheable caching method. */ -#define CACHING_UNCACHEABLE 1 -/*! \brief Flag representing Write combining caching method. */ -#define CACHING_WRITE_COMBINING 2 -/*! \brief Flag representing Write Through caching method. */ -#define CACHING_WRITE_THROUGH 3 -/*! \brief Flag representing Write Back caching method. */ -#define CACHING_WRITE_BACK 3 -/*! \brief Flag representing Write Protected caching method. */ -#define CACHING_WRITE_PROTECTED 3 - -#ifndef IMPLEMENTING_EDI -/*! \brief Initialize an EDI-MEMORY-MAPPING object with a physical address range. - * - * This method takes the start_physical_address of a memory mapping and the number of pages in that mapping and uses these arguments - * to initialize an EDI-MEMORY-MAPPING object. It can only be called once per object. It returns 1 when successful, -1 when an - * invalid physical address is given (one that the runtime knows is neither a physical memory mapping belonging to a device nor - * normal RAM), -2 when the number of pages requested is bad (for the same reasons as the starting address can be bad), and 0 for - * all other errors. - * - * Note that this method can't be invoked on an object which has already initialized via init_memory_mapping_with_pages(). */ -EDI_DEFVAR int32_t (*init_memory_mapping_with_address)(object_pointer mapping, data_pointer start_physical_address, uint32_t pages); -/*! \brief Initialize an EDI-MEMORY-MAPPING object by requesting a number of new physical pages. - * - * This method takes a desired number of physical pages for a memory mapping, and uses that number to initialize an - * EDI-MEMORY-MAPPING object by creating a buffer of contiguous physical pages. It can only be called once per object. It returns - * 1 when successful, -1 when the request for pages cannot be fulfilled, and 0 for all other errors. - * - * Note that this method cannot be called if init_memory_mapping_with_address() has already been used on the given object. */ -EDI_DEFVAR int32_t (*init_memory_mapping_with_pages)(object_pointer mapping, uint32_t pages); -/*! \brief Map the memory-mapping into this driver's visible address space. - * - * This asks the runtime to map a given memory mapping into the driver's virtual address space. Its parameter is the address of a - * data_pointer to place the virtual address of the mapping into. This method returns 1 on success, -1 on an invalid argument, -2 - * for an uninitialized object, and 0 for all other errors. */ -EDI_DEFVAR int32_t (*map_in_mapping)(object_pointer mapping, data_pointer *address_mapped_to); -/*! \brief Unmap the memory mapping from this driver's visible address space. - * - * This method tries to map the given memory mapping out of the driver's virtual address space. It returns 1 for success, -1 - * for an uninitialized memory mapping object, -2 if the mapping isn't mapped into the driver's address space already, and 0 - * for all other errors. */ -EDI_DEFVAR int32_t (*map_out_mapping)(object_pointer mapping); - -/*! \brief Set the caching flags for a memory mapping. */ -EDI_DEFVAR void (*mapping_set_caching_method)(object_pointer mapping, uint32_t caching_method); -/*! \brief Get the current caching method for a memory mapping. */ -EDI_DEFVAR uint32_t (*mapping_get_caching_method)(object_pointer mapping); -/*! \brief Flush write-combining buffers on CPU to make sure changes to memory mapping actually get written. Only applies to a Write Combining caching method (I think.).*/ -EDI_DEFVAR void (*flush_write_combining_mapping)(object_pointer mapping); -#endif - -#endif diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_objects.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_objects.h deleted file mode 100644 index 0e479517b74903e9902de8eeb9ecbd7d44198bc0..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/edi/edi_objects.h +++ /dev/null @@ -1,257 +0,0 @@ -#ifndef EDI_OBJECTS_H - -/* Copyright (c) 2006 Eli Gottlieb. - * Permission is granted to copy, distribute and/or modify this document - * under the terms of the GNU Free Documentation License, Version 1.2 - * or any later version published by the Free Software Foundation; - * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover - * Texts. A copy of the license is included in the file entitled "COPYING". */ - -#define EDI_OBJECTS_H - -/*! \file edi_objects.h - * \brief The header file for basic EDI types and the object system. - * - * This file contains declarations of EDI's primitive data types, as well as structures and functions for with the object system. - * It represents these data structures and algorithms: - * - * DATA STRUCTURE: THE CLASS LIST - EDI implementing runtime's must keep an internal list of classes implemented by the runtime - * and separate lists of classes implemented by each driver. Whoever implements a class is said to "own" that class. The - * internal format of this list is up to the runtime coders, but it must be possible to recreate the original list of - * edi_class_declaration structures the driver declared to the runtime from it. This list is declared to the runtime in an - * initialization function in the header edi.h. The object_class member of an edi_object_metadata structure must point to that - * object's class's entry in this list. - * - * ALGORITHM AND DATA STRUCTURE: CLASSES AND INHERITANCE - Classes are described using edi_class_declaration_t structures and - * follow very simple rules. All data is private and EDI provides no way to access instance data, so there are no member - * variable declarations. However, if the data isn't memory-protected (for example, driver data on the driver heap) EDI allows - * the possibility of pointer access to data, since runtime and driver coders could make use of that behavior. Classes may have - * one ancestor by declaring so in their class declaration structure, and if child methods are different then parent methods - * the children always override their parents. An EDI runtime must also be able to check the existence and ownership of a given - * class given its name in an edi_string_t. - * - * ALGORITHM: OBJECT CREATION AND DESTRUCTION - An EDI runtime should be able to call the constructor of a named class, put the - * resulting object_pointer into an edi_object_metadata_t and return that structure. The runtime should also be able to call an - * object's class's destructor when given a pointer to a valid edi_metadata_t for an already-existing object. Data equivalent - * to an edi_object_metadata_t should also be tracked by the runtime for every object in existence in case of sudden EDI shutdown - * (see edi.h). - * - * ALGORITHM: RUNTIME TYPE INFORMATION - When passed the data_pointer member of an edi_object_metadata_t to a valid object, an - * EDI runtime must be able to return an edi_string_t containing the name of that object's class and to return function_pointers - * to methods when the required information to find the correct method is given by calling a class's method getting function.*/ - -/* If the EDI headers are linked with the standard C library, they use its type definitions. Otherwise, equivalent definitions are - * made.*/ -#if __STDC_VERSION__ == 199901L -# include <stdbool.h> -# include <stdint.h> -#else -# ifndef NULL -# define NULL ((void*)0) -# endif -typedef unsigned char bool; -# define true 1 -# define false 0 -typedef char int8_t; -typedef short int16_t; -typedef long int32_t; -typedef long long int64_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned long uint32_t; -typedef unsigned long long uint64_t; -#endif - -/*! \brief Define a variable in the header - */ -#ifdef EDI_MAIN_FILE -# define EDI_DEFVAR -#else -# define EDI_DEFVAR extern -#endif - -/*! \brief A pointer to the in-memory instance of an object. - * - * This type is sized just like a general C pointer type (whatever*) for the target architecture. It's passed as a first parameter - * to all methods, thus allowing EDI classes to be implemented as C++ classes and providing some protection from confusing objects - * with normal pointers. Equivalent to a C++ this pointer or an Object Pascal Self argument. */ -typedef void *object_pointer; -/*! \brief A basic pointer type pointing to arbitrary data in an arbitrary location. */ -typedef void *data_pointer; -/*! \brief A basic function pointer type. - * - * A pointer to a piece of code which can be called and return to its caller, used to distinguish between pointers to code and - * pointers to data. Its size is hardware-dependent. */ -typedef void (*function_pointer)(void); -/*! \brief The length of an EDI string without its null character. */ -#define EDI_STRING_LENGTH 31 -/*! \brief A type representing a 31-character long string with a terminating NULL character at the end. All of EDI uses this type - * for strings. - * - * A null-terminated string type which stores characters in int8s. It allows for 31 characters in each string, with the final - * character being the NULL terminator. Functions which use this type must check that its final character is NULL, a string which - * doesn't not have this property is invalid and insecure. I (the author of EDI) know and understand that this form of a string - * suffers from C programmer's disease, but I can't use anything else without either making string use far buggier or dragging - * everyone onto a better language than C. */ -typedef int8_t edi_string_t[0x20]; -/*! \brief A type representing a pointer form of #edi_string_t suitable for function returns - */ -typedef int8_t *edi_string_ptr_t; - -/*! \var EDI_BASE_TYPES - * \brief A constant array of edi_string_t's holding every available EDI primitive type. */ -/*! \var EDI_TYPE_MODIFIERS - * \brief A constant array of edi_string_t's holding available modifiers for EDI primitive types. */ -#ifdef IMPLEMENTING_EDI - const edi_string_t EDI_BASE_TYPES[9] = {"void","bool","int8_t","int16_t","int32_t","int64_t","function_pointer","intreg","edi_string_t"}; - const edi_string_t EDI_TYPE_MODIFIERS[2] = {"pointer","unsigned"}; -#else - //extern const edi_string_t EDI_BASE_TYPES[9] = {"void","bool","int8_t","int16_t","int32_t","int64_t","function_pointer","intreg", "edi_string_t"}; - //extern const edi_string_t EDI_TYPE_MODIFIERS[2] = {"pointer","unsigned"}; - extern const edi_string_t EDI_BASE_TYPES[9]; - extern const edi_string_t EDI_TYPE_MODIFIERS[2]; -#endif - -/*! \struct edi_object_metadata_t - * \brief A packed structure holding all data to identify an object to the EDI object system. */ -typedef struct { - /*! \brief Points to the instance data of the object represented by this structure. - * - * An object_pointer to the object this structure refers to. The this pointer, so to speak. */ - object_pointer object; - /*! \brief Points the internal record kept by the runtime describing the object's class. - * - * Points to wherever the runtime has stored the class data this object was built from. The class data doesn't need to be - * readable to the driver, and so this pointer can point to an arbitrary runtime-reachable location. */ - data_pointer object_class; -} edi_object_metadata_t; - -/*! \struct edi_variable_declaration_t - * \brief The data structure used to describe a variable declaration to the EDI object system. - * - * The data structure used to describe a variable declaration to the EDI object system. The context of the declaration depends on - * where the data structure appears, ie: alone, in a class declaration, in a parameter list, etc. */ -typedef struct { - /*! \brief The type of the declared variable. - * - * The type of the variable, which must be a valid EDI primitive type as specified in the constant EDI_BASE_TYPES and - * possibly modified by a modifier specified in the constant EDI_TYPE_MODIFIERS. */ - edi_string_t type; - /*! \brief The name of the declared variable. */ - edi_string_t name; - /*! \brief Number of array entries if this variable is an array declaration. - * - * An int32_t specifying the number of variables of 'type' in the array 'name'. For a single variable this value should - * simply be set to 1, for values greater than 1 a packed array of contiguous variables is being declared, and a value of 0 - * is invalid. */ - int32_t array_length; -} edi_variable_declaration_t; - -/*! \struct edi_function_declaration_t - * \brief The data structure used to declare a function to the EDI object system. */ -typedef struct { - /*! \brief The return type of the function. The same type rules which govern variable definitions apply here. */ - edi_string_t return_type; - /*! \brief The name of the declared function. */ - edi_string_t name; - /*! \brief The version number of the function, used to tell different implementations of the same function apart. */ - uint32_t version; - /*! \brief The number of arguments passed to the function. - * - * The number of entries in the member arguments that the object system should care about. Caring about less misses - * parameters to functions, caring about more results in buffer overflows. */ - uint32_t num_arguments; - /*! \brief An array of the declared function's arguments. - * - * A pointer to an array num_arguments long containing edi_variable_declaration_t's for each argument to the declared - * function.*/ - edi_variable_declaration_t *arguments; - /*!\brief A pointer to the declared function's code in memory. */ - function_pointer code; -} edi_function_declaration_t; - -/*! \brief A pointer to a function for constructing instances of a class. - * - * A pointer to a function which takes no parameters and returns an object_pointer pointing to the newly made instance of a class. - * It is the constructor's responsibility to allocate memory for the new object. Each EDI class needs one of these. */ -typedef object_pointer (*edi_constructor_t)(void); -/*! \brief A pointer to a function for destroying instances of a class. - * - * A pointer to a function which takes an object_pointer as a parameter and returns void. This is the destructor counterpart to a - * class's edi_constructor_t, it destroys the object pointed to by its parameter and frees the object's memory. Every class must - * have one */ -typedef void (*edi_destructor_t)(object_pointer); - -/*! \brief Information the driver must give the runtime about its classes so EDI can construct them and call their methods. - * - * A structure used to declare a class to an EDI runtime so instances of it can be constructed by the EDI object system. */ -typedef struct { - /*! \brief The name of the class declared by the structure. */ - edi_string_t name; - /*! \brief The version of the class. This number is used to tell identically named but differently - * implemented classes apart.*/ - uint32_t version; - /*! \brief The number of methods in the 'methods' function declaration array. */ - uint32_t num_methods; - /*! \brief An array of edi_function_declaration_t declaring the methods of this class. */ - edi_function_declaration_t *methods; - /*! \brief Allocates the memory for a new object of the declared class and constructs the object. Absolutely required.*/ - edi_constructor_t constructor; - /*! \brief Destroys the given object of the declared class and frees its memory. Absolutely required. */ - edi_destructor_t destructor; - /*! \brief A pointer to another EDI class declaration structure specifying the declared class's parent class. - * - * Points to a parent class declared in another class declaration. It can be NULL to mean this class has no parent. */ - struct edi_class_declaration_t *parent; -} edi_class_declaration_t; - -/*! \brief Checks the existence of the named class. - * - * This checks for the existence on THE CLASS LIST of the class named by its edi_string_t parameter and returns a signed int32_t. If - * the class isn't found (ie: it doesn't exist as far as EDI is concerned) -1 is returned, if the class is owned by the driver - * (implemented by the driver and declared to the runtime by the driver) 0, and if the class is owned by the runtime (implemented by - * the runtime) 1. */ -int32_t check_class_existence(edi_string_t class_name); -/*! \brief Constructs an object of the named class and returns its object_pointer and a data_pointer to its class data. - * - * Given a valid class name in an edi_string_t this function constructs the specified class and returns an edi_metadata_t describing - * the new object as detailed in OBJECT CREATION AND DESTRUCTION. If the construction fails it returns a structure full of NULL - * pointers. */ -edi_object_metadata_t construct_object(edi_string_t class_name); -/*! \brief Destroys the given object using its class data. - * - * As specified in OBJECT CREATION AND DESTRUCTION this function should destroy an object when given its valid edi_metadata_t. The - * destruction is accomplished by calling the class's destructor. */ -void destroy_object(edi_object_metadata_t object); -/*! \brief Obtains a function pointer to a named method of a given class. - * - * When given a valid data_pointer object_class from an edi_object_metadata_t and an edi_string_t representing the name of the - * desired method retrieves a function_pointer to the method's machine code in memory. If the desired method isn't found, NULL is - * returned. */ -function_pointer get_method_by_name(data_pointer object_class,edi_string_t method_name); -/*! \brief Obtains a function pointer to a method given by a declaration of the given class if the class's method matches the - * declaration. - * - * Works just like get_method_by_name(), but by giving an edi_function_declaration_t for the desired method instead of just its name. - * Performs detailed checking against THE CLASS LIST to make sure that the method returned exactly matches the declaration passed - * in. */ -function_pointer get_method_by_declaration(data_pointer object_class,edi_function_declaration_t declaration); - -/* Runtime typing information. */ -/*! \brief Returns the name of the class specified by a pointer to class data. - * - * Given the data_pointer to an object's class data as stored in an edi_object_metadata_t retrieves the name of the object's class - * and returns it in an edi_string_t. */ -edi_string_ptr_t get_object_class(data_pointer object_class); -/*! \brief Returns the name of a class's parent class. - * - * When given an edi_string_t with a class name in it, returns another edi_string_t containing the name of the class's parent, or an - * empty string. */ -edi_string_ptr_t get_class_parent(edi_string_t some_class); -/*! \brief Returns the internal class data of a named class (if it exists) or NULL. - * - * When given an edi_string_t with a valid class name in it, returns a pointer to the runtime's internal class data for that class. - * Otherwise, it returns NULL. */ -data_pointer get_internal_class(edi_string_t some_class); - -#endif diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_port_io.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_port_io.h deleted file mode 100644 index a2a1773d6252197f2b165441802ccc928614a769..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/edi/edi_port_io.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef EDI_PORT_IO_H - -/* Copyright (c) 2006 Eli Gottlieb. - * Permission is granted to copy, distribute and/or modify this document - * under the terms of the GNU Free Documentation License, Version 1.2 - * or any later version published by the Free Software Foundation; - * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover - * Texts. A copy of the license is included in the file entitled "COPYING". */ - -/* Modified by thePowersGang (John Hodge) - * - Surround variable definitions with an #ifdef IMPLEMENTING_EDI - */ - -#define EDI_PORT_IO_H - -/*! \file edi_port_io.h - * \brief Declaration and description of EDI's port I/O class. - * - * Data structures and algorithms this header represents: - * - * DATA STRUCTURE AND ALGORITHM: PORT I/O OBJECTS - A class named "EDI-IO-PORT" is defined as an encapsulation of the port I/O - * used on some machine architectures. Each object of this class represents a single I/O port which can be read from and written to - * in various sizes. Each port can be held by one object only at a time. */ - -#include "edi_objects.h" - -/*! \brief Macro to create methods for reading from ports. - * - * This macro creates four similar methods, differing in the size of the type they read from the I/O port held by the object. Their - * parameter is a pointer to the output type, which is filled with the value read from the I/O port. They return 1 for success, -1 - * for an uninitialized I/O port object, and 0 for other errors. */ -#define port_read_method(type,name) int32_t (*name)(object_pointer port_object, type *out) -/*! \brief Macro to create methods for writing to ports. - * - * This macro creates four more similar methods, differing in the size of the type they write to the I/O port held by the object. - * Their parameter is the value to write to the port. They return 1 for success, -1 for an uninitialized I/O port object and 0 for - * other errors. */ -#define port_write_method(type,name) int32_t (*name)(object_pointer port_object, type in) - -/*! \brief Name of EDI I/O port class. (Constant) - * - * A CPP constant with the value of #io_port_class */ -#define IO_PORT_CLASS "EDI-IO-PORT" -/*! \brief Name of EDI I/O port class. - * - * An edi_string_t containing the class name "EDI-IO-PORT". */ -#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI) -const edi_string_t io_port_class = IO_PORT_CLASS; -#else -extern const edi_string_t io_port_class; -#endif - -#ifndef IMPLEMENTING_EDI -/*! \brief int32_t EDI-IO-PORT.init_io_port(unsigned int16_t port); - * - * This method takes an unsigned int16_t representing a particular I/O port and initializes the invoked EDI-IO-PORT object with it. - * The method returns 1 if successful, -1 if the I/O port could not be obtained for the object, and 0 for all other errors. */ -EDI_DEFVAR int32_t (*init_io_port)(object_pointer port_object, uint16_t port); -/*! \brief Get the port number from a port object. */ -EDI_DEFVAR uint16_t (*get_port_number)(object_pointer port); -/*! \brief Method created by port_read_method() in order to read bytes (int8s) from I/O ports. */ -EDI_DEFVAR int32_t (*read_byte_io_port)(object_pointer port_object, int8_t *out); -/*! \brief Method created by port_read_method() in order to read words (int16s) from I/O ports. */ -EDI_DEFVAR int32_t (*read_word_io_port)(object_pointer port_object, int16_t *out); -/*! \brief Method created by port_read_method() in order to read longwords (int32s) from I/O ports. */ -EDI_DEFVAR int32_t (*read_long_io_port)(object_pointer port_object, int32_t *out); -/*! \brief Method created by port_read_method() in order to read long longwords (int64s) from I/O ports. */ -EDI_DEFVAR int32_t (*read_longlong_io_port)(object_pointer port_object,int64_t *out); -/*! \brief Method of EDI-IO-PORT to read long strings of data from I/O ports. - * - * Reads arbitrarily long strings of data from the given I/O port. Returns 1 for success, -1 for an uninitialized port object, -2 - * for a bad pointer to the destination buffer, and 0 for all other errors. */ -EDI_DEFVAR int32_t (*read_string_io_port)(object_pointer port_object, uint32_t data_length, uint8_t *out); -/*! \brief Method created by port_write_method() in order to write bytes (int8s) to I/O ports. */ -EDI_DEFVAR int32_t (*write_byte_io_port)(object_pointer port_object, int8_t in); -/*! \brief Method created by port_write_method() in order to write words (int16s) to I/O ports. */ -EDI_DEFVAR int32_t (*write_word_io_port)(object_pointer port_object, int16_t in); -/*! \brief Method created by port_write_method() in order to write longwords (int32s) to I/O ports. */ -EDI_DEFVAR int32_t (*write_long_io_port)(object_pointer port_object, int32_t in); -/*! \brief Method created by port_write_method() in order to write long longwords (int64s) to I/O ports. */ -EDI_DEFVAR int32_t (*write_longlong_io_port)(object_pointer port_object, int64_t in); -/*! \brief Method of EDI-IO-PORT to write long strings of data to I/O ports. - * - * Writes arbitrarily long strings of data to the given I/O port. Returns 1 for success, -1 for an uninitialized port object, -2 - * for a bad pointer to the source buffer, and 0 for all other errors. */ -EDI_DEFVAR int32_t (*write_string_io_port)(object_pointer port_object, uint32_t data_length, uint8_t *in); - -#endif // defined(IMPLEMENTING_EDI) - -#endif diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_pthreads.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_pthreads.h deleted file mode 100644 index c21fa75195a7820167c79f0fd761416f92173d28..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/edi/edi_pthreads.h +++ /dev/null @@ -1,175 +0,0 @@ -#ifndef EDI_PTHREADS - -/* Copyright (c) 2006 Eli Gottlieb. - * Permission is granted to copy, distribute and/or modify this document - * under the terms of the GNU Free Documentation License, Version 1.2 - * or any later version published by the Free Software Foundation; - * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover - * Texts. A copy of the license is included in the file entitled "COPYING". */ - -#define EDI_PTHREADS -/*!\file edi_pthreads.h - * \brief A basic subset of POSIX Threads functionality, providing threading and thread synchronization. - * - * A very basic POSIX Threads interface. Note that pthreads are not a class, because none of these calls really gels with - * object-oriented programming. Also, if drivers aren't processes or threads under the implementing operating system a small - * threading system must be implemented in-runtime just to multiplex the pthreads of EDI drivers. Sorry about that. - * - * Data structures and algorithms this header represents: - * - * ALGORITHM AND DATA STRUCTURE: POSIX Threading - The runtime must provide enough of a POSIX threading interface to implement - * the calls described here. The actual multithreading must be performed by the runtime, and the runtime can implement that - * multithreading however it likes as long as the given POSIX Threads subset works. There is, however, a caveat: since the runtime - * calls the driver like it would a library, the driver must perceive all calls made to it by the runtime as running under one thread. - * From this thread the driver can create others. Such behavior is a quirk of EDI, and does not come from the POSIX standard. - * However, it is necessary to provide the driver with a thread for its own main codepaths. For further details on a given POSIX - * Threading routine, consult its Unix manual page. */ - -#include "edi_objects.h" - -/* Placeholder type definitions. Users of the PThreads interface only ever need to define pointers to these types. */ -/*!\brief Opaque POSIX Threading thread attribute type. */ -typedef void pthread_attr_t; -/*!\brief Opaque POSIX Threading mutex (mutual exclusion semaphore) type. */ -typedef void pthread_mutex_t; -/*!\brief Opaque POSIX Threading mutex attribute type. */ -typedef void pthread_mutex_attr_t; - -/*!\struct sched_param - * \brief POSIX Threading scheduler parameters for a thread. */ -typedef struct { - /*!\brief The priority of the thread. */ - int32_t sched_priority; -} sched_param; - -/*!\brief POSIX Threading thread identifier. */ -typedef uint32_t pthread_t; -/*!\brief POSIX Threading thread function type. - * - * A function pointer to a thread function, with the required signature of a thread function. A thread function takes one untyped - * pointer as an argument and returns an untyped pointer. Such a function is a thread's main routine: it's started with the thread, - * and the thread exits if it returns. */ -typedef void *(*pthread_function_t)(void*); - -/*!\brief Insufficient resources. */ -#define EAGAIN -1 -/*!\brief Invalid parameter. */ -#define EINVAL -2 -/*!\brief Permission denied. */ -#define EPERM -3 -/*!\brief Operation not supported. */ -#define ENOTSUP -4 -/*!\brief Priority scheduling for POSIX/multiple schedulers is not implemented. */ -#define ENOSYS -5 -/*!\brief Out of memory. */ -#define ENOMEM -6 -/*!\brief Deadlock. Crap. */ -#define EDEADLK -7 -/*!\brief Busy. Mutex already locked. */ -#define EBUSY -8 - -/*!\brief Scheduling policy for regular, non-realtime scheduling. The default. */ -#define SCHED_OTHER 0 -/*!\brief Real-time, first-in first-out scheduling policy. Requires special (superuser, where such a thing exists) permissions. */ -#define SCHED_FIFO 1 -/*!\brief Real-time, round-robin scheduling policy. Requires special (superuser, where such a thing exists) permissions. */ -#define SCHED_RR 0 - -/*!\brief Creates a new thread with the given attributes, thread function and arguments, giving back the thread ID of the new - * thread. - * - * pthread_create() creates a new thread of control that executes concurrently with the calling thread. The new thread applies the - * function start_routine, passing it arg as its argument. The attr argument specifies thread attributes to apply to the new thread; - * it can also be NULL for the default thread attributes (joinable with default scheduling policy). On success this function returns - * 0 and places the identifier of the new thread into thread_id. On an error, pthread_create() can return EAGAIN if insufficient - * runtime resources are available to create the requested thread, EINVAL a value specified by attributes is invalid, or EPERM if the - * caller doesn't have permissions to set the given attributes. - * - * For further information: man 3 pthread_create */ -int32_t pthread_create(pthread_t *thread_id, const pthread_attr_t *attributes, pthread_function_t thread_function, void *arguments); -/*!\brief Terminates the execution of the calling thread. The thread's exit code with by status, and this routine never returns. */ -void pthread_exit(void *status); -/*!\brief Returns the thread identifier of the calling thread. */ -pthread_t pthread_self(); -/*!\brief Compares two thread identifiers. - * - * Determines of the given two thread identifiers refer to the same thread. If so, returns non-zero. Otherwise, 0 is returned. */ -int32_t pthread_equal(pthread_t thread1, pthread_t thread2); -/*!\brief Used by the calling thread to relinquish use of the processor. The thread then waits in the run queue to be scheduled - * again. */ -void pthread_yield(); - -/*!\brief Gets the scheduling policy of the given attributes. - * - * Places the scheduling policy for attributes into policy. Returns 0 on success, EINVAL if attributes was invalid, and ENOSYS if - * priority scheduling/multiple scheduler support is not implemented. */ -int32_t pthread_attr_getschedpolicy(const pthread_attr_t *attributes, int32_t *policy); -/*!\brief Sets the scheduling policy of the given attributes. - * - * Requests a switch of scheduling policy to policy for the given attributes. Can return 0 for success, EINVAL if the given policy - * is not one of SCHED_OTHER, SCHED_FIFO or SCHED_RR or ENOTSUP if policy is either SCHED_FIFO or SCHED_RR and the driver is not - * running with correct privileges. */ -int32_t pthread_attr_setschedpolicy(pthread_attr_t *attributes, int32_t policy); - -/*!\brief Gets the scheduling paramaters (priority) from the given attributes. - * - * On success, stores scheduling parameters in param from attributes, and returns 0. Otherwise, returns non-zero error code, such - * as EINVAL if the attributes object is invalid. */ -int32_t pthread_attr_getschedparam(const pthread_attr_t *attributes, sched_param *param); -/*!\brief Sets the scheduling parameters (priority) of the given attributes. - * - * Requests that the runtime set the scheduling parameters (priority) of attributes from param. Returns 0 for success, EINVAL for an - * invalid attributes object, ENOSYS when multiple schedulers/priority scheduling is not implemented, and ENOTSUP when the value of - * param isn't supported/allowed. */ -int32_t pthread_attr_setschedparam(pthread_attr_t *attributes, const sched_param *param); - -/*!\brief The thread obtains its scheduling properties explicitly from its attributes structure. */ -#define PTHREAD_EXPLICIT_SCHED 1 -/*!\brief The thread inherits its scheduling properties from its parent thread. */ -#define PTHREAD_INHERIT_SCHED 0 - -/*!\brief Returns the inheritsched attribute of the given attributes. - * - * On success, returns 0 and places the inheritsched attribute from attributes into inherit. This attribute specifies where the - * thread's scheduling properites shall come from, and can be set to PTHREAD_EXPLICIT_SCHED or PTHREAD_INHERIT_SCHED. On failure it - * returns EINVAL if attributes was invalid or ENOSYS if multiple schedulers/priority scheduling isn't implemented. */ -int32_t pthread_attr_getinheritsched(const pthread_attr_t *attributes, int32_t *inherit); -/*!\brief Sets the inheritsched attribute of the given attributes. - * - * On success, places inherit into the inheritsched attribute of attributes and returns 0. inherit must either contain - * PTHREAD_EXPLICIT_SCHED or PTHREAD_INHERIT_SCHED. On failure, this routine returns EINVAL if attributes is invalid, ENOSYS when - * multiple schedulers/priority scheduling isn't implemented, and ENOSUP if the inheritsched attribute isn't supported. */ -int32_t pthread_attr_setinheritsched(pthread_attr_t *attributes, int32_t inherit); - -/*!\brief Creates a new POSIX Threads mutex, which will initially be unlocked. - * - * Creates a new mutex with the given attributes. If attributes is NULL, the default attributes will be used. The mutex starts out - * unlocked. On success, the new mutex resides in the mutex structure pointed to by mutex, and this routine routines 0. On failure, - * it returns EAGAIN if the system lacked sufficient non-memory resources to initialize the mutex, EBUSY if the given mutex is - * already initialized and in use, EINVAL if either parameter is invalid, and ENOMEM if the system lacks the memory for a new - * mutex. Note: All EDI mutexes are created with the default attributes, and are of type PTHREAD_MUTEX_ERRORCHECK. This means - * undefined behavior can never result from an badly placed function call. */ -int32_t pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutex_attr_t *attributes); -/*!\brief Locks the given mutex. - * - * Locks the given mutex. If the mutex is already locked, blocks the calling thread until it can acquire the lock. When this - * routine returns successfully, it will return 0 and the calling thread will own the lock of the mutex. If the call fails, it can - * return EINVAL when mutex is invalid or EDEADLK if the calling thread already owns the mutex. */ -int32_t pthread_mutex_lock(pthread_mutex_t *mutex); -/*!\brief Unlocks the given mutex. - * - * Unlocks the given mutex, returning 0 on success. On failure, it can return EINVAL when mutex is invalid or EPERM when the - * calling thread doesn't own the mutex. */ -int32_t pthread_mutex_unlock(pthread_mutex_t *mutex); -/*!\brief Tries to lock the given mutex, returning immediately even if the mutex is already locked. - * - * Attempts to lock the given mutex, but returns immediately if it can't acquire a lock. Returns 0 when it has acquired a lock, - * EBUSY if the mutex is already locked, or EINVAL if mutex is invalid. */ -int32_t pthread_mutex_trylock(pthread_mutex_t *mutex); -/*!\brief Destroys the given mutex, or at least the internal structure of it. - * - * Deletes the given mutex, making mutex invalid until it should be initialized by pthread_mutex_init(). Returns 0 on success, - * EINVAL when mutex is invalid, or EBUSY when mutex is locked or referenced by another thread. */ -int32_t pthread_mutex_destroy (pthread_mutex_t *mutex); - -#endif diff --git a/KernelLand/Modules/Interfaces/EDI/edi/helpers.h b/KernelLand/Modules/Interfaces/EDI/edi/helpers.h deleted file mode 100644 index d7bc138898644c49cc4d9ea51ec0922cd99fbea4..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/edi/helpers.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef HELPERS_H - -#define HELPERS_H - -#include <edi.h> - -// Locally Defined -bool edi_string_equal(edi_string_t x,edi_string_t y); -bool descends_from(data_pointer object_class,edi_string_t desired_class); -data_pointer get_actual_class(edi_string_t ancestor,int32_t num_objects,edi_object_metadata_t *objects); - -// Local Copy/set -void *memcpyd(void *dest, void *src, unsigned int count); - -// Implementation Defined Common functions -void *memcpy(void *dest, void *src, unsigned int count); -void *memmove(void *dest, void *src, unsigned int count); -void *realloc(void *ptr, unsigned int size); - -#endif diff --git a/KernelLand/Modules/Interfaces/EDI/edi_int.inc.c b/KernelLand/Modules/Interfaces/EDI/edi_int.inc.c deleted file mode 100644 index 0ab3359e9de40573b072f5cee18f0eeefd5b123b..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/edi_int.inc.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * AcessOS EDI Interface - * - IRQ Class - * - * By John Hodge (thePowersGang) - * - * This file has been released into the public domain. - * You are free to use it as you wish. - */ -#include "edi/edi.h" - -// === TYPES === -typedef struct { - uint16_t State; // 0: Unallocated, 1: Allocated, 2: Initialised, (Bit 0x8000 set if in heap) - uint16_t Num; - interrupt_handler_t Handler; -} tEdiIRQ; - -// === PROTOTYPES === -void EDI_Int_IRQ_Handler(tRegs *Regs); - -// === GLOBALS === -tEdiIRQ gEdi_IRQObjects[16]; - -// === FUNCTIONS === -/** - * \fn object_pointer Edi_Int_IRQ_Construct(void) - * \brief Creates a new IRQ Object - * \return Pointer to object - */ -object_pointer Edi_Int_IRQ_Construct(void) -{ - int i; - // Search for a free irq - for( i = 0; i < 16; i ++ ) - { - if(gEdi_IRQObjects[i].State) continue; - gEdi_IRQObjects[i].State = 1; - gEdi_IRQObjects[i].Num = 0; - gEdi_IRQObjects[i].Handler = NULL; - return &gEdi_IRQObjects[i]; - } - return NULL; -} - -/** - * \fn void Edi_Int_IRQ_Destruct(object_pointer Object) - * \brief Destruct an IRQ Object - * \param Object Object to destroy - */ -void Edi_Int_IRQ_Destruct(object_pointer Object) -{ - tEdiIRQ *obj; - - VALIDATE_PTR(Object,); - obj = GET_DATA(Object); - - if( !obj->State ) return; - - if( obj->Handler ) - irq_uninstall_handler( obj->Num ); - - if( obj->State & 0x8000 ) { // If in heap, free - free(Object); - } else { // Otherwise, mark as unallocated - obj->State = 0; - } -} - -/** - * \fn int32_t Edi_Int_IRQ_InitInt(object_pointer Object, uint16_t Num, interrupt_handler_t Handler) - * \brief Initialises an IRQ - * \param Object Object Pointer (this) - * \param Num IRQ Number to use - * \param Handler Callback for IRQ - */ -int32_t Edi_Int_IRQ_InitInt(object_pointer Object, uint16_t Num, interrupt_handler_t Handler) -{ - tEdiIRQ *obj; - - //LogF("Edi_Int_IRQ_InitInt: (Object=0x%x, Num=%i, Handler=0x%x)\n", Object, Num, Handler); - - VALIDATE_PTR(Object,0); - obj = GET_DATA(Object); - - if( !obj->State ) return 0; - - if(Num > 15) return 0; - - // Install the IRQ if a handler is passed - if(Handler) { - if( !irq_install_handler(Num, Edi_Int_IRQ_Handler) ) - return 0; - obj->Handler = Handler; - } - - obj->Num = Num; - obj->State &= ~0x3FFF; - obj->State |= 2; // Set initialised flag - return 1; -} - -/** - * \fn uint16_t Edi_Int_IRQ_GetInt(object_pointer Object) - * \brief Returns the irq number associated with the object - * \param Object IRQ Object to get number from - * \return IRQ Number - */ -uint16_t Edi_Int_IRQ_GetInt(object_pointer Object) -{ - tEdiIRQ *obj; - - VALIDATE_PTR(Object,0); - obj = GET_DATA(Object); - - if( !obj->State ) return 0; - return obj->Num; -} - -/** - * \fn void EDI_Int_IRQ_SetHandler(object_pointer Object, interrupt_handler_t Handler) - * \brief Set the IRQ handler for an IRQ object - * \param Object IRQ Object to alter - * \param Handler Function to use as handler - */ -void EDI_Int_IRQ_SetHandler(object_pointer Object, interrupt_handler_t Handler) -{ - tEdiIRQ *obj; - - // Get Data Pointer - VALIDATE_PTR(Object,); - obj = GET_DATA(Object); - - // Sanity Check arguments - if( !obj->State ) return ; - - // Only register the mediator if it is not already - if( Handler && !obj->Handler ) - if( !irq_install_handler(obj->Num, Edi_Int_IRQ_Handler) ) - return ; - obj->Handler = Handler; -} - -/** - * \fn void EDI_Int_IRQ_Return(object_pointer Object) - * \brief Return from interrupt - * \param Object IRQ Object - * \note Due to the structure of acess interrupts, this is a dummy - */ -void EDI_Int_IRQ_Return(object_pointer Object) -{ -} - -/** - * \fn void Edi_Int_IRQ_Handler(struct regs *Regs) - * \brief EDI IRQ Handler - Calls the handler - * \param Regs Register state at IRQ call - */ -void Edi_Int_IRQ_Handler(struct regs *Regs) -{ - int i; - for( i = 0; i < 16; i ++ ) - { - if(!gEdi_IRQObjects[i].State) continue; // Unused, Skip - if(gEdi_IRQObjects[i].Num != Regs->int_no) continue; // Another IRQ, Skip - if(!gEdi_IRQObjects[i].Handler) continue; // No Handler, Skip - gEdi_IRQObjects[i].Handler( Regs->int_no ); // Call Handler - return; - } -} - - -// === CLASS DECLARATION === -static edi_function_declaration_t scEdi_Int_Functions_IRQ[] = { - {"int32_t", "init_interrupt", 1, 3, NULL, //scEdi_Int_Variables_IO[0], - (function_pointer)Edi_Int_IRQ_InitInt - }, - {"uint32_t", "interrupt_get_irq", 1, 1, NULL, //scEdi_Int_Variables_IO[1], - (function_pointer)Edi_Int_IRQ_GetInt - }, - {"void", "interrupt_set_handler", 1, 2, NULL, //scEdi_Int_Variables_IO[2], - (function_pointer)Edi_Int_IRQ_GetInt - }, - {"void", "interrupt_return", 1, 1, NULL, //scEdi_Int_Variables_IO[3], - (function_pointer)Edi_Int_IRQ_GetInt - } - }; -static edi_class_declaration_t scEdi_Int_Class_IRQ = - { - INTERRUPTS_CLASS, 1, 12, - scEdi_Int_Functions_IRQ, - Edi_Int_IRQ_Construct, - Edi_Int_IRQ_Destruct, - NULL - }; diff --git a/KernelLand/Modules/Interfaces/EDI/edi_io.inc.c b/KernelLand/Modules/Interfaces/EDI/edi_io.inc.c deleted file mode 100644 index 8a6ef22ef60a40885249b49ddee0c4cf6e8fe027..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/edi_io.inc.c +++ /dev/null @@ -1,391 +0,0 @@ -/* - * AcessOS EDI Interface - * - IO Port Class - * - * By John Hodge (thePowersGang) - * - * This file has been released into the public domain. - * You are free to use it as you wish. - */ -#include "edi/edi.h" - -// === TYPES === -typedef struct { - uint16_t State; // 0: Unallocated, 1: Allocated, 2: Initialised, (Bit 0x8000 set if in heap) - uint16_t Num; -} tEdiPort; - -// === GLOBALS === -#define NUM_PREALLOC_PORTS 128 -tEdiPort gEdi_PortObjects[NUM_PREALLOC_PORTS]; - -// === FUNCTIONS === -/** - * \fn object_pointer Edi_Int_IO_Construct(void) - * \brief Creates a new IO Port Object - * \return Pointer to object - */ -object_pointer Edi_Int_IO_Construct(void) -{ - tEdiPort *ret; - int i; - // Search for a free preallocated port - for( i = 0; i < NUM_PREALLOC_PORTS; i ++ ) - { - if(gEdi_PortObjects[i].State) continue; - gEdi_PortObjects[i].State = 1; - gEdi_PortObjects[i].Num = 0; - return &gEdi_PortObjects[i]; - } - // Else, use heap space - ret = malloc( sizeof(tEdiPort) ); - ret->State = 0x8001; - ret->Num = 0; - return ret; -} - -/** - * \fn void Edi_Int_IO_Destruct(object_pointer Object) - * \brief Destruct an IO Port Object - * \param Object Object to destroy - */ -void Edi_Int_IO_Destruct(object_pointer Object) -{ - tEdiPort *obj; - // Get Data Pointer - VALIDATE_PTR(Object,); - obj = GET_DATA(Object); - - if(obj->State & 0x8000) { // If in heap, free - free(Object); - } else { // Otherwise, mark as unallocated - obj->State = 0; - } -} - -/** - * \fn int32_t Edi_Int_IO_InitPort(object_pointer Object, uint16_t Port) - * \brief Initialises an IO Port - * \param Object Object Pointer (this) - * \param Port Port Number to use - */ -int32_t Edi_Int_IO_InitPort(object_pointer Object, uint16_t Port) -{ - tEdiPort *obj; - // Get Data Pointer - VALIDATE_PTR(Object, 0); - obj = GET_DATA(Object); - - if( !obj->State ) return 0; - obj->Num = Port; - obj->State &= ~0x3FFF; - obj->State |= 2; // Set initialised flag - return 1; -} - -/** - * \fn uint16_t Edi_Int_IO_GetPortNum(object_pointer Object) - * \brief Returns the port number associated with the object - * \param Object Port Object to get number from - * \return Port Number - */ -uint16_t Edi_Int_IO_GetPortNum(object_pointer Object) -{ - tEdiPort *obj; - // Get Data Pointer - VALIDATE_PTR(Object, 0); - obj = GET_DATA(Object); - // Check if valid - if( !obj->State ) return 0; - // Return Port No - return obj->Num; -} - -/** - * \fn int32_t Edi_Int_IO_ReadByte(object_pointer Object, uint8_t *out) - * \brief Read a byte from an IO port - * \param Object Port Object - * \param out Pointer to put read data - */ -int32_t Edi_Int_IO_ReadByte(object_pointer Object, uint8_t *out) -{ - tEdiPort *obj; - // Get Data Pointer - VALIDATE_PTR(Object, 0); - obj = GET_DATA(Object); - - if( !obj->State ) return 0; - if( obj->State & 1 ) return -1; // Unintialised - - __asm__ __volatile__ ( "inb %%dx, %%al" : "=a" (*out) : "d" ( obj->Num ) ); - - return 1; -} - -/** - * \fn int32_t Edi_Int_IO_ReadWord(object_pointer Object, uint16_t *out) - * \brief Read a word from an IO port - * \param Object Port Object - * \param out Pointer to put read data - */ -int32_t Edi_Int_IO_ReadWord(object_pointer Object, uint16_t *out) -{ - - tEdiPort *obj; - // Get Data Pointer - VALIDATE_PTR(Object, 0); - obj = GET_DATA(Object); - if( !obj->State ) return 0; - if( obj->State & 1 ) return -1; // Unintialised - - __asm__ __volatile__ ( "inw %%dx, %%ax" : "=a" (*out) : "d" ( obj->Num ) ); - - return 1; -} - -/** - * \fn int32_t Edi_Int_IO_ReadDWord(object_pointer Object, uint32_t *out) - * \brief Read a double word from an IO port - * \param Object Port Object - * \param out Pointer to put read data - */ -int32_t Edi_Int_IO_ReadDWord(object_pointer Object, uint32_t *out) -{ - - tEdiPort *obj; - // Get Data Pointer - VALIDATE_PTR(Object, 0); - obj = GET_DATA(Object); - if( !obj->State ) return 0; - if( obj->State & 1 ) return -1; // Unintialised - - __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*out) : "d" ( obj->Num ) ); - - return 1; -} - -/** - * \fn int32_t Edi_Int_IO_ReadQWord(object_pointer Object, uint64_t *out) - * \brief Read a quad word from an IO port - * \param Object Port Object - * \param out Pointer to put read data - */ -int32_t Edi_Int_IO_ReadQWord(object_pointer Object, uint64_t *out) -{ - uint32_t *out32 = (uint32_t*)out; - tEdiPort *obj; - // Get Data Pointer - VALIDATE_PTR(Object, 0); - obj = GET_DATA(Object); - if( !obj->State ) return 0; - if( obj->State & 1 ) return -1; // Unintialised - - __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*out32) : "d" ( obj->Num ) ); - __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*(out32+1)) : "d" ( obj->Num+4 ) ); - - return 1; -} - -/** - * \fn int32_t Edi_Int_IO_ReadString(object_pointer Object, uint32_t Length, uint8_t *out) - * \brief Read a byte from an IO port - * \param Object Port Object - * \param Length Number of bytes to read - * \param out Pointer to put read data - */ -int32_t Edi_Int_IO_ReadString(object_pointer Object, uint32_t Length, uint8_t *out) -{ - tEdiPort *obj; - // Get Data Pointer - VALIDATE_PTR(Object, 0); - obj = GET_DATA(Object); - if( !obj->State ) return 0; - if( obj->State & 1 ) return -1; // Unintialised - - __asm__ __volatile__ ( "rep insb" : : "c" (Length), "D" (out), "d" ( obj->Num ) ); - - return 1; -} - -/** - * \fn int32_t Edi_Int_IO_WriteByte(object_pointer Object, uint8_t in) - * \brief Write a byte from an IO port - * \param Object Port Object - * \param in Data to write - */ -int32_t Edi_Int_IO_WriteByte(object_pointer Object, uint8_t in) -{ - tEdiPort *obj; - // Get Data Pointer - VALIDATE_PTR(Object, 0); - obj = GET_DATA(Object); - if( !obj->State ) return 0; - if( obj->State & 1 ) return -1; // Unintialised - - __asm__ __volatile__ ( "outb %%al, %%dx" : : "a" (in), "d" ( obj->Num ) ); - - return 1; -} - -/** - * \fn int32_t Edi_Int_IO_WriteWord(object_pointer Object, uint16_t in) - * \brief Write a word from an IO port - * \param Object Port Object - * \param in Data to write - */ -int32_t Edi_Int_IO_WriteWord(object_pointer Object, uint16_t in) -{ - tEdiPort *obj; - // Get Data Pointer - VALIDATE_PTR(Object, 0); - obj = GET_DATA(Object); - if( !obj->State ) return 0; - if( obj->State & 1 ) return -1; // Unintialised - - __asm__ __volatile__ ( "outw %%ax, %%dx" : : "a" (in), "d" ( obj->Num ) ); - - return 1; -} - -/** - * \fn int32_t Edi_Int_IO_WriteDWord(object_pointer Object, uint32_t in) - * \brief Write a double word from an IO port - * \param Object Port Object - * \param in Data to write - */ -int32_t Edi_Int_IO_WriteDWord(object_pointer Object, uint32_t in) -{ - tEdiPort *obj; - // Get Data Pointer - VALIDATE_PTR(Object, 0); - obj = GET_DATA(Object); - if( !obj->State ) return 0; - if( obj->State & 1 ) return -1; // Unintialised - - __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (in), "d" ( obj->Num ) ); - - return 1; -} - -/** - * \fn int32_t Edi_Int_IO_WriteQWord(object_pointer Object, uint64_t in) - * \brief Write a quad word from an IO port - * \param Object Port Object - * \param in Data to write - */ -int32_t Edi_Int_IO_WriteQWord(object_pointer Object, uint64_t in) -{ - uint32_t *in32 = (uint32_t*)∈ - tEdiPort *obj; - // Get Data Pointer - VALIDATE_PTR(Object, 0); - obj = GET_DATA(Object); - if( !obj->State ) return 0; - if( obj->State & 1 ) return -1; // Unintialised - - __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (*in32), "d" ( obj->Num ) ); - __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (*(in32+1)), "d" ( obj->Num+4 ) ); - - return 1; -} - -/** - * \fn int32_t Edi_Int_IO_WriteString(object_pointer Object, uint32_t Length, uint8_t *in) - * \brief Read a byte from an IO port - * \param Object Port Object - * \param Length Number of bytes to write - * \param in Pointer to of data to write - */ -int32_t Edi_Int_IO_WriteString(object_pointer Object, uint32_t Length, uint8_t *in) -{ - tEdiPort *obj; - // Get Data Pointer - VALIDATE_PTR(Object, 0); - obj = GET_DATA(Object); - if( !obj->State ) return 0; - if( obj->State & 1 ) return -1; // Unintialised - - __asm__ __volatile__ ( "rep outsb" : : "c" (Length), "D" (in), "d" ( obj->Num ) ); - - return 1; -} - -// === CLASS DECLARATION === -/*static edi_variable_declaration_t *scEdi_Int_Variables_IO[] = { - { - {"pointer", "port_object", 0}, - {"uint16_t", "port", 0} - }, - { - {"pointer", "port_object", 0} - }, - { - {"pointer", "port_object", 0}, - {"pointer int8_t", "out", 0} - } -};*/ -static edi_function_declaration_t scEdi_Int_Functions_IO[] = { - {"int32_t", "init_io_port", 1, 2, NULL, //scEdi_Int_Variables_IO[0], - (function_pointer)Edi_Int_IO_InitPort - }, - {"uint16_t", "get_port_number", 1, 1, NULL, //scEdi_Int_Variables_IO[1], - (function_pointer)Edi_Int_IO_GetPortNum - }, - {"int32_t", "read_byte_io_port", 1, 2, NULL, //scEdi_Int_Variables_IO[2], - (function_pointer)Edi_Int_IO_ReadByte - }, - {"int32_t", "read_word_io_port", 1, 2, NULL/*{ - {"pointer", "port_object", 0}, - {"pointer int16_t", "out", 0} - }*/, - (function_pointer)Edi_Int_IO_ReadWord - }, - {"int32_t", "read_long_io_port", 1, 2, NULL/*{ - {"pointer", "port_object", 0}, - {"pointer int32_t", "out", 0} - }*/, - (function_pointer)Edi_Int_IO_ReadDWord - }, - {"int32_t", "read_longlong_io_port", 1, 2, NULL/*{ - {"pointer", "port_object", 0}, - {"pointer int64_t", "out", 0} - }*/, - (function_pointer)Edi_Int_IO_ReadQWord - }, - {"int32_t", "read_string_io_port", 1, 3, NULL/*{ - {"pointer", "port_object", 0}, - {"int32_T", "data_length", 0}, - {"pointer int64_t", "out", 0} - }*/, - (function_pointer)Edi_Int_IO_ReadString - }, - - {"int32_t", "write_byte_io_port", 1, 2, NULL/*{ - {"pointer", "port_object", 0}, - {"int8_t", "in", 0} - }*/, - (function_pointer)Edi_Int_IO_WriteByte}, - {"int32_t", "write_word_io_port", 1, 2, NULL/*{ - {"pointer", "port_object", 0}, - {"int16_t", "in", 0} - }*/, - (function_pointer)Edi_Int_IO_WriteWord}, - {"int32_t", "write_long_io_port", 1, 2, NULL/*{ - {"pointer", "port_object", 0}, - {"int32_t", "in", 0} - }*/, - (function_pointer)Edi_Int_IO_WriteDWord}, - {"int32_t", "write_longlong_io_port", 1, 2, NULL/*{ - {"pointer", "port_object", 0}, - {"int64_t", "in", 0} - }*/, - (function_pointer)Edi_Int_IO_WriteQWord} - }; -static edi_class_declaration_t scEdi_Int_Class_IO = - { - IO_PORT_CLASS, 1, 12, - scEdi_Int_Functions_IO, - Edi_Int_IO_Construct, - Edi_Int_IO_Destruct, - NULL - }; diff --git a/KernelLand/Modules/Interfaces/EDI/main.c b/KernelLand/Modules/Interfaces/EDI/main.c deleted file mode 100644 index c3d0272af8c61a1dc6feaab88a6b2998fa88e534..0000000000000000000000000000000000000000 --- a/KernelLand/Modules/Interfaces/EDI/main.c +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Acess2 EDI Layer - */ -#define DEBUG 0 -#define VERSION ((0<<8)|1) -#include <acess.h> -#include <modules.h> -#include <fs_devfs.h> -#define IMPLEMENTING_EDI 1 -#include "edi/edi.h" - -#define VALIDATE_PTR(_ptr,_err) do{if(!(_ptr))return _err; }while(0) -#define GET_DATA(_ptr) (Object) - -#include "edi_io.inc.c" -#include "edi_int.inc.c" - -// === STRUCTURES === -typedef struct sAcessEdiDriver { - struct sAcessEdiDriver *Next; - tDevFS_Driver Driver; - int FileCount; - struct { - char *Name; - tVFS_Node Node; - } *Files; - edi_object_metadata_t *Objects; - edi_initialization_t Init; - driver_finish_t Finish; -} tAcessEdiDriver; - -// === PROTOTYPES === - int EDI_Install(char **Arguments); - int EDI_DetectDriver(void *Base); - int EDI_LoadDriver(void *Base); -vfs_node *EDI_FS_ReadDir(vfs_node *Node, int Pos); -vfs_node *EDI_FS_FindDir(vfs_node *Node, char *Name); - int EDI_FS_CharRead(vfs_node *Node, Uint64 Offset, Uint64 Length, void *Buffer); - int EDI_FS_CharWrite(vfs_node *Node, Uint64 Offset, Uint64 Length, void *Buffer); - int EDI_FS_IOCtl(vfs_node *Node, int Id, void *Data); -data_pointer EDI_GetInternalClass(edi_string_t ClassName); - -// === GLOBALS === -MODULE_DEFINE(0, VERSION, EDI, EDI_Install, NULL, NULL); -tModuleLoader gEDI_Loader = { - NULL, "EDI", EDI_DetectDriver, EDI_LoadDriver, NULL -}; -tSpinlock glEDI_Drivers; -tAcessEdiDriver *gEdi_Drivers = NULL; -edi_class_declaration_t *gcEdi_IntClasses[] = { - &scEdi_Int_Class_IO, &scEdi_Int_Class_IRQ -}; -#define NUM_INT_CLASSES (sizeof(gcEdi_IntClasses)/sizeof(gcEdi_IntClasses[0])) -char *csCharNumbers[] = {"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9"}; -char *csBlockNumbers[] = {"blk0", "blk1", "blk2", "blk3", "blk4", "blk5", "blk6", "blk7", "blk8", "blk9"}; - -// === CODE === -/** - * \fn int EDI_Install(char **Arguments) - * \brief Stub intialisation routine - */ -int EDI_Install(char **Arguments) -{ - Module_RegisterLoader( &gEDI_Loader ); - return 1; -} - -/** - * \brief Detects if a driver should be loaded by the EDI subsystem - */ -int EDI_DetectDriver(void *Base) -{ - if( Binary_FindSymbol(BASE, "driver_init", NULL) == 0 ) - return 0; - - return 1; -} - -/** - * \fn int Edi_LoadDriver(void *Base) - * \brief Load an EDI Driver from a loaded binary - * \param Base Binary Handle - * \return 0 on success, non zero on error - */ -int EDI_LoadDriver(void *Base) -{ - driver_init_t init; - driver_finish_t finish; - tAcessEdiDriver *info; - int i, j; - int devfsId; - edi_class_declaration_t *classes; - - ENTER("pBase", Base); - - // Get Functions - if( !Binary_FindSymbol(Base, "driver_init", (Uint*)&init) - || !Binary_FindSymbol(Base, "driver_finish", (Uint*)&finish) ) - { - Warning("[EDI ] Driver %p does not provide both `driver_init` and `driver_finish`\n", Base); - Binary_Unload(Base); - return 0; - } - - // Allocate Driver Information - info = malloc( sizeof(tAcessEdiDriver) ); - info->Finish = finish; - - // Initialise Driver - info->Init = init( 0, NULL ); // TODO: Implement Resources - - LOG("info->Init.driver_name = '%s'", info->Init.driver_name); - LOG("info->Init.num_driver_classes = %i", info->Init.num_driver_classes); - - // Count mappable classes - classes = info->Init.driver_classes; - info->FileCount = 0; - info->Objects = NULL; - for( i = 0, j = 0; i < info->Init.num_driver_classes; i++ ) - { - if( strncmp(classes[i].name, "EDI-CHARACTER-DEVICE", 32) == 0 ) - { - data_pointer *obj; - // Initialise Object Instances - for( ; (obj = classes[i].constructor()); j++ ) { - LOG("%i - Constructed '%s'", j, classes[i].name); - info->FileCount ++; - info->Objects = realloc(info->Objects, sizeof(*info->Objects)*info->FileCount); - info->Objects[j].object = obj; - info->Objects[j].object_class = &classes[i]; - } - } - else - LOG("%i - %s", i, classes[i].name); - } - - if(info->FileCount) - { - int iNumChar = 0; - // Create VFS Nodes - info->Files = malloc( info->FileCount * sizeof(*info->Files) ); - memset(info->Files, 0, info->FileCount * sizeof(*info->Files)); - j = 0; - for( j = 0; j < info->FileCount; j++ ) - { - classes = info->Objects[j].object_class; - if( strncmp(classes->name, "EDI-CHARACTER-DEVICE", 32) == 0 ) - { - LOG("%i - %s", j, csCharNumbers[iNumChar]); - info->Files[j].Name = csCharNumbers[iNumChar]; - info->Files[j].Node.NumACLs = 1; - info->Files[j].Node.ACLs = &gVFS_ACL_EveryoneRW; - info->Files[j].Node.ImplPtr = &info->Objects[j]; - info->Files[j].Node.Read = EDI_FS_CharRead; - info->Files[j].Node.Write = EDI_FS_CharWrite; - info->Files[j].Node.IOCtl = EDI_FS_IOCtl; - info->Files[j].Node.CTime = - info->Files[j].Node.MTime = - info->Files[j].Node.ATime = now(); - - iNumChar ++; - continue; - } - } - - // Create DevFS Driver - info->Driver.ioctl = EDI_FS_IOCtl; - memsetda(&info->Driver.rootNode, 0, sizeof(vfs_node) / 4); - info->Driver.Name = info->Init.driver_name; - info->Driver.RootNode.Flags = VFS_FFLAG_DIRECTORY; - info->Driver.RootNode.NumACLs = 1; - info->Driver.RootNode.ACLs = &gVFS_ACL_EveryoneRX; - info->Driver.RootNode.Length = info->FileCount; - info->Driver.RootNode.ImplPtr = info; - info->Driver.RootNode.ReadDir = EDI_FS_ReadDir; - info->Driver.RootNode.FindDir = EDI_FS_FindDir; - info->Driver.RootNode.IOCtl = EDI_FS_IOCtl; - - // Register - devfsId = dev_addDevice( &info->Driver ); - if(devfsId == -1) { - free(info->Files); // Free Files - info->Finish(); // Clean up driver - free(info); // Free info structure - Binary_Unload(iDriverBase); // Unload library - return -3; // Return error - } - } - - // Append to loaded list; - LOCK(&glEDI_Drivers); - info->Next = gEDI_Drivers; - gEDI_Drivers = info; - RELEASE(&glEDI_Drivers); - - LogF("[EDI ] Loaded Driver '%s' (%s)\n", info->Init.driver_name, Path); - LEAVE('i', 1); - return 1; -} - -// --- Filesystem Interaction --- -/** - * \brief Read from a drivers class list - * \param Node Driver's Root Node - * \param Pos Index of file to get - */ -char *EDI_FS_ReadDir(tVFS_Node *Node, int Pos) -{ - tAcessEdiDriver *info; - - // Sanity Check - if(!Node) return NULL; - - // Get Information Structure - info = (void *) Node->ImplPtr; - if(!info) return NULL; - - // Check Position - if(Pos < 0) return NULL; - if(Pos >= info->FileCount) return NULL; - - return strdup( info->Files[Pos].Name ); -} - -/** - * \fn tVFS_Node *EDI_FS_FindDir(tVFS_Node *Node, char *Name) - * \brief Find a named file in a driver - * \param Node Driver's Root Node - * \param Name Name of file to find - */ -tVFS_Node *EDI_FS_FindDir(tVFS_Node *Node, char *Name) -{ - tAcessEdiDriver *info; - int i; - - // Sanity Check - if(!Node) return NULL; - if(!Name) return NULL; - - // Get Information Structure - info = (void *) Node->ImplPtr; - if(!info) return NULL; - - for( i = 0; i < info->FileCount; i++ ) - { - if(strcmp(info->Files[i].name, Name) == 0) - return &info->Files[i].Node; - } - - return NULL; -} - -/** - * \fn Uint64 EDI_FS_CharRead(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) - * \brief Read from an EDI Character Device - * \param Node File Node - * \param Offset Offset into file (ignored) - * \param Length Number of characters to read - * \param Buffer Destination for data - * \return Number of characters read - */ -Uint64 EDI_FS_CharRead(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) -{ - edi_object_metadata_t *meta; - edi_class_declaration_t *class; - - // Sanity Check - if(!Node || !Buffer) return 0; - if(Length <= 0) return 0; - // Get Object Metadata - meta = (void *) Node->ImplPtr; - if(!meta) return 0; - - // Get Class - class = meta->object_class; - if(!class) return 0; - - // Read from object - if( ((tAnyFunction) class->methods[0].code)( meta->object, Buffer, Length )) - return Length; - - return 0; -} - -/** - * \fn Uint64 EDI_FS_CharWrite(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) - * \brief Write to an EDI Character Device - * \param Node File Node - * \param Offset Offset into file (ignored) - * \param Length Number of characters to write - * \param Buffer Source for data - * \return Number of characters written - */ -Uint64 EDI_FS_CharWrite(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) -{ - edi_object_metadata_t *meta; - edi_class_declaration_t *class; - - // Sanity Check - if(!Node || !Buffer) return 0; - if(Length <= 0) return 0; - // Get Object Metadata - meta = (void *) Node->ImplPtr; - if(!meta) return 0; - - // Get Class - class = meta->object_class; - if(!class) return 0; - - // Write to object - if( ((tAnyFunction) class->methods[1].code)( meta->object, Buffer, Length )) - return Length; - - return 0; -} - -/** - * \fn int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data) - * \brief Perfom an IOCtl call on the object - */ -int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data) -{ - return 0; -} - -// --- EDI Functions --- -/** - * \fn data_pointer EDI_GetDefinedClass(edi_string_t ClassName) - * \brief Gets the structure of a driver defined class - * \param ClassName Name of class to find - * \return Class definition or NULL - */ -data_pointer EDI_GetDefinedClass(edi_string_t ClassName) -{ - int i; - tAcessEdiDriver *drv; - edi_class_declaration_t *classes; - - for(drv = gEdi_Drivers; - drv; - drv = drv->Next ) - { - classes = drv->Init.driver_classes; - for( i = 0; i < drv->Init.num_driver_classes; i++ ) - { - if( strncmp(classes[i].name, ClassName, 32) == 0 ) - return &classes[i]; - } - } - return NULL; -} - -/** - * \fn int32_t EDI_CheckClassExistence(edi_string_t ClassName) - * \brief Checks if a class exists - * \param ClassName Name of class - * \return 1 if the class exists, -1 otherwise - */ -int32_t EDI_CheckClassExistence(edi_string_t ClassName) -{ - //LogF("check_class_existence: (ClassName='%s')\n", ClassName); - if(EDI_GetInternalClass(ClassName)) - return 1; - - if(EDI_GetDefinedClass(ClassName)) // Driver Defined - return 1; - - return -1; -} - -/** - * \fn edi_object_metadata_t EDI_ConstructObject(edi_string_t ClassName) - * \brief Construct an instance of an class (an object) - * \param ClassName Name of the class to construct - */ -edi_object_metadata_t EDI_ConstructObject(edi_string_t ClassName) -{ - edi_object_metadata_t ret = {0, 0}; - edi_class_declaration_t *class; - - //LogF("EDI_ConstructObject: (ClassName='%s')\n", ClassName); - - // Get class definition - if( !(class = EDI_GetInternalClass(ClassName)) ) // Internal - if( !(class = EDI_GetDefinedClass(ClassName)) ) // Driver Defined - return ret; // Return ERROR - - // Initialise - ret.object = class->constructor(); - if( !ret.object ) - return ret; // Return ERROR - - // Set declaration pointer - ret.object_class = class; - - //LogF("EDI_ConstructObject: RETURN {0x%x,0x%x}\n", ret.object, ret.object_class); - return ret; -} - -/** - * \fn void EDI_DestroyObject(edi_object_metadata_t Object) - * \brief Destroy an instance of a class - * \param Object Object to destroy - */ -void EDI_DestroyObject(edi_object_metadata_t Object) -{ - if( !Object.object ) return; - if( !Object.object_class ) return; - - ((edi_class_declaration_t*)(Object.object_class))->destructor( &Object ); -} - -/** - * \fn function_pointer EDI_GetMethodByName(data_pointer ObjectClass, edi_string_t MethodName) - * \brief Get a method of a class by it's name - * \param ObjectClass Pointer to a ::edi_object_metadata_t of the object - * \param MethodName Name of the desired method - * \return Function address or NULL - */ -function_pointer EDI_GetMethodByName(data_pointer ObjectClass, edi_string_t MethodName) -{ - edi_class_declaration_t *dec = ObjectClass; - int i; - - //LogF("get_method_by_name: (ObjectClass=0x%x, MethodName='%s')\n", ObjectClass, MethodName); - - if(!ObjectClass) return NULL; - - for(i = 0; i < dec->num_methods; i++) - { - if(strncmp(MethodName, dec->methods[i].name, 32) == 0) - return dec->methods[i].code; - } - return NULL; -} - -#if 0 -function_pointer get_method_by_declaration(data_pointer Class, edi_function_declaration_t Declaration); -#endif - -/** - * \fn edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName) - * \brief Get the parent of the named class - * \todo Implement - */ -edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName) -{ - WarningEx("EDI", "`get_class_parent` is unimplemented"); - return NULL; -} - -/** - * \fn data_pointer EDI_GetInternalClass(edi_string_t ClassName) - * \brief Get a builtin class - * \param ClassName Name of class to find - * \return Pointer to the ::edi_class_declaration_t of the class - */ -data_pointer EDI_GetInternalClass(edi_string_t ClassName) -{ - int i; - //LogF("get_internal_class: (ClassName='%s')\n", ClassName); - for( i = 0; i < NUM_INT_CLASSES; i++ ) - { - if( strncmp( gcEdi_IntClasses[i]->name, ClassName, 32 ) == 0 ) { - return gcEdi_IntClasses[i]; - } - } - //LogF("get_internal_class: RETURN NULL\n"); - return NULL; -} - -/** - * \fn edi_string_ptr_t EDI_GetObjectClass(data_pointer Object) - * \brief Get the name of the object of \a Object - * \param Object Object to get name of - * \return Pointer to the class name - */ -edi_string_ptr_t EDI_GetObjectClass(data_pointer ObjectClass) -{ - edi_object_metadata_t *Metadata = ObjectClass; - // Sanity Check - if(!ObjectClass) return NULL; - if(!(edi_class_declaration_t*) Metadata->object_class) return NULL; - - // Return Class Name - return ((edi_class_declaration_t*) Metadata->object_class)->name; -} - -// === EXPORTS === -EXPORTAS(EDI_CheckClassExistence, check_class_existence); -EXPORTAS(EDI_ConstructObject, construct_object); -EXPORTAS(EDI_DestroyObject, destroy_object); -EXPORTAS(EDI_GetMethodByName, get_method_by_name); -EXPORTAS(EDI_GetClassParent, get_class_parent); -EXPORTAS(EDI_GetInternalClass, get_internal_class); -EXPORTAS(EDI_GetObjectClass, get_object_class); diff --git a/KernelLand/Modules/Interfaces/UDI/Makefile b/KernelLand/Modules/Interfaces/UDI/Makefile index 3b1387bebf6f20d3432c0faba0ace399967d15e5..9b397401a42104ed15025c57cb228839f9ba0991 100644 --- a/KernelLand/Modules/Interfaces/UDI/Makefile +++ b/KernelLand/Modules/Interfaces/UDI/Makefile @@ -2,6 +2,7 @@ # CPPFLAGS = -I../../../../UDI/include -Iinclude +CPPFLAGS += -D UDI_VERSION=0x101 -D UDI_PHYSIO_VERSION=0x101 -D UDI_NIC_VERSION=0x101 # - UDI Library Files LIB_OBJS := core/logging.o core/strmem.o core/imc.o core/mem.o core/buf.o diff --git a/KernelLand/Modules/Interfaces/UDI/main.c b/KernelLand/Modules/Interfaces/UDI/main.c index 1c9fc29cc332a5e04101c14454ea3d771b82c02e..4a655f0c34ce64b0f05c448039ce405e47239723 100644 --- a/KernelLand/Modules/Interfaces/UDI/main.c +++ b/KernelLand/Modules/Interfaces/UDI/main.c @@ -37,6 +37,10 @@ tUDI_DriverModule *gpUDI_LoadedModules; */ int UDI_Install(char **Arguments) { + if( Arguments && Arguments[0] && strcmp(Arguments[0], "disable") == 0 ) { + // Module disabled by user + return MODULE_ERR_NOTNEEDED; + } Module_RegisterLoader( &gUDI_Loader ); Proc_SpawnWorker(UDI_int_DeferredThread, NULL); @@ -121,10 +125,10 @@ static udi_boolean_t _get_token_bool(const char *str, const char **outstr) static udi_index_t _get_token_idx(const char *str, const char **outstr) { char *end; - int ret = strtol(str, &end, 10); - if( ret < 0 || ret > 255 ) { - Log_Notice("UDI", "Value '%.*s' out of range for udi_index_t", - end-str, str); + unsigned long ret = strtoul(str, &end, 10); + if( ret > 255 ) { + Log_Notice("UDI", "Value '%.*s' (0x%lx) out of range for udi_index_t", + end-str, str, ret); *outstr = NULL; return 0; } @@ -145,8 +149,8 @@ static udi_ubit16_t _get_token_uint16(const char *str, const char **outstr) char *end; unsigned long ret = strtoul(str, &end, 10); if( ret > 0xFFFF ) { - Log_Notice("UDI", "Value '%.*s' out of range for udi_ubit16_t", - end-str, str); + Log_Notice("UDI", "Value '%.*s' (0x%lx) out of range for udi_ubit16_t", + end-str, str, ret); *outstr = NULL; return 0; } @@ -419,12 +423,14 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co int child_bind_index = 0; int device_index = 0; int next_unpop_region = 1; + #define IF_ERROR(op) if(!str){error_hit=1;op;} for( int i = 0; i < nLines; i ++ ) { const char *str = udipropsptrs[i]; if( !*str ) continue ; int sym = _get_token_sym_v(str, &str, true, caUDI_UdipropsNames); + //LOG("Processing option '%s'", (sym >= 0 ? caUDI_UdipropsNames[sym] : "ERR")); switch(sym) { case UDIPROPS__properties_version: @@ -439,7 +445,7 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co case UDIPROPS__meta: { tUDI_MetaLangRef *ml = &driver_module->MetaLangs[ml_index++]; ml->meta_idx = _get_token_idx(str, &str); - if( !str ) continue; + IF_ERROR(continue); ml->interface_name = str; // TODO: May need to trim trailing spaces ml->metalang = UDI_int_GetMetaLangByName(ml->interface_name); @@ -455,7 +461,7 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co tUDI_PropMessage *msg = &driver_module->Messages[msg_index++]; msg->locale = cur_locale; msg->index = _get_token_uint16(str, &str); - if( !str ) continue ; + IF_ERROR(continue); msg->string = str; //Log_Debug("UDI", "Message %i/%i: '%s'", msg->locale, msg->index, msg->string); break; @@ -467,7 +473,7 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co case UDIPROPS__region: { udi_index_t rgn_idx = _get_token_idx(str, &str); - if( !str ) continue ; + IF_ERROR(continue); // Search for region index (just in case internal_bind_ops appears earlier) tUDI_PropRegion *rgn = &driver_module->RegionTypes[0]; if( rgn_idx > 0 ) @@ -516,7 +522,7 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co rgn->OverrunTime = _get_token_uint32(str, &str); break; } - if( !str ) break ; + IF_ERROR(break); } break; } @@ -524,12 +530,13 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co { tUDI_BindOps *bind = &driver_module->Parents[parent_index++]; bind->meta_idx = _get_token_idx(str, &str); - if( !str ) continue ; + IF_ERROR(continue); bind->region_idx = _get_token_idx(str, &str); - if( !str ) continue ; + IF_ERROR(continue); bind->ops_idx = _get_token_idx(str, &str); - if( !str ) continue ; + IF_ERROR(continue); bind->bind_cb_idx = _get_token_idx(str, &str); + IF_ERROR(continue); if( *str ) { // Expected EOL, didn't get it :( } @@ -541,9 +548,9 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co { // Get region using index udi_index_t meta = _get_token_idx(str, &str); - if( !str ) continue ; + IF_ERROR(continue); udi_index_t rgn_idx = _get_token_idx(str, &str); - if( !str ) continue ; + IF_ERROR(continue); // Search for region index (just in case the relevant 'region' comes after) tUDI_PropRegion *rgn = &driver_module->RegionTypes[0]; @@ -569,11 +576,11 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co rgn->BindMeta = meta; rgn->PriBindOps = _get_token_idx(str, &str); - if( !str ) continue ; + IF_ERROR(continue); rgn->SecBindOps = _get_token_idx(str, &str); - if( !str ) continue ; + IF_ERROR(continue); rgn->BindCb = _get_token_idx(str, &str); - if( !str ) continue ; + IF_ERROR(continue); if( *str ) { // TODO: Please sir, I want an EOL } @@ -583,10 +590,11 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co { tUDI_BindOps *bind = &driver_module->ChildBindOps[child_bind_index++]; bind->meta_idx = _get_token_idx(str, &str); - if( !str ) continue ; + IF_ERROR(continue); bind->region_idx = _get_token_idx(str, &str); - if( !str ) continue ; + IF_ERROR(continue); bind->ops_idx = _get_token_idx(str, &str); + IF_ERROR(continue); if( *str ) { // Expected EOL, didn't get it :( } @@ -607,26 +615,27 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co { int n_attr = 0; // Count properties (and validate) - _get_token_idx(str, &str); // message - if( !str ) continue; + _get_token_uint16(str, &str); // message + IF_ERROR(continue); _get_token_idx(str, &str); // meta - if( !str ) continue; + IF_ERROR(continue); while( *str ) { _get_token_str(str, &str, NULL); - if( !str ) break; + IF_ERROR(break); _get_token_sym(str, &str, true, "string", "ubit32", "boolean", "array", NULL); - if( !str ) break; + IF_ERROR(break); _get_token_str(str, &str, NULL); - if( !str ) break; + IF_ERROR(break); n_attr ++; } // Rewind and actually parse + // - Eat the 'device' token and hence reset 'str' _get_token_str(udipropsptrs[i], &str, NULL); tUDI_PropDevSpec *dev = NEW_wA(tUDI_PropDevSpec, Attribs, n_attr); driver_module->Devices[device_index++] = dev;; - dev->MessageNum = _get_token_idx(str, &str); + dev->MessageNum = _get_token_uint16(str, &str); dev->MetaIdx = _get_token_idx(str, &str); dev->nAttribs = n_attr; n_attr = 0; @@ -634,10 +643,10 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co { udi_instance_attr_list_t *at = &dev->Attribs[n_attr]; _get_token_str(str, &str, at->attr_name); - if( !str ) break; + IF_ERROR(break); at->attr_type = _get_token_sym(str, &str, true, " ", "string", "array", "ubit32", "boolean", NULL); - if( !str ) break; + IF_ERROR(break); udi_ubit32_t val; switch( dev->Attribs[n_attr].attr_type ) { @@ -662,7 +671,7 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co UDI_ATTR32_SET(at->attr_value, _get_token_bool(str, &str)); break; } - if( !str ) break; + IF_ERROR(break); n_attr ++; } @@ -675,7 +684,7 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co } free(udipropsptrs); if( error_hit ) { - Log_Error("UDI", "Error encountered while parsing udiprops for '%s' (%p), bailing", + Log_Error("UDI", "Error encountered while parsing udiprops for '%s' (LoadBase=%p), bailing", driver_module->ModuleName, LoadBase); for( int i = 0; i < device_index; i ++ ) free(driver_module->Devices[i]); @@ -688,10 +697,14 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co free(driver_module); return NULL; } + ASSERTC(device_index, ==, driver_module->nDevices); - for( int i = 0; i < driver_module->nDevices; i ++ ) + for( int i = 0; i < driver_module->nDevices; i ++ ) { + ASSERT(driver_module); + ASSERT(driver_module->Devices[i]); driver_module->Devices[i]->Metalang = UDI_int_GetMetaLang(driver_module, driver_module->Devices[i]->MetaIdx); + } // Sort message list // TODO: Sort message list diff --git a/KernelLand/Modules/Interfaces/UDI/trans/bus_pci.c b/KernelLand/Modules/Interfaces/UDI/trans/bus_pci.c index deb78259d79705dd8173b12a9a0596e66a2b0f74..990965554acac3ceec30b5f6ebaea3270fa05f1d 100644 --- a/KernelLand/Modules/Interfaces/UDI/trans/bus_pci.c +++ b/KernelLand/Modules/Interfaces/UDI/trans/bus_pci.c @@ -6,6 +6,9 @@ * - PCI Bus Driver */ #define DEBUG 0 +#define UDI_VERSION 0x101 +#define UDI_PHYSIO_VERSION 0x101 +#define UDI_PCI_VERSION 0x101 #include <udi.h> #include <udi_physio.h> #include <udi_pci.h> diff --git a/KernelLand/Modules/Interfaces/UDI/trans/gfx.c b/KernelLand/Modules/Interfaces/UDI/trans/gfx.c new file mode 100644 index 0000000000000000000000000000000000000000..73efc103227458b9302e90f2f90a3a6cbaaf700e --- /dev/null +++ b/KernelLand/Modules/Interfaces/UDI/trans/gfx.c @@ -0,0 +1,91 @@ +/* + * Acess2 UDI Layer + * - By John Hodge (thePowersGang) + * + * trans/gfx.c + * - Graphics interface + */ +#define DEBUG 1 +#define UDI_VERSION 0x101 +#define UDI_GFX_VERSION 0x101 +#include <udi.h> +#include <udi_gfx.h> +#include <acess.h> +#include <api_drv_video.h> + +// === TYPES === +typedef struct rdata_s +{ + +} rdata_t; + +// === PROTOTYPES === +// --- Management metalang +void acessgfx_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level); +void acessgfx_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID); +void acessgfx_final_cleanup_req(udi_mgmt_cb_t *cb); +// --- GFX Binding +void acessgfx_channel_event_ind(udi_channel_event_cb_t *cb); +void acessgfx_bind_ack(udi_gfx_bind_cb_t *cb, udi_index_t sockets, udi_index_t engines, udi_status_t status); +void acessgfx_unbind_ack(udi_gfx_bind_cb_t *cb); +void acessgfx_set_connector_ack(udi_gfx_state_cb_t *cb); +void acessgfx_get_connector_ack(udi_gfx_state_cb_t *cb, udi_ubit32_t value); +void acessgfx_range_connector_ack(udi_gfx_range_cb_t *cb); +void acessgfx_set_engine_ack(udi_gfx_state_cb_t *cb); +void acessgfx_get_engine_ack(udi_gfx_state_cb_t *cb, udi_ubit32_t value); +void acessgfx_range_engine_ack(udi_gfx_range_cb_t *cb); +void acessgfx_command_ack(udi_gfx_command_cb_t *cb); + +// === CODE === +void acessgfx_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level) +{ + rdata_t *rdata = UDI_GCB(cb)->context; + + // Set up structures that don't need interegating the card to do + + udi_usage_res(cb); +} + +void acessgfx_channel_event_ind(udi_channel_event_cb_t *cb) +{ + rdata_t *rdata = UDI_GCB(cb)->context; + + switch(cb->event) + { + case UDI_CHANNEL_CLOSED: + udi_channel_event_complete(cb); + return; + case UDI_CHANNEL_BOUND: + rdata->active_cb = UDI_GCB(cb); + acessgfx_channel_event_ind$bound(cb->params.parent_bound.bind_cb); + return; + default: + // TODO: emit an error of some form? + return; + } +} + +void acessgfx_channel_event_ind$bound(udi_gfx_bind_cb_t *cb) +{ + rdata_t *rdata = UDI_GCB(bind_cb)->context; + + // request metalanguage-level bind + udi_gfx_bind_req(bind_cb); + // Continued in acessgfx_bind_ack +} + +void acessgfx_bind_ack(udi_gfx_bind_cb_t *cb, udi_index_t sockets, udi_index_t engines, udi_status_t status) +{ + rdata_t *rdata = UDI_GCB(bind_cb)->context; + + if( status != UDI_OK ) { + // binding failed + + return ; + } + + // +} + +// === UDI Bindings === + diff --git a/KernelLand/Modules/Interfaces/UDI/trans/gfx.udic b/KernelLand/Modules/Interfaces/UDI/trans/gfx.udic new file mode 100644 index 0000000000000000000000000000000000000000..d61579d484c292703180e24bbdaa63d557f9a0ea --- /dev/null +++ b/KernelLand/Modules/Interfaces/UDI/trans/gfx.udic @@ -0,0 +1,78 @@ +/* + * Acess2 UDI Layer + * - By John Hodge (thePowersGang) + * + * trans/gfx.c + * - Graphics interface + */ +#define DEBUG 1 +#define UDI_VERSION 0x101 +#define UDI_GFX_VERSION 0x101 +#include <udi.h> +#include <udi_gfx.h> +#include <acess.h> +#include <api_drv_video.h> + +// === TYPES === +typedef struct rdata_s +{ + +} rdata_t; + +// === CODE === +void usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level) +{ + // Set up structures that don't need interegating the card to do + +} + +@1=GFX_CLIENT channel_event_ind(udi_channel_event_cb_t *cb) +{ + udi_gfx_bind_cb_t *bind_cb = cb->params.parent_bound.bind_cb; + switch(cb->event) + { + case UDI_CHANNEL_CLOSED: + return; + case UDI_CHANNEL_BOUND: + [sockets, engines, status] = udi_gfx_bind_req(bind_cb); + if( status != UDI_OK ) { + return; + } + // allocate a CB + [new_cb] = udi_cb_alloc(bind_cb, ACESSGFX_CB_STATE); + udi_gfx_state_cb_t *state_cb = new_cb; + for( int i = 0; i < engines; i ++ ) + { + state_cb->subsystem = i; + state_cb->attribute = UDI_GFX_PROP_PIXELFORMAT; + [pixfmt] = @TRY_NAK[status] udi_gfx_get_engine_req(state_cb) + { + // Shit to do if NAK happens + return ; + // break PIXFMT_NONE; + } + + // TODO: Annotate udi_gfx_state_cb_t to note values are kept? + state_cb->subsystem = i; + state_cb->attribute = UDI_GFX_PROP_OPERATOR_INDEX; + [count] = udi_gfx_get_engine_req(state_cb); + for( int j = 0; j < count; j ++ ) + { + state_cb->attribute = j; + [operator, arg_1, arg_2, arg_3] = udi_gfx_engine_getop_req(state_cb); + Log_Debug("UDIGFX", "%i/%i: %i 0x%x 0x%x 0x%x", + i, j, + operator, arg_1, arg_2, arg_3); + } + } + return; + default: + // TODO: emit an error of some form? + return; + } +} + +// === UDI Bindings === + + +// vim: ft=c diff --git a/KernelLand/Modules/Interfaces/UDI/trans/gfx_plan.txt b/KernelLand/Modules/Interfaces/UDI/trans/gfx_plan.txt new file mode 100644 index 0000000000000000000000000000000000000000..b8e4bb9157ab41dc451c6279725a1c6613f21324 --- /dev/null +++ b/KernelLand/Modules/Interfaces/UDI/trans/gfx_plan.txt @@ -0,0 +1,12 @@ + +Upon binding: + +1. Enumerate connectors (types and possible inputs) +2. For all engines that can have their input be -1, get pixel format + a. Parse operator list into a tree +3. Create MIN(n_conns,n_edge) video devices + a. Each device represents an edge engine (engine selected on modeset) + +Notes: +- Need to figure out what engine(s) to use as framebuffer, and what ones to use as cursor + > Allow user/admin intervention to set these relations (based on an identifier from the driver) diff --git a/KernelLand/Modules/Libraries/VirtIO/virtio.c b/KernelLand/Modules/Libraries/VirtIO/virtio.c index 614bd357c5759efeb349413bfe96bc94074ecddb..4631b72c14eb78d05a8072ae2dc178ea6c1d9f15 100644 --- a/KernelLand/Modules/Libraries/VirtIO/virtio.c +++ b/KernelLand/Modules/Libraries/VirtIO/virtio.c @@ -390,7 +390,8 @@ void VirtIO_ReleaseBuffer(tVirtIO_Buf *Buffer) do { has_next = !!(queue->Entries[idx].Flags & VRING_DESC_F_NEXT); int next_idx = queue->Entries[idx].Next; - ASSERTC(!has_next || next_idx,!=,idx); + if( has_next ) + ASSERTC(next_idx,!=,idx); VirtIO_int_ReleaseQDesc(queue, idx); diff --git a/KernelLand/Modules/Makefile.tpl b/KernelLand/Modules/Makefile.tpl index a5ea222abe066d0291ea2004a65a1653d7a5f5f2..c96d8b058e001648a2713ae42b40b7cb4e535533 100644 --- a/KernelLand/Modules/Makefile.tpl +++ b/KernelLand/Modules/Makefile.tpl @@ -62,17 +62,17 @@ endif ifneq ($(BUILDTYPE),static) $(BIN): %.kmd.$(ARCH): $(OBJ) - @echo --- $(LD) -o $@ + @echo --- [LD] -o $@ @$(LD) --allow-shlib-undefined -shared -nostdlib -o $@ $(OBJ) -defsym=DriverInfo=_DriverInfo_$(FULLNAME) $(LDFLAGS) @$(DISASM) $(BIN) > $(BIN).dsm else $(BIN): %.xo.$(ARCH): $(OBJ) - @echo --- $(LD) -o $@ + @echo --- [LD] -o $@ @$(LD) -r -o $@ $(OBJ) $(LDFLAGS) endif obj-$(_SUFFIX)/%.o: %.c Makefile $(CFGFILES) - @echo --- $(CC) -o $@ + @echo --- [CC] -o $@ @mkdir -p $(dir $@) @$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< @$(CC) -M $(CPPFLAGS) -MT $@ -MP -o obj-$(_SUFFIX)/$*.d $< diff --git a/KernelLand/Modules/Network/E1000/e1000.c b/KernelLand/Modules/Network/E1000/e1000.c index 0ad49b01ae6bc1f7049f591ffca41b0c6c9b410a..600f3348ef560703e98657a65f61e137632d8e3f 100644 --- a/KernelLand/Modules/Network/E1000/e1000.c +++ b/KernelLand/Modules/Network/E1000/e1000.c @@ -64,6 +64,7 @@ int E1000_Install(char **Arguments) // Allocate card array gaE1000_Cards = calloc(sizeof(tCard), card_count); if( !gaE1000_Cards ) { + Log_Warning("E1000", "Allocation of %i card structures failed", card_count); return MODULE_ERR_MALLOC; } @@ -88,6 +89,7 @@ int E1000_Install(char **Arguments) Log_Debug("E1000", "Card %i: %P IRQ %i", card_idx, card->MMIOBasePhys, card->IRQ); if( E1000_int_InitialiseCard(card) ) { + Log_Warning("E1000", "Initialisation of card #%i failed", card_idx); return MODULE_ERR_MALLOC; } diff --git a/Makefile b/Makefile index 0edc9835bedf0574c7e004b85db5fe142bada23a..a2e46d10a5f38fb18773ff396442dd6d6e6adda8 100644 --- a/Makefile +++ b/Makefile @@ -10,9 +10,10 @@ SUBMAKE = $(MAKE) --no-print-directory -USRLIBS := crt0.o acess.ld ld-acess.so libc.so libc++.so libposix.so +USRLIBS := crt0.o ld-acess.so libc.so libposix.so libc++.so USRLIBS += libreadline.so libnet.so liburi.so libpsocket.so USRLIBS += libimage_sif.so libunicode.so libm.so +USRLIBS += libaxwin4.so EXTLIBS := #libspiderscript @@ -23,6 +24,7 @@ USRAPPS += insmod USRAPPS += bomb lspci USRAPPS += ip dhcpclient ping telnet irc wget telnetd USRAPPS += axwin3 gui_ate gui_terminal +USRAPPS += axwin4 define targetclasses AI_$1 := $$(addprefix allinstall-,$$($1)) @@ -66,15 +68,31 @@ all-install: install-Filesystem SyscallList ai-user ai-kmode clean: clean-kmode clean-user install: install-Filesystem SyscallList install-user install-kmode -utest: $(USRLIBS:%=utest-%) +utest-build: $(USRLIBS:%=utest-build-%) +utest-run: $(USRLIBS:%=utest-run-%) +utest: utest-build utest-run -$(USRLIBS:%=utest-%): utest-%: +utest-build-%: @CC=$(NCC) $(SUBMAKE) -C Usermode/Libraries/$*_src generate_exp - @CC=$(NCC) $(SUBMAKE) -C Usermode/Libraries/$*_src utest -k + @CC=$(NCC) $(SUBMAKE) -C Usermode/Libraries/$*_src utest-build +utest-run-%: + @CC=$(NCC) $(SUBMAKE) -C Usermode/Libraries/$*_src utest-run -k # TODO: Module tests using DiskTool and NetTest -mtest: +mtest: mtest-build mtest-run @echo > /dev/null +mtest-build: + # Network + @echo "== Build Module Tests" + @echo "-- nativelib" + @CC=$(NCC) $(SUBMAKE) -C Tools/nativelib + @echo "-- NetTest" + @CC=$(NCC) $(SUBMAKE) -C Tools/NetTest + @echo "-- NetTest Runner" + @CC=$(NCC) $(SUBMAKE) -C Tools/NetTest_Runner +mtest-run: + @echo "=== Network Module Test ===" + @cd Tools && ./nettest_runner SyscallList: include/syscalls.h include/syscalls.h: KernelLand/Kernel/Makefile KernelLand/Kernel/syscalls.lst @@ -85,13 +103,13 @@ _build_stmod := BUILDTYPE=static $(SUBMAKE) -C KernelLand/Modules/ _build_kernel := $(SUBMAKE) -C KernelLand/Kernel define rules -$$(ALL_$1): all-%: +$$(ALL_$1): all-%: $(CC) +@echo === $2 && $3 all -$$(AI_$1): allinstall-%: +$$(AI_$1): allinstall-%: $(CC) +@echo === $2 && $3 all install -$$(CLEAN_$1): clean-%: +$$(CLEAN_$1): clean-%: $(CC) +@echo === $2 && $3 clean -$$(INSTALL_$1): install-%: +$$(INSTALL_$1): install-%: $(CC) +@$3 install endef @@ -100,13 +118,23 @@ $(eval $(call rules,MODULES,Module: $$*,$(_build_stmod)$$*)) $(eval $(call rules,USRLIBS,User Library: $$*,$(SUBMAKE) -C Usermode/Libraries/$$*_src)) $(eval $(call rules,EXTLIBS,External Library: $$*,$(SUBMAKE) -C Externals/$$*)) $(eval $(call rules,USRAPPS,User Application: $$*,$(SUBMAKE) -C Usermode/Applications/$$*_src)) -all-Kernel: +all-Kernel: $(CC) +@echo === Kernel && $(_build_kernel) all -allinstall-Kernel: +allinstall-Kernel: $(CC) +@echo === Kernel && $(_build_kernel) all install -clean-Kernel: +clean-Kernel: $(CC) +@$(_build_kernel) clean -install-Kernel: +install-Kernel: $(CC) @$(_build_kernel) install -install-Filesystem: +install-Filesystem: $(CC) @$(SUBMAKE) install -C Usermode/Filesystem + +ifeq ($(ARCHDIR),native) +.PHONY: $(CC) +else +$(CC): + @echo --- + @echo $(CC) does not exist, recompiling + @echo --- + make -C Externals/cross-compiler/ -f Makefile.cross +endif diff --git a/Makefile.cfg b/Makefile.cfg index 022a02ef573eb705a4711817ffb39f28f401e64a..d12710cf90852936131825e5ad44055a786b681c 100644 --- a/Makefile.cfg +++ b/Makefile.cfg @@ -2,12 +2,15 @@ # Acess2 Build Configuration # +V ?= @ + ACESSDIR := $(dir $(lastword $(MAKEFILE_LIST))) ACESSDIR := $(shell cd $(ACESSDIR) && pwd) # Install destination configuration DISTROOT := -i $(ACESSDIR)/Acess2.img ::/Acess2 NCC := $(CC) +NCXX := $(CXX) xCP := mcopy -D o xMKDIR := mmd -D s @@ -16,7 +19,6 @@ xMKDIR := mmd -D s # Default build programs #CC := gcc #LD := ld -AS := nasm DISASM := objdump -d -S RM := @rm -f STRIP := strip @@ -35,12 +37,26 @@ ifeq ($(ARCHDIR),) ARCHDIR := x86 endif +# Default compilers +ifneq ($(ARCHDIR),native) +CC = $(COMPILERDIR)bin/$(TRIPLET)-gcc +CXX = $(COMPILERDIR)bin/$(TRIPLET)-g++ +LD = $(COMPILERDIR)bin/$(TRIPLET)-ld +OBJDUMP = $(COMPILERDIR)bin/$(TRIPLET)-objdump + ifeq ($(AS),as) + AS = $(COMPILERDIR)bin/$(TRIPLET)-gcc -c + endif +endif + ifneq ($(ARCH),host) ifneq ($(ARCHDIR),$(ARCH)) include $(ACESSDIR)/BuildConf/$(ARCHDIR)/Makefile.cfg endif endif +COMPILERDIR := $(ACESSDIR)/Externals/Output/$(ARCHDIR)-BUILD/ +PATH := $(COMPILERDIR)bin/ $(PATH) + ifeq ($(PLATFORM),) PLATFORM := default endif diff --git a/Notes/TODO b/Notes/TODO index 601e78adcadf496785f696dbfe6e64431c58eaef..dbc46fada578b5071019302a1e5a021017baead3 100644 --- a/Notes/TODO +++ b/Notes/TODO @@ -1,8 +1,5 @@ -Implement Ctrl-C in vterm Fix TCP code Get IPv6 working -Implement a DHCP client -Get UDI working (udiref) Finalise AxWin API structure Implement input in AxWin Write TFTP filesystem driver diff --git a/RunQemu b/RunQemu index e69a55ee9b796956ff2da5d806a6a7d0bdcd1b25..1202613f7ed1ec99ca592dfd7ae2b842b78dae22 100755 --- a/RunQemu +++ b/RunQemu @@ -80,6 +80,11 @@ while [ $# -ne 0 ]; do QEMU_PARAMS=$QEMU_PARAMS" -device pci-serial,chardev=serial2" QEMU_PARAMS=$QEMU_PARAMS" -chardev socket,id=serial2,host=localhost,port=10023,server,telnet" ;; + -sata) + QEMU_PARAMS=$QEMU_PARAMS" -device ich9-ahci,id=ahci" + QEMU_PARAMS=$QEMU_PARAMS" -drive if=none,id=sata_disk,file=HDD_sata.img" + QEMU_PARAMS=$QEMU_PARAMS" -device ide-drive,drive=sata_disk,bus=ahci.0" + ;; esac shift done diff --git a/Tools/NetTest/Makefile b/Tools/NetTest/Makefile index f76c8b47f8b538378f9114486e5ee918cf4563bc..913a9beabcfc38c74764146888f1a6edfd0c872c 100644 --- a/Tools/NetTest/Makefile +++ b/Tools/NetTest/Makefile @@ -23,7 +23,7 @@ L_OBJ = vfs_shim.o nic.o tcpclient.o tcpserver.o helpers.o cmdline_backend.o N_OBJ = main.o tap.o mode_cmdline.o # Compilation Options -CFLAGS := -Wall -std=gnu99 -g -Werror -O0 -pthread +CFLAGS := -Wall -std=gnu99 -g -O0 -pthread CPPFLAGS := -I include/ -I ../nativelib/include K_CPPFLAGS := -I $(KERNEL_SRC)include -I $(MODULE_SRC) -I ../../Usermode/Libraries/ld-acess.so_src/include_exp/ LDFLAGS += -Wl,--defsym,__buildnum=$(BUILD_NUM) -g -L .. -lpthread -lnativelib diff --git a/Tools/NetTest/vfs_shim.c b/Tools/NetTest/vfs_shim.c index 6d420646fa7e3371829cd259cbd4492f4ec83b4d..d2d1d5fe5c45bb3cf3d0ff71816062edb25c1280 100644 --- a/Tools/NetTest/vfs_shim.c +++ b/Tools/NetTest/vfs_shim.c @@ -12,7 +12,7 @@ // === CODE === int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode) { - const int maxfd = *Threads_GetMaxFD(); + const int maxfd = *Threads_GetMaxFD(NULL); tVFS_Handle *handles = *Threads_GetHandlesPtr(); if( !handles ) { handles = calloc( maxfd, sizeof(tVFS_Handle) ); @@ -34,7 +34,7 @@ int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode) tVFS_Handle *VFS_GetHandle(int FD) { - const int maxfd = *Threads_GetMaxFD(); + const int maxfd = *Threads_GetMaxFD(NULL); tVFS_Handle *handles = *Threads_GetHandlesPtr(); if( !handles ) return NULL; @@ -47,7 +47,7 @@ tVFS_Handle *VFS_GetHandle(int FD) int VFS_SetHandle(int FD, tVFS_Node *Node, int Mode) { - const int maxfd = *Threads_GetMaxFD(); + const int maxfd = *Threads_GetMaxFD(NULL); tVFS_Handle *handles = *Threads_GetHandlesPtr(); if( !handles ) return -1; diff --git a/Tools/NetTest_Runner/Makefile b/Tools/NetTest_Runner/Makefile index e9575793bb1b8b6202740ad133b078e3d1730100..59704c70404fec4ba9c18b01adb817144229e9c6 100644 --- a/Tools/NetTest_Runner/Makefile +++ b/Tools/NetTest_Runner/Makefile @@ -6,7 +6,7 @@ OBJ += link.o OBJ += test_arp.o test_tcp.o BIN := ../nettest_runner -CFLAGS := -Wall -std=c99 +CFLAGS := -Wall -std=c99 -g CPPFLAGS := -Iinclude LIBS := @@ -23,7 +23,7 @@ $(BIN): $(OBJ) @echo [CC] -o $@ @$(CC) $(LINKFLAGS) -o $@ $(OBJ) $(LIBS) -obj/%.o: %.c +obj/%.o: %.c Makefile @mkdir -p $(dir $@) @echo [CC] -c -o $@ @$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< -MMD -MP diff --git a/Tools/NetTest_Runner/include/stack.h b/Tools/NetTest_Runner/include/stack.h index 7ac2083b3e69ddd69849c1f06f13cbfd00772351..0110f04b4622996f2455c15bfbec253219dadff0 100644 --- a/Tools/NetTest_Runner/include/stack.h +++ b/Tools/NetTest_Runner/include/stack.h @@ -12,7 +12,7 @@ extern void Stack_AddInterface(const char *Name, int AddrType, const void *Addr, extern void Stack_AddRoute(int Type, const void *Network, int MaskBits, const void *NextHop); extern void Stack_AddArg(const char *Fmt, ...); -extern int Stack_Start(const char *Subcommand); +extern int Stack_Start(const char *TestName, const char *Subcommand); extern void Stack_Kill(void); extern int Stack_SendCommand(const char *CommandString, ...); diff --git a/Tools/NetTest_Runner/include/test.h b/Tools/NetTest_Runner/include/test.h index bf2da1516c83030e28956d8934655edb434a8852..9ad23c35cce0e3699962d978e69a9935b3d9e904 100644 --- a/Tools/NetTest_Runner/include/test.h +++ b/Tools/NetTest_Runner/include/test.h @@ -6,6 +6,7 @@ #include <stddef.h> #define TEST_SETNAME(name) test_setname(name) +#define TEST_STEP(name) do{}while(0) //test_setstep(name) #define TEST_ASSERT(cnd) do{if(!(cnd)) {test_assertion_fail(__FILE__,__LINE__,"%s",#cnd);return false;}}while(0) #define TEST_ASSERT_REL(a,r,b) do{long long a_val=(a),b_val=(b);if(!(a_val r b_val)) {test_assertion_fail(__FILE__,__LINE__,"%s(0x%llx)%s%s(0x%llx)",#a,a_val,#r,#b,b_val);return false;}}while(0) #define TEST_WARN(msg...) test_message(__FILE__,__LINE__,msg) @@ -16,5 +17,18 @@ extern void test_assertion_fail(const char *filename, int line, const char *test extern void test_trace(const char *msg, ...); extern void test_trace_hexdump(const char *hdr, const void *data, size_t len); +// Some helpful macros +// - They require some names to be present +#define RX_HEADER \ + size_t rxlen, ofs, len; \ + do { ofs = 0; ofs = ofs; len = 0; len = len; } while(0);\ + char rxbuf[MTU] +#define TEST_HEADER \ + TEST_SETNAME(__func__);\ + RX_HEADER + +#define TEST_ASSERT_rx() TEST_ASSERT( rxlen = Net_Receive(0, sizeof(rxbuf), rxbuf, ERX_TIMEOUT) ) +#define TEST_ASSERT_no_rx() TEST_ASSERT( Net_Receive(0, sizeof(rxbuf), rxbuf, NRX_TIMEOUT) == 0 ) + #endif diff --git a/Tools/NetTest_Runner/include/tests.h b/Tools/NetTest_Runner/include/tests.h index a96f3881f9cd1d190916f653bf789a5035d8f465..f6cc1356c85fe83ee316efeebebb90fc923a6a1a 100644 --- a/Tools/NetTest_Runner/include/tests.h +++ b/Tools/NetTest_Runner/include/tests.h @@ -10,6 +10,7 @@ extern bool Test_ARP_Basic(void); extern bool Test_TCP_Basic(void); +extern bool Test_TCP_Reset(void); extern bool Test_TCP_WindowSizes(void); #endif diff --git a/Tools/NetTest_Runner/main.c b/Tools/NetTest_Runner/main.c index b1d95c13f847b93b897171e8fba0f8e4c69f6a97..5c175d71e8d60f633478c560fc7168b5c96c71e3 100644 --- a/Tools/NetTest_Runner/main.c +++ b/Tools/NetTest_Runner/main.c @@ -23,43 +23,54 @@ int main(int argc, char *argv[]) return 1; typedef bool t_test(void); - t_test *tests[] = { - Test_ARP_Basic, - Test_TCP_Basic, - Test_TCP_WindowSizes, - NULL + struct { + t_test *fcn; + const char *name; + } tests[] = { + #define _(fcn) {fcn, #fcn} + _(Test_ARP_Basic), + _(Test_TCP_Basic), + //_(Test_TCP_WindowSizes), + _(Test_TCP_Reset), + {NULL,NULL} }; + // Truncate the two output files // TODO: Move to stack.c - FILE *fp; - fp = fopen("stdout.txt", "w"); fclose(fp); - fp = fopen("stderr.txt", "w"); fclose(fp); + fclose( fopen("stdout.txt", "w") ); + fclose( fopen("stderr.txt", "w") ); Net_Open(0, "/tmp/acess2net"); - for(int i = 0; tests[i]; i ++ ) + int n_pass = 0; + int n_fail = 0; + for(int i = 0; tests[i].fcn; i ++ ) { Stack_AddDevice("/tmp/acess2net", (char[]){TEST_MAC}); Stack_AddInterface("eth0", 4, (const char[]){TEST_IP}, 24); Stack_AddRoute(4, "\0\0\0\0", 0, (const char[]){HOST_IP}); - if( Stack_Start("cmdline") ) + if( Stack_Start(tests[i].name, "cmdline") ) goto teardown; if( Net_Receive(0, 1, &argc, 1000) == 0 ) goto teardown; - if( tests[i]() ) - printf("%s: PASS\n", gsTestName); + bool result = tests[i].fcn(); + + printf("%s: %s\n", gsTestName, (result ? "PASS" : "FAIL")); + if(result) + n_pass ++; else - printf("%s: FAIL\n", gsTestName); + n_fail ++; teardown: Stack_Kill(); } Net_Close(0); unlink("/tmp/acess2net"); + printf("--- All tests done %i pass, %i fail\n", n_pass, n_fail); - return 0; + return n_fail; } void PrintUsage(const char *ProgName) diff --git a/Tools/NetTest_Runner/net.c b/Tools/NetTest_Runner/net.c index 231df5024ff1c4284e67ce608da85276661e7efa..4cbf3c8de88ffc8682f8d615f4cf875eb86ac988 100644 --- a/Tools/NetTest_Runner/net.c +++ b/Tools/NetTest_Runner/net.c @@ -9,6 +9,8 @@ #include <sys/select.h> #include "net.h" #include <stdint.h> +#include <unistd.h> // unlink/... +#include <sys/time.h> // gettimeofday #define CONNECT_TIMEOUT 10*1000 #define MAX_IFS 4 @@ -145,7 +147,7 @@ size_t Net_Receive(int IfNum, size_t MaxLen, void *DestBuf, unsigned int Timeout if( Net_int_EnsureConnected(IfNum) && WaitOnFD(If->FD, false, Timeout) ) { - size_t rv = recvfrom(If->FD, DestBuf, MaxLen, 0, &If->addr, &If->addrlen); + size_t rv = recvfrom(If->FD, DestBuf, MaxLen, 0, (struct sockaddr*)&If->addr, &If->addrlen); Net_int_SavePacket(If, rv, DestBuf); return rv; } @@ -160,7 +162,7 @@ void Net_Send(int IfNum, size_t Length, const void *Buf) if( !WaitOnFD(If->FD, true, CONNECT_TIMEOUT) ) return ; Net_int_SavePacket(If, Length, Buf); - int rv = sendto(If->FD, Buf, Length, 0, &If->addr, If->addrlen); + int rv = sendto(If->FD, Buf, Length, 0, (struct sockaddr*)&If->addr, If->addrlen); if( rv < 0 ) perror("Net_Send - send"); } diff --git a/Tools/NetTest_Runner/stack.c b/Tools/NetTest_Runner/stack.c index 7d5e2613fd7c0a3a36755951e4dc36ceb54b1a26..07f8be7a58aea02e76126416d6aa9a2983dcca52 100644 --- a/Tools/NetTest_Runner/stack.c +++ b/Tools/NetTest_Runner/stack.c @@ -12,6 +12,8 @@ #include <fcntl.h> #include <spawn.h> +#include <sys/types.h> +#include <sys/wait.h> #define MAX_ARGS 16 @@ -53,6 +55,7 @@ void Stack_AddInterface(const char *Name, int AddrType, const void *Addr, int Ma break; default: assert(AddrType == 4); + fprintf(stderr, "Stack_AddInterface: Bad address type %i\n", AddrType); exit(1); } } @@ -63,14 +66,24 @@ void Stack_AddRoute(int Type, const void *Network, int MaskBits, const void *Nex void Stack_AddArg(const char *Fmt, ...) { + if( giNumStackArgs == MAX_ARGS ) { + fprintf(stderr, "ERROR: Too many arguments to stack, %i max\n", MAX_ARGS); + return ; + } va_list args; + va_start(args, Fmt); size_t len = vsnprintf(NULL, 0, Fmt, args); va_end(args); + char *arg = malloc(len+1); + assert(arg); + va_start(args, Fmt); vsnprintf(arg, len+1, Fmt, args); va_end(args); + + assert( arg[len] == '\0' ); gasStackArgs[giNumStackArgs++] = arg; } @@ -81,7 +94,7 @@ void sigchld_handler(int signum) fprintf(stderr, "FAILURE: Child exited (%i)\n", status); } -int Stack_Start(const char *Subcommand) +int Stack_Start(const char *RunName, const char *Subcommand) { Stack_AddArg(Subcommand); @@ -96,8 +109,8 @@ int Stack_Start(const char *Subcommand) fcntl(giStack_InFD, F_SETFD, FD_CLOEXEC); FILE *fp; - fp = fopen("stdout.txt", "a"); fprintf(fp, "--- Startup\n"); fclose(fp); - fp = fopen("stderr.txt", "a"); fprintf(fp, "--- Startup\n"); fclose(fp); + fp = fopen("stdout.txt", "a"); fprintf(fp, "--- TEST: %s\n", RunName); fclose(fp); + fp = fopen("stderr.txt", "a"); fprintf(fp, "--- TEST: %s\n", RunName); fclose(fp); posix_spawn_file_actions_t fa; posix_spawn_file_actions_init(&fa); @@ -123,6 +136,10 @@ void Stack_Kill(void) kill(giStack_PID, SIGTERM); giStack_PID = 0; } + + for( int i = 1; i < giNumStackArgs; i ++ ) + free(gasStackArgs[i]); + giNumStackArgs = 1; } int Stack_SendCommand(const char *Fmt, ...) diff --git a/Tools/NetTest_Runner/test_arp.c b/Tools/NetTest_Runner/test_arp.c index 92acc718e4f66b77ee156e185cec294c90bbc9b7..9c6f04447eb6c32db5f268e035d68a29ef14e720 100644 --- a/Tools/NetTest_Runner/test_arp.c +++ b/Tools/NetTest_Runner/test_arp.c @@ -6,25 +6,26 @@ #include "stack.h" #include "arp.h" +static const int ERX_TIMEOUT = 1000; // Expect RX timeout (timeout=failure) +static const int NRX_TIMEOUT = 250; // Not expect RX timeout (timeout=success) + bool Test_ARP_Basic(void) { - TEST_SETNAME(__func__); - size_t rxlen; - char rxbuf[MTU]; + TEST_HEADER; // Request test machine's IP ARP_SendRequest(0, BLOB(TEST_IP)); - TEST_ASSERT( rxlen = Net_Receive(0, sizeof(rxbuf), rxbuf, 1000) ); + TEST_ASSERT_rx(); TEST_ASSERT( ARP_Pkt_IsResponse(rxlen, rxbuf, BLOB(TEST_IP), BLOB(TEST_MAC)) ); // Request host machine's IP ARP_SendRequest(0, BLOB(HOST_IP)); - TEST_ASSERT( Net_Receive(0, sizeof(rxbuf), rxbuf, 1000) == 0 ); + TEST_ASSERT_no_rx(); #if 0 // Ask test machine to request our IP Stack_SendCommand("arprequest "HOST_IP_STR); - TEST_ASSERT( rxlen = Net_Receive(0, sizeof(rxbuf), rxbuf, 1000) ); + TEST_ASSERT_rx(); TEST_ASSERT( ARP_Pkt_IsRequest(rxlen, rxbuf, HOST_IP) ); // Respond @@ -32,7 +33,7 @@ bool Test_ARP_Basic(void) // Ask test machine to request our IP again (expecting nothing) Stack_SendCommand("arprequest "HOST_IP_STR); - TEST_ASSERT( !Net_Receive(0, sizeof(rxbuf), rxbuf, 1000) ); + TEST_ASSERT_no_rx(); #endif return true; diff --git a/Tools/NetTest_Runner/test_tcp.c b/Tools/NetTest_Runner/test_tcp.c index 36942a5a1f0890fa6149699965d0c45d2d51d283..42aa2d5032c77c6bf480d14e55812452d74c6959 100644 --- a/Tools/NetTest_Runner/test_tcp.c +++ b/Tools/NetTest_Runner/test_tcp.c @@ -4,6 +4,7 @@ * * test_tcp.c * - Tests for the behavior of the "Transmission Control Protocol" + * - These tests are written off RFC793 */ #include "test.h" #include "tests.h" @@ -13,20 +14,18 @@ #include "tcp.h" #include <string.h> -#define TEST_ASSERT_rx() TEST_ASSERT( rxlen = Net_Receive(0, sizeof(rxbuf), rxbuf, ERX_TIMEOUT) ) -#define TEST_ASSERT_no_rx() TEST_ASSERT( Net_Receive(0, sizeof(rxbuf), rxbuf, NRX_TIMEOUT) == 0 ) -const int ERX_TIMEOUT = 1000; // Expect RX timeout (timeout=failure) -const int NRX_TIMEOUT = 250; // Not expect RX timeout (timeout=success) -const int RETX_TIMEOUT = 1000; // OS PARAM - Retransmit timeout -const int LOST_TIMEOUT = 1000; // OS PARAM - Time before sending an ACK -const int DACK_TIMEOUT = 500; // OS PARAM - Timeout for delayed ACKs -const size_t DACK_BYTES = 4096; // OS PARAM - Threshold for delayed ACKs +#define TEST_TIMERS 0 + +static const int ERX_TIMEOUT = 1000; // Expect RX timeout (timeout=failure) +static const int NRX_TIMEOUT = 250; // Not expect RX timeout (timeout=success) +static const int RETX_TIMEOUT = 1000; // OS PARAM - Retransmit timeout +static const int LOST_TIMEOUT = 1000; // OS PARAM - Time before sending an ACK +static const int DACK_TIMEOUT = 500; // OS PARAM - Timeout for delayed ACKs +static const size_t DACK_BYTES = 4096; // OS PARAM - Threshold for delayed ACKs bool Test_TCP_Basic(void) { - TEST_SETNAME(__func__); - size_t rxlen, ofs, len; - char rxbuf[MTU]; + TEST_HEADER; tTCPConn testconn = { .IFNum = 0, .AF = 4, @@ -48,6 +47,7 @@ bool Test_TCP_Basic(void) // > RFC793 Pg.65 // 1.1. Send SYN packet + TEST_STEP("1.1. Send SYN packet to CLOSED"); TCP_SendC(&testconn, TCP_SYN, testblob_len, testblob); testconn.RSeq = 0; testconn.LSeq += testblob_len; @@ -57,6 +57,7 @@ bool Test_TCP_Basic(void) TEST_ASSERT_REL(ofs, ==, rxlen); // 1.2. Send a SYN,ACK packet + TEST_STEP("1.2. Send SYN,ACK packet to CLOSED"); testconn.RSeq = 12345; TCP_SendC(&testconn, TCP_SYN|TCP_ACK, 0, NULL); // Expect a TCP_RST with SEQ=ACK @@ -66,6 +67,7 @@ bool Test_TCP_Basic(void) testconn.LSeq ++; // 1.3. Send a RST packet + TEST_STEP("1.2. Send RST packet to CLOSED"); TCP_SendC(&testconn, TCP_RST, 0, NULL); // Expect nothing TEST_ASSERT_no_rx(); @@ -183,7 +185,7 @@ bool Test_TCP_Basic(void) // 2.6. Close connection (TCP FIN) TCP_SendC(&testconn, TCP_ACK|TCP_FIN, 0, NULL); testconn.LSeq ++; // Empty = 1 byte - // Expect ACK? (Does acess do delayed ACKs here?) + // Expect ACK? (Does Acess do delayed ACKs here?) TEST_ASSERT_rx(); TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_ACK) ); TEST_ASSERT_REL( len, ==, 0 ); @@ -206,20 +208,41 @@ bool Test_TCP_Basic(void) return true; } +bool Test_TCP_int_OpenConnection(tTCPConn *Conn) +{ + RX_HEADER; + // >> SYN + TCP_SendC(Conn, TCP_SYN, 0, NULL); + Conn->LSeq ++; + TEST_ASSERT_rx(); + // << SYN|ACK (save remote sequence number) + TCP_SkipCheck_Seq(true); + TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, Conn, TCP_SYN|TCP_ACK) ); + TEST_ASSERT_REL(len, ==, 0); + Conn->RSeq = TCP_Pkt_GetSeq(rxlen, rxbuf, Conn->AF) + 1; + // >> ACK + TCP_SendC(Conn, TCP_ACK, 0, NULL); + TEST_ASSERT_no_rx(); + return true; +} + +#if 0 bool Test_TCP_SYN_RECEIVED(void) { - TEST_SETNAME(__func__); + TEST_HEADER; + // 1. Get into SYN-RECEIVED + TCP_SendC(&testconn, TCP_SYN, 0, NULL); // 2. Send various non-ACK packets return false; } +#endif -bool Test_TCP_WindowSizes(void) +bool Test_TCP_Reset(void) { - TEST_SETNAME(__func__); - size_t rxlen, ofs, len; - char rxbuf[MTU]; + TEST_HEADER; + tTCPConn testconn = { .IFNum = 0, .AF = 4, @@ -231,20 +254,71 @@ bool Test_TCP_WindowSizes(void) .RSeq = 0x600, .Window = 128 }; - char testdata[152]; - memset(testdata, 0xAB, sizeof(testdata)); - + Stack_SendCommand("tcp_echo_server %i", testconn.RPort); - // > Open Connection + + // 1. Response in listen-based SYN-RECEIVED + // >> SYN TCP_SendC(&testconn, TCP_SYN, 0, NULL); testconn.LSeq ++; + // << SYN|ACK :: Now in SYN-RECEIVED TEST_ASSERT_rx(); TCP_SkipCheck_Seq(true); TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_SYN|TCP_ACK) ); TEST_ASSERT_REL(len, ==, 0); testconn.RSeq = TCP_Pkt_GetSeq(rxlen, rxbuf, testconn.AF) + 1; + // >> RST (not ACK) + TCP_SendC(&testconn, TCP_RST, 0, NULL); + // << nothing (connection should now be dead) + TEST_ASSERT_no_rx(); + // >> ACK (this should be to a closed conneciton, see LISTEN[ACK] above) TCP_SendC(&testconn, TCP_ACK, 0, NULL); + // << RST + TEST_ASSERT_rx(); + TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_RST) ); + TEST_ASSERT_REL(len, ==, 0); + + // 2. Response in open-based SYN-RECEIVED? (What is that?) + TEST_WARN("TODO: RFC793 pg70 mentions OPEN-based SYN-RECEIVED"); + + testconn.LPort += 1234; + // ESTABLISHED[RST] - RFC793:Pg70 + // 2. Response in ESTABLISHED + TEST_ASSERT( Test_TCP_int_OpenConnection(&testconn) ); + // >> RST + TCP_SendC(&testconn, TCP_RST, 0, NULL); + // << no response, connection closed TEST_ASSERT_no_rx(); + // >> ACK (LISTEN[ACK]) + TCP_SendC(&testconn, TCP_ACK, 0, NULL); + // << RST + TEST_ASSERT_rx(); + TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_RST) ); + TEST_ASSERT_REL(len, ==, 0); + + return true; +} + +bool Test_TCP_WindowSizes(void) +{ + TEST_HEADER; + tTCPConn testconn = { + .IFNum = 0, + .AF = 4, + .LAddr = BLOB(HOST_IP), + .RAddr = BLOB(TEST_IP), + .LPort = 44359, + .RPort = 9, + .LSeq = 0x600, + .RSeq = 0x600, + .Window = 128 + }; + char testdata[152]; + memset(testdata, 0xAB, sizeof(testdata)); + + Stack_SendCommand("tcp_echo_server %i", testconn.RPort); + // > Open Connection + TEST_ASSERT( Test_TCP_int_OpenConnection(&testconn) ); // 1. Test remote respecting our transmission window (>=1 byte) // > Send more data than our RX window @@ -265,7 +339,47 @@ bool Test_TCP_WindowSizes(void) TEST_ASSERT_REL(len, ==, 1); testconn.RSeq += len; // 2. Test remote handling our window being 0 (should only send ACKs) + // TODO: // 3. Test that remote drops data outside of its RX window // 3.1. Ensure that data that wraps the end of the RX window is handled correctly + // TODO: + return false; +} + +// RFC793 pg41 +bool Test_TCP_Retransmit(void) +{ + TEST_HEADER; + tTCPConn testconn = { + .IFNum = 0, + .AF = 4, + .LAddr = BLOB(HOST_IP), + .RAddr = BLOB(TEST_IP), + .LPort = 44359, + .RPort = 9, + .LSeq = 0x600, + .RSeq = 0x600, + .Window = 128 + }; + char testdata[128]; + memset(testdata, 0xAB, sizeof(testdata)); + + TEST_STEP("1. Open and connect to TCP server"); + Stack_SendCommand("tcp_echo_server %i", testconn.RPort); + TEST_ASSERT( Test_TCP_int_OpenConnection(&testconn) ); + + + TEST_STEP("2. Send data and expect it to be echoed"); + TCP_SendC(&testconn, TCP_PSH, sizeof(testdata), testdata); + testconn.LSeq += sizeof(testdata); + TEST_ASSERT_rx(); + TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_ACK|TCP_PSH) ); + + TEST_STEP("3. Expect nothing for TCP_RTX_TIMEOUT_1"); + TEST_ASSERT( Net_Receive(0, sizeof(rxbuf), rxbuf, RETX_TIMEOUT-100) == 0 ); + + TEST_STEP("4. Expect a retransmit"); + TEST_ASSERT_rx(); + return false; } diff --git a/Tools/nativelib/Makefile b/Tools/nativelib/Makefile index 1a50d88128722ea0a4eb2863e0d66048a8f1b5fd..8a8fc3300df42bc687a288a33f0fb6d672e0d0f9 100644 --- a/Tools/nativelib/Makefile +++ b/Tools/nativelib/Makefile @@ -19,7 +19,7 @@ KOBJ := $(KOBJ:%.o=obj/_Kernel/%.o) OBJ := $(NOBJ) $(LOBJ) $(KOBJ) BIN := ../libnativelib.a -CFLAGS := -Wall -std=c99 -Werror +CFLAGS := -Wall -std=c99 CPPFLAGS := -I include diff --git a/Tools/nativelib/include/threads_int.h b/Tools/nativelib/include/threads_int.h index 7bd91c17ec92431c3d9e4e666096b1176df9eca8..08bb4f789fa2ebc56fc316295272c1b11dadd65d 100644 --- a/Tools/nativelib/include/threads_int.h +++ b/Tools/nativelib/include/threads_int.h @@ -103,12 +103,12 @@ extern int Threads_int_CreateThread(struct sThread *Thread); extern int Threads_int_ThreadingEnabled(void); -extern tThread *Proc_GetCurThread(void); -extern tThread *Threads_RemActive(void); -extern void Threads_AddActive(tThread *Thread); +extern struct sThread *Proc_GetCurThread(void); +extern struct sThread *Threads_RemActive(void); +extern void Threads_AddActive(struct sThread *Thread); extern void Threads_int_WaitForStatusEnd(enum eThreadStatus Status); -extern int Threads_int_Sleep(enum eThreadStatus Status, void *Ptr, int Num, tThread **ListHead, tThread **ListTail, tShortSpinlock *Lock); -extern void Semaphore_ForceWake(tThread *Thread); +extern int Threads_int_Sleep(enum eThreadStatus Status, void *Ptr, int Num, struct sThread **ListHead, struct sThread **ListTail, tShortSpinlock *Lock); +extern void Semaphore_ForceWake(struct sThread *Thread); extern tThreadIntMutex *Threads_int_MutexCreate(void); extern void Threads_int_MutexDestroy(tThreadIntMutex *Mutex); diff --git a/Tools/nativelib/threads.c b/Tools/nativelib/threads.c index dafdc404ce6d87cac00a625a683266ebf6cb55c6..f80447334fcc89e47d5d7332c2d1e3c526600c40 100644 --- a/Tools/nativelib/threads.c +++ b/Tools/nativelib/threads.c @@ -40,9 +40,12 @@ tGID Threads_GetGID(void) { return 0; } tTID Threads_GetTID(void) { return lpThreads_This ? lpThreads_This->TID : 0; } -int *Threads_GetMaxFD(void) { return &lpThreads_This->Process->MaxFDs; } -char **Threads_GetCWD(void) { return &lpThreads_This->Process->CWD; } -char **Threads_GetChroot(void) { return &lpThreads_This->Process->Chroot; } +static inline tProcess* getproc(tProcess *Process) { + return (Process ? Process : lpThreads_This->Process); +} +int *Threads_GetMaxFD(tProcess *Process) { return &getproc(Process)->MaxFDs; } +char **Threads_GetCWD(tProcess *Process) { return &getproc(Process)->CWD; } +char **Threads_GetChroot(tProcess *Process) { return &getproc(Process)->Chroot; } void **Threads_GetHandlesPtr(void) { return &lpThreads_This->Process->Handles; } void Threads_Yield(void) diff --git a/UDI/Tools/udibuild.ini b/UDI/Tools/udibuild.ini index 227adc02f09129b1b9fabe7c29652d659f91e3c1..c5187fac11f755bfbac8677f987cc0580c79abb9 100644 --- a/UDI/Tools/udibuild.ini +++ b/UDI/Tools/udibuild.ini @@ -1,6 +1,8 @@ [COMMON] [ia32] -CFLAGS=-ffreestanding -I/home/tpg/Projects/GitClones/acess2/UDI/include/ +CFLAGS=-ffreestanding -I/home/tpg/Projects/GitClones/acess2/UDI/include/ -Wall -Wextra -Wno-unused-parameter +# -std=c89 +# -Wc++-compat CC=i586-elf-gcc LD=i586-elf-ld diff --git a/UDI/Tools/udibuild_src/build.c b/UDI/Tools/udibuild_src/build.c index 4d0b294781cc59d55c67a65ba378538caee23ba9..88f047385cd623f1bf9627c111acfe1cb36fa129 100644 --- a/UDI/Tools/udibuild_src/build.c +++ b/UDI/Tools/udibuild_src/build.c @@ -40,6 +40,9 @@ int Build_CompileFile(tIniFile *opts, const char *abi, tUdiprops *udiprops, tUdi srcfile->CompileOpts ? srcfile->CompileOpts : "", srcfile->Filename, objfile); printf("--- Compiling: %s\n", srcfile->Filename); + if( gbTraceEnabled ) { + printf(">> %s\n", cmd); + } int rv = system(cmd); free(cmd); free(objfile); @@ -110,7 +113,9 @@ int Build_LinkObjects(tIniFile *opts, const char *abi, tUdiprops *udiprops) abi, udiprops->ModuleName, objfiles_str, udiprops_c ); printf("--- Linking: bin/%s/%s\n", abi, udiprops->ModuleName); - printf("%s\n", cmd); + if( gbTraceEnabled ) { + printf(">> %s\n", cmd); + } int rv = system(cmd); free(cmd); free(udiprops_c); diff --git a/UDI/Tools/udibuild_src/include/common.h b/UDI/Tools/udibuild_src/include/common.h index 0cb419b66b7f364824fe93baa36fd55e6d63f923..2f92913e502ce31daedcede2c79169dcd8d20d81 100644 --- a/UDI/Tools/udibuild_src/include/common.h +++ b/UDI/Tools/udibuild_src/include/common.h @@ -9,6 +9,7 @@ #define _COMMON_H_ #include <stdarg.h> +#include <stdbool.h> #ifndef __GNUC__ # define __attribute__(...) @@ -16,5 +17,7 @@ extern char *mkstr(const char *fmt, ...) __attribute__((format(printf,1,2))); +extern bool gbTraceEnabled; + #endif diff --git a/UDI/Tools/udibuild_src/main.c b/UDI/Tools/udibuild_src/main.c index b5b0042e770b1afc9365c8d6a2f118f317170caf..f933cc1bc5f21eec2b17bbe26bdad15daf3befdf 100644 --- a/UDI/Tools/udibuild_src/main.c +++ b/UDI/Tools/udibuild_src/main.c @@ -29,6 +29,7 @@ void Usage(const char *progname); // === GLOBALS === +bool gbTraceEnabled = false; const char *gsRuntimeDir = RUNTIME_DIR; const char *gsOpt_ConfigFile; const char *gsOpt_WorkingDir; diff --git a/UDI/drivers/gfx_bochs/bochsga_common.h b/UDI/drivers/gfx_bochs/bochsga_common.h new file mode 100644 index 0000000000000000000000000000000000000000..5d40cfac964b52798089766239d77f1cd0acdfde --- /dev/null +++ b/UDI/drivers/gfx_bochs/bochsga_common.h @@ -0,0 +1,74 @@ +/* + * UDI Bochs Graphics Driver + * By John Hodge (thePowersGang) + * + * bochsga_common.c + * - Common definitions + */ +#ifndef _BOCHSGA_COMMON_H_ +#define _BOCHSGA_COMMON_H_ + +/** + * Definitions to match udiprops.txt + * \{ + */ +#define BOCHSGA_META_BUS 1 +#define BOCHSGA_META_GFX 2 + +#define BOCHSGA_OPS_DEV 1 +#define BOCHSGA_OPS_GFX 2 + +#define BOCHSGA_CB_BUS_BIND 1 +#define BOCHSGA_CB_GFX_BIND 2 +#define BOCHSGA_CB_GFX_STATE 3 +#define BOCHSGA_CB_GFX_RANGE 4 +#define BOCHSGA_CB_GFX_COMMAND 5 + +#define BOCHSGA_MSGNUM_PROPUNK 1001 +#define BOCHSGA_MSGNUM_BUFUNK 1002 +/** + * \} + */ + +#include "bochsga_pio.h" + +typedef struct { + udi_ubit32_t width; + udi_ubit32_t height; + udi_index_t bitdepth; +} engine_t; + +#define N_ENGINES 1 + +/** + * Region data + */ +typedef struct +{ + udi_cb_t *active_cb; + struct { + udi_index_t pio_index; + } init; + + udi_pio_handle_t pio_handles[N_PIO]; + + udi_boolean_t output_enable; + struct { + udi_ubit32_t width; + udi_ubit32_t height; + udi_ubit8_t bitdepth; + udi_index_t engine; + } outputstate; + struct { + udi_ubit32_t max_width; // 1024 or 1280 + udi_ubit32_t max_height; // 768 or 1024 + } limits; + + engine_t engines[N_ENGINES]; +} rdata_t; + +#define BOCHSGA_MIN_WIDTH 360 +#define BOCHSGA_MIN_HEIGHT 240 + +#endif + diff --git a/UDI/drivers/gfx_bochs/bochsga_core.c b/UDI/drivers/gfx_bochs/bochsga_core.c new file mode 100644 index 0000000000000000000000000000000000000000..458f89339c33a6cd3756484aeeba7e18856190ba --- /dev/null +++ b/UDI/drivers/gfx_bochs/bochsga_core.c @@ -0,0 +1,485 @@ +/* + * UDI Bochs Graphics Driver + * By John Hodge (thePowersGang) + * + * bochsga_core.c + * - Core Code + */ +#define UDI_VERSION 0x101 +#define UDI_PHYSIO_VERSION 0x101 +#define UDI_GFX_VERSION 0x101 +#define UDI_PCI_VERSION 0x101 +#include <udi.h> +#include <udi_physio.h> +#include <udi_gfx.h> +#include <udi_pci.h> +#define DEBUG_ENABLED 1 +#include "../helpers.h" +#include "../helpers_gfx.h" +#include "bochsga_common.h" + +/* --- Management Metalang -- */ +void bochsga_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level) +{ + //rdata_t *rdata = UDI_GCB(cb)->context; + /*udi_trace_write(rdata->init_context, UDI_TREVENT_LOCAL_PROC_ENTRY, 0, );*/ + + /* TODO: Set up region data */ + + udi_usage_res(cb); +} + +void bochsga_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level) +{ + //rdata_t *rdata = UDI_GCB(cb)->context; + udi_instance_attr_list_t *attr_list = cb->attr_list; + + switch(enumeration_level) + { + case UDI_ENUMERATE_START: + case UDI_ENUMERATE_START_RESCAN: + cb->attr_valid_length = attr_list - cb->attr_list; + udi_enumerate_ack(cb, UDI_ENUMERATE_OK, BOCHSGA_OPS_GFX); + break; + case UDI_ENUMERATE_NEXT: + udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0); + break; + } +} +void bochsga_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID) +{ +} +void bochsga_final_cleanup_req(udi_mgmt_cb_t *cb) +{ +} +/* --- */ +void bochsga_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb); +void bochsga_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb, udi_dma_constraints_t dma_constraints, udi_ubit8_t perferred_endianness, udi_status_t status); +void bochsga_bus_dev_bind__pio_map(udi_cb_t *cb, udi_pio_handle_t new_pio_handle); +void bochsga_bus_dev_bind__intr_chanel(udi_cb_t *gcb, udi_channel_t new_channel); +void bochsga_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb); + +void bochsga_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb) +{ + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + + switch(cb->event) + { + case UDI_CHANNEL_CLOSED: + break; + case UDI_CHANNEL_BOUND: { + rdata->active_cb = gcb; + udi_bus_bind_cb_t *bus_bind_cb = UDI_MCB(cb->params.parent_bound.bind_cb, udi_bus_bind_cb_t); + udi_bus_bind_req( bus_bind_cb ); + // continue at bochsga_bus_dev_bus_bind_ack + return; } + } +} +void bochsga_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb, + udi_dma_constraints_t dma_constraints, udi_ubit8_t perferred_endianness, udi_status_t status) +{ + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + + /* Set up PIO handles */ + rdata->init.pio_index = -1; + bochsga_bus_dev_bind__pio_map(gcb, UDI_NULL_PIO_HANDLE); + /* V V V V */ +} +void bochsga_bus_dev_bind__pio_map(udi_cb_t *gcb, udi_pio_handle_t new_pio_handle) +{ + rdata_t *rdata = gcb->context; + if( rdata->init.pio_index != (udi_index_t)-1 ) + { + rdata->pio_handles[rdata->init.pio_index] = new_pio_handle; + } + + rdata->init.pio_index ++; + if( rdata->init.pio_index < N_PIO ) + { + const struct s_pio_ops *ops = &bochsga_pio_ops[rdata->init.pio_index]; + udi_pio_map(bochsga_bus_dev_bind__pio_map, gcb, + ops->regset_idx, ops->base_offset, ops->length, + ops->trans_list, ops->list_length, + UDI_PIO_LITTLE_ENDIAN, 0, 0 + ); + return ; + } + + udi_channel_event_complete( UDI_MCB(rdata->active_cb, udi_channel_event_cb_t), UDI_OK); + // = = = = = +} +void bochsga_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb) +{ +} +void bochsga_bus_dev_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status) +{ +} +void bochsga_bus_dev_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb) +{ +} + +/* --- GFX Provider ops -- */ +void bochsga_gfx_channel_event_ind(udi_channel_event_cb_t *cb) +{ + /* No operation */ +} +void bochsga_gfx_bind_req(udi_gfx_bind_cb_t *cb) +{ + /* TODO: ACK bind if nothing already bound */ +} +void bochsga_gfx_unbind_req(udi_gfx_bind_cb_t *cb) +{ + /* TODO: Release internal state? */ +} +void bochsga_gfx_set_connector_req$pio(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result) +{ + udi_gfx_state_cb_t *cb = UDI_MCB(gcb, udi_gfx_state_cb_t); + udi_gfx_set_connector_ack(cb); +} +void bochsga_gfx_set_connector_req(udi_gfx_state_cb_t *cb, udi_ubit32_t value) +{ + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + + switch(cb->attribute) + { + case UDI_GFX_PROP_ENABLE: + if( rdata->output_enable != !!value ) + { + rdata->output_enable = !!value; + udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb, + rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate); + return ; + } + udi_gfx_set_connector_ack(cb); + return; + /* Change input engine */ + case UDI_GFX_PROP_INPUT: + udi_gfx_set_connector_ack(cb); + return; + /* Alter output dimensions */ + case UDI_GFX_PROP_WIDTH: + if( value % 8 != 0 ) { + /* Qemu doesn't like resolutions not a multiple of 8 */ + return ; + } + if( !(320 <= value && value <= rdata->limits.max_width) ) { + return ; + } + rdata->outputstate.width = value; + udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb, + rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate); + return; + case UDI_GFX_PROP_HEIGHT: + if( !(240 <= value && value <= rdata->limits.max_height) ) { + return ; + } + rdata->outputstate.height = value; + udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb, + rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate); + return; + } + CONTIN(bochsga_gfx_set_connector_req, udi_log_write, + (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute), + (udi_status_t status) + ); + udi_gfx_state_cb_t *cb = UDI_MCB(cb, udi_gfx_state_cb_t); + udi_gfx_set_connector_ack(cb /*, UDI_STAT_NOT_SUPPORTED*/); +} +void bochsga_gfx_get_connector_req(udi_gfx_state_cb_t *cb) +{ + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + + switch(cb->attribute) + { + case UDI_GFX_PROP_ENABLE: + udi_gfx_get_connector_ack(cb, !!rdata->output_enable); + return; + case UDI_GFX_PROP_INPUT: + udi_gfx_get_connector_ack(cb, 0); + return; + case UDI_GFX_PROP_WIDTH: + udi_gfx_get_connector_ack(cb, rdata->outputstate.width); + return; + case UDI_GFX_PROP_HEIGHT: + udi_gfx_get_connector_ack(cb, rdata->outputstate.height); + return; + case UDI_GFX_PROP_CONNECTOR_TYPE: + udi_gfx_get_connector_ack(cb, UDI_GFX_CONNECTOR_HIDDEN); + return; + case UDI_GFX_PROP_SIGNAL: + udi_gfx_get_connector_ack(cb, UDI_GFX_SIGNAL_INTEGRATED); + return; + } + CONTIN(bochsga_gfx_get_connector_req, udi_log_write, + (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute), + (udi_status_t status) + ); + udi_gfx_state_cb_t *cb = UDI_MCB(cb, udi_gfx_state_cb_t); + udi_gfx_get_connector_ack(cb, 0); +} +void bochsga_gfx_range_connector_req(udi_gfx_range_cb_t *cb) +{ + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + + switch(cb->attribute) + { + case UDI_GFX_PROP_ENABLE: + /* 2 values: 0 and 1 */ + gfxhelpers_return_range_set(udi_gfx_range_connector_ack, cb, 2, 0, 1); + return; + case UDI_GFX_PROP_INPUT: + /* Fix 0 */ + gfxhelpers_return_range_fixed(udi_gfx_range_connector_ack, cb, 0); + return; + case UDI_GFX_PROP_WIDTH: + /* qemu restricts to 8 step */ + gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb, + BOCHSGA_MIN_WIDTH, rdata->limits.max_width, 8); + return; + case UDI_GFX_PROP_HEIGHT: + /* step of 8 for neatness */ + gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb, + BOCHSGA_MIN_HEIGHT, rdata->limits.max_height, 8); + return; + case UDI_GFX_PROP_CONNECTOR_TYPE: + gfxhelpers_return_range_fixed(udi_gfx_range_connector_ack, cb, UDI_GFX_CONNECTOR_HIDDEN); + return; + case UDI_GFX_PROP_SIGNAL: + gfxhelpers_return_range_fixed(udi_gfx_range_connector_ack, cb, UDI_GFX_SIGNAL_INTEGRATED); + return; + } + CONTIN(bochsga_gfx_range_connector_req, udi_log_write, + (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute), + (udi_status_t status) + ); + udi_gfx_range_cb_t *cb = UDI_MCB(cb, udi_gfx_range_cb_t); + udi_gfx_range_connector_ack(cb); +} + +/* --- Engine Manipulation --- */ +void bochsga_gfx_set_engine_req(udi_gfx_state_cb_t *cb, udi_ubit32_t value) +{ + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + + if( cb->subsystem >= N_ENGINES ) { + udi_gfx_get_engine_ack(cb, 0); + return; + } + + engine_t *engine = &rdata->engines[cb->subsystem]; + + switch(cb->attribute) + { + case UDI_GFX_PROP_WIDTH: + engine->width = value; + udi_gfx_set_engine_ack(cb); + return; + case UDI_GFX_PROP_HEIGHT: + engine->height = value; + udi_gfx_set_engine_ack(cb); + return; + } + CONTIN(bochsga_gfx_set_engine_req, udi_log_write, + (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute), + (udi_status_t status) + ); + udi_gfx_state_cb_t *cb = UDI_MCB(cb, udi_gfx_state_cb_t); + udi_gfx_set_engine_ack(cb); +} +void bochsga_gfx_get_engine_req(udi_gfx_state_cb_t *cb) +{ + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + + if( cb->subsystem >= N_ENGINES ) { + udi_gfx_get_engine_ack(cb, 0); + return; + } + + const engine_t *engine = &rdata->engines[cb->subsystem]; + + switch(cb->attribute) + { + case UDI_GFX_PROP_ENABLE: + udi_gfx_get_engine_ack(cb, 1); + return; + + case UDI_GFX_PROP_INPUT: + udi_gfx_get_engine_ack(cb, -1); + return; + + case UDI_GFX_PROP_WIDTH: + udi_gfx_get_engine_ack(cb, engine->width); + return; + case UDI_GFX_PROP_HEIGHT: + udi_gfx_get_engine_ack(cb, engine->height); + return; + + case UDI_GFX_PROP_STOCK_FORMAT: + udi_gfx_get_engine_ack(cb, UDI_GFX_STOCK_FORMAT_R8G8B8); + return; + } + CONTIN(bochsga_gfx_get_engine_req, udi_log_write, + (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute), + (udi_status_t status) + ); + udi_gfx_state_cb_t *cb = UDI_MCB(cb, udi_gfx_state_cb_t); + udi_gfx_get_engine_ack(cb, 0); +} +void bochsga_gfx_range_engine_req(udi_gfx_range_cb_t *cb) +{ + udi_cb_t *gcb = UDI_GCB(cb); + rdata_t *rdata = gcb->context; + (void)rdata; + + if( cb->subsystem >= N_ENGINES ) { + udi_gfx_range_engine_ack(cb); + return; + } + + //engine_t *engine = &rdata->engines[cb->subsystem]; + + switch(cb->attribute) + { + case UDI_GFX_PROP_ENABLE: + gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb, 1); + return; + case UDI_GFX_PROP_INPUT: + gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb, -1); + return; + + case UDI_GFX_PROP_STOCK_FORMAT: + gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb, UDI_GFX_STOCK_FORMAT_B8G8R8); + return; + } + CONTIN(bochsga_gfx_range_engine_req, udi_log_write, + (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute), + (udi_status_t status) + ); + udi_gfx_range_cb_t *cb = UDI_MCB(cb, udi_gfx_range_cb_t); + udi_gfx_range_engine_ack( cb ); +} +void bochsga_gfx_get_engine_operator_req(udi_gfx_range_cb_t *cb) +{ + /* TODO: Get Engine operator */ + udi_gfx_get_engine_operator_ack(cb, 0, 0,0,0); +} +void bochsga_gfx_connector_command_req(udi_gfx_command_cb_t *cb) +{ + /* Need to parse the GLX stream */ + udi_gfx_connector_command_ack(cb); +} +void bochsga_gfx_engine_command_req(udi_gfx_command_cb_t *cb) +{ + /* Need to parse the GLX stream */ + udi_gfx_engine_command_ack(cb); +} +void bochsga_gfx_buffer_info_req(udi_gfx_buffer_info_cb_t *cb) +{ + udi_cb_t *gcb = UDI_GCB(cb); + switch(cb->buffer_index) + { + case 0: + udi_gfx_buffer_info_ack(cb, 1024, 768, 24, 0); + return; + default: + break; + } + CONTIN(bochsga_gfx_buffer_info_req, udi_log_write, + (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_BUFUNK, __func__, cb->buffer_index), + (udi_status_t status) + ); + udi_gfx_buffer_info_cb_t *cb = UDI_MCB(gcb, udi_gfx_buffer_info_cb_t); + udi_gfx_buffer_info_ack(cb, 0,0,0,0); +} +void bochsga_gfx_buffer_write_req(udi_gfx_buffer_cb_t *cb) +{ +} +void bochsga_gfx_buffer_read_req(udi_gfx_buffer_cb_t *cb) +{ +} + +/* +==================================================================== +Management ops +==================================================================== +*/ +udi_mgmt_ops_t bochsga_mgmt_ops = { + bochsga_usage_ind, + bochsga_enumerate_req, + bochsga_devmgmt_req, + bochsga_final_cleanup_req +}; +udi_ubit8_t bochsga_mgmt_op_flags[4] = {0,0,0,0}; +/* - Bus Ops */ +udi_bus_device_ops_t bochsga_bus_dev_ops = { + bochsga_bus_dev_channel_event_ind, + bochsga_bus_dev_bus_bind_ack, + bochsga_bus_dev_bus_unbind_ack, + bochsga_bus_dev_intr_attach_ack, + bochsga_bus_dev_intr_detach_ack +}; +udi_ubit8_t bochsga_bus_dev_ops_flags[5] = {0}; +/* - GFX provider ops */ +udi_gfx_provider_ops_t bochsga_gfx_ops = { + bochsga_gfx_channel_event_ind, + bochsga_gfx_bind_req, + bochsga_gfx_unbind_req, + bochsga_gfx_set_connector_req, + bochsga_gfx_set_engine_req, + bochsga_gfx_get_connector_req, + bochsga_gfx_get_engine_req, + bochsga_gfx_range_connector_req, + bochsga_gfx_range_engine_req, + bochsga_gfx_get_engine_operator_req, + bochsga_gfx_connector_command_req, + bochsga_gfx_engine_command_req, + bochsga_gfx_buffer_info_req, + bochsga_gfx_buffer_read_req, + bochsga_gfx_buffer_write_req, +}; +udi_ubit8_t bochsga_gfx_ops_flags[10] = {0}; +/* -- */ +udi_primary_init_t bochsga_pri_init = { + .mgmt_ops = &bochsga_mgmt_ops, + .mgmt_op_flags = bochsga_mgmt_op_flags, + .mgmt_scratch_requirement = 0, + .enumeration_attr_list_length = 0, + .rdata_size = sizeof(rdata_t), + .child_data_size = 0, + .per_parent_paths = 0 +}; +udi_ops_init_t bochsga_ops_list[] = { + { + BOCHSGA_OPS_DEV, BOCHSGA_META_BUS, UDI_BUS_DEVICE_OPS_NUM, + 0, + (udi_ops_vector_t*)&bochsga_bus_dev_ops, + bochsga_bus_dev_ops_flags + }, + { + BOCHSGA_OPS_GFX, BOCHSGA_META_GFX, UDI_GFX_PROVIDER_OPS_NUM, + 0, + (udi_ops_vector_t*)&bochsga_gfx_ops, + bochsga_gfx_ops_flags + }, + {0} +}; +udi_cb_init_t bochsga_cb_init_list[] = { + {BOCHSGA_CB_BUS_BIND, BOCHSGA_META_BUS, UDI_BUS_BIND_CB_NUM, 0, 0,NULL}, + {BOCHSGA_CB_GFX_BIND, BOCHSGA_META_GFX, UDI_GFX_BIND_CB_NUM, 0, 0,NULL}, + {BOCHSGA_CB_GFX_STATE, BOCHSGA_META_GFX, UDI_GFX_STATE_CB_NUM, 0, 0,NULL}, + {BOCHSGA_CB_GFX_RANGE, BOCHSGA_META_GFX, UDI_GFX_RANGE_CB_NUM, 0, 0,NULL}, + {BOCHSGA_CB_GFX_COMMAND, BOCHSGA_META_GFX, UDI_GFX_COMMAND_CB_NUM, 0, 0,NULL}, + {0} +}; +const udi_init_t udi_init_info = { + .primary_init_info = &bochsga_pri_init, + .ops_init_list = bochsga_ops_list, + .cb_init_list = bochsga_cb_init_list, +}; diff --git a/UDI/drivers/gfx_bochs/bochsga_engines.h b/UDI/drivers/gfx_bochs/bochsga_engines.h new file mode 100644 index 0000000000000000000000000000000000000000..272f0be76c67d464dcac855dd9634d21c862a3ad --- /dev/null +++ b/UDI/drivers/gfx_bochs/bochsga_engines.h @@ -0,0 +1,34 @@ +/* + * + */ + +#define BOCHSGA_ENGINE_PROP_BUFFER (UDI_GFX_PROP_CUSTOM+0) + +/* === CONSTANTS === */ +const gfxhelpers_op_t bochsga_engine_ops_8bpp[] = { +}; +const gfxhelpers_op_t bochsga_engine_ops_32bpp[] = { + {UDI_GFX_OPERATOR_RGB, 1, 2, 3}, /* #0 Output RGB from ops #1,#2,#3 */ + {UDI_GFX_OPERATOR_SEG, 4, 16, 8}, /* #1 Extract 8 bits from bit 16 of #4 */ + {UDI_GFX_OPERATOR_SEG, 4, 8, 8}, /* #2 8 bits from ofs 8 of #4 */ + {UDI_GFX_OPERATOR_SEG, 4, 0, 8}, /* #3 8 bits from ofs 0 of #4 */ + {UDI_GFX_OPERATOR_BUFFER, 5, 6, 32}, /* #4 32 bits from buffer #5 ofs #6 */ + {UDI_GFX_OPERATOR_ATTR, 0, BOCHSGA_ENGINE_PROP_BUFFER, 0}, /* #5 Buffer index */ + {UDI_GFX_OPERATOR_MAD, 7, 8, 9}, /* #6 Get offset (#8 * #7 + #9) */ + {UDI_GFX_OPERATOR_ATTR, 0, UDI_GFX_PROP_SOURCE_WIDTH, 0}, /* #7 Read buffer width */ + {UDI_GFX_OPERATOR_Y, 0, 0, 0}, /* #8 Y coordinate */ + {UDI_GFX_OPERATOR_X, 0, 0, 0} /* #9 X coordinate */ +}; + +typedef struct { + udi_ubit8_t bitdepth; + gfxhelpers_op_map_t op_map; +} engine_static_t; + +const engine_static_t bochsga_engine_defs[] = { + {.bitdepth = 8, .op_map = {ARRAY_COUNT(bochsga_engine_ops_8bpp), bochsga_engine_ops_8bpp}}, + {.bitdepth = 16}, + {.bitdepth = 24}, + {.bitdepth = 32, .op_map = {ARRAY_COUNT(bochsga_engine_ops_8bpp), bochsga_engine_ops_32bpp}}, +}; +#define N_ENGINES ARRAY_COUNT(bochsga_engine_defs) diff --git a/UDI/drivers/gfx_bochs/bochsga_pio.h b/UDI/drivers/gfx_bochs/bochsga_pio.h new file mode 100644 index 0000000000000000000000000000000000000000..f5ddf2656d4cb4bc2aedd14a0c88e077a5c4eed5 --- /dev/null +++ b/UDI/drivers/gfx_bochs/bochsga_pio.h @@ -0,0 +1,22 @@ +/* + * TODO + */ +#ifndef _BOCHSGA_PIO_H_ +#define _BOCHSGA_PIO_H_ + +udi_pio_trans_t bochsga_pio_enable[] = { + {UDI_PIO_END_IMM, UDI_PIO_2BYTE, 0}, + }; + +enum { + BOCHSGA_PIO_ENABLE, +}; + +const struct s_pio_ops bochsga_pio_ops[] = { + [BOCHSGA_PIO_ENABLE] = UDIH_PIO_OPS_ENTRY(bochsga_pio_enable, 0, UDI_PCI_BAR_2, 0x400, 0xB*2), +// UDIH_PIO_OPS_ENTRY(bochsga_pio_enable, 0, UDI_PCI_BAR_2, 0x400, 0xB*2), + }; +#define N_PIO (sizeof(bochsga_pio_ops)/sizeof(struct s_pio_ops)) + +#endif + diff --git a/UDI/drivers/gfx_bochs/udiprops.txt b/UDI/drivers/gfx_bochs/udiprops.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b43d5c1852bddd138a940e3d1aab8b0bbb54c33 --- /dev/null +++ b/UDI/drivers/gfx_bochs/udiprops.txt @@ -0,0 +1,43 @@ +properties_version 0x101 +supplier 1 +contact 2 +name 3 +shortname bochsga +release 5 1.0 + +requires udi 0x101 +requires udi_physio 0x101 +requires udi_bridge 0x101 +requires udi_gfx 0x101 + +meta 1 udi_bridge +meta 2 udi_gfx +#meta 3 udi_gio + +parent_bind_ops 1 0 1 1 # bridge, rgn 0, ops 1, cb 1 +child_bind_ops 2 0 2 # Provider +#parent_bind_ops 3 0 2 3 # GIO bound to 3D provider + +#enumerates 102 1 1 3 gio_type string software3d + +# - Classic non-PCI version +device 100 1 bus string system sysbus_io_addr_lo ubit32 0x01CE sysbus_io_size ubit32 2 sysbys_mem_addr_lo ubit32 0xE0000000 sysbus_mem_size 0x400000 +# - PCI Version (Non-indexed registers at offset 0x500 in BAR2 MMIO) +device 101 1 bus string pci pci_vendor_id ubit32 0x1234 pci_device_id ubit32 0x1111 pci_base_class ubit32 0x03 pci_sub_clais ubit32 0x00 pci_prog_if ubit32 0x00 + +# Messages +message 1 John Hodge (thePowersGang) +message 2 udi@mutabah.net +message 3 Bochs Graphics Adapter +message 5 BochsGA +message 100 BochsGA ISA Device +message 101 BochsGA PCI Device + +message 1001 "Unknown property passed to %s: %i" + +module bochsga +region 0 + +# Source-only udiprops +compile_options -Wall +source_files bochsga_core.c diff --git a/UDI/drivers/helpers.h b/UDI/drivers/helpers.h new file mode 100644 index 0000000000000000000000000000000000000000..dde98164c6cff4952c611d11e28ce44affbe8155 --- /dev/null +++ b/UDI/drivers/helpers.h @@ -0,0 +1,87 @@ +/* + * UDI Driver helper macros + */ +#ifndef _UDI_HELPERS_H_ +#define _UDI_HELPERS_H_ + +#if DEBUG_ENABLED +# define DEBUG_OUT(fmt, v...) udi_debug_printf("%s: "fmt"\n", __func__ ,## v) +#else +# define DEBUG_OUT(...) do{}while(0) +#endif + +#define ARRAY_COUNT(arr) (sizeof(arr)/sizeof(arr[0])) + +#define __EXPJOIN(a,b) a##b +#define _EXPJOIN(a,b) __EXPJOIN(a,b) +#define _EXPLODE(params...) params +#define _ADDGCB(params...) (udi_cb_t *gcb, params) +#define CONTIN(suffix, call, args, params) extern void _EXPJOIN(suffix##$,__LINE__) _ADDGCB params;\ + call( _EXPJOIN(suffix##$,__LINE__), gcb, _EXPLODE args); } \ + void _EXPJOIN(suffix##$,__LINE__) _ADDGCB params { \ + rdata_t *rdata = gcb->context; \ + (void)rdata; + +/* Copied from http://projectudi.cvs.sourceforge.net/viewvc/projectudi/udiref/driver/udi_dpt/udi_dpt.h */ +#define UDIH_SET_ATTR_BOOLEAN(attr, name, val) \ + udi_strcpy((attr)->attr_name, (name)); \ + (attr)->attr_type = UDI_ATTR_BOOLEAN; \ + (attr)->attr_length = sizeof(udi_boolean_t); \ + UDI_ATTR32_SET((attr)->attr_value, (val)) + +#define UDIH_SET_ATTR32(attr, name, val) \ + udi_strcpy((attr)->attr_name, (name)); \ + (attr)->attr_type = UDI_ATTR_UBIT32; \ + (attr)->attr_length = sizeof(udi_ubit32_t); \ + UDI_ATTR32_SET((attr)->attr_value, (val)) + +#define UDIH_SET_ATTR_ARRAY8(attr, name, val, len) \ + udi_strcpy((attr)->attr_name, (name)); \ + (attr)->attr_type = UDI_ATTR_ARRAY8; \ + (attr)->attr_length = (len); \ + udi_memcpy((attr)->attr_value, (val), (len)) + +#define UDIH_SET_ATTR_STRING(attr, name, val, len) \ + udi_strcpy((attr)->attr_name, (name)); \ + (attr)->attr_type = UDI_ATTR_STRING; \ + (attr)->attr_length = (len); \ + udi_strncpy_rtrim((char *)(attr)->attr_value, (val), (len)) +#define UDIH_SET_ATTR_STRFMT(attr, name, maxlen, fmt, v...) \ + udi_strcpy((attr)->attr_name, (name)); \ + (attr)->attr_type = UDI_ATTR_STRING; \ + (attr)->attr_length = udi_snprintf((char *)(attr)->attr_value, (maxlen), (fmt) ,## v ) + +/** + * \brief UDI PIO Helpers + */ +struct s_pio_ops { + udi_pio_trans_t *trans_list; + udi_ubit16_t list_length; + udi_ubit16_t pio_attributes; + udi_ubit32_t regset_idx; + udi_ubit32_t base_offset; + udi_ubit32_t length; +}; +#define UDIH_PIO_OPS_ENTRY(list, attr, regset, base, len) {list, ARRAY_COUNT(list), attr, regset, base, len} + + +#define UDIH_INIT_PIO(fcnname, _array, index_field, final_code) \ + void fcnname(udi_cb_t *gcb, udi_pio_handle_t new_pio_handle) {\ + rdata_t *rdata = gcb->context; \ + if( rdata->index_field != (udi_index_t)-1 ) { \ + rdata->pio_handles[rdata->index_field] = new_pio_handle; \ + }\ + rdata->index_field ++; \ + if( rdata->index_field < sizeof(_array)/sizeof(_array[0]) ) { \ + const struct s_pio_ops *ops = &pio_ops[rdata->index_field]; \ + udi_pio_map(bus_dev_bind__pio_map, gcb, \ + ops->regset_idx, ops->base_offset, ops->length, \ + ops->trans_list, ops->list_length, \ + UDI_PIO_LITTLE_ENDIAN, 0, 0 \ + ); \ + return ; \ + } \ + final_code \ + } + +#endif diff --git a/UDI/drivers/helpers_gfx.h b/UDI/drivers/helpers_gfx.h new file mode 100644 index 0000000000000000000000000000000000000000..999a4082ba674e0e5e3ea056ac48f7ed8d29cabb --- /dev/null +++ b/UDI/drivers/helpers_gfx.h @@ -0,0 +1,50 @@ +/* + * UDI Driver Helper Macros + * + * GFX-specific helpers + */ +#ifndef _HELPERS_GFX_H_ +#define _HELPERS_GFX_H_ + +#if __STDC_VERSION__ < 199901L +# define inline +#endif + +typedef struct { + udi_index_t op; + udi_ubit32_t arg_1; + udi_ubit32_t arg_2; + udi_ubit32_t arg_3; +} gfxhelpers_op_t; + +typedef struct { + udi_index_t op_count; + const gfxhelpers_op_t *ops; +} gfxhelpers_op_map_t; + +static inline void gfxhelpers_return_range_simple( + udi_gfx_range_connector_ack_op_t *callback, udi_gfx_range_cb_t *cb, + udi_ubit32_t min, udi_ubit32_t max, udi_ubit32_t step + ) +{ + +} + +static inline void gfxhelpers_return_range_set( + udi_gfx_range_connector_ack_op_t *callback, udi_gfx_range_cb_t *cb, + udi_ubit32_t count, ... + ) +{ + +} + +static inline void gfxhelpers_return_range_fixed( + udi_gfx_range_connector_ack_op_t *callback, udi_gfx_range_cb_t *cb, + udi_ubit32_t value + ) +{ + gfxhelpers_return_range_simple(callback, cb, value, value, 1); +} + +#endif + diff --git a/UDI/drivers/net_ne2000/ne2000_common.h b/UDI/drivers/net_ne2000/ne2000_common.h index b6a1689664711179db8219dc23211a1ddccf1a1d..d4e58aa34fb5326d7d04cf0c3d72f67c6a54a73f 100644 --- a/UDI/drivers/net_ne2000/ne2000_common.h +++ b/UDI/drivers/net_ne2000/ne2000_common.h @@ -8,8 +8,14 @@ #ifndef _NE2000_COMMON_H_ #define _NE2000_COMMON_H_ +#define UDI_VERSION 0x101 +#define UDI_PHYSIO_VERSION 0x101 +#define UDI_PCI_VERSION 0x101 +#define UDI_NIC_VERSION 0x101 + #include <udi.h> #include <udi_physio.h> +#include <udi_pci.h> #include <udi_nic.h> #include "ne2000_hw.h" @@ -77,10 +83,15 @@ typedef struct (attr)->attr_type = UDI_ATTR_STRING; \ (attr)->attr_length = (len); \ udi_strncpy_rtrim((char *)(attr)->attr_value, (val), (len)) -#define NE2K_SET_ATTR_STRFMT(attr, name, maxlen, fmt, v...) \ +#define NE2K_SET_ATTR_STRFMT(attr, name, maxlen, fmt, ...) \ udi_strcpy((attr)->attr_name, (name)); \ (attr)->attr_type = UDI_ATTR_STRING; \ - (attr)->attr_length = udi_snprintf((char *)(attr)->attr_value, (maxlen), (fmt) ,## v ) + (attr)->attr_length = udi_snprintf((char *)(attr)->attr_value, (maxlen), (fmt) ,## __VA_ARGS__ ) + +extern udi_usage_ind_op_t ne2k_usage_ind; +extern udi_enumerate_req_op_t ne2k_enumerate_req; +extern udi_devmgmt_req_op_t ne2k_devmgmt_req; +extern udi_final_cleanup_req_op_t ne2k_final_cleanup_req; extern udi_channel_event_ind_op_t ne2k_bus_dev_channel_event_ind; extern udi_bus_bind_ack_op_t ne2k_bus_dev_bus_bind_ack; diff --git a/UDI/drivers/net_ne2000/ne2000_core.c b/UDI/drivers/net_ne2000/ne2000_core.c index 2e44db1879c6147214322acb924ebd03e1fcbb4f..d630a8d4abba32239321b2db36416dbbce5daf1b 100644 --- a/UDI/drivers/net_ne2000/ne2000_core.c +++ b/UDI/drivers/net_ne2000/ne2000_core.c @@ -5,8 +5,6 @@ * ne2000_core.c * - UDI initialisation */ -#include <udi.h> -#include <udi_nic.h> #include "ne2000_common.h" enum { @@ -66,6 +64,9 @@ void ne2k_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level) case UDI_ENUMERATE_NEXT: udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0); break; + default: + udi_assert(!"invalid enumeration_level"); + break; } } void ne2k_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID) @@ -90,6 +91,9 @@ void ne2k_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb) udi_bus_bind_req( bus_bind_cb ); // continue at ne2k_bus_dev_bus_bind_ack return; } + default: + udi_assert(!"invalid channel event"); + break; } } void ne2k_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb, @@ -240,7 +244,7 @@ void ne2k_nd_ctrl_bind__rx_chan_ok(udi_cb_t *gcb, udi_channel_t new_channel) cb->max_perfect_multicast = 0; cb->max_total_multicast = 0; cb->mac_addr_len = 6; - memcpy(cb->mac_addr, rdata->macaddr, 6); + udi_memcpy(cb->mac_addr, rdata->macaddr, 6); udi_nsr_bind_ack( cb, UDI_OK ); // = = = = } diff --git a/UDI/drivers/net_ne2000/ne2000_rx.c b/UDI/drivers/net_ne2000/ne2000_rx.c index dda35770e2856b639a1eb70f952e61298958eb52..9b4b3c32370195dd8c62dd15049beb268517c408 100644 --- a/UDI/drivers/net_ne2000/ne2000_rx.c +++ b/UDI/drivers/net_ne2000/ne2000_rx.c @@ -5,6 +5,8 @@ * ne2000_rx.c * - Receive Code */ +#define UDI_VERSION 0x101 +#define UDI_NIC_VERSION 0x101 #include <udi.h> #include <udi_nic.h> #include "ne2000_common.h" @@ -45,7 +47,7 @@ void ne2k_intr__rx_ok(udi_cb_t *gcb) rdata->rx_next_cb = rx_cb->chain; rx_cb->chain = NULL; udi_debug_printf("ne2k_intr__rx_ok: Initialising buffer\n"); - udi_buf_write(ne2k_rx__buf_allocated, UDI_GCB(rx_cb), NULL, 1520, rx_cb->rx_buf, 0, 0, NULL); + udi_buf_write(ne2k_rx__buf_allocated, UDI_GCB(rx_cb), NULL, 1520, rx_cb->rx_buf, 0, 0, UDI_NULL_BUF_PATH); } else { diff --git a/UDI/drivers/net_ne2000/ne2000_tx.c b/UDI/drivers/net_ne2000/ne2000_tx.c index b943ae8827d111f7e6e526cc64c9952aaf3ac752..0e54fad2f089fdf66adddb9aa99cdbc518b554e7 100644 --- a/UDI/drivers/net_ne2000/ne2000_tx.c +++ b/UDI/drivers/net_ne2000/ne2000_tx.c @@ -5,6 +5,8 @@ * ne2000_tx.c * - Transmit Code */ +#define UDI_VERSION 0x101 +#define UDI_NIC_VERSION 0x101 #include <udi.h> #include <udi_nic.h> #include "ne2000_common.h" diff --git a/UDI/drivers/uart_16c550/uart16c550.c b/UDI/drivers/uart_16c550/uart16c550.c index cfe77707be24bda6c93a43646e41133b2f2e060e..510bc47202e8b3a149a0e9d199d956fe45e407c4 100644 --- a/UDI/drivers/uart_16c550/uart16c550.c +++ b/UDI/drivers/uart_16c550/uart16c550.c @@ -5,8 +5,12 @@ * uart16c550.c * - UDI initialisation */ +#define UDI_VERSION 0x101 +#define UDI_PCI_VERSION 0x101 +#define UDI_PHYSIO_VERSION 0x101 #include <udi.h> #include <udi_physio.h> +#include <udi_pci.h> #include "uart16c550_common.h" #include "uart16c550_pio.h" @@ -100,7 +104,7 @@ void uart_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb, void uart_bus_dev_bind__pio_map(udi_cb_t *gcb, udi_pio_handle_t new_pio_handle) { rdata_t *rdata = gcb->context; - if( rdata->init.pio_index != -1 ) + if( rdata->init.pio_index != (udi_index_t)-1 ) { rdata->pio_handles[rdata->init.pio_index] = new_pio_handle; } diff --git a/UDI/gfx_spec_issues.txt b/UDI/gfx_spec_issues.txt new file mode 100644 index 0000000000000000000000000000000000000000..e97aea4ffd23cab8b991e898739aeead1482b9cf --- /dev/null +++ b/UDI/gfx_spec_issues.txt @@ -0,0 +1,31 @@ + + +- Indexed engine operator list (would be better as second set of calls) + > Arguments can be passed using custom attributes +- GL-centric operations (would be better with read_buffer/write_buffer calls) +- No status returned from operations most +- Input data format specifcation + > Engine operator list specifies it, but in an abstract way (which would require quite smart code to determine) + > Doable though, but having a RO property on the engine that notes if it uses a standard pixel format would be nice + + +Engine inspection API: +> Readonly? Property for number of operations + - Readonly because modifcation of the count is not possible + - Attributes can be read, so that's your config mechanisim +> udi_gfx_engine_getop_req(udi_gfx_state_cb_t *cb); +> udi_gfx_engine_getop_ack(udi_gfx_state_cb_t *cb, udi_ubit8_t operation, udi_ubit32_t arg1, udi_ubit32_t arg2, udi_ubit32_t arg3); + + +Buffer manipulation API: + + struct { + udi_cb_t gcb; + udi_index_t buffer_idx; + udi_ubit32_t offset; + udi_buffer_t *data; + } udi_gfx_buffer_cb_t; + +> udi_gfx_buffer_write_req(udi_gfx_buffer_cb_t *cb); +> udi_gfx_buffer_write_ack(udi_gfx_buffer_cb_t *cb, udi_status_t status); +> (OPTIONAL) udi_gfx_buffer_read_req(udi_gfx_buffer_cb_t *cb); diff --git a/UDI/include/udi.h b/UDI/include/udi.h index 50c7077a4957b186af0962dad37aca4c425fee87..76dac7baac84e95cda42f0b735f4985c56b99e0b 100644 --- a/UDI/include/udi.h +++ b/UDI/include/udi.h @@ -4,6 +4,16 @@ #ifndef _UDI_H_ #define _UDI_H_ +#ifndef UDI_VERSION +# error "Please define UDI_VERSION before including" +#endif +#if UDI_VERSION < 0x100 +# error "Requesting an unsupported UDI version (pre 1.0)" +#endif +#if UDI_VERSION > 0x101 +# error "Requesting an unsupported UDI version (post 1.01)" +#endif + #include <stdint.h> #include <stdarg.h> diff --git a/UDI/include/udi_gfx.h b/UDI/include/udi_gfx.h new file mode 100644 index 0000000000000000000000000000000000000000..cd7db759f2002fb130d51860f775571057430bde --- /dev/null +++ b/UDI/include/udi_gfx.h @@ -0,0 +1,850 @@ +/** + * Summary: udi_gfx.h + * Contains the graphics metalanguage interface details + * + * Author: + * Marcel Sondaar + * + * License: + * <Public Domain> + * + * Origin: + * http:/*www.d-rift.nl/combuster/mos3/?p=viewsource&file=/include/common/udi_gfx.h*/ + */ + +/* note that the specification, and thus, the contents of this file is not fixed.*/ + +#ifndef __UDI_GFX_H__ +#define __UDI_GFX_H__ + +#include <udi.h> + +#ifndef UDI_GFX_VERSION +#error "UDI_GFX_VERSION not defined." +#elif UDI_GFX_VERSION != 0x101 +#error "UDI_GFX_VERSION not supported." +#endif + +/** + * Enumeration: UDI_GFX_PROP + * Lists the various UDI properties + */ + +/* General state properties*/ +/* Constant: UDI_GFX_PROP_ENABLE + * + * Valid values: + * 0 - disabled + * 1 - enabled + * 2 - reset + * + * Ranges: + * Must include at least 1 + * + * The primary state of the connector or engine. An enabled state indicates + * it is functioning and generating live output. A disabled state is one where + * it is not contributing to any output but is otherwise functional. Finally + * the reset state is where the driver is free to deallocate all resources + * corresponding to this component and trash any state not referenced by other + * components. + * + * A disabled or reset engine forwards all data from the previous stage + * unmodified. The disabled state indicates that the component might be + * returned to its enabled state within short notice. + * + * A disabled connector will not send pixel data, but can perform other + * initialisation communication such as DDC. A reset connector will not respond + * in any fashion and can not be used for other purposes. Hardware is expected + * to be powered down in such state. + * + * Users should expect significant delays when moving components in and out of + * the reset state. Moving engines between the enabled and disabled state should + * take effect within one frame, such transition should take effect on a frame + * boundary when supported. + */ +#define UDI_GFX_PROP_ENABLE 0 + +#define UDI_GFX_PROP_ENABLE_DISABLED 0 +#define UDI_GFX_PROP_ENABLE_ENABLED 1 +#define UDI_GFX_PROP_ENABLE_RESET 2 +/* Constant: UDI_GFX_PROP_INPUT + * + * Valid values: + * Any valid engine ID, provided no dependency cycles are created, or -1 + * + * Ranges: + * Any non-empty set of valid values. Often hardwired. + * + * Points to the engine that is processed before this unit. In the case of a + * connector, it points to the last engine in a pipeline, and each engine points + * to the next engine in the sequence. A value of -1 indicates a source that + * only yields black pixels. Implementations must not allow cyclic structures. + * Changing this value may reallocate resources, and engines that are no longer + * referenced may lose their data (but not their state) when it is not part of + * any pipeline. If preservation is required, the ENABLE state should be used + * instead. Valid ranges includes one or more from the list of engines and -1 + * combined. In most cases, this property can not be modified. + */ +#define UDI_GFX_PROP_INPUT 1 +/* Constant: UDI_GFX_PROP_WIDTH + * + * Valid values: + * Any non-zero positive number. + * + * Ranges: + * Contains at least one valid value. Often only multiples of UNIT_WIDTH + * or a power of two are allowed. May be hardwired. + * + * Contains the amount of pixels in the horizontal direction. For connectors, + * this is the amount of data pixels rendered horizontally. For engines, this + * is the width in pixels of the image. Pixels requested from an engine outside + * the range (0..width-1) are defined according to the <UDI_GFX_PROP_CLIP> + * property. In some cases, hardware may support only fixed combinations of + * width and height. In such cases, changing the width will also change the + * height to a corresponding valid number. Valid ranges include any values + * strictly above zero. For connectors, expect large continuous ranges, large + * ranges with a certain modulus, a limited number of fixed values, or a + * constant value. + */ +#define UDI_GFX_PROP_WIDTH 2 +/* Constant: UDI_GFX_PROP_HEIGHT + * + * Valid values: + * Any non-zero positive number. + * + * Ranges: + * Contains at least one valid value. Often only multiples of UNIT_HEIGHT + * or a power of two are allowed. May be hardwired. + * + * Contains the amount of pixels in the vertical direction. Functions similar + * to the width property, but changing it will not alter the width property, + * and it's range at any time contains the valid range for the currently + * selected width. + */ +#define UDI_GFX_PROP_HEIGHT 3 + +/* Constant: UDI_GFX_PROP_CUSTOM + * The first property index of the driver's custom range. These are not assigned + * directly assigned by the UDI specification, but may be specified in the + * operator tree. + */ +#define UDI_GFX_PROP_CUSTOM 1024 + +/* engine properties*/ + +/* Constant: UDI_GFX_PROP_CLIP + * + * Valid values: + * 0 - points outside width x height are passed unmodified from input + * 1 - the engine's contents is tiled with size width x height + * 2 - points outside the width overflow into the y coordinate + * 3 - points outside the height overflow into the x coordinate + * + * Ranges: + * Hardwired zero for connectors. Any non-empty subset for engines, usually + * hardwired. + * + * For engines, contains the behaviour for pixels requested outside the width + * and height of the engine. Can be either 0 (pass from next stage), 1 (the + * coordinates are wrapped modulus the height and width), 2 (the coordinates + * overflow onto the next scanline horizontally, and wrap vertically), 3 (the + * coordinates overflow onto the next column vertically, and wrap horizontally). + * Valid ranges contain one or more of these options. For overlays and sprites, + * a value 0 is common. For framebuffers, 2 is the most common value. For + * connectors, this property is always 0 since they do not store pixel data + */ +#define UDI_GFX_PROP_CLIP 4 + +/* Constant: UDI_GFX_PROP_UNIT_WIDTH + * + * Valid values: + * Any non-zero positive value + * + * Ranges: + * Any non-empty set of valid values. May be hardwired to 1 for + * framebuffers, or a range of small values for hardware scaling, or any + * larger hardwired number or set for tiling engines. + * + * Tiles are used to indicate that the hardware groups sets of pixels and have + * each group share certain properties, i.e. color or tile index, or share the + * same chroma subsample with only a different intensity. If the engine has no + * such grouping, or shares all properties over the entire contents, the value + * of this property should be 1. Some tile examples include rescaling, where a + * tile width of 2 indicates a pixel doubling in X direction, or in text mode + * where a tile width of 8 or 9 corresponds with the width of common bitmap + * fonts + */ +#define UDI_GFX_PROP_UNIT_WIDTH 5 + +/* Constant: UDI_GFX_PROP_UNIT_HEIGHT + * + * Valid values: + * Any non-zero positive value + * + * Ranges: + * Any non-empty set of valid values. May be hardwired to 1 for + * framebuffers, or a range of small values for hardware scaling, or any + * larger hardwired number or set for tiling engines. + * + * See <UDI_GFX_PROP_UNIT_WIDTH>, but for the Y direction. Common values are + * 1-2 for framebuffers (doublescanning on or off), identical to the tile + * width, or mostly independent. + */ +#define UDI_GFX_PROP_UNIT_HEIGHT 6 + +/* Constant: UDI_GFX_PROP_TRANSLATEX + * + * Valid values: + * Any, signed value. + * + * Ranges: + * Any non-empty set. Typical values are hardwired zero, continuous + * between -WIDTH and WIDTH, -WIDTH to zero inclusive, or all possible values + * + * The horizontal offset where drawing starts. A positive value means the top-left + * corner moves towards the right end of the screen, a negative value moves the + * origin off the screen on the left side. Clipped areas moved off the screen do + * not reappear on the opposite side. + * + * With clipping enabled, this field combined with <UDI_GFX_PROP_WIDTH> + * determines the area where the image should be drawn, which is the horizontal + * range from UDI_GFX_PROP_TRANSLATEX to UDI_GFX_PROP_WIDTH + + * UDI_GFX_PROP_TRANSLATEX - 1 + */ +#define UDI_GFX_PROP_TRANSLATEX 7 + +/* Constant: UDI_GFX_PROP_TRANSLATEY + * + * Valid values: + * Any signed value. + * + * Ranges: + * Any non-empty set. Typical values are hardwired zero, continuous + * between -WIDTH and WIDTH, or all possible values + * + * See <UDI_GFX_PROP_TRANSLATEX> but for the Y direction. + */ +#define UDI_GFX_PROP_TRANSLATEY 8 + +#define UDI_GFX_PROP_GL_VERSION 14 +#define UDI_GFX_PROP_GLES_VERSION 15 +#define UDI_GFX_PROP_STATE_BLOCK 16 +#define UDI_GFX_PROP_COLOR_BITS 22 +#define UDI_GFX_PROP_GL_TARGET 23 + +/* Constant: UDI_GFX_PROP_STOCK_FORMAT + * + * Value: + * Zero, or any constant from <UDI_GFX_STOCK_FORMAT> + * + * Ranges: + * Any non-empty set of valid values. + * + * This field indicates the storage format is one from a limited set of + * typical configurations. If the field is zero, the engine is not knowingly + * configured as a common framebuffer. If nonzero, the operator chain and any + * dependent settings are defined to be functionally equivalent to that of a + * typical framebuffer device. + * + * The value zero does not imply that the device does not actually follow a + * set convention. This saves drivers from writing elaborate checking code + * to determine the condition in question. + * + * Writing this field potentially modifies other property fields within the + * same engine to establish the requested configuration. Manually writing such + * properties after changing this setting may in turn revert this property to + * the zero state, even if there was no modification or the behaviour is still + * as previously advertised by this property. + */ +#define UDI_GFX_PROP_STOCK_FORMAT 27 + +/* Constant: UDI_GFX_PROP_OPERATOR_COUNT + * + * Valid values: + * Any non-zero positive number + * + * Ranges: + * Most likely constant. Can be any set of valid values. + * + * The current value is the number of entries in the operator tree that can + * be requested for this engine using <udi_gfx_get_engine_operator_req> and + * <udi_gfx_get_engine_operator_ack> + */ +#define UDI_GFX_PROP_OPERATOR_COUNT 28 + +#if 0 +/* properties for removal:*/ +#define UDI_GFX_PROP_STORE_COUNT 24 /* not generic*/ +#define UDI_GFX_PROP_STORE_WIDTH 9 /* not generic*/ +#define UDI_GFX_PROP_STORE_HEIGHT 10 /* not generic*/ +#define UDI_GFX_PROP_STORE_BITS 11 /* not generic*/ +#define UDI_GFX_PROP_PALETTE 1024 /* optional, can be derived from the operator tree*/ +#define UDI_GFX_PROP_BUFFER 1025 /* optional, can be derived from the operator tree*/ +#define UDI_GFX_PROP_TILESHEET 1026 /* optional, can be derived from the operator tree*/ +#define UDI_GFX_PROP_OPERATOR_INDEX 17 /* deprecated for dedicated methods*/ +#define UDI_GFX_PROP_OPERATOR_OPCODE 18 /* deprecated for dedicated methods*/ +#define UDI_GFX_PROP_OPERATOR_ARG_1 19 /* deprecated for dedicated methods*/ +#define UDI_GFX_PROP_OPERATOR_ARG_2 20 /* deprecated for dedicated methods*/ +#define UDI_GFX_PROP_OPERATOR_ARG_3 21 /* deprecated for dedicated methods*/ +#define UDI_GFX_PROP_SOURCE_WIDTH 12 /* should have been documented when I still knew what it did.*/ +#define UDI_GFX_PROP_SOURCE_HEIGHT 13 /* should have been documented when I still knew what it did.*/ +#define UDI_GFX_PROP_INPUTX 25 /* should have been documented when I still knew what it did.*/ +#define UDI_GFX_PROP_INPUTY 26 /* should have been documented when I still knew what it did.*/ +#endif + +/* connector properties*/ +#define UDI_GFX_PROP_SIGNAL 23 +#define UDI_GFX_PROP_CONNECTOR_TYPE 24 +#define UDI_GFX_PROP_VGA_H_FRONT_PORCH 25 +#define UDI_GFX_PROP_VGA_H_BACK_PORCH 26 +#define UDI_GFX_PROP_VGA_H_SYNC 27 +#define UDI_GFX_PROP_VGA_V_FRONT_PORCH 28 +#define UDI_GFX_PROP_VGA_V_BACK_PORCH 29 +#define UDI_GFX_PROP_VGA_V_SYNC 30 +#define UDI_GFX_PROP_DOT_CLOCK 31 +#define UDI_GFX_PROP_VGA_H_SYNC_POL 32 +#define UDI_GFX_PROP_VGA_V_SYNC_POL 33 + +/** + * Enumeration: UDI_GFX_SIGNAL + * Lists the various signal types + */ +#define UDI_GFX_SIGNAL_HIDDEN 0 +#define UDI_GFX_SIGNAL_INTEGRATED 0 +#define UDI_GFX_SIGNAL_RGBHV 1 +#define UDI_GFX_SIGNAL_RGBS 2 +#define UDI_GFX_SIGNAL_RGSB 3 +#define UDI_GFX_SIGNAL_YPBPR 4 +#define UDI_GFX_SIGNAL_DVID 5 +#define UDI_GFX_SIGNAL_YUV 6 +#define UDI_GFX_SIGNAL_YIQ 7 +#define UDI_GFX_SIGNAL_Y_UV 8 +#define UDI_GFX_SIGNAL_Y_IQ 9 +#define UDI_GFX_SIGNAL_HDMI 10 +#define UDI_GFX_SIGNAL_TEXT 11 +#define UDI_GFX_SIGNAL_CUSTOM 12 + +/** + * Enumeration: UDI_GFX_CONNECTOR + * Lists the various external connectors + */ +#define UDI_GFX_CONNECTOR_HIDDEN 0 +#define UDI_GFX_CONNECTOR_VGA 1 +#define UDI_GFX_CONNECTOR_DVI 2 +#define UDI_GFX_CONNECTOR_SVIDEO 3 +#define UDI_GFX_CONNECTOR_COMPONENT 4 +#define UDI_GFX_CONNECTOR_HDMI 5 +#define UDI_GFX_CONNECTOR_RF 6 +#define UDI_GFX_CONNECTOR_SCART 7 +#define UDI_GFX_CONNECTOR_COMPOSITE 8 +#define UDI_GFX_CONNECTOR_MEMBUFFER 9 + +/** + * Enumeration: UDI_GFX_OPERATOR + * Lists the display output operator + */ +#define UDI_GFX_OPERATOR_RGB 0 /* output = (color) red(a1) + green(a2) + blue(a3) (each component is UDI_GFX_PROP_COLOR_BITS*/ +#define UDI_GFX_OPERATOR_YUV 1 /* output = (color) Y(a1) + U(a2) + V(a3)*/ +#define UDI_GFX_OPERATOR_YIQ 2 /* output = (color) Y(a1) + I(a2) + Q(a3)*/ +#define UDI_GFX_OPERATOR_I 3 /* output = (color) intensity(a1)*/ +#define UDI_GFX_OPERATOR_ALPHA 4 /* output = (color) a1 + alpha(a2)*/ +#define UDI_GFX_OPERATOR_ADD 5 /* output = a1 + a2 + v3*/ +#define UDI_GFX_OPERATOR_SUB 6 /* output = a1 - a2 - v3*/ +#define UDI_GFX_OPERATOR_MUL 7 /* output = a1 * a2*/ +#define UDI_GFX_OPERATOR_DIV 8 /* output = a1 / a2*/ +#define UDI_GFX_OPERATOR_MAD 9 /* output = a1 * a2 + a3*/ +#define UDI_GFX_OPERATOR_FRC 10 /* output = (a1 * a2) / a3*/ +#define UDI_GFX_OPERATOR_SHR 11 /* output = a1 >> (a2 + v3)*/ +#define UDI_GFX_OPERATOR_SHL 12 /* output = a1 << (a2 + v3)*/ +#define UDI_GFX_OPERATOR_ROR 13 /* output = a1 >> a2 (over a3 bits)*/ +#define UDI_GFX_OPERATOR_ROL 14 /* output = a1 << a2 (over a3 bits)*/ +#define UDI_GFX_OPERATOR_SAR 15 /* output = a1 >> a2 (width is a3 bits, i.e. empties are filled with bit a3-1)*/ +#define UDI_GFX_OPERATOR_SAL 16 /* output = a1 <<< (a2 + v3) (empties filled with bit 0)*/ +#define UDI_GFX_OPERATOR_AND 17 /* output = a1 & a2*/ +#define UDI_GFX_OPERATOR_OR 18 /* output = a1 | a2 | v3*/ +#define UDI_GFX_OPERATOR_NOT 19 /* output = ~a1*/ +#define UDI_GFX_OPERATOR_XOR 20 /* output = a1 ^ a2 ^ v3*/ +#define UDI_GFX_OPERATOR_NEG 21 /* output = -a1*/ +#define UDI_GFX_OPERATOR_SEG 22 /* output = (a1 >> v2) & (2**v3-1) (select v3 bits starting from bit v2)*/ +#define UDI_GFX_OPERATOR_RANGE 23 /* output = (a1 > a2) ? a2 : ((a1 < a3) ? a3 : a1)*/ +#define UDI_GFX_OPERATOR_CONST 24 /* output = v1*/ +#define UDI_GFX_OPERATOR_ATTR 25 /* output = property[a1 + v2]*/ +#define UDI_GFX_OPERATOR_SWITCH 26 /* output = output[(a1 % v3) + v2]*/ +#define UDI_GFX_OPERATOR_BUFFER 27 /* output = buffer[a1][a2] (buffer is v3 bits per entry)*/ +#define UDI_GFX_OPERATOR_X 28 /* output = output x pixel*/ +#define UDI_GFX_OPERATOR_Y 29 /* output = output y pixel*/ +#define UDI_GFX_OPERATOR_TX 30 /* output = horizontal tile index belonging to output pixel*/ +#define UDI_GFX_OPERATOR_TY 31 /* output = vertical tile index belonging to output pixel*/ +#define UDI_GFX_OPERATOR_TXOFF 32 /* output = horizontal offset from start of tile*/ +#define UDI_GFX_OPERATOR_TYOFF 33 /* output = vertical offset from start of tile*/ +#define UDI_GFX_OPERATOR_INPUT 34 /* output = input engine[x][y] component v1*/ +#define UDI_GFX_OPERATOR_DINPUT 35 /* output = input engine[a1][a2] component v3*/ + +/* Enumeration: UDI_GFX_STOCK_FORMAT + * Lists stock configurations + * + * When a stock configuration is used, the device is set to behave as a + * simple framebuffer device. The <UDI_GFX_PROP_WIDTH> and <UDI_GFX_PROP_HEIGHT> + * determine the virtual size of the framebuffer, and <UDI_GFX_PROP_TRANSLATEX> + * and <UDI_GFX_PROP_TRANSLATEY> indicate the offset into that framebuffer + * that is visible (which are typically restricted to negative values) + */ +#define UDI_GFX_STOCK_FORMAT_UNKNOWN 0 +#define UDI_GFX_STOCK_FORMAT_R8G8B8X8 1 +#define UDI_GFX_STOCK_FORMAT_B8G8R8X8 2 +#define UDI_GFX_STOCK_FORMAT_R8G8B8 3 +#define UDI_GFX_STOCK_FORMAT_B8G8R8 4 +#define UDI_GFX_STOCK_FORMAT_R5G6B5 5 +#define UDI_GFX_STOCK_FORMAT_B5G6R5 6 +#define UDI_GFX_STOCK_FORMAT_R5G5B5X1 7 +#define UDI_GFX_STOCK_FORMAT_B5G5R5X1 8 +#define UDI_GFX_STOCK_FORMAT_N8 9 + +/* Enumeration: UDI_GFX_BUFFER_INFO_FLAG*/ +/* Lists behavioural patterns for direct buffer accesses.*/ +/**/ +#define UDI_GFX_BUFFER_INFO_FLAG_R 0x0001 /* buffer can be read*/ +#define UDI_GFX_BUFFER_INFO_FLAG_W 0x0002 /* buffer can be written*/ +#define UDI_GFX_BUFFER_INFO_FLAG_BITALIGN_ENTRY 0x0004 /* for non-multiple-of-eight buffer slot sizes, align on byte boundary every unit*/ +#define UDI_GFX_BUFFER_INFO_FLAG_BITALIGN_ROW 0x0008 /* for non-multiple-of-eight buffer slot sizes, align only the start of the row*/ + + +/* Constant: UDI_GFX_PROVIDER_OPS_NUM*/ +/* the ops number used for the graphics driver*/ +#define UDI_GFX_PROVIDER_OPS_NUM 1 + +/* Constant: UDI_GFX_CLIENT_OPS_NUM*/ +/* the ops number used for the graphics application*/ +#define UDI_GFX_CLIENT_OPS_NUM 2 + +/* Structure: udi_gfx_bind_cb_t*/ +/* Contains the operations of a driver binding request*/ +typedef struct { + /* Variable: gcb*/ + /* The main control block*/ + udi_cb_t gcb; +} udi_gfx_bind_cb_t; +#define UDI_GFX_BIND_CB_NUM 1 + +/* Function: udi_block_bind_req*/ +/* function pointer prototype for connecting to a block device*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_block_bind_cb_t>*/ +/**/ +typedef void udi_gfx_bind_req_op_t (udi_gfx_bind_cb_t *cb ); +udi_gfx_bind_req_op_t udi_gfx_bind_req; + +/* Function: udi_gfx_bind_ack*/ +/* function pointer prototype for acknowledging a connection request*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_bind_cb_t>*/ +/* sockets - The number of addressable socket components*/ +/* engines - The number of addressable engine components*/ +/* status - The result of the bind operation*/ +/**/ +typedef void udi_gfx_bind_ack_op_t (udi_gfx_bind_cb_t *cb, udi_index_t sockets, udi_index_t engines, udi_status_t status ); +udi_gfx_bind_ack_op_t udi_gfx_bind_ack; + +/* Function: udi_gfx_unbind_req*/ +/* function pointer prototype for disconnecting a block device*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_block_bind_cb_t>*/ +/**/ +typedef void udi_gfx_unbind_req_op_t (udi_gfx_bind_cb_t *cb ); +udi_gfx_unbind_req_op_t udi_gfx_unbind_req; + +/* Function: udi_gfx_unbind_ack*/ +/* function pointer prototype for connecting to a block device*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_bind_cb_t>*/ +/**/ +typedef void udi_gfx_unbind_ack_op_t (udi_gfx_bind_cb_t *cb ); +udi_gfx_unbind_ack_op_t udi_gfx_unbind_ack; + +/* Structure: udi_gfx_state_cb_t*/ +/* Contains the operations of a read/write transaction*/ +typedef struct { + /* Variable: gcb*/ + /* The main control block*/ + udi_cb_t gcb; + udi_ubit32_t subsystem; + udi_ubit32_t attribute; +} udi_gfx_state_cb_t; +#define UDI_GFX_STATE_CB_NUM 2 + +/* Function: udi_gfx_set_engine_req*/ +/* function pointer prototype for setting an engine state*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_state_cb_t>*/ +/**/ +typedef void udi_gfx_set_engine_req_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value); +udi_gfx_set_engine_req_op_t udi_gfx_set_engine_req; + +/* Function: udi_gfx_set_connector_req*/ +/* function pointer prototype for setting an connector state*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_state_cb_t>*/ +/**/ +typedef void udi_gfx_set_connector_req_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value); +udi_gfx_set_connector_req_op_t udi_gfx_set_connector_req; + +/* Function: udi_gfx_set_engine_ack*/ +/* function pointer prototype for setting an engine state*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_state_cb_t>*/ +/**/ +typedef void udi_gfx_set_engine_ack_op_t (udi_gfx_state_cb_t *cb ); +udi_gfx_set_engine_ack_op_t udi_gfx_set_engine_ack; + +/* Function: udi_gfx_set_connector_ack*/ +/* function pointer prototype for setting an engine state*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_state_cb_t>*/ +/**/ +typedef void udi_gfx_set_connector_ack_op_t (udi_gfx_state_cb_t *cb ); +udi_gfx_set_connector_ack_op_t udi_gfx_set_connector_ack; + +/* Function: udi_gfx_get_engine_req*/ +/* function pointer prototype for setting an engine state*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_state_cb_t>*/ +/**/ +typedef void udi_gfx_get_engine_req_op_t (udi_gfx_state_cb_t *cb ); +udi_gfx_get_engine_req_op_t udi_gfx_get_engine_req; + +/* Function: udi_gfx_get_connector_req*/ +/* function pointer prototype for setting an connector state*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_state_cb_t>*/ +/**/ +typedef void udi_gfx_get_connector_req_op_t (udi_gfx_state_cb_t *cb ); +udi_gfx_get_connector_req_op_t udi_gfx_get_connector_req; + +/* Function: udi_gfx_get_engine_ack*/ +/* function pointer prototype for setting an engine state*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_state_cb_t>*/ +/**/ +typedef void udi_gfx_get_engine_ack_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value); +udi_gfx_get_engine_ack_op_t udi_gfx_get_engine_ack; + +/* Function: udi_gfx_get_connector_ack*/ +/* function pointer prototype for setting an engine state*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_state_cb_t>*/ +/**/ +typedef void udi_gfx_get_connector_ack_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value); +udi_gfx_get_connector_ack_op_t udi_gfx_get_connector_ack; + +/* Function: udi_gfx_set_engine_nak*/ +/* function pointer prototype for setting an engine state*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_state_cb_t>*/ +/* status - An UDI status value indicative of the error*/ +/**/ +typedef void udi_gfx_set_engine_nak_op_t (udi_gfx_state_cb_t *cb, udi_status_t status); +udi_gfx_set_engine_nak_op_t udi_gfx_set_engine_nak; + +/* Function: udi_gfx_set_connector_nak*/ +/* function pointer prototype for setting an engine state*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_state_cb_t>*/ +/* status - An UDI status value indicative of the error*/ +/**/ +typedef void udi_gfx_set_connector_nak_op_t (udi_gfx_state_cb_t *cb, udi_status_t status); +udi_gfx_set_connector_nak_op_t udi_gfx_get_connector_nak; + +/* Structure: udi_gfx_range_cb_t*/ +/* Contains the operations of a range request transaction*/ +typedef struct { + /* Variable: gcb*/ + /* The main control block*/ + udi_cb_t gcb; + udi_ubit32_t subsystem; + udi_ubit32_t attribute; + udi_buf_t * rangedata; +} udi_gfx_range_cb_t; +#define UDI_GFX_RANGE_CB_NUM 3 + +/* Function: udi_gfx_range_engine_req*/ +/* function pointer prototype for getting an engine property range*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_range_cb_t>*/ +/**/ +typedef void udi_gfx_range_engine_req_op_t (udi_gfx_range_cb_t *cb ); +udi_gfx_range_engine_req_op_t udi_gfx_range_engine_req; + +/* Function: udi_gfx_range_connector_req*/ +/* function pointer prototype for getting a connector property range*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_range_cb_t>*/ +/**/ +typedef void udi_gfx_range_connector_req_op_t (udi_gfx_range_cb_t *cb ); +udi_gfx_range_connector_req_op_t udi_gfx_range_connector_req; + +/* Function: udi_gfx_range_engine_ack*/ +/* function pointer prototype for replying an engine property range*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_range_cb_t>*/ +/**/ +typedef void udi_gfx_range_engine_ack_op_t (udi_gfx_range_cb_t *cb ); +udi_gfx_range_engine_ack_op_t udi_gfx_range_engine_ack; + +/* Function: udi_gfx_range_connector_ack*/ +/* function pointer prototype for replying a connector property range*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_range_cb_t>*/ +/**/ +typedef void udi_gfx_range_connector_ack_op_t (udi_gfx_range_cb_t *cb ); +udi_gfx_range_connector_ack_op_t udi_gfx_range_connector_ack; + +/* Function: udi_gfx_get_engine_operator_req*/ +/* function pointer prototype for requesting the engine operator layout*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_state_cb_t>*/ +/**/ +typedef void udi_gfx_get_engine_operator_req_op_t (udi_gfx_range_cb_t *cb ); +udi_gfx_get_engine_operator_req_op_t udi_gfx_get_engine_operator_req; + +/* Function: udi_gfx_get_engine_operator_ack*/ +/* function pointer prototype for replying the engine operator layout*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_state_cb_t>*/ +/* op - The operator performed at this index*/ +/* arg1 - the first argument to this operator*/ +/* arg2 - the second argument to this operator*/ +/* arg3 - the third argument to this operator*/ +/**/ +typedef void udi_gfx_get_engine_operator_ack_op_t (udi_gfx_range_cb_t *cb, udi_ubit32_t op, udi_ubit32_t arg1, udi_ubit32_t arg2, udi_ubit32_t arg3 ); +udi_gfx_get_engine_operator_ack_op_t udi_gfx_get_engine_operator_ack; + + + +/* Structure: udi_gfx_command_cb_t*/ +/* Contains the operations of a command sequence*/ +typedef struct { + /* Variable: gcb*/ + /* The main control block*/ + udi_cb_t gcb; + udi_buf_t * commanddata; +} udi_gfx_command_cb_t; +#define UDI_GFX_COMMAND_CB_NUM 4 + +/* Function: udi_gfx_connector_command_req*/ +/* function pointer prototype for sending command data to the output connector*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_command_cb_t>*/ +/**/ +typedef void udi_gfx_connector_command_req_op_t (udi_gfx_command_cb_t *cb ); +udi_gfx_connector_command_req_op_t udi_gfx_connector_command_req; + +/* Function: udi_gfx_engine_command_req*/ +/* function pointer prototype for sending command data to the engine*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_command_cb_t>*/ +/**/ +typedef void udi_gfx_engine_command_req_op_t (udi_gfx_command_cb_t *cb ); +udi_gfx_engine_command_req_op_t udi_gfx_engine_command_req; + +/* Function: udi_gfx_connector_command_ack*/ +/* function pointer prototype for sending command data replies*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_command_cb_t>*/ +/**/ +typedef void udi_gfx_connector_command_ack_op_t (udi_gfx_command_cb_t *cb); +udi_gfx_connector_command_ack_op_t udi_gfx_connector_command_ack; + +/* Function: udi_gfx_engine_command_ack*/ +/* function pointer prototype for sending engine data replies*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_command_cb_t>*/ +/**/ +typedef void udi_gfx_engine_command_ack_op_t (udi_gfx_command_cb_t *cb); +udi_gfx_engine_command_ack_op_t udi_gfx_engine_command_ack; + +/* Structure: udi_gfx_buffer_cb_t*/ +/* Contains a description of a buffer, or area thereof*/ +typedef struct { + /* Variable: gcb*/ + /* The main control block*/ + udi_cb_t gcb; + udi_ubit32_t buffer_index; +} udi_gfx_buffer_info_cb_t; + +/* Function: udi_gfx_buffer_info_req*/ +/* function pointer prototype for getting buffer configuration information*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_command_cb_t>*/ +/**/ +typedef void udi_gfx_buffer_info_req_op_t (udi_gfx_buffer_info_cb_t *cb); +udi_gfx_buffer_info_req_op_t udi_gfx_buffer_info_req; + +/* Function: udi_gfx_buffer_info_ack*/ +/* function pointer prototype for getting buffer configuration information*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_command_cb_t>*/ +/* width - The width of the buffer*/ +/* height - The height of the buffer*/ +/* bitsper - The number of bits read from the buffer per pixel unit*/ +/* flags - A bitfield of <UDI_GFX_BUFFER_FLAGS> indicating the exposed */ +/* capabilities of this buffer*/ +/**/ +/* Note that bitsper might not be a multiple of eight.*/ +/**/ +typedef void udi_gfx_buffer_info_ack_op_t (udi_gfx_buffer_info_cb_t *cb, udi_ubit32_t width, udi_ubit32_t height, udi_ubit32_t bitsper, udi_ubit32_t flags); +udi_gfx_buffer_info_ack_op_t udi_gfx_buffer_info_ack; + +/* Structure: udi_gfx_buffer_cb_t*/ +/* Contains a description of a buffer, or area thereof*/ +typedef struct { + /* Variable: gcb*/ + /* The main control block*/ + udi_cb_t gcb; + udi_ubit32_t buffer_index; + udi_ubit32_t x; + udi_ubit32_t y; + udi_ubit32_t width; + udi_ubit32_t height; + udi_buf_t * buffer; +} udi_gfx_buffer_cb_t; + +/* Function: udi_gfx_buffer_write_req_op_t*/ +/* function pointer prototype for writing raw hardware buffers*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_buffer_cb_t>*/ +/**/ +typedef void udi_gfx_buffer_write_req_op_t (udi_gfx_buffer_cb_t *cb); +udi_gfx_buffer_write_req_op_t udi_gfx_buffer_write_req; + +/* Function: udi_gfx_buffer_write_req_op_t*/ +/* function pointer prototype for reading raw hardware buffers*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_buffer_cb_t>*/ +/**/ +typedef void udi_gfx_buffer_read_req_op_t (udi_gfx_buffer_cb_t *cb); +udi_gfx_buffer_read_req_op_t udi_gfx_buffer_read_req; + +/* Function: udi_gfx_buffer_write_ack_op_t*/ +/* function pointer prototype for writing raw hardware buffers*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_buffer_cb_t>*/ +/**/ +typedef void udi_gfx_buffer_write_ack_op_t (udi_gfx_buffer_cb_t *cb); +udi_gfx_buffer_write_ack_op_t udi_gfx_buffer_write_ack; + +/* Function: udi_gfx_buffer_write_ack_op_t*/ +/* function pointer prototype for reading raw hardware buffers*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_buffer_cb_t>*/ +/**/ +typedef void udi_gfx_buffer_read_ack_op_t (udi_gfx_buffer_cb_t *cb); +udi_gfx_buffer_read_ack_op_t udi_gfx_buffer_read_ack; + +/* Function: udi_gfx_buffer_write_nak_op_t*/ +/* error handling for buffer writes*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_buffer_cb_t>*/ +/**/ +typedef void udi_gfx_buffer_write_nak_op_t (udi_gfx_buffer_cb_t *cb, udi_status_t status); +udi_gfx_buffer_write_nak_op_t udi_gfx_buffer_write_nak; + +/* Function: udi_gfx_buffer_write_nak_op_t*/ +/* error handling for buffer reads*/ +/* */ +/* in:*/ +/* cb - A pointer to a <udi_gfx_buffer_cb_t>*/ +/**/ +typedef void udi_gfx_buffer_read_nak_op_t (udi_gfx_buffer_cb_t *cb, udi_status_t status); +udi_gfx_buffer_read_nak_op_t udi_gfx_buffer_read_nak; + +/* Structure: udi_gfx_provider_ops_t + * + * The graphics metalanguage entry points (provider side) + */ +typedef const struct { + udi_channel_event_ind_op_t *channel_event_ind_op; + udi_gfx_bind_req_op_t *gfx_bind_req_op; + udi_gfx_unbind_req_op_t *gfx_unbind_req_op; + udi_gfx_set_connector_req_op_t *gfx_set_connector_req_op; + udi_gfx_set_engine_req_op_t *gfx_set_engine_req_op; + udi_gfx_get_connector_req_op_t *gfx_get_connector_req_op; + udi_gfx_get_engine_req_op_t *gfx_get_engine_req_op; + udi_gfx_range_connector_req_op_t *gfx_range_connector_req_op; + udi_gfx_range_engine_req_op_t *gfx_range_engine_req_op; + udi_gfx_get_engine_operator_req_op_t*gfx_get_engine_operator_req_op; + udi_gfx_connector_command_req_op_t *gfx_connector_command_req_op; + udi_gfx_engine_command_req_op_t *gfx_engine_command_req_op; + udi_gfx_buffer_info_req_op_t *gfx_buffer_info_req_op; + udi_gfx_buffer_read_req_op_t *gfx_buffer_read_req_op; + udi_gfx_buffer_write_req_op_t *gfx_buffer_write_req_op; +} udi_gfx_provider_ops_t; + +/* Structure: udi_gfx_client_ops_t + * + * The graphics metalanguage entry points (client side) + */ +typedef const struct { + udi_channel_event_ind_op_t *channel_event_ind_op; + udi_gfx_bind_ack_op_t *gfx_bind_ack_op; + udi_gfx_unbind_ack_op_t *gfx_unbind_ack_op; + udi_gfx_set_connector_ack_op_t *gfx_set_connector_ack_op; + udi_gfx_set_engine_ack_op_t *gfx_set_engine_ack_op; + udi_gfx_set_connector_nak_op_t *gfx_set_connector_nak_op; + udi_gfx_set_engine_nak_op_t *gfx_set_engine_nak_op; + udi_gfx_get_connector_ack_op_t *gfx_get_connector_ack_op; + udi_gfx_get_engine_ack_op_t *gfx_get_engine_ack_op; + udi_gfx_range_connector_ack_op_t *gfx_range_connector_ack_op; + udi_gfx_range_engine_ack_op_t *gfx_range_engine_ack_op; + udi_gfx_get_engine_operator_req_op_t*gfx_get_engine_operator_ack_op; + udi_gfx_connector_command_ack_op_t *gfx_connector_command_ack_op; + udi_gfx_engine_command_ack_op_t *gfx_engine_command_ack_op; + udi_gfx_buffer_info_ack_op_t *gfx_buffer_info_ack_op; + udi_gfx_buffer_read_ack_op_t *gfx_buffer_read_ack_op; + udi_gfx_buffer_write_ack_op_t *gfx_buffer_write_ack_op; + udi_gfx_buffer_read_nak_op_t *gfx_buffer_read_nak_op; + udi_gfx_buffer_write_nak_op_t *gfx_buffer_write_nak_op; +} udi_gfx_client_ops_t; + + +/* temporary*/ +#ifndef UDI_ANNOY_ME +void EngineReturnSimpleRange (int source, int index, int prop, int first, int last, int modulus); +void ConnectorReturnSimpleRange (int source, int index, int prop, int first, int last, int modulus); +void EngineReturnConstantRange (int source, int index, int prop, int value); +void ConnectorReturnConstantRange (int source, int index, int prop, int value); +void EngineReturnBooleanRange (int source, int index, int prop, int value1, int value2); +void ConnectorReturnBooleanRange (int source, int index, int prop, int value1, int value2); +#endif + +#endif diff --git a/UDI/include/udi_gfx.h.ORIG b/UDI/include/udi_gfx.h.ORIG new file mode 100644 index 0000000000000000000000000000000000000000..fcaa5b7423896241c08210765de46ff4bcdc5e45 --- /dev/null +++ b/UDI/include/udi_gfx.h.ORIG @@ -0,0 +1,848 @@ +/** + * Summary: udi_gfx.h + * Contains the graphics metalanguage interface details + * + * Author: + * Marcel Sondaar + * + * License: + * <Public Domain> + * + * Origin: + * http://www.d-rift.nl/combuster/mos3/?p=viewsource&file=/include/common/udi_gfx.h + */ + +// note that the specification, and thus, the contents of this file is not fixed. + +#ifndef __UDI_GFX_H__ +#define __UDI_GFX_H__ + +#include <udi.h> + +#ifndef UDI_GFX_VERSION +#error "UDI_GFX_VERSION not defined." +#elif UDI_GFX_VERSION != 0x101 +#error "UDI_GFX_VERSION not supported." +#endif + +/** + * Enumeration: UDI_GFX_PROP + * Lists the various UDI properties + */ + +// General state properties +/* Constant: UDI_GFX_PROP_ENABLE + * + * Valid values: + * 0 - disabled + * 1 - enabled + * 2 - reset + * + * Ranges: + * Must include at least 1 + * + * The primary state of the connector or engine. An enabled state indicates + * it is functioning and generating live output. A disabled state is one where + * it is not contributing to any output but is otherwise functional. Finally + * the reset state is where the driver is free to deallocate all resources + * corresponding to this component and trash any state not referenced by other + * components. + * + * A disabled or reset engine forwards all data from the previous stage + * unmodified. The disabled state indicates that the component might be + * returned to its enabled state within short notice. + * + * A disabled connector will not send pixel data, but can perform other + * initialisation communication such as DDC. A reset connector will not respond + * in any fashion and can not be used for other purposes. Hardware is expected + * to be powered down in such state. + * + * Users should expect significant delays when moving components in and out of + * the reset state. Moving engines between the enabled and disabled state should + * take effect within one frame, such transition should take effect on a frame + * boundary when supported. + */ +#define UDI_GFX_PROP_ENABLE 0 + +#define UDI_GFX_PROP_ENABLE_DISABLED 0 +#define UDI_GFX_PROP_ENABLE_ENABLED 1 +#define UDI_GFX_PROP_ENABLE_RESET 2 +/* Constant: UDI_GFX_PROP_INPUT + * + * Valid values: + * Any valid engine ID, provided no dependency cycles are created, or -1 + * + * Ranges: + * Any non-empty set of valid values. Often hardwired. + * + * Points to the engine that is processed before this unit. In the case of a + * connector, it points to the last engine in a pipeline, and each engine points + * to the next engine in the sequence. A value of -1 indicates a source that + * only yields black pixels. Implementations must not allow cyclic structures. + * Changing this value may reallocate resources, and engines that are no longer + * referenced may lose their data (but not their state) when it is not part of + * any pipeline. If preservation is required, the ENABLE state should be used + * instead. Valid ranges includes one or more from the list of engines and -1 + * combined. In most cases, this property can not be modified. + */ +#define UDI_GFX_PROP_INPUT 1 +/* Constant: UDI_GFX_PROP_WIDTH + * + * Valid values: + * Any non-zero positive number. + * + * Ranges: + * Contains at least one valid value. Often only multiples of UNIT_WIDTH + * or a power of two are allowed. May be hardwired. + * + * Contains the amount of pixels in the horizontal direction. For connectors, + * this is the amount of data pixels rendered horizontally. For engines, this + * is the width in pixels of the image. Pixels requested from an engine outside + * the range (0..width-1) are defined according to the <UDI_GFX_PROP_CLIP> + * property. In some cases, hardware may support only fixed combinations of + * width and height. In such cases, changing the width will also change the + * height to a corresponding valid number. Valid ranges include any values + * strictly above zero. For connectors, expect large continuous ranges, large + * ranges with a certain modulus, a limited number of fixed values, or a + * constant value. + */ +#define UDI_GFX_PROP_WIDTH 2 +/* Constant: UDI_GFX_PROP_HEIGHT + * + * Valid values: + * Any non-zero positive number. + * + * Ranges: + * Contains at least one valid value. Often only multiples of UNIT_HEIGHT + * or a power of two are allowed. May be hardwired. + * + * Contains the amount of pixels in the vertical direction. Functions similar + * to the width property, but changing it will not alter the width property, + * and it's range at any time contains the valid range for the currently + * selected width. + */ +#define UDI_GFX_PROP_HEIGHT 3 + +/* Constant: UDI_GFX_PROP_CUSTOM + * The first property index of the driver's custom range. These are not assigned + * directly assigned by the UDI specification, but may be specified in the + * operator tree. + */ +#define UDI_GFX_PROP_CUSTOM 1024 + +// engine properties + +/* Constant: UDI_GFX_PROP_CLIP + * + * Valid values: + * 0 - points outside width x height are passed unmodified from input + * 1 - the engine's contents is tiled with size width x height + * 2 - points outside the width overflow into the y coordinate + * 3 - points outside the height overflow into the x coordinate + * + * Ranges: + * Hardwired zero for connectors. Any non-empty subset for engines, usually + * hardwired. + * + * For engines, contains the behaviour for pixels requested outside the width + * and height of the engine. Can be either 0 (pass from next stage), 1 (the + * coordinates are wrapped modulus the height and width), 2 (the coordinates + * overflow onto the next scanline horizontally, and wrap vertically), 3 (the + * coordinates overflow onto the next column vertically, and wrap horizontally). + * Valid ranges contain one or more of these options. For overlays and sprites, + * a value 0 is common. For framebuffers, 2 is the most common value. For + * connectors, this property is always 0 since they do not store pixel data + */ +#define UDI_GFX_PROP_CLIP 4 + +/* Constant: UDI_GFX_PROP_UNIT_WIDTH + * + * Valid values: + * Any non-zero positive value + * + * Ranges: + * Any non-empty set of valid values. May be hardwired to 1 for + * framebuffers, or a range of small values for hardware scaling, or any + * larger hardwired number or set for tiling engines. + * + * Tiles are used to indicate that the hardware groups sets of pixels and have + * each group share certain properties, i.e. color or tile index, or share the + * same chroma subsample with only a different intensity. If the engine has no + * such grouping, or shares all properties over the entire contents, the value + * of this property should be 1. Some tile examples include rescaling, where a + * tile width of 2 indicates a pixel doubling in X direction, or in text mode + * where a tile width of 8 or 9 corresponds with the width of common bitmap + * fonts + */ +#define UDI_GFX_PROP_UNIT_WIDTH 5 + +/* Constant: UDI_GFX_PROP_UNIT_HEIGHT + * + * Valid values: + * Any non-zero positive value + * + * Ranges: + * Any non-empty set of valid values. May be hardwired to 1 for + * framebuffers, or a range of small values for hardware scaling, or any + * larger hardwired number or set for tiling engines. + * + * See <UDI_GFX_PROP_UNIT_WIDTH>, but for the Y direction. Common values are + * 1-2 for framebuffers (doublescanning on or off), identical to the tile + * width, or mostly independent. + */ +#define UDI_GFX_PROP_UNIT_HEIGHT 6 + +/* Constant: UDI_GFX_PROP_TRANSLATEX + * + * Valid values: + * Any, signed value. + * + * Ranges: + * Any non-empty set. Typical values are hardwired zero, continuous + * between -WIDTH and WIDTH, -WIDTH to zero inclusive, or all possible values + * + * The horizontal offset where drawing starts. A positive value means the top-left + * corner moves towards the right end of the screen, a negative value moves the + * origin off the screen on the left side. Clipped areas moved off the screen do + * not reappear on the opposite side. + * + * With clipping enabled, this field combined with <UDI_GFX_PROP_WIDTH> + * determines the area where the image should be drawn, which is the horizontal + * range from UDI_GFX_PROP_TRANSLATEX to UDI_GFX_PROP_WIDTH + + * UDI_GFX_PROP_TRANSLATEX - 1 + */ +#define UDI_GFX_PROP_TRANSLATEX 7 + +/* Constant: UDI_GFX_PROP_TRANSLATEY + * + * Valid values: + * Any signed value. + * + * Ranges: + * Any non-empty set. Typical values are hardwired zero, continuous + * between -WIDTH and WIDTH, or all possible values + * + * See <UDI_GFX_PROP_TRANSLATEX> but for the Y direction. + */ +#define UDI_GFX_PROP_TRANSLATEY 8 + +#define UDI_GFX_PROP_GL_VERSION 14 +#define UDI_GFX_PROP_GLES_VERSION 15 +#define UDI_GFX_PROP_STATE_BLOCK 16 +#define UDI_GFX_PROP_COLOR_BITS 22 +#define UDI_GFX_PROP_GL_TARGET 23 + +/* Constant: UDI_GFX_PROP_STOCK_FORMAT + * + * Value: + * Zero, or any constant from <UDI_GFX_STOCK_FORMAT> + * + * Ranges: + * Any non-empty set of valid values. + * + * This field indicates the storage format is one from a limited set of + * typical configurations. If the field is zero, the engine is not knowingly + * configured as a common framebuffer. If nonzero, the operator chain and any + * dependent settings are defined to be functionally equivalent to that of a + * typical framebuffer device. + * + * The value zero does not imply that the device does not actually follow a + * set convention. This saves drivers from writing elaborate checking code + * to determine the condition in question. + * + * Writing this field potentially modifies other property fields within the + * same engine to establish the requested configuration. Manually writing such + * properties after changing this setting may in turn revert this property to + * the zero state, even if there was no modification or the behaviour is still + * as previously advertised by this property. + */ +#define UDI_GFX_PROP_STOCK_FORMAT 27 + +/* Constant: UDI_GFX_PROP_OPERATOR_COUNT + * + * Valid values: + * Any non-zero positive number + * + * Ranges: + * Most likely constant. Can be any set of valid values. + * + * The current value is the number of entries in the operator tree that can + * be requested for this engine using <udi_gfx_get_engine_operator_req> and + * <udi_gfx_get_engine_operator_ack> + */ +#define UDI_GFX_PROP_OPERATOR_COUNT 28 + +// properties for removal: +#define UDI_GFX_PROP_STORE_COUNT 24 // not generic +#define UDI_GFX_PROP_STORE_WIDTH 9 // not generic +#define UDI_GFX_PROP_STORE_HEIGHT 10 // not generic +#define UDI_GFX_PROP_STORE_BITS 11 // not generic +#define UDI_GFX_PROP_PALETTE 1024 // optional, can be derived from the operator tree +#define UDI_GFX_PROP_BUFFER 1025 // optional, can be derived from the operator tree +#define UDI_GFX_PROP_TILESHEET 1026 // optional, can be derived from the operator tree +#define UDI_GFX_PROP_OPERATOR_INDEX 17 // deprecated for dedicated methods +#define UDI_GFX_PROP_OPERATOR_OPCODE 18 // deprecated for dedicated methods +#define UDI_GFX_PROP_OPERATOR_ARG_1 19 // deprecated for dedicated methods +#define UDI_GFX_PROP_OPERATOR_ARG_2 20 // deprecated for dedicated methods +#define UDI_GFX_PROP_OPERATOR_ARG_3 21 // deprecated for dedicated methods +#define UDI_GFX_PROP_SOURCE_WIDTH 12 // should have been documented when I still knew what it did. +#define UDI_GFX_PROP_SOURCE_HEIGHT 13 // should have been documented when I still knew what it did. +#define UDI_GFX_PROP_INPUTX 25 // should have been documented when I still knew what it did. +#define UDI_GFX_PROP_INPUTY 26 // should have been documented when I still knew what it did. + +// connector properties +#define UDI_GFX_PROP_SIGNAL 23 +#define UDI_GFX_PROP_CONNECTOR_TYPE 24 +#define UDI_GFX_PROP_VGA_H_FRONT_PORCH 25 +#define UDI_GFX_PROP_VGA_H_BACK_PORCH 26 +#define UDI_GFX_PROP_VGA_H_SYNC 27 +#define UDI_GFX_PROP_VGA_V_FRONT_PORCH 28 +#define UDI_GFX_PROP_VGA_V_BACK_PORCH 29 +#define UDI_GFX_PROP_VGA_V_SYNC 30 +#define UDI_GFX_PROP_DOT_CLOCK 31 +#define UDI_GFX_PROP_VGA_H_SYNC_POL 32 +#define UDI_GFX_PROP_VGA_V_SYNC_POL 33 + +/** + * Enumeration: UDI_GFX_SIGNAL + * Lists the various signal types + */ +#define UDI_GFX_SIGNAL_HIDDEN 0 +#define UDI_GFX_SIGNAL_INTEGRATED 0 +#define UDI_GFX_SIGNAL_RGBHV 1 +#define UDI_GFX_SIGNAL_RGBS 2 +#define UDI_GFX_SIGNAL_RGSB 3 +#define UDI_GFX_SIGNAL_YPBPR 4 +#define UDI_GFX_SIGNAL_DVID 5 +#define UDI_GFX_SIGNAL_YUV 6 +#define UDI_GFX_SIGNAL_YIQ 7 +#define UDI_GFX_SIGNAL_Y_UV 8 +#define UDI_GFX_SIGNAL_Y_IQ 9 +#define UDI_GFX_SIGNAL_HDMI 10 +#define UDI_GFX_SIGNAL_TEXT 11 +#define UDI_GFX_SIGNAL_CUSTOM 12 + +/** + * Enumeration: UDI_GFX_CONNECTOR + * Lists the various external connectors + */ +#define UDI_GFX_CONNECTOR_HIDDEN 0 +#define UDI_GFX_CONNECTOR_VGA 1 +#define UDI_GFX_CONNECTOR_DVI 2 +#define UDI_GFX_CONNECTOR_SVIDEO 3 +#define UDI_GFX_CONNECTOR_COMPONENT 4 +#define UDI_GFX_CONNECTOR_HDMI 5 +#define UDI_GFX_CONNECTOR_RF 6 +#define UDI_GFX_CONNECTOR_SCART 7 +#define UDI_GFX_CONNECTOR_COMPOSITE 8 +#define UDI_GFX_CONNECTOR_MEMBUFFER 9 + +/** + * Enumeration: UDI_GFX_OPERATOR + * Lists the display output operator + */ +#define UDI_GFX_OPERATOR_RGB 0 // output = (color) red(a1) + green(a2) + blue(a3) (each component is UDI_GFX_PROP_COLOR_BITS +#define UDI_GFX_OPERATOR_YUV 1 // output = (color) Y(a1) + U(a2) + V(a3) +#define UDI_GFX_OPERATOR_YIQ 2 // output = (color) Y(a1) + I(a2) + Q(a3) +#define UDI_GFX_OPERATOR_I 3 // output = (color) intensity(a1) +#define UDI_GFX_OPERATOR_ALPHA 4 // output = (color) a1 + alpha(a2) +#define UDI_GFX_OPERATOR_ADD 5 // output = a1 + a2 + v3 +#define UDI_GFX_OPERATOR_SUB 6 // output = a1 - a2 - v3 +#define UDI_GFX_OPERATOR_MUL 7 // output = a1 * a2 +#define UDI_GFX_OPERATOR_DIV 8 // output = a1 / a2 +#define UDI_GFX_OPERATOR_MAD 9 // output = a1 * a2 + a3 +#define UDI_GFX_OPERATOR_FRC 10 // output = (a1 * a2) / a3 +#define UDI_GFX_OPERATOR_SHR 11 // output = a1 >> (a2 + v3) +#define UDI_GFX_OPERATOR_SHL 12 // output = a1 << (a2 + v3) +#define UDI_GFX_OPERATOR_ROR 13 // output = a1 >> a2 (over a3 bits) +#define UDI_GFX_OPERATOR_ROL 14 // output = a1 << a2 (over a3 bits) +#define UDI_GFX_OPERATOR_SAR 15 // output = a1 >> a2 (width is a3 bits, i.e. empties are filled with bit a3-1) +#define UDI_GFX_OPERATOR_SAL 16 // output = a1 <<< (a2 + v3) (empties filled with bit 0) +#define UDI_GFX_OPERATOR_AND 17 // output = a1 & a2 +#define UDI_GFX_OPERATOR_OR 18 // output = a1 | a2 | v3 +#define UDI_GFX_OPERATOR_NOT 19 // output = ~a1 +#define UDI_GFX_OPERATOR_XOR 20 // output = a1 ^ a2 ^ v3 +#define UDI_GFX_OPERATOR_NEG 21 // output = -a1 +#define UDI_GFX_OPERATOR_SEG 22 // output = (a1 >> v2) & (2**v3-1) (select v3 bits starting from bit v2) +#define UDI_GFX_OPERATOR_RANGE 23 // output = (a1 > a2) ? a2 : ((a1 < a3) ? a3 : a1) +#define UDI_GFX_OPERATOR_CONST 24 // output = v1 +#define UDI_GFX_OPERATOR_ATTR 25 // output = property[a1 + v2] +#define UDI_GFX_OPERATOR_SWITCH 26 // output = output[(a1 % v3) + v2] +#define UDI_GFX_OPERATOR_BUFFER 27 // output = buffer[a1][a2] (buffer is v3 bits per entry) +#define UDI_GFX_OPERATOR_X 28 // output = output x pixel +#define UDI_GFX_OPERATOR_Y 29 // output = output y pixel +#define UDI_GFX_OPERATOR_TX 30 // output = horizontal tile index belonging to output pixel +#define UDI_GFX_OPERATOR_TY 31 // output = vertical tile index belonging to output pixel +#define UDI_GFX_OPERATOR_TXOFF 32 // output = horizontal offset from start of tile +#define UDI_GFX_OPERATOR_TYOFF 33 // output = vertical offset from start of tile +#define UDI_GFX_OPERATOR_INPUT 34 // output = input engine[x][y] component v1 +#define UDI_GFX_OPERATOR_DINPUT 35 // output = input engine[a1][a2] component v3 + +/* Enumeration: UDI_GFX_STOCK_FORMAT + * Lists stock configurations + * + * When a stock configuration is used, the device is set to behave as a + * simple framebuffer device. The <UDI_GFX_PROP_WIDTH> and <UDI_GFX_PROP_HEIGHT> + * determine the virtual size of the framebuffer, and <UDI_GFX_PROP_TRANSLATEX> + * and <UDI_GFX_PROP_TRANSLATEY> indicate the offset into that framebuffer + * that is visible (which are typically restricted to negative values) + */ +#define UDI_GFX_STOCK_FORMAT_UNKNOWN 0 +#define UDI_GFX_STOCK_FORMAT_R8G8B8X8 1 +#define UDI_GFX_STOCK_FORMAT_B8G8R8X8 2 +#define UDI_GFX_STOCK_FORMAT_R8G8B8 3 +#define UDI_GFX_STOCK_FORMAT_B8G8R8 4 +#define UDI_GFX_STOCK_FORMAT_R5G6B5 5 +#define UDI_GFX_STOCK_FORMAT_B5G6R5 6 +#define UDI_GFX_STOCK_FORMAT_R5G5B5X1 7 +#define UDI_GFX_STOCK_FORMAT_B5G5R5X1 8 +#define UDI_GFX_STOCK_FORMAT_N8 9 + +// Enumeration: UDI_GFX_BUFFER_INFO_FLAG +// Lists behavioural patterns for direct buffer accesses. +// +#define UDI_GFX_BUFFER_INFO_FLAG_R 0x0001 // buffer can be read +#define UDI_GFX_BUFFER_INFO_FLAG_W 0x0002 // buffer can be written +#define UDI_GFX_BUFFER_INFO_FLAG_BITALIGN_ENTRY 0x0004 // for non-multiple-of-eight buffer slot sizes, align on byte boundary every unit +#define UDI_GFX_BUFFER_INFO_FLAG_BITALIGN_ROW 0x0008 // for non-multiple-of-eight buffer slot sizes, align only the start of the row + + +// Constant: UDI_GFX_PROVIDER_OPS_NUM +// the ops number used for the graphics driver +#define UDI_GFX_PROVIDER_OPS_NUM 1 + +// Constant: UDI_GFX_CLIENT_OPS_NUM +// the ops number used for the graphics application +#define UDI_GFX_CLIENT_OPS_NUM 2 + +// Structure: udi_gfx_bind_cb_t +// Contains the operations of a driver binding request +typedef struct { + // Variable: gcb + // The main control block + udi_cb_t gcb; +} udi_gfx_bind_cb_t; +#define UDI_GFX_BIND_CB_NUM 1 + +// Function: udi_block_bind_req +// function pointer prototype for connecting to a block device +// +// in: +// cb - A pointer to a <udi_block_bind_cb_t> +// +typedef void udi_gfx_bind_req_op_t (udi_gfx_bind_cb_t *cb ); +udi_gfx_bind_req_op_t udi_gfx_bind_req; + +// Function: udi_gfx_bind_ack +// function pointer prototype for acknowledging a connection request +// +// in: +// cb - A pointer to a <udi_gfx_bind_cb_t> +// sockets - The number of addressable socket components +// engines - The number of addressable engine components +// status - The result of the bind operation +// +typedef void udi_gfx_bind_ack_op_t (udi_gfx_bind_cb_t *cb, udi_index_t sockets, udi_index_t engines, udi_status_t status ); +udi_gfx_bind_ack_op_t udi_gfx_bind_ack; + +// Function: udi_gfx_unbind_req +// function pointer prototype for disconnecting a block device +// +// in: +// cb - A pointer to a <udi_block_bind_cb_t> +// +typedef void udi_gfx_unbind_req_op_t (udi_gfx_bind_cb_t *cb ); +udi_gfx_unbind_req_op_t udi_gfx_unbind_req; + +// Function: udi_gfx_unbind_ack +// function pointer prototype for connecting to a block device +// +// in: +// cb - A pointer to a <udi_gfx_bind_cb_t> +// +typedef void udi_gfx_unbind_ack_op_t (udi_gfx_bind_cb_t *cb ); +udi_gfx_unbind_ack_op_t udi_gfx_unbind_ack; + +// Structure: udi_gfx_state_cb_t +// Contains the operations of a read/write transaction +typedef struct { + // Variable: gcb + // The main control block + udi_cb_t gcb; + udi_ubit32_t subsystem; + udi_ubit32_t attribute; +} udi_gfx_state_cb_t; +#define UDI_GFX_STATE_CB_NUM 2 + +// Function: udi_gfx_set_engine_req +// function pointer prototype for setting an engine state +// +// in: +// cb - A pointer to a <udi_gfx_state_cb_t> +// +typedef void udi_gfx_set_engine_req_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value); +udi_gfx_set_engine_req_op_t udi_gfx_set_engine_req; + +// Function: udi_gfx_set_connector_req +// function pointer prototype for setting an connector state +// +// in: +// cb - A pointer to a <udi_gfx_state_cb_t> +// +typedef void udi_gfx_set_connector_req_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value); +udi_gfx_set_connector_req_op_t udi_gfx_set_connector_req; + +// Function: udi_gfx_set_engine_ack +// function pointer prototype for setting an engine state +// +// in: +// cb - A pointer to a <udi_gfx_state_cb_t> +// +typedef void udi_gfx_set_engine_ack_op_t (udi_gfx_state_cb_t *cb ); +udi_gfx_set_engine_ack_op_t udi_gfx_set_engine_ack; + +// Function: udi_gfx_set_connector_ack +// function pointer prototype for setting an engine state +// +// in: +// cb - A pointer to a <udi_gfx_state_cb_t> +// +typedef void udi_gfx_set_connector_ack_op_t (udi_gfx_state_cb_t *cb ); +udi_gfx_set_connector_ack_op_t udi_gfx_set_connector_ack; + +// Function: udi_gfx_get_engine_req +// function pointer prototype for setting an engine state +// +// in: +// cb - A pointer to a <udi_gfx_state_cb_t> +// +typedef void udi_gfx_get_engine_req_op_t (udi_gfx_state_cb_t *cb ); +udi_gfx_get_engine_req_op_t udi_gfx_get_engine_req; + +// Function: udi_gfx_get_connector_req +// function pointer prototype for setting an connector state +// +// in: +// cb - A pointer to a <udi_gfx_state_cb_t> +// +typedef void udi_gfx_get_connector_req_op_t (udi_gfx_state_cb_t *cb ); +udi_gfx_get_connector_req_op_t udi_gfx_get_connector_req; + +// Function: udi_gfx_get_engine_ack +// function pointer prototype for setting an engine state +// +// in: +// cb - A pointer to a <udi_gfx_state_cb_t> +// +typedef void udi_gfx_get_engine_ack_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value); +udi_gfx_get_engine_ack_op_t udi_gfx_get_engine_ack; + +// Function: udi_gfx_get_connector_ack +// function pointer prototype for setting an engine state +// +// in: +// cb - A pointer to a <udi_gfx_state_cb_t> +// +typedef void udi_gfx_get_connector_ack_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value); +udi_gfx_get_connector_ack_op_t udi_gfx_get_connector_ack; + +// Function: udi_gfx_set_engine_nak +// function pointer prototype for setting an engine state +// +// in: +// cb - A pointer to a <udi_gfx_state_cb_t> +// status - An UDI status value indicative of the error +// +typedef void udi_gfx_set_engine_nak_op_t (udi_gfx_state_cb_t *cb, udi_status_t status); +udi_gfx_set_engine_nak_op_t udi_gfx_set_engine_nak; + +// Function: udi_gfx_set_connector_nak +// function pointer prototype for setting an engine state +// +// in: +// cb - A pointer to a <udi_gfx_state_cb_t> +// status - An UDI status value indicative of the error +// +typedef void udi_gfx_set_connector_nak_op_t (udi_gfx_state_cb_t *cb, udi_status_t status); +udi_gfx_set_connector_nak_op_t udi_gfx_get_connector_nak; + +// Structure: udi_gfx_range_cb_t +// Contains the operations of a range request transaction +typedef struct { + // Variable: gcb + // The main control block + udi_cb_t gcb; + udi_ubit32_t subsystem; + udi_ubit32_t attribute; + udi_buf_t * rangedata; +} udi_gfx_range_cb_t; +#define UDI_GFX_RANGE_CB_NUM 3 + +// Function: udi_gfx_range_engine_req +// function pointer prototype for getting an engine property range +// +// in: +// cb - A pointer to a <udi_gfx_range_cb_t> +// +typedef void udi_gfx_range_engine_req_op_t (udi_gfx_range_cb_t *cb ); +udi_gfx_range_engine_req_op_t udi_gfx_range_engine_req; + +// Function: udi_gfx_range_connector_req +// function pointer prototype for getting a connector property range +// +// in: +// cb - A pointer to a <udi_gfx_range_cb_t> +// +typedef void udi_gfx_range_connector_req_op_t (udi_gfx_range_cb_t *cb ); +udi_gfx_range_connector_req_op_t udi_gfx_range_connector_req; + +// Function: udi_gfx_range_engine_ack +// function pointer prototype for replying an engine property range +// +// in: +// cb - A pointer to a <udi_gfx_range_cb_t> +// +typedef void udi_gfx_range_engine_ack_op_t (udi_gfx_range_cb_t *cb ); +udi_gfx_range_engine_ack_op_t udi_gfx_range_engine_ack; + +// Function: udi_gfx_range_connector_ack +// function pointer prototype for replying a connector property range +// +// in: +// cb - A pointer to a <udi_gfx_range_cb_t> +// +typedef void udi_gfx_range_connector_ack_op_t (udi_gfx_range_cb_t *cb ); +udi_gfx_range_connector_ack_op_t udi_gfx_range_connector_ack; + +// Function: udi_gfx_get_engine_operator_req +// function pointer prototype for requesting the engine operator layout +// +// in: +// cb - A pointer to a <udi_gfx_state_cb_t> +// +typedef void udi_gfx_get_engine_operator_req_op_t (udi_gfx_range_cb_t *cb ); +udi_gfx_get_engine_operator_req_op_t udi_gfx_get_engine_operator_req; + +// Function: udi_gfx_get_engine_operator_ack +// function pointer prototype for replying the engine operator layout +// +// in: +// cb - A pointer to a <udi_gfx_state_cb_t> +// op - The operator performed at this index +// arg1 - the first argument to this operator +// arg2 - the second argument to this operator +// arg3 - the third argument to this operator +// +typedef void udi_gfx_get_engine_operator_ack_op_t (udi_gfx_range_cb_t *cb, udi_ubit32_t op, udi_ubit32_t arg1, udi_ubit32_t arg2, udi_ubit32_t arg3 ); +udi_gfx_get_engine_operator_ack_op_t udi_gfx_get_engine_operator_ack; + + + +// Structure: udi_gfx_command_cb_t +// Contains the operations of a command sequence +typedef struct { + // Variable: gcb + // The main control block + udi_cb_t gcb; + udi_buf_t * commanddata; +} udi_gfx_command_cb_t; +#define UDI_GFX_COMMAND_CB_NUM 4 + +// Function: udi_gfx_connector_command_req +// function pointer prototype for sending command data to the output connector +// +// in: +// cb - A pointer to a <udi_gfx_command_cb_t> +// +typedef void udi_gfx_connector_command_req_op_t (udi_gfx_command_cb_t *cb ); +udi_gfx_connector_command_req_op_t udi_gfx_connector_command_req; + +// Function: udi_gfx_engine_command_req +// function pointer prototype for sending command data to the engine +// +// in: +// cb - A pointer to a <udi_gfx_command_cb_t> +// +typedef void udi_gfx_engine_command_req_op_t (udi_gfx_command_cb_t *cb ); +udi_gfx_engine_command_req_op_t udi_gfx_engine_command_req; + +// Function: udi_gfx_connector_command_ack +// function pointer prototype for sending command data replies +// +// in: +// cb - A pointer to a <udi_gfx_command_cb_t> +// +typedef void udi_gfx_connector_command_ack_op_t (udi_gfx_command_cb_t *cb); +udi_gfx_connector_command_ack_op_t udi_gfx_connector_command_ack; + +// Function: udi_gfx_engine_command_ack +// function pointer prototype for sending engine data replies +// +// in: +// cb - A pointer to a <udi_gfx_command_cb_t> +// +typedef void udi_gfx_engine_command_ack_op_t (udi_gfx_command_cb_t *cb); +udi_gfx_engine_command_ack_op_t udi_gfx_engine_command_ack; + +// Structure: udi_gfx_buffer_cb_t +// Contains a description of a buffer, or area thereof +typedef struct { + // Variable: gcb + // The main control block + udi_cb_t gcb; + udi_ubit32_t buffer_index; +} udi_gfx_buffer_info_cb_t; + +// Function: udi_gfx_buffer_info_req +// function pointer prototype for getting buffer configuration information +// +// in: +// cb - A pointer to a <udi_gfx_command_cb_t> +// +typedef void udi_gfx_buffer_info_req_op_t (udi_gfx_buffer_info_cb_t *cb); +udi_gfx_buffer_info_req_op_t udi_gfx_buffer_info_req; + +// Function: udi_gfx_buffer_info_ack +// function pointer prototype for getting buffer configuration information +// +// in: +// cb - A pointer to a <udi_gfx_command_cb_t> +// width - The width of the buffer +// height - The height of the buffer +// bitsper - The number of bits read from the buffer per pixel unit +// flags - A bitfield of <UDI_GFX_BUFFER_FLAGS> indicating the exposed +// capabilities of this buffer +// +// Note that bitsper might not be a multiple of eight. +// +typedef void udi_gfx_buffer_info_ack_op_t (udi_gfx_buffer_info_cb_t *cb, udi_ubit32_t width, udi_ubit32_t height, udi_ubit32_t bitsper, udi_ubit32_t flags); +udi_gfx_buffer_info_ack_op_t udi_gfx_buffer_info_ack; + +// Structure: udi_gfx_buffer_cb_t +// Contains a description of a buffer, or area thereof +typedef struct { + // Variable: gcb + // The main control block + udi_cb_t gcb; + udi_ubit32_t buffer_index; + udi_ubit32_t x; + udi_ubit32_t y; + udi_ubit32_t width; + udi_ubit32_t height; + udi_buf_t * buffer; +} udi_gfx_buffer_cb_t; + +// Function: udi_gfx_buffer_write_req_op_t +// function pointer prototype for writing raw hardware buffers +// +// in: +// cb - A pointer to a <udi_gfx_buffer_cb_t> +// +typedef void udi_gfx_buffer_write_req_op_t (udi_gfx_buffer_cb_t *cb); +udi_gfx_buffer_write_req_op_t udi_gfx_buffer_write_req; + +// Function: udi_gfx_buffer_write_req_op_t +// function pointer prototype for reading raw hardware buffers +// +// in: +// cb - A pointer to a <udi_gfx_buffer_cb_t> +// +typedef void udi_gfx_buffer_read_req_op_t (udi_gfx_buffer_cb_t *cb); +udi_gfx_buffer_read_req_op_t udi_gfx_buffer_read_req; + +// Function: udi_gfx_buffer_write_ack_op_t +// function pointer prototype for writing raw hardware buffers +// +// in: +// cb - A pointer to a <udi_gfx_buffer_cb_t> +// +typedef void udi_gfx_buffer_write_ack_op_t (udi_gfx_buffer_cb_t *cb); +udi_gfx_buffer_write_ack_op_t udi_gfx_buffer_write_ack; + +// Function: udi_gfx_buffer_write_ack_op_t +// function pointer prototype for reading raw hardware buffers +// +// in: +// cb - A pointer to a <udi_gfx_buffer_cb_t> +// +typedef void udi_gfx_buffer_read_ack_op_t (udi_gfx_buffer_cb_t *cb); +udi_gfx_buffer_read_ack_op_t udi_gfx_buffer_read_ack; + +// Function: udi_gfx_buffer_write_nak_op_t +// error handling for buffer writes +// +// in: +// cb - A pointer to a <udi_gfx_buffer_cb_t> +// +typedef void udi_gfx_buffer_write_nak_op_t (udi_gfx_buffer_cb_t *cb, udi_status_t status); +udi_gfx_buffer_write_nak_op_t udi_gfx_buffer_write_nak; + +// Function: udi_gfx_buffer_write_nak_op_t +// error handling for buffer reads +// +// in: +// cb - A pointer to a <udi_gfx_buffer_cb_t> +// +typedef void udi_gfx_buffer_read_nak_op_t (udi_gfx_buffer_cb_t *cb, udi_status_t status); +udi_gfx_buffer_read_nak_op_t udi_gfx_buffer_read_nak; + +/* Structure: udi_gfx_provider_ops_t + * + * The graphics metalanguage entry points (provider side) + */ +typedef const struct { + udi_channel_event_ind_op_t *channel_event_ind_op; + udi_gfx_bind_req_op_t *gfx_bind_req_op; + udi_gfx_unbind_req_op_t *gfx_unbind_req_op; + udi_gfx_set_connector_req_op_t *gfx_set_connector_req_op; + udi_gfx_set_engine_req_op_t *gfx_set_engine_req_op; + udi_gfx_get_connector_req_op_t *gfx_get_connector_req_op; + udi_gfx_get_engine_req_op_t *gfx_get_engine_req_op; + udi_gfx_range_connector_req_op_t *gfx_range_connector_req_op; + udi_gfx_range_engine_req_op_t *gfx_range_engine_req_op; + udi_gfx_get_engine_operator_req_op_t*gfx_get_engine_operator_req_op; + udi_gfx_connector_command_req_op_t *gfx_connector_command_req_op; + udi_gfx_engine_command_req_op_t *gfx_engine_command_req_op; + udi_gfx_buffer_info_req_op_t *gfx_buffer_info_req_op; + udi_gfx_buffer_read_req_op_t *gfx_buffer_read_req_op; + udi_gfx_buffer_write_req_op_t *gfx_buffer_write_req_op; +} udi_gfx_provider_ops_t; + +/* Structure: udi_gfx_client_ops_t + * + * The graphics metalanguage entry points (client side) + */ +typedef const struct { + udi_channel_event_ind_op_t *channel_event_ind_op; + udi_gfx_bind_ack_op_t *gfx_bind_ack_op; + udi_gfx_unbind_ack_op_t *gfx_unbind_ack_op; + udi_gfx_set_connector_ack_op_t *gfx_set_connector_ack_op; + udi_gfx_set_engine_ack_op_t *gfx_set_engine_ack_op; + udi_gfx_set_connector_nak_op_t *gfx_set_connector_nak_op; + udi_gfx_set_engine_nak_op_t *gfx_set_engine_nak_op; + udi_gfx_get_connector_ack_op_t *gfx_get_connector_ack_op; + udi_gfx_get_engine_ack_op_t *gfx_get_engine_ack_op; + udi_gfx_range_connector_ack_op_t *gfx_range_connector_ack_op; + udi_gfx_range_engine_ack_op_t *gfx_range_engine_ack_op; + udi_gfx_get_engine_operator_req_op_t*gfx_get_engine_operator_ack_op; + udi_gfx_connector_command_ack_op_t *gfx_connector_command_ack_op; + udi_gfx_engine_command_ack_op_t *gfx_engine_command_ack_op; + udi_gfx_buffer_info_ack_op_t *gfx_buffer_info_ack_op; + udi_gfx_buffer_read_ack_op_t *gfx_buffer_read_ack_op; + udi_gfx_buffer_write_ack_op_t *gfx_buffer_write_ack_op; + udi_gfx_buffer_read_nak_op_t *gfx_buffer_read_nak_op; + udi_gfx_buffer_write_nak_op_t *gfx_buffer_write_nak_op; +} udi_gfx_client_ops_t; + + +// temporary +#ifndef UDI_ANNOY_ME +void EngineReturnSimpleRange (int source, int index, int prop, int first, int last, int modulus); +void ConnectorReturnSimpleRange (int source, int index, int prop, int first, int last, int modulus); +void EngineReturnConstantRange (int source, int index, int prop, int value); +void ConnectorReturnConstantRange (int source, int index, int prop, int value); +void EngineReturnBooleanRange (int source, int index, int prop, int value1, int value2); +void ConnectorReturnBooleanRange (int source, int index, int prop, int value1, int value2); +#endif + +#endif diff --git a/UDI/include/udi_nic.h b/UDI/include/udi_nic.h index 169a81bfa6566e653b78c1d42b5f6da339005372..7b5659a9226f0968c5e3e28011ae92ecb6e2e0a0 100644 --- a/UDI/include/udi_nic.h +++ b/UDI/include/udi_nic.h @@ -8,6 +8,10 @@ #ifndef _UDI_NIC_H_ #define _UDI_NIC_H_ +#ifndef UDI_NIC_VERSION +# error "UDI_NIC_VERSION must be defined" +#endif + // === CBs === #define UDI_NIC_STD_CB_NUM 1 #define UDI_NIC_BIND_CB_NUM 2 diff --git a/UDI/include/udi_pci.h b/UDI/include/udi_pci.h index f65c6fd5b763eb80ffb0a06672205f8ba47844a5..16e54a178328ce6939d30227759ff94dd9016d10 100644 --- a/UDI/include/udi_pci.h +++ b/UDI/include/udi_pci.h @@ -8,6 +8,9 @@ #ifndef _UDI_PCI_H_ #define _UDI_PCI_H_ +#if UDI_PCI_VERSION != 0x101 +# error "udi_pci.h requires UDI_PCI_VERSION set to 0x101" +#endif #ifndef _UDI_PHYSIO_H_ # error "udi_pci.h requires udi_physio.h" #endif diff --git a/UDI/include/udi_physio.h b/UDI/include/udi_physio.h index f7643c8e59ef76b01fea614baf05df322c27ea08..7023687b5f695ff26de7d0e66167ee91a49410cc 100644 --- a/UDI/include/udi_physio.h +++ b/UDI/include/udi_physio.h @@ -6,9 +6,9 @@ #include <udi.h> -//#ifndef UDI_PHYSIO_VERSION -//# error "UDI_PHYSIO_VERSION must be defined" -//#endif +#ifndef UDI_PHYSIO_VERSION +# error "UDI_PHYSIO_VERSION must be defined" +#endif #define UDI_DL_PIO_HANDLE_T 200 #define UDI_DL_DMA_CONSTRAINTS_T 201 @@ -128,6 +128,4 @@ struct udi_scgth_s #include <physio/meta_bus.h> #include "physio/pio.h" -#include "physio/pci.h" - #endif diff --git a/Usermode/Applications/CLIShell_src/Makefile b/Usermode/Applications/CLIShell_src/Makefile index e500edd273ba4d799fbb90b5a8dd3d4804a595e2..76d8f5736ecd9a19320d7a2a83a0599e515acd15 100644 --- a/Usermode/Applications/CLIShell_src/Makefile +++ b/Usermode/Applications/CLIShell_src/Makefile @@ -3,7 +3,8 @@ -include ../Makefile.cfg CPPFLAGS += -I./include -LDFLAGS += -lreadline +LDFLAGS += +LIBS += -lreadline BIN = CLIShell OBJ = main.o lib.o diff --git a/Usermode/Applications/Makefile.cfg b/Usermode/Applications/Makefile.cfg index ef17a140303105d0f30089e11fa8d87c7546b2b0..be17100fffd8f08f328445844ce62490fce7f4f2 100644 --- a/Usermode/Applications/Makefile.cfg +++ b/Usermode/Applications/Makefile.cfg @@ -7,25 +7,24 @@ include $(_appsdir)../Makefile.cfg ifeq ($(ARCHDIR),native) ASFLAGS = -felf - CPPFLAGS = -Wall - CFLAGS = $(CPPFLAGS) - LDFLAGS = -L $(OUTPUTDIR)Libs -lacess-native -lc_acess -#LIBGCC_PATH = $(ACESSDIR)/AcessNative/symbol_renames.ld + LDFLAGS := + LIBS := -lacess-native -lc_acess else ASFLAGS = -felf - CPPFLAGS = -ffreestanding - CFLAGS = -fno-stack-protector -fno-builtin $(CPPFLAGS) -Wall - LDFLAGS = -T $(OUTPUTDIR)Libs/acess.ld -L $(OUTPUTDIR)Libs -I /Acess/Libs/ld-acess.so -lld-acess -lc $(OUTPUTDIR)Libs/crtbegin.o $(OUTPUTDIR)Libs/crtend.o -lposix - LIBGCC_PATH = $(shell $(CC) -print-libgcc-file-name) + LDFLAGS := + LIBS = -lld-acess endif +LDFLAGS += -rpath-link $(OUTPUTDIR)Libs # Needed so that dynamic libraries are linked correctly +CXXFLAGS += -std=gnu++11 +CPPFLAGS += +CFLAGS += -Wall + -include $(_appsdir)../common_settings.mk -LDFLAGS += -rpath-link $(OUTPUTDIR)Libs # Extra-verbose errors! #CFLAGS += -Wall -Wextra -Wwrite-strings -Wshadow -Wswitch-default -Wswitch-enum -Wstrict-overflow=5 -Wfloat-equal -Wundef -Wmissing-declarations -Wlogical-op -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wswitch-enum -Wsync-nand -Wunused -Wstrict-overflow=5 -Wfloat-equal -Wundef -Wno-endif-labels -Wshadow -Wunsafe-loop-optimizations -Wbad-function-cast -Wc++-compat -Wcast-qual -Wcast-align -Wwrite-strings -Wconversion -Wlogical-op -Waggregate-return -Wstrict-prototypes -Wold-style-definition -Wmissing-declarations -Wnormalized=nfc -Wpacked -Wpadded -Wredundant-decls -Wnested-externs -Winline -Winvalid-pch -Wdisabled-optimization -Woverlength-strings -CRTBEGIN = $(shell $(CC) $(CFLAGS) -print-file-name=crtbegin.o) -CRTEND = $(shell $(CC) $(CFLAGS) -print-file-name=crtend.o) - DIR = Bin + +# vim: ft=make diff --git a/Usermode/Applications/Makefile.tpl b/Usermode/Applications/Makefile.tpl index a6c8508c4ce379df754d7e9569deb4b04ca230e8..d72ac6a24cfc32889454b33f6a9933f5c6e68321 100644 --- a/Usermode/Applications/Makefile.tpl +++ b/Usermode/Applications/Makefile.tpl @@ -3,23 +3,26 @@ # - Application Template Makefile # -CFLAGS += -g -LDFLAGS += -g - -LDFLAGS += -Map $(_OBJPREFIX)Map.txt - -ifneq ($(lastword $(subst -, ,$(basename $(LD)))),ld) - comma=, - LDFLAGS := $(subst -rpath-link ,-Wl$(comma)-rpath-link$(comma),$(LDFLAGS)) - LDFLAGS := $(subst -Map ,-Wl$(comma)-Map$(comma),$(LDFLAGS)) -endif +CFLAGS += -g +CXXFLAGS += -g +LDFLAGS += -g _BIN := $(OUTPUTDIR)$(DIR)/$(BIN) _OBJPREFIX := obj-$(ARCH)/ -_LIBS := $(filter -l%,$(LDFLAGS)) +LDFLAGS += -Map $(_OBJPREFIX)Map.txt + +comma=, +LDFLAGS := $(subst -rpath-link ,-Wl$(comma)-rpath-link$(comma),$(LDFLAGS)) +LDFLAGS := $(subst -Map ,-Wl$(comma)-Map$(comma),$(LDFLAGS)) + +_LIBS := $(filter -l%,$(LIBS)) _LIBS := $(patsubst -l%,$(OUTPUTDIR)Libs/lib%.so,$(_LIBS)) +ifeq ($(ARCHDIR),native) + LDFLAGS := $(patsubst -lc++,-lc++_acess,$(LDFLAGS)) + LIBS := $(patsubst -lc++,-lc++_acess,$(LIBS)) +endif ifeq ($(VERBOSE),) V := @ else @@ -28,6 +31,9 @@ endif OBJ := $(addprefix $(_OBJPREFIX),$(OBJ)) +#LINK_OBJS := $(CRTI) $(CRTBEGIN) $(CRT0) $(OBJ) $(LIBGCC_PATH) $(CRTEND) $(CRTN) +LINK_OBJS := $(OBJ) + DEPFILES := $(OBJ:%.o=%.dep) .PHONY : all clean install @@ -45,10 +51,14 @@ install: $(_BIN) @$(xCP) $(_BIN)_ $(DISTROOT)/$(DIR)/$(BIN) @$(RM) $(_BIN)_ -$(_BIN): $(OUTPUTDIR)Libs/acess.ld $(OUTPUTDIR)Libs/crt0.o $(_LIBS) $(OBJ) +$(_BIN): $(_LIBS) $(LINK_OBJS) $(CRT0) $(CRTI) $(CRTN) @mkdir -p $(dir $(_BIN)) @echo [LD] -o $@ - $V$(LD) -g $(LDFLAGS) -o $@ $(CRTBEGIN) $(OBJ) $(LIBGCC_PATH) $(CRTEND) +ifneq ($(USE_CXX_LINK),) + $V$(CXX) -g $(LDFLAGS) -o $(_BIN) $(LINK_OBJS) $(LIBS) +else + $V$(CC) -g $(LDFLAGS) -o $(_BIN) $(LINK_OBJS) $(LIBS) +endif $V$(DISASM) $(_BIN) > $(_OBJPREFIX)$(BIN).dsm $(_OBJPREFIX)%.o: %.c @@ -56,8 +66,7 @@ $(_OBJPREFIX)%.o: %.c ifneq ($(_OBJPREFIX),) @mkdir -p $(dir $@) endif - $V$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ - $V$(CC) -M -MP -MT $@ $(CPPFLAGS) $< -o $(_OBJPREFIX)$*.dep + $V$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ -MQ $@ -MP -MD -MF $(_OBJPREFIX)$*.dep $(_OBJPREFIX)%.o: %.cpp @echo [CXX] -o $@ diff --git a/Usermode/Applications/axwin3_src/Interface/Makefile b/Usermode/Applications/axwin3_src/Interface/Makefile index d96cc5e9bbb92ef2bb9fc93edc0899b60f3c82c0..d5303649c0055f66a0b1bee11b1d9759f88efaea 100644 --- a/Usermode/Applications/axwin3_src/Interface/Makefile +++ b/Usermode/Applications/axwin3_src/Interface/Makefile @@ -8,7 +8,7 @@ DIR := Apps/AxWin/3.0 BIN := AxWinUI OBJ := main.o -LDFLAGS += -laxwin3 +LIBS += -laxwin3 -include ../../Makefile.tpl diff --git a/Usermode/Applications/axwin3_src/WM/Makefile b/Usermode/Applications/axwin3_src/WM/Makefile index 5854a3959e1e923a5e7f1f0b85b6e481355bb56f..595044db101f2c92d21ac910542891daf6856ce4 100644 --- a/Usermode/Applications/axwin3_src/WM/Makefile +++ b/Usermode/Applications/axwin3_src/WM/Makefile @@ -8,7 +8,7 @@ BIN := AxWinWM OBJ := main.o input.o video.o ipc_acess.o include common.mk -LDFLAGS += -lnet +LIBS += -lnet -include ../../Makefile.tpl diff --git a/Usermode/Applications/axwin3_src/WM/common.mk b/Usermode/Applications/axwin3_src/WM/common.mk index e354e0cf132285c4b86ca3a69fc3f514a67d105b..81ab3279ace1b23f8da05680f22982336b8c66f6 100644 --- a/Usermode/Applications/axwin3_src/WM/common.mk +++ b/Usermode/Applications/axwin3_src/WM/common.mk @@ -18,7 +18,7 @@ OBJ += renderers/widget/textinput.o OBJ += renderers/widget/spacer.o OBJ += renderers/widget/subwin.o -LDFLAGS += -limage_sif -luri -lunicode +LIBS += -limage_sif -luri -lunicode PNGIMAGES := toolbar_new.png toolbar_save.png toolbar_open.png IMG2SIF = ../../../../Tools/img2sif diff --git a/Usermode/Applications/axwin3_src/WM/renderers/widget/common.h b/Usermode/Applications/axwin3_src/WM/renderers/widget/common.h index 2564716e48907b368f4db1911b064350146eef87..9c87bde11265a2654fa458a29e87ec1bcbf6d074 100644 --- a/Usermode/Applications/axwin3_src/WM/renderers/widget/common.h +++ b/Usermode/Applications/axwin3_src/WM/renderers/widget/common.h @@ -49,7 +49,7 @@ extern void Widget_Fire(tElement *Element); #define DEFWIDGETTYPE(_type, _name, _flags, _attribs...) \ tWidgetDef _widget_typedef_##_type = {.Name=_name,.Flags=(_flags),_attribs};\ void _widget_set_##_type(void) __attribute__((constructor));\ -void _widget_set_##_type(void) { _SysDebug("hai!\n"); Widget_int_SetTypeDef(_type, &_widget_typedef_##_type);} +void _widget_set_##_type(void) { Widget_int_SetTypeDef(_type, &_widget_typedef_##_type); } #endif diff --git a/Usermode/Applications/axwin3_src/WM/renderers/widget/textinput.c b/Usermode/Applications/axwin3_src/WM/renderers/widget/textinput.c index 8335241707778e6df3f4794bf2e5b8f104e592da..de862bfe402efd0037fa21126e472e59343cc9f3 100644 --- a/Usermode/Applications/axwin3_src/WM/renderers/widget/textinput.c +++ b/Usermode/Applications/axwin3_src/WM/renderers/widget/textinput.c @@ -118,7 +118,7 @@ void Widget_TextInput_Init(tElement *Element) info->DrawOfs = 0; info->CursorXOfs = 0; info->CursorByteOfs = 0; - info->Length = NULL; + info->Length = 0; // No need to explicitly update parent min dims, as the AddElement routine does that } diff --git a/Usermode/Applications/axwin3_src/WM/wm.c b/Usermode/Applications/axwin3_src/WM/wm.c index b304cacd966878894e6c3efcaeec2b7da34ca0cd..cc7e86ea96d20e22f924ff268ced3033e1c1dc82 100644 --- a/Usermode/Applications/axwin3_src/WM/wm.c +++ b/Usermode/Applications/axwin3_src/WM/wm.c @@ -13,6 +13,7 @@ #include <wm_messages.h> #include <decorator.h> #include <axwin3/keysyms.h> +#include <wm_hotkeys.h> // === IMPORTS === extern int Renderer_Menu_Init(void); diff --git a/Usermode/Applications/axwin4_src/Common/include/ipc_proto.hpp b/Usermode/Applications/axwin4_src/Common/include/ipc_proto.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a2e1bc97cd86b53b477364ec500dd0500e716bf3 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Common/include/ipc_proto.hpp @@ -0,0 +1,68 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * ipc_proto.hpp + * - IPC Protocol Header + */ +#ifndef _IPC_PROTO_H_ +#define _IPC_PROTO_H_ + +namespace AxWin { + +enum +{ + IPCMSG_NULL, + IPCMSG_REPLY, + IPCMSG_PING, + IPCMSG_GETGLOBAL, + IPCMSG_SETGLOBAL, + + IPCMSG_CREATEWIN, + IPCMSG_CLOSEWIN, + IPCMSG_SETWINATTR, + IPCMSG_GETWINATTR, + IPCMSG_SENDIPC, + IPCMSG_GETWINBUF, // get a handle to the window's buffer + + // - Window drawing commands + IPCMSG_DAMAGERECT, // (u16 win, u16 x, u16 y, u16 w, u16 h) - Force reblit of area + //IPCMSG_DRAWGROUP, // (u16 win, u16 group_id) - (hint) Switch to this group + //IPCMSG_CLEAR, // (u16 win) - (hint) Clear current drawing group + IPCMSG_PUSHDATA, // (u16 win, u16 x, u16 y, u16 w, u16 h, void data) + IPCMSG_BLIT, // (win, sx, sy, dx, dy, w, h) - Blit locally + IPCMSG_DRAWCTL, // (win, x, y, w, h, ctlid) - Draw + IPCMSG_DRAWTEXT, // (win, x, y, fontid, text) - Draw text using an internal font + IPCMSG_FILLRECT, // (win, x, y, w, h, colour) + IPCMSG_DRAWRECT, // (win, x, y, w, h, colour) + + // - Client-bound commands + IPCMSG_INPUTEVENT, // (u8 event, u16 win, ...) +}; + +enum eIPC_GlobalAttrs +{ + IPC_GLOBATTR_SCREENDIMS, // Screen dimensions - Readonly + IPC_GLOBATTR_MAXAREA, // Maximum window area for screen (hint only, not enforced) +}; + +enum eIPC_WinAttrs +{ + IPC_WINATTR_SHOW, // u8 - Window shown + IPC_WINATTR_FLAGS, // u32 - Decoration enabled, always-on-top + IPC_WINATTR_POSITION, // s16, s16 + IPC_WINATTR_DIMENSIONS, // u16, u16 + IPC_WINATTR_TITLE, // string +}; + +enum eIPC_InputEvents +{ + IPC_INEV_KEYBOARD, // (u16 keysym, u8 keydown, string text) + IPC_INEV_MOUSEBTN, // (u16 x, u16 y) + IPC_INEV_MOUSEMOVE, // (u16 x, u16 y, u8 btn, u8 btndown) +}; + +}; + +#endif + diff --git a/Usermode/Applications/axwin4_src/Common/include/serialisation.hpp b/Usermode/Applications/axwin4_src/Common/include/serialisation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..54293c1b29ec5e7a590d0ac633eac33547b4a37e --- /dev/null +++ b/Usermode/Applications/axwin4_src/Common/include/serialisation.hpp @@ -0,0 +1,74 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * serialisation.hpp + * - Generic (de)serialisation code + */ +#ifndef _SERIALISATION_H_ +#define _SERIALISATION_H_ + +#include <cstdint> +#include <cstddef> +#include <exception> +#include <string> +#include <vector> + +namespace AxWin { + +class CDeserialiseException: + public ::std::exception +{ +}; + +class CDeserialiser +{ + ::std::vector<uint8_t> m_vect; + size_t m_offset; +public: + CDeserialiser(): + CDeserialiser(::std::vector<uint8_t>()) + {} + CDeserialiser(const ::std::vector<uint8_t>& vect); + CDeserialiser(::std::vector<uint8_t>&& vect); + CDeserialiser(const CDeserialiser& x) { *this = x; }; + CDeserialiser& operator=(const CDeserialiser& x); + bool IsConsumed() const; + ::uint8_t ReadU8(); + ::uint16_t ReadU16(); + ::int16_t ReadS16(); + ::uint32_t ReadU32(); + ::uint64_t ReadU64(); + const ::std::vector<uint8_t> ReadBuffer(); + const ::std::string ReadString(); +private: + void RangeCheck(const char *Method, size_t bytes) throw(::std::out_of_range); +}; + +class CSerialiser +{ + ::std::vector<uint8_t> m_data; +public: + CSerialiser(); + void WriteU8(::uint8_t val); + void WriteU16(::uint16_t val); + void WriteS16(::int16_t val); + void WriteU32(::uint32_t val); + void WriteU64(::uint64_t val); + void WriteBuffer(size_t n, const void* val); + void WriteString(const char* val, size_t n); + void WriteString(const char* val) { + WriteString(val, ::std::char_traits<char>::length(val)); + } + void WriteString(const ::std::string& val) { + WriteString(val.data(), val.size()); + } + void WriteSub(const CSerialiser& val); + + const ::std::vector<uint8_t>& Compact(); +}; + +}; + +#endif + diff --git a/Usermode/Applications/axwin4_src/Common/serialisation.cpp b/Usermode/Applications/axwin4_src/Common/serialisation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..016b000456aaf99733c9d50e93355701f0a60474 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Common/serialisation.cpp @@ -0,0 +1,182 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * serialisation.cpp + * - IPC Serialisation + */ +#include <serialisation.hpp> +#include <cstddef> +#include <stdexcept> +#include <acess/sys.h> // SysDebug + +namespace AxWin { + +CDeserialiser::CDeserialiser(const ::std::vector<uint8_t>& vector): + m_vect(vector), + m_offset(0) +{ +} +CDeserialiser::CDeserialiser(::std::vector<uint8_t>&& vector): + m_vect(vector), + m_offset(0) +{ +} +CDeserialiser& CDeserialiser::operator=(const CDeserialiser& x) +{ + m_vect = x.m_vect; + m_offset = x.m_offset; +} + +bool CDeserialiser::IsConsumed() const +{ + return m_offset == m_vect.size(); +} + +::uint8_t CDeserialiser::ReadU8() +{ + RangeCheck("CDeserialiser::ReadU8", 1); + uint8_t rv = m_vect[m_offset]; + m_offset ++; + return rv; +} + +::uint16_t CDeserialiser::ReadU16() +{ + RangeCheck("CDeserialiser::ReadU16", 2); + uint16_t rv = m_vect[m_offset] | ((uint16_t)m_vect[m_offset+1] << 8); + m_offset += 2; + return rv; +} + +::int16_t CDeserialiser::ReadS16() +{ + uint16_t rv_u = ReadU16(); + if( rv_u < 0x8000 ) + return rv_u; + else + return ~rv_u + 1; +} + +::uint32_t CDeserialiser::ReadU32() +{ + uint32_t rv = ReadU16(); + rv |= (uint32_t)ReadU16() << 16; + return rv; +} + +::uint64_t CDeserialiser::ReadU64() +{ + uint64_t rv = ReadU32(); + rv |= (uint64_t)ReadU32() << 32; + return rv; +} + +const ::std::vector<uint8_t> CDeserialiser::ReadBuffer() +{ + RangeCheck("CDeserialiser::ReadBuffer(len)", 2); + size_t size = ReadU16(); + + auto range_start = m_vect.begin() + int(m_offset); + ::std::vector<uint8_t> ret( range_start, range_start + int(size) ); + m_offset += size; + return ret; +} + +const ::std::string CDeserialiser::ReadString() +{ + RangeCheck("CDeserialiser::ReadString(len)", 1); + uint8_t len = ReadU8(); + + RangeCheck("CDeserialiser::ReadString(data)", len); + ::std::string ret( reinterpret_cast<const char*>(m_vect.data()+m_offset), len ); + m_offset += len; + return ret; +} + +void CDeserialiser::RangeCheck(const char *Method, size_t bytes) throw(::std::out_of_range) +{ + if( m_offset + bytes > m_vect.size() ) { + ::_SysDebug("%s - out of range %i+%i >= %i", Method, m_offset, bytes, m_vect.size()); + throw ::std::out_of_range(Method); + } +} + +CSerialiser::CSerialiser() +{ +} + +void CSerialiser::WriteU8(::uint8_t Value) +{ + m_data.push_back(Value); +} + +void CSerialiser::WriteU16(::uint16_t Value) +{ + m_data.push_back(Value & 0xFF); + m_data.push_back(Value >> 8); +} + +void CSerialiser::WriteS16(::int16_t Value) +{ + if( Value < 0 ) + { + ::uint16_t rawval = 0x10000 - (::int32_t)Value; + WriteU16(rawval); + } + else + { + WriteU16(Value); + } +} + +void CSerialiser::WriteU32(::uint32_t Value) +{ + m_data.push_back(Value & 0xFF); + m_data.push_back(Value >> 8); + m_data.push_back(Value >> 16); + m_data.push_back(Value >> 24); +} + +void CSerialiser::WriteU64(::uint64_t Value) +{ + WriteU32(Value); + WriteU32(Value>>32); +} + +void CSerialiser::WriteBuffer(size_t n, const void* val) +{ + const uint8_t* val8 = static_cast<const uint8_t*>(val); + if( n > 0xFFFF ) + throw ::std::length_error("CSerialiser::WriteBuffer"); + m_data.reserve( m_data.size() + 2 + n ); + WriteU16(n); + for( size_t i = 0; i < n; i ++ ) + m_data.push_back(val8[i]); +} + +void CSerialiser::WriteString(const char* val, size_t n) +{ + if( n > 0xFF ) + throw ::std::length_error("CSerialiser::WriteString"); + m_data.reserve( m_data.size() + 1 + n ); + WriteU8(n); + for( size_t i = 0; i < n; i ++ ) + m_data.push_back(val[i]); +} + +void CSerialiser::WriteSub(const CSerialiser& val) +{ + // TODO: Append reference to sub-buffer contents + m_data.reserve( m_data.size() + val.m_data.size() ); + for( auto byte : val.m_data ) + m_data.push_back( byte ); +} + +const ::std::vector<uint8_t>& CSerialiser::Compact() +{ + return m_data; +} + +}; // namespace AxWin + diff --git a/Usermode/Applications/axwin4_src/Makefile b/Usermode/Applications/axwin4_src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..28fb532fdaaff7bbeb2935b06594aed2cb23419d --- /dev/null +++ b/Usermode/Applications/axwin4_src/Makefile @@ -0,0 +1,5 @@ +%: + @echo --- AxWin4 Server + @make -C Server/ $* + @echo --- AxWin4 UI + @make -C UI/ $* diff --git a/Usermode/Applications/axwin4_src/Notes.txt b/Usermode/Applications/axwin4_src/Notes.txt new file mode 100644 index 0000000000000000000000000000000000000000..ee09686bb3e24771397e1764c76cb31a06aeb637 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Notes.txt @@ -0,0 +1,47 @@ +Layers: + +IPC / Client management +Compositor / Window Manager +Renderer / Window Contents + +Renderers +Window Management +> "WM_CreateWindow(Parent, Class, Name)" +Window Drawing +> "WD_Fill" +> "WD_Blit" +> "WD_LockSurface" +> "WD_UnlockSurface" +Decorations +> ".InitWindow" +> ".Render" ++ "WM_SetBorder" +Compositing +> Dirty rectangling, use 2DCmd to selectively blit +> Request kernel/server buffers if possible + + +Clients own windows +Windows are composed of multiple regions that conform to several types (see below) +- Re-draw is handled by using these regions + +Server-side rendering primitives: + # Apply to regions, rendered in fixed order, each has an ID +> Auto-scaling bitmaps + - Control backed by an image with three/five regions per axis + Edge Fixed, Fill, Center Fixed, Fill, Edge Fixed + - Definition is via two pixel counts (edge width, fill width), rest is derived + - Command to switch backing image to another already provided +> Tiling bitmaps + filled rects +> Text (single line) +> Canvas (Takes drawing commands, draws to internal buffer) +> Shared buffer (of an unspecified pixel format) + +=== Config options === +- Root App +- Display device (- = stdout) +- Keyboard device (- = stdin) +- Mouse device +- Pipe suffix, port number, etc. +- Key bindings + diff --git a/Usermode/Applications/axwin4_src/Server/CClient.cpp b/Usermode/Applications/axwin4_src/Server/CClient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2abcb9b5ed2714e4ca3e3b9b2bb839dfea684a3c --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/CClient.cpp @@ -0,0 +1,79 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CClient.cpp + * - IPC Client + */ +#include <CClient.hpp> +#include <IIPCChannel.hpp> +#include <ipc.hpp> +#include <draw_text.hpp> // for the fonts + +namespace AxWin { + +CClient::CClient(::AxWin::IIPCChannel& channel): + m_channel(channel), + m_id(0) +{ + +} + +CClient::~CClient() +{ + ::AxWin::IPC::DeregisterClient(*this); +} + +CWindow* CClient::GetWindow(int ID) +{ + try { + return m_windows.at(ID); + } + catch(const std::exception& e) { + return NULL; + } +} + +void CClient::SetWindow(int ID, CWindow* window) +{ + //_SysDebug("SetWindow(ID=%i,window=%p)", ID, window); + auto it = m_windows.find(ID); + if( it != m_windows.end() ) { + _SysDebug("CLIENT BUG: Window ID %i is already used by %p", ID, it->second); + } + else { + m_windows[ID] = window; + } +} + +IFontFace& CClient::GetFont(unsigned int id) +{ + static CFontFallback fallback_font; + if( id == 0 ) { + _SysDebug("GetFont: %i = %p", id, &fallback_font); + return fallback_font; + } + assert(!"TODO: CClient::GetFont id != 0"); +} + +void CClient::HandleMessage(CDeserialiser& message) +{ + try { + IPC::HandleMessage(*this, message); + if( !message.IsConsumed() ) + { + _SysDebug("NOTICE - CClient::HandleMessage - Trailing data in message"); + } + } + catch( const ::std::exception& e ) + { + _SysDebug("ERROR - Exception while processing message from client: %s", e.what()); + } + catch( ... ) + { + _SysDebug("ERROR - Unknown exception while processing message from client"); + } +} + +}; // namespace AxWin + diff --git a/Usermode/Applications/axwin4_src/Server/CConfig.cpp b/Usermode/Applications/axwin4_src/Server/CConfig.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eec783b44b04a4b018f2acd277fe8ba45951829d --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/CConfig.cpp @@ -0,0 +1,35 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CConfig.cpp + * - Configuration + */ +#include <CConfig.hpp> + +namespace AxWin { + +CConfig::CConfig() +{ +} + +bool CConfig::parseCommandline(int argc, char *argv[]) +{ + return false; +} + +CConfigVideo::CConfigVideo() +{ +} + +CConfigInput::CConfigInput(): + mouse_device("/Devices/Mouse/system") +{ +} + +CConfigIPC::CConfigIPC() +{ +} + +}; // namespace AxWin + diff --git a/Usermode/Applications/axwin4_src/Server/CIPCChannel_AcessIPCPipe.cpp b/Usermode/Applications/axwin4_src/Server/CIPCChannel_AcessIPCPipe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d894e3d25c9ccab0386e28780cb6097a9bee2b6 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/CIPCChannel_AcessIPCPipe.cpp @@ -0,0 +1,120 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CIPCChannel_AcessIPCPipe.cpp + * - IPC Channel :: Acess' IPC Pipe /Devices/ipcpipe/<name> + */ +#include <ipc.hpp> +#include <CIPCChannel_AcessIPCPipe.hpp> +#include <cerrno> +#include <system_error> +#include <acess/sys.h> +#include <algorithm> + +namespace AxWin { + +CIPCChannel_AcessIPCPipe::CIPCChannel_AcessIPCPipe(const ::std::string& suffix) +{ + ::std::string path = "/Devices/ipcpipe/" + suffix; + m_fd = _SysOpen(path.c_str(), OPENFLAG_CREATE); + if(m_fd == -1) { + _SysDebug("Failed to open %s: %s", path.c_str(), strerror(errno)); + throw ::std::system_error(errno, ::std::system_category()); + } +} +CIPCChannel_AcessIPCPipe::~CIPCChannel_AcessIPCPipe() +{ + _SysClose(m_fd); +} + +int CIPCChannel_AcessIPCPipe::FillSelect(fd_set& rfds) +{ + int maxfd = m_fd; + FD_SET(m_fd, &rfds); + + for( auto& clientref : m_clients ) + { + maxfd = ::std::max(maxfd, clientref.m_fd); + FD_SET(clientref.m_fd, &rfds); + } + + return maxfd+1; +} + +void CIPCChannel_AcessIPCPipe::HandleSelect(const fd_set& rfds) +{ + if( FD_ISSET(m_fd, &rfds) ) + { + int newfd = _SysOpenChild(m_fd, "newclient", OPENFLAG_READ|OPENFLAG_WRITE); + if( newfd == -1 ) { + _SysDebug("ERROR - Failure to open new client on FD%i", m_fd); + } + else { + _SysDebug("CIPCChannel_AcessIPCPipe::HandleSelect - New client on FD %i with FD%i", + m_fd, newfd); + + // emplace creates a new object within the list + m_clients.emplace( m_clients.end(), *this, newfd ); + IPC::RegisterClient( m_clients.back() ); + } + } + + for( auto it = m_clients.begin(); it != m_clients.end(); ) + { + CClient_AcessIPCPipe& clientref = *it; + ++ it; + + if( FD_ISSET(clientref.m_fd, &rfds) ) + { + try { + clientref.HandleReceive(); + } + catch( const ::std::exception& e ) { + _SysDebug("ERROR - Exception processing IPCPipe FD%i: '%s', removing", + clientref.m_fd, e.what() + ); + it = m_clients.erase(--it); + } + } + } +} + + +CClient_AcessIPCPipe::CClient_AcessIPCPipe(::AxWin::IIPCChannel& channel, int fd): + CClient(channel), + m_fd(fd) +{ +} + +CClient_AcessIPCPipe::~CClient_AcessIPCPipe() +{ + _SysClose(m_fd); + _SysDebug("Closed client FD%i", m_fd); +} + +void CClient_AcessIPCPipe::SendMessage(CSerialiser& message) +{ + const ::std::vector<uint8_t>& data = message.Compact(); + + _SysDebug("CClient_AcessIPCPipe::SendMessage - %i bytes to %i", data.size(), m_fd); + //_SysDebugHex("CClient_AcessIPCPipe::SendMessage", data.data(), data.size()); + _SysWrite(m_fd, data.data(), data.size()); +} + +void CClient_AcessIPCPipe::HandleReceive() +{ + ::std::vector<uint8_t> rxbuf(0x1000); + size_t len = _SysRead(m_fd, rxbuf.data(), rxbuf.capacity()); + if( len == (size_t)-1 ) + throw ::std::system_error(errno, ::std::system_category()); + _SysDebug("CClient_AcessIPCPipe::HandleReceive - Rx %i/%i bytes", len, rxbuf.capacity()); + //_SysDebugHex("CClient_AcessIPCPipe::HandleReceive", rxbuf.data(), len); + rxbuf.resize(len); + + CDeserialiser msg( ::std::move(rxbuf) ); + CClient::HandleMessage( msg ); +} + +}; + diff --git a/Usermode/Applications/axwin4_src/Server/CRect.cpp b/Usermode/Applications/axwin4_src/Server/CRect.cpp new file mode 100644 index 0000000000000000000000000000000000000000..acbcc27e30b3b7bb51a46089a5c168f1d88654a1 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/CRect.cpp @@ -0,0 +1,78 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CRect.cpp + * - Rectangle + */ +#include <CRect.hpp> +#include <algorithm> +#include <acess/sys.h> + +namespace AxWin { + +CRect::CRect(int x, int y, unsigned int w, unsigned int h): + m_x(x), m_y(y), + m_w(w), m_h(h), + m_x2(x+w), m_y2(y+h) +{ +} + +void CRect::Move(int NewX, int NewY) +{ + // TODO: Add a parent rectangle, and prevent this from fully leaving its bounds + m_x = NewX; + m_y = NewY; + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; +} + +void CRect::Resize(int NewW, int NewH) +{ + m_w = NewW; + m_h = NewH; + m_x2 = m_x + m_w; + m_y2 = m_y + m_h; +} + +bool CRect::HasIntersection(const CRect& other) const +{ + // If other's origin is past our far corner + if( m_x2 < other.m_x ) + return false; + if( m_y2 < other.m_y ) + return false; + + // If other's far corner is before our origin + if( m_x > other.m_x2 ) + return false; + if( m_y > other.m_y2 ) + return false; + return true; +} + +CRect CRect::Intersection(const CRect& other) const +{ + int x1 = ::std::max(m_x, other.m_x); + int y1 = ::std::max(m_y, other.m_y); + int x2 = ::std::min(m_x2, other.m_x2); + int y2 = ::std::min(m_y2, other.m_y2); + + if( x2 <= x1 || y2 <= y1 ) + return CRect(); + + return CRect(x1, y1, x2-x1, y2-y1); +} + +CRect CRect::RelativeIntersection(const CRect& area) +{ + CRect ret = Intersection(area); + ret.m_x -= m_x; + ret.m_x2 -= m_x; + ret.m_y -= m_y; + ret.m_y2 -= m_y; + return ret; +} + +}; + diff --git a/Usermode/Applications/axwin4_src/Server/CSurface.cpp b/Usermode/Applications/axwin4_src/Server/CSurface.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d0eddc428ef3101a7abb5bd54746c2808619e7a4 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/CSurface.cpp @@ -0,0 +1,143 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CWindow.cpp + * - Window + */ +#include <CSurface.hpp> +#include <cassert> +#include <stdexcept> +#include <cstring> +#include <system_error> +#include <cerrno> +#include <CColour.hpp> + +namespace AxWin { + +CSurface::CSurface(int x, int y, unsigned int w, unsigned int h): + m_rect(x,y, w,h), + m_fd(-1), + m_data(0) +{ + if( w > 0 && h > 0 ) + { + m_data = new uint32_t[w * h]; + } +} + +CSurface::~CSurface() +{ + if( m_fd == -1 ) { + delete[] m_data; + } + else { + size_t size = m_rect.m_w*m_rect.m_h*4; + _SysMUnMap(m_data, size); + } +} + +uint64_t CSurface::GetSHMHandle() +{ + size_t size = m_rect.m_w*m_rect.m_h*4; + if( m_fd == -1 ) + { + // 2. Allocate a copy in SHM + m_fd = _SysOpen("/Devices/shm/anon", OPENFLAG_WRITE|OPENFLAG_READ); + if(m_fd == -1) { + _SysDebug("GetSHMHandle: Unable to open anon SHM"); + return -1; + } + // 1. Free local buffer + delete m_data; + _SysTruncate(m_fd, size); + } + else + { + _SysMUnMap(m_data, size); + } + // 3. mmap shm copy + m_data = static_cast<uint32_t*>( _SysMMap(nullptr, size, MMAP_PROT_WRITE, 0, m_fd, 0) ); + if(!m_data) throw ::std::system_error(errno, ::std::system_category()); + + return _SysMarshalFD(m_fd); +} + +void CSurface::Resize(unsigned int W, unsigned int H) +{ + if( m_fd == -1 ) + { + // Easy realloc + // TODO: Should I maintain window contents sanely? NOPE! + delete m_data; + m_data = new uint32_t[W * H]; + } + else + { + //_SysIOCtl(m_fd, SHM_IOCTL_SETSIZE, W*H*4); + } + m_rect.Resize(W, H); +} + +void CSurface::DrawScanline(unsigned int row, unsigned int x_ofs, unsigned int w, const void* data) +{ + if( row >= m_rect.m_h ) + throw ::std::out_of_range("CSurface::DrawScanline row"); + if( x_ofs >= m_rect.m_w ) + throw ::std::out_of_range("CSurface::DrawScanline x_ofs"); + + if( w > m_rect.m_w ) + throw ::std::out_of_range("CSurface::DrawScanline width"); + + size_t ofs = row*m_rect.m_w + x_ofs; + ::memcpy( &m_data[ofs], data, w*4 ); +} + +void CSurface::BlendScanline(unsigned int row, unsigned int x_ofs, unsigned int w, const void* data) +{ + if( row >= m_rect.m_h ) + throw ::std::out_of_range("CSurface::DrawScanline row"); + if( x_ofs >= m_rect.m_w ) + throw ::std::out_of_range("CSurface::DrawScanline x_ofs"); + + if( w > m_rect.m_w ) + throw ::std::out_of_range("CSurface::DrawScanline width"); + + const uint32_t* in_data = (const uint32_t*)data; + size_t ofs = row*m_rect.m_w + x_ofs; + for( unsigned int x = 0; x < w; x ++ ) + { + CColour out = CColour::from_argb(m_data[ofs+x]).blend( CColour::from_argb(in_data[x]) ); + m_data[ofs+x] = out.to_argb(); + } +} + +void CSurface::FillScanline(unsigned int row, unsigned int x_ofs, unsigned int w, uint32_t colour) +{ + if( row >= m_rect.m_h ) + throw ::std::out_of_range("CSurface::FillScanline row"); + if( x_ofs >= m_rect.m_w ) + throw ::std::out_of_range("CSurface::FillScanline x_ofs"); + + if( w > m_rect.m_w ) + throw ::std::out_of_range("CSurface::FillScanline width"); + + size_t ofs = row*m_rect.m_w + x_ofs; + while( w -- ) + m_data[ofs++] = colour; +} + +const uint32_t* CSurface::GetScanline(unsigned int row, unsigned int x_ofs) const +{ + if( row >= m_rect.m_h ) + throw ::std::out_of_range("CSurface::GetScanline row"); + if( x_ofs >= m_rect.m_w ) + throw ::std::out_of_range("CSurface::GetScanline x_ofs"); + + return &m_data[row * m_rect.m_w + x_ofs]; +} + + +}; // namespace AxWin + + diff --git a/Usermode/Applications/axwin4_src/Server/CWindow.cpp b/Usermode/Applications/axwin4_src/Server/CWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..022d6b49be1d9690c01824fd03397fe2909f7911 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/CWindow.cpp @@ -0,0 +1,107 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CWindow.cpp + * - Window + */ +#include <CWindow.hpp> +#include <CCompositor.hpp> +#include <assert.h> +#include <ipc.hpp> + +namespace AxWin { + +CWindow::CWindow(CCompositor& compositor, CClient& client, const ::std::string& name, unsigned int id): + m_surface(0,0,0,0), + m_compositor(compositor), + m_client(client), + m_id(id), + m_name(name), + m_is_shown(false) +{ + _SysDebug("CWindow::CWindow()"); +} + +CWindow::~CWindow() +{ +} + +void CWindow::Repaint(const CRect& rect) +{ + if( m_is_shown ) + { + CRect outrect( + m_surface.m_rect.m_x + rect.m_x, + m_surface.m_rect.m_y + rect.m_y, + rect.m_w, rect.m_h + ); + m_compositor.DamageArea(outrect); + } +} + +void CWindow::Show(bool bShow) +{ + if( m_is_shown == bShow ) + return; + + if( bShow ) + m_compositor.ShowWindow( this ); + else + m_compositor.HideWindow( this ); + m_is_shown = bShow; +} + +void CWindow::Move(int X, int Y) +{ + m_surface.m_rect.Move(X, Y); +} +void CWindow::Resize(unsigned int W, unsigned int H) +{ + m_surface.Resize(W, H); + IPC::SendMessage_NotifyDims(m_client, m_id, W, H); +} +void CWindow::SetFlags(uint32_t Flags) +{ + // TODO: CWindow::SetFlags + _SysDebug("TOOD: CWindow::SetFlags"); +} +uint64_t CWindow::ShareSurface() +{ + assert(!"TODO: CWindow::ShareSurface"); + return 0; +} + +void CWindow::MouseButton(int ButtonID, int X, int Y, bool Down) +{ + IPC::SendMessage_MouseButton(m_client, m_id, X, Y, ButtonID, Down); +} + +void CWindow::MouseMove(int NewX, int NewY) +{ + // TODO: Only enable move events if client requests them + //IPC::SendMessage_MouseMove(m_client, m_id, NewX, NewY); +} + +void CWindow::KeyEvent(::uint32_t Scancode, const ::std::string &Translated, bool Down) +{ + IPC::SendMessage_KeyEvent(m_client, m_id, Scancode, Down, Translated.c_str()); +} + + +void CWindow::DrawScanline(unsigned int row, unsigned int x, unsigned int w, const uint8_t *data) +{ + m_surface.DrawScanline(row, x, w, data); + CRect damaged( m_surface.m_rect.m_x+x, m_surface.m_rect.m_y+row, w, 1 ); + m_compositor.DamageArea(damaged); +} + +void CWindow::FillScanline(unsigned int row, unsigned int x, unsigned int w, const uint32_t colour) +{ + m_surface.FillScanline(row, x, w, colour); + CRect damaged( m_surface.m_rect.m_x+x, m_surface.m_rect.m_y+row, w, 1 ); + m_compositor.DamageArea(damaged); +} + +}; + diff --git a/Usermode/Applications/axwin4_src/Server/Makefile b/Usermode/Applications/axwin4_src/Server/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b85fc08876ca58cabae28885d4094a3be6859e87 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/Makefile @@ -0,0 +1,26 @@ + +include ../../Makefile.cfg + +DIR := Apps/AxWin/4.0 + +CPPFLAGS += -Iinclude/ -I../Common/include/ +OBJ := main.o ipc.o CConfig.o video.o input.o timing.o +OBJ += compositor.o CWindow.o +OBJ += Common__serialisation.o +OBJ += CClient.o +OBJ += CIPCChannel_AcessIPCPipe.o +OBJ += CRect.o CSurface.o +OBJ += draw_control.o draw_text.o +BIN := AxWinServer + +LIBS += -lc++ -lunicode +#CXXFLAGS += -O3 +USE_CXX_LINK = 1 + +include ../../Makefile.tpl + +$(_OBJPREFIX)Common__%.o: ../Common/%.cpp + @echo [CXX] -o $@ + @mkdir -p $(dir $@) + $V$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@ -MQ $@ -MP -MD -MF $(@:%.o=%.dep) + diff --git a/Usermode/Applications/axwin4_src/Server/compositor.cpp b/Usermode/Applications/axwin4_src/Server/compositor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e488380fce4dedea6fa521dff1958cade6dbd4e2 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/compositor.cpp @@ -0,0 +1,186 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * compositor.cpp + * - Window compositor + */ +#include <video.hpp> +#include <CCompositor.hpp> +#include <CClient.hpp> +#include <ipc.hpp> +#include <cassert> + +namespace AxWin { + +CCompositor::CCompositor(CVideo& video): + // TODO: Support multiple screens + m_video(video), + m_focussed_window(nullptr), + m_windowIDBuffer(video.width(), video.height()) +{ + // +} + +void CCompositor::ShowWindow(CWindow* window) +{ + DamageArea(window->m_surface.m_rect); + // TODO: Append to separate sub-lists (or to separate lists all together) + // if flags AXWIN4_WNDFLAG_KEEPBELOW or AXWIN4_WNDFLAG_KEEPABOVE are set + m_windows.push_back(window); +} +void CCompositor::HideWindow(CWindow* window) +{ + DamageArea(window->m_surface.m_rect); + m_windows.remove(window); +} + +bool CCompositor::GetScreenDims(unsigned int ScreenID, unsigned int* W, unsigned int* H) +{ + assert(W && H); + if( ScreenID != 0 ) + { + *W = 0; + *H = 0; + return false; + } + else + { + m_video.GetDims(*W, *H); + return true; + } +} + +void CCompositor::Redraw() +{ + // Redraw the screen and clear damage rects + if( m_damageRects.empty() ) { + //_SysDebug("- No damaged regions"); + return ; + } + + // Build up foreground grid (Rects and windows) + // - This should already be built (mutated on window move/resize/reorder) + + // For all windows, check for intersection with damage rects + for( auto rect : m_damageRects ) + { + // window list should be sorted by draw order (lowest first) + for( auto window : m_windows ) + { + if( window->m_is_shown && rect.HasIntersection( window->m_surface.m_rect ) ) + { + // TODO: just reblit + CRect rel_rect = window->m_surface.m_rect.RelativeIntersection(rect); + _SysDebug("Reblit (%i,%i) %ix%i", rel_rect.m_x, rel_rect.m_y, rel_rect.m_w, rel_rect.m_h); + BlitFromSurface( window->m_surface, rel_rect ); + //window->Repaint( rel_rect ); + m_windowIDBuffer.set(rel_rect.m_x, rel_rect.m_y, rel_rect.m_w, rel_rect.m_h, window); + } + } + + // TODO: Blit from windows to a local surface, then blit from there to screen here + } + + m_damageRects.clear(); + m_video.Flush(); +} + +void CCompositor::DamageArea(const CRect& area) +{ + m_damageRects.push_back( area ); + // 1. Locate intersection with any existing damaged areas + // 2. Append after removing intersections +} + +void CCompositor::BlitFromSurface(const CSurface& dest, const CRect& src_rect) +{ + for( unsigned int i = 0; i < src_rect.m_h; i ++ ) + { + m_video.BlitLine( + dest.GetScanline(src_rect.m_y+i, src_rect.m_x), + dest.m_rect.m_y + src_rect.m_y + i, + dest.m_rect.m_x + src_rect.m_x, + src_rect.m_w + ); + } +} + +void CCompositor::MouseMove(unsigned int Cursor, unsigned int X, unsigned int Y, int dX, int dY) +{ + //_SysDebug("MouseButton(%i, %i,%i, %+i,%+i)", Cursor, X, Y, dX, dY); + m_video.SetCursorPos(X+dX, Y+dY); + CWindow *dstwin = getWindowForCoord(X, Y); + if( dstwin ) + { + // Pass event on to window + dstwin->MouseMove(X, Y); + } +} + +void CCompositor::MouseButton(unsigned int Cursor, unsigned int X, unsigned int Y, eMouseButton Button, bool Press) +{ + _SysDebug("MouseButton(%i, %i,%i, %i=%i)", Cursor, X, Y, Button, Press); + CWindow *dstwin = getWindowForCoord(X, Y); + _SysDebug("- dstwin = %p", dstwin); + if( dstwin ) + { + // 1. Give focus and bring to front + // 2. Send event + dstwin->MouseButton(Button, X, Y, Press); + } +} + +void CCompositor::KeyState(unsigned int KeyboardID, uint32_t KeySym, bool Press, uint32_t Codepoint) +{ + _SysDebug("KeyState(%i, 0x%x, %b, 0x%x)", KeyboardID, KeySym, Press, Codepoint); + // TODO: Global hotkeys + if( m_focussed_window ) + { + m_focussed_window->KeyEvent(KeySym, "", Press); + } +} + +CWindow* CCompositor::getWindowForCoord(unsigned int X, unsigned int Y) +{ + return m_windowIDBuffer.get(X, Y); +} + +// -------------------------------------------------------------------- +CWindowIDBuffer::CWindowIDBuffer(unsigned int W, unsigned int H): + m_w(W), + m_buf(W*H) +{ +} +void CWindowIDBuffer::set(unsigned int X, unsigned int Y, unsigned int W, unsigned int H, CWindow* win) +{ + TWindowID ent = { + .Client = win->client().id(), + .Window = win->id(), + }; + for( unsigned int row = 0; row < H; row ++ ) + { + TWindowID* dst = &m_buf[ (Y+row) * m_w ]; + for( unsigned int col = 0; col < W; col ++ ) + dst[col] = ent; + } +} +CWindow* CWindowIDBuffer::get(unsigned int X, unsigned int Y) +{ + if( X >= m_w ) + return nullptr; + unsigned int pos = Y*m_w + X; + if( pos >= m_buf.size() ) + return nullptr; + auto id = m_buf[pos]; + //_SysDebug("CWindowIDBuffer::get id = {%i,%i}", id.Client, id.Window); + auto client = ::AxWin::IPC::GetClientByID(id.Client); + if( client == nullptr ) { + //_SysDebug("CWindowIDBuffer::get client=%p", client); + return nullptr; + } + return client->GetWindow(id.Window); +} + +} // namespace AxWin + diff --git a/Usermode/Applications/axwin4_src/Server/draw_control.cpp b/Usermode/Applications/axwin4_src/Server/draw_control.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ef105e77d433b259ddfe6f4bb11b12d32f554bb9 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/draw_control.cpp @@ -0,0 +1,178 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * draw_control.cpp + * - Common "Control" Drawing + * + * Handles drawing of resizable controls defined by a bitmap and four region sizes + */ +#include <draw_control.hpp> +#include <axwin4/definitions.h> +#include <acess/sys.h> +#include <cassert> + +// === CODE === +namespace AxWin { + +CControl::CControl(int EdgeX, int FillX, int InnerX, int EdgeY, int FillY, int InnerY, ::std::vector<uint32_t>&& data): + m_edge_x(EdgeX), + m_fill_x(FillX), + m_inner_x(InnerX), + m_edge_y(EdgeY), + m_fill_y(FillY), + m_inner_y(InnerY), + m_data(data) +{ + _SysDebug("CControl(X={E:%i,F:%i,I:%i}, Y={E:%i,F:%i,I:%i}, data={Size:%i})", + m_edge_x, m_fill_x, m_inner_x, m_edge_y, m_fill_y, m_inner_y, m_data.size()); +} + +void CControl::Render(CSurface& dest, const CRect& rect) const +{ + if( rect.m_w < m_edge_x*2 + m_fill_x*2 + m_inner_x ) + return ; + if( rect.m_h < m_edge_y*2 + m_fill_y*2 + m_inner_y ) + return ; + + const int ctrl_width = m_edge_x + m_fill_x + m_inner_x + (m_inner_x ? m_fill_x : 0) + m_edge_x; + + const int top_fill_end = rect.m_h / 2 - m_inner_y; + const int bot_fill_start = top_fill_end + m_inner_y; + const int bot_fill_end = rect.m_h - m_edge_y; + + ::std::vector<uint32_t> scanline( rect.m_w ); + int y = 0; + int base_ofs = 0; + // EdgeY + for( int i = 0; i < m_edge_y; i ++ ) + renderLine(dest, y++, scanline, rect, &m_data[(base_ofs+i)*ctrl_width]); + base_ofs += m_edge_y; + // FillY + assert(m_fill_y > 0 || y == top_fill_end); + while( y < top_fill_end ) + { + for( int i = 0; i < m_fill_y && y < top_fill_end; i ++ ) + renderLine(dest, y++, scanline, rect, &m_data[(base_ofs+i)*ctrl_width]); + } + base_ofs += m_fill_y; + // InnerY + if( m_inner_y > 0 ) + { + for( int i = 0; i < m_inner_y; i ++ ) + renderLine(dest, y++, scanline, rect, &m_data[(base_ofs+i)*ctrl_width]); + base_ofs += m_inner_y; + } + else + { + base_ofs -= m_fill_x; + } + // FillY + while( y < bot_fill_end ) + { + for( int i = 0; i < m_fill_y && y < bot_fill_end; i ++ ) + renderLine(dest, y++, scanline, rect, &m_data[(base_ofs+i)*ctrl_width]); + } + base_ofs += m_fill_y; + // EdgeY + for( int i = 0; i < m_edge_y; i ++ ) + renderLine(dest, y++, scanline, rect, &m_data[(base_ofs+i)*ctrl_width]); + base_ofs += m_edge_y; +} + +void CControl::renderLine(CSurface& dest, int y, ::std::vector<uint32_t>& scanline, const CRect& rect, const uint32_t* ctrl_line) const +{ + //_SysDebug("renderLine: (y=%i,rect={(%i,%i) %ix%i}", y, rect.m_x, rect.m_y, rect.m_w, rect.m_h); + const int left_fill_end = rect.m_w / 2 - m_inner_x; + const int right_fill_end = rect.m_w - m_edge_x; + + int x = 0; + int base_ofs = 0; + // EdgeX + for( int i = 0; i < m_edge_x; i ++ ) + scanline[x++] = ctrl_line[base_ofs + i]; + base_ofs += m_edge_x; + // FillX + while( x < left_fill_end ) + { + for( int i = 0; i < m_fill_x && x < left_fill_end; i ++ ) + scanline[x++] = ctrl_line[base_ofs + i]; + } + base_ofs += m_fill_x; + // InnerX + if( m_inner_x > 0 ) + { + for( int i = 0; i < m_inner_x; i ++ ) + scanline[x++] = ctrl_line[base_ofs + i]; + base_ofs += m_inner_x; + } + else + { + base_ofs -= m_fill_x; + } + // FillX + while( x < right_fill_end ) + { + for( int i = 0; i < m_fill_x && x < right_fill_end; i ++ ) + scanline[x++] = ctrl_line[base_ofs + i]; + } + base_ofs += m_fill_x; + // EdgeX + for( int i = 0; i < m_edge_x; i ++ ) + scanline[x++] = ctrl_line[base_ofs + i]; + base_ofs += m_edge_x; + + dest.DrawScanline(rect.m_y + y, rect.m_x, rect.m_w, scanline.data()); +} + +// ---- Standard Controls --- +// Standard button control +CControl StdButton(2, 1, 0, 2, 1, 0, ::std::vector<uint32_t> { + 0xC0C0C0, 0xC0C0C0, 0xC0C0C0, 0xC0C0C0, 0xC0C0C0, + 0xC0C0C0, 0xFFD0D0, 0xFFD0D0, 0xFFD0D0, 0xC0C0C0, + 0xC0C0C0, 0xFFD0D0, 0xFFD0D0, 0xFFD0D0, 0xC0C0C0, + 0xC0C0C0, 0xFFD0D0, 0xFFD0D0, 0xFFD0D0, 0xC0C0C0, + 0xC0C0C0, 0xC0C0C0, 0xC0C0C0, 0xC0C0C0, 0xC0C0C0, + }); + +// Toolbar +CControl StdToolbar(2, 1, 0, 2, 1, 0, ::std::vector<uint32_t> { + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0xA0A0A0, 0x0A0000, 0xA0A0A0, 0x000000, + 0x000000, 0xA0A0A0, 0xFFFFFF, 0xA0A0A0, 0x000000, + 0x000000, 0xA0A0A0, 0x0A0000, 0xA0A0A0, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + }); + +// Text Area +CControl StdText(2, 1, 0, 2, 1, 0, ::std::vector<uint32_t> { + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0xA0A0A0, 0x0A0000, 0xA0A0A0, 0x000000, + 0x000000, 0xA0A0A0, 0xFFFFFF, 0xA0A0A0, 0x000000, + 0x000000, 0xA0A0A0, 0x0A0000, 0xA0A0A0, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + }); + +const CControl* CControl::GetByName(const ::std::string& name) +{ + if( name == "StdButton" ) + return &StdButton; + if( name == "StdText" ) + return &StdText; + // TODO: Use another exception + return nullptr; +} + +const CControl* CControl::GetByID(uint16_t id) +{ + switch(id) + { + case AXWIN4_CTL_BUTTON: return &StdButton; + case AXWIN4_CTL_TOOLBAR: return &StdToolbar; + case AXWIN4_CTL_TEXTBOX: return &StdText; + default: return nullptr; + } +} + +}; // AxWin + diff --git a/Usermode/Applications/axwin4_src/Server/draw_text.cpp b/Usermode/Applications/axwin4_src/Server/draw_text.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e9e7b8ede2bce15707e6bd9b02d7e98e9d92d2f --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/draw_text.cpp @@ -0,0 +1,167 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * draw_text.cpp + * - Text Drawing + * + * Handles font selection and drawing of text to windows + */ +#include <draw_text.hpp> +#include <axwin4/definitions.h> +#include <unicode.h> // libunicode (acess) +extern "C" { +#include <assert.h> // assert... and _SysDebug +}; +#include "resources/font_8x16.h" + +// === CODE === +namespace AxWin { + +// -- Primitive fallback font +CFontFallback::CFontFallback() +{ +} + +CRect CFontFallback::Size(const ::std::string& text, unsigned int Size) const +{ + return CRect(0,0, text.size() * Size * FONT_WIDTH / FONT_HEIGHT, Size); +} + +/** + * \param Text height in pixels (not in points) + */ +void CFontFallback::Render(CSurface& dest, const CRect& rect, const ::std::string& text, unsigned int Size) +{ + unsigned int font_step = Size * FONT_WIDTH / FONT_HEIGHT; + CRect pos = rect; + for( auto codepoint : ::libunicode::utf8string(text) ) + { + renderAtRes(dest, pos, codepoint, Size, 0x000000); + pos.Translate(font_step, 0); + } +} + +void CFontFallback::renderAtRes(CSurface& dest, const CRect& rect, uint32_t cp, unsigned int Size, uint32_t FGC) +{ + unsigned int char_idx = unicodeToCharmap(cp); + assert(char_idx < 256); + const uint8_t* char_ptr = &VTermFont[char_idx * FONT_HEIGHT]; + unsigned int out_h = Size; + unsigned int out_w = (Size * FONT_WIDTH / FONT_HEIGHT); + uint32_t char_data[out_w]; + if( Size == FONT_HEIGHT ) { + // Standard blit + for( unsigned int row = 0; row < out_h; row ++ ) + { + for( unsigned int col = 0; col < out_w; col ++ ) + { + uint8_t alpha = getValueAtRaw(char_ptr, col, row); + char_data[col] = ((uint32_t)alpha << 24) | (FGC & 0xFFFFFF); + } + dest.BlendScanline(rect.m_y + row, rect.m_x, FONT_WIDTH, char_data); + } + } + else if( Size < FONT_HEIGHT ) { + // Down-scaled blit + // NOTE: uses the same code as the upscale blit (probably not correct, need to replace) + for( unsigned int row = 0; row < out_h; row ++ ) + { + unsigned int yf16 = row * FONT_HEIGHT * 0x10000 / out_h; + for( unsigned int col = 0; col < out_w; col ++ ) + { + unsigned int xf16 = col * FONT_WIDTH * 0x10000 / out_w; + uint8_t alpha = getValueAtPt(char_ptr, xf16, yf16); + //_SysDebug("row %i (%05x), col %i (%05x): alpha = %02x", row, yf16, col, xf16, alpha); + char_data[col] = ((uint32_t)alpha << 24) | (FGC & 0xFFFFFF); + } + dest.BlendScanline(rect.m_y + row, rect.m_x, out_w, char_data); + } + } + else { + // up-scaled blit + for( unsigned int row = 0; row < out_h; row ++ ) + { + unsigned int yf16 = row * FONT_HEIGHT * 0x10000 / out_h; + for( unsigned int col = 0; col < out_w; col ++ ) + { + unsigned int xf16 = col * FONT_WIDTH * 0x10000 / out_w; + uint8_t alpha = getValueAtPt(char_ptr, xf16, yf16); + //_SysDebug("row %i (%05x), col %i (%05x): alpha = %02x", row, yf16, col, xf16, alpha); + char_data[col] = ((uint32_t)alpha << 24) | (FGC & 0xFFFFFF); + } + dest.BlendScanline(rect.m_y + row, rect.m_x, out_w, char_data); + } + } +} +// X and Y are fixed-point 16.16 values +uint8_t CFontFallback::getValueAtPt(const uint8_t* char_ptr, unsigned int xf16, unsigned int yf16) +{ + unsigned int ix = xf16 >> 16; + unsigned int iy = yf16 >> 16; + unsigned int fx = xf16 & 0xFFFF; + unsigned int fy = yf16 & 0xFFFF; + + if( fx == 0 && fy == 0 ) { + return getValueAtRaw(char_ptr, ix, iy); + } + else if( fx == 0 ) { + float y = (float)fy / 0x10000; + uint8_t v0 = getValueAtRaw(char_ptr, ix, iy ); + uint8_t v1 = getValueAtRaw(char_ptr, ix, iy+1); + return v0 * (1 - y) + v1 * y; + } + else if( fy == 0 ) { + float x = (float)fx / 0x10000; + uint8_t v0 = getValueAtRaw(char_ptr, ix , iy); + uint8_t v1 = getValueAtRaw(char_ptr, ix+1, iy); + return v0 * (1 - x) + v1 * x; + } + else { + float x = (float)fx / 0x10000; + float y = (float)fx / 0x10000; + // [0,0](1 - x)(1 - y) + [1,0]x(1-y) + [0,1](1-x)y + [1,1]xy + uint8_t v00 = getValueAtRaw(char_ptr, ix, iy); + uint8_t v01 = getValueAtRaw(char_ptr, ix, iy+1); + uint8_t v10 = getValueAtRaw(char_ptr, ix+1, iy); + uint8_t v11 = getValueAtRaw(char_ptr, ix+1, iy+1); + //_SysDebug("x,y = %04x %04x", (unsigned)(x * 0x10000), (unsigned)(y * 0x10000)); + //_SysDebug("v = %02x %02x %02x %02x", v00, v01, v10, v11); + float val1 = v00 * (1 - x) * (1 - y); + float val2 = v10 * x * (1 - y); + float val3 = v01 * (1 - x) * y; + float val4 = v11 * x * y; + //_SysDebug("vals = %04x %04x %04x %04x", + // (unsigned)(val1 * 0x10000), + // (unsigned)(val2 * 0x10000), + // (unsigned)(val3 * 0x10000), + // (unsigned)(val4 * 0x10000) + // ); + + return (uint8_t)(val1 + val2 + val3 + val4); + } +} + +uint8_t CFontFallback::getValueAtRaw(const uint8_t* char_ptr, unsigned int x, unsigned int y) +{ + //if( x == 0 || y == 0 ) + // return 0; + //x --; y --; + if(x >= FONT_WIDTH || y >= FONT_HEIGHT) + return 0; + return (char_ptr[y] & (1 << (7-x))) ? 255 : 0; +} + +unsigned int CFontFallback::unicodeToCharmap(uint32_t cp) const +{ + if(cp >= ' ' && cp < 0x7F) + return cp; + switch(cp) + { + default: + return 0; + } +} + +}; // namespace AxWin + diff --git a/Usermode/Applications/axwin4_src/Server/include/CClient.hpp b/Usermode/Applications/axwin4_src/Server/include/CClient.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2a23f155580d49ee96892a27714d116e5e1a6768 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/CClient.hpp @@ -0,0 +1,48 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CClient.hpp + * - IPC Client + */ +#ifndef _CCLIENT_H_ +#define _CCLIENT_H_ + +#include "CWindow.hpp" +#include "serialisation.hpp" +#include <map> +#include <cassert> +#include "IFontFace.hpp" + +namespace AxWin { + +class IIPCChannel; + +class CClient +{ + unsigned int m_id; + IIPCChannel& m_channel; + + ::std::map<unsigned int,CWindow*> m_windows; + //CWindow* m_windows[1]; +public: + CClient(::AxWin::IIPCChannel& channel); + virtual ~CClient(); + + void set_id(unsigned int id) { assert(m_id == 0); m_id = id; } + unsigned int id() const { return m_id; } + + CWindow* GetWindow(int ID); + void SetWindow(int ID, CWindow* window); + + IFontFace& GetFont(unsigned int id); + + virtual void SendMessage(CSerialiser& reply) = 0; + void HandleMessage(CDeserialiser& message); +}; + + +}; + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/CColour.hpp b/Usermode/Applications/axwin4_src/Server/include/CColour.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d47d7e044ec1a444b40c8b76654299affaab602e --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/CColour.hpp @@ -0,0 +1,93 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CColour.hpp + * - Generic colour handling and blending + */ +#ifndef _CCOLOUR_HPP_ +#define _CCOLOUR_HPP_ + +namespace AxWin { + +class CColour +{ + static const uint8_t uint8_max = 0xFF; + static const unsigned int comp_max = 0x7FFF; + + unsigned int m_alpha; + unsigned int m_red; + unsigned int m_green; + unsigned int m_blue; + +private: + static unsigned int u8_to_ui(uint8_t u8v) { + return (unsigned int)u8v * comp_max / uint8_max; + } + static uint8_t ui_to_u8(unsigned int uiv) { + return uiv * uint8_max / comp_max; + } + // Perform an alpha-based blend on two components + static unsigned int alpha_blend(unsigned int alpha_comp, unsigned int left, unsigned int right) { + return (left * (comp_max - alpha_comp) + right * alpha_comp) / comp_max; + } + // Float values: + // - infinity == saturation, 1 == nothing + // fv = MAX / (MAX - uiv) + static float ui_to_float(unsigned int uiv) { + return (float)comp_max / (comp_max - uiv); + } + // uiv = MAX - MAX / fv + static unsigned int float_to_ui(float fv) { + return comp_max - comp_max / fv; + } + // perform a non-oversaturating blend of two colours (using an inverse relationship) + static unsigned int add_blend(unsigned int a, unsigned int b) { + return float_to_ui( ui_to_float(a) + ui_to_float(b) ); + } + + CColour(unsigned int r, unsigned int g, unsigned int b, unsigned int a): + m_alpha(a), m_red(r), m_green(g), m_blue(b) + { + } +public: + + static CColour from_argb(uint32_t val) { + return CColour( + u8_to_ui((val>>16) & 0xFF), + u8_to_ui((val>> 8) & 0xFF), + u8_to_ui((val>> 0) & 0xFF), + u8_to_ui((val>>24) & 0xFF) + ); + } + + uint32_t to_argb() const { + uint32_t rv = 0; + rv |= (uint32_t)ui_to_u8(m_red) << 16; + rv |= (uint32_t)ui_to_u8(m_green) << 8; + rv |= (uint32_t)ui_to_u8(m_blue) << 0; + rv |= (uint32_t)ui_to_u8(m_alpha) << 24; + return rv; + } + + // performs a blend of the two colours, maintaining the target alpha, using the source alpha as the blend control + CColour& blend(const CColour& other) { + m_red = alpha_blend(other.m_alpha, m_red , other.m_red ); + m_green = alpha_blend(other.m_alpha, m_green, other.m_green); + m_blue = alpha_blend(other.m_alpha, m_blue , other.m_blue ); + return *this; + } + // Add all components + CColour& operator+(const CColour& other) { + m_alpha = add_blend(m_alpha, other.m_alpha); + m_red = add_blend(m_red , other.m_red ); + m_green = add_blend(m_green, other.m_green); + m_blue = add_blend(m_blue , other.m_blue ); + return *this; + } +}; + +} // namespace AxWin + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/CCompositor.hpp b/Usermode/Applications/axwin4_src/Server/include/CCompositor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fe24303929c9502981e59b704053d9d25dbec15f --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/CCompositor.hpp @@ -0,0 +1,83 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CCompositor.hpp + * - Window Compositor + */ +#ifndef _CCOMPOSITOR_H_ +#define _CCOMPOSITOR_H_ + +#include <string> +#include <list> +#include <vector> +#include "CRect.hpp" +#include "CWindow.hpp" + +namespace AxWin { + +class CClient; +class CVideo; + + +enum eMouseButton +{ + MOUSEBTN_MAIN, // Left + MOUSEBTN_SECONDARY, // Right + MOUSEBTN_MIDDLE, // Scroll wheel + MOUSEBTN_BTN4, + MOUSEBTN_BTN5, +}; + +class CWindowIDBuffer +{ + struct TWindowID + { + uint16_t Client; + uint16_t Window; + }; + unsigned int m_w; + ::std::vector<TWindowID> m_buf; +public: + CWindowIDBuffer(unsigned int W, unsigned int H); + + void set(unsigned int X, unsigned int Y, unsigned int W, unsigned int H, CWindow* win); + CWindow* get(unsigned int X, unsigned int Y); +}; + +class CCompositor +{ + CVideo& m_video; + ::std::list<CRect> m_damageRects; + ::std::list<CWindow*> m_windows; + CWindow* m_focussed_window; + + CWindowIDBuffer m_windowIDBuffer; // One 32-bit value per pixel + +public: + CCompositor(CVideo& video); + + CWindow* CreateWindow(CClient& client, const ::std::string& name); + + void ShowWindow(CWindow* window); + void HideWindow(CWindow* window); + + bool GetScreenDims(unsigned int ScrenID, unsigned int *Width, unsigned int *Height); + + void Redraw(); + void DamageArea(const CRect& rect); + void BlitFromSurface(const CSurface& dest, const CRect& src_rect); + + void MouseMove(unsigned int Cursor, unsigned int X, unsigned int Y, int dX, int dY); + void MouseButton(unsigned int Cursor, unsigned int X, unsigned int Y, eMouseButton Button, bool Press); + + void KeyState(unsigned int KeyboardID, uint32_t KeySym, bool Press, uint32_t Codepoint); +public: + CWindow* getWindowForCoord(unsigned int X, unsigned int Y); +}; + + +}; + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/CConfig.hpp b/Usermode/Applications/axwin4_src/Server/include/CConfig.hpp new file mode 100644 index 0000000000000000000000000000000000000000..aff7fc8cf77a429b455daee1800429c94c024ed9 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/CConfig.hpp @@ -0,0 +1,32 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CConfig.hpp + * - Configuration class + */ +#ifndef _CCONFIG_H_ +#define _CCONFIG_H_ + +#include "CConfigInput.hpp" +#include "CConfigVideo.hpp" +#include "CConfigIPC.hpp" + +namespace AxWin { + +class CConfig +{ +public: + CConfig(); + + bool parseCommandline(int argc, char *argv[]); + + CConfigInput m_input; + CConfigVideo m_video; + CConfigIPC m_ipc; +}; + +} + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/CConfigIPC.hpp b/Usermode/Applications/axwin4_src/Server/include/CConfigIPC.hpp new file mode 100644 index 0000000000000000000000000000000000000000..053e37616c144d26c04cd59a419ed0bf19b283fd --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/CConfigIPC.hpp @@ -0,0 +1,31 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CConfigIPC.hpp + * - Configuration class + */ +#ifndef _CCONFIGIPC_H_ +#define _CCONFIGIPC_H_ + +#include <string> + +namespace AxWin { + +class CConfigIPC_Channel +{ +public: + ::std::string m_name; + ::std::string m_argument; +}; + +class CConfigIPC +{ +public: + CConfigIPC(); +}; + +}; // namespace AxWin + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/CConfigInput.hpp b/Usermode/Applications/axwin4_src/Server/include/CConfigInput.hpp new file mode 100644 index 0000000000000000000000000000000000000000..28553ca0df1e668189c557773d1764f6d0117767 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/CConfigInput.hpp @@ -0,0 +1,26 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CConfig.hpp + * - Configuration class + */ +#ifndef _CCONFIGINPUT_H_ +#define _CCONFIGINPUT_H_ + +#include <string> + +namespace AxWin { + +class CConfigInput +{ +public: + CConfigInput(); + + ::std::string mouse_device; +}; + +}; // namespace AxWin + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/CConfigVideo.hpp b/Usermode/Applications/axwin4_src/Server/include/CConfigVideo.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9a81fb706942f2b36b792cc2edc51eaaa3b0d0fd --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/CConfigVideo.hpp @@ -0,0 +1,22 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CConfigVideo.hpp + * - Configuration class + */ +#ifndef _CCONFIGVIDEO_H_ +#define _CCONFIGVIDEO_H_ + +namespace AxWin { + +class CConfigVideo +{ +public: + CConfigVideo(); +}; + +}; // namespace AxWin + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/CIPCChannel_AcessIPCPipe.hpp b/Usermode/Applications/axwin4_src/Server/include/CIPCChannel_AcessIPCPipe.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c4ec004206fa7922b5832f5457f098a5aa3e2781 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/CIPCChannel_AcessIPCPipe.hpp @@ -0,0 +1,48 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CIPCChannel_AcessIPCPipe.hpp + * - IPC Channel :: Acess' IPC Pipe /Devices/ipcpipe/<name> + */ +#ifndef _CIPCCHANNEL_ACESSIPCPIPE_HPP_ +#define _CIPCCHANNEL_ACESSIPCPIPE_HPP_ + +#include <IIPCChannel.hpp> +#include <CClient.hpp> +#include <string> +#include <list> + +namespace AxWin { + +class CClient_AcessIPCPipe: + public CClient +{ + friend class CIPCChannel_AcessIPCPipe; + int m_fd; +public: + CClient_AcessIPCPipe(IIPCChannel& channel, int fd); + ~CClient_AcessIPCPipe(); + + void SendMessage(CSerialiser& message); + + void HandleReceive(); +}; + +class CIPCChannel_AcessIPCPipe: + public IIPCChannel +{ + int m_fd; + ::std::list<CClient_AcessIPCPipe> m_clients; +public: + CIPCChannel_AcessIPCPipe(const ::std::string& suffix); + virtual ~CIPCChannel_AcessIPCPipe(); + + virtual int FillSelect(fd_set& rfds); + virtual void HandleSelect(const fd_set& rfds); +}; + +} // namespace AxWin + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/CRect.hpp b/Usermode/Applications/axwin4_src/Server/include/CRect.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3c344b259f796e62aaf27dd992fc5cb6a3f5832b --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/CRect.hpp @@ -0,0 +1,40 @@ +/* + */ +#ifndef _CRECT_H_ +#define _CRECT_H_ + +namespace AxWin { + +class CRect +{ +public: + CRect(): + CRect(0,0,0,0) + { + }; + CRect(int X, int Y, unsigned int W, unsigned int H); + + void Translate(int DX, int DY) { + m_x += DX; m_x2 += DX; + m_y += DY; m_y2 += DY; + } + void Move(int NewX, int NewY); + void Resize(int NewW, int NewH); + + bool HasIntersection(const CRect& other) const; + CRect Intersection(const CRect& other) const; + + CRect RelativeIntersection(const CRect& area); + + int m_x; + int m_y; + int m_w; + int m_h; + int m_x2; + int m_y2; +}; + +}; // namespace AxWin + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/CSurface.hpp b/Usermode/Applications/axwin4_src/Server/include/CSurface.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ac20d0f57019b3c0c9a4232601bc3e171446c4a8 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/CSurface.hpp @@ -0,0 +1,35 @@ +/* + */ +#ifndef _CSURFACE_H_ +#define _CSURFACE_H_ + +#include <cstdint> +#include "CRect.hpp" + +namespace AxWin { + +class CSurface +{ +public: + CSurface(int x, int y, unsigned int w, unsigned int h); + ~CSurface(); + + uint64_t GetSHMHandle(); + + void Resize(unsigned int new_w, unsigned int new_h); + + void DrawScanline(unsigned int row, unsigned int x_ofs, unsigned int w, const void* data); + void BlendScanline(unsigned int row, unsigned int x_ofs, unsigned int w, const void* data); + void FillScanline(unsigned int row, unsigned int x, unsigned int w, uint32_t colour); + const uint32_t* GetScanline(unsigned int row, unsigned int x_ofs) const; + + CRect m_rect; + uint32_t* m_data; +private: + int m_fd; +}; + +}; // namespace AxWin + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/CWindow.hpp b/Usermode/Applications/axwin4_src/Server/include/CWindow.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e9026593098b65d063c1e36935936f8070fb7696 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/CWindow.hpp @@ -0,0 +1,62 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * CWindow.hpp + * - Window class + */ +#ifndef _CWINDOW_HPP_ +#define _CWINDOW_HPP_ + +#include <string> +#include <vector> +#include <cstdint> +#include "CRect.hpp" +#include "CSurface.hpp" + +namespace AxWin { + +class CClient; +class CCompositor; +class CRegion; + +class CWindow +{ +public: + CWindow(CCompositor& compositor, CClient& client, const ::std::string &name, unsigned int id); + ~CWindow(); + + const CClient& client() const { return m_client; } + const unsigned int id() const { return m_id; } + + void Repaint(const CRect& rect); + + void Show(bool bShow); + void Move(int X, int Y); + void Resize(unsigned int W, unsigned int H); + void SetFlags(uint32_t Flags); + + uint64_t ShareSurface(); + + void MouseButton(int ButtonID, int X, int Y, bool Down); + void MouseMove(int NewX, int NewY); + void KeyEvent(::uint32_t Scancode, const ::std::string &Translated, bool Down); + + void DrawScanline(unsigned int row, unsigned int x, unsigned int w, const uint8_t *data); + void FillScanline(unsigned int row, unsigned int x, unsigned int w, const uint32_t colour); + + bool m_is_shown; + CSurface m_surface; +private: + CCompositor& m_compositor; + CClient& m_client; + unsigned int m_id; + const ::std::string m_name; + ::std::vector<CRegion*> m_regions; +}; + +}; // namespace AxWin + +#endif + + diff --git a/Usermode/Applications/axwin4_src/Server/include/IFontFace.hpp b/Usermode/Applications/axwin4_src/Server/include/IFontFace.hpp new file mode 100644 index 0000000000000000000000000000000000000000..76ba042259edd2c20de4401281560c31458c5e7d --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/IFontFace.hpp @@ -0,0 +1,27 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * IFont.hpp + * - Text drawing (font rendering) primitive + */ +#ifndef _IFONT_HPP_ +#define _IFONT_HPP_ + +#include <string> +#include "CRect.hpp" +#include "CSurface.hpp" + +namespace AxWin { + +class IFontFace +{ +public: + virtual CRect Size(const ::std::string& text, unsigned int Size) const = 0; + virtual void Render(CSurface& dest, const CRect& rect, const ::std::string& text, unsigned int Size) = 0; +}; + +}; + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/IIPCChannel.hpp b/Usermode/Applications/axwin4_src/Server/include/IIPCChannel.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5dc88e2f91158f0adecec285d8bd4f02d04b51d9 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/IIPCChannel.hpp @@ -0,0 +1,30 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * IIPCChannel.hpp + * - IPC Channel interface + */ +#ifndef _IIPCCHANNEL_H_ +#define _IIPCCHANNEL_H_ + +extern "C" { +#include <acess/sys.h> +} + +namespace AxWin { + +class IIPCChannel +{ +public: + virtual ~IIPCChannel(); + + virtual int FillSelect(::fd_set& rfds) = 0; + virtual void HandleSelect(const ::fd_set& rfds) = 0; +}; + + +}; + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/IRegion.hpp b/Usermode/Applications/axwin4_src/Server/include/IRegion.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8208aa573aa3700174ef790d9a51355c461eeed3 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/IRegion.hpp @@ -0,0 +1,32 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * IRegion.hpp + * - Representation of a primitive region in a window (part of the window render list) + */ +#ifndef _IREGION_HPP_ +#define _IREGION_HPP_ + +#include <string> +#include <vector> +#include "CRect.hpp" + +namespace AxWin { + +class IRegion +{ +protected: + CWindow& m_parentWindow; +public: + virtual IRegion(CWindow& parent, const ::AxWin::Rect& position); + virtual ~IRegion(); + + virtual void Redraw(const ::AxWin::Rect& area) = 0; + virtual bool SetAttr(unsigned int Index, const IPCAttrib& Value) = 0; +}; + +}; + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/IVideo.hpp b/Usermode/Applications/axwin4_src/Server/include/IVideo.hpp new file mode 100644 index 0000000000000000000000000000000000000000..aa4fc52bfa1f5abcc160b7731d2bdc295535829a --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/IVideo.hpp @@ -0,0 +1,28 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * IVideo.hpp + * - Graphics backend abstraction + */ +#ifndef _IVIDEO_HPP_ +#define _IVIDEO_HPP_ + +namespace AxWin { + +class IVideo +{ +public: + virtual ~IVideo(); + + // Allocate a new hardware surface + IHWSurface& AllocateHWSurface(uint16_t Width, uint16_t Height); + + // Request redraw of backbuffer + void Flip(); +}; + +}; + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/IWindow.hpp b/Usermode/Applications/axwin4_src/Server/include/IWindow.hpp new file mode 100644 index 0000000000000000000000000000000000000000..83dd97f81b7c18d649f0f51fb458dea8c2c0deb9 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/IWindow.hpp @@ -0,0 +1,36 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * IWindow.hpp + * - Window abstract base class + */ +#ifndef _IWINDOW_HPP_ +#define _IWINDOW_HPP_ + +#include <string> +#include <vector> +#include <cstdint> +#include "CRect.hpp" + +namespace AxWin { + +class IWindow +{ +public: + IWindow(const ::std::string &name); + virtual ~IWindow(); + + virtual void Repaint() = 0; + + virtual void MouseButton(int ButtonID, int X, int Y, bool Down); + virtual void MouseMove(int NewX, int NewY); + virtual void KeyEvent(::uint32_t Scancode, const ::std::string &Translated, bool Down); +protected: + const ::std::string m_name; +}; + +} // namespace AxWin + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/common.hpp b/Usermode/Applications/axwin4_src/Server/include/common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1a1facc3bceedecdd9b8abfc6ca03e7be57324c0 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/common.hpp @@ -0,0 +1,26 @@ +/* + */ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include <exception> + +namespace AxWin { + +class InitFailure: + public ::std::exception +{ + const char *m_what; +public: + InitFailure(const char *reason): + m_what(reason) + { + } + + virtual const char* what() const throw(); +}; + +} // namespace AxWin + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/compositor.hpp b/Usermode/Applications/axwin4_src/Server/include/compositor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..403d943c23e99712dbc9d3ab1dcb66c04e3790f0 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/compositor.hpp @@ -0,0 +1,22 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * compositor.hpp + * - Compositor Interface Header + */ +#ifndef _COMPOSITOR_H_ +#define _COMPOSITOR_H_ + +namespace AxWin { + +class CCompositor; + +namespace Compositor { + +}; // namespace Compositor + +}; // namespace AxWin + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/draw_control.hpp b/Usermode/Applications/axwin4_src/Server/include/draw_control.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3797e2e98068d6fe3f983ba76701e3730a03f251 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/draw_control.hpp @@ -0,0 +1,37 @@ +/* + */ +#ifndef _DRAW_CONTROL_HPP_ +#define _DRAW_CONTROL_HPP_ + +#include <vector> +#include <string> +#include <cstdint> +#include <CSurface.hpp> + +namespace AxWin { + +class CControl +{ + unsigned int m_edge_x; + unsigned int m_edge_y; + unsigned int m_fill_x; + unsigned int m_fill_y; + unsigned int m_inner_x; + unsigned int m_inner_y; + ::std::vector<uint32_t> m_data; +public: + CControl(int EdgeX, int FillX, int InnerX, int EdgeY, int FillY, int InnerY, ::std::vector<uint32_t>&& data); + void Render(CSurface& dest, const CRect& rect) const; + + static const CControl* GetByName(const ::std::string& name); + static const CControl* GetByID(uint16_t id); + +private: + void renderLine(CSurface& dest, int y, ::std::vector<uint32_t>& scanline, const CRect& rect, const uint32_t* ctrl_line) const; +}; + + +} + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/draw_text.hpp b/Usermode/Applications/axwin4_src/Server/include/draw_text.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4bf28a61dd56c0182f03ed6ebddf77fd289f4878 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/draw_text.hpp @@ -0,0 +1,47 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * draw_text.hpp + * - Text drawing classes + */ +#ifndef _DRAW_TEXT_HPP_ +#define _DRAW_TEXT_HPP_ + +#include "IFontFace.hpp" + +namespace AxWin { + +class CFontFallback: + public IFontFace +{ +public: + CFontFallback(); + + CRect Size(const ::std::string& text, unsigned int Size) const override; + void Render(CSurface& dest, const CRect& rect, const ::std::string& text, unsigned int Size) override; +private: + void renderAtRes(CSurface& dest, const CRect& rect, uint32_t cp, unsigned int Size, uint32_t FGC); + static uint8_t getValueAtPt(const uint8_t* char_ptr, unsigned int xf16, unsigned int yf16); + static uint8_t getValueAtRaw(const uint8_t* char_ptr, unsigned int x, unsigned int y); + unsigned int unicodeToCharmap(uint32_t cp) const; +}; + +#if FREETYPE_ENABLED +class CFontFT: + public IFontFace +{ + FT_Face m_face; +public: + CFontFT(const char *Filename); + ~CFontFT(); + + CRect Size(const ::std::string& text, unsigned int Size) const override; + void Render(CSurface& dest, const CRect& rect, const ::std::string& text, unsigned int Size) override; +}; +#endif // FREETYPE_ENABLED + +} + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/input.hpp b/Usermode/Applications/axwin4_src/Server/include/input.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f8b27cea1c6ccbff3be5c700b6d12a97e0d40628 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/input.hpp @@ -0,0 +1,35 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * input.hpp + * - Input Interface Header + */ +#ifndef _INPUT_H_ +#define _INPUT_H_ + +#include <acess/sys.h> + +namespace AxWin { + +class CCompositor; + +class CInput +{ + CCompositor& m_compositor; + int m_keyboardFD; + int m_mouseFD; + + unsigned int m_mouseX; + unsigned int m_mouseY; + unsigned int m_mouseBtns; +public: + CInput(const CConfigInput& config, CCompositor& compositor); + int FillSelect(::fd_set& rfds); + void HandleSelect(::fd_set& rfds); +}; + +}; // namespace AxWin + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/ipc.hpp b/Usermode/Applications/axwin4_src/Server/include/ipc.hpp new file mode 100644 index 0000000000000000000000000000000000000000..50b0dbe25e3041f129980679d83739cd578c03bb --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/ipc.hpp @@ -0,0 +1,55 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * ipc.hpp + * - IPC Interface Header + */ +#ifndef _IPC_H_ +#define _IPC_H_ + +#include <exception> + +extern "C" { +#include <acess/sys.h> +}; + +#include <serialisation.hpp> +#include <CConfigIPC.hpp> + +namespace AxWin { + +class CCompositor; +class CClient; + +namespace IPC { + +extern void Initialise(const CConfigIPC& config, CCompositor& compositor); +extern int FillSelect(::fd_set& rfds); +extern void HandleSelect(const ::fd_set& rfds); +extern void RegisterClient(CClient& client); +extern CClient* GetClientByID(uint16_t id); +extern void DeregisterClient(CClient& client); + +extern void SendMessage_NotifyDims(CClient& client, unsigned int WinID, unsigned int NewW, unsigned int NewH); +extern void SendMessage_MouseButton(CClient& client, unsigned int WinID, unsigned int X, unsigned int Y, uint8_t Button, bool Pressed); +extern void SendMessage_MouseMove(CClient& client, unsigned int WinID, unsigned int X, unsigned int Y); +extern void SendMessage_KeyEvent(CClient& client, unsigned int WinID, uint32_t KeySym, bool Pressed, const char *Translated); + +extern void HandleMessage(CClient& client, CDeserialiser& message); + +class CClientFailure: + public ::std::exception +{ + const std::string m_what; +public: + CClientFailure(std::string&& what); + ~CClientFailure() throw(); + const char *what() const throw(); +}; + +}; // namespace IPC +}; // namespace AxWin + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/timing.hpp b/Usermode/Applications/axwin4_src/Server/include/timing.hpp new file mode 100644 index 0000000000000000000000000000000000000000..df5d814c5be9846c1ee218902b64f4d9e195e9de --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/timing.hpp @@ -0,0 +1,23 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * timing.hpp + * - Timing Interface Header + */ +#ifndef _TIMING_H_ +#define _TIMING_H_ + +#include <cstdint> + +namespace AxWin { +namespace Timing { + +extern ::int64_t GetTimeToNextEvent(); +extern void CheckEvents(); + +}; // namespace Timing +}; // namespace AxWin + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/include/video.hpp b/Usermode/Applications/axwin4_src/Server/include/video.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3738099b4e6e1d8a636b8951dc45d136c86af2ee --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/include/video.hpp @@ -0,0 +1,41 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * video.hpp + * - Graphics Interface Header + */ +#ifndef _VIDEO_H_ +#define _VIDEO_H_ + +#include <cstdint> +#include "CConfigVideo.hpp" + +namespace AxWin { + +class CVideo +{ + int m_fd; + unsigned int m_width; + unsigned int m_height; + int m_bufferFormat; +public: + CVideo(const CConfigVideo& config); + + void GetDims(unsigned int& w, unsigned int& h); + unsigned int width() const { return m_width; } + unsigned int height() const { return m_height; } + + void BlitLine(const uint32_t* src, unsigned int dst_y, unsigned int dst_x, unsigned int width); + void Flush(); + void SetCursorPos(int X, int Y); + +private: + void SetBufFormat(unsigned int FormatID); + void SetCursorBitmap(); +}; + +}; + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/input.cpp b/Usermode/Applications/axwin4_src/Server/input.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a0ab64663b197446e9216a2b92f25d7be5b9dccb --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/input.cpp @@ -0,0 +1,154 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * input.cpp + * - Input + */ +#include <CConfigInput.hpp> +#include <input.hpp> +#include <CCompositor.hpp> +#include <algorithm> +#include <acess/devices/joystick.h> +#include <cerrno> +#include <system_error> + +namespace AxWin { + +CInput::CInput(const ::AxWin::CConfigInput& config, CCompositor& compositor): + m_compositor(compositor), + m_keyboardFD(0), + m_mouseFD(-1) +{ + m_mouseFD = _SysOpen(config.mouse_device.c_str(), OPENFLAG_READ|OPENFLAG_WRITE); + if( m_mouseFD == -1 ) + throw ::std::system_error(errno, ::std::system_category()); + + m_mouseX = 640/2; + m_mouseY = 480/2; + + struct mouse_attribute attr; + // X : Limit + Position + attr.Num = 0; + attr.Value = 640; + _SysIOCtl(m_mouseFD, JOY_IOCTL_GETSETAXISLIMIT, &attr); + attr.Value = m_mouseX; + _SysIOCtl(m_mouseFD, JOY_IOCTL_GETSETAXISPOSITION, &attr); + // Y: Limit + Position + attr.Num = 1; + attr.Value = 480; + _SysIOCtl(m_mouseFD, JOY_IOCTL_GETSETAXISLIMIT, &attr); + attr.Value = m_mouseY; + _SysIOCtl(m_mouseFD, JOY_IOCTL_GETSETAXISPOSITION, &attr); +} + +int CInput::FillSelect(::fd_set& rfds) +{ + FD_SET(m_keyboardFD, &rfds); + if( m_mouseFD != -1 ) + FD_SET(m_mouseFD, &rfds); + return ::std::max(m_keyboardFD, m_mouseFD)+1; +} + +void CInput::HandleSelect(::fd_set& rfds) +{ + if( FD_ISSET(m_keyboardFD, &rfds) ) + { + uint32_t codepoint; + static uint32_t scancode; + #define KEY_CODEPOINT_MASK 0x3FFFFFFF + + size_t readlen = _SysRead(m_keyboardFD, &codepoint, sizeof(codepoint)); + if( readlen != sizeof(codepoint) ) + { + // oops, error + _SysDebug("Terminal read failed? (%i != %i)", readlen, sizeof(codepoint)); + } + +// _SysDebug("Keypress 0x%x", codepoint); + + switch(codepoint & 0xC0000000) + { + case 0x00000000: // Key pressed + m_compositor.KeyState(0, scancode, true, codepoint & KEY_CODEPOINT_MASK); + break; + case 0x40000000: // Key release + m_compositor.KeyState(0, scancode, false, codepoint & KEY_CODEPOINT_MASK); + scancode = 0; + break; + case 0x80000000: // Key refire + m_compositor.KeyState(0, scancode, true, codepoint & KEY_CODEPOINT_MASK); + scancode = 0; + break; + case 0xC0000000: // Raw scancode + scancode = codepoint & KEY_CODEPOINT_MASK; + break; + } + } + + if( m_mouseFD != -1 && FD_ISSET(m_mouseFD, &rfds) ) + { + const int c_n_axies = 4; + const int c_n_buttons = 5; + struct mouse_axis *axies; + uint8_t *buttons; + + char data[sizeof(struct mouse_header) + sizeof(*axies)*c_n_axies + c_n_buttons]; + struct mouse_header *mouseinfo = (struct mouse_header*)data; + + _SysSeek(m_mouseFD, 0, SEEK_SET); + int len = _SysRead(m_mouseFD, data, sizeof(data)); + if( len < 0 ) + throw ::std::system_error(errno, ::std::system_category()); + + len -= sizeof(*mouseinfo); + if( len < 0 ) { + _SysDebug("Mouse data undersized (%i bytes short on header)", len); + return ; + } + if( mouseinfo->NAxies > c_n_axies || mouseinfo->NButtons > c_n_buttons ) { + _SysDebug("%i axies, %i buttons above prealloc counts (%i, %i)", + mouseinfo->NAxies, mouseinfo->NButtons, c_n_axies, c_n_buttons + ); + return ; + } + if( len < sizeof(*axies)*mouseinfo->NAxies + mouseinfo->NButtons ) { + _SysDebug("Mouse data undersized (body doesn't fit %i < %i)", + len, sizeof(*axies)*mouseinfo->NAxies + mouseinfo->NButtons + ); + return ; + } + + // What? No X/Y? + if( mouseinfo->NAxies < 2 ) { + _SysDebug("Mouse data lacks X/Y"); + return ; + } + + axies = (struct mouse_axis*)( mouseinfo + 1 ); + buttons = (uint8_t*)( axies + mouseinfo->NAxies ); + + // TODO: Use cursor range only to caputre motion (ignore reported position) + m_compositor.MouseMove(0, + m_mouseX, m_mouseY, + axies[0].CursorPos - m_mouseX, axies[1].CursorPos - m_mouseY + ); + m_mouseX = axies[0].CursorPos; + m_mouseY = axies[1].CursorPos; + + for( int i = 0; i < mouseinfo->NButtons; i ++ ) + { + int bit = 1 << i; + int cur = buttons[i] > 128; + if( !!(m_mouseBtns & bit) != cur ) + { + m_compositor.MouseButton(0, m_mouseX, m_mouseY, (eMouseButton)i, cur); + // Flip button state + m_mouseBtns ^= bit; + } + } + } +} + +}; // namespace AxWin + diff --git a/Usermode/Applications/axwin4_src/Server/ipc.cpp b/Usermode/Applications/axwin4_src/Server/ipc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f522ac22767ea79b4d3b9808d1e924f65a528459 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/ipc.cpp @@ -0,0 +1,514 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * ipc.cpp + * - Client-Server communication (dispatch) + */ +#define __STDC_LIMIT_MACROS +#include <ipc.hpp> +#include <list> +#include <IIPCChannel.hpp> +#include <algorithm> +#include <CClient.hpp> +#include <serialisation.hpp> +#include <ipc_proto.hpp> +#include <CCompositor.hpp> +extern "C" { +#include <assert.h> +}; +#include <CIPCChannel_AcessIPCPipe.hpp> +#include <draw_control.hpp> +#include <draw_text.hpp> + +namespace AxWin { +namespace IPC { + +CCompositor* gpCompositor; +::std::list<IIPCChannel*> glChannels; +::std::map<uint16_t,CClient*> glClients; +uint16_t giNextClient = 1; + +void Initialise(const CConfigIPC& config, CCompositor& compositor) +{ + gpCompositor = &compositor; + + ::std::string pipe_basepath = "axwin4"; + glChannels.push_back( new CIPCChannel_AcessIPCPipe( pipe_basepath ) ); + + //glChannels.push_back( new CIPCChannel_TCP("0.0.0.0:2100") ); + + //for( auto channel : config.m_channels ) + //{ + // channels.push_back( ); + //} +} + +int FillSelect(fd_set& rfds) +{ + int ret = 0; + for( const auto channel : glChannels ) + { + assert(channel); + ret = ::std::max(ret, channel->FillSelect(rfds)); + } + return ret; +} + +void HandleSelect(const fd_set& rfds) +{ + for( const auto channel : glChannels ) + { + assert(channel); + channel->HandleSelect(rfds); + } +} + +void RegisterClient(CClient& client) +{ + _SysDebug("RegisterClient(&client=%p)", &client); + // allocate a client ID, and save + for( int i = 0; i < 100; i ++ ) + { + uint16_t id = giNextClient++; + if(giNextClient == 0) giNextClient = 1; + auto r = glClients.insert( ::std::pair<uint16_t,CClient*>(id, &client) ); + if( r.second == true ) + { + client.set_id(id); + return; + } + } + // Wut? 100 attempts and fail! + assert(!"Todo - Better way of handling client ID reuse"); +} + +CClient* GetClientByID(uint16_t id) +{ + auto it = glClients.find(id); + if(it == glClients.end()) { + //_SysDebug("Client %i not registered", id); + return nullptr; + } + else { + //_SysDebug("Client %i %i = %p", id, it->first, it->second); + return it->second; + } +} + +void DeregisterClient(CClient& client) +{ + glClients.erase( client.id() ); +} + + +void SendMessage_NotifyDims(CClient& client, unsigned int WinID, unsigned int NewW, unsigned int NewH) +{ + _SysDebug("TODO: IPC::SendMessage_NotifyDims"); +} +void SendMessage_MouseButton(CClient& client, unsigned int WinID, unsigned int X, unsigned int Y, uint8_t Button, bool Pressed) +{ + CSerialiser msg; + msg.WriteU8(IPCMSG_INPUTEVENT); + msg.WriteU8(IPC_INEV_MOUSEBTN); + msg.WriteU16(WinID); + msg.WriteU16(X); + msg.WriteU16(Y); + msg.WriteU8(Button); + msg.WriteU8(Pressed ? 0 : 1); + client.SendMessage(msg); +} +void SendMessage_MouseMove(CClient& client, unsigned int WinID, unsigned int X, unsigned int Y) +{ + _SysDebug("TODO: IPC::SendMessage_MouseMove"); +} +void SendMessage_KeyEvent(CClient& client, unsigned int WinID, uint32_t KeySym, bool Pressed, const char *Translated) +{ + CSerialiser msg; + msg.WriteU8(IPCMSG_INPUTEVENT); + msg.WriteU8(IPC_INEV_KEYBOARD); + msg.WriteU16(WinID); + msg.WriteU16(KeySym); + msg.WriteU8(Pressed ? 0 : 1); + msg.WriteString(Translated); + client.SendMessage(msg); +} + + +void HandleMessage_Nop(CClient& client, CDeserialiser& message) +{ + // Do nothing +} +void HandleMessage_Reply(CClient& client, CDeserialiser& message) +{ + // Reply to a sent message + // - Not many messages need server-bound replies + int orig_command = message.ReadU8(); + switch(orig_command) + { + case IPCMSG_PING: + // Ping reply, mark client as still responding + break; + default: + // Unexpected reply + break; + } +} + +void HandleMessage_Ping(CClient& client, CDeserialiser& message) +{ + // A client has asked for a ping, we pong them back + CSerialiser reply; + reply.WriteU8(IPCMSG_REPLY); + reply.WriteU8(IPCMSG_PING); + client.SendMessage(reply); +} + +void HandleMessage_GetGlobalAttr(CClient& client, CDeserialiser& message) +{ + uint16_t attr_id = message.ReadU16(); + + CSerialiser reply; + reply.WriteU8(IPCMSG_REPLY); + reply.WriteU8(IPCMSG_GETGLOBAL); + reply.WriteU16(attr_id); + + switch(attr_id) + { + case IPC_GLOBATTR_SCREENDIMS: { + uint8_t screen_id = message.ReadU8(); + unsigned int w, h; + gpCompositor->GetScreenDims(screen_id, &w, &h); + reply.WriteU16( (w <= UINT16_MAX ? w : UINT16_MAX) ); + reply.WriteU16( (h <= UINT16_MAX ? h : UINT16_MAX) ); + break; } + case IPC_GLOBATTR_MAXAREA: + assert(!"TODO: IPC_GLOBATTR_MAXAREA"); + break; + default: + throw IPC::CClientFailure("Bad global attribute ID"); + } + + client.SendMessage(reply); +} + +void HandleMessage_SetGlobalAttr(CClient& client, CDeserialiser& message) +{ + uint16_t attr_id = message.ReadU16(); + + switch(attr_id) + { + case IPC_GLOBATTR_SCREENDIMS: + // Setting readonly + break; + case IPC_GLOBATTR_MAXAREA: + assert(!"TODO: IPC_GLOBATTR_MAXAREA"); + break; + default: + throw IPC::CClientFailure("Bad global attribute ID"); + } +} + +void HandleMessage_CreateWindow(CClient& client, CDeserialiser& message) +{ + uint16_t new_id = message.ReadU16(); + //uint16_t parent_id = message.ReadU16(); + //CWindow* parent = client.GetWindow( parent_id ); + ::std::string name = message.ReadString(); + + ::_SysDebug("_CreateWindow: (%i, '%s')", new_id, name.c_str()); + client.SetWindow( new_id, new CWindow(*gpCompositor, client, name, new_id) ); +} + +void HandleMessage_DestroyWindow(CClient& client, CDeserialiser& message) +{ + uint16_t win_id = message.ReadU16(); + _SysDebug("_DestroyWindow: (%i)", win_id); + + CWindow* win = client.GetWindow(win_id); + if(!win) { + throw IPC::CClientFailure("_DestroyWindow: Bad window"); + } + client.SetWindow(win_id, 0); + + // TODO: Directly inform compositor? + delete win; +} + +void HandleMessage_SetWindowAttr(CClient& client, CDeserialiser& message) +{ + uint16_t win_id = message.ReadU16(); + uint16_t attr_id = message.ReadU16(); + _SysDebug("_SetWindowAttr: (Win=%i, ID=%i)", win_id, attr_id); + + CWindow* win = client.GetWindow(win_id); + if(!win) { + throw IPC::CClientFailure("_SetWindowAttr - Bad window"); + } + + switch(attr_id) + { + case IPC_WINATTR_DIMENSIONS: { + uint16_t new_w = message.ReadU16(); + uint16_t new_h = message.ReadU16(); + win->Resize(new_w, new_h); + break; } + case IPC_WINATTR_POSITION: { + int16_t new_x = message.ReadS16(); + int16_t new_y = message.ReadS16(); + win->Move(new_x, new_y); + break; } + case IPC_WINATTR_SHOW: + win->Show( message.ReadU8() != 0 ); + break; + case IPC_WINATTR_FLAGS: + win->SetFlags( message.ReadU8() ); // TODO: U8? why so small? + break; + case IPC_WINATTR_TITLE: + assert(!"TODO: IPC_WINATTR_TITLE"); + break; + default: + _SysDebug("HandleMessage_SetWindowAttr - Bad attr %u", attr_id); + throw IPC::CClientFailure("Bad window attr"); + } +} + +void HandleMessage_GetWindowAttr(CClient& client, CDeserialiser& message) +{ + assert(!"TODO HandleMessage_GetWindowAttr"); +} + +void HandleMessage_SendIPC(CClient& client, CDeserialiser& message) +{ + assert(!"TODO HandleMessage_SendIPC"); +} + +void HandleMessage_GetWindowBuffer(CClient& client, CDeserialiser& message) +{ + uint16_t win_id = message.ReadU16(); + _SysDebug("_GetWindowBuffer: (%i)", win_id); + + CWindow* win = client.GetWindow(win_id); + if(!win) { + throw IPC::CClientFailure("_PushData: Bad window"); + } + + uint64_t handle = win->m_surface.GetSHMHandle(); + + CSerialiser reply; + reply.WriteU8(IPCMSG_REPLY); + reply.WriteU8(IPCMSG_GETWINBUF); + reply.WriteU16(win_id); + reply.WriteU64(handle); + client.SendMessage(reply); +} + +void HandleMessage_DamageRect(CClient& client, CDeserialiser& message) +{ + uint16_t winid = message.ReadU16(); + uint16_t x = message.ReadU16(); + uint16_t y = message.ReadU16(); + uint16_t w = message.ReadU16(); + uint16_t h = message.ReadU16(); + + _SysDebug("_DamageRect: (%i %i,%i %ix%i)", winid, x, y, w, h); + + CWindow* win = client.GetWindow(winid); + if(!win) { + throw IPC::CClientFailure("_PushData: Bad window"); + } + + CRect area(x,y,w,h); + + win->Repaint(area); +} + +void HandleMessage_PushData(CClient& client, CDeserialiser& message) +{ + uint16_t win_id = message.ReadU16(); + uint16_t x = message.ReadU16(); + uint16_t y = message.ReadU16(); + uint16_t w = message.ReadU16(); + uint16_t h = message.ReadU16(); + _SysDebug("_PushData: (%i, (%i,%i) %ix%i)", win_id, x, y, w, h); + + CWindow* win = client.GetWindow(win_id); + if(!win) { + throw IPC::CClientFailure("_PushData: Bad window"); + } + + for( unsigned int row = 0; row < h; row ++ ) + { + const ::std::vector<uint8_t> scanline_data = message.ReadBuffer(); + if( scanline_data.size() != w * 4 ) { + _SysDebug("ERROR _PushData: Scanline buffer size mismatch (%i,%i)", + scanline_data.size(), w*4); + continue ; + } + win->DrawScanline(y+row, x, w, scanline_data.data()); + } +} +void HandleMessage_Blit(CClient& client, CDeserialiser& message) +{ + assert(!"TODO HandleMessage_Blit"); +} +void HandleMessage_DrawCtl(CClient& client, CDeserialiser& message) +{ + uint16_t win_id = message.ReadU16(); + uint16_t x = message.ReadU16(); + uint16_t y = message.ReadU16(); + uint16_t w = message.ReadU16(); + uint16_t h = message.ReadU16(); + uint16_t ctrl_id = message.ReadU16(); + uint16_t frame = message.ReadU16(); + _SysDebug("_DrawCtl: (%i, (%i,%i) %ix%i Ctl%i frame?=0x%04x)", win_id, x, y, w, h, ctrl_id, frame); + + CWindow* win = client.GetWindow(win_id); + if(!win) { + throw IPC::CClientFailure("_DrawCtl: Bad window"); + } + + const CControl* ctrl = CControl::GetByID(ctrl_id); + if(!ctrl) { + throw IPC::CClientFailure("_DrawCtl: Invalid control ID"); + } + + CRect area(x,y,w,h); + ctrl->Render(win->m_surface, area); +} +void HandleMessage_DrawText(CClient& client, CDeserialiser& message) +{ + uint16_t win_id = message.ReadU16(); + uint16_t x = message.ReadU16(); + uint16_t y = message.ReadU16(); + uint16_t w = message.ReadU16(); + uint16_t h = message.ReadU16(); + uint16_t font_id = message.ReadU16(); + ::std::string str = message.ReadString(); + _SysDebug("_DrawText: (%i (%i,%i) %ix%i Font%i \"%s\")", win_id, x, y, w, h, font_id, str.c_str()); + + CWindow* win = client.GetWindow(win_id); + if(!win) { + throw IPC::CClientFailure("_DrawText: Bad window"); + } + + // 1. Get font from client structure + IFontFace& fontface = client.GetFont(font_id); + + // 2. Render + CRect area(x, y, w, h); + fontface.Render(win->m_surface, area, str, h); +} + +void HandleMessage_FillRect(CClient& client, CDeserialiser& message) +{ + uint16_t win_id = message.ReadU16(); + uint16_t x = message.ReadU16(); + uint16_t y = message.ReadU16(); + uint16_t w = message.ReadU16(); + uint16_t h = message.ReadU16(); + uint32_t colour = message.ReadU32(); + _SysDebug("_FillRect: (%i (%i,%i) %ix%i %06x)", win_id, x, y, w, h, colour); + + CWindow* win = client.GetWindow(win_id); + if(!win) { + throw IPC::CClientFailure("_FillRect: Bad window"); + } + + while(h -- ) { + win->FillScanline(y++, x, w, colour); + } +} + +void HandleMessage_DrawRect(CClient& client, CDeserialiser& message) +{ + uint16_t win_id = message.ReadU16(); + uint16_t x = message.ReadU16(); + uint16_t y = message.ReadU16(); + uint16_t w = message.ReadU16(); + uint16_t h = message.ReadU16(); + uint32_t colour = message.ReadU32(); + _SysDebug("_DrawRect: (%i (%i,%i) %ix%i %06x)", win_id, x, y, w, h, colour); + + CWindow* win = client.GetWindow(win_id); + if(!win) { + throw IPC::CClientFailure("_DrawRect: Bad window"); + } + + if(h == 0) { + } + else if(h == 1) { + win->FillScanline(y, x, w, colour); + } + else if(h == 2) { + win->FillScanline(y++, x, w, colour); + win->FillScanline(y++, x, w, colour); + } + else { + win->FillScanline(y++, x, w, colour); + while( h -- > 2 ) { + win->FillScanline(y, x, 1, colour); + win->FillScanline(y, x+w-1, 1, colour); + y ++; + } + win->FillScanline(y++, x, w, colour); + } +} + +typedef void MessageHandler_op_t(CClient& client, CDeserialiser& message); + +MessageHandler_op_t *message_handlers[] = { + [IPCMSG_NULL] = &HandleMessage_Nop, + [IPCMSG_REPLY] = &HandleMessage_Reply, + [IPCMSG_PING] = &HandleMessage_Ping, + [IPCMSG_GETGLOBAL] = &HandleMessage_GetGlobalAttr, + [IPCMSG_SETGLOBAL] = &HandleMessage_SetGlobalAttr, + + [IPCMSG_CREATEWIN] = &HandleMessage_CreateWindow, + [IPCMSG_CLOSEWIN] = &HandleMessage_DestroyWindow, + [IPCMSG_SETWINATTR] = &HandleMessage_SetWindowAttr, + [IPCMSG_GETWINATTR] = &HandleMessage_GetWindowAttr, + [IPCMSG_SENDIPC] = &HandleMessage_SendIPC, // Use the GUI server for low-bandwith IPC + [IPCMSG_GETWINBUF] = &HandleMessage_GetWindowBuffer, + [IPCMSG_DAMAGERECT] = &HandleMessage_DamageRect, + [IPCMSG_PUSHDATA] = &HandleMessage_PushData, // to a window's buffer + [IPCMSG_BLIT] = &HandleMessage_Blit, // Copy data from one part of the window to another + [IPCMSG_DRAWCTL] = &HandleMessage_DrawCtl, // Draw a control + [IPCMSG_DRAWTEXT] = &HandleMessage_DrawText, // Draw text + [IPCMSG_FILLRECT] = &HandleMessage_FillRect, // Fill a rectangle + [IPCMSG_DRAWRECT] = &HandleMessage_DrawRect, // Draw (outline) a rectangle +}; + +void HandleMessage(CClient& client, CDeserialiser& message) +{ + const unsigned int num_commands = sizeof(message_handlers)/sizeof(IPC::MessageHandler_op_t*); + unsigned int command = message.ReadU8(); + if( command >= num_commands ) { + // Drop, invalid command + _SysDebug("HandleMessage: Command %u is invalid (out of range for %u)", command, num_commands); + return ; + } + + (message_handlers[command])(client, message); +} + +CClientFailure::CClientFailure(std::string&& what): + m_what(what) +{ +} +const char *CClientFailure::what() const throw() +{ + return m_what.c_str(); +} +CClientFailure::~CClientFailure() throw() +{ +} + +}; // namespace IPC + +IIPCChannel::~IIPCChannel() +{ +} + +}; // namespace AxWin + diff --git a/Usermode/Applications/axwin4_src/Server/main.cpp b/Usermode/Applications/axwin4_src/Server/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b64da4e324ea86a0ca3daf7051d4d7e4af2611e --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/main.cpp @@ -0,0 +1,152 @@ +/* + * Acess2 GUI v4 (AxWin4) + * - By John Hodge (thePowesGang) + * + * main.cpp + * - Program main + */ +#include <CConfig.hpp> +#include <ipc.hpp> +#include <input.hpp> +#include <video.hpp> +#include <CCompositor.hpp> +#include <timing.hpp> +#include <exception> +#include <algorithm> +#include <common.hpp> + +#include <system_error> +#include <cerrno> + +extern "C" { +#include <stdio.h> +#include <stdint.h> +}; + +using namespace AxWin; + +// === CODE === +int main(int argc, char *argv[]) +{ + // - Load configuration (from file and argv) + CConfig config; + try { + config.parseCommandline(argc, argv); + } + catch(const std::exception& e) { + fprintf(stderr, "Exception: %s\n", e.what()); + _SysDebug("Config threw exception: %s", e.what()); + return 1; + } + + CVideo* vid = 0; + CCompositor* compositor = 0; + CInput* input = 0; + + try { + // - Open graphics + vid = new CVideo(config.m_video); + ::_SysDebug("vid = %p", vid); + // - Initialise compositor structures + compositor = new CCompositor(/*config.m_compositor,*/ *vid); + ::_SysDebug("compositor = %p", compositor); + // - Open input + input = new CInput(config.m_input, *compositor); + ::_SysDebug("input = %p", input); + // > Handles hotkeys? + // - Bind IPC channels + IPC::Initialise(config.m_ipc, *compositor); + ::_SysDebug("IPC up"); + // - Start root child process (from config) + // TODO: Spin up child process + + { + const char *interface_app = "/Acess/Apps/AxWin/4.0/AxWinUI"; + const char *argv[] = {interface_app, NULL}; + int rv = _SysSpawn(interface_app, argv, NULL, 0, NULL, NULL); + if( rv < 0 ) { + _SysDebug("_SysSpawn chucked a sad, rv=%i, errno=%i", rv, _errno); + throw ::std::system_error(errno, ::std::system_category()); + } + } + } + catch(const ::std::exception& e) { + fprintf(stderr, "Startup threw exception: %s\n", e.what()); + _SysDebug("Startup threw exception: %s", e.what()); + delete input; + delete compositor; + delete vid; + return 1; + } + + // - Event loop + for( ;; ) + { + int nfd = 0; + fd_set rfds, efds; + + FD_ZERO(&rfds); + FD_ZERO(&efds); + + nfd = ::std::max(nfd, input->FillSelect(rfds)); + nfd = ::std::max(nfd, IPC::FillSelect(rfds)); + + for( int i = 0; i < nfd; i ++ ) + if( FD_ISSET(i, &rfds) ) + FD_SET(i, &efds); + + #if 0 + for( int i = 0; i < nfd; i ++ ) { + if( FD_ISSET(i, &rfds) ) { + _SysDebug("FD%i", i); + } + } + #endif + + // TODO: Support _SysSendMessage IPC? + int64_t timeout = Timing::GetTimeToNextEvent(); + int64_t *timeoutp; + if( timeout >= 0 ) { + ::_SysDebug("Calling select with timeout %lli", timeout); + timeoutp = &timeout; + } + else { + //::_SysDebug("Calling select with no timeout"); + timeoutp = 0; + } + int rv = ::_SysSelect(nfd, &rfds, NULL, NULL/*&efds*/, timeoutp, 0); + + #if 0 + for( int i = 0; i < nfd; i ++ ) { + if( FD_ISSET(i, &rfds) ) { + _SysDebug("FD%i", i); + } + } + #endif + //_SysDebug("rv=%i, timeout=%lli", rv, timeout); + + try { + Timing::CheckEvents(); + + input->HandleSelect(rfds); + IPC::HandleSelect(rfds); + + compositor->Redraw(); + } + catch(...) { + ::_SysDebug("Exception during select handling"); + } + } + return 0; +} + +namespace AxWin { + +const char* InitFailure::what() const throw() +{ + return m_what; +} + + +} + diff --git a/Usermode/Applications/axwin4_src/Server/resources/cursor.h b/Usermode/Applications/axwin4_src/Server/resources/cursor.h new file mode 100644 index 0000000000000000000000000000000000000000..be2d77b34480a75e981b1fe74d914dfdcbd2f2d0 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/resources/cursor.h @@ -0,0 +1,34 @@ +/* + */ +#ifndef _RESORUCE_CURSOR_H +#define _RESORUCE_CURSOR_H + +#include <stdint.h> + +static struct { + uint16_t W, H; + uint32_t Data[8*16]; +} __attribute__((packed)) cCursorBitmap = { + 8, 16, + { + 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFF000000, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, + 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000, + 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, + 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, + 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000, + 0xFF000000, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000, + 0xFF000000, 0xFF000000, 0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, + 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 + } +}; + +#endif + diff --git a/Usermode/Applications/axwin4_src/Server/resources/font_8x16.h b/Usermode/Applications/axwin4_src/Server/resources/font_8x16.h new file mode 100644 index 0000000000000000000000000000000000000000..b9bad5db2f427350fcf0ce46651d47e5e6770099 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/resources/font_8x16.h @@ -0,0 +1,265 @@ +/* + * Taken from http://cvs.savannah.gnu.org/viewvc/vgabios/vgafonts.h?root=vgabios&view=markup + * Altered for Acess2 + */ +#define FONT_WIDTH 8 +#define FONT_HEIGHT 16 +static uint8_t VTermFont[256*16]= +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, + 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; diff --git a/Usermode/Applications/axwin4_src/Server/timing.cpp b/Usermode/Applications/axwin4_src/Server/timing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e61c8e2c589fc330126245e1b0ffcebfbb70721b --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/timing.cpp @@ -0,0 +1,25 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * timing.cpp + * - Timing code + */ +#include <timing.hpp> + +namespace AxWin { +namespace Timing { + +int64_t GetTimeToNextEvent() +{ + return -1; +} + +void CheckEvents() +{ + +} + +}; // namespace Timing +}; // namespace AxWin + diff --git a/Usermode/Applications/axwin4_src/Server/video.cpp b/Usermode/Applications/axwin4_src/Server/video.cpp new file mode 100644 index 0000000000000000000000000000000000000000..50686c61be17f5e1d7b22b31a5ea8206c1b2ddf8 --- /dev/null +++ b/Usermode/Applications/axwin4_src/Server/video.cpp @@ -0,0 +1,120 @@ +/* + * Acess2 GUI v4 + * - By John Hodge (thePowersGang) + * + * video.cpp + * - Graphics output + */ +#include <cstddef> +#include <video.hpp> +#include <common.hpp> + +extern "C" { +#include <acess/sys.h> +#include <acess/devices/pty.h> +#include <acess/devices/pty_cmds.h> +#include "resources/cursor.h" +} + +namespace AxWin { + +CVideo::CVideo(const CConfigVideo& config): + m_fd(1), + m_width(0), + m_height(0), + m_bufferFormat(PTYBUFFMT_TEXT) +{ + // Obtain dimensions + { + if( _SysIOCtl(m_fd, DRV_IOCTL_TYPE, NULL) != DRV_TYPE_TERMINAL ) + throw AxWin::InitFailure("stdin isn't a terminal"); + struct ptydims dims; + if( _SysIOCtl(m_fd, PTY_IOCTL_GETDIMS, &dims) == -1 ) + throw AxWin::InitFailure("Failed to get dimensions from stdin"); + m_width = dims.PW; + m_height = dims.PH; + if( m_width == 0 || m_height == 0 ) + throw AxWin::InitFailure("Terminal not capable of graphics"); + } + + _SysDebug("m_width=%i, m_height=%i", m_width, m_height); + SetCursorBitmap(); + + SetCursorPos( m_width/2, m_height/2 ); + + SetBufFormat(PTYBUFFMT_FB); + uint32_t data[m_width]; + for( unsigned int i = 0; i < m_height; i ++ ) + BlitLine(data, i, 0, m_width); +} + +void CVideo::GetDims(unsigned int& w, unsigned int& h) +{ + w = m_width; + h = m_height; +} + +void CVideo::BlitLine(const uint32_t* src, unsigned int dst_y, unsigned int dst_x, unsigned int width) +{ + //_SysDebug("CVideo::BlitLine (%p, %i, %i, %i)", src, dst_y, dst_x, width); + //_SysDebugHex("CVideo::BlitLine", src, width*4); + size_t cmdlen = (sizeof(struct ptycmd_senddata) + width*4)/4; + //_SysDebug(" - Offset = %i, cmdlen = %i", (dst_y * m_width + dst_x) * 4, cmdlen); + struct ptycmd_senddata cmd = { + {PTY2D_CMD_SEND, uint8_t(cmdlen & 0xFF), uint16_t(cmdlen>>8)}, + (dst_y * m_width + dst_x) + }; + SetBufFormat(PTYBUFFMT_2DCMD); + _SysWrite(m_fd, &cmd, sizeof(cmd)); + _SysWrite(m_fd, src, width*4); +} + +void CVideo::Flush() +{ + // TODO: Write to a local copy of the framebuffer in BlitLine, and then flush out in this function +} + +void CVideo::SetBufFormat(unsigned int FormatID) +{ + if( m_bufferFormat != FormatID ) + { + + struct ptymode mode = {.OutputMode = FormatID, .InputMode = 0}; + int rv = _SysIOCtl( m_fd, PTY_IOCTL_SETMODE, &mode ); + if( rv ) { + throw ::AxWin::InitFailure("Can't set PTY to framebuffer mode"); + } + + m_bufferFormat = FormatID; + } +} + +void CVideo::SetCursorBitmap() +{ + // Set cursor position and bitmap + struct ptycmd_header hdr = {PTY2D_CMD_SETCURSORBMP,0,0}; + size_t size = sizeof(hdr) + sizeof(cCursorBitmap) + cCursorBitmap.W*cCursorBitmap.H*4; + hdr.len_low = size / 4; + hdr.len_hi = size / (256*4); + + SetBufFormat(PTYBUFFMT_2DCMD); + _SysWrite(m_fd, &hdr, sizeof(hdr)); + _SysDebug("SetCursorBitmap - size = %i (%04x:%02x * 4)", size, hdr.len_hi, hdr.len_low); + _SysWrite(m_fd, &cCursorBitmap, size-sizeof(hdr)); +} + +void CVideo::SetCursorPos(int X, int Y) +{ + struct ptycmd_setcursorpos cmd; + cmd.hdr.cmd = PTY2D_CMD_SETCURSORPOS; + cmd.hdr.len_low = sizeof(cmd)/4; + cmd.hdr.len_hi = 0; + cmd.x = X; + cmd.y = Y; + + SetBufFormat(PTYBUFFMT_2DCMD); + _SysWrite(m_fd, &cmd, sizeof(cmd)); +} + +}; // namespace AxWin + diff --git a/Usermode/Applications/axwin4_src/UI/Makefile b/Usermode/Applications/axwin4_src/UI/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f225d5f735b25ef03e2441b5d0547a0df360ed63 --- /dev/null +++ b/Usermode/Applications/axwin4_src/UI/Makefile @@ -0,0 +1,12 @@ + +include ../../Makefile.cfg + +DIR := Apps/AxWin/4.0 + +OBJ := main.o taskbar.o + +BIN := AxWinUI + +LIBS += -laxwin4 + +include ../../Makefile.tpl diff --git a/Usermode/Applications/axwin4_src/UI/include/common.h b/Usermode/Applications/axwin4_src/UI/include/common.h new file mode 100644 index 0000000000000000000000000000000000000000..f51cca647d24ab83de7d3230251ef008f57b8024 --- /dev/null +++ b/Usermode/Applications/axwin4_src/UI/include/common.h @@ -0,0 +1,10 @@ +/* + */ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +extern unsigned int giScreenWidth; +extern unsigned int giScreenHeight; + +#endif + diff --git a/Usermode/Applications/axwin4_src/UI/include/taskbar.h b/Usermode/Applications/axwin4_src/UI/include/taskbar.h new file mode 100644 index 0000000000000000000000000000000000000000..728ceceefae57d56571a1e856d3309bbf9b324f7 --- /dev/null +++ b/Usermode/Applications/axwin4_src/UI/include/taskbar.h @@ -0,0 +1,12 @@ +/* + */ +#ifndef _TASKBAR_H_ +#define _TASKBAR_H_ + +#include <stdbool.h> + +extern void Taskbar_Create(void); +extern void Taskbar_Redraw(void); + +#endif + diff --git a/Usermode/Applications/axwin4_src/UI/main.c b/Usermode/Applications/axwin4_src/UI/main.c new file mode 100644 index 0000000000000000000000000000000000000000..624e381a716726b6d0bd1747b1fcd8162970914f --- /dev/null +++ b/Usermode/Applications/axwin4_src/UI/main.c @@ -0,0 +1,69 @@ +/* + * AxWin4 GUI - UI Core + * - By John Hodge (thePowersGang) + * + * main.c + * - Program core + */ +#include <axwin4/axwin.h> +#include <assert.h> +#include "include/common.h" +#include "include/taskbar.h" + +// === PROTOTYPES === +tAxWin4_Window *CreateBGWin(int w, int h); + +// === GLOABLS === +unsigned int giScreenWidth = 640; +unsigned int giScreenHeight = 480; + +// === CODE === +int main(int argc, const char *argv[]) +{ + assert( AxWin4_Connect("ipcpipe:///Devices/ipcpipe/axwin4") ); + + AxWin4_GetScreenDimensions(0, &giScreenWidth, &giScreenHeight); + + tAxWin4_Window *bgwin = CreateBGWin(giScreenWidth, giScreenHeight); + Taskbar_Create(); + + _SysDebug("Beginning queue"); + while( AxWin4_WaitEventQueue(0) ) + ; + _SysDebug("Clean exit"); + + return 0; +} + +tAxWin4_Window *CreateBGWin(int w, int h) +{ + tAxWin4_Window *bgwin = AxWin4_CreateWindow("background"); + AxWin4_MoveWindow(bgwin, 0,0); + AxWin4_ResizeWindow(bgwin, w,h); + AxWin4_SetWindowFlags(bgwin, AXWIN4_WNDFLAG_NODECORATE|AXWIN4_WNDFLAG_KEEPBELOW); + + // Load background image + uint32_t *buf = AxWin4_GetWindowBuffer(bgwin); + if( buf ) + { + for( size_t y = 0; y < h; y ++ ) + { + for(size_t x = 0; x < w; x ++ ) + { + uint8_t r = y * 256 / h; + uint8_t g = 0; + uint8_t b = x * 256 / w; + buf[y*w+x] = (r << 16) | (g << 8) | b; + } + } + } + else + { + AxWin4_FillRect(bgwin, 0, 0, w, h, 0x8888CC); + } + //AxWin4_DamageRect(bgwin, 0, 0, w, h); + AxWin4_ShowWindow(bgwin, true); + + return bgwin; +} + diff --git a/Usermode/Applications/axwin4_src/UI/taskbar.c b/Usermode/Applications/axwin4_src/UI/taskbar.c new file mode 100644 index 0000000000000000000000000000000000000000..b62a0420555fa8e62436820d5ef64515c0e8929b --- /dev/null +++ b/Usermode/Applications/axwin4_src/UI/taskbar.c @@ -0,0 +1,92 @@ +/* + * AxWin4 GUI - UI Core + * - By John Hodge (thePowersGang) + * + * taskbar.c + * - Main toolbar (aka Taskbar) + */ +#include <axwin4/axwin.h> +#include "include/common.h" +#include "include/taskbar.h" +#include <time.h> + +// === CONSTANTS === +#define TASKBAR_HEIGHT 30 +#define TASKBAR_BORDER 3 // Border between window edge and controls +#define TASKBAR_SYSBTN_SIZE (TASKBAR_HEIGHT-TASKBAR_BORDER*2) +#define TASKBAR_WIN_MAXSIZE 100 +#define TASKBAR_WIN_MINSIZE 24 +#define TASKBAR_CLOCKSIZE 60 + +// === TYPES === +typedef struct sTaskbar_Win tTaskbar_Win; +struct sTaskbar_Win +{ + tTaskbar_Win *Next; + const char *Title; +}; + +// === PROTOTYPES === + +// === GLOBALS === +tAxWin4_Window *gpTaskbar_Window; +unsigned int giTaskbar_NumWins = 0; +tTaskbar_Win *gpTaskbar_FirstWin; + +// === CODE === +void Taskbar_Create(void) +{ + gpTaskbar_Window = AxWin4_CreateWindow("taskbar"); + tAxWin4_Window * const win = gpTaskbar_Window; + + AxWin4_MoveWindow(win, 0, 0); + AxWin4_ResizeWindow(win, giScreenWidth, TASKBAR_HEIGHT); + + AxWin4_SetWindowFlags(win, AXWIN4_WNDFLAG_NODECORATE); + Taskbar_Redraw(); + AxWin4_ShowWindow(win, true); +} + +void Taskbar_Redraw(void) +{ + const int w = giScreenWidth; + const int h = TASKBAR_HEIGHT; + + const int active_height = h - TASKBAR_BORDER*2; + const int winlist_start_x = TASKBAR_BORDER+TASKBAR_SYSBTN_SIZE+TASKBAR_BORDER; + const int clock_start_x = w - (TASKBAR_BORDER+TASKBAR_CLOCKSIZE); + + // Window background: Toolbar skin + AxWin4_DrawControl(gpTaskbar_Window, 0, 0, w, h, AXWIN4_CTL_TOOLBAR, 0); + + // System button + // TODO: Use an image instead + AxWin4_DrawControl(gpTaskbar_Window, TASKBAR_BORDER, TASKBAR_BORDER, TASKBAR_SYSBTN_SIZE, active_height, AXWIN4_CTL_BUTTON, 0); + + // Windows + // TODO: Maintain/request a list of windows + if( giTaskbar_NumWins ) + { + int winbutton_size = (clock_start_x - winlist_start_x) / giTaskbar_NumWins; + if(winbutton_size > TASKBAR_WIN_MAXSIZE) winbutton_size = TASKBAR_WIN_MAXSIZE; + int x = winlist_start_x; + for(tTaskbar_Win *win = gpTaskbar_FirstWin; win; win = win->Next ) + { + AxWin4_DrawControl(gpTaskbar_Window, x, TASKBAR_BORDER, winbutton_size, active_height, AXWIN4_CTL_BUTTON, 0); + } + } + + // Clock + { + char timestr[5]; + time_t rawtime; + time(&rawtime); + strftime(timestr, 5, "%H%M", localtime(&rawtime)); + //AxWin4_DrawControl(gpTaskbar_Window, clock_start_x, TASKBAR_BORDER, TASKBAR_CLOCKSIZE, active_height, AXWIN4_CTL_BOX); + + AxWin4_DrawText(gpTaskbar_Window, clock_start_x, TASKBAR_BORDER, TASKBAR_CLOCKSIZE, active_height, 0, timestr); + } + + AxWin4_DamageRect(gpTaskbar_Window, 0, 0, w, h); +} + diff --git a/Usermode/Applications/gui_ate_src/Makefile b/Usermode/Applications/gui_ate_src/Makefile index fe1b2148ccd6bb46abd4a48c35cd659847727270..25e256ef0682ea71e08e314fac179df699b1e674 100644 --- a/Usermode/Applications/gui_ate_src/Makefile +++ b/Usermode/Applications/gui_ate_src/Makefile @@ -2,7 +2,7 @@ -include ../Makefile.cfg -LDFLAGS += -laxwin3 +LIBS += -laxwin3 OBJ = main.o strings.o toolbar.o BIN = ate diff --git a/Usermode/Applications/gui_terminal_src/Makefile b/Usermode/Applications/gui_terminal_src/Makefile index a38f1355efcad0c9dd3d670779731a954d055a97..be6450093f972f93203c7716a574591987c47cd0 100644 --- a/Usermode/Applications/gui_terminal_src/Makefile +++ b/Usermode/Applications/gui_terminal_src/Makefile @@ -2,7 +2,7 @@ -include ../Makefile.cfg -LDFLAGS += -laxwin3 -lunicode +LIBS += -laxwin3 -lunicode OBJ = main.o vt100.o display.o BIN = terminal diff --git a/Usermode/Applications/gui_terminal_src/vt100.c b/Usermode/Applications/gui_terminal_src/vt100.c index 0f00bd994e4b9802a42d80b697c26e3a04d4a4d8..6a2321ea7e91f88168ef81e50e333434229f7297 100644 --- a/Usermode/Applications/gui_terminal_src/vt100.c +++ b/Usermode/Applications/gui_terminal_src/vt100.c @@ -17,6 +17,8 @@ # include <assert.h> # include <stdlib.h> // malloc/free +# define ASSERTC(a, r, b) assert(a r b) + static inline int MIN(int a, int b) { return a < b ? a : b; @@ -170,7 +172,7 @@ int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf) if( ret <= old_inc_len ) { _SysDebug("Term_HandleVT100: ret(%i) <= old_inc_len(%i), inc_len=%i, '%*C'", ret, old_inc_len, st->cache_len, st->cache_len, st->cache); - assert(ret > old_inc_len); + ASSERTC(ret, >, old_inc_len); } st->cache_len = 0; //_SysDebug("%i bytes of escape code '%.*s' (return %i)", @@ -186,6 +188,10 @@ int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf) switch( *Buf ) { + case '\a': + // Alarm, aka bell + //Display_SoundBell(Term); + break; case '\b': // backspace is aprarently just supposed to cursor left (if possible) Display_MoveCursor(Term, 0, -1); @@ -442,9 +448,13 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) Display_MoveCursor(Term, 0, -(args[0] != 0 ? args[0] : 1)); break; case 'H': - if( argc != 2 ) { + if( argc == 0 ) { + Display_SetCursor(Term, 0, 0); } - else { + else if( argc == 1 ) { + Display_SetCursor(Term, args[0]-1, 0); + } + else if( argc == 2 ) { // Adjust 1-based cursor position to 0-based Display_SetCursor(Term, args[0]-1, args[1]-1); } @@ -483,12 +493,12 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) break; } break; - case 'S': // Scroll text up n=1 - Display_ScrollDown(Term, (argc >= 1 ? args[0] : 1)); - break; - case 'T': // Scroll text down n=1 + case 'S': // Scroll text up n=1 (expose bottom) Display_ScrollDown(Term, -(argc >= 1 ? args[0] : 1)); break; + case 'T': // Scroll text down n=1 (expose top) + Display_ScrollDown(Term, (argc >= 1 ? args[0] : 1)); + break; case 'c': // Send Device Attributes switch(args[0]) { @@ -529,6 +539,40 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) // Reset Display_ResetAttributes(Term); } + else if( args[0] == 48 ) + { + // ISO-8613-3 Background + if( args[1] == 2 ) { + uint32_t col = 0; + col |= (uint32_t)args[2] << 16; + col |= (uint32_t)args[3] << 8; + col |= (uint32_t)args[4] << 0; + Display_SetBackground(Term, col); + } + else if( args[1] == 5 ) { + _SysDebug("TODO: Support xterm palette BG %i", args[2]); + } + else { + _SysDebug("VT100 Unknown mode set \e[48;%im", args[1]); + } + } + else if( args[0] == 38 ) + { + // ISO-8613-3 Foreground + if( args[1] == 2 ) { + uint32_t col = 0; + col |= (uint32_t)args[2] << 16; + col |= (uint32_t)args[3] << 8; + col |= (uint32_t)args[4] << 0; + Display_SetForeground(Term, col); + } + else if( args[1] == 5 ) { + _SysDebug("TODO: Support xterm palette FG %i", args[2]); + } + else { + _SysDebug("VT100 Unknown mode set \e[38;%im", args[1]); + } + } else { for( int i = 0; i < argc; i ++ ) @@ -549,6 +593,9 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) case 4: _SysDebug("TODO: \\e[4m - Underscore"); break; + //case 5: + // _SysDebug("TODO: \\e[5m - Blink/bold"); + // break; case 7: _SysDebug("TODO: \\e[7m - Reverse"); break; @@ -570,6 +617,14 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) st->CurBG = 0; Display_SetBackground( Term, caVT100Colours[ st->CurBG ] ); break; + case 90 ... 97: + st->CurFG = args[i]-90 + 8; + Display_SetForeground( Term, caVT100Colours[ st->CurBG ] ); + break;; + case 100 ... 107: + st->CurBG = args[i]-100 + 8; + Display_SetBackground( Term, caVT100Colours[ st->CurBG ] ); + break;; default: _SysDebug("Unknown mode set \\e[%im", args[i]); break; @@ -582,7 +637,7 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) break; // Set scrolling region case 'r': - Display_SetScrollArea(Term, args[0], (args[1] - args[0])); + Display_SetScrollArea(Term, args[0]-1, (args[1] - args[0])+1); break; case 's': diff --git a/Usermode/Applications/init_src/main.c b/Usermode/Applications/init_src/main.c index 11833a07f85bb47e4a23bfb191210ccb36acc3cf..73411b9345be1ca5362278ae834212ad07d87831 100644 --- a/Usermode/Applications/init_src/main.c +++ b/Usermode/Applications/init_src/main.c @@ -7,6 +7,7 @@ #include <string.h> #include "common.h" #include <ctype.h> +#include <inttypes.h> // === CONSTANTS === #define DEFAULT_SHELL "/Acess/SBin/login" @@ -452,6 +453,8 @@ int SpawnKTerm(tInitProgram *Program) int in = _SysOpen(path, OPENFLAG_READ); int out = _SysOpen(path, OPENFLAG_WRITE); + _SysDebug("Spawning virtual terminal '%s' with term '%s'", + path, Program->Command[0]); return SpawnCommand(in, out, out, Program->Command, env); } @@ -475,6 +478,8 @@ int SpawnSTerm(tInitProgram *Program) _SysIOCtl(in, SERIAL_IOCTL_GETSETFORMAT, &Program->TypeInfo.STerm.FormatBits); #endif + _SysDebug("Spawning serial terminal '%s' with term '%s'", + Program->TypeInfo.STerm.Path, Program->Command[0]); return SpawnCommand(in, out, out, Program->Command, NULL); } @@ -495,17 +500,15 @@ int SpawnDaemon(tInitProgram *Program) // Log spawn header { char buffer[101]; - size_t len = snprintf(buffer, 100, "[%lli] init spawning ", _SysTimestamp()); + size_t len = snprintf(buffer, 100, "[%"PRIi64"] init spawning ", _SysTimestamp()); _SysWrite(out, buffer, len); - char ch = '\''; for( int i = 0; Program->Command[i]; i ++ ) { - _SysWrite(out, &ch, 1); + _SysWrite(out, "'", 1); _SysWrite(out, Program->Command[i], strlen(Program->Command[i])); - _SysWrite(out, &ch, 1); + _SysWrite(out, "'", 1); } - ch = '\n'; - _SysWrite(out, &ch, 1); + _SysWrite(out, "\n", 1); } return SpawnCommand(in, out, err, Program->Command, NULL); diff --git a/Usermode/Applications/ip_src/Makefile b/Usermode/Applications/ip_src/Makefile index 1c976b500c44e8c5e2701176ccd7037eee41c834..e3ff4e9bd9c7d55f3bceefcfdf7e41f560ddb219 100644 --- a/Usermode/Applications/ip_src/Makefile +++ b/Usermode/Applications/ip_src/Makefile @@ -2,7 +2,8 @@ -include ../Makefile.cfg -LDFLAGS += -lnet +LDFLAGS += +LIBS += -lnet OBJ = main.o addr.o routes.o BIN = ip diff --git a/Usermode/Applications/irc_src/Makefile b/Usermode/Applications/irc_src/Makefile index 9fab060040e8f0ac3851af7e6ae3fc576be284d5..78d803e308ecf05fb401c4ecfca582fefd9bdcf4 100644 --- a/Usermode/Applications/irc_src/Makefile +++ b/Usermode/Applications/irc_src/Makefile @@ -2,9 +2,10 @@ -include ../Makefile.cfg -LDFLAGS += -lnet -lreadline +LIBS += -lnet -lreadline -OBJ = main.o +OBJ = main.o server.o input.o +OBJ += window.o pseudo_curses.o BIN = irc -include ../Makefile.tpl diff --git a/Usermode/Applications/irc_src/common.h b/Usermode/Applications/irc_src/common.h new file mode 100644 index 0000000000000000000000000000000000000000..e374328bb0372c66ad026e235f5c263a4eb4db11 --- /dev/null +++ b/Usermode/Applications/irc_src/common.h @@ -0,0 +1,20 @@ +/* + */ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include "pseudo_curses.h" + +typedef struct sServer tServer; + +extern void _SysDebug(const char *format, ...); + +extern int writef(int FD, const char *Format, ...); +extern int OpenTCP(const char *AddressString, short PortNumber); +extern char *GetValue(char *Src, int *Ofs); + +extern void Redraw_Screen(void); +extern void Exit(const char *Reason) __attribute__((noreturn)); + +#endif + diff --git a/Usermode/Applications/irc_src/input.c b/Usermode/Applications/irc_src/input.c new file mode 100644 index 0000000000000000000000000000000000000000..b99935c05e6560b841884c68a3527c194e0362eb --- /dev/null +++ b/Usermode/Applications/irc_src/input.c @@ -0,0 +1,171 @@ +/* + */ +#include "input.h" +#include "window.h" +#include "server.h" +#include <readline.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +// === PROTOTYPES === +void Input_FillSelect(int *nfds, fd_set *rfds); +void Input_HandleSelect(int nfds, const fd_set *rfds); + int ParseUserCommand(char *String); + +// === GLOBALS === +tReadline *gpInput_ReadlineInfo; + +// === CODE === +void Input_FillSelect(int *nfds, fd_set *rfds) +{ + if( !gpInput_ReadlineInfo ) { + gpInput_ReadlineInfo = Readline_Init(1); + } + + FD_SET(0, rfds); + if(*nfds < 0+1) + *nfds = 0+1; +} + +void Input_HandleSelect(int nfds, const fd_set *rfds) +{ + // User input + if(FD_ISSET(0, rfds)) + { + char *cmd = Readline_NonBlock(gpInput_ReadlineInfo); + if( cmd ) + { + if( cmd[0] ) + { + ParseUserCommand(cmd); + } + free(cmd); + // Prompt + SetCursorPos(giTerminal_Height, 1); + printf("\x1B[2K"); // Clear line + int prompt_len = printf("[%s] ", Window_GetName(NULL)); + SetCursorPos(giTerminal_Height, prompt_len+1); + fflush(stdout); + } + } +} + +void Cmd_join(char *ArgString) +{ + int pos=0; + char *channel_name = GetValue(ArgString, &pos); + + tServer *srv = Window_GetServer(NULL); + + if( srv ) + { + Windows_SwitchTo( Window_Create(srv, channel_name) ); + Redraw_Screen(); + Server_SendCommand(srv, "JOIN :%s", channel_name); + } +} + +void Cmd_quit(char *ArgString) +{ + const char *quit_message = ArgString; + if( quit_message == NULL || quit_message[0] == '\0' ) + quit_message = "/quit - Acess2 IRC Client"; + + Servers_CloseAll(quit_message); + + Exit(NULL); // NULL = user requested +} + +void Cmd_window(char *ArgString) +{ + int pos = 0; + char *window_id = GetValue(ArgString, &pos); + int window_num = atoi(window_id); + + if( window_num > 0 ) + { + // Get `window_num`th window + tWindow *win = Windows_GetByIndex(window_num-1); + if( win ) + { + Windows_SwitchTo( win ); + } + else + { + // Otherwise, silently ignore + } + } + else + { + window_num = 1; + for( tWindow *win; (win = Windows_GetByIndex(window_num-1)); window_num ++ ) + { + Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, NULL, "%i: %s", window_num, Window_GetName(win)); + } + } +} + +void Cmd_me(char *ArgString) +{ + tServer *srv = Window_GetServer(NULL); + if( srv && Window_IsChat(NULL) ) { + Window_AppendMessage(NULL, MSG_CLASS_ACTION, Server_GetNick(srv), "%s", ArgString); + Server_SendCommand(srv, "PRIVMSG %s :\1ACTION %s\1\n", Window_GetName(NULL), ArgString); + } +} + +const struct { + const char *Name; + void (*Fcn)(char *ArgString); +} caCommands[] = { + {"join", Cmd_join}, + {"quit", Cmd_quit}, + {"window", Cmd_window}, + {"win", Cmd_window}, + {"w", Cmd_window}, +}; +const int ciNumCommands = sizeof(caCommands)/sizeof(caCommands[0]); + +/** + * \brief Handle a line from the prompt + */ +int ParseUserCommand(char *String) +{ + if( String[0] == '/' ) + { + char *command; + int pos = 0; + + command = GetValue(String, &pos)+1; + + // TODO: Prefix matches + int cmdIdx = -1; + for( int i = 0; i < ciNumCommands; i ++ ) + { + if( strcmp(command, caCommands[i].Name) == 0 ) { + cmdIdx = i; + break; + } + } + if( cmdIdx != -1 ) { + caCommands[cmdIdx].Fcn(String+pos); + } + else + { + Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, NULL, "Unknown command %s", command); + } + } + else + { + // Message + // - Only send if server is valid and window name is non-empty + tServer *srv = Window_GetServer(NULL); + if( srv && Window_IsChat(NULL) ) { + Window_AppendMessage(NULL, MSG_CLASS_MESSAGE, Server_GetNick(srv), "%s", String); + Server_SendCommand(srv, "PRIVMSG %s :%s\n", Window_GetName(NULL), String); + } + } + + return 0; +} diff --git a/Usermode/Applications/irc_src/input.h b/Usermode/Applications/irc_src/input.h new file mode 100644 index 0000000000000000000000000000000000000000..dee859ee71573736ebd869a07e8f4305e17183df --- /dev/null +++ b/Usermode/Applications/irc_src/input.h @@ -0,0 +1,12 @@ +/* + */ +#ifndef _INPUT_H_ +#define _INPUT_H_ + +#include <acess/sys.h> + +extern void Input_FillSelect(int *nfds, fd_set *rfds); +extern void Input_HandleSelect(int nfds, const fd_set *rfds); + +#endif + diff --git a/Usermode/Applications/irc_src/main.c b/Usermode/Applications/irc_src/main.c index 1ca53c2b5b2b39be8291771c76cc3d17f6d2b569..6169519c6e5ce92df6b833897032b0cc9a3a5c17 100755 --- a/Usermode/Applications/irc_src/main.c +++ b/Usermode/Applications/irc_src/main.c @@ -6,94 +6,47 @@ #include <stdio.h> #include <string.h> #include <net.h> -#include <readline.h> -#include <acess/devices/pty.h> #include <stdarg.h> +#include <acess/devices/pty.h> -// === TYPES === -typedef struct sServer { - struct sServer *Next; - int FD; - char InBuf[BUFSIZ+1]; - int ReadPos; - char Name[]; -} tServer; - -typedef struct sMessage -{ - struct sMessage *Next; - time_t Timestamp; - tServer *Server; - int Type; - char *Source; // Pointer into `Data` - char Data[]; -} tMessage; - -typedef struct sWindow -{ - struct sWindow *Next; - tMessage *Messages; - tServer *Server; //!< Canonical server (can be NULL) - int ActivityLevel; - char Name[]; // Channel name / remote user -} tWindow; +#include "common.h" +#include "input.h" +#include "window.h" +#include "server.h" -enum eMessageTypes -{ - MSG_TYPE_NULL, - MSG_TYPE_SERVER, // Server message - - MSG_TYPE_NOTICE, // NOTICE command - MSG_TYPE_JOIN, // JOIN command - MSG_TYPE_PART, // PART command - MSG_TYPE_QUIT, // QUIT command - - MSG_TYPE_STANDARD, // Standard line - MSG_TYPE_ACTION, // /me - - MSG_TYPE_UNK -}; +// === TYPES === // === PROTOTYPES === int main(int argc, const char *argv[], const char *envp[]); int MainLoop(void); int ParseArguments(int argc, const char *argv[]); - int ParseUserCommand(char *String); // --- -tServer *Server_Connect(const char *Name, const char *AddressString, short PortNumber); -tMessage *Message_AppendF(tServer *Server, int Type, const char *Source, const char *Dest, const char *Message, ...) __attribute__((format(__printf__,5,6))); -tMessage *Message_Append(tServer *Server, int Type, const char *Source, const char *Dest, const char *Message); -tWindow *Window_Create(tServer *Server, const char *Name); void Redraw_Screen(void); - - int ProcessIncoming(tServer *Server); // --- Helpers -void SetCursorPos(int Row, int Col); +void Exit(const char *Reason); int writef(int FD, const char *Format, ...); int OpenTCP(const char *AddressString, short PortNumber); char *GetValue(char *Str, int *Ofs); -static inline int isdigit(int ch); // === GLOBALS === -char *gsUsername = "user"; -char *gsHostname = "acess"; -char *gsRealName = "Acess2 IRC Client"; -char *gsNickname = "acess"; -tServer *gpServers; -tWindow gWindow_Status = { - NULL, NULL, NULL, // No next, empty list, no server - 0, {""} // No activity, empty name (rendered as status) -}; -tWindow *gpWindows = &gWindow_Status; -tWindow *gpCurrentWindow = &gWindow_Status; - int giTerminal_Width = 80; - int giTerminal_Height = 25; +const char *gsExitReason = "No reason [BUG]"; // ==== CODE ==== void ExitHandler(void) { printf("\x1B[?1047l"); - printf("Quit\n"); + printf("Quit: %s\n", gsExitReason); + + // stty +echo,canon + struct ptymode mode = {.InputMode = 0, .OutputMode = 0}; + mode.InputMode = PTYIMODE_CANON|PTYIMODE_ECHO; + _SysIOCtl(0, PTY_IOCTL_SETMODE, &mode); +} + +void Exit(const char *Reason) +{ + gsExitReason = (Reason ? Reason : "User Requested"); + exit( (Reason ? 1 : 0) ); } int main(int argc, const char *argv[], const char *envp[]) @@ -105,117 +58,61 @@ int main(int argc, const char *argv[], const char *envp[]) atexit(ExitHandler); - if( _SysIOCtl(1, DRV_IOCTL_TYPE, NULL) != DRV_TYPE_TERMINAL ) { - fprintf(stderr, "note: assuming 80x25, can't get terminal dimensions\n"); - giTerminal_Width = 80; - giTerminal_Height = 25; - } - else { - struct ptydims dims; - _SysIOCtl(1, PTY_IOCTL_GETDIMS, &dims); - giTerminal_Width = dims.W; - giTerminal_Height = dims.H; - } + ACurses_Init(); printf("\x1B[?1047h"); - printf("\x1B[%i;%ir", 0, giTerminal_Height-1); - - SetCursorPos(giTerminal_Height-1, 1); - printf("[(status)] "); + printf("\x1B[%i;%ir", 2, giTerminal_Height-2); // HACK: Static server entry // UCC (University [of Western Australia] Computer Club) IRC Server - gWindow_Status.Server = Server_Connect( "UCC", "130.95.13.18", 6667 ); +// tServer *starting_server = Server_Connect( "UCC", "130.95.13.18", 6667 ); // Freenode (#osdev) -// gWindow_Status.Server = Server_Connect( "Freenode", "89.16.176.16", 6667 ); + tServer *starting_server = Server_Connect( "Freenode", "84.240.3.129", 6667 ); // Local servers // gWindow_Status.Server = Server_Connect( "VMHost", "10.0.2.2", 6667 ); // gWindow_Status.Server = Server_Connect( "BitlBee", "192.168.1.39", 6667 ); - if( !gWindow_Status.Server ) - return -1; + Windows_SetStatusServer(starting_server); + Windows_RepaintCurrent(); + SetCursorPos(giTerminal_Height-1, 1); + printf("[(status)] "); MainLoop(); - - for( tServer *srv = gpServers; srv; srv = srv->Next ) - _SysClose(srv->FD); + + Servers_CloseAll("Client closing"); return 0; } int MainLoop(void) { - SetCursorPos(giTerminal_Height-1, 1); + SetCursorPos(giTerminal_Height, 1); printf("[(status)] "); fflush(stdout); - tReadline *readline_info = Readline_Init(1); + // stty -echo,canon + struct ptymode mode = {.InputMode = 0, .OutputMode = 0}; + _SysIOCtl(0, PTY_IOCTL_SETMODE, &mode); for( ;; ) { fd_set readfds, errorfds; - int maxFD = 0; + int nfds = 1; FD_ZERO(&readfds); FD_ZERO(&errorfds); - FD_SET(0, &readfds); // stdin - - fflush(stdout); - // Fill server FDs in fd_set - for( tServer *srv = gpServers; srv; srv = srv->Next ) - { - FD_SET(srv->FD, &readfds); - FD_SET(srv->FD, &errorfds); - if( srv->FD > maxFD ) - maxFD = srv->FD; - } + Input_FillSelect(&nfds, &readfds); + Servers_FillSelect(&nfds, &readfds, &errorfds); - int rv = _SysSelect(maxFD+1, &readfds, 0, &errorfds, NULL, 0); - if( rv == -1 ) break; + int rv = _SysSelect(nfds, &readfds, 0, &errorfds, NULL, 0); + if( rv < 0 ) break; - if(FD_ISSET(0, &readfds)) - { - // User input - char *cmd = Readline_NonBlock(readline_info); - if( cmd ) - { - if( cmd[0] ) - { - ParseUserCommand(cmd); - } - free(cmd); - // Prompt - SetCursorPos(giTerminal_Height-1, 1); - printf("\x1B[2K"); // Clear line - if( gpCurrentWindow->Name[0] ) - printf("[%s:%s] ", - gpCurrentWindow->Server->Name, gpCurrentWindow->Name); - else - printf("[(status)] "); - } - } + // user input + Input_HandleSelect(nfds, &readfds); // Server response - for( tServer *srv = gpServers; srv; srv = srv->Next ) - { - if(FD_ISSET(srv->FD, &readfds)) - { - if( ProcessIncoming(srv) != 0 ) { - // Oops, error - _SysDebug("ProcessIncoming failed on FD%i (Server %p %s)", - srv->FD, srv, srv->Name); - return 1; - } - } - - if(FD_ISSET(srv->FD, &errorfds)) - { - _SysDebug("Error on FD%i (Server %p %s)", - srv->FD, srv, srv->Name); - return 1; - } - } + Servers_HandleSelect(nfds, &readfds, &errorfds); } return 0; } @@ -228,547 +125,12 @@ int ParseArguments(int argc, const char *argv[]) return 0; } - -void Cmd_join(char *ArgString) -{ - int pos=0; - char *channel_name = GetValue(ArgString, &pos); - - if( gpCurrentWindow->Server ) - { - gpCurrentWindow = Window_Create(gpCurrentWindow->Server, channel_name); - Redraw_Screen(); - writef(gpCurrentWindow->Server->FD, "JOIN :%s\n", channel_name); - } -} - -void Cmd_quit(char *ArgString) -{ - const char *quit_message = ArgString; - if( quit_message == NULL || quit_message[0] == '\0' ) - quit_message = "/quit - Acess2 IRC Client"; - - for( tServer *srv = gpServers; srv; srv = srv->Next ) - { - writef(srv->FD, "QUIT :%s\n", quit_message); - } - - exit(0); -} - -void Cmd_window(char *ArgString) -{ - int pos = 0; - char *window_id = GetValue(ArgString, &pos); - int window_num = atoi(window_id); - - if( window_num > 0 ) - { - tWindow *win; - window_num --; // Move to base 0 - // Get `window_num`th window - for( win = gpWindows; win && window_num--; win = win->Next ); - if( win ) { - gpCurrentWindow = win; - Redraw_Screen(); - } - // Otherwise, silently ignore - } - else - { - window_num = 1; - for( tWindow *win = gpWindows; win; win = win->Next, window_num ++ ) - { - if( win->Name[0] ) { - Message_AppendF(NULL, MSG_TYPE_SERVER, "client", "", - "%i: %s/%s", window_num, win->Server->Name, win->Name); - } - else { - Message_AppendF(NULL, MSG_TYPE_SERVER, "client", "", - "%i: (status)", window_num); - } - } - } -} - -const struct { - const char *Name; - void (*Fcn)(char *ArgString); -} caCommands[] = { - {"join", Cmd_join}, - {"quit", Cmd_quit}, - {"window", Cmd_window}, - {"win", Cmd_window}, - {"w", Cmd_window}, -}; -const int ciNumCommands = sizeof(caCommands)/sizeof(caCommands[0]); - -/** - * \brief Handle a line from the prompt - */ -int ParseUserCommand(char *String) -{ - if( String[0] == '/' ) - { - char *command; - int pos = 0; - - command = GetValue(String, &pos)+1; - - // TODO: Prefix matches - int cmdIdx = -1; - for( int i = 0; i < ciNumCommands; i ++ ) - { - if( strcmp(command, caCommands[i].Name) == 0 ) { - cmdIdx = i; - break; - } - } - if( cmdIdx != -1 ) { - caCommands[cmdIdx].Fcn(String+pos); - } - else - { - Message_AppendF(NULL, MSG_TYPE_SERVER, "client", "", "Unknown command %s", command); - } - } - else - { - // Message - // - Only send if server is valid and window name is non-empty - if( gpCurrentWindow->Server && gpCurrentWindow->Name[0] ) - { - Message_Append(gpCurrentWindow->Server, MSG_TYPE_STANDARD, - gsNickname, gpCurrentWindow->Name, String); - writef(gpCurrentWindow->Server->FD, - "PRIVMSG %s :%s\n", gpCurrentWindow->Name, - String - ); - } - } - - return 0; -} - -/** - * \brief Connect to a server - */ -tServer *Server_Connect(const char *Name, const char *AddressString, short PortNumber) -{ - tServer *ret; - - ret = calloc(1, sizeof(tServer) + strlen(Name) + 1); - - strcpy(ret->Name, Name); - - // Connect to the remove server - ret->FD = OpenTCP( AddressString, PortNumber ); - if( ret->FD == -1 ) { - fprintf(stderr, "%s: Unable to create socket\n", Name); - return NULL; - } - - // Append to open list - ret->Next = gpServers; - gpServers = ret; - - // Read some initial data - Message_Append(NULL, MSG_TYPE_SERVER, Name, "", "Connection opened"); - ProcessIncoming(ret); - - // Identify - writef(ret->FD, "USER %s %s %s : %s\n", gsUsername, gsHostname, AddressString, gsRealName); - writef(ret->FD, "NICK %s\n", gsNickname); - Message_Append(NULL, MSG_TYPE_SERVER, Name, "", "Identified"); - //printf("%s: Identified\n", Name); - - return ret; -} - -tMessage *Message_AppendF(tServer *Server, int Type, const char *Source, const char *Dest, const char *Message, ...) -{ - va_list args; - int len; - va_start(args, Message); - len = vsnprintf(NULL, 0, Message, args); - va_end(args); - - char buf[len+1]; - va_start(args, Message); - vsnprintf(buf, len+1, Message, args); - va_end(args); - - return Message_Append(Server, Type, Source, Dest, buf); -} - -tMessage *Message_Append(tServer *Server, int Type, const char *Source, const char *Dest, const char *Message) -{ - tWindow *win = NULL; - int msgLen = strlen(Message); - - // Server==NULL indicates an internal message - if( Server == NULL || Source[0] == '\0' ) - { - win = &gWindow_Status; - } - // Determine if it's a channel or PM - else if( Dest[0] == '#' || Dest[0] == '&' ) // TODO: Better determining here - { - for(win = gpWindows; win; win = win->Next) - { - if( win->Server == Server && strcmp(win->Name, Dest) == 0 ) - { - break; - } - } - if( !win ) { - //win = Window_Create(Server, Dest); - win = &gWindow_Status; // Stick it in the status window, just in case - } - } - #if 0 - else if( strcmp(Dest, Server->Nick) != 0 ) - { - // Umm... message for someone who isn't us? - win = &gWindow_Status; // Stick it in the status window, just in case - } - #endif - // Server message? - else if( strchr(Source, '.') ) // TODO: And again, less hack please - { - #if 1 - for(win = gpWindows; win; win = win->Next) - { - if( win->Server == Server && strcmp(win->Name, Source) == 0 ) - { - break; - } - } - #endif - if( !win ) { - win = &gWindow_Status; - } - - // Set source to the server name (instead of the hostname) - Source = Server->Name; - } - // Private message - else - { - for(win = gpWindows; win; win = win->Next) - { - if( win->Server == Server && strcmp(win->Name, Source) == 0 ) - { - break; - } - } - if( !win ) { - win = Window_Create(Server, Dest); - } - } - - // Create message cache - _SysDebug("Win (%s) msg: <%s> %s", win->Name, Source, Message); - tMessage *ret; - ret = malloc( sizeof(tMessage) + msgLen + 1 + strlen(Source) + 1 ); - ret->Source = ret->Data + msgLen + 1; - strcpy(ret->Source, Source); - strcpy(ret->Data, Message); - ret->Type = Type; - ret->Server = Server; - - // Append to window message list - ret->Next = win->Messages; - win->Messages = ret; - - // Print now if current window - if( win == gpCurrentWindow ) - { - printf("\33[s"); - printf("\33[T"); // Scroll down 1 (free space below) - SetCursorPos(giTerminal_Height-2, 1); - int prefixlen = strlen(Source) + 3; - int avail = giTerminal_Width - prefixlen; - int msglen = strlen(Message); - printf("[%s] %.*s", Source, avail, Message); - while( msglen > avail ) { - msglen -= avail; - Message += avail; - printf("\33[T"); - SetCursorPos(giTerminal_Height-2, prefixlen+1); - printf("%.*s", avail, Message); - } - printf("\x1b[u"); - } - - return ret; -} - -tWindow *Window_Create(tServer *Server, const char *Name) -{ - tWindow *ret, *prev = NULL; - int num = 1; - - // Get the end of the list - // TODO: Cache this instead - for( ret = gpCurrentWindow; ret; prev = ret, ret = ret->Next ) - num ++; - - ret = malloc(sizeof(tWindow) + strlen(Name) + 1); - ret->Messages = NULL; - ret->Server = Server; - ret->ActivityLevel = 1; - strcpy(ret->Name, Name); - - if( prev ) { - ret->Next = prev->Next; - prev->Next = ret; - } - else { // Shouldn't happen really - ret->Next = gpWindows; - gpWindows = ret; - } - -// printf("Win %i %s:%s created\n", num, Server->Name, Name); - - return ret; -} - void Redraw_Screen(void) { - int y = 0; - tMessage *msg; - printf("\x1B[2J"); // Clear screen - printf("\x1B[0;0H"); // Reset cursor - - msg = gpCurrentWindow->Messages; - - // TODO: Title bar? - - // Note: This renders from the bottom up - for( y = giTerminal_Height - 1; y -- && msg; msg = msg->Next) - { - int msglen = strlen(msg->Data); - int prefix_len = 3 + strlen(msg->Source); - int line_avail = giTerminal_Width - prefix_len; - int i = 0, done = 0; - - y -= msglen / line_avail; // Extra lines (y-- above handles the 1 line case) - SetCursorPos(y, 1); - printf("[%s] ", msg->Source); - - while(done < msglen) { - done += printf("%.*s", line_avail, msg->Data+done); - i ++; - SetCursorPos(y+i, prefix_len+1); - } - } - - // Bottom line is rendered by the prompt -} - -void Cmd_PRIVMSG(tServer *Server, const char *Dest, const char *Src, const char *Message) -{ - Message_Append(Server, MSG_TYPE_STANDARD, Dest, Src, Message); - //printf("<%s:%s:%s> %s\n", Server->Name, Dest, Src, Message); -} + printf("\x1B[H"); // Reset cursor -void ParseServerLine_Numeric(tServer *Server, const char *ident, int Num, char *Line) -{ - int pos = 0; - const char *message; - const char *user = GetValue(Line, &pos); - - if( Line[pos] == ':' ) { - message = Line + pos + 1; - } - else { - message = GetValue(Line, &pos); - } - - switch(Num) - { - case 332: // Topic - user = message; // Channel - message = Line + pos + 1; // Topic - Message_AppendF(Server, MSG_TYPE_SERVER, user, user, "Topic: %s", message); - break; - case 333: // Topic set by - user = message; // Channel - message = GetValue(Line, &pos); // User - GetValue(Line, &pos); // Timestamp - Message_AppendF(Server, MSG_TYPE_SERVER, user, user, "Set by %s", message); - break; - case 353: // /NAMES list - // <user> = <channel> :list - // '=' was eaten in and set to message - user = GetValue(Line, &pos); // Actually channel - message = Line + pos + 1; // List - Message_AppendF(Server, MSG_TYPE_SERVER, user, user, "Names: %s", message); - break; - case 366: // end of /NAMES list - // <user> <channel> :msg - user = message; - message = Line + pos + 1; - Message_Append(Server, MSG_TYPE_SERVER, user, user, message); - break; - case 372: // MOTD Data - case 375: // MOTD Start - case 376: // MOTD End - - default: - //printf("[%s] %i %s\n", Server->Name, num, message); - Message_Append(Server, MSG_TYPE_SERVER, ident, user, message); - break; - } -} - -void ParseServerLine_String(tServer *Server, const char *ident, const char *cmd, char *Line) -{ - int pos = 0; - _SysDebug("ident=%s,cmd=%s,Line=%s", ident, cmd, Line); - if( strcmp(cmd, "NOTICE") == 0 ) - { - const char *class = GetValue(Line, &pos); - _SysDebug("NOTICE class='%s'", class); - - const char *message = (Line[pos] == ':') ? Line + pos + 1 : GetValue(Line, &pos); - - //printf("[%s] NOTICE %s: %s\n", Server->Name, ident, message); - char *ident_bang = strchr(ident, '!'); - if( ident_bang ) { - *ident_bang = '\0'; - } - Message_Append(Server, MSG_TYPE_NOTICE, ident, "", message); - } - else if( strcmp(cmd, "PRIVMSG") == 0 ) - { - const char *dest = GetValue(Line, &pos); - const char *message = (Line[pos] == ':') ? Line + pos + 1 : GetValue(Line, &pos); - - // TODO: Catch when the privmsg is addressed to the user - -// Cmd_PRIVMSG(Server, dest, ident, message); - char *ident_bang = strchr(ident, '!'); - if( ident_bang ) { - *ident_bang = '\0'; - } - Message_Append(Server, MSG_TYPE_STANDARD, ident, dest, message); - } - else if( strcmp(cmd, "JOIN" ) == 0 ) - { - const char *channel = Line + pos + 1; - - Message_AppendF(Server, MSG_TYPE_JOIN, "", channel, "%s has joined", ident); - //Window_Create(Server, channel); - } - else if( strcmp(cmd, "PART" ) == 0 ) - { - const char *channel = Line + pos + 1; - - Message_AppendF(Server, MSG_TYPE_PART, "", channel, "%s has left", ident); - //Window_Create(Server, channel); - } - else - { - Message_AppendF(Server, MSG_TYPE_SERVER, "", "", "Unknown message %s (%s)", cmd, Line); - } -} - -/** - */ -void ParseServerLine(tServer *Server, char *Line) -{ - int pos = 0; - - _SysDebug("[%s] %s", Server->Name, Line); - - // Message? - if( *Line == ':' ) - { - pos ++; - const char *ident = GetValue(Line, &pos); // Ident (user or server) - const char *cmd = GetValue(Line, &pos); - - // Numeric command - if( isdigit(cmd[0]) && isdigit(cmd[1]) && isdigit(cmd[2]) ) - { - int num; - num = (cmd[0] - '0') * 100; - num += (cmd[1] - '0') * 10; - num += (cmd[2] - '0') * 1; - - ParseServerLine_Numeric(Server, ident, num, Line+pos); - } - else - { - ParseServerLine_String(Server, ident, cmd, Line+pos); - } - } - else { - const char *cmd = GetValue(Line, &pos); - - if( strcmp(cmd, "PING") == 0 ) { - writef(Server->FD, "PONG %s\n", Line+pos); - } - else { - // Command to client - Message_AppendF(NULL, MSG_TYPE_UNK, "", "", "Client Command: %s", Line); - } - } -} - -/** - * \brief Process incoming lines from the server - */ -int ProcessIncoming(tServer *Server) -{ - char *ptr, *newline; - int len; - - // While there is data in the buffer, read it into user memory and - // process it line by line - // ioctl#8 on a TCP client gets the number of bytes in the recieve buffer - // - Used to avoid blocking - #if NON_BLOCK_READ - while( (len = _SysIOCtl(Server->FD, 8, NULL)) > 0 ) - { - #endif - // Read data - len = _SysRead(Server->FD, &Server->InBuf[Server->ReadPos], BUFSIZ - Server->ReadPos); - if( len == -1 ) { - return -1; - } - Server->InBuf[Server->ReadPos + len] = '\0'; - - // Break into lines - ptr = Server->InBuf; - while( (newline = strchr(ptr, '\n')) ) - { - *newline = '\0'; - if( newline[-1] == '\r' ) newline[-1] = '\0'; - ParseServerLine(Server, ptr); - ptr = newline + 1; - } - - // Handle incomplete lines - if( ptr - Server->InBuf < len + Server->ReadPos ) { - // Update the read position - // InBuf ReadPos ptr ReadPos+len - // | old | new used | new unused | - Server->ReadPos = len + Server->ReadPos - (ptr - Server->InBuf); - // Copy stuff back (moving "new unused" to the start of the buffer) - memcpy(Server->InBuf, ptr, Server->ReadPos); - } - else { - Server->ReadPos = 0; - } - #if NON_BLOCK_READ - } - #endif - - return 0; + Windows_RepaintCurrent(); } /** @@ -863,12 +225,3 @@ char *GetValue(char *Src, int *Ofs) return ret; } -void SetCursorPos(int Row, int Col) -{ - printf("\x1B[%i;%iH", Row, Col); -} - -static inline int isdigit(int ch) -{ - return '0' <= ch && ch < '9'; -} diff --git a/Usermode/Applications/irc_src/message.h b/Usermode/Applications/irc_src/message.h new file mode 100644 index 0000000000000000000000000000000000000000..0b86f124873a7e01a92f2bfb731401c695353c28 --- /dev/null +++ b/Usermode/Applications/irc_src/message.h @@ -0,0 +1,37 @@ +/* + */ +#ifndef _MESSAGE_H_ +#define _MESSAGE_H_ + +enum eMessageTypes +{ + MSG_TYPE_NULL, + MSG_TYPE_SERVER, // Server message + + MSG_TYPE_NOTICE, // NOTICE command + MSG_TYPE_JOIN, // JOIN command + MSG_TYPE_PART, // PART command + MSG_TYPE_QUIT, // QUIT command + + MSG_TYPE_STANDARD, // Standard line + MSG_TYPE_ACTION, // /me + + MSG_TYPE_UNK +}; + +enum eMessageClass +{ + MSG_CLASS_BARE, // source is unused, just gets timestamped + MSG_CLASS_CLIENT, // source optional, prefixed by '-!-' + MSG_CLASS_WALL, // [SOURCE] MSG -- Server-provided message + MSG_CLASS_MESSAGE, // <SOURCE> MSG + MSG_CLASS_ACTION, // * SOURCE MSG +}; + +typedef struct sMessage tMessage; + +//extern tMessage *Message_AppendF(tServer *Server, int Type, const char *Src, const char *Dst, const char *Fmt, ...) __attribute__((format(__printf__,5,6))); +//extern tMessage *Message_Append(tServer *Server, int Type, const char *Source, const char *Dest, const char *Message); + +#endif + diff --git a/Usermode/Applications/irc_src/pseudo_curses.c b/Usermode/Applications/irc_src/pseudo_curses.c new file mode 100644 index 0000000000000000000000000000000000000000..23ee1371b2c0880d1953ceee807158183f8a5cfd --- /dev/null +++ b/Usermode/Applications/irc_src/pseudo_curses.c @@ -0,0 +1,75 @@ +/* + */ +#include "pseudo_curses.h" +#include <stdbool.h> +#include <acess/sys.h> +#include <acess/devices/pty.h> +#include <stdio.h> + +// === PROTOTYPES === +bool ACurses_GetDims_Acess(void); +bool ACurses_GetDims_SerialTermHack(void); + +// === GLOBALS === + int giTerminal_Width = 80; + int giTerminal_Height = 25; + +// === CODE === +void ACurses_Init(void) +{ + if( ACurses_GetDims_Acess() ) { + } + else if( ACurses_GetDims_SerialTermHack() ) { + } + else { + _SysDebug("note: assuming 80x25, can't get terminal dimensions"); + giTerminal_Width = 80; + giTerminal_Height = 25; + } +} + +bool ACurses_GetDims_Acess(void) +{ + if( _SysIOCtl(1, DRV_IOCTL_TYPE, NULL) != DRV_TYPE_TERMINAL ) + return false; + + struct ptydims dims; + if( _SysIOCtl(1, PTY_IOCTL_GETDIMS, &dims) == -1 ) + return false; + giTerminal_Width = dims.W; + giTerminal_Height = dims.H; + return true; +} + +bool ACurses_GetDims_SerialTermHack(void) +{ + _SysDebug("ACurses_GetDims_SerialTermHack: Trying"); + // Set cursor to 1000,1000 , request cursor position, reset cursor to 0,0 + static const char req[] = "\033[1000;1000H\033[6n\033[H"; + fflush(stdin); + _SysWrite(1, req, sizeof(req)); + int64_t timeout = 1000; + fd_set fds; + FD_ZERO(&fds); + FD_SET(0, &fds); + _SysSelect(1, &fds, NULL, NULL, &timeout, 0); + if( !FD_ISSET(0, &fds) ) + return false; + + if( fgetc(stdin) != '\x1b' ) + return false; + if( fgetc(stdin) != '[' ) + return false; + if( fscanf(stdin, "%i;%i", &giTerminal_Width, &giTerminal_Height) != 2 ) + return false; + if( fgetc(stdin) != 'R' ) + return false; + + return true; +} + +void SetCursorPos(int Row, int Col) +{ + printf("\x1B[%i;%iH", Row, Col); +} + diff --git a/Usermode/Applications/irc_src/pseudo_curses.h b/Usermode/Applications/irc_src/pseudo_curses.h new file mode 100644 index 0000000000000000000000000000000000000000..0548e923eca71649b064201398fe308a021a4a95 --- /dev/null +++ b/Usermode/Applications/irc_src/pseudo_curses.h @@ -0,0 +1,13 @@ +/* + */ +#ifndef _ACURSES_H_ +#define _ACURSES_H_ + +extern int giTerminal_Width; +extern int giTerminal_Height; + +extern void ACurses_Init(void); +extern void SetCursorPos(int Row, int Col); + +#endif + diff --git a/Usermode/Applications/irc_src/server.c b/Usermode/Applications/irc_src/server.c new file mode 100644 index 0000000000000000000000000000000000000000..1b85df4fe8781dfaf9e27e9313d538bc6b5023be --- /dev/null +++ b/Usermode/Applications/irc_src/server.c @@ -0,0 +1,407 @@ +/* + */ +#include <stdlib.h> +#include <string.h> +#include "server.h" +#include "window.h" +#include <acess/sys.h> +#include <ctype.h> // isdigit +#include <stdio.h> // vsnprintf + +// === PROTOTYPES === +tServer *Server_Connect(const char *Name, const char *AddressString, short PortNumber); + int Server_HandleIncoming(tServer *Server); +void ParseServerLine(tServer *Server, char *Line); + +// === GLOBALS === +const char *gsUsername = "user"; +const char *gsHostname = "acess"; +const char *gsRealName = "An Acess User"; +const char *gsNickname = "acess"; +const char *gsVersionResponse = "Acess2 IRC Client / Running on some VM probably"; +tServer *gpServers; + +// === CODE === +void Servers_FillSelect(int *nfds, fd_set *rfds, fd_set *efds) +{ + for( tServer *srv = gpServers; srv; srv = srv->Next ) + { + FD_SET(srv->FD, rfds); + FD_SET(srv->FD, efds); + if( srv->FD >= *nfds ) + *nfds = srv->FD+1; + } +} + +void Servers_HandleSelect(int nfds, const fd_set *rfds, const fd_set *efds) +{ + for( tServer *srv = gpServers; srv; srv = srv->Next ) + { + if(FD_ISSET(srv->FD, rfds)) + { + int rv = Server_HandleIncoming(srv); + if(rv) + { + // Oops, error + _SysDebug("ProcessIncoming failed on FD%i (Server %p %s)", + srv->FD, srv, srv->Name); + Exit("Processing error"); + } + } + + if(FD_ISSET(srv->FD, efds)) + { + _SysDebug("Error on FD%i (Server %p %s)", + srv->FD, srv, srv->Name); + Exit("Socket error"); + } + } +} + +void Servers_CloseAll(const char *QuitMessage) +{ + while( gpServers ) + { + tServer *srv = gpServers; + gpServers = srv->Next; + + Server_SendCommand(srv, "QUIT :%s", QuitMessage); + _SysClose(srv->FD); + free(srv); + } +} + +/** + * \brief Connect to a server + */ +tServer *Server_Connect(const char *Name, const char *AddressString, short PortNumber) +{ + tServer *ret; + + ret = calloc(1, sizeof(tServer) + strlen(Name) + 1); + + strcpy(ret->Name, Name); + + // Connect to the remove server + ret->FD = OpenTCP( AddressString, PortNumber ); + if( ret->FD == -1 ) { + free(ret); + Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, Name, "Unable to create socket"); + return NULL; + } + + ret->Nick = strdup(gsNickname); + + // Append to open list + ret->Next = gpServers; + gpServers = ret; + + // Read some initial data + Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, Name, "Unable to create socket"); + Server_HandleIncoming(ret); + + // Identify + Server_SendCommand(ret, "USER %s %s %s : %s", gsUsername, gsHostname, AddressString, gsRealName); + Server_SendCommand(ret, "NICK %s", ret->Nick); + Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, Name, "Identified"); + + return ret; +} + +const char *Server_GetNick(const tServer *Server) +{ + return Server ? Server->Nick : "NULL"; +} +const char *Server_GetName(const tServer *Server) +{ + return Server ? Server->Name : "NULL"; +} + +void Server_SendCommand(tServer *Server, const char *Format, ...) +{ + va_list args; + int len; + + va_start(args, Format); + len = vsnprintf(NULL, 0, Format, args); + va_end(args); + + char buf[len+1]; + va_start(args, Format); + vsnprintf(buf, len+1, Format, args); + va_end(args); + + _SysWrite(Server->FD, buf, len); + _SysWrite(Server->FD, "\n", 1); +} + +void Cmd_PRIVMSG(tServer *Server, const char *Dest, const char *Src, const char *Message) +{ + tWindow *win; + if( strcmp(Dest, Server->Nick) == 0 ) { + win = Windows_GetByNameOrCreate(Server, Src); + } + else { + win = Windows_GetByNameOrCreate(Server, Dest); + } + + // Detect CTCP + if( Message[0] == '\1' && Message[strlen(Message)-1] == '\1' ) + { + Message += 1; + // message is a CTCP command + if( strcmp(Message, "VERSION\1") == 0 ) + { + // Put a message in the status window, and reply + Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, Server->Name, "CTCP VERSION request from %s", Src); + // - Always reply via NOTICE + Server_SendCommand(Server, "NOTICE %s :\1VERSION %s\1", Src, gsVersionResponse); + } + else if( strncmp(Message, "ACTION ", 7) == 0 ) + { + Message += 7; + // Put a message in the status window, and reply + Window_AppendMessage(win, MSG_CLASS_ACTION, Src, "%.*s", (int)(strlen(Message)-1), Message); + } + else + { + Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, Server->Name, "Unknown CTCP '%s' from %s", + Message, Src); + } + } + else + { + Window_AppendMessage(win, MSG_CLASS_MESSAGE, Src, "%s", Message); + } +} + +/** + * \brief Process incoming lines from the server + */ +int Server_HandleIncoming(tServer *Server) +{ + char *ptr, *newline; + int len; + + // While there is data in the buffer, read it into user memory and + // process it line by line + // ioctl#8 on a TCP client gets the number of bytes in the recieve buffer + // - Used to avoid blocking + #if NON_BLOCK_READ + while( (len = _SysIOCtl(Server->FD, 8, NULL)) > 0 ) + { + #endif + // Read data + len = _SysRead(Server->FD, &Server->InBuf[Server->ReadPos], sizeof(Server->InBuf) - Server->ReadPos); + if( len == -1 ) { + return -1; + } + Server->InBuf[Server->ReadPos + len] = '\0'; + + // Break into lines + ptr = Server->InBuf; + while( (newline = strchr(ptr, '\n')) ) + { + *newline = '\0'; + if( newline[-1] == '\r' ) newline[-1] = '\0'; + ParseServerLine(Server, ptr); + ptr = newline + 1; + } + + // Handle incomplete lines + if( ptr - Server->InBuf < len + Server->ReadPos ) { + // Update the read position + // InBuf ReadPos ptr ReadPos+len + // | old | new used | new unused | + Server->ReadPos = len + Server->ReadPos - (ptr - Server->InBuf); + // Copy stuff back (moving "new unused" to the start of the buffer) + memcpy(Server->InBuf, ptr, Server->ReadPos); + } + else { + Server->ReadPos = 0; + } + #if NON_BLOCK_READ + } + #endif + + return 0; +} + +void ParseServerLine_Numeric(tServer *Server, const char *ident, int Num, char *Line) +{ + int pos = 0; + const char *message; + const char *user = GetValue(Line, &pos); + const char *timestamp; + + if( Line[pos] == ':' ) { + message = Line + pos + 1; + } + else { + message = GetValue(Line, &pos); + } + + switch(Num) + { + case 332: // Topic + user = message; // Channel + message = Line + pos + 1; // Topic + Window_AppendMsg_Topic( Windows_GetByNameOrCreate(Server, user), message ); + break; + case 333: // Topic set by + user = message; // Channel + message = GetValue(Line, &pos); // User + timestamp = GetValue(Line, &pos); // Timestamp + Window_AppendMsg_TopicTime( Windows_GetByNameOrCreate(Server, user), message, timestamp ); + break; + case 353: // /NAMES list + // TODO: Parse the /names list and store it locally, dump to window when end is seen + // <user> = <channel> :list + // '=' was eaten in and set to message + user = GetValue(Line, &pos); // Actually channel + message = Line + pos + 1; // List + Window_AppendMessage( Windows_GetByNameOrCreate(Server, user), MSG_CLASS_CLIENT, "NAMES", message ); + break; + case 366: // end of /NAMES list + // <user> <channel> :msg + // - Ignored + break; + + case 1: // welcome + case 2: // host name and version (text) + case 3: // host uptime + case 4: // host name, version, and signature + case 5: // parameters + + case 250: // Highest connection count + case 251: // user count (network) + case 252: // Operator count + case 253: // Unidentified connections + case 254: // Channel count + case 255: // Server's stats + case 265: // Local users -- min max :Text representation + case 266: // Global users (same as above) + + case 372: // MOTD Data + case 375: // MOTD Start + case 376: // MOTD End + Window_AppendMessage( WINDOW_STATUS, MSG_CLASS_WALL, Server->Name, "%s", message); + break; + + default: + //printf("[%s] %i %s\n", Server->Name, num, message); + Window_AppendMessage( WINDOW_STATUS, MSG_CLASS_WALL, Server->Name, "Unknown %i %s", Num, message); + break; + } +} + +void ParseServerLine_String(tServer *Server, const char *ident, const char *cmd, char *Line) +{ + int pos = 0; + _SysDebug("ident=%s,cmd=%s,Line=%s", ident, cmd, Line); + if( strcmp(cmd, "NOTICE") == 0 ) + { + const char *class = GetValue(Line, &pos); + const char *message = (Line[pos] == ':') ? Line + pos + 1 : GetValue(Line, &pos); + _SysDebug("NOTICE class='%s'", class); + + char *ident_bang = strchr(ident, '!'); + if( ident_bang ) { + *ident_bang = '\0'; + } + // TODO: Colour codes + Window_AppendMessage( WINDOW_STATUS, MSG_CLASS_WALL, Server->Name, "%s %s", ident, message); + } + else if( strcmp(cmd, "PRIVMSG") == 0 ) + { + const char *dest = GetValue(Line, &pos); + const char *message = (Line[pos] == ':') ? Line + pos + 1 : GetValue(Line, &pos); + + char *ident_bang = strchr(ident, '!'); + if( ident_bang ) { + *ident_bang = '\0'; + } + Cmd_PRIVMSG(Server, dest, ident, message); + } + else if( strcmp(cmd, "JOIN" ) == 0 ) + { + const char *channel = Line + pos + 1; + + Window_AppendMsg_Join( Windows_GetByNameOrCreate(Server, channel), ident ); + } + else if( strcmp(cmd, "PART" ) == 0 ) + { + const char *channel = Line + pos + 1; + + Window_AppendMsg_Part( Windows_GetByNameOrCreate(Server, channel), ident, "" ); + } + else if( strcmp(cmd, "MODE" ) == 0 ) + { + // ident MODE channel flags nick[ nick...] + const char *channel = GetValue(Line, &pos); + const char *flags = GetValue(Line, &pos); + const char *args = Line + pos; + + Window_AppendMsg_Mode( Windows_GetByNameOrCreate(Server, channel), ident, flags, args ); + } + else if( strcmp(cmd, "KICK" ) == 0 ) + { + // ident KICK channel nick :reason + const char *channel = GetValue(Line, &pos); + const char *nick = GetValue(Line, &pos); + const char *message = Line + pos + 1; + + Window_AppendMsg_Kick( Windows_GetByNameOrCreate(Server, channel), ident, nick, message ); + if( strcmp(nick, Server->Nick) == 0 ) { + // Oh, that was me :( + // - what do? + } + } + else + { + Window_AppendMessage( WINDOW_STATUS, MSG_CLASS_BARE, Server->Name, "Unknown command '%s' %s", cmd, Line); + } +} + +/** + */ +void ParseServerLine(tServer *Server, char *Line) +{ + int pos = 0; + + _SysDebug("[%s] %s", Server->Name, Line); + + // Message? + if( *Line == ':' ) + { + pos ++; + const char *ident = GetValue(Line, &pos); // Ident (user or server) + const char *cmd = GetValue(Line, &pos); + + // Numeric command + if( isdigit(cmd[0]) && isdigit(cmd[1]) && isdigit(cmd[2]) ) + { + int num; + num = (cmd[0] - '0') * 100; + num += (cmd[1] - '0') * 10; + num += (cmd[2] - '0') * 1; + + ParseServerLine_Numeric(Server, ident, num, Line+pos); + } + else + { + ParseServerLine_String(Server, ident, cmd, Line+pos); + } + } + else { + const char *cmd = GetValue(Line, &pos); + + if( strcmp(cmd, "PING") == 0 ) { + Server_SendCommand(Server, "PONG %s", Line+pos); + } + else { + // Command to client + Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, Server->Name, "UNK Client Command: %s", Line); + } + } +} diff --git a/Usermode/Applications/irc_src/server.h b/Usermode/Applications/irc_src/server.h new file mode 100644 index 0000000000000000000000000000000000000000..edc9bd0a7ee0084f5ed34524a0ca825f460a47df --- /dev/null +++ b/Usermode/Applications/irc_src/server.h @@ -0,0 +1,30 @@ +/* + */ +#ifndef _SERVER_H_ +#define _SERVER_H_ + +#include "common.h" + +typedef struct sServer { + struct sServer *Next; + int FD; + char InBuf[1024+1]; + int ReadPos; + char *Nick; + char Name[]; +} tServer; + +extern void Servers_FillSelect(int *nfds, fd_set *rfds, fd_set *efds); +extern void Servers_HandleSelect(int nfds, const fd_set *rfds, const fd_set *efds); +extern void Servers_CloseAll(const char *QuitMessage); + +extern tServer *Server_Connect(const char *Name, const char *AddressString, short PortNumber); +extern int Server_HandleIncoming(tServer *Server); + +extern const char *Server_GetNick(const tServer *Server); +extern const char *Server_GetName(const tServer *Server); + +extern void Server_SendCommand(tServer *Server, const char *Format, ...) __attribute__((format(__printf__,2,3))); + +#endif + diff --git a/Usermode/Applications/irc_src/window.c b/Usermode/Applications/irc_src/window.c new file mode 100644 index 0000000000000000000000000000000000000000..ba12880c1f3f33efd9fb15d4e9985adea070b06f --- /dev/null +++ b/Usermode/Applications/irc_src/window.c @@ -0,0 +1,358 @@ +/* + */ +#include "window.h" +#include <stddef.h> +#include <string.h> +#include <stdarg.h> +#include <stdio.h> // TODO: replace with calls into ACurses_* +#include <stdlib.h> +#include <assert.h> +#include "server.h" +#include <ctype.h> + +struct sMessage +{ + struct sMessage *Next; + time_t Timestamp; + enum eMessageClass Class; + char *Source; // Pointer to the end of `Data` + size_t PrefixLen; + char Data[]; +}; + +struct sWindow +{ + struct sWindow *Next; + tMessage *Messages; + tServer *Server; //!< Canonical server (can be NULL) + int ActivityLevel; + char Name[]; // Channel name / remote user +}; + +// === PROTOTYPES === +void Windows_RepaintCurrent(void); +size_t WordBreak(const char *Line, size_t avail); +size_t Windows_int_PaintMessagePrefix(const tMessage *Message, bool EnablePrint); +size_t Windows_int_PaintMessageLine(const tMessage *Message, size_t Offset, bool EnablePrint); + int Windows_int_GetMessageLines(const tMessage *Message); + int Windows_int_PaintMessage(tMessage *Message); + +// === GLOBALS === +tWindow gWindow_Status = { + NULL, NULL, NULL, // No next, empty list, no server + 0, {"(status)"} // No activity, empty name (rendered as status) +}; +tWindow *gpWindows = &gWindow_Status; +tWindow *gpCurrentWindow = &gWindow_Status; + +// === CODE === +void Windows_RepaintCurrent(void) +{ + // TODO: Title bar? + SetCursorPos(1, 1); + printf("\x1b[37;44m\x1b[2K%s\x1b[0m\n", gpCurrentWindow->Name); + + int avail_rows = giTerminal_Height - 3; + + // Note: This renders from the bottom up + tMessage *msg = gpCurrentWindow->Messages; + for( int y = avail_rows; msg && y > 0; ) + { + int lines = Windows_int_GetMessageLines(msg); + y -= lines; + size_t ofs = 0; + size_t len; + int i = 0; + do { + SetCursorPos(2 + y+i, 1); + len = Windows_int_PaintMessageLine(msg, ofs, (y+i >= 0)); + ofs += len; + i ++; + } while( len > 0 ); + msg = msg->Next; + } + + // Status line is our department + SetCursorPos(giTerminal_Height-1, 1); + printf("\x1b[37;44m\x1b[2K[%s] [%s/%s]\x1b[0m", Server_GetNick(gpCurrentWindow->Server), + Server_GetName(gpCurrentWindow->Server), gpCurrentWindow->Name); + fflush(stdout); + // Bottom line is rendered by the prompt +} + +size_t WordBreak(const char *Line, size_t avail) +{ + // If sufficient space, don't need to break on a word + if( strlen(Line) < avail ) + return strlen(Line); + + // Search backwards from end of space for a non-alpha-numeric character + size_t ret = avail-1; + while( ret > 0 && isalnum(Line[ret]) ) + ret --; + + // if one wasn't found in a sane area, just split + if( ret < avail-20 || ret == 0 ) + return avail; + + return ret; +} + +size_t Windows_int_PaintMessagePrefix(const tMessage *Message, bool EnablePrint) +{ + size_t len = 0; + + unsigned long seconds_today = Message->Timestamp/1000 % (24 * 3600); + if(EnablePrint) + printf("%02i:%02i:%02i ", seconds_today/3600, (seconds_today/60)%60, seconds_today%60); + else + len += snprintf(NULL, 0, "%02i:%02i:%02i ", seconds_today/3600, (seconds_today/60)%60, seconds_today%60); + + const char *format; + switch(Message->Class) + { + case MSG_CLASS_BARE: + format = ""; + break; + case MSG_CLASS_CLIENT: + if(Message->Source) + format = "[%s] -!- "; + else + format = "-!- "; + break; + case MSG_CLASS_WALL: + format = "[%s] "; + break; + case MSG_CLASS_MESSAGE: + format = "<%s> "; + break; + case MSG_CLASS_ACTION: + format = "* %s "; + break; + } + + if( EnablePrint ) + len += printf(format, Message->Source); + else + len += snprintf(NULL, 0, format, Message->Source); + + return len; +} + +size_t Windows_int_PaintMessageLine(const tMessage *Message, size_t Offset, bool EnablePrint) +{ + _SysDebug("Windows_int_PaintMessageLine: Message=%p,Offset=%i,EnablePrint=%b", + Message, (int)Offset, EnablePrint); + if( Offset > strlen(Message->Data) ) { + _SysDebug("Windows_int_PaintMessageLine: No message left"); + return 0; + } + _SysDebug("Windows_int_PaintMessageLine: Message->Data=\"%.*s\"+\"%s\"", + (int)Offset, Message->Data, Message->Data+Offset); + + size_t avail = giTerminal_Width - Message->PrefixLen; + const char *msg_data = Message->Data + Offset; + int used = WordBreak(msg_data, avail); + + if( EnablePrint ) + { + if( Offset == 0 ) + Windows_int_PaintMessagePrefix(Message, true); + else { + for(int i = 0; i < Message->PrefixLen; i ++) + printf(" "); + //printf("\x1b[%iC", Message->PrefixLen); + } + printf("%.*s", used, msg_data); + } + + _SysDebug("used(%i) >= strlen(msg_data)(%i)", used, strlen(msg_data)); + if( used >= strlen(msg_data) ) + return 0; + + return Offset + used; +} + +int Windows_int_GetMessageLines(const tMessage *Message) +{ + assert(Message->PrefixLen); + const size_t avail = giTerminal_Height - Message->PrefixLen; + const size_t msglen = strlen(Message->Data); + size_t offset = 0; + int nLines = 0; + do { + offset += WordBreak(Message->Data+offset, avail); + nLines ++; + } while(offset < msglen); + return nLines; +} + +void Windows_SwitchTo(tWindow *Window) +{ + gpCurrentWindow = Window; + Redraw_Screen(); +} + +void Windows_SetStatusServer(tServer *Server) +{ + gWindow_Status.Server = Server; +} + +tWindow *Windows_GetByIndex(int Index) +{ + tWindow *win; + for( win = gpWindows; win && Index--; win = win->Next ) + ; + return win; +} + +tWindow *Windows_GetByNameEx(tServer *Server, const char *Name, bool CreateAllowed) +{ + tWindow *ret, *prev = NULL; + int num = 1; + + // Get the end of the list and check for duplicates + // TODO: Cache this instead + for( ret = &gWindow_Status; ret; prev = ret, ret = ret->Next ) + { + if( ret->Server == Server && strcmp(ret->Name, Name) == 0 ) + { + return ret; + } + num ++; + } + if( !CreateAllowed ) { + return NULL; + } + + ret = malloc(sizeof(tWindow) + strlen(Name) + 1); + ret->Messages = NULL; + ret->Server = Server; + ret->ActivityLevel = 1; + strcpy(ret->Name, Name); + + if( prev ) { + ret->Next = prev->Next; + prev->Next = ret; + } + else { // Shouldn't happen really + ret->Next = gpWindows; + gpWindows = ret; + } + +// printf("Win %i %s:%s created\n", num, Server->Name, Name); + + return ret; +} + +tWindow *Windows_GetByName(tServer *Server, const char *Name) +{ + return Windows_GetByNameEx(Server, Name, false); +} + +tWindow *Window_Create(tServer *Server, const char *Name) +{ + return Windows_GetByNameEx(Server, Name, true); +} + + +tWindow *Window_int_ParseSpecial(const tWindow *Window) +{ + if( Window == NULL ) + return gpCurrentWindow; + if( Window == WINDOW_STATUS ) + return &gWindow_Status; + return (tWindow*)Window; +} + +const char *Window_GetName(const tWindow *Window) { + return Window_int_ParseSpecial(Window)->Name; +} +tServer *Window_GetServer(const tWindow *Window) { + return Window_int_ParseSpecial(Window)->Server; +} +bool Window_IsChat(const tWindow *Window) { + return Window_int_ParseSpecial(Window) != &gWindow_Status; +} + +// ----------------------------- +// Messages +// ----------------------------- +void Window_AppendMessage(tWindow *Window, enum eMessageClass Class, const char *Source, const char *Message, ...) +{ + Window = Window_int_ParseSpecial(Window); + + va_list args; + + va_start(args, Message); + size_t len = vsnprintf(NULL, 0, Message, args); + va_end(args); + + tMessage *msg = malloc( sizeof(tMessage) + len+1 + (Source?strlen(Source)+1:0) ); + assert(msg); + + msg->Class = Class; + msg->Source = (Source ? msg->Data + len+1 : NULL); + msg->Timestamp = _SysTimestamp(); + + va_start(args, Message); + vsnprintf(msg->Data, len+1, Message, args); + va_end(args); + + if( Source ) { + strcpy(msg->Source, Source); + } + + msg->PrefixLen = Windows_int_PaintMessagePrefix(msg, false); + + msg->Next = Window->Messages; + Window->Messages = msg; + + if( Window == gpCurrentWindow ) + { + // Scroll if needed, and redraw? + // - Lazy option of draw at bottom of screen + printf("\33[s"); // Save cursor + size_t offset = 0, len; + do { + printf("\33[S"); // Scroll down 1 (free space below) + SetCursorPos(giTerminal_Height-2, 1); + len = Windows_int_PaintMessageLine(msg, offset, true); + offset += len; + } while( len > 0 ); + printf("\33[u"); // Restore cursor + fflush(stdout); + } +} + +void Window_AppendMsg_Join(tWindow *Window, const char *Usermask) +{ + Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "%s has joined %s", Usermask, Window->Name); +} +void Window_AppendMsg_Quit(tWindow *Window, const char *Usermask, const char *Reason) +{ + Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "%s has joined quit (%s)", Usermask, Reason); +} +void Window_AppendMsg_Part(tWindow *Window, const char *Usermask, const char *Reason) +{ + Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "%s has joined left %s (%s)", Usermask, Window->Name, Reason); +} +void Window_AppendMsg_Topic(tWindow *Window, const char *Topic) +{ + Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "Topic of %s is %s", Window->Name, Topic); +} +void Window_AppendMsg_TopicTime(tWindow *Window, const char *User, const char *Timestamp) +{ + Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "Topic set by %s at %s", User, Timestamp); +} +void Window_AppendMsg_Kick(tWindow *Window, const char *Operator, const char *Nick, const char *Reason) +{ + Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "%s was kicked from %s by %s [%s]", + Nick, Window->Name, Operator, Reason); +} +void Window_AppendMsg_Mode(tWindow *Window, const char *Operator, const char *Flags, const char *Args) +{ + Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "mode/%s [%s %s] by %s", + Window->Name, Flags, Args, Operator); +} + diff --git a/Usermode/Applications/irc_src/window.h b/Usermode/Applications/irc_src/window.h new file mode 100644 index 0000000000000000000000000000000000000000..620e1a5da2a5fd374ae2b00568e3612de4b4d4f6 --- /dev/null +++ b/Usermode/Applications/irc_src/window.h @@ -0,0 +1,38 @@ +/* + */ +#ifndef _WINDOW_H_ +#define _WINDOW_H_ + +#include "common.h" +#include "message.h" +#include <stdbool.h> + +typedef struct sWindow tWindow; +extern void Windows_RepaintCurrent(void); + +extern void Windows_SetStatusServer(tServer *Server); +extern tWindow *Window_Create(tServer *Server, const char *Name); +extern tWindow *Windows_GetByIndex(int Index); +extern tWindow *Windows_GetByName(tServer *Server, const char *Name); +static inline tWindow *Windows_GetByNameOrCreate(tServer *Server, const char *Name) { + return Window_Create(Server, Name); +} +extern void Windows_SwitchTo(tWindow *Window); + +extern void Window_AppendMessage(tWindow *Window, enum eMessageClass Class, const char *Source, const char *Message, ...) + __attribute__((format(__printf__,4,5))); +extern void Window_AppendMsg_Join(tWindow *Window, const char *Usermask); +extern void Window_AppendMsg_Quit(tWindow *Window, const char *Usermask, const char *Reason); +extern void Window_AppendMsg_Part(tWindow *Window, const char *Usermask, const char *Reason); +extern void Window_AppendMsg_Kick(tWindow *Window, const char *Operator, const char *Nick, const char *Reason); +extern void Window_AppendMsg_Mode(tWindow *Window, const char *Operator, const char *Flags, const char *Args); +extern void Window_AppendMsg_Topic(tWindow *Window, const char *Topic); +extern void Window_AppendMsg_TopicTime(tWindow *Window, const char *User, const char *Timestmap); + +extern const char *Window_GetName(const tWindow *Window); +extern tServer *Window_GetServer(const tWindow *Window); +extern bool Window_IsChat(const tWindow *Window); + +#define WINDOW_STATUS ((void*)-1) + +#endif diff --git a/Usermode/Applications/ping_src/Makefile b/Usermode/Applications/ping_src/Makefile index 64c4649e8014da82086f4828395317c2ff69c552..3893fa0fcd146d9cd2df54c0414737df4f703fa5 100644 --- a/Usermode/Applications/ping_src/Makefile +++ b/Usermode/Applications/ping_src/Makefile @@ -2,7 +2,7 @@ -include ../Makefile.cfg -LDFLAGS += -lnet +LIBS += -lnet OBJ = main.o BIN = ping diff --git a/Usermode/Applications/telnet_src/Makefile b/Usermode/Applications/telnet_src/Makefile index bbcac85fba5217e85a2c9b414ed503d3ef796a18..7d61245e099d342ff5ee7073e2cf9ebc21eb5aff 100644 --- a/Usermode/Applications/telnet_src/Makefile +++ b/Usermode/Applications/telnet_src/Makefile @@ -2,7 +2,7 @@ -include ../Makefile.cfg -LDFLAGS += -lnet -lreadline +LIBS += -lnet -lreadline OBJ = main.o BIN = telnet diff --git a/Usermode/Applications/telnetd_src/Makefile b/Usermode/Applications/telnetd_src/Makefile index a85a07121c7165ac3e955f1af01497fcba9c51ab..d7d6ee6eb0ad29a7d535919706c140eaa87ea354 100644 --- a/Usermode/Applications/telnetd_src/Makefile +++ b/Usermode/Applications/telnetd_src/Makefile @@ -2,7 +2,7 @@ -include ../Makefile.cfg -LDFLAGS += -lnet +LIBS += -lnet OBJ = main.o BIN = telnetd diff --git a/Usermode/Applications/wget_src/Makefile b/Usermode/Applications/wget_src/Makefile index e6f5a012b29faf2d60a58fabddca1b5213116ba7..db28b27fa239466cd73afc8817d0694497493532 100644 --- a/Usermode/Applications/wget_src/Makefile +++ b/Usermode/Applications/wget_src/Makefile @@ -3,7 +3,8 @@ -include ../Makefile.cfg CFLAGS += -std=gnu99 -LDFLAGS += -lnet -lpsocket -luri +LIBS += -lnet -lpsocket -luri + OBJ = main.o BIN = wget diff --git a/Usermode/Libraries/Makefile.cfg b/Usermode/Libraries/Makefile.cfg index 5920059e71f70f3bd300fac550487da0fe86726e..b10117e493f67393d8063944a974a70d3e4b008c 100644 --- a/Usermode/Libraries/Makefile.cfg +++ b/Usermode/Libraries/Makefile.cfg @@ -4,11 +4,14 @@ _libsdir := $(dir $(lastword $(MAKEFILE_LIST))) -include $(_libsdir)../Makefile.cfg +USE_CXX_LINK := +PRELINK := MAKEDEP = $(CC) -M ifeq ($(ARCHDIR),native) ASFLAGS += -D ARCHDIR=$(ARCHDIR) -D __ASSEMBLER__=1 - LDFLAGS := -lacess-native + LDFLAGS := + LIBS := -lacess-native #CPPFLAGS := -D SoMain="__attribute__ ((constructor(101))) libacessnative_init" ifeq ($(PLATFORM),windows) else @@ -26,13 +29,16 @@ else ifneq ($(HOST_ARCH),) CFLAGS += -fPIC CXXFLAGS += -fPIC endif + LIBS := -lld-acess else - CPPFLAGS := -ffreestanding CFLAGS := -fno-stack-protector -fPIC - CXXFLAGS := -fno-stack-protector -fPIC - LDFLAGS := -I/Acess/Libs/ld-acess.so -lld-acess `$(CC) -print-libgcc-file-name` + CXXFLAGS := -fno-stack-protector -fPIC + LDFLAGS := + LIBS := -lld-acess endif -LDFLAGS += -g -nostdlib -shared -eSoMain -x --no-undefined -L$(OUTPUTDIR)Libs/ +LDFLAGS += -g -shared -eSoStart -L$(OUTPUTDIR)Libs/ --no-undefined +CXXFLAGS += -std=gnu++11 +#CPPFLAGS += -D 'SoMain(...)=SoMain(__VA_ARGS__) __attribute__ ((visibility ("hidden"))); int SoMain(__VA_ARGS__)' -include $(_libsdir)../common_settings.mk diff --git a/Usermode/Libraries/Makefile.tpl b/Usermode/Libraries/Makefile.tpl index a99ff144e3099134fd0ea5a9f0f745d4d5787d49..3b8d2f55aca31fab14e0edfd2d57e3820ed6daa0 100644 --- a/Usermode/Libraries/Makefile.tpl +++ b/Usermode/Libraries/Makefile.tpl @@ -10,21 +10,28 @@ ifeq ($(ARCH),native) LDFLAGS := $(LDFLAGS:-lc=-lc_acess) endif -_LD_CMD := $(lastword $(subst -, ,$(firstword $(LD)))) -ifneq ($(_LD_CMD),ld) - LDFLAGS := $(subst -soname ,-Wl$(comma)-soname$(comma),$(LDFLAGS)) - LDFLAGS := $(subst -Map ,-Wl$(comma)-Map$(comma),$(LDFLAGS)) - LDFLAGS := $(LDFLAGS:-x=-Wl,-x) - LDFLAGS := $(LDFLAGS:--%=-Wl,--%) -endif - _BIN := $(addprefix $(OUTPUTDIR)Libs/,$(BIN)) _XBIN := $(addprefix $(OUTPUTDIR)Libs/,$(EXTRABIN)) _OBJPREFIX := obj-$(ARCH)/ +LDFLAGS += -Map $(_OBJPREFIX)Map.txt + +_LD_CMD := $(lastword $(subst -, ,$(firstword $(LD)))) +LDFLAGS := $(subst -soname ,-Wl$(comma)-soname$(comma),$(LDFLAGS)) +LDFLAGS := $(subst -Map ,-Wl$(comma)-Map$(comma),$(LDFLAGS)) +LDFLAGS := $(LDFLAGS:-x=-Wl,-x) +LDFLAGS := $(LDFLAGS:--%=-Wl,--%) _LIBS := $(filter -l%,$(LDFLAGS)) _LIBS := $(patsubst -l%,$(OUTPUTDIR)Libs/lib%.so,$(_LIBS)) +ifeq ($(ARCHDIR),native) + LIBS := $(patsubst -lc,-lc_acess,$(LIBS)) + LIBS := $(patsubst -lc++,-lc++_acess,$(LIBS)) + ifneq ($(BIN),libc_acess.so) + LIBS += -lc_acess + endif +endif + OBJ := $(addprefix $(_OBJPREFIX),$(OBJ)) UTESTS := $(patsubst TEST_%.c,%,$(wildcard TEST_*.c)) @@ -36,14 +43,15 @@ else V := @ endif -.PHONY: all clean install postbuild +.PHONY: all clean install postbuild utest-build utest-run generate_exp all: _libs $(_BIN) $(_XBIN) .PHONY: _libs +.PRECIOUS: .no -HEADERS := $(patsubst include_exp/%,../../include/%,$(shell find include_exp/ -name \*.h)) +HEADERS := $(patsubst include_exp/%,../../include/%,$(shell find include_exp/ -name \*.h 2>/dev/null)) _libs: $(HEADERS) ../../include/%: include_exp/% @@ -54,16 +62,13 @@ _libs: $(HEADERS) utest: utest-build utest-run -generate_exp: $(UTESTS:%=EXP_%.txt) - @echo > /dev/null - utest-build: $(UTESTS:%=TEST_%) utest-run: $(UTESTS:%=runtest-%) - @echo > /dev/null -$(UTESTS:%=runtest-%): runtest-%: TEST_% EXP_%.txt - ./TEST_$* | diff EXP_$*.txt - +$(UTESTS:%=runtest-%): runtest-%: TEST_% + @echo --- [TEST] $* + @./TEST_$* clean: $(RM) $(_BIN) $(_XBIN) $(OBJ) $(_BIN).dsm $(DEPFILES) $(EXTRACLEAN) @@ -81,23 +86,33 @@ endif # for f in $(INCFILES); do ln -s $f $(ACESSDIR)/include/$f; done #endif -$(_BIN): $(OBJ) +LINK_OBJS = $(PRELINK) $(OBJ) +$(_BIN): $(CRTI) $(LINK_OBJS) $(CRTN) $(CRT0S) @mkdir -p $(dir $(_BIN)) @echo [LD] -o $(BIN) $(OBJ) - $V$(LD) $(LDFLAGS) -o $(_BIN) $(OBJ) $(shell $(CC) -print-libgcc-file-name) - $V$(DISASM) -D -S $(_BIN) > $(_OBJPREFIX)$(BIN).dsm +ifneq ($(USE_CXX_LINK),) + $V$(CXX) $(LDFLAGS) -o $(_BIN) $(LINK_OBJS) $(LIBS) +else + $V$(CC) $(LDFLAGS) -o $(_BIN) $(LINK_OBJS) $(LIBS) +endif + $V$(DISASM) -C $(_BIN) > $(_OBJPREFIX)$(BIN).dsm -$(_OBJPREFIX)%.o: %.c +$(_OBJPREFIX)%.o: %.c Makefile @echo [CC] -o $@ @mkdir -p $(dir $@) $V$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< -MMD -MP -MT $@ -MF $@.dep -$(_OBJPREFIX)%.o: %.cc +$(_OBJPREFIX)%.o: %.cc Makefile @echo [CXX] -o $@ @mkdir -p $(dir $@) $V$(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ -c $< -MMD -MP -MT $@ -MF $@.dep -$(_OBJPREFIX)%.ao: %.$(ASSUFFIX) +$(_OBJPREFIX)%.o: %.cpp Makefile + @echo [CXX] -o $@ + @mkdir -p $(dir $@) + $V$(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ -c $< -MMD -MP -MT $@ -MF $@.dep + +$(_OBJPREFIX)%.ao: %.$(ASSUFFIX) Makefile @echo [AS] -o $@ @mkdir -p $(dir $@) $V$(AS) $(ASFLAGS) -o $@ $< @@ -115,10 +130,14 @@ $(OUTPUTDIR)Libs/%: obj-native/%.no: %.c @mkdir -p $(dir $@) - $(NCC) -c $< -o $@ -Wall -std=gnu99 -MD -MP -MF $@.dep + @echo [CC Native] -o $@ + @$(NCC) -g -c $< -o $@ -Wall -std=gnu99 -MD -MP -MF $@.dep '-D_SysDebug(f,v...)=fprintf(stderr,"DEBUG "f"\n",##v)' -include stdio.h TEST_%: obj-native/TEST_%.no obj-native/%.no - $(NCC) -o $@ $^ + @echo [CC Native] -o $@ + @$(NCC) -g -o $@ $^ + +.PRECIOUS: $(UTESTS:%=obj-native/%.no) $(UTESTS:%=obj-native/TEST_%.no) -include $(UTESTS:%=obj-native/TEST_%.no.dep) -include $(UTESTS:%=obj-native/%.no.dep) diff --git a/Usermode/Libraries/acess.ld_src/.gitignore b/Usermode/Libraries/acess.ld_src/.gitignore deleted file mode 100644 index 3932ffb93f0d771d24aaa4039559f032e94801fb..0000000000000000000000000000000000000000 --- a/Usermode/Libraries/acess.ld_src/.gitignore +++ /dev/null @@ -1 +0,0 @@ -acess_native.ld.h diff --git a/Usermode/Libraries/acess.ld_src/Makefile b/Usermode/Libraries/acess.ld_src/Makefile deleted file mode 100644 index 25a5c56538954b3f59139cca857ebf4186fbaac6..0000000000000000000000000000000000000000 --- a/Usermode/Libraries/acess.ld_src/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# -# Acess2 -# - Common usermode linker script -# - - --include ../Makefile.cfg - -BIN = $(OUTPUTDIR)Libs/acess.ld - -.PHONY: all clean install utest generate_exp - -all: $(BIN) - -clean: - $(RM) $(BIN) - -install: $(BIN) - -# How does one unit test a linker script? -utest generate_exp: - @echo > /dev/null - -$(BIN): acess_$(ARCHDIR).ld.h - @mkdir -p $(dir $(BIN)) - cpp -nostdinc -U i386 -P -C $< -o $@ -D__LIBDIR=$(OUTPUTDIR)Libs - -acess_$(ARCHDIR).ld.h: - $(LD) --verbose | awk '{ if( substr($$0,0,5) == "====="){ bPrint = !bPrint; } else { if(bPrint){ print $$0;} } }' | sed 's/SEARCH_DIR\(.*\)/SEARCH_DIR(__LIBDIR)/' > $@ diff --git a/Usermode/Libraries/acess.ld_src/acess_armv6.ld.h b/Usermode/Libraries/acess.ld_src/acess_armv6.ld.h deleted file mode 100644 index 0ea7f9029a563ffd212c20e14b553a3996436326..0000000000000000000000000000000000000000 --- a/Usermode/Libraries/acess.ld_src/acess_armv6.ld.h +++ /dev/null @@ -1,235 +0,0 @@ -/* Script for -z combreloc: combine and sort reloc sections */ -OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", - "elf32-littlearm") -OUTPUT_ARCH(arm) -ENTRY(_start) -SEARCH_DIR(__LIBDIR) -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x8000)); . = SEGMENT_START("text-segment", 0x8000); - .interp : { *(.interp) } - .note.gnu.build-id : { *(.note.gnu.build-id) } - .hash : { *(.hash) } - .gnu.hash : { *(.gnu.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.dyn : - { - *(.rel.init) - *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) - *(.rel.fini) - *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) - *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) - *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) - *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) - *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) - *(.rel.ctors) - *(.rel.dtors) - *(.rel.got) - *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) - PROVIDE_HIDDEN (__rel_iplt_start = .); - *(.rel.iplt) - PROVIDE_HIDDEN (__rel_iplt_end = .); - PROVIDE_HIDDEN (__rela_iplt_start = .); - PROVIDE_HIDDEN (__rela_iplt_end = .); - } - .rela.dyn : - { - *(.rela.init) - *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) - *(.rela.fini) - *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) - *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) - *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) - *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) - *(.rela.ctors) - *(.rela.dtors) - *(.rela.got) - *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) - PROVIDE_HIDDEN (__rel_iplt_start = .); - PROVIDE_HIDDEN (__rel_iplt_end = .); - PROVIDE_HIDDEN (__rela_iplt_start = .); - *(.rela.iplt) - PROVIDE_HIDDEN (__rela_iplt_end = .); - } - .rel.plt : - { - *(.rel.plt) - } - .rela.plt : - { - *(.rela.plt) - } - .init : - { - KEEP (*(.init)) - } =0 - .plt : { *(.plt) } - .iplt : { *(.iplt) } - .text : - { - *(.text.unlikely .text.*_unlikely) - *(.text.exit .text.exit.*) - *(.text.startup .text.startup.*) - *(.text.hot .text.hot.*) - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) - } =0 - .fini : - { - KEEP (*(.fini)) - } =0 - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } - PROVIDE_HIDDEN(__exidx_start = .); - .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } - PROVIDE_HIDDEN(__exidx_end = .); - .eh_frame_hdr : { *(.eh_frame_hdr) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)); - /* Exception handling */ - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } - /* Thread Local Storage sections */ - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - .preinit_array : - { - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP (*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - } - .init_array : - { - PROVIDE_HIDDEN (__init_array_start = .); - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - } - .fini_array : - { - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP (*(SORT(.fini_array.*))) - KEEP (*(.fini_array)) - PROVIDE_HIDDEN (__fini_array_end = .); - } - .ctors : - { - /* gcc uses crtbegin.o to find the start of - the constructors, so we make sure it is - first. Because this is a wildcard, it - doesn't matter if the user does not - actually link against crtbegin.o; the - linker won't look for a file to match a - wildcard. The wildcard also means that it - doesn't matter which directory crtbegin.o - is in. */ - KEEP (*crtbegin.o(.ctors)) - KEEP (*crtbegin?.o(.ctors)) - /* We don't want to include the .ctor section from - the crtend.o file until after the sorted ctors. - The .ctor section from the crtend file contains the - end of ctors marker and it must be last */ - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - .dtors : - { - KEEP (*crtbegin.o(.dtors)) - KEEP (*crtbegin?.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - .jcr : { KEEP (*(.jcr)) } - .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } - .dynamic : { *(.dynamic) } - .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } - .data : - { - __data_start = . ; - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - _edata = .; PROVIDE (edata = .); - __bss_start = .; - __bss_start__ = .; - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. - FIXME: Why do we need it? When there is no .bss section, we don't - pad the .data section. */ - . = ALIGN(. != 0 ? 32 / 8 : 1); - } - _bss_end__ = . ; __bss_end__ = . ; - . = ALIGN(32 / 8); - . = ALIGN(32 / 8); - __end__ = . ; - _end = .; PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo .zdebug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames .zdebug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges .zdebug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames .zdebug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.* .zdebug_info) } - .debug_abbrev 0 : { *(.debug_abbrev .zdebug_abbrev) } - .debug_line 0 : { *(.debug_line .zdebug_line) } - .debug_frame 0 : { *(.debug_frame .zdebug_frame) } - .debug_str 0 : { *(.debug_str .zdebug_str) } - .debug_loc 0 : { *(.debug_loc .zdebug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo .zdebug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames .zdebug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames .zdebug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames .zdebug_typenames) } - .debug_varnames 0 : { *(.debug_varnames .zdebug_varnames) } - /* DWARF 3 */ - .debug_pubtypes 0 : { *(.debug_pubtypes .zdebug_pubtypes) } - .debug_ranges 0 : { *(.debug_ranges .zdebug_ranges) } - .stack 0x80000 : - { - _stack = .; - *(.stack) - } - .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) } - .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } -} - - diff --git a/Usermode/Libraries/acess.ld_src/acess_armv7.ld.h b/Usermode/Libraries/acess.ld_src/acess_armv7.ld.h deleted file mode 100644 index 24c4af34ad39afaf9a445f48d99428f98410c470..0000000000000000000000000000000000000000 --- a/Usermode/Libraries/acess.ld_src/acess_armv7.ld.h +++ /dev/null @@ -1,236 +0,0 @@ -/* Script for -z combreloc: combine and sort reloc sections */ -OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", - "elf32-littlearm") -OUTPUT_ARCH(arm) -ENTRY(start) -SEARCH_DIR(__LIBDIR) -INPUT(crt0.o) -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x8000)); . = SEGMENT_START("text-segment", 0x8000) + SIZEOF_HEADERS; - .interp : { *(.interp) } - .note.gnu.build-id : { *(.note.gnu.build-id) } - .hash : { *(.hash) } - .gnu.hash : { *(.gnu.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.dyn : - { - *(.rel.init) - *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) - *(.rel.fini) - *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) - *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) - *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) - *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) - *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) - *(.rel.ctors) - *(.rel.dtors) - *(.rel.got) - *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) - PROVIDE_HIDDEN (__rel_iplt_start = .); - *(.rel.iplt) - PROVIDE_HIDDEN (__rel_iplt_end = .); - PROVIDE_HIDDEN (__rela_iplt_start = .); - PROVIDE_HIDDEN (__rela_iplt_end = .); - } - .rela.dyn : - { - *(.rela.init) - *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) - *(.rela.fini) - *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) - *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) - *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) - *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) - *(.rela.ctors) - *(.rela.dtors) - *(.rela.got) - *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) - PROVIDE_HIDDEN (__rel_iplt_start = .); - PROVIDE_HIDDEN (__rel_iplt_end = .); - PROVIDE_HIDDEN (__rela_iplt_start = .); - *(.rela.iplt) - PROVIDE_HIDDEN (__rela_iplt_end = .); - } - .rel.plt : - { - *(.rel.plt) - } - .rela.plt : - { - *(.rela.plt) - } - .init : - { - KEEP (*(.init)) - } =0 - .plt : { *(.plt) } - .iplt : { *(.iplt) } - .text : - { - *(.text.unlikely .text.*_unlikely) - *(.text.exit .text.exit.*) - *(.text.startup .text.startup.*) - *(.text.hot .text.hot.*) - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) - } =0 - .fini : - { - KEEP (*(.fini)) - } =0 - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } - PROVIDE_HIDDEN (__exidx_start = .); - .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } - PROVIDE_HIDDEN (__exidx_end = .); - .eh_frame_hdr : { *(.eh_frame_hdr) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)); - /* Exception handling */ - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } - /* Thread Local Storage sections */ - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - .preinit_array : - { - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP (*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - } - .init_array : - { - PROVIDE_HIDDEN (__init_array_start = .); - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - } - .fini_array : - { - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP (*(SORT(.fini_array.*))) - KEEP (*(.fini_array)) - PROVIDE_HIDDEN (__fini_array_end = .); - } - .ctors : - { - /* gcc uses crtbegin.o to find the start of - the constructors, so we make sure it is - first. Because this is a wildcard, it - doesn't matter if the user does not - actually link against crtbegin.o; the - linker won't look for a file to match a - wildcard. The wildcard also means that it - doesn't matter which directory crtbegin.o - is in. */ - KEEP (*crtbegin.o(.ctors)) - KEEP (*crtbegin?.o(.ctors)) - /* We don't want to include the .ctor section from - the crtend.o file until after the sorted ctors. - The .ctor section from the crtend file contains the - end of ctors marker and it must be last */ - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - .dtors : - { - KEEP (*crtbegin.o(.dtors)) - KEEP (*crtbegin?.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - .jcr : { KEEP (*(.jcr)) } - .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } - .dynamic : { *(.dynamic) } - .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } - .data : - { - __data_start = . ; - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - _edata = .; PROVIDE (edata = .); - __bss_start = .; - __bss_start__ = .; - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. - FIXME: Why do we need it? When there is no .bss section, we don't - pad the .data section. */ - . = ALIGN(. != 0 ? 32 / 8 : 1); - } - _bss_end__ = . ; __bss_end__ = . ; - . = ALIGN(32 / 8); - . = ALIGN(32 / 8); - __end__ = . ; - _end = .; PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo .zdebug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames .zdebug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges .zdebug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames .zdebug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.* .zdebug_info) } - .debug_abbrev 0 : { *(.debug_abbrev .zdebug_abbrev) } - .debug_line 0 : { *(.debug_line .zdebug_line) } - .debug_frame 0 : { *(.debug_frame .zdebug_frame) } - .debug_str 0 : { *(.debug_str .zdebug_str) } - .debug_loc 0 : { *(.debug_loc .zdebug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo .zdebug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames .zdebug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames .zdebug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames .zdebug_typenames) } - .debug_varnames 0 : { *(.debug_varnames .zdebug_varnames) } - /* DWARF 3 */ - .debug_pubtypes 0 : { *(.debug_pubtypes .zdebug_pubtypes) } - .debug_ranges 0 : { *(.debug_ranges .zdebug_ranges) } - .stack 0x80000 : - { - _stack = .; - *(.stack) - } - .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) } - .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } -} - - diff --git a/Usermode/Libraries/acess.ld_src/acess_x86.ld.h b/Usermode/Libraries/acess.ld_src/acess_x86.ld.h deleted file mode 100644 index e81c0a56fb71579aed01db1cab31a368296d8773..0000000000000000000000000000000000000000 --- a/Usermode/Libraries/acess.ld_src/acess_x86.ld.h +++ /dev/null @@ -1,199 +0,0 @@ -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) -ENTRY(start) -SEARCH_DIR(__LIBDIR) -INPUT(crt0.o) -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - PROVIDE (__executable_start = 0x08048000); . = 0x08048000 + SIZEOF_HEADERS; - .interp : { *(.interp) } - .note.gnu.build-id : { *(.note.gnu.build-id) } - .hash : { *(.hash) } - .gnu.hash : { *(.gnu.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.dyn : - { - *(.rel.init) - *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) - *(.rel.fini) - *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) - *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) - *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) - *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) - *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) - *(.rel.ctors) - *(.rel.dtors) - *(.rel.got) - *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) - } - .rela.dyn : - { - *(.rela.init) - *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) - *(.rela.fini) - *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) - *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) - *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) - *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) - *(.rela.ctors) - *(.rela.dtors) - *(.rela.got) - *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) - } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : - { - KEEP (*(.init)) - } =0x90909090 - .plt : { *(.plt) } - .text : - { - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } =0x90909090 - .fini : - { - KEEP (*(.fini)) - } =0x90909090 - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .eh_frame_hdr : { *(.eh_frame_hdr) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); - /* Exception handling */ - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } - /* Thread Local Storage sections */ - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - .preinit_array : - { - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP (*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - } - .init_array : - { - PROVIDE_HIDDEN (__init_array_start = .); - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - } - .fini_array : - { - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - PROVIDE_HIDDEN (__fini_array_end = .); - } - .ctors : - { - /* gcc uses crtbegin.o to find the start of - the constructors, so we make sure it is - first. Because this is a wildcard, it - doesn't matter if the user does not - actually link against crtbegin.o; the - linker won't look for a file to match a - wildcard. The wildcard also means that it - doesn't matter which directory crtbegin.o - is in. */ - KEEP (*crtbegin.o(.ctors)) - KEEP (*crtbegin?.o(.ctors)) - /* We don't want to include the .ctor section from - the crtend.o file until after the sorted ctors. - The .ctor section from the crtend file contains the - end of ctors marker and it must be last */ - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - .dtors : - { - KEEP (*crtbegin.o(.dtors)) - KEEP (*crtbegin?.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - .jcr : { KEEP (*(.jcr)) } - .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } - .dynamic : { *(.dynamic) } - .got : { *(.got) } - . = DATA_SEGMENT_RELRO_END (12, .); - .got.plt : { *(.got.plt) } - .data : - { - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - _edata = .; PROVIDE (edata = .); - __bss_start = .; - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. - FIXME: Why do we need it? When there is no .bss section, we don't - pad the .data section. */ - . = ALIGN(. != 0 ? 32 / 8 : 1); - } - . = ALIGN(32 / 8); - . = ALIGN(32 / 8); - _end = .; PROVIDE (end = .); - . = DATA_SEGMENT_END (.); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /* DWARF 3 */ - .debug_pubtypes 0 : { *(.debug_pubtypes) } - .debug_ranges 0 : { *(.debug_ranges) } - .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) } -} diff --git a/Usermode/Libraries/acess.ld_src/acess_x86_64.ld.h b/Usermode/Libraries/acess.ld_src/acess_x86_64.ld.h deleted file mode 100644 index 469e4afd2df4235a6cf0078e7015ba1cc647f5e2..0000000000000000000000000000000000000000 --- a/Usermode/Libraries/acess.ld_src/acess_x86_64.ld.h +++ /dev/null @@ -1,199 +0,0 @@ -OUTPUT_FORMAT("elf64-x86-64") -/* OUTPUT_ARCH(x86_64) */ -ENTRY(start) -SEARCH_DIR(__LIBDIR) -INPUT(crt0.o) -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - PROVIDE (__executable_start = 0x00400000); . = 0x00400000 + SIZEOF_HEADERS; - .interp : { *(.interp) } - .note.gnu.build-id : { *(.note.gnu.build-id) } - .hash : { *(.hash) } - .gnu.hash : { *(.gnu.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.dyn : - { - *(.rel.init) - *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) - *(.rel.fini) - *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) - *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) - *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) - *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) - *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) - *(.rel.ctors) - *(.rel.dtors) - *(.rel.got) - *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) - } - .rela.dyn : - { - *(.rela.init) - *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) - *(.rela.fini) - *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) - *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) - *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) - *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) - *(.rela.ctors) - *(.rela.dtors) - *(.rela.got) - *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) - } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : - { - KEEP (*(.init)) - } =0x90909090 - .plt : { *(.plt) } - .text : - { - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } =0x90909090 - .fini : - { - KEEP (*(.fini)) - } =0x90909090 - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .eh_frame_hdr : { *(.eh_frame_hdr) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); - /* Exception handling */ - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } - /* Thread Local Storage sections */ - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - .preinit_array : - { - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP (*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - } - .init_array : - { - PROVIDE_HIDDEN (__init_array_start = .); - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - } - .fini_array : - { - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - PROVIDE_HIDDEN (__fini_array_end = .); - } - .ctors : - { - /* gcc uses crtbegin.o to find the start of - the constructors, so we make sure it is - first. Because this is a wildcard, it - doesn't matter if the user does not - actually link against crtbegin.o; the - linker won't look for a file to match a - wildcard. The wildcard also means that it - doesn't matter which directory crtbegin.o - is in. */ - KEEP (*crtbegin.o(.ctors)) - KEEP (*crtbegin?.o(.ctors)) - /* We don't want to include the .ctor section from - the crtend.o file until after the sorted ctors. - The .ctor section from the crtend file contains the - end of ctors marker and it must be last */ - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - .dtors : - { - KEEP (*crtbegin.o(.dtors)) - KEEP (*crtbegin?.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - .jcr : { KEEP (*(.jcr)) } - .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } - .dynamic : { *(.dynamic) } - .got : { *(.got) } - . = DATA_SEGMENT_RELRO_END (12, .); - .got.plt : { *(.got.plt) } - .data : - { - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - _edata = .; PROVIDE (edata = .); - __bss_start = .; - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. - FIXME: Why do we need it? When there is no .bss section, we don't - pad the .data section. */ - . = ALIGN(. != 0 ? 32 / 8 : 1); - } - . = ALIGN(32 / 8); - . = ALIGN(32 / 8); - _end = .; PROVIDE (end = .); - . = DATA_SEGMENT_END (.); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /* DWARF 3 */ - .debug_pubtypes 0 : { *(.debug_pubtypes) } - .debug_ranges 0 : { *(.debug_ranges) } - .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) } -} diff --git a/Usermode/Libraries/acess.ld_src/rules.mk b/Usermode/Libraries/acess.ld_src/rules.mk deleted file mode 100644 index f2f3de02016663fd0100e454b4850f2df7091b8a..0000000000000000000000000000000000000000 --- a/Usermode/Libraries/acess.ld_src/rules.mk +++ /dev/null @@ -1,20 +0,0 @@ -include $(BASE)header.mk - -# Variables -BIN = $(OUTPUTDIR)Libs/acess.ld - -# Rules -.PHONY: all-$(DIR) - -all-$(DIR): $(BIN) -clean-$(DIR): - $(RM) $(BIN) - -$(BIN): $(DIR)/acess_$(ARCHDIR).ld.h - @mkdir -p $(dir $(BIN)) - cpp -nostdinc -U i386 -P -C $< -o $@ -D__LIBDIR=$(OUTPUTDIR)Libs - -$(DIR)/acess_$(ARCHDIR).ld.h: - $(LD) --verbose | awk '{ if( substr($$0,0,5) == "====="){ bPrint = !bPrint; } else { if(bPrint){ print $$0;} } }' | sed 's/SEARCH_DIR\(.*\)/SEARCH_DIR(__LIBDIR)/' > $@ - -include $(BASE)footer.mk diff --git a/Usermode/Libraries/crt0.o_src/Makefile b/Usermode/Libraries/crt0.o_src/Makefile index 7ddc5f413966bc7f3ab61231729a46e3842b7993..29bdb0eee225035457c6ace03cf58f4c8e049d7f 100644 --- a/Usermode/Libraries/crt0.o_src/Makefile +++ b/Usermode/Libraries/crt0.o_src/Makefile @@ -4,9 +4,11 @@ -include ../Makefile.cfg -BIN = $(OUTPUTDIR)Libs/crt0.o $(OUTPUTDIR)Libs/crtbegin.o $(OUTPUTDIR)Libs/crtend.o +BIN = $(OUTPUTDIR)Libs/crt0.o $(OUTPUTDIR)Libs/crt0S.o $(OUTPUTDIR)Libs/crti.o $(OUTPUTDIR)Libs/crtn.o -.PHONY: all clean install utest generate_exp +CFLAGS := -std=c99 + +.PHONY: all clean install utest utest-build generate_exp all: $(BIN) @@ -16,22 +18,16 @@ clean: $(RM) $(BIN) # Disabled unit tests -utest generate_exp: +utest generate_exp utest-build utest-run: @echo > /dev/null -$(OUTPUTDIR)Libs/%.o: %.c +$(OUTPUTDIR)Libs/%S.o: %S.c Makefile @mkdir -p $(dir $@) - $(CC) -c $< -o $@ - -#$(OUTPUTDIR)Libs/crt0.o: obj-$(ARCH)/crt0_asm.o obj-$(ARCH)/crt0_c.o -# @mkdir -p $(dir $@) -# $(LD) -r -o $@ $? - -#obj-$(ARCH)/crt0_asm.o: crt0.$(ARCHDIR).$(ASSUFFIX) -# @mkdir -p $(dir $@) -# $(AS) $(ASFLAGS) $< -o $@ - -#obj-$(ARCH)/crt0_c.o: crt0.c -# @mkdir -p $(dir $@) -# $(CC) -c $< -o $@ + $(CC) $(CFLAGS) -c $< -o $@ -fPIC +$(OUTPUTDIR)Libs/%.o: %.c Makefile + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c $< -o $@ +$(OUTPUTDIR)Libs/%.o: $(ARCHDIR)-%.S + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c $< -o $@ diff --git a/Usermode/Libraries/crt0.o_src/armv7-crti.S b/Usermode/Libraries/crt0.o_src/armv7-crti.S new file mode 100644 index 0000000000000000000000000000000000000000..310cd6abad9f81bc48a20c8d93491825c20f33f2 --- /dev/null +++ b/Usermode/Libraries/crt0.o_src/armv7-crti.S @@ -0,0 +1,31 @@ +.section .init +.global _init +.type _init, function +_init: +#ifdef __thumb__ + .thumb + + push {r3, r4, r5, r6, r7, lr} +#else + .arm + mov ip, sp + stmdb sp!, {r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc} + sub fp, ip, #4 +#endif + /* gcc will nicely put the contents of crtbegin.o's .init section here. */ + +.section .fini +.global _fini +.type _fini, function +_fini: +#ifdef __thumb__ + .thumb + + push {r3, r4, r5, r6, r7, lr} +#else + .arm + mov ip, sp + stmdb sp!, {r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc} + sub fp, ip, #4 +#endif + /* gcc will nicely put the contents of crtbegin.o's .fini section here. */ diff --git a/Usermode/Libraries/crt0.o_src/armv7-crtn.S b/Usermode/Libraries/crt0.o_src/armv7-crtn.S new file mode 100644 index 0000000000000000000000000000000000000000..1c3e1113e82be2b18a637484f8bda441e1a9e67f --- /dev/null +++ b/Usermode/Libraries/crt0.o_src/armv7-crtn.S @@ -0,0 +1,41 @@ +.section .init + /* gcc will nicely put the contents of crtend.o's .init section here. */ +#ifdef __thumb__ + .thumb + + pop {r3, r4, r5, r6, r7} + pop {r3} + mov lr, r3 +#else + .arm + + sub sp, fp, #40 + ldmfd sp, {r4, r5, r6, r7, r8, r9, sl, fp, sp, lr} +#endif + +#if defined __THUMB_INTERWORK__ || defined __thumb__ + bx lr +#else + mov pc, lr +#endif + +.section .fini + /* gcc will nicely put the contents of crtend.o's .fini section here. */ +#ifdef __thumb__ + .thumb + + pop {r3, r4, r5, r6, r7} + pop {r3} + mov lr, r3 +#else + .arm + + sub sp, fp, #40 + ldmfd sp, {r4, r5, r6, r7, r8, r9, sl, fp, sp, lr} +#endif + +#if defined __THUMB_INTERWORK__ || defined __thumb__ + bx lr +#else + mov pc, lr +#endif diff --git a/Usermode/Libraries/crt0.o_src/crt0.c b/Usermode/Libraries/crt0.o_src/crt0.c index 8363aea9ae889bcdf02e098e47123f77fc06f14d..3cdbe119df16cb2fe37bd203fc2a95ec876f442e 100644 --- a/Usermode/Libraries/crt0.o_src/crt0.c +++ b/Usermode/Libraries/crt0.o_src/crt0.c @@ -9,7 +9,8 @@ typedef void (*constructor_t)(void); constructor_t _crtbegin_ctors[0] __attribute__((section(".ctors"))); exithandler_t _crt0_exit_handler; -//extern constructor_t _crtbegin_ctors[]; +extern void _init(void); +extern void _fini(void); extern void _exit(int status) __attribute__((noreturn)); extern int main(int argc, char *argv[], char **envp); @@ -17,16 +18,16 @@ void _start(int argc, char *argv[], char **envp) __attribute__ ((alias("start")) void start(int argc, char *argv[], char **envp) { - int i; - int rv; - - for( i = 0; _crtbegin_ctors[i]; i ++ ) + // TODO: isn't this handled by _init? + for( int i = 0; _crtbegin_ctors[i]; i ++ ) _crtbegin_ctors[i](); + + _init(); - rv = main(argc, argv, envp); + int rv = main(argc, argv, envp); if( _crt0_exit_handler ) _crt0_exit_handler(); - + _fini(); _exit(rv); } diff --git a/Usermode/Libraries/crt0.o_src/crt0S.c b/Usermode/Libraries/crt0.o_src/crt0S.c new file mode 100644 index 0000000000000000000000000000000000000000..1f35ce4519f9d374c4e4ab5e83d004fef9f63f9d --- /dev/null +++ b/Usermode/Libraries/crt0.o_src/crt0S.c @@ -0,0 +1,23 @@ +/* + * Acess2 + * - CRT0 Shared library version + */ + +typedef void (*exithandler_t)(void); +typedef void (*constructor_t)(void); + +extern void _SysDebug(const char *, ...); +extern void _init(void); +extern void _fini(void); +extern int SoMain(void *Base, int argc, char *argv[], char **envp) __attribute__((weak)); + +int SoStart(void *Base, int argc, char *argv[], char **envp) +{ + //_SysDebug("SoStart(%p,%i,%p)", Base, argc, argv); + _init(); + + if( SoMain ) + return SoMain(Base, argc, argv, envp); + else + return 0; +} diff --git a/Usermode/Libraries/crt0.o_src/native-crti.S b/Usermode/Libraries/crt0.o_src/native-crti.S new file mode 100644 index 0000000000000000000000000000000000000000..01c8127f0dbf3aeaf528cc437e496789a03ef104 --- /dev/null +++ b/Usermode/Libraries/crt0.o_src/native-crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +.type _init, @function +_init: + /* gcc will nicely put the contents of crtbegin.o's .init section here. */ + +.section .fini +.global _fini +.type _fini, @function +_fini: + /* gcc will nicely put the contents of crtbegin.o's .fini section here. */ diff --git a/Usermode/Libraries/crt0.o_src/native-crtn.S b/Usermode/Libraries/crt0.o_src/native-crtn.S new file mode 100644 index 0000000000000000000000000000000000000000..f884c09d9a69e06a0d43cc0515370b0bdb4be520 --- /dev/null +++ b/Usermode/Libraries/crt0.o_src/native-crtn.S @@ -0,0 +1,7 @@ +.section .init + /* gcc will nicely put the contents of crtend.o's .init section here. */ + ret + +.section .fini + ret + /* gcc will nicely put the contents of crtend.o's .fini section here. */ diff --git a/Usermode/Libraries/crt0.o_src/x86-crti.S b/Usermode/Libraries/crt0.o_src/x86-crti.S new file mode 100644 index 0000000000000000000000000000000000000000..cebea3e9007fd8d0a8ade3044c3906a373fec50a --- /dev/null +++ b/Usermode/Libraries/crt0.o_src/x86-crti.S @@ -0,0 +1,15 @@ +.section .init +.global _init +.type _init, @function +_init: + push %ebp + movl %esp, %ebp + /* gcc will nicely put the contents of crtbegin.o's .init section here. */ + +.section .fini +.global _fini +.type _fini, @function +_fini: + push %ebp + movl %esp, %ebp + /* gcc will nicely put the contents of crtbegin.o's .fini section here. */ diff --git a/Usermode/Libraries/crt0.o_src/x86-crtn.S b/Usermode/Libraries/crt0.o_src/x86-crtn.S new file mode 100644 index 0000000000000000000000000000000000000000..33957bfe1686086de0d8978421eed3c8245fef9e --- /dev/null +++ b/Usermode/Libraries/crt0.o_src/x86-crtn.S @@ -0,0 +1,9 @@ +.section .init + /* gcc will nicely put the contents of crtend.o's .init section here. */ + popl %ebp + ret + +.section .fini + /* gcc will nicely put the contents of crtend.o's .fini section here. */ + popl %ebp + ret diff --git a/Usermode/Libraries/crt0.o_src/x86_64-crti.S b/Usermode/Libraries/crt0.o_src/x86_64-crti.S new file mode 100644 index 0000000000000000000000000000000000000000..fb7dad336830a1d34ea825053de605ae62ea07b8 --- /dev/null +++ b/Usermode/Libraries/crt0.o_src/x86_64-crti.S @@ -0,0 +1,15 @@ +.section .init +.global _init +.type _init, @function +_init: + push %rbp + mov %rsp, %rbp + /* gcc will nicely put the contents of crtbegin.o's .init section here. */ + +.section .fini +.global _fini +.type _fini, @function +_fini: + push %rbp + mov %rsp, %rbp + /* gcc will nicely put the contents of crtbegin.o's .fini section here. */ diff --git a/Usermode/Libraries/crt0.o_src/x86_64-crtn.S b/Usermode/Libraries/crt0.o_src/x86_64-crtn.S new file mode 100644 index 0000000000000000000000000000000000000000..ec78f0b3cb6dea8f033a9656c255ada797e8f762 --- /dev/null +++ b/Usermode/Libraries/crt0.o_src/x86_64-crtn.S @@ -0,0 +1,9 @@ +.section .init + /* gcc will nicely put the contents of crtend.o's .init section here. */ + pop %rbp + ret + +.section .fini + /* gcc will nicely put the contents of crtend.o's .fini section here. */ + pop %rbp + ret diff --git a/Usermode/Libraries/ld-acess.so_src/Makefile b/Usermode/Libraries/ld-acess.so_src/Makefile index 4dc881c09ca2ed4ce5c8e03bac892cb27d49fb91..d6691e401c731185a9ba6803caa54582e7021689 100644 --- a/Usermode/Libraries/ld-acess.so_src/Makefile +++ b/Usermode/Libraries/ld-acess.so_src/Makefile @@ -11,10 +11,12 @@ EXTRABIN := libld-acess.so EXTRACLEAN = $(_OBJPREFIX)_stublib.o INCFILES := sys/sys.h -CFLAGS = -g -Wall -fno-builtin -fno-stack-protector -fPIC -std=c99 +#CPPFLAGS += -D DISABLE_ELF64 +CFLAGS = -g -Wall -fno-builtin -fno-stack-protector -fPIC -std=c99 -ffreestanding # -fno-leading-underscore CFLAGS += $(CPPFLAGS) -LDFLAGS = -g -T arch/$(ARCHDIR).ld -Map map.txt --export-dynamic +LDFLAGS = -ffreestanding -nostdlib -g -Wl,-T,arch/$(ARCHDIR).ld -Map map.txt --export-dynamic -x +LIBS := $(LIBGCC_PATH) ifeq ($(ARCH),native) XBIN := $(addprefix $(OUTPUTDIR)Libs/,$(EXTRABIN)) @@ -31,15 +33,15 @@ include ../Makefile.tpl # create libld-acess.so $(_XBIN): $(_OBJPREFIX)_stublib.o @echo [LD] -o -shared libld-acess.so - $(LD) -shared -o $@ $< + $V$(LD) -shared -o $@ $< # @$(LD) $(LDFLAGS) -o $@ $(OBJ) # Override .ao to look in the object prefix for the source -$(_OBJPREFIX)arch/$(ARCHDIR).ao_: $(_OBJPREFIX)arch/$(ARCHDIR).$(ASSUFFIX) +$(_OBJPREFIX)arch/$(ARCHDIR).ao_: $(_OBJPREFIX)arch/$(ARCHDIR).$(ASSUFFIX) Makefile @echo [AS] -o $@ @mkdir -p $(dir $@) - @$(AS) $(ASFLAGS) -o $@ $< + $V$(AS) $(ASFLAGS) -o $@ $< #.PRECIOUS: $(OBJ:%.ao=%.asm) @@ -47,7 +49,7 @@ $(_OBJPREFIX)arch/$(ARCHDIR).ao_: $(_OBJPREFIX)arch/$(ARCHDIR).$(ASSUFFIX) $(_OBJPREFIX)arch/$(ARCHDIR).$(ASSUFFIX): arch/$(ARCHDIR).$(ASSUFFIX).h arch/syscalls.s.h @echo [CPP] -o $@ @mkdir -p $(dir $@) - @$(CPP) $(CPPFLAGS) -P -D__ASSEMBLER__ $< -o $@ + $V$(CPP) $(CPPFLAGS) -P -D__ASSEMBLER__ $< -o $@ $(_OBJPREFIX)arch/$(ARCHDIR).$(ASSUFFIX): $(ACESSDIR)/KernelLand/Kernel/include/syscalls.h diff --git a/Usermode/Libraries/ld-acess.so_src/arch/armv7.S.h b/Usermode/Libraries/ld-acess.so_src/arch/armv7.S.h index 351c84147c43f2867c49b632548e5335b0557a13..7e604f1d85bd192374d8332ad56673b38e184e9b 100644 --- a/Usermode/Libraries/ld-acess.so_src/arch/armv7.S.h +++ b/Usermode/Libraries/ld-acess.so_src/arch/armv7.S.h @@ -16,7 +16,7 @@ _start: b _exit -@ Stupid GCC +// Stupid GCC .globl __ucmpdi2 __ucmpdi2: cmp r0, r2 @@ -32,8 +32,8 @@ __ucmpdi2: mov r0, #1 mov pc, lr -@ Well, can't blame it -@ - Clear the instruction cache +//@ Well, can't blame it +// - Clear the instruction cache .globl __clear_cache __clear_cache: svc #0x1001 diff --git a/Usermode/Libraries/ld-acess.so_src/arch/syscalls.s.h b/Usermode/Libraries/ld-acess.so_src/arch/syscalls.s.h index 7f0acb83528533f153b728acd4ad180222ffaf4a..1b9c3e82123e1fd05ef163e5bedf75b587b47a58 100644 --- a/Usermode/Libraries/ld-acess.so_src/arch/syscalls.s.h +++ b/Usermode/Libraries/ld-acess.so_src/arch/syscalls.s.h @@ -37,7 +37,11 @@ SYSCALL1(_SysSetFaultHandler, SYS_SETFAULTHANDLER) SYSCALL1(_SysLoadModule, SYS_LOADMOD) -SYSCALL6(_SysDebug, 0x100) +SYSCALL6(_ZN4_sys5debugEPKcz, SYS_DEBUGF) +SYSCALL6(_SysDebug, SYS_DEBUGF) +//SYSCALL3(_SysDebugS, SYS_DEBUGS) +SYSCALL3(_SysDebugHex, SYS_DEBUGHEX) + SYSCALL1(_SysGetPhys, SYS_GETPHYS) // uint64_t _SysGetPhys(uint addr) SYSCALL1(_SysAllocate, SYS_ALLOCATE) // uint64_t _SysAllocate(uint addr) SYSCALL3(_SysSetMemFlags, SYS_SETFLAGS) // uint32_t SysSetMemFlags(uint addr, uint flags, uint mask) @@ -49,7 +53,10 @@ SYSCALL2(_SysCopyFD, SYS_COPYFD) // int, int SYSCALL3(_SysFDFlags, SYS_FDCTL) // int, int, int SYSCALL1(_SysClose, SYS_CLOSE) // int SYSCALL3(_SysRead, SYS_READ) // int, uint, void* +SYSCALL5(_SysReadAt, SYS_READAT) // int, uint, uint64, void* SYSCALL3(_SysWrite, SYS_WRITE) // int, uint, void* +SYSCALL5(_SysWriteAt, SYS_WRITEAT) // int, uint, uint64, void* +SYSCALL3(_SysTruncate, SYS_TRUNCATE) // int, uint64 SYSCALL4(_SysSeek, SYS_SEEK) // int, uint64_t, int SYSCALL1(_SysTell, SYS_TELL) // int SYSCALL3(_SysFInfo, SYS_FINFO) // int, void*, int @@ -63,3 +70,9 @@ SYSCALL6(_SysSelect, SYS_SELECT) // int, fd_set*, fd_set*, fd_set*, tTime*, uint SYSCALL1(_SysMkDir, SYS_MKDIR) // const char* SYSCALL1(_SysUnlink, SYS_UNLINK) // const char* +SYSCALL6(_SysMMap, SYS_MMAP) +SYSCALL2(_SysMUnMap, SYS_MUNMAP) + +SYSCALL1(_SysMarshalFD, SYS_MARSHALFD) +SYSCALL2(_SysUnMarshalFD, SYS_UNMARSHALFD) + diff --git a/Usermode/Libraries/ld-acess.so_src/arch/x86_64.asm.h b/Usermode/Libraries/ld-acess.so_src/arch/x86_64.asm.h index 350585a0136f4e13493a9d8f44a2b15d37488052..b80e092ba2d2ec2df8d698668d22f91658be1fb5 100644 --- a/Usermode/Libraries/ld-acess.so_src/arch/x86_64.asm.h +++ b/Usermode/Libraries/ld-acess.so_src/arch/x86_64.asm.h @@ -56,9 +56,11 @@ _errno: dw 0 ; Placed in .text, to allow use of relative addressing [global %1:func] %1: push rbx + push rbp mov eax, %2 SYSCALL_OP mov [DWORD rel _errno], ebx + pop rbp pop rbx ret %endmacro diff --git a/Usermode/Libraries/ld-acess.so_src/common.h b/Usermode/Libraries/ld-acess.so_src/common.h index ac07f9c7365f2f0bd5d829c1461f132d6aed14dc..e0620c264da9224f642b9afaa818d9375091f304 100644 --- a/Usermode/Libraries/ld-acess.so_src/common.h +++ b/Usermode/Libraries/ld-acess.so_src/common.h @@ -41,7 +41,7 @@ extern void *DoRelocate(void *Base, char **envp, const char *Filename); // === Library/Symbol Manipulation == extern void *LoadLibrary(const char *Filename, const char *SearchDir, char **envp); extern void AddLoaded(const char *File, void *base); -extern int GetSymbol(const char *Name, void **Value, size_t *size); +extern int GetSymbol(const char *Name, void **Value, size_t *size, void *IgnoreBase); extern int GetSymbolFromBase(void *base, const char *name, void **ret, size_t *size); // === Library Functions === diff --git a/Usermode/Libraries/ld-acess.so_src/elf.c b/Usermode/Libraries/ld-acess.so_src/elf.c index 71e9a92baf9d0e125df9363d575338cac6c8f217..fa2e3f44da6ad793ccc9d914cb29469a2c85935d 100644 --- a/Usermode/Libraries/ld-acess.so_src/elf.c +++ b/Usermode/Libraries/ld-acess.so_src/elf.c @@ -4,8 +4,10 @@ * * elf.c * - ELF32/ELF64 relocation + * + * TODO: Have GetSymbol() return a symbol "strength" on success. Allows STB_WEAK to be overriden by STB_GLOBAL */ -#ifndef DEBUG // This code is #include'd from the kernel, so DEBUG may already be defined +#ifndef KERNEL_VERSION # define DEBUG 0 #endif @@ -15,6 +17,7 @@ #include "common.h" #include <stdint.h> +#include <stdbool.h> #ifndef assert # include <assert.h> #endif @@ -22,11 +25,16 @@ #include "elf64.h" #if DEBUG -# define DEBUGS(v...) SysDebug("ld-acess - " v) +# define DEBUG_OUT(...) SysDebug(__VA_ARGS__) #else -# define DEBUGS(...) +# define DEBUG_OUT(...) do{}while(0) //((void)(__VA_ARGS__)) #endif +#define WARNING(f,...) SysDebug("WARN: "f ,## __VA_ARGS__) // Malformed file +#define NOTICE(f,...) SysDebug("NOTICE: "f ,## __VA_ARGS__) // Missing relocation +//#define TRACE(f,...) DEBUG_OUT("TRACE:%s:%i "f, __func__, __LINE__ ,## __VA_ARGS__) // Debugging trace +#define TRACE(f,...) DEBUG_OUT("TRACE:%s "f, __func__,## __VA_ARGS__) // Debugging trace + #ifndef DISABLE_ELF64 # define SUPPORT_ELF64 #endif @@ -34,21 +42,20 @@ // === CONSTANTS === #if DEBUG //static const char *csaDT_NAMES[] = {"DT_NULL", "DT_NEEDED", "DT_PLTRELSZ", "DT_PLTGOT", "DT_HASH", "DT_STRTAB", "DT_SYMTAB", "DT_RELA", "DT_RELASZ", "DT_RELAENT", "DT_STRSZ", "DT_SYMENT", "DT_INIT", "DT_FINI", "DT_SONAME", "DT_RPATH", "DT_SYMBOLIC", "DT_REL", "DT_RELSZ", "DT_RELENT", "DT_PLTREL", "DT_DEBUG", "DT_TEXTREL", "DT_JMPREL"}; -static const char *csaR_NAMES[] = {"R_386_NONE", "R_386_32", "R_386_PC32", "R_386_GOT32", "R_386_PLT32", "R_386_COPY", "R_386_GLOB_DAT", "R_386_JMP_SLOT", "R_386_RELATIVE", "R_386_GOTOFF", "R_386_GOTPC", "R_386_LAST"}; +//static const char *csaR_NAMES[] = {"R_386_NONE", "R_386_32", "R_386_PC32", "R_386_GOT32", "R_386_PLT32", "R_386_COPY", "R_386_GLOB_DAT", "R_386_JMP_SLOT", "R_386_RELATIVE", "R_386_GOTOFF", "R_386_GOTPC", "R_386_LAST"}; +#endif + +#ifdef SUPPORT_ELF64 #endif // === PROTOTYPES === void *ElfRelocate(void *Base, char **envp, const char *Filename); int ElfGetSymbol(void *Base, const char *Name, void **Ret, size_t *Size); -void *Elf32Relocate(void *Base, char **envp, const char *Filename); - int Elf32GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size); - int elf_doRelocate_386(uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int type, int bRela, const char *Sym, intptr_t iBaseDiff); - int elf_doRelocate_arm(uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int type, int bRela, const char *Sym, intptr_t iBaseDiff); - int elf_doRelocate_unk(uint32_t , uint32_t *, Elf32_Addr , int , int , const char *, intptr_t); +void *Elf32_Relocate(void *Base, char **envp, const char *Filename); + int Elf32_GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size); #ifdef SUPPORT_ELF64 -int _Elf64DoReloc_X86_64(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend); -void *Elf64Relocate(void *Base, char **envp, const char *Filename); - int Elf64GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size); +void *Elf64_Relocate(void *Base, char **envp, const char *Filename); + int Elf64_GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size); #endif uint32_t ElfHashString(const char *name); @@ -64,10 +71,10 @@ void *ElfRelocate(void *Base, char **envp, const char *Filename) switch(hdr->e_ident[4]) { case ELFCLASS32: - return Elf32Relocate(Base, envp, Filename); + return Elf32_Relocate(Base, envp, Filename); #ifdef SUPPORT_ELF64 case ELFCLASS64: - return Elf64Relocate(Base, envp, Filename); + return Elf64_Relocate(Base, envp, Filename); #endif default: SysDebug("ld-acess - ElfRelocate: Unknown file class %i", hdr->e_ident[4]); @@ -85,10 +92,10 @@ int ElfGetSymbol(void *Base, const char *Name, void **ret, size_t *Size) switch(hdr->e_ident[4]) { case ELFCLASS32: - return Elf32GetSymbol(Base, Name, ret, Size); + return Elf32_GetSymbol(Base, Name, ret, Size); #ifdef SUPPORT_ELF64 case ELFCLASS64: - return Elf64GetSymbol(Base, Name, ret, Size); + return Elf64_GetSymbol(Base, Name, ret, Size); #endif default: SysDebug("ld-acess - ElfRelocate: Unknown file class %i", hdr->e_ident[4]); @@ -96,482 +103,219 @@ int ElfGetSymbol(void *Base, const char *Name, void **ret, size_t *Size) } } -int elf_doRelocate_386(uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int type, - int bRela, const char *Sym, intptr_t iBaseDiff) +// -------------------------------------------------------------------- +// Elf32 support +// -------------------------------------------------------------------- +#define ELFTYPE Elf32 +#include "elf_impl.c" +#undef ELFTYPE + +Elf32_RelocFcn elf_doRelocate_386; +Elf32_RelocFcn elf_doRelocate_arm; + +int elf_doRelocate_386(const Elf32_RelocInfo *Info, Elf32_Word r_info, Elf32_Word* ptr, Elf32_Addr addend, bool bRela) { - void *symval; - switch( type ) + const Elf32_Sym *sym = &Info->symtab[ ELF32_R_SYM(r_info) ]; + void *symval = (void*)(intptr_t)sym->st_value; + size_t size = sym->st_size; + TRACE("%i '%s'", ELF32_R_TYPE(r_info), Info->strtab + sym->st_name); + switch( ELF32_R_TYPE(r_info) ) { // Standard 32 Bit Relocation (S+A) case R_386_32: - if( !GetSymbol(Sym, &symval, NULL) ) - return 1; - DEBUGS(" elf_doRelocate: R_386_32 *0x%x += %p('%s')", - ptr, symval, Sym); + TRACE("R_386_32 *0x%x = %p + 0x%x", ptr, symval, addend); *ptr = (intptr_t)symval + addend; break; // 32 Bit Relocation wrt. Offset (S+A-P) case R_386_PC32: - DEBUGS(" elf_doRelocate: '%s'", Sym); - if( !GetSymbol(Sym, &symval, NULL) ) return 1; - DEBUGS(" elf_doRelocate: R_386_PC32 *0x%x = 0x%x + 0x%p - 0x%x", - ptr, *ptr, symval, (intptr_t)ptr ); + TRACE("R_386_PC32 *0x%x = 0x%x + 0x%p - 0x%x", ptr, *ptr, symval, (intptr_t)ptr ); *ptr = (intptr_t)symval + addend - (intptr_t)ptr; //*ptr = val + addend - ((Uint)ptr - iBaseDiff); break; // Absolute Value of a symbol (S) case R_386_GLOB_DAT: + TRACE("R_386_GLOB_DAT *0x%x = %p", ptr, symval); if(0) case R_386_JMP_SLOT: - DEBUGS(" elf_doRelocate: '%s'", Sym); - if( !GetSymbol(Sym, &symval, NULL) ) return 1; - DEBUGS(" elf_doRelocate: %s *0x%x = %p", csaR_NAMES[type], ptr, symval); + TRACE("R_386_JMP_SLOT *0x%x = %p", ptr, symval); *ptr = (intptr_t)symval; break; // Base Address (B+A) case R_386_RELATIVE: - DEBUGS(" elf_doRelocate: R_386_RELATIVE *0x%x = 0x%x + 0x%x", ptr, iBaseDiff, addend); - *ptr = iBaseDiff + addend; + TRACE("R_386_RELATIVE *0x%x = 0x%x + 0x%x", ptr, Info->iBaseDiff, addend); + *ptr = Info->iBaseDiff + addend; break; case R_386_COPY: { - size_t size; - if( !GetSymbol(Sym, &symval, &size) ) return 1; - DEBUGS(" elf_doRelocate_386: R_386_COPY (%p, %p, %i)", ptr, symval, size); - memcpy(ptr, symval, size); + void *old_symval = symval; + GetSymbol(Info->strtab + sym->st_name, &symval, &size, Info->Base); + if( symval == old_symval ) + { + if( ELF32_ST_BIND(sym->st_info) != STB_WEAK ) + { + WARNING("sym={val:%p,size:0x%x,info:0x%x,other:0x%x,shndx:%i}", + sym->st_value, sym->st_size, sym->st_info, sym->st_other, sym->st_shndx); + WARNING("Can't find required external symbol '%s' for R_386_COPY", Info->strtab + sym->st_name); + return 1; + } + // Don't bother doing the memcpy + TRACE("R_386_COPY (%p, %p, %i)", ptr, symval, size); + } + else + { + TRACE("R_386_COPY (%p, %p, %i)", ptr, symval, size); + memcpy(ptr, symval, size); + } break; } default: - SysDebug("elf_doRelocate_386: Unknown relocation %i", type); + WARNING("Unknown relocation %i", ELF32_ST_TYPE(r_info)); return 2; } return 0; } -int elf_doRelocate_arm(uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int type, int bRela, const char *Sym, intptr_t iBaseDiff) +int elf_doRelocate_arm(const Elf32_RelocInfo *Info, Elf32_Word r_info, Elf32_Word* ptr, Elf32_Addr addend, bool bRela) { - uint32_t val; - switch(type) + const Elf32_Sym *sym = &Info->symtab[ ELF32_R_SYM(r_info) ]; + void *symval = (void*)(intptr_t)sym->st_value; + size_t size = sym->st_size; + TRACE("%i '%s'", ELF32_R_TYPE(r_info), Info->strtab + sym->st_name); + uintptr_t val = (uintptr_t)symval; + switch( ELF32_R_TYPE(r_info) ) { // (S + A) | T case R_ARM_ABS32: - DEBUGS(" elf_doRelocate_arm: R_ARM_ABS32 %p (%s + %x)", ptr, Sym, addend); - if( !GetSymbol(Sym, (void**)&val, NULL) ) return 1; + TRACE("R_ARM_ABS32 %p (%p + %x)", ptr, symval, addend); *ptr = val + addend; break; case R_ARM_GLOB_DAT: - DEBUGS(" elf_doRelocate_arm: R_ARM_GLOB_DAT %p (%s + %x)", ptr, Sym, addend); - if( !GetSymbol(Sym, (void**)&val, NULL) ) return 1; + TRACE("R_ARM_GLOB_DAT %p (%p + %x)", ptr, symval, addend); *ptr = val + addend; break; case R_ARM_JUMP_SLOT: if(!bRela) addend = 0; - DEBUGS(" elf_doRelocate_arm: R_ARM_JUMP_SLOT %p (%s + %x)", ptr, Sym, addend); - if( !GetSymbol(Sym, (void**)&val, NULL) ) return 1; + TRACE("R_ARM_JUMP_SLOT %p (%p + %x)", ptr, symval, addend); *ptr = val + addend; break; // Copy - case R_ARM_COPY: { - size_t size; - void *src; - if( !GetSymbol(Sym, &src, &size) ) return 1; - DEBUGS(" elf_doRelocate_arm: R_ARM_COPY (%p, %p, %i)", ptr, src, size); - memcpy(ptr, src, size); - break; } + case R_ARM_COPY: + TRACE("R_ARM_COPY (%p, %p, %i)", ptr, symval, size); + memcpy(ptr, symval, size); + break; // Delta between link and runtime locations + A case R_ARM_RELATIVE: - DEBUGS(" elf_doRelocate_arm: R_ARM_RELATIVE %p (0x%x + 0x%x)", ptr, iBaseDiff, addend); - if(Sym[0] != '\0') { + TRACE("R_ARM_RELATIVE %p (0x%x + 0x%x)", ptr, Info->iBaseDiff, addend); + if(ELF32_R_SYM(r_info) != 0) { // TODO: Get delta for a symbol - SysDebug("elf_doRelocate_arm: TODO - Implment R_ARM_RELATIVE for symbols"); + WARNING("TODO - Implment R_ARM_RELATIVE for symbols"); return 2; } else { - *ptr = iBaseDiff + addend; + *ptr = Info->iBaseDiff + addend; } break; default: - SysDebug("elf_doRelocate_arm: Unknown Relocation, %i", type); + WARNING("Unknown Relocation, %i", ELF32_R_TYPE(r_info)); return 2; } return 0; } -int elf_doRelocate_unk(uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int type, int bRela, const char *Sym, intptr_t iBaseDiff) -{ - return 1; -} - -void *Elf32Relocate(void *Base, char **envp, const char *Filename) +Elf32_RelocFcn* Elf32_GetRelocFcn(unsigned Machine) { - Elf32_Ehdr *hdr = Base; - Elf32_Phdr *phtab; - char *libPath; - intptr_t iRealBase = -1; - intptr_t iBaseDiff; - int iSegmentCount; - Elf32_Rel *rel = NULL; - Elf32_Rela *rela = NULL; - void *plt = NULL; - int relSz=0, relEntSz=8; - int relaSz=0, relaEntSz=8; - int pltSz=0, pltType=0; - Elf32_Dyn *dynamicTab = NULL; // Dynamic Table Pointer - char *dynstrtab = NULL; // .dynamic String Table - Elf32_Sym *dynsymtab; - int (*do_relocate)(uint32_t t_info, uint32_t *ptr, Elf32_Addr addend, int Type, int bRela, const char *Sym, intptr_t iBaseDiff); - - DEBUGS("ElfRelocate: (Base=0x%x)", Base); - - // Check magic header - - - // Parse Program Header to get Dynamic Table - phtab = (void*)( (uintptr_t)Base + hdr->phoff ); - iSegmentCount = hdr->phentcount; - for(int i = 0; i < iSegmentCount; i ++) + switch(Machine) { - switch(phtab[i].Type) - { - case PT_LOAD: - // Determine linked base address - if( iRealBase > phtab[i].VAddr) - iRealBase = phtab[i].VAddr; - break; - case PT_DYNAMIC: - // Find Dynamic Section - if(!dynamicTab) { - dynamicTab = (void *) (intptr_t) phtab[i].VAddr; - } - else { - DEBUGS(" WARNING - elf_relocate: Multiple PT_DYNAMIC segments"); - } - break; - } - } - - // Page Align real base - iRealBase &= ~0xFFF; - DEBUGS(" elf_relocate: True Base = 0x%x, Compiled Base = 0x%x", Base, iRealBase); - - // Adjust "Real" Base - iBaseDiff = (intptr_t)Base - iRealBase; - -// hdr->entrypoint += iBaseDiff; // Adjust Entrypoint - - // Check if a PT_DYNAMIC segement was found - if(!dynamicTab) { - SysDebug(" elf_relocate: No PT_DYNAMIC segment in image %p, returning", Base); - return (void *)(intptr_t)(hdr->entrypoint + iBaseDiff); + case EM_386: return elf_doRelocate_386; + case EM_ARM: return elf_doRelocate_arm; + default: return NULL; } +} - // Allow writing to read-only segments, just in case they need to be relocated - // - Will be reversed at the end of the function - for( int i = 0; i < iSegmentCount; i ++ ) - { - if(phtab[i].Type == PT_LOAD && !(phtab[i].Flags & PF_W) ) { - uintptr_t addr = phtab[i].VAddr + iBaseDiff; - uintptr_t end = addr + phtab[i].MemSize; - for( ; addr < end; addr += PAGE_SIZE ) - _SysSetMemFlags(addr, 0, 1); // Unset RO - } - } - // Adjust Dynamic Table - dynamicTab = (void *)( (intptr_t)dynamicTab + iBaseDiff ); - - // === Get Symbol table and String Table === - dynsymtab = NULL; - for( int j = 0; dynamicTab[j].d_tag != DT_NULL; j++) - { - switch(dynamicTab[j].d_tag) - { - // --- Symbol Table --- - case DT_SYMTAB: - DEBUGS(" elf_relocate: DYNAMIC Symbol Table 0x%x (0x%x)", - dynamicTab[j].d_val, dynamicTab[j].d_val + iBaseDiff); - dynsymtab = (void*)((intptr_t)dynamicTab[j].d_val + iBaseDiff); - //if(iBaseDiff != 0) dynamicTab[j].d_val += iBaseDiff; - break; - // --- String Table --- - case DT_STRTAB: - DEBUGS(" elf_relocate: DYNAMIC String Table 0x%x (0x%x)", - dynamicTab[j].d_val, dynamicTab[j].d_val + iBaseDiff); - dynstrtab = (void*)((intptr_t)dynamicTab[j].d_val + iBaseDiff); - //if(iBaseDiff != 0) dynamicTab[j].d_val += iBaseDiff; - break; - // --- Hash Table -- - case DT_HASH: - //if(iBaseDiff != 0) dynamicTab[j].d_val += iBaseDiff; -// iSymCount = ((Elf32_Word*)(intptr_t)dynamicTab[j].d_val)[1]; - break; - } - } +// -------------------------------------------------------------------- +// Elf64 support +// -------------------------------------------------------------------- +#ifdef SUPPORT_ELF64 - if(dynsymtab == NULL) { - SysDebug("ld-acess.so - WARNING: No Dynamic Symbol table in %p, returning", hdr); - return (void *)(intptr_t) (hdr->entrypoint + iBaseDiff); - } +#define ELFTYPE Elf64 +#include "elf_impl.c" +#undef ELFTYPE - // === Add to loaded list (can be imported now) === - AddLoaded( Filename, Base ); +Elf64_RelocFcn elf_doRelocate_x86_64; - // === Parse Relocation Data === - DEBUGS(" elf_relocate: dynamicTab = 0x%x", dynamicTab); - for( int j = 0; dynamicTab[j].d_tag != DT_NULL; j++) - { - switch(dynamicTab[j].d_tag) - { - // --- Shared Library Name --- - case DT_SONAME: - DEBUGS(" elf_relocate: .so Name '%s'", dynstrtab+dynamicTab[j].d_val); - break; - // --- Needed Library --- - case DT_NEEDED: - libPath = dynstrtab + dynamicTab[j].d_val; - DEBUGS(" dynstrtab = %p, d_val = 0x%x", dynstrtab, dynamicTab[j].d_val); - DEBUGS(" Required Library '%s'", libPath); - if(LoadLibrary(libPath, NULL, envp) == 0) { - #if DEBUG - DEBUGS(" elf_relocate: Unable to load '%s'", libPath); - #else - SysDebug("Unable to load required library '%s'", libPath); - #endif - return 0; - } - DEBUGS(" Lib loaded"); - break; - // --- PLT/GOT --- -// case DT_PLTGOT: pltgot = (void*)(iBaseDiff + dynamicTab[j].d_val); break; - case DT_JMPREL: plt = (void*)(iBaseDiff + dynamicTab[j].d_val); break; - case DT_PLTREL: pltType = dynamicTab[j].d_val; break; - case DT_PLTRELSZ: pltSz = dynamicTab[j].d_val; break; - - // --- Relocation --- - case DT_REL: rel = (void*)(iBaseDiff + dynamicTab[j].d_val); break; - case DT_RELSZ: relSz = dynamicTab[j].d_val; break; - case DT_RELENT: relEntSz = dynamicTab[j].d_val; break; - case DT_RELA: rela = (void*)(iBaseDiff + dynamicTab[j].d_val); break; - case DT_RELASZ: relaSz = dynamicTab[j].d_val; break; - case DT_RELAENT: relaEntSz = dynamicTab[j].d_val; break; - - // --- Symbol Table --- - case DT_SYMTAB: - // --- Hash Table --- - case DT_HASH: - // --- String Table --- - case DT_STRTAB: - break; - - // --- Unknown --- - default: - if(dynamicTab[j].d_tag > DT_JMPREL) continue; - //DEBUGS(" elf_relocate: %i-%i = %s,0x%x", - // i,j, csaDT_NAMES[dynamicTab[j].d_tag],dynamicTab[j].d_val); - break; - } - } - - DEBUGS(" elf_relocate: Beginning Relocation"); - - int fail = 0; - - switch(hdr->machine) +int elf_doRelocate_x86_64(const Elf64_RelocInfo *Info, Elf64_Xword r_info, Elf64_Xword* ptr, Elf64_Addr addend, bool bRela) +{ + const Elf64_Sym *sym = &Info->symtab[ ELF64_R_SYM(r_info) ]; + void *symval = (void*)(intptr_t)sym->st_value; + size_t size = sym->st_size; + TRACE("%i '%s'", ELF64_R_TYPE(r_info), Info->strtab + sym->st_name); + switch( ELF64_R_TYPE(r_info) ) { - case EM_386: - do_relocate = elf_doRelocate_386; + case R_X86_64_NONE: break; - case EM_ARM: - do_relocate = elf_doRelocate_arm; + case R_X86_64_64: + TRACE("R_X86_64_64 *0x%x = %p + 0x%x", ptr, symval, addend); + *ptr = (intptr_t)symval + addend; break; - default: - SysDebug("Elf32Relocate: Unknown machine type %i", hdr->machine); - do_relocate = elf_doRelocate_unk; - fail = 1; + // Absolute Value of a symbol (S) + case R_X86_64_GLOB_DAT: + TRACE("R_X86_64_GLOB_DAT *0x%x = %p", ptr, symval); if(0) + case R_X86_64_JUMP_SLOT: + TRACE("R_X86_64_JUMP_SLOT *0x%x = %p", ptr, symval); + *ptr = (intptr_t)symval; break; - } - - DEBUGS("do_relocate = %p (%p or %p)", do_relocate, &elf_doRelocate_386, &elf_doRelocate_arm); - #define _doRelocate(r_info, ptr, bRela, addend) \ - do_relocate(r_info, ptr, addend, ELF32_R_TYPE(r_info), bRela, \ - dynstrtab + dynsymtab[ELF32_R_SYM(r_info)].nameOfs, iBaseDiff); + // Base Address (B+A) + case R_X86_64_RELATIVE: + TRACE("R_X86_64_RELATIVE *0x%x = 0x%x + 0x%x", ptr, Info->iBaseDiff, addend); + *ptr = Info->iBaseDiff + addend; + break; - // Parse Relocation Entries - if(rel && relSz) - { - Elf32_Word *ptr; - DEBUGS(" elf_relocate: rel=0x%x, relSz=0x%x, relEntSz=0x%x", rel, relSz, relEntSz); - int max = relSz / relEntSz; - for( int i = 0; i < max; i++ ) - { - //DEBUGS(" Rel %i: 0x%x+0x%x", i, iBaseDiff, rel[i].r_offset); - ptr = (void*)(iBaseDiff + rel[i].r_offset); - fail |= _doRelocate(rel[i].r_info, ptr, 0, *ptr); - } - } - // Parse Relocation Entries - if(rela && relaSz) - { - Elf32_Word *ptr; - DEBUGS(" elf_relocate: rela=0x%x, relaSz=0x%x, relaEntSz=0x%x", rela, relaSz, relaEntSz); - int count = relaSz / relaEntSz; - for( int i = 0; i < count; i++ ) - { - ptr = (void*)(iBaseDiff + rela[i].r_offset); - fail |= _doRelocate(rel[i].r_info, ptr, 1, rela[i].r_addend); - } - } - - // === Process PLT (Procedure Linkage Table) === - if(plt && pltSz) - { - Elf32_Word *ptr; - DEBUGS(" elf_relocate: Relocate PLT, plt=0x%x", plt); - if(pltType == DT_REL) + case R_X86_64_COPY: { + void *old_symval = symval; + GetSymbol(Info->strtab + sym->st_name, &symval, &size, Info->Base); + if( symval == old_symval ) { - Elf32_Rel *pltRel = plt; - int count = pltSz / sizeof(Elf32_Rel); - DEBUGS(" elf_relocate: PLT Reloc Type = Rel, %i entries", count); - for(int i = 0; i < count; i ++) + if( ELF64_ST_BIND(sym->st_info) != STB_WEAK ) { - ptr = (void*)(iBaseDiff + pltRel[i].r_offset); - fail |= _doRelocate(pltRel[i].r_info, ptr, 0, *ptr); + WARNING("sym={val:%p,size:0x%x,info:0x%x,other:0x%x,shndx:%i}", + sym->st_value, sym->st_size, sym->st_info, sym->st_other, sym->st_shndx); + WARNING("Can't find required external symbol '%s' for R_X86_64_COPY", Info->strtab + sym->st_name); + return 1; } + // Don't bother doing the memcpy + TRACE("R_X86_64_COPY (%p, %p, %i)", ptr, symval, size); } else { - Elf32_Rela *pltRela = plt; - int count = pltSz / sizeof(Elf32_Rela); - DEBUGS(" elf_relocate: PLT Reloc Type = Rela, %i entries", count); - for(int i=0;i<count;i++) - { - ptr = (void*)(iRealBase + pltRela[i].r_offset); - fail |= _doRelocate(pltRela[i].r_info, ptr, 1, pltRela[i].r_addend); - } - } - } - - // Re-set readonly - for( int i = 0; i < iSegmentCount; i ++ ) - { - // If load and not writable - if(phtab[i].Type == PT_LOAD && !(phtab[i].Flags & PF_W) ) { - uintptr_t addr = phtab[i].VAddr + iBaseDiff; - uintptr_t end = addr + phtab[i].MemSize; - for( ; addr < end; addr += PAGE_SIZE ) - _SysSetMemFlags(addr, 1, 1); // Unset RO + TRACE("R_X86_64_COPY (%p, %p, %i)", ptr, symval, size); + memcpy(ptr, symval, size); } + break; } + default: + WARNING("Unknown Relocation, %i", ELF64_R_TYPE(r_info)); + return 2; } - - if( fail ) { - DEBUGS("ElfRelocate: Failure"); - return NULL; - } - - #undef _doRelocate - - DEBUGS("ElfRelocate: RETURN 0x%x to %p", hdr->entrypoint + iBaseDiff, __builtin_return_address(0)); - return (void*)(intptr_t)( hdr->entrypoint + iBaseDiff ); + return 0; } -int Elf32GetSymbol(void *Base, const char *Name, void **ret, size_t *Size) +Elf64_RelocFcn* Elf64_GetRelocFcn(unsigned Machine) { - Elf32_Ehdr *hdr = Base; - Elf32_Sym *symtab = NULL; - int nbuckets = 0; - Elf32_Word *pBuckets = NULL; - Elf32_Word *pChains; - uint32_t iNameHash; - const char *dynstrtab = NULL; - uintptr_t iBaseDiff = -1; - Elf32_Phdr *phtab; - Elf32_Dyn *dynTab = NULL; - - // Locate the tables - phtab = (void*)( (uintptr_t)Base + hdr->phoff ); - for( int i = 0; i < hdr->phentcount; i ++ ) + switch(Machine) { - if(phtab[i].Type == PT_LOAD && iBaseDiff > phtab[i].VAddr) - iBaseDiff = phtab[i].VAddr; - if( phtab[i].Type == PT_DYNAMIC ) { - dynTab = (void*)(intptr_t)phtab[i].VAddr; - } - } - if( !dynTab ) { - SysDebug("ERROR - Unable to find DYNAMIC segment in %p", Base); - return 0; + case EM_X86_64: return elf_doRelocate_x86_64; + default: return NULL; } - iBaseDiff = (intptr_t)Base - iBaseDiff; // Make iBaseDiff actually the diff - dynTab = (void*)( (intptr_t)dynTab + iBaseDiff ); - for( int i = 0; dynTab[i].d_tag != DT_NULL; i++) - { - switch(dynTab[i].d_tag) - { - // --- Symbol Table --- - case DT_SYMTAB: - symtab = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff); // Rebased in Relocate - break; - case DT_STRTAB: - dynstrtab = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff); - break; - // --- Hash Table -- - case DT_HASH: - pBuckets = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff); - break; - } - } - - if( !symtab ) { - SysDebug("ERRO - No DT_SYMTAB in %p", Base); - return 0; - } - if( !pBuckets ) { - SysDebug("ERRO - No DT_HASH in %p", Base); - return 0; - } - if( !dynstrtab ) { - SysDebug("ERRO - No DT_STRTAB in %p", Base); - return 0; - } - - // ... ok... maybe they haven't been relocated - if( (uintptr_t)symtab < (uintptr_t)Base ) - { - symtab = (void*)( (uintptr_t)symtab + iBaseDiff ); - pBuckets = (void*)( (uintptr_t)pBuckets + iBaseDiff ); - dynstrtab = (void*)( (uintptr_t)dynstrtab + iBaseDiff ); - SysDebug("Executable not yet relocated"); - } - - nbuckets = pBuckets[0]; -// iSymCount = pBuckets[1]; - pBuckets = &pBuckets[2]; - pChains = &pBuckets[ nbuckets ]; - assert(pChains); +} - // Get hash - iNameHash = ElfHashString(Name); - iNameHash %= nbuckets; +#endif // SUPPORT_ELF64 - // Walk Chain - int idx = pBuckets[ iNameHash ]; - do { - Elf32_Sym *sym = &symtab[idx]; - assert(sym); - if(sym->shndx != SHN_UNDEF && strcmp(dynstrtab + sym->nameOfs, Name) == 0) { - *ret = (void*)( (uintptr_t)sym->value + iBaseDiff ); - if(Size) *Size = sym->size; - return 1; - } - } while( (idx = pChains[idx]) != STN_UNDEF && idx != pBuckets[iNameHash] ); - - return 0; -} #ifdef SUPPORT_ELF64 +#if 0 typedef int (*t_elf64_doreloc)(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend); int _Elf64DoReloc_X86_64(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend) @@ -586,20 +330,20 @@ int _Elf64DoReloc_X86_64(void *Base, const char *strtab, Elf64_Sym *symtab, Elf6 case R_X86_64_NONE: break; case R_X86_64_64: - if( !GetSymbol(symname, &symval, NULL) ) return 1; + if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1; *(uint64_t*)ptr = (uintptr_t)symval + addend; break; case R_X86_64_COPY: { size_t size; - if( !GetSymbol(symname, &symval, &size) ) return 1; + if( !GetSymbol(symname, &symval, &size, NULL) ) return 1; memcpy(ptr, symval, size); } break; case R_X86_64_GLOB_DAT: - if( !GetSymbol(symname, &symval, NULL) ) return 1; + if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1; *(uint64_t*)ptr = (uintptr_t)symval; break; case R_X86_64_JUMP_SLOT: - if( !GetSymbol(symname, &symval, NULL) ) return 1; + if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1; *(uint64_t*)ptr = (uintptr_t)symval; break; case R_X86_64_RELATIVE: @@ -630,18 +374,18 @@ void *Elf64Relocate(void *Base, char **envp, const char *Filename) void *pltrel = NULL; int plt_size = 0, plt_type = 0; - DEBUGS("Elf64Relocate: hdr = {"); - DEBUGS("Elf64Relocate: e_ident = '%.16s'", hdr->e_ident); - DEBUGS("Elf64Relocate: e_type = 0x%x", hdr->e_type); - DEBUGS("Elf64Relocate: e_machine = 0x%x", hdr->e_machine); - DEBUGS("Elf64Relocate: e_version = 0x%x", hdr->e_version); - DEBUGS("Elf64Relocate: e_entry = %p", hdr->e_entry); - DEBUGS("Elf64Relocate: e_phoff = 0x%llx", hdr->e_phoff); - DEBUGS("Elf64Relocate: e_shoff = 0x%llx", hdr->e_shoff); - DEBUGS("Elf64Relocate: e_flags = 0x%x", hdr->e_flags); - DEBUGS("Elf64Relocate: e_ehsize = 0x%x", hdr->e_ehsize); - DEBUGS("Elf64Relocate: e_phentsize = 0x%x", hdr->e_phentsize); - DEBUGS("Elf64Relocate: e_phnum = %i", hdr->e_phnum); + TRACE("hdr = {"); + TRACE(" e_ident = '%.16s'", hdr->e_ident); + TRACE(" e_type = 0x%x", hdr->e_type); + TRACE(" e_machine = 0x%x", hdr->e_machine); + TRACE(" e_version = 0x%x", hdr->e_version); + TRACE(" e_entry = %p", hdr->e_entry); + TRACE(" e_phoff = 0x%llx", hdr->e_phoff); + TRACE(" e_shoff = 0x%llx", hdr->e_shoff); + TRACE(" e_flags = 0x%x", hdr->e_flags); + TRACE(" e_ehsize = 0x%x", hdr->e_ehsize); + TRACE(" e_phentsize = 0x%x", hdr->e_phentsize); + TRACE(" e_phnum = %i", hdr->e_phnum); // Scan for the dynamic table (and find the compiled base) phtab = (void*)((uintptr_t)Base + (uintptr_t)hdr->e_phoff); @@ -655,7 +399,7 @@ void *Elf64Relocate(void *Base, char **envp, const char *Filename) baseDiff = (uintptr_t)Base - compiledBase; - DEBUGS("baseDiff = %p", baseDiff); + TRACE("baseDiff = %p", baseDiff); if(dyntab == NULL) { SysDebug(" Elf64Relocate: No PT_DYNAMIC segment in image %p, returning", Base); @@ -696,14 +440,14 @@ void *Elf64Relocate(void *Base, char **envp, const char *Filename) // Second pass on dynamic table for(i = 0; dyntab[i].d_tag != DT_NULL; i ++) { - DEBUGS("dyntab[%i].d_tag = %i", i, dyntab[i].d_tag); + TRACE("dyntab[%i].d_tag = %i", i, dyntab[i].d_tag); switch(dyntab[i].d_tag) { case DT_SONAME: break; case DT_NEEDED: { char *libPath = strtab + dyntab[i].d_un.d_val; - DEBUGS("Elf64Relocate: libPath = '%s'", libPath); + TRACE("Elf64Relocate: libPath = '%s'", libPath); if(LoadLibrary(libPath, NULL, envp) == 0) { SysDebug("ld-acess - Elf64Relocate: Unable to load '%s'", libPath); return NULL; @@ -752,6 +496,8 @@ void *Elf64Relocate(void *Base, char **envp, const char *Filename) } } + // TODO: Relocate symbols + // Relocation function t_elf64_doreloc fpElf64DoReloc = &_Elf64DoReloc_X86_64; #define _Elf64DoReloc(info, ptr, addend) fpElf64DoReloc(Base, strtab, symtab, info, ptr, addend) @@ -759,7 +505,7 @@ void *Elf64Relocate(void *Base, char **envp, const char *Filename) int fail = 0; if( rel ) { - DEBUGS("rel_count = %i", rel_count); + TRACE("rel_count = %i", rel_count); for( i = 0; i < rel_count; i ++ ) { uint64_t *ptr = (void *)(uintptr_t)( rel[i].r_offset + baseDiff ); @@ -769,7 +515,7 @@ void *Elf64Relocate(void *Base, char **envp, const char *Filename) if( rela ) { - DEBUGS("rela_count = %i", rela_count); + TRACE("rela_count = %i", rela_count); for( i = 0; i < rela_count; i ++ ) { uint64_t *ptr = (void *)(uintptr_t)( rela[i].r_offset + baseDiff ); @@ -782,7 +528,7 @@ void *Elf64Relocate(void *Base, char **envp, const char *Filename) if( plt_type == DT_REL ) { Elf64_Rel *plt = pltrel; int count = plt_size / sizeof(Elf64_Rel); - DEBUGS("plt rel count = %i", count); + TRACE("plt rel count = %i", count); for( i = 0; i < count; i ++ ) { uint64_t *ptr = (void *)(uintptr_t)( plt[i].r_offset + baseDiff ); @@ -792,7 +538,7 @@ void *Elf64Relocate(void *Base, char **envp, const char *Filename) else { Elf64_Rela *plt = pltrel; int count = plt_size / sizeof(Elf64_Rela); - DEBUGS("plt rela count = %i", count); + TRACE("plt rela count = %i", count); for( i = 0; i < count; i ++ ) { uint64_t *ptr = (void *)(uintptr_t)( plt[i].r_offset + baseDiff ); @@ -802,13 +548,13 @@ void *Elf64Relocate(void *Base, char **envp, const char *Filename) } if( fail ) { - DEBUGS("Elf64Relocate: Failure"); + TRACE("Failure"); return NULL; } { void *ret = (void *)(uintptr_t)(hdr->e_entry + baseDiff); - DEBUGS("Elf64Relocate: Relocations done, return %p", ret); + TRACE("Relocations done, return %p", ret); return ret; } } @@ -887,7 +633,7 @@ int Elf64GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size) if(symtab[i].st_shndx != SHN_UNDEF && strcmp(dynstrtab + symtab[i].st_name, Name) == 0) { *Ret = (void*)( (intptr_t)symtab[i].st_value + iBaseDiff ); if(Size) *Size = symtab[i].st_size; - DEBUGS("%s = %p", Name, *Ret); + TRACE("%s = %p", Name, *Ret); return 1; } @@ -897,7 +643,7 @@ int Elf64GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size) if(symtab[i].st_shndx != SHN_UNDEF && strcmp(dynstrtab + symtab[i].st_name, Name) == 0) { *Ret = (void*)((intptr_t)symtab[i].st_value + iBaseDiff); if(Size) *Size = symtab[i].st_size; - DEBUGS("%s = %p", Name, *Ret); + TRACE("%s = %p", Name, *Ret); return 1; } } @@ -905,7 +651,7 @@ int Elf64GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size) return 0; } #endif - +#endif uint32_t ElfHashString(const char *name) { diff --git a/Usermode/Libraries/ld-acess.so_src/elf32.h b/Usermode/Libraries/ld-acess.so_src/elf32.h index 2e9c1c4a9e161771d770d824c595781946c7838a..40c801c92a1b269c8becc87dd3821a6a066c0a45 100644 --- a/Usermode/Libraries/ld-acess.so_src/elf32.h +++ b/Usermode/Libraries/ld-acess.so_src/elf32.h @@ -12,6 +12,7 @@ typedef uint16_t Elf32_Half; typedef uint32_t Elf32_Addr; typedef uint32_t Elf32_Off; typedef uint32_t Elf32_Word; +typedef uint32_t Elf32_Xword; // < not strictly correct... but meh typedef int32_t Elf32_Sword; #define ELFCLASS32 1 @@ -26,19 +27,19 @@ typedef int32_t Elf32_Sword; */ struct sElf32_Ehdr { uint8_t e_ident[16]; //!< Identifier Bytes - Elf32_Half filetype; //!< File Type - Elf32_Half machine; //!< Machine / Arch - Elf32_Word version; //!< Version (File?) - Elf32_Addr entrypoint; //!< Entry Point - Elf32_Off phoff; //!< Program Header Offset - Elf32_Word shoff; //!< Section Header Offset - Elf32_Word flags; //!< Flags - Elf32_Half headersize; //!< Header Size - Elf32_Half phentsize; //!< Program Header Entry Size - Elf32_Half phentcount; //!< Program Header Entry Count - Elf32_Half shentsize; //!< Section Header Entry Size - Elf32_Half shentcount; //!< Section Header Entry Count - Elf32_Half shstrindex; //!< Section Header String Table Index + Elf32_Half e_filetype; //!< File Type + Elf32_Half e_machine; //!< Machine / Arch + Elf32_Word e_version; //!< Version (File?) + Elf32_Addr e_entry; //!< Entry Point + Elf32_Off e_phoff; //!< Program Header Offset + Elf32_Word e_shoff; //!< Section Header Offset + Elf32_Word e_flags; //!< Flags + Elf32_Half e_headersize; //!< Header Size + Elf32_Half e_phentsize; //!< Program Header Entry Size + Elf32_Half e_phnum; //!< Program Header Entry Count + Elf32_Half e_shentsize; //!< Section Header Entry Size + Elf32_Half e_shentcount; //!< Section Header Entry Count + Elf32_Half e_shstrindex; //!< Section Header String Table Index }; /** @@ -112,15 +113,24 @@ struct sElf32_Shent { #endif struct elf_sym_s { - Elf32_Word nameOfs; - Elf32_Addr value; //Address - Elf32_Word size; - uint8_t info; - uint8_t other; - Elf32_Half shndx; + Elf32_Word st_name; + Elf32_Addr st_value; //Address + Elf32_Word st_size; + uint8_t st_info; + uint8_t st_other; + Elf32_Half st_shndx; }; #define STN_UNDEF 0 // Undefined Symbol +#define ELF32_ST_BIND(i) ((i)>>4) +#define ELF32_ST_TYPE(i) ((i)&0xF) + +enum { + STB_LOCAL, + STB_GLOBAL, + STB_WEAK, +}; + enum { PT_NULL, //0 PT_LOAD, //1 @@ -138,14 +148,14 @@ enum { #define PF_R 4 struct sElf32_Phdr { - Elf32_Word Type; - Elf32_Off Offset; - Elf32_Addr VAddr; - Elf32_Addr PAddr; - Elf32_Word FileSize; - Elf32_Word MemSize; - Elf32_Word Flags; - Elf32_Word Align; + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; }; struct elf32_rel_s { diff --git a/Usermode/Libraries/ld-acess.so_src/elf64.h b/Usermode/Libraries/ld-acess.so_src/elf64.h index fb39782ab0b116ee6fe718c616dc37c9fe8c823a..9d04e8af5fd6fb8b9dfae543822fa1928267f104 100644 --- a/Usermode/Libraries/ld-acess.so_src/elf64.h +++ b/Usermode/Libraries/ld-acess.so_src/elf64.h @@ -69,7 +69,7 @@ typedef struct union { Elf64_Xword d_val; Elf64_Addr d_ptr; - } d_un; + };// d_un; } Elf64_Dyn; typedef struct @@ -97,6 +97,8 @@ typedef struct #define ELF64_R_SYM(info) ((info) >> 32) #define ELF64_R_TYPE(info) ((info) & 0xFFFFFFFF) +#define ELF64_ST_BIND(i) ((i)>>4) +#define ELF64_ST_TYPE(i) ((i)&0xF) enum eElf64_RelocTypes_x86_64 { diff --git a/Usermode/Libraries/ld-acess.so_src/elf_impl.c b/Usermode/Libraries/ld-acess.so_src/elf_impl.c new file mode 100644 index 0000000000000000000000000000000000000000..a89a26f695c06def4e58db210364b23a8ec8a5f8 --- /dev/null +++ b/Usermode/Libraries/ld-acess.so_src/elf_impl.c @@ -0,0 +1,506 @@ + +#ifndef ELFTYPE +# error "ELFTYPE must be defined to either ELf32 or Elf64 to use this file" +#endif + +#define __PREF(t,s) t##_##s +#define _PREF(t,s) __PREF(t,s) +#define PREF(sym) _PREF(ELFTYPE,sym) + +typedef struct +{ + void *Base; + intptr_t iBaseDiff; + const char *strtab; + const PREF(Sym) *symtab; +} PREF(RelocInfo); + +typedef int PREF(RelocFcn)(const PREF(RelocInfo)* Info, PREF(Xword) t_info, PREF(Xword)* ptr, PREF(Addr) addend, bool bRela); + +// - Extern +static PREF(RelocFcn)* PREF(GetRelocFcn)(unsigned Machine); +// - Local +static PREF(RelocFcn) PREF(doRelocate_unk); +static void PREF(int_GetBaseDyntab)(void* Base, const PREF(Phdr)* phtab, unsigned phentcount, intptr_t* iBaseDiff_p, PREF(Dyn)** dynamicTab_p); +static int PREF(GetSymbolVars)(void *Base, const PREF(Sym)** symtab, const PREF(Word)** pBuckets, const char **dynstrtab, uintptr_t* piBaseDiff); +static int PREF(GetSymbolInfo)(void *Base, const char *Name, void **Addr, size_t *Size, int* Section, int *Binding, int *Type); + +// - Relocate +void *PREF(Relocate)(void *Base, char **envp, const char *Filename) +{ + TRACE("(Base=0x%x)", Base); + const PREF(Ehdr) *hdr = Base; + + // Check magic header + // TODO: Validate header? + + + // Parse Program Header to get Dynamic Table + // - Determine the linked base of the executable + const PREF(Phdr) *phtab = (void*)( (uintptr_t)Base + hdr->e_phoff ); + + intptr_t iBaseDiff = 0; + PREF(Dyn)* dynamicTab = NULL; + + PREF(int_GetBaseDyntab)(Base, phtab, hdr->e_phnum, &iBaseDiff, &dynamicTab); + + // Check if a PT_DYNAMIC segement was found + if(!dynamicTab) + { + SysDebug(" elf_relocate: No PT_DYNAMIC segment in image %p, returning", Base); + return (void *)(intptr_t)(hdr->e_entry + iBaseDiff); + } + + // Allow writing to read-only segments, just in case they need to be relocated + // - Will be reversed at the end of the function + for( unsigned i = 0; i < hdr->e_phnum; i ++ ) + { + if(phtab[i].p_type == PT_LOAD && !(phtab[i].p_flags & PF_W) ) + { + uintptr_t addr = phtab[i].p_vaddr + iBaseDiff; + uintptr_t end = addr + phtab[i].p_memsz; + for( ; addr < end; addr += PAGE_SIZE ) + _SysSetMemFlags(addr, 0, 1); // Unset RO + } + } + + // === Get Symbol table and String Table === + char *dynstrtab = NULL; // .dynamic String Table + PREF(Sym) *dynsymtab = NULL; + PREF(Word) *hashtable = NULL; + unsigned iSymCount = 0; + for( unsigned j = 0; dynamicTab[j].d_tag != DT_NULL; j++) + { + const PREF(Dyn) *dt = &dynamicTab[j]; + switch(dt->d_tag) + { + // --- Symbol Table --- + case DT_SYMTAB: + TRACE("DYNAMIC Symbol Table 0x%x (0x%x)", dt->d_val, dt->d_val + iBaseDiff); + dynsymtab = (void*)((intptr_t)dt->d_val + iBaseDiff); + break; + // --- String Table --- + case DT_STRTAB: + TRACE("DYNAMIC String Table 0x%x (0x%x)", dt->d_val, dt->d_val + iBaseDiff); + dynstrtab = (void*)((intptr_t)dt->d_val + iBaseDiff); + break; + // --- Hash Table -- + case DT_HASH: + TRACE("DYNAMIC Hash table %p (%p)", dt->d_val, dt->d_val + iBaseDiff); + hashtable = (void*)((intptr_t)dt->d_val + iBaseDiff); + iSymCount = hashtable[1]; + break; + } + } + + if(dynsymtab == NULL) { + SysDebug("ld-acess.so - WARNING: No Dynamic Symbol table in %p, returning", hdr); + return (void *)(intptr_t) (hdr->e_entry + iBaseDiff); + } + + // Apply base offset to locally defined symbols + // - #0 is defined as ("" SHN_UNDEF), so skip it + for( unsigned i = 1; i < iSymCount; i ++ ) + { + PREF(Sym) *sym = &dynsymtab[i]; + const char *name = dynstrtab + sym->st_name; + (void)name; + if( sym->st_shndx == SHN_UNDEF ) + { + TRACE("Sym %i'%s' deferred (SHN_UNDEF)", i, name); + } + else if( sym->st_shndx == SHN_ABS ) + { + // Leave as is + TRACE("Sym %i'%s' untouched", i, name); + } + else + { + void *newval; + size_t newsize; + if( ELF32_ST_BIND(sym->st_info) != STB_WEAK ) + { + TRACE("Sym %i'%s' = %p (local)", i, name, sym->st_value + iBaseDiff); + sym->st_value += iBaseDiff; + } + // If GetSymbol doesn't return a strong/global symbol value + else if( GetSymbol(name, &newval, &newsize, Base) != 1 ) + { + TRACE("Sym %i'%s' = %p (Local weak)", i, name, sym->st_value + iBaseDiff); + sym->st_value += iBaseDiff; + } + else + { + TRACE("Sym %i'%s' = %p+0x%x (Extern weak)", i, name, newval, newsize); + sym->st_value = (uintptr_t)newval; + sym->st_size = newsize; + } + } + } + + // === Add to loaded list (can be imported now) === + AddLoaded( Filename, Base ); + + // === Parse Relocation Data === + PREF(Rel) *rel = NULL; + PREF(Rela) *rela = NULL; + void *plt = NULL; + int relSz=0, relEntSz=8; + int relaSz=0, relaEntSz=8; + int pltSz=0, pltType=0; + TRACE("dynamicTab = 0x%x", dynamicTab); + for( int j = 0; dynamicTab[j].d_tag != DT_NULL; j++) + { + const PREF(Dyn) *dt = &dynamicTab[j]; + switch(dt->d_tag) + { + // --- Shared Library Name --- + case DT_SONAME: + TRACE(".so Name '%s'", dynstrtab + dt->d_val); + break; + // --- Needed Library --- + case DT_NEEDED: { + //assert(dt->d_val < sizeof_dynstrtab); // Disabled, no sizeof_dynstrtab + const char *libPath = dynstrtab + dt->d_val; + TRACE(" Required Library '%s'", libPath); + if(LoadLibrary(libPath, NULL, envp) == 0) { + SysDebug("Unable to load required library '%s'", libPath); + return 0; + } + TRACE(" Lib loaded"); + break; } + // --- PLT/GOT --- +// case DT_PLTGOT: pltgot = (void*)(iBaseDiff + dt->d_val); break; + case DT_JMPREL: plt = (void*)(iBaseDiff + dt->d_val); break; + case DT_PLTREL: pltType = dt->d_val; break; + case DT_PLTRELSZ: pltSz = dt->d_val; break; + + // --- Relocation --- + case DT_REL: rel = (void*)(iBaseDiff + dt->d_val); break; + case DT_RELSZ: relSz = dt->d_val; break; + case DT_RELENT: relEntSz = dt->d_val; break; + case DT_RELA: rela = (void*)(iBaseDiff + dt->d_val); break; + case DT_RELASZ: relaSz = dt->d_val; break; + case DT_RELAENT: relaEntSz = dt->d_val; break; + + // --- Symbol Table --- + case DT_SYMTAB: + // --- Hash Table --- + case DT_HASH: + // --- String Table --- + case DT_STRTAB: + break; + + // --- Unknown --- + default: + if(dt->d_tag > DT_JMPREL) continue; + //DEBUGS(" elf_relocate: %i-%i = %s,0x%x", + // i,j, csaDT_NAMES[dynamicTab[j].d_tag],dynamicTab[j].d_val); + break; + } + } + + // Resolve symbols (second pass) + // - #0 is defined as ("" SHN_UNDEF), so skip it + int fail = 0; + for( int i = 1; i < iSymCount; i ++ ) + { + PREF(Sym) *sym = &dynsymtab[i]; + const char *name = dynstrtab + sym->st_name; + if( sym->st_shndx == SHN_UNDEF ) + { + void *newval; + size_t newsize; + if( !GetSymbol(name, &newval, &newsize, Base) ) { + if( ELF32_ST_BIND(sym->st_info) != STB_WEAK ) { + // Not a weak binding, set fail and move on + WARNING("%s: Can't find required symbol '%s' for '%s'", __func__, name, Filename); + fail = 1; + continue ; + } + // Leave the symbol value as-is + } + else { + TRACE("Sym %i'%s' bound to %p+0x%x", i, name, newval, newsize); + sym->st_value = (intptr_t)newval; + sym->st_size = newsize; + } + } + else if( sym->st_shndx == SHN_ABS ) + { + // Leave as is + } + else + { + // Handled previously + // TODO: What about weak locally-defined symbols? + //assert( ELF32_ST_BIND(sym->st_info) != STB_WEAK ); + } + } + if( fail ) { + WARNING("Relocation of '%s' failed", Filename); + return NULL; + } + + TRACE("Beginning Relocation on '%s'", Filename); + + + PREF(RelocFcn)* do_relocate = PREF(GetRelocFcn)(hdr->e_machine); + if( do_relocate == 0 ) + { + SysDebug("%s: Unknown machine type %i", __func__, hdr->e_machine); + do_relocate = PREF(doRelocate_unk); + fail = 1; + } + + TRACE("do_relocate = %p", do_relocate); + + #define _doRelocate(r_info, ptr, bRela, addend) \ + do_relocate(&reloc_info, r_info, ptr, addend, bRela); + + PREF(RelocInfo) reloc_info = { + .Base = Base, + .iBaseDiff = iBaseDiff, + .strtab = dynstrtab, + .symtab = dynsymtab + }; + + // Parse Relocation Entries + if(rel && relSz) + { + TRACE("rel=0x%x, relSz=0x%x, relEntSz=0x%x", rel, relSz, relEntSz); + int max = relSz / relEntSz; + for( int i = 0; i < max; i++ ) + { + PREF(Xword) *ptr = (void*)(iBaseDiff + rel[i].r_offset); + fail |= _doRelocate(rel[i].r_info, ptr, 0, *ptr); + } + } + // Parse Relocation Entries + if(rela && relaSz) + { + TRACE("rela=0x%x, relaSz=0x%x, relaEntSz=0x%x", rela, relaSz, relaEntSz); + int count = relaSz / relaEntSz; + for( int i = 0; i < count; i++ ) + { + void *ptr = (void*)(iBaseDiff + rela[i].r_offset); + fail |= _doRelocate(rela[i].r_info, ptr, 1, rela[i].r_addend); + } + } + + // === Process PLT (Procedure Linkage Table) === + if(plt && pltSz) + { + TRACE("Relocate PLT, plt=0x%x", plt); + if(pltType == DT_REL) + { + PREF(Rel) *pltRel = plt; + int count = pltSz / sizeof(*pltRel); + TRACE("PLT Reloc Type = Rel, %i entries", count); + for(int i = 0; i < count; i ++) + { + PREF(Xword) *ptr = (void*)(iBaseDiff + pltRel[i].r_offset); + fail |= _doRelocate(pltRel[i].r_info, ptr, 0, *ptr); + } + } + else + { + PREF(Rela) *pltRela = plt; + int count = pltSz / sizeof(*pltRela); + TRACE("PLT Reloc Type = Rela, %i entries", count); + for(int i=0;i<count;i++) + { + void *ptr = (void*)(iBaseDiff + pltRela[i].r_offset); + fail |= _doRelocate(pltRela[i].r_info, ptr, 1, pltRela[i].r_addend); + } + } + } + + // Re-set readonly + for( int i = 0; i < hdr->e_phnum; i ++ ) + { + // If load and not writable + if(phtab[i].p_type == PT_LOAD && !(phtab[i].p_flags & PF_W) ) + { + uintptr_t addr = phtab[i].p_vaddr + iBaseDiff; + uintptr_t end = addr + phtab[i].p_memsz; + for( ; addr < end; addr += PAGE_SIZE ) + _SysSetMemFlags(addr, 1, 1); // Unset RO + } + } + + if( fail ) { + TRACE("ElfRelocate: Failure"); + return NULL; + } + + #undef _doRelocate + + TRACE("RETURN 0x%x to %p", hdr->e_entry + iBaseDiff, __builtin_return_address(0)); + return (void*)(intptr_t)( hdr->e_entry + iBaseDiff ); +} + +void PREF(int_GetBaseDyntab)(void* Base, const PREF(Phdr)* phtab, unsigned phentcount, intptr_t* iBaseDiff_p, PREF(Dyn)** dynamicTab_p) +{ + uintptr_t iRealBase = UINTPTR_MAX; + assert(dynamicTab_p); + + for(unsigned i = 0; i < phentcount; i ++) + { + switch(phtab[i].p_type) + { + case PT_LOAD: + // Determine linked base address + if( iRealBase > phtab[i].p_vaddr) + iRealBase = phtab[i].p_vaddr; + break; + case PT_DYNAMIC: + // Find Dynamic Section + if(!*dynamicTab_p) { + *dynamicTab_p = (void *) (intptr_t) phtab[i].p_vaddr; + } + else { + WARNING("elf_relocate: Multiple PT_DYNAMIC segments"); + } + break; + } + } + + // Page Align real base + iRealBase &= ~0xFFF; + + // Adjust "Real" Base + const intptr_t iBaseDiff = (intptr_t)Base - iRealBase; + *iBaseDiff_p = iBaseDiff; + + // Adjust Dynamic Table + if( *dynamicTab_p ) + { + *dynamicTab_p = (void *)( (intptr_t)*dynamicTab_p + iBaseDiff ); + } + + TRACE("True Base = 0x%x, Compiled Base = 0x%x, Difference = 0x%x", Base, iRealBase, *iBaseDiff_p); +} + +int PREF(doRelocate_unk)(const PREF(RelocInfo)* Info, PREF(Xword) r_info, PREF(Xword)* ptr, PREF(Addr) addend, bool bRela) +{ + return 1; +} + +int PREF(GetSymbolVars)(void *Base, const PREF(Sym)** symtab, const PREF(Word)** pBuckets, const char **dynstrtab, uintptr_t* piBaseDiff) +{ + const PREF(Ehdr)* hdr = Base; + PREF(Dyn)* dynTab = NULL; + intptr_t iBaseDiff = -1; + + PREF(int_GetBaseDyntab)(Base, (void*)( (uintptr_t)Base + hdr->e_phoff ), hdr->e_phnum, &iBaseDiff, &dynTab); + if( !dynTab ) { + SysDebug("ERROR - Unable to find DYNAMIC segment in %p", Base); + return 1; + } + + for( int i = 0; dynTab[i].d_tag != DT_NULL; i++) + { + switch(dynTab[i].d_tag) + { + // --- Symbol Table --- + case DT_SYMTAB: + *symtab = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff); // Rebased in Relocate + break; + case DT_STRTAB: + *dynstrtab = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff); + break; + // --- Hash Table -- + case DT_HASH: + *pBuckets = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff); + break; + } + } + + if( !*symtab ) { + SysDebug("ERRO - No DT_SYMTAB in %p", Base); + return 1; + } + if( !*pBuckets ) { + SysDebug("ERRO - No DT_HASH in %p", Base); + return 1; + } + if( !*dynstrtab ) { + SysDebug("ERRO - No DT_STRTAB in %p", Base); + return 1; + } + + // ... ok... maybe they haven't been relocated + if( (uintptr_t)*symtab < (uintptr_t)Base ) + { + SysDebug("Executable not yet relocated (symtab,pBuckets,dynstrtab = %p,%p,%p + 0x%x)", + *symtab,*pBuckets,*dynstrtab, iBaseDiff); + *symtab = (void*)( (uintptr_t)*symtab + iBaseDiff ); + *pBuckets = (void*)( (uintptr_t)*pBuckets + iBaseDiff ); + *dynstrtab = (void*)( (uintptr_t)*dynstrtab + iBaseDiff ); + } + *piBaseDiff = iBaseDiff; + return 0; +} + +int PREF(GetSymbolInfo)(void *Base, const char *Name, void **Addr, size_t *Size, int* Section, int *Binding, int *Type) +{ + // Locate the tables + uintptr_t iBaseDiff = -1; + const PREF(Sym)* symtab = NULL; + const PREF(Word)* pBuckets = NULL; + const char *dynstrtab = NULL; + if( PREF(GetSymbolVars)(Base, &symtab, &pBuckets, &dynstrtab, &iBaseDiff) ) + return 1; + + unsigned nbuckets = pBuckets[0]; +// int iSymCount = pBuckets[1]; + pBuckets = &pBuckets[2]; + + const PREF(Word)* pChains = &pBuckets[ nbuckets ]; + assert(pChains); + + // Get hash + unsigned iNameHash = ElfHashString(Name); + iNameHash %= nbuckets; + + // Walk Chain + unsigned idx = pBuckets[ iNameHash ]; + do { + const PREF(Sym)* sym = &symtab[idx]; + assert(sym); + if( strcmp(dynstrtab + sym->st_name, Name) == 0 ) + { + TRACE("*sym = {value:0x%x,size:0x%x,info:0x%x,other:0x%x,shndx:%i}", + sym->st_value, sym->st_size, sym->st_info, + sym->st_other, sym->st_shndx); + if(Addr) *Addr = (void*)(intptr_t)( sym->st_value ); + if(Size) *Size = sym->st_size; + if(Binding) *Binding = ELF32_ST_BIND(sym->st_info); + if(Type) *Type = ELF32_ST_TYPE(sym->st_info); + if(Section) *Section = sym->st_shndx; + return 0; + } + } while( (idx = pChains[idx]) != STN_UNDEF && idx != pBuckets[iNameHash] ); + + TRACE("No symbol"); + return 1; +} + +int PREF(GetSymbol)(void *Base, const char *Name, void **ret, size_t *Size) +{ + int section, binding; + TRACE("%s(%p,%s,...)", __func__, Base, Name); + if( PREF(GetSymbolInfo)(Base, Name, ret, Size, §ion, &binding, NULL) ) + return 0; + if( section == SHN_UNDEF ) { + TRACE("%s: Undefined %p", __func__, *ret, (Size?*Size:0), section); + return 0; + } + if( binding == STB_WEAK ) { + TRACE("%s: Weak, return %p+0x%x,section=%i", __func__, *ret, (Size?*Size:0), section); + return 2; + } + TRACE("%s: Found %p+0x%x,section=%i", __func__, *ret, (Size?*Size:0), section); + return 1; +} diff --git a/Usermode/Libraries/ld-acess.so_src/export.c b/Usermode/Libraries/ld-acess.so_src/export.c index 10c5c5cd5acbadfed08629fadf65a9bb2d9b1134..e40dd8eb250324624397de216db9f8a0dda881c6 100644 --- a/Usermode/Libraries/ld-acess.so_src/export.c +++ b/Usermode/Libraries/ld-acess.so_src/export.c @@ -11,6 +11,7 @@ extern int32_t __modsi3(int32_t Num, int32_t Den); extern uint32_t __udivsi3(uint32_t Num, uint32_t Den); extern uint32_t __umodsi3(uint32_t Num, uint32_t Den); extern void ldacess_DumpLoadedLibraries(void); +extern void _ZN4_sys5debugEPKcz(const char *,...); // C++ "_sys::debug" used by STL debug #define _STR(x) #x #define STR(x) _STR(x) diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/acess/_native_syscallmod.h b/Usermode/Libraries/ld-acess.so_src/include_exp/acess/_native_syscallmod.h index 9da4e433e026e1c50ff3ac93367eb68b54b92cb2..b3d78bf1359f48e6ba76bf43565039052c6dfe21 100644 --- a/Usermode/Libraries/ld-acess.so_src/include_exp/acess/_native_syscallmod.h +++ b/Usermode/Libraries/ld-acess.so_src/include_exp/acess/_native_syscallmod.h @@ -24,6 +24,7 @@ #define _SysUnloadBin acess__SysUnloadBin #define _SysSetFaultHandler acess__SysSetFaultHandler #define _SysDebug acess__SysDebug +#define _SysDebugHex acess__SysDebugHex #define _SysGetPhys acess__SysGetPhys #define _SysAllocate acess__SysAllocate #define _SysSetMemFlags acess__SysSetMemFlags @@ -34,6 +35,7 @@ #define _SysFDFlags acess__SysFDFlags #define _SysClose acess__SysClose #define _SysRead acess__SysRead +#define _SysTruncate acess__SysTruncate #define _SysWrite acess__SysWrite #define _SysSeek acess__SysSeek #define _SysTell acess__SysTell @@ -46,5 +48,9 @@ #define _SysSelect acess__SysSelect #define _SysMkDir acess__SysMkDir #define _SysUnlink acess__SysUnlink +#define _SysMMap acess__SysMMap +#define _SysMUnMap acess__SysMUnMap +#define _SysMarshalFD acess__SysMarshalFD +#define _SysUnMarshalFD acess__SysUnMarshalFD #define _errno acess__errno diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/joystick.h b/Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/joystick.h new file mode 100644 index 0000000000000000000000000000000000000000..e5d670f20ef6e404348f15964d485432fdae3b00 --- /dev/null +++ b/Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/joystick.h @@ -0,0 +1,47 @@ +/* + * Acess2 System Calls + * - By John Hodge (thePowersGang) + * + * acess/devices/joystick.h + * - Joystick IOCtls and structures + */ +#ifndef _SYS_DEVICES_JOYSTICK_H +#define _SYS_DEVICES_JOYSTICK_H + +#if __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +struct mouse_attribute +{ + uint32_t Num; + uint32_t Value; +}; + +struct mouse_header +{ + uint16_t NAxies; + uint16_t NButtons; +}; + +struct mouse_axis +{ + int16_t MinValue; + int16_t MaxValue; + int16_t CurValue; + uint16_t CursorPos; +}; + +enum { + JOY_IOCTL_GETSETAXISLIMIT = 6, + JOY_IOCTL_GETSETAXISPOSITION, +}; + +#if __cplusplus +} +#endif + +#endif + diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/pty_cmds.h b/Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/pty_cmds.h index 2ec0cd077af769b98b2ffba67c61432bd3b5db8e..fde5d837c7ba30458d52af85da2f52ca43c11daa 100644 --- a/Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/pty_cmds.h +++ b/Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/pty_cmds.h @@ -25,6 +25,7 @@ enum struct ptycmd_header { uint8_t cmd; + // NOTE: Length is encoded as a count of 32-bit words uint8_t len_low; uint16_t len_hi; } PACKED; @@ -44,5 +45,11 @@ struct ptycmd_setcursorbmp char data[]; } PACKED; +struct ptycmd_senddata +{ + struct ptycmd_header hdr; + uint32_t ofs; +} PACKED; + #endif diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/acess/sys.h b/Usermode/Libraries/ld-acess.so_src/include_exp/acess/sys.h index d32f8c33b2e09d096be41cc7cc832e60a56cbc76..4e0f14524069191b98641b71e5f69a6dea8a435a 100644 --- a/Usermode/Libraries/ld-acess.so_src/include_exp/acess/sys.h +++ b/Usermode/Libraries/ld-acess.so_src/include_exp/acess/sys.h @@ -40,6 +40,14 @@ extern "C" { #define FILEFLAG_SYMLINK 0x20 #define CLONE_VM 0x10 +#define MMAP_PROT_READ 0x001 //!< Readable memory +#define MMAP_PROT_WRITE 0x002 //!< Writable memory +#define MMAP_PROT_EXEC 0x004 //!< Executable memory +#define MMAP_MAP_SHARED 0x001 //!< Shared with all other users of the FD +#define MMAP_MAP_PRIVATE 0x002 //!< Local (COW) copy +#define MMAP_MAP_FIXED 0x004 //!< Load to a fixed address +#define MMAP_MAP_ANONYMOUS 0x008 //!< Not associated with a FD + #ifdef ARCHDIR_is_native # include "_native_syscallmod.h" #endif @@ -51,6 +59,7 @@ extern int _errno; // === FUNCTIONS === extern void _SysDebug(const char *format, ...); +extern void _SysDebugHex(const char *Label, const void *Data, size_t Size); // --- Proc --- extern void _exit(int status) __attribute__((noreturn)); extern int _SysKill(int pid, int sig); @@ -88,9 +97,12 @@ extern int _SysReopen(int fd, const char *path, int flags); extern int _SysCopyFD(int srcfd, int dstfd); extern int _SysFDFlags(int fd, int mask, int newflags); extern size_t _SysRead(int fd, void *buffer, size_t length); +extern size_t _SysReadAt(int fd, uint64_t offset, size_t length, void *buffer); +extern uint64_t _SysTruncate(int fd, uint64_t size); extern int _SysClose(int fd); extern int _SysFDCtl(int fd, int option, ...); extern size_t _SysWrite(int fd, const void *buffer, size_t length); +extern size_t _SysWriteAt(int fd, uint64_t offset, size_t length, const void *buffer); extern int _SysSeek(int fd, int64_t offset, int whence); extern uint64_t _SysTell(int fd); extern int _SysIOCtl(int fd, int id, void *data); @@ -102,6 +114,16 @@ extern int _SysSelect(int nfds, fd_set *read, fd_set *write, fd_set *err, int64_ //#define select(nfs, rdfds, wrfds, erfds, timeout) _SysSelect(nfs, rdfds, wrfds, erfds, timeout, 0) extern int _SysMkDir(const char *dirname); extern int _SysUnlink(const char *pathname); +extern void* _SysMMap(void *addr, size_t length, unsigned int _flags, int fd, uint64_t offset); +#ifdef _SysMMap +# undef _SysMMap +# define _SysMMap(addr,length,flags,prot,fd,offset) acess__SysMMap(addr,length,(flags|(prot<<16)), fd, offset) +#else +# define _SysMMap(addr,length,flags,prot,fd,offset) _SysMMap(addr,length,(flags|(prot<<16)), fd, offset) +#endif +extern int _SysMUnMap(void *addr, size_t length); +extern uint64_t _SysMarshalFD(int FD); +extern int _SysUnMarshalFD(uint64_t Handle); // --- IPC --- extern int _SysSendMessage(int dest, size_t length, const void *Data); diff --git a/Usermode/Libraries/ld-acess.so_src/loadlib.c b/Usermode/Libraries/ld-acess.so_src/loadlib.c index 88aafc31a98010ebbed0ec94810612be8d0e04c1..31dcbd8acfa23840d954df1e2b555c7a78fee44f 100644 --- a/Usermode/Libraries/ld-acess.so_src/loadlib.c +++ b/Usermode/Libraries/ld-acess.so_src/loadlib.c @@ -4,6 +4,7 @@ */ #include "common.h" #include <stdint.h> +#include <stdbool.h> #include <acess/sys.h> #define DEBUG 0 @@ -14,8 +15,7 @@ # define DEBUGS(v...) #endif -// === PROTOTYPES === -void *IsFileLoaded(const char *file); +#define MAX_QUEUED_ENTRYPOINTS 8 // === IMPORTS === extern const struct { @@ -26,10 +26,21 @@ extern const int ciNumLocalExports; extern char **gEnvP; extern char gLinkedBase[]; +// === TYPES === +typedef void tLibEntry(void *, int, char *[], char**); + +// === PROTOTYPES === +void *IsFileLoaded(const char *file); + // === GLOABLS === tLoadedLib gLoadedLibraries[MAX_LOADED_LIBRARIES]; char gsLoadedStrings[MAX_STRINGS_BYTES]; char *gsNextAvailString = gsLoadedStrings; +struct sQueuedEntry { + void *Base; + tLibEntry *Entry; +} gaQueuedEntrypoints[MAX_QUEUED_ENTRYPOINTS]; + int giNumQueuedEntrypoints; //tLoadLib *gpLoadedLibraries = NULL; // === CODE === @@ -45,6 +56,20 @@ void ldacess_DumpLoadedLibraries(void) } } +/** + * \brief Call queued up entry points (after relocations completed) + */ +void CallQueuedEntrypoints(char **EnvP) +{ + while( giNumQueuedEntrypoints ) + { + giNumQueuedEntrypoints --; + const struct sQueuedEntry *qe = &gaQueuedEntrypoints[giNumQueuedEntrypoints]; + DEBUGS("Calling EP %p for %p", qe->Entry, qe->Base); + qe->Entry(qe->Base, 0, NULL, EnvP); + } +} + const char *FindLibrary(char *DestBuf, const char *SoName, const char *ExtraSearchDir) { // -- #1: Executable Specified @@ -72,14 +97,12 @@ const char *FindLibrary(char *DestBuf, const char *SoName, const char *ExtraSear void *LoadLibrary(const char *SoName, const char *SearchDir, char **envp) { char sTmpName[1024]; - const char *filename; void *base; - void (*fEntry)(void *, int, char *[], char**); DEBUGS("LoadLibrary: (SoName='%s', SearchDir='%s', envp=%p)", SoName, SearchDir, envp); // Create Temp Name - filename = FindLibrary(sTmpName, SoName, SearchDir); + const char *filename = FindLibrary(sTmpName, SoName, SearchDir); if(filename == NULL) { DEBUGS("LoadLibrary: RETURN 0"); return 0; @@ -91,6 +114,7 @@ void *LoadLibrary(const char *SoName, const char *SearchDir, char **envp) DEBUGS(" LoadLibrary: SysLoadBin()"); // Load Library + tLibEntry *fEntry; base = _SysLoadBin(filename, (void**)&fEntry); if(!base) { DEBUGS("LoadLibrary: RETURN 0"); @@ -106,10 +130,17 @@ void *LoadLibrary(const char *SoName, const char *SearchDir, char **envp) } // Call Entrypoint - DEBUGS(" LoadLibrary: '%s' Entry %p", SoName, fEntry); - fEntry(base, 0, NULL, gEnvP); + // - TODO: Queue entrypoint calls + if( giNumQueuedEntrypoints >= MAX_QUEUED_ENTRYPOINTS ) { + SysDebug("ERROR - Maximum number of queued entrypoints exceeded on %p '%s'", + base, SoName); + return 0; + } + gaQueuedEntrypoints[giNumQueuedEntrypoints].Base = base; + gaQueuedEntrypoints[giNumQueuedEntrypoints].Entry = fEntry; + giNumQueuedEntrypoints ++; - DEBUGS("LoadLibrary: RETURN 1"); + DEBUGS("LoadLibrary: RETURN success"); return base; } @@ -223,34 +254,50 @@ void Unload(void *Base) \fn Uint GetSymbol(const char *name) \brief Gets a symbol value from a loaded library */ -int GetSymbol(const char *name, void **Value, size_t *Size) +int GetSymbol(const char *name, void **Value, size_t *Size, void *IgnoreBase) { - int i; - - //SysDebug("ciNumLocalExports = %i", ciNumLocalExports); - for(i=0;i<ciNumLocalExports;i++) + //SysDebug("GetSymbol: (%s)"); + for( int i = 0; i < ciNumLocalExports; i ++ ) { if( strcmp(caLocalExports[i].Name, name) == 0 ) { *Value = caLocalExports[i].Value; if(Size) *Size = 0; + //SysDebug("GetSymbol: Local %p+0x%x", *Value, 0); return 1; } } - - // Entry 0 is ld-acess, ignore it - for(i = 0; i < MAX_LOADED_LIBRARIES; i ++) + + bool have_weak = false; + for(int i = 0; i < MAX_LOADED_LIBRARIES && gLoadedLibraries[i].Base != 0; i ++) { - if(gLoadedLibraries[i].Base == 0) - break; + // Allow ignoring the current module + if( gLoadedLibraries[i].Base == IgnoreBase ) { + //SysDebug("GetSymbol: Ignore %p", gLoadedLibraries[i].Base); + continue ; + } //SysDebug(" GetSymbol: Trying 0x%x, '%s'", // gLoadedLibraries[i].Base, gLoadedLibraries[i].Name); - if(GetSymbolFromBase(gLoadedLibraries[i].Base, name, Value, Size)) - return 1; + void *tmpval; + size_t tmpsize; + int rv = GetSymbolFromBase(gLoadedLibraries[i].Base, name, &tmpval, &tmpsize); + if(rv) + { + *Value = tmpval; + *Size = tmpsize; + if( rv == 1 ) { + return 1; + } + have_weak = true; + } + } + if(have_weak) { + return 2; + } + else { + return 0; } - SysDebug("GetSymbol: === Symbol '%s' not found ===", name); - return 0; } /** diff --git a/Usermode/Libraries/ld-acess.so_src/main.c b/Usermode/Libraries/ld-acess.so_src/main.c index 40c603ee2f94988b8017d7691b982499deab98ed..976ceec445a3c6483d3020ca50129d93d14290a5 100644 --- a/Usermode/Libraries/ld-acess.so_src/main.c +++ b/Usermode/Libraries/ld-acess.so_src/main.c @@ -5,6 +5,7 @@ #include <stdint.h> #include <stddef.h> #include "common.h" +#undef SoMain // === PROTOTYPES === void *DoRelocate(void *base, char **envp, const char *Filename); @@ -14,6 +15,7 @@ void *DoRelocate(void *base, char **envp, const char *Filename); extern char gLinkedBase[]; char **gEnvP; extern int memcmp(const void *m1, const void *m2, size_t size); +extern void CallQueuedEntrypoints(char **EnvP); // === CODE === /** @@ -41,7 +43,6 @@ void *SoMain(void *base, int argc, char **argv, char **envp) } // Otherwise do relocations - //ret = DoRelocate( base, envp, "Executable" ); ret = DoRelocate( base, NULL, "Executable" ); if( ret == 0 ) { SysDebug("ld-acess - SoMain: Relocate failed, base=0x%x\n", base); @@ -49,7 +50,10 @@ void *SoMain(void *base, int argc, char **argv, char **envp) for(;;); } - SysDebug("ld-acess - SoMain: ret = %p", ret); + // Call queued entry points (from libraries) + CallQueuedEntrypoints(envp); + + SysDebug("ld-acess - SoMain: Program entry %p", ret); return ret; } diff --git a/Usermode/Libraries/libaxwin4.so_src/Makefile b/Usermode/Libraries/libaxwin4.so_src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c530c558a4e110b9f66a94d6b99ee38f6f9b66fd --- /dev/null +++ b/Usermode/Libraries/libaxwin4.so_src/Makefile @@ -0,0 +1,29 @@ +# Acess2 AxWin4 Library +# Makefile + +-include ../Makefile.cfg + +AXWIN4DIR := ../../Applications/axwin4_src/ + +CPPFLAGS += -I$(AXWIN4DIR)Common/include/ +CFLAGS += -Wextra +CXXFLAGS += +ASFLAGS += +LDFLAGS += -soname libaxwin4.so -Map map.txt +LIBS += -lc -lc++ + +OBJ = main.o ipc.o ipc_acessipcpipe.o +OBJ += wm.o window_drawing.o +OBJ += Common__serialisation.o +BIN = libaxwin4.so + +include ../Makefile.tpl + +$(_OBJPREFIX)Common__%.o: $(AXWIN4DIR)/Common/%.cpp + @echo [CXX] -o $@ + @mkdir -p $(dir $@) + $V$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@ -MQ $@ -MP -MD -MF $(@:%=%.dep) + + + + diff --git a/Usermode/Libraries/libaxwin4.so_src/include/CIPCChannel_AcessIPCPipe.hpp b/Usermode/Libraries/libaxwin4.so_src/include/CIPCChannel_AcessIPCPipe.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d04d0524a7d6ab4ea838d553e520d4ca5d52ebcd --- /dev/null +++ b/Usermode/Libraries/libaxwin4.so_src/include/CIPCChannel_AcessIPCPipe.hpp @@ -0,0 +1,30 @@ +/* + * Acess2 GUIv4 Library + * - By John Hodge (thePowersGang) + * + * CIPCChannel_AcessIPCPipe.h + * - Acess IPC Datagram pipe + */ +#ifndef _LIBAXWIN4_CIPCCHANNEL_ACESSIPCPIPE_H_ +#define _LIBAXWIN4_CIPCCHANNEL_ACESSIPCPIPE_H_ + +#include "IIPCChannel.hpp" + +namespace AxWin { + +class CIPCChannel_AcessIPCPipe: + public IIPCChannel +{ + int m_fd; +public: + CIPCChannel_AcessIPCPipe(const char *Path); + virtual ~CIPCChannel_AcessIPCPipe(); + virtual int FillSelect(fd_set& fds); + virtual bool HandleSelect(const fd_set& fds); + virtual void Send(CSerialiser& message); +}; + +}; // namespace AxWin + +#endif + diff --git a/Usermode/Libraries/libaxwin4.so_src/include/IIPCChannel.hpp b/Usermode/Libraries/libaxwin4.so_src/include/IIPCChannel.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c4a514f7da3c061b2722a27915c33253dffd4621 --- /dev/null +++ b/Usermode/Libraries/libaxwin4.so_src/include/IIPCChannel.hpp @@ -0,0 +1,33 @@ +/* + * Acess2 GUIv4 Library + * - By John Hodge (thePowersGang) + * + * IIPCChannel.h + * - IPC Channel interface + */ +#ifndef _LIBAXWIN4_IIPCCHANNEL_H_ +#define _LIBAXWIN4_IIPCCHANNEL_H_ + +#include <serialisation.hpp> + +#include <acess/sys.h> + +namespace AxWin { + +class IIPCChannel +{ +public: + virtual ~IIPCChannel(); + virtual int FillSelect(fd_set& fds) = 0; + /** + * \return False if the connection has dropped/errored + */ + virtual bool HandleSelect(const fd_set& fds) = 0; + + virtual void Send(CSerialiser& message) = 0; +}; + +}; // namespace AxWin + +#endif + diff --git a/Usermode/Libraries/libaxwin4.so_src/include/common.hpp b/Usermode/Libraries/libaxwin4.so_src/include/common.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e3aa80743f9d1009954f5d33a7dcf30eacf0a4af --- /dev/null +++ b/Usermode/Libraries/libaxwin4.so_src/include/common.hpp @@ -0,0 +1,29 @@ +/* + * Acess2 GUIv4 Library + * - By John Hodge (thePowersGang) + * + * common.h + * - Library internal header + */ +#ifndef _LIBAXWIN4_COMMON_H_ +#define _LIBAXWIN4_COMMON_H_ + +#include <serialisation.hpp> + +namespace AxWin { + +extern void SendMessage(CSerialiser& message); +extern void RecvMessage(CDeserialiser& message); +extern CDeserialiser GetSyncReply(CSerialiser& request, unsigned int Message); + +}; + +struct sAxWin4_Window +{ + unsigned int m_id; + int m_fd; + void *m_buffer; +}; + +#endif + diff --git a/Usermode/Libraries/libaxwin4.so_src/include_exp/axwin4/axwin.h b/Usermode/Libraries/libaxwin4.so_src/include_exp/axwin4/axwin.h new file mode 100644 index 0000000000000000000000000000000000000000..255b0e1dbc6a343b239429bf9c0506cc00a4ac81 --- /dev/null +++ b/Usermode/Libraries/libaxwin4.so_src/include_exp/axwin4/axwin.h @@ -0,0 +1,88 @@ +/* + * Acess2 GUIv4 (AxWin4) + * - By John Hodge (thePowersGang) + * + * axwin4/axwin.h + * - Client library interface header + */ +#ifndef _LIBAXWIN4_AXWIN4_AXWIN_H_ +#define _LIBAXWIN4_AXWIN4_AXWIN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stdbool.h> +#include <acess/sys.h> + +typedef struct sAxWin4_Window tAxWin4_Window; + +// - Abstractions of core IPC methods +extern bool AxWin4_Connect(const char *URI); + +extern bool AxWin4_WaitEventQueue(uint64_t Timeout); +extern bool AxWin4_WaitEventQueueSelect(int nFDs, fd_set *rfds, fd_set *wfds, fd_set *efds, uint64_t Timeout); + +extern void AxWin4_GetScreenDimensions(unsigned int ScreenIndex, unsigned int *Width, unsigned int *Height); + +extern tAxWin4_Window *AxWin4_CreateWindow(const char *Name); +extern void AxWin4_DestroyWindow(tAxWin4_Window *Window); + +// Callbacks +typedef int tAxWin4_KeyCallback(tAxWin4_Window* Winow, unsigned int Key, const char *Translated); +extern void AxWin4_SetCallback_Key(tAxWin4_Window* Window, tAxWin4_KeyCallback* cb); +typedef int tAxWin4_MouseBtnCallback(tAxWin4_Window* Winow, unsigned int Mouse, unsigned int X, unsigned int Y, unsigned int Button, bool IsPress); +extern void AxWin4_SetCallback_MouseBtn(tAxWin4_Window* Window, tAxWin4_MouseBtnCallback* cb); +typedef int tAxWin4_MouseMoveCallback(tAxWin4_Window* Winow, unsigned int Mouse, unsigned int X, unsigned int Y); + +extern void AxWin4_ShowWindow(tAxWin4_Window *Window, bool Shown); +extern void AxWin4_SetWindowFlags(tAxWin4_Window *Window, unsigned int NewFlags); +extern void AxWin4_SetTitle(tAxWin4_Window *Window, const char *Title); +extern void AxWin4_MoveWindow(tAxWin4_Window *Window, int X, int Y); +extern void AxWin4_ResizeWindow(tAxWin4_Window *Window, unsigned int W, unsigned int H); + +extern void AxWin4_DamageRect(tAxWin4_Window *Window, unsigned int X, unsigned int Y, unsigned int W, unsigned int H); +extern void* AxWin4_GetWindowBuffer(tAxWin4_Window *Window); + +/** + * \brief Set the render clipping region. Any attempts to render outside this area will silently fail + * \param Window Target window + * + * \note Allows clipping other render functions to avoid excessive redraws + * \note Cleared when \a AxWin4_DamageRect is called, or when called with a zero width or height + */ +extern void AxWin4_SetRenderClip(tAxWin4_Window *Window, int X, int Y, unsigned int W, unsigned int H); + +/** + * \brief Draw a user-supplied bitmap to the window + * \param Data Bitmap data in the same format as the window's back buffer + * \note VERY SLOW + */ +extern void AxWin4_DrawBitmap(tAxWin4_Window *Window, int X, int Y, unsigned int W, unsigned int H, void *Data); +/** + * \brief Draw a "control" to the window + * \param Window Target window + * \param X Destination X + * \param Y Destination Y + * \param W Control width + * \param H Control height + * \param ControlID Specifies which control to use. Can be a global or application-registered (See eAxWin4_GlobalControls) + * \param Frame Control frame number. Used to specify a variant of the control (e.g. hovered/pressed) + * + * Controls are server-side bitmaps that can be arbitarily scaled to fit a region. + */ +extern void AxWin4_DrawControl(tAxWin4_Window *Window, int X, int Y, unsigned int W, unsigned int H, uint16_t ControlID, unsigned int Frame); + +extern void AxWin4_FillRect(tAxWin4_Window *Window, int X, int Y, unsigned int W, unsigned int H, uint32_t Colour); + +extern void AxWin4_DrawText(tAxWin4_Window *Window, int X, int Y, unsigned int W, unsigned int H, uint16_t FontID, const char *String); + +#include "definitions.h" + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/Usermode/Libraries/libaxwin4.so_src/include_exp/axwin4/definitions.h b/Usermode/Libraries/libaxwin4.so_src/include_exp/axwin4/definitions.h new file mode 100644 index 0000000000000000000000000000000000000000..5fe7e4db908a29435790490c1af061cb4cbfd559 --- /dev/null +++ b/Usermode/Libraries/libaxwin4.so_src/include_exp/axwin4/definitions.h @@ -0,0 +1,38 @@ +/* + * Acess2 GUIv4 (AxWin4) + * - By John Hodge (thePowersGang) + * + * axwin4/definitions.h + * - Shared definitions (Client and server) + */ +#ifndef _LIBAXWIN4_AXWIN4_DEFINITIONS_H_ +#define _LIBAXWIN4_AXWIN4_DEFINITIONS_H_ + +/** + * \name Window Flags + * \{ + */ +#define AXWIN4_WNDFLAG_NODECORATE 0x01 //!< Disable automatic inclusion of window decorations +#define AXWIN4_WNDFLAG_KEEPBELOW 0x02 //!< Keep the window below all others, even when it has focus +#define AXWIN4_WNDFLAG_KEEPABOVE 0x04 //!< Keep window above all others, ecen when it loses focus +/** + * \} + */ + +/** + * \brief Global controls + */ +enum eAxWin4_GlobalControls { + AXWIN4_CTL_BUTTON, //!< Standard button (possibly rounded edges) + AXWIN4_CTL_BOX, //!< Grouping box in a window + AXWIN4_CTL_TOOLBAR, //!< Toolbar (raised region) + AXWIN4_CTL_TEXTBOX, //!< Text edit box +}; + +enum eAxWin4_GlobalFonts { + AXWIN4_FONT_DEFAULT, //!< Default font (usually a sans-serif) + AXWIN4_FONT_MONOSPACE, //!< Default monospace font +}; + +#endif + diff --git a/Usermode/Libraries/libaxwin4.so_src/ipc.cpp b/Usermode/Libraries/libaxwin4.so_src/ipc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d0455f53a8a673607d2dd42d591defdf85f6d2f7 --- /dev/null +++ b/Usermode/Libraries/libaxwin4.so_src/ipc.cpp @@ -0,0 +1,178 @@ +/* + * AxWin4 Interface Library + * - By John Hodge (thePowersGang) + * + * ipc.c + * - IPC Abstraction + */ +#include <axwin4/axwin.h> +#include "include/common.hpp" +#include "include/IIPCChannel.hpp" +#include "include/CIPCChannel_AcessIPCPipe.hpp" +#include <ipc_proto.hpp> +#include <algorithm> +#include <mutex> +#include <stdexcept> + +#include <cstring> +#include <cstdio> + +namespace AxWin { + +IIPCChannel* gIPCChannel; +::std::mutex glSyncReply; +bool gSyncReplyActive; +bool gSyncReplyValid; +CDeserialiser gSyncReplyBuf; + +extern "C" bool AxWin4_Connect(const char *URI) +{ + _SysDebug("AxWin4_Connect('%s')", URI); + if( gIPCChannel ) { + return false; + } + try { + if( strncmp(URI, "ipcpipe://", 3+4+3) == 0 ) + { + gIPCChannel = new CIPCChannel_AcessIPCPipe(URI+3+4+3); + } + else + { + _SysDebug("Unknown protocol"); + return false; + } + } + catch( const ::std::exception& e ) + { + fprintf(stderr, "AxWin4_Connect: %s\n", e.what()); + return false; + } + return true; +} + +extern "C" bool AxWin4_PeekEventQueue(void) +{ + return false; +} + +extern "C" bool AxWin4_WaitEventQueue(uint64_t Timeout) +{ + return AxWin4_WaitEventQueueSelect(0, NULL, NULL, NULL, Timeout); +} + +extern "C" bool AxWin4_WaitEventQueueSelect(int nFDs, fd_set *rfds, fd_set *wfds, fd_set *efds, uint64_t Timeout) +{ + fd_set local_rfds; + if( !rfds ) { + FD_ZERO(&local_rfds); + rfds = &local_rfds; + } + + int64_t select_timeout = Timeout; + int64_t *select_timeout_p = (Timeout ? &select_timeout : 0); + + nFDs = ::std::max(nFDs, gIPCChannel->FillSelect(*rfds)); + _SysSelect(nFDs, rfds, wfds, efds, select_timeout_p, 0); + return gIPCChannel->HandleSelect(*rfds); +} + +void SendMessage(CSerialiser& message) +{ + gIPCChannel->Send(message); +} +void RecvMessage(CDeserialiser& message) +{ + uint8_t id = message.ReadU8(); + _SysDebug("RecvMessage: id=%i", id); + switch(id) + { + case IPCMSG_PING: + // If we hear ping, we must pong + { + CSerialiser pong; + pong.WriteU8(IPCMSG_REPLY); + pong.WriteU8(IPCMSG_PING); + SendMessage(pong); + } + break; + case IPCMSG_REPLY: + // Flag reply and take a copy of this message + if( !gSyncReplyActive ) + { + _SysDebug("Unexpected reply message %i", message.ReadU8()); + } + else if( gSyncReplyValid ) + { + // Oh... that was unexpected + _SysDebug("Unexpected second reply message %i", message.ReadU8()); + } + else + { + gSyncReplyValid = true; + gSyncReplyBuf = message; + } + break; + // TODO: Handle messages from server (input events, IPC) + // TODO: If an event is currently being processed, save the message in a queue to be handled when processing is complete + // - This will prevent deep recursion (and make server errors aparent) + case IPCMSG_INPUTEVENT: + _SysDebug("TODO: Input events"); + break; + default: + _SysDebug("TODO: RecvMessage(%i)", id); + break; + } +} + +CDeserialiser GetSyncReply(CSerialiser& request, unsigned int Message) +{ + ::std::lock_guard<std::mutex> lock(glSyncReply); + gSyncReplyActive = true; + gSyncReplyValid = false; + // Send once lock is acquired + SendMessage(request); + + while( !gSyncReplyValid ) + { + // Tick along + if( !AxWin4_WaitEventQueue(0) ) + throw ::std::runtime_error("Connection dropped while waiting for reply"); + } + gSyncReplyActive = false; + + uint8_t id = gSyncReplyBuf.ReadU8(); + if( id != Message ) + { + _SysDebug("Unexpected reply message id=%i, expected %i", + id, Message); + throw ::std::runtime_error("Sequencing error, unexpected reply"); + } + + // Use move to avoid copying + return ::std::move(gSyncReplyBuf); +} + +extern "C" void AxWin4_GetScreenDimensions(unsigned int ScreenIndex, unsigned int *Width, unsigned int *Height) +{ + CSerialiser req; + req.WriteU8(IPCMSG_GETGLOBAL); + req.WriteU16(IPC_GLOBATTR_SCREENDIMS); + req.WriteU8(ScreenIndex); + + CDeserialiser response = GetSyncReply(req, IPCMSG_GETGLOBAL); + if( response.ReadU16() != IPC_GLOBATTR_SCREENDIMS ) { + + } + + *Width = response.ReadU16(); + *Height = response.ReadU16(); + + _SysDebug("AxWin4_GetScreenDimensions: %i = %ix%i", ScreenIndex, *Width, *Height); +} + +IIPCChannel::~IIPCChannel() +{ +} + +}; // namespace AxWin + diff --git a/Usermode/Libraries/libaxwin4.so_src/ipc_acessipcpipe.cpp b/Usermode/Libraries/libaxwin4.so_src/ipc_acessipcpipe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87cc6c9315d764ea07f6dfb70977d15163e0612e --- /dev/null +++ b/Usermode/Libraries/libaxwin4.so_src/ipc_acessipcpipe.cpp @@ -0,0 +1,68 @@ +/* + * AxWin4 Interface Library + * - By John Hodge (thePowersGang) + * + * ipc_acessipcpipe.c + * - Acess2 /Devices/ipcpipe/ IPC Channel + */ +#include "include/common.hpp" +#include "include/CIPCChannel_AcessIPCPipe.hpp" +#include <system_error> +#include <cerrno> + +namespace AxWin { + +CIPCChannel_AcessIPCPipe::CIPCChannel_AcessIPCPipe(const char *Path) +{ + m_fd = _SysOpen(Path, OPENFLAG_READ|OPENFLAG_WRITE); + if( m_fd == -1 ) { + throw ::std::system_error(errno, ::std::system_category()); + } +} + +CIPCChannel_AcessIPCPipe::~CIPCChannel_AcessIPCPipe() +{ +} + +int CIPCChannel_AcessIPCPipe::FillSelect(fd_set& fds) +{ + FD_SET(m_fd, &fds); + return m_fd+1; +} + +bool CIPCChannel_AcessIPCPipe::HandleSelect(const fd_set& fds) +{ + if( FD_ISSET(m_fd, &fds) ) + { + ::std::vector<uint8_t> rxbuf(4096); + size_t len = _SysRead(m_fd, rxbuf.data(), rxbuf.capacity()); + if( len == (size_t)-1 ) + throw ::std::system_error(errno, ::std::system_category()); + rxbuf.resize(len); + _SysDebug("CClient_AcessIPCPipe::HandleReceive - Rx %i/%i bytes", len, rxbuf.capacity()); + //_SysDebugHex("CClient_AcessIPCPipe::HandleReceive", rxbuf.data(), len); + + CDeserialiser msg(rxbuf); + ::AxWin::RecvMessage( msg ); + } + return true; +} + +void CIPCChannel_AcessIPCPipe::Send(CSerialiser& message) +{ + const ::std::vector<uint8_t>& serialised = message.Compact(); + if(serialised.size() > 0x1000 ) { + throw ::std::length_error("CIPCChannel_AcessIPCPipe::Send"); + } + _SysDebug("CIPCChannel_AcessIPCPipe::Send(%i bytes)", serialised.size()); + //_SysDebugHex("CIPCChannel_AcessIPCPipe::Send", serialised.data(), serialised.size()); + + size_t rv = _SysWrite(m_fd, serialised.data(), serialised.size()); + if( rv != serialised.size() ) { + throw ::std::system_error(errno, ::std::system_category()); + } +} + + +}; // namespace AxWin + diff --git a/Usermode/Libraries/libaxwin4.so_src/main.c b/Usermode/Libraries/libaxwin4.so_src/main.c new file mode 100644 index 0000000000000000000000000000000000000000..5d555823fb02d75de5bce64d7a4d4ebd74c5151a --- /dev/null +++ b/Usermode/Libraries/libaxwin4.so_src/main.c @@ -0,0 +1,8 @@ +/* + */ +// === CODE === +int SoMain(void) +{ + return 0; +} + diff --git a/Usermode/Libraries/libaxwin4.so_src/window_drawing.cpp b/Usermode/Libraries/libaxwin4.so_src/window_drawing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e6a4448ce4cab82dc2165e919e093c7cef458576 --- /dev/null +++ b/Usermode/Libraries/libaxwin4.so_src/window_drawing.cpp @@ -0,0 +1,91 @@ +/* + * AxWin4 Interface Library + * - By John Hodge (thePowersGang) + * + * window_drawing.cpp + * - Window drawing code + */ +#include <axwin4/axwin.h> +#include "include/common.hpp" +#include <ipc_proto.hpp> +#include <algorithm> // min + +namespace AxWin { + +void _push_data(tAxWin4_Window *Window, int X, int Y, unsigned int W, unsigned int H, const void *Data) +{ + CSerialiser message; + //_SysDebug("_push_data - (%i,%i), %ix%i %p", X, Y, W, H, Data); + message.WriteU8(IPCMSG_PUSHDATA); + message.WriteU16(Window->m_id); + message.WriteU16(X); + message.WriteU16(Y); + message.WriteU16(W); + message.WriteU16(H); + message.WriteBuffer(H*W*4, Data); + ::AxWin::SendMessage(message); +} + +extern "C" void AxWin4_DrawBitmap(tAxWin4_Window *Window, int X, int Y, unsigned int W, unsigned int H, void *Data) +{ + // TODO: Split message up into blocks such that it can be dispatched + if( W > 128 ) + { + const uint32_t* data32 = static_cast<uint32_t*>(Data); + const unsigned int rows_per_message = 1; // 2048 / W; + for( unsigned int row = 0; row < H; row += rows_per_message ) + { + _push_data(Window, X, Y+row, W, ::std::min(rows_per_message,H-row), data32); + data32 += W*rows_per_message; + } + } + else + { + _push_data(Window, X, Y, W, H, Data); + } +} + +extern "C" void AxWin4_DrawControl(tAxWin4_Window *Window, int X, int Y, unsigned int W, unsigned int H, uint16_t ID, unsigned int Frame) +{ + CSerialiser message; + //_SysDebug("AxWin4_DrawControl: (Window->ID=%i, (%i,%i) %ix%i %i 0x%06x", Window->m_id, X, Y, W, H, ID, Frame); + message.WriteU8(IPCMSG_DRAWCTL); + message.WriteU16(Window->m_id); + message.WriteU16(X); + message.WriteU16(Y); + message.WriteU16(W); + message.WriteU16(H); + message.WriteU16(ID); + message.WriteU16(Frame); + ::AxWin::SendMessage(message); +} + +extern "C" void AxWin4_FillRect(tAxWin4_Window *Window, int X, int Y, unsigned int W, unsigned int H, uint32_t Colour) +{ + CSerialiser message; + message.WriteU8(IPCMSG_FILLRECT); + message.WriteU16(Window->m_id); + message.WriteU16(X); + message.WriteU16(Y); + message.WriteU16(W); + message.WriteU16(H); + message.WriteU32(Colour); + ::AxWin::SendMessage(message); +} + +extern "C" void AxWin4_DrawText(tAxWin4_Window *Window, int X, int Y, unsigned int W, unsigned int H, uint16_t FontID, const char *String) +{ + CSerialiser message; + message.WriteU8(IPCMSG_DRAWTEXT); + message.WriteU16(Window->m_id); + message.WriteU16(X); + message.WriteU16(Y); + message.WriteU16(W); + message.WriteU16(H); + message.WriteU16(FontID); + message.WriteString(String); + ::AxWin::SendMessage(message); +} + +}; // namespace AxWin + diff --git a/Usermode/Libraries/libaxwin4.so_src/wm.cpp b/Usermode/Libraries/libaxwin4.so_src/wm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cae79c719a824d9c8005fe683eca2a746c8774ab --- /dev/null +++ b/Usermode/Libraries/libaxwin4.so_src/wm.cpp @@ -0,0 +1,150 @@ +/* + * AxWin4 Interface Library + * - By John Hodge (thePowersGang) + * + * wm.cpp + * - Window Management + */ +#include <axwin4/axwin.h> +#include "include/common.hpp" +#include <ipc_proto.hpp> +#include <vector> +#include <algorithm> +#include <mutex> +#include <cassert> + +namespace AxWin { + +static const int MAX_WINDOW_ID = 16; +static ::std::mutex glWindowList; +static ::std::vector<tAxWin4_Window*> gWindowList; + +extern "C" tAxWin4_Window *AxWin4_CreateWindow(const char *Name) +{ + // Allocate a window ID + ::std::lock_guard<std::mutex> lock(glWindowList); + int id = ::std::find(gWindowList.begin(), gWindowList.end(), nullptr) - gWindowList.begin(); + if( id >= MAX_WINDOW_ID ) { + throw ::std::runtime_error("AxWin4_CreateWindow - Out of IDs (TODO: Better exception)"); + } + if( id == gWindowList.size() ) + { + gWindowList.push_back(nullptr); + } + assert(gWindowList[id] == nullptr); + + // Create window structure locally + tAxWin4_Window *ret = new tAxWin4_Window(); + gWindowList[id] = ret; + ret->m_id = id; + ret->m_fd = -1; + ret->m_buffer = nullptr; + // Request creation of window + CSerialiser message; + message.WriteU8(IPCMSG_CREATEWIN); + message.WriteU16(ret->m_id); + message.WriteString(Name); + ::AxWin::SendMessage(message); + return ret; +} + +extern "C" void AxWin4_ShowWindow(tAxWin4_Window *Window, bool Show) +{ + CSerialiser message; + message.WriteU8(IPCMSG_SETWINATTR); + message.WriteU16(Window->m_id); + message.WriteU16(IPC_WINATTR_SHOW); + message.WriteU8( (Show ? 1 : 0) ); + ::AxWin::SendMessage(message); +} + +extern "C" void AxWin4_SetWindowFlags(tAxWin4_Window *Window, unsigned int Flags) +{ + CSerialiser message; + message.WriteU8(IPCMSG_SETWINATTR); + message.WriteU16(Window->m_id); + message.WriteU16(IPC_WINATTR_FLAGS); + message.WriteU8( Flags ); + ::AxWin::SendMessage(message); +} + +extern "C" void AxWin4_MoveWindow(tAxWin4_Window *Window, int X, int Y) +{ + CSerialiser message; + message.WriteU8(IPCMSG_SETWINATTR); + message.WriteU16(Window->m_id); + message.WriteU16(IPC_WINATTR_POSITION); + message.WriteS16(X); + message.WriteS16(Y); + ::AxWin::SendMessage(message); +} +extern "C" void AxWin4_ResizeWindow(tAxWin4_Window *Window, unsigned int W, unsigned int H) +{ + CSerialiser message; + message.WriteU8(IPCMSG_SETWINATTR); + message.WriteU16(Window->m_id); + message.WriteU16(IPC_WINATTR_DIMENSIONS); + message.WriteU16(W); + message.WriteU16(H); + ::AxWin::SendMessage(message); +} + +extern "C" void AxWin4_SetTitle(tAxWin4_Window *Window, const char *Title) +{ + CSerialiser message; + message.WriteU8(IPCMSG_SETWINATTR); + message.WriteU16(Window->m_id); + message.WriteU16(IPC_WINATTR_TITLE); + message.WriteString(Title); + ::AxWin::SendMessage(message); +} + +extern "C" void AxWin4_DamageRect(tAxWin4_Window *Window, unsigned int X, unsigned int Y, unsigned int W, unsigned int H) +{ + CSerialiser message; + message.WriteU8(IPCMSG_DAMAGERECT); + message.WriteU16(Window->m_id); + message.WriteU16(X); + message.WriteU16(Y); + message.WriteU16(W); + message.WriteU16(H); + ::AxWin::SendMessage(message); +} + +extern "C" void *AxWin4_GetWindowBuffer(tAxWin4_Window *Window) +{ + if( Window->m_fd == -1 ) + { + CSerialiser req; + req.WriteU8(IPCMSG_GETWINBUF); + req.WriteU16(Window->m_id); + + CDeserialiser response = GetSyncReply(req, IPCMSG_GETWINBUF); + unsigned int rspwin = response.ReadU16(); + if( rspwin != Window->m_id ) + { + _SysDebug("AxWin4_GetWindowBuffer: GETWINBUF reply for different window (%u != %u)", rspwin, Window->m_id); + return NULL; + } + + uint64_t handle = response.ReadU64(); + Window->m_fd = _SysUnMarshalFD(handle); + if( Window->m_fd == -1 ) { + _SysDebug("AxWin4_GetWindowBuffer: Unable to unmarshal resultant FD (0x%llx)", handle); + return NULL; + } + + _SysDebug("AxWin4_GetWindowBuffer: %llx = %i", handle, Window->m_fd); + } + + if( !Window->m_buffer ) + { + size_t size = 640*480*4; + Window->m_buffer = _SysMMap(NULL, size, MMAP_PROT_WRITE, MMAP_MAP_SHARED, Window->m_fd, 0); + } + + return Window->m_buffer; +} + +}; // namespace AxWin + diff --git a/Usermode/Libraries/libc++.so_src/Makefile b/Usermode/Libraries/libc++.so_src/Makefile index 6cec94f11e6bf5f5abe329f4ea7a2db9f32c4486..72538379f47c0e1b39788ff9d576ffee560c71af 100644 --- a/Usermode/Libraries/libc++.so_src/Makefile +++ b/Usermode/Libraries/libc++.so_src/Makefile @@ -7,13 +7,22 @@ CPPFLAGS += CFLAGS += -Wall -Werror -Wextra CXXFLAGS += -Wall -Werror -Wextra ASFLAGS += -LDFLAGS += -Map map.txt -lc +LDFLAGS += -nostdlib +PRELINK := $(CRTI) $(CRTBEGINS) $(CRT0S) +LIBS += -lc $(LIBGCC_PATH) $(CRTENDS) $(CRTN) +USE_CXX_LINK := yes OBJ = misc.o new.o guard.o cxxabi.o typeinfo.o +OBJ += string.o mutex.o +OBJ += exceptions.o exception_handling.o system_error.o +OBJ += gxx_personality.o +ifeq ($(ARCHDIR),native) +# - Include libgcc_eh (separate in linux), and the linux libc (space avoids hack in Makefile.tpl) +LIBS += -lgcc_eh -l c +endif DEPFILES := $(OBJ:%.o=%.d) BIN = libc++.so ifeq ($(ARCHDIR),native) - OBJ := $(filter-out heap.o,$(OBJ)) BIN = libc++_acess.so endif diff --git a/Usermode/Libraries/libc++.so_src/cxxabi.cc b/Usermode/Libraries/libc++.so_src/cxxabi.cc index adda291c7982acd1cfc976bebbcc9a18a5d4ba2d..bd35690af4146f4dd554260814b024c8b21feffc 100644 --- a/Usermode/Libraries/libc++.so_src/cxxabi.cc +++ b/Usermode/Libraries/libc++.so_src/cxxabi.cc @@ -4,8 +4,13 @@ * * cxxabi.cc * - C++ ABI Namespace + * + * NOTE: GCC follows the Itaniumâ„¢ C++ ABI on all platforms + * http://mentorembedded.github.io/cxx-abi/abi.html + * http://libcxxabi.llvm.org/spec.html */ #include <cxxabi.h> +#include <acess/sys.h> namespace __cxxabiv1 { @@ -30,3 +35,28 @@ __vmi_class_type_info::~__vmi_class_type_info() }; // namespace __cxxabiv1 +extern "C" void __cxa_bad_cast () +{ + _SysDebug("__cxa_bad_cast"); + for(;;); + //throw ::std::bad_cast; +} + +extern "C" void __cxa_bad_typeid () +{ + _SysDebug("__cxa_bad_typeid"); + for(;;); + //throw ::std::bad_typeid; +} + +extern "C" void* __dynamic_cast( + const void *sub, + const __cxxabiv1::__class_type_info *src, + const __cxxabiv1::__class_type_info *dst, + ptrdiff_t src2dst_offset + ) +{ + _SysDebug("TODO: __dynamic_cast %p %s to %s, hint=%p", sub, dst->name(), src->name(), src2dst_offset); + return NULL; +} + diff --git a/Usermode/Libraries/libc++.so_src/exception_handling.cc b/Usermode/Libraries/libc++.so_src/exception_handling.cc new file mode 100644 index 0000000000000000000000000000000000000000..81d460524443a3b42a66a670513a438b02beba0b --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/exception_handling.cc @@ -0,0 +1,152 @@ +/* + * Acess2 C++ Support Library + * - By John Hodge (thePowersGang) + * + * exception_handling.cc + * - Exception handling code (defined by C++ ABI) + * + * References: + * - LLVM Exception handling + * > http://llvm.org/docs/ExceptionHandling.html + * - Itanium C++ ABI + * >http://mentorembedded.github.io/cxx-abi/abi-eh.html + * - HP's "aC++" Document, Ch 7 "Exception Handling Tables" + * > http://mentorembedded.github.io/cxx-abi/exceptions.pdf + */ +#include <typeinfo> +#include <cstdint> +#include <cstddef> +#include <cstdlib> +#include <cstring> +#include <exception> +#include "exception_handling_cxxabi.h" + +#include <acess/sys.h> + +#define DEBUG_ENABLED 1 + +#if DEBUG_ENABLED +# define DEBUG(v...) ::_SysDebug(v) +#else +# define DEBUG(v...) do{}while(0) +#endif + +/*__thread*/ struct __cxa_eh_globals { + __cxa_exception *caughtExceptions; + unsigned int uncaughtExceptions; +} eh_globals; + +/*__thread*/ struct { + __cxa_exception info; + char buf[32]; +} emergency_exception; +/*__thread*/ bool emergency_exception_used; + +static bool TEST_AND_SET(bool& flag) { + bool ret = flag; + flag = true; + return ret; +} + +// === CODE === +extern "C" __cxa_eh_globals *__cxa_get_globals(void) +{ + return &eh_globals; +} +extern "C" __cxa_eh_globals *__cxa_get_globals_fast(void) +{ + return &eh_globals; +} +extern "C" void __cxa_call_unexpected(void *) +{ + // An unexpected exception was thrown from a function that lists its possible exceptions + _SysDebug("__cxa_call_unexpected - TODO"); + for(;;); +} + +extern "C" void *__cxa_allocate_exception(size_t thrown_size) +{ + DEBUG("__cxa_allocate_exception(%i)", thrown_size); + __cxa_exception *ret = static_cast<__cxa_exception*>( malloc( sizeof(__cxa_exception) + thrown_size ) ); + if( !ret ) { + if( thrown_size <= sizeof(emergency_exception.buf) && TEST_AND_SET(emergency_exception_used) ) + { + ret = &emergency_exception.info; + } + } + if( !ret ) { + _SysDebug("__cxa_allocate_exception - No free space"); + ::std::terminate(); + } + DEBUG("__cxa_allocate_exception: return %p", ret+1); + return ret + 1; +} + +extern "C" void __cxa_free_exception(void *thrown_exception) +{ + DEBUG("__cxa_free_exception(%p)", thrown_exception); + if(thrown_exception == &emergency_exception.buf) { + //assert(emergency_exception_used); + emergency_exception_used = false; + } + else { + __cxa_exception *except = static_cast<__cxa_exception*>( thrown_exception ) - 1; + free(except); + } +} + +extern "C" void __cxa_throw(void *thrown_exception, std::type_info *tinfo, void (*dest)(void*)) +{ + #if DEBUG_ENABLED + DEBUG("__cxa_throw(%p,%p,%p) '%s' by %p", + thrown_exception, tinfo, dest, tinfo->name(), __builtin_return_address(0) + ); + { + const ::std::exception* e = reinterpret_cast<const ::std::exception*>(thrown_exception); + DEBUG("- e.what() = '%s'", e->what()); + } + #endif + + __cxa_exception *except = static_cast<__cxa_exception*>( thrown_exception ) - 1; + + except->unexpectedHandler = 0; + except->terminateHandler = 0; + except->exceptionType = tinfo; + except->exceptionDestructor = dest; + memcpy(&except->unwindHeader.exception_class, EXCEPTION_CLASS_ACESS, 8); + __cxa_get_globals()->uncaughtExceptions ++; + + int rv = _Unwind_RaiseException( &except->unwindHeader ); + + ::_SysDebug("__cxa_throw(%p,%s) :: UNCAUGHT %i", thrown_exception, tinfo->name(), rv); + ::std::terminate(); +} + +extern "C" void *__cxa_begin_catch(_Unwind_Exception *exceptionObject) +{ + __cxa_exception *except = reinterpret_cast<__cxa_exception*>( exceptionObject+1 )-1; + DEBUG("__cxa_begin_catch(%p) - except=%p", exceptionObject, except); + + except->handlerCount ++; + + except->nextException = __cxa_get_globals()->caughtExceptions; + __cxa_get_globals()->caughtExceptions = except; + + __cxa_get_globals_fast()->uncaughtExceptions --; + + return except+1; +} + +extern "C" void __cxa_end_catch() +{ + struct __cxa_exception *except = __cxa_get_globals()->caughtExceptions; + DEBUG("__cxa_end_catch - %p", except); + except->handlerCount --; + __cxa_get_globals()->caughtExceptions = except->nextException; + + if( except->handlerCount == 0 ) { + __cxa_free_exception(except+1); + } +} + + diff --git a/Usermode/Libraries/libc++.so_src/exception_handling_acxx.h b/Usermode/Libraries/libc++.so_src/exception_handling_acxx.h new file mode 100644 index 0000000000000000000000000000000000000000..536016effc5c526663e5ab6602d3b5627926e16b --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/exception_handling_acxx.h @@ -0,0 +1,59 @@ +/* + * Acess2 C++ Support Library + * - By John Hodge (thePowersGang) + * + * exception_handling_acxx.h + * - C++ Exception handling definions from HP's aC++ document + * + * Reference: http://mentorembedded.github.io/cxx-abi/exceptions.pdf + */ +#ifndef _EXCEPTION_HANLDING_ACXX_H_ +#define _EXCEPTION_HANLDING_ACXX_H_ + +/** + * \brief Language Specific Data Area + * \note Pointer obtained via _Unwind_GetLanguageSpecificData + */ +struct sLSDA_Header +{ + const void *Base; + uintptr_t LPStart; + uint8_t TTEncoding; + uintptr_t TypePtrBase; // base address for type pointers + uintptr_t TTBase; // Base address for type offsets + uint8_t CallSiteEncoding; + const void *CallSiteTable; + const void *ActionTable; +}; + +/* Pointer encodings, from dwarf2.h. */ +#define DW_EH_PE_absptr 0x00 +#define DW_EH_PE_omit 0xff + +// - Data format (mask with 0x0F) +#define DW_EH_PE_fmtmask 0x0F +#define DW_EH_PE_uleb128 0x01 +#define DW_EH_PE_udata2 0x02 +#define DW_EH_PE_udata4 0x03 +#define DW_EH_PE_udata8 0x04 +#define DW_EH_PE_sleb128 0x09 +#define DW_EH_PE_sdata2 0x0A +#define DW_EH_PE_sdata4 0x0B +#define DW_EH_PE_sdata8 0x0C +#define DW_EH_PE_signed 0x08 +// - Data maipulation (0x70) +#define DW_EH_PE_relmask 0x70 +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_textrel 0x20 +#define DW_EH_PE_datarel 0x30 +#define DW_EH_PE_funcrel 0x40 +#define DW_EH_PE_aligned 0x50 + +#define DW_EH_PE_indirect 0x80 + +typedef uint64_t leb128u_t; +typedef int64_t leb128s_t; + + +#endif + diff --git a/Usermode/Libraries/libc++.so_src/exception_handling_cxxabi.h b/Usermode/Libraries/libc++.so_src/exception_handling_cxxabi.h new file mode 100644 index 0000000000000000000000000000000000000000..69f373592f0e33b84ba74d62117c3c96f2f13753 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/exception_handling_cxxabi.h @@ -0,0 +1,88 @@ +/* + * Acess2 C++ Support Library + * - By John Hodge (thePowersGang) + * + * exception_handling_cxxabi.h + * - C++ Exception Handling definitions from the Itanium C++ ABI + */ +#ifndef _EXCEPTION_HANLDING_CXXABI_H_ +#define _EXCEPTION_HANLDING_CXXABI_H_ + +typedef void *(unexpected_handler)(void); +typedef void *(terminate_handler)(void); + +struct _Unwind_Context; + +typedef enum { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8 +} _Unwind_Reason_Code; + +typedef int _Unwind_Action; +static const _Unwind_Action _UA_SEARCH_PHASE = 1; +static const _Unwind_Action _UA_CLEANUP_PHASE = 2; +static const _Unwind_Action _UA_HANDLER_FRAME = 4; +static const _Unwind_Action _UA_FORCE_UNWIND = 8; + +typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code reason, struct _Unwind_Exception *exc); + +struct _Unwind_Exception +{ + uint64_t exception_class; + _Unwind_Exception_Cleanup_Fn exception_cleanup; + uint64_t private_1; + uint64_t private_2; +}; + +struct __cxa_exception +{ + std::type_info* exceptionType; + void (*exceptionDestructor)(void *); + unexpected_handler* unexpectedHandler; + terminate_handler* terminateHandler; + __cxa_exception* nextException; + + int handlerCount; + + int handlerSwitchValue; + const char* actionRecord; + const char* languageSpecificData; + void* catchTemp; + void* adjustedPtr; + + _Unwind_Exception unwindHeader; +}; + +#define EXCEPTION_CLASS_ACESS "Ac20C++\0" + +typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)(int version, _Unwind_Action actions, uint64_t exception_class, struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context, void *stop_parameter); + +// Exports +extern "C" void __cxa_call_unexpected(void *); +extern "C" void *__cxa_allocate_exception(size_t thrown_size); +extern "C" void __cxa_free_exception(void *thrown_exception); +extern "C" void __cxa_throw(void *thrown_exception, std::type_info *tinfo, void (*dest)(void*)); +extern "C" void *__cxa_begin_catch(_Unwind_Exception *exceptionObject); +extern "C" void __cxa_end_catch(); + +// Imports +extern "C" _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *exception_object); +extern "C" _Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object, _Unwind_Stop_Fn stop, void *stop_parameter); +extern "C" void _Unwind_DeleteException(struct _Unwind_Exception *exception_object); +extern "C" uint64_t _Unwind_GetGR(struct _Unwind_Context *context, int index); +extern "C" void _Unwind_SetGR(struct _Unwind_Context *context, int index, uint64_t new_value); +extern "C" uint64_t _Unwind_GetIP(struct _Unwind_Context *context); +extern "C" void _Unwind_SetIP(struct _Unwind_Context *context, uint64_t new_value); +extern "C" uint64_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context); +extern "C" uint64_t _Unwind_GetRegionStart(struct _Unwind_Context *context); + +#endif + + diff --git a/Usermode/Libraries/libc++.so_src/exceptions.cc b/Usermode/Libraries/libc++.so_src/exceptions.cc new file mode 100644 index 0000000000000000000000000000000000000000..cc7c8c27558fb6a9b6acf3deceba3e0b175ea1a5 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/exceptions.cc @@ -0,0 +1,79 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * exceptions.cc + * - exception and friends + */ +#include <string> +#include <exception> +#include <stdexcept> +#include <acess/sys.h> + +// === CODE === +namespace std { + +exception::exception() throw() +{ +} +exception::exception(const exception&) throw() +{ +} +exception& exception::operator=(const exception&) throw() +{ + return *this; +} +exception::~exception() throw() +{ +} +const char* exception::what() const throw() +{ + return "generic exception"; +} + +void terminate() +{ + _SysDebug("terminate()"); + _exit(0); +} + +_bits::str_except::str_except(const string& what_arg): + m_str(what_arg) +{ +} +_bits::str_except::~str_except() noexcept +{ +} +_bits::str_except& _bits::str_except::operator=(const str_except& e) noexcept +{ + m_str = e.m_str; + return *this; +} +const char* _bits::str_except::what() const throw() +{ + return m_str.c_str(); +} + +// --- Standar Exceptions --- +logic_error::logic_error(const string& what_str): + _bits::str_except(what_str) +{ +} + +out_of_range::out_of_range(const string& what_str): + logic_error(what_str) +{ +} + +length_error::length_error(const string& what_str): + logic_error(what_str) +{ +} + +runtime_error::runtime_error(const string& what_str): + _bits::str_except(what_str) +{ +} + +} // namespace std + diff --git a/Usermode/Libraries/libc++.so_src/guard.cc b/Usermode/Libraries/libc++.so_src/guard.cc index a075a7b610830dc087f49ad5643f534562e3ad4f..6468a676300fdcae4736960f4047cff55e1f1b81 100644 --- a/Usermode/Libraries/libc++.so_src/guard.cc +++ b/Usermode/Libraries/libc++.so_src/guard.cc @@ -6,24 +6,33 @@ * - One-time construction API */ #include <stdint.h> +#include <acess/sys.h> +#include <cstdlib> + +#define FLAG_INIT_COMPLETE (1<<0) +#define FLAG_INIT_LOCKED (1<<1) extern "C" int __cxa_guard_acquire ( int64_t *guard_object ) { // TODO: Mutex! - if( *guard_object ) - return 1; - *guard_object = 1; - return 0; + if( *guard_object == FLAG_INIT_COMPLETE ) + return 0; + if( *guard_object == FLAG_INIT_LOCKED ) { + _SysDebug("ERROR: __cxa_guard_acquire - nested"); + } + *guard_object = FLAG_INIT_LOCKED; + return 1; } extern "C" void __cxa_guard_release ( int64_t *guard_object ) { - *guard_object = 0; + *guard_object = FLAG_INIT_COMPLETE; } extern "C" void __cxa_guard_abort ( int64_t *guard_object ) { - *guard_object = 0; - // TODO: abort + *guard_object = FLAG_INIT_COMPLETE; + _SysDebug("__cxa_guard_abort"); + abort(); } diff --git a/Usermode/Libraries/libc++.so_src/gxx_personality.cc b/Usermode/Libraries/libc++.so_src/gxx_personality.cc new file mode 100644 index 0000000000000000000000000000000000000000..fbd1623417db6e03d193a7174659bc8add90a415 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/gxx_personality.cc @@ -0,0 +1,461 @@ +/* + * Acess2 C++ Support Library + * - By John Hodge (thePowersGang) + * + * gxx_personality.cc + * - Implementation of GNU C++ Exception handling "Personality" + */ +#include <typeinfo> +#include <cstdint> // [u]intN_t +#include <cstdlib> // abort +#include <cstring> // memcmp +#include "exception_handling_acxx.h" +#include "exception_handling_cxxabi.h" +#include <acess/sys.h> +#include <cassert> +#include <cxxabi.h> // __dynamic_cast + +#define DEBUG_ENABLED 1 + +#if DEBUG_ENABLED +# define DEBUG(v...) ::_SysDebug(v) +#else +# define DEBUG(v...) do{}while(0) +#endif + +// === PROTOTYPES === +extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass, + struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context); +static int get_frame_action(const sLSDA_Header &header, _Unwind_Context *context, const std::type_info *throw_type, + uint64_t &landingpad, int64_t &switch_value); +static bool exception_matches_single(const std::type_info *throw_type, const struct sLSDA_Header &header, int type_index); +static bool exception_matches_list(const std::type_info *throw_type, const struct sLSDA_Header &header, int list_index); +static void read_lsda_header(const void *&ptr, _Unwind_Context *context, struct sLSDA_Header *header); +static size_t _get_encoded_size(int encoding); +static uint64_t _get_base(uint8_t encoding, _Unwind_Context *context); +static uint64_t _read_encoded(const void *&ptr, _Unwind_Context *context, int encoding, uint64_t base); +static uint64_t _read_encoded(const void *&ptr, _Unwind_Context *context, int encoding); +template <typename T> static T read(const void *&ptr); +static uint64_t _read_leb128u(const void *&ptr); +static int64_t _read_leb128s(const void *&ptr); + +// === CODE === +extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass, + struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context) +{ + //::_SysDebug("__gxx_personality_v0(%i, 0x%x, 0x%llx, ...)", version, actions, exceptionClass); + //::_SysDebug("__gxx_personality_v0(..., %p, %p)", exceptionObject, context); + + //if( exceptionObject ) { + // ::_SysDebug("exception_object: Class 0x%llx", exceptionObject->exception_class); + //} + //if( context ) + //{ + // ::_SysDebug("context: IP 0x%llx", _Unwind_GetIP(context)); + // ::_SysDebug("context: RegionStart 0x%llx", _Unwind_GetRegionStart(context)); + // ::_SysDebug("context: LangSpecData 0x%llx", _Unwind_GetLanguageSpecificData(context)); + //} + + if( version != 1 ) { + ::_SysDebug("%s: Unexpected version %i != exp 1", __func__, version); + return _URC_FATAL_PHASE1_ERROR; + } + + const void *lsda_ptr = (const void*)_Unwind_GetLanguageSpecificData(context); + struct sLSDA_Header header; + read_lsda_header(lsda_ptr, context, &header); + + const void *exception_object = exceptionObject + 1; + const __cxa_exception *exception_info = static_cast<const __cxa_exception*>(exception_object) - 1; + std::type_info *throw_type = ( + memcmp(&exceptionClass,EXCEPTION_CLASS_ACESS,8) == 0 ? exception_info->exceptionType : NULL + ); + + uint64_t landingpad = 0; + int64_t switch_value = 0; + int frame_action = get_frame_action(header, context, throw_type, landingpad, switch_value); + + if( (actions & _UA_SEARCH_PHASE) && (actions & _UA_CLEANUP_PHASE) ) + { + _SysDebug("__gxx_personality_v0: ERROR Both _UA_SEARCH_PHASE and _UA_CLEANUP_PHASE set"); + abort(); + } + + // Search + if( actions & _UA_SEARCH_PHASE ) + { + // If a handler was found + if( frame_action == 2 ) { + // - return _URC_HANDLER_FOUND + DEBUG("SEARCH: 0x%llx Handler %p(%i)", + _Unwind_GetIP(context), landingpad, switch_value); + return _URC_HANDLER_FOUND; + } + // - If no handler (either nothing, or cleanups), return _URC_CONTINUE_UNWIND + DEBUG("SEARCH: 0x%llx no handler %p(%i)", + _Unwind_GetIP(context), landingpad, switch_value); + return _URC_CONTINUE_UNWIND; + } + + // Cleanup + if( actions & _UA_CLEANUP_PHASE ) + { + // No action, continue + if( frame_action == 0 ) { + return _URC_CONTINUE_UNWIND; + } + assert(landingpad); + + if( actions & _UA_FORCE_UNWIND ) + { + // Unwind forced, override switch_value to 0 + // - Disables any attempt to handle exception + switch_value = 0; + } + + DEBUG("Install context IP=0x%x, R%i=%p/R%i=%i", + (uintptr_t)landingpad, + __builtin_eh_return_data_regno(0), exceptionObject, + __builtin_eh_return_data_regno(1), switch_value + ); + _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)exceptionObject); + _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), switch_value); + _Unwind_SetIP(context, landingpad); + return _URC_INSTALL_CONTEXT; + } + + _SysDebug("__gxx_personality_v0: Neither _UA_SEARCH_PHASE or _UA_CLEANUP_PHASE set"); + return _URC_FATAL_PHASE1_ERROR; +} + +int get_frame_action(const sLSDA_Header &header, _Unwind_Context *context, const std::type_info* throw_type, + uint64_t &landingpad, int64_t &switch_value) +{ + uint64_t ip = _Unwind_GetIP(context) - _Unwind_GetRegionStart(context); + DEBUG("get_frame_action: IP = 0x%llx + 0x%llx", _Unwind_GetRegionStart(context), ip); + // Check if there is a handler for this exception in this frame + // - Search call site table for this return address (corresponds to a try block) + uintptr_t cs_ldgpad; + uint64_t cs_action; + const void *lsda_ptr = header.CallSiteTable; + while( lsda_ptr < header.ActionTable ) + { + uintptr_t cs_start = _read_encoded(lsda_ptr, context, header.CallSiteEncoding); + uintptr_t cs_len = _read_encoded(lsda_ptr, context, header.CallSiteEncoding); + cs_ldgpad = _read_encoded(lsda_ptr, context, header.CallSiteEncoding); + cs_action = _read_leb128u(lsda_ptr); + + // If IP falls below this entry, it's not on the list + if( ip <= cs_start ) { + lsda_ptr = header.ActionTable; + break ; + } + if( ip > cs_start + cs_len ) + continue; + + break; + } + if( lsda_ptr > header.ActionTable ) { + _SysDebug("__gxx_personality_v0: Malformed Call Site Table, reading overran the end (%p>%p)", + lsda_ptr, header.ActionTable); + } + if( lsda_ptr >= header.ActionTable ) { + // No match! + DEBUG("__gxx_personality_v0: No entry for IP 0x%x", ip); + return 0; + } + + // Found it + if( cs_ldgpad == 0 ) { + DEBUG("No landingpad, hence no action"); + if( cs_action != 0 ) { + _SysDebug("%s: NOTICE cs_ldgpad==0 but cs_action(0x%llx)!=0", + __func__, cs_action); + } + return 0; + } + else if( cs_action == 0 ) { + DEBUG("No action, cleanups only"); + switch_value = 0; + landingpad = header.LPStart + cs_ldgpad; + return 1; // 1 = cleanup only + } + else { + switch_value = 0; + landingpad = header.LPStart + cs_ldgpad; + // catch() handler + bool has_cleanups = false; // set to true to override return value + const void *action_list = (const char*)header.ActionTable + (cs_action-1); + for(;;) // broken by 0 length entry + { + leb128s_t filter = _read_leb128s(action_list); + leb128s_t disp = _read_leb128s(action_list); + if( filter == 0 ) + { + // Cleanup + has_cleanups = true; + } + else if( filter < 0 ) + { + // Exception specifcation + if( !exception_matches_list(throw_type, header, -filter) ) + { + switch_value = filter; + return 2; + } + } + else + { + // Catch + if( exception_matches_single(throw_type, header, filter) ) + { + switch_value = filter; + return 2; + } + } + + if( disp == 0 ) + break; + action_list = (const char*)action_list + disp-1; + } + + // If a cleanup request was seen, tell the caller that we want to handle it + if( has_cleanups ) { + return 1; // 1 = cleanup only + } + // Else, there's nothing here to handle + return 0; + } +} + +const ::std::type_info *get_type_info(const struct sLSDA_Header &header, int type_index) +{ + size_t encoded_size = _get_encoded_size(header.TTEncoding); + assert(encoded_size > 0); + const void *ptr = (const void*)(header.TTBase - encoded_size * type_index); + assert( header.TTBase ); + assert( ptr > header.ActionTable ); + + uintptr_t type_ptr = _read_encoded(ptr, NULL, header.TTEncoding, header.TypePtrBase); + return reinterpret_cast< ::std::type_info* >(type_ptr); +} + +const ::std::type_info *get_exception_type(const void *exception_object) +{ + if( !exception_object ) + return NULL; + const struct _Unwind_Exception *u_execept = (const struct _Unwind_Exception*)exception_object; + const struct __cxa_exception *except = (const struct __cxa_exception*)(u_execept + 1) - 1; + if( memcmp(&except->unwindHeader.exception_class, EXCEPTION_CLASS_ACESS, 8) != 0 ) + return NULL; + + return except->exceptionType; +} + +bool exception_matches_single(const std::type_info *throw_type, const struct sLSDA_Header &header, int type_index) +{ + const ::std::type_info *catch_type = get_type_info(header, type_index); + DEBUG("catch_type = %p", catch_type); + + if( !catch_type ) + { + DEBUG("catch(...)"); + return true; + } + else if( !throw_type ) + { + DEBUG("threw UNK"); + return false; + } + else + { + DEBUG("catch(%s), throw %s", catch_type->name(), throw_type->name()); + size_t ofs = 0; + if( !catch_type->__is_child(*throw_type, ofs) ) { + _SysDebug("> No match"); + return false; + } + + return true; + } +} +bool exception_matches_list(const std::type_info *throw_type, const struct sLSDA_Header &header, int list_index) +{ + _SysDebug("TODO: exception_matches_list %i", list_index); + abort(); + (void)throw_type; + (void)header; + return true; +} + +template <typename T> T read(const void *&ptr) +{ + T rv = *reinterpret_cast<const T*>(ptr); + ptr = (const char*)ptr + sizeof(T); + return rv; +} + +static void read_lsda_header(const void *&ptr, _Unwind_Context *context, struct sLSDA_Header *header) +{ + header->Base = ptr; + + uint8_t start_encoding = read<uint8_t>(ptr); + if( start_encoding == DW_EH_PE_omit ) + header->LPStart = _Unwind_GetRegionStart(context); + else + header->LPStart = _read_encoded(ptr, context, start_encoding); + + header->TTEncoding = read<uint8_t>(ptr); + if( header->TTEncoding == DW_EH_PE_omit ) + header->TTBase = 0; + else { + ptrdiff_t tt_ofs = _read_leb128u(ptr); + header->TTBase = (uintptr_t)ptr + tt_ofs; + } + header->TypePtrBase = _get_base(header->TTEncoding, context); + + header->CallSiteEncoding = read<uint8_t>(ptr); + uint64_t call_site_size = _read_leb128u(ptr); + header->CallSiteTable = ptr; + header->ActionTable = (const void*)( (uintptr_t)ptr + call_site_size ); + + #if 0 + ::_SysDebug("LSDA header:"); + ::_SysDebug("->LPStart = 0x%lx", header->LPStart); + ::_SysDebug("->TTEncoding = 0x%02x", header->TTEncoding); + ::_SysDebug("->TTBase = 0x%lx", header->TTBase); + ::_SysDebug("->CallSiteEncoding = 0x%02x", header->CallSiteEncoding); + ::_SysDebug("->CallSiteTable = %p", header->CallSiteTable); + ::_SysDebug("->ActionTable = %p", header->ActionTable); + #endif +} + +static size_t _get_encoded_size(int encoding) +{ + switch(encoding & DW_EH_PE_fmtmask) + { + case DW_EH_PE_absptr: // absolute + return sizeof(void*); + case DW_EH_PE_udata4: + return 4; + default: + _SysDebug("_get_encoded_size: Unknown encoding 0x%02x", encoding); + return 0; + } +} + +/* + * \brief Read a DWARF encoded pointer from the stream + */ +static uint64_t _read_encoded(const void *&ptr, _Unwind_Context *context, int encoding, uint64_t base) +{ + (void)context; + if( encoding == DW_EH_PE_aligned ) { + void **aligned = (void**)( ((uintptr_t)ptr + sizeof(void*) - 1) & -(sizeof(void*)-1) ); + ptr = (void*)( (uintptr_t)aligned + sizeof(void*) ); + return (uintptr_t)*aligned; + } + uint64_t rv; + uintptr_t orig_ptr = (uintptr_t)ptr; + switch(encoding & DW_EH_PE_fmtmask) + { + case DW_EH_PE_absptr: // absolute + rv = (uintptr_t)read<void*>(ptr); + break; + case DW_EH_PE_uleb128: + rv = _read_leb128u(ptr); + break; + case DW_EH_PE_sleb128: + rv = _read_leb128s(ptr); + break; + case DW_EH_PE_udata2: + rv = read<uint16_t>(ptr); + break; + case DW_EH_PE_udata4: + rv = read<uint32_t>(ptr); + break; + case DW_EH_PE_udata8: + rv = read<uint64_t>(ptr); + break; + default: + ::_SysDebug("_read_encoded: Unknown encoding format 0x%x", encoding & DW_EH_PE_fmtmask); + ::abort(); + } + if( rv != 0 ) + { + if( (encoding & DW_EH_PE_relmask) == DW_EH_PE_pcrel ) { + rv += orig_ptr; + } + else { + rv += base; + } + + if( encoding & DW_EH_PE_indirect ) { + rv = (uintptr_t)*(void**)(uintptr_t)rv; + } + else { + // nothing + } + } + return rv; +} +static uint64_t _get_base(uint8_t encoding, _Unwind_Context *context) +{ + if( encoding == 0xFF ) + return 0; + switch(encoding & DW_EH_PE_relmask) + { + case DW_EH_PE_absptr: + case DW_EH_PE_pcrel: + case DW_EH_PE_aligned: + return 0; + //case DW_EH_PE_textrel: + //return _Unwind_GetTextRelBase(context); + //case DW_EH_PE_datarel: + //return _Unwind_GetDataRelBase(context); + case DW_EH_PE_funcrel: + return _Unwind_GetRegionStart(context); + default: + ::_SysDebug("_get_base: Unknown encoding relativity 0x%x", (encoding & DW_EH_PE_relmask)); + ::abort(); + for(;;); + } +} +static uint64_t _read_encoded(const void *&ptr, _Unwind_Context *context, int encoding) +{ + return _read_encoded(ptr, context, encoding, _get_base(encoding, context)); +} + +static uint64_t _read_leb128_raw(const void *&ptr, int *sizep) +{ + int size = 0; + uint64_t val = 0; + const uint8_t *ptr8 = static_cast<const uint8_t*>(ptr); + do + { + val |= (*ptr8 & 0x7F) << (size*7); + size ++; + } while( *ptr8++ & 0x80 ); + + ptr = ptr8; + *sizep = size; + + return val; +} + +static uint64_t _read_leb128u(const void *&ptr) +{ + int unused_size; + return _read_leb128_raw(ptr, &unused_size); +} +static int64_t _read_leb128s(const void *&ptr) +{ + int size; + uint64_t val = _read_leb128_raw(ptr, &size); + if( size*7 <= 64 && (val & (1 << (size*7-1))) ) + { + val |= 0xFFFFFFFFFFFFFFFF << (size*7); + } + return val; +} + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/_libcxx_helpers.h b/Usermode/Libraries/libc++.so_src/include_exp/_libcxx_helpers.h new file mode 100644 index 0000000000000000000000000000000000000000..bd3b805c0f426dbdbf3a7232c3c4172f37478cd4 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/_libcxx_helpers.h @@ -0,0 +1,31 @@ + +#ifndef _LIBCXX__LIBCXX_HELEPRS_H_ +#define _LIBCXX__LIBCXX_HELEPRS_H_ + +#if __cplusplus > 199711L // C++11 check +# define _CXX11_AVAIL 1 +#else +# define _CXX11_AVAIL 0 +#endif + +#define _libcxx_assert(cnd) do { \ + if(!(cnd)) {\ + ::_sys::debug("libc++ assert failure %s:%i - %s", __FILE__, __LINE__, #cnd);\ + ::_sys::abort(); \ + } \ +} while(0) + +namespace _sys { +extern void abort() __asm__ ("abort") __attribute__((noreturn)); +extern void debug(const char *, ...); +extern void hexdump(const char *, const void *, unsigned int); +}; + +#if _CXX11_AVAIL +#define _CXX11_MOVE(val) ::std::move(val) +#else +#define _CXX11_MOVE(val) val +#endif + +#endif + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/algorithm b/Usermode/Libraries/libc++.so_src/include_exp/algorithm new file mode 100644 index 0000000000000000000000000000000000000000..c08e28f3e538980fc2f0533b99be0aaff6783fa8 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/algorithm @@ -0,0 +1,79 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * algorithm (header) + * - C++'s generic algorithms + */ +#ifndef _LIBCXX_ALGORITHM_ +#define _LIBCXX_ALGORITHM_ + +#include <utility> + +#include "_libcxx_helpers.h" + +namespace std { + +// --- Non-modifiying sequence operations --- +#if _CXX11_AVAIL +// TODO: all_of +// TODO: any_of +// TODO: none_of +#endif +template <class InputIterator, class Function> +Function for_each(InputIterator first, InputIterator last, Function fn) +{ + while( first != last ) + { + fn( *first ); + ++ first; + } + return _CXX11_MOVE(fn); +} + +template <class InputIterator, class T> +InputIterator find(InputIterator first, InputIterator last, const T& val) +{ + while( first != last ) + { + if( *first == val ) + return first; + ++ first; + } + return last; +} +// TODO: find_if +// TODO: find_if_not (C++11) +// TODO: find_end +// TODO: find_first_of + +// Maximum +template <class T> +const T& max(const T& a, const T& b) +{ + return (a<b) ? b : a; +} + +template <class T, class Compare> +const T& max(const T& a, const T& b, Compare comp) +{ + return comp(a, b) ? b : a; +} + +template <class T> +const T& min(const T& a, const T& b) +{ + return (a<b) ? a : b; +} + +template <class T, class Compare> +const T& min(const T& a, const T& b, Compare comp) +{ + return comp(a, b) ? a : b; +} + +}; // namespace std + +#endif + +// vim: ft=cpp diff --git a/Usermode/Libraries/libc++.so_src/include_exp/allocator b/Usermode/Libraries/libc++.so_src/include_exp/allocator new file mode 100644 index 0000000000000000000000000000000000000000..1608a3c72ed36f273230782e84a58104be4c1a3b --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/allocator @@ -0,0 +1,121 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * string (header) + * - C++'s String type + */ +#ifndef _LIBCXX_ALLOCATOR_ +#define _LIBCXX_ALLOCATOR_ + +#include "_libcxx_helpers.h" + +#include "new" +#include "cstddef" +#include "utility" + +namespace std { + +template <class T> class allocator; + +namespace _bits { + +template <class T> +class allocator_real +{ +public: + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef const T* const_pointer; + typedef const T& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + template <class Type> + struct rebind + { + typedef allocator<Type> other; + }; + + allocator_real() throw() { + } + allocator_real(const allocator_real& alloc __attribute__((unused))) throw() { + } + template <class U> + allocator_real(const allocator_real<U>& alloc) throw() { + } + ~allocator_real() throw() { + } + + pointer address(reference x) const { + return &x; + } + const_pointer address(const_reference x) const { + return &x; + } + pointer allocate(size_type n, const void* hint=0) { + hint = hint; + return static_cast<pointer>( ::operator new (n * sizeof(value_type)) ); + } + void deallocate(pointer p, size_type n) { + n=n; + ::operator delete(p); + } + size_type max_size() { + return ((size_type)-1) / sizeof(value_type); + } + void construct( pointer p, const_reference val ) { + new ((void*)p) value_type (val); + } + // C++11 + #if _CXX11_AVAIL + template<class U, class... Args> + void construct( U* p, Args&&... args ) { + ::new ((void*)p) U (::std::forward<Args>(args)...); + } + #endif + void destroy(pointer p) { + p->~value_type(); + } +}; + +template <class T> +class allocator_noconstruct: + public ::std::_bits::allocator_real<T> +{ +public: + void construct( typename allocator_real<T>::pointer p, typename allocator_real<T>::const_reference val ) { + *p = val; + } + void destroy(typename allocator_real<T>::pointer p) { + } +}; + +}; + +template <class T> +class allocator: + public _bits::allocator_real<T> +{ +}; + +#if 1 +template <> +class allocator<unsigned char>: + public _bits::allocator_noconstruct<unsigned char> +{ +}; +template <> +class allocator<unsigned long>: + public _bits::allocator_noconstruct<unsigned long> +{ +}; +#endif + +}; + +#endif + +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/cassert b/Usermode/Libraries/libc++.so_src/include_exp/cassert new file mode 100644 index 0000000000000000000000000000000000000000..d11b7462abe8ed920edb1f87e44eb7c607cd94a6 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/cassert @@ -0,0 +1,3 @@ +extern "C" { +#include <assert.h> +} diff --git a/Usermode/Libraries/libc++.so_src/include_exp/cerrno b/Usermode/Libraries/libc++.so_src/include_exp/cerrno new file mode 100644 index 0000000000000000000000000000000000000000..3ebd48a3f458bcb0120fd47b6154fc9c94006e8e --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/cerrno @@ -0,0 +1,6 @@ +/* + */ +extern "C" { +#include <errno.h> +} +// vim: ft=cpp diff --git a/Usermode/Libraries/libc++.so_src/include_exp/cstddef b/Usermode/Libraries/libc++.so_src/include_exp/cstddef new file mode 100644 index 0000000000000000000000000000000000000000..b7b0c1363d24fc502f7477ec3ba42120b80723a3 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/cstddef @@ -0,0 +1,15 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * cstddef (header) + * - C++ wrapper around stddef.h + */ +#ifndef _LIBCXX_CSTDDEF_ +#define _LIBCXX_CSTDDEF_ + +extern "C" { +#include <stddef.h> +}; + +#endif diff --git a/Usermode/Libraries/libc++.so_src/include_exp/cstdint b/Usermode/Libraries/libc++.so_src/include_exp/cstdint new file mode 100644 index 0000000000000000000000000000000000000000..c5575d9f232c0167eff709360db17ac4f38fab83 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/cstdint @@ -0,0 +1,16 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * cstdint (header) + * - C++ wrapper around stdint.h + */ +#ifndef _LIBCXX_CSTDINT_ +#define _LIBCXX_CSTDINT_ + +extern "C" { +#include <stdint.h> +}; + +#endif + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/cstdio b/Usermode/Libraries/libc++.so_src/include_exp/cstdio new file mode 100644 index 0000000000000000000000000000000000000000..f41fd058a1415cd66018f243744ae53bc798f8e9 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/cstdio @@ -0,0 +1,6 @@ +/* + */ +extern "C" { +#include <stdio.h> +} +// vim: ft=cpp diff --git a/Usermode/Libraries/libc++.so_src/include_exp/cstdlib b/Usermode/Libraries/libc++.so_src/include_exp/cstdlib new file mode 100644 index 0000000000000000000000000000000000000000..7d119a76a924d065ea65f0a4c166fb8eaf0cde0d --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/cstdlib @@ -0,0 +1,17 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * cstdlib (header) + * - C++ wrapper around stdlib.h + */ +#ifndef _LIBCXX_CSTDLIB_ +#define _LIBCXX_CSTDLIB_ + +extern "C" { +#include <stdlib.h> +}; + +#endif + + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/cstring b/Usermode/Libraries/libc++.so_src/include_exp/cstring new file mode 100644 index 0000000000000000000000000000000000000000..66149e035c98f672aba2a10f3f22f102ae62e266 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/cstring @@ -0,0 +1,17 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * cstring (header) + * - C++ wrapper around string.h + */ +#ifndef _LIBCXX_CSTRING_ +#define _LIBCXX_CSTRING_ + +extern "C" { +#include <string.h> +}; + +#endif + + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/cxxabi.h b/Usermode/Libraries/libc++.so_src/include_exp/cxxabi.h index a8e1f5ca1c7fffef70a28c9bfe9d17307663d1c0..2fbe897942d0a32e1ee6bd2d351f4cbb90581826 100644 --- a/Usermode/Libraries/libc++.so_src/include_exp/cxxabi.h +++ b/Usermode/Libraries/libc++.so_src/include_exp/cxxabi.h @@ -8,6 +8,8 @@ #ifndef _LIBCXX__CXXABI_H_ #define _LIBCXX__CXXABI_H_ +#include <cstddef> + #include <typeinfo> namespace __cxxabiv1 { @@ -71,6 +73,13 @@ public: }; }; +extern "C" void* __dynamic_cast( + const void *sub, + const __class_type_info *src, + const __class_type_info *dst, + ptrdiff_t src2dst_offset + ); + }; // namespace __cxxabiv1 #endif diff --git a/Usermode/Libraries/libc++.so_src/include_exp/exception b/Usermode/Libraries/libc++.so_src/include_exp/exception new file mode 100644 index 0000000000000000000000000000000000000000..9e1469d0c88f2675db39ff67fafe1a1389246149 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/exception @@ -0,0 +1,46 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * exception (header) + * - C++'s base exception type + */ +#ifndef _LIBCXX_EXCEPTION_ +#define _LIBCXX_EXCEPTION_ + +#define noexcept throw() + +namespace std { + +class exception +{ +public: + exception() noexcept; + exception(const exception& e) noexcept; + exception& operator= (const exception& e) noexcept; + virtual ~exception() noexcept; + virtual const char* what() const noexcept; +}; + +class bad_exception: + public exception +{ +public: + bad_exception() noexcept; + const char* what() const noexcept; +}; + +typedef void (*terminate_handler)(); +typedef void (*unexpected_handler)(); + +extern void set_terminate(terminate_handler f) throw(); +extern void set_unexpected(unexpected_handler f) throw(); +extern void terminate(); +extern void unexpected(); +extern bool uncaught_exception() throw(); + +}; // namespace std + +#endif +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/functional b/Usermode/Libraries/libc++.so_src/include_exp/functional new file mode 100644 index 0000000000000000000000000000000000000000..1ac05dec00daa6108f2973fc01f3375e1bc9dce2 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/functional @@ -0,0 +1,31 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * functional (header) + * - Funcional programming features + */ +#ifndef _LIBCXX_FUNCTIONAL_ +#define _LIBCXX_FUNCTIONAL_ + +#include "_libcxx_helpers.h" + +namespace std { + +template <class T> +struct less +{ + bool operator() (const T& x, const T& y) const { + return x < y; + } + typedef T first_argument_type; + typedef T second_argument_type; + typedef bool result_type; +}; + +}; // namespace std + +#endif + +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/initializer_list b/Usermode/Libraries/libc++.so_src/include_exp/initializer_list new file mode 100644 index 0000000000000000000000000000000000000000..565980fcb8a8a463f24c21150e5ae915312f55c8 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/initializer_list @@ -0,0 +1,55 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * vector (header) + * - C++'s vector (dynamic array) type + */ +#ifndef _LIBCXX__INITIALIZER_LIST_ +#define _LIBCXX__INITIALIZER_LIST_ + +namespace std { + +template <class T> +class initializer_list +{ +public: + typedef T value_type; + typedef const T& reference; + typedef const T& const_reference; + typedef size_t size_type; + typedef const T* iterator; + typedef const T* const_iterator; +private: + // ORDER MATTERS : The first item must be a pointer to the array, the second must be the size + value_type* m_values; + size_type m_len; +public: + constexpr initializer_list() noexcept: + m_len(0) + { + } + + size_type size() const noexcept + { + return m_len; + } + + const T* begin() const noexcept + { + return &m_values[0]; + } + const T* end() const noexcept + { + return &m_values[m_len]; + } +}; + +}; + +template <class T> const T* begin(const ::std::initializer_list<T>& il) { return il.begin(); } +template <class T> const T* end (const ::std::initializer_list<T>& il) { return il.end(); } + +#endif +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/iterator b/Usermode/Libraries/libc++.so_src/include_exp/iterator new file mode 100644 index 0000000000000000000000000000000000000000..e58ab803d3b8660c375b22516a78fe7af351ecc7 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/iterator @@ -0,0 +1,35 @@ +/* + */ +#ifndef _LIBCXX_ITERATOR_ +#define _LIBCXX_ITERATOR_ + +namespace std { + +struct input_iterator_tag {}; +struct output_iterator_tag {}; +struct forward_iterator_tag {}; +struct bidirectional_iterator_tag {}; +struct random_access_iterator_tag {}; + +template <class Category, class T, class Distance = ptrdiff_t, class Pointer = T*, class Reference = T&> +class iterator +{ +public: + typedef T value_type; + typedef Distance difference_type; + typedef Pointer pointer_type; + typedef Reference reference; + typedef Category iterator_category; +}; + +template <class Iterator> class iterator_traits; +template <class T> class iterator_traits<T*>; +template <class T> class iterator_traits<const T*>; + + +}; // namespace std + +#endif + +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/list b/Usermode/Libraries/libc++.so_src/include_exp/list new file mode 100644 index 0000000000000000000000000000000000000000..3bc614e4656903f0b8f122f71d02ce38cfc9f6b5 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/list @@ -0,0 +1,331 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * list (header) + * - List container + */ +#ifndef _LIBCXX_LIST_ +#define _LIBCXX_LIST_ + +#include <cstddef> +#include "allocator" +#include "stdexcept" +#include "utility" + +namespace std { + +namespace _bits { +template <class ListType, class T> class list_iterator; +template <class T> class list_item; +} + +template <class T, class Alloc = allocator<T> > +class list +{ + typedef ::std::_bits::list_item<T> item_type; + typedef ::std::_bits::list_item<const T> const_item_type; + friend class ::std::_bits::list_iterator<list, T>; + + typedef typename Alloc::template rebind<item_type>::other item_allocator; +public: + typedef T value_type; + typedef Alloc allocator_type; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef _bits::list_iterator<list,T> iterator; + typedef _bits::list_iterator<list,const T> const_iterator; + typedef int difference_type; + typedef size_t size_type; + +private: + item_allocator m_item_allocator; + allocator_type m_allocator; + item_type *m_start; + item_type *m_end; + size_type m_item_count; + +public: + list(const allocator_type& alloc = allocator_type()): + m_item_allocator(), + m_allocator(alloc), + m_start(0), m_end(0) + { + } + list(size_t n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type()): + list() + { + assign(n, val); + } + list(const list& x); + ~list() { + clear(); + } + + list& operator =(const list& x); + + iterator begin() { + return iterator(*this, m_start); + } + const_iterator begin() const { + return const_iterator(*this, m_start); + } + + iterator end() { + return iterator(*this, 0); + } + const_iterator end() const { + return const_iterator(*this, 0); + } + + bool empty() const { + return !m_start; + } + size_t size() const { + return m_item_count; + } + size_t max_size() const { + return (size_type)-1 / sizeof(item_type); + } + + T& front() { + return m_start->value; + } + const T& front() const { + return m_start->value; + } + T& back() { + return m_end->value; + } + const T& back() const { + return m_end->value; + } + + void assign(size_type n, const value_type& val) { + clear(); + for( size_t i = 0; i < n; i ++ ) + { + push_back(val); + } + } + + void push_front(const value_type& val) { + insert(front(), val); + } + void pop_front() { + erase(front()); + } + void push_back(const value_type& val) { + insert(end(), val); + } + void pop_back() { + erase(end()); + } + + template <class... Args> + iterator emplace(iterator position, Args&&... args) { + item_type *newi = m_item_allocator.allocate(1); + m_allocator.construct(&newi->value, ::std::forward<Args>(args)...); + return insert_item(position, newi); + } + + iterator insert(iterator position, const value_type& val) { + item_type *newi = m_item_allocator.allocate(1); + m_allocator.construct(&newi->value, val); + return insert_item(position, newi); + } + void insert(iterator position, size_type n, const value_type& val) { + for( size_type i = 0; i < n; i ++ ) + { + position = insert(position, val); + } + } + iterator erase(iterator position) { + if( position == end() ) { + } + else { + item_type *oldi = position.m_cur; + ++ position; + + if(oldi->prev) + oldi->prev->next = oldi->next; + else + m_start = oldi->next; + if(oldi->next) + oldi->next->prev = oldi->prev; + else + m_end = oldi->prev; + + m_item_count --; + m_allocator.destroy(&oldi->value); + m_item_allocator.deallocate(oldi, 1); + } + return position; + } + + void clear() { + while( m_start ) { + item_type* item = m_start; + m_start = m_start->next; + delete item; + } + m_item_count = 0; + } + + void splice(iterator position, list& x) { + splice(position, x, x.begin(), x.end()); + } + void splice(iterator position, list& x, iterator i) { + splice(position, x, i, x.end()); + } + void splice(iterator position, list& x, iterator first, iterator last); + +private: + class _equal + { + const value_type& m_val; + public: + _equal(const value_type& val): + m_val(val) + { + }; + bool operator() (const value_type& v1) + { + return m_val == v1; + } + }; +public: + void remove(const value_type& val) { + remove_if(_equal(val)); + } + template <class Predicate> void remove_if(Predicate pred) { + for( iterator it = begin(); it != end(); ) + { + if( pred(*it) ) + it = erase(it); + else + ++ it; + } + } + + void unique(); + template <class BinaryPredicate> void unique(BinaryPredicate binary_pred); + + void merge(list& x); + template <class Compare> void merge(list& x, Compare comp); + + void sort(); + template <class Compare> void sort(Compare comp); + + void reverse() throw(); +private: + iterator insert_item(iterator position, item_type *newi) { + m_item_count ++; + if( m_start == 0 ) { + newi->next = 0; + newi->prev = m_end; + m_start = newi; + m_end = newi; + return end(); + } + if( position == end() ) { + newi->next = 0; + newi->prev = m_end; + //assert(m_end); + m_end->next = newi; + m_end = newi; + } + else if( position == begin() ) { + newi->next = m_start; + newi->prev = 0; + //assert(m_start); + m_start->prev = newi; + m_start = newi; + } + else { + newi->prev = position.m_cur->prev; + newi->next = position.m_cur; + position.m_cur->prev->next = newi; + position.m_cur->prev = newi; + } + return ++iterator(*this, newi); + } +}; + + +namespace _bits { + +template <class T> +struct list_item +{ + typedef T value_type; + list_item<T> *next; + list_item<T> *prev; + value_type value; +}; + +template <class ListType, class T> +class list_iterator//: + //public bidirectional_iterator_tag; +{ + const ListType* m_list; + list_item<T> *m_cur; + friend ListType; +public: + list_iterator(const list_iterator& x): + m_list(x.m_list), + m_cur (x.m_cur) + { + } + list_iterator& operator=(const list_iterator& x) { + m_list = x.m_list; + m_cur = x.m_cur; + } + + bool operator == (const list_iterator& other) const { + return m_cur == other.m_cur; + } + bool operator != (const list_iterator& other) const { + return !(*this == other); + } + + T& operator * () { + return m_cur->value; + } + T& operator -> () { + return m_cur->value; + } + list_iterator& operator ++ () { + if(!m_cur) + throw ::std::logic_error("list iterator ++ on end"); + m_cur = m_cur->next; + return *this; + } + list_iterator& operator -- () { + if( m_cur == m_list->m_start ) + throw ::std::logic_error("list iterator -- on start"); + if(!m_cur) + m_cur = m_list->m_end; + else + m_cur = m_cur->prev; + return *this; + } + +private: + list_iterator(const ListType& list, list_item<T> *item): + m_list(&list), + m_cur(item) + { + } +}; + +}; // namespace _bits + +}; // namespace std + +#endif + +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/map b/Usermode/Libraries/libc++.so_src/include_exp/map new file mode 100644 index 0000000000000000000000000000000000000000..2f9031b93fac5d540692b0019c5f77119143433b --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/map @@ -0,0 +1,418 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * map (header) + * - C++'s map type + */ +#ifndef _LIBCXX_MAP_ +#define _LIBCXX_MAP_ + +#include "_libcxx_helpers.h" +#include <allocator> +#include <stdexcept> +#include <iterator> +#include <utility> +#include <functional> // less + +namespace std { + +namespace _bits { + +template <class Val, class Map> +class map_iterator: + public ::std::iterator< ::std::bidirectional_iterator_tag, Val > +{ + friend Map; + typedef Val value_type; + Map *m_map; + size_t m_index; +public: + map_iterator(): + m_map(0), m_index(0) + { + } + map_iterator(Map *map, typename Map::size_type ofs): + m_map(map), m_index(ofs) + { + } + map_iterator(const map_iterator& x) { + *this = x; + } + map_iterator& operator=(const map_iterator& x) { + m_map = x.m_map; + m_index = x.m_index; + return *this; + } + + map_iterator& operator++() { + m_index ++; + } + map_iterator& operator--() { + m_index --; + } + + bool operator==(const map_iterator& x) const { + return m_index == x.m_index; + } + bool operator!=(const map_iterator& x) const { + return !(*this == x); + } + value_type& operator*() { + _libcxx_assert(m_index < m_map->m_size); + return m_map->m_items[m_index]; + } + value_type* operator->() { + _libcxx_assert(m_index < m_map->m_size); + return &m_map->m_items[m_index]; + } +}; + +} // namespace _bits + +template <class Key, class T, class Compare=less<Key>, class Alloc=allocator<pair<const Key,T> > > +class map +{ + typedef map this_type; +public: + typedef Key key_type; + typedef T mapped_type; + typedef pair<const Key, T> value_type; + typedef Compare key_compare; + typedef Alloc allocator_type; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef _bits::map_iterator<value_type,this_type> iterator; + typedef _bits::map_iterator<const value_type,this_type> const_iterator; + typedef size_t size_type; + +private: + friend class ::std::_bits::map_iterator<value_type, this_type>; + friend class ::std::_bits::map_iterator<const value_type, this_type>; + + key_compare m_comp; + allocator_type m_alloc; + value_type* m_items; // sorted array + size_type m_size; + size_type m_capacity; + +public: + map(const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type()): + m_comp(comp), + m_alloc(alloc), + m_items(0), m_size(0), m_capacity(0) + { + } + template <class InputInterator> + map(InputInterator first, InputInterator last): + map() + { + insert(first, last); + } + map(const map& x): + map(x.m_comp, x.m_alloc) + { + *this = x; + } + ~map() { + clear(); + reserve(0); + } + map& operator=(const map& x) { + clear(); + reserve(x.m_size); + for( size_type i = 0; i < x.m_size; i ++ ) { + emplace_hint( end(), x.m_items[i] ); + } + return *this; + } + + // Iterators + iterator begin() { + return iterator(this, 0); + } + const_iterator begin() const { + return const_iterator(this, 0); + } + iterator end() { + return iterator(this, m_size); + } + const_iterator end() const { + return const_iterator(this, m_size); + } + #if _CXX11_AVAIL + const_iterator cbegin() const { + return const_iterator(this, 0); + } + const_iterator cend() const { + return const_iterator(this, m_size); + } + #endif + //reverse_iterator rbegin(); + //const_reverse_iterator rbegin() const; + //const_reverse_iterator crbegin() const; + //reverse_iterator rend(); + //const reverse_iterator rend() const; + //const reverse_iterator crend() const; + + // Capacity + bool empty() const { + return m_size == 0; + } + size_type size() const { + return m_size; + } + size_type max_size() const { + return (size_type)-1 / sizeof(value_type); + } + + // Element access + mapped_type& operator[](const key_type& k) { + iterator it = upper_bound(k); + if( it == end() || m_comp(k, it->first) ) { // if k < it->first, no match + insert_at(it.m_index, value_type(k,mapped_type()) ); + } + return it->second; + } + #if _CXX11_AVAIL + mapped_type& at(const key_type& k) { + iterator it = lower_bound(k); + if( it == end() || m_comp(it->first, k) ) + throw ::std::out_of_range("::std:map::at"); + return it->second; + } + const mapped_type& at(const key_type& k) const { + iterator it = lower_bound(k); + if( it == end() || m_comp(it->first, k) ) + throw ::std::out_of_range("::std:map::at"); + return it->second; + } + #endif + + // Modifiers + // - insert + pair<iterator,bool> insert(const value_type& val) + { + const key_type& k = val.first; + iterator it = upper_bound(k); + if( it == end() || m_comp(k, it->first) ) { // if k < it->first, no match + insert_at(it.m_index, val); + return pair<iterator,bool>(it, true); + } + else { + return pair<iterator,bool>(it, false); + } + } + iterator insert(iterator position, const value_type& val); + template <class InputInterator> + void insert(InputInterator first, InputInterator last); + // - erase + void erase(iterator position) + { + auto pos = position; + erase(pos, ++position); + } + size_type erase(const key_type& k) + { + auto it = find(k); + if( it != end() ) { + erase(it); + return 1; + } + else { + return 0; + } + } + void erase(iterator first, iterator last) + { + _libcxx_assert(first.m_index <= last.m_index); + unsigned int ofs = first.m_index; + unsigned int count = last.m_index - first.m_index; + for( unsigned int i = 0; i < count; i ++ ) + { + // Construct new item + m_alloc.destroy(&m_items[ofs]); + m_size --; + // Move following items down + shift_items(&m_items[ofs+1], &m_items[ofs], m_size-ofs); + } + } + // - swap + void swap(map& x); + // - clear + void clear() { + for( size_type i = 0; i < m_size; i ++ ) { + m_alloc.destroy( &m_items[i] ); + } + m_size = 0; + } + // - emplace + #if _CXX11_AVAIL + template <class... Args> + pair<iterator,bool> emplace(Args&&... args) { + return emplace_hint(begin(), args...); + } + template <class... Args> + pair<iterator,bool> emplace_hint(iterator position, Args&&... args); + #endif + + // TODO: Observers + + // Operators + iterator find(const key_type& k) { + iterator it = lower_bound(k); + if( it == end() || m_comp(it->first, k) ) // if it->first < k + return end(); + return it; + } + const_iterator find(const key_type& k) const { + const_iterator it = lower_bound(k); + if( it == end() || m_comp(it->first, k) ) // if it->first < k + return end(); + return it; + } + size_type count(const key_type& k) { + if( find(k) == end() ) + return 0; + return 1; + } + iterator lower_bound(const key_type& k) { + size_type idx; + if( _search(k, idx) ) { + // found, return direct iterator + return iterator(this, idx); + } + else { + // not found, return iterator to before + if( idx == 0 ) return begin(); + return iterator(this, idx-1); + } + } + const_iterator lower_bound(const key_type& k) const { + size_type idx; + if( _search(k, idx) ) { + // found, return direct iterator + return iterator(this, idx); + } + else { + // not found, return iterator to before + if( idx == 0 ) return begin(); + return iterator(this, idx-1); + } + } + iterator upper_bound(const key_type& k) { + size_type idx; + _search(k, idx); + // idx == item or just after it + return iterator(this, idx); + } + const_iterator upper_bound(const key_type& k) const { + size_type idx; + _search(k, idx); + return const_iterator(this, idx); + } + pair<iterator,iterator> equal_range(const key_type& k); + pair<const_iterator,const_iterator> equal_range(const key_type& k) const; + +private: + // Change reservation to fit 'n' items + // - NOTE: Will also resize down + void reserve(size_type n) { + n = (n + 31) & ~31; + if( n > max_size() ) + throw ::std::length_error("::std::map::reserve"); + if( n != m_capacity ) + { + auto new_area = m_alloc.allocate(n); + for( size_type i = 0; i < m_size && i < n; i ++ ) + m_alloc.construct(&new_area[i], m_items[i]); + for( size_type i = n; i < m_size; i ++ ) + m_alloc.destroy( &m_items[i] ); + m_alloc.deallocate(m_items, m_capacity); + m_items = new_area; + m_capacity = n; + if(m_size > n) + m_size = n; + } + } + // Returns the index above or equal to 'k' + // - TODO: Reimplement as a binary search + bool _search(const key_type& k, size_type &pos_out) const { + #if 0 + size_type pos = m_size / 2; + size_type step = m_size / 4; + while( step > 0 ) { + const key_type& item_key = m_items[pos].first; + if( m_comp(item_key, k) ) + pos += step; + else if( m_comp(k, item_key) ) + pos -= step; + else { + pos_out = pos; + return true; + } + step /= 2; + } + pos_out = pos; + return false; + #else + //::_sys::debug("map::_search (m_size=%i)", m_size); + for( size_type pos = 0; pos < m_size; pos ++ ) + { + const key_type& item_key = m_items[pos].first; + if( m_comp(item_key, k) ) { + continue; + } + else if( m_comp(k, item_key) ) { + //::_sys::debug("map::_search - Passed %i", pos); + pos_out = pos; + return false; + } + else { + //::_sys::debug("map::_search - Found %i", pos); + pos_out = pos; + return true; + } + } + //::_sys::debug("map::_search - Off end %i", m_size); + pos_out = m_size; + return false; + #endif + } + void insert_at(size_type ofs, const value_type& val) { + //_libcxx_assert( ofs == 0 || m_comp(m_items[ofs-1].first, val.first) ); + //_libcxx_assert( ofs == m_size || m_comp(m_items[ofs].first, val.first) ); + // Resize up + reserve( m_size + 1 ); + // Move following items up + shift_items(&m_items[ofs], &m_items[ofs+1], m_size-ofs); + // Construct new item + m_alloc.construct(&m_items[ofs], val); + m_size ++; + } + void shift_items(value_type *start, value_type *end, size_type count) { + if( start < end ) { + for( size_type i = count; i --; ) { + #if _CXX11_AVAIL && 0 + m_alloc.construct(&end[i], ::std::move(start[i])); + #else + m_alloc.construct(&end[i], start[i]); + m_alloc.destroy(&start[i]); + #endif + } + } + else { + for( size_type i = 0; i < count; i ++ ) { + } + } + } +}; + +} // namespace std + +#endif + +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/memory b/Usermode/Libraries/libc++.so_src/include_exp/memory new file mode 100644 index 0000000000000000000000000000000000000000..b604fbe89e67ed74ab3f07c812e3251e64de0ceb --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/memory @@ -0,0 +1,20 @@ + +#ifndef _LIBCXX_MEMORY_ +#define _LIBCXX_MEMORY_ + +namespace std { + +template <> +class allocator<void> +{ +public: + typedef void* pointer; + typedef const void* const_pointer; + typedef void value_type; + template <class U> struct rebind { typedef allocator<U> other; }; +}; + +} + +#endif + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/mutex b/Usermode/Libraries/libc++.so_src/include_exp/mutex new file mode 100644 index 0000000000000000000000000000000000000000..d3d9ffd379f17c81c8cdadc922124b2925feaa62 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/mutex @@ -0,0 +1,76 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * mutex (header) + * - C++11's tutex handling + */ +#ifndef _LIBCXX_MUTEX_ +#define _LIBCXX_MUTEX_ + +#include "_libcxx_helpers.h" + +#if !_CXX11_AVAIL +# error "<mutex> requires C++11 support" +#endif + +namespace std { + +#if _CXX11_AVAIL + +class mutex +{ +public: + constexpr mutex() noexcept: + m_flag(false) + { + } + mutex(const mutex&) = delete; + mutex& operator=(const mutex&) = delete; + ~mutex(); + + void lock(); + bool try_lock(); + void unlock(); + + typedef void* native_handle; +private: + // TODO: Proper userland mutex support + bool m_flag; +}; + +struct defer_lock_t {}; +struct try_to_lock_t {}; +struct adopt_lock_t {}; + +template< class Mutex > +class lock_guard +{ +public: + typedef Mutex mutex_type; +private: + mutex_type& m_lock; +public: + lock_guard(mutex_type& m): + m_lock(m) + { + m_lock.lock(); + } + lock_guard(mutex_type& m, std::adopt_lock_t t): + m_lock(m) + { + // Adopted + } + ~lock_guard() { + m_lock.unlock(); + } +}; + +#endif + +}; // namespace std + +#endif + +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/new b/Usermode/Libraries/libc++.so_src/include_exp/new new file mode 100644 index 0000000000000000000000000000000000000000..b895832905eeef4b40cca37466f3ac58a3c57a16 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/new @@ -0,0 +1,45 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * new (header) + * - C++'s new operators + */ +#ifndef _LIBCXX_NEW_ +#define _LIBCXX_NEW_ + + +#include "cstddef" + +//extern void* operator new(size_t size) throw (::std::bad_alloc); +//extern void* operator new(size_t size, const std::nothrow_t& nothrow_value) throw(); +inline void* operator new(size_t /*size*/, void* ptr) throw() { + return ptr; +} + +//extern void* operator new[](size_t size) throw (::std::bad_alloc); +//extern void* operator new[](size_t size, const std::nothrow_t& nothrow_value) throw(); +inline void* operator new[](size_t /*size*/, void* ptr) throw() { + return ptr; +} + +#include "exception" + +namespace std { + +class bad_alloc: + public ::std::exception +{ +public: + bad_alloc() noexcept; + ~bad_alloc() noexcept; + + const char *what() const noexcept; +}; + +} // namespace std + +#endif + +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/stdexcept b/Usermode/Libraries/libc++.so_src/include_exp/stdexcept new file mode 100644 index 0000000000000000000000000000000000000000..75562073bf8ce252b3e020f94cca2ccd3ded0b25 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/stdexcept @@ -0,0 +1,64 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * string (header) + * - C++'s String type + */ +#ifndef _LIBCXX_STDEXCEPT_ +#define _LIBCXX_STDEXCEPT_ + +#include "exception" +#include "string" + +namespace std { + +namespace _bits { + +class str_except: + public exception +{ + ::std::string m_str; +public: + explicit str_except(const string& what_arg); + virtual ~str_except() noexcept; + str_except& operator= (const str_except& e) noexcept; + virtual const char* what() const noexcept; +}; + +} // namespace _bits + +class logic_error: + public _bits::str_except +{ +public: + explicit logic_error(const string& what_arg); +}; + +class runtime_error: + public _bits::str_except +{ +public: + explicit runtime_error(const string& what_arg); +}; + +class out_of_range: + public logic_error +{ +public: + explicit out_of_range(const string& what_arg); +}; + +class length_error: + public logic_error +{ +public: + explicit length_error(const string& what_arg); +}; + +}; // namespace std + +#endif + +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/string b/Usermode/Libraries/libc++.so_src/include_exp/string new file mode 100644 index 0000000000000000000000000000000000000000..f36077dda2c1b5e07248ef6d0e8e85418b9bdf32 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/string @@ -0,0 +1,604 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * string (header) + * - C++'s String type + */ +#ifndef _LIBCXX_STRING_ +#define _LIBCXX_STRING_ + +#include "_libcxx_helpers.h" +#include <allocator> +#include <initializer_list> + +namespace std { + +template <class charT> +struct char_traits +{ +}; + +template <> +struct char_traits<char> +{ + typedef char char_type; + typedef int int_type; + //typedef streamoff off_type; + //typedef streampos pos_type; + //typedef mbstate_t state_type; + + static bool eq(const char_type& c, const char_type& d) { + return c == d; + } + static bool lt(const char_type& c, const char_type& d) { + return c < d; + } + static size_t length(const char_type* s) { + size_t ret = 0; + while(*s++) ret ++; + return ret; + } + static int compare (const char_type* p, const char_type* q, size_t n) { + while (n--) { + if( !eq(*p,*q) ) + return lt(*p,*q) ? -1 : 1; + ++p; ++q; + } + return 0; + } +}; + +template <> +struct char_traits<wchar_t> +{ + typedef wchar_t char_type; + typedef int int_type; + //typedef streamoff off_type; + //typedef streampos pos_type; + //typedef mbstate_t state_type; + + static size_t length(const char_type* s) { + size_t ret = 0; + while(*s++) ret ++; + return ret; + } + static bool eq(const char_type& c, const char_type& d) { + return c == d; + } + static bool lt(const char_type& c, const char_type& d) { + return c < d; + } +}; + +extern void _throw_out_of_range(const char *message); + +template < class charT, class traits=char_traits<charT>, class Alloc=allocator<charT> > +class basic_string +{ +public: + typedef traits traits_type; + typedef Alloc allocator_type; + typedef charT value_type; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef size_t size_type; + + typedef charT* iterator; + typedef const charT* const_iterator; + +private: + struct dynamic_info + { + allocator_type m_allocator; + int m_ref_count = 1; + size_type m_capacity = 0; + size_type m_size = 0; + typename allocator_type::pointer m_data = 0; + dynamic_info(const allocator_type& alloc): + m_allocator(alloc) + { + } + dynamic_info(const dynamic_info& other): + m_allocator(other.m_allocator), + m_ref_count(1), + m_capacity(other.m_capacity), + m_size(other.m_size) + { + m_data = m_allocator.allocate(m_capacity); + for( size_type i = 0; i < m_size; i ++ ) + m_data[i] = other.m_data[i]; + } + }; + + allocator_type m_allocator; + dynamic_info *m_content; + +public: + basic_string(const allocator_type& alloc = allocator_type()): + m_allocator(alloc), + m_content(0) + { + } + basic_string(const basic_string& str) throw(): + basic_string(allocator_type()) + { + *this = str; + } + #if _CXX11_AVAIL + basic_string(basic_string&& str): + m_allocator(str.m_allocator), + m_content(str.m_content) + { + str.m_content = 0; + ::_sys::debug("basic_string(move) %p %s", m_content, c_str()); + } + #endif + basic_string(const basic_string& str, const allocator_type& alloc): + basic_string(str, 0, str.length(), alloc) + { + } + basic_string(const basic_string& str, size_type pos, size_type len = npos, const allocator_type& alloc = allocator_type()): + basic_string(alloc) + { + if( pos < str.length() ) + { + if( len > str.length() - pos ) + len = str.length() - pos; + reserve(len); + for( size_type i = 0; i < len; i ++ ) + m_content->m_data[i] = str.m_content->m_data[pos+i]; + m_content->m_size = len; + } + } + basic_string(const charT *s, const allocator_type& alloc = allocator_type()): + basic_string(s, traits::length(s), alloc) + { + } + basic_string(const charT *s, size_type n, const allocator_type& alloc = allocator_type()): + basic_string(alloc) + { + if( n > 0 ) + { + reserve(n); + for( size_type i = 0; i < n; i ++ ) + m_content->m_data[i] = s[i]; + m_content->m_data[n] = 0; + m_content->m_size = n; + } + } + basic_string(size_type n, charT c, const allocator_type& alloc = allocator_type()): + basic_string(alloc) + { + if( n > 0 ) + { + reserve(n); + for( size_type i = 0; i < n; i ++ ) + m_content->m_data[i] = c; + m_content->m_data[n] = 0; + m_content->m_size = n; + } + } + #if __cplusplus < 199711L + basic_string(basic_string&& str) noexcept: + basic_string(allocator_type()) + { + } + basic_string(basic_string&& str, const allocator_type& alloc) noexcept: + basic_string(alloc) + { + m_content = str.m_content; + str.m_content = 0; + } + #endif + ~basic_string() + { + release_content(); + } + basic_string& operator=(const basic_string& str) throw() { + return assign(str); + } + basic_string& operator=(const charT* s) { + return assign(s); + } + basic_string& operator=(charT c) { + return assign(c); + } + + // iterators + + // capacity + size_type size() const { + return m_content ? m_content->m_size : 0; + } + size_type length() const { + return size(); + } + size_type max_size() const { + return -1; + } + void resize(size_type size, charT c = 0) { + reserve(size); + if( m_content->m_size < size ) { + for( size_type ofs = m_content->m_size; ofs < size; ofs ++ ) + m_content->m_data[ofs] = c; + m_content->m_data[size] = 0; + } + m_content->m_size = size; + m_content->m_data[size] = 0; + } + size_type capacity() const { + return m_content ? m_content->m_capacity : 0; + } + void reserve(size_type size) { + own_content(); + size = (size+1 + 31) & ~31; + if( size > m_content->m_capacity ) { + auto new_area = m_allocator.allocate(size); + for( size_type i = 0; i < m_content->m_size; i ++ ) + new_area[i] = m_content->m_data[i]; + m_allocator.deallocate(m_content->m_data, m_content->m_capacity); + m_content->m_data = new_area; + m_content->m_capacity = size; + } + } + void clear() { + own_content(); + m_content->m_size = 0; + } + bool empty() const { + return length() == 0; + } + #if _CXX11_AVAIL + void shrink_to_fit(); + #endif + + // Access + reference operator[] (size_type pos) { + own_content(); + return m_content->m_data[pos]; + } + const_reference operator[] (size_type pos) const { + return (m_content ? m_content->m_data[pos] : *(const charT*)0); + } + reference at(size_type pos) { + own_content(); + if(pos >= m_content->m_size) + _throw_out_of_range("basic_string - at"); + return m_content->m_data[pos]; + } + const_reference at(size_type pos) const { + if(!m_content || pos >= m_content.m_size) + _throw_out_of_range("basic_string - at"); + return m_content->m_data[pos]; + } + #if _CXX11_AVAIL + reference back() { + own_content(); + return m_content->m_data[m_content->m_size]; + } + const_reference back() const { + return m_content->m_data[m_content->m_size]; + } + reference front() { + own_content(); + return m_content->m_data[0]; + } + const_reference front() const { + return m_content->m_data[0]; + } + #endif + + // Modifiers + basic_string& operator +=(const basic_string& str) { + return append(str); + } + basic_string& operator +=(const charT* s) { + return append(s); + } + basic_string& operator +=(charT c) { + push_back(c); + return *this; + } + basic_string& append(const basic_string& str) { + return append(str, 0, npos); + } + basic_string& append(const basic_string& str, size_type subpos, size_type sublen) { + if(subpos >= str.size()) + _throw_out_of_range("basic_string - assign source"); + if( sublen > str.size() - subpos ) + sublen = str.size() - subpos; + append( str.data() + subpos, sublen ); + return *this; + } + basic_string& append(const charT* s) { + return append(s, traits::length(s)); + } + basic_string& append(const charT* s, size_type n) { + reserve(size() + n); + for( size_type i = 0; i < n; i ++ ) + m_content->m_data[size() + i] = s[i]; + m_content->m_data[size()+n] = '\0'; + m_content->m_size += n; + return *this; + } + basic_string& append(size_type n, charT c) { + reserve(size() + n); + for( size_type i = 0; i < n; i ++ ) + m_content->m_data[size() + i] = c; + m_content->m_data[size()+n] = '\0'; + m_content->m_size += n; + return *this; + } + void push_back(charT c) { + append(1, c); + } + basic_string& assign(const basic_string& str) throw() { + // Special case, triggers copy-on-write. + release_content(); + m_content = str.m_content; + m_content->m_ref_count ++; + return *this; + } + basic_string& assign(const basic_string& str, size_type subpos, size_type sublen) { + if(subpos >= str.size()) + _throw_out_of_range("basic_string - assign source"); + if( sublen > str.size() - subpos ) + sublen = str.size() - subpos; + + return assign(str.data() + subpos, sublen); + } + basic_string& assign(const charT* s) { + return assign(s, traits::length(s)); + } + basic_string& assign(const charT* s, size_type n) { + release_content(); + reserve(n); + for( size_type i = 0; i < n; i ++ ) + m_content->m_data[i] = s[i]; + m_content->m_data[n] = '\0'; + m_content->m_size = n; + return *this; + } + basic_string& assign(size_type n, charT c) { + release_content(); + reserve(n); + for( size_type i = 0; i < n; i ++ ) + m_content->m_data[i] = c; + m_content->m_data[n] = '\0'; + m_content->m_size = n; + return *this; + } + + basic_string& insert(size_type pos, const basic_string& str); + basic_string& insert(size_type pos, const basic_string& str, size_type subpos, size_type sublen); + basic_string& insert(size_type pos, const charT& s); + basic_string& insert(size_type pos, const charT& s, size_type n); + basic_string& insert(size_type pos, size_type n, charT c); + iterator insert(const_iterator p, size_type n, charT c); + iterator insert(const_iterator p, charT c); + template <class InputIterator> + iterator insert(iterator p, InputIterator first, InputIterator last); + #if _CXX11_AVAIL + basic_string& insert(const_iterator p, initializer_list<charT> il); + #endif + + basic_string& erase(size_type pos = 0, size_type len = npos); + iterator erase(const_iterator p); + iterator erase(const_iterator first, const_iterator last); + + basic_string& replace(size_type pos, size_type len, const basic_string& str); + basic_string& replace(const_iterator i1, const_reference i2, const basic_string& str); + basic_string& replace(size_type pos, size_type len, const basic_string& str, size_type subpos, size_type sublen); + basic_string& replace(size_type pos, size_type len, const charT *s); + basic_string& replace(const_iterator i1, const_reference i2, const charT* s); + basic_string& replace(size_type pos, size_type len, const charT *s, size_type n); + basic_string& replace(const_iterator i1, const_reference i2, const charT* s, size_type n); + basic_string& replace(size_type pos, size_type len, size_type n, charT c); + basic_string& replace(const_iterator i1, const_reference i2, size_type n, charT c); + template <class InputIterator> + basic_string& replace(const_iterator i1, const_reference i2, InputIterator first, InputIterator last); + basic_string& replace(const_iterator i1, const_iterator i2, initializer_list<charT> il); + + void swap(basic_string& str) + { + auto tmp = m_content; + m_content = str.m_content; + str.m_content = tmp; + } + + #if _CXX11_AVAIL + void pop_back(); + #endif + + // String operations + const charT *c_str() const noexcept + { + // TODO: this is const, but also might need to do processing + if(m_content) { + _libcxx_assert(m_content->m_data[m_content->m_size] == '\0'); + } + return (m_content ? m_content->m_data : ""); + } + const charT *data() const + { + return (m_content ? m_content->m_data : NULL); + } + allocator_type get_allocator() const noexcept + { + return m_allocator; + } + size_type copy(charT* s, size_type len, size_type pos = 0) const; + + size_type find(const basic_string& str, size_type pos = 0) const noexcept; + size_type find(const charT* s, size_type pos = 0) const; + size_type find(const charT* s, size_type pos, size_type n) const; + size_type find(charT c, size_type pos = 0) const noexcept; + + size_type rfind(const basic_string& str, size_type pos = 0) const noexcept; + size_type rfind(const charT* s, size_type pos = 0) const; + size_type rfind(const charT* s, size_type pos, size_type n) const; + size_type rfind(charT c, size_type pos = 0) const noexcept; + + size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept; + size_type find_first_of(const charT* s, size_type pos = 0) const; + size_type find_first_of(const charT* s, size_type pos, size_type n) const; + size_type find_first_of(charT c, size_type pos = 0) const noexcept; + + size_type find_last_of(const basic_string& str, size_type pos = 0) const noexcept; + size_type find_last_of(const charT* s, size_type pos = 0) const; + size_type find_last_of(const charT* s, size_type pos, size_type n) const; + size_type find_last_of(charT c, size_type pos = 0) const noexcept; + + size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept; + size_type find_first_not_of(const charT* s, size_type pos = 0) const; + size_type find_first_not_of(const charT* s, size_type pos, size_type n) const; + size_type find_first_not_of(charT c, size_type pos = 0) const noexcept; + + size_type find_last_not_of(const basic_string& str, size_type pos = 0) const noexcept; + size_type find_last_not_of(const charT* s, size_type pos = 0) const; + size_type find_last_not_of(const charT* s, size_type pos, size_type n) const; + size_type find_last_not_of(charT c, size_type pos = 0) const noexcept; + + basic_string substr(size_type pos = 0, size_type len = npos) const; + + int compare(const basic_string& str) const noexcept { + return compare(0, size(), str.data(), str.size()); + } + int compare(size_type pos, size_type len, const basic_string& str) const { + _libcxx_assert(pos <= size()); + _libcxx_assert(len <= size()); + _libcxx_assert(pos+len <= size()); + return compare(pos, len, str.data(), str.size()); + } + int compare(size_type pos, size_type len, const basic_string& str, size_type subpos, size_type sublen) const { + // TODO: check + _libcxx_assert(subpos <= str.size()); + _libcxx_assert(sublen <= str.size()); + _libcxx_assert(subpos+sublen <= str.size()); + return compare(pos, len, str.data()+subpos, sublen); + } + int compare(const charT* s) const { + return compare(0, npos, s, traits::length(s)); + } + int compare(size_type pos, size_type len, const charT* s) const { + return compare(pos, len, s, traits::length(s)); + } + int compare(size_type pos, size_type len, const charT* s, size_type n) const { + if( n <= len ) { + int rv = traits::compare(data()+pos, s, n); + if( rv == 0 && n < len ) { + rv = -1; + } + return rv; + } + else { + int rv = traits::compare(data()+pos, s, len); + if(rv == 0) { + rv = 1; + } + return rv; + } + } + + static const size_type npos = -1; +private: + void own_content() { + if(!m_content) + { + m_content = new dynamic_info(m_allocator); + } + else if( m_content->m_ref_count > 1 ) + { + dynamic_info *new_cont = new dynamic_info(*m_content); + m_content->m_ref_count --; + m_content = new_cont; + } + else + { + // already owned + } + } + void release_content() { + if( m_content ) + { + m_content->m_ref_count --; + if( m_content->m_ref_count == 0 ) { + m_allocator.deallocate(m_content->m_data, m_content->m_capacity); + delete m_content; + } + m_content = NULL; + } + } +}; + +typedef basic_string<char> string; + +#define _libcxx_str basic_string<charT,traits,Alloc> + +template <class charT, class traits, class Alloc> +basic_string<charT,traits,Alloc> operator+(const basic_string<charT,traits,Alloc>& lhs, const basic_string<charT,traits,Alloc>& rhs) +{ + basic_string<charT,traits,Alloc> ret; + ret.reserve(lhs.size() + rhs.size()); + ret += lhs; + ret += rhs; + return ret; +} +template <class charT, class traits, class Alloc> +basic_string<charT,traits,Alloc> operator+(const basic_string<charT,traits,Alloc>& lhs, const charT* rhs) +{ + basic_string<charT,traits,Alloc> ret; + ret.reserve(lhs.size() + traits::length(rhs)); + ret += lhs; + ret += rhs; + return ret; +} +template <class charT, class traits, class Alloc> +basic_string<charT,traits,Alloc> operator+(const charT* lhs, const basic_string<charT,traits,Alloc>& rhs) +{ + basic_string<charT,traits,Alloc> ret; + ret.reserve(traits::length(lhs) + rhs.size()); + ret += lhs; + ret += rhs; + return ret; +} +template <class charT, class traits, class Alloc> +basic_string<charT,traits,Alloc> operator+(const basic_string<charT,traits,Alloc>& lhs, const charT rhs) +{ + basic_string<charT,traits,Alloc> ret; + ret.reserve(lhs.size() + 1); + ret += lhs; + ret += rhs; + return ret; +} +template <class charT, class traits, class Alloc> +basic_string<charT,traits,Alloc> operator+(const charT lhs, const basic_string<charT,traits,Alloc>& rhs) +{ + basic_string<charT,traits,Alloc> ret; + ret.reserve(1 + rhs.size()); + ret += lhs; + ret += rhs; + return ret; +} + +// Three overloads each +// name: Actual operator, opp: reversed operator +#define _libcxx_string_def_cmp(name, opp) \ + template <class charT, class traits, class Alloc> \ + bool operator name(const _libcxx_str& lhs, const _libcxx_str& rhs) { return lhs.compare(rhs) name 0; } \ + template <class charT, class traits, class Alloc> \ + bool operator name(const charT* lhs, const _libcxx_str& rhs) { return rhs.compare(lhs) opp 0; } \ + template <class charT, class traits, class Alloc> \ + bool operator name(const _libcxx_str& lhs, const charT* rhs) { return lhs.compare(rhs) name 0; } + +_libcxx_string_def_cmp(<, >) +_libcxx_string_def_cmp(<=, >=) +_libcxx_string_def_cmp(==, ==) +_libcxx_string_def_cmp(>=, <=) +_libcxx_string_def_cmp(>, <) +}; + +#endif + +// vim: ft=cpp diff --git a/Usermode/Libraries/libc++.so_src/include_exp/system_error b/Usermode/Libraries/libc++.so_src/include_exp/system_error new file mode 100644 index 0000000000000000000000000000000000000000..496970eb08b048bbe6112564589fb4b2b72bdb27 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/system_error @@ -0,0 +1,189 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * system_error (header) + * - C++11's system_error exception + */ +#ifndef _LIBCXX_SYSTEM_ERROR_ +#define _LIBCXX_SYSTEM_ERROR_ + +#include "_libcxx_helpers.h" + +#if !_CXX11_AVAIL +# error "This header requires C++11 support enabled" +#endif + +#include <exception> +#include <string> + +namespace std { + +class error_category; +class error_condition; +class error_code; + +static bool operator==(const error_condition& lhs, const error_condition& rhs) noexcept; +static bool operator!=(const error_condition& lhs, const error_condition& rhs) noexcept; +static bool operator< (const error_condition& lhs, const error_condition& rhs) noexcept; +static bool operator==(const error_condition& lhs, const error_code& rhs) noexcept; +static bool operator==(const error_code& lhs, const error_condition& rhs) noexcept; +static bool operator!=(const error_condition& lhs, const error_code& rhs) noexcept; +static bool operator!=(const error_code& lhs, const error_condition& rhs) noexcept; + +extern const error_category& generic_category() noexcept; +extern const error_category& system_category() noexcept; + +class error_condition +{ + int m_val; + const error_category* m_cat; +public: + error_condition() noexcept: + error_condition(0, ::std::generic_category()) + { + } + error_condition(int val, const error_category& cat) noexcept: + m_val(val), + m_cat(&cat) + { + } + //template <class ErrorConditionEnum> error_condition(ErrorConditionEnum e) noexcept; + //template <class ErrorConditionEnum> error_condition& operator=(ErrorConditionEnum e) noexcept; + void assign(int val, const error_category& cat) noexcept { + m_val = val; + m_cat = &cat; + } + void clear() noexcept { + assign(0, ::std::generic_category()); + } + int value() const noexcept { + return m_val; + } + const error_category& category() const noexcept { + return *m_cat; + } + string message() const; + explicit operator bool() const noexcept { + return m_val != 0; + } +}; + +class error_category +{ +public: + error_category() { + } + error_category(const error_category&) = delete; // disallow copying + virtual ~error_category() noexcept { + } + bool operator==(const error_category& rhs) const noexcept { + return this == &rhs; + } + bool operator!=(const error_category& rhs) const noexcept { + return !(*this == rhs); + } + bool operator<(const error_category& rhs) const noexcept { + return this < &rhs; + } + virtual const char* name() const noexcept = 0; + virtual error_condition default_error_condition(int val) const noexcept { + return error_condition(val, *this); + } + virtual bool equivalent(int valcode, const ::std::error_condition& cond) const noexcept { + return default_error_condition(valcode) == cond; + } + virtual bool equivalent(const error_code& code, int valcond) const noexcept; // in system_error.cc + virtual ::std::string message(int val) const = 0; +}; + +class error_code +{ + int m_ev; + const ::std::error_category* m_ecat; +public: + error_code() noexcept: + error_code(0, ::std::generic_category()) + { + } + error_code(int ev, const ::std::error_category& ecat) noexcept: + m_ev(ev), + m_ecat(&ecat) + { + } + //template <class ErrorCodeEnum> + //error_code(ErrorCodeEnum e) noexcept; + void assign(int val, const error_category& ecat) noexcept { + m_ev = val; + m_ecat = &ecat; + } + //template <class ErrorCodeEnum> + //error_code& operator= (ErrorCodeEnum e) noexcept; + void clear() noexcept { + m_ev = 0; + m_ecat = 0; + } + int value() const noexcept { + return m_ev; + } + const error_category& category() const noexcept { + return *m_ecat; + } + error_condition default_error_condition() const noexcept { + return category().default_error_condition(value()); + } + ::std::string message() const { + return category().message(value()); + } + operator bool() const noexcept { + return m_ev != 0; + } +}; + +class system_error: + public ::std::exception +{ + const error_code m_error_code; + ::std::string m_what_str; +public: + system_error(::std::error_code ec); + system_error(::std::error_code ec, const ::std::string& what_arg); + system_error(::std::error_code ec, const char* what_arg); + system_error(int ev, const ::std::error_category& ecat); + system_error(int ev, const ::std::error_category& ecat, const ::std::string& what_arg); + system_error(int ev, const ::std::error_category& ecat, const char* what_arg); + ~system_error() noexcept; + + const char* what() const noexcept; +}; + +static inline bool operator==(const error_condition& lhs, const error_condition& rhs) noexcept { + return lhs.category() == rhs.category() && lhs.value() == rhs.value(); +} +static inline bool operator!=(const error_condition& lhs, const error_condition& rhs) noexcept { + return !(lhs == rhs); +} +static inline bool operator< (const error_condition& lhs, const error_condition& rhs) noexcept { + return lhs.category() < rhs.category() || lhs.value() < rhs.value(); +} +static inline bool operator==(const error_condition& lhs, const error_code& rhs) noexcept { + return lhs.category().equivalent(rhs, lhs.value()) || rhs.category().equivalent(rhs.value(), lhs); +} +static inline bool operator==(const error_code& lhs, const error_condition& rhs) noexcept { + return lhs.category().equivalent(lhs.value(),rhs) || rhs.category().equivalent(lhs,rhs.value()); +} +static inline bool operator!=(const error_condition& lhs, const error_code& rhs) noexcept { + return !(lhs == rhs); +} +static inline bool operator!=(const error_code& lhs, const error_condition& rhs) noexcept { + return !(lhs == rhs); +} + + + +}; // namespace std + +#endif + +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/type_traits b/Usermode/Libraries/libc++.so_src/include_exp/type_traits new file mode 100644 index 0000000000000000000000000000000000000000..62103ac2f1c36c53a5589f07bcb0f413a790f103 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/type_traits @@ -0,0 +1,24 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * type_traits (header) + * - C++11 type traits + */ +#ifndef _LIBCXX_TYPE_TRAITS_ +#define _LIBCXX_TYPE_TRAITS_ + +#include "_libcxx_helpers.h" + +#if !_CXX11_AVAIL +# error "This header requires C++11 support enabled" +#endif + +template <class T> struct remove_reference { typedef T type; }; +template <class T> struct remove_reference<T&> { typedef T type; }; +template <class T> struct remove_reference<T&&> { typedef T type; }; + +#endif + +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/typeinfo b/Usermode/Libraries/libc++.so_src/include_exp/typeinfo index c02d388b79d5191019a13ac80ac62e32c96adc5b..c8b037ceab3ff39e5879b28938bd3539dec8d6d1 100644 --- a/Usermode/Libraries/libc++.so_src/include_exp/typeinfo +++ b/Usermode/Libraries/libc++.so_src/include_exp/typeinfo @@ -8,6 +8,8 @@ #ifndef _LIBCXX__TYPEINFO_ #define _LIBCXX__TYPEINFO_ +#include <cstddef> + namespace std { // Type information class @@ -19,9 +21,16 @@ public: bool operator!=(const type_info &) const; bool before(const type_info &) const; const char* name() const; + + // acess + bool __is_child(const type_info &, size_t&) const; private: type_info (const type_info& rhs); type_info& operator= (const type_info& rhs); + + // acess + bool is_class() const; + bool is_subclass() const; // CXX ABI const char *__type_name; diff --git a/Usermode/Libraries/libc++.so_src/include_exp/utility b/Usermode/Libraries/libc++.so_src/include_exp/utility new file mode 100644 index 0000000000000000000000000000000000000000..b3e40c53b8961619ebfb21abeee4556eb1927136 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/utility @@ -0,0 +1,91 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * string (header) + * - C++'s String type + */ +#ifndef _LIBCXX_UTILITY_ +#define _LIBCXX_UTILITY_ + +#include "_libcxx_helpers.h" +#include "type_traits" + +namespace std { + +template <class T1, class T2> +class pair +{ +public: + typedef T1 first_type; + typedef T2 second_type; + + first_type first; + second_type second; + + pair() + { + } + template <class U, class V> + pair(const pair<U,V>& pr): + first (pr.first), + second(pr.second) + { + } + pair(const first_type& a, const second_type& b): + first (a), + second(b) + { + } + pair(const pair& pr): + first(pr.first), + second(pr.second) + { + } + pair(pair&& pr): + first(pr.first), second(pr.second) + { + } + // operator = is implicit + pair& operator=(const pair& x) { + first = x.first; + second = x.second; + return *this; + } +}; + +template <class T1, class T2> +bool operator== (const pair<T1,T2>& lhs, const pair<T1,T2>& rhs) { + return lhs.first == rhs.first && lhs.second == rhs.second; +} +template <class T1, class T2> +bool operator!= (const pair<T1,T2>& lhs, const pair<T1,T2>& rhs) { + return !(lhs == rhs); +} + +#if _CXX11_AVAIL +template <class T> +T&& forward(typename remove_reference<T>::type& arg) noexcept { + return static_cast<decltype(arg)&&>(arg); +} +template <class T> +T&& forward(typename remove_reference<T>::type&& arg) noexcept { + return static_cast<decltype(arg)&&>(arg); +} + +template <class T> +typename remove_reference<T>::type&& move( T&& t) noexcept { + return static_cast<typename remove_reference<T>::type&&>(t); +} +//template <class T> +//constexpr typename ::std::remove_reference<T>::type&& move( T&& t) noexcept { +// return static_cast<typename ::std::remove_reference<T>::type&&>(t); +//} +#endif + +}; // namespace std + +#endif + +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/include_exp/vector b/Usermode/Libraries/libc++.so_src/include_exp/vector new file mode 100644 index 0000000000000000000000000000000000000000..ab42c9c889fcfb1700535aed5cc33178f4e03438 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/include_exp/vector @@ -0,0 +1,397 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * vector (header) + * - C++'s vector (dynamic array) type + */ +#ifndef _LIBCXX_VECTOR_ +#define _LIBCXX_VECTOR_ + +#include <allocator> +#include <stdexcept> +#include <initializer_list> + +extern "C" void _SysDebug(const char *, ...); + +namespace std { + +namespace _bits { +template <class VectorType, class T> +class vector_iterator//: + //public random_acess_iterator_tag +{ + friend VectorType; + + typedef typename VectorType::size_type size_type; + typedef typename VectorType::difference_type difference_type; + + T* m_array; + size_type m_pos; + size_type m_max; +public: + vector_iterator(): + vector_iterator(0,0,0) + { + } + vector_iterator(const vector_iterator& x): + vector_iterator() + { + *this = x; + } + vector_iterator(T* array, size_type start, size_type max): + m_array(array), + m_pos(start), + m_max(max) + { + } + vector_iterator& operator=(const vector_iterator& x) + { + m_array = x.m_array; + m_pos = x.m_pos; + m_max = x.m_max; + return *this; + } + bool operator==(const vector_iterator& other) const { + return m_pos == other.m_pos; + } + bool operator!=(const vector_iterator& other) const { + return !(*this == other); + } + T& operator*() const { + return m_array[m_pos]; + } + T& operator->() const { + return m_array[m_pos]; + } + T& operator[](difference_type n) { + return *(*this + n); + } + vector_iterator& operator++() { + if(m_pos < m_max) { + m_pos ++; + } + return *this; + } + const vector_iterator operator++(int) { + vector_iterator ret(*this); + ++*this; + return ret; + } + vector_iterator& operator--() { + if(m_pos > 0) { + m_pos --; + } + return *this; + } + const vector_iterator operator--(int) { + vector_iterator ret(*this); + --*this; + return ret; + } + vector_iterator& operator+=(difference_type n) { + if( n < 0 ) + return (*this -= -n); + if( n > 0 ) + m_pos = (m_pos + n < m_max ? m_pos + n : m_max); + return *this; + } + vector_iterator& operator-=(difference_type n) { + if( n < 0 ) + return (*this += -n); + if( n > 0 ) + m_pos = (m_pos >= n ? m_pos - n : 0); + return *this; + } + const difference_type operator-(const vector_iterator& it2) const { + //_libcxx_assert(m_array == it2.m_array); + return m_pos - it2.m_pos; + } + bool operator<(const vector_iterator& o) const { return m_pos < o.m_pos; } + bool operator>(const vector_iterator& o) const { return m_pos > o.m_pos; } + bool operator<=(const vector_iterator& o) const { return m_pos <= o.m_pos; } + bool operator>=(const vector_iterator& o) const { return m_pos >= o.m_pos; } +}; +#define vector_iterator_tpl class VectorType, class T +#define vector_iterator vector_iterator<VectorType, T> +template <vector_iterator_tpl> +const vector_iterator operator+(const vector_iterator& it, typename VectorType::difference_type n) { + return vector_iterator(it) += n; +} +template <vector_iterator_tpl> +const vector_iterator operator+(typename VectorType::difference_type n, const vector_iterator& it) { + return vector_iterator(it) += n; +} +template <vector_iterator_tpl> +const vector_iterator operator-(const vector_iterator& it, typename VectorType::difference_type n) { + return vector_iterator(it) -= n; +} +#undef vector_iterator_tpl +#undef vector_iterator + +} + +template <class T, class Alloc = allocator<T> > +class vector +{ +public: + typedef T value_type; + typedef Alloc allocator_type; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef int difference_type; + typedef size_t size_type; + typedef ::std::_bits::vector_iterator<vector,T> iterator; + typedef ::std::_bits::vector_iterator<vector,const T> const_iterator; + +private: + allocator_type m_alloc; + size_type m_size; + size_type m_capacity; + value_type* m_data; + +public: + vector(const allocator_type& alloc = allocator_type()): + m_alloc(alloc), + m_size(0), + m_capacity(0), + m_data(0) + { + } + vector(size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type()): + vector(alloc) + { + resize(n, val); + } + template <class InputIterator> + vector(InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type()): + vector(alloc) + { + insert(begin(), first, last); + } + vector(const vector& x): + vector(x.m_alloc) + { + *this = x; + } + #if _CXX11_AVAIL + vector(vector&& x): + m_alloc(x.m_alloc), + m_size(x.m_size), + m_capacity(x.m_capacity), + m_data(x.m_data) + { + x.m_data = nullptr; + x.m_capacity = 0; + x.m_size = 0; + } + vector(vector&& x, const allocator_type& alloc): + m_alloc(alloc), + m_size(x.m_size), + m_capacity(x.m_capacity), + m_data(x.m_data) + { + x.m_data = nullptr; + x.m_capacity = 0; + x.m_size = 0; + } + vector(std::initializer_list<value_type> il, const allocator_type& alloc = allocator_type()): + vector(alloc) + { + reserve(il.size()); + insert(begin(), il.begin(), il.end()); + } + #endif + vector& operator=(const vector& x) + { + clear(); + m_alloc.deallocate(m_data, m_capacity); + m_capacity = 0; + m_data = nullptr; + + reserve(x.size()); + for( size_type i = 0; i < x.size(); i ++ ) + push_back( x[i] ); + + return *this; + } + + ~vector() + { + clear(); + m_alloc.deallocate(m_data, m_capacity); + m_capacity = 0; + m_data = nullptr; + } + + // Iterators + iterator begin() { return iterator_to(0); } + const_iterator begin() const { return iterator_to(0); } + iterator end() { return iterator_to(m_size); } + const_iterator end() const { return iterator_to(m_size); } + + // Capacity + size_type size() const { + return m_size; + } + size_type max_size() const { + return -1 / sizeof(value_type); + } + void resize(size_type new_cap, value_type val = value_type()) { + reserve(new_cap); + if( new_cap > m_size ) + { + for( size_type i = m_size; i < new_cap; i ++ ) { + m_alloc.construct( &m_data[i], val ); + } + } + else + { + for( size_type i = new_cap; i < m_size; i ++ ) + m_alloc.destroy( &m_data[i] ); + } + m_size = new_cap; + } + size_type capacity() const { + return m_capacity; + } + bool empty() const { + return m_size == 0; + } + void reserve(size_type n) { + if( n > max_size() ) + throw ::std::length_error("::std::vector::reserve"); + if( n > m_capacity ) + { + size_type size = (n + 0x1F) & ~0x1F; + auto new_area = m_alloc.allocate(size); + for( size_type i = 0; i < m_size; i ++ ) + new_area[i] = m_data[i]; + m_alloc.deallocate(m_data, m_capacity); + m_data = new_area; + m_capacity = size; + //::_SysDebug("::std::vector::resize - m_capacity=%i for n=%i", m_capacity, n); + } + } + void shrink_to_fit() { + } + + // Element access + reference operator[] (size_type n) { + return m_data[n]; + } + const_reference operator[] (size_type n) const { + return m_data[n]; + } + reference at(size_type n) { + if(n > size()) + _throw_out_of_range("::std::vector - at"); + return m_data[n]; + } + const_reference at(size_type n) const { + if(n > size()) + _throw_out_of_range("::std::vector - at"); + return m_data[n]; + } + reference front() { + return m_data[0]; + } + const_reference front() const { + return m_data[0]; + } + reference back() { + return m_data[size()-1]; + } + const_reference back() const { + return m_data[size()-1]; + } + pointer data() noexcept { + return m_data; + } + const_pointer data() const noexcept { + return m_data; + } + + // Modifiers + void assign(size_type n, const value_type& val) { + clear(); + resize(n, val); + } + void push_back(const value_type& val) { + resize(size()+1, val); + } + void pop_back() { + if( !empty() ) { + resize(size()-1); + } + } + iterator insert(iterator position, const value_type& val) { + insert(position, 1, val); + return iterator_to(position.m_pos); + } + void insert(iterator position, size_type n, const value_type& val) { + reserve(m_size + n); + if( position != end() ) { + ::_sys::debug("TODO: vector::insert within vector (%i!=%i)", + position-begin(), end()-begin()); + ::_sys::abort(); + } + size_type pos = m_size; + while( n -- ) + { + //::_sys::debug("vector::insert - %x at %i", val, pos); + m_alloc.construct( &m_data[pos], val ); + pos ++; + m_size ++; + } + } + template <class InputIterator> + void insert(iterator position, InputIterator first, InputIterator last) { + InputIterator it = first; + size_type len = 0; + while(it != last) { + ++ it; + len ++; + } + reserve(m_size + len); + + it = first; + while(it != last) + { + //::_sys::debug("vector::insert - to %i, from %p:%i", + // position.m_pos, it.m_array, it.m_pos); + position = insert(position, *it) + 1; + ++it; + } + } + iterator erase(iterator position); + iterator erase(iterator first, iterator last); + //void swap(vector& x) { + // ::std::swap(m_size, x.m_size); + // ::std::swap(m_capacity, x.m_capacity); + // ::std::swap(m_data, x.m_data); + //} + void clear() { + for( size_type i = 0; i < m_size; i ++ ) { + m_alloc.destroy( &m_data[i] ); + } + m_size = 0; + } +private: + iterator iterator_to(size_type index) { + _libcxx_assert(index <= m_size); + return iterator(m_data, index, m_size); + } + const_iterator iterator_to(size_type index) const { + _libcxx_assert(index <= m_size); + return const_iterator(m_data, index, m_size); + } +}; + +}; // namespace std + +#endif +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc++.so_src/misc.cc b/Usermode/Libraries/libc++.so_src/misc.cc index ed0a2eb63c431b321c60eda34a71dbd94df1fbfc..2ce7a5178b5c1db85cd7b129e6c2d0b0b2a47bc5 100644 --- a/Usermode/Libraries/libc++.so_src/misc.cc +++ b/Usermode/Libraries/libc++.so_src/misc.cc @@ -6,9 +6,13 @@ * - Miscelanious functions */ #include <string.h> +#include <acess/sys.h> +#include <exception> extern "C" int SoMain() { + //extern void _init(); + //_init(); // nope return 0; } @@ -16,11 +20,8 @@ extern "C" int SoMain() extern "C" void __cxa_pure_virtual() { // dunno -} - -extern "C" void __gxx_personality_v0() -{ - // TODO: Handle __gxx_personality_v0 somehow + ::_SysDebug("__cxa_pure_virtual by %p", __builtin_return_address(0)); + ::std::terminate(); } diff --git a/Usermode/Libraries/libc++.so_src/mutex.cc b/Usermode/Libraries/libc++.so_src/mutex.cc new file mode 100644 index 0000000000000000000000000000000000000000..5ff27dfa8392dfbbfed7e7cbcf7a95e772e5f8ad --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/mutex.cc @@ -0,0 +1,39 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * mutex.cc + * - ::std::mutex and helpers + */ +#include <mutex> +#include <system_error> +#include <cerrno> + +// === CODE === +::std::mutex::~mutex() +{ + +} + +void ::std::mutex::lock() +{ + if( m_flag ) + { + _sys::debug("TODO: userland mutexes"); + throw ::std::system_error(ENOTIMPL, ::std::system_category()); + } + m_flag = true; +} + +bool ::std::mutex::try_lock() +{ + bool rv = m_flag; + m_flag = true; + return !rv; +} + +void ::std::mutex::unlock() +{ + m_flag = false; +} + diff --git a/Usermode/Libraries/libc++.so_src/new.cc b/Usermode/Libraries/libc++.so_src/new.cc index 1d09fbc3dc1f09facd291503d1a6752befc8a831..f1ebc453143f88b2dc990e1ba52b1fce743d364b 100644 --- a/Usermode/Libraries/libc++.so_src/new.cc +++ b/Usermode/Libraries/libc++.so_src/new.cc @@ -7,25 +7,51 @@ */ #include <stddef.h> #include <stdlib.h> +#include <acess/sys.h> +#include <new> + +// === IMPORTS === +extern "C" bool _libc_free(void *mem); // from libc.so, actual free. // === CODE === void *operator new( size_t size ) { + //_SysDebug("libc++ - operator new(%i)", size); return malloc( size ); } void *operator new[]( size_t size ) { + //_SysDebug("libc++ - operator new[](%i)", size); return malloc( size ); } void operator delete(void *ptr) { - free(ptr); + if( !_libc_free(ptr) ) { + _SysDebug("delete of invalid by %p", __builtin_return_address(0)); + throw ::std::bad_alloc(); + } } void operator delete[](void *ptr) { - free(ptr); + if( !_libc_free(ptr) ) { + _SysDebug("delete[] of invalid by %p", __builtin_return_address(0)); + throw ::std::bad_alloc(); + } +} + + +::std::bad_alloc::bad_alloc() noexcept +{ +} +::std::bad_alloc::~bad_alloc() noexcept +{ +} + +const char *::std::bad_alloc::what() const noexcept +{ + return "allocation failure"; } diff --git a/Usermode/Libraries/libc++.so_src/string.cc b/Usermode/Libraries/libc++.so_src/string.cc new file mode 100644 index 0000000000000000000000000000000000000000..f063e3434b85141123a2f33fe231c8ccc3a25e4c --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/string.cc @@ -0,0 +1,15 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * exceptions.cc + * - ::std::exception and friends + */ +#include <string> +#include <stdexcept> + +void ::std::_throw_out_of_range(const char *message) +{ + throw ::std::out_of_range( ::std::string(message) ); +} + diff --git a/Usermode/Libraries/libc++.so_src/system_error.cc b/Usermode/Libraries/libc++.so_src/system_error.cc new file mode 100644 index 0000000000000000000000000000000000000000..9a9fb4d2352db0302a6bf7d21775f5d18a8c31c1 --- /dev/null +++ b/Usermode/Libraries/libc++.so_src/system_error.cc @@ -0,0 +1,107 @@ +/* + * Acess2 C++ Library + * - By John Hodge (thePowersGang) + * + * system_error.cc + * - ::std::system_error and other helpers + */ +#include <system_error> +#include <cerrno> + +namespace std { + +system_error::system_error(::std::error_code ec): + m_error_code(ec), + m_what_str( (::std::string)ec.category().name() + ":" + ec.message()) +{ + ::_sys::debug("system_error(%s:%s)", ec.category().name(), ec.message().c_str()); +} +system_error::system_error(::std::error_code ec, const ::std::string& what_arg): + system_error(ec) +{ + m_what_str += " - "; + m_what_str += what_arg; +} +system_error::system_error(::std::error_code ec, const char* what_arg): + system_error(ec) +{ + m_what_str += " - "; + m_what_str += what_arg; +} +system_error::system_error(int ev, const ::std::error_category& ecat): + system_error( ::std::error_code(ev, ecat) ) +{ +} +system_error::system_error(int ev, const ::std::error_category& ecat, const ::std::string& what_arg): + system_error(ev, ecat) +{ + m_what_str += " - "; + m_what_str += what_arg; +} +system_error::system_error(int ev, const ::std::error_category& ecat, const char* what_arg): + system_error(ev, ecat) +{ + m_what_str += " - "; + m_what_str += what_arg; +} + +system_error::~system_error() noexcept +{ +} + +const char* system_error::what() const noexcept +{ + return m_what_str.c_str(); +} + + +bool error_category::equivalent(const error_code& code, int valcond) const noexcept { + return *this == code.category() && code.value() == valcond; +} + + +class class_generic_category: + public error_category +{ +public: + class_generic_category() { + } + ~class_generic_category() noexcept { + } + const char *name() const noexcept { + return "generic"; + } + ::std::string message(int val) const { + return ::std::string( ::strerror(val) ); + } +} g_generic_category; + +const ::std::error_category& generic_category() noexcept +{ + return g_generic_category; +} + + +class class_system_category: + public error_category +{ +public: + class_system_category() { + } + ~class_system_category() noexcept { + } + const char *name() const noexcept { + return "system"; + } + ::std::string message(int val) const { + return ::std::string( ::strerror(val) ); + } +} g_system_category; + +const ::std::error_category& system_category() noexcept +{ + return g_system_category; +} + +}; // namespace std + diff --git a/Usermode/Libraries/libc++.so_src/typeinfo.cc b/Usermode/Libraries/libc++.so_src/typeinfo.cc index b0a9b3e1b9020d2455e3337e380a4aaa5c16f4da..99bfedc5de1ce40e459ac1de54e064da592aa34d 100644 --- a/Usermode/Libraries/libc++.so_src/typeinfo.cc +++ b/Usermode/Libraries/libc++.so_src/typeinfo.cc @@ -6,6 +6,9 @@ * - typeid and dynamic_cast */ #include <typeinfo> +#include <cxxabi.h> +#include <acess/sys.h> +#include <cstdlib> namespace std { @@ -16,16 +19,19 @@ type_info::~type_info() bool type_info::operator==(const type_info& other) const { + //_SysDebug("type_info::operator== - '%s' == '%s'", this->__type_name, other.__type_name); return this->__type_name == other.__type_name; } bool type_info::operator!=(const type_info& other) const { + //_SysDebug("type_info::operator!= - '%s' != '%s'", this->__type_name, other.__type_name); return this->__type_name != other.__type_name; } bool type_info::before(const type_info& other) const { + //_SysDebug("type_info::before - '%s' < '%s'", this->__type_name, other.__type_name); return this->__type_name < other.__type_name; } @@ -41,10 +47,76 @@ type_info::type_info(const type_info& rhs): } type_info& type_info::operator=(const type_info& rhs) { + _SysDebug("type_info::operator=, was %s now %s", __type_name, rhs.__type_name); __type_name = rhs.__type_name; return *this; } +bool type_info::is_class() const +{ + if( typeid(*this) == typeid(::__cxxabiv1::__class_type_info) ) + return true; + if( is_subclass() ) + return true; + return false; +} -}; // namespace std +bool type_info::is_subclass() const +{ + if( typeid(*this) == typeid(::__cxxabiv1::__si_class_type_info) ) + return true; + if( typeid(*this) == typeid(::__cxxabiv1::__vmi_class_type_info) ) + return true; + return false; +} + +// Acess-defined +bool type_info::__is_child(const type_info &poss_child, size_t &offset) const +{ + _SysDebug("typeids = this:%s , poss_child:%s", typeid(*this).name(), typeid(poss_child).name()); + + // Check #1: Child is same type + if( poss_child == *this ) { + offset = 0; + return true; + } + + // Check #2: This type must be a class + if( !this->is_class() ) { + return false; + } + // Check #3: Child class must be a subclass + if( !poss_child.is_subclass() ) { + return false; + } + + if( typeid(poss_child) == typeid(::__cxxabiv1::__si_class_type_info) ) { + auto &si_poss_child = reinterpret_cast<const ::__cxxabiv1::__si_class_type_info&>(poss_child); + // Single inheritance + _SysDebug("type_info::__is_child - Single inheritance"); + return __is_child( *si_poss_child.__base_type, offset ); + } + else if( typeid(poss_child) == typeid(::__cxxabiv1::__vmi_class_type_info) ) { + // Multiple inheritance + _SysDebug("TODO: type_info::__is_child - Multiple inheritance"); + abort(); + for(;;); + } + else { + // Oops! + _SysDebug("ERROR: type_info::__is_child - Reported subclass type, but not a subclass %s", + typeid(poss_child).name() + ); + abort(); + for(;;); + } +} + +// NOTE: Not defined by the C++ ABI, but is similar to one defined by GCC (__cxa_type_match +//bool __acess_type_match(std::typeinfo& possibly_derived, const std::typeinfo& base_type) +//{ +// return false; +//} + +}; // namespace std diff --git a/Usermode/Libraries/libc++_extras.so_src/Makefile b/Usermode/Libraries/libc++_extras.so_src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f129b612ce26cf65f9bcf6b4beebb564e83bb494 --- /dev/null +++ b/Usermode/Libraries/libc++_extras.so_src/Makefile @@ -0,0 +1,19 @@ +# Acess2 Basic C Library +# Makefile + +-include ../Makefile.cfg + +CPPFLAGS += +CXXFLAGS += -Wall -Werror -Wextra -std=c++11 +CFLAGS += -Wall -Werror -Wextra +ASFLAGS += +LDFLAGS += +LIBS += -lc++ + +include ../Makefile.tpl + +%.native: %.cpp + $(NCXX) $< -o $@ -Wall -std=c++11 -I include_exp/ + +TEST_cprintf.native: include_exp/cxxextras_printf + diff --git a/Usermode/Libraries/libc++_extras.so_src/TEST_cprintf.cpp b/Usermode/Libraries/libc++_extras.so_src/TEST_cprintf.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b77b00400ddc98412c10a9cfda299bd929c59e14 --- /dev/null +++ b/Usermode/Libraries/libc++_extras.so_src/TEST_cprintf.cpp @@ -0,0 +1,29 @@ +/* + */ +#include <cxxextras_printf> +#include <cstdio> +#include <stdexcept> + +void my_puts(const char *str, size_t len) +{ + fwrite(str, 1, len, stdout); +} + +#define ASSERT_EXCEPTION(expr, Exception) do{bool _ok=false; try { expr; } catch(const Exception& e){_ok=true;}if(!_ok)throw ::std::runtime_error("Didn't throw "#Exception);}while(0) + +int main() +{ + printf("Success\n"); + cprintf(my_puts, "%s %i %+#-010x\n", "hello_world", 1337, 0x1234565); + + //printf("Too Few\n"); + //ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%s %i %+#-010x\n"), ::cxxextras::cprintf_toofewargs ); + //printf("Too Many\n"); + //ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%s\n", "tst", 12345), ::cxxextras::cprintf_toomanyargs ); + // + //printf("Bad Format\n"); + //ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%-\n"), ::cxxextras::cprintf_badformat ); + + return 0; +} + diff --git a/Usermode/Libraries/libc++_extras.so_src/include_exp/cxxextras_printf b/Usermode/Libraries/libc++_extras.so_src/include_exp/cxxextras_printf new file mode 100644 index 0000000000000000000000000000000000000000..7d05e21938356c9757fdc7b02c5085580d878202 --- /dev/null +++ b/Usermode/Libraries/libc++_extras.so_src/include_exp/cxxextras_printf @@ -0,0 +1,473 @@ +/* + */ +#ifndef _LIBCXXEXTRAS_PRINTF_ +#define _LIBCXXEXTRAS_PRINTF_ + +#include <cstddef> +#include <cstdlib> +#include <cstdio> +#include <functional> + +namespace cxxextras { + +class cprintf_toomanyargs: + public ::std::exception +{ +}; +class cprintf_toofewargs: + public ::std::exception +{ +}; +class cprintf_badformat: + public ::std::exception +{ + const char *m_reason; +public: + cprintf_badformat(const char *reason): + m_reason(reason) + { + } + const char* what() const noexcept override { + return m_reason; + } +}; + +namespace _bits { + +enum e_cprintf_type +{ + TYPE_AUTO, + TYPE_BOOLEAN, + TYPE_BINARY, + TYPE_OCT, + TYPE_INT, + TYPE_INTU, + TYPE_INTS, + TYPE_HEXLC, + TYPE_HEXUC, + TYPE_STRING, +}; + +struct PrintfFlags +{ + unsigned int width; + unsigned int precision; + unsigned int flags; + + struct Left {}; + constexpr PrintfFlags(PrintfFlags x, Left _): width(x.width), precision(x.precision), flags(x.flags | 1) {} + struct Sign {}; + constexpr PrintfFlags(PrintfFlags x, Sign _): width(x.width), precision(x.precision), flags(x.flags | 2) {} + struct Space {}; + constexpr PrintfFlags(PrintfFlags x, Space _): width(x.width), precision(x.precision), flags(x.flags | 4) {} + struct Alt {}; + constexpr PrintfFlags(PrintfFlags x, Alt _): width(x.width), precision(x.precision), flags(x.flags | 8) {} + struct Zero {}; + constexpr PrintfFlags(PrintfFlags x, Zero _): width(x.width), precision(x.precision), flags(x.flags | 16) {} + + struct ArgWidth {}; + constexpr PrintfFlags(PrintfFlags x, ArgWidth _, unsigned int v): width(v), precision(x.precision), flags(x.flags) {} + struct ArgPrec {}; + constexpr PrintfFlags(PrintfFlags x, ArgPrec _, unsigned int v): width(x.width), precision(v), flags(x.flags) {} + + struct FAuto {}; + constexpr PrintfFlags(PrintfFlags x, FAuto _): width(x.width), precision(x.precision), flags(x.flags | 0x000) {} + struct FString {}; + constexpr PrintfFlags(PrintfFlags x, FString _): width(x.width), precision(x.precision), flags(x.flags | 0x100) {} + struct FBool {}; + constexpr PrintfFlags(PrintfFlags x, FBool _): width(x.width), precision(x.precision), flags(x.flags | 0x200) {} + struct FBinary {}; + constexpr PrintfFlags(PrintfFlags x, FBinary _): width(x.width), precision(x.precision), flags(x.flags | 0x300) {} + struct FOct {}; + constexpr PrintfFlags(PrintfFlags x, FOct _): width(x.width), precision(x.precision), flags(x.flags | 0x400) {} + struct FUDec {}; + constexpr PrintfFlags(PrintfFlags x, FUDec _): width(x.width), precision(x.precision), flags(x.flags | 0x500) {} + struct FSDec {}; + constexpr PrintfFlags(PrintfFlags x, FSDec _): width(x.width), precision(x.precision), flags(x.flags | 0x600) {} + struct FHexL {}; + constexpr PrintfFlags(PrintfFlags x, FHexL _): width(x.width), precision(x.precision), flags(x.flags | 0x700) {} + struct FHexU {}; + constexpr PrintfFlags(PrintfFlags x, FHexU _): width(x.width), precision(x.precision), flags(x.flags | 0x800) {} + + constexpr PrintfFlags(): + width(0), precision(0), flags(0) + { + } +}; +struct s_cprintf_fmt +{ + bool isValid = false; + unsigned int precision = 0; + unsigned int minLength = 0; + bool padLeft = false; + bool showSign = false; + bool showSpace = false; + bool altFormat = false; + bool padZero = false; + enum e_cprintf_type type; +}; +; + +constexpr bool isdigit_s(const char ch) { + return '0' <= ch && ch <= '9'; +} +constexpr unsigned todigit(const char ch) { + return ch - '0'; +} + + +}; // namespace _bits + +typedef ::std::function<void(const char*,size_t)> cprintf_cb; +template <typename Arg> size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags &fmt, Arg arg); +template <typename Arg> constexpr bool cprintf_val_chk(const _bits::PrintfFlags fmt, Arg arg); + +constexpr bool cprintf_val_chk(const _bits::PrintfFlags fmt, const char* arg) { + return true; +} +size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, const char* arg) { + unsigned int len; + for(len = 0; arg[len]; len ++) + ; + puts(arg, len); + return len; +} +constexpr bool cprintf_val_chk(const _bits::PrintfFlags& fmt, int arg) { + return true; +} +size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, int arg) { + size_t len = ::std::snprintf(nullptr, 0, "%i", arg); + char buf[len+1]; + ::std::snprintf(buf, len+1, "%i", arg); + puts(buf, len); + return len; +} +constexpr bool cprintf_val_chk(const _bits::PrintfFlags& fmt, unsigned int arg) { + return true; +} +size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, unsigned int arg) { + size_t len = ::std::snprintf(nullptr, 0, "%u", arg); + char buf[len+1]; + ::std::snprintf(buf, len+1, "%u", arg); + puts(buf, len); + return len; +} + +namespace _bits +{ +namespace _printf +{ + template <unsigned N> + class _str + { + const char m_buf[N]; + unsigned m_ofs; + public: + constexpr _str(const char buf[N]): + m_buf(buf), + m_ofs(0) + { + } + constexpr _str(const char buf[N], unsigned ofs): + m_buf(buf), + m_ofs(ofs) + { + } + constexpr _str<N> operator+(const unsigned o) { + return _str(m_buf, m_ofs+o); + } + constexpr char operator*() { + return m_buf[m_ofs]; + } + }; + + template <typename... Args> + constexpr bool val(const char* fmt, Args... args); + + template <typename Fmt> + constexpr bool val_fmt_done(const char * fmt, PrintfFlags item, Fmt fmtcode) + { + return false ? false : throw "Too few arguments"; + } + template <typename Fmt, typename Arg, typename... Args> + constexpr bool val_fmt_done(const char* fmt, PrintfFlags item, Fmt fmtcode, Arg arg, Args... args) + { + return cprintf_val_chk(item, arg) && val(fmt+1, args...); + } + // --- Format code + template <typename ...Args> + constexpr bool val_fmt_fmt(const char * fmt, PrintfFlags item, Args... args) + { + return *fmt == '\0' ? throw "ERROR: NUL byte in format specifier" + : *fmt == '?' ? val_fmt_done(fmt, item, PrintfFlags::FAuto(), args...) + : *fmt == 's' ? val_fmt_done(fmt, item, PrintfFlags::FString(),args...) + : *fmt == 'B' ? val_fmt_done(fmt, item, PrintfFlags::FBool(), args...) + : *fmt == 'b' ? val_fmt_done(fmt, item, PrintfFlags::FBinary(),args...) + : *fmt == 'o' ? val_fmt_done(fmt, item, PrintfFlags::FOct(), args...) + : *fmt == 'i' ? val_fmt_done(fmt, item, PrintfFlags::FSDec(), args...) + : *fmt == 'u' ? val_fmt_done(fmt, item, PrintfFlags::FUDec(), args...) + : *fmt == 'x' ? val_fmt_done(fmt, item, PrintfFlags::FHexL(), args...) + : *fmt == 'X' ? val_fmt_done(fmt, item, PrintfFlags::FHexU(), args...) + : throw cprintf_badformat("Unknown character in format string"); + } + // --- Size modifier (not implemented, not needed?) + template <typename ...Args> + constexpr bool val_fmt_size(const char * fmt, PrintfFlags item, Args... args) + { + // TODO: Size characters? + return val_fmt_fmt(fmt, item, args...); + } + // --- Precision + template <typename ...Args> + constexpr bool val_fmt_prec_val(const char * fmt, unsigned int value, PrintfFlags item, Args... args) + { + return _bits::isdigit_s(*fmt) ? val_fmt_prec_val(fmt+1, value*10+_bits::todigit(*fmt), item, args...) + : val_fmt_size(fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), value), args...); + } + template <typename ...Args> + constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item, unsigned int size, Args... args) + { + return val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), size), args...); + } + template <typename Arg, typename ...Args> + constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item, Arg size, Args... args) + { + //static_assert(false, "Invalid type for precision modifier, must be 'unsigned int'"); + return false ? false : throw "Invalid type for precision modifier, must be 'unsigned int'"; + } + constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item) + { + //static_assert(false, "Too few arguments when getting precision modifier"); + return false ? false : throw "Too few arguments when getting precision modifier"; + } + template <typename ...Args> + constexpr bool val_fmt_prec(const char * fmt, PrintfFlags item, Args... args) + { + return _bits::isdigit_s(*fmt) ? val_fmt_prec_val(fmt+1, _bits::todigit(*fmt), item, args...) + : *fmt == '*' ? val_fmt_prec_arg(fmt+1, item, args...) + : val_fmt_size(fmt, item, args...); + } + template <typename ...Args> + constexpr bool val_fmt_prec_opt(const char * fmt, PrintfFlags item, Args... args) + { + return *fmt == '.' ? val_fmt_prec(fmt+1, item, args...) + : val_fmt_size(fmt, item, args...); + } + // --- Field Width --- + template <typename ...Args> + constexpr bool val_fmt_width_val(const char* fmt, unsigned int size, PrintfFlags item, Args... args) + { + return _bits::isdigit_s(*fmt) ? val_fmt_width_val(fmt+1, size*10+_bits::todigit(*fmt), item, args...) + : val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...); + } + template <typename ...Args> + constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item, unsigned int size, Args... args) + { + return val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...); + } + template <typename Arg, typename ...Args> + constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item, Arg size, Args... args) + { + //static_assert(false, "Invalid type for width modifier, must be 'unsigned int'"); + return false ? false : throw "Invalid type for width modifier, must be 'unsigned int'"; + } + constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item) + { + //static_assert(false, "Too few arguments when reading width for width modifier"); + return false ? false : throw "Too few arguments when reading width for width modifier"; + } + template <typename ...Args> + constexpr bool val_fmt_width(const char * fmt, PrintfFlags item, Args... args) + { + return _bits::isdigit_s(*fmt) ? val_fmt_width_val(fmt+1, _bits::todigit(*fmt), item, args...) + : *fmt == '*' ? val_fmt_width_arg(fmt+1, item, args...) + : val_fmt_prec_opt(fmt, item, args...); + } + // --- Flags + template <typename ...Args> + constexpr bool val_fmt_flags(const char * fmt, PrintfFlags item, Args... args) + { + return + *fmt == '-' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Left()) , args...) + : *fmt == '+' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Sign()) , args...) + : *fmt == ' ' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Space()), args...) + : *fmt == '#' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Alt()) , args...) + : *fmt == '0' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Zero()) , args...) + : val_fmt_width(fmt, item, args...); + } + // --- Literal '%' + template <typename ...Args> + constexpr bool val_fmt_start(const char* fmt, Args... args) + { + return *fmt == '%' ? val(fmt+1, args...) : val_fmt_flags(fmt, PrintfFlags(), args...); + } + template <typename... Args> + constexpr bool val(const char* fmt, Args... args) + { + return *fmt == '\0' ? true + : *fmt == '%' ? val_fmt_start(fmt+1, args...) + : val(fmt+1, args...); + } + + size_t run(cprintf_cb puts, const char *fmt); + template <typename... Args> size_t run(cprintf_cb puts, const char * fmt, Args... args); + + // --- Print formatted value + template <typename Fmt> + constexpr size_t run_fmt_done(cprintf_cb puts, const char * fmt, PrintfFlags item, Fmt fmtcode) + { + throw cprintf_toofewargs(); + } + template <typename Fmt, typename Arg, typename... Args> + size_t run_fmt_done(cprintf_cb puts, const char * fmt, PrintfFlags item, Fmt fmtcode, Arg val, Args... args) + { + if( !puts ) + return run(puts, fmt+1, args...); + else + return ::cxxextras::cprintf_val(puts, PrintfFlags(item, fmtcode), val) + run(puts, fmt+1, args...); + } + // --- Format code + template <typename ...Args> + size_t run_fmt_fmt(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args) + { + return *fmt == '\0' ? throw "ERROR: NUL byte in format specifier" + : *fmt == '?' ? run_fmt_done(puts, fmt, item, PrintfFlags::FAuto(), args...) + : *fmt == 's' ? run_fmt_done(puts, fmt, item, PrintfFlags::FString(),args...) + : *fmt == 'B' ? run_fmt_done(puts, fmt, item, PrintfFlags::FBool(), args...) + : *fmt == 'b' ? run_fmt_done(puts, fmt, item, PrintfFlags::FBinary(),args...) + : *fmt == 'o' ? run_fmt_done(puts, fmt, item, PrintfFlags::FOct(), args...) + : *fmt == 'i' ? run_fmt_done(puts, fmt, item, PrintfFlags::FSDec(), args...) + : *fmt == 'u' ? run_fmt_done(puts, fmt, item, PrintfFlags::FUDec(), args...) + : *fmt == 'x' ? run_fmt_done(puts, fmt, item, PrintfFlags::FHexL(), args...) + : *fmt == 'X' ? run_fmt_done(puts, fmt, item, PrintfFlags::FHexU(), args...) + : throw cprintf_badformat("Unknown character in format string"); + } + // --- Size modifier (not implemented, not needed?) + template <typename ...Args> + size_t run_fmt_size(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args) + { + // TODO: Size characters? + return run_fmt_fmt(puts, fmt, item, args...); + } + // --- Precision + template <typename ...Args> + size_t run_fmt_prec_val(cprintf_cb puts, const char * fmt, unsigned int val, PrintfFlags item, Args... args) + { + return _bits::isdigit_s(*fmt) ? run_fmt_prec_val(puts, fmt+1, val*10+_bits::todigit(*fmt), item, args...) + : run_fmt_size(puts, fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), val), args...); + } + template <typename ...Args> + size_t run_fmt_prec_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, unsigned int size, Args... args) + { + return run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), size), args...); + } + template <typename Arg, typename ...Args> + size_t run_fmt_prec_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, Arg size, Args... args) + { + throw cprintf_badformat("Invalid type for printf precision modifier"); + } + size_t run_fmt_prec_arg(cprintf_cb puts, const char *fmt, PrintfFlags item) + { + throw cprintf_toofewargs(); + } + template <typename ...Args> + size_t run_fmt_prec(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args) + { + return _bits::isdigit_s(*fmt) ? run_fmt_prec_val(puts, fmt+1, _bits::todigit(*fmt), item, args...) + : *fmt == '*' ? run_fmt_prec_arg(puts, fmt+1, item, args...) + : run_fmt_size(puts, fmt, item, args...); + } + template <typename ...Args> + size_t run_fmt_prec_opt(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args) + { + return *fmt == '.' ? run_fmt_prec(puts, fmt+1, item, args...) + : run_fmt_size(puts, fmt, item, args...); + } + // --- Field Width --- + template <typename ...Args> + size_t run_fmt_width_val(cprintf_cb puts, const char* fmt, unsigned int val, PrintfFlags item, Args... args) + { + return _bits::isdigit_s(*fmt) ? run_fmt_width_val(puts, fmt+1, val*10+_bits::todigit(*fmt), item, args...) + : run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), val), args...); + } + template <typename ...Args> + size_t run_fmt_width_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, unsigned int size, Args... args) + { + return run_fmt_prec_opt(puts, fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...); + } + template <typename Arg, typename ...Args> + size_t run_fmt_width_arg(cprintf_cb puts, const char *fmt, PrintfFlags item, Arg size, Args... args) + { + throw cprintf_badformat("Invalid type for printf width modifier"); + } + size_t run_fmt_width_arg(cprintf_cb puts, const char *fmt, PrintfFlags item) + { + throw cprintf_toofewargs(); + } + template <typename ...Args> + size_t run_fmt_width(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args) + { + return _bits::isdigit_s(*fmt) ? run_fmt_width_val(puts, fmt+1, _bits::todigit(*fmt), item, args...) + : *fmt == '*' ? run_fmt_width_arg(puts, fmt+1, item, args...) + : run_fmt_prec_opt(puts, fmt, item, args...); + } + // --- Flags + template <typename ...Args> + size_t run_fmt_flags(cprintf_cb puts, const char * fmt, PrintfFlags item, Args... args) + { + return + *fmt == '-' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Left()) , args...) + : *fmt == '+' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Sign()) , args...) + : *fmt == ' ' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Space()), args...) + : *fmt == '#' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Alt()) , args...) + : *fmt == '0' ? run_fmt_flags(puts, fmt+1, PrintfFlags(item, PrintfFlags::Zero()) , args...) + : run_fmt_width(puts, fmt, item, args...); + } + // --- Literal '%' + template <typename ...Args> + size_t run_fmt_start(cprintf_cb puts, const char * fmt, Args... args) + { + return *fmt == '%' + ? (puts("%", 1), 1 + run(puts, fmt+1, args...)) + : run_fmt_flags(puts, fmt, PrintfFlags(), args...); + } + // --- Root + template <typename... Args> + size_t run(cprintf_cb puts, const char * fmt, Args... args) + { + int ofs; + for( ofs = 0; fmt[ofs] != '\0' && fmt[ofs] != '%'; ofs ++ ) + ; + if( fmt[ofs] != '%' ) + throw cprintf_toomanyargs(); + if(ofs > 0 && puts) puts(fmt, ofs); + return ofs + run_fmt_start(puts, fmt+ofs+1, args...); + } + size_t run(cprintf_cb puts, const char *fmt) + { + int ofs; + for( ofs = 0; fmt[ofs] != '\0' && fmt[ofs] != '%'; ofs ++ ) + ; + if(ofs > 0 && puts) puts(fmt, ofs); + return ofs + (fmt[ofs] == '%' ? run_fmt_start(puts, fmt+ofs+1) : 0); + } + +} + +}; // namespace _bits + +#define cprintf(puts, fmt, ...) static_assert(::cxxextras::_bits::_printf::val(fmt, __VA_ARGS__),"");::cxxextras::_bits::_printf::run(puts, fmt, __VA_ARGS__) + +//template <typename ... Args> +//size_t cprintf(cprintf_cb puts, const char *fmt, Args... args) +//{ +// _bits::_printf::run(nullptr, fmt, args...); +// return _bits::_printf::run(puts, fmt, args...); +//} + +}; + +#endif + +// vim: ft=cpp + diff --git a/Usermode/Libraries/libc.so_src/Makefile b/Usermode/Libraries/libc.so_src/Makefile index c615b6e96ed3907caeda14f0c174ec7764bcbfb0..64749b3b8c03eb5af66bb364fc605fc290f047e4 100644 --- a/Usermode/Libraries/libc.so_src/Makefile +++ b/Usermode/Libraries/libc.so_src/Makefile @@ -4,9 +4,11 @@ -include ../Makefile.cfg CPPFLAGS += -CFLAGS += -Wall -Werror -Wextra +CFLAGS += -nostdlib -Wall -Werror -Wextra ASFLAGS += -LDFLAGS += -Map map.txt +LDFLAGS += -nostdlib +PRELINK := $(CRTI) $(CRTBEGINS) $(CRT0S) +LIBS += $(LIBGCC_PATH) $(CRTENDS) $(CRTN) INCFILES := stdio.h stdlib.h @@ -19,7 +21,7 @@ OBJ += arch/$(ARCHDIR).ao DEPFILES := $(OBJ:%.o=%.d) BIN = libc.so ifeq ($(ARCHDIR),native) - OBJ := $(filter-out heap.o,$(OBJ)) + OBJ := $(filter-out heap.o,$(OBJ)) heap_native.o #LDFLAGS += -l c BIN = libc_acess.so endif @@ -27,8 +29,8 @@ endif include ../Makefile.tpl EXP_%.txt: TEST_%.native - ./$< > $@ - rm $< + @./$< > $@ + @rm $< EXP_strtoi.txt: echo -n "" > $@ diff --git a/Usermode/Libraries/libc.so_src/TEST_string.c b/Usermode/Libraries/libc.so_src/TEST_string.c new file mode 100644 index 0000000000000000000000000000000000000000..4ecca307d684819ece57ff7b12de56fe12834f64 --- /dev/null +++ b/Usermode/Libraries/libc.so_src/TEST_string.c @@ -0,0 +1,51 @@ +/* + */ +#include <stdio.h> +#include <string.h> + +#define ASSERT(cnd) printf("ASSERT: "#cnd" == %s\n", ((cnd) ? "pass" : "FAIL")) + +int main() +{ + ASSERT(strcmp("hello", "world") < 0); + ASSERT(strcmp("hello", "hello") == 0); + ASSERT(strcmp("wello", "hello") > 0); + ASSERT(strcmp("\xff", "\1") > 0); + ASSERT(strcmp("\1", "\xff") < 0); + ASSERT(strcmp("Hello", "hello") < 0); + + ASSERT(strncmp("hello world", "hello", 5) == 0); + + ASSERT(strcasecmp("hello", "world") < 0); + ASSERT(strcasecmp("hello", "hello") == 0); + ASSERT(strcasecmp("wello", "hello") > 0); + ASSERT(strcasecmp("\xff", "\1") > 0); + ASSERT(strcasecmp("\1", "\xff") < 0); + ASSERT(strcasecmp("Hello", "hello") == 0); + ASSERT(strcasecmp("Hello", "Hello") == 0); + ASSERT(strcasecmp("hellO", "Hello") == 0); + + char buf[13]; + memset(buf, 127, sizeof(buf)); + ASSERT(buf[0] == 127); ASSERT(buf[4] == 127); + strncpy(buf, "hello", 4); + ASSERT(buf[3] == 'l'); ASSERT(buf[4] == 127); + strncpy(buf, "hello", 8); + ASSERT(buf[4] == 'o'); ASSERT(buf[5] == '\0'); ASSERT(buf[7] == '\0'); ASSERT(buf[8] == 127); + + memset(buf, 0, 13); + ASSERT(buf[0] == 0); ASSERT(buf[12] == 0); + + ASSERT(memchr("\xffhello", 'x', 6) == NULL); + + const char *teststr_foo = "foo"; + ASSERT(strchr(teststr_foo, 'f') == teststr_foo+0); + ASSERT(strchr(teststr_foo, 'o') == teststr_foo+1); + ASSERT(strchr(teststr_foo, '\0') == teststr_foo+3); + ASSERT(strchr(teststr_foo, 'X') == NULL); + ASSERT(strrchr(teststr_foo, 'f') == teststr_foo+0); + ASSERT(strrchr(teststr_foo, 'o') == teststr_foo+2); + ASSERT(strrchr(teststr_foo, '\0') == teststr_foo+3); + ASSERT(strrchr(teststr_foo, 'X') == NULL); +} + diff --git a/Usermode/Libraries/libc.so_src/TEST_strtoi.c b/Usermode/Libraries/libc.so_src/TEST_strtoi.c index 6d89224eaa83b92c9231a8b57d4d8a69657ea106..e06580872615fe727e3548c7cd1971a455791bb4 100644 --- a/Usermode/Libraries/libc.so_src/TEST_strtoi.c +++ b/Usermode/Libraries/libc.so_src/TEST_strtoi.c @@ -7,15 +7,71 @@ */ #include <stdio.h> #include <stdlib.h> +#include <errno.h> +#include <limits.h> +#include <string.h> // strerror -#define TST(t, class, base, val, exp, fmt) do {\ - t ret = strto##class(#val, NULL, base); \ +#define STR_(v) #v +#define STR(v) STR_(v) +#define TST(t, class, base, val, exp, fmt, ofs, exp_errno) do {\ + const char *in = val;\ + char *end;\ + errno = 0;\ + t ret = strto##class(in, &end, base); \ if( ret != exp ) \ - printf("FAIL strto"#class"('"#val"') != "#val" (act 0x"fmt")\n", ret);\ + fprintf(stderr, "FAIL strto"#class"('%s') != "#exp" (act "fmt")\n", in, ret);\ + if( end != in+ofs ) \ + fprintf(stderr, "FAIL strto"#class"('%s') returned wrong end: %p (+%zi) instead of %p (+%zi)\n",\ + in,end,end-in,in+ofs,(size_t)ofs);\ + if( exp_errno != errno ) \ + fprintf(stderr, "FAIL strto"#class"('%s') returned wrong errno, exp '%s', got '%s'\n",\ + in, strerror(exp_errno), strerror(errno));\ }while(0) +#define PRIMEBUF(fmt, val) buf_len = snprintf(buf, sizeof(buf), fmt, val) + int main(int argc, char *argv[]) { - TST(unsigned long, ul, 0, 0x10ec, 0x10ec, "%lx"); - TST(unsigned long long, ull, 0, 0xffeed10ec, 0xffeed10ec, "%llx"); + char buf[64]; + size_t buf_len; + + // Success cases + TST(unsigned long, ul, 0, "0x10ec", 0x10ec, "%lx", 2+4, 0); + TST(unsigned long long, ull, 0, "0xffeed10ec", 0xffeed10ec, "%llx", 2+9, 0); + TST(unsigned long long, ull, 0, "01234567", 01234567, "%llo", 8, 0); + TST(unsigned long long, ull, 0, "1234567", 1234567, "%lld", 7, 0); + TST(long long, ll, 0, "-1", -1, "%lld", 2, 0); // -1 + TST(long long, ll, 0, "100113", 100113, "%lld", strlen(in), 0); + TST(long long, ll, 0, "0x101", 0x101, "0x%llx", strlen(in), 0); + + // Invalid strings + TST(unsigned long long, ull, 0, "0x", 0, "%llx", 1, 0); // Single 0 + TST(unsigned long long, ull, 0, "0xg", 0, "%llx", 1, 0); // Single 0 + TST(unsigned long long, ull, 0, "-a", 0, "%llx", 0, 0); // Nothing + TST(long long, ll, 0, "-a", 0, "%lld", 0, 0); // Nothing + TST(long long, ll, 0, "-1aaatg", -1, "%lld", 2, 0); // -1 (with traling junk) + TST(long long, ll, 0, "-+1aaatg", 0, "%lld", 0, 0); // Nothing + TST(long long, ll, 0, "- 1", 0, "%lld", 0, 0); // Nothing + TST(long long, ll, 0, "01278 1", 0127, "%lld", 4, 0); // 0127 with junk + + // Range edges + PRIMEBUF("0x%llx", ULLONG_MAX); + TST(unsigned long long, ull, 0, buf, ULLONG_MAX, "0x%llx", buf_len, 0); + PRIMEBUF("%llu", ULLONG_MAX); + TST(unsigned long long, ull, 0, buf, ULLONG_MAX, "%llu", buf_len, 0); + PRIMEBUF("-%llu", (long long)LONG_MAX); + TST(long, l, 0, buf, -LONG_MAX, "%ld", buf_len, 0); + + // Out of range + // - When the range limit is hit, valid characters should still be consumed (just not used) + TST(unsigned long long, ull, 0, "0x10000FFFF0000FFFF", ULLONG_MAX, "%llx", strlen(in), ERANGE); + TST(unsigned long, ul, 0, "0x10000FFFF0000FFFF", ULONG_MAX, "%lx", strlen(in), ERANGE); + TST(long, l, 0, "0x10000FFFF0000FFFF", LONG_MAX, "%ld", strlen(in), ERANGE); + TST(long, l, 0, "-0x10000FFFF0000FFFF", LONG_MIN, "%ld", strlen(in), ERANGE); + if( LONG_MIN < -LONG_MAX ) + { + // Ensure that if -LONG_MIN is greater than LONG_MAX, that converting it leaves a range error + PRIMEBUF("%ld", LONG_MIN); + TST(long, l, 0, buf+1, LONG_MAX, "%ld", buf_len-1, ERANGE); + } } diff --git a/Usermode/Libraries/libc.so_src/ctype.c b/Usermode/Libraries/libc.so_src/ctype.c index d5a5e97ae601d8f0009813e9357cd4f30a2a407b..18a199c647621270b9e8eabc886479f4ee5d43df 100644 --- a/Usermode/Libraries/libc.so_src/ctype.c +++ b/Usermode/Libraries/libc.so_src/ctype.c @@ -22,23 +22,40 @@ int isalnum(int ch) { return isalpha(ch) || isdigit(ch); } -int toupper(int ch) { - if('a'<=ch && ch <='z') - return ch - 'a' + 'A'; - return ch; +int isxdigit(int ch) { + if('0'<=ch&&ch<='9') return 1; + if('a'<=ch&&ch<='f') return 1; + if('F'<=ch&&ch<='F') return 1; + return 0; } -int tolower(int ch) { - if('A'<=ch && ch <='Z') - return ch - 'A' + 'a'; - return ch; + +int isupper(int ch) { + if('A'<=ch && ch <='Z') return 1; + return 0; +} + +int islower(int ch) { + if('a'<=ch && ch <='z') return 1; + return 0; +} + +int ispunct(int ch) { + if( isprint(ch) && !isspace(ch) && !isalnum(ch) ) + return 1; + return 0; } int isprint(int ch ) { - if( ch < ' ' ) return 0; - if( ch > 'z' ) return 0; + if( ' ' <= ch && ch <= 'z' ) return 1; return 1; } +int isgraph(int ch) { + // Anything but space + if( ' ' < ch && ch <= 'z' ) return 1; + return 0; +} + int isspace(int ch) { if(ch == ' ') return 1; if(ch == '\t') return 1; @@ -47,12 +64,17 @@ int isspace(int ch) { return 0; } -int isxdigit(int ch) { - if('0'<=ch&&ch<='9') return 1; - if('a'<=ch&&ch<='f') return 1; - if('F'<=ch&&ch<='F') return 1; - return 0; +int toupper(int ch) { + if('a'<=ch && ch <='z') + return ch - 'a' + 'A'; + return ch; } +int tolower(int ch) { + if('A'<=ch && ch <='Z') + return ch - 'A' + 'a'; + return ch; +} + // C99 int isblank(int ch) { diff --git a/Usermode/Libraries/libc.so_src/errno.c b/Usermode/Libraries/libc.so_src/errno.c index 6f9545749e8f246715e0e0e8a48da970c0b3e143..295183c4310c578594bc3809067432e7618d3f7f 100644 --- a/Usermode/Libraries/libc.so_src/errno.c +++ b/Usermode/Libraries/libc.so_src/errno.c @@ -21,13 +21,16 @@ EXPORT char *strerror(int errnum) switch((enum libc_eErrorNumbers)errnum) { case EOK: return "Success"; + case ERANGE: return "Value out of range"; + case EDOM: return "Value out of domain"; + case EILSEQ: return "Illegal character sequence"; + case ENOSYS: return "Invalid instruction/syscall"; case EINVAL: return "Bad argument(s)"; case EBADF: return "Invalid file"; case ENOMEM: return "No free memory"; case EACCES: return "Not permitted"; case EBUSY: return "Resource is busy"; - case ERANGE: return "Value out of range"; case ENOTFOUND: return "Item not found"; case EROFS: return "Read only filesystem"; case ENOTIMPL: return "Not implimented"; @@ -46,8 +49,15 @@ EXPORT char *strerror(int errnum) case ENOTTY: return "Not a TTY"; case EAGAIN: return "Try again"; case EFBIG: return "File too big"; + case E2BIG: return "Value too big"; case EALREADY: return "Operation was no-op"; + case ENOSPC: return "No space left on the device"; + case EAFNOSUPPORT: return "Address family not supported"; + case EADDRINUSE: return "Address already in use"; + case ETIMEDOUT: return "Operation timed out"; + case EOPNOTSUPP: return "Operation not supported on socket"; + case EINTERNAL: return "Internal error"; } _SysDebug("strerror: errnum=%i unk", errnum); diff --git a/Usermode/Libraries/libc.so_src/heap.c b/Usermode/Libraries/libc.so_src/heap.c index d6d9a40361e134db10ed997762f44bc2d123563b..71e3d6dc0c7cb754ed015aa66fc24d0bc0d7a568 100644 --- a/Usermode/Libraries/libc.so_src/heap.c +++ b/Usermode/Libraries/libc.so_src/heap.c @@ -8,6 +8,8 @@ #include <acess/sys.h> #include <stdlib.h> #include <string.h> +#include <assert.h> +#include <stdbool.h> #include "lib.h" #if 0 @@ -71,6 +73,7 @@ static const heap_head _heap_zero_allocation; EXPORT void *malloc(size_t bytes); void *_malloc(size_t bytes, void *owner); EXPORT void *calloc(size_t bytes, size_t count); +bool _libc_free(void *mem); EXPORT void free(void *mem); EXPORT void *realloc(void *mem, size_t bytes); EXPORT void *sbrk(int increment); @@ -221,26 +224,31 @@ EXPORT void *calloc(size_t __nmemb, size_t __size) \param mem Pointer - Memory to free */ EXPORT void free(void *mem) +{ + if( !_libc_free(mem) ) { + Heap_Validate(1); + exit(0); + } +} + +// Exported for libc++ +EXPORT bool _libc_free(void *mem) { heap_head *head = (heap_head*)mem - 1; // Free of NULL or the zero allocation does nothing if(!mem || mem == _heap_zero_allocation.data) - return ; + return true; // Sanity check the head address if(head->magic != MAGIC) { if( head->magic != MAGIC_FREE ) { - _SysDebug("Double free of %p", mem); - Heap_Validate(1); - exit(0); + _SysDebug("Double free of %p by %p", mem, __builtin_return_address(0)); } else { - _SysDebug("Free of invalid pointer %p", mem); - Heap_Validate(1); - exit(0); + _SysDebug("Free of invalid pointer %p by ", mem, __builtin_return_address(0)); } - return; + return false; } head->magic = MAGIC_FREE; @@ -265,8 +273,9 @@ EXPORT void free(void *mem) heap_foot *prevFoot = PREV_FOOT(head); if( prevFoot->magic != MAGIC ) { + _SysDebug("Heap corruption, previous foot magic invalid"); Heap_Validate(1); - exit(1); + return false; } heap_head *prevHead = prevFoot->header; @@ -281,6 +290,8 @@ EXPORT void free(void *mem) prevFoot->header = NULL; } } + + return true; } /** @@ -308,7 +319,8 @@ EXPORT void *realloc(void *oldPos, size_t bytes) // Check for free space after the block heap_head *nexthead = NEXT_HEAD(head); - if( nexthead && nexthead->magic == MAGIC_FREE && head->size + nexthead->size >= reqd_size ) + assert( nexthead <= _heap_end ); + if( nexthead != _heap_end && nexthead->magic == MAGIC_FREE && head->size + nexthead->size >= reqd_size ) { // Split next block if( head->size + nexthead->size > reqd_size ) @@ -337,12 +349,12 @@ EXPORT void *realloc(void *oldPos, size_t bytes) void *ret = _malloc(bytes, __builtin_return_address(0)); if(ret == NULL) return NULL; + heap_head *newhead = (heap_head*)ret - 1; - //Copy Old Data + // Copy Old Data + assert( head->size < newhead->size ); size_t copy_size = head->size-sizeof(heap_head)-sizeof(heap_foot); - if( copy_size > bytes ) - copy_size = bytes; - memcpy(ret, oldPos, bytes); + memcpy(ret, oldPos, copy_size); free(oldPos); //Return diff --git a/Usermode/Libraries/libc.so_src/heap_native.c b/Usermode/Libraries/libc.so_src/heap_native.c new file mode 100644 index 0000000000000000000000000000000000000000..0f4d9b3b66d2a2750733103b7f8d8cf0b11c41e6 --- /dev/null +++ b/Usermode/Libraries/libc.so_src/heap_native.c @@ -0,0 +1,8 @@ +#include <stdlib.h> +#include <stdbool.h> + +bool _libc_free(void *addr) +{ + free(addr); + return true; +} diff --git a/Usermode/Libraries/libc.so_src/include_exp/ctype.h b/Usermode/Libraries/libc.so_src/include_exp/ctype.h index 75e4ce88aa17139643da0ecb99ed6d7eb1123590..69067e87fa99e6ab6efea1daab987c5c05d04df2 100644 --- a/Usermode/Libraries/libc.so_src/include_exp/ctype.h +++ b/Usermode/Libraries/libc.so_src/include_exp/ctype.h @@ -14,21 +14,27 @@ extern "C" { extern int isalpha(int ch); extern int isdigit(int ch); - extern int isalnum(int ch); +extern int isxdigit(int ch); -extern int toupper(int ch); -extern int tolower(int ch); +extern int islower(int ch); +extern int isupper(int ch); +extern int ispunct(int ch); extern int isprint(int ch); +extern int isgraph(int ch); extern int isspace(int ch); -extern int isxdigit(int ch); +extern int iscntrl(int ch); // C99 extern int isblank(int ch); +// Conversions +extern int toupper(int ch); +extern int tolower(int ch); + #ifdef __cplusplus } #endif diff --git a/Usermode/Libraries/libc.so_src/include_exp/errno.enum.h b/Usermode/Libraries/libc.so_src/include_exp/errno.enum.h index f943654712f8e80a03b81c4663f90e3120727537..d7b105365e14bccf3c0614f22ad7206872c3c1ae 100755 --- a/Usermode/Libraries/libc.so_src/include_exp/errno.enum.h +++ b/Usermode/Libraries/libc.so_src/include_exp/errno.enum.h @@ -1,13 +1,16 @@ enum libc_eErrorNumbers { EOK, + EDOM, // (C99) Value out of domain + EILSEQ, // (C99) Illegal multi-byte sequence + ERANGE, // (C99) Value out of range + ENOSYS, // Invalid Instruction EINVAL, // Invalid Paramater EBADF, // Bad FD ENOMEM, // No free memory EACCES, // Not permitted EBUSY, // Resource is busy - ERANGE, // Value out of range ENOTFOUND, // Item not found EROFS, // Read only ENOTIMPL, // Not implemented @@ -27,11 +30,16 @@ enum libc_eErrorNumbers { EAGAIN, // Try again EALREADY, // Operation was a NOP + ENOSPC, // (POSIX) No space left on device EFBIG, // File too large + E2BIG, // Argument list too large // psockets EAFNOSUPPORT, + EADDRINUSE, // (POSIX.1) Specified addres is already in use + ETIMEDOUT, + EOPNOTSUPP, // (POSIX.1) Operation not supported on socket EINTERNAL // Internal Error }; diff --git a/Usermode/Libraries/libc.so_src/include_exp/inttypes.h b/Usermode/Libraries/libc.so_src/include_exp/inttypes.h index 0200aa6aa58691b2e009544204ef44eda564b4d4..05e6707016160ce05ac88f0689a77cb04b66ce82 100644 --- a/Usermode/Libraries/libc.so_src/include_exp/inttypes.h +++ b/Usermode/Libraries/libc.so_src/include_exp/inttypes.h @@ -11,18 +11,25 @@ #define _INTTYPES_H_ #include <stdint.h> +#include <limits.h> -#define PRId64 "lld" -#define PRIdLEAST64 "lld" -#define PRIdFAST64 "lld" +#if INT64_MAX == LONG_MAX +# define _PRI64 "l" +#else +# define _PRI64 "ll" +#endif + +#define PRId64 _PRI64"d" +#define PRIdLEAST64 _PRI64"d" +#define PRIdFAST64 _PRI64"d" #define PRIdMAX #define PRIdPTR -#define PRIi64 "lli" +#define PRIi64 _PRI64"i" #define PRIiLEAST64 #define PRIiFAST64 #define PRIiMAX #define PRIiPTR -#define PRIx64 "llx" +#define PRIx64 _PRI64"i" #endif diff --git a/Usermode/Libraries/libc.so_src/include_exp/stdio.h b/Usermode/Libraries/libc.so_src/include_exp/stdio.h index ed1fce584d1ce5bebcafc60f6af45dd3d661e526..b2cb8574368c11328f76a7bba7cdb4ebcf904941 100644 --- a/Usermode/Libraries/libc.so_src/include_exp/stdio.h +++ b/Usermode/Libraries/libc.so_src/include_exp/stdio.h @@ -94,7 +94,7 @@ extern FILE *open_memstream(char **bufferptr, size_t *lengthptr); extern FILE *fdopen(int fd, const char *modes); extern FILE *tmpfile(void); extern int fclose(FILE *fp); -extern void fflush(FILE *fp); +extern int fflush(FILE *fp); extern off_t ftell(FILE *fp); extern off_t ftello(FILE *fp); extern int fseek(FILE *fp, long int amt, int whence); diff --git a/Usermode/Libraries/libc.so_src/include_exp/stdlib.h b/Usermode/Libraries/libc.so_src/include_exp/stdlib.h index 07fc81f4c8d7756e978ac8c3574da9fe9e9b29ee..fa923eef6e7244cc3fe896d50852165e76605e0c 100644 --- a/Usermode/Libraries/libc.so_src/include_exp/stdlib.h +++ b/Usermode/Libraries/libc.so_src/include_exp/stdlib.h @@ -112,6 +112,8 @@ extern int rand_p(unsigned int *seedp); # define SEEK_END (-1) #endif +#define MB_CUR_MAX 5 // (C99) Max number of bytes in a single multibyte character (UTF8=5) + #ifdef __cplusplus } #endif diff --git a/Usermode/Libraries/libc.so_src/include_exp/string.h b/Usermode/Libraries/libc.so_src/include_exp/string.h index 7ef1bc7aef4e37847c0bc4a34f84d262cc9ab8bb..028ed27e5bbedcc4a3f2585abdb048a4326a5f06 100644 --- a/Usermode/Libraries/libc.so_src/include_exp/string.h +++ b/Usermode/Libraries/libc.so_src/include_exp/string.h @@ -29,6 +29,7 @@ extern char *strrchr(const char *str, int character); extern char *strstr(const char *str1, const char *str2); extern size_t strcspn(const char *haystack, const char *reject); extern size_t strspn(const char *haystack, const char *accept); +extern char *strpbrk(const char *haystack, const char *accept); extern char *strtok(char *str, const char *delim); extern char *strtok_r(char *str, const char *delim, char **saveptr); diff --git a/Usermode/Libraries/libc.so_src/signals.c b/Usermode/Libraries/libc.so_src/signals.c index 5e32fc8612ef88ac2ebcf903caac3448b1691164..532f09b732f57fe4ba9907218478b579df1a1301 100644 --- a/Usermode/Libraries/libc.so_src/signals.c +++ b/Usermode/Libraries/libc.so_src/signals.c @@ -41,6 +41,7 @@ int raise(int signal) void abort(void) { // raise(SIGABRT); + _SysDebug("abort() - %p", __builtin_return_address(0)); _exit(-1); } diff --git a/Usermode/Libraries/libc.so_src/stdio.c b/Usermode/Libraries/libc.so_src/stdio.c index 1bb90cd99221b512ca8d1cf38ff7fd0f2162e538..55fd52134750e57d62f5aeaa04d273a03f8fa54d 100644 --- a/Usermode/Libraries/libc.so_src/stdio.c +++ b/Usermode/Libraries/libc.so_src/stdio.c @@ -14,6 +14,9 @@ #define DEBUG_BUILD 0 +#define LOG_WARN(f,...) _SysDebug("WARN: %s: "f, __func__ ,## __VA_ARGS__) +#define LOG_NOTICE(f,...) _SysDebug("NOTE: %s: "f, __func__ ,## __VA_ARGS__) + // === CONSTANTS === #define _stdin 0 #define _stdout 1 @@ -27,9 +30,9 @@ struct sFILE *get_file_struct(); // === GLOBALS === struct sFILE _iob[STDIO_MAX_STREAMS]; // IO Buffer -struct sFILE *stdin; // Standard Input -struct sFILE *stdout; // Standard Output -struct sFILE *stderr; // Standard Error +struct sFILE *stdin = &_iob[0]; // Standard Input +struct sFILE *stdout = &_iob[1]; // Standard Output +struct sFILE *stderr = &_iob[2]; // Standard Error ///\note Initialised in SoMain static const int STDIN_BUFSIZ = 512; static const int STDOUT_BUFSIZ = 512; @@ -38,19 +41,16 @@ static const int STDOUT_BUFSIZ = 512; void _stdio_init(void) { // Init FileIO Pointers - stdin = &_iob[0]; stdin->FD = 0; stdin->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_READ|FILE_FLAG_LINEBUFFERED|FILE_FLAG_OURBUFFER; stdin->Buffer = malloc(STDIN_BUFSIZ); stdin->BufferSpace = STDIN_BUFSIZ; - stdout = &_iob[1]; stdout->FD = 1; stdout->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_WRITE|FILE_FLAG_LINEBUFFERED|FILE_FLAG_OURBUFFER; stdout->Buffer = malloc(STDOUT_BUFSIZ); stdout->BufferSpace = STDOUT_BUFSIZ; - stderr = &_iob[2]; stderr->FD = 2; stderr->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_WRITE; } @@ -374,22 +374,23 @@ int _fflush_int(FILE *fp) return ret; } -EXPORT void fflush(FILE *fp) +EXPORT int fflush(FILE *fp) { if( !fp || fp->FD == FD_NOTOPEN ) - return ; + return EBADF; // Nothing to do for memory files if( fp->FD == FD_MEMFILE ) - return ; + return 0; // Memory streams, update pointers if( fp->FD == FD_MEMSTREAM ) { *fp->BufPtr = fp->Buffer; *fp->LenPtr = fp->BufferPos; - return ; + return 0; } _fflush_int(fp); + return 0; } EXPORT void clearerr(FILE *fp) @@ -681,19 +682,28 @@ EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp) { size_t ret; - if(!fp || fp->FD == -1) + if(!fp || fp->FD == -1) { + LOG_WARN("bad fp %p", fp); return -1; + } if( size == 0 || num == 0 ) return 0; if( _GetFileMode(fp) != FILE_FLAG_MODE_READ ) { errno = 0; + LOG_WARN("not open for read"); + if( fp == stdin ) { + LOG_WARN("BUGCHECK FAIL: stdin was not open for read"); + exit(129); + } return -1; } // Don't read if EOF is set - if( fp->Flags & FILE_FLAG_EOF ) + if( fp->Flags & FILE_FLAG_EOF ) { + LOG_NOTICE("EOF"); return 0; + } if( fp->FD == FD_MEMFILE ) { @@ -701,6 +711,7 @@ EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp) } else if( fp->FD == FD_MEMSTREAM ) { //return _fread_memstream(ptr, size, num, fp); + LOG_WARN("Reading from a mem stream"); errno = EBADF; return 0; } @@ -744,6 +755,8 @@ EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp) extra, size, num ); } + LOG_NOTICE("Incomplete read %i/%i bytes (object size %i)", + ret, bytes, size); } return ret / size; @@ -782,13 +795,12 @@ EXPORT char *fgets(char *s, int size, FILE *fp) */ EXPORT int fputc(int c, FILE *fp) { - char ch = c; + unsigned char ch = c; return fwrite(&ch, 1, 1, fp); } EXPORT int putchar(int c) { - c &= 0xFF; return fputc(c, stdout); } @@ -798,7 +810,7 @@ EXPORT int putchar(int c) */ EXPORT int fgetc(FILE *fp) { - char ret = 0; + unsigned char ret = 0; if( fread(&ret, 1, 1, fp) != 1 ) return -1; return ret; @@ -812,7 +824,6 @@ EXPORT int getchar(void) EXPORT int puts(const char *str) { - if(!str) return 0; int len = strlen(str); diff --git a/Usermode/Libraries/libc.so_src/string.c b/Usermode/Libraries/libc.so_src/string.c index aa79ec961676057343d1fcd833541f6641631d30..d61d51dde0d2b742b69c06733c166d6e464b7150 100644 --- a/Usermode/Libraries/libc.so_src/string.c +++ b/Usermode/Libraries/libc.so_src/string.c @@ -2,7 +2,7 @@ * AcessOS Basic C Library * string.c */ -#include <acess/sys.h> +//#include <acess/sys.h> #include <stdlib.h> #include <stdio.h> #include <ctype.h> @@ -13,20 +13,19 @@ * \fn EXPORT int strcmp(const char *s1, const char *s2) * \brief Compare two strings */ -EXPORT int strcmp(const char *s1, const char *s2) +EXPORT int strcmp(const char *_s1, const char *_s2) { - while(*s1 && *s1 == *s2) { - s1++; s2++; - } - return (int)*s1 - (int)*s2; + return strncmp(_s1, _s2, SIZE_MAX); } /** - * \fn EXPORT int strncmp(const char *s1, const char *s2) - * \brief Compare two strings + * \fn EXPORT int strncmp(const char *s1, const char *s2, size_t n) + * \brief Compare two strings, stopping after n characters */ -EXPORT int strncmp(const char *s1, const char *s2, size_t n) +EXPORT int strncmp(const char *_s1, const char *_s2, size_t n) { + const unsigned char* s1 = (const unsigned char*)_s1; + const unsigned char* s2 = (const unsigned char*)_s2; while(n && *s1 && *s1 == *s2) { s1++; s2++; @@ -38,23 +37,31 @@ EXPORT int strncmp(const char *s1, const char *s2, size_t n) return (int)*s1 - (int)*s2; } -EXPORT int strcasecmp(const char *s1, const char *s2) +EXPORT int strcasecmp(const char *_s1, const char *_s2) { - int rv; - while( (rv = toupper(*s1) - toupper(*s2)) == 0 && *s1 != '\0' && *s2 != '\0' ) { - s1++; s2++; - } - return rv; + return strncasecmp(_s1, _s2, SIZE_MAX); } -EXPORT int strncasecmp(const char *s1, const char *s2, size_t n) +EXPORT int strncasecmp(const char *_s1, const char *_s2, size_t n) { - int rv = 0; - if( n == 0 ) return 0; - while(n -- && (rv = toupper(*s1) - toupper(*s2)) == 0 && *s1 != '\0' && *s2 != '\0') { - s1++; s2++; + const unsigned char* s1 = (const unsigned char*)_s1; + const unsigned char* s2 = (const unsigned char*)_s2; + while( n-- && *s1 && *s2 ) + { + if( *s1 != *s2 ) + { + int rv; + rv = toupper(*s1) - toupper(*s2); + if(rv != 0) + return rv; + rv = tolower(*s1) - tolower(*s2); + if(rv != 0) + return rv; + } + s1 ++; + s2 ++; } - return rv; + return 0; } /** @@ -80,8 +87,13 @@ EXPORT char *strcpy(char *dst, const char *src) EXPORT char *strncpy(char *dst, const char *src, size_t num) { char *to = dst; - while(*src && num--) *to++ = *src++; - *to = '\0'; + while(num --) + { + if(*src) + *to++ = *src++; + else + *to++ = '\0'; + } return dst; } @@ -118,9 +130,10 @@ EXPORT char *strncat(char *dst, const char *src, size_t n) */ EXPORT size_t strlen(const char *str) { - size_t retval; - for(retval = 0; *str != '\0'; str++, retval++); - return retval; + size_t len = 0; + while(str[len] != '\0') + len ++; + return len; } /** @@ -130,8 +143,9 @@ EXPORT size_t strlen(const char *str) */ EXPORT size_t strnlen(const char *str, size_t maxlen) { - size_t len; - for( len = 0; maxlen -- && *str; str ++, len ++ ); + size_t len = 0; + while( len < maxlen && str[len] != '\0' ) + len ++; return len; } @@ -171,11 +185,12 @@ EXPORT char *strndup(const char *str, size_t maxlen) * \fn EXPORT char *strchr(char *str, int character) * \brief Locate a character in a string */ -EXPORT char *strchr(const char *str, int character) +EXPORT char *strchr(const char *_str, int character) { + const unsigned char* str = (const unsigned char*)_str; for(;*str;str++) { - if(*str == character) + if( *str == character ) return (char*)str; } return NULL; @@ -185,11 +200,10 @@ EXPORT char *strchr(const char *str, int character) * \fn EXPORT char *strrchr(char *str, int character) * \brief Locate the last occurance of a character in a string */ -EXPORT char *strrchr(const char *str, int character) +EXPORT char *strrchr(const char *_str, int character) { - int i; - i = strlen(str)-1; - while(i--) + const unsigned char* str = (const unsigned char*)_str; + for( size_t i = strlen(_str); i--; ) { if(str[i] == character) return (void*)&str[i]; @@ -277,6 +291,8 @@ EXPORT void *memcpy(void *__dest, const void *__src, size_t count) return __dest; } +// TODO: memccpy (POSIX defined) + /** * \fn EXPORT void *memmove(void *dest, const void *src, size_t count) * \brief Copy data in memory, avoiding overlap problems @@ -316,7 +332,7 @@ EXPORT int memcmp(const void *mem1, const void *mem2, size_t count) while(count--) { if( *p1 != *p2 ) - return *p1 - *p2; + return (int)*p1 - (int)*p2; p1 ++; p2 ++; } @@ -332,11 +348,12 @@ EXPORT int memcmp(const void *mem1, const void *mem2, size_t count) */ EXPORT void *memchr(const void *ptr, int value, size_t num) { + const unsigned char* buf = ptr; while(num--) { - if( *(const unsigned char*)ptr == (unsigned char)value ) - return (void*)ptr; - ptr ++; + if( *buf == (unsigned char)value ) + return (void*)buf; + buf ++; } return NULL; } @@ -344,12 +361,13 @@ EXPORT void *memchr(const void *ptr, int value, size_t num) EXPORT size_t strcspn(const char *haystack, const char *reject) { size_t ret = 0; - int i; while( *haystack ) { - for( i = 0; reject[i] && reject[i] == *haystack; i ++ ); - - if( reject[i] ) return ret; + for( int i = 0; reject[i]; i ++ ) + { + if( reject[i] == *haystack ) + return ret; + } ret ++; } return ret; @@ -358,17 +376,32 @@ EXPORT size_t strcspn(const char *haystack, const char *reject) EXPORT size_t strspn(const char *haystack, const char *accept) { size_t ret = 0; - int i; while( *haystack ) { - for( i = 0; accept[i] && accept[i] == *haystack; i ++ ); - - if( !accept[i] ) return ret; + for( int i = 0; accept[i]; i ++ ) + { + if( accept[i] != *haystack ) + return ret; + } ret ++; } return ret; } +EXPORT char *strpbrk(const char *haystack, const char *accept) +{ + while( *haystack ) + { + for( int i = 0; accept[i]; i ++ ) + { + if( accept[i] == *haystack ) + return (char*)haystack; + } + haystack ++; + } + return NULL; +} + char *strtok(char *str, const char *delim) { static char *__saveptr; diff --git a/Usermode/Libraries/libc.so_src/strtoi.c b/Usermode/Libraries/libc.so_src/strtoi.c index de7f72545ef01aaab2b812f6a09b72ae8a139ef4..84bf0005919edbacef6a2dc0967f07fffe40d88c 100644 --- a/Usermode/Libraries/libc.so_src/strtoi.c +++ b/Usermode/Libraries/libc.so_src/strtoi.c @@ -12,7 +12,7 @@ unsigned long long strtoull(const char *str, char **end, int base) { - long long ret = 0; + unsigned long long ret = 0; if( !str || base < 0 || base > 36 || base == 1 ) { if(end) @@ -27,7 +27,7 @@ unsigned long long strtoull(const char *str, char **end, int base) // Handle base detection for hex if( base == 0 || base == 16 ) { - if( *str == '0' && str[1] == 'x' ) { + if( *str == '0' && (str[1] == 'x' || str[1] == 'X') && isxdigit(str[2]) ) { str += 2; base = 16; } @@ -43,6 +43,10 @@ unsigned long long strtoull(const char *str, char **end, int base) if( base == 0 ) base = 10; + // Value before getting within 1 digit of ULLONG_MAX + // - Used to avoid overflow in more accurate check + unsigned long long max_before_ullong_max = ULLONG_MAX / base; + unsigned int space_above = ULLONG_MAX - max_before_ullong_max * base; while( *str ) { int next = -1; @@ -58,8 +62,31 @@ unsigned long long strtoull(const char *str, char **end, int base) if( 'a' <= *str && *str <= 'a'+base-10-1 ) next = *str - 'a' + 10; } + //_SysDebug("strtoull - ret=0x%llx,next=%i,str='%s'", ret, next, str); if( next < 0 ) break; + + // If we're already out of range, keep eating + if( ret == ULLONG_MAX ) { + errno = ERANGE; + str ++; + // Keep eating until first unrecognised character + continue; + } + + // Rough then accurate check against max value + if( ret >= max_before_ullong_max ) + { + //_SysDebug("strtoull - 0x%llx>0x%llx", ret, max_before_ullong_max); + if( (ret - max_before_ullong_max) * base + next > space_above ) { + //_SysDebug("strtoull - %u*%u+%u (%u) > %u", + // (unsigned int)(ret - max_before_ullong_max), base, next, space_above); + ret = ULLONG_MAX; + errno = ERANGE; + str ++; + continue; + } + } ret *= base; ret += next; str ++; @@ -85,7 +112,6 @@ unsigned long strtoul(const char *ptr, char **end, int base) long long strtoll(const char *str, char **end, int base) { int neg = 0; - unsigned long long ret; if( !str ) { errno = EINVAL; @@ -96,17 +122,37 @@ long long strtoll(const char *str, char **end, int base) str++; // Check for negative (or positive) sign - if(*str == '-' || *str == '+') { + if(*str == '-' || *str == '+') + { + //_SysDebug("strtoll - str[0:1] = '%.2s'", str); + if( !isdigit(str[1]) ) { + // Non-digit, invalid string + if(end) *end = (char*)str; + return 0; + } neg = (*str == '-'); str++; } - ret = strtoull(str, end, base); + unsigned long long ret = strtoull(str, end, base); + //_SysDebug("strtoll - neg=%i,ret=%llu", neg, ret); - if( neg ) + if( neg ) { + // Abuses unsigned integer overflow + if( ret + LLONG_MIN < ret ) { + errno = ERANGE; + return LLONG_MIN; + } return -ret; + } else + { + if( ret > LLONG_MAX ) { + errno = ERANGE; + return LLONG_MAX; + } return ret; + } } long strtol(const char *str, char **end, int base) diff --git a/Usermode/Libraries/libc.so_src/stub.c b/Usermode/Libraries/libc.so_src/stub.c index a1c67ffb26ab48447e24465a70cb4199981d23f4..922943e1e71a7d4a120e583f85ca0e07c5e58d1c 100644 --- a/Usermode/Libraries/libc.so_src/stub.c +++ b/Usermode/Libraries/libc.so_src/stub.c @@ -45,21 +45,8 @@ tCPUID gCPU_Features; */ int SoMain(UNUSED(uintptr_t, BaseAddress), UNUSED(int, argc), UNUSED(char **, argv), char **envp) { - // Init for env.c environ = envp; - #if 0 - { - int i = 0; - char **tmp; - _SysDebug("envp = %p", envp); - for(tmp = envp; *tmp; tmp++,i++) - { - _SysDebug("envp[%i] = '%s'", i, *tmp); - } - } - #endif - _stdio_init(); #if USE_CPUID @@ -76,7 +63,7 @@ int SoMain(UNUSED(uintptr_t, BaseAddress), UNUSED(int, argc), UNUSED(char **, ar // Set Error handler _SysSetFaultHandler(ErrorHandler); - return 1; + return 0; } int ErrorHandler(int Fault) diff --git a/Usermode/Libraries/libc.so_src/time.c b/Usermode/Libraries/libc.so_src/time.c index 185af88f0a0c4019b462e31d525e7e9880b0e172..611ae9b0de3b566f07ceb01eca67ddac29674d6d 100644 --- a/Usermode/Libraries/libc.so_src/time.c +++ b/Usermode/Libraries/libc.so_src/time.c @@ -145,11 +145,18 @@ size_t strftime(char*restrict s, size_t maxsize, const char*restrict format, con if( *format == 0 ) break; format ++; + + // If EOS is hit on a '%', break early + if( *format == 0 ) + break; switch(*format++) { - case 0: format--; break; - case '%': ofs += _puts(s, maxsize, ofs, format-1, 1); break; - case 'd': // The day of the month as a decimal number (range 01 to 31). + // Literal '%', + case '%': + ofs += _puts(s, maxsize, ofs, format-1, 1); + break; + // The day of the month as a decimal number (range 01 to 31). + case 'd': { char tmp[2] = {'0','0'}; tmp[0] += (timeptr->tm_mday / 10) % 10; @@ -157,6 +164,24 @@ size_t strftime(char*restrict s, size_t maxsize, const char*restrict format, con ofs += _puts(s, maxsize, ofs, tmp, 2); } break; + // Two-digit 24 hour + case 'H': + { + char tmp[2] = {'0','0'}; + tmp[0] += (timeptr->tm_hour / 10) % 10; + tmp[1] += timeptr->tm_hour % 10; + ofs += _puts(s, maxsize, ofs, tmp, 2); + } + break; + // Two-digit minutes + case 'M': + { + char tmp[2] = {'0','0'}; + tmp[0] += (timeptr->tm_min / 10) % 10; + tmp[1] += timeptr->tm_min % 10; + ofs += _puts(s, maxsize, ofs, tmp, 2); + } + break; default: _SysDebug("TODO: strftime('...%%%c...')", format[-1]); break; diff --git a/Usermode/Libraries/libc.so_src/timeconv.c b/Usermode/Libraries/libc.so_src/timeconv.c index 6fed585ab39f2239c82ff53a9fe2e1bec013729b..00eb13f3205c3bb1e89514fb94c84659c9bd51d7 100644 --- a/Usermode/Libraries/libc.so_src/timeconv.c +++ b/Usermode/Libraries/libc.so_src/timeconv.c @@ -114,7 +114,7 @@ int64_t get_days_since_y2k(int64_t ts, int *h, int *m, int *s) ts -= n_leap; #endif - int64_t days = ts / 24*60*60; + int64_t days = ts / (24*60*60); int64_t seconds = ts % (24*60*60); *s = (is_ls ? 60 : seconds % 60); *m = (seconds/60 % 24); diff --git a/Usermode/Libraries/libiconv.so_src/Makefile b/Usermode/Libraries/libiconv.so_src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..50f257ac5322653b853e3b2b119f2da6d5befc4b --- /dev/null +++ b/Usermode/Libraries/libiconv.so_src/Makefile @@ -0,0 +1,15 @@ +# Acess 2 "libiconv" +# + +include ../Makefile.cfg + +CPPFLAGS += +CFLAGS += -Wall +LDFLAGS += -lc -soname libiconv.so + +OBJ = iconv.o +BIN = libiconv.so + +include ../Makefile.tpl + + diff --git a/Usermode/Libraries/libiconv.so_src/iconv.c b/Usermode/Libraries/libiconv.so_src/iconv.c new file mode 100644 index 0000000000000000000000000000000000000000..d339555caeb9660b272976d019c47c0c9e6fc870 --- /dev/null +++ b/Usermode/Libraries/libiconv.so_src/iconv.c @@ -0,0 +1,27 @@ +/* + */ +#include <iconv.h> +#include <acess/sys.h> + +// === CODE === +int SoMain(void) +{ + return 0; +} + +iconv_t iconv_open(const char *to, const char *from) +{ + return NULL; +} + +size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) +{ + _SysDebug("WTF are you using iconv for?"); + return 0; +} + +int iconv_close(iconv_t cd) +{ + return 0; +} + diff --git a/Usermode/Libraries/libiconv.so_src/include_exp/iconv.h b/Usermode/Libraries/libiconv.so_src/include_exp/iconv.h new file mode 100644 index 0000000000000000000000000000000000000000..817abeed70f6540c6002107a74d9e8b8017b76cb --- /dev/null +++ b/Usermode/Libraries/libiconv.so_src/include_exp/iconv.h @@ -0,0 +1,20 @@ +/* + * Acess2 libiconv + * - By John Hodge (thePowersGang) + * + * iconv.h + * - External header + */ +#ifndef _ICONV_H_ +#define _ICONV_H_ + +#include <stddef.h> + +typedef void *iconv_t; + +extern iconv_t iconv_open(const char *to, const char *from); +extern size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); +extern int iconv_close(iconv_t cd); + +#endif + diff --git a/Usermode/Libraries/libintl.so_src/Makefile b/Usermode/Libraries/libintl.so_src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..398ffc4ea1ee0b0eb2414cc45ac550367bc0d9dc --- /dev/null +++ b/Usermode/Libraries/libintl.so_src/Makefile @@ -0,0 +1,16 @@ +# Acess 2 "libintl" +# + +include ../Makefile.cfg + +CPPFLAGS += +CFLAGS += -Wall +LDFLAGS += -lc + +OBJ = main.o gettext.o +BIN = libintl.so + +include ../Makefile.tpl + + + diff --git a/Usermode/Libraries/libintl.so_src/gettext.c b/Usermode/Libraries/libintl.so_src/gettext.c new file mode 100644 index 0000000000000000000000000000000000000000..3b10d411393090233a0b8e93094618ab807b8407 --- /dev/null +++ b/Usermode/Libraries/libintl.so_src/gettext.c @@ -0,0 +1,35 @@ +/* + */ +#include <stddef.h> +#include <libintl.h> + +// === CODE === +char *gettext(const char *msg) +{ + return dcgettext(NULL, msg, 0); +} +char *dgettext(const char *domain, const char *msg) +{ + return dcgettext(domain, msg, 0); +} +char *dcgettext(const char *domain, const char *msg, int category) +{ + return (char*)msg; +} + +char *ngettext(const char *msg, const char *msgp, unsigned long int n) +{ + return dcngettext(NULL, msg, msgp, n, 0); +} +char *dngettext(const char *domain, const char *msg, const char *msgp, unsigned long int n) +{ + return dcngettext(domain, msg, msgp, n, 0); +} +char *dcngettext(const char *domain, const char *msg, const char *msgp, unsigned long int n, int category) +{ + if( n == 1 ) + return (char*)msg; + else + return (char*)msgp; +} + diff --git a/Usermode/Libraries/libintl.so_src/include_exp/libintl.h b/Usermode/Libraries/libintl.so_src/include_exp/libintl.h new file mode 100644 index 0000000000000000000000000000000000000000..54c0993809134cd7e13d5f31b334fc95cc6c03ff --- /dev/null +++ b/Usermode/Libraries/libintl.so_src/include_exp/libintl.h @@ -0,0 +1,13 @@ +/* + */ +#ifndef _LIBINTL_H_ +#define _LIBINTL_H_ + +extern char *gettext(const char *msg); +extern char *dgettext(const char *domain, const char *msg); +extern char *dcgettext(const char *domain, const char *msg, int category); +extern char *ngettext(const char *msg, const char *msgp, unsigned long int n); +extern char *dngettext(const char *domain, const char *msg, const char *msgp, unsigned long int n); +extern char *dcngettext(const char *domain, const char *msg, const char *msgp, unsigned long int n, int category); + +#endif diff --git a/Usermode/Libraries/libintl.so_src/main.c b/Usermode/Libraries/libintl.so_src/main.c new file mode 100644 index 0000000000000000000000000000000000000000..30dead738e1dc9fab6339151b2c2ee5028033556 --- /dev/null +++ b/Usermode/Libraries/libintl.so_src/main.c @@ -0,0 +1,7 @@ +/* + */ + +int SoMain(void) +{ + return 0; +} diff --git a/Usermode/Libraries/libm.so_src/include_exp/math.h b/Usermode/Libraries/libm.so_src/include_exp/math.h index d6d988f22c2deba6104df32e5b0d831083e155b4..a86001217923beb5097896521a208b2ed10e0e85 100644 --- a/Usermode/Libraries/libm.so_src/include_exp/math.h +++ b/Usermode/Libraries/libm.so_src/include_exp/math.h @@ -12,6 +12,13 @@ extern "C" { #endif +typedef float float_t; +typedef double double_t; + + +#define INFINITY (*(float*)((uint32_t[]){0x78000000})) +#define NAN (*(float*)((uint32_t[]){0x78000001})) + extern double pow(double x, double y); extern double exp(double x); extern double log(double val); diff --git a/Usermode/Libraries/libnet.so_src/Makefile b/Usermode/Libraries/libnet.so_src/Makefile index 29abaaa0e95d8b5223426b8d364fb89b4f6bd7ee..10d5b9620d45e8c01fc8fb6b77b5bc4f173a1640 100644 --- a/Usermode/Libraries/libnet.so_src/Makefile +++ b/Usermode/Libraries/libnet.so_src/Makefile @@ -7,6 +7,9 @@ CFLAGS += -Wall LDFLAGS += -lc -soname libnet.so OBJ = main.o address.o socket.o +OBJ += hostnames.o dns.o BIN = libnet.so +UTESTS = dns + include ../Makefile.tpl diff --git a/Usermode/Libraries/libnet.so_src/TEST_dns.c b/Usermode/Libraries/libnet.so_src/TEST_dns.c new file mode 100644 index 0000000000000000000000000000000000000000..26b36bf50481273e33c8fca0febdd67c0f92d572 --- /dev/null +++ b/Usermode/Libraries/libnet.so_src/TEST_dns.c @@ -0,0 +1,52 @@ +/* + */ +#include "include/dns.h" +#include <string.h> +#include <stdio.h> +#include <stdint.h> + +extern int DNS_int_ParseResponse(const void* packet, size_t return_len, void *info, handle_record_t* handle_record_t); + +// Complex response from "Q ssh.ucc.asn.au A IN" +const uint8_t test_packet_1[] = { + 0xac, 0x00, 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x03, 0x73, 0x73, 0x68, 0x03, 0x75, 0x63, 0x63, 0x03, 0x61, 0x73, 0x6e, 0x02, 0x61, 0x75, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x77, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x78, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x79, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x61, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x7a, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x62, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x75, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x76, 0xc0, 0x18, 0xc0, 0x2c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc0, 0x05, 0xc0, 0x3c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc2, 0x05, 0xc0, 0x4c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc4, 0x05, 0xc0, 0x5c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x3a, 0x41, 0xfe, 0x49, 0xc0, 0x6c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc6, 0x05, 0xc0, 0x7c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x3a, 0x41, 0xfd, 0x49, 0xc0, 0x8c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0xd3, 0x1d, 0x85, 0x20, 0xc0, 0x9c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0xca, 0x0c, 0x1f, 0x8d, + }; + +#define TEST_REL_INT(exp, rel, have) do { \ + int a = (exp);\ + int b = (have);\ + if( !(a rel b) ) { \ + fprintf(stderr, "TEST_REL_INT("#exp" "#rel" "#exp") FAILED l=%i r=%i", \ + a, b); \ + return 1; \ + } \ +} while(0) + +int test_response_parse_1_cb(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata) +{ + int* stagep = info; + switch( *stagep ) + { + case 0: + TEST_REL_INT(0, ==, strcmp(name, "au.")); + break; + } + (*stagep) += 1; + return 0; +} +int test_response_parse_1(void) +{ + int stage = 0; + TEST_REL_INT(0, ==, DNS_int_ParseResponse(test_packet_1, sizeof(test_packet_1), &stage, test_response_parse_1_cb) ); + return 0; +} + +int main(void) +{ + int rv = 0; + // - Name Encode + // - Name Decode + // - Response parsing + rv |= test_response_parse_1(); + return rv; +} diff --git a/Usermode/Libraries/libnet.so_src/address.c b/Usermode/Libraries/libnet.so_src/address.c index 66a28b1b45b22fe08b75d11dcc7c7ff1914a05a0..d103e64b04fee12d7951049fee38b6215e6a484e 100644 --- a/Usermode/Libraries/libnet.so_src/address.c +++ b/Usermode/Libraries/libnet.so_src/address.c @@ -7,7 +7,8 @@ */ #include <net.h> #include <stdint.h> -#include <stdio.h> +#include <stdio.h> // sprintf +#include <stdlib.h> #define DEBUG 0 static inline uint32_t htonl(uint32_t v) @@ -37,43 +38,50 @@ static inline uint16_t htons(uint16_t v) */ static int Net_ParseIPv4Addr(const char *String, uint8_t *Addr) { - int i = 0; int j; - int val; + const char *pos = String; - for( j = 0; String[i] && j < 4; j ++ ) + for( j = 0; *pos && j < 4; j ++ ) { - val = 0; - for( ; String[i] && String[i] != '.'; i++ ) - { - if('0' > String[i] || String[i] > '9') { - #if DEBUG - printf("0<c<9 expected, '%c' found\n", String[i]); - #endif - return 0; - } - val = val*10 + String[i] - '0'; + char *end; + unsigned long val = strtoul(pos, &end, 10); + if( *end && *end != '.' ) { + #if DEBUG + _SysDebug("%s: Unexpected character, '%c' found", __func__, *end); + #endif + return 0; + } + if( *pos == '.' ) { + #if DEBUG + _SysDebug("%s: Two dots in a row", __func__); + #endif + return 0; } if(val > 255) { #if DEBUG - printf("val > 255 (%i)\n", val); + _SysDebug("%s: val > 255 (%i)", __func__, val); #endif return 0; } + #if DEBUG + _SysDebug("%s: Comp '%.*s' = %lu", __func__, end - pos, pos, val); + #endif Addr[j] = val; - if(String[i] == '.') - i ++; + pos = end; + + if(*pos == '.') + pos ++; } if( j != 4 ) { #if DEBUG - printf("4 parts expected, %i found\n", j); + _SysDebug("%s: 4 parts expected, %i found", __func__, j); #endif return 0; } - if(String[i] != '\0') { + if(*pos != '\0') { #if DEBUG - printf("EOS != '\\0', '%c'\n", String[i]); + _SysDebug("%s: EOS != '\\0', '%c'", __func__, *pos); #endif return 0; } diff --git a/Usermode/Libraries/libnet.so_src/dns.c b/Usermode/Libraries/libnet.so_src/dns.c new file mode 100644 index 0000000000000000000000000000000000000000..3bb9c35575c767834d28031d4e8e7b234f4fd52e --- /dev/null +++ b/Usermode/Libraries/libnet.so_src/dns.c @@ -0,0 +1,338 @@ +/* + * Acess2 Networking Toolkit + * By John Hodge (thePowersGang) + * + * dns.c + * - Hostname<->Address resolution + */ +#include <stddef.h> // size_t / NULL +#include <stdint.h> // uint*_t +#include <string.h> // memcpy, strchr +#include <assert.h> +#include <acess/sys.h> // for _SysSelect +#include <acess/fd_set.h> // FD_SET +#include <net.h> +#include "include/dns.h" + +// === PROTOTYPES === +//int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eTypes type, enum eClass class, handle_record_t* handle_record, void *info); +int DNS_int_ParseResponse(const void* packet, size_t return_len, void *info, handle_record_t* handle_record_t); +size_t DNS_EncodeName(void *buf, const char *dotted_name); +int DNS_DecodeName(char dotted_name[256], const void *buf, size_t ofs, size_t space); +int DNS_int_ParseRR(const void *buf, size_t ofs, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p); + +static uint16_t get16(const void *buf); +static uint32_t get32(const void *buf); +static size_t put16(void *buf, uint16_t val); + + +// === CODE === +int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eTypes type, enum eClass class, handle_record_t* handle_record, void *info) +{ + int namelen = DNS_EncodeName(NULL, name); + assert(namelen < 256); + size_t pos = 0; + char packet[ 512 ]; + assert( (6*2) + (namelen + 2*2) < 512 ); + // - Header + pos += put16(packet + pos, 0xAC00); // Identifier (arbitary) + pos += put16(packet + pos, (0 << 0) | (0 << 1) | (1 << 8) ); // Op : Query, Standard, Recursion + pos += put16(packet + pos, 1); // QDCount + pos += put16(packet + pos, 0); // ANCount + pos += put16(packet + pos, 0); // NSCount + pos += put16(packet + pos, 0); // ARCount + // - Question + pos += DNS_EncodeName(packet + pos, name); + pos += put16(packet + pos, type); // QType + pos += put16(packet + pos, class); // QClass + + assert(pos <= sizeof(packet)); + + // Send and wait for reply + // - Lock + // > TODO: Lock DNS queries + // - Send + int sock = Net_OpenSocket_UDP(ServerAType, ServerAddr, 53, 0); + if( sock < 0 ) { + // Connection failed + _SysDebug("DNS_Query - UDP open failed"); + // TODO: Correctly report this failure with a useful error code + return 1; + } + int rv = Net_UDP_SendTo(sock, 53, ServerAType, ServerAddr, pos, packet); + if( rv != pos ) { + _SysDebug("DNS_Query - Write failed"); + // TODO: Error reporting + _SysClose(sock); + return 1; + } + // - Wait + { + int nfd = sock + 1; + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + int64_t timeout = 2000; // Give it two seconds, should be long enough + rv = _SysSelect(nfd, &fds, NULL, NULL, &timeout, 0); + if( rv == 0 ) { + // Timeout with no reply, give up + _SysDebug("DNS_Query - Timeout"); + _SysClose(sock); + return 1; + } + if( rv < 0 ) { + // Oops, select failed + _SysDebug("DNS_Query - Select failure"); + _SysClose(sock); + return 1; + } + } + int return_len = Net_UDP_RecvFrom(sock, NULL, NULL, NULL, sizeof(packet), packet); + if( return_len <= 0 ) { + // TODO: Error reporting + _SysDebug("DNS_Query - Read failure"); + _SysClose(sock); + return 1; + } + _SysClose(sock); + // - Release + // > TODO: Lock DNS queries + + // For each response in the answer (and additional) sections, call the passed callback + return DNS_int_ParseResponse(packet, return_len, info, handle_record); +} + +int DNS_int_ParseResponse(const void* buf, size_t return_len, void *info, handle_record_t* handle_record) +{ + const uint8_t* packet = buf; + char rr_name[256]; + unsigned int id = get16(packet + 0); + if( id != 0xAC00 ) { + _SysDebug("DNS_Query - Packet ID mismatch"); + return 2; + } + unsigned int flags = get16(packet + 2); + unsigned int qd_count = get16(packet + 4); + unsigned int an_count = get16(packet + 6); + unsigned int ns_count = get16(packet + 8); + unsigned int ar_count = get16(packet + 10); + size_t pos = 6*2; + // TODO: Can I safely assert / fail if qd_count is non-zero? + // - Questions, ignored + for( unsigned int i = 0; i < qd_count; i ++ ) { + int rv = DNS_DecodeName(rr_name, packet, pos, return_len); + if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in QD"); + return 1; + } + pos += rv + 2*2; + } + // - Answers, pass on to handler + for( unsigned int i = 0; i < an_count; i ++ ) + { + enum eTypes type; + enum eClass class; + uint32_t ttl; + size_t rdlength; + int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, &type, &class, &ttl, &rdlength); + if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in AN"); + return 1; + } + pos += rv; + + handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos - rdlength); + } + // Authority Records (should all be NS records) + for( unsigned int i = 0; i < ns_count; i ++ ) + { + size_t rdlength; + int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, NULL, NULL, NULL, &rdlength); + if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in NS"); + return 1; + } + pos += rv; + } + // - Additional records, pass to handler + for( unsigned int i = 0; i < ar_count; i ++ ) + { + enum eTypes type; + enum eClass class; + uint32_t ttl; + size_t rdlength; + int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, &type, &class, &ttl, &rdlength); + if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in AR"); + return 1; + } + pos += rv; + + handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos - rdlength); + } + + return 0; +} + +/// Encode a dotted name as a DNS name +size_t DNS_EncodeName(void *buf, const char *dotted_name) +{ + size_t ret = 0; + const char *str = dotted_name; + uint8_t *buf8 = buf; + while( *str ) + { + const char *next = strchr(str, '.'); + size_t seg_len = (next ? next - str : strlen(str)); + if( seg_len > 63 ) { + // Oops, too long (truncate) + seg_len = 63; + } + if( seg_len == 0 && next != NULL ) { + // '..' encountered, invalid (skip) + str = next+1; + continue ; + } + + if( buf8 ) + { + buf8[ret] = seg_len; + memcpy(buf8+ret+1, str, seg_len); + } + ret += 1 + seg_len; + + if( next == NULL ) { + // No trailing '.', assume it's there? Yes, need to be NUL terminated + if(buf8) buf8[ret] = 0; + ret ++; + break; + } + else { + str = next + 1; + } + } + return ret; +} + +// Decode a name (including trailing . for root) +int DNS_DecodeName(char dotted_name[256], const void *buf, size_t ofs, size_t space) +{ + int consumed = 0; + int out_pos = 0; + const uint8_t *buf8 = (const uint8_t*)buf + ofs; + for( ;; ) + { + if( ofs + consumed + 1 > space ) { + _SysDebug("DNS_DecodeName - Len byte OOR space=%i", space); + return -1; + } + uint8_t seg_len = *buf8; + buf8 ++; + consumed ++; + // Done + if( seg_len == 0 ) + break; + if( (seg_len & 0xC0) == 0xC0 ) + { + // Backreference, the rest of the name is a backref + char tmp[256]; + int ref_ofs = get16(buf8 - 1) & 0x3FFF; + consumed += 1, buf8 += 1; // Only one, previous inc still applies + _SysDebug("DNS_DecodeName - Nested at %i", ref_ofs); + if( DNS_DecodeName(tmp, buf, ref_ofs, space) < 0 ) + return -1; + memcpy(dotted_name+out_pos, tmp, strlen(tmp)); + out_pos += strlen(tmp); + break; + } + // Protocol violation (segment too long) + if( seg_len >= 64 ) { + _SysDebug("DNS_DecodeName - Seg too long %i", seg_len); + return -1; + } + // Protocol violation (overflowed end of buffer) + if( ofs + consumed + seg_len > space ) { + _SysDebug("DNS_DecodeName - Seg OOR %i+%i>%i", consumed, seg_len, space); + return -1; + } + // Protocol violation (name was too long) + if( out_pos + seg_len + 1 > 255 ) { + _SysDebug("DNS_DecodeName - Dotted name too long %i+%i+1 > %i", + out_pos, seg_len, 255); + return -1; + } + + _SysDebug("DNS_DecodeName : Seg %i '%.*s'", seg_len, seg_len, buf8); + + // Read segment + memcpy(dotted_name + out_pos, buf8, seg_len); + buf8 += seg_len; + consumed += seg_len; + out_pos += seg_len; + + // Place '.' + dotted_name[out_pos] = '.'; + out_pos ++; + } + dotted_name[out_pos] = '\0'; + _SysDebug("DNS_DecodeName - '%s', consumed = %i", dotted_name, consumed); + return consumed; +} + +// Parse a Resource Record +int DNS_int_ParseRR(const void *buf, size_t ofs, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p) +{ + const uint8_t *buf8 = buf; + size_t consumed = 0; + + // 1. Name + int rv = DNS_DecodeName(name_p, buf, ofs, space); + if(rv < 0) return -1; + + ofs += rv, consumed += rv; + + if( type_p ) + *type_p = get16(buf8 + ofs); + ofs += 2, consumed += 2; + + if( class_p ) + *class_p = get16(buf8 + ofs); + ofs += 2, consumed += 2; + + if( ttl_p ) + *ttl_p = get32(buf + ofs); + ofs += 4, consumed += 4; + + size_t rdlength = get16(buf + ofs); + if( rdlength_p ) + *rdlength_p = rdlength; + ofs += 2, consumed += 2; + + _SysDebug("DNS_int_ParseRR - name='%s', rdlength=%i", name_p, rdlength); + + return consumed + rdlength; +} + +static uint16_t get16(const void *buf) { + const uint8_t* buf8 = buf; + uint16_t rv = 0; + rv |= (uint16_t)buf8[0] << 8; + rv |= (uint16_t)buf8[1] << 0; + return rv; +} +static uint32_t get32(const void *buf) { + const uint8_t* buf8 = buf; + uint32_t rv = 0; + rv |= (uint32_t)buf8[0] << 24; + rv |= (uint32_t)buf8[1] << 16; + rv |= (uint32_t)buf8[2] << 8; + rv |= (uint32_t)buf8[3] << 0; + return rv; +} +static size_t put16(void *buf, uint16_t val) { + uint8_t* buf8 = buf; + buf8[0] = val >> 8; + buf8[1] = val & 0xFF; + return 2; +} + diff --git a/Usermode/Libraries/libnet.so_src/hostnames.c b/Usermode/Libraries/libnet.so_src/hostnames.c new file mode 100644 index 0000000000000000000000000000000000000000..c3c962681164ac02dbc769c9718792cc107a6424 --- /dev/null +++ b/Usermode/Libraries/libnet.so_src/hostnames.c @@ -0,0 +1,164 @@ +/* + * Acess2 Networking Toolkit + * By John Hodge (thePowersGang) + * + * dns.c + * - Hostname<->Address resolution + */ +#include <net.h> +#include "include/dns.h" +#include <string.h> +#include <stdlib.h> // malloc (for loading config) +#include <stdbool.h> +#include <acess/sys.h> // _SysDebug + +// === TYPES === +struct sDNSServer +{ + int AddrType; + char AddrData[16]; +}; + +struct sHostEntry +{ + int AddrType; + char AddrData[16]; + char *Names[]; +}; + +struct sLookupAnyInfo +{ + int expected_type; + void *dest_ptr; + bool have_result; +}; +struct sDNSCallbackInfo +{ + void *cb_info; + tNet_LookupAddrs_Callback *callback; + enum eTypes desired_type; + enum eClass desired_class; + bool got_value; +}; + +// === PROTOTYPES === + int int_lookupany_callback(void *info_v, int AddrType, const void *Addr); +void int_DNS_callback(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata); + +// === GLOBALS === + int giNumDNSServers; +struct sDNSServer *gaDNSServers; + int giNumHostEntries; +struct sHostEntry *gaHostEntries; + +// === CODE === +int Net_Lookup_AnyAddr(const char *Name, int AddrType, void *Addr) +{ + struct sLookupAnyInfo cb_info = { + .expected_type = AddrType, + .dest_ptr = Addr, + .have_result = false, + }; + return Net_Lookup_Addrs(Name, &cb_info, int_lookupany_callback); +} +int int_lookupany_callback(void *info_v, int AddrType, const void *Addr) +{ + struct sLookupAnyInfo *info = info_v; + if( AddrType == info->expected_type && info->have_result == false ) + { + memcpy(info->dest_ptr, Addr, Net_GetAddressSize(AddrType)); + + info->have_result = true; + return 1; + } + return 0; +} + +int Net_Lookup_Addrs(const char *Name, void *cb_info, tNet_LookupAddrs_Callback *callback) +{ + _SysDebug("Net_Lookup_Addrs(Name='%s')", Name); + // 1. Load (if not loaded) the DNS config from "/Acess/Conf/dns" + // - "* <ip> <ip>" for DNS server(s) + // - "127.0.0.1 localhost localhost.localdomain" + if( !gaDNSServers ) + { + giNumDNSServers = 1; + gaDNSServers = malloc( 1 * sizeof(gaDNSServers[0]) ); + gaDNSServers[0].AddrType = Net_ParseAddress("192.168.1.1", gaDNSServers[0].AddrData); + } + + // 2. Check the hosts list + for( int i = 0; i < giNumHostEntries; i ++ ) + { + const struct sHostEntry* he = &gaHostEntries[i]; + for( const char * const *namep = (const char**)he->Names; *namep; namep ++ ) + { + if( strcasecmp(Name, *namep) == 0 ) + { + if( callback(cb_info, he->AddrType, he->AddrData) != 0 ) + return 0; + } + } + } + // 3. Contact DNS server specified in config + for( int i = 0; i < giNumDNSServers; i ++ ) + { + const struct sDNSServer *s = &gaDNSServers[i]; + struct sDNSCallbackInfo info = { + .cb_info = cb_info, + .callback = callback, + .desired_type = TYPE_A, + .desired_class = CLASS_IN, + .got_value = false, + }; + if( ! DNS_Query(s->AddrType, s->AddrData, Name, info.desired_type, info.desired_class, int_DNS_callback, &info) ) + { + if( info.got_value ) + { + return 0; + } + else + { + // NXDomain, I guess + return 1; + } + } + } + return 1; +} + +void int_DNS_callback(void *info_v, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata) +{ + struct sDNSCallbackInfo *info = info_v; + _SysDebug("int_DNS_callback(name='%s', type=%i, class=%i)", name, type, class); + + // Check type matches (if pattern was provided) + if( info->desired_type != QTYPE_STAR && type != info->desired_type ) + return ; + if( info->desired_class != QCLASS_STAR && class != info->desired_class ) + return ; + + switch( type ) + { + case TYPE_A: + if( rdlength != 4 ) + return ; + info->callback( info->cb_info, 4, rdata ); + break; + //case TYPE_AAAA: + // if( rdlength != 16 ) + // return ; + // info->callback( info->cb_info, 6, rdata ); + // break; + default: + // Ignore anything not A/AAAA + break; + } + info->got_value = true; +} + +int Net_Lookup_Name(int AddrType, const void *Addr, char *Dest[256]) +{ + return 1; +} + diff --git a/Usermode/Libraries/libnet.so_src/include/dns.h b/Usermode/Libraries/libnet.so_src/include/dns.h new file mode 100644 index 0000000000000000000000000000000000000000..dc7a58b4f220440e9c6d5bb355240f9a944a2327 --- /dev/null +++ b/Usermode/Libraries/libnet.so_src/include/dns.h @@ -0,0 +1,48 @@ +/* + * Acess2 Networking Toolkit + * By John Hodge (thePowersGang) + * + * dns.h + * - DNS Protocol Interface + */ +#ifndef _DNS_H_ +#define _DNS_H_ + +#include <stddef.h> + +enum eTypes +{ + TYPE_A = 1, + TYPE_NS = 2, + TYPE_CNAME = 5, + TYPE_SOA = 6, + TYPE_NULL = 10, + TYPE_PTR = 12, + TYPE_HINFO = 13, + TYPE_MX = 15, + TYPE_TXT = 16, + QTYPE_STAR = 255, +}; + +enum eClass +{ + CLASS_IN = 1, + CLASS_CH = 3, // "Chaos" + QCLASS_STAR = 255, +}; + +/** + * \brief Handler for a DNS record obtained by DNS_Query + * \param info Value passed as the last argument to DNS_Query + * \param name NUL-terminated name associated with the returned record + * \param type Record type (may not be equal to requested) + * \param class Record class (may not be equal to requested) + * \param rdlength Length of data pointed to by 'rdata' + * \param rdata Record data + */ +typedef void handle_record_t(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata); + +int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eTypes type, enum eClass class, handle_record_t* handle_record, void *info); + +#endif + diff --git a/Usermode/Libraries/libnet.so_src/include_exp/net.h b/Usermode/Libraries/libnet.so_src/include_exp/net.h index 5fe4ba1058688e83365e6dc5df026a0108ce471d..3d33da0337c7a700ed2b1d470bae068145309b48 100644 --- a/Usermode/Libraries/libnet.so_src/include_exp/net.h +++ b/Usermode/Libraries/libnet.so_src/include_exp/net.h @@ -6,6 +6,8 @@ #ifndef __LIBNET_H_ #define __LIBNET_H_ +#include <stddef.h> + enum { NET_ADDRTYPE_NULL = 0, NET_ADDRTYPE_IPV4 = 4, @@ -53,8 +55,43 @@ extern char *Net_GetInterface(int AddrType, void *Addr); * Opens a file using /Devices/ip/routes/@<AddrType>:<Addr>/<SocketName> * */ -extern int Net_OpenSocket(int AddrType, void *Addr, const char *SocketName); +extern int Net_OpenSocket(int AddrType, const void *Addr, const char *SocketName); + +extern int Net_OpenSocket_TCPC(int AddrType, const void *Addr, int Port); + +extern int Net_OpenSocket_UDP(int AddrType, const void *Addr, int RAddr, int LAddr); +extern int Net_UDP_SendTo (int FD, int Port, int AddrType, const void *Addr, size_t Length, const void *Data); +extern int Net_UDP_RecvFrom(int FD, int* Port, int* AddrType, void *Addr, size_t Length, void *Data); -extern int Net_OpenSocket_TCPC(int AddrType, void *Addr, int Port); + +/** + * \name Hostnames + * \brief Handling of hostname resolution + * \{ + */ + +/** + * \brief Returns an address for the specified hostname + * \note Picks randomly if multiple addresses are present + */ +extern int Net_Lookup_AnyAddr(const char *Name, int AddrType, void *Addr); + +/** + * \brief Callback for Net_Lookup_Addrs, returns non-zero when lookup should terminate + */ +typedef int tNet_LookupAddrs_Callback(void *info, int AddrType, const void *Addr); + +/** + * \brief Enumerate addresses for a host, calling the provided function for each + */ +extern int Net_Lookup_Addrs(const char *Name, void *info, tNet_LookupAddrs_Callback* callback); + +/** + */ +extern int Net_Lookup_Name(int AddrType, const void *Addr, char *Dest[256]); + +/** + * \} + */ #endif diff --git a/Usermode/Libraries/libnet.so_src/socket.c b/Usermode/Libraries/libnet.so_src/socket.c index 85f7e54f28944711b7f026a280625bf3ccd94db7..825dc6fe274a2011bd56f61d01748205799db0d5 100644 --- a/Usermode/Libraries/libnet.so_src/socket.c +++ b/Usermode/Libraries/libnet.so_src/socket.c @@ -8,17 +8,28 @@ #include <net.h> #include <stdio.h> #include <stdint.h> +#include <string.h> // memcpy #include <acess/sys.h> -int Net_OpenSocket(int AddrType, void *Addr, const char *Filename) +enum { + UDP_IOCTL_GETSETLPORT = 4, + UDP_IOCTL_GETSETRPORT, + UDP_IOCTL_GETSETRMASK, + UDP_IOCTL_SETRADDR, + UDP_IOCTL_SENDTO, + UDP_IOCTL_RECVFROM, +}; + +int Net_OpenSocket(int AddrType, const void *Addr, const char *Filename) { int addrLen = Net_GetAddressSize(AddrType); - int i; - uint8_t *addrBuffer = Addr; char hexAddr[addrLen*2+1]; - for( i = 0; i < addrLen; i ++ ) - sprintf(hexAddr+i*2, "%02x", addrBuffer[i]); + { + const uint8_t *addrBuffer = Addr; + for( unsigned int i = 0; i < addrLen; i ++ ) + sprintf(hexAddr+i*2, "%02x", addrBuffer[i]); + } if(Filename) { @@ -37,14 +48,82 @@ int Net_OpenSocket(int AddrType, void *Addr, const char *Filename) } } -int Net_OpenSocket_TCPC(int AddrType, void *Addr, int Port) +int Net_OpenSocket_TCPC(int AddrType, const void *Addr, int Port) { int fd = Net_OpenSocket(AddrType, Addr, "tcpc"); if( fd == -1 ) return -1; - _SysIOCtl(fd, 5, &Port); // Remote Port - _SysIOCtl(fd, 6, Addr); // Remote address - _SysIOCtl(fd, 7, NULL); // connect + if( _SysIOCtl(fd, 5, &Port) < 0 ) // Remote Port + goto err; + if( _SysIOCtl(fd, 6, (void*)Addr) < 0 ) // Remote address (kernel shouldn't modify) + goto err; + if( _SysIOCtl(fd, 7, NULL) < 0) // connect + goto err; + return fd; +err: + _SysClose(fd); + return -1; +} + +int Net_OpenSocket_UDP(int AddrType, const void *Addr, int RPort, int LPort) +{ + int fd = Net_OpenSocket(AddrType, Addr, "udp"); + if( fd == -1 ) return -1; + + if( _SysIOCtl(fd, UDP_IOCTL_GETSETLPORT, &LPort) < 0 ) + goto err; + if( _SysIOCtl(fd, UDP_IOCTL_GETSETRPORT, &RPort) < 0 ) + goto err; + int maskbits = Net_GetAddressSize(AddrType) * 8; + if( _SysIOCtl(fd, UDP_IOCTL_GETSETRMASK, &maskbits) < 0 ) + goto err; + if( _SysIOCtl(fd, UDP_IOCTL_SETRADDR, (void*)Addr) < 0 ) // Remote address (kernel shouldn't modify) + goto err; return fd; +err: + _SysClose(fd); + return -1; +} + +int Net_UDP_SendTo(int FD, int Port, int AddrType, const void *Addr, size_t Length, const void *Data) +{ + struct { + uint16_t port; + uint16_t addr_type; + char addr[16]; + } ep; + ep.port = Port; + ep.addr_type = AddrType; + memcpy(ep.addr, Addr, Net_GetAddressSize(AddrType)); + struct { + const void *ep; + const void *buf; + uint16_t len; + } info = { .ep = &ep, .buf = Data, .len = Length }; + + return _SysIOCtl(FD, UDP_IOCTL_SENDTO, &info); +} + +int Net_UDP_RecvFrom(int FD, int* Port, int* AddrType, void *Addr, size_t Length, void *Data) +{ + struct { + uint16_t port; + uint16_t addr_type; + char addr[16]; + } ep; + struct { + void *ep; + void *buf; + uint16_t len; + } info = { .ep = &ep, .buf = Data, .len = Length }; + + int rv = _SysIOCtl(FD, UDP_IOCTL_RECVFROM, &info); + if( rv > 0 ) + { + if(Port) *Port = ep.port; + if(AddrType) *AddrType = ep.addr_type; + if(Addr) memcpy(Addr, ep.addr, Net_GetAddressSize(ep.addr_type)); + } + return rv; } diff --git a/Usermode/Libraries/libposix.so_src/Makefile b/Usermode/Libraries/libposix.so_src/Makefile index dcbf8f5392b0addcda4a1171b7bed2edf99d9b94..eb2fd2f2df5a77d7b01f8b2a46da31f7a8de80d3 100644 --- a/Usermode/Libraries/libposix.so_src/Makefile +++ b/Usermode/Libraries/libposix.so_src/Makefile @@ -6,12 +6,14 @@ CPPFLAGS += CFLAGS += -Wextra ASFLAGS += -LDFLAGS += -soname libposix.so -Map map.txt -lc +LDFLAGS += -nostdlib +PRELINK += $(CRTI) $(CRTBEGINS) $(CRT0S) +LIBS += -lc $(CRTENDS) $(CRTN) OBJ = main.o unistd.o dirent.o stat.o utmpx.o termios.o OBJ += pwd.o syslog.o sys_time.o sys_ioctl.o sys_resource.o OBJ += fcntl.o clocks.o sys_wait.o unistd_crypt.o -OBJ += grp.o pty.o mktemp.o utime.o +OBJ += grp.o pty.o mktemp.o utime.o getopt.o DEPFILES := $(OBJ:%.o=%.d) BIN = libposix.so diff --git a/Usermode/Libraries/libposix.so_src/getopt.c b/Usermode/Libraries/libposix.so_src/getopt.c new file mode 100644 index 0000000000000000000000000000000000000000..ab6186bba5def8d7827fafebcdaf242fd38cb7a5 --- /dev/null +++ b/Usermode/Libraries/libposix.so_src/getopt.c @@ -0,0 +1,21 @@ +/* + * Acess2 POSIX Emulation Layer + * - By John Hodge (thePowersGang) + * + * getopt.c + * - getopt() command line parsing code + */ +#include <getopt.h> + +// === GLOBALS === +char* optarg; + int opterr; + int optind; + int optopt; + +// === CODE === +int getopt(int argc, char * const argv[], const char *optstring) +{ + return -1; +} + diff --git a/Usermode/Libraries/libposix.so_src/include_exp/endian.h b/Usermode/Libraries/libposix.so_src/include_exp/endian.h new file mode 100644 index 0000000000000000000000000000000000000000..a70ec0d737852070bfae67d61d9e4e725ae85e27 --- /dev/null +++ b/Usermode/Libraries/libposix.so_src/include_exp/endian.h @@ -0,0 +1,11 @@ +/* + */ +#ifndef _LIBPOSIX_ENDIAN_H_ +#define _LIBPOSIX_ENDIAN_H_ + +#define __LITTLE_ENDIAN 0 +#define __BIG_ENDIAN 0 +#define __BYTE_ORDER __LITTLE_ENDIAN + +#endif + diff --git a/Usermode/Libraries/libposix.so_src/include_exp/getopt.h b/Usermode/Libraries/libposix.so_src/include_exp/getopt.h new file mode 100644 index 0000000000000000000000000000000000000000..b6db119ef9445edb4922fba9dff62a7f2088188a --- /dev/null +++ b/Usermode/Libraries/libposix.so_src/include_exp/getopt.h @@ -0,0 +1,27 @@ +/* + * Acess2 POSIX Emulation Layer + * - By John Hodge (thePowersGang) + * + * getopt.h + * - getopt() command line parsing code + */ +#ifndef _LIBPOSIX_GETOPT_H_ +#define _LIBPOSIX_GETOPT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern char* optarg; +extern int opterr; +extern int optind; +extern int optopt; + +extern int getopt(int argc, char * const argv[], const char *optstring); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/Usermode/Libraries/libposix.so_src/include_exp/glob.h b/Usermode/Libraries/libposix.so_src/include_exp/glob.h new file mode 100644 index 0000000000000000000000000000000000000000..ff96b8e600f755972074a0078681c9b9750a6270 --- /dev/null +++ b/Usermode/Libraries/libposix.so_src/include_exp/glob.h @@ -0,0 +1,13 @@ +/* + * Acess2 POSIX Emulation Library + * - By John Hodge (thePowersGang) + * + * glob.h + * - Globbing code + */ +#ifndef _LIBPOSIX__GLOB_H_ +#define _LIBPOSIX__GLOB_H_ + + + +#endif diff --git a/Usermode/Libraries/libposix.so_src/include_exp/regex.h b/Usermode/Libraries/libposix.so_src/include_exp/regex.h new file mode 100644 index 0000000000000000000000000000000000000000..ebbe6b631e4b9d1a8a871f09958a6829b527e8dd --- /dev/null +++ b/Usermode/Libraries/libposix.so_src/include_exp/regex.h @@ -0,0 +1,41 @@ +/* + * Acess2 POSIX Emulation Library + * - By John Hodge (thePowersGang) + * + * regex.h + * - POSIX regular expression support + */ +#ifndef _LIBPOSIX_REGEX_H_ +#define _LIBPOSIX_REGEX_H_ + +typedef struct { + void *unused; +} regex_t; + +typedef size_t regoff_t; + +typedef struct { + regoff_t rm_so; + regoff_t rm_eo; +} regmatch_t; + +extern int regcomp(regex_t *preg, const char *regex, int cflags); +extern int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags); +extern size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size); +extern void regfree(regex_t *preg); + +enum { + REG_BADBR = 1, + REG_BADPAT, + REG_BADRPT, +}; + +#define REG_EXTENDED 0x1 +#define REG_ICASE 0x2 +#define REG_NOSUB 0x4 +#define REG_NEWLINE 0x8 + + +#endif + + diff --git a/Usermode/Libraries/libposix.so_src/include_exp/strings.h b/Usermode/Libraries/libposix.so_src/include_exp/strings.h new file mode 100644 index 0000000000000000000000000000000000000000..9c4114d988135744e02bdcf1d717dfe45f7e2fc8 --- /dev/null +++ b/Usermode/Libraries/libposix.so_src/include_exp/strings.h @@ -0,0 +1,14 @@ +/* + * Acess2 POSIX Emulation Library + * - By John Hodge (thePowersGang) + * + * strings.h + * - BSD's verison of string.h + */ +#ifndef _LIBPOSIX_STRINGS_H_ +#define _LIBPOSIX_STRINGS_H_ + + + +#endif + diff --git a/Usermode/Libraries/libposix.so_src/include_exp/unistd.h b/Usermode/Libraries/libposix.so_src/include_exp/unistd.h index 6519b3b77d978fbd73a2f4c6166437fa17e774d3..10c4779faa76baaa42eacc29745e75bfaa8aabad 100644 --- a/Usermode/Libraries/libposix.so_src/include_exp/unistd.h +++ b/Usermode/Libraries/libposix.so_src/include_exp/unistd.h @@ -71,6 +71,10 @@ extern int chmod(const char *path, mode_t mode); extern int unlink(const char *pathname); +#define F_OK 00 +#define R_OK 04 +#define W_OK 02 +#define X_OK 01 extern int access(const char *pathname, int mode); extern pid_t setsid(void); @@ -93,6 +97,7 @@ extern unsigned int alarm(unsigned int seconds); extern char *crypt(const char *key, const char *salt); // - pty.c +extern int isatty(int fd); extern char *ttyname(int fd); extern int ttyname_r(int fd, char *buf, size_t buflen); diff --git a/Usermode/Libraries/libposix.so_src/mktemp.c b/Usermode/Libraries/libposix.so_src/mktemp.c index 863b9256b360577789e6d39dd2a8979b78923ed8..2cc5f2ad55f40dc4ed65c5b7657f985a8912cb3b 100644 --- a/Usermode/Libraries/libposix.so_src/mktemp.c +++ b/Usermode/Libraries/libposix.so_src/mktemp.c @@ -7,6 +7,7 @@ */ #include <unistd.h> // mktemp #include <stdlib.h> // mkstemp +#include <stdio.h> #include <string.h> // str* #include <errno.h> @@ -25,7 +26,7 @@ int mkstemp(char *template) for( int i = 0; i < 1000000; i ++ ) { - sprintf(template+tpl_len-6, "%06d", i); + snprintf(template+tpl_len-6, 6+1, "%06d", i); int fd = open(template, O_EXCL|O_CREAT, 0600); if(fd == -1) continue ; diff --git a/Usermode/Libraries/libposix.so_src/unistd.c b/Usermode/Libraries/libposix.so_src/unistd.c index 3af7bcbc34f15cf7f54e38051a5f3112c3a83c4a..dca29630e7e2f5b5e7a60175e681cd77df76e6df 100644 --- a/Usermode/Libraries/libposix.so_src/unistd.c +++ b/Usermode/Libraries/libposix.so_src/unistd.c @@ -292,3 +292,21 @@ int ttyname_r(int fd, char *buf, size_t buflen) return ENOTIMPL; } + +int isatty(int fd) +{ + if( fd < 0 ) { + errno = EBADF; + return 0; + } + + int type = _SysIOCtl(fd, DRV_IOCTL_TYPE, NULL); + if( type == -1 ) + return 0; + if( type != DRV_TYPE_TERMINAL ) { + errno = ENOTTY; + // NOTE: Pre POSIX 2001, EINVAL was returned + return 0; + } + return 1; +} diff --git a/Usermode/Libraries/libpsocket.so_src/Makefile b/Usermode/Libraries/libpsocket.so_src/Makefile index 0ad326e5b4f18d29dc85def41d3144cde31a85e0..65f7380bea07373d2d5a1541861e85d077081add 100644 --- a/Usermode/Libraries/libpsocket.so_src/Makefile +++ b/Usermode/Libraries/libpsocket.so_src/Makefile @@ -4,7 +4,8 @@ include ../Makefile.cfg CPPFLAGS += CFLAGS += -Wall -LDFLAGS += -lc -soname libpsocket.so -lnet +LDFLAGS += -lc -soname libpsocket.so +LIBS += -lnet OBJ = main.o getaddrinfo.o socket.o pton.o byteordering.o BIN = libpsocket.so diff --git a/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c b/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c index 5c21c06ea555621970653f23049a3e832a75a6c9..e1a0e424a4266a297d44e08e594600cc262bdd5d 100644 --- a/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c +++ b/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c @@ -13,6 +13,16 @@ #include <stdlib.h> // strtol #include <acess/sys.h> +// === TYPES === +struct sLookupInfo { + struct addrinfo **ret_p; +}; + +// === PROTOTYPES === +struct addrinfo *int_new_addrinfo(int af, const void *addrdata); +int int_getaddinfo_lookupcb(void *info, int addr_type, const void *addr); + +// === GLOBALS === static const struct { const char *Name; int SockType; @@ -52,28 +62,20 @@ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hi { // 1. Check if the node is an IP address { - int type; char addrdata[16]; - type = Net_ParseAddress(node, addrdata); + int type = Net_ParseAddress(node, addrdata); switch(type) { - case 0: + case NET_ADDRTYPE_NULL: break; - case 4: // IPv4 - ret = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in)); - ret->ai_family = AF_INET; - ret->ai_socktype = 0; - ret->ai_protocol = 0; - ret->ai_addrlen = sizeof(struct in_addr); - ret->ai_addr = (void*)( ret + 1 ); - ret->ai_canonname = 0; - ret->ai_next = 0; - ((struct sockaddr_in*)ret->ai_addr)->sin_family = AF_INET; - ((struct sockaddr_in*)ret->ai_addr)->sin_port = 0; - memcpy( &((struct sockaddr_in*)ret->ai_addr)->sin_addr, addrdata, 4 ); + case NET_ADDRTYPE_IPV4: + ret = int_new_addrinfo(AF_INET, addrdata); + break; + case NET_ADDRTYPE_IPV6: + ret = int_new_addrinfo(AF_INET6, addrdata); break; default: - _SysDebug("getaddrinfo: Unknown address family %i", type); + _SysDebug("getaddrinfo: Unknown address type %i", type); return 1; } } @@ -82,15 +84,19 @@ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hi // - No luck with above, and hints->ai_flags doesn't have AI_NUMERICHOST set if( !ret && !(hints->ai_flags & AI_NUMERICHOST) ) { - _SysDebug("getaddrinfo: TODO DNS Lookups"); - // TODO: DNS Lookups - // ? /Acess/Conf/Nameservers - // ? /Acess/Conf/Hosts - //count = Net_LookupDNS(node, service, NULL); - // + // Just does a basic A record lookup + // TODO: Support SRV records + // TODO: Ensure that CNAMEs are handled correctly + struct sLookupInfo info = { + .ret_p = &ret, + }; + if( Net_Lookup_Addrs(node, &info, int_getaddinfo_lookupcb) ) { + // Lookup failed, quick return + return EAI_NONAME; + } } - // 3. No Match, chuck sad + // 3. No Match, return sad if( !ret ) { return EAI_NONAME; @@ -182,9 +188,81 @@ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hi return 0; } +/** + * \brief Allocate a new zeroed addrinfo for the specified address + */ +struct addrinfo *int_new_addrinfo(int af, const void *addrdata) +{ + size_t addrlen = 0; + switch(af) + { + case AF_INET: + addrlen = sizeof(struct sockaddr_in); + break; + case AF_INET6: + addrlen = sizeof(struct sockaddr_in6); + break; + default: + _SysDebug("int_new_addrinfo: ERROR - Unknown AF %i", af); + return NULL; + } + struct addrinfo* ret = malloc(sizeof(struct addrinfo) + addrlen); + ret->ai_family = af; + ret->ai_socktype = 0; + ret->ai_protocol = 0; + ret->ai_addrlen = addrlen; + ret->ai_addr = (void*)( ret + 1 ); + ret->ai_canonname = 0; + ret->ai_next = 0; + switch(af) + { + case AF_INET: + ((struct sockaddr_in*)ret->ai_addr)->sin_family = AF_INET; + ((struct sockaddr_in*)ret->ai_addr)->sin_port = 0; + memcpy( &((struct sockaddr_in*)ret->ai_addr)->sin_addr, addrdata, 4 ); + break; + case AF_INET6: + ((struct sockaddr_in6*)ret->ai_addr)->sin6_family = AF_INET6; + ((struct sockaddr_in6*)ret->ai_addr)->sin6_port = 0; + memcpy( &((struct sockaddr_in6*)ret->ai_addr)->sin6_addr, addrdata, 16 ); + break; + default: + _SysDebug("int_new_addrinfo: BUGCHECK - Unhandled AF %i", af); + return NULL; + } + return ret; +} + +// Callback for getaddrinfo's call to Net_Lookup_Addrs +int int_getaddinfo_lookupcb(void *info_v, int addr_type, const void *addr) +{ + struct sLookupInfo *info = info_v; + struct addrinfo *ent; + switch( addr_type ) + { + case NET_ADDRTYPE_IPV4: + ent = int_new_addrinfo(AF_INET, addr); + break; + case NET_ADDRTYPE_IPV6: + ent = int_new_addrinfo(AF_INET6, addr); + break; + default: + // Huh... unknown address type, just ignore it + return 0; + } + ent->ai_next = *info->ret_p; + *info->ret_p = ent; + return 0; +} + void freeaddrinfo(struct addrinfo *res) { - + while( res ) + { + struct addrinfo *next = res->ai_next; + free(res); + res = next; + } } int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) diff --git a/Usermode/Libraries/libpthread.so_src/Makefile b/Usermode/Libraries/libpthread.so_src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0870c0cfbefa24182ae15af3d268f7074c7ff110 --- /dev/null +++ b/Usermode/Libraries/libpthread.so_src/Makefile @@ -0,0 +1,12 @@ +# Acess 2 - POSIX Threads + +include ../Makefile.cfg + +CPPFLAGS += +CFLAGS += -Wall +LDFLAGS += -lc -soname libpthread.so + +OBJ = main.o thread.o +BIN = libpthread.so + +include ../Makefile.tpl diff --git a/Usermode/Libraries/libpthread.so_src/include_exp/pthread.h b/Usermode/Libraries/libpthread.so_src/include_exp/pthread.h new file mode 100644 index 0000000000000000000000000000000000000000..376fb0e2b69c0cb35b28756a7bbba9042e0ce82a --- /dev/null +++ b/Usermode/Libraries/libpthread.so_src/include_exp/pthread.h @@ -0,0 +1,95 @@ +/* + * Acess2 libpthread + * - By John Hodge (thePowersGang) + * + * pthread.h + * - Core POSIX threads header + */ +#ifndef _LIBPTHREAT_PTHREAD_H_ +#define _LIBPTHREAT_PTHREAD_H_ + +// XXX: Hack - libgcc doesn't seem to be auto-detecting the presence of this header +#include "sched.h" + +//! \name pthread core +//! \{ +typedef struct pthread_attr_s pthread_attr_t; + +struct pthread_s +{ + void* retval; + unsigned int kernel_handle; +}; +typedef struct pthread_s pthread_t; + +extern int pthread_create(pthread_t *threadptr, const pthread_attr_t * attrs, void* (*fcn)(void*), void* arg); +extern int pthread_detach(pthread_t thread); +extern int pthread_join(pthread_t thread, void **retvalptr); +extern int pthread_cancel(pthread_t thread); +extern int pthread_equal(pthread_t t1, pthread_t t2); +extern pthread_t pthread_self(void); +extern void pthread_exit(void* retval); +//! } + + +//! \name pthread_once +//! \{ +struct pthread_once_s +{ + int flag; +}; +#define PTHREAD_ONCE_INIT ((struct pthread_once_s){.flag=0}) +typedef struct pthread_once_s pthread_once_t; +extern int pthread_once(pthread_once_t *once_contol, void (*init_routine)(void)); +//! \} + +//! \name pthread mutexes +//! \{ +#define PTHREAD_MUTEX_NORMAL 0 +#define PTHREAD_MUTEX_RECURSIVE 1 +struct pthread_mutexattr_s +{ + int type; +}; +typedef struct pthread_mutexattr_s pthread_mutexattr_t; +extern int pthread_mutexattr_init(pthread_mutexattr_t *attrs); +extern int pthread_mutexattr_settype(pthread_mutexattr_t *attrs, int type); +extern int pthread_mutexattr_destroy(pthread_mutexattr_t *attrs); + +struct pthread_mutex_s +{ + void* futex; +}; +#define PTHREAD_MUTEX_INITIALIZER ((struct pthread_mutex_s){0}) +typedef struct pthread_mutex_s pthread_mutex_t; +extern int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t *attrs); +extern int pthread_mutex_lock(pthread_mutex_t *lock); +extern int pthread_mutex_trylock(pthread_mutex_t *lock); +extern int pthread_mutex_unlock(pthread_mutex_t *lock); +extern int pthread_mutex_destroy(pthread_mutex_t *lock); +//! \} + +//! \name pthread TLS keys +//! \{ +//typedef struct pthread_key_s pthread_key_t; +typedef unsigned int pthread_key_t; +extern int pthread_key_create(pthread_key_t *keyptr, void (*fcn)(void*)); +extern int pthread_key_delete(pthread_key_t key); +extern int pthread_setspecific(pthread_key_t key, const void* data); +extern void* pthread_getspecific(pthread_key_t key); +//! \} + +//! \name pthread condvars +//! \{ +typedef struct pthread_cond_s pthread_cond_t; +typedef struct pthread_condattr_s pthread_condattr_t; +extern int pthread_cond_init(pthread_cond_t *condptr, const pthread_condattr_t* attrs); +extern int pthread_cond_wait(pthread_cond_t *condptr, pthread_mutex_t *mutex); +extern int pthread_cond_timedwait(pthread_cond_t *condptr, pthread_mutex_t *mutex, const struct timespec *timeout); +extern int pthread_cond_signal(pthread_cond_t *condptr); +extern int pthread_cond_broadcast(pthread_cond_t *condptr); +extern int pthread_cond_destroy(pthread_cond_t *condptr); +//! \} + +#endif + diff --git a/Usermode/Libraries/libpthread.so_src/include_exp/sched.h b/Usermode/Libraries/libpthread.so_src/include_exp/sched.h new file mode 100644 index 0000000000000000000000000000000000000000..8366ba22d4d9d68196a50f2e08d30bd299359bc3 --- /dev/null +++ b/Usermode/Libraries/libpthread.so_src/include_exp/sched.h @@ -0,0 +1,15 @@ +/* + * Acess2 libpthread + * - By John Hodge (thePowersGang) + * + * sched.h + * - Execution Scheduling (POSIX Realtime Extensions) + */ +#ifndef _LIBPTHREAT_SCHED_H_ +#define _LIBPTHREAT_SCHED_H_ + +// *grumble* libgcc wants a yield +extern int sched_yield(void); + +#endif + diff --git a/Usermode/Libraries/libpthread.so_src/main.c b/Usermode/Libraries/libpthread.so_src/main.c new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Usermode/Libraries/libpthread.so_src/thread.c b/Usermode/Libraries/libpthread.so_src/thread.c new file mode 100644 index 0000000000000000000000000000000000000000..4b5f51fee5388794c2da727186f4bc2e47bcfe58 --- /dev/null +++ b/Usermode/Libraries/libpthread.so_src/thread.c @@ -0,0 +1,44 @@ +/* + * Acess2 libpthread + * - By John Hodge (thePowersGang) + * + * thread.c + * - Thread management for pthreads + */ +#include <pthread.h> +#include <assert.h> + +int pthread_create(pthread_t *threadptr, const pthread_attr_t * attrs, void* (*fcn)(void*), void* arg) +{ + assert(!"TODO: pthread_create"); + return 0; +} +int pthread_detach(pthread_t thread) +{ + assert(!"TODO: pthread_detach"); + return 0; +} +int pthread_join(pthread_t thread, void **retvalptr) +{ + assert(!"TODO: pthread_join"); + return 0; +} +int pthread_cancel(pthread_t thread) +{ + assert(!"TODO: pthread_cancel"); + return 0; +} +int pthread_equal(pthread_t t1, pthread_t t2) +{ + assert(!"TODO: pthread_equal"); + return 0; +} +pthread_t pthread_self(void) +{ + assert(!"TODO: pthread_self"); + return (pthread_t){0}; +} +void pthread_exit(void* retval) +{ + assert(!"TODO: pthread_create"); +} diff --git a/Usermode/Libraries/libresolv.so_src/Makefile b/Usermode/Libraries/libresolv.so_src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..21eb942d6567d093d5a54d7d0739b44f0596e9d3 --- /dev/null +++ b/Usermode/Libraries/libresolv.so_src/Makefile @@ -0,0 +1,16 @@ +# Acess2 BSD "resolv" library +# Makefile + +-include ../Makefile.cfg + +CPPFLAGS += +CFLAGS += -Wextra +ASFLAGS += +LDFLAGS += +LIBS += -lnet -lpsocket + +OBJ = resolv.o +BIN = libresolv.so + +include ../Makefile.tpl + diff --git a/Usermode/Libraries/libresolv.so_src/include_exp/arpa/nameser.h b/Usermode/Libraries/libresolv.so_src/include_exp/arpa/nameser.h new file mode 100644 index 0000000000000000000000000000000000000000..5f2532b5b3553c7aea06cd72d28d326f42f29dd0 --- /dev/null +++ b/Usermode/Libraries/libresolv.so_src/include_exp/arpa/nameser.h @@ -0,0 +1,16 @@ +/* + * Acess2 POSIX Sockets Emulation + * - By John Hodge (thePowersGang) + * + * arpa/nameser.h + * - BSD name resolution (TODO: move to libresolv) + * + * NOTE: I have no fucking idea who/what defines this header, it's wanted by glib + */ +#ifndef _LIBPSOCKET__ARPA_NAMESER_H_ +#define _LIBPSOCKET__ARPA_NAMESER_H_ + +#define C_IN 0x1 + +#endif + diff --git a/Usermode/Libraries/libresolv.so_src/include_exp/resolv.h b/Usermode/Libraries/libresolv.so_src/include_exp/resolv.h new file mode 100644 index 0000000000000000000000000000000000000000..66d965731b0aa085df97727b43f7fb897cb5d71b --- /dev/null +++ b/Usermode/Libraries/libresolv.so_src/include_exp/resolv.h @@ -0,0 +1,20 @@ +/* + */ +#ifndef _LIBRESOLV__RESOLV_H_ +#define _LIBRESOLV__RESOLV_H_ + +extern int res_init(void); + +extern int res_query(const char *dname, int class, int type, unsigned char *answer, int anslen); + +extern int res_search(const char *dname, int class, int type, unsigned char *answer, int anslen); + +extern int res_querydomain(const char *name, const char *domain, int class, int type, unsigned char *answer, int anslen); + +extern int res_mkquery(int op, const char *dname, int class, int type, char *data, int datalen, struct rrec *newrr, char *buf, int buflen); + +extern int res_send(const char *msg, int msglen, char *answer, int anslen); + + +#endif + diff --git a/Usermode/Libraries/libresolv.so_src/resolv.c b/Usermode/Libraries/libresolv.so_src/resolv.c new file mode 100644 index 0000000000000000000000000000000000000000..e8d121bea636a13f34c4bbdc38eef4abff18c137 --- /dev/null +++ b/Usermode/Libraries/libresolv.so_src/resolv.c @@ -0,0 +1,33 @@ +/* + */ + +int res_init(void) +{ + return 1; +} + +int res_query(const char *dname, int class, int type, unsigned char *answer, int anslen) +{ + return 1; +} + +int res_search(const char *dname, int class, int type, unsigned char *answer, int anslen) +{ + return 1; +} + +int res_querydomain(const char *name, const char *domain, int class, int type, unsigned char *answer, int anslen) +{ + return 1; +} + +int res_mkquery(int op, const char *dname, int class, int type, char *data, int datalen, struct rrec *newrr, char *buf, int buflen) +{ + return 1; +} + +int res_send(const char *msg, int msglen, char *answer, int anslen) +{ + return 1; +} + diff --git a/Usermode/Libraries/libunicode.so_src/include_exp/unicode.h b/Usermode/Libraries/libunicode.so_src/include_exp/unicode.h index ef0eb56e04153bdfe6d9637da9158baf0a7c8163..6c7e3e4a4edaff22dac3c4d1f70582c9239383da 100644 --- a/Usermode/Libraries/libunicode.so_src/include_exp/unicode.h +++ b/Usermode/Libraries/libunicode.so_src/include_exp/unicode.h @@ -10,6 +10,10 @@ #include <stdint.h> +#ifdef __cplusplus +extern "C" { +#endif + /** * \breif Read a single codepoint from a UTF-8 stream * \return Number of bytes read @@ -27,5 +31,102 @@ extern int WriteUTF8(char *buf, uint32_t Val); static inline int Unicode_IsPrinting(uint32_t Codepoint) { return 1; } +#ifdef __cplusplus +} // extern "C" +#endif + +#ifdef __cplusplus +#include <iterator> + +namespace libunicode { + +class utf8iterator: + public ::std::iterator< ::std::forward_iterator_tag, uint32_t > +{ + const char* m_curpos; + uint32_t m_curval; +public: + utf8iterator(): + m_curpos(0) + { + } + utf8iterator(const char *pos): + m_curpos(pos) + { + (*this)++; + } + utf8iterator(const utf8iterator& other) { + m_curpos = other.m_curpos; + m_curval = other.m_curval; + } + utf8iterator& operator=(const utf8iterator& other) { + m_curpos = other.m_curpos; + m_curval = other.m_curval; + return *this; + } + + bool operator== (const utf8iterator& other) { + return other.m_curpos == m_curpos; + } + bool operator!= (const utf8iterator& other) { + return other.m_curpos != m_curpos; + } + utf8iterator& operator++() { + m_curpos += ::ReadUTF8(m_curpos, &m_curval); + return *this; + } + utf8iterator operator++(int) { + utf8iterator rv(*this); + m_curpos += ::ReadUTF8(m_curpos, &m_curval); + return rv; + } + uint32_t operator*() const { + return m_curval; + } + uint32_t operator->() const { + return m_curval; + } +}; + +class utf8string +{ + const char* m_data; + size_t m_len; + + size_t _strlen(const char*s) { + size_t l = 0; + while(*s) l ++; + return l; + } +public: + utf8string(const char* c_str): + m_data(c_str), + m_len(_strlen(c_str)) + { + } + utf8string(const char* c_str, size_t len): + m_data(c_str), + m_len(len) + { + } + utf8string(const ::std::string& str): + m_data(str.c_str()), + m_len(str.size()) + { + } + + utf8iterator begin() const { + return utf8iterator(m_data); + } + utf8iterator end() const { + return utf8iterator(m_data + m_len); + } +}; + + +}; + +#endif + #endif diff --git a/Usermode/common_settings.mk b/Usermode/common_settings.mk index 519b0fd353097e770f5e469b1844d02b454d7b26..2f6fa8f4d867beb51f4376bcddb06c4f9ec84f39 100644 --- a/Usermode/common_settings.mk +++ b/Usermode/common_settings.mk @@ -5,3 +5,14 @@ CPPFLAGS += -I$(ACESSUSERDIR)/include/ -DARCHDIR_is_$(ARCHDIR) CPPFLAGS += -I $(ACESSDIR)/Externals/Output/$(ARCHDIR)/include CFLAGS += -std=gnu99 -g LDFLAGS += -L $(ACESSDIR)/Externals/Output/$(ARCHDIR)/lib +LDFLAGS += -L $(OUTPUTDIR)Libs + +CRTI := $(OUTPUTDIR)Libs/crti.o +CRTBEGIN := $(shell $(CC) $(CFLAGS) -print-file-name=crtbegin.o 2>/dev/null) +CRTBEGINS := $(shell $(CC) $(CFLAGS) -print-file-name=crtbeginS.o 2>/dev/null) +CRT0 := $(OUTPUTDIR)Libs/crt0.o +CRT0S := $(OUTPUTDIR)Libs/crt0S.o +CRTEND := $(shell $(CC) $(CFLAGS) -print-file-name=crtend.o 2>/dev/null) +CRTENDS := $(shell $(CC) $(CFLAGS) -print-file-name=crtendS.o 2>/dev/null) +CRTN := $(OUTPUTDIR)Libs/crtn.o +LIBGCC_PATH = $(shell $(CC) -print-libgcc-file-name 2>/dev/null)