*.gz
*.img
*.vmdk
+*.iso
SrcDoc/
APIDoc/
Usermode/*/*/UTEST/stage
#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"
.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)
--- /dev/null
+#!/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
+
#!/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 $*
#!/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
LDACESS_SRC = ../../Usermode/Libraries/ld-acess.so_src/\r
\r
# - Kernel objects (from KernelLand/Kernel)\r
-KERNEL_OBJ := logging.o adt.o lib.o debug.o messages.o drvutil_disk.o drvutil_video.o\r
+KERNEL_OBJ := logging.o adt.o lib.o debug.o messages.o drvutil_disk.o drvutil_video.o memfs_helpers.o\r
KERNEL_OBJ += mutex.o semaphore.o rwlock.o workqueue.o events.o\r
#KERNEL_OBJ += libc.o\r
KERNEL_OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/io.o vfs/dir.o\r
# - Local objects (use the kernel includes)\r
OBJ := helpers.o threads.o threads_glue.o server.o syscalls.o time.o\r
OBJ += video.o keyboard.o mouse.o nativefs.o vfs_handle.o ui_sdl.o\r
+#OBJ += shm.o\r
OBJ += net.o syscall_getpath.o\r
\r
BUILDINFO_OBJ := obj-$(PLATFORM)/buildinfo.o\r
CFLAGS += -Wall -g -std=gnu99\r
CPPFLAGS += $(shell sdl-config --cflags) -I /usr/include/\r
LDFLAGS += $(shell sdl-config --libs) -g -Wl,--defsym,__buildnum=$(BUILD_NUM)\r
+LDFLAGS += -Wl,-Map,obj-$(PLATFORM)/Map.txt\r
\r
ifeq ($(PLATFORM),win)\r
BIN := ../AcessKernel.exe\r
typedef int BOOL;
+extern void exit(int status) __attribute__((noreturn));
#define HALT_CPU() exit(1)
#include <stddef.h>
#endif
#include <unistd.h>
#include <string.h>
+#include <stdbool.h>
#include "../../KernelLand/Kernel/include/logdebug.h"
#define VALGRIND_CLIENT 0
VFS_MkDir("/Acess");
VFS_Mount(gsAcessDir, "/Acess", "nativefs", "");
- Debug_SetKTerminal("/Devices/pts/vt7c");
+ Debug_SetKTerminal("/Devices/pts/vt7");
// Start syscall server
SyscallServer();
#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>
*/
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
#include <SDL/SDL.h>
#ifdef __WIN32__
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 )
{
}
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)
{
#include <pthread.h>
#define NORETURN __attribute__((noreturn))
+#include <stdbool.h>
#include <logdebug.h> // Kernel land, but uses standards
#include <errno.h>
ent = VFS_int_GetUserHandles(PID, 1);
- maxhandles = *Threads_GetMaxFD();
+ maxhandles = *Threads_GetMaxFD(NULL);
memcpy(ent->Handles, cur->Handles, maxhandles*sizeof(tVFS_Handle));
// Reference all
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 ++ )
else
{
int pid = Threads_GetPID();
- int maxhandles = *Threads_GetMaxFD();
+ int maxhandles = *Threads_GetMaxFD(NULL);
tUserHandles *ent = VFS_int_GetUserHandles(pid, 0);
if(!ent) {
else {
tUserHandles *ent;
int pid = Threads_GetPID();
- int maxhandles = *Threads_GetMaxFD();
+ int maxhandles = *Threads_GetMaxFD(NULL);
ent = VFS_int_GetUserHandles(pid, 0);
if(!ent) {
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
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;
};
tDevFS_Driver gVideo_DriverStruct = {
NULL, "NativeVideo",
- {.Type = &gVideo_NodeType}
+ {
+ .Type = &gVideo_NodeType
+ }
};
int giVideo_DriverID;
int giVideo_CurrentFormat;
// 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:
* - 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>
}
}
-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;
// 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) )
#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;
\r
void *Elf32Load(int FD, Elf32_Ehdr *hdr)\r
{\r
- Elf32_Phdr *phtab;\r
- int i;\r
- int iPageCount;\r
- uint32_t max, base;\r
- uint32_t addr;\r
- uint32_t baseDiff = 0;\r
- \r
ENTER("iFD", FD);\r
\r
// Check for a program header\r
- if(hdr->phoff == 0) {\r
+ if(hdr->e_phoff == 0) {\r
#if DEBUG_WARN\r
Warning("ELF File does not contain a program header\n");\r
#endif\r
}\r
\r
// Read Program Header Table\r
- phtab = malloc( sizeof(Elf32_Phdr) * hdr->phentcount );\r
+ Elf32_Phdr* phtab = malloc( sizeof(Elf32_Phdr) * hdr->e_phnum );\r
if( !phtab ) {\r
LEAVE('n');\r
return NULL;\r
}\r
- LOG("hdr.phoff = 0x%08x\n", hdr->phoff);\r
- acess__SysSeek(FD, hdr->phoff, ACESS_SEEK_SET);\r
- acess__SysRead(FD, phtab, sizeof(Elf32_Phdr) * hdr->phentcount);\r
+ LOG("hdr.e_phoff = 0x%08x\n", hdr->e_phoff);\r
+ acess__SysSeek(FD, hdr->e_phoff, ACESS_SEEK_SET);\r
+ acess__SysRead(FD, phtab, sizeof(Elf32_Phdr) * hdr->e_phnum);\r
\r
// Count Pages\r
- iPageCount = 0;\r
- LOG("hdr.phentcount = %i\n", hdr->phentcount);\r
- for( i = 0; i < hdr->phentcount; i++ )\r
+ unsigned int iPageCount = 0;\r
+ LOG("hdr.e_phnum = %i\n", hdr->e_phnum);\r
+ for( unsigned int i = 0; i < hdr->e_phnum; i++ )\r
{\r
// Ignore Non-LOAD types\r
- if(phtab[i].Type != PT_LOAD)\r
+ if(phtab[i].p_type != PT_LOAD)\r
continue;\r
- iPageCount += ((phtab[i].VAddr&0xFFF) + phtab[i].MemSize + 0xFFF) >> 12;\r
- LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}\n", i, phtab[i].VAddr, phtab[i].MemSize);\r
+ iPageCount += ((phtab[i].p_vaddr&0xFFF) + phtab[i].p_memsz + 0xFFF) >> 12;\r
+ LOG("phtab[%i] = {p_vaddr:0x%x, p_memsz:0x%x}\n", i, phtab[i].p_vaddr, phtab[i].MemSize);\r
}\r
\r
LOG("iPageCount = %i\n", iPageCount);\r
//ret->Interpreter = NULL;\r
\r
// Prescan for base and size\r
- max = 0;\r
- base = 0xFFFFFFFF;\r
- for( i = 0; i < hdr->phentcount; i ++)\r
+ uint32_t max = 0;\r
+ uint32_t base = UINT32_MAX;\r
+ for( unsigned int i = 0; i < hdr->e_phnum; i ++)\r
{\r
- if( phtab[i].Type != PT_LOAD )\r
+ if( phtab[i].p_type != PT_LOAD )\r
continue;\r
- if( phtab[i].VAddr < base )\r
- base = phtab[i].VAddr;\r
- if( phtab[i].VAddr + phtab[i].MemSize > max )\r
- max = phtab[i].VAddr + phtab[i].MemSize;\r
+ if( phtab[i].p_vaddr < base )\r
+ base = phtab[i].p_vaddr;\r
+ if( phtab[i].p_vaddr + phtab[i].p_memsz > max )\r
+ max = phtab[i].p_vaddr + phtab[i].p_memsz;\r
}\r
\r
LOG("base = %08x, max = %08x\n", base, max);\r
\r
+ uint32_t baseDiff = 0;\r
if( base == 0 ) {\r
// Find a nice space (47 address bits allowed)\r
base = FindFreeRange( max, 47 );\r
}\r
\r
// Load Pages\r
- for( i = 0; i < hdr->phentcount; i++ )\r
+ for( unsigned int i = 0; i < hdr->e_phnum; i++ )\r
{\r
// Get Interpreter Name\r
- if( phtab[i].Type == PT_INTERP )\r
+ if( phtab[i].p_type == PT_INTERP )\r
{\r
char *tmp;\r
//if(ret->Interpreter) continue;\r
- tmp = malloc(phtab[i].FileSize);\r
- acess__SysSeek(FD, phtab[i].Offset, ACESS_SEEK_SET);\r
- acess__SysRead(FD, tmp, phtab[i].FileSize);\r
+ tmp = malloc(phtab[i].p_filesz);\r
+ acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET);\r
+ acess__SysRead(FD, tmp, phtab[i].p_filesz);\r
//ret->Interpreter = Binary_RegInterp(tmp);\r
LOG("Interpreter '%s'\n", tmp);\r
free(tmp);\r
continue;\r
}\r
// Ignore non-LOAD types\r
- if(phtab[i].Type != PT_LOAD) continue;\r
+ if(phtab[i].p_type != PT_LOAD) continue;\r
\r
- LOG("phtab[%i] = PT_LOAD {Adj VAddr:0x%x, Offset:0x%x, FileSize:0x%x, MemSize:0x%x}\n",\r
- i, phtab[i].VAddr+baseDiff, phtab[i].Offset, phtab[i].FileSize, phtab[i].MemSize);\r
+ LOG("phtab[%i] = PT_LOAD {Adj p_vaddr:0x%x, p_offset:0x%x, p_filesz:0x%x, p_memsz:0x%x}\n",\r
+ i, phtab[i].p_vaddr+baseDiff, phtab[i].p_offset, phtab[i].p_filesz, phtab[i].p_memsz);\r
\r
- addr = phtab[i].VAddr + baseDiff;\r
+ uint64_t addr = phtab[i].p_vaddr + baseDiff;\r
\r
- if( AllocateMemory( addr, phtab[i].MemSize ) ) {\r
- fprintf(stderr, "Elf_Load: Unable to map memory at %x (0x%x bytes)\n",\r
- addr, phtab[i].MemSize);\r
+ if( AllocateMemory( addr, phtab[i].p_memsz ) ) {\r
+ fprintf(stderr, "Elf_Load: Unable to map memory at 0x%"PRIx64" (0x%x bytes)\n",\r
+ addr, phtab[i].p_memsz);\r
free( phtab );\r
return NULL;\r
}\r
\r
- acess__SysSeek(FD, phtab[i].Offset, ACESS_SEEK_SET);\r
- acess__SysRead(FD, PTRMK(void, addr), phtab[i].FileSize);\r
- memset( PTRMK(char, addr) + phtab[i].FileSize, 0, phtab[i].MemSize - phtab[i].FileSize );\r
+ acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET);\r
+ acess__SysRead(FD, PTRMK(void, addr), phtab[i].p_filesz);\r
+ memset( PTRMK(char, addr) + phtab[i].p_filesz, 0, phtab[i].p_memsz - phtab[i].p_filesz );\r
}\r
\r
// Clean Up\r
\r
void *Elf64Load(int FD, Elf64_Ehdr *hdr)\r
{\r
- Elf64_Phdr *phtab;\r
- int i;\r
- int iPageCount;\r
- uint64_t max, base;\r
- uint64_t addr;\r
- uint64_t baseDiff = 0;\r
- \r
ENTER("iFD", FD);\r
\r
if( sizeof(void*) == 4) {\r
}\r
\r
// Read Program Header Table\r
- phtab = malloc( sizeof(Elf64_Phdr) * hdr->e_phnum );\r
+ Elf64_Phdr* phtab = malloc( sizeof(Elf64_Phdr) * hdr->e_phnum );\r
if( !phtab ) {\r
LEAVE('n');\r
return NULL;\r
}\r
- LOG("hdr.phoff = 0x%08llx\n", (long long)hdr->e_phoff);\r
+ LOG("hdr.e_phoff = 0x%08llx\n", (long long)hdr->e_phoff);\r
acess__SysSeek(FD, hdr->e_phoff, ACESS_SEEK_SET);\r
acess__SysRead(FD, phtab, sizeof(Elf64_Phdr) * hdr->e_phnum);\r
\r
// Count Pages\r
- iPageCount = 0;\r
- LOG("hdr.phentcount = %i\n", hdr->e_phnum);\r
- for( i = 0; i < hdr->e_phnum; i++ )\r
+ unsigned int iPageCount = 0;\r
+ LOG("hdr.e_phnum = %i\n", hdr->e_phnum);\r
+ for( unsigned int i = 0; i < hdr->e_phnum; i++ )\r
{\r
// Ignore Non-LOAD types\r
if(phtab[i].p_type != PT_LOAD)\r
continue;\r
iPageCount += ((phtab[i].p_vaddr&0xFFF) + phtab[i].p_memsz + 0xFFF) >> 12;\r
- LOG("phtab[%i] = {VAddr:0x%llx, MemSize:0x%llx}\n",\r
+ LOG("phtab[%i] = {p_vaddr:0x%llx, p_memsz:0x%llx}\n",\r
i, (long long)phtab[i].p_vaddr, (long long)phtab[i].p_memsz);\r
}\r
\r
//ret->Interpreter = NULL;\r
\r
// Prescan for base and size\r
- max = 0;\r
- base = 0xFFFFFFFF;\r
- for( i = 0; i < hdr->e_phnum; i ++)\r
+ uint64_t max = 0;\r
+ uint64_t base = UINT64_MAX;\r
+ for( unsigned int i = 0; i < hdr->e_phnum; i ++)\r
{\r
if( phtab[i].p_type != PT_LOAD )\r
continue;\r
\r
LOG("base = %08lx, max = %08lx\n", base, max);\r
\r
+ uint64_t baseDiff = 0;\r
if( base == 0 ) {\r
// Find a nice space (31 address bits allowed)\r
base = FindFreeRange( max, 31 );\r
LOG("new base = %08lx\n", base);\r
- if( base == 0 ) return NULL;\r
+ if( base == 0 )\r
+ goto _err;\r
baseDiff = base;\r
}\r
\r
// Load Pages\r
- for( i = 0; i < hdr->e_phnum; i++ )\r
+ for( unsigned int i = 0; i < hdr->e_phnum; i++ )\r
{\r
// Get Interpreter Name\r
if( phtab[i].p_type == PT_INTERP )\r
// Ignore non-LOAD types\r
if(phtab[i].p_type != PT_LOAD) continue;\r
\r
- LOG("phtab[%i] = PT_LOAD {Adj VAddr:0x%llx, Offset:0x%llx, FileSize:0x%llx, MemSize:0x%llx}\n",\r
+ LOG("phtab[%i] = PT_LOAD {Adj p_vaddr:0x%llx, p_offset:0x%llx, p_filesz:0x%llx, p_memsz:0x%llx}\n",\r
i,\r
(long long)phtab[i].p_vaddr+baseDiff, (long long)phtab[i].p_offset,\r
(long long)phtab[i].p_filesz, (long long)phtab[i].p_memsz\r
);\r
\r
- addr = phtab[i].p_vaddr + baseDiff;\r
+ uint64_t addr = phtab[i].p_vaddr + baseDiff;\r
\r
if( AllocateMemory( addr, phtab[i].p_memsz ) ) {\r
fprintf(stderr, "Elf_Load: Unable to map memory at %"PRIx64" (0x%"PRIx64" bytes)\n",\r
(uint64_t)addr, (uint64_t)phtab[i].p_memsz);\r
- free( phtab );\r
- return NULL;\r
+ goto _err;\r
}\r
\r
acess__SysSeek(FD, phtab[i].p_offset, ACESS_SEEK_SET);\r
// Return\r
LEAVE('p', base);\r
return PTRMK(void, base);\r
+_err:\r
+ free(phtab);\r
+ LEAVE('n');\r
+ return NULL;\r
}\r
\r
{
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);
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)
{
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);
// --- Timekeeping ---
int64_t acess__SysTimestamp(void)
{
- // TODO: Better impl
- TODO();
-// return now()*1000;
- return 0;
+ return native_timestamp();
}
// --- Memory Management ---
}
// --- 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);
DEFSYM(_SysAllocate),
DEFSYM(_SysSetMemFlags),
DEFSYM(_SysDebug),
+ {"_ZN4_sys5debugEPKcz", &acess__SysDebug},
+ DEFSYM(_SysDebugHex),
+ {"_ZN4_sys7hexdumpEPKcPKvj", &acess__SysDebugHex},
DEFSYM(_SysSetFaultHandler),
DEFSYM(_SysWaitEvent),
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);
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);
/*
*/
+#define _GNU_SOURCE // needed for MAP_ANONYMOUS to be avaliable
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
# include <unistd.h>
# include <sys/socket.h>
# include <netinet/in.h>
+# include <sys/select.h>
#endif
#include "request.h"
#include "../syscalls.h"
// 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 )
{
# include <spawn.h> // posix_spawn
#endif
#include "request.h"
+#include <sys/time.h>
#define assert(cnd) do{ \
if( !(cnd) ) { \
tRequestHeader *req;
void *dataPtr;
uint64_t retValue;
- int i;
// DEBUG!
// printf("&tRequestHeader->Params = %i\n", offsetof(tRequestHeader, Params));
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));
exit(127);
}
retCount = 0;
- for( i = 2; i < req->NParams; i ++ )
+ for( unsigned int i = 2; i < req->NParams; i ++ )
{
#if 0
int j;
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] );
return rv;
}
+
+int64_t native_timestamp(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec*1000 + tv.tv_usec / 1000;
+}
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
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)
#include <stdint.h>
#include "../ld-acess_src/exports.h"
+extern int gbSyscallDebugEnabled;
+
#ifdef __WINDOWS__
int DllMain(void)
{
{
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, ':');
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;
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
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 ) {
}
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
printf("\n");
}
-void __libc_csu_fini()
-{
-}
-
-void __libc_csu_init()
-{
-}
-
-void __stack_chk_fail(void)
-{
- fprintf(stderr, "__stack_chk_fail");
- exit(1);
-}
-
+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
# 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
-#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
$(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)
-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
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)
+
+#
+#
+#
+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)
$(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-%)
--- /dev/null
+#
+#
+#
+-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
--- /dev/null
+#
+#
+#
+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-%)
+
+
--- /dev/null
+
+.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 $< $@
+
+
+ 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
--- 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 ;;
--- 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 \
--- 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 ;;
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
--- /dev/null
+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\"
+
--- 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*)
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
--- /dev/null
+; Options for acess2
+
+pthread
+Driver
+
+;
--- 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*)
--- /dev/null
+#
+# 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
+
--- /dev/null
+--- 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* \
+
--- /dev/null
+#
+# 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
+
+
--- /dev/null
+--- glib/config.sub
++++ glib/config.sub
+@@ -1335,2 +1335,5 @@
+ ;;
++ -acess2)
++ os=-acess2
++ ;;
+ -solaris)
-Subproject commit a5d190a89ca3f3a78c8b44a855b044ff4e713bb3
+Subproject commit 9f2d7faf34c16ceaee2f1bffe3d5558c41382523
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)
{
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
+
--- /dev/null
+#
+# 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
+
+
+
+
--- /dev/null
+--- 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* \
+
--- /dev/null
+--- glib/config.sub
++++ glib/config.sub
+@@ -1335,2 +1335,5 @@
+ ;;
++ -acess2)
++ os=-acess2
++ ;;
+ -solaris)
}
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[] = {
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
@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 $@
// > 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;\
--- /dev/null
+%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
; AcessOS Microkernel Version
;
; desctab.asm
+%include "arch/x86/common.inc.asm"
[BITS 32]
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:
; - Timer
[global Isr240]
[global Isr240.jmp]
-[extern SchedulerBase]
+[extern Proc_EventTimer_PIT]
[extern SetAPICTimerCount]
Isr240:
push 0 ; Line up with Argument in errors
%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
; --------------------------
[extern SyscallHandler]
SyscallCommon:
- pusha
- push ds
- push es
- push fs
- push gs
+ PUSH_CC ; Actually a pusha
+ PUSH_SEG
push esp
call SyscallHandler
[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
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);
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
*/
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 );
*/
void MM_ClearSpace(Uint32 CR3)
{
- int i, j;
-
if(CR3 == (*gpPageCR3 & ~0xFFF)) {
Log_Error("MMVirt", "Can't clear current address space");
return ;
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) )
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;
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) );
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
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);
}
; AcessOS Microkernel Version
; Start.asm
+%include "arch/x86/common.inc.asm"
[bits 32]
[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:
mov esi, [esp+0x20+8]
mov [esi], eax
; Undo the pusha
- add esp, 0x20
+ popa
mov eax, .newTask
ret
.newTask:
; +16 = Old RIP save loc
; +20 = CR3
SwitchTasks:
- pusha
+ PUSH_CC
; Old IP
mov eax, [esp+0x20+16]
jmp ecx
.restore:
- popa
+ POP_CC
xor eax, eax
ret
[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]
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
.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
;
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[];
//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);
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 ---
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
}
}
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
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;
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) ) {
}
// 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;
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));
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();
// 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();
}
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;
// === 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");
{
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 );
}
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"
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 );
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
extern void Debug_PutCharDebug(char ch);
extern void Debug_PutStringDebug(const char *Str);
+extern void __AtomicTestSetLoop(Uint *Ptr, Uint Value);
+
#endif
#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
Lock->Depth ++;
return ;
}
+ #else
+ ASSERT( !CPU_HAS_LOCK(Lock) );
#endif
// Wait for another CPU to release
#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)
__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;
#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;
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);
int MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags);
// === GLOBALS ===
-tMutex glMM_TempFractalLock;
tShortSpinlock glMM_ZeroPage;
tPAddr gMM_ZeroPage;
// Print Stack Backtrace
Error_Backtrace(Regs->RIP, Regs->RBP);
- MM_DumpTables(0, -1);
+ //MM_DumpTables(0, -1);
return 1;
}
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;
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));
*ent = PAddr | 3;
- if( (tVAddr)VAddr < USER_MAX )
+ if( (tVAddr)VAddr <= USER_MAX )
*ent |= PF_USER;
INVLPG( VAddr );
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
*/
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;
}
// 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);
{
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 ) {
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);
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 )
// MAGIC_BREAK();
// #7 Return
- TMPCR3() = 0;
- INVLPG_ALL();
- Mutex_Release(&glMM_TempFractalLock);
+ REL_TEMP_MAPPING();
// Log("MM_Clone: RETURN %P", ret);
return ret;
}
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)
if( !(*ptr & 1) ) break;
}
if( ret >= (1ULL << 47) ) {
- Mutex_Release(&glMM_TempFractalLock);
+ REL_TEMP_MAPPING();
return 0;
}
MM_FreeTemp(tmp_addr);
}
- TMPCR3() = 0;
- Mutex_Release(&glMM_TempFractalLock);
+ REL_TEMP_MAPPING();
return ret + i*0x1000;
}
[section .text]
[extern Threads_Exit]
+[extern glThreadListLock]
+[extern SHORTREL]
[global GetRIP]
GetRIP:
; [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)
// 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;
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);
}
/**
#if BITS <= 32\r
# define DISABLE_ELF64\r
#endif\r
-static int GetSymbol(const char *Name, void **Value, size_t *Size);\r
-static int GetSymbol(const char *Name, void **Value, size_t *Size) {\r
+static int GetSymbol(const char *Name, void **Value, size_t *Size, void *IgnoreBase);\r
+static int GetSymbol(const char *Name, void **Value, size_t *Size, void *IgnoreBase) {\r
Uint val;\r
if(!Binary_GetSymbol(Name, &val)) {\r
Log_Notice("ELF", "Lookup of '%s' failed", Name);\r
{\r
tBinary *ret;\r
Elf32_Phdr *phtab;\r
- int i, j;\r
- int iLoadCount;\r
+ int j;\r
\r
ENTER("xFD", FD);\r
\r
// Check architecture with current CPU\r
// - TODO: Support kernel level emulation\r
#if ARCH_IS_x86\r
- if( Header->machine != EM_386 )\r
+ if( Header->e_machine != EM_386 )\r
{\r
Log_Warning("ELF", "Unknown architecure on ELF-32");\r
LEAVE_RET('n');\r
#endif\r
\r
// Check for a program header\r
- if(Header->phoff == 0) {\r
+ if(Header->e_phoff == 0) {\r
#if DEBUG_WARN\r
Log_Warning("ELF", "File does not contain a program header (phoff == 0)");\r
#endif\r
}\r
\r
// Read Program Header Table\r
- phtab = malloc( sizeof(Elf32_Phdr) * Header->phentcount );\r
+ phtab = malloc( sizeof(Elf32_Phdr) * Header->e_phnum );\r
if( !phtab ) {\r
LEAVE('n');\r
return NULL;\r
}\r
- LOG("hdr.phoff = 0x%08x", Header->phoff);\r
- VFS_Seek(FD, Header->phoff, SEEK_SET);\r
- VFS_Read(FD, sizeof(Elf32_Phdr)*Header->phentcount, phtab);\r
+ LOG("hdr.phoff = 0x%08x", Header->e_phoff);\r
+ VFS_Seek(FD, Header->e_phoff, SEEK_SET);\r
+ VFS_Read(FD, sizeof(Elf32_Phdr)*Header->e_phnum, phtab);\r
\r
// Count Pages\r
- iLoadCount = 0;\r
- LOG("Header->phentcount = %i", Header->phentcount);\r
- for( i = 0; i < Header->phentcount; i++ )\r
+ unsigned iLoadCount = 0;\r
+ LOG("Header->phentcount = %i", Header->e_phnum);\r
+ for( int i = 0; i < Header->e_phnum; i++ )\r
{\r
// Ignore Non-LOAD types\r
- if(phtab[i].Type != PT_LOAD)\r
+ if(phtab[i].p_type != PT_LOAD)\r
continue;\r
iLoadCount ++;\r
- LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].VAddr, phtab[i].MemSize);\r
+ LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].p_vaddr, phtab[i].p_memsz);\r
}\r
\r
LOG("iLoadCount = %i", iLoadCount);\r
// Allocate Information Structure\r
ret = malloc( sizeof(tBinary) + sizeof(tBinarySection)*iLoadCount );\r
// Fill Info Struct\r
- ret->Entry = Header->entrypoint;\r
+ ret->Entry = Header->e_entry;\r
ret->Base = -1; // Set Base to maximum value\r
ret->NumSections = iLoadCount;\r
ret->Interpreter = NULL;\r
\r
// Load Pages\r
j = 0;\r
- for( i = 0; i < Header->phentcount; i++ )\r
+ for( int i = 0; i < Header->e_phnum; i++ )\r
{\r
//LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type);\r
LOG("phtab[%i] = {", i);\r
- LOG(" .Type = 0x%08x", phtab[i].Type);\r
- LOG(" .Offset = 0x%08x", phtab[i].Offset);\r
- LOG(" .VAddr = 0x%08x", phtab[i].VAddr);\r
- LOG(" .PAddr = 0x%08x", phtab[i].PAddr);\r
- LOG(" .FileSize = 0x%08x", phtab[i].FileSize);\r
- LOG(" .MemSize = 0x%08x", phtab[i].MemSize);\r
- LOG(" .Flags = 0x%08x", phtab[i].Flags);\r
- LOG(" .Align = 0x%08x", phtab[i].Align);\r
+ LOG(" .Type = 0x%08x", phtab[i].p_type);\r
+ LOG(" .Offset = 0x%08x", phtab[i].p_offset);\r
+ LOG(" .VAddr = 0x%08x", phtab[i].p_vaddr);\r
+ LOG(" .PAddr = 0x%08x", phtab[i].p_paddr);\r
+ LOG(" .FileSize = 0x%08x", phtab[i].p_filesz);\r
+ LOG(" .MemSize = 0x%08x", phtab[i].p_memsz);\r
+ LOG(" .Flags = 0x%08x", phtab[i].p_flags);\r
+ LOG(" .Align = 0x%08x", phtab[i].p_align);\r
LOG(" }");\r
// Get Interpreter Name\r
- if( phtab[i].Type == PT_INTERP )\r
+ if( phtab[i].p_type == PT_INTERP )\r
{\r
- char *tmp;\r
if(ret->Interpreter) continue;\r
- tmp = malloc(phtab[i].FileSize);\r
- VFS_Seek(FD, phtab[i].Offset, 1);\r
- VFS_Read(FD, phtab[i].FileSize, tmp);\r
+ char* tmp = malloc(phtab[i].p_filesz);\r
+ VFS_Seek(FD, phtab[i].p_offset, 1);\r
+ VFS_Read(FD, phtab[i].p_filesz, tmp);\r
ret->Interpreter = Binary_RegInterp(tmp);\r
LOG("Interpreter '%s'", tmp);\r
free(tmp);\r
continue;\r
}\r
// Ignore non-LOAD types\r
- if(phtab[i].Type != PT_LOAD) continue;\r
+ if(phtab[i].p_type != PT_LOAD) continue;\r
\r
// Find Base\r
- if(phtab[i].VAddr < ret->Base) ret->Base = phtab[i].VAddr;\r
+ if(phtab[i].p_vaddr < ret->Base) ret->Base = phtab[i].p_vaddr;\r
\r
LOG("phtab[%i] = {VAddr:0x%x,Offset:0x%x,FileSize:0x%x}",\r
- i, phtab[i].VAddr, phtab[i].Offset, phtab[i].FileSize);\r
+ i, phtab[i].p_vaddr, phtab[i].p_offset, phtab[i].p_filesz);\r
\r
- ret->LoadSections[j].Offset = phtab[i].Offset;\r
- ret->LoadSections[j].FileSize = phtab[i].FileSize;\r
- ret->LoadSections[j].Virtual = phtab[i].VAddr;\r
- ret->LoadSections[j].MemSize = phtab[i].MemSize;\r
+ ret->LoadSections[j].Offset = phtab[i].p_offset;\r
+ ret->LoadSections[j].FileSize = phtab[i].p_filesz;\r
+ ret->LoadSections[j].Virtual = phtab[i].p_vaddr;\r
+ ret->LoadSections[j].MemSize = phtab[i].p_memsz;\r
ret->LoadSections[j].Flags = 0;\r
- if( !(phtab[i].Flags & PF_W) )\r
+ if( !(phtab[i].p_flags & PF_W) )\r
ret->LoadSections[j].Flags |= BIN_SECTFLAG_RO;\r
- if( phtab[i].Flags & PF_X )\r
+ if( phtab[i].p_flags & PF_X )\r
ret->LoadSections[j].Flags |= BIN_SECTFLAG_EXEC;\r
j ++;\r
}\r
}
// --- 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
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;
}
#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 ===
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 ===
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;
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, ...)
/**
* \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, ...)
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();
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, ...)
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],
tMutex lList;
tIPCPipe_Packet *OutHead;
tIPCPipe_Packet *OutTail;
+ size_t ByteCount;
tVFS_Node Node;
};
struct sIPCPipe_Channel
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;
};
tVFS_NodeType gIPCPipe_ChannelNodeType = {
.TypeName = "IPC Pipe - Channel",
+ .Flags = VFS_NODETYPEFLAG_STREAM,
.Read = IPCPipe_Client_Read,
.Write = IPCPipe_Client_Write,
.Close = IPCPipe_Client_Close
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);
// 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;
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
}
else
{
- Log_Warning("IPCPipe", "No packet ready but semaphore returned");
+ Log_Warning("IPCPipe", "No packet ready but select returned");
}
LEAVE('i', ret);
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);
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
#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;
// === 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,
.NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRW,
};
-tPipe *gFIFO_NamedPipes = NULL;
// === CODE ===
/**
*/
int FIFO_Install(char **Options)
{
+ MemFS_InitDir( &gFIFO_RootDir );
DevFS_AddDevice( &gFIFO_DriverInfo );
return MODULE_ERR_OK;
}
*/
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);
}
/**
*/
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 )
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;
}
/**
*/
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;
}
*/
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
*/
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;
.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
.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
.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 = {
.ImplPtr = &gSysFS_Version,
.ImplInt = (Uint)&gSysFS_Root // Self-Link
},
- "/"
+ {"/"}
};
tDevFS_Driver gSysFS_DriverInfo = {
NULL, "system",
};
tVFS_NodeType gPTY_NodeType_Client = {
.TypeName = "PTY-Client",
+ .Flags = VFS_NODETYPEFLAG_STREAM,
.Read = PTY_ReadClient,
.Write = PTY_WriteClient,
.IOCtl = PTY_IOCtl,
};
tVFS_NodeType gPTY_NodeType_Server = {
.TypeName = "PTY-Server",
+ .Flags = VFS_NODETYPEFLAG_STREAM,
.Read = PTY_ReadServer,
.Write = PTY_WriteServer,
.IOCtl = PTY_IOCtl,
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();
// 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;
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;
* drv/serial.c
* - Common serial port code
*/
+#define DEBUG 0
#include <acess.h>
#include <modules.h>
#include <fs_devfs.h>
void Serial_ByteReceived(tSerialPort *Port, char Ch)
{
+ LOG("Port=%p,Ch=%i", Port, Ch);
if( !Port )
return ;
if( Port == gSerial_KernelDebugPort )
}
if( Ch == '\r' )
Ch = '\n';
+ LOG("Dispatch to PTY");
PTY_SendInput(Port->PTY, &Ch, 1);
}
--- /dev/null
+/*
+ * 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;
+}
+
* 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>
// === 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);
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;
}
}
int CachePos;
char Cache[32];
size_t PreEat;
+ union {
+ struct {
+ size_t Offset;
+ } Push;
+ } CmdInfo;
} Cmd2D;
tPTY *PTY;
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);
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)
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;
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
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]);
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 )
{
}
// 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;
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);
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);
}
}
// 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;
}
* drv/vterm_input.c
* - Virtual Terminal - Input code
*/
+#define DEBUG 0
#include "vterm.h"
#include <api_drv_video.h>
-#define DEBUG 0
// === CODE ===
/**
// 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;
// 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 )
tVideo_IOCtl_Pos csr_pos;
if( Term != gpVT_CurTerm ) return ;
+
+ ENTER("pTerm bShow", Term, bShow);
if( !bShow )
{
csr_pos.y = Term->VideoCursorY;
}
VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &csr_pos);
+ LEAVE('-');
}
/**
*/
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(
// 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),
}
VT_int_UpdateCursor(Term, 1);
+ LEAVE('-');
}
*/
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; )
{
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)
{
ASSERTC(wrpos->Col, <=, Term->TextWidth);
VT_int_UpdateScreen( Term, 0 );
- //wrpos->Row ++;
+ wrpos->Row ++;
wrpos->Col = 0;
}
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?
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;
}
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;
*wrpos = init_wrpos;
HEAP_VALIDATE();
+ LEAVE('-');
}
/**
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)
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
}
tDevFS_Driver gCoreDevs_Zero = {
NULL, "zero",
{
- .Size = 0, .NumACLs = 1,
+ .Size = -1, .NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRW,
.Type = &gCoreDevs_NT_Zero
}
tDevFS_Driver gCoreDevs_One = {
NULL, "one",
{
- .Size = 0, .NumACLs = 1,
+ .Size = -1, .NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRW,
.Type = &gCoreDevs_NT_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
tDevFS_Driver gCoreDevs_GRandom = {
NULL, "grandom",
{
- .Size = 0, .NumACLs = 1,
+ .Size = -1, .NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRW,
.Type = &gCoreDevs_NT_GRandom,
.DataAvaliable = 1
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 ;
// 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
--- /dev/null
+/*
+ * 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;
+}
+
*/
#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)
{
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 );
}
// 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 ) {
#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)))
/**
* \{
* \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)
/**
* \}
*/
* \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);
/**
* \}
* \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
#include <stdarg.h>
/**
- * \name Strings
+ * \name String Manipulation
* \{
*/
// - stdio.h in userland
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);
* 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
*
extern Uint32 PCI_GetBAR(tPCIDev id, int BAR);\r
extern Uint64 PCI_GetValidBAR(tPCIDev id, int BAR, tPCI_BARType BARType);\r
//extern Uint16 PCI_AssignPort(tPCIDev id, int bar, int count);\r
+//extern void* PCI_MapMemBAR(tPCIDev id, int BAR, tPCI_BARType BARType, size_t* Size, tPAddr* PAddr);\r
\r
#endif\r
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)
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)
#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)
/**
* \}
*/
--- /dev/null
+/*
+ * 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
+
#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[] = {
"SYS_COPYFD",
"SYS_FDCTL",
"SYS_READ",
+ "SYS_READAT",
"SYS_WRITE",
+ "SYS_WRITEAT",
+ "SYS_TRUNCATE",
"SYS_IOCTL",
"SYS_SEEK",
"SYS_READDIR",
"SYS_GETCWD",
"SYS_MOUNT",
"SYS_SELECT",
+ "SYS_MMAP",
+ "SYS_MUNMAP",
+ "SYS_MARSHALFD",
+ "SYS_UNMARSHALFD",
""
};
%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 GETMSG_IGNORE ((void*)-1)
typedef struct sThread tThread;
+typedef struct sProcess tProcess;
// === FUNCTIONS ===
extern tThread *Proc_GetCurThread(void);
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);
* \}
*/
+/**
+ * \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
*/
*/
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
* \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);
/**
* \}
* \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);
*/
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
*/
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
// === 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);
// === 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)
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);
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*);
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 );
}
--- /dev/null
+/*
+ * 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;
+}
+
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,
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);
#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;
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) );
);
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:
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)
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
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
+
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);
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";
Modules_LoadBuiltins();
Arch_LoadBootModules();
+ Log_Log("Config", "Running command line '%s", CommandLine);
System_ExecuteCommandLine();
// - Execute the Config Script
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);
+ }
}
/**
}
}
+void System_EmergencyConsole(void)
+{
+ // TODO: Support an emergency kernel-land console (with FS viewing support)
+ EmergencyConsole();
+}
* threads.c
* - Common Thread Control
*/
+#define DEBUG 0
#include <acess.h>
#include <threads.h>
#include <threads_int.h>
proc->Next->Prev = proc->Prev;
// VFS Cleanup
- VFS_CloseAllUserHandles();
+ VFS_CloseAllUserHandles( proc );
// Architecture cleanup
Proc_ClearProcess( proc );
// VFS Configuration strings
*/
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));
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
{
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
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 )
}
// --- 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;
}
// ---
*/
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)
// Single-list round-robin
// -----------------------------------
tThread *thread = gActiveThreads.Head;
+ LOG("thread = %p", thread);
if( thread )
{
gActiveThreads.Head = thread->Next;
*/
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
// Call actual scheduler
tThread *thread = Threads_int_GetRunnable();
-
+
// Anything to do?
if( thread )
{
Warning("No runnable thread for CPU%i", CPU);
}
- SHORTREL( &glThreadListLock );
-
return thread;
}
{
// 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 );
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 ];
}
h = &gaKernelHandles[FD];
}
else {
- if( FD >= *Threads_GetMaxFD()) return -1;
+ if( FD >= *Threads_GetMaxFD(NULL)) return -1;
h = &gaUserHandles[FD];
}
h->Node = Node;
// 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 )
{
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];
}
}
-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('-');
}
/**
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 )
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 ++ )
*/
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;
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;
}
*/
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);
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;
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;
}
#include <vfs.h>
#include <vfs_ext.h>
#include <vfs_int.h>
+#include <mm_virt.h> // MM_USER_MAX
#define MMAP_PAGES_PER_BLOCK 16
// === 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
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);
}
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
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;
}
}
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;
+}
#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)
{
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);
}
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;
}
// 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;
}
// 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;
}
int newf = VFS_Open(Path, Flags);
if( newf == -1 ) {
+ // errno = set by VFS_Open
return -1;
}
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 ;
}
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
VFS_Close(fd);
{
- char **cwdptr = Threads_GetCWD();
+ char **cwdptr = Threads_GetCWD(NULL);
// Free old working directory
if( *cwdptr ) free( *cwdptr );
// Set new
// Update
{
- char **chroot_ptr = Threads_GetChroot();
+ char **chroot_ptr = Threads_GetChroot(NULL);
if( *chroot_ptr ) free( *chroot_ptr );
*chroot_ptr = buf;
}
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);
// === 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;
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 )
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
// 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;
dev = PCI_GetDevice(0x1234, 0x1111, 0);\r
if(dev == -1)\r
base = VBE_DISPI_LFB_PHYSICAL_ADDRESS;\r
- else\r
- base = PCI_GetBAR(dev, 0);\r
+ else {\r
+ Log_Debug("BGA", "BARs %x,%x,%x,%x,%x,%x",\r
+ PCI_GetBAR(dev, 0), PCI_GetBAR(dev, 1), PCI_GetBAR(dev, 2),\r
+ PCI_GetBAR(dev, 3), PCI_GetBAR(dev, 4), PCI_GetBAR(dev, 5));\r
+ base = PCI_GetValidBAR(dev, 0, PCI_BARTYPE_MEM);\r
+ // TODO: Qemu/bochs have MMIO versions of the registers in BAR2\r
+ // - This range is non-indexed\r
+ //mmio_base = PCI_GetValidBAR(dev, 2, PCI_BARTYPE_MEM);\r
+ }\r
\r
// Map Framebuffer to hardware address\r
gBGA_Framebuffer = (void *) MM_MapHWPages(base, 768); // 768 pages (3Mb)\r
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 );
#include <limits.h>\r
\r
// === CONSTANTS ===\r
-#define USE_BIOS 1\r
+#ifdef ARCHDIR_is_x86\r
+# define USE_BIOS 1\r
+#else\r
+# define USE_BIOS 0\r
+#endif\r
#define VESA_DEFAULT_FRAMEBUFFER (KERNEL_BASE|0xA0000)\r
#define BLINKING_CURSOR 0\r
#if BLINKING_CURSOR\r
int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data);\r
void Vesa_int_HideCursor(void);\r
void Vesa_int_ShowCursor(void);\r
+ int Vesa_int_SetCursor(tVideo_IOCtl_Bitmap *Cursor);\r
void Vesa_FlipCursor(void *Arg);\r
Uint16 VBE_int_GetWord(const tVT_Char *Char);\r
void VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);\r
\r
// Allocate Info Block\r
info = VM8086_Allocate(gpVesa_BiosState, 512, &infoPtr.seg, &infoPtr.ofs);\r
+ if( info == NULL ) {\r
+ Log_Warning("VBE", "VM8086 allocation error");\r
+ return MODULE_ERR_NOTNEEDED;\r
+ }\r
// Set Requested Version\r
memcpy(info->signature, "VBE2", 4);\r
// Set Registers\r
case VIDEO_IOCTL_SETBUFFORMAT:\r
Vesa_int_HideCursor();\r
ret = gVesa_BufInfo.BufferFormat;\r
- if(Data) gVesa_BufInfo.BufferFormat = *(int*)Data;\r
+ if(Data)\r
+ gVesa_BufInfo.BufferFormat = *(int*)Data;\r
if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
- DrvUtil_Video_SetCursor( &gVesa_BufInfo, &gDrvUtil_TextModeCursor );\r
+ Vesa_int_SetCursor(&gDrvUtil_TextModeCursor);\r
Vesa_int_ShowCursor();\r
return ret;\r
\r
case VIDEO_IOCTL_SETCURSOR: // Set cursor position\r
+ if( !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )\r
+ return -EINVAL;\r
Vesa_int_HideCursor();\r
giVesaCursorX = ((tVideo_IOCtl_Pos*)Data)->x;\r
giVesaCursorY = ((tVideo_IOCtl_Pos*)Data)->y;\r
return 0;\r
\r
case VIDEO_IOCTL_SETCURSORBITMAP:\r
- if( gpVesaCurMode->flags & FLAG_LFB )\r
- DrvUtil_Video_SetCursor( &gVesa_BufInfo, Data );\r
- return 0;\r
+ return Vesa_int_SetCursor(Data);\r
}\r
return 0;\r
}\r
\r
Mutex_Release( &glVesa_Lock );\r
\r
- // TODO: Disableable backbuffer\r
- gVesa_BufInfo.BackBuffer = realloc(gVesa_BufInfo.BackBuffer,\r
- modeptr->height * modeptr->pitch);\r
+ // TODO: Allow disabling of back-buffer\r
+ gVesa_DriverStruct.RootNode.Size = modeptr->height * modeptr->pitch;\r
+ gVesa_BufInfo.BackBuffer = realloc(gVesa_BufInfo.BackBuffer, modeptr->height * modeptr->pitch);\r
gVesa_BufInfo.Framebuffer = gpVesa_Framebuffer;\r
gVesa_BufInfo.Pitch = modeptr->pitch;\r
gVesa_BufInfo.Width = modeptr->width;\r
}\r
}\r
\r
+int Vesa_int_SetCursor(tVideo_IOCtl_Bitmap *Cursor)\r
+{\r
+ if( !CheckMem(Cursor, sizeof(tVideo_IOCtl_Bitmap)) )\r
+ return -EINVAL;\r
+ \r
+ if( gpVesaCurMode && gpVesaCurMode->flags & FLAG_LFB )\r
+ {\r
+ DrvUtil_Video_SetCursor( &gVesa_BufInfo, Cursor );\r
+ }\r
+ else\r
+ {\r
+ }\r
+ return 0;\r
+}\r
+\r
/**\r
* \brief Swaps the text cursor on/off\r
*/\r
--- /dev/null
+/*
+ * 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);
+}
EOF;
+define("DEBUG_ENABLED", false);
+
$ACESSDIR = getenv("ACESSDIR");
$ARCH = getenv("ARCH");
{
$path = $item[1];
- echo $path,"\n";
+ if( DEBUG_ENABLED )
+ echo $path,"\n";
$size = filesize($path);
$_sym = "_binary_".str_replace(array("/","-",".","+"), "_", $path)."_start";
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"
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" {
*/
void ICMP_Initialise()
{
- IPv4_RegisterCallback(IP4PROT_ICMP, ICMP_GetPacket);
+ IPv4_RegisterCallback(IP4PROT_ICMP, ICMP_GetPacket, NULL);
}
/**
{
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
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 {
Uint32 ValidLifetime;
Uint32 PreferredLifetime;
Uint32 _reserved2;
- tIPv6 Prefix[];
+ tIPv6 Prefix[0];
} PACKED tICMPv6_Opt_Prefix;
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 {
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,
// === 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);
int IPv4_Ping(tInterface *Iface, tIPv4 Addr);
// === GLOBALS ===
-tIPCallback gaIPv4_Callbacks[256];
+struct {
+ tIPRxCallback* rx_cb;
+ tIPErrorCallback* err_cb;
+} gaIPv4_Callbacks[256];
// === CODE ===
/**
* \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;
}
*/
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",
void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
{
tIPv4Header *hdr = Buffer;
- tInterface *iface;
Uint8 *data;
int dataLength;
int ret;
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 ) {
}
// 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);
}
/**
*/
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;
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) )
#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
// === 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 ===
/**
* \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;
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
* Acess2 IP Stack
* - TCP Handling
*/
-#define DEBUG 1
+#define DEBUG 0
#include "ipstack.h"
#include "ipv4.h"
#include "ipv6.h"
#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
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);
};
tVFS_NodeType gTCP_ClientNodeType = {
.TypeName = "TCP Client/Connection",
+ .Flags = VFS_NODETYPEFLAG_STREAM,
.Read = TCP_Client_Read,
.Write = TCP_Client_Write,
.IOCtl = TCP_Client_IOCtl,
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);
}
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,
}
}
-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};
{
// 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 ;
}
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;
}
}
}
}
+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;
// 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
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");
}
// 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);
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
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 )
Connection->NextSequenceRcv ++;
Log_Log("TCP", "Empty Packet, inc and ACK the current sequence number");
TCP_INT_SendACK(Connection, "Empty");
- return ;
+ return 0;
}
// NOTES:
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;
Connection->State = TCP_ST_TIME_WAIT;
Log_Debug("TCP", "Conn %p CLOSING -> TIME WAIT", Connection);
VFS_MarkError(&Connection->Node, 1);
- return ;
+ return 0;
}
break;
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;
+
}
/**
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;
conn->LocalPort = -1;
conn->RemotePort = -1;
+ conn->Node.Size = -1;
conn->Node.ReferenceCount = 1;
conn->Node.ImplPtr = conn;
conn->Node.NumACLs = 1;
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);
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);
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 );
TCP_SendPacket( Connection, packet, Length, Data );
+ // TODO: Start a retransmit time (if data is not ACKed in x seconds, send again)
+
Connection->NextSequenceSend += Length;
}
// #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);
}
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);
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();
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)
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
// === 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);
// === GLOBALS ===
tVFS_NodeType gUDP_NodeType = {
+ .TypeName = "UDP",
+ .Flags = VFS_NODETYPEFLAG_STREAM,
.Read = UDP_Channel_Read,
.Write = UDP_Channel_Write,
.IOCtl = UDP_Channel_IOCtl,
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);
}
/**
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;
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);
/**
* \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)
{
}
{
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 );
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:
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;
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);
"getset_remoteport",
"getset_remotemask",
"set_remoteaddr",
+ "sendto",
+ "recvfrom",
NULL
};
/**
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;
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);
}
*/
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;
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
+++ /dev/null
-#
-# EDI - Extensible Driver Interface
-#
-# Acess Interface
-
-
-OBJ = main.o edi.o
-NAME = EDI
-
--include ../Makefile.tpl
+++ /dev/null
-/*! \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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-/*
- * 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
- };
+++ /dev/null
-/*
- * 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
- };
+++ /dev/null
-/*
- * 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);
#
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
*/
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);
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;
}
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;
}
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:
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);
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;
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 )
rgn->OverrunTime = _get_token_uint32(str, &str);
break;
}
- if( !str ) break ;
+ IF_ERROR(break);
}
break;
}
{
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 :(
}
{
// 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];
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
}
{
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 :(
}
{
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;
{
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 )
{
UDI_ATTR32_SET(at->attr_value, _get_token_bool(str, &str));
break;
}
- if( !str ) break;
+ IF_ERROR(break);
n_attr ++;
}
}
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]);
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
* - 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>
--- /dev/null
+/*
+ * 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 ===
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+
+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)
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);
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 $<
// 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;
}
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;
}
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
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))
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
_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
$(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
# 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
# Default build programs
#CC := gcc
#LD := ld
-AS := nasm
DISASM := objdump -d -S
RM := @rm -f
STRIP := strip
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
-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
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
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
// === 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) );
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;
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;
OBJ += test_arp.o test_tcp.o
BIN := ../nettest_runner
-CFLAGS := -Wall -std=c99
+CFLAGS := -Wall -std=c99 -g
CPPFLAGS := -Iinclude
LIBS :=
@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
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, ...);
#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)
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
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
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)
#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
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;
}
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");
}
#include <fcntl.h>
#include <spawn.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#define MAX_ARGS 16
break;
default:
assert(AddrType == 4);
+ fprintf(stderr, "Stack_AddInterface: Bad address type %i\n", AddrType);
exit(1);
}
}
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;
}
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);
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);
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, ...)
#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
// 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;
*
* test_tcp.c
* - Tests for the behavior of the "Transmission Control Protocol"
+ * - These tests are written off RFC793
*/
#include "test.h"
#include "tests.h"
#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,
// > 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;
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
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();
// 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 );
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,
.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
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;
}
OBJ := $(NOBJ) $(LOBJ) $(KOBJ)
BIN := ../libnativelib.a
-CFLAGS := -Wall -std=c99 -Werror
+CFLAGS := -Wall -std=c99
CPPFLAGS := -I include
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);
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)
[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
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);
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);
#define _COMMON_H_
#include <stdarg.h>
+#include <stdbool.h>
#ifndef __GNUC__
# define __attribute__(...)
extern char *mkstr(const char *fmt, ...) __attribute__((format(printf,1,2)));
+extern bool gbTraceEnabled;
+
#endif
void Usage(const char *progname);
// === GLOBALS ===
+bool gbTraceEnabled = false;
const char *gsRuntimeDir = RUNTIME_DIR;
const char *gsOpt_ConfigFile;
const char *gsOpt_WorkingDir;
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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,
+};
--- /dev/null
+/*
+ *
+ */
+
+#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)
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+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 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+
#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"
(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;
* ne2000_core.c
* - UDI initialisation
*/
-#include <udi.h>
-#include <udi_nic.h>
#include "ne2000_common.h"
enum {
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)
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,
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 );
// = = = =
}
* 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"
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
{
* 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"
* 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"
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;
}
--- /dev/null
+
+
+- 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);
#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>
--- /dev/null
+/**
+ * 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
--- /dev/null
+/**\r
+ * Summary: udi_gfx.h\r
+ * Contains the graphics metalanguage interface details\r
+ *\r
+ * Author:\r
+ * Marcel Sondaar\r
+ *\r
+ * License:\r
+ * <Public Domain>\r
+ *\r
+ * Origin:\r
+ * http://www.d-rift.nl/combuster/mos3/?p=viewsource&file=/include/common/udi_gfx.h\r
+ */\r
+\r
+// note that the specification, and thus, the contents of this file is not fixed.\r
+\r
+#ifndef __UDI_GFX_H__\r
+#define __UDI_GFX_H__\r
+\r
+#include <udi.h>\r
+\r
+#ifndef UDI_GFX_VERSION\r
+#error "UDI_GFX_VERSION not defined."\r
+#elif UDI_GFX_VERSION != 0x101\r
+#error "UDI_GFX_VERSION not supported."\r
+#endif\r
+\r
+/**\r
+ * Enumeration: UDI_GFX_PROP\r
+ * Lists the various UDI properties\r
+ */\r
+\r
+// General state properties\r
+/* Constant: UDI_GFX_PROP_ENABLE\r
+ *\r
+ * Valid values:\r
+ * 0 - disabled\r
+ * 1 - enabled\r
+ * 2 - reset\r
+ *\r
+ * Ranges:\r
+ * Must include at least 1\r
+ *\r
+ * The primary state of the connector or engine. An enabled state indicates\r
+ * it is functioning and generating live output. A disabled state is one where\r
+ * it is not contributing to any output but is otherwise functional. Finally\r
+ * the reset state is where the driver is free to deallocate all resources \r
+ * corresponding to this component and trash any state not referenced by other\r
+ * components.\r
+ *\r
+ * A disabled or reset engine forwards all data from the previous stage \r
+ * unmodified. The disabled state indicates that the component might be \r
+ * returned to its enabled state within short notice.\r
+ *\r
+ * A disabled connector will not send pixel data, but can perform other \r
+ * initialisation communication such as DDC. A reset connector will not respond\r
+ * in any fashion and can not be used for other purposes. Hardware is expected\r
+ * to be powered down in such state.\r
+ *\r
+ * Users should expect significant delays when moving components in and out of\r
+ * the reset state. Moving engines between the enabled and disabled state should\r
+ * take effect within one frame, such transition should take effect on a frame \r
+ * boundary when supported.\r
+ */\r
+#define UDI_GFX_PROP_ENABLE 0\r
+\r
+#define UDI_GFX_PROP_ENABLE_DISABLED 0\r
+#define UDI_GFX_PROP_ENABLE_ENABLED 1\r
+#define UDI_GFX_PROP_ENABLE_RESET 2\r
+/* Constant: UDI_GFX_PROP_INPUT\r
+ *\r
+ * Valid values:\r
+ * Any valid engine ID, provided no dependency cycles are created, or -1\r
+ *\r
+ * Ranges:\r
+ * Any non-empty set of valid values. Often hardwired.\r
+ *\r
+ * Points to the engine that is processed before this unit. In the case of a \r
+ * connector, it points to the last engine in a pipeline, and each engine points \r
+ * to the next engine in the sequence. A value of -1 indicates a source that \r
+ * only yields black pixels. Implementations must not allow cyclic structures. \r
+ * Changing this value may reallocate resources, and engines that are no longer \r
+ * referenced may lose their data (but not their state) when it is not part of \r
+ * any pipeline. If preservation is required, the ENABLE state should be used\r
+ * instead. Valid ranges includes one or more from the list of engines and -1 \r
+ * combined. In most cases, this property can not be modified.\r
+ */\r
+#define UDI_GFX_PROP_INPUT 1\r
+/* Constant: UDI_GFX_PROP_WIDTH\r
+ *\r
+ * Valid values:\r
+ * Any non-zero positive number.\r
+ *\r
+ * Ranges:\r
+ * Contains at least one valid value. Often only multiples of UNIT_WIDTH\r
+ * or a power of two are allowed. May be hardwired.\r
+ *\r
+ * Contains the amount of pixels in the horizontal direction. For connectors, \r
+ * this is the amount of data pixels rendered horizontally. For engines, this \r
+ * is the width in pixels of the image. Pixels requested from an engine outside \r
+ * the range (0..width-1) are defined according to the <UDI_GFX_PROP_CLIP> \r
+ * property. In some cases, hardware may support only fixed combinations of \r
+ * width and height. In such cases, changing the width will also change the \r
+ * height to a corresponding valid number. Valid ranges include any values\r
+ * strictly above zero. For connectors, expect large continuous ranges, large\r
+ * ranges with a certain modulus, a limited number of fixed values, or a\r
+ * constant value.\r
+ */\r
+#define UDI_GFX_PROP_WIDTH 2\r
+/* Constant: UDI_GFX_PROP_HEIGHT\r
+ *\r
+ * Valid values:\r
+ * Any non-zero positive number.\r
+ *\r
+ * Ranges:\r
+ * Contains at least one valid value. Often only multiples of UNIT_HEIGHT\r
+ * or a power of two are allowed. May be hardwired.\r
+ *\r
+ * Contains the amount of pixels in the vertical direction. Functions similar\r
+ * to the width property, but changing it will not alter the width property,\r
+ * and it's range at any time contains the valid range for the currently\r
+ * selected width.\r
+ */\r
+#define UDI_GFX_PROP_HEIGHT 3\r
+\r
+/* Constant: UDI_GFX_PROP_CUSTOM\r
+ * The first property index of the driver's custom range. These are not assigned\r
+ * directly assigned by the UDI specification, but may be specified in the\r
+ * operator tree.\r
+ */\r
+#define UDI_GFX_PROP_CUSTOM 1024\r
+\r
+// engine properties\r
+\r
+/* Constant: UDI_GFX_PROP_CLIP\r
+ *\r
+ * Valid values:\r
+ * 0 - points outside width x height are passed unmodified from input\r
+ * 1 - the engine's contents is tiled with size width x height\r
+ * 2 - points outside the width overflow into the y coordinate\r
+ * 3 - points outside the height overflow into the x coordinate\r
+ *\r
+ * Ranges:\r
+ * Hardwired zero for connectors. Any non-empty subset for engines, usually\r
+ * hardwired.\r
+ *\r
+ * For engines, contains the behaviour for pixels requested outside the width\r
+ * and height of the engine. Can be either 0 (pass from next stage), 1 (the\r
+ * coordinates are wrapped modulus the height and width), 2 (the coordinates\r
+ * overflow onto the next scanline horizontally, and wrap vertically), 3 (the\r
+ * coordinates overflow onto the next column vertically, and wrap horizontally).\r
+ * Valid ranges contain one or more of these options. For overlays and sprites,\r
+ * a value 0 is common. For framebuffers, 2 is the most common value. For\r
+ * connectors, this property is always 0 since they do not store pixel data\r
+ */\r
+#define UDI_GFX_PROP_CLIP 4\r
+\r
+/* Constant: UDI_GFX_PROP_UNIT_WIDTH\r
+ *\r
+ * Valid values:\r
+ * Any non-zero positive value\r
+ *\r
+ * Ranges:\r
+ * Any non-empty set of valid values. May be hardwired to 1 for\r
+ * framebuffers, or a range of small values for hardware scaling, or any\r
+ * larger hardwired number or set for tiling engines.\r
+ *\r
+ * Tiles are used to indicate that the hardware groups sets of pixels and have\r
+ * each group share certain properties, i.e. color or tile index, or share the\r
+ * same chroma subsample with only a different intensity. If the engine has no\r
+ * such grouping, or shares all properties over the entire contents, the value\r
+ * of this property should be 1. Some tile examples include rescaling, where a\r
+ * tile width of 2 indicates a pixel doubling in X direction, or in text mode\r
+ * where a tile width of 8 or 9 corresponds with the width of common bitmap\r
+ * fonts\r
+ */\r
+#define UDI_GFX_PROP_UNIT_WIDTH 5\r
+\r
+/* Constant: UDI_GFX_PROP_UNIT_HEIGHT\r
+ *\r
+ * Valid values:\r
+ * Any non-zero positive value\r
+ *\r
+ * Ranges:\r
+ * Any non-empty set of valid values. May be hardwired to 1 for\r
+ * framebuffers, or a range of small values for hardware scaling, or any\r
+ * larger hardwired number or set for tiling engines.\r
+ *\r
+ * See <UDI_GFX_PROP_UNIT_WIDTH>, but for the Y direction. Common values are\r
+ * 1-2 for framebuffers (doublescanning on or off), identical to the tile\r
+ * width, or mostly independent.\r
+ */\r
+#define UDI_GFX_PROP_UNIT_HEIGHT 6\r
+\r
+/* Constant: UDI_GFX_PROP_TRANSLATEX\r
+ * \r
+ * Valid values:\r
+ * Any, signed value.\r
+ *\r
+ * Ranges:\r
+ * Any non-empty set. Typical values are hardwired zero, continuous\r
+ * between -WIDTH and WIDTH, -WIDTH to zero inclusive, or all possible values\r
+ *\r
+ * The horizontal offset where drawing starts. A positive value means the top-left \r
+ * corner moves towards the right end of the screen, a negative value moves the\r
+ * origin off the screen on the left side. Clipped areas moved off the screen do \r
+ * not reappear on the opposite side.\r
+ *\r
+ * With clipping enabled, this field combined with <UDI_GFX_PROP_WIDTH> \r
+ * determines the area where the image should be drawn, which is the horizontal \r
+ * range from UDI_GFX_PROP_TRANSLATEX to UDI_GFX_PROP_WIDTH + \r
+ * UDI_GFX_PROP_TRANSLATEX - 1\r
+ */\r
+#define UDI_GFX_PROP_TRANSLATEX 7\r
+\r
+/* Constant: UDI_GFX_PROP_TRANSLATEY\r
+ *\r
+ * Valid values:\r
+ * Any signed value.\r
+ *\r
+ * Ranges:\r
+ * Any non-empty set. Typical values are hardwired zero, continuous\r
+ * between -WIDTH and WIDTH, or all possible values\r
+ *\r
+ * See <UDI_GFX_PROP_TRANSLATEX> but for the Y direction.\r
+ */\r
+#define UDI_GFX_PROP_TRANSLATEY 8\r
+\r
+#define UDI_GFX_PROP_GL_VERSION 14\r
+#define UDI_GFX_PROP_GLES_VERSION 15\r
+#define UDI_GFX_PROP_STATE_BLOCK 16\r
+#define UDI_GFX_PROP_COLOR_BITS 22\r
+#define UDI_GFX_PROP_GL_TARGET 23\r
+\r
+/* Constant: UDI_GFX_PROP_STOCK_FORMAT\r
+ *\r
+ * Value:\r
+ * Zero, or any constant from <UDI_GFX_STOCK_FORMAT>\r
+ *\r
+ * Ranges:\r
+ * Any non-empty set of valid values.\r
+ *\r
+ * This field indicates the storage format is one from a limited set of \r
+ * typical configurations. If the field is zero, the engine is not knowingly\r
+ * configured as a common framebuffer. If nonzero, the operator chain and any\r
+ * dependent settings are defined to be functionally equivalent to that of a\r
+ * typical framebuffer device.\r
+ *\r
+ * The value zero does not imply that the device does not actually follow a\r
+ * set convention. This saves drivers from writing elaborate checking code\r
+ * to determine the condition in question.\r
+ *\r
+ * Writing this field potentially modifies other property fields within the\r
+ * same engine to establish the requested configuration. Manually writing such \r
+ * properties after changing this setting may in turn revert this property to\r
+ * the zero state, even if there was no modification or the behaviour is still\r
+ * as previously advertised by this property.\r
+ */\r
+#define UDI_GFX_PROP_STOCK_FORMAT 27\r
+\r
+/* Constant: UDI_GFX_PROP_OPERATOR_COUNT\r
+ * \r
+ * Valid values:\r
+ * Any non-zero positive number\r
+ * \r
+ * Ranges:\r
+ * Most likely constant. Can be any set of valid values.\r
+ *\r
+ * The current value is the number of entries in the operator tree that can\r
+ * be requested for this engine using <udi_gfx_get_engine_operator_req> and\r
+ * <udi_gfx_get_engine_operator_ack>\r
+ */\r
+#define UDI_GFX_PROP_OPERATOR_COUNT 28\r
+\r
+// properties for removal:\r
+#define UDI_GFX_PROP_STORE_COUNT 24 // not generic\r
+#define UDI_GFX_PROP_STORE_WIDTH 9 // not generic\r
+#define UDI_GFX_PROP_STORE_HEIGHT 10 // not generic\r
+#define UDI_GFX_PROP_STORE_BITS 11 // not generic\r
+#define UDI_GFX_PROP_PALETTE 1024 // optional, can be derived from the operator tree\r
+#define UDI_GFX_PROP_BUFFER 1025 // optional, can be derived from the operator tree\r
+#define UDI_GFX_PROP_TILESHEET 1026 // optional, can be derived from the operator tree\r
+#define UDI_GFX_PROP_OPERATOR_INDEX 17 // deprecated for dedicated methods\r
+#define UDI_GFX_PROP_OPERATOR_OPCODE 18 // deprecated for dedicated methods\r
+#define UDI_GFX_PROP_OPERATOR_ARG_1 19 // deprecated for dedicated methods\r
+#define UDI_GFX_PROP_OPERATOR_ARG_2 20 // deprecated for dedicated methods\r
+#define UDI_GFX_PROP_OPERATOR_ARG_3 21 // deprecated for dedicated methods\r
+#define UDI_GFX_PROP_SOURCE_WIDTH 12 // should have been documented when I still knew what it did.\r
+#define UDI_GFX_PROP_SOURCE_HEIGHT 13 // should have been documented when I still knew what it did.\r
+#define UDI_GFX_PROP_INPUTX 25 // should have been documented when I still knew what it did.\r
+#define UDI_GFX_PROP_INPUTY 26 // should have been documented when I still knew what it did.\r
+\r
+// connector properties\r
+#define UDI_GFX_PROP_SIGNAL 23\r
+#define UDI_GFX_PROP_CONNECTOR_TYPE 24\r
+#define UDI_GFX_PROP_VGA_H_FRONT_PORCH 25\r
+#define UDI_GFX_PROP_VGA_H_BACK_PORCH 26\r
+#define UDI_GFX_PROP_VGA_H_SYNC 27\r
+#define UDI_GFX_PROP_VGA_V_FRONT_PORCH 28\r
+#define UDI_GFX_PROP_VGA_V_BACK_PORCH 29\r
+#define UDI_GFX_PROP_VGA_V_SYNC 30\r
+#define UDI_GFX_PROP_DOT_CLOCK 31\r
+#define UDI_GFX_PROP_VGA_H_SYNC_POL 32\r
+#define UDI_GFX_PROP_VGA_V_SYNC_POL 33\r
+\r
+/**\r
+ * Enumeration: UDI_GFX_SIGNAL\r
+ * Lists the various signal types\r
+ */\r
+#define UDI_GFX_SIGNAL_HIDDEN 0\r
+#define UDI_GFX_SIGNAL_INTEGRATED 0\r
+#define UDI_GFX_SIGNAL_RGBHV 1\r
+#define UDI_GFX_SIGNAL_RGBS 2\r
+#define UDI_GFX_SIGNAL_RGSB 3\r
+#define UDI_GFX_SIGNAL_YPBPR 4\r
+#define UDI_GFX_SIGNAL_DVID 5\r
+#define UDI_GFX_SIGNAL_YUV 6\r
+#define UDI_GFX_SIGNAL_YIQ 7\r
+#define UDI_GFX_SIGNAL_Y_UV 8\r
+#define UDI_GFX_SIGNAL_Y_IQ 9\r
+#define UDI_GFX_SIGNAL_HDMI 10\r
+#define UDI_GFX_SIGNAL_TEXT 11\r
+#define UDI_GFX_SIGNAL_CUSTOM 12\r
+\r
+/**\r
+ * Enumeration: UDI_GFX_CONNECTOR\r
+ * Lists the various external connectors\r
+ */\r
+#define UDI_GFX_CONNECTOR_HIDDEN 0\r
+#define UDI_GFX_CONNECTOR_VGA 1\r
+#define UDI_GFX_CONNECTOR_DVI 2\r
+#define UDI_GFX_CONNECTOR_SVIDEO 3\r
+#define UDI_GFX_CONNECTOR_COMPONENT 4\r
+#define UDI_GFX_CONNECTOR_HDMI 5\r
+#define UDI_GFX_CONNECTOR_RF 6\r
+#define UDI_GFX_CONNECTOR_SCART 7\r
+#define UDI_GFX_CONNECTOR_COMPOSITE 8\r
+#define UDI_GFX_CONNECTOR_MEMBUFFER 9\r
+\r
+/**\r
+ * Enumeration: UDI_GFX_OPERATOR\r
+ * Lists the display output operator\r
+ */\r
+#define UDI_GFX_OPERATOR_RGB 0 // output = (color) red(a1) + green(a2) + blue(a3) (each component is UDI_GFX_PROP_COLOR_BITS\r
+#define UDI_GFX_OPERATOR_YUV 1 // output = (color) Y(a1) + U(a2) + V(a3)\r
+#define UDI_GFX_OPERATOR_YIQ 2 // output = (color) Y(a1) + I(a2) + Q(a3)\r
+#define UDI_GFX_OPERATOR_I 3 // output = (color) intensity(a1)\r
+#define UDI_GFX_OPERATOR_ALPHA 4 // output = (color) a1 + alpha(a2)\r
+#define UDI_GFX_OPERATOR_ADD 5 // output = a1 + a2 + v3\r
+#define UDI_GFX_OPERATOR_SUB 6 // output = a1 - a2 - v3\r
+#define UDI_GFX_OPERATOR_MUL 7 // output = a1 * a2\r
+#define UDI_GFX_OPERATOR_DIV 8 // output = a1 / a2\r
+#define UDI_GFX_OPERATOR_MAD 9 // output = a1 * a2 + a3\r
+#define UDI_GFX_OPERATOR_FRC 10 // output = (a1 * a2) / a3\r
+#define UDI_GFX_OPERATOR_SHR 11 // output = a1 >> (a2 + v3)\r
+#define UDI_GFX_OPERATOR_SHL 12 // output = a1 << (a2 + v3)\r
+#define UDI_GFX_OPERATOR_ROR 13 // output = a1 >> a2 (over a3 bits)\r
+#define UDI_GFX_OPERATOR_ROL 14 // output = a1 << a2 (over a3 bits)\r
+#define UDI_GFX_OPERATOR_SAR 15 // output = a1 >> a2 (width is a3 bits, i.e. empties are filled with bit a3-1)\r
+#define UDI_GFX_OPERATOR_SAL 16 // output = a1 <<< (a2 + v3) (empties filled with bit 0)\r
+#define UDI_GFX_OPERATOR_AND 17 // output = a1 & a2\r
+#define UDI_GFX_OPERATOR_OR 18 // output = a1 | a2 | v3\r
+#define UDI_GFX_OPERATOR_NOT 19 // output = ~a1\r
+#define UDI_GFX_OPERATOR_XOR 20 // output = a1 ^ a2 ^ v3\r
+#define UDI_GFX_OPERATOR_NEG 21 // output = -a1\r
+#define UDI_GFX_OPERATOR_SEG 22 // output = (a1 >> v2) & (2**v3-1) (select v3 bits starting from bit v2)\r
+#define UDI_GFX_OPERATOR_RANGE 23 // output = (a1 > a2) ? a2 : ((a1 < a3) ? a3 : a1)\r
+#define UDI_GFX_OPERATOR_CONST 24 // output = v1\r
+#define UDI_GFX_OPERATOR_ATTR 25 // output = property[a1 + v2]\r
+#define UDI_GFX_OPERATOR_SWITCH 26 // output = output[(a1 % v3) + v2]\r
+#define UDI_GFX_OPERATOR_BUFFER 27 // output = buffer[a1][a2] (buffer is v3 bits per entry)\r
+#define UDI_GFX_OPERATOR_X 28 // output = output x pixel\r
+#define UDI_GFX_OPERATOR_Y 29 // output = output y pixel\r
+#define UDI_GFX_OPERATOR_TX 30 // output = horizontal tile index belonging to output pixel\r
+#define UDI_GFX_OPERATOR_TY 31 // output = vertical tile index belonging to output pixel\r
+#define UDI_GFX_OPERATOR_TXOFF 32 // output = horizontal offset from start of tile\r
+#define UDI_GFX_OPERATOR_TYOFF 33 // output = vertical offset from start of tile\r
+#define UDI_GFX_OPERATOR_INPUT 34 // output = input engine[x][y] component v1\r
+#define UDI_GFX_OPERATOR_DINPUT 35 // output = input engine[a1][a2] component v3\r
+\r
+/* Enumeration: UDI_GFX_STOCK_FORMAT\r
+ * Lists stock configurations\r
+ *\r
+ * When a stock configuration is used, the device is set to behave as a \r
+ * simple framebuffer device. The <UDI_GFX_PROP_WIDTH> and <UDI_GFX_PROP_HEIGHT>\r
+ * determine the virtual size of the framebuffer, and <UDI_GFX_PROP_TRANSLATEX>\r
+ * and <UDI_GFX_PROP_TRANSLATEY> indicate the offset into that framebuffer \r
+ * that is visible (which are typically restricted to negative values)\r
+ */\r
+#define UDI_GFX_STOCK_FORMAT_UNKNOWN 0\r
+#define UDI_GFX_STOCK_FORMAT_R8G8B8X8 1\r
+#define UDI_GFX_STOCK_FORMAT_B8G8R8X8 2\r
+#define UDI_GFX_STOCK_FORMAT_R8G8B8 3\r
+#define UDI_GFX_STOCK_FORMAT_B8G8R8 4\r
+#define UDI_GFX_STOCK_FORMAT_R5G6B5 5\r
+#define UDI_GFX_STOCK_FORMAT_B5G6R5 6\r
+#define UDI_GFX_STOCK_FORMAT_R5G5B5X1 7\r
+#define UDI_GFX_STOCK_FORMAT_B5G5R5X1 8\r
+#define UDI_GFX_STOCK_FORMAT_N8 9\r
+\r
+// Enumeration: UDI_GFX_BUFFER_INFO_FLAG\r
+// Lists behavioural patterns for direct buffer accesses.\r
+//\r
+#define UDI_GFX_BUFFER_INFO_FLAG_R 0x0001 // buffer can be read\r
+#define UDI_GFX_BUFFER_INFO_FLAG_W 0x0002 // buffer can be written\r
+#define UDI_GFX_BUFFER_INFO_FLAG_BITALIGN_ENTRY 0x0004 // for non-multiple-of-eight buffer slot sizes, align on byte boundary every unit\r
+#define UDI_GFX_BUFFER_INFO_FLAG_BITALIGN_ROW 0x0008 // for non-multiple-of-eight buffer slot sizes, align only the start of the row\r
+\r
+\r
+// Constant: UDI_GFX_PROVIDER_OPS_NUM\r
+// the ops number used for the graphics driver\r
+#define UDI_GFX_PROVIDER_OPS_NUM 1\r
+\r
+// Constant: UDI_GFX_CLIENT_OPS_NUM\r
+// the ops number used for the graphics application\r
+#define UDI_GFX_CLIENT_OPS_NUM 2\r
+\r
+// Structure: udi_gfx_bind_cb_t\r
+// Contains the operations of a driver binding request\r
+typedef struct {\r
+ // Variable: gcb\r
+ // The main control block\r
+ udi_cb_t gcb; \r
+} udi_gfx_bind_cb_t;\r
+#define UDI_GFX_BIND_CB_NUM 1\r
+\r
+// Function: udi_block_bind_req\r
+// function pointer prototype for connecting to a block device\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_block_bind_cb_t>\r
+//\r
+typedef void udi_gfx_bind_req_op_t (udi_gfx_bind_cb_t *cb );\r
+udi_gfx_bind_req_op_t udi_gfx_bind_req;\r
+\r
+// Function: udi_gfx_bind_ack\r
+// function pointer prototype for acknowledging a connection request\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_bind_cb_t>\r
+// sockets - The number of addressable socket components\r
+// engines - The number of addressable engine components\r
+// status - The result of the bind operation\r
+//\r
+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 );\r
+udi_gfx_bind_ack_op_t udi_gfx_bind_ack;\r
+\r
+// Function: udi_gfx_unbind_req\r
+// function pointer prototype for disconnecting a block device\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_block_bind_cb_t>\r
+//\r
+typedef void udi_gfx_unbind_req_op_t (udi_gfx_bind_cb_t *cb );\r
+udi_gfx_unbind_req_op_t udi_gfx_unbind_req;\r
+\r
+// Function: udi_gfx_unbind_ack\r
+// function pointer prototype for connecting to a block device\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_bind_cb_t>\r
+//\r
+typedef void udi_gfx_unbind_ack_op_t (udi_gfx_bind_cb_t *cb );\r
+udi_gfx_unbind_ack_op_t udi_gfx_unbind_ack;\r
+\r
+// Structure: udi_gfx_state_cb_t\r
+// Contains the operations of a read/write transaction\r
+typedef struct {\r
+ // Variable: gcb\r
+ // The main control block\r
+ udi_cb_t gcb; \r
+ udi_ubit32_t subsystem;\r
+ udi_ubit32_t attribute;\r
+} udi_gfx_state_cb_t;\r
+#define UDI_GFX_STATE_CB_NUM 2\r
+\r
+// Function: udi_gfx_set_engine_req\r
+// function pointer prototype for setting an engine state\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_state_cb_t>\r
+//\r
+typedef void udi_gfx_set_engine_req_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value);\r
+udi_gfx_set_engine_req_op_t udi_gfx_set_engine_req;\r
+\r
+// Function: udi_gfx_set_connector_req\r
+// function pointer prototype for setting an connector state\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_state_cb_t>\r
+//\r
+typedef void udi_gfx_set_connector_req_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value);\r
+udi_gfx_set_connector_req_op_t udi_gfx_set_connector_req;\r
+\r
+// Function: udi_gfx_set_engine_ack\r
+// function pointer prototype for setting an engine state\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_state_cb_t>\r
+//\r
+typedef void udi_gfx_set_engine_ack_op_t (udi_gfx_state_cb_t *cb );\r
+udi_gfx_set_engine_ack_op_t udi_gfx_set_engine_ack;\r
+\r
+// Function: udi_gfx_set_connector_ack\r
+// function pointer prototype for setting an engine state\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_state_cb_t>\r
+//\r
+typedef void udi_gfx_set_connector_ack_op_t (udi_gfx_state_cb_t *cb );\r
+udi_gfx_set_connector_ack_op_t udi_gfx_set_connector_ack;\r
+\r
+// Function: udi_gfx_get_engine_req\r
+// function pointer prototype for setting an engine state\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_state_cb_t>\r
+//\r
+typedef void udi_gfx_get_engine_req_op_t (udi_gfx_state_cb_t *cb );\r
+udi_gfx_get_engine_req_op_t udi_gfx_get_engine_req;\r
+\r
+// Function: udi_gfx_get_connector_req\r
+// function pointer prototype for setting an connector state\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_state_cb_t>\r
+//\r
+typedef void udi_gfx_get_connector_req_op_t (udi_gfx_state_cb_t *cb );\r
+udi_gfx_get_connector_req_op_t udi_gfx_get_connector_req;\r
+\r
+// Function: udi_gfx_get_engine_ack\r
+// function pointer prototype for setting an engine state\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_state_cb_t>\r
+//\r
+typedef void udi_gfx_get_engine_ack_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value);\r
+udi_gfx_get_engine_ack_op_t udi_gfx_get_engine_ack;\r
+\r
+// Function: udi_gfx_get_connector_ack\r
+// function pointer prototype for setting an engine state\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_state_cb_t>\r
+//\r
+typedef void udi_gfx_get_connector_ack_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value);\r
+udi_gfx_get_connector_ack_op_t udi_gfx_get_connector_ack;\r
+\r
+// Function: udi_gfx_set_engine_nak\r
+// function pointer prototype for setting an engine state\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_state_cb_t>\r
+// status - An UDI status value indicative of the error\r
+//\r
+typedef void udi_gfx_set_engine_nak_op_t (udi_gfx_state_cb_t *cb, udi_status_t status);\r
+udi_gfx_set_engine_nak_op_t udi_gfx_set_engine_nak;\r
+\r
+// Function: udi_gfx_set_connector_nak\r
+// function pointer prototype for setting an engine state\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_state_cb_t>\r
+// status - An UDI status value indicative of the error\r
+//\r
+typedef void udi_gfx_set_connector_nak_op_t (udi_gfx_state_cb_t *cb, udi_status_t status);\r
+udi_gfx_set_connector_nak_op_t udi_gfx_get_connector_nak;\r
+\r
+// Structure: udi_gfx_range_cb_t\r
+// Contains the operations of a range request transaction\r
+typedef struct {\r
+ // Variable: gcb\r
+ // The main control block\r
+ udi_cb_t gcb; \r
+ udi_ubit32_t subsystem;\r
+ udi_ubit32_t attribute;\r
+ udi_buf_t * rangedata; \r
+} udi_gfx_range_cb_t;\r
+#define UDI_GFX_RANGE_CB_NUM 3\r
+\r
+// Function: udi_gfx_range_engine_req\r
+// function pointer prototype for getting an engine property range\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_range_cb_t>\r
+//\r
+typedef void udi_gfx_range_engine_req_op_t (udi_gfx_range_cb_t *cb );\r
+udi_gfx_range_engine_req_op_t udi_gfx_range_engine_req;\r
+\r
+// Function: udi_gfx_range_connector_req\r
+// function pointer prototype for getting a connector property range\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_range_cb_t>\r
+//\r
+typedef void udi_gfx_range_connector_req_op_t (udi_gfx_range_cb_t *cb );\r
+udi_gfx_range_connector_req_op_t udi_gfx_range_connector_req;\r
+\r
+// Function: udi_gfx_range_engine_ack\r
+// function pointer prototype for replying an engine property range\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_range_cb_t>\r
+//\r
+typedef void udi_gfx_range_engine_ack_op_t (udi_gfx_range_cb_t *cb );\r
+udi_gfx_range_engine_ack_op_t udi_gfx_range_engine_ack;\r
+\r
+// Function: udi_gfx_range_connector_ack\r
+// function pointer prototype for replying a connector property range\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_range_cb_t>\r
+//\r
+typedef void udi_gfx_range_connector_ack_op_t (udi_gfx_range_cb_t *cb );\r
+udi_gfx_range_connector_ack_op_t udi_gfx_range_connector_ack;\r
+\r
+// Function: udi_gfx_get_engine_operator_req\r
+// function pointer prototype for requesting the engine operator layout\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_state_cb_t>\r
+//\r
+typedef void udi_gfx_get_engine_operator_req_op_t (udi_gfx_range_cb_t *cb );\r
+udi_gfx_get_engine_operator_req_op_t udi_gfx_get_engine_operator_req;\r
+\r
+// Function: udi_gfx_get_engine_operator_ack\r
+// function pointer prototype for replying the engine operator layout\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_state_cb_t>\r
+// op - The operator performed at this index\r
+// arg1 - the first argument to this operator\r
+// arg2 - the second argument to this operator\r
+// arg3 - the third argument to this operator\r
+//\r
+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 );\r
+udi_gfx_get_engine_operator_ack_op_t udi_gfx_get_engine_operator_ack;\r
+\r
+\r
+\r
+// Structure: udi_gfx_command_cb_t\r
+// Contains the operations of a command sequence\r
+typedef struct {\r
+ // Variable: gcb\r
+ // The main control block\r
+ udi_cb_t gcb; \r
+ udi_buf_t * commanddata;\r
+} udi_gfx_command_cb_t;\r
+#define UDI_GFX_COMMAND_CB_NUM 4\r
+\r
+// Function: udi_gfx_connector_command_req\r
+// function pointer prototype for sending command data to the output connector\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_command_cb_t>\r
+//\r
+typedef void udi_gfx_connector_command_req_op_t (udi_gfx_command_cb_t *cb );\r
+udi_gfx_connector_command_req_op_t udi_gfx_connector_command_req;\r
+\r
+// Function: udi_gfx_engine_command_req\r
+// function pointer prototype for sending command data to the engine\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_command_cb_t>\r
+//\r
+typedef void udi_gfx_engine_command_req_op_t (udi_gfx_command_cb_t *cb );\r
+udi_gfx_engine_command_req_op_t udi_gfx_engine_command_req;\r
+\r
+// Function: udi_gfx_connector_command_ack\r
+// function pointer prototype for sending command data replies\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_command_cb_t>\r
+//\r
+typedef void udi_gfx_connector_command_ack_op_t (udi_gfx_command_cb_t *cb);\r
+udi_gfx_connector_command_ack_op_t udi_gfx_connector_command_ack;\r
+\r
+// Function: udi_gfx_engine_command_ack\r
+// function pointer prototype for sending engine data replies\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_command_cb_t>\r
+//\r
+typedef void udi_gfx_engine_command_ack_op_t (udi_gfx_command_cb_t *cb);\r
+udi_gfx_engine_command_ack_op_t udi_gfx_engine_command_ack;\r
+\r
+// Structure: udi_gfx_buffer_cb_t\r
+// Contains a description of a buffer, or area thereof\r
+typedef struct {\r
+ // Variable: gcb\r
+ // The main control block\r
+ udi_cb_t gcb; \r
+ udi_ubit32_t buffer_index;\r
+} udi_gfx_buffer_info_cb_t;\r
+\r
+// Function: udi_gfx_buffer_info_req\r
+// function pointer prototype for getting buffer configuration information\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_command_cb_t>\r
+//\r
+typedef void udi_gfx_buffer_info_req_op_t (udi_gfx_buffer_info_cb_t *cb);\r
+udi_gfx_buffer_info_req_op_t udi_gfx_buffer_info_req;\r
+\r
+// Function: udi_gfx_buffer_info_ack\r
+// function pointer prototype for getting buffer configuration information\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_command_cb_t>\r
+// width - The width of the buffer\r
+// height - The height of the buffer\r
+// bitsper - The number of bits read from the buffer per pixel unit\r
+// flags - A bitfield of <UDI_GFX_BUFFER_FLAGS> indicating the exposed \r
+// capabilities of this buffer\r
+//\r
+// Note that bitsper might not be a multiple of eight.\r
+//\r
+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);\r
+udi_gfx_buffer_info_ack_op_t udi_gfx_buffer_info_ack;\r
+\r
+// Structure: udi_gfx_buffer_cb_t\r
+// Contains a description of a buffer, or area thereof\r
+typedef struct {\r
+ // Variable: gcb\r
+ // The main control block\r
+ udi_cb_t gcb; \r
+ udi_ubit32_t buffer_index;\r
+ udi_ubit32_t x;\r
+ udi_ubit32_t y;\r
+ udi_ubit32_t width;\r
+ udi_ubit32_t height;\r
+ udi_buf_t * buffer;\r
+} udi_gfx_buffer_cb_t;\r
+\r
+// Function: udi_gfx_buffer_write_req_op_t\r
+// function pointer prototype for writing raw hardware buffers\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_buffer_cb_t>\r
+//\r
+typedef void udi_gfx_buffer_write_req_op_t (udi_gfx_buffer_cb_t *cb);\r
+udi_gfx_buffer_write_req_op_t udi_gfx_buffer_write_req;\r
+\r
+// Function: udi_gfx_buffer_write_req_op_t\r
+// function pointer prototype for reading raw hardware buffers\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_buffer_cb_t>\r
+//\r
+typedef void udi_gfx_buffer_read_req_op_t (udi_gfx_buffer_cb_t *cb);\r
+udi_gfx_buffer_read_req_op_t udi_gfx_buffer_read_req;\r
+\r
+// Function: udi_gfx_buffer_write_ack_op_t\r
+// function pointer prototype for writing raw hardware buffers\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_buffer_cb_t>\r
+//\r
+typedef void udi_gfx_buffer_write_ack_op_t (udi_gfx_buffer_cb_t *cb);\r
+udi_gfx_buffer_write_ack_op_t udi_gfx_buffer_write_ack;\r
+\r
+// Function: udi_gfx_buffer_write_ack_op_t\r
+// function pointer prototype for reading raw hardware buffers\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_buffer_cb_t>\r
+//\r
+typedef void udi_gfx_buffer_read_ack_op_t (udi_gfx_buffer_cb_t *cb);\r
+udi_gfx_buffer_read_ack_op_t udi_gfx_buffer_read_ack;\r
+\r
+// Function: udi_gfx_buffer_write_nak_op_t\r
+// error handling for buffer writes\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_buffer_cb_t>\r
+//\r
+typedef void udi_gfx_buffer_write_nak_op_t (udi_gfx_buffer_cb_t *cb, udi_status_t status);\r
+udi_gfx_buffer_write_nak_op_t udi_gfx_buffer_write_nak;\r
+\r
+// Function: udi_gfx_buffer_write_nak_op_t\r
+// error handling for buffer reads\r
+// \r
+// in:\r
+// cb - A pointer to a <udi_gfx_buffer_cb_t>\r
+//\r
+typedef void udi_gfx_buffer_read_nak_op_t (udi_gfx_buffer_cb_t *cb, udi_status_t status);\r
+udi_gfx_buffer_read_nak_op_t udi_gfx_buffer_read_nak;\r
+\r
+/* Structure: udi_gfx_provider_ops_t\r
+ * \r
+ * The graphics metalanguage entry points (provider side)\r
+ */\r
+typedef const struct {\r
+ udi_channel_event_ind_op_t *channel_event_ind_op;\r
+ udi_gfx_bind_req_op_t *gfx_bind_req_op;\r
+ udi_gfx_unbind_req_op_t *gfx_unbind_req_op;\r
+ udi_gfx_set_connector_req_op_t *gfx_set_connector_req_op;\r
+ udi_gfx_set_engine_req_op_t *gfx_set_engine_req_op;\r
+ udi_gfx_get_connector_req_op_t *gfx_get_connector_req_op;\r
+ udi_gfx_get_engine_req_op_t *gfx_get_engine_req_op;\r
+ udi_gfx_range_connector_req_op_t *gfx_range_connector_req_op;\r
+ udi_gfx_range_engine_req_op_t *gfx_range_engine_req_op;\r
+ udi_gfx_get_engine_operator_req_op_t*gfx_get_engine_operator_req_op;\r
+ udi_gfx_connector_command_req_op_t *gfx_connector_command_req_op;\r
+ udi_gfx_engine_command_req_op_t *gfx_engine_command_req_op;\r
+ udi_gfx_buffer_info_req_op_t *gfx_buffer_info_req_op;\r
+ udi_gfx_buffer_read_req_op_t *gfx_buffer_read_req_op;\r
+ udi_gfx_buffer_write_req_op_t *gfx_buffer_write_req_op;\r
+} udi_gfx_provider_ops_t;\r
+\r
+/* Structure: udi_gfx_client_ops_t\r
+ *\r
+ * The graphics metalanguage entry points (client side)\r
+ */\r
+typedef const struct {\r
+ udi_channel_event_ind_op_t *channel_event_ind_op;\r
+ udi_gfx_bind_ack_op_t *gfx_bind_ack_op;\r
+ udi_gfx_unbind_ack_op_t *gfx_unbind_ack_op;\r
+ udi_gfx_set_connector_ack_op_t *gfx_set_connector_ack_op;\r
+ udi_gfx_set_engine_ack_op_t *gfx_set_engine_ack_op;\r
+ udi_gfx_set_connector_nak_op_t *gfx_set_connector_nak_op;\r
+ udi_gfx_set_engine_nak_op_t *gfx_set_engine_nak_op;\r
+ udi_gfx_get_connector_ack_op_t *gfx_get_connector_ack_op;\r
+ udi_gfx_get_engine_ack_op_t *gfx_get_engine_ack_op;\r
+ udi_gfx_range_connector_ack_op_t *gfx_range_connector_ack_op;\r
+ udi_gfx_range_engine_ack_op_t *gfx_range_engine_ack_op;\r
+ udi_gfx_get_engine_operator_req_op_t*gfx_get_engine_operator_ack_op;\r
+ udi_gfx_connector_command_ack_op_t *gfx_connector_command_ack_op;\r
+ udi_gfx_engine_command_ack_op_t *gfx_engine_command_ack_op;\r
+ udi_gfx_buffer_info_ack_op_t *gfx_buffer_info_ack_op;\r
+ udi_gfx_buffer_read_ack_op_t *gfx_buffer_read_ack_op;\r
+ udi_gfx_buffer_write_ack_op_t *gfx_buffer_write_ack_op;\r
+ udi_gfx_buffer_read_nak_op_t *gfx_buffer_read_nak_op;\r
+ udi_gfx_buffer_write_nak_op_t *gfx_buffer_write_nak_op;\r
+} udi_gfx_client_ops_t;\r
+\r
+\r
+// temporary\r
+#ifndef UDI_ANNOY_ME\r
+void EngineReturnSimpleRange (int source, int index, int prop, int first, int last, int modulus);\r
+void ConnectorReturnSimpleRange (int source, int index, int prop, int first, int last, int modulus);\r
+void EngineReturnConstantRange (int source, int index, int prop, int value);\r
+void ConnectorReturnConstantRange (int source, int index, int prop, int value);\r
+void EngineReturnBooleanRange (int source, int index, int prop, int value1, int value2);\r
+void ConnectorReturnBooleanRange (int source, int index, int prop, int value1, int value2);\r
+#endif\r
+\r
+#endif\r
#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
#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
#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
#include <physio/meta_bus.h>
#include "physio/pio.h"
-#include "physio/pci.h"
-
#endif
-include ../Makefile.cfg\r
\r
CPPFLAGS += -I./include\r
-LDFLAGS += -lreadline\r
+LDFLAGS +=\r
+LIBS += -lreadline\r
\r
BIN = CLIShell\r
OBJ = main.o lib.o\r
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
# - 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
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
@$(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
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 $@
BIN := AxWinUI
OBJ := main.o
-LDFLAGS += -laxwin3
+LIBS += -laxwin3
-include ../../Makefile.tpl
OBJ := main.o input.o video.o ipc_acess.o
include common.mk
-LDFLAGS += -lnet
+LIBS += -lnet
-include ../../Makefile.tpl
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
#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
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
}
#include <wm_messages.h>
#include <decorator.h>
#include <axwin3/keysyms.h>
+#include <wm_hotkeys.h>
// === IMPORTS ===
extern int Renderer_Menu_Init(void);
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+%:
+ @echo --- AxWin4 Server
+ @make -C Server/ $*
+ @echo --- AxWin4 UI
+ @make -C UI/ $*
--- /dev/null
+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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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 );
+}
+
+};
+
--- /dev/null
+/*
+ * 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;
+}
+
+};
+
--- /dev/null
+/*
+ * 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
+
+
--- /dev/null
+/*
+ * 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);
+}
+
+};
+
--- /dev/null
+
+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)
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ */
+#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
+
--- /dev/null
+/*
+ */
+#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
+
--- /dev/null
+/*
+ * 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
+
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ */
+#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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ */
+#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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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;
+}
+
+
+}
+
--- /dev/null
+/*
+ */
+#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
+
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+
+include ../../Makefile.cfg
+
+DIR := Apps/AxWin/4.0
+
+OBJ := main.o taskbar.o
+
+BIN := AxWinUI
+
+LIBS += -laxwin4
+
+include ../../Makefile.tpl
--- /dev/null
+/*
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+extern unsigned int giScreenWidth;
+extern unsigned int giScreenHeight;
+
+#endif
+
--- /dev/null
+/*
+ */
+#ifndef _TASKBAR_H_
+#define _TASKBAR_H_
+
+#include <stdbool.h>
+
+extern void Taskbar_Create(void);
+extern void Taskbar_Redraw(void);
+
+#endif
+
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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);
+}
+
-include ../Makefile.cfg
-LDFLAGS += -laxwin3
+LIBS += -laxwin3
OBJ = main.o strings.o toolbar.o
BIN = ate
-include ../Makefile.cfg
-LDFLAGS += -laxwin3 -lunicode
+LIBS += -laxwin3 -lunicode
OBJ = main.o vt100.o display.o
BIN = terminal
# 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;
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)",
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);
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);
}
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])
{
// 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 ++ )
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;
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;
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':
#include <string.h>
#include "common.h"
#include <ctype.h>
+#include <inttypes.h>
// === CONSTANTS ===
#define DEFAULT_SHELL "/Acess/SBin/login"
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);
}
_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);
}
// 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);
-include ../Makefile.cfg
-LDFLAGS += -lnet
+LDFLAGS +=
+LIBS += -lnet
OBJ = main.o addr.o routes.o
BIN = ip
-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
--- /dev/null
+/*
+ */
+#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
+
--- /dev/null
+/*
+ */
+#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;
+}
--- /dev/null
+/*
+ */
+#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
+
#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[])
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;
}
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();
}
/**
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';
-}
--- /dev/null
+/*
+ */
+#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
+
--- /dev/null
+/*
+ */
+#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);
+}
+
--- /dev/null
+/*
+ */
+#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
+
--- /dev/null
+/*
+ */
+#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);
+ }
+ }
+}
--- /dev/null
+/*
+ */
+#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
+
--- /dev/null
+/*
+ */
+#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);
+}
+
--- /dev/null
+/*
+ */
+#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
-include ../Makefile.cfg
-LDFLAGS += -lnet
+LIBS += -lnet
OBJ = main.o
BIN = ping
-include ../Makefile.cfg
-LDFLAGS += -lnet -lreadline
+LIBS += -lnet -lreadline
OBJ = main.o
BIN = telnet
-include ../Makefile.cfg
-LDFLAGS += -lnet
+LIBS += -lnet
OBJ = main.o
BIN = telnetd
-include ../Makefile.cfg
CFLAGS += -std=gnu99
-LDFLAGS += -lnet -lpsocket -luri
+LIBS += -lnet -lpsocket -luri
+
OBJ = main.o
BIN = wget
_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
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
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))
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/%
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)
# 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 $@)
-$(_OBJPREFIX)%.o: %.cc
+$(_OBJPREFIX)%.o: %.cc Makefile
@echo [CXX] -o $@
@mkdir -p $(dir $@)
-$(_OBJPREFIX)%.ao: %.$(ASSUFFIX)
+$(_OBJPREFIX)%.o: %.cpp Makefile
+ @echo [CXX] -o $@
+ @mkdir -p $(dir $@)
+
+$(_OBJPREFIX)%.ao: %.$(ASSUFFIX) Makefile
@echo [AS] -o $@
@mkdir -p $(dir $@)
$V$(AS) $(ASFLAGS) -o $@ $<
obj-native/%.no: %.c
@mkdir -p $(dir $@)
+ @echo [CC Native] -o $@
+ @$(NCC) -g -c $< -o $@ -Wall -std=gnu99 -MD -MP -MF
[email protected] '-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)
+++ /dev/null
-acess_native.ld.h
+++ /dev/null
-#
-# 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)/' > $@
+++ /dev/null
-/* 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_*) }
-}
-
-
+++ /dev/null
-/* 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_*) }
-}
-
-
+++ /dev/null
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")\r
-OUTPUT_ARCH(i386)\r
-ENTRY(start)\r
-SEARCH_DIR(__LIBDIR)\r
-INPUT(crt0.o)\r
-SECTIONS\r
-{\r
- /* Read-only sections, merged into text segment: */\r
- PROVIDE (__executable_start = 0x08048000); . = 0x08048000 + SIZEOF_HEADERS;\r
- .interp : { *(.interp) }\r
- .note.gnu.build-id : { *(.note.gnu.build-id) }\r
- .hash : { *(.hash) }\r
- .gnu.hash : { *(.gnu.hash) }\r
- .dynsym : { *(.dynsym) }\r
- .dynstr : { *(.dynstr) }\r
- .gnu.version : { *(.gnu.version) }\r
- .gnu.version_d : { *(.gnu.version_d) }\r
- .gnu.version_r : { *(.gnu.version_r) }\r
- .rel.dyn :\r
- {\r
- *(.rel.init)\r
- *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)\r
- *(.rel.fini)\r
- *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)\r
- *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)\r
- *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)\r
- *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)\r
- *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)\r
- *(.rel.ctors)\r
- *(.rel.dtors)\r
- *(.rel.got)\r
- *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)\r
- }\r
- .rela.dyn :\r
- {\r
- *(.rela.init)\r
- *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)\r
- *(.rela.fini)\r
- *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)\r
- *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)\r
- *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)\r
- *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)\r
- *(.rela.ctors)\r
- *(.rela.dtors)\r
- *(.rela.got)\r
- *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)\r
- }\r
- .rel.plt : { *(.rel.plt) }\r
- .rela.plt : { *(.rela.plt) }\r
- .init :\r
- {\r
- KEEP (*(.init))\r
- } =0x90909090\r
- .plt : { *(.plt) }\r
- .text :\r
- {\r
- *(.text .stub .text.* .gnu.linkonce.t.*)\r
- /* .gnu.warning sections are handled specially by elf32.em. */\r
- *(.gnu.warning)\r
- } =0x90909090\r
- .fini :\r
- {\r
- KEEP (*(.fini))\r
- } =0x90909090\r
- PROVIDE (__etext = .);\r
- PROVIDE (_etext = .);\r
- PROVIDE (etext = .);\r
- .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }\r
- .rodata1 : { *(.rodata1) }\r
- .eh_frame_hdr : { *(.eh_frame_hdr) }\r
- .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }\r
- .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }\r
- /* Adjust the address for the data segment. We want to adjust up to\r
- the same address within the page on the next page up. */\r
- . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));\r
- /* Exception handling */\r
- .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }\r
- .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }\r
- /* Thread Local Storage sections */\r
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }\r
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }\r
- .preinit_array :\r
- {\r
- PROVIDE_HIDDEN (__preinit_array_start = .);\r
- KEEP (*(.preinit_array))\r
- PROVIDE_HIDDEN (__preinit_array_end = .);\r
- }\r
- .init_array :\r
- {\r
- PROVIDE_HIDDEN (__init_array_start = .);\r
- KEEP (*(SORT(.init_array.*)))\r
- KEEP (*(.init_array))\r
- PROVIDE_HIDDEN (__init_array_end = .);\r
- }\r
- .fini_array :\r
- {\r
- PROVIDE_HIDDEN (__fini_array_start = .);\r
- KEEP (*(.fini_array))\r
- KEEP (*(SORT(.fini_array.*)))\r
- PROVIDE_HIDDEN (__fini_array_end = .);\r
- }\r
- .ctors :\r
- {\r
- /* gcc uses crtbegin.o to find the start of\r
- the constructors, so we make sure it is\r
- first. Because this is a wildcard, it\r
- doesn't matter if the user does not\r
- actually link against crtbegin.o; the\r
- linker won't look for a file to match a\r
- wildcard. The wildcard also means that it\r
- doesn't matter which directory crtbegin.o\r
- is in. */\r
- KEEP (*crtbegin.o(.ctors))\r
- KEEP (*crtbegin?.o(.ctors))\r
- /* We don't want to include the .ctor section from\r
- the crtend.o file until after the sorted ctors.\r
- The .ctor section from the crtend file contains the\r
- end of ctors marker and it must be last */\r
- KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))\r
- KEEP (*(SORT(.ctors.*)))\r
- KEEP (*(.ctors))\r
- }\r
- .dtors :\r
- {\r
- KEEP (*crtbegin.o(.dtors))\r
- KEEP (*crtbegin?.o(.dtors))\r
- KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))\r
- KEEP (*(SORT(.dtors.*)))\r
- KEEP (*(.dtors))\r
- }\r
- .jcr : { KEEP (*(.jcr)) }\r
- .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }\r
- .dynamic : { *(.dynamic) }\r
- .got : { *(.got) }\r
- . = DATA_SEGMENT_RELRO_END (12, .);\r
- .got.plt : { *(.got.plt) }\r
- .data :\r
- {\r
- *(.data .data.* .gnu.linkonce.d.*)\r
- SORT(CONSTRUCTORS)\r
- }\r
- .data1 : { *(.data1) }\r
- _edata = .; PROVIDE (edata = .);\r
- __bss_start = .;\r
- .bss :\r
- {\r
- *(.dynbss)\r
- *(.bss .bss.* .gnu.linkonce.b.*)\r
- *(COMMON)\r
- /* Align here to ensure that the .bss section occupies space up to\r
- _end. Align after .bss to ensure correct alignment even if the\r
- .bss section disappears because there are no input sections.\r
- FIXME: Why do we need it? When there is no .bss section, we don't\r
- pad the .data section. */\r
- . = ALIGN(. != 0 ? 32 / 8 : 1);\r
- }\r
- . = ALIGN(32 / 8);\r
- . = ALIGN(32 / 8);\r
- _end = .; PROVIDE (end = .);\r
- . = DATA_SEGMENT_END (.);\r
- /* Stabs debugging sections. */\r
- .stab 0 : { *(.stab) }\r
- .stabstr 0 : { *(.stabstr) }\r
- .stab.excl 0 : { *(.stab.excl) }\r
- .stab.exclstr 0 : { *(.stab.exclstr) }\r
- .stab.index 0 : { *(.stab.index) }\r
- .stab.indexstr 0 : { *(.stab.indexstr) }\r
- .comment 0 : { *(.comment) }\r
- /* DWARF debug sections.\r
- Symbols in the DWARF debugging sections are relative to the beginning\r
- of the section so we begin them at 0. */\r
- /* DWARF 1 */\r
- .debug 0 : { *(.debug) }\r
- .line 0 : { *(.line) }\r
- /* GNU DWARF 1 extensions */\r
- .debug_srcinfo 0 : { *(.debug_srcinfo) }\r
- .debug_sfnames 0 : { *(.debug_sfnames) }\r
- /* DWARF 1.1 and DWARF 2 */\r
- .debug_aranges 0 : { *(.debug_aranges) }\r
- .debug_pubnames 0 : { *(.debug_pubnames) }\r
- /* DWARF 2 */\r
- .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }\r
- .debug_abbrev 0 : { *(.debug_abbrev) }\r
- .debug_line 0 : { *(.debug_line) }\r
- .debug_frame 0 : { *(.debug_frame) }\r
- .debug_str 0 : { *(.debug_str) }\r
- .debug_loc 0 : { *(.debug_loc) }\r
- .debug_macinfo 0 : { *(.debug_macinfo) }\r
- /* SGI/MIPS DWARF 2 extensions */\r
- .debug_weaknames 0 : { *(.debug_weaknames) }\r
- .debug_funcnames 0 : { *(.debug_funcnames) }\r
- .debug_typenames 0 : { *(.debug_typenames) }\r
- .debug_varnames 0 : { *(.debug_varnames) }\r
- /* DWARF 3 */\r
- .debug_pubtypes 0 : { *(.debug_pubtypes) }\r
- .debug_ranges 0 : { *(.debug_ranges) }\r
- .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }\r
- /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) }\r
-}\r
+++ /dev/null
-OUTPUT_FORMAT("elf64-x86-64")\r
-/* OUTPUT_ARCH(x86_64) */\r
-ENTRY(start)\r
-SEARCH_DIR(__LIBDIR)\r
-INPUT(crt0.o)\r
-SECTIONS\r
-{\r
- /* Read-only sections, merged into text segment: */\r
- PROVIDE (__executable_start = 0x00400000); . = 0x00400000 + SIZEOF_HEADERS;\r
- .interp : { *(.interp) }\r
- .note.gnu.build-id : { *(.note.gnu.build-id) }\r
- .hash : { *(.hash) }\r
- .gnu.hash : { *(.gnu.hash) }\r
- .dynsym : { *(.dynsym) }\r
- .dynstr : { *(.dynstr) }\r
- .gnu.version : { *(.gnu.version) }\r
- .gnu.version_d : { *(.gnu.version_d) }\r
- .gnu.version_r : { *(.gnu.version_r) }\r
- .rel.dyn :\r
- {\r
- *(.rel.init)\r
- *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)\r
- *(.rel.fini)\r
- *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)\r
- *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)\r
- *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)\r
- *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)\r
- *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)\r
- *(.rel.ctors)\r
- *(.rel.dtors)\r
- *(.rel.got)\r
- *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)\r
- }\r
- .rela.dyn :\r
- {\r
- *(.rela.init)\r
- *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)\r
- *(.rela.fini)\r
- *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)\r
- *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)\r
- *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)\r
- *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)\r
- *(.rela.ctors)\r
- *(.rela.dtors)\r
- *(.rela.got)\r
- *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)\r
- }\r
- .rel.plt : { *(.rel.plt) }\r
- .rela.plt : { *(.rela.plt) }\r
- .init :\r
- {\r
- KEEP (*(.init))\r
- } =0x90909090\r
- .plt : { *(.plt) }\r
- .text :\r
- {\r
- *(.text .stub .text.* .gnu.linkonce.t.*)\r
- /* .gnu.warning sections are handled specially by elf32.em. */\r
- *(.gnu.warning)\r
- } =0x90909090\r
- .fini :\r
- {\r
- KEEP (*(.fini))\r
- } =0x90909090\r
- PROVIDE (__etext = .);\r
- PROVIDE (_etext = .);\r
- PROVIDE (etext = .);\r
- .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }\r
- .rodata1 : { *(.rodata1) }\r
- .eh_frame_hdr : { *(.eh_frame_hdr) }\r
- .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }\r
- .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }\r
- /* Adjust the address for the data segment. We want to adjust up to\r
- the same address within the page on the next page up. */\r
- . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));\r
- /* Exception handling */\r
- .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }\r
- .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }\r
- /* Thread Local Storage sections */\r
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }\r
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }\r
- .preinit_array :\r
- {\r
- PROVIDE_HIDDEN (__preinit_array_start = .);\r
- KEEP (*(.preinit_array))\r
- PROVIDE_HIDDEN (__preinit_array_end = .);\r
- }\r
- .init_array :\r
- {\r
- PROVIDE_HIDDEN (__init_array_start = .);\r
- KEEP (*(SORT(.init_array.*)))\r
- KEEP (*(.init_array))\r
- PROVIDE_HIDDEN (__init_array_end = .);\r
- }\r
- .fini_array :\r
- {\r
- PROVIDE_HIDDEN (__fini_array_start = .);\r
- KEEP (*(.fini_array))\r
- KEEP (*(SORT(.fini_array.*)))\r
- PROVIDE_HIDDEN (__fini_array_end = .);\r
- }\r
- .ctors :\r
- {\r
- /* gcc uses crtbegin.o to find the start of\r
- the constructors, so we make sure it is\r
- first. Because this is a wildcard, it\r
- doesn't matter if the user does not\r
- actually link against crtbegin.o; the\r
- linker won't look for a file to match a\r
- wildcard. The wildcard also means that it\r
- doesn't matter which directory crtbegin.o\r
- is in. */\r
- KEEP (*crtbegin.o(.ctors))\r
- KEEP (*crtbegin?.o(.ctors))\r
- /* We don't want to include the .ctor section from\r
- the crtend.o file until after the sorted ctors.\r
- The .ctor section from the crtend file contains the\r
- end of ctors marker and it must be last */\r
- KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))\r
- KEEP (*(SORT(.ctors.*)))\r
- KEEP (*(.ctors))\r
- }\r
- .dtors :\r
- {\r
- KEEP (*crtbegin.o(.dtors))\r
- KEEP (*crtbegin?.o(.dtors))\r
- KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))\r
- KEEP (*(SORT(.dtors.*)))\r
- KEEP (*(.dtors))\r
- }\r
- .jcr : { KEEP (*(.jcr)) }\r
- .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }\r
- .dynamic : { *(.dynamic) }\r
- .got : { *(.got) }\r
- . = DATA_SEGMENT_RELRO_END (12, .);\r
- .got.plt : { *(.got.plt) }\r
- .data :\r
- {\r
- *(.data .data.* .gnu.linkonce.d.*)\r
- SORT(CONSTRUCTORS)\r
- }\r
- .data1 : { *(.data1) }\r
- _edata = .; PROVIDE (edata = .);\r
- __bss_start = .;\r
- .bss :\r
- {\r
- *(.dynbss)\r
- *(.bss .bss.* .gnu.linkonce.b.*)\r
- *(COMMON)\r
- /* Align here to ensure that the .bss section occupies space up to\r
- _end. Align after .bss to ensure correct alignment even if the\r
- .bss section disappears because there are no input sections.\r
- FIXME: Why do we need it? When there is no .bss section, we don't\r
- pad the .data section. */\r
- . = ALIGN(. != 0 ? 32 / 8 : 1);\r
- }\r
- . = ALIGN(32 / 8);\r
- . = ALIGN(32 / 8);\r
- _end = .; PROVIDE (end = .);\r
- . = DATA_SEGMENT_END (.);\r
- /* Stabs debugging sections. */\r
- .stab 0 : { *(.stab) }\r
- .stabstr 0 : { *(.stabstr) }\r
- .stab.excl 0 : { *(.stab.excl) }\r
- .stab.exclstr 0 : { *(.stab.exclstr) }\r
- .stab.index 0 : { *(.stab.index) }\r
- .stab.indexstr 0 : { *(.stab.indexstr) }\r
- .comment 0 : { *(.comment) }\r
- /* DWARF debug sections.\r
- Symbols in the DWARF debugging sections are relative to the beginning\r
- of the section so we begin them at 0. */\r
- /* DWARF 1 */\r
- .debug 0 : { *(.debug) }\r
- .line 0 : { *(.line) }\r
- /* GNU DWARF 1 extensions */\r
- .debug_srcinfo 0 : { *(.debug_srcinfo) }\r
- .debug_sfnames 0 : { *(.debug_sfnames) }\r
- /* DWARF 1.1 and DWARF 2 */\r
- .debug_aranges 0 : { *(.debug_aranges) }\r
- .debug_pubnames 0 : { *(.debug_pubnames) }\r
- /* DWARF 2 */\r
- .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }\r
- .debug_abbrev 0 : { *(.debug_abbrev) }\r
- .debug_line 0 : { *(.debug_line) }\r
- .debug_frame 0 : { *(.debug_frame) }\r
- .debug_str 0 : { *(.debug_str) }\r
- .debug_loc 0 : { *(.debug_loc) }\r
- .debug_macinfo 0 : { *(.debug_macinfo) }\r
- /* SGI/MIPS DWARF 2 extensions */\r
- .debug_weaknames 0 : { *(.debug_weaknames) }\r
- .debug_funcnames 0 : { *(.debug_funcnames) }\r
- .debug_typenames 0 : { *(.debug_typenames) }\r
- .debug_varnames 0 : { *(.debug_varnames) }\r
- /* DWARF 3 */\r
- .debug_pubtypes 0 : { *(.debug_pubtypes) }\r
- .debug_ranges 0 : { *(.debug_ranges) }\r
- .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }\r
- /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) }\r
-}\r
+++ /dev/null
-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
-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)
$(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 $@
--- /dev/null
+.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. */
--- /dev/null
+.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
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);
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);
}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+.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. */
--- /dev/null
+.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. */
--- /dev/null
+.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. */
--- /dev/null
+.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
--- /dev/null
+.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. */
--- /dev/null
+.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
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))
# 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)
$(_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
b _exit
-@ Stupid GCC
+// Stupid GCC
.globl __ucmpdi2
__ucmpdi2:
cmp r0, r2
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
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)
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
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)
+
[global %1:func]
%1:
push rbx
+ push rbp
mov eax, %2
SYSCALL_OP
mov [DWORD rel _errno], ebx
+ pop rbp
pop rbx
ret
%endmacro
// === 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 ===
*
* 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
#include "common.h"
#include <stdint.h>
+#include <stdbool.h>
#ifndef assert
# include <assert.h>
#endif
#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
// === 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);
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]);
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]);
}
}
-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)
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:
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);
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);
// 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;
}
}
+ // TODO: Relocate symbols
+
// Relocation function
t_elf64_doreloc fpElf64DoReloc = &_Elf64DoReloc_X86_64;
#define _Elf64DoReloc(info, ptr, addend) fpElf64DoReloc(Base, strtab, symtab, info, ptr, addend)
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 );
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 );
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 );
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 );
}
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;
}
}
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;
}
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;
}
}
return 0;
}
#endif
-
+#endif
uint32_t ElfHashString(const char *name)
{
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
*/
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
};
/**
#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
#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 {
union {
Elf64_Xword d_val;
Elf64_Addr d_ptr;
- } d_un;
+ };// d_un;
} Elf64_Dyn;
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
{
--- /dev/null
+
+#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;
+}
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)
#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
#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
#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
--- /dev/null
+/*
+ * 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
+
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;
char data[];
} PACKED;
+struct ptycmd_senddata
+{
+ struct ptycmd_header hdr;
+ uint32_t ofs;
+} PACKED;
+
#endif
#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
// === 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);
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);
//#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);
*/
#include "common.h"
#include <stdint.h>
+#include <stdbool.h>
#include <acess/sys.h>
#define DEBUG 0
# define DEBUGS(v...)
#endif
-// === PROTOTYPES ===
-void *IsFileLoaded(const char *file);
+#define MAX_QUEUED_ENTRYPOINTS 8
// === IMPORTS ===
extern const struct {
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 ===
}
}
+/**
+ * \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
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;
DEBUGS(" LoadLibrary: SysLoadBin()");
// Load Library
+ tLibEntry *fEntry;
base = _SysLoadBin(filename, (void**)&fEntry);
if(!base) {
DEBUGS("LoadLibrary: RETURN 0");
}
// 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;
}
\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;
}
/**
#include <stdint.h>\r
#include <stddef.h>\r
#include "common.h"\r
+#undef SoMain\r
\r
// === PROTOTYPES ===\r
void *DoRelocate(void *base, char **envp, const char *Filename);\r
extern char gLinkedBase[];\r
char **gEnvP;\r
extern int memcmp(const void *m1, const void *m2, size_t size);\r
+extern void CallQueuedEntrypoints(char **EnvP);\r
\r
// === CODE ===\r
/**\r
}\r
\r
// Otherwise do relocations\r
- //ret = DoRelocate( base, envp, "Executable" );\r
ret = DoRelocate( base, NULL, "Executable" );\r
if( ret == 0 ) {\r
SysDebug("ld-acess - SoMain: Relocate failed, base=0x%x\n", base);\r
for(;;);\r
}\r
\r
- SysDebug("ld-acess - SoMain: ret = %p", ret); \r
+ // Call queued entry points (from libraries)\r
+ CallQueuedEntrypoints(envp);\r
+\r
+ SysDebug("ld-acess - SoMain: Program entry %p", ret); \r
return ret;\r
}\r
\r
--- /dev/null
+# 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)
+
+
+
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ */
+// === CODE ===
+int SoMain(void)
+{
+ return 0;
+}
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
CFLAGS += -Wall -Werror -Wextra\r
CXXFLAGS += -Wall -Werror -Wextra\r
ASFLAGS +=\r
-LDFLAGS += -Map map.txt -lc\r
+LDFLAGS += -nostdlib\r
+PRELINK := $(CRTI) $(CRTBEGINS) $(CRT0S)\r
+LIBS += -lc $(LIBGCC_PATH) $(CRTENDS) $(CRTN)\r
+USE_CXX_LINK := yes\r
\r
OBJ = misc.o new.o guard.o cxxabi.o typeinfo.o\r
+OBJ += string.o mutex.o\r
+OBJ += exceptions.o exception_handling.o system_error.o\r
+OBJ += gxx_personality.o\r
+ifeq ($(ARCHDIR),native)\r
+# - Include libgcc_eh (separate in linux), and the linux libc (space avoids hack in Makefile.tpl)\r
+LIBS += -lgcc_eh -l c\r
+endif\r
DEPFILES := $(OBJ:%.o=%.d)\r
BIN = libc++.so\r
ifeq ($(ARCHDIR),native)\r
- OBJ := $(filter-out heap.o,$(OBJ))\r
BIN = libc++_acess.so\r
endif\r
\r
*
* 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 {
}; // 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;
+}
+
--- /dev/null
+/*
+ * 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);
+ }
+}
+
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
+
--- /dev/null
+/*
+ * 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
+
* - 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();
}
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+
+#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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+extern "C" {
+#include <assert.h>
+}
--- /dev/null
+/*
+ */
+extern "C" {
+#include <errno.h>
+}
+// vim: ft=cpp
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ */
+extern "C" {
+#include <stdio.h>
+}
+// vim: ft=cpp
--- /dev/null
+/*
+ * 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
+
+
--- /dev/null
+/*
+ * 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
+
+
#ifndef _LIBCXX__CXXABI_H_
#define _LIBCXX__CXXABI_H_
+#include <cstddef>
+
#include <typeinfo>
namespace __cxxabiv1 {
};
};
+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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ */
+#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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+
+#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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
#ifndef _LIBCXX__TYPEINFO_
#define _LIBCXX__TYPEINFO_
+#include <cstddef>
+
namespace std {
// Type information class
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;
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
* - Miscelanious functions
*/
#include <string.h>
+#include <acess/sys.h>
+#include <exception>
extern "C" int SoMain()
{
+ //extern void _init();
+ //_init();
// nope
return 0;
}
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();
}
--- /dev/null
+/*
+ * 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;
+}
+
*/
#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";
}
--- /dev/null
+/*
+ * 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) );
+}
+
--- /dev/null
+/*
+ * 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
+
* - typeid and dynamic_cast
*/
#include <typeinfo>
+#include <cxxabi.h>
+#include <acess/sys.h>
+#include <cstdlib>
namespace std {
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;
}
}
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
--- /dev/null
+# 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
+
--- /dev/null
+/*
+ */
+#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;
+}
+
--- /dev/null
+/*
+ */
+#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
+
-include ../Makefile.cfg\r
\r
CPPFLAGS += \r
-CFLAGS += -Wall -Werror -Wextra\r
+CFLAGS += -nostdlib -Wall -Werror -Wextra\r
ASFLAGS +=\r
-LDFLAGS += -Map map.txt\r
+LDFLAGS += -nostdlib\r
+PRELINK := $(CRTI) $(CRTBEGINS) $(CRT0S)\r
+LIBS += $(LIBGCC_PATH) $(CRTENDS) $(CRTN)\r
\r
INCFILES := stdio.h stdlib.h\r
\r
DEPFILES := $(OBJ:%.o=%.d)\r
BIN = libc.so\r
ifeq ($(ARCHDIR),native)\r
- OBJ := $(filter-out heap.o,$(OBJ))\r
+ OBJ := $(filter-out heap.o,$(OBJ)) heap_native.o\r
#LDFLAGS += -l c\r
BIN = libc_acess.so\r
endif\r
include ../Makefile.tpl\r
\r
EXP_%.txt: TEST_%.native\r
- ./$< > $@\r
- rm $<\r
+ @./$< > $@\r
+ @rm $<\r
EXP_strtoi.txt:\r
echo -n "" > $@\r
\r
--- /dev/null
+/*
+ */
+#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);
+}
+
*/
#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);
+ }
}
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;
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) {
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";
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);
#include <acess/sys.h>\r
#include <stdlib.h>\r
#include <string.h>\r
+#include <assert.h>\r
+#include <stdbool.h>\r
#include "lib.h"\r
\r
#if 0\r
EXPORT void *malloc(size_t bytes);\r
void *_malloc(size_t bytes, void *owner);\r
EXPORT void *calloc(size_t bytes, size_t count);\r
+bool _libc_free(void *mem);\r
EXPORT void free(void *mem);\r
EXPORT void *realloc(void *mem, size_t bytes);\r
EXPORT void *sbrk(int increment);\r
\param mem Pointer - Memory to free\r
*/\r
EXPORT void free(void *mem)\r
+{\r
+ if( !_libc_free(mem) ) {\r
+ Heap_Validate(1);\r
+ exit(0);\r
+ }\r
+}\r
+\r
+// Exported for libc++\r
+EXPORT bool _libc_free(void *mem)\r
{\r
heap_head *head = (heap_head*)mem - 1;\r
\r
// Free of NULL or the zero allocation does nothing\r
if(!mem || mem == _heap_zero_allocation.data)\r
- return ;\r
+ return true;\r
\r
// Sanity check the head address\r
if(head->magic != MAGIC) {\r
if( head->magic != MAGIC_FREE ) {\r
- _SysDebug("Double free of %p", mem);\r
- Heap_Validate(1);\r
- exit(0);\r
+ _SysDebug("Double free of %p by %p", mem, __builtin_return_address(0));\r
}\r
else {\r
- _SysDebug("Free of invalid pointer %p", mem);\r
- Heap_Validate(1);\r
- exit(0);\r
+ _SysDebug("Free of invalid pointer %p by ", mem, __builtin_return_address(0));\r
}\r
- return;\r
+ return false;\r
}\r
\r
head->magic = MAGIC_FREE;\r
heap_foot *prevFoot = PREV_FOOT(head);\r
if( prevFoot->magic != MAGIC )\r
{\r
+ _SysDebug("Heap corruption, previous foot magic invalid");\r
Heap_Validate(1);\r
- exit(1);\r
+ return false;\r
}\r
\r
heap_head *prevHead = prevFoot->header;\r
prevFoot->header = NULL;\r
}\r
}\r
+ \r
+ return true;\r
}\r
\r
/**\r
\r
// Check for free space after the block\r
heap_head *nexthead = NEXT_HEAD(head);\r
- if( nexthead && nexthead->magic == MAGIC_FREE && head->size + nexthead->size >= reqd_size )\r
+ assert( nexthead <= _heap_end );\r
+ if( nexthead != _heap_end && nexthead->magic == MAGIC_FREE && head->size + nexthead->size >= reqd_size )\r
{\r
// Split next block\r
if( head->size + nexthead->size > reqd_size )\r
void *ret = _malloc(bytes, __builtin_return_address(0));\r
if(ret == NULL)\r
return NULL;\r
+ heap_head *newhead = (heap_head*)ret - 1;\r
\r
- //Copy Old Data\r
+ // Copy Old Data\r
+ assert( head->size < newhead->size );\r
size_t copy_size = head->size-sizeof(heap_head)-sizeof(heap_foot);\r
- if( copy_size > bytes )\r
- copy_size = bytes;\r
- memcpy(ret, oldPos, bytes);\r
+ memcpy(ret, oldPos, copy_size);\r
free(oldPos);\r
\r
//Return\r
--- /dev/null
+#include <stdlib.h>
+#include <stdbool.h>
+
+bool _libc_free(void *addr)
+{
+ free(addr);
+ return true;
+}
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
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
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
};
#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
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);
# define SEEK_END (-1)\r
#endif\r
\r
+#define MB_CUR_MAX 5 // (C99) Max number of bytes in a single multibyte character (UTF8=5)\r
+\r
#ifdef __cplusplus\r
}\r
#endif\r
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);
void abort(void)
{
// raise(SIGABRT);
+ _SysDebug("abort() - %p", __builtin_return_address(0));
_exit(-1);
}
\r
#define DEBUG_BUILD 0\r
\r
+#define LOG_WARN(f,...) _SysDebug("WARN: %s: "f, __func__ ,## __VA_ARGS__)\r
+#define LOG_NOTICE(f,...) _SysDebug("NOTE: %s: "f, __func__ ,## __VA_ARGS__)\r
+\r
// === CONSTANTS ===\r
#define _stdin 0\r
#define _stdout 1\r
\r
// === GLOBALS ===\r
struct sFILE _iob[STDIO_MAX_STREAMS]; // IO Buffer\r
-struct sFILE *stdin; // Standard Input\r
-struct sFILE *stdout; // Standard Output\r
-struct sFILE *stderr; // Standard Error\r
+struct sFILE *stdin = &_iob[0]; // Standard Input\r
+struct sFILE *stdout = &_iob[1]; // Standard Output\r
+struct sFILE *stderr = &_iob[2]; // Standard Error\r
///\note Initialised in SoMain\r
static const int STDIN_BUFSIZ = 512;\r
static const int STDOUT_BUFSIZ = 512;\r
void _stdio_init(void)\r
{\r
// Init FileIO Pointers\r
- stdin = &_iob[0];\r
stdin->FD = 0;\r
stdin->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_READ|FILE_FLAG_LINEBUFFERED|FILE_FLAG_OURBUFFER;\r
stdin->Buffer = malloc(STDIN_BUFSIZ);\r
stdin->BufferSpace = STDIN_BUFSIZ;\r
\r
- stdout = &_iob[1];\r
stdout->FD = 1;\r
stdout->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_WRITE|FILE_FLAG_LINEBUFFERED|FILE_FLAG_OURBUFFER;\r
stdout->Buffer = malloc(STDOUT_BUFSIZ);\r
stdout->BufferSpace = STDOUT_BUFSIZ;\r
\r
- stderr = &_iob[2];\r
stderr->FD = 2;\r
stderr->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_WRITE;\r
}\r
return ret;\r
}\r
\r
-EXPORT void fflush(FILE *fp)\r
+EXPORT int fflush(FILE *fp)\r
{\r
if( !fp || fp->FD == FD_NOTOPEN )\r
- return ;\r
+ return EBADF;\r
\r
// Nothing to do for memory files\r
if( fp->FD == FD_MEMFILE )\r
- return ;\r
+ return 0;\r
// Memory streams, update pointers\r
if( fp->FD == FD_MEMSTREAM ) {\r
*fp->BufPtr = fp->Buffer;\r
*fp->LenPtr = fp->BufferPos;\r
- return ;\r
+ return 0;\r
}\r
\r
_fflush_int(fp);\r
+ return 0;\r
}\r
\r
EXPORT void clearerr(FILE *fp)\r
{\r
size_t ret;\r
\r
- if(!fp || fp->FD == -1)\r
+ if(!fp || fp->FD == -1) {\r
+ LOG_WARN("bad fp %p", fp);\r
return -1;\r
+ }\r
if( size == 0 || num == 0 )\r
return 0;\r
\r
if( _GetFileMode(fp) != FILE_FLAG_MODE_READ ) {\r
errno = 0;\r
+ LOG_WARN("not open for read");\r
+ if( fp == stdin ) {\r
+ LOG_WARN("BUGCHECK FAIL: stdin was not open for read");\r
+ exit(129);\r
+ }\r
return -1;\r
}\r
\r
// Don't read if EOF is set\r
- if( fp->Flags & FILE_FLAG_EOF )\r
+ if( fp->Flags & FILE_FLAG_EOF ) {\r
+ LOG_NOTICE("EOF");\r
return 0;\r
+ }\r
\r
\r
if( fp->FD == FD_MEMFILE ) {\r
}\r
else if( fp->FD == FD_MEMSTREAM ) {\r
//return _fread_memstream(ptr, size, num, fp);\r
+ LOG_WARN("Reading from a mem stream");\r
errno = EBADF;\r
return 0;\r
}\r
extra, size, num\r
);\r
}\r
+ LOG_NOTICE("Incomplete read %i/%i bytes (object size %i)",\r
+ ret, bytes, size);\r
}\r
\r
return ret / size;\r
*/\r
EXPORT int fputc(int c, FILE *fp)\r
{\r
- char ch = c;\r
+ unsigned char ch = c;\r
return fwrite(&ch, 1, 1, fp);\r
}\r
\r
EXPORT int putchar(int c)\r
{\r
- c &= 0xFF;\r
return fputc(c, stdout);\r
}\r
\r
*/\r
EXPORT int fgetc(FILE *fp)\r
{\r
- char ret = 0;\r
+ unsigned char ret = 0;\r
if( fread(&ret, 1, 1, fp) != 1 )\r
return -1;\r
return ret;\r
\r
EXPORT int puts(const char *str)\r
{\r
- \r
if(!str) return 0;\r
int len = strlen(str);\r
\r
* AcessOS Basic C Library
* string.c
*/
-#include <acess/sys.h>
+//#include <acess/sys.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
* \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++;
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;
}
/**
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;
}
*/
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;
}
/**
*/
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;
}
* \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;
* \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];
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
while(count--)
{
if( *p1 != *p2 )
- return *p1 - *p2;
+ return (int)*p1 - (int)*p2;
p1 ++;
p2 ++;
}
*/
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;
}
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;
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;
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)
// 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;
}
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;
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 ++;
long long strtoll(const char *str, char **end, int base)
{
int neg = 0;
- unsigned long long ret;
if( !str ) {
errno = EINVAL;
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)
*/\r
int SoMain(UNUSED(uintptr_t, BaseAddress), UNUSED(int, argc), UNUSED(char **, argv), char **envp)\r
{\r
- // Init for env.c\r
environ = envp;\r
\r
- #if 0 \r
- {\r
- int i = 0;\r
- char **tmp;\r
- _SysDebug("envp = %p", envp);\r
- for(tmp = envp; *tmp; tmp++,i++)\r
- {\r
- _SysDebug("envp[%i] = '%s'", i, *tmp);\r
- }\r
- }\r
- #endif\r
-\r
_stdio_init(); \r
\r
#if USE_CPUID\r
// Set Error handler\r
_SysSetFaultHandler(ErrorHandler);\r
\r
- return 1;\r
+ return 0;\r
}\r
\r
int ErrorHandler(int Fault)\r
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;
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;
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);
--- /dev/null
+# Acess 2 "libiconv"
+#
+
+include ../Makefile.cfg
+
+CPPFLAGS +=
+CFLAGS += -Wall
+LDFLAGS += -lc -soname libiconv.so
+
+OBJ = iconv.o
+BIN = libiconv.so
+
+include ../Makefile.tpl
+
+
--- /dev/null
+/*
+ */
+#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;
+}
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+# Acess 2 "libintl"
+#
+
+include ../Makefile.cfg
+
+CPPFLAGS +=
+CFLAGS += -Wall
+LDFLAGS += -lc
+
+OBJ = main.o gettext.o
+BIN = libintl.so
+
+include ../Makefile.tpl
+
+
+
--- /dev/null
+/*
+ */
+#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;
+}
+
--- /dev/null
+/*
+ */
+#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
--- /dev/null
+/*
+ */
+
+int SoMain(void)
+{
+ return 0;
+}
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);
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
--- /dev/null
+/*
+ */
+#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;
+}
*/
#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)
*/
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;
}
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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
+
#ifndef __LIBNET_H_
#define __LIBNET_H_
+#include <stddef.h>
+
enum {
NET_ADDRTYPE_NULL = 0,
NET_ADDRTYPE_IPV4 = 4,
* 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
#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)
{
}
}
-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;
}
CPPFLAGS += \r
CFLAGS += -Wextra\r
ASFLAGS +=\r
-LDFLAGS += -soname libposix.so -Map map.txt -lc\r
+LDFLAGS += -nostdlib\r
+PRELINK += $(CRTI) $(CRTBEGINS) $(CRT0S)\r
+LIBS += -lc $(CRTENDS) $(CRTN)\r
\r
OBJ = main.o unistd.o dirent.o stat.o utmpx.o termios.o\r
OBJ += pwd.o syslog.o sys_time.o sys_ioctl.o sys_resource.o\r
OBJ += fcntl.o clocks.o sys_wait.o unistd_crypt.o\r
-OBJ += grp.o pty.o mktemp.o utime.o\r
+OBJ += grp.o pty.o mktemp.o utime.o getopt.o\r
DEPFILES := $(OBJ:%.o=%.d)\r
BIN = libposix.so\r
\r
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ */
+#ifndef _LIBPOSIX_ENDIAN_H_
+#define _LIBPOSIX_ENDIAN_H_
+
+#define __LITTLE_ENDIAN 0
+#define __BIG_ENDIAN 0
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+#endif
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * Acess2 POSIX Emulation Library
+ * - By John Hodge (thePowersGang)
+ *
+ * glob.h
+ * - Globbing code
+ */
+#ifndef _LIBPOSIX__GLOB_H_
+#define _LIBPOSIX__GLOB_H_
+
+
+
+#endif
--- /dev/null
+/*
+ * 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
+
+
--- /dev/null
+/*
+ * 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
+
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);
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);
*/
#include <unistd.h> // mktemp
#include <stdlib.h> // mkstemp
+#include <stdio.h>
#include <string.h> // str*
#include <errno.h>
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 ;
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;
+}
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
#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;
{
// 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;
}
}
// - 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;
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)
--- /dev/null
+# 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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+# 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ */
+#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
+
--- /dev/null
+/*
+ */
+
+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;
+}
+
#include <stdint.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/**
* \breif Read a single codepoint from a UTF-8 stream
* \return Number of bytes read
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
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)